thatgfsj-code 0.2.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.
Files changed (179) hide show
  1. package/.patches/0001-fix-repl-replace-readline-with-inquirer-input-for-ke.patch +279 -0
  2. package/.patches/0002-fix-repl-stream-AI-output-directly-to-stdout-so-term.patch +564 -0
  3. package/.patches/0003-fix-session-break-the-hallucination-loop-in-assistan.patch +194 -0
  4. package/.patches/0004-chore-release-bump-version-to-0.2.1.patch +24 -0
  5. package/LICENSE +21 -0
  6. package/README.md +100 -0
  7. package/ROADMAP.md +107 -0
  8. package/dist/agent/core.d.ts +56 -0
  9. package/dist/agent/core.d.ts.map +1 -0
  10. package/dist/agent/core.js +142 -0
  11. package/dist/agent/core.js.map +1 -0
  12. package/dist/agent/index.d.ts +8 -0
  13. package/dist/agent/index.d.ts.map +1 -0
  14. package/dist/agent/index.js +8 -0
  15. package/dist/agent/index.js.map +1 -0
  16. package/dist/agent/intent.d.ts +36 -0
  17. package/dist/agent/intent.d.ts.map +1 -0
  18. package/dist/agent/intent.js +146 -0
  19. package/dist/agent/intent.js.map +1 -0
  20. package/dist/agent/streaming.d.ts +50 -0
  21. package/dist/agent/streaming.d.ts.map +1 -0
  22. package/dist/agent/streaming.js +110 -0
  23. package/dist/agent/streaming.js.map +1 -0
  24. package/dist/core/ai-engine.d.ts +59 -0
  25. package/dist/core/ai-engine.d.ts.map +1 -0
  26. package/dist/core/ai-engine.js +378 -0
  27. package/dist/core/ai-engine.js.map +1 -0
  28. package/dist/core/cli.d.ts +21 -0
  29. package/dist/core/cli.d.ts.map +1 -0
  30. package/dist/core/cli.js +143 -0
  31. package/dist/core/cli.js.map +1 -0
  32. package/dist/core/config.d.ts +38 -0
  33. package/dist/core/config.d.ts.map +1 -0
  34. package/dist/core/config.js +129 -0
  35. package/dist/core/config.js.map +1 -0
  36. package/dist/core/context-compactor.d.ts +54 -0
  37. package/dist/core/context-compactor.d.ts.map +1 -0
  38. package/dist/core/context-compactor.js +197 -0
  39. package/dist/core/context-compactor.js.map +1 -0
  40. package/dist/core/hooks.d.ts +75 -0
  41. package/dist/core/hooks.d.ts.map +1 -0
  42. package/dist/core/hooks.js +146 -0
  43. package/dist/core/hooks.js.map +1 -0
  44. package/dist/core/permissions.d.ts +52 -0
  45. package/dist/core/permissions.d.ts.map +1 -0
  46. package/dist/core/permissions.js +237 -0
  47. package/dist/core/permissions.js.map +1 -0
  48. package/dist/core/session.d.ts +54 -0
  49. package/dist/core/session.d.ts.map +1 -0
  50. package/dist/core/session.js +147 -0
  51. package/dist/core/session.js.map +1 -0
  52. package/dist/core/skills.d.ts +60 -0
  53. package/dist/core/skills.d.ts.map +1 -0
  54. package/dist/core/skills.js +175 -0
  55. package/dist/core/skills.js.map +1 -0
  56. package/dist/core/state.d.ts +60 -0
  57. package/dist/core/state.d.ts.map +1 -0
  58. package/dist/core/state.js +106 -0
  59. package/dist/core/state.js.map +1 -0
  60. package/dist/core/subagent.d.ts +68 -0
  61. package/dist/core/subagent.d.ts.map +1 -0
  62. package/dist/core/subagent.js +142 -0
  63. package/dist/core/subagent.js.map +1 -0
  64. package/dist/core/system-prompt.d.ts +40 -0
  65. package/dist/core/system-prompt.d.ts.map +1 -0
  66. package/dist/core/system-prompt.js +138 -0
  67. package/dist/core/system-prompt.js.map +1 -0
  68. package/dist/core/tool-registry.d.ts +53 -0
  69. package/dist/core/tool-registry.d.ts.map +1 -0
  70. package/dist/core/tool-registry.js +138 -0
  71. package/dist/core/tool-registry.js.map +1 -0
  72. package/dist/core/types.d.ts +206 -0
  73. package/dist/core/types.d.ts.map +1 -0
  74. package/dist/core/types.js +127 -0
  75. package/dist/core/types.js.map +1 -0
  76. package/dist/index.d.ts +7 -0
  77. package/dist/index.d.ts.map +1 -0
  78. package/dist/index.js +481 -0
  79. package/dist/index.js.map +1 -0
  80. package/dist/mcp/client.d.ts +83 -0
  81. package/dist/mcp/client.d.ts.map +1 -0
  82. package/dist/mcp/client.js +267 -0
  83. package/dist/mcp/client.js.map +1 -0
  84. package/dist/repl/index.d.ts +8 -0
  85. package/dist/repl/index.d.ts.map +1 -0
  86. package/dist/repl/index.js +8 -0
  87. package/dist/repl/index.js.map +1 -0
  88. package/dist/repl/input.d.ts +61 -0
  89. package/dist/repl/input.d.ts.map +1 -0
  90. package/dist/repl/input.js +127 -0
  91. package/dist/repl/input.js.map +1 -0
  92. package/dist/repl/loop.d.ts +53 -0
  93. package/dist/repl/loop.d.ts.map +1 -0
  94. package/dist/repl/loop.js +241 -0
  95. package/dist/repl/loop.js.map +1 -0
  96. package/dist/repl/output.d.ts +105 -0
  97. package/dist/repl/output.d.ts.map +1 -0
  98. package/dist/repl/output.js +197 -0
  99. package/dist/repl/output.js.map +1 -0
  100. package/dist/repl/welcome.d.ts +68 -0
  101. package/dist/repl/welcome.d.ts.map +1 -0
  102. package/dist/repl/welcome.js +249 -0
  103. package/dist/repl/welcome.js.map +1 -0
  104. package/dist/tools/file.d.ts +46 -0
  105. package/dist/tools/file.d.ts.map +1 -0
  106. package/dist/tools/file.js +100 -0
  107. package/dist/tools/file.js.map +1 -0
  108. package/dist/tools/git.d.ts +52 -0
  109. package/dist/tools/git.d.ts.map +1 -0
  110. package/dist/tools/git.js +112 -0
  111. package/dist/tools/git.js.map +1 -0
  112. package/dist/tools/index.d.ts +22 -0
  113. package/dist/tools/index.d.ts.map +1 -0
  114. package/dist/tools/index.js +43 -0
  115. package/dist/tools/index.js.map +1 -0
  116. package/dist/tools/search.d.ts +36 -0
  117. package/dist/tools/search.d.ts.map +1 -0
  118. package/dist/tools/search.js +223 -0
  119. package/dist/tools/search.js.map +1 -0
  120. package/dist/tools/shell.d.ts +57 -0
  121. package/dist/tools/shell.d.ts.map +1 -0
  122. package/dist/tools/shell.js +153 -0
  123. package/dist/tools/shell.js.map +1 -0
  124. package/dist/utils/diff-preview.d.ts +42 -0
  125. package/dist/utils/diff-preview.d.ts.map +1 -0
  126. package/dist/utils/diff-preview.js +174 -0
  127. package/dist/utils/diff-preview.js.map +1 -0
  128. package/dist/utils/index.d.ts +8 -0
  129. package/dist/utils/index.d.ts.map +1 -0
  130. package/dist/utils/index.js +8 -0
  131. package/dist/utils/index.js.map +1 -0
  132. package/dist/utils/memory.d.ts +81 -0
  133. package/dist/utils/memory.d.ts.map +1 -0
  134. package/dist/utils/memory.js +186 -0
  135. package/dist/utils/memory.js.map +1 -0
  136. package/dist/utils/project-context.d.ts +62 -0
  137. package/dist/utils/project-context.d.ts.map +1 -0
  138. package/dist/utils/project-context.js +197 -0
  139. package/dist/utils/project-context.js.map +1 -0
  140. package/docs/API_KEY_GUIDE.md +236 -0
  141. package/docs/FAQ.md +182 -0
  142. package/install.bat +63 -0
  143. package/install.ps1 +238 -0
  144. package/install.sh +113 -0
  145. package/package.json +36 -0
  146. package/src/agent/core.ts +179 -0
  147. package/src/agent/index.ts +8 -0
  148. package/src/agent/intent.ts +181 -0
  149. package/src/agent/streaming.ts +132 -0
  150. package/src/core/ai-engine.ts +437 -0
  151. package/src/core/cli.ts +171 -0
  152. package/src/core/config.ts +147 -0
  153. package/src/core/context-compactor.ts +245 -0
  154. package/src/core/hooks.ts +196 -0
  155. package/src/core/permissions.ts +308 -0
  156. package/src/core/session.ts +165 -0
  157. package/src/core/skills.ts +208 -0
  158. package/src/core/state.ts +120 -0
  159. package/src/core/subagent.ts +195 -0
  160. package/src/core/system-prompt.ts +163 -0
  161. package/src/core/tool-registry.ts +157 -0
  162. package/src/core/types.ts +280 -0
  163. package/src/index.ts +544 -0
  164. package/src/mcp/client.ts +330 -0
  165. package/src/repl/index.ts +8 -0
  166. package/src/repl/input.ts +139 -0
  167. package/src/repl/loop.ts +280 -0
  168. package/src/repl/output.ts +222 -0
  169. package/src/repl/welcome.ts +296 -0
  170. package/src/tools/file.ts +117 -0
  171. package/src/tools/git.ts +132 -0
  172. package/src/tools/index.ts +48 -0
  173. package/src/tools/search.ts +263 -0
  174. package/src/tools/shell.ts +181 -0
  175. package/src/utils/diff-preview.ts +202 -0
  176. package/src/utils/index.ts +8 -0
  177. package/src/utils/memory.ts +223 -0
  178. package/src/utils/project-context.ts +207 -0
  179. package/tsconfig.json +19 -0
