thatgfsj-code 0.2.1 → 0.2.2

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 (64) hide show
  1. package/CHANGELOG.md +131 -0
  2. package/DEVELOPMENT.md +286 -0
  3. package/README.md +131 -30
  4. package/dist/core/ai-engine.d.ts +17 -0
  5. package/dist/core/ai-engine.d.ts.map +1 -1
  6. package/dist/core/ai-engine.js +23 -7
  7. package/dist/core/ai-engine.js.map +1 -1
  8. package/dist/index.js +18 -27
  9. package/dist/index.js.map +1 -1
  10. package/dist/repl/input.d.ts +8 -0
  11. package/dist/repl/input.d.ts.map +1 -1
  12. package/dist/repl/input.js +12 -0
  13. package/dist/repl/input.js.map +1 -1
  14. package/dist/repl/loop.d.ts +56 -0
  15. package/dist/repl/loop.d.ts.map +1 -1
  16. package/dist/repl/loop.js +333 -4
  17. package/dist/repl/loop.js.map +1 -1
  18. package/dist/repl/output.d.ts.map +1 -1
  19. package/dist/repl/output.js +3 -1
  20. package/dist/repl/output.js.map +1 -1
  21. package/dist/repl/welcome.js +1 -1
  22. package/dist/repl/welcome.js.map +1 -1
  23. package/docs/API_KEY_GUIDE.md +6 -0
  24. package/docs/FAQ.md +25 -3
  25. package/package.json +35 -3
  26. package/.patches/0001-fix-repl-replace-readline-with-inquirer-input-for-ke.patch +0 -279
  27. package/.patches/0002-fix-repl-stream-AI-output-directly-to-stdout-so-term.patch +0 -564
  28. package/.patches/0003-fix-session-break-the-hallucination-loop-in-assistan.patch +0 -194
  29. package/.patches/0004-chore-release-bump-version-to-0.2.1.patch +0 -24
  30. package/ROADMAP.md +0 -107
  31. package/src/agent/core.ts +0 -179
  32. package/src/agent/index.ts +0 -8
  33. package/src/agent/intent.ts +0 -181
  34. package/src/agent/streaming.ts +0 -132
  35. package/src/core/ai-engine.ts +0 -437
  36. package/src/core/cli.ts +0 -171
  37. package/src/core/config.ts +0 -147
  38. package/src/core/context-compactor.ts +0 -245
  39. package/src/core/hooks.ts +0 -196
  40. package/src/core/permissions.ts +0 -308
  41. package/src/core/session.ts +0 -165
  42. package/src/core/skills.ts +0 -208
  43. package/src/core/state.ts +0 -120
  44. package/src/core/subagent.ts +0 -195
  45. package/src/core/system-prompt.ts +0 -163
  46. package/src/core/tool-registry.ts +0 -157
  47. package/src/core/types.ts +0 -280
  48. package/src/index.ts +0 -544
  49. package/src/mcp/client.ts +0 -330
  50. package/src/repl/index.ts +0 -8
  51. package/src/repl/input.ts +0 -139
  52. package/src/repl/loop.ts +0 -280
  53. package/src/repl/output.ts +0 -222
  54. package/src/repl/welcome.ts +0 -296
  55. package/src/tools/file.ts +0 -117
  56. package/src/tools/git.ts +0 -132
  57. package/src/tools/index.ts +0 -48
  58. package/src/tools/search.ts +0 -263
  59. package/src/tools/shell.ts +0 -181
  60. package/src/utils/diff-preview.ts +0 -202
  61. package/src/utils/index.ts +0 -8
  62. package/src/utils/memory.ts +0 -223
  63. package/src/utils/project-context.ts +0 -207
  64. package/tsconfig.json +0 -19
