letfixit 0.1.1 → 0.1.2
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/package.json +12 -2
- package/server/index.js +75 -24
package/package.json
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "letfixit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "LetFixIt — AI-based realtime performance analysis & suggestions for Flutter, Android & iOS, powered by the local Ultron n0-beta model.",
|
|
5
|
-
"keywords": [
|
|
5
|
+
"keywords": [
|
|
6
|
+
"flutter",
|
|
7
|
+
"android",
|
|
8
|
+
"ios",
|
|
9
|
+
"performance",
|
|
10
|
+
"profiler",
|
|
11
|
+
"devtools",
|
|
12
|
+
"observability",
|
|
13
|
+
"llm",
|
|
14
|
+
"local-ai"
|
|
15
|
+
],
|
|
6
16
|
"license": "MIT",
|
|
7
17
|
"author": "JahidDev24",
|
|
8
18
|
"main": "server/index.js",
|
package/server/index.js
CHANGED
|
@@ -29,7 +29,7 @@ const ENABLE_LOCAL_AI = process.env.ENABLE_LOCAL_AI !== 'false';
|
|
|
29
29
|
const MODEL_PATH = model.MODEL_PATH;
|
|
30
30
|
|
|
31
31
|
// ── Terminal styling + branded startup ─────────────────────────────────────────
|
|
32
|
-
const C = { reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m', mag: '\x1b[95m', grn: '\x1b[92m', yel: '\x1b[93m', cyan: '\x1b[96m' };
|
|
32
|
+
const C = { reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m', mag: '\x1b[95m', grn: '\x1b[92m', yel: '\x1b[93m', red: '\x1b[91m', cyan: '\x1b[96m' };
|
|
33
33
|
const col = (x, s) => `${x}${s}${C.reset}`;
|
|
34
34
|
const stripAnsi = (s) => s.replace(/\x1b\[[0-9;]*m/g, '');
|
|
35
35
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
@@ -42,10 +42,11 @@ function bannerBox(lines) {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
function printWelcome() {
|
|
45
|
+
const v = require('../package.json').version;
|
|
45
46
|
console.log('');
|
|
46
47
|
bannerBox([
|
|
47
48
|
'',
|
|
48
|
-
col(C.bold + C.mag, '✦ P A R I T Y F I X') + col(C.dim,
|
|
49
|
+
col(C.bold + C.mag, '✦ P A R I T Y F I X') + col(C.dim, ` v${v}`),
|
|
49
50
|
col(C.reset, 'AI-based realtime performance analysis & suggestions'),
|
|
50
51
|
col(C.dim, 'Flutter · Android · iOS powered by Ultron n0-beta'),
|
|
51
52
|
'',
|
|
@@ -53,32 +54,40 @@ function printWelcome() {
|
|
|
53
54
|
console.log('');
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
//
|
|
57
|
-
//
|
|
57
|
+
// Boot the local model. On first run (model not installed) this RUNS the setup
|
|
58
|
+
// — download + key prompt + decrypt + merge — then starts the model. Returns
|
|
59
|
+
// true if AI is available (local model ready, or a cloud provider configured).
|
|
58
60
|
async function initUltron() {
|
|
59
61
|
if (!ENABLE_LOCAL_AI) {
|
|
60
62
|
console.log(' ' + col(C.dim, 'Ultron n0-beta is disabled (ENABLE_LOCAL_AI=false) — using cloud fallback if configured.\n'));
|
|
61
|
-
return;
|
|
63
|
+
return aiStatus().anyAvailable;
|
|
62
64
|
}
|
|
65
|
+
|
|
66
|
+
// First-time setup: install the model (prompts for the decryption key).
|
|
63
67
|
if (!model.isReady()) {
|
|
64
|
-
console.log(' ' + col(C.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
console.log(' ' + col(C.mag, '✦ First-time setup') + col(C.dim, ` — installing ${model.MODEL_NAME}. This runs once.\n`));
|
|
69
|
+
try {
|
|
70
|
+
await require('../scripts/setup-model').setup();
|
|
71
|
+
} catch (e) {
|
|
72
|
+
const msg = String(e.message || e);
|
|
73
|
+
if (msg.startsWith('WRONG_KEY:')) console.log('\n ' + col(C.red, '❌ ' + msg.replace('WRONG_KEY: ', '')));
|
|
74
|
+
else console.log('\n ' + col(C.red, '❌ Setup failed: ' + msg));
|
|
75
|
+
}
|
|
76
|
+
console.log('');
|
|
68
77
|
}
|
|
69
78
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
console.log(' ' + col(C.
|
|
78
|
-
|
|
79
|
-
console.log(' ' + col(C.yel, '… still loading') + col(C.dim, ' — weights load in the background (first start can take ~20s).'));
|
|
79
|
+
if (model.isReady()) {
|
|
80
|
+
process.stdout.write(' ' + col(C.mag, '✦ Ultron n0-beta') + col(C.dim, ' initializing'));
|
|
81
|
+
startLlamafile();
|
|
82
|
+
let ok = false;
|
|
83
|
+
for (let i = 0; i < 8 && !ok; i++) { process.stdout.write(col(C.dim, '.')); ok = await isLlamaHealthy(); if (!ok) await sleep(500); }
|
|
84
|
+
process.stdout.write('\n');
|
|
85
|
+
if (ok) console.log(' ' + col(C.grn, '✓ ready') + col(C.dim, ` — ${model.MODEL_NAME} running locally on :${LOCAL_AI_PORT} (${model.sizeGB()} GB, private)`));
|
|
86
|
+
else console.log(' ' + col(C.yel, '… still loading') + col(C.dim, ' — weights load in the background (first start can take ~20s).'));
|
|
87
|
+
console.log(' ' + col(C.dim, model.DISCLAIMER.split(' — ')[0] + ' — treat suggestions as hints.\n'));
|
|
80
88
|
}
|
|
81
|
-
|
|
89
|
+
|
|
90
|
+
return aiStatus().anyAvailable; // local ready OR cloud key present
|
|
82
91
|
}
|
|
83
92
|
|
|
84
93
|
// ── Interactive startup ───────────────────────────────────────────────────────
|
|
@@ -569,9 +578,16 @@ server.on('error', (err) => {
|
|
|
569
578
|
// ── Startup ───────────────────────────────────────────────────────────────────
|
|
570
579
|
async function main() {
|
|
571
580
|
printWelcome();
|
|
572
|
-
//
|
|
573
|
-
|
|
574
|
-
|
|
581
|
+
// First-run: install + start the model. Returns true only if AI is available.
|
|
582
|
+
const aiReady = await initUltron();
|
|
583
|
+
|
|
584
|
+
// AI is required to analyze — don't show the menu without it.
|
|
585
|
+
if (!aiReady) {
|
|
586
|
+
console.log(' ' + col(C.red, '⚠ AI is required to run analysis, and it isn\'t set up yet.'));
|
|
587
|
+
console.log(' ' + col(C.dim, `Re-run ${col(C.cyan, 'letfixit')} and paste your ${model.MODEL_NAME} key when prompted,`));
|
|
588
|
+
console.log(' ' + col(C.dim, `or add a cloud key (GROQ/GEMINI/CLAUDE) to .env, then start again.\n`));
|
|
589
|
+
process.exit(0);
|
|
590
|
+
}
|
|
575
591
|
|
|
576
592
|
const setup = await interactiveSetup();
|
|
577
593
|
|
|
@@ -616,4 +632,39 @@ function shutdown() {
|
|
|
616
632
|
process.on('SIGINT', shutdown);
|
|
617
633
|
process.on('SIGTERM', shutdown);
|
|
618
634
|
|
|
619
|
-
|
|
635
|
+
// ── CLI dispatch ────────────────────────────────────────────────────────────
|
|
636
|
+
function printHelp() {
|
|
637
|
+
const v = require('../package.json').version;
|
|
638
|
+
console.log(`
|
|
639
|
+
${col(C.bold + C.mag, 'LetFixIt')} v${v} ${col(C.dim, '— AI-based realtime performance analysis for Flutter, Android & iOS')}
|
|
640
|
+
|
|
641
|
+
${col(C.bold, 'Usage')}
|
|
642
|
+
${col(C.cyan, 'letfixit')} Launch the analyzer (first run installs ${model.MODEL_NAME})
|
|
643
|
+
${col(C.cyan, 'letfixit setup')} Download & set up the model (prompts for the decryption key)
|
|
644
|
+
${col(C.cyan, 'letfixit setup --force')} Re-download / reinstall the model
|
|
645
|
+
${col(C.cyan, 'letfixit version')} Print the installed version (or --version / -v)
|
|
646
|
+
${col(C.cyan, 'letfixit --help')} Show this help
|
|
647
|
+
|
|
648
|
+
${col(C.bold, 'Environment')}
|
|
649
|
+
${col(C.dim, 'PARITYFIX_MODEL_KEY')} decryption key for non-interactive / CI installs
|
|
650
|
+
${col(C.dim, 'DASHBOARD_PORT')} dashboard port (default 8081)
|
|
651
|
+
${col(C.dim, 'LOCAL_AI_PORT')} local model port (default 8080)
|
|
652
|
+
${col(C.dim, 'ENABLE_LOCAL_AI')} set to "false" to use cloud fallback only
|
|
653
|
+
`);
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
const cmd = process.argv[2];
|
|
657
|
+
if (cmd === '--version' || cmd === '-v') {
|
|
658
|
+
console.log(require('../package.json').version); // bare number (scripts)
|
|
659
|
+
} else if (cmd === 'version') {
|
|
660
|
+
console.log(`letfixit v${require('../package.json').version}`); // friendly line
|
|
661
|
+
} else if (cmd === '--help' || cmd === '-h' || cmd === 'help') {
|
|
662
|
+
printHelp();
|
|
663
|
+
} else if (cmd === 'setup') {
|
|
664
|
+
// Explicit setup: run the installer directly and exit (like `npm run setup`).
|
|
665
|
+
require('../scripts/setup-model').setup()
|
|
666
|
+
.then(() => process.exit(0))
|
|
667
|
+
.catch((e) => { console.error(' ❌ setup failed:', e.message); process.exit(1); });
|
|
668
|
+
} else {
|
|
669
|
+
main(); // default: launch the analyzer
|
|
670
|
+
}
|