@algolia/wizard 0.6.0-rc.53.32 → 0.6.0-rc.55.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +462 -734
- 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,54 +12,20 @@ import { nanoid } from "nanoid";
|
|
|
12
12
|
|
|
13
13
|
// src/lib/algoliaCli.ts
|
|
14
14
|
import { spawn } from "node:child_process";
|
|
15
|
-
|
|
16
|
-
|
|
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");
|
|
17
19
|
}
|
|
18
|
-
|
|
19
|
-
function lineSplitter(emit) {
|
|
20
|
-
let buffer = "";
|
|
21
|
-
return {
|
|
22
|
-
push(chunk) {
|
|
23
|
-
buffer += chunk;
|
|
24
|
-
const lines = buffer.split("\n");
|
|
25
|
-
buffer = lines.pop() ?? "";
|
|
26
|
-
for (const line of lines) emit(line.replace(/\r$/, ""));
|
|
27
|
-
},
|
|
28
|
-
flush() {
|
|
29
|
-
if (buffer) emit(buffer.replace(/\r$/, ""));
|
|
30
|
-
buffer = "";
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
var wizardSink = (stream, line) => {
|
|
35
|
-
if (!line.trim()) return;
|
|
36
|
-
useWizard.getState().pushCliOutput(stream, line);
|
|
37
|
-
};
|
|
38
|
-
function runAlgoliaCli(args, { onOutput } = {}) {
|
|
39
|
-
const store2 = useWizard.getState();
|
|
40
|
-
const logId = store2.logStart("tool", `algolia ${args.join(" ")}`);
|
|
20
|
+
function runAlgoliaCli(args) {
|
|
41
21
|
return new Promise((resolve4, reject) => {
|
|
42
|
-
const child = spawn(
|
|
22
|
+
const child = spawn(process.execPath, [algoliaCliEntry(), ...args]);
|
|
43
23
|
let stdout = "";
|
|
44
24
|
let stderr = "";
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
stderr: lineSplitter((line) => onOutput?.("stderr", line))
|
|
48
|
-
};
|
|
49
|
-
child.stdout.on("data", (chunk) => {
|
|
50
|
-
const text = String(chunk);
|
|
51
|
-
stdout += text;
|
|
52
|
-
splitters.stdout.push(text);
|
|
53
|
-
});
|
|
54
|
-
child.stderr.on("data", (chunk) => {
|
|
55
|
-
const text = String(chunk);
|
|
56
|
-
stderr += text;
|
|
57
|
-
splitters.stderr.push(text);
|
|
58
|
-
});
|
|
25
|
+
child.stdout.on("data", (chunk) => stdout += chunk);
|
|
26
|
+
child.stderr.on("data", (chunk) => stderr += chunk);
|
|
59
27
|
child.on("error", reject);
|
|
60
28
|
child.on("close", (code) => {
|
|
61
|
-
splitters.stdout.flush();
|
|
62
|
-
splitters.stderr.flush();
|
|
63
29
|
if (code === 0) {
|
|
64
30
|
resolve4(stdout);
|
|
65
31
|
} else {
|
|
@@ -71,16 +37,7 @@ function runAlgoliaCli(args, { onOutput } = {}) {
|
|
|
71
37
|
);
|
|
72
38
|
}
|
|
73
39
|
});
|
|
74
|
-
})
|
|
75
|
-
(out) => {
|
|
76
|
-
useWizard.getState().logEnd(logId, "success");
|
|
77
|
-
return out;
|
|
78
|
-
},
|
|
79
|
-
(err) => {
|
|
80
|
-
useWizard.getState().logEnd(logId, "error");
|
|
81
|
-
throw err;
|
|
82
|
-
}
|
|
83
|
-
);
|
|
40
|
+
});
|
|
84
41
|
}
|
|
85
42
|
async function getUser() {
|
|
86
43
|
let raw;
|
|
@@ -95,21 +52,13 @@ async function getUser() {
|
|
|
95
52
|
return null;
|
|
96
53
|
}
|
|
97
54
|
}
|
|
98
|
-
function needsInteractiveTerminal(err) {
|
|
99
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
100
|
-
return /non-interactive mode/i.test(message);
|
|
101
|
-
}
|
|
102
55
|
function runAuthLogin() {
|
|
103
|
-
return runAlgoliaCli(["auth", "login", "--default"], {
|
|
104
|
-
onOutput: wizardSink
|
|
105
|
-
}).then(() => void 0);
|
|
106
|
-
}
|
|
107
|
-
function runAuthLoginInTerminal() {
|
|
108
56
|
return new Promise((resolve4, reject) => {
|
|
109
|
-
const child = spawn(
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
57
|
+
const child = spawn(
|
|
58
|
+
process.execPath,
|
|
59
|
+
[algoliaCliEntry(), "auth", "login", "--default"],
|
|
60
|
+
{ stdio: "inherit" }
|
|
61
|
+
);
|
|
113
62
|
child.on("error", reject);
|
|
114
63
|
child.on("close", (code) => {
|
|
115
64
|
if (code === 0) resolve4();
|
|
@@ -222,7 +171,6 @@ function describeInputValue(value) {
|
|
|
222
171
|
return Array.isArray(value) ? value.join(", ") : value;
|
|
223
172
|
}
|
|
224
173
|
var NOTICE_INTERVAL_MS = 2e3;
|
|
225
|
-
var CLI_OUTPUT_LIMIT = 200;
|
|
226
174
|
var useWizard = create((set, get) => ({
|
|
227
175
|
phase: "idle",
|
|
228
176
|
homeScreen: "home",
|
|
@@ -234,23 +182,10 @@ var useWizard = create((set, get) => ({
|
|
|
234
182
|
notices: [],
|
|
235
183
|
_noticeQueue: [],
|
|
236
184
|
_noticeTimer: null,
|
|
237
|
-
cliOutput: [],
|
|
238
|
-
targetIndex: null,
|
|
239
185
|
logs: [],
|
|
240
186
|
error: null,
|
|
241
187
|
inputReq: null,
|
|
242
188
|
_resolve: null,
|
|
243
|
-
// Brackets a CLI subprocess that needs the screen. `endAuth` must land back
|
|
244
|
-
// on exactly 'idle': `confirmStart` is a no-op from any other phase and
|
|
245
|
-
// `waitForStart` resolves on any non-idle phase, so ending anywhere else
|
|
246
|
-
// either skips the welcome screen or ignores its spacebar forever.
|
|
247
|
-
beginAuth: () => set({ phase: "authenticating", cliOutput: [] }),
|
|
248
|
-
// Re-enters the auth phase *keeping* the CLI output on screen, for returning
|
|
249
|
-
// from a prompt raised mid-sign-in (`submitInput` leaves the phase at
|
|
250
|
-
// 'running'). Clearing here would blank the login output the user was reading
|
|
251
|
-
// the instant they answered.
|
|
252
|
-
resumeAuth: () => set({ phase: "authenticating" }),
|
|
253
|
-
endAuth: () => set((s) => s.phase === "authenticating" ? { phase: "idle" } : {}),
|
|
254
189
|
// Advances past the welcome screen. Only meaningful from 'idle' — once the
|
|
255
190
|
// workflow is running there's nothing left to confirm.
|
|
256
191
|
// Reset `homeScreen` so preflight shows Welcome, not the Learn more sub-view.
|
|
@@ -261,7 +196,7 @@ var useWizard = create((set, get) => ({
|
|
|
261
196
|
openLearnMore: () => set({ homeScreen: "learnMore" }),
|
|
262
197
|
backToHome: () => set({ homeScreen: "home" }),
|
|
263
198
|
// Resolves once the phase leaves 'idle', whether that happens before or
|
|
264
|
-
// after this is called (the welcome screen's
|
|
199
|
+
// after this is called (the welcome screen's enter handler is what
|
|
265
200
|
// drives the transition via `confirmStart`).
|
|
266
201
|
waitForStart: () => new Promise((resolve4) => {
|
|
267
202
|
if (get().phase !== "idle") {
|
|
@@ -285,13 +220,7 @@ var useWizard = create((set, get) => ({
|
|
|
285
220
|
syncSteps: (steps, currentStepIndex) => set({ steps, currentStepIndex }),
|
|
286
221
|
setActiveStep: (index) => {
|
|
287
222
|
get()._clearNoticeQueue();
|
|
288
|
-
set({
|
|
289
|
-
phase: "running",
|
|
290
|
-
currentStepIndex: index,
|
|
291
|
-
output: "",
|
|
292
|
-
notices: [],
|
|
293
|
-
cliOutput: []
|
|
294
|
-
});
|
|
223
|
+
set({ phase: "running", currentStepIndex: index, output: "", notices: [] });
|
|
295
224
|
},
|
|
296
225
|
setUser: (user2) => set({ user: user2 }),
|
|
297
226
|
appendToken: (text) => set((s) => ({ output: s.output + text })),
|
|
@@ -332,16 +261,6 @@ var useWizard = create((set, get) => ({
|
|
|
332
261
|
get()._clearNoticeQueue();
|
|
333
262
|
set({ notices: [] });
|
|
334
263
|
},
|
|
335
|
-
// Unthrottled, unlike `pushNotice`: these lines arrive at whatever rate the
|
|
336
|
-
// subprocess emits them, and holding them back would land output after the
|
|
337
|
-
// command it belongs to has already exited.
|
|
338
|
-
pushCliOutput: (stream, text) => set((s) => ({
|
|
339
|
-
cliOutput: [...s.cliOutput, { id: nanoid(), stream, text }].slice(
|
|
340
|
-
-CLI_OUTPUT_LIMIT
|
|
341
|
-
)
|
|
342
|
-
})),
|
|
343
|
-
clearCliOutput: () => set({ cliOutput: [] }),
|
|
344
|
-
setTargetIndex: (index) => set({ targetIndex: index }),
|
|
345
264
|
logStart: (kind, name, input) => {
|
|
346
265
|
const id = nanoid();
|
|
347
266
|
set((s) => ({
|
|
@@ -386,8 +305,6 @@ var useWizard = create((set, get) => ({
|
|
|
386
305
|
currentStepIndex: 0,
|
|
387
306
|
output: "",
|
|
388
307
|
notices: [],
|
|
389
|
-
cliOutput: [],
|
|
390
|
-
targetIndex: null,
|
|
391
308
|
logs: [],
|
|
392
309
|
error: null,
|
|
393
310
|
inputReq: null,
|
|
@@ -396,88 +313,16 @@ var useWizard = create((set, get) => ({
|
|
|
396
313
|
}
|
|
397
314
|
}));
|
|
398
315
|
|
|
399
|
-
// src/ui/CliOutput.tsx
|
|
400
|
-
import { Box, Text, useWindowSize } from "ink";
|
|
401
|
-
|
|
402
|
-
// src/ui/theme.ts
|
|
403
|
-
var MARKER = {
|
|
404
|
-
pending: "\u25CB",
|
|
405
|
-
running: "\u25D0",
|
|
406
|
-
done: "\u2713",
|
|
407
|
-
error: "\u2716"
|
|
408
|
-
};
|
|
409
|
-
var BRAND = "#003DFF";
|
|
410
|
-
var SECONDARY = "#5468FF";
|
|
411
|
-
var DANGER = "#F86E7E";
|
|
412
|
-
var COLORS = {
|
|
413
|
-
brand: BRAND,
|
|
414
|
-
primary: "#E6EDF3",
|
|
415
|
-
secondary: SECONDARY,
|
|
416
|
-
strong: "#FFFFFF",
|
|
417
|
-
muted: "#8B949E",
|
|
418
|
-
dim: "#484F58",
|
|
419
|
-
highlight: { bg: "#12331C", fg: "#4ADE80" },
|
|
420
|
-
badge: "#E3B341",
|
|
421
|
-
danger: DANGER,
|
|
422
|
-
success: "#4ADE80",
|
|
423
|
-
bg: {
|
|
424
|
-
main: "#0B0E14",
|
|
425
|
-
sidebar: "#14171E"
|
|
426
|
-
},
|
|
427
|
-
border: "#30363D",
|
|
428
|
-
accent: "#76A0FF",
|
|
429
|
-
status: {
|
|
430
|
-
pending: "gray",
|
|
431
|
-
running: "#76A0FF",
|
|
432
|
-
done: "#4ADE80",
|
|
433
|
-
error: DANGER
|
|
434
|
-
}
|
|
435
|
-
};
|
|
436
|
-
|
|
437
|
-
// src/ui/CliOutput.tsx
|
|
438
|
-
import { jsxs } from "react/jsx-runtime";
|
|
439
|
-
var CLI_MARKER = "\u203A";
|
|
440
|
-
var RESERVED_ROWS = 16;
|
|
441
|
-
var MAX_LINES = 12;
|
|
442
|
-
function CliOutput() {
|
|
443
|
-
const cliOutput = useWizard((s) => s.cliOutput);
|
|
444
|
-
const { rows } = useWindowSize();
|
|
445
|
-
if (!cliOutput.length) return null;
|
|
446
|
-
const budget = Math.min(Math.max(rows - RESERVED_ROWS, 3), MAX_LINES);
|
|
447
|
-
const visible = cliOutput.slice(-budget);
|
|
448
|
-
const hidden = cliOutput.length - visible.length;
|
|
449
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
450
|
-
hidden > 0 && /* @__PURE__ */ jsxs(Text, { color: COLORS.dim, children: [
|
|
451
|
-
"\u2191 ",
|
|
452
|
-
hidden,
|
|
453
|
-
" earlier line(s)"
|
|
454
|
-
] }),
|
|
455
|
-
visible.map((line) => /* @__PURE__ */ jsxs(
|
|
456
|
-
Text,
|
|
457
|
-
{
|
|
458
|
-
color: line.stream === "stderr" ? COLORS.muted : COLORS.dim,
|
|
459
|
-
wrap: "truncate",
|
|
460
|
-
children: [
|
|
461
|
-
CLI_MARKER,
|
|
462
|
-
" ",
|
|
463
|
-
line.text
|
|
464
|
-
]
|
|
465
|
-
},
|
|
466
|
-
line.id
|
|
467
|
-
))
|
|
468
|
-
] });
|
|
469
|
-
}
|
|
470
|
-
|
|
471
316
|
// src/ui/Notices.tsx
|
|
472
|
-
import { Box as
|
|
317
|
+
import { Box as Box2, Text as Text2, useWindowSize as useWindowSize2 } from "ink";
|
|
473
318
|
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
474
319
|
|
|
475
320
|
// src/ui/Table.tsx
|
|
476
|
-
import { Box
|
|
321
|
+
import { Box, Text, measureElement, useWindowSize } from "ink";
|
|
477
322
|
import { useEffect, useRef, useState } from "react";
|
|
478
323
|
import { jsx } from "react/jsx-runtime";
|
|
479
324
|
function Table({ columns, rows }) {
|
|
480
|
-
const { columns: termCols } =
|
|
325
|
+
const { columns: termCols } = useWindowSize();
|
|
481
326
|
const ref = useRef(null);
|
|
482
327
|
const [width, setWidth] = useState(0);
|
|
483
328
|
useEffect(() => {
|
|
@@ -485,7 +330,7 @@ function Table({ columns, rows }) {
|
|
|
485
330
|
}, [termCols, columns, rows]);
|
|
486
331
|
if (rows.length === 0) return null;
|
|
487
332
|
const lines = formatTable(columns, rows, width || void 0);
|
|
488
|
-
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}`)) });
|
|
489
334
|
}
|
|
490
335
|
function formatTable(columns, rows, width) {
|
|
491
336
|
const natural = columns.map(
|
|
@@ -525,10 +370,45 @@ function resize(widths, budget) {
|
|
|
525
370
|
}
|
|
526
371
|
var truncate = (s, width) => s.length <= width ? s : width <= 1 ? s.slice(0, width) : `${s.slice(0, width - 1)}\u2026`;
|
|
527
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
|
+
|
|
528
408
|
// src/ui/Notices.tsx
|
|
529
|
-
import { jsx as jsx2, jsxs
|
|
409
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
530
410
|
var AGENT_MARKER = "\u2726";
|
|
531
|
-
var
|
|
411
|
+
var RESERVED_ROWS = 14;
|
|
532
412
|
var PANEL_TEXT_WIDTH = 45;
|
|
533
413
|
function messageLineCount(text) {
|
|
534
414
|
return Math.max(1, Math.ceil(text.length / PANEL_TEXT_WIDTH));
|
|
@@ -542,7 +422,7 @@ function noticeLineCount(notice) {
|
|
|
542
422
|
return messageLines + tableLines;
|
|
543
423
|
}
|
|
544
424
|
function fitVisibleNotices(notices, windowRows) {
|
|
545
|
-
const budget = Math.max(windowRows -
|
|
425
|
+
const budget = Math.max(windowRows - RESERVED_ROWS, 3);
|
|
546
426
|
let used = 0;
|
|
547
427
|
let count = 0;
|
|
548
428
|
for (let i = notices.length - 1; i >= 0; i--) {
|
|
@@ -575,7 +455,7 @@ function parseHex(hex) {
|
|
|
575
455
|
}
|
|
576
456
|
function Notices() {
|
|
577
457
|
const notices = useWizard((s) => s.notices);
|
|
578
|
-
const { rows: windowRows } =
|
|
458
|
+
const { rows: windowRows } = useWindowSize2();
|
|
579
459
|
const visible = fitVisibleNotices(notices, windowRows);
|
|
580
460
|
const [pulseStep, setPulseStep] = useState2(0);
|
|
581
461
|
useEffect2(() => {
|
|
@@ -592,14 +472,14 @@ function Notices() {
|
|
|
592
472
|
}, []);
|
|
593
473
|
if (!visible.length) return null;
|
|
594
474
|
const pulseColor = PULSE_COLORS[pulseStep];
|
|
595
|
-
return /* @__PURE__ */ jsx2(
|
|
475
|
+
return /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", gap: 1, marginBottom: 1, children: visible.map((notice, i) => {
|
|
596
476
|
const isLatest = i === visible.length - 1;
|
|
597
|
-
return /* @__PURE__ */
|
|
477
|
+
return /* @__PURE__ */ jsxs(Box2, { flexDirection: "column", children: [
|
|
598
478
|
notice.messages?.map((m, j) => {
|
|
599
479
|
const line = typeof m === "string" ? { text: m } : m;
|
|
600
480
|
const prefix = j === 0 ? `${AGENT_MARKER} ` : " ";
|
|
601
|
-
return /* @__PURE__ */
|
|
602
|
-
|
|
481
|
+
return /* @__PURE__ */ jsxs(
|
|
482
|
+
Text2,
|
|
603
483
|
{
|
|
604
484
|
color: isLatest && !line.color ? pulseColor : line.color ?? COLORS.dim,
|
|
605
485
|
bold: line.bold,
|
|
@@ -617,37 +497,37 @@ function Notices() {
|
|
|
617
497
|
}
|
|
618
498
|
|
|
619
499
|
// src/ui/PromptInput.tsx
|
|
620
|
-
import { Box as
|
|
500
|
+
import { Box as Box5, Text as Text5, useInput as useInput2 } from "ink";
|
|
621
501
|
import TextInput from "ink-text-input";
|
|
622
502
|
import { useState as useState4 } from "react";
|
|
623
503
|
|
|
624
504
|
// src/ui/NextAction.tsx
|
|
625
|
-
import { Box as
|
|
626
|
-
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";
|
|
627
507
|
function NextAction({
|
|
628
508
|
action,
|
|
629
509
|
keyHint,
|
|
630
510
|
hierarchy = "primary"
|
|
631
511
|
}) {
|
|
632
|
-
return /* @__PURE__ */
|
|
633
|
-
hierarchy === "primary" && /* @__PURE__ */ jsx3(
|
|
634
|
-
hierarchy === "secondary" && /* @__PURE__ */
|
|
635
|
-
/* @__PURE__ */ jsx3(
|
|
636
|
-
/* @__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 })
|
|
637
517
|
] }),
|
|
638
|
-
/* @__PURE__ */
|
|
639
|
-
/* @__PURE__ */ jsx3(
|
|
640
|
-
/* @__PURE__ */ jsx3(
|
|
641
|
-
/* @__PURE__ */ jsx3(
|
|
642
|
-
/* @__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: `]` })
|
|
643
523
|
] })
|
|
644
524
|
] });
|
|
645
525
|
}
|
|
646
526
|
|
|
647
527
|
// src/ui/SelectPrompt.tsx
|
|
648
|
-
import { Box as
|
|
528
|
+
import { Box as Box4, Text as Text4, measureElement as measureElement2, useInput, useWindowSize as useWindowSize3 } from "ink";
|
|
649
529
|
import { useLayoutEffect, useRef as useRef2, useState as useState3 } from "react";
|
|
650
|
-
import { jsx as jsx4, jsxs as
|
|
530
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
651
531
|
var CANCEL = "cancel";
|
|
652
532
|
var ARROW_WIDTH = 4;
|
|
653
533
|
var COLUMN_GAP = 2;
|
|
@@ -684,7 +564,7 @@ function SelectPrompt({
|
|
|
684
564
|
if (multi) hints.push({ key: "[space]", label: "select" });
|
|
685
565
|
hints.push({ key: "[enter]", label: "confirm" });
|
|
686
566
|
const containerRef = useRef2(null);
|
|
687
|
-
const { columns } =
|
|
567
|
+
const { columns } = useWindowSize3();
|
|
688
568
|
const [width, setWidth] = useState3(columns);
|
|
689
569
|
useLayoutEffect(() => {
|
|
690
570
|
if (containerRef.current) {
|
|
@@ -729,53 +609,53 @@ function SelectPrompt({
|
|
|
729
609
|
}
|
|
730
610
|
}
|
|
731
611
|
});
|
|
732
|
-
return /* @__PURE__ */ jsx4(
|
|
733
|
-
error && /* @__PURE__ */ jsx4(
|
|
734
|
-
messages?.map((m, i) => /* @__PURE__ */ jsx4(
|
|
612
|
+
return /* @__PURE__ */ jsx4(Box4, { ref: containerRef, flexGrow: 1, children: /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", gap: 1, width, children: [
|
|
613
|
+
error && /* @__PURE__ */ jsx4(Text4, { color: COLORS.danger, children: error }),
|
|
614
|
+
messages?.map((m, i) => /* @__PURE__ */ jsx4(Text4, { color: COLORS.muted, children: m }, `msg-${i}`)),
|
|
735
615
|
table && /* @__PURE__ */ jsx4(Table, { columns: table.columns, rows: table.rows }),
|
|
736
|
-
/* @__PURE__ */
|
|
737
|
-
question && /* @__PURE__ */ jsx4(
|
|
738
|
-
helpText && /* @__PURE__ */ jsx4(
|
|
616
|
+
/* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", children: [
|
|
617
|
+
question && /* @__PURE__ */ jsx4(Text4, { color: COLORS.muted, children: question }),
|
|
618
|
+
helpText && /* @__PURE__ */ jsx4(Text4, { color: COLORS.dim, children: helpText })
|
|
739
619
|
] }),
|
|
740
|
-
/* @__PURE__ */ jsx4(
|
|
620
|
+
/* @__PURE__ */ jsx4(Box4, { flexDirection: "column", children: rows.map((option, i) => {
|
|
741
621
|
const highlighted = i === index;
|
|
742
622
|
const isCancel = i === cancelIndex;
|
|
743
623
|
const bullet = multi && !isCancel ? checked.has(i) ? "\u25CF " : "\u25CB " : "";
|
|
744
624
|
const sec = isCancel ? void 0 : secondary?.[i];
|
|
745
625
|
const labelColor = highlighted ? COLORS.highlight.fg : void 0;
|
|
746
|
-
const label = /* @__PURE__ */
|
|
626
|
+
const label = /* @__PURE__ */ jsxs3(Text4, { color: labelColor, wrap: "truncate", children: [
|
|
747
627
|
highlighted ? "\u276F " : " ",
|
|
748
628
|
bullet,
|
|
749
629
|
option
|
|
750
630
|
] });
|
|
751
631
|
const isText = sec?.kind === "text";
|
|
752
|
-
return /* @__PURE__ */
|
|
753
|
-
|
|
632
|
+
return /* @__PURE__ */ jsxs3(
|
|
633
|
+
Box4,
|
|
754
634
|
{
|
|
755
635
|
width: isText ? "100%" : barWidth,
|
|
756
636
|
paddingX: 1,
|
|
757
637
|
paddingY: 1,
|
|
758
638
|
backgroundColor: highlighted ? COLORS.highlight.bg : void 0,
|
|
759
639
|
children: [
|
|
760
|
-
/* @__PURE__ */ jsx4(
|
|
761
|
-
isText && textWidth > 0 && /* @__PURE__ */ jsx4(
|
|
762
|
-
|
|
640
|
+
/* @__PURE__ */ jsx4(Box4, { width: isText ? labelWidth : barLabelWidth, children: label }),
|
|
641
|
+
isText && textWidth > 0 && /* @__PURE__ */ jsx4(Box4, { width: textWidth, children: /* @__PURE__ */ jsx4(
|
|
642
|
+
Text4,
|
|
763
643
|
{
|
|
764
644
|
wrap: "truncate",
|
|
765
645
|
color: highlighted ? COLORS.primary : COLORS.muted,
|
|
766
646
|
children: sec.value
|
|
767
647
|
}
|
|
768
648
|
) }),
|
|
769
|
-
sec?.kind === "badge" && /* @__PURE__ */ jsx4(
|
|
649
|
+
sec?.kind === "badge" && /* @__PURE__ */ jsx4(Box4, { width: badgeWidth, justifyContent: "flex-end", children: /* @__PURE__ */ jsx4(Text4, { color: COLORS.badge, wrap: "truncate", children: sec.value }) })
|
|
770
650
|
]
|
|
771
651
|
},
|
|
772
652
|
`row-${i}`
|
|
773
653
|
);
|
|
774
654
|
}) }),
|
|
775
|
-
/* @__PURE__ */ jsx4(
|
|
655
|
+
/* @__PURE__ */ jsx4(Text4, { children: hints.map(({ key, label }, i) => /* @__PURE__ */ jsxs3(Text4, { children: [
|
|
776
656
|
i > 0 ? " " : "",
|
|
777
|
-
/* @__PURE__ */ jsx4(
|
|
778
|
-
/* @__PURE__ */
|
|
657
|
+
/* @__PURE__ */ jsx4(Text4, { color: COLORS.primary, children: key }),
|
|
658
|
+
/* @__PURE__ */ jsxs3(Text4, { color: COLORS.dim, children: [
|
|
779
659
|
" ",
|
|
780
660
|
label
|
|
781
661
|
] })
|
|
@@ -784,22 +664,22 @@ function SelectPrompt({
|
|
|
784
664
|
}
|
|
785
665
|
|
|
786
666
|
// src/ui/PromptInput.tsx
|
|
787
|
-
import { jsx as jsx5, jsxs as
|
|
667
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
788
668
|
var ACCEPT_REJECT_OPTIONS = ["Accept", "Reject"];
|
|
789
|
-
function
|
|
669
|
+
function EnterToContinuePrompt({
|
|
790
670
|
question,
|
|
791
671
|
messages,
|
|
792
672
|
onDecide
|
|
793
673
|
}) {
|
|
794
|
-
useInput2((
|
|
795
|
-
if (
|
|
674
|
+
useInput2((_input, key) => {
|
|
675
|
+
if (key.return) onDecide(true);
|
|
796
676
|
else if (key.escape) onDecide(false);
|
|
797
677
|
});
|
|
798
|
-
return /* @__PURE__ */
|
|
799
|
-
messages?.map((m, i) => /* @__PURE__ */ jsx5(
|
|
800
|
-
question && /* @__PURE__ */ jsx5(
|
|
801
|
-
/* @__PURE__ */
|
|
802
|
-
/* @__PURE__ */ jsx5(NextAction, { action: "continue", keyHint: "
|
|
678
|
+
return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", gap: 1, children: [
|
|
679
|
+
messages?.map((m, i) => /* @__PURE__ */ jsx5(Text5, { color: COLORS.muted, children: m }, `msg-${i}`)),
|
|
680
|
+
question && /* @__PURE__ */ jsx5(Text5, { color: COLORS.primary, children: question }),
|
|
681
|
+
/* @__PURE__ */ jsxs4(Box5, { gap: 1, flexDirection: "column", children: [
|
|
682
|
+
/* @__PURE__ */ jsx5(NextAction, { action: "continue", keyHint: "enter" }),
|
|
803
683
|
/* @__PURE__ */ jsx5(NextAction, { action: "decline", keyHint: "esc", hierarchy: "secondary" })
|
|
804
684
|
] })
|
|
805
685
|
] });
|
|
@@ -808,11 +688,11 @@ function PromptInput() {
|
|
|
808
688
|
const { phase, inputReq, submitInput } = useWizard();
|
|
809
689
|
const [draft, setDraft] = useState4("");
|
|
810
690
|
if (phase === "done" || phase === "error") {
|
|
811
|
-
return /* @__PURE__ */ jsx5(
|
|
691
|
+
return /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { color: "gray", dimColor: true, children: "Press Enter or Esc to exit" }) });
|
|
812
692
|
}
|
|
813
693
|
if (phase !== "awaitingInput" || !inputReq) return null;
|
|
814
694
|
if (inputReq.promptType === "multipleChoice") {
|
|
815
|
-
return /* @__PURE__ */ jsx5(
|
|
695
|
+
return /* @__PURE__ */ jsx5(Box5, { children: /* @__PURE__ */ jsx5(
|
|
816
696
|
SelectPrompt,
|
|
817
697
|
{
|
|
818
698
|
question: inputReq.prompt,
|
|
@@ -829,7 +709,7 @@ function PromptInput() {
|
|
|
829
709
|
) });
|
|
830
710
|
}
|
|
831
711
|
if (inputReq.promptType === "multiSelect") {
|
|
832
|
-
return /* @__PURE__ */ jsx5(
|
|
712
|
+
return /* @__PURE__ */ jsx5(Box5, { children: /* @__PURE__ */ jsx5(
|
|
833
713
|
SelectPrompt,
|
|
834
714
|
{
|
|
835
715
|
multi: true,
|
|
@@ -844,7 +724,7 @@ function PromptInput() {
|
|
|
844
724
|
) });
|
|
845
725
|
}
|
|
846
726
|
if (inputReq.promptType === "notice") {
|
|
847
|
-
return /* @__PURE__ */ jsx5(
|
|
727
|
+
return /* @__PURE__ */ jsx5(Box5, { children: /* @__PURE__ */ jsx5(
|
|
848
728
|
SelectPrompt,
|
|
849
729
|
{
|
|
850
730
|
question: inputReq.prompt,
|
|
@@ -854,9 +734,9 @@ function PromptInput() {
|
|
|
854
734
|
}
|
|
855
735
|
) });
|
|
856
736
|
}
|
|
857
|
-
if (inputReq.promptType === "
|
|
737
|
+
if (inputReq.promptType === "enterToContinue") {
|
|
858
738
|
return /* @__PURE__ */ jsx5(
|
|
859
|
-
|
|
739
|
+
EnterToContinuePrompt,
|
|
860
740
|
{
|
|
861
741
|
question: inputReq.prompt,
|
|
862
742
|
messages: inputReq.messages,
|
|
@@ -866,7 +746,7 @@ function PromptInput() {
|
|
|
866
746
|
}
|
|
867
747
|
if (inputReq.promptType === "acceptReject") {
|
|
868
748
|
const labels = inputReq.options?.length ? inputReq.options : ACCEPT_REJECT_OPTIONS;
|
|
869
|
-
return /* @__PURE__ */ jsx5(
|
|
749
|
+
return /* @__PURE__ */ jsx5(Box5, { children: /* @__PURE__ */ jsx5(
|
|
870
750
|
SelectPrompt,
|
|
871
751
|
{
|
|
872
752
|
question: inputReq.prompt,
|
|
@@ -877,11 +757,11 @@ function PromptInput() {
|
|
|
877
757
|
}
|
|
878
758
|
) });
|
|
879
759
|
}
|
|
880
|
-
return /* @__PURE__ */
|
|
881
|
-
inputReq.error && /* @__PURE__ */ jsx5(
|
|
882
|
-
inputReq.messages?.map((m, i) => /* @__PURE__ */ jsx5(
|
|
883
|
-
/* @__PURE__ */
|
|
884
|
-
/* @__PURE__ */
|
|
760
|
+
return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
|
|
761
|
+
inputReq.error && /* @__PURE__ */ jsx5(Text5, { color: COLORS.danger, children: inputReq.error }),
|
|
762
|
+
inputReq.messages?.map((m, i) => /* @__PURE__ */ jsx5(Text5, { color: COLORS.muted, children: m }, `msg-${i}`)),
|
|
763
|
+
/* @__PURE__ */ jsxs4(Box5, { children: [
|
|
764
|
+
/* @__PURE__ */ jsxs4(Text5, { color: COLORS.primary, children: [
|
|
885
765
|
inputReq.prompt,
|
|
886
766
|
" "
|
|
887
767
|
] }),
|
|
@@ -903,7 +783,7 @@ function PromptInput() {
|
|
|
903
783
|
// src/ui/Welcome.tsx
|
|
904
784
|
import { dirname as dirname2, join as join3 } from "node:path";
|
|
905
785
|
import { fileURLToPath } from "node:url";
|
|
906
|
-
import { Box as
|
|
786
|
+
import { Box as Box6, Spacer, Text as Text6, useInput as useInput3, useWindowSize as useWindowSize4 } from "ink";
|
|
907
787
|
|
|
908
788
|
// src/ui/copy/welcome.ts
|
|
909
789
|
var sidebarItems = [
|
|
@@ -931,29 +811,29 @@ var sidebarItems = [
|
|
|
931
811
|
|
|
932
812
|
// src/ui/Welcome.tsx
|
|
933
813
|
import Image, { InkPictureProvider } from "ink-picture";
|
|
934
|
-
import { jsx as jsx6, jsxs as
|
|
814
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
935
815
|
var IMAGE_PATH = join3(dirname2(fileURLToPath(import.meta.url)), "algolia.png");
|
|
936
816
|
function SidebarItem({
|
|
937
817
|
title,
|
|
938
818
|
description
|
|
939
819
|
}) {
|
|
940
|
-
return /* @__PURE__ */
|
|
941
|
-
/* @__PURE__ */
|
|
942
|
-
/* @__PURE__ */ jsx6(
|
|
943
|
-
/* @__PURE__ */ jsx6(
|
|
820
|
+
return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
|
|
821
|
+
/* @__PURE__ */ jsxs5(Box6, { gap: 1, children: [
|
|
822
|
+
/* @__PURE__ */ jsx6(Text6, { color: COLORS.success, children: "\u2192" }),
|
|
823
|
+
/* @__PURE__ */ jsx6(Text6, { color: COLORS.strong, bold: true, children: title })
|
|
944
824
|
] }),
|
|
945
|
-
/* @__PURE__ */
|
|
825
|
+
/* @__PURE__ */ jsxs5(Box6, { flexDirection: "row", gap: 2, children: [
|
|
946
826
|
/* @__PURE__ */ jsx6(Spacer, {}),
|
|
947
|
-
/* @__PURE__ */ jsx6(
|
|
827
|
+
/* @__PURE__ */ jsx6(Text6, { color: COLORS.muted, children: description })
|
|
948
828
|
] })
|
|
949
829
|
] });
|
|
950
830
|
}
|
|
951
831
|
function Welcome() {
|
|
952
832
|
const confirmStart = useWizard((s) => s.confirmStart);
|
|
953
833
|
const openLearnMore = useWizard((s) => s.openLearnMore);
|
|
954
|
-
const { rows } =
|
|
955
|
-
useInput3((input) => {
|
|
956
|
-
if (
|
|
834
|
+
const { rows } = useWindowSize4();
|
|
835
|
+
useInput3((input, key) => {
|
|
836
|
+
if (key.return) confirmStart();
|
|
957
837
|
else if (input === "i") openLearnMore();
|
|
958
838
|
});
|
|
959
839
|
const scales = {
|
|
@@ -970,15 +850,15 @@ function Welcome() {
|
|
|
970
850
|
if (rows < 30) {
|
|
971
851
|
layout = scales["small"];
|
|
972
852
|
}
|
|
973
|
-
return /* @__PURE__ */
|
|
853
|
+
return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "row", justifyContent: "space-between", width: "100%", children: [
|
|
974
854
|
/* @__PURE__ */ jsx6(
|
|
975
|
-
|
|
855
|
+
Box6,
|
|
976
856
|
{
|
|
977
857
|
paddingY: layout.main.padding.y,
|
|
978
858
|
paddingX: layout.main.padding.x,
|
|
979
859
|
flexDirection: "column",
|
|
980
860
|
justifyContent: "center",
|
|
981
|
-
children: /* @__PURE__ */
|
|
861
|
+
children: /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", gap: 2, children: [
|
|
982
862
|
/* @__PURE__ */ jsx6(InkPictureProvider, { children: /* @__PURE__ */ jsx6(
|
|
983
863
|
Image,
|
|
984
864
|
{
|
|
@@ -990,16 +870,16 @@ function Welcome() {
|
|
|
990
870
|
protocol: "halfBlock"
|
|
991
871
|
}
|
|
992
872
|
) }),
|
|
993
|
-
/* @__PURE__ */ jsx6(
|
|
994
|
-
/* @__PURE__ */
|
|
995
|
-
/* @__PURE__ */ jsx6(NextAction, { action: "start wizard", keyHint: "
|
|
873
|
+
/* @__PURE__ */ jsx6(Text6, { color: COLORS.muted, children: "\u2726 From zero \u2192 working search in ~10 minutes" }),
|
|
874
|
+
/* @__PURE__ */ jsxs5(Box6, { gap: 1, flexDirection: "column", children: [
|
|
875
|
+
/* @__PURE__ */ jsx6(NextAction, { action: "start wizard", keyHint: "enter" }),
|
|
996
876
|
/* @__PURE__ */ jsx6(NextAction, { action: "learn more", keyHint: "i", hierarchy: "secondary" })
|
|
997
877
|
] })
|
|
998
878
|
] })
|
|
999
879
|
}
|
|
1000
880
|
),
|
|
1001
|
-
/* @__PURE__ */
|
|
1002
|
-
|
|
881
|
+
/* @__PURE__ */ jsxs5(
|
|
882
|
+
Box6,
|
|
1003
883
|
{
|
|
1004
884
|
backgroundColor: COLORS.bg.sidebar,
|
|
1005
885
|
width: 40,
|
|
@@ -1009,7 +889,7 @@ function Welcome() {
|
|
|
1009
889
|
flexDirection: "column",
|
|
1010
890
|
justifyContent: "center",
|
|
1011
891
|
children: [
|
|
1012
|
-
/* @__PURE__ */ jsx6(
|
|
892
|
+
/* @__PURE__ */ jsx6(Text6, { color: COLORS.muted, children: "WHAT THIS WIZARD WILL DO" }),
|
|
1013
893
|
sidebarItems.map((i, idx) => /* @__PURE__ */ jsx6(SidebarItem, { title: i.title, description: i.description }, idx))
|
|
1014
894
|
]
|
|
1015
895
|
}
|
|
@@ -1019,7 +899,7 @@ function Welcome() {
|
|
|
1019
899
|
|
|
1020
900
|
// src/ui/LearnMore.tsx
|
|
1021
901
|
import { Fragment as Fragment2 } from "react";
|
|
1022
|
-
import { Box as
|
|
902
|
+
import { Box as Box7, Text as Text7, useInput as useInput4, useWindowSize as useWindowSize5 } from "ink";
|
|
1023
903
|
|
|
1024
904
|
// src/ui/copy/learn-more.ts
|
|
1025
905
|
var accessIntro = "Everything runs locally on your machine. Nothing is written or sent without an explicit yes from you.";
|
|
@@ -1056,7 +936,7 @@ var policyLinks = [
|
|
|
1056
936
|
];
|
|
1057
937
|
|
|
1058
938
|
// src/ui/LearnMore.tsx
|
|
1059
|
-
import { jsx as jsx7, jsxs as
|
|
939
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1060
940
|
var TAG_COLORS = {
|
|
1061
941
|
READ: COLORS.success,
|
|
1062
942
|
WRITE: COLORS.badge,
|
|
@@ -1072,25 +952,25 @@ function NeverLine({
|
|
|
1072
952
|
}) {
|
|
1073
953
|
const used = segments.reduce((n, s) => n + s.text.length, 0);
|
|
1074
954
|
const rightPad = Math.max(0, width - 2 - NEVER_BOX_PAD_X - used);
|
|
1075
|
-
return /* @__PURE__ */
|
|
1076
|
-
/* @__PURE__ */ jsx7(
|
|
955
|
+
return /* @__PURE__ */ jsxs6(Text7, { children: [
|
|
956
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.danger, children: "\u2502" }),
|
|
1077
957
|
" ".repeat(NEVER_BOX_PAD_X),
|
|
1078
|
-
segments.map((s, i) => /* @__PURE__ */ jsx7(
|
|
958
|
+
segments.map((s, i) => /* @__PURE__ */ jsx7(Text7, { color: s.color, bold: s.bold, children: s.text }, i)),
|
|
1079
959
|
" ".repeat(rightPad),
|
|
1080
|
-
/* @__PURE__ */ jsx7(
|
|
960
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.danger, children: "\u2502" })
|
|
1081
961
|
] });
|
|
1082
962
|
}
|
|
1083
963
|
function LearnMore() {
|
|
1084
964
|
const confirmStart = useWizard((s) => s.confirmStart);
|
|
1085
965
|
const backToHome = useWizard((s) => s.backToHome);
|
|
1086
|
-
const { columns } =
|
|
966
|
+
const { columns } = useWindowSize5();
|
|
1087
967
|
const dividerWidth = Math.max(0, columns - PADDING_X * 2);
|
|
1088
|
-
useInput4((
|
|
968
|
+
useInput4((_input, key) => {
|
|
1089
969
|
if (key.escape) backToHome();
|
|
1090
|
-
else if (
|
|
970
|
+
else if (key.return) confirmStart();
|
|
1091
971
|
});
|
|
1092
|
-
return /* @__PURE__ */
|
|
1093
|
-
|
|
972
|
+
return /* @__PURE__ */ jsxs6(
|
|
973
|
+
Box7,
|
|
1094
974
|
{
|
|
1095
975
|
flexDirection: "column",
|
|
1096
976
|
paddingX: PADDING_X,
|
|
@@ -1098,20 +978,20 @@ function LearnMore() {
|
|
|
1098
978
|
width: "100%",
|
|
1099
979
|
gap: 1,
|
|
1100
980
|
children: [
|
|
1101
|
-
/* @__PURE__ */ jsx7(
|
|
1102
|
-
/* @__PURE__ */ jsx7(
|
|
1103
|
-
/* @__PURE__ */ jsx7(
|
|
1104
|
-
/* @__PURE__ */ jsx7(
|
|
1105
|
-
/* @__PURE__ */
|
|
1106
|
-
/* @__PURE__ */ jsx7(
|
|
1107
|
-
/* @__PURE__ */ jsx7(
|
|
1108
|
-
/* @__PURE__ */ jsx7(
|
|
1109
|
-
/* @__PURE__ */ jsx7(
|
|
981
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.strong, bold: true, children: "What algolia wizard accesses" }),
|
|
982
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.muted, children: accessIntro }),
|
|
983
|
+
/* @__PURE__ */ jsx7(Box7, { flexDirection: "column", children: accessItems.map((item) => /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", marginTop: 1, children: [
|
|
984
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.border, children: "\u2500".repeat(dividerWidth) }),
|
|
985
|
+
/* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", gap: 1, marginTop: 1, children: [
|
|
986
|
+
/* @__PURE__ */ jsx7(Box7, { width: TAG_COLUMN_WIDTH, flexShrink: 0, children: /* @__PURE__ */ jsx7(Text7, { color: TAG_COLORS[item.tag], bold: true, children: `[${item.tag}]` }) }),
|
|
987
|
+
/* @__PURE__ */ jsx7(Box7, { flexDirection: "column", children: /* @__PURE__ */ jsxs6(Text7, { children: [
|
|
988
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.strong, bold: true, children: item.title }),
|
|
989
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.muted, children: ` \u2014 ${item.description}` })
|
|
1110
990
|
] }) })
|
|
1111
991
|
] })
|
|
1112
992
|
] }, item.tag)) }),
|
|
1113
|
-
/* @__PURE__ */
|
|
1114
|
-
/* @__PURE__ */ jsx7(
|
|
993
|
+
/* @__PURE__ */ jsxs6(Box7, { marginTop: 1, flexDirection: "column", children: [
|
|
994
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.danger, children: `\u256D${"\u2500".repeat(Math.max(0, dividerWidth - 2))}\u256E` }),
|
|
1115
995
|
/* @__PURE__ */ jsx7(NeverLine, { width: dividerWidth }),
|
|
1116
996
|
/* @__PURE__ */ jsx7(
|
|
1117
997
|
NeverLine,
|
|
@@ -1120,7 +1000,7 @@ function LearnMore() {
|
|
|
1120
1000
|
segments: [{ text: "I NEVER", color: COLORS.danger, bold: true }]
|
|
1121
1001
|
}
|
|
1122
1002
|
),
|
|
1123
|
-
neverItems.map((item) => /* @__PURE__ */
|
|
1003
|
+
neverItems.map((item) => /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
1124
1004
|
/* @__PURE__ */ jsx7(NeverLine, { width: dividerWidth }),
|
|
1125
1005
|
/* @__PURE__ */ jsx7(
|
|
1126
1006
|
NeverLine,
|
|
@@ -1135,23 +1015,23 @@ function LearnMore() {
|
|
|
1135
1015
|
)
|
|
1136
1016
|
] }, item)),
|
|
1137
1017
|
/* @__PURE__ */ jsx7(NeverLine, { width: dividerWidth }),
|
|
1138
|
-
/* @__PURE__ */ jsx7(
|
|
1018
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.danger, children: `\u2570${"\u2500".repeat(Math.max(0, dividerWidth - 2))}\u256F` })
|
|
1139
1019
|
] }),
|
|
1140
|
-
/* @__PURE__ */ jsx7(
|
|
1141
|
-
/* @__PURE__ */ jsx7(
|
|
1142
|
-
/* @__PURE__ */ jsx7(
|
|
1020
|
+
/* @__PURE__ */ jsx7(Box7, { marginTop: 1, flexDirection: "column", children: policyLinks.map((link) => /* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", gap: 1, children: [
|
|
1021
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.strong, bold: true, children: `${link.label}:` }),
|
|
1022
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.accent, children: link.url })
|
|
1143
1023
|
] }, link.label)) }),
|
|
1144
|
-
/* @__PURE__ */
|
|
1145
|
-
/* @__PURE__ */
|
|
1146
|
-
/* @__PURE__ */ jsx7(
|
|
1147
|
-
/* @__PURE__ */ jsx7(
|
|
1148
|
-
/* @__PURE__ */ jsx7(
|
|
1024
|
+
/* @__PURE__ */ jsxs6(Box7, { marginTop: 1, flexDirection: "row", gap: 3, children: [
|
|
1025
|
+
/* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", gap: 1, children: [
|
|
1026
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.muted, children: "[" }),
|
|
1027
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.primary, children: "esc" }),
|
|
1028
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.muted, children: "] back" })
|
|
1149
1029
|
] }),
|
|
1150
|
-
/* @__PURE__ */
|
|
1151
|
-
/* @__PURE__ */ jsx7(
|
|
1152
|
-
/* @__PURE__ */ jsx7(
|
|
1153
|
-
/* @__PURE__ */ jsx7(
|
|
1154
|
-
/* @__PURE__ */ jsx7(
|
|
1030
|
+
/* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", gap: 1, children: [
|
|
1031
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.muted, children: "[" }),
|
|
1032
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.primary, children: "enter" }),
|
|
1033
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.muted, children: "]" }),
|
|
1034
|
+
/* @__PURE__ */ jsx7(Text7, { color: COLORS.success, bold: true, children: "start wizard" })
|
|
1155
1035
|
] })
|
|
1156
1036
|
] })
|
|
1157
1037
|
]
|
|
@@ -1160,10 +1040,10 @@ function LearnMore() {
|
|
|
1160
1040
|
}
|
|
1161
1041
|
|
|
1162
1042
|
// src/ui/Sidebar.tsx
|
|
1163
|
-
import { Box as
|
|
1043
|
+
import { Box as Box10, Text as Text10 } from "ink";
|
|
1164
1044
|
|
|
1165
1045
|
// src/ui/Steps.tsx
|
|
1166
|
-
import { Box as
|
|
1046
|
+
import { Box as Box8, Text as Text8 } from "ink";
|
|
1167
1047
|
import Spinner from "ink-spinner";
|
|
1168
1048
|
|
|
1169
1049
|
// src/core/persistence.ts
|
|
@@ -1192,11 +1072,11 @@ async function clearWorkflowState(workflowId) {
|
|
|
1192
1072
|
}
|
|
1193
1073
|
|
|
1194
1074
|
// src/ui/Steps.tsx
|
|
1195
|
-
import { jsx as jsx8, jsxs as
|
|
1075
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1196
1076
|
function Steps() {
|
|
1197
1077
|
const { steps } = useWizard();
|
|
1198
1078
|
const visibleSteps = steps.filter(isStepVisible);
|
|
1199
|
-
return /* @__PURE__ */ jsx8(
|
|
1079
|
+
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: [
|
|
1200
1080
|
s.status === "running" ? /* @__PURE__ */ jsx8(Spinner, { type: "dots" }) : MARKER[s.status],
|
|
1201
1081
|
" ",
|
|
1202
1082
|
s.title
|
|
@@ -1206,7 +1086,7 @@ function CurrentStep() {
|
|
|
1206
1086
|
const { steps } = useWizard();
|
|
1207
1087
|
const currentStep = steps.filter(isStepVisible).find((s) => s.status === "running");
|
|
1208
1088
|
if (!currentStep) return null;
|
|
1209
|
-
return /* @__PURE__ */
|
|
1089
|
+
return /* @__PURE__ */ jsxs7(Text8, { color: COLORS.status.running, children: [
|
|
1210
1090
|
/* @__PURE__ */ jsx8(Spinner, { type: "dots" }),
|
|
1211
1091
|
" ",
|
|
1212
1092
|
` ${currentStep.title}`
|
|
@@ -1214,19 +1094,19 @@ function CurrentStep() {
|
|
|
1214
1094
|
}
|
|
1215
1095
|
|
|
1216
1096
|
// src/ui/Progress.tsx
|
|
1217
|
-
import { Box as
|
|
1218
|
-
import { jsx as jsx9, jsxs as
|
|
1097
|
+
import { Box as Box9, Text as Text9 } from "ink";
|
|
1098
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1219
1099
|
function Progress() {
|
|
1220
1100
|
const { steps, currentStepIndex } = useWizard();
|
|
1221
1101
|
const visibleSteps = steps.filter(isStepVisible);
|
|
1222
1102
|
if (visibleSteps.length === 0) return null;
|
|
1223
1103
|
const visibleCountThroughCurrent = steps.slice(0, currentStepIndex + 1).filter(isStepVisible).length;
|
|
1224
1104
|
const activeStepNumber = Math.max(1, visibleCountThroughCurrent);
|
|
1225
|
-
return /* @__PURE__ */
|
|
1226
|
-
/* @__PURE__ */ jsx9(
|
|
1227
|
-
/* @__PURE__ */ jsx9(
|
|
1228
|
-
/* @__PURE__ */ jsx9(
|
|
1229
|
-
/* @__PURE__ */ jsx9(
|
|
1105
|
+
return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "row", gap: 1, children: [
|
|
1106
|
+
/* @__PURE__ */ jsx9(Text9, { color: COLORS.muted, children: "STEP" }),
|
|
1107
|
+
/* @__PURE__ */ jsx9(Text9, { bold: true, children: activeStepNumber }),
|
|
1108
|
+
/* @__PURE__ */ jsx9(Text9, { bold: true, children: "/" }),
|
|
1109
|
+
/* @__PURE__ */ jsx9(Text9, { bold: true, children: visibleSteps.length })
|
|
1230
1110
|
] });
|
|
1231
1111
|
}
|
|
1232
1112
|
|
|
@@ -1237,10 +1117,10 @@ var sidebarCommands = [
|
|
|
1237
1117
|
];
|
|
1238
1118
|
|
|
1239
1119
|
// src/ui/Sidebar.tsx
|
|
1240
|
-
import { jsx as jsx10, jsxs as
|
|
1120
|
+
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1241
1121
|
function Sidebar() {
|
|
1242
|
-
return /* @__PURE__ */
|
|
1243
|
-
|
|
1122
|
+
return /* @__PURE__ */ jsxs9(
|
|
1123
|
+
Box10,
|
|
1244
1124
|
{
|
|
1245
1125
|
backgroundColor: "#14171E",
|
|
1246
1126
|
width: 30,
|
|
@@ -1249,16 +1129,16 @@ function Sidebar() {
|
|
|
1249
1129
|
flexDirection: "column",
|
|
1250
1130
|
justifyContent: "space-between",
|
|
1251
1131
|
children: [
|
|
1252
|
-
/* @__PURE__ */
|
|
1253
|
-
/* @__PURE__ */ jsx10(
|
|
1132
|
+
/* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", gap: 1, children: [
|
|
1133
|
+
/* @__PURE__ */ jsx10(Text10, { color: COLORS.muted, children: "PROGRESS" }),
|
|
1254
1134
|
/* @__PURE__ */ jsx10(Steps, {})
|
|
1255
1135
|
] }),
|
|
1256
|
-
/* @__PURE__ */
|
|
1136
|
+
/* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", gap: 1, children: [
|
|
1257
1137
|
/* @__PURE__ */ jsx10(Progress, {}),
|
|
1258
|
-
/* @__PURE__ */ jsx10(
|
|
1259
|
-
return /* @__PURE__ */
|
|
1260
|
-
/* @__PURE__ */ jsx10(
|
|
1261
|
-
/* @__PURE__ */ jsx10(
|
|
1138
|
+
/* @__PURE__ */ jsx10(Box10, { flexDirection: "column", children: sidebarCommands.map((c) => {
|
|
1139
|
+
return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "row", gap: 1, children: [
|
|
1140
|
+
/* @__PURE__ */ jsx10(Text10, { color: COLORS.primary, children: `[${c.keyHint}]` }),
|
|
1141
|
+
/* @__PURE__ */ jsx10(Text10, { color: COLORS.muted, children: c.description })
|
|
1262
1142
|
] });
|
|
1263
1143
|
}) })
|
|
1264
1144
|
] })
|
|
@@ -1268,12 +1148,12 @@ function Sidebar() {
|
|
|
1268
1148
|
}
|
|
1269
1149
|
|
|
1270
1150
|
// src/ui/Ribbon.tsx
|
|
1271
|
-
import { Box as
|
|
1272
|
-
import { jsx as jsx11, jsxs as
|
|
1151
|
+
import { Box as Box11, Text as Text11 } from "ink";
|
|
1152
|
+
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1273
1153
|
function Ribbon() {
|
|
1274
1154
|
const firstCommand = sidebarCommands[0];
|
|
1275
|
-
return /* @__PURE__ */
|
|
1276
|
-
|
|
1155
|
+
return /* @__PURE__ */ jsxs10(
|
|
1156
|
+
Box11,
|
|
1277
1157
|
{
|
|
1278
1158
|
backgroundColor: "#14171E",
|
|
1279
1159
|
flexDirection: "row",
|
|
@@ -1283,9 +1163,9 @@ function Ribbon() {
|
|
|
1283
1163
|
children: [
|
|
1284
1164
|
/* @__PURE__ */ jsx11(Progress, {}),
|
|
1285
1165
|
/* @__PURE__ */ jsx11(CurrentStep, {}),
|
|
1286
|
-
/* @__PURE__ */
|
|
1287
|
-
/* @__PURE__ */ jsx11(
|
|
1288
|
-
/* @__PURE__ */ jsx11(
|
|
1166
|
+
/* @__PURE__ */ jsxs10(Box11, { flexDirection: "row", gap: 1, children: [
|
|
1167
|
+
/* @__PURE__ */ jsx11(Text11, { color: COLORS.primary, children: `[${firstCommand.keyHint}]` }),
|
|
1168
|
+
/* @__PURE__ */ jsx11(Text11, { color: COLORS.muted, children: firstCommand.description })
|
|
1289
1169
|
] })
|
|
1290
1170
|
]
|
|
1291
1171
|
}
|
|
@@ -1297,8 +1177,8 @@ import { useState as useState6 } from "react";
|
|
|
1297
1177
|
|
|
1298
1178
|
// src/ui/Logs.tsx
|
|
1299
1179
|
import { useLayoutEffect as useLayoutEffect2, useRef as useRef3, useState as useState5 } from "react";
|
|
1300
|
-
import { Box as
|
|
1301
|
-
import { jsx as jsx12, jsxs as
|
|
1180
|
+
import { Box as Box12, Text as Text12, measureElement as measureElement3, useInput as useInput5, useWindowSize as useWindowSize6 } from "ink";
|
|
1181
|
+
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1302
1182
|
var KIND_COLOR = {
|
|
1303
1183
|
tool: COLORS.primary,
|
|
1304
1184
|
prompt: COLORS.badge
|
|
@@ -1328,7 +1208,7 @@ function formatTimestamp(ms) {
|
|
|
1328
1208
|
}
|
|
1329
1209
|
function Logs() {
|
|
1330
1210
|
const logs = useWizard((s) => s.logs);
|
|
1331
|
-
const { rows, columns } =
|
|
1211
|
+
const { rows, columns } = useWindowSize6();
|
|
1332
1212
|
const viewportRef = useRef3(null);
|
|
1333
1213
|
const [viewportHeight, setViewportHeight] = useState5(0);
|
|
1334
1214
|
const [viewportWidth, setViewportWidth] = useState5(0);
|
|
@@ -1365,10 +1245,10 @@ function Logs() {
|
|
|
1365
1245
|
const visible = logs.slice(scrollOffset, scrollOffset + capacity);
|
|
1366
1246
|
const hiddenAbove = scrollOffset;
|
|
1367
1247
|
const hiddenBelow = logs.length - scrollOffset - visible.length;
|
|
1368
|
-
return /* @__PURE__ */
|
|
1369
|
-
logs.length === 0 && /* @__PURE__ */ jsx12(
|
|
1370
|
-
/* @__PURE__ */
|
|
1371
|
-
hiddenAbove > 0 && /* @__PURE__ */
|
|
1248
|
+
return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", paddingX: 4, paddingY: 2, flexGrow: 1, children: [
|
|
1249
|
+
logs.length === 0 && /* @__PURE__ */ jsx12(Text12, { color: COLORS.dim, children: "No logs yet." }),
|
|
1250
|
+
/* @__PURE__ */ jsxs11(Box12, { ref: viewportRef, flexDirection: "column", flexGrow: 1, children: [
|
|
1251
|
+
hiddenAbove > 0 && /* @__PURE__ */ jsxs11(Text12, { color: COLORS.dim, children: [
|
|
1372
1252
|
"\u2191 ",
|
|
1373
1253
|
hiddenAbove,
|
|
1374
1254
|
" more"
|
|
@@ -1383,20 +1263,20 @@ function Logs() {
|
|
|
1383
1263
|
const name = truncate2(entry.name, budget);
|
|
1384
1264
|
budget -= name.length;
|
|
1385
1265
|
const preview = rawPreview ? truncate2(rawPreview, budget) : "";
|
|
1386
|
-
return /* @__PURE__ */
|
|
1387
|
-
/* @__PURE__ */ jsx12(
|
|
1388
|
-
/* @__PURE__ */ jsx12(
|
|
1389
|
-
preview && /* @__PURE__ */ jsx12(
|
|
1390
|
-
durationText && /* @__PURE__ */ jsx12(
|
|
1266
|
+
return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "row", gap: ROW_GAP, children: [
|
|
1267
|
+
/* @__PURE__ */ jsx12(Text12, { color: COLORS.dim, children: timestamp }),
|
|
1268
|
+
/* @__PURE__ */ jsx12(Text12, { color: logNameColor(entry), wrap: "truncate", children: name }),
|
|
1269
|
+
preview && /* @__PURE__ */ jsx12(Text12, { color: COLORS.dim, wrap: "truncate", children: preview }),
|
|
1270
|
+
durationText && /* @__PURE__ */ jsx12(Text12, { color: COLORS.dim, children: durationText })
|
|
1391
1271
|
] }, entry.id);
|
|
1392
1272
|
}),
|
|
1393
|
-
hiddenBelow > 0 && /* @__PURE__ */
|
|
1273
|
+
hiddenBelow > 0 && /* @__PURE__ */ jsxs11(Text12, { color: COLORS.dim, children: [
|
|
1394
1274
|
"\u2193 ",
|
|
1395
1275
|
hiddenBelow,
|
|
1396
1276
|
" more"
|
|
1397
1277
|
] })
|
|
1398
1278
|
] }),
|
|
1399
|
-
/* @__PURE__ */ jsx12(
|
|
1279
|
+
/* @__PURE__ */ jsx12(Text12, { color: COLORS.dim, children: "\u2191/\u2193 scroll" })
|
|
1400
1280
|
] });
|
|
1401
1281
|
}
|
|
1402
1282
|
|
|
@@ -1420,11 +1300,11 @@ function track(event, payload) {
|
|
|
1420
1300
|
}
|
|
1421
1301
|
|
|
1422
1302
|
// src/ui/App.tsx
|
|
1423
|
-
import { jsx as jsx13, jsxs as
|
|
1303
|
+
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1424
1304
|
function App() {
|
|
1425
1305
|
const { phase, error, homeScreen, currentStepIndex, steps, inputReq } = useWizard();
|
|
1426
1306
|
const { exit } = useApp();
|
|
1427
|
-
const { columns, rows } =
|
|
1307
|
+
const { columns, rows } = useWindowSize7();
|
|
1428
1308
|
const [showLogs, setShowLogs] = useState6(false);
|
|
1429
1309
|
const finished = phase === "done" || phase === "error";
|
|
1430
1310
|
const currentStep = steps[currentStepIndex];
|
|
@@ -1437,8 +1317,7 @@ function App() {
|
|
|
1437
1317
|
{ isActive: finished }
|
|
1438
1318
|
);
|
|
1439
1319
|
useInput6((_input, key) => {
|
|
1440
|
-
if (phase === "idle" || phase === "preflight"
|
|
1441
|
-
return;
|
|
1320
|
+
if (phase === "idle" || phase === "preflight") return;
|
|
1442
1321
|
if (key.tab) {
|
|
1443
1322
|
setShowLogs(!showLogs);
|
|
1444
1323
|
track("AI Wizard Interaction", {
|
|
@@ -1448,7 +1327,7 @@ function App() {
|
|
|
1448
1327
|
});
|
|
1449
1328
|
}
|
|
1450
1329
|
});
|
|
1451
|
-
const escOwnedElsewhere = phase === "idle" || phase === "
|
|
1330
|
+
const escOwnedElsewhere = phase === "idle" || phase === "awaitingInput" && inputReq?.promptType === "enterToContinue";
|
|
1452
1331
|
useInput6((_input, key) => {
|
|
1453
1332
|
if (escOwnedElsewhere) return;
|
|
1454
1333
|
if (key.escape) {
|
|
@@ -1461,19 +1340,19 @@ function App() {
|
|
|
1461
1340
|
exit();
|
|
1462
1341
|
}
|
|
1463
1342
|
});
|
|
1464
|
-
const mainWindowVisible = phase === "
|
|
1343
|
+
const mainWindowVisible = phase === "running" || phase === "awaitingInput" || phase === "error" || phase === "done";
|
|
1465
1344
|
const flexDirection = columns > 90 ? "row" : "column";
|
|
1466
1345
|
const showSidebar = flexDirection === "row";
|
|
1467
|
-
return /* @__PURE__ */
|
|
1468
|
-
|
|
1346
|
+
return /* @__PURE__ */ jsxs12(
|
|
1347
|
+
Box13,
|
|
1469
1348
|
{
|
|
1470
1349
|
backgroundColor: COLORS.bg.main,
|
|
1471
1350
|
flexDirection: "row",
|
|
1472
1351
|
width: columns,
|
|
1473
1352
|
minHeight: rows,
|
|
1474
1353
|
children: [
|
|
1475
|
-
mainWindowVisible && /* @__PURE__ */
|
|
1476
|
-
|
|
1354
|
+
mainWindowVisible && /* @__PURE__ */ jsxs12(
|
|
1355
|
+
Box13,
|
|
1477
1356
|
{
|
|
1478
1357
|
flexDirection,
|
|
1479
1358
|
width: "100%",
|
|
@@ -1481,8 +1360,8 @@ function App() {
|
|
|
1481
1360
|
children: [
|
|
1482
1361
|
showLogs ? /* @__PURE__ */ jsx13(Logs, {}) : (
|
|
1483
1362
|
/* Fill the width beside the sidebar; row layout only (would grow vertically when stacked). */
|
|
1484
|
-
/* @__PURE__ */
|
|
1485
|
-
|
|
1363
|
+
/* @__PURE__ */ jsxs12(
|
|
1364
|
+
Box13,
|
|
1486
1365
|
{
|
|
1487
1366
|
flexDirection: "column",
|
|
1488
1367
|
paddingX: 4,
|
|
@@ -1490,15 +1369,10 @@ function App() {
|
|
|
1490
1369
|
width: showSidebar ? 70 : "100%",
|
|
1491
1370
|
flexGrow: showSidebar ? 1 : 0,
|
|
1492
1371
|
children: [
|
|
1493
|
-
phase === "authenticating" && /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", marginBottom: 1, children: [
|
|
1494
|
-
/* @__PURE__ */ jsx13(Text14, { color: COLORS.strong, bold: true, children: "Signing in to Algolia" }),
|
|
1495
|
-
/* @__PURE__ */ jsx13(Text14, { color: COLORS.muted, children: "A browser window will open \u2014 complete sign-in there." })
|
|
1496
|
-
] }),
|
|
1497
|
-
/* @__PURE__ */ jsx13(CliOutput, {}),
|
|
1498
1372
|
/* @__PURE__ */ jsx13(Notices, {}),
|
|
1499
1373
|
/* @__PURE__ */ jsx13(PromptInput, {}),
|
|
1500
|
-
phase === "running" && showSidebar && /* @__PURE__ */ jsx13(
|
|
1501
|
-
phase === "error" && error && /* @__PURE__ */ jsx13(
|
|
1374
|
+
phase === "running" && showSidebar && /* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx13(CurrentStep, {}) }),
|
|
1375
|
+
phase === "error" && error && /* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsxs12(Text13, { color: COLORS.status.error, children: [
|
|
1502
1376
|
"\u2716 ",
|
|
1503
1377
|
error
|
|
1504
1378
|
] }) })
|
|
@@ -1752,7 +1626,7 @@ async function ensureConsent() {
|
|
|
1752
1626
|
const store2 = useWizard.getState();
|
|
1753
1627
|
const answer = await store2.requestUserInput({
|
|
1754
1628
|
prompt: "Wizard will make AI-authored changes to this repository.",
|
|
1755
|
-
promptType: "
|
|
1629
|
+
promptType: "enterToContinue",
|
|
1756
1630
|
options: []
|
|
1757
1631
|
});
|
|
1758
1632
|
if (answer !== true) {
|
|
@@ -1910,134 +1784,61 @@ async function runWorkflow(workflow2, appId) {
|
|
|
1910
1784
|
}
|
|
1911
1785
|
}
|
|
1912
1786
|
|
|
1913
|
-
// src/lib/
|
|
1914
|
-
import {
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
);
|
|
1927
|
-
async function currentApplication() {
|
|
1928
|
-
let raw;
|
|
1787
|
+
// src/lib/algoliaProfile.ts
|
|
1788
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
1789
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
1790
|
+
import { homedir as homedir2 } from "node:os";
|
|
1791
|
+
import { join as join6 } from "node:path";
|
|
1792
|
+
import { parse as parseToml } from "toml";
|
|
1793
|
+
var require3 = createRequire2(import.meta.url);
|
|
1794
|
+
function configPath() {
|
|
1795
|
+
const base = process.env.XDG_CONFIG_HOME || join6(homedir2(), ".config");
|
|
1796
|
+
return join6(base, "algolia", "config.toml");
|
|
1797
|
+
}
|
|
1798
|
+
function profilesFromConfig(tomlText) {
|
|
1799
|
+
let parsed;
|
|
1929
1800
|
try {
|
|
1930
|
-
|
|
1801
|
+
parsed = parseToml(tomlText);
|
|
1931
1802
|
} catch {
|
|
1932
|
-
return
|
|
1933
|
-
}
|
|
1934
|
-
const parsed = currentSchema.safeParse(parseJson(raw));
|
|
1935
|
-
return parsed.success ? parsed.data : null;
|
|
1936
|
-
}
|
|
1937
|
-
async function requireApplication() {
|
|
1938
|
-
const app2 = await currentApplication();
|
|
1939
|
-
if (!app2) {
|
|
1940
|
-
throw new Error(
|
|
1941
|
-
"No Algolia application is selected. Run `npx @algolia/cli@latest application select` and restart the wizard."
|
|
1942
|
-
);
|
|
1943
|
-
}
|
|
1944
|
-
return app2;
|
|
1945
|
-
}
|
|
1946
|
-
async function listApplications() {
|
|
1947
|
-
const raw = await runAlgoliaCli(["application", "list", "-o", "json"]);
|
|
1948
|
-
const parsed = listSchema.safeParse(parseJson(raw));
|
|
1949
|
-
if (!parsed.success) {
|
|
1950
|
-
throw new Error("Could not read the list of Algolia applications.");
|
|
1803
|
+
return [];
|
|
1951
1804
|
}
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
}
|
|
1960
|
-
|
|
1961
|
-
}
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
function parseJson(text) {
|
|
1805
|
+
const profiles = Object.entries(parsed).filter(
|
|
1806
|
+
([, t]) => typeof t.application_id === "string" && typeof t.api_key === "string"
|
|
1807
|
+
).map(([name, t]) => ({
|
|
1808
|
+
name,
|
|
1809
|
+
appId: t.application_id,
|
|
1810
|
+
apiKey: t.api_key,
|
|
1811
|
+
isDefault: t.default === true
|
|
1812
|
+
}));
|
|
1813
|
+
profiles.sort((a, b) => Number(b.isDefault) - Number(a.isDefault));
|
|
1814
|
+
return profiles.map(({ name, appId, apiKey }) => ({ name, appId, apiKey }));
|
|
1815
|
+
}
|
|
1816
|
+
async function loadActiveProfile() {
|
|
1817
|
+
let profiles;
|
|
1966
1818
|
try {
|
|
1967
|
-
|
|
1819
|
+
profiles = profilesFromConfig(await readFile3(configPath(), "utf8"));
|
|
1968
1820
|
} catch {
|
|
1969
|
-
|
|
1821
|
+
profiles = [];
|
|
1970
1822
|
}
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
// src/lib/algoliaAppPicker.ts
|
|
1974
|
-
function secondaryFor(app2) {
|
|
1975
|
-
return app2.plan ? { kind: "badge", value: app2.plan } : void 0;
|
|
1976
|
-
}
|
|
1977
|
-
async function promptForApplication() {
|
|
1978
|
-
const store2 = useWizard.getState();
|
|
1979
|
-
const phaseBefore = store2.phase;
|
|
1980
|
-
const all = await listApplications();
|
|
1981
|
-
const selectable = selectableApplications(all);
|
|
1982
|
-
const skipped = all.length - selectable.length;
|
|
1983
|
-
if (selectable.length === 0) {
|
|
1984
|
-
const why = all.length === 0 ? "this account has no applications" : "none of this account\u2019s applications have a unique name";
|
|
1823
|
+
const profile2 = profiles[0];
|
|
1824
|
+
if (!profile2) {
|
|
1985
1825
|
throw new Error(
|
|
1986
|
-
|
|
1987
|
-
);
|
|
1988
|
-
}
|
|
1989
|
-
const messages = ["Which Algolia application should the wizard work in?"];
|
|
1990
|
-
if (skipped > 0) {
|
|
1991
|
-
messages.push(
|
|
1992
|
-
`${skipped} application${skipped === 1 ? "" : "s"} not listed: the CLI selects by name, so unnamed and duplicate-named ones can\u2019t be chosen here.`
|
|
1826
|
+
"No Algolia profile is configured. Run `npx @algolia/cli auth login` to authenticate."
|
|
1993
1827
|
);
|
|
1994
1828
|
}
|
|
1995
|
-
|
|
1996
|
-
const choice = await store2.requestUserInput({
|
|
1997
|
-
prompt: "Select an application",
|
|
1998
|
-
promptType: "multipleChoice",
|
|
1999
|
-
options: selectable.map((app2) => `${app2.name} \u2014 ${app2.id}`),
|
|
2000
|
-
secondary: selectable.map(secondaryFor),
|
|
2001
|
-
messages
|
|
2002
|
-
});
|
|
2003
|
-
const index = selectable.findIndex(
|
|
2004
|
-
(app2) => `${app2.name} \u2014 ${app2.id}` === choice
|
|
2005
|
-
);
|
|
2006
|
-
const chosen = selectable[index];
|
|
2007
|
-
if (!chosen) {
|
|
2008
|
-
throw new Error("Application picker received an unexpected selection");
|
|
2009
|
-
}
|
|
2010
|
-
try {
|
|
2011
|
-
await selectApplication(chosen.name);
|
|
2012
|
-
} catch (err) {
|
|
2013
|
-
logger.warn(
|
|
2014
|
-
{ app: chosen.id, err: err.message },
|
|
2015
|
-
"application select failed; re-prompting"
|
|
2016
|
-
);
|
|
2017
|
-
messages.push(
|
|
2018
|
-
`Could not select \u201C${chosen.name}\u201D. It may have been renamed or removed \u2014 pick another.`
|
|
2019
|
-
);
|
|
2020
|
-
continue;
|
|
2021
|
-
}
|
|
2022
|
-
if (phaseBefore === "authenticating") store2.resumeAuth();
|
|
2023
|
-
logger.info({ app: chosen.id }, "selected Algolia application");
|
|
2024
|
-
return chosen;
|
|
2025
|
-
}
|
|
2026
|
-
}
|
|
2027
|
-
async function ensureApplication() {
|
|
2028
|
-
return await currentApplication() ?? await promptForApplication();
|
|
1829
|
+
return profile2;
|
|
2029
1830
|
}
|
|
2030
1831
|
|
|
2031
1832
|
// src/workflows/default.ts
|
|
2032
|
-
import { z as
|
|
1833
|
+
import { z as z25 } from "zod";
|
|
2033
1834
|
|
|
2034
1835
|
// src/actions/listIndices.ts
|
|
2035
|
-
import { z as
|
|
2036
|
-
var indicesListSchema =
|
|
2037
|
-
items:
|
|
2038
|
-
|
|
2039
|
-
name:
|
|
2040
|
-
entries:
|
|
1836
|
+
import { z as z3 } from "zod";
|
|
1837
|
+
var indicesListSchema = z3.object({
|
|
1838
|
+
items: z3.array(
|
|
1839
|
+
z3.object({
|
|
1840
|
+
name: z3.string(),
|
|
1841
|
+
entries: z3.number().default(0)
|
|
2041
1842
|
})
|
|
2042
1843
|
)
|
|
2043
1844
|
});
|
|
@@ -2108,12 +1909,12 @@ import "zod";
|
|
|
2108
1909
|
|
|
2109
1910
|
// src/lib/tools/listFiles.ts
|
|
2110
1911
|
import { tool } from "ai";
|
|
2111
|
-
import
|
|
1912
|
+
import z4 from "zod";
|
|
2112
1913
|
import { readdir } from "node:fs/promises";
|
|
2113
1914
|
|
|
2114
1915
|
// src/lib/tools/path.ts
|
|
2115
1916
|
import { lstat } from "node:fs/promises";
|
|
2116
|
-
import { resolve as resolve2, relative, isAbsolute, dirname as dirname3, join as
|
|
1917
|
+
import { resolve as resolve2, relative, isAbsolute, dirname as dirname3, join as join7, sep } from "node:path";
|
|
2117
1918
|
function resolveInRoot(ctx, path) {
|
|
2118
1919
|
const target = resolve2(ctx.cwd, path);
|
|
2119
1920
|
const rel = relative(ctx.root, target);
|
|
@@ -2129,7 +1930,7 @@ async function hasSymlinkParent(ctx, target) {
|
|
|
2129
1930
|
let current = ctx.root;
|
|
2130
1931
|
const parts = relative(ctx.root, dirname3(target)).split(sep).filter(Boolean);
|
|
2131
1932
|
for (const part of parts) {
|
|
2132
|
-
current =
|
|
1933
|
+
current = join7(current, part);
|
|
2133
1934
|
try {
|
|
2134
1935
|
if ((await lstat(current)).isSymbolicLink()) return true;
|
|
2135
1936
|
} catch (err) {
|
|
@@ -2144,7 +1945,7 @@ async function hasSymlinkParent(ctx, target) {
|
|
|
2144
1945
|
function listFilesTool(ctx) {
|
|
2145
1946
|
return tool({
|
|
2146
1947
|
description: "List files in the current working directory",
|
|
2147
|
-
inputSchema:
|
|
1948
|
+
inputSchema: z4.object(),
|
|
2148
1949
|
execute: async () => {
|
|
2149
1950
|
logger.info("called listFiles tool");
|
|
2150
1951
|
if (++ctx.counts.list > ctx.limits.list) {
|
|
@@ -2160,13 +1961,13 @@ function listFilesTool(ctx) {
|
|
|
2160
1961
|
|
|
2161
1962
|
// src/lib/tools/changeDirectory.ts
|
|
2162
1963
|
import { tool as tool2 } from "ai";
|
|
2163
|
-
import
|
|
1964
|
+
import z5 from "zod";
|
|
2164
1965
|
import { stat } from "node:fs/promises";
|
|
2165
1966
|
function changeDirectoryTool(ctx) {
|
|
2166
1967
|
return tool2({
|
|
2167
1968
|
description: "Change the current working directory. Subsequent file operations resolve relative to it. Returns the new working directory.",
|
|
2168
|
-
inputSchema:
|
|
2169
|
-
path:
|
|
1969
|
+
inputSchema: z5.object({
|
|
1970
|
+
path: z5.string().describe("Directory to change into")
|
|
2170
1971
|
}),
|
|
2171
1972
|
execute: async ({ path }) => {
|
|
2172
1973
|
logger.info({ path }, "called changeDirectory tool");
|
|
@@ -2188,13 +1989,13 @@ function changeDirectoryTool(ctx) {
|
|
|
2188
1989
|
|
|
2189
1990
|
// src/lib/tools/reportStatus.ts
|
|
2190
1991
|
import { tool as tool3 } from "ai";
|
|
2191
|
-
import
|
|
1992
|
+
import z6 from "zod";
|
|
2192
1993
|
function reportStatusTool(output) {
|
|
2193
1994
|
return tool3({
|
|
2194
1995
|
description: "Report the status of your execution. Return a reason in case of failure.",
|
|
2195
|
-
inputSchema:
|
|
2196
|
-
status:
|
|
2197
|
-
reason:
|
|
1996
|
+
inputSchema: z6.object({
|
|
1997
|
+
status: z6.enum(["success", "fail"]),
|
|
1998
|
+
reason: z6.string().optional(),
|
|
2198
1999
|
output
|
|
2199
2000
|
}),
|
|
2200
2001
|
execute: async ({ status, reason, output: output2 }) => {
|
|
@@ -2206,8 +2007,8 @@ function reportStatusTool(output) {
|
|
|
2206
2007
|
|
|
2207
2008
|
// src/lib/tools/readFile.ts
|
|
2208
2009
|
import { tool as tool4 } from "ai";
|
|
2209
|
-
import
|
|
2210
|
-
import { readFile as
|
|
2010
|
+
import z7 from "zod";
|
|
2011
|
+
import { readFile as readFile4 } from "node:fs/promises";
|
|
2211
2012
|
|
|
2212
2013
|
// src/lib/tools/env.ts
|
|
2213
2014
|
import { basename } from "node:path";
|
|
@@ -2234,8 +2035,8 @@ function redactEnvValues(content) {
|
|
|
2234
2035
|
function readFileTool(ctx) {
|
|
2235
2036
|
return tool4({
|
|
2236
2037
|
description: "Read the contents of a file at the given path",
|
|
2237
|
-
inputSchema:
|
|
2238
|
-
filePath:
|
|
2038
|
+
inputSchema: z7.object({
|
|
2039
|
+
filePath: z7.string().describe("Path to the file to read")
|
|
2239
2040
|
}),
|
|
2240
2041
|
execute: async ({ filePath }) => {
|
|
2241
2042
|
if (++ctx.counts.read > ctx.limits.read) {
|
|
@@ -2245,7 +2046,7 @@ function readFileTool(ctx) {
|
|
|
2245
2046
|
const resolved = resolveInRoot(ctx, filePath);
|
|
2246
2047
|
if (!resolved.ok) return resolved.error;
|
|
2247
2048
|
try {
|
|
2248
|
-
const content = await
|
|
2049
|
+
const content = await readFile4(resolved.target, "utf8");
|
|
2249
2050
|
return isEnvFile(resolved.target) ? redactEnvValues(content) : content;
|
|
2250
2051
|
} catch (err) {
|
|
2251
2052
|
return `Error reading ${filePath}: ${err.message}`;
|
|
@@ -2256,15 +2057,15 @@ function readFileTool(ctx) {
|
|
|
2256
2057
|
|
|
2257
2058
|
// src/lib/tools/writeFile.ts
|
|
2258
2059
|
import { tool as tool5 } from "ai";
|
|
2259
|
-
import
|
|
2060
|
+
import z8 from "zod";
|
|
2260
2061
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
|
|
2261
2062
|
import { dirname as dirname4 } from "node:path";
|
|
2262
2063
|
function writeFileTool(ctx) {
|
|
2263
2064
|
return tool5({
|
|
2264
2065
|
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.",
|
|
2265
|
-
inputSchema:
|
|
2266
|
-
filePath:
|
|
2267
|
-
content:
|
|
2066
|
+
inputSchema: z8.object({
|
|
2067
|
+
filePath: z8.string().describe("Path to the file to write"),
|
|
2068
|
+
content: z8.string().describe("Content to write to the file")
|
|
2268
2069
|
}),
|
|
2269
2070
|
execute: async ({ filePath, content }) => {
|
|
2270
2071
|
logger.info({ filePath }, "called writeFile tool");
|
|
@@ -2289,95 +2090,9 @@ function writeFileTool(ctx) {
|
|
|
2289
2090
|
|
|
2290
2091
|
// src/lib/tools/writeAlgoliaCredentials.ts
|
|
2291
2092
|
import { tool as tool6 } from "ai";
|
|
2292
|
-
import
|
|
2293
|
-
import { mkdir as mkdir4, readFile as
|
|
2093
|
+
import z9 from "zod";
|
|
2094
|
+
import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile4 } from "node:fs/promises";
|
|
2294
2095
|
import { dirname as dirname5 } from "node:path";
|
|
2295
|
-
|
|
2296
|
-
// src/lib/algoliaApiKey.ts
|
|
2297
|
-
import { z as z10 } from "zod";
|
|
2298
|
-
var SAFE_ACLS = /* @__PURE__ */ new Set(["search", "browse", "listIndexes"]);
|
|
2299
|
-
var WRITE_ACLS = [
|
|
2300
|
-
"addObject",
|
|
2301
|
-
"deleteObject",
|
|
2302
|
-
"settings",
|
|
2303
|
-
"editSettings",
|
|
2304
|
-
"listIndexes"
|
|
2305
|
-
];
|
|
2306
|
-
var WRITE_ACL_SET = new Set(WRITE_ACLS);
|
|
2307
|
-
var apiKeySchema = z10.object({
|
|
2308
|
-
value: z10.string().min(1),
|
|
2309
|
-
acl: z10.array(z10.string()).default([]),
|
|
2310
|
-
indexes: z10.array(z10.string()).default([])
|
|
2311
|
-
});
|
|
2312
|
-
var apiKeyListSchema = z10.object({
|
|
2313
|
-
items: z10.array(apiKeySchema).optional(),
|
|
2314
|
-
keys: z10.array(apiKeySchema).optional()
|
|
2315
|
-
}).transform((o) => o.items ?? o.keys ?? []);
|
|
2316
|
-
var createdKeySchema = z10.object({
|
|
2317
|
-
key: z10.string().min(1).optional(),
|
|
2318
|
-
value: z10.string().min(1).optional()
|
|
2319
|
-
});
|
|
2320
|
-
function canReuse(key, index) {
|
|
2321
|
-
return key.acl.includes("search") && key.acl.every((acl) => SAFE_ACLS.has(acl)) && (key.indexes.length === 0 || key.indexes.includes("*") || key.indexes.includes(index));
|
|
2322
|
-
}
|
|
2323
|
-
async function createSearchKey(index) {
|
|
2324
|
-
const stdout = await runAlgoliaCli([
|
|
2325
|
-
"apikeys",
|
|
2326
|
-
"create",
|
|
2327
|
-
"--indices",
|
|
2328
|
-
index,
|
|
2329
|
-
"--acl",
|
|
2330
|
-
"search,browse",
|
|
2331
|
-
"--description",
|
|
2332
|
-
`wizard search-only key for ${index}`,
|
|
2333
|
-
"-o",
|
|
2334
|
-
"json"
|
|
2335
|
-
]);
|
|
2336
|
-
const { key, value } = createdKeySchema.parse(JSON.parse(stdout));
|
|
2337
|
-
const created = key ?? value;
|
|
2338
|
-
if (!created) throw new Error("apikeys create returned no key value");
|
|
2339
|
-
return created;
|
|
2340
|
-
}
|
|
2341
|
-
function canReuseForWrites(key, index) {
|
|
2342
|
-
return WRITE_ACLS.every((acl) => key.acl.includes(acl)) && key.acl.every((acl) => WRITE_ACL_SET.has(acl)) && key.indexes.includes(index);
|
|
2343
|
-
}
|
|
2344
|
-
async function resolveWriteKey(index) {
|
|
2345
|
-
const stdout = await runAlgoliaCli(["apikeys", "list", "-o", "json"]);
|
|
2346
|
-
const existing = apiKeyListSchema.parse(JSON.parse(stdout)).find((key2) => canReuseForWrites(key2, index))?.value;
|
|
2347
|
-
if (existing) {
|
|
2348
|
-
logger.info({ index }, "reusing existing write API key");
|
|
2349
|
-
return existing;
|
|
2350
|
-
}
|
|
2351
|
-
logger.info({ index }, "no reusable write key found; creating one");
|
|
2352
|
-
const created = await runAlgoliaCli([
|
|
2353
|
-
"apikeys",
|
|
2354
|
-
"create",
|
|
2355
|
-
"--indices",
|
|
2356
|
-
index,
|
|
2357
|
-
"--acl",
|
|
2358
|
-
WRITE_ACLS.join(","),
|
|
2359
|
-
"--description",
|
|
2360
|
-
`wizard write key for ${index}`,
|
|
2361
|
-
"-o",
|
|
2362
|
-
"json"
|
|
2363
|
-
]);
|
|
2364
|
-
const { key, value } = createdKeySchema.parse(JSON.parse(created));
|
|
2365
|
-
const writeKey = key ?? value;
|
|
2366
|
-
if (!writeKey) throw new Error("apikeys create returned no key value");
|
|
2367
|
-
return writeKey;
|
|
2368
|
-
}
|
|
2369
|
-
async function resolveSearchOnlyKey(index) {
|
|
2370
|
-
const stdout = await runAlgoliaCli(["apikeys", "list", "-o", "json"]);
|
|
2371
|
-
const existing = apiKeyListSchema.parse(JSON.parse(stdout)).find((key) => canReuse(key, index))?.value;
|
|
2372
|
-
if (existing) {
|
|
2373
|
-
logger.info({ index }, "reusing existing search-only API key");
|
|
2374
|
-
return existing;
|
|
2375
|
-
}
|
|
2376
|
-
logger.info({ index }, "no reusable search-only key found; creating one");
|
|
2377
|
-
return createSearchKey(index);
|
|
2378
|
-
}
|
|
2379
|
-
|
|
2380
|
-
// src/lib/tools/writeAlgoliaCredentials.ts
|
|
2381
2096
|
var APP_ID_VAR = "ALGOLIA_APPLICATION_ID";
|
|
2382
2097
|
var API_KEY_VAR = "ALGOLIA_WRITE_API_KEY";
|
|
2383
2098
|
function appendEnv(content, entries) {
|
|
@@ -2391,9 +2106,9 @@ function hasEnv(content, name) {
|
|
|
2391
2106
|
}
|
|
2392
2107
|
function writeCredentialsTool(ctx) {
|
|
2393
2108
|
return tool6({
|
|
2394
|
-
description: `Write the active Algolia credentials (${APP_ID_VAR} and ${API_KEY_VAR}) into the given env file. The credentials
|
|
2395
|
-
inputSchema:
|
|
2396
|
-
filePath:
|
|
2109
|
+
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.`,
|
|
2110
|
+
inputSchema: z9.object({
|
|
2111
|
+
filePath: z9.string().describe(
|
|
2397
2112
|
'Path to the env file to write credentials into (e.g. ".env")'
|
|
2398
2113
|
)
|
|
2399
2114
|
}),
|
|
@@ -2401,17 +2116,11 @@ function writeCredentialsTool(ctx) {
|
|
|
2401
2116
|
logger.info({ filePath }, "called writeCredentials tool");
|
|
2402
2117
|
const resolved = resolveInRoot(ctx, filePath);
|
|
2403
2118
|
if (resolved.ok === false) return resolved.error;
|
|
2404
|
-
|
|
2405
|
-
if (!targetIndex) {
|
|
2406
|
-
return "Error: no target index is set for this run, so a scoped write key cannot be provisioned.";
|
|
2407
|
-
}
|
|
2408
|
-
let appId;
|
|
2409
|
-
let writeKey;
|
|
2119
|
+
let profile2;
|
|
2410
2120
|
try {
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
return `Error: could not resolve Algolia credentials (${err.message}). Ask the user to authenticate with the Algolia CLI first.`;
|
|
2121
|
+
profile2 = await loadActiveProfile();
|
|
2122
|
+
} catch {
|
|
2123
|
+
return "Error: no Algolia profile is configured, so credentials cannot be written. Ask the user to authenticate with the Algolia CLI first.";
|
|
2415
2124
|
}
|
|
2416
2125
|
try {
|
|
2417
2126
|
if (await hasSymlinkParent(ctx, resolved.target)) {
|
|
@@ -2419,7 +2128,7 @@ function writeCredentialsTool(ctx) {
|
|
|
2419
2128
|
}
|
|
2420
2129
|
let existing = "";
|
|
2421
2130
|
try {
|
|
2422
|
-
existing = await
|
|
2131
|
+
existing = await readFile5(resolved.target, "utf8");
|
|
2423
2132
|
} catch (err) {
|
|
2424
2133
|
if (err.code !== "ENOENT") throw err;
|
|
2425
2134
|
}
|
|
@@ -2430,8 +2139,8 @@ function writeCredentialsTool(ctx) {
|
|
|
2430
2139
|
return `Skipped: ${filePath} already defines ${present.join(" and ")}. Leaving existing credentials untouched.`;
|
|
2431
2140
|
}
|
|
2432
2141
|
const envWithCredentials = appendEnv(existing, [
|
|
2433
|
-
[APP_ID_VAR, appId],
|
|
2434
|
-
[API_KEY_VAR,
|
|
2142
|
+
[APP_ID_VAR, profile2.appId],
|
|
2143
|
+
[API_KEY_VAR, profile2.apiKey]
|
|
2435
2144
|
]);
|
|
2436
2145
|
await mkdir4(dirname5(resolved.target), { recursive: true });
|
|
2437
2146
|
await writeFile4(resolved.target, envWithCredentials, "utf8");
|
|
@@ -2445,16 +2154,16 @@ function writeCredentialsTool(ctx) {
|
|
|
2445
2154
|
|
|
2446
2155
|
// src/lib/tools/searchFiles.ts
|
|
2447
2156
|
import { tool as tool7 } from "ai";
|
|
2448
|
-
import
|
|
2449
|
-
import { readdir as readdir2, readFile as
|
|
2450
|
-
import { join as
|
|
2157
|
+
import z10 from "zod";
|
|
2158
|
+
import { readdir as readdir2, readFile as readFile6 } from "node:fs/promises";
|
|
2159
|
+
import { join as join8 } from "node:path";
|
|
2451
2160
|
var MAX_QUERY_LENGTH = 1e3;
|
|
2452
2161
|
async function walkFiles(dir) {
|
|
2453
2162
|
const skip = /* @__PURE__ */ new Set(["node_modules", ".git", "dist"]);
|
|
2454
2163
|
const out = [];
|
|
2455
2164
|
for (const e of await readdir2(dir, { withFileTypes: true })) {
|
|
2456
2165
|
if (e.name.startsWith(".") || skip.has(e.name)) continue;
|
|
2457
|
-
const full =
|
|
2166
|
+
const full = join8(dir, e.name);
|
|
2458
2167
|
if (e.isDirectory()) out.push(...await walkFiles(full));
|
|
2459
2168
|
else if (e.isFile()) out.push(full);
|
|
2460
2169
|
}
|
|
@@ -2463,9 +2172,9 @@ async function walkFiles(dir) {
|
|
|
2463
2172
|
function searchFilesTool(ctx) {
|
|
2464
2173
|
return tool7({
|
|
2465
2174
|
description: "Search file contents for a JavaScript regular expression (RegExp syntax, not grep/PCRE). Returns matching lines as file:line:text.",
|
|
2466
|
-
inputSchema:
|
|
2467
|
-
query:
|
|
2468
|
-
path:
|
|
2175
|
+
inputSchema: z10.object({
|
|
2176
|
+
query: z10.string().describe("JavaScript RegExp pattern to search for"),
|
|
2177
|
+
path: z10.string().optional().describe("Directory to search in (default: cwd)")
|
|
2469
2178
|
}),
|
|
2470
2179
|
execute: async ({ query, path = "." }) => {
|
|
2471
2180
|
logger.info({ query, path }, "called searchFiles tool");
|
|
@@ -2487,7 +2196,7 @@ function searchFilesTool(ctx) {
|
|
|
2487
2196
|
for (const file of await walkFiles(resolved.target)) {
|
|
2488
2197
|
let content;
|
|
2489
2198
|
try {
|
|
2490
|
-
content = await
|
|
2199
|
+
content = await readFile6(file, "utf8");
|
|
2491
2200
|
} catch {
|
|
2492
2201
|
continue;
|
|
2493
2202
|
}
|
|
@@ -2509,7 +2218,7 @@ function searchFilesTool(ctx) {
|
|
|
2509
2218
|
|
|
2510
2219
|
// src/lib/tools/verifyImplementation.ts
|
|
2511
2220
|
import { tool as tool8 } from "ai";
|
|
2512
|
-
import
|
|
2221
|
+
import z11 from "zod";
|
|
2513
2222
|
|
|
2514
2223
|
// src/lib/tools/utils/runCommand.ts
|
|
2515
2224
|
import { spawn as spawn2 } from "node:child_process";
|
|
@@ -2531,9 +2240,9 @@ function runCommand(command, args, cwd) {
|
|
|
2531
2240
|
}
|
|
2532
2241
|
|
|
2533
2242
|
// src/lib/tools/utils/packageManager.ts
|
|
2534
|
-
import { readFile as
|
|
2243
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
2535
2244
|
import { existsSync } from "node:fs";
|
|
2536
|
-
import { join as
|
|
2245
|
+
import { join as join9 } from "node:path";
|
|
2537
2246
|
var LOCKFILES = [
|
|
2538
2247
|
["pnpm-lock.yaml", "pnpm"],
|
|
2539
2248
|
["yarn.lock", "yarn"],
|
|
@@ -2542,13 +2251,13 @@ var LOCKFILES = [
|
|
|
2542
2251
|
["package-lock.json", "npm"]
|
|
2543
2252
|
];
|
|
2544
2253
|
async function readPackageJson(cwd = process.cwd()) {
|
|
2545
|
-
return JSON.parse(await
|
|
2254
|
+
return JSON.parse(await readFile7(join9(cwd, "package.json"), "utf8"));
|
|
2546
2255
|
}
|
|
2547
2256
|
function packageManagerFrom(pkg) {
|
|
2548
2257
|
return pkg.packageManager?.split("@")[0] ?? "npm";
|
|
2549
2258
|
}
|
|
2550
2259
|
function packageManagerFromLockfile(cwd) {
|
|
2551
|
-
return LOCKFILES.find(([file]) => existsSync(
|
|
2260
|
+
return LOCKFILES.find(([file]) => existsSync(join9(cwd, file)))?.[1];
|
|
2552
2261
|
}
|
|
2553
2262
|
async function detectPackageManager(cwd) {
|
|
2554
2263
|
try {
|
|
@@ -2589,7 +2298,7 @@ async function runRepoVerificationCheck() {
|
|
|
2589
2298
|
function verifyImplementationTool() {
|
|
2590
2299
|
return tool8({
|
|
2591
2300
|
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.",
|
|
2592
|
-
inputSchema:
|
|
2301
|
+
inputSchema: z11.object(),
|
|
2593
2302
|
execute: async () => {
|
|
2594
2303
|
logger.info("called verifyImplementation tool");
|
|
2595
2304
|
return runRepoVerificationCheck();
|
|
@@ -2603,7 +2312,7 @@ import { createAnthropic } from "@ai-sdk/anthropic";
|
|
|
2603
2312
|
import { nanoid as nanoid2 } from "nanoid";
|
|
2604
2313
|
import { mkdir as mkdir5, writeFile as writeFile5 } from "node:fs/promises";
|
|
2605
2314
|
import { dirname as dirname6 } from "node:path";
|
|
2606
|
-
import
|
|
2315
|
+
import z12 from "zod";
|
|
2607
2316
|
var DATA_DIR = ".algolia-wizard/data";
|
|
2608
2317
|
var RECORD_MODEL = "claude-haiku-4-5";
|
|
2609
2318
|
var MAX_RECORDS = 100;
|
|
@@ -2615,17 +2324,17 @@ var anthropic = createAnthropic({
|
|
|
2615
2324
|
function generateRecordTool(ctx) {
|
|
2616
2325
|
return tool9({
|
|
2617
2326
|
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.",
|
|
2618
|
-
inputSchema:
|
|
2619
|
-
entityName:
|
|
2620
|
-
attributes:
|
|
2621
|
-
count:
|
|
2622
|
-
hint:
|
|
2327
|
+
inputSchema: z12.object({
|
|
2328
|
+
entityName: z12.string().describe("Name of the entity to generate records for."),
|
|
2329
|
+
attributes: z12.array(z12.string()).describe("Attribute names each record must contain."),
|
|
2330
|
+
count: z12.number().int().min(1).max(MAX_RECORDS).default(10).describe(`How many records to generate (max ${MAX_RECORDS}).`),
|
|
2331
|
+
hint: z12.string().optional().describe("Optional context to steer realistic values.")
|
|
2623
2332
|
}),
|
|
2624
2333
|
execute: async ({ entityName, attributes, count, hint }) => {
|
|
2625
2334
|
logger.info({ entityName, count }, "called generateRecord tool");
|
|
2626
2335
|
try {
|
|
2627
|
-
const value =
|
|
2628
|
-
const recordSchema =
|
|
2336
|
+
const value = z12.union([z12.string(), z12.number(), z12.boolean(), z12.null()]);
|
|
2337
|
+
const recordSchema = z12.object(
|
|
2629
2338
|
Object.fromEntries(attributes.map((attr) => [attr, value]))
|
|
2630
2339
|
);
|
|
2631
2340
|
const generateBatch = async (batchCount) => {
|
|
@@ -2635,8 +2344,8 @@ function generateRecordTool(ctx) {
|
|
|
2635
2344
|
const { output } = await generateText({
|
|
2636
2345
|
model: anthropic(RECORD_MODEL),
|
|
2637
2346
|
output: Output.object({
|
|
2638
|
-
schema:
|
|
2639
|
-
records:
|
|
2347
|
+
schema: z12.object({
|
|
2348
|
+
records: z12.array(recordSchema).length(batchCount)
|
|
2640
2349
|
})
|
|
2641
2350
|
}),
|
|
2642
2351
|
prompt: [
|
|
@@ -2694,12 +2403,12 @@ function generateRecordTool(ctx) {
|
|
|
2694
2403
|
|
|
2695
2404
|
// src/lib/tools/notifyUser.ts
|
|
2696
2405
|
import { tool as tool10 } from "ai";
|
|
2697
|
-
import
|
|
2406
|
+
import z13 from "zod";
|
|
2698
2407
|
function notifyUserTool() {
|
|
2699
2408
|
return tool10({
|
|
2700
2409
|
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.`,
|
|
2701
|
-
inputSchema:
|
|
2702
|
-
message:
|
|
2410
|
+
inputSchema: z13.object({
|
|
2411
|
+
message: z13.string().describe(
|
|
2703
2412
|
"Short, plain-language description of what you are doing now."
|
|
2704
2413
|
)
|
|
2705
2414
|
}),
|
|
@@ -2879,10 +2588,10 @@ async function runAgent(req) {
|
|
|
2879
2588
|
}
|
|
2880
2589
|
|
|
2881
2590
|
// src/actions/detectLanguage.ts
|
|
2882
|
-
import
|
|
2883
|
-
var detectLanguageSchema =
|
|
2884
|
-
languages:
|
|
2885
|
-
frameworks:
|
|
2591
|
+
import z16 from "zod";
|
|
2592
|
+
var detectLanguageSchema = z16.object({
|
|
2593
|
+
languages: z16.array(z16.object({ name: z16.string(), version: z16.string() })),
|
|
2594
|
+
frameworks: z16.array(z16.object({ name: z16.string(), version: z16.string() }))
|
|
2886
2595
|
});
|
|
2887
2596
|
var detectLanguage = () => runAgent({
|
|
2888
2597
|
instructions: [
|
|
@@ -2900,31 +2609,31 @@ var detectLanguage = () => runAgent({
|
|
|
2900
2609
|
});
|
|
2901
2610
|
|
|
2902
2611
|
// src/actions/analyzeCodebase.ts
|
|
2903
|
-
import
|
|
2612
|
+
import z17 from "zod";
|
|
2904
2613
|
var READONLY_TOOLS = [
|
|
2905
2614
|
"listFiles",
|
|
2906
2615
|
"changeDirectory",
|
|
2907
2616
|
"readFile",
|
|
2908
2617
|
"searchFiles"
|
|
2909
2618
|
];
|
|
2910
|
-
var ingestionAnalysisSchema =
|
|
2911
|
-
ingestionAnalysis:
|
|
2912
|
-
|
|
2913
|
-
name:
|
|
2914
|
-
paths:
|
|
2619
|
+
var ingestionAnalysisSchema = z17.object({
|
|
2620
|
+
ingestionAnalysis: z17.array(
|
|
2621
|
+
z17.object({
|
|
2622
|
+
name: z17.string(),
|
|
2623
|
+
paths: z17.array(z17.string()),
|
|
2915
2624
|
// indexable fields the agent found for this entity
|
|
2916
|
-
attributes:
|
|
2625
|
+
attributes: z17.array(z17.string())
|
|
2917
2626
|
})
|
|
2918
2627
|
)
|
|
2919
2628
|
});
|
|
2920
|
-
var searchImplementationAnalysisSchema =
|
|
2921
|
-
searchImplementationAnalysis:
|
|
2629
|
+
var searchImplementationAnalysisSchema = z17.object({
|
|
2630
|
+
searchImplementationAnalysis: z17.string()
|
|
2922
2631
|
});
|
|
2923
|
-
var verificationSchema =
|
|
2924
|
-
verification:
|
|
2632
|
+
var verificationSchema = z17.object({
|
|
2633
|
+
verification: z17.array(z17.string())
|
|
2925
2634
|
});
|
|
2926
2635
|
var confirmedEntitiesFieldSchema = ingestionAnalysisSchema.shape.ingestionAnalysis.optional();
|
|
2927
|
-
var analyzeCodebaseSchema =
|
|
2636
|
+
var analyzeCodebaseSchema = z17.object({
|
|
2928
2637
|
ingestionAnalysis: ingestionAnalysisSchema.shape.ingestionAnalysis.optional(),
|
|
2929
2638
|
searchImplementationAnalysis: searchImplementationAnalysisSchema.shape.searchImplementationAnalysis.optional(),
|
|
2930
2639
|
verification: verificationSchema.shape.verification.optional(),
|
|
@@ -2986,7 +2695,7 @@ async function runAnalysis(mode, extraInstructions = []) {
|
|
|
2986
2695
|
// package.json
|
|
2987
2696
|
var package_default = {
|
|
2988
2697
|
name: "@algolia/wizard",
|
|
2989
|
-
version: "0.6.0-rc.
|
|
2698
|
+
version: "0.6.0-rc.55.31",
|
|
2990
2699
|
description: "Magically implement Algolia functionality in your codebase",
|
|
2991
2700
|
type: "module",
|
|
2992
2701
|
engines: {
|
|
@@ -3034,6 +2743,7 @@ var package_default = {
|
|
|
3034
2743
|
dependencies: {
|
|
3035
2744
|
"@ai-sdk/anthropic": "^3.0.81",
|
|
3036
2745
|
"@ai-sdk/openai-compatible": "^2.0.47",
|
|
2746
|
+
"@algolia/cli": "^5.11.0",
|
|
3037
2747
|
"@hono/node-server": "^2.0.10",
|
|
3038
2748
|
"@mishieck/ink-titled-box": "^0.4.2",
|
|
3039
2749
|
"@segment/analytics-node": "^3.1.0",
|
|
@@ -3048,6 +2758,7 @@ var package_default = {
|
|
|
3048
2758
|
nanoid: "^5.1.15",
|
|
3049
2759
|
pino: "^10.3.1",
|
|
3050
2760
|
react: "^19.2.7",
|
|
2761
|
+
toml: "^4.1.1",
|
|
3051
2762
|
varlock: "^1.5.1",
|
|
3052
2763
|
zod: "^4.4.3",
|
|
3053
2764
|
zustand: "^5.0.14"
|
|
@@ -3105,8 +2816,8 @@ async function askList(ctx, prompt, { required = false } = {}) {
|
|
|
3105
2816
|
}
|
|
3106
2817
|
|
|
3107
2818
|
// src/actions/confirmLanguage.ts
|
|
3108
|
-
import
|
|
3109
|
-
var confirmLanguageSchema =
|
|
2819
|
+
import z19 from "zod";
|
|
2820
|
+
var confirmLanguageSchema = z19.object({
|
|
3110
2821
|
languages: detectLanguageSchema.shape.languages
|
|
3111
2822
|
});
|
|
3112
2823
|
async function confirmLanguage(ctx) {
|
|
@@ -3127,8 +2838,8 @@ async function confirmLanguage(ctx) {
|
|
|
3127
2838
|
}
|
|
3128
2839
|
|
|
3129
2840
|
// src/actions/confirmFramework.ts
|
|
3130
|
-
import
|
|
3131
|
-
var confirmFrameworkSchema =
|
|
2841
|
+
import z20 from "zod";
|
|
2842
|
+
var confirmFrameworkSchema = z20.object({
|
|
3132
2843
|
frameworks: detectLanguageSchema.shape.frameworks
|
|
3133
2844
|
});
|
|
3134
2845
|
var CURATED_FRAMEWORKS = [
|
|
@@ -3256,8 +2967,8 @@ async function promptUser(ctx, params) {
|
|
|
3256
2967
|
}
|
|
3257
2968
|
|
|
3258
2969
|
// src/actions/confirmEntities.ts
|
|
3259
|
-
import
|
|
3260
|
-
var confirmEntitiesSchema =
|
|
2970
|
+
import z21 from "zod";
|
|
2971
|
+
var confirmEntitiesSchema = z21.object({
|
|
3261
2972
|
// Final detection — the focused re-run may supersede project-scan's.
|
|
3262
2973
|
ingestionAnalysis: ingestionAnalysisSchema.shape.ingestionAnalysis.optional(),
|
|
3263
2974
|
confirmedEntities: confirmedEntitiesFieldSchema
|
|
@@ -3327,15 +3038,15 @@ async function confirmEntities(ctx) {
|
|
|
3327
3038
|
}
|
|
3328
3039
|
|
|
3329
3040
|
// src/actions/review.ts
|
|
3330
|
-
import { z as
|
|
3331
|
-
var reviewSchema =
|
|
3041
|
+
import { z as z22 } from "zod";
|
|
3042
|
+
var reviewSchema = z22.object({
|
|
3332
3043
|
// Broad, high-level takeaways grouped by theme (e.g. ingestion, search UI),
|
|
3333
3044
|
// not one entry per workflow step — a step's raw output can be a long,
|
|
3334
3045
|
// multi-paragraph blob (see implement.ts's summaries.join), and mirroring
|
|
3335
3046
|
// that 1:1 is what made the old per-step summary an unreadable wall of text.
|
|
3336
|
-
summaryPoints:
|
|
3337
|
-
reviewPrompt:
|
|
3338
|
-
nextSteps:
|
|
3047
|
+
summaryPoints: z22.array(z22.string()),
|
|
3048
|
+
reviewPrompt: z22.string(),
|
|
3049
|
+
nextSteps: z22.array(z22.string())
|
|
3339
3050
|
});
|
|
3340
3051
|
function formatCompletedSteps(steps) {
|
|
3341
3052
|
if (!steps.length) return "(no prior steps completed)";
|
|
@@ -3386,16 +3097,16 @@ ${formatCompletedSteps(ctx.completedSteps)}`,
|
|
|
3386
3097
|
};
|
|
3387
3098
|
|
|
3388
3099
|
// src/actions/implement.ts
|
|
3389
|
-
import
|
|
3100
|
+
import z24 from "zod";
|
|
3390
3101
|
|
|
3391
3102
|
// src/lib/worktree.ts
|
|
3392
3103
|
import { execFile, spawn as spawn3 } from "node:child_process";
|
|
3393
|
-
import { copyFile, mkdir as mkdir6, readdir as readdir3, readFile as
|
|
3104
|
+
import { copyFile, mkdir as mkdir6, readdir as readdir3, readFile as readFile8, stat as stat2, writeFile as writeFile6 } from "node:fs/promises";
|
|
3394
3105
|
import {
|
|
3395
3106
|
basename as basename2,
|
|
3396
3107
|
dirname as dirname7,
|
|
3397
3108
|
isAbsolute as isAbsolute2,
|
|
3398
|
-
join as
|
|
3109
|
+
join as join10,
|
|
3399
3110
|
relative as relative2,
|
|
3400
3111
|
resolve as resolve3
|
|
3401
3112
|
} from "node:path";
|
|
@@ -3429,7 +3140,7 @@ async function isWorkingTreeDirty(repoRoot) {
|
|
|
3429
3140
|
return out.trim().length > 0;
|
|
3430
3141
|
}
|
|
3431
3142
|
async function pruneOldWorktrees(repoRoot) {
|
|
3432
|
-
const dir =
|
|
3143
|
+
const dir = join10(stateDir(repoRoot), "worktrees");
|
|
3433
3144
|
const stale = (await readdir3(dir).catch(() => [])).filter((name) => /^wizard-implement-\d+$/.test(name)).sort().reverse().slice(MAX_WIZARD_WORKTREES - 1);
|
|
3434
3145
|
for (const slug of stale) {
|
|
3435
3146
|
const branch = slug.replace("wizard-implement-", WIZARD_BRANCH_PREFIX);
|
|
@@ -3440,7 +3151,7 @@ async function pruneOldWorktrees(repoRoot) {
|
|
|
3440
3151
|
"worktree",
|
|
3441
3152
|
"remove",
|
|
3442
3153
|
"--force",
|
|
3443
|
-
|
|
3154
|
+
join10(dir, slug)
|
|
3444
3155
|
]);
|
|
3445
3156
|
await git(["-C", repoRoot, "branch", "-D", branch]);
|
|
3446
3157
|
} catch (err) {
|
|
@@ -3454,7 +3165,7 @@ async function pruneOldWorktrees(repoRoot) {
|
|
|
3454
3165
|
async function createWorktree(repoRoot) {
|
|
3455
3166
|
const branch = `${WIZARD_BRANCH_PREFIX}${Date.now()}`;
|
|
3456
3167
|
const dirSlug = branch.replace(/\//g, "-");
|
|
3457
|
-
const path =
|
|
3168
|
+
const path = join10(stateDir(repoRoot), "worktrees", dirSlug);
|
|
3458
3169
|
await git(["-C", repoRoot, "worktree", "prune"]);
|
|
3459
3170
|
await pruneOldWorktrees(repoRoot);
|
|
3460
3171
|
await mkdir6(dirname7(path), { recursive: true });
|
|
@@ -3574,8 +3285,8 @@ async function copyUploadIntoWorktree(repoRoot, worktreePath, ingestDir, sourceP
|
|
|
3574
3285
|
} catch {
|
|
3575
3286
|
return { ok: false, reason: `"${sourcePath}" does not exist` };
|
|
3576
3287
|
}
|
|
3577
|
-
const relPath =
|
|
3578
|
-
const dest =
|
|
3288
|
+
const relPath = join10(ingestDir, basename2(source));
|
|
3289
|
+
const dest = join10(worktreePath, relPath);
|
|
3579
3290
|
try {
|
|
3580
3291
|
await mkdir6(dirname7(dest), { recursive: true });
|
|
3581
3292
|
await copyFile(source, dest);
|
|
@@ -3591,10 +3302,10 @@ function hasEnvVar(content, name) {
|
|
|
3591
3302
|
return new RegExp(`^(\\s*(?:export\\s+)?${name})\\s*=`, "m").test(content);
|
|
3592
3303
|
}
|
|
3593
3304
|
async function writeSearchEnvValues(worktreePath, vars) {
|
|
3594
|
-
const target =
|
|
3305
|
+
const target = join10(worktreePath, ".env");
|
|
3595
3306
|
let existing = "";
|
|
3596
3307
|
try {
|
|
3597
|
-
existing = await
|
|
3308
|
+
existing = await readFile8(target, "utf8");
|
|
3598
3309
|
} catch (err) {
|
|
3599
3310
|
if (err.code !== "ENOENT") throw err;
|
|
3600
3311
|
}
|
|
@@ -3662,15 +3373,63 @@ async function confirmDirtyWorkingTree(ctx, repoRoot) {
|
|
|
3662
3373
|
}
|
|
3663
3374
|
}
|
|
3664
3375
|
|
|
3376
|
+
// src/lib/algoliaApiKey.ts
|
|
3377
|
+
import { z as z23 } from "zod";
|
|
3378
|
+
var SAFE_ACLS = /* @__PURE__ */ new Set(["search", "browse", "listIndexes"]);
|
|
3379
|
+
var apiKeySchema = z23.object({
|
|
3380
|
+
value: z23.string().min(1),
|
|
3381
|
+
acl: z23.array(z23.string()).default([]),
|
|
3382
|
+
indexes: z23.array(z23.string()).default([])
|
|
3383
|
+
});
|
|
3384
|
+
var apiKeyListSchema = z23.object({
|
|
3385
|
+
items: z23.array(apiKeySchema).optional(),
|
|
3386
|
+
keys: z23.array(apiKeySchema).optional()
|
|
3387
|
+
}).transform((o) => o.items ?? o.keys ?? []);
|
|
3388
|
+
var createdKeySchema = z23.object({
|
|
3389
|
+
key: z23.string().min(1).optional(),
|
|
3390
|
+
value: z23.string().min(1).optional()
|
|
3391
|
+
});
|
|
3392
|
+
function canReuse(key, index) {
|
|
3393
|
+
return key.acl.includes("search") && key.acl.every((acl) => SAFE_ACLS.has(acl)) && (key.indexes.length === 0 || key.indexes.includes("*") || key.indexes.includes(index));
|
|
3394
|
+
}
|
|
3395
|
+
async function createSearchKey(index) {
|
|
3396
|
+
const stdout = await runAlgoliaCli([
|
|
3397
|
+
"apikeys",
|
|
3398
|
+
"create",
|
|
3399
|
+
"--indices",
|
|
3400
|
+
index,
|
|
3401
|
+
"--acl",
|
|
3402
|
+
"search,browse",
|
|
3403
|
+
"--description",
|
|
3404
|
+
`wizard search-only key for ${index}`,
|
|
3405
|
+
"-o",
|
|
3406
|
+
"json"
|
|
3407
|
+
]);
|
|
3408
|
+
const { key, value } = createdKeySchema.parse(JSON.parse(stdout));
|
|
3409
|
+
const created = key ?? value;
|
|
3410
|
+
if (!created) throw new Error("apikeys create returned no key value");
|
|
3411
|
+
return created;
|
|
3412
|
+
}
|
|
3413
|
+
async function resolveSearchOnlyKey(index) {
|
|
3414
|
+
const stdout = await runAlgoliaCli(["apikeys", "list", "-o", "json"]);
|
|
3415
|
+
const existing = apiKeyListSchema.parse(JSON.parse(stdout)).find((key) => canReuse(key, index))?.value;
|
|
3416
|
+
if (existing) {
|
|
3417
|
+
logger.info({ index }, "reusing existing search-only API key");
|
|
3418
|
+
return existing;
|
|
3419
|
+
}
|
|
3420
|
+
logger.info({ index }, "no reusable search-only key found; creating one");
|
|
3421
|
+
return createSearchKey(index);
|
|
3422
|
+
}
|
|
3423
|
+
|
|
3665
3424
|
// src/lib/algoliaDocs.ts
|
|
3666
3425
|
import { readFileSync, readdirSync, existsSync as existsSync2 } from "node:fs";
|
|
3667
|
-
import { dirname as dirname8, join as
|
|
3426
|
+
import { dirname as dirname8, join as join11 } from "node:path";
|
|
3668
3427
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
3669
|
-
var DOCS_SUBPATH =
|
|
3428
|
+
var DOCS_SUBPATH = join11("docs", "algolia-sdk");
|
|
3670
3429
|
function findDocsDir() {
|
|
3671
3430
|
let dir = dirname8(fileURLToPath2(import.meta.url));
|
|
3672
3431
|
for (; ; ) {
|
|
3673
|
-
const candidate =
|
|
3432
|
+
const candidate = join11(dir, DOCS_SUBPATH);
|
|
3674
3433
|
if (existsSync2(candidate)) return candidate;
|
|
3675
3434
|
const parent = dirname8(dir);
|
|
3676
3435
|
if (parent === dir) return void 0;
|
|
@@ -3693,7 +3452,7 @@ function loadAlgoliaDoc(language) {
|
|
|
3693
3452
|
);
|
|
3694
3453
|
return "";
|
|
3695
3454
|
}
|
|
3696
|
-
return readFileSync(
|
|
3455
|
+
return readFileSync(join11(docsDir, files[0]), "utf8").trim();
|
|
3697
3456
|
}
|
|
3698
3457
|
function getNamedDoc(name, language) {
|
|
3699
3458
|
const docsDir = findDocsDir();
|
|
@@ -3701,7 +3460,7 @@ function getNamedDoc(name, language) {
|
|
|
3701
3460
|
logger.warn("docs/algolia-sdk not found");
|
|
3702
3461
|
return "";
|
|
3703
3462
|
}
|
|
3704
|
-
const file =
|
|
3463
|
+
const file = join11(docsDir, `${name}-${language}.md`);
|
|
3705
3464
|
if (!existsSync2(file)) {
|
|
3706
3465
|
logger.warn({ name, language }, "named SDK reference not found");
|
|
3707
3466
|
return "";
|
|
@@ -3728,50 +3487,50 @@ function shellQuote(value) {
|
|
|
3728
3487
|
}
|
|
3729
3488
|
|
|
3730
3489
|
// src/actions/implement.ts
|
|
3731
|
-
var implementSchema =
|
|
3732
|
-
filesChanged:
|
|
3733
|
-
summary:
|
|
3490
|
+
var implementSchema = z24.object({
|
|
3491
|
+
filesChanged: z24.array(z24.string()),
|
|
3492
|
+
summary: z24.string(),
|
|
3734
3493
|
// Absolute path to the throwaway worktree holding the generated changes, so
|
|
3735
3494
|
// the user can open it (`cd <worktreePath>`) or inspect the diff
|
|
3736
3495
|
// (`git -C <worktreePath> status/diff`).
|
|
3737
|
-
worktreePath:
|
|
3738
|
-
ingestCommand:
|
|
3496
|
+
worktreePath: z24.string().optional(),
|
|
3497
|
+
ingestCommand: z24.string().optional(),
|
|
3739
3498
|
// True when the user accepted the run-now prompt and the wizard executed the
|
|
3740
3499
|
// ingestion script; downstream steps use this to avoid telling the user to run
|
|
3741
3500
|
// a script that already ran.
|
|
3742
|
-
ingestScriptRan:
|
|
3501
|
+
ingestScriptRan: z24.boolean().optional(),
|
|
3743
3502
|
// Records ingested by the run-now execution, parsed from the script's
|
|
3744
3503
|
// machine-readable count line; absent when the script didn't run or emitted
|
|
3745
3504
|
// no parseable count.
|
|
3746
|
-
ingestRecordCount:
|
|
3505
|
+
ingestRecordCount: z24.number().optional(),
|
|
3747
3506
|
// Wall-clock duration of the run-now ingestion execution, in ms.
|
|
3748
|
-
ingestDurationMs:
|
|
3749
|
-
ingestionSource:
|
|
3507
|
+
ingestDurationMs: z24.number().optional(),
|
|
3508
|
+
ingestionSource: z24.enum(["local", "fileUpload", "generated"]),
|
|
3750
3509
|
// Suggested names/values, built from framework detection. The search agent is
|
|
3751
3510
|
// instructed to rename the prefix if it doesn't match the project's build
|
|
3752
3511
|
// tool, so the names it actually wrote can differ — treat these as hints, not
|
|
3753
3512
|
// ground truth (the agent's summary carries the final names).
|
|
3754
|
-
searchEnvVars:
|
|
3755
|
-
|
|
3756
|
-
name:
|
|
3757
|
-
value:
|
|
3513
|
+
searchEnvVars: z24.array(
|
|
3514
|
+
z24.object({
|
|
3515
|
+
name: z24.string(),
|
|
3516
|
+
value: z24.string()
|
|
3758
3517
|
})
|
|
3759
3518
|
).optional()
|
|
3760
3519
|
});
|
|
3761
|
-
var implementationOutputSchema =
|
|
3762
|
-
summary:
|
|
3520
|
+
var implementationOutputSchema = z24.object({
|
|
3521
|
+
summary: z24.string(),
|
|
3763
3522
|
// Ingestion only: how to run the generated script, as a structured pair the
|
|
3764
3523
|
// wizard turns into an argv (`<runtime> <entrypoint>`) — never a free-form
|
|
3765
3524
|
// command string. `runtime` is constrained to an allowlisted interpreter and
|
|
3766
3525
|
// `entrypoint` is validated to a worktree-relative path before execution, so
|
|
3767
3526
|
// the agent cannot inject extra commands or swap the interpreter.
|
|
3768
|
-
runtime:
|
|
3769
|
-
entrypoint:
|
|
3527
|
+
runtime: z24.enum(INGEST_RUNTIMES).optional(),
|
|
3528
|
+
entrypoint: z24.string().optional()
|
|
3770
3529
|
});
|
|
3771
|
-
var verificationOutputSchema =
|
|
3772
|
-
summary:
|
|
3773
|
-
sufficient:
|
|
3774
|
-
additionalInstructions:
|
|
3530
|
+
var verificationOutputSchema = z24.object({
|
|
3531
|
+
summary: z24.string(),
|
|
3532
|
+
sufficient: z24.boolean(),
|
|
3533
|
+
additionalInstructions: z24.string().optional()
|
|
3775
3534
|
});
|
|
3776
3535
|
var MAX_IMPLEMENT_VERIFICATION_ATTEMPTS = 3;
|
|
3777
3536
|
var DEFAULT_IMPLEMENT_USE_CASES = ["ingestion", "search"];
|
|
@@ -3885,7 +3644,7 @@ function searchInstructions(input) {
|
|
|
3885
3644
|
doc,
|
|
3886
3645
|
`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.`,
|
|
3887
3646
|
"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.",
|
|
3888
|
-
// appId always resolves (
|
|
3647
|
+
// appId always resolves (loadActiveProfile throws otherwise); only the
|
|
3889
3648
|
// search-only key is best-effort and can fall back to a placeholder.
|
|
3890
3649
|
`Values: App ID "${input.appId}", search-only key ${input.searchKey ? `"${input.searchKey}"` : "(placeholder for the developer to fill in)"}.`,
|
|
3891
3650
|
// Names are fixed, not the agent's to rename: the wizard writes the
|
|
@@ -4034,7 +3793,6 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4034
3793
|
}
|
|
4035
3794
|
}
|
|
4036
3795
|
const targetIndex = selected?.selection;
|
|
4037
|
-
useWizard.getState().setTargetIndex(targetIndex ?? null);
|
|
4038
3796
|
await assertGitRepoWithHead(repoRoot);
|
|
4039
3797
|
if (await isWorkingTreeDirty(repoRoot)) {
|
|
4040
3798
|
await confirmDirtyWorkingTree(ctx, repoRoot);
|
|
@@ -4045,7 +3803,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4045
3803
|
let appId;
|
|
4046
3804
|
let searchKey;
|
|
4047
3805
|
if (useCases.includes("search")) {
|
|
4048
|
-
appId = (await
|
|
3806
|
+
appId = (await loadActiveProfile()).appId;
|
|
4049
3807
|
try {
|
|
4050
3808
|
searchKey = await resolveSearchOnlyKey(targetIndex);
|
|
4051
3809
|
} catch (err) {
|
|
@@ -4156,8 +3914,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4156
3914
|
messages: []
|
|
4157
3915
|
}) === true;
|
|
4158
3916
|
if (runNow) {
|
|
4159
|
-
const
|
|
4160
|
-
const writeKey = await resolveWriteKey(targetIndex);
|
|
3917
|
+
const profile2 = await loadActiveProfile();
|
|
4161
3918
|
ctx.notify({ messages: [`Writing records to "${targetIndex}"\u2026`] });
|
|
4162
3919
|
const scriptLogId = ctx.logStart("runIngestScript", {
|
|
4163
3920
|
runtime: ingestRuntime,
|
|
@@ -4169,8 +3926,8 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4169
3926
|
ingestRuntime,
|
|
4170
3927
|
ingestEntrypoint,
|
|
4171
3928
|
{
|
|
4172
|
-
[APP_ID_VAR]:
|
|
4173
|
-
[API_KEY_VAR]:
|
|
3929
|
+
[APP_ID_VAR]: profile2.appId,
|
|
3930
|
+
[API_KEY_VAR]: profile2.apiKey
|
|
4174
3931
|
}
|
|
4175
3932
|
);
|
|
4176
3933
|
ctx.logEnd(scriptLogId, run.ok ? "success" : "error");
|
|
@@ -4242,7 +3999,7 @@ ${run.output}` : status;
|
|
|
4242
3999
|
// No question being asked here, just an acknowledgement — the
|
|
4243
4000
|
// continue/decline hints below already say "continue".
|
|
4244
4001
|
prompt: "",
|
|
4245
|
-
promptType: "
|
|
4002
|
+
promptType: "enterToContinue",
|
|
4246
4003
|
options: [],
|
|
4247
4004
|
messages: ingestOutcomeMessage ? [ingestOutcomeMessage, ...commandMessages] : commandMessages
|
|
4248
4005
|
});
|
|
@@ -4381,8 +4138,8 @@ var defaultWorkflow = {
|
|
|
4381
4138
|
defineStep({
|
|
4382
4139
|
id: "select-index",
|
|
4383
4140
|
title: "Set up index",
|
|
4384
|
-
outputSchema:
|
|
4385
|
-
selection:
|
|
4141
|
+
outputSchema: z25.object({
|
|
4142
|
+
selection: z25.string()
|
|
4386
4143
|
}),
|
|
4387
4144
|
run: (ctx) => selectIndexStep(ctx)
|
|
4388
4145
|
}),
|
|
@@ -4463,54 +4220,25 @@ var store = useWizard.getState();
|
|
|
4463
4220
|
var instance = render(/* @__PURE__ */ jsx14(App, {}), { incrementalRendering: true });
|
|
4464
4221
|
var user = await getUser();
|
|
4465
4222
|
if (!user) {
|
|
4466
|
-
|
|
4223
|
+
await instance.waitUntilRenderFlush();
|
|
4224
|
+
instance.cleanup();
|
|
4467
4225
|
try {
|
|
4468
4226
|
await runAuthLogin();
|
|
4469
4227
|
} catch (err) {
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
await instance.waitUntilExit();
|
|
4473
|
-
process.exit(1);
|
|
4474
|
-
}
|
|
4475
|
-
try {
|
|
4476
|
-
await promptForApplication();
|
|
4477
|
-
} catch (pickErr) {
|
|
4478
|
-
logger.warn(
|
|
4479
|
-
{ err: pickErr.message },
|
|
4480
|
-
"in-wizard application selection failed; handing over the terminal"
|
|
4481
|
-
);
|
|
4482
|
-
await instance.waitUntilRenderFlush();
|
|
4483
|
-
instance.cleanup();
|
|
4484
|
-
try {
|
|
4485
|
-
await runAuthLoginInTerminal();
|
|
4486
|
-
} catch (fallbackErr) {
|
|
4487
|
-
console.error(
|
|
4488
|
-
fallbackErr instanceof Error ? fallbackErr.message : String(fallbackErr)
|
|
4489
|
-
);
|
|
4490
|
-
process.exit(1);
|
|
4491
|
-
}
|
|
4492
|
-
instance = render(/* @__PURE__ */ jsx14(App, {}), { incrementalRendering: true });
|
|
4493
|
-
store.clearCliOutput();
|
|
4494
|
-
}
|
|
4228
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
4229
|
+
process.exit(1);
|
|
4495
4230
|
}
|
|
4496
|
-
|
|
4231
|
+
instance = render(/* @__PURE__ */ jsx14(App, {}), { incrementalRendering: true });
|
|
4497
4232
|
user = await getUser();
|
|
4498
4233
|
if (!user) {
|
|
4499
4234
|
store.setError(
|
|
4500
|
-
"Authentication completed but no Algolia user was returned. Try running `npx @algolia/cli
|
|
4235
|
+
"Authentication completed but no Algolia user was returned. Try running `npx @algolia/cli auth login` directly."
|
|
4501
4236
|
);
|
|
4502
4237
|
await instance.waitUntilExit();
|
|
4503
4238
|
process.exit(1);
|
|
4504
4239
|
}
|
|
4505
4240
|
}
|
|
4506
4241
|
store.setUser(user);
|
|
4242
|
+
var profile = await loadActiveProfile();
|
|
4507
4243
|
await store.waitForStart();
|
|
4508
|
-
|
|
4509
|
-
try {
|
|
4510
|
-
app = await ensureApplication();
|
|
4511
|
-
} catch (err) {
|
|
4512
|
-
store.setError(err instanceof Error ? err.message : String(err));
|
|
4513
|
-
await instance.waitUntilExit();
|
|
4514
|
-
process.exit(1);
|
|
4515
|
-
}
|
|
4516
|
-
runWorkflow(workflow, app.id);
|
|
4244
|
+
runWorkflow(workflow, profile?.appId);
|