@algolia/wizard 0.84.0-rc.202.644 → 0.84.0-rc.202.646
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
|
@@ -2315,7 +2315,7 @@ async function ensureApplication(resumeAppId) {
|
|
|
2315
2315
|
// package.json
|
|
2316
2316
|
var package_default = {
|
|
2317
2317
|
name: "@algolia/wizard",
|
|
2318
|
-
version: "0.84.0-rc.202.
|
|
2318
|
+
version: "0.84.0-rc.202.646",
|
|
2319
2319
|
description: "Magically implement Algolia functionality in your codebase",
|
|
2320
2320
|
type: "module",
|
|
2321
2321
|
engines: {
|
|
@@ -3739,7 +3739,7 @@ import { execFile as execFile2 } from "node:child_process";
|
|
|
3739
3739
|
import { tool as tool8 } from "ai";
|
|
3740
3740
|
import z15 from "zod";
|
|
3741
3741
|
import { lstat as lstat3, readdir as readdir2, readFile as readFile8, realpath, stat as stat2 } from "node:fs/promises";
|
|
3742
|
-
import { isAbsolute as isAbsolute2, join as join8, relative as relative4, sep as sep2 } from "node:path";
|
|
3742
|
+
import { basename as basename2, isAbsolute as isAbsolute2, join as join8, relative as relative4, sep as sep2 } from "node:path";
|
|
3743
3743
|
import { performance } from "node:perf_hooks";
|
|
3744
3744
|
import { Worker } from "node:worker_threads";
|
|
3745
3745
|
var MAX_GIT_OUTPUT_BYTES = 32e6;
|
|
@@ -4082,6 +4082,9 @@ async function safeSearchPath(rootPath, file) {
|
|
|
4082
4082
|
}
|
|
4083
4083
|
async function searchableFiles(root, target) {
|
|
4084
4084
|
try {
|
|
4085
|
+
if (SKIP_FILES.has(basename2(target)) && (await lstat3(target)).isFile()) {
|
|
4086
|
+
return [target];
|
|
4087
|
+
}
|
|
4085
4088
|
const gitRoot = await gitRootForTarget(root, target);
|
|
4086
4089
|
const result = await gitVisibleFiles(gitRoot, target);
|
|
4087
4090
|
return result.available ? expandNestedRepositories(result.files) : walkFiles(root, target);
|
|
@@ -4113,7 +4116,7 @@ function searchFilesTool(ctx) {
|
|
|
4113
4116
|
description: "Search file contents for a JavaScript regular expression (RegExp syntax, not grep/PCRE). Returns matching lines as file:line:text.",
|
|
4114
4117
|
inputSchema: z15.object({
|
|
4115
4118
|
query: z15.string().describe("JavaScript RegExp pattern to search for"),
|
|
4116
|
-
path: z15.string().optional().describe("Directory to search in (default: cwd)")
|
|
4119
|
+
path: z15.string().optional().describe("Directory or file to search in (default: cwd)")
|
|
4117
4120
|
}),
|
|
4118
4121
|
execute: async ({ query, path = "." }) => {
|
|
4119
4122
|
logger.info({ query, path }, "called searchFiles tool");
|
|
@@ -4258,7 +4261,7 @@ import { tool as tool9 } from "ai";
|
|
|
4258
4261
|
import z16 from "zod";
|
|
4259
4262
|
import { createHash as createHash2 } from "node:crypto";
|
|
4260
4263
|
import { readFile as readFile9, stat as stat3 } from "node:fs/promises";
|
|
4261
|
-
import { basename as
|
|
4264
|
+
import { basename as basename3, relative as relative5, resolve as resolve3 } from "node:path";
|
|
4262
4265
|
|
|
4263
4266
|
// src/lib/tools/utils/prompt.ts
|
|
4264
4267
|
var chain = Promise.resolve();
|
|
@@ -4356,7 +4359,7 @@ function commandDiffersFromReviewedScript(ctx, command, cwd) {
|
|
|
4356
4359
|
if (approval.command === command && approval.cwd === cwd) return false;
|
|
4357
4360
|
if (approval.command === command) return true;
|
|
4358
4361
|
const scriptReferences = [
|
|
4359
|
-
|
|
4362
|
+
basename3(approval.filePath),
|
|
4360
4363
|
relative5(ctx.root, approval.filePath),
|
|
4361
4364
|
".algolia-wizard"
|
|
4362
4365
|
];
|
|
@@ -6009,7 +6012,7 @@ import {
|
|
|
6009
6012
|
// src/lib/git.ts
|
|
6010
6013
|
import { execFile as execFile3 } from "node:child_process";
|
|
6011
6014
|
import { copyFile, mkdir as mkdir4, stat as stat4 } from "node:fs/promises";
|
|
6012
|
-
import { basename as
|
|
6015
|
+
import { basename as basename4, dirname as dirname3, isAbsolute as isAbsolute3, join as join9, resolve as resolve4 } from "node:path";
|
|
6013
6016
|
var MAX_BUFFER = 32 * 1024 * 1024;
|
|
6014
6017
|
function git(args) {
|
|
6015
6018
|
return new Promise((resolve6, reject) => {
|
|
@@ -6046,7 +6049,7 @@ async function copyUploadIntoProject(repoRoot, ingestDir, sourcePath) {
|
|
|
6046
6049
|
} catch {
|
|
6047
6050
|
return { ok: false, reason: `"${sourcePath}" does not exist` };
|
|
6048
6051
|
}
|
|
6049
|
-
const relPath = join9(ingestDir,
|
|
6052
|
+
const relPath = join9(ingestDir, basename4(source));
|
|
6050
6053
|
const dest = join9(repoRoot, relPath);
|
|
6051
6054
|
if (resolve4(source) === resolve4(dest)) {
|
|
6052
6055
|
return { ok: true, relPath };
|
|
@@ -6193,6 +6196,11 @@ var INGESTION_SOURCE = {
|
|
|
6193
6196
|
var BUILD_CHECK_PROMPT = "Run type-check now? This can take several minutes on a large repository.";
|
|
6194
6197
|
var MISSING_DEPENDENCIES_PROMPT = "Dependencies are not installed. Install them and run type-check now?";
|
|
6195
6198
|
var UNRELATED_FAILURE_PROMPT = "These checks are still failing and appear unrelated to the changes. Continue the investigation?";
|
|
6199
|
+
var INGEST_RETRY_PROMPT = "Fix the cause (for example, start the database the script reads from), then retry.";
|
|
6200
|
+
var INGEST_RETRY = {
|
|
6201
|
+
retry: "Retry ingestion",
|
|
6202
|
+
skip: "Continue without records"
|
|
6203
|
+
};
|
|
6196
6204
|
var FILE_UPLOAD_PATH_PROMPT = "Enter the path to your JSON, CSV, or TSV file (relative to the project root, or absolute):";
|
|
6197
6205
|
var JS_LANGUAGES = ["javascript", "typescript", "jsx", "tsx", "node"];
|
|
6198
6206
|
function lower(entries) {
|
|
@@ -6295,6 +6303,7 @@ function ingestionInstructions(input) {
|
|
|
6295
6303
|
] : [],
|
|
6296
6304
|
`When the script is finished, decide the exact command and cwd you will use to run it. Make sure that the script path in the command resolves from that cwd to the filePath. Then call reviewScript with that filePath, command, cwd, the exact selected entityName, and usesGeneratedRecords set to ${input.ingestionSource === "generated"}. Wait for the developer to review it because running it writes records to a live index. Do not run it before that call returns. If you change the command or cwd after a failed run, call reviewScript again before runShell.`,
|
|
6297
6305
|
'Then, without changing directories, run the script yourself via runShell using the exact same command and cwd. 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.',
|
|
6306
|
+
"When the script reads from a database or another service, find how the project connects to it locally (env files, README, socket or TCP settings). If that connection needs a local service, such as a database proxy (for example cloud-sql-proxy) or a tunnel, make the script check the connection before it reads, and exit with an error that names the service and the command from the project docs that starts it.",
|
|
6298
6307
|
"If external data access fails, do not run authentication commands, change accounts or machine configuration, or start proxies, containers, or services.",
|
|
6299
6308
|
"Do not troubleshoot unavailable external infrastructure. Preserve the script and command, report success, and let the developer prepare the data source.",
|
|
6300
6309
|
"If the script cannot access an external data source because credentials or a service are unavailable, do not report status=fail. Report status=success with the completed script, ingestCommand, and a concise failure summary. The wizard handles this run failure and tells the developer how to retry.",
|
|
@@ -6427,6 +6436,7 @@ function validationInstructions(input) {
|
|
|
6427
6436
|
"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.",
|
|
6428
6437
|
"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.",
|
|
6429
6438
|
"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.",
|
|
6439
|
+
"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.",
|
|
6430
6440
|
"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 the component or the global stylesheet. If it is installed but not imported, set sufficient=false.",
|
|
6431
6441
|
"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.",
|
|
6432
6442
|
"Do not run the test suite or any test command.",
|
|
@@ -6596,6 +6606,22 @@ function ingestFailure(attempt, executions) {
|
|
|
6596
6606
|
}
|
|
6597
6607
|
return { reason: `it failed (exit ${attempt.exitCode ?? "unknown"})`, detail };
|
|
6598
6608
|
}
|
|
6609
|
+
function errorLine(output) {
|
|
6610
|
+
const lines = output?.split("\n").map((l) => l.trim()).filter(Boolean) ?? [];
|
|
6611
|
+
return [...lines].reverse().find((l) => /\w*(Error|Exception)\b/.test(l)) ?? lines.at(-1);
|
|
6612
|
+
}
|
|
6613
|
+
function ingestFailureMessages(headline, detail, command, cwd) {
|
|
6614
|
+
return [
|
|
6615
|
+
headline,
|
|
6616
|
+
// One message per line: Notices.tsx counts a message as one wrapped
|
|
6617
|
+
// line, so an embedded newline overflows the panel's height accounting.
|
|
6618
|
+
...detail?.split("\n").filter((l) => l.trim()) ?? [],
|
|
6619
|
+
...command ? [
|
|
6620
|
+
`Ingestion command: ${command}`,
|
|
6621
|
+
...cwd !== "." ? [`Working directory: ${cwd}`] : []
|
|
6622
|
+
] : []
|
|
6623
|
+
];
|
|
6624
|
+
}
|
|
6599
6625
|
function makeToolContext(root, appId, env = async () => ({}), secretEnv = async () => ({})) {
|
|
6600
6626
|
return {
|
|
6601
6627
|
...createToolContext(
|
|
@@ -6903,11 +6929,45 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
|
|
|
6903
6929
|
ingestCommand = result.ingestCommand;
|
|
6904
6930
|
const ingestionContext = ingestionTools;
|
|
6905
6931
|
const executions = ingestionContext.shell.executions;
|
|
6932
|
+
let outcome = ingestOutcome(executions, repoRoot, ingestCommand);
|
|
6933
|
+
let failureAcknowledged = false;
|
|
6934
|
+
while (!outcome.run && outcome.attempt?.approved) {
|
|
6935
|
+
const attempt = outcome.attempt;
|
|
6936
|
+
const { reason, detail } = ingestFailure(attempt, executions);
|
|
6937
|
+
const choice = await ctx.requestUserInput({
|
|
6938
|
+
prompt: INGEST_RETRY_PROMPT,
|
|
6939
|
+
promptType: "multipleChoice",
|
|
6940
|
+
options: [INGEST_RETRY.retry, INGEST_RETRY.skip],
|
|
6941
|
+
messages: ingestFailureMessages(
|
|
6942
|
+
`\u26A0\uFE0F Records were not indexed \u2014 ${reason}.`,
|
|
6943
|
+
errorLine(detail),
|
|
6944
|
+
attempt.command,
|
|
6945
|
+
relativeIngestCwd(attempt, repoRoot)
|
|
6946
|
+
)
|
|
6947
|
+
});
|
|
6948
|
+
if (choice !== INGEST_RETRY.retry) {
|
|
6949
|
+
failureAcknowledged = true;
|
|
6950
|
+
break;
|
|
6951
|
+
}
|
|
6952
|
+
const rerun = await runReviewedCommand(
|
|
6953
|
+
ingestionContext,
|
|
6954
|
+
attempt.command,
|
|
6955
|
+
attempt.cwd
|
|
6956
|
+
);
|
|
6957
|
+
if (rerun === void 0 || typeof rerun === "string") {
|
|
6958
|
+
logger.warn(
|
|
6959
|
+
{ command: attempt.command, refusal: rerun },
|
|
6960
|
+
"implement: could not retry the ingestion command"
|
|
6961
|
+
);
|
|
6962
|
+
break;
|
|
6963
|
+
}
|
|
6964
|
+
outcome = ingestOutcome(executions, repoRoot, ingestCommand);
|
|
6965
|
+
}
|
|
6906
6966
|
const {
|
|
6907
6967
|
run: ingestRun,
|
|
6908
6968
|
attempt: ingestAttempt,
|
|
6909
6969
|
recordCount
|
|
6910
|
-
} =
|
|
6970
|
+
} = outcome;
|
|
6911
6971
|
let ingestCwd = ".";
|
|
6912
6972
|
if (ingestAttempt) {
|
|
6913
6973
|
ingestCommand = ingestAttempt.command;
|
|
@@ -6987,22 +7047,17 @@ ${detail}` : ""}`
|
|
|
6987
7047
|
"When you're ready to continue, we'll move on to search implementation."
|
|
6988
7048
|
]
|
|
6989
7049
|
});
|
|
6990
|
-
} else {
|
|
6991
|
-
const commandMessages = ingestCommand ? [
|
|
6992
|
-
`Ingestion command: ${ingestCommand}`,
|
|
6993
|
-
...ingestCwd !== "." ? [`Working directory: ${ingestCwd}`] : []
|
|
6994
|
-
] : [];
|
|
7050
|
+
} else if (!failureAcknowledged) {
|
|
6995
7051
|
await ctx.requestUserInput({
|
|
6996
7052
|
prompt: "",
|
|
6997
7053
|
promptType: "enterToContinue",
|
|
6998
7054
|
options: [],
|
|
6999
|
-
|
|
7000
|
-
// line, so an embedded newline overflows the panel's height accounting.
|
|
7001
|
-
messages: [
|
|
7055
|
+
messages: ingestFailureMessages(
|
|
7002
7056
|
ingestOutcomeMessage,
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7057
|
+
ingestFailureDetail,
|
|
7058
|
+
ingestCommand,
|
|
7059
|
+
ingestCwd
|
|
7060
|
+
)
|
|
7006
7061
|
});
|
|
7007
7062
|
}
|
|
7008
7063
|
}
|
|
@@ -9270,7 +9325,7 @@ async function resetProjectState() {
|
|
|
9270
9325
|
// package.json with { type: 'json' }
|
|
9271
9326
|
var package_default2 = {
|
|
9272
9327
|
name: "@algolia/wizard",
|
|
9273
|
-
version: "0.84.0-rc.202.
|
|
9328
|
+
version: "0.84.0-rc.202.646",
|
|
9274
9329
|
description: "Magically implement Algolia functionality in your codebase",
|
|
9275
9330
|
type: "module",
|
|
9276
9331
|
engines: {
|
|
@@ -160,6 +160,25 @@ above). When the app has a dark mode, also override the dark values with `:root:
|
|
|
160
160
|
a dark class or `:root:root[data-theme=dark]` for a `data-theme` attribute: `:root:root` alone
|
|
161
161
|
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.
|
|
162
162
|
|
|
163
|
+
**Follow the app's theme switch.** The theme switches palette only through `:root[data-theme=dark], .dark`,
|
|
164
|
+
so find how the app selects each theme and set the `--ais-*-rgb` values through the same switch:
|
|
165
|
+
|
|
166
|
+
- A class or attribute on an ancestor: override under that selector, as above.
|
|
167
|
+
- A `prefers-color-scheme` media query: override inside the same query, for example
|
|
168
|
+
`@media (prefers-color-scheme: dark) { :root:root { … } }`.
|
|
169
|
+
- A theme that exists only in code (a theme object, a theme store), with no class or attribute
|
|
170
|
+
on the page: set the values from that theme as inline custom properties on the widget
|
|
171
|
+
container, and set them again when the theme changes.
|
|
172
|
+
|
|
173
|
+
The panel renders inside the widget, so values on the container apply to the whole widget. Make
|
|
174
|
+
triplets from opaque theme colors, because a triplet has no alpha:
|
|
175
|
+
|
|
176
|
+
```js
|
|
177
|
+
container.style.setProperty('--ais-background-color-rgb', toRgbTriplet(theme.surface))
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Then check the input and the panel in each theme that the app supports.
|
|
181
|
+
|
|
163
182
|
Everything else is plain CSS against the widget's classes, or `cssClasses` /
|
|
164
183
|
`indices[].cssClasses` to add your own names to the same elements. Who owns what:
|
|
165
184
|
|
|
@@ -152,6 +152,25 @@ above). When the app has a dark mode, also override the dark values with `:root:
|
|
|
152
152
|
a dark class or `:root:root[data-theme=dark]` for a `data-theme` attribute: `:root:root` alone
|
|
153
153
|
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.
|
|
154
154
|
|
|
155
|
+
**Follow the app's theme switch.** The theme switches palette only through `:root[data-theme=dark], .dark`,
|
|
156
|
+
so find how the app selects each theme and set the `--ais-*-rgb` values through the same switch:
|
|
157
|
+
|
|
158
|
+
- A class or attribute on an ancestor: override under that selector, as above.
|
|
159
|
+
- A `prefers-color-scheme` media query: override inside the same query, for example
|
|
160
|
+
`@media (prefers-color-scheme: dark) { :root:root { … } }`.
|
|
161
|
+
- A theme that exists only in code (a theme object, a CSS-in-JS provider, a theme store), with
|
|
162
|
+
no class or attribute on the page: set the values from that theme as inline custom properties
|
|
163
|
+
on the element that wraps the widget, so they follow theme changes.
|
|
164
|
+
|
|
165
|
+
The panel renders inside the widget, so values on a wrapper apply to the whole widget. Make
|
|
166
|
+
triplets from opaque theme colors, because a triplet has no alpha:
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
<search style={{ '--ais-background-color-rgb': toRgbTriplet(theme.surface) } as React.CSSProperties}>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Then check the input and the panel in each theme that the app supports.
|
|
173
|
+
|
|
155
174
|
Everything else is plain CSS against the widget's classes, or the `classNames` /
|
|
156
175
|
`indices[].classNames` props to add your own names to the same elements. Who owns what:
|
|
157
176
|
|