@algolia/wizard 0.8.0-rc.58.43 → 0.8.0-rc.58.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/dist/main.js +504 -780
  3. package/package.json +3 -1
package/dist/main.js CHANGED
@@ -4,7 +4,7 @@
4
4
  import { render } from "ink";
5
5
 
6
6
  // src/ui/App.tsx
7
- import { Box as Box14, Text as Text14, useApp, useInput as useInput6, useWindowSize as useWindowSize8 } from "ink";
7
+ import { Box as Box13, Text as Text13, useApp, useInput as useInput6, useWindowSize as useWindowSize7 } from "ink";
8
8
 
9
9
  // src/core/store.ts
10
10
  import { create } from "zustand";
@@ -12,86 +12,32 @@ import { nanoid } from "nanoid";
12
12
 
13
13
  // src/lib/algoliaCli.ts
14
14
  import { spawn } from "node:child_process";
15
- import { z } from "zod";
16
- function npxArgs(args) {
17
- return ["--yes", "@algolia/cli@latest", ...args];
15
+ import { createRequire } from "node:module";
16
+ var require2 = createRequire(import.meta.url);
17
+ function algoliaCliEntry() {
18
+ return require2.resolve("@algolia/cli/bin/run.js");
18
19
  }
19
- var shell = process.platform === "win32";
20
- function lineSplitter(emit) {
21
- let buffer = "";
22
- return {
23
- push(chunk) {
24
- buffer += chunk;
25
- const lines = buffer.split("\n");
26
- buffer = lines.pop() ?? "";
27
- for (const line of lines) emit(line.replace(/\r$/, ""));
28
- },
29
- flush() {
30
- if (buffer) emit(buffer.replace(/\r$/, ""));
31
- buffer = "";
32
- }
33
- };
34
- }
35
- var wizardSink = (stream, line) => {
36
- if (!line.trim()) return;
37
- useWizard.getState().pushCliOutput(stream, line);
38
- };
39
- var stderrSink = (stream, line) => {
40
- if (stream === "stdout") return;
41
- wizardSink(stream, line);
42
- };
43
- function runAlgoliaCli(args, { onOutput } = {}) {
44
- const store = useWizard.getState();
45
- const logId = store.logStart("tool", `algolia ${args.join(" ")}`);
20
+ function runAlgoliaCli(args) {
46
21
  return new Promise((resolve4, reject) => {
47
- const child = spawn("npx", npxArgs(args), { shell });
22
+ const child = spawn(process.execPath, [algoliaCliEntry(), ...args]);
48
23
  let stdout = "";
49
24
  let stderr = "";
50
- const splitters = {
51
- stdout: lineSplitter((line) => onOutput?.("stdout", line)),
52
- stderr: lineSplitter((line) => onOutput?.("stderr", line))
53
- };
54
- child.stdout.on("data", (chunk) => {
55
- const text = String(chunk);
56
- stdout += text;
57
- splitters.stdout.push(text);
58
- });
59
- child.stderr.on("data", (chunk) => {
60
- const text = String(chunk);
61
- stderr += text;
62
- splitters.stderr.push(text);
63
- });
25
+ child.stdout.on("data", (chunk) => stdout += chunk);
26
+ child.stderr.on("data", (chunk) => stderr += chunk);
64
27
  child.on("error", reject);
65
28
  child.on("close", (code) => {
66
- splitters.stdout.flush();
67
- splitters.stderr.flush();
68
29
  if (code === 0) {
69
30
  resolve4(stdout);
70
31
  } else {
71
- const failed = stderr.trim();
72
- let detail = "";
73
- if (failed) {
74
- detail = `: ${failed}`;
75
- } else if (stdout.trim()) {
76
- detail = " (no stderr; stdout withheld \u2014 it may contain credentials)";
77
- }
32
+ const detail = stderr.trim() || stdout.trim();
78
33
  reject(
79
34
  new Error(
80
- `Algolia CLI \`${args.join(" ")}\` failed (exit ${code})${detail}`
35
+ `Algolia CLI \`${args.join(" ")}\` failed (exit ${code})${detail ? `: ${detail}` : ""}`
81
36
  )
82
37
  );
83
38
  }
84
39
  });
85
- }).then(
86
- (out) => {
87
- useWizard.getState().logEnd(logId, "success");
88
- return out;
89
- },
90
- (err) => {
91
- useWizard.getState().logEnd(logId, "error");
92
- throw err;
93
- }
94
- );
40
+ });
95
41
  }
96
42
  async function getUser() {
97
43
  let raw;
@@ -106,23 +52,19 @@ async function getUser() {
106
52
  return null;
107
53
  }
108
54
  }
