@algolia/wizard 0.100.0 → 0.102.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 CHANGED
@@ -2447,7 +2447,7 @@ async function ensureApplication(resumeAppId) {
2447
2447
  // package.json
2448
2448
  var package_default = {
2449
2449
  name: "@algolia/wizard",
2450
- version: "0.100.0",
2450
+ version: "0.102.0",
2451
2451
  description: "Magically implement Algolia functionality in your codebase",
2452
2452
  type: "module",
2453
2453
  engines: {
@@ -3075,7 +3075,6 @@ var selectIndexStep = async (ctx) => {
3075
3075
  // src/lib/agent.ts
3076
3076
  import {
3077
3077
  ToolLoopAgent,
3078
- hasToolCall,
3079
3078
  Output as Output3,
3080
3079
  APICallError,
3081
3080
  NoOutputGeneratedError,
@@ -3167,6 +3166,22 @@ function resolveInRoot(ctx, path) {
3167
3166
  }
3168
3167
  return { ok: true, target };
3169
3168
  }
3169
+ function isPackageManifest(parts) {
3170
+ if (parts.at(-1) !== "package.json") return false;
3171
+ return parts.length === 2 || parts.length === 3 && parts[0].startsWith("@");
3172
+ }
3173
+ var DEPENDENCY_INTERNALS_REFUSAL = "Refused: do not explore node_modules. Use the Algolia SDK reference and the type checker output. To check an installed version, read node_modules/<package>/package.json.";
3174
+ function dependencyInternalsRefusal(ctx, target) {
3175
+ if (!ctx.dependencyManifestsOnly) return null;
3176
+ const parts = relative(ctx.root, target).split(sep);
3177
+ const index = parts.lastIndexOf("node_modules");
3178
+ if (index === -1 || isPackageManifest(parts.slice(index + 1))) return null;
3179
+ return DEPENDENCY_INTERNALS_REFUSAL;
3180
+ }
3181
+ var DEPENDENCY_INTERNALS_PATH = /node_modules\/(?!\.bin\/|(?:@[^/\s'"`]+\/)?[^/\s'"`]+\/package\.json\b)/;
3182
+ function commandNamesDependencyInternals(ctx, command) {
3183
+ return Boolean(ctx.dependencyManifestsOnly) && DEPENDENCY_INTERNALS_PATH.test(command);
3184
+ }
3170
3185
  async function hasSymlinkParent(ctx, target) {
3171
3186
  let current = ctx.root;
3172
3187
  const parts = relative(ctx.root, dirname2(target)).split(sep).filter(Boolean);
@@ -3230,6 +3245,8 @@ function listFilesTool(ctx) {
3230
3245
  }
3231
3246
  const resolved2 = resolveInRoot(ctx, path);
3232
3247
  if (!resolved2.ok) return resolved2.error;
3248
+ const refusal = dependencyInternalsRefusal(ctx, resolved2.target);
3249
+ if (refusal) return refusal;
3233
3250
  try {
3234
3251
  const entries = await readdir(resolved2.target, { withFileTypes: true });
3235
3252
  return entries.map((e) => e.isDirectory() ? `${e.name}/` : e.name).join("\n");
@@ -3271,6 +3288,19 @@ function changeDirectoryTool(ctx) {
3271
3288
  // src/lib/tools/reportStatus.ts
3272
3289
  import { tool as tool3 } from "ai";
3273
3290
  import z8 from "zod";
3291
+ var PLACEHOLDER_REPORT_REFUSAL = 'Refused: reportStatus got the placeholder text "placeholder" instead of a real result. The task is not finished. Continue the task, then call reportStatus with the real status, reason, and output.';
3292
+ var PLACEHOLDER_VALUE = /^\s*placeholder\s*$/i;
3293
+ function isPlaceholder(value) {
3294
+ return typeof value === "string" && PLACEHOLDER_VALUE.test(value);
3295
+ }
3296
+ function hasPlaceholder(reason, output) {
3297
+ if (isPlaceholder(reason)) return true;
3298
+ if (typeof output !== "object" || output === null) return false;
3299
+ return Object.values(output).some(isPlaceholder);
3300
+ }
3301
+ function isAcceptedReport(result) {
3302
+ return typeof result === "object" && result !== null && "status" in result && !("rejected" in result);
3303
+ }
3274
3304
  function reportStatusTool(output) {
3275
3305
  return tool3({
3276
3306
  description: "Report the status of your execution. Return a reason in case of failure.",
@@ -3280,6 +3310,10 @@ function reportStatusTool(output) {
3280
3310
  output
3281
3311
  }),
3282
3312
  execute: async ({ status, reason, output: output2 }) => {
3313
+ if (hasPlaceholder(reason, output2)) {
3314
+ logger.warn({ status, reason }, "reportStatus: refused a placeholder report");
3315
+ return { rejected: true, message: PLACEHOLDER_REPORT_REFUSAL };
3316
+ }
3283
3317
  logger.info({ status, reason }, "called reportStatus tool");
3284
3318
  return { status, reason, output: output2 };
3285
3319
  }
@@ -3379,6 +3413,8 @@ function readFileTool(ctx) {
3379
3413
  logger.info({ filePath, readLines }, "called readFile tool");
3380
3414
  const resolved2 = resolveInRoot(ctx, filePath);
3381
3415
  if (resolved2.ok === false) return resolved2.error;
3416
+ const refusal = dependencyInternalsRefusal(ctx, resolved2.target);
3417
+ if (refusal) return refusal;
3382
3418
  try {
3383
3419
  const content = await readFile4(resolved2.target, "utf8");
3384
3420
  const safeContent = isEnvFile(resolved2.target) ? redactEnvValues(content) : content;
@@ -4323,6 +4359,8 @@ function searchFilesTool(ctx) {
4323
4359
  }
4324
4360
  const resolved2 = resolveInRoot(ctx, path);
4325
4361
  if (!resolved2.ok) return resolved2.error;
4362
+ const refusal = dependencyInternalsRefusal(ctx, resolved2.target);
4363
+ if (refusal) return refusal;
4326
4364
  try {
4327
4365
  await stat2(resolved2.target);
4328
4366
  } catch (err) {
@@ -4347,7 +4385,9 @@ function searchFilesTool(ctx) {
4347
4385
  let workerFailed = false;
4348
4386
  try {
4349
4387
  try {
4350
- const files = await searchableFiles(ctx.root, resolved2.target);
4388
+ const files = (await searchableFiles(ctx.root, resolved2.target)).filter(
4389
+ (file) => !dependencyInternalsRefusal(ctx, file)
4390
+ );
4351
4391
  const rootPath = await realpath(ctx.root);
4352
4392
  for (const [fileIndex, file] of files.entries()) {
4353
4393
  const moreFilesRemain = fileIndex < files.length - LINE_NUMBER_OFFSET;
@@ -5132,6 +5172,9 @@ function runShellTool(ctx, createModel = defaultCreateModel) {
5132
5172
  if (isFileIOCommand(command)) {
5133
5173
  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).";
5134
5174
  }
5175
+ if (commandNamesDependencyInternals(ctx, command)) {
5176
+ return DEPENDENCY_INTERNALS_REFUSAL;
5177
+ }
5135
5178
  logger.info({ command, cwd: resolved2.target }, "called runShell tool");
5136
5179
  const reviewed = await serializePrompt(
5137
5180
  () => runReviewedCommand(ctx, command, resolved2.target)
@@ -5444,6 +5487,14 @@ function withCachedHistory(messages) {
5444
5487
  }
5445
5488
  ];
5446
5489
  }
5490
+ function isAcceptedReportResult(result) {
5491
+ return result.toolName === "reportStatus" && isAcceptedReport(result.output);
5492
+ }
5493
+ function reportAccepted({
5494
+ steps
5495
+ }) {
5496
+ return steps.at(-1)?.toolResults?.some(isAcceptedReportResult) ?? false;
5497
+ }
5447
5498
  function isMissingReportRetry(kind) {
5448
5499
  return kind === "missingReport" || incompleteReasonOf(kind) !== void 0;
5449
5500
  }
@@ -5563,10 +5614,7 @@ async function runAgentAttempt(req, attempt, retryReason) {
5563
5614
  tools: req.tools
5564
5615
  }),
5565
5616
  toolChoice: "required",
5566
- stopWhen: [
5567
- hasToolCall("reportStatus"),
5568
- stepCountIs(maxSteps)
5569
- ],
5617
+ stopWhen: [reportAccepted, stepCountIs(maxSteps)],
5570
5618
  prepareStep: ({ stepNumber, messages }) => ({
5571
5619
  messages: withCachedHistory(messages),
5572
5620
  ...stepNumber >= maxSteps - 1 && {
@@ -5648,7 +5696,7 @@ async function runAgentAttempt(req, attempt, retryReason) {
5648
5696
  "tool usage"
5649
5697
  );
5650
5698
  const toolResults = await stream.toolResults;
5651
- const report = [...toolResults].reverse().find((r) => r.toolName === "reportStatus");
5699
+ const report = [...toolResults].reverse().find(isAcceptedReportResult);
5652
5700
  if (!report) {
5653
5701
  logger.error(
5654
5702
  {
@@ -6995,7 +7043,8 @@ function ingestionRetryInstruction(reason, detail) {
6995
7043
  }
6996
7044
  function validationRetryInstructions(validation) {
6997
7045
  return [
6998
- `Implementation insufficient. Address these findings before reporting completion: ${validation.additionalInstructions ?? validation.summary}`
7046
+ `Implementation insufficient. Address these findings before reporting completion: ${validation.additionalInstructions ?? validation.summary}`,
7047
+ "Apply these fixes first, with the fewest edits. When a finding names a fix, apply that fix instead of studying the API again."
6999
7048
  ];
7000
7049
  }
7001
7050
  async function pathExists(path) {
@@ -7067,7 +7116,7 @@ function validationRunInstructions(plan, attempt) {
7067
7116
  function retryTypeCheckInstructions(plan) {
7068
7117
  if (!plan.run) return [];
7069
7118
  return [
7070
- "The developer approved the type check. After your edits, run it once with the project's existing command. Do not install dependencies, use npx, dlx, or another package runner, or use an autofix option. Fix the errors that your changes cause, and name any error that remains in the summary."
7119
+ "The developer approved the type check. Run it once with the project's existing command right after you apply the fixes, before other work. Do not install dependencies, use npx, dlx, or another package runner, or use an autofix option. Fix the errors that your changes cause, and name any error that remains in the summary."
7071
7120
  ];
7072
7121
  }
7073
7122
  async function resolveIngestionSource(ctx, repoRoot) {
@@ -7238,7 +7287,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
7238
7287
  async function runImplementationUseCase(currentUseCase, extraInstructions = [], isRetry = false) {
7239
7288
  if (agentRuns > 0) ctx.recordStepExecution();
7240
7289
  agentRuns += 1;
7241
- const toolContext = currentUseCase === "ingestion" ? ingestionTools : makeToolContext(repoRoot);
7290
+ const toolContext = currentUseCase === "ingestion" ? ingestionTools : { ...makeToolContext(repoRoot), dependencyManifestsOnly: true };
7242
7291
  try {
7243
7292
  return await runAgent({
7244
7293
  operation: `${currentUseCase}-implementation`,
@@ -7283,7 +7332,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
7283
7332
  tools: toolsForUseCase("validation"),
7284
7333
  outputSchema: validationOutputSchema,
7285
7334
  modelProfile: "validation" /* validation */,
7286
- toolContext: makeToolContext(repoRoot)
7335
+ toolContext: { ...makeToolContext(repoRoot), dependencyManifestsOnly: true }
7287
7336
  });
7288
7337
  }
7289
7338
  if (useCases.includes("ingestion")) {
@@ -10024,7 +10073,7 @@ async function resetProjectState() {
10024
10073
  // package.json with { type: 'json' }
10025
10074
  var package_default2 = {
10026
10075
  name: "@algolia/wizard",
10027
- version: "0.100.0",
10076
+ version: "0.102.0",
10028
10077
  description: "Magically implement Algolia functionality in your codebase",
10029
10078
  type: "module",
10030
10079
  engines: {
@@ -95,6 +95,8 @@ Ensure the attributes you map into the component match the entity. 'title' above
95
95
  - The `item` template renders content only: **no `<a>`, no `href`, no click handler of
96
96
  your own, never `stopPropagation`.** The widget's `<li>` owns the click — it sends the
97
97
  Insights `click`, closes the panel, clears the active option.
98
+ - Do not pass a top-level `onSelect` to `autocomplete()` to navigate. `getURL` already
99
+ navigates.
98
100
  - `getSearchPageURL` sends Enter with nothing highlighted to a full results page; pass it
99
101
  only if the app has one. `.getQuery` is optional.
100
102
  - TypeScript: type records through the generic, not casts inside templates —
@@ -87,6 +87,9 @@ Ensure the attributes you map into the component match the entity. 'title' above
87
87
  - `itemComponent` renders content only: **no `<a>`, no `href`, no `onClick` beyond the
88
88
  `onSelect` it is handed, never `stopPropagation`.** The widget's `<li>` owns the click —
89
89
  it sends the Insights `click`, closes the panel, clears the active option.
90
+ - Do not pass a top-level `onSelect` to `<Autocomplete>` (for example to call
91
+ `router.push`). `getURL` already navigates. The top-level callback can receive a
92
+ `SyntheticEvent` instead of `{ item }`, so reading `item` from it fails the type check.
90
93
  - `getSearchPageURL` sends Enter with nothing highlighted to a full results page; pass it
91
94
  only if the app has one. `.getQuery` is optional.
92
95
  - TypeScript: type records through the generic, not casts inside `itemComponent` —
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@algolia/wizard",
3
- "version": "0.100.0",
3
+ "version": "0.102.0",
4
4
  "description": "Magically implement Algolia functionality in your codebase",
5
5
  "type": "module",
6
6
  "engines": {