@kernel.chat/kbot 3.23.0 → 3.26.1
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 +33 -22
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +3 -1
- package/dist/agent.js.map +1 -1
- package/dist/agents/trader.d.ts +32 -0
- package/dist/agents/trader.d.ts.map +1 -0
- package/dist/agents/trader.js +190 -0
- package/dist/agents/trader.js.map +1 -0
- package/dist/cli.js +219 -15
- package/dist/cli.js.map +1 -1
- package/dist/context.d.ts +4 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +28 -1
- package/dist/context.js.map +1 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +71 -1
- package/dist/doctor.js.map +1 -1
- package/dist/inference.d.ts +9 -0
- package/dist/inference.d.ts.map +1 -1
- package/dist/inference.js +38 -5
- package/dist/inference.js.map +1 -1
- package/dist/introspection.d.ts +17 -0
- package/dist/introspection.d.ts.map +1 -0
- package/dist/introspection.js +490 -0
- package/dist/introspection.js.map +1 -0
- package/dist/learned-router.d.ts.map +1 -1
- package/dist/learned-router.js +3 -0
- package/dist/learned-router.js.map +1 -1
- package/dist/machine.d.ts +85 -0
- package/dist/machine.d.ts.map +1 -0
- package/dist/machine.js +538 -0
- package/dist/machine.js.map +1 -0
- package/dist/matrix.d.ts.map +1 -1
- package/dist/matrix.js +11 -0
- package/dist/matrix.js.map +1 -1
- package/dist/provider-fallback.d.ts +6 -0
- package/dist/provider-fallback.d.ts.map +1 -1
- package/dist/provider-fallback.js +29 -0
- package/dist/provider-fallback.js.map +1 -1
- package/dist/synthesis-engine.d.ts +175 -0
- package/dist/synthesis-engine.d.ts.map +1 -0
- package/dist/synthesis-engine.js +783 -0
- package/dist/synthesis-engine.js.map +1 -0
- package/dist/tool-pipeline.d.ts +7 -1
- package/dist/tool-pipeline.d.ts.map +1 -1
- package/dist/tool-pipeline.js +39 -1
- package/dist/tool-pipeline.js.map +1 -1
- package/dist/tools/finance.d.ts +2 -0
- package/dist/tools/finance.d.ts.map +1 -0
- package/dist/tools/finance.js +1116 -0
- package/dist/tools/finance.js.map +1 -0
- package/dist/tools/finance.test.d.ts +2 -0
- package/dist/tools/finance.test.d.ts.map +1 -0
- package/dist/tools/finance.test.js +245 -0
- package/dist/tools/finance.test.js.map +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +5 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/machine-tools.d.ts +2 -0
- package/dist/tools/machine-tools.d.ts.map +1 -0
- package/dist/tools/machine-tools.js +690 -0
- package/dist/tools/machine-tools.js.map +1 -0
- package/dist/tools/sentiment.d.ts +2 -0
- package/dist/tools/sentiment.d.ts.map +1 -0
- package/dist/tools/sentiment.js +513 -0
- package/dist/tools/sentiment.js.map +1 -0
- package/dist/tools/stocks.d.ts +2 -0
- package/dist/tools/stocks.d.ts.map +1 -0
- package/dist/tools/stocks.js +345 -0
- package/dist/tools/stocks.js.map +1 -0
- package/dist/tools/stocks.test.d.ts +2 -0
- package/dist/tools/stocks.test.d.ts.map +1 -0
- package/dist/tools/stocks.test.js +82 -0
- package/dist/tools/stocks.test.js.map +1 -0
- package/dist/tools/wallet.d.ts +2 -0
- package/dist/tools/wallet.d.ts.map +1 -0
- package/dist/tools/wallet.js +698 -0
- package/dist/tools/wallet.js.map +1 -0
- package/dist/tools/wallet.test.d.ts +2 -0
- package/dist/tools/wallet.test.d.ts.map +1 -0
- package/dist/tools/wallet.test.js +205 -0
- package/dist/tools/wallet.test.js.map +1 -0
- package/dist/ui.js +1 -1
- package/dist/ui.js.map +1 -1
- package/package.json +94 -42
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
export interface CpuInfo {
|
|
2
|
+
model: string;
|
|
3
|
+
chip?: string;
|
|
4
|
+
cores: number;
|
|
5
|
+
performanceCores?: number;
|
|
6
|
+
efficiencyCores?: number;
|
|
7
|
+
arch: string;
|
|
8
|
+
}
|
|
9
|
+
export interface GpuInfo {
|
|
10
|
+
model: string;
|
|
11
|
+
cores?: number;
|
|
12
|
+
vram?: string;
|
|
13
|
+
metal?: string;
|
|
14
|
+
cuda?: boolean;
|
|
15
|
+
driver?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface MemoryInfo {
|
|
18
|
+
total: string;
|
|
19
|
+
totalBytes: number;
|
|
20
|
+
free: string;
|
|
21
|
+
freeBytes: number;
|
|
22
|
+
used: string;
|
|
23
|
+
usedBytes: number;
|
|
24
|
+
pressure: 'low' | 'moderate' | 'high';
|
|
25
|
+
}
|
|
26
|
+
export interface DiskInfo {
|
|
27
|
+
total: string;
|
|
28
|
+
available: string;
|
|
29
|
+
used: string;
|
|
30
|
+
usedPercent: number;
|
|
31
|
+
filesystem: string;
|
|
32
|
+
}
|
|
33
|
+
export interface DisplayInfo {
|
|
34
|
+
name: string;
|
|
35
|
+
resolution: string;
|
|
36
|
+
type?: string;
|
|
37
|
+
main: boolean;
|
|
38
|
+
}
|
|
39
|
+
export interface BatteryInfo {
|
|
40
|
+
present: boolean;
|
|
41
|
+
percent?: number;
|
|
42
|
+
charging?: boolean;
|
|
43
|
+
timeRemaining?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface NetworkInfo {
|
|
46
|
+
hostname: string;
|
|
47
|
+
wifi?: string;
|
|
48
|
+
localIp?: string;
|
|
49
|
+
}
|
|
50
|
+
export interface DevTool {
|
|
51
|
+
name: string;
|
|
52
|
+
version: string;
|
|
53
|
+
}
|
|
54
|
+
export interface MachineProfile {
|
|
55
|
+
model?: string;
|
|
56
|
+
modelId?: string;
|
|
57
|
+
cpu: CpuInfo;
|
|
58
|
+
gpu: GpuInfo[];
|
|
59
|
+
memory: MemoryInfo;
|
|
60
|
+
disk: DiskInfo;
|
|
61
|
+
os: string;
|
|
62
|
+
osVersion: string;
|
|
63
|
+
kernel: string;
|
|
64
|
+
platform: string;
|
|
65
|
+
uptime: string;
|
|
66
|
+
displays: DisplayInfo[];
|
|
67
|
+
battery: BatteryInfo;
|
|
68
|
+
network: NetworkInfo;
|
|
69
|
+
shell: string;
|
|
70
|
+
user: string;
|
|
71
|
+
home: string;
|
|
72
|
+
devTools: DevTool[];
|
|
73
|
+
canRunLocalModels: boolean;
|
|
74
|
+
gpuAcceleration: 'metal' | 'cuda' | 'vulkan' | 'cpu-only';
|
|
75
|
+
recommendedModelSize: string;
|
|
76
|
+
probedAt: string;
|
|
77
|
+
}
|
|
78
|
+
export declare function probeMachine(): Promise<MachineProfile>;
|
|
79
|
+
/** Get the cached profile (null if probeMachine hasn't been called) */
|
|
80
|
+
export declare function getMachineProfile(): MachineProfile | null;
|
|
81
|
+
/** Force a fresh probe (clears cache) */
|
|
82
|
+
export declare function reprobeMachine(): Promise<MachineProfile>;
|
|
83
|
+
export declare function formatMachineProfile(p: MachineProfile): string;
|
|
84
|
+
export declare function formatMachineForPrompt(p: MachineProfile): string;
|
|
85
|
+
//# sourceMappingURL=machine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../src/machine.ts"],"names":[],"mappings":"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"}
|
package/dist/machine.js
ADDED
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
// kbot Machine Awareness — Full system profiler
|
|
2
|
+
//
|
|
3
|
+
// Probes hardware, OS, GPU, display, battery, network, dev tools.
|
|
4
|
+
// Cross-platform: macOS (system_profiler), Linux (/proc, lscpu, lspci).
|
|
5
|
+
// Cached after first probe — call probeMachine() once at startup.
|
|
6
|
+
//
|
|
7
|
+
// Usage:
|
|
8
|
+
// import { probeMachine, getMachineProfile } from './machine.js'
|
|
9
|
+
// await probeMachine() // probe once
|
|
10
|
+
// const profile = getMachineProfile() // read cached result
|
|
11
|
+
import { execSync } from 'node:child_process';
|
|
12
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
13
|
+
import { hostname, homedir, userInfo, totalmem, freemem, cpus, platform, arch, release } from 'node:os';
|
|
14
|
+
// ── Cache ──
|
|
15
|
+
let cached = null;
|
|
16
|
+
// ── Helpers ──
|
|
17
|
+
function exec(cmd, timeoutMs = 3000) {
|
|
18
|
+
try {
|
|
19
|
+
return execSync(cmd, { encoding: 'utf-8', timeout: timeoutMs, stdio: ['pipe', 'pipe', 'pipe'] }).trim();
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return '';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function parseBytes(str) {
|
|
26
|
+
const match = str.match(/([\d.]+)\s*(B|KB|MB|GB|TB|Ki|Mi|Gi|Ti)/i);
|
|
27
|
+
if (!match)
|
|
28
|
+
return 0;
|
|
29
|
+
const val = parseFloat(match[1]);
|
|
30
|
+
const unit = match[2].toUpperCase();
|
|
31
|
+
const multipliers = {
|
|
32
|
+
'B': 1, 'KB': 1024, 'MB': 1024 ** 2, 'GB': 1024 ** 3, 'TB': 1024 ** 4,
|
|
33
|
+
'KI': 1024, 'MI': 1024 ** 2, 'GI': 1024 ** 3, 'TI': 1024 ** 4,
|
|
34
|
+
};
|
|
35
|
+
return val * (multipliers[unit] || 1);
|
|
36
|
+
}
|
|
37
|
+
function formatBytes(bytes) {
|
|
38
|
+
if (bytes >= 1024 ** 4)
|
|
39
|
+
return `${(bytes / 1024 ** 4).toFixed(1)} TB`;
|
|
40
|
+
if (bytes >= 1024 ** 3)
|
|
41
|
+
return `${(bytes / 1024 ** 3).toFixed(1)} GB`;
|
|
42
|
+
if (bytes >= 1024 ** 2)
|
|
43
|
+
return `${(bytes / 1024 ** 2).toFixed(0)} MB`;
|
|
44
|
+
if (bytes >= 1024)
|
|
45
|
+
return `${(bytes / 1024).toFixed(0)} KB`;
|
|
46
|
+
return `${bytes} B`;
|
|
47
|
+
}
|
|
48
|
+
function formatUptime(seconds) {
|
|
49
|
+
const days = Math.floor(seconds / 86400);
|
|
50
|
+
const hours = Math.floor((seconds % 86400) / 3600);
|
|
51
|
+
const mins = Math.floor((seconds % 3600) / 60);
|
|
52
|
+
const parts = [];
|
|
53
|
+
if (days > 0)
|
|
54
|
+
parts.push(`${days}d`);
|
|
55
|
+
if (hours > 0)
|
|
56
|
+
parts.push(`${hours}h`);
|
|
57
|
+
if (mins > 0)
|
|
58
|
+
parts.push(`${mins}m`);
|
|
59
|
+
return parts.join(' ') || '<1m';
|
|
60
|
+
}
|
|
61
|
+
// ── macOS Probes ──
|
|
62
|
+
function probeMacHardware() {
|
|
63
|
+
const raw = exec('system_profiler SPHardwareDataType', 5000);
|
|
64
|
+
if (!raw)
|
|
65
|
+
return {};
|
|
66
|
+
const get = (label) => {
|
|
67
|
+
const match = raw.match(new RegExp(`${label}:\\s*(.+)`, 'i'));
|
|
68
|
+
return match ? match[1].trim() : '';
|
|
69
|
+
};
|
|
70
|
+
const coresMatch = get('Total Number of Cores').match(/(\d+)\s*\((\d+)\s*Performance.*?(\d+)\s*Efficiency\)/);
|
|
71
|
+
return {
|
|
72
|
+
model: get('Model Name') || undefined,
|
|
73
|
+
modelId: get('Model Identifier') || undefined,
|
|
74
|
+
chip: get('Chip') || undefined,
|
|
75
|
+
totalCores: coresMatch ? parseInt(coresMatch[1]) : parseInt(get('Total Number of Cores')) || undefined,
|
|
76
|
+
perfCores: coresMatch ? parseInt(coresMatch[2]) : undefined,
|
|
77
|
+
effCores: coresMatch ? parseInt(coresMatch[3]) : undefined,
|
|
78
|
+
memoryGB: parseInt(get('Memory')) || undefined,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function probeMacGpu() {
|
|
82
|
+
const raw = exec('system_profiler SPDisplaysDataType', 5000);
|
|
83
|
+
if (!raw)
|
|
84
|
+
return [];
|
|
85
|
+
const gpus = [];
|
|
86
|
+
// Split by GPU entries — each starts with a chipset name followed by a colon at 4-space indent
|
|
87
|
+
const sections = raw.split(/\n (?=\S.*:)/).filter(s => s.includes('Chipset Model') || s.includes('Vendor'));
|
|
88
|
+
// Simpler: extract all GPU blocks
|
|
89
|
+
const chipsetMatches = raw.match(/Chipset Model:\s*(.+)/g) || [];
|
|
90
|
+
const coreMatches = raw.match(/Total Number of Cores:\s*(\d+)/g) || [];
|
|
91
|
+
const metalMatches = raw.match(/Metal Support:\s*(.+)/g) || [];
|
|
92
|
+
for (let i = 0; i < chipsetMatches.length; i++) {
|
|
93
|
+
const model = chipsetMatches[i]?.replace('Chipset Model:', '').trim() || 'Unknown';
|
|
94
|
+
const cores = coreMatches[i] ? parseInt(coreMatches[i].replace(/\D/g, '')) : undefined;
|
|
95
|
+
const metal = metalMatches[i]?.replace('Metal Support:', '').trim() || undefined;
|
|
96
|
+
gpus.push({ model, cores, metal });
|
|
97
|
+
}
|
|
98
|
+
return gpus.length > 0 ? gpus : [{ model: 'Unknown' }];
|
|
99
|
+
}
|
|
100
|
+
function probeMacDisplays() {
|
|
101
|
+
const raw = exec('system_profiler SPDisplaysDataType', 5000);
|
|
102
|
+
if (!raw)
|
|
103
|
+
return [];
|
|
104
|
+
const displays = [];
|
|
105
|
+
const displayBlocks = raw.split(/\n (?=\S.*:)/);
|
|
106
|
+
for (const block of displayBlocks) {
|
|
107
|
+
const nameMatch = block.match(/^\s*(.+?):\s*$/m);
|
|
108
|
+
const resMatch = block.match(/Resolution:\s*(.+)/i);
|
|
109
|
+
const typeMatch = block.match(/Display Type:\s*(.+)/i);
|
|
110
|
+
const mainMatch = block.match(/Main Display:\s*(Yes)/i);
|
|
111
|
+
if (resMatch) {
|
|
112
|
+
displays.push({
|
|
113
|
+
name: nameMatch ? nameMatch[1].trim() : 'Display',
|
|
114
|
+
resolution: resMatch[1].trim(),
|
|
115
|
+
type: typeMatch ? typeMatch[1].trim() : undefined,
|
|
116
|
+
main: !!mainMatch,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return displays;
|
|
121
|
+
}
|
|
122
|
+
function probeMacBattery() {
|
|
123
|
+
const raw = exec('pmset -g batt');
|
|
124
|
+
if (!raw)
|
|
125
|
+
return { present: false };
|
|
126
|
+
const percentMatch = raw.match(/(\d+)%/);
|
|
127
|
+
const chargingMatch = raw.match(/(charging|discharging|charged|AC Power)/i);
|
|
128
|
+
const timeMatch = raw.match(/([\d:]+)\s*remaining/);
|
|
129
|
+
if (!percentMatch)
|
|
130
|
+
return { present: false };
|
|
131
|
+
return {
|
|
132
|
+
present: true,
|
|
133
|
+
percent: parseInt(percentMatch[1]),
|
|
134
|
+
charging: chargingMatch ? /charging|AC Power/i.test(chargingMatch[1]) && !/discharging/i.test(chargingMatch[1]) : undefined,
|
|
135
|
+
timeRemaining: timeMatch ? timeMatch[1] : undefined,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function probeMacNetwork() {
|
|
139
|
+
const wifi = exec('networksetup -getairportnetwork en0');
|
|
140
|
+
const wifiName = wifi.match(/Current Wi-Fi Network:\s*(.+)/i)?.[1] ||
|
|
141
|
+
(wifi.includes('not associated') ? 'not connected' : undefined);
|
|
142
|
+
const ip = exec("ipconfig getifaddr en0 2>/dev/null || ipconfig getifaddr en1 2>/dev/null");
|
|
143
|
+
return { wifi: wifiName, localIp: ip || undefined };
|
|
144
|
+
}
|
|
145
|
+
function probeMacOs() {
|
|
146
|
+
const productName = exec('sw_vers -productName') || 'macOS';
|
|
147
|
+
const productVersion = exec('sw_vers -productVersion') || 'unknown';
|
|
148
|
+
return {
|
|
149
|
+
os: `${productName} ${productVersion}`,
|
|
150
|
+
osVersion: productVersion,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
// ── Linux Probes ──
|
|
154
|
+
function probeLinuxCpu() {
|
|
155
|
+
const model = exec("grep -m1 'model name' /proc/cpuinfo")?.split(':')?.[1]?.trim() || 'Unknown';
|
|
156
|
+
const cores = parseInt(exec('nproc') || '0') || cpus().length;
|
|
157
|
+
return { model, cores, arch: arch() };
|
|
158
|
+
}
|
|
159
|
+
function probeLinuxGpu() {
|
|
160
|
+
const lspci = exec('lspci 2>/dev/null | grep -iE "VGA|3D|Display"');
|
|
161
|
+
if (!lspci)
|
|
162
|
+
return [{ model: 'Unknown' }];
|
|
163
|
+
const gpus = [];
|
|
164
|
+
for (const line of lspci.split('\n')) {
|
|
165
|
+
const match = line.match(/:\s*(.+)/);
|
|
166
|
+
if (match) {
|
|
167
|
+
const model = match[1].trim();
|
|
168
|
+
const cuda = /nvidia/i.test(model);
|
|
169
|
+
gpus.push({ model, cuda });
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
// Check for NVIDIA driver
|
|
173
|
+
const nvidiaSmi = exec('nvidia-smi --query-gpu=driver_version --format=csv,noheader 2>/dev/null');
|
|
174
|
+
if (nvidiaSmi && gpus.length > 0) {
|
|
175
|
+
gpus[0].driver = nvidiaSmi.split('\n')[0];
|
|
176
|
+
gpus[0].cuda = true;
|
|
177
|
+
// Get VRAM
|
|
178
|
+
const vram = exec('nvidia-smi --query-gpu=memory.total --format=csv,noheader 2>/dev/null');
|
|
179
|
+
if (vram)
|
|
180
|
+
gpus[0].vram = vram.split('\n')[0].trim();
|
|
181
|
+
}
|
|
182
|
+
return gpus.length > 0 ? gpus : [{ model: 'Unknown' }];
|
|
183
|
+
}
|
|
184
|
+
function probeLinuxDisplays() {
|
|
185
|
+
const xrandr = exec('xrandr --current 2>/dev/null');
|
|
186
|
+
if (!xrandr)
|
|
187
|
+
return [];
|
|
188
|
+
const displays = [];
|
|
189
|
+
const lines = xrandr.split('\n');
|
|
190
|
+
for (const line of lines) {
|
|
191
|
+
const match = line.match(/^(\S+)\s+connected\s+(primary\s+)?(\d+x\d+)/);
|
|
192
|
+
if (match) {
|
|
193
|
+
displays.push({
|
|
194
|
+
name: match[1],
|
|
195
|
+
resolution: match[3],
|
|
196
|
+
main: !!match[2],
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return displays;
|
|
201
|
+
}
|
|
202
|
+
function probeLinuxBattery() {
|
|
203
|
+
const capacityPath = '/sys/class/power_supply/BAT0/capacity';
|
|
204
|
+
const statusPath = '/sys/class/power_supply/BAT0/status';
|
|
205
|
+
if (!existsSync(capacityPath))
|
|
206
|
+
return { present: false };
|
|
207
|
+
try {
|
|
208
|
+
const percent = parseInt(readFileSync(capacityPath, 'utf-8').trim());
|
|
209
|
+
const status = existsSync(statusPath) ? readFileSync(statusPath, 'utf-8').trim() : '';
|
|
210
|
+
return {
|
|
211
|
+
present: true,
|
|
212
|
+
percent,
|
|
213
|
+
charging: status === 'Charging',
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
return { present: false };
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
function probeLinuxNetwork() {
|
|
221
|
+
const wifi = exec('iwgetid -r 2>/dev/null') || exec('nmcli -t -f active,ssid dev wifi 2>/dev/null | grep "^yes"')?.split(':')?.[1];
|
|
222
|
+
const ip = exec("hostname -I 2>/dev/null")?.split(' ')[0];
|
|
223
|
+
return {
|
|
224
|
+
wifi: wifi || 'not connected',
|
|
225
|
+
localIp: ip || undefined,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
function probeLinuxOs() {
|
|
229
|
+
const prettyName = exec("grep PRETTY_NAME /etc/os-release 2>/dev/null")?.replace(/PRETTY_NAME=["']?/, '').replace(/["']$/, '') || 'Linux';
|
|
230
|
+
const version = exec("grep VERSION_ID /etc/os-release 2>/dev/null")?.replace(/VERSION_ID=["']?/, '').replace(/["']$/, '') || release();
|
|
231
|
+
return { os: prettyName, osVersion: version };
|
|
232
|
+
}
|
|
233
|
+
// ── Disk ──
|
|
234
|
+
function probeDisk() {
|
|
235
|
+
if (platform() === 'darwin') {
|
|
236
|
+
const raw = exec('df -h /');
|
|
237
|
+
const line = raw.split('\n')[1];
|
|
238
|
+
if (line) {
|
|
239
|
+
const parts = line.split(/\s+/);
|
|
240
|
+
return {
|
|
241
|
+
filesystem: parts[0] || '/',
|
|
242
|
+
total: parts[1] || 'unknown',
|
|
243
|
+
used: parts[2] || 'unknown',
|
|
244
|
+
available: parts[3] || 'unknown',
|
|
245
|
+
usedPercent: parseInt(parts[4]) || 0,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
const raw = exec('df -h / 2>/dev/null');
|
|
251
|
+
const line = raw.split('\n')[1];
|
|
252
|
+
if (line) {
|
|
253
|
+
const parts = line.split(/\s+/);
|
|
254
|
+
return {
|
|
255
|
+
filesystem: parts[0] || '/',
|
|
256
|
+
total: parts[1] || 'unknown',
|
|
257
|
+
used: parts[2] || 'unknown',
|
|
258
|
+
available: parts[3] || 'unknown',
|
|
259
|
+
usedPercent: parseInt(parts[4]) || 0,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return { filesystem: '/', total: 'unknown', available: 'unknown', used: 'unknown', usedPercent: 0 };
|
|
264
|
+
}
|
|
265
|
+
// ── Dev Tools ──
|
|
266
|
+
function probeDevTools() {
|
|
267
|
+
const tools = [];
|
|
268
|
+
const checks = [
|
|
269
|
+
{ name: 'Node.js', cmd: 'node -v' },
|
|
270
|
+
{ name: 'npm', cmd: 'npm -v', parse: v => `v${v}` },
|
|
271
|
+
{ name: 'Python', cmd: 'python3 --version', parse: v => v.replace('Python ', 'v') },
|
|
272
|
+
{ name: 'Git', cmd: 'git --version', parse: v => v.replace('git version ', 'v').split(' ')[0] },
|
|
273
|
+
{ name: 'Docker', cmd: 'docker --version', parse: v => 'v' + (v.match(/(\d+\.\d+\.\d+)/)?.[1] || v) },
|
|
274
|
+
{ name: 'Homebrew', cmd: 'brew --version', parse: v => 'v' + (v.match(/(\d+\.\d+\.\d+)/)?.[1] || v) },
|
|
275
|
+
{ name: 'Rust', cmd: 'rustc --version', parse: v => 'v' + (v.match(/(\d+\.\d+\.\d+)/)?.[1] || v) },
|
|
276
|
+
{ name: 'Go', cmd: 'go version', parse: v => v.match(/go(\d+\.\d+\.\d+)/)?.[0] || v },
|
|
277
|
+
{ name: 'Deno', cmd: 'deno --version', parse: v => 'v' + (v.match(/deno\s+(\d+\.\d+\.\d+)/)?.[1] || v) },
|
|
278
|
+
{ name: 'Bun', cmd: 'bun --version', parse: v => `v${v}` },
|
|
279
|
+
{ name: 'pnpm', cmd: 'pnpm --version', parse: v => `v${v}` },
|
|
280
|
+
{ name: 'Supabase CLI', cmd: 'npx supabase --version 2>/dev/null', parse: v => `v${v}` },
|
|
281
|
+
{ name: 'Xcode', cmd: 'xcodebuild -version 2>/dev/null', parse: v => v.split('\n')[0]?.replace('Xcode ', 'v') || v },
|
|
282
|
+
{ name: 'Swift', cmd: 'swift --version 2>/dev/null', parse: v => 'v' + (v.match(/(\d+\.\d+(\.\d+)?)/)?.[1] || v) },
|
|
283
|
+
{ name: 'FFmpeg', cmd: 'ffmpeg -version 2>/dev/null', parse: v => 'v' + (v.match(/version\s+(\S+)/)?.[1] || v) },
|
|
284
|
+
{ name: 'Ollama', cmd: 'ollama --version 2>/dev/null', parse: v => 'v' + (v.match(/(\d+\.\d+\.\d+)/)?.[1] || v) },
|
|
285
|
+
];
|
|
286
|
+
for (const { name, cmd, parse } of checks) {
|
|
287
|
+
const raw = exec(cmd, 2000);
|
|
288
|
+
if (raw && !raw.includes('not found') && !raw.includes('No such file')) {
|
|
289
|
+
const version = parse ? parse(raw) : raw;
|
|
290
|
+
tools.push({ name, version });
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return tools;
|
|
294
|
+
}
|
|
295
|
+
// ── Memory pressure ──
|
|
296
|
+
function getMemoryPressure(freeBytes, totalBytes) {
|
|
297
|
+
const freePercent = freeBytes / totalBytes;
|
|
298
|
+
if (freePercent > 0.25)
|
|
299
|
+
return 'low';
|
|
300
|
+
if (freePercent > 0.10)
|
|
301
|
+
return 'moderate';
|
|
302
|
+
return 'high';
|
|
303
|
+
}
|
|
304
|
+
// ── GPU acceleration detection ──
|
|
305
|
+
function detectGpuAcceleration(gpus) {
|
|
306
|
+
if (platform() === 'darwin') {
|
|
307
|
+
if (gpus.some(g => g.metal))
|
|
308
|
+
return 'metal';
|
|
309
|
+
}
|
|
310
|
+
if (gpus.some(g => g.cuda))
|
|
311
|
+
return 'cuda';
|
|
312
|
+
// Check for Vulkan support on Linux
|
|
313
|
+
if (platform() === 'linux' && exec('vulkaninfo --summary 2>/dev/null'))
|
|
314
|
+
return 'vulkan';
|
|
315
|
+
return 'cpu-only';
|
|
316
|
+
}
|
|
317
|
+
// ── Model size recommendation ──
|
|
318
|
+
function recommendModelSize(totalMemoryGB, gpuAccel) {
|
|
319
|
+
// Conservative: leave room for OS + apps
|
|
320
|
+
const availableForModel = totalMemoryGB * 0.6;
|
|
321
|
+
if (availableForModel >= 40)
|
|
322
|
+
return '70B';
|
|
323
|
+
if (availableForModel >= 20)
|
|
324
|
+
return '34B';
|
|
325
|
+
if (availableForModel >= 12)
|
|
326
|
+
return '14B';
|
|
327
|
+
if (availableForModel >= 6)
|
|
328
|
+
return '7B';
|
|
329
|
+
if (availableForModel >= 3)
|
|
330
|
+
return '3B';
|
|
331
|
+
return '1B';
|
|
332
|
+
}
|
|
333
|
+
// ── Main Probe ──
|
|
334
|
+
export async function probeMachine() {
|
|
335
|
+
if (cached)
|
|
336
|
+
return cached;
|
|
337
|
+
const plat = platform();
|
|
338
|
+
const totalBytes = totalmem();
|
|
339
|
+
const freeBytes = freemem();
|
|
340
|
+
const usedBytes = totalBytes - freeBytes;
|
|
341
|
+
const totalGB = totalBytes / (1024 ** 3);
|
|
342
|
+
let cpu;
|
|
343
|
+
let gpus;
|
|
344
|
+
let displays;
|
|
345
|
+
let battery;
|
|
346
|
+
let net;
|
|
347
|
+
let osInfo;
|
|
348
|
+
let model;
|
|
349
|
+
let modelId;
|
|
350
|
+
if (plat === 'darwin') {
|
|
351
|
+
const hw = probeMacHardware();
|
|
352
|
+
cpu = {
|
|
353
|
+
model: hw.chip || cpus()[0]?.model || 'Unknown',
|
|
354
|
+
chip: hw.chip,
|
|
355
|
+
cores: hw.totalCores || cpus().length,
|
|
356
|
+
performanceCores: hw.perfCores,
|
|
357
|
+
efficiencyCores: hw.effCores,
|
|
358
|
+
arch: arch(),
|
|
359
|
+
};
|
|
360
|
+
model = hw.model;
|
|
361
|
+
modelId = hw.modelId;
|
|
362
|
+
gpus = probeMacGpu();
|
|
363
|
+
displays = probeMacDisplays();
|
|
364
|
+
battery = probeMacBattery();
|
|
365
|
+
net = probeMacNetwork();
|
|
366
|
+
osInfo = probeMacOs();
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
cpu = probeLinuxCpu();
|
|
370
|
+
gpus = probeLinuxGpu();
|
|
371
|
+
displays = probeLinuxDisplays();
|
|
372
|
+
battery = probeLinuxBattery();
|
|
373
|
+
net = probeLinuxNetwork();
|
|
374
|
+
osInfo = probeLinuxOs();
|
|
375
|
+
}
|
|
376
|
+
const gpuAccel = detectGpuAcceleration(gpus);
|
|
377
|
+
const devTools = probeDevTools();
|
|
378
|
+
// Uptime
|
|
379
|
+
const uptimeSeconds = plat === 'darwin'
|
|
380
|
+
? (() => {
|
|
381
|
+
const bootTime = exec("sysctl -n kern.boottime");
|
|
382
|
+
const match = bootTime.match(/sec\s*=\s*(\d+)/);
|
|
383
|
+
return match ? Math.floor(Date.now() / 1000) - parseInt(match[1]) : 0;
|
|
384
|
+
})()
|
|
385
|
+
: (() => {
|
|
386
|
+
const raw = exec('cat /proc/uptime 2>/dev/null');
|
|
387
|
+
return raw ? Math.floor(parseFloat(raw.split(' ')[0])) : 0;
|
|
388
|
+
})();
|
|
389
|
+
const profile = {
|
|
390
|
+
model,
|
|
391
|
+
modelId,
|
|
392
|
+
cpu,
|
|
393
|
+
gpu: gpus,
|
|
394
|
+
memory: {
|
|
395
|
+
total: formatBytes(totalBytes),
|
|
396
|
+
totalBytes,
|
|
397
|
+
free: formatBytes(freeBytes),
|
|
398
|
+
freeBytes,
|
|
399
|
+
used: formatBytes(usedBytes),
|
|
400
|
+
usedBytes,
|
|
401
|
+
pressure: getMemoryPressure(freeBytes, totalBytes),
|
|
402
|
+
},
|
|
403
|
+
disk: probeDisk(),
|
|
404
|
+
os: osInfo.os,
|
|
405
|
+
osVersion: osInfo.osVersion,
|
|
406
|
+
kernel: release(),
|
|
407
|
+
platform: plat,
|
|
408
|
+
uptime: formatUptime(uptimeSeconds),
|
|
409
|
+
displays,
|
|
410
|
+
battery,
|
|
411
|
+
network: {
|
|
412
|
+
hostname: hostname(),
|
|
413
|
+
wifi: net.wifi,
|
|
414
|
+
localIp: net.localIp,
|
|
415
|
+
},
|
|
416
|
+
shell: process.env.SHELL || 'unknown',
|
|
417
|
+
user: userInfo().username,
|
|
418
|
+
home: homedir(),
|
|
419
|
+
devTools,
|
|
420
|
+
canRunLocalModels: gpuAccel !== 'cpu-only' || totalGB >= 8,
|
|
421
|
+
gpuAcceleration: gpuAccel,
|
|
422
|
+
recommendedModelSize: recommendModelSize(totalGB, gpuAccel),
|
|
423
|
+
probedAt: new Date().toISOString(),
|
|
424
|
+
};
|
|
425
|
+
cached = profile;
|
|
426
|
+
return profile;
|
|
427
|
+
}
|
|
428
|
+
/** Get the cached profile (null if probeMachine hasn't been called) */
|
|
429
|
+
export function getMachineProfile() {
|
|
430
|
+
return cached;
|
|
431
|
+
}
|
|
432
|
+
/** Force a fresh probe (clears cache) */
|
|
433
|
+
export async function reprobeMachine() {
|
|
434
|
+
cached = null;
|
|
435
|
+
return probeMachine();
|
|
436
|
+
}
|
|
437
|
+
// ── Formatted output (for `kbot machine` command) ──
|
|
438
|
+
export function formatMachineProfile(p) {
|
|
439
|
+
const lines = [];
|
|
440
|
+
// Header
|
|
441
|
+
lines.push('');
|
|
442
|
+
lines.push(` ${p.model || 'Machine'}${p.modelId ? ` (${p.modelId})` : ''}`);
|
|
443
|
+
lines.push(` ${'─'.repeat(54)}`);
|
|
444
|
+
// Hardware
|
|
445
|
+
lines.push('');
|
|
446
|
+
lines.push(' Hardware');
|
|
447
|
+
lines.push(` CPU ${p.cpu.model}`);
|
|
448
|
+
if (p.cpu.performanceCores) {
|
|
449
|
+
lines.push(` Cores ${p.cpu.cores} (${p.cpu.performanceCores}P + ${p.cpu.efficiencyCores}E)`);
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
lines.push(` Cores ${p.cpu.cores}`);
|
|
453
|
+
}
|
|
454
|
+
lines.push(` Arch ${p.cpu.arch}`);
|
|
455
|
+
for (const gpu of p.gpu) {
|
|
456
|
+
lines.push(` GPU ${gpu.model}${gpu.cores ? ` (${gpu.cores} cores)` : ''}`);
|
|
457
|
+
if (gpu.metal)
|
|
458
|
+
lines.push(` Metal ${gpu.metal}`);
|
|
459
|
+
if (gpu.cuda)
|
|
460
|
+
lines.push(` CUDA yes${gpu.driver ? ` (driver ${gpu.driver})` : ''}`);
|
|
461
|
+
if (gpu.vram)
|
|
462
|
+
lines.push(` VRAM ${gpu.vram}`);
|
|
463
|
+
}
|
|
464
|
+
lines.push(` Memory ${p.memory.total} (${p.memory.free} free, pressure: ${p.memory.pressure})`);
|
|
465
|
+
lines.push(` Disk ${p.disk.total} total, ${p.disk.available} available (${p.disk.usedPercent}% used)`);
|
|
466
|
+
// Displays
|
|
467
|
+
if (p.displays.length > 0) {
|
|
468
|
+
lines.push('');
|
|
469
|
+
lines.push(' Displays');
|
|
470
|
+
for (const d of p.displays) {
|
|
471
|
+
lines.push(` ${d.name} ${d.resolution}${d.type ? ` — ${d.type}` : ''}${d.main ? ' (main)' : ''}`);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
// OS
|
|
475
|
+
lines.push('');
|
|
476
|
+
lines.push(' System');
|
|
477
|
+
lines.push(` OS ${p.os}`);
|
|
478
|
+
lines.push(` Kernel ${p.kernel}`);
|
|
479
|
+
lines.push(` Uptime ${p.uptime}`);
|
|
480
|
+
lines.push(` Shell ${p.shell.split('/').pop()}`);
|
|
481
|
+
lines.push(` User ${p.user} (${p.home})`);
|
|
482
|
+
// Battery
|
|
483
|
+
if (p.battery.present) {
|
|
484
|
+
const status = p.battery.charging ? 'charging' : 'discharging';
|
|
485
|
+
const time = p.battery.timeRemaining ? `, ${p.battery.timeRemaining} remaining` : '';
|
|
486
|
+
lines.push(` Battery ${p.battery.percent}% ${status}${time}`);
|
|
487
|
+
}
|
|
488
|
+
// Network
|
|
489
|
+
lines.push(` Hostname ${p.network.hostname}`);
|
|
490
|
+
if (p.network.wifi)
|
|
491
|
+
lines.push(` WiFi ${p.network.wifi}`);
|
|
492
|
+
if (p.network.localIp)
|
|
493
|
+
lines.push(` Local IP ${p.network.localIp}`);
|
|
494
|
+
// Dev tools
|
|
495
|
+
if (p.devTools.length > 0) {
|
|
496
|
+
lines.push('');
|
|
497
|
+
lines.push(' Dev Tools');
|
|
498
|
+
// Two-column layout
|
|
499
|
+
const maxNameLen = Math.max(...p.devTools.map(t => t.name.length));
|
|
500
|
+
for (const tool of p.devTools) {
|
|
501
|
+
lines.push(` ${tool.name.padEnd(maxNameLen + 2)}${tool.version}`);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
// AI capabilities
|
|
505
|
+
lines.push('');
|
|
506
|
+
lines.push(' AI Capabilities');
|
|
507
|
+
lines.push(` Acceleration ${p.gpuAcceleration}`);
|
|
508
|
+
lines.push(` Local models ${p.canRunLocalModels ? 'yes' : 'no'}`);
|
|
509
|
+
lines.push(` Recommended up to ${p.recommendedModelSize} parameters`);
|
|
510
|
+
lines.push('');
|
|
511
|
+
lines.push(` ${'─'.repeat(54)}`);
|
|
512
|
+
lines.push(` Probed at ${p.probedAt}`);
|
|
513
|
+
lines.push('');
|
|
514
|
+
return lines.join('\n');
|
|
515
|
+
}
|
|
516
|
+
// ── Compact format for system prompt injection ──
|
|
517
|
+
export function formatMachineForPrompt(p) {
|
|
518
|
+
const parts = ['[Machine Context]'];
|
|
519
|
+
parts.push(`Machine: ${p.model || 'Unknown'}${p.cpu.chip ? ` — ${p.cpu.chip}` : ` — ${p.cpu.model}`}`);
|
|
520
|
+
parts.push(`CPU: ${p.cpu.cores} cores${p.cpu.performanceCores ? ` (${p.cpu.performanceCores}P + ${p.cpu.efficiencyCores}E)` : ''}, ${p.cpu.arch}`);
|
|
521
|
+
const gpuSummary = p.gpu.map(g => `${g.model}${g.cores ? ` (${g.cores} cores)` : ''}`).join(', ');
|
|
522
|
+
parts.push(`GPU: ${gpuSummary}`);
|
|
523
|
+
parts.push(`Memory: ${p.memory.total} (${p.memory.free} free, ${p.memory.pressure} pressure)`);
|
|
524
|
+
parts.push(`Disk: ${p.disk.available} available of ${p.disk.total}`);
|
|
525
|
+
parts.push(`OS: ${p.os} (${p.kernel})`);
|
|
526
|
+
if (p.displays.length > 0) {
|
|
527
|
+
parts.push(`Display: ${p.displays.map(d => `${d.resolution}${d.type ? ` ${d.type}` : ''}`).join(', ')}`);
|
|
528
|
+
}
|
|
529
|
+
if (p.battery.present) {
|
|
530
|
+
parts.push(`Battery: ${p.battery.percent}% ${p.battery.charging ? 'charging' : 'discharging'}`);
|
|
531
|
+
}
|
|
532
|
+
parts.push(`GPU accel: ${p.gpuAcceleration} — local models up to ${p.recommendedModelSize}`);
|
|
533
|
+
const toolNames = p.devTools.map(t => `${t.name} ${t.version}`).join(', ');
|
|
534
|
+
if (toolNames)
|
|
535
|
+
parts.push(`Tools: ${toolNames}`);
|
|
536
|
+
return parts.join('\n');
|
|
537
|
+
}
|
|
538
|
+
//# sourceMappingURL=machine.js.map
|