@algolia/wizard 0.75.0 → 0.77.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 +834 -338
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -4,9 +4,54 @@
|
|
|
4
4
|
import { render } from "ink";
|
|
5
5
|
|
|
6
6
|
// src/ui/App.tsx
|
|
7
|
-
import { Box as
|
|
7
|
+
import { Box as Box21, Text as Text22, useApp as useApp2, useInput as useInput9, useWindowSize as useWindowSize8 } from "ink";
|
|
8
8
|
import Spinner3 from "ink-spinner";
|
|
9
9
|
|
|
10
|
+
// src/lib/terminalSize.ts
|
|
11
|
+
var MIN_ROWS = 30;
|
|
12
|
+
var MIN_COLUMNS = 100;
|
|
13
|
+
var COMPACT_ROWS = 24;
|
|
14
|
+
var COMPACT_COLUMNS = 80;
|
|
15
|
+
var SIDEBAR_MIN_COLUMNS = 90;
|
|
16
|
+
function isCompactTerminal(columns, rows) {
|
|
17
|
+
return rows < COMPACT_ROWS || columns < COMPACT_COLUMNS;
|
|
18
|
+
}
|
|
19
|
+
async function requestTerminalSize(stdout = process.stdout, {
|
|
20
|
+
rows = MIN_ROWS,
|
|
21
|
+
columns = MIN_COLUMNS,
|
|
22
|
+
timeoutMs = 150,
|
|
23
|
+
settleMs = 120
|
|
24
|
+
} = {}) {
|
|
25
|
+
if (!stdout.isTTY) return;
|
|
26
|
+
const currentRows = stdout.rows ?? 0;
|
|
27
|
+
const currentColumns = stdout.columns ?? 0;
|
|
28
|
+
if (currentRows >= rows && currentColumns >= columns) return;
|
|
29
|
+
stdout.write(
|
|
30
|
+
`\x1B[8;${Math.max(currentRows, rows)};${Math.max(currentColumns, columns)}t`
|
|
31
|
+
);
|
|
32
|
+
const resized = await waitForResize(stdout, timeoutMs);
|
|
33
|
+
if (!resized) return;
|
|
34
|
+
await delay(settleMs);
|
|
35
|
+
stdout.write("\x1B[2J\x1B[H");
|
|
36
|
+
}
|
|
37
|
+
function waitForResize(stdout, timeoutMs) {
|
|
38
|
+
return new Promise((resolve6) => {
|
|
39
|
+
const finish = (didResize) => () => {
|
|
40
|
+
clearTimeout(timer);
|
|
41
|
+
stdout.off("resize", onResize);
|
|
42
|
+
resolve6(didResize);
|
|
43
|
+
};
|
|
44
|
+
const onResize = finish(true);
|
|
45
|
+
const timer = setTimeout(finish(false), timeoutMs);
|
|
46
|
+
stdout.once("resize", onResize);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function delay(ms) {
|
|
50
|
+
return new Promise((resolve6) => {
|
|
51
|
+
setTimeout(resolve6, ms);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
10
55
|
// src/core/store.ts
|
|
11
56
|
import { create } from "zustand";
|
|
12
57
|
import { nanoid } from "nanoid";
|
|
@@ -48,7 +93,7 @@ function runAlgoliaCli(args, { onOutput, redact } = {}) {
|
|
|
48
93
|
const store = useWizard.getState();
|
|
49
94
|
const command = mask(args.join(" "), redact);
|
|
50
95
|
const logId = store.logStart("tool", `algolia ${command}`);
|
|
51
|
-
return new Promise((
|
|
96
|
+
return new Promise((resolve6, reject) => {
|
|
52
97
|
const child = spawn("npx", npxArgs(args), { shell });
|
|
53
98
|
let stdout = "";
|
|
54
99
|
let stderr = "";
|
|
@@ -71,7 +116,7 @@ function runAlgoliaCli(args, { onOutput, redact } = {}) {
|
|
|
71
116
|
splitters.stdout.flush();
|
|
72
117
|
splitters.stderr.flush();
|
|
73
118
|
if (code === 0) {
|
|
74
|
-
|
|
119
|
+
resolve6(stdout);
|
|
75
120
|
} else {
|
|
76
121
|
const failed = stderr.trim();
|
|
77
122
|
let detail = "";
|
|
@@ -277,15 +322,15 @@ var useWizard = create((set, get) => ({
|
|
|
277
322
|
),
|
|
278
323
|
openLearnMore: () => set({ homeScreen: "learnMore" }),
|
|
279
324
|
backToHome: () => set({ homeScreen: "home" }),
|
|
280
|
-
waitForStart: () => new Promise((
|
|
325
|
+
waitForStart: () => new Promise((resolve6) => {
|
|
281
326
|
if (get().phase !== "idle") {
|
|
282
|
-
|
|
327
|
+
resolve6();
|
|
283
328
|
return;
|
|
284
329
|
}
|
|
285
330
|
const unsubscribe = useWizard.subscribe((s) => {
|
|
286
331
|
if (s.phase !== "idle") {
|
|
287
332
|
unsubscribe();
|
|
288
|
-
|
|
333
|
+
resolve6();
|
|
289
334
|
}
|
|
290
335
|
});
|
|
291
336
|
}),
|
|
@@ -392,11 +437,11 @@ var useWizard = create((set, get) => ({
|
|
|
392
437
|
(t) => t.id === id ? { ...t, status, durationMs: Date.now() - t.startedAt } : t
|
|
393
438
|
)
|
|
394
439
|
})),
|
|
395
|
-
requestUserInput: (req) => new Promise((
|
|
440
|
+
requestUserInput: (req) => new Promise((resolve6) => {
|
|
396
441
|
set({
|
|
397
442
|
phase: "awaitingInput",
|
|
398
443
|
inputReq: req,
|
|
399
|
-
_resolve:
|
|
444
|
+
_resolve: resolve6,
|
|
400
445
|
loadingMessage: null
|
|
401
446
|
});
|
|
402
447
|
}),
|
|
@@ -2234,6 +2279,7 @@ async function promptForApplication(highlight) {
|
|
|
2234
2279
|
}
|
|
2235
2280
|
async function promptToChangeApplication(currentId) {
|
|
2236
2281
|
const store = useWizard.getState();
|
|
2282
|
+
store.clearNotices();
|
|
2237
2283
|
store.setLoadingMessage("Loading applications\u2026");
|
|
2238
2284
|
try {
|
|
2239
2285
|
const env = await findEnvApplicationId();
|
|
@@ -2260,7 +2306,7 @@ async function ensureApplication(resumeAppId) {
|
|
|
2260
2306
|
// package.json
|
|
2261
2307
|
var package_default = {
|
|
2262
2308
|
name: "@algolia/wizard",
|
|
2263
|
-
version: "0.
|
|
2309
|
+
version: "0.77.0",
|
|
2264
2310
|
description: "Magically implement Algolia functionality in your codebase",
|
|
2265
2311
|
type: "module",
|
|
2266
2312
|
engines: {
|
|
@@ -3314,10 +3360,10 @@ var GIT_ENV_OVERRIDES = [
|
|
|
3314
3360
|
function gitSucceeds(root, args) {
|
|
3315
3361
|
const env = { ...process.env };
|
|
3316
3362
|
for (const key of GIT_ENV_OVERRIDES) delete env[key];
|
|
3317
|
-
return new Promise((
|
|
3363
|
+
return new Promise((resolve6) => {
|
|
3318
3364
|
execFile("git", ["-C", root, ...args], { env }, (err) => {
|
|
3319
|
-
if (!err) return
|
|
3320
|
-
|
|
3365
|
+
if (!err) return resolve6(true);
|
|
3366
|
+
resolve6(
|
|
3321
3367
|
err.code === 1 ? false : void 0
|
|
3322
3368
|
);
|
|
3323
3369
|
});
|
|
@@ -3603,7 +3649,7 @@ import { tool as tool8 } from "ai";
|
|
|
3603
3649
|
import z15 from "zod";
|
|
3604
3650
|
import { createHash as createHash2 } from "node:crypto";
|
|
3605
3651
|
import { readFile as readFile8, stat as stat2 } from "node:fs/promises";
|
|
3606
|
-
import { relative as relative4 } from "node:path";
|
|
3652
|
+
import { basename as basename2, relative as relative4, resolve as resolve3 } from "node:path";
|
|
3607
3653
|
|
|
3608
3654
|
// src/lib/tools/utils/prompt.ts
|
|
3609
3655
|
var chain = Promise.resolve();
|
|
@@ -3623,11 +3669,92 @@ async function fileDigest(filePath) {
|
|
|
3623
3669
|
function grantReviewedCommandApproval(ctx, approval) {
|
|
3624
3670
|
reviewedCommandApprovals.set(ctx, approval);
|
|
3625
3671
|
}
|
|
3672
|
+
function scriptOperandTokens(command) {
|
|
3673
|
+
const tokens = [];
|
|
3674
|
+
let token = "";
|
|
3675
|
+
let quote = null;
|
|
3676
|
+
let escaped = false;
|
|
3677
|
+
let comment = false;
|
|
3678
|
+
let skipNext = false;
|
|
3679
|
+
let stop = false;
|
|
3680
|
+
const windowsPaths = process.platform === "win32";
|
|
3681
|
+
const finishToken = () => {
|
|
3682
|
+
if (token) {
|
|
3683
|
+
if (!stop) {
|
|
3684
|
+
if (skipNext) skipNext = false;
|
|
3685
|
+
else tokens.push(token);
|
|
3686
|
+
}
|
|
3687
|
+
}
|
|
3688
|
+
token = "";
|
|
3689
|
+
};
|
|
3690
|
+
for (const character of command) {
|
|
3691
|
+
if (stop) break;
|
|
3692
|
+
if (comment) {
|
|
3693
|
+
if (character === "\n") comment = false;
|
|
3694
|
+
continue;
|
|
3695
|
+
}
|
|
3696
|
+
if (escaped) {
|
|
3697
|
+
token += character;
|
|
3698
|
+
escaped = false;
|
|
3699
|
+
continue;
|
|
3700
|
+
}
|
|
3701
|
+
if (quote) {
|
|
3702
|
+
if (character === quote) quote = null;
|
|
3703
|
+
else if (quote === '"' && character === "\\") escaped = true;
|
|
3704
|
+
else token += character;
|
|
3705
|
+
continue;
|
|
3706
|
+
}
|
|
3707
|
+
if (character === "\\") {
|
|
3708
|
+
if (windowsPaths) token += character;
|
|
3709
|
+
else escaped = true;
|
|
3710
|
+
} else if (character === '"' || character === "'") {
|
|
3711
|
+
quote = character;
|
|
3712
|
+
} else if (character === "#" && token === "") {
|
|
3713
|
+
comment = true;
|
|
3714
|
+
} else if (character === ">" || character === "<") {
|
|
3715
|
+
finishToken();
|
|
3716
|
+
skipNext = true;
|
|
3717
|
+
} else if (character === "|" || character === "&" || character === ";") {
|
|
3718
|
+
finishToken();
|
|
3719
|
+
stop = true;
|
|
3720
|
+
} else if (/\s/.test(character) || "()".includes(character)) {
|
|
3721
|
+
finishToken();
|
|
3722
|
+
} else {
|
|
3723
|
+
token += character;
|
|
3724
|
+
}
|
|
3725
|
+
}
|
|
3726
|
+
finishToken();
|
|
3727
|
+
return tokens;
|
|
3728
|
+
}
|
|
3729
|
+
function tokenResolvesToScript(cwd, token, scriptPath) {
|
|
3730
|
+
if (resolve3(cwd, token) === scriptPath) return true;
|
|
3731
|
+
if (!token.includes("\\")) return false;
|
|
3732
|
+
return resolve3(cwd, token.replaceAll("\\", "/")) === scriptPath;
|
|
3733
|
+
}
|
|
3734
|
+
function commandReferencesScript(command, scriptPath, cwd) {
|
|
3735
|
+
return scriptOperandTokens(command).some(
|
|
3736
|
+
(token) => tokenResolvesToScript(cwd, token, scriptPath)
|
|
3737
|
+
);
|
|
3738
|
+
}
|
|
3626
3739
|
function getReviewedCommandApproval(ctx, command, cwd) {
|
|
3627
3740
|
const approval = reviewedCommandApprovals.get(ctx);
|
|
3628
3741
|
if (approval?.command !== command || approval.cwd !== cwd) return void 0;
|
|
3629
3742
|
return approval;
|
|
3630
3743
|
}
|
|
3744
|
+
function commandDiffersFromReviewedScript(ctx, command, cwd) {
|
|
3745
|
+
const approval = reviewedCommandApprovals.get(ctx);
|
|
3746
|
+
if (approval === void 0) return false;
|
|
3747
|
+
if (approval.command === command && approval.cwd === cwd) return false;
|
|
3748
|
+
if (approval.command === command) return true;
|
|
3749
|
+
const scriptReferences = [
|
|
3750
|
+
basename2(approval.filePath),
|
|
3751
|
+
relative4(ctx.root, approval.filePath),
|
|
3752
|
+
".algolia-wizard"
|
|
3753
|
+
];
|
|
3754
|
+
return scriptReferences.some(
|
|
3755
|
+
(reference) => reference !== "" && command.includes(reference)
|
|
3756
|
+
);
|
|
3757
|
+
}
|
|
3631
3758
|
function clearReviewedCommandApproval(ctx) {
|
|
3632
3759
|
reviewedCommandApprovals.delete(ctx);
|
|
3633
3760
|
}
|
|
@@ -3682,6 +3809,14 @@ function reviewScriptTool(ctx) {
|
|
|
3682
3809
|
if (!isFile) {
|
|
3683
3810
|
return `Refused: ${filePath} is not a file. Write the script first, then review the path you wrote.`;
|
|
3684
3811
|
}
|
|
3812
|
+
const relativeScriptPath = relative4(resolvedCwd.target, resolved2.target);
|
|
3813
|
+
if (!commandReferencesScript(
|
|
3814
|
+
command,
|
|
3815
|
+
resolved2.target,
|
|
3816
|
+
resolvedCwd.target
|
|
3817
|
+
)) {
|
|
3818
|
+
return `Refused: the command does not reference the reviewed script from its cwd. Use "${relativeScriptPath}" as the script path, then call reviewScript again.`;
|
|
3819
|
+
}
|
|
3685
3820
|
const reviewedDigest = await fileDigest(resolved2.target).catch(
|
|
3686
3821
|
() => null
|
|
3687
3822
|
);
|
|
@@ -3773,7 +3908,7 @@ var SIGKILL_DELAY_MS = 5e3;
|
|
|
3773
3908
|
function runShell(command, opts) {
|
|
3774
3909
|
const timeoutMs = opts.timeoutMs ?? DEFAULT_SHELL_TIMEOUT_MS;
|
|
3775
3910
|
const startedAt = Date.now();
|
|
3776
|
-
return new Promise((
|
|
3911
|
+
return new Promise((resolve6) => {
|
|
3777
3912
|
let output = "";
|
|
3778
3913
|
let timedOut = false;
|
|
3779
3914
|
let settled = false;
|
|
@@ -3788,7 +3923,7 @@ function runShell(command, opts) {
|
|
|
3788
3923
|
settled = true;
|
|
3789
3924
|
clearTimeout(timer);
|
|
3790
3925
|
clearTimeout(killTimer);
|
|
3791
|
-
|
|
3926
|
+
resolve6({
|
|
3792
3927
|
exitCode,
|
|
3793
3928
|
output: truncateText(output.trim()),
|
|
3794
3929
|
timedOut,
|
|
@@ -4071,6 +4206,7 @@ async function classifyCommandSafety(createModel, command, cwd, explanation, app
|
|
|
4071
4206
|
prompt: [
|
|
4072
4207
|
"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.",
|
|
4073
4208
|
"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.",
|
|
4209
|
+
"Never judge a command SAFE if it runs, imports, requires, or otherwise references an ingestion script or any path under `.algolia-wizard/`. This rule includes shell wrappers, inline code, variable indirection, and dry-run or check descriptions. Such a command always requires explicit user approval.",
|
|
4074
4210
|
"Three broad categories are safe, and most commands you will see fall into one of them:",
|
|
4075
4211
|
"(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.",
|
|
4076
4212
|
'(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.',
|
|
@@ -4198,6 +4334,9 @@ function runShellTool(ctx, createModel = defaultCreateModel) {
|
|
|
4198
4334
|
() => runReviewedCommand(ctx, command, resolved2.target)
|
|
4199
4335
|
);
|
|
4200
4336
|
if (reviewed !== void 0) return reviewed;
|
|
4337
|
+
if (commandDiffersFromReviewedScript(ctx, command, resolved2.target)) {
|
|
4338
|
+
return "Refused: this ingestion command differs from the reviewed command. Call reviewScript with this exact command and cwd before runShell.";
|
|
4339
|
+
}
|
|
4201
4340
|
const fast = fastPathSafety(command);
|
|
4202
4341
|
let isSafe = fast;
|
|
4203
4342
|
let usedStoredApproval = false;
|
|
@@ -5209,15 +5348,15 @@ ${formatCompletedSteps(ctx.completedSteps)}`,
|
|
|
5209
5348
|
// src/actions/implement.ts
|
|
5210
5349
|
import z28 from "zod";
|
|
5211
5350
|
import { access, mkdir as mkdir5, readFile as readFile9 } from "node:fs/promises";
|
|
5212
|
-
import { dirname as dirname5, isAbsolute as isAbsolute3, join as join11, relative as relative6, resolve as
|
|
5351
|
+
import { dirname as dirname5, isAbsolute as isAbsolute3, join as join11, relative as relative6, resolve as resolve5, sep as sep2 } from "node:path";
|
|
5213
5352
|
|
|
5214
5353
|
// src/lib/git.ts
|
|
5215
5354
|
import { execFile as execFile2 } from "node:child_process";
|
|
5216
5355
|
import { copyFile, mkdir as mkdir4, stat as stat3 } from "node:fs/promises";
|
|
5217
|
-
import { basename as
|
|
5356
|
+
import { basename as basename3, dirname as dirname3, isAbsolute as isAbsolute2, join as join9, resolve as resolve4 } from "node:path";
|
|
5218
5357
|
var MAX_BUFFER = 32 * 1024 * 1024;
|
|
5219
5358
|
function git(args) {
|
|
5220
|
-
return new Promise((
|
|
5359
|
+
return new Promise((resolve6, reject) => {
|
|
5221
5360
|
execFile2("git", args, { maxBuffer: MAX_BUFFER }, (err, stdout, stderr) => {
|
|
5222
5361
|
if (err)
|
|
5223
5362
|
return reject(
|
|
@@ -5225,7 +5364,7 @@ function git(args) {
|
|
|
5225
5364
|
`git ${args.join(" ")} failed: ${stderr.toString().trim() || err.message}`
|
|
5226
5365
|
)
|
|
5227
5366
|
);
|
|
5228
|
-
|
|
5367
|
+
resolve6(stdout.toString());
|
|
5229
5368
|
});
|
|
5230
5369
|
});
|
|
5231
5370
|
}
|
|
@@ -5243,7 +5382,7 @@ async function copyUploadIntoProject(repoRoot, ingestDir, sourcePath) {
|
|
|
5243
5382
|
if (!trimmed) {
|
|
5244
5383
|
return { ok: false, reason: "no file path was provided" };
|
|
5245
5384
|
}
|
|
5246
|
-
const source = isAbsolute2(trimmed) ? trimmed :
|
|
5385
|
+
const source = isAbsolute2(trimmed) ? trimmed : resolve4(repoRoot, trimmed);
|
|
5247
5386
|
try {
|
|
5248
5387
|
if (!(await stat3(source)).isFile()) {
|
|
5249
5388
|
return { ok: false, reason: `"${sourcePath}" is not a file` };
|
|
@@ -5251,9 +5390,9 @@ async function copyUploadIntoProject(repoRoot, ingestDir, sourcePath) {
|
|
|
5251
5390
|
} catch {
|
|
5252
5391
|
return { ok: false, reason: `"${sourcePath}" does not exist` };
|
|
5253
5392
|
}
|
|
5254
|
-
const relPath = join9(ingestDir,
|
|
5393
|
+
const relPath = join9(ingestDir, basename3(source));
|
|
5255
5394
|
const dest = join9(repoRoot, relPath);
|
|
5256
|
-
if (
|
|
5395
|
+
if (resolve4(source) === resolve4(dest)) {
|
|
5257
5396
|
return { ok: true, relPath };
|
|
5258
5397
|
}
|
|
5259
5398
|
try {
|
|
@@ -5477,8 +5616,16 @@ function ingestionInstructions(input) {
|
|
|
5477
5616
|
...algoliaClientDoc(input),
|
|
5478
5617
|
"Install the Algolia client with the project's own package manager via runShell, declaring it in whatever manifest the project uses (e.g. package.json, requirements.txt, Gemfile, go.mod, composer.json) so the dependency is not just installed ad hoc.",
|
|
5479
5618
|
`If the script loads its env vars from a file (e.g. via dotenv or an equivalent for its language) rather than the process environment directly, decide that up front and call writeCredentials on that file before you finish the script \u2014 do not wait to discover the need for it by having a writeFile call refused.`,
|
|
5480
|
-
|
|
5619
|
+
"Before reviewScript, only use a non-executing parse check such as `node --check <script>` or `python -m py_compile <script>`. Never import, require, run, or dry-run the ingestion script before reviewScript returns.",
|
|
5620
|
+
"Check installed dependency presence at the manifest level, such as `npm ls <package>` or `pip show <package>`. Do not load the ingestion script to resolve dependencies.",
|
|
5621
|
+
...isJsProject(input.language) ? [
|
|
5622
|
+
"For Node.js, module resolution starts from the script path, not the cwd."
|
|
5623
|
+
] : [],
|
|
5624
|
+
`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.`,
|
|
5481
5625
|
'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.',
|
|
5626
|
+
"If external data access fails, do not run authentication commands, change accounts or machine configuration, or start proxies, containers, or services.",
|
|
5627
|
+
"Do not troubleshoot unavailable external infrastructure. Preserve the script and command, report success, and let the developer prepare the data source.",
|
|
5628
|
+
"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.",
|
|
5482
5629
|
"The summary should be extremely concise.",
|
|
5483
5630
|
...sourceSpecificInstructions(input)
|
|
5484
5631
|
] : []
|
|
@@ -5630,15 +5777,30 @@ function parseIngestRecordCount(output) {
|
|
|
5630
5777
|
const count = Number(match[1]);
|
|
5631
5778
|
return Number.isFinite(count) ? count : void 0;
|
|
5632
5779
|
}
|
|
5633
|
-
function
|
|
5780
|
+
function relativeIngestCwd(execution, repoRoot) {
|
|
5781
|
+
const cwd = relative6(repoRoot, execution.cwd);
|
|
5782
|
+
return cwd && cwd !== "." ? cwd : ".";
|
|
5783
|
+
}
|
|
5784
|
+
function reportedCommandWithCwdNote(execution, repoRoot) {
|
|
5785
|
+
const cwd = relativeIngestCwd(execution, repoRoot);
|
|
5786
|
+
return cwd === "." ? execution.command : `${execution.command} (run from ${cwd})`;
|
|
5787
|
+
}
|
|
5788
|
+
function ingestOutcome(executions, repoRoot, ingestCommand) {
|
|
5634
5789
|
const newestFirst = [...executions].reverse();
|
|
5790
|
+
const matchesReportedCommand = (execution) => {
|
|
5791
|
+
if (execution.command === ingestCommand) return true;
|
|
5792
|
+
if (!ingestCommand) return false;
|
|
5793
|
+
return ingestCommand === reportedCommandWithCwdNote(execution, repoRoot);
|
|
5794
|
+
};
|
|
5635
5795
|
const withCount = newestFirst.filter(
|
|
5636
5796
|
(e) => parseIngestRecordCount(e.output ?? "") != null
|
|
5637
5797
|
);
|
|
5638
|
-
const succeeded = newestFirst.filter(
|
|
5798
|
+
const succeeded = newestFirst.filter(
|
|
5799
|
+
(e) => e.approved && e.exitCode === 0 && !e.timedOut
|
|
5800
|
+
);
|
|
5639
5801
|
return {
|
|
5640
|
-
run: succeeded.find(
|
|
5641
|
-
attempt: ingestCommand ? newestFirst.find(
|
|
5802
|
+
run: succeeded.find(matchesReportedCommand) ?? succeeded.find((e) => withCount.includes(e)),
|
|
5803
|
+
attempt: ingestCommand ? newestFirst.find(matchesReportedCommand) : void 0,
|
|
5642
5804
|
recordCount: parseIngestRecordCount(withCount[0]?.output ?? "")
|
|
5643
5805
|
};
|
|
5644
5806
|
}
|
|
@@ -5732,7 +5894,7 @@ async function pathExists(path) {
|
|
|
5732
5894
|
async function frontendHasPackageJson(repoRoot, searchLocation) {
|
|
5733
5895
|
let directory = repoRoot;
|
|
5734
5896
|
if (searchLocation) {
|
|
5735
|
-
const candidate = dirname5(
|
|
5897
|
+
const candidate = dirname5(resolve5(repoRoot, searchLocation));
|
|
5736
5898
|
const candidateRelative = relative6(repoRoot, candidate);
|
|
5737
5899
|
const outsideRoot = candidateRelative === ".." || candidateRelative.startsWith(`..${sep2}`) || isAbsolute3(candidateRelative);
|
|
5738
5900
|
if (!outsideRoot) directory = candidate;
|
|
@@ -5985,7 +6147,12 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
|
|
|
5985
6147
|
run: ingestRun,
|
|
5986
6148
|
attempt: ingestAttempt,
|
|
5987
6149
|
recordCount
|
|
5988
|
-
} = ingestOutcome(executions, ingestCommand);
|
|
6150
|
+
} = ingestOutcome(executions, repoRoot, ingestCommand);
|
|
6151
|
+
let ingestCwd = ".";
|
|
6152
|
+
if (ingestAttempt) {
|
|
6153
|
+
ingestCommand = ingestAttempt.command;
|
|
6154
|
+
ingestCwd = relativeIngestCwd(ingestAttempt, repoRoot);
|
|
6155
|
+
}
|
|
5989
6156
|
ingestScriptRan = ingestRun != null;
|
|
5990
6157
|
ingestRecordCount = recordCount;
|
|
5991
6158
|
ingestDurationMs = ingestRun?.durationMs;
|
|
@@ -6061,7 +6228,10 @@ ${detail}` : ""}`
|
|
|
6061
6228
|
]
|
|
6062
6229
|
});
|
|
6063
6230
|
} else {
|
|
6064
|
-
const commandMessages = ingestCommand ? [
|
|
6231
|
+
const commandMessages = ingestCommand ? [
|
|
6232
|
+
`Ingestion command: ${ingestCommand}`,
|
|
6233
|
+
...ingestCwd !== "." ? [`Working directory: ${ingestCwd}`] : []
|
|
6234
|
+
] : [];
|
|
6065
6235
|
await ctx.requestUserInput({
|
|
6066
6236
|
prompt: "",
|
|
6067
6237
|
promptType: "enterToContinue",
|
|
@@ -6314,6 +6484,9 @@ var defaultWorkflow = {
|
|
|
6314
6484
|
]
|
|
6315
6485
|
};
|
|
6316
6486
|
|
|
6487
|
+
// src/workflows/playbook.ts
|
|
6488
|
+
import "zod";
|
|
6489
|
+
|
|
6317
6490
|
// src/actions/playbookSteps/selectPlaybook.ts
|
|
6318
6491
|
import { z as z32 } from "zod";
|
|
6319
6492
|
|
|
@@ -6333,6 +6506,16 @@ var DashboardApiError = class extends Error {
|
|
|
6333
6506
|
return isRecord(this.body) ? this.body : void 0;
|
|
6334
6507
|
}
|
|
6335
6508
|
};
|
|
6509
|
+
async function retryOnDashboardError(call, recover) {
|
|
6510
|
+
for (; ; ) {
|
|
6511
|
+
try {
|
|
6512
|
+
return await call();
|
|
6513
|
+
} catch (err) {
|
|
6514
|
+
if (!(err instanceof DashboardApiError)) throw err;
|
|
6515
|
+
await recover(err);
|
|
6516
|
+
}
|
|
6517
|
+
}
|
|
6518
|
+
}
|
|
6336
6519
|
function isRecord(value) {
|
|
6337
6520
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
6338
6521
|
}
|
|
@@ -6435,6 +6618,21 @@ async function getPlaybooks() {
|
|
|
6435
6618
|
);
|
|
6436
6619
|
return data;
|
|
6437
6620
|
}
|
|
6621
|
+
async function createPlaybookExecution(appId, slug, indexName, options) {
|
|
6622
|
+
const { data } = await dashboardRequest(
|
|
6623
|
+
`/api/1/playbook-integrations/applications/${appId}/playbooks/${slug}/executions`,
|
|
6624
|
+
playbookExecutionCreateResponseSchema,
|
|
6625
|
+
{
|
|
6626
|
+
method: "POST",
|
|
6627
|
+
headers: { "content-type": "application/json" },
|
|
6628
|
+
body: JSON.stringify({
|
|
6629
|
+
index_name: indexName,
|
|
6630
|
+
force_new: options?.forceNew ?? false
|
|
6631
|
+
})
|
|
6632
|
+
}
|
|
6633
|
+
);
|
|
6634
|
+
return data;
|
|
6635
|
+
}
|
|
6438
6636
|
async function createSampleIndex(appId, playbookSlug) {
|
|
6439
6637
|
const { data } = await dashboardRequest(
|
|
6440
6638
|
`/api/1/playbook-integrations/applications/${appId}/playbooks/${playbookSlug}/sample_index`,
|
|
@@ -6443,6 +6641,20 @@ async function createSampleIndex(appId, playbookSlug) {
|
|
|
6443
6641
|
);
|
|
6444
6642
|
return data;
|
|
6445
6643
|
}
|
|
6644
|
+
async function getPlaybookExecution(uuid) {
|
|
6645
|
+
const { data } = await dashboardRequest(
|
|
6646
|
+
`/api/1/playbook-integrations/playbooks/executions/${uuid}`,
|
|
6647
|
+
playbookExecutionSchema
|
|
6648
|
+
);
|
|
6649
|
+
return data;
|
|
6650
|
+
}
|
|
6651
|
+
async function assessPlaybookExecution(uuid) {
|
|
6652
|
+
await dashboardRequest(
|
|
6653
|
+
`/api/1/playbook-integrations/playbooks/executions/${uuid}/assess`,
|
|
6654
|
+
messageResponseSchema,
|
|
6655
|
+
{ method: "POST" }
|
|
6656
|
+
);
|
|
6657
|
+
}
|
|
6446
6658
|
|
|
6447
6659
|
// src/actions/playbookSteps/selectPlaybook.ts
|
|
6448
6660
|
var selectPlaybookSchema = z32.object({
|
|
@@ -6477,45 +6689,15 @@ async function selectPlaybookStep(ctx, requestedSlug) {
|
|
|
6477
6689
|
return persistSlug(ctx, selection);
|
|
6478
6690
|
}
|
|
6479
6691
|
|
|
6480
|
-
// src/actions/playbookSteps/confirmPlaybook.ts
|
|
6481
|
-
import { z as z33 } from "zod";
|
|
6482
|
-
var confirmPlaybookSchema = z33.void();
|
|
6483
|
-
var CONTINUE_OPTION = "Looks good, continue";
|
|
6484
|
-
var GO_BACK_OPTION = "Go back";
|
|
6485
|
-
var SELECT_APP_OPTION = "Select app";
|
|
6486
|
-
async function confirmPlaybookStep(ctx) {
|
|
6487
|
-
const { slug } = ctx.getStepOutput("select-playbook");
|
|
6488
|
-
for (; ; ) {
|
|
6489
|
-
const selection = await ctx.requestUserInput({
|
|
6490
|
-
prompt: "Ready to continue?",
|
|
6491
|
-
promptType: "multipleChoice",
|
|
6492
|
-
options: [CONTINUE_OPTION, GO_BACK_OPTION, SELECT_APP_OPTION],
|
|
6493
|
-
messages: [`Playbook: ${slug}`, `Application: ${ctx.appId}`],
|
|
6494
|
-
helpText: "Going back re-opens the playbook catalogue. Select app opens the application catalogue \u2014 keep the current app to stay here, or pick another to restart the wizard."
|
|
6495
|
-
});
|
|
6496
|
-
if (typeof selection !== "string") {
|
|
6497
|
-
throw new Error("confirm-playbook received an unexpected result");
|
|
6498
|
-
}
|
|
6499
|
-
if (selection === SELECT_APP_OPTION) {
|
|
6500
|
-
await ctx.changeApplication();
|
|
6501
|
-
continue;
|
|
6502
|
-
}
|
|
6503
|
-
if (selection === GO_BACK_OPTION) {
|
|
6504
|
-
return ctx.returnToStep("select-playbook");
|
|
6505
|
-
}
|
|
6506
|
-
return;
|
|
6507
|
-
}
|
|
6508
|
-
}
|
|
6509
|
-
|
|
6510
6692
|
// src/actions/playbookSteps/selectIndex.ts
|
|
6511
|
-
import { z as
|
|
6512
|
-
var selectIndexSchema =
|
|
6513
|
-
indexName:
|
|
6514
|
-
sampleIndex:
|
|
6693
|
+
import { z as z33 } from "zod";
|
|
6694
|
+
var selectIndexSchema = z33.object({
|
|
6695
|
+
indexName: z33.string(),
|
|
6696
|
+
sampleIndex: z33.boolean()
|
|
6515
6697
|
});
|
|
6516
6698
|
var CREATE_SAMPLE_INDEX = "Create a sample index";
|
|
6517
|
-
var
|
|
6518
|
-
var
|
|
6699
|
+
var GO_BACK_OPTION = "Go back to playbook selection";
|
|
6700
|
+
var SELECT_APP_OPTION = "Select app";
|
|
6519
6701
|
var MIN_ENTRIES_FOR_SELECTION = 1;
|
|
6520
6702
|
function formatIndexOption(index) {
|
|
6521
6703
|
if (index.entries < MIN_ENTRIES_FOR_SELECTION) {
|
|
@@ -6541,8 +6723,8 @@ async function selectIndexStep2(ctx) {
|
|
|
6541
6723
|
const options = [
|
|
6542
6724
|
...indexOptions,
|
|
6543
6725
|
CREATE_SAMPLE_INDEX,
|
|
6544
|
-
|
|
6545
|
-
|
|
6726
|
+
GO_BACK_OPTION,
|
|
6727
|
+
SELECT_APP_OPTION
|
|
6546
6728
|
];
|
|
6547
6729
|
const disabled = hasIndices ? [
|
|
6548
6730
|
...indices.map((idx) => !isIndexSelectable(idx)),
|
|
@@ -6571,11 +6753,11 @@ you can explore or switch to another application`;
|
|
|
6571
6753
|
"selectIndex received an unexpected non-text result"
|
|
6572
6754
|
);
|
|
6573
6755
|
}
|
|
6574
|
-
if (selection ===
|
|
6756
|
+
if (selection === GO_BACK_OPTION) {
|
|
6575
6757
|
ctx.setUserInput("fetchedIndices", void 0);
|
|
6576
6758
|
return ctx.returnToStep("select-playbook");
|
|
6577
6759
|
}
|
|
6578
|
-
if (selection ===
|
|
6760
|
+
if (selection === SELECT_APP_OPTION) {
|
|
6579
6761
|
await ctx.changeApplication();
|
|
6580
6762
|
continue;
|
|
6581
6763
|
}
|
|
@@ -6604,8 +6786,8 @@ you can explore or switch to another application`;
|
|
|
6604
6786
|
// src/actions/playbookSteps/confirmIndex.ts
|
|
6605
6787
|
import "zod";
|
|
6606
6788
|
var confirmIndexSchema = playbookExecutionSchema.nullable();
|
|
6607
|
-
var
|
|
6608
|
-
var
|
|
6789
|
+
var CONTINUE_OPTION = "Looks good, continue";
|
|
6790
|
+
var GO_BACK_OPTION2 = "Go back";
|
|
6609
6791
|
async function confirmIndexStep(ctx) {
|
|
6610
6792
|
const { sampleIndex } = ctx.getStepOutput("select-index");
|
|
6611
6793
|
if (!sampleIndex) {
|
|
@@ -6615,7 +6797,7 @@ async function confirmIndexStep(ctx) {
|
|
|
6615
6797
|
const selection = await ctx.requestUserInput({
|
|
6616
6798
|
prompt: "Ready to create sample index?",
|
|
6617
6799
|
promptType: "multipleChoice",
|
|
6618
|
-
options: [
|
|
6800
|
+
options: [CONTINUE_OPTION, GO_BACK_OPTION2],
|
|
6619
6801
|
messages: [
|
|
6620
6802
|
`A new index called "algolia_playbooks_${slug}_sample_index" will be created with sample ${slug} data.`
|
|
6621
6803
|
],
|
|
@@ -6624,7 +6806,7 @@ async function confirmIndexStep(ctx) {
|
|
|
6624
6806
|
if (typeof selection !== "string") {
|
|
6625
6807
|
throw new Error("confirm-index received an unexpected result");
|
|
6626
6808
|
}
|
|
6627
|
-
if (selection ===
|
|
6809
|
+
if (selection === GO_BACK_OPTION2) {
|
|
6628
6810
|
return ctx.returnToStep("select-index");
|
|
6629
6811
|
}
|
|
6630
6812
|
ctx.notify({
|
|
@@ -6654,6 +6836,227 @@ async function confirmIndexStep(ctx) {
|
|
|
6654
6836
|
}
|
|
6655
6837
|
}
|
|
6656
6838
|
|
|
6839
|
+
// src/actions/playbookSteps/dataAssessment.ts
|
|
6840
|
+
var CONTINUE_EXECUTION_OPTION = "Continue";
|
|
6841
|
+
var RESTART_OPTION = "Restart";
|
|
6842
|
+
var GO_BACK_OPTION3 = "Go back";
|
|
6843
|
+
var SWITCH_APPLICATION_OPTION = "Switch application";
|
|
6844
|
+
var SWITCH_INDEX_OPTION = "Switch index";
|
|
6845
|
+
var RETRY_OPTION = "Retry";
|
|
6846
|
+
var POLL_INTERVAL_MS = 5e3;
|
|
6847
|
+
var POLL_TIMEOUT_MS = 6e4;
|
|
6848
|
+
var ASSESSING_NOTICE_HOLD_MS = 2e4;
|
|
6849
|
+
var CREATING_EXECUTION_NOTICE = "creating playbook execution\u2026";
|
|
6850
|
+
var POLL_NOTICES = [
|
|
6851
|
+
{ message: "created playbook execution", holdMs: POLL_INTERVAL_MS },
|
|
6852
|
+
{ message: "sampled records", holdMs: POLL_INTERVAL_MS },
|
|
6853
|
+
{
|
|
6854
|
+
message: "assessing schema and readiness \u2014 this usually takes ~20s for indices under 1M records.",
|
|
6855
|
+
holdMs: ASSESSING_NOTICE_HOLD_MS
|
|
6856
|
+
},
|
|
6857
|
+
{ message: "detecting required fields\u2026" }
|
|
6858
|
+
];
|
|
6859
|
+
async function dataAssessmentStep(ctx) {
|
|
6860
|
+
const { slug } = ctx.getStepOutput("select-playbook");
|
|
6861
|
+
const { indexName, existingExecution } = indexForAssessment(ctx);
|
|
6862
|
+
if (existingExecution) return existingExecution;
|
|
6863
|
+
try {
|
|
6864
|
+
showNotice(ctx, CREATING_EXECUTION_NOTICE);
|
|
6865
|
+
const { id: appId } = await requireApplication();
|
|
6866
|
+
const execution = await resolveExecution(ctx, appId, slug, indexName);
|
|
6867
|
+
return await runAssessment(ctx, execution, indexName);
|
|
6868
|
+
} finally {
|
|
6869
|
+
ctx.clearNotices();
|
|
6870
|
+
}
|
|
6871
|
+
}
|
|
6872
|
+
function indexForAssessment(ctx) {
|
|
6873
|
+
const selected = ctx.getStepOutput("select-index");
|
|
6874
|
+
if (!selected.sampleIndex) {
|
|
6875
|
+
return { indexName: selected.indexName, existingExecution: null };
|
|
6876
|
+
}
|
|
6877
|
+
const created = ctx.getStepOutput("confirm-index");
|
|
6878
|
+
if (!created) {
|
|
6879
|
+
throw new Error(
|
|
6880
|
+
"data-assessment expected confirm-index to create a sample index"
|
|
6881
|
+
);
|
|
6882
|
+
}
|
|
6883
|
+
return {
|
|
6884
|
+
indexName: created.source_index_name,
|
|
6885
|
+
existingExecution: created
|
|
6886
|
+
};
|
|
6887
|
+
}
|
|
6888
|
+
function showNotice(ctx, message) {
|
|
6889
|
+
ctx.clearNotices();
|
|
6890
|
+
ctx.notify({ messages: [message] });
|
|
6891
|
+
}
|
|
6892
|
+
function startPollNotices(ctx) {
|
|
6893
|
+
let index = 0;
|
|
6894
|
+
let timer;
|
|
6895
|
+
const showCurrent = () => {
|
|
6896
|
+
const notice = POLL_NOTICES[index];
|
|
6897
|
+
showNotice(ctx, notice.message);
|
|
6898
|
+
if (notice.holdMs == null) return;
|
|
6899
|
+
timer = setTimeout(() => {
|
|
6900
|
+
index += 1;
|
|
6901
|
+
showCurrent();
|
|
6902
|
+
}, notice.holdMs);
|
|
6903
|
+
};
|
|
6904
|
+
showCurrent();
|
|
6905
|
+
return () => clearTimeout(timer);
|
|
6906
|
+
}
|
|
6907
|
+
async function runAssessment(ctx, execution, indexName) {
|
|
6908
|
+
if (execution.step_status === "done") {
|
|
6909
|
+
return execution;
|
|
6910
|
+
}
|
|
6911
|
+
if (execution.step_status === "not_started" || execution.step_status === "error") {
|
|
6912
|
+
await assessExecution(ctx, execution.uuid, indexName);
|
|
6913
|
+
} else if (execution.step_status !== "in_progress") {
|
|
6914
|
+
throw unexpectedAssessmentStatus(execution.step_status);
|
|
6915
|
+
}
|
|
6916
|
+
for (; ; ) {
|
|
6917
|
+
const assessed = await pollUntilAssessed(ctx, execution.uuid, indexName);
|
|
6918
|
+
if (assessed.step_status === "done") {
|
|
6919
|
+
return assessed;
|
|
6920
|
+
}
|
|
6921
|
+
if (assessed.step_status !== "error") {
|
|
6922
|
+
throw unexpectedAssessmentStatus(assessed.step_status);
|
|
6923
|
+
}
|
|
6924
|
+
await promptAssessmentRecovery(
|
|
6925
|
+
ctx,
|
|
6926
|
+
assessmentFailureMessage(assessed),
|
|
6927
|
+
assessed.status_reason === "index_empty"
|
|
6928
|
+
);
|
|
6929
|
+
await assessExecution(ctx, execution.uuid, indexName);
|
|
6930
|
+
}
|
|
6931
|
+
}
|
|
6932
|
+
function unexpectedAssessmentStatus(status) {
|
|
6933
|
+
return new Error(
|
|
6934
|
+
`data-assessment received an unexpected assessment status: ${status}`
|
|
6935
|
+
);
|
|
6936
|
+
}
|
|
6937
|
+
async function resolveExecution(ctx, appId, slug, indexName) {
|
|
6938
|
+
const created = await createWithRecovery(ctx, appId, slug, indexName);
|
|
6939
|
+
if (!created.resumed) return created;
|
|
6940
|
+
const choice = await ctx.requestUserInput({
|
|
6941
|
+
prompt: `${indexName} has a playbook in progress.`,
|
|
6942
|
+
promptType: "multipleChoice",
|
|
6943
|
+
options: [CONTINUE_EXECUTION_OPTION, RESTART_OPTION, GO_BACK_OPTION3],
|
|
6944
|
+
secondary: [{ kind: "text", value: "resume Assessment" }]
|
|
6945
|
+
});
|
|
6946
|
+
if (choice === CONTINUE_EXECUTION_OPTION) return created;
|
|
6947
|
+
if (choice === RESTART_OPTION) {
|
|
6948
|
+
return createWithRecovery(ctx, appId, slug, indexName, { forceNew: true });
|
|
6949
|
+
}
|
|
6950
|
+
if (choice === GO_BACK_OPTION3) {
|
|
6951
|
+
return ctx.returnToStep("select-index");
|
|
6952
|
+
}
|
|
6953
|
+
throw new Error("data-assessment received an unexpected execution choice");
|
|
6954
|
+
}
|
|
6955
|
+
async function createWithRecovery(ctx, appId, slug, indexName, options) {
|
|
6956
|
+
return retryOnDashboardError(
|
|
6957
|
+
() => {
|
|
6958
|
+
showNotice(ctx, CREATING_EXECUTION_NOTICE);
|
|
6959
|
+
return createPlaybookExecution(appId, slug, indexName, options);
|
|
6960
|
+
},
|
|
6961
|
+
onRequestFailure(ctx, indexName)
|
|
6962
|
+
);
|
|
6963
|
+
}
|
|
6964
|
+
function onRequestFailure(ctx, indexName) {
|
|
6965
|
+
return async (err) => {
|
|
6966
|
+
await promptAssessmentRecovery(
|
|
6967
|
+
ctx,
|
|
6968
|
+
requestFailureMessage(indexName, err),
|
|
6969
|
+
isEmptyIndexError(err)
|
|
6970
|
+
);
|
|
6971
|
+
};
|
|
6972
|
+
}
|
|
6973
|
+
function requestFailureMessage(indexName, err) {
|
|
6974
|
+
if (isEmptyIndexError(err)) {
|
|
6975
|
+
return `Index "${indexName}" has no records to assess.`;
|
|
6976
|
+
}
|
|
6977
|
+
const message = err.errorBody()?.message;
|
|
6978
|
+
if (typeof message === "string" && message.trim()) return message;
|
|
6979
|
+
return "Couldn't complete the request.";
|
|
6980
|
+
}
|
|
6981
|
+
function isEmptyIndexError(err) {
|
|
6982
|
+
const body = err.errorBody();
|
|
6983
|
+
return body?.status_reason === "index_empty" || body?.message === "index_empty";
|
|
6984
|
+
}
|
|
6985
|
+
async function pollUntilAssessed(ctx, uuid, indexName) {
|
|
6986
|
+
const logId = ctx.logStart("Assessing index data");
|
|
6987
|
+
const deadline = Date.now() + POLL_TIMEOUT_MS;
|
|
6988
|
+
let logStatus = "error";
|
|
6989
|
+
let stopNotices = startPollNotices(ctx);
|
|
6990
|
+
try {
|
|
6991
|
+
for (; ; ) {
|
|
6992
|
+
const execution = await retryOnDashboardError(
|
|
6993
|
+
() => getPlaybookExecution(uuid),
|
|
6994
|
+
async (err) => {
|
|
6995
|
+
stopNotices();
|
|
6996
|
+
ctx.clearNotices();
|
|
6997
|
+
await promptAssessmentRecovery(
|
|
6998
|
+
ctx,
|
|
6999
|
+
requestFailureMessage(indexName, err),
|
|
7000
|
+
isEmptyIndexError(err)
|
|
7001
|
+
);
|
|
7002
|
+
stopNotices = startPollNotices(ctx);
|
|
7003
|
+
}
|
|
7004
|
+
);
|
|
7005
|
+
if (execution.step_status === "done") {
|
|
7006
|
+
logStatus = "success";
|
|
7007
|
+
return execution;
|
|
7008
|
+
}
|
|
7009
|
+
if (execution.step_status === "error") {
|
|
7010
|
+
ctx.clearNotices();
|
|
7011
|
+
return execution;
|
|
7012
|
+
}
|
|
7013
|
+
if (Date.now() >= deadline) {
|
|
7014
|
+
throw new Error("Timed out waiting for the data assessment to finish.");
|
|
7015
|
+
}
|
|
7016
|
+
await sleep(POLL_INTERVAL_MS);
|
|
7017
|
+
}
|
|
7018
|
+
} catch (err) {
|
|
7019
|
+
ctx.clearNotices();
|
|
7020
|
+
throw err;
|
|
7021
|
+
} finally {
|
|
7022
|
+
stopNotices();
|
|
7023
|
+
ctx.logEnd(logId, logStatus);
|
|
7024
|
+
}
|
|
7025
|
+
}
|
|
7026
|
+
var sleep = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
7027
|
+
async function assessExecution(ctx, uuid, indexName) {
|
|
7028
|
+
await retryOnDashboardError(
|
|
7029
|
+
() => assessPlaybookExecution(uuid),
|
|
7030
|
+
onRequestFailure(ctx, indexName)
|
|
7031
|
+
);
|
|
7032
|
+
}
|
|
7033
|
+
async function promptAssessmentRecovery(ctx, message, retryDisabled) {
|
|
7034
|
+
const choice = await ctx.requestUserInput({
|
|
7035
|
+
prompt: "Data assessment failed.",
|
|
7036
|
+
promptType: "multipleChoice",
|
|
7037
|
+
options: [SWITCH_APPLICATION_OPTION, SWITCH_INDEX_OPTION, RETRY_OPTION],
|
|
7038
|
+
messages: [message],
|
|
7039
|
+
disabled: [false, false, retryDisabled],
|
|
7040
|
+
helpText: "Retry re-runs assessment on this index. Switch index or application to pick a different target."
|
|
7041
|
+
});
|
|
7042
|
+
if (choice === SWITCH_APPLICATION_OPTION) {
|
|
7043
|
+
return ctx.changeApplication();
|
|
7044
|
+
}
|
|
7045
|
+
if (choice === SWITCH_INDEX_OPTION) {
|
|
7046
|
+
return ctx.returnToStep("select-index");
|
|
7047
|
+
}
|
|
7048
|
+
if (choice === RETRY_OPTION) {
|
|
7049
|
+
return;
|
|
7050
|
+
}
|
|
7051
|
+
throw new Error("data-assessment received an unexpected recovery choice");
|
|
7052
|
+
}
|
|
7053
|
+
function assessmentFailureMessage(execution) {
|
|
7054
|
+
if (execution.status_reason === "index_empty") {
|
|
7055
|
+
return `Index "${execution.source_index_name}" has no records to assess.`;
|
|
7056
|
+
}
|
|
7057
|
+
return execution.status_reason ?? "Data assessment failed.";
|
|
7058
|
+
}
|
|
7059
|
+
|
|
6657
7060
|
// src/lib/cli.ts
|
|
6658
7061
|
var USAGE = `Usage: wizard [workflow-id] [options]
|
|
6659
7062
|
wizard playbook [playbook-slug] [options]
|
|
@@ -6721,13 +7124,6 @@ var playbookWorkflow = {
|
|
|
6721
7124
|
outputSchema: selectPlaybookSchema,
|
|
6722
7125
|
run: (ctx) => selectPlaybookStep(ctx, getPlaybookSlugArg())
|
|
6723
7126
|
}),
|
|
6724
|
-
defineStep({
|
|
6725
|
-
id: "confirm-playbook",
|
|
6726
|
-
title: "Confirm selections",
|
|
6727
|
-
outputSchema: confirmPlaybookSchema,
|
|
6728
|
-
visible: false,
|
|
6729
|
-
run: (ctx) => confirmPlaybookStep(ctx)
|
|
6730
|
-
}),
|
|
6731
7127
|
defineStep({
|
|
6732
7128
|
id: "select-index",
|
|
6733
7129
|
title: "Select index",
|
|
@@ -6742,6 +7138,12 @@ var playbookWorkflow = {
|
|
|
6742
7138
|
visible: false,
|
|
6743
7139
|
tips: ["apps-and-indices", "records-are-json", "speed"],
|
|
6744
7140
|
run: (ctx) => confirmIndexStep(ctx)
|
|
7141
|
+
}),
|
|
7142
|
+
defineStep({
|
|
7143
|
+
id: "data-assessment",
|
|
7144
|
+
title: "Assess index data",
|
|
7145
|
+
outputSchema: playbookExecutionSchema,
|
|
7146
|
+
run: (ctx) => dataAssessmentStep(ctx)
|
|
6745
7147
|
})
|
|
6746
7148
|
]
|
|
6747
7149
|
};
|
|
@@ -6759,7 +7161,19 @@ function getWorkflow(id) {
|
|
|
6759
7161
|
import { dirname as dirname6, join as join12 } from "node:path";
|
|
6760
7162
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
6761
7163
|
import { useState as useState10 } from "react";
|
|
6762
|
-
import { Box as
|
|
7164
|
+
import { Box as Box12, Spacer, Text as Text13, useInput as useInput6, useWindowSize as useWindowSize6 } from "ink";
|
|
7165
|
+
|
|
7166
|
+
// src/ui/ResizeNotice.tsx
|
|
7167
|
+
import { Box as Box11, Text as Text12, useWindowSize as useWindowSize5 } from "ink";
|
|
7168
|
+
import { jsx as jsx10, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
7169
|
+
function ResizeNotice() {
|
|
7170
|
+
const { columns, rows } = useWindowSize5();
|
|
7171
|
+
if (rows >= MIN_ROWS && columns >= MIN_COLUMNS) return null;
|
|
7172
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
|
|
7173
|
+
/* @__PURE__ */ jsx10(Text12, { color: COLORS.badge, children: `Terminal is ${columns}x${rows}. Recommended size is ${MIN_COLUMNS}x${MIN_ROWS}.` }),
|
|
7174
|
+
/* @__PURE__ */ jsx10(Text12, { color: COLORS.muted, children: "Enlarge the pane for the full layout." })
|
|
7175
|
+
] });
|
|
7176
|
+
}
|
|
6763
7177
|
|
|
6764
7178
|
// src/ui/copy/welcome.ts
|
|
6765
7179
|
var sidebarItems = [
|
|
@@ -6787,7 +7201,7 @@ var sidebarItems = [
|
|
|
6787
7201
|
|
|
6788
7202
|
// src/ui/Welcome.tsx
|
|
6789
7203
|
import Image, { TerminalInfoContext, defaultTerminalInfo } from "ink-picture";
|
|
6790
|
-
import { jsx as
|
|
7204
|
+
import { jsx as jsx11, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
6791
7205
|
var IMAGE_PATH = join12(dirname6(fileURLToPath2(import.meta.url)), "algolia.png");
|
|
6792
7206
|
var TERMINAL_INFO = {
|
|
6793
7207
|
...defaultTerminalInfo,
|
|
@@ -6798,21 +7212,23 @@ function SidebarItem({
|
|
|
6798
7212
|
title,
|
|
6799
7213
|
description
|
|
6800
7214
|
}) {
|
|
6801
|
-
return /* @__PURE__ */
|
|
6802
|
-
/* @__PURE__ */
|
|
6803
|
-
/* @__PURE__ */
|
|
6804
|
-
/* @__PURE__ */
|
|
7215
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
|
|
7216
|
+
/* @__PURE__ */ jsxs12(Box12, { gap: 1, children: [
|
|
7217
|
+
/* @__PURE__ */ jsx11(Text13, { color: COLORS.success, children: "\u2192" }),
|
|
7218
|
+
/* @__PURE__ */ jsx11(Text13, { color: COLORS.strong, bold: true, children: title })
|
|
6805
7219
|
] }),
|
|
6806
|
-
/* @__PURE__ */
|
|
6807
|
-
/* @__PURE__ */
|
|
6808
|
-
/* @__PURE__ */
|
|
7220
|
+
/* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", gap: 2, children: [
|
|
7221
|
+
/* @__PURE__ */ jsx11(Spacer, {}),
|
|
7222
|
+
/* @__PURE__ */ jsx11(Text13, { color: COLORS.muted, children: description })
|
|
6809
7223
|
] })
|
|
6810
7224
|
] });
|
|
6811
7225
|
}
|
|
6812
7226
|
function Welcome() {
|
|
6813
7227
|
const confirmStart = useWizard((s) => s.confirmStart);
|
|
6814
7228
|
const openLearnMore = useWizard((s) => s.openLearnMore);
|
|
6815
|
-
const { rows } =
|
|
7229
|
+
const { columns, rows } = useWindowSize6();
|
|
7230
|
+
const showSidebar = !isCompactTerminal(columns, rows) && columns > SIDEBAR_MIN_COLUMNS;
|
|
7231
|
+
const showLogo = showSidebar && rows >= MIN_ROWS && columns >= MIN_COLUMNS;
|
|
6816
7232
|
const actions = [
|
|
6817
7233
|
{ label: "start wizard", run: confirmStart },
|
|
6818
7234
|
{ label: "learn more", run: openLearnMore }
|
|
@@ -6838,19 +7254,20 @@ function Welcome() {
|
|
|
6838
7254
|
}
|
|
6839
7255
|
};
|
|
6840
7256
|
let layout = scales["large"];
|
|
6841
|
-
if (rows <
|
|
7257
|
+
if (rows < MIN_ROWS) {
|
|
6842
7258
|
layout = scales["small"];
|
|
6843
7259
|
}
|
|
6844
|
-
return /* @__PURE__ */
|
|
6845
|
-
/* @__PURE__ */
|
|
6846
|
-
|
|
7260
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", justifyContent: "space-between", width: "100%", children: [
|
|
7261
|
+
/* @__PURE__ */ jsx11(
|
|
7262
|
+
Box12,
|
|
6847
7263
|
{
|
|
6848
7264
|
paddingY: layout.main.padding.y,
|
|
6849
7265
|
paddingX: layout.main.padding.x,
|
|
6850
7266
|
flexDirection: "column",
|
|
6851
7267
|
justifyContent: "center",
|
|
6852
|
-
children: /* @__PURE__ */
|
|
6853
|
-
/* @__PURE__ */
|
|
7268
|
+
children: /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", gap: 2, children: [
|
|
7269
|
+
/* @__PURE__ */ jsx11(ResizeNotice, {}),
|
|
7270
|
+
showLogo && /* @__PURE__ */ jsx11(TerminalInfoContext.Provider, { value: TERMINAL_INFO, children: /* @__PURE__ */ jsx11(
|
|
6854
7271
|
Image,
|
|
6855
7272
|
{
|
|
6856
7273
|
src: IMAGE_PATH,
|
|
@@ -6861,8 +7278,8 @@ function Welcome() {
|
|
|
6861
7278
|
protocol: "halfBlock"
|
|
6862
7279
|
}
|
|
6863
7280
|
) }),
|
|
6864
|
-
/* @__PURE__ */
|
|
6865
|
-
/* @__PURE__ */
|
|
7281
|
+
/* @__PURE__ */ jsx11(Text13, { color: COLORS.muted, children: "\u2726 From zero \u2192 working search in ~10 minutes" }),
|
|
7282
|
+
/* @__PURE__ */ jsx11(Box12, { flexDirection: "column", children: actions.map((action, i) => /* @__PURE__ */ jsx11(
|
|
6866
7283
|
SelectRow,
|
|
6867
7284
|
{
|
|
6868
7285
|
highlighted: i === index,
|
|
@@ -6871,21 +7288,21 @@ function Welcome() {
|
|
|
6871
7288
|
},
|
|
6872
7289
|
action.label
|
|
6873
7290
|
)) }),
|
|
6874
|
-
/* @__PURE__ */
|
|
6875
|
-
/* @__PURE__ */
|
|
6876
|
-
/* @__PURE__ */
|
|
6877
|
-
/* @__PURE__ */
|
|
7291
|
+
/* @__PURE__ */ jsxs12(Box12, { gap: 2, children: [
|
|
7292
|
+
/* @__PURE__ */ jsxs12(Text13, { children: [
|
|
7293
|
+
/* @__PURE__ */ jsx11(Text13, { color: COLORS.primary, children: "[\u2191] [\u2193]" }),
|
|
7294
|
+
/* @__PURE__ */ jsx11(Text13, { color: COLORS.dim, children: " move" })
|
|
6878
7295
|
] }),
|
|
6879
|
-
/* @__PURE__ */
|
|
6880
|
-
/* @__PURE__ */
|
|
6881
|
-
/* @__PURE__ */
|
|
7296
|
+
/* @__PURE__ */ jsxs12(Text13, { children: [
|
|
7297
|
+
/* @__PURE__ */ jsx11(Text13, { color: COLORS.primary, children: "[enter]" }),
|
|
7298
|
+
/* @__PURE__ */ jsx11(Text13, { color: COLORS.dim, children: " confirm" })
|
|
6882
7299
|
] })
|
|
6883
7300
|
] })
|
|
6884
7301
|
] })
|
|
6885
7302
|
}
|
|
6886
7303
|
),
|
|
6887
|
-
/* @__PURE__ */
|
|
6888
|
-
|
|
7304
|
+
showSidebar && /* @__PURE__ */ jsxs12(
|
|
7305
|
+
Box12,
|
|
6889
7306
|
{
|
|
6890
7307
|
backgroundColor: COLORS.bg.sidebar,
|
|
6891
7308
|
width: 40,
|
|
@@ -6895,8 +7312,8 @@ function Welcome() {
|
|
|
6895
7312
|
flexDirection: "column",
|
|
6896
7313
|
justifyContent: "center",
|
|
6897
7314
|
children: [
|
|
6898
|
-
/* @__PURE__ */
|
|
6899
|
-
sidebarItems.map((i, idx) => /* @__PURE__ */
|
|
7315
|
+
/* @__PURE__ */ jsx11(Text13, { color: COLORS.muted, children: "WHAT THIS WIZARD WILL DO" }),
|
|
7316
|
+
sidebarItems.map((i, idx) => /* @__PURE__ */ jsx11(SidebarItem, { title: i.title, description: i.description }, idx))
|
|
6900
7317
|
]
|
|
6901
7318
|
}
|
|
6902
7319
|
)
|
|
@@ -6904,8 +7321,7 @@ function Welcome() {
|
|
|
6904
7321
|
}
|
|
6905
7322
|
|
|
6906
7323
|
// src/ui/LearnMore.tsx
|
|
6907
|
-
import {
|
|
6908
|
-
import { Box as Box12, Text as Text13, useInput as useInput7, useWindowSize as useWindowSize6 } from "ink";
|
|
7324
|
+
import { Box as Box13, Text as Text14, useInput as useInput7, useWindowSize as useWindowSize7 } from "ink";
|
|
6909
7325
|
|
|
6910
7326
|
// src/ui/copy/learn-more.ts
|
|
6911
7327
|
var accessIntro = "Everything runs locally on your machine. Nothing is written or sent without an explicit yes from you.";
|
|
@@ -6947,7 +7363,7 @@ var policyLinks = [
|
|
|
6947
7363
|
];
|
|
6948
7364
|
|
|
6949
7365
|
// src/ui/LearnMore.tsx
|
|
6950
|
-
import { jsx as
|
|
7366
|
+
import { jsx as jsx12, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
6951
7367
|
var TAG_COLORS = {
|
|
6952
7368
|
READ: COLORS.success,
|
|
6953
7369
|
WRITE: COLORS.badge,
|
|
@@ -6958,92 +7374,156 @@ var TAG_COLORS = {
|
|
|
6958
7374
|
var TAG_COLUMN_WIDTH = 10;
|
|
6959
7375
|
var PADDING_X = 6;
|
|
6960
7376
|
var NEVER_BOX_PAD_X = 2;
|
|
6961
|
-
|
|
6962
|
-
|
|
6963
|
-
segments = []
|
|
6964
|
-
}) {
|
|
7377
|
+
var BLANK3 = { parts: [{ text: " ", color: COLORS.dim }] };
|
|
7378
|
+
function neverRow(width, segments = []) {
|
|
6965
7379
|
const used = segments.reduce((n, s) => n + s.text.length, 0);
|
|
6966
7380
|
const rightPad = Math.max(0, width - 2 - NEVER_BOX_PAD_X - used);
|
|
6967
|
-
return
|
|
6968
|
-
|
|
6969
|
-
|
|
6970
|
-
|
|
6971
|
-
|
|
6972
|
-
|
|
6973
|
-
|
|
7381
|
+
return {
|
|
7382
|
+
parts: [
|
|
7383
|
+
{ text: "\u2502", color: COLORS.danger },
|
|
7384
|
+
{ text: " ".repeat(NEVER_BOX_PAD_X), color: COLORS.primary },
|
|
7385
|
+
...segments.map((s) => ({
|
|
7386
|
+
text: s.text,
|
|
7387
|
+
color: s.color ?? COLORS.primary,
|
|
7388
|
+
bold: s.bold
|
|
7389
|
+
})),
|
|
7390
|
+
{ text: " ".repeat(rightPad), color: COLORS.primary },
|
|
7391
|
+
{ text: "\u2502", color: COLORS.danger }
|
|
7392
|
+
]
|
|
7393
|
+
};
|
|
7394
|
+
}
|
|
7395
|
+
function buildLearnMoreRows(contentWidth) {
|
|
7396
|
+
const width = Math.max(contentWidth, 1);
|
|
7397
|
+
const rows = [];
|
|
7398
|
+
rows.push({
|
|
7399
|
+
parts: [
|
|
7400
|
+
{
|
|
7401
|
+
text: "What algolia wizard accesses",
|
|
7402
|
+
color: COLORS.strong,
|
|
7403
|
+
bold: true
|
|
7404
|
+
}
|
|
7405
|
+
]
|
|
7406
|
+
});
|
|
7407
|
+
for (const line of wrapText(accessIntro, width)) {
|
|
7408
|
+
rows.push({ parts: [{ text: line, color: COLORS.muted }] });
|
|
7409
|
+
}
|
|
7410
|
+
for (const item of accessItems) {
|
|
7411
|
+
rows.push({
|
|
7412
|
+
parts: [{ text: "\u2500".repeat(width), color: COLORS.border }]
|
|
7413
|
+
});
|
|
7414
|
+
rows.push(BLANK3);
|
|
7415
|
+
const tag = `[${item.tag}]`.padEnd(TAG_COLUMN_WIDTH);
|
|
7416
|
+
const bodyWidth = Math.max(width - TAG_COLUMN_WIDTH, 1);
|
|
7417
|
+
const body = wrapText(`${item.title}: ${item.description}`, bodyWidth);
|
|
7418
|
+
body.forEach((line, i) => {
|
|
7419
|
+
const titleEnd = i === 0 ? item.title.length : 0;
|
|
7420
|
+
rows.push({
|
|
7421
|
+
parts: [
|
|
7422
|
+
{
|
|
7423
|
+
text: i === 0 ? tag : " ".repeat(TAG_COLUMN_WIDTH),
|
|
7424
|
+
color: TAG_COLORS[item.tag],
|
|
7425
|
+
bold: i === 0
|
|
7426
|
+
},
|
|
7427
|
+
{
|
|
7428
|
+
text: line.slice(0, titleEnd),
|
|
7429
|
+
color: COLORS.strong,
|
|
7430
|
+
bold: true
|
|
7431
|
+
},
|
|
7432
|
+
{ text: line.slice(titleEnd), color: COLORS.muted }
|
|
7433
|
+
]
|
|
7434
|
+
});
|
|
7435
|
+
});
|
|
7436
|
+
}
|
|
7437
|
+
const inner = Math.max(width - 2, 0);
|
|
7438
|
+
rows.push(BLANK3);
|
|
7439
|
+
rows.push({
|
|
7440
|
+
parts: [{ text: `\u256D${"\u2500".repeat(inner)}\u256E`, color: COLORS.danger }]
|
|
7441
|
+
});
|
|
7442
|
+
rows.push(neverRow(width));
|
|
7443
|
+
rows.push(
|
|
7444
|
+
neverRow(width, [{ text: "I NEVER", color: COLORS.danger, bold: true }])
|
|
7445
|
+
);
|
|
7446
|
+
for (const item of neverItems) {
|
|
7447
|
+
rows.push(neverRow(width));
|
|
7448
|
+
const marker = "\u2715 ";
|
|
7449
|
+
const bodyWidth = Math.max(width - 2 - NEVER_BOX_PAD_X - marker.length, 1);
|
|
7450
|
+
const lines = wrapText(item, bodyWidth);
|
|
7451
|
+
lines.forEach((line, i) => {
|
|
7452
|
+
rows.push(
|
|
7453
|
+
neverRow(
|
|
7454
|
+
width,
|
|
7455
|
+
i === 0 ? [
|
|
7456
|
+
{ text: "\u2715", color: COLORS.danger },
|
|
7457
|
+
{ text: " " },
|
|
7458
|
+
{ text: line, color: COLORS.primary }
|
|
7459
|
+
] : [
|
|
7460
|
+
{ text: " ".repeat(marker.length) },
|
|
7461
|
+
{ text: line, color: COLORS.primary }
|
|
7462
|
+
]
|
|
7463
|
+
)
|
|
7464
|
+
);
|
|
7465
|
+
});
|
|
7466
|
+
}
|
|
7467
|
+
rows.push(neverRow(width));
|
|
7468
|
+
rows.push({
|
|
7469
|
+
parts: [{ text: `\u2570${"\u2500".repeat(inner)}\u256F`, color: COLORS.danger }]
|
|
7470
|
+
});
|
|
7471
|
+
rows.push(BLANK3);
|
|
7472
|
+
for (const link of policyLinks) {
|
|
7473
|
+
const prefix = `${link.label}: `;
|
|
7474
|
+
const urlLines = wrapText(link.url, Math.max(width - prefix.length, 1));
|
|
7475
|
+
urlLines.forEach((line, i) => {
|
|
7476
|
+
rows.push({
|
|
7477
|
+
parts: i === 0 ? [
|
|
7478
|
+
{ text: prefix, color: COLORS.strong, bold: true },
|
|
7479
|
+
{ text: line, color: COLORS.accent }
|
|
7480
|
+
] : [{ text: `${" ".repeat(prefix.length)}${line}`, color: COLORS.accent }]
|
|
7481
|
+
});
|
|
7482
|
+
});
|
|
7483
|
+
}
|
|
7484
|
+
return rows;
|
|
6974
7485
|
}
|
|
6975
7486
|
function LearnMore() {
|
|
6976
7487
|
const confirmStart = useWizard((s) => s.confirmStart);
|
|
6977
7488
|
const backToHome = useWizard((s) => s.backToHome);
|
|
6978
|
-
const { columns } =
|
|
6979
|
-
const
|
|
6980
|
-
|
|
7489
|
+
const { columns } = useWindowSize7();
|
|
7490
|
+
const contentWidth = Math.max(columns - PADDING_X * 2, 1);
|
|
7491
|
+
const rows = buildLearnMoreRows(contentWidth);
|
|
7492
|
+
const scroll = useScrollWindow({ itemCount: rows.length });
|
|
7493
|
+
const scrollable = scroll.maxOffset > 0;
|
|
7494
|
+
useInput7((input, key) => {
|
|
6981
7495
|
if (key.escape) backToHome();
|
|
6982
7496
|
else if (key.return) confirmStart();
|
|
7497
|
+
else if (scrollable && (input === "k" || key.upArrow)) scroll.scrollBy(-1);
|
|
7498
|
+
else if (scrollable && (input === "j" || key.downArrow)) scroll.scrollBy(1);
|
|
6983
7499
|
});
|
|
6984
|
-
|
|
6985
|
-
|
|
7500
|
+
const visible = rows.slice(scroll.offset, scroll.offset + scroll.capacity);
|
|
7501
|
+
return /* @__PURE__ */ jsxs13(
|
|
7502
|
+
Box13,
|
|
6986
7503
|
{
|
|
6987
7504
|
flexDirection: "column",
|
|
6988
7505
|
paddingX: PADDING_X,
|
|
6989
7506
|
paddingY: 2,
|
|
6990
7507
|
width: "100%",
|
|
6991
|
-
|
|
7508
|
+
flexGrow: 1,
|
|
6992
7509
|
children: [
|
|
6993
|
-
/* @__PURE__ */
|
|
6994
|
-
/* @__PURE__ */
|
|
6995
|
-
|
|
6996
|
-
/* @__PURE__ */
|
|
6997
|
-
/* @__PURE__ */
|
|
6998
|
-
/* @__PURE__ */ jsx11(Box12, { width: TAG_COLUMN_WIDTH, flexShrink: 0, children: /* @__PURE__ */ jsx11(Text13, { color: TAG_COLORS[item.tag], bold: true, children: `[${item.tag}]` }) }),
|
|
6999
|
-
/* @__PURE__ */ jsx11(Box12, { flexDirection: "column", children: /* @__PURE__ */ jsxs12(Text13, { color: COLORS.primary, children: [
|
|
7000
|
-
/* @__PURE__ */ jsx11(Text13, { color: COLORS.strong, bold: true, children: item.title }),
|
|
7001
|
-
/* @__PURE__ */ jsx11(Text13, { color: COLORS.muted, children: ` \u2014 ${item.description}` })
|
|
7002
|
-
] }) })
|
|
7003
|
-
] })
|
|
7004
|
-
] }, item.tag)) }),
|
|
7005
|
-
/* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
|
|
7006
|
-
/* @__PURE__ */ jsx11(Text13, { color: COLORS.danger, children: `\u256D${"\u2500".repeat(Math.max(0, dividerWidth - 2))}\u256E` }),
|
|
7007
|
-
/* @__PURE__ */ jsx11(NeverLine, { width: dividerWidth }),
|
|
7008
|
-
/* @__PURE__ */ jsx11(
|
|
7009
|
-
NeverLine,
|
|
7010
|
-
{
|
|
7011
|
-
width: dividerWidth,
|
|
7012
|
-
segments: [{ text: "I NEVER", color: COLORS.danger, bold: true }]
|
|
7013
|
-
}
|
|
7014
|
-
),
|
|
7015
|
-
neverItems.map((item) => /* @__PURE__ */ jsxs12(Fragment, { children: [
|
|
7016
|
-
/* @__PURE__ */ jsx11(NeverLine, { width: dividerWidth }),
|
|
7017
|
-
/* @__PURE__ */ jsx11(
|
|
7018
|
-
NeverLine,
|
|
7019
|
-
{
|
|
7020
|
-
width: dividerWidth,
|
|
7021
|
-
segments: [
|
|
7022
|
-
{ text: "\u2715", color: COLORS.danger },
|
|
7023
|
-
{ text: " " },
|
|
7024
|
-
{ text: item, color: COLORS.primary }
|
|
7025
|
-
]
|
|
7026
|
-
}
|
|
7027
|
-
)
|
|
7028
|
-
] }, item)),
|
|
7029
|
-
/* @__PURE__ */ jsx11(NeverLine, { width: dividerWidth }),
|
|
7030
|
-
/* @__PURE__ */ jsx11(Text13, { color: COLORS.danger, children: `\u2570${"\u2500".repeat(Math.max(0, dividerWidth - 2))}\u256F` })
|
|
7510
|
+
/* @__PURE__ */ jsx12(ResizeNotice, {}),
|
|
7511
|
+
/* @__PURE__ */ jsx12(ScrollView, { scroll, children: visible.map((row, i) => /* @__PURE__ */ jsx12(Text14, { wrap: "truncate", children: row.parts.map((part, j) => /* @__PURE__ */ jsx12(Text14, { color: part.color, bold: part.bold, children: part.text }, j)) }, `learn-more-${scroll.offset}-${i}`)) }),
|
|
7512
|
+
scrollable && /* @__PURE__ */ jsxs13(Text14, { children: [
|
|
7513
|
+
/* @__PURE__ */ jsx12(Text14, { color: COLORS.primary, children: "[j] [k]" }),
|
|
7514
|
+
/* @__PURE__ */ jsx12(Text14, { color: COLORS.dim, children: " scroll" })
|
|
7031
7515
|
] }),
|
|
7032
|
-
/* @__PURE__ */
|
|
7033
|
-
/* @__PURE__ */
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
/* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", gap: 1, children: [
|
|
7038
|
-
/* @__PURE__ */ jsx11(Text13, { color: COLORS.muted, children: "[" }),
|
|
7039
|
-
/* @__PURE__ */ jsx11(Text13, { color: COLORS.primary, children: "esc" }),
|
|
7040
|
-
/* @__PURE__ */ jsx11(Text13, { color: COLORS.muted, children: "] back" })
|
|
7516
|
+
/* @__PURE__ */ jsxs13(Box13, { flexDirection: "row", gap: 3, children: [
|
|
7517
|
+
/* @__PURE__ */ jsxs13(Box13, { flexDirection: "row", gap: 1, children: [
|
|
7518
|
+
/* @__PURE__ */ jsx12(Text14, { color: COLORS.muted, children: "[" }),
|
|
7519
|
+
/* @__PURE__ */ jsx12(Text14, { color: COLORS.primary, children: "esc" }),
|
|
7520
|
+
/* @__PURE__ */ jsx12(Text14, { color: COLORS.muted, children: "] back" })
|
|
7041
7521
|
] }),
|
|
7042
|
-
/* @__PURE__ */
|
|
7043
|
-
/* @__PURE__ */
|
|
7044
|
-
/* @__PURE__ */
|
|
7045
|
-
/* @__PURE__ */
|
|
7046
|
-
/* @__PURE__ */
|
|
7522
|
+
/* @__PURE__ */ jsxs13(Box13, { flexDirection: "row", gap: 1, children: [
|
|
7523
|
+
/* @__PURE__ */ jsx12(Text14, { color: COLORS.muted, children: "[" }),
|
|
7524
|
+
/* @__PURE__ */ jsx12(Text14, { color: COLORS.primary, children: "enter" }),
|
|
7525
|
+
/* @__PURE__ */ jsx12(Text14, { color: COLORS.muted, children: "]" }),
|
|
7526
|
+
/* @__PURE__ */ jsx12(Text14, { color: COLORS.success, bold: true, children: "start wizard" })
|
|
7047
7527
|
] })
|
|
7048
7528
|
] })
|
|
7049
7529
|
]
|
|
@@ -7052,17 +7532,17 @@ function LearnMore() {
|
|
|
7052
7532
|
}
|
|
7053
7533
|
|
|
7054
7534
|
// src/ui/Sidebar.tsx
|
|
7055
|
-
import { Box as
|
|
7535
|
+
import { Box as Box16, Text as Text17 } from "ink";
|
|
7056
7536
|
|
|
7057
7537
|
// src/ui/Steps.tsx
|
|
7058
|
-
import { Box as
|
|
7538
|
+
import { Box as Box14, Text as Text15 } from "ink";
|
|
7059
7539
|
import Spinner2 from "ink-spinner";
|
|
7060
|
-
import { jsx as
|
|
7540
|
+
import { jsx as jsx13, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
7061
7541
|
function Steps() {
|
|
7062
7542
|
const { steps } = useWizard();
|
|
7063
7543
|
const visibleSteps = steps.filter(isStepVisible);
|
|
7064
|
-
return /* @__PURE__ */
|
|
7065
|
-
s.status === "running" ? /* @__PURE__ */
|
|
7544
|
+
return /* @__PURE__ */ jsx13(Box14, { flexDirection: "column", gap: 1, children: visibleSteps.map((s) => /* @__PURE__ */ jsx13(Box14, { flexDirection: "column", children: /* @__PURE__ */ jsxs14(Text15, { color: COLORS.status[s.status], children: [
|
|
7545
|
+
s.status === "running" ? /* @__PURE__ */ jsx13(Spinner2, { type: "dots" }) : MARKER[s.status],
|
|
7066
7546
|
" ",
|
|
7067
7547
|
s.title
|
|
7068
7548
|
] }) }, s.id)) });
|
|
@@ -7071,27 +7551,27 @@ function CurrentStep() {
|
|
|
7071
7551
|
const { steps } = useWizard();
|
|
7072
7552
|
const currentStep = steps.filter(isStepVisible).find((s) => s.status === "running");
|
|
7073
7553
|
if (!currentStep) return null;
|
|
7074
|
-
return /* @__PURE__ */
|
|
7075
|
-
/* @__PURE__ */
|
|
7554
|
+
return /* @__PURE__ */ jsxs14(Text15, { color: COLORS.status.running, children: [
|
|
7555
|
+
/* @__PURE__ */ jsx13(Spinner2, { type: "dots" }),
|
|
7076
7556
|
" ",
|
|
7077
7557
|
` ${currentStep.title}`
|
|
7078
7558
|
] });
|
|
7079
7559
|
}
|
|
7080
7560
|
|
|
7081
7561
|
// src/ui/Progress.tsx
|
|
7082
|
-
import { Box as
|
|
7083
|
-
import { jsx as
|
|
7562
|
+
import { Box as Box15, Text as Text16 } from "ink";
|
|
7563
|
+
import { jsx as jsx14, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
7084
7564
|
function Progress() {
|
|
7085
7565
|
const { steps, currentStepIndex } = useWizard();
|
|
7086
7566
|
const visibleSteps = steps.filter(isStepVisible);
|
|
7087
7567
|
if (visibleSteps.length === 0) return null;
|
|
7088
7568
|
const visibleCountThroughCurrent = steps.slice(0, currentStepIndex + 1).filter(isStepVisible).length;
|
|
7089
7569
|
const activeStepNumber = Math.max(1, visibleCountThroughCurrent);
|
|
7090
|
-
return /* @__PURE__ */
|
|
7091
|
-
/* @__PURE__ */
|
|
7092
|
-
/* @__PURE__ */
|
|
7093
|
-
/* @__PURE__ */
|
|
7094
|
-
/* @__PURE__ */
|
|
7570
|
+
return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "row", gap: 1, children: [
|
|
7571
|
+
/* @__PURE__ */ jsx14(Text16, { color: COLORS.muted, children: "STEP" }),
|
|
7572
|
+
/* @__PURE__ */ jsx14(Text16, { color: COLORS.strong, bold: true, children: activeStepNumber }),
|
|
7573
|
+
/* @__PURE__ */ jsx14(Text16, { color: COLORS.strong, bold: true, children: "/" }),
|
|
7574
|
+
/* @__PURE__ */ jsx14(Text16, { color: COLORS.strong, bold: true, children: visibleSteps.length })
|
|
7095
7575
|
] });
|
|
7096
7576
|
}
|
|
7097
7577
|
|
|
@@ -7102,10 +7582,10 @@ var sidebarCommands = [
|
|
|
7102
7582
|
];
|
|
7103
7583
|
|
|
7104
7584
|
// src/ui/Sidebar.tsx
|
|
7105
|
-
import { jsx as
|
|
7585
|
+
import { jsx as jsx15, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
7106
7586
|
function Sidebar() {
|
|
7107
|
-
return /* @__PURE__ */
|
|
7108
|
-
|
|
7587
|
+
return /* @__PURE__ */ jsxs16(
|
|
7588
|
+
Box16,
|
|
7109
7589
|
{
|
|
7110
7590
|
backgroundColor: "#14171E",
|
|
7111
7591
|
width: 30,
|
|
@@ -7114,16 +7594,16 @@ function Sidebar() {
|
|
|
7114
7594
|
flexDirection: "column",
|
|
7115
7595
|
justifyContent: "space-between",
|
|
7116
7596
|
children: [
|
|
7117
|
-
/* @__PURE__ */
|
|
7118
|
-
/* @__PURE__ */
|
|
7119
|
-
/* @__PURE__ */
|
|
7597
|
+
/* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", gap: 1, children: [
|
|
7598
|
+
/* @__PURE__ */ jsx15(Text17, { color: COLORS.muted, children: "PROGRESS" }),
|
|
7599
|
+
/* @__PURE__ */ jsx15(Steps, {})
|
|
7120
7600
|
] }),
|
|
7121
|
-
/* @__PURE__ */
|
|
7122
|
-
/* @__PURE__ */
|
|
7123
|
-
/* @__PURE__ */
|
|
7124
|
-
return /* @__PURE__ */
|
|
7125
|
-
/* @__PURE__ */
|
|
7126
|
-
/* @__PURE__ */
|
|
7601
|
+
/* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", gap: 1, children: [
|
|
7602
|
+
/* @__PURE__ */ jsx15(Progress, {}),
|
|
7603
|
+
/* @__PURE__ */ jsx15(Box16, { flexDirection: "column", children: sidebarCommands.map((c) => {
|
|
7604
|
+
return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "row", gap: 1, children: [
|
|
7605
|
+
/* @__PURE__ */ jsx15(Text17, { color: COLORS.primary, children: `[${c.keyHint}]` }),
|
|
7606
|
+
/* @__PURE__ */ jsx15(Text17, { color: COLORS.muted, children: c.description })
|
|
7127
7607
|
] }, c.keyHint);
|
|
7128
7608
|
}) })
|
|
7129
7609
|
] })
|
|
@@ -7133,12 +7613,12 @@ function Sidebar() {
|
|
|
7133
7613
|
}
|
|
7134
7614
|
|
|
7135
7615
|
// src/ui/Ribbon.tsx
|
|
7136
|
-
import { Box as
|
|
7137
|
-
import { jsx as
|
|
7616
|
+
import { Box as Box17, Text as Text18 } from "ink";
|
|
7617
|
+
import { jsx as jsx16, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
7138
7618
|
function Ribbon() {
|
|
7139
7619
|
const firstCommand = sidebarCommands[0];
|
|
7140
|
-
return /* @__PURE__ */
|
|
7141
|
-
|
|
7620
|
+
return /* @__PURE__ */ jsxs17(
|
|
7621
|
+
Box17,
|
|
7142
7622
|
{
|
|
7143
7623
|
backgroundColor: "#14171E",
|
|
7144
7624
|
flexDirection: "row",
|
|
@@ -7146,11 +7626,11 @@ function Ribbon() {
|
|
|
7146
7626
|
paddingX: 2,
|
|
7147
7627
|
paddingY: 1,
|
|
7148
7628
|
children: [
|
|
7149
|
-
/* @__PURE__ */
|
|
7150
|
-
/* @__PURE__ */
|
|
7151
|
-
/* @__PURE__ */
|
|
7152
|
-
/* @__PURE__ */
|
|
7153
|
-
/* @__PURE__ */
|
|
7629
|
+
/* @__PURE__ */ jsx16(Progress, {}),
|
|
7630
|
+
/* @__PURE__ */ jsx16(CurrentStep, {}),
|
|
7631
|
+
/* @__PURE__ */ jsxs17(Box17, { flexDirection: "row", gap: 1, children: [
|
|
7632
|
+
/* @__PURE__ */ jsx16(Text18, { color: COLORS.primary, children: `[${firstCommand.keyHint}]` }),
|
|
7633
|
+
/* @__PURE__ */ jsx16(Text18, { color: COLORS.muted, children: firstCommand.description })
|
|
7154
7634
|
] })
|
|
7155
7635
|
]
|
|
7156
7636
|
}
|
|
@@ -7161,8 +7641,8 @@ function Ribbon() {
|
|
|
7161
7641
|
import { useState as useState12 } from "react";
|
|
7162
7642
|
|
|
7163
7643
|
// src/ui/Logs.tsx
|
|
7164
|
-
import { Box as
|
|
7165
|
-
import { jsx as
|
|
7644
|
+
import { Box as Box18, Text as Text19, useInput as useInput8 } from "ink";
|
|
7645
|
+
import { jsx as jsx17, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
7166
7646
|
var KIND_COLOR = {
|
|
7167
7647
|
tool: COLORS.primary,
|
|
7168
7648
|
prompt: COLORS.badge
|
|
@@ -7198,9 +7678,9 @@ function Logs() {
|
|
|
7198
7678
|
else if (input === "j" || key.downArrow) scroll.scrollBy(1);
|
|
7199
7679
|
});
|
|
7200
7680
|
const visible = logs.slice(scroll.offset, scroll.offset + scroll.capacity);
|
|
7201
|
-
return /* @__PURE__ */
|
|
7202
|
-
logs.length === 0 && /* @__PURE__ */
|
|
7203
|
-
/* @__PURE__ */
|
|
7681
|
+
return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", paddingX: 4, paddingY: 2, flexGrow: 1, children: [
|
|
7682
|
+
logs.length === 0 && /* @__PURE__ */ jsx17(Text19, { color: COLORS.dim, children: "No logs yet." }),
|
|
7683
|
+
/* @__PURE__ */ jsx17(ScrollView, { scroll, children: visible.map((entry) => {
|
|
7204
7684
|
const timestamp = `[${formatTimestamp(entry.startedAt)}]`;
|
|
7205
7685
|
const durationText = entry.kind === "tool" && entry.durationMs !== void 0 ? `${entry.durationMs}ms` : "";
|
|
7206
7686
|
const rawPreview = rawInputText(entry.input);
|
|
@@ -7210,28 +7690,28 @@ function Logs() {
|
|
|
7210
7690
|
const name = truncate3(entry.name, budget);
|
|
7211
7691
|
budget -= name.length;
|
|
7212
7692
|
const preview = rawPreview ? truncate3(rawPreview, budget) : "";
|
|
7213
|
-
return /* @__PURE__ */
|
|
7214
|
-
/* @__PURE__ */
|
|
7215
|
-
/* @__PURE__ */
|
|
7216
|
-
preview && /* @__PURE__ */
|
|
7217
|
-
durationText && /* @__PURE__ */
|
|
7693
|
+
return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "row", gap: ROW_GAP, children: [
|
|
7694
|
+
/* @__PURE__ */ jsx17(Text19, { color: COLORS.dim, children: timestamp }),
|
|
7695
|
+
/* @__PURE__ */ jsx17(Text19, { color: logNameColor(entry), wrap: "truncate", children: name }),
|
|
7696
|
+
preview && /* @__PURE__ */ jsx17(Text19, { color: COLORS.dim, wrap: "truncate", children: preview }),
|
|
7697
|
+
durationText && /* @__PURE__ */ jsx17(Text19, { color: COLORS.dim, children: durationText })
|
|
7218
7698
|
] }, entry.id);
|
|
7219
7699
|
}) }),
|
|
7220
|
-
/* @__PURE__ */
|
|
7221
|
-
/* @__PURE__ */
|
|
7222
|
-
/* @__PURE__ */
|
|
7700
|
+
/* @__PURE__ */ jsxs18(Text19, { children: [
|
|
7701
|
+
/* @__PURE__ */ jsx17(Text19, { color: COLORS.primary, children: "[j] [k]" }),
|
|
7702
|
+
/* @__PURE__ */ jsx17(Text19, { color: COLORS.dim, children: " scroll" })
|
|
7223
7703
|
] })
|
|
7224
7704
|
] });
|
|
7225
7705
|
}
|
|
7226
7706
|
|
|
7227
7707
|
// src/ui/Tips.tsx
|
|
7228
7708
|
import { useEffect as useEffect3, useRef as useRef4, useState as useState11 } from "react";
|
|
7229
|
-
import { Box as
|
|
7709
|
+
import { Box as Box20, Text as Text21 } from "ink";
|
|
7230
7710
|
import terminalLink from "terminal-link";
|
|
7231
7711
|
|
|
7232
7712
|
// src/ui/Code.tsx
|
|
7233
|
-
import { Box as
|
|
7234
|
-
import { jsx as
|
|
7713
|
+
import { Box as Box19, Text as Text20 } from "ink";
|
|
7714
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
7235
7715
|
var TOKEN_RE = /("(?:\\.|[^"\\])*"|\btrue\b|\bfalse\b|\bnull\b|-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|[{}[\]:,])/g;
|
|
7236
7716
|
function highlightJson(json) {
|
|
7237
7717
|
const parts = json.split(TOKEN_RE);
|
|
@@ -7240,22 +7720,22 @@ function highlightJson(json) {
|
|
|
7240
7720
|
if (part[0] === '"') {
|
|
7241
7721
|
const next = parts.slice(i + 1).find((p) => p.trim());
|
|
7242
7722
|
const isKey = next?.trimStart().startsWith(":");
|
|
7243
|
-
return /* @__PURE__ */
|
|
7723
|
+
return /* @__PURE__ */ jsx18(Text20, { color: isKey ? "cyan" : "green", children: part }, i);
|
|
7244
7724
|
}
|
|
7245
7725
|
if (part === "true" || part === "false" || part === "null") {
|
|
7246
|
-
return /* @__PURE__ */
|
|
7726
|
+
return /* @__PURE__ */ jsx18(Text20, { color: "magenta", children: part }, i);
|
|
7247
7727
|
}
|
|
7248
7728
|
if (/^-?\d/.test(part)) {
|
|
7249
|
-
return /* @__PURE__ */
|
|
7729
|
+
return /* @__PURE__ */ jsx18(Text20, { color: "yellow", children: part }, i);
|
|
7250
7730
|
}
|
|
7251
7731
|
if (/^[{}[\]:,]$/.test(part)) {
|
|
7252
|
-
return /* @__PURE__ */
|
|
7732
|
+
return /* @__PURE__ */ jsx18(Text20, { color: COLORS.dim, children: part }, i);
|
|
7253
7733
|
}
|
|
7254
|
-
return /* @__PURE__ */
|
|
7734
|
+
return /* @__PURE__ */ jsx18(Text20, { children: part }, i);
|
|
7255
7735
|
});
|
|
7256
7736
|
}
|
|
7257
7737
|
function Code({ children }) {
|
|
7258
|
-
return /* @__PURE__ */
|
|
7738
|
+
return /* @__PURE__ */ jsx18(Box19, { children: /* @__PURE__ */ jsx18(Text20, { children: highlightJson(children) }) });
|
|
7259
7739
|
}
|
|
7260
7740
|
|
|
7261
7741
|
// src/ui/copy/tips.ts
|
|
@@ -7469,26 +7949,26 @@ function tipsByIds(ids) {
|
|
|
7469
7949
|
}
|
|
7470
7950
|
|
|
7471
7951
|
// src/ui/Tips.tsx
|
|
7472
|
-
import { jsx as
|
|
7952
|
+
import { jsx as jsx19, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
7473
7953
|
var TICK_MS = 16;
|
|
7474
7954
|
var CHUNK_HOLD_MS = 2e3;
|
|
7475
7955
|
var HOLD_MS = 12e3;
|
|
7476
7956
|
function TipTitle({ children }) {
|
|
7477
|
-
return /* @__PURE__ */
|
|
7478
|
-
/* @__PURE__ */
|
|
7479
|
-
/* @__PURE__ */
|
|
7957
|
+
return /* @__PURE__ */ jsxs19(Box20, { gap: 1, children: [
|
|
7958
|
+
/* @__PURE__ */ jsx19(Text21, { color: "cyan", children: "\u2726" }),
|
|
7959
|
+
/* @__PURE__ */ jsx19(Text21, { color: "white", bold: true, children })
|
|
7480
7960
|
] });
|
|
7481
7961
|
}
|
|
7482
7962
|
function InlineSegment({ segment }) {
|
|
7483
7963
|
switch (segment.type) {
|
|
7484
7964
|
case "highlight":
|
|
7485
|
-
return /* @__PURE__ */
|
|
7965
|
+
return /* @__PURE__ */ jsx19(Text21, { color: COLORS.success, children: segment.value });
|
|
7486
7966
|
case "link":
|
|
7487
|
-
return /* @__PURE__ */
|
|
7967
|
+
return /* @__PURE__ */ jsx19(Text21, { color: "cyan", underline: true, children: segment.href ? terminalLink(segment.value, segment.href) : segment.value });
|
|
7488
7968
|
case "codeword":
|
|
7489
|
-
return /* @__PURE__ */
|
|
7969
|
+
return /* @__PURE__ */ jsx19(Text21, { color: COLORS.highlight.fg, backgroundColor: COLORS.highlight.bg, children: segment.value });
|
|
7490
7970
|
default:
|
|
7491
|
-
return /* @__PURE__ */
|
|
7971
|
+
return /* @__PURE__ */ jsx19(Text21, { color: COLORS.muted, children: segment.value });
|
|
7492
7972
|
}
|
|
7493
7973
|
}
|
|
7494
7974
|
function TipContent({
|
|
@@ -7522,10 +8002,10 @@ function TipContent({
|
|
|
7522
8002
|
blocks.push({ type: "inline", segments: [segment] });
|
|
7523
8003
|
}
|
|
7524
8004
|
}
|
|
7525
|
-
return /* @__PURE__ */
|
|
7526
|
-
(block, i) => block.type === "code" ? /* @__PURE__ */
|
|
8005
|
+
return /* @__PURE__ */ jsx19(Box20, { flexDirection: "column", marginLeft: 2, gap: 1, children: blocks.map(
|
|
8006
|
+
(block, i) => block.type === "code" ? /* @__PURE__ */ jsx19(Code, { children: block.segment.value }, i) : /* @__PURE__ */ jsx19(Text21, { children: block.segments.map((segment, j) => /* @__PURE__ */ jsxs19(Text21, { children: [
|
|
7527
8007
|
j > 0 && " ",
|
|
7528
|
-
/* @__PURE__ */
|
|
8008
|
+
/* @__PURE__ */ jsx19(InlineSegment, { segment })
|
|
7529
8009
|
] }, j)) }, i)
|
|
7530
8010
|
) });
|
|
7531
8011
|
}
|
|
@@ -7602,14 +8082,51 @@ function Tips({
|
|
|
7602
8082
|
if (!tip) return null;
|
|
7603
8083
|
const titleRevealed = tip.title.slice(0, revealed);
|
|
7604
8084
|
const contentRevealed = Math.max(0, revealed - tip.title.length);
|
|
7605
|
-
return /* @__PURE__ */
|
|
7606
|
-
/* @__PURE__ */
|
|
7607
|
-
/* @__PURE__ */
|
|
8085
|
+
return /* @__PURE__ */ jsxs19(Box20, { flexDirection: "column", marginBottom: 1, gap: 1, children: [
|
|
8086
|
+
/* @__PURE__ */ jsx19(TipTitle, { children: titleRevealed }),
|
|
8087
|
+
/* @__PURE__ */ jsx19(TipContent, { chunks: tip.chunks, revealed: contentRevealed })
|
|
7608
8088
|
] });
|
|
7609
8089
|
}
|
|
7610
8090
|
|
|
8091
|
+
// src/ui/useRepaintOnResize.ts
|
|
8092
|
+
import { useEffect as useEffect4 } from "react";
|
|
8093
|
+
import { useApp, useStdout } from "ink";
|
|
8094
|
+
var BEGIN_SYNC = "\x1B[?2026h";
|
|
8095
|
+
var END_SYNC = "\x1B[?2026l";
|
|
8096
|
+
var CLEAR_SCREEN_AND_SCROLLBACK = "\x1B[2J\x1B[3J\x1B[H";
|
|
8097
|
+
function useRepaintOnResize(debounceMs = 100) {
|
|
8098
|
+
const { stdout } = useStdout();
|
|
8099
|
+
const { suspendTerminal } = useApp();
|
|
8100
|
+
useEffect4(() => {
|
|
8101
|
+
if (!stdout.isTTY) return;
|
|
8102
|
+
let timer;
|
|
8103
|
+
let repaint = Promise.resolve();
|
|
8104
|
+
const onResize = () => {
|
|
8105
|
+
clearTimeout(timer);
|
|
8106
|
+
timer = setTimeout(() => {
|
|
8107
|
+
repaint = repaint.then(async () => {
|
|
8108
|
+
stdout.write(BEGIN_SYNC);
|
|
8109
|
+
try {
|
|
8110
|
+
await suspendTerminal(() => {
|
|
8111
|
+
stdout.write(CLEAR_SCREEN_AND_SCROLLBACK);
|
|
8112
|
+
});
|
|
8113
|
+
} finally {
|
|
8114
|
+
stdout.write(END_SYNC);
|
|
8115
|
+
}
|
|
8116
|
+
}).catch(() => {
|
|
8117
|
+
});
|
|
8118
|
+
}, debounceMs);
|
|
8119
|
+
};
|
|
8120
|
+
stdout.on("resize", onResize);
|
|
8121
|
+
return () => {
|
|
8122
|
+
clearTimeout(timer);
|
|
8123
|
+
stdout.off("resize", onResize);
|
|
8124
|
+
};
|
|
8125
|
+
}, [stdout, suspendTerminal, debounceMs]);
|
|
8126
|
+
}
|
|
8127
|
+
|
|
7611
8128
|
// src/ui/App.tsx
|
|
7612
|
-
import { jsx as
|
|
8129
|
+
import { jsx as jsx20, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
7613
8130
|
function App() {
|
|
7614
8131
|
const {
|
|
7615
8132
|
phase,
|
|
@@ -7624,8 +8141,10 @@ function App() {
|
|
|
7624
8141
|
loadingMessage,
|
|
7625
8142
|
review: review2
|
|
7626
8143
|
} = useWizard();
|
|
7627
|
-
const { exit } =
|
|
7628
|
-
const { columns, rows } =
|
|
8144
|
+
const { exit } = useApp2();
|
|
8145
|
+
const { columns, rows } = useWindowSize8();
|
|
8146
|
+
useRepaintOnResize();
|
|
8147
|
+
const compactRun = isCompactTerminal(columns, rows);
|
|
7629
8148
|
const [showLogs, setShowLogs] = useState12(false);
|
|
7630
8149
|
const [tipState, setTipState] = useState12("idle");
|
|
7631
8150
|
const finished = phase === "done" || phase === "error";
|
|
@@ -7636,10 +8155,10 @@ function App() {
|
|
|
7636
8155
|
const isAwaitingUserInput = phase === "awaitingInput" && !!inputReq;
|
|
7637
8156
|
const isCommandApprovalPrompt = isAwaitingUserInput && inputReq?.promptType === "commandApproval";
|
|
7638
8157
|
const promptPending = isAwaitingUserInput && !isCommandApprovalPrompt;
|
|
7639
|
-
const holdForTip = stepHasTips && promptPending && tipState === "revealing";
|
|
7640
|
-
const showTips = stepHasTips && (phase === "running" && currentStep?.status === "running"
|
|
8158
|
+
const holdForTip = !compactRun && stepHasTips && promptPending && tipState === "revealing";
|
|
8159
|
+
const showTips = !compactRun && stepHasTips && (phase === "running" && currentStep?.status === "running" && !loadingMessage && !settingUpAppId || isCommandApprovalPrompt);
|
|
7641
8160
|
const showNoticesInMain = !stepHasTips;
|
|
7642
|
-
const showNotices = (!isAwaitingUserInput || holdForTip) && !review2;
|
|
8161
|
+
const showNotices = !compactRun && (!isAwaitingUserInput || holdForTip) && !review2;
|
|
7643
8162
|
useInput9(
|
|
7644
8163
|
(_input, key) => {
|
|
7645
8164
|
if (key.return) {
|
|
@@ -7672,32 +8191,31 @@ function App() {
|
|
|
7672
8191
|
}
|
|
7673
8192
|
});
|
|
7674
8193
|
const mainWindowVisible = phase === "authenticating" || phase === "preflight" || phase === "running" || phase === "awaitingInput" || phase === "error" || phase === "done";
|
|
7675
|
-
const flexDirection = columns >
|
|
8194
|
+
const flexDirection = columns > SIDEBAR_MIN_COLUMNS ? "row" : "column";
|
|
7676
8195
|
const showSidebar = flexDirection === "row";
|
|
7677
|
-
const scrollsPastViewport = phase === "idle" && homeScreen === "learnMore";
|
|
7678
8196
|
return (
|
|
7679
8197
|
/* Clamped to exactly the viewport: a taller frame makes Ink clear and repaint
|
|
7680
|
-
the whole screen, and the scrolling throws off its cursor arithmetic
|
|
7681
|
-
|
|
7682
|
-
/* @__PURE__ */
|
|
7683
|
-
|
|
8198
|
+
the whole screen, and the scrolling throws off its cursor arithmetic.
|
|
8199
|
+
Flicker and leftover rows. */
|
|
8200
|
+
/* @__PURE__ */ jsxs20(
|
|
8201
|
+
Box21,
|
|
7684
8202
|
{
|
|
7685
8203
|
backgroundColor: COLORS.bg.main,
|
|
7686
8204
|
flexDirection: "row",
|
|
7687
8205
|
width: columns,
|
|
7688
|
-
height:
|
|
7689
|
-
overflow:
|
|
8206
|
+
height: rows,
|
|
8207
|
+
overflow: "hidden",
|
|
7690
8208
|
children: [
|
|
7691
|
-
mainWindowVisible && /* @__PURE__ */
|
|
7692
|
-
|
|
8209
|
+
mainWindowVisible && /* @__PURE__ */ jsxs20(
|
|
8210
|
+
Box21,
|
|
7693
8211
|
{
|
|
7694
8212
|
flexDirection,
|
|
7695
8213
|
width: "100%",
|
|
7696
8214
|
maxHeight: rows,
|
|
7697
8215
|
justifyContent: "space-between",
|
|
7698
8216
|
children: [
|
|
7699
|
-
showLogs ? /* @__PURE__ */
|
|
7700
|
-
|
|
8217
|
+
showLogs ? /* @__PURE__ */ jsx20(Logs, {}) : /* @__PURE__ */ jsxs20(
|
|
8218
|
+
Box21,
|
|
7701
8219
|
{
|
|
7702
8220
|
flexDirection: "column",
|
|
7703
8221
|
paddingX: 4,
|
|
@@ -7706,35 +8224,35 @@ function App() {
|
|
|
7706
8224
|
flexGrow: 1,
|
|
7707
8225
|
gap: 1,
|
|
7708
8226
|
children: [
|
|
7709
|
-
/* @__PURE__ */
|
|
7710
|
-
phase === "preflight" && !user && /* @__PURE__ */
|
|
7711
|
-
/* @__PURE__ */
|
|
8227
|
+
/* @__PURE__ */ jsxs20(Box21, { flexGrow: 2, flexDirection: "column", children: [
|
|
8228
|
+
phase === "preflight" && !user && /* @__PURE__ */ jsx20(Box21, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs20(Text22, { color: COLORS.strong, bold: true, children: [
|
|
8229
|
+
/* @__PURE__ */ jsx20(Spinner3, { type: "dots" }),
|
|
7712
8230
|
" Signing in to Algolia"
|
|
7713
8231
|
] }) }),
|
|
7714
|
-
phase === "preflight" && user && /* @__PURE__ */
|
|
7715
|
-
/* @__PURE__ */
|
|
8232
|
+
phase === "preflight" && user && /* @__PURE__ */ jsx20(Box21, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs20(Text22, { color: COLORS.strong, bold: true, children: [
|
|
8233
|
+
/* @__PURE__ */ jsx20(Spinner3, { type: "dots" }),
|
|
7716
8234
|
" Getting things ready"
|
|
7717
8235
|
] }) }),
|
|
7718
|
-
phase === "authenticating" && /* @__PURE__ */
|
|
7719
|
-
/* @__PURE__ */
|
|
7720
|
-
/* @__PURE__ */
|
|
8236
|
+
phase === "authenticating" && /* @__PURE__ */ jsxs20(Box21, { flexDirection: "column", marginBottom: 1, children: [
|
|
8237
|
+
/* @__PURE__ */ jsxs20(Text22, { color: COLORS.strong, bold: true, children: [
|
|
8238
|
+
/* @__PURE__ */ jsx20(Spinner3, { type: "dots" }),
|
|
7721
8239
|
" Signing in to Algolia"
|
|
7722
8240
|
] }),
|
|
7723
|
-
/* @__PURE__ */
|
|
8241
|
+
/* @__PURE__ */ jsx20(Text22, { color: COLORS.muted, children: "A browser window will open \u2014 complete sign-in there." })
|
|
7724
8242
|
] }),
|
|
7725
|
-
settingUpAppId && /* @__PURE__ */
|
|
7726
|
-
/* @__PURE__ */
|
|
8243
|
+
settingUpAppId && /* @__PURE__ */ jsx20(Box21, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs20(Text22, { color: COLORS.strong, bold: true, children: [
|
|
8244
|
+
/* @__PURE__ */ jsx20(Spinner3, { type: "dots" }),
|
|
7727
8245
|
" Setting up Wizard using app",
|
|
7728
8246
|
" ",
|
|
7729
8247
|
settingUpAppId
|
|
7730
8248
|
] }) }),
|
|
7731
|
-
phase === "running" && !settingUpAppId && loadingMessage && /* @__PURE__ */
|
|
7732
|
-
/* @__PURE__ */
|
|
8249
|
+
phase === "running" && !settingUpAppId && loadingMessage && /* @__PURE__ */ jsx20(Box21, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs20(Text22, { color: COLORS.strong, bold: true, children: [
|
|
8250
|
+
/* @__PURE__ */ jsx20(Spinner3, { type: "dots" }),
|
|
7733
8251
|
" ",
|
|
7734
8252
|
loadingMessage
|
|
7735
8253
|
] }) }),
|
|
7736
|
-
/* @__PURE__ */
|
|
7737
|
-
showTips && currentStep && /* @__PURE__ */
|
|
8254
|
+
/* @__PURE__ */ jsx20(CliOutput, {}),
|
|
8255
|
+
showTips && currentStep && /* @__PURE__ */ jsx20(
|
|
7738
8256
|
Tips,
|
|
7739
8257
|
{
|
|
7740
8258
|
stepId: currentStep.id,
|
|
@@ -7742,24 +8260,24 @@ function App() {
|
|
|
7742
8260
|
onRevealStateChange: setTipState
|
|
7743
8261
|
}
|
|
7744
8262
|
),
|
|
7745
|
-
showNoticesInMain && showNotices && /* @__PURE__ */
|
|
7746
|
-
/* @__PURE__ */
|
|
7747
|
-
!showTips && /* @__PURE__ */
|
|
7748
|
-
phase === "error" && error && /* @__PURE__ */
|
|
8263
|
+
showNoticesInMain && showNotices && /* @__PURE__ */ jsx20(Notices, { showAll: true, border: false }),
|
|
8264
|
+
/* @__PURE__ */ jsx20(Review, {}),
|
|
8265
|
+
!showTips && /* @__PURE__ */ jsx20(PromptInput, {}),
|
|
8266
|
+
phase === "error" && error && /* @__PURE__ */ jsx20(Box21, { marginTop: 1, children: /* @__PURE__ */ jsxs20(Text22, { color: COLORS.status.error, children: [
|
|
7749
8267
|
"\u2716 ",
|
|
7750
8268
|
error
|
|
7751
8269
|
] }) })
|
|
7752
8270
|
] }),
|
|
7753
|
-
!showNoticesInMain && showNotices && /* @__PURE__ */
|
|
7754
|
-
showTips && !holdForTip && /* @__PURE__ */
|
|
8271
|
+
!showNoticesInMain && showNotices && /* @__PURE__ */ jsx20(Notices, {}),
|
|
8272
|
+
showTips && !holdForTip && /* @__PURE__ */ jsx20(PromptInput, {})
|
|
7755
8273
|
]
|
|
7756
8274
|
}
|
|
7757
8275
|
),
|
|
7758
|
-
showSidebar ? /* @__PURE__ */
|
|
8276
|
+
showSidebar ? /* @__PURE__ */ jsx20(Sidebar, {}) : /* @__PURE__ */ jsx20(Ribbon, {})
|
|
7759
8277
|
]
|
|
7760
8278
|
}
|
|
7761
8279
|
),
|
|
7762
|
-
phase === "idle" && (homeScreen === "learnMore" ? /* @__PURE__ */
|
|
8280
|
+
phase === "idle" && (homeScreen === "learnMore" ? /* @__PURE__ */ jsx20(LearnMore, {}) : /* @__PURE__ */ jsx20(Welcome, {}))
|
|
7763
8281
|
]
|
|
7764
8282
|
}
|
|
7765
8283
|
)
|
|
@@ -7826,6 +8344,23 @@ var selectPlaybookIndex = {
|
|
|
7826
8344
|
indexName: "wizard_seed_orders",
|
|
7827
8345
|
sampleIndex: false
|
|
7828
8346
|
};
|
|
8347
|
+
var dataAssessment = {
|
|
8348
|
+
uuid: "seed-exec-uuid",
|
|
8349
|
+
playbook_slug: selectPlaybook.slug,
|
|
8350
|
+
application_id: "SEEDAPPID",
|
|
8351
|
+
source_index_name: selectPlaybookIndex.indexName,
|
|
8352
|
+
current_step: "assessment",
|
|
8353
|
+
step_status: "done",
|
|
8354
|
+
status_reason: null,
|
|
8355
|
+
completed: true,
|
|
8356
|
+
assessment_result: {
|
|
8357
|
+
ready: true,
|
|
8358
|
+
schema_comparison: [],
|
|
8359
|
+
settings_recommendation: {}
|
|
8360
|
+
},
|
|
8361
|
+
settings_snapshot: null,
|
|
8362
|
+
created_at: "2026-09-22T09:00:00.000Z"
|
|
8363
|
+
};
|
|
7829
8364
|
var review = {
|
|
7830
8365
|
summaryPoints: [
|
|
7831
8366
|
"Ingested 25 generated Product records into wizard_seed_products.",
|
|
@@ -7847,9 +8382,9 @@ var SEEDS = {
|
|
|
7847
8382
|
},
|
|
7848
8383
|
playbook: {
|
|
7849
8384
|
"select-playbook": selectPlaybook,
|
|
7850
|
-
"confirm-playbook": void 0,
|
|
7851
8385
|
"select-index": selectPlaybookIndex,
|
|
7852
|
-
"confirm-index": null
|
|
8386
|
+
"confirm-index": null,
|
|
8387
|
+
"data-assessment": dataAssessment
|
|
7853
8388
|
}
|
|
7854
8389
|
};
|
|
7855
8390
|
var SEED_ALGOLIA_STATE = {
|
|
@@ -7978,49 +8513,10 @@ async function resetProjectState() {
|
|
|
7978
8513
|
return { dir, removed: targets };
|
|
7979
8514
|
}
|
|
7980
8515
|
|
|
7981
|
-
// src/lib/terminalSize.ts
|
|
7982
|
-
var MIN_ROWS = 30;
|
|
7983
|
-
var MIN_COLUMNS = 100;
|
|
7984
|
-
async function requestTerminalSize(stdout = process.stdout, {
|
|
7985
|
-
rows = MIN_ROWS,
|
|
7986
|
-
columns = MIN_COLUMNS,
|
|
7987
|
-
timeoutMs = 150,
|
|
7988
|
-
settleMs = 120
|
|
7989
|
-
} = {}) {
|
|
7990
|
-
if (!stdout.isTTY) return;
|
|
7991
|
-
const currentRows = stdout.rows ?? 0;
|
|
7992
|
-
const currentColumns = stdout.columns ?? 0;
|
|
7993
|
-
if (currentRows >= rows && currentColumns >= columns) return;
|
|
7994
|
-
stdout.write(
|
|
7995
|
-
`\x1B[8;${Math.max(currentRows, rows)};${Math.max(currentColumns, columns)}t`
|
|
7996
|
-
);
|
|
7997
|
-
const resized = await waitForResize(stdout, timeoutMs);
|
|
7998
|
-
if (!resized) return;
|
|
7999
|
-
await delay(settleMs);
|
|
8000
|
-
stdout.write("\x1B[2J\x1B[H");
|
|
8001
|
-
}
|
|
8002
|
-
function waitForResize(stdout, timeoutMs) {
|
|
8003
|
-
return new Promise((resolve5) => {
|
|
8004
|
-
const finish = (didResize) => () => {
|
|
8005
|
-
clearTimeout(timer);
|
|
8006
|
-
stdout.off("resize", onResize);
|
|
8007
|
-
resolve5(didResize);
|
|
8008
|
-
};
|
|
8009
|
-
const onResize = finish(true);
|
|
8010
|
-
const timer = setTimeout(finish(false), timeoutMs);
|
|
8011
|
-
stdout.once("resize", onResize);
|
|
8012
|
-
});
|
|
8013
|
-
}
|
|
8014
|
-
function delay(ms) {
|
|
8015
|
-
return new Promise((resolve5) => {
|
|
8016
|
-
setTimeout(resolve5, ms);
|
|
8017
|
-
});
|
|
8018
|
-
}
|
|
8019
|
-
|
|
8020
8516
|
// package.json with { type: 'json' }
|
|
8021
8517
|
var package_default2 = {
|
|
8022
8518
|
name: "@algolia/wizard",
|
|
8023
|
-
version: "0.
|
|
8519
|
+
version: "0.77.0",
|
|
8024
8520
|
description: "Magically implement Algolia functionality in your codebase",
|
|
8025
8521
|
type: "module",
|
|
8026
8522
|
engines: {
|
|
@@ -8127,7 +8623,7 @@ async function checkVersion() {
|
|
|
8127
8623
|
}
|
|
8128
8624
|
|
|
8129
8625
|
// src/main.tsx
|
|
8130
|
-
import { jsx as
|
|
8626
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
8131
8627
|
var FAILURE_EXIT_CODE = 1;
|
|
8132
8628
|
async function exitProcessWithError(store, instance, message) {
|
|
8133
8629
|
store.setError(message);
|
|
@@ -8190,7 +8686,7 @@ ${formatStepList(workflow)}`);
|
|
|
8190
8686
|
async function run(opts) {
|
|
8191
8687
|
const { workflow, skipResumePrompt } = opts;
|
|
8192
8688
|
const store = useWizard.getState();
|
|
8193
|
-
const instance = render(/* @__PURE__ */
|
|
8689
|
+
const instance = render(/* @__PURE__ */ jsx21(App, {}), { incrementalRendering: true });
|
|
8194
8690
|
await store.waitForStart();
|
|
8195
8691
|
store.syncSteps(
|
|
8196
8692
|
workflow.steps.map((s) => ({
|