@runloop/rl-cli 0.1.2 → 0.3.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.
Files changed (105) hide show
  1. package/README.md +54 -10
  2. package/dist/cli.js +79 -72
  3. package/dist/commands/auth.js +2 -2
  4. package/dist/commands/blueprint/create.js +31 -83
  5. package/dist/commands/blueprint/get.js +29 -34
  6. package/dist/commands/blueprint/list.js +278 -230
  7. package/dist/commands/blueprint/logs.js +133 -37
  8. package/dist/commands/config.js +118 -0
  9. package/dist/commands/devbox/create.js +120 -40
  10. package/dist/commands/devbox/delete.js +17 -33
  11. package/dist/commands/devbox/download.js +29 -43
  12. package/dist/commands/devbox/exec.js +22 -39
  13. package/dist/commands/devbox/execAsync.js +20 -37
  14. package/dist/commands/devbox/get.js +13 -35
  15. package/dist/commands/devbox/getAsync.js +12 -34
  16. package/dist/commands/devbox/list.js +241 -402
  17. package/dist/commands/devbox/logs.js +20 -38
  18. package/dist/commands/devbox/read.js +29 -43
  19. package/dist/commands/devbox/resume.js +13 -35
  20. package/dist/commands/devbox/rsync.js +26 -78
  21. package/dist/commands/devbox/scp.js +25 -79
  22. package/dist/commands/devbox/sendStdin.js +41 -0
  23. package/dist/commands/devbox/shutdown.js +13 -35
  24. package/dist/commands/devbox/ssh.js +46 -78
  25. package/dist/commands/devbox/suspend.js +13 -35
  26. package/dist/commands/devbox/tunnel.js +37 -88
  27. package/dist/commands/devbox/upload.js +28 -36
  28. package/dist/commands/devbox/write.js +29 -44
  29. package/dist/commands/mcp-http.js +6 -5
  30. package/dist/commands/mcp-install.js +12 -10
  31. package/dist/commands/mcp.js +5 -4
  32. package/dist/commands/menu.js +26 -67
  33. package/dist/commands/object/delete.js +12 -34
  34. package/dist/commands/object/download.js +26 -74
  35. package/dist/commands/object/get.js +12 -34
  36. package/dist/commands/object/list.js +15 -93
  37. package/dist/commands/object/upload.js +35 -96
  38. package/dist/commands/snapshot/create.js +23 -39
  39. package/dist/commands/snapshot/delete.js +17 -33
  40. package/dist/commands/snapshot/get.js +16 -0
  41. package/dist/commands/snapshot/list.js +309 -80
  42. package/dist/commands/snapshot/status.js +12 -34
  43. package/dist/components/ActionsPopup.js +64 -39
  44. package/dist/components/Banner.js +7 -1
  45. package/dist/components/Breadcrumb.js +11 -48
  46. package/dist/components/DevboxActionsMenu.js +117 -207
  47. package/dist/components/DevboxCreatePage.js +12 -7
  48. package/dist/components/DevboxDetailPage.js +76 -28
  49. package/dist/components/ErrorBoundary.js +29 -0
  50. package/dist/components/ErrorMessage.js +10 -2
  51. package/dist/components/Header.js +12 -4
  52. package/dist/components/InteractiveSpawn.js +104 -0
  53. package/dist/components/LogsViewer.js +169 -0
  54. package/dist/components/MainMenu.js +37 -33
  55. package/dist/components/MetadataDisplay.js +4 -4
  56. package/dist/components/OperationsMenu.js +1 -1
  57. package/dist/components/ResourceActionsMenu.js +4 -4
  58. package/dist/components/ResourceListView.js +46 -34
  59. package/dist/components/Spinner.js +7 -2
  60. package/dist/components/StatusBadge.js +1 -1
  61. package/dist/components/SuccessMessage.js +12 -2
  62. package/dist/components/Table.js +16 -6
  63. package/dist/components/UpdateNotification.js +56 -0
  64. package/dist/hooks/useCursorPagination.js +125 -85
  65. package/dist/hooks/useExitOnCtrlC.js +15 -0
  66. package/dist/hooks/useViewportHeight.js +47 -0
  67. package/dist/mcp/server-http.js +2 -1
  68. package/dist/mcp/server.js +71 -7
  69. package/dist/router/Router.js +70 -0
  70. package/dist/router/types.js +1 -0
  71. package/dist/screens/BlueprintListScreen.js +7 -0
  72. package/dist/screens/BlueprintLogsScreen.js +74 -0
  73. package/dist/screens/DevboxActionsScreen.js +25 -0
  74. package/dist/screens/DevboxCreateScreen.js +11 -0
  75. package/dist/screens/DevboxDetailScreen.js +60 -0
  76. package/dist/screens/DevboxListScreen.js +23 -0
  77. package/dist/screens/LogsSessionScreen.js +49 -0
  78. package/dist/screens/MenuScreen.js +23 -0
  79. package/dist/screens/SSHSessionScreen.js +55 -0
  80. package/dist/screens/SnapshotListScreen.js +7 -0
  81. package/dist/services/blueprintService.js +101 -0
  82. package/dist/services/devboxService.js +215 -0
  83. package/dist/services/snapshotService.js +81 -0
  84. package/dist/store/blueprintStore.js +89 -0
  85. package/dist/store/devboxStore.js +105 -0
  86. package/dist/store/index.js +7 -0
  87. package/dist/store/navigationStore.js +101 -0
  88. package/dist/store/snapshotStore.js +87 -0
  89. package/dist/utils/client.js +4 -2
  90. package/dist/utils/config.js +22 -111
  91. package/dist/utils/interactiveCommand.js +3 -2
  92. package/dist/utils/logFormatter.js +208 -0
  93. package/dist/utils/memoryMonitor.js +85 -0
  94. package/dist/utils/output.js +153 -61
  95. package/dist/utils/process.js +106 -0
  96. package/dist/utils/processUtils.js +135 -0
  97. package/dist/utils/screen.js +61 -0
  98. package/dist/utils/ssh.js +6 -3
  99. package/dist/utils/sshSession.js +5 -29
  100. package/dist/utils/terminalDetection.js +185 -0
  101. package/dist/utils/terminalSync.js +39 -0
  102. package/dist/utils/theme.js +162 -13
  103. package/dist/utils/versionCheck.js +53 -0
  104. package/dist/version.js +12 -0
  105. package/package.json +19 -17
