clawcontrol 0.2.0 → 0.2.1
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/index.js +197 -56
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
// src/index.tsx
|
|
2
2
|
import { createRequire } from "module";
|
|
3
|
+
import { release } from "os";
|
|
3
4
|
import { createCliRenderer } from "@opentui/core";
|
|
4
5
|
import { createRoot } from "@opentui/react";
|
|
5
6
|
|
|
6
7
|
// src/App.tsx
|
|
7
|
-
import { useState as useState12, useCallback as useCallback4, useRef as
|
|
8
|
+
import { useState as useState12, useCallback as useCallback4, useRef as useRef7 } from "react";
|
|
8
9
|
import { useRenderer as useRenderer2 } from "@opentui/react";
|
|
9
10
|
|
|
10
11
|
// src/components/Home.tsx
|
|
11
|
-
import { useState } from "react";
|
|
12
|
+
import { useState, useRef } from "react";
|
|
13
|
+
import { useKeyboard } from "@opentui/react";
|
|
12
14
|
|
|
13
15
|
// src/theme.ts
|
|
14
16
|
var palette = {
|
|
@@ -155,27 +157,53 @@ var COMMANDS = [
|
|
|
155
157
|
function Home({ context }) {
|
|
156
158
|
const [inputValue, setInputValue] = useState("");
|
|
157
159
|
const [error, setError] = useState(null);
|
|
160
|
+
const [selectedSuggestionIndex, setSelectedSuggestionIndex] = useState(-1);
|
|
161
|
+
const viewMap = {
|
|
162
|
+
"/new": "new",
|
|
163
|
+
"/list": "list",
|
|
164
|
+
"/deploy": "deploy",
|
|
165
|
+
"/status": "status",
|
|
166
|
+
"/ssh": "ssh",
|
|
167
|
+
"/logs": "logs",
|
|
168
|
+
"/dashboard": "dashboard",
|
|
169
|
+
"/destroy": "destroy",
|
|
170
|
+
"/templates": "templates",
|
|
171
|
+
"/help": "help"
|
|
172
|
+
};
|
|
173
|
+
const filteredCommands = inputValue.length >= 2 && inputValue.startsWith("/") ? COMMANDS.filter((cmd) => cmd.name.startsWith(inputValue.toLowerCase())) : [];
|
|
174
|
+
const stateRef = useRef({ selectedSuggestionIndex, filteredCommands, inputValue });
|
|
175
|
+
stateRef.current = { selectedSuggestionIndex, filteredCommands, inputValue };
|
|
158
176
|
const handleCommand = (command) => {
|
|
159
177
|
const cmd = command.trim().toLowerCase();
|
|
160
178
|
setError(null);
|
|
161
|
-
const viewMap = {
|
|
162
|
-
"/new": "new",
|
|
163
|
-
"/list": "list",
|
|
164
|
-
"/deploy": "deploy",
|
|
165
|
-
"/status": "status",
|
|
166
|
-
"/ssh": "ssh",
|
|
167
|
-
"/logs": "logs",
|
|
168
|
-
"/dashboard": "dashboard",
|
|
169
|
-
"/destroy": "destroy",
|
|
170
|
-
"/templates": "templates",
|
|
171
|
-
"/help": "help"
|
|
172
|
-
};
|
|
173
179
|
if (viewMap[cmd]) {
|
|
174
180
|
context.navigateTo(viewMap[cmd]);
|
|
175
181
|
} else if (cmd.startsWith("/")) {
|
|
176
182
|
setError(`Unknown command: ${cmd}. Type /help for available commands.`);
|
|
177
183
|
}
|
|
178
184
|
};
|
|
185
|
+
useKeyboard((key) => {
|
|
186
|
+
const s = stateRef.current;
|
|
187
|
+
if (s.filteredCommands.length === 0) return;
|
|
188
|
+
if (key.name === "down") {
|
|
189
|
+
setSelectedSuggestionIndex(
|
|
190
|
+
(prev) => prev < s.filteredCommands.length - 1 ? prev + 1 : 0
|
|
191
|
+
);
|
|
192
|
+
} else if (key.name === "up") {
|
|
193
|
+
setSelectedSuggestionIndex(
|
|
194
|
+
(prev) => prev > 0 ? prev - 1 : s.filteredCommands.length - 1
|
|
195
|
+
);
|
|
196
|
+
} else if (key.name === "tab") {
|
|
197
|
+
if (s.selectedSuggestionIndex >= 0 && s.selectedSuggestionIndex < s.filteredCommands.length) {
|
|
198
|
+
const cmd = s.filteredCommands[s.selectedSuggestionIndex].name;
|
|
199
|
+
setInputValue("");
|
|
200
|
+
setSelectedSuggestionIndex(-1);
|
|
201
|
+
handleCommand(cmd);
|
|
202
|
+
}
|
|
203
|
+
} else if (key.name === "escape") {
|
|
204
|
+
setSelectedSuggestionIndex(-1);
|
|
205
|
+
}
|
|
206
|
+
});
|
|
179
207
|
return /* @__PURE__ */ jsxs("box", { flexDirection: "column", width: "100%", height: "100%", children: [
|
|
180
208
|
/* @__PURE__ */ jsx(
|
|
181
209
|
"scrollbox",
|
|
@@ -278,9 +306,19 @@ function Home({ context }) {
|
|
|
278
306
|
placeholder: "Type a command (e.g., /new)...",
|
|
279
307
|
focused: true,
|
|
280
308
|
width: "100%",
|
|
281
|
-
onInput: (value) =>
|
|
309
|
+
onInput: (value) => {
|
|
310
|
+
setInputValue(value);
|
|
311
|
+
const matches = value.length >= 2 && value.startsWith("/") ? COMMANDS.filter((cmd) => cmd.name.startsWith(value.toLowerCase())) : [];
|
|
312
|
+
setSelectedSuggestionIndex(matches.length > 0 ? 0 : -1);
|
|
313
|
+
},
|
|
282
314
|
onSubmit: (value) => {
|
|
283
|
-
|
|
315
|
+
const s = stateRef.current;
|
|
316
|
+
if (s.selectedSuggestionIndex >= 0 && s.selectedSuggestionIndex < s.filteredCommands.length) {
|
|
317
|
+
const cmd = s.filteredCommands[s.selectedSuggestionIndex].name;
|
|
318
|
+
setInputValue("");
|
|
319
|
+
setSelectedSuggestionIndex(-1);
|
|
320
|
+
handleCommand(cmd);
|
|
321
|
+
} else if (typeof value === "string" && typeof value.trim === "function" && value.trim()) {
|
|
284
322
|
handleCommand(value);
|
|
285
323
|
setInputValue("");
|
|
286
324
|
}
|
|
@@ -290,14 +328,22 @@ function Home({ context }) {
|
|
|
290
328
|
}
|
|
291
329
|
)
|
|
292
330
|
}
|
|
293
|
-
)
|
|
331
|
+
),
|
|
332
|
+
filteredCommands.length > 0 && /* @__PURE__ */ jsx("box", { flexDirection: "column", paddingLeft: 1, backgroundColor: t.bg.elevated, children: filteredCommands.map((cmd, i) => {
|
|
333
|
+
const selected = i === selectedSuggestionIndex;
|
|
334
|
+
return /* @__PURE__ */ jsxs("box", { flexDirection: "row", height: 1, overflow: "hidden", backgroundColor: selected ? t.selection.bg : t.bg.elevated, children: [
|
|
335
|
+
/* @__PURE__ */ jsx("text", { fg: selected ? t.selection.indicator : t.fg.muted, children: selected ? "> " : " " }),
|
|
336
|
+
/* @__PURE__ */ jsx("text", { fg: selected ? t.accent : t.fg.primary, width: 14, children: cmd.name }),
|
|
337
|
+
/* @__PURE__ */ jsx("text", { fg: t.fg.secondary, children: cmd.description })
|
|
338
|
+
] }, cmd.name);
|
|
339
|
+
}) })
|
|
294
340
|
] })
|
|
295
341
|
] });
|
|
296
342
|
}
|
|
297
343
|
|
|
298
344
|
// src/components/NewDeployment.tsx
|
|
299
|
-
import { useState as useState2, useRef, useEffect } from "react";
|
|
300
|
-
import { useKeyboard } from "@opentui/react";
|
|
345
|
+
import { useState as useState2, useRef as useRef2, useEffect } from "react";
|
|
346
|
+
import { useKeyboard as useKeyboard2 } from "@opentui/react";
|
|
301
347
|
import { appendFileSync } from "fs";
|
|
302
348
|
import { homedir as homedir3 } from "os";
|
|
303
349
|
import { join as join4 } from "path";
|
|
@@ -1428,7 +1474,7 @@ function NewDeployment({ context }) {
|
|
|
1428
1474
|
setSelectedSavedKeyIndex(0);
|
|
1429
1475
|
}
|
|
1430
1476
|
}, [step]);
|
|
1431
|
-
const stateRef =
|
|
1477
|
+
const stateRef = useRef2({
|
|
1432
1478
|
name,
|
|
1433
1479
|
provider,
|
|
1434
1480
|
apiKey,
|
|
@@ -1558,7 +1604,7 @@ function NewDeployment({ context }) {
|
|
|
1558
1604
|
setError(`Failed to ${s.editMode === "edit" ? "update" : "create"} deployment: ${err instanceof Error ? err.message : String(err)}`);
|
|
1559
1605
|
}
|
|
1560
1606
|
};
|
|
1561
|
-
|
|
1607
|
+
useKeyboard2((key) => {
|
|
1562
1608
|
const currentState = stateRef.current;
|
|
1563
1609
|
debugLog(`useKeyboard: key=${key.name}, step=${currentState.step}`);
|
|
1564
1610
|
if (currentState.step === "template_choice") {
|
|
@@ -2811,8 +2857,8 @@ function NewDeployment({ context }) {
|
|
|
2811
2857
|
}
|
|
2812
2858
|
|
|
2813
2859
|
// src/components/ListView.tsx
|
|
2814
|
-
import { useState as useState3, useRef as
|
|
2815
|
-
import { useKeyboard as
|
|
2860
|
+
import { useState as useState3, useRef as useRef3 } from "react";
|
|
2861
|
+
import { useKeyboard as useKeyboard3 } from "@opentui/react";
|
|
2816
2862
|
import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "@opentui/react/jsx-runtime";
|
|
2817
2863
|
function ListView({ context }) {
|
|
2818
2864
|
const [viewState, setViewState] = useState3("listing");
|
|
@@ -2822,9 +2868,9 @@ function ListView({ context }) {
|
|
|
2822
2868
|
const [deletedName, setDeletedName] = useState3("");
|
|
2823
2869
|
const deployments = context.deployments;
|
|
2824
2870
|
const selectedDeployment = deployments[selectedIndex];
|
|
2825
|
-
const stateRef =
|
|
2871
|
+
const stateRef = useRef3({ viewState, selectedIndex });
|
|
2826
2872
|
stateRef.current = { viewState, selectedIndex };
|
|
2827
|
-
|
|
2873
|
+
useKeyboard3((key) => {
|
|
2828
2874
|
const current = stateRef.current;
|
|
2829
2875
|
if (deployments.length === 0) {
|
|
2830
2876
|
context.navigateTo("home");
|
|
@@ -3122,7 +3168,7 @@ function ListView({ context }) {
|
|
|
3122
3168
|
|
|
3123
3169
|
// src/components/DeployView.tsx
|
|
3124
3170
|
import { useState as useState4 } from "react";
|
|
3125
|
-
import { useKeyboard as
|
|
3171
|
+
import { useKeyboard as useKeyboard4 } from "@opentui/react";
|
|
3126
3172
|
import { jsx as jsx4, jsxs as jsxs4 } from "@opentui/react/jsx-runtime";
|
|
3127
3173
|
function DeployView({ context }) {
|
|
3128
3174
|
const [selectedIndex, setSelectedIndex] = useState4(0);
|
|
@@ -3132,7 +3178,7 @@ function DeployView({ context }) {
|
|
|
3132
3178
|
const deployed = deployments.filter((d) => d.state.status === "deployed");
|
|
3133
3179
|
const allDeployments = [...notDeployed, ...deployed];
|
|
3134
3180
|
const selectedDeployment = allDeployments[selectedIndex];
|
|
3135
|
-
|
|
3181
|
+
useKeyboard4((key) => {
|
|
3136
3182
|
if (allDeployments.length === 0) {
|
|
3137
3183
|
context.navigateTo("home");
|
|
3138
3184
|
return;
|
|
@@ -3251,8 +3297,8 @@ function DeployView({ context }) {
|
|
|
3251
3297
|
}
|
|
3252
3298
|
|
|
3253
3299
|
// src/components/DeployingView.tsx
|
|
3254
|
-
import { useState as useState5, useEffect as useEffect2, useCallback, useRef as
|
|
3255
|
-
import { useKeyboard as
|
|
3300
|
+
import { useState as useState5, useEffect as useEffect2, useCallback, useRef as useRef4 } from "react";
|
|
3301
|
+
import { useKeyboard as useKeyboard5 } from "@opentui/react";
|
|
3256
3302
|
import open from "open";
|
|
3257
3303
|
|
|
3258
3304
|
// src/services/ssh.ts
|
|
@@ -4713,6 +4759,12 @@ function detectTerminal() {
|
|
|
4713
4759
|
return { app: "konsole", canOpenTab: true };
|
|
4714
4760
|
}
|
|
4715
4761
|
}
|
|
4762
|
+
if (os === "win32") {
|
|
4763
|
+
if (env.WT_SESSION) {
|
|
4764
|
+
return { app: "windows-terminal", canOpenTab: true };
|
|
4765
|
+
}
|
|
4766
|
+
return { app: "powershell", canOpenTab: false };
|
|
4767
|
+
}
|
|
4716
4768
|
if (os === "darwin") {
|
|
4717
4769
|
return { app: "terminal.app", canOpenTab: true };
|
|
4718
4770
|
}
|
|
@@ -4747,11 +4799,19 @@ function openTerminalWithCommand(command) {
|
|
|
4747
4799
|
return openKonsole(command);
|
|
4748
4800
|
case "xfce4-terminal":
|
|
4749
4801
|
return openXfce4Terminal(command);
|
|
4802
|
+
case "windows-terminal":
|
|
4803
|
+
return openWindowsTerminal(command);
|
|
4804
|
+
case "powershell":
|
|
4805
|
+
return openPowerShell(command);
|
|
4806
|
+
case "cmd":
|
|
4807
|
+
return openCmd(command);
|
|
4750
4808
|
default:
|
|
4751
4809
|
if (os === "darwin") {
|
|
4752
4810
|
return openTerminalApp(command);
|
|
4753
4811
|
} else if (os === "linux") {
|
|
4754
4812
|
return openLinuxFallback(command);
|
|
4813
|
+
} else if (os === "win32") {
|
|
4814
|
+
return openWindowsFallback(command);
|
|
4755
4815
|
}
|
|
4756
4816
|
return { success: false, error: `Unsupported terminal or OS: ${terminal.app}` };
|
|
4757
4817
|
}
|
|
@@ -4947,6 +5007,9 @@ function openCursorTerminal(command) {
|
|
|
4947
5007
|
}
|
|
4948
5008
|
return openTerminalApp(command);
|
|
4949
5009
|
}
|
|
5010
|
+
if (platform() === "win32") {
|
|
5011
|
+
return openWindowsFallback(command);
|
|
5012
|
+
}
|
|
4950
5013
|
return openLinuxFallback(command);
|
|
4951
5014
|
}
|
|
4952
5015
|
function openVSCodeTerminal(command) {
|
|
@@ -5018,6 +5081,62 @@ function openLinuxFallback(command) {
|
|
|
5018
5081
|
}
|
|
5019
5082
|
return { success: false, error: "Could not find a supported terminal emulator" };
|
|
5020
5083
|
}
|
|
5084
|
+
function createTempScriptWindows(command) {
|
|
5085
|
+
const scriptPath = join5(tmpdir(), `clawcontrol-${process.pid}-${Date.now()}.cmd`);
|
|
5086
|
+
const content = [
|
|
5087
|
+
"@echo off",
|
|
5088
|
+
command,
|
|
5089
|
+
`del "${scriptPath}"`,
|
|
5090
|
+
""
|
|
5091
|
+
].join("\r\n");
|
|
5092
|
+
writeFileSync5(scriptPath, content);
|
|
5093
|
+
return scriptPath;
|
|
5094
|
+
}
|
|
5095
|
+
function openWindowsTerminal(command) {
|
|
5096
|
+
const script = createTempScriptWindows(command);
|
|
5097
|
+
const proc = spawn("wt.exe", ["new-tab", "cmd", "/c", script], {
|
|
5098
|
+
stdio: "ignore",
|
|
5099
|
+
detached: true,
|
|
5100
|
+
shell: true
|
|
5101
|
+
});
|
|
5102
|
+
proc.unref();
|
|
5103
|
+
return { success: true };
|
|
5104
|
+
}
|
|
5105
|
+
function openPowerShell(command) {
|
|
5106
|
+
const proc = spawn("powershell.exe", [
|
|
5107
|
+
"-NoProfile",
|
|
5108
|
+
"Start-Process",
|
|
5109
|
+
"powershell",
|
|
5110
|
+
"-ArgumentList",
|
|
5111
|
+
`'-NoExit -Command "${command.replace(/"/g, '`"')}"'`
|
|
5112
|
+
], {
|
|
5113
|
+
stdio: "ignore",
|
|
5114
|
+
detached: true,
|
|
5115
|
+
shell: true
|
|
5116
|
+
});
|
|
5117
|
+
proc.unref();
|
|
5118
|
+
return { success: true };
|
|
5119
|
+
}
|
|
5120
|
+
function openCmd(command) {
|
|
5121
|
+
const script = createTempScriptWindows(command);
|
|
5122
|
+
const proc = spawn("cmd.exe", ["/c", "start", "cmd", "/k", script], {
|
|
5123
|
+
stdio: "ignore",
|
|
5124
|
+
detached: true,
|
|
5125
|
+
shell: true
|
|
5126
|
+
});
|
|
5127
|
+
proc.unref();
|
|
5128
|
+
return { success: true };
|
|
5129
|
+
}
|
|
5130
|
+
function openWindowsFallback(command) {
|
|
5131
|
+
try {
|
|
5132
|
+
const result = spawnSync("where", ["wt.exe"], { stdio: "pipe", timeout: 2e3 });
|
|
5133
|
+
if (result.status === 0) {
|
|
5134
|
+
return openWindowsTerminal(command);
|
|
5135
|
+
}
|
|
5136
|
+
} catch {
|
|
5137
|
+
}
|
|
5138
|
+
return openPowerShell(command);
|
|
5139
|
+
}
|
|
5021
5140
|
function getTerminalDisplayName(app) {
|
|
5022
5141
|
const names = {
|
|
5023
5142
|
"terminal.app": "Terminal.app",
|
|
@@ -5033,6 +5152,9 @@ function getTerminalDisplayName(app) {
|
|
|
5033
5152
|
"konsole": "Konsole",
|
|
5034
5153
|
"xfce4-terminal": "XFCE Terminal",
|
|
5035
5154
|
"xterm": "XTerm",
|
|
5155
|
+
"windows-terminal": "Windows Terminal",
|
|
5156
|
+
"powershell": "PowerShell",
|
|
5157
|
+
"cmd": "Command Prompt",
|
|
5036
5158
|
"unknown": "System Terminal"
|
|
5037
5159
|
};
|
|
5038
5160
|
return names[app];
|
|
@@ -5094,9 +5216,9 @@ function DeployingView({ context }) {
|
|
|
5094
5216
|
setDeployState("deploying");
|
|
5095
5217
|
addLog("Terminal session confirmed complete, continuing deployment...");
|
|
5096
5218
|
}, [terminalResolve, addLog]);
|
|
5097
|
-
const stateRef =
|
|
5219
|
+
const stateRef = useRef4({ deployState, terminalResolve });
|
|
5098
5220
|
stateRef.current = { deployState, terminalResolve };
|
|
5099
|
-
|
|
5221
|
+
useKeyboard5((key) => {
|
|
5100
5222
|
const currentState = stateRef.current;
|
|
5101
5223
|
if (currentState.deployState === "waiting_terminal") {
|
|
5102
5224
|
if (key.name === "return") {
|
|
@@ -5344,7 +5466,7 @@ function DeployingView({ context }) {
|
|
|
5344
5466
|
|
|
5345
5467
|
// src/components/StatusView.tsx
|
|
5346
5468
|
import { useState as useState6 } from "react";
|
|
5347
|
-
import { useKeyboard as
|
|
5469
|
+
import { useKeyboard as useKeyboard6 } from "@opentui/react";
|
|
5348
5470
|
import { jsx as jsx6, jsxs as jsxs6 } from "@opentui/react/jsx-runtime";
|
|
5349
5471
|
function StatusView({ context }) {
|
|
5350
5472
|
const [selectedIndex, setSelectedIndex] = useState6(0);
|
|
@@ -5374,7 +5496,7 @@ function StatusView({ context }) {
|
|
|
5374
5496
|
setHealthStatus((prev) => new Map(prev).set(name, health));
|
|
5375
5497
|
setChecking(null);
|
|
5376
5498
|
};
|
|
5377
|
-
|
|
5499
|
+
useKeyboard6((key) => {
|
|
5378
5500
|
if (deployments.length === 0) {
|
|
5379
5501
|
context.navigateTo("home");
|
|
5380
5502
|
return;
|
|
@@ -5528,7 +5650,7 @@ function StatusView({ context }) {
|
|
|
5528
5650
|
|
|
5529
5651
|
// src/components/SSHView.tsx
|
|
5530
5652
|
import { useState as useState7, useCallback as useCallback2 } from "react";
|
|
5531
|
-
import { useKeyboard as
|
|
5653
|
+
import { useKeyboard as useKeyboard7 } from "@opentui/react";
|
|
5532
5654
|
import { jsx as jsx7, jsxs as jsxs7 } from "@opentui/react/jsx-runtime";
|
|
5533
5655
|
function SSHView({ context }) {
|
|
5534
5656
|
const [viewState, setViewState] = useState7("selecting");
|
|
@@ -5554,7 +5676,7 @@ function SSHView({ context }) {
|
|
|
5554
5676
|
}
|
|
5555
5677
|
}, []);
|
|
5556
5678
|
const selectedDeployment = deployedDeployments[selectedIndex];
|
|
5557
|
-
|
|
5679
|
+
useKeyboard7((key) => {
|
|
5558
5680
|
if (deployedDeployments.length === 0) {
|
|
5559
5681
|
context.navigateTo("home");
|
|
5560
5682
|
return;
|
|
@@ -5709,8 +5831,8 @@ function SSHView({ context }) {
|
|
|
5709
5831
|
}
|
|
5710
5832
|
|
|
5711
5833
|
// src/components/LogsView.tsx
|
|
5712
|
-
import { useState as useState8, useEffect as useEffect3, useRef as
|
|
5713
|
-
import { useKeyboard as
|
|
5834
|
+
import { useState as useState8, useEffect as useEffect3, useRef as useRef5 } from "react";
|
|
5835
|
+
import { useKeyboard as useKeyboard8 } from "@opentui/react";
|
|
5714
5836
|
import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs8 } from "@opentui/react/jsx-runtime";
|
|
5715
5837
|
function parseLogLine(line) {
|
|
5716
5838
|
if (!line.trim()) return null;
|
|
@@ -5736,8 +5858,8 @@ function LogsView({ context }) {
|
|
|
5736
5858
|
const [error, setError] = useState8(null);
|
|
5737
5859
|
const [autoRefresh, setAutoRefresh] = useState8(false);
|
|
5738
5860
|
const [lastFetched, setLastFetched] = useState8(null);
|
|
5739
|
-
const sshRef =
|
|
5740
|
-
const refreshIntervalRef =
|
|
5861
|
+
const sshRef = useRef5(null);
|
|
5862
|
+
const refreshIntervalRef = useRef5(null);
|
|
5741
5863
|
const deployedDeployments = context.deployments.filter(
|
|
5742
5864
|
(d) => d.state.status === "deployed" && d.state.serverIp
|
|
5743
5865
|
);
|
|
@@ -5788,7 +5910,7 @@ function LogsView({ context }) {
|
|
|
5788
5910
|
setLogs([]);
|
|
5789
5911
|
};
|
|
5790
5912
|
const selectedDeployment = deployedDeployments[selectedIndex];
|
|
5791
|
-
|
|
5913
|
+
useKeyboard8((key) => {
|
|
5792
5914
|
if (deployedDeployments.length === 0) {
|
|
5793
5915
|
context.navigateTo("home");
|
|
5794
5916
|
return;
|
|
@@ -5947,7 +6069,7 @@ function LogsView({ context }) {
|
|
|
5947
6069
|
|
|
5948
6070
|
// src/components/DestroyView.tsx
|
|
5949
6071
|
import { useState as useState9 } from "react";
|
|
5950
|
-
import { useKeyboard as
|
|
6072
|
+
import { useKeyboard as useKeyboard9 } from "@opentui/react";
|
|
5951
6073
|
import { jsx as jsx9, jsxs as jsxs9 } from "@opentui/react/jsx-runtime";
|
|
5952
6074
|
function DestroyView({ context }) {
|
|
5953
6075
|
const [viewState, setViewState] = useState9("selecting");
|
|
@@ -5998,7 +6120,7 @@ function DestroyView({ context }) {
|
|
|
5998
6120
|
}
|
|
5999
6121
|
};
|
|
6000
6122
|
const selectedDeployment = deployments[selectedIndex];
|
|
6001
|
-
|
|
6123
|
+
useKeyboard9((key) => {
|
|
6002
6124
|
if (deployments.length === 0) {
|
|
6003
6125
|
context.navigateTo("home");
|
|
6004
6126
|
return;
|
|
@@ -6189,10 +6311,10 @@ function DestroyView({ context }) {
|
|
|
6189
6311
|
}
|
|
6190
6312
|
|
|
6191
6313
|
// src/components/HelpView.tsx
|
|
6192
|
-
import { useKeyboard as
|
|
6314
|
+
import { useKeyboard as useKeyboard10 } from "@opentui/react";
|
|
6193
6315
|
import { jsx as jsx10, jsxs as jsxs10 } from "@opentui/react/jsx-runtime";
|
|
6194
6316
|
function HelpView({ context }) {
|
|
6195
|
-
|
|
6317
|
+
useKeyboard10(() => {
|
|
6196
6318
|
context.navigateTo("home");
|
|
6197
6319
|
});
|
|
6198
6320
|
return /* @__PURE__ */ jsxs10("box", { flexDirection: "column", width: "100%", padding: 1, children: [
|
|
@@ -6319,8 +6441,8 @@ function HelpView({ context }) {
|
|
|
6319
6441
|
}
|
|
6320
6442
|
|
|
6321
6443
|
// src/components/TemplatesView.tsx
|
|
6322
|
-
import { useState as useState10, useRef as
|
|
6323
|
-
import { useKeyboard as
|
|
6444
|
+
import { useState as useState10, useRef as useRef6, useEffect as useEffect4 } from "react";
|
|
6445
|
+
import { useKeyboard as useKeyboard11 } from "@opentui/react";
|
|
6324
6446
|
import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs11 } from "@opentui/react/jsx-runtime";
|
|
6325
6447
|
var DO_DROPLET_SIZES2 = [
|
|
6326
6448
|
{ slug: "s-1vcpu-2gb", label: "1 vCPU, 2GB RAM, 50GB SSD", price: "$12/mo" },
|
|
@@ -6343,7 +6465,7 @@ function TemplatesView({ context }) {
|
|
|
6343
6465
|
const [forkAiProvider, setForkAiProvider] = useState10("");
|
|
6344
6466
|
const [forkAiProviderIndex, setForkAiProviderIndex] = useState10(0);
|
|
6345
6467
|
const [forkModel, setForkModel] = useState10("");
|
|
6346
|
-
const stateRef =
|
|
6468
|
+
const stateRef = useRef6({
|
|
6347
6469
|
viewState,
|
|
6348
6470
|
selectedIndex,
|
|
6349
6471
|
selectedTemplate,
|
|
@@ -6457,7 +6579,7 @@ function TemplatesView({ context }) {
|
|
|
6457
6579
|
setViewState("viewing");
|
|
6458
6580
|
}
|
|
6459
6581
|
};
|
|
6460
|
-
|
|
6582
|
+
useKeyboard11((key) => {
|
|
6461
6583
|
const s = stateRef.current;
|
|
6462
6584
|
if (s.viewState === "listing") {
|
|
6463
6585
|
if (key.name === "up") {
|
|
@@ -6866,7 +6988,7 @@ function TemplatesView({ context }) {
|
|
|
6866
6988
|
|
|
6867
6989
|
// src/components/DashboardView.tsx
|
|
6868
6990
|
import { useState as useState11, useCallback as useCallback3 } from "react";
|
|
6869
|
-
import { useKeyboard as
|
|
6991
|
+
import { useKeyboard as useKeyboard12, useRenderer } from "@opentui/react";
|
|
6870
6992
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
6871
6993
|
import { platform as platform2 } from "os";
|
|
6872
6994
|
|
|
@@ -7035,7 +7157,7 @@ function DashboardView({ context }) {
|
|
|
7035
7157
|
setViewState("error");
|
|
7036
7158
|
}
|
|
7037
7159
|
}, []);
|
|
7038
|
-
|
|
7160
|
+
useKeyboard12((key) => {
|
|
7039
7161
|
if (viewState === "selecting") {
|
|
7040
7162
|
if (deployedDeployments.length === 0) {
|
|
7041
7163
|
if (key.name === "escape" || key.name === "return") {
|
|
@@ -7294,8 +7416,8 @@ function DashboardView({ context }) {
|
|
|
7294
7416
|
}
|
|
7295
7417
|
|
|
7296
7418
|
// src/App.tsx
|
|
7297
|
-
import { jsx as jsx13 } from "@opentui/react/jsx-runtime";
|
|
7298
|
-
function App() {
|
|
7419
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "@opentui/react/jsx-runtime";
|
|
7420
|
+
function App({ lacksTrueColor: lacksTrueColor2 }) {
|
|
7299
7421
|
const renderer = useRenderer2();
|
|
7300
7422
|
const [currentView, setCurrentView] = useState12("home");
|
|
7301
7423
|
const [selectedDeployment, setSelectedDeployment] = useState12(null);
|
|
@@ -7308,7 +7430,7 @@ function App() {
|
|
|
7308
7430
|
});
|
|
7309
7431
|
const [selectedTemplate, setSelectedTemplate] = useState12(null);
|
|
7310
7432
|
const [editingDeployment, setEditingDeployment] = useState12(null);
|
|
7311
|
-
const wasDraggingRef =
|
|
7433
|
+
const wasDraggingRef = useRef7(false);
|
|
7312
7434
|
const handleMouseDrag = useCallback4(() => {
|
|
7313
7435
|
wasDraggingRef.current = true;
|
|
7314
7436
|
}, []);
|
|
@@ -7377,7 +7499,7 @@ function App() {
|
|
|
7377
7499
|
return /* @__PURE__ */ jsx13(Home, { context });
|
|
7378
7500
|
}
|
|
7379
7501
|
};
|
|
7380
|
-
return /* @__PURE__ */
|
|
7502
|
+
return /* @__PURE__ */ jsxs13(
|
|
7381
7503
|
"scrollbox",
|
|
7382
7504
|
{
|
|
7383
7505
|
width: "100%",
|
|
@@ -7398,7 +7520,23 @@ function App() {
|
|
|
7398
7520
|
verticalScrollbarOptions: {
|
|
7399
7521
|
showArrows: false
|
|
7400
7522
|
},
|
|
7401
|
-
children:
|
|
7523
|
+
children: [
|
|
7524
|
+
lacksTrueColor2 && /* @__PURE__ */ jsx13(
|
|
7525
|
+
"box",
|
|
7526
|
+
{
|
|
7527
|
+
width: "100%",
|
|
7528
|
+
style: {
|
|
7529
|
+
paddingLeft: 1,
|
|
7530
|
+
paddingRight: 1,
|
|
7531
|
+
paddingTop: 0,
|
|
7532
|
+
paddingBottom: 0,
|
|
7533
|
+
backgroundColor: t.status.warning
|
|
7534
|
+
},
|
|
7535
|
+
children: /* @__PURE__ */ jsx13("text", { fg: "#000000", children: "\u26A0 Your terminal does not support true color. Colors may look wrong. For full color support, use Ghostty, iTerm2, Kitty, or WezTerm \u2014 or upgrade to macOS 26+ for Terminal.app true color support." })
|
|
7536
|
+
}
|
|
7537
|
+
),
|
|
7538
|
+
renderView()
|
|
7539
|
+
]
|
|
7402
7540
|
}
|
|
7403
7541
|
);
|
|
7404
7542
|
}
|
|
@@ -7433,11 +7571,14 @@ Documentation & source:
|
|
|
7433
7571
|
`);
|
|
7434
7572
|
process.exit(0);
|
|
7435
7573
|
}
|
|
7574
|
+
var isAppleTerminal = process.env.TERM_PROGRAM === "Apple_Terminal";
|
|
7575
|
+
var darwinMajor = process.platform === "darwin" ? parseInt(release(), 10) : Infinity;
|
|
7576
|
+
var lacksTrueColor = isAppleTerminal && darwinMajor < 25;
|
|
7436
7577
|
async function main() {
|
|
7437
7578
|
const renderer = await createCliRenderer({
|
|
7438
7579
|
useMouse: true
|
|
7439
7580
|
});
|
|
7440
7581
|
const root = createRoot(renderer);
|
|
7441
|
-
root.render(/* @__PURE__ */ jsx14(App, {}));
|
|
7582
|
+
root.render(/* @__PURE__ */ jsx14(App, { lacksTrueColor }));
|
|
7442
7583
|
}
|
|
7443
7584
|
main().catch(console.error);
|