@lzhzzzzwill/cofos 1.2.3 → 1.2.4

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/cofos.js +63 -9
  2. package/package.json +1 -1
package/bin/cofos.js CHANGED
@@ -106,7 +106,8 @@ function render({ modelPath, cacheDir, pdfDir }) {
106
106
  const SLASH_COMMANDS = [
107
107
  { cmd: "/help", desc: "Show help" },
108
108
  { cmd: "/exit", desc: "Quit" },
109
- { cmd: "/clear", desc: "Clear conversation history" },
109
+ { cmd: "/clear", desc: "Clear page and conversation history" },
110
+ { cmd: "/cls", desc: "Clear page only" },
110
111
  { cmd: "/save", desc: "Save this session history" },
111
112
  { cmd: "/info", desc: "Show model and RAG info" },
112
113
  { cmd: "/topk 5", desc: "Set retrieval top-k" },
@@ -169,8 +170,8 @@ function createTui() {
169
170
  alwaysScroll: true,
170
171
  keys: true,
171
172
  vi: true,
172
- mouse: false,
173
- tags: false,
173
+ mouse: true,
174
+ tags: true,
174
175
  scrollbar: { ch: " ", track: { bg: "black" }, style: { bg: "cyan" } },
175
176
  });
176
177
 
@@ -213,6 +214,7 @@ function createTui() {
213
214
  let selectedSuggestion = 0;
214
215
 
215
216
  function append(text = "") {
217
+ const wasAtBottom = history.getScrollPerc() >= 98;
216
218
  const data = String(text).replace(/\x1b\[[0-9;]*[A-Za-z]/g, "");
217
219
  for (const part of data.split("\r")) {
218
220
  if (part === "") continue;
@@ -225,7 +227,7 @@ function createTui() {
225
227
  }
226
228
  if (buffer.length > 250000) buffer = buffer.slice(-220000);
227
229
  history.setContent(buffer);
228
- history.setScrollPerc(100);
230
+ if (wasAtBottom) history.setScrollPerc(100);
229
231
  screen.render();
230
232
  }
231
233
 
@@ -314,6 +316,10 @@ function createTui() {
314
316
  });
315
317
 
316
318
  screen.key(["escape"], hideSuggestions);
319
+ screen.key(["pageup"], () => { history.scroll(-Math.max(3, Math.floor(screen.height * 0.8))); screen.render(); });
320
+ screen.key(["pagedown"], () => { history.scroll(Math.max(3, Math.floor(screen.height * 0.8))); screen.render(); });
321
+ screen.key(["home"], () => { history.setScrollPerc(0); screen.render(); });
322
+ screen.key(["end"], () => { history.setScrollPerc(100); screen.render(); });
317
323
  screen.key(["C-c"], () => onExit());
318
324
 
319
325
  input.focus();
@@ -324,6 +330,7 @@ function createTui() {
324
330
  input,
325
331
  append,
326
332
  print: (text = "") => append(String(text) + "\n"),
333
+ clear: () => { buffer = ""; history.setContent(""); history.setScrollPerc(100); screen.render(); },
327
334
  setSubmitHandler: (fn) => { onSubmit = fn; },
328
335
  setExitHandler: (fn) => { onExit = fn; },
329
336
  focus: () => { input.focus(); screen.render(); },
@@ -432,6 +439,7 @@ function main() {
432
439
  proc.stderr.setEncoding("utf-8");
433
440
 
434
441
  let buf = "", ready = false, generating = false, responseOpen = false, commandOpen = false, closed = false;
442
+ let responseMaybeReasoning = false, responseReasoning = false, responseBuffer = "";
435
443
  const inputQ = [];
436
444
  let mlBuf = [];
437
445
 
@@ -476,7 +484,12 @@ function main() {
476
484
  ui.print(slashHint("/") + "\n Add local papers to RAG:\n cofos --pdf-dir ./new_pdfs\n cofos --pdf-dir ./new_pdfs --rebuild-pdf-index\n\n Multi-line: end a line with \\ to continue.");
477
485
  return false;
478
486
  }
487
+ if (/^\/(cls)$/.test(input)) {
488
+ ui.clear();
489
+ return false;
490
+ }
479
491
  if (/^\/(clear)$/.test(input)) {
492
+ ui.clear();
480
493
  mlBuf = [];
481
494
  responseOpen = false;
482
495
  commandOpen = true;
@@ -495,8 +508,12 @@ function main() {
495
508
  ui.print(`\n COFOS CLI — v${pkg.version}\n Model: ${modelPath} (Hugging Face)\n RAG: Willlzh/COFOS_data/runtime (KG + BM25) + optional --pdf-dir BM25 evidence\n Cache: ${cacheDir}\n HF: ${backendEnv.HF_HOME}\n Engine: StudentAdapterInference + transformers + PyTorch\n Hist: ~/.cofos_history.jsonl\n`);
496
509
  return false;
497
510
  }
511
+ if (input.startsWith("/")) {
512
+ ui.print(`{red-fg}•{/red-fg} Unknown command: ${input}. Press / then Tab for commands, or run /help.`);
513
+ return false;
514
+ }
498
515
 
499
- ui.print(Y + "● " + R + input);
516
+ ui.print("{yellow-fg}{/yellow-fg} " + input);
500
517
  responseOpen = false;
501
518
  generating = true;
502
519
  proc.stdin.write(input + "\n");
@@ -510,6 +527,39 @@ function main() {
510
527
 
511
528
  proc.stderr.on("data", (chunk) => ui.append(chunk));
512
529
 
530
+ function appendAssistant(text) {
531
+ if (!text) return;
532
+ if (responseMaybeReasoning) {
533
+ responseBuffer += text;
534
+ const enough = responseBuffer.length > 80 || responseBuffer.includes("\n\n") || responseBuffer.includes("。") || responseBuffer.includes(".");
535
+ if (!enough) return;
536
+ const start = responseBuffer.trimStart();
537
+ responseReasoning = /^(The user|Okay[,,]|I need|We need|Based on the provided information[,,]? I can|用户)/i.test(start);
538
+ responseMaybeReasoning = false;
539
+ if (responseReasoning) {
540
+ ui.append("{gray-fg}- " + responseBuffer + "{/gray-fg}");
541
+ } else {
542
+ ui.append(responseBuffer);
543
+ }
544
+ responseBuffer = "";
545
+ return;
546
+ }
547
+ if (responseReasoning) {
548
+ const end = text.indexOf("\n\n");
549
+ if (end !== -1) {
550
+ const reason = text.slice(0, end);
551
+ const answer = text.slice(end).replace(/^\s+/, "");
552
+ if (reason) ui.append("{gray-fg}" + reason + "{/gray-fg}");
553
+ responseReasoning = false;
554
+ if (answer) ui.append("\n{green-fg}{bold}◆{/bold}{/green-fg} " + answer);
555
+ } else {
556
+ ui.append("{gray-fg}" + text + "{/gray-fg}");
557
+ }
558
+ return;
559
+ }
560
+ ui.append(text);
561
+ }
562
+
513
563
  proc.stdout.on("data", (chunk) => {
514
564
  buf += chunk;
515
565
  if (!ready) {
@@ -528,7 +578,7 @@ function main() {
528
578
  const di = buf.indexOf(DONE);
529
579
  if (di === -1) return;
530
580
  const pre = buf.slice(0, di).trim();
531
- if (pre) ui.print(G + "• " + R + pre);
581
+ if (pre) ui.print("{gray-fg}{/gray-fg} " + pre);
532
582
  buf = buf.slice(di + DONE.length);
533
583
  if (buf[0] === "\n") buf = buf.slice(1);
534
584
  generating = false;
@@ -548,15 +598,19 @@ function main() {
548
598
  buf = buf.slice(ri + RESPONSE.length);
549
599
  if (buf[0] === "\n") buf = buf.slice(1);
550
600
  responseOpen = true;
551
- ui.append(GR + B + "◆ COFOS " + R);
601
+ responseMaybeReasoning = true;
602
+ responseReasoning = false;
603
+ responseBuffer = "";
604
+ ui.append("{green-fg}{bold}◆{/bold}{/green-fg} ");
552
605
  }
553
606
 
554
607
  const di = buf.indexOf(DONE);
555
608
  if (di !== -1) {
556
609
  const pre = buf.slice(0, di);
557
- if (pre) ui.append(pre);
610
+ if (pre) appendAssistant(pre);
558
611
  buf = buf.slice(di + DONE.length);
559
612
  if (buf[0] === "\n") buf = buf.slice(1);
613
+ if (responseBuffer) { appendAssistant("\n"); }
560
614
  generating = false;
561
615
  responseOpen = false;
562
616
  ui.append("\n");
@@ -566,7 +620,7 @@ function main() {
566
620
  const keep = DONE.length - 1;
567
621
  if (buf.length > keep) {
568
622
  const out = buf.slice(0, -keep);
569
- if (out) ui.append(out);
623
+ if (out) appendAssistant(out);
570
624
  buf = buf.slice(-keep);
571
625
  }
572
626
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lzhzzzzwill/cofos",
3
- "version": "1.2.3",
3
+ "version": "1.2.4",
4
4
  "description": "COFOS 9B + RAG chat CLI with optional local PDF ingestion.",
5
5
  "type": "module",
6
6
  "bin": {