@@ -1,45 +1,28 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React from "react";
3
- import { Box, Text } from "ink";
1
+ /**
2
+ * Execute command in devbox
3
+ */
4
4
  import { getClient } from "../../utils/client.js";
5
- import { Header } from "../../components/Header.js";
6
- import { SpinnerComponent } from "../../components/Spinner.js";
7
- import { ErrorMessage } from "../../components/ErrorMessage.js";
8
- import { colors } from "../../utils/theme.js";
9
- import { createExecutor } from "../../utils/CommandExecutor.js";
10
- const ExecCommandUI = ({ id, command, }) => {
11
- const [loading, setLoading] = React.useState(true);
12
- const [output, setOutput] = React.useState("");
13
- const [error, setError] = React.useState(null);
14
- React.useEffect(() => {
15
- const exec = async () => {
16
- try {
17
- const client = getClient();
18
- const result = await client.devboxes.executeSync(id, {
19
- command: command.join(" "),
20
- });
21
- setOutput(result.stdout || result.stderr || "Command executed successfully");
22
- }
23
- catch (err) {
24
- setError(err);
25
- }
26
- finally {
27
- setLoading(false);
28
- }
29
- };
30
- exec();
31
- }, []);
32
- return (_jsxs(_Fragment, { children: [_jsx(Header, { title: "Execute Command", subtitle: `Running in devbox: ${id}` }), loading && _jsx(SpinnerComponent, { message: "Executing command..." }), !loading && !error && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(Box, { borderStyle: "round", borderColor: colors.success, padding: 1, children: _jsx(Text, { children: output }) }) })), error && (_jsx(ErrorMessage, { message: "Failed to execute command", error: error }))] }));
33
- };
5
+ import { output, outputError } from "../../utils/output.js";
34
6
  export async function execCommand(id, command, options = {}) {
35
- const executor = createExecutor({ output: options.output });
36
- await executor.executeAction(async () => {
37
- const client = executor.getClient();
7
+ try {
8
+ const client = getClient();
38
9
  const result = await client.devboxes.executeSync(id, {
39
10
  command: command.join(" "),
11
+ shell_name: options.shellName || undefined,
40
12
  });
41
- return {
42
- result: result.stdout || result.stderr || "Command executed successfully",
43
- };
44
- }, () => _jsx(ExecCommandUI, { id: id, command: command }));
13
+ // For text output, just print stdout/stderr directly
14
+ if (!options.output || options.output === "text") {
15
+ if (result.stdout) {
16
+ console.log(result.stdout);
17
+ }
18
+ if (result.stderr) {
19
+ console.error(result.stderr);
20
+ }
21
+ return;
22
+ }
23
+ output(result, { format: options.output, defaultFormat: "json" });
24
+ }
25
+ catch (error) {
26
+ outputError("Failed to execute command", error);
27
+ }
45
28
  }
