@algolia/wizard 0.5.0-rc.49.19 → 0.5.0-rc.50.20

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 +156 -180
  2. package/package.json +2 -2
package/dist/main.js CHANGED
@@ -1324,7 +1324,18 @@ function App() {
1324
1324
  width: "100%",
1325
1325
  justifyContent: "space-between",
1326
1326
  children: [
1327
- showLogs ? /* @__PURE__ */ jsx13(Logs, {}) : /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", paddingX: 4, paddingY: 2, width: 70, children: [
1327
+ showLogs ? (
1328
+ // The error also renders here, not just in the main panel — a user
1329
+ // watching the raw log through a long step would otherwise never
1330
+ // see that the workflow failed.
1331
+ /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", flexGrow: 1, children: [
1332
+ /* @__PURE__ */ jsx13(Logs, {}),
1333
+ phase === "error" && error && /* @__PURE__ */ jsx13(Box13, { paddingX: 4, paddingBottom: 1, children: /* @__PURE__ */ jsxs12(Text13, { color: COLORS.status.error, children: [
1334
+ "\u2716 ",
1335
+ error
1336
+ ] }) })
1337
+ ] })
1338
+ ) : /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", paddingX: 4, paddingY: 2, width: 70, children: [
1328
1339
  /* @__PURE__ */ jsx13(Notices, {}),
1329
1340
  /* @__PURE__ */ jsx13(PromptInput, {}),
