@algolia/wizard 0.8.0-rc.58.43 → 0.8.0-rc.58.44
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 +504 -780
- 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
|
|
7
|
+
import { Box as Box13, Text as Text13, 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,
|
|
@@ -631,37 +497,37 @@ function Notices() {
|
|
|
631
497
|
}
|
|
632
498
|
|
|
633
499
|
// src/ui/PromptInput.tsx
|
|
634
|
-
import { Box as
|
|
500
|
+
import { Box as Box5, Text as Text5, useInput as useInput2 } from "ink";
|
|
635
501
|
import TextInput from "ink-text-input";
|
|
636
502
|
import { useState as useState4 } 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
|
|
528
|
+
import { Box as Box4, Text as Text4, measureElement as measureElement2, useInput, useWindowSize as useWindowSize3 } from "ink";
|
|
663
529
|
import { useLayoutEffect, useRef as useRef2, useState as useState3 } from "react";
|
|
664
|
-
import { jsx as jsx4, jsxs as
|
|
530
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
665
531
|
var CANCEL = "cancel";
|
|
666
532
|
var ARROW_WIDTH = 4;
|
|
667
533
|
var COLUMN_GAP = 2;
|
|
@@ -701,7 +567,7 @@ function SelectPrompt({
|
|
|
701
567
|
hints.push({ key: "[enter]", label: "confirm" });
|
|
702
568
|
const containerRef = useRef2(null);
|
|
703
569
|
const viewportRef = useRef2(null);
|
|
704
|
-
const { columns, rows: windowRows } =
|
|
570
|
+
const { columns, rows: windowRows } = useWindowSize3();
|
|
705
571
|
const [width, setWidth] = useState3(columns);
|
|
706
572
|
const [viewportHeight, setViewportHeight] = useState3(null);
|
|
707
573
|
useLayoutEffect(() => {
|
|
@@ -766,18 +632,18 @@ function SelectPrompt({
|
|
|
766
632
|
}
|
|
767
633
|
}
|
|
768
634
|
});
|
|
769
|
-
return /* @__PURE__ */ jsx4(
|
|
770
|
-
/* @__PURE__ */
|
|
771
|
-
error && /* @__PURE__ */ jsx4(
|
|
772
|
-
messages?.map((m, i) => /* @__PURE__ */ jsx4(
|
|
635
|
+
return /* @__PURE__ */ jsx4(Box4, { ref: containerRef, flexGrow: 1, children: /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", gap: 1, width, children: [
|
|
636
|
+
/* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", gap: 1, flexShrink: 0, children: [
|
|
637
|
+
error && /* @__PURE__ */ jsx4(Text4, { color: COLORS.danger, children: error }),
|
|
638
|
+
messages?.map((m, i) => /* @__PURE__ */ jsx4(Text4, { color: COLORS.muted, children: m }, `msg-${i}`)),
|
|
773
639
|
table && /* @__PURE__ */ jsx4(Table, { columns: table.columns, rows: table.rows }),
|
|
774
|
-
/* @__PURE__ */
|
|
775
|
-
question && /* @__PURE__ */ jsx4(
|
|
776
|
-
helpText && /* @__PURE__ */ jsx4(
|
|
640
|
+
/* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", children: [
|
|
641
|
+
question && /* @__PURE__ */ jsx4(Text4, { color: COLORS.muted, children: question }),
|
|
642
|
+
helpText && /* @__PURE__ */ jsx4(Text4, { color: COLORS.dim, children: helpText })
|
|
777
643
|
] })
|
|
778
644
|
] }),
|
|
779
|
-
/* @__PURE__ */
|
|
780
|
-
hiddenAbove > 0 && /* @__PURE__ */
|
|
645
|
+
/* @__PURE__ */ jsxs3(Box4, { ref: viewportRef, flexDirection: "column", flexGrow: 1, children: [
|
|
646
|
+
hiddenAbove > 0 && /* @__PURE__ */ jsxs3(Text4, { color: COLORS.dim, children: [
|
|
781
647
|
"\u2191 ",
|
|
782
648
|
hiddenAbove,
|
|
783
649
|
" more"
|
|
@@ -789,45 +655,45 @@ function SelectPrompt({
|
|
|
789
655
|
const bullet = multi && !isCancel ? checked.has(i) ? "\u25CF " : "\u25CB " : "";
|
|
790
656
|
const sec = isCancel ? void 0 : secondary?.[i];
|
|
791
657
|
const labelColor = highlighted ? COLORS.highlight.fg : void 0;
|
|
792
|
-
const label = /* @__PURE__ */
|
|
658
|
+
const label = /* @__PURE__ */ jsxs3(Text4, { color: labelColor, wrap: "truncate", children: [
|
|
793
659
|
highlighted ? "\u276F " : " ",
|
|
794
660
|
bullet,
|
|
795
661
|
option
|
|
796
662
|
] });
|
|
797
663
|
const isText = sec?.kind === "text";
|
|
798
|
-
return /* @__PURE__ */
|
|
799
|
-
|
|
664
|
+
return /* @__PURE__ */ jsxs3(
|
|
665
|
+
Box4,
|
|
800
666
|
{
|
|
801
667
|
width: isText ? "100%" : barWidth,
|
|
802
668
|
paddingX: 1,
|
|
803
669
|
paddingY: 1,
|
|
804
670
|
backgroundColor: highlighted ? COLORS.highlight.bg : void 0,
|
|
805
671
|
children: [
|
|
806
|
-
/* @__PURE__ */ jsx4(
|
|
807
|
-
isText && textWidth > 0 && /* @__PURE__ */ jsx4(
|
|
808
|
-
|
|
672
|
+
/* @__PURE__ */ jsx4(Box4, { width: isText ? labelWidth : barLabelWidth, children: label }),
|
|
673
|
+
isText && textWidth > 0 && /* @__PURE__ */ jsx4(Box4, { width: textWidth, children: /* @__PURE__ */ jsx4(
|
|
674
|
+
Text4,
|
|
809
675
|
{
|
|
810
676
|
wrap: "truncate",
|
|
811
677
|
color: highlighted ? COLORS.primary : COLORS.muted,
|
|
812
678
|
children: sec.value
|
|
813
679
|
}
|
|
814
680
|
) }),
|
|
815
|
-
sec?.kind === "badge" && /* @__PURE__ */ jsx4(
|
|
681
|
+
sec?.kind === "badge" && /* @__PURE__ */ jsx4(Box4, { width: badgeWidth, justifyContent: "flex-end", children: /* @__PURE__ */ jsx4(Text4, { color: COLORS.badge, wrap: "truncate", children: sec.value }) })
|
|
816
682
|
]
|
|
817
683
|
},
|
|
818
684
|
`row-${i}`
|
|
819
685
|
);
|
|
820
686
|
}),
|
|
821
|
-
hiddenBelow > 0 && /* @__PURE__ */
|
|
687
|
+
hiddenBelow > 0 && /* @__PURE__ */ jsxs3(Text4, { color: COLORS.dim, children: [
|
|
822
688
|
"\u2193 ",
|
|
823
689
|
hiddenBelow,
|
|
824
690
|
" more"
|
|
825
691
|
] })
|
|
826
692
|
] }),
|
|
827
|
-
/* @__PURE__ */ jsx4(
|
|
693
|
+
/* @__PURE__ */ jsx4(Box4, { flexShrink: 0, children: /* @__PURE__ */ jsx4(Text4, { children: hints.map(({ key, label }, i) => /* @__PURE__ */ jsxs3(Text4, { children: [
|
|
828
694
|
i > 0 ? " " : "",
|
|
829
|
-
/* @__PURE__ */ jsx4(
|
|
830
|
-
/* @__PURE__ */
|
|
695
|
+
/* @__PURE__ */ jsx4(Text4, { color: COLORS.primary, children: key }),
|
|
696
|
+
/* @__PURE__ */ jsxs3(Text4, { color: COLORS.dim, children: [
|
|
831
697
|
" ",
|
|
832
698
|
label
|
|
833
699
|
] })
|
|
@@ -836,7 +702,7 @@ function SelectPrompt({
|
|
|
836
702
|
}
|
|
837
703
|
|
|
838
704
|
// src/ui/PromptInput.tsx
|
|
839
|
-
import { jsx as jsx5, jsxs as
|
|
705
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
840
706
|
var ACCEPT_REJECT_OPTIONS = ["Accept", "Reject"];
|
|
841
707
|
function EnterToContinuePrompt({
|
|
842
708
|
question,
|
|
@@ -847,10 +713,10 @@ function EnterToContinuePrompt({
|
|
|
847
713
|
if (key.return) onDecide(true);
|
|
848
714
|
else if (key.escape) onDecide(false);
|
|
849
715
|
});
|
|
850
|
-
return /* @__PURE__ */
|
|
851
|
-
messages?.map((m, i) => /* @__PURE__ */ jsx5(
|
|
852
|
-
question && /* @__PURE__ */ jsx5(
|
|
853
|
-
/* @__PURE__ */
|
|
716
|
+
return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", gap: 1, children: [
|
|
717
|
+
messages?.map((m, i) => /* @__PURE__ */ jsx5(Text5, { color: COLORS.muted, children: m }, `msg-${i}`)),
|
|
718
|
+
question && /* @__PURE__ */ jsx5(Text5, { color: COLORS.primary, children: question }),
|
|
719
|
+
/* @__PURE__ */ jsxs4(Box5, { gap: 1, flexDirection: "column", children: [
|
|
854
720
|
/* @__PURE__ */ jsx5(NextAction, { action: "continue", keyHint: "enter" }),
|
|
855
721
|
/* @__PURE__ */ jsx5(NextAction, { action: "decline", keyHint: "esc", hierarchy: "secondary" })
|
|
856
722
|
] })
|
|
@@ -860,11 +726,11 @@ function PromptInput() {
|
|
|
860
726
|
const { phase, inputReq, submitInput } = useWizard();
|
|
861
727
|
const [draft, setDraft] = useState4("");
|
|
862
728
|
if (phase === "done" || phase === "error") {
|
|
863
|
-
return /* @__PURE__ */ jsx5(
|
|
729
|
+
return /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { color: "gray", dimColor: true, children: "Press Enter or Esc to exit" }) });
|
|
864
730
|
}
|
|
865
731
|
if (phase !== "awaitingInput" || !inputReq) return null;
|
|
866
732
|
if (inputReq.promptType === "multipleChoice") {
|
|
867
|
-
return /* @__PURE__ */ jsx5(
|
|
733
|
+
return /* @__PURE__ */ jsx5(Box5, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
|
|
868
734
|
SelectPrompt,
|
|
869
735
|
{
|
|
870
736
|
question: inputReq.prompt,
|
|
@@ -881,7 +747,7 @@ function PromptInput() {
|
|
|
881
747
|
) });
|
|
882
748
|
}
|
|
883
749
|
if (inputReq.promptType === "multiSelect") {
|
|
884
|
-
return /* @__PURE__ */ jsx5(
|
|
750
|
+
return /* @__PURE__ */ jsx5(Box5, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
|
|
885
751
|
SelectPrompt,
|
|
886
752
|
{
|
|
887
753
|
multi: true,
|
|
@@ -896,7 +762,7 @@ function PromptInput() {
|
|
|
896
762
|
) });
|
|
897
763
|
}
|
|
898
764
|
if (inputReq.promptType === "notice") {
|
|
899
|
-
return /* @__PURE__ */ jsx5(
|
|
765
|
+
return /* @__PURE__ */ jsx5(Box5, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
|
|
900
766
|
SelectPrompt,
|
|
901
767
|
{
|
|
902
768
|
question: inputReq.prompt,
|
|
@@ -918,7 +784,7 @@ function PromptInput() {
|
|
|
918
784
|
}
|
|
919
785
|
if (inputReq.promptType === "acceptReject") {
|
|
920
786
|
const labels = inputReq.options?.length ? inputReq.options : ACCEPT_REJECT_OPTIONS;
|
|
921
|
-
return /* @__PURE__ */ jsx5(
|
|
787
|
+
return /* @__PURE__ */ jsx5(Box5, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
|
|
922
788
|
SelectPrompt,
|
|
923
789
|
{
|
|
924
790
|
question: inputReq.prompt,
|
|
@@ -929,11 +795,11 @@ function PromptInput() {
|
|
|
929
795
|
}
|
|
930
796
|
) });
|
|
931
797
|
}
|
|
932
|
-
return /* @__PURE__ */
|
|
933
|
-
inputReq.error && /* @__PURE__ */ jsx5(
|
|
934
|
-
inputReq.messages?.map((m, i) => /* @__PURE__ */ jsx5(
|
|
935
|
-
/* @__PURE__ */
|
|
936
|
-
/* @__PURE__ */
|
|
798
|
+
return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
|
|
799
|
+
inputReq.error && /* @__PURE__ */ jsx5(Text5, { color: COLORS.danger, children: inputReq.error }),
|
|
800
|
+
inputReq.messages?.map((m, i) => /* @__PURE__ */ jsx5(Text5, { color: COLORS.muted, children: m }, `msg-${i}`)),
|
|
801
|
+
/* @__PURE__ */ jsxs4(Box5, { children: [
|
|
802
|
+
/* @__PURE__ */ jsxs4(Text5, { color: COLORS.primary, children: [
|
|
937
803
|
inputReq.prompt,
|
|
938
804
|
" "
|
|
939
805
|
] }),
|
|
@@ -955,7 +821,7 @@ function PromptInput() {
|
|
|
955
821
|
// src/ui/Welcome.tsx
|
|
956
822
|
import { dirname as dirname2, join as join3 } from "node:path";
|
|
957
823
|
import { fileURLToPath } from "node:url";
|
|
958
|
-
import { Box as
|
|
824
|
+
import { Box as Box6, Spacer, Text as Text6, useInput as useInput3, useWindowSize as useWindowSize4 } from "ink";
|
|
959
825
|
|
|
960
826
|
// src/ui/copy/welcome.ts
|
|
961
827
|
var sidebarItems = [
|
|
@@ -983,27 +849,27 @@ var sidebarItems = [
|
|
|
983
849
|
|
|
984
850
|
// src/ui/Welcome.tsx
|
|
985
851
|
import Image, { InkPictureProvider } from "ink-picture";
|
|
986
|
-
import { jsx as jsx6, jsxs as
|
|
852
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
987
853
|
var IMAGE_PATH = join3(dirname2(fileURLToPath(import.meta.url)), "algolia.png");
|
|
988
854
|
function SidebarItem({
|
|
989
855
|
title,
|
|
990
856
|
description
|
|
991
857
|
}) {
|
|
992
|
-
return /* @__PURE__ */
|
|
993
|
-
/* @__PURE__ */
|
|
994
|
-
/* @__PURE__ */ jsx6(
|
|
995
|
-
/* @__PURE__ */ jsx6(
|
|
858
|
+
return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
|
|
859
|
+
/* @__PURE__ */ jsxs5(Box6, { gap: 1, children: [
|
|
860
|
+
/* @__PURE__ */ jsx6(Text6, { color: COLORS.success, children: "\u2192" }),
|
|
861
|
+
/* @__PURE__ */ jsx6(Text6, { color: COLORS.strong, bold: true, children: title })
|
|
996
862
|
] }),
|
|
997
|
-
/* @__PURE__ */
|
|
863
|
+
/* @__PURE__ */ jsxs5(Box6, { flexDirection: "row", gap: 2, children: [
|
|
998
864
|
/* @__PURE__ */ jsx6(Spacer, {}),
|
|
999
|
-
/* @__PURE__ */ jsx6(
|
|
865
|
+
/* @__PURE__ */ jsx6(Text6, { color: COLORS.muted, children: description })
|
|
1000
866
|
] })
|
|
1001
867
|
] });
|
|
1002
868
|
}
|
|
1003
869
|
function Welcome() {
|
|
1004
870
|
const confirmStart = useWizard((s) => s.confirmStart);
|
|
1005
871
|
const openLearnMore = useWizard((s) => s.openLearnMore);
|
|
1006
|
-
const { rows } =
|
|
872
|
+
const { rows } = useWindowSize4();
|
|
1007
873
|
useInput3((input, key) => {
|
|
1008
874
|
if (key.return) confirmStart();
|
|
1009
875
|
else if (input === "i") openLearnMore();
|
|
@@ -1022,15 +888,15 @@ function Welcome() {
|
|
|
1022
888
|
if (rows < 30) {
|
|
1023
889
|
layout = scales["small"];
|
|
1024
890
|
}
|
|
1025
|
-
return /* @__PURE__ */
|
|
891
|
+
return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "row", justifyContent: "space-between", width: "100%", children: [
|
|
1026
892
|
/* @__PURE__ */ jsx6(
|
|
1027
|
-
|
|
893
|
+
Box6,
|
|
1028
894
|
{
|
|
1029
895
|
paddingY: layout.main.padding.y,
|
|
1030
896
|
paddingX: layout.main.padding.x,
|
|
1031
897
|
flexDirection: "column",
|
|
1032
898
|
justifyContent: "center",
|
|
1033
|
-
children: /* @__PURE__ */
|
|
899
|
+
children: /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", gap: 2, children: [
|
|
1034
900
|
/* @__PURE__ */ jsx6(InkPictureProvider, { children: /* @__PURE__ */ jsx6(
|
|
1035
901
|
Image,
|
|
1036
902
|
{
|
|
@@ -1042,16 +908,16 @@ function Welcome() {
|
|
|
1042
908
|
protocol: "halfBlock"
|
|
1043
909
|
}
|
|
1044
910
|
) }),
|
|
1045
|
-
/* @__PURE__ */ jsx6(
|
|
1046
|
-
/* @__PURE__ */
|
|
911
|
+
/* @__PURE__ */ jsx6(Text6, { color: COLORS.muted, children: "\u2726 From zero \u2192 working search in ~10 minutes" }),
|
|
912
|
+
/* @__PURE__ */ jsxs5(Box6, { gap: 1, flexDirection: "column", children: [
|
|
1047
913
|
/* @__PURE__ */ jsx6(NextAction, { action: "start wizard", keyHint: "enter" }),
|
|
1048
914
|
/* @__PURE__ */ jsx6(NextAction, { action: "learn more", keyHint: "i", hierarchy: "secondary" })
|
|
1049
915
|
] })
|
|
1050
916
|
] })
|
|
1051
917
|
}
|
|
1052
918
|
),
|
|
1053
|
-
/* @__PURE__ */
|
|
1054
|
-
|
|
919
|
+
/* @__PURE__ */ jsxs5(
|
|
920
|
+
Box6,
|
|
1055
921
|
{
|
|
1056
922
|
backgroundColor: COLORS.bg.sidebar,
|
|
1057
923
|
width: 40,
|
|
@@ -1061,7 +927,7 @@ function Welcome() {
|
|
|
1061
927
|
flexDirection: "column",
|
|
1062
928
|
justifyContent: "center",
|
|
1063
929
|
children: [
|
|
1064
|
-
/* @__PURE__ */ jsx6(
|
|
930
|
+
/* @__PURE__ */ jsx6(Text6, { color: COLORS.muted, children: "WHAT THIS WIZARD WILL DO" }),
|
|
1065
931
|
sidebarItems.map((i, idx) => /* @__PURE__ */ jsx6(SidebarItem, { title: i.title, description: i.description }, idx))
|
|
1066
932
|
]
|
|
1067
933
|
}
|
|
@@ -1071,7 +937,7 @@ function Welcome() {
|
|
|
1071
937
|
|
|
1072
938
|
// src/ui/LearnMore.tsx
|
|
1073
939
|
import { Fragment as Fragment2 } from "react";
|
|
1074
|
-
import { Box as
|
|
940
|
+
import { Box as Box7, Text as Text7, useInput as useInput4, useWindowSize as useWindowSize5 } from "ink";
|
|
1075
941
|
|
|
1076
942
|
// src/ui/copy/learn-more.ts
|
|
1077
943
|
var accessIntro = "Everything runs locally on your machine. Nothing is written or sent without an explicit yes from you.";
|
|
@@ -1108,7 +974,7 @@ var policyLinks = [
|
|
|
1108
974
|
];
|
|
1109
975
|
|
|
1110
976
|
// src/ui/LearnMore.tsx
|
|
1111
|
-
import { jsx as jsx7, jsxs as
|
|
977
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1112
978
|
var TAG_COLORS = {
|
|
1113
979
|
READ: COLORS.success,
|
|
1114
980
|
WRITE: COLORS.badge,
|
|
@@ -1124,25 +990,25 @@ function NeverLine({
|
|
|
1124
990
|
}) {
|
|
1125
991
|
const used = segments.reduce((n, s) => n + s.text.length, 0);
|
|
1126
992
|
const rightPad = Math.max(0, width - 2 - NEVER_BOX_PAD_X - used);
|
|
1127
|
-
return /* @__PURE__ */
|
|
1128
|
-
/* @__PURE__ */ jsx7(
|
|
993
|
+
return /* @__PURE__ */ jsxs6(Text7, { children: [
|
|
994
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.danger, children: "\u2502" }),
|
|
1129
995
|
" ".repeat(NEVER_BOX_PAD_X),
|
|
1130
|
-
segments.map((s, i) => /* @__PURE__ */ jsx7(
|
|
996
|
+
segments.map((s, i) => /* @__PURE__ */ jsx7(Text7, { color: s.color, bold: s.bold, children: s.text }, i)),
|
|
1131
997
|
" ".repeat(rightPad),
|
|
1132
|
-
/* @__PURE__ */ jsx7(
|
|
998
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.danger, children: "\u2502" })
|
|
1133
999
|
] });
|
|
1134
1000
|
}
|
|
1135
1001
|
function LearnMore() {
|
|
1136
1002
|
const confirmStart = useWizard((s) => s.confirmStart);
|
|
1137
1003
|
const backToHome = useWizard((s) => s.backToHome);
|
|
1138
|
-
const { columns } =
|
|
1004
|
+
const { columns } = useWindowSize5();
|
|
1139
1005
|
const dividerWidth = Math.max(0, columns - PADDING_X * 2);
|
|
1140
1006
|
useInput4((_input, key) => {
|
|
1141
1007
|
if (key.escape) backToHome();
|
|
1142
1008
|
else if (key.return) confirmStart();
|
|
1143
1009
|
});
|
|
1144
|
-
return /* @__PURE__ */
|
|
1145
|
-
|
|
1010
|
+
return /* @__PURE__ */ jsxs6(
|
|
1011
|
+
Box7,
|
|
1146
1012
|
{
|
|
1147
1013
|
flexDirection: "column",
|
|
1148
1014
|
paddingX: PADDING_X,
|
|
@@ -1150,20 +1016,20 @@ function LearnMore() {
|
|
|
1150
1016
|
width: "100%",
|
|
1151
1017
|
gap: 1,
|
|
1152
1018
|
children: [
|
|
1153
|
-
/* @__PURE__ */ jsx7(
|
|
1154
|
-
/* @__PURE__ */ jsx7(
|
|
1155
|
-
/* @__PURE__ */ jsx7(
|
|
1156
|
-
/* @__PURE__ */ jsx7(
|
|
1157
|
-
/* @__PURE__ */
|
|
1158
|
-
/* @__PURE__ */ jsx7(
|
|
1159
|
-
/* @__PURE__ */ jsx7(
|
|
1160
|
-
/* @__PURE__ */ jsx7(
|
|
1161
|
-
/* @__PURE__ */ jsx7(
|
|
1019
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.strong, bold: true, children: "What algolia wizard accesses" }),
|
|
1020
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.muted, children: accessIntro }),
|
|
1021
|
+
/* @__PURE__ */ jsx7(Box7, { flexDirection: "column", children: accessItems.map((item) => /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", marginTop: 1, children: [
|
|
1022
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.border, children: "\u2500".repeat(dividerWidth) }),
|
|
1023
|
+
/* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", gap: 1, marginTop: 1, children: [
|
|
1024
|
+
/* @__PURE__ */ jsx7(Box7, { width: TAG_COLUMN_WIDTH, flexShrink: 0, children: /* @__PURE__ */ jsx7(Text7, { color: TAG_COLORS[item.tag], bold: true, children: `[${item.tag}]` }) }),
|
|
1025
|
+
/* @__PURE__ */ jsx7(Box7, { flexDirection: "column", children: /* @__PURE__ */ jsxs6(Text7, { children: [
|
|
1026
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.strong, bold: true, children: item.title }),
|
|
1027
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.muted, children: ` \u2014 ${item.description}` })
|
|
1162
1028
|
] }) })
|
|
1163
1029
|
] })
|
|
1164
1030
|
] }, item.tag)) }),
|
|
1165
|
-
/* @__PURE__ */
|
|
1166
|
-
/* @__PURE__ */ jsx7(
|
|
1031
|
+
/* @__PURE__ */ jsxs6(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
1032
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.danger, children: `\u256D${"\u2500".repeat(Math.max(0, dividerWidth - 2))}\u256E` }),
|
|
1167
1033
|
/* @__PURE__ */ jsx7(NeverLine, { width: dividerWidth }),
|
|
1168
1034
|
/* @__PURE__ */ jsx7(
|
|
1169
1035
|
NeverLine,
|
|
@@ -1172,7 +1038,7 @@ function LearnMore() {
|
|
|
1172
1038
|
segments: [{ text: "I NEVER", color: COLORS.danger, bold: true }]
|
|
1173
1039
|
}
|
|
1174
1040
|
),
|
|
1175
|
-
neverItems.map((item) => /* @__PURE__ */
|
|
1041
|
+
neverItems.map((item) => /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
1176
1042
|
/* @__PURE__ */ jsx7(NeverLine, { width: dividerWidth }),
|
|
1177
1043
|
/* @__PURE__ */ jsx7(
|
|
1178
1044
|
NeverLine,
|
|
@@ -1187,23 +1053,23 @@ function LearnMore() {
|
|
|
1187
1053
|
)
|
|
1188
1054
|
] }, item)),
|
|
1189
1055
|
/* @__PURE__ */ jsx7(NeverLine, { width: dividerWidth }),
|
|
1190
|
-
/* @__PURE__ */ jsx7(
|
|
1056
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.danger, children: `\u2570${"\u2500".repeat(Math.max(0, dividerWidth - 2))}\u256F` })
|
|
1191
1057
|
] }),
|
|
1192
|
-
/* @__PURE__ */ jsx7(
|
|
1193
|
-
/* @__PURE__ */ jsx7(
|
|
1194
|
-
/* @__PURE__ */ jsx7(
|
|
1058
|
+
/* @__PURE__ */ jsx7(Box7, { marginTop: 1, flexDirection: "column", children: policyLinks.map((link) => /* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", gap: 1, children: [
|
|
1059
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.strong, bold: true, children: `${link.label}:` }),
|
|
1060
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.accent, children: link.url })
|
|
1195
1061
|
] }, link.label)) }),
|
|
1196
|
-
/* @__PURE__ */
|
|
1197
|
-
/* @__PURE__ */
|
|
1198
|
-
/* @__PURE__ */ jsx7(
|
|
1199
|
-
/* @__PURE__ */ jsx7(
|
|
1200
|
-
/* @__PURE__ */ jsx7(
|
|
1062
|
+
/* @__PURE__ */ jsxs6(Box7, { marginTop: 1, flexDirection: "row", gap: 3, children: [
|
|
1063
|
+
/* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", gap: 1, children: [
|
|
1064
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.muted, children: "[" }),
|
|
1065
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.primary, children: "esc" }),
|
|
1066
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.muted, children: "] back" })
|
|
1201
1067
|
] }),
|
|
1202
|
-
/* @__PURE__ */
|
|
1203
|
-
/* @__PURE__ */ jsx7(
|
|
1204
|
-
/* @__PURE__ */ jsx7(
|
|
1205
|
-
/* @__PURE__ */ jsx7(
|
|
1206
|
-
/* @__PURE__ */ jsx7(
|
|
1068
|
+
/* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", gap: 1, children: [
|
|
1069
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.muted, children: "[" }),
|
|
1070
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.primary, children: "enter" }),
|
|
1071
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.muted, children: "]" }),
|
|
1072
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.success, bold: true, children: "start wizard" })
|
|
1207
1073
|
] })
|
|
1208
1074
|
] })
|
|
1209
1075
|
]
|
|
@@ -1212,10 +1078,10 @@ function LearnMore() {
|
|
|
1212
1078
|
}
|
|
1213
1079
|
|
|
1214
1080
|
// src/ui/Sidebar.tsx
|
|
1215
|
-
import { Box as
|
|
1081
|
+
import { Box as Box10, Text as Text10 } from "ink";
|
|
1216
1082
|
|
|
1217
1083
|
// src/ui/Steps.tsx
|
|
1218
|
-
import { Box as
|
|
1084
|
+
import { Box as Box8, Text as Text8 } from "ink";
|
|
1219
1085
|
import Spinner from "ink-spinner";
|
|
1220
1086
|
|
|
1221
1087
|
// src/core/persistence.ts
|
|
@@ -1244,11 +1110,11 @@ async function clearWorkflowState(workflowId) {
|
|
|
1244
1110
|
}
|
|
1245
1111
|
|
|
1246
1112
|
// src/ui/Steps.tsx
|
|
1247
|
-
import { jsx as jsx8, jsxs as
|
|
1113
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1248
1114
|
function Steps() {
|
|
1249
1115
|
const { steps } = useWizard();
|
|
1250
1116
|
const visibleSteps = steps.filter(isStepVisible);
|
|
1251
|
-
return /* @__PURE__ */ jsx8(
|
|
1117
|
+
return /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", gap: 1, children: visibleSteps.map((s) => /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", children: /* @__PURE__ */ jsxs7(Text8, { color: COLORS.status[s.status], children: [
|
|
1252
1118
|
s.status === "running" ? /* @__PURE__ */ jsx8(Spinner, { type: "dots" }) : MARKER[s.status],
|
|
1253
1119
|
" ",
|
|
1254
1120
|
s.title
|
|
@@ -1258,7 +1124,7 @@ function CurrentStep() {
|
|
|
1258
1124
|
const { steps } = useWizard();
|
|
1259
1125
|
const currentStep = steps.filter(isStepVisible).find((s) => s.status === "running");
|
|
1260
1126
|
if (!currentStep) return null;
|
|
1261
|
-
return /* @__PURE__ */
|
|
1127
|
+
return /* @__PURE__ */ jsxs7(Text8, { color: COLORS.status.running, children: [
|
|
1262
1128
|
/* @__PURE__ */ jsx8(Spinner, { type: "dots" }),
|
|
1263
1129
|
" ",
|
|
1264
1130
|
` ${currentStep.title}`
|
|
@@ -1266,19 +1132,19 @@ function CurrentStep() {
|
|
|
1266
1132
|
}
|
|
1267
1133
|
|
|
1268
1134
|
// src/ui/Progress.tsx
|
|
1269
|
-
import { Box as
|
|
1270
|
-
import { jsx as jsx9, jsxs as
|
|
1135
|
+
import { Box as Box9, Text as Text9 } from "ink";
|
|
1136
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1271
1137
|
function Progress() {
|
|
1272
1138
|
const { steps, currentStepIndex } = useWizard();
|
|
1273
1139
|
const visibleSteps = steps.filter(isStepVisible);
|
|
1274
1140
|
if (visibleSteps.length === 0) return null;
|
|
1275
1141
|
const visibleCountThroughCurrent = steps.slice(0, currentStepIndex + 1).filter(isStepVisible).length;
|
|
1276
1142
|
const activeStepNumber = Math.max(1, visibleCountThroughCurrent);
|
|
1277
|
-
return /* @__PURE__ */
|
|
1278
|
-
/* @__PURE__ */ jsx9(
|
|
1279
|
-
/* @__PURE__ */ jsx9(
|
|
1280
|
-
/* @__PURE__ */ jsx9(
|
|
1281
|
-
/* @__PURE__ */ jsx9(
|
|
1143
|
+
return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "row", gap: 1, children: [
|
|
1144
|
+
/* @__PURE__ */ jsx9(Text9, { color: COLORS.muted, children: "STEP" }),
|
|
1145
|
+
/* @__PURE__ */ jsx9(Text9, { bold: true, children: activeStepNumber }),
|
|
1146
|
+
/* @__PURE__ */ jsx9(Text9, { bold: true, children: "/" }),
|
|
1147
|
+
/* @__PURE__ */ jsx9(Text9, { bold: true, children: visibleSteps.length })
|
|
1282
1148
|
] });
|
|
1283
1149
|
}
|
|
1284
1150
|
|
|
@@ -1289,10 +1155,10 @@ var sidebarCommands = [
|
|
|
1289
1155
|
];
|
|
1290
1156
|
|
|
1291
1157
|
// src/ui/Sidebar.tsx
|
|
1292
|
-
import { jsx as jsx10, jsxs as
|
|
1158
|
+
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1293
1159
|
function Sidebar() {
|
|
1294
|
-
return /* @__PURE__ */
|
|
1295
|
-
|
|
1160
|
+
return /* @__PURE__ */ jsxs9(
|
|
1161
|
+
Box10,
|
|
1296
1162
|
{
|
|
1297
1163
|
backgroundColor: "#14171E",
|
|
1298
1164
|
width: 30,
|
|
@@ -1301,16 +1167,16 @@ function Sidebar() {
|
|
|
1301
1167
|
flexDirection: "column",
|
|
1302
1168
|
justifyContent: "space-between",
|
|
1303
1169
|
children: [
|
|
1304
|
-
/* @__PURE__ */
|
|
1305
|
-
/* @__PURE__ */ jsx10(
|
|
1170
|
+
/* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", gap: 1, children: [
|
|
1171
|
+
/* @__PURE__ */ jsx10(Text10, { color: COLORS.muted, children: "PROGRESS" }),
|
|
1306
1172
|
/* @__PURE__ */ jsx10(Steps, {})
|
|
1307
1173
|
] }),
|
|
1308
|
-
/* @__PURE__ */
|
|
1174
|
+
/* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", gap: 1, children: [
|
|
1309
1175
|
/* @__PURE__ */ jsx10(Progress, {}),
|
|
1310
|
-
/* @__PURE__ */ jsx10(
|
|
1311
|
-
return /* @__PURE__ */
|
|
1312
|
-
/* @__PURE__ */ jsx10(
|
|
1313
|
-
/* @__PURE__ */ jsx10(
|
|
1176
|
+
/* @__PURE__ */ jsx10(Box10, { flexDirection: "column", children: sidebarCommands.map((c) => {
|
|
1177
|
+
return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "row", gap: 1, children: [
|
|
1178
|
+
/* @__PURE__ */ jsx10(Text10, { color: COLORS.primary, children: `[${c.keyHint}]` }),
|
|
1179
|
+
/* @__PURE__ */ jsx10(Text10, { color: COLORS.muted, children: c.description })
|
|
1314
1180
|
] });
|
|
1315
1181
|
}) })
|
|
1316
1182
|
] })
|
|
@@ -1320,12 +1186,12 @@ function Sidebar() {
|
|
|
1320
1186
|
}
|
|
1321
1187
|
|
|
1322
1188
|
// src/ui/Ribbon.tsx
|
|
1323
|
-
import { Box as
|
|
1324
|
-
import { jsx as jsx11, jsxs as
|
|
1189
|
+
import { Box as Box11, Text as Text11 } from "ink";
|
|
1190
|
+
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1325
1191
|
function Ribbon() {
|
|
1326
1192
|
const firstCommand = sidebarCommands[0];
|
|
1327
|
-
return /* @__PURE__ */
|
|
1328
|
-
|
|
1193
|
+
return /* @__PURE__ */ jsxs10(
|
|
1194
|
+
Box11,
|
|
1329
1195
|
{
|
|
1330
1196
|
backgroundColor: "#14171E",
|
|
1331
1197
|
flexDirection: "row",
|
|
@@ -1335,9 +1201,9 @@ function Ribbon() {
|
|
|
1335
1201
|
children: [
|
|
1336
1202
|
/* @__PURE__ */ jsx11(Progress, {}),
|
|
1337
1203
|
/* @__PURE__ */ jsx11(CurrentStep, {}),
|
|
1338
|
-
/* @__PURE__ */
|
|
1339
|
-
/* @__PURE__ */ jsx11(
|
|
1340
|
-
/* @__PURE__ */ jsx11(
|
|
1204
|
+
/* @__PURE__ */ jsxs10(Box11, { flexDirection: "row", gap: 1, children: [
|
|
1205
|
+
/* @__PURE__ */ jsx11(Text11, { color: COLORS.primary, children: `[${firstCommand.keyHint}]` }),
|
|
1206
|
+
/* @__PURE__ */ jsx11(Text11, { color: COLORS.muted, children: firstCommand.description })
|
|
1341
1207
|
] })
|
|
1342
1208
|
]
|
|
1343
1209
|
}
|
|
@@ -1349,8 +1215,8 @@ import { useState as useState6 } from "react";
|
|
|
1349
1215
|
|
|
1350
1216
|
// src/ui/Logs.tsx
|
|
1351
1217
|
import { useLayoutEffect as useLayoutEffect2, useRef as useRef3, useState as useState5 } from "react";
|
|
1352
|
-
import { Box as
|
|
1353
|
-
import { jsx as jsx12, jsxs as
|
|
1218
|
+
import { Box as Box12, Text as Text12, measureElement as measureElement3, useInput as useInput5, useWindowSize as useWindowSize6 } from "ink";
|
|
1219
|
+
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1354
1220
|
var KIND_COLOR = {
|
|
1355
1221
|
tool: COLORS.primary,
|
|
1356
1222
|
prompt: COLORS.badge
|
|
@@ -1380,7 +1246,7 @@ function formatTimestamp(ms) {
|
|
|
1380
1246
|
}
|
|
1381
1247
|
function Logs() {
|
|
1382
1248
|
const logs = useWizard((s) => s.logs);
|
|
1383
|
-
const { rows, columns } =
|
|
1249
|
+
const { rows, columns } = useWindowSize6();
|
|
1384
1250
|
const viewportRef = useRef3(null);
|
|
1385
1251
|
const [viewportHeight, setViewportHeight] = useState5(0);
|
|
1386
1252
|
const [viewportWidth, setViewportWidth] = useState5(0);
|
|
@@ -1417,10 +1283,10 @@ function Logs() {
|
|
|
1417
1283
|
const visible = logs.slice(scrollOffset, scrollOffset + capacity);
|
|
1418
1284
|
const hiddenAbove = scrollOffset;
|
|
1419
1285
|
const hiddenBelow = logs.length - scrollOffset - visible.length;
|
|
1420
|
-
return /* @__PURE__ */
|
|
1421
|
-
logs.length === 0 && /* @__PURE__ */ jsx12(
|
|
1422
|
-
/* @__PURE__ */
|
|
1423
|
-
hiddenAbove > 0 && /* @__PURE__ */
|
|
1286
|
+
return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", paddingX: 4, paddingY: 2, flexGrow: 1, children: [
|
|
1287
|
+
logs.length === 0 && /* @__PURE__ */ jsx12(Text12, { color: COLORS.dim, children: "No logs yet." }),
|
|
1288
|
+
/* @__PURE__ */ jsxs11(Box12, { ref: viewportRef, flexDirection: "column", flexGrow: 1, children: [
|
|
1289
|
+
hiddenAbove > 0 && /* @__PURE__ */ jsxs11(Text12, { color: COLORS.dim, children: [
|
|
1424
1290
|
"\u2191 ",
|
|
1425
1291
|
hiddenAbove,
|
|
1426
1292
|
" more"
|
|
@@ -1435,20 +1301,20 @@ function Logs() {
|
|
|
1435
1301
|
const name = truncate2(entry.name, budget);
|
|
1436
1302
|
budget -= name.length;
|
|
1437
1303
|
const preview = rawPreview ? truncate2(rawPreview, budget) : "";
|
|
1438
|
-
return /* @__PURE__ */
|
|
1439
|
-
/* @__PURE__ */ jsx12(
|
|
1440
|
-
/* @__PURE__ */ jsx12(
|
|
1441
|
-
preview && /* @__PURE__ */ jsx12(
|
|
1442
|
-
durationText && /* @__PURE__ */ jsx12(
|
|
1304
|
+
return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "row", gap: ROW_GAP, children: [
|
|
1305
|
+
/* @__PURE__ */ jsx12(Text12, { color: COLORS.dim, children: timestamp }),
|
|
1306
|
+
/* @__PURE__ */ jsx12(Text12, { color: logNameColor(entry), wrap: "truncate", children: name }),
|
|
1307
|
+
preview && /* @__PURE__ */ jsx12(Text12, { color: COLORS.dim, wrap: "truncate", children: preview }),
|
|
1308
|
+
durationText && /* @__PURE__ */ jsx12(Text12, { color: COLORS.dim, children: durationText })
|
|
1443
1309
|
] }, entry.id);
|
|
1444
1310
|
}),
|
|
1445
|
-
hiddenBelow > 0 && /* @__PURE__ */
|
|
1311
|
+
hiddenBelow > 0 && /* @__PURE__ */ jsxs11(Text12, { color: COLORS.dim, children: [
|
|
1446
1312
|
"\u2193 ",
|
|
1447
1313
|
hiddenBelow,
|
|
1448
1314
|
" more"
|
|
1449
1315
|
] })
|
|
1450
1316
|
] }),
|
|
1451
|
-
/* @__PURE__ */ jsx12(
|
|
1317
|
+
/* @__PURE__ */ jsx12(Text12, { color: COLORS.dim, children: "\u2191/\u2193 scroll" })
|
|
1452
1318
|
] });
|
|
1453
1319
|
}
|
|
1454
1320
|
|
|
@@ -1640,11 +1506,11 @@ function track(event, payload) {
|
|
|
1640
1506
|
}
|
|
1641
1507
|
|
|
1642
1508
|
// src/ui/App.tsx
|
|
1643
|
-
import { jsx as jsx13, jsxs as
|
|
1509
|
+
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1644
1510
|
function App() {
|
|
1645
1511
|
const { phase, error, homeScreen, currentStepIndex, steps, inputReq } = useWizard();
|
|
1646
1512
|
const { exit } = useApp();
|
|
1647
|
-
const { columns, rows } =
|
|
1513
|
+
const { columns, rows } = useWindowSize7();
|
|
1648
1514
|
const [showLogs, setShowLogs] = useState6(false);
|
|
1649
1515
|
const finished = phase === "done" || phase === "error";
|
|
1650
1516
|
const currentStep = steps[currentStepIndex];
|
|
@@ -1657,7 +1523,7 @@ function App() {
|
|
|
1657
1523
|
{ isActive: finished }
|
|
1658
1524
|
);
|
|
1659
1525
|
useInput6((_input, key) => {
|
|
1660
|
-
if (phase === "idle" || phase === "
|
|
1526
|
+
if (phase === "idle" || phase === "preflight") return;
|
|
1661
1527
|
if (key.tab) {
|
|
1662
1528
|
setShowLogs(!showLogs);
|
|
1663
1529
|
track("AI Wizard Interaction", {
|
|
@@ -1667,7 +1533,7 @@ function App() {
|
|
|
1667
1533
|
});
|
|
1668
1534
|
}
|
|
1669
1535
|
});
|
|
1670
|
-
const escOwnedElsewhere = phase === "idle" || phase === "
|
|
1536
|
+
const escOwnedElsewhere = phase === "idle" || phase === "awaitingInput" && inputReq?.promptType === "enterToContinue";
|
|
1671
1537
|
useInput6((_input, key) => {
|
|
1672
1538
|
if (escOwnedElsewhere) return;
|
|
1673
1539
|
if (key.escape) {
|
|
@@ -1680,70 +1546,56 @@ function App() {
|
|
|
1680
1546
|
exit();
|
|
1681
1547
|
}
|
|
1682
1548
|
});
|
|
1683
|
-
const mainWindowVisible = phase === "
|
|
1549
|
+
const mainWindowVisible = phase === "running" || phase === "awaitingInput" || phase === "error" || phase === "done";
|
|
1684
1550
|
const flexDirection = columns > 90 ? "row" : "column";
|
|
1685
1551
|
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
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
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
|
-
)
|
|
1552
|
+
return /* @__PURE__ */ jsxs12(
|
|
1553
|
+
Box13,
|
|
1554
|
+
{
|
|
1555
|
+
backgroundColor: COLORS.bg.main,
|
|
1556
|
+
flexDirection: "row",
|
|
1557
|
+
width: columns,
|
|
1558
|
+
minHeight: rows,
|
|
1559
|
+
children: [
|
|
1560
|
+
mainWindowVisible && /* @__PURE__ */ jsxs12(
|
|
1561
|
+
Box13,
|
|
1562
|
+
{
|
|
1563
|
+
flexDirection,
|
|
1564
|
+
width: "100%",
|
|
1565
|
+
justifyContent: "space-between",
|
|
1566
|
+
children: [
|
|
1567
|
+
showLogs ? /* @__PURE__ */ jsx13(Logs, {}) : (
|
|
1568
|
+
/* Fill the space the sidebar/ribbon leaves — width beside the
|
|
1569
|
+
sidebar, height above the ribbon. The height matters even
|
|
1570
|
+
stacked: it is what the prompt's scrolling list measures itself
|
|
1571
|
+
against (see SelectPrompt). */
|
|
1572
|
+
/* @__PURE__ */ jsxs12(
|
|
1573
|
+
Box13,
|
|
1574
|
+
{
|
|
1575
|
+
flexDirection: "column",
|
|
1576
|
+
paddingX: 4,
|
|
1577
|
+
paddingY: 2,
|
|
1578
|
+
width: showSidebar ? 70 : "100%",
|
|
1579
|
+
flexGrow: 1,
|
|
1580
|
+
children: [
|
|
1581
|
+
/* @__PURE__ */ jsx13(Notices, {}),
|
|
1582
|
+
/* @__PURE__ */ jsx13(PromptInput, {}),
|
|
1583
|
+
phase === "running" && showSidebar && /* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx13(CurrentStep, {}) }),
|
|
1584
|
+
phase === "error" && error && /* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsxs12(Text13, { color: COLORS.status.error, children: [
|
|
1585
|
+
"\u2716 ",
|
|
1586
|
+
error
|
|
1587
|
+
] }) })
|
|
1588
|
+
]
|
|
1589
|
+
}
|
|
1590
|
+
)
|
|
1591
|
+
),
|
|
1592
|
+
showSidebar ? /* @__PURE__ */ jsx13(Sidebar, {}) : /* @__PURE__ */ jsx13(Ribbon, {})
|
|
1593
|
+
]
|
|
1594
|
+
}
|
|
1595
|
+
),
|
|
1596
|
+
(phase === "idle" || phase === "preflight") && (homeScreen === "learnMore" ? /* @__PURE__ */ jsx13(LearnMore, {}) : /* @__PURE__ */ jsx13(Welcome, {}))
|
|
1597
|
+
]
|
|
1598
|
+
}
|
|
1747
1599
|
);
|
|
1748
1600
|
}
|
|
1749
1601
|
|
|
@@ -1979,138 +1831,61 @@ async function runWorkflow(workflow, appId) {
|
|
|
1979
1831
|
}
|
|
1980
1832
|
}
|
|
1981
1833
|
|
|
1982
|
-
// src/lib/
|
|
1983
|
-
import {
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
);
|
|
1996
|
-
async function currentApplication() {
|
|
1997
|
-
let raw;
|
|
1834
|
+
// src/lib/algoliaProfile.ts
|
|
1835
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
1836
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
1837
|
+
import { homedir as homedir2 } from "node:os";
|
|
1838
|
+
import { join as join6 } from "node:path";
|
|
1839
|
+
import { parse as parseToml } from "toml";
|
|
1840
|
+
var require3 = createRequire2(import.meta.url);
|
|
1841
|
+
function configPath() {
|
|
1842
|
+
const base = process.env.XDG_CONFIG_HOME || join6(homedir2(), ".config");
|
|
1843
|
+
return join6(base, "algolia", "config.toml");
|
|
1844
|
+
}
|
|
1845
|
+
function profilesFromConfig(tomlText) {
|
|
1846
|
+
let parsed;
|
|
1998
1847
|
try {
|
|
1999
|
-
|
|
1848
|
+
parsed = parseToml(tomlText);
|
|
2000
1849
|
} catch {
|
|
2001
|
-
return
|
|
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
|
-
);
|
|
1850
|
+
return [];
|
|
2033
1851
|
}
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
1852
|
+
const profiles = Object.entries(parsed).filter(
|
|
1853
|
+
([, t]) => typeof t.application_id === "string" && typeof t.api_key === "string"
|
|
1854
|
+
).map(([name, t]) => ({
|
|
1855
|
+
name,
|
|
1856
|
+
appId: t.application_id,
|
|
1857
|
+
apiKey: t.api_key,
|
|
1858
|
+
isDefault: t.default === true
|
|
1859
|
+
}));
|
|
1860
|
+
profiles.sort((a, b) => Number(b.isDefault) - Number(a.isDefault));
|
|
1861
|
+
return profiles.map(({ name, appId, apiKey }) => ({ name, appId, apiKey }));
|
|
1862
|
+
}
|
|
1863
|
+
async function loadActiveProfile() {
|
|
1864
|
+
let profiles;
|
|
2037
1865
|
try {
|
|
2038
|
-
|
|
1866
|
+
profiles = profilesFromConfig(await readFile3(configPath(), "utf8"));
|
|
2039
1867
|
} catch {
|
|
2040
|
-
|
|
1868
|
+
profiles = [];
|
|
2041
1869
|
}
|
|
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) {
|
|
1870
|
+
const profile = profiles[0];
|
|
1871
|
+
if (!profile) {
|
|
2062
1872
|
throw new Error(
|
|
2063
|
-
"
|
|
1873
|
+
"No Algolia profile is configured. Run `npx @algolia/cli auth login` to authenticate."
|
|
2064
1874
|
);
|
|
2065
1875
|
}
|
|
2066
|
-
|
|
2067
|
-
const only = apps[0];
|
|
2068
|
-
logger.info(
|
|
2069
|
-
{ app: only.id },
|
|
2070
|
-
"single application on the account; selecting it"
|
|
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
|
-
}
|
|
2098
|
-
}
|
|
2099
|
-
}
|
|
2100
|
-
async function ensureApplication() {
|
|
2101
|
-
return await currentApplication() ?? await promptForApplication();
|
|
1876
|
+
return profile;
|
|
2102
1877
|
}
|
|
2103
1878
|
|
|
2104
1879
|
// src/workflows/default.ts
|
|
2105
|
-
import { z as
|
|
1880
|
+
import { z as z25 } from "zod";
|
|
2106
1881
|
|
|
2107
1882
|
// src/actions/listIndices.ts
|
|
2108
|
-
import { z as
|
|
2109
|
-
var indicesListSchema =
|
|
2110
|
-
items:
|
|
2111
|
-
|
|
2112
|
-
name:
|
|
2113
|
-
entries:
|
|
1883
|
+
import { z as z3 } from "zod";
|
|
1884
|
+
var indicesListSchema = z3.object({
|
|
1885
|
+
items: z3.array(
|
|
1886
|
+
z3.object({
|
|
1887
|
+
name: z3.string(),
|
|
1888
|
+
entries: z3.number().default(0)
|
|
2114
1889
|
})
|
|
2115
1890
|
)
|
|
2116
1891
|
});
|
|
@@ -2181,12 +1956,12 @@ import "zod";
|
|
|
2181
1956
|
|
|
2182
1957
|
// src/lib/tools/listFiles.ts
|
|
2183
1958
|
import { tool } from "ai";
|
|
2184
|
-
import
|
|
1959
|
+
import z4 from "zod";
|
|
2185
1960
|
import { readdir } from "node:fs/promises";
|
|
2186
1961
|
|
|
2187
1962
|
// src/lib/tools/path.ts
|
|
2188
1963
|
import { lstat } from "node:fs/promises";
|
|
2189
|
-
import { resolve as resolve2, relative, isAbsolute, dirname as dirname3, join as
|
|
1964
|
+
import { resolve as resolve2, relative, isAbsolute, dirname as dirname3, join as join7, sep } from "node:path";
|
|
2190
1965
|
function resolveInRoot(ctx, path) {
|
|
2191
1966
|
const target = resolve2(ctx.cwd, path);
|
|
2192
1967
|
const rel = relative(ctx.root, target);
|
|
@@ -2202,7 +1977,7 @@ async function hasSymlinkParent(ctx, target) {
|
|
|
2202
1977
|
let current = ctx.root;
|
|
2203
1978
|
const parts = relative(ctx.root, dirname3(target)).split(sep).filter(Boolean);
|
|
2204
1979
|
for (const part of parts) {
|
|
2205
|
-
current =
|
|
1980
|
+
current = join7(current, part);
|
|
2206
1981
|
try {
|
|
2207
1982
|
if ((await lstat(current)).isSymbolicLink()) return true;
|
|
2208
1983
|
} catch (err) {
|
|
@@ -2217,7 +1992,7 @@ async function hasSymlinkParent(ctx, target) {
|
|
|
2217
1992
|
function listFilesTool(ctx) {
|
|
2218
1993
|
return tool({
|
|
2219
1994
|
description: "List files in the current working directory",
|
|
2220
|
-
inputSchema:
|
|
1995
|
+
inputSchema: z4.object(),
|
|
2221
1996
|
execute: async () => {
|
|
2222
1997
|
logger.info("called listFiles tool");
|
|
2223
1998
|
if (++ctx.counts.list > ctx.limits.list) {
|
|
@@ -2233,13 +2008,13 @@ function listFilesTool(ctx) {
|
|
|
2233
2008
|
|
|
2234
2009
|
// src/lib/tools/changeDirectory.ts
|
|
2235
2010
|
import { tool as tool2 } from "ai";
|
|
2236
|
-
import
|
|
2011
|
+
import z5 from "zod";
|
|
2237
2012
|
import { stat } from "node:fs/promises";
|
|
2238
2013
|
function changeDirectoryTool(ctx) {
|
|
2239
2014
|
return tool2({
|
|
2240
2015
|
description: "Change the current working directory. Subsequent file operations resolve relative to it. Returns the new working directory.",
|
|
2241
|
-
inputSchema:
|
|
2242
|
-
path:
|
|
2016
|
+
inputSchema: z5.object({
|
|
2017
|
+
path: z5.string().describe("Directory to change into")
|
|
2243
2018
|
}),
|
|
2244
2019
|
execute: async ({ path }) => {
|
|
2245
2020
|
logger.info({ path }, "called changeDirectory tool");
|
|
@@ -2261,13 +2036,13 @@ function changeDirectoryTool(ctx) {
|
|
|
2261
2036
|
|
|
2262
2037
|
// src/lib/tools/reportStatus.ts
|
|
2263
2038
|
import { tool as tool3 } from "ai";
|
|
2264
|
-
import
|
|
2039
|
+
import z6 from "zod";
|
|
2265
2040
|
function reportStatusTool(output) {
|
|
2266
2041
|
return tool3({
|
|
2267
2042
|
description: "Report the status of your execution. Return a reason in case of failure.",
|
|
2268
|
-
inputSchema:
|
|
2269
|
-
status:
|
|
2270
|
-
reason:
|
|
2043
|
+
inputSchema: z6.object({
|
|
2044
|
+
status: z6.enum(["success", "fail"]),
|
|
2045
|
+
reason: z6.string().optional(),
|
|
2271
2046
|
output
|
|
2272
2047
|
}),
|
|
2273
2048
|
execute: async ({ status, reason, output: output2 }) => {
|
|
@@ -2279,8 +2054,8 @@ function reportStatusTool(output) {
|
|
|
2279
2054
|
|
|
2280
2055
|
// src/lib/tools/readFile.ts
|
|
2281
2056
|
import { tool as tool4 } from "ai";
|
|
2282
|
-
import
|
|
2283
|
-
import { readFile as
|
|
2057
|
+
import z7 from "zod";
|
|
2058
|
+
import { readFile as readFile4 } from "node:fs/promises";
|
|
2284
2059
|
|
|
2285
2060
|
// src/lib/tools/env.ts
|
|
2286
2061
|
import { basename } from "node:path";
|
|
@@ -2307,8 +2082,8 @@ function redactEnvValues(content) {
|
|
|
2307
2082
|
function readFileTool(ctx) {
|
|
2308
2083
|
return tool4({
|
|
2309
2084
|
description: "Read the contents of a file at the given path",
|
|
2310
|
-
inputSchema:
|
|
2311
|
-
filePath:
|
|
2085
|
+
inputSchema: z7.object({
|
|
2086
|
+
filePath: z7.string().describe("Path to the file to read")
|
|
2312
2087
|
}),
|
|
2313
2088
|
execute: async ({ filePath }) => {
|
|
2314
2089
|
if (++ctx.counts.read > ctx.limits.read) {
|
|
@@ -2318,7 +2093,7 @@ function readFileTool(ctx) {
|
|
|
2318
2093
|
const resolved = resolveInRoot(ctx, filePath);
|
|
2319
2094
|
if (!resolved.ok) return resolved.error;
|
|
2320
2095
|
try {
|
|
2321
|
-
const content = await
|
|
2096
|
+
const content = await readFile4(resolved.target, "utf8");
|
|
2322
2097
|
return isEnvFile(resolved.target) ? redactEnvValues(content) : content;
|
|
2323
2098
|
} catch (err) {
|
|
2324
2099
|
return `Error reading ${filePath}: ${err.message}`;
|
|
@@ -2329,15 +2104,15 @@ function readFileTool(ctx) {
|
|
|
2329
2104
|
|
|
2330
2105
|
// src/lib/tools/writeFile.ts
|
|
2331
2106
|
import { tool as tool5 } from "ai";
|
|
2332
|
-
import
|
|
2107
|
+
import z8 from "zod";
|
|
2333
2108
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
|
|
2334
2109
|
import { dirname as dirname4 } from "node:path";
|
|
2335
2110
|
function writeFileTool(ctx) {
|
|
2336
2111
|
return tool5({
|
|
2337
2112
|
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:
|
|
2113
|
+
inputSchema: z8.object({
|
|
2114
|
+
filePath: z8.string().describe("Path to the file to write"),
|
|
2115
|
+
content: z8.string().describe("Content to write to the file")
|
|
2341
2116
|
}),
|
|
2342
2117
|
execute: async ({ filePath, content }) => {
|
|
2343
2118
|
logger.info({ filePath }, "called writeFile tool");
|
|
@@ -2362,95 +2137,9 @@ function writeFileTool(ctx) {
|
|
|
2362
2137
|
|
|
2363
2138
|
// src/lib/tools/writeAlgoliaCredentials.ts
|
|
2364
2139
|
import { tool as tool6 } from "ai";
|
|
2365
|
-
import
|
|
2366
|
-
import { mkdir as mkdir4, readFile as
|
|
2140
|
+
import z9 from "zod";
|
|
2141
|
+
import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile4 } from "node:fs/promises";
|
|
2367
2142
|
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
2143
|
var APP_ID_VAR = "ALGOLIA_APPLICATION_ID";
|
|
2455
2144
|
var API_KEY_VAR = "ALGOLIA_WRITE_API_KEY";
|
|
2456
2145
|
function appendEnv(content, entries) {
|
|
@@ -2464,9 +2153,9 @@ function hasEnv(content, name) {
|
|
|
2464
2153
|
}
|
|
2465
2154
|
function writeCredentialsTool(ctx) {
|
|
2466
2155
|
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:
|
|
2156
|
+
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.`,
|
|
2157
|
+
inputSchema: z9.object({
|
|
2158
|
+
filePath: z9.string().describe(
|
|
2470
2159
|
'Path to the env file to write credentials into (e.g. ".env")'
|
|
2471
2160
|
)
|
|
2472
2161
|
}),
|
|
@@ -2474,17 +2163,11 @@ function writeCredentialsTool(ctx) {
|
|
|
2474
2163
|
logger.info({ filePath }, "called writeCredentials tool");
|
|
2475
2164
|
const resolved = resolveInRoot(ctx, filePath);
|
|
2476
2165
|
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;
|
|
2166
|
+
let profile;
|
|
2483
2167
|
try {
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
return `Error: could not resolve Algolia credentials (${err.message}). Ask the user to authenticate with the Algolia CLI first.`;
|
|
2168
|
+
profile = await loadActiveProfile();
|
|
2169
|
+
} catch {
|
|
2170
|
+
return "Error: no Algolia profile is configured, so credentials cannot be written. Ask the user to authenticate with the Algolia CLI first.";
|
|
2488
2171
|
}
|
|
2489
2172
|
try {
|
|
2490
2173
|
if (await hasSymlinkParent(ctx, resolved.target)) {
|
|
@@ -2492,7 +2175,7 @@ function writeCredentialsTool(ctx) {
|
|
|
2492
2175
|
}
|
|
2493
2176
|
let existing = "";
|
|
2494
2177
|
try {
|
|
2495
|
-
existing = await
|
|
2178
|
+
existing = await readFile5(resolved.target, "utf8");
|
|
2496
2179
|
} catch (err) {
|
|
2497
2180
|
if (err.code !== "ENOENT") throw err;
|
|
2498
2181
|
}
|
|
@@ -2503,8 +2186,8 @@ function writeCredentialsTool(ctx) {
|
|
|
2503
2186
|
return `Skipped: ${filePath} already defines ${present.join(" and ")}. Leaving existing credentials untouched.`;
|
|
2504
2187
|
}
|
|
2505
2188
|
const envWithCredentials = appendEnv(existing, [
|
|
2506
|
-
[APP_ID_VAR, appId],
|
|
2507
|
-
[API_KEY_VAR,
|
|
2189
|
+
[APP_ID_VAR, profile.appId],
|
|
2190
|
+
[API_KEY_VAR, profile.apiKey]
|
|
2508
2191
|
]);
|
|
2509
2192
|
await mkdir4(dirname5(resolved.target), { recursive: true });
|
|
2510
2193
|
await writeFile4(resolved.target, envWithCredentials, "utf8");
|
|
@@ -2518,16 +2201,16 @@ function writeCredentialsTool(ctx) {
|
|
|
2518
2201
|
|
|
2519
2202
|
// src/lib/tools/searchFiles.ts
|
|
2520
2203
|
import { tool as tool7 } from "ai";
|
|
2521
|
-
import
|
|
2522
|
-
import { readdir as readdir2, readFile as
|
|
2523
|
-
import { join as
|
|
2204
|
+
import z10 from "zod";
|
|
2205
|
+
import { readdir as readdir2, readFile as readFile6 } from "node:fs/promises";
|
|
2206
|
+
import { join as join8 } from "node:path";
|
|
2524
2207
|
var MAX_QUERY_LENGTH = 1e3;
|
|
2525
2208
|
async function walkFiles(dir) {
|
|
2526
2209
|
const skip = /* @__PURE__ */ new Set(["node_modules", ".git", "dist"]);
|
|
2527
2210
|
const out = [];
|
|
2528
2211
|
for (const e of await readdir2(dir, { withFileTypes: true })) {
|
|
2529
2212
|
if (e.name.startsWith(".") || skip.has(e.name)) continue;
|
|
2530
|
-
const full =
|
|
2213
|
+
const full = join8(dir, e.name);
|
|
2531
2214
|
if (e.isDirectory()) out.push(...await walkFiles(full));
|
|
2532
2215
|
else if (e.isFile()) out.push(full);
|
|
2533
2216
|
}
|
|
@@ -2536,9 +2219,9 @@ async function walkFiles(dir) {
|
|
|
2536
2219
|
function searchFilesTool(ctx) {
|
|
2537
2220
|
return tool7({
|
|
2538
2221
|
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:
|
|
2222
|
+
inputSchema: z10.object({
|
|
2223
|
+
query: z10.string().describe("JavaScript RegExp pattern to search for"),
|
|
2224
|
+
path: z10.string().optional().describe("Directory to search in (default: cwd)")
|
|
2542
2225
|
}),
|
|
2543
2226
|
execute: async ({ query, path = "." }) => {
|
|
2544
2227
|
logger.info({ query, path }, "called searchFiles tool");
|
|
@@ -2560,7 +2243,7 @@ function searchFilesTool(ctx) {
|
|
|
2560
2243
|
for (const file of await walkFiles(resolved.target)) {
|
|
2561
2244
|
let content;
|
|
2562
2245
|
try {
|
|
2563
|
-
content = await
|
|
2246
|
+
content = await readFile6(file, "utf8");
|
|
2564
2247
|
} catch {
|
|
2565
2248
|
continue;
|
|
2566
2249
|
}
|
|
@@ -2582,7 +2265,7 @@ function searchFilesTool(ctx) {
|
|
|
2582
2265
|
|
|
2583
2266
|
// src/lib/tools/verifyImplementation.ts
|
|
2584
2267
|
import { tool as tool8 } from "ai";
|
|
2585
|
-
import
|
|
2268
|
+
import z11 from "zod";
|
|
2586
2269
|
|
|
2587
2270
|
// src/lib/tools/utils/runCommand.ts
|
|
2588
2271
|
import { spawn as spawn2 } from "node:child_process";
|
|
@@ -2604,9 +2287,9 @@ function runCommand(command, args, cwd) {
|
|
|
2604
2287
|
}
|
|
2605
2288
|
|
|
2606
2289
|
// src/lib/tools/utils/packageManager.ts
|
|
2607
|
-
import { readFile as
|
|
2290
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
2608
2291
|
import { existsSync } from "node:fs";
|
|
2609
|
-
import { join as
|
|
2292
|
+
import { join as join9 } from "node:path";
|
|
2610
2293
|
var LOCKFILES = [
|
|
2611
2294
|
["pnpm-lock.yaml", "pnpm"],
|
|
2612
2295
|
["yarn.lock", "yarn"],
|
|
@@ -2615,13 +2298,13 @@ var LOCKFILES = [
|
|
|
2615
2298
|
["package-lock.json", "npm"]
|
|
2616
2299
|
];
|
|
2617
2300
|
async function readPackageJson(cwd = process.cwd()) {
|
|
2618
|
-
return JSON.parse(await
|
|
2301
|
+
return JSON.parse(await readFile7(join9(cwd, "package.json"), "utf8"));
|
|
2619
2302
|
}
|
|
2620
2303
|
function packageManagerFrom(pkg) {
|
|
2621
2304
|
return pkg.packageManager?.split("@")[0] ?? "npm";
|
|
2622
2305
|
}
|
|
2623
2306
|
function packageManagerFromLockfile(cwd) {
|
|
2624
|
-
return LOCKFILES.find(([file]) => existsSync(
|
|
2307
|
+
return LOCKFILES.find(([file]) => existsSync(join9(cwd, file)))?.[1];
|
|
2625
2308
|
}
|
|
2626
2309
|
async function detectPackageManager(cwd) {
|
|
2627
2310
|
try {
|
|
@@ -2662,7 +2345,7 @@ async function runRepoVerificationCheck() {
|
|
|
2662
2345
|
function verifyImplementationTool() {
|
|
2663
2346
|
return tool8({
|
|
2664
2347
|
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:
|
|
2348
|
+
inputSchema: z11.object(),
|
|
2666
2349
|
execute: async () => {
|
|
2667
2350
|
logger.info("called verifyImplementation tool");
|
|
2668
2351
|
return runRepoVerificationCheck();
|
|
@@ -2676,7 +2359,7 @@ import { createAnthropic } from "@ai-sdk/anthropic";
|
|
|
2676
2359
|
import { nanoid as nanoid2 } from "nanoid";
|
|
2677
2360
|
import { mkdir as mkdir5, writeFile as writeFile5 } from "node:fs/promises";
|
|
2678
2361
|
import { dirname as dirname6 } from "node:path";
|
|
2679
|
-
import
|
|
2362
|
+
import z12 from "zod";
|
|
2680
2363
|
var DATA_DIR = ".algolia-wizard/data";
|
|
2681
2364
|
var RECORD_MODEL = "claude-haiku-4-5";
|
|
2682
2365
|
var MAX_RECORDS = 100;
|
|
@@ -2688,17 +2371,17 @@ var anthropic = createAnthropic({
|
|
|
2688
2371
|
function generateRecordTool(ctx) {
|
|
2689
2372
|
return tool9({
|
|
2690
2373
|
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:
|
|
2374
|
+
inputSchema: z12.object({
|
|
2375
|
+
entityName: z12.string().describe("Name of the entity to generate records for."),
|
|
2376
|
+
attributes: z12.array(z12.string()).describe("Attribute names each record must contain."),
|
|
2377
|
+
count: z12.number().int().min(1).max(MAX_RECORDS).default(10).describe(`How many records to generate (max ${MAX_RECORDS}).`),
|
|
2378
|
+
hint: z12.string().optional().describe("Optional context to steer realistic values.")
|
|
2696
2379
|
}),
|
|
2697
2380
|
execute: async ({ entityName, attributes, count, hint }) => {
|
|
2698
2381
|
logger.info({ entityName, count }, "called generateRecord tool");
|
|
2699
2382
|
try {
|
|
2700
|
-
const value =
|
|
2701
|
-
const recordSchema =
|
|
2383
|
+
const value = z12.union([z12.string(), z12.number(), z12.boolean(), z12.null()]);
|
|
2384
|
+
const recordSchema = z12.object(
|
|
2702
2385
|
Object.fromEntries(attributes.map((attr) => [attr, value]))
|
|
2703
2386
|
);
|
|
2704
2387
|
const generateBatch = async (batchCount) => {
|
|
@@ -2708,8 +2391,8 @@ function generateRecordTool(ctx) {
|
|
|
2708
2391
|
const { output } = await generateText({
|
|
2709
2392
|
model: anthropic(RECORD_MODEL),
|
|
2710
2393
|
output: Output.object({
|
|
2711
|
-
schema:
|
|
2712
|
-
records:
|
|
2394
|
+
schema: z12.object({
|
|
2395
|
+
records: z12.array(recordSchema).length(batchCount)
|
|
2713
2396
|
})
|
|
2714
2397
|
}),
|
|
2715
2398
|
prompt: [
|
|
@@ -2767,12 +2450,12 @@ function generateRecordTool(ctx) {
|
|
|
2767
2450
|
|
|
2768
2451
|
// src/lib/tools/notifyUser.ts
|
|
2769
2452
|
import { tool as tool10 } from "ai";
|
|
2770
|
-
import
|
|
2453
|
+
import z13 from "zod";
|
|
2771
2454
|
function notifyUserTool() {
|
|
2772
2455
|
return tool10({
|
|
2773
2456
|
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:
|
|
2457
|
+
inputSchema: z13.object({
|
|
2458
|
+
message: z13.string().describe(
|
|
2776
2459
|
"Short, plain-language description of what you are doing now."
|
|
2777
2460
|
)
|
|
2778
2461
|
}),
|
|
@@ -2952,10 +2635,10 @@ async function runAgent(req) {
|
|
|
2952
2635
|
}
|
|
2953
2636
|
|
|
2954
2637
|
// src/actions/detectLanguage.ts
|
|
2955
|
-
import
|
|
2956
|
-
var detectLanguageSchema =
|
|
2957
|
-
languages:
|
|
2958
|
-
frameworks:
|
|
2638
|
+
import z16 from "zod";
|
|
2639
|
+
var detectLanguageSchema = z16.object({
|
|
2640
|
+
languages: z16.array(z16.object({ name: z16.string(), version: z16.string() })),
|
|
2641
|
+
frameworks: z16.array(z16.object({ name: z16.string(), version: z16.string() }))
|
|
2959
2642
|
});
|
|
2960
2643
|
var detectLanguage = () => runAgent({
|
|
2961
2644
|
instructions: [
|
|
@@ -2973,31 +2656,31 @@ var detectLanguage = () => runAgent({
|
|
|
2973
2656
|
});
|
|
2974
2657
|
|
|
2975
2658
|
// src/actions/analyzeCodebase.ts
|
|
2976
|
-
import
|
|
2659
|
+
import z17 from "zod";
|
|
2977
2660
|
var READONLY_TOOLS = [
|
|
2978
2661
|
"listFiles",
|
|
2979
2662
|
"changeDirectory",
|
|
2980
2663
|
"readFile",
|
|
2981
2664
|
"searchFiles"
|
|
2982
2665
|
];
|
|
2983
|
-
var ingestionAnalysisSchema =
|
|
2984
|
-
ingestionAnalysis:
|
|
2985
|
-
|
|
2986
|
-
name:
|
|
2987
|
-
paths:
|
|
2666
|
+
var ingestionAnalysisSchema = z17.object({
|
|
2667
|
+
ingestionAnalysis: z17.array(
|
|
2668
|
+
z17.object({
|
|
2669
|
+
name: z17.string(),
|
|
2670
|
+
paths: z17.array(z17.string()),
|
|
2988
2671
|
// indexable fields the agent found for this entity
|
|
2989
|
-
attributes:
|
|
2672
|
+
attributes: z17.array(z17.string())
|
|
2990
2673
|
})
|
|
2991
2674
|
)
|
|
2992
2675
|
});
|
|
2993
|
-
var searchImplementationAnalysisSchema =
|
|
2994
|
-
searchImplementationAnalysis:
|
|
2676
|
+
var searchImplementationAnalysisSchema = z17.object({
|
|
2677
|
+
searchImplementationAnalysis: z17.string()
|
|
2995
2678
|
});
|
|
2996
|
-
var verificationSchema =
|
|
2997
|
-
verification:
|
|
2679
|
+
var verificationSchema = z17.object({
|
|
2680
|
+
verification: z17.array(z17.string())
|
|
2998
2681
|
});
|
|
2999
2682
|
var confirmedEntitiesFieldSchema = ingestionAnalysisSchema.shape.ingestionAnalysis.optional();
|
|
3000
|
-
var analyzeCodebaseSchema =
|
|
2683
|
+
var analyzeCodebaseSchema = z17.object({
|
|
3001
2684
|
ingestionAnalysis: ingestionAnalysisSchema.shape.ingestionAnalysis.optional(),
|
|
3002
2685
|
searchImplementationAnalysis: searchImplementationAnalysisSchema.shape.searchImplementationAnalysis.optional(),
|
|
3003
2686
|
verification: verificationSchema.shape.verification.optional(),
|
|
@@ -3059,7 +2742,7 @@ async function runAnalysis(mode, extraInstructions = []) {
|
|
|
3059
2742
|
// package.json
|
|
3060
2743
|
var package_default = {
|
|
3061
2744
|
name: "@algolia/wizard",
|
|
3062
|
-
version: "0.8.0-rc.58.
|
|
2745
|
+
version: "0.8.0-rc.58.44",
|
|
3063
2746
|
description: "Magically implement Algolia functionality in your codebase",
|
|
3064
2747
|
type: "module",
|
|
3065
2748
|
engines: {
|
|
@@ -3107,6 +2790,7 @@ var package_default = {
|
|
|
3107
2790
|
dependencies: {
|
|
3108
2791
|
"@ai-sdk/anthropic": "^3.0.81",
|
|
3109
2792
|
"@ai-sdk/openai-compatible": "^2.0.47",
|
|
2793
|
+
"@algolia/cli": "^5.11.0",
|
|
3110
2794
|
"@hono/node-server": "^2.0.10",
|
|
3111
2795
|
"@mishieck/ink-titled-box": "^0.4.2",
|
|
3112
2796
|
"@segment/analytics-node": "^3.1.0",
|
|
@@ -3121,6 +2805,7 @@ var package_default = {
|
|
|
3121
2805
|
nanoid: "^5.1.15",
|
|
3122
2806
|
pino: "^10.3.1",
|
|
3123
2807
|
react: "^19.2.7",
|
|
2808
|
+
toml: "^4.1.1",
|
|
3124
2809
|
varlock: "^1.5.1",
|
|
3125
2810
|
zod: "^4.4.3",
|
|
3126
2811
|
zustand: "^5.0.14"
|
|
@@ -3178,8 +2863,8 @@ async function askList(ctx, prompt, { required = false } = {}) {
|
|
|
3178
2863
|
}
|
|
3179
2864
|
|
|
3180
2865
|
// src/actions/confirmLanguage.ts
|
|
3181
|
-
import
|
|
3182
|
-
var confirmLanguageSchema =
|
|
2866
|
+
import z19 from "zod";
|
|
2867
|
+
var confirmLanguageSchema = z19.object({
|
|
3183
2868
|
languages: detectLanguageSchema.shape.languages
|
|
3184
2869
|
});
|
|
3185
2870
|
async function confirmLanguage(ctx) {
|
|
@@ -3200,8 +2885,8 @@ async function confirmLanguage(ctx) {
|
|
|
3200
2885
|
}
|
|
3201
2886
|
|
|
3202
2887
|
// src/actions/confirmFramework.ts
|
|
3203
|
-
import
|
|
3204
|
-
var confirmFrameworkSchema =
|
|
2888
|
+
import z20 from "zod";
|
|
2889
|
+
var confirmFrameworkSchema = z20.object({
|
|
3205
2890
|
frameworks: detectLanguageSchema.shape.frameworks
|
|
3206
2891
|
});
|
|
3207
2892
|
var CURATED_FRAMEWORKS = [
|
|
@@ -3329,8 +3014,8 @@ async function promptUser(ctx, params) {
|
|
|
3329
3014
|
}
|
|
3330
3015
|
|
|
3331
3016
|
// src/actions/confirmEntities.ts
|
|
3332
|
-
import
|
|
3333
|
-
var confirmEntitiesSchema =
|
|
3017
|
+
import z21 from "zod";
|
|
3018
|
+
var confirmEntitiesSchema = z21.object({
|
|
3334
3019
|
// Final detection — the focused re-run may supersede project-scan's.
|
|
3335
3020
|
ingestionAnalysis: ingestionAnalysisSchema.shape.ingestionAnalysis.optional(),
|
|
3336
3021
|
confirmedEntities: confirmedEntitiesFieldSchema
|
|
@@ -3400,15 +3085,15 @@ async function confirmEntities(ctx) {
|
|
|
3400
3085
|
}
|
|
3401
3086
|
|
|
3402
3087
|
// src/actions/review.ts
|
|
3403
|
-
import { z as
|
|
3404
|
-
var reviewSchema =
|
|
3088
|
+
import { z as z22 } from "zod";
|
|
3089
|
+
var reviewSchema = z22.object({
|
|
3405
3090
|
// Broad, high-level takeaways grouped by theme (e.g. ingestion, search UI),
|
|
3406
3091
|
// not one entry per workflow step — a step's raw output can be a long,
|
|
3407
3092
|
// multi-paragraph blob (see implement.ts's summaries.join), and mirroring
|
|
3408
3093
|
// that 1:1 is what made the old per-step summary an unreadable wall of text.
|
|
3409
|
-
summaryPoints:
|
|
3410
|
-
reviewPrompt:
|
|
3411
|
-
nextSteps:
|
|
3094
|
+
summaryPoints: z22.array(z22.string()),
|
|
3095
|
+
reviewPrompt: z22.string(),
|
|
3096
|
+
nextSteps: z22.array(z22.string())
|
|
3412
3097
|
});
|
|
3413
3098
|
function formatCompletedSteps(steps) {
|
|
3414
3099
|
if (!steps.length) return "(no prior steps completed)";
|
|
@@ -3459,16 +3144,16 @@ ${formatCompletedSteps(ctx.completedSteps)}`,
|
|
|
3459
3144
|
};
|
|
3460
3145
|
|
|
3461
3146
|
// src/actions/implement.ts
|
|
3462
|
-
import
|
|
3147
|
+
import z24 from "zod";
|
|
3463
3148
|
|
|
3464
3149
|
// src/lib/worktree.ts
|
|
3465
3150
|
import { execFile, spawn as spawn3 } from "node:child_process";
|
|
3466
|
-
import { copyFile, mkdir as mkdir6, readdir as readdir3, readFile as
|
|
3151
|
+
import { copyFile, mkdir as mkdir6, readdir as readdir3, readFile as readFile8, stat as stat2, writeFile as writeFile6 } from "node:fs/promises";
|
|
3467
3152
|
import {
|
|
3468
3153
|
basename as basename2,
|
|
3469
3154
|
dirname as dirname7,
|
|
3470
3155
|
isAbsolute as isAbsolute2,
|
|
3471
|
-
join as
|
|
3156
|
+
join as join10,
|
|
3472
3157
|
relative as relative2,
|
|
3473
3158
|
resolve as resolve3
|
|
3474
3159
|
} from "node:path";
|
|
@@ -3502,7 +3187,7 @@ async function isWorkingTreeDirty(repoRoot) {
|
|
|
3502
3187
|
return out.trim().length > 0;
|
|
3503
3188
|
}
|
|
3504
3189
|
async function pruneOldWorktrees(repoRoot) {
|
|
3505
|
-
const dir =
|
|
3190
|
+
const dir = join10(stateDir(repoRoot), "worktrees");
|
|
3506
3191
|
const stale = (await readdir3(dir).catch(() => [])).filter((name) => /^wizard-implement-\d+$/.test(name)).sort().reverse().slice(MAX_WIZARD_WORKTREES - 1);
|
|
3507
3192
|
for (const slug of stale) {
|
|
3508
3193
|
const branch = slug.replace("wizard-implement-", WIZARD_BRANCH_PREFIX);
|
|
@@ -3513,7 +3198,7 @@ async function pruneOldWorktrees(repoRoot) {
|
|
|
3513
3198
|
"worktree",
|
|
3514
3199
|
"remove",
|
|
3515
3200
|
"--force",
|
|
3516
|
-
|
|
3201
|
+
join10(dir, slug)
|
|
3517
3202
|
]);
|
|
3518
3203
|
await git(["-C", repoRoot, "branch", "-D", branch]);
|
|
3519
3204
|
} catch (err) {
|
|
@@ -3527,7 +3212,7 @@ async function pruneOldWorktrees(repoRoot) {
|
|
|
3527
3212
|
async function createWorktree(repoRoot) {
|
|
3528
3213
|
const branch = `${WIZARD_BRANCH_PREFIX}${Date.now()}`;
|
|
3529
3214
|
const dirSlug = branch.replace(/\//g, "-");
|
|
3530
|
-
const path =
|
|
3215
|
+
const path = join10(stateDir(repoRoot), "worktrees", dirSlug);
|
|
3531
3216
|
await git(["-C", repoRoot, "worktree", "prune"]);
|
|
3532
3217
|
await pruneOldWorktrees(repoRoot);
|
|
3533
3218
|
await mkdir6(dirname7(path), { recursive: true });
|
|
@@ -3647,8 +3332,8 @@ async function copyUploadIntoWorktree(repoRoot, worktreePath, ingestDir, sourceP
|
|
|
3647
3332
|
} catch {
|
|
3648
3333
|
return { ok: false, reason: `"${sourcePath}" does not exist` };
|
|
3649
3334
|
}
|
|
3650
|
-
const relPath =
|
|
3651
|
-
const dest =
|
|
3335
|
+
const relPath = join10(ingestDir, basename2(source));
|
|
3336
|
+
const dest = join10(worktreePath, relPath);
|
|
3652
3337
|
try {
|
|
3653
3338
|
await mkdir6(dirname7(dest), { recursive: true });
|
|
3654
3339
|
await copyFile(source, dest);
|
|
@@ -3664,10 +3349,10 @@ function hasEnvVar(content, name) {
|
|
|
3664
3349
|
return new RegExp(`^(\\s*(?:export\\s+)?${name})\\s*=`, "m").test(content);
|
|
3665
3350
|
}
|
|
3666
3351
|
async function writeSearchEnvValues(worktreePath, vars) {
|
|
3667
|
-
const target =
|
|
3352
|
+
const target = join10(worktreePath, ".env");
|
|
3668
3353
|
let existing = "";
|
|
3669
3354
|
try {
|
|
3670
|
-
existing = await
|
|
3355
|
+
existing = await readFile8(target, "utf8");
|
|
3671
3356
|
} catch (err) {
|
|
3672
3357
|
if (err.code !== "ENOENT") throw err;
|
|
3673
3358
|
}
|
|
@@ -3735,15 +3420,63 @@ async function confirmDirtyWorkingTree(ctx, repoRoot) {
|
|
|
3735
3420
|
}
|
|
3736
3421
|
}
|
|
3737
3422
|
|
|
3423
|
+
// src/lib/algoliaApiKey.ts
|
|
3424
|
+
import { z as z23 } from "zod";
|
|
3425
|
+
var SAFE_ACLS = /* @__PURE__ */ new Set(["search", "browse", "listIndexes"]);
|
|
3426
|
+
var apiKeySchema = z23.object({
|
|
3427
|
+
value: z23.string().min(1),
|
|
3428
|
+
acl: z23.array(z23.string()).default([]),
|
|
3429
|
+
indexes: z23.array(z23.string()).default([])
|
|
3430
|
+
});
|
|
3431
|
+
var apiKeyListSchema = z23.object({
|
|
3432
|
+
items: z23.array(apiKeySchema).optional(),
|
|
3433
|
+
keys: z23.array(apiKeySchema).optional()
|
|
3434
|
+
}).transform((o) => o.items ?? o.keys ?? []);
|
|
3435
|
+
var createdKeySchema = z23.object({
|
|
3436
|
+
key: z23.string().min(1).optional(),
|
|
3437
|
+
value: z23.string().min(1).optional()
|
|
3438
|
+
});
|
|
3439
|
+
function canReuse(key, index) {
|
|
3440
|
+
return key.acl.includes("search") && key.acl.every((acl) => SAFE_ACLS.has(acl)) && (key.indexes.length === 0 || key.indexes.includes("*") || key.indexes.includes(index));
|
|
3441
|
+
}
|
|
3442
|
+
async function createSearchKey(index) {
|
|
3443
|
+
const stdout = await runAlgoliaCli([
|
|
3444
|
+
"apikeys",
|
|
3445
|
+
"create",
|
|
3446
|
+
"--indices",
|
|
3447
|
+
index,
|
|
3448
|
+
"--acl",
|
|
3449
|
+
"search,browse",
|
|
3450
|
+
"--description",
|
|
3451
|
+
`wizard search-only key for ${index}`,
|
|
3452
|
+
"-o",
|
|
3453
|
+
"json"
|
|
3454
|
+
]);
|
|
3455
|
+
const { key, value } = createdKeySchema.parse(JSON.parse(stdout));
|
|
3456
|
+
const created = key ?? value;
|
|
3457
|
+
if (!created) throw new Error("apikeys create returned no key value");
|
|
3458
|
+
return created;
|
|
3459
|
+
}
|
|
3460
|
+
async function resolveSearchOnlyKey(index) {
|
|
3461
|
+
const stdout = await runAlgoliaCli(["apikeys", "list", "-o", "json"]);
|
|
3462
|
+
const existing = apiKeyListSchema.parse(JSON.parse(stdout)).find((key) => canReuse(key, index))?.value;
|
|
3463
|
+
if (existing) {
|
|
3464
|
+
logger.info({ index }, "reusing existing search-only API key");
|
|
3465
|
+
return existing;
|
|
3466
|
+
}
|
|
3467
|
+
logger.info({ index }, "no reusable search-only key found; creating one");
|
|
3468
|
+
return createSearchKey(index);
|
|
3469
|
+
}
|
|
3470
|
+
|
|
3738
3471
|
// src/lib/algoliaDocs.ts
|
|
3739
3472
|
import { readFileSync, readdirSync, existsSync as existsSync2 } from "node:fs";
|
|
3740
|
-
import { dirname as dirname8, join as
|
|
3473
|
+
import { dirname as dirname8, join as join11 } from "node:path";
|
|
3741
3474
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
3742
|
-
var DOCS_SUBPATH =
|
|
3475
|
+
var DOCS_SUBPATH = join11("docs", "algolia-sdk");
|
|
3743
3476
|
function findDocsDir() {
|
|
3744
3477
|
let dir = dirname8(fileURLToPath2(import.meta.url));
|
|
3745
3478
|
for (; ; ) {
|
|
3746
|
-
const candidate =
|
|
3479
|
+
const candidate = join11(dir, DOCS_SUBPATH);
|
|
3747
3480
|
if (existsSync2(candidate)) return candidate;
|
|
3748
3481
|
const parent = dirname8(dir);
|
|
3749
3482
|
if (parent === dir) return void 0;
|
|
@@ -3766,7 +3499,7 @@ function loadAlgoliaDoc(language) {
|
|
|
3766
3499
|
);
|
|
3767
3500
|
return "";
|
|
3768
3501
|
}
|
|
3769
|
-
return readFileSync(
|
|
3502
|
+
return readFileSync(join11(docsDir, files[0]), "utf8").trim();
|
|
3770
3503
|
}
|
|
3771
3504
|
function getNamedDoc(name, language) {
|
|
3772
3505
|
const docsDir = findDocsDir();
|
|
@@ -3774,7 +3507,7 @@ function getNamedDoc(name, language) {
|
|
|
3774
3507
|
logger.warn("docs/algolia-sdk not found");
|
|
3775
3508
|
return "";
|
|
3776
3509
|
}
|
|
3777
|
-
const file =
|
|
3510
|
+
const file = join11(docsDir, `${name}-${language}.md`);
|
|
3778
3511
|
if (!existsSync2(file)) {
|
|
3779
3512
|
logger.warn({ name, language }, "named SDK reference not found");
|
|
3780
3513
|
return "";
|
|
@@ -3801,50 +3534,50 @@ function shellQuote(value) {
|
|
|
3801
3534
|
}
|
|
3802
3535
|
|
|
3803
3536
|
// src/actions/implement.ts
|
|
3804
|
-
var implementSchema =
|
|
3805
|
-
filesChanged:
|
|
3806
|
-
summary:
|
|
3537
|
+
var implementSchema = z24.object({
|
|
3538
|
+
filesChanged: z24.array(z24.string()),
|
|
3539
|
+
summary: z24.string(),
|
|
3807
3540
|
// Absolute path to the throwaway worktree holding the generated changes, so
|
|
3808
3541
|
// the user can open it (`cd <worktreePath>`) or inspect the diff
|
|
3809
3542
|
// (`git -C <worktreePath> status/diff`).
|
|
3810
|
-
worktreePath:
|
|
3811
|
-
ingestCommand:
|
|
3543
|
+
worktreePath: z24.string().optional(),
|
|
3544
|
+
ingestCommand: z24.string().optional(),
|
|
3812
3545
|
// True when the user accepted the run-now prompt and the wizard executed the
|
|
3813
3546
|
// ingestion script; downstream steps use this to avoid telling the user to run
|
|
3814
3547
|
// a script that already ran.
|
|
3815
|
-
ingestScriptRan:
|
|
3548
|
+
ingestScriptRan: z24.boolean().optional(),
|
|
3816
3549
|
// Records ingested by the run-now execution, parsed from the script's
|
|
3817
3550
|
// machine-readable count line; absent when the script didn't run or emitted
|
|
3818
3551
|
// no parseable count.
|
|
3819
|
-
ingestRecordCount:
|
|
3552
|
+
ingestRecordCount: z24.number().optional(),
|
|
3820
3553
|
// Wall-clock duration of the run-now ingestion execution, in ms.
|
|
3821
|
-
ingestDurationMs:
|
|
3822
|
-
ingestionSource:
|
|
3554
|
+
ingestDurationMs: z24.number().optional(),
|
|
3555
|
+
ingestionSource: z24.enum(["local", "fileUpload", "generated"]),
|
|
3823
3556
|
// Suggested names/values, built from framework detection. The search agent is
|
|
3824
3557
|
// instructed to rename the prefix if it doesn't match the project's build
|
|
3825
3558
|
// tool, so the names it actually wrote can differ — treat these as hints, not
|
|
3826
3559
|
// ground truth (the agent's summary carries the final names).
|
|
3827
|
-
searchEnvVars:
|
|
3828
|
-
|
|
3829
|
-
name:
|
|
3830
|
-
value:
|
|
3560
|
+
searchEnvVars: z24.array(
|
|
3561
|
+
z24.object({
|
|
3562
|
+
name: z24.string(),
|
|
3563
|
+
value: z24.string()
|
|
3831
3564
|
})
|
|
3832
3565
|
).optional()
|
|
3833
3566
|
});
|
|
3834
|
-
var implementationOutputSchema =
|
|
3835
|
-
summary:
|
|
3567
|
+
var implementationOutputSchema = z24.object({
|
|
3568
|
+
summary: z24.string(),
|
|
3836
3569
|
// Ingestion only: how to run the generated script, as a structured pair the
|
|
3837
3570
|
// wizard turns into an argv (`<runtime> <entrypoint>`) — never a free-form
|
|
3838
3571
|
// command string. `runtime` is constrained to an allowlisted interpreter and
|
|
3839
3572
|
// `entrypoint` is validated to a worktree-relative path before execution, so
|
|
3840
3573
|
// the agent cannot inject extra commands or swap the interpreter.
|
|
3841
|
-
runtime:
|
|
3842
|
-
entrypoint:
|
|
3574
|
+
runtime: z24.enum(INGEST_RUNTIMES).optional(),
|
|
3575
|
+
entrypoint: z24.string().optional()
|
|
3843
3576
|
});
|
|
3844
|
-
var verificationOutputSchema =
|
|
3845
|
-
summary:
|
|
3846
|
-
sufficient:
|
|
3847
|
-
additionalInstructions:
|
|
3577
|
+
var verificationOutputSchema = z24.object({
|
|
3578
|
+
summary: z24.string(),
|
|
3579
|
+
sufficient: z24.boolean(),
|
|
3580
|
+
additionalInstructions: z24.string().optional()
|
|
3848
3581
|
});
|
|
3849
3582
|
var MAX_IMPLEMENT_VERIFICATION_ATTEMPTS = 3;
|
|
3850
3583
|
var DEFAULT_IMPLEMENT_USE_CASES = ["ingestion", "search"];
|
|
@@ -3958,7 +3691,7 @@ function searchInstructions(input) {
|
|
|
3958
3691
|
doc,
|
|
3959
3692
|
`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
3693
|
"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 (
|
|
3694
|
+
// appId always resolves (loadActiveProfile throws otherwise); only the
|
|
3962
3695
|
// search-only key is best-effort and can fall back to a placeholder.
|
|
3963
3696
|
`Values: App ID "${input.appId}", search-only key ${input.searchKey ? `"${input.searchKey}"` : "(placeholder for the developer to fill in)"}.`,
|
|
3964
3697
|
// Names are fixed, not the agent's to rename: the wizard writes the
|
|
@@ -4107,7 +3840,6 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4107
3840
|
}
|
|
4108
3841
|
}
|
|
4109
3842
|
const targetIndex = selected?.selection;
|
|
4110
|
-
useWizard.getState().setTargetIndex(targetIndex ?? null);
|
|
4111
3843
|
await assertGitRepoWithHead(repoRoot);
|
|
4112
3844
|
if (await isWorkingTreeDirty(repoRoot)) {
|
|
4113
3845
|
await confirmDirtyWorkingTree(ctx, repoRoot);
|
|
@@ -4118,7 +3850,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4118
3850
|
let appId;
|
|
4119
3851
|
let searchKey;
|
|
4120
3852
|
if (useCases.includes("search")) {
|
|
4121
|
-
appId = (await
|
|
3853
|
+
appId = (await loadActiveProfile()).appId;
|
|
4122
3854
|
try {
|
|
4123
3855
|
searchKey = await resolveSearchOnlyKey(targetIndex);
|
|
4124
3856
|
} catch (err) {
|
|
@@ -4229,8 +3961,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4229
3961
|
messages: []
|
|
4230
3962
|
}) === true;
|
|
4231
3963
|
if (runNow) {
|
|
4232
|
-
const
|
|
4233
|
-
const writeKey = await resolveWriteKey(targetIndex);
|
|
3964
|
+
const profile = await loadActiveProfile();
|
|
4234
3965
|
ctx.notify({ messages: [`Writing records to "${targetIndex}"\u2026`] });
|
|
4235
3966
|
const scriptLogId = ctx.logStart("runIngestScript", {
|
|
4236
3967
|
runtime: ingestRuntime,
|
|
@@ -4242,8 +3973,8 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4242
3973
|
ingestRuntime,
|
|
4243
3974
|
ingestEntrypoint,
|
|
4244
3975
|
{
|
|
4245
|
-
[APP_ID_VAR]:
|
|
4246
|
-
[API_KEY_VAR]:
|
|
3976
|
+
[APP_ID_VAR]: profile.appId,
|
|
3977
|
+
[API_KEY_VAR]: profile.apiKey
|
|
4247
3978
|
}
|
|
4248
3979
|
);
|
|
4249
3980
|
ctx.logEnd(scriptLogId, run2.ok ? "success" : "error");
|
|
@@ -4454,8 +4185,8 @@ var defaultWorkflow = {
|
|
|
4454
4185
|
defineStep({
|
|
4455
4186
|
id: "select-index",
|
|
4456
4187
|
title: "Set up index",
|
|
4457
|
-
outputSchema:
|
|
4458
|
-
selection:
|
|
4188
|
+
outputSchema: z25.object({
|
|
4189
|
+
selection: z25.string()
|
|
4459
4190
|
}),
|
|
4460
4191
|
run: (ctx) => selectIndexStep(ctx)
|
|
4461
4192
|
}),
|
|
@@ -4734,7 +4465,7 @@ function parseCliArgs(argv) {
|
|
|
4734
4465
|
|
|
4735
4466
|
// src/lib/resetState.ts
|
|
4736
4467
|
import { readdir as readdir4, rm as rm2 } from "node:fs/promises";
|
|
4737
|
-
import { join as
|
|
4468
|
+
import { join as join12 } from "node:path";
|
|
4738
4469
|
var KEEP = ["wizard.log"];
|
|
4739
4470
|
async function resetProjectState() {
|
|
4740
4471
|
const dir = stateDir();
|
|
@@ -4746,7 +4477,7 @@ async function resetProjectState() {
|
|
|
4746
4477
|
}
|
|
4747
4478
|
const targets = entries.filter((name) => !KEEP.includes(name));
|
|
4748
4479
|
await Promise.all(
|
|
4749
|
-
targets.map((name) => rm2(
|
|
4480
|
+
targets.map((name) => rm2(join12(dir, name), { recursive: true, force: true }))
|
|
4750
4481
|
);
|
|
4751
4482
|
return { dir, removed: targets };
|
|
4752
4483
|
}
|
|
@@ -4801,38 +4532,31 @@ ${formatStepList(workflow)}`);
|
|
|
4801
4532
|
}
|
|
4802
4533
|
async function run(workflow) {
|
|
4803
4534
|
const store = useWizard.getState();
|
|
4804
|
-
|
|
4805
|
-
await store.waitForStart();
|
|
4535
|
+
let instance = render(/* @__PURE__ */ jsx14(App, {}), { incrementalRendering: true });
|
|
4806
4536
|
let user = await getUser();
|
|
4807
4537
|
if (!user) {
|
|
4808
|
-
|
|
4538
|
+
await instance.waitUntilRenderFlush();
|
|
4539
|
+
instance.cleanup();
|
|
4809
4540
|
try {
|
|
4810
4541
|
await runAuthLogin();
|
|
4811
4542
|
} catch (err) {
|
|
4812
|
-
|
|
4813
|
-
await instance.waitUntilExit();
|
|
4543
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
4814
4544
|
process.exit(1);
|
|
4815
4545
|
}
|
|
4816
|
-
|
|
4546
|
+
instance = render(/* @__PURE__ */ jsx14(App, {}), { incrementalRendering: true });
|
|
4817
4547
|
user = await getUser();
|
|
4818
4548
|
if (!user) {
|
|
4819
4549
|
store.setError(
|
|
4820
|
-
"Authentication completed but no Algolia user was returned. Try running `npx @algolia/cli
|
|
4550
|
+
"Authentication completed but no Algolia user was returned. Try running `npx @algolia/cli auth login` directly."
|
|
4821
4551
|
);
|
|
4822
4552
|
await instance.waitUntilExit();
|
|
4823
4553
|
process.exit(1);
|
|
4824
4554
|
}
|
|
4825
4555
|
}
|
|
4826
4556
|
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);
|
|
4557
|
+
const profile = await loadActiveProfile();
|
|
4558
|
+
await store.waitForStart();
|
|
4559
|
+
runWorkflow(workflow, profile?.appId);
|
|
4836
4560
|
}
|
|
4837
4561
|
var started = await startup();
|
|
4838
4562
|
if (typeof started === "number") {
|