nlos 1.6.0 → 1.8.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/bin/nlos.js +202 -4
- package/package.json +1 -1
package/bin/nlos.js
CHANGED
|
@@ -319,14 +319,26 @@ function boot(options = {}) {
|
|
|
319
319
|
|
|
320
320
|
function chat(options = {}) {
|
|
321
321
|
const {
|
|
322
|
-
model =
|
|
322
|
+
model = null, // null means check config
|
|
323
323
|
full = false,
|
|
324
324
|
minimal = false,
|
|
325
325
|
profile = null,
|
|
326
326
|
} = options;
|
|
327
327
|
|
|
328
|
-
// Resolve model
|
|
329
|
-
let selectedModel =
|
|
328
|
+
// Resolve model: CLI flag > config file > profile > default
|
|
329
|
+
let selectedModel = 'qwen2.5:3b';
|
|
330
|
+
|
|
331
|
+
// Check .nlos.yaml for default
|
|
332
|
+
const configPath = path.join(process.cwd(), '.nlos.yaml');
|
|
333
|
+
if (fs.existsSync(configPath)) {
|
|
334
|
+
const config = fs.readFileSync(configPath, 'utf-8');
|
|
335
|
+
const match = config.match(/default_model:\s*(\S+)/);
|
|
336
|
+
if (match) {
|
|
337
|
+
selectedModel = match[1];
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Profile overrides config
|
|
330
342
|
if (profile) {
|
|
331
343
|
const profiles = {
|
|
332
344
|
speed: 'qwen2.5:3b',
|
|
@@ -334,7 +346,12 @@ function chat(options = {}) {
|
|
|
334
346
|
quality: 'llama3.1:8b',
|
|
335
347
|
memory_constrained: 'qwen2.5:3b',
|
|
336
348
|
};
|
|
337
|
-
selectedModel = profiles[profile] ||
|
|
349
|
+
selectedModel = profiles[profile] || selectedModel;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// CLI flag overrides everything
|
|
353
|
+
if (model) {
|
|
354
|
+
selectedModel = model;
|
|
338
355
|
}
|
|
339
356
|
|
|
340
357
|
log('blue', `Starting NL-OS chat session...`);
|
|
@@ -477,6 +494,175 @@ function payload(options = {}) {
|
|
|
477
494
|
}
|
|
478
495
|
}
|
|
479
496
|
|
|
497
|
+
function model(args = []) {
|
|
498
|
+
const subcommand = args[0];
|
|
499
|
+
const modelName = args[1];
|
|
500
|
+
|
|
501
|
+
const configPath = path.join(process.cwd(), '.nlos.yaml');
|
|
502
|
+
const hasLocalConfig = fs.existsSync(configPath);
|
|
503
|
+
|
|
504
|
+
// Recommended models by capability
|
|
505
|
+
const recommended = {
|
|
506
|
+
'qwen2.5:3b': { size: '1.9GB', context: '32K', note: 'Fast, minimal capability' },
|
|
507
|
+
'qwen2.5:7b': { size: '4.4GB', context: '32K', note: 'Good balance' },
|
|
508
|
+
'llama3.1:8b': { size: '4.7GB', context: '128K', note: 'Strong reasoning' },
|
|
509
|
+
'mistral:7b': { size: '4.1GB', context: '32K', note: 'Fast, good quality' },
|
|
510
|
+
'llama3.2:3b': { size: '2.0GB', context: '128K', note: 'Newest small model' },
|
|
511
|
+
'deepseek-r1:8b': { size: '4.9GB', context: '64K', note: 'Strong reasoning' },
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
if (!subcommand || subcommand === 'list') {
|
|
515
|
+
log('blue', 'Recommended models for NL-OS:\n');
|
|
516
|
+
console.log(`${'Model'.padEnd(20)} ${'Size'.padEnd(10)} ${'Context'.padEnd(10)} Note`);
|
|
517
|
+
console.log('─'.repeat(60));
|
|
518
|
+
for (const [name, info] of Object.entries(recommended)) {
|
|
519
|
+
console.log(`${name.padEnd(20)} ${info.size.padEnd(10)} ${info.context.padEnd(10)} ${info.note}`);
|
|
520
|
+
}
|
|
521
|
+
console.log();
|
|
522
|
+
log('yellow', 'Commands:');
|
|
523
|
+
console.log(' nlos model use <name> Set as default and pull if needed');
|
|
524
|
+
console.log(' nlos model pull <name> Just pull the model');
|
|
525
|
+
console.log(' nlos model current Show current default');
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
if (subcommand === 'current') {
|
|
530
|
+
if (hasLocalConfig) {
|
|
531
|
+
const config = fs.readFileSync(configPath, 'utf-8');
|
|
532
|
+
const match = config.match(/default_model:\s*(\S+)/);
|
|
533
|
+
if (match) {
|
|
534
|
+
log('green', `Current model: ${match[1]}`);
|
|
535
|
+
} else {
|
|
536
|
+
log('yellow', 'No default model set. Using: qwen2.5:3b');
|
|
537
|
+
}
|
|
538
|
+
} else {
|
|
539
|
+
log('yellow', 'No .nlos.yaml found. Run "nlos init" first, or using default: qwen2.5:3b');
|
|
540
|
+
}
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
if (subcommand === 'pull') {
|
|
545
|
+
if (!modelName) {
|
|
546
|
+
log('red', 'Usage: nlos model pull <name>');
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
log('blue', `Pulling ${modelName}...`);
|
|
550
|
+
try {
|
|
551
|
+
execSync(`ollama pull ${modelName}`, { stdio: 'inherit' });
|
|
552
|
+
log('green', `\nModel ${modelName} ready!`);
|
|
553
|
+
} catch (error) {
|
|
554
|
+
log('red', `Failed to pull: ${error.message}`);
|
|
555
|
+
}
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
if (subcommand === 'use' || subcommand === 'set') {
|
|
560
|
+
if (!modelName) {
|
|
561
|
+
log('red', 'Usage: nlos model use <name>');
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// Pull model if not present
|
|
566
|
+
log('blue', `Setting up ${modelName}...\n`);
|
|
567
|
+
try {
|
|
568
|
+
execSync(`ollama list | grep -q "^${modelName.split(':')[0]}"`, { stdio: 'pipe' });
|
|
569
|
+
log('cyan', `Model ${modelName} already pulled`);
|
|
570
|
+
} catch {
|
|
571
|
+
log('yellow', `Pulling ${modelName}...`);
|
|
572
|
+
try {
|
|
573
|
+
execSync(`ollama pull ${modelName}`, { stdio: 'inherit' });
|
|
574
|
+
} catch (error) {
|
|
575
|
+
log('red', `Failed to pull: ${error.message}`);
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Update .nlos.yaml if it exists
|
|
581
|
+
if (hasLocalConfig) {
|
|
582
|
+
let config = fs.readFileSync(configPath, 'utf-8');
|
|
583
|
+
if (config.includes('default_model:')) {
|
|
584
|
+
config = config.replace(/default_model:\s*\S+/, `default_model: ${modelName}`);
|
|
585
|
+
} else {
|
|
586
|
+
config += `\nkernel:\n default_model: ${modelName}\n`;
|
|
587
|
+
}
|
|
588
|
+
fs.writeFileSync(configPath, config);
|
|
589
|
+
log('green', `\nDefault model set to: ${modelName}`);
|
|
590
|
+
console.log(`\nRun ${colors.cyan}nlos chat --minimal${colors.reset} to start`);
|
|
591
|
+
} else {
|
|
592
|
+
log('green', `\nModel ${modelName} ready!`);
|
|
593
|
+
console.log(`\nRun ${colors.cyan}nlos chat --minimal --model ${modelName}${colors.reset} to start`);
|
|
594
|
+
console.log(`Or run ${colors.cyan}nlos init${colors.reset} first to save as default`);
|
|
595
|
+
}
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
log('red', `Unknown subcommand: ${subcommand}`);
|
|
600
|
+
console.log('Use: nlos model list|use|pull|current');
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
function clean(options = {}) {
|
|
604
|
+
const { local = false, all = false } = options;
|
|
605
|
+
|
|
606
|
+
log('blue', 'Cleaning NL-OS...\n');
|
|
607
|
+
|
|
608
|
+
// Remove Ollama model
|
|
609
|
+
log('yellow', 'Removing Ollama model...');
|
|
610
|
+
try {
|
|
611
|
+
execSync('ollama rm nlos-kernel:latest', { stdio: 'pipe' });
|
|
612
|
+
log('green', ' [removed] nlos-kernel:latest');
|
|
613
|
+
} catch {
|
|
614
|
+
log('cyan', ' [skip] nlos-kernel:latest not found');
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// Clean local workspace files if --local or --all
|
|
618
|
+
if (local || all) {
|
|
619
|
+
const targetDir = process.cwd();
|
|
620
|
+
const localFiles = [
|
|
621
|
+
'KERNEL.md',
|
|
622
|
+
'memory.md',
|
|
623
|
+
'AGENTS.md',
|
|
624
|
+
'axioms.yaml',
|
|
625
|
+
'personalities.md',
|
|
626
|
+
'.nlos.yaml',
|
|
627
|
+
];
|
|
628
|
+
const localDirs = ['commands'];
|
|
629
|
+
|
|
630
|
+
log('yellow', 'Removing local workspace files...');
|
|
631
|
+
for (const file of localFiles) {
|
|
632
|
+
const filePath = path.join(targetDir, file);
|
|
633
|
+
if (fs.existsSync(filePath)) {
|
|
634
|
+
fs.unlinkSync(filePath);
|
|
635
|
+
log('green', ` [removed] ${file}`);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
for (const dir of localDirs) {
|
|
639
|
+
const dirPath = path.join(targetDir, dir);
|
|
640
|
+
if (fs.existsSync(dirPath)) {
|
|
641
|
+
fs.rmSync(dirPath, { recursive: true });
|
|
642
|
+
log('green', ` [removed] ${dir}/`);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// Uninstall global package if --all
|
|
648
|
+
if (all) {
|
|
649
|
+
log('yellow', 'Uninstalling global package...');
|
|
650
|
+
console.log();
|
|
651
|
+
log('cyan', 'Run this command to complete uninstall:');
|
|
652
|
+
console.log(` npm uninstall -g nlos\n`);
|
|
653
|
+
log('yellow', '(Cannot self-uninstall while running)');
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
console.log();
|
|
657
|
+
log('green', 'Clean complete!\n');
|
|
658
|
+
|
|
659
|
+
if (!local && !all) {
|
|
660
|
+
console.log(`${colors.yellow}Options:${colors.reset}`);
|
|
661
|
+
console.log(` nlos clean --local Also remove local workspace files`);
|
|
662
|
+
console.log(` nlos clean --all Remove everything (local + instructions for global)`);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
480
666
|
function init(options = {}) {
|
|
481
667
|
const targetDir = process.cwd();
|
|
482
668
|
|
|
@@ -604,6 +790,8 @@ ${colors.yellow}Usage:${colors.reset}
|
|
|
604
790
|
${colors.yellow}Commands:${colors.reset}
|
|
605
791
|
init Initialize NL-OS workspace in current directory
|
|
606
792
|
chat Interactive NL-OS chat session (recommended)
|
|
793
|
+
model Manage models (list, use, pull, current)
|
|
794
|
+
clean Remove Ollama model and optionally local files
|
|
607
795
|
boot Boot NL-OS and verify kernel loads
|
|
608
796
|
payload Generate portable kernel payloads
|
|
609
797
|
verify Verify kernel files exist
|
|
@@ -669,6 +857,8 @@ function parseArgs(args) {
|
|
|
669
857
|
options.dryRun = true;
|
|
670
858
|
} else if (arg === '--all') {
|
|
671
859
|
options.all = true;
|
|
860
|
+
} else if (arg === '--local') {
|
|
861
|
+
options.local = true;
|
|
672
862
|
}
|
|
673
863
|
|
|
674
864
|
i++;
|
|
@@ -687,6 +877,14 @@ switch (command) {
|
|
|
687
877
|
init(options);
|
|
688
878
|
break;
|
|
689
879
|
|
|
880
|
+
case 'clean':
|
|
881
|
+
clean(options);
|
|
882
|
+
break;
|
|
883
|
+
|
|
884
|
+
case 'model':
|
|
885
|
+
model(args.slice(1));
|
|
886
|
+
break;
|
|
887
|
+
|
|
690
888
|
case 'chat':
|
|
691
889
|
chat(options);
|
|
692
890
|
break;
|