@algolia/wizard 0.86.0 → 0.87.0

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 (2) hide show
  1. package/dist/main.js +299 -129
  2. package/package.json +1 -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 Box22, Text as Text23, useApp as useApp2, useInput as useInput9, useWindowSize as useWindowSize8 } from "ink";
7
+ import { Box as Box23, Text as Text24, useApp as useApp2, useInput as useInput10, useWindowSize as useWindowSize8 } from "ink";
8
8
  import Spinner3 from "ink-spinner";
9
9
 
10
10
  // src/lib/terminalSize.ts
@@ -98,8 +98,8 @@ function runAlgoliaCli(args, { onOutput, redact } = {}) {
98
98
  let stdout = "";
99
99
  let stderr = "";
100
100
  const splitters = {
101
- stdout: lineSplitter((line) => onOutput?.("stdout", line)),
102
- stderr: lineSplitter((line) => onOutput?.("stderr", line))
101
+ stdout: lineSplitter((line) => onOutput?.("stdout", mask(line, redact))),
102
+ stderr: lineSplitter((line) => onOutput?.("stderr", mask(line, redact)))
103
103
  };
104
104
  child.stdout.on("data", (chunk) => {
105
105
  const text = String(chunk);
@@ -287,6 +287,16 @@ var CLI_OUTPUT_LIMIT = 200;
287
287
  function commandApprovalKey(command, cwd) {
288
288
  return `${cwd}\0${command}`;
289
289
  }
290
+ function appendOutputLog(logs, outputCount, entry) {
291
+ if (outputCount < CLI_OUTPUT_LIMIT) {
292
+ return { logs: [...logs, entry], _outputLogCount: outputCount + 1 };
293
+ }
294
+ const oldest = logs.findIndex((e) => e.kind === "output");
295
+ return {
296
+ logs: [...logs.filter((_, i) => i !== oldest), entry],
297
+ _outputLogCount: outputCount
298
+ };
299
+ }
290
300
  var useWizard = create((set, get) => ({
291
301
  phase: "idle",
292
302
  homeScreen: "home",
@@ -304,6 +314,7 @@ var useWizard = create((set, get) => ({
304
314
  writtenFiles: [],
305
315
  approvedCommands: /* @__PURE__ */ new Set(),
306
316
  logs: [],
317
+ _outputLogCount: 0,
307
318
  error: null,
308
319
  inputReq: null,
309
320
  _resolve: null,
@@ -396,11 +407,23 @@ var useWizard = create((set, get) => ({
396
407
  get()._clearNoticeQueue();
397
408
  set({ notices: [] });
398
409
  },
399
- pushCliOutput: (stream, text) => set((s) => ({
400
- cliOutput: [...s.cliOutput, { id: nanoid(), stream, text }].slice(
401
- -CLI_OUTPUT_LIMIT
402
- )
403
- })),
410
+ // Logged too, so a line cut off on the main screen can be read in the log view.
411
+ pushCliOutput: (stream, text) => {
412
+ const id = nanoid();
413
+ set((s) => ({
414
+ cliOutput: [...s.cliOutput, { id, stream, text }].slice(
415
+ -CLI_OUTPUT_LIMIT
416
+ ),
417
+ ...appendOutputLog(s.logs, s._outputLogCount, {
418
+ id,
419
+ kind: "output",
420
+ name: text,
421
+ stream,
422
+ status: "success",
423
+ startedAt: Date.now()
424
+ })
425
+ }));
426
+ },
404
427
  clearCliOutput: () => set({ cliOutput: [] }),
405
428
  setReview: (review2) => set({ review: review2 }),
406
429
  setTargetIndex: (index) => set({ targetIndex: index }),
@@ -474,6 +497,7 @@ var useWizard = create((set, get) => ({
474
497
  writtenFiles: [],
475
498
  approvedCommands: /* @__PURE__ */ new Set(),
476
499
  logs: [],
500
+ _outputLogCount: 0,
477
501
  error: null,
478
502
  inputReq: null,
479
503
  _resolve: null,
@@ -713,6 +737,32 @@ import { useState as useState9 } from "react";
713
737
  import { Box as Box8, Text as Text8, useInput as useInput3 } from "ink";
714
738
  import { useLayoutEffect as useLayoutEffect3, useState as useState6 } from "react";
715
739
 
740
+ // src/lib/wrapExact.ts
741
+ function wrapExactLine(line, width) {
742
+ if (line.length === 0) return [" "];
743
+ const lines = [];
744
+ let i = 0;
745
+ while (i < line.length) {
746
+ if (line.length - i <= width) {
747
+ lines.push(line.slice(i));
748
+ break;
749
+ }
750
+ let end = i + width;
751
+ if (line.charAt(end) !== " ") {
752
+ const lastSpace = line.lastIndexOf(" ", end - 1);
753
+ if (lastSpace >= i) end = lastSpace + 1;
754
+ }
755
+ if (end <= i) end = i + width;
756
+ lines.push(line.slice(i, end));
757
+ i = end;
758
+ }
759
+ return lines;
760
+ }
761
+ function wrapExact(text, width) {
762
+ if (width <= 0) return [text || " "];
763
+ return text.split(/\r\n|\n|\r/).flatMap((line) => wrapExactLine(line, width));
764
+ }
765
+
716
766
  // src/ui/DecisionSelect.tsx
717
767
  import { Box as Box5, Text as Text5, useInput } from "ink";
718
768
  import { useState as useState3 } from "react";
@@ -1028,30 +1078,6 @@ function Review() {
1028
1078
  import { jsx as jsx6, jsxs as jsxs7 } from "react/jsx-runtime";
1029
1079
  var BLANK2 = { prefix: "", text: " ", color: COLORS.dim };
1030
1080
  var COMMAND_PREFIX = "$ ";
1031
- function wrapExactLine(line, width) {
1032
- if (line.length === 0) return [" "];
1033
- const lines = [];
1034
- let i = 0;
1035
- while (i < line.length) {
1036
- if (line.length - i <= width) {
1037
- lines.push(line.slice(i));
1038
- break;
1039
- }
1040
- let end = i + width;
1041
- if (line.charAt(end) !== " ") {
1042
- const lastSpace = line.lastIndexOf(" ", end - 1);
1043
- if (lastSpace >= i) end = lastSpace + 1;
1044
- }
1045
- if (end <= i) end = i + width;
1046
- lines.push(line.slice(i, end));
1047
- i = end;
1048
- }
1049
- return lines;
1050
- }
1051
- function wrapExact(text, width) {
1052
- if (width <= 0) return [text || " "];
1053
- return text.split(/\r\n|\n|\r/).flatMap((line) => wrapExactLine(line, width));
1054
- }
1055
1081
  function fieldLines(prefix, value, color, width) {
1056
1082
  return wrapText(value, Math.max(width - prefix.length, 1)).map((text, i) => ({
1057
1083
  prefix: i === 0 ? prefix : " ".repeat(prefix.length),
@@ -2332,7 +2358,7 @@ async function ensureApplication(resumeAppId) {
2332
2358
  // package.json
2333
2359
  var package_default = {
2334
2360
  name: "@algolia/wizard",
2335
- version: "0.86.0",
2361
+ version: "0.87.0",
2336
2362
  description: "Magically implement Algolia functionality in your codebase",
2337
2363
  type: "module",
2338
2364
  engines: {
@@ -8564,10 +8590,15 @@ var sidebarCommands = [
8564
8590
  { keyHint: "tab", description: "toggle logs" },
8565
8591
  { keyHint: "esc", description: "exit wizard" }
8566
8592
  ];
8593
+ var logsSidebarCommands = [
8594
+ { keyHint: "tab", description: "toggle logs" },
8595
+ { keyHint: "esc", description: "back" }
8596
+ ];
8567
8597
 
8568
8598
  // src/ui/Sidebar.tsx
8569
8599
  import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
8570
- function Sidebar() {
8600
+ function Sidebar({ inLogs = false }) {
8601
+ const commands = inLogs ? logsSidebarCommands : sidebarCommands;
8571
8602
  return /* @__PURE__ */ jsxs16(
8572
8603
  Box17,
8573
8604
  {
@@ -8584,7 +8615,7 @@ function Sidebar() {
8584
8615
  ] }),
8585
8616
  /* @__PURE__ */ jsxs16(Box17, { flexDirection: "column", gap: 1, children: [
8586
8617
  /* @__PURE__ */ jsx16(Progress, {}),
8587
- /* @__PURE__ */ jsx16(Box17, { flexDirection: "column", children: sidebarCommands.map((c) => {
8618
+ /* @__PURE__ */ jsx16(Box17, { flexDirection: "column", children: commands.map((c) => {
8588
8619
  return /* @__PURE__ */ jsxs16(Box17, { flexDirection: "row", gap: 1, children: [
8589
8620
  /* @__PURE__ */ jsx16(Text18, { color: COLORS.primary, children: `[${c.keyHint}]` }),
8590
8621
  /* @__PURE__ */ jsx16(Text18, { color: COLORS.muted, children: c.description })
@@ -8622,23 +8653,130 @@ function Ribbon() {
8622
8653
  }
8623
8654
 
8624
8655
  // src/ui/App.tsx
8625
- import { useState as useState12 } from "react";
8656
+ import { useState as useState14 } from "react";
8626
8657
 
8627
8658
  // src/ui/Logs.tsx
8659
+ import { Box as Box20, Text as Text21, useInput as useInput9 } from "ink";
8660
+ import { useLayoutEffect as useLayoutEffect6, useState as useState12 } from "react";
8661
+
8662
+ // src/ui/LogDetails.tsx
8628
8663
  import { Box as Box19, Text as Text20, useInput as useInput8 } from "ink";
8629
- import { jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
8664
+ import { useLayoutEffect as useLayoutEffect5, useMemo, useState as useState11 } from "react";
8665
+
8666
+ // src/ui/logFormat.ts
8630
8667
  var KIND_COLOR = {
8631
8668
  tool: COLORS.primary,
8632
- prompt: COLORS.badge
8669
+ prompt: COLORS.badge,
8670
+ output: COLORS.muted
8671
+ };
8672
+ var STREAM_COLOR = {
8673
+ stderr: COLORS.muted,
8674
+ stdout: COLORS.dim
8633
8675
  };
8634
8676
  var STATUS_COLOR = {
8635
8677
  running: COLORS.status.running,
8636
8678
  error: COLORS.danger
8637
8679
  };
8638
8680
  function logNameColor(entry) {
8639
- return STATUS_COLOR[entry.status] ?? KIND_COLOR[entry.kind];
8681
+ const base = entry.stream ? STREAM_COLOR[entry.stream] : KIND_COLOR[entry.kind];
8682
+ return STATUS_COLOR[entry.status] ?? base;
8683
+ }
8684
+ function formatTimestamp(ms) {
8685
+ const d = new Date(ms);
8686
+ const pad = (n) => String(n).padStart(2, "0");
8687
+ return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
8688
+ }
8689
+ function durationText(entry) {
8690
+ return entry.kind === "tool" && entry.durationMs !== void 0 ? `${entry.durationMs}ms` : "";
8691
+ }
8692
+
8693
+ // src/ui/LogDetails.tsx
8694
+ import { jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
8695
+ var BLANK4 = { text: " ", color: COLORS.dim };
8696
+ var VALUE_INDENT = " ";
8697
+ var TAB = " ";
8698
+ function wrapLines(text, width, line, indent = "") {
8699
+ return wrapExact(
8700
+ text.replaceAll(" ", TAB),
8701
+ Math.max(width - indent.length, 1)
8702
+ ).map((part) => ({ ...line, text: indent + part }));
8703
+ }
8704
+ function formatValue(value) {
8705
+ return typeof value === "string" ? value : JSON.stringify(value, null, 2);
8706
+ }
8707
+ function inputFields(input) {
8708
+ if (input === void 0) return [];
8709
+ if (input !== null && typeof input === "object" && !Array.isArray(input)) {
8710
+ return Object.entries(input).filter(([, value]) => value !== void 0).map(([label, value]) => [label, formatValue(value)]);
8711
+ }
8712
+ return [["input", formatValue(input)]];
8713
+ }
8714
+ function metaText(entry) {
8715
+ const parts = [`[${formatTimestamp(entry.startedAt)}]`];
8716
+ if (entry.kind === "tool") parts.push(entry.status, durationText(entry));
8717
+ return parts.filter(Boolean).join(" ");
8718
+ }
8719
+ function buildDetailLines(entry, width) {
8720
+ const lines = wrapLines(entry.name, width, {
8721
+ color: logNameColor(entry),
8722
+ bold: true
8723
+ });
8724
+ lines.push({ text: metaText(entry), color: COLORS.dim });
8725
+ for (const [label, value] of inputFields(entry.input)) {
8726
+ lines.push(BLANK4, { text: label, color: COLORS.muted });
8727
+ lines.push(
8728
+ ...wrapLines(value, width, { color: COLORS.primary }, VALUE_INDENT)
8729
+ );
8730
+ }
8731
+ return lines;
8640
8732
  }
8733
+ function LogDetails({
8734
+ entry,
8735
+ onClose
8736
+ }) {
8737
+ const [width, setWidth] = useState11(0);
8738
+ const lines = useMemo(
8739
+ () => width > 0 ? buildDetailLines(entry, width) : [],
8740
+ [entry, width]
8741
+ );
8742
+ const scroll = useScrollWindow({ itemCount: lines.length });
8743
+ useLayoutEffect5(() => {
8744
+ if (scroll.measured) setWidth(scroll.width);
8745
+ }, [scroll.measured, scroll.width]);
8746
+ useInput8((input, key) => {
8747
+ if (input === "k" || key.upArrow) scroll.scrollBy(-1);
8748
+ else if (input === "j" || key.downArrow) scroll.scrollBy(1);
8749
+ else if (key.escape) onClose();
8750
+ });
8751
+ const visible = lines.slice(scroll.offset, scroll.offset + scroll.capacity);
8752
+ return /* @__PURE__ */ jsxs18(Box19, { flexDirection: "column", flexGrow: 1, children: [
8753
+ /* @__PURE__ */ jsx18(ScrollView, { scroll, children: visible.map((line, i) => /* @__PURE__ */ jsx18(
8754
+ Text20,
8755
+ {
8756
+ color: line.color,
8757
+ bold: line.bold,
8758
+ wrap: "truncate",
8759
+ children: line.text
8760
+ },
8761
+ `detail-${scroll.offset + i}`
8762
+ )) }),
8763
+ /* @__PURE__ */ jsxs18(Box19, { gap: 2, children: [
8764
+ scroll.maxOffset > 0 && /* @__PURE__ */ jsxs18(Text20, { children: [
8765
+ /* @__PURE__ */ jsx18(Text20, { color: COLORS.primary, children: "[j] [k]" }),
8766
+ /* @__PURE__ */ jsx18(Text20, { color: COLORS.dim, children: " scroll" })
8767
+ ] }),
8768
+ /* @__PURE__ */ jsxs18(Text20, { children: [
8769
+ /* @__PURE__ */ jsx18(Text20, { color: COLORS.primary, children: "[esc]" }),
8770
+ /* @__PURE__ */ jsx18(Text20, { color: COLORS.dim, children: " back" })
8771
+ ] })
8772
+ ] })
8773
+ ] });
8774
+ }
8775
+
8776
+ // src/ui/Logs.tsx
8777
+ import { Fragment, jsx as jsx19, jsxs as jsxs19 } from "react/jsx-runtime";
8641
8778
  var ROW_GAP = 1;
8779
+ var SELECTED_MARKER = "\u276F";
8642
8780
  function truncate3(str, maxWidth) {
8643
8781
  if (maxWidth <= 0) return "";
8644
8782
  return str.length > maxWidth ? `${str.slice(0, maxWidth - 1)}\u2026` : str;
@@ -8649,53 +8787,84 @@ function rawInputText(input) {
8649
8787
  if (!str || str === "{}") return "";
8650
8788
  return str.replace(/\s+/g, " ").trim();
8651
8789
  }
8652
- function formatTimestamp(ms) {
8653
- const d = new Date(ms);
8654
- const pad = (n) => String(n).padStart(2, "0");
8655
- return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
8656
- }
8657
- function Logs() {
8790
+ function Logs({ onBack }) {
8658
8791
  const logs = useWizard((s) => s.logs);
8659
- const scroll = useScrollWindow({ itemCount: logs.length, followBottom: true });
8660
- useInput8((input, key) => {
8661
- if (input === "k" || key.upArrow) scroll.scrollBy(-1);
8662
- else if (input === "j" || key.downArrow) scroll.scrollBy(1);
8792
+ const [openLogId, setOpenLogId] = useState12(null);
8793
+ const [selectedId, setSelectedId] = useState12(null);
8794
+ const found = selectedId === null ? -1 : logs.findIndex((e) => e.id === selectedId);
8795
+ if (selectedId !== null && found < 0) setSelectedId(null);
8796
+ const scroll = useScrollWindow({
8797
+ itemCount: logs.length,
8798
+ followBottom: selectedId === null
8663
8799
  });
8800
+ const selectedIndex = found >= 0 ? found : logs.length - 1;
8801
+ const openEntry = logs.find((e) => e.id === openLogId);
8802
+ const { revealIndex } = scroll;
8803
+ useLayoutEffect6(() => {
8804
+ if (selectedIndex >= 0) revealIndex(selectedIndex);
8805
+ }, [selectedIndex, revealIndex]);
8806
+ const moveSelection = (delta) => {
8807
+ if (logs.length === 0) return;
8808
+ const next = Math.min(Math.max(selectedIndex + delta, 0), logs.length - 1);
8809
+ setSelectedId(next === logs.length - 1 ? null : logs[next].id);
8810
+ };
8811
+ useInput9(
8812
+ (input, key) => {
8813
+ if (input === "k" || key.upArrow) moveSelection(-1);
8814
+ else if (input === "j" || key.downArrow) moveSelection(1);
8815
+ else if (key.return && logs[selectedIndex]) {
8816
+ setOpenLogId(logs[selectedIndex].id);
8817
+ } else if (key.escape) onBack();
8818
+ },
8819
+ { isActive: !openEntry }
8820
+ );
8664
8821
  const visible = logs.slice(scroll.offset, scroll.offset + scroll.capacity);
8665
- return /* @__PURE__ */ jsxs18(Box19, { flexDirection: "column", paddingX: 4, paddingY: 2, flexGrow: 1, children: [
8666
- logs.length === 0 && /* @__PURE__ */ jsx18(Text20, { color: COLORS.dim, children: "No logs yet." }),
8667
- /* @__PURE__ */ jsx18(ScrollView, { scroll, children: visible.map((entry) => {
8822
+ return /* @__PURE__ */ jsx19(Box20, { flexDirection: "column", paddingX: 4, paddingY: 2, flexGrow: 1, children: openEntry ? /* @__PURE__ */ jsx19(LogDetails, { entry: openEntry, onClose: () => setOpenLogId(null) }) : /* @__PURE__ */ jsxs19(Fragment, { children: [
8823
+ logs.length === 0 && /* @__PURE__ */ jsx19(Text21, { color: COLORS.dim, children: "No logs yet." }),
8824
+ /* @__PURE__ */ jsx19(ScrollView, { scroll, children: visible.map((entry, i) => {
8825
+ const selected = scroll.offset + i === selectedIndex;
8668
8826
  const timestamp = `[${formatTimestamp(entry.startedAt)}]`;
8669
- const durationText = entry.kind === "tool" && entry.durationMs !== void 0 ? `${entry.durationMs}ms` : "";
8827
+ const duration = durationText(entry);
8670
8828
  const rawPreview = rawInputText(entry.input);
8671
- const partCount = 2 + (rawPreview ? 1 : 0) + (durationText ? 1 : 0);
8829
+ const partCount = 3 + (rawPreview ? 1 : 0) + (duration ? 1 : 0);
8672
8830
  const gaps = (partCount - 1) * ROW_GAP;
8673
- let budget = scroll.width - timestamp.length - durationText.length - gaps;
8831
+ let budget = scroll.width - SELECTED_MARKER.length - timestamp.length - duration.length - gaps;
8674
8832
  const name = truncate3(entry.name, budget);
8675
8833
  budget -= name.length;
8676
8834
  const preview = rawPreview ? truncate3(rawPreview, budget) : "";
8677
- return /* @__PURE__ */ jsxs18(Box19, { flexDirection: "row", gap: ROW_GAP, children: [
8678
- /* @__PURE__ */ jsx18(Text20, { color: COLORS.dim, children: timestamp }),
8679
- /* @__PURE__ */ jsx18(Text20, { color: logNameColor(entry), wrap: "truncate", children: name }),
8680
- preview && /* @__PURE__ */ jsx18(Text20, { color: COLORS.dim, wrap: "truncate", children: preview }),
8681
- durationText && /* @__PURE__ */ jsx18(Text20, { color: COLORS.dim, children: durationText })
8835
+ return /* @__PURE__ */ jsxs19(Box20, { flexDirection: "row", gap: ROW_GAP, children: [
8836
+ /* @__PURE__ */ jsx19(Text21, { color: COLORS.success, children: selected ? SELECTED_MARKER : " " }),
8837
+ /* @__PURE__ */ jsx19(Text21, { color: COLORS.dim, children: timestamp }),
8838
+ /* @__PURE__ */ jsx19(Text21, { color: logNameColor(entry), wrap: "truncate", children: name }),
8839
+ preview && /* @__PURE__ */ jsx19(Text21, { color: COLORS.dim, wrap: "truncate", children: preview }),
8840
+ duration && /* @__PURE__ */ jsx19(Text21, { color: COLORS.dim, children: duration })
8682
8841
  ] }, entry.id);
8683
8842
  }) }),
8684
- /* @__PURE__ */ jsxs18(Text20, { children: [
8685
- /* @__PURE__ */ jsx18(Text20, { color: COLORS.primary, children: "[j] [k]" }),
8686
- /* @__PURE__ */ jsx18(Text20, { color: COLORS.dim, children: " scroll" })
8843
+ /* @__PURE__ */ jsxs19(Box20, { gap: 2, children: [
8844
+ /* @__PURE__ */ jsxs19(Text21, { children: [
8845
+ /* @__PURE__ */ jsx19(Text21, { color: COLORS.primary, children: "[j] [k]" }),
8846
+ /* @__PURE__ */ jsx19(Text21, { color: COLORS.dim, children: " select" })
8847
+ ] }),
8848
+ /* @__PURE__ */ jsxs19(Text21, { children: [
8849
+ /* @__PURE__ */ jsx19(Text21, { color: COLORS.primary, children: "[enter]" }),
8850
+ /* @__PURE__ */ jsx19(Text21, { color: COLORS.dim, children: " details" })
8851
+ ] }),
8852
+ /* @__PURE__ */ jsxs19(Text21, { children: [
8853
+ /* @__PURE__ */ jsx19(Text21, { color: COLORS.primary, children: "[esc]" }),
8854
+ /* @__PURE__ */ jsx19(Text21, { color: COLORS.dim, children: " back" })
8855
+ ] })
8687
8856
  ] })
8688
- ] });
8857
+ ] }) });
8689
8858
  }
8690
8859
 
8691
8860
  // src/ui/Tips.tsx
8692
- import { useEffect as useEffect3, useRef as useRef4, useState as useState11 } from "react";
8693
- import { Box as Box21, Text as Text22 } from "ink";
8861
+ import { useEffect as useEffect3, useRef as useRef4, useState as useState13 } from "react";
8862
+ import { Box as Box22, Text as Text23 } from "ink";
8694
8863
  import terminalLink from "terminal-link";
8695
8864
 
8696
8865
  // src/ui/Code.tsx
8697
- import { Box as Box20, Text as Text21 } from "ink";
8698
- import { jsx as jsx19 } from "react/jsx-runtime";
8866
+ import { Box as Box21, Text as Text22 } from "ink";
8867
+ import { jsx as jsx20 } from "react/jsx-runtime";
8699
8868
  var TOKEN_RE = /("(?:\\.|[^"\\])*"|\btrue\b|\bfalse\b|\bnull\b|-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|[{}[\]:,])/g;
8700
8869
  function highlightJson(json) {
8701
8870
  const parts = json.split(TOKEN_RE);
@@ -8704,22 +8873,22 @@ function highlightJson(json) {
8704
8873
  if (part[0] === '"') {
8705
8874
  const next = parts.slice(i + 1).find((p) => p.trim());
8706
8875
  const isKey = next?.trimStart().startsWith(":");
8707
- return /* @__PURE__ */ jsx19(Text21, { color: isKey ? "cyan" : "green", children: part }, i);
8876
+ return /* @__PURE__ */ jsx20(Text22, { color: isKey ? "cyan" : "green", children: part }, i);
8708
8877
  }
8709
8878
  if (part === "true" || part === "false" || part === "null") {
8710
- return /* @__PURE__ */ jsx19(Text21, { color: "magenta", children: part }, i);
8879
+ return /* @__PURE__ */ jsx20(Text22, { color: "magenta", children: part }, i);
8711
8880
  }
8712
8881
  if (/^-?\d/.test(part)) {
8713
- return /* @__PURE__ */ jsx19(Text21, { color: "yellow", children: part }, i);
8882
+ return /* @__PURE__ */ jsx20(Text22, { color: "yellow", children: part }, i);
8714
8883
  }
8715
8884
  if (/^[{}[\]:,]$/.test(part)) {
8716
- return /* @__PURE__ */ jsx19(Text21, { color: COLORS.dim, children: part }, i);
8885
+ return /* @__PURE__ */ jsx20(Text22, { color: COLORS.dim, children: part }, i);
8717
8886
  }
8718
- return /* @__PURE__ */ jsx19(Text21, { children: part }, i);
8887
+ return /* @__PURE__ */ jsx20(Text22, { children: part }, i);
8719
8888
  });
8720
8889
  }
8721
8890
  function Code({ children }) {
8722
- return /* @__PURE__ */ jsx19(Box20, { children: /* @__PURE__ */ jsx19(Text21, { children: highlightJson(children) }) });
8891
+ return /* @__PURE__ */ jsx20(Box21, { children: /* @__PURE__ */ jsx20(Text22, { children: highlightJson(children) }) });
8723
8892
  }
8724
8893
 
8725
8894
  // src/ui/copy/tips.ts
@@ -8915,26 +9084,26 @@ var tips = [
8915
9084
  ];
8916
9085
 
8917
9086
  // src/ui/Tips.tsx
8918
- import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
9087
+ import { jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
8919
9088
  var TICK_MS = 16;
8920
9089
  var CHUNK_HOLD_MS = 2e3;
8921
9090
  var TIP_DURATION_MS = 25e3;
8922
9091
  function TipTitle({ children }) {
8923
- return /* @__PURE__ */ jsxs19(Box21, { gap: 1, children: [
8924
- /* @__PURE__ */ jsx20(Text22, { color: "cyan", children: "\u2726" }),
8925
- /* @__PURE__ */ jsx20(Text22, { color: "white", bold: true, children })
9092
+ return /* @__PURE__ */ jsxs20(Box22, { gap: 1, children: [
9093
+ /* @__PURE__ */ jsx21(Text23, { color: "cyan", children: "\u2726" }),
9094
+ /* @__PURE__ */ jsx21(Text23, { color: "white", bold: true, children })
8926
9095
  ] });
8927
9096
  }
8928
9097
  function InlineSegment({ segment }) {
8929
9098
  switch (segment.type) {
8930
9099
  case "highlight":
8931
- return /* @__PURE__ */ jsx20(Text22, { color: COLORS.success, children: segment.value });
9100
+ return /* @__PURE__ */ jsx21(Text23, { color: COLORS.success, children: segment.value });
8932
9101
  case "link":
8933
- return /* @__PURE__ */ jsx20(Text22, { color: "cyan", underline: true, children: segment.href ? terminalLink(segment.value, segment.href) : segment.value });
9102
+ return /* @__PURE__ */ jsx21(Text23, { color: "cyan", underline: true, children: segment.href ? terminalLink(segment.value, segment.href) : segment.value });
8934
9103
  case "codeword":
8935
- return /* @__PURE__ */ jsx20(Text22, { color: COLORS.highlight.fg, backgroundColor: COLORS.highlight.bg, children: segment.value });
9104
+ return /* @__PURE__ */ jsx21(Text23, { color: COLORS.highlight.fg, backgroundColor: COLORS.highlight.bg, children: segment.value });
8936
9105
  default:
8937
- return /* @__PURE__ */ jsx20(Text22, { color: COLORS.muted, children: segment.value });
9106
+ return /* @__PURE__ */ jsx21(Text23, { color: COLORS.muted, children: segment.value });
8938
9107
  }
8939
9108
  }
8940
9109
  function TipContent({
@@ -8968,10 +9137,10 @@ function TipContent({
8968
9137
  blocks.push({ type: "inline", segments: [segment] });
8969
9138
  }
8970
9139
  }
8971
- return /* @__PURE__ */ jsx20(Box21, { flexDirection: "column", marginLeft: 2, gap: 1, children: blocks.map(
8972
- (block, i) => block.type === "code" ? /* @__PURE__ */ jsx20(Code, { children: block.segment.value }, i) : /* @__PURE__ */ jsx20(Text22, { children: block.segments.map((segment, j) => /* @__PURE__ */ jsxs19(Text22, { children: [
9140
+ return /* @__PURE__ */ jsx21(Box22, { flexDirection: "column", marginLeft: 2, gap: 1, children: blocks.map(
9141
+ (block, i) => block.type === "code" ? /* @__PURE__ */ jsx21(Code, { children: block.segment.value }, i) : /* @__PURE__ */ jsx21(Text23, { children: block.segments.map((segment, j) => /* @__PURE__ */ jsxs20(Text23, { children: [
8973
9142
  j > 0 && " ",
8974
- /* @__PURE__ */ jsx20(InlineSegment, { segment })
9143
+ /* @__PURE__ */ jsx21(InlineSegment, { segment })
8975
9144
  ] }, j)) }, i)
8976
9145
  ) });
8977
9146
  }
@@ -9001,7 +9170,7 @@ function Tips({
9001
9170
  onRevealStateChange,
9002
9171
  onComplete
9003
9172
  }) {
9004
- const [position, setPosition] = useState11(() => {
9173
+ const [position, setPosition] = useState13(() => {
9005
9174
  const now = Date.now();
9006
9175
  return {
9007
9176
  tipIndex: clock.tipIndex,
@@ -9061,9 +9230,9 @@ function Tips({
9061
9230
  if (position.complete) return null;
9062
9231
  const titleRevealed = tip.title.slice(0, revealed);
9063
9232
  const contentRevealed = Math.max(0, revealed - tip.title.length);
9064
- return /* @__PURE__ */ jsxs19(Box21, { flexDirection: "column", marginBottom: 1, gap: 1, children: [
9065
- /* @__PURE__ */ jsx20(TipTitle, { children: titleRevealed }),
9066
- /* @__PURE__ */ jsx20(TipContent, { chunks: tip.chunks, revealed: contentRevealed })
9233
+ return /* @__PURE__ */ jsxs20(Box22, { flexDirection: "column", marginBottom: 1, gap: 1, children: [
9234
+ /* @__PURE__ */ jsx21(TipTitle, { children: titleRevealed }),
9235
+ /* @__PURE__ */ jsx21(TipContent, { chunks: tip.chunks, revealed: contentRevealed })
9067
9236
  ] });
9068
9237
  }
9069
9238
 
@@ -9105,7 +9274,7 @@ function useRepaintOnResize(debounceMs = 100) {
9105
9274
  }
9106
9275
 
9107
9276
  // src/ui/App.tsx
9108
- import { jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
9277
+ import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
9109
9278
  function App() {
9110
9279
  const {
9111
9280
  phase,
@@ -9124,9 +9293,9 @@ function App() {
9124
9293
  const { columns, rows } = useWindowSize8();
9125
9294
  useRepaintOnResize();
9126
9295
  const compactRun = isCompactTerminal(columns, rows);
9127
- const [showLogs, setShowLogs] = useState12(false);
9128
- const [tipState, setTipState] = useState12("idle");
9129
- const [tipsComplete, setTipsComplete] = useState12(false);
9296
+ const [showLogs, setShowLogs] = useState14(false);
9297
+ const [tipState, setTipState] = useState14("idle");
9298
+ const [tipsComplete, setTipsComplete] = useState14(false);
9130
9299
  const finished = phase === "done" || phase === "error";
9131
9300
  const currentStep = steps[currentStepIndex];
9132
9301
  const workflowDef = workflow ? getWorkflow(workflow.id) : void 0;
@@ -9137,15 +9306,15 @@ function App() {
9137
9306
  const showTips = !compactRun && tipsActive && (phase === "running" && currentStep?.status === "running" && !loadingMessage && !settingUpAppId || holdForTip);
9138
9307
  const showNoticesInMain = !tipsActive;
9139
9308
  const showNotices = !compactRun && (!isAwaitingUserInput || holdForTip) && !review2;
9140
- useInput9(
9309
+ useInput10(
9141
9310
  (_input, key) => {
9142
9311
  if (key.return) {
9143
9312
  exit();
9144
9313
  }
9145
9314
  },
9146
- { isActive: finished }
9315
+ { isActive: finished && !showLogs }
9147
9316
  );
9148
- useInput9((_input, key) => {
9317
+ useInput10((_input, key) => {
9149
9318
  if (phase === "idle" || phase === "authenticating") return;
9150
9319
  if (key.tab) {
9151
9320
  setShowLogs(!showLogs);
@@ -9156,8 +9325,9 @@ function App() {
9156
9325
  });
9157
9326
  }
9158
9327
  });
9159
- const escOwnedElsewhere = phase === "idle" || phase === "authenticating" || phase === "awaitingInput" && !holdForTip && (inputReq?.promptType === "enterToContinue" || inputReq?.promptType === "commandApproval");
9160
- useInput9((_input, key) => {
9328
+ const escOwnedElsewhere = phase === "idle" || phase === "authenticating" || // The log view owns esc: it closes the details, then leaves the list.
9329
+ showLogs || phase === "awaitingInput" && !holdForTip && (inputReq?.promptType === "enterToContinue" || inputReq?.promptType === "commandApproval");
9330
+ useInput10((_input, key) => {
9161
9331
  if (escOwnedElsewhere) return;
9162
9332
  if (key.escape) {
9163
9333
  track("AI Wizard Interaction", {
@@ -9175,8 +9345,8 @@ function App() {
9175
9345
  /* Clamped to exactly the viewport: a taller frame makes Ink clear and repaint
9176
9346
  the whole screen, and the scrolling throws off its cursor arithmetic.
9177
9347
  Flicker and leftover rows. */
9178
- /* @__PURE__ */ jsxs20(
9179
- Box22,
9348
+ /* @__PURE__ */ jsxs21(
9349
+ Box23,
9180
9350
  {
9181
9351
  backgroundColor: COLORS.bg.main,
9182
9352
  flexDirection: "row",
@@ -9184,16 +9354,16 @@ function App() {
9184
9354
  height: rows,
9185
9355
  overflow: "hidden",
9186
9356
  children: [
9187
- mainWindowVisible && /* @__PURE__ */ jsxs20(
9188
- Box22,
9357
+ mainWindowVisible && /* @__PURE__ */ jsxs21(
9358
+ Box23,
9189
9359
  {
9190
9360
  flexDirection,
9191
9361
  width: "100%",
9192
9362
  maxHeight: rows,
9193
9363
  justifyContent: "space-between",
9194
9364
  children: [
9195
- showLogs ? /* @__PURE__ */ jsx21(Logs, {}) : /* @__PURE__ */ jsxs20(
9196
- Box22,
9365
+ showLogs ? /* @__PURE__ */ jsx22(Logs, { onBack: () => setShowLogs(false) }) : /* @__PURE__ */ jsxs21(
9366
+ Box23,
9197
9367
  {
9198
9368
  flexDirection: "column",
9199
9369
  paddingX: 4,
@@ -9202,58 +9372,58 @@ function App() {
9202
9372
  flexGrow: 1,
9203
9373
  gap: 1,
9204
9374
  children: [
9205
- /* @__PURE__ */ jsxs20(Box22, { flexGrow: 2, flexDirection: "column", children: [
9206
- phase === "preflight" && !user && /* @__PURE__ */ jsx21(Box22, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs20(Text23, { color: COLORS.strong, bold: true, children: [
9207
- /* @__PURE__ */ jsx21(Spinner3, { type: "dots" }),
9375
+ /* @__PURE__ */ jsxs21(Box23, { flexGrow: 2, flexDirection: "column", children: [
9376
+ phase === "preflight" && !user && /* @__PURE__ */ jsx22(Box23, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs21(Text24, { color: COLORS.strong, bold: true, children: [
9377
+ /* @__PURE__ */ jsx22(Spinner3, { type: "dots" }),
9208
9378
  " Signing in to Algolia"
9209
9379
  ] }) }),
9210
- phase === "preflight" && user && /* @__PURE__ */ jsx21(Box22, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs20(Text23, { color: COLORS.strong, bold: true, children: [
9211
- /* @__PURE__ */ jsx21(Spinner3, { type: "dots" }),
9380
+ phase === "preflight" && user && /* @__PURE__ */ jsx22(Box23, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs21(Text24, { color: COLORS.strong, bold: true, children: [
9381
+ /* @__PURE__ */ jsx22(Spinner3, { type: "dots" }),
9212
9382
  " Getting things ready"
9213
9383
  ] }) }),
9214
- phase === "authenticating" && /* @__PURE__ */ jsxs20(Box22, { flexDirection: "column", marginBottom: 1, children: [
9215
- /* @__PURE__ */ jsxs20(Text23, { color: COLORS.strong, bold: true, children: [
9216
- /* @__PURE__ */ jsx21(Spinner3, { type: "dots" }),
9384
+ phase === "authenticating" && /* @__PURE__ */ jsxs21(Box23, { flexDirection: "column", marginBottom: 1, children: [
9385
+ /* @__PURE__ */ jsxs21(Text24, { color: COLORS.strong, bold: true, children: [
9386
+ /* @__PURE__ */ jsx22(Spinner3, { type: "dots" }),
9217
9387
  " Signing in to Algolia"
9218
9388
  ] }),
9219
- /* @__PURE__ */ jsx21(Text23, { color: COLORS.muted, children: "A browser window will open \u2014 complete sign-in there." })
9389
+ /* @__PURE__ */ jsx22(Text24, { color: COLORS.muted, children: "A browser window will open \u2014 complete sign-in there." })
9220
9390
  ] }),
9221
- settingUpAppId && /* @__PURE__ */ jsx21(Box22, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs20(Text23, { color: COLORS.strong, bold: true, children: [
9222
- /* @__PURE__ */ jsx21(Spinner3, { type: "dots" }),
9391
+ settingUpAppId && /* @__PURE__ */ jsx22(Box23, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs21(Text24, { color: COLORS.strong, bold: true, children: [
9392
+ /* @__PURE__ */ jsx22(Spinner3, { type: "dots" }),
9223
9393
  " Setting up Wizard using app",
9224
9394
  " ",
9225
9395
  settingUpAppId
9226
9396
  ] }) }),
9227
- phase === "running" && !settingUpAppId && loadingMessage && /* @__PURE__ */ jsx21(Box22, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs20(Text23, { color: COLORS.strong, bold: true, children: [
9228
- /* @__PURE__ */ jsx21(Spinner3, { type: "dots" }),
9397
+ phase === "running" && !settingUpAppId && loadingMessage && /* @__PURE__ */ jsx22(Box23, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs21(Text24, { color: COLORS.strong, bold: true, children: [
9398
+ /* @__PURE__ */ jsx22(Spinner3, { type: "dots" }),
9229
9399
  " ",
9230
9400
  loadingMessage
9231
9401
  ] }) }),
9232
- /* @__PURE__ */ jsx21(CliOutput, {}),
9233
- showTips && /* @__PURE__ */ jsx21(
9402
+ /* @__PURE__ */ jsx22(CliOutput, {}),
9403
+ showTips && /* @__PURE__ */ jsx22(
9234
9404
  Tips,
9235
9405
  {
9236
9406
  onRevealStateChange: setTipState,
9237
9407
  onComplete: () => setTipsComplete(true)
9238
9408
  }
9239
9409
  ),
9240
- showNoticesInMain && showNotices && /* @__PURE__ */ jsx21(Notices, { border: false }),
9241
- /* @__PURE__ */ jsx21(Review, {}),
9242
- !showTips && /* @__PURE__ */ jsx21(PromptInput, {}),
9243
- phase === "error" && error && /* @__PURE__ */ jsx21(Box22, { marginTop: 1, children: /* @__PURE__ */ jsxs20(Text23, { color: COLORS.status.error, children: [
9410
+ showNoticesInMain && showNotices && /* @__PURE__ */ jsx22(Notices, { border: false }),
9411
+ /* @__PURE__ */ jsx22(Review, {}),
9412
+ !showTips && /* @__PURE__ */ jsx22(PromptInput, {}),
9413
+ phase === "error" && error && /* @__PURE__ */ jsx22(Box23, { marginTop: 1, children: /* @__PURE__ */ jsxs21(Text24, { color: COLORS.status.error, children: [
9244
9414
  "\u2716 ",
9245
9415
  error
9246
9416
  ] }) })
9247
9417
  ] }),
9248
- !showNoticesInMain && showNotices && /* @__PURE__ */ jsx21(Notices, {})
9418
+ !showNoticesInMain && showNotices && /* @__PURE__ */ jsx22(Notices, {})
9249
9419
  ]
9250
9420
  }
9251
9421
  ),
9252
- showSidebar ? /* @__PURE__ */ jsx21(Sidebar, {}) : /* @__PURE__ */ jsx21(Ribbon, {})
9422
+ showSidebar ? /* @__PURE__ */ jsx22(Sidebar, { inLogs: showLogs }) : /* @__PURE__ */ jsx22(Ribbon, {})
9253
9423
  ]
9254
9424
  }
9255
9425
  ),
9256
- phase === "idle" && (homeScreen === "learnMore" ? /* @__PURE__ */ jsx21(LearnMore, {}) : /* @__PURE__ */ jsx21(Welcome, {}))
9426
+ phase === "idle" && (homeScreen === "learnMore" ? /* @__PURE__ */ jsx22(LearnMore, {}) : /* @__PURE__ */ jsx22(Welcome, {}))
9257
9427
  ]
9258
9428
  }
9259
9429
  )
@@ -9492,7 +9662,7 @@ async function resetProjectState() {
9492
9662
  // package.json with { type: 'json' }
9493
9663
  var package_default2 = {
9494
9664
  name: "@algolia/wizard",
9495
- version: "0.86.0",
9665
+ version: "0.87.0",
9496
9666
  description: "Magically implement Algolia functionality in your codebase",
9497
9667
  type: "module",
9498
9668
  engines: {
@@ -9598,7 +9768,7 @@ async function checkVersion() {
9598
9768
  }
9599
9769
 
9600
9770
  // src/main.tsx
9601
- import { jsx as jsx22 } from "react/jsx-runtime";
9771
+ import { jsx as jsx23 } from "react/jsx-runtime";
9602
9772
  var FAILURE_EXIT_CODE = 1;
9603
9773
  async function exitProcessWithError(store, instance, message) {
9604
9774
  store.setError(message);
@@ -9661,7 +9831,7 @@ ${formatStepList(workflow)}`);
9661
9831
  async function run(opts) {
9662
9832
  const { workflow, skipResumePrompt } = opts;
9663
9833
  const store = useWizard.getState();
9664
- const instance = render(/* @__PURE__ */ jsx22(App, {}), { incrementalRendering: true });
9834
+ const instance = render(/* @__PURE__ */ jsx23(App, {}), { incrementalRendering: true });
9665
9835
  await store.waitForStart();
9666
9836
  store.syncSteps(
9667
9837
  workflow.steps.map((s) => ({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@algolia/wizard",
3
- "version": "0.86.0",
3
+ "version": "0.87.0",
4
4
  "description": "Magically implement Algolia functionality in your codebase",
5
5
  "type": "module",
6
6
  "engines": {