nlos 1.4.0 → 1.6.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 +183 -8
  2. package/package.json +1 -1
package/bin/nlos.js CHANGED
@@ -112,6 +112,40 @@ function showTokens() {
112
112
  }
113
113
  }
114
114
 
115
+ // Minimal kernel for small models (~500 tokens)
116
+ const MINIMAL_KERNEL = `# YOU ARE NL-OS
117
+
118
+ You are NL-OS, a Natural Language Operating System. You help users think and work.
119
+
120
+ ## YOUR FIRST RESPONSE
121
+
122
+ Say exactly: "NL-OS ready."
123
+
124
+ ## COMMANDS
125
+
126
+ When user message starts with ">", it is a command. Execute it:
127
+
128
+ >hype = Give 1-2 sentences of encouragement about their work
129
+ >note TEXT = Say "Noted." (do not do anything with TEXT)
130
+ >help = Say "Commands: >hype >note >help >deep >assume"
131
+ >deep = Say "Deep mode on." Then think step-by-step
132
+ >assume NAME = Say "Now acting as NAME." Then roleplay as NAME
133
+
134
+ ## RULES
135
+
136
+ 1. ">" means command - execute it immediately
137
+ 2. Be helpful, concise, no emojis
138
+ 3. If unsure, ask for clarification
139
+
140
+ ## EXAMPLE
141
+
142
+ User: >hype
143
+ Assistant: You're making real progress. Keep that momentum going.
144
+
145
+ User: hello
146
+ Assistant: Hello! How can I help you today?
147
+ `;
148
+
115
149
  // Command preamble - explicit rules that help ALL models parse commands correctly
116
150
  const COMMAND_PREAMBLE = `# YOU ARE NL-OS (Natural Language Operating System)
117
151
 
@@ -287,6 +321,7 @@ function chat(options = {}) {
287
321
  const {
288
322
  model = 'qwen2.5:3b',
289
323
  full = false,
324
+ minimal = false,
290
325
  profile = null,
291
326
  } = options;
292
327
 
@@ -304,18 +339,24 @@ function chat(options = {}) {
304
339
 
305
340
  log('blue', `Starting NL-OS chat session...`);
306
341
  log('cyan', `Model: ${selectedModel}`);
307
- log('cyan', `Tier: ${full ? 'FULL' : 'MANDATORY'}`);
342
+ log('cyan', `Tier: ${minimal ? 'MINIMAL' : full ? 'FULL' : 'MANDATORY'}`);
308
343
  console.log();
309
344
 
310
345
  // Generate the kernel payload
311
346
  log('yellow', 'Building kernel payload...');
312
- const payload = generatePayload(full ? 'full' : 'mandatory', 'markdown');
313
347
 
314
- // Escape the payload for Modelfile SYSTEM directive
315
- // Replace """ with escaped version and handle multiline
316
- const escapedPayload = payload.replace(/"""/g, '\\"\\"\\"');
348
+ let payload;
349
+ let tokenEstimate;
350
+
351
+ if (minimal) {
352
+ // Use minimal kernel for small models
353
+ payload = MINIMAL_KERNEL;
354
+ tokenEstimate = '~500';
355
+ } else {
356
+ payload = generatePayload(full ? 'full' : 'mandatory', 'markdown');
357
+ tokenEstimate = full ? '~15,500' : '~10,600';
358
+ }
317
359
 
318
- const tokenEstimate = full ? '~15,500' : '~10,600';
319
360
  log('green', `Kernel payload ready (${tokenEstimate} tokens)`);
320
361
  console.log();
321
362
 
@@ -337,6 +378,14 @@ function chat(options = {}) {
337
378
  const modelfilePath = path.join(PACKAGE_ROOT, 'portable', '.Modelfile.nlos');
338
379
  const nlosModelName = 'nlos-kernel:latest';
339
380
 
381
+ // Delete old model to ensure fresh kernel
382
+ try {
383
+ execSync(`ollama rm ${nlosModelName}`, { stdio: 'pipe' });
384
+ log('cyan', 'Removed old kernel model');
385
+ } catch {
386
+ // Model didn't exist, that's fine
387
+ }
388
+
340
389
  const modelfileContent = `FROM ${selectedModel}
