@runloop/rl-cli 0.2.0 → 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.
- package/README.md +0 -10
- package/dist/cli.js +7 -13
- package/dist/commands/auth.js +2 -1
- package/dist/commands/blueprint/list.js +68 -22
- package/dist/commands/blueprint/preview.js +38 -42
- package/dist/commands/config.js +3 -2
- package/dist/commands/devbox/ssh.js +2 -1
- package/dist/commands/devbox/tunnel.js +2 -1
- package/dist/commands/mcp-http.js +6 -5
- package/dist/commands/mcp-install.js +8 -7
- package/dist/commands/mcp.js +5 -4
- package/dist/commands/menu.js +2 -1
- package/dist/components/ActionsPopup.js +18 -17
- package/dist/components/Banner.js +7 -1
- package/dist/components/Breadcrumb.js +10 -9
- package/dist/components/DevboxActionsMenu.js +18 -180
- package/dist/components/InteractiveSpawn.js +24 -14
- package/dist/components/LogsViewer.js +169 -0
- package/dist/components/MainMenu.js +2 -2
- package/dist/components/UpdateNotification.js +56 -0
- package/dist/hooks/useExitOnCtrlC.js +2 -1
- package/dist/mcp/server-http.js +2 -1
- package/dist/mcp/server.js +6 -1
- package/dist/router/Router.js +3 -1
- package/dist/screens/BlueprintLogsScreen.js +74 -0
- package/dist/services/blueprintService.js +18 -22
- package/dist/utils/CommandExecutor.js +24 -53
- package/dist/utils/client.js +4 -0
- package/dist/utils/logFormatter.js +47 -1
- package/dist/utils/output.js +4 -3
- package/dist/utils/process.js +106 -0
- package/dist/utils/processUtils.js +135 -0
- package/dist/utils/screen.js +40 -2
- package/dist/utils/ssh.js +3 -2
- package/dist/utils/terminalDetection.js +120 -32
- package/dist/utils/theme.js +34 -19
- package/dist/utils/versionCheck.js +53 -0
- package/dist/version.js +12 -0
- package/package.json +4 -5
package/dist/utils/screen.js
CHANGED
|
@@ -6,18 +6,56 @@
|
|
|
6
6
|
* the current screen content and switches to a clean buffer. Upon exit,
|
|
7
7
|
* the original screen content is restored.
|
|
8
8
|
*/
|
|
9
|
+
import { processUtils } from "./processUtils.js";
|
|
9
10
|
/**
|
|
10
11
|
* Enter the alternate screen buffer.
|
|
11
12
|
* This provides a fullscreen experience where content won't mix with
|
|
12
13
|
* previous terminal output. Like vim or top.
|
|
13
14
|
*/
|
|
14
15
|
export function enterAlternateScreenBuffer() {
|
|
15
|
-
|
|
16
|
+
processUtils.stdout.write("\x1b[?1049h");
|
|
16
17
|
}
|
|
17
18
|
/**
|
|
18
19
|
* Exit the alternate screen buffer and restore the previous screen content.
|
|
19
20
|
* This returns the terminal to its original state before enterAlternateScreen() was called.
|
|
20
21
|
*/
|
|
21
22
|
export function exitAlternateScreenBuffer() {
|
|
22
|
-
|
|
23
|
+
processUtils.stdout.write("\x1b[?1049l");
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Clear the terminal screen.
|
|
27
|
+
* Uses ANSI escape sequences to clear the screen and move cursor to top-left.
|
|
28
|
+
*/
|
|
29
|
+
export function clearScreen() {
|
|
30
|
+
// Clear entire screen and move cursor to top-left
|
|
31
|
+
processUtils.stdout.write("\x1b[2J\x1b[H");
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Show the terminal cursor.
|
|
35
|
+
* Uses ANSI escape sequence to make the cursor visible.
|
|
36
|
+
*/
|
|
37
|
+
export function showCursor() {
|
|
38
|
+
processUtils.stdout.write("\x1b[?25h");
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Hide the terminal cursor.
|
|
42
|
+
* Uses ANSI escape sequence to make the cursor invisible.
|
|
43
|
+
*/
|
|
44
|
+
export function hideCursor() {
|
|
45
|
+
processUtils.stdout.write("\x1b[?25l");
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Reset terminal to a clean state.
|
|
49
|
+
* Exits alternate screen buffer, clears the screen, and resets cursor.
|
|
50
|
+
* Also resets terminal attributes to ensure clean state for subprocesses.
|
|
51
|
+
*/
|
|
52
|
+
export function resetTerminal() {
|
|
53
|
+
exitAlternateScreenBuffer();
|
|
54
|
+
clearScreen();
|
|
55
|
+
// Reset terminal attributes (SGR reset)
|
|
56
|
+
processUtils.stdout.write("\x1b[0m");
|
|
57
|
+
// Move cursor to home position
|
|
58
|
+
processUtils.stdout.write("\x1b[H");
|
|
59
|
+
// Show cursor to ensure it's visible
|
|
60
|
+
showCursor();
|
|
23
61
|
}
|
package/dist/utils/ssh.js
CHANGED
|
@@ -4,6 +4,7 @@ import { writeFile, mkdir, chmod } from "fs/promises";
|
|
|
4
4
|
import { join } from "path";
|
|
5
5
|
import { homedir } from "os";
|
|
6
6
|
import { getClient } from "./client.js";
|
|
7
|
+
import { processUtils } from "./processUtils.js";
|
|
7
8
|
const execAsync = promisify(exec);
|
|
8
9
|
export function constructSSHConfig(options) {
|
|
9
10
|
return `Host ${options.hostname}
|
|
@@ -91,7 +92,7 @@ export async function waitForReady(devboxId, timeoutSeconds = 180, pollIntervalS
|
|
|
91
92
|
* Get SSH URL based on environment
|
|
92
93
|
*/
|
|
93
94
|
export function getSSHUrl() {
|
|
94
|
-
const env =
|
|
95
|
+
const env = processUtils.env.RUNLOOP_ENV?.toLowerCase();
|
|
95
96
|
return env === "dev" ? "ssh.runloop.pro:443" : "ssh.runloop.ai:443";
|
|
96
97
|
}
|
|
97
98
|
/**
|
|
@@ -128,7 +129,7 @@ export async function executeSSH(devboxId, user, keyfilePath, url, additionalArg
|
|
|
128
129
|
}
|
|
129
130
|
catch (error) {
|
|
130
131
|
console.error("SSH command failed:", error);
|
|
131
|
-
|
|
132
|
+
processUtils.exit(1);
|
|
132
133
|
}
|
|
133
134
|
}
|
|
134
135
|
/**
|
|
@@ -18,80 +18,168 @@ function getLuminance(r, g, b) {
|
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
20
|
* Parse RGB color from terminal response
|
|
21
|
-
*
|
|
21
|
+
* Terminal responses can come in various formats:
|
|
22
|
+
* - OSC 11;rgb:RRRR/GGGG/BBBB (xterm-style, 4 hex digits per channel)
|
|
23
|
+
* - OSC 11;rgb:RR/GG/BB (short format, 2 hex digits per channel)
|
|
24
|
+
* - rgb:RRRR/GGGG/BBBB (without OSC prefix)
|
|
22
25
|
*/
|
|
23
26
|
function parseRGBResponse(response) {
|
|
24
|
-
//
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
// Try multiple patterns to handle different terminal response formats
|
|
28
|
+
// Pattern 1: OSC 11;rgb:RRRR/GGGG/BBBB or 11;rgb:RRRR/GGGG/BBBB (xterm-style, 4 hex digits)
|
|
29
|
+
let match = response.match(/11;rgb:([0-9a-f]{4})\/([0-9a-f]{4})\/([0-9a-f]{4})/i);
|
|
30
|
+
if (match) {
|
|
31
|
+
// Take first 2 hex digits and convert to 0-255
|
|
32
|
+
const r = parseInt(match[1].substring(0, 2), 16);
|
|
33
|
+
const g = parseInt(match[2].substring(0, 2), 16);
|
|
34
|
+
const b = parseInt(match[3].substring(0, 2), 16);
|
|
35
|
+
return { r, g, b };
|
|
36
|
+
}
|
|
37
|
+
// Pattern 2: OSC 11;rgb:RR/GG/BB (short format, 2 hex digits)
|
|
38
|
+
match = response.match(/11;rgb:([0-9a-f]{2})\/([0-9a-f]{2})\/([0-9a-f]{2})/i);
|
|
39
|
+
if (match) {
|
|
40
|
+
const r = parseInt(match[1], 16);
|
|
41
|
+
const g = parseInt(match[2], 16);
|
|
42
|
+
const b = parseInt(match[3], 16);
|
|
43
|
+
return { r, g, b };
|
|
44
|
+
}
|
|
45
|
+
// Pattern 3: rgb:RRRR/GGGG/BBBB (without OSC prefix, 4 hex digits)
|
|
46
|
+
match = response.match(/rgb:([0-9a-f]{4})\/([0-9a-f]{4})\/([0-9a-f]{4})/i);
|
|
47
|
+
if (match) {
|
|
48
|
+
const r = parseInt(match[1].substring(0, 2), 16);
|
|
49
|
+
const g = parseInt(match[2].substring(0, 2), 16);
|
|
50
|
+
const b = parseInt(match[3].substring(0, 2), 16);
|
|
51
|
+
return { r, g, b };
|
|
52
|
+
}
|
|
53
|
+
// Pattern 4: rgb:RR/GG/BB (without OSC prefix, 2 hex digits)
|
|
54
|
+
match = response.match(/rgb:([0-9a-f]{2})\/([0-9a-f]{2})\/([0-9a-f]{2})/i);
|
|
55
|
+
if (match) {
|
|
56
|
+
const r = parseInt(match[1], 16);
|
|
57
|
+
const g = parseInt(match[2], 16);
|
|
58
|
+
const b = parseInt(match[3], 16);
|
|
59
|
+
return { r, g, b };
|
|
28
60
|
}
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
61
|
+
// Pattern 5: Generic pattern for any hex values separated by /
|
|
62
|
+
match = response.match(/([0-9a-f]{2,4})\/([0-9a-f]{2,4})\/([0-9a-f]{2,4})/i);
|
|
63
|
+
if (match) {
|
|
64
|
+
const r = parseInt(match[1].substring(0, 2), 16);
|
|
65
|
+
const g = parseInt(match[2].substring(0, 2), 16);
|
|
66
|
+
const b = parseInt(match[3].substring(0, 2), 16);
|
|
67
|
+
return { r, g, b };
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
34
70
|
}
|
|
35
71
|
/**
|
|
36
72
|
* Detect terminal theme by querying background color
|
|
37
73
|
* Returns 'light' or 'dark' based on background luminance, or null if detection fails
|
|
38
74
|
*
|
|
39
|
-
* NOTE:
|
|
40
|
-
*
|
|
41
|
-
*
|
|
75
|
+
* NOTE: Theme detection runs automatically when theme preference is "auto".
|
|
76
|
+
* Users can disable it by setting RUNLOOP_DISABLE_THEME_DETECTION=1 to prevent
|
|
77
|
+
* any potential terminal flashing.
|
|
42
78
|
*/
|
|
43
79
|
export async function detectTerminalTheme() {
|
|
44
80
|
// Skip detection in non-TTY environments
|
|
45
81
|
if (!stdin.isTTY || !stdout.isTTY) {
|
|
46
82
|
return null;
|
|
47
83
|
}
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
if (process.env.RUNLOOP_ENABLE_THEME_DETECTION !== "1") {
|
|
84
|
+
// Allow users to opt-out of theme detection if they experience flashing
|
|
85
|
+
if (process.env.RUNLOOP_DISABLE_THEME_DETECTION === "1") {
|
|
51
86
|
return null;
|
|
52
87
|
}
|
|
53
88
|
return new Promise((resolve) => {
|
|
54
89
|
let response = "";
|
|
55
90
|
let timeout;
|
|
91
|
+
let hasResolved = false;
|
|
56
92
|
const cleanup = () => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
93
|
+
try {
|
|
94
|
+
stdin.setRawMode(false);
|
|
95
|
+
stdin.pause();
|
|
96
|
+
stdin.removeListener("data", onData);
|
|
97
|
+
stdin.removeListener("readable", onReadable);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// Ignore errors during cleanup
|
|
101
|
+
}
|
|
102
|
+
if (timeout) {
|
|
103
|
+
clearTimeout(timeout);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
const finish = (result) => {
|
|
107
|
+
if (hasResolved)
|
|
108
|
+
return;
|
|
109
|
+
hasResolved = true;
|
|
110
|
+
cleanup();
|
|
111
|
+
resolve(result);
|
|
61
112
|
};
|
|
62
113
|
const onData = (chunk) => {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
114
|
+
if (hasResolved)
|
|
115
|
+
return;
|
|
116
|
+
const text = chunk.toString("utf8");
|
|
117
|
+
response += text;
|
|
118
|
+
// Check if we have a complete response
|
|
119
|
+
// Terminal responses typically end with ESC \ (ST) or BEL (\x07)
|
|
120
|
+
// Some terminals may also send the response without the OSC prefix
|
|
121
|
+
if (response.includes("\x1b\\") ||
|
|
122
|
+
response.includes("\x07") ||
|
|
123
|
+
response.includes("\x1b]")) {
|
|
67
124
|
const rgb = parseRGBResponse(response);
|
|
68
125
|
if (rgb) {
|
|
69
126
|
const luminance = getLuminance(rgb.r, rgb.g, rgb.b);
|
|
70
127
|
// Threshold: luminance > 0.5 is considered light background
|
|
71
|
-
|
|
128
|
+
finish(luminance > 0.5 ? "light" : "dark");
|
|
129
|
+
return;
|
|
72
130
|
}
|
|
73
|
-
|
|
74
|
-
|
|
131
|
+
// If we got a response but couldn't parse it, check if it's complete
|
|
132
|
+
if (response.includes("\x1b\\") || response.includes("\x07")) {
|
|
133
|
+
finish(null);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
// Some terminals may send responses through the readable event instead
|
|
139
|
+
const onReadable = () => {
|
|
140
|
+
if (hasResolved)
|
|
141
|
+
return;
|
|
142
|
+
let chunk;
|
|
143
|
+
while ((chunk = stdin.read()) !== null) {
|
|
144
|
+
const text = chunk.toString("utf8");
|
|
145
|
+
response += text;
|
|
146
|
+
if (text.includes("\x1b\\") || text.includes("\x07")) {
|
|
147
|
+
const rgb = parseRGBResponse(response);
|
|
148
|
+
if (rgb) {
|
|
149
|
+
const luminance = getLuminance(rgb.r, rgb.g, rgb.b);
|
|
150
|
+
finish(luminance > 0.5 ? "light" : "dark");
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
finish(null);
|
|
154
|
+
return;
|
|
75
155
|
}
|
|
76
156
|
}
|
|
77
157
|
};
|
|
78
158
|
// Set timeout for terminals that don't support the query
|
|
79
159
|
timeout = setTimeout(() => {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}, 50); // 50ms timeout - quick to minimize any visual flashing
|
|
160
|
+
finish(null);
|
|
161
|
+
}, 200); // Increased timeout to 200ms to give terminals more time to respond
|
|
83
162
|
try {
|
|
84
163
|
// Enable raw mode to capture escape sequences
|
|
85
164
|
stdin.setRawMode(true);
|
|
86
165
|
stdin.resume();
|
|
166
|
+
// Listen to both data and readable events
|
|
87
167
|
stdin.on("data", onData);
|
|
168
|
+
stdin.on("readable", onReadable);
|
|
88
169
|
// Query background color using OSC 11 sequence
|
|
89
170
|
// Format: ESC ] 11 ; ? ESC \
|
|
171
|
+
// Some terminals may need the BEL terminator instead
|
|
90
172
|
stdout.write("\x1b]11;?\x1b\\");
|
|
173
|
+
// Also try with BEL terminator as some terminals prefer it
|
|
174
|
+
// (but wait a bit to see if first one works)
|
|
175
|
+
setTimeout(() => {
|
|
176
|
+
if (!hasResolved) {
|
|
177
|
+
stdout.write("\x1b]11;?\x07");
|
|
178
|
+
}
|
|
179
|
+
}, 10);
|
|
91
180
|
}
|
|
92
181
|
catch {
|
|
93
|
-
|
|
94
|
-
resolve(null);
|
|
182
|
+
finish(null);
|
|
95
183
|
}
|
|
96
184
|
});
|
|
97
185
|
}
|
package/dist/utils/theme.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { detectTerminalTheme } from "./terminalDetection.js";
|
|
6
6
|
import { getThemePreference, getDetectedTheme, setDetectedTheme, } from "./config.js";
|
|
7
|
+
import chalk from "chalk";
|
|
7
8
|
// Dark mode color palette (default)
|
|
8
9
|
const darkColors = {
|
|
9
10
|
// Primary brand colors
|
|
@@ -68,27 +69,21 @@ export async function initializeTheme() {
|
|
|
68
69
|
const preference = getThemePreference();
|
|
69
70
|
let detectedTheme = null;
|
|
70
71
|
// Auto-detect if preference is 'auto'
|
|
72
|
+
// Always detect on startup to support different terminal profiles
|
|
73
|
+
// (users may have different terminal profiles with different themes)
|
|
71
74
|
if (preference === "auto") {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
// First time detection - run it and cache the result
|
|
80
|
-
try {
|
|
81
|
-
detectedTheme = await detectTerminalTheme();
|
|
82
|
-
if (detectedTheme) {
|
|
83
|
-
// Cache the result so we don't detect again
|
|
84
|
-
setDetectedTheme(detectedTheme);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
catch {
|
|
88
|
-
// Detection failed, fall back to dark mode
|
|
89
|
-
detectedTheme = null;
|
|
75
|
+
try {
|
|
76
|
+
detectedTheme = await detectTerminalTheme();
|
|
77
|
+
// Cache the result for reference, but we always re-detect on startup
|
|
78
|
+
if (detectedTheme) {
|
|
79
|
+
setDetectedTheme(detectedTheme);
|
|
90
80
|
}
|
|
91
81
|
}
|
|
82
|
+
catch {
|
|
83
|
+
// Detection failed, fall back to cached value or dark mode
|
|
84
|
+
const cachedTheme = getDetectedTheme();
|
|
85
|
+
detectedTheme = cachedTheme || null;
|
|
86
|
+
}
|
|
92
87
|
}
|
|
93
88
|
// Determine final theme
|
|
94
89
|
if (preference === "light") {
|
|
@@ -117,12 +112,32 @@ export function getCurrentTheme() {
|
|
|
117
112
|
return currentTheme;
|
|
118
113
|
}
|
|
119
114
|
/**
|
|
120
|
-
* Get
|
|
115
|
+
* Get hex color value for a color name
|
|
121
116
|
* Useful for applying colors dynamically
|
|
122
117
|
*/
|
|
123
118
|
export function getChalkColor(colorName) {
|
|
124
119
|
return activeColors[colorName];
|
|
125
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Get chalk text color function for a color name
|
|
123
|
+
* Converts hex color to chalk function for text coloring
|
|
124
|
+
* @param colorName - Name of the color from the palette
|
|
125
|
+
* @returns Chalk function that can be used to color text
|
|
126
|
+
*/
|
|
127
|
+
export function getChalkTextColor(colorName) {
|
|
128
|
+
const hexColor = activeColors[colorName];
|
|
129
|
+
return chalk.hex(hexColor);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Get chalk background color function for a color name
|
|
133
|
+
* Converts hex color to chalk function for background coloring
|
|
134
|
+
* @param colorName - Name of the color from the palette
|
|
135
|
+
* @returns Chalk function that can be used to color backgrounds
|
|
136
|
+
*/
|
|
137
|
+
export function getChalkBgColor(colorName) {
|
|
138
|
+
const hexColor = activeColors[colorName];
|
|
139
|
+
return chalk.bgHex(hexColor);
|
|
140
|
+
}
|
|
126
141
|
/**
|
|
127
142
|
* Check if we should use inverted colors (light mode)
|
|
128
143
|
* Useful for components that need to explicitly set backgrounds
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { shouldCheckForUpdates, updateCheckCache } from "./config.js";
|
|
2
|
+
import { VERSION } from "../cli.js";
|
|
3
|
+
/**
|
|
4
|
+
* Check if a new version is available on npm
|
|
5
|
+
* Uses caching to avoid checking too frequently
|
|
6
|
+
*/
|
|
7
|
+
export async function checkForUpdates() {
|
|
8
|
+
const currentVersion = VERSION;
|
|
9
|
+
// Check if we should check for updates (respects cache)
|
|
10
|
+
if (!shouldCheckForUpdates()) {
|
|
11
|
+
return {
|
|
12
|
+
isUpdateAvailable: false,
|
|
13
|
+
latestVersion: null,
|
|
14
|
+
currentVersion,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
// Fetch latest version from npm registry
|
|
19
|
+
const response = await fetch("https://registry.npmjs.org/@runloop/rl-cli/latest", {
|
|
20
|
+
headers: {
|
|
21
|
+
Accept: "application/json",
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
if (!response.ok) {
|
|
25
|
+
// If fetch fails, don't show update message
|
|
26
|
+
return {
|
|
27
|
+
isUpdateAvailable: false,
|
|
28
|
+
latestVersion: null,
|
|
29
|
+
currentVersion,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const data = (await response.json());
|
|
33
|
+
const latestVersion = data.version;
|
|
34
|
+
// Update the cache
|
|
35
|
+
updateCheckCache();
|
|
36
|
+
// Compare versions (simple string comparison works for semver)
|
|
37
|
+
const isUpdateAvailable = latestVersion !== currentVersion;
|
|
38
|
+
return {
|
|
39
|
+
isUpdateAvailable,
|
|
40
|
+
latestVersion,
|
|
41
|
+
currentVersion,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
// Silently fail - don't show update message if check fails
|
|
46
|
+
// This prevents network errors from disrupting the user experience
|
|
47
|
+
return {
|
|
48
|
+
isUpdateAvailable: false,
|
|
49
|
+
latestVersion: null,
|
|
50
|
+
currentVersion,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version information for the CLI.
|
|
3
|
+
* Separated from cli.ts to allow importing without side effects.
|
|
4
|
+
*/
|
|
5
|
+
import { readFileSync } from "fs";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
import { dirname, join } from "path";
|
|
8
|
+
// Get version from package.json
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = dirname(__filename);
|
|
11
|
+
const packageJson = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf8"));
|
|
12
|
+
export const VERSION = packageJson.version;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@runloop/rl-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Beautiful CLI for Runloop
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Beautiful CLI for the Runloop platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"rli": "./dist/cli.js"
|
|
@@ -21,11 +21,9 @@
|
|
|
21
21
|
"lint": "eslint src --ext .ts,.tsx",
|
|
22
22
|
"lint:fix": "eslint src --ext .ts,.tsx --fix",
|
|
23
23
|
"test": "jest",
|
|
24
|
-
"test:unit": "jest tests/__tests__/unit",
|
|
25
|
-
"test:integration": "jest tests/__tests__/integration",
|
|
26
24
|
"test:watch": "jest --watch",
|
|
27
25
|
"test:coverage": "jest --coverage",
|
|
28
|
-
"test:
|
|
26
|
+
"test:components": "NODE_OPTIONS='--experimental-vm-modules' jest --config jest.components.config.js --coverage --forceExit"
|
|
29
27
|
},
|
|
30
28
|
"keywords": [
|
|
31
29
|
"runloop",
|
|
@@ -89,6 +87,7 @@
|
|
|
89
87
|
"eslint-plugin-react": "^7.37.5",
|
|
90
88
|
"eslint-plugin-react-hooks": "^6.1.1",
|
|
91
89
|
"globals": "^16.4.0",
|
|
90
|
+
"ink-testing-library": "^4.0.0",
|
|
92
91
|
"jest": "^29.7.0",
|
|
93
92
|
"prettier": "^3.6.2",
|
|
94
93
|
"ts-jest": "^29.1.0",
|