@algolia/wizard 0.87.0-rc.211.681 → 0.87.0

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 +346 -309
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -4,7 +4,7 @@
4
4
  import { render } from "ink";
5
5
 
6
6
  // src/ui/App.tsx
7
- import { Box as Box22, Text as Text23, useApp as useApp2, useInput as useInput9, useWindowSize as useWindowSize8 } from "ink";
7
+ import { Box as Box23, Text as Text24, useApp as useApp2, useInput as useInput10, useWindowSize as useWindowSize8 } from "ink";
8
8
  import Spinner3 from "ink-spinner";
9
9
 
10
10
  // src/lib/terminalSize.ts
@@ -98,8 +98,8 @@ function runAlgoliaCli(args, { onOutput, redact } = {}) {
98
98
  let stdout = "";
99
99
  let stderr = "";
100
100
  const splitters = {
101
- stdout: lineSplitter((line) => onOutput?.("stdout", line)),
102
- stderr: lineSplitter((line) => onOutput?.("stderr", line))
101
+ stdout: lineSplitter((line) => onOutput?.("stdout", mask(line, redact))),
102
+ stderr: lineSplitter((line) => onOutput?.("stderr", mask(line, redact)))
103
103
  };
104
104
  child.stdout.on("data", (chunk) => {
105
105
  const text = String(chunk);
@@ -287,6 +287,16 @@ var CLI_OUTPUT_LIMIT = 200;
287
287
  function commandApprovalKey(command, cwd) {
288
288
  return `${cwd}\0${command}`;
289
289
  }
290
+ function appendOutputLog(logs, outputCount, entry) {
291
+ if (outputCount < CLI_OUTPUT_LIMIT) {
292
+ return { logs: [...logs, entry], _outputLogCount: outputCount + 1 };
293
+ }
294
+ const oldest = logs.findIndex((e) => e.kind === "output");
295
+ return {
296
+ logs: [...logs.filter((_, i) => i !== oldest), entry],
297
+ _outputLogCount: outputCount
298
+ };
299
+ }
290
300
  var useWizard = create((set, get) => ({
291
301
  phase: "idle",
292
302
  homeScreen: "home",
@@ -304,6 +314,7 @@ var useWizard = create((set, get) => ({
304
314
  writtenFiles: [],
305
315
  approvedCommands: /* @__PURE__ */ new Set(),
306
316
  logs: [],
317
+ _outputLogCount: 0,
307
318
  error: null,
308
319
  inputReq: null,
309
320
  _resolve: null,
@@ -396,11 +407,23 @@ var useWizard = create((set, get) => ({
396
407
  get()._clearNoticeQueue();
397
408
  set({ notices: [] });
398
409
  },
399
- pushCliOutput: (stream, text) => set((s) => ({
400
- cliOutput: [...s.cliOutput, { id: nanoid(), stream, text }].slice(
401
- -CLI_OUTPUT_LIMIT
402
- )
403
- })),
410
+ // Logged too, so a line cut off on the main screen can be read in the log view.
411
+ pushCliOutput: (stream, text) => {
412
+ const id = nanoid();
413
+ set((s) => ({
414
+ cliOutput: [...s.cliOutput, { id, stream, text }].slice(
415
+ -CLI_OUTPUT_LIMIT
416
+ ),
417
+ ...appendOutputLog(s.logs, s._outputLogCount, {
418
+ id,
419
+ kind: "output",
420
+ name: text,
421
+ stream,
422
+ status: "success",
423
+ startedAt: Date.now()
424
+ })
425
+ }));
426
+ },
404
427
  clearCliOutput: () => set({ cliOutput: [] }),
405
428
  setReview: (review2) => set({ review: review2 }),
406
429
  setTargetIndex: (index) => set({ targetIndex: index }),
@@ -474,6 +497,7 @@ var useWizard = create((set, get) => ({
474
497
  writtenFiles: [],
475
498
  approvedCommands: /* @__PURE__ */ new Set(),
476
499
  logs: [],
500
+ _outputLogCount: 0,
477
501
  error: null,
478
502
  inputReq: null,
479
503
  _resolve: null,
@@ -713,6 +737,32 @@ import { useState as useState9 } from "react";
713
737
  import { Box as Box8, Text as Text8, useInput as useInput3 } from "ink";
714
738
  import { useLayoutEffect as useLayoutEffect3, useState as useState6 } from "react";
715
739
 
740
+ // src/lib/wrapExact.ts
741
+ function wrapExactLine(line, width) {
742
+ if (line.length === 0) return [" "];
743
+ const lines = [];
744
+ let i = 0;
745
+ while (i < line.length) {
746
+ if (line.length - i <= width) {
747
+ lines.push(line.slice(i));
748
+ break;
749
+ }
750
+ let end = i + width;
751
+ if (line.charAt(end) !== " ") {
752
+ const lastSpace = line.lastIndexOf(" ", end - 1);
753
+ if (lastSpace >= i) end = lastSpace + 1;
754
+ }
755
+ if (end <= i) end = i + width;
756
+ lines.push(line.slice(i, end));
757
+ i = end;
758
+ }
759
+ return lines;
760
+ }
761
+ function wrapExact(text, width) {
762
+ if (width <= 0) return [text || " "];
763
+ return text.split(/\r\n|\n|\r/).flatMap((line) => wrapExactLine(line, width));
764
+ }
765
+
716
766
  // src/ui/DecisionSelect.tsx
717
767
  import { Box as Box5, Text as Text5, useInput } from "ink";
718
768
  import { useState as useState3 } from "react";
@@ -1028,30 +1078,6 @@ function Review() {
1028
1078
  import { jsx as jsx6, jsxs as jsxs7 } from "react/jsx-runtime";
1029
1079
  var BLANK2 = { prefix: "", text: " ", color: COLORS.dim };
1030
1080
  var COMMAND_PREFIX = "$ ";
1031
- function wrapExactLine(line, width) {
1032
- if (line.length === 0) return [" "];
1033
- const lines = [];
1034
- let i = 0;
1035
- while (i < line.length) {
1036
- if (line.length - i <= width) {
1037
- lines.push(line.slice(i));
1038
- break;
1039
- }
1040
- let end = i + width;
1041
- if (line.charAt(end) !== " ") {
1042
- const lastSpace = line.lastIndexOf(" ", end - 1);
1043
- if (lastSpace >= i) end = lastSpace + 1;
1044
- }
1045
- if (end <= i) end = i + width;
1046
- lines.push(line.slice(i, end));
1047
- i = end;
1048
- }
1049
- return lines;
1050
- }
1051
- function wrapExact(text, width) {
1052
- if (width <= 0) return [text || " "];
1053
- return text.split(/\r\n|\n|\r/).flatMap((line) => wrapExactLine(line, width));
1054
- }
1055
1081
  function fieldLines(prefix, value, color, width) {
1056
1082
  return wrapText(value, Math.max(width - prefix.length, 1)).map((text, i) => ({
1057
1083
  prefix: i === 0 ? prefix : " ".repeat(prefix.length),
@@ -2332,7 +2358,7 @@ async function ensureApplication(resumeAppId) {
2332
2358
  // package.json
2333
2359
  var package_default = {
2334
2360
  name: "@algolia/wizard",
2335
- version: "0.87.0-rc.211.681",
2361
+ version: "0.87.0",
2336
2362
  description: "Magically implement Algolia functionality in your codebase",
2337
2363
  type: "module",
2338
2364
  engines: {
@@ -2805,9 +2831,6 @@ async function runWorkflow(workflow, startWorkflowAppId, options) {
2805
2831
  }
2806
2832
  }
2807
2833
 
2808
- // src/actions/selectIndex.ts
2809
- import { basename } from "node:path";
2810
-
2811
2834
  // src/actions/listIndices.ts
2812
2835
  import { z as z5 } from "zod";
2813
2836
  var indicesListSchema = z5.object({
@@ -2842,28 +2865,11 @@ function indexNameError(name) {
2842
2865
  return "Index name cannot end with .txt, .bin, or .idx.";
2843
2866
  return void 0;
2844
2867
  }
2845
- function slug(text) {
2846
- return text.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
2847
- }
2848
- function suggestIndexName(project, entity, taken) {
2849
- const base = ([slug(project), slug(entity ?? "")].filter(Boolean).join("_") || "records").slice(0, MAX_INDEX_NAME_LENGTH);
2850
- let name = base;
2851
- for (let n = 2; taken.includes(name); n++) {
2852
- const suffix = `_${n}`;
2853
- name = base.slice(0, MAX_INDEX_NAME_LENGTH - suffix.length) + suffix;
2854
- }
2855
- return name;
2856
- }
2857
2868
  var selectIndexStep = async (ctx) => {
2858
2869
  await requireApplication(ctx.appId);
2859
2870
  const indices = await listIndices();
2860
2871
  const names = indices.map((i) => i.name);
2861
2872
  const hasIndices = names.length > 0;
2862
- const entity = ctx.getStepOutput(
2863
- "confirm-entities"
2864
- )?.confirmedEntities?.[0]?.name;
2865
- const suggested = suggestIndexName(basename(process.cwd()), entity, names);
2866
- const suggestionHint = `Press Enter to use "${suggested}".`;
2867
2873
  let error;
2868
2874
  let chosen;
2869
2875
  while (chosen === void 0) {
@@ -2878,8 +2884,7 @@ var selectIndexStep = async (ctx) => {
2878
2884
  promptType: "textInput",
2879
2885
  options: [],
2880
2886
  messages: [
2881
- "This app has no existing indices \u2014 enter a name to create one.",
2882
- suggestionHint
2887
+ "This app has no existing indices \u2014 enter a name to create one."
2883
2888
  ],
2884
2889
  error
2885
2890
  });
@@ -2889,18 +2894,17 @@ var selectIndexStep = async (ctx) => {
2889
2894
  let candidate;
2890
2895
  let isNewName = true;
2891
2896
  if (!hasIndices) {
2892
- candidate = selection.trim() || suggested;
2897
+ candidate = selection.trim();
2893
2898
  } else if (selection === CREATE_NEW_INDEX) {
2894
2899
  const name = await ctx.requestUserInput({
2895
2900
  prompt: "Name the new index:",
2896
2901
  promptType: "textInput",
2897
- options: [],
2898
- messages: [suggestionHint]
2902
+ options: []
2899
2903
  });
2900
2904
  if (typeof name !== "string") {
2901
2905
  throw new Error("selectIndex received an unexpected non-text result");
2902
2906
  }
2903
- candidate = name.trim() || suggested;
2907
+ candidate = name.trim();
2904
2908
  } else {
2905
2909
  candidate = selection;
2906
2910
  isNewName = false;
@@ -3136,14 +3140,14 @@ import z9 from "zod";
3136
3140
  import { readFile as readFile4 } from "node:fs/promises";
3137
3141
 
3138
3142
  // src/lib/tools/env.ts
3139
- import { basename as basename2 } from "node:path";
3143
+ import { basename } from "node:path";
3140
3144
  function isEnvFile(filePath) {
3141
- const name = basename2(filePath);
3145
+ const name = basename(filePath);
3142
3146
  return name === ".env" || name.startsWith(".env.");
3143
3147
  }
3144
3148
  function isSecretEnvFile(filePath) {
3145
3149
  if (!isEnvFile(filePath)) return false;
3146
- const name = basename2(filePath);
3150
+ const name = basename(filePath);
3147
3151
  return !/\.(example|sample|template)$/.test(name);
3148
3152
  }
3149
3153
  function secretEnvWriteRefusal(filePath) {
@@ -3778,7 +3782,7 @@ import { execFile as execFile2 } from "node:child_process";
3778
3782
  import { tool as tool8 } from "ai";
3779
3783
  import z15 from "zod";
3780
3784
  import { lstat as lstat3, readdir as readdir2, readFile as readFile8, realpath, stat as stat2 } from "node:fs/promises";
3781
- import { basename as basename3, isAbsolute as isAbsolute2, join as join8, relative as relative4, sep as sep2 } from "node:path";
3785
+ import { basename as basename2, isAbsolute as isAbsolute2, join as join8, relative as relative4, sep as sep2 } from "node:path";
3782
3786
  import { performance } from "node:perf_hooks";
3783
3787
  import { Worker } from "node:worker_threads";
3784
3788
  var MAX_GIT_OUTPUT_BYTES = 32e6;
@@ -4121,7 +4125,7 @@ async function safeSearchPath(rootPath, file) {
4121
4125
  }
4122
4126
  async function searchableFiles(root, target) {
4123
4127
  try {
4124
- if (SKIP_FILES.has(basename3(target)) && (await lstat3(target)).isFile()) {
4128
+ if (SKIP_FILES.has(basename2(target)) && (await lstat3(target)).isFile()) {
4125
4129
  return [target];
4126
4130
  }
4127
4131
  const gitRoot = await gitRootForTarget(root, target);
@@ -4300,7 +4304,7 @@ import { tool as tool9 } from "ai";
4300
4304
  import z16 from "zod";
4301
4305
  import { createHash as createHash2 } from "node:crypto";
4302
4306
  import { readFile as readFile9, stat as stat3 } from "node:fs/promises";
4303
- import { basename as basename4, relative as relative5, resolve as resolve3 } from "node:path";
4307
+ import { basename as basename3, relative as relative5, resolve as resolve3 } from "node:path";
4304
4308
 
4305
4309
  // src/lib/tools/utils/prompt.ts
4306
4310
  var chain = Promise.resolve();
@@ -4398,7 +4402,7 @@ function commandDiffersFromReviewedScript(ctx, command, cwd) {
4398
4402
  if (approval.command === command && approval.cwd === cwd) return false;
4399
4403
  if (approval.command === command) return true;
4400
4404
  const scriptReferences = [
4401
- basename4(approval.filePath),
4405
+ basename3(approval.filePath),
4402
4406
  relative5(ctx.root, approval.filePath),
4403
4407
  ".algolia-wizard"
4404
4408
  ];
@@ -5119,8 +5123,8 @@ function generateRecordTool(ctx, createModel = defaultCreateModel2) {
5119
5123
  ...record,
5120
5124
  objectID: nanoid2()
5121
5125
  }));
5122
- const slug2 = entityName.toLowerCase().replace(/[^a-z0-9]+/g, "-");
5123
- const relPath = `${DATA_DIR}/${slug2}.json`;
5126
+ const slug = entityName.toLowerCase().replace(/[^a-z0-9]+/g, "-");
5127
+ const relPath = `${DATA_DIR}/${slug}.json`;
5124
5128
  const resolved2 = resolveInRoot(ctx, relPath);
5125
5129
  if (resolved2.ok === false) return resolved2.error;
5126
5130
  const writeError = await safeWriteFile(
@@ -6073,7 +6077,7 @@ import {
6073
6077
  // src/lib/git.ts
6074
6078
  import { execFile as execFile3 } from "node:child_process";
6075
6079
  import { copyFile, mkdir as mkdir4, stat as stat4 } from "node:fs/promises";
6076
- import { basename as basename5, dirname as dirname3, isAbsolute as isAbsolute3, join as join9, resolve as resolve4 } from "node:path";
6080
+ import { basename as basename4, dirname as dirname3, isAbsolute as isAbsolute3, join as join9, resolve as resolve4 } from "node:path";
6077
6081
  var MAX_BUFFER = 32 * 1024 * 1024;
6078
6082
  function git(args) {
6079
6083
  return new Promise((resolve6, reject) => {
@@ -6110,7 +6114,7 @@ async function copyUploadIntoProject(repoRoot, ingestDir, sourcePath) {
6110
6114
  } catch {
6111
6115
  return { ok: false, reason: `"${sourcePath}" does not exist` };
6112
6116
  }
6113
- const relPath = join9(ingestDir, basename5(source));
6117
+ const relPath = join9(ingestDir, basename4(source));
6114
6118
  const dest = join9(repoRoot, relPath);
6115
6119
  if (resolve4(source) === resolve4(dest)) {
6116
6120
  return { ok: true, relPath };
@@ -6268,7 +6272,6 @@ var INGEST_RETRY = {
6268
6272
  retry: "Retry ingestion",
6269
6273
  skip: "Continue without records"
6270
6274
  };
6271
- var INGEST_AGENT_RETRY_PROMPT = "Retry to let the wizard write and run the ingestion script again.";
6272
6275
  var FILE_UPLOAD_PATH_PROMPT = "Enter the path to your JSON, CSV, or TSV file (relative to the project root, or absolute):";
6273
6276
  var JS_LANGUAGES = ["javascript", "typescript", "jsx", "tsx", "node"];
6274
6277
  function lower(entries) {
@@ -6495,29 +6498,9 @@ function cdnSearchInstructions(input) {
6495
6498
  input.searchKey ? `Set window.${SEARCH_CONFIG_SEARCH_KEY} to "${input.searchKey}".` : `A real search-only key could not be provisioned${input.searchKeyError ? ` (${input.searchKeyError})` : ""} \u2014 set window.${SEARCH_CONFIG_SEARCH_KEY} to the placeholder "${SEARCH_KEY_PLACEHOLDER}" and add a prominent TODO for the developer to fill in a real one.`,
6496
6499
  'Load these exact pinned tags in order before the config and search scripts: <script src="https://cdn.jsdelivr.net/npm/algoliasearch@5.59.0/dist/lite/builds/browser.umd.js" integrity="sha256-pduQHl1jn0IaN/BIpSotQm7Y5THdpKcX3Bw6xdRteRw=" crossorigin="anonymous"></script> then <script src="https://cdn.jsdelivr.net/npm/instantsearch.js@4.117.0/dist/instantsearch.production.min.js" integrity="sha256-5zhKxAGeH7ThWfnmdD4pS1gsmafE2b8aWRsq8set/dc=" crossorigin="anonymous"></script>.',
6497
6500
  'When using the InstantSearch theme, load this exact tag before the application styles: <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/instantsearch.css@8.22.1/themes/satellite-min.css" integrity="sha256-5/eHPZl63VYJSDVOKrOgGe/5+owUkX3uPAW6+XYeLNc=" crossorigin="anonymous">. Never use an unversioned or differently versioned theme URL, and never omit its integrity attribute.',
6498
- `In that classic search script, use window['algoliasearch/lite'].liteClient and window.instantsearch. Add window.instantsearch.widgets.autocomplete as the only search widget. Configure it with container '#autocomplete', the content-specific placeholder ${JSON.stringify(placeholder)}, and an indices array containing one object whose indexName is window.${SEARCH_CONFIG_INDEX_NAME}. Put the item and noResults functions in the templates option of that indices entry, implement getURL only for an existing route, and match the item template to the entity schema. Keep insights: true and call search.start(). Do not substitute searchBox or hits, omit indices, use imports or exports, or use type="module".`,
6499
- CDN_AUTOCOMPLETE_SHAPE
6501
+ `In that classic search script, use window['algoliasearch/lite'].liteClient and window.instantsearch. Add window.instantsearch.widgets.autocomplete as the only search widget. Configure it with container '#autocomplete', the content-specific placeholder ${JSON.stringify(placeholder)}, and an indices array containing one object whose indexName is window.${SEARCH_CONFIG_INDEX_NAME}; put item and noResults functions in its templates option, implement getURL only for an existing route, and match the item template to the entity schema. Keep insights: true and call search.start(). Do not substitute searchBox or hits, omit indices, use imports or exports, or use type="module".`
6500
6502
  ];
6501
6503
  }
6502
- var CDN_AUTOCOMPLETE_SHAPE = `Use this shape for the autocomplete call. Replace the item fields and the getURL route with the real record fields and an existing route:
6503
- \`\`\`js
6504
- window.instantsearch.widgets.autocomplete({
6505
- container: '#autocomplete',
6506
- placeholder: '...',
6507
- indices: [
6508
- {
6509
- indexName: window.${SEARCH_CONFIG_INDEX_NAME},
6510
- getURL: (item) => '/existing-route/' + item.slug,
6511
- templates: {
6512
- item: ({ item, onSelect }, { html, components }) =>
6513
- html\`<div onClick=\${onSelect}>\${components.Highlight({ hit: item, attribute: 'name' })}</div>\`,
6514
- noResults: (_, { html }) => html\`<span>No results</span>\`,
6515
- },
6516
- },
6517
- ],
6518
- })
6519
- \`\`\`
6520
- The widget reads the item and noResults templates only from each indices entry. Its own top-level templates option accepts only panel. If item is not inside indices[].templates, the widget throws "Template must be 'string' or 'function', was 'undefined' (key: item)" on the first search and shows no results.`;
6521
6504
  function validationInstructions(input) {
6522
6505
  return [
6523
6506
  "Validate the Algolia search implementation by inspecting the project source.",
@@ -6538,8 +6521,7 @@ function validationInstructions(input) {
6538
6521
  "Do not modify files. Report each implementation issue as a concrete instruction for the next implementation pass.",
6539
6522
  `Detected verification tools: ${JSON.stringify(input.findings.verification ?? [])}. Use only a type checker; ignore any linter or formatter in this list.`,
6540
6523
  ...!input.frontendHasPackageJson ? [
6541
- "The frontend has no package.json: never create one or run npm, pnpm, yarn, or bun. Validate the CDN implementation by inspecting its HTML or template and classic scripts for the search container, Algolia \u2192 InstantSearch \u2192 config \u2192 search load order, browser globals, autocomplete widget configuration, search.start(), and exact pinned CDN URLs and integrity attributes for every Algolia script or stylesheet. Source inspection is required even when the project has no automated checks. window.instantsearch.widgets.autocomplete is a real widget in the pinned InstantSearch build; do not report its use as an error, and do not fetch a remote bundle or URL to verify it.",
6542
- "In the autocomplete call, confirm that the item and noResults templates are inside the templates option of the indices entry, not in the top-level templates option of the widget. The top-level templates option accepts only panel, so an item template there throws on the first search and no results show. If item is missing from indices[].templates, set sufficient=false and tell the next pass to move the templates into the indices entry."
6524
+ "The frontend has no package.json: never create one or run npm, pnpm, yarn, or bun. Validate the CDN implementation by inspecting its HTML or template and classic scripts for the search container, Algolia \u2192 InstantSearch \u2192 config \u2192 search load order, browser globals, autocomplete widget configuration, search.start(), and exact pinned CDN URLs and integrity attributes for every Algolia script or stylesheet. Source inspection is required even when the project has no automated checks. window.instantsearch.widgets.autocomplete is a real widget in the pinned InstantSearch build; do not report its use as an error, and do not fetch a remote bundle or URL to verify it."
6543
6525
  ] : [],
6544
6526
  "Always call reportStatus with status=success after validation, even when sufficient=false.",
6545
6527
  "Set sufficient=false if the input's computed accessible name is empty or generic, including when aria-labelledby references a missing or empty element; a placeholder does not count as the label.",
@@ -6679,8 +6661,8 @@ async function firstRecordIn(filePath) {
6679
6661
  async function ingestedRecordSample(repoRoot, entityName, uploadFilePath) {
6680
6662
  const candidates = [];
6681
6663
  if (entityName) {
6682
- const slug2 = entityName.toLowerCase().replace(/[^a-z0-9]+/g, "-");
6683
- candidates.push(join11(repoRoot, INGEST_DIR, "data", `${slug2}.json`));
6664
+ const slug = entityName.toLowerCase().replace(/[^a-z0-9]+/g, "-");
6665
+ candidates.push(join11(repoRoot, INGEST_DIR, "data", `${slug}.json`));
6684
6666
  }
6685
6667
  if (uploadFilePath?.toLowerCase().endsWith(".json")) {
6686
6668
  candidates.push(join11(repoRoot, uploadFilePath));
@@ -6699,25 +6681,12 @@ function recordSchema(sample, attributes) {
6699
6681
  }
6700
6682
  return Object.fromEntries(attributes.map((key) => [key, "unknown"]));
6701
6683
  }
6702
- function noRunReason({
6703
- agentFailure,
6704
- executions,
6705
- ingestCommand,
6706
- scriptPath
6707
- }) {
6708
- if (agentFailure !== void 0) {
6709
- return `the wizard stopped before it finished the ingestion script (${agentFailure || "no reason given"})`;
6710
- }
6711
- if (executions.some((e) => !e.approved)) {
6712
- return "a command it needed was declined";
6713
- }
6714
- if (!ingestCommand) {
6715
- return scriptPath ? `the ingestion script ${scriptPath} was written but not run` : "no ingestion script was written";
6684
+ function ingestFailure(attempt, executions) {
6685
+ if (!attempt) {
6686
+ return {
6687
+ reason: executions.some((e) => !e.approved) ? "a command it needed was declined" : "no successful run was recorded"
6688
+ };
6716
6689
  }
6717
- return "no successful run was recorded";
6718
- }
6719
- function ingestFailure(attempt, missingRunReason = "no successful run was recorded") {
6720
- if (!attempt) return { reason: missingRunReason };
6721
6690
  if (!attempt.approved) return { reason: "you declined to run it" };
6722
6691
  const detail = errorLine(attempt.output);
6723
6692
  if (attempt.timedOut) {
@@ -6759,9 +6728,6 @@ function briefSummary(summary) {
6759
6728
  if (!firstLine) return "no summary given";
6760
6729
  return firstLine.length > ERROR_SUMMARY_MAX_CHARS ? `${firstLine.slice(0, ERROR_SUMMARY_MAX_CHARS - 1)}\u2026` : firstLine;
6761
6730
  }
6762
- function ingestionRetryInstruction(reason) {
6763
- return `The previous ingestion attempt ended with no successful run: ${reason}. Look in "${INGEST_DIR}/" for a script from that attempt and finish or fix it instead of starting over. Then call reviewScript and run the script as described above.`;
6764
- }
6765
6731
  function validationRetryInstructions(validation) {
6766
6732
  return [
6767
6733
  `Implementation insufficient. Address these findings before reporting completion: ${validation.additionalInstructions ?? validation.summary}`
@@ -7048,70 +7014,16 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
7048
7014
  }
7049
7015
  if (useCases.includes("ingestion")) {
7050
7016
  let ingestFailureDetail;
7017
+ const result = await runImplementationUseCase("ingestion");
7018
+ summaries.push(formatSummary("ingestion", result.summary));
7019
+ ingestCommand = result.ingestCommand;
7051
7020
  const ingestionContext = ingestionTools;
7052
7021
  const executions = ingestionContext.shell.executions;
7053
- let agentFailure;
7054
- const runIngestionAgent = async (extraInstructions = []) => {
7055
- const isRetry = extraInstructions.length > 0;
7056
- if (isRetry) {
7057
- resetToolCounts(ingestionContext);
7058
- ingestionContext.cwd = ingestionContext.root;
7059
- }
7060
- try {
7061
- const result = await runImplementationUseCase(
7062
- "ingestion",
7063
- extraInstructions,
7064
- isRetry
7065
- );
7066
- summaries.push(formatSummary("ingestion", result.summary));
7067
- ingestCommand = result.ingestCommand ?? ingestCommand;
7068
- agentFailure = void 0;
7069
- } catch (err) {
7070
- if (!(err instanceof AgentReportedFailureError)) throw err;
7071
- agentFailure = err.reason ?? "";
7072
- summaries.push(
7073
- formatSummary(
7074
- "ingestion",
7075
- `Stopped before the script was finished: ${err.reason ?? "no reason given"}`
7076
- )
7077
- );
7078
- logger.warn(
7079
- { reason: err.reason, counts: ingestionContext.counts },
7080
- "implement: ingestion agent reported fail"
7081
- );
7082
- }
7083
- };
7084
- const currentNoRunReason = async () => noRunReason({
7085
- agentFailure,
7086
- executions,
7087
- ingestCommand,
7088
- scriptPath: await findIngestionScript(
7089
- repoRoot,
7090
- INGEST_DIR,
7091
- ingestCommand
7092
- )
7093
- });
7094
- await runIngestionAgent();
7095
7022
  let outcome = ingestOutcome(executions, repoRoot, ingestCommand);
7096
7023
  let failureAcknowledged = false;
7097
- while (!outcome.run && !outcome.attempt) {
7098
- const reason = await currentNoRunReason();
7099
- const choice = await ctx.requestUserInput({
7100
- prompt: INGEST_AGENT_RETRY_PROMPT,
7101
- promptType: "multipleChoice",
7102
- options: [INGEST_RETRY.retry, INGEST_RETRY.skip],
7103
- messages: [`\u26A0\uFE0F Records were not indexed \u2014 ${reason}.`]
7104
- });
7105
- if (choice !== INGEST_RETRY.retry) {
7106
- failureAcknowledged = true;
7107
- break;
7108
- }
7109
- await runIngestionAgent([ingestionRetryInstruction(reason)]);
7110
- outcome = ingestOutcome(executions, repoRoot, ingestCommand);
7111
- }
7112
- while (!failureAcknowledged && !outcome.run && outcome.attempt?.approved) {
7024
+ while (!outcome.run && outcome.attempt?.approved) {
7113
7025
  const attempt = outcome.attempt;
7114
- const { reason, detail } = ingestFailure(attempt);
7026
+ const { reason, detail } = ingestFailure(attempt, executions);
7115
7027
  const choice = await ctx.requestUserInput({
7116
7028
  prompt: INGEST_RETRY_PROMPT,
7117
7029
  promptType: "multipleChoice",
@@ -7187,10 +7099,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
7187
7099
  );
7188
7100
  }
7189
7101
  } else {
7190
- const { reason, detail } = ingestFailure(
7191
- ingestAttempt,
7192
- await currentNoRunReason()
7193
- );
7102
+ const { reason, detail } = ingestFailure(ingestAttempt, executions);
7194
7103
  ingestOutcomeMessage = `\u26A0\uFE0F Records were not indexed \u2014 ${reason}.${ingestCommand ? " Run the command below when you are ready." : ""}`;
7195
7104
  ingestFailureDetail = detail;
7196
7105
  summaries.push(
@@ -7477,25 +7386,14 @@ var defaultWorkflow = {
7477
7386
  "ingestion"
7478
7387
  );
7479
7388
  return reviewStep(ctx, {
7480
- nextStepsGuidance: ingestionGuidance(ingestion2)
7389
+ // ingestCommand was already shown verbatim as a notice; an
7390
+ // LLM-paraphrased restatement in nextSteps risks being wrong.
7391
+ nextStepsGuidance: ingestion2?.ingestScriptRan ? "The wizard already ran the ingestion script and records are in the index. Do NOT tell the user to run it again; instead point them at the target index to confirm the records. Do not restate the ingestion command \u2014 the wizard already showed it to them." : "Tell the user to run the ingestion script; do not restate the exact command \u2014 the wizard already showed it to them above."
7481
7392
  });
7482
7393
  }
7483
7394
  })
7484
7395
  ]
7485
7396
  };
7486
- function ingestionGuidance(ingestion2) {
7487
- if (ingestion2?.ingestScriptRan) {
7488
- return "The wizard already ran the ingestion script and records are in the index. Do NOT tell the user to run it again; instead point them at the target index to confirm the records. Do not restate the ingestion command \u2014 the wizard already showed it to them.";
7489
- }
7490
- const partialCount = ingestion2?.ingestRecordCount ?? 0;
7491
- if (partialCount > 0) {
7492
- return `The ingestion script indexed ${partialCount} record(s) and then failed before it finished. Say that plainly. Do not say that ingestion succeeded or that no records were indexed. Tell the user to fix the error shown above and run the ingestion script again. Do not restate the exact command, because the wizard already showed it to them above.`;
7493
- }
7494
- if (ingestion2?.ingestCommand) {
7495
- return "No records were indexed in this run. Say that plainly, and do not say that the wizard created or populated an index. Tell the user to run the ingestion script; do not restate the exact command \u2014 the wizard already showed it to them above.";
7496
- }
7497
- return "No ingestion script ran and no records were indexed in this run. Say that plainly. Do not say that the wizard created, selected, or populated an index, and do not tell the user to run an ingestion script, because the wizard has no tested command for one. Tell the user to run the wizard again to create and run the ingestion script.";
7498
- }
7499
7397
 
7500
7398
  // src/actions/playbookSteps/selectPlaybook.ts
7501
7399
  import { z as z33 } from "zod";
@@ -7628,9 +7526,9 @@ async function getPlaybooks() {
7628
7526
  );
7629
7527
  return data;
7630
7528
  }
7631
- async function createPlaybookExecution(appId, slug2, indexName, options) {
7529
+ async function createPlaybookExecution(appId, slug, indexName, options) {
7632
7530
  const { data } = await dashboardRequest(
7633
- `/api/1/playbook-integrations/applications/${appId}/playbooks/${slug2}/executions`,
7531
+ `/api/1/playbook-integrations/applications/${appId}/playbooks/${slug}/executions`,
7634
7532
  playbookExecutionCreateResponseSchema,
7635
7533
  {
7636
7534
  method: "POST",
@@ -7671,9 +7569,9 @@ async function assessPlaybookExecution(uuid) {
7671
7569
  var selectPlaybookSchema = z33.object({
7672
7570
  slug: z33.string()
7673
7571
  });
7674
- function persistSlug(ctx, slug2) {
7675
- ctx.setUserInput("playbookSlug", slug2);
7676
- return { slug: slug2 };
7572
+ function persistSlug(ctx, slug) {
7573
+ ctx.setUserInput("playbookSlug", slug);
7574
+ return { slug };
7677
7575
  }
7678
7576
  async function selectPlaybookStep(ctx, requestedSlug) {
7679
7577
  const playbooks = await getPlaybooks();
@@ -7804,13 +7702,13 @@ async function confirmIndexStep(ctx) {
7804
7702
  if (!sampleIndex) {
7805
7703
  return null;
7806
7704
  }
7807
- const { slug: slug2 } = ctx.getStepOutput("select-playbook");
7705
+ const { slug } = ctx.getStepOutput("select-playbook");
7808
7706
  const selection = await ctx.requestUserInput({
7809
7707
  prompt: "Ready to create sample index?",
7810
7708
  promptType: "multipleChoice",
7811
7709
  options: [CONTINUE_OPTION, GO_BACK_OPTION2],
7812
7710
  messages: [
7813
- `A new index called "algolia_playbooks_${slug2}_sample_index" will be created with sample ${slug2} data.`
7711
+ `A new index called "algolia_playbooks_${slug}_sample_index" will be created with sample ${slug} data.`
7814
7712
  ],
7815
7713
  helpText: "Going back lets you choose a different index."
7816
7714
  });
@@ -7962,13 +7860,13 @@ var POLL_NOTICES = [
7962
7860
  { message: "detecting required fields\u2026" }
7963
7861
  ];
7964
7862
  async function dataAssessmentStep(ctx) {
7965
- const { slug: slug2 } = ctx.getStepOutput("select-playbook");
7863
+ const { slug } = ctx.getStepOutput("select-playbook");
7966
7864
  const { indexName, existingExecution } = indexForAssessment(ctx);
7967
7865
  if (existingExecution) return existingExecution;
7968
7866
  try {
7969
7867
  showNotice(ctx, CREATING_EXECUTION_NOTICE);
7970
7868
  const { id: appId } = await requireApplication();
7971
- const execution = await resolveExecution(ctx, appId, slug2, indexName);
7869
+ const execution = await resolveExecution(ctx, appId, slug, indexName);
7972
7870
  const assessed = await runAssessment(ctx, execution, indexName);
7973
7871
  ctx.clearNotices();
7974
7872
  await promptReady(ctx, assessed);
@@ -8073,24 +7971,24 @@ function unexpectedAssessmentStatus(status) {
8073
7971
  `data-assessment received an unexpected assessment status: ${status}`
8074
7972
  );
8075
7973
  }
8076
- async function resolveExecution(ctx, appId, slug2, indexName) {
8077
- const created = await createWithRecovery(ctx, appId, slug2, indexName);
7974
+ async function resolveExecution(ctx, appId, slug, indexName) {
7975
+ const created = await createWithRecovery(ctx, appId, slug, indexName);
8078
7976
  if (!created.resumed) return created;
8079
7977
  const choice = await promptResumeExecution(ctx, indexName);
8080
7978
  if (choice === CONTINUE_EXECUTION_OPTION) return created;
8081
7979
  if (choice === RESTART_OPTION) {
8082
- return createWithRecovery(ctx, appId, slug2, indexName, { forceNew: true });
7980
+ return createWithRecovery(ctx, appId, slug, indexName, { forceNew: true });
8083
7981
  }
8084
7982
  if (choice === GO_BACK_OPTION3) {
8085
7983
  return ctx.returnToStep("select-index");
8086
7984
  }
8087
7985
  throw new Error("data-assessment received an unexpected execution choice");
8088
7986
  }
8089
- async function createWithRecovery(ctx, appId, slug2, indexName, options) {
7987
+ async function createWithRecovery(ctx, appId, slug, indexName, options) {
8090
7988
  return retryOnDashboardError(
8091
7989
  () => {
8092
7990
  showNotice(ctx, CREATING_EXECUTION_NOTICE);
8093
- return createPlaybookExecution(appId, slug2, indexName, options);
7991
+ return createPlaybookExecution(appId, slug, indexName, options);
8094
7992
  },
8095
7993
  onRequestFailure(ctx, indexName)
8096
7994
  );
@@ -8692,10 +8590,15 @@ var sidebarCommands = [
8692
8590
  { keyHint: "tab", description: "toggle logs" },
8693
8591
  { keyHint: "esc", description: "exit wizard" }
8694
8592
  ];
8593
+ var logsSidebarCommands = [
8594
+ { keyHint: "tab", description: "toggle logs" },
8595
+ { keyHint: "esc", description: "back" }
8596
+ ];
8695
8597
 
8696
8598
  // src/ui/Sidebar.tsx
8697
8599
  import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
8698
- function Sidebar() {
8600
+ function Sidebar({ inLogs = false }) {
8601
+ const commands = inLogs ? logsSidebarCommands : sidebarCommands;
8699
8602
  return /* @__PURE__ */ jsxs16(
8700
8603
  Box17,
8701
8604
  {
@@ -8712,7 +8615,7 @@ function Sidebar() {
8712
8615
  ] }),
8713
8616
  /* @__PURE__ */ jsxs16(Box17, { flexDirection: "column", gap: 1, children: [
8714
8617
  /* @__PURE__ */ jsx16(Progress, {}),
8715
- /* @__PURE__ */ jsx16(Box17, { flexDirection: "column", children: sidebarCommands.map((c) => {
8618
+ /* @__PURE__ */ jsx16(Box17, { flexDirection: "column", children: commands.map((c) => {
8716
8619
  return /* @__PURE__ */ jsxs16(Box17, { flexDirection: "row", gap: 1, children: [
8717
8620
  /* @__PURE__ */ jsx16(Text18, { color: COLORS.primary, children: `[${c.keyHint}]` }),
8718
8621
  /* @__PURE__ */ jsx16(Text18, { color: COLORS.muted, children: c.description })
@@ -8750,23 +8653,130 @@ function Ribbon() {
8750
8653
  }
8751
8654
 
8752
8655
  // src/ui/App.tsx
8753
- import { useState as useState12 } from "react";
8656
+ import { useState as useState14 } from "react";
8754
8657
 
8755
8658
  // src/ui/Logs.tsx
8659
+ import { Box as Box20, Text as Text21, useInput as useInput9 } from "ink";
8660
+ import { useLayoutEffect as useLayoutEffect6, useState as useState12 } from "react";
8661
+
8662
+ // src/ui/LogDetails.tsx
8756
8663
  import { Box as Box19, Text as Text20, useInput as useInput8 } from "ink";
8757
- import { jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
8664
+ import { useLayoutEffect as useLayoutEffect5, useMemo, useState as useState11 } from "react";
8665
+
8666
+ // src/ui/logFormat.ts
8758
8667
  var KIND_COLOR = {
8759
8668
  tool: COLORS.primary,
8760
- prompt: COLORS.badge
8669
+ prompt: COLORS.badge,
8670
+ output: COLORS.muted
8671
+ };
8672
+ var STREAM_COLOR = {
8673
+ stderr: COLORS.muted,
8674
+ stdout: COLORS.dim
8761
8675
  };
8762
8676
  var STATUS_COLOR = {
8763
8677
  running: COLORS.status.running,
8764
8678
  error: COLORS.danger
8765
8679
  };
8766
8680
  function logNameColor(entry) {
8767
- return STATUS_COLOR[entry.status] ?? KIND_COLOR[entry.kind];
8681
+ const base = entry.stream ? STREAM_COLOR[entry.stream] : KIND_COLOR[entry.kind];
8682
+ return STATUS_COLOR[entry.status] ?? base;
8683
+ }
8684
+ function formatTimestamp(ms) {
8685
+ const d = new Date(ms);
8686
+ const pad = (n) => String(n).padStart(2, "0");
8687
+ return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
8688
+ }
8689
+ function durationText(entry) {
8690
+ return entry.kind === "tool" && entry.durationMs !== void 0 ? `${entry.durationMs}ms` : "";
8691
+ }
8692
+
8693
+ // src/ui/LogDetails.tsx
8694
+ import { jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
8695
+ var BLANK4 = { text: " ", color: COLORS.dim };
8696
+ var VALUE_INDENT = " ";
8697
+ var TAB = " ";
8698
+ function wrapLines(text, width, line, indent = "") {
8699
+ return wrapExact(
8700
+ text.replaceAll(" ", TAB),
8701
+ Math.max(width - indent.length, 1)
8702
+ ).map((part) => ({ ...line, text: indent + part }));
8703
+ }
8704
+ function formatValue(value) {
8705
+ return typeof value === "string" ? value : JSON.stringify(value, null, 2);
8706
+ }
8707
+ function inputFields(input) {
8708
+ if (input === void 0) return [];
8709
+ if (input !== null && typeof input === "object" && !Array.isArray(input)) {
8710
+ return Object.entries(input).filter(([, value]) => value !== void 0).map(([label, value]) => [label, formatValue(value)]);
8711
+ }
8712
+ return [["input", formatValue(input)]];
8713
+ }
8714
+ function metaText(entry) {
8715
+ const parts = [`[${formatTimestamp(entry.startedAt)}]`];
8716
+ if (entry.kind === "tool") parts.push(entry.status, durationText(entry));
8717
+ return parts.filter(Boolean).join(" ");
8718
+ }
8719
+ function buildDetailLines(entry, width) {
8720
+ const lines = wrapLines(entry.name, width, {
8721
+ color: logNameColor(entry),
8722
+ bold: true
8723
+ });
8724
+ lines.push({ text: metaText(entry), color: COLORS.dim });
8725
+ for (const [label, value] of inputFields(entry.input)) {
8726
+ lines.push(BLANK4, { text: label, color: COLORS.muted });
8727
+ lines.push(
8728
+ ...wrapLines(value, width, { color: COLORS.primary }, VALUE_INDENT)
8729
+ );
8730
+ }
8731
+ return lines;
8732
+ }
8733
+ function LogDetails({
8734
+ entry,
8735
+ onClose
8736
+ }) {
8737
+ const [width, setWidth] = useState11(0);
8738
+ const lines = useMemo(
8739
+ () => width > 0 ? buildDetailLines(entry, width) : [],
8740
+ [entry, width]
8741
+ );
8742
+ const scroll = useScrollWindow({ itemCount: lines.length });
8743
+ useLayoutEffect5(() => {
8744
+ if (scroll.measured) setWidth(scroll.width);
8745
+ }, [scroll.measured, scroll.width]);
8746
+ useInput8((input, key) => {
8747
+ if (input === "k" || key.upArrow) scroll.scrollBy(-1);
8748
+ else if (input === "j" || key.downArrow) scroll.scrollBy(1);
8749
+ else if (key.escape) onClose();
8750
+ });
8751
+ const visible = lines.slice(scroll.offset, scroll.offset + scroll.capacity);
8752
+ return /* @__PURE__ */ jsxs18(Box19, { flexDirection: "column", flexGrow: 1, children: [
8753
+ /* @__PURE__ */ jsx18(ScrollView, { scroll, children: visible.map((line, i) => /* @__PURE__ */ jsx18(
8754
+ Text20,
8755
+ {
8756
+ color: line.color,
8757
+ bold: line.bold,
8758
+ wrap: "truncate",
8759
+ children: line.text
8760
+ },
8761
+ `detail-${scroll.offset + i}`
8762
+ )) }),
8763
+ /* @__PURE__ */ jsxs18(Box19, { gap: 2, children: [
8764
+ scroll.maxOffset > 0 && /* @__PURE__ */ jsxs18(Text20, { children: [
8765
+ /* @__PURE__ */ jsx18(Text20, { color: COLORS.primary, children: "[j] [k]" }),
8766
+ /* @__PURE__ */ jsx18(Text20, { color: COLORS.dim, children: " scroll" })
8767
+ ] }),
8768
+ /* @__PURE__ */ jsxs18(Text20, { children: [
8769
+ /* @__PURE__ */ jsx18(Text20, { color: COLORS.primary, children: "[esc]" }),
8770
+ /* @__PURE__ */ jsx18(Text20, { color: COLORS.dim, children: " back" })
8771
+ ] })
8772
+ ] })
8773
+ ] });
8768
8774
  }
8775
+
8776
+ // src/ui/Logs.tsx
8777
+ import { Fragment, jsx as jsx19, jsxs as jsxs19 } from "react/jsx-runtime";
8769
8778
  var ROW_GAP = 1;
8779
+ var SELECTED_MARKER = "\u276F";
8770
8780
  function truncate3(str, maxWidth) {
8771
8781
  if (maxWidth <= 0) return "";
8772
8782
  return str.length > maxWidth ? `${str.slice(0, maxWidth - 1)}\u2026` : str;
@@ -8777,53 +8787,84 @@ function rawInputText(input) {
8777
8787
  if (!str || str === "{}") return "";
8778
8788
  return str.replace(/\s+/g, " ").trim();
8779
8789
  }
8780
- function formatTimestamp(ms) {
8781
- const d = new Date(ms);
8782
- const pad = (n) => String(n).padStart(2, "0");
8783
- return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
8784
- }
8785
- function Logs() {
8790
+ function Logs({ onBack }) {
8786
8791
  const logs = useWizard((s) => s.logs);
8787
- const scroll = useScrollWindow({ itemCount: logs.length, followBottom: true });
8788
- useInput8((input, key) => {
8789
- if (input === "k" || key.upArrow) scroll.scrollBy(-1);
8790
- else if (input === "j" || key.downArrow) scroll.scrollBy(1);
8792
+ const [openLogId, setOpenLogId] = useState12(null);
8793
+ const [selectedId, setSelectedId] = useState12(null);
8794
+ const found = selectedId === null ? -1 : logs.findIndex((e) => e.id === selectedId);
8795
+ if (selectedId !== null && found < 0) setSelectedId(null);
8796
+ const scroll = useScrollWindow({
8797
+ itemCount: logs.length,
8798
+ followBottom: selectedId === null
8791
8799
  });
8800
+ const selectedIndex = found >= 0 ? found : logs.length - 1;
8801
+ const openEntry = logs.find((e) => e.id === openLogId);
8802
+ const { revealIndex } = scroll;
8803
+ useLayoutEffect6(() => {
8804
+ if (selectedIndex >= 0) revealIndex(selectedIndex);
8805
+ }, [selectedIndex, revealIndex]);
8806
+ const moveSelection = (delta) => {
8807
+ if (logs.length === 0) return;
8808
+ const next = Math.min(Math.max(selectedIndex + delta, 0), logs.length - 1);
8809
+ setSelectedId(next === logs.length - 1 ? null : logs[next].id);
8810
+ };
8811
+ useInput9(
8812
+ (input, key) => {
8813
+ if (input === "k" || key.upArrow) moveSelection(-1);
8814
+ else if (input === "j" || key.downArrow) moveSelection(1);
8815
+ else if (key.return && logs[selectedIndex]) {
8816
+ setOpenLogId(logs[selectedIndex].id);
8817
+ } else if (key.escape) onBack();
8818
+ },
8819
+ { isActive: !openEntry }
8820
+ );
8792
8821
  const visible = logs.slice(scroll.offset, scroll.offset + scroll.capacity);
8793
- return /* @__PURE__ */ jsxs18(Box19, { flexDirection: "column", paddingX: 4, paddingY: 2, flexGrow: 1, children: [
8794
- logs.length === 0 && /* @__PURE__ */ jsx18(Text20, { color: COLORS.dim, children: "No logs yet." }),
8795
- /* @__PURE__ */ jsx18(ScrollView, { scroll, children: visible.map((entry) => {
8822
+ return /* @__PURE__ */ jsx19(Box20, { flexDirection: "column", paddingX: 4, paddingY: 2, flexGrow: 1, children: openEntry ? /* @__PURE__ */ jsx19(LogDetails, { entry: openEntry, onClose: () => setOpenLogId(null) }) : /* @__PURE__ */ jsxs19(Fragment, { children: [
8823
+ logs.length === 0 && /* @__PURE__ */ jsx19(Text21, { color: COLORS.dim, children: "No logs yet." }),
8824
+ /* @__PURE__ */ jsx19(ScrollView, { scroll, children: visible.map((entry, i) => {
8825
+ const selected = scroll.offset + i === selectedIndex;
8796
8826
  const timestamp = `[${formatTimestamp(entry.startedAt)}]`;
8797
- const durationText = entry.kind === "tool" && entry.durationMs !== void 0 ? `${entry.durationMs}ms` : "";
8827
+ const duration = durationText(entry);
8798
8828
  const rawPreview = rawInputText(entry.input);
8799
- const partCount = 2 + (rawPreview ? 1 : 0) + (durationText ? 1 : 0);
8829
+ const partCount = 3 + (rawPreview ? 1 : 0) + (duration ? 1 : 0);
8800
8830
  const gaps = (partCount - 1) * ROW_GAP;
8801
- let budget = scroll.width - timestamp.length - durationText.length - gaps;
8831
+ let budget = scroll.width - SELECTED_MARKER.length - timestamp.length - duration.length - gaps;
8802
8832
  const name = truncate3(entry.name, budget);
8803
8833
  budget -= name.length;
8804
8834
  const preview = rawPreview ? truncate3(rawPreview, budget) : "";
8805
- return /* @__PURE__ */ jsxs18(Box19, { flexDirection: "row", gap: ROW_GAP, children: [
8806
- /* @__PURE__ */ jsx18(Text20, { color: COLORS.dim, children: timestamp }),
8807
- /* @__PURE__ */ jsx18(Text20, { color: logNameColor(entry), wrap: "truncate", children: name }),
8808
- preview && /* @__PURE__ */ jsx18(Text20, { color: COLORS.dim, wrap: "truncate", children: preview }),
8809
- durationText && /* @__PURE__ */ jsx18(Text20, { color: COLORS.dim, children: durationText })
8835
+ return /* @__PURE__ */ jsxs19(Box20, { flexDirection: "row", gap: ROW_GAP, children: [
8836
+ /* @__PURE__ */ jsx19(Text21, { color: COLORS.success, children: selected ? SELECTED_MARKER : " " }),
8837
+ /* @__PURE__ */ jsx19(Text21, { color: COLORS.dim, children: timestamp }),
8838
+ /* @__PURE__ */ jsx19(Text21, { color: logNameColor(entry), wrap: "truncate", children: name }),
8839
+ preview && /* @__PURE__ */ jsx19(Text21, { color: COLORS.dim, wrap: "truncate", children: preview }),
8840
+ duration && /* @__PURE__ */ jsx19(Text21, { color: COLORS.dim, children: duration })
8810
8841
  ] }, entry.id);
8811
8842
  }) }),
8812
- /* @__PURE__ */ jsxs18(Text20, { children: [
8813
- /* @__PURE__ */ jsx18(Text20, { color: COLORS.primary, children: "[j] [k]" }),
8814
- /* @__PURE__ */ jsx18(Text20, { color: COLORS.dim, children: " scroll" })
8843
+ /* @__PURE__ */ jsxs19(Box20, { gap: 2, children: [
8844
+ /* @__PURE__ */ jsxs19(Text21, { children: [
8845
+ /* @__PURE__ */ jsx19(Text21, { color: COLORS.primary, children: "[j] [k]" }),
8846
+ /* @__PURE__ */ jsx19(Text21, { color: COLORS.dim, children: " select" })
8847
+ ] }),
8848
+ /* @__PURE__ */ jsxs19(Text21, { children: [
8849
+ /* @__PURE__ */ jsx19(Text21, { color: COLORS.primary, children: "[enter]" }),
8850
+ /* @__PURE__ */ jsx19(Text21, { color: COLORS.dim, children: " details" })
8851
+ ] }),
8852
+ /* @__PURE__ */ jsxs19(Text21, { children: [
8853
+ /* @__PURE__ */ jsx19(Text21, { color: COLORS.primary, children: "[esc]" }),
8854
+ /* @__PURE__ */ jsx19(Text21, { color: COLORS.dim, children: " back" })
8855
+ ] })
8815
8856
  ] })
8816
- ] });
8857
+ ] }) });
8817
8858
  }
8818
8859
 
8819
8860
  // src/ui/Tips.tsx
8820
- import { useEffect as useEffect3, useRef as useRef4, useState as useState11 } from "react";
8821
- import { Box as Box21, Text as Text22 } from "ink";
8861
+ import { useEffect as useEffect3, useRef as useRef4, useState as useState13 } from "react";
8862
+ import { Box as Box22, Text as Text23 } from "ink";
8822
8863
  import terminalLink from "terminal-link";
8823
8864
 
8824
8865
  // src/ui/Code.tsx
8825
- import { Box as Box20, Text as Text21 } from "ink";
8826
- import { jsx as jsx19 } from "react/jsx-runtime";
8866
+ import { Box as Box21, Text as Text22 } from "ink";
8867
+ import { jsx as jsx20 } from "react/jsx-runtime";
8827
8868
  var TOKEN_RE = /("(?:\\.|[^"\\])*"|\btrue\b|\bfalse\b|\bnull\b|-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|[{}[\]:,])/g;
8828
8869
  function highlightJson(json) {
8829
8870
  const parts = json.split(TOKEN_RE);
@@ -8832,22 +8873,22 @@ function highlightJson(json) {
8832
8873
  if (part[0] === '"') {
8833
8874
  const next = parts.slice(i + 1).find((p) => p.trim());
8834
8875
  const isKey = next?.trimStart().startsWith(":");
8835
- return /* @__PURE__ */ jsx19(Text21, { color: isKey ? "cyan" : "green", children: part }, i);
8876
+ return /* @__PURE__ */ jsx20(Text22, { color: isKey ? "cyan" : "green", children: part }, i);
8836
8877
  }
8837
8878
  if (part === "true" || part === "false" || part === "null") {
8838
- return /* @__PURE__ */ jsx19(Text21, { color: "magenta", children: part }, i);
8879
+ return /* @__PURE__ */ jsx20(Text22, { color: "magenta", children: part }, i);
8839
8880
  }
8840
8881
  if (/^-?\d/.test(part)) {
8841
- return /* @__PURE__ */ jsx19(Text21, { color: "yellow", children: part }, i);
8882
+ return /* @__PURE__ */ jsx20(Text22, { color: "yellow", children: part }, i);
8842
8883
  }
8843
8884
  if (/^[{}[\]:,]$/.test(part)) {
8844
- return /* @__PURE__ */ jsx19(Text21, { color: COLORS.dim, children: part }, i);
8885
+ return /* @__PURE__ */ jsx20(Text22, { color: COLORS.dim, children: part }, i);
8845
8886
  }
8846
- return /* @__PURE__ */ jsx19(Text21, { children: part }, i);
8887
+ return /* @__PURE__ */ jsx20(Text22, { children: part }, i);
8847
8888
  });
8848
8889
  }
8849
8890
  function Code({ children }) {
8850
- return /* @__PURE__ */ jsx19(Box20, { children: /* @__PURE__ */ jsx19(Text21, { children: highlightJson(children) }) });
8891
+ return /* @__PURE__ */ jsx20(Box21, { children: /* @__PURE__ */ jsx20(Text22, { children: highlightJson(children) }) });
8851
8892
  }
8852
8893
 
8853
8894
  // src/ui/copy/tips.ts
@@ -9043,26 +9084,26 @@ var tips = [
9043
9084
  ];
9044
9085
 
9045
9086
  // src/ui/Tips.tsx
9046
- import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
9087
+ import { jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
9047
9088
  var TICK_MS = 16;
9048
9089
  var CHUNK_HOLD_MS = 2e3;
9049
9090
  var TIP_DURATION_MS = 25e3;
9050
9091
  function TipTitle({ children }) {
9051
- return /* @__PURE__ */ jsxs19(Box21, { gap: 1, children: [
9052
- /* @__PURE__ */ jsx20(Text22, { color: "cyan", children: "\u2726" }),
9053
- /* @__PURE__ */ jsx20(Text22, { color: "white", bold: true, children })
9092
+ return /* @__PURE__ */ jsxs20(Box22, { gap: 1, children: [
9093
+ /* @__PURE__ */ jsx21(Text23, { color: "cyan", children: "\u2726" }),
9094
+ /* @__PURE__ */ jsx21(Text23, { color: "white", bold: true, children })
9054
9095
  ] });
9055
9096
  }
9056
9097
  function InlineSegment({ segment }) {
9057
9098
  switch (segment.type) {
9058
9099
  case "highlight":
9059
- return /* @__PURE__ */ jsx20(Text22, { color: COLORS.success, children: segment.value });
9100
+ return /* @__PURE__ */ jsx21(Text23, { color: COLORS.success, children: segment.value });
9060
9101
  case "link":
9061
- return /* @__PURE__ */ jsx20(Text22, { color: "cyan", underline: true, children: segment.href ? terminalLink(segment.value, segment.href) : segment.value });
9102
+ return /* @__PURE__ */ jsx21(Text23, { color: "cyan", underline: true, children: segment.href ? terminalLink(segment.value, segment.href) : segment.value });
9062
9103
  case "codeword":
9063
- return /* @__PURE__ */ jsx20(Text22, { color: COLORS.highlight.fg, backgroundColor: COLORS.highlight.bg, children: segment.value });
9104
+ return /* @__PURE__ */ jsx21(Text23, { color: COLORS.highlight.fg, backgroundColor: COLORS.highlight.bg, children: segment.value });
9064
9105
  default:
9065
- return /* @__PURE__ */ jsx20(Text22, { color: COLORS.muted, children: segment.value });
9106
+ return /* @__PURE__ */ jsx21(Text23, { color: COLORS.muted, children: segment.value });
9066
9107
  }
9067
9108
  }
9068
9109
  function TipContent({
@@ -9096,10 +9137,10 @@ function TipContent({
9096
9137
  blocks.push({ type: "inline", segments: [segment] });
9097
9138
  }
9098
9139
  }
9099
- return /* @__PURE__ */ jsx20(Box21, { flexDirection: "column", marginLeft: 2, gap: 1, children: blocks.map(
9100
- (block, i) => block.type === "code" ? /* @__PURE__ */ jsx20(Code, { children: block.segment.value }, i) : /* @__PURE__ */ jsx20(Text22, { children: block.segments.map((segment, j) => /* @__PURE__ */ jsxs19(Text22, { children: [
9140
+ return /* @__PURE__ */ jsx21(Box22, { flexDirection: "column", marginLeft: 2, gap: 1, children: blocks.map(
9141
+ (block, i) => block.type === "code" ? /* @__PURE__ */ jsx21(Code, { children: block.segment.value }, i) : /* @__PURE__ */ jsx21(Text23, { children: block.segments.map((segment, j) => /* @__PURE__ */ jsxs20(Text23, { children: [
9101
9142
  j > 0 && " ",
9102
- /* @__PURE__ */ jsx20(InlineSegment, { segment })
9143
+ /* @__PURE__ */ jsx21(InlineSegment, { segment })
9103
9144
  ] }, j)) }, i)
9104
9145
  ) });
9105
9146
  }
@@ -9129,7 +9170,7 @@ function Tips({
9129
9170
  onRevealStateChange,
9130
9171
  onComplete
9131
9172
  }) {
9132
- const [position, setPosition] = useState11(() => {
9173
+ const [position, setPosition] = useState13(() => {
9133
9174
  const now = Date.now();
9134
9175
  return {
9135
9176
  tipIndex: clock.tipIndex,
@@ -9189,9 +9230,9 @@ function Tips({
9189
9230
  if (position.complete) return null;
9190
9231
  const titleRevealed = tip.title.slice(0, revealed);
9191
9232
  const contentRevealed = Math.max(0, revealed - tip.title.length);
9192
- return /* @__PURE__ */ jsxs19(Box21, { flexDirection: "column", marginBottom: 1, gap: 1, children: [
9193
- /* @__PURE__ */ jsx20(TipTitle, { children: titleRevealed }),
9194
- /* @__PURE__ */ jsx20(TipContent, { chunks: tip.chunks, revealed: contentRevealed })
9233
+ return /* @__PURE__ */ jsxs20(Box22, { flexDirection: "column", marginBottom: 1, gap: 1, children: [
9234
+ /* @__PURE__ */ jsx21(TipTitle, { children: titleRevealed }),
9235
+ /* @__PURE__ */ jsx21(TipContent, { chunks: tip.chunks, revealed: contentRevealed })
9195
9236
  ] });
9196
9237
  }
9197
9238
 
@@ -9233,7 +9274,7 @@ function useRepaintOnResize(debounceMs = 100) {
9233
9274
  }
9234
9275
 
9235
9276
  // src/ui/App.tsx
9236
- import { jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
9277
+ import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
9237
9278
  function App() {
9238
9279
  const {
9239
9280
  phase,
@@ -9252,14 +9293,9 @@ function App() {
9252
9293
  const { columns, rows } = useWindowSize8();
9253
9294
  useRepaintOnResize();
9254
9295
  const compactRun = isCompactTerminal(columns, rows);
9255
- const [showLogs, setShowLogs] = useState12(false);
9256
- const [seenInputReq, setSeenInputReq] = useState12(inputReq);
9257
- if (inputReq !== seenInputReq) {
9258
- setSeenInputReq(inputReq);
9259
- if (inputReq) setShowLogs(false);
9260
- }
9261
- const [tipState, setTipState] = useState12("idle");
9262
- const [tipsComplete, setTipsComplete] = useState12(false);
9296
+ const [showLogs, setShowLogs] = useState14(false);
9297
+ const [tipState, setTipState] = useState14("idle");
9298
+ const [tipsComplete, setTipsComplete] = useState14(false);
9263
9299
  const finished = phase === "done" || phase === "error";
9264
9300
  const currentStep = steps[currentStepIndex];
9265
9301
  const workflowDef = workflow ? getWorkflow(workflow.id) : void 0;
@@ -9270,15 +9306,15 @@ function App() {
9270
9306
  const showTips = !compactRun && tipsActive && (phase === "running" && currentStep?.status === "running" && !loadingMessage && !settingUpAppId || holdForTip);
9271
9307
  const showNoticesInMain = !tipsActive;
9272
9308
  const showNotices = !compactRun && (!isAwaitingUserInput || holdForTip) && !review2;
9273
- useInput9(
9309
+ useInput10(
9274
9310
  (_input, key) => {
9275
9311
  if (key.return) {
9276
9312
  exit();
9277
9313
  }
9278
9314
  },
9279
- { isActive: finished }
9315
+ { isActive: finished && !showLogs }
9280
9316
  );
9281
- useInput9((_input, key) => {
9317
+ useInput10((_input, key) => {
9282
9318
  if (phase === "idle" || phase === "authenticating") return;
9283
9319
  if (key.tab) {
9284
9320
  setShowLogs(!showLogs);
@@ -9289,8 +9325,9 @@ function App() {
9289
9325
  });
9290
9326
  }
9291
9327
  });
9292
- const escOwnedElsewhere = phase === "idle" || phase === "authenticating" || phase === "awaitingInput" && !holdForTip && (inputReq?.promptType === "enterToContinue" || inputReq?.promptType === "commandApproval");
9293
- useInput9((_input, key) => {
9328
+ const escOwnedElsewhere = phase === "idle" || phase === "authenticating" || // The log view owns esc: it closes the details, then leaves the list.
9329
+ showLogs || phase === "awaitingInput" && !holdForTip && (inputReq?.promptType === "enterToContinue" || inputReq?.promptType === "commandApproval");
9330
+ useInput10((_input, key) => {
9294
9331
  if (escOwnedElsewhere) return;
9295
9332
  if (key.escape) {
9296
9333
  track("AI Wizard Interaction", {
@@ -9308,8 +9345,8 @@ function App() {
9308
9345
  /* Clamped to exactly the viewport: a taller frame makes Ink clear and repaint
9309
9346
  the whole screen, and the scrolling throws off its cursor arithmetic.
9310
9347
  Flicker and leftover rows. */
9311
- /* @__PURE__ */ jsxs20(
9312
- Box22,
9348
+ /* @__PURE__ */ jsxs21(
9349
+ Box23,
9313
9350
  {
9314
9351
  backgroundColor: COLORS.bg.main,
9315
9352
  flexDirection: "row",
@@ -9317,16 +9354,16 @@ function App() {
9317
9354
  height: rows,
9318
9355
  overflow: "hidden",
9319
9356
  children: [
9320
- mainWindowVisible && /* @__PURE__ */ jsxs20(
9321
- Box22,
9357
+ mainWindowVisible && /* @__PURE__ */ jsxs21(
9358
+ Box23,
9322
9359
  {
9323
9360
  flexDirection,
9324
9361
  width: "100%",
9325
9362
  maxHeight: rows,
9326
9363
  justifyContent: "space-between",
9327
9364
  children: [
9328
- showLogs ? /* @__PURE__ */ jsx21(Logs, {}) : /* @__PURE__ */ jsxs20(
9329
- Box22,
9365
+ showLogs ? /* @__PURE__ */ jsx22(Logs, { onBack: () => setShowLogs(false) }) : /* @__PURE__ */ jsxs21(
9366
+ Box23,
9330
9367
  {
9331
9368
  flexDirection: "column",
9332
9369
  paddingX: 4,
@@ -9335,58 +9372,58 @@ function App() {
9335
9372
  flexGrow: 1,
9336
9373
  gap: 1,
9337
9374
  children: [
9338
- /* @__PURE__ */ jsxs20(Box22, { flexGrow: 2, flexDirection: "column", children: [
9339
- phase === "preflight" && !user && /* @__PURE__ */ jsx21(Box22, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs20(Text23, { color: COLORS.strong, bold: true, children: [
9340
- /* @__PURE__ */ jsx21(Spinner3, { type: "dots" }),
9375
+ /* @__PURE__ */ jsxs21(Box23, { flexGrow: 2, flexDirection: "column", children: [
9376
+ phase === "preflight" && !user && /* @__PURE__ */ jsx22(Box23, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs21(Text24, { color: COLORS.strong, bold: true, children: [
9377
+ /* @__PURE__ */ jsx22(Spinner3, { type: "dots" }),
9341
9378
  " Signing in to Algolia"
9342
9379
  ] }) }),
9343
- phase === "preflight" && user && /* @__PURE__ */ jsx21(Box22, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs20(Text23, { color: COLORS.strong, bold: true, children: [
9344
- /* @__PURE__ */ jsx21(Spinner3, { type: "dots" }),
9380
+ phase === "preflight" && user && /* @__PURE__ */ jsx22(Box23, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs21(Text24, { color: COLORS.strong, bold: true, children: [
9381
+ /* @__PURE__ */ jsx22(Spinner3, { type: "dots" }),
9345
9382
  " Getting things ready"
9346
9383
  ] }) }),
9347
- phase === "authenticating" && /* @__PURE__ */ jsxs20(Box22, { flexDirection: "column", marginBottom: 1, children: [
9348
- /* @__PURE__ */ jsxs20(Text23, { color: COLORS.strong, bold: true, children: [
9349
- /* @__PURE__ */ jsx21(Spinner3, { type: "dots" }),
9384
+ phase === "authenticating" && /* @__PURE__ */ jsxs21(Box23, { flexDirection: "column", marginBottom: 1, children: [
9385
+ /* @__PURE__ */ jsxs21(Text24, { color: COLORS.strong, bold: true, children: [
9386
+ /* @__PURE__ */ jsx22(Spinner3, { type: "dots" }),
9350
9387
  " Signing in to Algolia"
9351
9388
  ] }),
9352
- /* @__PURE__ */ jsx21(Text23, { color: COLORS.muted, children: "A browser window will open \u2014 complete sign-in there." })
9389
+ /* @__PURE__ */ jsx22(Text24, { color: COLORS.muted, children: "A browser window will open \u2014 complete sign-in there." })
9353
9390
  ] }),
9354
- settingUpAppId && /* @__PURE__ */ jsx21(Box22, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs20(Text23, { color: COLORS.strong, bold: true, children: [
9355
- /* @__PURE__ */ jsx21(Spinner3, { type: "dots" }),
9391
+ settingUpAppId && /* @__PURE__ */ jsx22(Box23, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs21(Text24, { color: COLORS.strong, bold: true, children: [
9392
+ /* @__PURE__ */ jsx22(Spinner3, { type: "dots" }),
9356
9393
  " Setting up Wizard using app",
9357
9394
  " ",
9358
9395
  settingUpAppId
9359
9396
  ] }) }),
9360
- phase === "running" && !settingUpAppId && loadingMessage && /* @__PURE__ */ jsx21(Box22, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs20(Text23, { color: COLORS.strong, bold: true, children: [
9361
- /* @__PURE__ */ jsx21(Spinner3, { type: "dots" }),
9397
+ phase === "running" && !settingUpAppId && loadingMessage && /* @__PURE__ */ jsx22(Box23, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs21(Text24, { color: COLORS.strong, bold: true, children: [
9398
+ /* @__PURE__ */ jsx22(Spinner3, { type: "dots" }),
9362
9399
  " ",
9363
9400
  loadingMessage
9364
9401
  ] }) }),
9365
- /* @__PURE__ */ jsx21(CliOutput, {}),
9366
- showTips && /* @__PURE__ */ jsx21(
9402
+ /* @__PURE__ */ jsx22(CliOutput, {}),
9403
+ showTips && /* @__PURE__ */ jsx22(
9367
9404
  Tips,
9368
9405
  {
9369
9406
  onRevealStateChange: setTipState,
9370
9407
  onComplete: () => setTipsComplete(true)
9371
9408
  }
9372
9409
  ),
9373
- showNoticesInMain && showNotices && /* @__PURE__ */ jsx21(Notices, { border: false }),
9374
- /* @__PURE__ */ jsx21(Review, {}),
9375
- !showTips && /* @__PURE__ */ jsx21(PromptInput, {}),
9376
- phase === "error" && error && /* @__PURE__ */ jsx21(Box22, { marginTop: 1, children: /* @__PURE__ */ jsxs20(Text23, { color: COLORS.status.error, children: [
9410
+ showNoticesInMain && showNotices && /* @__PURE__ */ jsx22(Notices, { border: false }),
9411
+ /* @__PURE__ */ jsx22(Review, {}),
9412
+ !showTips && /* @__PURE__ */ jsx22(PromptInput, {}),
9413
+ phase === "error" && error && /* @__PURE__ */ jsx22(Box23, { marginTop: 1, children: /* @__PURE__ */ jsxs21(Text24, { color: COLORS.status.error, children: [
9377
9414
  "\u2716 ",
9378
9415
  error
9379
9416
  ] }) })
9380
9417
  ] }),
9381
- !showNoticesInMain && showNotices && /* @__PURE__ */ jsx21(Notices, {})
9418
+ !showNoticesInMain && showNotices && /* @__PURE__ */ jsx22(Notices, {})
9382
9419
  ]
9383
9420
  }
9384
9421
  ),
9385
- showSidebar ? /* @__PURE__ */ jsx21(Sidebar, {}) : /* @__PURE__ */ jsx21(Ribbon, {})
9422
+ showSidebar ? /* @__PURE__ */ jsx22(Sidebar, { inLogs: showLogs }) : /* @__PURE__ */ jsx22(Ribbon, {})
9386
9423
  ]
9387
9424
  }
9388
9425
  ),
9389
- phase === "idle" && (homeScreen === "learnMore" ? /* @__PURE__ */ jsx21(LearnMore, {}) : /* @__PURE__ */ jsx21(Welcome, {}))
9426
+ phase === "idle" && (homeScreen === "learnMore" ? /* @__PURE__ */ jsx22(LearnMore, {}) : /* @__PURE__ */ jsx22(Welcome, {}))
9390
9427
  ]
9391
9428
  }
9392
9429
  )
@@ -9625,7 +9662,7 @@ async function resetProjectState() {
9625
9662
  // package.json with { type: 'json' }
9626
9663
  var package_default2 = {
9627
9664
  name: "@algolia/wizard",
9628
- version: "0.87.0-rc.211.681",
9665
+ version: "0.87.0",
9629
9666
  description: "Magically implement Algolia functionality in your codebase",
9630
9667
  type: "module",
9631
9668
  engines: {
@@ -9731,7 +9768,7 @@ async function checkVersion() {
9731
9768
  }
9732
9769
 
9733
9770
  // src/main.tsx
9734
- import { jsx as jsx22 } from "react/jsx-runtime";
9771
+ import { jsx as jsx23 } from "react/jsx-runtime";
9735
9772
  var FAILURE_EXIT_CODE = 1;
9736
9773
  async function exitProcessWithError(store, instance, message) {
9737
9774
  store.setError(message);
@@ -9794,7 +9831,7 @@ ${formatStepList(workflow)}`);
9794
9831
  async function run(opts) {
9795
9832
  const { workflow, skipResumePrompt } = opts;
9796
9833
  const store = useWizard.getState();
9797
- const instance = render(/* @__PURE__ */ jsx22(App, {}), { incrementalRendering: true });
9834
+ const instance = render(/* @__PURE__ */ jsx23(App, {}), { incrementalRendering: true });
9798
9835
  await store.waitForStart();
9799
9836
  store.syncSteps(
9800
9837
  workflow.steps.map((s) => ({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@algolia/wizard",
3
- "version": "0.87.0-rc.211.681",
3
+ "version": "0.87.0",
4
4
  "description": "Magically implement Algolia functionality in your codebase",
5
5
  "type": "module",
6
6
  "engines": {