@algolia/wizard 0.103.0-rc.217.757 → 0.103.0-rc.217.761

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
@@ -2467,7 +2467,7 @@ async function ensureApplication(resumeAppId) {
2467
2467
  // package.json
2468
2468
  var package_default = {
2469
2469
  name: "@algolia/wizard",
2470
- version: "0.103.0-rc.217.757",
2470
+ version: "0.103.0-rc.217.761",
2471
2471
  description: "Magically implement Algolia functionality in your codebase",
2472
2472
  type: "module",
2473
2473
  engines: {
@@ -3216,6 +3216,18 @@ async function hasSymlinkParent(ctx, target) {
3216
3216
  }
3217
3217
  return false;
3218
3218
  }
3219
+ var fileLocks = /* @__PURE__ */ new Map();
3220
+ async function withFileLock(target, fn) {
3221
+ const previous = fileLocks.get(target) ?? Promise.resolve();
3222
+ const run2 = previous.then(fn);
3223
+ const settled = run2.catch(() => void 0);
3224
+ fileLocks.set(target, settled);
3225
+ try {
3226
+ return await run2;
3227
+ } finally {
3228
+ if (fileLocks.get(target) === settled) fileLocks.delete(target);
3229
+ }
3230
+ }
3219
3231
  function symlinkTargetError(target) {
3220
3232
  return `Refused: ${target} is a symbolic link.`;
3221
3233
  }
@@ -3464,7 +3476,10 @@ function writeFileTool(ctx) {
3464
3476
  return secretEnvWriteRefusal(filePath);
3465
3477
  }
3466
3478
  try {
3467
- const writeError = await safeWriteFile(ctx, resolved2.target, content);
3479
+ const writeError = await withFileLock(
3480
+ resolved2.target,
3481
+ () => safeWriteFile(ctx, resolved2.target, content)
3482
+ );
3468
3483
  if (writeError) return writeError;
3469
3484
  useWizard.getState().recordWrittenFile(resolved2.target);
3470
3485
  return `Wrote to ${filePath}`;
@@ -3530,29 +3545,31 @@ function editFileTool(ctx) {
3530
3545
  return "Error: oldString and newString are identical. No change made.";
3531
3546
  }
3532
3547
  try {
3533
- const unsafe = await validateSafeWriteTarget(ctx, resolved2.target);
3534
- if (unsafe) return unsafe;
3535
- let content;
3536
- try {
3537
- content = await readFile5(resolved2.target, "utf8");
3538
- } catch (err) {
3539
- if (err.code === "ENOENT") {
3540
- return `Error: ${filePath} does not exist. To create it, use writeFile.`;
3548
+ return await withFileLock(resolved2.target, async () => {
3549
+ const unsafe = await validateSafeWriteTarget(ctx, resolved2.target);
3550
+ if (unsafe) return unsafe;
3551
+ let content;
3552
+ try {
3553
+ content = await readFile5(resolved2.target, "utf8");
3554
+ } catch (err) {
3555
+ if (err.code === "ENOENT") {
3556
+ return `Error: ${filePath} does not exist. To create it, use writeFile.`;
3557
+ }
3558
+ throw err;
3541
3559
  }
3542
- throw err;
3543
- }
3544
- const matches = countOccurrences(content, oldString);
3545
- if (matches === 0) {
3546
- return `Error: oldString not found in ${filePath}. Read the file again and copy the exact text, including whitespace.`;
3547
- }
3548
- if (matches > 1 && !replaceAll) {
3549
- return `Error: oldString matches ${matches} places in ${filePath}. Add surrounding lines to make it unique, or set replaceAll to true.`;
3550
- }
3551
- const updated = replaceAll ? content.split(oldString).join(newString) : replaceFirst(content, oldString, newString);
3552
- const writeError = await safeWriteFile(ctx, resolved2.target, updated);
3553
- if (writeError) return writeError;
3554
- useWizard.getState().recordWrittenFile(resolved2.target);
3555
- return matches > 1 ? `Edited ${filePath} (${matches} replacements)` : `Edited ${filePath}. ${editedSnippet(updated, content.indexOf(oldString), newString)}`;
3560
+ const matches = countOccurrences(content, oldString);
3561
+ if (matches === 0) {
3562
+ return `Error: oldString not found in ${filePath}. Read the file again and copy the exact text, including whitespace.`;
3563
+ }
3564
+ if (matches > 1 && !replaceAll) {
3565
+ return `Error: oldString matches ${matches} places in ${filePath}. Add surrounding lines to make it unique, or set replaceAll to true.`;
3566
+ }
3567
+ const updated = replaceAll ? content.split(oldString).join(newString) : replaceFirst(content, oldString, newString);
3568
+ const writeError = await safeWriteFile(ctx, resolved2.target, updated);
3569
+ if (writeError) return writeError;
3570
+ useWizard.getState().recordWrittenFile(resolved2.target);
3571
+ return matches > 1 ? `Edited ${filePath} (${matches} replacements)` : `Edited ${filePath}. ${editedSnippet(updated, content.indexOf(oldString), newString)}`;
3572
+ });
3556
3573
  } catch (err) {
3557
3574
  return `Error editing ${filePath}: ${err.message}`;
3558
3575
  }
@@ -6568,7 +6585,8 @@ var validationOutputSchema = z29.object({
6568
6585
  summary: z29.string(),
6569
6586
  sufficient: z29.boolean(),
6570
6587
  additionalInstructions: z29.string().optional(),
6571
- unrelatedFailure: z29.string().optional()
6588
+ unrelatedFailure: z29.string().optional(),
6589
+ styleOnly: z29.boolean().optional()
6572
6590
  });
6573
6591
  var MAX_IMPLEMENT_VALIDATION_ATTEMPTS = 3;
6574
6592
  var INGESTION_MAX_STEPS = 96;
@@ -6855,7 +6873,8 @@ function validationInstructions(input) {
6855
6873
  "Confirm the input has a persistent accessible name; widget-provided combobox, popup, and item relationships and keyboard behavior are preserved; and loading, empty, and error status text is perceivable to assistive technology.",
6856
6874
  "Inspect the CSS that actually applies to the generated DOM. Confirm the results panel and the element drawing the input frame have non-transparent surfaces, the input frame is distinguishable from its surrounding background in every supported theme, text meets 4.5:1 contrast, meaningful boundaries and focus indicators meet 3:1, and no state relies on color alone.",
6857
6875
  "Confirm the search experience reflows without horizontal page scrolling at 320 CSS pixels, keeps its panel on-screen, preserves visible focus, and respects reduced-motion preferences for any added animation.",
6858
- "If the project imports an InstantSearch theme and overrides its palette, confirm that the palette overrides (--ais-*-rgb) win over the theme: they must use a higher specificity than the theme, for example `:root:root`, and for a dark mode `:root:root.dark` or `:root:root[data-theme=dark]`, because the theme sets its own blue in `:root` and in `:root[data-theme=dark], .dark`. `:root:root` alone ties with `:root[data-theme=dark]`. If an override can lose to the theme, set sufficient=false, because the search icon and focus ring then show the theme blue instead of the app accent color.",
6876
+ "If the project imports an InstantSearch theme, confirm that the project sets the theme palette to the app colors in each theme that the app supports: --ais-primary-color-rgb to the app accent color, and --ais-background-color-rgb, --ais-text-color-rgb, and --ais-border-color-rgb to the app surface, text, and border colors. If the project keeps the theme defaults, set sufficient=false, because the search icon, focus ring, and active item then show the theme blue, and the panel shows the theme surface instead of the app surface. A match between the light and dark themes of the widget and the page is not enough. The theme colors .ais-Highlight-highlighted and .ais-Snippet-highlighted with a fixed blue that the palette does not change: if the results show either class and the project does not restyle it, set sufficient=false.",
6877
+ "Then confirm that the palette overrides (--ais-*-rgb) win over the theme: they must use a higher specificity than the theme, for example `:root:root`, and for a dark mode `:root:root.dark` or `:root:root[data-theme=dark]`, because the theme sets its own blue in `:root` and in `:root[data-theme=dark], .dark`. `:root:root` alone ties with `:root[data-theme=dark]`. If an override can lose to the theme, set sufficient=false, because the search icon and focus ring then show the theme blue instead of the app accent color.",
6859
6878
  "Find how the app selects each theme it supports (a class or attribute on an ancestor, a prefers-color-scheme media query, or a theme that exists only in code). Confirm that the search input and results panel take their colors from the active app theme through that same switch. A search widget whose colors do not match the page theme, for example a light panel on a dark page, is a failure: set sufficient=false.",
6860
6879
  "When the project has a package.json, confirm that the theme CSS of the search widget (for InstantSearch, a theme from instantsearch.css) is imported once from a legal global-CSS entry for that framework (Next.js Pages Router: pages/_app; Next.js App Router: root layout; otherwise the app global stylesheet or a component module when allowed). If it is installed but not imported, or imported from a Next.js component file, set sufficient=false.",
6861
6880
  "Confirm that the search component is reachable from and fits the corresponding content task at every supported breakpoint; require app-wide reachability only when the search scope is genuinely app-wide.",
@@ -6869,10 +6888,11 @@ function validationInstructions(input) {
6869
6888
  "Always call reportStatus with status=success after validation, even when sufficient=false.",
6870
6889
  "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.",
6871
6890
  'Exception: the InstantSearch Autocomplete widget (react-instantsearch or instantsearch.js) names its input "Submit" through its generated label (the input has aria-labelledby pointing at that label), and no widget option changes it. Accept that name when the widget is used unmodified, and do not ask for an aria-label, inputProps, or a label wrapper: do not set sufficient=false for it, and do not request a headless rebuild or DOM patch.',
6872
- "Set sufficient=true when the search bar is unique and structurally complete and no placement or accessibility violation was found.",
6873
- "Set sufficient=false when a required placement or accessibility property is observed to fail, the implementation is incomplete, or checks have implementation-caused failures; include concrete additionalInstructions for the next pass.",
6891
+ "Set sufficient=true when the search bar is unique and structurally complete and no placement, accessibility, or theme-color violation was found.",
6892
+ "Set sufficient=false when a required placement, accessibility, or theme-color property is observed to fail, the implementation is incomplete, or checks have implementation-caused failures; include concrete additionalInstructions for the next pass.",
6874
6893
  "You can only read source files. If a required property can be checked in the source, check it there. If it can be established only in a browser (rendered contrast, keyboard behavior, 320-pixel reflow, live-region status, computed accessible name), set sufficient=true when the source shows no violation. Never request devtools, a screenshot, or a contrast tool, and never repeat a finding that an earlier pass already fixed.",
6875
6894
  "If a check fails only in untouched code, set unrelatedFailure to a concise failure description.",
6895
+ "Set styleOnly=true when sufficient=false and every finding is one of these: the theme palette defaults remain, a palette override loses to the theme, or the highlight classes keep the theme blue. If any other finding exists, for example a light panel on a dark page, do not set styleOnly.",
6876
6896
  "Keep the summary to one short sentence. Put the details in additionalInstructions."
6877
6897
  ];
6878
6898
  }
@@ -7688,10 +7708,16 @@ ${detail}` : ""}`
7688
7708
  }
7689
7709
  }
7690
7710
  }
7691
- if (validation.sufficient && (!validation.unrelatedFailure || finalAttempt)) {
7711
+ const styleFindingsRemain = finalAttempt && !validation.sufficient && validation.styleOnly === true;
7712
+ if (validation.sufficient && (!validation.unrelatedFailure || finalAttempt) || styleFindingsRemain) {
7692
7713
  if (validation.unrelatedFailure) {
7693
7714
  summaries.push("Validation: Unrelated check failures remain.");
7694
7715
  }
7716
+ if (styleFindingsRemain) {
7717
+ summaries.push(
7718
+ `Validation: Style issues remain: ${briefSummary(validation.additionalInstructions ?? validation.summary)}`
7719
+ );
7720
+ }
7695
7721
  ctx.setUserInput("implementation", "success");
7696
7722
  trackComponentGenerated(true, attempt);
7697
7723
  break;
@@ -10136,7 +10162,7 @@ async function resetProjectState() {
10136
10162
  // package.json with { type: 'json' }
10137
10163
  var package_default2 = {
10138
10164
  name: "@algolia/wizard",
10139
- version: "0.103.0-rc.217.757",
10165
+ version: "0.103.0-rc.217.761",
10140
10166
  description: "Magically implement Algolia functionality in your codebase",
10141
10167
  type: "module",
10142
10168
  engines: {
@@ -178,6 +178,10 @@ above). When the app has a dark mode, also override the dark values with `:root:
178
178
  a dark class or `:root:root[data-theme=dark]` for a `data-theme` attribute: `:root:root` alone
179
179
  ties with `:root[data-theme=dark]`. The override then wins whatever the import order. Then check that the search icon has the app's accent color, not the theme blue.
180
180
 
181
+ The `components.Highlight` and `components.Snippet` marks (`.ais-Highlight-highlighted`,
182
+ `.ais-Snippet-highlighted`) use a fixed blue that the palette does not change. Restyle them
183
+ with the app's accent color or a bold weight in the text color.
184
+
181
185
  **Follow the app's theme switch.** The theme switches palette only through `:root[data-theme=dark], .dark`,
182
186
  so find how the app selects each theme and set the `--ais-*-rgb` values through the same switch:
183
187
 
@@ -171,6 +171,10 @@ above). When the app has a dark mode, also override the dark values with `:root:
171
171
  a dark class or `:root:root[data-theme=dark]` for a `data-theme` attribute: `:root:root` alone
172
172
  ties with `:root[data-theme=dark]`. The override then wins whatever the import order. Then check that the search icon has the app's accent color, not the theme blue.
173
173
 
174
+ The `<Highlight>` and `<Snippet>` marks (`.ais-Highlight-highlighted`, `.ais-Snippet-highlighted`)
175
+ use a fixed blue that the palette does not change. Restyle them with the app's accent color or
176
+ a bold weight in the text color.
177
+
174
178
  **Follow the app's theme switch.** The theme switches palette only through `:root[data-theme=dark], .dark`,
175
179
  so find how the app selects each theme and set the `--ais-*-rgb` values through the same switch:
176
180
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@algolia/wizard",
3
- "version": "0.103.0-rc.217.757",
3
+ "version": "0.103.0-rc.217.761",
4
4
  "description": "Magically implement Algolia functionality in your codebase",
5
5
  "type": "module",
6
6
  "engines": {