1330
1341
  phase === "running" && showSidebar && /* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx13(CurrentStep, {}) }),
@@ -1353,8 +1364,7 @@ var configFile = () => join5(stateDir(), "config.json");
1353
1364
  var DEFAULT_CONFIG = {
1354
1365
  version: 1,
1355
1366
  aiConsent: false,
1356
- workflowsRun: [],
1357
- searchApiKeys: {}
1367
+ workflowsRun: []
1358
1368
  };
1359
1369
  async function loadConfig() {
1360
1370
  try {
@@ -1373,38 +1383,6 @@ async function recordWorkflowRun(workflowId, completedAt) {
1373
1383
  config.workflowsRun.push({ workflowId, completedAt });
1374
1384
  await saveConfig(config);
1375
1385
  }
1376
- function isStoredSearchKey(value) {
1377
- if (typeof value !== "object" || value === null) return false;
1378
- const { appId, key } = value;
1379
- return typeof appId === "string" && !!appId && typeof key === "string" && !!key;
1380
- }
1381
- function storedSearchKeys(config) {
1382
- const stored = config.searchApiKeys;
1383
- if (typeof stored !== "object" || stored === null || Array.isArray(stored)) {
1384
- return {};
1385
- }
1386
- return stored;
1387
- }
1388
- async function getStoredSearchKey(index, appId) {
1389
- const entry = storedSearchKeys(await loadConfig())[index];
1390
- if (!isStoredSearchKey(entry) || entry.appId !== appId) return void 0;
1391
- return entry.key;
1392
- }
1393
- async function storeSearchKey(index, appId, key) {
1394
- const config = await loadConfig();
1395
- config.searchApiKeys = {
1396
- ...storedSearchKeys(config),
1397
- [index]: { appId, key }
1398
- };
1399
- await saveConfig(config);
1400
- }
1401
- async function forgetSearchKey(index) {
1402
- const config = await loadConfig();
1403
- const remaining = { ...storedSearchKeys(config) };
1404
- delete remaining[index];
1405
- config.searchApiKeys = remaining;
1406
- await saveConfig(config);
1407
- }
1408
1386
 
1409
1387
  // src/lib/telemetry.ts
1410
1388
  function isTelemetryEnabled() {
@@ -1886,7 +1864,12 @@ var selectIndexStep = async (ctx) => {
1886
1864
  };
1887
1865
 
1888
1866
  // src/lib/agent.ts
1889
- import { ToolLoopAgent, hasToolCall, Output as Output2 } from "ai";
1867
+ import {
1868
+ ToolLoopAgent,
1869
+ hasToolCall,
1870
+ stepCountIs,
1871
+ Output as Output2
1872
+ } from "ai";
1890
1873
  import { createAnthropic as createAnthropic2 } from "@ai-sdk/anthropic";
1891
1874
  import "zod";
1892
1875
 
@@ -2479,9 +2462,41 @@ var MODEL_BY_SIZE = {
2479
2462
  medium: "claude-sonnet-4-6",
2480
2463
  large: "claude-opus-4-8"
2481
2464
  };
2465
+ var STEP_TIMEOUT_MS = 15e4;
2466
+ var CHUNK_TIMEOUT_MS = 45e3;
2467
+ var MAX_STEPS = 100;
2468
+ function withRollingCacheBreakpoint(messages) {
2469
+ const last = messages.at(-1);
2470
+ if (!last) return messages;
2471
+ return [
2472
+ ...messages.slice(0, -1),
2473
+ {
2474
+ ...last,
2475
+ providerOptions: {
2476
+ ...last.providerOptions,
2477
+ anthropic: {
2478
+ ...last.providerOptions?.anthropic,
2479
+ cacheControl: { type: "ephemeral" }
2480
+ }
2481
+ }
2482
+ }
2483
+ ];
2484
+ }
2485
+ function asAgentError(name, err) {
2486
+ const aborted = err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError");
2487
+ const message = err instanceof Error ? err.message : String(err);
2488
+ return new Error(
2489
+ aborted ? `${name} agent stalled \u2014 no response for ${STEP_TIMEOUT_MS / 1e3}s, or the stream died mid-response` : `${name} agent failed: ${message}`,
2490
+ { cause: err }
2491
+ );
2492
+ }
2482
2493
  async function runAgent(req) {
2483
2494
  const start = Date.now();
2484
- logger.info({ startedAt: new Date(start).toISOString() }, "runAgent started");
2495
+ const name = req.name ?? "unnamed";
2496
+ logger.info(
2497
+ { agent: name, startedAt: new Date(start).toISOString() },
2498
+ "runAgent started"
2499
+ );
2485
2500
  const token = getAuthToken();
2486
2501
  if (!token) {
2487
2502
  throw new Error("Not authenticated: no user token available");
@@ -2501,11 +2516,16 @@ async function runAgent(req) {
2501
2516
  ] : [],
2502
2517
  "Call notifyUser whenever you start a new phase of work or your focus shifts (e.g. moving from reading code to writing files) \u2014 a short, plain-language, high-level update. Do not call it for every tool use."
2503
2518
  ];
2519
+ let streamError;
2520
+ const logStreamErrors = {
2521
+ onError: ({ error }) => logger.error({ agent: name, err: error }, "agent stream error")
2522
+ };
2504
2523
  const agent = new ToolLoopAgent({
2524
+ ...logStreamErrors,
2505
2525
  model: anthropic2(MODEL_BY_SIZE[req.modelSize ?? "medium"]),
2506
- // Cache tools + system on the last system block. Tools render before
2507
- // system, so one breakpoint here caches both, reused on every loop turn
2508
- // after the first.
2526
+ // Cache the tools and instructions too (see `withRollingCacheBreakpoint`).
2527
+ // Tools are sent ahead of instructions, so one mark on the last instruction
2528
+ // covers both; every step after the first reads them from cache.
2509
2529
  instructions: instructions.map((i, idx, arr) => {
2510
2530
  return {
2511
2531
  role: "system",
@@ -2523,51 +2543,70 @@ async function runAgent(req) {
2523
2543
  tools: req.tools
2524
2544
  }),
2525
2545
  toolChoice: "required",
2526
- stopWhen: [hasToolCall("reportStatus")]
2546
+ stopWhen: [hasToolCall("reportStatus"), stepCountIs(MAX_STEPS)],
2547
+ prepareStep: ({ messages }) => ({
2548
+ messages: withRollingCacheBreakpoint(messages)
2549
+ })
2527
2550
  });
2528
2551
  const stream = await agent.stream({
2529
- prompt: "Follow system instructions"
2552
+ prompt: "Follow system instructions",
2553
+ timeout: { stepMs: STEP_TIMEOUT_MS, chunkMs: CHUNK_TIMEOUT_MS }
2530
2554
  });
2531
2555
  let chunks = [];
2532
2556
  const chunkLimit = 5;
2533
- for await (const chunk of stream.textStream) {
2534
- if (chunks.length < chunkLimit) {
2535
- chunks.push(chunk);
2536
- continue;
2557
+ try {
2558
+ for await (const part of stream.fullStream) {
2559
+ if (part.type === "error") {
2560
+ streamError ??= part.error;
2561
+ continue;
2562
+ }
2563
+ if (part.type !== "text-delta") continue;
2564
+ if (chunks.length < chunkLimit) {
2565
+ chunks.push(part.text);
2566
+ continue;
2567
+ }
2568
+ chunks.push(part.text);
2569
+ logger.debug(chunks.join(""));
2570
+ chunks = [];
2537
2571
  }
2538
- chunks.push(chunk);
2539
- logger.debug(chunks.join(""));
2540
- chunks = [];
2572
+ } catch (err) {
2573
+ throw asAgentError(name, streamError ?? err);
2541
2574
  }
2542
2575
  if (chunks.length) {
2543
2576
  logger.debug(chunks.join(""));
2544
2577
  }
2545
2578
  const end = Date.now();
2546
- const usage = await stream.totalUsage;
2579
+ let usage;
2580
+ let toolResults;
2581
+ try {
2582
+ usage = await stream.totalUsage;
2583
+ toolResults = await stream.toolResults;
2584
+ } catch (err) {
2585
+ throw asAgentError(name, streamError ?? err);
2586
+ }
2547
2587
  logger.info(
2548
2588
  {
2589
+ agent: name,
2549
2590
  finishedAt: new Date(end).toISOString(),
2550
2591
  durationMs: end - start,
2551
- // cachedInputTokens > 0 confirms prompt caching engaged. If it stays 0
2552
- // across turns, the tools+system prefix is under the model's min
2553
- // cacheable size (2048 tokens for sonnet-4-6) and caching is a no-op.
2554
2592
  usage
2555
2593
  },
2556
2594
  "runAgent finished"
2557
2595
  );
2558
2596
  logger.info(
2559
- { counts: toolContext.counts, limits: toolContext.limits },
2597
+ { agent: name, counts: toolContext.counts, limits: toolContext.limits },
2560
2598
  "tool usage"
2561
2599
  );
2562
- const toolResults = await stream.toolResults;
2563
2600
  const report = [...toolResults].reverse().find((r) => r.toolName === "reportStatus");
2564
2601
  if (!report) {
2565
- throw new Error("Agent finished without calling reportStatus");
2602
+ throw new Error(`${name} agent finished without calling reportStatus`, {
2603
+ cause: streamError
2604
+ });
2566
2605
  }
2567
2606
  const result = report.output;
2568
2607
  if (result.status !== "success") {
2569
2608
  throw new Error(
2570
- `Agent reported failure: ${result.reason ?? "no reason given"}`
2609
+ `${name} agent reported failure: ${result.reason ?? "no reason given"}`
2571
2610
  );
2572
2611
  }
2573
2612
  return result.output;
@@ -2591,7 +2630,8 @@ var detectLanguage = () => runAgent({
2591
2630
  ],
2592
2631
  tools: ["listFiles", "changeDirectory", "readFile", "searchFiles"],
2593
2632
  outputSchema: detectLanguageSchema,
2594
- modelSize: "small"
2633
+ modelSize: "small",
2634
+ name: "detect-language"
2595
2635
  });
2596
2636
 
2597
2637
  // src/actions/analyzeCodebase.ts
@@ -2667,7 +2707,8 @@ function runMode(mode, extraInstructions = []) {
2667
2707
  return runAgent({
2668
2708
  instructions: [...instructions, ...extraInstructions],
2669
2709
  tools: READONLY_TOOLS,
2670
- outputSchema
2710
+ outputSchema,
2711
+ name: `analyze:${mode}`
2671
2712
  });
2672
2713
  }
2673
2714
  async function runAnalysis(mode, extraInstructions = []) {
@@ -2681,7 +2722,7 @@ async function runAnalysis(mode, extraInstructions = []) {
2681
2722
  // package.json
2682
2723
  var package_default = {
2683
2724
  name: "@algolia/wizard",
2684
- version: "0.5.0-rc.49.19",
2725
+ version: "0.5.0-rc.50.20",
2685
2726
  description: "Magically implement Algolia functionality in your codebase",
2686
2727
  type: "module",
2687
2728
  engines: {
@@ -2729,7 +2770,7 @@ var package_default = {
2729
2770
  dependencies: {
2730
2771
  "@ai-sdk/anthropic": "^3.0.81",
2731
2772
  "@ai-sdk/openai-compatible": "^2.0.47",
2732
- "@algolia/cli": "^5.15.0",
2773
+ "@algolia/cli": "^5.11.0",
2733
2774
  "@hono/node-server": "^2.0.10",
2734
2775
  "@mishieck/ink-titled-box": "^0.4.2",
2735
2776
  "@segment/analytics-node": "^3.1.0",
@@ -3076,7 +3117,8 @@ ${formatCompletedSteps(ctx.completedSteps)}`,
3076
3117
  ],
3077
3118
  tools: [],
3078
3119
  outputSchema: reviewSchema,
3079
- modelSize: "small"
3120
+ modelSize: "small",
3121
+ name: "review"
3080
3122
  });
3081
3123
  ctx.notify({ messages: formatReviewSummary(result) });
3082
3124
  return result;
@@ -3287,23 +3329,6 @@ async function copyUploadIntoWorktree(repoRoot, worktreePath, ingestDir, sourceP
3287
3329
  function hasEnvVar(content, name) {
3288
3330
  return new RegExp(`^(\\s*(?:export\\s+)?${name})\\s*=`, "m").test(content);
3289
3331
  }
3290
- async function readEnvVar(worktreePath, name) {
3291
- let content;
3292
- try {
3293
- content = await readFile8(join10(worktreePath, ".env"), "utf8");
3294
- } catch (err) {
3295
- if (err.code !== "ENOENT") throw err;
3296
- return void 0;
3297
- }
3298
- const match = new RegExp(
3299
- `^[ \\t]*(?:export[ \\t]+)?${name}[ \\t]*=[ \\t]*(.*)$`,
3300
- "m"
3301
- ).exec(content);
3302
- if (!match) return void 0;
3303
- const value = match[1].trim().replace(/^(['"])(.*)\1$/, "$2").trim();
3304
- if (!value || value.startsWith("<")) return void 0;
3305
- return value;
3306
- }
3307
3332
  async function writeSearchEnvValues(worktreePath, vars) {
3308
3333
  const target = join10(worktreePath, ".env");
3309
3334
  let existing = "";
@@ -3378,72 +3403,50 @@ async function confirmDirtyWorkingTree(ctx, repoRoot) {
3378
3403
 
3379
3404
  // src/lib/algoliaApiKey.ts
3380
3405
  import { z as z23 } from "zod";
3406
+ var SAFE_ACLS = /* @__PURE__ */ new Set(["search", "browse", "listIndexes"]);
3407
+ var apiKeySchema = z23.object({
3408
+ value: z23.string().min(1),
3409
+ acl: z23.array(z23.string()).default([]),
3410
+ indexes: z23.array(z23.string()).default([])
3411
+ });
3412
+ var apiKeyListSchema = z23.object({
3413
+ items: z23.array(apiKeySchema).optional(),
3414
+ keys: z23.array(apiKeySchema).optional()
3415
+ }).transform((o) => o.items ?? o.keys ?? []);
3381
3416
  var createdKeySchema = z23.object({
3382
3417
  key: z23.string().min(1).optional(),
3383
3418
  value: z23.string().min(1).optional()
3384
- }).transform((o) => o.key ?? o.value);
3385
- async function createSearchOnlyKey(index) {
3386
- logger.info({ index }, "creating a search-only API key");
3419
+ });
3420
+ function canReuse(key, index) {
3421
+ return key.acl.includes("search") && key.acl.every((acl) => SAFE_ACLS.has(acl)) && (key.indexes.length === 0 || key.indexes.includes("*") || key.indexes.includes(index));
3422
+ }
3423
+ async function createSearchKey(index) {
3387
3424
  const stdout = await runAlgoliaCli([
3388
3425
  "apikeys",
3389
3426
  "create",
3390
- "--acl",
3391
- "search",
3392
3427
  "--indices",
3393
3428
  index,
3429
+ "--acl",
3430
+ "search,browse",
3394
3431
  "--description",
3395
- `Algolia Wizard search-only key for ${index}`,
3432
+ `wizard search-only key for ${index}`,
3396
3433
  "-o",
3397
3434
  "json"
3398
3435
  ]);
3399
- let payload;
3400
- try {
3401
- payload = JSON.parse(stdout);
3402
- } catch {
3403
- throw new Error("apikeys create returned output that is not valid JSON");
3404
- }
3405
- const created = createdKeySchema.parse(payload);
3436
+ const { key, value } = createdKeySchema.parse(JSON.parse(stdout));
3437
+ const created = key ?? value;
3406
3438
  if (!created) throw new Error("apikeys create returned no key value");
3407
3439
  return created;
3408
3440
  }
