@algolia/wizard 0.6.0-rc.51.26 → 0.6.0-rc.53.27
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 +767 -495
- package/package.json +1 -3
package/dist/main.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { render } from "ink";
|
|
5
5
|
|
|
6
6
|
// src/ui/App.tsx
|
|
7
|
-
import { Box as
|
|
7
|
+
import { Box as Box14, Text as Text14, useApp, useInput as useInput6, useWindowSize as useWindowSize8 } from "ink";
|
|
8
8
|
|
|
9
9
|
// src/core/store.ts
|
|
10
10
|
import { create } from "zustand";
|
|
@@ -12,20 +12,54 @@ import { nanoid } from "nanoid";
|
|
|
12
12
|
|
|
13
13
|
// src/lib/algoliaCli.ts
|
|
14
14
|
import { spawn } from "node:child_process";
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
function algoliaCliEntry() {
|
|
18
|
-
return require2.resolve("@algolia/cli/bin/run.js");
|
|
15
|
+
function npxArgs(args) {
|
|
16
|
+
return ["--yes", "@algolia/cli@latest", ...args];
|
|
19
17
|
}
|
|
20
|
-
|
|
18
|
+
var shell = process.platform === "win32";
|
|
19
|
+
function lineSplitter(emit) {
|
|
20
|
+
let buffer = "";
|
|
21
|
+
return {
|
|
22
|
+
push(chunk) {
|
|
23
|
+
buffer += chunk;
|
|
24
|
+
const lines = buffer.split("\n");
|
|
25
|
+
buffer = lines.pop() ?? "";
|
|
26
|
+
for (const line of lines) emit(line.replace(/\r$/, ""));
|
|
27
|
+
},
|
|
28
|
+
flush() {
|
|
29
|
+
if (buffer) emit(buffer.replace(/\r$/, ""));
|
|
30
|
+
buffer = "";
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
var wizardSink = (stream, line) => {
|
|
35
|
+
if (!line.trim()) return;
|
|
36
|
+
useWizard.getState().pushCliOutput(stream, line);
|
|
37
|
+
};
|
|
38
|
+
function runAlgoliaCli(args, { onOutput } = {}) {
|
|
39
|
+
const store2 = useWizard.getState();
|
|
40
|
+
const logId = store2.logStart("tool", `algolia ${args.join(" ")}`);
|
|
21
41
|
return new Promise((resolve4, reject) => {
|
|
22
|
-
const child = spawn(
|
|
42
|
+
const child = spawn("npx", npxArgs(args), { shell });
|
|
23
43
|
let stdout = "";
|
|
24
44
|
let stderr = "";
|
|
25
|
-
|
|
26
|
-
|
|
45
|
+
const splitters = {
|
|
46
|
+
stdout: lineSplitter((line) => onOutput?.("stdout", line)),
|
|
47
|
+
stderr: lineSplitter((line) => onOutput?.("stderr", line))
|
|
48
|
+
};
|
|
49
|
+
child.stdout.on("data", (chunk) => {
|
|
50
|
+
const text = String(chunk);
|
|
51
|
+
stdout += text;
|
|
52
|
+
splitters.stdout.push(text);
|
|
53
|
+
});
|
|
54
|
+
child.stderr.on("data", (chunk) => {
|
|
55
|
+
const text = String(chunk);
|
|
56
|
+
stderr += text;
|
|
57
|
+
splitters.stderr.push(text);
|
|
58
|
+
});
|
|
27
59
|
child.on("error", reject);
|
|
28
60
|
child.on("close", (code) => {
|
|
61
|
+
splitters.stdout.flush();
|
|
62
|
+
splitters.stderr.flush();
|
|
29
63
|
if (code === 0) {
|
|
30
64
|
resolve4(stdout);
|
|
31
65
|
} else {
|
|
@@ -37,7 +71,16 @@ function runAlgoliaCli(args) {
|
|
|
37
71
|
);
|
|
38
72
|
}
|
|
39
73
|
});
|
|
40
|
-
})
|
|
74
|
+
}).then(
|
|
75
|
+
(out) => {
|
|
76
|
+
useWizard.getState().logEnd(logId, "success");
|
|
77
|
+
return out;
|
|
78
|
+
},
|
|
79
|
+
(err) => {
|
|
80
|
+
useWizard.getState().logEnd(logId, "error");
|
|
81
|
+
throw err;
|
|
82
|
+
}
|
|
83
|
+
);
|
|
41
84
|
}
|
|
42
85
|
async function getUser() {
|
|
43
86
|
let raw;
|
|
@@ -52,13 +95,21 @@ async function getUser() {
|
|
|
52
95
|
return null;
|
|
53
96
|
}
|
|
54
97
|
}
|
|
98
|
+
function needsInteractiveTerminal(err) {
|
|
99
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
100
|
+
return /non-interactive mode/i.test(message);
|
|
101
|
+
}
|
|
55
102
|
function runAuthLogin() {
|
|
103
|
+
return runAlgoliaCli(["auth", "login", "--default"], {
|
|
104
|
+
onOutput: wizardSink
|
|
105
|
+
}).then(() => void 0);
|
|
106
|
+
}
|
|
107
|
+
function runAuthLoginInTerminal() {
|
|
56
108
|
return new Promise((resolve4, reject) => {
|
|
57
|
-
const child = spawn(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
);
|
|
109
|
+
const child = spawn("npx", npxArgs(["auth", "login", "--default"]), {
|
|
110
|
+
shell,
|
|
111
|
+
stdio: "inherit"
|
|
112
|
+
});
|
|
62
113
|
child.on("error", reject);
|
|
63
114
|
child.on("close", (code) => {
|
|
64
115
|
if (code === 0) resolve4();
|
|
@@ -171,6 +222,7 @@ function describeInputValue(value) {
|
|
|
171
222
|
return Array.isArray(value) ? value.join(", ") : value;
|
|
172
223
|
}
|
|
173
224
|
var NOTICE_INTERVAL_MS = 2e3;
|
|
225
|
+
var CLI_OUTPUT_LIMIT = 200;
|
|
174
226
|
var useWizard = create((set, get) => ({
|
|
175
227
|
phase: "idle",
|
|
176
228
|
homeScreen: "home",
|
|
@@ -182,10 +234,23 @@ var useWizard = create((set, get) => ({
|
|
|
182
234
|
notices: [],
|
|
183
235
|
_noticeQueue: [],
|
|
184
236
|
_noticeTimer: null,
|
|
237
|
+
cliOutput: [],
|
|
238
|
+
targetIndex: null,
|
|
185
239
|
logs: [],
|
|
186
240
|
error: null,
|
|
187
241
|
inputReq: null,
|
|
188
242
|
_resolve: null,
|
|
243
|
+
// Brackets a CLI subprocess that needs the screen. `endAuth` must land back
|
|
244
|
+
// on exactly 'idle': `confirmStart` is a no-op from any other phase and
|
|
245
|
+
// `waitForStart` resolves on any non-idle phase, so ending anywhere else
|
|
246
|
+
// either skips the welcome screen or ignores its spacebar forever.
|
|
247
|
+
beginAuth: () => set({ phase: "authenticating", cliOutput: [] }),
|
|
248
|
+
// Re-enters the auth phase *keeping* the CLI output on screen, for returning
|
|
249
|
+
// from a prompt raised mid-sign-in (`submitInput` leaves the phase at
|
|
250
|
+
// 'running'). Clearing here would blank the login output the user was reading
|
|
251
|
+
// the instant they answered.
|
|
252
|
+
resumeAuth: () => set({ phase: "authenticating" }),
|
|
253
|
+
endAuth: () => set((s) => s.phase === "authenticating" ? { phase: "idle" } : {}),
|
|
189
254
|
// Advances past the welcome screen. Only meaningful from 'idle' — once the
|
|
190
255
|
// workflow is running there's nothing left to confirm.
|
|
191
256
|
// Reset `homeScreen` so preflight shows Welcome, not the Learn more sub-view.
|
|
@@ -220,7 +285,13 @@ var useWizard = create((set, get) => ({
|
|
|
220
285
|
syncSteps: (steps, currentStepIndex) => set({ steps, currentStepIndex }),
|
|
221
286
|
setActiveStep: (index) => {
|
|
222
287
|
get()._clearNoticeQueue();
|
|
223
|
-
set({
|
|
288
|
+
set({
|
|
289
|
+
phase: "running",
|
|
290
|
+
currentStepIndex: index,
|
|
291
|
+
output: "",
|
|
292
|
+
notices: [],
|
|
293
|
+
cliOutput: []
|
|
294
|
+
});
|
|
224
295
|
},
|
|
225
296
|
setUser: (user2) => set({ user: user2 }),
|
|
226
297
|
appendToken: (text) => set((s) => ({ output: s.output + text })),
|
|
@@ -261,6 +332,16 @@ var useWizard = create((set, get) => ({
|
|
|
261
332
|
get()._clearNoticeQueue();
|
|
262
333
|
set({ notices: [] });
|
|
263
334
|
},
|
|
335
|
+
// Unthrottled, unlike `pushNotice`: these lines arrive at whatever rate the
|
|
336
|
+
// subprocess emits them, and holding them back would land output after the
|
|
337
|
+
// command it belongs to has already exited.
|
|
338
|
+
pushCliOutput: (stream, text) => set((s) => ({
|
|
339
|
+
cliOutput: [...s.cliOutput, { id: nanoid(), stream, text }].slice(
|
|
340
|
+
-CLI_OUTPUT_LIMIT
|
|
341
|
+
)
|
|
342
|
+
})),
|
|
343
|
+
clearCliOutput: () => set({ cliOutput: [] }),
|
|
344
|
+
setTargetIndex: (index) => set({ targetIndex: index }),
|
|
264
345
|
logStart: (kind, name, input) => {
|
|
265
346
|
const id = nanoid();
|
|
266
347
|
set((s) => ({
|
|
@@ -305,6 +386,8 @@ var useWizard = create((set, get) => ({
|
|
|
305
386
|
currentStepIndex: 0,
|
|
306
387
|
output: "",
|
|
307
388
|
notices: [],
|
|
389
|
+
cliOutput: [],
|
|
390
|
+
targetIndex: null,
|
|
308
391
|
logs: [],
|
|
309
392
|
error: null,
|
|
310
393
|
inputReq: null,
|
|
@@ -313,16 +396,88 @@ var useWizard = create((set, get) => ({
|
|
|
313
396
|
}
|
|
314
397
|
}));
|
|
315
398
|
|
|
399
|
+
// src/ui/CliOutput.tsx
|
|
400
|
+
import { Box, Text, useWindowSize } from "ink";
|
|
401
|
+
|
|
402
|
+
// src/ui/theme.ts
|
|
403
|
+
var MARKER = {
|
|
404
|
+
pending: "\u25CB",
|
|
405
|
+
running: "\u25D0",
|
|
406
|
+
done: "\u2713",
|
|
407
|
+
error: "\u2716"
|
|
408
|
+
};
|
|
409
|
+
var BRAND = "#003DFF";
|
|
410
|
+
var SECONDARY = "#5468FF";
|
|
411
|
+
var DANGER = "#F86E7E";
|
|
412
|
+
var COLORS = {
|
|
413
|
+
brand: BRAND,
|
|
414
|
+
primary: "#E6EDF3",
|
|
415
|
+
secondary: SECONDARY,
|
|
416
|
+
strong: "#FFFFFF",
|
|
417
|
+
muted: "#8B949E",
|
|
418
|
+
dim: "#484F58",
|
|
419
|
+
highlight: { bg: "#12331C", fg: "#4ADE80" },
|
|
420
|
+
badge: "#E3B341",
|
|
421
|
+
danger: DANGER,
|
|
422
|
+
success: "#4ADE80",
|
|
423
|
+
bg: {
|
|
424
|
+
main: "#0B0E14",
|
|
425
|
+
sidebar: "#14171E"
|
|
426
|
+
},
|
|
427
|
+
border: "#30363D",
|
|
428
|
+
accent: "#76A0FF",
|
|
429
|
+
status: {
|
|
430
|
+
pending: "gray",
|
|
431
|
+
running: "#76A0FF",
|
|
432
|
+
done: "#4ADE80",
|
|
433
|
+
error: DANGER
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
// src/ui/CliOutput.tsx
|
|
438
|
+
import { jsxs } from "react/jsx-runtime";
|
|
439
|
+
var CLI_MARKER = "\u203A";
|
|
440
|
+
var RESERVED_ROWS = 16;
|
|
441
|
+
var MAX_LINES = 12;
|
|
442
|
+
function CliOutput() {
|
|
443
|
+
const cliOutput = useWizard((s) => s.cliOutput);
|
|
444
|
+
const { rows } = useWindowSize();
|
|
445
|
+
if (!cliOutput.length) return null;
|
|
446
|
+
const budget = Math.min(Math.max(rows - RESERVED_ROWS, 3), MAX_LINES);
|
|
447
|
+
const visible = cliOutput.slice(-budget);
|
|
448
|
+
const hidden = cliOutput.length - visible.length;
|
|
449
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
450
|
+
hidden > 0 && /* @__PURE__ */ jsxs(Text, { color: COLORS.dim, children: [
|
|
451
|
+
"\u2191 ",
|
|
452
|
+
hidden,
|
|
453
|
+
" earlier line(s)"
|
|
454
|
+
] }),
|
|
455
|
+
visible.map((line) => /* @__PURE__ */ jsxs(
|
|
456
|
+
Text,
|
|
457
|
+
{
|
|
458
|
+
color: line.stream === "stderr" ? COLORS.muted : COLORS.dim,
|
|
459
|
+
wrap: "truncate",
|
|
460
|
+
children: [
|
|
461
|
+
CLI_MARKER,
|
|
462
|
+
" ",
|
|
463
|
+
line.text
|
|
464
|
+
]
|
|
465
|
+
},
|
|
466
|
+
line.id
|
|
467
|
+
))
|
|
468
|
+
] });
|
|
469
|
+
}
|
|
470
|
+
|
|
316
471
|
// src/ui/Notices.tsx
|
|
317
|
-
import { Box as
|
|
472
|
+
import { Box as Box3, Text as Text3, useWindowSize as useWindowSize3 } from "ink";
|
|
318
473
|
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
319
474
|
|
|
320
475
|
// src/ui/Table.tsx
|
|
321
|
-
import { Box, Text, measureElement, useWindowSize } from "ink";
|
|
476
|
+
import { Box as Box2, Text as Text2, measureElement, useWindowSize as useWindowSize2 } from "ink";
|
|
322
477
|
import { useEffect, useRef, useState } from "react";
|
|
323
478
|
import { jsx } from "react/jsx-runtime";
|
|
324
479
|
function Table({ columns, rows }) {
|
|
325
|
-
const { columns: termCols } =
|
|
480
|
+
const { columns: termCols } = useWindowSize2();
|
|
326
481
|
const ref = useRef(null);
|
|
327
482
|
const [width, setWidth] = useState(0);
|
|
328
483
|
useEffect(() => {
|
|
@@ -330,7 +485,7 @@ function Table({ columns, rows }) {
|
|
|
330
485
|
}, [termCols, columns, rows]);
|
|
331
486
|
if (rows.length === 0) return null;
|
|
332
487
|
const lines = formatTable(columns, rows, width || void 0);
|
|
333
|
-
return /* @__PURE__ */ jsx(
|
|
488
|
+
return /* @__PURE__ */ jsx(Box2, { flexDirection: "column", ref, children: lines.map((line, i) => /* @__PURE__ */ jsx(Text2, { wrap: "truncate", children: line }, `tbl-${i}`)) });
|
|
334
489
|
}
|
|
335
490
|
function formatTable(columns, rows, width) {
|
|
336
491
|
const natural = columns.map(
|
|
@@ -370,45 +525,10 @@ function resize(widths, budget) {
|
|
|
370
525
|
}
|
|
371
526
|
var truncate = (s, width) => s.length <= width ? s : width <= 1 ? s.slice(0, width) : `${s.slice(0, width - 1)}\u2026`;
|
|
372
527
|
|
|
373
|
-
// src/ui/theme.ts
|
|
374
|
-
var MARKER = {
|
|
375
|
-
pending: "\u25CB",
|
|
376
|
-
running: "\u25D0",
|
|
377
|
-
done: "\u2713",
|
|
378
|
-
error: "\u2716"
|
|
379
|
-
};
|
|
380
|
-
var BRAND = "#003DFF";
|
|
381
|
-
var SECONDARY = "#5468FF";
|
|
382
|
-
var DANGER = "#F86E7E";
|
|
383
|
-
var COLORS = {
|
|
384
|
-
brand: BRAND,
|
|
385
|
-
primary: "#E6EDF3",
|
|
386
|
-
secondary: SECONDARY,
|
|
387
|
-
strong: "#FFFFFF",
|
|
388
|
-
muted: "#8B949E",
|
|
389
|
-
dim: "#484F58",
|
|
390
|
-
highlight: { bg: "#12331C", fg: "#4ADE80" },
|
|
391
|
-
badge: "#E3B341",
|
|
392
|
-
danger: DANGER,
|
|
393
|
-
success: "#4ADE80",
|
|
394
|
-
bg: {
|
|
395
|
-
main: "#0B0E14",
|
|
396
|
-
sidebar: "#14171E"
|
|
397
|
-
},
|
|
398
|
-
border: "#30363D",
|
|
399
|
-
accent: "#76A0FF",
|
|
400
|
-
status: {
|
|
401
|
-
pending: "gray",
|
|
402
|
-
running: "#76A0FF",
|
|
403
|
-
done: "#4ADE80",
|
|
404
|
-
error: DANGER
|
|
405
|
-
}
|
|
406
|
-
};
|
|
407
|
-
|
|
408
528
|
// src/ui/Notices.tsx
|
|
409
|
-
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
529
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
410
530
|
var AGENT_MARKER = "\u2726";
|
|
411
|
-
var
|
|
531
|
+
var RESERVED_ROWS2 = 14;
|
|
412
532
|
var PANEL_TEXT_WIDTH = 45;
|
|
413
533
|
function messageLineCount(text) {
|
|
414
534
|
return Math.max(1, Math.ceil(text.length / PANEL_TEXT_WIDTH));
|
|
@@ -422,7 +542,7 @@ function noticeLineCount(notice) {
|
|
|
422
542
|
return messageLines + tableLines;
|
|
423
543
|
}
|
|
424
544
|
function fitVisibleNotices(notices, windowRows) {
|
|
425
|
-
const budget = Math.max(windowRows -
|
|
545
|
+
const budget = Math.max(windowRows - RESERVED_ROWS2, 3);
|
|
426
546
|
let used = 0;
|
|
427
547
|
let count = 0;
|
|
428
548
|
for (let i = notices.length - 1; i >= 0; i--) {
|
|
@@ -455,7 +575,7 @@ function parseHex(hex) {
|
|
|
455
575
|
}
|
|
456
576
|
function Notices() {
|
|
457
577
|
const notices = useWizard((s) => s.notices);
|
|
458
|
-
const { rows: windowRows } =
|
|
578
|
+
const { rows: windowRows } = useWindowSize3();
|
|
459
579
|
const visible = fitVisibleNotices(notices, windowRows);
|
|
460
580
|
const [pulseStep, setPulseStep] = useState2(0);
|
|
461
581
|
useEffect2(() => {
|
|
@@ -472,14 +592,14 @@ function Notices() {
|
|
|
472
592
|
}, []);
|
|
473
593
|
if (!visible.length) return null;
|
|
474
594
|
const pulseColor = PULSE_COLORS[pulseStep];
|
|
475
|
-
return /* @__PURE__ */ jsx2(
|
|
595
|
+
return /* @__PURE__ */ jsx2(Box3, { flexDirection: "column", gap: 1, marginBottom: 1, children: visible.map((notice, i) => {
|
|
476
596
|
const isLatest = i === visible.length - 1;
|
|
477
|
-
return /* @__PURE__ */
|
|
597
|
+
return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", children: [
|
|
478
598
|
notice.messages?.map((m, j) => {
|
|
479
599
|
const line = typeof m === "string" ? { text: m } : m;
|
|
480
600
|
const prefix = j === 0 ? `${AGENT_MARKER} ` : " ";
|
|
481
|
-
return /* @__PURE__ */
|
|
482
|
-
|
|
601
|
+
return /* @__PURE__ */ jsxs2(
|
|
602
|
+
Text3,
|
|
483
603
|
{
|
|
484
604
|
color: isLatest && !line.color ? pulseColor : line.color ?? COLORS.dim,
|
|
485
605
|
bold: line.bold,
|
|
@@ -497,37 +617,37 @@ function Notices() {
|
|
|
497
617
|
}
|
|
498
618
|
|
|
499
619
|
// src/ui/PromptInput.tsx
|
|
500
|
-
import { Box as
|
|
620
|
+
import { Box as Box6, Text as Text6, useInput as useInput2 } from "ink";
|
|
501
621
|
import TextInput from "ink-text-input";
|
|
502
622
|
import { useState as useState4 } from "react";
|
|
503
623
|
|
|
504
624
|
// src/ui/NextAction.tsx
|
|
505
|
-
import { Box as
|
|
506
|
-
import { Fragment, jsx as jsx3, jsxs as
|
|
625
|
+
import { Box as Box4, Text as Text4 } from "ink";
|
|
626
|
+
import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
507
627
|
function NextAction({
|
|
508
628
|
action,
|
|
509
629
|
keyHint,
|
|
510
630
|
hierarchy = "primary"
|
|
511
631
|
}) {
|
|
512
|
-
return /* @__PURE__ */
|
|
513
|
-
hierarchy === "primary" && /* @__PURE__ */ jsx3(
|
|
514
|
-
hierarchy === "secondary" && /* @__PURE__ */
|
|
515
|
-
/* @__PURE__ */ jsx3(
|
|
516
|
-
/* @__PURE__ */ jsx3(
|
|
632
|
+
return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "row", gap: 1, children: [
|
|
633
|
+
hierarchy === "primary" && /* @__PURE__ */ jsx3(Text4, { color: COLORS.success, bold: true, children: `> ${action}` }),
|
|
634
|
+
hierarchy === "secondary" && /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
635
|
+
/* @__PURE__ */ jsx3(Text4, { color: COLORS.success, bold: true, children: `>` }),
|
|
636
|
+
/* @__PURE__ */ jsx3(Text4, { color: COLORS.primary, bold: true, children: action })
|
|
517
637
|
] }),
|
|
518
|
-
/* @__PURE__ */
|
|
519
|
-
/* @__PURE__ */ jsx3(
|
|
520
|
-
/* @__PURE__ */ jsx3(
|
|
521
|
-
/* @__PURE__ */ jsx3(
|
|
522
|
-
/* @__PURE__ */ jsx3(
|
|
638
|
+
/* @__PURE__ */ jsxs3(Box4, { children: [
|
|
639
|
+
/* @__PURE__ */ jsx3(Text4, { color: COLORS.muted, children: "press " }),
|
|
640
|
+
/* @__PURE__ */ jsx3(Text4, { color: COLORS.muted, children: `[` }),
|
|
641
|
+
/* @__PURE__ */ jsx3(Text4, { color: COLORS.primary, children: keyHint }),
|
|
642
|
+
/* @__PURE__ */ jsx3(Text4, { color: COLORS.muted, children: `]` })
|
|
523
643
|
] })
|
|
524
644
|
] });
|
|
525
645
|
}
|
|
526
646
|
|
|
527
647
|
// src/ui/SelectPrompt.tsx
|
|
528
|
-
import { Box as
|
|
648
|
+
import { Box as Box5, Text as Text5, measureElement as measureElement2, useInput, useWindowSize as useWindowSize4 } from "ink";
|
|
529
649
|
import { useLayoutEffect, useRef as useRef2, useState as useState3 } from "react";
|
|
530
|
-
import { jsx as jsx4, jsxs as
|
|
650
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
531
651
|
var CANCEL = "cancel";
|
|
532
652
|
var ARROW_WIDTH = 4;
|
|
533
653
|
var COLUMN_GAP = 2;
|
|
@@ -564,7 +684,7 @@ function SelectPrompt({
|
|
|
564
684
|
if (multi) hints.push({ key: "[space]", label: "select" });
|
|
565
685
|
hints.push({ key: "[enter]", label: "confirm" });
|
|
566
686
|
const containerRef = useRef2(null);
|
|
567
|
-
const { columns } =
|
|
687
|
+
const { columns } = useWindowSize4();
|
|
568
688
|
const [width, setWidth] = useState3(columns);
|
|
569
689
|
useLayoutEffect(() => {
|
|
570
690
|
if (containerRef.current) {
|
|
@@ -609,53 +729,53 @@ function SelectPrompt({
|
|
|
609
729
|
}
|
|
610
730
|
}
|
|
611
731
|
});
|
|
612
|
-
return /* @__PURE__ */ jsx4(
|
|
613
|
-
error && /* @__PURE__ */ jsx4(
|
|
614
|
-
messages?.map((m, i) => /* @__PURE__ */ jsx4(
|
|
732
|
+
return /* @__PURE__ */ jsx4(Box5, { ref: containerRef, flexGrow: 1, children: /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", gap: 1, width, children: [
|
|
733
|
+
error && /* @__PURE__ */ jsx4(Text5, { color: COLORS.danger, children: error }),
|
|
734
|
+
messages?.map((m, i) => /* @__PURE__ */ jsx4(Text5, { color: COLORS.muted, children: m }, `msg-${i}`)),
|
|
615
735
|
table && /* @__PURE__ */ jsx4(Table, { columns: table.columns, rows: table.rows }),
|
|
616
|
-
/* @__PURE__ */
|
|
617
|
-
question && /* @__PURE__ */ jsx4(
|
|
618
|
-
helpText && /* @__PURE__ */ jsx4(
|
|
736
|
+
/* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
|
|
737
|
+
question && /* @__PURE__ */ jsx4(Text5, { color: COLORS.muted, children: question }),
|
|
738
|
+
helpText && /* @__PURE__ */ jsx4(Text5, { color: COLORS.dim, children: helpText })
|
|
619
739
|
] }),
|
|
620
|
-
/* @__PURE__ */ jsx4(
|
|
740
|
+
/* @__PURE__ */ jsx4(Box5, { flexDirection: "column", children: rows.map((option, i) => {
|
|
621
741
|
const highlighted = i === index;
|
|
622
742
|
const isCancel = i === cancelIndex;
|
|
623
743
|
const bullet = multi && !isCancel ? checked.has(i) ? "\u25CF " : "\u25CB " : "";
|
|
624
744
|
const sec = isCancel ? void 0 : secondary?.[i];
|
|
625
745
|
const labelColor = highlighted ? COLORS.highlight.fg : void 0;
|
|
626
|
-
const label = /* @__PURE__ */
|
|
746
|
+
const label = /* @__PURE__ */ jsxs4(Text5, { color: labelColor, wrap: "truncate", children: [
|
|
627
747
|
highlighted ? "\u276F " : " ",
|
|
628
748
|
bullet,
|
|
629
749
|
option
|
|
630
750
|
] });
|
|
631
751
|
const isText = sec?.kind === "text";
|
|
632
|
-
return /* @__PURE__ */
|
|
633
|
-
|
|
752
|
+
return /* @__PURE__ */ jsxs4(
|
|
753
|
+
Box5,
|
|
634
754
|
{
|
|
635
755
|
width: isText ? "100%" : barWidth,
|
|
636
756
|
paddingX: 1,
|
|
637
757
|
paddingY: 1,
|
|
638
758
|
backgroundColor: highlighted ? COLORS.highlight.bg : void 0,
|
|
639
759
|
children: [
|
|
640
|
-
/* @__PURE__ */ jsx4(
|
|
641
|
-
isText && textWidth > 0 && /* @__PURE__ */ jsx4(
|
|
642
|
-
|
|
760
|
+
/* @__PURE__ */ jsx4(Box5, { width: isText ? labelWidth : barLabelWidth, children: label }),
|
|
761
|
+
isText && textWidth > 0 && /* @__PURE__ */ jsx4(Box5, { width: textWidth, children: /* @__PURE__ */ jsx4(
|
|
762
|
+
Text5,
|
|
643
763
|
{
|
|
644
764
|
wrap: "truncate",
|
|
645
765
|
color: highlighted ? COLORS.primary : COLORS.muted,
|
|
646
766
|
children: sec.value
|
|
647
767
|
}
|
|
648
768
|
) }),
|
|
649
|
-
sec?.kind === "badge" && /* @__PURE__ */ jsx4(
|
|
769
|
+
sec?.kind === "badge" && /* @__PURE__ */ jsx4(Box5, { width: badgeWidth, justifyContent: "flex-end", children: /* @__PURE__ */ jsx4(Text5, { color: COLORS.badge, wrap: "truncate", children: sec.value }) })
|
|
650
770
|
]
|
|
651
771
|
},
|
|
652
772
|
`row-${i}`
|
|
653
773
|
);
|
|
654
774
|
}) }),
|
|
655
|
-
/* @__PURE__ */ jsx4(
|
|
775
|
+
/* @__PURE__ */ jsx4(Text5, { children: hints.map(({ key, label }, i) => /* @__PURE__ */ jsxs4(Text5, { children: [
|
|
656
776
|
i > 0 ? " " : "",
|
|
657
|
-
/* @__PURE__ */ jsx4(
|
|
658
|
-
/* @__PURE__ */
|
|
777
|
+
/* @__PURE__ */ jsx4(Text5, { color: COLORS.primary, children: key }),
|
|
778
|
+
/* @__PURE__ */ jsxs4(Text5, { color: COLORS.dim, children: [
|
|
659
779
|
" ",
|
|
660
780
|
label
|
|
661
781
|
] })
|
|
@@ -664,7 +784,7 @@ function SelectPrompt({
|
|
|
664
784
|
}
|
|
665
785
|
|
|
666
786
|
// src/ui/PromptInput.tsx
|
|
667
|
-
import { jsx as jsx5, jsxs as
|
|
787
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
668
788
|
var ACCEPT_REJECT_OPTIONS = ["Accept", "Reject"];
|
|
669
789
|
function SpaceToContinuePrompt({
|
|
670
790
|
question,
|
|
@@ -675,10 +795,10 @@ function SpaceToContinuePrompt({
|
|
|
675
795
|
if (input === " ") onDecide(true);
|
|
676
796
|
else if (key.escape) onDecide(false);
|
|
677
797
|
});
|
|
678
|
-
return /* @__PURE__ */
|
|
679
|
-
messages?.map((m, i) => /* @__PURE__ */ jsx5(
|
|
680
|
-
question && /* @__PURE__ */ jsx5(
|
|
681
|
-
/* @__PURE__ */
|
|
798
|
+
return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", gap: 1, children: [
|
|
799
|
+
messages?.map((m, i) => /* @__PURE__ */ jsx5(Text6, { color: COLORS.muted, children: m }, `msg-${i}`)),
|
|
800
|
+
question && /* @__PURE__ */ jsx5(Text6, { color: COLORS.primary, children: question }),
|
|
801
|
+
/* @__PURE__ */ jsxs5(Box6, { gap: 1, flexDirection: "column", children: [
|
|
682
802
|
/* @__PURE__ */ jsx5(NextAction, { action: "continue", keyHint: "space" }),
|
|
683
803
|
/* @__PURE__ */ jsx5(NextAction, { action: "decline", keyHint: "esc", hierarchy: "secondary" })
|
|
684
804
|
] })
|
|
@@ -688,11 +808,11 @@ function PromptInput() {
|
|
|
688
808
|
const { phase, inputReq, submitInput } = useWizard();
|
|
689
809
|
const [draft, setDraft] = useState4("");
|
|
690
810
|
if (phase === "done" || phase === "error") {
|
|
691
|
-
return /* @__PURE__ */ jsx5(
|
|
811
|
+
return /* @__PURE__ */ jsx5(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text6, { color: "gray", dimColor: true, children: "Press Enter or Esc to exit" }) });
|
|
692
812
|
}
|
|
693
813
|
if (phase !== "awaitingInput" || !inputReq) return null;
|
|
694
814
|
if (inputReq.promptType === "multipleChoice") {
|
|
695
|
-
return /* @__PURE__ */ jsx5(
|
|
815
|
+
return /* @__PURE__ */ jsx5(Box6, { children: /* @__PURE__ */ jsx5(
|
|
696
816
|
SelectPrompt,
|
|
697
817
|
{
|
|
698
818
|
question: inputReq.prompt,
|
|
@@ -709,7 +829,7 @@ function PromptInput() {
|
|
|
709
829
|
) });
|
|
710
830
|
}
|
|
711
831
|
if (inputReq.promptType === "multiSelect") {
|
|
712
|
-
return /* @__PURE__ */ jsx5(
|
|
832
|
+
return /* @__PURE__ */ jsx5(Box6, { children: /* @__PURE__ */ jsx5(
|
|
713
833
|
SelectPrompt,
|
|
714
834
|
{
|
|
715
835
|
multi: true,
|
|
@@ -724,7 +844,7 @@ function PromptInput() {
|
|
|
724
844
|
) });
|
|
725
845
|
}
|
|
726
846
|
if (inputReq.promptType === "notice") {
|
|
727
|
-
return /* @__PURE__ */ jsx5(
|
|
847
|
+
return /* @__PURE__ */ jsx5(Box6, { children: /* @__PURE__ */ jsx5(
|
|
728
848
|
SelectPrompt,
|
|
729
849
|
{
|
|
730
850
|
question: inputReq.prompt,
|
|
@@ -746,7 +866,7 @@ function PromptInput() {
|
|
|
746
866
|
}
|
|
747
867
|
if (inputReq.promptType === "acceptReject") {
|
|
748
868
|
const labels = inputReq.options?.length ? inputReq.options : ACCEPT_REJECT_OPTIONS;
|
|
749
|
-
return /* @__PURE__ */ jsx5(
|
|
869
|
+
return /* @__PURE__ */ jsx5(Box6, { children: /* @__PURE__ */ jsx5(
|
|
750
870
|
SelectPrompt,
|
|
751
871
|
{
|
|
752
872
|
question: inputReq.prompt,
|
|
@@ -757,11 +877,11 @@ function PromptInput() {
|
|
|
757
877
|
}
|
|
758
878
|
) });
|
|
759
879
|
}
|
|
760
|
-
return /* @__PURE__ */
|
|
761
|
-
inputReq.error && /* @__PURE__ */ jsx5(
|
|
762
|
-
inputReq.messages?.map((m, i) => /* @__PURE__ */ jsx5(
|
|
763
|
-
/* @__PURE__ */
|
|
764
|
-
/* @__PURE__ */
|
|
880
|
+
return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
|
|
881
|
+
inputReq.error && /* @__PURE__ */ jsx5(Text6, { color: COLORS.danger, children: inputReq.error }),
|
|
882
|
+
inputReq.messages?.map((m, i) => /* @__PURE__ */ jsx5(Text6, { color: COLORS.muted, children: m }, `msg-${i}`)),
|
|
883
|
+
/* @__PURE__ */ jsxs5(Box6, { children: [
|
|
884
|
+
/* @__PURE__ */ jsxs5(Text6, { color: COLORS.primary, children: [
|
|
765
885
|
inputReq.prompt,
|
|
766
886
|
" "
|
|
767
887
|
] }),
|
|
@@ -783,7 +903,7 @@ function PromptInput() {
|
|
|
783
903
|
// src/ui/Welcome.tsx
|
|
784
904
|
import { dirname as dirname2, join as join3 } from "node:path";
|
|
785
905
|
import { fileURLToPath } from "node:url";
|
|
786
|
-
import { Box as
|
|
906
|
+
import { Box as Box7, Spacer, Text as Text7, useInput as useInput3, useWindowSize as useWindowSize5 } from "ink";
|
|
787
907
|
|
|
788
908
|
// src/ui/copy/welcome.ts
|
|
789
909
|
var sidebarItems = [
|
|
@@ -811,27 +931,27 @@ var sidebarItems = [
|
|
|
811
931
|
|
|
812
932
|
// src/ui/Welcome.tsx
|
|
813
933
|
import Image, { InkPictureProvider } from "ink-picture";
|
|
814
|
-
import { jsx as jsx6, jsxs as
|
|
934
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
815
935
|
var IMAGE_PATH = join3(dirname2(fileURLToPath(import.meta.url)), "algolia.png");
|
|
816
936
|
function SidebarItem({
|
|
817
937
|
title,
|
|
818
938
|
description
|
|
819
939
|
}) {
|
|
820
|
-
return /* @__PURE__ */
|
|
821
|
-
/* @__PURE__ */
|
|
822
|
-
/* @__PURE__ */ jsx6(
|
|
823
|
-
/* @__PURE__ */ jsx6(
|
|
940
|
+
return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", children: [
|
|
941
|
+
/* @__PURE__ */ jsxs6(Box7, { gap: 1, children: [
|
|
942
|
+
/* @__PURE__ */ jsx6(Text7, { color: COLORS.success, children: "\u2192" }),
|
|
943
|
+
/* @__PURE__ */ jsx6(Text7, { color: COLORS.strong, bold: true, children: title })
|
|
824
944
|
] }),
|
|
825
|
-
/* @__PURE__ */
|
|
945
|
+
/* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", gap: 2, children: [
|
|
826
946
|
/* @__PURE__ */ jsx6(Spacer, {}),
|
|
827
|
-
/* @__PURE__ */ jsx6(
|
|
947
|
+
/* @__PURE__ */ jsx6(Text7, { color: COLORS.muted, children: description })
|
|
828
948
|
] })
|
|
829
949
|
] });
|
|
830
950
|
}
|
|
831
951
|
function Welcome() {
|
|
832
952
|
const confirmStart = useWizard((s) => s.confirmStart);
|
|
833
953
|
const openLearnMore = useWizard((s) => s.openLearnMore);
|
|
834
|
-
const { rows } =
|
|
954
|
+
const { rows } = useWindowSize5();
|
|
835
955
|
useInput3((input) => {
|
|
836
956
|
if (input === " ") confirmStart();
|
|
837
957
|
else if (input === "i") openLearnMore();
|
|
@@ -850,15 +970,15 @@ function Welcome() {
|
|
|
850
970
|
if (rows < 30) {
|
|
851
971
|
layout = scales["small"];
|
|
852
972
|
}
|
|
853
|
-
return /* @__PURE__ */
|
|
973
|
+
return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", justifyContent: "space-between", width: "100%", children: [
|
|
854
974
|
/* @__PURE__ */ jsx6(
|
|
855
|
-
|
|
975
|
+
Box7,
|
|
856
976
|
{
|
|
857
977
|
paddingY: layout.main.padding.y,
|
|
858
978
|
paddingX: layout.main.padding.x,
|
|
859
979
|
flexDirection: "column",
|
|
860
980
|
justifyContent: "center",
|
|
861
|
-
children: /* @__PURE__ */
|
|
981
|
+
children: /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", gap: 2, children: [
|
|
862
982
|
/* @__PURE__ */ jsx6(InkPictureProvider, { children: /* @__PURE__ */ jsx6(
|
|
863
983
|
Image,
|
|
864
984
|
{
|
|
@@ -870,16 +990,16 @@ function Welcome() {
|
|
|
870
990
|
protocol: "halfBlock"
|
|
871
991
|
}
|
|
872
992
|
) }),
|
|
873
|
-
/* @__PURE__ */ jsx6(
|
|
874
|
-
/* @__PURE__ */
|
|
993
|
+
/* @__PURE__ */ jsx6(Text7, { color: COLORS.muted, children: "\u2726 From zero \u2192 working search in ~10 minutes" }),
|
|
994
|
+
/* @__PURE__ */ jsxs6(Box7, { gap: 1, flexDirection: "column", children: [
|
|
875
995
|
/* @__PURE__ */ jsx6(NextAction, { action: "start wizard", keyHint: "space" }),
|
|
876
996
|
/* @__PURE__ */ jsx6(NextAction, { action: "learn more", keyHint: "i", hierarchy: "secondary" })
|
|
877
997
|
] })
|
|
878
998
|
] })
|
|
879
999
|
}
|
|
880
1000
|
),
|
|
881
|
-
/* @__PURE__ */
|
|
882
|
-
|
|
1001
|
+
/* @__PURE__ */ jsxs6(
|
|
1002
|
+
Box7,
|
|
883
1003
|
{
|
|
884
1004
|
backgroundColor: COLORS.bg.sidebar,
|
|
885
1005
|
width: 40,
|
|
@@ -889,7 +1009,7 @@ function Welcome() {
|
|
|
889
1009
|
flexDirection: "column",
|
|
890
1010
|
justifyContent: "center",
|
|
891
1011
|
children: [
|
|
892
|
-
/* @__PURE__ */ jsx6(
|
|
1012
|
+
/* @__PURE__ */ jsx6(Text7, { color: COLORS.muted, children: "WHAT THIS WIZARD WILL DO" }),
|
|
893
1013
|
sidebarItems.map((i, idx) => /* @__PURE__ */ jsx6(SidebarItem, { title: i.title, description: i.description }, idx))
|
|
894
1014
|
]
|
|
895
1015
|
}
|
|
@@ -899,7 +1019,7 @@ function Welcome() {
|
|
|
899
1019
|
|
|
900
1020
|
// src/ui/LearnMore.tsx
|
|
901
1021
|
import { Fragment as Fragment2 } from "react";
|
|
902
|
-
import { Box as
|
|
1022
|
+
import { Box as Box8, Text as Text8, useInput as useInput4, useWindowSize as useWindowSize6 } from "ink";
|
|
903
1023
|
|
|
904
1024
|
// src/ui/copy/learn-more.ts
|
|
905
1025
|
var accessIntro = "Everything runs locally on your machine. Nothing is written or sent without an explicit yes from you.";
|
|
@@ -936,7 +1056,7 @@ var policyLinks = [
|
|
|
936
1056
|
];
|
|
937
1057
|
|
|
938
1058
|
// src/ui/LearnMore.tsx
|
|
939
|
-
import { jsx as jsx7, jsxs as
|
|
1059
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
940
1060
|
var TAG_COLORS = {
|
|
941
1061
|
READ: COLORS.success,
|
|
942
1062
|
WRITE: COLORS.badge,
|
|
@@ -952,25 +1072,25 @@ function NeverLine({
|
|
|
952
1072
|
}) {
|
|
953
1073
|
const used = segments.reduce((n, s) => n + s.text.length, 0);
|
|
954
1074
|
const rightPad = Math.max(0, width - 2 - NEVER_BOX_PAD_X - used);
|
|
955
|
-
return /* @__PURE__ */
|
|
956
|
-
/* @__PURE__ */ jsx7(
|
|
1075
|
+
return /* @__PURE__ */ jsxs7(Text8, { children: [
|
|
1076
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.danger, children: "\u2502" }),
|
|
957
1077
|
" ".repeat(NEVER_BOX_PAD_X),
|
|
958
|
-
segments.map((s, i) => /* @__PURE__ */ jsx7(
|
|
1078
|
+
segments.map((s, i) => /* @__PURE__ */ jsx7(Text8, { color: s.color, bold: s.bold, children: s.text }, i)),
|
|
959
1079
|
" ".repeat(rightPad),
|
|
960
|
-
/* @__PURE__ */ jsx7(
|
|
1080
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.danger, children: "\u2502" })
|
|
961
1081
|
] });
|
|
962
1082
|
}
|
|
963
1083
|
function LearnMore() {
|
|
964
1084
|
const confirmStart = useWizard((s) => s.confirmStart);
|
|
965
1085
|
const backToHome = useWizard((s) => s.backToHome);
|
|
966
|
-
const { columns } =
|
|
1086
|
+
const { columns } = useWindowSize6();
|
|
967
1087
|
const dividerWidth = Math.max(0, columns - PADDING_X * 2);
|
|
968
1088
|
useInput4((input, key) => {
|
|
969
1089
|
if (key.escape) backToHome();
|
|
970
1090
|
else if (input === " ") confirmStart();
|
|
971
1091
|
});
|
|
972
|
-
return /* @__PURE__ */
|
|
973
|
-
|
|
1092
|
+
return /* @__PURE__ */ jsxs7(
|
|
1093
|
+
Box8,
|
|
974
1094
|
{
|
|
975
1095
|
flexDirection: "column",
|
|
976
1096
|
paddingX: PADDING_X,
|
|
@@ -978,20 +1098,20 @@ function LearnMore() {
|
|
|
978
1098
|
width: "100%",
|
|
979
1099
|
gap: 1,
|
|
980
1100
|
children: [
|
|
981
|
-
/* @__PURE__ */ jsx7(
|
|
982
|
-
/* @__PURE__ */ jsx7(
|
|
983
|
-
/* @__PURE__ */ jsx7(
|
|
984
|
-
/* @__PURE__ */ jsx7(
|
|
985
|
-
/* @__PURE__ */
|
|
986
|
-
/* @__PURE__ */ jsx7(
|
|
987
|
-
/* @__PURE__ */ jsx7(
|
|
988
|
-
/* @__PURE__ */ jsx7(
|
|
989
|
-
/* @__PURE__ */ jsx7(
|
|
1101
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.strong, bold: true, children: "What algolia wizard accesses" }),
|
|
1102
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: accessIntro }),
|
|
1103
|
+
/* @__PURE__ */ jsx7(Box8, { flexDirection: "column", children: accessItems.map((item) => /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", marginTop: 1, children: [
|
|
1104
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.border, children: "\u2500".repeat(dividerWidth) }),
|
|
1105
|
+
/* @__PURE__ */ jsxs7(Box8, { flexDirection: "row", gap: 1, marginTop: 1, children: [
|
|
1106
|
+
/* @__PURE__ */ jsx7(Box8, { width: TAG_COLUMN_WIDTH, flexShrink: 0, children: /* @__PURE__ */ jsx7(Text8, { color: TAG_COLORS[item.tag], bold: true, children: `[${item.tag}]` }) }),
|
|
1107
|
+
/* @__PURE__ */ jsx7(Box8, { flexDirection: "column", children: /* @__PURE__ */ jsxs7(Text8, { children: [
|
|
1108
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.strong, bold: true, children: item.title }),
|
|
1109
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: ` \u2014 ${item.description}` })
|
|
990
1110
|
] }) })
|
|
991
1111
|
] })
|
|
992
1112
|
] }, item.tag)) }),
|
|
993
|
-
/* @__PURE__ */
|
|
994
|
-
/* @__PURE__ */ jsx7(
|
|
1113
|
+
/* @__PURE__ */ jsxs7(Box8, { marginTop: 1, flexDirection: "column", children: [
|
|
1114
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.danger, children: `\u256D${"\u2500".repeat(Math.max(0, dividerWidth - 2))}\u256E` }),
|
|
995
1115
|
/* @__PURE__ */ jsx7(NeverLine, { width: dividerWidth }),
|
|
996
1116
|
/* @__PURE__ */ jsx7(
|
|
997
1117
|
NeverLine,
|
|
@@ -1000,7 +1120,7 @@ function LearnMore() {
|
|
|
1000
1120
|
segments: [{ text: "I NEVER", color: COLORS.danger, bold: true }]
|
|
1001
1121
|
}
|
|
1002
1122
|
),
|
|
1003
|
-
neverItems.map((item) => /* @__PURE__ */
|
|
1123
|
+
neverItems.map((item) => /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
1004
1124
|
/* @__PURE__ */ jsx7(NeverLine, { width: dividerWidth }),
|
|
1005
1125
|
/* @__PURE__ */ jsx7(
|
|
1006
1126
|
NeverLine,
|
|
@@ -1015,23 +1135,23 @@ function LearnMore() {
|
|
|
1015
1135
|
)
|
|
1016
1136
|
] }, item)),
|
|
1017
1137
|
/* @__PURE__ */ jsx7(NeverLine, { width: dividerWidth }),
|
|
1018
|
-
/* @__PURE__ */ jsx7(
|
|
1138
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.danger, children: `\u2570${"\u2500".repeat(Math.max(0, dividerWidth - 2))}\u256F` })
|
|
1019
1139
|
] }),
|
|
1020
|
-
/* @__PURE__ */ jsx7(
|
|
1021
|
-
/* @__PURE__ */ jsx7(
|
|
1022
|
-
/* @__PURE__ */ jsx7(
|
|
1140
|
+
/* @__PURE__ */ jsx7(Box8, { marginTop: 1, flexDirection: "column", children: policyLinks.map((link) => /* @__PURE__ */ jsxs7(Box8, { flexDirection: "row", gap: 1, children: [
|
|
1141
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.strong, bold: true, children: `${link.label}:` }),
|
|
1142
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.accent, children: link.url })
|
|
1023
1143
|
] }, link.label)) }),
|
|
1024
|
-
/* @__PURE__ */
|
|
1025
|
-
/* @__PURE__ */
|
|
1026
|
-
/* @__PURE__ */ jsx7(
|
|
1027
|
-
/* @__PURE__ */ jsx7(
|
|
1028
|
-
/* @__PURE__ */ jsx7(
|
|
1144
|
+
/* @__PURE__ */ jsxs7(Box8, { marginTop: 1, flexDirection: "row", gap: 3, children: [
|
|
1145
|
+
/* @__PURE__ */ jsxs7(Box8, { flexDirection: "row", gap: 1, children: [
|
|
1146
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: "[" }),
|
|
1147
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.primary, children: "esc" }),
|
|
1148
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: "] back" })
|
|
1029
1149
|
] }),
|
|
1030
|
-
/* @__PURE__ */
|
|
1031
|
-
/* @__PURE__ */ jsx7(
|
|
1032
|
-
/* @__PURE__ */ jsx7(
|
|
1033
|
-
/* @__PURE__ */ jsx7(
|
|
1034
|
-
/* @__PURE__ */ jsx7(
|
|
1150
|
+
/* @__PURE__ */ jsxs7(Box8, { flexDirection: "row", gap: 1, children: [
|
|
1151
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: "[" }),
|
|
1152
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.primary, children: "space" }),
|
|
1153
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: "]" }),
|
|
1154
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.success, bold: true, children: "start wizard" })
|
|
1035
1155
|
] })
|
|
1036
1156
|
] })
|
|
1037
1157
|
]
|
|
@@ -1040,10 +1160,10 @@ function LearnMore() {
|
|
|
1040
1160
|
}
|
|
1041
1161
|
|
|
1042
1162
|
// src/ui/Sidebar.tsx
|
|
1043
|
-
import { Box as
|
|
1163
|
+
import { Box as Box11, Text as Text11 } from "ink";
|
|
1044
1164
|
|
|
1045
1165
|
// src/ui/Steps.tsx
|
|
1046
|
-
import { Box as
|
|
1166
|
+
import { Box as Box9, Text as Text9 } from "ink";
|
|
1047
1167
|
import Spinner from "ink-spinner";
|
|
1048
1168
|
|
|
1049
1169
|
// src/core/persistence.ts
|
|
@@ -1072,11 +1192,11 @@ async function clearWorkflowState(workflowId) {
|
|
|
1072
1192
|
}
|
|
1073
1193
|
|
|
1074
1194
|
// src/ui/Steps.tsx
|
|
1075
|
-
import { jsx as jsx8, jsxs as
|
|
1195
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1076
1196
|
function Steps() {
|
|
1077
1197
|
const { steps } = useWizard();
|
|
1078
1198
|
const visibleSteps = steps.filter(isStepVisible);
|
|
1079
|
-
return /* @__PURE__ */ jsx8(
|
|
1199
|
+
return /* @__PURE__ */ jsx8(Box9, { flexDirection: "column", gap: 1, children: visibleSteps.map((s) => /* @__PURE__ */ jsx8(Box9, { flexDirection: "column", children: /* @__PURE__ */ jsxs8(Text9, { color: COLORS.status[s.status], children: [
|
|
1080
1200
|
s.status === "running" ? /* @__PURE__ */ jsx8(Spinner, { type: "dots" }) : MARKER[s.status],
|
|
1081
1201
|
" ",
|
|
1082
1202
|
s.title
|
|
@@ -1086,7 +1206,7 @@ function CurrentStep() {
|
|
|
1086
1206
|
const { steps } = useWizard();
|
|
1087
1207
|
const currentStep = steps.filter(isStepVisible).find((s) => s.status === "running");
|
|
1088
1208
|
if (!currentStep) return null;
|
|
1089
|
-
return /* @__PURE__ */
|
|
1209
|
+
return /* @__PURE__ */ jsxs8(Text9, { color: COLORS.status.running, children: [
|
|
1090
1210
|
/* @__PURE__ */ jsx8(Spinner, { type: "dots" }),
|
|
1091
1211
|
" ",
|
|
1092
1212
|
` ${currentStep.title}`
|
|
@@ -1094,19 +1214,19 @@ function CurrentStep() {
|
|
|
1094
1214
|
}
|
|
1095
1215
|
|
|
1096
1216
|
// src/ui/Progress.tsx
|
|
1097
|
-
import { Box as
|
|
1098
|
-
import { jsx as jsx9, jsxs as
|
|
1217
|
+
import { Box as Box10, Text as Text10 } from "ink";
|
|
1218
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1099
1219
|
function Progress() {
|
|
1100
1220
|
const { steps, currentStepIndex } = useWizard();
|
|
1101
1221
|
const visibleSteps = steps.filter(isStepVisible);
|
|
1102
1222
|
if (visibleSteps.length === 0) return null;
|
|
1103
1223
|
const visibleCountThroughCurrent = steps.slice(0, currentStepIndex + 1).filter(isStepVisible).length;
|
|
1104
1224
|
const activeStepNumber = Math.max(1, visibleCountThroughCurrent);
|
|
1105
|
-
return /* @__PURE__ */
|
|
1106
|
-
/* @__PURE__ */ jsx9(
|
|
1107
|
-
/* @__PURE__ */ jsx9(
|
|
1108
|
-
/* @__PURE__ */ jsx9(
|
|
1109
|
-
/* @__PURE__ */ jsx9(
|
|
1225
|
+
return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "row", gap: 1, children: [
|
|
1226
|
+
/* @__PURE__ */ jsx9(Text10, { color: COLORS.muted, children: "STEP" }),
|
|
1227
|
+
/* @__PURE__ */ jsx9(Text10, { bold: true, children: activeStepNumber }),
|
|
1228
|
+
/* @__PURE__ */ jsx9(Text10, { bold: true, children: "/" }),
|
|
1229
|
+
/* @__PURE__ */ jsx9(Text10, { bold: true, children: visibleSteps.length })
|
|
1110
1230
|
] });
|
|
1111
1231
|
}
|
|
1112
1232
|
|
|
@@ -1117,10 +1237,10 @@ var sidebarCommands = [
|
|
|
1117
1237
|
];
|
|
1118
1238
|
|
|
1119
1239
|
// src/ui/Sidebar.tsx
|
|
1120
|
-
import { jsx as jsx10, jsxs as
|
|
1240
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1121
1241
|
function Sidebar() {
|
|
1122
|
-
return /* @__PURE__ */
|
|
1123
|
-
|
|
1242
|
+
return /* @__PURE__ */ jsxs10(
|
|
1243
|
+
Box11,
|
|
1124
1244
|
{
|
|
1125
1245
|
backgroundColor: "#14171E",
|
|
1126
1246
|
width: 30,
|
|
@@ -1129,16 +1249,16 @@ function Sidebar() {
|
|
|
1129
1249
|
flexDirection: "column",
|
|
1130
1250
|
justifyContent: "space-between",
|
|
1131
1251
|
children: [
|
|
1132
|
-
/* @__PURE__ */
|
|
1133
|
-
/* @__PURE__ */ jsx10(
|
|
1252
|
+
/* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", gap: 1, children: [
|
|
1253
|
+
/* @__PURE__ */ jsx10(Text11, { color: COLORS.muted, children: "PROGRESS" }),
|
|
1134
1254
|
/* @__PURE__ */ jsx10(Steps, {})
|
|
1135
1255
|
] }),
|
|
1136
|
-
/* @__PURE__ */
|
|
1256
|
+
/* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", gap: 1, children: [
|
|
1137
1257
|
/* @__PURE__ */ jsx10(Progress, {}),
|
|
1138
|
-
/* @__PURE__ */ jsx10(
|
|
1139
|
-
return /* @__PURE__ */
|
|
1140
|
-
/* @__PURE__ */ jsx10(
|
|
1141
|
-
/* @__PURE__ */ jsx10(
|
|
1258
|
+
/* @__PURE__ */ jsx10(Box11, { flexDirection: "column", children: sidebarCommands.map((c) => {
|
|
1259
|
+
return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "row", gap: 1, children: [
|
|
1260
|
+
/* @__PURE__ */ jsx10(Text11, { color: COLORS.primary, children: `[${c.keyHint}]` }),
|
|
1261
|
+
/* @__PURE__ */ jsx10(Text11, { color: COLORS.muted, children: c.description })
|
|
1142
1262
|
] });
|
|
1143
1263
|
}) })
|
|
1144
1264
|
] })
|
|
@@ -1148,12 +1268,12 @@ function Sidebar() {
|
|
|
1148
1268
|
}
|
|
1149
1269
|
|
|
1150
1270
|
// src/ui/Ribbon.tsx
|
|
1151
|
-
import { Box as
|
|
1152
|
-
import { jsx as jsx11, jsxs as
|
|
1271
|
+
import { Box as Box12, Text as Text12 } from "ink";
|
|
1272
|
+
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1153
1273
|
function Ribbon() {
|
|
1154
1274
|
const firstCommand = sidebarCommands[0];
|
|
1155
|
-
return /* @__PURE__ */
|
|
1156
|
-
|
|
1275
|
+
return /* @__PURE__ */ jsxs11(
|
|
1276
|
+
Box12,
|
|
1157
1277
|
{
|
|
1158
1278
|
backgroundColor: "#14171E",
|
|
1159
1279
|
flexDirection: "row",
|
|
@@ -1163,9 +1283,9 @@ function Ribbon() {
|
|
|
1163
1283
|
children: [
|
|
1164
1284
|
/* @__PURE__ */ jsx11(Progress, {}),
|
|
1165
1285
|
/* @__PURE__ */ jsx11(CurrentStep, {}),
|
|
1166
|
-
/* @__PURE__ */
|
|
1167
|
-
/* @__PURE__ */ jsx11(
|
|
1168
|
-
/* @__PURE__ */ jsx11(
|
|
1286
|
+
/* @__PURE__ */ jsxs11(Box12, { flexDirection: "row", gap: 1, children: [
|
|
1287
|
+
/* @__PURE__ */ jsx11(Text12, { color: COLORS.primary, children: `[${firstCommand.keyHint}]` }),
|
|
1288
|
+
/* @__PURE__ */ jsx11(Text12, { color: COLORS.muted, children: firstCommand.description })
|
|
1169
1289
|
] })
|
|
1170
1290
|
]
|
|
1171
1291
|
}
|
|
@@ -1177,8 +1297,8 @@ import { useState as useState6 } from "react";
|
|
|
1177
1297
|
|
|
1178
1298
|
// src/ui/Logs.tsx
|
|
1179
1299
|
import { useLayoutEffect as useLayoutEffect2, useRef as useRef3, useState as useState5 } from "react";
|
|
1180
|
-
import { Box as
|
|
1181
|
-
import { jsx as jsx12, jsxs as
|
|
1300
|
+
import { Box as Box13, Text as Text13, measureElement as measureElement3, useInput as useInput5, useWindowSize as useWindowSize7 } from "ink";
|
|
1301
|
+
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1182
1302
|
var KIND_COLOR = {
|
|
1183
1303
|
tool: COLORS.primary,
|
|
1184
1304
|
prompt: COLORS.badge
|
|
@@ -1208,7 +1328,7 @@ function formatTimestamp(ms) {
|
|
|
1208
1328
|
}
|
|
1209
1329
|
function Logs() {
|
|
1210
1330
|
const logs = useWizard((s) => s.logs);
|
|
1211
|
-
const { rows, columns } =
|
|
1331
|
+
const { rows, columns } = useWindowSize7();
|
|
1212
1332
|
const viewportRef = useRef3(null);
|
|
1213
1333
|
const [viewportHeight, setViewportHeight] = useState5(0);
|
|
1214
1334
|
const [viewportWidth, setViewportWidth] = useState5(0);
|
|
@@ -1245,10 +1365,10 @@ function Logs() {
|
|
|
1245
1365
|
const visible = logs.slice(scrollOffset, scrollOffset + capacity);
|
|
1246
1366
|
const hiddenAbove = scrollOffset;
|
|
1247
1367
|
const hiddenBelow = logs.length - scrollOffset - visible.length;
|
|
1248
|
-
return /* @__PURE__ */
|
|
1249
|
-
logs.length === 0 && /* @__PURE__ */ jsx12(
|
|
1250
|
-
/* @__PURE__ */
|
|
1251
|
-
hiddenAbove > 0 && /* @__PURE__ */
|
|
1368
|
+
return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", paddingX: 4, paddingY: 2, flexGrow: 1, children: [
|
|
1369
|
+
logs.length === 0 && /* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, children: "No logs yet." }),
|
|
1370
|
+
/* @__PURE__ */ jsxs12(Box13, { ref: viewportRef, flexDirection: "column", flexGrow: 1, children: [
|
|
1371
|
+
hiddenAbove > 0 && /* @__PURE__ */ jsxs12(Text13, { color: COLORS.dim, children: [
|
|
1252
1372
|
"\u2191 ",
|
|
1253
1373
|
hiddenAbove,
|
|
1254
1374
|
" more"
|
|
@@ -1263,20 +1383,20 @@ function Logs() {
|
|
|
1263
1383
|
const name = truncate2(entry.name, budget);
|
|
1264
1384
|
budget -= name.length;
|
|
1265
1385
|
const preview = rawPreview ? truncate2(rawPreview, budget) : "";
|
|
1266
|
-
return /* @__PURE__ */
|
|
1267
|
-
/* @__PURE__ */ jsx12(
|
|
1268
|
-
/* @__PURE__ */ jsx12(
|
|
1269
|
-
preview && /* @__PURE__ */ jsx12(
|
|
1270
|
-
durationText && /* @__PURE__ */ jsx12(
|
|
1386
|
+
return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "row", gap: ROW_GAP, children: [
|
|
1387
|
+
/* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, children: timestamp }),
|
|
1388
|
+
/* @__PURE__ */ jsx12(Text13, { color: logNameColor(entry), wrap: "truncate", children: name }),
|
|
1389
|
+
preview && /* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, wrap: "truncate", children: preview }),
|
|
1390
|
+
durationText && /* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, children: durationText })
|
|
1271
1391
|
] }, entry.id);
|
|
1272
1392
|
}),
|
|
1273
|
-
hiddenBelow > 0 && /* @__PURE__ */
|
|
1393
|
+
hiddenBelow > 0 && /* @__PURE__ */ jsxs12(Text13, { color: COLORS.dim, children: [
|
|
1274
1394
|
"\u2193 ",
|
|
1275
1395
|
hiddenBelow,
|
|
1276
1396
|
" more"
|
|
1277
1397
|
] })
|
|
1278
1398
|
] }),
|
|
1279
|
-
/* @__PURE__ */ jsx12(
|
|
1399
|
+
/* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, children: "\u2191/\u2193 scroll" })
|
|
1280
1400
|
] });
|
|
1281
1401
|
}
|
|
1282
1402
|
|
|
@@ -1300,11 +1420,11 @@ function track(event, payload) {
|
|
|
1300
1420
|
}
|
|
1301
1421
|
|
|
1302
1422
|
// src/ui/App.tsx
|
|
1303
|
-
import { jsx as jsx13, jsxs as
|
|
1423
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1304
1424
|
function App() {
|
|
1305
1425
|
const { phase, error, homeScreen, currentStepIndex, steps, inputReq } = useWizard();
|
|
1306
1426
|
const { exit } = useApp();
|
|
1307
|
-
const { columns, rows } =
|
|
1427
|
+
const { columns, rows } = useWindowSize8();
|
|
1308
1428
|
const [showLogs, setShowLogs] = useState6(false);
|
|
1309
1429
|
const finished = phase === "done" || phase === "error";
|
|
1310
1430
|
const currentStep = steps[currentStepIndex];
|
|
@@ -1317,7 +1437,8 @@ function App() {
|
|
|
1317
1437
|
{ isActive: finished }
|
|
1318
1438
|
);
|
|
1319
1439
|
useInput6((_input, key) => {
|
|
1320
|
-
if (phase === "idle" || phase === "preflight")
|
|
1440
|
+
if (phase === "idle" || phase === "preflight" || phase === "authenticating")
|
|
1441
|
+
return;
|
|
1321
1442
|
if (key.tab) {
|
|
1322
1443
|
setShowLogs(!showLogs);
|
|
1323
1444
|
track("AI Wizard Interaction", {
|
|
@@ -1327,7 +1448,7 @@ function App() {
|
|
|
1327
1448
|
});
|
|
1328
1449
|
}
|
|
1329
1450
|
});
|
|
1330
|
-
const escOwnedElsewhere = phase === "idle" || phase === "awaitingInput" && inputReq?.promptType === "spaceToContinue";
|
|
1451
|
+
const escOwnedElsewhere = phase === "idle" || phase === "authenticating" || phase === "awaitingInput" && inputReq?.promptType === "spaceToContinue";
|
|
1331
1452
|
useInput6((_input, key) => {
|
|
1332
1453
|
if (escOwnedElsewhere) return;
|
|
1333
1454
|
if (key.escape) {
|
|
@@ -1340,19 +1461,19 @@ function App() {
|
|
|
1340
1461
|
exit();
|
|
1341
1462
|
}
|
|
1342
1463
|
});
|
|
1343
|
-
const mainWindowVisible = phase === "running" || phase === "awaitingInput" || phase === "error" || phase === "done";
|
|
1464
|
+
const mainWindowVisible = phase === "authenticating" || phase === "running" || phase === "awaitingInput" || phase === "error" || phase === "done";
|
|
1344
1465
|
const flexDirection = columns > 90 ? "row" : "column";
|
|
1345
1466
|
const showSidebar = flexDirection === "row";
|
|
1346
|
-
return /* @__PURE__ */
|
|
1347
|
-
|
|
1467
|
+
return /* @__PURE__ */ jsxs13(
|
|
1468
|
+
Box14,
|
|
1348
1469
|
{
|
|
1349
1470
|
backgroundColor: COLORS.bg.main,
|
|
1350
1471
|
flexDirection: "row",
|
|
1351
1472
|
width: columns,
|
|
1352
1473
|
minHeight: rows,
|
|
1353
1474
|
children: [
|
|
1354
|
-
mainWindowVisible && /* @__PURE__ */
|
|
1355
|
-
|
|
1475
|
+
mainWindowVisible && /* @__PURE__ */ jsxs13(
|
|
1476
|
+
Box14,
|
|
1356
1477
|
{
|
|
1357
1478
|
flexDirection,
|
|
1358
1479
|
width: "100%",
|
|
@@ -1360,8 +1481,8 @@ function App() {
|
|
|
1360
1481
|
children: [
|
|
1361
1482
|
showLogs ? /* @__PURE__ */ jsx13(Logs, {}) : (
|
|
1362
1483
|
/* Fill the width beside the sidebar; row layout only (would grow vertically when stacked). */
|
|
1363
|
-
/* @__PURE__ */
|
|
1364
|
-
|
|
1484
|
+
/* @__PURE__ */ jsxs13(
|
|
1485
|
+
Box14,
|
|
1365
1486
|
{
|
|
1366
1487
|
flexDirection: "column",
|
|
1367
1488
|
paddingX: 4,
|
|
@@ -1369,10 +1490,15 @@ function App() {
|
|
|
1369
1490
|
width: showSidebar ? 70 : "100%",
|
|
1370
1491
|
flexGrow: showSidebar ? 1 : 0,
|
|
1371
1492
|
children: [
|
|
1493
|
+
phase === "authenticating" && /* @__PURE__ */ jsxs13(Box14, { flexDirection: "column", marginBottom: 1, children: [
|
|
1494
|
+
/* @__PURE__ */ jsx13(Text14, { color: COLORS.strong, bold: true, children: "Signing in to Algolia" }),
|
|
1495
|
+
/* @__PURE__ */ jsx13(Text14, { color: COLORS.muted, children: "A browser window will open \u2014 complete sign-in there." })
|
|
1496
|
+
] }),
|
|
1497
|
+
/* @__PURE__ */ jsx13(CliOutput, {}),
|
|
1372
1498
|
/* @__PURE__ */ jsx13(Notices, {}),
|
|
1373
1499
|
/* @__PURE__ */ jsx13(PromptInput, {}),
|
|
1374
|
-
phase === "running" && showSidebar && /* @__PURE__ */ jsx13(
|
|
1375
|
-
phase === "error" && error && /* @__PURE__ */ jsx13(
|
|
1500
|
+
phase === "running" && showSidebar && /* @__PURE__ */ jsx13(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx13(CurrentStep, {}) }),
|
|
1501
|
+
phase === "error" && error && /* @__PURE__ */ jsx13(Box14, { marginTop: 1, children: /* @__PURE__ */ jsxs13(Text14, { color: COLORS.status.error, children: [
|
|
1376
1502
|
"\u2716 ",
|
|
1377
1503
|
error
|
|
1378
1504
|
] }) })
|
|
@@ -1784,61 +1910,134 @@ async function runWorkflow(workflow2, appId) {
|
|
|
1784
1910
|
}
|
|
1785
1911
|
}
|
|
1786
1912
|
|
|
1787
|
-
// src/lib/
|
|
1788
|
-
import {
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1913
|
+
// src/lib/algoliaApp.ts
|
|
1914
|
+
import { z as z3 } from "zod";
|
|
1915
|
+
var currentSchema = z3.object({
|
|
1916
|
+
id: z3.string().min(1),
|
|
1917
|
+
name: z3.string().default(""),
|
|
1918
|
+
plan: z3.string().optional()
|
|
1919
|
+
});
|
|
1920
|
+
var listSchema = z3.array(
|
|
1921
|
+
z3.object({
|
|
1922
|
+
id: z3.string().min(1),
|
|
1923
|
+
name: z3.string().default(""),
|
|
1924
|
+
plan_label: z3.string().optional()
|
|
1925
|
+
}).transform(({ id, name, plan_label }) => ({ id, name, plan: plan_label }))
|
|
1926
|
+
);
|
|
1927
|
+
async function currentApplication() {
|
|
1928
|
+
let raw;
|
|
1800
1929
|
try {
|
|
1801
|
-
|
|
1930
|
+
raw = await runAlgoliaCli(["application", "current", "-o", "json"]);
|
|
1802
1931
|
} catch {
|
|
1803
|
-
return
|
|
1932
|
+
return null;
|
|
1933
|
+
}
|
|
1934
|
+
const parsed = currentSchema.safeParse(parseJson(raw));
|
|
1935
|
+
return parsed.success ? parsed.data : null;
|
|
1936
|
+
}
|
|
1937
|
+
async function requireApplication() {
|
|
1938
|
+
const app2 = await currentApplication();
|
|
1939
|
+
if (!app2) {
|
|
1940
|
+
throw new Error(
|
|
1941
|
+
"No Algolia application is selected. Run `npx @algolia/cli@latest application select` and restart the wizard."
|
|
1942
|
+
);
|
|
1943
|
+
}
|
|
1944
|
+
return app2;
|
|
1945
|
+
}
|
|
1946
|
+
async function listApplications() {
|
|
1947
|
+
const raw = await runAlgoliaCli(["application", "list", "-o", "json"]);
|
|
1948
|
+
const parsed = listSchema.safeParse(parseJson(raw));
|
|
1949
|
+
if (!parsed.success) {
|
|
1950
|
+
throw new Error("Could not read the list of Algolia applications.");
|
|
1951
|
+
}
|
|
1952
|
+
return parsed.data;
|
|
1953
|
+
}
|
|
1954
|
+
function selectableApplications(apps) {
|
|
1955
|
+
const nameCounts = /* @__PURE__ */ new Map();
|
|
1956
|
+
for (const app2 of apps) {
|
|
1957
|
+
const name = app2.name.trim();
|
|
1958
|
+
if (name) nameCounts.set(name, (nameCounts.get(name) ?? 0) + 1);
|
|
1804
1959
|
}
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
isDefault: t.default === true
|
|
1812
|
-
}));
|
|
1813
|
-
profiles.sort((a, b) => Number(b.isDefault) - Number(a.isDefault));
|
|
1814
|
-
return profiles.map(({ name, appId, apiKey }) => ({ name, appId, apiKey }));
|
|
1815
|
-
}
|
|
1816
|
-
async function loadActiveProfile() {
|
|
1817
|
-
let profiles;
|
|
1960
|
+
return apps.filter((app2) => nameCounts.get(app2.name.trim()) === 1);
|
|
1961
|
+
}
|
|
1962
|
+
async function selectApplication(name) {
|
|
1963
|
+
await runAlgoliaCli(["application", "select", "--app-name", name]);
|
|
1964
|
+
}
|
|
1965
|
+
function parseJson(text) {
|
|
1818
1966
|
try {
|
|
1819
|
-
|
|
1967
|
+
return JSON.parse(text);
|
|
1820
1968
|
} catch {
|
|
1821
|
-
|
|
1969
|
+
return void 0;
|
|
1822
1970
|
}
|
|
1823
|
-
|
|
1824
|
-
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
// src/lib/algoliaAppPicker.ts
|
|
1974
|
+
function secondaryFor(app2) {
|
|
1975
|
+
return app2.plan ? { kind: "badge", value: app2.plan } : void 0;
|
|
1976
|
+
}
|
|
1977
|
+
async function promptForApplication() {
|
|
1978
|
+
const store2 = useWizard.getState();
|
|
1979
|
+
const phaseBefore = store2.phase;
|
|
1980
|
+
const all = await listApplications();
|
|
1981
|
+
const selectable = selectableApplications(all);
|
|
1982
|
+
const skipped = all.length - selectable.length;
|
|
1983
|
+
if (selectable.length === 0) {
|
|
1984
|
+
const why = all.length === 0 ? "this account has no applications" : "none of this account\u2019s applications have a unique name";
|
|
1825
1985
|
throw new Error(
|
|
1826
|
-
|
|
1986
|
+
`No selectable Algolia application was found: the CLI selects an application by name, and ${why}. Name one in the Algolia dashboard, or run \`npx @algolia/cli@latest application select\` directly.`
|
|
1987
|
+
);
|
|
1988
|
+
}
|
|
1989
|
+
const messages = ["Which Algolia application should the wizard work in?"];
|
|
1990
|
+
if (skipped > 0) {
|
|
1991
|
+
messages.push(
|
|
1992
|
+
`${skipped} application${skipped === 1 ? "" : "s"} not listed: the CLI selects by name, so unnamed and duplicate-named ones can\u2019t be chosen here.`
|
|
1993
|
+
);
|
|
1994
|
+
}
|
|
1995
|
+
for (; ; ) {
|
|
1996
|
+
const choice = await store2.requestUserInput({
|
|
1997
|
+
prompt: "Select an application",
|
|
1998
|
+
promptType: "multipleChoice",
|
|
1999
|
+
options: selectable.map((app2) => `${app2.name} \u2014 ${app2.id}`),
|
|
2000
|
+
secondary: selectable.map(secondaryFor),
|
|
2001
|
+
messages
|
|
2002
|
+
});
|
|
2003
|
+
const index = selectable.findIndex(
|
|
2004
|
+
(app2) => `${app2.name} \u2014 ${app2.id}` === choice
|
|
1827
2005
|
);
|
|
2006
|
+
const chosen = selectable[index];
|
|
2007
|
+
if (!chosen) {
|
|
2008
|
+
throw new Error("Application picker received an unexpected selection");
|
|
2009
|
+
}
|
|
2010
|
+
try {
|
|
2011
|
+
await selectApplication(chosen.name);
|
|
2012
|
+
} catch (err) {
|
|
2013
|
+
logger.warn(
|
|
2014
|
+
{ app: chosen.id, err: err.message },
|
|
2015
|
+
"application select failed; re-prompting"
|
|
2016
|
+
);
|
|
2017
|
+
messages.push(
|
|
2018
|
+
`Could not select \u201C${chosen.name}\u201D. It may have been renamed or removed \u2014 pick another.`
|
|
2019
|
+
);
|
|
2020
|
+
continue;
|
|
2021
|
+
}
|
|
2022
|
+
if (phaseBefore === "authenticating") store2.resumeAuth();
|
|
2023
|
+
logger.info({ app: chosen.id }, "selected Algolia application");
|
|
2024
|
+
return chosen;
|
|
1828
2025
|
}
|
|
1829
|
-
|
|
2026
|
+
}
|
|
2027
|
+
async function ensureApplication() {
|
|
2028
|
+
return await currentApplication() ?? await promptForApplication();
|
|
1830
2029
|
}
|
|
1831
2030
|
|
|
1832
2031
|
// src/workflows/default.ts
|
|
1833
|
-
import { z as
|
|
2032
|
+
import { z as z26 } from "zod";
|
|
1834
2033
|
|
|
1835
2034
|
// src/actions/listIndices.ts
|
|
1836
|
-
import { z as
|
|
1837
|
-
var indicesListSchema =
|
|
1838
|
-
items:
|
|
1839
|
-
|
|
1840
|
-
name:
|
|
1841
|
-
entries:
|
|
2035
|
+
import { z as z4 } from "zod";
|
|
2036
|
+
var indicesListSchema = z4.object({
|
|
2037
|
+
items: z4.array(
|
|
2038
|
+
z4.object({
|
|
2039
|
+
name: z4.string(),
|
|
2040
|
+
entries: z4.number().default(0)
|
|
1842
2041
|
})
|
|
1843
2042
|
)
|
|
1844
2043
|
});
|
|
@@ -1909,12 +2108,12 @@ import "zod";
|
|
|
1909
2108
|
|
|
1910
2109
|
// src/lib/tools/listFiles.ts
|
|
1911
2110
|
import { tool } from "ai";
|
|
1912
|
-
import
|
|
2111
|
+
import z5 from "zod";
|
|
1913
2112
|
import { readdir } from "node:fs/promises";
|
|
1914
2113
|
|
|
1915
2114
|
// src/lib/tools/path.ts
|
|
1916
2115
|
import { lstat } from "node:fs/promises";
|
|
1917
|
-
import { resolve as resolve2, relative, isAbsolute, dirname as dirname3, join as
|
|
2116
|
+
import { resolve as resolve2, relative, isAbsolute, dirname as dirname3, join as join6, sep } from "node:path";
|
|
1918
2117
|
function resolveInRoot(ctx, path) {
|
|
1919
2118
|
const target = resolve2(ctx.cwd, path);
|
|
1920
2119
|
const rel = relative(ctx.root, target);
|
|
@@ -1930,7 +2129,7 @@ async function hasSymlinkParent(ctx, target) {
|
|
|
1930
2129
|
let current = ctx.root;
|
|
1931
2130
|
const parts = relative(ctx.root, dirname3(target)).split(sep).filter(Boolean);
|
|
1932
2131
|
for (const part of parts) {
|
|
1933
|
-
current =
|
|
2132
|
+
current = join6(current, part);
|
|
1934
2133
|
try {
|
|
1935
2134
|
if ((await lstat(current)).isSymbolicLink()) return true;
|
|
1936
2135
|
} catch (err) {
|
|
@@ -1945,7 +2144,7 @@ async function hasSymlinkParent(ctx, target) {
|
|
|
1945
2144
|
function listFilesTool(ctx) {
|
|
1946
2145
|
return tool({
|
|
1947
2146
|
description: "List files in the current working directory",
|
|
1948
|
-
inputSchema:
|
|
2147
|
+
inputSchema: z5.object(),
|
|
1949
2148
|
execute: async () => {
|
|
1950
2149
|
logger.info("called listFiles tool");
|
|
1951
2150
|
if (++ctx.counts.list > ctx.limits.list) {
|
|
@@ -1961,13 +2160,13 @@ function listFilesTool(ctx) {
|
|
|
1961
2160
|
|
|
1962
2161
|
// src/lib/tools/changeDirectory.ts
|
|
1963
2162
|
import { tool as tool2 } from "ai";
|
|
1964
|
-
import
|
|
2163
|
+
import z6 from "zod";
|
|
1965
2164
|
import { stat } from "node:fs/promises";
|
|
1966
2165
|
function changeDirectoryTool(ctx) {
|
|
1967
2166
|
return tool2({
|
|
1968
2167
|
description: "Change the current working directory. Subsequent file operations resolve relative to it. Returns the new working directory.",
|
|
1969
|
-
inputSchema:
|
|
1970
|
-
path:
|
|
2168
|
+
inputSchema: z6.object({
|
|
2169
|
+
path: z6.string().describe("Directory to change into")
|
|
1971
2170
|
}),
|
|
1972
2171
|
execute: async ({ path }) => {
|
|
1973
2172
|
logger.info({ path }, "called changeDirectory tool");
|
|
@@ -1989,13 +2188,13 @@ function changeDirectoryTool(ctx) {
|
|
|
1989
2188
|
|
|
1990
2189
|
// src/lib/tools/reportStatus.ts
|
|
1991
2190
|
import { tool as tool3 } from "ai";
|
|
1992
|
-
import
|
|
2191
|
+
import z7 from "zod";
|
|
1993
2192
|
function reportStatusTool(output) {
|
|
1994
2193
|
return tool3({
|
|
1995
2194
|
description: "Report the status of your execution. Return a reason in case of failure.",
|
|
1996
|
-
inputSchema:
|
|
1997
|
-
status:
|
|
1998
|
-
reason:
|
|
2195
|
+
inputSchema: z7.object({
|
|
2196
|
+
status: z7.enum(["success", "fail"]),
|
|
2197
|
+
reason: z7.string().optional(),
|
|
1999
2198
|
output
|
|
2000
2199
|
}),
|
|
2001
2200
|
execute: async ({ status, reason, output: output2 }) => {
|
|
@@ -2007,8 +2206,8 @@ function reportStatusTool(output) {
|
|
|
2007
2206
|
|
|
2008
2207
|
// src/lib/tools/readFile.ts
|
|
2009
2208
|
import { tool as tool4 } from "ai";
|
|
2010
|
-
import
|
|
2011
|
-
import { readFile as
|
|
2209
|
+
import z8 from "zod";
|
|
2210
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
2012
2211
|
|
|
2013
2212
|
// src/lib/tools/env.ts
|
|
2014
2213
|
import { basename } from "node:path";
|
|
@@ -2035,8 +2234,8 @@ function redactEnvValues(content) {
|
|
|
2035
2234
|
function readFileTool(ctx) {
|
|
2036
2235
|
return tool4({
|
|
2037
2236
|
description: "Read the contents of a file at the given path",
|
|
2038
|
-
inputSchema:
|
|
2039
|
-
filePath:
|
|
2237
|
+
inputSchema: z8.object({
|
|
2238
|
+
filePath: z8.string().describe("Path to the file to read")
|
|
2040
2239
|
}),
|
|
2041
2240
|
execute: async ({ filePath }) => {
|
|
2042
2241
|
if (++ctx.counts.read > ctx.limits.read) {
|
|
@@ -2046,7 +2245,7 @@ function readFileTool(ctx) {
|
|
|
2046
2245
|
const resolved = resolveInRoot(ctx, filePath);
|
|
2047
2246
|
if (!resolved.ok) return resolved.error;
|
|
2048
2247
|
try {
|
|
2049
|
-
const content = await
|
|
2248
|
+
const content = await readFile3(resolved.target, "utf8");
|
|
2050
2249
|
return isEnvFile(resolved.target) ? redactEnvValues(content) : content;
|
|
2051
2250
|
} catch (err) {
|
|
2052
2251
|
return `Error reading ${filePath}: ${err.message}`;
|
|
@@ -2057,15 +2256,15 @@ function readFileTool(ctx) {
|
|
|
2057
2256
|
|
|
2058
2257
|
// src/lib/tools/writeFile.ts
|
|
2059
2258
|
import { tool as tool5 } from "ai";
|
|
2060
|
-
import
|
|
2259
|
+
import z9 from "zod";
|
|
2061
2260
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
|
|
2062
2261
|
import { dirname as dirname4 } from "node:path";
|
|
2063
2262
|
function writeFileTool(ctx) {
|
|
2064
2263
|
return tool5({
|
|
2065
2264
|
description: "Write content to a file at the given path, overwriting it. To set Algolia credentials in an env file, use writeCredentials instead of this tool.",
|
|
2066
|
-
inputSchema:
|
|
2067
|
-
filePath:
|
|
2068
|
-
content:
|
|
2265
|
+
inputSchema: z9.object({
|
|
2266
|
+
filePath: z9.string().describe("Path to the file to write"),
|
|
2267
|
+
content: z9.string().describe("Content to write to the file")
|
|
2069
2268
|
}),
|
|
2070
2269
|
execute: async ({ filePath, content }) => {
|
|
2071
2270
|
logger.info({ filePath }, "called writeFile tool");
|
|
@@ -2090,9 +2289,95 @@ function writeFileTool(ctx) {
|
|
|
2090
2289
|
|
|
2091
2290
|
// src/lib/tools/writeAlgoliaCredentials.ts
|
|
2092
2291
|
import { tool as tool6 } from "ai";
|
|
2093
|
-
import
|
|
2094
|
-
import { mkdir as mkdir4, readFile as
|
|
2292
|
+
import z11 from "zod";
|
|
2293
|
+
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "node:fs/promises";
|
|
2095
2294
|
import { dirname as dirname5 } from "node:path";
|
|
2295
|
+
|
|
2296
|
+
// src/lib/algoliaApiKey.ts
|
|
2297
|
+
import { z as z10 } from "zod";
|
|
2298
|
+
var SAFE_ACLS = /* @__PURE__ */ new Set(["search", "browse", "listIndexes"]);
|
|
2299
|
+
var WRITE_ACLS = [
|
|
2300
|
+
"addObject",
|
|
2301
|
+
"deleteObject",
|
|
2302
|
+
"settings",
|
|
2303
|
+
"editSettings",
|
|
2304
|
+
"listIndexes"
|
|
2305
|
+
];
|
|
2306
|
+
var WRITE_ACL_SET = new Set(WRITE_ACLS);
|
|
2307
|
+
var apiKeySchema = z10.object({
|
|
2308
|
+
value: z10.string().min(1),
|
|
2309
|
+
acl: z10.array(z10.string()).default([]),
|
|
2310
|
+
indexes: z10.array(z10.string()).default([])
|
|
2311
|
+
});
|
|
2312
|
+
var apiKeyListSchema = z10.object({
|
|
2313
|
+
items: z10.array(apiKeySchema).optional(),
|
|
2314
|
+
keys: z10.array(apiKeySchema).optional()
|
|
2315
|
+
}).transform((o) => o.items ?? o.keys ?? []);
|
|
2316
|
+
var createdKeySchema = z10.object({
|
|
2317
|
+
key: z10.string().min(1).optional(),
|
|
2318
|
+
value: z10.string().min(1).optional()
|
|
2319
|
+
});
|
|
2320
|
+
function canReuse(key, index) {
|
|
2321
|
+
return key.acl.includes("search") && key.acl.every((acl) => SAFE_ACLS.has(acl)) && (key.indexes.length === 0 || key.indexes.includes("*") || key.indexes.includes(index));
|
|
2322
|
+
}
|
|
2323
|
+
async function createSearchKey(index) {
|
|
2324
|
+
const stdout = await runAlgoliaCli([
|
|
2325
|
+
"apikeys",
|
|
2326
|
+
"create",
|
|
2327
|
+
"--indices",
|
|
2328
|
+
index,
|
|
2329
|
+
"--acl",
|
|
2330
|
+
"search,browse",
|
|
2331
|
+
"--description",
|
|
2332
|
+
`wizard search-only key for ${index}`,
|
|
2333
|
+
"-o",
|
|
2334
|
+
"json"
|
|
2335
|
+
]);
|
|
2336
|
+
const { key, value } = createdKeySchema.parse(JSON.parse(stdout));
|
|
2337
|
+
const created = key ?? value;
|
|
2338
|
+
if (!created) throw new Error("apikeys create returned no key value");
|
|
2339
|
+
return created;
|
|
2340
|
+
}
|
|
2341
|
+
function canReuseForWrites(key, index) {
|
|
2342
|
+
return WRITE_ACLS.every((acl) => key.acl.includes(acl)) && key.acl.every((acl) => WRITE_ACL_SET.has(acl)) && key.indexes.includes(index);
|
|
2343
|
+
}
|
|
2344
|
+
async function resolveWriteKey(index) {
|
|
2345
|
+
const stdout = await runAlgoliaCli(["apikeys", "list", "-o", "json"]);
|
|
2346
|
+
const existing = apiKeyListSchema.parse(JSON.parse(stdout)).find((key2) => canReuseForWrites(key2, index))?.value;
|
|
2347
|
+
if (existing) {
|
|
2348
|
+
logger.info({ index }, "reusing existing write API key");
|
|
2349
|
+
return existing;
|
|
2350
|
+
}
|
|
2351
|
+
logger.info({ index }, "no reusable write key found; creating one");
|
|
2352
|
+
const created = await runAlgoliaCli([
|
|
2353
|
+
"apikeys",
|
|
2354
|
+
"create",
|
|
2355
|
+
"--indices",
|
|
2356
|
+
index,
|
|
2357
|
+
"--acl",
|
|
2358
|
+
WRITE_ACLS.join(","),
|
|
2359
|
+
"--description",
|
|
2360
|
+
`wizard write key for ${index}`,
|
|
2361
|
+
"-o",
|
|
2362
|
+
"json"
|
|
2363
|
+
]);
|
|
2364
|
+
const { key, value } = createdKeySchema.parse(JSON.parse(created));
|
|
2365
|
+
const writeKey = key ?? value;
|
|
2366
|
+
if (!writeKey) throw new Error("apikeys create returned no key value");
|
|
2367
|
+
return writeKey;
|
|
2368
|
+
}
|
|
2369
|
+
async function resolveSearchOnlyKey(index) {
|
|
2370
|
+
const stdout = await runAlgoliaCli(["apikeys", "list", "-o", "json"]);
|
|
2371
|
+
const existing = apiKeyListSchema.parse(JSON.parse(stdout)).find((key) => canReuse(key, index))?.value;
|
|
2372
|
+
if (existing) {
|
|
2373
|
+
logger.info({ index }, "reusing existing search-only API key");
|
|
2374
|
+
return existing;
|
|
2375
|
+
}
|
|
2376
|
+
logger.info({ index }, "no reusable search-only key found; creating one");
|
|
2377
|
+
return createSearchKey(index);
|
|
2378
|
+
}
|
|
2379
|
+
|
|
2380
|
+
// src/lib/tools/writeAlgoliaCredentials.ts
|
|
2096
2381
|
var APP_ID_VAR = "ALGOLIA_APPLICATION_ID";
|
|
2097
2382
|
var API_KEY_VAR = "ALGOLIA_WRITE_API_KEY";
|
|
2098
2383
|
function appendEnv(content, entries) {
|
|
@@ -2106,9 +2391,9 @@ function hasEnv(content, name) {
|
|
|
2106
2391
|
}
|
|
2107
2392
|
function writeCredentialsTool(ctx) {
|
|
2108
2393
|
return tool6({
|
|
2109
|
-
description: `Write the active Algolia credentials (${APP_ID_VAR} and ${API_KEY_VAR}) into the given env file. The credentials
|
|
2110
|
-
inputSchema:
|
|
2111
|
-
filePath:
|
|
2394
|
+
description: `Write the active Algolia credentials (${APP_ID_VAR} and ${API_KEY_VAR}) into the given env file. The credentials come from the selected Algolia application, with a write key scoped to the target index; you only pass the path to the env file (e.g. ".env"). If the file already defines ${APP_ID_VAR} or ${API_KEY_VAR}, the write is skipped and existing values are left untouched.`,
|
|
2395
|
+
inputSchema: z11.object({
|
|
2396
|
+
filePath: z11.string().describe(
|
|
2112
2397
|
'Path to the env file to write credentials into (e.g. ".env")'
|
|
2113
2398
|
)
|
|
2114
2399
|
}),
|
|
@@ -2116,11 +2401,17 @@ function writeCredentialsTool(ctx) {
|
|
|
2116
2401
|
logger.info({ filePath }, "called writeCredentials tool");
|
|
2117
2402
|
const resolved = resolveInRoot(ctx, filePath);
|
|
2118
2403
|
if (resolved.ok === false) return resolved.error;
|
|
2119
|
-
|
|
2404
|
+
const targetIndex = useWizard.getState().targetIndex;
|
|
2405
|
+
if (!targetIndex) {
|
|
2406
|
+
return "Error: no target index is set for this run, so a scoped write key cannot be provisioned.";
|
|
2407
|
+
}
|
|
2408
|
+
let appId;
|
|
2409
|
+
let writeKey;
|
|
2120
2410
|
try {
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2411
|
+
appId = (await requireApplication()).id;
|
|
2412
|
+
writeKey = await resolveWriteKey(targetIndex);
|
|
2413
|
+
} catch (err) {
|
|
2414
|
+
return `Error: could not resolve Algolia credentials (${err.message}). Ask the user to authenticate with the Algolia CLI first.`;
|
|
2124
2415
|
}
|
|
2125
2416
|
try {
|
|
2126
2417
|
if (await hasSymlinkParent(ctx, resolved.target)) {
|
|
@@ -2128,7 +2419,7 @@ function writeCredentialsTool(ctx) {
|
|
|
2128
2419
|
}
|
|
2129
2420
|
let existing = "";
|
|
2130
2421
|
try {
|
|
2131
|
-
existing = await
|
|
2422
|
+
existing = await readFile4(resolved.target, "utf8");
|
|
2132
2423
|
} catch (err) {
|
|
2133
2424
|
if (err.code !== "ENOENT") throw err;
|
|
2134
2425
|
}
|
|
@@ -2139,8 +2430,8 @@ function writeCredentialsTool(ctx) {
|
|
|
2139
2430
|
return `Skipped: ${filePath} already defines ${present.join(" and ")}. Leaving existing credentials untouched.`;
|
|
2140
2431
|
}
|
|
2141
2432
|
const envWithCredentials = appendEnv(existing, [
|
|
2142
|
-
[APP_ID_VAR,
|
|
2143
|
-
[API_KEY_VAR,
|
|
2433
|
+
[APP_ID_VAR, appId],
|
|
2434
|
+
[API_KEY_VAR, writeKey]
|
|
2144
2435
|
]);
|
|
2145
2436
|
await mkdir4(dirname5(resolved.target), { recursive: true });
|
|
2146
2437
|
await writeFile4(resolved.target, envWithCredentials, "utf8");
|
|
@@ -2154,19 +2445,19 @@ function writeCredentialsTool(ctx) {
|
|
|
2154
2445
|
|
|
2155
2446
|
// src/lib/tools/searchFiles.ts
|
|
2156
2447
|
import { tool as tool7 } from "ai";
|
|
2157
|
-
import
|
|
2158
|
-
import { readdir as readdir3, readFile as
|
|
2159
|
-
import { join as
|
|
2448
|
+
import z12 from "zod";
|
|
2449
|
+
import { readdir as readdir3, readFile as readFile6 } from "node:fs/promises";
|
|
2450
|
+
import { join as join9 } from "node:path";
|
|
2160
2451
|
|
|
2161
2452
|
// src/lib/languages.ts
|
|
2162
2453
|
import { readdir as readdir2 } from "node:fs/promises";
|
|
2163
2454
|
import { existsSync as existsSync2 } from "node:fs";
|
|
2164
|
-
import { join as
|
|
2455
|
+
import { join as join8 } from "node:path";
|
|
2165
2456
|
|
|
2166
2457
|
// src/lib/tools/utils/packageManager.ts
|
|
2167
|
-
import { readFile as
|
|
2458
|
+
import { readFile as readFile5 } from "node:fs/promises";
|
|
2168
2459
|
import { existsSync } from "node:fs";
|
|
2169
|
-
import { join as
|
|
2460
|
+
import { join as join7 } from "node:path";
|
|
2170
2461
|
var LOCKFILES = [
|
|
2171
2462
|
["pnpm-lock.yaml", "pnpm"],
|
|
2172
2463
|
["yarn.lock", "yarn"],
|
|
@@ -2175,13 +2466,13 @@ var LOCKFILES = [
|
|
|
2175
2466
|
["package-lock.json", "npm"]
|
|
2176
2467
|
];
|
|
2177
2468
|
async function readPackageJson(cwd = process.cwd()) {
|
|
2178
|
-
return JSON.parse(await
|
|
2469
|
+
return JSON.parse(await readFile5(join7(cwd, "package.json"), "utf8"));
|
|
2179
2470
|
}
|
|
2180
2471
|
function packageManagerFrom(pkg) {
|
|
2181
2472
|
return pkg.packageManager?.split("@")[0] ?? "npm";
|
|
2182
2473
|
}
|
|
2183
2474
|
function packageManagerFromLockfile(cwd) {
|
|
2184
|
-
return LOCKFILES.find(([file]) => existsSync(
|
|
2475
|
+
return LOCKFILES.find(([file]) => existsSync(join7(cwd, file)))?.[1];
|
|
2185
2476
|
}
|
|
2186
2477
|
async function detectPackageManager(cwd) {
|
|
2187
2478
|
try {
|
|
@@ -2703,17 +2994,17 @@ var DEFAULT_LANGUAGE_ID = "javascript";
|
|
|
2703
2994
|
var JAVASCRIPT = "javascript";
|
|
2704
2995
|
var CURATED_LANGUAGES = Object.values(
|
|
2705
2996
|
LANGUAGE_PROFILES
|
|
2706
|
-
).map((
|
|
2707
|
-
function isBackendLanguage(
|
|
2708
|
-
return
|
|
2997
|
+
).map((profile) => profile.displayName);
|
|
2998
|
+
function isBackendLanguage(profile) {
|
|
2999
|
+
return profile.id !== JAVASCRIPT;
|
|
2709
3000
|
}
|
|
2710
3001
|
function normalizeLanguageName(name) {
|
|
2711
3002
|
return name.toLowerCase().trim().replace(/[\s_-]+/g, "");
|
|
2712
3003
|
}
|
|
2713
3004
|
var ALIAS_TO_ID = /* @__PURE__ */ new Map();
|
|
2714
|
-
for (const
|
|
2715
|
-
for (const alias of [
|
|
2716
|
-
ALIAS_TO_ID.set(normalizeLanguageName(alias),
|
|
3005
|
+
for (const profile of Object.values(LANGUAGE_PROFILES)) {
|
|
3006
|
+
for (const alias of [profile.id, profile.displayName, ...profile.aliases]) {
|
|
3007
|
+
ALIAS_TO_ID.set(normalizeLanguageName(alias), profile.id);
|
|
2717
3008
|
}
|
|
2718
3009
|
}
|
|
2719
3010
|
function resolveLanguageProfile(name) {
|
|
@@ -2734,12 +3025,12 @@ var ALL_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
2734
3025
|
...Object.values(LANGUAGE_PROFILES).flatMap((p) => p.skipDirs)
|
|
2735
3026
|
]);
|
|
2736
3027
|
var ALLOWED_BINARIES = new Set(
|
|
2737
|
-
Object.values(LANGUAGE_PROFILES).flatMap((
|
|
2738
|
-
...
|
|
3028
|
+
Object.values(LANGUAGE_PROFILES).flatMap((profile) => [
|
|
3029
|
+
...profile.packageManagers.flatMap((pm) => [
|
|
2739
3030
|
...pm.installSteps.map((s) => s.argv[0]),
|
|
2740
3031
|
...pm.ingest.kind === "auto" ? [pm.ingest.argv[0]] : []
|
|
2741
3032
|
]),
|
|
2742
|
-
...
|
|
3033
|
+
...profile.verification.map((v) => v.argv[0])
|
|
2743
3034
|
])
|
|
2744
3035
|
);
|
|
2745
3036
|
var JS_PACKAGE_MANAGERS = /* @__PURE__ */ new Set(["npm", "pnpm", "yarn", "bun"]);
|
|
@@ -2755,13 +3046,13 @@ function resolveDeclaredManifest(root, packageManager) {
|
|
|
2755
3046
|
return packageManager;
|
|
2756
3047
|
}
|
|
2757
3048
|
const present = [dependency.file, ...dependency.alternatives].find(
|
|
2758
|
-
(file) => existsSync2(
|
|
3049
|
+
(file) => existsSync2(join8(root, file))
|
|
2759
3050
|
);
|
|
2760
3051
|
if (!present || present === dependency.file) return packageManager;
|
|
2761
3052
|
return { ...packageManager, dependency: { ...dependency, file: present } };
|
|
2762
3053
|
}
|
|
2763
3054
|
async function manifestPresent(root, manifest, listing) {
|
|
2764
|
-
if (!manifest.startsWith("*.")) return existsSync2(
|
|
3055
|
+
if (!manifest.startsWith("*.")) return existsSync2(join8(root, manifest));
|
|
2765
3056
|
if (!listing.entries) {
|
|
2766
3057
|
const entries = await readdir2(root).catch(() => []);
|
|
2767
3058
|
listing.entries = Array.isArray(entries) ? entries : [];
|
|
@@ -2769,8 +3060,8 @@ async function manifestPresent(root, manifest, listing) {
|
|
|
2769
3060
|
const suffix = manifest.slice(1);
|
|
2770
3061
|
return listing.entries.some((e) => e.endsWith(suffix));
|
|
2771
3062
|
}
|
|
2772
|
-
async function profileManifestPresent(root,
|
|
2773
|
-
for (const manifest of
|
|
3063
|
+
async function profileManifestPresent(root, profile, listing) {
|
|
3064
|
+
for (const manifest of profile.manifests) {
|
|
2774
3065
|
if (await manifestPresent(root, manifest, listing)) return true;
|
|
2775
3066
|
}
|
|
2776
3067
|
return false;
|
|
@@ -2778,13 +3069,13 @@ async function profileManifestPresent(root, profile2, listing) {
|
|
|
2778
3069
|
async function detectProfilesFromManifests(root) {
|
|
2779
3070
|
const listing = {};
|
|
2780
3071
|
const found = [];
|
|
2781
|
-
for (const
|
|
2782
|
-
if (await profileManifestPresent(root,
|
|
3072
|
+
for (const profile of Object.values(LANGUAGE_PROFILES)) {
|
|
3073
|
+
if (await profileManifestPresent(root, profile, listing)) found.push(profile);
|
|
2783
3074
|
}
|
|
2784
3075
|
return found;
|
|
2785
3076
|
}
|
|
2786
|
-
async function hasProfileManifest(root,
|
|
2787
|
-
return profileManifestPresent(root,
|
|
3077
|
+
async function hasProfileManifest(root, profile) {
|
|
3078
|
+
return profileManifestPresent(root, profile, {});
|
|
2788
3079
|
}
|
|
2789
3080
|
async function pickIngestionCandidates(root, confirmedNames) {
|
|
2790
3081
|
const confirmed3 = confirmedNames.map((name) => resolveLanguageProfile(name)).filter((p) => p !== void 0);
|
|
@@ -2797,27 +3088,27 @@ async function pickIngestionCandidates(root, confirmedNames) {
|
|
|
2797
3088
|
];
|
|
2798
3089
|
return { candidates, confirmed: confirmed3, onDisk };
|
|
2799
3090
|
}
|
|
2800
|
-
async function resolveToolchain(root,
|
|
2801
|
-
const matched =
|
|
3091
|
+
async function resolveToolchain(root, profile) {
|
|
3092
|
+
const matched = profile.packageManagers.find(
|
|
2802
3093
|
(pm) => [...pm.lockfiles ?? [], ...pm.detectFiles ?? []].some(
|
|
2803
|
-
(f) => existsSync2(
|
|
3094
|
+
(f) => existsSync2(join8(root, f))
|
|
2804
3095
|
)
|
|
2805
3096
|
);
|
|
2806
3097
|
const packageManager = resolveDeclaredManifest(
|
|
2807
3098
|
root,
|
|
2808
|
-
matched ??
|
|
3099
|
+
matched ?? profile.packageManagers[0]
|
|
2809
3100
|
);
|
|
2810
3101
|
let { installSteps, ingest } = packageManager;
|
|
2811
3102
|
installSteps = installSteps.map(
|
|
2812
|
-
(step) => isWorktreeRelativeCommand(step.argv[0]) ? { ...step, argv: withCommand(step.argv,
|
|
3103
|
+
(step) => isWorktreeRelativeCommand(step.argv[0]) ? { ...step, argv: withCommand(step.argv, join8(root, step.argv[0])) } : step
|
|
2813
3104
|
);
|
|
2814
3105
|
if (ingest.kind === "auto" && isWorktreeRelativeCommand(ingest.argv[0])) {
|
|
2815
3106
|
ingest = {
|
|
2816
3107
|
...ingest,
|
|
2817
|
-
argv: withCommand(ingest.argv,
|
|
3108
|
+
argv: withCommand(ingest.argv, join8(root, ingest.argv[0]))
|
|
2818
3109
|
};
|
|
2819
3110
|
}
|
|
2820
|
-
if (
|
|
3111
|
+
if (profile.id === "javascript") {
|
|
2821
3112
|
const pm = await detectPackageManager(root);
|
|
2822
3113
|
if (JS_PACKAGE_MANAGERS.has(pm)) {
|
|
2823
3114
|
installSteps = installSteps.map((step) => ({
|
|
@@ -2829,7 +3120,7 @@ async function resolveToolchain(root, profile2) {
|
|
|
2829
3120
|
}
|
|
2830
3121
|
}
|
|
2831
3122
|
}
|
|
2832
|
-
return { profile
|
|
3123
|
+
return { profile, packageManager, installSteps, ingest };
|
|
2833
3124
|
}
|
|
2834
3125
|
function resolveIngestArgv(ingest, entrypoint) {
|
|
2835
3126
|
if (ingest.kind !== "auto") {
|
|
@@ -2843,14 +3134,14 @@ function describeIngestCommand(ingest, entrypoint) {
|
|
|
2843
3134
|
if (ingest.kind !== "auto") return ingest.runCommand;
|
|
2844
3135
|
return ingest.argv.map((part) => part === ENTRYPOINT_TOKEN ? shellQuote(entrypoint) : part).join(" ");
|
|
2845
3136
|
}
|
|
2846
|
-
function ingestScriptDir(
|
|
2847
|
-
const parts =
|
|
3137
|
+
function ingestScriptDir(profile) {
|
|
3138
|
+
const parts = profile.ingestEntrypointExample.split("/");
|
|
2848
3139
|
return parts.slice(0, -1).join("/") || ".";
|
|
2849
3140
|
}
|
|
2850
3141
|
function dependencyInstruction(toolchain) {
|
|
2851
|
-
const { profile
|
|
2852
|
-
const { packageName, versionPin } =
|
|
2853
|
-
const also =
|
|
3142
|
+
const { profile, packageManager } = toolchain;
|
|
3143
|
+
const { packageName, versionPin } = profile.sdk;
|
|
3144
|
+
const also = profile.sdk.alsoRequires ? ` ${profile.sdk.alsoRequires}` : "";
|
|
2854
3145
|
switch (packageManager.dependency.mode) {
|
|
2855
3146
|
case "wizard-installs":
|
|
2856
3147
|
return `The wizard installs ${packageName} ${versionPin} in the worktree after you finish \u2014 import it directly and do not edit dependency manifests for it.${also}`;
|
|
@@ -2867,7 +3158,7 @@ async function walkFiles(dir) {
|
|
|
2867
3158
|
const out = [];
|
|
2868
3159
|
for (const e of await readdir3(dir, { withFileTypes: true })) {
|
|
2869
3160
|
if (e.name.startsWith(".") || ALL_SKIP_DIRS.has(e.name)) continue;
|
|
2870
|
-
const full =
|
|
3161
|
+
const full = join9(dir, e.name);
|
|
2871
3162
|
if (e.isDirectory()) out.push(...await walkFiles(full));
|
|
2872
3163
|
else if (e.isFile()) out.push(full);
|
|
2873
3164
|
}
|
|
@@ -2876,9 +3167,9 @@ async function walkFiles(dir) {
|
|
|
2876
3167
|
function searchFilesTool(ctx) {
|
|
2877
3168
|
return tool7({
|
|
2878
3169
|
description: "Search file contents for a JavaScript regular expression (RegExp syntax, not grep/PCRE). Returns matching lines as file:line:text.",
|
|
2879
|
-
inputSchema:
|
|
2880
|
-
query:
|
|
2881
|
-
path:
|
|
3170
|
+
inputSchema: z12.object({
|
|
3171
|
+
query: z12.string().describe("JavaScript RegExp pattern to search for"),
|
|
3172
|
+
path: z12.string().optional().describe("Directory to search in (default: cwd)")
|
|
2882
3173
|
}),
|
|
2883
3174
|
execute: async ({ query, path = "." }) => {
|
|
2884
3175
|
logger.info({ query, path }, "called searchFiles tool");
|
|
@@ -2900,7 +3191,7 @@ function searchFilesTool(ctx) {
|
|
|
2900
3191
|
for (const file of await walkFiles(resolved.target)) {
|
|
2901
3192
|
let content;
|
|
2902
3193
|
try {
|
|
2903
|
-
content = await
|
|
3194
|
+
content = await readFile6(file, "utf8");
|
|
2904
3195
|
} catch {
|
|
2905
3196
|
continue;
|
|
2906
3197
|
}
|
|
@@ -2922,11 +3213,11 @@ function searchFilesTool(ctx) {
|
|
|
2922
3213
|
|
|
2923
3214
|
// src/lib/tools/verifyImplementation.ts
|
|
2924
3215
|
import { tool as tool8 } from "ai";
|
|
2925
|
-
import
|
|
3216
|
+
import z13 from "zod";
|
|
2926
3217
|
|
|
2927
3218
|
// src/lib/tools/repoVerification.ts
|
|
2928
3219
|
import { existsSync as existsSync3 } from "node:fs";
|
|
2929
|
-
import { join as
|
|
3220
|
+
import { join as join10 } from "node:path";
|
|
2930
3221
|
|
|
2931
3222
|
// src/lib/tools/utils/runCommand.ts
|
|
2932
3223
|
import { spawn as spawn2 } from "node:child_process";
|
|
@@ -3024,13 +3315,13 @@ async function runRepoVerificationCheck(languages = [DEFAULT_LANGUAGE_ID]) {
|
|
|
3024
3315
|
else limitations.push(result.limitation);
|
|
3025
3316
|
continue;
|
|
3026
3317
|
}
|
|
3027
|
-
const
|
|
3028
|
-
const runnable =
|
|
3029
|
-
(spec) => !spec.requiresFile || existsSync3(
|
|
3318
|
+
const profile = LANGUAGE_PROFILES[id];
|
|
3319
|
+
const runnable = profile.verification.filter(
|
|
3320
|
+
(spec) => !spec.requiresFile || existsSync3(join10(process.cwd(), spec.requiresFile))
|
|
3030
3321
|
);
|
|
3031
3322
|
if (runnable.length === 0) {
|
|
3032
3323
|
limitations.push(
|
|
3033
|
-
`No mechanical verification available for ${
|
|
3324
|
+
`No mechanical verification available for ${profile.displayName} in this repo.`
|
|
3034
3325
|
);
|
|
3035
3326
|
continue;
|
|
3036
3327
|
}
|
|
@@ -3060,7 +3351,7 @@ async function runRepoVerificationCheck(languages = [DEFAULT_LANGUAGE_ID]) {
|
|
|
3060
3351
|
function verifyImplementationTool(ctx) {
|
|
3061
3352
|
return tool8({
|
|
3062
3353
|
description: "Run the repo's mechanical verification checks for generated implementation changes. Uses the conventions of the repo's languages (package.json lint/typecheck/check scripts for JavaScript, the equivalent compile/analyze command elsewhere) and returns structured pass/fail evidence for the verifier to interpret.",
|
|
3063
|
-
inputSchema:
|
|
3354
|
+
inputSchema: z13.object(),
|
|
3064
3355
|
execute: async () => {
|
|
3065
3356
|
logger.info({ languages: ctx.languages }, "called verifyImplementation tool");
|
|
3066
3357
|
return runRepoVerificationCheck(ctx.languages);
|
|
@@ -3074,7 +3365,7 @@ import { createAnthropic } from "@ai-sdk/anthropic";
|
|
|
3074
3365
|
import { nanoid as nanoid2 } from "nanoid";
|
|
3075
3366
|
import { mkdir as mkdir5, writeFile as writeFile5 } from "node:fs/promises";
|
|
3076
3367
|
import { dirname as dirname6 } from "node:path";
|
|
3077
|
-
import
|
|
3368
|
+
import z14 from "zod";
|
|
3078
3369
|
var DATA_DIR = ".algolia-wizard/data";
|
|
3079
3370
|
var RECORD_MODEL = "claude-haiku-4-5";
|
|
3080
3371
|
var MAX_RECORDS = 100;
|
|
@@ -3086,17 +3377,17 @@ var anthropic = createAnthropic({
|
|
|
3086
3377
|
function generateRecordTool(ctx) {
|
|
3087
3378
|
return tool9({
|
|
3088
3379
|
description: "Generate realistic sample records for an entity and write them to a JSON file in the worktree. Provide the entity name and its attributes; this tool asks a model to invent varied, realistic values, each with a unique objectID, and returns the file path to read them from at runtime. Do not invent the record values or objectIDs yourself, and do not inline the returned records into the script \u2014 call this tool and read the file it writes.",
|
|
3089
|
-
inputSchema:
|
|
3090
|
-
entityName:
|
|
3091
|
-
attributes:
|
|
3092
|
-
count:
|
|
3093
|
-
hint:
|
|
3380
|
+
inputSchema: z14.object({
|
|
3381
|
+
entityName: z14.string().describe("Name of the entity to generate records for."),
|
|
3382
|
+
attributes: z14.array(z14.string()).describe("Attribute names each record must contain."),
|
|
3383
|
+
count: z14.number().int().min(1).max(MAX_RECORDS).default(10).describe(`How many records to generate (max ${MAX_RECORDS}).`),
|
|
3384
|
+
hint: z14.string().optional().describe("Optional context to steer realistic values.")
|
|
3094
3385
|
}),
|
|
3095
3386
|
execute: async ({ entityName, attributes, count, hint }) => {
|
|
3096
3387
|
logger.info({ entityName, count }, "called generateRecord tool");
|
|
3097
3388
|
try {
|
|
3098
|
-
const value =
|
|
3099
|
-
const recordSchema =
|
|
3389
|
+
const value = z14.union([z14.string(), z14.number(), z14.boolean(), z14.null()]);
|
|
3390
|
+
const recordSchema = z14.object(
|
|
3100
3391
|
Object.fromEntries(attributes.map((attr) => [attr, value]))
|
|
3101
3392
|
);
|
|
3102
3393
|
const generateBatch = async (batchCount) => {
|
|
@@ -3106,8 +3397,8 @@ function generateRecordTool(ctx) {
|
|
|
3106
3397
|
const { output } = await generateText({
|
|
3107
3398
|
model: anthropic(RECORD_MODEL),
|
|
3108
3399
|
output: Output.object({
|
|
3109
|
-
schema:
|
|
3110
|
-
records:
|
|
3400
|
+
schema: z14.object({
|
|
3401
|
+
records: z14.array(recordSchema).length(batchCount)
|
|
3111
3402
|
})
|
|
3112
3403
|
}),
|
|
3113
3404
|
prompt: [
|
|
@@ -3165,12 +3456,12 @@ function generateRecordTool(ctx) {
|
|
|
3165
3456
|
|
|
3166
3457
|
// src/lib/tools/notifyUser.ts
|
|
3167
3458
|
import { tool as tool10 } from "ai";
|
|
3168
|
-
import
|
|
3459
|
+
import z15 from "zod";
|
|
3169
3460
|
function notifyUserTool() {
|
|
3170
3461
|
return tool10({
|
|
3171
3462
|
description: `Give the user a brief, high-level update on what you are currently doing or about to do next. This is for the big picture (e.g. "Reading through your data models", "Writing the search UI") \u2014 not granular detail like individual tool calls, which are already logged separately. Call it when you start a new phase of work or your focus shifts, just not on every step, enough to keep the user engaged. Don't say things like "starting", just describe what you are doing. Don't mention tool calls themselves, just general direction of the work.`,
|
|
3172
|
-
inputSchema:
|
|
3173
|
-
message:
|
|
3463
|
+
inputSchema: z15.object({
|
|
3464
|
+
message: z15.string().describe(
|
|
3174
3465
|
"Short, plain-language description of what you are doing now."
|
|
3175
3466
|
)
|
|
3176
3467
|
}),
|
|
@@ -3355,10 +3646,10 @@ async function runAgent(req) {
|
|
|
3355
3646
|
}
|
|
3356
3647
|
|
|
3357
3648
|
// src/actions/detectLanguage.ts
|
|
3358
|
-
import
|
|
3359
|
-
var detectLanguageSchema =
|
|
3360
|
-
languages:
|
|
3361
|
-
frameworks:
|
|
3649
|
+
import z18 from "zod";
|
|
3650
|
+
var detectLanguageSchema = z18.object({
|
|
3651
|
+
languages: z18.array(z18.object({ name: z18.string(), version: z18.string() })),
|
|
3652
|
+
frameworks: z18.array(z18.object({ name: z18.string(), version: z18.string() }))
|
|
3362
3653
|
});
|
|
3363
3654
|
var detectLanguage = () => runAgent({
|
|
3364
3655
|
instructions: [
|
|
@@ -3379,31 +3670,31 @@ var detectLanguage = () => runAgent({
|
|
|
3379
3670
|
});
|
|
3380
3671
|
|
|
3381
3672
|
// src/actions/analyzeCodebase.ts
|
|
3382
|
-
import
|
|
3673
|
+
import z19 from "zod";
|
|
3383
3674
|
var READONLY_TOOLS = [
|
|
3384
3675
|
"listFiles",
|
|
3385
3676
|
"changeDirectory",
|
|
3386
3677
|
"readFile",
|
|
3387
3678
|
"searchFiles"
|
|
3388
3679
|
];
|
|
3389
|
-
var ingestionAnalysisSchema =
|
|
3390
|
-
ingestionAnalysis:
|
|
3391
|
-
|
|
3392
|
-
name:
|
|
3393
|
-
paths:
|
|
3680
|
+
var ingestionAnalysisSchema = z19.object({
|
|
3681
|
+
ingestionAnalysis: z19.array(
|
|
3682
|
+
z19.object({
|
|
3683
|
+
name: z19.string(),
|
|
3684
|
+
paths: z19.array(z19.string()),
|
|
3394
3685
|
// indexable fields the agent found for this entity
|
|
3395
|
-
attributes:
|
|
3686
|
+
attributes: z19.array(z19.string())
|
|
3396
3687
|
})
|
|
3397
3688
|
)
|
|
3398
3689
|
});
|
|
3399
|
-
var searchImplementationAnalysisSchema =
|
|
3400
|
-
searchImplementationAnalysis:
|
|
3690
|
+
var searchImplementationAnalysisSchema = z19.object({
|
|
3691
|
+
searchImplementationAnalysis: z19.string()
|
|
3401
3692
|
});
|
|
3402
|
-
var verificationSchema =
|
|
3403
|
-
verification:
|
|
3693
|
+
var verificationSchema = z19.object({
|
|
3694
|
+
verification: z19.array(z19.string())
|
|
3404
3695
|
});
|
|
3405
3696
|
var confirmedEntitiesFieldSchema = ingestionAnalysisSchema.shape.ingestionAnalysis.optional();
|
|
3406
|
-
var analyzeCodebaseSchema =
|
|
3697
|
+
var analyzeCodebaseSchema = z19.object({
|
|
3407
3698
|
ingestionAnalysis: ingestionAnalysisSchema.shape.ingestionAnalysis.optional(),
|
|
3408
3699
|
searchImplementationAnalysis: searchImplementationAnalysisSchema.shape.searchImplementationAnalysis.optional(),
|
|
3409
3700
|
verification: verificationSchema.shape.verification.optional(),
|
|
@@ -3467,7 +3758,7 @@ async function runAnalysis(mode, extraInstructions = []) {
|
|
|
3467
3758
|
// package.json
|
|
3468
3759
|
var package_default = {
|
|
3469
3760
|
name: "@algolia/wizard",
|
|
3470
|
-
version: "0.6.0-rc.
|
|
3761
|
+
version: "0.6.0-rc.53.27",
|
|
3471
3762
|
description: "Magically implement Algolia functionality in your codebase",
|
|
3472
3763
|
type: "module",
|
|
3473
3764
|
engines: {
|
|
@@ -3515,7 +3806,6 @@ var package_default = {
|
|
|
3515
3806
|
dependencies: {
|
|
3516
3807
|
"@ai-sdk/anthropic": "^3.0.81",
|
|
3517
3808
|
"@ai-sdk/openai-compatible": "^2.0.47",
|
|
3518
|
-
"@algolia/cli": "^5.11.0",
|
|
3519
3809
|
"@hono/node-server": "^2.0.10",
|
|
3520
3810
|
"@mishieck/ink-titled-box": "^0.4.2",
|
|
3521
3811
|
"@segment/analytics-node": "^3.1.0",
|
|
@@ -3530,7 +3820,6 @@ var package_default = {
|
|
|
3530
3820
|
nanoid: "^5.1.15",
|
|
3531
3821
|
pino: "^10.3.1",
|
|
3532
3822
|
react: "^19.2.7",
|
|
3533
|
-
toml: "^4.1.1",
|
|
3534
3823
|
varlock: "^1.5.1",
|
|
3535
3824
|
zod: "^4.4.3",
|
|
3536
3825
|
zustand: "^5.0.14"
|
|
@@ -3572,8 +3861,8 @@ function parseEntries(raw) {
|
|
|
3572
3861
|
var summarize = (entries) => entries.length ? entries.map((e) => e.name).join(", ") : "none";
|
|
3573
3862
|
|
|
3574
3863
|
// src/actions/confirmLanguage.ts
|
|
3575
|
-
import
|
|
3576
|
-
var confirmLanguageSchema =
|
|
3864
|
+
import z21 from "zod";
|
|
3865
|
+
var confirmLanguageSchema = z21.object({
|
|
3577
3866
|
languages: detectLanguageSchema.shape.languages
|
|
3578
3867
|
});
|
|
3579
3868
|
var OTHER_OPTION = "Other";
|
|
@@ -3643,7 +3932,7 @@ async function confirmLanguage(ctx) {
|
|
|
3643
3932
|
}
|
|
3644
3933
|
|
|
3645
3934
|
// src/actions/confirmFramework.ts
|
|
3646
|
-
import
|
|
3935
|
+
import z22 from "zod";
|
|
3647
3936
|
|
|
3648
3937
|
// src/lib/frameworks.ts
|
|
3649
3938
|
var BACKEND_ONLY_FRAMEWORK = "Backend only / API";
|
|
@@ -3744,7 +4033,7 @@ function describeSearchTarget(strategy, frameworkName) {
|
|
|
3744
4033
|
}
|
|
3745
4034
|
|
|
3746
4035
|
// src/actions/confirmFramework.ts
|
|
3747
|
-
var confirmFrameworkSchema =
|
|
4036
|
+
var confirmFrameworkSchema = z22.object({
|
|
3748
4037
|
frameworks: detectLanguageSchema.shape.frameworks
|
|
3749
4038
|
});
|
|
3750
4039
|
var OTHER_OPTION2 = "Other";
|
|
@@ -3842,8 +4131,8 @@ async function promptUser(ctx, params) {
|
|
|
3842
4131
|
}
|
|
3843
4132
|
|
|
3844
4133
|
// src/actions/confirmEntities.ts
|
|
3845
|
-
import
|
|
3846
|
-
var confirmEntitiesSchema =
|
|
4134
|
+
import z23 from "zod";
|
|
4135
|
+
var confirmEntitiesSchema = z23.object({
|
|
3847
4136
|
// Final detection — the focused re-run may supersede project-scan's.
|
|
3848
4137
|
ingestionAnalysis: ingestionAnalysisSchema.shape.ingestionAnalysis.optional(),
|
|
3849
4138
|
confirmedEntities: confirmedEntitiesFieldSchema
|
|
@@ -3913,15 +4202,15 @@ async function confirmEntities(ctx) {
|
|
|
3913
4202
|
}
|
|
3914
4203
|
|
|
3915
4204
|
// src/actions/review.ts
|
|
3916
|
-
import { z as
|
|
3917
|
-
var reviewSchema =
|
|
4205
|
+
import { z as z24 } from "zod";
|
|
4206
|
+
var reviewSchema = z24.object({
|
|
3918
4207
|
// Broad, high-level takeaways grouped by theme (e.g. ingestion, search UI),
|
|
3919
4208
|
// not one entry per workflow step — a step's raw output can be a long,
|
|
3920
4209
|
// multi-paragraph blob (see implement.ts's summaries.join), and mirroring
|
|
3921
4210
|
// that 1:1 is what made the old per-step summary an unreadable wall of text.
|
|
3922
|
-
summaryPoints:
|
|
3923
|
-
reviewPrompt:
|
|
3924
|
-
nextSteps:
|
|
4211
|
+
summaryPoints: z24.array(z24.string()),
|
|
4212
|
+
reviewPrompt: z24.string(),
|
|
4213
|
+
nextSteps: z24.array(z24.string())
|
|
3925
4214
|
});
|
|
3926
4215
|
function formatCompletedSteps(steps) {
|
|
3927
4216
|
if (!steps.length) return "(no prior steps completed)";
|
|
@@ -3972,17 +4261,17 @@ ${formatCompletedSteps(ctx.completedSteps)}`,
|
|
|
3972
4261
|
};
|
|
3973
4262
|
|
|
3974
4263
|
// src/actions/implement.ts
|
|
3975
|
-
import
|
|
4264
|
+
import z25 from "zod";
|
|
3976
4265
|
|
|
3977
4266
|
// src/lib/worktree.ts
|
|
3978
4267
|
import { execFile } from "node:child_process";
|
|
3979
4268
|
import { existsSync as existsSync4 } from "node:fs";
|
|
3980
|
-
import { copyFile, mkdir as mkdir6, readdir as readdir4, readFile as
|
|
4269
|
+
import { copyFile, mkdir as mkdir6, readdir as readdir4, readFile as readFile7, stat as stat2, writeFile as writeFile6 } from "node:fs/promises";
|
|
3981
4270
|
import {
|
|
3982
4271
|
basename as basename2,
|
|
3983
4272
|
dirname as dirname7,
|
|
3984
4273
|
isAbsolute as isAbsolute2,
|
|
3985
|
-
join as
|
|
4274
|
+
join as join11,
|
|
3986
4275
|
relative as relative2,
|
|
3987
4276
|
resolve as resolve3
|
|
3988
4277
|
} from "node:path";
|
|
@@ -4016,7 +4305,7 @@ async function isWorkingTreeDirty(repoRoot) {
|
|
|
4016
4305
|
return out.trim().length > 0;
|
|
4017
4306
|
}
|
|
4018
4307
|
async function pruneOldWorktrees(repoRoot) {
|
|
4019
|
-
const dir =
|
|
4308
|
+
const dir = join11(stateDir(repoRoot), "worktrees");
|
|
4020
4309
|
const stale = (await readdir4(dir).catch(() => [])).filter((name) => /^wizard-implement-\d+$/.test(name)).sort().reverse().slice(MAX_WIZARD_WORKTREES - 1);
|
|
4021
4310
|
for (const slug of stale) {
|
|
4022
4311
|
const branch = slug.replace("wizard-implement-", WIZARD_BRANCH_PREFIX);
|
|
@@ -4027,7 +4316,7 @@ async function pruneOldWorktrees(repoRoot) {
|
|
|
4027
4316
|
"worktree",
|
|
4028
4317
|
"remove",
|
|
4029
4318
|
"--force",
|
|
4030
|
-
|
|
4319
|
+
join11(dir, slug)
|
|
4031
4320
|
]);
|
|
4032
4321
|
await git(["-C", repoRoot, "branch", "-D", branch]);
|
|
4033
4322
|
} catch (err) {
|
|
@@ -4041,7 +4330,7 @@ async function pruneOldWorktrees(repoRoot) {
|
|
|
4041
4330
|
async function createWorktree(repoRoot) {
|
|
4042
4331
|
const branch = `${WIZARD_BRANCH_PREFIX}${Date.now()}`;
|
|
4043
4332
|
const dirSlug = branch.replace(/\//g, "-");
|
|
4044
|
-
const path =
|
|
4333
|
+
const path = join11(stateDir(repoRoot), "worktrees", dirSlug);
|
|
4045
4334
|
await git(["-C", repoRoot, "worktree", "prune"]);
|
|
4046
4335
|
await pruneOldWorktrees(repoRoot);
|
|
4047
4336
|
await mkdir6(dirname7(path), { recursive: true });
|
|
@@ -4056,24 +4345,24 @@ async function spawnStep(worktreePath, argv) {
|
|
|
4056
4345
|
return { ok: code === 0, output: output.trim() };
|
|
4057
4346
|
}
|
|
4058
4347
|
async function installWorktreeDeps(worktreePath, toolchain) {
|
|
4059
|
-
const { profile
|
|
4348
|
+
const { profile, installSteps, packageManager } = toolchain;
|
|
4060
4349
|
const declared = packageManager.dependency.mode === "agent-declares" ? packageManager.dependency.file : void 0;
|
|
4061
|
-
const haveSomethingToInstall = await hasProfileManifest(worktreePath,
|
|
4350
|
+
const haveSomethingToInstall = await hasProfileManifest(worktreePath, profile) || declared !== void 0 && existsSync4(join11(worktreePath, declared));
|
|
4062
4351
|
if (!haveSomethingToInstall) {
|
|
4063
4352
|
return {
|
|
4064
4353
|
ok: true,
|
|
4065
|
-
output: `no ${
|
|
4354
|
+
output: `no ${profile.displayName} manifest; skipped install`
|
|
4066
4355
|
};
|
|
4067
4356
|
}
|
|
4068
4357
|
if (installSteps.length === 0) {
|
|
4069
4358
|
return {
|
|
4070
4359
|
ok: true,
|
|
4071
|
-
output: `${
|
|
4360
|
+
output: `${profile.displayName} (${toolchain.packageManager.id}) has no wizard-run install step`
|
|
4072
4361
|
};
|
|
4073
4362
|
}
|
|
4074
4363
|
const outputs = [];
|
|
4075
4364
|
for (const step of installSteps) {
|
|
4076
|
-
if (step.requiresFile && !existsSync4(
|
|
4365
|
+
if (step.requiresFile && !existsSync4(join11(worktreePath, step.requiresFile)))
|
|
4077
4366
|
continue;
|
|
4078
4367
|
const result = await spawnStep(worktreePath, step.argv);
|
|
4079
4368
|
if (result.output) outputs.push(result.output);
|
|
@@ -4113,13 +4402,13 @@ function validateIngestEntrypoint(worktreePath, entrypoint, allowedExtensions) {
|
|
|
4113
4402
|
return { ok: true, target };
|
|
4114
4403
|
}
|
|
4115
4404
|
async function runIngestScript(worktreePath, toolchain, entrypoint, env = {}) {
|
|
4116
|
-
const { ingest, profile
|
|
4405
|
+
const { ingest, profile, packageManager } = toolchain;
|
|
4117
4406
|
if (ingest.kind !== "auto") {
|
|
4118
4407
|
return {
|
|
4119
4408
|
ran: false,
|
|
4120
4409
|
ok: false,
|
|
4121
4410
|
output: "",
|
|
4122
|
-
reason: `${
|
|
4411
|
+
reason: `${profile.displayName} (${packageManager.id}) projects must be run manually: ${ingest.runCommand}`
|
|
4123
4412
|
};
|
|
4124
4413
|
}
|
|
4125
4414
|
const validated = validateIngestEntrypoint(
|
|
@@ -4168,8 +4457,8 @@ async function copyUploadIntoWorktree(repoRoot, worktreePath, ingestDir, sourceP
|
|
|
4168
4457
|
} catch {
|
|
4169
4458
|
return { ok: false, reason: `"${sourcePath}" does not exist` };
|
|
4170
4459
|
}
|
|
4171
|
-
const relPath =
|
|
4172
|
-
const dest =
|
|
4460
|
+
const relPath = join11(ingestDir, basename2(source));
|
|
4461
|
+
const dest = join11(worktreePath, relPath);
|
|
4173
4462
|
try {
|
|
4174
4463
|
await mkdir6(dirname7(dest), { recursive: true });
|
|
4175
4464
|
await copyFile(source, dest);
|
|
@@ -4185,10 +4474,10 @@ function hasEnvVar(content, name) {
|
|
|
4185
4474
|
return new RegExp(`^(\\s*(?:export\\s+)?${name})\\s*=`, "m").test(content);
|
|
4186
4475
|
}
|
|
4187
4476
|
async function writeSearchEnvValues(worktreePath, vars) {
|
|
4188
|
-
const target =
|
|
4477
|
+
const target = join11(worktreePath, ".env");
|
|
4189
4478
|
let existing = "";
|
|
4190
4479
|
try {
|
|
4191
|
-
existing = await
|
|
4480
|
+
existing = await readFile7(target, "utf8");
|
|
4192
4481
|
} catch (err) {
|
|
4193
4482
|
if (err.code !== "ENOENT") throw err;
|
|
4194
4483
|
}
|
|
@@ -4256,63 +4545,15 @@ async function confirmDirtyWorkingTree(ctx, repoRoot) {
|
|
|
4256
4545
|
}
|
|
4257
4546
|
}
|
|
4258
4547
|
|
|
4259
|
-
// src/lib/algoliaApiKey.ts
|
|
4260
|
-
import { z as z23 } from "zod";
|
|
4261
|
-
var SAFE_ACLS = /* @__PURE__ */ new Set(["search", "browse", "listIndexes"]);
|
|
4262
|
-
var apiKeySchema = z23.object({
|
|
4263
|
-
value: z23.string().min(1),
|
|
4264
|
-
acl: z23.array(z23.string()).default([]),
|
|
4265
|
-
indexes: z23.array(z23.string()).default([])
|
|
4266
|
-
});
|
|
4267
|
-
var apiKeyListSchema = z23.object({
|
|
4268
|
-
items: z23.array(apiKeySchema).optional(),
|
|
4269
|
-
keys: z23.array(apiKeySchema).optional()
|
|
4270
|
-
}).transform((o) => o.items ?? o.keys ?? []);
|
|
4271
|
-
var createdKeySchema = z23.object({
|
|
4272
|
-
key: z23.string().min(1).optional(),
|
|
4273
|
-
value: z23.string().min(1).optional()
|
|
4274
|
-
});
|
|
4275
|
-
function canReuse(key, index) {
|
|
4276
|
-
return key.acl.includes("search") && key.acl.every((acl) => SAFE_ACLS.has(acl)) && (key.indexes.length === 0 || key.indexes.includes("*") || key.indexes.includes(index));
|
|
4277
|
-
}
|
|
4278
|
-
async function createSearchKey(index) {
|
|
4279
|
-
const stdout = await runAlgoliaCli([
|
|
4280
|
-
"apikeys",
|
|
4281
|
-
"create",
|
|
4282
|
-
"--indices",
|
|
4283
|
-
index,
|
|
4284
|
-
"--acl",
|
|
4285
|
-
"search,browse",
|
|
4286
|
-
"--description",
|
|
4287
|
-
`wizard search-only key for ${index}`,
|
|
4288
|
-
"-o",
|
|
4289
|
-
"json"
|
|
4290
|
-
]);
|
|
4291
|
-
const { key, value } = createdKeySchema.parse(JSON.parse(stdout));
|
|
4292
|
-
const created = key ?? value;
|
|
4293
|
-
if (!created) throw new Error("apikeys create returned no key value");
|
|
4294
|
-
return created;
|
|
4295
|
-
}
|
|
4296
|
-
async function resolveSearchOnlyKey(index) {
|
|
4297
|
-
const stdout = await runAlgoliaCli(["apikeys", "list", "-o", "json"]);
|
|
4298
|
-
const existing = apiKeyListSchema.parse(JSON.parse(stdout)).find((key) => canReuse(key, index))?.value;
|
|
4299
|
-
if (existing) {
|
|
4300
|
-
logger.info({ index }, "reusing existing search-only API key");
|
|
4301
|
-
return existing;
|
|
4302
|
-
}
|
|
4303
|
-
logger.info({ index }, "no reusable search-only key found; creating one");
|
|
4304
|
-
return createSearchKey(index);
|
|
4305
|
-
}
|
|
4306
|
-
|
|
4307
4548
|
// src/lib/algoliaDocs.ts
|
|
4308
4549
|
import { readFileSync, existsSync as existsSync5 } from "node:fs";
|
|
4309
|
-
import { dirname as dirname8, join as
|
|
4550
|
+
import { dirname as dirname8, join as join12 } from "node:path";
|
|
4310
4551
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
4311
|
-
var DOCS_SUBPATH =
|
|
4552
|
+
var DOCS_SUBPATH = join12("docs", "algolia-sdk");
|
|
4312
4553
|
function findDocsDir() {
|
|
4313
4554
|
let dir = dirname8(fileURLToPath2(import.meta.url));
|
|
4314
4555
|
for (; ; ) {
|
|
4315
|
-
const candidate =
|
|
4556
|
+
const candidate = join12(dir, DOCS_SUBPATH);
|
|
4316
4557
|
if (existsSync5(candidate)) return candidate;
|
|
4317
4558
|
const parent = dirname8(dir);
|
|
4318
4559
|
if (parent === dir) return void 0;
|
|
@@ -4325,7 +4566,7 @@ function getNamedDoc(name, key) {
|
|
|
4325
4566
|
logger.warn("docs/algolia-sdk not found");
|
|
4326
4567
|
return "";
|
|
4327
4568
|
}
|
|
4328
|
-
const file =
|
|
4569
|
+
const file = join12(docsDir, `${name}-${key}.md`);
|
|
4329
4570
|
if (!existsSync5(file)) {
|
|
4330
4571
|
logger.warn({ name, key }, "named SDK reference not found");
|
|
4331
4572
|
return "";
|
|
@@ -4334,49 +4575,49 @@ function getNamedDoc(name, key) {
|
|
|
4334
4575
|
}
|
|
4335
4576
|
|
|
4336
4577
|
// src/actions/implement.ts
|
|
4337
|
-
var implementSchema =
|
|
4338
|
-
filesChanged:
|
|
4339
|
-
summary:
|
|
4578
|
+
var implementSchema = z25.object({
|
|
4579
|
+
filesChanged: z25.array(z25.string()),
|
|
4580
|
+
summary: z25.string(),
|
|
4340
4581
|
// Absolute path to the throwaway worktree holding the generated changes, so
|
|
4341
4582
|
// the user can open it (`cd <worktreePath>`) or inspect the diff
|
|
4342
4583
|
// (`git -C <worktreePath> status/diff`).
|
|
4343
|
-
worktreePath:
|
|
4344
|
-
ingestCommand:
|
|
4584
|
+
worktreePath: z25.string().optional(),
|
|
4585
|
+
ingestCommand: z25.string().optional(),
|
|
4345
4586
|
// True when the user accepted the run-now prompt and the wizard executed the
|
|
4346
4587
|
// ingestion script; downstream steps use this to avoid telling the user to run
|
|
4347
4588
|
// a script that already ran.
|
|
4348
|
-
ingestScriptRan:
|
|
4589
|
+
ingestScriptRan: z25.boolean().optional(),
|
|
4349
4590
|
// Records ingested by the run-now execution, parsed from the script's
|
|
4350
4591
|
// machine-readable count line; absent when the script didn't run or emitted
|
|
4351
4592
|
// no parseable count.
|
|
4352
|
-
ingestRecordCount:
|
|
4593
|
+
ingestRecordCount: z25.number().optional(),
|
|
4353
4594
|
// Wall-clock duration of the run-now ingestion execution, in ms.
|
|
4354
|
-
ingestDurationMs:
|
|
4355
|
-
ingestionSource:
|
|
4595
|
+
ingestDurationMs: z25.number().optional(),
|
|
4596
|
+
ingestionSource: z25.enum(["local", "fileUpload", "generated"]),
|
|
4356
4597
|
// Suggested names/values, built from framework detection. The search agent is
|
|
4357
4598
|
// instructed to rename the prefix if it doesn't match the project's build
|
|
4358
4599
|
// tool, so the names it actually wrote can differ — treat these as hints, not
|
|
4359
4600
|
// ground truth (the agent's summary carries the final names).
|
|
4360
|
-
searchEnvVars:
|
|
4361
|
-
|
|
4362
|
-
name:
|
|
4363
|
-
value:
|
|
4601
|
+
searchEnvVars: z25.array(
|
|
4602
|
+
z25.object({
|
|
4603
|
+
name: z25.string(),
|
|
4604
|
+
value: z25.string()
|
|
4364
4605
|
})
|
|
4365
4606
|
).optional()
|
|
4366
4607
|
});
|
|
4367
|
-
var implementationOutputSchema =
|
|
4368
|
-
summary:
|
|
4608
|
+
var implementationOutputSchema = z25.object({
|
|
4609
|
+
summary: z25.string(),
|
|
4369
4610
|
// Ingestion only: the script the wizard should run, as a bare path — never a
|
|
4370
4611
|
// command string, and never the interpreter. The command comes from the
|
|
4371
4612
|
// resolved language toolchain (a registry constant); this path is validated to
|
|
4372
4613
|
// a worktree-relative file with a runnable extension and substituted into it.
|
|
4373
4614
|
// So the agent contributes no part of the command that gets executed.
|
|
4374
|
-
entrypoint:
|
|
4615
|
+
entrypoint: z25.string().optional()
|
|
4375
4616
|
});
|
|
4376
|
-
var verificationOutputSchema =
|
|
4377
|
-
summary:
|
|
4378
|
-
sufficient:
|
|
4379
|
-
additionalInstructions:
|
|
4617
|
+
var verificationOutputSchema = z25.object({
|
|
4618
|
+
summary: z25.string(),
|
|
4619
|
+
sufficient: z25.boolean(),
|
|
4620
|
+
additionalInstructions: z25.string().optional()
|
|
4380
4621
|
});
|
|
4381
4622
|
var MAX_IMPLEMENT_VERIFICATION_ATTEMPTS = 3;
|
|
4382
4623
|
var DEFAULT_IMPLEMENT_USE_CASES = ["ingestion", "search"];
|
|
@@ -4462,18 +4703,18 @@ function sourceSpecificInstructions(input) {
|
|
|
4462
4703
|
return byLine[input.ingestionSource];
|
|
4463
4704
|
}
|
|
4464
4705
|
function ingestionInstructions(input) {
|
|
4465
|
-
const { ingestionProfile:
|
|
4706
|
+
const { ingestionProfile: profile, toolchain } = input;
|
|
4466
4707
|
const { ingest } = toolchain;
|
|
4467
4708
|
const extensions = ingest.entrypointExtensions.join(", ");
|
|
4468
|
-
const runInstruction = ingest.kind === "auto" ? `Return "entrypoint": the script path relative to the worktree root (e.g. "${
|
|
4709
|
+
const runInstruction = ingest.kind === "auto" ? `Return "entrypoint": the script path relative to the worktree root (e.g. "${profile.ingestEntrypointExample}"), ending in one of ${extensions}. The wizard runs it with \`${describeIngestCommand(ingest, profile.ingestEntrypointExample)}\`, so it must be a plain path with no flags or arguments and must run as-is under that command.` : `Return "entrypoint": the script path relative to the worktree root (e.g. "${profile.ingestEntrypointExample}"), ending in one of ${extensions}. The wizard does NOT run ${profile.displayName} ${toolchain.packageManager.id} projects itself \u2014 it tells the developer to run \`${describeIngestCommand(ingest, profile.ingestEntrypointExample)}\`, so also add whatever build configuration that command needs.`;
|
|
4469
4710
|
return [
|
|
4470
4711
|
...input.confirmed && input.confirmed.length ? [
|
|
4471
|
-
`Write the ingestion script in ${
|
|
4712
|
+
`Write the ingestion script in ${profile.displayName}, at "${ingestScriptDir(profile)}/" in the repo.`,
|
|
4472
4713
|
`Ingest only these confirmed entities (name, source paths, attributes): ${JSON.stringify(input.confirmed)}.`,
|
|
4473
|
-
`Ingesting writes to Algolia, so the script needs a write API key and App ID \u2014 read them from the ${API_KEY_VAR} and ${APP_ID_VAR} environment variables rather than hardcoding them. ${
|
|
4474
|
-
`Use the official Algolia ${
|
|
4714
|
+
`Ingesting writes to Algolia, so the script needs a write API key and App ID \u2014 read them from the ${API_KEY_VAR} and ${APP_ID_VAR} environment variables rather than hardcoding them. ${profile.envReadInstruction} The wizard sets these when it runs the script.`,
|
|
4715
|
+
`Use the official Algolia ${profile.displayName} client (${profile.sdk.packageName}). Do not use the raw HTTP API, and do not use a client for another language.`,
|
|
4475
4716
|
"After a successful ingest, the script must print exactly one line to stdout in the form `ALGOLIA_WIZARD_RECORD_COUNT=<n>`, where <n> is the total number of records pushed to Algolia. Print it last, on its own line, with no surrounding text.",
|
|
4476
|
-
getNamedDoc("save-records",
|
|
4717
|
+
getNamedDoc("save-records", profile.sdk.docKey),
|
|
4477
4718
|
dependencyInstruction(toolchain),
|
|
4478
4719
|
"The summary should be extremely concise.",
|
|
4479
4720
|
runInstruction,
|
|
@@ -4497,7 +4738,7 @@ function searchInstructions(input) {
|
|
|
4497
4738
|
`It needs at least a working SearchBox and Hits against the "${input.targetIndex}" index.`,
|
|
4498
4739
|
isTemplate ? "Load InstantSearch from a CDN with script tags as shown in the reference. Do not add JavaScript package dependencies, a bundler, or a build step." : 'Add any Algolia/InstantSearch packages you import to package.json "dependencies" with a valid version range; the wizard installs them in the worktree after you finish.',
|
|
4499
4740
|
isTemplate ? "Read the App ID and search-only API key from server-side configuration/environment and render them into the page (e.g. as data- attributes the script reads); never hardcode them, and never put a write/admin key in HTML." : "Read the App ID and a search-only API key from public env vars; never hardcode them. A search-only key is safe to expose client-side.",
|
|
4500
|
-
// appId always resolves (
|
|
4741
|
+
// appId always resolves (requireApplication throws otherwise); only the
|
|
4501
4742
|
// search-only key is best-effort and can fall back to a placeholder.
|
|
4502
4743
|
`Values: App ID "${input.appId}", search-only key ${input.searchKey ? `"${input.searchKey}"` : "(placeholder for the developer to fill in)"}.`,
|
|
4503
4744
|
// Names are fixed, not the agent's to rename: the wizard writes the
|
|
@@ -4650,6 +4891,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4650
4891
|
}
|
|
4651
4892
|
}
|
|
4652
4893
|
const targetIndex = selected?.selection;
|
|
4894
|
+
useWizard.getState().setTargetIndex(targetIndex ?? null);
|
|
4653
4895
|
await assertGitRepoWithHead(repoRoot);
|
|
4654
4896
|
if (await isWorkingTreeDirty(repoRoot)) {
|
|
4655
4897
|
await confirmDirtyWorkingTree(ctx, repoRoot);
|
|
@@ -4660,7 +4902,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4660
4902
|
let appId;
|
|
4661
4903
|
let searchKey;
|
|
4662
4904
|
if (useCases.includes("search")) {
|
|
4663
|
-
appId = (await
|
|
4905
|
+
appId = (await requireApplication()).id;
|
|
4664
4906
|
try {
|
|
4665
4907
|
searchKey = await resolveSearchOnlyKey(targetIndex);
|
|
4666
4908
|
} catch (err) {
|
|
@@ -4810,7 +5052,8 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4810
5052
|
messages: []
|
|
4811
5053
|
}) === true;
|
|
4812
5054
|
if (runNow) {
|
|
4813
|
-
const
|
|
5055
|
+
const ingestApp = await requireApplication();
|
|
5056
|
+
const writeKey = await resolveWriteKey(targetIndex);
|
|
4814
5057
|
ctx.notify({ messages: [`Writing records to "${targetIndex}"\u2026`] });
|
|
4815
5058
|
const scriptLogId = ctx.logStart("runIngestScript", {
|
|
4816
5059
|
language: ingestionProfile.id,
|
|
@@ -4822,8 +5065,8 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4822
5065
|
toolchain,
|
|
4823
5066
|
ingestEntrypoint,
|
|
4824
5067
|
{
|
|
4825
|
-
[APP_ID_VAR]:
|
|
4826
|
-
[API_KEY_VAR]:
|
|
5068
|
+
[APP_ID_VAR]: ingestApp.id,
|
|
5069
|
+
[API_KEY_VAR]: writeKey
|
|
4827
5070
|
}
|
|
4828
5071
|
);
|
|
4829
5072
|
ctx.logEnd(scriptLogId, run.ok ? "success" : "error");
|
|
@@ -5052,8 +5295,8 @@ var defaultWorkflow = {
|
|
|
5052
5295
|
defineStep({
|
|
5053
5296
|
id: "select-index",
|
|
5054
5297
|
title: "Set up index",
|
|
5055
|
-
outputSchema:
|
|
5056
|
-
selection:
|
|
5298
|
+
outputSchema: z26.object({
|
|
5299
|
+
selection: z26.string()
|
|
5057
5300
|
}),
|
|
5058
5301
|
run: (ctx) => selectIndexStep(ctx)
|
|
5059
5302
|
}),
|
|
@@ -5134,25 +5377,54 @@ var store = useWizard.getState();
|
|
|
5134
5377
|
var instance = render(/* @__PURE__ */ jsx14(App, {}), { incrementalRendering: true });
|
|
5135
5378
|
var user = await getUser();
|
|
5136
5379
|
if (!user) {
|
|
5137
|
-
|
|
5138
|
-
instance.cleanup();
|
|
5380
|
+
store.beginAuth();
|
|
5139
5381
|
try {
|
|
5140
5382
|
await runAuthLogin();
|
|
5141
5383
|
} catch (err) {
|
|
5142
|
-
|
|
5143
|
-
|
|
5384
|
+
if (!needsInteractiveTerminal(err)) {
|
|
5385
|
+
store.setError(err instanceof Error ? err.message : String(err));
|
|
5386
|
+
await instance.waitUntilExit();
|
|
5387
|
+
process.exit(1);
|
|
5388
|
+
}
|
|
5389
|
+
try {
|
|
5390
|
+
await promptForApplication();
|
|
5391
|
+
} catch (pickErr) {
|
|
5392
|
+
logger.warn(
|
|
5393
|
+
{ err: pickErr.message },
|
|
5394
|
+
"in-wizard application selection failed; handing over the terminal"
|
|
5395
|
+
);
|
|
5396
|
+
await instance.waitUntilRenderFlush();
|
|
5397
|
+
instance.cleanup();
|
|
5398
|
+
try {
|
|
5399
|
+
await runAuthLoginInTerminal();
|
|
5400
|
+
} catch (fallbackErr) {
|
|
5401
|
+
console.error(
|
|
5402
|
+
fallbackErr instanceof Error ? fallbackErr.message : String(fallbackErr)
|
|
5403
|
+
);
|
|
5404
|
+
process.exit(1);
|
|
5405
|
+
}
|
|
5406
|
+
instance = render(/* @__PURE__ */ jsx14(App, {}), { incrementalRendering: true });
|
|
5407
|
+
store.clearCliOutput();
|
|
5408
|
+
}
|
|
5144
5409
|
}
|
|
5145
|
-
|
|
5410
|
+
store.endAuth();
|
|
5146
5411
|
user = await getUser();
|
|
5147
5412
|
if (!user) {
|
|
5148
5413
|
store.setError(
|
|
5149
|
-
"Authentication completed but no Algolia user was returned. Try running `npx @algolia/cli auth login` directly."
|
|
5414
|
+
"Authentication completed but no Algolia user was returned. Try running `npx @algolia/cli@latest auth login` directly."
|
|
5150
5415
|
);
|
|
5151
5416
|
await instance.waitUntilExit();
|
|
5152
5417
|
process.exit(1);
|
|
5153
5418
|
}
|
|
5154
5419
|
}
|
|
5155
5420
|
store.setUser(user);
|
|
5156
|
-
var profile = await loadActiveProfile();
|
|
5157
5421
|
await store.waitForStart();
|
|
5158
|
-
|
|
5422
|
+
var app;
|
|
5423
|
+
try {
|
|
5424
|
+
app = await ensureApplication();
|
|
5425
|
+
} catch (err) {
|
|
5426
|
+
store.setError(err instanceof Error ? err.message : String(err));
|
|
5427
|
+
await instance.waitUntilExit();
|
|
5428
|
+
process.exit(1);
|
|
5429
|
+
}
|
|
5430
|
+
runWorkflow(workflow, app.id);
|