@algolia/wizard 0.46.0 → 0.48.0-rc.141.344
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js
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
|
|
8
|
+
import Spinner3 from "ink-spinner";
|
|
9
9
|
|
|
10
10
|
// src/core/store.ts
|
|
11
11
|
import { create } from "zustand";
|
|
@@ -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(
|
|
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
|
}));
|
|
@@ -637,6 +642,7 @@ function Notices({
|
|
|
637
642
|
|
|
638
643
|
// src/ui/PromptInput.tsx
|
|
639
644
|
import { Box as Box9, Text as Text9 } from "ink";
|
|
645
|
+
import Spinner from "ink-spinner";
|
|
640
646
|
import TextInput from "ink-text-input";
|
|
641
647
|
import { useState as useState6 } from "react";
|
|
642
648
|
|
|
@@ -657,25 +663,27 @@ function SelectRow({
|
|
|
657
663
|
labelWidth,
|
|
658
664
|
highlightBackground = true,
|
|
659
665
|
usePadding = false,
|
|
666
|
+
disabled = false,
|
|
660
667
|
children
|
|
661
668
|
}) {
|
|
662
|
-
const
|
|
669
|
+
const active = highlighted && !disabled;
|
|
670
|
+
const labelColor = disabled ? COLORS.dim : active ? highlightBackground ? COLORS.highlight.fg : COLORS.success : COLORS.primary;
|
|
663
671
|
return /* @__PURE__ */ jsxs3(
|
|
664
672
|
Box4,
|
|
665
673
|
{
|
|
666
674
|
width,
|
|
667
675
|
paddingX: usePadding ? 1 : 0,
|
|
668
676
|
paddingY: usePadding ? 1 : 0,
|
|
669
|
-
backgroundColor:
|
|
677
|
+
backgroundColor: active && highlightBackground ? COLORS.highlight.bg : void 0,
|
|
670
678
|
children: [
|
|
671
679
|
/* @__PURE__ */ jsx3(Box4, { width: labelWidth, children: /* @__PURE__ */ jsxs3(
|
|
672
680
|
Text4,
|
|
673
681
|
{
|
|
674
682
|
color: labelColor,
|
|
675
|
-
bold:
|
|
683
|
+
bold: active && !highlightBackground,
|
|
676
684
|
wrap: "truncate",
|
|
677
685
|
children: [
|
|
678
|
-
|
|
686
|
+
active ? "\u276F " : " ",
|
|
679
687
|
label
|
|
680
688
|
]
|
|
681
689
|
}
|
|
@@ -875,6 +883,14 @@ var ARROW_WIDTH = 4;
|
|
|
875
883
|
var COLUMN_GAP = 2;
|
|
876
884
|
var BAR_PADDING = 2;
|
|
877
885
|
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
|
+
}
|
|
878
894
|
function SelectPrompt({
|
|
879
895
|
options,
|
|
880
896
|
onSelect,
|
|
@@ -886,15 +902,18 @@ function SelectPrompt({
|
|
|
886
902
|
multi,
|
|
887
903
|
cancelable,
|
|
888
904
|
secondary,
|
|
905
|
+
disabled,
|
|
889
906
|
defaultSelectedIndex = 0
|
|
890
907
|
}) {
|
|
891
|
-
const [index, setIndex] = useState5(
|
|
892
|
-
() => defaultSelectedIndex > 0 && defaultSelectedIndex < options.length ? defaultSelectedIndex : 0
|
|
893
|
-
);
|
|
894
|
-
const [checked, setChecked] = useState5(() => /* @__PURE__ */ new Set());
|
|
895
908
|
const hasCancel = Boolean(multi || cancelable);
|
|
896
909
|
const rows = hasCancel ? [...options, "Cancel"] : options;
|
|
897
910
|
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());
|
|
898
917
|
const hints = [];
|
|
899
918
|
if (rows.length > 1) hints.push({ key: "[\u2191] [\u2193]", label: "move" });
|
|
900
919
|
if (multi) hints.push({ key: "[space]", label: "select" });
|
|
@@ -934,10 +953,10 @@ function SelectPrompt({
|
|
|
934
953
|
useInput2((input, key) => {
|
|
935
954
|
if (rows.length === 0) return;
|
|
936
955
|
if (key.upArrow || input === "k") {
|
|
937
|
-
setIndex((i) => (i -
|
|
956
|
+
setIndex((i) => nextSelectableIndex(i, -1, rows.length, isDisabled));
|
|
938
957
|
} else if (key.downArrow || input === "j") {
|
|
939
|
-
setIndex((i) => (i
|
|
940
|
-
} else if (multi && input === " " && index !== cancelIndex) {
|
|
958
|
+
setIndex((i) => nextSelectableIndex(i, 1, rows.length, isDisabled));
|
|
959
|
+
} else if (multi && input === " " && index !== cancelIndex && !isDisabled(index)) {
|
|
941
960
|
setChecked((prev) => {
|
|
942
961
|
const next = new Set(prev);
|
|
943
962
|
if (next.has(index)) next.delete(index);
|
|
@@ -947,10 +966,12 @@ function SelectPrompt({
|
|
|
947
966
|
} else if (key.return) {
|
|
948
967
|
if (index === cancelIndex) {
|
|
949
968
|
onSelect(CANCEL);
|
|
969
|
+
} else if (isDisabled(index)) {
|
|
950
970
|
} else if (!multi) {
|
|
951
971
|
onSelect(options[index]);
|
|
952
|
-
} else
|
|
953
|
-
|
|
972
|
+
} else {
|
|
973
|
+
const picked = options.filter((_, i) => checked.has(i) && !isDisabled(i));
|
|
974
|
+
if (picked.length > 0) onSelect(picked);
|
|
954
975
|
}
|
|
955
976
|
}
|
|
956
977
|
});
|
|
@@ -971,10 +992,12 @@ function SelectPrompt({
|
|
|
971
992
|
const bullet = multi && !isCancel ? checked.has(i) ? "\u25CF " : "\u25CB " : "";
|
|
972
993
|
const sec = isCancel ? void 0 : secondary?.[i];
|
|
973
994
|
const isText = sec?.kind === "text";
|
|
995
|
+
const rowDisabled = isDisabled(i);
|
|
974
996
|
return /* @__PURE__ */ jsxs7(
|
|
975
997
|
SelectRow,
|
|
976
998
|
{
|
|
977
999
|
highlighted,
|
|
1000
|
+
disabled: rowDisabled,
|
|
978
1001
|
width: isText ? "100%" : barWidth,
|
|
979
1002
|
labelWidth: isText ? labelWidth : barLabelWidth,
|
|
980
1003
|
label: `${bullet}${option}`,
|
|
@@ -984,7 +1007,7 @@ function SelectPrompt({
|
|
|
984
1007
|
Text8,
|
|
985
1008
|
{
|
|
986
1009
|
wrap: "truncate",
|
|
987
|
-
color: highlighted ? COLORS.primary : COLORS.muted,
|
|
1010
|
+
color: rowDisabled ? COLORS.dim : highlighted ? COLORS.primary : COLORS.muted,
|
|
988
1011
|
children: sec.value
|
|
989
1012
|
}
|
|
990
1013
|
) }),
|
|
@@ -1031,11 +1054,23 @@ function EnterToContinuePrompt({
|
|
|
1031
1054
|
function PromptInput() {
|
|
1032
1055
|
const { phase, inputReq, submitInput } = useWizard();
|
|
1033
1056
|
const [draft, setDraft] = useState6("");
|
|
1057
|
+
const [submittedReq, setSubmittedReq] = useState6(null);
|
|
1034
1058
|
const promptKey = inputReq && `${inputReq.promptType}:${inputReq.prompt}`;
|
|
1059
|
+
const submitting = inputReq != null && submittedReq === inputReq;
|
|
1035
1060
|
if (phase === "done" || phase === "error") {
|
|
1036
1061
|
return /* @__PURE__ */ jsx7(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text9, { color: "gray", dimColor: true, children: "Press Enter or Esc to exit" }) });
|
|
1037
1062
|
}
|
|
1038
1063
|
if (phase !== "awaitingInput" || !inputReq) return null;
|
|
1064
|
+
if (submitting) {
|
|
1065
|
+
return /* @__PURE__ */ jsx7(Box9, { flexGrow: 1, children: /* @__PURE__ */ jsxs8(Text9, { color: COLORS.strong, bold: true, children: [
|
|
1066
|
+
/* @__PURE__ */ jsx7(Spinner, { type: "dots" }),
|
|
1067
|
+
" Continuing\u2026"
|
|
1068
|
+
] }) });
|
|
1069
|
+
}
|
|
1070
|
+
const handleSubmit = (value) => {
|
|
1071
|
+
setSubmittedReq(inputReq);
|
|
1072
|
+
submitInput(value);
|
|
1073
|
+
};
|
|
1039
1074
|
if (inputReq.promptType === "multipleChoice") {
|
|
1040
1075
|
return /* @__PURE__ */ jsx7(Box9, { flexGrow: 1, children: /* @__PURE__ */ jsx7(
|
|
1041
1076
|
SelectPrompt,
|
|
@@ -1046,10 +1081,11 @@ function PromptInput() {
|
|
|
1046
1081
|
table: inputReq.table,
|
|
1047
1082
|
options: inputReq.options,
|
|
1048
1083
|
secondary: inputReq.secondary,
|
|
1084
|
+
disabled: inputReq.disabled,
|
|
1049
1085
|
defaultSelectedIndex: inputReq.defaultSelectedIndex,
|
|
1050
1086
|
cancelable: inputReq.cancelable,
|
|
1051
1087
|
error: inputReq.error,
|
|
1052
|
-
onSelect:
|
|
1088
|
+
onSelect: handleSubmit
|
|
1053
1089
|
},
|
|
1054
1090
|
promptKey
|
|
1055
1091
|
) });
|
|
@@ -1065,7 +1101,7 @@ function PromptInput() {
|
|
|
1065
1101
|
table: inputReq.table,
|
|
1066
1102
|
options: inputReq.options,
|
|
1067
1103
|
error: inputReq.error,
|
|
1068
|
-
onSelect:
|
|
1104
|
+
onSelect: handleSubmit
|
|
1069
1105
|
},
|
|
1070
1106
|
promptKey
|
|
1071
1107
|
) });
|
|
@@ -1077,7 +1113,7 @@ function PromptInput() {
|
|
|
1077
1113
|
question: inputReq.prompt,
|
|
1078
1114
|
messages: inputReq.messages,
|
|
1079
1115
|
options: ["Continue"],
|
|
1080
|
-
onSelect:
|
|
1116
|
+
onSelect: handleSubmit
|
|
1081
1117
|
},
|
|
1082
1118
|
promptKey
|
|
1083
1119
|
) });
|
|
@@ -1104,7 +1140,7 @@ function PromptInput() {
|
|
|
1104
1140
|
messages: inputReq.messages,
|
|
1105
1141
|
options: labels,
|
|
1106
1142
|
secondary: inputReq.secondary,
|
|
1107
|
-
onSelect: (value) =>
|
|
1143
|
+
onSelect: (value) => handleSubmit(value === labels[0])
|
|
1108
1144
|
},
|
|
1109
1145
|
promptKey
|
|
1110
1146
|
) });
|
|
@@ -1285,6 +1321,10 @@ import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2, rm } f
|
|
|
1285
1321
|
import { join as join4 } from "node:path";
|
|
1286
1322
|
var isStepVisible = (s) => s.visible !== false;
|
|
1287
1323
|
var stateFile = (workflowId) => join4(stateDir(), `state-${workflowId}.json`);
|
|
1324
|
+
function runAppId(state) {
|
|
1325
|
+
const appId = state.algoliaState.appId;
|
|
1326
|
+
return typeof appId === "string" && appId ? appId : void 0;
|
|
1327
|
+
}
|
|
1288
1328
|
async function loadWorkflowState(workflowId) {
|
|
1289
1329
|
try {
|
|
1290
1330
|
const raw = await readFile2(stateFile(workflowId), "utf8");
|
|
@@ -1564,7 +1604,11 @@ function reconcileWorkflowState(state, workflow) {
|
|
|
1564
1604
|
}
|
|
1565
1605
|
return state;
|
|
1566
1606
|
}
|
|
1567
|
-
function
|
|
1607
|
+
async function loadResumableState(workflow) {
|
|
1608
|
+
const persisted = await loadWorkflowState(workflow.id);
|
|
1609
|
+
return persisted ? reconcileWorkflowState(persisted, workflow) : null;
|
|
1610
|
+
}
|
|
1611
|
+
function initWorkflowState(workflow, now, appId) {
|
|
1568
1612
|
return {
|
|
1569
1613
|
workflowId: workflow.id,
|
|
1570
1614
|
startedAt: now,
|
|
@@ -1576,7 +1620,7 @@ function initWorkflowState(workflow, now) {
|
|
|
1576
1620
|
visible: s.visible,
|
|
1577
1621
|
status: "pending"
|
|
1578
1622
|
})),
|
|
1579
|
-
algoliaState: {},
|
|
1623
|
+
algoliaState: appId ? { appId } : {},
|
|
1580
1624
|
userInputs: {}
|
|
1581
1625
|
};
|
|
1582
1626
|
}
|
|
@@ -1666,11 +1710,11 @@ async function runStep(state, index, step, appId) {
|
|
|
1666
1710
|
durationMs: Date.now() - startedAt
|
|
1667
1711
|
});
|
|
1668
1712
|
}
|
|
1669
|
-
async function runWorkflow(workflow, appId) {
|
|
1713
|
+
async function runWorkflow(workflow, appId, resumableState) {
|
|
1670
1714
|
const store = useWizard.getState();
|
|
1671
1715
|
try {
|
|
1672
|
-
const
|
|
1673
|
-
const state =
|
|
1716
|
+
const resolved2 = resumableState !== void 0 ? resumableState : await loadResumableState(workflow);
|
|
1717
|
+
const state = resolved2 ?? initWorkflowState(workflow, nowIso(), appId);
|
|
1674
1718
|
ensureExecutedStepCount(state);
|
|
1675
1719
|
store.startWorkflow(
|
|
1676
1720
|
{
|
|
@@ -1762,14 +1806,89 @@ async function listIndices() {
|
|
|
1762
1806
|
return items.map((i) => ({ name: i.name, entries: i.entries })).sort((a, b) => a.name.localeCompare(b.name));
|
|
1763
1807
|
}
|
|
1764
1808
|
|
|
1809
|
+
// src/lib/algoliaApp.ts
|
|
1810
|
+
import { z as z5 } from "zod";
|
|
1811
|
+
var applicationSchema = z5.object({
|
|
1812
|
+
id: z5.string().min(1),
|
|
1813
|
+
name: z5.string().default(""),
|
|
1814
|
+
plan: z5.string().optional()
|
|
1815
|
+
});
|
|
1816
|
+
var listSchema = z5.array(
|
|
1817
|
+
z5.object({
|
|
1818
|
+
id: z5.string().min(1),
|
|
1819
|
+
name: z5.string().default(""),
|
|
1820
|
+
plan_label: z5.string().optional(),
|
|
1821
|
+
status: z5.string().optional(),
|
|
1822
|
+
acl: z5.array(z5.string()).optional()
|
|
1823
|
+
}).transform(({ id, name, plan_label, status, acl }) => ({
|
|
1824
|
+
id,
|
|
1825
|
+
name,
|
|
1826
|
+
plan: plan_label,
|
|
1827
|
+
status,
|
|
1828
|
+
acl
|
|
1829
|
+
}))
|
|
1830
|
+
);
|
|
1831
|
+
function canSelectApplication(app) {
|
|
1832
|
+
return app.status === "active" && (app.acl ?? []).includes("keys");
|
|
1833
|
+
}
|
|
1834
|
+
async function currentApplication() {
|
|
1835
|
+
let raw;
|
|
1836
|
+
try {
|
|
1837
|
+
raw = await runAlgoliaCli(["application", "current", "-o", "json"]);
|
|
1838
|
+
} catch {
|
|
1839
|
+
return null;
|
|
1840
|
+
}
|
|
1841
|
+
const parsed = applicationSchema.safeParse(parseJson(raw));
|
|
1842
|
+
return parsed.success ? parsed.data : null;
|
|
1843
|
+
}
|
|
1844
|
+
async function requireApplication() {
|
|
1845
|
+
const app = await currentApplication();
|
|
1846
|
+
if (!app) {
|
|
1847
|
+
throw new Error(
|
|
1848
|
+
"No Algolia application is selected. Run `npx @algolia/cli@latest application select` and restart the wizard."
|
|
1849
|
+
);
|
|
1850
|
+
}
|
|
1851
|
+
return app;
|
|
1852
|
+
}
|
|
1853
|
+
async function listApplications() {
|
|
1854
|
+
const raw = await runAlgoliaCli(["application", "list", "-o", "json"]);
|
|
1855
|
+
const parsed = listSchema.safeParse(parseJson(raw));
|
|
1856
|
+
if (!parsed.success) {
|
|
1857
|
+
throw new Error("Could not read the list of Algolia applications.");
|
|
1858
|
+
}
|
|
1859
|
+
return parsed.data;
|
|
1860
|
+
}
|
|
1861
|
+
async function selectApplication(id) {
|
|
1862
|
+
const raw = await runAlgoliaCli(
|
|
1863
|
+
["application", "select", "--non-interactive", "--app-id", id],
|
|
1864
|
+
{ onOutput: stderrSink }
|
|
1865
|
+
);
|
|
1866
|
+
const parsed = applicationSchema.safeParse(parseJson(raw));
|
|
1867
|
+
if (!parsed.success) {
|
|
1868
|
+
throw new Error(
|
|
1869
|
+
`Selected application ${id}, but the Algolia CLI returned an unreadable result.`
|
|
1870
|
+
);
|
|
1871
|
+
}
|
|
1872
|
+
return parsed.data;
|
|
1873
|
+
}
|
|
1874
|
+
function parseJson(text) {
|
|
1875
|
+
try {
|
|
1876
|
+
return JSON.parse(text);
|
|
1877
|
+
} catch {
|
|
1878
|
+
return void 0;
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1765
1882
|
// src/actions/selectIndex.ts
|
|
1766
1883
|
var CREATE_NEW_INDEX = "Create a new index\u2026";
|
|
1767
1884
|
var selectIndexStep = async (ctx) => {
|
|
1885
|
+
await requireApplication();
|
|
1768
1886
|
const indices = await listIndices();
|
|
1769
1887
|
const names = indices.map((i) => i.name);
|
|
1770
1888
|
const hasIndices = names.length > 0;
|
|
1771
1889
|
let error;
|
|
1772
|
-
|
|
1890
|
+
let chosen;
|
|
1891
|
+
while (chosen === void 0) {
|
|
1773
1892
|
const selection = hasIndices ? await ctx.requestUserInput({
|
|
1774
1893
|
prompt: "Which index do you want to ingest into?",
|
|
1775
1894
|
promptType: "multipleChoice",
|
|
@@ -1788,9 +1907,9 @@ var selectIndexStep = async (ctx) => {
|
|
|
1788
1907
|
if (typeof selection !== "string") {
|
|
1789
1908
|
throw new Error("selectIndex received an unexpected non-text result");
|
|
1790
1909
|
}
|
|
1791
|
-
let
|
|
1910
|
+
let candidate;
|
|
1792
1911
|
if (!hasIndices) {
|
|
1793
|
-
|
|
1912
|
+
candidate = selection.trim();
|
|
1794
1913
|
} else if (selection === CREATE_NEW_INDEX) {
|
|
1795
1914
|
const name = await ctx.requestUserInput({
|
|
1796
1915
|
prompt: "Name the new index:",
|
|
@@ -1800,17 +1919,18 @@ var selectIndexStep = async (ctx) => {
|
|
|
1800
1919
|
if (typeof name !== "string") {
|
|
1801
1920
|
throw new Error("selectIndex received an unexpected non-text result");
|
|
1802
1921
|
}
|
|
1803
|
-
|
|
1922
|
+
candidate = name.trim();
|
|
1804
1923
|
} else {
|
|
1805
|
-
|
|
1924
|
+
candidate = selection;
|
|
1806
1925
|
}
|
|
1807
|
-
if (!
|
|
1926
|
+
if (!candidate) {
|
|
1808
1927
|
error = "Index name cannot be empty.";
|
|
1809
1928
|
continue;
|
|
1810
1929
|
}
|
|
1811
|
-
|
|
1812
|
-
return { selection: chosen };
|
|
1930
|
+
chosen = candidate;
|
|
1813
1931
|
}
|
|
1932
|
+
ctx.setUserInput("index", chosen);
|
|
1933
|
+
return { selection: chosen };
|
|
1814
1934
|
};
|
|
1815
1935
|
|
|
1816
1936
|
// src/lib/agent.ts
|
|
@@ -1829,7 +1949,7 @@ import "zod";
|
|
|
1829
1949
|
|
|
1830
1950
|
// src/lib/tools/listFiles.ts
|
|
1831
1951
|
import { tool } from "ai";
|
|
1832
|
-
import
|
|
1952
|
+
import z6 from "zod";
|
|
1833
1953
|
import { readdir } from "node:fs/promises";
|
|
1834
1954
|
|
|
1835
1955
|
// src/lib/tools/path.ts
|
|
@@ -1865,8 +1985,8 @@ async function hasSymlinkParent(ctx, target) {
|
|
|
1865
1985
|
function listFilesTool(ctx) {
|
|
1866
1986
|
return tool({
|
|
1867
1987
|
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.',
|
|
1868
|
-
inputSchema:
|
|
1869
|
-
path:
|
|
1988
|
+
inputSchema: z6.object({
|
|
1989
|
+
path: z6.string().optional().describe("Directory to list, relative to cwd (default: cwd)")
|
|
1870
1990
|
}),
|
|
1871
1991
|
execute: async ({ path = "." }) => {
|
|
1872
1992
|
logger.info({ path }, "called listFiles tool");
|
|
@@ -1887,13 +2007,13 @@ function listFilesTool(ctx) {
|
|
|
1887
2007
|
|
|
1888
2008
|
// src/lib/tools/changeDirectory.ts
|
|
1889
2009
|
import { tool as tool2 } from "ai";
|
|
1890
|
-
import
|
|
2010
|
+
import z7 from "zod";
|
|
1891
2011
|
import { stat } from "node:fs/promises";
|
|
1892
2012
|
function changeDirectoryTool(ctx) {
|
|
1893
2013
|
return tool2({
|
|
1894
2014
|
description: "Change the current working directory. Subsequent file operations resolve relative to it. Returns the new working directory.",
|
|
1895
|
-
inputSchema:
|
|
1896
|
-
path:
|
|
2015
|
+
inputSchema: z7.object({
|
|
2016
|
+
path: z7.string().describe("Directory to change into")
|
|
1897
2017
|
}),
|
|
1898
2018
|
execute: async ({ path }) => {
|
|
1899
2019
|
logger.info({ path }, "called changeDirectory tool");
|
|
@@ -1915,13 +2035,13 @@ function changeDirectoryTool(ctx) {
|
|
|
1915
2035
|
|
|
1916
2036
|
// src/lib/tools/reportStatus.ts
|
|
1917
2037
|
import { tool as tool3 } from "ai";
|
|
1918
|
-
import
|
|
2038
|
+
import z8 from "zod";
|
|
1919
2039
|
function reportStatusTool(output) {
|
|
1920
2040
|
return tool3({
|
|
1921
2041
|
description: "Report the status of your execution. Return a reason in case of failure.",
|
|
1922
|
-
inputSchema:
|
|
1923
|
-
status:
|
|
1924
|
-
reason:
|
|
2042
|
+
inputSchema: z8.object({
|
|
2043
|
+
status: z8.enum(["success", "fail"]),
|
|
2044
|
+
reason: z8.string().optional(),
|
|
1925
2045
|
output
|
|
1926
2046
|
}),
|
|
1927
2047
|
execute: async ({ status, reason, output: output2 }) => {
|
|
@@ -1933,7 +2053,7 @@ function reportStatusTool(output) {
|
|
|
1933
2053
|
|
|
1934
2054
|
// src/lib/tools/readFile.ts
|
|
1935
2055
|
import { tool as tool4 } from "ai";
|
|
1936
|
-
import
|
|
2056
|
+
import z9 from "zod";
|
|
1937
2057
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
1938
2058
|
|
|
1939
2059
|
// src/lib/tools/env.ts
|
|
@@ -1961,8 +2081,8 @@ function redactEnvValues(content) {
|
|
|
1961
2081
|
function readFileTool(ctx) {
|
|
1962
2082
|
return tool4({
|
|
1963
2083
|
description: "Read the contents of a file at the given path",
|
|
1964
|
-
inputSchema:
|
|
1965
|
-
filePath:
|
|
2084
|
+
inputSchema: z9.object({
|
|
2085
|
+
filePath: z9.string().describe("Path to the file to read")
|
|
1966
2086
|
}),
|
|
1967
2087
|
execute: async ({ filePath }) => {
|
|
1968
2088
|
if (++ctx.counts.read > ctx.limits.read) {
|
|
@@ -1983,15 +2103,15 @@ function readFileTool(ctx) {
|
|
|
1983
2103
|
|
|
1984
2104
|
// src/lib/tools/writeFile.ts
|
|
1985
2105
|
import { tool as tool5 } from "ai";
|
|
1986
|
-
import
|
|
2106
|
+
import z10 from "zod";
|
|
1987
2107
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
|
|
1988
2108
|
import { dirname as dirname3 } from "node:path";
|
|
1989
2109
|
function writeFileTool(ctx) {
|
|
1990
2110
|
return tool5({
|
|
1991
2111
|
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.",
|
|
1992
|
-
inputSchema:
|
|
1993
|
-
filePath:
|
|
1994
|
-
content:
|
|
2112
|
+
inputSchema: z10.object({
|
|
2113
|
+
filePath: z10.string().describe("Path to the file to write"),
|
|
2114
|
+
content: z10.string().describe("Content to write to the file")
|
|
1995
2115
|
}),
|
|
1996
2116
|
execute: async ({ filePath, content }) => {
|
|
1997
2117
|
logger.info({ filePath }, "called writeFile tool");
|
|
@@ -2021,68 +2141,6 @@ import z13 from "zod";
|
|
|
2021
2141
|
import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile5 } from "node:fs/promises";
|
|
2022
2142
|
import { dirname as dirname4, relative as relative3 } from "node:path";
|
|
2023
2143
|
|
|
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
|
-
|
|
2086
2144
|
// src/lib/algoliaApiKey.ts
|
|
2087
2145
|
import { z as z12 } from "zod";
|
|
2088
2146
|
|
|
@@ -2090,13 +2148,13 @@ import { z as z12 } from "zod";
|
|
|
2090
2148
|
import { deletePassword, getPassword, setPassword } from "cross-keychain";
|
|
2091
2149
|
import { z as z11 } from "zod";
|
|
2092
2150
|
var SERVICE = "algolia-wizard";
|
|
2093
|
-
var
|
|
2151
|
+
var account = (userId) => `api-keys:${userId}`;
|
|
2094
2152
|
var storedKeysSchema = z11.record(z11.string(), z11.string());
|
|
2095
2153
|
function entryId(kind, index, appId) {
|
|
2096
2154
|
return `${kind}:${appId}:${index}`;
|
|
2097
2155
|
}
|
|
2098
|
-
async function loadKeys() {
|
|
2099
|
-
const raw = await getPassword(SERVICE,
|
|
2156
|
+
async function loadKeys(userId) {
|
|
2157
|
+
const raw = await getPassword(SERVICE, account(userId));
|
|
2100
2158
|
if (!raw) return {};
|
|
2101
2159
|
let payload;
|
|
2102
2160
|
try {
|
|
@@ -2118,47 +2176,47 @@ function serialized(op) {
|
|
|
2118
2176
|
});
|
|
2119
2177
|
return next;
|
|
2120
2178
|
}
|
|
2121
|
-
async function readStoredKey(kind, index, appId) {
|
|
2179
|
+
async function readStoredKey(kind, userId, index, appId) {
|
|
2122
2180
|
try {
|
|
2123
|
-
return (await loadKeys())[entryId(kind, index, appId)] ?? null;
|
|
2181
|
+
return (await loadKeys(userId))[entryId(kind, index, appId)] ?? null;
|
|
2124
2182
|
} catch (err) {
|
|
2125
2183
|
logger.warn(
|
|
2126
|
-
{ err: err.message, kind, index, appId },
|
|
2184
|
+
{ err: err.message, kind, index, appId, userId },
|
|
2127
2185
|
"could not read the API key from the keychain"
|
|
2128
2186
|
);
|
|
2129
2187
|
return null;
|
|
2130
2188
|
}
|
|
2131
2189
|
}
|
|
2132
|
-
function storeKey(kind, index, appId, value) {
|
|
2190
|
+
function storeKey(kind, userId, index, appId, value) {
|
|
2133
2191
|
return serialized(async () => {
|
|
2134
2192
|
const id = entryId(kind, index, appId);
|
|
2135
2193
|
try {
|
|
2136
|
-
const keys = await loadKeys();
|
|
2194
|
+
const keys = await loadKeys(userId);
|
|
2137
2195
|
await setPassword(
|
|
2138
2196
|
SERVICE,
|
|
2139
|
-
|
|
2197
|
+
account(userId),
|
|
2140
2198
|
JSON.stringify({ ...keys, [id]: value })
|
|
2141
2199
|
);
|
|
2142
|
-
if ((await loadKeys())[id] !== value) {
|
|
2200
|
+
if ((await loadKeys(userId))[id] !== value) {
|
|
2143
2201
|
throw new Error("the keychain did not store the value");
|
|
2144
2202
|
}
|
|
2145
2203
|
} catch (err) {
|
|
2146
2204
|
logger.warn(
|
|
2147
|
-
{ err: err.message, kind, index, appId },
|
|
2205
|
+
{ err: err.message, kind, index, appId, userId },
|
|
2148
2206
|
"could not store the API key in the keychain; the next run will create another"
|
|
2149
2207
|
);
|
|
2150
2208
|
}
|
|
2151
2209
|
});
|
|
2152
2210
|
}
|
|
2153
|
-
function deleteStoredKeys() {
|
|
2211
|
+
function deleteStoredKeys(userId) {
|
|
2154
2212
|
return serialized(async () => {
|
|
2155
2213
|
try {
|
|
2156
|
-
await deletePassword(SERVICE,
|
|
2214
|
+
await deletePassword(SERVICE, account(userId));
|
|
2157
2215
|
} catch (err) {
|
|
2158
2216
|
const message = err.message;
|
|
2159
2217
|
if (/not found/i.test(message)) return;
|
|
2160
2218
|
logger.warn(
|
|
2161
|
-
{ err: message },
|
|
2219
|
+
{ err: message, userId },
|
|
2162
2220
|
"could not delete the API keys from the keychain"
|
|
2163
2221
|
);
|
|
2164
2222
|
}
|
|
@@ -2166,6 +2224,16 @@ function deleteStoredKeys() {
|
|
|
2166
2224
|
}
|
|
2167
2225
|
|
|
2168
2226
|
// src/lib/algoliaApiKey.ts
|
|
2227
|
+
function requireUserId() {
|
|
2228
|
+
const userId = useWizard.getState().user?.userId;
|
|
2229
|
+
if (!userId) {
|
|
2230
|
+
throw new Error("No Algolia user is signed in; cannot scope the API key.");
|
|
2231
|
+
}
|
|
2232
|
+
return userId;
|
|
2233
|
+
}
|
|
2234
|
+
async function currentUserId() {
|
|
2235
|
+
return useWizard.getState().user?.userId ?? (await getUser())?.userId ?? null;
|
|
2236
|
+
}
|
|
2169
2237
|
var WRITE_ACLS = [
|
|
2170
2238
|
"addObject",
|
|
2171
2239
|
"deleteObject",
|
|
@@ -2212,23 +2280,30 @@ async function keyExists(key) {
|
|
|
2212
2280
|
var resolved = /* @__PURE__ */ new Map();
|
|
2213
2281
|
async function forgetResolvedKeys() {
|
|
2214
2282
|
resolved.clear();
|
|
2215
|
-
await
|
|
2283
|
+
const userId = await currentUserId();
|
|
2284
|
+
if (userId) await deleteStoredKeys(userId);
|
|
2216
2285
|
}
|
|
2217
2286
|
function resolveKey(kind, index, appId, acls, description) {
|
|
2218
|
-
const
|
|
2287
|
+
const userId = requireUserId();
|
|
2288
|
+
const cacheKey = `${userId}:${kind}:${appId}:${index}`;
|
|
2219
2289
|
const cached = resolved.get(cacheKey);
|
|
2220
2290
|
if (cached) return cached;
|
|
2221
|
-
const pending = provisionKey(
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2291
|
+
const pending = provisionKey(
|
|
2292
|
+
kind,
|
|
2293
|
+
userId,
|
|
2294
|
+
index,
|
|
2295
|
+
appId,
|
|
2296
|
+
acls,
|
|
2297
|
+
description
|
|
2298
|
+
).catch((err) => {
|
|
2299
|
+
resolved.delete(cacheKey);
|
|
2300
|
+
throw err;
|
|
2301
|
+
});
|
|
2227
2302
|
resolved.set(cacheKey, pending);
|
|
2228
2303
|
return pending;
|
|
2229
2304
|
}
|
|
2230
|
-
async function provisionKey(kind, index, appId, acls, description) {
|
|
2231
|
-
const stored = await readStoredKey(kind, index, appId);
|
|
2305
|
+
async function provisionKey(kind, userId, index, appId, acls, description) {
|
|
2306
|
+
const stored = await readStoredKey(kind, userId, index, appId);
|
|
2232
2307
|
if (stored) {
|
|
2233
2308
|
if (await keyExists(stored)) {
|
|
2234
2309
|
logger.info({ kind, index, appId }, "reusing the stored API key");
|
|
@@ -2240,7 +2315,7 @@ async function provisionKey(kind, index, appId, acls, description) {
|
|
|
2240
2315
|
);
|
|
2241
2316
|
}
|
|
2242
2317
|
const key = await createKey(index, acls, description);
|
|
2243
|
-
await storeKey(kind, index, appId, key);
|
|
2318
|
+
await storeKey(kind, userId, index, appId, key);
|
|
2244
2319
|
return { key, source: "created" };
|
|
2245
2320
|
}
|
|
2246
2321
|
function resolveWriteKey(index, appId) {
|
|
@@ -3509,7 +3584,7 @@ async function runAnalysis(mode, extraInstructions = []) {
|
|
|
3509
3584
|
// package.json
|
|
3510
3585
|
var package_default = {
|
|
3511
3586
|
name: "@algolia/wizard",
|
|
3512
|
-
version: "0.
|
|
3587
|
+
version: "0.48.0-rc.141.344",
|
|
3513
3588
|
description: "Magically implement Algolia functionality in your codebase",
|
|
3514
3589
|
type: "module",
|
|
3515
3590
|
engines: {
|
|
@@ -4224,6 +4299,7 @@ function searchInstructions(input) {
|
|
|
4224
4299
|
return [
|
|
4225
4300
|
"Implement an in-app Algolia search experience.",
|
|
4226
4301
|
`Build the search UI for ${input.searchUiTarget}.`,
|
|
4302
|
+
"Search UI only \u2014 the index is already populated. Do not create or modify ingestion scripts, rake/manage/CLI tasks, migrations, seeders, or other data-loading code, even if the data looks incomplete.",
|
|
4227
4303
|
...doc ? [
|
|
4228
4304
|
"Follow the Algolia SDK reference below for client setup, search UI wiring, and Insights instrumentation \u2014 Insights is required, not optional; prefer the reference over prior knowledge:",
|
|
4229
4305
|
doc
|
|
@@ -4231,9 +4307,12 @@ function searchInstructions(input) {
|
|
|
4231
4307
|
"No bundled Algolia SDK reference exists for this stack, so rely on the project's own conventions and Algolia's official client for its language. Do not invent APIs \u2014 keep to the documented search endpoint and its parameters."
|
|
4232
4308
|
],
|
|
4233
4309
|
`Create the search experience as its own component in a new file, following the project's existing component conventions (location, naming, styling approach). Do not write it inline into an existing file.`,
|
|
4234
|
-
`Import and render that new component from ${input.searchLocation ? `"${input.searchLocation}"` : "the best shared, always-rendered layout location (e.g. a header/nav component)"} so it is reachable across the app \u2014 at least a working search input and results
|
|
4310
|
+
`Import and render that new component from ${input.searchLocation ? `"${input.searchLocation}"` : "the best shared, always-rendered layout location (e.g. a header/nav component)"} so it is reachable across the app \u2014 at least a working search input and results panel against the target index.`,
|
|
4235
4311
|
"If a search box already exists, replace its usage with an import and render of your new component; remove the old implementation.",
|
|
4236
4312
|
"When rendering results with an existing shared component (e.g. a card), import and reuse that component rather than inlining its markup \u2014 inlining silently drops the styles and behavior its own file provides.",
|
|
4313
|
+
"Meet WCAG AA contrast (4.5:1 body text, 3:1 large text/icons) between the panel's text and its own background, and give the input and the active result a focus indicator visible against whatever sits behind it. Style the panel through the widget's class and CSS-variable overrides (or, when hand-built, the app's existing theme tokens) \u2014 never assume a light surface or reuse the surrounding page's colors unchanged inside the panel.",
|
|
4314
|
+
"Vendor theme CSS, and any CSS you write against vendor class names, must be global: import the theme from the component's own script module or the app's global stylesheet, and put overrides in a global block (Astro <style is:global>, an unscoped Vue block, a plain global CSS file). Never a framework-scoped style block or a CSS Module \u2014 scoping rewrites the vendor selectors and the widget's runtime DOM carries no scope attribute, so not one rule matches: styling silently does nothing and the build still passes.",
|
|
4315
|
+
"The panel takes its width from the input by default, so a small input makes it unreadably narrow: give it a min-width of 320px independent of the input, anchored to the input edge it opens from so widening does not push it off-screen.",
|
|
4237
4316
|
`Define ${SEARCH_CONFIG_APP_ID}, ${SEARCH_CONFIG_SEARCH_KEY}, and ${SEARCH_CONFIG_INDEX_NAME} as exported constants in a module that fits this project's existing conventions for shared client-side config \u2014 reuse an existing one if it already holds config like this, or add a small new one otherwise. These are PUBLIC values, safe to commit and expose client-side: never read them from an environment variable or a .env* file, and never hardcode them anywhere except in that one module (import them wherever the search client needs them).`,
|
|
4238
4317
|
`Set ${SEARCH_CONFIG_APP_ID} to "${input.appId}" and ${SEARCH_CONFIG_INDEX_NAME} to "${input.targetIndex}".`,
|
|
4239
4318
|
input.searchKey ? `Set ${SEARCH_CONFIG_SEARCH_KEY} to "${input.searchKey}".` : `A real search-only key could not be provisioned${input.searchKeyError ? ` (${input.searchKeyError})` : ""} \u2014 set ${SEARCH_CONFIG_SEARCH_KEY} to the placeholder "${SEARCH_KEY_PLACEHOLDER}" and add a prominent TODO for the developer to fill in a real one.`,
|
|
@@ -4435,6 +4514,10 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
|
|
|
4435
4514
|
if (useCases.includes("ingestion")) {
|
|
4436
4515
|
ingestAppId = appId ?? (await requireApplication()).id;
|
|
4437
4516
|
}
|
|
4517
|
+
let ingestWriteKey;
|
|
4518
|
+
if (useCases.includes("ingestion") && ingestAppId) {
|
|
4519
|
+
ingestWriteKey = (await resolveWriteKey(targetIndex, ingestAppId)).key;
|
|
4520
|
+
}
|
|
4438
4521
|
let uploadFilePath;
|
|
4439
4522
|
let uploadWarning;
|
|
4440
4523
|
if (ingestionSource === "fileUpload") {
|
|
@@ -4497,9 +4580,9 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
|
|
|
4497
4580
|
let ingestDurationMs;
|
|
4498
4581
|
let ingestOutcomeMessage;
|
|
4499
4582
|
const ingestKeyAppId = ingestAppId;
|
|
4500
|
-
const ingestionTools = ingestKeyAppId ? makeToolContext(repoRoot, async () => ({
|
|
4583
|
+
const ingestionTools = ingestKeyAppId && ingestWriteKey ? makeToolContext(repoRoot, async () => ({
|
|
4501
4584
|
[APP_ID_VAR]: ingestKeyAppId,
|
|
4502
|
-
[API_KEY_VAR]:
|
|
4585
|
+
[API_KEY_VAR]: ingestWriteKey,
|
|
4503
4586
|
[INDEX_NAME_VAR]: targetIndex
|
|
4504
4587
|
})) : void 0;
|
|
4505
4588
|
const searchTools = makeToolContext(repoRoot);
|
|
@@ -5094,13 +5177,13 @@ import { Box as Box15, Text as Text15 } from "ink";
|
|
|
5094
5177
|
|
|
5095
5178
|
// src/ui/Steps.tsx
|
|
5096
5179
|
import { Box as Box13, Text as Text13 } from "ink";
|
|
5097
|
-
import
|
|
5180
|
+
import Spinner2 from "ink-spinner";
|
|
5098
5181
|
import { jsx as jsx11, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
5099
5182
|
function Steps() {
|
|
5100
5183
|
const { steps } = useWizard();
|
|
5101
5184
|
const visibleSteps = steps.filter(isStepVisible);
|
|
5102
5185
|
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: [
|
|
5103
|
-
s.status === "running" ? /* @__PURE__ */ jsx11(
|
|
5186
|
+
s.status === "running" ? /* @__PURE__ */ jsx11(Spinner2, { type: "dots" }) : MARKER[s.status],
|
|
5104
5187
|
" ",
|
|
5105
5188
|
s.title
|
|
5106
5189
|
] }) }, s.id)) });
|
|
@@ -5110,7 +5193,7 @@ function CurrentStep() {
|
|
|
5110
5193
|
const currentStep = steps.filter(isStepVisible).find((s) => s.status === "running");
|
|
5111
5194
|
if (!currentStep) return null;
|
|
5112
5195
|
return /* @__PURE__ */ jsxs12(Text13, { color: COLORS.status.running, children: [
|
|
5113
|
-
/* @__PURE__ */ jsx11(
|
|
5196
|
+
/* @__PURE__ */ jsx11(Spinner2, { type: "dots" }),
|
|
5114
5197
|
" ",
|
|
5115
5198
|
` ${currentStep.title}`
|
|
5116
5199
|
] });
|
|
@@ -5655,6 +5738,7 @@ function App() {
|
|
|
5655
5738
|
inputReq,
|
|
5656
5739
|
user,
|
|
5657
5740
|
workflow,
|
|
5741
|
+
settingUpAppId,
|
|
5658
5742
|
review: review2
|
|
5659
5743
|
} = useWizard();
|
|
5660
5744
|
const { exit } = useApp();
|
|
@@ -5670,7 +5754,7 @@ function App() {
|
|
|
5670
5754
|
const isCommandApprovalPrompt = isAwaitingUserInput && inputReq?.promptType === "commandApproval";
|
|
5671
5755
|
const promptPending = isAwaitingUserInput && !isCommandApprovalPrompt;
|
|
5672
5756
|
const holdForTip = stepHasTips && promptPending && tipState === "revealing";
|
|
5673
|
-
const showTips = stepHasTips && (phase === "running" || isCommandApprovalPrompt || holdForTip);
|
|
5757
|
+
const showTips = stepHasTips && (phase === "running" && currentStep?.status === "running" || isCommandApprovalPrompt || holdForTip);
|
|
5674
5758
|
const showNoticesInMain = !stepHasTips;
|
|
5675
5759
|
const showNotices = (!isAwaitingUserInput || holdForTip) && !review2;
|
|
5676
5760
|
useInput7(
|
|
@@ -5741,20 +5825,26 @@ function App() {
|
|
|
5741
5825
|
children: [
|
|
5742
5826
|
/* @__PURE__ */ jsxs18(Box20, { flexGrow: 2, flexDirection: "column", children: [
|
|
5743
5827
|
phase === "preflight" && !user && /* @__PURE__ */ jsx18(Box20, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs18(Text20, { color: COLORS.strong, bold: true, children: [
|
|
5744
|
-
/* @__PURE__ */ jsx18(
|
|
5828
|
+
/* @__PURE__ */ jsx18(Spinner3, { type: "dots" }),
|
|
5745
5829
|
" Signing in to Algolia"
|
|
5746
5830
|
] }) }),
|
|
5747
5831
|
phase === "preflight" && user && /* @__PURE__ */ jsx18(Box20, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs18(Text20, { color: COLORS.strong, bold: true, children: [
|
|
5748
|
-
/* @__PURE__ */ jsx18(
|
|
5832
|
+
/* @__PURE__ */ jsx18(Spinner3, { type: "dots" }),
|
|
5749
5833
|
" Getting things ready"
|
|
5750
5834
|
] }) }),
|
|
5751
5835
|
phase === "authenticating" && /* @__PURE__ */ jsxs18(Box20, { flexDirection: "column", marginBottom: 1, children: [
|
|
5752
5836
|
/* @__PURE__ */ jsxs18(Text20, { color: COLORS.strong, bold: true, children: [
|
|
5753
|
-
/* @__PURE__ */ jsx18(
|
|
5837
|
+
/* @__PURE__ */ jsx18(Spinner3, { type: "dots" }),
|
|
5754
5838
|
" Signing in to Algolia"
|
|
5755
5839
|
] }),
|
|
5756
5840
|
/* @__PURE__ */ jsx18(Text20, { color: COLORS.muted, children: "A browser window will open \u2014 complete sign-in there." })
|
|
5757
5841
|
] }),
|
|
5842
|
+
settingUpAppId && /* @__PURE__ */ jsx18(Box20, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs18(Text20, { color: COLORS.strong, bold: true, children: [
|
|
5843
|
+
/* @__PURE__ */ jsx18(Spinner3, { type: "dots" }),
|
|
5844
|
+
" Setting up Wizard using app",
|
|
5845
|
+
" ",
|
|
5846
|
+
settingUpAppId
|
|
5847
|
+
] }) }),
|
|
5758
5848
|
/* @__PURE__ */ jsx18(CliOutput, {}),
|
|
5759
5849
|
showTips && currentStep && /* @__PURE__ */ jsx18(
|
|
5760
5850
|
Tips,
|
|
@@ -5825,54 +5915,71 @@ function readValue(raw) {
|
|
|
5825
5915
|
}
|
|
5826
5916
|
|
|
5827
5917
|
// src/lib/algoliaAppPicker.ts
|
|
5828
|
-
function
|
|
5918
|
+
function blockReasonFor(app) {
|
|
5919
|
+
return app.status !== "active" ? "Paused" : "Missing permissions";
|
|
5920
|
+
}
|
|
5921
|
+
function secondaryFor(app, highlightId) {
|
|
5922
|
+
if (!canSelectApplication(app)) {
|
|
5923
|
+
return { kind: "text", value: blockReasonFor(app) };
|
|
5924
|
+
}
|
|
5925
|
+
if (app.id === highlightId) {
|
|
5926
|
+
return { kind: "badge", value: "[DETECTED]" };
|
|
5927
|
+
}
|
|
5829
5928
|
return app.plan ? { kind: "badge", value: app.plan } : void 0;
|
|
5830
5929
|
}
|
|
5831
5930
|
function labelFor(app) {
|
|
5832
5931
|
return app.name.trim() ? `${app.name} \u2014 ${app.id}` : app.id;
|
|
5833
5932
|
}
|
|
5834
|
-
function selectAndReport(
|
|
5835
|
-
useWizard.getState()
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5933
|
+
async function selectAndReport(id) {
|
|
5934
|
+
const store = useWizard.getState();
|
|
5935
|
+
store.setSettingUpApp(id);
|
|
5936
|
+
try {
|
|
5937
|
+
return await selectApplication(id);
|
|
5938
|
+
} finally {
|
|
5939
|
+
store.setSettingUpApp(null);
|
|
5940
|
+
}
|
|
5840
5941
|
}
|
|
5841
|
-
async function promptForApplication(
|
|
5942
|
+
async function promptForApplication(highlight) {
|
|
5842
5943
|
const store = useWizard.getState();
|
|
5843
|
-
const
|
|
5844
|
-
if (
|
|
5944
|
+
const unordered = await listApplications();
|
|
5945
|
+
if (unordered.length === 0) {
|
|
5845
5946
|
throw new Error(
|
|
5846
5947
|
"This Algolia account has no applications. Create one in the Algolia dashboard, or with `npx @algolia/cli@latest application create`, then restart the wizard."
|
|
5847
5948
|
);
|
|
5848
5949
|
}
|
|
5849
|
-
if (
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
{ app: only.id },
|
|
5853
|
-
"single application on the account; selecting it"
|
|
5950
|
+
if (!unordered.some(canSelectApplication)) {
|
|
5951
|
+
throw new Error(
|
|
5952
|
+
"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."
|
|
5854
5953
|
);
|
|
5855
|
-
for (const line of leadIn) store.pushCliOutput("stdout", line);
|
|
5856
|
-
return selectAndReport(only);
|
|
5857
5954
|
}
|
|
5858
|
-
const
|
|
5859
|
-
...
|
|
5860
|
-
|
|
5955
|
+
const apps = [
|
|
5956
|
+
...unordered.filter(canSelectApplication),
|
|
5957
|
+
...unordered.filter((app) => !canSelectApplication(app))
|
|
5861
5958
|
];
|
|
5959
|
+
const envApp = highlight ? unordered.find((app) => app.id === highlight.id) : void 0;
|
|
5960
|
+
const highlightIndex = envApp && canSelectApplication(envApp) ? apps.indexOf(envApp) : -1;
|
|
5961
|
+
const messages = [];
|
|
5962
|
+
if (highlight && highlightIndex < 0) {
|
|
5963
|
+
messages.push(
|
|
5964
|
+
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.`
|
|
5965
|
+
);
|
|
5966
|
+
}
|
|
5862
5967
|
for (; ; ) {
|
|
5863
5968
|
const choice = await store.requestUserInput({
|
|
5864
|
-
prompt: "
|
|
5969
|
+
prompt: "Which Algolia application should the wizard work in?",
|
|
5865
5970
|
promptType: "multipleChoice",
|
|
5866
5971
|
options: apps.map(labelFor),
|
|
5867
|
-
secondary: apps.map(secondaryFor),
|
|
5972
|
+
secondary: apps.map((app) => secondaryFor(app, highlight?.id)),
|
|
5973
|
+
disabled: apps.map((app) => !canSelectApplication(app)),
|
|
5974
|
+
...highlightIndex >= 0 ? { defaultSelectedIndex: highlightIndex } : {},
|
|
5868
5975
|
messages
|
|
5869
5976
|
});
|
|
5870
5977
|
const chosen = apps.find((app) => labelFor(app) === choice);
|
|
5871
|
-
if (!chosen) {
|
|
5978
|
+
if (!chosen || !canSelectApplication(chosen)) {
|
|
5872
5979
|
throw new Error("Application picker received an unexpected selection");
|
|
5873
5980
|
}
|
|
5874
5981
|
try {
|
|
5875
|
-
return await selectAndReport(chosen);
|
|
5982
|
+
return await selectAndReport(chosen.id);
|
|
5876
5983
|
} catch (err) {
|
|
5877
5984
|
logger.warn(
|
|
5878
5985
|
{ app: chosen.id, err: err.message },
|
|
@@ -5884,42 +5991,11 @@ async function promptForApplication(leadIn = []) {
|
|
|
5884
5991
|
}
|
|
5885
5992
|
}
|
|
5886
5993
|
}
|
|
5887
|
-
async function
|
|
5888
|
-
|
|
5889
|
-
const choice = await useWizard.getState().requestUserInput({
|
|
5890
|
-
prompt: "Select an application",
|
|
5891
|
-
promptType: "multipleChoice",
|
|
5892
|
-
options: [
|
|
5893
|
-
useEnv,
|
|
5894
|
-
current ? `Use ${labelFor(current)} (already selected)` : "Pick a different application"
|
|
5895
|
-
],
|
|
5896
|
-
messages: [
|
|
5897
|
-
`${env.file} already sets ${env.name}=${env.id}.`,
|
|
5898
|
-
"Which Algolia application should the wizard work in?"
|
|
5899
|
-
]
|
|
5900
|
-
});
|
|
5901
|
-
return choice === useEnv;
|
|
5902
|
-
}
|
|
5903
|
-
async function selectEnvApplication(env) {
|
|
5904
|
-
try {
|
|
5905
|
-
return await selectAndReport({ id: env.id, name: "" });
|
|
5906
|
-
} catch (err) {
|
|
5907
|
-
logger.warn(
|
|
5908
|
-
{ app: env.id, err: err.message },
|
|
5909
|
-
"could not select the application named in env; falling back to the picker"
|
|
5910
|
-
);
|
|
5911
|
-
return promptForApplication([
|
|
5912
|
-
`Could not select ${env.id} from ${env.file} \u2014 it may have been removed, or this account may not have access to it.`
|
|
5913
|
-
]);
|
|
5914
|
-
}
|
|
5915
|
-
}
|
|
5916
|
-
async function ensureApplication() {
|
|
5917
|
-
const current = await currentApplication();
|
|
5994
|
+
async function ensureApplication(resumeAppId) {
|
|
5995
|
+
if (resumeAppId) return selectAndReport(resumeAppId);
|
|
5918
5996
|
const env = await findEnvApplicationId();
|
|
5919
|
-
if (env
|
|
5920
|
-
|
|
5921
|
-
}
|
|
5922
|
-
return current ?? await promptForApplication();
|
|
5997
|
+
if (!env) return promptForApplication();
|
|
5998
|
+
return promptForApplication({ id: env.id, file: env.file });
|
|
5923
5999
|
}
|
|
5924
6000
|
|
|
5925
6001
|
// src/lib/seed.ts
|
|
@@ -6283,14 +6359,17 @@ async function run(workflow) {
|
|
|
6283
6359
|
}
|
|
6284
6360
|
store.setUser(user);
|
|
6285
6361
|
let app;
|
|
6362
|
+
const resumableState = await loadResumableState(workflow);
|
|
6286
6363
|
try {
|
|
6287
|
-
app = await ensureApplication(
|
|
6364
|
+
app = await ensureApplication(
|
|
6365
|
+
resumableState ? runAppId(resumableState) : void 0
|
|
6366
|
+
);
|
|
6288
6367
|
} catch (err) {
|
|
6289
6368
|
store.setError(err instanceof Error ? err.message : String(err));
|
|
6290
6369
|
await instance.waitUntilExit();
|
|
6291
6370
|
process.exit(1);
|
|
6292
6371
|
}
|
|
6293
|
-
runWorkflow(workflow, app.id);
|
|
6372
|
+
runWorkflow(workflow, app.id, resumableState);
|
|
6294
6373
|
}
|
|
6295
6374
|
await requestTerminalSize();
|
|
6296
6375
|
var started = await startup();
|