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.
Files changed (2) hide show
  1. package/bin/nlos.js +202 -4
  2. 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 = 'qwen2.5:3b',
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 based on profile
329
- let selectedModel = model;
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] || model;
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nlos",
3
- "version": "1.6.0",
3
+ "version": "1.8.0",
4
4
  "description": "Natural Language Operating System - A model-agnostic kernel for any LLM",
5
5
  "main": "bin/nlos.js",
6
6
  "bin": {