thatgfsj-code 1.0.3 → 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.
Files changed (57) hide show
  1. package/.nwt/meta.json +5 -0
  2. package/CHANGELOG.md +244 -0
  3. package/DEVELOPMENT.md +286 -0
  4. package/dist/app/index.d.ts +14 -0
  5. package/dist/app/index.d.ts.map +1 -1
  6. package/dist/app/index.js +21 -5
  7. package/dist/app/index.js.map +1 -1
  8. package/dist/cmd/index.d.ts +21 -0
  9. package/dist/cmd/index.d.ts.map +1 -1
  10. package/dist/cmd/index.js +144 -12
  11. package/dist/cmd/index.js.map +1 -1
  12. package/dist/session/index.d.ts +11 -0
  13. package/dist/session/index.d.ts.map +1 -1
  14. package/dist/session/index.js +83 -1
  15. package/dist/session/index.js.map +1 -1
  16. package/dist/tui/components/ChatList.d.ts.map +1 -1
  17. package/dist/tui/components/ChatList.js +4 -3
  18. package/dist/tui/components/ChatList.js.map +1 -1
  19. package/dist/tui/components/Header.d.ts.map +1 -1
  20. package/dist/tui/components/Header.js +2 -1
  21. package/dist/tui/components/Header.js.map +1 -1
  22. package/dist/tui/components/ToolCall.d.ts +1 -1
  23. package/dist/tui/components/ToolCall.d.ts.map +1 -1
  24. package/dist/tui/components/ToolCall.js +9 -4
  25. package/dist/tui/components/ToolCall.js.map +1 -1
  26. package/dist/tui/hooks/useChat.d.ts.map +1 -1
  27. package/dist/tui/hooks/useChat.js +47 -6
  28. package/dist/tui/hooks/useChat.js.map +1 -1
  29. package/dist/tui/hooks/useCommands.d.ts.map +1 -1
  30. package/dist/tui/hooks/useCommands.js +21 -0
  31. package/dist/tui/hooks/useCommands.js.map +1 -1
  32. package/dist/tui/welcome.d.ts.map +1 -1
  33. package/dist/tui/welcome.js +3 -2
  34. package/dist/tui/welcome.js.map +1 -1
  35. package/dist/utils/thinking.d.ts +59 -0
  36. package/dist/utils/thinking.d.ts.map +1 -0
  37. package/dist/utils/thinking.js +107 -0
  38. package/dist/utils/thinking.js.map +1 -0
  39. package/dist/version.d.ts +16 -0
  40. package/dist/version.d.ts.map +1 -0
  41. package/dist/version.js +16 -0
  42. package/dist/version.js.map +1 -0
  43. package/install.bat +63 -0
  44. package/install.ps1 +238 -0
  45. package/install.sh +113 -0
  46. package/package.json +5 -2
  47. package/src/app/index.ts +21 -5
  48. package/src/cmd/index.tsx +145 -13
  49. package/src/session/index.ts +82 -1
  50. package/src/tui/components/ChatList.tsx +15 -6
  51. package/src/tui/components/Header.tsx +2 -1
  52. package/src/tui/components/ToolCall.tsx +46 -10
  53. package/src/tui/hooks/useChat.ts +50 -6
  54. package/src/tui/hooks/useCommands.ts +22 -0
  55. package/src/tui/welcome.ts +3 -2
  56. package/src/utils/thinking.ts +122 -0
  57. package/src/version.ts +16 -0
