cueclaw 0.2.1 → 0.2.2
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/{app-P3ERBGJD.js → app-PUHQN5BJ.js} +217 -245
- package/dist/cli.js +2 -2
- package/package.json +1 -1
|
@@ -268,8 +268,12 @@ var KeyPriority = {
|
|
|
268
268
|
var KeypressContext = createContext(null);
|
|
269
269
|
function KeypressProvider({ children }) {
|
|
270
270
|
const handlersRef = useRef([]);
|
|
271
|
+
const sortHandlers = () => {
|
|
272
|
+
handlersRef.current.sort((a, b) => b.priority - a.priority);
|
|
273
|
+
};
|
|
271
274
|
const register = useCallback((entry) => {
|
|
272
275
|
handlersRef.current = [...handlersRef.current.filter((h) => h.id !== entry.id), entry];
|
|
276
|
+
sortHandlers();
|
|
273
277
|
}, []);
|
|
274
278
|
const unregister = useCallback((id) => {
|
|
275
279
|
handlersRef.current = handlersRef.current.filter((h) => h.id !== id);
|
|
@@ -280,8 +284,8 @@ function KeypressProvider({ children }) {
|
|
|
280
284
|
);
|
|
281
285
|
}, []);
|
|
282
286
|
useInput((input, key) => {
|
|
283
|
-
const
|
|
284
|
-
|
|
287
|
+
for (const entry of handlersRef.current) {
|
|
288
|
+
if (!entry.isActive) continue;
|
|
285
289
|
const consumed = entry.handler(input, key);
|
|
286
290
|
if (consumed === true) break;
|
|
287
291
|
}
|
|
@@ -369,7 +373,7 @@ function DialogManager({ children }) {
|
|
|
369
373
|
}
|
|
370
374
|
|
|
371
375
|
// src/tui/app-provider.tsx
|
|
372
|
-
import { useReducer, useCallback as useCallback7, useMemo
|
|
376
|
+
import { useReducer, useCallback as useCallback7, useMemo, useState as useState4, useEffect as useEffect3, useRef as useRef6 } from "react";
|
|
373
377
|
import { useApp } from "ink";
|
|
374
378
|
|
|
375
379
|
// src/tui/ui-state-context.ts
|
|
@@ -806,6 +810,8 @@ function useWorkflowExecution(workflow, db, cwd, bridgeRef, plannerSessionRef, d
|
|
|
806
810
|
upsertWorkflow(db, confirmed);
|
|
807
811
|
} catch (err) {
|
|
808
812
|
logger.error({ err }, "Failed to persist workflow");
|
|
813
|
+
dispatch({ type: "ADD_MESSAGE", message: { type: "error", text: `Failed to save workflow: ${err instanceof Error ? err.message : String(err)}` } });
|
|
814
|
+
return;
|
|
809
815
|
}
|
|
810
816
|
const controller = new AbortController();
|
|
811
817
|
abortRef.current = controller;
|
|
@@ -1131,7 +1137,7 @@ function useGlobalKeypress({
|
|
|
1131
1137
|
}
|
|
1132
1138
|
|
|
1133
1139
|
// src/tui/hooks/use-command-dispatch.ts
|
|
1134
|
-
import React4, { useCallback as useCallback6,
|
|
1140
|
+
import React4, { useCallback as useCallback6, useRef as useRef5 } from "react";
|
|
1135
1141
|
|
|
1136
1142
|
// src/tui/commands/registry.ts
|
|
1137
1143
|
var commands = [];
|
|
@@ -1494,7 +1500,8 @@ function useCommandDispatch({
|
|
|
1494
1500
|
showDialog,
|
|
1495
1501
|
dismissDialog
|
|
1496
1502
|
}) {
|
|
1497
|
-
const
|
|
1503
|
+
const commandCtxRef = useRef5(null);
|
|
1504
|
+
commandCtxRef.current = {
|
|
1498
1505
|
db,
|
|
1499
1506
|
config,
|
|
1500
1507
|
cwd,
|
|
@@ -1503,13 +1510,12 @@ function useCommandDispatch({
|
|
|
1503
1510
|
clearMessages: () => dispatch({ type: "SET_MESSAGES", messages: [] }),
|
|
1504
1511
|
setConfig,
|
|
1505
1512
|
setThemeVersion
|
|
1506
|
-
}
|
|
1513
|
+
};
|
|
1507
1514
|
const handleSlashCommand = useCallback6(async (text) => {
|
|
1508
1515
|
if (!config) return false;
|
|
1509
1516
|
const parsed = parseSlashCommand(text);
|
|
1510
1517
|
if (!parsed) return false;
|
|
1511
|
-
commandCtx
|
|
1512
|
-
commandCtx.config = config;
|
|
1518
|
+
const commandCtx = commandCtxRef.current;
|
|
1513
1519
|
dispatch({ type: "ADD_MESSAGE", message: { type: "user", text } });
|
|
1514
1520
|
if (parsed.name === "cancel") {
|
|
1515
1521
|
if (plannerSessionRef.current) {
|
|
@@ -1598,8 +1604,8 @@ function useCommandDispatch({
|
|
|
1598
1604
|
dispatch({ type: "ADD_MESSAGE", message: { type: "assistant", text: `Unknown command: /${parsed.name}. Type /help for available commands.` } });
|
|
1599
1605
|
}
|
|
1600
1606
|
return true;
|
|
1601
|
-
}, [config, db,
|
|
1602
|
-
return { handleSlashCommand
|
|
1607
|
+
}, [config, db, exit, showDialog, dismissDialog]);
|
|
1608
|
+
return { handleSlashCommand };
|
|
1603
1609
|
}
|
|
1604
1610
|
|
|
1605
1611
|
// src/tui/app-provider.tsx
|
|
@@ -1628,8 +1634,10 @@ function appReducer(state, action) {
|
|
|
1628
1634
|
return { ...state, streamingText: action.text };
|
|
1629
1635
|
case "UPDATE_STEP":
|
|
1630
1636
|
return { ...state, stepProgress: new Map(state.stepProgress).set(action.stepId, action.progress) };
|
|
1631
|
-
case "ADD_OUTPUT":
|
|
1632
|
-
|
|
1637
|
+
case "ADD_OUTPUT": {
|
|
1638
|
+
const next = [...state.executionOutput, action.line];
|
|
1639
|
+
return { ...state, executionOutput: next.length > 200 ? next.slice(-200) : next };
|
|
1640
|
+
}
|
|
1633
1641
|
default:
|
|
1634
1642
|
return state;
|
|
1635
1643
|
}
|
|
@@ -1637,7 +1645,7 @@ function appReducer(state, action) {
|
|
|
1637
1645
|
function AppProvider({ cwd, skipOnboarding, children }) {
|
|
1638
1646
|
const { exit } = useApp();
|
|
1639
1647
|
const { showDialog, dismissDialog } = useDialog();
|
|
1640
|
-
const validation =
|
|
1648
|
+
const validation = useMemo(() => validateConfig(), []);
|
|
1641
1649
|
const needsSetup = !skipOnboarding && !validation.valid;
|
|
1642
1650
|
const [config, setConfig] = useState4(() => {
|
|
1643
1651
|
if (needsSetup) return null;
|
|
@@ -1647,7 +1655,7 @@ function AppProvider({ cwd, skipOnboarding, children }) {
|
|
|
1647
1655
|
return null;
|
|
1648
1656
|
}
|
|
1649
1657
|
});
|
|
1650
|
-
const db =
|
|
1658
|
+
const db = useMemo(() => initDb(), []);
|
|
1651
1659
|
const [themeVersion, setThemeVersion] = useState4(0);
|
|
1652
1660
|
const initialState = {
|
|
1653
1661
|
view: needsSetup ? "onboarding" : "chat",
|
|
@@ -1662,7 +1670,16 @@ function AppProvider({ cwd, skipOnboarding, children }) {
|
|
|
1662
1670
|
detailRuns: [],
|
|
1663
1671
|
detailStepRuns: []
|
|
1664
1672
|
};
|
|
1665
|
-
const
|
|
1673
|
+
const msgIdRef = useRef6(0);
|
|
1674
|
+
const [state, rawDispatch] = useReducer(appReducer, initialState);
|
|
1675
|
+
const dispatch = useCallback7((action) => {
|
|
1676
|
+
if (action.type === "ADD_MESSAGE") {
|
|
1677
|
+
msgIdRef.current += 1;
|
|
1678
|
+
rawDispatch({ type: "ADD_MESSAGE", message: { ...action.message, id: msgIdRef.current } });
|
|
1679
|
+
} else {
|
|
1680
|
+
rawDispatch(action);
|
|
1681
|
+
}
|
|
1682
|
+
}, []);
|
|
1666
1683
|
useEffect3(() => {
|
|
1667
1684
|
markSessionStart();
|
|
1668
1685
|
}, []);
|
|
@@ -1783,7 +1800,7 @@ function AppProvider({ cwd, skipOnboarding, children }) {
|
|
|
1783
1800
|
execution.handleExecutionBack();
|
|
1784
1801
|
}
|
|
1785
1802
|
}, [state.previousView, state.workflow, db, execution.handleExecutionBack]);
|
|
1786
|
-
const uiState =
|
|
1803
|
+
const uiState = useMemo(() => ({
|
|
1787
1804
|
view: state.view,
|
|
1788
1805
|
messages: state.messages,
|
|
1789
1806
|
workflow: state.workflow,
|
|
@@ -1803,7 +1820,7 @@ function AppProvider({ cwd, skipOnboarding, children }) {
|
|
|
1803
1820
|
detailRuns: state.detailRuns,
|
|
1804
1821
|
detailStepRuns: state.detailStepRuns
|
|
1805
1822
|
}), [state, daemonStatus, execution.isExecuting, config, cwd, footerExtra, footerHints, planner.isConversing, themeVersion]);
|
|
1806
|
-
const uiActions =
|
|
1823
|
+
const uiActions = useMemo(() => ({
|
|
1807
1824
|
handleChatSubmit,
|
|
1808
1825
|
handleCancelGeneration: planner.handleCancelGeneration,
|
|
1809
1826
|
handleConfirm: execution.handleConfirm,
|
|
@@ -1824,7 +1841,7 @@ function AppProvider({ cwd, skipOnboarding, children }) {
|
|
|
1824
1841
|
}
|
|
1825
1842
|
|
|
1826
1843
|
// src/tui/app-layout.tsx
|
|
1827
|
-
import { useMemo as
|
|
1844
|
+
import { useMemo as useMemo5 } from "react";
|
|
1828
1845
|
import { Box as Box21, Static, useStdout as useStdout5 } from "ink";
|
|
1829
1846
|
|
|
1830
1847
|
// src/tui/banner.tsx
|
|
@@ -1890,18 +1907,18 @@ function lerpGradient(stops, t) {
|
|
|
1890
1907
|
import { Box as Box15 } from "ink";
|
|
1891
1908
|
|
|
1892
1909
|
// src/tui/main-content.tsx
|
|
1893
|
-
import { useState as useState6, useMemo as
|
|
1910
|
+
import { useState as useState6, useMemo as useMemo2, useCallback as useCallback9 } from "react";
|
|
1894
1911
|
import { Box as Box13, Text as Text13, useStdout as useStdout2 } from "ink";
|
|
1895
1912
|
|
|
1896
1913
|
// src/tui/thinking-indicator.tsx
|
|
1897
|
-
import { useState as useState5, useEffect as useEffect4, useCallback as useCallback8, useRef as
|
|
1914
|
+
import { useState as useState5, useEffect as useEffect4, useCallback as useCallback8, useRef as useRef7, memo as memo2 } from "react";
|
|
1898
1915
|
import { Box as Box4, Text as Text4 } from "ink";
|
|
1899
1916
|
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1900
1917
|
var DOTS = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
1901
1918
|
var ThinkingIndicator = memo2(function ThinkingIndicator2({ onCancel }) {
|
|
1902
1919
|
const [elapsed, setElapsed] = useState5(0);
|
|
1903
1920
|
const [frame, setFrame] = useState5(0);
|
|
1904
|
-
const startRef =
|
|
1921
|
+
const startRef = useRef7(Date.now());
|
|
1905
1922
|
useEffect4(() => {
|
|
1906
1923
|
const timer = setInterval(() => {
|
|
1907
1924
|
setElapsed(Math.floor((Date.now() - startRef.current) / 1e3));
|
|
@@ -1917,8 +1934,7 @@ var ThinkingIndicator = memo2(function ThinkingIndicator2({ onCancel }) {
|
|
|
1917
1934
|
return false;
|
|
1918
1935
|
}, [onCancel]));
|
|
1919
1936
|
const gradient = theme.ui.gradient;
|
|
1920
|
-
const
|
|
1921
|
-
const gradientIdx = Math.floor(cyclePos * gradient.length) % gradient.length;
|
|
1937
|
+
const gradientIdx = frame % gradient.length;
|
|
1922
1938
|
const spinnerColor = gradient[gradientIdx] ?? theme.text.accent;
|
|
1923
1939
|
const cancelHint = onCancel ? " (esc to cancel)" : "";
|
|
1924
1940
|
return /* @__PURE__ */ jsxs4(Box4, { paddingX: 1, children: [
|
|
@@ -2057,12 +2073,6 @@ function MainContent() {
|
|
|
2057
2073
|
const { stdout } = useStdout2();
|
|
2058
2074
|
const rows = stdout?.rows ?? 24;
|
|
2059
2075
|
const [scrollOffset, setScrollOffset] = useState6(0);
|
|
2060
|
-
const prevMessageCountRef = useRef6(messages.length);
|
|
2061
|
-
useEffect5(() => {
|
|
2062
|
-
if (messages.length > prevMessageCountRef.current && scrollOffset === 0) {
|
|
2063
|
-
}
|
|
2064
|
-
prevMessageCountRef.current = messages.length;
|
|
2065
|
-
}, [messages.length, scrollOffset]);
|
|
2066
2076
|
const pageSize = Math.max(1, Math.floor(rows / 2));
|
|
2067
2077
|
useKeypress("chat-scroll", KeyPriority.Normal, useCallback9((input, key) => {
|
|
2068
2078
|
if (keyBindings.scrollUp(input, key)) {
|
|
@@ -2075,7 +2085,7 @@ function MainContent() {
|
|
|
2075
2085
|
}
|
|
2076
2086
|
return false;
|
|
2077
2087
|
}, [pageSize, messages.length]));
|
|
2078
|
-
const visibleMessages =
|
|
2088
|
+
const visibleMessages = useMemo2(() => {
|
|
2079
2089
|
if (scrollOffset === 0) return messages;
|
|
2080
2090
|
const end = messages.length - scrollOffset;
|
|
2081
2091
|
return messages.slice(0, Math.max(0, end));
|
|
@@ -2090,7 +2100,7 @@ function MainContent() {
|
|
|
2090
2100
|
" (Ctrl+P/Ctrl+N)"
|
|
2091
2101
|
] }) }),
|
|
2092
2102
|
/* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", flexGrow: 1, marginTop: hiddenAbove > 0 ? 0 : 1, children: [
|
|
2093
|
-
visibleMessages.map((msg
|
|
2103
|
+
visibleMessages.map((msg) => /* @__PURE__ */ jsx16(Box13, { marginBottom: 1, flexDirection: "column", children: /* @__PURE__ */ jsx16(MessageDisplay, { message: msg }) }, msg.id)),
|
|
2094
2104
|
streamingText && /* @__PURE__ */ jsxs12(Box13, { marginBottom: 1, paddingX: 1, children: [
|
|
2095
2105
|
/* @__PURE__ */ jsx16(Box13, { width: 2, children: /* @__PURE__ */ jsx16(Text13, { color: theme.text.accent, children: "\u2726 " }) }),
|
|
2096
2106
|
/* @__PURE__ */ jsx16(Box13, { flexShrink: 1, children: /* @__PURE__ */ jsx16(Text13, { color: theme.text.primary, children: streamingText }) })
|
|
@@ -2101,11 +2111,11 @@ function MainContent() {
|
|
|
2101
2111
|
}
|
|
2102
2112
|
|
|
2103
2113
|
// src/tui/composer.tsx
|
|
2104
|
-
import { useState as useState7, useMemo as
|
|
2114
|
+
import { useState as useState7, useMemo as useMemo3, useCallback as useCallback12 } from "react";
|
|
2105
2115
|
import { Box as Box14, Text as Text15, useStdout as useStdout3 } from "ink";
|
|
2106
2116
|
|
|
2107
2117
|
// src/tui/resettable-input.tsx
|
|
2108
|
-
import { useReducer as useReducer2, useEffect as
|
|
2118
|
+
import { useReducer as useReducer2, useEffect as useEffect5, useRef as useRef8, useCallback as useCallback10 } from "react";
|
|
2109
2119
|
import { Text as Text14 } from "ink";
|
|
2110
2120
|
import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2111
2121
|
function inputReducer(state, action) {
|
|
@@ -2131,13 +2141,13 @@ function inputReducer(state, action) {
|
|
|
2131
2141
|
}
|
|
2132
2142
|
function ResettableInput({ placeholder, onSubmit, onChange, isDisabled, onUpArrow, onDownArrow }) {
|
|
2133
2143
|
const [state, dispatch] = useReducer2(inputReducer, { value: "", prevValue: "", cursor: 0 });
|
|
2134
|
-
const submitRef =
|
|
2135
|
-
|
|
2144
|
+
const submitRef = useRef8(null);
|
|
2145
|
+
useEffect5(() => {
|
|
2136
2146
|
if (state.value !== state.prevValue) {
|
|
2137
2147
|
onChange?.(state.value);
|
|
2138
2148
|
}
|
|
2139
2149
|
}, [state.value, state.prevValue, onChange]);
|
|
2140
|
-
|
|
2150
|
+
useEffect5(() => {
|
|
2141
2151
|
if (submitRef.current !== null) {
|
|
2142
2152
|
const value = submitRef.current;
|
|
2143
2153
|
submitRef.current = null;
|
|
@@ -2145,7 +2155,7 @@ function ResettableInput({ placeholder, onSubmit, onChange, isDisabled, onUpArro
|
|
|
2145
2155
|
}
|
|
2146
2156
|
});
|
|
2147
2157
|
useKeypress("resettable-input", KeyPriority.Normal, useCallback10((input, key) => {
|
|
2148
|
-
if (key.ctrl && input === "c" || key.tab || key.shift && key.tab) return false;
|
|
2158
|
+
if (key.ctrl && input === "c" || key.tab || key.shift && key.tab || key.escape) return false;
|
|
2149
2159
|
if (key.upArrow) {
|
|
2150
2160
|
if (onUpArrow) {
|
|
2151
2161
|
const entry = onUpArrow(state.value);
|
|
@@ -2197,11 +2207,11 @@ function ResettableInput({ placeholder, onSubmit, onChange, isDisabled, onUpArro
|
|
|
2197
2207
|
}
|
|
2198
2208
|
|
|
2199
2209
|
// src/tui/use-input-history.ts
|
|
2200
|
-
import { useRef as
|
|
2210
|
+
import { useRef as useRef9, useCallback as useCallback11 } from "react";
|
|
2201
2211
|
function useInputHistory() {
|
|
2202
|
-
const historyRef =
|
|
2203
|
-
const indexRef =
|
|
2204
|
-
const draftRef =
|
|
2212
|
+
const historyRef = useRef9([]);
|
|
2213
|
+
const indexRef = useRef9(-1);
|
|
2214
|
+
const draftRef = useRef9("");
|
|
2205
2215
|
const up = useCallback11((currentValue) => {
|
|
2206
2216
|
const history = historyRef.current;
|
|
2207
2217
|
if (history.length === 0) return void 0;
|
|
@@ -2268,8 +2278,8 @@ function Composer() {
|
|
|
2268
2278
|
const cols = stdout?.columns ?? 80;
|
|
2269
2279
|
const history = useInputHistory();
|
|
2270
2280
|
const [currentInput, setCurrentInput] = useState7("");
|
|
2271
|
-
const allCommands =
|
|
2272
|
-
const matchingCommands =
|
|
2281
|
+
const allCommands = useMemo3(() => getCommands(), []);
|
|
2282
|
+
const matchingCommands = useMemo3(() => {
|
|
2273
2283
|
if (!currentInput.startsWith("/")) return [];
|
|
2274
2284
|
const prefix = currentInput.toLowerCase();
|
|
2275
2285
|
return allCommands.filter((c) => {
|
|
@@ -2278,6 +2288,18 @@ function Composer() {
|
|
|
2278
2288
|
});
|
|
2279
2289
|
}, [currentInput, allCommands]);
|
|
2280
2290
|
const showCommandHints = currentInput.startsWith("/") && matchingCommands.length > 0 && currentInput !== "/" + matchingCommands[0]?.name;
|
|
2291
|
+
const handleInputChange = useCallback12((value) => {
|
|
2292
|
+
setCurrentInput(value);
|
|
2293
|
+
history.resetBrowsing();
|
|
2294
|
+
}, [history]);
|
|
2295
|
+
const handleInputSubmit = useCallback12((value) => {
|
|
2296
|
+
const trimmed = value.trim();
|
|
2297
|
+
if (trimmed) {
|
|
2298
|
+
history.push(trimmed);
|
|
2299
|
+
setCurrentInput("");
|
|
2300
|
+
handleChatSubmit(trimmed);
|
|
2301
|
+
}
|
|
2302
|
+
}, [history, handleChatSubmit]);
|
|
2281
2303
|
const mode = modeLabel({ isExecuting, isGenerating, isConversing });
|
|
2282
2304
|
const daemon = daemonLabel(daemonStatus);
|
|
2283
2305
|
return /* @__PURE__ */ jsxs14(Fragment3, { children: [
|
|
@@ -2320,18 +2342,8 @@ function Composer() {
|
|
|
2320
2342
|
ResettableInput,
|
|
2321
2343
|
{
|
|
2322
2344
|
placeholder: "Describe a workflow or type /help",
|
|
2323
|
-
onChange:
|
|
2324
|
-
|
|
2325
|
-
history.resetBrowsing();
|
|
2326
|
-
},
|
|
2327
|
-
onSubmit: (value) => {
|
|
2328
|
-
const trimmed = value.trim();
|
|
2329
|
-
if (trimmed) {
|
|
2330
|
-
history.push(trimmed);
|
|
2331
|
-
setCurrentInput("");
|
|
2332
|
-
handleChatSubmit(trimmed);
|
|
2333
|
-
}
|
|
2334
|
-
},
|
|
2345
|
+
onChange: handleInputChange,
|
|
2346
|
+
onSubmit: handleInputSubmit,
|
|
2335
2347
|
onUpArrow: history.up,
|
|
2336
2348
|
onDownArrow: history.down,
|
|
2337
2349
|
isDisabled: isGenerating
|
|
@@ -2353,11 +2365,11 @@ function Chat() {
|
|
|
2353
2365
|
}
|
|
2354
2366
|
|
|
2355
2367
|
// src/tui/plan-view.tsx
|
|
2356
|
-
import { useCallback as
|
|
2368
|
+
import { useCallback as useCallback13, memo as memo10 } from "react";
|
|
2357
2369
|
import { Box as Box16, Text as Text16 } from "ink";
|
|
2358
2370
|
import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2359
2371
|
function PlanView({ workflow, onConfirm, onModify, onCancel }) {
|
|
2360
|
-
useKeypress("plan-view-actions", KeyPriority.Normal,
|
|
2372
|
+
useKeypress("plan-view-actions", KeyPriority.Normal, useCallback13((input, key) => {
|
|
2361
2373
|
if (keyBindings.confirmPlan(input, key)) {
|
|
2362
2374
|
onConfirm();
|
|
2363
2375
|
return true;
|
|
@@ -2420,13 +2432,90 @@ var StepLine = memo10(function StepLine2({ step, index }) {
|
|
|
2420
2432
|
});
|
|
2421
2433
|
|
|
2422
2434
|
// src/tui/execution-view.tsx
|
|
2423
|
-
import { useCallback as
|
|
2435
|
+
import { useCallback as useCallback14 } from "react";
|
|
2424
2436
|
import { Box as Box17, Text as Text17 } from "ink";
|
|
2437
|
+
|
|
2438
|
+
// src/tui/format-utils.ts
|
|
2439
|
+
function stepStatusIcon(status) {
|
|
2440
|
+
switch (status) {
|
|
2441
|
+
case "succeeded":
|
|
2442
|
+
return "\u2713";
|
|
2443
|
+
case "running":
|
|
2444
|
+
return "\u22B7";
|
|
2445
|
+
case "failed":
|
|
2446
|
+
return "\u2717";
|
|
2447
|
+
case "skipped":
|
|
2448
|
+
return "\u25CB";
|
|
2449
|
+
default:
|
|
2450
|
+
return "\u25CB";
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2453
|
+
function stepStatusColor(status) {
|
|
2454
|
+
switch (status) {
|
|
2455
|
+
case "succeeded":
|
|
2456
|
+
return theme.status.success;
|
|
2457
|
+
case "running":
|
|
2458
|
+
return theme.status.warning;
|
|
2459
|
+
case "failed":
|
|
2460
|
+
return theme.status.error;
|
|
2461
|
+
case "skipped":
|
|
2462
|
+
return theme.status.muted;
|
|
2463
|
+
default:
|
|
2464
|
+
return theme.status.muted;
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
function phaseColor2(phase) {
|
|
2468
|
+
switch (phase) {
|
|
2469
|
+
case "executing":
|
|
2470
|
+
return theme.status.warning;
|
|
2471
|
+
case "active":
|
|
2472
|
+
return theme.status.success;
|
|
2473
|
+
case "completed":
|
|
2474
|
+
return theme.status.success;
|
|
2475
|
+
case "failed":
|
|
2476
|
+
return theme.status.error;
|
|
2477
|
+
case "paused":
|
|
2478
|
+
return theme.status.muted;
|
|
2479
|
+
default:
|
|
2480
|
+
return theme.text.primary;
|
|
2481
|
+
}
|
|
2482
|
+
}
|
|
2483
|
+
function runStatusColor(status) {
|
|
2484
|
+
switch (status) {
|
|
2485
|
+
case "completed":
|
|
2486
|
+
return theme.status.success;
|
|
2487
|
+
case "running":
|
|
2488
|
+
return theme.status.warning;
|
|
2489
|
+
case "failed":
|
|
2490
|
+
return theme.status.error;
|
|
2491
|
+
default:
|
|
2492
|
+
return theme.text.primary;
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
function formatDuration2(ms) {
|
|
2496
|
+
if (ms < 1e3) return `${ms}ms`;
|
|
2497
|
+
if (ms < 6e4) return `${Math.round(ms / 1e3)}s`;
|
|
2498
|
+
return `${Math.round(ms / 6e4)}m`;
|
|
2499
|
+
}
|
|
2500
|
+
function formatTrigger(trigger) {
|
|
2501
|
+
switch (trigger.type) {
|
|
2502
|
+
case "poll":
|
|
2503
|
+
return `poll every ${trigger.interval_seconds}s (${trigger.diff_mode})`;
|
|
2504
|
+
case "cron":
|
|
2505
|
+
return `cron: ${trigger.expression}${trigger.timezone ? ` (${trigger.timezone})` : ""}`;
|
|
2506
|
+
case "manual":
|
|
2507
|
+
return "manual";
|
|
2508
|
+
default:
|
|
2509
|
+
return trigger.type;
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
|
|
2513
|
+
// src/tui/execution-view.tsx
|
|
2425
2514
|
import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2426
2515
|
function ExecutionView({ workflow, stepProgress, output, onBack, onAbort }) {
|
|
2427
2516
|
const { isExecuting } = useUIState();
|
|
2428
2517
|
const isRunning = Array.from(stepProgress.values()).some((s) => s.status === "running");
|
|
2429
|
-
useKeypress("execution-view-actions", KeyPriority.Normal,
|
|
2518
|
+
useKeypress("execution-view-actions", KeyPriority.Normal, useCallback14((input, key) => {
|
|
2430
2519
|
if (isExecuting && onAbort && keyBindings.abortExec(input, key)) {
|
|
2431
2520
|
onAbort();
|
|
2432
2521
|
return true;
|
|
@@ -2454,9 +2543,9 @@ function ExecutionView({ workflow, stepProgress, output, onBack, onAbort }) {
|
|
|
2454
2543
|
workflow.steps.map((step, i) => {
|
|
2455
2544
|
const progress = stepProgress.get(step.id);
|
|
2456
2545
|
const status = progress?.status ?? "pending";
|
|
2457
|
-
const icon =
|
|
2546
|
+
const icon = stepStatusIcon(status);
|
|
2458
2547
|
const durationText = progress?.duration ? ` (${formatDuration2(progress.duration)})` : "";
|
|
2459
|
-
return /* @__PURE__ */ jsx21(Box17, { children: /* @__PURE__ */ jsxs17(Text17, { color:
|
|
2548
|
+
return /* @__PURE__ */ jsx21(Box17, { children: /* @__PURE__ */ jsxs17(Text17, { color: stepStatusColor(status), children: [
|
|
2460
2549
|
icon,
|
|
2461
2550
|
" ",
|
|
2462
2551
|
i + 1,
|
|
@@ -2473,52 +2562,20 @@ function ExecutionView({ workflow, stepProgress, output, onBack, onAbort }) {
|
|
|
2473
2562
|
/* @__PURE__ */ jsx21(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx21(Text17, { color: theme.ui.comment, children: isExecuting ? "Press [X] to cancel" : "Press Enter, Q, or Esc to return to chat" }) })
|
|
2474
2563
|
] });
|
|
2475
2564
|
}
|
|
2476
|
-
function statusIcon(status) {
|
|
2477
|
-
switch (status) {
|
|
2478
|
-
case "succeeded":
|
|
2479
|
-
return "\u2713";
|
|
2480
|
-
case "running":
|
|
2481
|
-
return "\u22B7";
|
|
2482
|
-
case "failed":
|
|
2483
|
-
return "\u2717";
|
|
2484
|
-
case "skipped":
|
|
2485
|
-
return "\u25CB";
|
|
2486
|
-
default:
|
|
2487
|
-
return "\u25CB";
|
|
2488
|
-
}
|
|
2489
|
-
}
|
|
2490
|
-
function statusColor(status) {
|
|
2491
|
-
switch (status) {
|
|
2492
|
-
case "succeeded":
|
|
2493
|
-
return theme.status.success;
|
|
2494
|
-
case "running":
|
|
2495
|
-
return theme.status.warning;
|
|
2496
|
-
case "failed":
|
|
2497
|
-
return theme.status.error;
|
|
2498
|
-
case "skipped":
|
|
2499
|
-
return theme.status.muted;
|
|
2500
|
-
default:
|
|
2501
|
-
return theme.status.muted;
|
|
2502
|
-
}
|
|
2503
|
-
}
|
|
2504
|
-
function formatDuration2(ms) {
|
|
2505
|
-
if (ms < 1e3) return `${ms}ms`;
|
|
2506
|
-
return `${Math.round(ms / 1e3)}s`;
|
|
2507
|
-
}
|
|
2508
2565
|
|
|
2509
2566
|
// src/tui/workflow-detail-view.tsx
|
|
2510
|
-
import { useState as useState8, useCallback as
|
|
2567
|
+
import { useState as useState8, useCallback as useCallback15, useEffect as useEffect6 } from "react";
|
|
2511
2568
|
import { Box as Box18, Text as Text18 } from "ink";
|
|
2512
2569
|
import { Fragment as Fragment4, jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2513
2570
|
function WorkflowDetailView({ workflow, runs, latestStepRuns, onBack, onSelectRun, onStop }) {
|
|
2514
2571
|
const [selectedRunIndex, setSelectedRunIndex] = useState8(0);
|
|
2515
2572
|
const displayRuns = runs.slice(0, 5);
|
|
2516
|
-
|
|
2573
|
+
useEffect6(() => {
|
|
2517
2574
|
if (selectedRunIndex >= displayRuns.length && displayRuns.length > 0) {
|
|
2518
2575
|
setSelectedRunIndex(displayRuns.length - 1);
|
|
2519
2576
|
}
|
|
2520
2577
|
}, [displayRuns.length, selectedRunIndex]);
|
|
2521
|
-
useKeypress("detail-view-actions", KeyPriority.Normal,
|
|
2578
|
+
useKeypress("detail-view-actions", KeyPriority.Normal, useCallback15((input, key) => {
|
|
2522
2579
|
if (keyBindings.escape(input, key) || keyBindings.quit(input, key)) {
|
|
2523
2580
|
onBack();
|
|
2524
2581
|
return true;
|
|
@@ -2580,8 +2637,8 @@ function WorkflowDetailView({ workflow, runs, latestStepRuns, onBack, onSelectRu
|
|
|
2580
2637
|
workflow.steps.map((step, i) => {
|
|
2581
2638
|
const deps = step.depends_on.length > 0 ? ` \u2192 depends on: ${step.depends_on.join(", ")}` : "";
|
|
2582
2639
|
const stepRun = latestStepRuns.find((sr) => sr.step_id === step.id);
|
|
2583
|
-
const icon = stepRun ?
|
|
2584
|
-
const iconColor = stepRun ?
|
|
2640
|
+
const icon = stepRun ? stepStatusIcon(stepRun.status) : "\u25CB";
|
|
2641
|
+
const iconColor = stepRun ? stepStatusColor(stepRun.status) : theme.status.muted;
|
|
2585
2642
|
return /* @__PURE__ */ jsxs18(Box18, { children: [
|
|
2586
2643
|
/* @__PURE__ */ jsxs18(Text18, { color: iconColor, children: [
|
|
2587
2644
|
icon,
|
|
@@ -2607,7 +2664,7 @@ function WorkflowDetailView({ workflow, runs, latestStepRuns, onBack, onSelectRu
|
|
|
2607
2664
|
displayRuns.map((run, i) => /* @__PURE__ */ jsx22(Box18, { children: /* @__PURE__ */ jsxs18(Text18, { inverse: i === selectedRunIndex, children: [
|
|
2608
2665
|
/* @__PURE__ */ jsx22(Text18, { color: runStatusColor(run.status), children: run.status.padEnd(14) }),
|
|
2609
2666
|
/* @__PURE__ */ jsx22(Text18, { children: run.started_at.slice(0, 22).padEnd(24) }),
|
|
2610
|
-
/* @__PURE__ */ jsx22(Text18, { children: (run.duration_ms != null ?
|
|
2667
|
+
/* @__PURE__ */ jsx22(Text18, { children: (run.duration_ms != null ? formatDuration2(run.duration_ms) : "\u2014").padEnd(12) }),
|
|
2611
2668
|
/* @__PURE__ */ jsx22(Text18, { color: theme.status.error, children: run.error ? run.error.slice(0, 40) : "" })
|
|
2612
2669
|
] }) }, run.id))
|
|
2613
2670
|
] })
|
|
@@ -2619,80 +2676,9 @@ function WorkflowDetailView({ workflow, runs, latestStepRuns, onBack, onSelectRu
|
|
|
2619
2676
|
] }) })
|
|
2620
2677
|
] });
|
|
2621
2678
|
}
|
|
2622
|
-
function phaseColor2(phase) {
|
|
2623
|
-
switch (phase) {
|
|
2624
|
-
case "executing":
|
|
2625
|
-
return theme.status.warning;
|
|
2626
|
-
case "active":
|
|
2627
|
-
return theme.status.success;
|
|
2628
|
-
case "completed":
|
|
2629
|
-
return theme.status.success;
|
|
2630
|
-
case "failed":
|
|
2631
|
-
return theme.status.error;
|
|
2632
|
-
case "paused":
|
|
2633
|
-
return theme.status.muted;
|
|
2634
|
-
default:
|
|
2635
|
-
return theme.text.primary;
|
|
2636
|
-
}
|
|
2637
|
-
}
|
|
2638
|
-
function runStatusColor(status) {
|
|
2639
|
-
switch (status) {
|
|
2640
|
-
case "completed":
|
|
2641
|
-
return theme.status.success;
|
|
2642
|
-
case "running":
|
|
2643
|
-
return theme.status.warning;
|
|
2644
|
-
case "failed":
|
|
2645
|
-
return theme.status.error;
|
|
2646
|
-
default:
|
|
2647
|
-
return theme.text.primary;
|
|
2648
|
-
}
|
|
2649
|
-
}
|
|
2650
|
-
function statusIcon2(status) {
|
|
2651
|
-
switch (status) {
|
|
2652
|
-
case "succeeded":
|
|
2653
|
-
return "\u2713";
|
|
2654
|
-
case "running":
|
|
2655
|
-
return "\u22B7";
|
|
2656
|
-
case "failed":
|
|
2657
|
-
return "\u2717";
|
|
2658
|
-
case "skipped":
|
|
2659
|
-
return "\u25CB";
|
|
2660
|
-
default:
|
|
2661
|
-
return "\u25CB";
|
|
2662
|
-
}
|
|
2663
|
-
}
|
|
2664
|
-
function statusColor2(status) {
|
|
2665
|
-
switch (status) {
|
|
2666
|
-
case "succeeded":
|
|
2667
|
-
return theme.status.success;
|
|
2668
|
-
case "running":
|
|
2669
|
-
return theme.status.warning;
|
|
2670
|
-
case "failed":
|
|
2671
|
-
return theme.status.error;
|
|
2672
|
-
case "skipped":
|
|
2673
|
-
return theme.status.muted;
|
|
2674
|
-
default:
|
|
2675
|
-
return theme.status.muted;
|
|
2676
|
-
}
|
|
2677
|
-
}
|
|
2678
|
-
function formatTrigger(trigger) {
|
|
2679
|
-
switch (trigger.type) {
|
|
2680
|
-
case "poll":
|
|
2681
|
-
return `poll every ${trigger.interval_seconds}s (${trigger.diff_mode})`;
|
|
2682
|
-
case "cron":
|
|
2683
|
-
return `cron: ${trigger.expression}${trigger.timezone ? ` (${trigger.timezone})` : ""}`;
|
|
2684
|
-
case "manual":
|
|
2685
|
-
return "manual";
|
|
2686
|
-
}
|
|
2687
|
-
}
|
|
2688
|
-
function formatDuration3(ms) {
|
|
2689
|
-
if (ms < 1e3) return `${ms}ms`;
|
|
2690
|
-
if (ms < 6e4) return `${Math.round(ms / 1e3)}s`;
|
|
2691
|
-
return `${Math.round(ms / 6e4)}m`;
|
|
2692
|
-
}
|
|
2693
2679
|
|
|
2694
2680
|
// src/tui/onboarding.tsx
|
|
2695
|
-
import { useState as useState9, useCallback as
|
|
2681
|
+
import { useState as useState9, useCallback as useCallback16, useMemo as useMemo4, useRef as useRef10, useEffect as useEffect7 } from "react";
|
|
2696
2682
|
import { Box as Box19, Text as Text19, useStdout as useStdout4 } from "ink";
|
|
2697
2683
|
import { TextInput, PasswordInput, ConfirmInput, Spinner, StatusMessage } from "@inkjs/ui";
|
|
2698
2684
|
import { jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
@@ -2700,17 +2686,23 @@ function maskKey(key) {
|
|
|
2700
2686
|
if (key.length <= 8) return "****";
|
|
2701
2687
|
return key.slice(0, 4) + "****" + key.slice(-4);
|
|
2702
2688
|
}
|
|
2689
|
+
function StepLayout({ children, input }) {
|
|
2690
|
+
return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", flexGrow: 1, children: [
|
|
2691
|
+
/* @__PURE__ */ jsx23(Box19, { flexDirection: "column", flexGrow: 1, children }),
|
|
2692
|
+
/* @__PURE__ */ jsx23(Box19, { marginTop: 1, children: input })
|
|
2693
|
+
] });
|
|
2694
|
+
}
|
|
2703
2695
|
function Onboarding({ onComplete, onCancel, issues }) {
|
|
2704
2696
|
const { stdout } = useStdout4();
|
|
2705
2697
|
const cols = stdout?.columns ?? 80;
|
|
2706
|
-
const existing =
|
|
2707
|
-
const completeTimerRef =
|
|
2708
|
-
|
|
2698
|
+
const existing = useMemo4(() => loadExistingConfig(), []);
|
|
2699
|
+
const completeTimerRef = useRef10(null);
|
|
2700
|
+
useEffect7(() => {
|
|
2709
2701
|
return () => {
|
|
2710
2702
|
if (completeTimerRef.current) clearTimeout(completeTimerRef.current);
|
|
2711
2703
|
};
|
|
2712
2704
|
}, []);
|
|
2713
|
-
const initialStep =
|
|
2705
|
+
const initialStep = useMemo4(() => {
|
|
2714
2706
|
if (!issues || issues.length === 0) return "welcome";
|
|
2715
2707
|
const errorFields = new Set(issues.filter((i) => i.severity === "error").map((i) => i.field));
|
|
2716
2708
|
if (errorFields.size === 1 && errorFields.has("claude.api_key")) {
|
|
@@ -2727,8 +2719,8 @@ function Onboarding({ onComplete, onCancel, issues }) {
|
|
|
2727
2719
|
telegramToken: existing.telegramToken ?? "",
|
|
2728
2720
|
whatsappEnabled: existing.whatsappEnabled ?? false
|
|
2729
2721
|
});
|
|
2730
|
-
const env = checkEnvironment();
|
|
2731
|
-
useKeypress("onboarding-cancel", KeyPriority.Normal,
|
|
2722
|
+
const env = useMemo4(() => checkEnvironment(), []);
|
|
2723
|
+
useKeypress("onboarding-cancel", KeyPriority.Normal, useCallback16((input, key) => {
|
|
2732
2724
|
if (onCancel && keyBindings.escape(input, key)) {
|
|
2733
2725
|
if (completeTimerRef.current) clearTimeout(completeTimerRef.current);
|
|
2734
2726
|
onCancel();
|
|
@@ -2736,54 +2728,37 @@ function Onboarding({ onComplete, onCancel, issues }) {
|
|
|
2736
2728
|
}
|
|
2737
2729
|
return false;
|
|
2738
2730
|
}, [onCancel]));
|
|
2739
|
-
const gotoApiKey =
|
|
2731
|
+
const gotoApiKey = useCallback16(() => {
|
|
2740
2732
|
setStep(existing.apiKey ? "api_key_existing" : "api_key");
|
|
2741
2733
|
}, [existing]);
|
|
2742
|
-
const gotoBaseUrl =
|
|
2734
|
+
const gotoBaseUrl = useCallback16(() => {
|
|
2743
2735
|
if (!isDev) return;
|
|
2744
2736
|
setStep(existing.baseUrl ? "base_url_existing" : "base_url");
|
|
2745
2737
|
}, [existing]);
|
|
2746
|
-
const
|
|
2738
|
+
const gotoTelegram = useCallback16(() => {
|
|
2739
|
+
setStep(existing.telegramEnabled !== void 0 ? "telegram_existing" : "telegram");
|
|
2740
|
+
}, [existing]);
|
|
2741
|
+
const gotoContainer = useCallback16(() => {
|
|
2747
2742
|
if (!(env.docker && env.dockerRunning)) {
|
|
2748
2743
|
gotoTelegram();
|
|
2749
2744
|
return;
|
|
2750
2745
|
}
|
|
2751
2746
|
setStep(existing.containerEnabled !== void 0 ? "container_existing" : "container");
|
|
2752
|
-
}, [env, existing]);
|
|
2753
|
-
const
|
|
2754
|
-
setStep(existing.telegramEnabled !== void 0 ? "telegram_existing" : "telegram");
|
|
2755
|
-
}, [existing]);
|
|
2756
|
-
const gotoTelegramToken = useCallback15(() => {
|
|
2747
|
+
}, [env, existing, gotoTelegram]);
|
|
2748
|
+
const gotoTelegramToken = useCallback16(() => {
|
|
2757
2749
|
setStep(existing.telegramToken ? "telegram_token_existing" : "telegram_token");
|
|
2758
2750
|
}, [existing]);
|
|
2759
|
-
const gotoWhatsApp =
|
|
2751
|
+
const gotoWhatsApp = useCallback16(() => {
|
|
2760
2752
|
setStep(existing.whatsappEnabled !== void 0 ? "whatsapp_existing" : "whatsapp");
|
|
2761
2753
|
}, [existing]);
|
|
2762
|
-
const afterValidation =
|
|
2754
|
+
const afterValidation = useCallback16(() => {
|
|
2763
2755
|
if (env.docker && env.dockerRunning) {
|
|
2764
2756
|
gotoContainer();
|
|
2765
2757
|
} else {
|
|
2766
2758
|
gotoTelegram();
|
|
2767
2759
|
}
|
|
2768
2760
|
}, [env, gotoContainer, gotoTelegram]);
|
|
2769
|
-
const
|
|
2770
|
-
const key = value.trim();
|
|
2771
|
-
if (!key) return;
|
|
2772
|
-
setState((s) => ({ ...s, apiKey: key }));
|
|
2773
|
-
if (isDev) {
|
|
2774
|
-
gotoBaseUrl();
|
|
2775
|
-
} else {
|
|
2776
|
-
setStep("validating");
|
|
2777
|
-
doValidation(key, "");
|
|
2778
|
-
}
|
|
2779
|
-
}, [gotoBaseUrl]);
|
|
2780
|
-
const handleBaseUrlSubmit = useCallback15((value) => {
|
|
2781
|
-
const url = value.trim();
|
|
2782
|
-
setState((s) => ({ ...s, baseUrl: url }));
|
|
2783
|
-
setStep("validating");
|
|
2784
|
-
doValidation(state.apiKey, url);
|
|
2785
|
-
}, [state.apiKey]);
|
|
2786
|
-
const doValidation = useCallback15(async (apiKey, baseUrl) => {
|
|
2761
|
+
const doValidation = useCallback16(async (apiKey, baseUrl) => {
|
|
2787
2762
|
const prevKey = process.env["ANTHROPIC_API_KEY"];
|
|
2788
2763
|
const prevUrl = process.env["ANTHROPIC_BASE_URL"];
|
|
2789
2764
|
process.env["ANTHROPIC_API_KEY"] = apiKey;
|
|
@@ -2812,35 +2787,44 @@ function Onboarding({ onComplete, onCancel, issues }) {
|
|
|
2812
2787
|
else delete process.env["ANTHROPIC_BASE_URL"];
|
|
2813
2788
|
}
|
|
2814
2789
|
}, [afterValidation]);
|
|
2815
|
-
const
|
|
2790
|
+
const handleApiKeySubmit = useCallback16((value) => {
|
|
2791
|
+
const key = value.trim();
|
|
2792
|
+
if (!key) return;
|
|
2793
|
+
setState((s) => ({ ...s, apiKey: key }));
|
|
2794
|
+
if (isDev) {
|
|
2795
|
+
gotoBaseUrl();
|
|
2796
|
+
} else {
|
|
2797
|
+
setStep("validating");
|
|
2798
|
+
doValidation(key, "");
|
|
2799
|
+
}
|
|
2800
|
+
}, [gotoBaseUrl, doValidation]);
|
|
2801
|
+
const handleBaseUrlSubmit = useCallback16((value) => {
|
|
2802
|
+
const url = value.trim();
|
|
2803
|
+
setState((s) => ({ ...s, baseUrl: url }));
|
|
2804
|
+
setStep("validating");
|
|
2805
|
+
doValidation(state.apiKey, url);
|
|
2806
|
+
}, [state.apiKey, doValidation]);
|
|
2807
|
+
const handleContainerYes = useCallback16(() => {
|
|
2816
2808
|
setState((s) => ({ ...s, containerEnabled: true }));
|
|
2817
2809
|
gotoTelegram();
|
|
2818
2810
|
}, [gotoTelegram]);
|
|
2819
|
-
const handleContainerNo =
|
|
2811
|
+
const handleContainerNo = useCallback16(() => {
|
|
2820
2812
|
setState((s) => ({ ...s, containerEnabled: false }));
|
|
2821
2813
|
gotoTelegram();
|
|
2822
2814
|
}, [gotoTelegram]);
|
|
2823
|
-
const handleTelegramYes =
|
|
2815
|
+
const handleTelegramYes = useCallback16(() => {
|
|
2824
2816
|
setState((s) => ({ ...s, telegramEnabled: true }));
|
|
2825
2817
|
gotoTelegramToken();
|
|
2826
2818
|
}, [gotoTelegramToken]);
|
|
2827
|
-
const handleTelegramNo =
|
|
2819
|
+
const handleTelegramNo = useCallback16(() => {
|
|
2828
2820
|
setState((s) => ({ ...s, telegramEnabled: false }));
|
|
2829
2821
|
gotoWhatsApp();
|
|
2830
2822
|
}, [gotoWhatsApp]);
|
|
2831
|
-
const handleTelegramTokenSubmit =
|
|
2823
|
+
const handleTelegramTokenSubmit = useCallback16((value) => {
|
|
2832
2824
|
setState((s) => ({ ...s, telegramToken: value.trim() }));
|
|
2833
2825
|
gotoWhatsApp();
|
|
2834
2826
|
}, [gotoWhatsApp]);
|
|
2835
|
-
const
|
|
2836
|
-
const next = { ...state, whatsappEnabled: enabled };
|
|
2837
|
-
setState((s) => ({ ...s, whatsappEnabled: enabled }));
|
|
2838
|
-
setStep("saving");
|
|
2839
|
-
doSaveConfig(next);
|
|
2840
|
-
}, [state]);
|
|
2841
|
-
const handleWhatsAppYes = useCallback15(() => finishWithWhatsApp(true), [finishWithWhatsApp]);
|
|
2842
|
-
const handleWhatsAppNo = useCallback15(() => finishWithWhatsApp(false), [finishWithWhatsApp]);
|
|
2843
|
-
const doSaveConfig = useCallback15((finalState) => {
|
|
2827
|
+
const doSaveConfig = useCallback16((finalState) => {
|
|
2844
2828
|
if (isDev) {
|
|
2845
2829
|
writeEnvVar("ANTHROPIC_API_KEY", finalState.apiKey);
|
|
2846
2830
|
if (finalState.baseUrl) {
|
|
@@ -2871,10 +2855,14 @@ function Onboarding({ onComplete, onCancel, issues }) {
|
|
|
2871
2855
|
setStep("done");
|
|
2872
2856
|
completeTimerRef.current = setTimeout(() => onComplete(config), 1500);
|
|
2873
2857
|
}, [onComplete]);
|
|
2874
|
-
const
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2858
|
+
const finishWithWhatsApp = useCallback16((enabled) => {
|
|
2859
|
+
const next = { ...state, whatsappEnabled: enabled };
|
|
2860
|
+
setState((s) => ({ ...s, whatsappEnabled: enabled }));
|
|
2861
|
+
setStep("saving");
|
|
2862
|
+
doSaveConfig(next);
|
|
2863
|
+
}, [state, doSaveConfig]);
|
|
2864
|
+
const handleWhatsAppYes = useCallback16(() => finishWithWhatsApp(true), [finishWithWhatsApp]);
|
|
2865
|
+
const handleWhatsAppNo = useCallback16(() => finishWithWhatsApp(false), [finishWithWhatsApp]);
|
|
2878
2866
|
return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
|
|
2879
2867
|
onCancel && /* @__PURE__ */ jsx23(Box19, { justifyContent: "flex-end", children: /* @__PURE__ */ jsx23(Text19, { dimColor: true, children: "Press Esc to cancel" }) }),
|
|
2880
2868
|
step === "welcome" && /* @__PURE__ */ jsxs19(
|
|
@@ -3127,24 +3115,24 @@ function Onboarding({ onComplete, onCancel, issues }) {
|
|
|
3127
3115
|
}
|
|
3128
3116
|
|
|
3129
3117
|
// src/tui/status.tsx
|
|
3130
|
-
import { useState as useState10, useCallback as
|
|
3118
|
+
import { useState as useState10, useCallback as useCallback17, useEffect as useEffect8 } from "react";
|
|
3131
3119
|
import { Box as Box20, Text as Text20 } from "ink";
|
|
3132
3120
|
import { Fragment as Fragment5, jsx as jsx24, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
3133
3121
|
function Status({ workflows, onSelect, onBack, onStop, onDelete }) {
|
|
3134
3122
|
const [selectedIndex, setSelectedIndex] = useState10(0);
|
|
3135
3123
|
const [confirm, setConfirm] = useState10(null);
|
|
3136
3124
|
const [message, setMessage] = useState10(null);
|
|
3137
|
-
|
|
3125
|
+
useEffect8(() => {
|
|
3138
3126
|
if (selectedIndex >= workflows.length && workflows.length > 0) {
|
|
3139
3127
|
setSelectedIndex(workflows.length - 1);
|
|
3140
3128
|
}
|
|
3141
3129
|
}, [workflows.length, selectedIndex]);
|
|
3142
|
-
|
|
3130
|
+
useEffect8(() => {
|
|
3143
3131
|
if (!message) return;
|
|
3144
3132
|
const timer = setTimeout(() => setMessage(null), 3e3);
|
|
3145
3133
|
return () => clearTimeout(timer);
|
|
3146
3134
|
}, [message]);
|
|
3147
|
-
useKeypress("status-view", KeyPriority.Normal,
|
|
3135
|
+
useKeypress("status-view", KeyPriority.Normal, useCallback17((input, key) => {
|
|
3148
3136
|
if (confirm) {
|
|
3149
3137
|
if (keyBindings.confirmYes(input, key)) {
|
|
3150
3138
|
const wf = workflows.find((w) => w.id === confirm.workflowId);
|
|
@@ -3193,22 +3181,6 @@ function Status({ workflows, onSelect, onBack, onStop, onDelete }) {
|
|
|
3193
3181
|
}
|
|
3194
3182
|
return false;
|
|
3195
3183
|
}, [confirm, message, selectedIndex, workflows, onSelect, onBack, onStop, onDelete]));
|
|
3196
|
-
const phaseColor3 = (phase) => {
|
|
3197
|
-
switch (phase) {
|
|
3198
|
-
case "executing":
|
|
3199
|
-
return theme.status.warning;
|
|
3200
|
-
case "active":
|
|
3201
|
-
return theme.status.success;
|
|
3202
|
-
case "completed":
|
|
3203
|
-
return theme.status.success;
|
|
3204
|
-
case "failed":
|
|
3205
|
-
return theme.status.error;
|
|
3206
|
-
case "paused":
|
|
3207
|
-
return theme.status.muted;
|
|
3208
|
-
default:
|
|
3209
|
-
return theme.text.primary;
|
|
3210
|
-
}
|
|
3211
|
-
};
|
|
3212
3184
|
return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
|
|
3213
3185
|
/* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", flexGrow: 1, children: [
|
|
3214
3186
|
/* @__PURE__ */ jsx24(Text20, { bold: true, color: theme.border.accent, children: "Workflows" }),
|
|
@@ -3222,7 +3194,7 @@ function Status({ workflows, onSelect, onBack, onStop, onDelete }) {
|
|
|
3222
3194
|
workflows.map((wf, i) => /* @__PURE__ */ jsx24(Box20, { children: /* @__PURE__ */ jsxs20(Text20, { inverse: i === selectedIndex, children: [
|
|
3223
3195
|
/* @__PURE__ */ jsx24(Text20, { children: wf.id.slice(0, 12).padEnd(14) }),
|
|
3224
3196
|
/* @__PURE__ */ jsx24(Text20, { children: wf.name.slice(0, 26).padEnd(28) }),
|
|
3225
|
-
/* @__PURE__ */ jsx24(Text20, { color:
|
|
3197
|
+
/* @__PURE__ */ jsx24(Text20, { color: phaseColor2(wf.phase), children: wf.phase })
|
|
3226
3198
|
] }) }, wf.id))
|
|
3227
3199
|
] })
|
|
3228
3200
|
] }),
|
|
@@ -3247,7 +3219,7 @@ function AppLayout({ cwd }) {
|
|
|
3247
3219
|
const rows = stdout?.rows ?? 24;
|
|
3248
3220
|
const displayPath = cwd ? cwd.replace(process.env["HOME"] ?? "", "~") : "";
|
|
3249
3221
|
const versionLabel = appVersion === "dev" ? "dev" : `v${appVersion}`;
|
|
3250
|
-
const configIssues =
|
|
3222
|
+
const configIssues = useMemo5(() => {
|
|
3251
3223
|
const validation = validateConfig();
|
|
3252
3224
|
return validation.issues.filter((i) => i.severity === "error");
|
|
3253
3225
|
}, [config]);
|
package/dist/cli.js
CHANGED
|
@@ -508,7 +508,7 @@ program.command("tui").description("Start interactive TUI").option("--skip-onboa
|
|
|
508
508
|
enableTuiLogging();
|
|
509
509
|
const React = await import("react");
|
|
510
510
|
const { render } = await import("ink");
|
|
511
|
-
const { App } = await import("./app-
|
|
511
|
+
const { App } = await import("./app-PUHQN5BJ.js");
|
|
512
512
|
render(React.createElement(App, { cwd: process.cwd(), skipOnboarding: opts.skipOnboarding }), { exitOnCtrlC: false });
|
|
513
513
|
} catch (err) {
|
|
514
514
|
logger.error({ err }, "Failed to start TUI");
|
|
@@ -522,7 +522,7 @@ program.option("--skip-onboarding", "Skip first-run onboarding wizard").action(a
|
|
|
522
522
|
enableTuiLogging();
|
|
523
523
|
const React = await import("react");
|
|
524
524
|
const { render } = await import("ink");
|
|
525
|
-
const { App } = await import("./app-
|
|
525
|
+
const { App } = await import("./app-PUHQN5BJ.js");
|
|
526
526
|
render(React.createElement(App, { cwd: process.cwd(), skipOnboarding }), { exitOnCtrlC: false });
|
|
527
527
|
} catch (err) {
|
|
528
528
|
logger.error({ err }, "Failed to start TUI");
|