@algolia/wizard 0.12.0-rc.104.151 → 0.13.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 +588 -557
- package/package.json +1 -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 Box16, Text as Text16, useApp, useInput as useInput7, useWindowSize as useWindowSize8 } from "ink";
|
|
8
8
|
|
|
9
9
|
// src/core/store.ts
|
|
10
10
|
import { create } from "zustand";
|
|
@@ -304,7 +304,10 @@ var useWizard = create((set, get) => ({
|
|
|
304
304
|
if (_noticeTimer === null) {
|
|
305
305
|
set({
|
|
306
306
|
notices: [...notices, notice],
|
|
307
|
-
_noticeTimer: setTimeout(
|
|
307
|
+
_noticeTimer: setTimeout(
|
|
308
|
+
() => get()._drainNoticeQueue(),
|
|
309
|
+
NOTICE_INTERVAL_MS
|
|
310
|
+
)
|
|
308
311
|
});
|
|
309
312
|
} else {
|
|
310
313
|
set({ _noticeQueue: [..._noticeQueue, notice] });
|
|
@@ -316,7 +319,10 @@ var useWizard = create((set, get) => ({
|
|
|
316
319
|
set((s) => ({
|
|
317
320
|
notices: [...s.notices, next],
|
|
318
321
|
_noticeQueue: rest,
|
|
319
|
-
_noticeTimer: setTimeout(
|
|
322
|
+
_noticeTimer: setTimeout(
|
|
323
|
+
() => get()._drainNoticeQueue(),
|
|
324
|
+
NOTICE_INTERVAL_MS
|
|
325
|
+
)
|
|
320
326
|
}));
|
|
321
327
|
} else {
|
|
322
328
|
set({ _noticeTimer: null });
|
|
@@ -364,13 +370,17 @@ var useWizard = create((set, get) => ({
|
|
|
364
370
|
await markInteraction();
|
|
365
371
|
get()._resolve?.(value);
|
|
366
372
|
set({ inputReq: null, _resolve: null, phase: "running" });
|
|
367
|
-
const id = get().logStart(
|
|
373
|
+
const id = get().logStart(
|
|
374
|
+
"prompt",
|
|
375
|
+
`User input: ${describeInputValue(value)}`
|
|
376
|
+
);
|
|
368
377
|
get().logEnd(id, "success");
|
|
369
378
|
},
|
|
370
379
|
setDone: () => set({ phase: "done" }),
|
|
371
380
|
setError: (message) => set({ phase: "error", error: message }),
|
|
372
381
|
reset: () => {
|
|
373
382
|
get()._clearNoticeQueue();
|
|
383
|
+
get()._resolve?.(false);
|
|
374
384
|
set({
|
|
375
385
|
phase: "idle",
|
|
376
386
|
homeScreen: "home",
|
|
@@ -622,10 +632,13 @@ function Notices() {
|
|
|
622
632
|
}
|
|
623
633
|
|
|
624
634
|
// src/ui/PromptInput.tsx
|
|
625
|
-
import { Box as
|
|
635
|
+
import { Box as Box8, Text as Text8, useInput as useInput3 } from "ink";
|
|
626
636
|
import TextInput from "ink-text-input";
|
|
627
637
|
import { useState as useState5 } from "react";
|
|
628
638
|
|
|
639
|
+
// src/ui/CommandApproval.tsx
|
|
640
|
+
import { Box as Box5, Text as Text5, useInput } from "ink";
|
|
641
|
+
|
|
629
642
|
// src/ui/NextAction.tsx
|
|
630
643
|
import { Box as Box4, Text as Text4 } from "ink";
|
|
631
644
|
import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
@@ -649,14 +662,60 @@ function NextAction({
|
|
|
649
662
|
] });
|
|
650
663
|
}
|
|
651
664
|
|
|
665
|
+
// src/ui/CommandApproval.tsx
|
|
666
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
667
|
+
function CommandApproval({
|
|
668
|
+
command,
|
|
669
|
+
onDecide
|
|
670
|
+
}) {
|
|
671
|
+
useInput((_input, key) => {
|
|
672
|
+
if (key.return) onDecide("approve");
|
|
673
|
+
else if (key.escape) onDecide("reject");
|
|
674
|
+
});
|
|
675
|
+
return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", gap: 1, children: [
|
|
676
|
+
/* @__PURE__ */ jsx4(Text5, { color: COLORS.primary, bold: true, children: "Run this command?" }),
|
|
677
|
+
/* @__PURE__ */ jsxs4(
|
|
678
|
+
Box5,
|
|
679
|
+
{
|
|
680
|
+
flexDirection: "column",
|
|
681
|
+
paddingLeft: 2,
|
|
682
|
+
borderStyle: "single",
|
|
683
|
+
borderColor: COLORS.success,
|
|
684
|
+
borderTop: false,
|
|
685
|
+
borderBottom: false,
|
|
686
|
+
borderRight: false,
|
|
687
|
+
gap: 1,
|
|
688
|
+
children: [
|
|
689
|
+
/* @__PURE__ */ jsxs4(Box5, { children: [
|
|
690
|
+
/* @__PURE__ */ jsx4(Text5, { color: COLORS.muted, children: "$ " }),
|
|
691
|
+
/* @__PURE__ */ jsx4(Text5, { color: COLORS.strong, wrap: "wrap", children: command.command })
|
|
692
|
+
] }),
|
|
693
|
+
/* @__PURE__ */ jsxs4(Box5, { gap: 1, children: [
|
|
694
|
+
/* @__PURE__ */ jsx4(Text5, { color: COLORS.muted, children: "in:" }),
|
|
695
|
+
/* @__PURE__ */ jsx4(Text5, { color: COLORS.muted, wrap: "wrap", children: command.cwd })
|
|
696
|
+
] }),
|
|
697
|
+
command.explanation && /* @__PURE__ */ jsxs4(Box5, { gap: 1, children: [
|
|
698
|
+
/* @__PURE__ */ jsx4(Text5, { color: COLORS.muted, children: "why:" }),
|
|
699
|
+
/* @__PURE__ */ jsx4(Text5, { color: COLORS.accent, wrap: "wrap", children: command.explanation })
|
|
700
|
+
] })
|
|
701
|
+
]
|
|
702
|
+
}
|
|
703
|
+
),
|
|
704
|
+
/* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
|
|
705
|
+
/* @__PURE__ */ jsx4(NextAction, { action: "approve", keyHint: "enter" }),
|
|
706
|
+
/* @__PURE__ */ jsx4(NextAction, { action: "reject", keyHint: "esc", hierarchy: "secondary" })
|
|
707
|
+
] })
|
|
708
|
+
] });
|
|
709
|
+
}
|
|
710
|
+
|
|
652
711
|
// src/ui/SelectPrompt.tsx
|
|
653
|
-
import { Box as
|
|
712
|
+
import { Box as Box7, Text as Text7, useInput as useInput2, useWindowSize as useWindowSize5 } from "ink";
|
|
654
713
|
import { useLayoutEffect as useLayoutEffect2, useRef as useRef3, useState as useState4 } from "react";
|
|
655
714
|
|
|
656
715
|
// src/ui/ScrollView.tsx
|
|
657
|
-
import { Box as
|
|
716
|
+
import { Box as Box6, Text as Text6, measureElement as measureElement2, useWindowSize as useWindowSize4 } from "ink";
|
|
658
717
|
import { useCallback, useLayoutEffect, useRef as useRef2, useState as useState3 } from "react";
|
|
659
|
-
import { jsxs as
|
|
718
|
+
import { jsxs as jsxs5 } from "react/jsx-runtime";
|
|
660
719
|
var INDICATOR_ROWS = 2;
|
|
661
720
|
function fittedWidth(node, columns) {
|
|
662
721
|
let left = 0;
|
|
@@ -726,14 +785,14 @@ function useScrollWindow({
|
|
|
726
785
|
};
|
|
727
786
|
}
|
|
728
787
|
function ScrollView({ scroll, children }) {
|
|
729
|
-
return /* @__PURE__ */
|
|
730
|
-
scroll.hiddenAbove > 0 && /* @__PURE__ */
|
|
788
|
+
return /* @__PURE__ */ jsxs5(Box6, { ref: scroll.viewportRef, flexDirection: "column", flexGrow: 1, children: [
|
|
789
|
+
scroll.hiddenAbove > 0 && /* @__PURE__ */ jsxs5(Text6, { color: COLORS.dim, children: [
|
|
731
790
|
"\u2191 ",
|
|
732
791
|
scroll.hiddenAbove,
|
|
733
792
|
" more"
|
|
734
793
|
] }),
|
|
735
794
|
children,
|
|
736
|
-
scroll.hiddenBelow > 0 && /* @__PURE__ */
|
|
795
|
+
scroll.hiddenBelow > 0 && /* @__PURE__ */ jsxs5(Text6, { color: COLORS.dim, children: [
|
|
737
796
|
"\u2193 ",
|
|
738
797
|
scroll.hiddenBelow,
|
|
739
798
|
" more"
|
|
@@ -742,7 +801,7 @@ function ScrollView({ scroll, children }) {
|
|
|
742
801
|
}
|
|
743
802
|
|
|
744
803
|
// src/ui/SelectPrompt.tsx
|
|
745
|
-
import { jsx as
|
|
804
|
+
import { jsx as jsx5, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
746
805
|
var CANCEL = "cancel";
|
|
747
806
|
var ARROW_WIDTH = 4;
|
|
748
807
|
var COLUMN_GAP = 2;
|
|
@@ -804,7 +863,7 @@ function SelectPrompt({
|
|
|
804
863
|
revealIndex(index);
|
|
805
864
|
}, [index, revealIndex]);
|
|
806
865
|
const visible = rows.slice(scroll.offset, scroll.offset + scroll.capacity);
|
|
807
|
-
|
|
866
|
+
useInput2((input, key) => {
|
|
808
867
|
if (rows.length === 0) return;
|
|
809
868
|
if (key.upArrow || input === "k") {
|
|
810
869
|
setIndex((i) => (i - 1 + rows.length) % rows.length);
|
|
@@ -827,56 +886,56 @@ function SelectPrompt({
|
|
|
827
886
|
}
|
|
828
887
|
}
|
|
829
888
|
});
|
|
830
|
-
return /* @__PURE__ */
|
|
831
|
-
/* @__PURE__ */
|
|
832
|
-
error && /* @__PURE__ */
|
|
833
|
-
messages?.map((m, i) => /* @__PURE__ */
|
|
834
|
-
table && /* @__PURE__ */
|
|
835
|
-
/* @__PURE__ */
|
|
836
|
-
question && /* @__PURE__ */
|
|
837
|
-
helpText && /* @__PURE__ */
|
|
889
|
+
return /* @__PURE__ */ jsx5(Box7, { ref: containerRef, flexGrow: 1, children: /* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", gap: 1, width, children: [
|
|
890
|
+
/* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", gap: 1, flexShrink: 0, children: [
|
|
891
|
+
error && /* @__PURE__ */ jsx5(Text7, { color: COLORS.danger, children: error }),
|
|
892
|
+
messages?.map((m, i) => /* @__PURE__ */ jsx5(Text7, { color: COLORS.muted, children: m }, `msg-${i}`)),
|
|
893
|
+
table && /* @__PURE__ */ jsx5(Table, { columns: table.columns, rows: table.rows }),
|
|
894
|
+
/* @__PURE__ */ jsxs6(Box7, { flexDirection: "column", children: [
|
|
895
|
+
question && /* @__PURE__ */ jsx5(Text7, { color: COLORS.muted, children: question }),
|
|
896
|
+
helpText && /* @__PURE__ */ jsx5(Text7, { color: COLORS.dim, children: helpText })
|
|
838
897
|
] })
|
|
839
898
|
] }),
|
|
840
|
-
/* @__PURE__ */
|
|
899
|
+
/* @__PURE__ */ jsx5(ScrollView, { scroll, children: visible.map((option, visibleIndex) => {
|
|
841
900
|
const i = scroll.offset + visibleIndex;
|
|
842
901
|
const highlighted = i === index;
|
|
843
902
|
const isCancel = i === cancelIndex;
|
|
844
903
|
const bullet = multi && !isCancel ? checked.has(i) ? "\u25CF " : "\u25CB " : "";
|
|
845
904
|
const sec = isCancel ? void 0 : secondary?.[i];
|
|
846
905
|
const labelColor = highlighted ? COLORS.highlight.fg : void 0;
|
|
847
|
-
const label = /* @__PURE__ */
|
|
906
|
+
const label = /* @__PURE__ */ jsxs6(Text7, { color: labelColor, wrap: "truncate", children: [
|
|
848
907
|
highlighted ? "\u276F " : " ",
|
|
849
908
|
bullet,
|
|
850
909
|
option
|
|
851
910
|
] });
|
|
852
911
|
const isText = sec?.kind === "text";
|
|
853
|
-
return /* @__PURE__ */
|
|
854
|
-
|
|
912
|
+
return /* @__PURE__ */ jsxs6(
|
|
913
|
+
Box7,
|
|
855
914
|
{
|
|
856
915
|
width: isText ? "100%" : barWidth,
|
|
857
916
|
paddingX: 1,
|
|
858
917
|
paddingY: 1,
|
|
859
918
|
backgroundColor: highlighted ? COLORS.highlight.bg : void 0,
|
|
860
919
|
children: [
|
|
861
|
-
/* @__PURE__ */
|
|
862
|
-
isText && textWidth > 0 && /* @__PURE__ */
|
|
863
|
-
|
|
920
|
+
/* @__PURE__ */ jsx5(Box7, { width: isText ? labelWidth : barLabelWidth, children: label }),
|
|
921
|
+
isText && textWidth > 0 && /* @__PURE__ */ jsx5(Box7, { width: textWidth, children: /* @__PURE__ */ jsx5(
|
|
922
|
+
Text7,
|
|
864
923
|
{
|
|
865
924
|
wrap: "truncate",
|
|
866
925
|
color: highlighted ? COLORS.primary : COLORS.muted,
|
|
867
926
|
children: sec.value
|
|
868
927
|
}
|
|
869
928
|
) }),
|
|
870
|
-
sec?.kind === "badge" && /* @__PURE__ */
|
|
929
|
+
sec?.kind === "badge" && /* @__PURE__ */ jsx5(Box7, { width: badgeWidth, justifyContent: "flex-end", children: /* @__PURE__ */ jsx5(Text7, { color: COLORS.badge, wrap: "truncate", children: sec.value }) })
|
|
871
930
|
]
|
|
872
931
|
},
|
|
873
932
|
`row-${i}`
|
|
874
933
|
);
|
|
875
934
|
}) }),
|
|
876
|
-
/* @__PURE__ */
|
|
935
|
+
/* @__PURE__ */ jsx5(Box7, { flexShrink: 0, children: /* @__PURE__ */ jsx5(Text7, { children: hints.map(({ key, label }, i) => /* @__PURE__ */ jsxs6(Text7, { children: [
|
|
877
936
|
i > 0 ? " " : "",
|
|
878
|
-
/* @__PURE__ */
|
|
879
|
-
/* @__PURE__ */
|
|
937
|
+
/* @__PURE__ */ jsx5(Text7, { color: COLORS.primary, children: key }),
|
|
938
|
+
/* @__PURE__ */ jsxs6(Text7, { color: COLORS.dim, children: [
|
|
880
939
|
" ",
|
|
881
940
|
label
|
|
882
941
|
] })
|
|
@@ -885,23 +944,23 @@ function SelectPrompt({
|
|
|
885
944
|
}
|
|
886
945
|
|
|
887
946
|
// src/ui/PromptInput.tsx
|
|
888
|
-
import { jsx as
|
|
947
|
+
import { jsx as jsx6, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
889
948
|
var ACCEPT_REJECT_OPTIONS = ["Accept", "Reject"];
|
|
890
949
|
function EnterToContinuePrompt({
|
|
891
950
|
question,
|
|
892
951
|
messages,
|
|
893
952
|
onDecide
|
|
894
953
|
}) {
|
|
895
|
-
|
|
954
|
+
useInput3((_input, key) => {
|
|
896
955
|
if (key.return) onDecide(true);
|
|
897
956
|
else if (key.escape) onDecide(false);
|
|
898
957
|
});
|
|
899
|
-
return /* @__PURE__ */
|
|
900
|
-
messages?.map((m, i) => /* @__PURE__ */
|
|
901
|
-
question && /* @__PURE__ */
|
|
902
|
-
/* @__PURE__ */
|
|
903
|
-
/* @__PURE__ */
|
|
904
|
-
/* @__PURE__ */
|
|
958
|
+
return /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", gap: 1, children: [
|
|
959
|
+
messages?.map((m, i) => /* @__PURE__ */ jsx6(Text8, { color: COLORS.muted, children: m }, `msg-${i}`)),
|
|
960
|
+
question && /* @__PURE__ */ jsx6(Text8, { color: COLORS.primary, children: question }),
|
|
961
|
+
/* @__PURE__ */ jsxs7(Box8, { gap: 1, flexDirection: "column", children: [
|
|
962
|
+
/* @__PURE__ */ jsx6(NextAction, { action: "continue", keyHint: "enter" }),
|
|
963
|
+
/* @__PURE__ */ jsx6(NextAction, { action: "decline", keyHint: "esc", hierarchy: "secondary" })
|
|
905
964
|
] })
|
|
906
965
|
] });
|
|
907
966
|
}
|
|
@@ -909,11 +968,11 @@ function PromptInput() {
|
|
|
909
968
|
const { phase, inputReq, submitInput } = useWizard();
|
|
910
969
|
const [draft, setDraft] = useState5("");
|
|
911
970
|
if (phase === "done" || phase === "error") {
|
|
912
|
-
return /* @__PURE__ */
|
|
971
|
+
return /* @__PURE__ */ jsx6(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text8, { color: "gray", dimColor: true, children: "Press Enter or Esc to exit" }) });
|
|
913
972
|
}
|
|
914
973
|
if (phase !== "awaitingInput" || !inputReq) return null;
|
|
915
974
|
if (inputReq.promptType === "multipleChoice") {
|
|
916
|
-
return /* @__PURE__ */
|
|
975
|
+
return /* @__PURE__ */ jsx6(Box8, { flexGrow: 1, children: /* @__PURE__ */ jsx6(
|
|
917
976
|
SelectPrompt,
|
|
918
977
|
{
|
|
919
978
|
question: inputReq.prompt,
|
|
@@ -930,7 +989,7 @@ function PromptInput() {
|
|
|
930
989
|
) });
|
|
931
990
|
}
|
|
932
991
|
if (inputReq.promptType === "multiSelect") {
|
|
933
|
-
return /* @__PURE__ */
|
|
992
|
+
return /* @__PURE__ */ jsx6(Box8, { flexGrow: 1, children: /* @__PURE__ */ jsx6(
|
|
934
993
|
SelectPrompt,
|
|
935
994
|
{
|
|
936
995
|
multi: true,
|
|
@@ -945,7 +1004,7 @@ function PromptInput() {
|
|
|
945
1004
|
) });
|
|
946
1005
|
}
|
|
947
1006
|
if (inputReq.promptType === "notice") {
|
|
948
|
-
return /* @__PURE__ */
|
|
1007
|
+
return /* @__PURE__ */ jsx6(Box8, { flexGrow: 1, children: /* @__PURE__ */ jsx6(
|
|
949
1008
|
SelectPrompt,
|
|
950
1009
|
{
|
|
951
1010
|
question: inputReq.prompt,
|
|
@@ -956,7 +1015,7 @@ function PromptInput() {
|
|
|
956
1015
|
) });
|
|
957
1016
|
}
|
|
958
1017
|
if (inputReq.promptType === "enterToContinue") {
|
|
959
|
-
return /* @__PURE__ */
|
|
1018
|
+
return /* @__PURE__ */ jsx6(
|
|
960
1019
|
EnterToContinuePrompt,
|
|
961
1020
|
{
|
|
962
1021
|
question: inputReq.prompt,
|
|
@@ -965,9 +1024,12 @@ function PromptInput() {
|
|
|
965
1024
|
}
|
|
966
1025
|
);
|
|
967
1026
|
}
|
|
1027
|
+
if (inputReq.promptType === "commandApproval" && inputReq.command) {
|
|
1028
|
+
return /* @__PURE__ */ jsx6(CommandApproval, { command: inputReq.command, onDecide: submitInput });
|
|
1029
|
+
}
|
|
968
1030
|
if (inputReq.promptType === "acceptReject") {
|
|
969
1031
|
const labels = inputReq.options?.length ? inputReq.options : ACCEPT_REJECT_OPTIONS;
|
|
970
|
-
return /* @__PURE__ */
|
|
1032
|
+
return /* @__PURE__ */ jsx6(Box8, { flexGrow: 1, children: /* @__PURE__ */ jsx6(
|
|
971
1033
|
SelectPrompt,
|
|
972
1034
|
{
|
|
973
1035
|
question: inputReq.prompt,
|
|
@@ -978,15 +1040,15 @@ function PromptInput() {
|
|
|
978
1040
|
}
|
|
979
1041
|
) });
|
|
980
1042
|
}
|
|
981
|
-
return /* @__PURE__ */
|
|
982
|
-
inputReq.error && /* @__PURE__ */
|
|
983
|
-
inputReq.messages?.map((m, i) => /* @__PURE__ */
|
|
984
|
-
/* @__PURE__ */
|
|
985
|
-
/* @__PURE__ */
|
|
1043
|
+
return /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", children: [
|
|
1044
|
+
inputReq.error && /* @__PURE__ */ jsx6(Text8, { color: COLORS.danger, children: inputReq.error }),
|
|
1045
|
+
inputReq.messages?.map((m, i) => /* @__PURE__ */ jsx6(Text8, { color: COLORS.muted, children: m }, `msg-${i}`)),
|
|
1046
|
+
/* @__PURE__ */ jsxs7(Box8, { children: [
|
|
1047
|
+
/* @__PURE__ */ jsxs7(Text8, { color: COLORS.primary, children: [
|
|
986
1048
|
inputReq.prompt,
|
|
987
1049
|
" "
|
|
988
1050
|
] }),
|
|
989
|
-
/* @__PURE__ */
|
|
1051
|
+
/* @__PURE__ */ jsx6(
|
|
990
1052
|
TextInput,
|
|
991
1053
|
{
|
|
992
1054
|
value: draft,
|
|
@@ -1004,7 +1066,7 @@ function PromptInput() {
|
|
|
1004
1066
|
// src/ui/Welcome.tsx
|
|
1005
1067
|
import { dirname as dirname2, join as join3 } from "node:path";
|
|
1006
1068
|
import { fileURLToPath } from "node:url";
|
|
1007
|
-
import { Box as
|
|
1069
|
+
import { Box as Box9, Spacer, Text as Text9, useInput as useInput4, useWindowSize as useWindowSize6 } from "ink";
|
|
1008
1070
|
|
|
1009
1071
|
// src/ui/copy/welcome.ts
|
|
1010
1072
|
var sidebarItems = [
|
|
@@ -1032,7 +1094,7 @@ var sidebarItems = [
|
|
|
1032
1094
|
|
|
1033
1095
|
// src/ui/Welcome.tsx
|
|
1034
1096
|
import Image, { TerminalInfoContext, defaultTerminalInfo } from "ink-picture";
|
|
1035
|
-
import { jsx as
|
|
1097
|
+
import { jsx as jsx7, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1036
1098
|
var IMAGE_PATH = join3(dirname2(fileURLToPath(import.meta.url)), "algolia.png");
|
|
1037
1099
|
var TERMINAL_INFO = {
|
|
1038
1100
|
...defaultTerminalInfo,
|
|
@@ -1043,14 +1105,14 @@ function SidebarItem({
|
|
|
1043
1105
|
title,
|
|
1044
1106
|
description
|
|
1045
1107
|
}) {
|
|
1046
|
-
return /* @__PURE__ */
|
|
1047
|
-
/* @__PURE__ */
|
|
1048
|
-
/* @__PURE__ */
|
|
1049
|
-
/* @__PURE__ */
|
|
1108
|
+
return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "column", children: [
|
|
1109
|
+
/* @__PURE__ */ jsxs8(Box9, { gap: 1, children: [
|
|
1110
|
+
/* @__PURE__ */ jsx7(Text9, { color: COLORS.success, children: "\u2192" }),
|
|
1111
|
+
/* @__PURE__ */ jsx7(Text9, { color: COLORS.strong, bold: true, children: title })
|
|
1050
1112
|
] }),
|
|
1051
|
-
/* @__PURE__ */
|
|
1052
|
-
/* @__PURE__ */
|
|
1053
|
-
/* @__PURE__ */
|
|
1113
|
+
/* @__PURE__ */ jsxs8(Box9, { flexDirection: "row", gap: 2, children: [
|
|
1114
|
+
/* @__PURE__ */ jsx7(Spacer, {}),
|
|
1115
|
+
/* @__PURE__ */ jsx7(Text9, { color: COLORS.muted, children: description })
|
|
1054
1116
|
] })
|
|
1055
1117
|
] });
|
|
1056
1118
|
}
|
|
@@ -1058,7 +1120,7 @@ function Welcome() {
|
|
|
1058
1120
|
const confirmStart = useWizard((s) => s.confirmStart);
|
|
1059
1121
|
const openLearnMore = useWizard((s) => s.openLearnMore);
|
|
1060
1122
|
const { rows } = useWindowSize6();
|
|
1061
|
-
|
|
1123
|
+
useInput4((input, key) => {
|
|
1062
1124
|
if (key.return) confirmStart();
|
|
1063
1125
|
else if (input === "i") openLearnMore();
|
|
1064
1126
|
});
|
|
@@ -1076,16 +1138,16 @@ function Welcome() {
|
|
|
1076
1138
|
if (rows < 30) {
|
|
1077
1139
|
layout = scales["small"];
|
|
1078
1140
|
}
|
|
1079
|
-
return /* @__PURE__ */
|
|
1080
|
-
/* @__PURE__ */
|
|
1081
|
-
|
|
1141
|
+
return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "row", justifyContent: "space-between", width: "100%", children: [
|
|
1142
|
+
/* @__PURE__ */ jsx7(
|
|
1143
|
+
Box9,
|
|
1082
1144
|
{
|
|
1083
1145
|
paddingY: layout.main.padding.y,
|
|
1084
1146
|
paddingX: layout.main.padding.x,
|
|
1085
1147
|
flexDirection: "column",
|
|
1086
1148
|
justifyContent: "center",
|
|
1087
|
-
children: /* @__PURE__ */
|
|
1088
|
-
/* @__PURE__ */
|
|
1149
|
+
children: /* @__PURE__ */ jsxs8(Box9, { flexDirection: "column", gap: 2, children: [
|
|
1150
|
+
/* @__PURE__ */ jsx7(TerminalInfoContext.Provider, { value: TERMINAL_INFO, children: /* @__PURE__ */ jsx7(
|
|
1089
1151
|
Image,
|
|
1090
1152
|
{
|
|
1091
1153
|
src: IMAGE_PATH,
|
|
@@ -1096,16 +1158,16 @@ function Welcome() {
|
|
|
1096
1158
|
protocol: "halfBlock"
|
|
1097
1159
|
}
|
|
1098
1160
|
) }),
|
|
1099
|
-
/* @__PURE__ */
|
|
1100
|
-
/* @__PURE__ */
|
|
1101
|
-
/* @__PURE__ */
|
|
1102
|
-
/* @__PURE__ */
|
|
1161
|
+
/* @__PURE__ */ jsx7(Text9, { color: COLORS.muted, children: "\u2726 From zero \u2192 working search in ~10 minutes" }),
|
|
1162
|
+
/* @__PURE__ */ jsxs8(Box9, { gap: 1, flexDirection: "column", children: [
|
|
1163
|
+
/* @__PURE__ */ jsx7(NextAction, { action: "start wizard", keyHint: "enter" }),
|
|
1164
|
+
/* @__PURE__ */ jsx7(NextAction, { action: "learn more", keyHint: "i", hierarchy: "secondary" })
|
|
1103
1165
|
] })
|
|
1104
1166
|
] })
|
|
1105
1167
|
}
|
|
1106
1168
|
),
|
|
1107
|
-
/* @__PURE__ */
|
|
1108
|
-
|
|
1169
|
+
/* @__PURE__ */ jsxs8(
|
|
1170
|
+
Box9,
|
|
1109
1171
|
{
|
|
1110
1172
|
backgroundColor: COLORS.bg.sidebar,
|
|
1111
1173
|
width: 40,
|
|
@@ -1115,8 +1177,8 @@ function Welcome() {
|
|
|
1115
1177
|
flexDirection: "column",
|
|
1116
1178
|
justifyContent: "center",
|
|
1117
1179
|
children: [
|
|
1118
|
-
/* @__PURE__ */
|
|
1119
|
-
sidebarItems.map((i, idx) => /* @__PURE__ */
|
|
1180
|
+
/* @__PURE__ */ jsx7(Text9, { color: COLORS.muted, children: "WHAT THIS WIZARD WILL DO" }),
|
|
1181
|
+
sidebarItems.map((i, idx) => /* @__PURE__ */ jsx7(SidebarItem, { title: i.title, description: i.description }, idx))
|
|
1120
1182
|
]
|
|
1121
1183
|
}
|
|
1122
1184
|
)
|
|
@@ -1125,7 +1187,7 @@ function Welcome() {
|
|
|
1125
1187
|
|
|
1126
1188
|
// src/ui/LearnMore.tsx
|
|
1127
1189
|
import { Fragment as Fragment2 } from "react";
|
|
1128
|
-
import { Box as
|
|
1190
|
+
import { Box as Box10, Text as Text10, useInput as useInput5, useWindowSize as useWindowSize7 } from "ink";
|
|
1129
1191
|
|
|
1130
1192
|
// src/ui/copy/learn-more.ts
|
|
1131
1193
|
var accessIntro = "Everything runs locally on your machine. Nothing is written or sent without an explicit yes from you.";
|
|
@@ -1133,12 +1195,17 @@ var accessItems = [
|
|
|
1133
1195
|
{
|
|
1134
1196
|
tag: "READ",
|
|
1135
1197
|
title: "Project files",
|
|
1136
|
-
description: "reads
|
|
1198
|
+
description: "reads manifests, configs & source to detect your stack. Read-only; nothing is uploaded."
|
|
1137
1199
|
},
|
|
1138
1200
|
{
|
|
1139
1201
|
tag: "WRITE",
|
|
1140
1202
|
title: "Code changes",
|
|
1141
|
-
description: "creates & edits files (search UI, config)
|
|
1203
|
+
description: "creates & edits files (search UI, config) in a throwaway git worktree \u2014 your checkout is never touched."
|
|
1204
|
+
},
|
|
1205
|
+
{
|
|
1206
|
+
tag: "EXEC",
|
|
1207
|
+
title: "Setup commands",
|
|
1208
|
+
description: "runs dependency installs, the ingestion script & your own checks. Every command is shown in full and needs your OK; its output is shown as-is, so a command that prints a secret will display it."
|
|
1142
1209
|
},
|
|
1143
1210
|
{
|
|
1144
1211
|
tag: "NET",
|
|
@@ -1148,13 +1215,13 @@ var accessItems = [
|
|
|
1148
1215
|
{
|
|
1149
1216
|
tag: "KEY",
|
|
1150
1217
|
title: "Credentials",
|
|
1151
|
-
description: "
|
|
1218
|
+
description: "writes your Algolia app id and a search-only key (safe to expose) to .env in the worktree."
|
|
1152
1219
|
}
|
|
1153
1220
|
];
|
|
1154
1221
|
var neverItems = [
|
|
1155
1222
|
"Send your source code to a model or third party",
|
|
1156
1223
|
"Commit or push to git",
|
|
1157
|
-
"
|
|
1224
|
+
"Run a command you haven't approved"
|
|
1158
1225
|
];
|
|
1159
1226
|
var policyLinks = [
|
|
1160
1227
|
{ label: "Terms", url: "https://www.algolia.com/policies/terms" },
|
|
@@ -1162,10 +1229,11 @@ var policyLinks = [
|
|
|
1162
1229
|
];
|
|
1163
1230
|
|
|
1164
1231
|
// src/ui/LearnMore.tsx
|
|
1165
|
-
import { jsx as
|
|
1232
|
+
import { jsx as jsx8, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1166
1233
|
var TAG_COLORS = {
|
|
1167
1234
|
READ: COLORS.success,
|
|
1168
1235
|
WRITE: COLORS.badge,
|
|
1236
|
+
EXEC: COLORS.danger,
|
|
1169
1237
|
NET: COLORS.accent,
|
|
1170
1238
|
KEY: COLORS.muted
|
|
1171
1239
|
};
|
|
@@ -1178,12 +1246,12 @@ function NeverLine({
|
|
|
1178
1246
|
}) {
|
|
1179
1247
|
const used = segments.reduce((n, s) => n + s.text.length, 0);
|
|
1180
1248
|
const rightPad = Math.max(0, width - 2 - NEVER_BOX_PAD_X - used);
|
|
1181
|
-
return /* @__PURE__ */
|
|
1182
|
-
/* @__PURE__ */
|
|
1249
|
+
return /* @__PURE__ */ jsxs9(Text10, { children: [
|
|
1250
|
+
/* @__PURE__ */ jsx8(Text10, { color: COLORS.danger, children: "\u2502" }),
|
|
1183
1251
|
" ".repeat(NEVER_BOX_PAD_X),
|
|
1184
|
-
segments.map((s, i) => /* @__PURE__ */
|
|
1252
|
+
segments.map((s, i) => /* @__PURE__ */ jsx8(Text10, { color: s.color, bold: s.bold, children: s.text }, i)),
|
|
1185
1253
|
" ".repeat(rightPad),
|
|
1186
|
-
/* @__PURE__ */
|
|
1254
|
+
/* @__PURE__ */ jsx8(Text10, { color: COLORS.danger, children: "\u2502" })
|
|
1187
1255
|
] });
|
|
1188
1256
|
}
|
|
1189
1257
|
function LearnMore() {
|
|
@@ -1191,12 +1259,12 @@ function LearnMore() {
|
|
|
1191
1259
|
const backToHome = useWizard((s) => s.backToHome);
|
|
1192
1260
|
const { columns } = useWindowSize7();
|
|
1193
1261
|
const dividerWidth = Math.max(0, columns - PADDING_X * 2);
|
|
1194
|
-
|
|
1262
|
+
useInput5((_input, key) => {
|
|
1195
1263
|
if (key.escape) backToHome();
|
|
1196
1264
|
else if (key.return) confirmStart();
|
|
1197
1265
|
});
|
|
1198
|
-
return /* @__PURE__ */
|
|
1199
|
-
|
|
1266
|
+
return /* @__PURE__ */ jsxs9(
|
|
1267
|
+
Box10,
|
|
1200
1268
|
{
|
|
1201
1269
|
flexDirection: "column",
|
|
1202
1270
|
paddingX: PADDING_X,
|
|
@@ -1204,31 +1272,31 @@ function LearnMore() {
|
|
|
1204
1272
|
width: "100%",
|
|
1205
1273
|
gap: 1,
|
|
1206
1274
|
children: [
|
|
1207
|
-
/* @__PURE__ */
|
|
1208
|
-
/* @__PURE__ */
|
|
1209
|
-
/* @__PURE__ */
|
|
1210
|
-
/* @__PURE__ */
|
|
1211
|
-
/* @__PURE__ */
|
|
1212
|
-
/* @__PURE__ */
|
|
1213
|
-
/* @__PURE__ */
|
|
1214
|
-
/* @__PURE__ */
|
|
1215
|
-
/* @__PURE__ */
|
|
1275
|
+
/* @__PURE__ */ jsx8(Text10, { color: COLORS.strong, bold: true, children: "What algolia wizard accesses" }),
|
|
1276
|
+
/* @__PURE__ */ jsx8(Text10, { color: COLORS.muted, children: accessIntro }),
|
|
1277
|
+
/* @__PURE__ */ jsx8(Box10, { flexDirection: "column", children: accessItems.map((item) => /* @__PURE__ */ jsxs9(Box10, { flexDirection: "column", marginTop: 1, children: [
|
|
1278
|
+
/* @__PURE__ */ jsx8(Text10, { color: COLORS.border, children: "\u2500".repeat(dividerWidth) }),
|
|
1279
|
+
/* @__PURE__ */ jsxs9(Box10, { flexDirection: "row", gap: 1, marginTop: 1, children: [
|
|
1280
|
+
/* @__PURE__ */ jsx8(Box10, { width: TAG_COLUMN_WIDTH, flexShrink: 0, children: /* @__PURE__ */ jsx8(Text10, { color: TAG_COLORS[item.tag], bold: true, children: `[${item.tag}]` }) }),
|
|
1281
|
+
/* @__PURE__ */ jsx8(Box10, { flexDirection: "column", children: /* @__PURE__ */ jsxs9(Text10, { children: [
|
|
1282
|
+
/* @__PURE__ */ jsx8(Text10, { color: COLORS.strong, bold: true, children: item.title }),
|
|
1283
|
+
/* @__PURE__ */ jsx8(Text10, { color: COLORS.muted, children: ` \u2014 ${item.description}` })
|
|
1216
1284
|
] }) })
|
|
1217
1285
|
] })
|
|
1218
1286
|
] }, item.tag)) }),
|
|
1219
|
-
/* @__PURE__ */
|
|
1220
|
-
/* @__PURE__ */
|
|
1221
|
-
/* @__PURE__ */
|
|
1222
|
-
/* @__PURE__ */
|
|
1287
|
+
/* @__PURE__ */ jsxs9(Box10, { marginTop: 1, flexDirection: "column", children: [
|
|
1288
|
+
/* @__PURE__ */ jsx8(Text10, { color: COLORS.danger, children: `\u256D${"\u2500".repeat(Math.max(0, dividerWidth - 2))}\u256E` }),
|
|
1289
|
+
/* @__PURE__ */ jsx8(NeverLine, { width: dividerWidth }),
|
|
1290
|
+
/* @__PURE__ */ jsx8(
|
|
1223
1291
|
NeverLine,
|
|
1224
1292
|
{
|
|
1225
1293
|
width: dividerWidth,
|
|
1226
1294
|
segments: [{ text: "I NEVER", color: COLORS.danger, bold: true }]
|
|
1227
1295
|
}
|
|
1228
1296
|
),
|
|
1229
|
-
neverItems.map((item) => /* @__PURE__ */
|
|
1230
|
-
/* @__PURE__ */
|
|
1231
|
-
/* @__PURE__ */
|
|
1297
|
+
neverItems.map((item) => /* @__PURE__ */ jsxs9(Fragment2, { children: [
|
|
1298
|
+
/* @__PURE__ */ jsx8(NeverLine, { width: dividerWidth }),
|
|
1299
|
+
/* @__PURE__ */ jsx8(
|
|
1232
1300
|
NeverLine,
|
|
1233
1301
|
{
|
|
1234
1302
|
width: dividerWidth,
|
|
@@ -1240,24 +1308,24 @@ function LearnMore() {
|
|
|
1240
1308
|
}
|
|
1241
1309
|
)
|
|
1242
1310
|
] }, item)),
|
|
1243
|
-
/* @__PURE__ */
|
|
1244
|
-
/* @__PURE__ */
|
|
1311
|
+
/* @__PURE__ */ jsx8(NeverLine, { width: dividerWidth }),
|
|
1312
|
+
/* @__PURE__ */ jsx8(Text10, { color: COLORS.danger, children: `\u2570${"\u2500".repeat(Math.max(0, dividerWidth - 2))}\u256F` })
|
|
1245
1313
|
] }),
|
|
1246
|
-
/* @__PURE__ */
|
|
1247
|
-
/* @__PURE__ */
|
|
1248
|
-
/* @__PURE__ */
|
|
1314
|
+
/* @__PURE__ */ jsx8(Box10, { marginTop: 1, flexDirection: "column", children: policyLinks.map((link) => /* @__PURE__ */ jsxs9(Box10, { flexDirection: "row", gap: 1, children: [
|
|
1315
|
+
/* @__PURE__ */ jsx8(Text10, { color: COLORS.strong, bold: true, children: `${link.label}:` }),
|
|
1316
|
+
/* @__PURE__ */ jsx8(Text10, { color: COLORS.accent, children: link.url })
|
|
1249
1317
|
] }, link.label)) }),
|
|
1250
|
-
/* @__PURE__ */
|
|
1251
|
-
/* @__PURE__ */
|
|
1252
|
-
/* @__PURE__ */
|
|
1253
|
-
/* @__PURE__ */
|
|
1254
|
-
/* @__PURE__ */
|
|
1318
|
+
/* @__PURE__ */ jsxs9(Box10, { marginTop: 1, flexDirection: "row", gap: 3, children: [
|
|
1319
|
+
/* @__PURE__ */ jsxs9(Box10, { flexDirection: "row", gap: 1, children: [
|
|
1320
|
+
/* @__PURE__ */ jsx8(Text10, { color: COLORS.muted, children: "[" }),
|
|
1321
|
+
/* @__PURE__ */ jsx8(Text10, { color: COLORS.primary, children: "esc" }),
|
|
1322
|
+
/* @__PURE__ */ jsx8(Text10, { color: COLORS.muted, children: "] back" })
|
|
1255
1323
|
] }),
|
|
1256
|
-
/* @__PURE__ */
|
|
1257
|
-
/* @__PURE__ */
|
|
1258
|
-
/* @__PURE__ */
|
|
1259
|
-
/* @__PURE__ */
|
|
1260
|
-
/* @__PURE__ */
|
|
1324
|
+
/* @__PURE__ */ jsxs9(Box10, { flexDirection: "row", gap: 1, children: [
|
|
1325
|
+
/* @__PURE__ */ jsx8(Text10, { color: COLORS.muted, children: "[" }),
|
|
1326
|
+
/* @__PURE__ */ jsx8(Text10, { color: COLORS.primary, children: "enter" }),
|
|
1327
|
+
/* @__PURE__ */ jsx8(Text10, { color: COLORS.muted, children: "]" }),
|
|
1328
|
+
/* @__PURE__ */ jsx8(Text10, { color: COLORS.success, bold: true, children: "start wizard" })
|
|
1261
1329
|
] })
|
|
1262
1330
|
] })
|
|
1263
1331
|
]
|
|
@@ -1266,10 +1334,10 @@ function LearnMore() {
|
|
|
1266
1334
|
}
|
|
1267
1335
|
|
|
1268
1336
|
// src/ui/Sidebar.tsx
|
|
1269
|
-
import { Box as
|
|
1337
|
+
import { Box as Box13, Text as Text13 } from "ink";
|
|
1270
1338
|
|
|
1271
1339
|
// src/ui/Steps.tsx
|
|
1272
|
-
import { Box as
|
|
1340
|
+
import { Box as Box11, Text as Text11 } from "ink";
|
|
1273
1341
|
import Spinner from "ink-spinner";
|
|
1274
1342
|
|
|
1275
1343
|
// src/core/persistence.ts
|
|
@@ -1298,12 +1366,12 @@ async function clearWorkflowState(workflowId) {
|
|
|
1298
1366
|
}
|
|
1299
1367
|
|
|
1300
1368
|
// src/ui/Steps.tsx
|
|
1301
|
-
import { jsx as
|
|
1369
|
+
import { jsx as jsx9, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1302
1370
|
function Steps() {
|
|
1303
1371
|
const { steps } = useWizard();
|
|
1304
1372
|
const visibleSteps = steps.filter(isStepVisible);
|
|
1305
|
-
return /* @__PURE__ */
|
|
1306
|
-
s.status === "running" ? /* @__PURE__ */
|
|
1373
|
+
return /* @__PURE__ */ jsx9(Box11, { flexDirection: "column", gap: 1, children: visibleSteps.map((s) => /* @__PURE__ */ jsx9(Box11, { flexDirection: "column", children: /* @__PURE__ */ jsxs10(Text11, { color: COLORS.status[s.status], children: [
|
|
1374
|
+
s.status === "running" ? /* @__PURE__ */ jsx9(Spinner, { type: "dots" }) : MARKER[s.status],
|
|
1307
1375
|
" ",
|
|
1308
1376
|
s.title
|
|
1309
1377
|
] }) }, s.id)) });
|
|
@@ -1312,27 +1380,27 @@ function CurrentStep() {
|
|
|
1312
1380
|
const { steps } = useWizard();
|
|
1313
1381
|
const currentStep = steps.filter(isStepVisible).find((s) => s.status === "running");
|
|
1314
1382
|
if (!currentStep) return null;
|
|
1315
|
-
return /* @__PURE__ */
|
|
1316
|
-
/* @__PURE__ */
|
|
1383
|
+
return /* @__PURE__ */ jsxs10(Text11, { color: COLORS.status.running, children: [
|
|
1384
|
+
/* @__PURE__ */ jsx9(Spinner, { type: "dots" }),
|
|
1317
1385
|
" ",
|
|
1318
1386
|
` ${currentStep.title}`
|
|
1319
1387
|
] });
|
|
1320
1388
|
}
|
|
1321
1389
|
|
|
1322
1390
|
// src/ui/Progress.tsx
|
|
1323
|
-
import { Box as
|
|
1324
|
-
import { jsx as
|
|
1391
|
+
import { Box as Box12, Text as Text12 } from "ink";
|
|
1392
|
+
import { jsx as jsx10, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1325
1393
|
function Progress() {
|
|
1326
1394
|
const { steps, currentStepIndex } = useWizard();
|
|
1327
1395
|
const visibleSteps = steps.filter(isStepVisible);
|
|
1328
1396
|
if (visibleSteps.length === 0) return null;
|
|
1329
1397
|
const visibleCountThroughCurrent = steps.slice(0, currentStepIndex + 1).filter(isStepVisible).length;
|
|
1330
1398
|
const activeStepNumber = Math.max(1, visibleCountThroughCurrent);
|
|
1331
|
-
return /* @__PURE__ */
|
|
1332
|
-
/* @__PURE__ */
|
|
1333
|
-
/* @__PURE__ */
|
|
1334
|
-
/* @__PURE__ */
|
|
1335
|
-
/* @__PURE__ */
|
|
1399
|
+
return /* @__PURE__ */ jsxs11(Box12, { flexDirection: "row", gap: 1, children: [
|
|
1400
|
+
/* @__PURE__ */ jsx10(Text12, { color: COLORS.muted, children: "STEP" }),
|
|
1401
|
+
/* @__PURE__ */ jsx10(Text12, { bold: true, children: activeStepNumber }),
|
|
1402
|
+
/* @__PURE__ */ jsx10(Text12, { bold: true, children: "/" }),
|
|
1403
|
+
/* @__PURE__ */ jsx10(Text12, { bold: true, children: visibleSteps.length })
|
|
1336
1404
|
] });
|
|
1337
1405
|
}
|
|
1338
1406
|
|
|
@@ -1343,10 +1411,10 @@ var sidebarCommands = [
|
|
|
1343
1411
|
];
|
|
1344
1412
|
|
|
1345
1413
|
// src/ui/Sidebar.tsx
|
|
1346
|
-
import { jsx as
|
|
1414
|
+
import { jsx as jsx11, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1347
1415
|
function Sidebar() {
|
|
1348
|
-
return /* @__PURE__ */
|
|
1349
|
-
|
|
1416
|
+
return /* @__PURE__ */ jsxs12(
|
|
1417
|
+
Box13,
|
|
1350
1418
|
{
|
|
1351
1419
|
backgroundColor: "#14171E",
|
|
1352
1420
|
width: 30,
|
|
@@ -1355,16 +1423,16 @@ function Sidebar() {
|
|
|
1355
1423
|
flexDirection: "column",
|
|
1356
1424
|
justifyContent: "space-between",
|
|
1357
1425
|
children: [
|
|
1358
|
-
/* @__PURE__ */
|
|
1359
|
-
/* @__PURE__ */
|
|
1360
|
-
/* @__PURE__ */
|
|
1426
|
+
/* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", gap: 1, children: [
|
|
1427
|
+
/* @__PURE__ */ jsx11(Text13, { color: COLORS.muted, children: "PROGRESS" }),
|
|
1428
|
+
/* @__PURE__ */ jsx11(Steps, {})
|
|
1361
1429
|
] }),
|
|
1362
|
-
/* @__PURE__ */
|
|
1363
|
-
/* @__PURE__ */
|
|
1364
|
-
/* @__PURE__ */
|
|
1365
|
-
return /* @__PURE__ */
|
|
1366
|
-
/* @__PURE__ */
|
|
1367
|
-
/* @__PURE__ */
|
|
1430
|
+
/* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", gap: 1, children: [
|
|
1431
|
+
/* @__PURE__ */ jsx11(Progress, {}),
|
|
1432
|
+
/* @__PURE__ */ jsx11(Box13, { flexDirection: "column", children: sidebarCommands.map((c) => {
|
|
1433
|
+
return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "row", gap: 1, children: [
|
|
1434
|
+
/* @__PURE__ */ jsx11(Text13, { color: COLORS.primary, children: `[${c.keyHint}]` }),
|
|
1435
|
+
/* @__PURE__ */ jsx11(Text13, { color: COLORS.muted, children: c.description })
|
|
1368
1436
|
] });
|
|
1369
1437
|
}) })
|
|
1370
1438
|
] })
|
|
@@ -1374,12 +1442,12 @@ function Sidebar() {
|
|
|
1374
1442
|
}
|
|
1375
1443
|
|
|
1376
1444
|
// src/ui/Ribbon.tsx
|
|
1377
|
-
import { Box as
|
|
1378
|
-
import { jsx as
|
|
1445
|
+
import { Box as Box14, Text as Text14 } from "ink";
|
|
1446
|
+
import { jsx as jsx12, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1379
1447
|
function Ribbon() {
|
|
1380
1448
|
const firstCommand = sidebarCommands[0];
|
|
1381
|
-
return /* @__PURE__ */
|
|
1382
|
-
|
|
1449
|
+
return /* @__PURE__ */ jsxs13(
|
|
1450
|
+
Box14,
|
|
1383
1451
|
{
|
|
1384
1452
|
backgroundColor: "#14171E",
|
|
1385
1453
|
flexDirection: "row",
|
|
@@ -1387,11 +1455,11 @@ function Ribbon() {
|
|
|
1387
1455
|
paddingX: 2,
|
|
1388
1456
|
paddingY: 1,
|
|
1389
1457
|
children: [
|
|
1390
|
-
/* @__PURE__ */
|
|
1391
|
-
/* @__PURE__ */
|
|
1392
|
-
/* @__PURE__ */
|
|
1393
|
-
/* @__PURE__ */
|
|
1394
|
-
/* @__PURE__ */
|
|
1458
|
+
/* @__PURE__ */ jsx12(Progress, {}),
|
|
1459
|
+
/* @__PURE__ */ jsx12(CurrentStep, {}),
|
|
1460
|
+
/* @__PURE__ */ jsxs13(Box14, { flexDirection: "row", gap: 1, children: [
|
|
1461
|
+
/* @__PURE__ */ jsx12(Text14, { color: COLORS.primary, children: `[${firstCommand.keyHint}]` }),
|
|
1462
|
+
/* @__PURE__ */ jsx12(Text14, { color: COLORS.muted, children: firstCommand.description })
|
|
1395
1463
|
] })
|
|
1396
1464
|
]
|
|
1397
1465
|
}
|
|
@@ -1402,8 +1470,8 @@ function Ribbon() {
|
|
|
1402
1470
|
import { useState as useState6 } from "react";
|
|
1403
1471
|
|
|
1404
1472
|
// src/ui/Logs.tsx
|
|
1405
|
-
import { Box as
|
|
1406
|
-
import { jsx as
|
|
1473
|
+
import { Box as Box15, Text as Text15, useInput as useInput6 } from "ink";
|
|
1474
|
+
import { jsx as jsx13, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1407
1475
|
var KIND_COLOR = {
|
|
1408
1476
|
tool: COLORS.primary,
|
|
1409
1477
|
prompt: COLORS.badge
|
|
@@ -1434,14 +1502,14 @@ function formatTimestamp(ms) {
|
|
|
1434
1502
|
function Logs() {
|
|
1435
1503
|
const logs = useWizard((s) => s.logs);
|
|
1436
1504
|
const scroll = useScrollWindow({ itemCount: logs.length, followBottom: true });
|
|
1437
|
-
|
|
1505
|
+
useInput6((_input, key) => {
|
|
1438
1506
|
if (key.upArrow) scroll.scrollBy(-1);
|
|
1439
1507
|
else if (key.downArrow) scroll.scrollBy(1);
|
|
1440
1508
|
});
|
|
1441
1509
|
const visible = logs.slice(scroll.offset, scroll.offset + scroll.capacity);
|
|
1442
|
-
return /* @__PURE__ */
|
|
1443
|
-
logs.length === 0 && /* @__PURE__ */
|
|
1444
|
-
/* @__PURE__ */
|
|
1510
|
+
return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "column", paddingX: 4, paddingY: 2, flexGrow: 1, children: [
|
|
1511
|
+
logs.length === 0 && /* @__PURE__ */ jsx13(Text15, { color: COLORS.dim, children: "No logs yet." }),
|
|
1512
|
+
/* @__PURE__ */ jsx13(ScrollView, { scroll, children: visible.map((entry) => {
|
|
1445
1513
|
const timestamp = `[${formatTimestamp(entry.startedAt)}]`;
|
|
1446
1514
|
const durationText = entry.kind === "tool" && entry.durationMs !== void 0 ? `${entry.durationMs}ms` : "";
|
|
1447
1515
|
const rawPreview = rawInputText(entry.input);
|
|
@@ -1451,14 +1519,14 @@ function Logs() {
|
|
|
1451
1519
|
const name = truncate2(entry.name, budget);
|
|
1452
1520
|
budget -= name.length;
|
|
1453
1521
|
const preview = rawPreview ? truncate2(rawPreview, budget) : "";
|
|
1454
|
-
return /* @__PURE__ */
|
|
1455
|
-
/* @__PURE__ */
|
|
1456
|
-
/* @__PURE__ */
|
|
1457
|
-
preview && /* @__PURE__ */
|
|
1458
|
-
durationText && /* @__PURE__ */
|
|
1522
|
+
return /* @__PURE__ */ jsxs14(Box15, { flexDirection: "row", gap: ROW_GAP, children: [
|
|
1523
|
+
/* @__PURE__ */ jsx13(Text15, { color: COLORS.dim, children: timestamp }),
|
|
1524
|
+
/* @__PURE__ */ jsx13(Text15, { color: logNameColor(entry), wrap: "truncate", children: name }),
|
|
1525
|
+
preview && /* @__PURE__ */ jsx13(Text15, { color: COLORS.dim, wrap: "truncate", children: preview }),
|
|
1526
|
+
durationText && /* @__PURE__ */ jsx13(Text15, { color: COLORS.dim, children: durationText })
|
|
1459
1527
|
] }, entry.id);
|
|
1460
1528
|
}) }),
|
|
1461
|
-
/* @__PURE__ */
|
|
1529
|
+
/* @__PURE__ */ jsx13(Text15, { color: COLORS.dim, children: "\u2191/\u2193 scroll" })
|
|
1462
1530
|
] });
|
|
1463
1531
|
}
|
|
1464
1532
|
|
|
@@ -1650,7 +1718,7 @@ function track(event, payload) {
|
|
|
1650
1718
|
}
|
|
1651
1719
|
|
|
1652
1720
|
// src/ui/App.tsx
|
|
1653
|
-
import { jsx as
|
|
1721
|
+
import { jsx as jsx14, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1654
1722
|
function App() {
|
|
1655
1723
|
const { phase, error, homeScreen, currentStepIndex, steps, inputReq } = useWizard();
|
|
1656
1724
|
const { exit } = useApp();
|
|
@@ -1658,7 +1726,7 @@ function App() {
|
|
|
1658
1726
|
const [showLogs, setShowLogs] = useState6(false);
|
|
1659
1727
|
const finished = phase === "done" || phase === "error";
|
|
1660
1728
|
const currentStep = steps[currentStepIndex];
|
|
1661
|
-
|
|
1729
|
+
useInput7(
|
|
1662
1730
|
(_input, key) => {
|
|
1663
1731
|
if (key.return) {
|
|
1664
1732
|
exit();
|
|
@@ -1666,7 +1734,7 @@ function App() {
|
|
|
1666
1734
|
},
|
|
1667
1735
|
{ isActive: finished }
|
|
1668
1736
|
);
|
|
1669
|
-
|
|
1737
|
+
useInput7((_input, key) => {
|
|
1670
1738
|
if (phase === "idle" || phase === "authenticating") return;
|
|
1671
1739
|
if (key.tab) {
|
|
1672
1740
|
setShowLogs(!showLogs);
|
|
@@ -1677,8 +1745,8 @@ function App() {
|
|
|
1677
1745
|
});
|
|
1678
1746
|
}
|
|
1679
1747
|
});
|
|
1680
|
-
const escOwnedElsewhere = phase === "idle" || phase === "authenticating" || phase === "awaitingInput" && inputReq?.promptType === "enterToContinue";
|
|
1681
|
-
|
|
1748
|
+
const escOwnedElsewhere = phase === "idle" || phase === "authenticating" || phase === "awaitingInput" && (inputReq?.promptType === "enterToContinue" || inputReq?.promptType === "commandApproval");
|
|
1749
|
+
useInput7((_input, key) => {
|
|
1682
1750
|
if (escOwnedElsewhere) return;
|
|
1683
1751
|
if (key.escape) {
|
|
1684
1752
|
track("AI Wizard Interaction", {
|
|
@@ -1697,8 +1765,8 @@ function App() {
|
|
|
1697
1765
|
/* Clamped to exactly the viewport: a taller frame makes Ink clear and repaint
|
|
1698
1766
|
the whole screen, and the scrolling throws off its cursor arithmetic —
|
|
1699
1767
|
flicker and leftover rows. */
|
|
1700
|
-
/* @__PURE__ */
|
|
1701
|
-
|
|
1768
|
+
/* @__PURE__ */ jsxs15(
|
|
1769
|
+
Box16,
|
|
1702
1770
|
{
|
|
1703
1771
|
backgroundColor: COLORS.bg.main,
|
|
1704
1772
|
flexDirection: "row",
|
|
@@ -1706,16 +1774,16 @@ function App() {
|
|
|
1706
1774
|
height: scrollsPastViewport ? void 0 : rows,
|
|
1707
1775
|
overflow: scrollsPastViewport ? "visible" : "hidden",
|
|
1708
1776
|
children: [
|
|
1709
|
-
mainWindowVisible && /* @__PURE__ */
|
|
1710
|
-
|
|
1777
|
+
mainWindowVisible && /* @__PURE__ */ jsxs15(
|
|
1778
|
+
Box16,
|
|
1711
1779
|
{
|
|
1712
1780
|
flexDirection,
|
|
1713
1781
|
width: "100%",
|
|
1714
1782
|
maxHeight: rows,
|
|
1715
1783
|
justifyContent: "space-between",
|
|
1716
1784
|
children: [
|
|
1717
|
-
showLogs ? /* @__PURE__ */
|
|
1718
|
-
|
|
1785
|
+
showLogs ? /* @__PURE__ */ jsx14(Logs, {}) : /* @__PURE__ */ jsxs15(
|
|
1786
|
+
Box16,
|
|
1719
1787
|
{
|
|
1720
1788
|
flexDirection: "column",
|
|
1721
1789
|
paddingX: 4,
|
|
@@ -1723,26 +1791,26 @@ function App() {
|
|
|
1723
1791
|
width: showSidebar ? 70 : "100%",
|
|
1724
1792
|
flexGrow: 1,
|
|
1725
1793
|
children: [
|
|
1726
|
-
phase === "authenticating" && /* @__PURE__ */
|
|
1727
|
-
/* @__PURE__ */
|
|
1728
|
-
/* @__PURE__ */
|
|
1794
|
+
phase === "authenticating" && /* @__PURE__ */ jsxs15(Box16, { flexDirection: "column", marginBottom: 1, children: [
|
|
1795
|
+
/* @__PURE__ */ jsx14(Text16, { color: COLORS.strong, bold: true, children: "Signing in to Algolia" }),
|
|
1796
|
+
/* @__PURE__ */ jsx14(Text16, { color: COLORS.muted, children: "A browser window will open \u2014 complete sign-in there." })
|
|
1729
1797
|
] }),
|
|
1730
|
-
/* @__PURE__ */
|
|
1731
|
-
/* @__PURE__ */
|
|
1732
|
-
/* @__PURE__ */
|
|
1733
|
-
phase === "running" && showSidebar && /* @__PURE__ */
|
|
1734
|
-
phase === "error" && error && /* @__PURE__ */
|
|
1798
|
+
/* @__PURE__ */ jsx14(CliOutput, {}),
|
|
1799
|
+
/* @__PURE__ */ jsx14(Notices, {}),
|
|
1800
|
+
/* @__PURE__ */ jsx14(PromptInput, {}),
|
|
1801
|
+
phase === "running" && showSidebar && /* @__PURE__ */ jsx14(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx14(CurrentStep, {}) }),
|
|
1802
|
+
phase === "error" && error && /* @__PURE__ */ jsx14(Box16, { marginTop: 1, children: /* @__PURE__ */ jsxs15(Text16, { color: COLORS.status.error, children: [
|
|
1735
1803
|
"\u2716 ",
|
|
1736
1804
|
error
|
|
1737
1805
|
] }) })
|
|
1738
1806
|
]
|
|
1739
1807
|
}
|
|
1740
1808
|
),
|
|
1741
|
-
showSidebar ? /* @__PURE__ */
|
|
1809
|
+
showSidebar ? /* @__PURE__ */ jsx14(Sidebar, {}) : /* @__PURE__ */ jsx14(Ribbon, {})
|
|
1742
1810
|
]
|
|
1743
1811
|
}
|
|
1744
1812
|
),
|
|
1745
|
-
phase === "idle" && (homeScreen === "learnMore" ? /* @__PURE__ */
|
|
1813
|
+
phase === "idle" && (homeScreen === "learnMore" ? /* @__PURE__ */ jsx14(LearnMore, {}) : /* @__PURE__ */ jsx14(Welcome, {}))
|
|
1746
1814
|
]
|
|
1747
1815
|
}
|
|
1748
1816
|
)
|
|
@@ -1822,7 +1890,7 @@ async function ensureConsent() {
|
|
|
1822
1890
|
if (config.aiConsent) return;
|
|
1823
1891
|
const store = useWizard.getState();
|
|
1824
1892
|
const answer = await store.requestUserInput({
|
|
1825
|
-
prompt: "Wizard will make AI-authored changes to this repository.",
|
|
1893
|
+
prompt: "Wizard will make AI-authored changes to this repository, and will propose shell commands to set it up. You approve each command before it runs.",
|
|
1826
1894
|
promptType: "enterToContinue",
|
|
1827
1895
|
options: []
|
|
1828
1896
|
});
|
|
@@ -2811,92 +2879,192 @@ function searchFilesTool(ctx) {
|
|
|
2811
2879
|
});
|
|
2812
2880
|
}
|
|
2813
2881
|
|
|
2814
|
-
// src/lib/tools/
|
|
2882
|
+
// src/lib/tools/runShell.ts
|
|
2815
2883
|
import { tool as tool8 } from "ai";
|
|
2816
2884
|
import z15 from "zod";
|
|
2885
|
+
import { relative as relative2 } from "node:path";
|
|
2817
2886
|
|
|
2818
|
-
// src/lib/tools/utils/
|
|
2887
|
+
// src/lib/tools/utils/runShell.ts
|
|
2819
2888
|
import { spawn as spawn2 } from "node:child_process";
|
|
2820
|
-
|
|
2889
|
+
|
|
2890
|
+
// src/lib/tools/context.ts
|
|
2891
|
+
var DEFAULT_TOOL_LIMITS = {
|
|
2892
|
+
list: 10,
|
|
2893
|
+
search: 10,
|
|
2894
|
+
read: 20,
|
|
2895
|
+
match: 100,
|
|
2896
|
+
shell: 30
|
|
2897
|
+
};
|
|
2898
|
+
var DEFAULT_SHELL_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
2899
|
+
async function refuseByDefault() {
|
|
2900
|
+
return "reject";
|
|
2901
|
+
}
|
|
2902
|
+
function createShellContext(overrides = {}) {
|
|
2903
|
+
return {
|
|
2904
|
+
env: async () => ({}),
|
|
2905
|
+
timeoutMs: DEFAULT_SHELL_TIMEOUT_MS,
|
|
2906
|
+
executions: [],
|
|
2907
|
+
approve: refuseByDefault,
|
|
2908
|
+
...overrides
|
|
2909
|
+
};
|
|
2910
|
+
}
|
|
2911
|
+
function createToolContext(limits = DEFAULT_TOOL_LIMITS, cwd = process.cwd(), shell2 = createShellContext()) {
|
|
2912
|
+
return {
|
|
2913
|
+
root: cwd,
|
|
2914
|
+
cwd,
|
|
2915
|
+
limits: { ...limits },
|
|
2916
|
+
counts: { list: 0, search: 0, read: 0, shell: 0 },
|
|
2917
|
+
shell: shell2
|
|
2918
|
+
};
|
|
2919
|
+
}
|
|
2920
|
+
|
|
2921
|
+
// src/lib/tools/utils/runShell.ts
|
|
2922
|
+
var SIGKILL_DELAY_MS = 5e3;
|
|
2923
|
+
var HEAD_CHARS = 4e3;
|
|
2924
|
+
var TAIL_CHARS = 8e3;
|
|
2925
|
+
function truncateOutput(output) {
|
|
2926
|
+
if (output.length <= HEAD_CHARS + TAIL_CHARS) return output;
|
|
2927
|
+
const omitted = output.length - HEAD_CHARS - TAIL_CHARS;
|
|
2928
|
+
return [
|
|
2929
|
+
output.slice(0, HEAD_CHARS),
|
|
2930
|
+
`
|
|
2931
|
+
\u2026 [${omitted} characters omitted] \u2026
|
|
2932
|
+
`,
|
|
2933
|
+
output.slice(-TAIL_CHARS)
|
|
2934
|
+
].join("");
|
|
2935
|
+
}
|
|
2936
|
+
function runShell(command, opts) {
|
|
2937
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_SHELL_TIMEOUT_MS;
|
|
2938
|
+
const startedAt = Date.now();
|
|
2821
2939
|
return new Promise((resolve4) => {
|
|
2822
2940
|
let output = "";
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2941
|
+
let timedOut = false;
|
|
2942
|
+
let settled = false;
|
|
2943
|
+
const child = spawn2(command, {
|
|
2944
|
+
shell: true,
|
|
2945
|
+
cwd: opts.cwd,
|
|
2946
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
2947
|
+
env: { ...process.env, ...opts.env }
|
|
2826
2948
|
});
|
|
2949
|
+
const finish = (exitCode) => {
|
|
2950
|
+
if (settled) return;
|
|
2951
|
+
settled = true;
|
|
2952
|
+
clearTimeout(timer);
|
|
2953
|
+
clearTimeout(killTimer);
|
|
2954
|
+
resolve4({
|
|
2955
|
+
exitCode,
|
|
2956
|
+
output: truncateOutput(output.trim()),
|
|
2957
|
+
timedOut,
|
|
2958
|
+
durationMs: Date.now() - startedAt
|
|
2959
|
+
});
|
|
2960
|
+
};
|
|
2961
|
+
let killTimer;
|
|
2962
|
+
const timer = setTimeout(() => {
|
|
2963
|
+
timedOut = true;
|
|
2964
|
+
output += `
|
|
2965
|
+
[timed out after ${timeoutMs}ms]`;
|
|
2966
|
+
child.kill("SIGTERM");
|
|
2967
|
+
killTimer = setTimeout(() => child.kill("SIGKILL"), SIGKILL_DELAY_MS);
|
|
2968
|
+
}, timeoutMs);
|
|
2827
2969
|
child.stdout?.on("data", (d) => output += d);
|
|
2828
2970
|
child.stderr?.on("data", (d) => output += d);
|
|
2829
|
-
child.on(
|
|
2830
|
-
|
|
2831
|
-
(
|
|
2832
|
-
);
|
|
2833
|
-
child.on("close", (code) =>
|
|
2971
|
+
child.on("error", (err) => {
|
|
2972
|
+
output += `Failed to run ${command}: ${err.message}`;
|
|
2973
|
+
finish(1);
|
|
2974
|
+
});
|
|
2975
|
+
child.on("close", (code) => finish(code ?? 1));
|
|
2834
2976
|
});
|
|
2835
2977
|
}
|
|
2836
2978
|
|
|
2837
|
-
// src/lib/tools/
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
return pkg.packageManager?.split("@")[0] ?? "npm";
|
|
2853
|
-
}
|
|
2854
|
-
function packageManagerFromLockfile(cwd) {
|
|
2855
|
-
return LOCKFILES.find(([file]) => existsSync(join9(cwd, file)))?.[1];
|
|
2979
|
+
// src/lib/tools/runShell.ts
|
|
2980
|
+
function storeApproval(root) {
|
|
2981
|
+
return async (req) => {
|
|
2982
|
+
const rel = relative2(root, req.cwd);
|
|
2983
|
+
const answer = await useWizard.getState().requestUserInput({
|
|
2984
|
+
prompt: "Run this command?",
|
|
2985
|
+
promptType: "commandApproval",
|
|
2986
|
+
options: [],
|
|
2987
|
+
command: {
|
|
2988
|
+
...req,
|
|
2989
|
+
cwd: rel === "" || rel.startsWith("..") ? req.cwd : rel
|
|
2990
|
+
}
|
|
2991
|
+
});
|
|
2992
|
+
return answer === "approve" ? "approve" : "reject";
|
|
2993
|
+
};
|
|
2856
2994
|
}
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
}
|
|
2862
|
-
|
|
2863
|
-
return packageManagerFromLockfile(cwd) ?? "npm";
|
|
2995
|
+
var shellChain = Promise.resolve();
|
|
2996
|
+
function serialize(work) {
|
|
2997
|
+
const result = shellChain.then(work);
|
|
2998
|
+
shellChain = result.catch(() => {
|
|
2999
|
+
});
|
|
3000
|
+
return result;
|
|
2864
3001
|
}
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
pkg = await readPackageJson();
|
|
2872
|
-
} catch (err) {
|
|
2873
|
-
const limitation = `Could not read package.json to detect verification conventions: ${err.message}`;
|
|
2874
|
-
return { ok: false, checks: [], limitation };
|
|
3002
|
+
async function approveAndRun(ctx, command, cwd, explanation) {
|
|
3003
|
+
const decision = await ctx.shell.approve({ command, cwd, explanation });
|
|
3004
|
+
if (decision === "reject") {
|
|
3005
|
+
ctx.shell.executions.push({ command, cwd, approved: false });
|
|
3006
|
+
logger.info({ command }, "runShell: user rejected the command");
|
|
3007
|
+
return "The user rejected this command. Do not retry it. Propose a different command, or report the limitation via reportStatus.";
|
|
2875
3008
|
}
|
|
2876
|
-
|
|
2877
|
-
const
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
3009
|
+
useWizard.getState().pushNotice({ messages: [`Running: ${command}`] });
|
|
3010
|
+
const env = await ctx.shell.env().catch((err) => {
|
|
3011
|
+
logger.warn({ err, command }, "runShell: could not resolve command env");
|
|
3012
|
+
return {};
|
|
3013
|
+
});
|
|
3014
|
+
const run2 = await (ctx.shell.run ?? runShell)(command, {
|
|
3015
|
+
cwd,
|
|
3016
|
+
env,
|
|
3017
|
+
timeoutMs: ctx.shell.timeoutMs
|
|
3018
|
+
});
|
|
3019
|
+
logger.info(
|
|
3020
|
+
{
|
|
3021
|
+
command,
|
|
3022
|
+
exitCode: run2.exitCode,
|
|
3023
|
+
timedOut: run2.timedOut,
|
|
3024
|
+
durationMs: run2.durationMs
|
|
3025
|
+
},
|
|
3026
|
+
"runShell finished"
|
|
3027
|
+
);
|
|
3028
|
+
await markInteraction();
|
|
3029
|
+
ctx.shell.executions.push({
|
|
3030
|
+
command,
|
|
3031
|
+
cwd,
|
|
3032
|
+
approved: true,
|
|
3033
|
+
exitCode: run2.exitCode,
|
|
3034
|
+
output: run2.output,
|
|
3035
|
+
timedOut: run2.timedOut,
|
|
3036
|
+
durationMs: run2.durationMs
|
|
3037
|
+
});
|
|
3038
|
+
return {
|
|
3039
|
+
exitCode: run2.exitCode,
|
|
3040
|
+
timedOut: run2.timedOut,
|
|
3041
|
+
output: run2.output
|
|
3042
|
+
};
|
|
2890
3043
|
}
|
|
2891
|
-
|
|
2892
|
-
// src/lib/tools/verifyImplementation.ts
|
|
2893
|
-
function verifyImplementationTool() {
|
|
3044
|
+
function runShellTool(ctx) {
|
|
2894
3045
|
return tool8({
|
|
2895
|
-
description: "Run the
|
|
2896
|
-
inputSchema: z15.object(
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
3046
|
+
description: "Run a shell command in the project. Use this for anything the project needs done in its own ecosystem: installing dependencies, running a script you wrote, running the project's lint/typecheck/test commands. The user sees and approves every command before it runs, so write a clear `explanation`. If the user rejects a command, do not retry it \u2014 propose a different approach.",
|
|
3047
|
+
inputSchema: z15.object({
|
|
3048
|
+
command: z15.string().describe(
|
|
3049
|
+
"The command to run, exactly as it would be typed in a shell. Pipes, && and redirects are allowed."
|
|
3050
|
+
),
|
|
3051
|
+
cwd: z15.string().optional().describe(
|
|
3052
|
+
"Directory to run in, relative to the project root. Defaults to the project root."
|
|
3053
|
+
),
|
|
3054
|
+
explanation: z15.string().describe(
|
|
3055
|
+
"One short line telling the user what this command does and why, including any side effect (e.g. writes records to Algolia). This is what they approve against."
|
|
3056
|
+
)
|
|
3057
|
+
}),
|
|
3058
|
+
execute: async ({ command, cwd, explanation }) => {
|
|
3059
|
+
if (++ctx.counts.shell > ctx.limits.shell) {
|
|
3060
|
+
return `Refused: command limit (${ctx.limits.shell}) reached. Stop running commands and report what you have.`;
|
|
3061
|
+
}
|
|
3062
|
+
const resolved2 = resolveInRoot(ctx, cwd ?? ".");
|
|
3063
|
+
if (!resolved2.ok) return resolved2.error;
|
|
3064
|
+
logger.info({ command, cwd: resolved2.target }, "called runShell tool");
|
|
3065
|
+
return serialize(
|
|
3066
|
+
() => approveAndRun(ctx, command, resolved2.target, explanation)
|
|
3067
|
+
);
|
|
2900
3068
|
}
|
|
2901
3069
|
});
|
|
2902
3070
|
}
|
|
@@ -3015,22 +3183,6 @@ function notifyUserTool() {
|
|
|
3015
3183
|
});
|
|
3016
3184
|
}
|
|
3017
3185
|
|
|
3018
|
-
// src/lib/tools/context.ts
|
|
3019
|
-
var DEFAULT_TOOL_LIMITS = {
|
|
3020
|
-
list: 10,
|
|
3021
|
-
search: 10,
|
|
3022
|
-
read: 20,
|
|
3023
|
-
match: 100
|
|
3024
|
-
};
|
|
3025
|
-
function createToolContext(limits = DEFAULT_TOOL_LIMITS, cwd = process.cwd()) {
|
|
3026
|
-
return {
|
|
3027
|
-
root: cwd,
|
|
3028
|
-
cwd,
|
|
3029
|
-
limits,
|
|
3030
|
-
counts: { list: 0, search: 0, read: 0 }
|
|
3031
|
-
};
|
|
3032
|
-
}
|
|
3033
|
-
|
|
3034
3186
|
// src/lib/tools/index.ts
|
|
3035
3187
|
function withLogging(name, def) {
|
|
3036
3188
|
const execute = def.execute;
|
|
@@ -3062,10 +3214,7 @@ function createTools(ctx, { output, tools }) {
|
|
|
3062
3214
|
writeCredentialsTool(ctx)
|
|
3063
3215
|
),
|
|
3064
3216
|
searchFiles: withLogging("searchFiles", searchFilesTool(ctx)),
|
|
3065
|
-
|
|
3066
|
-
"verifyImplementation",
|
|
3067
|
-
verifyImplementationTool()
|
|
3068
|
-
),
|
|
3217
|
+
runShell: withLogging("runShell", runShellTool(ctx)),
|
|
3069
3218
|
generateRecord: withLogging("generateRecord", generateRecordTool(ctx)),
|
|
3070
3219
|
notifyUser: withLogging("notifyUser", notifyUserTool())
|
|
3071
3220
|
};
|
|
@@ -3100,7 +3249,7 @@ async function runAgent(req) {
|
|
|
3100
3249
|
baseURL: PROXY_BASE_URL,
|
|
3101
3250
|
fetch: proxyFetch
|
|
3102
3251
|
});
|
|
3103
|
-
const toolContext = createToolContext();
|
|
3252
|
+
const toolContext = req.toolContext ?? createToolContext();
|
|
3104
3253
|
const readTools = ["readFile", "searchFiles", "listFiles"];
|
|
3105
3254
|
const hasReadTools = !req.tools || req.tools.some((t) => readTools.includes(t));
|
|
3106
3255
|
const instructions = [
|
|
@@ -3165,7 +3314,11 @@ async function runAgent(req) {
|
|
|
3165
3314
|
"runAgent finished"
|
|
3166
3315
|
);
|
|
3167
3316
|
logger.info(
|
|
3168
|
-
{
|
|
3317
|
+
{
|
|
3318
|
+
counts: toolContext.counts,
|
|
3319
|
+
limits: toolContext.limits,
|
|
3320
|
+
commandsRun: toolContext.shell.executions.length
|
|
3321
|
+
},
|
|
3169
3322
|
"tool usage"
|
|
3170
3323
|
);
|
|
3171
3324
|
const toolResults = await stream.toolResults;
|
|
@@ -3290,7 +3443,7 @@ async function runAnalysis(mode, extraInstructions = []) {
|
|
|
3290
3443
|
// package.json
|
|
3291
3444
|
var package_default = {
|
|
3292
3445
|
name: "@algolia/wizard",
|
|
3293
|
-
version: "0.
|
|
3446
|
+
version: "0.13.0",
|
|
3294
3447
|
description: "Magically implement Algolia functionality in your codebase",
|
|
3295
3448
|
type: "module",
|
|
3296
3449
|
engines: {
|
|
@@ -3693,16 +3846,9 @@ ${formatCompletedSteps(ctx.completedSteps)}`,
|
|
|
3693
3846
|
import z27 from "zod";
|
|
3694
3847
|
|
|
3695
3848
|
// src/lib/worktree.ts
|
|
3696
|
-
import { execFile
|
|
3697
|
-
import { copyFile, mkdir as mkdir6, readdir as readdir3, readFile as
|
|
3698
|
-
import {
|
|
3699
|
-
basename as basename2,
|
|
3700
|
-
dirname as dirname7,
|
|
3701
|
-
isAbsolute as isAbsolute2,
|
|
3702
|
-
join as join10,
|
|
3703
|
-
relative as relative2,
|
|
3704
|
-
resolve as resolve3
|
|
3705
|
-
} from "node:path";
|
|
3849
|
+
import { execFile } from "node:child_process";
|
|
3850
|
+
import { copyFile, mkdir as mkdir6, readdir as readdir3, readFile as readFile7, stat as stat2, writeFile as writeFile6 } from "node:fs/promises";
|
|
3851
|
+
import { basename as basename2, dirname as dirname7, isAbsolute as isAbsolute2, join as join9, resolve as resolve3 } from "node:path";
|
|
3706
3852
|
var MAX_BUFFER = 32 * 1024 * 1024;
|
|
3707
3853
|
var MAX_WIZARD_WORKTREES = 3;
|
|
3708
3854
|
var WIZARD_BRANCH_PREFIX = "wizard/implement-";
|
|
@@ -3733,7 +3879,7 @@ async function isWorkingTreeDirty(repoRoot) {
|
|
|
3733
3879
|
return out.trim().length > 0;
|
|
3734
3880
|
}
|
|
3735
3881
|
async function pruneOldWorktrees(repoRoot) {
|
|
3736
|
-
const dir =
|
|
3882
|
+
const dir = join9(stateDir(repoRoot), "worktrees");
|
|
3737
3883
|
const stale = (await readdir3(dir).catch(() => [])).filter((name) => /^wizard-implement-\d+$/.test(name)).sort().reverse().slice(MAX_WIZARD_WORKTREES - 1);
|
|
3738
3884
|
for (const slug of stale) {
|
|
3739
3885
|
const branch = slug.replace("wizard-implement-", WIZARD_BRANCH_PREFIX);
|
|
@@ -3744,7 +3890,7 @@ async function pruneOldWorktrees(repoRoot) {
|
|
|
3744
3890
|
"worktree",
|
|
3745
3891
|
"remove",
|
|
3746
3892
|
"--force",
|
|
3747
|
-
|
|
3893
|
+
join9(dir, slug)
|
|
3748
3894
|
]);
|
|
3749
3895
|
await git(["-C", repoRoot, "branch", "-D", branch]);
|
|
3750
3896
|
} catch (err) {
|
|
@@ -3758,113 +3904,13 @@ async function pruneOldWorktrees(repoRoot) {
|
|
|
3758
3904
|
async function createWorktree(repoRoot) {
|
|
3759
3905
|
const branch = `${WIZARD_BRANCH_PREFIX}${Date.now()}`;
|
|
3760
3906
|
const dirSlug = branch.replace(/\//g, "-");
|
|
3761
|
-
const path =
|
|
3907
|
+
const path = join9(stateDir(repoRoot), "worktrees", dirSlug);
|
|
3762
3908
|
await git(["-C", repoRoot, "worktree", "prune"]);
|
|
3763
3909
|
await pruneOldWorktrees(repoRoot);
|
|
3764
3910
|
await mkdir6(dirname7(path), { recursive: true });
|
|
3765
3911
|
await git(["-C", repoRoot, "worktree", "add", "-b", branch, path, "HEAD"]);
|
|
3766
3912
|
return { path, branch };
|
|
3767
3913
|
}
|
|
3768
|
-
async function installWorktreeDeps(worktreePath) {
|
|
3769
|
-
try {
|
|
3770
|
-
await readPackageJson(worktreePath);
|
|
3771
|
-
} catch {
|
|
3772
|
-
return { ok: true, output: "no package.json; skipped install" };
|
|
3773
|
-
}
|
|
3774
|
-
const pm = await detectPackageManager(worktreePath);
|
|
3775
|
-
return new Promise((resolve4) => {
|
|
3776
|
-
let output = "";
|
|
3777
|
-
const child = spawn3(pm, ["install"], {
|
|
3778
|
-
cwd: worktreePath,
|
|
3779
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
3780
|
-
});
|
|
3781
|
-
child.stdout?.on("data", (d) => output += d);
|
|
3782
|
-
child.stderr?.on("data", (d) => output += d);
|
|
3783
|
-
child.on(
|
|
3784
|
-
"error",
|
|
3785
|
-
(err) => resolve4({
|
|
3786
|
-
ok: false,
|
|
3787
|
-
output: `Failed to run ${pm} install: ${err.message}`
|
|
3788
|
-
})
|
|
3789
|
-
);
|
|
3790
|
-
child.on(
|
|
3791
|
-
"close",
|
|
3792
|
-
(code) => resolve4({ ok: code === 0, output: output.trim() })
|
|
3793
|
-
);
|
|
3794
|
-
});
|
|
3795
|
-
}
|
|
3796
|
-
var INGEST_RUNTIMES = ["node", "python", "python3", "bun"];
|
|
3797
|
-
function validateIngestEntrypoint(worktreePath, entrypoint) {
|
|
3798
|
-
if (!entrypoint || entrypoint.startsWith("-")) {
|
|
3799
|
-
return {
|
|
3800
|
-
ok: false,
|
|
3801
|
-
reason: `entrypoint "${entrypoint}" is not a plain file path`
|
|
3802
|
-
};
|
|
3803
|
-
}
|
|
3804
|
-
const target = resolve3(worktreePath, entrypoint);
|
|
3805
|
-
const rel = relative2(worktreePath, target);
|
|
3806
|
-
if (rel.startsWith("..") || isAbsolute2(rel)) {
|
|
3807
|
-
return {
|
|
3808
|
-
ok: false,
|
|
3809
|
-
reason: `entrypoint "${entrypoint}" resolves outside the worktree`
|
|
3810
|
-
};
|
|
3811
|
-
}
|
|
3812
|
-
return { ok: true, target };
|
|
3813
|
-
}
|
|
3814
|
-
async function runIngestScript(worktreePath, runtime, entrypoint, env = {}) {
|
|
3815
|
-
if (!INGEST_RUNTIMES.includes(runtime)) {
|
|
3816
|
-
return {
|
|
3817
|
-
ran: false,
|
|
3818
|
-
ok: false,
|
|
3819
|
-
output: "",
|
|
3820
|
-
reason: `runtime "${runtime}" is not an allowed interpreter (${INGEST_RUNTIMES.join(", ")})`
|
|
3821
|
-
};
|
|
3822
|
-
}
|
|
3823
|
-
const validated = validateIngestEntrypoint(worktreePath, entrypoint);
|
|
3824
|
-
if (!validated.ok) {
|
|
3825
|
-
return { ran: false, ok: false, output: "", reason: validated.reason };
|
|
3826
|
-
}
|
|
3827
|
-
try {
|
|
3828
|
-
if (!(await stat2(validated.target)).isFile()) {
|
|
3829
|
-
return {
|
|
3830
|
-
ran: false,
|
|
3831
|
-
ok: false,
|
|
3832
|
-
output: "",
|
|
3833
|
-
reason: `entrypoint "${entrypoint}" is not a file`
|
|
3834
|
-
};
|
|
3835
|
-
}
|
|
3836
|
-
} catch {
|
|
3837
|
-
return {
|
|
3838
|
-
ran: false,
|
|
3839
|
-
ok: false,
|
|
3840
|
-
output: "",
|
|
3841
|
-
reason: `entrypoint "${entrypoint}" does not exist`
|
|
3842
|
-
};
|
|
3843
|
-
}
|
|
3844
|
-
return new Promise((resolveRun) => {
|
|
3845
|
-
let output = "";
|
|
3846
|
-
const child = spawn3(runtime, [entrypoint], {
|
|
3847
|
-
cwd: worktreePath,
|
|
3848
|
-
shell: false,
|
|
3849
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
3850
|
-
env: { ...process.env, ...env }
|
|
3851
|
-
});
|
|
3852
|
-
child.stdout?.on("data", (d) => output += d);
|
|
3853
|
-
child.stderr?.on("data", (d) => output += d);
|
|
3854
|
-
child.on(
|
|
3855
|
-
"error",
|
|
3856
|
-
(err) => resolveRun({
|
|
3857
|
-
ran: true,
|
|
3858
|
-
ok: false,
|
|
3859
|
-
output: `Failed to run ${runtime} ${entrypoint}: ${err.message}`
|
|
3860
|
-
})
|
|
3861
|
-
);
|
|
3862
|
-
child.on(
|
|
3863
|
-
"close",
|
|
3864
|
-
(code) => resolveRun({ ran: true, ok: code === 0, output: output.trim() })
|
|
3865
|
-
);
|
|
3866
|
-
});
|
|
3867
|
-
}
|
|
3868
3914
|
async function copyUploadIntoWorktree(repoRoot, worktreePath, ingestDir, sourcePath) {
|
|
3869
3915
|
const trimmed = sourcePath.trim();
|
|
3870
3916
|
if (!trimmed) {
|
|
@@ -3878,8 +3924,8 @@ async function copyUploadIntoWorktree(repoRoot, worktreePath, ingestDir, sourceP
|
|
|
3878
3924
|
} catch {
|
|
3879
3925
|
return { ok: false, reason: `"${sourcePath}" does not exist` };
|
|
3880
3926
|
}
|
|
3881
|
-
const relPath =
|
|
3882
|
-
const dest =
|
|
3927
|
+
const relPath = join9(ingestDir, basename2(source));
|
|
3928
|
+
const dest = join9(worktreePath, relPath);
|
|
3883
3929
|
try {
|
|
3884
3930
|
await mkdir6(dirname7(dest), { recursive: true });
|
|
3885
3931
|
await copyFile(source, dest);
|
|
@@ -3897,7 +3943,7 @@ function hasEnvVar(content, name) {
|
|
|
3897
3943
|
async function readEnvVar(worktreePath, name) {
|
|
3898
3944
|
let content;
|
|
3899
3945
|
try {
|
|
3900
|
-
content = await
|
|
3946
|
+
content = await readFile7(join9(worktreePath, ".env"), "utf8");
|
|
3901
3947
|
} catch (err) {
|
|
3902
3948
|
if (err.code !== "ENOENT") throw err;
|
|
3903
3949
|
return void 0;
|
|
@@ -3912,10 +3958,10 @@ async function readEnvVar(worktreePath, name) {
|
|
|
3912
3958
|
return value;
|
|
3913
3959
|
}
|
|
3914
3960
|
async function writeSearchEnvValues(worktreePath, vars) {
|
|
3915
|
-
const target =
|
|
3961
|
+
const target = join9(worktreePath, ".env");
|
|
3916
3962
|
let existing = "";
|
|
3917
3963
|
try {
|
|
3918
|
-
existing = await
|
|
3964
|
+
existing = await readFile7(target, "utf8");
|
|
3919
3965
|
} catch (err) {
|
|
3920
3966
|
if (err.code !== "ENOENT") throw err;
|
|
3921
3967
|
}
|
|
@@ -3984,15 +4030,15 @@ async function confirmDirtyWorkingTree(ctx, repoRoot) {
|
|
|
3984
4030
|
}
|
|
3985
4031
|
|
|
3986
4032
|
// src/lib/algoliaDocs.ts
|
|
3987
|
-
import { readFileSync, readdirSync, existsSync
|
|
3988
|
-
import { dirname as dirname8, join as
|
|
4033
|
+
import { readFileSync, readdirSync, existsSync } from "node:fs";
|
|
4034
|
+
import { dirname as dirname8, join as join10 } from "node:path";
|
|
3989
4035
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
3990
|
-
var DOCS_SUBPATH =
|
|
4036
|
+
var DOCS_SUBPATH = join10("docs", "algolia-sdk");
|
|
3991
4037
|
function findDocsDir() {
|
|
3992
4038
|
let dir = dirname8(fileURLToPath2(import.meta.url));
|
|
3993
4039
|
for (; ; ) {
|
|
3994
|
-
const candidate =
|
|
3995
|
-
if (
|
|
4040
|
+
const candidate = join10(dir, DOCS_SUBPATH);
|
|
4041
|
+
if (existsSync(candidate)) return candidate;
|
|
3996
4042
|
const parent = dirname8(dir);
|
|
3997
4043
|
if (parent === dir) return void 0;
|
|
3998
4044
|
dir = parent;
|
|
@@ -4014,7 +4060,7 @@ function loadAlgoliaDoc(language) {
|
|
|
4014
4060
|
);
|
|
4015
4061
|
return "";
|
|
4016
4062
|
}
|
|
4017
|
-
return readFileSync(
|
|
4063
|
+
return readFileSync(join10(docsDir, files[0]), "utf8").trim();
|
|
4018
4064
|
}
|
|
4019
4065
|
function getNamedDoc(name, language) {
|
|
4020
4066
|
const docsDir = findDocsDir();
|
|
@@ -4022,8 +4068,8 @@ function getNamedDoc(name, language) {
|
|
|
4022
4068
|
logger.warn("docs/algolia-sdk not found");
|
|
4023
4069
|
return "";
|
|
4024
4070
|
}
|
|
4025
|
-
const file =
|
|
4026
|
-
if (!
|
|
4071
|
+
const file = join10(docsDir, `${name}-${language}.md`);
|
|
4072
|
+
if (!existsSync(file)) {
|
|
4027
4073
|
logger.warn({ name, language }, "named SDK reference not found");
|
|
4028
4074
|
return "";
|
|
4029
4075
|
}
|
|
@@ -4067,11 +4113,7 @@ var implementSchema = z27.object({
|
|
|
4067
4113
|
});
|
|
4068
4114
|
var implementationOutputSchema = z27.object({
|
|
4069
4115
|
summary: z27.string(),
|
|
4070
|
-
|
|
4071
|
-
// free-form command string. `runtime` is allowlisted and `entrypoint` is
|
|
4072
|
-
// validated worktree-relative, so the agent cannot inject extra commands.
|
|
4073
|
-
runtime: z27.enum(INGEST_RUNTIMES).optional(),
|
|
4074
|
-
entrypoint: z27.string().optional()
|
|
4116
|
+
ingestCommand: z27.string().optional()
|
|
4075
4117
|
});
|
|
4076
4118
|
var verificationOutputSchema = z27.object({
|
|
4077
4119
|
summary: z27.string(),
|
|
@@ -4156,7 +4198,9 @@ function baseInstructions(input) {
|
|
|
4156
4198
|
// index-scoped keys then reject with a 403.
|
|
4157
4199
|
`Target Algolia index, to be used exactly as written \u2014 never renamed, re-cased, prefixed, or suffixed: "${input.targetIndex}"`,
|
|
4158
4200
|
`Project languages and frameworks: ${JSON.stringify(input.language)}`,
|
|
4159
|
-
"Make minimal, idiomatic changes; do not touch unrelated code."
|
|
4201
|
+
"Make minimal, idiomatic changes; do not touch unrelated code.",
|
|
4202
|
+
`Commands run through a shell on ${process.platform}. Write commands that work there.`,
|
|
4203
|
+
"runShell needs the developer to approve each command, so give every call a clear `explanation` naming what it does and any side effect. If a command is rejected, do not retry it \u2014 take a different approach or report the limitation."
|
|
4160
4204
|
];
|
|
4161
4205
|
}
|
|
4162
4206
|
function sourceSpecificInstructions(input) {
|
|
@@ -4192,9 +4236,9 @@ function ingestionInstructions(input) {
|
|
|
4192
4236
|
"Use the appropriate Algolia package in the ingestion script. Do not use the raw HTTP API.",
|
|
4193
4237
|
"After a successful ingest, the script must print exactly one line to stdout in the form `ALGOLIA_WIZARD_RECORD_COUNT=<n>`, where <n> is the total number of records pushed to Algolia. Print it last, on its own line, with no surrounding text.",
|
|
4194
4238
|
getNamedDoc("save-records", "js"),
|
|
4195
|
-
'
|
|
4239
|
+
'Install the Algolia client via runShell and add it to package.json "dependencies" with a valid version range, so the dependency is not just installed ad hoc.',
|
|
4240
|
+
'Then run the script yourself via runShell, and report the command you ran as "ingestCommand" so the developer can re-run it. Its explanation must say that running it writes records to Algolia.',
|
|
4196
4241
|
"The summary should be extremely concise.",
|
|
4197
|
-
`Return how to run the script as two fields, not a command string: "runtime" (one of ${INGEST_RUNTIMES.join(", ")}) and "entrypoint" (the script path relative to the worktree root, e.g. "${input.ingestDir}/ingest.mjs"). The wizard runs \`<runtime> <entrypoint>\` directly, so the entrypoint must be a plain path with no flags or arguments. Write a script one of those interpreters can run as-is.`,
|
|
4198
4242
|
...sourceSpecificInstructions(input)
|
|
4199
4243
|
] : []
|
|
4200
4244
|
];
|
|
@@ -4208,6 +4252,7 @@ function searchInstructions(input) {
|
|
|
4208
4252
|
doc,
|
|
4209
4253
|
`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 target index.`,
|
|
4210
4254
|
`Read the index name from the ${searchIndexVar(input.language)} env var, which the wizard sets to "${input.targetIndex}". Never hardcode an index name or derive one from the project, file, or component name.`,
|
|
4255
|
+
"Read the App ID, the search-only API key, and the index name from env vars; never hardcode them. A search-only key is safe to expose client-side.",
|
|
4211
4256
|
// The key is provisioned only after verification passes, so the agent never
|
|
4212
4257
|
// sees one. It must also leave .env alone: the wizard reads that file to
|
|
4213
4258
|
// decide whether a key already exists, and an agent-invented value there
|
|
@@ -4217,8 +4262,7 @@ function searchInstructions(input) {
|
|
|
4217
4262
|
// ".env" right after this step, so a renamed prefix would leave the code
|
|
4218
4263
|
// reading a var the wizard never wrote.
|
|
4219
4264
|
`Use exactly these public env var names in the code: ${input.searchEnvVars.map(({ name }) => name).join(", ")}.`,
|
|
4220
|
-
|
|
4221
|
-
'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.',
|
|
4265
|
+
'Install any Algolia/InstantSearch packages you import via runShell, and add them to package.json "dependencies" with a valid version range.',
|
|
4222
4266
|
"The summary should be extremely concise; do not mention env var setup or manual testing steps \u2014 the wizard writes the resolved credentials to .env and reports that separately."
|
|
4223
4267
|
];
|
|
4224
4268
|
}
|
|
@@ -4226,11 +4270,12 @@ function verificationInstructions(input) {
|
|
|
4226
4270
|
return [
|
|
4227
4271
|
"Verify the Algolia implementation changes in the current worktree.",
|
|
4228
4272
|
`Verification tools found in the codebase: ${JSON.stringify(input.findings.verification ?? [])}.`,
|
|
4229
|
-
"
|
|
4230
|
-
"
|
|
4231
|
-
"
|
|
4273
|
+
"Run the project's own checks (lint, type check, tests) via runShell, using the commands the project actually defines \u2014 its task runner, manifest scripts, or Makefile. Run every check that applies, not just the first.",
|
|
4274
|
+
"This worktree starts with no installed dependencies. If a check fails because packages or modules are missing, install the dependencies via runShell and re-run it rather than changing the code.",
|
|
4275
|
+
"For issues caused by the implementation, make minimal fixes with writeFile and re-run the checks.",
|
|
4276
|
+
"Do not make speculative fixes when no checks exist, a check cannot run, or failures are unrelated to these changes \u2014 note the limitation in your summary.",
|
|
4232
4277
|
"Do not add new Algolia functionality here; only validate and make minimal correctness fixes.",
|
|
4233
|
-
`Do not modify "${input.ingestDir}/" unless
|
|
4278
|
+
`Do not modify "${input.ingestDir}/" unless a check reports an actionable issue in its files.`,
|
|
4234
4279
|
"Always call reportStatus with status=success once verification has run, even when sufficient=false.",
|
|
4235
4280
|
"Set sufficient=true only when the implementation is complete and checks pass (or fail for a clearly unrelated reason).",
|
|
4236
4281
|
"Set sufficient=false when the implementation is incomplete or has implementation-caused failures; include concrete additionalInstructions for the next pass."
|
|
@@ -4251,14 +4296,15 @@ var IMPLEMENT_CONFIG = {
|
|
|
4251
4296
|
}
|
|
4252
4297
|
};
|
|
4253
4298
|
var useCaseToolMap = {
|
|
4254
|
-
ingestion: [
|
|
4255
|
-
search: [...FS_READ_TOOLS, "writeFile", "notifyUser"],
|
|
4256
|
-
verification: [
|
|
4299
|
+
ingestion: [
|
|
4257
4300
|
...FS_READ_TOOLS,
|
|
4258
4301
|
"writeFile",
|
|
4259
|
-
"
|
|
4302
|
+
"writeCredentials",
|
|
4303
|
+
"runShell",
|
|
4260
4304
|
"notifyUser"
|
|
4261
|
-
]
|
|
4305
|
+
],
|
|
4306
|
+
search: [...FS_READ_TOOLS, "writeFile", "runShell", "notifyUser"],
|
|
4307
|
+
verification: [...FS_READ_TOOLS, "writeFile", "runShell", "notifyUser"]
|
|
4262
4308
|
};
|
|
4263
4309
|
function toolsForUseCase(useCase, ingestionSource) {
|
|
4264
4310
|
const tools = useCaseToolMap[useCase];
|
|
@@ -4281,15 +4327,51 @@ function formatSummary(useCase, summary) {
|
|
|
4281
4327
|
const label = useCase === "ingestion" ? "Ingestion" : useCase === "search" ? "Search" : "Verification";
|
|
4282
4328
|
return `${label}: ${summary}`;
|
|
4283
4329
|
}
|
|
4284
|
-
function buildIngestCommand(worktree, runtime, entrypoint) {
|
|
4285
|
-
return `cd ${shellQuote(worktree)} && ${runtime} ${shellQuote(entrypoint)}`;
|
|
4286
|
-
}
|
|
4287
4330
|
function parseIngestRecordCount(output) {
|
|
4288
4331
|
const match = output.match(/ALGOLIA_WIZARD_RECORD_COUNT=(\d+)/);
|
|
4289
4332
|
if (!match) return void 0;
|
|
4290
4333
|
const count = Number(match[1]);
|
|
4291
4334
|
return Number.isFinite(count) ? count : void 0;
|
|
4292
4335
|
}
|
|
4336
|
+
function ingestOutcome(executions, ingestCommand) {
|
|
4337
|
+
const newestFirst = [...executions].reverse();
|
|
4338
|
+
const withCount = newestFirst.filter(
|
|
4339
|
+
(e) => parseIngestRecordCount(e.output ?? "") != null
|
|
4340
|
+
);
|
|
4341
|
+
const succeeded = newestFirst.filter((e) => e.approved && e.exitCode === 0);
|
|
4342
|
+
return {
|
|
4343
|
+
run: succeeded.find((e) => e.command === ingestCommand) ?? succeeded.find((e) => withCount.includes(e)),
|
|
4344
|
+
attempt: ingestCommand ? newestFirst.find((e) => e.command === ingestCommand) : void 0,
|
|
4345
|
+
recordCount: parseIngestRecordCount(withCount[0]?.output ?? "")
|
|
4346
|
+
};
|
|
4347
|
+
}
|
|
4348
|
+
var INGEST_OUTPUT_TAIL_CHARS = 400;
|
|
4349
|
+
function outputTail(output) {
|
|
4350
|
+
const trimmed = output?.trim();
|
|
4351
|
+
if (!trimmed) return void 0;
|
|
4352
|
+
return trimmed.length > INGEST_OUTPUT_TAIL_CHARS ? `\u2026${trimmed.slice(-INGEST_OUTPUT_TAIL_CHARS)}` : trimmed;
|
|
4353
|
+
}
|
|
4354
|
+
function ingestFailure(attempt, executions) {
|
|
4355
|
+
if (!attempt) {
|
|
4356
|
+
return {
|
|
4357
|
+
reason: executions.some((e) => !e.approved) ? "a command it needed was declined" : "no successful run was recorded"
|
|
4358
|
+
};
|
|
4359
|
+
}
|
|
4360
|
+
if (!attempt.approved) return { reason: "you declined to run it" };
|
|
4361
|
+
const detail = outputTail(attempt.output);
|
|
4362
|
+
if (attempt.timedOut) {
|
|
4363
|
+
const seconds = Math.round((attempt.durationMs ?? 0) / 1e3);
|
|
4364
|
+
return { reason: `it timed out after ${seconds}s`, detail };
|
|
4365
|
+
}
|
|
4366
|
+
return { reason: `it failed (exit ${attempt.exitCode ?? "unknown"})`, detail };
|
|
4367
|
+
}
|
|
4368
|
+
function makeToolContext(worktree, env = async () => ({})) {
|
|
4369
|
+
return createToolContext(
|
|
4370
|
+
DEFAULT_TOOL_LIMITS,
|
|
4371
|
+
worktree,
|
|
4372
|
+
createShellContext({ env, approve: storeApproval(worktree) })
|
|
4373
|
+
);
|
|
4374
|
+
}
|
|
4293
4375
|
function verificationRetryInstructions(verification) {
|
|
4294
4376
|
return [
|
|
4295
4377
|
`Implementation insufficient. Address these findings before reporting completion: ${verification.additionalInstructions ?? verification.summary}`
|
|
@@ -4368,9 +4450,13 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4368
4450
|
const confirmed2 = normalized.confirmedEntities;
|
|
4369
4451
|
const searchLocation = normalized.searchImplementationAnalysis;
|
|
4370
4452
|
let appId;
|
|
4453
|
+
let ingestAppId;
|
|
4371
4454
|
if (useCases.includes("search")) {
|
|
4372
4455
|
appId = (await requireApplication()).id;
|
|
4373
4456
|
}
|
|
4457
|
+
if (useCases.includes("ingestion")) {
|
|
4458
|
+
ingestAppId = appId ?? (await requireApplication()).id;
|
|
4459
|
+
}
|
|
4374
4460
|
const worktree = existingWorktreePath ?? (await createWorktree(repoRoot)).path;
|
|
4375
4461
|
try {
|
|
4376
4462
|
process.chdir(worktree);
|
|
@@ -4428,41 +4514,31 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4428
4514
|
}
|
|
4429
4515
|
let finalSearchEnvVars = input.searchEnvVars;
|
|
4430
4516
|
let agentRuns = 0;
|
|
4431
|
-
let
|
|
4432
|
-
let ingestEntrypoint;
|
|
4517
|
+
let ingestCommand;
|
|
4433
4518
|
let ingestScriptRan = false;
|
|
4434
4519
|
let ingestRecordCount;
|
|
4435
4520
|
let ingestDurationMs;
|
|
4436
|
-
let installFailed = false;
|
|
4437
4521
|
let ingestOutcomeMessage;
|
|
4522
|
+
const ingestKeyAppId = ingestAppId;
|
|
4523
|
+
const ingestionTools = ingestKeyAppId ? makeToolContext(worktree, async () => ({
|
|
4524
|
+
[APP_ID_VAR]: ingestKeyAppId,
|
|
4525
|
+
[API_KEY_VAR]: (await resolveWriteKey(targetIndex, ingestKeyAppId)).key,
|
|
4526
|
+
[INDEX_NAME_VAR]: targetIndex
|
|
4527
|
+
})) : void 0;
|
|
4528
|
+
const searchTools = makeToolContext(worktree);
|
|
4438
4529
|
async function runImplementationUseCase(currentUseCase, extraInstructions = []) {
|
|
4439
4530
|
if (agentRuns > 0) ctx.recordStepExecution();
|
|
4440
4531
|
agentRuns += 1;
|
|
4441
|
-
|
|
4532
|
+
return runAgent({
|
|
4442
4533
|
instructions: buildAgentInstructions(
|
|
4443
4534
|
currentUseCase,
|
|
4444
4535
|
input,
|
|
4445
4536
|
extraInstructions
|
|
4446
4537
|
),
|
|
4447
4538
|
tools: toolsForUseCase(currentUseCase, input.ingestionSource),
|
|
4448
|
-
outputSchema: implementationOutputSchema
|
|
4449
|
-
|
|
4450
|
-
ctx.notify({
|
|
4451
|
-
messages: [`Installing dependencies for ${currentUseCase}\u2026`]
|
|
4539
|
+
outputSchema: implementationOutputSchema,
|
|
4540
|
+
toolContext: currentUseCase === "ingestion" ? ingestionTools ?? searchTools : searchTools
|
|
4452
4541
|
});
|
|
4453
|
-
const installLogId = ctx.logStart("installWorktreeDeps", {
|
|
4454
|
-
useCase: currentUseCase
|
|
4455
|
-
});
|
|
4456
|
-
const install = await installWorktreeDeps(worktree);
|
|
4457
|
-
ctx.logEnd(installLogId, install.ok ? "success" : "error");
|
|
4458
|
-
if (!install.ok) {
|
|
4459
|
-
installFailed = true;
|
|
4460
|
-
logger.warn(
|
|
4461
|
-
{ useCase: currentUseCase, output: install.output },
|
|
4462
|
-
"implement: dependency install in worktree failed; generated commands may not run until deps are installed"
|
|
4463
|
-
);
|
|
4464
|
-
}
|
|
4465
|
-
return result;
|
|
4466
4542
|
}
|
|
4467
4543
|
async function runVerificationUseCase() {
|
|
4468
4544
|
if (agentRuns > 0) ctx.recordStepExecution();
|
|
@@ -4470,111 +4546,75 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES, existingWo
|
|
|
4470
4546
|
return runAgent({
|
|
4471
4547
|
instructions: buildAgentInstructions("verification", input),
|
|
4472
4548
|
tools: toolsForUseCase("verification"),
|
|
4473
|
-
outputSchema: verificationOutputSchema
|
|
4549
|
+
outputSchema: verificationOutputSchema,
|
|
4550
|
+
toolContext: searchTools
|
|
4474
4551
|
});
|
|
4475
4552
|
}
|
|
4476
4553
|
if (useCases.includes("ingestion")) {
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4554
|
+
let ingestFailureDetail;
|
|
4555
|
+
const result = await runImplementationUseCase("ingestion");
|
|
4556
|
+
summaries.push(formatSummary("ingestion", result.summary));
|
|
4557
|
+
ingestCommand = result.ingestCommand;
|
|
4558
|
+
const executions = (ingestionTools ?? searchTools).shell.executions;
|
|
4559
|
+
const {
|
|
4560
|
+
run: ingestRun,
|
|
4561
|
+
attempt: ingestAttempt,
|
|
4562
|
+
recordCount
|
|
4563
|
+
} = ingestOutcome(executions, ingestCommand);
|
|
4564
|
+
ingestScriptRan = ingestRun != null;
|
|
4565
|
+
ingestRecordCount = recordCount;
|
|
4566
|
+
ingestDurationMs = ingestRun?.durationMs;
|
|
4567
|
+
if (ingestScriptRan) {
|
|
4568
|
+
ingestOutcomeMessage = `\u2705 Ingestion succeeded${ingestRecordCount != null ? ` \u2014 ${ingestRecordCount} record(s) indexed.` : "."}`;
|
|
4569
|
+
if (ingestRecordCount != null) {
|
|
4570
|
+
track("AI Wizard Ingest Successful", {
|
|
4571
|
+
entity_name: confirmed2?.map((e) => e.name).join(", ") || "unknown",
|
|
4572
|
+
record_count: ingestRecordCount,
|
|
4573
|
+
duration_ms: ingestDurationMs ?? 0
|
|
4496
4574
|
});
|
|
4497
|
-
const startedAt = Date.now();
|
|
4498
|
-
const run2 = await runIngestScript(
|
|
4499
|
-
worktree,
|
|
4500
|
-
ingestRuntime,
|
|
4501
|
-
ingestEntrypoint,
|
|
4502
|
-
{
|
|
4503
|
-
[APP_ID_VAR]: ingestApp.id,
|
|
4504
|
-
[API_KEY_VAR]: writeKey,
|
|
4505
|
-
[INDEX_NAME_VAR]: targetIndex
|
|
4506
|
-
}
|
|
4507
|
-
);
|
|
4508
|
-
ctx.logEnd(scriptLogId, run2.ok ? "success" : "error");
|
|
4509
|
-
ingestScriptRan = run2.ran && run2.ok;
|
|
4510
|
-
if (ingestScriptRan) {
|
|
4511
|
-
ingestDurationMs = Date.now() - startedAt;
|
|
4512
|
-
ingestRecordCount = parseIngestRecordCount(run2.output);
|
|
4513
|
-
if (ingestRecordCount != null) {
|
|
4514
|
-
track("AI Wizard Ingest Successful", {
|
|
4515
|
-
entity_name: confirmed2?.map((e) => e.name).join(", ") || "unknown",
|
|
4516
|
-
record_count: ingestRecordCount,
|
|
4517
|
-
duration_ms: ingestDurationMs
|
|
4518
|
-
});
|
|
4519
|
-
}
|
|
4520
|
-
}
|
|
4521
|
-
let summaryLine;
|
|
4522
|
-
let outcomeMessage;
|
|
4523
|
-
if (!run2.ran) {
|
|
4524
|
-
summaryLine = `\u26A0\uFE0F Skipped running the ingestion script: ${run2.reason}`;
|
|
4525
|
-
outcomeMessage = `\u26A0\uFE0F The ingestion script did not run: ${run2.reason}`;
|
|
4526
|
-
logger.warn(
|
|
4527
|
-
{
|
|
4528
|
-
runtime: ingestRuntime,
|
|
4529
|
-
entrypoint: ingestEntrypoint,
|
|
4530
|
-
reason: run2.reason
|
|
4531
|
-
},
|
|
4532
|
-
"implement: refused to auto-run ingestion script"
|
|
4533
|
-
);
|
|
4534
|
-
track("Error", {
|
|
4535
|
-
step: "Push Data",
|
|
4536
|
-
error: `ingestion script skipped: ${run2.reason}`,
|
|
4537
|
-
product_area: "AI Wizard"
|
|
4538
|
-
});
|
|
4539
|
-
} else if (run2.ok) {
|
|
4540
|
-
const status = "Ingestion run: succeeded.";
|
|
4541
|
-
summaryLine = run2.output ? `${status}
|
|
4542
|
-
${run2.output}` : status;
|
|
4543
|
-
outcomeMessage = `\u2705 Ingestion succeeded${ingestRecordCount != null ? ` \u2014 ${ingestRecordCount} record(s) indexed.` : "."}`;
|
|
4544
|
-
} else {
|
|
4545
|
-
const status = "\u26A0\uFE0F Ingestion run failed:";
|
|
4546
|
-
summaryLine = run2.output ? `${status}
|
|
4547
|
-
${run2.output}` : status;
|
|
4548
|
-
outcomeMessage = `\u274C Ingestion failed.${run2.output ? ` ${run2.output}` : ""}`;
|
|
4549
|
-
logger.warn(
|
|
4550
|
-
{
|
|
4551
|
-
runtime: ingestRuntime,
|
|
4552
|
-
entrypoint: ingestEntrypoint,
|
|
4553
|
-
output: run2.output
|
|
4554
|
-
},
|
|
4555
|
-
"implement: ingestion script run failed"
|
|
4556
|
-
);
|
|
4557
|
-
track("Error", {
|
|
4558
|
-
step: "Push Data",
|
|
4559
|
-
error: run2.output || "ingestion script exited non-zero",
|
|
4560
|
-
product_area: "AI Wizard"
|
|
4561
|
-
});
|
|
4562
|
-
}
|
|
4563
|
-
summaries.push(summaryLine);
|
|
4564
|
-
ingestOutcomeMessage = outcomeMessage;
|
|
4565
4575
|
}
|
|
4576
|
+
} else {
|
|
4577
|
+
const { reason, detail } = ingestFailure(ingestAttempt, executions);
|
|
4578
|
+
ingestOutcomeMessage = `\u26A0\uFE0F Records were not indexed \u2014 ${reason}.${ingestCommand ? " Run the command below when you are ready." : ""}`;
|
|
4579
|
+
ingestFailureDetail = detail;
|
|
4580
|
+
summaries.push(
|
|
4581
|
+
`\u26A0\uFE0F Ingestion did not complete: ${reason}.${detail ? `
|
|
4582
|
+
${detail}` : ""}`
|
|
4583
|
+
);
|
|
4584
|
+
logger.warn(
|
|
4585
|
+
{
|
|
4586
|
+
ingestCommand,
|
|
4587
|
+
reason,
|
|
4588
|
+
approved: ingestAttempt?.approved,
|
|
4589
|
+
exitCode: ingestAttempt?.exitCode,
|
|
4590
|
+
timedOut: ingestAttempt?.timedOut,
|
|
4591
|
+
commandsRun: executions.length
|
|
4592
|
+
},
|
|
4593
|
+
"implement: ingestion script did not complete successfully"
|
|
4594
|
+
);
|
|
4595
|
+
track("Error", {
|
|
4596
|
+
step: "Push Data",
|
|
4597
|
+
error: `ingestion did not complete: ${reason}`,
|
|
4598
|
+
product_area: "AI Wizard"
|
|
4599
|
+
});
|
|
4566
4600
|
}
|
|
4567
4601
|
const commandMessages = [`Open the worktree: cd ${shellQuote(worktree)}`];
|
|
4568
|
-
if (
|
|
4569
|
-
commandMessages.push(
|
|
4570
|
-
`Ingestion command: ${buildIngestCommand(worktree, ingestRuntime, ingestEntrypoint)}`
|
|
4571
|
-
);
|
|
4602
|
+
if (ingestCommand) {
|
|
4603
|
+
commandMessages.push(`Ingestion command: ${ingestCommand}`);
|
|
4572
4604
|
}
|
|
4573
4605
|
await ctx.requestUserInput({
|
|
4574
4606
|
prompt: "",
|
|
4575
4607
|
promptType: "enterToContinue",
|
|
4576
4608
|
options: [],
|
|
4577
|
-
|
|
4609
|
+
// The wizard never streams command output, so a failed run's tail is the
|
|
4610
|
+
// only place the developer sees why it failed. One message per line:
|
|
4611
|
+
// the panel's height accounting counts a message as one wrapped line
|
|
4612
|
+
// (see Notices.tsx), so an embedded newline overflows it.
|
|
4613
|
+
messages: [
|
|
4614
|
+
ingestOutcomeMessage,
|
|
4615
|
+
...ingestFailureDetail?.split("\n").filter((l) => l.trim()) ?? [],
|
|
4616
|
+
...commandMessages
|
|
4617
|
+
]
|
|
4578
4618
|
});
|
|
4579
4619
|
}
|
|
4580
4620
|
if (useCases.includes("search")) {
|
|
@@ -4691,22 +4731,13 @@ ${run2.output}` : status;
|
|
|
4691
4731
|
"implement: agent reported success but no files changed in the worktree"
|
|
4692
4732
|
);
|
|
4693
4733
|
}
|
|
4694
|
-
if (installFailed) {
|
|
4695
|
-
summaries.push(
|
|
4696
|
-
'\u26A0\uFE0F Dependency install in the worktree failed. Run your package manager install in the worktree before the command below, or it will fail with "Cannot find module".'
|
|
4697
|
-
);
|
|
4698
|
-
}
|
|
4699
4734
|
return {
|
|
4700
4735
|
ingestionSource,
|
|
4701
4736
|
filesChanged,
|
|
4702
4737
|
summary: summaries.join("\n\n"),
|
|
4703
4738
|
worktreePath: worktree,
|
|
4704
|
-
...useCases.includes("ingestion") &&
|
|
4705
|
-
ingestCommand
|
|
4706
|
-
worktree,
|
|
4707
|
-
ingestRuntime,
|
|
4708
|
-
ingestEntrypoint
|
|
4709
|
-
),
|
|
4739
|
+
...useCases.includes("ingestion") && ingestCommand ? {
|
|
4740
|
+
ingestCommand,
|
|
4710
4741
|
ingestScriptRan,
|
|
4711
4742
|
...ingestRecordCount != null ? { ingestRecordCount } : {},
|
|
4712
4743
|
...ingestDurationMs != null ? { ingestDurationMs } : {}
|
|
@@ -5038,7 +5069,7 @@ function parseCliArgs(argv) {
|
|
|
5038
5069
|
|
|
5039
5070
|
// src/lib/resetState.ts
|
|
5040
5071
|
import { readdir as readdir4, rm as rm2 } from "node:fs/promises";
|
|
5041
|
-
import { join as
|
|
5072
|
+
import { join as join11 } from "node:path";
|
|
5042
5073
|
var KEEP = ["wizard.log"];
|
|
5043
5074
|
async function resetProjectState() {
|
|
5044
5075
|
const dir = stateDir();
|
|
@@ -5052,14 +5083,14 @@ async function resetProjectState() {
|
|
|
5052
5083
|
const targets = entries.filter((name) => !KEEP.includes(name));
|
|
5053
5084
|
await Promise.all(
|
|
5054
5085
|
targets.map(
|
|
5055
|
-
(name) => rm2(
|
|
5086
|
+
(name) => rm2(join11(dir, name), { recursive: true, force: true })
|
|
5056
5087
|
)
|
|
5057
5088
|
);
|
|
5058
5089
|
return { dir, removed: targets };
|
|
5059
5090
|
}
|
|
5060
5091
|
|
|
5061
5092
|
// src/main.tsx
|
|
5062
|
-
import { jsx as
|
|
5093
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
5063
5094
|
async function startup() {
|
|
5064
5095
|
setProjectRoot(process.cwd());
|
|
5065
5096
|
let args;
|
|
@@ -5109,7 +5140,7 @@ ${formatStepList(workflow)}`);
|
|
|
5109
5140
|
}
|
|
5110
5141
|
async function run(workflow) {
|
|
5111
5142
|
const store = useWizard.getState();
|
|
5112
|
-
const instance = render(/* @__PURE__ */
|
|
5143
|
+
const instance = render(/* @__PURE__ */ jsx15(App, {}), { incrementalRendering: true });
|
|
5113
5144
|
await store.waitForStart();
|
|
5114
5145
|
let user = await getUser();
|
|
5115
5146
|
if (!user) {
|