kafox-cli 0.9.8 → 0.9.9
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/package.json +18 -1
- package/src/tools.js +13 -2
- package/src/tui.js +34 -19
package/package.json
CHANGED
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kafox-cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.9",
|
|
4
4
|
"description": "Kafox CLI: TUI com streaming, thinking, edit com diff, agent tools (files/shell), MCP e temas",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/kafox/kafox-cli.git"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://kafox.com",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/kafox/kafox-cli/issues"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"cli",
|
|
15
|
+
"tui",
|
|
16
|
+
"ai",
|
|
17
|
+
"agent",
|
|
18
|
+
"llm",
|
|
19
|
+
"mcp"
|
|
20
|
+
],
|
|
5
21
|
"bin": {
|
|
6
22
|
"kafox": "bin/kafox.js"
|
|
7
23
|
},
|
|
@@ -14,6 +30,7 @@
|
|
|
14
30
|
"node": ">=22.5"
|
|
15
31
|
},
|
|
16
32
|
"license": "MIT",
|
|
33
|
+
"author": "Kafox <dev@kafox.com> (https://kafox.com)",
|
|
17
34
|
"dependencies": {
|
|
18
35
|
"chalk": "4.1.2",
|
|
19
36
|
"commander": "12.1.0",
|
package/src/tools.js
CHANGED
|
@@ -122,9 +122,20 @@ function toolMeta(name, hub) {
|
|
|
122
122
|
|
|
123
123
|
function resolveInside(cwd, target) {
|
|
124
124
|
const root = path.resolve(cwd);
|
|
125
|
-
const
|
|
125
|
+
const raw = String(target ?? ".");
|
|
126
|
+
// Caminho absoluto de outro sistema (ex.: "C:\Windows\..." no Linux) e
|
|
127
|
+
// NUL nunca valem: sem isso o `path.resolve` trata como nome de arquivo.
|
|
128
|
+
if (raw.includes("\0")) throw new Error(`caminho invalido: ${raw}`);
|
|
129
|
+
if (path.win32.isAbsolute(raw) || path.posix.isAbsolute(raw)) {
|
|
130
|
+
const full = path.isAbsolute(raw) ? path.resolve(raw) : null;
|
|
131
|
+
if (!full || (full !== root && !full.startsWith(root + path.sep))) {
|
|
132
|
+
throw new Error(`caminho fora do diretorio de trabalho: ${raw}`);
|
|
133
|
+
}
|
|
134
|
+
return full;
|
|
135
|
+
}
|
|
136
|
+
const full = path.resolve(root, raw);
|
|
126
137
|
if (full !== root && !full.startsWith(root + path.sep)) {
|
|
127
|
-
throw new Error(`caminho fora do diretorio de trabalho: ${
|
|
138
|
+
throw new Error(`caminho fora do diretorio de trabalho: ${raw}`);
|
|
128
139
|
}
|
|
129
140
|
return full;
|
|
130
141
|
}
|
package/src/tui.js
CHANGED
|
@@ -905,8 +905,36 @@ function formatTokens(count) {
|
|
|
905
905
|
return `${(count / 1_000_000).toFixed(1)}M`;
|
|
906
906
|
}
|
|
907
907
|
|
|
908
|
-
|
|
909
|
-
|
|
908
|
+
/**
|
|
909
|
+
* Commita o texto que chegou pelo stream como mensagem `assistant`.
|
|
910
|
+
* Nao duplica quando o mesmo trecho ja foi commitado neste turno (retry do
|
|
911
|
+
* gateway repetindo tokens, `onToolStart` chamado duas vezes, etc.).
|
|
912
|
+
*/
|
|
913
|
+
function commitStreamedText(state, text) {
|
|
914
|
+
const value = String(text || "").trim();
|
|
915
|
+
if (!value) return false;
|
|
916
|
+
if (state.streamedText.includes(value)) return false;
|
|
917
|
+
const previous = [...state.messages].reverse().find((message) => message.role === "assistant");
|
|
918
|
+
if (previous && previous.text === value) return false;
|
|
919
|
+
state.messages.push({ role: "assistant", text: value });
|
|
920
|
+
state.streamedText = `${state.streamedText}${value}`;
|
|
921
|
+
return true;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
/**
|
|
925
|
+
* Ultimo texto devolvido por `runAgent`. Quando o stream ja mostrou esse texto
|
|
926
|
+
* (commit em `finishStreaming`), nao empurra de novo: era isso que fazia a
|
|
927
|
+
* resposta aparecer duas vezes na tela.
|
|
928
|
+
*/
|
|
929
|
+
function commitFinalText(state, text, ms) {
|
|
930
|
+
const value = String(text || "").trim();
|
|
931
|
+
if (!value) return false;
|
|
932
|
+
if (state.streamedText.includes(value)) return false;
|
|
933
|
+
state.messages.push({ role: "assistant", text: value, ms });
|
|
934
|
+
return true;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
function estimateTokens(state) { let chars = 0;
|
|
910
938
|
for (const message of state.context) chars += String(message.content || "").length;
|
|
911
939
|
if (state.streaming) chars += String(state.streaming.text || "").length;
|
|
912
940
|
return Math.round(chars / 4);
|
|
@@ -1955,13 +1983,7 @@ async function runTUI({
|
|
|
1955
1983
|
const text = String(result.text || "").trim();
|
|
1956
1984
|
// O stream ja foi commitado em finishStreaming(): so empurra aqui se for
|
|
1957
1985
|
// texto novo (ou se nao houve streaming, ex.: resposta sem onText).
|
|
1958
|
-
if (text
|
|
1959
|
-
state.messages.push({
|
|
1960
|
-
role: "assistant",
|
|
1961
|
-
text,
|
|
1962
|
-
ms: result.ms,
|
|
1963
|
-
});
|
|
1964
|
-
}
|
|
1986
|
+
if (text) commitFinalText(state, text, result.ms);
|
|
1965
1987
|
state.streamedText = "";
|
|
1966
1988
|
if (result.messages) state.context = result.messages;
|
|
1967
1989
|
} else {
|
|
@@ -1989,16 +2011,7 @@ async function runTUI({
|
|
|
1989
2011
|
ms: streaming.thinkingStartedAt ? Date.now() - streaming.thinkingStartedAt : 0,
|
|
1990
2012
|
});
|
|
1991
2013
|
}
|
|
1992
|
-
if (streaming.text.trim())
|
|
1993
|
-
const text = streaming.text.trim();
|
|
1994
|
-
// Evita repetir o texto quando o mesmo trecho ja foi commitado (retry
|
|
1995
|
-
// que repetiu tokens ou onToolStart chamado duas vezes).
|
|
1996
|
-
const previous = [...state.messages].reverse().find((message) => message.role === "assistant");
|
|
1997
|
-
if (!previous || previous.text !== text) {
|
|
1998
|
-
state.messages.push({ role: "assistant", text });
|
|
1999
|
-
state.streamedText += text;
|
|
2000
|
-
}
|
|
2001
|
-
}
|
|
2014
|
+
if (streaming.text.trim()) commitStreamedText(state, streaming.text.trim());
|
|
2002
2015
|
state.streaming = { text: "", reasoning: "", thinkingStartedAt: 0 };
|
|
2003
2016
|
}
|
|
2004
2017
|
|
|
@@ -2396,4 +2409,6 @@ module.exports = {
|
|
|
2396
2409
|
planRepaint,
|
|
2397
2410
|
APPROVAL_OPTIONS,
|
|
2398
2411
|
layoutFor,
|
|
2412
|
+
commitStreamedText,
|
|
2413
|
+
commitFinalText,
|
|
2399
2414
|
};
|