109
- var loginResultSchema = z.object({
110
- success: z.boolean(),
111
- email: z.string().optional()
112
- });
113
- async function runAuthLogin() {
114
- const raw = await runAlgoliaCli(["auth", "login", "--non-interactive"], {
115
- onOutput: stderrSink
55
+ function runAuthLogin() {
56
+ return new Promise((resolve4, reject) => {
57
+ const child = spawn(
58
+ process.execPath,
59
+ [algoliaCliEntry(), "auth", "login", "--default"],
60
+ { stdio: "inherit" }
61
+ );
62
+ child.on("error", reject);
63
+ child.on("close", (code) => {
64
+ if (code === 0) resolve4();
65
+ else reject(new Error(`Algolia authentication failed (exit ${code}).`));
66
+ });
116
67
  });
117
- let parsed;
118
- try {
119
- parsed = loginResultSchema.safeParse(JSON.parse(raw));
120
- } catch {
121
- parsed = void 0;
122
- }
123
- if (parsed?.success && !parsed.data.success) {
124
- throw new Error("Algolia sign-in did not report success.");
125
- }
126
68
  }
127
69
 
128
70
  // src/lib/auth.ts
@@ -229,7 +171,6 @@ function describeInputValue(value) {
229
171
  return Array.isArray(value) ? value.join(", ") : value;
230
172
  }
231
173
  var NOTICE_INTERVAL_MS = 2e3;
232
- var CLI_OUTPUT_LIMIT = 200;
233
174
  var useWizard = create((set, get) => ({
234
175
  phase: "idle",
235
176
  homeScreen: "home",
@@ -241,18 +182,10 @@ var useWizard = create((set, get) => ({
241
182
  notices: [],
242
183
  _noticeQueue: [],
243
184
  _noticeTimer: null,
244
- cliOutput: [],
245
- targetIndex: null,
246
185
  logs: [],
247
186
  error: null,
248
187
  inputReq: null,
249
188
  _resolve: null,
250
- // Brackets a CLI subprocess that needs the screen. Sign-in happens after the
251
- // welcome screen's enter, so `endAuth` lands on 'preflight', not 'idle':
252
- // returning to 'idle' would put the welcome screen back up and ask the user
253
- // to confirm the run a second time.
254
- beginAuth: () => set({ phase: "authenticating", cliOutput: [] }),
255
- endAuth: () => set((s) => s.phase === "authenticating" ? { phase: "preflight" } : {}),
256
189
  // Advances past the welcome screen. Only meaningful from 'idle' — once the
257
190
  // workflow is running there's nothing left to confirm.
258
191
  // Reset `homeScreen` so preflight shows Welcome, not the Learn more sub-view.
@@ -287,13 +220,7 @@ var useWizard = create((set, get) => ({
287
220
  syncSteps: (steps, currentStepIndex) => set({ steps, currentStepIndex }),
288
221
  setActiveStep: (index) => {
289
222
  get()._clearNoticeQueue();
290
- set({
291
- phase: "running",
292
- currentStepIndex: index,
293
- output: "",
294
- notices: [],
295
- cliOutput: []
296
- });
223
+ set({ phase: "running", currentStepIndex: index, output: "", notices: [] });
297
224
  },
298
225
  setUser: (user) => set({ user }),
299
226
  appendToken: (text) => set((s) => ({ output: s.output + text })),
@@ -334,16 +261,6 @@ var useWizard = create((set, get) => ({
334
261
  get()._clearNoticeQueue();
335
262
  set({ notices: [] });
336
263
  },
337
- // Unthrottled, unlike `pushNotice`: these lines arrive at whatever rate the
338
- // subprocess emits them, and holding them back would land output after the
339
- // command it belongs to has already exited.
340
- pushCliOutput: (stream, text) => set((s) => ({
341
- cliOutput: [...s.cliOutput, { id: nanoid(), stream, text }].slice(
342
- -CLI_OUTPUT_LIMIT
343
- )
344
- })),
345
- clearCliOutput: () => set({ cliOutput: [] }),
346
- setTargetIndex: (index) => set({ targetIndex: index }),
347
264
  logStart: (kind, name, input) => {
348
265
  const id = nanoid();
349
266
  set((s) => ({
@@ -388,8 +305,6 @@ var useWizard = create((set, get) => ({
388
305
  currentStepIndex: 0,
389
306
  output: "",
390
307
  notices: [],
391
- cliOutput: [],
392
- targetIndex: null,
393
308
  logs: [],
394
309
  error: null,
395
310
  inputReq: null,
@@ -398,100 +313,16 @@ var useWizard = create((set, get) => ({
398
313
  }
399
314
  }));
400
315
 
401
- // src/ui/CliOutput.tsx
402
- import { Box, Text, useWindowSize } from "ink";
403
-
404
- // src/ui/theme.ts
405
- var MARKER = {
406
- pending: "\u25CB",
407
- running: "\u25D0",
408
- done: "\u2713",
409
- error: "\u2716"
410
- };
411
- var BRAND = "#003DFF";
412
- var SECONDARY = "#5468FF";
413
- var DANGER = "#F86E7E";
414
- var COLORS = {
415
- brand: BRAND,
416
- primary: "#E6EDF3",
417
- secondary: SECONDARY,
418
- strong: "#FFFFFF",
419
- muted: "#8B949E",
420
- dim: "#484F58",
421
- highlight: { bg: "#12331C", fg: "#4ADE80" },
422
- badge: "#E3B341",
423
- danger: DANGER,
424
- success: "#4ADE80",
425
- bg: {
426
- main: "#0B0E14",
427
- sidebar: "#14171E"
428
- },
429
- border: "#30363D",
430
- accent: "#76A0FF",
431
- status: {
432
- pending: "gray",
433
- running: "#76A0FF",
434
- done: "#4ADE80",
435
- error: DANGER
436
- }
437
- };
438
-
439
- // src/ui/CliOutput.tsx
440
- import { jsxs } from "react/jsx-runtime";
441
- var CLI_MARKER = "\u203A";
442
- var RESERVED_ROWS = 16;
443
- var MAX_ROWS = 12;
444
- var PANEL_TEXT_WIDTH = 45;
445
- var URL_PATTERN = /https?:\/\//;
446
- function rowCost(text) {
447
- return URL_PATTERN.test(text) ? Math.max(1, Math.ceil(text.length / PANEL_TEXT_WIDTH)) : 1;
448
- }
449
- function CliOutput() {
450
- const cliOutput = useWizard((s) => s.cliOutput);
451
- const { rows } = useWindowSize();
452
- if (!cliOutput.length) return null;
453
- const rowBudget = Math.min(Math.max(rows - RESERVED_ROWS, 3), MAX_ROWS);
454
- const visible = [];
455
- let usedRows = 0;
456
- for (let i = cliOutput.length - 1; i >= 0; i--) {
457
- const cost = rowCost(cliOutput[i].text);
458
- if (usedRows + cost > rowBudget && visible.length > 0) break;
459
- visible.unshift(cliOutput[i]);
460
- usedRows += cost;
461
- }
462
- const hidden = cliOutput.length - visible.length;
463
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
464
- hidden > 0 && /* @__PURE__ */ jsxs(Text, { color: COLORS.dim, children: [
465
- "\u2191 ",
466
- hidden,
467
- " earlier line(s)"
468
- ] }),
469
- visible.map((line) => /* @__PURE__ */ jsxs(
470
- Text,
471
- {
472
- color: line.stream === "stderr" ? COLORS.muted : COLORS.dim,
473
- wrap: URL_PATTERN.test(line.text) ? "wrap" : "truncate",
474
- children: [
475
- CLI_MARKER,
476
- " ",
477
- line.text
478
- ]
479
- },
480
- line.id
481
- ))
482
- ] });
483
- }
484
-
485
316
  // src/ui/Notices.tsx
486
- import { Box as Box3, Text as Text3, useWindowSize as useWindowSize3 } from "ink";
317
+ import { Box as Box2, Text as Text2, useWindowSize as useWindowSize2 } from "ink";
487
318
  import { useEffect as useEffect2, useState as useState2 } from "react";
488
319
 
489
320
  // src/ui/Table.tsx
490
- import { Box as Box2, Text as Text2, measureElement, useWindowSize as useWindowSize2 } from "ink";
321
+ import { Box, Text, measureElement, useWindowSize } from "ink";
491
322
  import { useEffect, useRef, useState } from "react";
492
323
  import { jsx } from "react/jsx-runtime";
493
324
  function Table({ columns, rows }) {
494
- const { columns: termCols } = useWindowSize2();
325
+ const { columns: termCols } = useWindowSize();
495
326
  const ref = useRef(null);
496
327
  const [width, setWidth] = useState(0);
497
328
  useEffect(() => {
@@ -499,7 +330,7 @@ function Table({ columns, rows }) {
499
330
  }, [termCols, columns, rows]);
500
331
  if (rows.length === 0) return null;
501
332
  const lines = formatTable(columns, rows, width || void 0);
502
- return /* @__PURE__ */ jsx(Box2, { flexDirection: "column", ref, children: lines.map((line, i) => /* @__PURE__ */ jsx(Text2, { wrap: "truncate", children: line }, `tbl-${i}`)) });
333
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", ref, children: lines.map((line, i) => /* @__PURE__ */ jsx(Text, { wrap: "truncate", children: line }, `tbl-${i}`)) });
503
334
  }
504
335
  function formatTable(columns, rows, width) {
505
336
  const natural = columns.map(
@@ -539,13 +370,48 @@ function resize(widths, budget) {
539
370
  }
540
371
  var truncate = (s, width) => s.length <= width ? s : width <= 1 ? s.slice(0, width) : `${s.slice(0, width - 1)}\u2026`;
541
372
 
373
+ // src/ui/theme.ts
374
+ var MARKER = {
375
+ pending: "\u25CB",
376
+ running: "\u25D0",
377
+ done: "\u2713",
378
+ error: "\u2716"
379
+ };
380
+ var BRAND = "#003DFF";
381
+ var SECONDARY = "#5468FF";
382
+ var DANGER = "#F86E7E";
383
+ var COLORS = {
384
+ brand: BRAND,
385
+ primary: "#E6EDF3",
386
+ secondary: SECONDARY,
387
+ strong: "#FFFFFF",
388
+ muted: "#8B949E",
389
+ dim: "#484F58",
390
+ highlight: { bg: "#12331C", fg: "#4ADE80" },
391
+ badge: "#E3B341",
392
+ danger: DANGER,
393
+ success: "#4ADE80",
394
+ bg: {
395
+ main: "#0B0E14",
396
+ sidebar: "#14171E"
397
+ },
398
+ border: "#30363D",
399
+ accent: "#76A0FF",
400
+ status: {
401
+ pending: "gray",
402
+ running: "#76A0FF",
403
+ done: "#4ADE80",
404
+ error: DANGER
405
+ }
406
+ };
407
+
542
408
  // src/ui/Notices.tsx
543
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
409
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
544
410
  var AGENT_MARKER = "\u2726";
545
- var RESERVED_ROWS2 = 14;
546
- var PANEL_TEXT_WIDTH2 = 45;
411
+ var RESERVED_ROWS = 14;
412
+ var PANEL_TEXT_WIDTH = 45;
547
413
  function messageLineCount(text) {
548
- return Math.max(1, Math.ceil(text.length / PANEL_TEXT_WIDTH2));
414
+ return Math.max(1, Math.ceil(text.length / PANEL_TEXT_WIDTH));
549
415
  }
550
416
  function noticeLineCount(notice) {
551
417
  const messageLines = (notice.messages ?? []).reduce((sum, m) => {
@@ -556,7 +422,7 @@ function noticeLineCount(notice) {
556
422
  return messageLines + tableLines;
557
423
  }
558
424
  function fitVisibleNotices(notices, windowRows) {
559
- const budget = Math.max(windowRows - RESERVED_ROWS2, 3);
425
+ const budget = Math.max(windowRows - RESERVED_ROWS, 3);
560
426
  let used = 0;
561
427
  let count = 0;
562
428
  for (let i = notices.length - 1; i >= 0; i--) {
@@ -589,7 +455,7 @@ function parseHex(hex) {
589
455
  }
590
456
  function Notices() {
591
457
  const notices = useWizard((s) => s.notices);
592
- const { rows: windowRows } = useWindowSize3();
458
+ const { rows: windowRows } = useWindowSize2();
593
459
  const visible = fitVisibleNotices(notices, windowRows);
594
460
  const [pulseStep, setPulseStep] = useState2(0);
595
461
  useEffect2(() => {
@@ -606,14 +472,14 @@ function Notices() {
606
472
  }, []);
607
473
  if (!visible.length) return null;
608
474
  const pulseColor = PULSE_COLORS[pulseStep];
609
- return /* @__PURE__ */ jsx2(Box3, { flexDirection: "column", gap: 1, marginBottom: 1, children: visible.map((notice, i) => {
475
+ return /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", gap: 1, marginBottom: 1, children: visible.map((notice, i) => {
610
476
  const isLatest = i === visible.length - 1;
611
- return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", children: [
477
+ return /* @__PURE__ */ jsxs(Box2, { flexDirection: "column", children: [
612
478
  notice.messages?.map((m, j) => {
613
479
  const line = typeof m === "string" ? { text: m } : m;
614
480
  const prefix = j === 0 ? `${AGENT_MARKER} ` : " ";
615
- return /* @__PURE__ */ jsxs2(
616
- Text3,
481
+ return /* @__PURE__ */ jsxs(
482
+ Text2,
617
483
  {
618
484
  color: isLatest && !line.color ? pulseColor : line.color ?? COLORS.dim,
619
485
  bold: line.bold,
@@ -631,37 +497,37 @@ function Notices() {
631
497
  }
632
498
 
633
499
  // src/ui/PromptInput.tsx
634
- import { Box as Box6, Text as Text6, useInput as useInput2 } from "ink";
500
+ import { Box as Box5, Text as Text5, useInput as useInput2 } from "ink";
635
501
  import TextInput from "ink-text-input";
636
502
  import { useState as useState4 } from "react";
637
503
 
638
504
  // src/ui/NextAction.tsx
639
- import { Box as Box4, Text as Text4 } from "ink";
640
- import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
505
+ import { Box as Box3, Text as Text3 } from "ink";
506
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
641
507
  function NextAction({
642
508
  action,
643
509
  keyHint,
644
510
  hierarchy = "primary"
645
511
  }) {
646
- return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "row", gap: 1, children: [
647
- hierarchy === "primary" && /* @__PURE__ */ jsx3(Text4, { color: COLORS.success, bold: true, children: `> ${action}` }),
648
- hierarchy === "secondary" && /* @__PURE__ */ jsxs3(Fragment, { children: [
649
- /* @__PURE__ */ jsx3(Text4, { color: COLORS.success, bold: true, children: `>` }),
650
- /* @__PURE__ */ jsx3(Text4, { color: COLORS.primary, bold: true, children: action })
512
+ return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "row", gap: 1, children: [
513
+ hierarchy === "primary" && /* @__PURE__ */ jsx3(Text3, { color: COLORS.success, bold: true, children: `> ${action}` }),
514
+ hierarchy === "secondary" && /* @__PURE__ */ jsxs2(Fragment, { children: [
515
+ /* @__PURE__ */ jsx3(Text3, { color: COLORS.success, bold: true, children: `>` }),
516
+ /* @__PURE__ */ jsx3(Text3, { color: COLORS.primary, bold: true, children: action })
651
517
  ] }),
652
- /* @__PURE__ */ jsxs3(Box4, { children: [
653
- /* @__PURE__ */ jsx3(Text4, { color: COLORS.muted, children: "press " }),
654
- /* @__PURE__ */ jsx3(Text4, { color: COLORS.muted, children: `[` }),
655
- /* @__PURE__ */ jsx3(Text4, { color: COLORS.primary, children: keyHint }),
656
- /* @__PURE__ */ jsx3(Text4, { color: COLORS.muted, children: `]` })
518
+ /* @__PURE__ */ jsxs2(Box3, { children: [
519
+ /* @__PURE__ */ jsx3(Text3, { color: COLORS.muted, children: "press " }),
520
+ /* @__PURE__ */ jsx3(Text3, { color: COLORS.muted, children: `[` }),
521
+ /* @__PURE__ */ jsx3(Text3, { color: COLORS.primary, children: keyHint }),
522
+ /* @__PURE__ */ jsx3(Text3, { color: COLORS.muted, children: `]` })
657
523
  ] })
658
524
  ] });
659
525
  }
660
526
 
661
527
  // src/ui/SelectPrompt.tsx
662
- import { Box as Box5, Text as Text5, measureElement as measureElement2, useInput, useWindowSize as useWindowSize4 } from "ink";
528
+ import { Box as Box4, Text as Text4, measureElement as measureElement2, useInput, useWindowSize as useWindowSize3 } from "ink";
663
529
  import { useLayoutEffect, useRef as useRef2, useState as useState3 } from "react";
664
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
530
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
665
531
  var CANCEL = "cancel";
666
532
  var ARROW_WIDTH = 4;
667
533
  var COLUMN_GAP = 2;
@@ -701,7 +567,7 @@ function SelectPrompt({
701
567
  hints.push({ key: "[enter]", label: "confirm" });
702
568
  const containerRef = useRef2(null);
703
569
  const viewportRef = useRef2(null);
704
- const { columns, rows: windowRows } = useWindowSize4();
570
+ const { columns, rows: windowRows } = useWindowSize3();
705
571
  const [width, setWidth] = useState3(columns);
706
572
  const [viewportHeight, setViewportHeight] = useState3(null);
707
573
  useLayoutEffect(() => {
@@ -766,18 +632,18 @@ function SelectPrompt({
766
632
  }
767
633
  }
768
634
  });
769
- return /* @__PURE__ */ jsx4(Box5, { ref: containerRef, flexGrow: 1, children: /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", gap: 1, width, children: [
770
- /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", gap: 1, flexShrink: 0, children: [
771
- error && /* @__PURE__ */ jsx4(Text5, { color: COLORS.danger, children: error }),
772
- messages?.map((m, i) => /* @__PURE__ */ jsx4(Text5, { color: COLORS.muted, children: m }, `msg-${i}`)),
635
+ return /* @__PURE__ */ jsx4(Box4, { ref: containerRef, flexGrow: 1, children: /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", gap: 1, width, children: [
636
+ /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", gap: 1, flexShrink: 0, children: [
637
+ error && /* @__PURE__ */ jsx4(Text4, { color: COLORS.danger, children: error }),
638
+ messages?.map((m, i) => /* @__PURE__ */ jsx4(Text4, { color: COLORS.muted, children: m }, `msg-${i}`)),
773
639
  table && /* @__PURE__ */ jsx4(Table, { columns: table.columns, rows: table.rows }),
774
- /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
775
- question && /* @__PURE__ */ jsx4(Text5, { color: COLORS.muted, children: question }),
776
- helpText && /* @__PURE__ */ jsx4(Text5, { color: COLORS.dim, children: helpText })
640
+ /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", children: [
641
+ question && /* @__PURE__ */ jsx4(Text4, { color: COLORS.muted, children: question }),
642
+ helpText && /* @__PURE__ */ jsx4(Text4, { color: COLORS.dim, children: helpText })
777
643
  ] })
778
644
  ] }),
779
- /* @__PURE__ */ jsxs4(Box5, { ref: viewportRef, flexDirection: "column", flexGrow: 1, children: [
780
- hiddenAbove > 0 && /* @__PURE__ */ jsxs4(Text5, { color: COLORS.dim, children: [
645
+ /* @__PURE__ */ jsxs3(Box4, { ref: viewportRef, flexDirection: "column", flexGrow: 1, children: [
646
+ hiddenAbove > 0 && /* @__PURE__ */ jsxs3(Text4, { color: COLORS.dim, children: [
781
647
  "\u2191 ",
782
648
  hiddenAbove,
783
649
  " more"
@@ -789,45 +655,45 @@ function SelectPrompt({
789
655
  const bullet = multi && !isCancel ? checked.has(i) ? "\u25CF " : "\u25CB " : "";
790
656
  const sec = isCancel ? void 0 : secondary?.[i];
791
657
  const labelColor = highlighted ? COLORS.highlight.fg : void 0;
792
- const label = /* @__PURE__ */ jsxs4(Text5, { color: labelColor, wrap: "truncate", children: [
658
+ const label = /* @__PURE__ */ jsxs3(Text4, { color: labelColor, wrap: "truncate", children: [
793
659
  highlighted ? "\u276F " : " ",
794
660
  bullet,
795
661
  option
796
662
  ] });
797
663
  const isText = sec?.kind === "text";
798
- return /* @__PURE__ */ jsxs4(
799
- Box5,
664
+ return /* @__PURE__ */ jsxs3(
665
+ Box4,
800
666
  {
801
667
  width: isText ? "100%" : barWidth,
802
668
  paddingX: 1,
803
669
  paddingY: 1,
804
670
  backgroundColor: highlighted ? COLORS.highlight.bg : void 0,
805
671
  children: [
806
- /* @__PURE__ */ jsx4(Box5, { width: isText ? labelWidth : barLabelWidth, children: label }),
807
- isText && textWidth > 0 && /* @__PURE__ */ jsx4(Box5, { width: textWidth, children: /* @__PURE__ */ jsx4(
808
- Text5,
672
+ /* @__PURE__ */ jsx4(Box4, { width: isText ? labelWidth : barLabelWidth, children: label }),
673
+ isText && textWidth > 0 && /* @__PURE__ */ jsx4(Box4, { width: textWidth, children: /* @__PURE__ */ jsx4(
674
+ Text4,
809
675
  {
810
676
  wrap: "truncate",
811
677
  color: highlighted ? COLORS.primary : COLORS.muted,
812
678
  children: sec.value
813
679
  }
814
680
  ) }),
815
- sec?.kind === "badge" && /* @__PURE__ */ jsx4(Box5, { width: badgeWidth, justifyContent: "flex-end", children: /* @__PURE__ */ jsx4(Text5, { color: COLORS.badge, wrap: "truncate", children: sec.value }) })
681
+ sec?.kind === "badge" && /* @__PURE__ */ jsx4(Box4, { width: badgeWidth, justifyContent: "flex-end", children: /* @__PURE__ */ jsx4(Text4, { color: COLORS.badge, wrap: "truncate", children: sec.value }) })
816
682
  ]
817
683
  },
818
684
  `row-${i}`
819
685
  );
820
686
  }),
821
- hiddenBelow > 0 && /* @__PURE__ */ jsxs4(Text5, { color: COLORS.dim, children: [
687
+ hiddenBelow > 0 && /* @__PURE__ */ jsxs3(Text4, { color: COLORS.dim, children: [
822
688
  "\u2193 ",
823
689
  hiddenBelow,
824
690
  " more"
825
691
  ] })
826
692
  ] }),
827
- /* @__PURE__ */ jsx4(Box5, { flexShrink: 0, children: /* @__PURE__ */ jsx4(Text5, { children: hints.map(({ key, label }, i) => /* @__PURE__ */ jsxs4(Text5, { children: [
693
+ /* @__PURE__ */ jsx4(Box4, { flexShrink: 0, children: /* @__PURE__ */ jsx4(Text4, { children: hints.map(({ key, label }, i) => /* @__PURE__ */ jsxs3(Text4, { children: [
828
694
  i > 0 ? " " : "",
829
- /* @__PURE__ */ jsx4(Text5, { color: COLORS.primary, children: key }),
830
- /* @__PURE__ */ jsxs4(Text5, { color: COLORS.dim, children: [
695
+ /* @__PURE__ */ jsx4(Text4, { color: COLORS.primary, children: key }),
696
+ /* @__PURE__ */ jsxs3(Text4, { color: COLORS.dim, children: [
831
697
  " ",
832
698
  label
833
699
  ] })
@@ -836,7 +702,7 @@ function SelectPrompt({
836
702
  }
837
703
 
838
704
  // src/ui/PromptInput.tsx
839
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
705
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
840
706
  var ACCEPT_REJECT_OPTIONS = ["Accept", "Reject"];
841
707
  function EnterToContinuePrompt({
842
708
  question,
@@ -847,10 +713,10 @@ function EnterToContinuePrompt({
847
713
  if (key.return) onDecide(true);
848
714
  else if (key.escape) onDecide(false);
849
715
  });
850
- return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", gap: 1, children: [
851
- messages?.map((m, i) => /* @__PURE__ */ jsx5(Text6, { color: COLORS.muted, children: m }, `msg-${i}`)),
852
- question && /* @__PURE__ */ jsx5(Text6, { color: COLORS.primary, children: question }),
853
- /* @__PURE__ */ jsxs5(Box6, { gap: 1, flexDirection: "column", children: [
716
+ return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", gap: 1, children: [
717
+ messages?.map((m, i) => /* @__PURE__ */ jsx5(Text5, { color: COLORS.muted, children: m }, `msg-${i}`)),
718
+ question && /* @__PURE__ */ jsx5(Text5, { color: COLORS.primary, children: question }),
719
+ /* @__PURE__ */ jsxs4(Box5, { gap: 1, flexDirection: "column", children: [
854
720
  /* @__PURE__ */ jsx5(NextAction, { action: "continue", keyHint: "enter" }),
855
721
  /* @__PURE__ */ jsx5(NextAction, { action: "decline", keyHint: "esc", hierarchy: "secondary" })
856
722
  ] })
@@ -860,11 +726,11 @@ function PromptInput() {
860
726
  const { phase, inputReq, submitInput } = useWizard();
861
727
  const [draft, setDraft] = useState4("");
862
728
  if (phase === "done" || phase === "error") {
863
- return /* @__PURE__ */ jsx5(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text6, { color: "gray", dimColor: true, children: "Press Enter or Esc to exit" }) });
729
+ return /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { color: "gray", dimColor: true, children: "Press Enter or Esc to exit" }) });
864
730
  }
865
731
  if (phase !== "awaitingInput" || !inputReq) return null;
866
732
  if (inputReq.promptType === "multipleChoice") {
867
- return /* @__PURE__ */ jsx5(Box6, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
733
+ return /* @__PURE__ */ jsx5(Box5, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
868
734
  SelectPrompt,
869
735
  {
870
736
  question: inputReq.prompt,
@@ -881,7 +747,7 @@ function PromptInput() {
881
747
  ) });
882
748
  }
883
749
  if (inputReq.promptType === "multiSelect") {
884
- return /* @__PURE__ */ jsx5(Box6, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
750
+ return /* @__PURE__ */ jsx5(Box5, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
885
751
  SelectPrompt,
886
752
  {
887
753
  multi: true,
@@ -896,7 +762,7 @@ function PromptInput() {
896
762
  ) });
897
763
  }
898
764
  if (inputReq.promptType === "notice") {
899
- return /* @__PURE__ */ jsx5(Box6, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
765
+ return /* @__PURE__ */ jsx5(Box5, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
900
766
  SelectPrompt,
901
767
  {
902
768
  question: inputReq.prompt,
@@ -918,7 +784,7 @@ function PromptInput() {
918
784
  }
919
785
  if (inputReq.promptType === "acceptReject") {
920
786
  const labels = inputReq.options?.length ? inputReq.options : ACCEPT_REJECT_OPTIONS;
921
- return /* @__PURE__ */ jsx5(Box6, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
787
+ return /* @__PURE__ */ jsx5(Box5, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
922
788
  SelectPrompt,
923
789
  {
924
790
  question: inputReq.prompt,
@@ -929,11 +795,11 @@ function PromptInput() {
929
795
  }
930
796
  ) });
931
797
  }
932
- return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
933
- inputReq.error && /* @__PURE__ */ jsx5(Text6, { color: COLORS.danger, children: inputReq.error }),
934
- inputReq.messages?.map((m, i) => /* @__PURE__ */ jsx5(Text6, { color: COLORS.muted, children: m }, `msg-${i}`)),
935
- /* @__PURE__ */ jsxs5(Box6, { children: [
936
- /* @__PURE__ */ jsxs5(Text6, { color: COLORS.primary, children: [
798
+ return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
799
+ inputReq.error && /* @__PURE__ */ jsx5(Text5, { color: COLORS.danger, children: inputReq.error }),
800
+ inputReq.messages?.map((m, i) => /* @__PURE__ */ jsx5(Text5, { color: COLORS.muted, children: m }, `msg-${i}`)),
801
+ /* @__PURE__ */ jsxs4(Box5, { children: [
802
+ /* @__PURE__ */ jsxs4(Text5, { color: COLORS.primary, children: [
937
803
  inputReq.prompt,
938
804
  " "
939
805
  ] }),
@@ -955,7 +821,7 @@ function PromptInput() {
955
821
  // src/ui/Welcome.tsx
956
822
  import { dirname as dirname2, join as join3 } from "node:path";
957
823
  import { fileURLToPath } from "node:url";
958
- import { Box as Box7, Spacer, Text as Text7, useInput as useInput3, useWindowSize as useWindowSize5 } from "ink";
824
+ import { Box as Box6, Spacer, Text as Text6, useInput as useInput3, useWindowSize as useWindowSize4 } from "ink";
959
825
 
960
826
  // src/ui/copy/welcome.ts
961
827
  var sidebarItems = [
@@ -983,27 +849,27 @@ var sidebarItems = [
983
849
 
984
850
  // src/ui/Welcome.tsx
985
851
  import Image, { InkPictureProvider } from "ink-picture";
986
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
852
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
987
853
  var IMAGE_PATH = join3(dirname2(fileURLToPath(import.meta.url)), "algolia.png");
988
854
  function SidebarItem({
989
855
  title,
990
856
  description
991
857
  }) {
992
- return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", children: [
993
- /* @__PURE__ */ jsxs6(Box7, { gap: 1, children: [
994
- /* @__PURE__ */ jsx6(Text7, { color: COLORS.success, children: "\u2192" }),
995
- /* @__PURE__ */ jsx6(Text7, { color: COLORS.strong, bold: true, children: title })
858
+ return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
859
+ /* @__PURE__ */ jsxs5(Box6, { gap: 1, children: [
860
+ /* @__PURE__ */ jsx6(Text6, { color: COLORS.success, children: "\u2192" }),
861
+ /* @__PURE__ */ jsx6(Text6, { color: COLORS.strong, bold: true, children: title })
996
862
  ] }),
997
- /* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", gap: 2, children: [
863
+ /* @__PURE__ */ jsxs5(Box6, { flexDirection: "row", gap: 2, children: [
998
864
  /* @__PURE__ */ jsx6(Spacer, {}),
999
- /* @__PURE__ */ jsx6(Text7, { color: COLORS.muted, children: description })
865
+ /* @__PURE__ */ jsx6(Text6, { color: COLORS.muted, children: description })
1000
866
  ] })
1001
867
  ] });
1002
868
  }
1003
869
  function Welcome() {
1004
870
  const confirmStart = useWizard((s) => s.confirmStart);
1005
871
  const openLearnMore = useWizard((s) => s.openLearnMore);
1006
- const { rows } = useWindowSize5();
872
+ const { rows } = useWindowSize4();
1007
873
  useInput3((input, key) => {
1008
874
  if (key.return) confirmStart();
1009
875
  else if (input === "i") openLearnMore();
@@ -1022,15 +888,15 @@ function Welcome() {
1022
888
  if (rows < 30) {
1023
889
  layout = scales["small"];
1024
890
  }
1025
- return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", justifyContent: "space-between", width: "100%", children: [
891
+ return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "row", justifyContent: "space-between", width: "100%", children: [
1026
892
  /* @__PURE__ */ jsx6(
1027
- Box7,
893
+ Box6,
1028
894
  {
1029
895
  paddingY: layout.main.padding.y,
1030
896
  paddingX: layout.main.padding.x,
1031
897
  flexDirection: "column",
1032
898
  justifyContent: "center",
1033
- children: /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", gap: 2, children: [
899
+ children: /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", gap: 2, children: [
1034
900
  /* @__PURE__ */ jsx6(InkPictureProvider, { children: /* @__PURE__ */ jsx6(
1035
901
  Image,
1036
902
  {
@@ -1042,16 +908,16 @@ function Welcome() {
1042
908
  protocol: "halfBlock"
1043
909
  }
1044
910
  ) }),
1045
- /* @__PURE__ */ jsx6(Text7, { color: COLORS.muted, children: "\u2726 From zero \u2192 working search in ~10 minutes" }),
1046
- /* @__PURE__ */ jsxs6(Box7, { gap: 1, flexDirection: "column", children: [
911
+ /* @__PURE__ */ jsx6(Text6, { color: COLORS.muted, children: "\u2726 From zero \u2192 working search in ~10 minutes" }),
912
+ /* @__PURE__ */ jsxs5(Box6, { gap: 1, flexDirection: "column", children: [
1047
913
  /* @__PURE__ */ jsx6(NextAction, { action: "start wizard", keyHint: "enter" }),
1048
914
  /* @__PURE__ */ jsx6(NextAction, { action: "learn more", keyHint: "i", hierarchy: "secondary" })
1049
915
  ] })
1050
916
  ] })
1051
917
  }
1052
918
  ),
1053
- /* @__PURE__ */ jsxs6(
1054
- Box7,
919
+ /* @__PURE__ */ jsxs5(
920
+ Box6,
1055
921
  {
1056
922
  backgroundColor: COLORS.bg.sidebar,
1057
923
  width: 40,
@@ -1061,7 +927,7 @@ function Welcome() {
1061
927
  flexDirection: "column",
1062
928
  justifyContent: "center",
1063
929
  children: [
1064
- /* @__PURE__ */ jsx6(Text7, { color: COLORS.muted, children: "WHAT THIS WIZARD WILL DO" }),
930
+ /* @__PURE__ */ jsx6(Text6, { color: COLORS.muted, children: "WHAT THIS WIZARD WILL DO" }),
1065
931
  sidebarItems.map((i, idx) => /* @__PURE__ */ jsx6(SidebarItem, { title: i.title, description: i.description }, idx))
1066
932
  ]
1067
933
  }
@@ -1071,7 +937,7 @@ function Welcome() {
1071
937
 
1072
938
  // src/ui/LearnMore.tsx
1073
939
  import { Fragment as Fragment2 } from "react";
1074
- import { Box as Box8, Text as Text8, useInput as useInput4, useWindowSize as useWindowSize6 } from "ink";
940
+ import { Box as Box7, Text as Text7, useInput as useInput4, useWindowSize as useWindowSize5 } from "ink";
1075
941
 
1076
942
  // src/ui/copy/learn-more.ts
1077
943
  var accessIntro = "Everything runs locally on your machine. Nothing is written or sent without an explicit yes from you.";
@@ -1108,7 +974,7 @@ var policyLinks = [
1108
974
  ];
1109
975
 
1110
976
  // src/ui/LearnMore.tsx
1111
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
977
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1112
978
  var TAG_COLORS = {
1113
979
  READ: COLORS.success,
1114
980
  WRITE: COLORS.badge,
@@ -1124,25 +990,25 @@ function NeverLine({
1124
990
  }) {
1125
991
  const used = segments.reduce((n, s) => n + s.text.length, 0);
1126
992
  const rightPad = Math.max(0, width - 2 - NEVER_BOX_PAD_X - used);
1127
- return /* @__PURE__ */ jsxs7(Text8, { children: [
1128
- /* @__PURE__ */ jsx7(Text8, { color: COLORS.danger, children: "\u2502" }),
993
+ return /* @__PURE__ */ jsxs6(Text7, { children: [
994
+ /* @__PURE__ */ jsx7(Text7, { color: COLORS.danger, children: "\u2502" }),
1129
995
  " ".repeat(NEVER_BOX_PAD_X),
1130
- segments.map((s, i) => /* @__PURE__ */ jsx7(Text8, { color: s.color, bold: s.bold, children: s.text }, i)),
996
+ segments.map((s, i) => /* @__PURE__ */ jsx7(Text7, { color: s.color, bold: s.bold, children: s.text }, i)),
1131
997
  " ".repeat(rightPad),
1132
- /* @__PURE__ */ jsx7(Text8, { color: COLORS.danger, children: "\u2502" })
998
+ /* @__PURE__ */ jsx7(Text7, { color: COLORS.danger, children: "\u2502" })
1133
999
  ] });
1134
1000
  }
1135
1001
  function LearnMore() {
1136
1002
  const confirmStart = useWizard((s) => s.confirmStart);
1137
1003
  const backToHome = useWizard((s) => s.backToHome);
1138
- const { columns } = useWindowSize6();
1004
+ const { columns } = useWindowSize5();
1139
1005
  const dividerWidth = Math.max(0, columns - PADDING_X * 2);
1140
1006
  useInput4((_input, key) => {
1141
1007
  if (key.escape) backToHome();
1142
1008
  else if (key.return) confirmStart();
1143
1009
  });
1144
- return /* @__PURE__ */ jsxs7(
1145
- Box8,
1010
+ return /* @__PURE__ */ jsxs6(
1011
+ Box7,
1146
1012
  {
1147
1013
  flexDirection: "column",
1148
1014
  paddingX: PADDING_X,
@@ -1150,20 +1016,20 @@ function LearnMore() {
1150
1016
  width: "100%",
1151
1017
  gap: 1,
1152
1018
  children: [
1153
- /* @__PURE__ */ jsx7(Text8, { color: COLORS.strong, bold: true, children: "What algolia wizard accesses" }),
1154
- /* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: accessIntro }),
1155
- /* @__PURE__ */ jsx7(Box8, { flexDirection: "column", children: accessItems.map((item) => /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", marginTop: 1, children: [
1156
- /* @__PURE__ */ jsx7(Text8, { color: COLORS.border, children: "\u2500".repeat(dividerWidth) }),
1157
- /* @__PURE__ */ jsxs7(Box8, { flexDirection: "row", gap: 1, marginTop: 1, children: [
1158
- /* @__PURE__ */ jsx7(Box8, { width: TAG_COLUMN_WIDTH, flexShrink: 0, children: /* @__PURE__ */ jsx7(Text8, { color: TAG_COLORS[item.tag], bold: true, children: `[${item.tag}]` }) }),
1159
- /* @__PURE__ */ jsx7(Box8, { flexDirection: "column", children: /* @__PURE__ */ jsxs7(Text8, { children: [
1160
- /* @__PURE__ */ jsx7(Text8, { color: COLORS.strong, bold: true, children: item.title }),
1161
- /* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: ` \u2014 ${item.description}` })
1019
+ /* @__PURE__ */ jsx7(Text7, { color: COLORS.strong, bold: true, children: "What algolia wizard accesses" }),
1020
+ /* @__PURE__ */ jsx7(Text7, { color: COLORS.muted, children: accessIntro }),
1021
+ /* @__PURE__ */ jsx7(Box7, { flexDirection: "column", children: accessItems.map((item) => /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", marginTop: 1, children: [
1022
+ /* @__PURE__ */ jsx7(Text7, { color: COLORS.border, children: "\u2500".repeat(dividerWidth) }),
1023
+ /* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", gap: 1, marginTop: 1, children: [
1024
+ /* @__PURE__ */ jsx7(Box7, { width: TAG_COLUMN_WIDTH, flexShrink: 0, children: /* @__PURE__ */ jsx7(Text7, { color: TAG_COLORS[item.tag], bold: true, children: `[${item.tag}]` }) }),
1025
+ /* @__PURE__ */ jsx7(Box7, { flexDirection: "column", children: /* @__PURE__ */ jsxs6(Text7, { children: [
1026
+ /* @__PURE__ */ jsx7(Text7, { color: COLORS.strong, bold: true, children: item.title }),
1027
+ /* @__PURE__ */ jsx7(Text7, { color: COLORS.muted, children: ` \u2014 ${item.description}` })
1162
1028
  ] }) })
1163
1029
  ] })
1164
1030
  ] }, item.tag)) }),
1165
- /* @__PURE__ */ jsxs7(Box8, { marginTop: 1, flexDirection: "column", children: [
1166
- /* @__PURE__ */ jsx7(Text8, { color: COLORS.danger, children: `\u256D${"\u2500".repeat(Math.max(0, dividerWidth - 2))}\u256E` }),
1031
+ /* @__PURE__ */ jsxs6(Box7, { marginTop: 1, flexDirection: "column", children: [
1032
+ /* @__PURE__ */ jsx7(Text7, { color: COLORS.danger, children: `\u256D${"\u2500".repeat(Math.max(0, dividerWidth - 2))}\u256E` }),
1167
1033
  /* @__PURE__ */ jsx7(NeverLine, { width: dividerWidth }),
1168
1034
  /* @__PURE__ */ jsx7(
1169
1035
  NeverLine,
@@ -1172,7 +1038,7 @@ function LearnMore() {
1172
1038
  segments: [{ text: "I NEVER", color: COLORS.danger, bold: true }]
1173
1039
  }
1174
1040
  ),
1175
- neverItems.map((item) => /* @__PURE__ */ jsxs7(Fragment2, { children: [
1041
+ neverItems.map((item) => /* @__PURE__ */ jsxs6(Fragment2, { children: [
1176
1042
  /* @__PURE__ */ jsx7(NeverLine, { width: dividerWidth }),
1177
1043
  /* @__PURE__ */ jsx7(
1178
1044
  NeverLine,
@@ -1187,23 +1053,23 @@ function LearnMore() {
1187
1053
  )
1188
1054
  ] }, item)),
1189
1055
  /* @__PURE__ */ jsx7(NeverLine, { width: dividerWidth }),
1190
- /* @__PURE__ */ jsx7(Text8, { color: COLORS.danger, children: `\u2570${"\u2500".repeat(Math.max(0, dividerWidth - 2))}\u256F` })
1056
+ /* @__PURE__ */ jsx7(Text7, { color: COLORS.danger, children: `\u2570${"\u2500".repeat(Math.max(0, dividerWidth - 2))}\u256F` })
1191
1057
  ] }),
1192
- /* @__PURE__ */ jsx7(Box8, { marginTop: 1, flexDirection: "column", children: policyLinks.map((link) => /* @__PURE__ */ jsxs7(Box8, { flexDirection: "row", gap: 1, children: [
1193
- /* @__PURE__ */ jsx7(Text8, { color: COLORS.strong, bold: true, children: `${link.label}:` }),
1194
- /* @__PURE__ */ jsx7(Text8, { color: COLORS.accent, children: link.url })
1058
+ /* @__PURE__ */ jsx7(Box7, { marginTop: 1, flexDirection: "column", children: policyLinks.map((link) => /* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", gap: 1, children: [
1059
+ /* @__PURE__ */ jsx7(Text7, { color: COLORS.strong, bold: true, children: `${link.label}:` }),
1060
+ /* @__PURE__ */ jsx7(Text7, { color: COLORS.accent, children: link.url })
1195
1061
  ] }, link.label)) }),
1196
- /* @__PURE__ */ jsxs7(Box8, { marginTop: 1, flexDirection: "row", gap: 3, children: [
1197
- /* @__PURE__ */ jsxs7(Box8, { flexDirection: "row", gap: 1, children: [
1198
- /* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: "[" }),
1199
- /* @__PURE__ */ jsx7(Text8, { color: COLORS.primary, children: "esc" }),
1200
- /* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: "] back" })
1062
+ /* @__PURE__ */ jsxs6(Box7, { marginTop: 1, flexDirection: "row", gap: 3, children: [
1063
+ /* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", gap: 1, children: [
1064
+ /* @__PURE__ */ jsx7(Text7, { color: COLORS.muted, children: "[" }),
1065
+ /* @__PURE__ */ jsx7(Text7, { color: COLORS.primary, children: "esc" }),
1066
+ /* @__PURE__ */ jsx7(Text7, { color: COLORS.muted, children: "] back" })
1201
1067
  ] }),
1202
- /* @__PURE__ */ jsxs7(Box8, { flexDirection: "row", gap: 1, children: [
1203
- /* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: "[" }),
1204
- /* @__PURE__ */ jsx7(Text8, { color: COLORS.primary, children: "enter" }),
1205
- /* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: "]" }),
1206
- /* @__PURE__ */ jsx7(Text8, { color: COLORS.success, bold: true, children: "start wizard" })
1068
+ /* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", gap: 1, children: [
1069
+ /* @__PURE__ */ jsx7(Text7, { color: COLORS.muted, children: "[" }),
1070
+ /* @__PURE__ */ jsx7(Text7, { color: COLORS.primary, children: "enter" }),
1071
+ /* @__PURE__ */ jsx7(Text7, { color: COLORS.muted, children: "]" }),
1072
+ /* @__PURE__ */ jsx7(Text7, { color: COLORS.success, bold: true, children: "start wizard" })
1207
1073
  ] })
1208
1074
  ] })
1209
1075
  ]
@@ -1212,10 +1078,10 @@ function LearnMore() {
1212
1078
  }
1213
1079
 
1214
1080
  // src/ui/Sidebar.tsx
1215
- import { Box as Box11, Text as Text11 } from "ink";
1081
+ import { Box as Box10, Text as Text10 } from "ink";
1216
1082
 
1217
1083
  // src/ui/Steps.tsx
1218
- import { Box as Box9, Text as Text9 } from "ink";
1084
+ import { Box as Box8, Text as Text8 } from "ink";
1219
1085
  import Spinner from "ink-spinner";
1220
1086
 
1221
1087
  // src/core/persistence.ts
@@ -1244,11 +1110,11 @@ async function clearWorkflowState(workflowId) {
1244
1110
  }
1245
1111
 
1246
1112
  // src/ui/Steps.tsx
1247
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1113
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1248
1114
  function Steps() {
1249
1115
  const { steps } = useWizard();
1250
1116
  const visibleSteps = steps.filter(isStepVisible);
1251
- return /* @__PURE__ */ jsx8(Box9, { flexDirection: "column", gap: 1, children: visibleSteps.map((s) => /* @__PURE__ */ jsx8(Box9, { flexDirection: "column", children: /* @__PURE__ */ jsxs8(Text9, { color: COLORS.status[s.status], children: [
1117
+ return /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", gap: 1, children: visibleSteps.map((s) => /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", children: /* @__PURE__ */ jsxs7(Text8, { color: COLORS.status[s.status], children: [
1252
1118
  s.status === "running" ? /* @__PURE__ */ jsx8(Spinner, { type: "dots" }) : MARKER[s.status],
1253
1119
  " ",
1254
1120
  s.title
@@ -1258,7 +1124,7 @@ function CurrentStep() {
1258
1124
  const { steps } = useWizard();
1259
1125
  const currentStep = steps.filter(isStepVisible).find((s) => s.status === "running");
1260
1126
  if (!currentStep) return null;
1261
- return /* @__PURE__ */ jsxs8(Text9, { color: COLORS.status.running, children: [
1127
+ return /* @__PURE__ */ jsxs7(Text8, { color: COLORS.status.running, children: [
1262
1128
  /* @__PURE__ */ jsx8(Spinner, { type: "dots" }),
1263
1129
  " ",
1264
1130
  ` ${currentStep.title}`
@@ -1266,19 +1132,19 @@ function CurrentStep() {
1266
1132
  }
1267
1133
 
1268
1134
  // src/ui/Progress.tsx
1269
- import { Box as Box10, Text as Text10 } from "ink";
1270
- import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
1135
+ import { Box as Box9, Text as Text9 } from "ink";
1136
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1271
1137
  function Progress() {
1272
1138
  const { steps, currentStepIndex } = useWizard();
1273
1139
  const visibleSteps = steps.filter(isStepVisible);
1274
1140
  if (visibleSteps.length === 0) return null;
1275
1141
  const visibleCountThroughCurrent = steps.slice(0, currentStepIndex + 1).filter(isStepVisible).length;
1276
1142
  const activeStepNumber = Math.max(1, visibleCountThroughCurrent);
1277
- return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "row", gap: 1, children: [
1278
- /* @__PURE__ */ jsx9(Text10, { color: COLORS.muted, children: "STEP" }),
1279
- /* @__PURE__ */ jsx9(Text10, { bold: true, children: activeStepNumber }),
1280
- /* @__PURE__ */ jsx9(Text10, { bold: true, children: "/" }),
1281
- /* @__PURE__ */ jsx9(Text10, { bold: true, children: visibleSteps.length })
1143
+ return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "row", gap: 1, children: [
1144
+ /* @__PURE__ */ jsx9(Text9, { color: COLORS.muted, children: "STEP" }),
1145
+ /* @__PURE__ */ jsx9(Text9, { bold: true, children: activeStepNumber }),
1146
+ /* @__PURE__ */ jsx9(Text9, { bold: true, children: "/" }),
1147
+ /* @__PURE__ */ jsx9(Text9, { bold: true, children: visibleSteps.length })
1282
1148
  ] });
1283
1149
  }
1284
1150
 
@@ -1289,10 +1155,10 @@ var sidebarCommands = [
1289
1155
  ];
1290
1156
 
1291
1157
  // src/ui/Sidebar.tsx
1292
- import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
1158
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1293
1159
  function Sidebar() {
1294
- return /* @__PURE__ */ jsxs10(
1295
- Box11,
1160
+ return /* @__PURE__ */ jsxs9(
1161
+ Box10,
1296
1162
  {
1297
1163
  backgroundColor: "#14171E",
1298
1164
  width: 30,
@@ -1301,16 +1167,16 @@ function Sidebar() {
1301
1167
  flexDirection: "column",
1302
1168
  justifyContent: "space-between",
1303
1169
  children: [
1304
- /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", gap: 1, children: [
1305
- /* @__PURE__ */ jsx10(Text11, { color: COLORS.muted, children: "PROGRESS" }),
1170
+ /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", gap: 1, children: [
1171
+ /* @__PURE__ */ jsx10(Text10, { color: COLORS.muted, children: "PROGRESS" }),
1306
1172
  /* @__PURE__ */ jsx10(Steps, {})
1307
1173
  ] }),
1308
- /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", gap: 1, children: [
1174
+ /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", gap: 1, children: [
1309
1175
  /* @__PURE__ */ jsx10(Progress, {}),
1310
- /* @__PURE__ */ jsx10(Box11, { flexDirection: "column", children: sidebarCommands.map((c) => {
1311
- return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "row", gap: 1, children: [
1312
- /* @__PURE__ */ jsx10(Text11, { color: COLORS.primary, children: `[${c.keyHint}]` }),
1313
- /* @__PURE__ */ jsx10(Text11, { color: COLORS.muted, children: c.description })
1176
+ /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", children: sidebarCommands.map((c) => {
1177
+ return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "row", gap: 1, children: [
1178
+ /* @__PURE__ */ jsx10(Text10, { color: COLORS.primary, children: `[${c.keyHint}]` }),
1179
+ /* @__PURE__ */ jsx10(Text10, { color: COLORS.muted, children: c.description })
1314
1180
  ] });
1315
1181
  }) })
1316
1182
  ] })
@@ -1320,12 +1186,12 @@ function Sidebar() {
1320
1186
  }
1321
1187
 
1322
1188
  // src/ui/Ribbon.tsx
1323
- import { Box as Box12, Text as Text12 } from "ink";
1324
- import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
1189
+ import { Box as Box11, Text as Text11 } from "ink";
1190
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
1325
1191
  function Ribbon() {
1326
1192
  const firstCommand = sidebarCommands[0];
1327
- return /* @__PURE__ */ jsxs11(
1328
- Box12,
1193
+ return /* @__PURE__ */ jsxs10(
1194
+ Box11,
1329
1195
  {
1330
1196
  backgroundColor: "#14171E",
1331
1197
  flexDirection: "row",
@@ -1335,9 +1201,9 @@ function Ribbon() {
1335
1201
  children: [
1336
1202
  /* @__PURE__ */ jsx11(Progress, {}),
1337
1203
  /* @__PURE__ */ jsx11(CurrentStep, {}),
1338
- /* @__PURE__ */ jsxs11(Box12, { flexDirection: "row", gap: 1, children: [
1339
- /* @__PURE__ */ jsx11(Text12, { color: COLORS.primary, children: `[${firstCommand.keyHint}]` }),
1340
- /* @__PURE__ */ jsx11(Text12, { color: COLORS.muted, children: firstCommand.description })
1204
+ /* @__PURE__ */ jsxs10(Box11, { flexDirection: "row", gap: 1, children: [
1205
+ /* @__PURE__ */ jsx11(Text11, { color: COLORS.primary, children: `[${firstCommand.keyHint}]` }),
1206
+ /* @__PURE__ */ jsx11(Text11, { color: COLORS.muted, children: firstCommand.description })
1341
1207
  ] })
1342
1208
  ]
1343
1209
  }
@@ -1349,8 +1215,8 @@ import { useState as useState6 } from "react";
1349
1215
 
1350
1216
  // src/ui/Logs.tsx
1351
1217
  import { useLayoutEffect as useLayoutEffect2, useRef as useRef3, useState as useState5 } from "react";
1352
- import { Box as Box13, Text as Text13, measureElement as measureElement3, useInput as useInput5, useWindowSize as useWindowSize7 } from "ink";
1353
- import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
1218
+ import { Box as Box12, Text as Text12, measureElement as measureElement3, useInput as useInput5, useWindowSize as useWindowSize6 } from "ink";
1219
+ import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
1354
1220
  var KIND_COLOR = {
1355
1221
  tool: COLORS.primary,
1356
1222
  prompt: COLORS.badge
@@ -1380,7 +1246,7 @@ function formatTimestamp(ms) {
1380
1246
  }
1381
1247
  function Logs() {
1382
1248
  const logs = useWizard((s) => s.logs);
1383
- const { rows, columns } = useWindowSize7();
1249
+ const { rows, columns } = useWindowSize6();
1384
1250
  const viewportRef = useRef3(null);
1385
1251
  const [viewportHeight, setViewportHeight] = useState5(0);
1386
1252
  const [viewportWidth, setViewportWidth] = useState5(0);
@@ -1417,10 +1283,10 @@ function Logs() {
1417
1283
  const visible = logs.slice(scrollOffset, scrollOffset + capacity);
1418
1284
  const hiddenAbove = scrollOffset;
1419
1285
  const hiddenBelow = logs.length - scrollOffset - visible.length;
1420
- return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", paddingX: 4, paddingY: 2, flexGrow: 1, children: [
1421
- logs.length === 0 && /* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, children: "No logs yet." }),
1422
- /* @__PURE__ */ jsxs12(Box13, { ref: viewportRef, flexDirection: "column", flexGrow: 1, children: [
1423
- hiddenAbove > 0 && /* @__PURE__ */ jsxs12(Text13, { color: COLORS.dim, children: [
1286
+ return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", paddingX: 4, paddingY: 2, flexGrow: 1, children: [
1287
+ logs.length === 0 && /* @__PURE__ */ jsx12(Text12, { color: COLORS.dim, children: "No logs yet." }),
1288
+ /* @__PURE__ */ jsxs11(Box12, { ref: viewportRef, flexDirection: "column", flexGrow: 1, children: [
1289
+ hiddenAbove > 0 && /* @__PURE__ */ jsxs11(Text12, { color: COLORS.dim, children: [
1424
1290
  "\u2191 ",
1425
1291
  hiddenAbove,
1426
1292
  " more"
@@ -1435,20 +1301,20 @@ function Logs() {
1435
1301
  const name = truncate2(entry.name, budget);
1436
1302
  budget -= name.length;
1437
1303
  const preview = rawPreview ? truncate2(rawPreview, budget) : "";
1438
- return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "row", gap: ROW_GAP, children: [
1439
- /* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, children: timestamp }),
1440
- /* @__PURE__ */ jsx12(Text13, { color: logNameColor(entry), wrap: "truncate", children: name }),
1441
- preview && /* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, wrap: "truncate", children: preview }),
1442
- durationText && /* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, children: durationText })
1304
+ return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "row", gap: ROW_GAP, children: [
1305
+ /* @__PURE__ */ jsx12(Text12, { color: COLORS.dim, children: timestamp }),
1306
+ /* @__PURE__ */ jsx12(Text12, { color: logNameColor(entry), wrap: "truncate", children: name }),
1307
+ preview && /* @__PURE__ */ jsx12(Text12, { color: COLORS.dim, wrap: "truncate", children: preview }),
1308
+ durationText && /* @__PURE__ */ jsx12(Text12, { color: COLORS.dim, children: durationText })
1443
1309
  ] }, entry.id);
1444
1310
  }),
1445
- hiddenBelow > 0 && /* @__PURE__ */ jsxs12(Text13, { color: COLORS.dim, children: [
1311
+ hiddenBelow > 0 && /* @__PURE__ */ jsxs11(Text12, { color: COLORS.dim, children: [
1446
1312
  "\u2193 ",
1447
1313
  hiddenBelow,
1448
1314
  " more"
1449
1315
  ] })
1450
1316
  ] }),
1451
- /* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, children: "\u2191/\u2193 scroll" })
1317
+ /* @__PURE__ */ jsx12(Text12, { color: COLORS.dim, children: "\u2191/\u2193 scroll" })
1452
1318
  ] });
1453
1319
  }
1454
1320
 
@@ -1640,11 +1506,11 @@ function track(event, payload) {
1640
1506
  }
1641
1507
 
1642
1508
  // src/ui/App.tsx
1643
- import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
1509
+ import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
1644
1510
  function App() {
1645
1511
  const { phase, error, homeScreen, currentStepIndex, steps, inputReq } = useWizard();
1646
1512
  const { exit } = useApp();
1647
- const { columns, rows } = useWindowSize8();
1513
+ const { columns, rows } = useWindowSize7();
1648
1514
  const [showLogs, setShowLogs] = useState6(false);
1649
1515
  const finished = phase === "done" || phase === "error";
1650
1516
  const currentStep = steps[currentStepIndex];
@@ -1657,7 +1523,7 @@ function App() {
1657
1523
  { isActive: finished }
1658
1524
  );
1659
1525
  useInput6((_input, key) => {
1660
- if (phase === "idle" || phase === "authenticating") return;
1526
+ if (phase === "idle" || phase === "preflight") return;
1661
1527
  if (key.tab) {
1662
1528
  setShowLogs(!showLogs);
1663
1529
  track("AI Wizard Interaction", {
@@ -1667,7 +1533,7 @@ function App() {
1667
1533
  });
1668
1534
  }
1669
1535
  });
1670
- const escOwnedElsewhere = phase === "idle" || phase === "authenticating" || phase === "awaitingInput" && inputReq?.promptType === "enterToContinue";
1536
+ const escOwnedElsewhere = phase === "idle" || phase === "awaitingInput" && inputReq?.promptType === "enterToContinue";
1671
1537
  useInput6((_input, key) => {
1672
1538
  if (escOwnedElsewhere) return;
1673
1539
  if (key.escape) {
@@ -1680,70 +1546,56 @@ function App() {
1680
1546
  exit();
1681
1547
  }
1682
1548
  });
1683
- const mainWindowVisible = phase === "authenticating" || phase === "preflight" || phase === "running" || phase === "awaitingInput" || phase === "error" || phase === "done";
1549
+ const mainWindowVisible = phase === "running" || phase === "awaitingInput" || phase === "error" || phase === "done";
1684
1550
  const flexDirection = columns > 90 ? "row" : "column";
1685
1551
  const showSidebar = flexDirection === "row";
1686
- return (
1687
- /* Exactly the viewport, clipped — never `minHeight`, which lets the frame
1688
- grow past the terminal. Ink then abandons diffing to clear and repaint
1689
- the whole screen, and the scrolling that frame causes throws off its
1690
- cursor arithmetic: flicker and leftover rows, worst when a burst of CLI
1691
- output is swapped out. Clipping drops the bottom of an over-tall frame;
1692
- the per-panel row budgets are what keep it from coming to that. */
1693
- /* @__PURE__ */ jsxs13(
1694
- Box14,
1695
- {
1696
- backgroundColor: COLORS.bg.main,
1697
- flexDirection: "row",
1698
- width: columns,
1699
- height: rows,
1700
- overflow: "hidden",
1701
- children: [
1702
- mainWindowVisible && /* @__PURE__ */ jsxs13(
1703
- Box14,
1704
- {
1705
- flexDirection,
1706
- width: "100%",
1707
- justifyContent: "space-between",
1708
- children: [
1709
- showLogs ? /* @__PURE__ */ jsx13(Logs, {}) : (
1710
- /* Fill the space the sidebar/ribbon leaves — width beside the
1711
- sidebar, height above the ribbon. The height matters even
1712
- stacked: it is what the prompt's scrolling list measures itself
1713
- against (see SelectPrompt). */
1714
- /* @__PURE__ */ jsxs13(
1715
- Box14,
1716
- {
1717
- flexDirection: "column",
1718
- paddingX: 4,
1719
- paddingY: 2,
1720
- width: showSidebar ? 70 : "100%",
1721
- flexGrow: 1,
1722
- children: [
1723
- phase === "authenticating" && /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", marginBottom: 1, children: [
1724
- /* @__PURE__ */ jsx13(Text14, { color: COLORS.strong, bold: true, children: "Signing in to Algolia" }),
1725
- /* @__PURE__ */ jsx13(Text14, { color: COLORS.muted, children: "A browser window will open \u2014 complete sign-in there." })
1726
- ] }),
1727
- /* @__PURE__ */ jsx13(CliOutput, {}),
1728
- /* @__PURE__ */ jsx13(Notices, {}),
1729
- /* @__PURE__ */ jsx13(PromptInput, {}),
1730
- phase === "running" && showSidebar && /* @__PURE__ */ jsx13(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx13(CurrentStep, {}) }),
1731
- phase === "error" && error && /* @__PURE__ */ jsx13(Box14, { marginTop: 1, children: /* @__PURE__ */ jsxs13(Text14, { color: COLORS.status.error, children: [
1732
- "\u2716 ",
1733
- error
1734
- ] }) })
1735
- ]
1736
- }
1737
- )
1738
- ),
1739
- showSidebar ? /* @__PURE__ */ jsx13(Sidebar, {}) : /* @__PURE__ */ jsx13(Ribbon, {})
1740
- ]
1741
- }
1742
- ),
1743
- phase === "idle" && (homeScreen === "learnMore" ? /* @__PURE__ */ jsx13(LearnMore, {}) : /* @__PURE__ */ jsx13(Welcome, {}))
1744
- ]
1745
- }
1746
- )
1552
+ return /* @__PURE__ */ jsxs12(
1553
+ Box13,
1554
+ {
1555
+ backgroundColor: COLORS.bg.main,
1556
+ flexDirection: "row",
1557
+ width: columns,
1558
+ minHeight: rows,
1559
+ children: [
1560
+ mainWindowVisible && /* @__PURE__ */ jsxs12(
1561
+ Box13,
1562
+ {
1563
+ flexDirection,
1564
+ width: "100%",
1565
+ justifyContent: "space-between",
1566
+ children: [
1567
+ showLogs ? /* @__PURE__ */ jsx13(Logs, {}) : (
1568
+ /* Fill the space the sidebar/ribbon leaves — width beside the
1569
+ sidebar, height above the ribbon. The height matters even
1570
+ stacked: it is what the prompt's scrolling list measures itself
1571
+ against (see SelectPrompt). */
1572
+ /* @__PURE__ */ jsxs12(
1573
+ Box13,
1574
+ {
1575
+ flexDirection: "column",
1576
+ paddingX: 4,
1577
+ paddingY: 2,
1578
+ width: showSidebar ? 70 : "100%",
1579
+ flexGrow: 1,
1580
+ children: [
1581
+ /* @__PURE__ */ jsx13(Notices, {}),
1582
+ /* @__PURE__ */ jsx13(PromptInput, {}),
1583
+ phase === "running" && showSidebar && /* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx13(CurrentStep, {}) }),
1584
+ phase === "error" && error && /* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsxs12(Text13, { color: COLORS.status.error, children: [
1585
+ "\u2716 ",
1586
+ error
1587
+ ] }) })
1588
+ ]
1589
+ }
1590
+ )
1591
+ ),
1592
+ showSidebar ? /* @__PURE__ */ jsx13(Sidebar, {}) : /* @__PURE__ */ jsx13(Ribbon, {})
1593
+ ]
1594
+ }
1595
+ ),
1596
+ (phase === "idle" || phase === "preflight") && (homeScreen === "learnMore" ? /* @__PURE__ */ jsx13(LearnMore, {}) : /* @__PURE__ */ jsx13(Welcome, {}))
1597
+ ]
1598
+ }
1747
1599
  );
1748
1600
  }
1749
1601
 
@@ -1979,138 +1831,61 @@ async function runWorkflow(workflow, appId) {
1979
1831
  }
1980
1832
  }
1981
1833
 
1982
- // src/lib/algoliaApp.ts
1983
- import { z as z4 } from "zod";
1984
- var applicationSchema = z4.object({
1985
- id: z4.string().min(1),
1986
- name: z4.string().default(""),
1987
- plan: z4.string().optional()
1988
- });
1989
- var listSchema = z4.array(
1990
- z4.object({
1991
- id: z4.string().min(1),
1992
- name: z4.string().default(""),
1993
- plan_label: z4.string().optional()
1994
- }).transform(({ id, name, plan_label }) => ({ id, name, plan: plan_label }))
1995
- );
1996
- async function currentApplication() {
1997
- let raw;
1834
+ // src/lib/algoliaProfile.ts
1835
+ import { readFile as readFile3 } from "node:fs/promises";
1836
+ import { createRequire as createRequire2 } from "node:module";
1837
+ import { homedir as homedir2 } from "node:os";
1838
+ import { join as join6 } from "node:path";
1839
+ import { parse as parseToml } from "toml";
1840
+ var require3 = createRequire2(import.meta.url);
1841
+ function configPath() {
1842
+ const base = process.env.XDG_CONFIG_HOME || join6(homedir2(), ".config");
1843
+ return join6(base, "algolia", "config.toml");
1844
+ }
1845
+ function profilesFromConfig(tomlText) {
1846
+ let parsed;
1998
1847
  try {
1999
- raw = await runAlgoliaCli(["application", "current", "-o", "json"]);
1848
+ parsed = parseToml(tomlText);
2000
1849
  } catch {
2001
- return null;
2002
- }
2003
- const parsed = applicationSchema.safeParse(parseJson(raw));
2004
- return parsed.success ? parsed.data : null;
2005
- }
2006
- async function requireApplication() {
2007
- const app = await currentApplication();
2008
- if (!app) {
2009
- throw new Error(
2010
- "No Algolia application is selected. Run `npx @algolia/cli@latest application select` and restart the wizard."
2011
- );
2012
- }
2013
- return app;
2014
- }
2015
- async function listApplications() {
2016
- const raw = await runAlgoliaCli(["application", "list", "-o", "json"]);
2017
- const parsed = listSchema.safeParse(parseJson(raw));
2018
- if (!parsed.success) {
2019
- throw new Error("Could not read the list of Algolia applications.");
2020
- }
2021
- return parsed.data;
2022
- }
2023
- async function selectApplication(id) {
2024
- const raw = await runAlgoliaCli(
2025
- ["application", "select", "--non-interactive", "--app-id", id],
2026
- { onOutput: stderrSink }
2027
- );
2028
- const parsed = applicationSchema.safeParse(parseJson(raw));
2029
- if (!parsed.success) {
2030
- throw new Error(
2031
- `Selected application ${id}, but the Algolia CLI returned an unreadable result.`
2032
- );
1850
+ return [];
2033
1851
  }
2034
- return parsed.data;
2035
- }
2036
- function parseJson(text) {
1852
+ const profiles = Object.entries(parsed).filter(
1853
+ ([, t]) => typeof t.application_id === "string" && typeof t.api_key === "string"
1854
+ ).map(([name, t]) => ({
1855
+ name,
1856
+ appId: t.application_id,
1857
+ apiKey: t.api_key,
1858
+ isDefault: t.default === true
1859
+ }));
1860
+ profiles.sort((a, b) => Number(b.isDefault) - Number(a.isDefault));
1861
+ return profiles.map(({ name, appId, apiKey }) => ({ name, appId, apiKey }));
1862
+ }
1863
+ async function loadActiveProfile() {
1864
+ let profiles;
2037
1865
  try {
2038
- return JSON.parse(text);
1866
+ profiles = profilesFromConfig(await readFile3(configPath(), "utf8"));
2039
1867
  } catch {
2040
- return void 0;
1868
+ profiles = [];
2041
1869
  }
2042
- }
2043
-
2044
- // src/lib/algoliaAppPicker.ts
2045
- function secondaryFor(app) {
2046
- return app.plan ? { kind: "badge", value: app.plan } : void 0;
2047
- }
2048
- function labelFor(app) {
2049
- return app.name.trim() ? `${app.name} \u2014 ${app.id}` : app.id;
2050
- }
2051
- function selectAndReport(app) {
2052
- useWizard.getState().pushCliOutput(
2053
- "stdout",
2054
- `Selecting ${labelFor(app)} \u2014 provisioning its API key\u2026`
2055
- );
2056
- return selectApplication(app.id);
2057
- }
2058
- async function promptForApplication() {
2059
- const store = useWizard.getState();
2060
- const apps = await listApplications();
2061
- if (apps.length === 0) {
1870
+ const profile = profiles[0];
1871
+ if (!profile) {
2062
1872
  throw new Error(
2063
- "This Algolia account has no applications. Create one in the Algolia dashboard, or with `npx @algolia/cli@latest application create`, then restart the wizard."
1873
+ "No Algolia profile is configured. Run `npx @algolia/cli auth login` to authenticate."
2064
1874
  );
2065
1875
  }
2066
- if (apps.length === 1) {
2067
- const only = apps[0];
2068
- logger.info(
2069
- { app: only.id },
2070
- "single application on the account; selecting it"
2071
- );
2072
- return selectAndReport(only);
2073
- }
2074
- const messages = ["Which Algolia application should the wizard work in?"];
2075
- for (; ; ) {
2076
- const choice = await store.requestUserInput({
2077
- prompt: "Select an application",
2078
- promptType: "multipleChoice",
2079
- options: apps.map(labelFor),
2080
- secondary: apps.map(secondaryFor),
2081
- messages
2082
- });
2083
- const chosen = apps.find((app) => labelFor(app) === choice);
2084
- if (!chosen) {
2085
- throw new Error("Application picker received an unexpected selection");
2086
- }
2087
- try {
2088
- return await selectAndReport(chosen);
2089
- } catch (err) {
2090
- logger.warn(
2091
- { app: chosen.id, err: err.message },
2092
- "application select failed; re-prompting"
2093
- );
2094
- messages.push(
2095
- `Could not select \u201C${labelFor(chosen)}\u201D. It may have been removed \u2014 pick another.`
2096
- );
2097
- }
2098
- }
2099
- }
2100
- async function ensureApplication() {
2101
- return await currentApplication() ?? await promptForApplication();
1876
+ return profile;
2102
1877
  }
2103
1878
 
2104
1879
  // src/workflows/default.ts
2105
- import { z as z27 } from "zod";
1880
+ import { z as z25 } from "zod";
2106
1881
 
2107
1882
  // src/actions/listIndices.ts
2108
- import { z as z5 } from "zod";
2109
- var indicesListSchema = z5.object({
2110
- items: z5.array(
2111
- z5.object({
2112
- name: z5.string(),
2113
- entries: z5.number().default(0)
1883
+ import { z as z3 } from "zod";
1884
+ var indicesListSchema = z3.object({
1885
+ items: z3.array(
1886
+ z3.object({
1887
+ name: z3.string(),
1888
+ entries: z3.number().default(0)
2114
1889
  })
2115
1890
  )
2116
1891
  });
@@ -2181,12 +1956,12 @@ import "zod";
2181
1956
 
2182
1957
  // src/lib/tools/listFiles.ts
2183
1958
  import { tool } from "ai";
2184
- import z6 from "zod";
1959
+ import z4 from "zod";
2185
1960
  import { readdir } from "node:fs/promises";
2186
1961
 
2187
1962
  // src/lib/tools/path.ts
2188
1963
  import { lstat } from "node:fs/promises";
2189
- import { resolve as resolve2, relative, isAbsolute, dirname as dirname3, join as join6, sep } from "node:path";
1964
+ import { resolve as resolve2, relative, isAbsolute, dirname as dirname3, join as join7, sep } from "node:path";
2190
1965
  function resolveInRoot(ctx, path) {
2191
1966
  const target = resolve2(ctx.cwd, path);
2192
1967
  const rel = relative(ctx.root, target);
@@ -2202,7 +1977,7 @@ async function hasSymlinkParent(ctx, target) {
2202
1977
  let current = ctx.root;
2203
1978
  const parts = relative(ctx.root, dirname3(target)).split(sep).filter(Boolean);
2204
1979
  for (const part of parts) {
2205
- current = join6(current, part);
1980
+ current = join7(current, part);
2206
1981
  try {
2207
1982
  if ((await lstat(current)).isSymbolicLink()) return true;
2208
1983
  } catch (err) {
@@ -2217,7 +1992,7 @@ async function hasSymlinkParent(ctx, target) {
2217
1992
  function listFilesTool(ctx) {
2218
1993
  return tool({
2219
1994
  description: "List files in the current working directory",
2220
- inputSchema: z6.object(),
1995
+ inputSchema: z4.object(),
2221
1996
  execute: async () => {
2222
1997
  logger.info("called listFiles tool");
2223
1998
  if (++ctx.counts.list > ctx.limits.list) {
@@ -2233,13 +2008,13 @@ function listFilesTool(ctx) {
2233
2008
 
2234
2009
  // src/lib/tools/changeDirectory.ts
2235
2010
  import { tool as tool2 } from "ai";
2236
- import z7 from "zod";
2011
+ import z5 from "zod";
2237
2012
  import { stat } from "node:fs/promises";
2238
2013
  function changeDirectoryTool(ctx) {
2239
2014
  return tool2({
2240
2015
  description: "Change the current working directory. Subsequent file operations resolve relative to it. Returns the new working directory.",
2241
- inputSchema: z7.object({
2242
- path: z7.string().describe("Directory to change into")
2016
+ inputSchema: z5.object({
2017
+ path: z5.string().describe("Directory to change into")
2243
2018
  }),
2244
2019
  execute: async ({ path }) => {
2245
2020
  logger.info({ path }, "called changeDirectory tool");
@@ -2261,13 +2036,13 @@ function changeDirectoryTool(ctx) {
2261
2036
 
2262
2037
  // src/lib/tools/reportStatus.ts
2263
2038
  import { tool as tool3 } from "ai";
2264
- import z8 from "zod";
2039
+ import z6 from "zod";
2265
2040
  function reportStatusTool(output) {
2266
2041
  return tool3({
2267
2042
  description: "Report the status of your execution. Return a reason in case of failure.",
2268
- inputSchema: z8.object({
2269
- status: z8.enum(["success", "fail"]),
2270
- reason: z8.string().optional(),
2043
+ inputSchema: z6.object({
2044
+ status: z6.enum(["success", "fail"]),
2045
+ reason: z6.string().optional(),
2271
2046
  output
2272
2047
  }),
2273
2048
  execute: async ({ status, reason, output: output2 }) => {
@@ -2279,8 +2054,8 @@ function reportStatusTool(output) {
2279
2054
 
2280
2055
  // src/lib/tools/readFile.ts
2281
2056
  import { tool as tool4 } from "ai";
2282
- import z9 from "zod";
2283
- import { readFile as readFile3 } from "node:fs/promises";
2057
+ import z7 from "zod";
2058
+ import { readFile as readFile4 } from "node:fs/promises";
2284
2059
 
2285
2060
  // src/lib/tools/env.ts
2286
2061
  import { basename } from "node:path";
@@ -2307,8 +2082,8 @@ function redactEnvValues(content) {
2307
2082
  function readFileTool(ctx) {
2308
2083
  return tool4({
2309
2084
  description: "Read the contents of a file at the given path",
2310
- inputSchema: z9.object({
2311
- filePath: z9.string().describe("Path to the file to read")
2085
+ inputSchema: z7.object({
2086
+ filePath: z7.string().describe("Path to the file to read")
2312
2087
  }),
2313
2088
  execute: async ({ filePath }) => {
2314
2089
  if (++ctx.counts.read > ctx.limits.read) {
@@ -2318,7 +2093,7 @@ function readFileTool(ctx) {
2318
2093
  const resolved = resolveInRoot(ctx, filePath);
2319
2094
  if (!resolved.ok) return resolved.error;
2320
2095
  try {
2321
- const content = await readFile3(resolved.target, "utf8");
2096
+ const content = await readFile4(resolved.target, "utf8");
2322
2097
  return isEnvFile(resolved.target) ? redactEnvValues(content) : content;
2323
2098
  } catch (err) {
2324
2099
  return `Error reading ${filePath}: ${err.message}`;
@@ -2329,15 +2104,15 @@ function readFileTool(ctx) {
2329
2104
 
2330
2105
  // src/lib/tools/writeFile.ts
2331
2106
  import { tool as tool5 } from "ai";
2332
- import z10 from "zod";
2107
+ import z8 from "zod";
2333
2108
  import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
2334
2109
  import { dirname as dirname4 } from "node:path";
2335
2110
  function writeFileTool(ctx) {
2336
2111
  return tool5({
2337
2112
  description: "Write content to a file at the given path, overwriting it. To set Algolia credentials in an env file, use writeCredentials instead of this tool.",
2338
- inputSchema: z10.object({
2339
- filePath: z10.string().describe("Path to the file to write"),
2340
- content: z10.string().describe("Content to write to the file")
2113
+ inputSchema: z8.object({
2114
+ filePath: z8.string().describe("Path to the file to write"),
2115
+ content: z8.string().describe("Content to write to the file")
2341
2116
  }),
2342
2117
  execute: async ({ filePath, content }) => {
2343
2118
  logger.info({ filePath }, "called writeFile tool");
@@ -2362,95 +2137,9 @@ function writeFileTool(ctx) {
2362
2137
 
2363
2138
  // src/lib/tools/writeAlgoliaCredentials.ts
2364
2139
  import { tool as tool6 } from "ai";
2365
- import z12 from "zod";
2366
- import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "node:fs/promises";
2140
+ import z9 from "zod";
2141
+ import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile4 } from "node:fs/promises";
2367
2142
  import { dirname as dirname5 } from "node:path";
2368
-
2369
- // src/lib/algoliaApiKey.ts
2370
- import { z as z11 } from "zod";
2371
- var SAFE_ACLS = /* @__PURE__ */ new Set(["search", "browse", "listIndexes"]);
2372
- var WRITE_ACLS = [
2373
- "addObject",
2374
- "deleteObject",
2375
- "settings",
2376
- "editSettings",
2377
- "listIndexes"
2378
- ];
2379
- var WRITE_ACL_SET = new Set(WRITE_ACLS);
2380
- var apiKeySchema = z11.object({
2381
- value: z11.string().min(1),
2382
- acl: z11.array(z11.string()).default([]),
2383
- indexes: z11.array(z11.string()).default([])
2384
- });
2385
- var apiKeyListSchema = z11.object({
2386
- items: z11.array(apiKeySchema).optional(),
2387
- keys: z11.array(apiKeySchema).optional()
2388
- }).transform((o) => o.items ?? o.keys ?? []);
2389
- var createdKeySchema = z11.object({
2390
- key: z11.string().min(1).optional(),
2391
- value: z11.string().min(1).optional()
2392
- });
2393
- function canReuse(key, index) {
2394
- return key.acl.includes("search") && key.acl.every((acl) => SAFE_ACLS.has(acl)) && (key.indexes.length === 0 || key.indexes.includes("*") || key.indexes.includes(index));
2395
- }
2396
- async function createSearchKey(index) {
2397
- const stdout = await runAlgoliaCli([
2398
- "apikeys",
2399
- "create",
2400
- "--indices",
2401
- index,
2402
- "--acl",
2403
- "search,browse",
2404
- "--description",
2405
- `wizard search-only key for ${index}`,
2406
- "-o",
2407
- "json"
2408
- ]);
2409
- const { key, value } = createdKeySchema.parse(JSON.parse(stdout));
2410
- const created = key ?? value;
2411
- if (!created) throw new Error("apikeys create returned no key value");
2412
- return created;
2413
- }
2414
- function canReuseForWrites(key, index) {
2415
- return WRITE_ACLS.every((acl) => key.acl.includes(acl)) && key.acl.every((acl) => WRITE_ACL_SET.has(acl)) && key.indexes.includes(index);
2416
- }
2417
- async function resolveWriteKey(index) {
2418
- const stdout = await runAlgoliaCli(["apikeys", "list", "-o", "json"]);
2419
- const existing = apiKeyListSchema.parse(JSON.parse(stdout)).find((key2) => canReuseForWrites(key2, index))?.value;
2420
- if (existing) {
2421
- logger.info({ index }, "reusing existing write API key");
2422
- return existing;
2423
- }
2424
- logger.info({ index }, "no reusable write key found; creating one");
2425
- const created = await runAlgoliaCli([
2426
- "apikeys",
2427
- "create",
2428
- "--indices",
2429
- index,
2430
- "--acl",
2431
- WRITE_ACLS.join(","),
2432
- "--description",
2433
- `wizard write key for ${index}`,
2434
- "-o",
2435
- "json"
2436
- ]);
2437
- const { key, value } = createdKeySchema.parse(JSON.parse(created));
2438
- const writeKey = key ?? value;
2439
- if (!writeKey) throw new Error("apikeys create returned no key value");
2440
- return writeKey;
2441
- }
2442
- async function resolveSearchOnlyKey(index) {
2443
- const stdout = await runAlgoliaCli(["apikeys", "list", "-o", "json"]);
2444
- const existing = apiKeyListSchema.parse(JSON.parse(stdout)).find((key) => canReuse(key, index))?.value;
2445
- if (existing) {
2446
- logger.info({ index }, "reusing existing search-only API key");
2447
- return existing;
2448
- }
2449
- logger.info({ index }, "no reusable search-only key found; creating one");
2450
- return createSearchKey(index);
2451
- }
2452
-
2453
- // src/lib/tools/writeAlgoliaCredentials.ts
2454
2143
  var APP_ID_VAR = "ALGOLIA_APPLICATION_ID";
2455
2144
  var API_KEY_VAR = "ALGOLIA_WRITE_API_KEY";
2456
2145
  function appendEnv(content, entries) {
@@ -2464,9 +2153,9 @@ function hasEnv(content, name) {
2464
2153
  }
2465
2154
  function writeCredentialsTool(ctx) {
2466
2155
  return tool6({
2467
- description: `Write the active Algolia credentials (${APP_ID_VAR} and ${API_KEY_VAR}) into the given env file. The credentials come from the selected Algolia application, with a write key scoped to the target index; you only pass the path to the env file (e.g. ".env"). If the file already defines ${APP_ID_VAR} or ${API_KEY_VAR}, the write is skipped and existing values are left untouched.`,
2468
- inputSchema: z12.object({
2469
- filePath: z12.string().describe(
2156
+ description: `Write the active Algolia credentials (${APP_ID_VAR} and ${API_KEY_VAR}) into the given env file. The credentials are read from the local Algolia CLI profile; you only pass the path to the env file (e.g. ".env"). If the file already defines ${APP_ID_VAR} or ${API_KEY_VAR}, the write is skipped and existing values are left untouched.`,
2157
+ inputSchema: z9.object({
2158
+ filePath: z9.string().describe(
2470
2159
  'Path to the env file to write credentials into (e.g. ".env")'
2471
2160
  )
2472
2161
  }),
@@ -2474,17 +2163,11 @@ function writeCredentialsTool(ctx) {
2474
2163
  logger.info({ filePath }, "called writeCredentials tool");
2475
2164
  const resolved = resolveInRoot(ctx, filePath);
2476
2165
  if (resolved.ok === false) return resolved.error;
2477
- const targetIndex = useWizard.getState().targetIndex;
2478
- if (!targetIndex) {
2479
- return "Error: no target index is set for this run, so a scoped write key cannot be provisioned.";
2480
- }
2481
- let appId;
2482
- let writeKey;
2166
+ let profile;
2483
2167
  try {
2484
- appId = (await requireApplication()).id;
2485
- writeKey = await resolveWriteKey(targetIndex);
2486
- } catch (err) {
2487
- return `Error: could not resolve Algolia credentials (${err.message}). Ask the user to authenticate with the Algolia CLI first.`;
2168
+ profile = await loadActiveProfile();
2169
+ } catch {
2170
+ return "Error: no Algolia profile is configured, so credentials cannot be written. Ask the user to authenticate with the Algolia CLI first.";
2488
2171
  }
2489
2172
  try {
2490
2173
  if (await hasSymlinkParent(ctx, resolved.target)) {
@@ -2492,7 +2175,7 @@ function writeCredentialsTool(ctx) {
2492
2175
  }
2493
2176
  let existing = "";
2494
2177
  try {
2495
- existing = await readFile4(resolved.target, "utf8");
2178
+ existing = await readFile5(resolved.target, "utf8");
2496
2179
  } catch (err) {
2497
2180
  if (err.code !== "ENOENT") throw err;
2498
2181
  }
@@ -2503,8 +2186,8 @@ function writeCredentialsTool(ctx) {
2503
2186
  return `Skipped: ${filePath} already defines ${present.join(" and ")}. Leaving existing credentials untouched.`;
2504
2187
  }
2505
2188
  const envWithCredentials = appendEnv(existing, [
2506
- [APP_ID_VAR, appId],
2507
- [API_KEY_VAR, writeKey]
2189
+ [APP_ID_VAR, profile.appId],
2190
+ [API_KEY_VAR, profile.apiKey]
2508
2191
  ]);
2509
2192
  await mkdir4(dirname5(resolved.target), { recursive: true });
2510
2193
  await writeFile4(resolved.target, envWithCredentials, "utf8");
@@ -2518,16 +2201,16 @@ function writeCredentialsTool(ctx) {
2518
2201
 
2519
2202
  // src/lib/tools/searchFiles.ts
2520
2203
  import { tool as tool7 } from "ai";
2521
- import z13 from "zod";
2522
- import { readdir as readdir2, readFile as readFile5 } from "node:fs/promises";
2523
- import { join as join7 } from "node:path";
2204
+ import z10 from "zod";
2205
+ import { readdir as readdir2, readFile as readFile6 } from "node:fs/promises";
2206
+ import { join as join8 } from "node:path";
2524
2207
  var MAX_QUERY_LENGTH = 1e3;
2525
2208
  async function walkFiles(dir) {
2526
2209
  const skip = /* @__PURE__ */ new Set(["node_modules", ".git", "dist"]);
2527
2210
  const out = [];
2528
2211
  for (const e of await readdir2(dir, { withFileTypes: true })) {
2529
2212
  if (e.name.startsWith(".") || skip.has(e.name)) continue;
2530
- const full = join7(dir, e.name);
2213
+ const full = join8(dir, e.name);
2531
2214
  if (e.isDirectory()) out.push(...await walkFiles(full));
2532
2215
  else if (e.isFile()) out.push(full);
2533
2216
  }
@@ -2536,9 +2219,9 @@ async function walkFiles(dir) {
2536
2219
  function searchFilesTool(ctx) {
2537
2220
  return tool7({
2538
2221
  description: "Search file contents for a JavaScript regular expression (RegExp syntax, not grep/PCRE). Returns matching lines as file:line:text.",
2539
- inputSchema: z13.object({
2540
- query: z13.string().describe("JavaScript RegExp pattern to search for"),
2541
- path: z13.string().optional().describe("Directory to search in (default: cwd)")
2222
+ inputSchema: z10.object({
2223
+ query: z10.string().describe("JavaScript RegExp pattern to search for"),
2224
+ path: z10.string().optional().describe("Directory to search in (default: cwd)")
2542
2225
  }),
2543
2226
  execute: async ({ query, path = "." }) => {
2544
2227
  logger.info({ query, path }, "called searchFiles tool");
@@ -2560,7 +2243,7 @@ function searchFilesTool(ctx) {
2560
2243
  for (const file of await walkFiles(resolved.target)) {
2561
2244
  let content;
2562
2245
  try {
2563
- content = await readFile5(file, "utf8");
2246
+ content = await readFile6(file, "utf8");
2564
2247
  } catch {
2565
2248
  continue;
2566
2249
  }
@@ -2582,7 +2265,7 @@ function searchFilesTool(ctx) {
2582
2265
 
2583
2266
  // src/lib/tools/verifyImplementation.ts
2584
2267
  import { tool as tool8 } from "ai";
2585
- import z14 from "zod";
2268
+ import z11 from "zod";
2586
2269
 
2587
2270
  // src/lib/tools/utils/runCommand.ts
2588
2271
  import { spawn as spawn2 } from "node:child_process";
@@ -2604,9 +2287,9 @@ function runCommand(command, args, cwd) {
2604
2287
  }
2605
2288
 
2606
2289
  // src/lib/tools/utils/packageManager.ts
2607
- import { readFile as readFile6 } from "node:fs/promises";
2290
+ import { readFile as readFile7 } from "node:fs/promises";
2608
2291
  import { existsSync } from "node:fs";
2609
- import { join as join8 } from "node:path";
2292
+ import { join as join9 } from "node:path";
2610
2293
  var LOCKFILES = [
2611
2294
  ["pnpm-lock.yaml", "pnpm"],
2612
2295
  ["yarn.lock", "yarn"],
@@ -2615,13 +2298,13 @@ var LOCKFILES = [
2615
2298
  ["package-lock.json", "npm"]
2616
2299
  ];
2617
2300
  async function readPackageJson(cwd = process.cwd()) {
2618
- return JSON.parse(await readFile6(join8(cwd, "package.json"), "utf8"));
2301
+ return JSON.parse(await readFile7(join9(cwd, "package.json"), "utf8"));
2619
2302
  }
2620
2303
  function packageManagerFrom(pkg) {
2621
2304
  return pkg.packageManager?.split("@")[0] ?? "npm";
2622
2305
  }
2623
2306
  function packageManagerFromLockfile(cwd) {
2624
- return LOCKFILES.find(([file]) => existsSync(join8(cwd, file)))?.[1];
2307
+ return LOCKFILES.find(([file]) => existsSync(join9(cwd, file)))?.[1];
2625
2308
  }
2626
2309
  async function detectPackageManager(cwd) {
2627
2310
  try {
@@ -2662,7 +2345,7 @@ async function runRepoVerificationCheck() {
2662
2345
  function verifyImplementationTool() {
2663
2346
  return tool8({
2664
2347
  description: "Run the repo's mechanical verification check for generated implementation changes. Detects lint/typecheck/check from package.json and returns structured pass/fail evidence for the verifier to interpret.",
2665
- inputSchema: z14.object(),
2348
+ inputSchema: z11.object(),
2666
2349
  execute: async () => {
2667
2350
  logger.info("called verifyImplementation tool");
2668
2351
  return runRepoVerificationCheck();
@@ -2676,7 +2359,7 @@ import { createAnthropic } from "@ai-sdk/anthropic";
2676
2359
  import { nanoid as nanoid2 } from "nanoid";
2677
2360
  import { mkdir as mkdir5, writeFile as writeFile5 } from "node:fs/promises";
2678
2361
  import { dirname as dirname6 } from "node:path";
2679
- import z15 from "zod";
2362
+ import z12 from "zod";
2680
2363
  var DATA_DIR = ".algolia-wizard/data";
2681
2364
  var RECORD_MODEL = "claude-haiku-4-5";
2682
2365
  var MAX_RECORDS = 100;
@@ -2688,17 +2371,17 @@ var anthropic = createAnthropic({
2688
2371
  function generateRecordTool(ctx) {
2689
2372
  return tool9({
2690
2373
  description: "Generate realistic sample records for an entity and write them to a JSON file in the worktree. Provide the entity name and its attributes; this tool asks a model to invent varied, realistic values, each with a unique objectID, and returns the file path to read them from at runtime. Do not invent the record values or objectIDs yourself, and do not inline the returned records into the script \u2014 call this tool and read the file it writes.",
2691
- inputSchema: z15.object({
2692
- entityName: z15.string().describe("Name of the entity to generate records for."),
2693
- attributes: z15.array(z15.string()).describe("Attribute names each record must contain."),
2694
- count: z15.number().int().min(1).max(MAX_RECORDS).default(10).describe(`How many records to generate (max ${MAX_RECORDS}).`),
2695
- hint: z15.string().optional().describe("Optional context to steer realistic values.")
2374
+ inputSchema: z12.object({
2375
+ entityName: z12.string().describe("Name of the entity to generate records for."),
2376
+ attributes: z12.array(z12.string()).describe("Attribute names each record must contain."),
2377
+ count: z12.number().int().min(1).max(MAX_RECORDS).default(10).describe(`How many records to generate (max ${MAX_RECORDS}).`),
2378
+ hint: z12.string().optional().describe("Optional context to steer realistic values.")
2696
2379
  }),
2697
2380
  execute: async ({ entityName, attributes, count, hint }) => {
2698
2381
  logger.info({ entityName, count }, "called generateRecord tool");
2699
2382
  try {
2700
- const value = z15.union([z15.string(), z15.number(), z15.boolean(), z15.null()]);
2701
- const recordSchema = z15.object(
2383
+ const value = z12.union([z12.string(), z12.number(), z12.boolean(), z12.null()]);
2384
+ const recordSchema = z12.object(
2702
2385
  Object.fromEntries(attributes.map((attr) => [attr, value]))
2703
2386
  );
2704
2387
  const generateBatch = async (batchCount) => {
@@ -2708,8 +2391,8 @@ function generateRecordTool(ctx) {
2708
2391
  const { output } = await generateText({
2709
2392
  model: anthropic(RECORD_MODEL),
2710
2393
  output: Output.object({
2711
- schema: z15.object({
2712
- records: z15.array(recordSchema).length(batchCount)
2394
+ schema: z12.object({
2395
+ records: z12.array(recordSchema).length(batchCount)
2713
2396
  })
2714
2397
  }),
2715
2398
  prompt: [
@@ -2767,12 +2450,12 @@ function generateRecordTool(ctx) {
2767
2450
 
2768
2451
  // src/lib/tools/notifyUser.ts
2769
2452
  import { tool as tool10 } from "ai";
2770
- import z16 from "zod";
2453
+ import z13 from "zod";
2771
2454
  function notifyUserTool() {
2772
2455
  return tool10({
2773
2456
  description: `Give the user a brief, high-level update on what you are currently doing or about to do next. This is for the big picture (e.g. "Reading through your data models", "Writing the search UI") \u2014 not granular detail like individual tool calls, which are already logged separately. Call it when you start a new phase of work or your focus shifts, just not on every step, enough to keep the user engaged. Don't say things like "starting", just describe what you are doing. Don't mention tool calls themselves, just general direction of the work.`,
2774
- inputSchema: z16.object({
2775
- message: z16.string().describe(
2457
+ inputSchema: z13.object({
2458
+ message: z13.string().describe(
2776
2459
  "Short, plain-language description of what you are doing now."
2777
2460
  )
2778
2461
  }),
@@ -2952,10 +2635,10 @@ async function runAgent(req) {
2952
2635
  }
2953
2636
 
2954
2637
  // src/actions/detectLanguage.ts
2955
- import z19 from "zod";
2956
- var detectLanguageSchema = z19.object({
2957
- languages: z19.array(z19.object({ name: z19.string(), version: z19.string() })),
2958
- frameworks: z19.array(z19.object({ name: z19.string(), version: z19.string() }))
2638
+ import z16 from "zod";
2639
+ var detectLanguageSchema = z16.object({
2640
+ languages: z16.array(z16.object({ name: z16.string(), version: z16.string() })),
2641
+ frameworks: z16.array(z16.object({ name: z16.string(), version: z16.string() }))
2959
2642
  });
2960
2643
  var detectLanguage = () => runAgent({
2961
2644
  instructions: [
@@ -2973,31 +2656,31 @@ var detectLanguage = () => runAgent({
2973
2656
  });
2974
2657
 
2975
2658
  // src/actions/analyzeCodebase.ts
2976
- import z20 from "zod";
2659
+ import z17 from "zod";
2977
2660
  var READONLY_TOOLS = [
2978
2661
  "listFiles",
2979
2662
  "changeDirectory",
2980
2663
  "readFile",
2981
2664
  "searchFiles"
2982
2665
  ];
2983
- var ingestionAnalysisSchema = z20.object({
2984
- ingestionAnalysis: z20.array(
2985
- z20.object({
2986
- name: z20.string(),
2987
- paths: z20.array(z20.string()),
2666
+ var ingestionAnalysisSchema = z17.object({
2667
+ ingestionAnalysis: z17.array(
2668
+ z17.object({
2669
+ name: z17.string(),
2670
+ paths: z17.array(z17.string()),
2988
2671
  // indexable fields the agent found for this entity
2989
- attributes: z20.array(z20.string())
2672
+ attributes: z17.array(z17.string())
2990
2673
  })
2991
2674
  )
2992
2675
  });
2993
- var searchImplementationAnalysisSchema = z20.object({
2994
- searchImplementationAnalysis: z20.string()
2676
+ var searchImplementationAnalysisSchema = z17.object({
2677
+ searchImplementationAnalysis: z17.string()
2995
2678
  });
2996
- var verificationSchema = z20.object({
2997
- verification: z20.array(z20.string())
2679
+ var verificationSchema = z17.object({
2680
+ verification: z17.array(z17.string())
2998
2681
  });
2999
2682
  var confirmedEntitiesFieldSchema = ingestionAnalysisSchema.shape.ingestionAnalysis.optional();
3000
- var analyzeCodebaseSchema = z20.object({
2683
+ var analyzeCodebaseSchema = z17.object({
3001
2684
  ingestionAnalysis: ingestionAnalysisSchema.shape.ingestionAnalysis.optional(),
3002
2685
  searchImplementationAnalysis: searchImplementationAnalysisSchema.shape.searchImplementationAnalysis.optional(),
3003
2686
  verification: verificationSchema.shape.verification.optional(),
@@ -3059,7 +2742,7 @@ async function runAnalysis(mode, extraInstructions = []) {
3059
2742
  // package.json
3060
2743
  var package_default = {
3061
2744
  name: "@algolia/wizard",
3062
- version: "0.8.0-rc.58.43",
2745
+ version: "0.8.0-rc.58.44",
3063
2746
  description: "Magically implement Algolia functionality in your codebase",
3064
2747
  type: "module",
3065
2748
  engines: {
@@ -3107,6 +2790,7 @@ var package_default = {
3107
2790
  dependencies: {
3108
2791
  "@ai-sdk/anthropic": "^3.0.81",
3109
2792
  "@ai-sdk/openai-compatible": "^2.0.47",
2793
+ "@algolia/cli": "^5.11.0",
3110
2794
  "@hono/node-server": "^2.0.10",
3111
2795
  "@mishieck/ink-titled-box": "^0.4.2",
3112
2796
  "@segment/analytics-node": "^3.1.0",
@@ -3121,6 +2805,7 @@ var package_default = {
3121
2805
  nanoid: "^5.1.15",
3122
2806
  pino: "^10.3.1",
3123
2807
  react: "^19.2.7",
2808
+ toml: "^4.1.1",
3124
2809
  varlock: "^1.5.1",
3125
2810
  zod: "^4.4.3",
3126
2811
  zustand: "^5.0.14"
@@ -3178,8 +2863,8 @@ async function askList(ctx, prompt, { required = false } = {}) {
3178
2863
  }
3179
2864
 
3180
2865
  // src/actions/confirmLanguage.ts
3181
- import z22 from "zod";
3182
- var confirmLanguageSchema = z22.object({
2866
+ import z19 from "zod";
2867
+ var confirmLanguageSchema = z19.object({
3183
2868
  languages: detectLanguageSchema.shape.languages
3184
2869
  });
3185
2870
  async function confirmLanguage(ctx) {
@@ -3200,8 +2885,8 @@ async function confirmLanguage(ctx) {
3200
2885
  }
3201
2886
 
3202
2887
  // src/actions/confirmFramework.ts
3203
- import z23 from "zod";
3204
- var confirmFrameworkSchema = z23.object({
2888
+ import z20 from "zod";
2889
+ var confirmFrameworkSchema = z20.object({
3205
2890
  frameworks: detectLanguageSchema.shape.frameworks
3206
2891
  });
3207
2892
  var CURATED_FRAMEWORKS = [
@@ -3329,8 +3014,8 @@ async function promptUser(ctx, params) {
3329
3014
  }
3330
3015
 
3331
3016
  // src/actions/confirmEntities.ts
3332
- import z24 from "zod";
3333
- var confirmEntitiesSchema = z24.object({
3017
+ import z21 from "zod";
3018
+ var confirmEntitiesSchema = z21.object({
3334
3019
  // Final detection — the focused re-run may supersede project-scan's.
3335
3020
  ingestionAnalysis: ingestionAnalysisSchema.shape.ingestionAnalysis.optional(),
3336
3021
  confirmedEntities: confirmedEntitiesFieldSchema
@@ -3400,15 +3085,15 @@ async function confirmEntities(ctx) {
3400
3085
  }
3401
3086
 
3402
3087
  // src/actions/review.ts
3403
- import { z as z25 } from "zod";
3404
- var reviewSchema = z25.object({
3088
+ import { z as z22 } from "zod";
3089
+ var reviewSchema = z22.object({
3405
3090
  // Broad, high-level takeaways grouped by theme (e.g. ingestion, search UI),
3406
3091
  // not one entry per workflow step — a step's raw output can be a long,
3407
3092
  // multi-paragraph blob (see implement.ts's summaries.join), and mirroring
3408
3093
  // that 1:1 is what made the old per-step summary an unreadable wall of text.
3409
- summaryPoints: z25.array(z25.string()),
3410
- reviewPrompt: z25.string(),
3411
- nextSteps: z25.array(z25.string())
3094
+ summaryPoints: z22.array(z22.string()),
3095
+ reviewPrompt: z22.string(),
3096
+ nextSteps: z22.array(z22.string())
3412
3097
  });
3413
3098
  function formatCompletedSteps(steps) {
3414
3099
  if (!steps.length) return "(no prior steps completed)";
@@ -3459,16 +3144,16 @@ ${formatCompletedSteps(ctx.completedSteps)}`,
3459
3144
  };
3460
3145
 
3461
3146
  // src/actions/implement.ts
3462
- import z26 from "zod";
3147
+ import z24 from "zod";
3463
3148
 
3464
3149
  // src/lib/worktree.ts
3465
3150
  import { execFile, spawn as spawn3 } from "node:child_process";
3466
- import { copyFile, mkdir as mkdir6, readdir as readdir3, readFile as readFile7, stat as stat2, writeFile as writeFile6 } from "node:fs/promises";
3151
+ import { copyFile, mkdir as mkdir6, readdir as readdir3, readFile as readFile8, stat as stat2, writeFile as writeFile6 } from "node:fs/promises";
3467
3152
  import {
3468
3153
  basename as basename2,
3469
3154
  dirname as dirname7,
3470
3155
  isAbsolute as isAbsolute2,
3471
- join as join9,
3156
+ join as join10,
3472
3157
  relative as relative2,
3473
3158
  resolve as resolve3
3474
3159
  } from "node:path";
@@ -3502,7 +3187,7 @@ async function isWorkingTreeDirty(repoRoot) {
3502
3187
  return out.trim().length > 0;
3503
3188
  }
3504
3189
  async function pruneOldWorktrees(repoRoot) {
3505
- const dir = join9(stateDir(repoRoot), "worktrees");
3190
+ const dir = join10(stateDir(repoRoot), "worktrees");
3506
3191
  const stale = (await readdir3(dir).catch(() => [])).filter((name) => /^wizard-implement-\d+$/.test(name)).sort().reverse().slice(MAX_WIZARD_WORKTREES - 1);
3507
3192
  for (const slug of stale) {
3508
3193
  const branch = slug.replace("wizard-implement-", WIZARD_BRANCH_PREFIX);
@@ -3513,7 +3198,7 @@ async function pruneOldWorktrees(repoRoot) {
3513
3198
  "worktree",
3514
3199
  "remove",
3515
3200
  "--force",
3516
- join9(dir, slug)
3201
+ join10(dir, slug)
3517
3202
  ]);
3518
3203
  await git(["-C", repoRoot, "branch", "-D", branch]);
3519
3204
  } catch (err) {
@@ -3527,7 +3212,7 @@ async function pruneOldWorktrees(repoRoot) {
3527
3212
  async function createWorktree(repoRoot) {
3528
3213
  const branch = `${WIZARD_BRANCH_PREFIX}${Date.now()}`;
3529
3214
  const dirSlug = branch.replace(/\//g, "-");
3530
- const path = join9(stateDir(repoRoot), "worktrees", dirSlug);
3215
+ const path = join10(stateDir(repoRoot), "worktrees", dirSlug);
3531
3216
  await git(["-C", repoRoot, "worktree", "prune"]);
3532
3217
  await pruneOldWorktrees(repoRoot);
3533
3218
  await mkdir6(dirname7(path), { recursive: true });
@@ -3647,8 +3332,8 @@ async function copyUploadIntoWorktree(repoRoot, worktreePath, ingestDir, sourceP
3647
3332
  } catch {
3648
3333
  return { ok: false, reason: `"${sourcePath}" does not exist` };
3649
3334
  }
3650
- const relPath = join9(ingestDir, basename2(source));
3651
- const dest = join9(worktreePath, relPath);
3335
+ const relPath = join10(ingestDir, basename2(source));
3336
+ const dest = join10(worktreePath, relPath);
3652
3337
  try {
3653
3338
  await mkdir6(dirname7(dest), { recursive: true });
3654
3339
  await copyFile(source, dest);
@@ -3664,10 +3349,10 @@ function hasEnvVar(content, name) {
3664
3349
  return new RegExp(`^(\\s*(?:export\\s+)?${name})\\s*=`, "m").test(content);
3665
3350
  }
3666
3351
  async function writeSearchEnvValues(worktreePath, vars) {
3667
- const target = join9(worktreePath, ".env");
3352
+ const target = join10(worktreePath, ".env");
3668
3353
  let existing = "";
3669
3354
  try {
3670
- existing = await readFile7(target, "utf8");
3355
+ existing = await readFile8(target, "utf8");
3671
3356
  } catch (err) {
3672
3357
  if (err.code !== "ENOENT") throw err;
3673
3358
  }
@@ -3735,15 +3420,63 @@ async function confirmDirtyWorkingTree(ctx, repoRoot) {
3735
3420
  }
3736
3421
  }
3737
3422
 
3423
+ // src/lib/algoliaApiKey.ts
3424
+ import { z as z23 } from "zod";
3425
+ var SAFE_ACLS = /* @__PURE__ */ new Set(["search", "browse", "listIndexes"]);
3426
+ var apiKeySchema = z23.object({
3427
+ value: z23.string().min(1),
3428
+ acl: z23.array(z23.string()).default([]),
3429
+ indexes: z23.array(z23.string()).default([])
3430
+ });
3431
+ var apiKeyListSchema = z23.object({
3432
+ items: z23.array(apiKeySchema).optional(),
3433
+ keys: z23.array(apiKeySchema).optional()
3434
+ }).transform((o) => o.items ?? o.keys ?? []);
3435
+ var createdKeySchema = z23.object({
3436
+ key: z23.string().min(1).optional(),
3437
+ value: z23.string().min(1).optional()
3438
+ });
3439
+ function canReuse(key, index) {
3440
+ return key.acl.includes("search") && key.acl.every((acl) => SAFE_ACLS.has(acl)) && (key.indexes.length === 0 || key.indexes.includes("*") || key.indexes.includes(index));
3441
+ }
3442
+ async function createSearchKey(index) {
3443
+ const stdout = await runAlgoliaCli([
3444
+ "apikeys",
3445
+ "create",
3446
+ "--indices",
3447
+ index,
3448
+ "--acl",
3449
+ "search,browse",
3450
+ "--description",
3451
+ `wizard search-only key for ${index}`,
3452
+ "-o",
3453
+ "json"
3454
+ ]);
3455
+ const { key, value } = createdKeySchema.parse(JSON.parse(stdout));
3456
+ const created = key ?? value;
3457
+ if (!created) throw new Error("apikeys create returned no key value");
3458
+ return created;
3459
+ }
3460
+ async function resolveSearchOnlyKey(index) {
3461
+ const stdout = await runAlgoliaCli(["apikeys", "list", "-o", "json"]);
3462
+ const existing = apiKeyListSchema.parse(JSON.parse(stdout)).find((key) => canReuse(key, index))?.value;
3463
+ if (existing) {
3464
+ logger.info({ index }, "reusing existing search-only API key");
3465
+ return existing;
3466
+ }
3467
+ logger.info({ index }, "no reusable search-only key found; creating one");
3468
+ return createSearchKey(index);
3469
+ }
3470
+
3738
3471
  // src/lib/algoliaDocs.ts
3739
3472
  import { readFileSync, readdirSync, existsSync as existsSync2 } from "node:fs";
3740
- import { dirname as dirname8, join as join10 } from "node:path";
3473
+ import { dirname as dirname8, join as join11 } from "node:path";
3741
3474
  import { fileURLToPath as fileURLToPath2 } from "node:url";
3742
- var DOCS_SUBPATH = join10("docs", "algolia-sdk");
3475
+ var DOCS_SUBPATH = join11("docs", "algolia-sdk");
3743
3476
  function findDocsDir() {
3744
3477
  let dir = dirname8(fileURLToPath2(import.meta.url));
3745
3478
  for (; ; ) {
3746
- const candidate = join10(dir, DOCS_SUBPATH);
3479
+ const candidate = join11(dir, DOCS_SUBPATH);
3747
3480
  if (existsSync2(candidate)) return candidate;
3748
3481
  const parent = dirname8(dir);
3749
3482
  if (parent === dir) return void 0;
@@ -3766,7 +3499,7 @@ function loadAlgoliaDoc(language) {
3766
3499
  );
3767
3500
  return "";
3768
3501
  }
3769
- return readFileSync(join10(docsDir, files[0]), "utf8").trim();
3502
+ return readFileSync(join11(docsDir, files[0]), "utf8").trim();
3770
3503
  }
3771
3504
  function getNamedDoc(name, language) {
3772
3505
  const docsDir = findDocsDir();
@@ -3774,7 +3507,7 @@ function getNamedDoc(name, language) {
3774
3507
  logger.warn("docs/algolia-sdk not found");
3775
3508
  return "";
3776
3509
  }
3777
- const file = join10(docsDir, `${name}-${language}.md`);
3510
+ const file = join11(docsDir, `${name}-${language}.md`);
3778
3511
  if (!existsSync2(file)) {
3779
3512
  logger.warn({ name, language }, "named SDK reference not found");
3780
3513
  return "";
@@ -3801,50 +3534,50 @@ function shellQuote(value) {
3801
3534
  }
3802
3535
 
3803
3536
  // src/actions/implement.ts
3804
- var implementSchema = z26.object({
3805
- filesChanged: z26.array(z26.string()),
3806
- summary: z26.string(),
3537
+ var implementSchema = z24.object({
3538
+ filesChanged: z24.array(z24.string()),
3539
+ summary: z24.string(),
3807
3540
  // Absolute path to the throwaway worktree holding the generated changes, so
3808
3541
  // the user can open it (`cd <worktreePath>`) or inspect the diff
3809
3542
  // (`git -C <worktreePath> status/diff`).
3810
- worktreePath: z26.string().optional(),
3811
- ingestCommand: z26.string().optional(),
3543
+ worktreePath: z24.string().optional(),
3544
+ ingestCommand: z24.string().optional(),
3812
3545
  // True when the user accepted the run-now prompt and the wizard executed the
3813
3546
  // ingestion script; downstream steps use this to avoid telling the user to run
3814
3547
  // a script that already ran.
3815
- ingestScriptRan: z26.boolean().optional(),
3548
+ ingestScriptRan: z24.boolean().optional(),
3816
3549
  // Records ingested by the run-now execution, parsed from the script's
3817
3550
  // machine-readable count line; absent when the script didn't run or emitted
3818
3551
  // no parseable count.
3819
- ingestRecordCount: z26.number().optional(),
3552
+ ingestRecordCount: z24.number().optional(),
3820
3553
  // Wall-clock duration of the run-now ingestion execution, in ms.
3821
- ingestDurationMs: z26.number().optional(),
3822
- ingestionSource: z26.enum(["local", "fileUpload", "generated"]),
3554
+ ingestDurationMs: z24.number().optional(),
3555
+ ingestionSource: z24.enum(["local", "fileUpload", "generated"]),
3823
3556
  // Suggested names/values, built from framework detection. The search agent is
3824
3557
  // instructed to rename the prefix if it doesn't match the project's build
3825
3558
  // tool, so the names it actually wrote can differ — treat these as hints, not
3826
3559
  // ground truth (the agent's summary carries the final names).
3827
- searchEnvVars: z26.array(
3828
- z26.object({
3829
- name: z26.string(),
3830
- value: z26.string()
3560
+ searchEnvVars: z24.array(
3561
+ z24.object({
3562
+ name: z24.string(),
3563
+ value: z24.string()
3831
3564
  })
3832
3565
  ).optional()
3833
3566
  });
3834
- var implementationOutputSchema = z26.object({
3835
- summary: z26.string(),
3567
+ var implementationOutputSchema = z24.object({
3568
+ summary: z24.string(),
3836
3569
  // Ingestion only: how to run the generated script, as a structured pair the
3837
3570
  // wizard turns into an argv (`<runtime> <entrypoint>`) — never a free-form
3838
3571
  // command string. `runtime` is constrained to an allowlisted interpreter and
3839
3572
  // `entrypoint` is validated to a worktree-relative path before execution, so
3840
3573
  // the agent cannot inject extra commands or swap the interpreter.
3841
- runtime: z26.enum(INGEST_RUNTIMES).optional(),
3842
- entrypoint: z26.string().optional()
3574
+ runtime: z24.enum(INGEST_RUNTIMES).optional(),
3575
+ entrypoint: z24.string().optional()
3843
3576
  });
3844
- var verificationOutputSchema = z26.object({
3845
- summary: z26.string(),
3846
- sufficient: z26.boolean(),
3847
- additionalInstructions: z26.string().optional()
3577
+ var verificationOutputSchema = z24.object({
3578
+ summary: z24.string(),
3579
+ sufficient: z24.boolean(),
3580
+ additionalInstructions: z24.string().optional()
3848
3581
  });
3849
3582
  var MAX_IMPLEMENT_VERIFICATION_ATTEMPTS = 3;
3850
3583
  var DEFAULT_IMPLEMENT_USE_CASES = ["ingestion", "search"];
@@ -3958,7 +3691,7 @@ function searchInstructions(input) {
3958
3691
  doc,
3959
3692
  `Add the search UI at ${input.searchLocation ? `"${input.searchLocation}"` : "the best shared, always-rendered layout location (e.g. a header/nav component)"} so it is reachable across the app \u2014 at least a working SearchBox and Hits against the "${input.targetIndex}" index.`,
3960
3693
  "Read the App ID and a search-only API key from public env vars; never hardcode them. A search-only key is safe to expose client-side.",
3961
- // appId always resolves (requireApplication throws otherwise); only the
3694
+ // appId always resolves (loadActiveProfile throws otherwise); only the
3962
3695
  // search-only key is best-effort and can fall back to a placeholder.
3963
3696
  `Values: App ID "${input.appId}", search-only key ${input.searchKey ? `"${input.searchKey}"` : "(placeholder for the developer to fill in)"}.`,
3964
3697
  // Names are fixed, not the agent's to rename: the wizard writes the
@@ -4107,7 +3840,6 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
4107
3840
  }
4108
3841
  }
4109
3842
  const targetIndex = selected?.selection;
4110
- useWizard.getState().setTargetIndex(targetIndex ?? null);
4111
3843
  await assertGitRepoWithHead(repoRoot);
4112
3844
  if (await isWorkingTreeDirty(repoRoot)) {
4113
3845
  await confirmDirtyWorkingTree(ctx, repoRoot);
@@ -4118,7 +3850,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
4118
3850
  let appId;
4119
3851
  let searchKey;
4120
3852
  if (useCases.includes("search")) {
4121
- appId = (await requireApplication()).id;
3853
+ appId = (await loadActiveProfile()).appId;
4122
3854
  try {
4123
3855
  searchKey = await resolveSearchOnlyKey(targetIndex);
4124
3856
  } catch (err) {
@@ -4229,8 +3961,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
4229
3961
  messages: []
4230
3962
  }) === true;
4231
3963
  if (runNow) {
4232
- const ingestApp = await requireApplication();
4233
- const writeKey = await resolveWriteKey(targetIndex);
3964
+ const profile = await loadActiveProfile();
4234
3965
  ctx.notify({ messages: [`Writing records to "${targetIndex}"\u2026`] });
4235
3966
  const scriptLogId = ctx.logStart("runIngestScript", {
4236
3967
  runtime: ingestRuntime,
@@ -4242,8 +3973,8 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
4242
3973
  ingestRuntime,
4243
3974
  ingestEntrypoint,
4244
3975
  {
4245
- [APP_ID_VAR]: ingestApp.id,
4246
- [API_KEY_VAR]: writeKey
3976
+ [APP_ID_VAR]: profile.appId,
3977
+ [API_KEY_VAR]: profile.apiKey
4247
3978
  }
4248
3979
  );
4249
3980
  ctx.logEnd(scriptLogId, run2.ok ? "success" : "error");
@@ -4454,8 +4185,8 @@ var defaultWorkflow = {
4454
4185
  defineStep({
4455
4186
  id: "select-index",
4456
4187
  title: "Set up index",
4457
- outputSchema: z27.object({
4458
- selection: z27.string()
4188
+ outputSchema: z25.object({
4189
+ selection: z25.string()
4459
4190
  }),
4460
4191
  run: (ctx) => selectIndexStep(ctx)
4461
4192
  }),
@@ -4734,7 +4465,7 @@ function parseCliArgs(argv) {
4734
4465
 
4735
4466
  // src/lib/resetState.ts
4736
4467
  import { readdir as readdir4, rm as rm2 } from "node:fs/promises";
4737
- import { join as join11 } from "node:path";
4468
+ import { join as join12 } from "node:path";
4738
4469
  var KEEP = ["wizard.log"];
4739
4470
  async function resetProjectState() {
4740
4471
  const dir = stateDir();
@@ -4746,7 +4477,7 @@ async function resetProjectState() {
4746
4477
  }
4747
4478
  const targets = entries.filter((name) => !KEEP.includes(name));
4748
4479
  await Promise.all(
4749
- targets.map((name) => rm2(join11(dir, name), { recursive: true, force: true }))
4480
+ targets.map((name) => rm2(join12(dir, name), { recursive: true, force: true }))
4750
4481
  );
4751
4482
  return { dir, removed: targets };
4752
4483
  }
@@ -4801,38 +4532,31 @@ ${formatStepList(workflow)}`);
4801
4532
  }
4802
4533
  async function run(workflow) {
4803
4534
  const store = useWizard.getState();
4804
- const instance = render(/* @__PURE__ */ jsx14(App, {}), { incrementalRendering: true });
4805
- await store.waitForStart();
4535
+ let instance = render(/* @__PURE__ */ jsx14(App, {}), { incrementalRendering: true });
4806
4536
  let user = await getUser();
4807
4537
  if (!user) {
4808
- store.beginAuth();
4538
+ await instance.waitUntilRenderFlush();
4539
+ instance.cleanup();
4809
4540
  try {
4810
4541
  await runAuthLogin();
4811
4542
  } catch (err) {
4812
- store.setError(err instanceof Error ? err.message : String(err));
4813
- await instance.waitUntilExit();
4543
+ console.error(err instanceof Error ? err.message : String(err));
4814
4544
  process.exit(1);
4815
4545
  }
4816
- store.endAuth();
4546
+ instance = render(/* @__PURE__ */ jsx14(App, {}), { incrementalRendering: true });
4817
4547
  user = await getUser();
4818
4548
  if (!user) {
4819
4549
  store.setError(
4820
- "Authentication completed but no Algolia user was returned. Try running `npx @algolia/cli@latest auth login` directly."
4550
+ "Authentication completed but no Algolia user was returned. Try running `npx @algolia/cli auth login` directly."
4821
4551
  );
4822
4552
  await instance.waitUntilExit();
4823
4553
  process.exit(1);
4824
4554
  }
4825
4555
  }
4826
4556
  store.setUser(user);
4827
- let app;
4828
- try {
4829
- app = await ensureApplication();
4830
- } catch (err) {
4831
- store.setError(err instanceof Error ? err.message : String(err));
4832
- await instance.waitUntilExit();
4833
- process.exit(1);
4834
- }
4835
- runWorkflow(workflow, app.id);
4557
+ const profile = await loadActiveProfile();
4558
+ await store.waitForStart();
4559
+ runWorkflow(workflow, profile?.appId);
4836
4560
  }
4837
4561
  var started = await startup();
4838
4562
  if (typeof started === "number") {