package/CHANGELOG.md ADDED
@@ -0,0 +1,131 @@
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
+ ## [Unreleased]
8
+
9
+ ### Planned
10
+ - 实现真实的 provider 工具调用解析(OpenAI `delta.tool_calls`、Anthropic
11
+ `tool_use` block、Gemini `functionCall`),让已注册的 Tool 真正参与 Agent Loop
12
+ - `install.sh` / `install.ps1` 默认分支自适应(`master` ↔ `main`)
13
+ - 移除 README 中失效的 `git.io/thatgfsj` 短链,全部改回 `raw.githubusercontent.com`
14
+ - MCP 客户端 `this.process?.connected` → `this.process?.stdin?.writable`
15
+
16
+ ---
17
+
18
+ ## [0.2.2] - 2026-07-06
19
+
20
+ ### Added
21
+ - **`/model` / `/provider` REPL 命令**:1.0.4 老版本里这两个交互式切换命令
22
+ 在 0.2.x 系列中曾经被删掉,这次重新实现并对齐新代码结构,并且从
23
+ `thatgfsj-code@1.0.4` 的 TUI 版本里借鉴并移植了两项核心体验:
24
+ - `/model` 列出当前 provider 的所有模型(含 `✓` 标记当前选中),输入编号
25
+ 或完整 model id 切换;立即写入 `~/.thatgfsj/config.json` 并通过
26
+ `AIEngine.updateConfig()` 让下一次流式请求生效。空输入回车保持当前,
27
+ Ctrl+C 取消。
28
+ - **历史记录持久化**(借鉴 1.0.4 的 `saveModelToHistory`):切换过的
29
+ model id 写入 `~/.thatgfsj/models.json`,下次打开 `/model` 时会在
30
+ 内置列表上方显示「最近使用」段(最多 5 条,按时间排序,可通过 `r1`..`r5`
31
+ 快捷选取,自动 dedup)。
32
+ - **任意 model id**:输入既不在内置列表也不在历史里的字符串,按自定义模型
33
+ 处理(适合 OpenAI-compatible 中转站 / Ollama 自定义模型名场景)。
34
+ - `/provider` 列出 9 个支持的 provider,选完自动跟进 `/model` 让用户选
35
+ 新 provider 下的模型;如果新 provider 缺少对应的 API Key 环境变量,会提示
36
+ 用户先 `gfcode init` 或 `export`。
37
+ - 两个命令都接受带或不带前导 `/`(与 1.0.4 的 `/模型` 老习惯兼容)。
38
+ - 切换后会把一行 `[system: ... switched to ...]` 注入 `SessionManager`,
39
+ 让 LLM 在下一轮看到变更而不丢失上下文。
40
+ - **`AIEngine.updateConfig()` / `getConfig()`**:暴露给 REPL 内部用,支持
41
+ 在不重启引擎的情况下替换 `model` / `provider` / `baseUrl` / `temperature` /
42
+ `maxTokens`。
43
+ - **34 个单元 / 冒烟测试**(`tests/`):npm 内置 `node:test`,覆盖:
44
+ - `smoke-cli.test.js` — `--version` / `--help` / 子命令空参守卫 / `bash -n`。
45
+ - `unit-session.test.js` — `SessionManager` 拦截「已中断」、相邻助手去重、
46
+ `truncate` 保留 system。
47
+ - `unit-diff.test.js` — `DiffPreview.compare` 边界(unicode / 大输入 / CRLF /
48
+ 空输入)。
49
+ - `unit-switcher.test.js` — `/model` 的纯 helper(编号 / id 解析)
50
+ 与 `AIEngine.updateConfig` 行为。
51
+ - **新增** `unit-model-history.test.js` — `~/.thatgfsj/models.json` 的
52
+ 读写、dedup、corrupt-file 容错(`tests` 5 个 case)。
53
+
54
+ ### Fixed
55
+ - **ESM `require()` 报错**:`src/index.ts` 顶层原先使用
56
+ `require('child_process')` / `require('fs')`,在 `"type": "module"` 项目里
57
+ 直接抛 `ReferenceError: require is not defined`,导致 CLI 在包含 `package.json`
58
+ 的项目目录下完全无法启动。改为 `createRequire(import.meta.url)` 兼容。
59
+ - **`--version` 与 banner 打印老版本号**:`src/index.ts:102` 与
60
+ `src/repl/output.ts:198` 硬编码 `0.2.0`/`v0.2.0`,而 `package.json` 是 `0.2.1`
61
+ 甚至后续 release。两处都改为从 `package.json` 动态读取。
62
+ - **REPL Ctrl+C 无法退出**:`src/repl/loop.ts` 的全局 SIGINT 处理只打
63
+ warning,从来不调用 `this.running = false`。新增 `REPLInput.requestCancel()`,
64
+ 在空输入连按两次 Ctrl+C 时正确退出。
65
+ - **`executeTask` 助手消息丢失**:单命令模式下助手回复从来没写回
66
+ `SessionManager`,导致同名 SessionManager 实例对多轮 prompt 拿不到上下文。
67
+ - **`(this.ai as any).chatStream`** 多余 `any` 强转:`this.ai` 已经过
68
+ null-check,删掉即可。
69
+ - **`extractToolCalls` 死分支**:`src/core/ai-engine.ts` 中 `if (…includes('tool_use'))
70
+ return undefined; return undefined;` 等价于永远返回 `undefined`。改为单行
71
+ `return undefined;` 并添加注释说明当前实际无法解析 tool call(属于已知限制)。
72
+ - **欢迎页 banner 字样写错**:`src/repl/welcome.ts` 顶部仍写着 `Claude Code`,
73
+ 与项目名 `Thatgfsj Code` 不一致。已更正。
74
+
75
+ ### Changed
76
+ - **`init` 命令动态 import 去重**:`src/index.ts:54` 的
77
+ `await import('./repl/welcome.js')` 与顶部静态 import 重复,删除。
78
+ - **`handleModelSwitch`** 在 `src/index.ts` 中属于死代码(无调用者),删除。
79
+ - **欢迎页标题框宽度自适应**:把 banner 顶部的 `Claude Code ` 换成
80
+ `Thatgfsj Code ` 后调整间隔符长度,保证盒子保持 62 列对齐。
81
+
82
+ ### Documentation
83
+ - 新增 `DEVELOPMENT.md`:覆盖架构图、构建/测试流程、添加 provider / 命令 / tool
84
+ 的步骤、跨平台注意事项、发布流程。
85
+ - 新增本文件 `CHANGELOG.md`。
86
+ - 更新 `README.md`:替换失效的 `git.io/thatgfsj` 安装链接为 GitHub raw 直链;
87
+ 补上 `gfcode init` 使用示例与所有顶层 / 子命令 flag;附 REPL 内置命令列表
88
+ 以及 Node ≥ 18 的前置条件。
89
+ - `docs/FAQ.md`、`docs/API_KEY_GUIDE.md` 交叉链接到 `DEVELOPMENT.md`。
90
+
91
+ ### Packaging
92
+ - `package.json` 新增 `files`、`engines`、`repository`、`bugs`、`homepage`
93
+ 字段;原先没有 `files` 白名单会导致 `npm publish` 不会自动包含 `dist/`
94
+ (dist 在 `.gitignore` 里),现在通过显式白名单确保 tarball 包含
95
+ 构建产物与文档。
96
+ - 新增 `scripts.test`、`scripts.test:silent`、`scripts.prepublishOnly`,
97
+ 发布前自动跑测试和 build,防止 release 出错。
98
+
99
+ ### Tests
100
+ - 新增 `tests/` 目录,使用 Node 内置 `node --test` 跑通:
101
+ - `tests/smoke-cli.test.js` — `dist/index.js --version` / `--help` / `chat`
102
+ / `explain` / `debug` / `template` 空参守卫;`bash -n install.sh` 语法。
103
+ - `tests/unit-session.test.js` — `SessionManager` 拦截「已中断」污染、
104
+ 相邻助手消息去重、`truncate` 保留 system。
105
+ - `tests/unit-diff.test.js` — `DiffPreview.compare` 在相同 / 不同 /
106
+ 空 / unicode / CRLF 输入下的行为。
107
+
108
+ ---
109
+
110
+ ## [0.2.1] - 2026-07-XX
111
+
112
+ ### Fixed
113
+ - REPL 数字小键盘方向键响应(升级到 `@inquirer/input`,不再用 Node `readline`
114
+ 直接 `.question()`)。
115
+ - 流式输出保留完整内容、不再 reset 终端 / 跳顶,用户可滚动查看历史。
116
+ - 修复 AI 输出 `[已中断]` 等污染字符串时反复循环同一段的 bug(`SessionManager`
117
+ 拦截 `已中断` / `think` block,`getMessages()` 做相邻助手去重)。
118
+
119
+ ### Added
120
+ - `src/repl/welcome.ts` Claude Code 风格欢迎页与 `gfcode init` 配置向导。
121
+ - `src/tools/{file,shell,git,search}.ts` 完整工具实现,并通过
122
+ `ToolRegistry` 注册到 AI Engine。
123
+ - `src/agent/{core,intent,streaming}.ts` Agent Loop、意图识别、流式输出。
124
+ - `src/utils/{diff-preview,memory,project-context}.ts`。
125
+ - `src/mcp/client.ts`:MCP 客户端雏形。
126
+
127
+ ---
128
+
129
+ ## [0.1.0] - initial
130
+
131
+ - 初版发布:基础 `explain` / `debug` / `chat` / `template` 命令与 REPL 雏形。
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.
package/README.md CHANGED
@@ -1,16 +1,20 @@
1
1
  # Thatgfsj Code 🤖
