@algolia/wizard 0.40.0 → 0.41.0-rc.131.289

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 +379 -224
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -259,10 +259,14 @@ 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 }),
262
264
  // `endAuth` lands on 'preflight', not 'idle': sign-in happens after the
263
265
  // welcome screen, so going back would gate the run a second time.
264
266
  beginAuth: () => set({ phase: "authenticating", cliOutput: [] }),
265
- endAuth: () => set((s) => s.phase === "authenticating" ? { phase: "preflight" } : {}),
267
+ endAuth: () => set(
268
+ (s) => s.phase === "authenticating" ? { phase: "preflight", cliOutput: [] } : {}
269
+ ),
266
270
  confirmStart: () => set(
267
271
  (s) => s.phase === "idle" ? { phase: "preflight", homeScreen: "home" } : {}
268
272
  ),
@@ -409,7 +413,8 @@ var useWizard = create((set, get) => ({
409
413
  logs: [],
410
414
  error: null,
411
415
  inputReq: null,
412
- _resolve: null
416
+ _resolve: null,
417
+ settingUpAppId: null
413
418
  });
414
419
  }
415
420
  }));
@@ -657,25 +662,27 @@ function SelectRow({
657
662
  labelWidth,
658
663
  highlightBackground = true,
659
664
  usePadding = false,
665
+ disabled = false,
660
666
  children
661
667
  }) {
662
- const labelColor = highlighted ? highlightBackground ? COLORS.highlight.fg : COLORS.success : COLORS.primary;
668
+ const active = highlighted && !disabled;
669
+ const labelColor = disabled ? COLORS.dim : active ? highlightBackground ? COLORS.highlight.fg : COLORS.success : COLORS.primary;
663
670
  return /* @__PURE__ */ jsxs3(
664
671
  Box4,
665
672
  {
666
673
  width,
667
674
  paddingX: usePadding ? 1 : 0,
668
675
  paddingY: usePadding ? 1 : 0,
669
- backgroundColor: highlighted && highlightBackground ? COLORS.highlight.bg : void 0,
676
+ backgroundColor: active && highlightBackground ? COLORS.highlight.bg : void 0,
670
677
  children: [
671
678
  /* @__PURE__ */ jsx3(Box4, { width: labelWidth, children: /* @__PURE__ */ jsxs3(
672
679
  Text4,
673
680
  {
674
681
  color: labelColor,
675
- bold: highlighted && !highlightBackground,
682
+ bold: active && !highlightBackground,
676
683
  wrap: "truncate",
677
684
  children: [
678
- highlighted ? "\u276F " : " ",
685
+ active ? "\u276F " : " ",
679
686
  label
680
687
  ]
681
688
  }
@@ -875,6 +882,14 @@ var ARROW_WIDTH = 4;
875
882
  var COLUMN_GAP = 2;
876
883
  var BAR_PADDING = 2;
877
884
  var ROW_HEIGHT = 3;
885
+ function nextSelectableIndex(start, dir, rowCount, isDisabled) {
886
+ let i = start;
887
+ for (let step = 0; step < rowCount; step++) {
888
+ i = (i + dir + rowCount) % rowCount;
889
+ if (!isDisabled(i)) return i;
890
+ }
891
+ return start;
892
+ }
878
893
  function SelectPrompt({
879
894
  options,
880
895
  onSelect,
@@ -886,15 +901,18 @@ function SelectPrompt({
886
901
  multi,
887
902
  cancelable,
888
903
  secondary,
904
+ disabled,
889
905
  defaultSelectedIndex = 0
890
906
  }) {
891
- const [index, setIndex] = useState5(
892
- () => defaultSelectedIndex > 0 && defaultSelectedIndex < options.length ? defaultSelectedIndex : 0
893
- );
894
- const [checked, setChecked] = useState5(() => /* @__PURE__ */ new Set());
895
907
  const hasCancel = Boolean(multi || cancelable);
896
908
  const rows = hasCancel ? [...options, "Cancel"] : options;
897
909
  const cancelIndex = hasCancel ? options.length : -1;
910
+ const isDisabled = (i) => i !== cancelIndex && Boolean(disabled?.[i]);
911
+ const [index, setIndex] = useState5(() => {
912
+ const start = defaultSelectedIndex > 0 && defaultSelectedIndex < options.length ? defaultSelectedIndex : 0;
913
+ return isDisabled(start) ? nextSelectableIndex(start, 1, rows.length, isDisabled) : start;
914
+ });
915
+ const [checked, setChecked] = useState5(() => /* @__PURE__ */ new Set());
898
916
  const hints = [];
899
917
  if (rows.length > 1) hints.push({ key: "[\u2191] [\u2193]", label: "move" });
900
918
  if (multi) hints.push({ key: "[space]", label: "select" });
@@ -934,9 +952,15 @@ function SelectPrompt({
934
952
  useInput2((input, key) => {
935
953
  if (rows.length === 0) return;
936
954
  if (key.upArrow || input === "k") {
937
- setIndex((i) => (i - 1 + rows.length) % rows.length);
955
+ setIndex((i) => {
956
+ const next = (i - 1 + rows.length) % rows.length;
957
+ return isDisabled(next) ? i : next;
958
+ });
938
959
  } else if (key.downArrow || input === "j") {
939
- setIndex((i) => (i + 1) % rows.length);
960
+ setIndex((i) => {
961
+ const next = (i + 1) % rows.length;
962
+ return isDisabled(next) ? i : next;
963
+ });
940
964
  } else if (multi && input === " " && index !== cancelIndex) {
941
965
  setChecked((prev) => {
942
966
  const next = new Set(prev);
@@ -947,6 +971,7 @@ function SelectPrompt({
947
971
  } else if (key.return) {
948
972
  if (index === cancelIndex) {
949
973
  onSelect(CANCEL);
974
+ } else if (isDisabled(index)) {
950
975
  } else if (!multi) {
951
976
  onSelect(options[index]);
952
977
  } else if (checked.size > 0) {
@@ -971,10 +996,12 @@ function SelectPrompt({
971
996
  const bullet = multi && !isCancel ? checked.has(i) ? "\u25CF " : "\u25CB " : "";
972
997
  const sec = isCancel ? void 0 : secondary?.[i];
973
998
  const isText = sec?.kind === "text";
999
+ const rowDisabled = isDisabled(i);
974
1000
  return /* @__PURE__ */ jsxs7(
975
1001
  SelectRow,
976
1002
  {
977
1003
  highlighted,
1004
+ disabled: rowDisabled,
978
1005
  width: isText ? "100%" : barWidth,
979
1006
  labelWidth: isText ? labelWidth : barLabelWidth,
980
1007
  label: `${bullet}${option}`,
@@ -984,7 +1011,7 @@ function SelectPrompt({
984
1011
  Text8,
985
1012
  {
986
1013
  wrap: "truncate",
987
- color: highlighted ? COLORS.primary : COLORS.muted,
1014
+ color: rowDisabled ? COLORS.dim : highlighted ? COLORS.primary : COLORS.muted,
988
1015
  children: sec.value
989
1016
  }
990
1017
  ) }),
@@ -1046,6 +1073,7 @@ function PromptInput() {
1046
1073
  table: inputReq.table,
1047
1074
  options: inputReq.options,
1048
1075
  secondary: inputReq.secondary,
1076
+ disabled: inputReq.disabled,
1049
1077
  defaultSelectedIndex: inputReq.defaultSelectedIndex,
1050
1078
  cancelable: inputReq.cancelable,
1051
1079
  error: inputReq.error,
@@ -1417,6 +1445,44 @@ function trackActionEnd(ctx) {
1417
1445
  metricTags(ctx.workflowId, ctx.actionId)
1418
1446
  );
1419
1447
  }
1448
+ var MAX_ATTRIBUTE_LENGTH = 500;
1449
+ function truncate2(value) {
1450
+ return value.length <= MAX_ATTRIBUTE_LENGTH ? value : `${value.slice(0, MAX_ATTRIBUTE_LENGTH - 3)}...`;
1451
+ }
1452
+ function readString(source, key) {
1453
+ const value = Reflect.get(source, key);
1454
+ return typeof value === "string" && value.length > 0 ? value : void 0;
1455
+ }
1456
+ function causeAttributes(cause) {
1457
+ if (cause instanceof Error) {
1458
+ return {
1459
+ error_cause_name: cause.name,
1460
+ error_cause: truncate2(cause.message)
1461
+ };
1462
+ }
1463
+ return typeof cause === "string" ? { error_cause: truncate2(cause) } : {};
1464
+ }
1465
+ function providerAttributes(source) {
1466
+ const statusCode = Reflect.get(source, "statusCode");
1467
+ const isRetryable = Reflect.get(source, "isRetryable");
1468
+ const url = readString(source, "url");
1469
+ const responseBody = readString(source, "responseBody");
1470
+ return {
1471
+ ...typeof statusCode === "number" && Number.isFinite(statusCode) && { error_status_code: statusCode },
1472
+ ...typeof isRetryable === "boolean" && { error_retryable: isRetryable },
1473
+ ...url && { error_url: truncate2(url) },
1474
+ ...responseBody && { error_response_body: truncate2(responseBody) }
1475
+ };
1476
+ }
1477
+ function errorAttributes(err) {
1478
+ if (!(err instanceof Error)) return {};
1479
+ const { cause } = err;
1480
+ return {
1481
+ error_name: err.name,
1482
+ ...causeAttributes(cause),
1483
+ ...providerAttributes(cause instanceof Error ? cause : err)
1484
+ };
1485
+ }
1420
1486
  function trackActionError(ctx) {
1421
1487
  const attributes = {
1422
1488
  event: "wizard.action.error",
@@ -1424,7 +1490,8 @@ function trackActionError(ctx) {
1424
1490
  action_id: ctx.actionId,
1425
1491
  action_title: ctx.actionTitle,
1426
1492
  error: ctx.error,
1427
- app_id: ctx.appId
1493
+ app_id: ctx.appId,
1494
+ ...errorAttributes(ctx.cause)
1428
1495
  };
1429
1496
  emitTelemetryLog(
1430
1497
  "error",
@@ -1460,7 +1527,8 @@ function trackWorkflowError(ctx) {
1460
1527
  workflow_id: ctx.workflowId,
1461
1528
  action_id: ctx.actionId,
1462
1529
  error: ctx.error,
1463
- app_id: ctx.appId
1530
+ app_id: ctx.appId,
1531
+ ...errorAttributes(ctx.cause)
1464
1532
  };
1465
1533
  emitTelemetryLog(
1466
1534
  "error",
@@ -1524,6 +1592,10 @@ function reconcileWorkflowState(state, workflow) {
1524
1592
  }
1525
1593
  return state;
1526
1594
  }
1595
+ async function loadResumableState(workflow) {
1596
+ const persisted = await loadWorkflowState(workflow.id);
1597
+ return persisted ? reconcileWorkflowState(persisted, workflow) : null;
1598
+ }
1527
1599
  function initWorkflowState(workflow, now) {
1528
1600
  return {
1529
1601
  workflowId: workflow.id,
@@ -1626,11 +1698,11 @@ async function runStep(state, index, step, appId) {
1626
1698
  durationMs: Date.now() - startedAt
1627
1699
  });
1628
1700
  }
1629
- async function runWorkflow(workflow, appId) {
1701
+ async function runWorkflow(workflow, appId, resumableState) {
1630
1702
  const store = useWizard.getState();
1631
1703
  try {
1632
- const persisted = await loadWorkflowState(workflow.id);
1633
- const state = (persisted && reconcileWorkflowState(persisted, workflow)) ?? initWorkflowState(workflow, nowIso());
1704
+ const resolved2 = resumableState !== void 0 ? resumableState : await loadResumableState(workflow);
1705
+ const state = resolved2 ?? initWorkflowState(workflow, nowIso());
1634
1706
  ensureExecutedStepCount(state);
1635
1707
  store.startWorkflow(
1636
1708
  {
@@ -1686,14 +1758,16 @@ async function runWorkflow(workflow, appId) {
1686
1758
  appId,
1687
1759
  actionId: failedActionId,
1688
1760
  actionTitle: failedActionTitle,
1689
- error: message
1761
+ error: message,
1762
+ cause: err
1690
1763
  });
1691
1764
  }
1692
1765
  trackWorkflowError({
1693
1766
  workflowId: workflow.id,
1694
1767
  appId,
1695
1768
  error: message,
1696
- actionId: failedActionId
1769
+ actionId: failedActionId,
1770
+ cause: err
1697
1771
  });
1698
1772
  track("Error", {
1699
1773
  step,
@@ -1720,14 +1794,89 @@ async function listIndices() {
1720
1794
  return items.map((i) => ({ name: i.name, entries: i.entries })).sort((a, b) => a.name.localeCompare(b.name));
1721
1795
  }
1722
1796
 
1797
+ // src/lib/algoliaApp.ts
1798
+ import { z as z5 } from "zod";
1799
+ var applicationSchema = z5.object({
1800
+ id: z5.string().min(1),
1801
+ name: z5.string().default(""),
1802
+ plan: z5.string().optional()
1803
+ });
1804
+ var listSchema = z5.array(
1805
+ z5.object({
1806
+ id: z5.string().min(1),
1807
+ name: z5.string().default(""),
1808
+ plan_label: z5.string().optional(),
1809
+ status: z5.string().optional(),
1810
+ acl: z5.array(z5.string()).optional()
1811
+ }).transform(({ id, name, plan_label, status, acl }) => ({
1812
+ id,
1813
+ name,
1814
+ plan: plan_label,
1815
+ status,
1816
+ acl
1817
+ }))
1818
+ );
1819
+ function canSelectApplication(app) {
1820
+ return app.status === "active" && (app.acl ?? []).includes("keys");
1821
+ }
1822
+ async function currentApplication() {
1823
+ let raw;
1824
+ try {
1825
+ raw = await runAlgoliaCli(["application", "current", "-o", "json"]);
1826
+ } catch {
1827
+ return null;
1828
+ }
1829
+ const parsed = applicationSchema.safeParse(parseJson(raw));
1830
+ return parsed.success ? parsed.data : null;
1831
+ }
1832
+ async function requireApplication() {
1833
+ const app = await currentApplication();
1834
+ if (!app) {
1835
+ throw new Error(
1836
+ "No Algolia application is selected. Run `npx @algolia/cli@latest application select` and restart the wizard."
1837
+ );
1838
+ }
1839
+ return app;
1840
+ }
1841
+ async function listApplications() {
1842
+ const raw = await runAlgoliaCli(["application", "list", "-o", "json"]);
1843
+ const parsed = listSchema.safeParse(parseJson(raw));
1844
+ if (!parsed.success) {
1845
+ throw new Error("Could not read the list of Algolia applications.");
1846
+ }
1847
+ return parsed.data;
1848
+ }
1849
+ async function selectApplication(id) {
1850
+ const raw = await runAlgoliaCli(
1851
+ ["application", "select", "--non-interactive", "--app-id", id],
1852
+ { onOutput: stderrSink }
1853
+ );
1854
+ const parsed = applicationSchema.safeParse(parseJson(raw));
1855
+ if (!parsed.success) {
1856
+ throw new Error(
1857
+ `Selected application ${id}, but the Algolia CLI returned an unreadable result.`
1858
+ );
1859
+ }
1860
+ return parsed.data;
1861
+ }
1862
+ function parseJson(text) {
1863
+ try {
1864
+ return JSON.parse(text);
1865
+ } catch {
1866
+ return void 0;
1867
+ }
1868
+ }
1869
+
1723
1870
  // src/actions/selectIndex.ts
1724
1871
  var CREATE_NEW_INDEX = "Create a new index\u2026";
1725
1872
  var selectIndexStep = async (ctx) => {
1873
+ await requireApplication();
1726
1874
  const indices = await listIndices();
1727
1875
  const names = indices.map((i) => i.name);
1728
1876
  const hasIndices = names.length > 0;
1729
1877
  let error;
1730
- for (; ; ) {
1878
+ let chosen;
1879
+ while (chosen === void 0) {
1731
1880
  const selection = hasIndices ? await ctx.requestUserInput({
1732
1881
  prompt: "Which index do you want to ingest into?",
1733
1882
  promptType: "multipleChoice",
@@ -1746,9 +1895,9 @@ var selectIndexStep = async (ctx) => {
1746
1895
  if (typeof selection !== "string") {
1747
1896
  throw new Error("selectIndex received an unexpected non-text result");
1748
1897
  }
1749
- let chosen;
1898
+ let candidate;
1750
1899
  if (!hasIndices) {
1751
- chosen = selection.trim();
1900
+ candidate = selection.trim();
1752
1901
  } else if (selection === CREATE_NEW_INDEX) {
1753
1902
  const name = await ctx.requestUserInput({
1754
1903
  prompt: "Name the new index:",
@@ -1758,21 +1907,28 @@ var selectIndexStep = async (ctx) => {
1758
1907
  if (typeof name !== "string") {
1759
1908
  throw new Error("selectIndex received an unexpected non-text result");
1760
1909
  }
1761
- chosen = name.trim();
1910
+ candidate = name.trim();
1762
1911
  } else {
1763
- chosen = selection;
1912
+ candidate = selection;
1764
1913
  }
1765
- if (!chosen) {
1914
+ if (!candidate) {
1766
1915
  error = "Index name cannot be empty.";
1767
1916
  continue;
1768
1917
  }
1769
- ctx.setUserInput("index", chosen);
1770
- return { selection: chosen };
1918
+ chosen = candidate;
1771
1919
  }
1920
+ ctx.setUserInput("index", chosen);
1921
+ return { selection: chosen };
1772
1922
  };
1773
1923
 
1774
1924
  // src/lib/agent.ts
1775
- import { ToolLoopAgent, hasToolCall, Output as Output3 } from "ai";
1925
+ import {
1926
+ ToolLoopAgent,
1927
+ hasToolCall,
1928
+ Output as Output3,
1929
+ APICallError,
1930
+ NoOutputGeneratedError
1931
+ } from "ai";
1776
1932
  import { createAnthropic as createAnthropic3 } from "@ai-sdk/anthropic";
1777
1933
  import "zod";
1778
1934
 
@@ -1781,7 +1937,7 @@ import "zod";
1781
1937
 
1782
1938
  // src/lib/tools/listFiles.ts
1783
1939
  import { tool } from "ai";
1784
- import z5 from "zod";
1940
+ import z6 from "zod";
1785
1941
  import { readdir } from "node:fs/promises";
1786
1942
 
1787
1943
  // src/lib/tools/path.ts
@@ -1817,8 +1973,8 @@ async function hasSymlinkParent(ctx, target) {
1817
1973
  function listFilesTool(ctx) {
1818
1974
  return tool({
1819
1975
  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.',
1820
- inputSchema: z5.object({
1821
- path: z5.string().optional().describe("Directory to list, relative to cwd (default: cwd)")
1976
+ inputSchema: z6.object({
1977
+ path: z6.string().optional().describe("Directory to list, relative to cwd (default: cwd)")
1822
1978
  }),
1823
1979
  execute: async ({ path = "." }) => {
1824
1980
  logger.info({ path }, "called listFiles tool");
@@ -1839,13 +1995,13 @@ function listFilesTool(ctx) {
1839
1995
 
1840
1996
  // src/lib/tools/changeDirectory.ts
1841
1997
  import { tool as tool2 } from "ai";
1842
- import z6 from "zod";
1998
+ import z7 from "zod";
1843
1999
  import { stat } from "node:fs/promises";
1844
2000
  function changeDirectoryTool(ctx) {
1845
2001
  return tool2({
1846
2002
  description: "Change the current working directory. Subsequent file operations resolve relative to it. Returns the new working directory.",
1847
- inputSchema: z6.object({
1848
- path: z6.string().describe("Directory to change into")
2003
+ inputSchema: z7.object({
2004
+ path: z7.string().describe("Directory to change into")
1849
2005
  }),
1850
2006
  execute: async ({ path }) => {
1851
2007
  logger.info({ path }, "called changeDirectory tool");
@@ -1867,13 +2023,13 @@ function changeDirectoryTool(ctx) {
1867
2023
 
1868
2024
  // src/lib/tools/reportStatus.ts
1869
2025
  import { tool as tool3 } from "ai";
1870
- import z7 from "zod";
2026
+ import z8 from "zod";
1871
2027
  function reportStatusTool(output) {
1872
2028
  return tool3({
1873
2029
  description: "Report the status of your execution. Return a reason in case of failure.",
1874
- inputSchema: z7.object({
1875
- status: z7.enum(["success", "fail"]),
1876
- reason: z7.string().optional(),
2030
+ inputSchema: z8.object({
2031
+ status: z8.enum(["success", "fail"]),
2032
+ reason: z8.string().optional(),
1877
2033
  output
1878
2034
  }),
1879
2035
  execute: async ({ status, reason, output: output2 }) => {
@@ -1885,7 +2041,7 @@ function reportStatusTool(output) {
1885
2041
 
1886
2042
  // src/lib/tools/readFile.ts
1887
2043
  import { tool as tool4 } from "ai";
1888
- import z8 from "zod";
2044
+ import z9 from "zod";
1889
2045
  import { readFile as readFile3 } from "node:fs/promises";
1890
2046
 
1891
2047
  // src/lib/tools/env.ts
@@ -1913,8 +2069,8 @@ function redactEnvValues(content) {
1913
2069
  function readFileTool(ctx) {
1914
2070
  return tool4({
1915
2071
  description: "Read the contents of a file at the given path",
1916
- inputSchema: z8.object({
1917
- filePath: z8.string().describe("Path to the file to read")
2072
+ inputSchema: z9.object({
2073
+ filePath: z9.string().describe("Path to the file to read")
1918
2074
  }),
1919
2075
  execute: async ({ filePath }) => {
1920
2076
  if (++ctx.counts.read > ctx.limits.read) {
@@ -1935,15 +2091,15 @@ function readFileTool(ctx) {
1935
2091
 
1936
2092
  // src/lib/tools/writeFile.ts
1937
2093
  import { tool as tool5 } from "ai";
1938
- import z9 from "zod";
2094
+ import z10 from "zod";
1939
2095
  import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
1940
2096
  import { dirname as dirname3 } from "node:path";
1941
2097
  function writeFileTool(ctx) {
1942
2098
  return tool5({
1943
2099
  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.",
1944
- inputSchema: z9.object({
1945
- filePath: z9.string().describe("Path to the file to write"),
1946
- content: z9.string().describe("Content to write to the file")
2100
+ inputSchema: z10.object({
2101
+ filePath: z10.string().describe("Path to the file to write"),
2102
+ content: z10.string().describe("Content to write to the file")
1947
2103
  }),
1948
2104
  execute: async ({ filePath, content }) => {
1949
2105
  logger.info({ filePath }, "called writeFile tool");
@@ -1973,68 +2129,6 @@ import z13 from "zod";
1973
2129
  import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile5 } from "node:fs/promises";
1974
2130
  import { dirname as dirname4, relative as relative3 } from "node:path";
1975
2131
 
1976
- // src/lib/algoliaApp.ts
1977
- import { z as z10 } from "zod";
1978
- var applicationSchema = z10.object({
1979
- id: z10.string().min(1),
1980
- name: z10.string().default(""),
1981
- plan: z10.string().optional()
1982
- });
1983
- var listSchema = z10.array(
1984
- z10.object({
1985
- id: z10.string().min(1),
1986
- name: z10.string().default(""),
1987
- plan_label: z10.string().optional()
1988
- }).transform(({ id, name, plan_label }) => ({ id, name, plan: plan_label }))
1989
- );
1990
- async function currentApplication() {
1991
- let raw;
1992
- try {
1993
- raw = await runAlgoliaCli(["application", "current", "-o", "json"]);
1994
- } catch {
1995
- return null;
1996
- }
1997
- const parsed = applicationSchema.safeParse(parseJson(raw));
1998
- return parsed.success ? parsed.data : null;
1999
- }
2000
- async function requireApplication() {
2001
- const app = await currentApplication();
2002
- if (!app) {
2003
- throw new Error(
2004
- "No Algolia application is selected. Run `npx @algolia/cli@latest application select` and restart the wizard."
2005
- );
2006
- }
2007
- return app;
2008
- }
2009
- async function listApplications() {
2010
- const raw = await runAlgoliaCli(["application", "list", "-o", "json"]);
2011
- const parsed = listSchema.safeParse(parseJson(raw));
2012
- if (!parsed.success) {
2013
- throw new Error("Could not read the list of Algolia applications.");
2014
- }
2015
- return parsed.data;
2016
- }
2017
- async function selectApplication(id) {
2018
- const raw = await runAlgoliaCli(
2019
- ["application", "select", "--non-interactive", "--app-id", id],
2020
- { onOutput: stderrSink }
2021
- );
2022
- const parsed = applicationSchema.safeParse(parseJson(raw));
2023
- if (!parsed.success) {
2024
- throw new Error(
2025
- `Selected application ${id}, but the Algolia CLI returned an unreadable result.`
2026
- );
2027
- }
2028
- return parsed.data;
2029
- }
2030
- function parseJson(text) {
2031
- try {
2032
- return JSON.parse(text);
2033
- } catch {
2034
- return void 0;
2035
- }
2036
- }
2037
-
2038
2132
  // src/lib/algoliaApiKey.ts
2039
2133
  import { z as z12 } from "zod";
2040
2134
 
@@ -2042,13 +2136,13 @@ import { z as z12 } from "zod";
2042
2136
  import { deletePassword, getPassword, setPassword } from "cross-keychain";
2043
2137
  import { z as z11 } from "zod";
2044
2138
  var SERVICE = "algolia-wizard";
2045
- var ACCOUNT = "api-keys";
2139
+ var account = (userId) => `api-keys:${userId}`;
2046
2140
  var storedKeysSchema = z11.record(z11.string(), z11.string());
2047
2141
  function entryId(kind, index, appId) {
2048
2142
  return `${kind}:${appId}:${index}`;
2049
2143
  }
2050
- async function loadKeys() {
2051
- const raw = await getPassword(SERVICE, ACCOUNT);
2144
+ async function loadKeys(userId) {
2145
+ const raw = await getPassword(SERVICE, account(userId));
2052
2146
  if (!raw) return {};
2053
2147
  let payload;
2054
2148
  try {
@@ -2070,47 +2164,47 @@ function serialized(op) {
2070
2164
  });
2071
2165
  return next;
2072
2166
  }
2073
- async function readStoredKey(kind, index, appId) {
2167
+ async function readStoredKey(kind, userId, index, appId) {
2074
2168
  try {
2075
- return (await loadKeys())[entryId(kind, index, appId)] ?? null;
2169
+ return (await loadKeys(userId))[entryId(kind, index, appId)] ?? null;
2076
2170
  } catch (err) {
2077
2171
  logger.warn(
2078
- { err: err.message, kind, index, appId },
2172
+ { err: err.message, kind, index, appId, userId },
2079
2173
  "could not read the API key from the keychain"
2080
2174
  );
2081
2175
  return null;
2082
2176
  }
2083
2177
  }
2084
- function storeKey(kind, index, appId, value) {
2178
+ function storeKey(kind, userId, index, appId, value) {
2085
2179
  return serialized(async () => {
2086
2180
  const id = entryId(kind, index, appId);
2087
2181
  try {
2088
- const keys = await loadKeys();
2182
+ const keys = await loadKeys(userId);
2089
2183
  await setPassword(
2090
2184
  SERVICE,
2091
- ACCOUNT,
2185
+ account(userId),
2092
2186
  JSON.stringify({ ...keys, [id]: value })
2093
2187
  );
2094
- if ((await loadKeys())[id] !== value) {
2188
+ if ((await loadKeys(userId))[id] !== value) {
2095
2189
  throw new Error("the keychain did not store the value");
2096
2190
  }
2097
2191
  } catch (err) {
2098
2192
  logger.warn(
2099
- { err: err.message, kind, index, appId },
2193
+ { err: err.message, kind, index, appId, userId },
2100
2194
  "could not store the API key in the keychain; the next run will create another"
2101
2195
  );
2102
2196
  }
2103
2197
  });
2104
2198
  }
2105
- function deleteStoredKeys() {
2199
+ function deleteStoredKeys(userId) {
2106
2200
  return serialized(async () => {
2107
2201
  try {
2108
- await deletePassword(SERVICE, ACCOUNT);
2202
+ await deletePassword(SERVICE, account(userId));
2109
2203
  } catch (err) {
2110
2204
  const message = err.message;
2111
2205
  if (/not found/i.test(message)) return;
2112
2206
  logger.warn(
2113
- { err: message },
2207
+ { err: message, userId },
2114
2208
  "could not delete the API keys from the keychain"
2115
2209
  );
2116
2210
  }
@@ -2118,6 +2212,16 @@ function deleteStoredKeys() {
2118
2212
  }
2119
2213
 
2120
2214
  // src/lib/algoliaApiKey.ts
2215
+ function requireUserId() {
2216
+ const userId = useWizard.getState().user?.userId;
2217
+ if (!userId) {
2218
+ throw new Error("No Algolia user is signed in; cannot scope the API key.");
2219
+ }
2220
+ return userId;
2221
+ }
2222
+ async function currentUserId() {
2223
+ return useWizard.getState().user?.userId ?? (await getUser())?.userId ?? null;
2224
+ }
2121
2225
  var WRITE_ACLS = [
2122
2226
  "addObject",
2123
2227
  "deleteObject",
@@ -2164,23 +2268,30 @@ async function keyExists(key) {
2164
2268
  var resolved = /* @__PURE__ */ new Map();
2165
2269
  async function forgetResolvedKeys() {
2166
2270
  resolved.clear();
2167
- await deleteStoredKeys();
2271
+ const userId = await currentUserId();
2272
+ if (userId) await deleteStoredKeys(userId);
2168
2273
  }
2169
2274
  function resolveKey(kind, index, appId, acls, description) {
2170
- const cacheKey = `${kind}:${appId}:${index}`;
2275
+ const userId = requireUserId();
2276
+ const cacheKey = `${userId}:${kind}:${appId}:${index}`;
2171
2277
  const cached = resolved.get(cacheKey);
2172
2278
  if (cached) return cached;
2173
- const pending = provisionKey(kind, index, appId, acls, description).catch(
2174
- (err) => {
2175
- resolved.delete(cacheKey);
2176
- throw err;
2177
- }
2178
- );
2279
+ const pending = provisionKey(
2280
+ kind,
2281
+ userId,
2282
+ index,
2283
+ appId,
2284
+ acls,
2285
+ description
2286
+ ).catch((err) => {
2287
+ resolved.delete(cacheKey);
2288
+ throw err;
2289
+ });
2179
2290
  resolved.set(cacheKey, pending);
2180
2291
  return pending;
2181
2292
  }
2182
- async function provisionKey(kind, index, appId, acls, description) {
2183
- const stored = await readStoredKey(kind, index, appId);
2293
+ async function provisionKey(kind, userId, index, appId, acls, description) {
2294
+ const stored = await readStoredKey(kind, userId, index, appId);
2184
2295
  if (stored) {
2185
2296
  if (await keyExists(stored)) {
2186
2297
  logger.info({ kind, index, appId }, "reusing the stored API key");
@@ -2192,7 +2303,7 @@ async function provisionKey(kind, index, appId, acls, description) {
2192
2303
  );
2193
2304
  }
2194
2305
  const key = await createKey(index, acls, description);
2195
- await storeKey(kind, index, appId, key);
2306
+ await storeKey(kind, userId, index, appId, key);
2196
2307
  return { key, source: "created" };
2197
2308
  }
2198
2309
  function resolveWriteKey(index, appId) {
@@ -2635,17 +2746,38 @@ function storeApproval(root) {
2635
2746
  return "approve";
2636
2747
  };
2637
2748
  }
2638
- var EXPLORATORY_COMMANDS = /* @__PURE__ */ new Set(["ls", "find", "tree", "dir"]);
2749
+ var FILE_IO_COMMANDS = /* @__PURE__ */ new Set([
2750
+ "ls",
2751
+ "find",
2752
+ "fd",
2753
+ "tree",
2754
+ "dir",
2755
+ "locate",
2756
+ "cat",
2757
+ "head",
2758
+ "tail",
2759
+ "less",
2760
+ "more",
2761
+ "tac",
2762
+ "nl",
2763
+ "grep",
2764
+ "egrep",
2765
+ "fgrep",
2766
+ "rg",
2767
+ "ack",
2768
+ "ag",
2769
+ "xxd",
2770
+ "hexdump",
2771
+ "od",
2772
+ "strings"
2773
+ ]);
2639
2774
  function commandSegments(command) {
2640
2775
  return command.split(/&&|;|\|/).map((segment) => segment.trim());
2641
2776
  }
2642
- function isExploratoryCommand(command) {
2643
- return commandSegments(command).map((segment) => segment.split(/\s+/)[0]).some((word) => word !== void 0 && EXPLORATORY_COMMANDS.has(word));
2777
+ function isFileIOCommand(command) {
2778
+ return commandSegments(command).map((segment) => segment.split(/\s+/)[0]).some((word) => word !== void 0 && FILE_IO_COMMANDS.has(word));
2644
2779
  }
2645
2780
  var READ_ONLY_BINARIES = /* @__PURE__ */ new Set([
2646
- "cat",
2647
- "head",
2648
- "tail",
2649
2781
  "wc",
2650
2782
  "pwd",
2651
2783
  "echo",
@@ -2656,10 +2788,6 @@ var READ_ONLY_BINARIES = /* @__PURE__ */ new Set([
2656
2788
  "which",
2657
2789
  "file",
2658
2790
  "stat",
2659
- "grep",
2660
- "egrep",
2661
- "fgrep",
2662
- "rg",
2663
2791
  "diff"
2664
2792
  ]);
2665
2793
  var READ_ONLY_NO_ARGS_BINARIES = /* @__PURE__ */ new Set(["env", "printenv"]);
@@ -2865,7 +2993,7 @@ async function approveAndRun(ctx, command, cwd, explanation) {
2865
2993
  }
2866
2994
  function runShellTool(ctx, createModel = defaultCreateModel) {
2867
2995
  return tool8({
2868
- description: "Run a shell command in the project. Use this for anything the project needs done in its own ecosystem: installing dependencies, running a script you wrote, running the project's lint/typecheck/test commands. Do not use this to find or read files \u2014 use listFiles, searchFiles, and readFile instead of ls/find/cat/head/tail/grep/rg. This tool refuses ls/find/tree/dir outright; a read command like cat is not refused (some read-only commands run without approval, see below), but it's still the wrong tool for reading a file \u2014 the dedicated tools exist for that and won't count against this tool's command budget. The user approves any command that could change the project before it runs, so write a clear `explanation`. A command judged read-only (inspection, or running tests/typecheck/lint without an autofix flag, in any language) runs immediately without approval. If the user rejects a command, do not retry it \u2014 propose a different approach.",
2996
+ description: "Run a shell command in the project. Use this for anything the project needs done in its own ecosystem: installing dependencies, running a script you wrote, running the project's lint/typecheck/test commands. Do not use this to find or read files \u2014 use listFiles, searchFiles, and readFile instead of shell file-listing, reading, or search commands (ls/find/tree/cat/head/tail/grep/rg and similar). This tool refuses all of those outright: the dedicated tools enforce the project-root boundary and secret redaction that a raw shell read would bypass, and they won't count against this tool's command budget. The user approves any command that could change the project before it runs, so write a clear `explanation`. A command judged read-only (inspection, or running tests/typecheck/lint without an autofix flag, in any language) runs immediately without approval. If the user rejects a command, do not retry it \u2014 propose a different approach.",
2869
2997
  inputSchema: z15.object({
2870
2998
  command: z15.string().describe(
2871
2999
  "The command to run, exactly as it would be typed in a shell. Pipes, && and redirects are allowed."
@@ -2883,8 +3011,8 @@ function runShellTool(ctx, createModel = defaultCreateModel) {
2883
3011
  }
2884
3012
  const resolved2 = resolveInRoot(ctx, cwd ?? ".");
2885
3013
  if (!resolved2.ok) return resolved2.error;
2886
- if (isExploratoryCommand(command)) {
2887
- return "Refused: use listFiles or searchFiles to find files, and readFile to read one, instead of ls/find/tree/dir.";
3014
+ if (isFileIOCommand(command)) {
3015
+ return "Refused: use listFiles or searchFiles to find files, and readFile to read one, instead of a shell file-listing, reading, or search command (ls/find/fd/tree/dir/locate/cat/head/tail/less/more/tac/nl/grep/egrep/fgrep/rg/ack/ag/xxd/hexdump/od/strings).";
2888
3016
  }
2889
3017
  logger.info({ command, cwd: resolved2.target }, "called runShell tool");
2890
3018
  const fast = fastPathSafety(command);
@@ -3139,21 +3267,31 @@ var MODEL_BY_SIZE = {
3139
3267
  var MISSING_REPORT_STATUS_ERROR_MESSAGE = "Agent finished without calling reportStatus";
3140
3268
  var MISSING_REPORT_USER_MESSAGE = "This step ran into a problem finishing. Run the wizard again to retry it.";
3141
3269
  var REPORT_STATUS_RETRIES = 2;
3270
+ var PROVIDER_ERROR_USER_MESSAGE = "The AI service had trouble responding. Run the wizard again to retry this step.";
3271
+ function retryKind(err) {
3272
+ if (err instanceof Error && err.message === MISSING_REPORT_STATUS_ERROR_MESSAGE) {
3273
+ return "missingReport";
3274
+ }
3275
+ if (NoOutputGeneratedError.isInstance(err)) return "transientProvider";
3276
+ if (APICallError.isInstance(err) && err.isRetryable) {
3277
+ return "transientProvider";
3278
+ }
3279
+ return null;
3280
+ }
3281
+ function exhaustedError(kind, err) {
3282
+ return kind === "missingReport" ? new Error(MISSING_REPORT_USER_MESSAGE) : new Error(PROVIDER_ERROR_USER_MESSAGE, { cause: err });
3283
+ }
3142
3284
  async function runAgent(req) {
3143
3285
  for (let attempt = 0; attempt <= REPORT_STATUS_RETRIES; attempt++) {
3144
3286
  try {
3145
3287
  return await runAgentAttempt(req, attempt);
3146
3288
  } catch (err) {
3147
- const isMissingReport = err instanceof Error && err.message === MISSING_REPORT_STATUS_ERROR_MESSAGE;
3148
- if (!isMissingReport) {
3149
- throw err;
3150
- }
3151
- if (attempt === REPORT_STATUS_RETRIES) {
3152
- throw new Error(MISSING_REPORT_USER_MESSAGE);
3153
- }
3289
+ const kind = retryKind(err);
3290
+ if (!kind) throw err;
3291
+ if (attempt === REPORT_STATUS_RETRIES) throw exhaustedError(kind, err);
3154
3292
  logger.warn(
3155
- { attempt: attempt + 1 },
3156
- "retrying runAgent after missing reportStatus"
3293
+ { attempt: attempt + 1, err },
3294
+ kind === "missingReport" ? "retrying runAgent after missing reportStatus" : "retrying runAgent after a transient provider error"
3157
3295
  );
3158
3296
  }
3159
3297
  }
@@ -3216,18 +3354,28 @@ async function runAgentAttempt(req, attempt) {
3216
3354
  });
3217
3355
  let chunks = [];
3218
3356
  const chunkLimit = 5;
3219
- for await (const chunk of stream.textStream) {
3357
+ let streamError;
3358
+ for await (const part of stream.fullStream) {
3359
+ if (part.type === "error") {
3360
+ streamError = part.error;
3361
+ continue;
3362
+ }
3363
+ if (part.type !== "text-delta") continue;
3220
3364
  if (chunks.length < chunkLimit) {
3221
- chunks.push(chunk);
3365
+ chunks.push(part.text);
3222
3366
  continue;
3223
3367
  }
3224
- chunks.push(chunk);
3368
+ chunks.push(part.text);
3225
3369
  logger.debug(chunks.join(""));
3226
3370
  chunks = [];
3227
3371
  }
3228
3372
  if (chunks.length) {
3229
3373
  logger.debug(chunks.join(""));
3230
3374
  }
3375
+ if (streamError !== void 0) {
3376
+ logger.error({ err: streamError }, "agent stream reported an error");
3377
+ throw streamError;
3378
+ }
3231
3379
  const end = Date.now();
3232
3380
  const usage = await stream.totalUsage;
3233
3381
  logger.info(
@@ -3387,7 +3535,7 @@ async function runAnalysis(mode, extraInstructions = []) {
3387
3535
  // package.json
3388
3536
  var package_default = {
3389
3537
  name: "@algolia/wizard",
3390
- version: "0.40.0",
3538
+ version: "0.41.0-rc.131.289",
3391
3539
  description: "Magically implement Algolia functionality in your codebase",
3392
3540
  type: "module",
3393
3541
  engines: {
@@ -4258,6 +4406,10 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
4258
4406
  if (useCases.includes("ingestion")) {
4259
4407
  ingestAppId = appId ?? (await requireApplication()).id;
4260
4408
  }
4409
+ let ingestWriteKey;
4410
+ if (useCases.includes("ingestion") && ingestAppId) {
4411
+ ingestWriteKey = (await resolveWriteKey(targetIndex, ingestAppId)).key;
4412
+ }
4261
4413
  let uploadFilePath;
4262
4414
  let uploadWarning;
4263
4415
  if (ingestionSource === "fileUpload") {
@@ -4320,9 +4472,9 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
4320
4472
  let ingestDurationMs;
4321
4473
  let ingestOutcomeMessage;
4322
4474
  const ingestKeyAppId = ingestAppId;
4323
- const ingestionTools = ingestKeyAppId ? makeToolContext(repoRoot, async () => ({
4475
+ const ingestionTools = ingestKeyAppId && ingestWriteKey ? makeToolContext(repoRoot, async () => ({
4324
4476
  [APP_ID_VAR]: ingestKeyAppId,
4325
- [API_KEY_VAR]: (await resolveWriteKey(targetIndex, ingestKeyAppId)).key,
4477
+ [API_KEY_VAR]: ingestWriteKey,
4326
4478
  [INDEX_NAME_VAR]: targetIndex
4327
4479
  })) : void 0;
4328
4480
  const searchTools = makeToolContext(repoRoot);
@@ -5036,7 +5188,7 @@ function logNameColor(entry) {
5036
5188
  return STATUS_COLOR[entry.status] ?? KIND_COLOR[entry.kind];
5037
5189
  }
5038
5190
  var ROW_GAP = 1;
5039
- function truncate2(str, maxWidth) {
5191
+ function truncate3(str, maxWidth) {
5040
5192
  if (maxWidth <= 0) return "";
5041
5193
  return str.length > maxWidth ? `${str.slice(0, maxWidth - 1)}\u2026` : str;
5042
5194
  }
@@ -5068,9 +5220,9 @@ function Logs() {
5068
5220
  const partCount = 2 + (rawPreview ? 1 : 0) + (durationText ? 1 : 0);
5069
5221
  const gaps = (partCount - 1) * ROW_GAP;
5070
5222
  let budget = scroll.width - timestamp.length - durationText.length - gaps;
5071
- const name = truncate2(entry.name, budget);
5223
+ const name = truncate3(entry.name, budget);
5072
5224
  budget -= name.length;
5073
- const preview = rawPreview ? truncate2(rawPreview, budget) : "";
5225
+ const preview = rawPreview ? truncate3(rawPreview, budget) : "";
5074
5226
  return /* @__PURE__ */ jsxs16(Box17, { flexDirection: "row", gap: ROW_GAP, children: [
5075
5227
  /* @__PURE__ */ jsx15(Text17, { color: COLORS.dim, children: timestamp }),
5076
5228
  /* @__PURE__ */ jsx15(Text17, { color: logNameColor(entry), wrap: "truncate", children: name }),
@@ -5478,6 +5630,7 @@ function App() {
5478
5630
  inputReq,
5479
5631
  user,
5480
5632
  workflow,
5633
+ settingUpAppId,
5481
5634
  review: review2
5482
5635
  } = useWizard();
5483
5636
  const { exit } = useApp();
@@ -5493,7 +5646,7 @@ function App() {
5493
5646
  const isCommandApprovalPrompt = isAwaitingUserInput && inputReq?.promptType === "commandApproval";
5494
5647
  const promptPending = isAwaitingUserInput && !isCommandApprovalPrompt;
5495
5648
  const holdForTip = stepHasTips && promptPending && tipState === "revealing";
5496
- const showTips = stepHasTips && (phase === "running" || isCommandApprovalPrompt || holdForTip);
5649
+ const showTips = stepHasTips && (phase === "running" && currentStep?.status === "running" || isCommandApprovalPrompt || holdForTip);
5497
5650
  const showNoticesInMain = !stepHasTips;
5498
5651
  const showNotices = (!isAwaitingUserInput || holdForTip) && !review2;
5499
5652
  useInput7(
@@ -5578,6 +5731,12 @@ function App() {
5578
5731
  ] }),
5579
5732
  /* @__PURE__ */ jsx18(Text20, { color: COLORS.muted, children: "A browser window will open \u2014 complete sign-in there." })
5580
5733
  ] }),
5734
+ settingUpAppId && /* @__PURE__ */ jsx18(Box20, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs18(Text20, { color: COLORS.strong, bold: true, children: [
5735
+ /* @__PURE__ */ jsx18(Spinner2, { type: "dots" }),
5736
+ " Setting up Wizard using app",
5737
+ " ",
5738
+ settingUpAppId
5739
+ ] }) }),
5581
5740
  /* @__PURE__ */ jsx18(CliOutput, {}),
5582
5741
  showTips && currentStep && /* @__PURE__ */ jsx18(
5583
5742
  Tips,
@@ -5648,50 +5807,72 @@ function readValue(raw) {
5648
5807
  }
5649
5808
 
5650
5809
  // src/lib/algoliaAppPicker.ts
5651
- function secondaryFor(app) {
5810
+ function blockReasonFor(app) {
5811
+ return app.status !== "active" ? "Paused" : "Missing permissions";
5812
+ }
5813
+ function secondaryFor(app, highlightId) {
5814
+ if (!canSelectApplication(app)) {
5815
+ return { kind: "text", value: blockReasonFor(app) };
5816
+ }
5817
+ if (app.id === highlightId) {
5818
+ return { kind: "badge", value: "[DETECTED]" };
5819
+ }
5652
5820
  return app.plan ? { kind: "badge", value: app.plan } : void 0;
5653
5821
  }
5654
5822
  function labelFor(app) {
5655
5823
  return app.name.trim() ? `${app.name} \u2014 ${app.id}` : app.id;
5656
5824
  }
5657
- function selectAndReport(app) {
5658
- useWizard.getState().pushCliOutput(
5659
- "stdout",
5660
- `Selecting ${labelFor(app)} \u2014 provisioning its API key\u2026`
5661
- );
5662
- return selectApplication(app.id);
5825
+ async function isEligible(app) {
5826
+ const apps = await listApplications();
5827
+ const full = apps.find((candidate) => candidate.id === app.id);
5828
+ return full != null && canSelectApplication(full);
5663
5829
  }
5664
- async function promptForApplication(leadIn = []) {
5830
+ async function selectAndReport(app) {
5665
5831
  const store = useWizard.getState();
5666
- const apps = await listApplications();
5667
- if (apps.length === 0) {
5832
+ store.setSettingUpApp(app.id);
5833
+ try {
5834
+ return await selectApplication(app.id);
5835
+ } finally {
5836
+ store.setSettingUpApp(null);
5837
+ }
5838
+ }
5839
+ async function promptForApplication(highlight) {
5840
+ const store = useWizard.getState();
5841
+ const unordered = await listApplications();
5842
+ if (unordered.length === 0) {
5668
5843
  throw new Error(
5669
5844
  "This Algolia account has no applications. Create one in the Algolia dashboard, or with `npx @algolia/cli@latest application create`, then restart the wizard."
5670
5845
  );
5671
5846
  }
5672
- if (apps.length === 1) {
5673
- const only = apps[0];
5674
- logger.info(
5675
- { app: only.id },
5676
- "single application on the account; selecting it"
5847
+ if (!unordered.some(canSelectApplication)) {
5848
+ throw new Error(
5849
+ "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."
5677
5850
  );
5678
- for (const line of leadIn) store.pushCliOutput("stdout", line);
5679
- return selectAndReport(only);
5680
5851
  }
5681
- const messages = [
5682
- ...leadIn,
5683
- "Which Algolia application should the wizard work in?"
5852
+ const apps = [
5853
+ ...unordered.filter(canSelectApplication),
5854
+ ...unordered.filter((app) => !canSelectApplication(app))
5684
5855
  ];
5856
+ const envApp = highlight ? unordered.find((app) => app.id === highlight.id) : void 0;
5857
+ const highlightIndex = envApp && canSelectApplication(envApp) ? apps.indexOf(envApp) : -1;
5858
+ const messages = [];
5859
+ if (highlight && highlightIndex < 0) {
5860
+ messages.push(
5861
+ 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.`
5862
+ );
5863
+ }
5685
5864
  for (; ; ) {
5686
5865
  const choice = await store.requestUserInput({
5687
- prompt: "Select an application",
5866
+ prompt: "Which Algolia application should the wizard work in?",
5688
5867
  promptType: "multipleChoice",
5689
5868
  options: apps.map(labelFor),
5690
- secondary: apps.map(secondaryFor),
5869
+ secondary: apps.map((app) => secondaryFor(app, highlight?.id)),
5870
+ disabled: apps.map((app) => !canSelectApplication(app)),
5871
+ ...highlightIndex >= 0 ? { defaultSelectedIndex: highlightIndex } : {},
5691
5872
  messages
5692
5873
  });
5693
5874
  const chosen = apps.find((app) => labelFor(app) === choice);
5694
- if (!chosen) {
5875
+ if (!chosen || !canSelectApplication(chosen)) {
5695
5876
  throw new Error("Application picker received an unexpected selection");
5696
5877
  }
5697
5878
  try {
@@ -5707,42 +5888,15 @@ async function promptForApplication(leadIn = []) {
5707
5888
  }
5708
5889
  }
5709
5890
  }
5710
- async function confirmEnvApplication(env, current) {
5711
- const useEnv = `Use ${env.id} (from ${env.file})`;
5712
- const choice = await useWizard.getState().requestUserInput({
5713
- prompt: "Select an application",
5714
- promptType: "multipleChoice",
5715
- options: [
5716
- useEnv,
5717
- current ? `Use ${labelFor(current)} (already selected)` : "Pick a different application"
5718
- ],
5719
- messages: [
5720
- `${env.file} already sets ${env.name}=${env.id}.`,
5721
- "Which Algolia application should the wizard work in?"
5722
- ]
5723
- });
5724
- return choice === useEnv;
5725
- }
5726
- async function selectEnvApplication(env) {
5727
- try {
5728
- return await selectAndReport({ id: env.id, name: "" });
5729
- } catch (err) {
5730
- logger.warn(
5731
- { app: env.id, err: err.message },
5732
- "could not select the application named in env; falling back to the picker"
5733
- );
5734
- return promptForApplication([
5735
- `Could not select ${env.id} from ${env.file} \u2014 it may have been removed, or this account may not have access to it.`
5736
- ]);
5737
- }
5738
- }
5739
- async function ensureApplication() {
5891
+ async function ensureApplication(isResuming) {
5740
5892
  const current = await currentApplication();
5741
- const env = await findEnvApplicationId();
5742
- if (env && env.id !== current?.id && await confirmEnvApplication(env, current)) {
5743
- return selectEnvApplication(env);
5893
+ if (isResuming) {
5894
+ if (current && await isEligible(current)) return current;
5895
+ return promptForApplication();
5744
5896
  }
5745
- return current ?? await promptForApplication();
5897
+ const env = await findEnvApplicationId();
5898
+ if (!env) return promptForApplication();
5899
+ return promptForApplication({ id: env.id, file: env.file });
5746
5900
  }
5747
5901
 
5748
5902
  // src/lib/seed.ts
@@ -6106,14 +6260,15 @@ async function run(workflow) {
6106
6260
  }
6107
6261
  store.setUser(user);
6108
6262
  let app;
6263
+ const resumableState = await loadResumableState(workflow);
6109
6264
  try {
6110
- app = await ensureApplication();
6265
+ app = await ensureApplication(resumableState != null);
6111
6266
  } catch (err) {
6112
6267
  store.setError(err instanceof Error ? err.message : String(err));
6113
6268
  await instance.waitUntilExit();
6114
6269
  process.exit(1);
6115
6270
  }
6116
- runWorkflow(workflow, app.id);
6271
+ runWorkflow(workflow, app.id, resumableState);
6117
6272
  }
6118
6273
  await requestTerminalSize();
6119
6274
  var started = await startup();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@algolia/wizard",
3
- "version": "0.40.0",
3
+ "version": "0.41.0-rc.131.289",
4
4
  "description": "Magically implement Algolia functionality in your codebase",
5
5
  "type": "module",
6
6
  "engines": {