@algolia/wizard 0.52.0-rc.136.364 → 0.52.0-rc.151.365
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 +216 -230
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -239,9 +239,6 @@ function describeInputValue(value) {
|
|
|
239
239
|
}
|
|
240
240
|
var NOTICE_INTERVAL_MS = 2e3;
|
|
241
241
|
var CLI_OUTPUT_LIMIT = 200;
|
|
242
|
-
function commandApprovalKey(command, cwd) {
|
|
243
|
-
return `${cwd}\0${command}`;
|
|
244
|
-
}
|
|
245
242
|
var useWizard = create((set, get) => ({
|
|
246
243
|
phase: "idle",
|
|
247
244
|
homeScreen: "home",
|
|
@@ -359,17 +356,10 @@ var useWizard = create((set, get) => ({
|
|
|
359
356
|
setTargetIndex: (index) => set({ targetIndex: index }),
|
|
360
357
|
recordWrittenFile: (path) => set((s) => ({ writtenFiles: [...s.writtenFiles, path] })),
|
|
361
358
|
clearWrittenFiles: () => set({ writtenFiles: [] }),
|
|
362
|
-
isCommandApproved: (command, cwd) => get().approvedCommands.has(
|
|
359
|
+
isCommandApproved: (command, cwd) => get().approvedCommands.has(`${cwd}\0${command}`),
|
|
363
360
|
approveCommand: (command, cwd) => set((s) => ({
|
|
364
|
-
approvedCommands: new Set(s.approvedCommands).add(
|
|
365
|
-
commandApprovalKey(command, cwd)
|
|
366
|
-
)
|
|
361
|
+
approvedCommands: new Set(s.approvedCommands).add(`${cwd}\0${command}`)
|
|
367
362
|
})),
|
|
368
|
-
revokeCommand: (command, cwd) => set((s) => {
|
|
369
|
-
const approvedCommands = new Set(s.approvedCommands);
|
|
370
|
-
approvedCommands.delete(commandApprovalKey(command, cwd));
|
|
371
|
-
return { approvedCommands };
|
|
372
|
-
}),
|
|
373
363
|
logStart: (kind, name, input) => {
|
|
374
364
|
const id = nanoid();
|
|
375
365
|
set((s) => ({
|
|
@@ -748,11 +738,9 @@ function DecisionSelect({
|
|
|
748
738
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
749
739
|
function CommandApproval({
|
|
750
740
|
command,
|
|
751
|
-
messages,
|
|
752
741
|
onDecide
|
|
753
742
|
}) {
|
|
754
743
|
return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", gap: 1, children: [
|
|
755
|
-
messages?.map((message, index) => /* @__PURE__ */ jsx5(Text6, { color: COLORS.muted, children: message }, `msg-${index}`)),
|
|
756
744
|
/* @__PURE__ */ jsx5(Text6, { color: COLORS.primary, bold: true, children: "Run this command?" }),
|
|
757
745
|
/* @__PURE__ */ jsxs5(
|
|
758
746
|
Box6,
|
|
@@ -1169,6 +1157,7 @@ function PromptInput() {
|
|
|
1169
1157
|
return /* @__PURE__ */ jsx8(Box9, { flexGrow: 1, children: /* @__PURE__ */ jsx8(
|
|
1170
1158
|
SelectPrompt,
|
|
1171
1159
|
{
|
|
1160
|
+
question: inputReq.prompt,
|
|
1172
1161
|
messages: inputReq.messages,
|
|
1173
1162
|
options: ["Continue"],
|
|
1174
1163
|
onSelect: handleSubmit
|
|
@@ -1187,14 +1176,7 @@ function PromptInput() {
|
|
|
1187
1176
|
);
|
|
1188
1177
|
}
|
|
1189
1178
|
if (inputReq.promptType === "commandApproval" && inputReq.command) {
|
|
1190
|
-
return /* @__PURE__ */ jsx8(
|
|
1191
|
-
CommandApproval,
|
|
1192
|
-
{
|
|
1193
|
-
command: inputReq.command,
|
|
1194
|
-
messages: inputReq.messages,
|
|
1195
|
-
onDecide: submitInput
|
|
1196
|
-
}
|
|
1197
|
-
);
|
|
1179
|
+
return /* @__PURE__ */ jsx8(CommandApproval, { command: inputReq.command, onDecide: submitInput });
|
|
1198
1180
|
}
|
|
1199
1181
|
if (inputReq.promptType === "acceptReject") {
|
|
1200
1182
|
const labels = inputReq.options?.length ? inputReq.options : ACCEPT_REJECT_OPTIONS;
|
|
@@ -2716,16 +2698,9 @@ function searchFilesTool(ctx) {
|
|
|
2716
2698
|
}
|
|
2717
2699
|
|
|
2718
2700
|
// src/lib/tools/runShell.ts
|
|
2719
|
-
import { tool as
|
|
2701
|
+
import { tool as tool8, generateText, Output } from "ai";
|
|
2720
2702
|
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
2721
|
-
import z16 from "zod";
|
|
2722
|
-
import { relative as relative5 } from "node:path";
|
|
2723
|
-
|
|
2724
|
-
// src/lib/tools/reviewScript.ts
|
|
2725
|
-
import { tool as tool8 } from "ai";
|
|
2726
2703
|
import z15 from "zod";
|
|
2727
|
-
import { createHash } from "node:crypto";
|
|
2728
|
-
import { readFile as readFile7, stat as stat2 } from "node:fs/promises";
|
|
2729
2704
|
import { relative as relative4 } from "node:path";
|
|
2730
2705
|
|
|
2731
2706
|
// src/lib/tools/utils/prompt.ts
|
|
@@ -2737,116 +2712,6 @@ function serializePrompt(work) {
|
|
|
2737
2712
|
return result;
|
|
2738
2713
|
}
|
|
2739
2714
|
|
|
2740
|
-
// src/lib/tools/reviewScript.ts
|
|
2741
|
-
var reviewedCommandApprovals = /* @__PURE__ */ new WeakMap();
|
|
2742
|
-
async function fileDigest(filePath) {
|
|
2743
|
-
const content = await readFile7(filePath);
|
|
2744
|
-
return createHash("sha256").update(content).digest("hex");
|
|
2745
|
-
}
|
|
2746
|
-
function grantReviewedCommandApproval(ctx, approval) {
|
|
2747
|
-
reviewedCommandApprovals.set(ctx, approval);
|
|
2748
|
-
}
|
|
2749
|
-
function getReviewedCommandApproval(ctx, command, cwd) {
|
|
2750
|
-
const approval = reviewedCommandApprovals.get(ctx);
|
|
2751
|
-
if (approval?.command !== command || approval.cwd !== cwd) return void 0;
|
|
2752
|
-
return approval;
|
|
2753
|
-
}
|
|
2754
|
-
function clearReviewedCommandApproval(ctx) {
|
|
2755
|
-
reviewedCommandApprovals.delete(ctx);
|
|
2756
|
-
}
|
|
2757
|
-
function revokeCommandApprovals(ctx, command, cwd) {
|
|
2758
|
-
clearReviewedCommandApproval(ctx);
|
|
2759
|
-
useWizard.getState().revokeCommand(command, cwd);
|
|
2760
|
-
}
|
|
2761
|
-
async function reviewedCommandApprovalIsCurrent(approval) {
|
|
2762
|
-
const currentDigest = await fileDigest(approval.filePath).catch(() => null);
|
|
2763
|
-
return currentDigest === approval.digest;
|
|
2764
|
-
}
|
|
2765
|
-
function reviewScriptTool(ctx) {
|
|
2766
|
-
return tool8({
|
|
2767
|
-
description: "Call this as soon as the ingestion script is finished and before you run it. It summarizes the records that will be written, then asks the user to review the script and approve the exact command that will run it, so a matching runShell call needs no second approval.",
|
|
2768
|
-
inputSchema: z15.object({
|
|
2769
|
-
filePath: z15.string().describe(
|
|
2770
|
-
"Path to the script to review, relative to the project root."
|
|
2771
|
-
),
|
|
2772
|
-
command: z15.string().min(1).describe("The exact command that runShell will use to run the script."),
|
|
2773
|
-
cwd: z15.string().describe(
|
|
2774
|
-
"The exact working directory that runShell will use, relative to the current tool working directory."
|
|
2775
|
-
),
|
|
2776
|
-
entityName: z15.string().trim().min(1).max(100).regex(/^[^\r\n]+$/).describe("The exact entity name selected by the user."),
|
|
2777
|
-
usesGeneratedRecords: z15.boolean().describe(
|
|
2778
|
-
"Whether the script reads generated sample records instead of the selected real data source."
|
|
2779
|
-
)
|
|
2780
|
-
}),
|
|
2781
|
-
execute: async ({
|
|
2782
|
-
filePath,
|
|
2783
|
-
command,
|
|
2784
|
-
cwd,
|
|
2785
|
-
entityName,
|
|
2786
|
-
usesGeneratedRecords
|
|
2787
|
-
}) => {
|
|
2788
|
-
logger.info(
|
|
2789
|
-
{ filePath, command, cwd, entityName, usesGeneratedRecords },
|
|
2790
|
-
"called reviewScript tool"
|
|
2791
|
-
);
|
|
2792
|
-
const resolved2 = resolveInRoot(ctx, filePath);
|
|
2793
|
-
if (resolved2.ok === false) return resolved2.error;
|
|
2794
|
-
const resolvedCwd = resolveInRoot(ctx, cwd);
|
|
2795
|
-
if (resolvedCwd.ok === false) return resolvedCwd.error;
|
|
2796
|
-
const displayCwd = relative4(ctx.root, resolvedCwd.target) || ".";
|
|
2797
|
-
const displayFilePath = relative4(ctx.root, resolved2.target);
|
|
2798
|
-
const ingestionSummary = usesGeneratedRecords ? `This will push ${entityName} records from generated sample data to Algolia. You can replace the sample dataset with your real data source in ${displayFilePath}.` : `This will push ${entityName} records from your selected source to Algolia.`;
|
|
2799
|
-
return serializePrompt(async () => {
|
|
2800
|
-
revokeCommandApprovals(ctx, command, resolvedCwd.target);
|
|
2801
|
-
const isFile = await stat2(resolved2.target).then(
|
|
2802
|
-
(s) => s.isFile(),
|
|
2803
|
-
() => false
|
|
2804
|
-
);
|
|
2805
|
-
if (!isFile) {
|
|
2806
|
-
return `Refused: ${filePath} is not a file. Write the script first, then review the path you wrote.`;
|
|
2807
|
-
}
|
|
2808
|
-
const reviewedDigest = await fileDigest(resolved2.target).catch(
|
|
2809
|
-
() => null
|
|
2810
|
-
);
|
|
2811
|
-
if (reviewedDigest === null) {
|
|
2812
|
-
return `Refused: ${filePath} could not be read. Write the script first, then review it again.`;
|
|
2813
|
-
}
|
|
2814
|
-
const answer = await useWizard.getState().requestUserInput({
|
|
2815
|
-
prompt: "Run this command?",
|
|
2816
|
-
promptType: "commandApproval",
|
|
2817
|
-
options: [],
|
|
2818
|
-
messages: [
|
|
2819
|
-
`We have created your ingestion script. Please review it at ${displayFilePath} before approving.`
|
|
2820
|
-
],
|
|
2821
|
-
command: {
|
|
2822
|
-
command,
|
|
2823
|
-
cwd: displayCwd,
|
|
2824
|
-
explanation: ingestionSummary
|
|
2825
|
-
}
|
|
2826
|
-
});
|
|
2827
|
-
if (answer !== "approve") {
|
|
2828
|
-
revokeCommandApprovals(ctx, command, resolvedCwd.target);
|
|
2829
|
-
return "The user declined to run this ingestion script. Do not run it.";
|
|
2830
|
-
}
|
|
2831
|
-
const approvedDigest = await fileDigest(resolved2.target).catch(
|
|
2832
|
-
() => null
|
|
2833
|
-
);
|
|
2834
|
-
if (approvedDigest !== reviewedDigest) {
|
|
2835
|
-
return "The ingestion script changed while it was being reviewed. Call reviewScript again before running it.";
|
|
2836
|
-
}
|
|
2837
|
-
ctx.reviewed.push(resolved2.target);
|
|
2838
|
-
grantReviewedCommandApproval(ctx, {
|
|
2839
|
-
command,
|
|
2840
|
-
cwd: resolvedCwd.target,
|
|
2841
|
-
filePath: resolved2.target,
|
|
2842
|
-
digest: reviewedDigest
|
|
2843
|
-
});
|
|
2844
|
-
return "The user reviewed the script and approved this exact command. Run it now with the same cwd.";
|
|
2845
|
-
});
|
|
2846
|
-
}
|
|
2847
|
-
});
|
|
2848
|
-
}
|
|
2849
|
-
|
|
2850
2715
|
// src/lib/tools/utils/runShell.ts
|
|
2851
2716
|
import { spawn as spawn2 } from "node:child_process";
|
|
2852
2717
|
|
|
@@ -2945,7 +2810,7 @@ function storeApproval(root) {
|
|
|
2945
2810
|
return async (req) => {
|
|
2946
2811
|
const store = useWizard.getState();
|
|
2947
2812
|
if (store.isCommandApproved(req.command, req.cwd)) return "approve";
|
|
2948
|
-
const rel =
|
|
2813
|
+
const rel = relative4(root, req.cwd);
|
|
2949
2814
|
const answer = await store.requestUserInput({
|
|
2950
2815
|
prompt: "Run this command?",
|
|
2951
2816
|
promptType: "commandApproval",
|
|
@@ -2960,7 +2825,6 @@ function storeApproval(root) {
|
|
|
2960
2825
|
return "approve";
|
|
2961
2826
|
};
|
|
2962
2827
|
}
|
|
2963
|
-
var SUCCESS_EXIT_CODE = 0;
|
|
2964
2828
|
var FILE_IO_COMMANDS = /* @__PURE__ */ new Set([
|
|
2965
2829
|
"ls",
|
|
2966
2830
|
"find",
|
|
@@ -3099,9 +2963,9 @@ function fastPathSafety(command) {
|
|
|
3099
2963
|
return void 0;
|
|
3100
2964
|
}
|
|
3101
2965
|
var CLASSIFIER_MODEL = "claude-haiku-4-5";
|
|
3102
|
-
var commandSafetySchema =
|
|
3103
|
-
safe:
|
|
3104
|
-
reason:
|
|
2966
|
+
var commandSafetySchema = z15.object({
|
|
2967
|
+
safe: z15.boolean(),
|
|
2968
|
+
reason: z15.string().describe("One short sentence explaining the verdict.")
|
|
3105
2969
|
});
|
|
3106
2970
|
function defaultCreateModel() {
|
|
3107
2971
|
const token = getAuthToken();
|
|
@@ -3161,15 +3025,12 @@ async function classifyCommandSafety(createModel, command, cwd, explanation, app
|
|
|
3161
3025
|
return false;
|
|
3162
3026
|
}
|
|
3163
3027
|
}
|
|
3164
|
-
async function
|
|
3165
|
-
|
|
3028
|
+
async function runAndRecord(ctx, command, cwd) {
|
|
3029
|
+
useWizard.getState().pushNotice({ messages: [`Running: ${command}`] });
|
|
3030
|
+
const env = await ctx.shell.env().catch((err) => {
|
|
3166
3031
|
logger.warn({ err, command }, "runShell: could not resolve command env");
|
|
3167
3032
|
return {};
|
|
3168
3033
|
});
|
|
3169
|
-
}
|
|
3170
|
-
async function runAndRecord(ctx, command, cwd, resolvedEnv) {
|
|
3171
|
-
useWizard.getState().pushNotice({ messages: [`Running: ${command}`] });
|
|
3172
|
-
const env = resolvedEnv ?? await resolveShellEnv(ctx, command);
|
|
3173
3034
|
const run2 = await (ctx.shell.run ?? runShell)(command, {
|
|
3174
3035
|
cwd,
|
|
3175
3036
|
env,
|
|
@@ -3200,19 +3061,6 @@ async function runAndRecord(ctx, command, cwd, resolvedEnv) {
|
|
|
3200
3061
|
output: run2.output
|
|
3201
3062
|
};
|
|
3202
3063
|
}
|
|
3203
|
-
async function runReviewedCommand(ctx, command, cwd) {
|
|
3204
|
-
const approval = getReviewedCommandApproval(ctx, command, cwd);
|
|
3205
|
-
if (!approval) return void 0;
|
|
3206
|
-
const env = await resolveShellEnv(ctx, command);
|
|
3207
|
-
if (!await reviewedCommandApprovalIsCurrent(approval)) {
|
|
3208
|
-
return `Refused: ${relative5(ctx.root, approval.filePath)} changed after review. Call reviewScript again before running it.`;
|
|
3209
|
-
}
|
|
3210
|
-
const result = await runAndRecord(ctx, command, cwd, env);
|
|
3211
|
-
if (result.exitCode === SUCCESS_EXIT_CODE && !result.timedOut) {
|
|
3212
|
-
clearReviewedCommandApproval(ctx);
|
|
3213
|
-
}
|
|
3214
|
-
return result;
|
|
3215
|
-
}
|
|
3216
3064
|
async function approveAndRun(ctx, command, cwd, explanation) {
|
|
3217
3065
|
const decision = await ctx.shell.approve({ command, cwd, explanation });
|
|
3218
3066
|
if (decision === "reject") {
|
|
@@ -3223,16 +3071,16 @@ async function approveAndRun(ctx, command, cwd, explanation) {
|
|
|
3223
3071
|
return runAndRecord(ctx, command, cwd);
|
|
3224
3072
|
}
|
|
3225
3073
|
function runShellTool(ctx, createModel = defaultCreateModel) {
|
|
3226
|
-
return
|
|
3074
|
+
return tool8({
|
|
3227
3075
|
description: "Run a shell command in the project. Use this for anything the project needs done in its own ecosystem: installing dependencies, running a script you wrote, running the project's lint/typecheck/test commands. Do not use this to find or read files \u2014 use listFiles, searchFiles, and readFile instead of shell file-listing, reading, or search commands (ls/find/tree/cat/head/tail/grep/rg and similar). This tool refuses all of those outright: the dedicated tools enforce the project-root boundary and secret redaction that a raw shell read would bypass, and they won't count against this tool's command budget. The user approves any command that could change the project before it runs, so write a clear `explanation`. A command judged read-only (inspection, or running tests/typecheck/lint without an autofix flag, in any language) runs immediately without approval. If the user rejects a command, do not retry it \u2014 propose a different approach.",
|
|
3228
|
-
inputSchema:
|
|
3229
|
-
command:
|
|
3076
|
+
inputSchema: z15.object({
|
|
3077
|
+
command: z15.string().describe(
|
|
3230
3078
|
"The command to run, exactly as it would be typed in a shell. Pipes, && and redirects are allowed."
|
|
3231
3079
|
),
|
|
3232
|
-
cwd:
|
|
3080
|
+
cwd: z15.string().optional().describe(
|
|
3233
3081
|
"Directory to run in, relative to the project root. Defaults to the project root."
|
|
3234
3082
|
),
|
|
3235
|
-
explanation:
|
|
3083
|
+
explanation: z15.string().describe(
|
|
3236
3084
|
"One short line telling the user what this command does and why, including any side effect (e.g. writes records to Algolia). This is what they approve against."
|
|
3237
3085
|
)
|
|
3238
3086
|
}),
|
|
@@ -3241,22 +3089,16 @@ function runShellTool(ctx, createModel = defaultCreateModel) {
|
|
|
3241
3089
|
return `Refused: command limit (${ctx.limits.shell}) reached. Stop running commands and report what you have.`;
|
|
3242
3090
|
}
|
|
3243
3091
|
const resolved2 = resolveInRoot(ctx, cwd ?? ".");
|
|
3244
|
-
if (resolved2.ok
|
|
3092
|
+
if (!resolved2.ok) return resolved2.error;
|
|
3245
3093
|
if (isFileIOCommand(command)) {
|
|
3246
3094
|
return "Refused: use listFiles or searchFiles to find files, and readFile to read one, instead of a shell file-listing, reading, or search command (ls/find/fd/tree/dir/locate/cat/head/tail/less/more/tac/nl/grep/egrep/fgrep/rg/ack/ag/xxd/hexdump/od/strings).";
|
|
3247
3095
|
}
|
|
3248
3096
|
logger.info({ command, cwd: resolved2.target }, "called runShell tool");
|
|
3249
|
-
const reviewed = await serializePrompt(
|
|
3250
|
-
() => runReviewedCommand(ctx, command, resolved2.target)
|
|
3251
|
-
);
|
|
3252
|
-
if (reviewed !== void 0) return reviewed;
|
|
3253
3097
|
const fast = fastPathSafety(command);
|
|
3254
3098
|
let isSafe = fast;
|
|
3255
|
-
let usedStoredApproval = false;
|
|
3256
3099
|
if (isSafe === void 0) {
|
|
3257
3100
|
const store = useWizard.getState();
|
|
3258
|
-
|
|
3259
|
-
isSafe = usedStoredApproval;
|
|
3101
|
+
isSafe = store.isCommandApproved(command, resolved2.target);
|
|
3260
3102
|
if (!isSafe) {
|
|
3261
3103
|
isSafe = await classifyCommandSafety(
|
|
3262
3104
|
createModel,
|
|
@@ -3267,18 +3109,54 @@ function runShellTool(ctx, createModel = defaultCreateModel) {
|
|
|
3267
3109
|
);
|
|
3268
3110
|
}
|
|
3269
3111
|
}
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
ctx,
|
|
3273
|
-
command,
|
|
3274
|
-
resolved2.target
|
|
3112
|
+
if (isSafe) {
|
|
3113
|
+
return serializePrompt(
|
|
3114
|
+
() => runAndRecord(ctx, command, resolved2.target)
|
|
3275
3115
|
);
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3116
|
+
}
|
|
3117
|
+
return serializePrompt(
|
|
3118
|
+
() => approveAndRun(ctx, command, resolved2.target, explanation)
|
|
3119
|
+
);
|
|
3120
|
+
}
|
|
3121
|
+
});
|
|
3122
|
+
}
|
|
3123
|
+
|
|
3124
|
+
// src/lib/tools/reviewScript.ts
|
|
3125
|
+
import { tool as tool9 } from "ai";
|
|
3126
|
+
import z16 from "zod";
|
|
3127
|
+
import { stat as stat2 } from "node:fs/promises";
|
|
3128
|
+
import { relative as relative5 } from "node:path";
|
|
3129
|
+
function reviewScriptTool(ctx) {
|
|
3130
|
+
return tool9({
|
|
3131
|
+
description: "Call this as soon as the ingestion script is finished and before you run it, so the user can review it.It shows the file path and returns once they have confirmed reviewing it.",
|
|
3132
|
+
inputSchema: z16.object({
|
|
3133
|
+
filePath: z16.string().describe(
|
|
3134
|
+
"Path to the script to review, relative to the project root."
|
|
3135
|
+
)
|
|
3136
|
+
}),
|
|
3137
|
+
execute: async ({ filePath }) => {
|
|
3138
|
+
logger.info({ filePath }, "called reviewScript tool");
|
|
3139
|
+
const resolved2 = resolveInRoot(ctx, filePath);
|
|
3140
|
+
if (resolved2.ok === false) return resolved2.error;
|
|
3141
|
+
const isFile = await stat2(resolved2.target).then(
|
|
3142
|
+
(s) => s.isFile(),
|
|
3143
|
+
() => false
|
|
3144
|
+
);
|
|
3145
|
+
if (!isFile) {
|
|
3146
|
+
return `Refused: ${filePath} is not a file. Write the script first, then review the path you wrote.`;
|
|
3147
|
+
}
|
|
3148
|
+
return serializePrompt(async () => {
|
|
3149
|
+
await useWizard.getState().requestUserInput({
|
|
3150
|
+
prompt: "",
|
|
3151
|
+
promptType: "enterToContinue",
|
|
3152
|
+
options: [],
|
|
3153
|
+
messages: [
|
|
3154
|
+
`Please review ${relative5(ctx.root, resolved2.target)} before it runs:`,
|
|
3155
|
+
resolved2.target
|
|
3156
|
+
]
|
|
3157
|
+
});
|
|
3158
|
+
ctx.reviewed.push(resolved2.target);
|
|
3159
|
+
return "The user has reviewed the script. You may run it now.";
|
|
3282
3160
|
});
|
|
3283
3161
|
}
|
|
3284
3162
|
});
|
|
@@ -3773,7 +3651,7 @@ async function runAnalysis(mode, extraInstructions = []) {
|
|
|
3773
3651
|
// package.json
|
|
3774
3652
|
var package_default = {
|
|
3775
3653
|
name: "@algolia/wizard",
|
|
3776
|
-
version: "0.52.0-rc.
|
|
3654
|
+
version: "0.52.0-rc.151.365",
|
|
3777
3655
|
description: "Magically implement Algolia functionality in your codebase",
|
|
3778
3656
|
type: "module",
|
|
3779
3657
|
engines: {
|
|
@@ -4475,8 +4353,8 @@ function ingestionInstructions(input) {
|
|
|
4475
4353
|
...algoliaClientDoc(input),
|
|
4476
4354
|
"Install the Algolia client with the project's own package manager via runShell, declaring it in whatever manifest the project uses (e.g. package.json, requirements.txt, Gemfile, go.mod, composer.json) so the dependency is not just installed ad hoc.",
|
|
4477
4355
|
`If the script loads its env vars from a file (e.g. via dotenv or an equivalent for its language) rather than the process environment directly, decide that up front and call writeCredentials on that file before you finish the script \u2014 do not wait to discover the need for it by having a writeFile call refused.`,
|
|
4478
|
-
|
|
4479
|
-
'Then
|
|
4356
|
+
"When the script is finished, call reviewScript with its path and wait: running it writes records to a live index, so the developer reads it first. Do not run it before that call returns.",
|
|
4357
|
+
'Then run the script yourself via runShell, and report the command you ran as "ingestCommand" so the developer can re-run it. Its explanation must say that running it writes records to Algolia.',
|
|
4480
4358
|
"The summary should be extremely concise.",
|
|
4481
4359
|
...sourceSpecificInstructions(input)
|
|
4482
4360
|
] : []
|
|
@@ -4856,33 +4734,19 @@ ${detail}` : ""}`
|
|
|
4856
4734
|
product_area: "AI Wizard"
|
|
4857
4735
|
});
|
|
4858
4736
|
}
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
}
|
|
4872
|
-
const commandMessages = ingestCommand ? [`Ingestion command: ${ingestCommand}`] : [];
|
|
4873
|
-
await ctx.requestUserInput({
|
|
4874
|
-
prompt: "",
|
|
4875
|
-
promptType: "enterToContinue",
|
|
4876
|
-
options: [],
|
|
4877
|
-
// One message per line: Notices.tsx counts a message as one wrapped
|
|
4878
|
-
// line, so an embedded newline overflows the panel's height accounting.
|
|
4879
|
-
messages: [
|
|
4880
|
-
ingestOutcomeMessage,
|
|
4881
|
-
...ingestFailureDetail?.split("\n").filter((l) => l.trim()) ?? [],
|
|
4882
|
-
...commandMessages
|
|
4883
|
-
]
|
|
4884
|
-
});
|
|
4885
|
-
}
|
|
4737
|
+
const commandMessages = ingestCommand ? [`Ingestion command: ${ingestCommand}`] : [];
|
|
4738
|
+
await ctx.requestUserInput({
|
|
4739
|
+
prompt: "",
|
|
4740
|
+
promptType: "enterToContinue",
|
|
4741
|
+
options: [],
|
|
4742
|
+
// One message per line: Notices.tsx counts a message as one wrapped
|
|
4743
|
+
// line, so an embedded newline overflows the panel's height accounting.
|
|
4744
|
+
messages: [
|
|
4745
|
+
ingestOutcomeMessage,
|
|
4746
|
+
...ingestFailureDetail?.split("\n").filter((l) => l.trim()) ?? [],
|
|
4747
|
+
...commandMessages
|
|
4748
|
+
]
|
|
4749
|
+
});
|
|
4886
4750
|
}
|
|
4887
4751
|
let searchConfigFile;
|
|
4888
4752
|
if (useCases.includes("search")) {
|
|
@@ -6240,7 +6104,7 @@ function App() {
|
|
|
6240
6104
|
}
|
|
6241
6105
|
|
|
6242
6106
|
// src/lib/envAppId.ts
|
|
6243
|
-
import { readFile as
|
|
6107
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
6244
6108
|
import { join as join12 } from "node:path";
|
|
6245
6109
|
var ENV_FILES = [".env", ".env.local"];
|
|
6246
6110
|
var APP_ID_LINE = /^[ \t]*(?:export[ \t]+)?([A-Z0-9_]*ALGOLIA_APP(?:LICATION)?_ID)[ \t]*=[ \t]*(.*)$/gm;
|
|
@@ -6248,7 +6112,7 @@ async function findEnvApplicationId(root = process.cwd()) {
|
|
|
6248
6112
|
for (const file of ENV_FILES) {
|
|
6249
6113
|
let content;
|
|
6250
6114
|
try {
|
|
6251
|
-
content = await
|
|
6115
|
+
content = await readFile7(join12(root, file), "utf8");
|
|
6252
6116
|
} catch (err) {
|
|
6253
6117
|
if (err.code !== "ENOENT") {
|
|
6254
6118
|
logger.warn(
|
|
@@ -6598,8 +6462,118 @@ function delay(ms) {
|
|
|
6598
6462
|
});
|
|
6599
6463
|
}
|
|
6600
6464
|
|
|
6465
|
+
// package.json with { type: 'json' }
|
|
6466
|
+
var package_default2 = {
|
|
6467
|
+
name: "@algolia/wizard",
|
|
6468
|
+
version: "0.52.0-rc.151.365",
|
|
6469
|
+
description: "Magically implement Algolia functionality in your codebase",
|
|
6470
|
+
type: "module",
|
|
6471
|
+
engines: {
|
|
6472
|
+
node: ">=24"
|
|
6473
|
+
},
|
|
6474
|
+
bin: {
|
|
6475
|
+
wizard: "dist/main.js"
|
|
6476
|
+
},
|
|
6477
|
+
files: [
|
|
6478
|
+
"dist",
|
|
6479
|
+
"docs"
|
|
6480
|
+
],
|
|
6481
|
+
scripts: {
|
|
6482
|
+
"build:proxy": "node scripts/build.mjs proxy",
|
|
6483
|
+
build: "node scripts/build.mjs",
|
|
6484
|
+
"dev:proxy": "touch .env && NODE_OPTIONS=--use-system-ca tsx watch --env-file=.env src/proxy/index.ts",
|
|
6485
|
+
dev: "touch .env && tsx --env-file=.env ./src/main.tsx",
|
|
6486
|
+
"env:load": "pnpm exec -- varlock load",
|
|
6487
|
+
prepare: "husky",
|
|
6488
|
+
prepublishOnly: "pnpm build",
|
|
6489
|
+
reset: "tsx ./scripts/reset-state.ts",
|
|
6490
|
+
"test:fixtures": "touch .env && tsx --env-file=.env ./fixtures/run-fixtures.ts",
|
|
6491
|
+
"test:tools": "tsx ./tool-evals/toolEval.ts",
|
|
6492
|
+
"test:tools:improve": "tsx ./tool-evals/improveFromPlan.ts",
|
|
6493
|
+
test: "vitest",
|
|
6494
|
+
typecheck: "tsc --noEmit -p tsconfig.json"
|
|
6495
|
+
},
|
|
6496
|
+
keywords: [],
|
|
6497
|
+
author: "",
|
|
6498
|
+
license: "ISC",
|
|
6499
|
+
packageManager: "pnpm@11.9.0+sha512.bd682d5d03fe525ef7c9fd6780c6884d1e756ac4c9c9fe00c538782824310dcf90e3ddc4f53835f06dfaebd5085e41855e0bcbb3b60de2ac5bbab89e5036f03b",
|
|
6500
|
+
devDependencies: {
|
|
6501
|
+
"@clack/prompts": "^1.6.0",
|
|
6502
|
+
"@types/ioredis-mock": "^8.2.7",
|
|
6503
|
+
"@types/node": "^25.9.1",
|
|
6504
|
+
"@types/react": "^19.2.16",
|
|
6505
|
+
esbuild: "^0.28.0",
|
|
6506
|
+
husky: "^9.1.7",
|
|
6507
|
+
"ink-testing-library": "^4.0.0",
|
|
6508
|
+
"ioredis-mock": "^8.13.1",
|
|
6509
|
+
"lint-staged": "^17.0.8",
|
|
6510
|
+
tsx: "^4.22.3",
|
|
6511
|
+
typescript: "^6.0.3",
|
|
6512
|
+
vitest: "^4.1.8"
|
|
6513
|
+
},
|
|
6514
|
+
dependencies: {
|
|
6515
|
+
"@ai-sdk/anthropic": "^3.0.81",
|
|
6516
|
+
"@ai-sdk/openai-compatible": "^2.0.47",
|
|
6517
|
+
"@hono/node-server": "^2.0.10",
|
|
6518
|
+
"@segment/analytics-node": "^3.1.0",
|
|
6519
|
+
ai: "^6.0.190",
|
|
6520
|
+
"cross-keychain": "^1.1.0",
|
|
6521
|
+
dotenv: "^17.4.2",
|
|
6522
|
+
hono: "^4.12.27",
|
|
6523
|
+
ink: "^7.0.5",
|
|
6524
|
+
"ink-picture": "^2.1.0",
|
|
6525
|
+
"ink-spinner": "^5.0.0",
|
|
6526
|
+
ioredis: "^5.11.1",
|
|
6527
|
+
nanoid: "^5.1.15",
|
|
6528
|
+
pino: "^10.3.1",
|
|
6529
|
+
react: "^19.2.7",
|
|
6530
|
+
"terminal-link": "^5.0.0",
|
|
6531
|
+
varlock: "^1.5.1",
|
|
6532
|
+
zod: "^4.4.3",
|
|
6533
|
+
zustand: "^5.0.14"
|
|
6534
|
+
}
|
|
6535
|
+
};
|
|
6536
|
+
|
|
6537
|
+
// src/lib/checkVersion.ts
|
|
6538
|
+
function parseVersion(version) {
|
|
6539
|
+
const [major = 0, minor = 0, patch = 0] = version.split("-")[0].split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
6540
|
+
return [major, minor, patch];
|
|
6541
|
+
}
|
|
6542
|
+
function isOlder(local, remote) {
|
|
6543
|
+
const a = parseVersion(local);
|
|
6544
|
+
const b = parseVersion(remote);
|
|
6545
|
+
for (let i = 0; i < 3; i++) {
|
|
6546
|
+
if (a[i] !== b[i]) return a[i] < b[i];
|
|
6547
|
+
}
|
|
6548
|
+
return false;
|
|
6549
|
+
}
|
|
6550
|
+
async function checkVersion() {
|
|
6551
|
+
try {
|
|
6552
|
+
const res = await fetch(
|
|
6553
|
+
"https://registry.npmjs.org/@algolia/wizard/latest",
|
|
6554
|
+
{ signal: AbortSignal.timeout(3e3) }
|
|
6555
|
+
);
|
|
6556
|
+
if (!res.ok) {
|
|
6557
|
+
throw Error(`npmjs registry responded ${res.status}`);
|
|
6558
|
+
}
|
|
6559
|
+
const { version } = await res.json();
|
|
6560
|
+
if (typeof version !== "string") {
|
|
6561
|
+
throw Error("npmjs registry returned no version");
|
|
6562
|
+
}
|
|
6563
|
+
return isOlder(package_default2.version, version);
|
|
6564
|
+
} catch {
|
|
6565
|
+
logger.error("Could not resolve remote version number from npmjs registry");
|
|
6566
|
+
return false;
|
|
6567
|
+
}
|
|
6568
|
+
}
|
|
6569
|
+
|
|
6601
6570
|
// src/main.tsx
|
|
6602
6571
|
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
6572
|
+
async function exitProcessWithError(store, instance, message) {
|
|
6573
|
+
store.setError(message);
|
|
6574
|
+
await instance.waitUntilExit();
|
|
6575
|
+
process.exit(1);
|
|
6576
|
+
}
|
|
6603
6577
|
async function startup() {
|
|
6604
6578
|
setProjectRoot(process.cwd());
|
|
6605
6579
|
let args;
|
|
@@ -6652,6 +6626,14 @@ async function run(opts) {
|
|
|
6652
6626
|
const store = useWizard.getState();
|
|
6653
6627
|
const instance = render(/* @__PURE__ */ jsx20(App, {}), { incrementalRendering: true });
|
|
6654
6628
|
await store.waitForStart();
|
|
6629
|
+
const wizardOutdated = await checkVersion();
|
|
6630
|
+
if (wizardOutdated) {
|
|
6631
|
+
await exitProcessWithError(
|
|
6632
|
+
store,
|
|
6633
|
+
instance,
|
|
6634
|
+
"You have loaded an old version of the Wizard. Please use @algolia/wizard@latest"
|
|
6635
|
+
);
|
|
6636
|
+
}
|
|
6655
6637
|
store.syncSteps(
|
|
6656
6638
|
workflow.steps.map((s) => ({
|
|
6657
6639
|
id: s.id,
|
|
@@ -6667,18 +6649,20 @@ async function run(opts) {
|
|
|
6667
6649
|
try {
|
|
6668
6650
|
await runAuthLogin();
|
|
6669
6651
|
} catch (err) {
|
|
6670
|
-
|
|
6671
|
-
|
|
6672
|
-
|
|
6652
|
+
await exitProcessWithError(
|
|
6653
|
+
store,
|
|
6654
|
+
instance,
|
|
6655
|
+
err instanceof Error ? err.message : String(err)
|
|
6656
|
+
);
|
|
6673
6657
|
}
|
|
6674
6658
|
store.endAuth();
|
|
6675
6659
|
user = await getUser();
|
|
6676
6660
|
if (!user) {
|
|
6677
|
-
|
|
6661
|
+
await exitProcessWithError(
|
|
6662
|
+
store,
|
|
6663
|
+
instance,
|
|
6678
6664
|
"Authentication completed but no Algolia user was returned. Try running `npx @algolia/cli@latest auth login` directly."
|
|
6679
6665
|
);
|
|
6680
|
-
await instance.waitUntilExit();
|
|
6681
|
-
process.exit(1);
|
|
6682
6666
|
}
|
|
6683
6667
|
}
|
|
6684
6668
|
store.setUser(user);
|
|
@@ -6688,12 +6672,14 @@ async function run(opts) {
|
|
|
6688
6672
|
app = await ensureApplication(
|
|
6689
6673
|
resumableState ? runAppId(resumableState) : void 0
|
|
6690
6674
|
);
|
|
6675
|
+
runWorkflow(workflow, app.id, { skipResumePrompt, resumableState });
|
|
6691
6676
|
} catch (err) {
|
|
6692
|
-
|
|
6693
|
-
|
|
6694
|
-
|
|
6677
|
+
await exitProcessWithError(
|
|
6678
|
+
store,
|
|
6679
|
+
instance,
|
|
6680
|
+
err instanceof Error ? err.message : String(err)
|
|
6681
|
+
);
|
|
6695
6682
|
}
|
|
6696
|
-
runWorkflow(workflow, app.id, { skipResumePrompt, resumableState });
|
|
6697
6683
|
}
|
|
6698
6684
|
await requestTerminalSize();
|
|
6699
6685
|
var started = await startup();
|