@algolia/wizard 0.41.0-rc.131.290 → 0.42.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 +202 -285
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -5,7 +5,7 @@ import { render } from "ink";
5
5
 
6
6
  // src/ui/App.tsx
7
7
  import { Box as Box20, Text as Text20, useApp, useInput as useInput7, useWindowSize as useWindowSize7 } from "ink";
8
- import Spinner3 from "ink-spinner";
8
+ import Spinner2 from "ink-spinner";
9
9
 
10
10
  // src/core/store.ts
11
11
  import { create } from "zustand";
@@ -259,14 +259,10 @@ var useWizard = create((set, get) => ({
259
259
  error: null,
260
260
  inputReq: null,
261
261
  _resolve: null,
262
- settingUpAppId: null,
263
- setSettingUpApp: (appId) => set({ settingUpAppId: appId }),
264
262
  // `endAuth` lands on 'preflight', not 'idle': sign-in happens after the
265
263
  // welcome screen, so going back would gate the run a second time.
266
264
  beginAuth: () => set({ phase: "authenticating", cliOutput: [] }),
267
- endAuth: () => set(
268
- (s) => s.phase === "authenticating" ? { phase: "preflight", cliOutput: [] } : {}
269
- ),
265
+ endAuth: () => set((s) => s.phase === "authenticating" ? { phase: "preflight" } : {}),
270
266
  confirmStart: () => set(
271
267
  (s) => s.phase === "idle" ? { phase: "preflight", homeScreen: "home" } : {}
272
268
  ),
@@ -413,8 +409,7 @@ var useWizard = create((set, get) => ({
413
409
  logs: [],
414
410
  error: null,
415
411
  inputReq: null,
416
- _resolve: null,
417
- settingUpAppId: null
412
+ _resolve: null
418
413
  });
419
414
  }
420
415
  }));
