@runloop/rl-cli 0.2.0 → 0.4.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 (42) hide show
  1. package/README.md +5 -75
  2. package/dist/cli.js +24 -56
  3. package/dist/commands/auth.js +2 -1
  4. package/dist/commands/blueprint/list.js +68 -22
  5. package/dist/commands/blueprint/preview.js +38 -42
  6. package/dist/commands/config.js +3 -2
  7. package/dist/commands/devbox/ssh.js +2 -1
  8. package/dist/commands/devbox/tunnel.js +2 -1
  9. package/dist/commands/mcp-http.js +6 -5
  10. package/dist/commands/mcp-install.js +9 -8
  11. package/dist/commands/mcp.js +5 -4
  12. package/dist/commands/menu.js +2 -1
  13. package/dist/components/ActionsPopup.js +18 -17
  14. package/dist/components/Banner.js +7 -1
  15. package/dist/components/Breadcrumb.js +10 -9
  16. package/dist/components/DevboxActionsMenu.js +18 -180
  17. package/dist/components/InteractiveSpawn.js +24 -14
  18. package/dist/components/LogsViewer.js +169 -0
  19. package/dist/components/MainMenu.js +2 -2
  20. package/dist/components/ResourceListView.js +3 -3
  21. package/dist/components/UpdateNotification.js +56 -0
  22. package/dist/hooks/useCursorPagination.js +3 -3
  23. package/dist/hooks/useExitOnCtrlC.js +2 -1
  24. package/dist/mcp/server-http.js +2 -1
  25. package/dist/mcp/server.js +7 -2
  26. package/dist/router/Router.js +3 -1
  27. package/dist/screens/BlueprintLogsScreen.js +74 -0
  28. package/dist/services/blueprintService.js +18 -22
  29. package/dist/utils/CommandExecutor.js +24 -53
  30. package/dist/utils/client.js +5 -1
  31. package/dist/utils/config.js +2 -1
  32. package/dist/utils/logFormatter.js +47 -1
  33. package/dist/utils/output.js +4 -3
  34. package/dist/utils/process.js +106 -0
  35. package/dist/utils/processUtils.js +135 -0
  36. package/dist/utils/screen.js +40 -2
  37. package/dist/utils/ssh.js +3 -2
  38. package/dist/utils/terminalDetection.js +120 -32
  39. package/dist/utils/theme.js +34 -19
  40. package/dist/utils/versionCheck.js +53 -0
  41. package/dist/version.js +12 -0
  42. package/package.json +4 -6
@@ -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
- // Check cache first - only detect if we haven't cached a result
73
- const cachedTheme = getDetectedTheme();
74
- if (cachedTheme) {
75
- // Use cached detection result (no flashing!)
76
- detectedTheme = cachedTheme;
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 chalk function for a color name
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
+ }
@@ -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.2.0",
4
- "description": "Beautiful CLI for Runloop devbox management",
3
+ "version": "0.4.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:e2e": "RUN_E2E=1 jest tests/__tests__/integration"
26
+ "test:components": "NODE_OPTIONS='--experimental-vm-modules' jest --config jest.components.config.js --coverage --forceExit"
29
27
  },
30
28
  "keywords": [
31
29
  "runloop",
@@ -58,7 +56,6 @@
58
56
  "dependencies": {
59
57
  "@modelcontextprotocol/sdk": "^1.19.1",
60
58
  "@runloop/api-client": "^1.0.0",
61
- "@runloop/rl-cli": "^0.1.2",
62
59
  "@types/express": "^5.0.3",
63
60
  "chalk": "^5.3.0",
64
61
  "commander": "^14.0.1",
@@ -89,6 +86,7 @@
89
86
  "eslint-plugin-react": "^7.37.5",
90
87
  "eslint-plugin-react-hooks": "^6.1.1",
91
88
  "globals": "^16.4.0",
89
+ "ink-testing-library": "^4.0.0",
92
90
  "jest": "^29.7.0",
93
91
  "prettier": "^3.6.2",
94
92
  "ts-jest": "^29.1.0",