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 +41 -6
- package/dist/cli.js.map +1 -1
- package/dist/index.js +16 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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 =
|
|
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, {
|
|
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).
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
2907
|
+
exit(0);
|
|
2873
2908
|
}
|
|
2874
2909
|
main().catch((err) => {
|
|
2875
2910
|
disposeTreeSitter();
|