@@ -642,7 +637,6 @@ function Notices({
642
637
 
643
638
  // src/ui/PromptInput.tsx
644
639
  import { Box as Box9, Text as Text9 } from "ink";
645
- import Spinner from "ink-spinner";
646
640
  import TextInput from "ink-text-input";
647
641
  import { useState as useState6 } from "react";
648
642
 
@@ -663,27 +657,25 @@ function SelectRow({
663
657
  labelWidth,
664
658
  highlightBackground = true,
665
659
  usePadding = false,
666
- disabled = false,
667
660
  children
668
661
  }) {
669
- const active = highlighted && !disabled;
670
- const labelColor = disabled ? COLORS.dim : active ? highlightBackground ? COLORS.highlight.fg : COLORS.success : COLORS.primary;
662
+ const labelColor = highlighted ? highlightBackground ? COLORS.highlight.fg : COLORS.success : COLORS.primary;
671
663
  return /* @__PURE__ */ jsxs3(
672
664
  Box4,
673
665
  {
674
666
  width,
675
667
  paddingX: usePadding ? 1 : 0,
676
668
  paddingY: usePadding ? 1 : 0,
677
- backgroundColor: active && highlightBackground ? COLORS.highlight.bg : void 0,
669
+ backgroundColor: highlighted && highlightBackground ? COLORS.highlight.bg : void 0,
678
670
  children: [
679
671
  /* @__PURE__ */ jsx3(Box4, { width: labelWidth, children: /* @__PURE__ */ jsxs3(
680
672
  Text4,
681
673
  {
682
674
  color: labelColor,
683
- bold: active && !highlightBackground,
675
+ bold: highlighted && !highlightBackground,
684
676
  wrap: "truncate",
685
677
  children: [
686
- active ? "\u276F " : " ",
678
+ highlighted ? "\u276F " : " ",
687
679
  label
688
680
  ]
689
681
  }
@@ -883,14 +875,6 @@ var ARROW_WIDTH = 4;
883
875
  var COLUMN_GAP = 2;
884
876
  var BAR_PADDING = 2;
885
877
  var ROW_HEIGHT = 3;
886
- function nextSelectableIndex(start, dir, rowCount, isDisabled) {
887
- let i = start;
888
- for (let step = 0; step < rowCount; step++) {
889
- i = (i + dir + rowCount) % rowCount;
890
- if (!isDisabled(i)) return i;
891
- }
892
- return start;
893
- }
894
878
  function SelectPrompt({
895
879
  options,
896
880
  onSelect,
@@ -902,18 +886,15 @@ function SelectPrompt({
902
886
  multi,
903
887
  cancelable,
904
888
  secondary,
905
- disabled,
906
889
  defaultSelectedIndex = 0
907
890
  }) {
891
+ const [index, setIndex] = useState5(
892
+ () => defaultSelectedIndex > 0 && defaultSelectedIndex < options.length ? defaultSelectedIndex : 0
893
+ );
894
+ const [checked, setChecked] = useState5(() => /* @__PURE__ */ new Set());
908
895
  const hasCancel = Boolean(multi || cancelable);
909
896
  const rows = hasCancel ? [...options, "Cancel"] : options;
910
897
  const cancelIndex = hasCancel ? options.length : -1;
911
- const isDisabled = (i) => i !== cancelIndex && Boolean(disabled?.[i]);
912
- const [index, setIndex] = useState5(() => {
913
- const start = defaultSelectedIndex > 0 && defaultSelectedIndex < options.length ? defaultSelectedIndex : 0;
914
- return isDisabled(start) ? nextSelectableIndex(start, 1, rows.length, isDisabled) : start;
915
- });
916
- const [checked, setChecked] = useState5(() => /* @__PURE__ */ new Set());
917
898
  const hints = [];
918
899
  if (rows.length > 1) hints.push({ key: "[\u2191] [\u2193]", label: "move" });
919
900
  if (multi) hints.push({ key: "[space]", label: "select" });
@@ -953,15 +934,9 @@ function SelectPrompt({
953
934
  useInput2((input, key) => {
954
935
  if (rows.length === 0) return;
955
936
  if (key.upArrow || input === "k") {
956
- setIndex((i) => {
957
- const next = (i - 1 + rows.length) % rows.length;
958
- return isDisabled(next) ? i : next;
959
- });
937
+ setIndex((i) => (i - 1 + rows.length) % rows.length);
960
938
  } else if (key.downArrow || input === "j") {
961
- setIndex((i) => {
962
- const next = (i + 1) % rows.length;
963
- return isDisabled(next) ? i : next;
964
- });
939
+ setIndex((i) => (i + 1) % rows.length);
965
940
  } else if (multi && input === " " && index !== cancelIndex) {
966
941
  setChecked((prev) => {
967
942
  const next = new Set(prev);
@@ -972,7 +947,6 @@ function SelectPrompt({
972
947
  } else if (key.return) {
973
948
  if (index === cancelIndex) {
974
949
  onSelect(CANCEL);
975
- } else if (isDisabled(index)) {
976
950
  } else if (!multi) {
977
951
  onSelect(options[index]);
978
952
  } else if (checked.size > 0) {
@@ -997,12 +971,10 @@ function SelectPrompt({
997
971
  const bullet = multi && !isCancel ? checked.has(i) ? "\u25CF " : "\u25CB " : "";
998
972
  const sec = isCancel ? void 0 : secondary?.[i];
999
973
  const isText = sec?.kind === "text";
1000
- const rowDisabled = isDisabled(i);
1001
974
  return /* @__PURE__ */ jsxs7(
1002
975
  SelectRow,
1003
976
  {
1004
977
  highlighted,
1005
- disabled: rowDisabled,
1006
978
  width: isText ? "100%" : barWidth,
1007
979
  labelWidth: isText ? labelWidth : barLabelWidth,
1008
980
  label: `${bullet}${option}`,
@@ -1012,7 +984,7 @@ function SelectPrompt({
1012
984
  Text8,
1013
985
  {
1014
986
  wrap: "truncate",
1015
- color: rowDisabled ? COLORS.dim : highlighted ? COLORS.primary : COLORS.muted,
987
+ color: highlighted ? COLORS.primary : COLORS.muted,
1016
988
  children: sec.value
1017
989
  }
1018
990
  ) }),
@@ -1059,23 +1031,11 @@ function EnterToContinuePrompt({
1059
1031
  function PromptInput() {
1060
1032
  const { phase, inputReq, submitInput } = useWizard();
1061
1033
  const [draft, setDraft] = useState6("");
1062
- const [submittedReq, setSubmittedReq] = useState6(null);
1063
1034
  const promptKey = inputReq && `${inputReq.promptType}:${inputReq.prompt}`;
1064
- const submitting = inputReq != null && submittedReq === inputReq;
1065
1035
  if (phase === "done" || phase === "error") {
1066
1036
  return /* @__PURE__ */ jsx7(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text9, { color: "gray", dimColor: true, children: "Press Enter or Esc to exit" }) });
1067
1037
  }
1068
1038
  if (phase !== "awaitingInput" || !inputReq) return null;
1069
- if (submitting) {
1070
- return /* @__PURE__ */ jsx7(Box9, { flexGrow: 1, children: /* @__PURE__ */ jsxs8(Text9, { color: COLORS.strong, bold: true, children: [
1071
- /* @__PURE__ */ jsx7(Spinner, { type: "dots" }),
1072
- " Continuing\u2026"
1073
- ] }) });
1074
- }
1075
- const handleSubmit = (value) => {
1076
- setSubmittedReq(inputReq);
1077
- submitInput(value);
1078
- };
1079
1039
  if (inputReq.promptType === "multipleChoice") {
1080
1040
  return /* @__PURE__ */ jsx7(Box9, { flexGrow: 1, children: /* @__PURE__ */ jsx7(
1081
1041
  SelectPrompt,
@@ -1086,11 +1046,10 @@ function PromptInput() {
1086
1046
  table: inputReq.table,
1087
1047
  options: inputReq.options,
1088
1048
  secondary: inputReq.secondary,
1089
- disabled: inputReq.disabled,
1090
1049
  defaultSelectedIndex: inputReq.defaultSelectedIndex,
1091
1050
  cancelable: inputReq.cancelable,
1092
1051
  error: inputReq.error,
1093
- onSelect: handleSubmit
1052
+ onSelect: submitInput
1094
1053
  },
1095
1054
  promptKey
1096
1055
  ) });
@@ -1106,7 +1065,7 @@ function PromptInput() {
1106
1065
  table: inputReq.table,
1107
1066
  options: inputReq.options,
1108
1067
  error: inputReq.error,
1109
- onSelect: handleSubmit
1068
+ onSelect: submitInput
1110
1069
  },
1111
1070
  promptKey
1112
1071
  ) });
@@ -1118,7 +1077,7 @@ function PromptInput() {
1118
1077
  question: inputReq.prompt,
1119
1078
  messages: inputReq.messages,
1120
1079
  options: ["Continue"],
1121
- onSelect: handleSubmit
1080
+ onSelect: submitInput
1122
1081
  },
1123
1082
  promptKey
1124
1083
  ) });
@@ -1145,7 +1104,7 @@ function PromptInput() {
1145
1104
  messages: inputReq.messages,
1146
1105
  options: labels,
1147
1106
  secondary: inputReq.secondary,
1148
- onSelect: (value) => handleSubmit(value === labels[0])
1107
+ onSelect: (value) => submitInput(value === labels[0])
1149
1108
  },
1150
1109
  promptKey
1151
1110
  ) });
@@ -1605,10 +1564,6 @@ function reconcileWorkflowState(state, workflow) {
1605
1564
  }
1606
1565
  return state;
1607
1566
  }
1608
- async function loadResumableState(workflow) {
1609
- const persisted = await loadWorkflowState(workflow.id);
1610
- return persisted ? reconcileWorkflowState(persisted, workflow) : null;
1611
- }
1612
1567
  function initWorkflowState(workflow, now) {
1613
1568
  return {
1614
1569
  workflowId: workflow.id,
@@ -1711,11 +1666,11 @@ async function runStep(state, index, step, appId) {
1711
1666
  durationMs: Date.now() - startedAt
1712
1667
  });
1713
1668
  }
1714
- async function runWorkflow(workflow, appId, resumableState) {
1669
+ async function runWorkflow(workflow, appId) {
1715
1670
  const store = useWizard.getState();
1716
1671
  try {
1717
- const resolved2 = resumableState !== void 0 ? resumableState : await loadResumableState(workflow);
1718
- const state = resolved2 ?? initWorkflowState(workflow, nowIso());
1672
+ const persisted = await loadWorkflowState(workflow.id);
1673
+ const state = (persisted && reconcileWorkflowState(persisted, workflow)) ?? initWorkflowState(workflow, nowIso());
1719
1674
  ensureExecutedStepCount(state);
1720
1675
  store.startWorkflow(
1721
1676
  {
@@ -1807,89 +1762,14 @@ async function listIndices() {
1807
1762
  return items.map((i) => ({ name: i.name, entries: i.entries })).sort((a, b) => a.name.localeCompare(b.name));
1808
1763
  }
1809
1764
 
1810
- // src/lib/algoliaApp.ts
1811
- import { z as z5 } from "zod";
1812
- var applicationSchema = z5.object({
1813
- id: z5.string().min(1),
1814
- name: z5.string().default(""),
1815
- plan: z5.string().optional()
1816
- });
1817
- var listSchema = z5.array(
1818
- z5.object({
1819
- id: z5.string().min(1),
1820
- name: z5.string().default(""),
1821
- plan_label: z5.string().optional(),
1822
- status: z5.string().optional(),
1823
- acl: z5.array(z5.string()).optional()
1824
- }).transform(({ id, name, plan_label, status, acl }) => ({
1825
- id,
1826
- name,
1827
- plan: plan_label,
1828
- status,
1829
- acl
1830
- }))
1831
- );
1832
- function canSelectApplication(app) {
1833
- return app.status === "active" && (app.acl ?? []).includes("keys");
1834
- }
1835
- async function currentApplication() {
1836
- let raw;
1837
- try {
1838
- raw = await runAlgoliaCli(["application", "current", "-o", "json"]);
1839
- } catch {
1840
- return null;
1841
- }
1842
- const parsed = applicationSchema.safeParse(parseJson(raw));
1843
- return parsed.success ? parsed.data : null;
1844
- }
1845
- async function requireApplication() {
1846
- const app = await currentApplication();
1847
- if (!app) {
1848
- throw new Error(
1849
- "No Algolia application is selected. Run `npx @algolia/cli@latest application select` and restart the wizard."
1850
- );
1851
- }
1852
- return app;
1853
- }
1854
- async function listApplications() {
1855
- const raw = await runAlgoliaCli(["application", "list", "-o", "json"]);
1856
- const parsed = listSchema.safeParse(parseJson(raw));
1857
- if (!parsed.success) {
1858
- throw new Error("Could not read the list of Algolia applications.");
1859
- }
1860
- return parsed.data;
1861
- }
1862
- async function selectApplication(id) {
1863
- const raw = await runAlgoliaCli(
1864
- ["application", "select", "--non-interactive", "--app-id", id],
1865
- { onOutput: stderrSink }
1866
- );
1867
- const parsed = applicationSchema.safeParse(parseJson(raw));
1868
- if (!parsed.success) {
1869
- throw new Error(
1870
- `Selected application ${id}, but the Algolia CLI returned an unreadable result.`
1871
- );
1872
- }
1873
- return parsed.data;
1874
- }
1875
- function parseJson(text) {
1876
- try {
1877
- return JSON.parse(text);
1878
- } catch {
1879
- return void 0;
1880
- }
1881
- }
1882
-
1883
1765
  // src/actions/selectIndex.ts
1884
1766
  var CREATE_NEW_INDEX = "Create a new index\u2026";
1885
1767
  var selectIndexStep = async (ctx) => {
1886
- await requireApplication();
1887
1768
  const indices = await listIndices();
1888
1769
  const names = indices.map((i) => i.name);
1889
1770
  const hasIndices = names.length > 0;
1890
1771
  let error;
1891
- let chosen;
1892
- while (chosen === void 0) {
1772
+ for (; ; ) {
1893
1773
  const selection = hasIndices ? await ctx.requestUserInput({
1894
1774
  prompt: "Which index do you want to ingest into?",
1895
1775
  promptType: "multipleChoice",
@@ -1908,9 +1788,9 @@ var selectIndexStep = async (ctx) => {
1908
1788
  if (typeof selection !== "string") {
1909
1789
  throw new Error("selectIndex received an unexpected non-text result");
1910
1790
  }
1911
- let candidate;
1791
+ let chosen;
1912
1792
  if (!hasIndices) {
1913
- candidate = selection.trim();
1793
+ chosen = selection.trim();
1914
1794
  } else if (selection === CREATE_NEW_INDEX) {
1915
1795
  const name = await ctx.requestUserInput({
1916
1796
  prompt: "Name the new index:",
@@ -1920,18 +1800,17 @@ var selectIndexStep = async (ctx) => {
1920
1800
  if (typeof name !== "string") {
1921
1801
  throw new Error("selectIndex received an unexpected non-text result");
1922
1802
  }
1923
- candidate = name.trim();
1803
+ chosen = name.trim();
1924
1804
  } else {
1925
- candidate = selection;
1805
+ chosen = selection;
1926
1806
  }
1927
- if (!candidate) {
1807
+ if (!chosen) {
1928
1808
  error = "Index name cannot be empty.";
1929
1809
  continue;
1930
1810
  }
1931
- chosen = candidate;
1811
+ ctx.setUserInput("index", chosen);
1812
+ return { selection: chosen };
1932
1813
  }
1933
- ctx.setUserInput("index", chosen);
1934
- return { selection: chosen };
1935
1814
  };
1936
1815
 
1937
1816
  // src/lib/agent.ts
@@ -1950,7 +1829,7 @@ import "zod";
1950
1829
 
1951
1830
  // src/lib/tools/listFiles.ts
1952
1831
  import { tool } from "ai";
1953
- import z6 from "zod";
1832
+ import z5 from "zod";
1954
1833
  import { readdir } from "node:fs/promises";
1955
1834
 
1956
1835
  // src/lib/tools/path.ts
@@ -1986,8 +1865,8 @@ async function hasSymlinkParent(ctx, target) {
1986
1865
  function listFilesTool(ctx) {
1987
1866
  return tool({
1988
1867
  description: 'List files in a directory (default: the current working directory). Pass path to list a subdirectory directly \u2014 e.g. "packages/api" \u2014 without first changeDirectory-ing into it.',
1989
- inputSchema: z6.object({
1990
- path: z6.string().optional().describe("Directory to list, relative to cwd (default: cwd)")
1868
+ inputSchema: z5.object({
1869
+ path: z5.string().optional().describe("Directory to list, relative to cwd (default: cwd)")
1991
1870
  }),
1992
1871
  execute: async ({ path = "." }) => {
1993
1872
  logger.info({ path }, "called listFiles tool");
@@ -2008,13 +1887,13 @@ function listFilesTool(ctx) {
2008
1887
 
2009
1888
  // src/lib/tools/changeDirectory.ts
2010
1889
  import { tool as tool2 } from "ai";
2011
- import z7 from "zod";
1890
+ import z6 from "zod";
2012
1891
  import { stat } from "node:fs/promises";
2013
1892
  function changeDirectoryTool(ctx) {
2014
1893
  return tool2({
2015
1894
  description: "Change the current working directory. Subsequent file operations resolve relative to it. Returns the new working directory.",
2016
- inputSchema: z7.object({
2017
- path: z7.string().describe("Directory to change into")
1895
+ inputSchema: z6.object({
1896
+ path: z6.string().describe("Directory to change into")
2018
1897
  }),
2019
1898
  execute: async ({ path }) => {
2020
1899
  logger.info({ path }, "called changeDirectory tool");
@@ -2036,13 +1915,13 @@ function changeDirectoryTool(ctx) {
2036
1915
 
2037
1916
  // src/lib/tools/reportStatus.ts
2038
1917
  import { tool as tool3 } from "ai";
2039
- import z8 from "zod";
1918
+ import z7 from "zod";
2040
1919
  function reportStatusTool(output) {
2041
1920
  return tool3({
2042
1921
  description: "Report the status of your execution. Return a reason in case of failure.",
2043
- inputSchema: z8.object({
2044
- status: z8.enum(["success", "fail"]),
2045
- reason: z8.string().optional(),
1922
+ inputSchema: z7.object({
1923
+ status: z7.enum(["success", "fail"]),
1924
+ reason: z7.string().optional(),
2046
1925
  output
2047
1926
  }),
2048
1927
  execute: async ({ status, reason, output: output2 }) => {
@@ -2054,7 +1933,7 @@ function reportStatusTool(output) {
2054
1933
 
2055
1934
  // src/lib/tools/readFile.ts
2056
1935
  import { tool as tool4 } from "ai";
2057
- import z9 from "zod";
1936
+ import z8 from "zod";
2058
1937
  import { readFile as readFile3 } from "node:fs/promises";
2059
1938
 
2060
1939
  // src/lib/tools/env.ts
@@ -2082,8 +1961,8 @@ function redactEnvValues(content) {
2082
1961
  function readFileTool(ctx) {
2083
1962
  return tool4({
2084
1963
  description: "Read the contents of a file at the given path",
2085
- inputSchema: z9.object({
2086
- filePath: z9.string().describe("Path to the file to read")
1964
+ inputSchema: z8.object({
1965
+ filePath: z8.string().describe("Path to the file to read")
2087
1966
  }),
2088
1967
  execute: async ({ filePath }) => {
2089
1968
  if (++ctx.counts.read > ctx.limits.read) {
@@ -2104,15 +1983,15 @@ function readFileTool(ctx) {
2104
1983
 
2105
1984
  // src/lib/tools/writeFile.ts
2106
1985
  import { tool as tool5 } from "ai";
2107
- import z10 from "zod";
1986
+ import z9 from "zod";
2108
1987
  import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
2109
1988
  import { dirname as dirname3 } from "node:path";
2110
1989
  function writeFileTool(ctx) {
2111
1990
  return tool5({
2112
1991
  description: "Write content to a file at the given path, overwriting it. Writes to secret env files (.env, .env.local, etc.) are refused by this tool \u2014 call it anyway and the tool will tell you how to proceed.",
2113
- inputSchema: z10.object({
2114
- filePath: z10.string().describe("Path to the file to write"),
2115
- content: z10.string().describe("Content to write to the file")
1992
+ inputSchema: z9.object({
1993
+ filePath: z9.string().describe("Path to the file to write"),
1994
+ content: z9.string().describe("Content to write to the file")
2116
1995
  }),
2117
1996
  execute: async ({ filePath, content }) => {
2118
1997
  logger.info({ filePath }, "called writeFile tool");
@@ -2142,6 +2021,68 @@ import z13 from "zod";
2142
2021
  import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile5 } from "node:fs/promises";
2143
2022
  import { dirname as dirname4, relative as relative3 } from "node:path";
2144
2023
 
2024
+ // src/lib/algoliaApp.ts
2025
+ import { z as z10 } from "zod";
2026
+ var applicationSchema = z10.object({
2027
+ id: z10.string().min(1),
2028
+ name: z10.string().default(""),
2029
+ plan: z10.string().optional()
2030
+ });
2031
+ var listSchema = z10.array(
2032
+ z10.object({
2033
+ id: z10.string().min(1),
2034
+ name: z10.string().default(""),
2035
+ plan_label: z10.string().optional()
2036
+ }).transform(({ id, name, plan_label }) => ({ id, name, plan: plan_label }))
2037
+ );
2038
+ async function currentApplication() {
2039
+ let raw;
2040
+ try {
2041
+ raw = await runAlgoliaCli(["application", "current", "-o", "json"]);
2042
+ } catch {
2043
+ return null;
2044
+ }
2045
+ const parsed = applicationSchema.safeParse(parseJson(raw));
2046
+ return parsed.success ? parsed.data : null;
2047
+ }
2048
+ async function requireApplication() {
2049
+ const app = await currentApplication();
2050
+ if (!app) {
2051
+ throw new Error(
2052
+ "No Algolia application is selected. Run `npx @algolia/cli@latest application select` and restart the wizard."
2053
+ );
2054
+ }
2055
+ return app;
2056
+ }
2057
+ async function listApplications() {
2058
+ const raw = await runAlgoliaCli(["application", "list", "-o", "json"]);
2059
+ const parsed = listSchema.safeParse(parseJson(raw));
2060
+ if (!parsed.success) {
2061
+ throw new Error("Could not read the list of Algolia applications.");
2062
+ }
2063
+ return parsed.data;
2064
+ }
2065
+ async function selectApplication(id) {
2066
+ const raw = await runAlgoliaCli(
2067
+ ["application", "select", "--non-interactive", "--app-id", id],
2068
+ { onOutput: stderrSink }
2069
+ );
2070
+ const parsed = applicationSchema.safeParse(parseJson(raw));
2071
+ if (!parsed.success) {
2072
+ throw new Error(
2073
+ `Selected application ${id}, but the Algolia CLI returned an unreadable result.`
2074
+ );
2075
+ }
2076
+ return parsed.data;
2077
+ }
2078
+ function parseJson(text) {
2079
+ try {
2080
+ return JSON.parse(text);
2081
+ } catch {
2082
+ return void 0;
2083
+ }
2084
+ }
2085
+
2145
2086
  // src/lib/algoliaApiKey.ts
2146
2087
  import { z as z12 } from "zod";
2147
2088
 
@@ -2149,13 +2090,13 @@ import { z as z12 } from "zod";
2149
2090
  import { deletePassword, getPassword, setPassword } from "cross-keychain";
2150
2091
  import { z as z11 } from "zod";
2151
2092
  var SERVICE = "algolia-wizard";
2152
- var account = (userId) => `api-keys:${userId}`;
2093
+ var ACCOUNT = "api-keys";
2153
2094
  var storedKeysSchema = z11.record(z11.string(), z11.string());
2154
2095
  function entryId(kind, index, appId) {
2155
2096
  return `${kind}:${appId}:${index}`;
2156
2097
  }
2157
- async function loadKeys(userId) {
2158
- const raw = await getPassword(SERVICE, account(userId));
2098
+ async function loadKeys() {
2099
+ const raw = await getPassword(SERVICE, ACCOUNT);
2159
2100
  if (!raw) return {};
2160
2101
  let payload;
2161
2102
  try {
@@ -2177,47 +2118,47 @@ function serialized(op) {
2177
2118
  });
2178
2119
  return next;
2179
2120
  }
2180
- async function readStoredKey(kind, userId, index, appId) {
2121
+ async function readStoredKey(kind, index, appId) {
2181
2122
  try {
2182
- return (await loadKeys(userId))[entryId(kind, index, appId)] ?? null;
2123
+ return (await loadKeys())[entryId(kind, index, appId)] ?? null;
2183
2124
  } catch (err) {
2184
2125
  logger.warn(
2185
- { err: err.message, kind, index, appId, userId },
2126
+ { err: err.message, kind, index, appId },
2186
2127
  "could not read the API key from the keychain"
2187
2128
  );
2188
2129
  return null;
2189
2130
  }
2190
2131
  }
2191
- function storeKey(kind, userId, index, appId, value) {
2132
+ function storeKey(kind, index, appId, value) {
2192
2133
  return serialized(async () => {
2193
2134
  const id = entryId(kind, index, appId);
2194
2135
  try {
2195
- const keys = await loadKeys(userId);
2136
+ const keys = await loadKeys();
2196
2137
  await setPassword(
2197
2138
  SERVICE,
2198
- account(userId),
2139
+ ACCOUNT,
2199
2140
  JSON.stringify({ ...keys, [id]: value })
2200
2141
  );
2201
- if ((await loadKeys(userId))[id] !== value) {
2142
+ if ((await loadKeys())[id] !== value) {
2202
2143
  throw new Error("the keychain did not store the value");
2203
2144
  }
2204
2145
  } catch (err) {
2205
2146
  logger.warn(
2206
- { err: err.message, kind, index, appId, userId },
2147
+ { err: err.message, kind, index, appId },
2207
2148
  "could not store the API key in the keychain; the next run will create another"
2208
2149
  );
2209
2150
  }
2210
2151
  });
2211
2152
  }
2212
- function deleteStoredKeys(userId) {
2153
+ function deleteStoredKeys() {
2213
2154
  return serialized(async () => {
2214
2155
  try {
2215
- await deletePassword(SERVICE, account(userId));
2156
+ await deletePassword(SERVICE, ACCOUNT);
2216
2157
  } catch (err) {
2217
2158
  const message = err.message;
2218
2159
  if (/not found/i.test(message)) return;
2219
2160
  logger.warn(
2220
- { err: message, userId },
2161
+ { err: message },
2221
2162
  "could not delete the API keys from the keychain"
2222
2163
  );
2223
2164
  }
@@ -2225,16 +2166,6 @@ function deleteStoredKeys(userId) {
2225
2166
  }
2226
2167
 
2227
2168
  // src/lib/algoliaApiKey.ts
2228
- function requireUserId() {
2229
- const userId = useWizard.getState().user?.userId;
2230
- if (!userId) {
2231
- throw new Error("No Algolia user is signed in; cannot scope the API key.");
2232
- }
2233
- return userId;
2234
- }
2235
- async function currentUserId() {
2236
- return useWizard.getState().user?.userId ?? (await getUser())?.userId ?? null;
2237
- }
2238
2169
  var WRITE_ACLS = [
2239
2170
  "addObject",
2240
2171
  "deleteObject",
@@ -2281,30 +2212,23 @@ async function keyExists(key) {
2281
2212
  var resolved = /* @__PURE__ */ new Map();
2282
2213
  async function forgetResolvedKeys() {
2283
2214
  resolved.clear();
2284
- const userId = await currentUserId();
2285
- if (userId) await deleteStoredKeys(userId);
2215
+ await deleteStoredKeys();
2286
2216
  }
2287
2217
  function resolveKey(kind, index, appId, acls, description) {
2288
- const userId = requireUserId();
2289
- const cacheKey = `${userId}:${kind}:${appId}:${index}`;
2218
+ const cacheKey = `${kind}:${appId}:${index}`;
2290
2219
  const cached = resolved.get(cacheKey);
2291
2220
  if (cached) return cached;
2292
- const pending = provisionKey(
2293
- kind,
2294
- userId,
2295
- index,
2296
- appId,
2297
- acls,
2298
- description
2299
- ).catch((err) => {
2300
- resolved.delete(cacheKey);
2301
- throw err;
2302
- });
2221
+ const pending = provisionKey(kind, index, appId, acls, description).catch(
2222
+ (err) => {
2223
+ resolved.delete(cacheKey);
2224
+ throw err;
2225
+ }
2226
+ );
2303
2227
  resolved.set(cacheKey, pending);
2304
2228
  return pending;
2305
2229
  }
2306
- async function provisionKey(kind, userId, index, appId, acls, description) {
2307
- const stored = await readStoredKey(kind, userId, index, appId);
2230
+ async function provisionKey(kind, index, appId, acls, description) {
2231
+ const stored = await readStoredKey(kind, index, appId);
2308
2232
  if (stored) {
2309
2233
  if (await keyExists(stored)) {
2310
2234
  logger.info({ kind, index, appId }, "reusing the stored API key");
@@ -2316,7 +2240,7 @@ async function provisionKey(kind, userId, index, appId, acls, description) {
2316
2240
  );
2317
2241
  }
2318
2242
  const key = await createKey(index, acls, description);
2319
- await storeKey(kind, userId, index, appId, key);
2243
+ await storeKey(kind, index, appId, key);
2320
2244
  return { key, source: "created" };
2321
2245
  }
2322
2246
  function resolveWriteKey(index, appId) {
@@ -3548,7 +3472,7 @@ async function runAnalysis(mode, extraInstructions = []) {
3548
3472
  // package.json
3549
3473
  var package_default = {
3550
3474
  name: "@algolia/wizard",
3551
- version: "0.41.0-rc.131.290",
3475
+ version: "0.42.0",
3552
3476
  description: "Magically implement Algolia functionality in your codebase",
3553
3477
  type: "module",
3554
3478
  engines: {
@@ -4419,10 +4343,6 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
4419
4343
  if (useCases.includes("ingestion")) {
4420
4344
  ingestAppId = appId ?? (await requireApplication()).id;
4421
4345
  }
4422
- let ingestWriteKey;
4423
- if (useCases.includes("ingestion") && ingestAppId) {
4424
- ingestWriteKey = (await resolveWriteKey(targetIndex, ingestAppId)).key;
4425
- }
4426
4346
  let uploadFilePath;
4427
4347
  let uploadWarning;
4428
4348
  if (ingestionSource === "fileUpload") {
@@ -4485,9 +4405,9 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
4485
4405
  let ingestDurationMs;
4486
4406
  let ingestOutcomeMessage;
4487
4407
  const ingestKeyAppId = ingestAppId;
4488
- const ingestionTools = ingestKeyAppId && ingestWriteKey ? makeToolContext(repoRoot, async () => ({
4408
+ const ingestionTools = ingestKeyAppId ? makeToolContext(repoRoot, async () => ({
4489
4409
  [APP_ID_VAR]: ingestKeyAppId,
4490
- [API_KEY_VAR]: ingestWriteKey,
4410
+ [API_KEY_VAR]: (await resolveWriteKey(targetIndex, ingestKeyAppId)).key,
4491
4411
  [INDEX_NAME_VAR]: targetIndex
4492
4412
  })) : void 0;
4493
4413
  const searchTools = makeToolContext(repoRoot);
@@ -5082,13 +5002,13 @@ import { Box as Box15, Text as Text15 } from "ink";
5082
5002
 
5083
5003
  // src/ui/Steps.tsx
5084
5004
  import { Box as Box13, Text as Text13 } from "ink";
5085
- import Spinner2 from "ink-spinner";
5005
+ import Spinner from "ink-spinner";
5086
5006
  import { jsx as jsx11, jsxs as jsxs12 } from "react/jsx-runtime";
5087
5007
  function Steps() {
5088
5008
  const { steps } = useWizard();
5089
5009
  const visibleSteps = steps.filter(isStepVisible);
5090
5010
  return /* @__PURE__ */ jsx11(Box13, { flexDirection: "column", gap: 1, children: visibleSteps.map((s) => /* @__PURE__ */ jsx11(Box13, { flexDirection: "column", children: /* @__PURE__ */ jsxs12(Text13, { color: COLORS.status[s.status], children: [
5091
- s.status === "running" ? /* @__PURE__ */ jsx11(Spinner2, { type: "dots" }) : MARKER[s.status],
5011
+ s.status === "running" ? /* @__PURE__ */ jsx11(Spinner, { type: "dots" }) : MARKER[s.status],
5092
5012
  " ",
5093
5013
  s.title
5094
5014
  ] }) }, s.id)) });
@@ -5098,7 +5018,7 @@ function CurrentStep() {
5098
5018
  const currentStep = steps.filter(isStepVisible).find((s) => s.status === "running");
5099
5019
  if (!currentStep) return null;
5100
5020
  return /* @__PURE__ */ jsxs12(Text13, { color: COLORS.status.running, children: [
5101
- /* @__PURE__ */ jsx11(Spinner2, { type: "dots" }),
5021
+ /* @__PURE__ */ jsx11(Spinner, { type: "dots" }),
5102
5022
  " ",
5103
5023
  ` ${currentStep.title}`
5104
5024
  ] });
@@ -5643,7 +5563,6 @@ function App() {
5643
5563
  inputReq,
5644
5564
  user,
5645
5565
  workflow,
5646
- settingUpAppId,
5647
5566
  review: review2
5648
5567
  } = useWizard();
5649
5568
  const { exit } = useApp();
@@ -5659,7 +5578,7 @@ function App() {
5659
5578
  const isCommandApprovalPrompt = isAwaitingUserInput && inputReq?.promptType === "commandApproval";
5660
5579
  const promptPending = isAwaitingUserInput && !isCommandApprovalPrompt;
5661
5580
  const holdForTip = stepHasTips && promptPending && tipState === "revealing";
5662
- const showTips = stepHasTips && (phase === "running" && currentStep?.status === "running" || isCommandApprovalPrompt || holdForTip);
5581
+ const showTips = stepHasTips && (phase === "running" || isCommandApprovalPrompt || holdForTip);
5663
5582
  const showNoticesInMain = !stepHasTips;
5664
5583
  const showNotices = (!isAwaitingUserInput || holdForTip) && !review2;
5665
5584
  useInput7(
@@ -5730,26 +5649,20 @@ function App() {
5730
5649
  children: [
5731
5650
  /* @__PURE__ */ jsxs18(Box20, { flexGrow: 2, flexDirection: "column", children: [
5732
5651
  phase === "preflight" && !user && /* @__PURE__ */ jsx18(Box20, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs18(Text20, { color: COLORS.strong, bold: true, children: [
5733
- /* @__PURE__ */ jsx18(Spinner3, { type: "dots" }),
5652
+ /* @__PURE__ */ jsx18(Spinner2, { type: "dots" }),
5734
5653
  " Signing in to Algolia"
5735
5654
  ] }) }),
5736
5655
  phase === "preflight" && user && /* @__PURE__ */ jsx18(Box20, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs18(Text20, { color: COLORS.strong, bold: true, children: [
5737
- /* @__PURE__ */ jsx18(Spinner3, { type: "dots" }),
5656
+ /* @__PURE__ */ jsx18(Spinner2, { type: "dots" }),
5738
5657
  " Getting things ready"
5739
5658
  ] }) }),
5740
5659
  phase === "authenticating" && /* @__PURE__ */ jsxs18(Box20, { flexDirection: "column", marginBottom: 1, children: [
5741
5660
  /* @__PURE__ */ jsxs18(Text20, { color: COLORS.strong, bold: true, children: [
5742
- /* @__PURE__ */ jsx18(Spinner3, { type: "dots" }),
5661
+ /* @__PURE__ */ jsx18(Spinner2, { type: "dots" }),
5743
5662
  " Signing in to Algolia"
5744
5663
  ] }),
5745
5664
  /* @__PURE__ */ jsx18(Text20, { color: COLORS.muted, children: "A browser window will open \u2014 complete sign-in there." })
5746
5665
  ] }),
5747
- settingUpAppId && /* @__PURE__ */ jsx18(Box20, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs18(Text20, { color: COLORS.strong, bold: true, children: [
5748
- /* @__PURE__ */ jsx18(Spinner3, { type: "dots" }),
5749
- " Setting up Wizard using app",
5750
- " ",
5751
- settingUpAppId
5752
- ] }) }),
5753
5666
  /* @__PURE__ */ jsx18(CliOutput, {}),
5754
5667
  showTips && currentStep && /* @__PURE__ */ jsx18(
5755
5668
  Tips,
@@ -5820,72 +5733,50 @@ function readValue(raw) {
5820
5733
  }
5821
5734
 
5822
5735
  // src/lib/algoliaAppPicker.ts
5823
- function blockReasonFor(app) {
5824
- return app.status !== "active" ? "Paused" : "Missing permissions";
5825
- }
5826
- function secondaryFor(app, highlightId) {
5827
- if (!canSelectApplication(app)) {
5828
- return { kind: "text", value: blockReasonFor(app) };
5829
- }
5830
- if (app.id === highlightId) {
5831
- return { kind: "badge", value: "[DETECTED]" };
5832
- }
5736
+ function secondaryFor(app) {
5833
5737
  return app.plan ? { kind: "badge", value: app.plan } : void 0;
5834
5738
  }
5835
5739
  function labelFor(app) {
5836
5740
  return app.name.trim() ? `${app.name} \u2014 ${app.id}` : app.id;
5837
5741
  }
5838
- async function isEligible(app) {
5839
- const apps = await listApplications();
5840
- const full = apps.find((candidate) => candidate.id === app.id);
5841
- return full != null && canSelectApplication(full);
5842
- }
5843
- async function selectAndReport(app) {
5844
- const store = useWizard.getState();
5845
- store.setSettingUpApp(app.id);
5846
- try {
5847
- return await selectApplication(app.id);
5848
- } finally {
5849
- store.setSettingUpApp(null);
5850
- }
5742
+ function selectAndReport(app) {
5743
+ useWizard.getState().pushCliOutput(
5744
+ "stdout",
5745
+ `Selecting ${labelFor(app)} \u2014 provisioning its API key\u2026`
5746
+ );
5747
+ return selectApplication(app.id);
5851
5748
  }
5852
- async function promptForApplication(highlight) {
5749
+ async function promptForApplication(leadIn = []) {
5853
5750
  const store = useWizard.getState();
5854
- const unordered = await listApplications();
5855
- if (unordered.length === 0) {
5751
+ const apps = await listApplications();
5752
+ if (apps.length === 0) {
5856
5753
  throw new Error(
5857
5754
  "This Algolia account has no applications. Create one in the Algolia dashboard, or with `npx @algolia/cli@latest application create`, then restart the wizard."
5858
5755
  );
5859
5756
  }
5860
- if (!unordered.some(canSelectApplication)) {
5861
- throw new Error(
5862
- "None of the applications on this Algolia account are usable \u2014 each is either paused or missing key-management access. Activate one, or grant it the `keys` ACL, then restart the wizard."
5757
+ if (apps.length === 1) {
5758
+ const only = apps[0];
5759
+ logger.info(
5760
+ { app: only.id },
5761
+ "single application on the account; selecting it"
5863
5762
  );
5763
+ for (const line of leadIn) store.pushCliOutput("stdout", line);
5764
+ return selectAndReport(only);
5864
5765
  }
5865
- const apps = [
5866
- ...unordered.filter(canSelectApplication),
5867
- ...unordered.filter((app) => !canSelectApplication(app))
5766
+ const messages = [
5767
+ ...leadIn,
5768
+ "Which Algolia application should the wizard work in?"
5868
5769
  ];
5869
- const envApp = highlight ? unordered.find((app) => app.id === highlight.id) : void 0;
5870
- const highlightIndex = envApp && canSelectApplication(envApp) ? apps.indexOf(envApp) : -1;
5871
- const messages = [];
5872
- if (highlight && highlightIndex < 0) {
5873
- messages.push(
5874
- envApp ? `Could not use ${highlight.id} from ${highlight.file} \u2014 it\u2019s ${blockReasonFor(envApp).toLowerCase()}. Pick another below.` : `Could not use ${highlight.id} from ${highlight.file} \u2014 it may have been removed, or this account may not have access to it.`
5875
- );
5876
- }
5877
5770
  for (; ; ) {
5878
5771
  const choice = await store.requestUserInput({
5879
- prompt: "Which Algolia application should the wizard work in?",
5772
+ prompt: "Select an application",
5880
5773
  promptType: "multipleChoice",
5881
5774
  options: apps.map(labelFor),
5882
- secondary: apps.map((app) => secondaryFor(app, highlight?.id)),
5883
- disabled: apps.map((app) => !canSelectApplication(app)),
5884
- ...highlightIndex >= 0 ? { defaultSelectedIndex: highlightIndex } : {},
5775
+ secondary: apps.map(secondaryFor),
5885
5776
  messages
5886
5777
  });
5887
5778
  const chosen = apps.find((app) => labelFor(app) === choice);
5888
- if (!chosen || !canSelectApplication(chosen)) {
5779
+ if (!chosen) {
5889
5780
  throw new Error("Application picker received an unexpected selection");
5890
5781
  }
5891
5782
  try {
@@ -5901,15 +5792,42 @@ async function promptForApplication(highlight) {
5901
5792
  }
5902
5793
  }
5903
5794
  }
5904
- async function ensureApplication(isResuming) {
5905
- const current = await currentApplication();
5906
- if (isResuming) {
5907
- if (current && await isEligible(current)) return current;
5908
- return promptForApplication();
5795
+ async function confirmEnvApplication(env, current) {
5796
+ const useEnv = `Use ${env.id} (from ${env.file})`;
5797
+ const choice = await useWizard.getState().requestUserInput({
5798
+ prompt: "Select an application",
5799
+ promptType: "multipleChoice",
5800
+ options: [
5801
+ useEnv,
5802
+ current ? `Use ${labelFor(current)} (already selected)` : "Pick a different application"
5803
+ ],
5804
+ messages: [
5805
+ `${env.file} already sets ${env.name}=${env.id}.`,
5806
+ "Which Algolia application should the wizard work in?"
5807
+ ]
5808
+ });
5809
+ return choice === useEnv;
5810
+ }
5811
+ async function selectEnvApplication(env) {
5812
+ try {
5813
+ return await selectAndReport({ id: env.id, name: "" });
5814
+ } catch (err) {
5815
+ logger.warn(
5816
+ { app: env.id, err: err.message },
5817
+ "could not select the application named in env; falling back to the picker"
5818
+ );
5819
+ return promptForApplication([
5820
+ `Could not select ${env.id} from ${env.file} \u2014 it may have been removed, or this account may not have access to it.`
5821
+ ]);
5909
5822
  }
5823
+ }
5824
+ async function ensureApplication() {
5825
+ const current = await currentApplication();
5910
5826
  const env = await findEnvApplicationId();
5911
- if (!env) return promptForApplication();
5912
- return promptForApplication({ id: env.id, file: env.file });
5827
+ if (env && env.id !== current?.id && await confirmEnvApplication(env, current)) {
5828
+ return selectEnvApplication(env);
5829
+ }
5830
+ return current ?? await promptForApplication();
5913
5831
  }
5914
5832
 
5915
5833
  // src/lib/seed.ts
@@ -6273,15 +6191,14 @@ async function run(workflow) {
6273
6191
  }
6274
6192
  store.setUser(user);
6275
6193
  let app;
6276
- const resumableState = await loadResumableState(workflow);
6277
6194
  try {
6278
- app = await ensureApplication(resumableState != null);
6195
+ app = await ensureApplication();
6279
6196
  } catch (err) {
6280
6197
  store.setError(err instanceof Error ? err.message : String(err));
6281
6198
  await instance.waitUntilExit();
6282
6199
  process.exit(1);
6283
6200
  }
6284
- runWorkflow(workflow, app.id, resumableState);
6201
+ runWorkflow(workflow, app.id);
6285
6202
  }
6286
6203
  await requestTerminalSize();
6287
6204
  var started = await startup();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@algolia/wizard",
3
- "version": "0.41.0-rc.131.290",
3
+ "version": "0.42.0",
4
4
  "description": "Magically implement Algolia functionality in your codebase",
5
5
  "type": "module",
6
6
  "engines": {