thatgfsj-code 3.0.3 → 3.0.6

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 (212) hide show
  1. package/README.md +64 -21
  2. package/dist/app/index.d.ts +93 -22
  3. package/dist/app/index.d.ts.map +1 -1
  4. package/dist/app/index.js +232 -40
  5. package/dist/app/index.js.map +1 -1
  6. package/dist/cache/smartModel.d.ts +29 -22
  7. package/dist/cache/smartModel.d.ts.map +1 -1
  8. package/dist/cache/smartModel.js +33 -40
  9. package/dist/cache/smartModel.js.map +1 -1
  10. package/dist/cmd/index.d.ts +12 -20
  11. package/dist/cmd/index.d.ts.map +1 -1
  12. package/dist/cmd/index.js +192 -146
  13. package/dist/cmd/index.js.map +1 -1
  14. package/dist/config/index.d.ts +4 -0
  15. package/dist/config/index.d.ts.map +1 -1
  16. package/dist/config/index.js +9 -6
  17. package/dist/config/index.js.map +1 -1
  18. package/dist/config/types.d.ts +5 -0
  19. package/dist/config/types.d.ts.map +1 -1
  20. package/dist/llm/anthropic.d.ts +1 -1
  21. package/dist/llm/anthropic.d.ts.map +1 -1
  22. package/dist/llm/anthropic.js +116 -84
  23. package/dist/llm/anthropic.js.map +1 -1
  24. package/dist/llm/gemini.d.ts +27 -3
  25. package/dist/llm/gemini.d.ts.map +1 -1
  26. package/dist/llm/gemini.js +196 -73
  27. package/dist/llm/gemini.js.map +1 -1
  28. package/dist/llm/index.d.ts +20 -1
  29. package/dist/llm/index.d.ts.map +1 -1
  30. package/dist/llm/index.js +71 -10
  31. package/dist/llm/index.js.map +1 -1
  32. package/dist/llm/openai.d.ts +5 -1
  33. package/dist/llm/openai.d.ts.map +1 -1
  34. package/dist/llm/openai.js +96 -56
  35. package/dist/llm/openai.js.map +1 -1
  36. package/dist/mcp/client.d.ts +84 -34
  37. package/dist/mcp/client.d.ts.map +1 -1
  38. package/dist/mcp/client.js +291 -126
  39. package/dist/mcp/client.js.map +1 -1
  40. package/dist/session/compactor.d.ts +27 -7
  41. package/dist/session/compactor.d.ts.map +1 -1
  42. package/dist/session/compactor.js +78 -23
  43. package/dist/session/compactor.js.map +1 -1
  44. package/dist/session/index.d.ts +96 -33
  45. package/dist/session/index.d.ts.map +1 -1
  46. package/dist/session/index.js +278 -60
  47. package/dist/session/index.js.map +1 -1
  48. package/dist/tools/file.d.ts +10 -2
  49. package/dist/tools/file.d.ts.map +1 -1
  50. package/dist/tools/file.js +54 -5
  51. package/dist/tools/file.js.map +1 -1
  52. package/dist/tools/git.d.ts +16 -2
  53. package/dist/tools/git.d.ts.map +1 -1
  54. package/dist/tools/git.js +61 -18
  55. package/dist/tools/git.js.map +1 -1
  56. package/dist/tools/nwt.d.ts.map +1 -1
  57. package/dist/tools/nwt.js +8 -1
  58. package/dist/tools/nwt.js.map +1 -1
  59. package/dist/tools/search.d.ts +8 -1
  60. package/dist/tools/search.d.ts.map +1 -1
  61. package/dist/tools/search.js +105 -34
  62. package/dist/tools/search.js.map +1 -1
  63. package/dist/tools/shell.d.ts +0 -4
  64. package/dist/tools/shell.d.ts.map +1 -1
  65. package/dist/tools/shell.js +11 -26
  66. package/dist/tools/shell.js.map +1 -1
  67. package/dist/tools/types.d.ts +7 -0
  68. package/dist/tools/types.d.ts.map +1 -1
  69. package/dist/tools/types.js.map +1 -1
  70. package/dist/tui/app.d.ts.map +1 -1
  71. package/dist/tui/app.js +90 -18
  72. package/dist/tui/app.js.map +1 -1
  73. package/dist/tui/components/ChatMessage.d.ts.map +1 -1
  74. package/dist/tui/components/ChatMessage.js +9 -2
  75. package/dist/tui/components/ChatMessage.js.map +1 -1
  76. package/dist/tui/components/ConfirmPrompt.d.ts +21 -0
  77. package/dist/tui/components/ConfirmPrompt.d.ts.map +1 -0
  78. package/dist/tui/components/ConfirmPrompt.js +45 -0
  79. package/dist/tui/components/ConfirmPrompt.js.map +1 -0
  80. package/dist/tui/components/Header.d.ts +10 -5
  81. package/dist/tui/components/Header.d.ts.map +1 -1
  82. package/dist/tui/components/Header.js +13 -5
  83. package/dist/tui/components/Header.js.map +1 -1
  84. package/dist/tui/components/InitWizard.d.ts.map +1 -1
  85. package/dist/tui/components/InitWizard.js +8 -13
  86. package/dist/tui/components/InitWizard.js.map +1 -1
  87. package/dist/tui/components/StatusBar.d.ts +7 -0
  88. package/dist/tui/components/StatusBar.d.ts.map +1 -1
  89. package/dist/tui/components/StatusBar.js +8 -3
  90. package/dist/tui/components/StatusBar.js.map +1 -1
  91. package/dist/tui/components/Thinking.d.ts +5 -0
  92. package/dist/tui/components/Thinking.d.ts.map +1 -1
  93. package/dist/tui/components/Thinking.js +24 -2
  94. package/dist/tui/components/Thinking.js.map +1 -1
  95. package/dist/tui/components/ToolCall.d.ts +6 -1
  96. package/dist/tui/components/ToolCall.d.ts.map +1 -1
  97. package/dist/tui/components/ToolCall.js +50 -22
  98. package/dist/tui/components/ToolCall.js.map +1 -1
  99. package/dist/tui/components/UserInput.d.ts +5 -0
  100. package/dist/tui/components/UserInput.d.ts.map +1 -1
  101. package/dist/tui/components/UserInput.js +9 -13
  102. package/dist/tui/components/UserInput.js.map +1 -1
  103. package/dist/tui/hooks/useChat.d.ts +1 -0
  104. package/dist/tui/hooks/useChat.d.ts.map +1 -1
  105. package/dist/tui/hooks/useChat.js +36 -16
  106. package/dist/tui/hooks/useChat.js.map +1 -1
  107. package/dist/tui/hooks/useCommands.d.ts +7 -1
  108. package/dist/tui/hooks/useCommands.d.ts.map +1 -1
  109. package/dist/tui/hooks/useCommands.js +83 -49
  110. package/dist/tui/hooks/useCommands.js.map +1 -1
  111. package/dist/tui/theme.d.ts +34 -0
  112. package/dist/tui/theme.d.ts.map +1 -0
  113. package/dist/tui/theme.js +34 -0
  114. package/dist/tui/theme.js.map +1 -0
  115. package/dist/tui/welcome.d.ts.map +1 -1
  116. package/dist/tui/welcome.js +9 -7
  117. package/dist/tui/welcome.js.map +1 -1
  118. package/dist/types.d.ts +16 -1
  119. package/dist/types.d.ts.map +1 -1
  120. package/dist/utils/diff.d.ts +5 -0
  121. package/dist/utils/diff.d.ts.map +1 -1
  122. package/dist/utils/diff.js +15 -0
  123. package/dist/utils/diff.js.map +1 -1
  124. package/dist/version.d.ts +12 -0
  125. package/dist/version.d.ts.map +1 -0
  126. package/dist/version.js +29 -0
  127. package/dist/version.js.map +1 -0
  128. package/package.json +19 -7
  129. package/CHANGELOG.md +0 -192
  130. package/DEVELOPMENT.md +0 -286
  131. package/ROADMAP.md +0 -91
  132. package/docs/API_KEY_GUIDE.md +0 -236
  133. package/docs/FAQ.md +0 -182
  134. package/install.bat +0 -63
  135. package/install.ps1 +0 -238
  136. package/install.sh +0 -113
  137. package/src/app/index.ts +0 -197
  138. package/src/cache/fingerprint.ts +0 -101
  139. package/src/cache/index.ts +0 -21
  140. package/src/cache/smartModel.ts +0 -145
  141. package/src/cache/stats.ts +0 -199
  142. package/src/cache/volatile.ts +0 -47
  143. package/src/cmd/index.tsx +0 -288
  144. package/src/config/index.ts +0 -158
  145. package/src/config/providers.ts +0 -234
  146. package/src/config/types.ts +0 -71
  147. package/src/hooks/index.ts +0 -111
  148. package/src/llm/anthropic.ts +0 -413
  149. package/src/llm/gemini.ts +0 -169
  150. package/src/llm/index.ts +0 -302
  151. package/src/llm/openai.ts +0 -243
  152. package/src/llm/provider.ts +0 -71
  153. package/src/mcp/client.ts +0 -330
  154. package/src/prompts/index.ts +0 -260
  155. package/src/session/compactor.ts +0 -103
  156. package/src/session/index.ts +0 -181
  157. package/src/session/message.ts +0 -42
  158. package/src/skills/brainstorming.ts +0 -43
  159. package/src/skills/code-review.ts +0 -45
  160. package/src/skills/executing-plans.ts +0 -27
  161. package/src/skills/frontend-design.ts +0 -35
  162. package/src/skills/git-workflow.ts +0 -36
  163. package/src/skills/improve-architecture.ts +0 -38
  164. package/src/skills/index.ts +0 -136
  165. package/src/skills/neuroweave.ts +0 -47
  166. package/src/skills/playwright.ts +0 -72
  167. package/src/skills/prototype.ts +0 -30
  168. package/src/skills/subagent.ts +0 -28
  169. package/src/skills/supabase.ts +0 -44
  170. package/src/skills/systematic-debugging.ts +0 -44
  171. package/src/skills/tdd.ts +0 -39
  172. package/src/skills/triage.ts +0 -35
  173. package/src/skills/verification.ts +0 -31
  174. package/src/skills/writing-plans.ts +0 -42
  175. package/src/tools/file.ts +0 -143
  176. package/src/tools/git.ts +0 -132
  177. package/src/tools/index.ts +0 -111
  178. package/src/tools/nwt.ts +0 -598
  179. package/src/tools/search.ts +0 -263
  180. package/src/tools/shell.ts +0 -136
  181. package/src/tools/types.ts +0 -122
  182. package/src/tui/app.tsx +0 -159
  183. package/src/tui/components/ChatList.tsx +0 -41
  184. package/src/tui/components/ChatMessage.tsx +0 -54
  185. package/src/tui/components/Header.tsx +0 -66
  186. package/src/tui/components/InitWizard.tsx +0 -251
  187. package/src/tui/components/Markdown.tsx +0 -35
  188. package/src/tui/components/ModelSelector.tsx +0 -107
  189. package/src/tui/components/StatusBar.tsx +0 -30
  190. package/src/tui/components/Thinking.tsx +0 -17
  191. package/src/tui/components/ToolCall.tsx +0 -102
  192. package/src/tui/components/UserInput.tsx +0 -151
  193. package/src/tui/hooks/useChat.ts +0 -287
  194. package/src/tui/hooks/useCommands.ts +0 -273
  195. package/src/tui/index.ts +0 -6
  196. package/src/tui/welcome.ts +0 -177
  197. package/src/types.ts +0 -104
  198. package/src/utils/diff.ts +0 -71
  199. package/src/utils/project.ts +0 -99
  200. package/src/utils/stableStringify.ts +0 -47
  201. package/src/utils/thinking.ts +0 -119
  202. package/tests/cache/fingerprint.test.ts +0 -75
  203. package/tests/cache/providerCatalog.test.ts +0 -31
  204. package/tests/cache/smartModel.test.ts +0 -112
  205. package/tests/cache/stableStringify.test.ts +0 -43
  206. package/tests/cache/stats.test.ts +0 -146
  207. package/tests/cache/volatile.test.ts +0 -75
  208. package/tests/smoke-pollution.mjs +0 -78
  209. package/tests/smoke-thinking.mjs +0 -110
  210. package/tests/smoke-tool-stream.mjs +0 -69
  211. package/tests/smoke-tool.mjs +0 -117
  212. package/tsconfig.json +0 -21
