dsh-codebase-chat 0.25.2 → 0.25.5

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/dist/cli.js CHANGED
@@ -1623,6 +1623,10 @@ function formatHealthReport(r, lang = "fr") {
1623
1623
  };
1624
1624
  const out = [];
1625
1625
  out.push(`== ${t2.title} \u2014 ${basename(r.projectPath)} ==`);
1626
+ if (r.analyzedFiles === 0) {
1627
+ out.push(lang === "en" ? "No code files detected in this project \u2014 check the path or your .codebase-chat.json ignore rules." : "Aucun fichier de code d\xE9tect\xE9 dans ce projet \u2014 v\xE9rifie le chemin ou les r\xE8gles ignore de .codebase-chat.json.");
1628
+ return out.join("\n");
1629
+ }
1626
1630
  out.push(`${t2.score}: ${r.score}/100 (${r.grade}) \xB7 ${r.analyzedFiles} ${t2.files} \xB7 ${r.importEdges} ${t2.edges}`);
1627
1631
  out.push("");
1628
1632
  out.push(`\u25CF ${t2.cycles} (${r.cycles.length})`);
@@ -2533,7 +2537,7 @@ import { existsSync as existsSync2 } from "fs";
2533
2537
  import { join as join8 } from "path";
2534
2538
  var DEFAULT_MODEL_URI = "hf:Qwen/Qwen2.5-1.5B-Instruct-GGUF:Q4_K_M";
2535
2539
  var LOCAL_CONTEXT_SIZE = 8192;
2536
- var LOCAL_MAX_TOKENS = 1024;
2540
+ var LOCAL_MAX_TOKENS = 1536;
2537
2541
  function isLocalLlmEnabled() {
2538
2542
  return !!(process.env.CODEBASE_LOCAL_LLM || "").trim();
2539
2543
  }
@@ -2584,13 +2588,42 @@ async function callLocalLlm(prompt, lang = "fr") {
2584
2588
  contextSequence: context.getSequence(),
2585
2589
  systemPrompt: lang === "en" ? "You are a senior codebase analyst. Be precise and cite files with [source: path:line]." : "Tu es un analyste codebase senior. Sois precis et cite les fichiers avec [source: chemin:ligne]."
2586
2590
  });
2587
- return await session.prompt(prompt, { temperature: 0.2, maxTokens: LOCAL_MAX_TOKENS });
2591
+ return await session.prompt(prompt, {
2592
+ temperature: 0.2,
2593
+ maxTokens: LOCAL_MAX_TOKENS,
2594
+ // Small models degenerate into loops at low temperature — penalize
2595
+ // repeated tokens so the answer moves forward instead of echoing.
2596
+ repeatPenalty: { lastTokens: 128, penalty: 1.2, penalizeNewLine: false }
2597
+ });
2588
2598
  } finally {
2589
2599
  await context.dispose();
2590
2600
  }
2591
2601
  }
2592
2602
 
2593
2603
  // src/cli.ts