2
2
 
3
- 你的 CLI 工具
3
+ 你的 CLI 工具 - 像 Claude Code 一样使用 AI 编程。
4
+
5
+ > 当前版本: **0.2.2** · Node.js ≥ 18 · MIT 许可证
4
6
 
5
7
  ---
6
8
 
7
9
  ## ⭐ 特性
8
10
 
9
- - 🤖 **AI 对话** - 用自然语言让 AI 帮你写代码
10
- - 📖 **代码解释** - 通俗易懂地解释代码含义
11
- - 🔧 **代码调试** - 找出 bug 并给出修复方案
12
- - 📦 **代码模板** - 快速生成项目代码
13
- - 💬 **交互模式** - 持续对话,像聊天一样编程
11
+ - 🤖 **AI 对话** 用自然语言让 AI 帮你写代码
12
+ - 📖 **代码解释** 通俗易懂地解释代码含义
13
+ - 🔧 **代码调试** 找出 bug 并给出修复方案
14
+ - 📦 **代码模板** 快速生成项目代码
15
+ - 💬 **交互模式** 持续对话,像聊天一样编程
16
+ - 🧰 **内置工具** — 文件读写 / Shell 执行 / Git 操作 / 代码搜索
17
+ - 🚫 **抗污染防御** — `SessionManager` 自动过滤 `[已中断]` 等历史污染
14
18
 
