thatgfsj-code 0.3.0 → 0.3.1
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/CHANGELOG.md +229 -0
- package/DEVELOPMENT.md +286 -0
- package/README.md +144 -79
- package/dist/agent/core.d.ts +56 -0
- package/dist/agent/core.d.ts.map +1 -0
- package/dist/agent/core.js +142 -0
- package/dist/agent/core.js.map +1 -0
- package/dist/agent/index.d.ts +8 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +8 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/intent.d.ts +36 -0
- package/dist/agent/intent.d.ts.map +1 -0
- package/dist/agent/intent.js +146 -0
- package/dist/agent/intent.js.map +1 -0
- package/dist/agent/streaming.d.ts +50 -0
- package/dist/agent/streaming.d.ts.map +1 -0
- package/dist/agent/streaming.js +110 -0
- package/dist/agent/streaming.js.map +1 -0
- package/dist/core/ai-engine.d.ts +76 -0
- package/dist/core/ai-engine.d.ts.map +1 -0
- package/dist/core/ai-engine.js +394 -0
- package/dist/core/ai-engine.js.map +1 -0
- package/dist/core/cli.d.ts +21 -0
- package/dist/core/cli.d.ts.map +1 -0
- package/dist/core/cli.js +143 -0
- package/dist/core/cli.js.map +1 -0
- package/dist/core/config.d.ts +55 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +162 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/context-compactor.d.ts +54 -0
- package/dist/core/context-compactor.d.ts.map +1 -0
- package/dist/core/context-compactor.js +197 -0
- package/dist/core/context-compactor.js.map +1 -0
- package/dist/core/hooks.d.ts +75 -0
- package/dist/core/hooks.d.ts.map +1 -0
- package/dist/core/hooks.js +146 -0
- package/dist/core/hooks.js.map +1 -0
- package/dist/core/permissions.d.ts +52 -0
- package/dist/core/permissions.d.ts.map +1 -0
- package/dist/core/permissions.js +237 -0
- package/dist/core/permissions.js.map +1 -0
- package/dist/core/session.d.ts +54 -0
- package/dist/core/session.d.ts.map +1 -0
- package/dist/core/session.js +147 -0
- package/dist/core/session.js.map +1 -0
- package/dist/core/skills.d.ts +60 -0
- package/dist/core/skills.d.ts.map +1 -0
- package/dist/core/skills.js +175 -0
- package/dist/core/skills.js.map +1 -0
- package/dist/core/state.d.ts +60 -0
- package/dist/core/state.d.ts.map +1 -0
- package/dist/core/state.js +106 -0
- package/dist/core/state.js.map +1 -0
- package/dist/core/subagent.d.ts +68 -0
- package/dist/core/subagent.d.ts.map +1 -0
- package/dist/core/subagent.js +142 -0
- package/dist/core/subagent.js.map +1 -0
- package/dist/core/system-prompt.d.ts +40 -0
- package/dist/core/system-prompt.d.ts.map +1 -0
- package/dist/core/system-prompt.js +138 -0
- package/dist/core/system-prompt.js.map +1 -0
- package/dist/core/tool-registry.d.ts +53 -0
- package/dist/core/tool-registry.d.ts.map +1 -0
- package/dist/core/tool-registry.js +138 -0
- package/dist/core/tool-registry.js.map +1 -0
- package/dist/core/types.d.ts +206 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +127 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/{cmd/index.d.ts.map → index.d.ts.map} +1 -1
- package/dist/index.js +472 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/client.d.ts +1 -1
- package/dist/mcp/client.d.ts.map +1 -1
- package/dist/repl/index.d.ts +8 -0
- package/dist/repl/index.d.ts.map +1 -0
- package/dist/repl/index.js +8 -0
- package/dist/repl/index.js.map +1 -0
- package/dist/repl/input.d.ts +69 -0
- package/dist/repl/input.d.ts.map +1 -0
- package/dist/repl/input.js +139 -0
- package/dist/repl/input.js.map +1 -0
- package/dist/repl/loop.d.ts +184 -0
- package/dist/repl/loop.d.ts.map +1 -0
- package/dist/repl/loop.js +932 -0
- package/dist/repl/loop.js.map +1 -0
- package/dist/repl/output.d.ts +105 -0
- package/dist/repl/output.d.ts.map +1 -0
- package/dist/repl/output.js +199 -0
- package/dist/repl/output.js.map +1 -0
- package/dist/repl/welcome.d.ts +68 -0
- package/dist/repl/welcome.d.ts.map +1 -0
- package/dist/repl/welcome.js +254 -0
- package/dist/repl/welcome.js.map +1 -0
- package/dist/tools/file.d.ts +1 -1
- package/dist/tools/file.d.ts.map +1 -1
- package/dist/tools/git.d.ts +1 -1
- package/dist/tools/git.d.ts.map +1 -1
- package/dist/tools/index.d.ts +15 -35
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +31 -80
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/search.d.ts +1 -1
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tools/shell.d.ts +11 -4
- package/dist/tools/shell.d.ts.map +1 -1
- package/dist/tools/shell.js +78 -42
- package/dist/tools/shell.js.map +1 -1
- package/dist/utils/diff-preview.d.ts +42 -0
- package/dist/utils/diff-preview.d.ts.map +1 -0
- package/dist/utils/diff-preview.js +174 -0
- package/dist/utils/diff-preview.js.map +1 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +8 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/memory.d.ts +81 -0
- package/dist/utils/memory.d.ts.map +1 -0
- package/dist/utils/memory.js +186 -0
- package/dist/utils/memory.js.map +1 -0
- package/dist/utils/project-context.d.ts +62 -0
- package/dist/utils/project-context.d.ts.map +1 -0
- package/dist/utils/project-context.js +197 -0
- package/dist/utils/project-context.js.map +1 -0
- package/docs/API_KEY_GUIDE.md +6 -0
- package/docs/FAQ.md +25 -3
- package/package.json +41 -9
- package/ROADMAP.md +0 -61
- package/dist/app/agent.d.ts +0 -31
- package/dist/app/agent.d.ts.map +0 -1
- package/dist/app/agent.js +0 -106
- package/dist/app/agent.js.map +0 -1
- package/dist/app/index.d.ts +0 -39
- package/dist/app/index.d.ts.map +0 -1
- package/dist/app/index.js +0 -80
- package/dist/app/index.js.map +0 -1
- package/dist/cmd/index.d.ts +0 -12
- package/dist/cmd/index.js +0 -85
- package/dist/cmd/index.js.map +0 -1
- package/dist/config/index.d.ts +0 -39
- package/dist/config/index.d.ts.map +0 -1
- package/dist/config/index.js +0 -110
- package/dist/config/index.js.map +0 -1
- package/dist/config/providers.d.ts +0 -23
- package/dist/config/providers.d.ts.map +0 -1
- package/dist/config/providers.js +0 -152
- package/dist/config/providers.js.map +0 -1
- package/dist/config/types.d.ts +0 -33
- package/dist/config/types.d.ts.map +0 -1
- package/dist/config/types.js +0 -5
- package/dist/config/types.js.map +0 -1
- package/dist/hooks/index.d.ts +0 -31
- package/dist/hooks/index.d.ts.map +0 -1
- package/dist/hooks/index.js +0 -71
- package/dist/hooks/index.js.map +0 -1
- package/dist/llm/anthropic.d.ts +0 -17
- package/dist/llm/anthropic.d.ts.map +0 -1
- package/dist/llm/anthropic.js +0 -126
- package/dist/llm/anthropic.js.map +0 -1
- package/dist/llm/gemini.d.ts +0 -16
- package/dist/llm/gemini.d.ts.map +0 -1
- package/dist/llm/gemini.js +0 -107
- package/dist/llm/gemini.js.map +0 -1
- package/dist/llm/index.d.ts +0 -48
- package/dist/llm/index.d.ts.map +0 -1
- package/dist/llm/index.js +0 -174
- package/dist/llm/index.js.map +0 -1
- package/dist/llm/openai.d.ts +0 -17
- package/dist/llm/openai.d.ts.map +0 -1
- package/dist/llm/openai.js +0 -113
- package/dist/llm/openai.js.map +0 -1
- package/dist/llm/provider.d.ts +0 -33
- package/dist/llm/provider.d.ts.map +0 -1
- package/dist/llm/provider.js +0 -6
- package/dist/llm/provider.js.map +0 -1
- package/dist/prompts/index.d.ts +0 -27
- package/dist/prompts/index.d.ts.map +0 -1
- package/dist/prompts/index.js +0 -102
- package/dist/prompts/index.js.map +0 -1
- package/dist/session/compactor.d.ts +0 -48
- package/dist/session/compactor.d.ts.map +0 -1
- package/dist/session/compactor.js +0 -77
- package/dist/session/compactor.js.map +0 -1
- package/dist/session/index.d.ts +0 -48
- package/dist/session/index.d.ts.map +0 -1
- package/dist/session/index.js +0 -69
- package/dist/session/index.js.map +0 -1
- package/dist/session/message.d.ts +0 -26
- package/dist/session/message.d.ts.map +0 -1
- package/dist/session/message.js +0 -34
- package/dist/session/message.js.map +0 -1
- package/dist/tools/types.d.ts +0 -68
- package/dist/tools/types.d.ts.map +0 -1
- package/dist/tools/types.js +0 -57
- package/dist/tools/types.js.map +0 -1
- package/dist/tui/index.d.ts +0 -8
- package/dist/tui/index.d.ts.map +0 -1
- package/dist/tui/index.js +0 -8
- package/dist/tui/index.js.map +0 -1
- package/dist/tui/input.d.ts +0 -14
- package/dist/tui/input.d.ts.map +0 -1
- package/dist/tui/input.js +0 -50
- package/dist/tui/input.js.map +0 -1
- package/dist/tui/output.d.ts +0 -20
- package/dist/tui/output.d.ts.map +0 -1
- package/dist/tui/output.js +0 -70
- package/dist/tui/output.js.map +0 -1
- package/dist/tui/repl.d.ts +0 -25
- package/dist/tui/repl.d.ts.map +0 -1
- package/dist/tui/repl.js +0 -114
- package/dist/tui/repl.js.map +0 -1
- package/dist/tui/welcome.d.ts +0 -15
- package/dist/tui/welcome.d.ts.map +0 -1
- package/dist/tui/welcome.js +0 -86
- package/dist/tui/welcome.js.map +0 -1
- package/dist/types.d.ts +0 -38
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -6
- package/dist/types.js.map +0 -1
- package/dist/utils/diff.d.ts +0 -22
- package/dist/utils/diff.d.ts.map +0 -1
- package/dist/utils/diff.js +0 -60
- package/dist/utils/diff.js.map +0 -1
- package/dist/utils/project.d.ts +0 -32
- package/dist/utils/project.d.ts.map +0 -1
- package/dist/utils/project.js +0 -89
- package/dist/utils/project.js.map +0 -1
- package/src/app/agent.ts +0 -140
- package/src/app/index.ts +0 -101
- package/src/cmd/index.ts +0 -96
- package/src/config/index.ts +0 -130
- package/src/config/providers.ts +0 -160
- package/src/config/types.ts +0 -46
- package/src/hooks/index.ts +0 -111
- package/src/llm/anthropic.ts +0 -146
- package/src/llm/gemini.ts +0 -127
- package/src/llm/index.ts +0 -209
- package/src/llm/openai.ts +0 -132
- package/src/llm/provider.ts +0 -38
- package/src/mcp/client.ts +0 -330
- package/src/prompts/index.ts +0 -123
- package/src/session/compactor.ts +0 -103
- package/src/session/index.ts +0 -81
- package/src/session/message.ts +0 -42
- package/src/tools/file.ts +0 -117
- package/src/tools/git.ts +0 -132
- package/src/tools/index.ts +0 -108
- package/src/tools/search.ts +0 -263
- package/src/tools/shell.ts +0 -136
- package/src/tools/types.ts +0 -122
- package/src/tui/index.ts +0 -8
- package/src/tui/input.ts +0 -56
- package/src/tui/output.ts +0 -83
- package/src/tui/repl.ts +0 -131
- package/src/tui/welcome.ts +0 -101
- package/src/types.ts +0 -42
- package/src/utils/diff.ts +0 -71
- package/src/utils/project.ts +0 -99
- package/tsconfig.json +0 -19
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
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.3.1] - 2026-07-06
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
- **「已保存的模型」作为 `/model` 主视图**:0.2.x 进 `/model` 先列内置模型,
|
|
22
|
+
这版改为先列 `~/.thatgfsj/models.json` 里**已经保存的模型**(显示 id +
|
|
23
|
+
`ctx` + `thinking` + `note/provider`),与 1.0.4 的 `ModelSelector` 行为
|
|
24
|
+
对齐。内置 provider 模型列表作为辅助信息保留在底部。
|
|
25
|
+
- **`+ 添加新模型` 向导**:在 `/model` 选 `a` / `add` / `+` 启动完整向导:
|
|
26
|
+
1. **步骤 1/6: 选择 provider**(10 个:8 个内置 + `custom_openai` + `custom_anthropic`)
|
|
27
|
+
2. **步骤 2/6: 输入 API Key**(custom_* 可选跳过)
|
|
28
|
+
3. **步骤 3/6: 输入 baseUrl**(仅 custom_*;要求 `https://.../v1` 形式)
|
|
29
|
+
4. **步骤 4/6: 输入模型 id**
|
|
30
|
+
5. **步骤 5/6: 上下文长度 (MiB)**(默认 8;常见 8 / 32 / 128 / 200)
|
|
31
|
+
6. **步骤 6/6: 思考强度**(`none` / `low` / `medium` / `high` / `max`,默认 `none`)
|
|
32
|
+
完成后:写入 `~/.thatgfsj/models.json`,同步切换到新模型(更新
|
|
33
|
+
`AIEngine` + `~/.thatgfsj/config.json`),并把 `[system: model ... added]`
|
|
34
|
+
注入 `SessionManager`,让 LLM 下一轮看到。
|
|
35
|
+
- **`/edit` 修改已保存模型**:1.0.4 时代就期望的能力,本次补齐:
|
|
36
|
+
- `/edit` 列出全部已保存模型,输入编号或完整 id 进入
|
|
37
|
+
- `/edit 1` / `/edit Qwen3-32B` 直接跳到对应模型
|
|
38
|
+
- 修改 `ctx` / `thinking` / `note`,空回车保留旧值,`-` 清空字段
|
|
39
|
+
- **`/provider` 支持自定义 provider**:
|
|
40
|
+
- 新增 `custom_openai`(OpenAI 兼容中转站)与 `custom_anthropic`
|
|
41
|
+
(Anthropic 兼容中转站)两项
|
|
42
|
+
- 选中后立刻提示输入 baseUrl,跳过内置的 `envKey` 校验
|
|
43
|
+
- 自动跟进 `/model` 让你顺便挑 / 添加一个模型
|
|
44
|
+
- **`SavedModel` 类型导出**(`src/repl/loop.ts`):
|
|
45
|
+
```ts
|
|
46
|
+
interface SavedModel {
|
|
47
|
+
id: string;
|
|
48
|
+
addedAt?: number;
|
|
49
|
+
ctx?: number; // 上下文长度,单位 MiB
|
|
50
|
+
thinking?: 'none' | 'low' | 'medium' | 'high' | 'max';
|
|
51
|
+
note?: string; // 备注(如 provider id、quant 说明等)
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
- **6 个新单元测试**(`tests/unit-wizard.test.js`):覆盖 v0.2.x → v0.3.x
|
|
55
|
+
history 形状的透明迁移、`appendSavedModel` 大小写不敏感去重 + canonical
|
|
56
|
+
casing 保留、`replaceSavedModel` 单条更新、`SavedModel` 形状 JSON 往返。
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
- **appendSavedModel casing**:之前大小写不一致的同一模型会被当成两条;
|
|
60
|
+
现在若已经存了 `Qwen3-32B`,再次输入 `qwen3-32b` 仍然只保留 `Qwen3-32B`
|
|
61
|
+
(原始拼写规范)。
|
|
62
|
+
|
|
63
|
+
> ⚠️ 上游 npm 上 `0.3.0` 已经被 1.0.4 时代占用过,因此本次发布使用 `0.3.1`,
|
|
64
|
+
> 仅是 patch 编号变化,feature 内容就是上面这份。
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## [0.2.3] - 2026-07-06
|
|
69
|
+
|
|
70
|
+
### Added
|
|
71
|
+
- **中文命令别名**:1.0.4 老版本支持的 `/模型`、`/提供商`、`/提供商切换`、
|
|
72
|
+
`/帮助`、`/退出`、`/清除`、`/清屏`、`/历史`、`/工具`、`/上下文`、
|
|
73
|
+
`/模型列表` 现在都被识别。同时支持全角斜杠 `/模型`。详见
|
|
74
|
+
`src/repl/loop.ts::handleCommand`。
|
|
75
|
+
- **`/model`「当前」标记**:即使当前模型不在内置列表里(老配置 / 自定义 id),
|
|
76
|
+
`/model` 现在会在顶部显示一行 `⮕ 当前 (非内置): <id>`,并保留内置 / 历史
|
|
77
|
+
列表中的 `✓` 标记逻辑。
|
|
78
|
+
- **3 个新单元测试**(`tests/unit-config.test.js`):验证 0.2.3 的
|
|
79
|
+
`ConfigManager` 行为契约(不再有 silent fallback 警告、从 `CUSTOM_BASE_URL`
|
|
80
|
+
/ `OPENAI_API_KEY` 派生 baseUrl、识别 8 个 provider name)。
|
|
81
|
+
|
|
82
|
+
### Fixed
|
|
83
|
+
- **legacy provider 名称崩溃**:0.2.2 的 `ConfigManager.resolveProvider` 对
|
|
84
|
+
任何不在白名单的 provider(如 1.0.4 的 `custom_openai`)会强行 overwrite
|
|
85
|
+
成 `siliconflow` 并打印 `Unknown provider: custom_openai, falling back to
|
|
86
|
+
siliconflow` 警告,结果用户的 `MiniMax-M3` 等真实配置被悄悄丢掉,下一个
|
|
87
|
+
AI 请求直接撞上 401。0.2.3 改为:
|
|
88
|
+
- 保留用户的 provider id 不动。
|
|
89
|
+
- 从 `CUSTOM_BASE_URL` / `BASE_URL` 环境变量派生 baseUrl,如果都没有则
|
|
90
|
+
退到 `https://api.openai.com/v1`。
|
|
91
|
+
- API Key 从 `OPENAI_API_KEY` / `CUSTOM_API_KEY` / config 里取。
|
|
92
|
+
- 不再打「Unknown provider」警告。
|
|
93
|
+
- **空 prompt / 引号包裹 prompt**:`REPLInput.prompt()` 收到被意外粘贴成
|
|
94
|
+
`""` 或 `''` 的内容时,0.2.3 会在 loop 里剥离外层引号再判断是否为空。
|
|
95
|
+
这避免了用户从 markdown 复制示例时把空串丢给 LLM(命中 `[API Error: 401]`)。
|
|
96
|
+
- **DEFAULT_CONFIG 太老**:`ConfigManager` 默认从 `Qwen2.5-7B-Instruct`
|
|
97
|
+
升级到 `Qwen3-235B-A22B-Instruct-2507`(或 `Qwen3-32B` 作为
|
|
98
|
+
`PROVIDERS.siliconflow.defaultModel`)。
|
|
99
|
+
|
|
100
|
+
### Changed
|
|
101
|
+
- **刷新内置模型列表**(`src/repl/welcome.ts` + `src/core/types.ts`):
|
|
102
|
+
- SiliconFlow:Qwen3-235B / Qwen3-Coder-480B / Kimi-K2 / DeepSeek-V3.2 /
|
|
103
|
+
ERNIE-4.5 等。
|
|
104
|
+
- MiniMax:M3(推荐)、M2.5、M2.1(默认从 `MiniMax-M2.5` 升到 `MiniMax-M3`)。
|
|
105
|
+
- OpenAI:GPT-4.1 / GPT-4.1-mini / GPT-4o / o4-mini / GPT-5。
|
|
106
|
+
- Anthropic:Claude-Haiku-4.5 / Claude-Sonnet-4.5 / Claude-Opus-4.1。
|
|
107
|
+
- Gemini:Gemini-2.5-Flash / Gemini-2.5-Pro / Gemini-2.0-Flash。
|
|
108
|
+
- Kimi:Moonshot-V1-128K / Kimi-K2。
|
|
109
|
+
- DeepSeek:DeepSeek-V3(带 R1 推理)。
|
|
110
|
+
- ERNIE:ERNIE-4.5-8K(百度最新旗舰)。
|
|
111
|
+
- **`PROVIDERS` 默认模型**全部更新到 2025+ 推荐(Qwen3-32B、MiniMax-M3、
|
|
112
|
+
GPT-4.1-mini、Claude-Haiku-4.5、Llama3、Gemini-2.5-Flash、Kimi-K2 等)。
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## [0.2.2] - 2026-07-06
|
|
117
|
+
|
|
118
|
+
### Added
|
|
119
|
+
- **`/model` / `/provider` REPL 命令**:1.0.4 老版本里这两个交互式切换命令
|
|
120
|
+
在 0.2.x 系列中曾经被删掉,这次重新实现并对齐新代码结构,并且从
|
|
121
|
+
`thatgfsj-code@1.0.4` 的 TUI 版本里借鉴并移植了两项核心体验:
|
|
122
|
+
- `/model` 列出当前 provider 的所有模型(含 `✓` 标记当前选中),输入编号
|
|
123
|
+
或完整 model id 切换;立即写入 `~/.thatgfsj/config.json` 并通过
|
|
124
|
+
`AIEngine.updateConfig()` 让下一次流式请求生效。空输入回车保持当前,
|
|
125
|
+
Ctrl+C 取消。
|
|
126
|
+
- **历史记录持久化**(借鉴 1.0.4 的 `saveModelToHistory`):切换过的
|
|
127
|
+
model id 写入 `~/.thatgfsj/models.json`,下次打开 `/model` 时会在
|
|
128
|
+
内置列表上方显示「最近使用」段(最多 5 条,按时间排序,可通过 `r1`..`r5`
|
|
129
|
+
快捷选取,自动 dedup)。
|
|
130
|
+
- **任意 model id**:输入既不在内置列表也不在历史里的字符串,按自定义模型
|
|
131
|
+
处理(适合 OpenAI-compatible 中转站 / Ollama 自定义模型名场景)。
|
|
132
|
+
- `/provider` 列出 9 个支持的 provider,选完自动跟进 `/model` 让用户选
|
|
133
|
+
新 provider 下的模型;如果新 provider 缺少对应的 API Key 环境变量,会提示
|
|
134
|
+
用户先 `gfcode init` 或 `export`。
|
|
135
|
+
- 两个命令都接受带或不带前导 `/`(与 1.0.4 的 `/模型` 老习惯兼容)。
|
|
136
|
+
- 切换后会把一行 `[system: ... switched to ...]` 注入 `SessionManager`,
|
|
137
|
+
让 LLM 在下一轮看到变更而不丢失上下文。
|
|
138
|
+
- **`AIEngine.updateConfig()` / `getConfig()`**:暴露给 REPL 内部用,支持
|
|
139
|
+
在不重启引擎的情况下替换 `model` / `provider` / `baseUrl` / `temperature` /
|
|
140
|
+
`maxTokens`。
|
|
141
|
+
- **34 个单元 / 冒烟测试**(`tests/`):npm 内置 `node:test`,覆盖:
|
|
142
|
+
- `smoke-cli.test.js` — `--version` / `--help` / 子命令空参守卫 / `bash -n`。
|
|
143
|
+
- `unit-session.test.js` — `SessionManager` 拦截「已中断」、相邻助手去重、
|
|
144
|
+
`truncate` 保留 system。
|
|
145
|
+
- `unit-diff.test.js` — `DiffPreview.compare` 边界(unicode / 大输入 / CRLF /
|
|
146
|
+
空输入)。
|
|
147
|
+
- `unit-switcher.test.js` — `/model` 的纯 helper(编号 / id 解析)
|
|
148
|
+
与 `AIEngine.updateConfig` 行为。
|
|
149
|
+
- **新增** `unit-model-history.test.js` — `~/.thatgfsj/models.json` 的
|
|
150
|
+
读写、dedup、corrupt-file 容错(`tests` 5 个 case)。
|
|
151
|
+
|
|
152
|
+
### Fixed
|
|
153
|
+
- **ESM `require()` 报错**:`src/index.ts` 顶层原先使用
|
|
154
|
+
`require('child_process')` / `require('fs')`,在 `"type": "module"` 项目里
|
|
155
|
+
直接抛 `ReferenceError: require is not defined`,导致 CLI 在包含 `package.json`
|
|
156
|
+
的项目目录下完全无法启动。改为 `createRequire(import.meta.url)` 兼容。
|
|
157
|
+
- **`--version` 与 banner 打印老版本号**:`src/index.ts:102` 与
|
|
158
|
+
`src/repl/output.ts:198` 硬编码 `0.2.0`/`v0.2.0`,而 `package.json` 是 `0.2.1`
|
|
159
|
+
甚至后续 release。两处都改为从 `package.json` 动态读取。
|
|
160
|
+
- **REPL Ctrl+C 无法退出**:`src/repl/loop.ts` 的全局 SIGINT 处理只打
|
|
161
|
+
warning,从来不调用 `this.running = false`。新增 `REPLInput.requestCancel()`,
|
|
162
|
+
在空输入连按两次 Ctrl+C 时正确退出。
|
|
163
|
+
- **`executeTask` 助手消息丢失**:单命令模式下助手回复从来没写回
|
|
164
|
+
`SessionManager`,导致同名 SessionManager 实例对多轮 prompt 拿不到上下文。
|
|
165
|
+
- **`(this.ai as any).chatStream`** 多余 `any` 强转:`this.ai` 已经过
|
|
166
|
+
null-check,删掉即可。
|
|
167
|
+
- **`extractToolCalls` 死分支**:`src/core/ai-engine.ts` 中 `if (…includes('tool_use'))
|
|
168
|
+
return undefined; return undefined;` 等价于永远返回 `undefined`。改为单行
|
|
169
|
+
`return undefined;` 并添加注释说明当前实际无法解析 tool call(属于已知限制)。
|
|
170
|
+
- **欢迎页 banner 字样写错**:`src/repl/welcome.ts` 顶部仍写着 `Claude Code`,
|
|
171
|
+
与项目名 `Thatgfsj Code` 不一致。已更正。
|
|
172
|
+
|
|
173
|
+
### Changed
|
|
174
|
+
- **`init` 命令动态 import 去重**:`src/index.ts:54` 的
|
|
175
|
+
`await import('./repl/welcome.js')` 与顶部静态 import 重复,删除。
|
|
176
|
+
- **`handleModelSwitch`** 在 `src/index.ts` 中属于死代码(无调用者),删除。
|
|
177
|
+
- **欢迎页标题框宽度自适应**:把 banner 顶部的 `Claude Code ` 换成
|
|
178
|
+
`Thatgfsj Code ` 后调整间隔符长度,保证盒子保持 62 列对齐。
|
|
179
|
+
|
|
180
|
+
### Documentation
|
|
181
|
+
- 新增 `DEVELOPMENT.md`:覆盖架构图、构建/测试流程、添加 provider / 命令 / tool
|
|
182
|
+
的步骤、跨平台注意事项、发布流程。
|
|
183
|
+
- 新增本文件 `CHANGELOG.md`。
|
|
184
|
+
- 更新 `README.md`:替换失效的 `git.io/thatgfsj` 安装链接为 GitHub raw 直链;
|
|
185
|
+
补上 `gfcode init` 使用示例与所有顶层 / 子命令 flag;附 REPL 内置命令列表
|
|
186
|
+
以及 Node ≥ 18 的前置条件。
|
|
187
|
+
- `docs/FAQ.md`、`docs/API_KEY_GUIDE.md` 交叉链接到 `DEVELOPMENT.md`。
|
|
188
|
+
|
|
189
|
+
### Packaging
|
|
190
|
+
- `package.json` 新增 `files`、`engines`、`repository`、`bugs`、`homepage`
|
|
191
|
+
字段;原先没有 `files` 白名单会导致 `npm publish` 不会自动包含 `dist/`
|
|
192
|
+
(dist 在 `.gitignore` 里),现在通过显式白名单确保 tarball 包含
|
|
193
|
+
构建产物与文档。
|
|
194
|
+
- 新增 `scripts.test`、`scripts.test:silent`、`scripts.prepublishOnly`,
|
|
195
|
+
发布前自动跑测试和 build,防止 release 出错。
|
|
196
|
+
|
|
197
|
+
### Tests
|
|
198
|
+
- 新增 `tests/` 目录,使用 Node 内置 `node --test` 跑通:
|
|
199
|
+
- `tests/smoke-cli.test.js` — `dist/index.js --version` / `--help` / `chat`
|
|
200
|
+
/ `explain` / `debug` / `template` 空参守卫;`bash -n install.sh` 语法。
|
|
201
|
+
- `tests/unit-session.test.js` — `SessionManager` 拦截「已中断」污染、
|
|
202
|
+
相邻助手消息去重、`truncate` 保留 system。
|
|
203
|
+
- `tests/unit-diff.test.js` — `DiffPreview.compare` 在相同 / 不同 /
|
|
204
|
+
空 / unicode / CRLF 输入下的行为。
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## [0.2.1] - 2026-07-XX
|
|
209
|
+
|
|
210
|
+
### Fixed
|
|
211
|
+
- REPL 数字小键盘方向键响应(升级到 `@inquirer/input`,不再用 Node `readline`
|
|
212
|
+
直接 `.question()`)。
|
|
213
|
+
- 流式输出保留完整内容、不再 reset 终端 / 跳顶,用户可滚动查看历史。
|
|
214
|
+
- 修复 AI 输出 `[已中断]` 等污染字符串时反复循环同一段的 bug(`SessionManager`
|
|
215
|
+
拦截 `已中断` / `think` block,`getMessages()` 做相邻助手去重)。
|
|
216
|
+
|
|
217
|
+
### Added
|
|
218
|
+
- `src/repl/welcome.ts` Claude Code 风格欢迎页与 `gfcode init` 配置向导。
|
|
219
|
+
- `src/tools/{file,shell,git,search}.ts` 完整工具实现,并通过
|
|
220
|
+
`ToolRegistry` 注册到 AI Engine。
|
|
221
|
+
- `src/agent/{core,intent,streaming}.ts` Agent Loop、意图识别、流式输出。
|
|
222
|
+
- `src/utils/{diff-preview,memory,project-context}.ts`。
|
|
223
|
+
- `src/mcp/client.ts`:MCP 客户端雏形。
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## [0.1.0] - initial
|
|
228
|
+
|
|
229
|
+
- 初版发布:基础 `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.
|