@algolia/wizard 0.33.0-rc.126.240 → 0.33.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.
- package/dist/main.js +35 -222
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -253,7 +253,6 @@ var useWizard = create((set, get) => ({
|
|
|
253
253
|
cliOutput: [],
|
|
254
254
|
targetIndex: null,
|
|
255
255
|
writtenFiles: [],
|
|
256
|
-
approvedCommands: /* @__PURE__ */ new Set(),
|
|
257
256
|
logs: [],
|
|
258
257
|
error: null,
|
|
259
258
|
inputReq: null,
|
|
@@ -349,10 +348,6 @@ var useWizard = create((set, get) => ({
|
|
|
349
348
|
setTargetIndex: (index) => set({ targetIndex: index }),
|
|
350
349
|
recordWrittenFile: (path) => set((s) => ({ writtenFiles: [...s.writtenFiles, path] })),
|
|
351
350
|
clearWrittenFiles: () => set({ writtenFiles: [] }),
|
|
352
|
-
isCommandApproved: (command, cwd) => get().approvedCommands.has(`${cwd}\0${command}`),
|
|
353
|
-
approveCommand: (command, cwd) => set((s) => ({
|
|
354
|
-
approvedCommands: new Set(s.approvedCommands).add(`${cwd}\0${command}`)
|
|
355
|
-
})),
|
|
356
351
|
logStart: (kind, name, input) => {
|
|
357
352
|
const id = nanoid();
|
|
358
353
|
set((s) => ({
|
|
@@ -401,7 +396,6 @@ var useWizard = create((set, get) => ({
|
|
|
401
396
|
cliOutput: [],
|
|
402
397
|
targetIndex: null,
|
|
403
398
|
writtenFiles: [],
|
|
404
|
-
approvedCommands: /* @__PURE__ */ new Set(),
|
|
405
399
|
logs: [],
|
|
406
400
|
error: null,
|
|
407
401
|
inputReq: null,
|
|
@@ -1026,6 +1020,7 @@ function EnterToContinuePrompt({
|
|
|
1026
1020
|
function PromptInput() {
|
|
1027
1021
|
const { phase, inputReq, submitInput } = useWizard();
|
|
1028
1022
|
const [draft, setDraft] = useState6("");
|
|
1023
|
+
const promptKey = inputReq && `${inputReq.promptType}:${inputReq.prompt}`;
|
|
1029
1024
|
if (phase === "done" || phase === "error") {
|
|
1030
1025
|
return /* @__PURE__ */ jsx7(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text9, { color: "gray", dimColor: true, children: "Press Enter or Esc to exit" }) });
|
|
1031
1026
|
}
|
|
@@ -1044,7 +1039,8 @@ function PromptInput() {
|
|
|
1044
1039
|
cancelable: inputReq.cancelable,
|
|
1045
1040
|
error: inputReq.error,
|
|
1046
1041
|
onSelect: submitInput
|
|
1047
|
-
}
|
|
1042
|
+
},
|
|
1043
|
+
promptKey
|
|
1048
1044
|
) });
|
|
1049
1045
|
}
|
|
1050
1046
|
if (inputReq.promptType === "multiSelect") {
|
|
@@ -1059,7 +1055,8 @@ function PromptInput() {
|
|
|
1059
1055
|
options: inputReq.options,
|
|
1060
1056
|
error: inputReq.error,
|
|
1061
1057
|
onSelect: submitInput
|
|
1062
|
-
}
|
|
1058
|
+
},
|
|
1059
|
+
promptKey
|
|
1063
1060
|
) });
|
|
1064
1061
|
}
|
|
1065
1062
|
if (inputReq.promptType === "notice") {
|
|
@@ -1070,7 +1067,8 @@ function PromptInput() {
|
|
|
1070
1067
|
messages: inputReq.messages,
|
|
1071
1068
|
options: ["Continue"],
|
|
1072
1069
|
onSelect: submitInput
|
|
1073
|
-
}
|
|
1070
|
+
},
|
|
1071
|
+
promptKey
|
|
1074
1072
|
) });
|
|
1075
1073
|
}
|
|
1076
1074
|
if (inputReq.promptType === "enterToContinue") {
|
|
@@ -1096,7 +1094,8 @@ function PromptInput() {
|
|
|
1096
1094
|
options: labels,
|
|
1097
1095
|
secondary: inputReq.secondary,
|
|
1098
1096
|
onSelect: (value) => submitInput(value === labels[0])
|
|
1099
|
-
}
|
|
1097
|
+
},
|
|
1098
|
+
promptKey
|
|
1100
1099
|
) });
|
|
1101
1100
|
}
|
|
1102
1101
|
return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "column", children: [
|
|
@@ -2716,8 +2715,8 @@ var selectIndexStep = async (ctx) => {
|
|
|
2716
2715
|
};
|
|
2717
2716
|
|
|
2718
2717
|
// src/lib/agent.ts
|
|
2719
|
-
import { ToolLoopAgent, hasToolCall, Output as
|
|
2720
|
-
import { createAnthropic as
|
|
2718
|
+
import { ToolLoopAgent, hasToolCall, Output as Output2 } from "ai";
|
|
2719
|
+
import { createAnthropic as createAnthropic2 } from "@ai-sdk/anthropic";
|
|
2721
2720
|
import "zod";
|
|
2722
2721
|
|
|
2723
2722
|
// src/lib/tools/index.ts
|
|
@@ -3399,8 +3398,7 @@ function searchFilesTool(ctx) {
|
|
|
3399
3398
|
}
|
|
3400
3399
|
|
|
3401
3400
|
// src/lib/tools/runShell.ts
|
|
3402
|
-
import { tool as tool8
|
|
3403
|
-
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
3401
|
+
import { tool as tool8 } from "ai";
|
|
3404
3402
|
import z15 from "zod";
|
|
3405
3403
|
import { relative as relative4 } from "node:path";
|
|
3406
3404
|
|
|
@@ -3509,10 +3507,8 @@ function runShell(command, opts) {
|
|
|
3509
3507
|
// src/lib/tools/runShell.ts
|
|
3510
3508
|
function storeApproval(root) {
|
|
3511
3509
|
return async (req) => {
|
|
3512
|
-
const store = useWizard.getState();
|
|
3513
|
-
if (store.isCommandApproved(req.command, req.cwd)) return "approve";
|
|
3514
3510
|
const rel = relative4(root, req.cwd);
|
|
3515
|
-
const answer = await
|
|
3511
|
+
const answer = await useWizard.getState().requestUserInput({
|
|
3516
3512
|
prompt: "Run this command?",
|
|
3517
3513
|
promptType: "commandApproval",
|
|
3518
3514
|
options: [],
|
|
@@ -3521,170 +3517,20 @@ function storeApproval(root) {
|
|
|
3521
3517
|
cwd: rel === "" || rel.startsWith("..") ? req.cwd : rel
|
|
3522
3518
|
}
|
|
3523
3519
|
});
|
|
3524
|
-
|
|
3525
|
-
store.approveCommand(req.command, req.cwd);
|
|
3526
|
-
return "approve";
|
|
3520
|
+
return answer === "approve" ? "approve" : "reject";
|
|
3527
3521
|
};
|
|
3528
3522
|
}
|
|
3529
3523
|
var EXPLORATORY_COMMANDS = /* @__PURE__ */ new Set(["ls", "find", "tree", "dir"]);
|
|
3530
|
-
function commandSegments(command) {
|
|
3531
|
-
return command.split(/&&|;|\|/).map((segment) => segment.trim());
|
|
3532
|
-
}
|
|
3533
3524
|
function isExploratoryCommand(command) {
|
|
3534
|
-
return
|
|
3535
|
-
}
|
|
3536
|
-
var READ_ONLY_BINARIES = /* @__PURE__ */ new Set([
|
|
3537
|
-
"cat",
|
|
3538
|
-
"head",
|
|
3539
|
-
"tail",
|
|
3540
|
-
"wc",
|
|
3541
|
-
"pwd",
|
|
3542
|
-
"echo",
|
|
3543
|
-
"date",
|
|
3544
|
-
"whoami",
|
|
3545
|
-
"hostname",
|
|
3546
|
-
"uname",
|
|
3547
|
-
"which",
|
|
3548
|
-
"file",
|
|
3549
|
-
"stat",
|
|
3550
|
-
"grep",
|
|
3551
|
-
"egrep",
|
|
3552
|
-
"fgrep",
|
|
3553
|
-
"rg",
|
|
3554
|
-
"diff"
|
|
3555
|
-
]);
|
|
3556
|
-
var READ_ONLY_NO_ARGS_BINARIES = /* @__PURE__ */ new Set(["env", "printenv"]);
|
|
3557
|
-
var GIT_READ_ONLY_SUBCOMMANDS = /* @__PURE__ */ new Set([
|
|
3558
|
-
"status",
|
|
3559
|
-
"log",
|
|
3560
|
-
"diff",
|
|
3561
|
-
"show",
|
|
3562
|
-
"describe",
|
|
3563
|
-
"blame",
|
|
3564
|
-
"ls-files",
|
|
3565
|
-
"rev-parse",
|
|
3566
|
-
"cat-file",
|
|
3567
|
-
"shortlog",
|
|
3568
|
-
"ls-remote"
|
|
3569
|
-
]);
|
|
3570
|
-
var VERSION_CHECK_BINARIES = /* @__PURE__ */ new Set([
|
|
3571
|
-
"node",
|
|
3572
|
-
"tsc",
|
|
3573
|
-
"npm",
|
|
3574
|
-
"pnpm",
|
|
3575
|
-
"yarn",
|
|
3576
|
-
"python",
|
|
3577
|
-
"python3",
|
|
3578
|
-
"ruby",
|
|
3579
|
-
"go",
|
|
3580
|
-
"cargo",
|
|
3581
|
-
"rustc",
|
|
3582
|
-
"php",
|
|
3583
|
-
"composer",
|
|
3584
|
-
"java",
|
|
3585
|
-
"mvn",
|
|
3586
|
-
"gradle",
|
|
3587
|
-
"bundle",
|
|
3588
|
-
"git"
|
|
3589
|
-
]);
|
|
3590
|
-
var VERSION_FLAGS = /* @__PURE__ */ new Set(["--version", "-v", "-V"]);
|
|
3591
|
-
function hasFileRedirect(segment) {
|
|
3592
|
-
return segment.replace(/\d>&\d/g, "").includes(">");
|
|
3593
|
-
}
|
|
3594
|
-
function hasShellInjectionRisk(segment) {
|
|
3595
|
-
if (segment.includes("$(") || segment.includes("<(") || segment.includes("`")) {
|
|
3596
|
-
return true;
|
|
3597
|
-
}
|
|
3598
|
-
return segment.replace(/\d>&\d/g, "").includes("&");
|
|
3599
|
-
}
|
|
3600
|
-
function fastPathSegmentSafety(segment) {
|
|
3601
|
-
if (!segment) return true;
|
|
3602
|
-
if (hasFileRedirect(segment)) return false;
|
|
3603
|
-
if (hasShellInjectionRisk(segment)) return false;
|
|
3604
|
-
const [cmd0, ...rest] = segment.split(/\s+/);
|
|
3605
|
-
if (cmd0 === void 0) return true;
|
|
3606
|
-
if (VERSION_CHECK_BINARIES.has(cmd0) && rest.length === 1 && VERSION_FLAGS.has(rest[0])) {
|
|
3607
|
-
return true;
|
|
3608
|
-
}
|
|
3609
|
-
if (READ_ONLY_BINARIES.has(cmd0)) return true;
|
|
3610
|
-
if (READ_ONLY_NO_ARGS_BINARIES.has(cmd0)) {
|
|
3611
|
-
return rest.length === 0 ? true : void 0;
|
|
3612
|
-
}
|
|
3613
|
-
if (cmd0 === "git") {
|
|
3614
|
-
return GIT_READ_ONLY_SUBCOMMANDS.has(rest[0] ?? "") ? true : void 0;
|
|
3615
|
-
}
|
|
3616
|
-
return void 0;
|
|
3617
|
-
}
|
|
3618
|
-
function fastPathSafety(command) {
|
|
3619
|
-
const results = commandSegments(command).map(fastPathSegmentSafety);
|
|
3620
|
-
if (results.some((r) => r === false)) return false;
|
|
3621
|
-
if (results.every((r) => r === true)) return true;
|
|
3622
|
-
return void 0;
|
|
3623
|
-
}
|
|
3624
|
-
var CLASSIFIER_MODEL = "claude-haiku-4-5";
|
|
3625
|
-
var commandSafetySchema = z15.object({
|
|
3626
|
-
safe: z15.boolean(),
|
|
3627
|
-
reason: z15.string().describe("One short sentence explaining the verdict.")
|
|
3628
|
-
});
|
|
3629
|
-
function defaultCreateModel() {
|
|
3630
|
-
const token = getAuthToken();
|
|
3631
|
-
if (!token) {
|
|
3632
|
-
throw new Error("Not authenticated: no user token available");
|
|
3633
|
-
}
|
|
3634
|
-
return createAnthropic({
|
|
3635
|
-
apiKey: token,
|
|
3636
|
-
baseURL: PROXY_BASE_URL,
|
|
3637
|
-
fetch: proxyFetch
|
|
3638
|
-
});
|
|
3639
|
-
}
|
|
3640
|
-
function approvedCommandHistory(approvedCommands) {
|
|
3641
|
-
return Array.from(approvedCommands).map((entry) => {
|
|
3642
|
-
const sep2 = entry.indexOf("\0");
|
|
3643
|
-
return { cwd: entry.slice(0, sep2), command: entry.slice(sep2 + 1) };
|
|
3644
|
-
});
|
|
3525
|
+
return command.split(/&&|;|\|/).map((segment) => segment.trim().split(/\s+/)[0]).some((word) => word !== void 0 && EXPLORATORY_COMMANDS.has(word));
|
|
3645
3526
|
}
|
|
3646
|
-
async function
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
output: Output.object({ schema: commandSafetySchema }),
|
|
3653
|
-
prompt: [
|
|
3654
|
-
"A coding agent wants to run this shell command in a user's project without asking for approval first. The command may be in any programming language or ecosystem.",
|
|
3655
|
-
"Judge it SAFE only if it cannot modify, delete, move, rename, or install anything the project cares about, cannot push/publish/deploy/commit anything, and cannot make a network request that changes remote state.",
|
|
3656
|
-
"Three broad categories are safe, and most commands you will see fall into one of them:",
|
|
3657
|
-
"(1) Reporting or listing existing state, with no side effect \u2014 e.g. `git status`, `npm ls`, `npm outdated`, `pip show`, `pip freeze`, `cargo tree`, `docker ps`, `docker images`, `kubectl get pods`, `terraform state list`. This includes a read-only GET-style query to a remote registry or API that only fetches public metadata and changes nothing remote (e.g. `npm view <package>`, `pip index versions <package>`, `curl` with no -X/--request other than GET and no -d/--data) \u2014 safe because nothing changes, not because it stays local.",
|
|
3658
|
-
'(2) A "preview" or "check" mode that reports what a change WOULD do, or reports a problem, without making the change. This is a general pattern, not a fixed list \u2014 ANY command that takes a dry-run/check/plan/validate/diff/list-only flag is safe when that flag is present, regardless of whether the same flag would normally appear on a "safe" kind of command: `terraform plan`, `terraform validate`, `terraform fmt -check`, `black --check`, `prettier --check`, `isort --check`, `gofmt -l` (list-only), `stylelint` with no `--fix`, and equally `git push --dry-run`, `npm publish --dry-run`, `kubectl apply --dry-run=client` \u2014 these last three are otherwise-unsafe operations (push, publish, cluster changes) that the dry-run flag turns into a report. The corresponding command WITHOUT that flag (e.g. `terraform apply`, `black .`, `gofmt -w`, `git push`) is a different, unsafe command \u2014 the flag is what makes the difference, for any tool, not just the ones named here. This cuts both ways, so do not assume a bare invocation is the safe one: `cargo fmt`, `black`, `prettier`, `isort`, `rustfmt`, and `terraform fmt` all REWRITE FILES by default and need an explicit check/diff/dry-run flag to become safe, while `gofmt`, `eslint`, `stylelint`, `rubocop`, and `ruff check` default to a safe check-only mode and need an explicit fix/write flag to become unsafe \u2014 the same-looking bare command is safe for one group and unsafe for the other, so judge each by what its own flags actually say, not by resemblance to a tool you already judged.',
|
|
3659
|
-
"(3) Running the project's own tests, type checker, linter, or build/compile step (e.g. `npm run build`, `yarn build`, `vite build`, `webpack`, `tsc`, `cargo build`, `go build`, `mvn compile`), as long as it is not passed an autofix/write/update flag (e.g. --fix, -u, --write, rubocop -a) \u2014 this holds even though the point of a build step is to write compiled output to a build/dist/target directory inside the project (e.g. a target/, build/, dist/, or __pycache__ directory): writing that output does not make the command unsafe. It stops being safe the moment the command chain goes past building \u2014 a step that also deploys, publishes, uploads, or pushes the build (e.g. `next build && vercel deploy`, `npm run build && npm publish`) is unsafe for that later segment even though the build segment itself is fine; judge each chained segment on its own, same as elsewhere in this list.",
|
|
3660
|
-
"Deleting or removing anything is unsafe, even something in a cache or build directory (e.g. `rm -rf __pycache__`, `cargo clean`, `git clean`), and even if the command otherwise fits one of the three categories above. Installing, uninstalling, or upgrading a dependency, changing a database schema, or writing to a path outside the project is also unsafe. A command chained with && or ; is only safe if every part of the chain is safe on its own.",
|
|
3661
|
-
"One specific, narrow exception to all of the above: when the command literally invokes one of these runner programs BY NAME as the leading command \u2014 npx, bunx, pnpm dlx, yarn dlx, pipx run, uvx \u2014 it is unsafe regardless of what it then runs, even something that looks like a harmless test/lint/typecheck command (e.g. `npx tsc --noEmit`, `uvx ruff check .`), because that runner can fetch and execute a different, unreviewed version of a package from a registry each time. This exception is about that specific syntax, not a general doubt about whether a tool is installed: a plain `ruff check .`, `pytest`, or any other bare command name is NOT this exception merely because you cannot verify from the string alone that it is installed \u2014 judge those the same as any other already-installed project tool, per the categories above. If you are unsure, judge it unsafe.",
|
|
3662
|
-
...approvedHistory.length > 0 ? [
|
|
3663
|
-
"The user has already explicitly approved these exact commands earlier in this session (working directory in parentheses, then the command):",
|
|
3664
|
-
approvedHistory.map((h) => `- (${h.cwd}) ${h.command}`).join("\n"),
|
|
3665
|
-
"If the new command performs the same action and side-effect profile as one of these \u2014 differing only in a trivial way, such as a different file path, package name, or argument value that does not change what kind of action it is \u2014 judge it SAFE on that precedent, even if it would not otherwise fit categories (1)-(3) above. Do not stretch this to a command that merely shares a binary name, or superficially resembles one on the list while doing something riskier or of a different kind (e.g. an approved `rm build/tmp.log` does not license a new `rm -rf src/`, and an approved `git push origin feature-x` does not license `git push --force`)."
|
|
3666
|
-
] : [],
|
|
3667
|
-
`Command: ${command}`,
|
|
3668
|
-
`Working directory: ${cwd}`,
|
|
3669
|
-
`Stated purpose: ${explanation}`
|
|
3670
|
-
].join("\n")
|
|
3671
|
-
});
|
|
3672
|
-
if (!output.safe) {
|
|
3673
|
-
logger.info(
|
|
3674
|
-
{ command, reason: output.reason },
|
|
3675
|
-
"runShell: classifier judged command unsafe, requiring approval"
|
|
3676
|
-
);
|
|
3677
|
-
}
|
|
3678
|
-
return output.safe;
|
|
3679
|
-
} catch (err) {
|
|
3680
|
-
logger.warn(
|
|
3681
|
-
{ err, command },
|
|
3682
|
-
"runShell: command safety classifier failed, requiring approval"
|
|
3683
|
-
);
|
|
3684
|
-
return false;
|
|
3527
|
+
async function approveAndRun(ctx, command, cwd, explanation) {
|
|
3528
|
+
const decision = await ctx.shell.approve({ command, cwd, explanation });
|
|
3529
|
+
if (decision === "reject") {
|
|
3530
|
+
ctx.shell.executions.push({ command, cwd, approved: false });
|
|
3531
|
+
logger.info({ command }, "runShell: user rejected the command");
|
|
3532
|
+
return "The user rejected this command. Do not retry it. Propose a different command, or report the limitation via reportStatus.";
|
|
3685
3533
|
}
|
|
3686
|
-
}
|
|
3687
|
-
async function runAndRecord(ctx, command, cwd) {
|
|
3688
3534
|
useWizard.getState().pushNotice({ messages: [`Running: ${command}`] });
|
|
3689
3535
|
const env = await ctx.shell.env().catch((err) => {
|
|
3690
3536
|
logger.warn({ err, command }, "runShell: could not resolve command env");
|
|
@@ -3720,18 +3566,9 @@ async function runAndRecord(ctx, command, cwd) {
|
|
|
3720
3566
|
output: run2.output
|
|
3721
3567
|
};
|
|
3722
3568
|
}
|
|
3723
|
-
|
|
3724
|
-
const decision = await ctx.shell.approve({ command, cwd, explanation });
|
|
3725
|
-
if (decision === "reject") {
|
|
3726
|
-
ctx.shell.executions.push({ command, cwd, approved: false });
|
|
3727
|
-
logger.info({ command }, "runShell: user rejected the command");
|
|
3728
|
-
return "The user rejected this command. Do not retry it. Propose a different command, or report the limitation via reportStatus.";
|
|
3729
|
-
}
|
|
3730
|
-
return runAndRecord(ctx, command, cwd);
|
|
3731
|
-
}
|
|
3732
|
-
function runShellTool(ctx, createModel = defaultCreateModel) {
|
|
3569
|
+
function runShellTool(ctx) {
|
|
3733
3570
|
return tool8({
|
|
3734
|
-
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.
|
|
3571
|
+
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. To inspect the project, use listFiles or searchFiles instead of ls/find \u2014 this tool refuses those. The user sees and approves every command before it runs, so write a clear `explanation`. If the user rejects a command, do not retry it \u2014 propose a different approach.",
|
|
3735
3572
|
inputSchema: z15.object({
|
|
3736
3573
|
command: z15.string().describe(
|
|
3737
3574
|
"The command to run, exactly as it would be typed in a shell. Pipes, && and redirects are allowed."
|
|
@@ -3750,29 +3587,9 @@ function runShellTool(ctx, createModel = defaultCreateModel) {
|
|
|
3750
3587
|
const resolved2 = resolveInRoot(ctx, cwd ?? ".");
|
|
3751
3588
|
if (!resolved2.ok) return resolved2.error;
|
|
3752
3589
|
if (isExploratoryCommand(command)) {
|
|
3753
|
-
return "Refused: use listFiles or searchFiles to
|
|
3590
|
+
return "Refused: use listFiles or searchFiles to inspect the project instead of ls/find/tree.";
|
|
3754
3591
|
}
|
|
3755
3592
|
logger.info({ command, cwd: resolved2.target }, "called runShell tool");
|
|
3756
|
-
const fast = fastPathSafety(command);
|
|
3757
|
-
let isSafe = fast;
|
|
3758
|
-
if (isSafe === void 0) {
|
|
3759
|
-
const store = useWizard.getState();
|
|
3760
|
-
isSafe = store.isCommandApproved(command, resolved2.target);
|
|
3761
|
-
if (!isSafe) {
|
|
3762
|
-
isSafe = await classifyCommandSafety(
|
|
3763
|
-
createModel,
|
|
3764
|
-
command,
|
|
3765
|
-
resolved2.target,
|
|
3766
|
-
explanation,
|
|
3767
|
-
approvedCommandHistory(store.approvedCommands)
|
|
3768
|
-
);
|
|
3769
|
-
}
|
|
3770
|
-
}
|
|
3771
|
-
if (isSafe) {
|
|
3772
|
-
return serializePrompt(
|
|
3773
|
-
() => runAndRecord(ctx, command, resolved2.target)
|
|
3774
|
-
);
|
|
3775
|
-
}
|
|
3776
3593
|
return serializePrompt(
|
|
3777
3594
|
() => approveAndRun(ctx, command, resolved2.target, explanation)
|
|
3778
3595
|
);
|
|
@@ -3822,8 +3639,8 @@ function reviewScriptTool(ctx) {
|
|
|
3822
3639
|
}
|
|
3823
3640
|
|
|
3824
3641
|
// src/lib/tools/generateRecord.ts
|
|
3825
|
-
import { tool as tool10, generateText
|
|
3826
|
-
import { createAnthropic
|
|
3642
|
+
import { tool as tool10, generateText, Output, NoObjectGeneratedError } from "ai";
|
|
3643
|
+
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
3827
3644
|
import { nanoid as nanoid2 } from "nanoid";
|
|
3828
3645
|
import { mkdir as mkdir5, writeFile as writeFile6 } from "node:fs/promises";
|
|
3829
3646
|
import { dirname as dirname6 } from "node:path";
|
|
@@ -3833,18 +3650,18 @@ var RECORD_MODEL = "claude-haiku-4-5";
|
|
|
3833
3650
|
var MAX_RECORDS = 100;
|
|
3834
3651
|
var BATCH_SIZE = 10;
|
|
3835
3652
|
var MAX_BATCH_ATTEMPTS = 3;
|
|
3836
|
-
function
|
|
3653
|
+
function defaultCreateModel() {
|
|
3837
3654
|
const token = getAuthToken();
|
|
3838
3655
|
if (!token) {
|
|
3839
3656
|
throw new Error("Not authenticated: no user token available");
|
|
3840
3657
|
}
|
|
3841
|
-
return
|
|
3658
|
+
return createAnthropic({
|
|
3842
3659
|
apiKey: token,
|
|
3843
3660
|
baseURL: PROXY_BASE_URL,
|
|
3844
3661
|
fetch: proxyFetch
|
|
3845
3662
|
});
|
|
3846
3663
|
}
|
|
3847
|
-
function generateRecordTool(ctx, createModel =
|
|
3664
|
+
function generateRecordTool(ctx, createModel = defaultCreateModel) {
|
|
3848
3665
|
return tool10({
|
|
3849
3666
|
description: "Generate realistic sample records for an entity and write them to a JSON file. Provide the entity name and its attributes; this tool asks a model to invent varied, realistic values, each with a unique objectID, and returns the file path to read them from at runtime. Do not invent the record values or objectIDs yourself, and do not inline the returned records into the script \u2014 call this tool and read the file it writes.",
|
|
3850
3667
|
inputSchema: z17.object({
|
|
@@ -3865,9 +3682,9 @@ function generateRecordTool(ctx, createModel = defaultCreateModel2) {
|
|
|
3865
3682
|
let lastError;
|
|
3866
3683
|
for (let attempt = 1; attempt <= MAX_BATCH_ATTEMPTS; attempt++) {
|
|
3867
3684
|
try {
|
|
3868
|
-
const { output } = await
|
|
3685
|
+
const { output } = await generateText({
|
|
3869
3686
|
model: anthropic(RECORD_MODEL),
|
|
3870
|
-
output:
|
|
3687
|
+
output: Output.object({
|
|
3871
3688
|
schema: z17.object({
|
|
3872
3689
|
records: z17.array(recordSchema).length(batchCount)
|
|
3873
3690
|
})
|
|
@@ -4032,7 +3849,7 @@ async function runAgentAttempt(req, attempt) {
|
|
|
4032
3849
|
if (!token) {
|
|
4033
3850
|
throw new Error("Not authenticated: no user token available");
|
|
4034
3851
|
}
|
|
4035
|
-
const anthropic =
|
|
3852
|
+
const anthropic = createAnthropic2({
|
|
4036
3853
|
apiKey: token,
|
|
4037
3854
|
baseURL: PROXY_BASE_URL,
|
|
4038
3855
|
fetch: proxyFetch
|
|
@@ -4069,7 +3886,7 @@ async function runAgentAttempt(req, attempt) {
|
|
|
4069
3886
|
}
|
|
4070
3887
|
};
|
|
4071
3888
|
}),
|
|
4072
|
-
output:
|
|
3889
|
+
output: Output2.object({ schema: req.outputSchema }),
|
|
4073
3890
|
tools: createTools(toolContext, {
|
|
4074
3891
|
output: req.outputSchema,
|
|
4075
3892
|
tools: req.tools
|
|
@@ -4252,7 +4069,7 @@ async function runAnalysis(mode, extraInstructions = []) {
|
|
|
4252
4069
|
// package.json
|
|
4253
4070
|
var package_default = {
|
|
4254
4071
|
name: "@algolia/wizard",
|
|
4255
|
-
version: "0.33.0
|
|
4072
|
+
version: "0.33.0",
|
|
4256
4073
|
description: "Magically implement Algolia functionality in your codebase",
|
|
4257
4074
|
type: "module",
|
|
4258
4075
|
engines: {
|
|
@@ -4658,7 +4475,6 @@ ${formatCompletedSteps(ctx.completedSteps)}`,
|
|
|
4658
4475
|
|
|
4659
4476
|
// src/actions/implement.ts
|
|
4660
4477
|
import z29 from "zod";
|
|
4661
|
-
import { mkdir as mkdir7 } from "node:fs/promises";
|
|
4662
4478
|
import { join as join12, relative as relative6 } from "node:path";
|
|
4663
4479
|
|
|
4664
4480
|
// src/lib/git.ts
|
|
@@ -4948,7 +4764,7 @@ function algoliaClientDoc(input) {
|
|
|
4948
4764
|
function ingestionInstructions(input) {
|
|
4949
4765
|
return [
|
|
4950
4766
|
...input.confirmed && input.confirmed.length ? [
|
|
4951
|
-
`Create an ingestion script under "${input.ingestDir}/" at the repo root
|
|
4767
|
+
`Create an ingestion script under "${input.ingestDir}/" at the repo root.`,
|
|
4952
4768
|
`Ingest only the confirmed entity (name, source paths, attributes): ${JSON.stringify(input.confirmed)}.`,
|
|
4953
4769
|
`Ingesting writes to Algolia, so the script needs a write API key and App ID \u2014 read them from the ${API_KEY_VAR} and ${APP_ID_VAR} environment variables rather than hardcoding them. The wizard sets these when it runs the script.`,
|
|
4954
4770
|
`Read the index name from the ${INDEX_NAME_VAR} environment variable, which the wizard sets to "${input.targetIndex}". Never hardcode an index name or derive one from the project, file, or entity name \u2014 the write key only works for that exact index. Exit with an error if ${INDEX_NAME_VAR} is unset.`,
|
|
@@ -5183,9 +4999,6 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
|
|
|
5183
4999
|
const targetIndex = selected?.selection;
|
|
5184
5000
|
useWizard.getState().setTargetIndex(targetIndex ?? null);
|
|
5185
5001
|
await assertGitRepoWithHead(repoRoot);
|
|
5186
|
-
if (useCases.includes("ingestion")) {
|
|
5187
|
-
await mkdir7(join12(repoRoot, INGEST_DIR), { recursive: true });
|
|
5188
|
-
}
|
|
5189
5002
|
const normalized = normalizeFindingPaths(findings);
|
|
5190
5003
|
const confirmed2 = normalized.confirmedEntities;
|
|
5191
5004
|
const searchLocation = normalized.searchImplementationAnalysis;
|