15
19
  ---
16
20
 
@@ -18,83 +22,180 @@
18
22
 
19
23
  ### 🎯 一键安装(推荐)
20
24
 
21
- **Windows 用户**:复制下面命令,粘贴到 CMD 里回车:
25
+ 安装脚本全部托管在 GitHub 上、`install.sh` / `install.ps1` / `install.bat`
26
+ 可直接 curl / iwr:
22
27
 
23
- ```cmd
24
- curl -L https://git.io/thatgfsj -o install.bat && install.bat
28
+ **macOS / Linux**:
29
+
30
+ ```bash
31
+ curl -L https://raw.githubusercontent.com/Thatgfsj/thatgfsj-code/main/install.sh | bash
25
32
  ```
26
33
 
27
34
  **Windows (PowerShell)**:
28
35
 
29
36
  ```powershell
30
- powershell -c "irm https://git.io/thatgfsj | iex"
37
+ irm https://raw.githubusercontent.com/Thatgfsj/thatgfsj-code/main/install.ps1 | iex
31
38
  ```
32
39
 
33
- **macOS / Linux**:
40
+ **Windows (CMD)**:
34
41
 
35
- ```bash
36
- curl -sL https://git.io/thatgfsj | bash
42
+ ```cmd
43
+ curl -L https://raw.githubusercontent.com/Thatgfsj/thatgfsj-code/main/install.bat -o install.bat && install.bat
37
44
  ```
38
45
 
46
+ > ⚠️ 旧版本 README 里出现的 `https://git.io/thatgfsj` 短链已失效(GitHub 在 2022
47
+ > 年下线了 `git.io`),请使用上面的原始 GitHub 链接。
48
+
39
49
  安装过程会自动完成:
40
- 1. 检查/安装 Node.js
41
- 2. 下载代码
42
- 3. 安装依赖
43
- 4. 配置命令
44
- 5. 引导设置 API Key
50
+ 1. 检查/安装 Node.js(≥ 18)
51
+ 2. 下载代码 / 链接 npm 全局命令
52
+ 3. 安装依赖并构建 `dist/`
53
+ 4. 引导你设置 API Key
45
54
 
46
55
  ---
47
56
 
48
57
  ## 📖 使用方法
49
58
 
50
- 安装完成后,在终端里直接用:
59
+ 安装完成后,在终端里直接用 `gfcode`(或 `thatgfsj`,两个 bin 都指向同一入口):
51
60
 
52
61
  ```bash
53
62
  # 交互模式(推荐)
54
63
  gfcode
55
64
 
56
- # 让 AI 帮你写代码
65
+ # 让 AI 帮你写代码(单命令模式,自动流式输出)
57
66
  gfcode "写一个 Python 的 Hello World"
67
+ gfcode -m Qwen/Qwen2.5-32B-Instruct "重构 src/index.ts"
58
68
 
59
- # 解释代码
69
+ # 解释代码:直接传字符串,或 -f 指定文件
60
70
  gfcode explain "const add = (a, b) => a + b;"
71
+ gfcode explain -f src/index.ts
61
72
 
62
- # 调试代码
73
+ # 调试代码:可附加 -e 错误信息
63
74
  gfcode debug "你的代码"
75
+ gfcode debug -f src/foo.ts -e "TypeError: x is not a function"
64
76
 
65
- # 问答
77
+ # 问答(带当前项目上下文)
66
78
  gfcode chat "怎么用 Node.js 写 API?"
67
79
 
68
80
  # 生成代码模板
69
- gfcode template react -n MyButton
81
+ gfcode template react -n MyButton -o ./components
70
82
  ```
