@algolia/wizard 0.85.0 → 0.87.0-rc.211.681
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +182 -49
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -2332,7 +2332,7 @@ async function ensureApplication(resumeAppId) {
|
|
|
2332
2332
|
// package.json
|
|
2333
2333
|
var package_default = {
|
|
2334
2334
|
name: "@algolia/wizard",
|
|
2335
|
-
version: "0.
|
|
2335
|
+
version: "0.87.0-rc.211.681",
|
|
2336
2336
|
description: "Magically implement Algolia functionality in your codebase",
|
|
2337
2337
|
type: "module",
|
|
2338
2338
|
engines: {
|
|
@@ -2805,6 +2805,9 @@ async function runWorkflow(workflow, startWorkflowAppId, options) {
|
|
|
2805
2805
|
}
|
|
2806
2806
|
}
|
|
2807
2807
|
|
|
2808
|
+
// src/actions/selectIndex.ts
|
|
2809
|
+
import { basename } from "node:path";
|
|
2810
|
+
|
|
2808
2811
|
// src/actions/listIndices.ts
|
|
2809
2812
|
import { z as z5 } from "zod";
|
|
2810
2813
|
var indicesListSchema = z5.object({
|
|
@@ -2839,11 +2842,28 @@ function indexNameError(name) {
|
|
|
2839
2842
|
return "Index name cannot end with .txt, .bin, or .idx.";
|
|
2840
2843
|
return void 0;
|
|
2841
2844
|
}
|
|
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
|
+
}
|
|
2842
2857
|
var selectIndexStep = async (ctx) => {
|
|
2843
2858
|
await requireApplication(ctx.appId);
|
|
2844
2859
|
const indices = await listIndices();
|
|
2845
2860
|
const names = indices.map((i) => i.name);
|
|
2846
2861
|
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}".`;
|
|
2847
2867
|
let error;
|
|
2848
2868
|
let chosen;
|
|
2849
2869
|
while (chosen === void 0) {
|
|
@@ -2858,7 +2878,8 @@ var selectIndexStep = async (ctx) => {
|
|
|
2858
2878
|
promptType: "textInput",
|
|
2859
2879
|
options: [],
|
|
2860
2880
|
messages: [
|
|
2861
|
-
"This app has no existing indices \u2014 enter a name to create one."
|
|
2881
|
+
"This app has no existing indices \u2014 enter a name to create one.",
|
|
2882
|
+
suggestionHint
|
|
2862
2883
|
],
|
|
2863
2884
|
error
|
|
2864
2885
|
});
|
|
@@ -2868,17 +2889,18 @@ var selectIndexStep = async (ctx) => {
|
|
|
2868
2889
|
let candidate;
|
|
2869
2890
|
let isNewName = true;
|
|
2870
2891
|
if (!hasIndices) {
|
|
2871
|
-
candidate = selection.trim();
|
|
2892
|
+
candidate = selection.trim() || suggested;
|
|
2872
2893
|
} else if (selection === CREATE_NEW_INDEX) {
|
|
2873
2894
|
const name = await ctx.requestUserInput({
|
|
2874
2895
|
prompt: "Name the new index:",
|
|
2875
2896
|
promptType: "textInput",
|
|
2876
|
-
options: []
|
|
2897
|
+
options: [],
|
|
2898
|
+
messages: [suggestionHint]
|
|
2877
2899
|
});
|
|
2878
2900
|
if (typeof name !== "string") {
|
|
2879
2901
|
throw new Error("selectIndex received an unexpected non-text result");
|
|
2880
2902
|
}
|
|
2881
|
-
candidate = name.trim();
|
|
2903
|
+
candidate = name.trim() || suggested;
|
|
2882
2904
|
} else {
|
|
2883
2905
|
candidate = selection;
|
|
2884
2906
|
isNewName = false;
|
|
@@ -3114,14 +3136,14 @@ import z9 from "zod";
|
|
|
3114
3136
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
3115
3137
|
|
|
3116
3138
|
// src/lib/tools/env.ts
|
|
3117
|
-
import { basename } from "node:path";
|
|
3139
|
+
import { basename as basename2 } from "node:path";
|
|
3118
3140
|
function isEnvFile(filePath) {
|
|
3119
|
-
const name =
|
|
3141
|
+
const name = basename2(filePath);
|
|
3120
3142
|
return name === ".env" || name.startsWith(".env.");
|
|
3121
3143
|
}
|
|
3122
3144
|
function isSecretEnvFile(filePath) {
|
|
3123
3145
|
if (!isEnvFile(filePath)) return false;
|
|
3124
|
-
const name =
|
|
3146
|
+
const name = basename2(filePath);
|
|
3125
3147
|
return !/\.(example|sample|template)$/.test(name);
|
|
3126
3148
|
}
|
|
3127
3149
|
function secretEnvWriteRefusal(filePath) {
|
|
@@ -3756,7 +3778,7 @@ import { execFile as execFile2 } from "node:child_process";
|
|
|
3756
3778
|
import { tool as tool8 } from "ai";
|
|
3757
3779
|
import z15 from "zod";
|
|
3758
3780
|
import { lstat as lstat3, readdir as readdir2, readFile as readFile8, realpath, stat as stat2 } from "node:fs/promises";
|
|
3759
|
-
import { basename as
|
|
3781
|
+
import { basename as basename3, isAbsolute as isAbsolute2, join as join8, relative as relative4, sep as sep2 } from "node:path";
|
|
3760
3782
|
import { performance } from "node:perf_hooks";
|
|
3761
3783
|
import { Worker } from "node:worker_threads";
|
|
3762
3784
|
var MAX_GIT_OUTPUT_BYTES = 32e6;
|
|
@@ -4099,7 +4121,7 @@ async function safeSearchPath(rootPath, file) {
|
|
|
4099
4121
|
}
|
|
4100
4122
|
async function searchableFiles(root, target) {
|
|
4101
4123
|
try {
|
|
4102
|
-
if (SKIP_FILES.has(
|
|
4124
|
+
if (SKIP_FILES.has(basename3(target)) && (await lstat3(target)).isFile()) {
|
|
4103
4125
|
return [target];
|
|
4104
4126
|
}
|
|
4105
4127
|
const gitRoot = await gitRootForTarget(root, target);
|
|
@@ -4278,7 +4300,7 @@ import { tool as tool9 } from "ai";
|
|
|
4278
4300
|
import z16 from "zod";
|
|
4279
4301
|
import { createHash as createHash2 } from "node:crypto";
|
|
4280
4302
|
import { readFile as readFile9, stat as stat3 } from "node:fs/promises";
|
|
4281
|
-
import { basename as
|
|
4303
|
+
import { basename as basename4, relative as relative5, resolve as resolve3 } from "node:path";
|
|
4282
4304
|
|
|
4283
4305
|
// src/lib/tools/utils/prompt.ts
|
|
4284
4306
|
var chain = Promise.resolve();
|
|
@@ -4376,7 +4398,7 @@ function commandDiffersFromReviewedScript(ctx, command, cwd) {
|
|
|
4376
4398
|
if (approval.command === command && approval.cwd === cwd) return false;
|
|
4377
4399
|
if (approval.command === command) return true;
|
|
4378
4400
|
const scriptReferences = [
|
|
4379
|
-
|
|
4401
|
+
basename4(approval.filePath),
|
|
4380
4402
|
relative5(ctx.root, approval.filePath),
|
|
4381
4403
|
".algolia-wizard"
|
|
4382
4404
|
];
|
|
@@ -5097,8 +5119,8 @@ function generateRecordTool(ctx, createModel = defaultCreateModel2) {
|
|
|
5097
5119
|
...record,
|
|
5098
5120
|
objectID: nanoid2()
|
|
5099
5121
|
}));
|
|
5100
|
-
const
|
|
5101
|
-
const relPath = `${DATA_DIR}/${
|
|
5122
|
+
const slug2 = entityName.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
5123
|
+
const relPath = `${DATA_DIR}/${slug2}.json`;
|
|
5102
5124
|
const resolved2 = resolveInRoot(ctx, relPath);
|
|
5103
5125
|
if (resolved2.ok === false) return resolved2.error;
|
|
5104
5126
|
const writeError = await safeWriteFile(
|
|
@@ -6051,7 +6073,7 @@ import {
|
|
|
6051
6073
|
// src/lib/git.ts
|
|
6052
6074
|
import { execFile as execFile3 } from "node:child_process";
|
|
6053
6075
|
import { copyFile, mkdir as mkdir4, stat as stat4 } from "node:fs/promises";
|
|
6054
|
-
import { basename as
|
|
6076
|
+
import { basename as basename5, dirname as dirname3, isAbsolute as isAbsolute3, join as join9, resolve as resolve4 } from "node:path";
|
|
6055
6077
|
var MAX_BUFFER = 32 * 1024 * 1024;
|
|
6056
6078
|
function git(args) {
|
|
6057
6079
|
return new Promise((resolve6, reject) => {
|
|
@@ -6088,7 +6110,7 @@ async function copyUploadIntoProject(repoRoot, ingestDir, sourcePath) {
|
|
|
6088
6110
|
} catch {
|
|
6089
6111
|
return { ok: false, reason: `"${sourcePath}" does not exist` };
|
|
6090
6112
|
}
|
|
6091
|
-
const relPath = join9(ingestDir,
|
|
6113
|
+
const relPath = join9(ingestDir, basename5(source));
|
|
6092
6114
|
const dest = join9(repoRoot, relPath);
|
|
6093
6115
|
if (resolve4(source) === resolve4(dest)) {
|
|
6094
6116
|
return { ok: true, relPath };
|
|
@@ -6246,6 +6268,7 @@ var INGEST_RETRY = {
|
|
|
6246
6268
|
retry: "Retry ingestion",
|
|
6247
6269
|
skip: "Continue without records"
|
|
6248
6270
|
};
|
|
6271
|
+
var INGEST_AGENT_RETRY_PROMPT = "Retry to let the wizard write and run the ingestion script again.";
|
|
6249
6272
|
var FILE_UPLOAD_PATH_PROMPT = "Enter the path to your JSON, CSV, or TSV file (relative to the project root, or absolute):";
|
|
6250
6273
|
var JS_LANGUAGES = ["javascript", "typescript", "jsx", "tsx", "node"];
|
|
6251
6274
|
function lower(entries) {
|
|
@@ -6472,9 +6495,29 @@ function cdnSearchInstructions(input) {
|
|
|
6472
6495
|
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.`,
|
|
6473
6496
|
'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>.',
|
|
6474
6497
|
'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.',
|
|
6475
|
-
`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}
|
|
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
|
|
6476
6500
|
];
|
|
6477
6501
|
}
|
|
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.`;
|
|
6478
6521
|
function validationInstructions(input) {
|
|
6479
6522
|
return [
|
|
6480
6523
|
"Validate the Algolia search implementation by inspecting the project source.",
|
|
@@ -6495,7 +6538,8 @@ function validationInstructions(input) {
|
|
|
6495
6538
|
"Do not modify files. Report each implementation issue as a concrete instruction for the next implementation pass.",
|
|
6496
6539
|
`Detected verification tools: ${JSON.stringify(input.findings.verification ?? [])}. Use only a type checker; ignore any linter or formatter in this list.`,
|
|
6497
6540
|
...!input.frontendHasPackageJson ? [
|
|
6498
|
-
"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."
|
|
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."
|
|
6499
6543
|
] : [],
|
|
6500
6544
|
"Always call reportStatus with status=success after validation, even when sufficient=false.",
|
|
6501
6545
|
"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.",
|
|
@@ -6635,8 +6679,8 @@ async function firstRecordIn(filePath) {
|
|
|
6635
6679
|
async function ingestedRecordSample(repoRoot, entityName, uploadFilePath) {
|
|
6636
6680
|
const candidates = [];
|
|
6637
6681
|
if (entityName) {
|
|
6638
|
-
const
|
|
6639
|
-
candidates.push(join11(repoRoot, INGEST_DIR, "data", `${
|
|
6682
|
+
const slug2 = entityName.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
6683
|
+
candidates.push(join11(repoRoot, INGEST_DIR, "data", `${slug2}.json`));
|
|
6640
6684
|
}
|
|
6641
6685
|
if (uploadFilePath?.toLowerCase().endsWith(".json")) {
|
|
6642
6686
|
candidates.push(join11(repoRoot, uploadFilePath));
|
|
@@ -6655,12 +6699,25 @@ function recordSchema(sample, attributes) {
|
|
|
6655
6699
|
}
|
|
6656
6700
|
return Object.fromEntries(attributes.map((key) => [key, "unknown"]));
|
|
6657
6701
|
}
|
|
6658
|
-
function
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
|
|
6662
|
-
|
|
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";
|
|
6663
6713
|
}
|
|
6714
|
+
if (!ingestCommand) {
|
|
6715
|
+
return scriptPath ? `the ingestion script ${scriptPath} was written but not run` : "no ingestion script was written";
|
|
6716
|
+
}
|
|
6717
|
+
return "no successful run was recorded";
|
|
6718
|
+
}
|
|
6719
|
+
function ingestFailure(attempt, missingRunReason = "no successful run was recorded") {
|
|
6720
|
+
if (!attempt) return { reason: missingRunReason };
|
|
6664
6721
|
if (!attempt.approved) return { reason: "you declined to run it" };
|
|
6665
6722
|
const detail = errorLine(attempt.output);
|
|
6666
6723
|
if (attempt.timedOut) {
|
|
@@ -6702,6 +6759,9 @@ function briefSummary(summary) {
|
|
|
6702
6759
|
if (!firstLine) return "no summary given";
|
|
6703
6760
|
return firstLine.length > ERROR_SUMMARY_MAX_CHARS ? `${firstLine.slice(0, ERROR_SUMMARY_MAX_CHARS - 1)}\u2026` : firstLine;
|
|
6704
6761
|
}
|
|
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
|
+
}
|
|
6705
6765
|
function validationRetryInstructions(validation) {
|
|
6706
6766
|
return [
|
|
6707
6767
|
`Implementation insufficient. Address these findings before reporting completion: ${validation.additionalInstructions ?? validation.summary}`
|
|
@@ -6988,16 +7048,70 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
|
|
|
6988
7048
|
}
|
|
6989
7049
|
if (useCases.includes("ingestion")) {
|
|
6990
7050
|
let ingestFailureDetail;
|
|
6991
|
-
const result = await runImplementationUseCase("ingestion");
|
|
6992
|
-
summaries.push(formatSummary("ingestion", result.summary));
|
|
6993
|
-
ingestCommand = result.ingestCommand;
|
|
6994
7051
|
const ingestionContext = ingestionTools;
|
|
6995
7052
|
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();
|
|
6996
7095
|
let outcome = ingestOutcome(executions, repoRoot, ingestCommand);
|
|
6997
7096
|
let failureAcknowledged = false;
|
|
6998
|
-
while (!outcome.run && outcome.attempt
|
|
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) {
|
|
6999
7113
|
const attempt = outcome.attempt;
|
|
7000
|
-
const { reason, detail } = ingestFailure(attempt
|
|
7114
|
+
const { reason, detail } = ingestFailure(attempt);
|
|
7001
7115
|
const choice = await ctx.requestUserInput({
|
|
7002
7116
|
prompt: INGEST_RETRY_PROMPT,
|
|
7003
7117
|
promptType: "multipleChoice",
|
|
@@ -7073,7 +7187,10 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
|
|
|
7073
7187
|
);
|
|
7074
7188
|
}
|
|
7075
7189
|
} else {
|
|
7076
|
-
const { reason, detail } = ingestFailure(
|
|
7190
|
+
const { reason, detail } = ingestFailure(
|
|
7191
|
+
ingestAttempt,
|
|
7192
|
+
await currentNoRunReason()
|
|
7193
|
+
);
|
|
7077
7194
|
ingestOutcomeMessage = `\u26A0\uFE0F Records were not indexed \u2014 ${reason}.${ingestCommand ? " Run the command below when you are ready." : ""}`;
|
|
7078
7195
|
ingestFailureDetail = detail;
|
|
7079
7196
|
summaries.push(
|
|
@@ -7360,14 +7477,25 @@ var defaultWorkflow = {
|
|
|
7360
7477
|
"ingestion"
|
|
7361
7478
|
);
|
|
7362
7479
|
return reviewStep(ctx, {
|
|
7363
|
-
|
|
7364
|
-
// LLM-paraphrased restatement in nextSteps risks being wrong.
|
|
7365
|
-
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."
|
|
7480
|
+
nextStepsGuidance: ingestionGuidance(ingestion2)
|
|
7366
7481
|
});
|
|
7367
7482
|
}
|
|
7368
7483
|
})
|
|
7369
7484
|
]
|
|
7370
7485
|
};
|
|
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
|
+
}
|
|
7371
7499
|
|
|
7372
7500
|
// src/actions/playbookSteps/selectPlaybook.ts
|
|
7373
7501
|
import { z as z33 } from "zod";
|
|
@@ -7500,9 +7628,9 @@ async function getPlaybooks() {
|
|
|
7500
7628
|
);
|
|
7501
7629
|
return data;
|
|
7502
7630
|
}
|
|
7503
|
-
async function createPlaybookExecution(appId,
|
|
7631
|
+
async function createPlaybookExecution(appId, slug2, indexName, options) {
|
|
7504
7632
|
const { data } = await dashboardRequest(
|
|
7505
|
-
`/api/1/playbook-integrations/applications/${appId}/playbooks/${
|
|
7633
|
+
`/api/1/playbook-integrations/applications/${appId}/playbooks/${slug2}/executions`,
|
|
7506
7634
|
playbookExecutionCreateResponseSchema,
|
|
7507
7635
|
{
|
|
7508
7636
|
method: "POST",
|
|
@@ -7543,9 +7671,9 @@ async function assessPlaybookExecution(uuid) {
|
|
|
7543
7671
|
var selectPlaybookSchema = z33.object({
|
|
7544
7672
|
slug: z33.string()
|
|
7545
7673
|
});
|
|
7546
|
-
function persistSlug(ctx,
|
|
7547
|
-
ctx.setUserInput("playbookSlug",
|
|
7548
|
-
return { slug };
|
|
7674
|
+
function persistSlug(ctx, slug2) {
|
|
7675
|
+
ctx.setUserInput("playbookSlug", slug2);
|
|
7676
|
+
return { slug: slug2 };
|
|
7549
7677
|
}
|
|
7550
7678
|
async function selectPlaybookStep(ctx, requestedSlug) {
|
|
7551
7679
|
const playbooks = await getPlaybooks();
|
|
@@ -7676,13 +7804,13 @@ async function confirmIndexStep(ctx) {
|
|
|
7676
7804
|
if (!sampleIndex) {
|
|
7677
7805
|
return null;
|
|
7678
7806
|
}
|
|
7679
|
-
const { slug } = ctx.getStepOutput("select-playbook");
|
|
7807
|
+
const { slug: slug2 } = ctx.getStepOutput("select-playbook");
|
|
7680
7808
|
const selection = await ctx.requestUserInput({
|
|
7681
7809
|
prompt: "Ready to create sample index?",
|
|
7682
7810
|
promptType: "multipleChoice",
|
|
7683
7811
|
options: [CONTINUE_OPTION, GO_BACK_OPTION2],
|
|
7684
7812
|
messages: [
|
|
7685
|
-
`A new index called "algolia_playbooks_${
|
|
7813
|
+
`A new index called "algolia_playbooks_${slug2}_sample_index" will be created with sample ${slug2} data.`
|
|
7686
7814
|
],
|
|
7687
7815
|
helpText: "Going back lets you choose a different index."
|
|
7688
7816
|
});
|
|
@@ -7834,13 +7962,13 @@ var POLL_NOTICES = [
|
|
|
7834
7962
|
{ message: "detecting required fields\u2026" }
|
|
7835
7963
|
];
|
|
7836
7964
|
async function dataAssessmentStep(ctx) {
|
|
7837
|
-
const { slug } = ctx.getStepOutput("select-playbook");
|
|
7965
|
+
const { slug: slug2 } = ctx.getStepOutput("select-playbook");
|
|
7838
7966
|
const { indexName, existingExecution } = indexForAssessment(ctx);
|
|
7839
7967
|
if (existingExecution) return existingExecution;
|
|
7840
7968
|
try {
|
|
7841
7969
|
showNotice(ctx, CREATING_EXECUTION_NOTICE);
|
|
7842
7970
|
const { id: appId } = await requireApplication();
|
|
7843
|
-
const execution = await resolveExecution(ctx, appId,
|
|
7971
|
+
const execution = await resolveExecution(ctx, appId, slug2, indexName);
|
|
7844
7972
|
const assessed = await runAssessment(ctx, execution, indexName);
|
|
7845
7973
|
ctx.clearNotices();
|
|
7846
7974
|
await promptReady(ctx, assessed);
|
|
@@ -7945,24 +8073,24 @@ function unexpectedAssessmentStatus(status) {
|
|
|
7945
8073
|
`data-assessment received an unexpected assessment status: ${status}`
|
|
7946
8074
|
);
|
|
7947
8075
|
}
|
|
7948
|
-
async function resolveExecution(ctx, appId,
|
|
7949
|
-
const created = await createWithRecovery(ctx, appId,
|
|
8076
|
+
async function resolveExecution(ctx, appId, slug2, indexName) {
|
|
8077
|
+
const created = await createWithRecovery(ctx, appId, slug2, indexName);
|
|
7950
8078
|
if (!created.resumed) return created;
|
|
7951
8079
|
const choice = await promptResumeExecution(ctx, indexName);
|
|
7952
8080
|
if (choice === CONTINUE_EXECUTION_OPTION) return created;
|
|
7953
8081
|
if (choice === RESTART_OPTION) {
|
|
7954
|
-
return createWithRecovery(ctx, appId,
|
|
8082
|
+
return createWithRecovery(ctx, appId, slug2, indexName, { forceNew: true });
|
|
7955
8083
|
}
|
|
7956
8084
|
if (choice === GO_BACK_OPTION3) {
|
|
7957
8085
|
return ctx.returnToStep("select-index");
|
|
7958
8086
|
}
|
|
7959
8087
|
throw new Error("data-assessment received an unexpected execution choice");
|
|
7960
8088
|
}
|
|
7961
|
-
async function createWithRecovery(ctx, appId,
|
|
8089
|
+
async function createWithRecovery(ctx, appId, slug2, indexName, options) {
|
|
7962
8090
|
return retryOnDashboardError(
|
|
7963
8091
|
() => {
|
|
7964
8092
|
showNotice(ctx, CREATING_EXECUTION_NOTICE);
|
|
7965
|
-
return createPlaybookExecution(appId,
|
|
8093
|
+
return createPlaybookExecution(appId, slug2, indexName, options);
|
|
7966
8094
|
},
|
|
7967
8095
|
onRequestFailure(ctx, indexName)
|
|
7968
8096
|
);
|
|
@@ -9125,6 +9253,11 @@ function App() {
|
|
|
9125
9253
|
useRepaintOnResize();
|
|
9126
9254
|
const compactRun = isCompactTerminal(columns, rows);
|
|
9127
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
|
+
}
|
|
9128
9261
|
const [tipState, setTipState] = useState12("idle");
|
|
9129
9262
|
const [tipsComplete, setTipsComplete] = useState12(false);
|
|
9130
9263
|
const finished = phase === "done" || phase === "error";
|
|
@@ -9492,7 +9625,7 @@ async function resetProjectState() {
|
|
|
9492
9625
|
// package.json with { type: 'json' }
|
|
9493
9626
|
var package_default2 = {
|
|
9494
9627
|
name: "@algolia/wizard",
|
|
9495
|
-
version: "0.
|
|
9628
|
+
version: "0.87.0-rc.211.681",
|
|
9496
9629
|
description: "Magically implement Algolia functionality in your codebase",
|
|
9497
9630
|
type: "module",
|
|
9498
9631
|
engines: {
|