@algolia/wizard 0.29.0-rc.118.223 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +405 -114
- package/package.json +2 -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 Box19, Text as Text19, useApp, useInput as useInput7, useWindowSize as useWindowSize7 } from "ink";
|
|
8
8
|
import Spinner2 from "ink-spinner";
|
|
9
9
|
|
|
10
10
|
// src/core/store.ts
|
|
@@ -489,7 +489,7 @@ function CliOutput() {
|
|
|
489
489
|
}
|
|
490
490
|
|
|
491
491
|
// src/ui/Notices.tsx
|
|
492
|
-
import { Box as Box3, Text as Text3
|
|
492
|
+
import { Box as Box3, Text as Text3 } from "ink";
|
|
493
493
|
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
494
494
|
|
|
495
495
|
// src/ui/Table.tsx
|
|
@@ -548,31 +548,6 @@ var truncate = (s, width) => s.length <= width ? s : width <= 1 ? s.slice(0, wid
|
|
|
548
548
|
// src/ui/Notices.tsx
|
|
549
549
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
550
550
|
var AGENT_MARKER = "\u2726";
|
|
551
|
-
var RESERVED_ROWS2 = 14;
|
|
552
|
-
var PANEL_TEXT_WIDTH2 = 45;
|
|
553
|
-
function messageLineCount(text) {
|
|
554
|
-
return Math.max(1, Math.ceil(text.length / PANEL_TEXT_WIDTH2));
|
|
555
|
-
}
|
|
556
|
-
function noticeLineCount(notice) {
|
|
557
|
-
const messageLines = (notice.messages ?? []).reduce((sum, m) => {
|
|
558
|
-
const text = typeof m === "string" ? m : m.text;
|
|
559
|
-
return sum + messageLineCount(text);
|
|
560
|
-
}, 0);
|
|
561
|
-
const tableLines = notice.table ? notice.table.rows.length + 4 : 0;
|
|
562
|
-
return messageLines + tableLines;
|
|
563
|
-
}
|
|
564
|
-
function fitVisibleNotices(notices, windowRows) {
|
|
565
|
-
const budget = Math.max(windowRows - RESERVED_ROWS2, 3);
|
|
566
|
-
let used = 0;
|
|
567
|
-
let count = 0;
|
|
568
|
-
for (let i = notices.length - 1; i >= 0; i--) {
|
|
569
|
-
const height = noticeLineCount(notices[i]) + (count > 0 ? 1 : 0);
|
|
570
|
-
if (count > 0 && used + height > budget) break;
|
|
571
|
-
used += height;
|
|
572
|
-
count++;
|
|
573
|
-
}
|
|
574
|
-
return notices.slice(notices.length - count);
|
|
575
|
-
}
|
|
576
551
|
var PULSE_STEPS = 12;
|
|
577
552
|
var PULSE_STEP_MS = 150;
|
|
578
553
|
var PULSE_COLORS = Array.from(
|
|
@@ -593,10 +568,13 @@ function parseHex(hex) {
|
|
|
593
568
|
b: parseInt(n.slice(4, 6), 16)
|
|
594
569
|
};
|
|
595
570
|
}
|
|
596
|
-
function Notices(
|
|
571
|
+
function Notices({
|
|
572
|
+
showAll = false,
|
|
573
|
+
border = true
|
|
574
|
+
} = {}) {
|
|
597
575
|
const notices = useWizard((s) => s.notices);
|
|
598
|
-
const
|
|
599
|
-
const visible =
|
|
576
|
+
const latest = notices[notices.length - 1];
|
|
577
|
+
const visible = showAll ? notices : latest ? [latest] : [];
|
|
600
578
|
const [pulseStep, setPulseStep] = useState2(0);
|
|
601
579
|
useEffect2(() => {
|
|
602
580
|
let direction = 1;
|
|
@@ -610,30 +588,41 @@ function Notices() {
|
|
|
610
588
|
}, PULSE_STEP_MS);
|
|
611
589
|
return () => clearInterval(id);
|
|
612
590
|
}, []);
|
|
613
|
-
if (
|
|
591
|
+
if (visible.length === 0) return null;
|
|
614
592
|
const pulseColor = PULSE_COLORS[pulseStep];
|
|
615
|
-
return /* @__PURE__ */ jsx2(
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
593
|
+
return /* @__PURE__ */ jsx2(
|
|
594
|
+
Box3,
|
|
595
|
+
{
|
|
596
|
+
borderColor: border ? COLORS.border : void 0,
|
|
597
|
+
borderStyle: border ? "single" : void 0,
|
|
598
|
+
borderBackgroundColor: COLORS.bg.main,
|
|
599
|
+
borderLeft: false,
|
|
600
|
+
borderRight: false,
|
|
601
|
+
borderBottom: false,
|
|
602
|
+
paddingTop: border ? 1 : 0,
|
|
603
|
+
flexDirection: "column",
|
|
604
|
+
gap: 1,
|
|
605
|
+
children: visible.map((notice, i) => /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", children: [
|
|
606
|
+
notice.messages?.map((m, j) => {
|
|
607
|
+
const line = typeof m === "string" ? { text: m } : m;
|
|
608
|
+
const prefix = j === 0 ? `${AGENT_MARKER} ` : " ";
|
|
609
|
+
return /* @__PURE__ */ jsxs2(
|
|
610
|
+
Text3,
|
|
611
|
+
{
|
|
612
|
+
color: !line.color ? notice === latest ? pulseColor : COLORS.dim : line.color ?? COLORS.dim,
|
|
613
|
+
bold: line.bold,
|
|
614
|
+
children: [
|
|
615
|
+
prefix,
|
|
616
|
+
line.text
|
|
617
|
+
]
|
|
618
|
+
},
|
|
619
|
+
`notice-line-${j}`
|
|
620
|
+
);
|
|
621
|
+
}),
|
|
622
|
+
notice.table && /* @__PURE__ */ jsx2(Table, { columns: notice.table.columns, rows: notice.table.rows })
|
|
623
|
+
] }, `notice-${i}`))
|
|
624
|
+
}
|
|
625
|
+
);
|
|
637
626
|
}
|
|
638
627
|
|
|
639
628
|
// src/ui/PromptInput.tsx
|
|
@@ -714,11 +703,11 @@ function CommandApproval({
|
|
|
714
703
|
}
|
|
715
704
|
|
|
716
705
|
// src/ui/SelectPrompt.tsx
|
|
717
|
-
import { Box as Box8, Text as Text8, useInput as useInput2, useWindowSize as
|
|
706
|
+
import { Box as Box8, Text as Text8, useInput as useInput2, useWindowSize as useWindowSize4 } from "ink";
|
|
718
707
|
import { useLayoutEffect as useLayoutEffect2, useRef as useRef3, useState as useState4 } from "react";
|
|
719
708
|
|
|
720
709
|
// src/ui/ScrollView.tsx
|
|
721
|
-
import { Box as Box6, Text as Text6, measureElement as measureElement2, useWindowSize as
|
|
710
|
+
import { Box as Box6, Text as Text6, measureElement as measureElement2, useWindowSize as useWindowSize3 } from "ink";
|
|
722
711
|
import { useCallback, useLayoutEffect, useRef as useRef2, useState as useState3 } from "react";
|
|
723
712
|
import { jsxs as jsxs5 } from "react/jsx-runtime";
|
|
724
713
|
var INDICATOR_ROWS = 2;
|
|
@@ -735,7 +724,7 @@ function useScrollWindow({
|
|
|
735
724
|
followBottom = false
|
|
736
725
|
}) {
|
|
737
726
|
const viewportRef = useRef2(null);
|
|
738
|
-
const { columns } =
|
|
727
|
+
const { columns } = useWindowSize3();
|
|
739
728
|
const [size, setSize] = useState3(
|
|
740
729
|
null
|
|
741
730
|
);
|
|
@@ -876,7 +865,7 @@ function SelectPrompt({
|
|
|
876
865
|
if (multi) hints.push({ key: "[space]", label: "select" });
|
|
877
866
|
hints.push({ key: "[enter]", label: "confirm" });
|
|
878
867
|
const containerRef = useRef3(null);
|
|
879
|
-
const { columns } =
|
|
868
|
+
const { columns } = useWindowSize4();
|
|
880
869
|
const [width, setWidth] = useState4(columns);
|
|
881
870
|
useLayoutEffect2(() => {
|
|
882
871
|
if (!containerRef.current) return;
|
|
@@ -1105,7 +1094,7 @@ function PromptInput() {
|
|
|
1105
1094
|
import { dirname as dirname2, join as join3 } from "node:path";
|
|
1106
1095
|
import { fileURLToPath } from "node:url";
|
|
1107
1096
|
import { useState as useState6 } from "react";
|
|
1108
|
-
import { Box as Box10, Spacer, Text as Text10, useInput as useInput4, useWindowSize as
|
|
1097
|
+
import { Box as Box10, Spacer, Text as Text10, useInput as useInput4, useWindowSize as useWindowSize5 } from "ink";
|
|
1109
1098
|
|
|
1110
1099
|
// src/ui/copy/welcome.ts
|
|
1111
1100
|
var sidebarItems = [
|
|
@@ -1158,7 +1147,7 @@ function SidebarItem({
|
|
|
1158
1147
|
function Welcome() {
|
|
1159
1148
|
const confirmStart = useWizard((s) => s.confirmStart);
|
|
1160
1149
|
const openLearnMore = useWizard((s) => s.openLearnMore);
|
|
1161
|
-
const { rows } =
|
|
1150
|
+
const { rows } = useWindowSize5();
|
|
1162
1151
|
const actions = [
|
|
1163
1152
|
{ label: "start wizard", run: confirmStart },
|
|
1164
1153
|
{ label: "learn more", run: openLearnMore }
|
|
@@ -1251,7 +1240,7 @@ function Welcome() {
|
|
|
1251
1240
|
|
|
1252
1241
|
// src/ui/LearnMore.tsx
|
|
1253
1242
|
import { Fragment as Fragment2 } from "react";
|
|
1254
|
-
import { Box as Box11, Text as Text11, useInput as useInput5, useWindowSize as
|
|
1243
|
+
import { Box as Box11, Text as Text11, useInput as useInput5, useWindowSize as useWindowSize6 } from "ink";
|
|
1255
1244
|
|
|
1256
1245
|
// src/ui/copy/learn-more.ts
|
|
1257
1246
|
var accessIntro = "Everything runs locally on your machine. Nothing is written or sent without an explicit yes from you.";
|
|
@@ -1321,7 +1310,7 @@ function NeverLine({
|
|
|
1321
1310
|
function LearnMore() {
|
|
1322
1311
|
const confirmStart = useWizard((s) => s.confirmStart);
|
|
1323
1312
|
const backToHome = useWizard((s) => s.backToHome);
|
|
1324
|
-
const { columns } =
|
|
1313
|
+
const { columns } = useWindowSize6();
|
|
1325
1314
|
const dividerWidth = Math.max(0, columns - PADDING_X * 2);
|
|
1326
1315
|
useInput5((_input, key) => {
|
|
1327
1316
|
if (key.escape) backToHome();
|
|
@@ -1531,7 +1520,7 @@ function Ribbon() {
|
|
|
1531
1520
|
}
|
|
1532
1521
|
|
|
1533
1522
|
// src/ui/App.tsx
|
|
1534
|
-
import { useState as
|
|
1523
|
+
import { useState as useState8 } from "react";
|
|
1535
1524
|
|
|
1536
1525
|
// src/ui/Logs.tsx
|
|
1537
1526
|
import { Box as Box16, Text as Text16, useInput as useInput6 } from "ink";
|
|
@@ -1781,15 +1770,303 @@ function track(event, payload) {
|
|
|
1781
1770
|
});
|
|
1782
1771
|
}
|
|
1783
1772
|
|
|
1773
|
+
// src/ui/Tips.tsx
|
|
1774
|
+
import { useEffect as useEffect3, useState as useState7 } from "react";
|
|
1775
|
+
import { Box as Box18, Text as Text18 } from "ink";
|
|
1776
|
+
import terminalLink from "terminal-link";
|
|
1777
|
+
|
|
1778
|
+
// src/ui/Code.tsx
|
|
1779
|
+
import { Box as Box17, Text as Text17 } from "ink";
|
|
1780
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
1781
|
+
var TOKEN_RE = /("(?:\\.|[^"\\])*"|\btrue\b|\bfalse\b|\bnull\b|-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|[{}[\]:,])/g;
|
|
1782
|
+
function highlightJson(json) {
|
|
1783
|
+
const parts = json.split(TOKEN_RE);
|
|
1784
|
+
return parts.map((part, i) => {
|
|
1785
|
+
if (!part) return null;
|
|
1786
|
+
if (part[0] === '"') {
|
|
1787
|
+
const next = parts.slice(i + 1).find((p) => p.trim());
|
|
1788
|
+
const isKey = next?.trimStart().startsWith(":");
|
|
1789
|
+
return /* @__PURE__ */ jsx15(Text17, { color: isKey ? "cyan" : "green", children: part }, i);
|
|
1790
|
+
}
|
|
1791
|
+
if (part === "true" || part === "false" || part === "null") {
|
|
1792
|
+
return /* @__PURE__ */ jsx15(Text17, { color: "magenta", children: part }, i);
|
|
1793
|
+
}
|
|
1794
|
+
if (/^-?\d/.test(part)) {
|
|
1795
|
+
return /* @__PURE__ */ jsx15(Text17, { color: "yellow", children: part }, i);
|
|
1796
|
+
}
|
|
1797
|
+
if (/^[{}[\]:,]$/.test(part)) {
|
|
1798
|
+
return /* @__PURE__ */ jsx15(Text17, { dimColor: true, children: part }, i);
|
|
1799
|
+
}
|
|
1800
|
+
return /* @__PURE__ */ jsx15(Text17, { children: part }, i);
|
|
1801
|
+
});
|
|
1802
|
+
}
|
|
1803
|
+
function Code({ children }) {
|
|
1804
|
+
return /* @__PURE__ */ jsx15(Box17, { children: /* @__PURE__ */ jsx15(Text17, { children: highlightJson(children) }) });
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
// src/ui/copy/tips.ts
|
|
1808
|
+
var tips = [
|
|
1809
|
+
{
|
|
1810
|
+
title: "An Application is like your library. Indices are the books in it.",
|
|
1811
|
+
chunks: [
|
|
1812
|
+
{
|
|
1813
|
+
type: "text",
|
|
1814
|
+
value: "Applications hold your API keys and Indices."
|
|
1815
|
+
},
|
|
1816
|
+
{
|
|
1817
|
+
type: "text",
|
|
1818
|
+
value: "Each index is a searchable collection of records (think: products, articles, orders, concerts)."
|
|
1819
|
+
}
|
|
1820
|
+
]
|
|
1821
|
+
},
|
|
1822
|
+
{
|
|
1823
|
+
title: "A Record is a JSON object inside of an index.",
|
|
1824
|
+
chunks: [
|
|
1825
|
+
{
|
|
1826
|
+
type: "text",
|
|
1827
|
+
value: "Every object you index is just a JSON document with a unique objectID."
|
|
1828
|
+
},
|
|
1829
|
+
{
|
|
1830
|
+
type: "text",
|
|
1831
|
+
value: "No fixed schema, no hard requirements."
|
|
1832
|
+
},
|
|
1833
|
+
{
|
|
1834
|
+
type: "text",
|
|
1835
|
+
value: "Everything else is up to you:"
|
|
1836
|
+
},
|
|
1837
|
+
{
|
|
1838
|
+
type: "code",
|
|
1839
|
+
value: JSON.stringify(
|
|
1840
|
+
{
|
|
1841
|
+
objectID: "sku_48213",
|
|
1842
|
+
name: "Trail Running Shoe",
|
|
1843
|
+
brand: "Northline",
|
|
1844
|
+
categories: ["Footwear", "Running", "Mens"],
|
|
1845
|
+
price: 129.99,
|
|
1846
|
+
in_stock: true,
|
|
1847
|
+
rating: 4.6
|
|
1848
|
+
},
|
|
1849
|
+
null,
|
|
1850
|
+
2
|
|
1851
|
+
)
|
|
1852
|
+
}
|
|
1853
|
+
]
|
|
1854
|
+
},
|
|
1855
|
+
{
|
|
1856
|
+
title: "Speed isn't a feature, it's our business",
|
|
1857
|
+
chunks: [
|
|
1858
|
+
{
|
|
1859
|
+
type: "text",
|
|
1860
|
+
value: "Algolia's engine processes most search queries in 1 to 50 milliseconds."
|
|
1861
|
+
},
|
|
1862
|
+
{
|
|
1863
|
+
type: "text",
|
|
1864
|
+
value: "This is why our search-as-you-type experience feels instant."
|
|
1865
|
+
}
|
|
1866
|
+
]
|
|
1867
|
+
},
|
|
1868
|
+
{
|
|
1869
|
+
title: "Searchable attributes are your relevance dial #1",
|
|
1870
|
+
chunks: [
|
|
1871
|
+
{
|
|
1872
|
+
type: "text",
|
|
1873
|
+
value: "Order matters. Attributes listed first in"
|
|
1874
|
+
},
|
|
1875
|
+
{ type: "codeword", value: "searchableAttributes" },
|
|
1876
|
+
{ type: "text", value: "carry more ranking weight." },
|
|
1877
|
+
{
|
|
1878
|
+
type: "text",
|
|
1879
|
+
value: "This is the single highest-leverage lever new users don't know exists."
|
|
1880
|
+
}
|
|
1881
|
+
]
|
|
1882
|
+
},
|
|
1883
|
+
{
|
|
1884
|
+
title: "Facets aren't just filters, they help build your UI",
|
|
1885
|
+
chunks: [
|
|
1886
|
+
{ type: "codeword", value: "attributesForFaceting" },
|
|
1887
|
+
{
|
|
1888
|
+
type: "text",
|
|
1889
|
+
value: "unlock category sidebars, price sliders, tag clouds without extra backend work."
|
|
1890
|
+
}
|
|
1891
|
+
]
|
|
1892
|
+
},
|
|
1893
|
+
{
|
|
1894
|
+
title: "Test relevance in the dashboard before you write a line of ranking code",
|
|
1895
|
+
chunks: [
|
|
1896
|
+
{
|
|
1897
|
+
type: "text",
|
|
1898
|
+
value: "Our Search dashboard has a live preview where you can browse results."
|
|
1899
|
+
},
|
|
1900
|
+
{
|
|
1901
|
+
type: "text",
|
|
1902
|
+
value: "Tune your settings and see how it alters your results in"
|
|
1903
|
+
},
|
|
1904
|
+
{
|
|
1905
|
+
type: "link",
|
|
1906
|
+
value: "real-time.",
|
|
1907
|
+
href: "https://dashboard.algolia.com/explorer/browse"
|
|
1908
|
+
}
|
|
1909
|
+
]
|
|
1910
|
+
},
|
|
1911
|
+
{
|
|
1912
|
+
title: "Search Analytics helps you discover opportunities",
|
|
1913
|
+
chunks: [
|
|
1914
|
+
{
|
|
1915
|
+
type: "text",
|
|
1916
|
+
value: "No click results for a particular query? Low click-through rates for another?"
|
|
1917
|
+
},
|
|
1918
|
+
{
|
|
1919
|
+
type: "text",
|
|
1920
|
+
value: "Our Search Analytics will help you identify synonyms, rules or other relevancy settings to improve your results."
|
|
1921
|
+
}
|
|
1922
|
+
]
|
|
1923
|
+
},
|
|
1924
|
+
{
|
|
1925
|
+
title: "Let Algolia act as your recommendation engine",
|
|
1926
|
+
chunks: [
|
|
1927
|
+
{
|
|
1928
|
+
type: "text",
|
|
1929
|
+
value: "Beyond search, Algolia Recommend runs models trained on your existing indices and event data to power your recommendation engine."
|
|
1930
|
+
},
|
|
1931
|
+
{
|
|
1932
|
+
type: "text",
|
|
1933
|
+
value: "You can improve engagement with related, popular or visually similar items."
|
|
1934
|
+
}
|
|
1935
|
+
]
|
|
1936
|
+
}
|
|
1937
|
+
];
|
|
1938
|
+
|
|
1939
|
+
// src/ui/Tips.tsx
|
|
1940
|
+
import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1941
|
+
var TICK_MS = 16;
|
|
1942
|
+
var CHUNK_HOLD_MS = 2e3;
|
|
1943
|
+
var HOLD_MS = 8e3;
|
|
1944
|
+
function TipTitle({ children }) {
|
|
1945
|
+
return /* @__PURE__ */ jsxs16(Box18, { gap: 1, children: [
|
|
1946
|
+
/* @__PURE__ */ jsx16(Text18, { color: "cyan", children: "\u2726" }),
|
|
1947
|
+
/* @__PURE__ */ jsx16(Text18, { color: "white", bold: true, children })
|
|
1948
|
+
] });
|
|
1949
|
+
}
|
|
1950
|
+
function InlineSegment({ segment }) {
|
|
1951
|
+
switch (segment.type) {
|
|
1952
|
+
case "highlight":
|
|
1953
|
+
return /* @__PURE__ */ jsx16(Text18, { color: COLORS.success, children: segment.value });
|
|
1954
|
+
case "link":
|
|
1955
|
+
return /* @__PURE__ */ jsx16(Text18, { color: "cyan", underline: true, children: segment.href ? terminalLink(segment.value, segment.href) : segment.value });
|
|
1956
|
+
case "codeword":
|
|
1957
|
+
return /* @__PURE__ */ jsx16(Text18, { color: COLORS.highlight.fg, backgroundColor: COLORS.highlight.bg, children: segment.value });
|
|
1958
|
+
default:
|
|
1959
|
+
return /* @__PURE__ */ jsx16(Text18, { color: COLORS.muted, children: segment.value });
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
function TipContent({
|
|
1963
|
+
chunks,
|
|
1964
|
+
revealed
|
|
1965
|
+
}) {
|
|
1966
|
+
let remaining = revealed;
|
|
1967
|
+
const slices = chunks.map((chunk) => {
|
|
1968
|
+
const slice = chunk.value.slice(0, Math.max(0, remaining));
|
|
1969
|
+
remaining -= chunk.value.length;
|
|
1970
|
+
return slice;
|
|
1971
|
+
});
|
|
1972
|
+
const blocks = [];
|
|
1973
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
1974
|
+
const chunk = chunks[i];
|
|
1975
|
+
const slice = slices[i];
|
|
1976
|
+
if (!slice) continue;
|
|
1977
|
+
const segment = {
|
|
1978
|
+
type: chunk.type,
|
|
1979
|
+
value: slice,
|
|
1980
|
+
href: chunk.type === "link" ? chunk.href : void 0
|
|
1981
|
+
};
|
|
1982
|
+
if (chunk.type === "code") {
|
|
1983
|
+
blocks.push({ type: "code", segment });
|
|
1984
|
+
continue;
|
|
1985
|
+
}
|
|
1986
|
+
const last = blocks[blocks.length - 1];
|
|
1987
|
+
if (last?.type === "inline") {
|
|
1988
|
+
last.segments.push(segment);
|
|
1989
|
+
} else {
|
|
1990
|
+
blocks.push({ type: "inline", segments: [segment] });
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
return /* @__PURE__ */ jsx16(Box18, { flexDirection: "column", marginLeft: 2, gap: 1, children: blocks.map(
|
|
1994
|
+
(block, i) => block.type === "code" ? /* @__PURE__ */ jsx16(Code, { children: block.segment.value }, i) : /* @__PURE__ */ jsx16(Text18, { children: block.segments.map((segment, j) => /* @__PURE__ */ jsxs16(Text18, { children: [
|
|
1995
|
+
j > 0 && " ",
|
|
1996
|
+
/* @__PURE__ */ jsx16(InlineSegment, { segment })
|
|
1997
|
+
] }, j)) }, i)
|
|
1998
|
+
) });
|
|
1999
|
+
}
|
|
2000
|
+
function Tips() {
|
|
2001
|
+
const [tipIndex, setTipIndex] = useState7(0);
|
|
2002
|
+
const [revealed, setRevealed] = useState7(0);
|
|
2003
|
+
const tip = tips[tipIndex];
|
|
2004
|
+
const contentLength = tip.chunks.reduce((sum, c) => sum + c.value.length, 0);
|
|
2005
|
+
const totalLength = tip.title.length + contentLength;
|
|
2006
|
+
const segments = [
|
|
2007
|
+
{ type: "title", length: tip.title.length },
|
|
2008
|
+
...tip.chunks.map((c) => ({ type: c.type, length: c.value.length }))
|
|
2009
|
+
];
|
|
2010
|
+
const noPauseAfterText = [
|
|
2011
|
+
"highlight",
|
|
2012
|
+
"link",
|
|
2013
|
+
"codeword"
|
|
2014
|
+
];
|
|
2015
|
+
const chunkBoundaries = [];
|
|
2016
|
+
let cumulative = 0;
|
|
2017
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
2018
|
+
cumulative += segments[i].length;
|
|
2019
|
+
const skipPause = noPauseAfterText.includes(
|
|
2020
|
+
segments[i + 1].type
|
|
2021
|
+
);
|
|
2022
|
+
if (!skipPause) chunkBoundaries.push(cumulative);
|
|
2023
|
+
}
|
|
2024
|
+
useEffect3(() => {
|
|
2025
|
+
if (revealed < totalLength) {
|
|
2026
|
+
const delay2 = chunkBoundaries.includes(revealed) ? CHUNK_HOLD_MS : TICK_MS;
|
|
2027
|
+
const timer2 = setTimeout(() => setRevealed((r) => r + 1), delay2);
|
|
2028
|
+
return () => clearTimeout(timer2);
|
|
2029
|
+
}
|
|
2030
|
+
const timer = setTimeout(() => {
|
|
2031
|
+
setTipIndex((i) => {
|
|
2032
|
+
if (i < tips.length - 1) return i + 1;
|
|
2033
|
+
return 0;
|
|
2034
|
+
});
|
|
2035
|
+
setRevealed(0);
|
|
2036
|
+
}, HOLD_MS);
|
|
2037
|
+
return () => clearTimeout(timer);
|
|
2038
|
+
}, [revealed, totalLength]);
|
|
2039
|
+
const titleRevealed = tip.title.slice(0, revealed);
|
|
2040
|
+
const contentRevealed = Math.max(0, revealed - tip.title.length);
|
|
2041
|
+
return /* @__PURE__ */ jsxs16(Box18, { flexDirection: "column", marginBottom: 1, gap: 1, children: [
|
|
2042
|
+
/* @__PURE__ */ jsx16(TipTitle, { children: titleRevealed }),
|
|
2043
|
+
/* @__PURE__ */ jsx16(TipContent, { chunks: tip.chunks, revealed: contentRevealed })
|
|
2044
|
+
] });
|
|
2045
|
+
}
|
|
2046
|
+
|
|
1784
2047
|
// src/ui/App.tsx
|
|
1785
|
-
import { jsx as
|
|
2048
|
+
import { jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1786
2049
|
function App() {
|
|
1787
|
-
const {
|
|
2050
|
+
const {
|
|
2051
|
+
phase,
|
|
2052
|
+
error,
|
|
2053
|
+
homeScreen,
|
|
2054
|
+
currentStepIndex,
|
|
2055
|
+
steps,
|
|
2056
|
+
inputReq,
|
|
2057
|
+
user,
|
|
2058
|
+
notices
|
|
2059
|
+
} = useWizard();
|
|
1788
2060
|
const { exit } = useApp();
|
|
1789
|
-
const { columns, rows } =
|
|
1790
|
-
const [showLogs, setShowLogs] =
|
|
2061
|
+
const { columns, rows } = useWindowSize7();
|
|
2062
|
+
const [showLogs, setShowLogs] = useState8(false);
|
|
1791
2063
|
const finished = phase === "done" || phase === "error";
|
|
1792
2064
|
const currentStep = steps[currentStepIndex];
|
|
2065
|
+
const isInitialAnalysisStep = currentStepIndex === 0;
|
|
2066
|
+
const isAwaitingUserInput = phase === "awaitingInput" && !!inputReq;
|
|
2067
|
+
const showTips = phase === "running" && isInitialAnalysisStep && notices.length > 0;
|
|
2068
|
+
const showNoticesInMain = !isInitialAnalysisStep;
|
|
2069
|
+
const showNotices = !isAwaitingUserInput;
|
|
1793
2070
|
useInput7(
|
|
1794
2071
|
(_input, key) => {
|
|
1795
2072
|
if (key.return) {
|
|
@@ -1829,8 +2106,8 @@ function App() {
|
|
|
1829
2106
|
/* Clamped to exactly the viewport: a taller frame makes Ink clear and repaint
|
|
1830
2107
|
the whole screen, and the scrolling throws off its cursor arithmetic —
|
|
1831
2108
|
flicker and leftover rows. */
|
|
1832
|
-
/* @__PURE__ */
|
|
1833
|
-
|
|
2109
|
+
/* @__PURE__ */ jsxs17(
|
|
2110
|
+
Box19,
|
|
1834
2111
|
{
|
|
1835
2112
|
backgroundColor: COLORS.bg.main,
|
|
1836
2113
|
flexDirection: "row",
|
|
@@ -1838,53 +2115,58 @@ function App() {
|
|
|
1838
2115
|
height: scrollsPastViewport ? void 0 : rows,
|
|
1839
2116
|
overflow: scrollsPastViewport ? "visible" : "hidden",
|
|
1840
2117
|
children: [
|
|
1841
|
-
mainWindowVisible && /* @__PURE__ */
|
|
1842
|
-
|
|
2118
|
+
mainWindowVisible && /* @__PURE__ */ jsxs17(
|
|
2119
|
+
Box19,
|
|
1843
2120
|
{
|
|
1844
2121
|
flexDirection,
|
|
1845
2122
|
width: "100%",
|
|
1846
2123
|
maxHeight: rows,
|
|
1847
2124
|
justifyContent: "space-between",
|
|
1848
2125
|
children: [
|
|
1849
|
-
showLogs ? /* @__PURE__ */
|
|
1850
|
-
|
|
2126
|
+
showLogs ? /* @__PURE__ */ jsx17(Logs, {}) : /* @__PURE__ */ jsxs17(
|
|
2127
|
+
Box19,
|
|
1851
2128
|
{
|
|
1852
2129
|
flexDirection: "column",
|
|
1853
2130
|
paddingX: 4,
|
|
1854
2131
|
paddingY: 2,
|
|
1855
2132
|
width: showSidebar ? 70 : "100%",
|
|
1856
2133
|
flexGrow: 1,
|
|
2134
|
+
gap: 1,
|
|
1857
2135
|
children: [
|
|
1858
|
-
|
|
1859
|
-
/* @__PURE__ */
|
|
1860
|
-
|
|
1861
|
-
] }) }),
|
|
1862
|
-
phase === "preflight" && user && /* @__PURE__ */ jsx15(Box17, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs16(Text17, { color: COLORS.strong, bold: true, children: [
|
|
1863
|
-
/* @__PURE__ */ jsx15(Spinner2, { type: "dots" }),
|
|
1864
|
-
" Getting things ready"
|
|
1865
|
-
] }) }),
|
|
1866
|
-
phase === "authenticating" && /* @__PURE__ */ jsxs16(Box17, { flexDirection: "column", marginBottom: 1, children: [
|
|
1867
|
-
/* @__PURE__ */ jsxs16(Text17, { color: COLORS.strong, bold: true, children: [
|
|
1868
|
-
/* @__PURE__ */ jsx15(Spinner2, { type: "dots" }),
|
|
2136
|
+
/* @__PURE__ */ jsxs17(Box19, { flexGrow: 2, flexDirection: "column", children: [
|
|
2137
|
+
phase === "preflight" && !user && /* @__PURE__ */ jsx17(Box19, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs17(Text19, { color: COLORS.strong, bold: true, children: [
|
|
2138
|
+
/* @__PURE__ */ jsx17(Spinner2, { type: "dots" }),
|
|
1869
2139
|
" Signing in to Algolia"
|
|
2140
|
+
] }) }),
|
|
2141
|
+
phase === "preflight" && user && /* @__PURE__ */ jsx17(Box19, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs17(Text19, { color: COLORS.strong, bold: true, children: [
|
|
2142
|
+
/* @__PURE__ */ jsx17(Spinner2, { type: "dots" }),
|
|
2143
|
+
" Getting things ready"
|
|
2144
|
+
] }) }),
|
|
2145
|
+
phase === "authenticating" && /* @__PURE__ */ jsxs17(Box19, { flexDirection: "column", marginBottom: 1, children: [
|
|
2146
|
+
/* @__PURE__ */ jsxs17(Text19, { color: COLORS.strong, bold: true, children: [
|
|
2147
|
+
/* @__PURE__ */ jsx17(Spinner2, { type: "dots" }),
|
|
2148
|
+
" Signing in to Algolia"
|
|
2149
|
+
] }),
|
|
2150
|
+
/* @__PURE__ */ jsx17(Text19, { color: COLORS.muted, children: "A browser window will open \u2014 complete sign-in there." })
|
|
1870
2151
|
] }),
|
|
1871
|
-
/* @__PURE__ */
|
|
2152
|
+
/* @__PURE__ */ jsx17(CliOutput, {}),
|
|
2153
|
+
showTips && /* @__PURE__ */ jsx17(Tips, {}),
|
|
2154
|
+
showNoticesInMain && showNotices && /* @__PURE__ */ jsx17(Notices, { showAll: true, border: false }),
|
|
2155
|
+
/* @__PURE__ */ jsx17(PromptInput, {}),
|
|
2156
|
+
phase === "error" && error && /* @__PURE__ */ jsx17(Box19, { marginTop: 1, children: /* @__PURE__ */ jsxs17(Text19, { color: COLORS.status.error, children: [
|
|
2157
|
+
"\u2716 ",
|
|
2158
|
+
error
|
|
2159
|
+
] }) })
|
|
1872
2160
|
] }),
|
|
1873
|
-
/* @__PURE__ */
|
|
1874
|
-
/* @__PURE__ */ jsx15(Notices, {}),
|
|
1875
|
-
/* @__PURE__ */ jsx15(PromptInput, {}),
|
|
1876
|
-
phase === "error" && error && /* @__PURE__ */ jsx15(Box17, { marginTop: 1, children: /* @__PURE__ */ jsxs16(Text17, { color: COLORS.status.error, children: [
|
|
1877
|
-
"\u2716 ",
|
|
1878
|
-
error
|
|
1879
|
-
] }) })
|
|
2161
|
+
!showNoticesInMain && showNotices && /* @__PURE__ */ jsx17(Notices, {})
|
|
1880
2162
|
]
|
|
1881
2163
|
}
|
|
1882
2164
|
),
|
|
1883
|
-
showSidebar ? /* @__PURE__ */
|
|
2165
|
+
showSidebar ? /* @__PURE__ */ jsx17(Sidebar, {}) : /* @__PURE__ */ jsx17(Ribbon, {})
|
|
1884
2166
|
]
|
|
1885
2167
|
}
|
|
1886
2168
|
),
|
|
1887
|
-
phase === "idle" && (homeScreen === "learnMore" ? /* @__PURE__ */
|
|
2169
|
+
phase === "idle" && (homeScreen === "learnMore" ? /* @__PURE__ */ jsx17(LearnMore, {}) : /* @__PURE__ */ jsx17(Welcome, {}))
|
|
1888
2170
|
]
|
|
1889
2171
|
}
|
|
1890
2172
|
)
|
|
@@ -1938,20 +2220,8 @@ function reconcileWorkflowState(state, workflow) {
|
|
|
1938
2220
|
const definedIds = workflow.steps.map((s) => s.id).join("\n");
|
|
1939
2221
|
if (persistedIds !== definedIds) return null;
|
|
1940
2222
|
for (let i = 0; i < state.steps.length; i++) {
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
if (record.status === "done") {
|
|
1944
|
-
const parsed = step.outputSchema.safeParse(record.output);
|
|
1945
|
-
if (!parsed.success) {
|
|
1946
|
-
logger.warn(
|
|
1947
|
-
{ stepId: step.id, issues: parsed.error.issues },
|
|
1948
|
-
"reconcileWorkflowState: persisted output for a completed step no longer matches its schema; restarting the run from scratch"
|
|
1949
|
-
);
|
|
1950
|
-
return null;
|
|
1951
|
-
}
|
|
1952
|
-
}
|
|
1953
|
-
record.title = step.title;
|
|
1954
|
-
record.visible = step.visible;
|
|
2223
|
+
state.steps[i].title = workflow.steps[i].title;
|
|
2224
|
+
state.steps[i].visible = workflow.steps[i].visible;
|
|
1955
2225
|
}
|
|
1956
2226
|
return state;
|
|
1957
2227
|
}
|
|
@@ -3289,9 +3559,28 @@ import { tool as tool9 } from "ai";
|
|
|
3289
3559
|
import z16 from "zod";
|
|
3290
3560
|
import { stat as stat2 } from "node:fs/promises";
|
|
3291
3561
|
import { relative as relative5 } from "node:path";
|
|
3562
|
+
|
|
3563
|
+
// src/lib/editor.ts
|
|
3564
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
3565
|
+
function openInEditor(filePath) {
|
|
3566
|
+
const { command, args } = process.platform === "darwin" ? (
|
|
3567
|
+
// -t forces the default *text* editor; plain `open` on an extension
|
|
3568
|
+
// with no handler (.mjs, .py) pops a "choose an application" dialog.
|
|
3569
|
+
{ command: "open", args: ["-t", filePath] }
|
|
3570
|
+
) : process.platform === "win32" ? { command: "cmd", args: ["/c", "start", "", filePath] } : { command: "xdg-open", args: [filePath] };
|
|
3571
|
+
try {
|
|
3572
|
+
const child = spawn3(command, args, { stdio: "ignore", detached: true });
|
|
3573
|
+
child.on("error", () => {
|
|
3574
|
+
});
|
|
3575
|
+
child.unref();
|
|
3576
|
+
} catch {
|
|
3577
|
+
}
|
|
3578
|
+
}
|
|
3579
|
+
|
|
3580
|
+
// src/lib/tools/reviewScript.ts
|
|
3292
3581
|
function reviewScriptTool(ctx) {
|
|
3293
3582
|
return tool9({
|
|
3294
|
-
description: "Call this as soon as the
|
|
3583
|
+
description: "Show a script you have written to the user and wait while they read it. Call this as soon as the script is finished and before you run it for the first time, so nothing with a side effect happens behind their back. It opens the file in their editor and returns once they have confirmed.",
|
|
3295
3584
|
inputSchema: z16.object({
|
|
3296
3585
|
filePath: z16.string().describe(
|
|
3297
3586
|
"Path to the script to review, relative to the project root."
|
|
@@ -3309,6 +3598,7 @@ function reviewScriptTool(ctx) {
|
|
|
3309
3598
|
return `Refused: ${filePath} is not a file. Write the script first, then review the path you wrote.`;
|
|
3310
3599
|
}
|
|
3311
3600
|
return serializePrompt(async () => {
|
|
3601
|
+
openInEditor(resolved2.target);
|
|
3312
3602
|
await useWizard.getState().requestUserInput({
|
|
3313
3603
|
prompt: "",
|
|
3314
3604
|
promptType: "enterToContinue",
|
|
@@ -3437,10 +3727,10 @@ import { tool as tool11 } from "ai";
|
|
|
3437
3727
|
import z18 from "zod";
|
|
3438
3728
|
function notifyUserTool() {
|
|
3439
3729
|
return tool11({
|
|
3440
|
-
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.`,
|
|
3730
|
+
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. Only the latest update is shown on screen, in one line, so keep it under 140 characters.`,
|
|
3441
3731
|
inputSchema: z18.object({
|
|
3442
|
-
message: z18.string().describe(
|
|
3443
|
-
"Short, plain-language description of what you are doing now."
|
|
3732
|
+
message: z18.string().max(140).describe(
|
|
3733
|
+
"Short, plain-language description of what you are doing now. Under 140 characters \u2014 only the latest update is shown, on one line."
|
|
3444
3734
|
)
|
|
3445
3735
|
}),
|
|
3446
3736
|
execute: async ({ message }) => {
|
|
@@ -3756,7 +4046,7 @@ async function runAnalysis(mode, extraInstructions = []) {
|
|
|
3756
4046
|
// package.json
|
|
3757
4047
|
var package_default = {
|
|
3758
4048
|
name: "@algolia/wizard",
|
|
3759
|
-
version: "0.29.0
|
|
4049
|
+
version: "0.29.0",
|
|
3760
4050
|
description: "Magically implement Algolia functionality in your codebase",
|
|
3761
4051
|
type: "module",
|
|
3762
4052
|
engines: {
|
|
@@ -3818,6 +4108,7 @@ var package_default = {
|
|
|
3818
4108
|
nanoid: "^5.1.15",
|
|
3819
4109
|
pino: "^10.3.1",
|
|
3820
4110
|
react: "^19.2.7",
|
|
4111
|
+
"terminal-link": "^5.0.0",
|
|
3821
4112
|
varlock: "^1.5.1",
|
|
3822
4113
|
zod: "^4.4.3",
|
|
3823
4114
|
zustand: "^5.0.14"
|
|
@@ -5369,7 +5660,7 @@ function delay(ms) {
|
|
|
5369
5660
|
}
|
|
5370
5661
|
|
|
5371
5662
|
// src/main.tsx
|
|
5372
|
-
import { jsx as
|
|
5663
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
5373
5664
|
async function startup() {
|
|
5374
5665
|
setProjectRoot(process.cwd());
|
|
5375
5666
|
let args;
|
|
@@ -5419,7 +5710,7 @@ ${formatStepList(workflow)}`);
|
|
|
5419
5710
|
}
|
|
5420
5711
|
async function run(workflow) {
|
|
5421
5712
|
const store = useWizard.getState();
|
|
5422
|
-
const instance = render(/* @__PURE__ */
|
|
5713
|
+
const instance = render(/* @__PURE__ */ jsx18(App, {}), { incrementalRendering: true });
|
|
5423
5714
|
await store.waitForStart();
|
|
5424
5715
|
store.syncSteps(
|
|
5425
5716
|
workflow.steps.map((s) => ({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@algolia/wizard",
|
|
3
|
-
"version": "0.29.0
|
|
3
|
+
"version": "0.29.0",
|
|
4
4
|
"description": "Magically implement Algolia functionality in your codebase",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
"nanoid": "^5.1.15",
|
|
63
63
|
"pino": "^10.3.1",
|
|
64
64
|
"react": "^19.2.7",
|
|
65
|
+
"terminal-link": "^5.0.0",
|
|
65
66
|
"varlock": "^1.5.1",
|
|
66
67
|
"zod": "^4.4.3",
|
|
67
68
|
"zustand": "^5.0.14"
|