@runloop/rl-cli 0.4.0 → 0.9.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 +73 -106
- package/dist/cli.js +4 -416
- package/dist/commands/blueprint/list.js +2 -1
- package/dist/commands/devbox/list.js +5 -1
- package/dist/commands/snapshot/list.js +47 -6
- package/dist/components/Breadcrumb.js +8 -8
- package/dist/components/DevboxCreatePage.js +2 -2
- package/dist/components/DevboxDetailPage.js +2 -1
- package/dist/components/MainMenu.js +13 -2
- package/dist/components/StateHistory.js +80 -0
- package/dist/components/UpdateNotification.js +3 -44
- package/dist/hooks/useUpdateCheck.js +54 -0
- package/dist/mcp/server.js +1 -1
- package/dist/screens/DevboxCreateScreen.js +4 -4
- package/dist/utils/client.js +1 -1
- package/dist/utils/commands.js +408 -0
- package/dist/utils/config.js +21 -0
- package/dist/utils/exec.js +22 -0
- package/dist/utils/theme.js +1 -1
- package/package.json +21 -8
- package/dist/commands/auth.js +0 -29
- package/dist/commands/blueprint/preview.js +0 -45
- package/dist/commands/config.js +0 -118
- package/dist/commands/create.js +0 -42
- package/dist/commands/delete.js +0 -34
- package/dist/commands/exec.js +0 -35
- package/dist/commands/list.js +0 -59
- package/dist/commands/upload.js +0 -40
- package/dist/components/Table.example.js +0 -85
- package/dist/screens/LogsSessionScreen.js +0 -49
- package/dist/utils/CommandExecutor.js +0 -131
- package/dist/utils/memoryMonitor.js +0 -85
- package/dist/utils/process.js +0 -106
- package/dist/utils/versionCheck.js +0 -53
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Memory Monitor - Track memory usage and manage GC
|
|
3
|
-
* Helps prevent heap exhaustion during navigation
|
|
4
|
-
*/
|
|
5
|
-
let lastMemoryUsage = null;
|
|
6
|
-
let gcAttempts = 0;
|
|
7
|
-
const MAX_GC_ATTEMPTS_PER_MINUTE = 5;
|
|
8
|
-
let lastGCReset = Date.now();
|
|
9
|
-
// Memory thresholds (in bytes)
|
|
10
|
-
const HEAP_WARNING_THRESHOLD = 3.5e9; // 3.5 GB
|
|
11
|
-
const HEAP_CRITICAL_THRESHOLD = 4e9; // 4 GB
|
|
12
|
-
export function logMemoryUsage(label) {
|
|
13
|
-
if (process.env.NODE_ENV === "development" || process.env.DEBUG_MEMORY) {
|
|
14
|
-
const current = process.memoryUsage();
|
|
15
|
-
const heapUsedMB = (current.heapUsed / 1024 / 1024).toFixed(2);
|
|
16
|
-
const heapTotalMB = (current.heapTotal / 1024 / 1024).toFixed(2);
|
|
17
|
-
const rssMB = (current.rss / 1024 / 1024).toFixed(2);
|
|
18
|
-
let delta = "";
|
|
19
|
-
if (lastMemoryUsage) {
|
|
20
|
-
const heapDelta = current.heapUsed - lastMemoryUsage.heapUsed;
|
|
21
|
-
const heapDeltaMB = (heapDelta / 1024 / 1024).toFixed(2);
|
|
22
|
-
delta = ` (Δ ${heapDeltaMB}MB)`;
|
|
23
|
-
}
|
|
24
|
-
console.error(`[MEMORY] ${label}: Heap ${heapUsedMB}/${heapTotalMB}MB, RSS ${rssMB}MB${delta}`);
|
|
25
|
-
// Warn if approaching limits
|
|
26
|
-
if (current.heapUsed > HEAP_WARNING_THRESHOLD) {
|
|
27
|
-
console.warn(`[MEMORY WARNING] Heap usage is high: ${heapUsedMB}MB (threshold: 3500MB)`);
|
|
28
|
-
}
|
|
29
|
-
lastMemoryUsage = current;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
export function getMemoryPressure() {
|
|
33
|
-
const usage = process.memoryUsage();
|
|
34
|
-
const heapUsedPercent = (usage.heapUsed / usage.heapTotal) * 100;
|
|
35
|
-
if (usage.heapUsed > HEAP_CRITICAL_THRESHOLD || heapUsedPercent > 95)
|
|
36
|
-
return "critical";
|
|
37
|
-
if (usage.heapUsed > HEAP_WARNING_THRESHOLD || heapUsedPercent > 85)
|
|
38
|
-
return "high";
|
|
39
|
-
if (heapUsedPercent > 70)
|
|
40
|
-
return "medium";
|
|
41
|
-
return "low";
|
|
42
|
-
}
|
|
43
|
-
export function shouldTriggerGC() {
|
|
44
|
-
const pressure = getMemoryPressure();
|
|
45
|
-
return pressure === "high" || pressure === "critical";
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Force garbage collection if available and needed
|
|
49
|
-
* Respects rate limiting to avoid GC thrashing
|
|
50
|
-
*/
|
|
51
|
-
export function tryForceGC(reason) {
|
|
52
|
-
// Reset GC attempt counter every minute
|
|
53
|
-
const now = Date.now();
|
|
54
|
-
if (now - lastGCReset > 60000) {
|
|
55
|
-
gcAttempts = 0;
|
|
56
|
-
lastGCReset = now;
|
|
57
|
-
}
|
|
58
|
-
// Rate limit GC attempts
|
|
59
|
-
if (gcAttempts >= MAX_GC_ATTEMPTS_PER_MINUTE) {
|
|
60
|
-
return false;
|
|
61
|
-
}
|
|
62
|
-
// Check if global.gc is available (requires --expose-gc flag)
|
|
63
|
-
if (typeof global.gc === "function") {
|
|
64
|
-
const beforeHeap = process.memoryUsage().heapUsed;
|
|
65
|
-
global.gc();
|
|
66
|
-
gcAttempts++;
|
|
67
|
-
const afterHeap = process.memoryUsage().heapUsed;
|
|
68
|
-
const freedMB = ((beforeHeap - afterHeap) / 1024 / 1024).toFixed(2);
|
|
69
|
-
if (process.env.DEBUG_MEMORY) {
|
|
70
|
-
console.error(`[MEMORY] Forced GC${reason ? ` (${reason})` : ""}: Freed ${freedMB}MB`);
|
|
71
|
-
}
|
|
72
|
-
return true;
|
|
73
|
-
}
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Monitor memory and trigger GC if needed
|
|
78
|
-
* Call this after major operations like screen transitions
|
|
79
|
-
*/
|
|
80
|
-
export function checkMemoryPressure() {
|
|
81
|
-
const pressure = getMemoryPressure();
|
|
82
|
-
if (pressure === "critical" || pressure === "high") {
|
|
83
|
-
tryForceGC(`Memory pressure: ${pressure}`);
|
|
84
|
-
}
|
|
85
|
-
}
|
package/dist/utils/process.js
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Process utilities wrapper for testability.
|
|
3
|
-
*
|
|
4
|
-
* This module provides wrappers around Node.js process functions
|
|
5
|
-
* that can be easily mocked in tests.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Default implementation using real process
|
|
9
|
-
*/
|
|
10
|
-
const defaultProcess = {
|
|
11
|
-
exit: (code) => {
|
|
12
|
-
process.exit(code);
|
|
13
|
-
},
|
|
14
|
-
stdout: {
|
|
15
|
-
write: (data) => process.stdout.write(data),
|
|
16
|
-
get isTTY() {
|
|
17
|
-
return process.stdout.isTTY;
|
|
18
|
-
},
|
|
19
|
-
},
|
|
20
|
-
stderr: {
|
|
21
|
-
write: (data) => process.stderr.write(data),
|
|
22
|
-
},
|
|
23
|
-
get env() {
|
|
24
|
-
return process.env;
|
|
25
|
-
},
|
|
26
|
-
cwd: () => process.cwd(),
|
|
27
|
-
};
|
|
28
|
-
/**
|
|
29
|
-
* Current process implementation - can be swapped for testing
|
|
30
|
-
*/
|
|
31
|
-
let currentProcess = defaultProcess;
|
|
32
|
-
/**
|
|
33
|
-
* Get the current process wrapper
|
|
34
|
-
*/
|
|
35
|
-
export function getProcess() {
|
|
36
|
-
return currentProcess;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Set a custom process wrapper (for testing)
|
|
40
|
-
*/
|
|
41
|
-
export function setProcess(proc) {
|
|
42
|
-
currentProcess = proc;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Reset to the default process wrapper
|
|
46
|
-
*/
|
|
47
|
-
export function resetProcess() {
|
|
48
|
-
currentProcess = defaultProcess;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Exit the process with an optional exit code
|
|
52
|
-
*/
|
|
53
|
-
export function exitProcess(code) {
|
|
54
|
-
return currentProcess.exit(code);
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Write to stdout
|
|
58
|
-
*/
|
|
59
|
-
export function writeStdout(data) {
|
|
60
|
-
return currentProcess.stdout.write(data);
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Write to stderr
|
|
64
|
-
*/
|
|
65
|
-
export function writeStderr(data) {
|
|
66
|
-
return currentProcess.stderr.write(data);
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Check if stdout is a TTY
|
|
70
|
-
*/
|
|
71
|
-
export function isStdoutTTY() {
|
|
72
|
-
return !!currentProcess.stdout.isTTY;
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Get environment variable
|
|
76
|
-
*/
|
|
77
|
-
export function getEnv(key) {
|
|
78
|
-
return currentProcess.env[key];
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Get current working directory
|
|
82
|
-
*/
|
|
83
|
-
export function getCwd() {
|
|
84
|
-
return currentProcess.cwd();
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Create a mock process for testing
|
|
88
|
-
*/
|
|
89
|
-
export function createMockProcess(overrides = {}) {
|
|
90
|
-
const exitFn = jest.fn();
|
|
91
|
-
const stdoutWriteFn = jest.fn().mockReturnValue(true);
|
|
92
|
-
const stderrWriteFn = jest.fn().mockReturnValue(true);
|
|
93
|
-
const cwdFn = jest.fn().mockReturnValue("/mock/cwd");
|
|
94
|
-
return {
|
|
95
|
-
exit: overrides.exit ?? exitFn,
|
|
96
|
-
stdout: overrides.stdout ?? {
|
|
97
|
-
write: stdoutWriteFn,
|
|
98
|
-
isTTY: true,
|
|
99
|
-
},
|
|
100
|
-
stderr: overrides.stderr ?? {
|
|
101
|
-
write: stderrWriteFn,
|
|
102
|
-
},
|
|
103
|
-
env: overrides.env ?? {},
|
|
104
|
-
cwd: overrides.cwd ?? cwdFn,
|
|
105
|
-
};
|
|
106
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
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
|
-
}
|