@algolia/wizard 0.3.0-rc.47.9 → 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.
Files changed (2) hide show
  1. package/dist/main.js +257 -55
  2. 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 Box12, Text as Text12, useApp, useInput as useInput5, useWindowSize as useWindowSize5 } from "ink";
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
@@ -1112,53 +1139,205 @@ function Ribbon() {
1112
1139
  }
1113
1140
 
1114
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";
1115
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";
1116
1270
  function App() {
1117
- const { phase, error, homeScreen } = useWizard();
1271
+ const { phase, error, homeScreen, currentStepIndex, steps, inputReq } = useWizard();
1118
1272
  const { exit } = useApp();
1119
- const { columns, rows } = useWindowSize5();
1273
+ const { columns, rows } = useWindowSize6();
1274
+ const [showLogs, setShowLogs] = useState6(false);
1120
1275
  const finished = phase === "done" || phase === "error";
1121
- useInput5(
1276
+ const currentStep = steps[currentStepIndex];
1277
+ useInput6(
1122
1278
  (_input, key) => {
1123
- if (key.return || key.escape) {
1279
+ if (key.return) {
1124
1280
  exit();
1125
1281
  }
1126
1282
  },
1127
1283
  { isActive: finished }
1128
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
+ });
1129
1309
  const mainWindowVisible = phase === "running" || phase === "awaitingInput" || phase === "error" || phase === "done";
1130
1310
  const flexDirection = columns > 90 ? "row" : "column";
1131
1311
  const showSidebar = flexDirection === "row";
1132
- return /* @__PURE__ */ jsxs11(
1133
- Box12,
1312
+ return /* @__PURE__ */ jsxs12(
1313
+ Box13,
1134
1314
  {
1135
1315
  backgroundColor: COLORS.bg.main,
1136
1316
  flexDirection: "row",
1137
1317
  width: columns,
1138
1318
  minHeight: rows,
1139
1319
  children: [
1140
- mainWindowVisible && /* @__PURE__ */ jsxs11(
1141
- Box12,
1320
+ mainWindowVisible && /* @__PURE__ */ jsxs12(
1321
+ Box13,
1142
1322
  {
1143
1323
  flexDirection,
1144
1324
  width: "100%",
1145
1325
  justifyContent: "space-between",
1146
1326
  children: [
1147
- /* @__PURE__ */ jsxs11(Box12, { flexDirection: "column", paddingX: 4, paddingY: 2, width: 70, children: [
1148
- /* @__PURE__ */ jsx12(Notices, {}),
1149
- /* @__PURE__ */ jsx12(PromptInput, {}),
1150
- phase === "running" && showSidebar && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(CurrentStep, {}) }),
1151
- phase === "error" && error && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsxs11(Text12, { color: COLORS.status.error, children: [
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: [
1152
1332
  "\u2716 ",
1153
1333
  error
1154
1334
  ] }) })
1155
1335
  ] }),
1156
- /* @__PURE__ */ jsx12(Text12, { color: "white", backgroundColor: "#14171E" }),
1157
- showSidebar ? /* @__PURE__ */ jsx12(Sidebar, {}) : /* @__PURE__ */ jsx12(Ribbon, {})
1336
+ showSidebar ? /* @__PURE__ */ jsx13(Sidebar, {}) : /* @__PURE__ */ jsx13(Ribbon, {})
1158
1337
  ]
1159
1338
  }
1160
1339
  ),
1161
- (phase === "idle" || phase === "preflight") && (homeScreen === "learnMore" ? /* @__PURE__ */ jsx12(LearnMore, {}) : /* @__PURE__ */ jsx12(Welcome, {}))
1340
+ (phase === "idle" || phase === "preflight") && (homeScreen === "learnMore" ? /* @__PURE__ */ jsx13(LearnMore, {}) : /* @__PURE__ */ jsx13(Welcome, {}))
1162
1341
  ]
1163
1342
  }
1164
1343
  );
@@ -1356,25 +1535,6 @@ function trackWorkflowError(ctx) {
1356
1535
  );
1357
1536
  }
1358
1537
 
