@pixelkit-labs/cli 1.5.5 → 1.5.6
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/LICENSE +21 -21
- package/README.md +70 -69
- package/build/index.d.ts +1 -1
- package/build/index.js +209 -16
- package/index.ts +715 -515
- package/package.json +50 -50
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
The MIT License (MIT)
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Traves Theberge
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Traves Theberge
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,69 +1,70 @@
|
|
|
1
|
-
# @pixelkit-labs/cli
|
|
2
|
-
|
|
3
|
-
Command-line diagnostics for [PixelKit](https://www.npmjs.com/package/@pixelkit-labs/sdk).
|
|
4
|
-
`pixelkit doctor
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
`
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
1
|
+
# @pixelkit-labs/cli
|
|
2
|
+
|
|
3
|
+
Command-line diagnostics and autonomous hardware agents for [PixelKit](https://www.npmjs.com/package/@pixelkit-labs/sdk).
|
|
4
|
+
- `pixelkit doctor`: answers "why is everything showing —?" before you file an issue.
|
|
5
|
+
- `pixelkit agent`: runs autonomous on-device hardware telemetry triage (CPU, battery, thermals, AICore) and queries the Google Gen AI hardware agent.
|
|
6
|
+
|
|
7
|
+
PixelKit hooks report `source: 'unavailable'` and render an em dash when a reading cannot be taken
|
|
8
|
+
on real hardware. That is correct behaviour, but on the wrong device, without a development build,
|
|
9
|
+
or without the native packages installed, every hook looks that way at once. `doctor` and `agent`
|
|
10
|
+
run the checks and diagnostics an expert systems engineer would run by hand.
|
|
11
|
+
|
|
12
|
+
**Zero third-party dependencies.** It uses only Node's `child_process`, `util`, and native `fetch`.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# Verify environment readiness
|
|
16
|
+
npx @pixelkit-labs/cli doctor
|
|
17
|
+
|
|
18
|
+
# Run autonomous hardware diagnostic triage
|
|
19
|
+
npx @pixelkit-labs/cli agent --diagnose
|
|
20
|
+
|
|
21
|
+
# Query the hardware agent with custom diagnostic prompt
|
|
22
|
+
npx @pixelkit-labs/cli agent --query "Check battery wear and thermal throttling headroom"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## What it checks
|
|
26
|
+
|
|
27
|
+
1. **adb on PATH and exactly one device connected** (`adb devices`). If several devices are
|
|
28
|
+
connected, they are listed and you are told to pass `--serial`.
|
|
29
|
+
2. **The connected device's identity** — manufacturer, model, Android release, SDK int
|
|
30
|
+
(`adb shell getprop`). States plainly whether it is a Pixel, because most hooks report
|
|
31
|
+
`unavailable` otherwise.
|
|
32
|
+
3. **Whether a PixelKit-based development build is installed** (`adb shell pm path <package>`),
|
|
33
|
+
keyed off `--package` (default `com.pixelkit.sdk`). Expo Go can never satisfy this: the Kotlin
|
|
34
|
+
Expo Modules (`@pixelkit-labs/native`, `@pixelkit-labs/mlkit`) must be compiled in.
|
|
35
|
+
4. **Whether `@pixelkit-labs/native` and `@pixelkit-labs/mlkit` resolve from the current project**
|
|
36
|
+
(`require.resolve` from the working directory), and which hook groups are therefore available.
|
|
37
|
+
A missing `@pixelkit-labs/mlkit` is reported as informational, not a failure — it is the opt-in ML
|
|
38
|
+
Kit package.
|
|
39
|
+
5. **Whether AICore is present on the device** (`adb shell pm list packages`, matched for
|
|
40
|
+
"aicore"), which Gemini Nano needs. Not-applicable on a non-Pixel.
|
|
41
|
+
6. **Whether `adb reverse tcp:8081 tcp:8081` is set**, so a development client can reach Metro on
|
|
42
|
+
localhost.
|
|
43
|
+
|
|
44
|
+
Each check is reported as `PASS`, `FAIL`, `N/A` or `UNKN` ("could not be determined" — the check
|
|
45
|
+
itself could not be run, for example because adb is missing or the device went offline).
|
|
46
|
+
`doctor` never guesses a result: an inconclusive check is reported as such, the same discipline
|
|
47
|
+
PixelKit hooks use for `source: 'unavailable'`.
|
|
48
|
+
|
|
49
|
+
## Options
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
pixelkit doctor [--package <id>] [--serial <serial>]
|
|
53
|
+
|
|
54
|
+
--package <id> Application id of the installed PixelKit development build
|
|
55
|
+
(default: com.pixelkit.sdk)
|
|
56
|
+
--serial <id> adb serial to target when more than one device is connected
|
|
57
|
+
-h, --help Show help
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Exit code
|
|
61
|
+
|
|
62
|
+
`0` when every check passed or was not applicable. `1` when any check failed, or could not be
|
|
63
|
+
determined at all.
|
|
64
|
+
|
|
65
|
+
## Documentation
|
|
66
|
+
|
|
67
|
+
[https://pixelkit-labs.github.io/pixelkit-docs/](https://pixelkit-labs.github.io/pixelkit-docs/) covers the hooks this command
|
|
68
|
+
diagnoses: each one's inputs, outputs, and what `source: 'unavailable'` means for it.
|
|
69
|
+
|
|
70
|
+
MIT
|
package/build/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* @file
|
|
3
|
+
* @file index.ts
|
|
4
4
|
* @description `pixelkit doctor`: the first and only command of `@pixelkit-labs/cli`. PixelKit hooks
|
|
5
5
|
* report `source: 'unavailable'` and render an em dash when a reading cannot be taken on real
|
|
6
6
|
* hardware; on the wrong device, without a development build, or without the native packages
|
package/build/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
/**
|
|
4
|
-
* @file
|
|
4
|
+
* @file index.ts
|
|
5
5
|
* @description `pixelkit doctor`: the first and only command of `@pixelkit-labs/cli`. PixelKit hooks
|
|
6
6
|
* report `source: 'unavailable'` and render an em dash when a reading cannot be taken on real
|
|
7
7
|
* hardware; on the wrong device, without a development build, or without the native packages
|
|
@@ -351,6 +351,21 @@ function parseArgs(argv) {
|
|
|
351
351
|
else if (arg.startsWith('--serial=')) {
|
|
352
352
|
flags.serial = arg.slice('--serial='.length);
|
|
353
353
|
}
|
|
354
|
+
else if (arg === '--diagnose') {
|
|
355
|
+
flags.diagnose = true;
|
|
356
|
+
}
|
|
357
|
+
else if (arg === '--query' || arg === '-q') {
|
|
358
|
+
flags.query = argv[++i];
|
|
359
|
+
}
|
|
360
|
+
else if (arg.startsWith('--query=')) {
|
|
361
|
+
flags.query = arg.slice('--query='.length);
|
|
362
|
+
}
|
|
363
|
+
else if (arg === '--model' || arg === '-m') {
|
|
364
|
+
flags.model = argv[++i];
|
|
365
|
+
}
|
|
366
|
+
else if (arg.startsWith('--model=')) {
|
|
367
|
+
flags.model = arg.slice('--model='.length);
|
|
368
|
+
}
|
|
354
369
|
else if (arg === '--help' || arg === '-h') {
|
|
355
370
|
flags.help = true;
|
|
356
371
|
}
|
|
@@ -361,15 +376,23 @@ function parseArgs(argv) {
|
|
|
361
376
|
return { command, flags };
|
|
362
377
|
}
|
|
363
378
|
function printUsage() {
|
|
364
|
-
console.log(`${ANSI.bold}pixelkit
|
|
365
|
-
|
|
366
|
-
Usage:
|
|
367
|
-
pixelkit doctor [--package <id>] [--serial <serial>]
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
379
|
+
console.log(`${ANSI.bold}pixelkit${ANSI.reset} - developer tooling and diagnostics for Google Pixel hardware
|
|
380
|
+
|
|
381
|
+
Usage:
|
|
382
|
+
pixelkit doctor [--package <id>] [--serial <serial>]
|
|
383
|
+
pixelkit agent [--diagnose] [--query <prompt>] [--model <model>] [--serial <serial>]
|
|
384
|
+
|
|
385
|
+
Commands:
|
|
386
|
+
doctor Diagnose why PixelKit hooks might report source: "unavailable"
|
|
387
|
+
agent Run autonomous hardware diagnostics and query the device agent
|
|
388
|
+
|
|
389
|
+
Options:
|
|
390
|
+
--diagnose Run complete hardware diagnostic triage (CPU, battery, thermals, AICore)
|
|
391
|
+
--query, -q Query the hardware agent with a specific diagnostic question
|
|
392
|
+
--model, -m Gemini model for cloud reasoning (default: gemini-2.5-flash)
|
|
393
|
+
--package <id> Application id of the installed PixelKit development build (default: com.pixelkit.sdk)
|
|
394
|
+
--serial <id> adb serial to target when more than one device is connected
|
|
395
|
+
-h, --help Show this help
|
|
373
396
|
`);
|
|
374
397
|
}
|
|
375
398
|
function printResult(r) {
|
|
@@ -377,6 +400,172 @@ function printResult(r) {
|
|
|
377
400
|
if (r.fix)
|
|
378
401
|
console.log(`${ANSI.dim} fix: ${r.fix}${ANSI.reset}`);
|
|
379
402
|
}
|
|
403
|
+
/**
|
|
404
|
+
* Runs the autonomous hardware agent diagnostic command.
|
|
405
|
+
*/
|
|
406
|
+
async function runHardwareAgent(flags) {
|
|
407
|
+
console.log(`${ANSI.bold}PixelKit Hardware Diagnostics Agent${ANSI.reset}\n`);
|
|
408
|
+
const step1 = await checkAdbAndDevice(flags.serial);
|
|
409
|
+
if (step1.result.status === 'fail' || !step1.serial) {
|
|
410
|
+
printResult(step1.result);
|
|
411
|
+
return 1;
|
|
412
|
+
}
|
|
413
|
+
const serial = step1.serial;
|
|
414
|
+
console.log(`${ANSI.dim}Collecting hardware telemetry from ${serial}...${ANSI.reset}`);
|
|
415
|
+
// 1. Device identity & SoC
|
|
416
|
+
const modelRes = await runAdb(['-s', serial, 'shell', 'getprop', 'ro.product.model']);
|
|
417
|
+
const manufacturerRes = await runAdb(['-s', serial, 'shell', 'getprop', 'ro.product.manufacturer']);
|
|
418
|
+
const releaseRes = await runAdb(['-s', serial, 'shell', 'getprop', 'ro.build.version.release']);
|
|
419
|
+
const sdkRes = await runAdb(['-s', serial, 'shell', 'getprop', 'ro.build.version.sdk']);
|
|
420
|
+
const socRes = await runAdb(['-s', serial, 'shell', 'getprop', 'ro.soc.model']);
|
|
421
|
+
const platformRes = await runAdb(['-s', serial, 'shell', 'getprop', 'ro.board.platform']);
|
|
422
|
+
const model = modelRes.ok ? modelRes.stdout.trim() : 'Unknown';
|
|
423
|
+
const manufacturer = manufacturerRes.ok ? manufacturerRes.stdout.trim() : 'Unknown';
|
|
424
|
+
const release = releaseRes.ok ? releaseRes.stdout.trim() : 'Unknown';
|
|
425
|
+
const sdk = sdkRes.ok ? sdkRes.stdout.trim() : 'Unknown';
|
|
426
|
+
const soc = socRes.ok && socRes.stdout.trim() ? socRes.stdout.trim() : (platformRes.ok ? platformRes.stdout.trim() : 'Google Tensor');
|
|
427
|
+
// 2. Battery telemetry
|
|
428
|
+
const batteryRes = await runAdb(['-s', serial, 'shell', 'dumpsys', 'battery']);
|
|
429
|
+
let batteryLevel = 'N/A';
|
|
430
|
+
let batteryTemp = 'N/A';
|
|
431
|
+
let batteryVoltage = 'N/A';
|
|
432
|
+
let batteryStatus = 'N/A';
|
|
433
|
+
let batteryHealth = 'N/A';
|
|
434
|
+
if (batteryRes.ok) {
|
|
435
|
+
const lines = batteryRes.stdout.split(/\r?\n/);
|
|
436
|
+
for (const line of lines) {
|
|
437
|
+
const trimmed = line.trim();
|
|
438
|
+
if (trimmed.startsWith('level:'))
|
|
439
|
+
batteryLevel = trimmed.split(':')[1].trim() + '%';
|
|
440
|
+
else if (trimmed.startsWith('temperature:')) {
|
|
441
|
+
const raw = parseFloat(trimmed.split(':')[1].trim());
|
|
442
|
+
batteryTemp = (raw / 10).toFixed(1) + '°C';
|
|
443
|
+
}
|
|
444
|
+
else if (trimmed.startsWith('voltage:')) {
|
|
445
|
+
const raw = parseFloat(trimmed.split(':')[1].trim());
|
|
446
|
+
batteryVoltage = (raw / 1000).toFixed(2) + 'V';
|
|
447
|
+
}
|
|
448
|
+
else if (trimmed.startsWith('status:')) {
|
|
449
|
+
const code = trimmed.split(':')[1].trim();
|
|
450
|
+
batteryStatus = code === '2' ? 'Charging' : code === '3' ? 'Discharging' : code === '5' ? 'Full' : 'Not Charging';
|
|
451
|
+
}
|
|
452
|
+
else if (trimmed.startsWith('health:')) {
|
|
453
|
+
const code = trimmed.split(':')[1].trim();
|
|
454
|
+
batteryHealth = code === '2' ? 'Good' : 'Degraded';
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
// 3. Thermal telemetry
|
|
459
|
+
const thermalRes = await runAdb(['-s', serial, 'shell', 'dumpsys', 'thermalservice']);
|
|
460
|
+
let thermalStatus = 'Normal (0)';
|
|
461
|
+
if (thermalRes.ok) {
|
|
462
|
+
const match = thermalRes.stdout.match(/mStatus=(\d+)/i) || thermalRes.stdout.match(/Current thermal status: (\d+)/i);
|
|
463
|
+
if (match) {
|
|
464
|
+
const code = parseInt(match[1], 10);
|
|
465
|
+
const labels = ['None', 'Light', 'Moderate', 'Severe', 'Critical', 'Emergency', 'Shutdown'];
|
|
466
|
+
thermalStatus = `${labels[code] ?? 'Unknown'} (${code})`;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
// 4. Memory telemetry
|
|
470
|
+
const memRes = await runAdb(['-s', serial, 'shell', 'cat', '/proc/meminfo']);
|
|
471
|
+
let memTotal = 'N/A';
|
|
472
|
+
let memAvail = 'N/A';
|
|
473
|
+
let memPct = 'N/A';
|
|
474
|
+
if (memRes.ok) {
|
|
475
|
+
const totalMatch = memRes.stdout.match(/MemTotal:\s+(\d+)\s+kB/);
|
|
476
|
+
const availMatch = memRes.stdout.match(/MemAvailable:\s+(\d+)\s+kB/);
|
|
477
|
+
if (totalMatch && availMatch) {
|
|
478
|
+
const totalMB = Math.round(parseInt(totalMatch[1], 10) / 1024);
|
|
479
|
+
const availMB = Math.round(parseInt(availMatch[1], 10) / 1024);
|
|
480
|
+
memTotal = `${totalMB} MB`;
|
|
481
|
+
memAvail = `${availMB} MB`;
|
|
482
|
+
memPct = `${Math.round((availMB / totalMB) * 100)}% available`;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
// 5. AICore status
|
|
486
|
+
const aicoreRes = await runAdb(['-s', serial, 'shell', 'pm', 'list', 'packages', 'com.google.android.aicore']);
|
|
487
|
+
const aicoreInstalled = aicoreRes.ok && aicoreRes.stdout.includes('com.google.android.aicore');
|
|
488
|
+
// Print Telemetry Matrix
|
|
489
|
+
console.log(`\n${ANSI.bold}Hardware Telemetry Snapshot:${ANSI.reset}`);
|
|
490
|
+
console.log(` Device: ${manufacturer} ${model} (Android ${release}, API ${sdk})`);
|
|
491
|
+
console.log(` Silicon: ${soc}`);
|
|
492
|
+
console.log(` Battery: ${batteryLevel} · ${batteryTemp} · ${batteryVoltage} · ${batteryStatus} (${batteryHealth})`);
|
|
493
|
+
console.log(` Thermals: ${thermalStatus}`);
|
|
494
|
+
console.log(` Memory: ${memAvail} / ${memTotal} (${memPct})`);
|
|
495
|
+
console.log(` AICore: ${aicoreInstalled ? `${ANSI.green}Active${ANSI.reset}` : `${ANSI.yellow}Not Installed${ANSI.reset}`}\n`);
|
|
496
|
+
const apiKey = process.env.GEMINI_API_KEY || process.env.GOOGLE_GENAI_API_KEY;
|
|
497
|
+
const userQuery = flags.query || 'Perform a comprehensive hardware diagnostic check on this Pixel device.';
|
|
498
|
+
if (!apiKey) {
|
|
499
|
+
console.log(`${ANSI.bold}Autonomous Diagnostic Assessment (Local Heuristics):${ANSI.reset}`);
|
|
500
|
+
const issues = [];
|
|
501
|
+
if (batteryHealth !== 'Good' && batteryHealth !== 'N/A')
|
|
502
|
+
issues.push('Battery reports degraded health.');
|
|
503
|
+
if (thermalStatus.includes('Severe') || thermalStatus.includes('Critical'))
|
|
504
|
+
issues.push('Thermal throttling active.');
|
|
505
|
+
if (!aicoreInstalled)
|
|
506
|
+
issues.push('AICore is not installed; Gemini Nano hardware acceleration disabled.');
|
|
507
|
+
if (issues.length === 0) {
|
|
508
|
+
console.log(` ${ANSI.green}✔ System hardware health nominal. All silicon, battery, and thermal parameters within optimal operational thresholds.${ANSI.reset}`);
|
|
509
|
+
}
|
|
510
|
+
else {
|
|
511
|
+
for (const iss of issues) {
|
|
512
|
+
console.log(` ${ANSI.yellow}⚠ ${iss}${ANSI.reset}`);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
console.log(`\n${ANSI.dim}💡 Tip: Export GEMINI_API_KEY to activate cloud agent multi-turn LLM reasoning and custom hardware triage queries.${ANSI.reset}`);
|
|
516
|
+
return 0;
|
|
517
|
+
}
|
|
518
|
+
// Cloud Agent Reasoning
|
|
519
|
+
const modelName = flags.model || 'gemini-2.5-flash';
|
|
520
|
+
console.log(`${ANSI.bold}Cloud Hardware Agent (${modelName}):${ANSI.reset}`);
|
|
521
|
+
console.log(`${ANSI.dim}Reasoning over hardware telemetry with Google Gen AI...${ANSI.reset}\n`);
|
|
522
|
+
const prompt = `Target Device Telemetry:
|
|
523
|
+
- Manufacturer: ${manufacturer}
|
|
524
|
+
- Model: ${model}
|
|
525
|
+
- Android Release: ${release} (SDK ${sdk})
|
|
526
|
+
- SoC Silicon: ${soc}
|
|
527
|
+
- Battery: Level=${batteryLevel}, Temp=${batteryTemp}, Voltage=${batteryVoltage}, Status=${batteryStatus}, Health=${batteryHealth}
|
|
528
|
+
- Thermal Headroom: ${thermalStatus}
|
|
529
|
+
- Memory: Available=${memAvail}, Total=${memTotal} (${memPct})
|
|
530
|
+
- AICore: ${aicoreInstalled ? 'Installed and available' : 'Not installed'}
|
|
531
|
+
|
|
532
|
+
User Diagnostic Query: "${userQuery}"
|
|
533
|
+
|
|
534
|
+
Provide a concise, professional hardware engineering assessment. Evaluate thermal headroom, battery wear/charging, memory constraints, and AICore readiness. Give specific actionable recommendations.`;
|
|
535
|
+
try {
|
|
536
|
+
const url = `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(modelName)}:generateContent?key=${encodeURIComponent(apiKey)}`;
|
|
537
|
+
const res = await fetch(url, {
|
|
538
|
+
method: 'POST',
|
|
539
|
+
headers: { 'Content-Type': 'application/json' },
|
|
540
|
+
body: JSON.stringify({
|
|
541
|
+
contents: [{ role: 'user', parts: [{ text: prompt }] }],
|
|
542
|
+
systemInstruction: {
|
|
543
|
+
parts: [{ text: 'You are the PixelKit Hardware Diagnostics Agent, an expert embedded and systems engineer specializing in Google Pixel hardware (Tensor G-series, Android, AICore).' }]
|
|
544
|
+
}
|
|
545
|
+
})
|
|
546
|
+
});
|
|
547
|
+
if (!res.ok) {
|
|
548
|
+
const errText = await res.text();
|
|
549
|
+
console.error(`Agent API error (${res.status}): ${errText}`);
|
|
550
|
+
return 1;
|
|
551
|
+
}
|
|
552
|
+
const data = await res.json();
|
|
553
|
+
const replyText = data?.candidates?.[0]?.content?.parts?.[0]?.text;
|
|
554
|
+
if (replyText) {
|
|
555
|
+
console.log(replyText.trim());
|
|
556
|
+
console.log(`\n${ANSI.green}✔ Hardware diagnostic triage complete.${ANSI.reset}`);
|
|
557
|
+
return 0;
|
|
558
|
+
}
|
|
559
|
+
else {
|
|
560
|
+
console.error('No response text received from agent.');
|
|
561
|
+
return 1;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
catch (err) {
|
|
565
|
+
console.error(`Agent reasoning failed: ${err.message || String(err)}`);
|
|
566
|
+
return 1;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
380
569
|
/**
|
|
381
570
|
* Runs all six checks in order and prints them. Returns the process exit code: 0 only when every
|
|
382
571
|
* check passed or was not applicable; 1 when any check failed or — per the "never fabricate a
|
|
@@ -416,15 +605,19 @@ async function main() {
|
|
|
416
605
|
process.exitCode = 1;
|
|
417
606
|
return;
|
|
418
607
|
}
|
|
419
|
-
if (command
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
608
|
+
if (command === 'doctor') {
|
|
609
|
+
process.exitCode = await doctor(flags);
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
if (command === 'agent') {
|
|
613
|
+
process.exitCode = await runHardwareAgent(flags);
|
|
423
614
|
return;
|
|
424
615
|
}
|
|
425
|
-
|
|
616
|
+
console.error(`Unknown command "${command}". Available commands: "doctor", "agent".\n`);
|
|
617
|
+
printUsage();
|
|
618
|
+
process.exitCode = 1;
|
|
426
619
|
}
|
|
427
620
|
main().catch((err) => {
|
|
428
|
-
console.error(`pixelkit
|
|
621
|
+
console.error(`pixelkit crashed: ${err.stack || String(err)}`);
|
|
429
622
|
process.exitCode = 1;
|
|
430
623
|
});
|