@algolia/wizard 0.9.0-rc.53.58 → 0.9.0-rc.69.59
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/README.md +1 -1
- package/dist/main.js +578 -764
- 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 Box14, Text as Text14, useApp, useInput as useInput6, useWindowSize as useWindowSize7 } from "ink";
|
|
8
8
|
|
|
9
9
|
// src/core/store.ts
|
|
10
10
|
import { create } from "zustand";
|
|
@@ -12,86 +12,32 @@ import { nanoid } from "nanoid";
|
|
|
12
12
|
|
|
13
13
|
// src/lib/algoliaCli.ts
|
|
14
14
|
import { spawn } from "node:child_process";
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
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");
|
|
18
19
|
}
|
|
19
|
-
|
|
20
|
-
function lineSplitter(emit) {
|
|
21
|
-
let buffer = "";
|
|
22
|
-
return {
|
|
23
|
-
push(chunk) {
|
|
24
|
-
buffer += chunk;
|
|
25
|
-
const lines = buffer.split("\n");
|
|
26
|
-
buffer = lines.pop() ?? "";
|
|
27
|
-
for (const line of lines) emit(line.replace(/\r$/, ""));
|
|
28
|
-
},
|
|
29
|
-
flush() {
|
|
30
|
-
if (buffer) emit(buffer.replace(/\r$/, ""));
|
|
31
|
-
buffer = "";
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
var wizardSink = (stream, line) => {
|
|
36
|
-
if (!line.trim()) return;
|
|
37
|
-
useWizard.getState().pushCliOutput(stream, line);
|
|
38
|
-
};
|
|
39
|
-
var stderrSink = (stream, line) => {
|
|
40
|
-
if (stream === "stdout") return;
|
|
41
|
-
wizardSink(stream, line);
|
|
42
|
-
};
|
|
43
|
-
function runAlgoliaCli(args, { onOutput } = {}) {
|
|
44
|
-
const store = useWizard.getState();
|
|
45
|
-
const logId = store.logStart("tool", `algolia ${args.join(" ")}`);
|
|
20
|
+
function runAlgoliaCli(args) {
|
|
46
21
|
return new Promise((resolve4, reject) => {
|
|
47
|
-
const child = spawn(
|
|
22
|
+
const child = spawn(process.execPath, [algoliaCliEntry(), ...args]);
|
|
48
23
|
let stdout = "";
|
|
49
24
|
let stderr = "";
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
stderr: lineSplitter((line) => onOutput?.("stderr", line))
|
|
53
|
-
};
|
|
54
|
-
child.stdout.on("data", (chunk) => {
|
|
55
|
-
const text = String(chunk);
|
|
56
|
-
stdout += text;
|
|
57
|
-
splitters.stdout.push(text);
|
|
58
|
-
});
|
|
59
|
-
child.stderr.on("data", (chunk) => {
|
|
60
|
-
const text = String(chunk);
|
|
61
|
-
stderr += text;
|
|
62
|
-
splitters.stderr.push(text);
|
|
63
|
-
});
|
|
25
|
+
child.stdout.on("data", (chunk) => stdout += chunk);
|
|
26
|
+
child.stderr.on("data", (chunk) => stderr += chunk);
|
|
64
27
|
child.on("error", reject);
|
|
65
28
|
child.on("close", (code) => {
|
|
66
|
-
splitters.stdout.flush();
|
|
67
|
-
splitters.stderr.flush();
|
|
68
29
|
if (code === 0) {
|
|
69
30
|
resolve4(stdout);
|
|
70
31
|
} else {
|
|
71
|
-
const
|
|
72
|
-
let detail = "";
|
|
73
|
-
if (failed) {
|
|
74
|
-
detail = `: ${failed}`;
|
|
75
|
-
} else if (stdout.trim()) {
|
|
76
|
-
detail = " (no stderr; stdout withheld \u2014 it may contain credentials)";
|
|
77
|
-
}
|
|
32
|
+
const detail = stderr.trim() || stdout.trim();
|
|
78
33
|
reject(
|
|
79
34
|
new Error(
|
|
80
|
-
`Algolia CLI \`${args.join(" ")}\` failed (exit ${code})${detail}`
|
|
35
|
+
`Algolia CLI \`${args.join(" ")}\` failed (exit ${code})${detail ? `: ${detail}` : ""}`
|
|
81
36
|
)
|
|
82
37
|
);
|
|
83
38
|
}
|
|
84
39
|
});
|
|
85
|
-
})
|
|
86
|
-
(out) => {
|
|
87
|
-
useWizard.getState().logEnd(logId, "success");
|
|
88
|
-
return out;
|
|
89
|
-
},
|
|
90
|
-
(err) => {
|
|
91
|
-
useWizard.getState().logEnd(logId, "error");
|
|
92
|
-
throw err;
|
|
93
|
-
}
|
|
94
|
-
);
|
|
40
|
+
});
|
|
95
41
|
}
|
|
96
42
|
async function getUser() {
|
|
97
43
|
let raw;
|
|
@@ -106,23 +52,19 @@ async function getUser() {
|
|
|
106
52
|
return null;
|
|
107
53
|
}
|
|
108
54
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
55
|
+
function runAuthLogin() {
|
|
56
|
+
return new Promise((resolve4, reject) => {
|
|
57
|
+
const child = spawn(
|
|
58
|
+
process.execPath,
|
|
59
|
+
[algoliaCliEntry(), "auth", "login", "--default"],
|
|
60
|
+
{ stdio: "inherit" }
|
|
61
|
+
);
|
|
62
|
+
child.on("error", reject);
|
|
63
|
+
child.on("close", (code) => {
|
|
64
|
+
if (code === 0) resolve4();
|
|
65
|
+
else reject(new Error(`Algolia authentication failed (exit ${code}).`));
|
|
66
|
+
});
|
|
116
67
|
});
|
|
117
|
-
let parsed;
|
|
118
|
-
try {
|
|
119
|
-
parsed = loginResultSchema.safeParse(JSON.parse(raw));
|
|
120
|
-
} catch {
|
|
121
|
-
parsed = void 0;
|
|
122
|
-
}
|
|
123
|
-
if (parsed?.success && !parsed.data.success) {
|
|
124
|
-
throw new Error("Algolia sign-in did not report success.");
|
|
125
|
-
}
|
|
126
68
|
}
|
|
127
69
|
|
|
128
70
|
// src/lib/auth.ts
|
|
@@ -229,7 +171,6 @@ function describeInputValue(value) {
|
|
|
229
171
|
return Array.isArray(value) ? value.join(", ") : value;
|
|
230
172
|
}
|
|
231
173
|
var NOTICE_INTERVAL_MS = 2e3;
|
|
232
|
-
var CLI_OUTPUT_LIMIT = 200;
|
|
233
174
|
var useWizard = create((set, get) => ({
|
|
234
175
|
phase: "idle",
|
|
235
176
|
homeScreen: "home",
|
|
@@ -241,21 +182,22 @@ var useWizard = create((set, get) => ({
|
|
|
241
182
|
notices: [],
|
|
242
183
|
_noticeQueue: [],
|
|
243
184
|
_noticeTimer: null,
|
|
244
|
-
cliOutput: [],
|
|
245
|
-
targetIndex: null,
|
|
246
185
|
logs: [],
|
|
247
186
|
error: null,
|
|
248
187
|
inputReq: null,
|
|
249
188
|
_resolve: null,
|
|
250
|
-
//
|
|
251
|
-
//
|
|
252
|
-
|
|
253
|
-
endAuth: () => set((s) => s.phase === "authenticating" ? { phase: "preflight" } : {}),
|
|
189
|
+
// Advances past the welcome screen. Only meaningful from 'idle' — once the
|
|
190
|
+
// workflow is running there's nothing left to confirm.
|
|
191
|
+
// Reset `homeScreen` so preflight shows Welcome, not the Learn more sub-view.
|
|
254
192
|
confirmStart: () => set(
|
|
255
193
|
(s) => s.phase === "idle" ? { phase: "preflight", homeScreen: "home" } : {}
|
|
256
194
|
),
|
|
195
|
+
// Welcome sub-view navigation; leaves `phase` untouched so the workflow stays paused.
|
|
257
196
|
openLearnMore: () => set({ homeScreen: "learnMore" }),
|
|
258
197
|
backToHome: () => set({ homeScreen: "home" }),
|
|
198
|
+
// Resolves once the phase leaves 'idle', whether that happens before or
|
|
199
|
+
// after this is called (the welcome screen's enter handler is what
|
|
200
|
+
// drives the transition via `confirmStart`).
|
|
259
201
|
waitForStart: () => new Promise((resolve4) => {
|
|
260
202
|
if (get().phase !== "idle") {
|
|
261
203
|
resolve4();
|
|
@@ -278,19 +220,15 @@ var useWizard = create((set, get) => ({
|
|
|
278
220
|
syncSteps: (steps, currentStepIndex) => set({ steps, currentStepIndex }),
|
|
279
221
|
setActiveStep: (index) => {
|
|
280
222
|
get()._clearNoticeQueue();
|
|
281
|
-
set({
|
|
282
|
-
phase: "running",
|
|
283
|
-
currentStepIndex: index,
|
|
284
|
-
output: "",
|
|
285
|
-
notices: [],
|
|
286
|
-
cliOutput: []
|
|
287
|
-
});
|
|
223
|
+
set({ phase: "running", currentStepIndex: index, output: "", notices: [] });
|
|
288
224
|
},
|
|
289
225
|
setUser: (user) => set({ user }),
|
|
290
226
|
appendToken: (text) => set((s) => ({ output: s.output + text })),
|
|
291
227
|
clearOutput: () => set({ output: "" }),
|
|
292
|
-
//
|
|
293
|
-
//
|
|
228
|
+
// Renders the first notice of a burst immediately, then holds later
|
|
229
|
+
// arrivals in `_noticeQueue` and drains one per `NOTICE_INTERVAL_MS` —
|
|
230
|
+
// the timer stays armed through an empty drain so the cooldown always
|
|
231
|
+
// covers the time since the last render, even across bursts.
|
|
294
232
|
pushNotice: (notice) => {
|
|
295
233
|
const { notices, _noticeQueue, _noticeTimer } = get();
|
|
296
234
|
if (_noticeTimer === null) {
|
|
@@ -323,13 +261,6 @@ var useWizard = create((set, get) => ({
|
|
|
323
261
|
get()._clearNoticeQueue();
|
|
324
262
|
set({ notices: [] });
|
|
325
263
|
},
|
|
326
|
-
pushCliOutput: (stream, text) => set((s) => ({
|
|
327
|
-
cliOutput: [...s.cliOutput, { id: nanoid(), stream, text }].slice(
|
|
328
|
-
-CLI_OUTPUT_LIMIT
|
|
329
|
-
)
|
|
330
|
-
})),
|
|
331
|
-
clearCliOutput: () => set({ cliOutput: [] }),
|
|
332
|
-
setTargetIndex: (index) => set({ targetIndex: index }),
|
|
333
264
|
logStart: (kind, name, input) => {
|
|
334
265
|
const id = nanoid();
|
|
335
266
|
set((s) => ({
|
|
@@ -352,6 +283,9 @@ var useWizard = create((set, get) => ({
|
|
|
352
283
|
_resolve: resolve4
|
|
353
284
|
});
|
|
354
285
|
}),
|
|
286
|
+
// Logs what the user picked — not the prompt text that was shown, which
|
|
287
|
+
// may repeat or duplicate on-screen content and isn't the useful signal
|
|
288
|
+
// here.
|
|
355
289
|
submitInput: async (value) => {
|
|
356
290
|
await markInteraction();
|
|
357
291
|
get()._resolve?.(value);
|
|
@@ -371,8 +305,6 @@ var useWizard = create((set, get) => ({
|
|
|
371
305
|
currentStepIndex: 0,
|
|
372
306
|
output: "",
|
|
373
307
|
notices: [],
|
|
374
|
-
cliOutput: [],
|
|
375
|
-
targetIndex: null,
|
|
376
308
|
logs: [],
|
|
377
309
|
error: null,
|
|
378
310
|
inputReq: null,
|
|
@@ -381,100 +313,16 @@ var useWizard = create((set, get) => ({
|
|
|
381
313
|
}
|
|
382
314
|
}));
|
|
383
315
|
|
|
384
|
-
// src/ui/CliOutput.tsx
|
|
385
|
-
import { Box, Text, useWindowSize } from "ink";
|
|
386
|
-
|
|
387
|
-
// src/ui/theme.ts
|
|
388
|
-
var MARKER = {
|
|
389
|
-
pending: "\u25CB",
|
|
390
|
-
running: "\u25D0",
|
|
391
|
-
done: "\u2713",
|
|
392
|
-
error: "\u2716"
|
|
393
|
-
};
|
|
394
|
-
var BRAND = "#003DFF";
|
|
395
|
-
var SECONDARY = "#5468FF";
|
|
396
|
-
var DANGER = "#F86E7E";
|
|
397
|
-
var COLORS = {
|
|
398
|
-
brand: BRAND,
|
|
399
|
-
primary: "#E6EDF3",
|
|
400
|
-
secondary: SECONDARY,
|
|
401
|
-
strong: "#FFFFFF",
|
|
402
|
-
muted: "#8B949E",
|
|
403
|
-
dim: "#484F58",
|
|
404
|
-
highlight: { bg: "#12331C", fg: "#4ADE80" },
|
|
405
|
-
badge: "#E3B341",
|
|
406
|
-
danger: DANGER,
|
|
407
|
-
success: "#4ADE80",
|
|
408
|
-
bg: {
|
|
409
|
-
main: "#0B0E14",
|
|
410
|
-
sidebar: "#14171E"
|
|
411
|
-
},
|
|
412
|
-
border: "#30363D",
|
|
413
|
-
accent: "#76A0FF",
|
|
414
|
-
status: {
|
|
415
|
-
pending: "gray",
|
|
416
|
-
running: "#76A0FF",
|
|
417
|
-
done: "#4ADE80",
|
|
418
|
-
error: DANGER
|
|
419
|
-
}
|
|
420
|
-
};
|
|
421
|
-
|
|
422
|
-
// src/ui/CliOutput.tsx
|
|
423
|
-
import { jsxs } from "react/jsx-runtime";
|
|
424
|
-
var CLI_MARKER = "\u203A";
|
|
425
|
-
var RESERVED_ROWS = 16;
|
|
426
|
-
var MAX_ROWS = 12;
|
|
427
|
-
var PANEL_TEXT_WIDTH = 45;
|
|
428
|
-
var URL_PATTERN = /https?:\/\//;
|
|
429
|
-
function rowCost(text) {
|
|
430
|
-
return URL_PATTERN.test(text) ? Math.max(1, Math.ceil(text.length / PANEL_TEXT_WIDTH)) : 1;
|
|
431
|
-
}
|
|
432
|
-
function CliOutput() {
|
|
433
|
-
const cliOutput = useWizard((s) => s.cliOutput);
|
|
434
|
-
const { rows } = useWindowSize();
|
|
435
|
-
if (!cliOutput.length) return null;
|
|
436
|
-
const rowBudget = Math.min(Math.max(rows - RESERVED_ROWS, 3), MAX_ROWS);
|
|
437
|
-
const visible = [];
|
|
438
|
-
let usedRows = 0;
|
|
439
|
-
for (let i = cliOutput.length - 1; i >= 0; i--) {
|
|
440
|
-
const cost = rowCost(cliOutput[i].text);
|
|
441
|
-
if (usedRows + cost > rowBudget && visible.length > 0) break;
|
|
442
|
-
visible.unshift(cliOutput[i]);
|
|
443
|
-
usedRows += cost;
|
|
444
|
-
}
|
|
445
|
-
const hidden = cliOutput.length - visible.length;
|
|
446
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
447
|
-
hidden > 0 && /* @__PURE__ */ jsxs(Text, { color: COLORS.dim, children: [
|
|
448
|
-
"\u2191 ",
|
|
449
|
-
hidden,
|
|
450
|
-
" earlier line(s)"
|
|
451
|
-
] }),
|
|
452
|
-
visible.map((line) => /* @__PURE__ */ jsxs(
|
|
453
|
-
Text,
|
|
454
|
-
{
|
|
455
|
-
color: line.stream === "stderr" ? COLORS.muted : COLORS.dim,
|
|
456
|
-
wrap: URL_PATTERN.test(line.text) ? "wrap" : "truncate",
|
|
457
|
-
children: [
|
|
458
|
-
CLI_MARKER,
|
|
459
|
-
" ",
|
|
460
|
-
line.text
|
|
461
|
-
]
|
|
462
|
-
},
|
|
463
|
-
line.id
|
|
464
|
-
))
|
|
465
|
-
] });
|
|
466
|
-
}
|
|
467
|
-
|
|
468
316
|
// src/ui/Notices.tsx
|
|
469
|
-
import { Box as
|
|
317
|
+
import { Box as Box2, Text as Text2, useWindowSize as useWindowSize2 } from "ink";
|
|
470
318
|
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
471
319
|
|
|
472
320
|
// src/ui/Table.tsx
|
|
473
|
-
import { Box
|
|
321
|
+
import { Box, Text, measureElement, useWindowSize } from "ink";
|
|
474
322
|
import { useEffect, useRef, useState } from "react";
|
|
475
323
|
import { jsx } from "react/jsx-runtime";
|
|
476
324
|
function Table({ columns, rows }) {
|
|
477
|
-
const { columns: termCols } =
|
|
325
|
+
const { columns: termCols } = useWindowSize();
|
|
478
326
|
const ref = useRef(null);
|
|
479
327
|
const [width, setWidth] = useState(0);
|
|
480
328
|
useEffect(() => {
|
|
@@ -482,7 +330,7 @@ function Table({ columns, rows }) {
|
|
|
482
330
|
}, [termCols, columns, rows]);
|
|
483
331
|
if (rows.length === 0) return null;
|
|
484
332
|
const lines = formatTable(columns, rows, width || void 0);
|
|
485
|
-
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}`)) });
|
|
486
334
|
}
|
|
487
335
|
function formatTable(columns, rows, width) {
|
|
488
336
|
const natural = columns.map(
|
|
@@ -522,13 +370,48 @@ function resize(widths, budget) {
|
|
|
522
370
|
}
|
|
523
371
|
var truncate = (s, width) => s.length <= width ? s : width <= 1 ? s.slice(0, width) : `${s.slice(0, width - 1)}\u2026`;
|
|
524
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
|
+
|
|
525
408
|
// src/ui/Notices.tsx
|
|
526
|
-
import { jsx as jsx2, jsxs
|
|
409
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
527
410
|
var AGENT_MARKER = "\u2726";
|
|
528
|
-
var
|
|
529
|
-
var
|
|
411
|
+
var RESERVED_ROWS = 14;
|
|
412
|
+
var PANEL_TEXT_WIDTH = 45;
|
|
530
413
|
function messageLineCount(text) {
|
|
531
|
-
return Math.max(1, Math.ceil(text.length /
|
|
414
|
+
return Math.max(1, Math.ceil(text.length / PANEL_TEXT_WIDTH));
|
|
532
415
|
}
|
|
533
416
|
function noticeLineCount(notice) {
|
|
534
417
|
const messageLines = (notice.messages ?? []).reduce((sum, m) => {
|
|
@@ -539,7 +422,7 @@ function noticeLineCount(notice) {
|
|
|
539
422
|
return messageLines + tableLines;
|
|
540
423
|
}
|
|
541
424
|
function fitVisibleNotices(notices, windowRows) {
|
|
542
|
-
const budget = Math.max(windowRows -
|
|
425
|
+
const budget = Math.max(windowRows - RESERVED_ROWS, 3);
|
|
543
426
|
let used = 0;
|
|
544
427
|
let count = 0;
|
|
545
428
|
for (let i = notices.length - 1; i >= 0; i--) {
|
|
@@ -572,7 +455,7 @@ function parseHex(hex) {
|
|
|
572
455
|
}
|
|
573
456
|
function Notices() {
|
|
574
457
|
const notices = useWizard((s) => s.notices);
|
|
575
|
-
const { rows: windowRows } =
|
|
458
|
+
const { rows: windowRows } = useWindowSize2();
|
|
576
459
|
const visible = fitVisibleNotices(notices, windowRows);
|
|
577
460
|
const [pulseStep, setPulseStep] = useState2(0);
|
|
578
461
|
useEffect2(() => {
|
|
@@ -589,14 +472,14 @@ function Notices() {
|
|
|
589
472
|
}, []);
|
|
590
473
|
if (!visible.length) return null;
|
|
591
474
|
const pulseColor = PULSE_COLORS[pulseStep];
|
|
592
|
-
return /* @__PURE__ */ jsx2(
|
|
475
|
+
return /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", gap: 1, marginBottom: 1, children: visible.map((notice, i) => {
|
|
593
476
|
const isLatest = i === visible.length - 1;
|
|
594
|
-
return /* @__PURE__ */
|
|
477
|
+
return /* @__PURE__ */ jsxs(Box2, { flexDirection: "column", children: [
|
|
595
478
|
notice.messages?.map((m, j) => {
|
|
596
479
|
const line = typeof m === "string" ? { text: m } : m;
|
|
597
480
|
const prefix = j === 0 ? `${AGENT_MARKER} ` : " ";
|
|
598
|
-
return /* @__PURE__ */
|
|
599
|
-
|
|
481
|
+
return /* @__PURE__ */ jsxs(
|
|
482
|
+
Text2,
|
|
600
483
|
{
|
|
601
484
|
color: isLatest && !line.color ? pulseColor : line.color ?? COLORS.dim,
|
|
602
485
|
bold: line.bold,
|
|
@@ -614,41 +497,41 @@ function Notices() {
|
|
|
614
497
|
}
|
|
615
498
|
|
|
616
499
|
// src/ui/PromptInput.tsx
|
|
617
|
-
import { Box as
|
|
500
|
+
import { Box as Box6, Text as Text6, useInput as useInput2 } from "ink";
|
|
618
501
|
import TextInput from "ink-text-input";
|
|
619
502
|
import { useState as useState5 } from "react";
|
|
620
503
|
|
|
621
504
|
// src/ui/NextAction.tsx
|
|
622
|
-
import { Box as
|
|
623
|
-
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";
|
|
624
507
|
function NextAction({
|
|
625
508
|
action,
|
|
626
509
|
keyHint,
|
|
627
510
|
hierarchy = "primary"
|
|
628
511
|
}) {
|
|
629
|
-
return /* @__PURE__ */
|
|
630
|
-
hierarchy === "primary" && /* @__PURE__ */ jsx3(
|
|
631
|
-
hierarchy === "secondary" && /* @__PURE__ */
|
|
632
|
-
/* @__PURE__ */ jsx3(
|
|
633
|
-
/* @__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 })
|
|
634
517
|
] }),
|
|
635
|
-
/* @__PURE__ */
|
|
636
|
-
/* @__PURE__ */ jsx3(
|
|
637
|
-
/* @__PURE__ */ jsx3(
|
|
638
|
-
/* @__PURE__ */ jsx3(
|
|
639
|
-
/* @__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: `]` })
|
|
640
523
|
] })
|
|
641
524
|
] });
|
|
642
525
|
}
|
|
643
526
|
|
|
644
527
|
// src/ui/SelectPrompt.tsx
|
|
645
|
-
import { Box as
|
|
528
|
+
import { Box as Box5, Text as Text5, useInput, useWindowSize as useWindowSize4 } from "ink";
|
|
646
529
|
import { useLayoutEffect as useLayoutEffect2, useRef as useRef3, useState as useState4 } from "react";
|
|
647
530
|
|
|
648
531
|
// src/ui/ScrollView.tsx
|
|
649
|
-
import { Box as
|
|
532
|
+
import { Box as Box4, Text as Text4, measureElement as measureElement2, useWindowSize as useWindowSize3 } from "ink";
|
|
650
533
|
import { useCallback, useLayoutEffect, useRef as useRef2, useState as useState3 } from "react";
|
|
651
|
-
import { jsxs as
|
|
534
|
+
import { jsxs as jsxs3 } from "react/jsx-runtime";
|
|
652
535
|
var INDICATOR_ROWS = 2;
|
|
653
536
|
function fittedWidth(node, columns) {
|
|
654
537
|
let left = 0;
|
|
@@ -663,7 +546,7 @@ function useScrollWindow({
|
|
|
663
546
|
followBottom = false
|
|
664
547
|
}) {
|
|
665
548
|
const viewportRef = useRef2(null);
|
|
666
|
-
const { columns } =
|
|
549
|
+
const { columns } = useWindowSize3();
|
|
667
550
|
const [size, setSize] = useState3(
|
|
668
551
|
null
|
|
669
552
|
);
|
|
@@ -718,14 +601,14 @@ function useScrollWindow({
|
|
|
718
601
|
};
|
|
719
602
|
}
|
|
720
603
|
function ScrollView({ scroll, children }) {
|
|
721
|
-
return /* @__PURE__ */
|
|
722
|
-
scroll.hiddenAbove > 0 && /* @__PURE__ */
|
|
604
|
+
return /* @__PURE__ */ jsxs3(Box4, { ref: scroll.viewportRef, flexDirection: "column", flexGrow: 1, children: [
|
|
605
|
+
scroll.hiddenAbove > 0 && /* @__PURE__ */ jsxs3(Text4, { color: COLORS.dim, children: [
|
|
723
606
|
"\u2191 ",
|
|
724
607
|
scroll.hiddenAbove,
|
|
725
608
|
" more"
|
|
726
609
|
] }),
|
|
727
610
|
children,
|
|
728
|
-
scroll.hiddenBelow > 0 && /* @__PURE__ */
|
|
611
|
+
scroll.hiddenBelow > 0 && /* @__PURE__ */ jsxs3(Text4, { color: COLORS.dim, children: [
|
|
729
612
|
"\u2193 ",
|
|
730
613
|
scroll.hiddenBelow,
|
|
731
614
|
" more"
|
|
@@ -734,7 +617,7 @@ function ScrollView({ scroll, children }) {
|
|
|
734
617
|
}
|
|
735
618
|
|
|
736
619
|
// src/ui/SelectPrompt.tsx
|
|
737
|
-
import { jsx as jsx4, jsxs as
|
|
620
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
738
621
|
var CANCEL = "cancel";
|
|
739
622
|
var ARROW_WIDTH = 4;
|
|
740
623
|
var COLUMN_GAP = 2;
|
|
@@ -765,7 +648,7 @@ function SelectPrompt({
|
|
|
765
648
|
if (multi) hints.push({ key: "[space]", label: "select" });
|
|
766
649
|
hints.push({ key: "[enter]", label: "confirm" });
|
|
767
650
|
const containerRef = useRef3(null);
|
|
768
|
-
const { columns } =
|
|
651
|
+
const { columns } = useWindowSize4();
|
|
769
652
|
const [width, setWidth] = useState4(columns);
|
|
770
653
|
useLayoutEffect2(() => {
|
|
771
654
|
if (!containerRef.current) return;
|
|
@@ -819,14 +702,14 @@ function SelectPrompt({
|
|
|
819
702
|
}
|
|
820
703
|
}
|
|
821
704
|
});
|
|
822
|
-
return /* @__PURE__ */ jsx4(
|
|
823
|
-
/* @__PURE__ */
|
|
824
|
-
error && /* @__PURE__ */ jsx4(
|
|
825
|
-
messages?.map((m, i) => /* @__PURE__ */ jsx4(
|
|
705
|
+
return /* @__PURE__ */ jsx4(Box5, { ref: containerRef, flexGrow: 1, children: /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", gap: 1, width, children: [
|
|
706
|
+
/* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", gap: 1, flexShrink: 0, children: [
|
|
707
|
+
error && /* @__PURE__ */ jsx4(Text5, { color: COLORS.danger, children: error }),
|
|
708
|
+
messages?.map((m, i) => /* @__PURE__ */ jsx4(Text5, { color: COLORS.muted, children: m }, `msg-${i}`)),
|
|
826
709
|
table && /* @__PURE__ */ jsx4(Table, { columns: table.columns, rows: table.rows }),
|
|
827
|
-
/* @__PURE__ */
|
|
828
|
-
question && /* @__PURE__ */ jsx4(
|
|
829
|
-
helpText && /* @__PURE__ */ jsx4(
|
|
710
|
+
/* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
|
|
711
|
+
question && /* @__PURE__ */ jsx4(Text5, { color: COLORS.muted, children: question }),
|
|
712
|
+
helpText && /* @__PURE__ */ jsx4(Text5, { color: COLORS.dim, children: helpText })
|
|
830
713
|
] })
|
|
831
714
|
] }),
|
|
832
715
|
/* @__PURE__ */ jsx4(ScrollView, { scroll, children: visible.map((option, visibleIndex) => {
|
|
@@ -836,39 +719,39 @@ function SelectPrompt({
|
|
|
836
719
|
const bullet = multi && !isCancel ? checked.has(i) ? "\u25CF " : "\u25CB " : "";
|
|
837
720
|
const sec = isCancel ? void 0 : secondary?.[i];
|
|
838
721
|
const labelColor = highlighted ? COLORS.highlight.fg : void 0;
|
|
839
|
-
const label = /* @__PURE__ */
|
|
722
|
+
const label = /* @__PURE__ */ jsxs4(Text5, { color: labelColor, wrap: "truncate", children: [
|
|
840
723
|
highlighted ? "\u276F " : " ",
|
|
841
724
|
bullet,
|
|
842
725
|
option
|
|
843
726
|
] });
|
|
844
727
|
const isText = sec?.kind === "text";
|
|
845
|
-
return /* @__PURE__ */
|
|
846
|
-
|
|
728
|
+
return /* @__PURE__ */ jsxs4(
|
|
729
|
+
Box5,
|
|
847
730
|
{
|
|
848
731
|
width: isText ? "100%" : barWidth,
|
|
849
732
|
paddingX: 1,
|
|
850
733
|
paddingY: 1,
|
|
851
734
|
backgroundColor: highlighted ? COLORS.highlight.bg : void 0,
|
|
852
735
|
children: [
|
|
853
|
-
/* @__PURE__ */ jsx4(
|
|
854
|
-
isText && textWidth > 0 && /* @__PURE__ */ jsx4(
|
|
855
|
-
|
|
736
|
+
/* @__PURE__ */ jsx4(Box5, { width: isText ? labelWidth : barLabelWidth, children: label }),
|
|
737
|
+
isText && textWidth > 0 && /* @__PURE__ */ jsx4(Box5, { width: textWidth, children: /* @__PURE__ */ jsx4(
|
|
738
|
+
Text5,
|
|
856
739
|
{
|
|
857
740
|
wrap: "truncate",
|
|
858
741
|
color: highlighted ? COLORS.primary : COLORS.muted,
|
|
859
742
|
children: sec.value
|
|
860
743
|
}
|
|
861
744
|
) }),
|
|
862
|
-
sec?.kind === "badge" && /* @__PURE__ */ jsx4(
|
|
745
|
+
sec?.kind === "badge" && /* @__PURE__ */ jsx4(Box5, { width: badgeWidth, justifyContent: "flex-end", children: /* @__PURE__ */ jsx4(Text5, { color: COLORS.badge, wrap: "truncate", children: sec.value }) })
|
|
863
746
|
]
|
|
864
747
|
},
|
|
865
748
|
`row-${i}`
|
|
866
749
|
);
|
|
867
750
|
}) }),
|
|
868
|
-
/* @__PURE__ */ jsx4(
|
|
751
|
+
/* @__PURE__ */ jsx4(Box5, { flexShrink: 0, children: /* @__PURE__ */ jsx4(Text5, { children: hints.map(({ key, label }, i) => /* @__PURE__ */ jsxs4(Text5, { children: [
|
|
869
752
|
i > 0 ? " " : "",
|
|
870
|
-
/* @__PURE__ */ jsx4(
|
|
871
|
-
/* @__PURE__ */
|
|
753
|
+
/* @__PURE__ */ jsx4(Text5, { color: COLORS.primary, children: key }),
|
|
754
|
+
/* @__PURE__ */ jsxs4(Text5, { color: COLORS.dim, children: [
|
|
872
755
|
" ",
|
|
873
756
|
label
|
|
874
757
|
] })
|
|
@@ -877,7 +760,7 @@ function SelectPrompt({
|
|
|
877
760
|
}
|
|
878
761
|
|
|
879
762
|
// src/ui/PromptInput.tsx
|
|
880
|
-
import { jsx as jsx5, jsxs as
|
|
763
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
881
764
|
var ACCEPT_REJECT_OPTIONS = ["Accept", "Reject"];
|
|
882
765
|
function EnterToContinuePrompt({
|
|
883
766
|
question,
|
|
@@ -888,10 +771,10 @@ function EnterToContinuePrompt({
|
|
|
888
771
|
if (key.return) onDecide(true);
|
|
889
772
|
else if (key.escape) onDecide(false);
|
|
890
773
|
});
|
|
891
|
-
return /* @__PURE__ */
|
|
892
|
-
messages?.map((m, i) => /* @__PURE__ */ jsx5(
|
|
893
|
-
question && /* @__PURE__ */ jsx5(
|
|
894
|
-
/* @__PURE__ */
|
|
774
|
+
return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", gap: 1, children: [
|
|
775
|
+
messages?.map((m, i) => /* @__PURE__ */ jsx5(Text6, { color: COLORS.muted, children: m }, `msg-${i}`)),
|
|
776
|
+
question && /* @__PURE__ */ jsx5(Text6, { color: COLORS.primary, children: question }),
|
|
777
|
+
/* @__PURE__ */ jsxs5(Box6, { gap: 1, flexDirection: "column", children: [
|
|
895
778
|
/* @__PURE__ */ jsx5(NextAction, { action: "continue", keyHint: "enter" }),
|
|
896
779
|
/* @__PURE__ */ jsx5(NextAction, { action: "decline", keyHint: "esc", hierarchy: "secondary" })
|
|
897
780
|
] })
|
|
@@ -901,11 +784,11 @@ function PromptInput() {
|
|
|
901
784
|
const { phase, inputReq, submitInput } = useWizard();
|
|
902
785
|
const [draft, setDraft] = useState5("");
|
|
903
786
|
if (phase === "done" || phase === "error") {
|
|
904
|
-
return /* @__PURE__ */ jsx5(
|
|
787
|
+
return /* @__PURE__ */ jsx5(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text6, { color: "gray", dimColor: true, children: "Press Enter or Esc to exit" }) });
|
|
905
788
|
}
|
|
906
789
|
if (phase !== "awaitingInput" || !inputReq) return null;
|
|
907
790
|
if (inputReq.promptType === "multipleChoice") {
|
|
908
|
-
return /* @__PURE__ */ jsx5(
|
|
791
|
+
return /* @__PURE__ */ jsx5(Box6, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
|
|
909
792
|
SelectPrompt,
|
|
910
793
|
{
|
|
911
794
|
question: inputReq.prompt,
|
|
@@ -922,7 +805,7 @@ function PromptInput() {
|
|
|
922
805
|
) });
|
|
923
806
|
}
|
|
924
807
|
if (inputReq.promptType === "multiSelect") {
|
|
925
|
-
return /* @__PURE__ */ jsx5(
|
|
808
|
+
return /* @__PURE__ */ jsx5(Box6, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
|
|
926
809
|
SelectPrompt,
|
|
927
810
|
{
|
|
928
811
|
multi: true,
|
|
@@ -937,7 +820,7 @@ function PromptInput() {
|
|
|
937
820
|
) });
|
|
938
821
|
}
|
|
939
822
|
if (inputReq.promptType === "notice") {
|
|
940
|
-
return /* @__PURE__ */ jsx5(
|
|
823
|
+
return /* @__PURE__ */ jsx5(Box6, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
|
|
941
824
|
SelectPrompt,
|
|
942
825
|
{
|
|
943
826
|
question: inputReq.prompt,
|
|
@@ -959,7 +842,7 @@ function PromptInput() {
|
|
|
959
842
|
}
|
|
960
843
|
if (inputReq.promptType === "acceptReject") {
|
|
961
844
|
const labels = inputReq.options?.length ? inputReq.options : ACCEPT_REJECT_OPTIONS;
|
|
962
|
-
return /* @__PURE__ */ jsx5(
|
|
845
|
+
return /* @__PURE__ */ jsx5(Box6, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
|
|
963
846
|
SelectPrompt,
|
|
964
847
|
{
|
|
965
848
|
question: inputReq.prompt,
|
|
@@ -970,11 +853,11 @@ function PromptInput() {
|
|
|
970
853
|
}
|
|
971
854
|
) });
|
|
972
855
|
}
|
|
973
|
-
return /* @__PURE__ */
|
|
974
|
-
inputReq.error && /* @__PURE__ */ jsx5(
|
|
975
|
-
inputReq.messages?.map((m, i) => /* @__PURE__ */ jsx5(
|
|
976
|
-
/* @__PURE__ */
|
|
977
|
-
/* @__PURE__ */
|
|
856
|
+
return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
|
|
857
|
+
inputReq.error && /* @__PURE__ */ jsx5(Text6, { color: COLORS.danger, children: inputReq.error }),
|
|
858
|
+
inputReq.messages?.map((m, i) => /* @__PURE__ */ jsx5(Text6, { color: COLORS.muted, children: m }, `msg-${i}`)),
|
|
859
|
+
/* @__PURE__ */ jsxs5(Box6, { children: [
|
|
860
|
+
/* @__PURE__ */ jsxs5(Text6, { color: COLORS.primary, children: [
|
|
978
861
|
inputReq.prompt,
|
|
979
862
|
" "
|
|
980
863
|
] }),
|
|
@@ -996,7 +879,7 @@ function PromptInput() {
|
|
|
996
879
|
// src/ui/Welcome.tsx
|
|
997
880
|
import { dirname as dirname2, join as join3 } from "node:path";
|
|
998
881
|
import { fileURLToPath } from "node:url";
|
|
999
|
-
import { Box as
|
|
882
|
+
import { Box as Box7, Spacer, Text as Text7, useInput as useInput3, useWindowSize as useWindowSize5 } from "ink";
|
|
1000
883
|
|
|
1001
884
|
// src/ui/copy/welcome.ts
|
|
1002
885
|
var sidebarItems = [
|
|
@@ -1024,27 +907,27 @@ var sidebarItems = [
|
|
|
1024
907
|
|
|
1025
908
|
// src/ui/Welcome.tsx
|
|
1026
909
|
import Image, { InkPictureProvider } from "ink-picture";
|
|
1027
|
-
import { jsx as jsx6, jsxs as
|
|
910
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1028
911
|
var IMAGE_PATH = join3(dirname2(fileURLToPath(import.meta.url)), "algolia.png");
|
|
1029
912
|
function SidebarItem({
|
|
1030
913
|
title,
|
|
1031
914
|
description
|
|
1032
915
|
}) {
|
|
1033
|
-
return /* @__PURE__ */
|
|
1034
|
-
/* @__PURE__ */
|
|
1035
|
-
/* @__PURE__ */ jsx6(
|
|
1036
|
-
/* @__PURE__ */ jsx6(
|
|
916
|
+
return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", children: [
|
|
917
|
+
/* @__PURE__ */ jsxs6(Box7, { gap: 1, children: [
|
|
918
|
+
/* @__PURE__ */ jsx6(Text7, { color: COLORS.success, children: "\u2192" }),
|
|
919
|
+
/* @__PURE__ */ jsx6(Text7, { color: COLORS.strong, bold: true, children: title })
|
|
1037
920
|
] }),
|
|
1038
|
-
/* @__PURE__ */
|
|
921
|
+
/* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", gap: 2, children: [
|
|
1039
922
|
/* @__PURE__ */ jsx6(Spacer, {}),
|
|
1040
|
-
/* @__PURE__ */ jsx6(
|
|
923
|
+
/* @__PURE__ */ jsx6(Text7, { color: COLORS.muted, children: description })
|
|
1041
924
|
] })
|
|
1042
925
|
] });
|
|
1043
926
|
}
|
|
1044
927
|
function Welcome() {
|
|
1045
928
|
const confirmStart = useWizard((s) => s.confirmStart);
|
|
1046
929
|
const openLearnMore = useWizard((s) => s.openLearnMore);
|
|
1047
|
-
const { rows } =
|
|
930
|
+
const { rows } = useWindowSize5();
|
|
1048
931
|
useInput3((input, key) => {
|
|
1049
932
|
if (key.return) confirmStart();
|
|
1050
933
|
else if (input === "i") openLearnMore();
|
|
@@ -1063,15 +946,15 @@ function Welcome() {
|
|
|
1063
946
|
if (rows < 30) {
|
|
1064
947
|
layout = scales["small"];
|
|
1065
948
|
}
|
|
1066
|
-
return /* @__PURE__ */
|
|
949
|
+
return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", justifyContent: "space-between", width: "100%", children: [
|
|
1067
950
|
/* @__PURE__ */ jsx6(
|
|
1068
|
-
|
|
951
|
+
Box7,
|
|
1069
952
|
{
|
|
1070
953
|
paddingY: layout.main.padding.y,
|
|
1071
954
|
paddingX: layout.main.padding.x,
|
|
1072
955
|
flexDirection: "column",
|
|
1073
956
|
justifyContent: "center",
|
|
1074
|
-
children: /* @__PURE__ */
|
|
957
|
+
children: /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", gap: 2, children: [
|
|
1075
958
|
/* @__PURE__ */ jsx6(InkPictureProvider, { children: /* @__PURE__ */ jsx6(
|
|
1076
959
|
Image,
|
|
1077
960
|
{
|
|
@@ -1083,16 +966,16 @@ function Welcome() {
|
|
|
1083
966
|
protocol: "halfBlock"
|
|
1084
967
|
}
|
|
1085
968
|
) }),
|
|
1086
|
-
/* @__PURE__ */ jsx6(
|
|
1087
|
-
/* @__PURE__ */
|
|
969
|
+
/* @__PURE__ */ jsx6(Text7, { color: COLORS.muted, children: "\u2726 From zero \u2192 working search in ~10 minutes" }),
|
|
970
|
+
/* @__PURE__ */ jsxs6(Box7, { gap: 1, flexDirection: "column", children: [
|
|
1088
971
|
/* @__PURE__ */ jsx6(NextAction, { action: "start wizard", keyHint: "enter" }),
|
|
1089
972
|
/* @__PURE__ */ jsx6(NextAction, { action: "learn more", keyHint: "i", hierarchy: "secondary" })
|
|
1090
973
|
] })
|
|
1091
974
|
] })
|
|
1092
975
|
}
|
|
1093
976
|
),
|
|
1094
|
-
/* @__PURE__ */
|
|
1095
|
-
|
|
977
|
+
/* @__PURE__ */ jsxs6(
|
|
978
|
+
Box7,
|
|
1096
979
|
{
|
|
1097
980
|
backgroundColor: COLORS.bg.sidebar,
|
|
1098
981
|
width: 40,
|
|
@@ -1102,7 +985,7 @@ function Welcome() {
|
|
|
1102
985
|
flexDirection: "column",
|
|
1103
986
|
justifyContent: "center",
|
|
1104
987
|
children: [
|
|
1105
|
-
/* @__PURE__ */ jsx6(
|
|
988
|
+
/* @__PURE__ */ jsx6(Text7, { color: COLORS.muted, children: "WHAT THIS WIZARD WILL DO" }),
|
|
1106
989
|
sidebarItems.map((i, idx) => /* @__PURE__ */ jsx6(SidebarItem, { title: i.title, description: i.description }, idx))
|
|
1107
990
|
]
|
|
1108
991
|
}
|
|
@@ -1112,7 +995,7 @@ function Welcome() {
|
|
|
1112
995
|
|
|
1113
996
|
// src/ui/LearnMore.tsx
|
|
1114
997
|
import { Fragment as Fragment2 } from "react";
|
|
1115
|
-
import { Box as
|
|
998
|
+
import { Box as Box8, Text as Text8, useInput as useInput4, useWindowSize as useWindowSize6 } from "ink";
|
|
1116
999
|
|
|
1117
1000
|
// src/ui/copy/learn-more.ts
|
|
1118
1001
|
var accessIntro = "Everything runs locally on your machine. Nothing is written or sent without an explicit yes from you.";
|
|
@@ -1149,7 +1032,7 @@ var policyLinks = [
|
|
|
1149
1032
|
];
|
|
1150
1033
|
|
|
1151
1034
|
// src/ui/LearnMore.tsx
|
|
1152
|
-
import { jsx as jsx7, jsxs as
|
|
1035
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1153
1036
|
var TAG_COLORS = {
|
|
1154
1037
|
READ: COLORS.success,
|
|
1155
1038
|
WRITE: COLORS.badge,
|
|
@@ -1165,25 +1048,25 @@ function NeverLine({
|
|
|
1165
1048
|
}) {
|
|
1166
1049
|
const used = segments.reduce((n, s) => n + s.text.length, 0);
|
|
1167
1050
|
const rightPad = Math.max(0, width - 2 - NEVER_BOX_PAD_X - used);
|
|
1168
|
-
return /* @__PURE__ */
|
|
1169
|
-
/* @__PURE__ */ jsx7(
|
|
1051
|
+
return /* @__PURE__ */ jsxs7(Text8, { children: [
|
|
1052
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.danger, children: "\u2502" }),
|
|
1170
1053
|
" ".repeat(NEVER_BOX_PAD_X),
|
|
1171
|
-
segments.map((s, i) => /* @__PURE__ */ jsx7(
|
|
1054
|
+
segments.map((s, i) => /* @__PURE__ */ jsx7(Text8, { color: s.color, bold: s.bold, children: s.text }, i)),
|
|
1172
1055
|
" ".repeat(rightPad),
|
|
1173
|
-
/* @__PURE__ */ jsx7(
|
|
1056
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.danger, children: "\u2502" })
|
|
1174
1057
|
] });
|
|
1175
1058
|
}
|
|
1176
1059
|
function LearnMore() {
|
|
1177
1060
|
const confirmStart = useWizard((s) => s.confirmStart);
|
|
1178
1061
|
const backToHome = useWizard((s) => s.backToHome);
|
|
1179
|
-
const { columns } =
|
|
1062
|
+
const { columns } = useWindowSize6();
|
|
1180
1063
|
const dividerWidth = Math.max(0, columns - PADDING_X * 2);
|
|
1181
1064
|
useInput4((_input, key) => {
|
|
1182
1065
|
if (key.escape) backToHome();
|
|
1183
1066
|
else if (key.return) confirmStart();
|
|
1184
1067
|
});
|
|
1185
|
-
return /* @__PURE__ */
|
|
1186
|
-
|
|
1068
|
+
return /* @__PURE__ */ jsxs7(
|
|
1069
|
+
Box8,
|
|
1187
1070
|
{
|
|
1188
1071
|
flexDirection: "column",
|
|
1189
1072
|
paddingX: PADDING_X,
|
|
@@ -1191,20 +1074,20 @@ function LearnMore() {
|
|
|
1191
1074
|
width: "100%",
|
|
1192
1075
|
gap: 1,
|
|
1193
1076
|
children: [
|
|
1194
|
-
/* @__PURE__ */ jsx7(
|
|
1195
|
-
/* @__PURE__ */ jsx7(
|
|
1196
|
-
/* @__PURE__ */ jsx7(
|
|
1197
|
-
/* @__PURE__ */ jsx7(
|
|
1198
|
-
/* @__PURE__ */
|
|
1199
|
-
/* @__PURE__ */ jsx7(
|
|
1200
|
-
/* @__PURE__ */ jsx7(
|
|
1201
|
-
/* @__PURE__ */ jsx7(
|
|
1202
|
-
/* @__PURE__ */ jsx7(
|
|
1077
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.strong, bold: true, children: "What algolia wizard accesses" }),
|
|
1078
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: accessIntro }),
|
|
1079
|
+
/* @__PURE__ */ jsx7(Box8, { flexDirection: "column", children: accessItems.map((item) => /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", marginTop: 1, children: [
|
|
1080
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.border, children: "\u2500".repeat(dividerWidth) }),
|
|
1081
|
+
/* @__PURE__ */ jsxs7(Box8, { flexDirection: "row", gap: 1, marginTop: 1, children: [
|
|
1082
|
+
/* @__PURE__ */ jsx7(Box8, { width: TAG_COLUMN_WIDTH, flexShrink: 0, children: /* @__PURE__ */ jsx7(Text8, { color: TAG_COLORS[item.tag], bold: true, children: `[${item.tag}]` }) }),
|
|
1083
|
+
/* @__PURE__ */ jsx7(Box8, { flexDirection: "column", children: /* @__PURE__ */ jsxs7(Text8, { children: [
|
|
1084
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.strong, bold: true, children: item.title }),
|
|
1085
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: ` \u2014 ${item.description}` })
|
|
1203
1086
|
] }) })
|
|
1204
1087
|
] })
|
|
1205
1088
|
] }, item.tag)) }),
|
|
1206
|
-
/* @__PURE__ */
|
|
1207
|
-
/* @__PURE__ */ jsx7(
|
|
1089
|
+
/* @__PURE__ */ jsxs7(Box8, { marginTop: 1, flexDirection: "column", children: [
|
|
1090
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.danger, children: `\u256D${"\u2500".repeat(Math.max(0, dividerWidth - 2))}\u256E` }),
|
|
1208
1091
|
/* @__PURE__ */ jsx7(NeverLine, { width: dividerWidth }),
|
|
1209
1092
|
/* @__PURE__ */ jsx7(
|
|
1210
1093
|
NeverLine,
|
|
@@ -1213,7 +1096,7 @@ function LearnMore() {
|
|
|
1213
1096
|
segments: [{ text: "I NEVER", color: COLORS.danger, bold: true }]
|
|
1214
1097
|
}
|
|
1215
1098
|
),
|
|
1216
|
-
neverItems.map((item) => /* @__PURE__ */
|
|
1099
|
+
neverItems.map((item) => /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
1217
1100
|
/* @__PURE__ */ jsx7(NeverLine, { width: dividerWidth }),
|
|
1218
1101
|
/* @__PURE__ */ jsx7(
|
|
1219
1102
|
NeverLine,
|
|
@@ -1228,23 +1111,23 @@ function LearnMore() {
|
|
|
1228
1111
|
)
|
|
1229
1112
|
] }, item)),
|
|
1230
1113
|
/* @__PURE__ */ jsx7(NeverLine, { width: dividerWidth }),
|
|
1231
|
-
/* @__PURE__ */ jsx7(
|
|
1114
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.danger, children: `\u2570${"\u2500".repeat(Math.max(0, dividerWidth - 2))}\u256F` })
|
|
1232
1115
|
] }),
|
|
1233
|
-
/* @__PURE__ */ jsx7(
|
|
1234
|
-
/* @__PURE__ */ jsx7(
|
|
1235
|
-
/* @__PURE__ */ jsx7(
|
|
1116
|
+
/* @__PURE__ */ jsx7(Box8, { marginTop: 1, flexDirection: "column", children: policyLinks.map((link) => /* @__PURE__ */ jsxs7(Box8, { flexDirection: "row", gap: 1, children: [
|
|
1117
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.strong, bold: true, children: `${link.label}:` }),
|
|
1118
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.accent, children: link.url })
|
|
1236
1119
|
] }, link.label)) }),
|
|
1237
|
-
/* @__PURE__ */
|
|
1238
|
-
/* @__PURE__ */
|
|
1239
|
-
/* @__PURE__ */ jsx7(
|
|
1240
|
-
/* @__PURE__ */ jsx7(
|
|
1241
|
-
/* @__PURE__ */ jsx7(
|
|
1120
|
+
/* @__PURE__ */ jsxs7(Box8, { marginTop: 1, flexDirection: "row", gap: 3, children: [
|
|
1121
|
+
/* @__PURE__ */ jsxs7(Box8, { flexDirection: "row", gap: 1, children: [
|
|
1122
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: "[" }),
|
|
1123
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.primary, children: "esc" }),
|
|
1124
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: "] back" })
|
|
1242
1125
|
] }),
|
|
1243
|
-
/* @__PURE__ */
|
|
1244
|
-
/* @__PURE__ */ jsx7(
|
|
1245
|
-
/* @__PURE__ */ jsx7(
|
|
1246
|
-
/* @__PURE__ */ jsx7(
|
|
1247
|
-
/* @__PURE__ */ jsx7(
|
|
1126
|
+
/* @__PURE__ */ jsxs7(Box8, { flexDirection: "row", gap: 1, children: [
|
|
1127
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: "[" }),
|
|
1128
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.primary, children: "enter" }),
|
|
1129
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.muted, children: "]" }),
|
|
1130
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.success, bold: true, children: "start wizard" })
|
|
1248
1131
|
] })
|
|
1249
1132
|
] })
|
|
1250
1133
|
]
|
|
@@ -1253,10 +1136,10 @@ function LearnMore() {
|
|
|
1253
1136
|
}
|
|
1254
1137
|
|
|
1255
1138
|
// src/ui/Sidebar.tsx
|
|
1256
|
-
import { Box as
|
|
1139
|
+
import { Box as Box11, Text as Text11 } from "ink";
|
|
1257
1140
|
|
|
1258
1141
|
// src/ui/Steps.tsx
|
|
1259
|
-
import { Box as
|
|
1142
|
+
import { Box as Box9, Text as Text9 } from "ink";
|
|
1260
1143
|
import Spinner from "ink-spinner";
|
|
1261
1144
|
|
|
1262
1145
|
// src/core/persistence.ts
|
|
@@ -1285,11 +1168,11 @@ async function clearWorkflowState(workflowId) {
|
|
|
1285
1168
|
}
|
|
1286
1169
|
|
|
1287
1170
|
// src/ui/Steps.tsx
|
|
1288
|
-
import { jsx as jsx8, jsxs as
|
|
1171
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1289
1172
|
function Steps() {
|
|
1290
1173
|
const { steps } = useWizard();
|
|
1291
1174
|
const visibleSteps = steps.filter(isStepVisible);
|
|
1292
|
-
return /* @__PURE__ */ jsx8(
|
|
1175
|
+
return /* @__PURE__ */ jsx8(Box9, { flexDirection: "column", gap: 1, children: visibleSteps.map((s) => /* @__PURE__ */ jsx8(Box9, { flexDirection: "column", children: /* @__PURE__ */ jsxs8(Text9, { color: COLORS.status[s.status], children: [
|
|
1293
1176
|
s.status === "running" ? /* @__PURE__ */ jsx8(Spinner, { type: "dots" }) : MARKER[s.status],
|
|
1294
1177
|
" ",
|
|
1295
1178
|
s.title
|
|
@@ -1299,7 +1182,7 @@ function CurrentStep() {
|
|
|
1299
1182
|
const { steps } = useWizard();
|
|
1300
1183
|
const currentStep = steps.filter(isStepVisible).find((s) => s.status === "running");
|
|
1301
1184
|
if (!currentStep) return null;
|
|
1302
|
-
return /* @__PURE__ */
|
|
1185
|
+
return /* @__PURE__ */ jsxs8(Text9, { color: COLORS.status.running, children: [
|
|
1303
1186
|
/* @__PURE__ */ jsx8(Spinner, { type: "dots" }),
|
|
1304
1187
|
" ",
|
|
1305
1188
|
` ${currentStep.title}`
|
|
@@ -1307,19 +1190,19 @@ function CurrentStep() {
|
|
|
1307
1190
|
}
|
|
1308
1191
|
|
|
1309
1192
|
// src/ui/Progress.tsx
|
|
1310
|
-
import { Box as
|
|
1311
|
-
import { jsx as jsx9, jsxs as
|
|
1193
|
+
import { Box as Box10, Text as Text10 } from "ink";
|
|
1194
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1312
1195
|
function Progress() {
|
|
1313
1196
|
const { steps, currentStepIndex } = useWizard();
|
|
1314
1197
|
const visibleSteps = steps.filter(isStepVisible);
|
|
1315
1198
|
if (visibleSteps.length === 0) return null;
|
|
1316
1199
|
const visibleCountThroughCurrent = steps.slice(0, currentStepIndex + 1).filter(isStepVisible).length;
|
|
1317
1200
|
const activeStepNumber = Math.max(1, visibleCountThroughCurrent);
|
|
1318
|
-
return /* @__PURE__ */
|
|
1319
|
-
/* @__PURE__ */ jsx9(
|
|
1320
|
-
/* @__PURE__ */ jsx9(
|
|
1321
|
-
/* @__PURE__ */ jsx9(
|
|
1322
|
-
/* @__PURE__ */ jsx9(
|
|
1201
|
+
return /* @__PURE__ */ jsxs9(Box10, { flexDirection: "row", gap: 1, children: [
|
|
1202
|
+
/* @__PURE__ */ jsx9(Text10, { color: COLORS.muted, children: "STEP" }),
|
|
1203
|
+
/* @__PURE__ */ jsx9(Text10, { bold: true, children: activeStepNumber }),
|
|
1204
|
+
/* @__PURE__ */ jsx9(Text10, { bold: true, children: "/" }),
|
|
1205
|
+
/* @__PURE__ */ jsx9(Text10, { bold: true, children: visibleSteps.length })
|
|
1323
1206
|
] });
|
|
1324
1207
|
}
|
|
1325
1208
|
|
|
@@ -1330,10 +1213,10 @@ var sidebarCommands = [
|
|
|
1330
1213
|
];
|
|
1331
1214
|
|
|
1332
1215
|
// src/ui/Sidebar.tsx
|
|
1333
|
-
import { jsx as jsx10, jsxs as
|
|
1216
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1334
1217
|
function Sidebar() {
|
|
1335
|
-
return /* @__PURE__ */
|
|
1336
|
-
|
|
1218
|
+
return /* @__PURE__ */ jsxs10(
|
|
1219
|
+
Box11,
|
|
1337
1220
|
{
|
|
1338
1221
|
backgroundColor: "#14171E",
|
|
1339
1222
|
width: 30,
|
|
@@ -1342,16 +1225,16 @@ function Sidebar() {
|
|
|
1342
1225
|
flexDirection: "column",
|
|
1343
1226
|
justifyContent: "space-between",
|
|
1344
1227
|
children: [
|
|
1345
|
-
/* @__PURE__ */
|
|
1346
|
-
/* @__PURE__ */ jsx10(
|
|
1228
|
+
/* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", gap: 1, children: [
|
|
1229
|
+
/* @__PURE__ */ jsx10(Text11, { color: COLORS.muted, children: "PROGRESS" }),
|
|
1347
1230
|
/* @__PURE__ */ jsx10(Steps, {})
|
|
1348
1231
|
] }),
|
|
1349
|
-
/* @__PURE__ */
|
|
1232
|
+
/* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", gap: 1, children: [
|
|
1350
1233
|
/* @__PURE__ */ jsx10(Progress, {}),
|
|
1351
|
-
/* @__PURE__ */ jsx10(
|
|
1352
|
-
return /* @__PURE__ */
|
|
1353
|
-
/* @__PURE__ */ jsx10(
|
|
1354
|
-
/* @__PURE__ */ jsx10(
|
|
1234
|
+
/* @__PURE__ */ jsx10(Box11, { flexDirection: "column", children: sidebarCommands.map((c) => {
|
|
1235
|
+
return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "row", gap: 1, children: [
|
|
1236
|
+
/* @__PURE__ */ jsx10(Text11, { color: COLORS.primary, children: `[${c.keyHint}]` }),
|
|
1237
|
+
/* @__PURE__ */ jsx10(Text11, { color: COLORS.muted, children: c.description })
|
|
1355
1238
|
] });
|
|
1356
1239
|
}) })
|
|
1357
1240
|
] })
|
|
@@ -1361,12 +1244,12 @@ function Sidebar() {
|
|
|
1361
1244
|
}
|
|
1362
1245
|
|
|
1363
1246
|
// src/ui/Ribbon.tsx
|
|
1364
|
-
import { Box as
|
|
1365
|
-
import { jsx as jsx11, jsxs as
|
|
1247
|
+
import { Box as Box12, Text as Text12 } from "ink";
|
|
1248
|
+
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1366
1249
|
function Ribbon() {
|
|
1367
1250
|
const firstCommand = sidebarCommands[0];
|
|
1368
|
-
return /* @__PURE__ */
|
|
1369
|
-
|
|
1251
|
+
return /* @__PURE__ */ jsxs11(
|
|
1252
|
+
Box12,
|
|
1370
1253
|
{
|
|
1371
1254
|
backgroundColor: "#14171E",
|
|
1372
1255
|
flexDirection: "row",
|
|
@@ -1376,9 +1259,9 @@ function Ribbon() {
|
|
|
1376
1259
|
children: [
|
|
1377
1260
|
/* @__PURE__ */ jsx11(Progress, {}),
|
|
1378
1261
|
/* @__PURE__ */ jsx11(CurrentStep, {}),
|
|
1379
|
-
/* @__PURE__ */
|
|
1380
|
-
/* @__PURE__ */ jsx11(
|
|
1381
|
-
/* @__PURE__ */ jsx11(
|
|
1262
|
+
/* @__PURE__ */ jsxs11(Box12, { flexDirection: "row", gap: 1, children: [
|
|
1263
|
+
/* @__PURE__ */ jsx11(Text12, { color: COLORS.primary, children: `[${firstCommand.keyHint}]` }),
|
|
1264
|
+
/* @__PURE__ */ jsx11(Text12, { color: COLORS.muted, children: firstCommand.description })
|
|
1382
1265
|
] })
|
|
1383
1266
|
]
|
|
1384
1267
|
}
|
|
@@ -1389,8 +1272,8 @@ function Ribbon() {
|
|
|
1389
1272
|
import { useState as useState6 } from "react";
|
|
1390
1273
|
|
|
1391
1274
|
// src/ui/Logs.tsx
|
|
1392
|
-
import { Box as
|
|
1393
|
-
import { jsx as jsx12, jsxs as
|
|
1275
|
+
import { Box as Box13, Text as Text13, useInput as useInput5 } from "ink";
|
|
1276
|
+
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1394
1277
|
var KIND_COLOR = {
|
|
1395
1278
|
tool: COLORS.primary,
|
|
1396
1279
|
prompt: COLORS.badge
|
|
@@ -1426,8 +1309,8 @@ function Logs() {
|
|
|
1426
1309
|
else if (key.downArrow) scroll.scrollBy(1);
|
|
1427
1310
|
});
|
|
1428
1311
|
const visible = logs.slice(scroll.offset, scroll.offset + scroll.capacity);
|
|
1429
|
-
return /* @__PURE__ */
|
|
1430
|
-
logs.length === 0 && /* @__PURE__ */ jsx12(
|
|
1312
|
+
return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", paddingX: 4, paddingY: 2, flexGrow: 1, children: [
|
|
1313
|
+
logs.length === 0 && /* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, children: "No logs yet." }),
|
|
1431
1314
|
/* @__PURE__ */ jsx12(ScrollView, { scroll, children: visible.map((entry) => {
|
|
1432
1315
|
const timestamp = `[${formatTimestamp(entry.startedAt)}]`;
|
|
1433
1316
|
const durationText = entry.kind === "tool" && entry.durationMs !== void 0 ? `${entry.durationMs}ms` : "";
|
|
@@ -1438,14 +1321,14 @@ function Logs() {
|
|
|
1438
1321
|
const name = truncate2(entry.name, budget);
|
|
1439
1322
|
budget -= name.length;
|
|
1440
1323
|
const preview = rawPreview ? truncate2(rawPreview, budget) : "";
|
|
1441
|
-
return /* @__PURE__ */
|
|
1442
|
-
/* @__PURE__ */ jsx12(
|
|
1443
|
-
/* @__PURE__ */ jsx12(
|
|
1444
|
-
preview && /* @__PURE__ */ jsx12(
|
|
1445
|
-
durationText && /* @__PURE__ */ jsx12(
|
|
1324
|
+
return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "row", gap: ROW_GAP, children: [
|
|
1325
|
+
/* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, children: timestamp }),
|
|
1326
|
+
/* @__PURE__ */ jsx12(Text13, { color: logNameColor(entry), wrap: "truncate", children: name }),
|
|
1327
|
+
preview && /* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, wrap: "truncate", children: preview }),
|
|
1328
|
+
durationText && /* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, children: durationText })
|
|
1446
1329
|
] }, entry.id);
|
|
1447
1330
|
}) }),
|
|
1448
|
-
/* @__PURE__ */ jsx12(
|
|
1331
|
+
/* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, children: "\u2191/\u2193 scroll" })
|
|
1449
1332
|
] });
|
|
1450
1333
|
}
|
|
1451
1334
|
|
|
@@ -1637,11 +1520,11 @@ function track(event, payload) {
|
|
|
1637
1520
|
}
|
|
1638
1521
|
|
|
1639
1522
|
// src/ui/App.tsx
|
|
1640
|
-
import { jsx as jsx13, jsxs as
|
|
1523
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1641
1524
|
function App() {
|
|
1642
1525
|
const { phase, error, homeScreen, currentStepIndex, steps, inputReq } = useWizard();
|
|
1643
1526
|
const { exit } = useApp();
|
|
1644
|
-
const { columns, rows } =
|
|
1527
|
+
const { columns, rows } = useWindowSize7();
|
|
1645
1528
|
const [showLogs, setShowLogs] = useState6(false);
|
|
1646
1529
|
const finished = phase === "done" || phase === "error";
|
|
1647
1530
|
const currentStep = steps[currentStepIndex];
|
|
@@ -1654,7 +1537,7 @@ function App() {
|
|
|
1654
1537
|
{ isActive: finished }
|
|
1655
1538
|
);
|
|
1656
1539
|
useInput6((_input, key) => {
|
|
1657
|
-
if (phase === "idle" || phase === "
|
|
1540
|
+
if (phase === "idle" || phase === "preflight") return;
|
|
1658
1541
|
if (key.tab) {
|
|
1659
1542
|
setShowLogs(!showLogs);
|
|
1660
1543
|
track("AI Wizard Interaction", {
|
|
@@ -1664,45 +1547,49 @@ function App() {
|
|
|
1664
1547
|
});
|
|
1665
1548
|
}
|
|
1666
1549
|
});
|
|
1667
|
-
const escOwnedElsewhere = phase === "idle" || phase === "
|
|
1550
|
+
const escOwnedElsewhere = phase === "idle" || phase === "awaitingInput" && inputReq?.promptType === "enterToContinue";
|
|
1668
1551
|
useInput6((_input, key) => {
|
|
1669
1552
|
if (escOwnedElsewhere) return;
|
|
1670
1553
|
if (key.escape) {
|
|
1671
1554
|
track("AI Wizard Interaction", {
|
|
1672
1555
|
context: "global",
|
|
1673
1556
|
key: "esc",
|
|
1557
|
+
// No step is active until `startWorkflow` — report the phase instead.
|
|
1674
1558
|
currentStep: currentStep?.id ?? phase
|
|
1675
1559
|
});
|
|
1676
1560
|
exit();
|
|
1677
1561
|
}
|
|
1678
1562
|
});
|
|
1679
|
-
const mainWindowVisible = phase === "
|
|
1563
|
+
const mainWindowVisible = phase === "running" || phase === "awaitingInput" || phase === "error" || phase === "done";
|
|
1680
1564
|
const flexDirection = columns > 90 ? "row" : "column";
|
|
1681
1565
|
const showSidebar = flexDirection === "row";
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1566
|
+
return /* @__PURE__ */ jsxs13(
|
|
1567
|
+
Box14,
|
|
1568
|
+
{
|
|
1569
|
+
backgroundColor: COLORS.bg.main,
|
|
1570
|
+
flexDirection: "row",
|
|
1571
|
+
width: columns,
|
|
1572
|
+
minHeight: rows,
|
|
1573
|
+
children: [
|
|
1574
|
+
mainWindowVisible && // Ink sizes the root by width only, so without a cap the scrolling
|
|
1575
|
+
// lists in here grow to their content instead of windowing (see
|
|
1576
|
+
// `useScrollWindow`). The home screens below stay uncapped: they are
|
|
1577
|
+
// long static copy that would be clipped rather than windowed.
|
|
1578
|
+
/* @__PURE__ */ jsxs13(
|
|
1579
|
+
Box14,
|
|
1580
|
+
{
|
|
1581
|
+
flexDirection,
|
|
1582
|
+
width: "100%",
|
|
1583
|
+
maxHeight: rows,
|
|
1584
|
+
justifyContent: "space-between",
|
|
1585
|
+
children: [
|
|
1586
|
+
showLogs ? /* @__PURE__ */ jsx13(Logs, {}) : (
|
|
1587
|
+
/* Fill the space the sidebar/ribbon leaves — width beside the
|
|
1588
|
+
sidebar, height above the ribbon. The height matters even
|
|
1589
|
+
stacked: it is what the prompt's scrolling list measures itself
|
|
1590
|
+
against (see SelectPrompt). */
|
|
1591
|
+
/* @__PURE__ */ jsxs13(
|
|
1592
|
+
Box14,
|
|
1706
1593
|
{
|
|
1707
1594
|
flexDirection: "column",
|
|
1708
1595
|
paddingX: 4,
|
|
@@ -1710,29 +1597,24 @@ function App() {
|
|
|
1710
1597
|
width: showSidebar ? 70 : "100%",
|
|
1711
1598
|
flexGrow: 1,
|
|
1712
1599
|
children: [
|
|
1713
|
-
phase === "authenticating" && /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", marginBottom: 1, children: [
|
|
1714
|
-
/* @__PURE__ */ jsx13(Text15, { color: COLORS.strong, bold: true, children: "Signing in to Algolia" }),
|
|
1715
|
-
/* @__PURE__ */ jsx13(Text15, { color: COLORS.muted, children: "A browser window will open \u2014 complete sign-in there." })
|
|
1716
|
-
] }),
|
|
1717
|
-
/* @__PURE__ */ jsx13(CliOutput, {}),
|
|
1718
1600
|
/* @__PURE__ */ jsx13(Notices, {}),
|
|
1719
1601
|
/* @__PURE__ */ jsx13(PromptInput, {}),
|
|
1720
|
-
phase === "running" && showSidebar && /* @__PURE__ */ jsx13(
|
|
1721
|
-
phase === "error" && error && /* @__PURE__ */ jsx13(
|
|
1602
|
+
phase === "running" && showSidebar && /* @__PURE__ */ jsx13(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx13(CurrentStep, {}) }),
|
|
1603
|
+
phase === "error" && error && /* @__PURE__ */ jsx13(Box14, { marginTop: 1, children: /* @__PURE__ */ jsxs13(Text14, { color: COLORS.status.error, children: [
|
|
1722
1604
|
"\u2716 ",
|
|
1723
1605
|
error
|
|
1724
1606
|
] }) })
|
|
1725
1607
|
]
|
|
1726
1608
|
}
|
|
1727
|
-
)
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1609
|
+
)
|
|
1610
|
+
),
|
|
1611
|
+
showSidebar ? /* @__PURE__ */ jsx13(Sidebar, {}) : /* @__PURE__ */ jsx13(Ribbon, {})
|
|
1612
|
+
]
|
|
1613
|
+
}
|
|
1614
|
+
),
|
|
1615
|
+
(phase === "idle" || phase === "preflight") && (homeScreen === "learnMore" ? /* @__PURE__ */ jsx13(LearnMore, {}) : /* @__PURE__ */ jsx13(Welcome, {}))
|
|
1616
|
+
]
|
|
1617
|
+
}
|
|
1736
1618
|
);
|
|
1737
1619
|
}
|
|
1738
1620
|
|
|
@@ -1968,138 +1850,61 @@ async function runWorkflow(workflow, appId) {
|
|
|
1968
1850
|
}
|
|
1969
1851
|
}
|
|
1970
1852
|
|
|
1971
|
-
// src/lib/
|
|
1972
|
-
import {
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
);
|
|
1985
|
-
async function currentApplication() {
|
|
1986
|
-
let raw;
|
|
1853
|
+
// src/lib/algoliaProfile.ts
|
|
1854
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
1855
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
1856
|
+
import { homedir as homedir2 } from "node:os";
|
|
1857
|
+
import { join as join6 } from "node:path";
|
|
1858
|
+
import { parse as parseToml } from "toml";
|
|
1859
|
+
var require3 = createRequire2(import.meta.url);
|
|
1860
|
+
function configPath() {
|
|
1861
|
+
const base = process.env.XDG_CONFIG_HOME || join6(homedir2(), ".config");
|
|
1862
|
+
return join6(base, "algolia", "config.toml");
|
|
1863
|
+
}
|
|
1864
|
+
function profilesFromConfig(tomlText) {
|
|
1865
|
+
let parsed;
|
|
1987
1866
|
try {
|
|
1988
|
-
|
|
1867
|
+
parsed = parseToml(tomlText);
|
|
1989
1868
|
} catch {
|
|
1990
|
-
return
|
|
1869
|
+
return [];
|
|
1991
1870
|
}
|
|
1992
|
-
const
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
}
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
const raw = await runAlgoliaCli(["application", "list", "-o", "json"]);
|
|
2006
|
-
const parsed = listSchema.safeParse(parseJson(raw));
|
|
2007
|
-
if (!parsed.success) {
|
|
2008
|
-
throw new Error("Could not read the list of Algolia applications.");
|
|
2009
|
-
}
|
|
2010
|
-
return parsed.data;
|
|
2011
|
-
}
|
|
2012
|
-
async function selectApplication(id) {
|
|
2013
|
-
const raw = await runAlgoliaCli(
|
|
2014
|
-
["application", "select", "--non-interactive", "--app-id", id],
|
|
2015
|
-
{ onOutput: stderrSink }
|
|
2016
|
-
);
|
|
2017
|
-
const parsed = applicationSchema.safeParse(parseJson(raw));
|
|
2018
|
-
if (!parsed.success) {
|
|
2019
|
-
throw new Error(
|
|
2020
|
-
`Selected application ${id}, but the Algolia CLI returned an unreadable result.`
|
|
2021
|
-
);
|
|
2022
|
-
}
|
|
2023
|
-
return parsed.data;
|
|
2024
|
-
}
|
|
2025
|
-
function parseJson(text) {
|
|
1871
|
+
const profiles = Object.entries(parsed).filter(
|
|
1872
|
+
([, t]) => typeof t.application_id === "string" && typeof t.api_key === "string"
|
|
1873
|
+
).map(([name, t]) => ({
|
|
1874
|
+
name,
|
|
1875
|
+
appId: t.application_id,
|
|
1876
|
+
apiKey: t.api_key,
|
|
1877
|
+
isDefault: t.default === true
|
|
1878
|
+
}));
|
|
1879
|
+
profiles.sort((a, b) => Number(b.isDefault) - Number(a.isDefault));
|
|
1880
|
+
return profiles.map(({ name, appId, apiKey }) => ({ name, appId, apiKey }));
|
|
1881
|
+
}
|
|
1882
|
+
async function loadActiveProfile() {
|
|
1883
|
+
let profiles;
|
|
2026
1884
|
try {
|
|
2027
|
-
|
|
1885
|
+
profiles = profilesFromConfig(await readFile3(configPath(), "utf8"));
|
|
2028
1886
|
} catch {
|
|
2029
|
-
|
|
1887
|
+
profiles = [];
|
|
2030
1888
|
}
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
// src/lib/algoliaAppPicker.ts
|
|
2034
|
-
function secondaryFor(app) {
|
|
2035
|
-
return app.plan ? { kind: "badge", value: app.plan } : void 0;
|
|
2036
|
-
}
|
|
2037
|
-
function labelFor(app) {
|
|
2038
|
-
return app.name.trim() ? `${app.name} \u2014 ${app.id}` : app.id;
|
|
2039
|
-
}
|
|
2040
|
-
function selectAndReport(app) {
|
|
2041
|
-
useWizard.getState().pushCliOutput(
|
|
2042
|
-
"stdout",
|
|
2043
|
-
`Selecting ${labelFor(app)} \u2014 provisioning its API key\u2026`
|
|
2044
|
-
);
|
|
2045
|
-
return selectApplication(app.id);
|
|
2046
|
-
}
|
|
2047
|
-
async function promptForApplication() {
|
|
2048
|
-
const store = useWizard.getState();
|
|
2049
|
-
const apps = await listApplications();
|
|
2050
|
-
if (apps.length === 0) {
|
|
1889
|
+
const profile = profiles[0];
|
|
1890
|
+
if (!profile) {
|
|
2051
1891
|
throw new Error(
|
|
2052
|
-
"
|
|
2053
|
-
);
|
|
2054
|
-
}
|
|
2055
|
-
if (apps.length === 1) {
|
|
2056
|
-
const only = apps[0];
|
|
2057
|
-
logger.info(
|
|
2058
|
-
{ app: only.id },
|
|
2059
|
-
"single application on the account; selecting it"
|
|
1892
|
+
"No Algolia profile is configured. Run `npx @algolia/cli auth login` to authenticate."
|
|
2060
1893
|
);
|
|
2061
|
-
return selectAndReport(only);
|
|
2062
|
-
}
|
|
2063
|
-
const messages = ["Which Algolia application should the wizard work in?"];
|
|
2064
|
-
for (; ; ) {
|
|
2065
|
-
const choice = await store.requestUserInput({
|
|
2066
|
-
prompt: "Select an application",
|
|
2067
|
-
promptType: "multipleChoice",
|
|
2068
|
-
options: apps.map(labelFor),
|
|
2069
|
-
secondary: apps.map(secondaryFor),
|
|
2070
|
-
messages
|
|
2071
|
-
});
|
|
2072
|
-
const chosen = apps.find((app) => labelFor(app) === choice);
|
|
2073
|
-
if (!chosen) {
|
|
2074
|
-
throw new Error("Application picker received an unexpected selection");
|
|
2075
|
-
}
|
|
2076
|
-
try {
|
|
2077
|
-
return await selectAndReport(chosen);
|
|
2078
|
-
} catch (err) {
|
|
2079
|
-
logger.warn(
|
|
2080
|
-
{ app: chosen.id, err: err.message },
|
|
2081
|
-
"application select failed; re-prompting"
|
|
2082
|
-
);
|
|
2083
|
-
messages.push(
|
|
2084
|
-
`Could not select \u201C${labelFor(chosen)}\u201D. It may have been removed \u2014 pick another.`
|
|
2085
|
-
);
|
|
2086
|
-
}
|
|
2087
1894
|
}
|
|
2088
|
-
|
|
2089
|
-
async function ensureApplication() {
|
|
2090
|
-
return await currentApplication() ?? await promptForApplication();
|
|
1895
|
+
return profile;
|
|
2091
1896
|
}
|
|
2092
1897
|
|
|
2093
1898
|
// src/workflows/default.ts
|
|
2094
|
-
import { z as
|
|
1899
|
+
import { z as z25 } from "zod";
|
|
2095
1900
|
|
|
2096
1901
|
// src/actions/listIndices.ts
|
|
2097
|
-
import { z as
|
|
2098
|
-
var indicesListSchema =
|
|
2099
|
-
items:
|
|
2100
|
-
|
|
2101
|
-
name:
|
|
2102
|
-
entries:
|
|
1902
|
+
import { z as z3 } from "zod";
|
|
1903
|
+
var indicesListSchema = z3.object({
|
|
1904
|
+
items: z3.array(
|
|
1905
|
+
z3.object({
|
|
1906
|
+
name: z3.string(),
|
|
1907
|
+
entries: z3.number().default(0)
|
|
2103
1908
|
})
|
|
2104
1909
|
)
|
|
2105
1910
|
});
|
|
@@ -2170,12 +1975,12 @@ import "zod";
|
|
|
2170
1975
|
|
|
2171
1976
|
// src/lib/tools/listFiles.ts
|
|
2172
1977
|
import { tool } from "ai";
|
|
2173
|
-
import
|
|
1978
|
+
import z4 from "zod";
|
|
2174
1979
|
import { readdir } from "node:fs/promises";
|
|
2175
1980
|
|
|
2176
1981
|
// src/lib/tools/path.ts
|
|
2177
1982
|
import { lstat } from "node:fs/promises";
|
|
2178
|
-
import { resolve as resolve2, relative, isAbsolute, dirname as dirname3, join as
|
|
1983
|
+
import { resolve as resolve2, relative, isAbsolute, dirname as dirname3, join as join7, sep } from "node:path";
|
|
2179
1984
|
function resolveInRoot(ctx, path) {
|
|
2180
1985
|
const target = resolve2(ctx.cwd, path);
|
|
2181
1986
|
const rel = relative(ctx.root, target);
|
|
@@ -2191,7 +1996,7 @@ async function hasSymlinkParent(ctx, target) {
|
|
|
2191
1996
|
let current = ctx.root;
|
|
2192
1997
|
const parts = relative(ctx.root, dirname3(target)).split(sep).filter(Boolean);
|
|
2193
1998
|
for (const part of parts) {
|
|
2194
|
-
current =
|
|
1999
|
+
current = join7(current, part);
|
|
2195
2000
|
try {
|
|
2196
2001
|
if ((await lstat(current)).isSymbolicLink()) return true;
|
|
2197
2002
|
} catch (err) {
|
|
@@ -2206,7 +2011,7 @@ async function hasSymlinkParent(ctx, target) {
|
|
|
2206
2011
|
function listFilesTool(ctx) {
|
|
2207
2012
|
return tool({
|
|
2208
2013
|
description: "List files in the current working directory",
|
|
2209
|
-
inputSchema:
|
|
2014
|
+
inputSchema: z4.object(),
|
|
2210
2015
|
execute: async () => {
|
|
2211
2016
|
logger.info("called listFiles tool");
|
|
2212
2017
|
if (++ctx.counts.list > ctx.limits.list) {
|
|
@@ -2222,13 +2027,13 @@ function listFilesTool(ctx) {
|
|
|
2222
2027
|
|
|
2223
2028
|
// src/lib/tools/changeDirectory.ts
|
|
2224
2029
|
import { tool as tool2 } from "ai";
|
|
2225
|
-
import
|
|
2030
|
+
import z5 from "zod";
|
|
2226
2031
|
import { stat } from "node:fs/promises";
|
|
2227
2032
|
function changeDirectoryTool(ctx) {
|
|
2228
2033
|
return tool2({
|
|
2229
2034
|
description: "Change the current working directory. Subsequent file operations resolve relative to it. Returns the new working directory.",
|
|
2230
|
-
inputSchema:
|
|
2231
|
-
path:
|
|
2035
|
+
inputSchema: z5.object({
|
|
2036
|
+
path: z5.string().describe("Directory to change into")
|
|
2232
2037
|
}),
|
|
2233
2038
|
execute: async ({ path }) => {
|
|
2234
2039
|
logger.info({ path }, "called changeDirectory tool");
|
|
@@ -2250,13 +2055,13 @@ function changeDirectoryTool(ctx) {
|
|
|
2250
2055
|
|
|
2251
2056
|
// src/lib/tools/reportStatus.ts
|
|
2252
2057
|
import { tool as tool3 } from "ai";
|
|
2253
|
-
import
|
|
2058
|
+
import z6 from "zod";
|
|
2254
2059
|
function reportStatusTool(output) {
|
|
2255
2060
|
return tool3({
|
|
2256
2061
|
description: "Report the status of your execution. Return a reason in case of failure.",
|
|
2257
|
-
inputSchema:
|
|
2258
|
-
status:
|
|
2259
|
-
reason:
|
|
2062
|
+
inputSchema: z6.object({
|
|
2063
|
+
status: z6.enum(["success", "fail"]),
|
|
2064
|
+
reason: z6.string().optional(),
|
|
2260
2065
|
output
|
|
2261
2066
|
}),
|
|
2262
2067
|
execute: async ({ status, reason, output: output2 }) => {
|
|
@@ -2268,8 +2073,8 @@ function reportStatusTool(output) {
|
|
|
2268
2073
|
|
|
2269
2074
|
// src/lib/tools/readFile.ts
|
|
2270
2075
|
import { tool as tool4 } from "ai";
|
|
2271
|
-
import
|
|
2272
|
-
import { readFile as
|
|
2076
|
+
import z7 from "zod";
|
|
2077
|
+
import { readFile as readFile4 } from "node:fs/promises";
|
|
2273
2078
|
|
|
2274
2079
|
// src/lib/tools/env.ts
|
|
2275
2080
|
import { basename } from "node:path";
|
|
@@ -2296,8 +2101,8 @@ function redactEnvValues(content) {
|
|
|
2296
2101
|
function readFileTool(ctx) {
|
|
2297
2102
|
return tool4({
|
|
2298
2103
|
description: "Read the contents of a file at the given path",
|
|
2299
|
-
inputSchema:
|
|
2300
|
-
filePath:
|
|
2104
|
+
inputSchema: z7.object({
|
|
2105
|
+
filePath: z7.string().describe("Path to the file to read")
|
|
2301
2106
|
}),
|
|
2302
2107
|
execute: async ({ filePath }) => {
|
|
2303
2108
|
if (++ctx.counts.read > ctx.limits.read) {
|
|
@@ -2307,7 +2112,7 @@ function readFileTool(ctx) {
|
|
|
2307
2112
|
const resolved = resolveInRoot(ctx, filePath);
|
|
2308
2113
|
if (!resolved.ok) return resolved.error;
|
|
2309
2114
|
try {
|
|
2310
|
-
const content = await
|
|
2115
|
+
const content = await readFile4(resolved.target, "utf8");
|
|
2311
2116
|
return isEnvFile(resolved.target) ? redactEnvValues(content) : content;
|
|
2312
2117
|
} catch (err) {
|
|
2313
2118
|
return `Error reading ${filePath}: ${err.message}`;
|
|
@@ -2318,15 +2123,15 @@ function readFileTool(ctx) {
|
|
|
2318
2123
|
|
|
2319
2124
|
// src/lib/tools/writeFile.ts
|
|
2320
2125
|
import { tool as tool5 } from "ai";
|
|
2321
|
-
import
|
|
2126
|
+
import z8 from "zod";
|
|
2322
2127
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
|
|
2323
2128
|
import { dirname as dirname4 } from "node:path";
|
|
2324
2129
|
function writeFileTool(ctx) {
|
|
2325
2130
|
return tool5({
|
|
2326
2131
|
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.",
|
|
2327
|
-
inputSchema:
|
|
2328
|
-
filePath:
|
|
2329
|
-
content:
|
|
2132
|
+
inputSchema: z8.object({
|
|
2133
|
+
filePath: z8.string().describe("Path to the file to write"),
|
|
2134
|
+
content: z8.string().describe("Content to write to the file")
|
|
2330
2135
|
}),
|
|
2331
2136
|
execute: async ({ filePath, content }) => {
|
|
2332
2137
|
logger.info({ filePath }, "called writeFile tool");
|
|
@@ -2351,95 +2156,9 @@ function writeFileTool(ctx) {
|
|
|
2351
2156
|
|
|
2352
2157
|
// src/lib/tools/writeAlgoliaCredentials.ts
|
|
2353
2158
|
import { tool as tool6 } from "ai";
|
|
2354
|
-
import
|
|
2355
|
-
import { mkdir as mkdir4, readFile as
|
|
2159
|
+
import z9 from "zod";
|
|
2160
|
+
import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile4 } from "node:fs/promises";
|
|
2356
2161
|
import { dirname as dirname5 } from "node:path";
|
|
2357
|
-
|
|
2358
|
-
// src/lib/algoliaApiKey.ts
|
|
2359
|
-
import { z as z11 } from "zod";
|
|
2360
|
-
var SAFE_ACLS = /* @__PURE__ */ new Set(["search", "browse", "listIndexes"]);
|
|
2361
|
-
var WRITE_ACLS = [
|
|
2362
|
-
"addObject",
|
|
2363
|
-
"deleteObject",
|
|
2364
|
-
"settings",
|
|
2365
|
-
"editSettings",
|
|
2366
|
-
"listIndexes"
|
|
2367
|
-
];
|
|
2368
|
-
var WRITE_ACL_SET = new Set(WRITE_ACLS);
|
|
2369
|
-
var apiKeySchema = z11.object({
|
|
2370
|
-
value: z11.string().min(1),
|
|
2371
|
-
acl: z11.array(z11.string()).default([]),
|
|
2372
|
-
indexes: z11.array(z11.string()).default([])
|
|
2373
|
-
});
|
|
2374
|
-
var apiKeyListSchema = z11.object({
|
|
2375
|
-
items: z11.array(apiKeySchema).optional(),
|
|
2376
|
-
keys: z11.array(apiKeySchema).optional()
|
|
2377
|
-
}).transform((o) => o.items ?? o.keys ?? []);
|
|
2378
|
-
var createdKeySchema = z11.object({
|
|
2379
|
-
key: z11.string().min(1).optional(),
|
|
2380
|
-
value: z11.string().min(1).optional()
|
|
2381
|
-
});
|
|
2382
|
-
function canReuse(key, index) {
|
|
2383
|
-
return key.acl.includes("search") && key.acl.every((acl) => SAFE_ACLS.has(acl)) && (key.indexes.length === 0 || key.indexes.includes("*") || key.indexes.includes(index));
|
|
2384
|
-
}
|
|
2385
|
-
async function createSearchKey(index) {
|
|
2386
|
-
const stdout = await runAlgoliaCli([
|
|
2387
|
-
"apikeys",
|
|
2388
|
-
"create",
|
|
2389
|
-
"--indices",
|
|
2390
|
-
index,
|
|
2391
|
-
"--acl",
|
|
2392
|
-
"search,browse",
|
|
2393
|
-
"--description",
|
|
2394
|
-
`wizard search-only key for ${index}`,
|
|
2395
|
-
"-o",
|
|
2396
|
-
"json"
|
|
2397
|
-
]);
|
|
2398
|
-
const { key, value } = createdKeySchema.parse(JSON.parse(stdout));
|
|
2399
|
-
const created = key ?? value;
|
|
2400
|
-
if (!created) throw new Error("apikeys create returned no key value");
|
|
2401
|
-
return created;
|
|
2402
|
-
}
|
|
2403
|
-
function canReuseForWrites(key, index) {
|
|
2404
|
-
return WRITE_ACLS.every((acl) => key.acl.includes(acl)) && key.acl.every((acl) => WRITE_ACL_SET.has(acl)) && key.indexes.includes(index);
|
|
2405
|
-
}
|
|
2406
|
-
async function resolveWriteKey(index) {
|
|
2407
|
-
const stdout = await runAlgoliaCli(["apikeys", "list", "-o", "json"]);
|
|
2408
|
-
const existing = apiKeyListSchema.parse(JSON.parse(stdout)).find((key2) => canReuseForWrites(key2, index))?.value;
|
|
2409
|
-
if (existing) {
|
|
2410
|
-
logger.info({ index }, "reusing existing write API key");
|
|
2411
|
-
return existing;
|
|
2412
|
-
}
|
|
2413
|
-
logger.info({ index }, "no reusable write key found; creating one");
|
|
2414
|
-
const created = await runAlgoliaCli([
|
|
2415
|
-
"apikeys",
|
|
2416
|
-
"create",
|
|
2417
|
-
"--indices",
|
|
2418
|
-
index,
|
|
2419
|
-
"--acl",
|
|
2420
|
-
WRITE_ACLS.join(","),
|
|
2421
|
-
"--description",
|
|
2422
|
-
`wizard write key for ${index}`,
|
|
2423
|
-
"-o",
|
|
2424
|
-
"json"
|
|
2425
|
-
]);
|
|
2426
|
-
const { key, value } = createdKeySchema.parse(JSON.parse(created));
|
|
2427
|
-
const writeKey = key ?? value;
|
|
2428
|
-
if (!writeKey) throw new Error("apikeys create returned no key value");
|
|
2429
|
-
return writeKey;
|
|
2430
|
-
}
|
|
2431
|
-
async function resolveSearchOnlyKey(index) {
|
|
2432
|
-
const stdout = await runAlgoliaCli(["apikeys", "list", "-o", "json"]);
|
|
2433
|
-
const existing = apiKeyListSchema.parse(JSON.parse(stdout)).find((key) => canReuse(key, index))?.value;
|
|
2434
|
-
if (existing) {
|
|
2435
|
-
logger.info({ index }, "reusing existing search-only API key");
|
|
2436
|
-
return existing;
|
|
2437
|
-
}
|
|
2438
|
-
logger.info({ index }, "no reusable search-only key found; creating one");
|
|
2439
|
-
return createSearchKey(index);
|
|
2440
|
-
}
|
|
2441
|
-
|
|
2442
|
-
// src/lib/tools/writeAlgoliaCredentials.ts
|
|
2443
2162
|
var APP_ID_VAR = "ALGOLIA_APPLICATION_ID";
|
|
2444
2163
|
var API_KEY_VAR = "ALGOLIA_WRITE_API_KEY";
|
|
2445
2164
|
function appendEnv(content, entries) {
|
|
@@ -2453,9 +2172,9 @@ function hasEnv(content, name) {
|
|
|
2453
2172
|
}
|
|
2454
2173
|
function writeCredentialsTool(ctx) {
|
|
2455
2174
|
return tool6({
|
|
2456
|
-
description: `Write the active Algolia credentials (${APP_ID_VAR} and ${API_KEY_VAR}) into the given env file. The credentials
|
|
2457
|
-
inputSchema:
|
|
2458
|
-
filePath:
|
|
2175
|
+
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.`,
|
|
2176
|
+
inputSchema: z9.object({
|
|
2177
|
+
filePath: z9.string().describe(
|
|
2459
2178
|
'Path to the env file to write credentials into (e.g. ".env")'
|
|
2460
2179
|
)
|
|
2461
2180
|
}),
|
|
@@ -2463,17 +2182,11 @@ function writeCredentialsTool(ctx) {
|
|
|
2463
2182
|
logger.info({ filePath }, "called writeCredentials tool");
|
|
2464
2183
|
const resolved = resolveInRoot(ctx, filePath);
|
|
2465
2184
|
if (resolved.ok === false) return resolved.error;
|
|
2466
|
-
|
|
2467
|
-
if (!targetIndex) {
|
|
2468
|
-
return "Error: no target index is set for this run, so a scoped write key cannot be provisioned.";
|
|
2469
|
-
}
|
|
2470
|
-
let appId;
|
|
2471
|
-
let writeKey;
|
|
2185
|
+
let profile;
|
|
2472
2186
|
try {
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
return `Error: could not resolve Algolia credentials (${err.message}). Ask the user to authenticate with the Algolia CLI first.`;
|
|
2187
|
+
profile = await loadActiveProfile();
|
|
2188
|
+
} catch {
|
|
2189
|
+
return "Error: no Algolia profile is configured, so credentials cannot be written. Ask the user to authenticate with the Algolia CLI first.";
|
|
2477
2190
|
}
|
|
2478
2191
|
try {
|
|
2479
2192
|
if (await hasSymlinkParent(ctx, resolved.target)) {
|
|
@@ -2481,7 +2194,7 @@ function writeCredentialsTool(ctx) {
|
|
|
2481
2194
|
}
|
|
2482
2195
|
let existing = "";
|
|
2483
2196
|
try {
|
|
2484
|
-
existing = await
|
|
2197
|
+
existing = await readFile5(resolved.target, "utf8");
|
|
2485
2198
|
} catch (err) {
|
|
2486
2199
|
if (err.code !== "ENOENT") throw err;
|
|
2487
2200
|
}
|
|
@@ -2492,8 +2205,8 @@ function writeCredentialsTool(ctx) {
|
|
|
2492
2205
|
return `Skipped: ${filePath} already defines ${present.join(" and ")}. Leaving existing credentials untouched.`;
|
|
2493
2206
|
}
|
|
2494
2207
|
const envWithCredentials = appendEnv(existing, [
|
|
2495
|
-
[APP_ID_VAR, appId],
|
|
2496
|
-
[API_KEY_VAR,
|
|
2208
|
+
[APP_ID_VAR, profile.appId],
|
|
2209
|
+
[API_KEY_VAR, profile.apiKey]
|
|
2497
2210
|
]);
|
|
2498
2211
|
await mkdir4(dirname5(resolved.target), { recursive: true });
|
|
2499
2212
|
await writeFile4(resolved.target, envWithCredentials, "utf8");
|
|
@@ -2507,16 +2220,16 @@ function writeCredentialsTool(ctx) {
|
|
|
2507
2220
|
|
|
2508
2221
|
// src/lib/tools/searchFiles.ts
|
|
2509
2222
|
import { tool as tool7 } from "ai";
|
|
2510
|
-
import
|
|
2511
|
-
import { readdir as readdir2, readFile as
|
|
2512
|
-
import { join as
|
|
2223
|
+
import z10 from "zod";
|
|
2224
|
+
import { readdir as readdir2, readFile as readFile6 } from "node:fs/promises";
|
|
2225
|
+
import { join as join8 } from "node:path";
|
|
2513
2226
|
var MAX_QUERY_LENGTH = 1e3;
|
|
2514
2227
|
async function walkFiles(dir) {
|
|
2515
2228
|
const skip = /* @__PURE__ */ new Set(["node_modules", ".git", "dist"]);
|
|
2516
2229
|
const out = [];
|
|
2517
2230
|
for (const e of await readdir2(dir, { withFileTypes: true })) {
|
|
2518
2231
|
if (e.name.startsWith(".") || skip.has(e.name)) continue;
|
|
2519
|
-
const full =
|
|
2232
|
+
const full = join8(dir, e.name);
|
|
2520
2233
|
if (e.isDirectory()) out.push(...await walkFiles(full));
|
|
2521
2234
|
else if (e.isFile()) out.push(full);
|
|
2522
2235
|
}
|
|
@@ -2525,9 +2238,9 @@ async function walkFiles(dir) {
|
|
|
2525
2238
|
function searchFilesTool(ctx) {
|
|
2526
2239
|
return tool7({
|
|
2527
2240
|
description: "Search file contents for a JavaScript regular expression (RegExp syntax, not grep/PCRE). Returns matching lines as file:line:text.",
|
|
2528
|
-
inputSchema:
|
|
2529
|
-
query:
|
|
2530
|
-
path:
|
|
2241
|
+
inputSchema: z10.object({
|
|
2242
|
+
query: z10.string().describe("JavaScript RegExp pattern to search for"),
|
|
2243
|
+
path: z10.string().optional().describe("Directory to search in (default: cwd)")
|
|
2531
2244
|
}),
|
|
2532
2245
|
execute: async ({ query, path = "." }) => {
|
|
2533
2246
|
logger.info({ query, path }, "called searchFiles tool");
|
|
@@ -2549,7 +2262,7 @@ function searchFilesTool(ctx) {
|
|
|
2549
2262
|
for (const file of await walkFiles(resolved.target)) {
|
|
2550
2263
|
let content;
|
|
2551
2264
|
try {
|
|
2552
|
-
content = await
|
|
2265
|
+
content = await readFile6(file, "utf8");
|
|
2553
2266
|
} catch {
|
|
2554
2267
|
continue;
|
|
2555
2268
|
}
|
|
@@ -2571,31 +2284,63 @@ function searchFilesTool(ctx) {
|
|
|
2571
2284
|
|
|
2572
2285
|
// src/lib/tools/verifyImplementation.ts
|
|
2573
2286
|
import { tool as tool8 } from "ai";
|
|
2574
|
-
import
|
|
2287
|
+
import z11 from "zod";
|
|
2575
2288
|
|
|
2576
2289
|
// src/lib/tools/utils/runCommand.ts
|
|
2577
2290
|
import { spawn as spawn2 } from "node:child_process";
|
|
2578
|
-
|
|
2291
|
+
var INSTALL_TIMEOUT_MS = 15 * 6e4;
|
|
2292
|
+
var INGEST_TIMEOUT_MS = 15 * 6e4;
|
|
2293
|
+
var VERIFY_TIMEOUT_MS = 10 * 6e4;
|
|
2294
|
+
var KILL_GRACE_MS = 5e3;
|
|
2295
|
+
function runCommand(command, args, options = {}) {
|
|
2296
|
+
const { cwd, env, timeoutMs = VERIFY_TIMEOUT_MS } = options;
|
|
2579
2297
|
return new Promise((resolve4) => {
|
|
2580
2298
|
let output = "";
|
|
2299
|
+
let settled = false;
|
|
2581
2300
|
const child = spawn2(command, args, {
|
|
2582
2301
|
cwd,
|
|
2583
|
-
|
|
2302
|
+
shell: false,
|
|
2303
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
2304
|
+
...env ? { env: { ...process.env, ...env } } : {}
|
|
2584
2305
|
});
|
|
2306
|
+
const settle = (result) => {
|
|
2307
|
+
if (settled) return;
|
|
2308
|
+
settled = true;
|
|
2309
|
+
clearTimeout(timer);
|
|
2310
|
+
resolve4(result);
|
|
2311
|
+
};
|
|
2312
|
+
const timer = setTimeout(() => {
|
|
2313
|
+
child.kill("SIGTERM");
|
|
2314
|
+
setTimeout(() => child.kill("SIGKILL"), KILL_GRACE_MS).unref();
|
|
2315
|
+
const seconds = Math.round(timeoutMs / 1e3);
|
|
2316
|
+
settle({
|
|
2317
|
+
code: 1,
|
|
2318
|
+
output: `${output}
|
|
2319
|
+
Timed out after ${seconds}s: ${command} ${args.join(" ")}`.trim(),
|
|
2320
|
+
timedOut: true
|
|
2321
|
+
});
|
|
2322
|
+
}, timeoutMs);
|
|
2585
2323
|
child.stdout?.on("data", (d) => output += d);
|
|
2586
2324
|
child.stderr?.on("data", (d) => output += d);
|
|
2587
2325
|
child.on(
|
|
2588
2326
|
"error",
|
|
2589
|
-
(err) =>
|
|
2327
|
+
(err) => settle({
|
|
2328
|
+
code: 1,
|
|
2329
|
+
output: `Failed to run ${command}: ${err.message}`,
|
|
2330
|
+
timedOut: false
|
|
2331
|
+
})
|
|
2332
|
+
);
|
|
2333
|
+
child.on(
|
|
2334
|
+
"close",
|
|
2335
|
+
(code) => settle({ code: code ?? 1, output, timedOut: false })
|
|
2590
2336
|
);
|
|
2591
|
-
child.on("close", (code) => resolve4({ code: code ?? 1, output }));
|
|
2592
2337
|
});
|
|
2593
2338
|
}
|
|
2594
2339
|
|
|
2595
2340
|
// src/lib/tools/utils/packageManager.ts
|
|
2596
|
-
import { readFile as
|
|
2341
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
2597
2342
|
import { existsSync } from "node:fs";
|
|
2598
|
-
import { join as
|
|
2343
|
+
import { join as join9 } from "node:path";
|
|
2599
2344
|
var LOCKFILES = [
|
|
2600
2345
|
["pnpm-lock.yaml", "pnpm"],
|
|
2601
2346
|
["yarn.lock", "yarn"],
|
|
@@ -2604,13 +2349,13 @@ var LOCKFILES = [
|
|
|
2604
2349
|
["package-lock.json", "npm"]
|
|
2605
2350
|
];
|
|
2606
2351
|
async function readPackageJson(cwd = process.cwd()) {
|
|
2607
|
-
return JSON.parse(await
|
|
2352
|
+
return JSON.parse(await readFile7(join9(cwd, "package.json"), "utf8"));
|
|
2608
2353
|
}
|
|
2609
2354
|
function packageManagerFrom(pkg) {
|
|
2610
2355
|
return pkg.packageManager?.split("@")[0] ?? "npm";
|
|
2611
2356
|
}
|
|
2612
2357
|
function packageManagerFromLockfile(cwd) {
|
|
2613
|
-
return LOCKFILES.find(([file]) => existsSync(
|
|
2358
|
+
return LOCKFILES.find(([file]) => existsSync(join9(cwd, file)))?.[1];
|
|
2614
2359
|
}
|
|
2615
2360
|
async function detectPackageManager(cwd) {
|
|
2616
2361
|
try {
|
|
@@ -2641,7 +2386,9 @@ async function runRepoVerificationCheck() {
|
|
|
2641
2386
|
const checks = [];
|
|
2642
2387
|
for (const script of present) {
|
|
2643
2388
|
const command = `${pm} run ${script}`;
|
|
2644
|
-
const { code, output } = await runCommand(pm, ["run", script]
|
|
2389
|
+
const { code, output } = await runCommand(pm, ["run", script], {
|
|
2390
|
+
timeoutMs: VERIFY_TIMEOUT_MS
|
|
2391
|
+
});
|
|
2645
2392
|
checks.push({ command, exitCode: code, ok: code === 0, output: output.trim() });
|
|
2646
2393
|
}
|
|
2647
2394
|
return { ok: checks.every((c) => c.ok), checks };
|
|
@@ -2651,7 +2398,7 @@ async function runRepoVerificationCheck() {
|
|
|
2651
2398
|
function verifyImplementationTool() {
|
|
2652
2399
|
return tool8({
|
|
2653
2400
|
description: "Run the repo's mechanical verification check for generated implementation changes. Detects lint/typecheck/check from package.json and returns structured pass/fail evidence for the verifier to interpret.",
|
|
2654
|
-
inputSchema:
|
|
2401
|
+
inputSchema: z11.object(),
|
|
2655
2402
|
execute: async () => {
|
|
2656
2403
|
logger.info("called verifyImplementation tool");
|
|
2657
2404
|
return runRepoVerificationCheck();
|
|
@@ -2665,7 +2412,7 @@ import { createAnthropic } from "@ai-sdk/anthropic";
|
|
|
2665
2412
|
import { nanoid as nanoid2 } from "nanoid";
|
|
2666
2413
|
import { mkdir as mkdir5, writeFile as writeFile5 } from "node:fs/promises";
|
|
2667
2414
|
import { dirname as dirname6 } from "node:path";
|
|
2668
|
-
import
|
|
2415
|
+
import z12 from "zod";
|
|
2669
2416
|
var DATA_DIR = ".algolia-wizard/data";
|
|
2670
2417
|
var RECORD_MODEL = "claude-haiku-4-5";
|
|
2671
2418
|
var MAX_RECORDS = 100;
|
|
@@ -2677,17 +2424,17 @@ var anthropic = createAnthropic({
|
|
|
2677
2424
|
function generateRecordTool(ctx) {
|
|
2678
2425
|
return tool9({
|
|
2679
2426
|
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.",
|
|
2680
|
-
inputSchema:
|
|
2681
|
-
entityName:
|
|
2682
|
-
attributes:
|
|
2683
|
-
count:
|
|
2684
|
-
hint:
|
|
2427
|
+
inputSchema: z12.object({
|
|
2428
|
+
entityName: z12.string().describe("Name of the entity to generate records for."),
|
|
2429
|
+
attributes: z12.array(z12.string()).describe("Attribute names each record must contain."),
|
|
2430
|
+
count: z12.number().int().min(1).max(MAX_RECORDS).default(10).describe(`How many records to generate (max ${MAX_RECORDS}).`),
|
|
2431
|
+
hint: z12.string().optional().describe("Optional context to steer realistic values.")
|
|
2685
2432
|
}),
|
|
2686
2433
|
execute: async ({ entityName, attributes, count, hint }) => {
|
|
2687
2434
|
logger.info({ entityName, count }, "called generateRecord tool");
|
|
2688
2435
|
try {
|
|
2689
|
-
const value =
|
|
2690
|
-
const recordSchema =
|
|
2436
|
+
const value = z12.union([z12.string(), z12.number(), z12.boolean(), z12.null()]);
|
|
2437
|
+
const recordSchema = z12.object(
|
|
2691
2438
|
Object.fromEntries(attributes.map((attr) => [attr, value]))
|
|
2692
2439
|
);
|
|
2693
2440
|
const generateBatch = async (batchCount) => {
|
|
@@ -2697,8 +2444,8 @@ function generateRecordTool(ctx) {
|
|
|
2697
2444
|
const { output } = await generateText({
|
|
2698
2445
|
model: anthropic(RECORD_MODEL),
|
|
2699
2446
|
output: Output.object({
|
|
2700
|
-
schema:
|
|
2701
|
-
records:
|
|
2447
|
+
schema: z12.object({
|
|
2448
|
+
records: z12.array(recordSchema).length(batchCount)
|
|
2702
2449
|
})
|
|
2703
2450
|
}),
|
|
2704
2451
|
prompt: [
|
|
@@ -2756,12 +2503,12 @@ function generateRecordTool(ctx) {
|
|
|
2756
2503
|
|
|
2757
2504
|
// src/lib/tools/notifyUser.ts
|
|
2758
2505
|
import { tool as tool10 } from "ai";
|
|
2759
|
-
import
|
|
2506
|
+
import z13 from "zod";
|
|
2760
2507
|
function notifyUserTool() {
|
|
2761
2508
|
return tool10({
|
|
2762
2509
|
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.`,
|
|
2763
|
-
inputSchema:
|
|
2764
|
-
message:
|
|
2510
|
+
inputSchema: z13.object({
|
|
2511
|
+
message: z13.string().describe(
|
|
2765
2512
|
"Short, plain-language description of what you are doing now."
|
|
2766
2513
|
)
|
|
2767
2514
|
}),
|
|
@@ -2941,10 +2688,10 @@ async function runAgent(req) {
|
|
|
2941
2688
|
}
|
|
2942
2689
|
|
|
2943
2690
|
// src/actions/detectLanguage.ts
|
|
2944
|
-
import
|
|
2945
|
-
var detectLanguageSchema =
|
|
2946
|
-
languages:
|
|
2947
|
-
frameworks:
|
|
2691
|
+
import z16 from "zod";
|
|
2692
|
+
var detectLanguageSchema = z16.object({
|
|
2693
|
+
languages: z16.array(z16.object({ name: z16.string(), version: z16.string() })),
|
|
2694
|
+
frameworks: z16.array(z16.object({ name: z16.string(), version: z16.string() }))
|
|
2948
2695
|
});
|
|
2949
2696
|
var detectLanguage = () => runAgent({
|
|
2950
2697
|
instructions: [
|
|
@@ -2962,31 +2709,31 @@ var detectLanguage = () => runAgent({
|
|
|
2962
2709
|
});
|
|
2963
2710
|
|
|
2964
2711
|
// src/actions/analyzeCodebase.ts
|
|
2965
|
-
import
|
|
2712
|
+
import z17 from "zod";
|
|
2966
2713
|
var READONLY_TOOLS = [
|
|
2967
2714
|
"listFiles",
|
|
2968
2715
|
"changeDirectory",
|
|
2969
2716
|
"readFile",
|
|
2970
2717
|
"searchFiles"
|
|
2971
2718
|
];
|
|
2972
|
-
var ingestionAnalysisSchema =
|
|
2973
|
-
ingestionAnalysis:
|
|
2974
|
-
|
|
2975
|
-
name:
|
|
2976
|
-
paths:
|
|
2719
|
+
var ingestionAnalysisSchema = z17.object({
|
|
2720
|
+
ingestionAnalysis: z17.array(
|
|
2721
|
+
z17.object({
|
|
2722
|
+
name: z17.string(),
|
|
2723
|
+
paths: z17.array(z17.string()),
|
|
2977
2724
|
// indexable fields the agent found for this entity
|
|
2978
|
-
attributes:
|
|
2725
|
+
attributes: z17.array(z17.string())
|
|
2979
2726
|
})
|
|
2980
2727
|
)
|
|
2981
2728
|
});
|
|
2982
|
-
var searchImplementationAnalysisSchema =
|
|
2983
|
-
searchImplementationAnalysis:
|
|
2729
|
+
var searchImplementationAnalysisSchema = z17.object({
|
|
2730
|
+
searchImplementationAnalysis: z17.string()
|
|
2984
2731
|
});
|
|
2985
|
-
var verificationSchema =
|
|
2986
|
-
verification:
|
|
2732
|
+
var verificationSchema = z17.object({
|
|
2733
|
+
verification: z17.array(z17.string())
|
|
2987
2734
|
});
|
|
2988
2735
|
var confirmedEntitiesFieldSchema = ingestionAnalysisSchema.shape.ingestionAnalysis.optional();
|
|
2989
|
-
var analyzeCodebaseSchema =
|
|
2736
|
+
var analyzeCodebaseSchema = z17.object({
|
|
2990
2737
|
ingestionAnalysis: ingestionAnalysisSchema.shape.ingestionAnalysis.optional(),
|
|
2991
2738
|
searchImplementationAnalysis: searchImplementationAnalysisSchema.shape.searchImplementationAnalysis.optional(),
|
|
2992
2739
|
verification: verificationSchema.shape.verification.optional(),
|
|
@@ -3048,7 +2795,7 @@ async function runAnalysis(mode, extraInstructions = []) {
|
|
|
3048
2795
|
// package.json
|
|
3049
2796
|
var package_default = {
|
|
3050
2797
|
name: "@algolia/wizard",
|
|
3051
|
-
version: "0.9.0-rc.
|
|
2798
|
+
version: "0.9.0-rc.69.59",
|
|
3052
2799
|
description: "Magically implement Algolia functionality in your codebase",
|
|
3053
2800
|
type: "module",
|
|
3054
2801
|
engines: {
|
|
@@ -3096,6 +2843,7 @@ var package_default = {
|
|
|
3096
2843
|
dependencies: {
|
|
3097
2844
|
"@ai-sdk/anthropic": "^3.0.81",
|
|
3098
2845
|
"@ai-sdk/openai-compatible": "^2.0.47",
|
|
2846
|
+
"@algolia/cli": "^5.11.0",
|
|
3099
2847
|
"@hono/node-server": "^2.0.10",
|
|
3100
2848
|
"@mishieck/ink-titled-box": "^0.4.2",
|
|
3101
2849
|
"@segment/analytics-node": "^3.1.0",
|
|
@@ -3110,6 +2858,7 @@ var package_default = {
|
|
|
3110
2858
|
nanoid: "^5.1.15",
|
|
3111
2859
|
pino: "^10.3.1",
|
|
3112
2860
|
react: "^19.2.7",
|
|
2861
|
+
toml: "^4.1.1",
|
|
3113
2862
|
varlock: "^1.5.1",
|
|
3114
2863
|
zod: "^4.4.3",
|
|
3115
2864
|
zustand: "^5.0.14"
|
|
@@ -3167,8 +2916,8 @@ async function askList(ctx, prompt, { required = false } = {}) {
|
|
|
3167
2916
|
}
|
|
3168
2917
|
|
|
3169
2918
|
// src/actions/confirmLanguage.ts
|
|
3170
|
-
import
|
|
3171
|
-
var confirmLanguageSchema =
|
|
2919
|
+
import z19 from "zod";
|
|
2920
|
+
var confirmLanguageSchema = z19.object({
|
|
3172
2921
|
languages: detectLanguageSchema.shape.languages
|
|
3173
2922
|
});
|
|
3174
2923
|
async function confirmLanguage(ctx) {
|
|
@@ -3189,8 +2938,8 @@ async function confirmLanguage(ctx) {
|
|
|
3189
2938
|
}
|
|
3190
2939
|
|
|
3191
2940
|
// src/actions/confirmFramework.ts
|
|
3192
|
-
import
|
|
3193
|
-
var confirmFrameworkSchema =
|
|
2941
|
+
import z20 from "zod";
|
|
2942
|
+
var confirmFrameworkSchema = z20.object({
|
|
3194
2943
|
frameworks: detectLanguageSchema.shape.frameworks
|
|
3195
2944
|
});
|
|
3196
2945
|
var CURATED_FRAMEWORKS = [
|
|
@@ -3318,8 +3067,8 @@ async function promptUser(ctx, params) {
|
|
|
3318
3067
|
}
|
|
3319
3068
|
|
|
3320
3069
|
// src/actions/confirmEntities.ts
|
|
3321
|
-
import
|
|
3322
|
-
var confirmEntitiesSchema =
|
|
3070
|
+
import z21 from "zod";
|
|
3071
|
+
var confirmEntitiesSchema = z21.object({
|
|
3323
3072
|
// Final detection — the focused re-run may supersede project-scan's.
|
|
3324
3073
|
ingestionAnalysis: ingestionAnalysisSchema.shape.ingestionAnalysis.optional(),
|
|
3325
3074
|
confirmedEntities: confirmedEntitiesFieldSchema
|
|
@@ -3389,15 +3138,15 @@ async function confirmEntities(ctx) {
|
|
|
3389
3138
|
}
|
|
3390
3139
|
|
|
3391
3140
|
// src/actions/review.ts
|
|
3392
|
-
import { z as
|
|
3393
|
-
var reviewSchema =
|
|
3141
|
+
import { z as z22 } from "zod";
|
|
3142
|
+
var reviewSchema = z22.object({
|
|
3394
3143
|
// Broad, high-level takeaways grouped by theme (e.g. ingestion, search UI),
|
|
3395
3144
|
// not one entry per workflow step — a step's raw output can be a long,
|
|
3396
3145
|
// multi-paragraph blob (see implement.ts's summaries.join), and mirroring
|
|
3397
3146
|
// that 1:1 is what made the old per-step summary an unreadable wall of text.
|
|
3398
|
-
summaryPoints:
|
|
3399
|
-
reviewPrompt:
|
|
3400
|
-
nextSteps:
|
|
3147
|
+
summaryPoints: z22.array(z22.string()),
|
|
3148
|
+
reviewPrompt: z22.string(),
|
|
3149
|
+
nextSteps: z22.array(z22.string())
|
|
3401
3150
|
});
|
|
3402
3151
|
function formatCompletedSteps(steps) {
|
|
3403
3152
|
if (!steps.length) return "(no prior steps completed)";
|
|
@@ -3448,16 +3197,16 @@ ${formatCompletedSteps(ctx.completedSteps)}`,
|
|
|
3448
3197
|
};
|
|
3449
3198
|
|
|
3450
3199
|
// src/actions/implement.ts
|
|
3451
|
-
import
|
|
3200
|
+
import z24 from "zod";
|
|
3452
3201
|
|
|
3453
3202
|
// src/lib/worktree.ts
|
|
3454
3203
|
import { execFile, spawn as spawn3 } from "node:child_process";
|
|
3455
|
-
import { copyFile, mkdir as mkdir6, readdir as readdir3, readFile as
|
|
3204
|
+
import { copyFile, mkdir as mkdir6, readdir as readdir3, readFile as readFile8, stat as stat2, writeFile as writeFile6 } from "node:fs/promises";
|
|
3456
3205
|
import {
|
|
3457
3206
|
basename as basename2,
|
|
3458
3207
|
dirname as dirname7,
|
|
3459
3208
|
isAbsolute as isAbsolute2,
|
|
3460
|
-
join as
|
|
3209
|
+
join as join10,
|
|
3461
3210
|
relative as relative2,
|
|
3462
3211
|
resolve as resolve3
|
|
3463
3212
|
} from "node:path";
|
|
@@ -3491,7 +3240,7 @@ async function isWorkingTreeDirty(repoRoot) {
|
|
|
3491
3240
|
return out.trim().length > 0;
|
|
3492
3241
|
}
|
|
3493
3242
|
async function pruneOldWorktrees(repoRoot) {
|
|
3494
|
-
const dir =
|
|
3243
|
+
const dir = join10(stateDir(repoRoot), "worktrees");
|
|
3495
3244
|
const stale = (await readdir3(dir).catch(() => [])).filter((name) => /^wizard-implement-\d+$/.test(name)).sort().reverse().slice(MAX_WIZARD_WORKTREES - 1);
|
|
3496
3245
|
for (const slug of stale) {
|
|
3497
3246
|
const branch = slug.replace("wizard-implement-", WIZARD_BRANCH_PREFIX);
|
|
@@ -3502,7 +3251,7 @@ async function pruneOldWorktrees(repoRoot) {
|
|
|
3502
3251
|
"worktree",
|
|
3503
3252
|
"remove",
|
|
3504
3253
|
"--force",
|
|
3505
|
-
|
|
3254
|
+
join10(dir, slug)
|
|
3506
3255
|
]);
|
|
3507
3256
|
await git(["-C", repoRoot, "branch", "-D", branch]);
|
|
3508
3257
|
} catch (err) {
|
|
@@ -3516,7 +3265,7 @@ async function pruneOldWorktrees(repoRoot) {
|
|
|
3516
3265
|
async function createWorktree(repoRoot) {
|
|
3517
3266
|
const branch = `${WIZARD_BRANCH_PREFIX}${Date.now()}`;
|
|
3518
3267
|
const dirSlug = branch.replace(/\//g, "-");
|
|
3519
|
-
const path =
|
|
3268
|
+
const path = join10(stateDir(repoRoot), "worktrees", dirSlug);
|
|
3520
3269
|
await git(["-C", repoRoot, "worktree", "prune"]);
|
|
3521
3270
|
await pruneOldWorktrees(repoRoot);
|
|
3522
3271
|
await mkdir6(dirname7(path), { recursive: true });
|
|
@@ -3636,8 +3385,8 @@ async function copyUploadIntoWorktree(repoRoot, worktreePath, ingestDir, sourceP
|
|
|
3636
3385
|
} catch {
|
|
3637
3386
|
return { ok: false, reason: `"${sourcePath}" does not exist` };
|
|
3638
3387
|
}
|
|
3639
|
-
const relPath =
|
|
3640
|
-
const dest =
|
|
3388
|
+
const relPath = join10(ingestDir, basename2(source));
|
|
3389
|
+
const dest = join10(worktreePath, relPath);
|
|
3641
3390
|
try {
|
|
3642
3391
|
await mkdir6(dirname7(dest), { recursive: true });
|
|
3643
3392
|
await copyFile(source, dest);
|
|
@@ -3653,10 +3402,10 @@ function hasEnvVar(content, name) {
|
|
|
3653
3402
|
return new RegExp(`^(\\s*(?:export\\s+)?${name})\\s*=`, "m").test(content);
|
|
3654
3403
|
}
|
|
3655
3404
|
async function writeSearchEnvValues(worktreePath, vars) {
|
|
3656
|
-
const target =
|
|
3405
|
+
const target = join10(worktreePath, ".env");
|
|
3657
3406
|
let existing = "";
|
|
3658
3407
|
try {
|
|
3659
|
-
existing = await
|
|
3408
|
+
existing = await readFile8(target, "utf8");
|
|
3660
3409
|
} catch (err) {
|
|
3661
3410
|
if (err.code !== "ENOENT") throw err;
|
|
3662
3411
|
}
|
|
@@ -3724,15 +3473,63 @@ async function confirmDirtyWorkingTree(ctx, repoRoot) {
|
|
|
3724
3473
|
}
|
|
3725
3474
|
}
|
|
3726
3475
|
|
|
3476
|
+
// src/lib/algoliaApiKey.ts
|
|
3477
|
+
import { z as z23 } from "zod";
|
|
3478
|
+
var SAFE_ACLS = /* @__PURE__ */ new Set(["search", "browse", "listIndexes"]);
|
|
3479
|
+
var apiKeySchema = z23.object({
|
|
3480
|
+
value: z23.string().min(1),
|
|
3481
|
+
acl: z23.array(z23.string()).default([]),
|
|
3482
|
+
indexes: z23.array(z23.string()).default([])
|
|
3483
|
+
});
|
|
3484
|
+
var apiKeyListSchema = z23.object({
|
|
3485
|
+
items: z23.array(apiKeySchema).optional(),
|
|
3486
|
+
keys: z23.array(apiKeySchema).optional()
|
|
3487
|
+
}).transform((o) => o.items ?? o.keys ?? []);
|
|
3488
|
+
var createdKeySchema = z23.object({
|
|
3489
|
+
key: z23.string().min(1).optional(),
|
|
3490
|
+
value: z23.string().min(1).optional()
|
|
3491
|
+
});
|
|
3492
|
+
function canReuse(key, index) {
|
|
3493
|
+
return key.acl.includes("search") && key.acl.every((acl) => SAFE_ACLS.has(acl)) && (key.indexes.length === 0 || key.indexes.includes("*") || key.indexes.includes(index));
|
|
3494
|
+
}
|
|
3495
|
+
async function createSearchKey(index) {
|
|
3496
|
+
const stdout = await runAlgoliaCli([
|
|
3497
|
+
"apikeys",
|
|
3498
|
+
"create",
|
|
3499
|
+
"--indices",
|
|
3500
|
+
index,
|
|
3501
|
+
"--acl",
|
|
3502
|
+
"search,browse",
|
|
3503
|
+
"--description",
|
|
3504
|
+
`wizard search-only key for ${index}`,
|
|
3505
|
+
"-o",
|
|
3506
|
+
"json"
|
|
3507
|
+
]);
|
|
3508
|
+
const { key, value } = createdKeySchema.parse(JSON.parse(stdout));
|
|
3509
|
+
const created = key ?? value;
|
|
3510
|
+
if (!created) throw new Error("apikeys create returned no key value");
|
|
3511
|
+
return created;
|
|
3512
|
+
}
|
|
3513
|
+
async function resolveSearchOnlyKey(index) {
|
|
3514
|
+
const stdout = await runAlgoliaCli(["apikeys", "list", "-o", "json"]);
|
|
3515
|
+
const existing = apiKeyListSchema.parse(JSON.parse(stdout)).find((key) => canReuse(key, index))?.value;
|
|
3516
|
+
if (existing) {
|
|
3517
|
+
logger.info({ index }, "reusing existing search-only API key");
|
|
3518
|
+
return existing;
|
|
3519
|
+
}
|
|
3520
|
+
logger.info({ index }, "no reusable search-only key found; creating one");
|
|
3521
|
+
return createSearchKey(index);
|
|
3522
|
+
}
|
|
3523
|
+
|
|
3727
3524
|
// src/lib/algoliaDocs.ts
|
|
3728
3525
|
import { readFileSync, readdirSync, existsSync as existsSync2 } from "node:fs";
|
|
3729
|
-
import { dirname as dirname8, join as
|
|
3526
|
+
import { dirname as dirname8, join as join11 } from "node:path";
|
|
3730
3527
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
3731
|
-
var DOCS_SUBPATH =
|
|
3528
|
+
var DOCS_SUBPATH = join11("docs", "algolia-sdk");
|
|
3732
3529
|
function findDocsDir() {
|
|
3733
3530
|
let dir = dirname8(fileURLToPath2(import.meta.url));
|
|
3734
3531
|
for (; ; ) {
|
|
3735
|
-
const candidate =
|
|
3532
|
+
const candidate = join11(dir, DOCS_SUBPATH);
|
|
3736
3533
|
if (existsSync2(candidate)) return candidate;
|
|
3737
3534
|
const parent = dirname8(dir);
|
|
3738
3535
|
if (parent === dir) return void 0;
|
|
@@ -3755,7 +3552,7 @@ function loadAlgoliaDoc(language) {
|
|
|
3755
3552
|
);
|
|
3756
3553
|
return "";
|
|
3757
3554
|
}
|
|
3758
|
-
return readFileSync(
|
|
3555
|
+
return readFileSync(join11(docsDir, files[0]), "utf8").trim();
|
|
3759
3556
|
}
|
|
3760
3557
|
function getNamedDoc(name, language) {
|
|
3761
3558
|
const docsDir = findDocsDir();
|
|
@@ -3763,7 +3560,7 @@ function getNamedDoc(name, language) {
|
|
|
3763
3560
|
logger.warn("docs/algolia-sdk not found");
|
|
3764
3561
|
return "";
|
|
3765
3562
|
}
|
|
3766
|
-
const file =
|
|
3563
|
+
const file = join11(docsDir, `${name}-${language}.md`);
|
|
3767
3564
|
if (!existsSync2(file)) {
|
|
3768
3565
|
logger.warn({ name, language }, "named SDK reference not found");
|
|
3769
3566
|
return "";
|
|
@@ -3790,34 +3587,50 @@ function shellQuote(value) {
|
|
|
3790
3587
|
}
|
|
3791
3588
|
|
|
3792
3589
|
// src/actions/implement.ts
|
|
3793
|
-
var implementSchema =
|
|
3794
|
-
filesChanged:
|
|
3795
|
-
summary:
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3590
|
+
var implementSchema = z24.object({
|
|
3591
|
+
filesChanged: z24.array(z24.string()),
|
|
3592
|
+
summary: z24.string(),
|
|
3593
|
+
// Absolute path to the throwaway worktree holding the generated changes, so
|
|
3594
|
+
// the user can open it (`cd <worktreePath>`) or inspect the diff
|
|
3595
|
+
// (`git -C <worktreePath> status/diff`).
|
|
3596
|
+
worktreePath: z24.string().optional(),
|
|
3597
|
+
ingestCommand: z24.string().optional(),
|
|
3598
|
+
// True when the user accepted the run-now prompt and the wizard executed the
|
|
3599
|
+
// ingestion script; downstream steps use this to avoid telling the user to run
|
|
3600
|
+
// a script that already ran.
|
|
3601
|
+
ingestScriptRan: z24.boolean().optional(),
|
|
3602
|
+
// Records ingested by the run-now execution, parsed from the script's
|
|
3603
|
+
// machine-readable count line; absent when the script didn't run or emitted
|
|
3604
|
+
// no parseable count.
|
|
3605
|
+
ingestRecordCount: z24.number().optional(),
|
|
3606
|
+
// Wall-clock duration of the run-now ingestion execution, in ms.
|
|
3607
|
+
ingestDurationMs: z24.number().optional(),
|
|
3608
|
+
ingestionSource: z24.enum(["local", "fileUpload", "generated"]),
|
|
3609
|
+
// Suggested names/values, built from framework detection. The search agent is
|
|
3610
|
+
// instructed to rename the prefix if it doesn't match the project's build
|
|
3611
|
+
// tool, so the names it actually wrote can differ — treat these as hints, not
|
|
3612
|
+
// ground truth (the agent's summary carries the final names).
|
|
3613
|
+
searchEnvVars: z24.array(
|
|
3614
|
+
z24.object({
|
|
3615
|
+
name: z24.string(),
|
|
3616
|
+
value: z24.string()
|
|
3806
3617
|
})
|
|
3807
3618
|
).optional()
|
|
3808
3619
|
});
|
|
3809
|
-
var implementationOutputSchema =
|
|
3810
|
-
summary:
|
|
3811
|
-
// Ingestion only:
|
|
3812
|
-
//
|
|
3813
|
-
//
|
|
3814
|
-
|
|
3815
|
-
|
|
3620
|
+
var implementationOutputSchema = z24.object({
|
|
3621
|
+
summary: z24.string(),
|
|
3622
|
+
// Ingestion only: how to run the generated script, as a structured pair the
|
|
3623
|
+
// wizard turns into an argv (`<runtime> <entrypoint>`) — never a free-form
|
|
3624
|
+
// command string. `runtime` is constrained to an allowlisted interpreter and
|
|
3625
|
+
// `entrypoint` is validated to a worktree-relative path before execution, so
|
|
3626
|
+
// the agent cannot inject extra commands or swap the interpreter.
|
|
3627
|
+
runtime: z24.enum(INGEST_RUNTIMES).optional(),
|
|
3628
|
+
entrypoint: z24.string().optional()
|
|
3816
3629
|
});
|
|
3817
|
-
var verificationOutputSchema =
|
|
3818
|
-
summary:
|
|
3819
|
-
sufficient:
|
|
3820
|
-
additionalInstructions:
|
|
3630
|
+
var verificationOutputSchema = z24.object({
|
|
3631
|
+
summary: z24.string(),
|
|
3632
|
+
sufficient: z24.boolean(),
|
|
3633
|
+
additionalInstructions: z24.string().optional()
|
|
3821
3634
|
});
|
|
3822
3635
|
var MAX_IMPLEMENT_VERIFICATION_ATTEMPTS = 3;
|
|
3823
3636
|
var DEFAULT_IMPLEMENT_USE_CASES = ["ingestion", "search"];
|
|
@@ -3889,6 +3702,9 @@ function sourceSpecificInstructions(input) {
|
|
|
3889
3702
|
"Add env vars for any local source access (DB URL, API base, file paths) that is not a fixed repo path."
|
|
3890
3703
|
],
|
|
3891
3704
|
fileUpload: [
|
|
3705
|
+
// The wizard already copied the developer's file into the worktree at this
|
|
3706
|
+
// exact path, so the agent must read it directly — never search for or
|
|
3707
|
+
// substitute another file.
|
|
3892
3708
|
`Records come from the developer's file, already copied into the worktree at "${input.uploadFilePath}". Read and parse that exact file.`,
|
|
3893
3709
|
"Parse by extension: JSON = array of objects; CSV/TSV = header row maps to keys.",
|
|
3894
3710
|
"Map parsed columns/fields to the confirmed entity attributes.",
|
|
@@ -3928,9 +3744,12 @@ function searchInstructions(input) {
|
|
|
3928
3744
|
doc,
|
|
3929
3745
|
`Add the search UI at ${input.searchLocation ? `"${input.searchLocation}"` : "the best shared, always-rendered layout location (e.g. a header/nav component)"} so it is reachable across the app \u2014 at least a working SearchBox and Hits against the "${input.targetIndex}" index.`,
|
|
3930
3746
|
"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.",
|
|
3747
|
+
// appId always resolves (loadActiveProfile throws otherwise); only the
|
|
3748
|
+
// search-only key is best-effort and can fall back to a placeholder.
|
|
3931
3749
|
`Values: App ID "${input.appId}", search-only key ${input.searchKey ? `"${input.searchKey}"` : "(placeholder for the developer to fill in)"}.`,
|
|
3932
|
-
//
|
|
3933
|
-
//
|
|
3750
|
+
// Names are fixed, not the agent's to rename: the wizard writes the
|
|
3751
|
+
// resolved app id / search-only key into ".env" under these exact names
|
|
3752
|
+
// right after this step, so a renamed prefix here would leave the code
|
|
3934
3753
|
// reading a var the wizard never wrote.
|
|
3935
3754
|
`Use exactly these public env var names in the code: ${input.searchEnvVars.map(({ name }) => name).join(", ")}.`,
|
|
3936
3755
|
'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.',
|
|
@@ -4074,7 +3893,6 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4074
3893
|
}
|
|
4075
3894
|
}
|
|
4076
3895
|
const targetIndex = selected?.selection;
|
|
4077
|
-
useWizard.getState().setTargetIndex(targetIndex ?? null);
|
|
4078
3896
|
await assertGitRepoWithHead(repoRoot);
|
|
4079
3897
|
if (await isWorkingTreeDirty(repoRoot)) {
|
|
4080
3898
|
await confirmDirtyWorkingTree(ctx, repoRoot);
|
|
@@ -4085,7 +3903,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4085
3903
|
let appId;
|
|
4086
3904
|
let searchKey;
|
|
4087
3905
|
if (useCases.includes("search")) {
|
|
4088
|
-
appId = (await
|
|
3906
|
+
appId = (await loadActiveProfile()).appId;
|
|
4089
3907
|
try {
|
|
4090
3908
|
searchKey = await resolveSearchOnlyKey(targetIndex);
|
|
4091
3909
|
} catch (err) {
|
|
@@ -4130,6 +3948,8 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4130
3948
|
ingestDir: INGEST_DIR,
|
|
4131
3949
|
ingestionSource,
|
|
4132
3950
|
uploadFilePath,
|
|
3951
|
+
// language.frameworks already prefers the confirm-framework step output,
|
|
3952
|
+
// so the user's confirmed stack (not just raw detection) picks the flavor.
|
|
4133
3953
|
uiFramework: detectUiFramework(language)
|
|
4134
3954
|
};
|
|
4135
3955
|
const summaries = [];
|
|
@@ -4194,8 +4014,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4194
4014
|
messages: []
|
|
4195
4015
|
}) === true;
|
|
4196
4016
|
if (runNow) {
|
|
4197
|
-
const
|
|
4198
|
-
const writeKey = await resolveWriteKey(targetIndex);
|
|
4017
|
+
const profile = await loadActiveProfile();
|
|
4199
4018
|
ctx.notify({ messages: [`Writing records to "${targetIndex}"\u2026`] });
|
|
4200
4019
|
const scriptLogId = ctx.logStart("runIngestScript", {
|
|
4201
4020
|
runtime: ingestRuntime,
|
|
@@ -4207,8 +4026,8 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4207
4026
|
ingestRuntime,
|
|
4208
4027
|
ingestEntrypoint,
|
|
4209
4028
|
{
|
|
4210
|
-
[APP_ID_VAR]:
|
|
4211
|
-
[API_KEY_VAR]:
|
|
4029
|
+
[APP_ID_VAR]: profile.appId,
|
|
4030
|
+
[API_KEY_VAR]: profile.apiKey
|
|
4212
4031
|
}
|
|
4213
4032
|
);
|
|
4214
4033
|
ctx.logEnd(scriptLogId, run2.ok ? "success" : "error");
|
|
@@ -4277,6 +4096,8 @@ ${run2.output}` : status;
|
|
|
4277
4096
|
);
|
|
4278
4097
|
}
|
|
4279
4098
|
await ctx.requestUserInput({
|
|
4099
|
+
// No question being asked here, just an acknowledgement — the
|
|
4100
|
+
// continue/decline hints below already say "continue".
|
|
4280
4101
|
prompt: "",
|
|
4281
4102
|
promptType: "enterToContinue",
|
|
4282
4103
|
options: [],
|
|
@@ -4417,8 +4238,8 @@ var defaultWorkflow = {
|
|
|
4417
4238
|
defineStep({
|
|
4418
4239
|
id: "select-index",
|
|
4419
4240
|
title: "Set up index",
|
|
4420
|
-
outputSchema:
|
|
4421
|
-
selection:
|
|
4241
|
+
outputSchema: z25.object({
|
|
4242
|
+
selection: z25.string()
|
|
4422
4243
|
}),
|
|
4423
4244
|
run: (ctx) => selectIndexStep(ctx)
|
|
4424
4245
|
}),
|
|
@@ -4697,7 +4518,7 @@ function parseCliArgs(argv) {
|
|
|
4697
4518
|
|
|
4698
4519
|
// src/lib/resetState.ts
|
|
4699
4520
|
import { readdir as readdir4, rm as rm2 } from "node:fs/promises";
|
|
4700
|
-
import { join as
|
|
4521
|
+
import { join as join12 } from "node:path";
|
|
4701
4522
|
var KEEP = ["wizard.log"];
|
|
4702
4523
|
async function resetProjectState() {
|
|
4703
4524
|
const dir = stateDir();
|
|
@@ -4709,7 +4530,7 @@ async function resetProjectState() {
|
|
|
4709
4530
|
}
|
|
4710
4531
|
const targets = entries.filter((name) => !KEEP.includes(name));
|
|
4711
4532
|
await Promise.all(
|
|
4712
|
-
targets.map((name) => rm2(
|
|
4533
|
+
targets.map((name) => rm2(join12(dir, name), { recursive: true, force: true }))
|
|
4713
4534
|
);
|
|
4714
4535
|
return { dir, removed: targets };
|
|
4715
4536
|
}
|
|
@@ -4764,38 +4585,31 @@ ${formatStepList(workflow)}`);
|
|
|
4764
4585
|
}
|
|
4765
4586
|
async function run(workflow) {
|
|
4766
4587
|
const store = useWizard.getState();
|
|
4767
|
-
|
|
4768
|
-
await store.waitForStart();
|
|
4588
|
+
let instance = render(/* @__PURE__ */ jsx14(App, {}), { incrementalRendering: true });
|
|
4769
4589
|
let user = await getUser();
|
|
4770
4590
|
if (!user) {
|
|
4771
|
-
|
|
4591
|
+
await instance.waitUntilRenderFlush();
|
|
4592
|
+
instance.cleanup();
|
|
4772
4593
|
try {
|
|
4773
4594
|
await runAuthLogin();
|
|
4774
4595
|
} catch (err) {
|
|
4775
|
-
|
|
4776
|
-
await instance.waitUntilExit();
|
|
4596
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
4777
4597
|
process.exit(1);
|
|
4778
4598
|
}
|
|
4779
|
-
|
|
4599
|
+
instance = render(/* @__PURE__ */ jsx14(App, {}), { incrementalRendering: true });
|
|
4780
4600
|
user = await getUser();
|
|
4781
4601
|
if (!user) {
|
|
4782
4602
|
store.setError(
|
|
4783
|
-
"Authentication completed but no Algolia user was returned. Try running `npx @algolia/cli
|
|
4603
|
+
"Authentication completed but no Algolia user was returned. Try running `npx @algolia/cli auth login` directly."
|
|
4784
4604
|
);
|
|
4785
4605
|
await instance.waitUntilExit();
|
|
4786
4606
|
process.exit(1);
|
|
4787
4607
|
}
|
|
4788
4608
|
}
|
|
4789
4609
|
store.setUser(user);
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
} catch (err) {
|
|
4794
|
-
store.setError(err instanceof Error ? err.message : String(err));
|
|
4795
|
-
await instance.waitUntilExit();
|
|
4796
|
-
process.exit(1);
|
|
4797
|
-
}
|
|
4798
|
-
runWorkflow(workflow, app.id);
|
|
4610
|
+
const profile = await loadActiveProfile();
|
|
4611
|
+
await store.waitForStart();
|
|
4612
|
+
runWorkflow(workflow, profile?.appId);
|
|
4799
4613
|
}
|
|
4800
4614
|
var started = await startup();
|
|
4801
4615
|
if (typeof started === "number") {
|