@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.
- package/dist/main.js +379 -224
- 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(
|
|
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
|
|
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:
|
|
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:
|
|
682
|
+
bold: active && !highlightBackground,
|
|
676
683
|
wrap: "truncate",
|
|
677
684
|
children: [
|
|
678
|
-
|
|
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) =>
|
|
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) =>
|
|
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
|
|
1633
|
-
const state =
|
|
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
|
-
|
|
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
|
|
1898
|
+
let candidate;
|
|
1750
1899
|
if (!hasIndices) {
|
|
1751
|
-
|
|
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
|
-
|
|
1910
|
+
candidate = name.trim();
|
|
1762
1911
|
} else {
|
|
1763
|
-
|
|
1912
|
+
candidate = selection;
|
|
1764
1913
|
}
|
|
1765
|
-
if (!
|
|
1914
|
+
if (!candidate) {
|
|
1766
1915
|
error = "Index name cannot be empty.";
|
|
1767
1916
|
continue;
|
|
1768
1917
|
}
|
|
1769
|
-
|
|
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 {
|
|
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
|
|
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:
|
|
1821
|
-
path:
|
|
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
|
|
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:
|
|
1848
|
-
path:
|
|
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
|
|
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:
|
|
1875
|
-
status:
|
|
1876
|
-
reason:
|
|
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
|
|
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:
|
|
1917
|
-
filePath:
|
|
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
|
|
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:
|
|
1945
|
-
filePath:
|
|
1946
|
-
content:
|
|
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
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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
|
|
2271
|
+
const userId = await currentUserId();
|
|
2272
|
+
if (userId) await deleteStoredKeys(userId);
|
|
2168
2273
|
}
|
|
2169
2274
|
function resolveKey(kind, index, appId, acls, description) {
|
|
2170
|
-
const
|
|
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(
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
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
|
|
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
|
|
2643
|
-
return commandSegments(command).map((segment) => segment.split(/\s+/)[0]).some((word) => word !== void 0 &&
|
|
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
|
|
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 (
|
|
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
|
|
3148
|
-
if (!
|
|
3149
|
-
|
|
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
|
-
|
|
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(
|
|
3365
|
+
chunks.push(part.text);
|
|
3222
3366
|
continue;
|
|
3223
3367
|
}
|
|
3224
|
-
chunks.push(
|
|
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.
|
|
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]:
|
|
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
|
|
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 =
|
|
5223
|
+
const name = truncate3(entry.name, budget);
|
|
5072
5224
|
budget -= name.length;
|
|
5073
|
-
const preview = rawPreview ?
|
|
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
|
|
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
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
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
|
|
5830
|
+
async function selectAndReport(app) {
|
|
5665
5831
|
const store = useWizard.getState();
|
|
5666
|
-
|
|
5667
|
-
|
|
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 (
|
|
5673
|
-
|
|
5674
|
-
|
|
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
|
|
5682
|
-
...
|
|
5683
|
-
|
|
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: "
|
|
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
|
|
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
|
-
|
|
5742
|
-
|
|
5743
|
-
return
|
|
5893
|
+
if (isResuming) {
|
|
5894
|
+
if (current && await isEligible(current)) return current;
|
|
5895
|
+
return promptForApplication();
|
|
5744
5896
|
}
|
|
5745
|
-
|
|
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();
|