71
83
 
84
+ > `--stream` / `--no-auto` / `-m` 接受任意命令并对当次调用生效;`-i` 强制进入 REPL。
85
+ > 详细 flag 见 [`DEVELOPMENT.md`](./DEVELOPMENT.md) 第 5 节。
86
+
87
+ ### REPL 内置命令
88
+
89
+ 进入交互模式(直接运行 `gfcode`)后,可以输入下列命令(带或不带前导 `/` 都行):
90
+
91
+ | 命令 | 作用 |
92
+ | -------------- | --------------------------------------------------- |
93
+ | `help` | 显示所有内置命令 |
94
+ | `exit` | 退出 REPL |
95
+ | `clear` | 清屏 |
96
+ | `context` | 显示当前项目上下文 |
97
+ | `history` | 显示本次会话的命令历史 |
98
+ | `tools` | 列出已注册的工具(file / shell / git / search) |
99
+ | `models` | 只读地列出当前 provider 的可用模型 |
100
+ | `providers` | 只读地列出支持的 provider |
101
+ | `/model` | **交互式切换当前 provider 下的模型**,立即生效并持久化到 `~/.thatgfsj/config.json` |
102
+ | `/provider` | **交互式切换 provider**,切换后自动跟进选模型 |
103
+ | `Ctrl+C` | 单次:停止当前流式生成;空输入连续两次退出 REPL |
104
+
105
+ #### `/model` / `/provider` 示例
106
+
107
+ ```
108
+ > /model
109
+ 🤖 /model — 切换模型 (provider: siliconflow)
110
+
111
+ 最近使用:
112
+ r1. Qwen/Qwen2.5-32B-Instruct
113
+ r2. Pro/moonshotai/Kimi-K2.5
114
+
115
+ 内置模型:
116
+ 1. Qwen2.5-7B (推荐) Qwen/Qwen2.5-7B-Instruct ✓
117
+ 2. Qwen2.5-32B Qwen/Qwen2.5-32B-Instruct
118
+ 3. Qwen2.5-72B Qwen/Qwen2.5-72B-Instruct
119
+ 4. Kimi-K2.5 (私有) Pro/moonshotai/Kimi-K2.5
120
+ 5. DeepSeek-V3 Pro/deepseek-ai/DeepSeek-V3
121
+
122
+
123
+ 输入编号 (r1-r2 / 1-10)、完整 model id、或任意自定义 id。回车保持当前。
124
+ model > r2
125
+ ✅ 模型已切换为: Pro/moonshotai/Kimi-K2.5 (Pro/moonshotai/Kimi-K2.5)
126
+
127
+ # 也可以直接粘一个自定义 model id(适合 OpenAI-compatible 中转/Ollama):
128
+ model > my-custom-fine-tune
129
+ ✅ 模型已切换为: my-custom-fine-tune (自定义)
130
+ ```
131
+
132
+ `/provider` 的工作流类似,但会让你先选 9 个提供商之一(SiliconFlow /
133
+ MiniMax / OpenAI / Anthropic / Gemini / Kimi / DeepSeek / ERNIE / Ollama),
134
+ 然后自动跟进模型选择。如果新 provider 缺少对应的环境变量,会提示先
135
+ `gfcode init` 或手动 `export`。
136
+
137
+ 切换过的 model 会写入 `~/.thatgfsj/models.json` 历史文件,下次打开
138
+ `/model` 时按时间倒序展示在「最近使用」段。
139
+
72
140
  ---
73
141
 
74
142
  ## ❓ 常见问题
75
143
 
76
144
  ### Q: 安装后命令找不到?
77
145
 
78
- **A**: 重启终端,然后运行 `gfcode`
146
+ **A**: 重启终端,然后运行 `gfcode`。Windows 上确认 PowerShell / CMD 已重新加载 `%PATH%`。
79
147
 
80
148
  ### Q: 怎么配置 API Key?
81
149
 