@@ -1,43 +1,26 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React from "react";
1
+ /**
2
+ * Execute command asynchronously in devbox
3
+ */
3
4
  import { getClient } from "../../utils/client.js";
4
- import { Banner } from "../../components/Banner.js";
5
- import { SpinnerComponent } from "../../components/Spinner.js";
6
- import { SuccessMessage } from "../../components/SuccessMessage.js";
7
- import { ErrorMessage } from "../../components/ErrorMessage.js";
8
- import { createExecutor } from "../../utils/CommandExecutor.js";
9
- const ExecAsyncUI = ({ devboxId, command, shellName }) => {
10
- const [loading, setLoading] = React.useState(true);
11
- const [result, setResult] = React.useState(null);
12
- const [error, setError] = React.useState(null);
13
- React.useEffect(() => {
14
- const execAsync = async () => {
15
- try {
16
- const client = getClient();
17
- const execution = await client.devboxes.executeAsync(devboxId, {
18
- command,
19
- shell_name: shellName || undefined,
20
- });
21
- setResult(execution);
22
- }
23
- catch (err) {
24
- setError(err);
25
- }
26
- finally {
27
- setLoading(false);
28
- }
29
- };
30
- execAsync();
31
- }, [devboxId, command, shellName]);
32
- return (_jsxs(_Fragment, { children: [_jsx(Banner, {}), loading && _jsx(SpinnerComponent, { message: "Starting async execution..." }), result && (_jsx(SuccessMessage, { message: "Async execution started", details: `Execution ID: ${result.id}\nCommand: ${command}\nStatus: ${result.status}` })), error && (_jsx(ErrorMessage, { message: "Failed to start async execution", error: error }))] }));
33
- };
5
+ import { output, outputError } from "../../utils/output.js";
34
6
  export async function execAsync(devboxId, options) {
35
- const executor = createExecutor({ output: options.output });
36
- await executor.executeAction(async () => {
37
- const client = executor.getClient();
38
- return client.devboxes.executeAsync(devboxId, {
7
+ try {
8
+ const client = getClient();
9
+ const execution = await client.devboxes.executeAsync(devboxId, {
39
10
  command: options.command,
40
11
  shell_name: options.shellName || undefined,
41
12
  });
42
- }, () => (_jsx(ExecAsyncUI, { devboxId: devboxId, command: options.command, shellName: options.shellName })));
13
+ // Default: just output the execution ID for easy scripting
14
+ if (!options.output || options.output === "text") {
15
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
+ const execId = execution.execution_id || execution.id;
17
+ console.log(execId);
18
+ }
19
+ else {
20
+ output(execution, { format: options.output, defaultFormat: "json" });
21
+ }
22
+ }
23
+ catch (error) {
24
+ outputError("Failed to start async execution", error);
25
+ }
43
26
  }
@@ -1,37 +1,15 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React from "react";
1
+ /**
2
+ * Get devbox details command
3
+ */
3
4
  import { getClient } from "../../utils/client.js";
4
- import { Banner } from "../../components/Banner.js";
5
- import { SpinnerComponent } from "../../components/Spinner.js";
6
- import { SuccessMessage } from "../../components/SuccessMessage.js";
7
- import { ErrorMessage } from "../../components/ErrorMessage.js";
8
- import { createExecutor } from "../../utils/CommandExecutor.js";
9
- const GetDevboxUI = ({ devboxId }) => {
10
- const [loading, setLoading] = React.useState(true);
11
- const [result, setResult] = React.useState(null);
12
- const [error, setError] = React.useState(null);
13
- React.useEffect(() => {
14
- const getDevbox = async () => {
15
- try {
16
- const client = getClient();
17
- const devbox = await client.devboxes.retrieve(devboxId);
18
- setResult(devbox);
19
- }
20
- catch (err) {
21
- setError(err);
22
- }
23
- finally {
24
- setLoading(false);
25
- }
26
- };
27
- getDevbox();
28
- }, [devboxId]);
29
- return (_jsxs(_Fragment, { children: [_jsx(Banner, {}), loading && _jsx(SpinnerComponent, { message: "Fetching devbox details..." }), result && (_jsx(SuccessMessage, { message: "Devbox details retrieved", details: `ID: ${result.id}\nStatus: ${result.status}\nCreated: ${new Date(result.createdAt).toLocaleString()}` })), error && _jsx(ErrorMessage, { message: "Failed to get devbox", error: error })] }));
30
- };
31
- export async function getDevbox(devboxId, options) {
32
- const executor = createExecutor(options);
33
- await executor.executeAction(async () => {
34
- const client = executor.getClient();
35
- return client.devboxes.retrieve(devboxId);
36
- }, () => _jsx(GetDevboxUI, { devboxId: devboxId }));
5
+ import { output, outputError } from "../../utils/output.js";
6
+ export async function getDevbox(devboxId, options = {}) {
7
+ try {
8
+ const client = getClient();
9
+ const devbox = await client.devboxes.retrieve(devboxId);
10
+ output(devbox, { format: options.output, defaultFormat: "json" });
11
+ }
12
+ catch (error) {
13
+ outputError("Failed to get devbox", error);
14
+ }
37
15
  }
@@ -1,37 +1,15 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React from "react";
1
+ /**
2
+ * Get async execution status
3
+ */
3
4
  import { getClient } from "../../utils/client.js";
4
- import { Banner } from "../../components/Banner.js";
5
- import { SpinnerComponent } from "../../components/Spinner.js";
6
- import { SuccessMessage } from "../../components/SuccessMessage.js";
7
- import { ErrorMessage } from "../../components/ErrorMessage.js";
8
- import { createExecutor } from "../../utils/CommandExecutor.js";
9
- const GetAsyncUI = ({ devboxId, executionId }) => {
10
- const [loading, setLoading] = React.useState(true);
11
- const [result, setResult] = React.useState(null);
12
- const [error, setError] = React.useState(null);
13
- React.useEffect(() => {
14
- const getAsync = async () => {
15
- try {
16
- const client = getClient();
17
- const execution = await client.devboxes.executions.retrieve(executionId, devboxId);
18
- setResult(execution);
19
- }
20
- catch (err) {
21
- setError(err);
22
- }
23
- finally {
24
- setLoading(false);
25
- }
26
- };
27
- getAsync();
28
- }, [devboxId, executionId]);
29
- return (_jsxs(_Fragment, { children: [_jsx(Banner, {}), loading && (_jsx(SpinnerComponent, { message: "Getting async execution status..." })), result && (_jsx(SuccessMessage, { message: "Async execution status retrieved", details: `Execution ID: ${result.id}\nStatus: ${result.status}\nCommand: ${result.command}` })), error && (_jsx(ErrorMessage, { message: "Failed to get async execution status", error: error }))] }));
30
- };
5
+ import { output, outputError } from "../../utils/output.js";
31
6
  export async function getAsync(devboxId, options) {
32
- const executor = createExecutor({ output: options.output });
33
- await executor.executeAction(async () => {
34
- const client = executor.getClient();
35
- return client.devboxes.executions.retrieve(devboxId, options.executionId);
36
- }, () => _jsx(GetAsyncUI, { devboxId: devboxId, executionId: options.executionId }));
7
+ try {
8
+ const client = getClient();
9
+ const execution = await client.devboxes.executions.retrieve(devboxId, options.executionId);
10
+ output(execution, { format: options.output, defaultFormat: "json" });
11
+ }
12
+ catch (error) {
13
+ outputError("Failed to get async execution status", error);
14
+ }
37
15
  }