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