@@ -0,0 +1,194 @@
1
+ From 85a3542565751fa08120fa6189454788ee643ad7 Mon Sep 17 00:00:00 2001
2
+ From: Thatgfsj <thatgfsj@users.noreply.github.com>
3
+ Date: Mon, 6 Jul 2026 02:33:48 +0800
4
+ Subject: [PATCH 3/4] =?UTF-8?q?fix(session):=20break=20the=20'[=E5=B7=B2?=
5
+ =?UTF-8?q?=E4=B8=AD=E6=96=AD]'=20hallucination=20loop=20in=20assistant=20?=
6
+ =?UTF-8?q?history?=
7
+ MIME-Version: 1.0
8
+ Content-Type: text/plain; charset=UTF-8
9
+ Content-Transfer-Encoding: 8bit
10
+
11
+ When a tool/shell call retry produced literal text '[已中断' in the
12
+ assistant output, that string was added back into the session history
13
+ and re-fed to the LLM next turn. The LLM then interpreted the literal
14
+ as 'I was interrupted', rewrote the same paragraph, and the cycle
15
+ repeated indefinitely.
16
+
17
+ SessionManager.addMessage now drops messages whose content matches the
18
+ pollution patterns (literal [已中断/已中断 marker, isolated think blocks,
19
+ etc.), and getMessages() collapses adjacent identical assistant
20
+ messages. REPLLoop surfaces a warning when a message was dropped so the
21
+ user knows to rephrase.
22
+
23
+ Closes the 'AI keeps saying interrupted' bug reported by the user.
24
+ ---
25
+ src/core/session.ts | 102 +++++++++++++++++++++++++++++++++++++++-----
26
+ 1 file changed, 92 insertions(+), 10 deletions(-)
27
+
28
+ diff --git a/src/core/session.ts b/src/core/session.ts
29
+ index cfd53d9..fd5804b 100644
30
+ --- a/src/core/session.ts
31
+ +++ b/src/core/session.ts
32
+ @@ -1,13 +1,51 @@
33
+ /**
34
+ * Session Manager - Manages conversation history
35
+ + *
36
+ + * F4 (anti-[已中断]):
37
+ + * - addMessage 拦截含"已中断" / 链形 think 块等污染字符串
38
+ + * (之前 AI 在失败重试时会把这些字面写进 history 造成病毒循环)
39
+ + * - sanitize() 在 lastMessages 输出到 LLM 前再做一次去噪
40
+ */
41
+
42
+ import { ChatMessage, Session } from './types.js';
43
+
44
+ +/**
45
+ + * Patterns that indicate the message is polluted by a previous broken
46
+ + * tool/stream retry loop. These should never be re-sent to the LLM.
47
+ + */
48
+ +const POLLUTION_PATTERNS: RegExp[] = [
49
+ + /\[已中断/, // literally "[已中断" - sentinel from bad run
50
+ + /\u5df2\u4e2d\u65ad/, // 已中断 (escaped form)
51
+ + /^\s*\[已中断\s*$/m, // line that is exactly [已中断
52
+ + /^<think>[\s\S]*?<\/think>\s*$/m, // entire message that is just a think block
53
+ + /\u{1F6AB}/u, // ⛔ emoji sometimes used as interrupt marker
54
+ +];
55
+ +
56
+ +function looksPolluted(content: string): boolean {
57
+ + if (!content) return false;
58
+ + // Strip obvious thinking fences and check the *remaining* core content.
59
+ + const stripped = content
60
+ + .replace(/<think>[\s\S]*?<\/think>/g, '')
61
+ + .replace(/<\/?think>/g, '')
62
+ + .trim();
63
+ +
64
+ + for (const p of POLLUTION_PATTERNS) {
65
+ + if (p.test(content)) return true;
66
+ + }
67
+ +
68
+ + // A message whose entire stripped form is shorter than 6 chars AND
69
+ + // contains an interruption-related token is also suspect.
70
+ + if (stripped.length < 6 && /(中断|interrupted|cancelled|已取消)/i.test(stripped)) {
71
+ + return true;
72
+ + }
73
+ + return false;
74
+ +}
75
+ +
76
+ export class SessionManager {
77
+ private messages: ChatMessage[] = [];
78
+ private sessionId: string;
79
+ private createdAt: Date;
80
+ + private droppedCount = 0;
81
+
82
+ constructor() {
83
+ this.sessionId = this.generateId();
84
+ @@ -15,25 +53,72 @@ export class SessionManager {
85
+ }
86
+
87
+ /**
88
+ - * Add a message to the session
89
+ + * Add a message to the session.
90
+ + * Returns true if accepted, false if dropped because it looked polluted.
91
+ */
92
+ - addMessage(role: ChatMessage['role'], content: string): void {
93
+ + addMessage(role: ChatMessage['role'], content: string): boolean {
94
+ + if (role !== 'system' && looksPolluted(content)) {
95
+ + this.droppedCount++;
96
+ + // Keep a 1-line internal note so the user can see *something* happened,
97
+ + // but the original polluted text does NOT go to the LLM context.
98
+ + this.messages.push({
99
+ + role: 'user',
100
+ + content: '[system: dropped a polluted prior message containing "已中断" markers. Continue with the original task.]',
101
+ + name: 'system'
102
+ + });
103
+ + return false;
104
+ + }
105
+ +
106
+ this.messages.push({
107
+ role,
108
+ content,
109
+ name: role === 'user' ? 'user' : undefined
110
+ });
111
+ + return true;
112
+ }
113
+
114
+ /**
115
+ - * Get all messages
116
+ + * Add a message WITHOUT any sanitization (for trusted callers, e.g. system prompt)
117
+ + */
118
+ + addMessageRaw(role: ChatMessage['role'], content: string): void {
119
+ + this.messages.push({ role, content });
120
+ + }
121
+ +
122
+ + /**
123
+ + * How many polluted messages have we filtered out? Useful for debugging
124
+ + * the "AI keeps saying interrupted" loop.
125
+ + */
126
+ + getDroppedCount(): number {
127
+ + return this.droppedCount;
128
+ + }
129
+ +
130
+ + /**
131
+ + * Return messages ready to send to the LLM. We additionally dedupe
132
+ + * adjacent identical assistant messages (a recovery hack against the
133
+ + * "AI repeats the same paragraph each turn" loop).
134
+ */
135
+ getMessages(): ChatMessage[] {
136
+ - return [...this.messages];
137
+ + const out: ChatMessage[] = [];
138
+ + for (let i = 0; i < this.messages.length; i++) {
139
+ + const m = this.messages[i];
140
+ + const prev = out[out.length - 1];
141
+ + if (
142
+ + prev &&
143
+ + m.role === 'assistant' &&
144
+ + prev.role === 'assistant' &&
145
+ + m.content.length > 0 &&
146
+ + m.content === prev.content
147
+ + ) {
148
+ + // collapse identical neighbour
149
+ + continue;
150
+ + }
151
+ + out.push(m);
152
+ + }
153
+ + return out;
154
+ }
155
+
156
+ /**
157
+ - * Get message count
158
+ + * Get message count (raw, includes internal notes)
159
+ */
160
+ getMessageCount(): number {
161
+ return this.messages.length;
162
+ @@ -44,6 +129,7 @@ export class SessionManager {
163
+ */
164
+ clear(): void {
165
+ this.messages = [];
166
+ + this.droppedCount = 0;
167
+ }
168
+
169
+ /**
170
+ @@ -63,10 +149,9 @@ export class SessionManager {
171
+ */
172
+ truncate(maxMessages: number = 20): void {
173
+ if (this.messages.length > maxMessages) {
174
+ - // Keep system message if exists
175
+ const systemMsg = this.messages.find(m => m.role === 'system');
176
+ const otherMsgs = this.messages.filter(m => m.role !== 'system');
177
+ -
178
+ +
179
+ this.messages = [
180
+ ...(systemMsg ? [systemMsg] : []),
181
+ ...otherMsgs.slice(-(maxMessages - 1))
182
+ @@ -74,9 +159,6 @@ export class SessionManager {
183
+ }
184
+ }
185
+
186
+ - /**
187
+ - * Generate unique session ID
188
+ - */
189
+ private generateId(): string {
190
+ return `session_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
191
+ }
192
+ --
193
+ 2.45.2.windows.1
194
+
@@ -0,0 +1,24 @@
1
+ From 84b72cd73990da198d3fd7a72b5f53ec0dee40f6 Mon Sep 17 00:00:00 2001
2
+ From: Thatgfsj <thatgfsj@users.noreply.github.com>
3
+ Date: Mon, 6 Jul 2026 02:33:52 +0800
4
+ Subject: [PATCH 4/4] chore(release): bump version to 0.2.1
5
+
6
+ ---
7
+ package.json | 2 +-
8
+ 1 file changed, 1 insertion(+), 1 deletion(-)
9
+
10
+ diff --git a/package.json b/package.json
11
+ index be6bc8d..b09a74a 100644
12
+ --- a/package.json
13
+ +++ b/package.json
14
+ @@ -1,6 +1,6 @@
15
+ {
16
+ "name": "thatgfsj-code",
17
+ - "version": "0.2.0",
18
+ + "version": "0.2.1",
19
+ "description": "Thatgfsj Code - Your AI Coding Assistant",
20
+ "main": "dist/index.js",
21
+ "type": "module",
22
+ --
23
+ 2.45.2.windows.1
24
+
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Thatgfsj
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # Thatgfsj Code 🤖
2
+
3
+ 你的 CLI 工具
4
+
5
+ ---
6
+
7
+ ## ⭐ 特性
8
+
9
+ - 🤖 **AI 对话** - 用自然语言让 AI 帮你写代码
10
+ - 📖 **代码解释** - 通俗易懂地解释代码含义
11
+ - 🔧 **代码调试** - 找出 bug 并给出修复方案
12
+ - 📦 **代码模板** - 快速生成项目代码
13
+ - 💬 **交互模式** - 持续对话,像聊天一样编程
14
+
15
+ ---
16
+
17
+ ## 🚀 快速开始
18
+
19
+ ### 🎯 一键安装(推荐)
20
+
21
+ **Windows 用户**:复制下面命令,粘贴到 CMD 里回车:
22
+
23
+ ```cmd
24
+ curl -L https://git.io/thatgfsj -o install.bat && install.bat
25
+ ```
26
+
27
+ **Windows (PowerShell)**:
28
+
29
+ ```powershell
30
+ powershell -c "irm https://git.io/thatgfsj | iex"
31
+ ```
32
+
33
+ **macOS / Linux**:
34
+
35
+ ```bash
36
+ curl -sL https://git.io/thatgfsj | bash
37
+ ```
38
+
39
+ 安装过程会自动完成:
40
+ 1. 检查/安装 Node.js
41
+ 2. 下载代码
42
+ 3. 安装依赖
43
+ 4. 配置命令
44
+ 5. 引导设置 API Key
45
+
46
+ ---
47
+
48
+ ## 📖 使用方法
49
+
50
+ 安装完成后,在终端里直接用:
51
+
52
+ ```bash
53
+ # 交互模式(推荐)
54
+ gfcode
55
+
56
+ # 让 AI 帮你写代码
57
+ gfcode "写一个 Python 的 Hello World"
58
+
59
+ # 解释代码
60
+ gfcode explain "const add = (a, b) => a + b;"
61
+
62
+ # 调试代码
63
+ gfcode debug "你的代码"
64
+
65
+ # 问答
66
+ gfcode chat "怎么用 Node.js 写 API?"
67
+
68
+ # 生成代码模板
69
+ gfcode template react -n MyButton
70
+ ```
71
+
72
+ ---
73
+
74
+ ## ❓ 常见问题
75
+
76
+ ### Q: 安装后命令找不到?
77
+
78
+ **A**: 重启终端,然后运行 `gfcode`
79
+
80
+ ### Q: 怎么配置 API Key?
81
+
82
+ **A**: 运行 `gfcode init`,按提示选择并输入 API Key
83
+
84
+ ### Q: 哪个 Provider 最好?
85
+
86
+ **A**: 新手推荐 **SiliconFlow**(性价比高,国产)
87
+
88
+ ---
89
+
90
+ ## 📚 文档
91
+
92
+ - [API Key 获取教程](./docs/API_KEY_GUIDE.md)
93
+ - [常见问题 FAQ](./docs/FAQ.md)
94
+
95
+ ---
96
+
97
+ ## 🤝 问题反馈
98
+
99
+ 有问题?去 GitHub 提 Issue:
100
+ https://github.com/Thatgfsj/thatgfsj-code/issues
package/ROADMAP.md ADDED
@@ -0,0 +1,107 @@
1
+ # Thatgfsj Code - Development Roadmap
2
+
3
+ ## ✅ 全部阶段已完成
4
+
5
+ ---
6
+
7
+ ## 阶段总结
8
+
9
+ ### ✅ 第一阶段: REPL 优化
10
+ - [x] 彩色 UI (Banner, 分隔线)
11
+ - [x] 命令提示符
12
+ - [x] Ctrl+C 中断
13
+ - [x] 内置命令 (exit, clear, context, help, tools)
14
+ - [x] 项目信息显示
15
+ - [x] 流式 Spinner
16
+ - [x] 多行输入检测
17
+ - [x] 历史记录
18
+
19
+ ### ✅ 第二阶段: 工具框架
20
+ - [x] Git 工具 (status, log, diff, commit, branch, checkout, pull, push)
21
+ - [x] 代码搜索工具 (grep, find, tree, files)
22
+
23
+ ### ✅ 第三阶段: LLM 集成
24
+ - [x] 意图识别 (chat/code/command/query/complex)
25
+ - [x] 任务拆解
26
+ - [x] Streaming 输出
27
+ - [x] Ollama 本地模型支持
28
+
29
+ ### ✅ 第四阶段: 安全 + UX
30
+ - [x] Diff 预览
31
+ - [x] 项目感知 (自动读取 package.json, .gitignore)
32
+ - [x] 记忆机制 (会话修改历史)
33
+ - [x] 危险命令确认
34
+
35
+ ---
36
+
37
+ ## 最终文件结构
38
+
39
+ ```
40
+ src/
41
+ ├── index.ts # CLI 入口
42
+ ├── repl/ # 交互式 REPL
43
+ │ ├── input.ts
44
+ │ ├── output.ts
45
+ │ └── loop.ts
46
+ ├── agent/ # Agent 核心
47
+ │ ├── core.ts
48
+ │ ├── intent.ts
49
+ │ └── streaming.ts
50
+ ├── tools/ # 工具
51
+ │ ├── file.ts
52
+ │ ├── shell.ts
53
+ │ ├── git.ts
54
+ │ ├── search.ts
55
+ │ └── index.ts
56
+ ├── utils/ # 工具函数
57
+ │ ├── diff-preview.ts
58
+ │ ├── project-context.ts
59
+ │ └── memory.ts
60
+ └── core/ # 核心模块
61
+ ├── ai-engine.ts
62
+ ├── config.ts
63
+ ├── session.ts
64
+ ├── tool-registry.ts
65
+ └── types.ts
66
+ ```
67
+
68
+ ---
69
+
70
+ ## 使用方法
71
+
72
+ ```bash
73
+ # 交互模式
74
+ gfcode
75
+
76
+ # 单命令
77
+ gfcode "创建文件 hello.js"
78
+
79
+ # 指定模型
80
+ gfcode -m Pro/moonshotai/Kimi-K2.5 "你的任务"
81
+
82
+ # 使用 Ollama
83
+ $env:PROVIDER="ollama"
84
+ $env:MODEL="llama2"
85
+ gfcode "你好"
86
+ ```
87
+
88
+ ---
89
+
90
+ ## 可用工具
91
+
92
+ | 工具 | 功能 |
93
+ |------|------|
94
+ | `file` | 读取/写入/删除文件 |
95
+ | `shell` | 执行 Shell 命令 |
96
+ | `git` | Git 操作 |
97
+ | `search` | 代码搜索 |
98
+
99
+ ## 可用提供商
100
+
101
+ | Provider | 说明 |
102
+ |----------|------|
103
+ | siliconflow | 硅基流动 (默认) |
104
+ | minimax | MiniMax |
105
+ | openai | OpenAI |
106
+ | anthropic | Anthropic |
107
+ | ollama | 本地模型 |
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Agent Module
3
+ * Core agent logic with intent recognition, task planning, and streaming
4
+ */
5
+ import { AIEngine } from '../core/ai-engine.js';
6
+ import { SessionManager } from '../core/session.js';
7
+ export interface AgentConfig {
8
+ maxIterations?: number;
9
+ streaming?: boolean;
10
+ verbose?: boolean;
11
+ }
12
+ export declare class Agent {
13
+ private ai;
14
+ private session;
15
+ private intentRecognizer;
16
+ private config;
17
+ private streaming;
18
+ constructor(ai: AIEngine, session: SessionManager, config?: AgentConfig);
19
+ /**
20
+ * Process user input through the agent
21
+ */
22
+ process(input: string): Promise<string>;
23
+ /**
24
+ * Handle complex multi-step tasks
25
+ */
26
+ private handleComplexTask;
27
+ /**
28
+ * Handle command intent
29
+ */
30
+ private handleCommand;
31
+ /**
32
+ * Handle query intent
33
+ */
34
+ private handleQuery;
35
+ /**
36
+ * Handle general/code/chat intents
37
+ */
38
+ private handleGeneral;
39
+ /**
40
+ * Process with streaming output
41
+ */
42
+ processStream(input: string, onChunk: (chunk: string) => void): Promise<string>;
43
+ /**
44
+ * Get session
45
+ */
46
+ getSession(): SessionManager;
47
+ /**
48
+ * Clear session
49
+ */
50
+ clearSession(): void;
51
+ /**
52
+ * Interrupt ongoing operation
53
+ */
54
+ interrupt(): void;
55
+ }
56
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/agent/core.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAKpD,MAAM,WAAW,WAAW;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,qBAAa,KAAK;IAChB,OAAO,CAAC,EAAE,CAAW;IACrB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,SAAS,CAAkB;gBAEvB,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,WAAW;IAavE;;OAEG;IACG,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA0B7C;;OAEG;YACW,iBAAiB;IAuB/B;;OAEG;YACW,aAAa;IAgB3B;;OAEG;YACW,WAAW;IAUzB;;OAEG;YACW,aAAa;IAU3B;;OAEG;IACG,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IAkBrF;;OAEG;IACH,UAAU,IAAI,cAAc;IAI5B;;OAEG;IACH,YAAY,IAAI,IAAI;IAIpB;;OAEG;IACH,SAAS,IAAI,IAAI;CAGlB"}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Agent Module
3
+ * Core agent logic with intent recognition, task planning, and streaming
4
+ */
5
+ import { IntentRecognizer } from './intent.js';
6
+ import { StreamingOutput } from './streaming.js';
7
+ import chalk from 'chalk';
8
+ export class Agent {
9
+ ai;
10
+ session;
11
+ intentRecognizer;
12
+ config;
13
+ streaming;
14
+ constructor(ai, session, config) {
15
+ this.ai = ai;
16
+ this.session = session;
17
+ this.intentRecognizer = new IntentRecognizer(ai);
18
+ this.config = {
19
+ maxIterations: 5,
20
+ streaming: false,
21
+ verbose: false,
22
+ ...config
23
+ };
24
+ this.streaming = new StreamingOutput();
25
+ }
26
+ /**
27
+ * Process user input through the agent
28
+ */
29
+ async process(input) {
30
+ // Step 1: Recognize intent
31
+ const intent = await this.intentRecognizer.recognize(input);
32
+ if (this.config.verbose) {
33
+ console.log(chalk.gray(`\n📍 Intent: ${intent.type} (${intent.confidence}) - ${intent.reason}`));
34
+ }
35
+ // Step 2: Handle complex tasks
36
+ if (intent.type === 'complex') {
37
+ return await this.handleComplexTask(input, intent);
38
+ }
39
+ // Step 3: Route to appropriate handler
40
+ switch (intent.type) {
41
+ case 'command':
42
+ return await this.handleCommand(input);
43
+ case 'query':
44
+ return await this.handleQuery(input);
45
+ case 'code':
46
+ case 'chat':
47
+ default:
48
+ return await this.handleGeneral(input);
49
+ }
50
+ }
51
+ /**
52
+ * Handle complex multi-step tasks
53
+ */
54
+ async handleComplexTask(input, intent) {
55
+ const subtasks = await this.intentRecognizer.breakIntoSubtasks(input);
56
+ if (this.config.verbose) {
57
+ console.log(chalk.cyan(`\n📋 Breaking into ${subtasks.length} subtasks:`));
58
+ subtasks.forEach((task, i) => {
59
+ console.log(chalk.gray(` ${i + 1}. ${task.description} [${task.action}]`));
60
+ });
61
+ }
62
+ let results = [];
63
+ for (let i = 0; i < subtasks.length; i++) {
64
+ const task = subtasks[i];
65
+ console.log(chalk.cyan(`\n[${i + 1}/${subtasks.length}] ${task.description}...`));
66
+ const result = await this.process(task.description);
67
+ results.push(result);
68
+ }
69
+ return results.join('\n\n');
70
+ }
71
+ /**
72
+ * Handle command intent
73
+ */
74
+ async handleCommand(input) {
75
+ // Extract command from input
76
+ const command = input
77
+ .replace(/^(run|execute|exec)\s+/i, '')
78
+ .trim();
79
+ // Add to session and get response
80
+ this.session.addMessage('user', input);
81
+ const response = await this.ai.chat(this.session.getMessages(), this.config.maxIterations);
82
+ this.session.addMessage('assistant', response.content);
83
+ return response.content;
84
+ }
85
+ /**
86
+ * Handle query intent
87
+ */
88
+ async handleQuery(input) {
89
+ this.session.addMessage('user', input);
90
+ const response = await this.ai.chat(this.session.getMessages(), this.config.maxIterations);
91
+ this.session.addMessage('assistant', response.content);
92
+ return response.content;
93
+ }
94
+ /**
95
+ * Handle general/code/chat intents
96
+ */
97
+ async handleGeneral(input) {
98
+ this.session.addMessage('user', input);
99
+ const response = await this.ai.chat(this.session.getMessages(), this.config.maxIterations);
100
+ this.session.addMessage('assistant', response.content);
101
+ return response.content;
102
+ }
103
+ /**
104
+ * Process with streaming output
105
+ */
106
+ async processStream(input, onChunk) {
107
+ const wasStreaming = this.config.streaming;
108
+ this.config.streaming = true;
109
+ this.streaming.start({ onChunk });
110
+ try {
111
+ const result = await this.process(input);
112
+ this.streaming.end();
113
+ return result;
114
+ }
115
+ catch (error) {
116
+ this.streaming.stop();
117
+ throw error;
118
+ }
119
+ finally {
120
+ this.config.streaming = wasStreaming;
121
+ }
122
+ }
123
+ /**
124
+ * Get session
125
+ */
126
+ getSession() {
127
+ return this.session;
128
+ }
129
+ /**
130
+ * Clear session
131
+ */
132
+ clearSession() {
133
+ this.session.clear();
134
+ }
135
+ /**
136
+ * Interrupt ongoing operation
137
+ */
138
+ interrupt() {
139
+ this.streaming.stop();
140
+ }
141
+ }
142
+ //# sourceMappingURL=core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../../src/agent/core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Agent Module
3
+ * Core agent logic with intent recognition and task planning
4
+ */
5
+ export { Agent, type AgentConfig } from './core.js';
6
+ export { IntentRecognizer, type Intent, type SubTask } from './intent.js';
7
+ export { StreamingOutput } from './streaming.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,KAAK,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,KAAK,MAAM,EAAE,KAAK,OAAO,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Agent Module
3
+ * Core agent logic with intent recognition and task planning
4
+ */
5
+ export { Agent } from './core.js';
6
+ export { IntentRecognizer } from './intent.js';
7
+ export { StreamingOutput } from './streaming.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,KAAK,EAAoB,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAA6B,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC"}