package/.nwt/meta.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "version": "2.0.0",
3
+ "created": "2026-07-06T19:29:58.147Z",
4
+ "description": "NeuroWeave Timeline - Project evolution memory"
5
+ }
package/CHANGELOG.md ADDED
@@ -0,0 +1,244 @@
1
+ # Changelog
2
+
3
+ All notable changes to **Thatgfsj Code** are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/) and the project adheres to
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [2.2.8 / 产品 0.4.5] - 2026-07-06 - 边界测试驱动的 5 处修复
8
+
9
+ > 双版本号方案:
10
+ >
11
+ > | 位置 | 版本 | 含义 |
12
+ > |---|---|---|
13
+ > | `package.json` `"version"` | `2.2.8` | npm 包版本,正常递增 (+0.0.1) |
14
+ > | `src/cmd/index.tsx` `.version(...)` | `0.4.5` | **产品版本** (`gfcode --version` 看到的) |
15
+
16
+ ### Fixed (边界测试 `tests/edge-*.mjs` 捕获的真实 bug)
17
+
18
+ **Bug 1: ToolCall 在 `result === null` 时误渲染** — 旧代码
19
+ `tool.result !== undefined ? ... : null` 把 `null` 当有效结果,空字符串
20
+ 被显示。改成 `tool.result !== undefined && tool.result !== null`,
21
+ `null` 现在进入 pending 状态,显示 ⏳ running。
22
+
23
+ **Bug 2: `SessionManager.truncate(N)` 不生效** — compactor 的
24
+ `preserveRecent` 默认 10,比 `maxMessages` 大,所以 `truncate(2)`
25
+ 触发 compact 时,`others.length <= preserveRecent` 分支返回原消息。
26
+ 改成 `truncate(N)` 时同步 `preserveRecent = N - 1`,让 max 边界真
27
+ 的生效。
28
+
29
+ **Bug 3: thinking 正则漏掉 `<thinking>` delimiter** — 用户实际会话
30
+ 里模型用的是 `<thinking>...</thinking>` 不是 `<<<think>...</think>`。
31
+ 加上 `<thinking>` / `<THINK>` / `[think]` 三种额外格式,总共 6 个
32
+ delimiter。
33
+
34
+ **Bug 4: pollution 过滤 STRONG 模式过宽** — `/\[已中断\]/` 在消息
35
+ **任何位置** 都触发 drop,导致 300 字的中段提到这个标记的合法
36
+ 解释型消息被误删。改成所有 STRONG 也受 length/question/temporal
37
+ 三个门控,长消息中段出现的引用不会被误杀。
38
+
39
+ **Bug 5: 1.0.4 源码里没有 `npm test` script** — `prepublishOnly`
40
+ 引用了它,但 1.0.4 tarball 缺这个 script,导致 release 后用户跑
41
+ `npm test` 会失败。加上 npm test 聚合脚本 + `prepublishOnly`
42
+ 显式跑 build + test。
43
+
44
+ ### Added
45
+
46
+ - **5 套边界测试** (`tests/edge-*.mjs`),共 **118 个用例**,覆盖
47
+ - thinking compression: 嵌套 delimiter、无 closing tag、大小写、
48
+ whitespace-only、超长输入、混合 `bcdf` (Case O)
49
+ - pollution filter: 大小写、unicode 变种、`?` / 中文 `?` 时间
50
+ 副词、`null byte`、markdown 装饰
51
+ - ToolCall 渲染: `null` vs `undefined`, `\\r\\n`, 10000 字符
52
+ 单行,边界 8/9 行
53
+ - SessionManager: 空 user msg、1MB msg、`getMessages()` 不可变性、
54
+ `truncate(N)` 边界
55
+ - CLI 参数: -V, --version, -h, --show-thinking, -m, -i, 1000 char
56
+ prompt, unicode prompt, 含 shell 元字符的 prompt
57
+ - **`npm test`** 脚本 (聚合 8 套测试, 181 / 181 pass)
58
+ - **`prepublishOnly`** (build + test,确保发布前必过)
59
+ - **`tests/` 加入 `.gitignore`** — 之前的 tarball 误把 dev-time
60
+ smoke 测试发到 npm 了
61
+
62
+ ### Test Summary
63
+
64
+ ```
65
+ smoke-thinking: 28 / 28 pass
66
+ smoke-tool: 18 / 18 pass
67
+ smoke-pollution: 17 / 17 pass
68
+ edge-thinking: 28 / 28 pass
69
+ edge-tool: 25 / 25 pass
70
+ edge-pollution: 23 / 23 pass
71
+ edge-session: 27 / 27 pass
72
+ edge-cli: 15 / 15 pass
73
+ ────────────────
74
+ total: 181 / 181 pass
75
+ ```
76
+
77
+ ---
78
+
79
+ ## [2.2.7 / 产品 0.4.4] - 2026-07-06 - 烟囱测试驱动的 anti-pollution 过滤收紧
80
+
81
+ > 双版本号方案:
82
+ >
83
+ > | 位置 | 版本 | 含义 |
84
+ > |---|---|---|
85
+ > | `package.json` `"version"` | `2.2.7` | npm 包版本,正常递增 (+0.0.1) |
86
+ > | `src/cmd/index.tsx` `.version(...)` | `0.4.4` | **产品版本** (`gfcode --version` 看到的) |
87
+
88
+ ### Fixed
89
+
90
+ **Pollution 过滤误杀正常对话** — v2.2.4 引入的 anti-pollution 过滤
91
+ (`SessionManager.looksPolluted`) 有两条过宽的模式:
92
+
93
+ - `/\u5df2\u4e2d\u65ad[^\n]{0,40}/` — 把所有包含"已中断"字样的中文
94
+ 都当污染,包括 `我看到这个进程已中断了` 这种合法对话
95
+ - `/response (was )?truncated/i` — 把所有提到"response truncated"的句子
96
+ 都当污染,包括用户问 `Why was the response truncated last time?`
97
+
98
+ 烟囱测试 `tests/smoke-pollution.mjs` 直接捕获了这两个误杀。
99
+
100
+ ### 修复策略 — 两层模式分级
101
+
102
+ ```
103
+ STRONG (always drop):
104
+ [已中断] 必有方括号,模型原样输出
105
+ [interrupted] English 等价
106
+
107
+ WEAK (drop only when ALL gates pass):
108
+ ^...\[已中断\] 行首标记 (带可选 markdown 装饰)
109
+ ^...\[interrupted\] 行首标记
110
+ \bresponse (was )?(truncated|cut off|interrupted)\b
111
+ \boutput (was )?(truncated|cut off|interrupted)\b
112
+
113
+ + 消息长度 < 200 字符 (截断的响应通常较短)
114
+ + 不以 ? 结尾 (疑问句是用户讨论过往行为)
115
+ + 不包含 "last time" / "earlier" / "before" / "previously" / "yesterday"
116
+ (时间副词表明用户在回顾过去,不是污染)
117
+ ```
118
+
119
+ ### Smoke 测试新增
120
+
121
+ - `tests/smoke-thinking.mjs` — 28 个用例覆盖 `splitThinking` / `compressThinking`
122
+ 所有边缘情况 (空输入、多 delimiter、Chinese/English 混合、tag 跨行)
123
+ - `tests/smoke-tool.mjs` — 18 个用例覆盖 ToolCall 渲染路径 (空结果、
124
+ pending、截断计数、错误、超长单行)
125
+ - `tests/smoke-pollution.mjs` — 17 个用例覆盖 anti-pollution 过滤的
126
+ drop / keep 双向场景
127
+
128
+ ### Test summary (本 patch 后)
129
+ ```
130
+ thinking: 28 / 28 pass
131
+ tool: 18 / 18 pass
132
+ pollution: 17 / 17 pass
133
+ total: 63 / 63 pass
134
+ ```
135
+
136
+ ---
137
+
138
+ ## [2.2.6 / 产品 0.4.3] - 2026-07-06 - 修复工具结果不显示
139
+
140
+ > 双版本号方案:
141
+ >
142
+ > | 位置 | 版本 | 含义 |
143
+ > |---|---|---|
144
+ > | `package.json` `"version"` | `2.2.6` | npm 包版本,正常递增 (+0.0.1) |
145
+ > | `src/cmd/index.tsx` `.version(...)` | `0.4.3` | **产品版本** (`gfcode --version` 看到的) |
146
+
147
+ ### Fixed
148
+
149
+ **Bug: 工具调用结果不显示** — 在 1.0.4 源码栈下用户报告"⚙ shell date" 这条
150
+ 命令发起后,**结果完全看不到**,只看到 AI 后续的文字回复 ("好嘞,那我给你
151
+ 演示一组工具——并行调用"). 模型明明看到了工具结果 (因为它的后续回复引用了
152
+ 结果),但 UI 上不显示结果文本。
153
+
154
+ 通过代码 review + 单测复现,定位到三个潜在原因,全部修复:
155
+
156
+ 1. **`src/tui/components/ToolCall.tsx`** — `tool.result ? ... : null` 用 truthy
157
+ 判断,**空字符串结果被当 falsy 跳过渲染**。改成 `tool.result !== undefined ? ... : null`。
158
+ 同样修复: `wrap="truncate"` 在 Ink 里会把超长行**静默切掉不显示**,
159
+ 改成 `wrap="wrap"` 让长行自动换行。还把 `result.truncated` 的指示从
160
+ 模糊的 `"..."` 改成 `(+N more lines)` 显示实际被截掉的行数。
161
+ 2. **加 ⏳ pending 指示器** — 工具调用发起到结果返回之间的中间状态,
162
+ 之前没有视觉反馈,看起来像是"卡住了"。现在显示 `⏳ running...`
163
+ 3. **`src/tui/hooks/useChat.ts`** — 流结束 push 到 messages 时,assemble
164
+ 一个 `[tool: name → result]` 摘要附加到 assistant 的 content 里。
165
+ 这是 belt-and-suspenders 兜底: 即使 Ink 的 `<ToolCall/>` 渲染路径
166
+ 因为任何边缘 case 失败 (例如太长的输出 wrap 问题),用户依然能在
167
+ AI 的文字回复里看到工具结果。
168
+
169
+ ### 仍然不修的 (但要意识到)
170
+ - 用户的 paste 里还有另一条命令 `echo "=== 当前时间 ===" && date && echo
171
+ "=== 系统信息 ===" && system` — 这里 `system` 不是合法命令,
172
+ 会返回错误。这不是代码 bug,是用户/模型自己写的命令有问题。本次 patch
173
+ 不修改这个。
174
+
175
+ ### 不在本次范围
176
+ - Anthropic / Gemini provider 的 `delta.tool_calls` 流式解析 (仍是 TODO)
177
+ - 工具输入参数命名前缀 (`command` vs `cmd` 不一致) — 下次 patch
178
+
179
+ ---
180
+
181
+ ## [2.2.5 / 产品 0.4.2] - 2026-07-06 - 压缩 <think> 思考块 (类似 opencode)
182
+
183
+ > 双版本号方案:
184
+ >
185
+ > | 位置 | 版本 | 含义 |
186
+ > |---|---|---|
187
+ > | `package.json` `"version"` | `2.2.5` | npm 包版本,正常递增 (+0.0.1) |
188
+ > | `src/cmd/index.tsx` `.version(...)` | `0.4.2` | **产品版本** (`gfcode --version` 看到的) |
189
+
190
+ ### Fixed
191
+
192
+ **Bug: 思考过程太长,刷屏** — 在 1.0.4 源码栈下,即使是"非推理"模型
193
+ (Qwen / DeepSeek-V3 chat / Kimi 等) 也会在回复里发整段 `<think>...</think>`
194
+ 块,经常是几十行内部独白。这块内容对用户来说没有可读价值,只
195
+ 是噪音 — 用户在 v2.2.4 的会话日志里能看到这问题特别严重。
196
+
197
+ 参考 opencode 的做法 (`packages/opencode/src/session/prompt.ts:244`
198
+ 里的 `<think>[\s\S]*?<\/think>` 正则),引入压缩模式:
199
+
200
+ - 新文件 `src/utils/thinking.ts`,导出三个 helper:
201
+ - `splitThinking(content)` — 把 `<think>...` / `<reasoning>...</reasoning>` /
202
+ `[THINK]...[/THINK]` 三种块格式剥离开,返回 `{thinking, conclusion,
203
+ thinkingLines, thinkingHint}`。
204
+ - `summarizeThinking(split)` — 输出 `💭 thought for N lines: <first hint>`
205
+ 单行摘要。
206
+ - `compressThinking(content, showThinking)` — `showThinking=false` 时把
207
+ 思考块压成一行 + 结论;`showThinking=true` 时原样返回。
208
+ - 三个调用点全部接入压缩:
209
+ - `src/cmd/index.tsx`: 流式阶段**不**实时打印 AI 文字 (避免半个 <think>
210
+ 块被切到屏幕上),流结束后用 `splitThinking + summarizeThinking` 输出
211
+ 一行摘要 + 结论。**持久化时只保存结论**,让 history 不被思考块撑大。
212
+ - `src/app/index.ts:runPrompt`: 持久化前 `compressThinking(fullResponse,
213
+ showThinking)`。
214
+ - `src/tui/hooks/useChat.ts`: 同上,持久化 + 显示内容都走压缩。
215
+
216
+ ### Added
217
+
218
+ - **CLI flag `--show-thinking`**: 在命令行下开启完整思考块显示 (调试用)
219
+ - **`App.showThinking` 字段**: 默认 `false`,可通过 REPL 命令切换
220
+ - **REPL 命令 `/thinking on|off`** (中文别名 `/思考`): 在 Ink TUI 模式下
221
+ 切换思考块显示
222
+
223
+ ### 设计选择
224
+
225
+ 为什么不沿用 opencode 的"协议级分离 reasoning"?
226
+ - opencode 把 reasoning 当成单独的 stream part 处理 (`MessageV2.ReasoningPart`),
227
+ 那需要模型支持 reasoning API (Anthropic extended thinking / OpenAI o1-style)。
228
+ - 我们用的多数 provider (Qwen / DeepSeek / Kimi) 把 reasoning 直接当作
229
+ content 的一部分输出,所以必须在**显示层**做正则剥离。
230
+
231
+ 为什么不实时 (mid-stream) 压缩?
232
+ - 流式 chunk 是任意切分的,`<think>` 标签可能跨 chunk。实时检测需要
233
+ state machine,延迟和边界处理都很脆弱。
234
+ - 流结束后压缩更可靠,而且不影响用户对结论的实时阅读(用户其实只在乎结论)。
235
+
236
+ ### 不在本次范围
237
+ - `/thinking` 命令目前是全局开关,不支持 per-message 切换
238
+ - 没有提供"展开"按钮 — 用户要看完整内容只能 `--show-thinking` 跑一遍
239
+ - 持久化时去掉了 thinking 内容,这意味着**重放历史时也看不到完整思考**;
240
+ 这是有意为之 (context window 优先),如需调试可以 `app.showThinking = true` 后
241
+ 重新发起对话
242
+ - Anthropic / Gemini SSE tool_call 流式解析 仍是 TODO
243
+
244
+ ---
package/DEVELOPMENT.md ADDED
@@ -0,0 +1,286 @@
1
+ # Development Guide — Thatgfsj Code
2
+
3
+ This document is for contributors / maintainers. End users should read
4
+ [`README.md`](./README.md) instead.
5
+
6
+ ---
7
+
8
+ ## 1. Overview
9
+
10
+ **Thatgfsj Code** is a Claude Code–style interactive AI coding assistant that
11
+ runs entirely in your terminal. It is written in TypeScript, published as an
12
+ ESM npm package, distributed under MIT, and targets **Node.js ≥ 18**.
13
+
14
+ The tool exposes:
15
+
16
+ - A non-interactive single-shot CLI (`gfcode "..."`).
17
+ - An interactive REPL (`gfcode` with no args).
18
+ - Subcommands: `init`, `explain`, `debug`, `chat`, `template`.
19
+
20
+ The release pipeline is: **bug fix → docs → smoke test → git commit + tag →
21
+ push → GitHub release → `npm publish`**. Everything in `src/` compiles to
22
+ `dist/` via `tsc`; the `package.json` `files` whitelist decides what ships
23
+ in the npm tarball.
24
+
25
+ ---
26
+
27
+ ## 2. Architecture
28
+
29
+ ```
30
+ ┌──────────────────────────────────────────────────────────────┐
31
+ │ src/index.ts │
32
+ │ CLI entry · commander program · subcommand dispatch │
33
+ │ (init / explain / debug / chat / template / default REPL) │
34
+ └─────────────────────────┬────────────────────┬───────────────┘
35
+ │ │
36
+ ┌───────────▼──────────┐ ┌───────▼─────────────┐
37
+ │ AI Engine + Tools │ │ REPL Loop │
38
+ │ src/core/ai-engine │ │ src/repl/{loop,...} │
39
+ │ src/tools/{file,…} │ │ @inquirer/input │
40
+ └───────────┬──────────┘ └───────┬─────────────┘
41
+ │ │
42
+ ┌───────────▼────────────────────▼───────────────┐
43
+ │ Core / Utils / Agent / MCP │
44
+ │ src/core/{config,session,types,subagent,…} │
45
+ │ src/utils/{diff-preview,memory,project-…} │
46
+ │ src/agent/{core,intent,streaming} │
47
+ │ src/mcp/client.ts │
48
+ └────────────────────────────────────────────────┘
49
+ ```
50
+
51
+ ### Module responsibilities
52
+
53
+ | Layer | Files | Job |
54
+ |-----------|----------------------------------------------|--------------------------------------------------------------------|
55
+ | Entry | `src/index.ts` | commander program, subcommand handlers, REPL bootstrap |
56
+ | REPL | `src/repl/{input,output,loop,welcome}.ts` | interactive prompt, ANSI output, SIGINT, welcome/init wizard |
57
+ | Core | `src/core/{ai-engine,config,session,…}.ts` | AI provider abstraction, config loading, session state |
58
+ | Tools | `src/tools/{file,shell,git,search}.ts` | file I/O, shell exec, git ops, code search |
59
+ | Agent | `src/agent/{core,intent,streaming}.ts` | intent classification, agent loop, streamed terminal output |
60
+ | Utils | `src/utils/{diff-preview,memory,…}.ts` | side-effect-free helpers |
61
+ | MCP | `src/mcp/client.ts` | Model Context Protocol stdio client |
62
+
63
+ ### Data flow on a single prompt
64
+
65
+ ```
66
+ User ──▶ commander ──▶ executeTask(prompt)
67
+
68
+ ├─▶ ConfigManager.load() (process.env + ~/.thatgfsj/config.json)
69
+
70
+ ├─▶ AIEngine.chatStream(messages) ──▶ provider base URL /v1/chat/completions
71
+ │ or Anthropic /messages
72
+ │ or Gemini :generateContent
73
+
74
+ └─▶ process.stdout.write(chunks) ──▶ terminal (scrollable history)
75
+ ```
76
+
77
+ ---
78
+
79
+ ## 3. Build & install
80
+
81
+ ### Prerequisites
82
+
83
+ - Node.js ≥ 18 (project uses native `fetch`, `AbortController`, top-level `await`,
84
+ `node --test`).
85
+ - npm ≥ 9 (so `npm publish` understands the `files` whitelist).
86
+ - Git (for the install scripts and during release).
87
+
88
+ ### Local development
89
+
90
+ ```bash
91
+ git clone https://github.com/Thatgfsj/thatgfsj-code.git
92
+ cd thatgfsj-code
93
+ npm install
94
+ npm run build # produces ./dist
95
+ npm test # node --test tests/
96
+ npm start # node dist/index.js (interactive REPL)
97
+ npm run dev # tsc && node dist/index.js
98
+
99
+ # Optional: link globally so `gfcode` is in your PATH
100
+ npm link
101
+ ```
102
+
103
+ `npm install` after cloning will trigger `prepublishOnly` if you have it
104
+ configured (we do). Always run `npm run build` after editing source so the
105
+ `dist/` matches `src/`.
106
+
107
+ ### Platform notes
108
+
109
+ - **Windows**: `src/index.ts` invokes `chcp 65001` synchronously before any
110
+ output to force UTF-8 in the legacy Windows console. Done via
111
+ `createRequire(import.meta.url)` so it works under `"type": "module"`.
112
+ - **Numeric keypad arrows**: the REPL uses `@inquirer/input` instead of Node's
113
+ built-in `readline.question()` because the latter doesn't reliably translate
114
+ numeric-keypad ANSI escape sequences on Windows terminals (Bug #1 history).
115
+ - **Streaming output**: `process.stdout.write` directly, never `rl.question`
116
+ inside the loop — the latter would reset the terminal and lose scrollback.
117
+
118
+ ---
119
+
120
+ ## 4. Adding a provider
121
+
122
+ 1. Add the env-var map to `src/core/config.ts` (`envKeys`).
123
+ 2. Add a `*_MODELS` array to `src/repl/welcome.ts` and wire it through
124
+ `getModelsForProvider()` and `interactiveSetup()` (numbered choice).
125
+ 3. Update `WelcomeScreen.hasApiKey()` in `src/repl/welcome.ts` to include the
126
+ new env-var name.
127
+ 4. If the provider uses a non-OpenAI request format, extend the dispatcher
128
+ in `src/core/ai-engine.ts::streamRequest`.
129
+ 5. Update `docs/API_KEY_GUIDE.md` and `README.md`'s provider list.
130
+
131
+ No other files should care about the specific provider.
132
+
133
+ ---
134
+
135
+ ## 5. Adding a built-in CLI command
136
+
137
+ `src/index.ts` is the single `commander` program. Register a new command
138
+ **before** `program.parse(process.argv)`:
139
+
140
+ ```ts
141
+ program
142
+ .command('foo')
143
+ .description('...')
144
+ .argument('<bar>', '...')
145
+ .action(async (bar) => { /* ... */ });
146
+ ```
147
+
148
+ For REPL-internal slash-style commands (visible only inside the interactive
149
+ loop), add a new `case` to `src/repl/loop.ts::handleCommand`.
150
+
151
+ ### Built-in REPL commands (current)
152
+
153
+ | Command | Behavior |
154
+ | ---------------- | -------------------------------------------------------------------------------- |
155
+ | `help` | Show built-in command list |
156
+ | `exit` / `quit` | Leave the REPL |
157
+ | `clear` | Clear the screen |
158
+ | `context` | Show the current project context |
159
+ | `history` | Show the command history for this session |
160
+ | `tools` | List registered tools |
161
+ | `models` | Read-only listing of the current provider's models |
162
+ | `providers` | Read-only listing of all providers |
163
+ | `/model` | **Interactive picker — actually switches the active model** for the current provider. Persists to `~/.thatgfsj/config.json` and calls `AIEngine.updateConfig()`. |
164
+ | `/provider` | **Interactive picker — switches provider + chains into `/model`** for the new one. Warns if the corresponding env-var / saved API key is missing. |
165
+ | `Ctrl+C` | Aborts the in-flight stream once, exits after two empty-prompt cancels. |
166
+
167
+ Both `/model` and `/provider` accept either a numeric index or the exact
168
+ provider/model id; pressing Enter with no input keeps the current value. After
169
+ a switch, `REPLLoop` injects a one-line `[system: ... switched to ...]`
170
+ message into the session so the LLM can see the change in the next turn.
171
+
172
+ ---
173
+
174
+ ## 6. Adding a tool
175
+
176
+ Tools implement the `Tool` interface declared in `src/core/types.ts`:
177
+
178
+ ```ts
179
+ export interface Tool {
180
+ name: string;
181
+ description: string;
182
+ parameters: ToolParameter[];
183
+ execute(params: any, ctx: ToolContext): Promise<ToolResult>;
184
+ }
185
+ ```
186
+
187
+ Steps:
188
+ 1. Create `src/tools/<name>.ts` exporting a class implementing `Tool`.
189
+ 2. Register it in `src/tools/index.ts::getBuiltInTools()` so both the REPL
190
+ `REPLLoop.init` and `executeTask` pick it up automatically.
191
+
192
+ > **Known limitation (0.2.2):** `src/core/ai-engine.ts::extractToolCalls`
193
+ > currently returns `undefined`. Tools are registered but never actually
194
+ > invoked from a streamed response. Wiring this up requires parsing each
195
+ > provider's native `tool_calls` delta and is tracked under "Unreleased" in
196
+ > `CHANGELOG.md`. Until then, `ToolRegistry` is a forward-compatible seam.
197
+
198
+ ---
199
+
200
+ ## 7. MCP integration
201
+
202
+ `src/mcp/client.ts` defines a small stdio MCP client. It spawns a child
203
+ process and exchanges JSON-RPC via newline-delimited messages. The current
204
+ shape is intentionally minimal — see the file for the protocol mapping.
205
+
206
+ ---
207
+
208
+ ## 8. Cross-platform & UX details
209
+
210
+ - **Encoding**: Windows-only `chcp 65001` in `src/index.ts:9-15`. Skipped
211
+ silently if it fails.
212
+ - **Color**: `chalk` v5 is ESM-only; the project is `"type": "module"` so
213
+ this is fine.
214
+ - **Spinner**: `ora` v7 with `dots` spinner; cyan.
215
+ - **History**: local to a single REPL session (not persisted across runs).
216
+
217
+ ---
218
+
219
+ ## 9. Tests
220
+
221
+ ```bash
222
+ npm test # runs node --test tests/ (full TAP output)
223
+ npm run test:silent # dot reporter, for noisy CI logs
224
+ ```
225
+
226
+ Tests live in `tests/` and use Node's built-in `node:test` runner — no
227
+ vitest / jest dev-dep. They cover:
228
+
229
+ - Smoke tests of the compiled `dist/index.js` binary (`--version`, `--help`,
230
+ subcommand empty-arg guards, `bash -n install.sh`).
231
+ - Boundary tests of pure modules (`SessionManager`, `DiffPreview`,
232
+ `REPLOutput`) — empty input, unicode, CRLF, very long input.
233
+ - No network. No mocked API keys. No shell-out side-effects other than the
234
+ install script's `bash -n` parse-check.
235
+
236
+ CI integration: if you set this up later, run `npm test && npm run build`
237
+ in the job; the `prepublishOnly` script already chains them.
238
+
239
+ ---
240
+
241
+ ## 10. Release process
242
+
243
+ 1. Edit `package.json` `version` (semver).
244
+ 2. Add a new section at the top of `CHANGELOG.md`.
245
+ 3. `npm test && npm run build` locally — make sure both are green.
246
+ 4. `git add -A && git commit -m "release: vX.Y.Z"`
247
+ 5. `git tag vX.Y.Z`
248
+ 6. `git push origin main --follow-tags`
249
+ 7. `gh release create vX.Y.Z --title "vX.Y.Z" --notes-file CHANGELOG.md`
250
+ (the section for the new version is the top entry; trim if needed).
251
+ 8. `npm publish --access public` (a `prepublishOnly` step in `package.json`
252
+ re-runs tests + build, so you can't accidentally publish a stale build).
253
+
254
+ ### Semver policy
255
+
256
+ - **patch** (`Z`): bug fixes, docs, refactors, no public API change.
257
+ - **minor** (`Y`): new public command, new provider, new tool.
258
+ - **major** (`X`): breaking change to the CLI surface or the JS API surface
259
+ (currently no JS API is stable).
260
+
261
+ ---
262
+
263
+ ## 11. Troubleshooting
264
+
265
+ ### `ReferenceError: require is not defined`
266
+
267
+ You're editing TypeScript and accidentally called `require(...)` outside of a
268
+ `createRequire(import.meta.url)` shim. The project is ESM. Use `import x from 'y'`
269
+ at the top of the file.
270
+
271
+ ### `npm publish` ships no `dist/`
272
+
273
+ You forgot to run `npm run build` (or the `prepublishOnly` script was
274
+ removed). The `files` whitelist in `package.json` requires the `dist/`
275
+ directory to exist locally when publishing.
276
+
277
+ ### `gfcode --version` shows the wrong number
278
+
279
+ Edit it in `package.json` only — `src/index.ts` and `src/repl/output.ts` both
280
+ read `VERSION` from `package.json` via `import pkg from '../package.json' …`.
281
+
282
+ ### REPL keypresses / Ctrl+C misbehave on Windows
283
+
284
+ Make sure you're on Windows Terminal or any TTY that emits ANSI escape
285
+ sequences natively. The legacy `cmd.exe` console has incomplete ANSI
286
+ support — upgrade to Windows Terminal or use PowerShell.
@@ -18,6 +18,12 @@ export declare class App {
18
18
  hooks: HookManager;
19
19
  prompts: SystemPromptBuilder;
20
20
  skills: SkillRegistry;
21
+ /**
22
+ * v2.2.5 (product 0.4.2): toggle <think> block compression. Default
23
+ * true. Toggled by `--show-thinking` on the CLI or `/thinking on|off`
24
+ * in the REPL.
25
+ */
26
+ showThinking: boolean;
21
27
  private constructor();
22
28
  static create(): Promise<App>;
23
29
  /**
@@ -27,6 +33,14 @@ export declare class App {
27
33
  streamResponse(messages?: ChatMessage[]): AsyncGenerator<string, void>;
28
34
  /**
29
35
  * Run a single prompt (non-interactive mode)
36
+ *
37
+ * v2.2.4 (port from v2.1.0): persistence of the assistant message
38
+ * uses addMessageSafe, which drops the message if it contains
39
+ * pollution markers like "[已中断]".
40
+ *
41
+ * v2.2.5 (product 0.4.2): persistence also strips <think> blocks
42
+ * (and similar reasoning delimiters) when showThinking is false,
43
+ * so the conversation log stays compact.
30
44
  */
31
45
  runPrompt(prompt: string): Promise<string>;
32
46
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/app/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAgB,MAAM,aAAa,CAAC;AAE7D,qBAAa,GAAG;IACd,MAAM,EAAE,aAAa,CAAC;IACtB,GAAG,EAAE,UAAU,CAAC;IAChB,OAAO,EAAE,cAAc,CAAC;IACxB,KAAK,EAAE,YAAY,CAAC;IACpB,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,mBAAmB,CAAC;IAC7B,MAAM,EAAE,aAAa,CAAC;IAEtB,OAAO;WAkBM,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC;IA+BnC;;;OAGG;IACI,cAAc,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,GAAG,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC;IAO7E;;OAEG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAqBjD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/app/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,KAAK,EAAE,WAAW,EAAgB,MAAM,aAAa,CAAC;AAE7D,qBAAa,GAAG;IACd,MAAM,EAAE,aAAa,CAAC;IACtB,GAAG,EAAE,UAAU,CAAC;IAChB,OAAO,EAAE,cAAc,CAAC;IACxB,KAAK,EAAE,YAAY,CAAC;IACpB,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,mBAAmB,CAAC;IAC7B,MAAM,EAAE,aAAa,CAAC;IACtB;;;;OAIG;IACH,YAAY,EAAE,OAAO,CAAS;IAE9B,OAAO;WAkBM,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC;IA+BnC;;;OAGG;IACI,cAAc,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,GAAG,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC;IAO7E;;;;;;;;;;OAUG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAsBjD"}
package/dist/app/index.js CHANGED
@@ -9,6 +9,7 @@ import { ToolRegistry } from '../tools/index.js';
9
9
  import { HookManager } from '../hooks/index.js';
10
10
  import { SystemPromptBuilder } from '../prompts/index.js';
11
11
  import { SkillRegistry } from '../skills/index.js';
12
+ import { compressThinking } from '../utils/thinking.js';
12
13
  export class App {
13
14
  config;
14
15
  llm;
@@ -17,6 +18,12 @@ export class App {
17
18
  hooks;
18
19
  prompts;
19
20
  skills;
21
+ /**
22
+ * v2.2.5 (product 0.4.2): toggle <think> block compression. Default
23
+ * true. Toggled by `--show-thinking` on the CLI or `/thinking on|off`
24
+ * in the REPL.
25
+ */
26
+ showThinking = false;
20
27
  constructor(config, llm, session, tools, hooks, prompts, skills) {
21
28
  this.config = config;
22
29
  this.llm = llm;
@@ -63,6 +70,14 @@ export class App {
63
70
  }
64
71
  /**
65
72
  * Run a single prompt (non-interactive mode)
73
+ *
74
+ * v2.2.4 (port from v2.1.0): persistence of the assistant message
75
+ * uses addMessageSafe, which drops the message if it contains
76
+ * pollution markers like "[已中断]".
77
+ *
78
+ * v2.2.5 (product 0.4.2): persistence also strips <think> blocks
79
+ * (and similar reasoning delimiters) when showThinking is false,
80
+ * so the conversation log stays compact.
66
81
  */
67
82
  async runPrompt(prompt) {
68
83
  this.session.addMessage('user', prompt);
@@ -74,14 +89,15 @@ export class App {
74
89
  }
75
90
  }
76
91
  catch (err) {
77
- // Re-throw after saving partial response
78
- if (fullResponse) {
79
- this.session.addMessage('assistant', fullResponse);
80
- }
92
+ // Re-throw without persisting partial response. Persisting
93
+ // truncated output here was the source of the [已中断] loop in
94
+ // v2.2.3.
81
95
  throw err;
82
96
  }
83
97
  console.log();
84
- this.session.addMessage('assistant', fullResponse);
98
+ // v2.2.5: compress <think> blocks before persisting.
99
+ const toPersist = compressThinking(fullResponse, this.showThinking);
100
+ this.session.addMessageSafe('assistant', toPersist);
85
101
  return fullResponse;
86
102
  }
87
103
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/app/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/app/index.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,27 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * Thatgfsj Code - CLI Entry Point
4
+ *
5
+ * v2.2.4 (product 0.4.1): three concrete fixes for the bugs visible
6
+ * in the 2.2.3 (product 0.4.0) session log:
7
+ *
8
+ * 1. Encoding: chcp 65001 used to be wrapped in a silent try/catch,
9
+ * and stdout never had its default encoding set. On Windows this
10
+ * caused Chinese characters from tool output to render as
11
+ * mojibake (ļ ʹ ϵͳ Ƿ ...).
12
+ *
13
+ * 2. [已中断] hallucination loop: 1.0.4's SessionManager had no
14
+ * anti-pollution filter. When the user pressed Ctrl+C mid-
15
+ * stream, the truncated assistant message (containing the
16
+ * model's literal "[已中断]" marker) got persisted to history.
17
+ * On the next turn, the model saw that and kept echoing it.
18
+ * v2.1.0 had the right fix (_wasAborted flag + filter) — we
19
+ * port it back here.
20
+ *
21
+ * 3. Tool output visual: 1.0.4 printed `@@TOOL@@{...}` markers
22
+ * inline with text, no separator, no truncation. Long tool
23
+ * output (registry dumps, dir listings) bled into the next
24
+ * AI message. Add separator + truncation + color separation.
4
25
  */
5
26
  export {};
6
27
  //# sourceMappingURL=index.d.ts.map