82
- **A**: 运行 `gfcode init`,按提示选择并输入 API Key
150
+ **A**: 运行 `gfcode init`,按提示选择提供商、粘贴 key、挑选模型。也可以直接设置环境变量
151
+ (`SILICONFLOW_API_KEY` / `OPENAI_API_KEY` / `MINIMAX_API_KEY` /
152
+ `ANTHROPIC_API_KEY` / `GEMINI_API_KEY` / `KIMI_API_KEY` / `DEEPSEEK_API_KEY` /
153
+ `ERNIE_API_KEY`),或者把配置写到 `~/.thatgfsj/config.json`。
83
154
 
84
155
  ### Q: 哪个 Provider 最好?
85
156
 
86
- **A**: 新手推荐 **SiliconFlow**(性价比高,国产)
157
+ **A**: 新手推荐 **SiliconFlow**(性价比高,国产),可选用 Qwen2.5 / Kimi-K2.5 / DeepSeek-V3 等模型。
158
+
159
+ ### Q: `--version` 显示老版本号?
160
+
161
+ **A**: 升级到 0.2.2+,版本号现在从 `package.json` 动态读取,CI / re-install 都会自动同步。
162
+
163
+ ### Q: 启动瞬间报错 `ReferenceError: require is not defined`?
164
+
165
+ **A**: 那是 0.2.1 之前的 bug,0.2.2 已经修复(使用 `createRequire(import.meta.url)` 兼容)。
166
+
167
+ 更多问题 → [`docs/FAQ.md`](./docs/FAQ.md)。
87
168
 
88
169
  ---
89
170
 
90
171
  ## 📚 文档
91
172
 
92
- - [API Key 获取教程](./docs/API_KEY_GUIDE.md)
93
- - [常见问题 FAQ](./docs/FAQ.md)
173
+ - [DEVELOPMENT.md](./DEVELOPMENT.md) — 架构 / 构建 / 扩展 / 发布(贡献者必读)
174
+ - [CHANGELOG.md](./CHANGELOG.md) — 每次版本的变更说明
175
+ - [docs/API_KEY_GUIDE.md](./docs/API_KEY_GUIDE.md) — 9 个 Provider 的 API Key 获取教程
176
+ - [docs/FAQ.md](./docs/FAQ.md) — 详细 FAQ
177
+
178
+ ---
179
+
180
+ ## 🧪 本地自检
181
+
182
+ ```bash
183
+ npm install
184
+ npm test # node --test tests/
185
+ npm run build
186
+ node dist/index.js --version
187
+ ```
94
188
 
95
189
  ---
96
190
 
97
191
  ## 🤝 问题反馈
98
192
 
99
- 有问题?去 GitHub 提 Issue:
193
+ 有问题?去 GitHub 提 Issue:
194
+
100
195
  https://github.com/Thatgfsj/thatgfsj-code/issues
196
+
197
+ ---
198
+
199
+ ## 📜 License
200
+
201
+ MIT © Thatgfsj
@@ -11,6 +11,16 @@ export declare class AIEngine {
11
11
  private config;
12
12
  private tools;
13
13
  constructor(config: AIConfig);
14
+ /**
15
+ * Replace the active configuration at runtime.
16
+ * Used by the REPL `/model` / `/provider` commands — the next streamed
17
+ * request will pick up the new model / baseUrl / provider.
18
+ */
19
+ updateConfig(config: AIConfig): void;
20
+ /**
21
+ * Inspect a snapshot of the active configuration (read-only).
22
+ */
23
+ getConfig(): Readonly<AIConfig>;
14
24
  /**
15
25
  * Register tools for function calling
16
26
  */
@@ -43,6 +53,13 @@ export declare class AIEngine {
43
53
  private parseResponse;
44
54
  /**
45
55
  * Extract tool calls from response content
56
+ *
57
+ * NOTE: 当前为占位实现,实际不会从流式内容中解析工具调用。这意味着
58
+ * `chatStream` 内的 `if (response.tool_calls ...)` 分支永远不会进入,
59
+ * 已注册的 `Tool` 不会被调用,Agent 等价于一个聊天客户端。这是有意为之的
60
+ * 局限性 — 真实工具调用解析需要每个提供商走 JSON mode / native tool_calls
61
+ * 流(chunks 里的 `delta.tool_calls` 已被 `extractChunkText` 丢弃)。
62
+ * 修复此问题需要更大的重构,不属于 0.2.2 patch 的范围。
46
63
  */
47
64
  private extractToolCalls;
48
65
  /**