thatgfsj-code 1.0.2 → 2.2.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/.nwt/meta.json +5 -0
- package/CHANGELOG.md +244 -0
- package/DEVELOPMENT.md +286 -0
- package/README.md +23 -1
- package/dist/app/index.d.ts +14 -0
- package/dist/app/index.d.ts.map +1 -1
- package/dist/app/index.js +21 -5
- package/dist/app/index.js.map +1 -1
- package/dist/cmd/index.d.ts +21 -0
- package/dist/cmd/index.d.ts.map +1 -1
- package/dist/cmd/index.js +144 -12
- package/dist/cmd/index.js.map +1 -1
- package/dist/session/index.d.ts +11 -0
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/index.js +83 -1
- package/dist/session/index.js.map +1 -1
- package/dist/tools/nwt.d.ts +14 -4
- package/dist/tools/nwt.d.ts.map +1 -1
- package/dist/tools/nwt.js +160 -13
- package/dist/tools/nwt.js.map +1 -1
- package/dist/tui/components/ChatList.d.ts.map +1 -1
- package/dist/tui/components/ChatList.js +4 -3
- package/dist/tui/components/ChatList.js.map +1 -1
- package/dist/tui/components/Header.d.ts.map +1 -1
- package/dist/tui/components/Header.js +2 -1
- package/dist/tui/components/Header.js.map +1 -1
- package/dist/tui/components/ToolCall.d.ts +1 -1
- package/dist/tui/components/ToolCall.d.ts.map +1 -1
- package/dist/tui/components/ToolCall.js +9 -4
- package/dist/tui/components/ToolCall.js.map +1 -1
- package/dist/tui/hooks/useChat.d.ts.map +1 -1
- package/dist/tui/hooks/useChat.js +47 -6
- package/dist/tui/hooks/useChat.js.map +1 -1
- package/dist/tui/hooks/useCommands.d.ts.map +1 -1
- package/dist/tui/hooks/useCommands.js +21 -0
- package/dist/tui/hooks/useCommands.js.map +1 -1
- package/dist/tui/welcome.d.ts.map +1 -1
- package/dist/tui/welcome.js +3 -2
- package/dist/tui/welcome.js.map +1 -1
- package/dist/utils/thinking.d.ts +59 -0
- package/dist/utils/thinking.d.ts.map +1 -0
- package/dist/utils/thinking.js +107 -0
- package/dist/utils/thinking.js.map +1 -0
- package/dist/version.d.ts +16 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +16 -0
- package/dist/version.js.map +1 -0
- package/install.bat +63 -0
- package/install.ps1 +238 -0
- package/install.sh +113 -0
- package/package.json +5 -2
- package/src/app/index.ts +21 -5
- package/src/cmd/index.tsx +145 -13
- package/src/session/index.ts +82 -1
- package/src/tools/nwt.ts +181 -13
- package/src/tui/components/ChatList.tsx +15 -6
- package/src/tui/components/Header.tsx +2 -1
- package/src/tui/components/ToolCall.tsx +46 -10
- package/src/tui/hooks/useChat.ts +50 -6
- package/src/tui/hooks/useCommands.ts +22 -0
- package/src/tui/welcome.ts +3 -2
- package/src/utils/thinking.ts +122 -0
- package/src/version.ts +16 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thinking block extraction + compression
|
|
3
|
+
*
|
|
4
|
+
* Models that aren't truly reasoning-capable (Qwen, DeepSeek-V3 chat,
|
|
5
|
+
* Kimi, etc.) still emit `<think>...</think>` blocks as plain text
|
|
6
|
+
* inside their response. These blocks can be hundreds of lines of
|
|
7
|
+
* internal monologue that the user doesn't want to see scroll by.
|
|
8
|
+
*
|
|
9
|
+
* opencode handles this by separating reasoning into its own stream
|
|
10
|
+
* part at the protocol level. We don't have that luxury — the model
|
|
11
|
+
* is emitting everything as a single `content` field. So we use the
|
|
12
|
+
* same regex-strip approach opencode uses internally (see
|
|
13
|
+
* packages/opencode/src/session/prompt.ts line 244).
|
|
14
|
+
*
|
|
15
|
+
* Three block delimiters are supported:
|
|
16
|
+
* 1. <think>...</think> — DeepSeek / Qwen / Kimi
|
|
17
|
+
* 2. <reasoning>...</reasoning> — OpenRouter-style
|
|
18
|
+
* 3. [THINK]...[/THINK] — some custom fine-tunes
|
|
19
|
+
*
|
|
20
|
+
* Usage:
|
|
21
|
+
* const { thinking, conclusion } = splitThinking(fullContent);
|
|
22
|
+
* if (thinking && compress) {
|
|
23
|
+
* render(`💭 ${summarize(thinking)}\n${conclusion}`);
|
|
24
|
+
* } else {
|
|
25
|
+
* render(fullContent);
|
|
26
|
+
* }
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
export interface ThinkingSplit {
|
|
30
|
+
/** Raw `<think>...` content, or empty if none. */
|
|
31
|
+
thinking: string;
|
|
32
|
+
/** Content with thinking blocks stripped + trimmed. */
|
|
33
|
+
conclusion: string;
|
|
34
|
+
/** How many lines the thinking block spanned. */
|
|
35
|
+
thinkingLines: number;
|
|
36
|
+
/** First non-empty line of the thinking block (heuristic summary). */
|
|
37
|
+
thinkingHint: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* All known thinking-block delimiters, in priority order. The regex
|
|
42
|
+
* flags `gi` (global, case-insensitive) so `[THINK]` and `<think>`
|
|
43
|
+
* are both caught, and so multiple blocks collapse cleanly.
|
|
44
|
+
*/
|
|
45
|
+
const THINKING_PATTERNS: RegExp[] = [
|
|
46
|
+
/<think>[\s\S]*?<\/think>/gi,
|
|
47
|
+
/<thinking>[\s\S]*?<\/thinking>/gi,
|
|
48
|
+
/<reasoning>[\s\S]*?<\/reasoning>/gi,
|
|
49
|
+
/<THINK>[\s\S]*?<\/THINK>/gi, // v2.2.7 edge: case variant
|
|
50
|
+
/\[THINK\][\s\S]*?\[\/THINK\]/gi,
|
|
51
|
+
/\[\/?think\]/gi, // bare [think] / [/think] (rare)
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
export function splitThinking(content: string): ThinkingSplit {
|
|
55
|
+
if (!content) {
|
|
56
|
+
return { thinking: '', conclusion: '', thinkingLines: 0, thinkingHint: '' };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
let thinking = '';
|
|
60
|
+
let remaining = content;
|
|
61
|
+
|
|
62
|
+
for (const pat of THINKING_PATTERNS) {
|
|
63
|
+
const matches = remaining.match(pat);
|
|
64
|
+
if (matches) {
|
|
65
|
+
thinking += matches.join('\n');
|
|
66
|
+
remaining = remaining.replace(pat, '');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const conclusion = remaining.trim();
|
|
71
|
+
const thinkingLines = thinking ? thinking.split('\n').length : 0;
|
|
72
|
+
const thinkingHint = firstNonEmptyLine(thinking);
|
|
73
|
+
|
|
74
|
+
return { thinking, conclusion, thinkingLines, thinkingHint };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Build a short, single-line summary of a thinking block, suitable
|
|
79
|
+
* for collapsed display. Returns something like:
|
|
80
|
+
* "💭 thought for 24 lines: The user is asking about Win+E..."
|
|
81
|
+
* Falls back to "(no hint)" if the block is empty.
|
|
82
|
+
*/
|
|
83
|
+
export function summarizeThinking(split: ThinkingSplit): string {
|
|
84
|
+
if (!split.thinking) return '';
|
|
85
|
+
const hint = split.thinkingHint.length > 60
|
|
86
|
+
? split.thinkingHint.slice(0, 57) + '...'
|
|
87
|
+
: split.thinkingHint;
|
|
88
|
+
return `💭 thought for ${split.thinkingLines} line${split.thinkingLines === 1 ? '' : 's'}${hint ? `: ${hint}` : ''}`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Render full content with thinking blocks compressed (collapsed to
|
|
93
|
+
* a single-line indicator). If `showThinking` is true, returns the
|
|
94
|
+
* content unchanged (debug mode).
|
|
95
|
+
*/
|
|
96
|
+
export function compressThinking(content: string, showThinking: boolean = false): string {
|
|
97
|
+
if (showThinking || !content) return content;
|
|
98
|
+
const split = splitThinking(content);
|
|
99
|
+
if (!split.thinking) return content;
|
|
100
|
+
const summary = summarizeThinking(split);
|
|
101
|
+
return summary ? `${summary}\n${split.conclusion}` : split.conclusion;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function firstNonEmptyLine(s: string): string {
|
|
105
|
+
if (!s) return '';
|
|
106
|
+
for (const line of s.split('\n')) {
|
|
107
|
+
// Strip any leading/trailing thinking-tag fragments that may have
|
|
108
|
+
// been captured by the regex (e.g. "<think>The user said..."
|
|
109
|
+
// or "...</think>"). We strip ALL occurrences to handle the
|
|
110
|
+
// case where the first line wraps across a tag.
|
|
111
|
+
const t = line
|
|
112
|
+
.trim()
|
|
113
|
+
.replace(/<\/?think>/gi, '')
|
|
114
|
+
.replace(/<\/?reasoning>/gi, '')
|
|
115
|
+
.replace(/\[\/?THINK\]/gi, '')
|
|
116
|
+
.trim();
|
|
117
|
+
if (t) return t;
|
|
118
|
+
}
|
|
119
|
+
return '';
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export { THINKING_PATTERNS };
|
package/src/version.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Product version (what users see in --version, the TUI header, and
|
|
3
|
+
* the welcome screen). This is SEPARATE from the npm package version
|
|
4
|
+
* (`package.json` `version` field) — see the dual-version scheme docs
|
|
5
|
+
* in CHANGELOG.md (v2.2.2 entry).
|
|
6
|
+
*
|
|
7
|
+
* Bump this when shipping a user-visible change. Bump package.json
|
|
8
|
+
* version (npm version) at the same time. They are both +0.0.1 per
|
|
9
|
+
* release.
|
|
10
|
+
*/
|
|
11
|
+
export const PRODUCT_VERSION = '0.4.6';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Convenience: format with leading "v" for display contexts.
|
|
15
|
+
*/
|
|
16
|
+
export const PRODUCT_VERSION_DISPLAY = `v${PRODUCT_VERSION}`;
|