1359
- // src/lib/events.ts
1360
- import "zod";
1361
- function track(event, payload) {
1362
- const token = getAuthToken();
1363
- if (!token) return;
1364
- const userId = useWizard.getState().user?.userId;
1365
- if (!userId) return;
1366
- void proxyFetch(`${PROXY_BASE_URL}/events`, {
1367
- method: "POST",
1368
- headers: {
1369
- "content-type": "application/json",
1370
- authorization: `Bearer ${token}`
1371
- },
1372
- body: JSON.stringify({ userId, event, properties: payload })
1373
- }).catch((err) => {
1374
- logger.warn({ err, event }, "failed to send analytics event");
1375
- });
1376
- }
1377
-
1378
1538
  // src/core/orchestrator.ts
1379
1539
  function defineStep(step) {
1380
1540
  return { visible: true, ...step };
@@ -1448,6 +1608,8 @@ async function makeContext(state) {
1448
1608
  requestUserInput: (prompt) => useWizard.getState().requestUserInput(prompt),
1449
1609
  notify: (notice) => useWizard.getState().pushNotice(notice),
1450
1610
  clearNotices: () => useWizard.getState().clearNotices(),
1611
+ logStart: (name, input) => useWizard.getState().logStart("tool", name, input),
1612
+ logEnd: (id, status) => useWizard.getState().logEnd(id, status),
1451
1613
  updateAlgoliaState: (key, value) => {
1452
1614
  state.algoliaState[key] = value;
1453
1615
  },
@@ -2100,7 +2262,7 @@ function verifyImplementationTool() {
2100
2262
  // src/lib/tools/generateRecord.ts
2101
2263
  import { tool as tool9, generateText, Output, NoObjectGeneratedError } from "ai";
2102
2264
  import { createAnthropic } from "@ai-sdk/anthropic";
2103
- import { nanoid } from "nanoid";
2265
+ import { nanoid as nanoid2 } from "nanoid";
2104
2266
  import { mkdir as mkdir5, writeFile as writeFile5 } from "node:fs/promises";
2105
2267
  import { dirname as dirname6 } from "node:path";
2106
2268
  import z12 from "zod";
@@ -2146,7 +2308,7 @@ function generateRecordTool(ctx) {
2146
2308
  // would otherwise drift to the same high-probability values and
2147
2309
  // collide across batches. This per-batch seed pushes each call
2148
2310
  // into a different region of the output space.
2149
- `Variety seed: ${nanoid()}. Use it to diversify values.`
2311
+ `Variety seed: ${nanoid2()}. Use it to diversify values.`
2150
2312
  ].filter(Boolean).join("\n")
2151
2313
  });
2152
2314
  return output.records;
@@ -2168,7 +2330,7 @@ function generateRecordTool(ctx) {
2168
2330
  const batches = await Promise.all(batchSizes.map(generateBatch));
2169
2331
  const records = batches.flat().map((record) => ({
2170
2332
  ...record,
2171
- objectID: nanoid()
2333
+ objectID: nanoid2()
2172
2334
  }));
2173
2335
  const slug = entityName.toLowerCase().replace(/[^a-z0-9]+/g, "-");
2174
2336
  const relPath = `${DATA_DIR}/${slug}.json`;
@@ -2228,18 +2390,42 @@ function createToolContext(limits = DEFAULT_TOOL_LIMITS, cwd = process.cwd()) {
2228
2390
  }
2229
2391
 
2230
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
+ }
2231
2411
  function createTools(ctx, { output, tools }) {
2232
2412
  const all = {
2233
- listFiles: listFilesTool(ctx),
2234
- changeDirectory: changeDirectoryTool(ctx),
2235
- reportStatus: reportStatusTool(output),
2236
- readFile: readFileTool(ctx),
2237
- writeFile: writeFileTool(ctx),
2238
- writeCredentials: writeCredentialsTool(ctx),
2239
- searchFiles: searchFilesTool(ctx),
2240
- verifyImplementation: verifyImplementationTool(),
2241
- generateRecord: generateRecordTool(ctx),
2242
- notifyUser: notifyUserTool()
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())
2243
2429
  };
2244
2430
  if (!tools) return all;
2245
2431
  const selection = /* @__PURE__ */ new Set([...tools, "reportStatus", "notifyUser"]);
@@ -2462,7 +2648,7 @@ async function runAnalysis(mode, extraInstructions = []) {
2462
2648
  // package.json
2463
2649
  var package_default = {
2464
2650
  name: "@algolia/wizard",
2465
- version: "0.3.0-rc.47.9",
2651
+ version: "0.4.0-rc.48.12",
2466
2652
  description: "Magically implement Algolia functionality in your codebase",
2467
2653
  type: "module",
2468
2654
  engines: {
@@ -3411,13 +3597,16 @@ function searchInstructions(input) {
3411
3597
  doc,
3412
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.`,
3413
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.",
3414
- `Values: App ID ${input.appId ? `"${input.appId}"` : "(placeholder for the developer to fill in)"}, search-only key ${input.searchKey ? `"${input.searchKey}"` : "(placeholder for the developer to fill in)"}.`,
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)"}.`,
3415
3603
  // Names are fixed, not the agent's to rename: the wizard writes the
3416
3604
  // resolved app id / search-only key into ".env" under these exact names
3417
3605
  // right after this step, so a renamed prefix here would leave the code
3418
3606
  // reading a var the wizard never wrote.
3419
3607
  `Use exactly these public env var names in the code: ${input.searchEnvVars.map(({ name }) => name).join(", ")}.`,
3420
- '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."
3421
3610
  ];
3422
3611
  }
3423
3612
  function verificationInstructions(input) {
@@ -3638,7 +3827,14 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
3638
3827
  tools: toolsForUseCase(currentUseCase, input.ingestionSource),
3639
3828
  outputSchema: implementationOutputSchema
3640
3829
  });
3830
+ ctx.notify({
3831
+ messages: [`Installing dependencies for ${currentUseCase}\u2026`]
3832
+ });
3833
+ const installLogId = ctx.logStart("installWorktreeDeps", {
3834
+ useCase: currentUseCase
3835
+ });
3641
3836
  const install = await installWorktreeDeps(worktree);
3837
+ ctx.logEnd(installLogId, install.ok ? "success" : "error");
3642
3838
  if (!install.ok) {
3643
3839
  installFailed = true;
3644
3840
  logger.warn(
@@ -3672,6 +3868,11 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
3672
3868
  }) === true;
3673
3869
  if (runNow) {
3674
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
+ });
3675
3876
  const startedAt = Date.now();
3676
3877
  const run = await runIngestScript(
3677
3878
  worktree,
@@ -3682,6 +3883,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
3682
3883
  [API_KEY_VAR]: profile2.apiKey
3683
3884
  }
3684
3885
  );
