@algolia/wizard 0.103.0-rc.217.762 → 0.103.0-rc.217.764
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 +91 -76
- package/package.json +1 -1
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.
|
|
2470
|
+
version: "0.103.0-rc.217.764",
|
|
2471
2471
|
description: "Magically implement Algolia functionality in your codebase",
|
|
2472
2472
|
type: "module",
|
|
2473
2473
|
engines: {
|
|
@@ -3909,82 +3909,87 @@ function writeCredentialsTool(ctx) {
|
|
|
3909
3909
|
if (!targetIndex) {
|
|
3910
3910
|
return "Error: no target index is set for this run, so a scoped write key cannot be provisioned.";
|
|
3911
3911
|
}
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
const targetError = await validateSafeWriteTarget(ctx, resolved2.target);
|
|
3916
|
-
if (targetError) return targetError;
|
|
3912
|
+
return withFileLock(resolved2.target, async () => {
|
|
3913
|
+
let existing = "";
|
|
3914
|
+
let present;
|
|
3917
3915
|
try {
|
|
3918
|
-
|
|
3916
|
+
const targetError = await validateSafeWriteTarget(
|
|
3917
|
+
ctx,
|
|
3918
|
+
resolved2.target
|
|
3919
|
+
);
|
|
3920
|
+
if (targetError) return targetError;
|
|
3921
|
+
try {
|
|
3922
|
+
existing = await readFile7(resolved2.target, "utf8");
|
|
3923
|
+
} catch (err) {
|
|
3924
|
+
if (err.code !== "ENOENT") throw err;
|
|
3925
|
+
}
|
|
3926
|
+
present = [APP_ID_VAR, API_KEY_VAR].filter(
|
|
3927
|
+
(name) => readEnv(existing, name) !== null
|
|
3928
|
+
);
|
|
3919
3929
|
} catch (err) {
|
|
3920
|
-
|
|
3930
|
+
return `Error writing credentials to ${filePath}: ${err.message}`;
|
|
3921
3931
|
}
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
);
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3932
|
+
const credentials = [];
|
|
3933
|
+
const notes = [];
|
|
3934
|
+
const fileAppId = readEnv(existing, APP_ID_VAR);
|
|
3935
|
+
const fileKey = readEnv(existing, API_KEY_VAR);
|
|
3936
|
+
const fileIndex = readEnv(existing, INDEX_NAME_VAR);
|
|
3937
|
+
if (fileAppId === null || fileKey === null) {
|
|
3938
|
+
try {
|
|
3939
|
+
const selected = (await requireApplication(ctx.appId)).id;
|
|
3940
|
+
if (fileAppId === null) credentials.push([APP_ID_VAR, selected]);
|
|
3941
|
+
if (fileKey === null) {
|
|
3942
|
+
if (fileAppId !== null && fileAppId !== selected) {
|
|
3943
|
+
notes.push(
|
|
3944
|
+
`No ${API_KEY_VAR} was provisioned: ${filePath} names application ${fileAppId}, but ${selected} is selected. Tell the user to remove ${APP_ID_VAR} from ${filePath} and re-run so a matching pair can be written, or to fill in a ${API_KEY_VAR} for ${fileAppId} by hand.`
|
|
3945
|
+
);
|
|
3946
|
+
} else {
|
|
3947
|
+
credentials.push([
|
|
3948
|
+
API_KEY_VAR,
|
|
3949
|
+
(await resolveWriteKey(targetIndex, selected)).key
|
|
3950
|
+
]);
|
|
3951
|
+
}
|
|
3952
|
+
} else {
|
|
3939
3953
|
notes.push(
|
|
3940
|
-
`
|
|
3954
|
+
`The existing ${API_KEY_VAR} must belong to application ${selected} or writes will fail.`
|
|
3941
3955
|
);
|
|
3942
|
-
} else {
|
|
3943
|
-
credentials.push([
|
|
3944
|
-
API_KEY_VAR,
|
|
3945
|
-
(await resolveWriteKey(targetIndex, selected)).key
|
|
3946
|
-
]);
|
|
3947
3956
|
}
|
|
3948
|
-
}
|
|
3949
|
-
|
|
3950
|
-
`The existing ${API_KEY_VAR} must belong to application ${selected} or writes will fail.`
|
|
3951
|
-
);
|
|
3957
|
+
} catch (err) {
|
|
3958
|
+
return `Error: could not resolve Algolia credentials (${err.message})`;
|
|
3952
3959
|
}
|
|
3953
|
-
} catch (err) {
|
|
3954
|
-
return `Error: could not resolve Algolia credentials (${err.message})`;
|
|
3955
3960
|
}
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
existing
|
|
3967
|
-
);
|
|
3968
|
-
const writeError = await safeWriteFile(ctx, resolved2.target, updated);
|
|
3969
|
-
if (writeError) return writeError;
|
|
3970
|
-
const sentences = [
|
|
3971
|
-
`Wrote ${[...credentials.map(([name]) => name), INDEX_NAME_VAR].join(", ")} to ${filePath}.`
|
|
3972
|
-
];
|
|
3973
|
-
if (fileIndex !== null && fileIndex !== targetIndex) {
|
|
3974
|
-
sentences.push(
|
|
3975
|
-
`That replaced the ${INDEX_NAME_VAR} already there ("${fileIndex}"), which this run does not target.`
|
|
3976
|
-
);
|
|
3977
|
-
}
|
|
3978
|
-
if (present.length > 0) {
|
|
3979
|
-
sentences.push(
|
|
3980
|
-
`Skipped ${present.join(" and ")}: already defined there.`
|
|
3961
|
+
let wrote;
|
|
3962
|
+
try {
|
|
3963
|
+
const updated = [
|
|
3964
|
+
...credentials,
|
|
3965
|
+
// Unconditional, unlike the credentials: the write key is scoped to
|
|
3966
|
+
// the run's index, so a stale name left in the file earns a 403.
|
|
3967
|
+
[INDEX_NAME_VAR, targetIndex]
|
|
3968
|
+
].reduce(
|
|
3969
|
+
(content, [name, value]) => upsertEnv(content, name, value),
|
|
3970
|
+
existing
|
|
3981
3971
|
);
|
|
3972
|
+
const writeError = await safeWriteFile(ctx, resolved2.target, updated);
|
|
3973
|
+
if (writeError) return writeError;
|
|
3974
|
+
const sentences = [
|
|
3975
|
+
`Wrote ${[...credentials.map(([name]) => name), INDEX_NAME_VAR].join(", ")} to ${filePath}.`
|
|
3976
|
+
];
|
|
3977
|
+
if (fileIndex !== null && fileIndex !== targetIndex) {
|
|
3978
|
+
sentences.push(
|
|
3979
|
+
`That replaced the ${INDEX_NAME_VAR} already there ("${fileIndex}"), which this run does not target.`
|
|
3980
|
+
);
|
|
3981
|
+
}
|
|
3982
|
+
if (present.length > 0) {
|
|
3983
|
+
sentences.push(
|
|
3984
|
+
`Skipped ${present.join(" and ")}: already defined there.`
|
|
3985
|
+
);
|
|
3986
|
+
}
|
|
3987
|
+
wrote = [...sentences, ...notes].join(" ");
|
|
3988
|
+
} catch (err) {
|
|
3989
|
+
return `Error writing credentials to ${filePath}: ${err.message}`;
|
|
3982
3990
|
}
|
|
3983
|
-
wrote
|
|
3984
|
-
}
|
|
3985
|
-
return `Error writing credentials to ${filePath}: ${err.message}`;
|
|
3986
|
-
}
|
|
3987
|
-
return wrote + await gitIgnoreOutcome(ctx, resolved2.target);
|
|
3991
|
+
return wrote + await gitIgnoreOutcome(ctx, resolved2.target);
|
|
3992
|
+
});
|
|
3988
3993
|
}
|
|
3989
3994
|
});
|
|
3990
3995
|
}
|
|
@@ -5044,7 +5049,6 @@ async function classifyCommandSafety(createModel, command, cwd, explanation, app
|
|
|
5044
5049
|
const { output, usage } = await generateText({
|
|
5045
5050
|
model: anthropic(profile.model),
|
|
5046
5051
|
maxOutputTokens: CLASSIFIER_MAX_OUTPUT_TOKENS,
|
|
5047
|
-
temperature: 0,
|
|
5048
5052
|
providerOptions: {
|
|
5049
5053
|
anthropic: {
|
|
5050
5054
|
thinking: modelOptions.thinking,
|
|
@@ -5739,7 +5743,7 @@ async function runAgentAttempt(req, attempt, retryReason, continuation) {
|
|
|
5739
5743
|
continuation: continuation?.number ?? 0,
|
|
5740
5744
|
durationMs: end - start,
|
|
5741
5745
|
usage,
|
|
5742
|
-
stepCount
|
|
5746
|
+
stepCount,
|
|
5743
5747
|
hitStepLimit,
|
|
5744
5748
|
finishReason
|
|
5745
5749
|
});
|
|
@@ -5751,7 +5755,8 @@ async function runAgentAttempt(req, attempt, retryReason, continuation) {
|
|
|
5751
5755
|
profile: profileName,
|
|
5752
5756
|
model: profile.model,
|
|
5753
5757
|
usage,
|
|
5754
|
-
stepCount
|
|
5758
|
+
stepCount,
|
|
5759
|
+
totalSteps,
|
|
5755
5760
|
maxSteps,
|
|
5756
5761
|
hitStepLimit,
|
|
5757
5762
|
finishReason
|
|
@@ -6869,14 +6874,14 @@ function validationInstructions(input) {
|
|
|
6869
6874
|
`The confirmed placement candidate was "${input.searchLocation ?? "unknown"}", but verify the actual mount rather than assuming the candidate was used.`,
|
|
6870
6875
|
"Inspect the generated search component, its actual mount file, that file's parent layout and sibling controls, and the relevant content UI. Do not rely only on type checks or tests.",
|
|
6871
6876
|
"Confirm that the application renders exactly one search bar. Check for an old search bar and duplicate mounts.",
|
|
6872
|
-
"If the project sets a Content-Security-Policy, confirm that connect-src allows https://*.algolia.net, https://*.algolianet.com, and https://insights.algolia.io, and that search-insights is loaded from npm (not a CDN). If a CSP exists and fails either check, set sufficient=false. If the project has no CSP, skip both checks: do not set sufficient=false, and do not ask to add a CSP.",
|
|
6877
|
+
"If the project sets a Content-Security-Policy, confirm that connect-src allows https://*.algolia.net, https://*.algolianet.com, and https://insights.algolia.io, and that search-insights is loaded from npm (not a CDN). If a CSP exists and fails either check, set sufficient=false. If the project has no CSP, skip both checks: do not set sufficient=false, and do not ask to add a CSP. Without a CSP, insights={true} (or insights: true) with no search-insights package is correct, because the widget loads search-insights from its CDN: do not report a missing search-insights package.",
|
|
6873
6878
|
"Confirm content-specific search is placed with the corresponding content or task controls. Shared navigation is valid only for genuinely app-wide search that fits the visual hierarchy and responsive layout without crowding primary actions.",
|
|
6874
6879
|
"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.",
|
|
6875
6880
|
"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.",
|
|
6876
6881
|
"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.",
|
|
6877
6882
|
"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.",
|
|
6878
6883
|
"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.",
|
|
6879
|
-
"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.",
|
|
6884
|
+
"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). A theme is supported only when the app can select it at runtime: a mounted theme switch, or a stored or system preference that the app applies. A theme file or theme option that the app never selects, for example because the app forces one mode, does not count. 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.",
|
|
6880
6885
|
"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.",
|
|
6881
6886
|
"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.",
|
|
6882
6887
|
"For an InstantSearch Autocomplete, confirm that the item component (the React itemComponent, or the item template in indices[].templates) calls the onSelect that it receives when the user clicks the result, for example onClick={onSelect} on its root element. The widget goes to the getURL route only through onSelect: the click on its <li> only sends the Insights event. If the item ignores onSelect, set sufficient=false, because a click on a result then does nothing.",
|
|
@@ -7199,6 +7204,13 @@ function validationRunInstructions(plan, attempt) {
|
|
|
7199
7204
|
"Do not use an autofix option during validation."
|
|
7200
7205
|
];
|
|
7201
7206
|
}
|
|
7207
|
+
function previousFindingsInstructions(findings) {
|
|
7208
|
+
if (!findings) return [];
|
|
7209
|
+
return [
|
|
7210
|
+
`The previous validation pass reported these findings: ${findings}`,
|
|
7211
|
+
"Check those findings first. Keep the conclusions of that pass that the changes did not affect, for example which themes the app supports. Report a new finding only when it breaks the search (the search bar does not render, search returns no results, or a click on a result does not open it), fails an accessibility requirement, or comes from a change made after the previous pass. Do not set sufficient=false for any other new issue: name it briefly in the summary."
|
|
7212
|
+
];
|
|
7213
|
+
}
|
|
7202
7214
|
function retryTypeCheckInstructions(plan) {
|
|
7203
7215
|
if (!plan.run) return [];
|
|
7204
7216
|
return [
|
|
@@ -7642,6 +7654,7 @@ ${detail}` : ""}`
|
|
|
7642
7654
|
);
|
|
7643
7655
|
let extraInstructions = [];
|
|
7644
7656
|
let buildCheckPlan;
|
|
7657
|
+
let previousFindings;
|
|
7645
7658
|
const confirmedFrameworks = language.frameworks ?? [];
|
|
7646
7659
|
const detectedFrameworks = scan.frameworks ?? [];
|
|
7647
7660
|
const framework = confirmedFrameworks[0]?.name ?? "unknown";
|
|
@@ -7687,9 +7700,10 @@ ${detail}` : ""}`
|
|
|
7687
7700
|
searchConfigFile = searchResult.searchConfigFile;
|
|
7688
7701
|
}
|
|
7689
7702
|
buildCheckPlan ??= await resolveBuildCheckPlan(ctx, repoRoot, input);
|
|
7690
|
-
const validation = await runValidationUseCase(
|
|
7691
|
-
validationRunInstructions(buildCheckPlan, attempt)
|
|
7692
|
-
|
|
7703
|
+
const validation = await runValidationUseCase([
|
|
7704
|
+
...validationRunInstructions(buildCheckPlan, attempt),
|
|
7705
|
+
...previousFindingsInstructions(previousFindings)
|
|
7706
|
+
]);
|
|
7693
7707
|
summaries.push(formatSummary("validation", validation.summary));
|
|
7694
7708
|
const finalAttempt = attempt === MAX_IMPLEMENT_VALIDATION_ATTEMPTS;
|
|
7695
7709
|
let investigateUnrelated = false;
|
|
@@ -7740,6 +7754,7 @@ ${detail}` : ""}`
|
|
|
7740
7754
|
`Unable to validate the implementation after ${MAX_IMPLEMENT_VALIDATION_ATTEMPTS} attempts (details in wizard.log): ${briefSummary(validation.summary)}`
|
|
7741
7755
|
);
|
|
7742
7756
|
}
|
|
7757
|
+
previousFindings = validation.sufficient ? void 0 : validation.additionalInstructions ?? validation.summary;
|
|
7743
7758
|
extraInstructions = validation.sufficient ? [] : validationRetryInstructions(validation);
|
|
7744
7759
|
if (validation.unrelatedFailure && investigateUnrelated) {
|
|
7745
7760
|
extraInstructions.push(
|
|
@@ -10165,7 +10180,7 @@ async function resetProjectState() {
|
|
|
10165
10180
|
// package.json with { type: 'json' }
|
|
10166
10181
|
var package_default2 = {
|
|
10167
10182
|
name: "@algolia/wizard",
|
|
10168
|
-
version: "0.103.0-rc.217.
|
|
10183
|
+
version: "0.103.0-rc.217.764",
|
|
10169
10184
|
description: "Magically implement Algolia functionality in your codebase",
|
|
10170
10185
|
type: "module",
|
|
10171
10186
|
engines: {
|