@algolia/wizard 0.9.0-rc.53.57 → 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 +591 -801
- 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,26 +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
|
-
beginAuth: () => set({ phase: "authenticating", cliOutput: [] }),
|
|
254
|
-
endAuth: () => set((s) => s.phase === "authenticating" ? { phase: "preflight" } : {}),
|
|
255
|
-
// Only meaningful from 'idle' — once the workflow is running there's nothing
|
|
256
|
-
// left to confirm. `homeScreen` resets so preflight shows Welcome rather than
|
|
257
|
-
// the Learn more sub-view.
|
|
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.
|
|
258
192
|
confirmStart: () => set(
|
|
259
193
|
(s) => s.phase === "idle" ? { phase: "preflight", homeScreen: "home" } : {}
|
|
260
194
|
),
|
|
195
|
+
// Welcome sub-view navigation; leaves `phase` untouched so the workflow stays paused.
|
|
261
196
|
openLearnMore: () => set({ homeScreen: "learnMore" }),
|
|
262
197
|
backToHome: () => set({ homeScreen: "home" }),
|
|
263
|
-
// Resolves
|
|
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`).
|
|
264
201
|
waitForStart: () => new Promise((resolve4) => {
|
|
265
202
|
if (get().phase !== "idle") {
|
|
266
203
|
resolve4();
|
|
@@ -283,20 +220,15 @@ var useWizard = create((set, get) => ({
|
|
|
283
220
|
syncSteps: (steps, currentStepIndex) => set({ steps, currentStepIndex }),
|
|
284
221
|
setActiveStep: (index) => {
|
|
285
222
|
get()._clearNoticeQueue();
|
|
286
|
-
set({
|
|
287
|
-
phase: "running",
|
|
288
|
-
currentStepIndex: index,
|
|
289
|
-
output: "",
|
|
290
|
-
notices: [],
|
|
291
|
-
cliOutput: []
|
|
292
|
-
});
|
|
223
|
+
set({ phase: "running", currentStepIndex: index, output: "", notices: [] });
|
|
293
224
|
},
|
|
294
225
|
setUser: (user) => set({ user }),
|
|
295
226
|
appendToken: (text) => set((s) => ({ output: s.output + text })),
|
|
296
227
|
clearOutput: () => set({ output: "" }),
|
|
297
|
-
// Renders the first notice of a burst immediately, then
|
|
298
|
-
//
|
|
299
|
-
//
|
|
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.
|
|
300
232
|
pushNotice: (notice) => {
|
|
301
233
|
const { notices, _noticeQueue, _noticeTimer } = get();
|
|
302
234
|
if (_noticeTimer === null) {
|
|
@@ -329,15 +261,6 @@ var useWizard = create((set, get) => ({
|
|
|
329
261
|
get()._clearNoticeQueue();
|
|
330
262
|
set({ notices: [] });
|
|
331
263
|
},
|
|
332
|
-
// Unthrottled, unlike `pushNotice`: holding these back would land output
|
|
333
|
-
// after the command it belongs to has already exited.
|
|
334
|
-
pushCliOutput: (stream, text) => set((s) => ({
|
|
335
|
-
cliOutput: [...s.cliOutput, { id: nanoid(), stream, text }].slice(
|
|
336
|
-
-CLI_OUTPUT_LIMIT
|
|
337
|
-
)
|
|
338
|
-
})),
|
|
339
|
-
clearCliOutput: () => set({ cliOutput: [] }),
|
|
340
|
-
setTargetIndex: (index) => set({ targetIndex: index }),
|
|
341
264
|
logStart: (kind, name, input) => {
|
|
342
265
|
const id = nanoid();
|
|
343
266
|
set((s) => ({
|
|
@@ -360,8 +283,9 @@ var useWizard = create((set, get) => ({
|
|
|
360
283
|
_resolve: resolve4
|
|
361
284
|
});
|
|
362
285
|
}),
|
|
363
|
-
// Logs what the user picked
|
|
364
|
-
// on-screen content
|
|
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.
|
|
365
289
|
submitInput: async (value) => {
|
|
366
290
|
await markInteraction();
|
|
367
291
|
get()._resolve?.(value);
|
|
@@ -381,8 +305,6 @@ var useWizard = create((set, get) => ({
|
|
|
381
305
|
currentStepIndex: 0,
|
|
382
306
|
output: "",
|
|
383
307
|
notices: [],
|
|
384
|
-
cliOutput: [],
|
|
385
|
-
targetIndex: null,
|
|
386
308
|
logs: [],
|
|
387
309
|
error: null,
|
|
388
310
|
inputReq: null,
|
|
@@ -391,100 +313,16 @@ var useWizard = create((set, get) => ({
|
|
|
391
313
|
}
|
|
392
314
|
}));
|
|
393
315
|
|
|
394
|
-
// src/ui/CliOutput.tsx
|
|
395
|
-
import { Box, Text, useWindowSize } from "ink";
|
|
396
|
-
|
|
397
|
-
// src/ui/theme.ts
|
|
398
|
-
var MARKER = {
|
|
399
|
-
pending: "\u25CB",
|
|
400
|
-
running: "\u25D0",
|
|
401
|
-
done: "\u2713",
|
|
402
|
-
error: "\u2716"
|
|
403
|
-
};
|
|
404
|
-
var BRAND = "#003DFF";
|
|
405
|
-
var SECONDARY = "#5468FF";
|
|
406
|
-
var DANGER = "#F86E7E";
|
|
407
|
-
var COLORS = {
|
|
408
|
-
brand: BRAND,
|
|
409
|
-
primary: "#E6EDF3",
|
|
410
|
-
secondary: SECONDARY,
|
|
411
|
-
strong: "#FFFFFF",
|
|
412
|
-
muted: "#8B949E",
|
|
413
|
-
dim: "#484F58",
|
|
414
|
-
highlight: { bg: "#12331C", fg: "#4ADE80" },
|
|
415
|
-
badge: "#E3B341",
|
|
416
|
-
danger: DANGER,
|
|
417
|
-
success: "#4ADE80",
|
|
418
|
-
bg: {
|
|
419
|
-
main: "#0B0E14",
|
|
420
|
-
sidebar: "#14171E"
|
|
421
|
-
},
|
|
422
|
-
border: "#30363D",
|
|
423
|
-
accent: "#76A0FF",
|
|
424
|
-
status: {
|
|
425
|
-
pending: "gray",
|
|
426
|
-
running: "#76A0FF",
|
|
427
|
-
done: "#4ADE80",
|
|
428
|
-
error: DANGER
|
|
429
|
-
}
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
// src/ui/CliOutput.tsx
|
|
433
|
-
import { jsxs } from "react/jsx-runtime";
|
|
434
|
-
var CLI_MARKER = "\u203A";
|
|
435
|
-
var RESERVED_ROWS = 16;
|
|
436
|
-
var MAX_ROWS = 12;
|
|
437
|
-
var PANEL_TEXT_WIDTH = 45;
|
|
438
|
-
var URL_PATTERN = /https?:\/\//;
|
|
439
|
-
function rowCost(text) {
|
|
440
|
-
return URL_PATTERN.test(text) ? Math.max(1, Math.ceil(text.length / PANEL_TEXT_WIDTH)) : 1;
|
|
441
|
-
}
|
|
442
|
-
function CliOutput() {
|
|
443
|
-
const cliOutput = useWizard((s) => s.cliOutput);
|
|
444
|
-
const { rows } = useWindowSize();
|
|
445
|
-
if (!cliOutput.length) return null;
|
|
446
|
-
const rowBudget = Math.min(Math.max(rows - RESERVED_ROWS, 3), MAX_ROWS);
|
|
447
|
-
const visible = [];
|
|
448
|
-
let usedRows = 0;
|
|
449
|
-
for (let i = cliOutput.length - 1; i >= 0; i--) {
|
|
450
|
-
const cost = rowCost(cliOutput[i].text);
|
|
451
|
-
if (usedRows + cost > rowBudget && visible.length > 0) break;
|
|
452
|
-
visible.unshift(cliOutput[i]);
|
|
453
|
-
usedRows += cost;
|
|
454
|
-
}
|
|
455
|
-
const hidden = cliOutput.length - visible.length;
|
|
456
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
457
|
-
hidden > 0 && /* @__PURE__ */ jsxs(Text, { color: COLORS.dim, children: [
|
|
458
|
-
"\u2191 ",
|
|
459
|
-
hidden,
|
|
460
|
-
" earlier line(s)"
|
|
461
|
-
] }),
|
|
462
|
-
visible.map((line) => /* @__PURE__ */ jsxs(
|
|
463
|
-
Text,
|
|
464
|
-
{
|
|
465
|
-
color: line.stream === "stderr" ? COLORS.muted : COLORS.dim,
|
|
466
|
-
wrap: URL_PATTERN.test(line.text) ? "wrap" : "truncate",
|
|
467
|
-
children: [
|
|
468
|
-
CLI_MARKER,
|
|
469
|
-
" ",
|
|
470
|
-
line.text
|
|
471
|
-
]
|
|
472
|
-
},
|
|
473
|
-
line.id
|
|
474
|
-
))
|
|
475
|
-
] });
|
|
476
|
-
}
|
|
477
|
-
|
|
478
316
|
// src/ui/Notices.tsx
|
|
479
|
-
import { Box as
|
|
317
|
+
import { Box as Box2, Text as Text2, useWindowSize as useWindowSize2 } from "ink";
|
|
480
318
|
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
481
319
|
|
|
482
320
|
// src/ui/Table.tsx
|
|
483
|
-
import { Box
|
|
321
|
+
import { Box, Text, measureElement, useWindowSize } from "ink";
|
|
484
322
|
import { useEffect, useRef, useState } from "react";
|
|
485
323
|
import { jsx } from "react/jsx-runtime";
|
|
486
324
|
function Table({ columns, rows }) {
|
|
487
|
-
const { columns: termCols } =
|
|
325
|
+
const { columns: termCols } = useWindowSize();
|
|
488
326
|
const ref = useRef(null);
|
|
489
327
|
const [width, setWidth] = useState(0);
|
|
490
328
|
useEffect(() => {
|
|
@@ -492,7 +330,7 @@ function Table({ columns, rows }) {
|
|
|
492
330
|
}, [termCols, columns, rows]);
|
|
493
331
|
if (rows.length === 0) return null;
|
|
494
332
|
const lines = formatTable(columns, rows, width || void 0);
|
|
495
|
-
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}`)) });
|
|
496
334
|
}
|
|
497
335
|
function formatTable(columns, rows, width) {
|
|
498
336
|
const natural = columns.map(
|
|
@@ -532,13 +370,48 @@ function resize(widths, budget) {
|
|
|
532
370
|
}
|
|
533
371
|
var truncate = (s, width) => s.length <= width ? s : width <= 1 ? s.slice(0, width) : `${s.slice(0, width - 1)}\u2026`;
|
|
534
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
|
+
|
|
535
408
|
// src/ui/Notices.tsx
|
|
536
|
-
import { jsx as jsx2, jsxs
|
|
409
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
537
410
|
var AGENT_MARKER = "\u2726";
|
|
538
|
-
var
|
|
539
|
-
var
|
|
411
|
+
var RESERVED_ROWS = 14;
|
|
412
|
+
var PANEL_TEXT_WIDTH = 45;
|
|
540
413
|
function messageLineCount(text) {
|
|
541
|
-
return Math.max(1, Math.ceil(text.length /
|
|
414
|
+
return Math.max(1, Math.ceil(text.length / PANEL_TEXT_WIDTH));
|
|
542
415
|
}
|
|
543
416
|
function noticeLineCount(notice) {
|
|
544
417
|
const messageLines = (notice.messages ?? []).reduce((sum, m) => {
|
|
@@ -549,7 +422,7 @@ function noticeLineCount(notice) {
|
|
|
549
422
|
return messageLines + tableLines;
|
|
550
423
|
}
|
|
551
424
|
function fitVisibleNotices(notices, windowRows) {
|
|
552
|
-
const budget = Math.max(windowRows -
|
|
425
|
+
const budget = Math.max(windowRows - RESERVED_ROWS, 3);
|
|
553
426
|
let used = 0;
|
|
554
427
|
let count = 0;
|
|
555
428
|
for (let i = notices.length - 1; i >= 0; i--) {
|
|
@@ -582,7 +455,7 @@ function parseHex(hex) {
|
|
|
582
455
|
}
|
|
583
456
|
function Notices() {
|
|
584
457
|
const notices = useWizard((s) => s.notices);
|
|
585
|
-
const { rows: windowRows } =
|
|
458
|
+
const { rows: windowRows } = useWindowSize2();
|
|
586
459
|
const visible = fitVisibleNotices(notices, windowRows);
|
|
587
460
|
const [pulseStep, setPulseStep] = useState2(0);
|
|
588
461
|
useEffect2(() => {
|
|
@@ -599,14 +472,14 @@ function Notices() {
|
|
|
599
472
|
}, []);
|
|
600
473
|
if (!visible.length) return null;
|
|
601
474
|
const pulseColor = PULSE_COLORS[pulseStep];
|
|
602
|
-
return /* @__PURE__ */ jsx2(
|
|
475
|
+
return /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", gap: 1, marginBottom: 1, children: visible.map((notice, i) => {
|
|
603
476
|
const isLatest = i === visible.length - 1;
|
|
604
|
-
return /* @__PURE__ */
|
|
477
|
+
return /* @__PURE__ */ jsxs(Box2, { flexDirection: "column", children: [
|
|
605
478
|
notice.messages?.map((m, j) => {
|
|
606
479
|
const line = typeof m === "string" ? { text: m } : m;
|
|
607
480
|
const prefix = j === 0 ? `${AGENT_MARKER} ` : " ";
|
|
608
|
-
return /* @__PURE__ */
|
|
609
|
-
|
|
481
|
+
return /* @__PURE__ */ jsxs(
|
|
482
|
+
Text2,
|
|
610
483
|
{
|
|
611
484
|
color: isLatest && !line.color ? pulseColor : line.color ?? COLORS.dim,
|
|
612
485
|
bold: line.bold,
|
|
@@ -624,41 +497,41 @@ function Notices() {
|
|
|
624
497
|
}
|
|
625
498
|
|
|
626
499
|
// src/ui/PromptInput.tsx
|
|
627
|
-
import { Box as
|
|
500
|
+
import { Box as Box6, Text as Text6, useInput as useInput2 } from "ink";
|
|
628
501
|
import TextInput from "ink-text-input";
|
|
629
502
|
import { useState as useState5 } from "react";
|
|
630
503
|
|
|
631
504
|
// src/ui/NextAction.tsx
|
|
632
|
-
import { Box as
|
|
633
|
-
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";
|
|
634
507
|
function NextAction({
|
|
635
508
|
action,
|
|
636
509
|
keyHint,
|
|
637
510
|
hierarchy = "primary"
|
|
638
511
|
}) {
|
|
639
|
-
return /* @__PURE__ */
|
|
640
|
-
hierarchy === "primary" && /* @__PURE__ */ jsx3(
|
|
641
|
-
hierarchy === "secondary" && /* @__PURE__ */
|
|
642
|
-
/* @__PURE__ */ jsx3(
|
|
643
|
-
/* @__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 })
|
|
644
517
|
] }),
|
|
645
|
-
/* @__PURE__ */
|
|
646
|
-
/* @__PURE__ */ jsx3(
|
|
647
|
-
/* @__PURE__ */ jsx3(
|
|
648
|
-
/* @__PURE__ */ jsx3(
|
|
649
|
-
/* @__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: `]` })
|
|
650
523
|
] })
|
|
651
524
|
] });
|
|
652
525
|
}
|
|
653
526
|
|
|
654
527
|
// src/ui/SelectPrompt.tsx
|
|
655
|
-
import { Box as
|
|
528
|
+
import { Box as Box5, Text as Text5, useInput, useWindowSize as useWindowSize4 } from "ink";
|
|
656
529
|
import { useLayoutEffect as useLayoutEffect2, useRef as useRef3, useState as useState4 } from "react";
|
|
657
530
|
|
|
658
531
|
// src/ui/ScrollView.tsx
|
|
659
|
-
import { Box as
|
|
532
|
+
import { Box as Box4, Text as Text4, measureElement as measureElement2, useWindowSize as useWindowSize3 } from "ink";
|
|
660
533
|
import { useCallback, useLayoutEffect, useRef as useRef2, useState as useState3 } from "react";
|
|
661
|
-
import { jsxs as
|
|
534
|
+
import { jsxs as jsxs3 } from "react/jsx-runtime";
|
|
662
535
|
var INDICATOR_ROWS = 2;
|
|
663
536
|
function fittedWidth(node, columns) {
|
|
664
537
|
let left = 0;
|
|
@@ -673,7 +546,7 @@ function useScrollWindow({
|
|
|
673
546
|
followBottom = false
|
|
674
547
|
}) {
|
|
675
548
|
const viewportRef = useRef2(null);
|
|
676
|
-
const { columns } =
|
|
549
|
+
const { columns } = useWindowSize3();
|
|
677
550
|
const [size, setSize] = useState3(
|
|
678
551
|
null
|
|
679
552
|
);
|
|
@@ -728,14 +601,14 @@ function useScrollWindow({
|
|
|
728
601
|
};
|
|
729
602
|
}
|
|
730
603
|
function ScrollView({ scroll, children }) {
|
|
731
|
-
return /* @__PURE__ */
|
|
732
|
-
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: [
|
|
733
606
|
"\u2191 ",
|
|
734
607
|
scroll.hiddenAbove,
|
|
735
608
|
" more"
|
|
736
609
|
] }),
|
|
737
610
|
children,
|
|
738
|
-
scroll.hiddenBelow > 0 && /* @__PURE__ */
|
|
611
|
+
scroll.hiddenBelow > 0 && /* @__PURE__ */ jsxs3(Text4, { color: COLORS.dim, children: [
|
|
739
612
|
"\u2193 ",
|
|
740
613
|
scroll.hiddenBelow,
|
|
741
614
|
" more"
|
|
@@ -744,7 +617,7 @@ function ScrollView({ scroll, children }) {
|
|
|
744
617
|
}
|
|
745
618
|
|
|
746
619
|
// src/ui/SelectPrompt.tsx
|
|
747
|
-
import { jsx as jsx4, jsxs as
|
|
620
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
748
621
|
var CANCEL = "cancel";
|
|
749
622
|
var ARROW_WIDTH = 4;
|
|
750
623
|
var COLUMN_GAP = 2;
|
|
@@ -775,7 +648,7 @@ function SelectPrompt({
|
|
|
775
648
|
if (multi) hints.push({ key: "[space]", label: "select" });
|
|
776
649
|
hints.push({ key: "[enter]", label: "confirm" });
|
|
777
650
|
const containerRef = useRef3(null);
|
|
778
|
-
const { columns } =
|
|
651
|
+
const { columns } = useWindowSize4();
|
|
779
652
|
const [width, setWidth] = useState4(columns);
|
|
780
653
|
useLayoutEffect2(() => {
|
|
781
654
|
if (!containerRef.current) return;
|
|
@@ -829,14 +702,14 @@ function SelectPrompt({
|
|
|
829
702
|
}
|
|
830
703
|
}
|
|
831
704
|
});
|
|
832
|
-
return /* @__PURE__ */ jsx4(
|
|
833
|
-
/* @__PURE__ */
|
|
834
|
-
error && /* @__PURE__ */ jsx4(
|
|
835
|
-
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}`)),
|
|
836
709
|
table && /* @__PURE__ */ jsx4(Table, { columns: table.columns, rows: table.rows }),
|
|
837
|
-
/* @__PURE__ */
|
|
838
|
-
question && /* @__PURE__ */ jsx4(
|
|
839
|
-
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 })
|
|
840
713
|
] })
|
|
841
714
|
] }),
|
|
842
715
|
/* @__PURE__ */ jsx4(ScrollView, { scroll, children: visible.map((option, visibleIndex) => {
|
|
@@ -846,39 +719,39 @@ function SelectPrompt({
|
|
|
846
719
|
const bullet = multi && !isCancel ? checked.has(i) ? "\u25CF " : "\u25CB " : "";
|
|
847
720
|
const sec = isCancel ? void 0 : secondary?.[i];
|
|
848
721
|
const labelColor = highlighted ? COLORS.highlight.fg : void 0;
|
|
849
|
-
const label = /* @__PURE__ */
|
|
722
|
+
const label = /* @__PURE__ */ jsxs4(Text5, { color: labelColor, wrap: "truncate", children: [
|
|
850
723
|
highlighted ? "\u276F " : " ",
|
|
851
724
|
bullet,
|
|
852
725
|
option
|
|
853
726
|
] });
|
|
854
727
|
const isText = sec?.kind === "text";
|
|
855
|
-
return /* @__PURE__ */
|
|
856
|
-
|
|
728
|
+
return /* @__PURE__ */ jsxs4(
|
|
729
|
+
Box5,
|
|
857
730
|
{
|
|
858
731
|
width: isText ? "100%" : barWidth,
|
|
859
732
|
paddingX: 1,
|
|
860
733
|
paddingY: 1,
|
|
861
734
|
backgroundColor: highlighted ? COLORS.highlight.bg : void 0,
|
|
862
735
|
children: [
|
|
863
|
-
/* @__PURE__ */ jsx4(
|
|
864
|
-
isText && textWidth > 0 && /* @__PURE__ */ jsx4(
|
|
865
|
-
|
|
736
|
+
/* @__PURE__ */ jsx4(Box5, { width: isText ? labelWidth : barLabelWidth, children: label }),
|
|
737
|
+
isText && textWidth > 0 && /* @__PURE__ */ jsx4(Box5, { width: textWidth, children: /* @__PURE__ */ jsx4(
|
|
738
|
+
Text5,
|
|
866
739
|
{
|
|
867
740
|
wrap: "truncate",
|
|
868
741
|
color: highlighted ? COLORS.primary : COLORS.muted,
|
|
869
742
|
children: sec.value
|
|
870
743
|
}
|
|
871
744
|
) }),
|
|
872
|
-
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 }) })
|
|
873
746
|
]
|
|
874
747
|
},
|
|
875
748
|
`row-${i}`
|
|
876
749
|
);
|
|
877
750
|
}) }),
|
|
878
|
-
/* @__PURE__ */ jsx4(
|
|
751
|
+
/* @__PURE__ */ jsx4(Box5, { flexShrink: 0, children: /* @__PURE__ */ jsx4(Text5, { children: hints.map(({ key, label }, i) => /* @__PURE__ */ jsxs4(Text5, { children: [
|
|
879
752
|
i > 0 ? " " : "",
|
|
880
|
-
/* @__PURE__ */ jsx4(
|
|
881
|
-
/* @__PURE__ */
|
|
753
|
+
/* @__PURE__ */ jsx4(Text5, { color: COLORS.primary, children: key }),
|
|
754
|
+
/* @__PURE__ */ jsxs4(Text5, { color: COLORS.dim, children: [
|
|
882
755
|
" ",
|
|
883
756
|
label
|
|
884
757
|
] })
|
|
@@ -887,7 +760,7 @@ function SelectPrompt({
|
|
|
887
760
|
}
|
|
888
761
|
|
|
889
762
|
// src/ui/PromptInput.tsx
|
|
890
|
-
import { jsx as jsx5, jsxs as
|
|
763
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
891
764
|
var ACCEPT_REJECT_OPTIONS = ["Accept", "Reject"];
|
|
892
765
|
function EnterToContinuePrompt({
|
|
893
766
|
question,
|
|
@@ -898,10 +771,10 @@ function EnterToContinuePrompt({
|
|
|
898
771
|
if (key.return) onDecide(true);
|
|
899
772
|
else if (key.escape) onDecide(false);
|
|
900
773
|
});
|
|
901
|
-
return /* @__PURE__ */
|
|
902
|
-
messages?.map((m, i) => /* @__PURE__ */ jsx5(
|
|
903
|
-
question && /* @__PURE__ */ jsx5(
|
|
904
|
-
/* @__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: [
|
|
905
778
|
/* @__PURE__ */ jsx5(NextAction, { action: "continue", keyHint: "enter" }),
|
|
906
779
|
/* @__PURE__ */ jsx5(NextAction, { action: "decline", keyHint: "esc", hierarchy: "secondary" })
|
|
907
780
|
] })
|
|
@@ -911,11 +784,11 @@ function PromptInput() {
|
|
|
911
784
|
const { phase, inputReq, submitInput } = useWizard();
|
|
912
785
|
const [draft, setDraft] = useState5("");
|
|
913
786
|
if (phase === "done" || phase === "error") {
|
|
914
|
-
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" }) });
|
|
915
788
|
}
|
|
916
789
|
if (phase !== "awaitingInput" || !inputReq) return null;
|
|
917
790
|
if (inputReq.promptType === "multipleChoice") {
|
|
918
|
-
return /* @__PURE__ */ jsx5(
|
|
791
|
+
return /* @__PURE__ */ jsx5(Box6, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
|
|
919
792
|
SelectPrompt,
|
|
920
793
|
{
|
|
921
794
|
question: inputReq.prompt,
|
|
@@ -932,7 +805,7 @@ function PromptInput() {
|
|
|
932
805
|
) });
|
|
933
806
|
}
|
|
934
807
|
if (inputReq.promptType === "multiSelect") {
|
|
935
|
-
return /* @__PURE__ */ jsx5(
|
|
808
|
+
return /* @__PURE__ */ jsx5(Box6, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
|
|
936
809
|
SelectPrompt,
|
|
937
810
|
{
|
|
938
811
|
multi: true,
|
|
@@ -947,7 +820,7 @@ function PromptInput() {
|
|
|
947
820
|
) });
|
|
948
821
|
}
|
|
949
822
|
if (inputReq.promptType === "notice") {
|
|
950
|
-
return /* @__PURE__ */ jsx5(
|
|
823
|
+
return /* @__PURE__ */ jsx5(Box6, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
|
|
951
824
|
SelectPrompt,
|
|
952
825
|
{
|
|
953
826
|
question: inputReq.prompt,
|
|
@@ -969,7 +842,7 @@ function PromptInput() {
|
|
|
969
842
|
}
|
|
970
843
|
if (inputReq.promptType === "acceptReject") {
|
|
971
844
|
const labels = inputReq.options?.length ? inputReq.options : ACCEPT_REJECT_OPTIONS;
|
|
972
|
-
return /* @__PURE__ */ jsx5(
|
|
845
|
+
return /* @__PURE__ */ jsx5(Box6, { flexGrow: 1, children: /* @__PURE__ */ jsx5(
|
|
973
846
|
SelectPrompt,
|
|
974
847
|
{
|
|
975
848
|
question: inputReq.prompt,
|
|
@@ -980,11 +853,11 @@ function PromptInput() {
|
|
|
980
853
|
}
|
|
981
854
|
) });
|
|
982
855
|
}
|
|
983
|
-
return /* @__PURE__ */
|
|
984
|
-
inputReq.error && /* @__PURE__ */ jsx5(
|
|
985
|
-
inputReq.messages?.map((m, i) => /* @__PURE__ */ jsx5(
|
|
986
|
-
/* @__PURE__ */
|
|
987
|
-
/* @__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: [
|
|
988
861
|
inputReq.prompt,
|
|
989
862
|
" "
|
|
990
863
|
] }),
|
|
@@ -1006,7 +879,7 @@ function PromptInput() {
|
|
|
1006
879
|
// src/ui/Welcome.tsx
|
|
1007
880
|
import { dirname as dirname2, join as join3 } from "node:path";
|
|
1008
881
|
import { fileURLToPath } from "node:url";
|
|
1009
|
-
import { Box as
|
|
882
|
+
import { Box as Box7, Spacer, Text as Text7, useInput as useInput3, useWindowSize as useWindowSize5 } from "ink";
|
|
1010
883
|
|
|
1011
884
|
// src/ui/copy/welcome.ts
|
|
1012
885
|
var sidebarItems = [
|
|
@@ -1034,27 +907,27 @@ var sidebarItems = [
|
|
|
1034
907
|
|
|
1035
908
|
// src/ui/Welcome.tsx
|
|
1036
909
|
import Image, { InkPictureProvider } from "ink-picture";
|
|
1037
|
-
import { jsx as jsx6, jsxs as
|
|
910
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1038
911
|
var IMAGE_PATH = join3(dirname2(fileURLToPath(import.meta.url)), "algolia.png");
|
|
1039
912
|
function SidebarItem({
|
|
1040
913
|
title,
|
|
1041
914
|
description
|
|
1042
915
|
}) {
|
|
1043
|
-
return /* @__PURE__ */
|
|
1044
|
-
/* @__PURE__ */
|
|
1045
|
-
/* @__PURE__ */ jsx6(
|
|
1046
|
-
/* @__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 })
|
|
1047
920
|
] }),
|
|
1048
|
-
/* @__PURE__ */
|
|
921
|
+
/* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", gap: 2, children: [
|
|
1049
922
|
/* @__PURE__ */ jsx6(Spacer, {}),
|
|
1050
|
-
/* @__PURE__ */ jsx6(
|
|
923
|
+
/* @__PURE__ */ jsx6(Text7, { color: COLORS.muted, children: description })
|
|
1051
924
|
] })
|
|
1052
925
|
] });
|
|
1053
926
|
}
|
|
1054
927
|
function Welcome() {
|
|
1055
928
|
const confirmStart = useWizard((s) => s.confirmStart);
|
|
1056
929
|
const openLearnMore = useWizard((s) => s.openLearnMore);
|
|
1057
|
-
const { rows } =
|
|
930
|
+
const { rows } = useWindowSize5();
|
|
1058
931
|
useInput3((input, key) => {
|
|
1059
932
|
if (key.return) confirmStart();
|
|
1060
933
|
else if (input === "i") openLearnMore();
|
|
@@ -1073,15 +946,15 @@ function Welcome() {
|
|
|
1073
946
|
if (rows < 30) {
|
|
1074
947
|
layout = scales["small"];
|
|
1075
948
|
}
|
|
1076
|
-
return /* @__PURE__ */
|
|
949
|
+
return /* @__PURE__ */ jsxs6(Box7, { flexDirection: "row", justifyContent: "space-between", width: "100%", children: [
|
|
1077
950
|
/* @__PURE__ */ jsx6(
|
|
1078
|
-
|
|
951
|
+
Box7,
|
|
1079
952
|
{
|
|
1080
953
|
paddingY: layout.main.padding.y,
|
|
1081
954
|
paddingX: layout.main.padding.x,
|
|
1082
955
|
flexDirection: "column",
|
|
1083
956
|
justifyContent: "center",
|
|
1084
|
-
children: /* @__PURE__ */
|
|
957
|
+
children: /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", gap: 2, children: [
|
|
1085
958
|
/* @__PURE__ */ jsx6(InkPictureProvider, { children: /* @__PURE__ */ jsx6(
|
|
1086
959
|
Image,
|
|
1087
960
|
{
|
|
@@ -1093,16 +966,16 @@ function Welcome() {
|
|
|
1093
966
|
protocol: "halfBlock"
|
|
1094
967
|
}
|
|
1095
968
|
) }),
|
|
1096
|
-
/* @__PURE__ */ jsx6(
|
|
1097
|
-
/* @__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: [
|
|
1098
971
|
/* @__PURE__ */ jsx6(NextAction, { action: "start wizard", keyHint: "enter" }),
|
|
1099
972
|
/* @__PURE__ */ jsx6(NextAction, { action: "learn more", keyHint: "i", hierarchy: "secondary" })
|
|
1100
973
|
] })
|
|
1101
974
|
] })
|
|
1102
975
|
}
|
|
1103
976
|
),
|
|
1104
|
-
/* @__PURE__ */
|
|
1105
|
-
|
|
977
|
+
/* @__PURE__ */ jsxs6(
|
|
978
|
+
Box7,
|
|
1106
979
|
{
|
|
1107
980
|
backgroundColor: COLORS.bg.sidebar,
|
|
1108
981
|
width: 40,
|
|
@@ -1112,7 +985,7 @@ function Welcome() {
|
|
|
1112
985
|
flexDirection: "column",
|
|
1113
986
|
justifyContent: "center",
|
|
1114
987
|
children: [
|
|
1115
|
-
/* @__PURE__ */ jsx6(
|
|
988
|
+
/* @__PURE__ */ jsx6(Text7, { color: COLORS.muted, children: "WHAT THIS WIZARD WILL DO" }),
|
|
1116
989
|
sidebarItems.map((i, idx) => /* @__PURE__ */ jsx6(SidebarItem, { title: i.title, description: i.description }, idx))
|
|
1117
990
|
]
|
|
1118
991
|
}
|
|
@@ -1122,7 +995,7 @@ function Welcome() {
|
|
|
1122
995
|
|
|
1123
996
|
// src/ui/LearnMore.tsx
|
|
1124
997
|
import { Fragment as Fragment2 } from "react";
|
|
1125
|
-
import { Box as
|
|
998
|
+
import { Box as Box8, Text as Text8, useInput as useInput4, useWindowSize as useWindowSize6 } from "ink";
|
|
1126
999
|
|
|
1127
1000
|
// src/ui/copy/learn-more.ts
|
|
1128
1001
|
var accessIntro = "Everything runs locally on your machine. Nothing is written or sent without an explicit yes from you.";
|
|
@@ -1159,7 +1032,7 @@ var policyLinks = [
|
|
|
1159
1032
|
];
|
|
1160
1033
|
|
|
1161
1034
|
// src/ui/LearnMore.tsx
|
|
1162
|
-
import { jsx as jsx7, jsxs as
|
|
1035
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1163
1036
|
var TAG_COLORS = {
|
|
1164
1037
|
READ: COLORS.success,
|
|
1165
1038
|
WRITE: COLORS.badge,
|
|
@@ -1175,25 +1048,25 @@ function NeverLine({
|
|
|
1175
1048
|
}) {
|
|
1176
1049
|
const used = segments.reduce((n, s) => n + s.text.length, 0);
|
|
1177
1050
|
const rightPad = Math.max(0, width - 2 - NEVER_BOX_PAD_X - used);
|
|
1178
|
-
return /* @__PURE__ */
|
|
1179
|
-
/* @__PURE__ */ jsx7(
|
|
1051
|
+
return /* @__PURE__ */ jsxs7(Text8, { children: [
|
|
1052
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.danger, children: "\u2502" }),
|
|
1180
1053
|
" ".repeat(NEVER_BOX_PAD_X),
|
|
1181
|
-
segments.map((s, i) => /* @__PURE__ */ jsx7(
|
|
1054
|
+
segments.map((s, i) => /* @__PURE__ */ jsx7(Text8, { color: s.color, bold: s.bold, children: s.text }, i)),
|
|
1182
1055
|
" ".repeat(rightPad),
|
|
1183
|
-
/* @__PURE__ */ jsx7(
|
|
1056
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.danger, children: "\u2502" })
|
|
1184
1057
|
] });
|
|
1185
1058
|
}
|
|
1186
1059
|
function LearnMore() {
|
|
1187
1060
|
const confirmStart = useWizard((s) => s.confirmStart);
|
|
1188
1061
|
const backToHome = useWizard((s) => s.backToHome);
|
|
1189
|
-
const { columns } =
|
|
1062
|
+
const { columns } = useWindowSize6();
|
|
1190
1063
|
const dividerWidth = Math.max(0, columns - PADDING_X * 2);
|
|
1191
1064
|
useInput4((_input, key) => {
|
|
1192
1065
|
if (key.escape) backToHome();
|
|
1193
1066
|
else if (key.return) confirmStart();
|
|
1194
1067
|
});
|
|
1195
|
-
return /* @__PURE__ */
|
|
1196
|
-
|
|
1068
|
+
return /* @__PURE__ */ jsxs7(
|
|
1069
|
+
Box8,
|
|
1197
1070
|
{
|
|
1198
1071
|
flexDirection: "column",
|
|
1199
1072
|
paddingX: PADDING_X,
|
|
@@ -1201,20 +1074,20 @@ function LearnMore() {
|
|
|
1201
1074
|
width: "100%",
|
|
1202
1075
|
gap: 1,
|
|
1203
1076
|
children: [
|
|
1204
|
-
/* @__PURE__ */ jsx7(
|
|
1205
|
-
/* @__PURE__ */ jsx7(
|
|
1206
|
-
/* @__PURE__ */ jsx7(
|
|
1207
|
-
/* @__PURE__ */ jsx7(
|
|
1208
|
-
/* @__PURE__ */
|
|
1209
|
-
/* @__PURE__ */ jsx7(
|
|
1210
|
-
/* @__PURE__ */ jsx7(
|
|
1211
|
-
/* @__PURE__ */ jsx7(
|
|
1212
|
-
/* @__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}` })
|
|
1213
1086
|
] }) })
|
|
1214
1087
|
] })
|
|
1215
1088
|
] }, item.tag)) }),
|
|
1216
|
-
/* @__PURE__ */
|
|
1217
|
-
/* @__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` }),
|
|
1218
1091
|
/* @__PURE__ */ jsx7(NeverLine, { width: dividerWidth }),
|
|
1219
1092
|
/* @__PURE__ */ jsx7(
|
|
1220
1093
|
NeverLine,
|
|
@@ -1223,7 +1096,7 @@ function LearnMore() {
|
|
|
1223
1096
|
segments: [{ text: "I NEVER", color: COLORS.danger, bold: true }]
|
|
1224
1097
|
}
|
|
1225
1098
|
),
|
|
1226
|
-
neverItems.map((item) => /* @__PURE__ */
|
|
1099
|
+
neverItems.map((item) => /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
1227
1100
|
/* @__PURE__ */ jsx7(NeverLine, { width: dividerWidth }),
|
|
1228
1101
|
/* @__PURE__ */ jsx7(
|
|
1229
1102
|
NeverLine,
|
|
@@ -1238,23 +1111,23 @@ function LearnMore() {
|
|
|
1238
1111
|
)
|
|
1239
1112
|
] }, item)),
|
|
1240
1113
|
/* @__PURE__ */ jsx7(NeverLine, { width: dividerWidth }),
|
|
1241
|
-
/* @__PURE__ */ jsx7(
|
|
1114
|
+
/* @__PURE__ */ jsx7(Text8, { color: COLORS.danger, children: `\u2570${"\u2500".repeat(Math.max(0, dividerWidth - 2))}\u256F` })
|
|
1242
1115
|
] }),
|
|
1243
|
-
/* @__PURE__ */ jsx7(
|
|
1244
|
-
/* @__PURE__ */ jsx7(
|
|
1245
|
-
/* @__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 })
|
|
1246
1119
|
] }, link.label)) }),
|
|
1247
|
-
/* @__PURE__ */
|
|
1248
|
-
/* @__PURE__ */
|
|
1249
|
-
/* @__PURE__ */ jsx7(
|
|
1250
|
-
/* @__PURE__ */ jsx7(
|
|
1251
|
-
/* @__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" })
|
|
1252
1125
|
] }),
|
|
1253
|
-
/* @__PURE__ */
|
|
1254
|
-
/* @__PURE__ */ jsx7(
|
|
1255
|
-
/* @__PURE__ */ jsx7(
|
|
1256
|
-
/* @__PURE__ */ jsx7(
|
|
1257
|
-
/* @__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" })
|
|
1258
1131
|
] })
|
|
1259
1132
|
] })
|
|
1260
1133
|
]
|
|
@@ -1263,10 +1136,10 @@ function LearnMore() {
|
|
|
1263
1136
|
}
|
|
1264
1137
|
|
|
1265
1138
|
// src/ui/Sidebar.tsx
|
|
1266
|
-
import { Box as
|
|
1139
|
+
import { Box as Box11, Text as Text11 } from "ink";
|
|
1267
1140
|
|
|
1268
1141
|
// src/ui/Steps.tsx
|
|
1269
|
-
import { Box as
|
|
1142
|
+
import { Box as Box9, Text as Text9 } from "ink";
|
|
1270
1143
|
import Spinner from "ink-spinner";
|
|
1271
1144
|
|
|
1272
1145
|
// src/core/persistence.ts
|
|
@@ -1295,11 +1168,11 @@ async function clearWorkflowState(workflowId) {
|
|
|
1295
1168
|
}
|
|
1296
1169
|
|
|
1297
1170
|
// src/ui/Steps.tsx
|
|
1298
|
-
import { jsx as jsx8, jsxs as
|
|
1171
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1299
1172
|
function Steps() {
|
|
1300
1173
|
const { steps } = useWizard();
|
|
1301
1174
|
const visibleSteps = steps.filter(isStepVisible);
|
|
1302
|
-
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: [
|
|
1303
1176
|
s.status === "running" ? /* @__PURE__ */ jsx8(Spinner, { type: "dots" }) : MARKER[s.status],
|
|
1304
1177
|
" ",
|
|
1305
1178
|
s.title
|
|
@@ -1309,7 +1182,7 @@ function CurrentStep() {
|
|
|
1309
1182
|
const { steps } = useWizard();
|
|
1310
1183
|
const currentStep = steps.filter(isStepVisible).find((s) => s.status === "running");
|
|
1311
1184
|
if (!currentStep) return null;
|
|
1312
|
-
return /* @__PURE__ */
|
|
1185
|
+
return /* @__PURE__ */ jsxs8(Text9, { color: COLORS.status.running, children: [
|
|
1313
1186
|
/* @__PURE__ */ jsx8(Spinner, { type: "dots" }),
|
|
1314
1187
|
" ",
|
|
1315
1188
|
` ${currentStep.title}`
|
|
@@ -1317,19 +1190,19 @@ function CurrentStep() {
|
|
|
1317
1190
|
}
|
|
1318
1191
|
|
|
1319
1192
|
// src/ui/Progress.tsx
|
|
1320
|
-
import { Box as
|
|
1321
|
-
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";
|
|
1322
1195
|
function Progress() {
|
|
1323
1196
|
const { steps, currentStepIndex } = useWizard();
|
|
1324
1197
|
const visibleSteps = steps.filter(isStepVisible);
|
|
1325
1198
|
if (visibleSteps.length === 0) return null;
|
|
1326
1199
|
const visibleCountThroughCurrent = steps.slice(0, currentStepIndex + 1).filter(isStepVisible).length;
|
|
1327
1200
|
const activeStepNumber = Math.max(1, visibleCountThroughCurrent);
|
|
1328
|
-
return /* @__PURE__ */
|
|
1329
|
-
/* @__PURE__ */ jsx9(
|
|
1330
|
-
/* @__PURE__ */ jsx9(
|
|
1331
|
-
/* @__PURE__ */ jsx9(
|
|
1332
|
-
/* @__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 })
|
|
1333
1206
|
] });
|
|
1334
1207
|
}
|
|
1335
1208
|
|
|
@@ -1340,10 +1213,10 @@ var sidebarCommands = [
|
|
|
1340
1213
|
];
|
|
1341
1214
|
|
|
1342
1215
|
// src/ui/Sidebar.tsx
|
|
1343
|
-
import { jsx as jsx10, jsxs as
|
|
1216
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1344
1217
|
function Sidebar() {
|
|
1345
|
-
return /* @__PURE__ */
|
|
1346
|
-
|
|
1218
|
+
return /* @__PURE__ */ jsxs10(
|
|
1219
|
+
Box11,
|
|
1347
1220
|
{
|
|
1348
1221
|
backgroundColor: "#14171E",
|
|
1349
1222
|
width: 30,
|
|
@@ -1352,16 +1225,16 @@ function Sidebar() {
|
|
|
1352
1225
|
flexDirection: "column",
|
|
1353
1226
|
justifyContent: "space-between",
|
|
1354
1227
|
children: [
|
|
1355
|
-
/* @__PURE__ */
|
|
1356
|
-
/* @__PURE__ */ jsx10(
|
|
1228
|
+
/* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", gap: 1, children: [
|
|
1229
|
+
/* @__PURE__ */ jsx10(Text11, { color: COLORS.muted, children: "PROGRESS" }),
|
|
1357
1230
|
/* @__PURE__ */ jsx10(Steps, {})
|
|
1358
1231
|
] }),
|
|
1359
|
-
/* @__PURE__ */
|
|
1232
|
+
/* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", gap: 1, children: [
|
|
1360
1233
|
/* @__PURE__ */ jsx10(Progress, {}),
|
|
1361
|
-
/* @__PURE__ */ jsx10(
|
|
1362
|
-
return /* @__PURE__ */
|
|
1363
|
-
/* @__PURE__ */ jsx10(
|
|
1364
|
-
/* @__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 })
|
|
1365
1238
|
] });
|
|
1366
1239
|
}) })
|
|
1367
1240
|
] })
|
|
@@ -1371,12 +1244,12 @@ function Sidebar() {
|
|
|
1371
1244
|
}
|
|
1372
1245
|
|
|
1373
1246
|
// src/ui/Ribbon.tsx
|
|
1374
|
-
import { Box as
|
|
1375
|
-
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";
|
|
1376
1249
|
function Ribbon() {
|
|
1377
1250
|
const firstCommand = sidebarCommands[0];
|
|
1378
|
-
return /* @__PURE__ */
|
|
1379
|
-
|
|
1251
|
+
return /* @__PURE__ */ jsxs11(
|
|
1252
|
+
Box12,
|
|
1380
1253
|
{
|
|
1381
1254
|
backgroundColor: "#14171E",
|
|
1382
1255
|
flexDirection: "row",
|
|
@@ -1386,9 +1259,9 @@ function Ribbon() {
|
|
|
1386
1259
|
children: [
|
|
1387
1260
|
/* @__PURE__ */ jsx11(Progress, {}),
|
|
1388
1261
|
/* @__PURE__ */ jsx11(CurrentStep, {}),
|
|
1389
|
-
/* @__PURE__ */
|
|
1390
|
-
/* @__PURE__ */ jsx11(
|
|
1391
|
-
/* @__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 })
|
|
1392
1265
|
] })
|
|
1393
1266
|
]
|
|
1394
1267
|
}
|
|
@@ -1399,8 +1272,8 @@ function Ribbon() {
|
|
|
1399
1272
|
import { useState as useState6 } from "react";
|
|
1400
1273
|
|
|
1401
1274
|
// src/ui/Logs.tsx
|
|
1402
|
-
import { Box as
|
|
1403
|
-
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";
|
|
1404
1277
|
var KIND_COLOR = {
|
|
1405
1278
|
tool: COLORS.primary,
|
|
1406
1279
|
prompt: COLORS.badge
|
|
@@ -1436,8 +1309,8 @@ function Logs() {
|
|
|
1436
1309
|
else if (key.downArrow) scroll.scrollBy(1);
|
|
1437
1310
|
});
|
|
1438
1311
|
const visible = logs.slice(scroll.offset, scroll.offset + scroll.capacity);
|
|
1439
|
-
return /* @__PURE__ */
|
|
1440
|
-
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." }),
|
|
1441
1314
|
/* @__PURE__ */ jsx12(ScrollView, { scroll, children: visible.map((entry) => {
|
|
1442
1315
|
const timestamp = `[${formatTimestamp(entry.startedAt)}]`;
|
|
1443
1316
|
const durationText = entry.kind === "tool" && entry.durationMs !== void 0 ? `${entry.durationMs}ms` : "";
|
|
@@ -1448,14 +1321,14 @@ function Logs() {
|
|
|
1448
1321
|
const name = truncate2(entry.name, budget);
|
|
1449
1322
|
budget -= name.length;
|
|
1450
1323
|
const preview = rawPreview ? truncate2(rawPreview, budget) : "";
|
|
1451
|
-
return /* @__PURE__ */
|
|
1452
|
-
/* @__PURE__ */ jsx12(
|
|
1453
|
-
/* @__PURE__ */ jsx12(
|
|
1454
|
-
preview && /* @__PURE__ */ jsx12(
|
|
1455
|
-
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 })
|
|
1456
1329
|
] }, entry.id);
|
|
1457
1330
|
}) }),
|
|
1458
|
-
/* @__PURE__ */ jsx12(
|
|
1331
|
+
/* @__PURE__ */ jsx12(Text13, { color: COLORS.dim, children: "\u2191/\u2193 scroll" })
|
|
1459
1332
|
] });
|
|
1460
1333
|
}
|
|
1461
1334
|
|
|
@@ -1647,11 +1520,11 @@ function track(event, payload) {
|
|
|
1647
1520
|
}
|
|
1648
1521
|
|
|
1649
1522
|
// src/ui/App.tsx
|
|
1650
|
-
import { jsx as jsx13, jsxs as
|
|
1523
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1651
1524
|
function App() {
|
|
1652
1525
|
const { phase, error, homeScreen, currentStepIndex, steps, inputReq } = useWizard();
|
|
1653
1526
|
const { exit } = useApp();
|
|
1654
|
-
const { columns, rows } =
|
|
1527
|
+
const { columns, rows } = useWindowSize7();
|
|
1655
1528
|
const [showLogs, setShowLogs] = useState6(false);
|
|
1656
1529
|
const finished = phase === "done" || phase === "error";
|
|
1657
1530
|
const currentStep = steps[currentStepIndex];
|
|
@@ -1664,7 +1537,7 @@ function App() {
|
|
|
1664
1537
|
{ isActive: finished }
|
|
1665
1538
|
);
|
|
1666
1539
|
useInput6((_input, key) => {
|
|
1667
|
-
if (phase === "idle" || phase === "
|
|
1540
|
+
if (phase === "idle" || phase === "preflight") return;
|
|
1668
1541
|
if (key.tab) {
|
|
1669
1542
|
setShowLogs(!showLogs);
|
|
1670
1543
|
track("AI Wizard Interaction", {
|
|
@@ -1674,7 +1547,7 @@ function App() {
|
|
|
1674
1547
|
});
|
|
1675
1548
|
}
|
|
1676
1549
|
});
|
|
1677
|
-
const escOwnedElsewhere = phase === "idle" || phase === "
|
|
1550
|
+
const escOwnedElsewhere = phase === "idle" || phase === "awaitingInput" && inputReq?.promptType === "enterToContinue";
|
|
1678
1551
|
useInput6((_input, key) => {
|
|
1679
1552
|
if (escOwnedElsewhere) return;
|
|
1680
1553
|
if (key.escape) {
|
|
@@ -1687,71 +1560,61 @@ function App() {
|
|
|
1687
1560
|
exit();
|
|
1688
1561
|
}
|
|
1689
1562
|
});
|
|
1690
|
-
const mainWindowVisible = phase === "
|
|
1563
|
+
const mainWindowVisible = phase === "running" || phase === "awaitingInput" || phase === "error" || phase === "done";
|
|
1691
1564
|
const flexDirection = columns > 90 ? "row" : "column";
|
|
1692
1565
|
const showSidebar = flexDirection === "row";
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
children: [
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
)
|
|
1746
|
-
),
|
|
1747
|
-
showSidebar ? /* @__PURE__ */ jsx13(Sidebar, {}) : /* @__PURE__ */ jsx13(Ribbon, {})
|
|
1748
|
-
]
|
|
1749
|
-
}
|
|
1750
|
-
),
|
|
1751
|
-
phase === "idle" && (homeScreen === "learnMore" ? /* @__PURE__ */ jsx13(LearnMore, {}) : /* @__PURE__ */ jsx13(Welcome, {}))
|
|
1752
|
-
]
|
|
1753
|
-
}
|
|
1754
|
-
)
|
|
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,
|
|
1593
|
+
{
|
|
1594
|
+
flexDirection: "column",
|
|
1595
|
+
paddingX: 4,
|
|
1596
|
+
paddingY: 2,
|
|
1597
|
+
width: showSidebar ? 70 : "100%",
|
|
1598
|
+
flexGrow: 1,
|
|
1599
|
+
children: [
|
|
1600
|
+
/* @__PURE__ */ jsx13(Notices, {}),
|
|
1601
|
+
/* @__PURE__ */ jsx13(PromptInput, {}),
|
|
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: [
|
|
1604
|
+
"\u2716 ",
|
|
1605
|
+
error
|
|
1606
|
+
] }) })
|
|
1607
|
+
]
|
|
1608
|
+
}
|
|
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
|
+
}
|
|
1755
1618
|
);
|
|
1756
1619
|
}
|
|
1757
1620
|
|
|
@@ -1987,138 +1850,61 @@ async function runWorkflow(workflow, appId) {
|
|
|
1987
1850
|
}
|
|
1988
1851
|
}
|
|
1989
1852
|
|
|
1990
|
-
// src/lib/
|
|
1991
|
-
import {
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
);
|
|
2004
|
-
async function currentApplication() {
|
|
2005
|
-
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;
|
|
2006
1866
|
try {
|
|
2007
|
-
|
|
1867
|
+
parsed = parseToml(tomlText);
|
|
2008
1868
|
} catch {
|
|
2009
|
-
return
|
|
1869
|
+
return [];
|
|
2010
1870
|
}
|
|
2011
|
-
const
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
}
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
const raw = await runAlgoliaCli(["application", "list", "-o", "json"]);
|
|
2025
|
-
const parsed = listSchema.safeParse(parseJson(raw));
|
|
2026
|
-
if (!parsed.success) {
|
|
2027
|
-
throw new Error("Could not read the list of Algolia applications.");
|
|
2028
|
-
}
|
|
2029
|
-
return parsed.data;
|
|
2030
|
-
}
|
|
2031
|
-
async function selectApplication(id) {
|
|
2032
|
-
const raw = await runAlgoliaCli(
|
|
2033
|
-
["application", "select", "--non-interactive", "--app-id", id],
|
|
2034
|
-
{ onOutput: stderrSink }
|
|
2035
|
-
);
|
|
2036
|
-
const parsed = applicationSchema.safeParse(parseJson(raw));
|
|
2037
|
-
if (!parsed.success) {
|
|
2038
|
-
throw new Error(
|
|
2039
|
-
`Selected application ${id}, but the Algolia CLI returned an unreadable result.`
|
|
2040
|
-
);
|
|
2041
|
-
}
|
|
2042
|
-
return parsed.data;
|
|
2043
|
-
}
|
|
2044
|
-
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;
|
|
2045
1884
|
try {
|
|
2046
|
-
|
|
1885
|
+
profiles = profilesFromConfig(await readFile3(configPath(), "utf8"));
|
|
2047
1886
|
} catch {
|
|
2048
|
-
|
|
1887
|
+
profiles = [];
|
|
2049
1888
|
}
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
// src/lib/algoliaAppPicker.ts
|
|
2053
|
-
function secondaryFor(app) {
|
|
2054
|
-
return app.plan ? { kind: "badge", value: app.plan } : void 0;
|
|
2055
|
-
}
|
|
2056
|
-
function labelFor(app) {
|
|
2057
|
-
return app.name.trim() ? `${app.name} \u2014 ${app.id}` : app.id;
|
|
2058
|
-
}
|
|
2059
|
-
function selectAndReport(app) {
|
|
2060
|
-
useWizard.getState().pushCliOutput(
|
|
2061
|
-
"stdout",
|
|
2062
|
-
`Selecting ${labelFor(app)} \u2014 provisioning its API key\u2026`
|
|
2063
|
-
);
|
|
2064
|
-
return selectApplication(app.id);
|
|
2065
|
-
}
|
|
2066
|
-
async function promptForApplication() {
|
|
2067
|
-
const store = useWizard.getState();
|
|
2068
|
-
const apps = await listApplications();
|
|
2069
|
-
if (apps.length === 0) {
|
|
1889
|
+
const profile = profiles[0];
|
|
1890
|
+
if (!profile) {
|
|
2070
1891
|
throw new Error(
|
|
2071
|
-
"
|
|
2072
|
-
);
|
|
2073
|
-
}
|
|
2074
|
-
if (apps.length === 1) {
|
|
2075
|
-
const only = apps[0];
|
|
2076
|
-
logger.info(
|
|
2077
|
-
{ app: only.id },
|
|
2078
|
-
"single application on the account; selecting it"
|
|
1892
|
+
"No Algolia profile is configured. Run `npx @algolia/cli auth login` to authenticate."
|
|
2079
1893
|
);
|
|
2080
|
-
return selectAndReport(only);
|
|
2081
|
-
}
|
|
2082
|
-
const messages = ["Which Algolia application should the wizard work in?"];
|
|
2083
|
-
for (; ; ) {
|
|
2084
|
-
const choice = await store.requestUserInput({
|
|
2085
|
-
prompt: "Select an application",
|
|
2086
|
-
promptType: "multipleChoice",
|
|
2087
|
-
options: apps.map(labelFor),
|
|
2088
|
-
secondary: apps.map(secondaryFor),
|
|
2089
|
-
messages
|
|
2090
|
-
});
|
|
2091
|
-
const chosen = apps.find((app) => labelFor(app) === choice);
|
|
2092
|
-
if (!chosen) {
|
|
2093
|
-
throw new Error("Application picker received an unexpected selection");
|
|
2094
|
-
}
|
|
2095
|
-
try {
|
|
2096
|
-
return await selectAndReport(chosen);
|
|
2097
|
-
} catch (err) {
|
|
2098
|
-
logger.warn(
|
|
2099
|
-
{ app: chosen.id, err: err.message },
|
|
2100
|
-
"application select failed; re-prompting"
|
|
2101
|
-
);
|
|
2102
|
-
messages.push(
|
|
2103
|
-
`Could not select \u201C${labelFor(chosen)}\u201D. It may have been removed \u2014 pick another.`
|
|
2104
|
-
);
|
|
2105
|
-
}
|
|
2106
1894
|
}
|
|
2107
|
-
|
|
2108
|
-
async function ensureApplication() {
|
|
2109
|
-
return await currentApplication() ?? await promptForApplication();
|
|
1895
|
+
return profile;
|
|
2110
1896
|
}
|
|
2111
1897
|
|
|
2112
1898
|
// src/workflows/default.ts
|
|
2113
|
-
import { z as
|
|
1899
|
+
import { z as z25 } from "zod";
|
|
2114
1900
|
|
|
2115
1901
|
// src/actions/listIndices.ts
|
|
2116
|
-
import { z as
|
|
2117
|
-
var indicesListSchema =
|
|
2118
|
-
items:
|
|
2119
|
-
|
|
2120
|
-
name:
|
|
2121
|
-
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)
|
|
2122
1908
|
})
|
|
2123
1909
|
)
|
|
2124
1910
|
});
|
|
@@ -2189,12 +1975,12 @@ import "zod";
|
|
|
2189
1975
|
|
|
2190
1976
|
// src/lib/tools/listFiles.ts
|
|
2191
1977
|
import { tool } from "ai";
|
|
2192
|
-
import
|
|
1978
|
+
import z4 from "zod";
|
|
2193
1979
|
import { readdir } from "node:fs/promises";
|
|
2194
1980
|
|
|
2195
1981
|
// src/lib/tools/path.ts
|
|
2196
1982
|
import { lstat } from "node:fs/promises";
|
|
2197
|
-
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";
|
|
2198
1984
|
function resolveInRoot(ctx, path) {
|
|
2199
1985
|
const target = resolve2(ctx.cwd, path);
|
|
2200
1986
|
const rel = relative(ctx.root, target);
|
|
@@ -2210,7 +1996,7 @@ async function hasSymlinkParent(ctx, target) {
|
|
|
2210
1996
|
let current = ctx.root;
|
|
2211
1997
|
const parts = relative(ctx.root, dirname3(target)).split(sep).filter(Boolean);
|
|
2212
1998
|
for (const part of parts) {
|
|
2213
|
-
current =
|
|
1999
|
+
current = join7(current, part);
|
|
2214
2000
|
try {
|
|
2215
2001
|
if ((await lstat(current)).isSymbolicLink()) return true;
|
|
2216
2002
|
} catch (err) {
|
|
@@ -2225,7 +2011,7 @@ async function hasSymlinkParent(ctx, target) {
|
|
|
2225
2011
|
function listFilesTool(ctx) {
|
|
2226
2012
|
return tool({
|
|
2227
2013
|
description: "List files in the current working directory",
|
|
2228
|
-
inputSchema:
|
|
2014
|
+
inputSchema: z4.object(),
|
|
2229
2015
|
execute: async () => {
|
|
2230
2016
|
logger.info("called listFiles tool");
|
|
2231
2017
|
if (++ctx.counts.list > ctx.limits.list) {
|
|
@@ -2241,13 +2027,13 @@ function listFilesTool(ctx) {
|
|
|
2241
2027
|
|
|
2242
2028
|
// src/lib/tools/changeDirectory.ts
|
|
2243
2029
|
import { tool as tool2 } from "ai";
|
|
2244
|
-
import
|
|
2030
|
+
import z5 from "zod";
|
|
2245
2031
|
import { stat } from "node:fs/promises";
|
|
2246
2032
|
function changeDirectoryTool(ctx) {
|
|
2247
2033
|
return tool2({
|
|
2248
2034
|
description: "Change the current working directory. Subsequent file operations resolve relative to it. Returns the new working directory.",
|
|
2249
|
-
inputSchema:
|
|
2250
|
-
path:
|
|
2035
|
+
inputSchema: z5.object({
|
|
2036
|
+
path: z5.string().describe("Directory to change into")
|
|
2251
2037
|
}),
|
|
2252
2038
|
execute: async ({ path }) => {
|
|
2253
2039
|
logger.info({ path }, "called changeDirectory tool");
|
|
@@ -2269,13 +2055,13 @@ function changeDirectoryTool(ctx) {
|
|
|
2269
2055
|
|
|
2270
2056
|
// src/lib/tools/reportStatus.ts
|
|
2271
2057
|
import { tool as tool3 } from "ai";
|
|
2272
|
-
import
|
|
2058
|
+
import z6 from "zod";
|
|
2273
2059
|
function reportStatusTool(output) {
|
|
2274
2060
|
return tool3({
|
|
2275
2061
|
description: "Report the status of your execution. Return a reason in case of failure.",
|
|
2276
|
-
inputSchema:
|
|
2277
|
-
status:
|
|
2278
|
-
reason:
|
|
2062
|
+
inputSchema: z6.object({
|
|
2063
|
+
status: z6.enum(["success", "fail"]),
|
|
2064
|
+
reason: z6.string().optional(),
|
|
2279
2065
|
output
|
|
2280
2066
|
}),
|
|
2281
2067
|
execute: async ({ status, reason, output: output2 }) => {
|
|
@@ -2287,8 +2073,8 @@ function reportStatusTool(output) {
|
|
|
2287
2073
|
|
|
2288
2074
|
// src/lib/tools/readFile.ts
|
|
2289
2075
|
import { tool as tool4 } from "ai";
|
|
2290
|
-
import
|
|
2291
|
-
import { readFile as
|
|
2076
|
+
import z7 from "zod";
|
|
2077
|
+
import { readFile as readFile4 } from "node:fs/promises";
|
|
2292
2078
|
|
|
2293
2079
|
// src/lib/tools/env.ts
|
|
2294
2080
|
import { basename } from "node:path";
|
|
@@ -2315,8 +2101,8 @@ function redactEnvValues(content) {
|
|
|
2315
2101
|
function readFileTool(ctx) {
|
|
2316
2102
|
return tool4({
|
|
2317
2103
|
description: "Read the contents of a file at the given path",
|
|
2318
|
-
inputSchema:
|
|
2319
|
-
filePath:
|
|
2104
|
+
inputSchema: z7.object({
|
|
2105
|
+
filePath: z7.string().describe("Path to the file to read")
|
|
2320
2106
|
}),
|
|
2321
2107
|
execute: async ({ filePath }) => {
|
|
2322
2108
|
if (++ctx.counts.read > ctx.limits.read) {
|
|
@@ -2326,7 +2112,7 @@ function readFileTool(ctx) {
|
|
|
2326
2112
|
const resolved = resolveInRoot(ctx, filePath);
|
|
2327
2113
|
if (!resolved.ok) return resolved.error;
|
|
2328
2114
|
try {
|
|
2329
|
-
const content = await
|
|
2115
|
+
const content = await readFile4(resolved.target, "utf8");
|
|
2330
2116
|
return isEnvFile(resolved.target) ? redactEnvValues(content) : content;
|
|
2331
2117
|
} catch (err) {
|
|
2332
2118
|
return `Error reading ${filePath}: ${err.message}`;
|
|
@@ -2337,15 +2123,15 @@ function readFileTool(ctx) {
|
|
|
2337
2123
|
|
|
2338
2124
|
// src/lib/tools/writeFile.ts
|
|
2339
2125
|
import { tool as tool5 } from "ai";
|
|
2340
|
-
import
|
|
2126
|
+
import z8 from "zod";
|
|
2341
2127
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
|
|
2342
2128
|
import { dirname as dirname4 } from "node:path";
|
|
2343
2129
|
function writeFileTool(ctx) {
|
|
2344
2130
|
return tool5({
|
|
2345
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.",
|
|
2346
|
-
inputSchema:
|
|
2347
|
-
filePath:
|
|
2348
|
-
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")
|
|
2349
2135
|
}),
|
|
2350
2136
|
execute: async ({ filePath, content }) => {
|
|
2351
2137
|
logger.info({ filePath }, "called writeFile tool");
|
|
@@ -2370,95 +2156,9 @@ function writeFileTool(ctx) {
|
|
|
2370
2156
|
|
|
2371
2157
|
// src/lib/tools/writeAlgoliaCredentials.ts
|
|
2372
2158
|
import { tool as tool6 } from "ai";
|
|
2373
|
-
import
|
|
2374
|
-
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";
|
|
2375
2161
|
import { dirname as dirname5 } from "node:path";
|
|
2376
|
-
|
|
2377
|
-
// src/lib/algoliaApiKey.ts
|
|
2378
|
-
import { z as z11 } from "zod";
|
|
2379
|
-
var SAFE_ACLS = /* @__PURE__ */ new Set(["search", "browse", "listIndexes"]);
|
|
2380
|
-
var WRITE_ACLS = [
|
|
2381
|
-
"addObject",
|
|
2382
|
-
"deleteObject",
|
|
2383
|
-
"settings",
|
|
2384
|
-
"editSettings",
|
|
2385
|
-
"listIndexes"
|
|
2386
|
-
];
|
|
2387
|
-
var WRITE_ACL_SET = new Set(WRITE_ACLS);
|
|
2388
|
-
var apiKeySchema = z11.object({
|
|
2389
|
-
value: z11.string().min(1),
|
|
2390
|
-
acl: z11.array(z11.string()).default([]),
|
|
2391
|
-
indexes: z11.array(z11.string()).default([])
|
|
2392
|
-
});
|
|
2393
|
-
var apiKeyListSchema = z11.object({
|
|
2394
|
-
items: z11.array(apiKeySchema).optional(),
|
|
2395
|
-
keys: z11.array(apiKeySchema).optional()
|
|
2396
|
-
}).transform((o) => o.items ?? o.keys ?? []);
|
|
2397
|
-
var createdKeySchema = z11.object({
|
|
2398
|
-
key: z11.string().min(1).optional(),
|
|
2399
|
-
value: z11.string().min(1).optional()
|
|
2400
|
-
});
|
|
2401
|
-
function canReuse(key, index) {
|
|
2402
|
-
return key.acl.includes("search") && key.acl.every((acl) => SAFE_ACLS.has(acl)) && (key.indexes.length === 0 || key.indexes.includes("*") || key.indexes.includes(index));
|
|
2403
|
-
}
|
|
2404
|
-
async function createSearchKey(index) {
|
|
2405
|
-
const stdout = await runAlgoliaCli([
|
|
2406
|
-
"apikeys",
|
|
2407
|
-
"create",
|
|
2408
|
-
"--indices",
|
|
2409
|
-
index,
|
|
2410
|
-
"--acl",
|
|
2411
|
-
"search,browse",
|
|
2412
|
-
"--description",
|
|
2413
|
-
`wizard search-only key for ${index}`,
|
|
2414
|
-
"-o",
|
|
2415
|
-
"json"
|
|
2416
|
-
]);
|
|
2417
|
-
const { key, value } = createdKeySchema.parse(JSON.parse(stdout));
|
|
2418
|
-
const created = key ?? value;
|
|
2419
|
-
if (!created) throw new Error("apikeys create returned no key value");
|
|
2420
|
-
return created;
|
|
2421
|
-
}
|
|
2422
|
-
function canReuseForWrites(key, index) {
|
|
2423
|
-
return WRITE_ACLS.every((acl) => key.acl.includes(acl)) && key.acl.every((acl) => WRITE_ACL_SET.has(acl)) && key.indexes.includes(index);
|
|
2424
|
-
}
|
|
2425
|
-
async function resolveWriteKey(index) {
|
|
2426
|
-
const stdout = await runAlgoliaCli(["apikeys", "list", "-o", "json"]);
|
|
2427
|
-
const existing = apiKeyListSchema.parse(JSON.parse(stdout)).find((key2) => canReuseForWrites(key2, index))?.value;
|
|
2428
|
-
if (existing) {
|
|
2429
|
-
logger.info({ index }, "reusing existing write API key");
|
|
2430
|
-
return existing;
|
|
2431
|
-
}
|
|
2432
|
-
logger.info({ index }, "no reusable write key found; creating one");
|
|
2433
|
-
const created = await runAlgoliaCli([
|
|
2434
|
-
"apikeys",
|
|
2435
|
-
"create",
|
|
2436
|
-
"--indices",
|
|
2437
|
-
index,
|
|
2438
|
-
"--acl",
|
|
2439
|
-
WRITE_ACLS.join(","),
|
|
2440
|
-
"--description",
|
|
2441
|
-
`wizard write key for ${index}`,
|
|
2442
|
-
"-o",
|
|
2443
|
-
"json"
|
|
2444
|
-
]);
|
|
2445
|
-
const { key, value } = createdKeySchema.parse(JSON.parse(created));
|
|
2446
|
-
const writeKey = key ?? value;
|
|
2447
|
-
if (!writeKey) throw new Error("apikeys create returned no key value");
|
|
2448
|
-
return writeKey;
|
|
2449
|
-
}
|
|
2450
|
-
async function resolveSearchOnlyKey(index) {
|
|
2451
|
-
const stdout = await runAlgoliaCli(["apikeys", "list", "-o", "json"]);
|
|
2452
|
-
const existing = apiKeyListSchema.parse(JSON.parse(stdout)).find((key) => canReuse(key, index))?.value;
|
|
2453
|
-
if (existing) {
|
|
2454
|
-
logger.info({ index }, "reusing existing search-only API key");
|
|
2455
|
-
return existing;
|
|
2456
|
-
}
|
|
2457
|
-
logger.info({ index }, "no reusable search-only key found; creating one");
|
|
2458
|
-
return createSearchKey(index);
|
|
2459
|
-
}
|
|
2460
|
-
|
|
2461
|
-
// src/lib/tools/writeAlgoliaCredentials.ts
|
|
2462
2162
|
var APP_ID_VAR = "ALGOLIA_APPLICATION_ID";
|
|
2463
2163
|
var API_KEY_VAR = "ALGOLIA_WRITE_API_KEY";
|
|
2464
2164
|
function appendEnv(content, entries) {
|
|
@@ -2472,9 +2172,9 @@ function hasEnv(content, name) {
|
|
|
2472
2172
|
}
|
|
2473
2173
|
function writeCredentialsTool(ctx) {
|
|
2474
2174
|
return tool6({
|
|
2475
|
-
description: `Write the active Algolia credentials (${APP_ID_VAR} and ${API_KEY_VAR}) into the given env file. The credentials
|
|
2476
|
-
inputSchema:
|
|
2477
|
-
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(
|
|
2478
2178
|
'Path to the env file to write credentials into (e.g. ".env")'
|
|
2479
2179
|
)
|
|
2480
2180
|
}),
|
|
@@ -2482,17 +2182,11 @@ function writeCredentialsTool(ctx) {
|
|
|
2482
2182
|
logger.info({ filePath }, "called writeCredentials tool");
|
|
2483
2183
|
const resolved = resolveInRoot(ctx, filePath);
|
|
2484
2184
|
if (resolved.ok === false) return resolved.error;
|
|
2485
|
-
|
|
2486
|
-
if (!targetIndex) {
|
|
2487
|
-
return "Error: no target index is set for this run, so a scoped write key cannot be provisioned.";
|
|
2488
|
-
}
|
|
2489
|
-
let appId;
|
|
2490
|
-
let writeKey;
|
|
2185
|
+
let profile;
|
|
2491
2186
|
try {
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
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.";
|
|
2496
2190
|
}
|
|
2497
2191
|
try {
|
|
2498
2192
|
if (await hasSymlinkParent(ctx, resolved.target)) {
|
|
@@ -2500,7 +2194,7 @@ function writeCredentialsTool(ctx) {
|
|
|
2500
2194
|
}
|
|
2501
2195
|
let existing = "";
|
|
2502
2196
|
try {
|
|
2503
|
-
existing = await
|
|
2197
|
+
existing = await readFile5(resolved.target, "utf8");
|
|
2504
2198
|
} catch (err) {
|
|
2505
2199
|
if (err.code !== "ENOENT") throw err;
|
|
2506
2200
|
}
|
|
@@ -2511,8 +2205,8 @@ function writeCredentialsTool(ctx) {
|
|
|
2511
2205
|
return `Skipped: ${filePath} already defines ${present.join(" and ")}. Leaving existing credentials untouched.`;
|
|
2512
2206
|
}
|
|
2513
2207
|
const envWithCredentials = appendEnv(existing, [
|
|
2514
|
-
[APP_ID_VAR, appId],
|
|
2515
|
-
[API_KEY_VAR,
|
|
2208
|
+
[APP_ID_VAR, profile.appId],
|
|
2209
|
+
[API_KEY_VAR, profile.apiKey]
|
|
2516
2210
|
]);
|
|
2517
2211
|
await mkdir4(dirname5(resolved.target), { recursive: true });
|
|
2518
2212
|
await writeFile4(resolved.target, envWithCredentials, "utf8");
|
|
@@ -2526,16 +2220,16 @@ function writeCredentialsTool(ctx) {
|
|
|
2526
2220
|
|
|
2527
2221
|
// src/lib/tools/searchFiles.ts
|
|
2528
2222
|
import { tool as tool7 } from "ai";
|
|
2529
|
-
import
|
|
2530
|
-
import { readdir as readdir2, readFile as
|
|
2531
|
-
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";
|
|
2532
2226
|
var MAX_QUERY_LENGTH = 1e3;
|
|
2533
2227
|
async function walkFiles(dir) {
|
|
2534
2228
|
const skip = /* @__PURE__ */ new Set(["node_modules", ".git", "dist"]);
|
|
2535
2229
|
const out = [];
|
|
2536
2230
|
for (const e of await readdir2(dir, { withFileTypes: true })) {
|
|
2537
2231
|
if (e.name.startsWith(".") || skip.has(e.name)) continue;
|
|
2538
|
-
const full =
|
|
2232
|
+
const full = join8(dir, e.name);
|
|
2539
2233
|
if (e.isDirectory()) out.push(...await walkFiles(full));
|
|
2540
2234
|
else if (e.isFile()) out.push(full);
|
|
2541
2235
|
}
|
|
@@ -2544,9 +2238,9 @@ async function walkFiles(dir) {
|
|
|
2544
2238
|
function searchFilesTool(ctx) {
|
|
2545
2239
|
return tool7({
|
|
2546
2240
|
description: "Search file contents for a JavaScript regular expression (RegExp syntax, not grep/PCRE). Returns matching lines as file:line:text.",
|
|
2547
|
-
inputSchema:
|
|
2548
|
-
query:
|
|
2549
|
-
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)")
|
|
2550
2244
|
}),
|
|
2551
2245
|
execute: async ({ query, path = "." }) => {
|
|
2552
2246
|
logger.info({ query, path }, "called searchFiles tool");
|
|
@@ -2568,7 +2262,7 @@ function searchFilesTool(ctx) {
|
|
|
2568
2262
|
for (const file of await walkFiles(resolved.target)) {
|
|
2569
2263
|
let content;
|
|
2570
2264
|
try {
|
|
2571
|
-
content = await
|
|
2265
|
+
content = await readFile6(file, "utf8");
|
|
2572
2266
|
} catch {
|
|
2573
2267
|
continue;
|
|
2574
2268
|
}
|
|
@@ -2590,31 +2284,63 @@ function searchFilesTool(ctx) {
|
|
|
2590
2284
|
|
|
2591
2285
|
// src/lib/tools/verifyImplementation.ts
|
|
2592
2286
|
import { tool as tool8 } from "ai";
|
|
2593
|
-
import
|
|
2287
|
+
import z11 from "zod";
|
|
2594
2288
|
|
|
2595
2289
|
// src/lib/tools/utils/runCommand.ts
|
|
2596
2290
|
import { spawn as spawn2 } from "node:child_process";
|
|
2597
|
-
|
|
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;
|
|
2598
2297
|
return new Promise((resolve4) => {
|
|
2599
2298
|
let output = "";
|
|
2299
|
+
let settled = false;
|
|
2600
2300
|
const child = spawn2(command, args, {
|
|
2601
2301
|
cwd,
|
|
2602
|
-
|
|
2302
|
+
shell: false,
|
|
2303
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
2304
|
+
...env ? { env: { ...process.env, ...env } } : {}
|
|
2603
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);
|
|
2604
2323
|
child.stdout?.on("data", (d) => output += d);
|
|
2605
2324
|
child.stderr?.on("data", (d) => output += d);
|
|
2606
2325
|
child.on(
|
|
2607
2326
|
"error",
|
|
2608
|
-
(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 })
|
|
2609
2336
|
);
|
|
2610
|
-
child.on("close", (code) => resolve4({ code: code ?? 1, output }));
|
|
2611
2337
|
});
|
|
2612
2338
|
}
|
|
2613
2339
|
|
|
2614
2340
|
// src/lib/tools/utils/packageManager.ts
|
|
2615
|
-
import { readFile as
|
|
2341
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
2616
2342
|
import { existsSync } from "node:fs";
|
|
2617
|
-
import { join as
|
|
2343
|
+
import { join as join9 } from "node:path";
|
|
2618
2344
|
var LOCKFILES = [
|
|
2619
2345
|
["pnpm-lock.yaml", "pnpm"],
|
|
2620
2346
|
["yarn.lock", "yarn"],
|
|
@@ -2623,13 +2349,13 @@ var LOCKFILES = [
|
|
|
2623
2349
|
["package-lock.json", "npm"]
|
|
2624
2350
|
];
|
|
2625
2351
|
async function readPackageJson(cwd = process.cwd()) {
|
|
2626
|
-
return JSON.parse(await
|
|
2352
|
+
return JSON.parse(await readFile7(join9(cwd, "package.json"), "utf8"));
|
|
2627
2353
|
}
|
|
2628
2354
|
function packageManagerFrom(pkg) {
|
|
2629
2355
|
return pkg.packageManager?.split("@")[0] ?? "npm";
|
|
2630
2356
|
}
|
|
2631
2357
|
function packageManagerFromLockfile(cwd) {
|
|
2632
|
-
return LOCKFILES.find(([file]) => existsSync(
|
|
2358
|
+
return LOCKFILES.find(([file]) => existsSync(join9(cwd, file)))?.[1];
|
|
2633
2359
|
}
|
|
2634
2360
|
async function detectPackageManager(cwd) {
|
|
2635
2361
|
try {
|
|
@@ -2660,7 +2386,9 @@ async function runRepoVerificationCheck() {
|
|
|
2660
2386
|
const checks = [];
|
|
2661
2387
|
for (const script of present) {
|
|
2662
2388
|
const command = `${pm} run ${script}`;
|
|
2663
|
-
const { code, output } = await runCommand(pm, ["run", script]
|
|
2389
|
+
const { code, output } = await runCommand(pm, ["run", script], {
|
|
2390
|
+
timeoutMs: VERIFY_TIMEOUT_MS
|
|
2391
|
+
});
|
|
2664
2392
|
checks.push({ command, exitCode: code, ok: code === 0, output: output.trim() });
|
|
2665
2393
|
}
|
|
2666
2394
|
return { ok: checks.every((c) => c.ok), checks };
|
|
@@ -2670,7 +2398,7 @@ async function runRepoVerificationCheck() {
|
|
|
2670
2398
|
function verifyImplementationTool() {
|
|
2671
2399
|
return tool8({
|
|
2672
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.",
|
|
2673
|
-
inputSchema:
|
|
2401
|
+
inputSchema: z11.object(),
|
|
2674
2402
|
execute: async () => {
|
|
2675
2403
|
logger.info("called verifyImplementation tool");
|
|
2676
2404
|
return runRepoVerificationCheck();
|
|
@@ -2684,7 +2412,7 @@ import { createAnthropic } from "@ai-sdk/anthropic";
|
|
|
2684
2412
|
import { nanoid as nanoid2 } from "nanoid";
|
|
2685
2413
|
import { mkdir as mkdir5, writeFile as writeFile5 } from "node:fs/promises";
|
|
2686
2414
|
import { dirname as dirname6 } from "node:path";
|
|
2687
|
-
import
|
|
2415
|
+
import z12 from "zod";
|
|
2688
2416
|
var DATA_DIR = ".algolia-wizard/data";
|
|
2689
2417
|
var RECORD_MODEL = "claude-haiku-4-5";
|
|
2690
2418
|
var MAX_RECORDS = 100;
|
|
@@ -2696,17 +2424,17 @@ var anthropic = createAnthropic({
|
|
|
2696
2424
|
function generateRecordTool(ctx) {
|
|
2697
2425
|
return tool9({
|
|
2698
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.",
|
|
2699
|
-
inputSchema:
|
|
2700
|
-
entityName:
|
|
2701
|
-
attributes:
|
|
2702
|
-
count:
|
|
2703
|
-
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.")
|
|
2704
2432
|
}),
|
|
2705
2433
|
execute: async ({ entityName, attributes, count, hint }) => {
|
|
2706
2434
|
logger.info({ entityName, count }, "called generateRecord tool");
|
|
2707
2435
|
try {
|
|
2708
|
-
const value =
|
|
2709
|
-
const recordSchema =
|
|
2436
|
+
const value = z12.union([z12.string(), z12.number(), z12.boolean(), z12.null()]);
|
|
2437
|
+
const recordSchema = z12.object(
|
|
2710
2438
|
Object.fromEntries(attributes.map((attr) => [attr, value]))
|
|
2711
2439
|
);
|
|
2712
2440
|
const generateBatch = async (batchCount) => {
|
|
@@ -2716,8 +2444,8 @@ function generateRecordTool(ctx) {
|
|
|
2716
2444
|
const { output } = await generateText({
|
|
2717
2445
|
model: anthropic(RECORD_MODEL),
|
|
2718
2446
|
output: Output.object({
|
|
2719
|
-
schema:
|
|
2720
|
-
records:
|
|
2447
|
+
schema: z12.object({
|
|
2448
|
+
records: z12.array(recordSchema).length(batchCount)
|
|
2721
2449
|
})
|
|
2722
2450
|
}),
|
|
2723
2451
|
prompt: [
|
|
@@ -2775,12 +2503,12 @@ function generateRecordTool(ctx) {
|
|
|
2775
2503
|
|
|
2776
2504
|
// src/lib/tools/notifyUser.ts
|
|
2777
2505
|
import { tool as tool10 } from "ai";
|
|
2778
|
-
import
|
|
2506
|
+
import z13 from "zod";
|
|
2779
2507
|
function notifyUserTool() {
|
|
2780
2508
|
return tool10({
|
|
2781
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.`,
|
|
2782
|
-
inputSchema:
|
|
2783
|
-
message:
|
|
2510
|
+
inputSchema: z13.object({
|
|
2511
|
+
message: z13.string().describe(
|
|
2784
2512
|
"Short, plain-language description of what you are doing now."
|
|
2785
2513
|
)
|
|
2786
2514
|
}),
|
|
@@ -2960,10 +2688,10 @@ async function runAgent(req) {
|
|
|
2960
2688
|
}
|
|
2961
2689
|
|
|
2962
2690
|
// src/actions/detectLanguage.ts
|
|
2963
|
-
import
|
|
2964
|
-
var detectLanguageSchema =
|
|
2965
|
-
languages:
|
|
2966
|
-
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() }))
|
|
2967
2695
|
});
|
|
2968
2696
|
var detectLanguage = () => runAgent({
|
|
2969
2697
|
instructions: [
|
|
@@ -2981,31 +2709,31 @@ var detectLanguage = () => runAgent({
|
|
|
2981
2709
|
});
|
|
2982
2710
|
|
|
2983
2711
|
// src/actions/analyzeCodebase.ts
|
|
2984
|
-
import
|
|
2712
|
+
import z17 from "zod";
|
|
2985
2713
|
var READONLY_TOOLS = [
|
|
2986
2714
|
"listFiles",
|
|
2987
2715
|
"changeDirectory",
|
|
2988
2716
|
"readFile",
|
|
2989
2717
|
"searchFiles"
|
|
2990
2718
|
];
|
|
2991
|
-
var ingestionAnalysisSchema =
|
|
2992
|
-
ingestionAnalysis:
|
|
2993
|
-
|
|
2994
|
-
name:
|
|
2995
|
-
paths:
|
|
2719
|
+
var ingestionAnalysisSchema = z17.object({
|
|
2720
|
+
ingestionAnalysis: z17.array(
|
|
2721
|
+
z17.object({
|
|
2722
|
+
name: z17.string(),
|
|
2723
|
+
paths: z17.array(z17.string()),
|
|
2996
2724
|
// indexable fields the agent found for this entity
|
|
2997
|
-
attributes:
|
|
2725
|
+
attributes: z17.array(z17.string())
|
|
2998
2726
|
})
|
|
2999
2727
|
)
|
|
3000
2728
|
});
|
|
3001
|
-
var searchImplementationAnalysisSchema =
|
|
3002
|
-
searchImplementationAnalysis:
|
|
2729
|
+
var searchImplementationAnalysisSchema = z17.object({
|
|
2730
|
+
searchImplementationAnalysis: z17.string()
|
|
3003
2731
|
});
|
|
3004
|
-
var verificationSchema =
|
|
3005
|
-
verification:
|
|
2732
|
+
var verificationSchema = z17.object({
|
|
2733
|
+
verification: z17.array(z17.string())
|
|
3006
2734
|
});
|
|
3007
2735
|
var confirmedEntitiesFieldSchema = ingestionAnalysisSchema.shape.ingestionAnalysis.optional();
|
|
3008
|
-
var analyzeCodebaseSchema =
|
|
2736
|
+
var analyzeCodebaseSchema = z17.object({
|
|
3009
2737
|
ingestionAnalysis: ingestionAnalysisSchema.shape.ingestionAnalysis.optional(),
|
|
3010
2738
|
searchImplementationAnalysis: searchImplementationAnalysisSchema.shape.searchImplementationAnalysis.optional(),
|
|
3011
2739
|
verification: verificationSchema.shape.verification.optional(),
|
|
@@ -3067,7 +2795,7 @@ async function runAnalysis(mode, extraInstructions = []) {
|
|
|
3067
2795
|
// package.json
|
|
3068
2796
|
var package_default = {
|
|
3069
2797
|
name: "@algolia/wizard",
|
|
3070
|
-
version: "0.9.0-rc.
|
|
2798
|
+
version: "0.9.0-rc.69.59",
|
|
3071
2799
|
description: "Magically implement Algolia functionality in your codebase",
|
|
3072
2800
|
type: "module",
|
|
3073
2801
|
engines: {
|
|
@@ -3115,6 +2843,7 @@ var package_default = {
|
|
|
3115
2843
|
dependencies: {
|
|
3116
2844
|
"@ai-sdk/anthropic": "^3.0.81",
|
|
3117
2845
|
"@ai-sdk/openai-compatible": "^2.0.47",
|
|
2846
|
+
"@algolia/cli": "^5.11.0",
|
|
3118
2847
|
"@hono/node-server": "^2.0.10",
|
|
3119
2848
|
"@mishieck/ink-titled-box": "^0.4.2",
|
|
3120
2849
|
"@segment/analytics-node": "^3.1.0",
|
|
@@ -3129,6 +2858,7 @@ var package_default = {
|
|
|
3129
2858
|
nanoid: "^5.1.15",
|
|
3130
2859
|
pino: "^10.3.1",
|
|
3131
2860
|
react: "^19.2.7",
|
|
2861
|
+
toml: "^4.1.1",
|
|
3132
2862
|
varlock: "^1.5.1",
|
|
3133
2863
|
zod: "^4.4.3",
|
|
3134
2864
|
zustand: "^5.0.14"
|
|
@@ -3186,8 +2916,8 @@ async function askList(ctx, prompt, { required = false } = {}) {
|
|
|
3186
2916
|
}
|
|
3187
2917
|
|
|
3188
2918
|
// src/actions/confirmLanguage.ts
|
|
3189
|
-
import
|
|
3190
|
-
var confirmLanguageSchema =
|
|
2919
|
+
import z19 from "zod";
|
|
2920
|
+
var confirmLanguageSchema = z19.object({
|
|
3191
2921
|
languages: detectLanguageSchema.shape.languages
|
|
3192
2922
|
});
|
|
3193
2923
|
async function confirmLanguage(ctx) {
|
|
@@ -3208,8 +2938,8 @@ async function confirmLanguage(ctx) {
|
|
|
3208
2938
|
}
|
|
3209
2939
|
|
|
3210
2940
|
// src/actions/confirmFramework.ts
|
|
3211
|
-
import
|
|
3212
|
-
var confirmFrameworkSchema =
|
|
2941
|
+
import z20 from "zod";
|
|
2942
|
+
var confirmFrameworkSchema = z20.object({
|
|
3213
2943
|
frameworks: detectLanguageSchema.shape.frameworks
|
|
3214
2944
|
});
|
|
3215
2945
|
var CURATED_FRAMEWORKS = [
|
|
@@ -3337,8 +3067,8 @@ async function promptUser(ctx, params) {
|
|
|
3337
3067
|
}
|
|
3338
3068
|
|
|
3339
3069
|
// src/actions/confirmEntities.ts
|
|
3340
|
-
import
|
|
3341
|
-
var confirmEntitiesSchema =
|
|
3070
|
+
import z21 from "zod";
|
|
3071
|
+
var confirmEntitiesSchema = z21.object({
|
|
3342
3072
|
// Final detection — the focused re-run may supersede project-scan's.
|
|
3343
3073
|
ingestionAnalysis: ingestionAnalysisSchema.shape.ingestionAnalysis.optional(),
|
|
3344
3074
|
confirmedEntities: confirmedEntitiesFieldSchema
|
|
@@ -3408,15 +3138,15 @@ async function confirmEntities(ctx) {
|
|
|
3408
3138
|
}
|
|
3409
3139
|
|
|
3410
3140
|
// src/actions/review.ts
|
|
3411
|
-
import { z as
|
|
3412
|
-
var reviewSchema =
|
|
3141
|
+
import { z as z22 } from "zod";
|
|
3142
|
+
var reviewSchema = z22.object({
|
|
3413
3143
|
// Broad, high-level takeaways grouped by theme (e.g. ingestion, search UI),
|
|
3414
3144
|
// not one entry per workflow step — a step's raw output can be a long,
|
|
3415
3145
|
// multi-paragraph blob (see implement.ts's summaries.join), and mirroring
|
|
3416
3146
|
// that 1:1 is what made the old per-step summary an unreadable wall of text.
|
|
3417
|
-
summaryPoints:
|
|
3418
|
-
reviewPrompt:
|
|
3419
|
-
nextSteps:
|
|
3147
|
+
summaryPoints: z22.array(z22.string()),
|
|
3148
|
+
reviewPrompt: z22.string(),
|
|
3149
|
+
nextSteps: z22.array(z22.string())
|
|
3420
3150
|
});
|
|
3421
3151
|
function formatCompletedSteps(steps) {
|
|
3422
3152
|
if (!steps.length) return "(no prior steps completed)";
|
|
@@ -3467,16 +3197,16 @@ ${formatCompletedSteps(ctx.completedSteps)}`,
|
|
|
3467
3197
|
};
|
|
3468
3198
|
|
|
3469
3199
|
// src/actions/implement.ts
|
|
3470
|
-
import
|
|
3200
|
+
import z24 from "zod";
|
|
3471
3201
|
|
|
3472
3202
|
// src/lib/worktree.ts
|
|
3473
3203
|
import { execFile, spawn as spawn3 } from "node:child_process";
|
|
3474
|
-
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";
|
|
3475
3205
|
import {
|
|
3476
3206
|
basename as basename2,
|
|
3477
3207
|
dirname as dirname7,
|
|
3478
3208
|
isAbsolute as isAbsolute2,
|
|
3479
|
-
join as
|
|
3209
|
+
join as join10,
|
|
3480
3210
|
relative as relative2,
|
|
3481
3211
|
resolve as resolve3
|
|
3482
3212
|
} from "node:path";
|
|
@@ -3510,7 +3240,7 @@ async function isWorkingTreeDirty(repoRoot) {
|
|
|
3510
3240
|
return out.trim().length > 0;
|
|
3511
3241
|
}
|
|
3512
3242
|
async function pruneOldWorktrees(repoRoot) {
|
|
3513
|
-
const dir =
|
|
3243
|
+
const dir = join10(stateDir(repoRoot), "worktrees");
|
|
3514
3244
|
const stale = (await readdir3(dir).catch(() => [])).filter((name) => /^wizard-implement-\d+$/.test(name)).sort().reverse().slice(MAX_WIZARD_WORKTREES - 1);
|
|
3515
3245
|
for (const slug of stale) {
|
|
3516
3246
|
const branch = slug.replace("wizard-implement-", WIZARD_BRANCH_PREFIX);
|
|
@@ -3521,7 +3251,7 @@ async function pruneOldWorktrees(repoRoot) {
|
|
|
3521
3251
|
"worktree",
|
|
3522
3252
|
"remove",
|
|
3523
3253
|
"--force",
|
|
3524
|
-
|
|
3254
|
+
join10(dir, slug)
|
|
3525
3255
|
]);
|
|
3526
3256
|
await git(["-C", repoRoot, "branch", "-D", branch]);
|
|
3527
3257
|
} catch (err) {
|
|
@@ -3535,7 +3265,7 @@ async function pruneOldWorktrees(repoRoot) {
|
|
|
3535
3265
|
async function createWorktree(repoRoot) {
|
|
3536
3266
|
const branch = `${WIZARD_BRANCH_PREFIX}${Date.now()}`;
|
|
3537
3267
|
const dirSlug = branch.replace(/\//g, "-");
|
|
3538
|
-
const path =
|
|
3268
|
+
const path = join10(stateDir(repoRoot), "worktrees", dirSlug);
|
|
3539
3269
|
await git(["-C", repoRoot, "worktree", "prune"]);
|
|
3540
3270
|
await pruneOldWorktrees(repoRoot);
|
|
3541
3271
|
await mkdir6(dirname7(path), { recursive: true });
|
|
@@ -3655,8 +3385,8 @@ async function copyUploadIntoWorktree(repoRoot, worktreePath, ingestDir, sourceP
|
|
|
3655
3385
|
} catch {
|
|
3656
3386
|
return { ok: false, reason: `"${sourcePath}" does not exist` };
|
|
3657
3387
|
}
|
|
3658
|
-
const relPath =
|
|
3659
|
-
const dest =
|
|
3388
|
+
const relPath = join10(ingestDir, basename2(source));
|
|
3389
|
+
const dest = join10(worktreePath, relPath);
|
|
3660
3390
|
try {
|
|
3661
3391
|
await mkdir6(dirname7(dest), { recursive: true });
|
|
3662
3392
|
await copyFile(source, dest);
|
|
@@ -3672,10 +3402,10 @@ function hasEnvVar(content, name) {
|
|
|
3672
3402
|
return new RegExp(`^(\\s*(?:export\\s+)?${name})\\s*=`, "m").test(content);
|
|
3673
3403
|
}
|
|
3674
3404
|
async function writeSearchEnvValues(worktreePath, vars) {
|
|
3675
|
-
const target =
|
|
3405
|
+
const target = join10(worktreePath, ".env");
|
|
3676
3406
|
let existing = "";
|
|
3677
3407
|
try {
|
|
3678
|
-
existing = await
|
|
3408
|
+
existing = await readFile8(target, "utf8");
|
|
3679
3409
|
} catch (err) {
|
|
3680
3410
|
if (err.code !== "ENOENT") throw err;
|
|
3681
3411
|
}
|
|
@@ -3743,15 +3473,63 @@ async function confirmDirtyWorkingTree(ctx, repoRoot) {
|
|
|
3743
3473
|
}
|
|
3744
3474
|
}
|
|
3745
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
|
+
|
|
3746
3524
|
// src/lib/algoliaDocs.ts
|
|
3747
3525
|
import { readFileSync, readdirSync, existsSync as existsSync2 } from "node:fs";
|
|
3748
|
-
import { dirname as dirname8, join as
|
|
3526
|
+
import { dirname as dirname8, join as join11 } from "node:path";
|
|
3749
3527
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
3750
|
-
var DOCS_SUBPATH =
|
|
3528
|
+
var DOCS_SUBPATH = join11("docs", "algolia-sdk");
|
|
3751
3529
|
function findDocsDir() {
|
|
3752
3530
|
let dir = dirname8(fileURLToPath2(import.meta.url));
|
|
3753
3531
|
for (; ; ) {
|
|
3754
|
-
const candidate =
|
|
3532
|
+
const candidate = join11(dir, DOCS_SUBPATH);
|
|
3755
3533
|
if (existsSync2(candidate)) return candidate;
|
|
3756
3534
|
const parent = dirname8(dir);
|
|
3757
3535
|
if (parent === dir) return void 0;
|
|
@@ -3774,7 +3552,7 @@ function loadAlgoliaDoc(language) {
|
|
|
3774
3552
|
);
|
|
3775
3553
|
return "";
|
|
3776
3554
|
}
|
|
3777
|
-
return readFileSync(
|
|
3555
|
+
return readFileSync(join11(docsDir, files[0]), "utf8").trim();
|
|
3778
3556
|
}
|
|
3779
3557
|
function getNamedDoc(name, language) {
|
|
3780
3558
|
const docsDir = findDocsDir();
|
|
@@ -3782,7 +3560,7 @@ function getNamedDoc(name, language) {
|
|
|
3782
3560
|
logger.warn("docs/algolia-sdk not found");
|
|
3783
3561
|
return "";
|
|
3784
3562
|
}
|
|
3785
|
-
const file =
|
|
3563
|
+
const file = join11(docsDir, `${name}-${language}.md`);
|
|
3786
3564
|
if (!existsSync2(file)) {
|
|
3787
3565
|
logger.warn({ name, language }, "named SDK reference not found");
|
|
3788
3566
|
return "";
|
|
@@ -3809,36 +3587,50 @@ function shellQuote(value) {
|
|
|
3809
3587
|
}
|
|
3810
3588
|
|
|
3811
3589
|
// src/actions/implement.ts
|
|
3812
|
-
var implementSchema =
|
|
3813
|
-
filesChanged:
|
|
3814
|
-
summary:
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
//
|
|
3822
|
-
//
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
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()
|
|
3827
3617
|
})
|
|
3828
3618
|
).optional()
|
|
3829
3619
|
});
|
|
3830
|
-
var implementationOutputSchema =
|
|
3831
|
-
summary:
|
|
3832
|
-
// Ingestion only:
|
|
3833
|
-
//
|
|
3834
|
-
//
|
|
3835
|
-
|
|
3836
|
-
|
|
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()
|
|
3837
3629
|
});
|
|
3838
|
-
var verificationOutputSchema =
|
|
3839
|
-
summary:
|
|
3840
|
-
sufficient:
|
|
3841
|
-
additionalInstructions:
|
|
3630
|
+
var verificationOutputSchema = z24.object({
|
|
3631
|
+
summary: z24.string(),
|
|
3632
|
+
sufficient: z24.boolean(),
|
|
3633
|
+
additionalInstructions: z24.string().optional()
|
|
3842
3634
|
});
|
|
3843
3635
|
var MAX_IMPLEMENT_VERIFICATION_ATTEMPTS = 3;
|
|
3844
3636
|
var DEFAULT_IMPLEMENT_USE_CASES = ["ingestion", "search"];
|
|
@@ -3910,6 +3702,9 @@ function sourceSpecificInstructions(input) {
|
|
|
3910
3702
|
"Add env vars for any local source access (DB URL, API base, file paths) that is not a fixed repo path."
|
|
3911
3703
|
],
|
|
3912
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.
|
|
3913
3708
|
`Records come from the developer's file, already copied into the worktree at "${input.uploadFilePath}". Read and parse that exact file.`,
|
|
3914
3709
|
"Parse by extension: JSON = array of objects; CSV/TSV = header row maps to keys.",
|
|
3915
3710
|
"Map parsed columns/fields to the confirmed entity attributes.",
|
|
@@ -3949,11 +3744,12 @@ function searchInstructions(input) {
|
|
|
3949
3744
|
doc,
|
|
3950
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.`,
|
|
3951
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.",
|
|
3952
|
-
// appId always resolves (
|
|
3953
|
-
// can fall back to a placeholder.
|
|
3747
|
+
// appId always resolves (loadActiveProfile throws otherwise); only the
|
|
3748
|
+
// search-only key is best-effort and can fall back to a placeholder.
|
|
3954
3749
|
`Values: App ID "${input.appId}", search-only key ${input.searchKey ? `"${input.searchKey}"` : "(placeholder for the developer to fill in)"}.`,
|
|
3955
|
-
//
|
|
3956
|
-
//
|
|
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
|
|
3957
3753
|
// reading a var the wizard never wrote.
|
|
3958
3754
|
`Use exactly these public env var names in the code: ${input.searchEnvVars.map(({ name }) => name).join(", ")}.`,
|
|
3959
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.',
|
|
@@ -4097,7 +3893,6 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4097
3893
|
}
|
|
4098
3894
|
}
|
|
4099
3895
|
const targetIndex = selected?.selection;
|
|
4100
|
-
useWizard.getState().setTargetIndex(targetIndex ?? null);
|
|
4101
3896
|
await assertGitRepoWithHead(repoRoot);
|
|
4102
3897
|
if (await isWorkingTreeDirty(repoRoot)) {
|
|
4103
3898
|
await confirmDirtyWorkingTree(ctx, repoRoot);
|
|
@@ -4108,7 +3903,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4108
3903
|
let appId;
|
|
4109
3904
|
let searchKey;
|
|
4110
3905
|
if (useCases.includes("search")) {
|
|
4111
|
-
appId = (await
|
|
3906
|
+
appId = (await loadActiveProfile()).appId;
|
|
4112
3907
|
try {
|
|
4113
3908
|
searchKey = await resolveSearchOnlyKey(targetIndex);
|
|
4114
3909
|
} catch (err) {
|
|
@@ -4153,6 +3948,8 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4153
3948
|
ingestDir: INGEST_DIR,
|
|
4154
3949
|
ingestionSource,
|
|
4155
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.
|
|
4156
3953
|
uiFramework: detectUiFramework(language)
|
|
4157
3954
|
};
|
|
4158
3955
|
const summaries = [];
|
|
@@ -4217,8 +4014,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4217
4014
|
messages: []
|
|
4218
4015
|
}) === true;
|
|
4219
4016
|
if (runNow) {
|
|
4220
|
-
const
|
|
4221
|
-
const writeKey = await resolveWriteKey(targetIndex);
|
|
4017
|
+
const profile = await loadActiveProfile();
|
|
4222
4018
|
ctx.notify({ messages: [`Writing records to "${targetIndex}"\u2026`] });
|
|
4223
4019
|
const scriptLogId = ctx.logStart("runIngestScript", {
|
|
4224
4020
|
runtime: ingestRuntime,
|
|
@@ -4230,8 +4026,8 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4230
4026
|
ingestRuntime,
|
|
4231
4027
|
ingestEntrypoint,
|
|
4232
4028
|
{
|
|
4233
|
-
[APP_ID_VAR]:
|
|
4234
|
-
[API_KEY_VAR]:
|
|
4029
|
+
[APP_ID_VAR]: profile.appId,
|
|
4030
|
+
[API_KEY_VAR]: profile.apiKey
|
|
4235
4031
|
}
|
|
4236
4032
|
);
|
|
4237
4033
|
ctx.logEnd(scriptLogId, run2.ok ? "success" : "error");
|
|
@@ -4300,7 +4096,8 @@ ${run2.output}` : status;
|
|
|
4300
4096
|
);
|
|
4301
4097
|
}
|
|
4302
4098
|
await ctx.requestUserInput({
|
|
4303
|
-
//
|
|
4099
|
+
// No question being asked here, just an acknowledgement — the
|
|
4100
|
+
// continue/decline hints below already say "continue".
|
|
4304
4101
|
prompt: "",
|
|
4305
4102
|
promptType: "enterToContinue",
|
|
4306
4103
|
options: [],
|
|
@@ -4441,8 +4238,8 @@ var defaultWorkflow = {
|
|
|
4441
4238
|
defineStep({
|
|
4442
4239
|
id: "select-index",
|
|
4443
4240
|
title: "Set up index",
|
|
4444
|
-
outputSchema:
|
|
4445
|
-
selection:
|
|
4241
|
+
outputSchema: z25.object({
|
|
4242
|
+
selection: z25.string()
|
|
4446
4243
|
}),
|
|
4447
4244
|
run: (ctx) => selectIndexStep(ctx)
|
|
4448
4245
|
}),
|
|
@@ -4721,7 +4518,7 @@ function parseCliArgs(argv) {
|
|
|
4721
4518
|
|
|
4722
4519
|
// src/lib/resetState.ts
|
|
4723
4520
|
import { readdir as readdir4, rm as rm2 } from "node:fs/promises";
|
|
4724
|
-
import { join as
|
|
4521
|
+
import { join as join12 } from "node:path";
|
|
4725
4522
|
var KEEP = ["wizard.log"];
|
|
4726
4523
|
async function resetProjectState() {
|
|
4727
4524
|
const dir = stateDir();
|
|
@@ -4733,7 +4530,7 @@ async function resetProjectState() {
|
|
|
4733
4530
|
}
|
|
4734
4531
|
const targets = entries.filter((name) => !KEEP.includes(name));
|
|
4735
4532
|
await Promise.all(
|
|
4736
|
-
targets.map((name) => rm2(
|
|
4533
|
+
targets.map((name) => rm2(join12(dir, name), { recursive: true, force: true }))
|
|
4737
4534
|
);
|
|
4738
4535
|
return { dir, removed: targets };
|
|
4739
4536
|
}
|
|
@@ -4788,38 +4585,31 @@ ${formatStepList(workflow)}`);
|
|
|
4788
4585
|
}
|
|
4789
4586
|
async function run(workflow) {
|
|
4790
4587
|
const store = useWizard.getState();
|
|
4791
|
-
|
|
4792
|
-
await store.waitForStart();
|
|
4588
|
+
let instance = render(/* @__PURE__ */ jsx14(App, {}), { incrementalRendering: true });
|
|
4793
4589
|
let user = await getUser();
|
|
4794
4590
|
if (!user) {
|
|
4795
|
-
|
|
4591
|
+
await instance.waitUntilRenderFlush();
|
|
4592
|
+
instance.cleanup();
|
|
4796
4593
|
try {
|
|
4797
4594
|
await runAuthLogin();
|
|
4798
4595
|
} catch (err) {
|
|
4799
|
-
|
|
4800
|
-
await instance.waitUntilExit();
|
|
4596
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
4801
4597
|
process.exit(1);
|
|
4802
4598
|
}
|
|
4803
|
-
|
|
4599
|
+
instance = render(/* @__PURE__ */ jsx14(App, {}), { incrementalRendering: true });
|
|
4804
4600
|
user = await getUser();
|
|
4805
4601
|
if (!user) {
|
|
4806
4602
|
store.setError(
|
|
4807
|
-
"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."
|
|
4808
4604
|
);
|
|
4809
4605
|
await instance.waitUntilExit();
|
|
4810
4606
|
process.exit(1);
|
|
4811
4607
|
}
|
|
4812
4608
|
}
|
|
4813
4609
|
store.setUser(user);
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
} catch (err) {
|
|
4818
|
-
store.setError(err instanceof Error ? err.message : String(err));
|
|
4819
|
-
await instance.waitUntilExit();
|
|
4820
|
-
process.exit(1);
|
|
4821
|
-
}
|
|
4822
|
-
runWorkflow(workflow, app.id);
|
|
4610
|
+
const profile = await loadActiveProfile();
|
|
4611
|
+
await store.waitForStart();
|
|
4612
|
+
runWorkflow(workflow, profile?.appId);
|
|
4823
4613
|
}
|
|
4824
4614
|
var started = await startup();
|
|
4825
4615
|
if (typeof started === "number") {
|