3409
- async function apiKeyExists(key) {
3410
- try {
3411
- await runAlgoliaCli(["apikeys", "get", key, "-o", "json"]);
3412
- return true;
3413
- } catch (err) {
3414
- return !/does not exist|not found|404/i.test(err.message);
3415
- }
3416
- }
3417
- async function resolveSearchOnlyKey(index, appId, envKey) {
3418
- if (envKey) {
3419
- await recordSearchKey(index, appId, envKey);
3420
- return { key: envKey, source: "env" };
3421
- }
3422
- const stored = await getStoredSearchKey(index, appId);
3423
- if (stored) {
3424
- if (await apiKeyExists(stored)) {
3425
- logger.info({ index, appId }, "reusing the stored search-only API key");
3426
- return { key: stored, source: "config" };
3427
- }
3428
- logger.warn(
3429
- { index, appId },
3430
- "the stored search-only API key no longer exists; creating a replacement"
3431
- );
3432
- await forgetSearchKey(index);
3433
- }
3434
- const key = await createSearchOnlyKey(index);
3435
- await recordSearchKey(index, appId, key);
3436
- return { key, source: "created" };
3437
- }
3438
- async function recordSearchKey(index, appId, key) {
3439
- try {
3440
- await storeSearchKey(index, appId, key);
3441
- } catch (err) {
3442
- logger.warn(
3443
- { err: err.message, index },
3444
- "could not record the search-only API key; a later run may create another"
3445
- );
3441
+ async function resolveSearchOnlyKey(index) {
3442
+ const stdout = await runAlgoliaCli(["apikeys", "list", "-o", "json"]);
3443
+ const existing = apiKeyListSchema.parse(JSON.parse(stdout)).find((key) => canReuse(key, index))?.value;
3444
+ if (existing) {
3445
+ logger.info({ index }, "reusing existing search-only API key");
3446
+ return existing;
3446
3447
  }
3448
+ logger.info({ index }, "no reusable search-only key found; creating one");
3449
+ return createSearchKey(index);
3447
3450
  }
3448
3451
 
3449
3452
  // src/lib/algoliaDocs.ts
@@ -3598,22 +3601,15 @@ function publicEnvPrefix(language) {
3598
3601
  }
3599
3602
  return "PUBLIC_";
3600
3603
  }
3601
- var APP_ID_VAR_SUFFIX = "ALGOLIA_APP_ID";
3602
- var SEARCH_KEY_VAR_SUFFIX = "ALGOLIA_SEARCH_API_KEY";
3603
- function appIdVar(language) {
3604
- return `${publicEnvPrefix(language)}${APP_ID_VAR_SUFFIX}`;
3605
- }
3606
- function searchKeyVar(language) {
3607
- return `${publicEnvPrefix(language)}${SEARCH_KEY_VAR_SUFFIX}`;
3608
- }
3609
3604
  function searchEnvVars(language, appId, searchKey) {
3605
+ const prefix = publicEnvPrefix(language);
3610
3606
  return [
3611
3607
  {
3612
- name: appIdVar(language),
3608
+ name: `${prefix}ALGOLIA_APP_ID`,
3613
3609
  value: appId ?? "<your-algolia-app-id>"
3614
3610
  },
3615
3611
  {
3616
- name: searchKeyVar(language),
3612
+ name: `${prefix}ALGOLIA_SEARCH_API_KEY`,
3617
3613
  value: searchKey ?? "<your-algolia-search-only-api-key>"
3618
3614
  }
3619
3615
  ];
@@ -3675,9 +3671,15 @@ function searchInstructions(input) {
3675
3671
  "Follow the Algolia JS SDK reference below for client setup and InstantSearch wiring; prefer it over prior knowledge:",
3676
3672
  doc,
3677
3673
  `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.`,
3678
- `Add Algolia App ID "${input.appId}", search-only key ${input.searchKey ? `"${input.searchKey}"` : "(placeholder for the developer to fill in)"}.`,
3679
- `Use exactly these public env var names in the code: ${input.searchEnvVars.map(({ name }) => name).join(", ")}.`,
3680
3674
  "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.",
3675
+ // appId always resolves (loadActiveProfile throws otherwise); only the
3676
+ // search-only key is best-effort and can fall back to a placeholder.
3677
+ `Values: App ID "${input.appId}", search-only key ${input.searchKey ? `"${input.searchKey}"` : "(placeholder for the developer to fill in)"}.`,
3678
+ // Names are fixed, not the agent's to rename: the wizard writes the
3679
+ // resolved app id / search-only key into ".env" under these exact names
3680
+ // right after this step, so a renamed prefix here would leave the code
3681
+ // reading a var the wizard never wrote.
3682
+ `Use exactly these public env var names in the code: ${input.searchEnvVars.map(({ name }) => name).join(", ")}.`,
3681
3683
  '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.',
3682
3684
  "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."
3683
3685
  ];
@@ -3830,43 +3832,17 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
3830
3832
  let searchKey;
3831
3833
  if (useCases.includes("search")) {
3832
3834
  appId = (await loadActiveProfile()).appId;
3835
+ try {
3836
+ searchKey = await resolveSearchOnlyKey(targetIndex);
3837
+ } catch (err) {
3838
+ logger.warn(
3839
+ { err: err.message },
3840
+ "implement: could not resolve a search-only API key; the agent will scaffold a placeholder"
3841
+ );
3842
+ }
3833
3843
  }
3834
3844
  const worktree = existingWorktreePath ?? (await createWorktree(repoRoot)).path;
3835
3845
  try {
3836
- const searchKeyNotices = [];
3837
- let searchKeyError;
3838
- if (useCases.includes("search") && appId) {
3839
- const envAppId = await readEnvVar(worktree, appIdVar(language));
3840
- const envKey = envAppId === appId ? await readEnvVar(worktree, searchKeyVar(language)) : void 0;
3841
- if (envAppId && envAppId !== appId) {
3842
- searchKeyNotices.push(
3843
- `\u26A0\uFE0F .env already sets ${appIdVar(language)}=${envAppId}, but the active Algolia application is ${appId}. The wizard left those values alone \u2014 update ${appIdVar(language)} and ${searchKeyVar(language)} by hand, or searches will fail.`
3844
- );
3845
- logger.warn(
3846
- { envAppId, appId },
3847
- "implement: .env holds credentials for a different Algolia application; not reusing its search key"
3848
- );
3849
- }
3850
- try {
3851
- const resolved = await resolveSearchOnlyKey(targetIndex, appId, envKey);
3852
- searchKey = resolved.key;
3853
- if (resolved.source === "created") {
3854
- searchKeyNotices.push(
3855
- `Created a new search-only Algolia API key for the "${targetIndex}" index in app ${appId} \u2014 safe to expose in frontend code.`
3856
- );
3857
- } else {
3858
- searchKeyNotices.push(
3859
- `Reused the existing search-only Algolia API key for the "${targetIndex}" index in app ${appId}.`
3860
- );
3861
- }
3862
- } catch (err) {
3863
- searchKeyError = err.message;
3864
- logger.warn(
3865
- { err: searchKeyError },
3866
- "implement: could not provision a search-only API key; the agent will scaffold a placeholder"
3867
- );
3868
- }
3869
- }
3870
3846
  process.chdir(worktree);
3871
3847
  let uploadFilePath;
3872
3848
  let uploadWarning;
@@ -3906,7 +3882,6 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
3906
3882
  };
3907
3883
  const summaries = [];
3908
3884
  if (uploadWarning) summaries.push(uploadWarning);
3909
- summaries.push(...searchKeyNotices);
3910
3885
  let agentRuns = 0;
3911
3886
  let ingestRuntime;
3912
3887
  let ingestEntrypoint;
@@ -3925,7 +3900,8 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
3925
3900
  extraInstructions
3926
3901
  ),
3927
3902
  tools: toolsForUseCase(currentUseCase, input.ingestionSource),
3928
- outputSchema: implementationOutputSchema
3903
+ outputSchema: implementationOutputSchema,
3904
+ name: `implement:${currentUseCase}`
3929
3905
  });