341
390
  SYSTEM """${payload}"""
342
391
  `;
@@ -428,6 +477,123 @@ function payload(options = {}) {
428
477
  }
429
478
  }
430
479
 
480
+ function init(options = {}) {
481
+ const targetDir = process.cwd();
482
+
483
+ log('blue', `Initializing NL-OS workspace in ${targetDir}...\n`);
484
+
485
+ // Files to copy from package to local workspace
486
+ const filesToCopy = [
487
+ { src: 'memory.md', dest: 'memory.md', desc: 'Directive stack (customize this!)' },
488
+ { src: 'KERNEL.md', dest: 'KERNEL.md', desc: 'Kernel entry point' },
489
+ { src: 'AGENTS.md', dest: 'AGENTS.md', desc: 'Agent rules and invariants' },
490
+ { src: 'axioms.yaml', dest: 'axioms.yaml', desc: 'Canonical definitions' },
491
+ { src: 'personalities.md', dest: 'personalities.md', desc: 'Voice presets' },
492
+ ];
493
+
494
+ const commandsToCopy = [
495
+ 'hype.md',
496
+ 'note.md',
497
+ 'assume.md',
498
+ ];
499
+
500
+ // Create directories
501
+ const commandsDir = path.join(targetDir, 'commands');
502
+ if (!fs.existsSync(commandsDir)) {
503
+ fs.mkdirSync(commandsDir, { recursive: true });
504
+ }
505
+
506
+ // Copy kernel files
507
+ log('yellow', 'Copying kernel files:');
508
+ for (const { src, dest, desc } of filesToCopy) {
509
+ const srcPath = path.join(PACKAGE_ROOT, src);
510
+ const destPath = path.join(targetDir, dest);
511
+
512
+ if (fs.existsSync(destPath)) {
513
+ log('cyan', ` [skip] ${dest} (already exists)`);
514
+ } else if (fs.existsSync(srcPath)) {
515
+ fs.copyFileSync(srcPath, destPath);
516
+ log('green', ` [created] ${dest} - ${desc}`);
517
+ } else {
518
+ log('red', ` [missing] ${src} not found in package`);
519
+ }
520
+ }
521
+
522
+ // Copy command files
523
+ console.log();
524
+ log('yellow', 'Copying command files:');
525
+ for (const cmd of commandsToCopy) {
526
+ const srcPath = path.join(PACKAGE_ROOT, '.cursor', 'commands', cmd);
527
+ const destPath = path.join(commandsDir, cmd);
528
+
529
+ if (fs.existsSync(destPath)) {
530
+ log('cyan', ` [skip] commands/${cmd} (already exists)`);
531
+ } else if (fs.existsSync(srcPath)) {
532
+ fs.copyFileSync(srcPath, destPath);
533
+ log('green', ` [created] commands/${cmd}`);
534
+ } else {
535
+ log('red', ` [missing] ${cmd} not found in package`);
536
+ }
537
+ }
538
+
539
+ // Create .nlos config file
540
+ const configPath = path.join(targetDir, '.nlos.yaml');
541
+ if (!fs.existsSync(configPath)) {
542
+ const config = `# NL-OS Workspace Configuration
543
+ # Generated: ${new Date().toISOString().split('T')[0]}
544
+
545
+ workspace:
546
+ name: "${path.basename(targetDir)}"
547
+ initialized: true
548
+
549
+ kernel:
550
+ # Use local files (set to false to use global package)
551
+ use_local: true
552
+
553
+ # Default model for this workspace
554
+ default_model: qwen2.5:3b
555
+
556
+ # Tier: minimal, mandatory, full
557
+ default_tier: minimal
558
+
559
+ # Add workspace-specific settings below
560
+ `;
561
+ fs.writeFileSync(configPath, config);
562
+ log('green', ` [created] .nlos.yaml - workspace config`);
563
+ }
564
+
565
+ // Create .gitignore addition
566
+ const gitignorePath = path.join(targetDir, '.gitignore');
567
+ const gitignoreContent = `# NL-OS
568
+ .nlos-cache/
569
+ `;
570
+ if (!fs.existsSync(gitignorePath)) {
571
+ fs.writeFileSync(gitignorePath, gitignoreContent);
572
+ log('green', ` [created] .gitignore`);
573
+ }
574
+
575
+ console.log();
576
+ log('green', 'Workspace initialized!\n');
577
+
578
+ console.log(`${colors.yellow}Next steps:${colors.reset}`);
579
+ console.log(` 1. Edit ${colors.cyan}memory.md${colors.reset} to customize your directives`);
580
+ console.log(` 2. Add commands to ${colors.cyan}commands/${colors.reset}`);
581
+ console.log(` 3. Run ${colors.cyan}nlos chat --minimal${colors.reset} to start\n`);
582
+
583
+ console.log(`${colors.yellow}Files created:${colors.reset}`);
584
+ console.log(` ${targetDir}/`);
585
+ console.log(` ├── KERNEL.md # Entry point`);
586
+ console.log(` ├── memory.md # Your directives (edit this!)`);
587
+ console.log(` ├── AGENTS.md # Agent rules`);
588
+ console.log(` ├── axioms.yaml # Definitions`);
589
+ console.log(` ├── personalities.md # Voice presets`);
590
+ console.log(` ├── commands/ # Your commands`);
591
+ console.log(` │ ├── hype.md`);
592
+ console.log(` │ ├── note.md`);
593
+ console.log(` │ └── assume.md`);
594
+ console.log(` └── .nlos.yaml # Workspace config`);
595
+ }
596
+
431
597
  function showHelp() {
432
598
  console.log(`
433
599
  ${colors.cyan}NL-OS${colors.reset} - Natural Language Operating System
@@ -436,6 +602,7 @@ ${colors.yellow}Usage:${colors.reset}
436
602
  nlos <command> [options]
437
603
 
438
604
  ${colors.yellow}Commands:${colors.reset}
605
+ init Initialize NL-OS workspace in current directory
439
606
  chat Interactive NL-OS chat session (recommended)
440
607
  boot Boot NL-OS and verify kernel loads
441
608
  payload Generate portable kernel payloads
@@ -443,9 +610,10 @@ ${colors.yellow}Commands:${colors.reset}
443
610
  tokens Show token estimates
444
611
  help Show this help message
445
612
 
446
- ${colors.yellow}Boot Options:${colors.reset}
613
+ ${colors.yellow}Chat/Boot Options:${colors.reset}
447
614
  --model <name> Model to use (default: qwen2.5:3b)
448
615
  --profile <name> Use profile: speed, balanced, quality, memory_constrained
616
+ --minimal Use minimal ~500 token kernel (best for small models)
449
617
  --full Load full kernel (includes personalities)
450
618
  --dry-run Preview system prompt without launching
451
619
  --runtime <name> Runtime: ollama, llama-cpp, lm-studio (default: ollama)
@@ -457,7 +625,8 @@ ${colors.yellow}Payload Options:${colors.reset}
457
625
  --all Generate all variants
458
626
 
459
627
  ${colors.yellow}Examples:${colors.reset}
460
- nlos chat # Start interactive chat (recommended)
628
+ nlos init # Initialize workspace with kernel files
629
+ nlos chat --minimal # Use minimal kernel for small models (3B)
461
630
  nlos chat --model llama3.1:8b # Chat with specific model
462
631
  nlos chat --profile quality --full # Quality mode with full kernel
463
632
  nlos boot # Verify kernel loads (one-shot)
@@ -494,6 +663,8 @@ function parseArgs(args) {
494
663
  options.runtime = args[++i];
495
664
  } else if (arg === '--full') {
496
665
  options.full = true;
666
+ } else if (arg === '--minimal') {
667
+ options.minimal = true;
497
668
  } else if (arg === '--dry-run') {
498
669
  options.dryRun = true;
499
670
  } else if (arg === '--all') {
@@ -512,6 +683,10 @@ const command = args[0];
512
683
  const options = parseArgs(args.slice(1));
513
684
 
514
685
  switch (command) {
686
+ case 'init':
687
+ init(options);
688
+ break;
689
+
515
690
  case 'chat':
516
691
  chat(options);
517
692
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nlos",
3
- "version": "1.4.0",
3
+ "version": "1.6.0",
4
4
  "description": "Natural Language Operating System - A model-agnostic kernel for any LLM",
5
5
  "main": "bin/nlos.js",
6
6
  "bin": {