@algolia/wizard 0.3.0 → 0.4.0-rc.48.12
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 +305 -78
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
import { render } from "ink";
|
|
5
5
|
|
|
6
6
|
// src/ui/App.tsx
|
|
7
|
-
import { Box as
|
|
7
|
+
import { Box as Box13, Text as Text13, useApp, useInput as useInput6, useWindowSize as useWindowSize6 } from "ink";
|
|
8
8
|
|
|
9
9
|
// src/core/store.ts
|
|
10
10
|
import { create } from "zustand";
|
|
11
|
+
import { nanoid } from "nanoid";
|
|
11
12
|
|
|
12
13
|
// src/lib/algoliaCli.ts
|
|
13
14
|
import { spawn } from "node:child_process";
|
|
@@ -165,6 +166,10 @@ async function markInteraction() {
|
|
|
165
166
|
function toUserInfo({ user_id, ...rest }) {
|
|
166
167
|
return { userId: user_id, ...rest };
|
|
167
168
|
}
|
|
169
|
+
function describeInputValue(value) {
|
|
170
|
+
if (typeof value === "boolean") return value ? "Yes" : "No";
|
|
171
|
+
return Array.isArray(value) ? value.join(", ") : value;
|
|
172
|
+
}
|
|
168
173
|
var NOTICE_INTERVAL_MS = 2e3;
|
|
169
174
|
var useWizard = create((set, get) => ({
|
|
170
175
|
phase: "idle",
|
|
@@ -177,6 +182,7 @@ var useWizard = create((set, get) => ({
|
|
|
177
182
|
notices: [],
|
|
178
183
|
_noticeQueue: [],
|
|
179
184
|
_noticeTimer: null,
|
|
185
|
+
logs: [],
|
|
180
186
|
error: null,
|
|
181
187
|
inputReq: null,
|
|
182
188
|
_resolve: null,
|
|
@@ -255,6 +261,21 @@ var useWizard = create((set, get) => ({
|
|
|
255
261
|
get()._clearNoticeQueue();
|
|
256
262
|
set({ notices: [] });
|
|
257
263
|
},
|
|
264
|
+
logStart: (kind, name, input) => {
|
|
265
|
+
const id = nanoid();
|
|
266
|
+
set((s) => ({
|
|
267
|
+
logs: [
|
|
268
|
+
...s.logs,
|
|
269
|
+
{ id, kind, name, input, status: "running", startedAt: Date.now() }
|
|
270
|
+
]
|
|
271
|
+
}));
|
|
272
|
+
return id;
|
|
273
|
+
},
|
|
274
|
+
logEnd: (id, status) => set((s) => ({
|
|
275
|
+
logs: s.logs.map(
|
|
276
|
+
(t) => t.id === id ? { ...t, status, durationMs: Date.now() - t.startedAt } : t
|
|
277
|
+
)
|
|
278
|
+
})),
|
|
258
279
|
requestUserInput: (req) => new Promise((resolve4) => {
|
|
259
280
|
set({
|
|
260
281
|
phase: "awaitingInput",
|
|
@@ -262,10 +283,15 @@ var useWizard = create((set, get) => ({
|
|
|
262
283
|
_resolve: resolve4
|
|
263
284
|
});
|
|
264
285
|
}),
|
|
286
|
+
// Logs what the user picked — not the prompt text that was shown, which
|
|
287
|
+
// may repeat or duplicate on-screen content and isn't the useful signal
|
|
288
|
+
// here.
|
|
265
289
|
submitInput: async (value) => {
|
|
266
290
|
await markInteraction();
|
|
267
291
|
get()._resolve?.(value);
|
|
268
292
|
set({ inputReq: null, _resolve: null, phase: "running" });
|
|
293
|
+
const id = get().logStart("prompt", `User input: ${describeInputValue(value)}`);
|
|
294
|
+
get().logEnd(id, "success");
|
|
269
295
|
},
|
|
270
296
|
setDone: () => set({ phase: "done" }),
|
|
271
297
|
setError: (message) => set({ phase: "error", error: message }),
|
|
@@ -279,6 +305,7 @@ var useWizard = create((set, get) => ({
|
|
|
279
305
|
currentStepIndex: 0,
|
|
280
306
|
output: "",
|
|
281
307
|
notices: [],
|
|
308
|
+
logs: [],
|
|
282
309
|
error: null,
|
|
283
310
|
inputReq: null,
|
|
284
311
|
_resolve: null
|
|
@@ -722,7 +749,7 @@ function PromptInput() {
|
|
|
722
749
|
// src/ui/Welcome.tsx
|
|
723
750
|
import { dirname as dirname2, join as join3 } from "node:path";
|
|
724
751
|
import { fileURLToPath } from "node:url";
|
|
725
|
-
import { Box as Box6, Spacer, Text as Text6, useInput as useInput3 } from "ink";
|
|
752
|
+
import { Box as Box6, Spacer, Text as Text6, useInput as useInput3, useWindowSize as useWindowSize3 } from "ink";
|
|
726
753
|
|
|
727
754
|
// src/ui/copy/welcome.ts
|
|
728
755
|
var sidebarItems = [
|
|
@@ -770,36 +797,61 @@ function SidebarItem({
|
|
|
770
797
|
function Welcome() {
|
|
771
798
|
const confirmStart = useWizard((s) => s.confirmStart);
|
|
772
799
|
const openLearnMore = useWizard((s) => s.openLearnMore);
|
|
800
|
+
const { rows } = useWindowSize3();
|
|
773
801
|
useInput3((input) => {
|
|
774
802
|
if (input === " ") confirmStart();
|
|
775
803
|
else if (input === "i") openLearnMore();
|
|
776
804
|
});
|
|
805
|
+
const scales = {
|
|
806
|
+
large: {
|
|
807
|
+
sidebar: { padding: { x: 4, y: 2 }, gap: 2 },
|
|
808
|
+
main: { padding: { x: 8, y: 4 } }
|
|
809
|
+
},
|
|
810
|
+
small: {
|
|
811
|
+
sidebar: { padding: { x: 2, y: 1 }, gap: 1 },
|
|
812
|
+
main: { padding: { x: 4, y: 2 } }
|
|
813
|
+
}
|
|
814
|
+
};
|
|
815
|
+
let layout = scales["large"];
|
|
816
|
+
if (rows < 30) {
|
|
817
|
+
layout = scales["small"];
|
|
818
|
+
}
|
|
777
819
|
return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "row", justifyContent: "space-between", width: "100%", children: [
|
|
778
|
-
/* @__PURE__ */ jsx6(
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
820
|
+
/* @__PURE__ */ jsx6(
|
|
821
|
+
Box6,
|
|
822
|
+
{
|
|
823
|
+
paddingY: layout.main.padding.y,
|
|
824
|
+
paddingX: layout.main.padding.x,
|
|
825
|
+
flexDirection: "column",
|
|
826
|
+
justifyContent: "center",
|
|
827
|
+
children: /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", gap: 2, children: [
|
|
828
|
+
/* @__PURE__ */ jsx6(InkPictureProvider, { children: /* @__PURE__ */ jsx6(
|
|
829
|
+
Image,
|
|
830
|
+
{
|
|
831
|
+
src: IMAGE_PATH,
|
|
832
|
+
objectFit: "contain",
|
|
833
|
+
alt: "Algolia",
|
|
834
|
+
width: 20,
|
|
835
|
+
height: 10,
|
|
836
|
+
protocol: "halfBlock"
|
|
837
|
+
}
|
|
838
|
+
) }),
|
|
839
|
+
/* @__PURE__ */ jsx6(Text6, { color: COLORS.muted, children: "\u2726 From zero \u2192 working search in ~10 minutes" }),
|
|
840
|
+
/* @__PURE__ */ jsxs5(Box6, { gap: 1, flexDirection: "column", children: [
|
|
841
|
+
/* @__PURE__ */ jsx6(NextAction, { action: "start wizard", keyHint: "space" }),
|
|
842
|
+
/* @__PURE__ */ jsx6(NextAction, { action: "learn more", keyHint: "i", hierarchy: "secondary" })
|
|
843
|
+
] })
|
|
844
|
+
] })
|
|
845
|
+
}
|
|
846
|
+
),
|
|
796
847
|
/* @__PURE__ */ jsxs5(
|
|
797
848
|
Box6,
|
|
798
849
|
{
|
|
799
850
|
backgroundColor: COLORS.bg.sidebar,
|
|
800
851
|
width: 40,
|
|
801
|
-
|
|
802
|
-
|
|
852
|
+
paddingY: layout.sidebar.padding.y,
|
|
853
|
+
paddingX: layout.sidebar.padding.x,
|
|
854
|
+
gap: layout.sidebar.gap,
|
|
803
855
|
flexDirection: "column",
|
|
804
856
|
justifyContent: "center",
|
|
805
857
|
children: [
|
|
@@ -813,7 +865,7 @@ function Welcome() {
|
|
|
813
865
|
|
|
814
866
|
// src/ui/LearnMore.tsx
|
|
815
867
|
import { Fragment as Fragment2 } from "react";
|
|
816
|
-
import { Box as Box7, Text as Text7, useInput as useInput4, useWindowSize as
|
|
868
|
+
import { Box as Box7, Text as Text7, useInput as useInput4, useWindowSize as useWindowSize4 } from "ink";
|
|
817
869
|
|
|
818
870
|
// src/ui/copy/learn-more.ts
|
|
819
871
|
var accessIntro = "Everything runs locally on your machine. Nothing is written or sent without an explicit yes from you.";
|
|
@@ -877,7 +929,7 @@ function NeverLine({
|
|
|
877
929
|
function LearnMore() {
|
|
878
930
|
const confirmStart = useWizard((s) => s.confirmStart);
|
|
879
931
|
const backToHome = useWizard((s) => s.backToHome);
|
|
880
|
-
const { columns } =
|
|
932
|
+
const { columns } = useWindowSize4();
|
|
881
933
|
const dividerWidth = Math.max(0, columns - PADDING_X * 2);
|
|
882
934
|
useInput4((input, key) => {
|
|
883
935
|
if (key.escape) backToHome();
|
|
@@ -1087,53 +1139,205 @@ function Ribbon() {
|
|
|
1087
1139
|
}
|
|
1088
1140
|
|
|
1089
1141
|
// src/ui/App.tsx
|
|
1142
|
+
import { useState as useState6 } from "react";
|
|
1143
|
+
|
|
1144
|
+
// src/ui/Logs.tsx
|
|
1145
|
+
import { useLayoutEffect, useRef as useRef2, useState as useState5 } from "react";
|
|
1146
|
+
import { Box as Box12, Text as Text12, measureElement as measureElement2, useInput as useInput5, useWindowSize as useWindowSize5 } from "ink";
|
|
1090
1147
|
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1148
|
+
var KIND_COLOR = {
|
|
1149
|
+
tool: COLORS.primary,
|
|
1150
|
+
prompt: COLORS.badge
|
|
1151
|
+
};
|
|
1152
|
+
var STATUS_COLOR = {
|
|
1153
|
+
running: COLORS.status.running,
|
|
1154
|
+
error: COLORS.danger
|
|
1155
|
+
};
|
|
1156
|
+
function logNameColor(entry) {
|
|
1157
|
+
return STATUS_COLOR[entry.status] ?? KIND_COLOR[entry.kind];
|
|
1158
|
+
}
|
|
1159
|
+
var ROW_GAP = 1;
|
|
1160
|
+
function truncate2(str, maxWidth) {
|
|
1161
|
+
if (maxWidth <= 0) return "";
|
|
1162
|
+
return str.length > maxWidth ? `${str.slice(0, maxWidth - 1)}\u2026` : str;
|
|
1163
|
+
}
|
|
1164
|
+
function rawInputText(input) {
|
|
1165
|
+
if (input === void 0) return "";
|
|
1166
|
+
const str = typeof input === "string" ? input : JSON.stringify(input);
|
|
1167
|
+
if (!str || str === "{}") return "";
|
|
1168
|
+
return str.replace(/\s+/g, " ").trim();
|
|
1169
|
+
}
|
|
1170
|
+
function formatTimestamp(ms) {
|
|
1171
|
+
const d = new Date(ms);
|
|
1172
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
1173
|
+
return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
|
|
1174
|
+
}
|
|
1175
|
+
function Logs() {
|
|
1176
|
+
const logs = useWizard((s) => s.logs);
|
|
1177
|
+
const { rows, columns } = useWindowSize5();
|
|
1178
|
+
const viewportRef = useRef2(null);
|
|
1179
|
+
const [viewportHeight, setViewportHeight] = useState5(0);
|
|
1180
|
+
const [viewportWidth, setViewportWidth] = useState5(0);
|
|
1181
|
+
const [scrollOffset, setScrollOffset] = useState5(0);
|
|
1182
|
+
const prevMaxOffsetRef = useRef2(0);
|
|
1183
|
+
useLayoutEffect(() => {
|
|
1184
|
+
if (!viewportRef.current) return;
|
|
1185
|
+
const { width, height } = measureElement2(viewportRef.current);
|
|
1186
|
+
setViewportHeight(height);
|
|
1187
|
+
setViewportWidth(width);
|
|
1188
|
+
}, [rows, columns, logs.length === 0]);
|
|
1189
|
+
let capacity = viewportHeight;
|
|
1190
|
+
for (let i = 0; i < 2; i++) {
|
|
1191
|
+
const hasAbove = scrollOffset > 0;
|
|
1192
|
+
const hasBelow = scrollOffset + capacity < logs.length;
|
|
1193
|
+
capacity = Math.max(
|
|
1194
|
+
viewportHeight - (hasAbove ? 1 : 0) - (hasBelow ? 1 : 0),
|
|
1195
|
+
0
|
|
1196
|
+
);
|
|
1197
|
+
}
|
|
1198
|
+
const capacityAtBottom = logs.length > viewportHeight ? Math.max(viewportHeight - 1, 0) : viewportHeight;
|
|
1199
|
+
const maxOffset = Math.max(logs.length - capacityAtBottom, 0);
|
|
1200
|
+
useLayoutEffect(() => {
|
|
1201
|
+
const wasAtBottom = scrollOffset >= prevMaxOffsetRef.current;
|
|
1202
|
+
prevMaxOffsetRef.current = maxOffset;
|
|
1203
|
+
setScrollOffset((o) => wasAtBottom ? maxOffset : Math.min(o, maxOffset));
|
|
1204
|
+
}, [maxOffset]);
|
|
1205
|
+
useInput5((_input, key) => {
|
|
1206
|
+
if (!key.upArrow && !key.downArrow) return;
|
|
1207
|
+
setScrollOffset(
|
|
1208
|
+
(o) => key.upArrow ? Math.max(o - 1, 0) : Math.min(o + 1, maxOffset)
|
|
1209
|
+
);
|
|
1210
|
+
});
|
|
1211
|
+
const visible = logs.slice(scrollOffset, scrollOffset + capacity);
|
|
1212
|
+
const hiddenAbove = scrollOffset;
|
|
1213
|
+
const hiddenBelow = logs.length - scrollOffset - visible.length;
|
|
1214
|
+
return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", paddingX: 4, paddingY: 2, flexGrow: 1, children: [
|
|
1215
|
+
logs.length === 0 && /* @__PURE__ */ jsx12(Text12, { color: COLORS.dim, children: "No logs yet." }),
|
|
1216
|
+
/* @__PURE__ */ jsxs11(Box12, { ref: viewportRef, flexDirection: "column", flexGrow: 1, children: [
|
|
1217
|
+
hiddenAbove > 0 && /* @__PURE__ */ jsxs11(Text12, { color: COLORS.dim, children: [
|
|
1218
|
+
"\u2191 ",
|
|
1219
|
+
hiddenAbove,
|
|
1220
|
+
" more"
|
|
1221
|
+
] }),
|
|
1222
|
+
visible.map((entry) => {
|
|
1223
|
+
const timestamp = `[${formatTimestamp(entry.startedAt)}]`;
|
|
1224
|
+
const durationText = entry.kind === "tool" && entry.durationMs !== void 0 ? `${entry.durationMs}ms` : "";
|
|
1225
|
+
const rawPreview = rawInputText(entry.input);
|
|
1226
|
+
const partCount = 2 + (rawPreview ? 1 : 0) + (durationText ? 1 : 0);
|
|
1227
|
+
const gaps = (partCount - 1) * ROW_GAP;
|
|
1228
|
+
let budget = viewportWidth - timestamp.length - durationText.length - gaps;
|
|
1229
|
+
const name = truncate2(entry.name, budget);
|
|
1230
|
+
budget -= name.length;
|
|
1231
|
+
const preview = rawPreview ? truncate2(rawPreview, budget) : "";
|
|
1232
|
+
return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "row", gap: ROW_GAP, children: [
|
|
1233
|
+
/* @__PURE__ */ jsx12(Text12, { color: COLORS.dim, children: timestamp }),
|
|
1234
|
+
/* @__PURE__ */ jsx12(Text12, { color: logNameColor(entry), wrap: "truncate", children: name }),
|
|
1235
|
+
preview && /* @__PURE__ */ jsx12(Text12, { color: COLORS.dim, wrap: "truncate", children: preview }),
|
|
1236
|
+
durationText && /* @__PURE__ */ jsx12(Text12, { color: COLORS.dim, children: durationText })
|
|
1237
|
+
] }, entry.id);
|
|
1238
|
+
}),
|
|
1239
|
+
hiddenBelow > 0 && /* @__PURE__ */ jsxs11(Text12, { color: COLORS.dim, children: [
|
|
1240
|
+
"\u2193 ",
|
|
1241
|
+
hiddenBelow,
|
|
1242
|
+
" more"
|
|
1243
|
+
] })
|
|
1244
|
+
] }),
|
|
1245
|
+
/* @__PURE__ */ jsx12(Text12, { color: COLORS.dim, children: "\u2191/\u2193 scroll" })
|
|
1246
|
+
] });
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
// src/lib/events.ts
|
|
1250
|
+
import "zod";
|
|
1251
|
+
function track(event, payload) {
|
|
1252
|
+
const token = getAuthToken();
|
|
1253
|
+
if (!token) return;
|
|
1254
|
+
const userId = useWizard.getState().user?.userId;
|
|
1255
|
+
if (!userId) return;
|
|
1256
|
+
void proxyFetch(`${PROXY_BASE_URL}/events`, {
|
|
1257
|
+
method: "POST",
|
|
1258
|
+
headers: {
|
|
1259
|
+
"content-type": "application/json",
|
|
1260
|
+
authorization: `Bearer ${token}`
|
|
1261
|
+
},
|
|
1262
|
+
body: JSON.stringify({ userId, event, properties: payload })
|
|
1263
|
+
}).catch((err) => {
|
|
1264
|
+
logger.warn({ err, event }, "failed to send analytics event");
|
|
1265
|
+
});
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
// src/ui/App.tsx
|
|
1269
|
+
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1091
1270
|
function App() {
|
|
1092
|
-
const { phase, error, homeScreen } = useWizard();
|
|
1271
|
+
const { phase, error, homeScreen, currentStepIndex, steps, inputReq } = useWizard();
|
|
1093
1272
|
const { exit } = useApp();
|
|
1094
|
-
const { columns, rows } =
|
|
1273
|
+
const { columns, rows } = useWindowSize6();
|
|
1274
|
+
const [showLogs, setShowLogs] = useState6(false);
|
|
1095
1275
|
const finished = phase === "done" || phase === "error";
|
|
1096
|
-
|
|
1276
|
+
const currentStep = steps[currentStepIndex];
|
|
1277
|
+
useInput6(
|
|
1097
1278
|
(_input, key) => {
|
|
1098
|
-
if (key.return
|
|
1279
|
+
if (key.return) {
|
|
1099
1280
|
exit();
|
|
1100
1281
|
}
|
|
1101
1282
|
},
|
|
1102
1283
|
{ isActive: finished }
|
|
1103
1284
|
);
|
|
1285
|
+
useInput6((_input, key) => {
|
|
1286
|
+
if (phase === "idle" || phase === "preflight") return;
|
|
1287
|
+
if (key.tab) {
|
|
1288
|
+
setShowLogs(!showLogs);
|
|
1289
|
+
track("AI Wizard Interaction", {
|
|
1290
|
+
context: "global",
|
|
1291
|
+
key: "tab",
|
|
1292
|
+
currentStep: currentStep?.id
|
|
1293
|
+
});
|
|
1294
|
+
}
|
|
1295
|
+
});
|
|
1296
|
+
const escOwnedElsewhere = phase === "idle" || phase === "awaitingInput" && inputReq?.promptType === "spaceToContinue";
|
|
1297
|
+
useInput6((_input, key) => {
|
|
1298
|
+
if (escOwnedElsewhere) return;
|
|
1299
|
+
if (key.escape) {
|
|
1300
|
+
track("AI Wizard Interaction", {
|
|
1301
|
+
context: "global",
|
|
1302
|
+
key: "esc",
|
|
1303
|
+
// No step is active until `startWorkflow` — report the phase instead.
|
|
1304
|
+
currentStep: currentStep?.id ?? phase
|
|
1305
|
+
});
|
|
1306
|
+
exit();
|
|
1307
|
+
}
|
|
1308
|
+
});
|
|
1104
1309
|
const mainWindowVisible = phase === "running" || phase === "awaitingInput" || phase === "error" || phase === "done";
|
|
1105
1310
|
const flexDirection = columns > 90 ? "row" : "column";
|
|
1106
1311
|
const showSidebar = flexDirection === "row";
|
|
1107
|
-
return /* @__PURE__ */
|
|
1108
|
-
|
|
1312
|
+
return /* @__PURE__ */ jsxs12(
|
|
1313
|
+
Box13,
|
|
1109
1314
|
{
|
|
1110
1315
|
backgroundColor: COLORS.bg.main,
|
|
1111
1316
|
flexDirection: "row",
|
|
1112
1317
|
width: columns,
|
|
1113
1318
|
minHeight: rows,
|
|
1114
1319
|
children: [
|
|
1115
|
-
mainWindowVisible && /* @__PURE__ */
|
|
1116
|
-
|
|
1320
|
+
mainWindowVisible && /* @__PURE__ */ jsxs12(
|
|
1321
|
+
Box13,
|
|
1117
1322
|
{
|
|
1118
1323
|
flexDirection,
|
|
1119
1324
|
width: "100%",
|
|
1120
1325
|
justifyContent: "space-between",
|
|
1121
1326
|
children: [
|
|
1122
|
-
/* @__PURE__ */
|
|
1123
|
-
/* @__PURE__ */
|
|
1124
|
-
/* @__PURE__ */
|
|
1125
|
-
phase === "running" && showSidebar && /* @__PURE__ */
|
|
1126
|
-
phase === "error" && error && /* @__PURE__ */
|
|
1327
|
+
showLogs ? /* @__PURE__ */ jsx13(Logs, {}) : /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", paddingX: 4, paddingY: 2, width: 70, children: [
|
|
1328
|
+
/* @__PURE__ */ jsx13(Notices, {}),
|
|
1329
|
+
/* @__PURE__ */ jsx13(PromptInput, {}),
|
|
1330
|
+
phase === "running" && showSidebar && /* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx13(CurrentStep, {}) }),
|
|
1331
|
+
phase === "error" && error && /* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsxs12(Text13, { color: COLORS.status.error, children: [
|
|
1127
1332
|
"\u2716 ",
|
|
1128
1333
|
error
|
|
1129
1334
|
] }) })
|
|
1130
1335
|
] }),
|
|
1131
|
-
/* @__PURE__ */
|
|
1132
|
-
showSidebar ? /* @__PURE__ */ jsx12(Sidebar, {}) : /* @__PURE__ */ jsx12(Ribbon, {})
|
|
1336
|
+
showSidebar ? /* @__PURE__ */ jsx13(Sidebar, {}) : /* @__PURE__ */ jsx13(Ribbon, {})
|
|
1133
1337
|
]
|
|
1134
1338
|
}
|
|
1135
1339
|
),
|
|
1136
|
-
(phase === "idle" || phase === "preflight") && (homeScreen === "learnMore" ? /* @__PURE__ */
|
|
1340
|
+
(phase === "idle" || phase === "preflight") && (homeScreen === "learnMore" ? /* @__PURE__ */ jsx13(LearnMore, {}) : /* @__PURE__ */ jsx13(Welcome, {}))
|
|
1137
1341
|
]
|
|
1138
1342
|
}
|
|
1139
1343
|
);
|
|
@@ -1331,25 +1535,6 @@ function trackWorkflowError(ctx) {
|
|
|
1331
1535
|
);
|
|
1332
1536
|
}
|
|
1333
1537
|
|
|
1334
|
-
// src/lib/events.ts
|
|
1335
|
-
import "zod";
|
|
1336
|
-
function track(event, payload) {
|
|
1337
|
-
const token = getAuthToken();
|
|
1338
|
-
if (!token) return;
|
|
1339
|
-
const userId = useWizard.getState().user?.userId;
|
|
1340
|
-
if (!userId) return;
|
|
1341
|
-
void proxyFetch(`${PROXY_BASE_URL}/events`, {
|
|
1342
|
-
method: "POST",
|
|
1343
|
-
headers: {
|
|
1344
|
-
"content-type": "application/json",
|
|
1345
|
-
authorization: `Bearer ${token}`
|
|
1346
|
-
},
|
|
1347
|
-
body: JSON.stringify({ userId, event, properties: payload })
|
|
1348
|
-
}).catch((err) => {
|
|
1349
|
-
logger.warn({ err, event }, "failed to send analytics event");
|
|
1350
|
-
});
|
|
1351
|
-
}
|
|
1352
|
-
|
|
1353
1538
|
// src/core/orchestrator.ts
|
|
1354
1539
|
function defineStep(step) {
|
|
1355
1540
|
return { visible: true, ...step };
|
|
@@ -1423,6 +1608,8 @@ async function makeContext(state) {
|
|
|
1423
1608
|
requestUserInput: (prompt) => useWizard.getState().requestUserInput(prompt),
|
|
1424
1609
|
notify: (notice) => useWizard.getState().pushNotice(notice),
|
|
1425
1610
|
clearNotices: () => useWizard.getState().clearNotices(),
|
|
1611
|
+
logStart: (name, input) => useWizard.getState().logStart("tool", name, input),
|
|
1612
|
+
logEnd: (id, status) => useWizard.getState().logEnd(id, status),
|
|
1426
1613
|
updateAlgoliaState: (key, value) => {
|
|
1427
1614
|
state.algoliaState[key] = value;
|
|
1428
1615
|
},
|
|
@@ -2075,7 +2262,7 @@ function verifyImplementationTool() {
|
|
|
2075
2262
|
// src/lib/tools/generateRecord.ts
|
|
2076
2263
|
import { tool as tool9, generateText, Output, NoObjectGeneratedError } from "ai";
|
|
2077
2264
|
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
2078
|
-
import { nanoid } from "nanoid";
|
|
2265
|
+
import { nanoid as nanoid2 } from "nanoid";
|
|
2079
2266
|
import { mkdir as mkdir5, writeFile as writeFile5 } from "node:fs/promises";
|
|
2080
2267
|
import { dirname as dirname6 } from "node:path";
|
|
2081
2268
|
import z12 from "zod";
|
|
@@ -2121,7 +2308,7 @@ function generateRecordTool(ctx) {
|
|
|
2121
2308
|
// would otherwise drift to the same high-probability values and
|
|
2122
2309
|
// collide across batches. This per-batch seed pushes each call
|
|
2123
2310
|
// into a different region of the output space.
|
|
2124
|
-
`Variety seed: ${
|
|
2311
|
+
`Variety seed: ${nanoid2()}. Use it to diversify values.`
|
|
2125
2312
|
].filter(Boolean).join("\n")
|
|
2126
2313
|
});
|
|
2127
2314
|
return output.records;
|
|
@@ -2143,7 +2330,7 @@ function generateRecordTool(ctx) {
|
|
|
2143
2330
|
const batches = await Promise.all(batchSizes.map(generateBatch));
|
|
2144
2331
|
const records = batches.flat().map((record) => ({
|
|
2145
2332
|
...record,
|
|
2146
|
-
objectID:
|
|
2333
|
+
objectID: nanoid2()
|
|
2147
2334
|
}));
|
|
2148
2335
|
const slug = entityName.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
2149
2336
|
const relPath = `${DATA_DIR}/${slug}.json`;
|
|
@@ -2203,18 +2390,42 @@ function createToolContext(limits = DEFAULT_TOOL_LIMITS, cwd = process.cwd()) {
|
|
|
2203
2390
|
}
|
|
2204
2391
|
|
|
2205
2392
|
// src/lib/tools/index.ts
|
|
2393
|
+
function withLogging(name, def) {
|
|
2394
|
+
const execute = def.execute;
|
|
2395
|
+
if (!execute) return def;
|
|
2396
|
+
return {
|
|
2397
|
+
...def,
|
|
2398
|
+
execute: async (input, options) => {
|
|
2399
|
+
const id = useWizard.getState().logStart("tool", name, input);
|
|
2400
|
+
try {
|
|
2401
|
+
const output = await execute(input, options);
|
|
2402
|
+
useWizard.getState().logEnd(id, "success");
|
|
2403
|
+
return output;
|
|
2404
|
+
} catch (err) {
|
|
2405
|
+
useWizard.getState().logEnd(id, "error");
|
|
2406
|
+
throw err;
|
|
2407
|
+
}
|
|
2408
|
+
}
|
|
2409
|
+
};
|
|
2410
|
+
}
|
|
2206
2411
|
function createTools(ctx, { output, tools }) {
|
|
2207
2412
|
const all = {
|
|
2208
|
-
listFiles: listFilesTool(ctx),
|
|
2209
|
-
changeDirectory: changeDirectoryTool(ctx),
|
|
2210
|
-
reportStatus: reportStatusTool(output),
|
|
2211
|
-
readFile: readFileTool(ctx),
|
|
2212
|
-
writeFile: writeFileTool(ctx),
|
|
2213
|
-
writeCredentials:
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2413
|
+
listFiles: withLogging("listFiles", listFilesTool(ctx)),
|
|
2414
|
+
changeDirectory: withLogging("changeDirectory", changeDirectoryTool(ctx)),
|
|
2415
|
+
reportStatus: withLogging("reportStatus", reportStatusTool(output)),
|
|
2416
|
+
readFile: withLogging("readFile", readFileTool(ctx)),
|
|
2417
|
+
writeFile: withLogging("writeFile", writeFileTool(ctx)),
|
|
2418
|
+
writeCredentials: withLogging(
|
|
2419
|
+
"writeCredentials",
|
|
2420
|
+
writeCredentialsTool(ctx)
|
|
2421
|
+
),
|
|
2422
|
+
searchFiles: withLogging("searchFiles", searchFilesTool(ctx)),
|
|
2423
|
+
verifyImplementation: withLogging(
|
|
2424
|
+
"verifyImplementation",
|
|
2425
|
+
verifyImplementationTool()
|
|
2426
|
+
),
|
|
2427
|
+
generateRecord: withLogging("generateRecord", generateRecordTool(ctx)),
|
|
2428
|
+
notifyUser: withLogging("notifyUser", notifyUserTool())
|
|
2218
2429
|
};
|
|
2219
2430
|
if (!tools) return all;
|
|
2220
2431
|
const selection = /* @__PURE__ */ new Set([...tools, "reportStatus", "notifyUser"]);
|
|
@@ -2437,7 +2648,7 @@ async function runAnalysis(mode, extraInstructions = []) {
|
|
|
2437
2648
|
// package.json
|
|
2438
2649
|
var package_default = {
|
|
2439
2650
|
name: "@algolia/wizard",
|
|
2440
|
-
version: "0.
|
|
2651
|
+
version: "0.4.0-rc.48.12",
|
|
2441
2652
|
description: "Magically implement Algolia functionality in your codebase",
|
|
2442
2653
|
type: "module",
|
|
2443
2654
|
engines: {
|
|
@@ -3386,13 +3597,16 @@ function searchInstructions(input) {
|
|
|
3386
3597
|
doc,
|
|
3387
3598
|
`Add the search UI at ${input.searchLocation ? `"${input.searchLocation}"` : "the best shared, always-rendered layout location (e.g. a header/nav component)"} so it is reachable across the app \u2014 at least a working SearchBox and Hits against the "${input.targetIndex}" index.`,
|
|
3388
3599
|
"Read the App ID and a search-only API key from public env vars; never hardcode them. A search-only key is safe to expose client-side.",
|
|
3389
|
-
|
|
3600
|
+
// appId always resolves (loadActiveProfile throws otherwise); only the
|
|
3601
|
+
// search-only key is best-effort and can fall back to a placeholder.
|
|
3602
|
+
`Values: App ID "${input.appId}", search-only key ${input.searchKey ? `"${input.searchKey}"` : "(placeholder for the developer to fill in)"}.`,
|
|
3390
3603
|
// Names are fixed, not the agent's to rename: the wizard writes the
|
|
3391
3604
|
// resolved app id / search-only key into ".env" under these exact names
|
|
3392
3605
|
// right after this step, so a renamed prefix here would leave the code
|
|
3393
3606
|
// reading a var the wizard never wrote.
|
|
3394
3607
|
`Use exactly these public env var names in the code: ${input.searchEnvVars.map(({ name }) => name).join(", ")}.`,
|
|
3395
|
-
'Add any Algolia/InstantSearch packages you import to package.json "dependencies" with a valid version range; the wizard installs them in the worktree after you finish.'
|
|
3608
|
+
'Add any Algolia/InstantSearch packages you import to package.json "dependencies" with a valid version range; the wizard installs them in the worktree after you finish.',
|
|
3609
|
+
"The summary should be extremely concise; do not mention env var setup or manual testing steps \u2014 the wizard writes the resolved credentials to .env and reports that separately."
|
|
3396
3610
|
];
|
|
3397
3611
|
}
|
|
3398
3612
|
function verificationInstructions(input) {
|
|
@@ -3613,7 +3827,14 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
3613
3827
|
tools: toolsForUseCase(currentUseCase, input.ingestionSource),
|
|
3614
3828
|
outputSchema: implementationOutputSchema
|
|
3615
3829
|
});
|
|
3830
|
+
ctx.notify({
|
|
3831
|
+
messages: [`Installing dependencies for ${currentUseCase}\u2026`]
|
|
3832
|
+
});
|
|
3833
|
+
const installLogId = ctx.logStart("installWorktreeDeps", {
|
|
3834
|
+
useCase: currentUseCase
|
|
3835
|
+
});
|
|
3616
3836
|
const install = await installWorktreeDeps(worktree);
|
|
3837
|
+
ctx.logEnd(installLogId, install.ok ? "success" : "error");
|
|
3617
3838
|
if (!install.ok) {
|
|
3618
3839
|
installFailed = true;
|
|
3619
3840
|
logger.warn(
|
|
@@ -3647,6 +3868,11 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
3647
3868
|
}) === true;
|
|
3648
3869
|
if (runNow) {
|
|
3649
3870
|
const profile2 = await loadActiveProfile();
|
|
3871
|
+
ctx.notify({ messages: [`Writing records to "${targetIndex}"\u2026`] });
|
|
3872
|
+
const scriptLogId = ctx.logStart("runIngestScript", {
|
|
3873
|
+
runtime: ingestRuntime,
|
|
3874
|
+
entrypoint: ingestEntrypoint
|
|
3875
|
+
});
|
|
3650
3876
|
const startedAt = Date.now();
|
|
3651
3877
|
const run = await runIngestScript(
|
|
3652
3878
|
worktree,
|
|
@@ -3657,6 +3883,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
3657
3883
|
[API_KEY_VAR]: profile2.apiKey
|
|
3658
3884
|
}
|
|
3659
3885
|
);
|
|
3886
|
+
ctx.logEnd(scriptLogId, run.ok ? "success" : "error");
|
|
3660
3887
|
ingestScriptRan = run.ran && run.ok;
|
|
3661
3888
|
if (ingestScriptRan) {
|
|
3662
3889
|
ingestDurationMs = Date.now() - startedAt;
|
|
@@ -3934,7 +4161,7 @@ function getWorkflow(id) {
|
|
|
3934
4161
|
}
|
|
3935
4162
|
|
|
3936
4163
|
// src/main.tsx
|
|
3937
|
-
import { jsx as
|
|
4164
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
3938
4165
|
var requestedId = process.argv[2] ?? defaultWorkflow.id;
|
|
3939
4166
|
var workflow = getWorkflow(requestedId);
|
|
3940
4167
|
if (!workflow) {
|
|
@@ -3943,7 +4170,7 @@ if (!workflow) {
|
|
|
3943
4170
|
process.exit(1);
|
|
3944
4171
|
}
|
|
3945
4172
|
var store = useWizard.getState();
|
|
3946
|
-
var instance = render(/* @__PURE__ */
|
|
4173
|
+
var instance = render(/* @__PURE__ */ jsx14(App, {}), { incrementalRendering: true });
|
|
3947
4174
|
var user = await getUser();
|
|
3948
4175
|
if (!user) {
|
|
3949
4176
|
await instance.waitUntilRenderFlush();
|
|
@@ -3954,7 +4181,7 @@ if (!user) {
|
|
|
3954
4181
|
console.error(err instanceof Error ? err.message : String(err));
|
|
3955
4182
|
process.exit(1);
|
|
3956
4183
|
}
|
|
3957
|
-
instance = render(/* @__PURE__ */
|
|
4184
|
+
instance = render(/* @__PURE__ */ jsx14(App, {}), { incrementalRendering: true });
|
|
3958
4185
|
user = await getUser();
|
|
3959
4186
|
if (!user) {
|
|
3960
4187
|
store.setError(
|