gambi 0.2.3
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 +1 -0
- package/package.json +60 -0
- package/src/cli.ts +32 -0
- package/src/commands/create.ts +160 -0
- package/src/commands/join.ts +937 -0
- package/src/commands/list.ts +104 -0
- package/src/commands/monitor.ts +27 -0
- package/src/commands/serve.ts +116 -0
- package/src/utils/network-endpoint.test.ts +40 -0
- package/src/utils/network-endpoint.ts +136 -0
- package/src/utils/option.ts +10 -0
- package/src/utils/prompt.ts +24 -0
- package/src/utils/runtime-config.ts +211 -0
- package/src/utils/specs.ts +149 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { cpus, platform, totalmem } from "node:os";
|
|
2
|
+
import { $ } from "bun";
|
|
3
|
+
|
|
4
|
+
const LSPCI_GPU_REGEX = /: (.+)$/m;
|
|
5
|
+
const MACOS_CHIP_REGEX = /Chip(?:set)? Model: (.+)/;
|
|
6
|
+
const MACOS_VRAM_REGEX = /VRAM.*?: (\d+)/;
|
|
7
|
+
|
|
8
|
+
export interface MachineSpecs {
|
|
9
|
+
cpu: string;
|
|
10
|
+
ram: number; // in GB
|
|
11
|
+
gpu?: string;
|
|
12
|
+
vram?: number; // in GB
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface GPUInfo {
|
|
16
|
+
gpu?: string;
|
|
17
|
+
vram?: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function detectLinuxGPU(): Promise<GPUInfo> {
|
|
21
|
+
// Try nvidia-smi first (NVIDIA GPUs)
|
|
22
|
+
try {
|
|
23
|
+
const result =
|
|
24
|
+
await $`nvidia-smi --query-gpu=name,memory.total --format=csv,noheader,nounits`
|
|
25
|
+
.text()
|
|
26
|
+
.catch(() => null);
|
|
27
|
+
|
|
28
|
+
if (result) {
|
|
29
|
+
const parts = result.trim().split(", ");
|
|
30
|
+
const name = parts[0];
|
|
31
|
+
const vramMB = parts[1];
|
|
32
|
+
if (name && vramMB) {
|
|
33
|
+
return {
|
|
34
|
+
gpu: name,
|
|
35
|
+
vram: Math.round(Number.parseInt(vramMB, 10) / 1024),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
} catch {
|
|
40
|
+
// nvidia-smi not available
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Fallback to lspci for any GPU
|
|
44
|
+
const lspci = await $`lspci 2>/dev/null | grep -i 'vga\\|3d\\|display'`
|
|
45
|
+
.text()
|
|
46
|
+
.catch(() => null);
|
|
47
|
+
|
|
48
|
+
if (lspci) {
|
|
49
|
+
const match = lspci.match(LSPCI_GPU_REGEX);
|
|
50
|
+
if (match?.[1]) {
|
|
51
|
+
return { gpu: match[1].trim() };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return {};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function detectMacOSGPU(): Promise<GPUInfo> {
|
|
59
|
+
const result = await $`system_profiler SPDisplaysDataType 2>/dev/null`
|
|
60
|
+
.text()
|
|
61
|
+
.catch(() => null);
|
|
62
|
+
|
|
63
|
+
if (result) {
|
|
64
|
+
const chipMatch = result.match(MACOS_CHIP_REGEX);
|
|
65
|
+
const vramMatch = result.match(MACOS_VRAM_REGEX);
|
|
66
|
+
const vramValue = vramMatch?.[1];
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
gpu: chipMatch?.[1]?.trim(),
|
|
70
|
+
vram: vramValue
|
|
71
|
+
? Math.round(Number.parseInt(vramValue, 10) / 1024)
|
|
72
|
+
: undefined,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function detectWindowsGPU(): Promise<GPUInfo> {
|
|
80
|
+
const result =
|
|
81
|
+
await $`wmic path win32_VideoController get name,adapterram /format:csv`
|
|
82
|
+
.text()
|
|
83
|
+
.catch(() => null);
|
|
84
|
+
|
|
85
|
+
if (result) {
|
|
86
|
+
const lines = result.trim().split("\n").filter(Boolean);
|
|
87
|
+
const dataLine = lines[1];
|
|
88
|
+
if (dataLine) {
|
|
89
|
+
const parts = dataLine.split(",");
|
|
90
|
+
const adapterRam = parts[1];
|
|
91
|
+
const name = parts[2];
|
|
92
|
+
return {
|
|
93
|
+
gpu: name?.trim(),
|
|
94
|
+
vram: adapterRam
|
|
95
|
+
? Math.round(Number.parseInt(adapterRam, 10) / 1024 / 1024 / 1024)
|
|
96
|
+
: undefined,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return {};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function detectGPU(): Promise<GPUInfo> {
|
|
105
|
+
const os = platform();
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
if (os === "linux") {
|
|
109
|
+
return await detectLinuxGPU();
|
|
110
|
+
}
|
|
111
|
+
if (os === "darwin") {
|
|
112
|
+
return await detectMacOSGPU();
|
|
113
|
+
}
|
|
114
|
+
if (os === "win32") {
|
|
115
|
+
return await detectWindowsGPU();
|
|
116
|
+
}
|
|
117
|
+
} catch {
|
|
118
|
+
// GPU detection failed
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return {};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export async function detectSpecs(): Promise<MachineSpecs> {
|
|
125
|
+
const cpuInfo = cpus();
|
|
126
|
+
const cpu = cpuInfo[0]?.model ?? "Unknown";
|
|
127
|
+
const ram = Math.round(totalmem() / 1024 / 1024 / 1024); // Convert to GB
|
|
128
|
+
|
|
129
|
+
const gpuInfo = await detectGPU();
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
cpu,
|
|
133
|
+
ram,
|
|
134
|
+
...gpuInfo,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function formatSpecs(specs: MachineSpecs): string {
|
|
139
|
+
const parts = [`CPU: ${specs.cpu}`, `RAM: ${specs.ram}GB`];
|
|
140
|
+
|
|
141
|
+
if (specs.gpu) {
|
|
142
|
+
parts.push(`GPU: ${specs.gpu}`);
|
|
143
|
+
}
|
|
144
|
+
if (specs.vram) {
|
|
145
|
+
parts.push(`VRAM: ${specs.vram}GB`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return parts.join(" | ");
|
|
149
|
+
}
|