@@ -1,273 +0,0 @@
1
- import { useCallback } from 'react';
2
- import type { App } from '../../app/index.js';
3
-
4
- interface CommandResult {
5
- handled: boolean;
6
- output?: string;
7
- action?: 'clear' | 'reinit';
8
- }
9
-
10
- // 中文命令别名映射
11
- const CMD_ALIASES: Record<string, string> = {
12
- '/模型': '/model',
13
- '/新建': '/new',
14
- '/清空': '/new',
15
- '/压缩': '/compact',
16
- '/技能': '/skills',
17
- '/技能管理': '/skills',
18
- '/mcp': '/mcp',
19
- '/帮助': '/help',
20
- '/服务商': '/provider',
21
- '/思考': '/thinking',
22
- '/缓存': '/cache',
23
- '/ttl': '/ttl',
24
- '/TTL': '/ttl',
25
- };
26
-
27
- export const COMMAND_LIST = [
28
- { name: '/模型', desc: '切换模型' },
29
- { name: '/服务商', desc: '更换服务商' },
30
- { name: '/新建', desc: '新建会话' },
31
- { name: '/压缩', desc: '压缩上下文' },
32
- { name: '/缓存', desc: '缓存命中率' },
33
- { name: '/ttl', desc: '查看/设置 Cache TTL' },
34
- { name: '/技能', desc: '管理技能' },
35
- { name: '/mcp', desc: 'MCP 设置' },
36
- { name: '/帮助', desc: '查看帮助' },
37
- ];
38
-
39
- export function useCommands(app: App) {
40
-
41
- const handleCommand = useCallback((input: string): CommandResult => {
42
- const cmd = input.trim();
43
- const parts = cmd.split(/\s+/);
44
- let name = parts[0].toLowerCase();
45
- const arg = parts.slice(1).join(' ');
46
-
47
- // 中文别名映射
48
- if (CMD_ALIASES[name]) {
49
- name = CMD_ALIASES[name];
50
- }
51
-
52
- // ── /model [name] ───────────────────────────────────
53
- if (name === '/model') {
54
- if (!arg) {
55
- const c = app.config.get();
56
- return {
57
- handled: true,
58
- output: [
59
- `当前: ${c.provider} / ${c.model}`,
60
- '',
61
- '用法: /模型 <名称>',
62
- ' /模型 deepseek-chat',
63
- ' /模型 gpt-4o',
64
- ' /模型 claude-sonnet-4-20250514',
65
- '',
66
- '或: /服务商 更换服务商',
67
- ].join('\n'),
68
- };
69
- }
70
- app.config.save({ model: arg });
71
- return { handled: true, output: `模型 → ${arg}` };
72
- }
73
-
74
- // ── /provider ───────────────────────────────────────
75
- if (name === '/provider') {
76
- return { handled: true, action: 'reinit' };
77
- }
78
-
79
- // ── /new, /clear ────────────────────────────────────
80
- if (name === '/new') {
81
- app.session.clear();
82
- return { handled: true, output: '新会话已创建。', action: 'clear' };
83
- }
84
-
85
- // ── /compact ────────────────────────────────────────
86
- if (name === '/compact') {
87
- const before = app.session.getMessageCount();
88
- app.session.truncate();
89
- const after = app.session.getMessageCount();
90
- return { handled: true, output: `上下文已压缩: ${before} → ${after} 条消息` };
91
- }
92
-
93
- // ── /cache — prompt cache hit-rate + cost savings ───
94
- // v3.0.0: surfaces CacheStatsStore snapshots. Sub-commands:
95
- // /cache show full breakdown
96
- // /cache reset zero the persistent stats
97
- if (name === '/cache') {
98
- if (arg === 'reset' || arg === '重置') {
99
- app.cacheStats.reset();
100
- return { handled: true, output: '✓ 缓存统计已重置' };
101
- }
102
- if (arg === 'off' || arg === '关') {
103
- // Toggle disable: writes through to provider config (currently a
104
- // no-op until M4.5 wires Config.cache). Print a hint.
105
- return {
106
- handled: true,
107
- output: [
108
- '✗ 关闭缓存功能:在 ~/.thatgfsj/config.json 添加 "cache": { "enabled": false } 后重启。',
109
- ' (提示:完全关闭会大幅增加 token 成本;推荐保留开启)',
110
- ].join('\n'),
111
- };
112
- }
113
- const s = app.cacheStats.snapshot();
114
- if (s.totalRequests === 0) {
115
- return {
116
- handled: true,
117
- output: [
118
- '⚡ 缓存统计',
119
- '─────────────────────────',
120
- ' 暂无请求。开启一段对话后再来查看。',
121
- '',
122
- '/cache reset · 重置统计',
123
- ].join('\n'),
124
- };
125
- }
126
- const hitRateStr = (s.hitRate * 100).toFixed(1) + '%';
127
- const recent = s.history.slice(-10);
128
- const lines = [
129
- '⚡ 缓存统计 (累计 ' + s.totalRequests + ' 轮)',
130
- '─────────────────────────',
131
- ` 命中率: ${hitRateStr} (${s.totalReadTokens.toLocaleString()} / ${s.totalInputTokens.toLocaleString()} tokens)`,
132
- ` 累计创建: ${s.totalCreationTokens.toLocaleString()} tokens`,
133
- ` 累计节省: ¥${s.estimatedSavingsCNY.toFixed(4)}`,
134
- '',
135
- '最近 10 轮:',
136
- ];
137
- for (let i = 0; i < recent.length; i++) {
138
- const r = recent[i];
139
- const tag = r.read > 0 ? '⚡' : '💸';
140
- const pct = (r.hitRate * 100).toFixed(0) + '%';
141
- lines.push(` #${s.history.length - recent.length + i + 1} [${tag}] ${String(r.read).padStart(5)} / ${String(r.input).padStart(5)} ${pct.padStart(4)}`);
142
- }
143
- lines.push('');
144
- lines.push('/cache reset · 重置统计');
145
- return { handled: true, output: lines.join('\n') };
146
- }
147
-
148
- // v3.0.3: /ttl — view or pin the cache TTL.
149
- //
150
- // /ttl show current effective TTL + decision reason
151
- // /ttl 5m|1h pin TTL for this session (sticky, no cache reset)
152
- // /ttl auto resume auto-decision (clears the pin)
153
- if (name === '/ttl') {
154
- const configTtl = (app.config.get() as any).cache?.ttl as 'auto' | '5m' | '1h' | undefined;
155
- const resolved = app.resolvedTtl;
156
- if (arg === 'auto') {
157
- app.config.save({ cache: { ...(app.config.get() as any).cache, ttl: 'auto' } });
158
- app.resolvedTtl = null;
159
- return { handled: true, output: '✓ Cache TTL 已重置为自动(下一轮重新评估)' };
160
- }
161
- if (arg === '5m' || arg === '1h') {
162
- app.config.save({ cache: { ...(app.config.get() as any).cache, ttl: arg } });
163
- app.resolvedTtl = arg;
164
- return { handled: true, output: `✓ Cache TTL 已固定为 ${arg}(首次请求会重建缓存)` };
165
- }
166
- // No arg: show current state
167
- const lines = [
168
- '⏱ Cache TTL',
169
- '─────────────────────────',
170
- ` 配置: ${configTtl ?? 'auto'}`,
171
- ` 当前会话: ${resolved ?? '尚未评估'}`,
172
- '',
173
- '说明: '+
174
- (configTtl === 'auto'
175
- ? '自动模式 – 短会话(≤14 轮)用 5m节省写入成本,' +
176
- '长会话(≥15 轮 或 ≥50k 字符)自动升级到 1h 复用缓存。'
177
- : `${configTtl} 模式 – TTL 每次请求都固定。`),
178
- '',
179
- '/ttl 5m|1h|auto 调整 TTL',
180
- ];
181
- return { handled: true, output: lines.join('\n') };
182
- }
183
-
184
- // ── /skills [id] ────────────────────────────────────
185
- if (name === '/skills') {
186
- if (arg) {
187
- if (app.skills.isActive(arg)) {
188
- app.skills.deactivate(arg);
189
- return { handled: true, output: `✗ 已关闭: ${arg}` };
190
- } else if (app.skills.activate(arg)) {
191
- return { handled: true, output: `✓ 已开启: ${arg}` };
192
- }
193
- return { handled: true, output: `未知技能: ${arg}` };
194
- }
195
-
196
- const all = app.skills.list();
197
- const lines = [
198
- '技能列表:',
199
- ...all.map(s => {
200
- const mark = app.skills.isActive(s.id) ? '✓' : '·';
201
- return ` ${mark} ${s.id} ${s.description}`;
202
- }),
203
- '',
204
- '用法: /技能 <id> 切换',
205
- ];
206
- return { handled: true, output: lines.join('\n') };
207
- }
208
-
209
- // ── /mcp ────────────────────────────────────────────
210
- if (name === '/mcp') {
211
- return {
212
- handled: true,
213
- output: [
214
- 'MCP 配置: ~/.thatgfsj/mcp.json',
215
- '',
216
- ' {',
217
- ' "servers": {',
218
- ' "名称": { "command": "npx", "args": ["-y", "server"] }',
219
- ' }',
220
- ' }',
221
- ].join('\n'),
222
- };
223
- }
224
-
225
- // ── /thinking on|off ─────────────────────────────────
226
- if (name === '/thinking' || name === '/思考') {
227
- if (!arg) {
228
- return {
229
- handled: true,
230
- output: `思考块显示: ${app.showThinking ? '开启 (显示完整 <think>...</think>)' : '关闭 (压缩为单行提示)'}`,
231
- };
232
- }
233
- const want = arg.toLowerCase();
234
- if (want === 'on' || want === '开启' || want === 'true' || want === '1') {
235
- app.showThinking = true;
236
- return { handled: true, output: '✓ 已开启完整思考块显示' };
237
- }
238
- if (want === 'off' || want === '关闭' || want === 'false' || want === '0') {
239
- app.showThinking = false;
240
- return { handled: true, output: '✓ 已关闭思考块显示 (压缩为单行提示)' };
241
- }
242
- return { handled: true, output: `用法: /thinking on|off (当前: ${app.showThinking ? 'on' : 'off'})` };
243
- }
244
-
245
- // ── /help ───────────────────────────────────────────
246
- if (name === '/help') {
247
- return {
248
- handled: true,
249
- output: [
250
- '命令列表:',
251
- ' /模型 <名称> 切换模型',
252
- ' /服务商 更换服务商',
253
- ' /新建 新建会话',
254
- ' /压缩 压缩上下文',
255
- ' /缓存 查看缓存命中率',
256
- ' /思考 [on|off] 切换思考块显示',
257
- ' /技能 [id] 管理技能',
258
- ' /mcp MCP 设置',
259
- ' /帮助 查看帮助',
260
- ' exit 退出',
261
- '',
262
- '快捷键:',
263
- ' ↑/↓ 历史记录',
264
- ' Ctrl+C 退出',
265
- ].join('\n'),
266
- };
267
- }
268
-
269
- return { handled: false };
270
- }, [app]);
271
-
272
- return { handleCommand };
273
- }
package/src/tui/index.ts DELETED
@@ -1,6 +0,0 @@
1
- /**
2
- * TUI Module - Ink-based Terminal UI
3
- */
4
-
5
- export { TuiApp } from './app.js';
6
- export { WelcomeScreen } from './welcome.js';
@@ -1,177 +0,0 @@
1
- /**
2
- * Welcome / Setup Wizard - Clean UI
3
- */
4
-
5
- import chalk from 'chalk';
6
- import readline from 'readline';
7
- import { existsSync, mkdirSync, writeFileSync } from 'fs';
8
- import { join } from 'path';
9
- import { homedir } from 'os';
10
- import { PROVIDERS, getModelsForProvider, listProviders, isCustomProvider } from '../config/providers.js';
11
- import type { ProviderName } from '../config/types.js';
12
-
13
- const line = chalk.gray('─'.repeat(52));
14
-
15
- export class WelcomeScreen {
16
-
17
- static show(hasApiKey: boolean): void {
18
- if (hasApiKey) return;
19
-
20
- console.log();
21
- console.log(chalk.cyan.bold(' ⚡ Thatgfsj Code') + chalk.gray(' v0.5.0'));
22
- console.log(chalk.gray(' AI Coding Assistant'));
23
- console.log(line);
24
- console.log();
25
- console.log(chalk.yellow(' ⚠ No API key configured'));
26
- console.log();
27
- console.log(chalk.gray(' Run ') + chalk.cyan.bold('gfcode init') + chalk.gray(' to set up your provider.'));
28
- console.log();
29
- console.log(chalk.gray(' Supported providers:'));
30
- console.log(chalk.gray(' OpenAI · Claude · DeepSeek · Kimi · GLM · Gemini · 中转站'));
31
- console.log(line);
32
- console.log();
33
- }
34
-
35
- static async interactiveSetup(): Promise<void> {
36
- console.clear();
37
- console.log();
38
- console.log(chalk.cyan.bold(' ⚡ Thatgfsj Code') + chalk.gray(' - Setup'));
39
- console.log(line);
40
- console.log();
41
-
42
- const rl = readline.createInterface({
43
- input: process.stdin,
44
- output: process.stdout,
45
- });
46
-
47
- const ask = (prompt: string): Promise<string> =>
48
- new Promise(resolve => rl.question(prompt, answer => resolve(answer.trim())));
49
-
50
- try {
51
- // ── Step 1: Provider ────────────────────────────────
52
- console.log(chalk.bold(' 1. Choose Provider'));
53
- console.log();
54
- const providers = listProviders();
55
- providers.forEach((p, i) => {
56
- const num = chalk.cyan((i + 1).toString().padStart(2));
57
- console.log(` ${num} ${p.name}`);
58
- });
59
- console.log();
60
-
61
- const choice = await ask(chalk.cyan(' ❯ '));
62
- const selected = providers[parseInt(choice) - 1] || providers[0];
63
- const providerName = selected.key;
64
-
65
- // ── Step 2: API Key ─────────────────────────────────
66
- console.log();
67
- console.log(chalk.bold(' 2. API Key'));
68
- console.log();
69
-
70
- let baseUrl: string | undefined;
71
-
72
- if (isCustomProvider(providerName)) {
73
- console.log(chalk.yellow(' Custom Provider (Relay Station)'));
74
- console.log(chalk.gray(' OpenAI-compatible or Anthropic-compatible'));
75
- console.log();
76
- baseUrl = await ask(chalk.cyan(' Base URL ❯ '));
77
- if (!baseUrl) {
78
- console.log(chalk.red(' ❌ Base URL required'));
79
- rl.close();
80
- return;
81
- }
82
- baseUrl = baseUrl.replace(/\/+$/, '');
83
- }
84
-
85
- const apiKey = await ask(chalk.cyan(' API Key ❯ '));
86
-
87
- // ── Step 3: Model ───────────────────────────────────
88
- console.log();
89
- console.log(chalk.bold(' 3. Choose Model'));
90
- console.log();
91
-
92
- let model: string;
93
- if (isCustomProvider(providerName)) {
94
- console.log(chalk.gray(' Enter model name for your relay station'));
95
- console.log(chalk.gray(' e.g. gpt-4o-mini, claude-sonnet-4-20250514'));
96
- console.log();
97
- model = await ask(chalk.cyan(' Model ❯ '));
98
- if (!model) {
99
- console.log(chalk.red(' ❌ Model name required'));
100
- rl.close();
101
- return;
102
- }
103
- } else {
104
- const models = getModelsForProvider(providerName);
105
- models.forEach((m, i) => {
106
- const num = chalk.cyan((i + 1).toString().padStart(2));
107
- console.log(` ${num} ${chalk.white(m.name)} ${chalk.gray(m.desc)}`);
108
- });
109
- console.log();
110
- const modelChoice = await ask(chalk.cyan(' ❯ '));
111
- const selectedModel = models[parseInt(modelChoice) - 1] || models[0];
112
- model = selectedModel.id;
113
- }
114
-
115
- // ── Step 4: Context Length ───────────────────────────
116
- console.log();
117
- console.log(chalk.bold(' 4. Context Length'));
118
- console.log();
119
- console.log(chalk.gray(' Max messages kept in conversation history'));
120
- console.log(chalk.gray(' Higher = more context, more tokens used'));
121
- console.log();
122
- console.log(chalk.cyan(' 1') + ' 20 ' + chalk.gray('(short,节省 token)'));
123
- console.log(chalk.cyan(' 2') + ' 50 ' + chalk.gray('(default,推荐)'));
124
- console.log(chalk.cyan(' 3') + ' 100 ' + chalk.gray('(long,长对话)'));
125
- console.log(chalk.cyan(' 4') + ' 200 ' + chalk.gray('(very long,超长对话)'));
126
- console.log();
127
- const ctxChoice = await ask(chalk.cyan(' ❯ '));
128
- const ctxMap: Record<string, number> = { '1': 20, '2': 50, '3': 100, '4': 200 };
129
- const contextLength = ctxMap[ctxChoice] || 50;
130
-
131
- // ── Save ────────────────────────────────────────────
132
- this.saveConfig(providerName, model, apiKey, baseUrl, contextLength);
133
-
134
- // ── Done ────────────────────────────────────────────
135
- console.log();
136
- console.log(line);
137
- console.log(chalk.green.bold(' ✅ Configuration saved!'));
138
- console.log();
139
- console.log(chalk.gray(' Config: ') + chalk.white(join(homedir(), '.thatgfsj', 'config.json')));
140
- console.log(chalk.gray(' Run ') + chalk.cyan.bold('gfcode') + chalk.gray(' to start.'));
141
- console.log(line);
142
- console.log();
143
-
144
- } finally {
145
- rl.close();
146
- }
147
- }
148
-
149
- private static saveConfig(provider: ProviderName, model: string, apiKey: string, baseUrl?: string, contextLength = 50): void {
150
- const configDir = join(homedir(), '.thatgfsj');
151
- const configPath = join(configDir, 'config.json');
152
-
153
- if (!existsSync(configDir)) {
154
- mkdirSync(configDir, { recursive: true });
155
- }
156
-
157
- const config: Record<string, any> = {
158
- provider,
159
- model,
160
- apiKey,
161
- temperature: 0.7,
162
- maxTokens: 4096,
163
- contextLength,
164
- };
165
-
166
- if (baseUrl) config.baseUrl = baseUrl;
167
-
168
- writeFileSync(configPath, JSON.stringify(config, null, 2));
169
-
170
- console.log();
171
- console.log(chalk.gray(' Provider: ') + chalk.white(provider));
172
- console.log(chalk.gray(' Model: ') + chalk.white(model));
173
- if (baseUrl) {
174
- console.log(chalk.gray(' URL: ') + chalk.white(baseUrl));
175
- }
176
- }
177
- }
package/src/types.ts DELETED
@@ -1,104 +0,0 @@
1
- /**
2
- * Global shared types for Thatgfsj Code
3
- * Only the most fundamental types used across modules
4
- *
5
- * v3.0.0+: Extended for Reasonix-style prompt caching:
6
- * - ChatMessage.content now accepts ContentBlock[] (Anthropic-style)
7
- * - cache_control field for explicit Anthropic cache breakpoints
8
- * - usage extended with cache_creation_input_tokens / cache_read_input_tokens
9
- * (Anthropic) and prompt_cache_hit_tokens / prompt_cache_miss_tokens (DeepSeek)
10
- * - StreamChunk now has 'thinking' / 'usage' variants for structured streaming
11
- */
12
-
13
- export type Role = 'system' | 'user' | 'assistant' | 'tool';
14
-
15
- /**
16
- * Anthropic-style cache control. ttl: '5m' (default) | '1h'
17
- * - '5m': cheaper write cost, refreshed on each hit, expires 5 min after last hit
18
- * - '1h': more expensive write cost, expires 1 hour after last hit
19
- */
20
- export interface CacheControl {
21
- type: 'ephemeral';
22
- ttl?: '5m' | '1h';
23
- }
24
-
25
- /**
26
- * Anthropic-style content blocks. text carries optional cache_control so that
27
- * Anthropic prompt caching breakpoints can be placed inside messages.
28
- */
29
- export type ContentBlock =
30
- | { type: 'text'; text: string; cache_control?: CacheControl }
31
- | { type: 'image'; source: { type: 'base64'; media_type: string; data: string } };
32
-
33
- export interface ChatMessage {
34
- role: Role;
35
- /**
36
- * For 'system' / 'user' / 'assistant' (text only): a plain string.
37
- * For 'user' (multimodal) or 'assistant' (Anthropic tool_use mixed with text):
38
- * an array of ContentBlock.
39
- * 'tool' messages must use string content (carries tool result text).
40
- */
41
- content: string | ContentBlock[];
42
- name?: string;
43
- tool_calls?: ToolCall[];
44
- tool_call_id?: string;
45
- reasoning_content?: string;
46
- /**
47
- * Anthropic prompt caching marker attached to the message itself.
48
- * Only honored when the underlying provider supports it (anthropic, anthropic-relay).
49
- * OpenAI / Gemini / DeepSeek ignore it (DeepSeek uses automatic prefix cache).
50
- */
51
- cache_control?: CacheControl;
52
- }
53
-
54
- export interface ToolCall {
55
- id: string;
56
- type: 'function';
57
- function: {
58
- name: string;
59
- arguments: string;
60
- };
61
- }
62
-
63
- export interface Usage {
64
- prompt_tokens: number;
65
- completion_tokens: number;
66
- total_tokens: number;
67
- // Anthropic prompt cache fields
68
- cache_creation_input_tokens?: number;
69
- cache_read_input_tokens?: number;
70
- // DeepSeek prompt cache fields
71
- prompt_cache_hit_tokens?: number;
72
- prompt_cache_miss_tokens?: number;
73
- }
74
-
75
- export interface ChatResponse {
76
- content: string;
77
- role: 'assistant';
78
- usage?: Usage;
79
- tool_calls?: ToolCall[];
80
- reasoning_content?: string;
81
- }
82
-
83
- export interface ChatOptions {
84
- temperature?: number;
85
- maxTokens?: number;
86
- stream?: boolean;
87
- }
88
-
89
- /**
90
- * Structured streaming chunk. Replaces the legacy @@TOOL@@ sentinel-string
91
- * protocol that the previous version of useChat parsed by string-splitting.
92
- *
93
- * - 'text': regular model output
94
- * - 'tool_calls': one or more tool calls ready to dispatch
95
- * - 'thinking': reasoning content (stripped from final persistence; kept in
96
- * VolatileScratch for the current round only)
97
- * - 'usage': token usage + cache stats; emitted at end of stream if
98
- * the upstream provider returned them
99
- */
100
- export type StreamChunk =
101
- | { type: 'text'; content: string }
102
- | { type: 'tool_calls'; toolCalls: ToolCall[] }
103
- | { type: 'thinking'; content: string }
104
- | { type: 'usage'; usage: Usage };
package/src/utils/diff.ts DELETED
@@ -1,71 +0,0 @@
1
- /**
2
- * Diff Preview - Show file changes in a readable format
3
- * Migrated from old src/utils/diff-preview.ts
4
- */
5
-
6
- export interface DiffResult {
7
- original: string;
8
- modified: string;
9
- diff: string;
10
- added: number;
11
- removed: number;
12
- }
13
-
14
- export class DiffPreview {
15
- /**
16
- * Generate a simple line-by-line diff
17
- */
18
- static diff(original: string, modified: string): DiffResult {
19
- const originalLines = original.split('\n');
20
- const modifiedLines = modified.split('\n');
21
- const diffLines: string[] = [];
22
- let added = 0;
23
- let removed = 0;
24
-
25
- // Simple diff: show removed (-) and added (+) lines
26
- const maxLen = Math.max(originalLines.length, modifiedLines.length);
27
-
28
- for (let i = 0; i < maxLen; i++) {
29
- const orig = originalLines[i];
30
- const mod = modifiedLines[i];
31
-
32
- if (orig === mod) {
33
- diffLines.push(` ${orig}`);
34
- } else {
35
- if (orig !== undefined) {
36
- diffLines.push(`- ${orig}`);
37
- removed++;
38
- }
39
- if (mod !== undefined) {
40
- diffLines.push(`+ ${mod}`);
41
- added++;
42
- }
43
- }
44
- }
45
-
46
- return {
47
- original,
48
- modified,
49
- diff: diffLines.join('\n'),
50
- added,
51
- removed,
52
- };
53
- }
54
-
55
- /**
56
- * Format diff for display
57
- */
58
- static format(result: DiffResult): string {
59
- const lines = result.diff.split('\n').map(line => {
60
- if (line.startsWith('+')) return `\x1b[32m${line}\x1b[0m`;
61
- if (line.startsWith('-')) return `\x1b[31m${line}\x1b[0m`;
62
- return line;
63
- });
64
-
65
- return [
66
- `\x1b[36m--- Changes: -${result.removed} / +${result.added} ---\x1b[0m`,
67
- ...lines,
68
- `\x1b[36m--- End ---\x1b[0m`,
69
- ].join('\n');
70
- }
71
- }