3886
+ ctx.logEnd(scriptLogId, run.ok ? "success" : "error");
3685
3887
  ingestScriptRan = run.ran && run.ok;
3686
3888
  if (ingestScriptRan) {
3687
3889
  ingestDurationMs = Date.now() - startedAt;
@@ -3959,7 +4161,7 @@ function getWorkflow(id) {
3959
4161
  }
3960
4162
 
3961
4163
  // src/main.tsx
3962
- import { jsx as jsx13 } from "react/jsx-runtime";
4164
+ import { jsx as jsx14 } from "react/jsx-runtime";
3963
4165
  var requestedId = process.argv[2] ?? defaultWorkflow.id;
3964
4166
  var workflow = getWorkflow(requestedId);
3965
4167
  if (!workflow) {
@@ -3968,7 +4170,7 @@ if (!workflow) {
3968
4170
  process.exit(1);
3969
4171
  }
3970
4172
  var store = useWizard.getState();
3971
- var instance = render(/* @__PURE__ */ jsx13(App, {}), { incrementalRendering: true });
4173
+ var instance = render(/* @__PURE__ */ jsx14(App, {}), { incrementalRendering: true });
3972
4174
  var user = await getUser();
3973
4175
  if (!user) {
3974
4176
  await instance.waitUntilRenderFlush();
@@ -3979,7 +4181,7 @@ if (!user) {
3979
4181
  console.error(err instanceof Error ? err.message : String(err));
3980
4182
  process.exit(1);
3981
4183
  }
3982
- instance = render(/* @__PURE__ */ jsx13(App, {}), { incrementalRendering: true });
4184
+ instance = render(/* @__PURE__ */ jsx14(App, {}), { incrementalRendering: true });
3983
4185
  user = await getUser();
3984
4186
  if (!user) {
3985
4187
  store.setError(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@algolia/wizard",
3
- "version": "0.3.0-rc.47.9",
3
+ "version": "0.4.0-rc.48.12",
4
4
  "description": "Magically implement Algolia functionality in your codebase",
5
5
  "type": "module",
6
6
  "engines": {