@algolia/wizard 0.40.0 → 0.41.0-rc.131.290
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 +403 -235
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -5,7 +5,7 @@ import { render } from "ink";
|
|
|
5
5
|
|
|
6
6
|
// src/ui/App.tsx
|
|
7
7
|
import { Box as Box20, Text as Text20, useApp, useInput as useInput7, useWindowSize as useWindowSize7 } from "ink";
|
|
8
|
-
import
|
|
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,9 +953,15 @@ function SelectPrompt({
|
|
|
934
953
|
useInput2((input, key) => {
|
|
935
954
|
if (rows.length === 0) return;
|
|
936
955
|
if (key.upArrow || input === "k") {
|
|
937
|
-
setIndex((i) =>
|
|
956
|
+
setIndex((i) => {
|
|
957
|
+
const next = (i - 1 + rows.length) % rows.length;
|
|
958
|
+
return isDisabled(next) ? i : next;
|
|
959
|
+
});
|
|
938
960
|
} else if (key.downArrow || input === "j") {
|
|
939
|
-
setIndex((i) =>
|
|
961
|
+
setIndex((i) => {
|
|
962
|
+
const next = (i + 1) % rows.length;
|
|
963
|
+
return isDisabled(next) ? i : next;
|
|
964
|
+
});
|
|
940
965
|
} else if (multi && input === " " && index !== cancelIndex) {
|
|
941
966
|
setChecked((prev) => {
|
|
942
967
|
const next = new Set(prev);
|
|
@@ -947,6 +972,7 @@ function SelectPrompt({
|
|
|
947
972
|
} else if (key.return) {
|
|
948
973
|
if (index === cancelIndex) {
|
|
949
974
|
onSelect(CANCEL);
|
|
975
|
+
} else if (isDisabled(index)) {
|
|
950
976
|
} else if (!multi) {
|
|
951
977
|
onSelect(options[index]);
|
|
952
978
|
} else if (checked.size > 0) {
|
|
@@ -971,10 +997,12 @@ function SelectPrompt({
|
|
|
971
997
|
const bullet = multi && !isCancel ? checked.has(i) ? "\u25CF " : "\u25CB " : "";
|
|
972
998
|
const sec = isCancel ? void 0 : secondary?.[i];
|
|
973
999
|
const isText = sec?.kind === "text";
|
|
1000
|
+
const rowDisabled = isDisabled(i);
|
|
974
1001
|
return /* @__PURE__ */ jsxs7(
|
|
975
1002
|
SelectRow,
|
|
976
1003
|
{
|
|
977
1004
|
highlighted,
|
|
1005
|
+
disabled: rowDisabled,
|
|
978
1006
|
width: isText ? "100%" : barWidth,
|
|
979
1007
|
labelWidth: isText ? labelWidth : barLabelWidth,
|
|
980
1008
|
label: `${bullet}${option}`,
|
|
@@ -984,7 +1012,7 @@ function SelectPrompt({
|
|
|
984
1012
|
Text8,
|
|
985
1013
|
{
|
|
986
1014
|
wrap: "truncate",
|
|
987
|
-
color: highlighted ? COLORS.primary : COLORS.muted,
|
|
1015
|
+
color: rowDisabled ? COLORS.dim : highlighted ? COLORS.primary : COLORS.muted,
|
|
988
1016
|
children: sec.value
|
|
989
1017
|
}
|
|
990
1018
|
) }),
|
|
@@ -1031,11 +1059,23 @@ function EnterToContinuePrompt({
|
|
|
1031
1059
|
function PromptInput() {
|
|
1032
1060
|
const { phase, inputReq, submitInput } = useWizard();
|
|
1033
1061
|
const [draft, setDraft] = useState6("");
|
|
1062
|
+
const [submittedReq, setSubmittedReq] = useState6(null);
|
|
1034
1063
|
const promptKey = inputReq && `${inputReq.promptType}:${inputReq.prompt}`;
|
|
1064
|
+
const submitting = inputReq != null && submittedReq === inputReq;
|
|
1035
1065
|
if (phase === "done" || phase === "error") {
|
|
1036
1066
|
return /* @__PURE__ */ jsx7(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text9, { color: "gray", dimColor: true, children: "Press Enter or Esc to exit" }) });
|
|
1037
1067
|
}
|
|
1038
1068
|
if (phase !== "awaitingInput" || !inputReq) return null;
|
|
1069
|
+
if (submitting) {
|
|
1070
|
+
return /* @__PURE__ */ jsx7(Box9, { flexGrow: 1, children: /* @__PURE__ */ jsxs8(Text9, { color: COLORS.strong, bold: true, children: [
|
|
1071
|
+
/* @__PURE__ */ jsx7(Spinner, { type: "dots" }),
|
|
1072
|
+
" Continuing\u2026"
|
|
1073
|
+
] }) });
|
|
1074
|
+
}
|
|
1075
|
+
const handleSubmit = (value) => {
|
|
1076
|
+
setSubmittedReq(inputReq);
|
|
1077
|
+
submitInput(value);
|
|
1078
|
+
};
|
|
1039
1079
|
if (inputReq.promptType === "multipleChoice") {
|
|
1040
1080
|
return /* @__PURE__ */ jsx7(Box9, { flexGrow: 1, children: /* @__PURE__ */ jsx7(
|
|
1041
1081
|
SelectPrompt,
|
|
@@ -1046,10 +1086,11 @@ function PromptInput() {
|
|
|
1046
1086
|
table: inputReq.table,
|
|
1047
1087
|
options: inputReq.options,
|
|
1048
1088
|
secondary: inputReq.secondary,
|
|
1089
|
+
disabled: inputReq.disabled,
|
|
1049
1090
|
defaultSelectedIndex: inputReq.defaultSelectedIndex,
|
|
1050
1091
|
cancelable: inputReq.cancelable,
|
|
1051
1092
|
error: inputReq.error,
|
|
1052
|
-
onSelect:
|
|
1093
|
+
onSelect: handleSubmit
|
|
1053
1094
|
},
|
|
1054
1095
|
promptKey
|
|
1055
1096
|
) });
|
|
@@ -1065,7 +1106,7 @@ function PromptInput() {
|
|
|
1065
1106
|
table: inputReq.table,
|
|
1066
1107
|
options: inputReq.options,
|
|
1067
1108
|
error: inputReq.error,
|
|
1068
|
-
onSelect:
|
|
1109
|
+
onSelect: handleSubmit
|
|
1069
1110
|
},
|
|
1070
1111
|
promptKey
|
|
1071
1112
|
) });
|
|
@@ -1077,7 +1118,7 @@ function PromptInput() {
|
|
|
1077
1118
|
question: inputReq.prompt,
|
|
1078
1119
|
messages: inputReq.messages,
|
|
1079
1120
|
options: ["Continue"],
|
|
1080
|
-
onSelect:
|
|
1121
|
+
onSelect: handleSubmit
|
|
1081
1122
|
},
|
|
1082
1123
|
promptKey
|
|
1083
1124
|
) });
|
|
@@ -1104,7 +1145,7 @@ function PromptInput() {
|
|
|
1104
1145
|
messages: inputReq.messages,
|
|
1105
1146
|
options: labels,
|
|
1106
1147
|
secondary: inputReq.secondary,
|
|
1107
|
-
onSelect: (value) =>
|
|
1148
|
+
onSelect: (value) => handleSubmit(value === labels[0])
|
|
1108
1149
|
},
|
|
1109
1150
|
promptKey
|
|
1110
1151
|
) });
|
|
@@ -1417,6 +1458,44 @@ function trackActionEnd(ctx) {
|
|
|
1417
1458
|
metricTags(ctx.workflowId, ctx.actionId)
|
|
1418
1459
|
);
|
|
1419
1460
|
}
|
|
1461
|
+
var MAX_ATTRIBUTE_LENGTH = 500;
|
|
1462
|
+
function truncate2(value) {
|
|
1463
|
+
return value.length <= MAX_ATTRIBUTE_LENGTH ? value : `${value.slice(0, MAX_ATTRIBUTE_LENGTH - 3)}...`;
|
|
1464
|
+
}
|
|
1465
|
+
function readString(source, key) {
|
|
1466
|
+
const value = Reflect.get(source, key);
|
|
1467
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
1468
|
+
}
|
|
1469
|
+
function causeAttributes(cause) {
|
|
1470
|
+
if (cause instanceof Error) {
|
|
1471
|
+
return {
|
|
1472
|
+
error_cause_name: cause.name,
|
|
1473
|
+
error_cause: truncate2(cause.message)
|
|
1474
|
+
};
|
|
1475
|
+
}
|
|
1476
|
+
return typeof cause === "string" ? { error_cause: truncate2(cause) } : {};
|
|
1477
|
+
}
|
|
1478
|
+
function providerAttributes(source) {
|
|
1479
|
+
const statusCode = Reflect.get(source, "statusCode");
|
|
1480
|
+
const isRetryable = Reflect.get(source, "isRetryable");
|
|
1481
|
+
const url = readString(source, "url");
|
|
1482
|
+
const responseBody = readString(source, "responseBody");
|
|
1483
|
+
return {
|
|
1484
|
+
...typeof statusCode === "number" && Number.isFinite(statusCode) && { error_status_code: statusCode },
|
|
1485
|
+
...typeof isRetryable === "boolean" && { error_retryable: isRetryable },
|
|
1486
|
+
...url && { error_url: truncate2(url) },
|
|
1487
|
+
...responseBody && { error_response_body: truncate2(responseBody) }
|
|
1488
|
+
};
|
|
1489
|
+
}
|
|
1490
|
+
function errorAttributes(err) {
|
|
1491
|
+
if (!(err instanceof Error)) return {};
|
|
1492
|
+
const { cause } = err;
|
|
1493
|
+
return {
|
|
1494
|
+
error_name: err.name,
|
|
1495
|
+
...causeAttributes(cause),
|
|
1496
|
+
...providerAttributes(cause instanceof Error ? cause : err)
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1420
1499
|
function trackActionError(ctx) {
|
|
1421
1500
|
const attributes = {
|
|
1422
1501
|
event: "wizard.action.error",
|
|
@@ -1424,7 +1503,8 @@ function trackActionError(ctx) {
|
|
|
1424
1503
|
action_id: ctx.actionId,
|
|
1425
1504
|
action_title: ctx.actionTitle,
|
|
1426
1505
|
error: ctx.error,
|
|
1427
|
-
app_id: ctx.appId
|
|
1506
|
+
app_id: ctx.appId,
|
|
1507
|
+
...errorAttributes(ctx.cause)
|
|
1428
1508
|
};
|
|
1429
1509
|
emitTelemetryLog(
|
|
1430
1510
|
"error",
|
|
@@ -1460,7 +1540,8 @@ function trackWorkflowError(ctx) {
|
|
|
1460
1540
|
workflow_id: ctx.workflowId,
|
|
1461
1541
|
action_id: ctx.actionId,
|
|
1462
1542
|
error: ctx.error,
|
|
1463
|
-
app_id: ctx.appId
|
|
1543
|
+
app_id: ctx.appId,
|
|
1544
|
+
...errorAttributes(ctx.cause)
|
|
1464
1545
|
};
|
|
1465
1546
|
emitTelemetryLog(
|
|
1466
1547
|
"error",
|
|
@@ -1524,6 +1605,10 @@ function reconcileWorkflowState(state, workflow) {
|
|
|
1524
1605
|
}
|
|
1525
1606
|
return state;
|
|
1526
1607
|
}
|
|
1608
|
+
async function loadResumableState(workflow) {
|
|
1609
|
+
const persisted = await loadWorkflowState(workflow.id);
|
|
1610
|
+
return persisted ? reconcileWorkflowState(persisted, workflow) : null;
|
|
1611
|
+
}
|
|
1527
1612
|
function initWorkflowState(workflow, now) {
|
|
1528
1613
|
return {
|
|
1529
1614
|
workflowId: workflow.id,
|
|
@@ -1626,11 +1711,11 @@ async function runStep(state, index, step, appId) {
|
|
|
1626
1711
|
durationMs: Date.now() - startedAt
|
|
1627
1712
|
});
|
|
1628
1713
|
}
|
|
1629
|
-
async function runWorkflow(workflow, appId) {
|
|
1714
|
+
async function runWorkflow(workflow, appId, resumableState) {
|
|
1630
1715
|
const store = useWizard.getState();
|
|
1631
1716
|
try {
|
|
1632
|
-
const
|
|
1633
|
-
const state =
|
|
1717
|
+
const resolved2 = resumableState !== void 0 ? resumableState : await loadResumableState(workflow);
|
|
1718
|
+
const state = resolved2 ?? initWorkflowState(workflow, nowIso());
|
|
1634
1719
|
ensureExecutedStepCount(state);
|
|
1635
1720
|
store.startWorkflow(
|
|
1636
1721
|
{
|
|
@@ -1686,14 +1771,16 @@ async function runWorkflow(workflow, appId) {
|
|
|
1686
1771
|
appId,
|
|
1687
1772
|
actionId: failedActionId,
|
|
1688
1773
|
actionTitle: failedActionTitle,
|
|
1689
|
-
error: message
|
|
1774
|
+
error: message,
|
|
1775
|
+
cause: err
|
|
1690
1776
|
});
|
|
1691
1777
|
}
|
|
1692
1778
|
trackWorkflowError({
|
|
1693
1779
|
workflowId: workflow.id,
|
|
1694
1780
|
appId,
|
|
1695
1781
|
error: message,
|
|
1696
|
-
actionId: failedActionId
|
|
1782
|
+
actionId: failedActionId,
|
|
1783
|
+
cause: err
|
|
1697
1784
|
});
|
|
1698
1785
|
track("Error", {
|
|
1699
1786
|
step,
|
|
@@ -1720,14 +1807,89 @@ async function listIndices() {
|
|
|
1720
1807
|
return items.map((i) => ({ name: i.name, entries: i.entries })).sort((a, b) => a.name.localeCompare(b.name));
|
|
1721
1808
|
}
|
|
1722
1809
|
|
|
1810
|
+
// src/lib/algoliaApp.ts
|
|
1811
|
+
import { z as z5 } from "zod";
|
|
1812
|
+
var applicationSchema = z5.object({
|
|
1813
|
+
id: z5.string().min(1),
|
|
1814
|
+
name: z5.string().default(""),
|
|
1815
|
+
plan: z5.string().optional()
|
|
1816
|
+
});
|
|
1817
|
+
var listSchema = z5.array(
|
|
1818
|
+
z5.object({
|
|
1819
|
+
id: z5.string().min(1),
|
|
1820
|
+
name: z5.string().default(""),
|
|
1821
|
+
plan_label: z5.string().optional(),
|
|
1822
|
+
status: z5.string().optional(),
|
|
1823
|
+
acl: z5.array(z5.string()).optional()
|
|
1824
|
+
}).transform(({ id, name, plan_label, status, acl }) => ({
|
|
1825
|
+
id,
|
|
1826
|
+
name,
|
|
1827
|
+
plan: plan_label,
|
|
1828
|
+
status,
|
|
1829
|
+
acl
|
|
1830
|
+
}))
|
|
1831
|
+
);
|
|
1832
|
+
function canSelectApplication(app) {
|
|
1833
|
+
return app.status === "active" && (app.acl ?? []).includes("keys");
|
|
1834
|
+
}
|
|
1835
|
+
async function currentApplication() {
|
|
1836
|
+
let raw;
|
|
1837
|
+
try {
|
|
1838
|
+
raw = await runAlgoliaCli(["application", "current", "-o", "json"]);
|
|
1839
|
+
} catch {
|
|
1840
|
+
return null;
|
|
1841
|
+
}
|
|
1842
|
+
const parsed = applicationSchema.safeParse(parseJson(raw));
|
|
1843
|
+
return parsed.success ? parsed.data : null;
|
|
1844
|
+
}
|
|
1845
|
+
async function requireApplication() {
|
|
1846
|
+
const app = await currentApplication();
|
|
1847
|
+
if (!app) {
|
|
1848
|
+
throw new Error(
|
|
1849
|
+
"No Algolia application is selected. Run `npx @algolia/cli@latest application select` and restart the wizard."
|
|
1850
|
+
);
|
|
1851
|
+
}
|
|
1852
|
+
return app;
|
|
1853
|
+
}
|
|
1854
|
+
async function listApplications() {
|
|
1855
|
+
const raw = await runAlgoliaCli(["application", "list", "-o", "json"]);
|
|
1856
|
+
const parsed = listSchema.safeParse(parseJson(raw));
|
|
1857
|
+
if (!parsed.success) {
|
|
1858
|
+
throw new Error("Could not read the list of Algolia applications.");
|
|
1859
|
+
}
|
|
1860
|
+
return parsed.data;
|
|
1861
|
+
}
|
|
1862
|
+
async function selectApplication(id) {
|
|
1863
|
+
const raw = await runAlgoliaCli(
|
|
1864
|
+
["application", "select", "--non-interactive", "--app-id", id],
|
|
1865
|
+
{ onOutput: stderrSink }
|
|
1866
|
+
);
|
|
1867
|
+
const parsed = applicationSchema.safeParse(parseJson(raw));
|
|
1868
|
+
if (!parsed.success) {
|
|
1869
|
+
throw new Error(
|
|
1870
|
+
`Selected application ${id}, but the Algolia CLI returned an unreadable result.`
|
|
1871
|
+
);
|
|
1872
|
+
}
|
|
1873
|
+
return parsed.data;
|
|
1874
|
+
}
|
|
1875
|
+
function parseJson(text) {
|
|
1876
|
+
try {
|
|
1877
|
+
return JSON.parse(text);
|
|
1878
|
+
} catch {
|
|
1879
|
+
return void 0;
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1723
1883
|
// src/actions/selectIndex.ts
|
|
1724
1884
|
var CREATE_NEW_INDEX = "Create a new index\u2026";
|
|
1725
1885
|
var selectIndexStep = async (ctx) => {
|
|
1886
|
+
await requireApplication();
|
|
1726
1887
|
const indices = await listIndices();
|
|
1727
1888
|
const names = indices.map((i) => i.name);
|
|
1728
1889
|
const hasIndices = names.length > 0;
|
|
1729
1890
|
let error;
|
|
1730
|
-
|
|
1891
|
+
let chosen;
|
|
1892
|
+
while (chosen === void 0) {
|
|
1731
1893
|
const selection = hasIndices ? await ctx.requestUserInput({
|
|
1732
1894
|
prompt: "Which index do you want to ingest into?",
|
|
1733
1895
|
promptType: "multipleChoice",
|
|
@@ -1746,9 +1908,9 @@ var selectIndexStep = async (ctx) => {
|
|
|
1746
1908
|
if (typeof selection !== "string") {
|
|
1747
1909
|
throw new Error("selectIndex received an unexpected non-text result");
|
|
1748
1910
|
}
|
|
1749
|
-
let
|
|
1911
|
+
let candidate;
|
|
1750
1912
|
if (!hasIndices) {
|
|
1751
|
-
|
|
1913
|
+
candidate = selection.trim();
|
|
1752
1914
|
} else if (selection === CREATE_NEW_INDEX) {
|
|
1753
1915
|
const name = await ctx.requestUserInput({
|
|
1754
1916
|
prompt: "Name the new index:",
|
|
@@ -1758,21 +1920,28 @@ var selectIndexStep = async (ctx) => {
|
|
|
1758
1920
|
if (typeof name !== "string") {
|
|
1759
1921
|
throw new Error("selectIndex received an unexpected non-text result");
|
|
1760
1922
|
}
|
|
1761
|
-
|
|
1923
|
+
candidate = name.trim();
|
|
1762
1924
|
} else {
|
|
1763
|
-
|
|
1925
|
+
candidate = selection;
|
|
1764
1926
|
}
|
|
1765
|
-
if (!
|
|
1927
|
+
if (!candidate) {
|
|
1766
1928
|
error = "Index name cannot be empty.";
|
|
1767
1929
|
continue;
|
|
1768
1930
|
}
|
|
1769
|
-
|
|
1770
|
-
return { selection: chosen };
|
|
1931
|
+
chosen = candidate;
|
|
1771
1932
|
}
|
|
1933
|
+
ctx.setUserInput("index", chosen);
|
|
1934
|
+
return { selection: chosen };
|
|
1772
1935
|
};
|
|
1773
1936
|
|
|
1774
1937
|
// src/lib/agent.ts
|
|
1775
|
-
import {
|
|
1938
|
+
import {
|
|
1939
|
+
ToolLoopAgent,
|
|
1940
|
+
hasToolCall,
|
|
1941
|
+
Output as Output3,
|
|
1942
|
+
APICallError,
|
|
1943
|
+
NoOutputGeneratedError
|
|
1944
|
+
} from "ai";
|
|
1776
1945
|
import { createAnthropic as createAnthropic3 } from "@ai-sdk/anthropic";
|
|
1777
1946
|
import "zod";
|
|
1778
1947
|
|
|
@@ -1781,7 +1950,7 @@ import "zod";
|
|
|
1781
1950
|
|
|
1782
1951
|
// src/lib/tools/listFiles.ts
|
|
1783
1952
|
import { tool } from "ai";
|
|
1784
|
-
import
|
|
1953
|
+
import z6 from "zod";
|
|
1785
1954
|
import { readdir } from "node:fs/promises";
|
|
1786
1955
|
|
|
1787
1956
|
// src/lib/tools/path.ts
|
|
@@ -1817,8 +1986,8 @@ async function hasSymlinkParent(ctx, target) {
|
|
|
1817
1986
|
function listFilesTool(ctx) {
|
|
1818
1987
|
return tool({
|
|
1819
1988
|
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:
|
|
1989
|
+
inputSchema: z6.object({
|
|
1990
|
+
path: z6.string().optional().describe("Directory to list, relative to cwd (default: cwd)")
|
|
1822
1991
|
}),
|
|
1823
1992
|
execute: async ({ path = "." }) => {
|
|
1824
1993
|
logger.info({ path }, "called listFiles tool");
|
|
@@ -1839,13 +2008,13 @@ function listFilesTool(ctx) {
|
|
|
1839
2008
|
|
|
1840
2009
|
// src/lib/tools/changeDirectory.ts
|
|
1841
2010
|
import { tool as tool2 } from "ai";
|
|
1842
|
-
import
|
|
2011
|
+
import z7 from "zod";
|
|
1843
2012
|
import { stat } from "node:fs/promises";
|
|
1844
2013
|
function changeDirectoryTool(ctx) {
|
|
1845
2014
|
return tool2({
|
|
1846
2015
|
description: "Change the current working directory. Subsequent file operations resolve relative to it. Returns the new working directory.",
|
|
1847
|
-
inputSchema:
|
|
1848
|
-
path:
|
|
2016
|
+
inputSchema: z7.object({
|
|
2017
|
+
path: z7.string().describe("Directory to change into")
|
|
1849
2018
|
}),
|
|
1850
2019
|
execute: async ({ path }) => {
|
|
1851
2020
|
logger.info({ path }, "called changeDirectory tool");
|
|
@@ -1867,13 +2036,13 @@ function changeDirectoryTool(ctx) {
|
|
|
1867
2036
|
|
|
1868
2037
|
// src/lib/tools/reportStatus.ts
|
|
1869
2038
|
import { tool as tool3 } from "ai";
|
|
1870
|
-
import
|
|
2039
|
+
import z8 from "zod";
|
|
1871
2040
|
function reportStatusTool(output) {
|
|
1872
2041
|
return tool3({
|
|
1873
2042
|
description: "Report the status of your execution. Return a reason in case of failure.",
|
|
1874
|
-
inputSchema:
|
|
1875
|
-
status:
|
|
1876
|
-
reason:
|
|
2043
|
+
inputSchema: z8.object({
|
|
2044
|
+
status: z8.enum(["success", "fail"]),
|
|
2045
|
+
reason: z8.string().optional(),
|
|
1877
2046
|
output
|
|
1878
2047
|
}),
|
|
1879
2048
|
execute: async ({ status, reason, output: output2 }) => {
|
|
@@ -1885,7 +2054,7 @@ function reportStatusTool(output) {
|
|
|
1885
2054
|
|
|
1886
2055
|
// src/lib/tools/readFile.ts
|
|
1887
2056
|
import { tool as tool4 } from "ai";
|
|
1888
|
-
import
|
|
2057
|
+
import z9 from "zod";
|
|
1889
2058
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
1890
2059
|
|
|
1891
2060
|
// src/lib/tools/env.ts
|
|
@@ -1913,8 +2082,8 @@ function redactEnvValues(content) {
|
|
|
1913
2082
|
function readFileTool(ctx) {
|
|
1914
2083
|
return tool4({
|
|
1915
2084
|
description: "Read the contents of a file at the given path",
|
|
1916
|
-
inputSchema:
|
|
1917
|
-
filePath:
|
|
2085
|
+
inputSchema: z9.object({
|
|
2086
|
+
filePath: z9.string().describe("Path to the file to read")
|
|
1918
2087
|
}),
|
|
1919
2088
|
execute: async ({ filePath }) => {
|
|
1920
2089
|
if (++ctx.counts.read > ctx.limits.read) {
|
|
@@ -1935,15 +2104,15 @@ function readFileTool(ctx) {
|
|
|
1935
2104
|
|
|
1936
2105
|
// src/lib/tools/writeFile.ts
|
|
1937
2106
|
import { tool as tool5 } from "ai";
|
|
1938
|
-
import
|
|
2107
|
+
import z10 from "zod";
|
|
1939
2108
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
|
|
1940
2109
|
import { dirname as dirname3 } from "node:path";
|
|
1941
2110
|
function writeFileTool(ctx) {
|
|
1942
2111
|
return tool5({
|
|
1943
2112
|
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:
|
|
2113
|
+
inputSchema: z10.object({
|
|
2114
|
+
filePath: z10.string().describe("Path to the file to write"),
|
|
2115
|
+
content: z10.string().describe("Content to write to the file")
|
|
1947
2116
|
}),
|
|
1948
2117
|
execute: async ({ filePath, content }) => {
|
|
1949
2118
|
logger.info({ filePath }, "called writeFile tool");
|
|
@@ -1973,68 +2142,6 @@ import z13 from "zod";
|
|
|
1973
2142
|
import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile5 } from "node:fs/promises";
|
|
1974
2143
|
import { dirname as dirname4, relative as relative3 } from "node:path";
|
|
1975
2144
|
|
|
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
2145
|
// src/lib/algoliaApiKey.ts
|
|
2039
2146
|
import { z as z12 } from "zod";
|
|
2040
2147
|
|
|
@@ -2042,13 +2149,13 @@ import { z as z12 } from "zod";
|
|
|
2042
2149
|
import { deletePassword, getPassword, setPassword } from "cross-keychain";
|
|
2043
2150
|
import { z as z11 } from "zod";
|
|
2044
2151
|
var SERVICE = "algolia-wizard";
|
|
2045
|
-
var
|
|
2152
|
+
var account = (userId) => `api-keys:${userId}`;
|
|
2046
2153
|
var storedKeysSchema = z11.record(z11.string(), z11.string());
|
|
2047
2154
|
function entryId(kind, index, appId) {
|
|
2048
2155
|
return `${kind}:${appId}:${index}`;
|
|
2049
2156
|
}
|
|
2050
|
-
async function loadKeys() {
|
|
2051
|
-
const raw = await getPassword(SERVICE,
|
|
2157
|
+
async function loadKeys(userId) {
|
|
2158
|
+
const raw = await getPassword(SERVICE, account(userId));
|
|
2052
2159
|
if (!raw) return {};
|
|
2053
2160
|
let payload;
|
|
2054
2161
|
try {
|
|
@@ -2070,47 +2177,47 @@ function serialized(op) {
|
|
|
2070
2177
|
});
|
|
2071
2178
|
return next;
|
|
2072
2179
|
}
|
|
2073
|
-
async function readStoredKey(kind, index, appId) {
|
|
2180
|
+
async function readStoredKey(kind, userId, index, appId) {
|
|
2074
2181
|
try {
|
|
2075
|
-
return (await loadKeys())[entryId(kind, index, appId)] ?? null;
|
|
2182
|
+
return (await loadKeys(userId))[entryId(kind, index, appId)] ?? null;
|
|
2076
2183
|
} catch (err) {
|
|
2077
2184
|
logger.warn(
|
|
2078
|
-
{ err: err.message, kind, index, appId },
|
|
2185
|
+
{ err: err.message, kind, index, appId, userId },
|
|
2079
2186
|
"could not read the API key from the keychain"
|
|
2080
2187
|
);
|
|
2081
2188
|
return null;
|
|
2082
2189
|
}
|
|
2083
2190
|
}
|
|
2084
|
-
function storeKey(kind, index, appId, value) {
|
|
2191
|
+
function storeKey(kind, userId, index, appId, value) {
|
|
2085
2192
|
return serialized(async () => {
|
|
2086
2193
|
const id = entryId(kind, index, appId);
|
|
2087
2194
|
try {
|
|
2088
|
-
const keys = await loadKeys();
|
|
2195
|
+
const keys = await loadKeys(userId);
|
|
2089
2196
|
await setPassword(
|
|
2090
2197
|
SERVICE,
|
|
2091
|
-
|
|
2198
|
+
account(userId),
|
|
2092
2199
|
JSON.stringify({ ...keys, [id]: value })
|
|
2093
2200
|
);
|
|
2094
|
-
if ((await loadKeys())[id] !== value) {
|
|
2201
|
+
if ((await loadKeys(userId))[id] !== value) {
|
|
2095
2202
|
throw new Error("the keychain did not store the value");
|
|
2096
2203
|
}
|
|
2097
2204
|
} catch (err) {
|
|
2098
2205
|
logger.warn(
|
|
2099
|
-
{ err: err.message, kind, index, appId },
|
|
2206
|
+
{ err: err.message, kind, index, appId, userId },
|
|
2100
2207
|
"could not store the API key in the keychain; the next run will create another"
|
|
2101
2208
|
);
|
|
2102
2209
|
}
|
|
2103
2210
|
});
|
|
2104
2211
|
}
|
|
2105
|
-
function deleteStoredKeys() {
|
|
2212
|
+
function deleteStoredKeys(userId) {
|
|
2106
2213
|
return serialized(async () => {
|
|
2107
2214
|
try {
|
|
2108
|
-
await deletePassword(SERVICE,
|
|
2215
|
+
await deletePassword(SERVICE, account(userId));
|
|
2109
2216
|
} catch (err) {
|
|
2110
2217
|
const message = err.message;
|
|
2111
2218
|
if (/not found/i.test(message)) return;
|
|
2112
2219
|
logger.warn(
|
|
2113
|
-
{ err: message },
|
|
2220
|
+
{ err: message, userId },
|
|
2114
2221
|
"could not delete the API keys from the keychain"
|
|
2115
2222
|
);
|
|
2116
2223
|
}
|
|
@@ -2118,6 +2225,16 @@ function deleteStoredKeys() {
|
|
|
2118
2225
|
}
|
|
2119
2226
|
|
|
2120
2227
|
// src/lib/algoliaApiKey.ts
|
|
2228
|
+
function requireUserId() {
|
|
2229
|
+
const userId = useWizard.getState().user?.userId;
|
|
2230
|
+
if (!userId) {
|
|
2231
|
+
throw new Error("No Algolia user is signed in; cannot scope the API key.");
|
|
2232
|
+
}
|
|
2233
|
+
return userId;
|
|
2234
|
+
}
|
|
2235
|
+
async function currentUserId() {
|
|
2236
|
+
return useWizard.getState().user?.userId ?? (await getUser())?.userId ?? null;
|
|
2237
|
+
}
|
|
2121
2238
|
var WRITE_ACLS = [
|
|
2122
2239
|
"addObject",
|
|
2123
2240
|
"deleteObject",
|
|
@@ -2164,23 +2281,30 @@ async function keyExists(key) {
|
|
|
2164
2281
|
var resolved = /* @__PURE__ */ new Map();
|
|
2165
2282
|
async function forgetResolvedKeys() {
|
|
2166
2283
|
resolved.clear();
|
|
2167
|
-
await
|
|
2284
|
+
const userId = await currentUserId();
|
|
2285
|
+
if (userId) await deleteStoredKeys(userId);
|
|
2168
2286
|
}
|
|
2169
2287
|
function resolveKey(kind, index, appId, acls, description) {
|
|
2170
|
-
const
|
|
2288
|
+
const userId = requireUserId();
|
|
2289
|
+
const cacheKey = `${userId}:${kind}:${appId}:${index}`;
|
|
2171
2290
|
const cached = resolved.get(cacheKey);
|
|
2172
2291
|
if (cached) return cached;
|
|
2173
|
-
const pending = provisionKey(
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2292
|
+
const pending = provisionKey(
|
|
2293
|
+
kind,
|
|
2294
|
+
userId,
|
|
2295
|
+
index,
|
|
2296
|
+
appId,
|
|
2297
|
+
acls,
|
|
2298
|
+
description
|
|
2299
|
+
).catch((err) => {
|
|
2300
|
+
resolved.delete(cacheKey);
|
|
2301
|
+
throw err;
|
|
2302
|
+
});
|
|
2179
2303
|
resolved.set(cacheKey, pending);
|
|
2180
2304
|
return pending;
|
|
2181
2305
|
}
|
|
2182
|
-
async function provisionKey(kind, index, appId, acls, description) {
|
|
2183
|
-
const stored = await readStoredKey(kind, index, appId);
|
|
2306
|
+
async function provisionKey(kind, userId, index, appId, acls, description) {
|
|
2307
|
+
const stored = await readStoredKey(kind, userId, index, appId);
|
|
2184
2308
|
if (stored) {
|
|
2185
2309
|
if (await keyExists(stored)) {
|
|
2186
2310
|
logger.info({ kind, index, appId }, "reusing the stored API key");
|
|
@@ -2192,7 +2316,7 @@ async function provisionKey(kind, index, appId, acls, description) {
|
|
|
2192
2316
|
);
|
|
2193
2317
|
}
|
|
2194
2318
|
const key = await createKey(index, acls, description);
|
|
2195
|
-
await storeKey(kind, index, appId, key);
|
|
2319
|
+
await storeKey(kind, userId, index, appId, key);
|
|
2196
2320
|
return { key, source: "created" };
|
|
2197
2321
|
}
|
|
2198
2322
|
function resolveWriteKey(index, appId) {
|
|
@@ -2635,17 +2759,38 @@ function storeApproval(root) {
|
|
|
2635
2759
|
return "approve";
|
|
2636
2760
|
};
|
|
2637
2761
|
}
|
|
2638
|
-
var
|
|
2762
|
+
var FILE_IO_COMMANDS = /* @__PURE__ */ new Set([
|
|
2763
|
+
"ls",
|
|
2764
|
+
"find",
|
|
2765
|
+
"fd",
|
|
2766
|
+
"tree",
|
|
2767
|
+
"dir",
|
|
2768
|
+
"locate",
|
|
2769
|
+
"cat",
|
|
2770
|
+
"head",
|
|
2771
|
+
"tail",
|
|
2772
|
+
"less",
|
|
2773
|
+
"more",
|
|
2774
|
+
"tac",
|
|
2775
|
+
"nl",
|
|
2776
|
+
"grep",
|
|
2777
|
+
"egrep",
|
|
2778
|
+
"fgrep",
|
|
2779
|
+
"rg",
|
|
2780
|
+
"ack",
|
|
2781
|
+
"ag",
|
|
2782
|
+
"xxd",
|
|
2783
|
+
"hexdump",
|
|
2784
|
+
"od",
|
|
2785
|
+
"strings"
|
|
2786
|
+
]);
|
|
2639
2787
|
function commandSegments(command) {
|
|
2640
2788
|
return command.split(/&&|;|\|/).map((segment) => segment.trim());
|
|
2641
2789
|
}
|
|
2642
|
-
function
|
|
2643
|
-
return commandSegments(command).map((segment) => segment.split(/\s+/)[0]).some((word) => word !== void 0 &&
|
|
2790
|
+
function isFileIOCommand(command) {
|
|
2791
|
+
return commandSegments(command).map((segment) => segment.split(/\s+/)[0]).some((word) => word !== void 0 && FILE_IO_COMMANDS.has(word));
|
|
2644
2792
|
}
|
|
2645
2793
|
var READ_ONLY_BINARIES = /* @__PURE__ */ new Set([
|
|
2646
|
-
"cat",
|
|
2647
|
-
"head",
|
|
2648
|
-
"tail",
|
|
2649
2794
|
"wc",
|
|
2650
2795
|
"pwd",
|
|
2651
2796
|
"echo",
|
|
@@ -2656,10 +2801,6 @@ var READ_ONLY_BINARIES = /* @__PURE__ */ new Set([
|
|
|
2656
2801
|
"which",
|
|
2657
2802
|
"file",
|
|
2658
2803
|
"stat",
|
|
2659
|
-
"grep",
|
|
2660
|
-
"egrep",
|
|
2661
|
-
"fgrep",
|
|
2662
|
-
"rg",
|
|
2663
2804
|
"diff"
|
|
2664
2805
|
]);
|
|
2665
2806
|
var READ_ONLY_NO_ARGS_BINARIES = /* @__PURE__ */ new Set(["env", "printenv"]);
|
|
@@ -2865,7 +3006,7 @@ async function approveAndRun(ctx, command, cwd, explanation) {
|
|
|
2865
3006
|
}
|
|
2866
3007
|
function runShellTool(ctx, createModel = defaultCreateModel) {
|
|
2867
3008
|
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
|
|
3009
|
+
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
3010
|
inputSchema: z15.object({
|
|
2870
3011
|
command: z15.string().describe(
|
|
2871
3012
|
"The command to run, exactly as it would be typed in a shell. Pipes, && and redirects are allowed."
|
|
@@ -2883,8 +3024,8 @@ function runShellTool(ctx, createModel = defaultCreateModel) {
|
|
|
2883
3024
|
}
|
|
2884
3025
|
const resolved2 = resolveInRoot(ctx, cwd ?? ".");
|
|
2885
3026
|
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.";
|
|
3027
|
+
if (isFileIOCommand(command)) {
|
|
3028
|
+
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
3029
|
}
|
|
2889
3030
|
logger.info({ command, cwd: resolved2.target }, "called runShell tool");
|
|
2890
3031
|
const fast = fastPathSafety(command);
|
|
@@ -3139,21 +3280,31 @@ var MODEL_BY_SIZE = {
|
|
|
3139
3280
|
var MISSING_REPORT_STATUS_ERROR_MESSAGE = "Agent finished without calling reportStatus";
|
|
3140
3281
|
var MISSING_REPORT_USER_MESSAGE = "This step ran into a problem finishing. Run the wizard again to retry it.";
|
|
3141
3282
|
var REPORT_STATUS_RETRIES = 2;
|
|
3283
|
+
var PROVIDER_ERROR_USER_MESSAGE = "The AI service had trouble responding. Run the wizard again to retry this step.";
|
|
3284
|
+
function retryKind(err) {
|
|
3285
|
+
if (err instanceof Error && err.message === MISSING_REPORT_STATUS_ERROR_MESSAGE) {
|
|
3286
|
+
return "missingReport";
|
|
3287
|
+
}
|
|
3288
|
+
if (NoOutputGeneratedError.isInstance(err)) return "transientProvider";
|
|
3289
|
+
if (APICallError.isInstance(err) && err.isRetryable) {
|
|
3290
|
+
return "transientProvider";
|
|
3291
|
+
}
|
|
3292
|
+
return null;
|
|
3293
|
+
}
|
|
3294
|
+
function exhaustedError(kind, err) {
|
|
3295
|
+
return kind === "missingReport" ? new Error(MISSING_REPORT_USER_MESSAGE) : new Error(PROVIDER_ERROR_USER_MESSAGE, { cause: err });
|
|
3296
|
+
}
|
|
3142
3297
|
async function runAgent(req) {
|
|
3143
3298
|
for (let attempt = 0; attempt <= REPORT_STATUS_RETRIES; attempt++) {
|
|
3144
3299
|
try {
|
|
3145
3300
|
return await runAgentAttempt(req, attempt);
|
|
3146
3301
|
} catch (err) {
|
|
3147
|
-
const
|
|
3148
|
-
if (!
|
|
3149
|
-
|
|
3150
|
-
}
|
|
3151
|
-
if (attempt === REPORT_STATUS_RETRIES) {
|
|
3152
|
-
throw new Error(MISSING_REPORT_USER_MESSAGE);
|
|
3153
|
-
}
|
|
3302
|
+
const kind = retryKind(err);
|
|
3303
|
+
if (!kind) throw err;
|
|
3304
|
+
if (attempt === REPORT_STATUS_RETRIES) throw exhaustedError(kind, err);
|
|
3154
3305
|
logger.warn(
|
|
3155
|
-
{ attempt: attempt + 1 },
|
|
3156
|
-
"retrying runAgent after missing reportStatus"
|
|
3306
|
+
{ attempt: attempt + 1, err },
|
|
3307
|
+
kind === "missingReport" ? "retrying runAgent after missing reportStatus" : "retrying runAgent after a transient provider error"
|
|
3157
3308
|
);
|
|
3158
3309
|
}
|
|
3159
3310
|
}
|
|
@@ -3216,18 +3367,28 @@ async function runAgentAttempt(req, attempt) {
|
|
|
3216
3367
|
});
|
|
3217
3368
|
let chunks = [];
|
|
3218
3369
|
const chunkLimit = 5;
|
|
3219
|
-
|
|
3370
|
+
let streamError;
|
|
3371
|
+
for await (const part of stream.fullStream) {
|
|
3372
|
+
if (part.type === "error") {
|
|
3373
|
+
streamError = part.error;
|
|
3374
|
+
continue;
|
|
3375
|
+
}
|
|
3376
|
+
if (part.type !== "text-delta") continue;
|
|
3220
3377
|
if (chunks.length < chunkLimit) {
|
|
3221
|
-
chunks.push(
|
|
3378
|
+
chunks.push(part.text);
|
|
3222
3379
|
continue;
|
|
3223
3380
|
}
|
|
3224
|
-
chunks.push(
|
|
3381
|
+
chunks.push(part.text);
|
|
3225
3382
|
logger.debug(chunks.join(""));
|
|
3226
3383
|
chunks = [];
|
|
3227
3384
|
}
|
|
3228
3385
|
if (chunks.length) {
|
|
3229
3386
|
logger.debug(chunks.join(""));
|
|
3230
3387
|
}
|
|
3388
|
+
if (streamError !== void 0) {
|
|
3389
|
+
logger.error({ err: streamError }, "agent stream reported an error");
|
|
3390
|
+
throw streamError;
|
|
3391
|
+
}
|
|
3231
3392
|
const end = Date.now();
|
|
3232
3393
|
const usage = await stream.totalUsage;
|
|
3233
3394
|
logger.info(
|
|
@@ -3387,7 +3548,7 @@ async function runAnalysis(mode, extraInstructions = []) {
|
|
|
3387
3548
|
// package.json
|
|
3388
3549
|
var package_default = {
|
|
3389
3550
|
name: "@algolia/wizard",
|
|
3390
|
-
version: "0.
|
|
3551
|
+
version: "0.41.0-rc.131.290",
|
|
3391
3552
|
description: "Magically implement Algolia functionality in your codebase",
|
|
3392
3553
|
type: "module",
|
|
3393
3554
|
engines: {
|
|
@@ -4258,6 +4419,10 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
|
|
|
4258
4419
|
if (useCases.includes("ingestion")) {
|
|
4259
4420
|
ingestAppId = appId ?? (await requireApplication()).id;
|
|
4260
4421
|
}
|
|
4422
|
+
let ingestWriteKey;
|
|
4423
|
+
if (useCases.includes("ingestion") && ingestAppId) {
|
|
4424
|
+
ingestWriteKey = (await resolveWriteKey(targetIndex, ingestAppId)).key;
|
|
4425
|
+
}
|
|
4261
4426
|
let uploadFilePath;
|
|
4262
4427
|
let uploadWarning;
|
|
4263
4428
|
if (ingestionSource === "fileUpload") {
|
|
@@ -4320,9 +4485,9 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
|
|
|
4320
4485
|
let ingestDurationMs;
|
|
4321
4486
|
let ingestOutcomeMessage;
|
|
4322
4487
|
const ingestKeyAppId = ingestAppId;
|
|
4323
|
-
const ingestionTools = ingestKeyAppId ? makeToolContext(repoRoot, async () => ({
|
|
4488
|
+
const ingestionTools = ingestKeyAppId && ingestWriteKey ? makeToolContext(repoRoot, async () => ({
|
|
4324
4489
|
[APP_ID_VAR]: ingestKeyAppId,
|
|
4325
|
-
[API_KEY_VAR]:
|
|
4490
|
+
[API_KEY_VAR]: ingestWriteKey,
|
|
4326
4491
|
[INDEX_NAME_VAR]: targetIndex
|
|
4327
4492
|
})) : void 0;
|
|
4328
4493
|
const searchTools = makeToolContext(repoRoot);
|
|
@@ -4917,13 +5082,13 @@ import { Box as Box15, Text as Text15 } from "ink";
|
|
|
4917
5082
|
|
|
4918
5083
|
// src/ui/Steps.tsx
|
|
4919
5084
|
import { Box as Box13, Text as Text13 } from "ink";
|
|
4920
|
-
import
|
|
5085
|
+
import Spinner2 from "ink-spinner";
|
|
4921
5086
|
import { jsx as jsx11, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
4922
5087
|
function Steps() {
|
|
4923
5088
|
const { steps } = useWizard();
|
|
4924
5089
|
const visibleSteps = steps.filter(isStepVisible);
|
|
4925
5090
|
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: [
|
|
4926
|
-
s.status === "running" ? /* @__PURE__ */ jsx11(
|
|
5091
|
+
s.status === "running" ? /* @__PURE__ */ jsx11(Spinner2, { type: "dots" }) : MARKER[s.status],
|
|
4927
5092
|
" ",
|
|
4928
5093
|
s.title
|
|
4929
5094
|
] }) }, s.id)) });
|
|
@@ -4933,7 +5098,7 @@ function CurrentStep() {
|
|
|
4933
5098
|
const currentStep = steps.filter(isStepVisible).find((s) => s.status === "running");
|
|
4934
5099
|
if (!currentStep) return null;
|
|
4935
5100
|
return /* @__PURE__ */ jsxs12(Text13, { color: COLORS.status.running, children: [
|
|
4936
|
-
/* @__PURE__ */ jsx11(
|
|
5101
|
+
/* @__PURE__ */ jsx11(Spinner2, { type: "dots" }),
|
|
4937
5102
|
" ",
|
|
4938
5103
|
` ${currentStep.title}`
|
|
4939
5104
|
] });
|
|
@@ -5036,7 +5201,7 @@ function logNameColor(entry) {
|
|
|
5036
5201
|
return STATUS_COLOR[entry.status] ?? KIND_COLOR[entry.kind];
|
|
5037
5202
|
}
|
|
5038
5203
|
var ROW_GAP = 1;
|
|
5039
|
-
function
|
|
5204
|
+
function truncate3(str, maxWidth) {
|
|
5040
5205
|
if (maxWidth <= 0) return "";
|
|
5041
5206
|
return str.length > maxWidth ? `${str.slice(0, maxWidth - 1)}\u2026` : str;
|
|
5042
5207
|
}
|
|
@@ -5068,9 +5233,9 @@ function Logs() {
|
|
|
5068
5233
|
const partCount = 2 + (rawPreview ? 1 : 0) + (durationText ? 1 : 0);
|
|
5069
5234
|
const gaps = (partCount - 1) * ROW_GAP;
|
|
5070
5235
|
let budget = scroll.width - timestamp.length - durationText.length - gaps;
|
|
5071
|
-
const name =
|
|
5236
|
+
const name = truncate3(entry.name, budget);
|
|
5072
5237
|
budget -= name.length;
|
|
5073
|
-
const preview = rawPreview ?
|
|
5238
|
+
const preview = rawPreview ? truncate3(rawPreview, budget) : "";
|
|
5074
5239
|
return /* @__PURE__ */ jsxs16(Box17, { flexDirection: "row", gap: ROW_GAP, children: [
|
|
5075
5240
|
/* @__PURE__ */ jsx15(Text17, { color: COLORS.dim, children: timestamp }),
|
|
5076
5241
|
/* @__PURE__ */ jsx15(Text17, { color: logNameColor(entry), wrap: "truncate", children: name }),
|
|
@@ -5478,6 +5643,7 @@ function App() {
|
|
|
5478
5643
|
inputReq,
|
|
5479
5644
|
user,
|
|
5480
5645
|
workflow,
|
|
5646
|
+
settingUpAppId,
|
|
5481
5647
|
review: review2
|
|
5482
5648
|
} = useWizard();
|
|
5483
5649
|
const { exit } = useApp();
|
|
@@ -5493,7 +5659,7 @@ function App() {
|
|
|
5493
5659
|
const isCommandApprovalPrompt = isAwaitingUserInput && inputReq?.promptType === "commandApproval";
|
|
5494
5660
|
const promptPending = isAwaitingUserInput && !isCommandApprovalPrompt;
|
|
5495
5661
|
const holdForTip = stepHasTips && promptPending && tipState === "revealing";
|
|
5496
|
-
const showTips = stepHasTips && (phase === "running" || isCommandApprovalPrompt || holdForTip);
|
|
5662
|
+
const showTips = stepHasTips && (phase === "running" && currentStep?.status === "running" || isCommandApprovalPrompt || holdForTip);
|
|
5497
5663
|
const showNoticesInMain = !stepHasTips;
|
|
5498
5664
|
const showNotices = (!isAwaitingUserInput || holdForTip) && !review2;
|
|
5499
5665
|
useInput7(
|
|
@@ -5564,20 +5730,26 @@ function App() {
|
|
|
5564
5730
|
children: [
|
|
5565
5731
|
/* @__PURE__ */ jsxs18(Box20, { flexGrow: 2, flexDirection: "column", children: [
|
|
5566
5732
|
phase === "preflight" && !user && /* @__PURE__ */ jsx18(Box20, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs18(Text20, { color: COLORS.strong, bold: true, children: [
|
|
5567
|
-
/* @__PURE__ */ jsx18(
|
|
5733
|
+
/* @__PURE__ */ jsx18(Spinner3, { type: "dots" }),
|
|
5568
5734
|
" Signing in to Algolia"
|
|
5569
5735
|
] }) }),
|
|
5570
5736
|
phase === "preflight" && user && /* @__PURE__ */ jsx18(Box20, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs18(Text20, { color: COLORS.strong, bold: true, children: [
|
|
5571
|
-
/* @__PURE__ */ jsx18(
|
|
5737
|
+
/* @__PURE__ */ jsx18(Spinner3, { type: "dots" }),
|
|
5572
5738
|
" Getting things ready"
|
|
5573
5739
|
] }) }),
|
|
5574
5740
|
phase === "authenticating" && /* @__PURE__ */ jsxs18(Box20, { flexDirection: "column", marginBottom: 1, children: [
|
|
5575
5741
|
/* @__PURE__ */ jsxs18(Text20, { color: COLORS.strong, bold: true, children: [
|
|
5576
|
-
/* @__PURE__ */ jsx18(
|
|
5742
|
+
/* @__PURE__ */ jsx18(Spinner3, { type: "dots" }),
|
|
5577
5743
|
" Signing in to Algolia"
|
|
5578
5744
|
] }),
|
|
5579
5745
|
/* @__PURE__ */ jsx18(Text20, { color: COLORS.muted, children: "A browser window will open \u2014 complete sign-in there." })
|
|
5580
5746
|
] }),
|
|
5747
|
+
settingUpAppId && /* @__PURE__ */ jsx18(Box20, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs18(Text20, { color: COLORS.strong, bold: true, children: [
|
|
5748
|
+
/* @__PURE__ */ jsx18(Spinner3, { type: "dots" }),
|
|
5749
|
+
" Setting up Wizard using app",
|
|
5750
|
+
" ",
|
|
5751
|
+
settingUpAppId
|
|
5752
|
+
] }) }),
|
|
5581
5753
|
/* @__PURE__ */ jsx18(CliOutput, {}),
|
|
5582
5754
|
showTips && currentStep && /* @__PURE__ */ jsx18(
|
|
5583
5755
|
Tips,
|
|
@@ -5648,50 +5820,72 @@ function readValue(raw) {
|
|
|
5648
5820
|
}
|
|
5649
5821
|
|
|
5650
5822
|
// src/lib/algoliaAppPicker.ts
|
|
5651
|
-
function
|
|
5823
|
+
function blockReasonFor(app) {
|
|
5824
|
+
return app.status !== "active" ? "Paused" : "Missing permissions";
|
|
5825
|
+
}
|
|
5826
|
+
function secondaryFor(app, highlightId) {
|
|
5827
|
+
if (!canSelectApplication(app)) {
|
|
5828
|
+
return { kind: "text", value: blockReasonFor(app) };
|
|
5829
|
+
}
|
|
5830
|
+
if (app.id === highlightId) {
|
|
5831
|
+
return { kind: "badge", value: "[DETECTED]" };
|
|
5832
|
+
}
|
|
5652
5833
|
return app.plan ? { kind: "badge", value: app.plan } : void 0;
|
|
5653
5834
|
}
|
|
5654
5835
|
function labelFor(app) {
|
|
5655
5836
|
return app.name.trim() ? `${app.name} \u2014 ${app.id}` : app.id;
|
|
5656
5837
|
}
|
|
5657
|
-
function
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
);
|
|
5662
|
-
return selectApplication(app.id);
|
|
5838
|
+
async function isEligible(app) {
|
|
5839
|
+
const apps = await listApplications();
|
|
5840
|
+
const full = apps.find((candidate) => candidate.id === app.id);
|
|
5841
|
+
return full != null && canSelectApplication(full);
|
|
5663
5842
|
}
|
|
5664
|
-
async function
|
|
5843
|
+
async function selectAndReport(app) {
|
|
5665
5844
|
const store = useWizard.getState();
|
|
5666
|
-
|
|
5667
|
-
|
|
5845
|
+
store.setSettingUpApp(app.id);
|
|
5846
|
+
try {
|
|
5847
|
+
return await selectApplication(app.id);
|
|
5848
|
+
} finally {
|
|
5849
|
+
store.setSettingUpApp(null);
|
|
5850
|
+
}
|
|
5851
|
+
}
|
|
5852
|
+
async function promptForApplication(highlight) {
|
|
5853
|
+
const store = useWizard.getState();
|
|
5854
|
+
const unordered = await listApplications();
|
|
5855
|
+
if (unordered.length === 0) {
|
|
5668
5856
|
throw new Error(
|
|
5669
5857
|
"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
5858
|
);
|
|
5671
5859
|
}
|
|
5672
|
-
if (
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
{ app: only.id },
|
|
5676
|
-
"single application on the account; selecting it"
|
|
5860
|
+
if (!unordered.some(canSelectApplication)) {
|
|
5861
|
+
throw new Error(
|
|
5862
|
+
"None of the applications on this Algolia account are usable \u2014 each is either paused or missing key-management access. Activate one, or grant it the `keys` ACL, then restart the wizard."
|
|
5677
5863
|
);
|
|
5678
|
-
for (const line of leadIn) store.pushCliOutput("stdout", line);
|
|
5679
|
-
return selectAndReport(only);
|
|
5680
5864
|
}
|
|
5681
|
-
const
|
|
5682
|
-
...
|
|
5683
|
-
|
|
5865
|
+
const apps = [
|
|
5866
|
+
...unordered.filter(canSelectApplication),
|
|
5867
|
+
...unordered.filter((app) => !canSelectApplication(app))
|
|
5684
5868
|
];
|
|
5869
|
+
const envApp = highlight ? unordered.find((app) => app.id === highlight.id) : void 0;
|
|
5870
|
+
const highlightIndex = envApp && canSelectApplication(envApp) ? apps.indexOf(envApp) : -1;
|
|
5871
|
+
const messages = [];
|
|
5872
|
+
if (highlight && highlightIndex < 0) {
|
|
5873
|
+
messages.push(
|
|
5874
|
+
envApp ? `Could not use ${highlight.id} from ${highlight.file} \u2014 it\u2019s ${blockReasonFor(envApp).toLowerCase()}. Pick another below.` : `Could not use ${highlight.id} from ${highlight.file} \u2014 it may have been removed, or this account may not have access to it.`
|
|
5875
|
+
);
|
|
5876
|
+
}
|
|
5685
5877
|
for (; ; ) {
|
|
5686
5878
|
const choice = await store.requestUserInput({
|
|
5687
|
-
prompt: "
|
|
5879
|
+
prompt: "Which Algolia application should the wizard work in?",
|
|
5688
5880
|
promptType: "multipleChoice",
|
|
5689
5881
|
options: apps.map(labelFor),
|
|
5690
|
-
secondary: apps.map(secondaryFor),
|
|
5882
|
+
secondary: apps.map((app) => secondaryFor(app, highlight?.id)),
|
|
5883
|
+
disabled: apps.map((app) => !canSelectApplication(app)),
|
|
5884
|
+
...highlightIndex >= 0 ? { defaultSelectedIndex: highlightIndex } : {},
|
|
5691
5885
|
messages
|
|
5692
5886
|
});
|
|
5693
5887
|
const chosen = apps.find((app) => labelFor(app) === choice);
|
|
5694
|
-
if (!chosen) {
|
|
5888
|
+
if (!chosen || !canSelectApplication(chosen)) {
|
|
5695
5889
|
throw new Error("Application picker received an unexpected selection");
|
|
5696
5890
|
}
|
|
5697
5891
|
try {
|
|
@@ -5707,42 +5901,15 @@ async function promptForApplication(leadIn = []) {
|
|
|
5707
5901
|
}
|
|
5708
5902
|
}
|
|
5709
5903
|
}
|
|
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() {
|
|
5904
|
+
async function ensureApplication(isResuming) {
|
|
5740
5905
|
const current = await currentApplication();
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
return
|
|
5906
|
+
if (isResuming) {
|
|
5907
|
+
if (current && await isEligible(current)) return current;
|
|
5908
|
+
return promptForApplication();
|
|
5744
5909
|
}
|
|
5745
|
-
|
|
5910
|
+
const env = await findEnvApplicationId();
|
|
5911
|
+
if (!env) return promptForApplication();
|
|
5912
|
+
return promptForApplication({ id: env.id, file: env.file });
|
|
5746
5913
|
}
|
|
5747
5914
|
|
|
5748
5915
|
// src/lib/seed.ts
|
|
@@ -6106,14 +6273,15 @@ async function run(workflow) {
|
|
|
6106
6273
|
}
|
|
6107
6274
|
store.setUser(user);
|
|
6108
6275
|
let app;
|
|
6276
|
+
const resumableState = await loadResumableState(workflow);
|
|
6109
6277
|
try {
|
|
6110
|
-
app = await ensureApplication();
|
|
6278
|
+
app = await ensureApplication(resumableState != null);
|
|
6111
6279
|
} catch (err) {
|
|
6112
6280
|
store.setError(err instanceof Error ? err.message : String(err));
|
|
6113
6281
|
await instance.waitUntilExit();
|
|
6114
6282
|
process.exit(1);
|
|
6115
6283
|
}
|
|
6116
|
-
runWorkflow(workflow, app.id);
|
|
6284
|
+
runWorkflow(workflow, app.id, resumableState);
|
|
6117
6285
|
}
|
|
6118
6286
|
await requestTerminalSize();
|
|
6119
6287
|
var started = await startup();
|