@algolia/wizard 0.37.0 → 0.38.0-rc.131.266
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 +245 -159
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -258,10 +258,14 @@ var useWizard = create((set, get) => ({
|
|
|
258
258
|
error: null,
|
|
259
259
|
inputReq: null,
|
|
260
260
|
_resolve: null,
|
|
261
|
+
settingUpAppId: null,
|
|
262
|
+
setSettingUpApp: (appId) => set({ settingUpAppId: appId }),
|
|
261
263
|
// `endAuth` lands on 'preflight', not 'idle': sign-in happens after the
|
|
262
264
|
// welcome screen, so going back would gate the run a second time.
|
|
263
265
|
beginAuth: () => set({ phase: "authenticating", cliOutput: [] }),
|
|
264
|
-
endAuth: () => set(
|
|
266
|
+
endAuth: () => set(
|
|
267
|
+
(s) => s.phase === "authenticating" ? { phase: "preflight", cliOutput: [] } : {}
|
|
268
|
+
),
|
|
265
269
|
confirmStart: () => set(
|
|
266
270
|
(s) => s.phase === "idle" ? { phase: "preflight", homeScreen: "home" } : {}
|
|
267
271
|
),
|
|
@@ -405,7 +409,8 @@ var useWizard = create((set, get) => ({
|
|
|
405
409
|
logs: [],
|
|
406
410
|
error: null,
|
|
407
411
|
inputReq: null,
|
|
408
|
-
_resolve: null
|
|
412
|
+
_resolve: null,
|
|
413
|
+
settingUpAppId: null
|
|
409
414
|
});
|
|
410
415
|
}
|
|
411
416
|
}));
|
|
@@ -653,25 +658,27 @@ function SelectRow({
|
|
|
653
658
|
labelWidth,
|
|
654
659
|
highlightBackground = true,
|
|
655
660
|
usePadding = false,
|
|
661
|
+
disabled = false,
|
|
656
662
|
children
|
|
657
663
|
}) {
|
|
658
|
-
const
|
|
664
|
+
const active = highlighted && !disabled;
|
|
665
|
+
const labelColor = disabled ? COLORS.dim : active ? highlightBackground ? COLORS.highlight.fg : COLORS.success : COLORS.primary;
|
|
659
666
|
return /* @__PURE__ */ jsxs3(
|
|
660
667
|
Box4,
|
|
661
668
|
{
|
|
662
669
|
width,
|
|
663
670
|
paddingX: usePadding ? 1 : 0,
|
|
664
671
|
paddingY: usePadding ? 1 : 0,
|
|
665
|
-
backgroundColor:
|
|
672
|
+
backgroundColor: active && highlightBackground ? COLORS.highlight.bg : void 0,
|
|
666
673
|
children: [
|
|
667
674
|
/* @__PURE__ */ jsx3(Box4, { width: labelWidth, children: /* @__PURE__ */ jsxs3(
|
|
668
675
|
Text4,
|
|
669
676
|
{
|
|
670
677
|
color: labelColor,
|
|
671
|
-
bold:
|
|
678
|
+
bold: active && !highlightBackground,
|
|
672
679
|
wrap: "truncate",
|
|
673
680
|
children: [
|
|
674
|
-
|
|
681
|
+
active ? "\u276F " : " ",
|
|
675
682
|
label
|
|
676
683
|
]
|
|
677
684
|
}
|
|
@@ -870,6 +877,14 @@ var ARROW_WIDTH = 4;
|
|
|
870
877
|
var COLUMN_GAP = 2;
|
|
871
878
|
var BAR_PADDING = 2;
|
|
872
879
|
var ROW_HEIGHT = 3;
|
|
880
|
+
function nextSelectableIndex(start, dir, rowCount, isDisabled) {
|
|
881
|
+
let i = start;
|
|
882
|
+
for (let step = 0; step < rowCount; step++) {
|
|
883
|
+
i = (i + dir + rowCount) % rowCount;
|
|
884
|
+
if (!isDisabled(i)) return i;
|
|
885
|
+
}
|
|
886
|
+
return start;
|
|
887
|
+
}
|
|
873
888
|
function SelectPrompt({
|
|
874
889
|
options,
|
|
875
890
|
onSelect,
|
|
@@ -881,15 +896,18 @@ function SelectPrompt({
|
|
|
881
896
|
multi,
|
|
882
897
|
cancelable,
|
|
883
898
|
secondary,
|
|
899
|
+
disabled,
|
|
884
900
|
defaultSelectedIndex = 0
|
|
885
901
|
}) {
|
|
886
|
-
const [index, setIndex] = useState5(
|
|
887
|
-
() => defaultSelectedIndex > 0 && defaultSelectedIndex < options.length ? defaultSelectedIndex : 0
|
|
888
|
-
);
|
|
889
|
-
const [checked, setChecked] = useState5(() => /* @__PURE__ */ new Set());
|
|
890
902
|
const hasCancel = Boolean(multi || cancelable);
|
|
891
903
|
const rows = hasCancel ? [...options, "Cancel"] : options;
|
|
892
904
|
const cancelIndex = hasCancel ? options.length : -1;
|
|
905
|
+
const isDisabled = (i) => i !== cancelIndex && Boolean(disabled?.[i]);
|
|
906
|
+
const [index, setIndex] = useState5(() => {
|
|
907
|
+
const start = defaultSelectedIndex > 0 && defaultSelectedIndex < options.length ? defaultSelectedIndex : 0;
|
|
908
|
+
return isDisabled(start) ? nextSelectableIndex(start, 1, rows.length, isDisabled) : start;
|
|
909
|
+
});
|
|
910
|
+
const [checked, setChecked] = useState5(() => /* @__PURE__ */ new Set());
|
|
893
911
|
const hints = [];
|
|
894
912
|
if (rows.length > 1) hints.push({ key: "[\u2191] [\u2193]", label: "move" });
|
|
895
913
|
if (multi) hints.push({ key: "[space]", label: "select" });
|
|
@@ -929,9 +947,15 @@ function SelectPrompt({
|
|
|
929
947
|
useInput2((input, key) => {
|
|
930
948
|
if (rows.length === 0) return;
|
|
931
949
|
if (key.upArrow || input === "k") {
|
|
932
|
-
setIndex((i) =>
|
|
950
|
+
setIndex((i) => {
|
|
951
|
+
const next = (i - 1 + rows.length) % rows.length;
|
|
952
|
+
return isDisabled(next) ? i : next;
|
|
953
|
+
});
|
|
933
954
|
} else if (key.downArrow || input === "j") {
|
|
934
|
-
setIndex((i) =>
|
|
955
|
+
setIndex((i) => {
|
|
956
|
+
const next = (i + 1) % rows.length;
|
|
957
|
+
return isDisabled(next) ? i : next;
|
|
958
|
+
});
|
|
935
959
|
} else if (multi && input === " " && index !== cancelIndex) {
|
|
936
960
|
setChecked((prev) => {
|
|
937
961
|
const next = new Set(prev);
|
|
@@ -942,6 +966,7 @@ function SelectPrompt({
|
|
|
942
966
|
} else if (key.return) {
|
|
943
967
|
if (index === cancelIndex) {
|
|
944
968
|
onSelect(CANCEL);
|
|
969
|
+
} else if (isDisabled(index)) {
|
|
945
970
|
} else if (!multi) {
|
|
946
971
|
onSelect(options[index]);
|
|
947
972
|
} else if (checked.size > 0) {
|
|
@@ -966,10 +991,12 @@ function SelectPrompt({
|
|
|
966
991
|
const bullet = multi && !isCancel ? checked.has(i) ? "\u25CF " : "\u25CB " : "";
|
|
967
992
|
const sec = isCancel ? void 0 : secondary?.[i];
|
|
968
993
|
const isText = sec?.kind === "text";
|
|
994
|
+
const rowDisabled = isDisabled(i);
|
|
969
995
|
return /* @__PURE__ */ jsxs7(
|
|
970
996
|
SelectRow,
|
|
971
997
|
{
|
|
972
998
|
highlighted,
|
|
999
|
+
disabled: rowDisabled,
|
|
973
1000
|
width: isText ? "100%" : barWidth,
|
|
974
1001
|
labelWidth: isText ? labelWidth : barLabelWidth,
|
|
975
1002
|
label: `${bullet}${option}`,
|
|
@@ -979,7 +1006,7 @@ function SelectPrompt({
|
|
|
979
1006
|
Text8,
|
|
980
1007
|
{
|
|
981
1008
|
wrap: "truncate",
|
|
982
|
-
color: highlighted ? COLORS.primary : COLORS.muted,
|
|
1009
|
+
color: rowDisabled ? COLORS.dim : highlighted ? COLORS.primary : COLORS.muted,
|
|
983
1010
|
children: sec.value
|
|
984
1011
|
}
|
|
985
1012
|
) }),
|
|
@@ -1041,6 +1068,7 @@ function PromptInput() {
|
|
|
1041
1068
|
table: inputReq.table,
|
|
1042
1069
|
options: inputReq.options,
|
|
1043
1070
|
secondary: inputReq.secondary,
|
|
1071
|
+
disabled: inputReq.disabled,
|
|
1044
1072
|
defaultSelectedIndex: inputReq.defaultSelectedIndex,
|
|
1045
1073
|
cancelable: inputReq.cancelable,
|
|
1046
1074
|
error: inputReq.error,
|
|
@@ -1112,7 +1140,7 @@ function PromptInput() {
|
|
|
1112
1140
|
inputReq.prompt,
|
|
1113
1141
|
" "
|
|
1114
1142
|
] }),
|
|
1115
|
-
/* @__PURE__ */ jsx7(
|
|
1143
|
+
/* @__PURE__ */ jsx7(Text9, { color: COLORS.primary, children: /* @__PURE__ */ jsx7(
|
|
1116
1144
|
TextInput,
|
|
1117
1145
|
{
|
|
1118
1146
|
value: draft,
|
|
@@ -1122,7 +1150,7 @@ function PromptInput() {
|
|
|
1122
1150
|
setDraft("");
|
|
1123
1151
|
}
|
|
1124
1152
|
}
|
|
1125
|
-
)
|
|
1153
|
+
) })
|
|
1126
1154
|
] })
|
|
1127
1155
|
] });
|
|
1128
1156
|
}
|
|
@@ -1404,6 +1432,10 @@ function reconcileWorkflowState(state, workflow) {
|
|
|
1404
1432
|
}
|
|
1405
1433
|
return state;
|
|
1406
1434
|
}
|
|
1435
|
+
async function isResumableWorkflow(workflow) {
|
|
1436
|
+
const persisted = await loadWorkflowState(workflow.id);
|
|
1437
|
+
return persisted != null && reconcileWorkflowState(persisted, workflow) != null;
|
|
1438
|
+
}
|
|
1407
1439
|
function initWorkflowState(workflow, now) {
|
|
1408
1440
|
return {
|
|
1409
1441
|
workflowId: workflow.id,
|
|
@@ -1600,14 +1632,89 @@ async function listIndices() {
|
|
|
1600
1632
|
return items.map((i) => ({ name: i.name, entries: i.entries })).sort((a, b) => a.name.localeCompare(b.name));
|
|
1601
1633
|
}
|
|
1602
1634
|
|
|
1635
|
+
// src/lib/algoliaApp.ts
|
|
1636
|
+
import { z as z5 } from "zod";
|
|
1637
|
+
var applicationSchema = z5.object({
|
|
1638
|
+
id: z5.string().min(1),
|
|
1639
|
+
name: z5.string().default(""),
|
|
1640
|
+
plan: z5.string().optional()
|
|
1641
|
+
});
|
|
1642
|
+
var listSchema = z5.array(
|
|
1643
|
+
z5.object({
|
|
1644
|
+
id: z5.string().min(1),
|
|
1645
|
+
name: z5.string().default(""),
|
|
1646
|
+
plan_label: z5.string().optional(),
|
|
1647
|
+
status: z5.string().optional(),
|
|
1648
|
+
acl: z5.array(z5.string()).optional()
|
|
1649
|
+
}).transform(({ id, name, plan_label, status, acl }) => ({
|
|
1650
|
+
id,
|
|
1651
|
+
name,
|
|
1652
|
+
plan: plan_label,
|
|
1653
|
+
status,
|
|
1654
|
+
acl
|
|
1655
|
+
}))
|
|
1656
|
+
);
|
|
1657
|
+
function canSelectApplication(app) {
|
|
1658
|
+
return app.status === "active" && (app.acl ?? []).includes("keys");
|
|
1659
|
+
}
|
|
1660
|
+
async function currentApplication() {
|
|
1661
|
+
let raw;
|
|
1662
|
+
try {
|
|
1663
|
+
raw = await runAlgoliaCli(["application", "current", "-o", "json"]);
|
|
1664
|
+
} catch {
|
|
1665
|
+
return null;
|
|
1666
|
+
}
|
|
1667
|
+
const parsed = applicationSchema.safeParse(parseJson(raw));
|
|
1668
|
+
return parsed.success ? parsed.data : null;
|
|
1669
|
+
}
|
|
1670
|
+
async function requireApplication() {
|
|
1671
|
+
const app = await currentApplication();
|
|
1672
|
+
if (!app) {
|
|
1673
|
+
throw new Error(
|
|
1674
|
+
"No Algolia application is selected. Run `npx @algolia/cli@latest application select` and restart the wizard."
|
|
1675
|
+
);
|
|
1676
|
+
}
|
|
1677
|
+
return app;
|
|
1678
|
+
}
|
|
1679
|
+
async function listApplications() {
|
|
1680
|
+
const raw = await runAlgoliaCli(["application", "list", "-o", "json"]);
|
|
1681
|
+
const parsed = listSchema.safeParse(parseJson(raw));
|
|
1682
|
+
if (!parsed.success) {
|
|
1683
|
+
throw new Error("Could not read the list of Algolia applications.");
|
|
1684
|
+
}
|
|
1685
|
+
return parsed.data;
|
|
1686
|
+
}
|
|
1687
|
+
async function selectApplication(id) {
|
|
1688
|
+
const raw = await runAlgoliaCli(
|
|
1689
|
+
["application", "select", "--non-interactive", "--app-id", id],
|
|
1690
|
+
{ onOutput: stderrSink }
|
|
1691
|
+
);
|
|
1692
|
+
const parsed = applicationSchema.safeParse(parseJson(raw));
|
|
1693
|
+
if (!parsed.success) {
|
|
1694
|
+
throw new Error(
|
|
1695
|
+
`Selected application ${id}, but the Algolia CLI returned an unreadable result.`
|
|
1696
|
+
);
|
|
1697
|
+
}
|
|
1698
|
+
return parsed.data;
|
|
1699
|
+
}
|
|
1700
|
+
function parseJson(text) {
|
|
1701
|
+
try {
|
|
1702
|
+
return JSON.parse(text);
|
|
1703
|
+
} catch {
|
|
1704
|
+
return void 0;
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1603
1708
|
// src/actions/selectIndex.ts
|
|
1604
1709
|
var CREATE_NEW_INDEX = "Create a new index\u2026";
|
|
1605
1710
|
var selectIndexStep = async (ctx) => {
|
|
1711
|
+
await requireApplication();
|
|
1606
1712
|
const indices = await listIndices();
|
|
1607
1713
|
const names = indices.map((i) => i.name);
|
|
1608
1714
|
const hasIndices = names.length > 0;
|
|
1609
1715
|
let error;
|
|
1610
|
-
|
|
1716
|
+
let chosen;
|
|
1717
|
+
while (chosen === void 0) {
|
|
1611
1718
|
const selection = hasIndices ? await ctx.requestUserInput({
|
|
1612
1719
|
prompt: "Which index do you want to ingest into?",
|
|
1613
1720
|
promptType: "multipleChoice",
|
|
@@ -1626,9 +1733,9 @@ var selectIndexStep = async (ctx) => {
|
|
|
1626
1733
|
if (typeof selection !== "string") {
|
|
1627
1734
|
throw new Error("selectIndex received an unexpected non-text result");
|
|
1628
1735
|
}
|
|
1629
|
-
let
|
|
1736
|
+
let candidate;
|
|
1630
1737
|
if (!hasIndices) {
|
|
1631
|
-
|
|
1738
|
+
candidate = selection.trim();
|
|
1632
1739
|
} else if (selection === CREATE_NEW_INDEX) {
|
|
1633
1740
|
const name = await ctx.requestUserInput({
|
|
1634
1741
|
prompt: "Name the new index:",
|
|
@@ -1638,17 +1745,18 @@ var selectIndexStep = async (ctx) => {
|
|
|
1638
1745
|
if (typeof name !== "string") {
|
|
1639
1746
|
throw new Error("selectIndex received an unexpected non-text result");
|
|
1640
1747
|
}
|
|
1641
|
-
|
|
1748
|
+
candidate = name.trim();
|
|
1642
1749
|
} else {
|
|
1643
|
-
|
|
1750
|
+
candidate = selection;
|
|
1644
1751
|
}
|
|
1645
|
-
if (!
|
|
1752
|
+
if (!candidate) {
|
|
1646
1753
|
error = "Index name cannot be empty.";
|
|
1647
1754
|
continue;
|
|
1648
1755
|
}
|
|
1649
|
-
|
|
1650
|
-
return { selection: chosen };
|
|
1756
|
+
chosen = candidate;
|
|
1651
1757
|
}
|
|
1758
|
+
ctx.setUserInput("index", chosen);
|
|
1759
|
+
return { selection: chosen };
|
|
1652
1760
|
};
|
|
1653
1761
|
|
|
1654
1762
|
// src/lib/agent.ts
|
|
@@ -1661,7 +1769,7 @@ import "zod";
|
|
|
1661
1769
|
|
|
1662
1770
|
// src/lib/tools/listFiles.ts
|
|
1663
1771
|
import { tool } from "ai";
|
|
1664
|
-
import
|
|
1772
|
+
import z6 from "zod";
|
|
1665
1773
|
import { readdir } from "node:fs/promises";
|
|
1666
1774
|
|
|
1667
1775
|
// src/lib/tools/path.ts
|
|
@@ -1697,8 +1805,8 @@ async function hasSymlinkParent(ctx, target) {
|
|
|
1697
1805
|
function listFilesTool(ctx) {
|
|
1698
1806
|
return tool({
|
|
1699
1807
|
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.',
|
|
1700
|
-
inputSchema:
|
|
1701
|
-
path:
|
|
1808
|
+
inputSchema: z6.object({
|
|
1809
|
+
path: z6.string().optional().describe("Directory to list, relative to cwd (default: cwd)")
|
|
1702
1810
|
}),
|
|
1703
1811
|
execute: async ({ path = "." }) => {
|
|
1704
1812
|
logger.info({ path }, "called listFiles tool");
|
|
@@ -1719,13 +1827,13 @@ function listFilesTool(ctx) {
|
|
|
1719
1827
|
|
|
1720
1828
|
// src/lib/tools/changeDirectory.ts
|
|
1721
1829
|
import { tool as tool2 } from "ai";
|
|
1722
|
-
import
|
|
1830
|
+
import z7 from "zod";
|
|
1723
1831
|
import { stat } from "node:fs/promises";
|
|
1724
1832
|
function changeDirectoryTool(ctx) {
|
|
1725
1833
|
return tool2({
|
|
1726
1834
|
description: "Change the current working directory. Subsequent file operations resolve relative to it. Returns the new working directory.",
|
|
1727
|
-
inputSchema:
|
|
1728
|
-
path:
|
|
1835
|
+
inputSchema: z7.object({
|
|
1836
|
+
path: z7.string().describe("Directory to change into")
|
|
1729
1837
|
}),
|
|
1730
1838
|
execute: async ({ path }) => {
|
|
1731
1839
|
logger.info({ path }, "called changeDirectory tool");
|
|
@@ -1747,13 +1855,13 @@ function changeDirectoryTool(ctx) {
|
|
|
1747
1855
|
|
|
1748
1856
|
// src/lib/tools/reportStatus.ts
|
|
1749
1857
|
import { tool as tool3 } from "ai";
|
|
1750
|
-
import
|
|
1858
|
+
import z8 from "zod";
|
|
1751
1859
|
function reportStatusTool(output) {
|
|
1752
1860
|
return tool3({
|
|
1753
1861
|
description: "Report the status of your execution. Return a reason in case of failure.",
|
|
1754
|
-
inputSchema:
|
|
1755
|
-
status:
|
|
1756
|
-
reason:
|
|
1862
|
+
inputSchema: z8.object({
|
|
1863
|
+
status: z8.enum(["success", "fail"]),
|
|
1864
|
+
reason: z8.string().optional(),
|
|
1757
1865
|
output
|
|
1758
1866
|
}),
|
|
1759
1867
|
execute: async ({ status, reason, output: output2 }) => {
|
|
@@ -1765,7 +1873,7 @@ function reportStatusTool(output) {
|
|
|
1765
1873
|
|
|
1766
1874
|
// src/lib/tools/readFile.ts
|
|
1767
1875
|
import { tool as tool4 } from "ai";
|
|
1768
|
-
import
|
|
1876
|
+
import z9 from "zod";
|
|
1769
1877
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
1770
1878
|
|
|
1771
1879
|
// src/lib/tools/env.ts
|
|
@@ -1793,8 +1901,8 @@ function redactEnvValues(content) {
|
|
|
1793
1901
|
function readFileTool(ctx) {
|
|
1794
1902
|
return tool4({
|
|
1795
1903
|
description: "Read the contents of a file at the given path",
|
|
1796
|
-
inputSchema:
|
|
1797
|
-
filePath:
|
|
1904
|
+
inputSchema: z9.object({
|
|
1905
|
+
filePath: z9.string().describe("Path to the file to read")
|
|
1798
1906
|
}),
|
|
1799
1907
|
execute: async ({ filePath }) => {
|
|
1800
1908
|
if (++ctx.counts.read > ctx.limits.read) {
|
|
@@ -1815,15 +1923,15 @@ function readFileTool(ctx) {
|
|
|
1815
1923
|
|
|
1816
1924
|
// src/lib/tools/writeFile.ts
|
|
1817
1925
|
import { tool as tool5 } from "ai";
|
|
1818
|
-
import
|
|
1926
|
+
import z10 from "zod";
|
|
1819
1927
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
|
|
1820
1928
|
import { dirname as dirname3 } from "node:path";
|
|
1821
1929
|
function writeFileTool(ctx) {
|
|
1822
1930
|
return tool5({
|
|
1823
1931
|
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.",
|
|
1824
|
-
inputSchema:
|
|
1825
|
-
filePath:
|
|
1826
|
-
content:
|
|
1932
|
+
inputSchema: z10.object({
|
|
1933
|
+
filePath: z10.string().describe("Path to the file to write"),
|
|
1934
|
+
content: z10.string().describe("Content to write to the file")
|
|
1827
1935
|
}),
|
|
1828
1936
|
execute: async ({ filePath, content }) => {
|
|
1829
1937
|
logger.info({ filePath }, "called writeFile tool");
|
|
@@ -1853,68 +1961,6 @@ import z13 from "zod";
|
|
|
1853
1961
|
import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile5 } from "node:fs/promises";
|
|
1854
1962
|
import { dirname as dirname4, relative as relative3 } from "node:path";
|
|
1855
1963
|
|
|
1856
|
-
// src/lib/algoliaApp.ts
|
|
1857
|
-
import { z as z10 } from "zod";
|
|
1858
|
-
var applicationSchema = z10.object({
|
|
1859
|
-
id: z10.string().min(1),
|
|
1860
|
-
name: z10.string().default(""),
|
|
1861
|
-
plan: z10.string().optional()
|
|
1862
|
-
});
|
|
1863
|
-
var listSchema = z10.array(
|
|
1864
|
-
z10.object({
|
|
1865
|
-
id: z10.string().min(1),
|
|
1866
|
-
name: z10.string().default(""),
|
|
1867
|
-
plan_label: z10.string().optional()
|
|
1868
|
-
}).transform(({ id, name, plan_label }) => ({ id, name, plan: plan_label }))
|
|
1869
|
-
);
|
|
1870
|
-
async function currentApplication() {
|
|
1871
|
-
let raw;
|
|
1872
|
-
try {
|
|
1873
|
-
raw = await runAlgoliaCli(["application", "current", "-o", "json"]);
|
|
1874
|
-
} catch {
|
|
1875
|
-
return null;
|
|
1876
|
-
}
|
|
1877
|
-
const parsed = applicationSchema.safeParse(parseJson(raw));
|
|
1878
|
-
return parsed.success ? parsed.data : null;
|
|
1879
|
-
}
|
|
1880
|
-
async function requireApplication() {
|
|
1881
|
-
const app = await currentApplication();
|
|
1882
|
-
if (!app) {
|
|
1883
|
-
throw new Error(
|
|
1884
|
-
"No Algolia application is selected. Run `npx @algolia/cli@latest application select` and restart the wizard."
|
|
1885
|
-
);
|
|
1886
|
-
}
|
|
1887
|
-
return app;
|
|
1888
|
-
}
|
|
1889
|
-
async function listApplications() {
|
|
1890
|
-
const raw = await runAlgoliaCli(["application", "list", "-o", "json"]);
|
|
1891
|
-
const parsed = listSchema.safeParse(parseJson(raw));
|
|
1892
|
-
if (!parsed.success) {
|
|
1893
|
-
throw new Error("Could not read the list of Algolia applications.");
|
|
1894
|
-
}
|
|
1895
|
-
return parsed.data;
|
|
1896
|
-
}
|
|
1897
|
-
async function selectApplication(id) {
|
|
1898
|
-
const raw = await runAlgoliaCli(
|
|
1899
|
-
["application", "select", "--non-interactive", "--app-id", id],
|
|
1900
|
-
{ onOutput: stderrSink }
|
|
1901
|
-
);
|
|
1902
|
-
const parsed = applicationSchema.safeParse(parseJson(raw));
|
|
1903
|
-
if (!parsed.success) {
|
|
1904
|
-
throw new Error(
|
|
1905
|
-
`Selected application ${id}, but the Algolia CLI returned an unreadable result.`
|
|
1906
|
-
);
|
|
1907
|
-
}
|
|
1908
|
-
return parsed.data;
|
|
1909
|
-
}
|
|
1910
|
-
function parseJson(text) {
|
|
1911
|
-
try {
|
|
1912
|
-
return JSON.parse(text);
|
|
1913
|
-
} catch {
|
|
1914
|
-
return void 0;
|
|
1915
|
-
}
|
|
1916
|
-
}
|
|
1917
|
-
|
|
1918
1964
|
// src/lib/algoliaApiKey.ts
|
|
1919
1965
|
import { z as z12 } from "zod";
|
|
1920
1966
|
|
|
@@ -1922,13 +1968,13 @@ import { z as z12 } from "zod";
|
|
|
1922
1968
|
import { deletePassword, getPassword, setPassword } from "cross-keychain";
|
|
1923
1969
|
import { z as z11 } from "zod";
|
|
1924
1970
|
var SERVICE = "algolia-wizard";
|
|
1925
|
-
var
|
|
1971
|
+
var account = (userId) => `api-keys:${userId}`;
|
|
1926
1972
|
var storedKeysSchema = z11.record(z11.string(), z11.string());
|
|
1927
1973
|
function entryId(kind, index, appId) {
|
|
1928
1974
|
return `${kind}:${appId}:${index}`;
|
|
1929
1975
|
}
|
|
1930
|
-
async function loadKeys() {
|
|
1931
|
-
const raw = await getPassword(SERVICE,
|
|
1976
|
+
async function loadKeys(userId) {
|
|
1977
|
+
const raw = await getPassword(SERVICE, account(userId));
|
|
1932
1978
|
if (!raw) return {};
|
|
1933
1979
|
let payload;
|
|
1934
1980
|
try {
|
|
@@ -1950,47 +1996,47 @@ function serialized(op) {
|
|
|
1950
1996
|
});
|
|
1951
1997
|
return next;
|
|
1952
1998
|
}
|
|
1953
|
-
async function readStoredKey(kind, index, appId) {
|
|
1999
|
+
async function readStoredKey(kind, userId, index, appId) {
|
|
1954
2000
|
try {
|
|
1955
|
-
return (await loadKeys())[entryId(kind, index, appId)] ?? null;
|
|
2001
|
+
return (await loadKeys(userId))[entryId(kind, index, appId)] ?? null;
|
|
1956
2002
|
} catch (err) {
|
|
1957
2003
|
logger.warn(
|
|
1958
|
-
{ err: err.message, kind, index, appId },
|
|
2004
|
+
{ err: err.message, kind, index, appId, userId },
|
|
1959
2005
|
"could not read the API key from the keychain"
|
|
1960
2006
|
);
|
|
1961
2007
|
return null;
|
|
1962
2008
|
}
|
|
1963
2009
|
}
|
|
1964
|
-
function storeKey(kind, index, appId, value) {
|
|
2010
|
+
function storeKey(kind, userId, index, appId, value) {
|
|
1965
2011
|
return serialized(async () => {
|
|
1966
2012
|
const id = entryId(kind, index, appId);
|
|
1967
2013
|
try {
|
|
1968
|
-
const keys = await loadKeys();
|
|
2014
|
+
const keys = await loadKeys(userId);
|
|
1969
2015
|
await setPassword(
|
|
1970
2016
|
SERVICE,
|
|
1971
|
-
|
|
2017
|
+
account(userId),
|
|
1972
2018
|
JSON.stringify({ ...keys, [id]: value })
|
|
1973
2019
|
);
|
|
1974
|
-
if ((await loadKeys())[id] !== value) {
|
|
2020
|
+
if ((await loadKeys(userId))[id] !== value) {
|
|
1975
2021
|
throw new Error("the keychain did not store the value");
|
|
1976
2022
|
}
|
|
1977
2023
|
} catch (err) {
|
|
1978
2024
|
logger.warn(
|
|
1979
|
-
{ err: err.message, kind, index, appId },
|
|
2025
|
+
{ err: err.message, kind, index, appId, userId },
|
|
1980
2026
|
"could not store the API key in the keychain; the next run will create another"
|
|
1981
2027
|
);
|
|
1982
2028
|
}
|
|
1983
2029
|
});
|
|
1984
2030
|
}
|
|
1985
|
-
function deleteStoredKeys() {
|
|
2031
|
+
function deleteStoredKeys(userId) {
|
|
1986
2032
|
return serialized(async () => {
|
|
1987
2033
|
try {
|
|
1988
|
-
await deletePassword(SERVICE,
|
|
2034
|
+
await deletePassword(SERVICE, account(userId));
|
|
1989
2035
|
} catch (err) {
|
|
1990
2036
|
const message = err.message;
|
|
1991
2037
|
if (/not found/i.test(message)) return;
|
|
1992
2038
|
logger.warn(
|
|
1993
|
-
{ err: message },
|
|
2039
|
+
{ err: message, userId },
|
|
1994
2040
|
"could not delete the API keys from the keychain"
|
|
1995
2041
|
);
|
|
1996
2042
|
}
|
|
@@ -1998,6 +2044,16 @@ function deleteStoredKeys() {
|
|
|
1998
2044
|
}
|
|
1999
2045
|
|
|
2000
2046
|
// src/lib/algoliaApiKey.ts
|
|
2047
|
+
function requireUserId() {
|
|
2048
|
+
const userId = useWizard.getState().user?.userId;
|
|
2049
|
+
if (!userId) {
|
|
2050
|
+
throw new Error("No Algolia user is signed in; cannot scope the API key.");
|
|
2051
|
+
}
|
|
2052
|
+
return userId;
|
|
2053
|
+
}
|
|
2054
|
+
async function currentUserId() {
|
|
2055
|
+
return useWizard.getState().user?.userId ?? (await getUser())?.userId ?? null;
|
|
2056
|
+
}
|
|
2001
2057
|
var WRITE_ACLS = [
|
|
2002
2058
|
"addObject",
|
|
2003
2059
|
"deleteObject",
|
|
@@ -2044,23 +2100,30 @@ async function keyExists(key) {
|
|
|
2044
2100
|
var resolved = /* @__PURE__ */ new Map();
|
|
2045
2101
|
async function forgetResolvedKeys() {
|
|
2046
2102
|
resolved.clear();
|
|
2047
|
-
await
|
|
2103
|
+
const userId = await currentUserId();
|
|
2104
|
+
if (userId) await deleteStoredKeys(userId);
|
|
2048
2105
|
}
|
|
2049
2106
|
function resolveKey(kind, index, appId, acls, description) {
|
|
2050
|
-
const
|
|
2107
|
+
const userId = requireUserId();
|
|
2108
|
+
const cacheKey = `${userId}:${kind}:${appId}:${index}`;
|
|
2051
2109
|
const cached = resolved.get(cacheKey);
|
|
2052
2110
|
if (cached) return cached;
|
|
2053
|
-
const pending = provisionKey(
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2111
|
+
const pending = provisionKey(
|
|
2112
|
+
kind,
|
|
2113
|
+
userId,
|
|
2114
|
+
index,
|
|
2115
|
+
appId,
|
|
2116
|
+
acls,
|
|
2117
|
+
description
|
|
2118
|
+
).catch((err) => {
|
|
2119
|
+
resolved.delete(cacheKey);
|
|
2120
|
+
throw err;
|
|
2121
|
+
});
|
|
2059
2122
|
resolved.set(cacheKey, pending);
|
|
2060
2123
|
return pending;
|
|
2061
2124
|
}
|
|
2062
|
-
async function provisionKey(kind, index, appId, acls, description) {
|
|
2063
|
-
const stored = await readStoredKey(kind, index, appId);
|
|
2125
|
+
async function provisionKey(kind, userId, index, appId, acls, description) {
|
|
2126
|
+
const stored = await readStoredKey(kind, userId, index, appId);
|
|
2064
2127
|
if (stored) {
|
|
2065
2128
|
if (await keyExists(stored)) {
|
|
2066
2129
|
logger.info({ kind, index, appId }, "reusing the stored API key");
|
|
@@ -2072,7 +2135,7 @@ async function provisionKey(kind, index, appId, acls, description) {
|
|
|
2072
2135
|
);
|
|
2073
2136
|
}
|
|
2074
2137
|
const key = await createKey(index, acls, description);
|
|
2075
|
-
await storeKey(kind, index, appId, key);
|
|
2138
|
+
await storeKey(kind, userId, index, appId, key);
|
|
2076
2139
|
return { key, source: "created" };
|
|
2077
2140
|
}
|
|
2078
2141
|
function resolveWriteKey(index, appId) {
|
|
@@ -3267,7 +3330,7 @@ async function runAnalysis(mode, extraInstructions = []) {
|
|
|
3267
3330
|
// package.json
|
|
3268
3331
|
var package_default = {
|
|
3269
3332
|
name: "@algolia/wizard",
|
|
3270
|
-
version: "0.
|
|
3333
|
+
version: "0.38.0-rc.131.266",
|
|
3271
3334
|
description: "Magically implement Algolia functionality in your codebase",
|
|
3272
3335
|
type: "module",
|
|
3273
3336
|
engines: {
|
|
@@ -4154,6 +4217,10 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
|
|
|
4154
4217
|
if (useCases.includes("ingestion")) {
|
|
4155
4218
|
ingestAppId = appId ?? (await requireApplication()).id;
|
|
4156
4219
|
}
|
|
4220
|
+
let ingestWriteKey;
|
|
4221
|
+
if (useCases.includes("ingestion") && ingestAppId) {
|
|
4222
|
+
ingestWriteKey = (await resolveWriteKey(targetIndex, ingestAppId)).key;
|
|
4223
|
+
}
|
|
4157
4224
|
let uploadFilePath;
|
|
4158
4225
|
let uploadWarning;
|
|
4159
4226
|
if (ingestionSource === "fileUpload") {
|
|
@@ -4216,9 +4283,9 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
|
|
|
4216
4283
|
let ingestDurationMs;
|
|
4217
4284
|
let ingestOutcomeMessage;
|
|
4218
4285
|
const ingestKeyAppId = ingestAppId;
|
|
4219
|
-
const ingestionTools = ingestKeyAppId ? makeToolContext(repoRoot, async () => ({
|
|
4286
|
+
const ingestionTools = ingestKeyAppId && ingestWriteKey ? makeToolContext(repoRoot, async () => ({
|
|
4220
4287
|
[APP_ID_VAR]: ingestKeyAppId,
|
|
4221
|
-
[API_KEY_VAR]:
|
|
4288
|
+
[API_KEY_VAR]: ingestWriteKey,
|
|
4222
4289
|
[INDEX_NAME_VAR]: targetIndex
|
|
4223
4290
|
})) : void 0;
|
|
4224
4291
|
const searchTools = makeToolContext(repoRoot);
|
|
@@ -5373,7 +5440,8 @@ function App() {
|
|
|
5373
5440
|
steps,
|
|
5374
5441
|
inputReq,
|
|
5375
5442
|
user,
|
|
5376
|
-
workflow
|
|
5443
|
+
workflow,
|
|
5444
|
+
settingUpAppId
|
|
5377
5445
|
} = useWizard();
|
|
5378
5446
|
const { exit } = useApp();
|
|
5379
5447
|
const { columns, rows } = useWindowSize7();
|
|
@@ -5388,7 +5456,7 @@ function App() {
|
|
|
5388
5456
|
const isCommandApprovalPrompt = isAwaitingUserInput && inputReq?.promptType === "commandApproval";
|
|
5389
5457
|
const promptPending = isAwaitingUserInput && !isCommandApprovalPrompt;
|
|
5390
5458
|
const holdForTip = stepHasTips && promptPending && tipState === "revealing";
|
|
5391
|
-
const showTips = stepHasTips && (phase === "running" || isCommandApprovalPrompt || holdForTip);
|
|
5459
|
+
const showTips = stepHasTips && (phase === "running" && currentStep?.status === "running" || isCommandApprovalPrompt || holdForTip);
|
|
5392
5460
|
const showNoticesInMain = !stepHasTips;
|
|
5393
5461
|
const showNotices = !isAwaitingUserInput || holdForTip;
|
|
5394
5462
|
useInput6(
|
|
@@ -5473,6 +5541,12 @@ function App() {
|
|
|
5473
5541
|
] }),
|
|
5474
5542
|
/* @__PURE__ */ jsx17(Text19, { color: COLORS.muted, children: "A browser window will open \u2014 complete sign-in there." })
|
|
5475
5543
|
] }),
|
|
5544
|
+
settingUpAppId && /* @__PURE__ */ jsx17(Box19, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs17(Text19, { color: COLORS.strong, bold: true, children: [
|
|
5545
|
+
/* @__PURE__ */ jsx17(Spinner2, { type: "dots" }),
|
|
5546
|
+
" Setting up Wizard using app",
|
|
5547
|
+
" ",
|
|
5548
|
+
settingUpAppId
|
|
5549
|
+
] }) }),
|
|
5476
5550
|
/* @__PURE__ */ jsx17(CliOutput, {}),
|
|
5477
5551
|
showTips && currentStep && /* @__PURE__ */ jsx17(
|
|
5478
5552
|
Tips,
|
|
@@ -5542,50 +5616,56 @@ function readValue(raw) {
|
|
|
5542
5616
|
}
|
|
5543
5617
|
|
|
5544
5618
|
// src/lib/algoliaAppPicker.ts
|
|
5619
|
+
function blockReasonFor(app) {
|
|
5620
|
+
return app.status !== "active" ? "Inactive" : "Missing permissions";
|
|
5621
|
+
}
|
|
5545
5622
|
function secondaryFor(app) {
|
|
5623
|
+
if (!canSelectApplication(app)) {
|
|
5624
|
+
return { kind: "text", value: blockReasonFor(app) };
|
|
5625
|
+
}
|
|
5546
5626
|
return app.plan ? { kind: "badge", value: app.plan } : void 0;
|
|
5547
5627
|
}
|
|
5548
5628
|
function labelFor(app) {
|
|
5549
5629
|
return app.name.trim() ? `${app.name} \u2014 ${app.id}` : app.id;
|
|
5550
5630
|
}
|
|
5551
|
-
function selectAndReport(app) {
|
|
5552
|
-
useWizard.getState()
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
|
|
5631
|
+
async function selectAndReport(app) {
|
|
5632
|
+
const store = useWizard.getState();
|
|
5633
|
+
store.setSettingUpApp(app.id);
|
|
5634
|
+
try {
|
|
5635
|
+
return await selectApplication(app.id);
|
|
5636
|
+
} finally {
|
|
5637
|
+
store.setSettingUpApp(null);
|
|
5638
|
+
}
|
|
5557
5639
|
}
|
|
5558
5640
|
async function promptForApplication(leadIn = []) {
|
|
5559
5641
|
const store = useWizard.getState();
|
|
5560
|
-
const
|
|
5561
|
-
if (
|
|
5642
|
+
const unordered = await listApplications();
|
|
5643
|
+
if (unordered.length === 0) {
|
|
5562
5644
|
throw new Error(
|
|
5563
5645
|
"This Algolia account has no applications. Create one in the Algolia dashboard, or with `npx @algolia/cli@latest application create`, then restart the wizard."
|
|
5564
5646
|
);
|
|
5565
5647
|
}
|
|
5566
|
-
if (
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
{ app: only.id },
|
|
5570
|
-
"single application on the account; selecting it"
|
|
5648
|
+
if (!unordered.some(canSelectApplication)) {
|
|
5649
|
+
throw new Error(
|
|
5650
|
+
"None of the applications on this Algolia account are usable \u2014 each is either inactive or missing key-management access. Activate one, or grant it the `keys` ACL, then restart the wizard."
|
|
5571
5651
|
);
|
|
5572
|
-
for (const line of leadIn) store.pushCliOutput("stdout", line);
|
|
5573
|
-
return selectAndReport(only);
|
|
5574
5652
|
}
|
|
5575
|
-
const
|
|
5576
|
-
...
|
|
5577
|
-
|
|
5653
|
+
const apps = [
|
|
5654
|
+
...unordered.filter(canSelectApplication),
|
|
5655
|
+
...unordered.filter((app) => !canSelectApplication(app))
|
|
5578
5656
|
];
|
|
5657
|
+
const messages = [...leadIn];
|
|
5579
5658
|
for (; ; ) {
|
|
5580
5659
|
const choice = await store.requestUserInput({
|
|
5581
|
-
prompt: "
|
|
5660
|
+
prompt: "Which Algolia application should the wizard work in?",
|
|
5582
5661
|
promptType: "multipleChoice",
|
|
5583
5662
|
options: apps.map(labelFor),
|
|
5584
5663
|
secondary: apps.map(secondaryFor),
|
|
5664
|
+
disabled: apps.map((app) => !canSelectApplication(app)),
|
|
5585
5665
|
messages
|
|
5586
5666
|
});
|
|
5587
5667
|
const chosen = apps.find((app) => labelFor(app) === choice);
|
|
5588
|
-
if (!chosen) {
|
|
5668
|
+
if (!chosen || !canSelectApplication(chosen)) {
|
|
5589
5669
|
throw new Error("Application picker received an unexpected selection");
|
|
5590
5670
|
}
|
|
5591
5671
|
try {
|
|
@@ -5612,10 +5692,11 @@ async function confirmEnvApplication(env, current) {
|
|
|
5612
5692
|
],
|
|
5613
5693
|
messages: [
|
|
5614
5694
|
`${env.file} already sets ${env.name}=${env.id}.`,
|
|
5615
|
-
"Which Algolia application
|
|
5695
|
+
"Which Algolia application would you like to use?"
|
|
5616
5696
|
]
|
|
5617
5697
|
});
|
|
5618
|
-
|
|
5698
|
+
if (choice === useEnv) return selectEnvApplication(env);
|
|
5699
|
+
return current ? selectAndReport(current) : null;
|
|
5619
5700
|
}
|
|
5620
5701
|
async function selectEnvApplication(env) {
|
|
5621
5702
|
try {
|
|
@@ -5630,13 +5711,17 @@ async function selectEnvApplication(env) {
|
|
|
5630
5711
|
]);
|
|
5631
5712
|
}
|
|
5632
5713
|
}
|
|
5633
|
-
async function ensureApplication() {
|
|
5714
|
+
async function ensureApplication(isResuming) {
|
|
5634
5715
|
const current = await currentApplication();
|
|
5716
|
+
if (isResuming) {
|
|
5717
|
+
return current ?? await promptForApplication();
|
|
5718
|
+
}
|
|
5635
5719
|
const env = await findEnvApplicationId();
|
|
5636
|
-
if (env && env.id !== current?.id
|
|
5637
|
-
|
|
5720
|
+
if (env && env.id !== current?.id) {
|
|
5721
|
+
const chosen = await confirmEnvApplication(env, current);
|
|
5722
|
+
if (chosen) return chosen;
|
|
5638
5723
|
}
|
|
5639
|
-
return
|
|
5724
|
+
return promptForApplication();
|
|
5640
5725
|
}
|
|
5641
5726
|
|
|
5642
5727
|
// src/lib/seed.ts
|
|
@@ -6001,7 +6086,8 @@ async function run(workflow) {
|
|
|
6001
6086
|
store.setUser(user);
|
|
6002
6087
|
let app;
|
|
6003
6088
|
try {
|
|
6004
|
-
|
|
6089
|
+
const resuming = await isResumableWorkflow(workflow);
|
|
6090
|
+
app = await ensureApplication(resuming);
|
|
6005
6091
|
} catch (err) {
|
|
6006
6092
|
store.setError(err instanceof Error ? err.message : String(err));
|
|
6007
6093
|
await instance.waitUntilExit();
|