2604
+ var ANSI = { reset: "\x1B[0m", bold: "\x1B[1m", dim: "\x1B[2m", cyan: "\x1B[36m", yellow: "\x1B[33m", magenta: "\x1B[35m", green: "\x1B[32m" };
2605
+ function renderAnswerTerminal(md) {
2606
+ let inCode = false;
2607
+ const inline = (s) => s.replace(/\*\*([^*]+)\*\*/g, `${ANSI.bold}$1${ANSI.reset}`).replace(/`([^`]+)`/g, `${ANSI.cyan}$1${ANSI.reset}`).replace(/\[source: ([^\]]+)\]/g, `${ANSI.dim}${ANSI.cyan}[source: $1]${ANSI.reset}`);
2608
+ return md.split("\n").map((line) => {
2609
+ if (/^\s*```/.test(line)) {
2610
+ inCode = !inCode;
2611
+ return `${ANSI.dim} \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500${ANSI.reset}`;
2612
+ }
2613
+ if (inCode) return `${ANSI.dim} ${line}${ANSI.reset}`;
2614
+ const h = line.match(/^(#{1,6})\s+(.*)/);
2615
+ if (h) {
2616
+ const color = h[1].length <= 2 ? `${ANSI.bold}${ANSI.magenta}` : `${ANSI.bold}${ANSI.yellow}`;
2617
+ return `
2618
+ ${color}${h[2]}${ANSI.reset}`;
2619
+ }
2620
+ const bullet = line.match(/^(\s*)([-*•]|\d+\.)\s+(.*)/);
2621
+ if (bullet) return `${bullet[1]}${ANSI.cyan}${bullet[2]}${ANSI.reset} ${inline(bullet[3])}`;
2622
+ if (/^\s*>/.test(line)) return `${ANSI.dim}${ANSI.green}\u2502${ANSI.reset}${ANSI.dim} ${inline(line.replace(/^\s*>\s?/, ""))}${ANSI.reset}`;
2623
+ if (/^\s*(---+|\*\*\*+)\s*$/.test(line)) return `${ANSI.dim}${"\u2500".repeat(60)}${ANSI.reset}`;
2624
+ return inline(line);
2625
+ }).join("\n");
2626
+ }
2594
2627
  var ExitSignal = class {
2595
2628
  constructor(code) {
2596
2629
  this.code = code;
@@ -2795,7 +2828,7 @@ ${formatHealthReport(report, lang)}`;
2795
2828
  try {
2796
2829
  prompt = useLocal ? `${result.context}${staticSection}
2797
2830
 
2798
- ${lang === "en" ? `Answer based only on the codebase context above (${mode} mode). Be concise and cite file paths and lines.${query ? ` Question: ${query}` : ""}` : `R\xE9ponds en t'appuyant uniquement sur le contexte du codebase ci-dessus (mode ${mode}). Sois concis et cite les chemins de fichiers et lignes.${query ? ` Question : ${query}` : ""}`}
2831
+ ${lang === "en" ? `Answer based only on the codebase context above (${mode} mode). Structure your answer in short sections with bullet points, and cite each fact as [source: path:line].${query ? ` Question: ${query}` : ""}` : `R\xE9ponds en t'appuyant uniquement sur le contexte du codebase ci-dessus (mode ${mode}). Structure ta r\xE9ponse en sections courtes avec des puces, et cite chaque fait avec [source: fichier:ligne].${query ? ` Question : ${query}` : ""}`}
2799
2832
 
2800
2833
  ${lang === "en" ? "Answer" : "R\xE9ponse"} :` : buildToolPrompt(tool, {
2801
2834
  context: `${result.context}${staticSection}`,
@@ -2813,7 +2846,8 @@ ${lang === "en" ? "Answer" : "R\xE9ponse"} :` : buildToolPrompt(tool, {
2813
2846
  }
2814
2847
  if (values.local || isLocalLlmEnabled()) {
2815
2848
  console.error(lang === "en" ? "Answering with the embedded local model (first run downloads ~1 GB)..." : "R\xE9ponse via le mod\xE8le local embarqu\xE9 (premier lancement : ~1 Go de t\xE9l\xE9chargement)...");
2816
- console.log(await callLocalLlm(prompt, lang));
2849
+ const answer = await callLocalLlm(prompt, lang);
2850
+ console.log(process.stdout.isTTY ? renderAnswerTerminal(answer) : answer);
2817
2851
  exit(0);
2818
2852
  }
2819
2853
  if (values.call) {
@@ -2844,7 +2878,8 @@ ${lang === "en" ? "Answer" : "R\xE9ponse"} :` : buildToolPrompt(tool, {
2844
2878
  exit(1);
2845
2879
  }
2846
2880
  const data = await res.json();
2847
- console.log(data.choices?.[0]?.message?.content || "");
2881
+ const answer = data.choices?.[0]?.message?.content || "";
2882
+ console.log(process.stdout.isTTY ? renderAnswerTerminal(answer) : answer);
2848
2883
  exit(0);
2849
2884
  }
2850
2885
  console.log(prompt);
@@ -2869,7 +2904,7 @@ ${lang === "en" ? "Answer" : "R\xE9ponse"} :` : buildToolPrompt(tool, {
2869
2904
  exit(0);
2870
2905
  }
2871
2906
  printHelp();
2872
- exit(1);
2907
+ exit(0);
2873
2908
  }
2874
2909
  main().catch((err) => {
2875
2910
  disposeTreeSitter();