3930
3906
  ctx.notify({
3931
3907
  messages: [`Installing dependencies for ${currentUseCase}\u2026`]
@@ -3950,7 +3926,8 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
3950
3926
  return runAgent({
3951
3927
  instructions: buildAgentInstructions("verification", input),
3952
3928
  tools: toolsForUseCase("verification"),
3953
- outputSchema: verificationOutputSchema
3929
+ outputSchema: verificationOutputSchema,
3930
+ name: "implement:verification"
3954
3931
  });
3955
3932
  }
3956
3933
  if (useCases.includes("ingestion")) {
@@ -4116,8 +4093,7 @@ ${run.output}` : status;
4116
4093
  );
4117
4094
  if (unresolvedSearchEnvVars.length > 0) {
4118
4095
  summaries.push(
4119
- `Could not resolve a value for ${unresolvedSearchEnvVars.map((v) => v.name).join(", ")} \u2014 fill it in manually in .env.` + // Without the reason the line is a dead end.
4120
- (searchKeyError ? ` Reason: ${searchKeyError}` : "")
4096
+ `Could not resolve a value for ${unresolvedSearchEnvVars.map((v) => v.name).join(", ")} \u2014 fill it in manually in .env.`
4121
4097
  );
4122
4098
  }
4123
4099
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@algolia/wizard",
3
- "version": "0.5.0-rc.49.19",
3
+ "version": "0.5.0-rc.50.20",
4
4
  "description": "Magically implement Algolia functionality in your codebase",
5
5
  "type": "module",
6
6
  "engines": {
@@ -48,7 +48,7 @@
48
48
  "dependencies": {
49
49
  "@ai-sdk/anthropic": "^3.0.81",
50
50
  "@ai-sdk/openai-compatible": "^2.0.47",
51
- "@algolia/cli": "^5.15.0",
51
+ "@algolia/cli": "^5.11.0",
52
52
  "@hono/node-server": "^2.0.10",
53
53
  "@mishieck/ink-titled-box": "^0.4.2",
54
54
  "@segment/analytics-node": "^3.1.0",