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.
Files changed (262) hide show
  1. package/CHANGELOG.md +229 -0
  2. package/DEVELOPMENT.md +286 -0
  3. package/README.md +144 -79
  4. package/dist/agent/core.d.ts +56 -0
  5. package/dist/agent/core.d.ts.map +1 -0
  6. package/dist/agent/core.js +142 -0
  7. package/dist/agent/core.js.map +1 -0
  8. package/dist/agent/index.d.ts +8 -0
  9. package/dist/agent/index.d.ts.map +1 -0
  10. package/dist/agent/index.js +8 -0
  11. package/dist/agent/index.js.map +1 -0
  12. package/dist/agent/intent.d.ts +36 -0
  13. package/dist/agent/intent.d.ts.map +1 -0
  14. package/dist/agent/intent.js +146 -0
  15. package/dist/agent/intent.js.map +1 -0
  16. package/dist/agent/streaming.d.ts +50 -0
  17. package/dist/agent/streaming.d.ts.map +1 -0
  18. package/dist/agent/streaming.js +110 -0
  19. package/dist/agent/streaming.js.map +1 -0
  20. package/dist/core/ai-engine.d.ts +76 -0
  21. package/dist/core/ai-engine.d.ts.map +1 -0
  22. package/dist/core/ai-engine.js +394 -0
  23. package/dist/core/ai-engine.js.map +1 -0
  24. package/dist/core/cli.d.ts +21 -0
  25. package/dist/core/cli.d.ts.map +1 -0
  26. package/dist/core/cli.js +143 -0
  27. package/dist/core/cli.js.map +1 -0
  28. package/dist/core/config.d.ts +55 -0
  29. package/dist/core/config.d.ts.map +1 -0
  30. package/dist/core/config.js +162 -0
  31. package/dist/core/config.js.map +1 -0
  32. package/dist/core/context-compactor.d.ts +54 -0
  33. package/dist/core/context-compactor.d.ts.map +1 -0
  34. package/dist/core/context-compactor.js +197 -0
  35. package/dist/core/context-compactor.js.map +1 -0
  36. package/dist/core/hooks.d.ts +75 -0
  37. package/dist/core/hooks.d.ts.map +1 -0
  38. package/dist/core/hooks.js +146 -0
  39. package/dist/core/hooks.js.map +1 -0
  40. package/dist/core/permissions.d.ts +52 -0
  41. package/dist/core/permissions.d.ts.map +1 -0
  42. package/dist/core/permissions.js +237 -0
  43. package/dist/core/permissions.js.map +1 -0
  44. package/dist/core/session.d.ts +54 -0
  45. package/dist/core/session.d.ts.map +1 -0
  46. package/dist/core/session.js +147 -0
  47. package/dist/core/session.js.map +1 -0
  48. package/dist/core/skills.d.ts +60 -0
  49. package/dist/core/skills.d.ts.map +1 -0
  50. package/dist/core/skills.js +175 -0
  51. package/dist/core/skills.js.map +1 -0
  52. package/dist/core/state.d.ts +60 -0
  53. package/dist/core/state.d.ts.map +1 -0
  54. package/dist/core/state.js +106 -0
  55. package/dist/core/state.js.map +1 -0
  56. package/dist/core/subagent.d.ts +68 -0
  57. package/dist/core/subagent.d.ts.map +1 -0
  58. package/dist/core/subagent.js +142 -0
  59. package/dist/core/subagent.js.map +1 -0
  60. package/dist/core/system-prompt.d.ts +40 -0
  61. package/dist/core/system-prompt.d.ts.map +1 -0
  62. package/dist/core/system-prompt.js +138 -0
  63. package/dist/core/system-prompt.js.map +1 -0
  64. package/dist/core/tool-registry.d.ts +53 -0
  65. package/dist/core/tool-registry.d.ts.map +1 -0
  66. package/dist/core/tool-registry.js +138 -0
  67. package/dist/core/tool-registry.js.map +1 -0
  68. package/dist/core/types.d.ts +206 -0
  69. package/dist/core/types.d.ts.map +1 -0
  70. package/dist/core/types.js +127 -0
  71. package/dist/core/types.js.map +1 -0
  72. package/dist/index.d.ts +7 -0
  73. package/dist/{cmd/index.d.ts.map → index.d.ts.map} +1 -1
  74. package/dist/index.js +472 -0
  75. package/dist/index.js.map +1 -0
  76. package/dist/mcp/client.d.ts +1 -1
  77. package/dist/mcp/client.d.ts.map +1 -1
  78. package/dist/repl/index.d.ts +8 -0
  79. package/dist/repl/index.d.ts.map +1 -0
  80. package/dist/repl/index.js +8 -0
  81. package/dist/repl/index.js.map +1 -0
  82. package/dist/repl/input.d.ts +69 -0
  83. package/dist/repl/input.d.ts.map +1 -0
  84. package/dist/repl/input.js +139 -0
  85. package/dist/repl/input.js.map +1 -0
  86. package/dist/repl/loop.d.ts +184 -0
  87. package/dist/repl/loop.d.ts.map +1 -0
  88. package/dist/repl/loop.js +932 -0
  89. package/dist/repl/loop.js.map +1 -0
  90. package/dist/repl/output.d.ts +105 -0
  91. package/dist/repl/output.d.ts.map +1 -0
  92. package/dist/repl/output.js +199 -0
  93. package/dist/repl/output.js.map +1 -0
  94. package/dist/repl/welcome.d.ts +68 -0
  95. package/dist/repl/welcome.d.ts.map +1 -0
  96. package/dist/repl/welcome.js +254 -0
  97. package/dist/repl/welcome.js.map +1 -0
  98. package/dist/tools/file.d.ts +1 -1
  99. package/dist/tools/file.d.ts.map +1 -1
  100. package/dist/tools/git.d.ts +1 -1
  101. package/dist/tools/git.d.ts.map +1 -1
  102. package/dist/tools/index.d.ts +15 -35
  103. package/dist/tools/index.d.ts.map +1 -1
  104. package/dist/tools/index.js +31 -80
  105. package/dist/tools/index.js.map +1 -1
  106. package/dist/tools/search.d.ts +1 -1
  107. package/dist/tools/search.d.ts.map +1 -1
  108. package/dist/tools/shell.d.ts +11 -4
  109. package/dist/tools/shell.d.ts.map +1 -1
  110. package/dist/tools/shell.js +78 -42
  111. package/dist/tools/shell.js.map +1 -1
  112. package/dist/utils/diff-preview.d.ts +42 -0
  113. package/dist/utils/diff-preview.d.ts.map +1 -0
  114. package/dist/utils/diff-preview.js +174 -0
  115. package/dist/utils/diff-preview.js.map +1 -0
  116. package/dist/utils/index.d.ts +8 -0
  117. package/dist/utils/index.d.ts.map +1 -0
  118. package/dist/utils/index.js +8 -0
  119. package/dist/utils/index.js.map +1 -0
  120. package/dist/utils/memory.d.ts +81 -0
  121. package/dist/utils/memory.d.ts.map +1 -0
  122. package/dist/utils/memory.js +186 -0
  123. package/dist/utils/memory.js.map +1 -0
  124. package/dist/utils/project-context.d.ts +62 -0
  125. package/dist/utils/project-context.d.ts.map +1 -0
  126. package/dist/utils/project-context.js +197 -0
  127. package/dist/utils/project-context.js.map +1 -0
  128. package/docs/API_KEY_GUIDE.md +6 -0
  129. package/docs/FAQ.md +25 -3
  130. package/package.json +41 -9
  131. package/ROADMAP.md +0 -61
  132. package/dist/app/agent.d.ts +0 -31
  133. package/dist/app/agent.d.ts.map +0 -1
  134. package/dist/app/agent.js +0 -106
  135. package/dist/app/agent.js.map +0 -1
  136. package/dist/app/index.d.ts +0 -39
  137. package/dist/app/index.d.ts.map +0 -1
  138. package/dist/app/index.js +0 -80
  139. package/dist/app/index.js.map +0 -1
  140. package/dist/cmd/index.d.ts +0 -12
  141. package/dist/cmd/index.js +0 -85
  142. package/dist/cmd/index.js.map +0 -1
  143. package/dist/config/index.d.ts +0 -39
  144. package/dist/config/index.d.ts.map +0 -1
  145. package/dist/config/index.js +0 -110
  146. package/dist/config/index.js.map +0 -1
  147. package/dist/config/providers.d.ts +0 -23
  148. package/dist/config/providers.d.ts.map +0 -1
  149. package/dist/config/providers.js +0 -152
  150. package/dist/config/providers.js.map +0 -1
  151. package/dist/config/types.d.ts +0 -33
  152. package/dist/config/types.d.ts.map +0 -1
  153. package/dist/config/types.js +0 -5
  154. package/dist/config/types.js.map +0 -1
  155. package/dist/hooks/index.d.ts +0 -31
  156. package/dist/hooks/index.d.ts.map +0 -1
  157. package/dist/hooks/index.js +0 -71
  158. package/dist/hooks/index.js.map +0 -1
  159. package/dist/llm/anthropic.d.ts +0 -17
  160. package/dist/llm/anthropic.d.ts.map +0 -1
  161. package/dist/llm/anthropic.js +0 -126
  162. package/dist/llm/anthropic.js.map +0 -1
  163. package/dist/llm/gemini.d.ts +0 -16
  164. package/dist/llm/gemini.d.ts.map +0 -1
  165. package/dist/llm/gemini.js +0 -107
  166. package/dist/llm/gemini.js.map +0 -1
  167. package/dist/llm/index.d.ts +0 -48
  168. package/dist/llm/index.d.ts.map +0 -1
  169. package/dist/llm/index.js +0 -174
  170. package/dist/llm/index.js.map +0 -1
  171. package/dist/llm/openai.d.ts +0 -17
  172. package/dist/llm/openai.d.ts.map +0 -1
  173. package/dist/llm/openai.js +0 -113
  174. package/dist/llm/openai.js.map +0 -1
  175. package/dist/llm/provider.d.ts +0 -33
  176. package/dist/llm/provider.d.ts.map +0 -1
  177. package/dist/llm/provider.js +0 -6
  178. package/dist/llm/provider.js.map +0 -1
  179. package/dist/prompts/index.d.ts +0 -27
  180. package/dist/prompts/index.d.ts.map +0 -1
  181. package/dist/prompts/index.js +0 -102
  182. package/dist/prompts/index.js.map +0 -1
  183. package/dist/session/compactor.d.ts +0 -48
  184. package/dist/session/compactor.d.ts.map +0 -1
  185. package/dist/session/compactor.js +0 -77
  186. package/dist/session/compactor.js.map +0 -1
  187. package/dist/session/index.d.ts +0 -48
  188. package/dist/session/index.d.ts.map +0 -1
  189. package/dist/session/index.js +0 -69
  190. package/dist/session/index.js.map +0 -1
  191. package/dist/session/message.d.ts +0 -26
  192. package/dist/session/message.d.ts.map +0 -1
  193. package/dist/session/message.js +0 -34
  194. package/dist/session/message.js.map +0 -1
  195. package/dist/tools/types.d.ts +0 -68
  196. package/dist/tools/types.d.ts.map +0 -1
  197. package/dist/tools/types.js +0 -57
  198. package/dist/tools/types.js.map +0 -1
  199. package/dist/tui/index.d.ts +0 -8
  200. package/dist/tui/index.d.ts.map +0 -1
  201. package/dist/tui/index.js +0 -8
  202. package/dist/tui/index.js.map +0 -1
  203. package/dist/tui/input.d.ts +0 -14
  204. package/dist/tui/input.d.ts.map +0 -1
  205. package/dist/tui/input.js +0 -50
  206. package/dist/tui/input.js.map +0 -1
  207. package/dist/tui/output.d.ts +0 -20
  208. package/dist/tui/output.d.ts.map +0 -1
  209. package/dist/tui/output.js +0 -70
  210. package/dist/tui/output.js.map +0 -1
  211. package/dist/tui/repl.d.ts +0 -25
  212. package/dist/tui/repl.d.ts.map +0 -1
  213. package/dist/tui/repl.js +0 -114
  214. package/dist/tui/repl.js.map +0 -1
  215. package/dist/tui/welcome.d.ts +0 -15
  216. package/dist/tui/welcome.d.ts.map +0 -1
  217. package/dist/tui/welcome.js +0 -86
  218. package/dist/tui/welcome.js.map +0 -1
  219. package/dist/types.d.ts +0 -38
  220. package/dist/types.d.ts.map +0 -1
  221. package/dist/types.js +0 -6
  222. package/dist/types.js.map +0 -1
  223. package/dist/utils/diff.d.ts +0 -22
  224. package/dist/utils/diff.d.ts.map +0 -1
  225. package/dist/utils/diff.js +0 -60
  226. package/dist/utils/diff.js.map +0 -1
  227. package/dist/utils/project.d.ts +0 -32
  228. package/dist/utils/project.d.ts.map +0 -1
  229. package/dist/utils/project.js +0 -89
  230. package/dist/utils/project.js.map +0 -1
  231. package/src/app/agent.ts +0 -140
  232. package/src/app/index.ts +0 -101
  233. package/src/cmd/index.ts +0 -96
  234. package/src/config/index.ts +0 -130
  235. package/src/config/providers.ts +0 -160
  236. package/src/config/types.ts +0 -46
  237. package/src/hooks/index.ts +0 -111
  238. package/src/llm/anthropic.ts +0 -146
  239. package/src/llm/gemini.ts +0 -127
  240. package/src/llm/index.ts +0 -209
  241. package/src/llm/openai.ts +0 -132
  242. package/src/llm/provider.ts +0 -38
  243. package/src/mcp/client.ts +0 -330
  244. package/src/prompts/index.ts +0 -123
  245. package/src/session/compactor.ts +0 -103
  246. package/src/session/index.ts +0 -81
  247. package/src/session/message.ts +0 -42
  248. package/src/tools/file.ts +0 -117
  249. package/src/tools/git.ts +0 -132
  250. package/src/tools/index.ts +0 -108
  251. package/src/tools/search.ts +0 -263
  252. package/src/tools/shell.ts +0 -136
  253. package/src/tools/types.ts +0 -122
  254. package/src/tui/index.ts +0 -8
  255. package/src/tui/input.ts +0 -56
  256. package/src/tui/output.ts +0 -83
  257. package/src/tui/repl.ts +0 -131
  258. package/src/tui/welcome.ts +0 -101
  259. package/src/types.ts +0 -42
  260. package/src/utils/diff.ts +0 -71
  261. package/src/utils/project.ts +0 -99
  262. package/tsconfig.json +0 -19
package/src/mcp/client.ts DELETED
@@ -1,330 +0,0 @@
1
- /**
2
- * S07: MCP Client (Model Context Protocol)
3
- * Connect to MCP servers and expose their tools as agent tools
4
- *
5
- * MCP turns the agent from a closed system into an open platform.
6
- * Any server can expose tools via the MCP JSON-RPC 2.0 protocol.
7
- */
8
-
9
- import { spawn, ChildProcess } from 'child_process';
10
- import type { Tool, ToolResult } from '../tools/types.js';
11
-
12
- // ==================== MCP Types ====================
13
-
14
- interface MCPJsonRPCRequest {
15
- jsonrpc: '2.0';
16
- id: number | string;
17
- method: string;
18
- params?: any;
19
- }
20
-
21
- interface MCPJsonRPCResponse {
22
- jsonrpc: '2.0';
23
- id: number | string;
24
- result?: any;
25
- error?: { code: number; message: string; data?: any };
26
- }
27
-
28
- interface MCPTool {
29
- name: string;
30
- description: string;
31
- inputSchema: {
32
- type: 'object';
33
- properties: Record<string, any>;
34
- required?: string[];
35
- };
36
- }
37
-
38
- // ==================== MCP Client ====================
39
-
40
- export class MCPClient {
41
- private process: ChildProcess | null = null;
42
- private tools: Map<string, MCPTool> = new Map();
43
- private requestId = 0;
44
- private pendingRequests: Map<number | string, {
45
- resolve: (value: any) => void;
46
- reject: (reason: any) => void;
47
- }> = new Map();
48
- private name: string;
49
- private connected = false;
50
-
51
- constructor(name: string) {
52
- this.name = name;
53
- }
54
-
55
- /**
56
- * S07: Connect to an MCP server
57
- * @param command Command to run (e.g., 'npx', 'node')
58
- * @param args Arguments (e.g., ['-y', '@modelcontextprotocol/server-filesystem', '/path/to/dir'])
59
- */
60
- async connect(command: string, args: string[]): Promise<void> {
61
- return new Promise((resolve, reject) => {
62
- this.process = spawn(command, args, {
63
- stdio: ['pipe', 'pipe', 'pipe']
64
- });
65
-
66
- let buffer = '';
67
-
68
- this.process.stdout?.on('data', (data: Buffer) => {
69
- buffer += data.toString();
70
- const lines = buffer.split('\n');
71
- buffer = lines.pop() || '';
72
-
73
- for (const line of lines) {
74
- if (line.trim()) {
75
- this.handleMessage(line);
76
- }
77
- }
78
- });
79
-
80
- this.process.stderr?.on('data', (data: Buffer) => {
81
- console.error(`[MCP ${this.name}] stderr:`, data.toString().trim());
82
- });
83
-
84
- this.process.on('error', (err) => {
85
- reject(err);
86
- });
87
-
88
- this.process.on('close', (code) => {
89
- this.connected = false;
90
- console.log(`[MCP ${this.name}] exited with code ${code}`);
91
- });
92
-
93
- // Initialize MCP connection
94
- this.sendRequest('initialize', {
95
- protocolVersion: '2024-11-05',
96
- capabilities: { tools: {} },
97
- clientInfo: { name: 'thatgfsj-code', version: '1.0.0' }
98
- }).then(() => {
99
- this.connected = true;
100
- // Send initialized notification
101
- this.sendNotification('initialized', {});
102
- // List available tools
103
- return this.listTools();
104
- }).then(() => {
105
- resolve();
106
- }).catch(reject);
107
-
108
- // Timeout
109
- setTimeout(() => reject(new Error('MCP connection timeout')), 30000);
110
- });
111
- }
112
-
113
- /**
114
- * S07: Handle incoming JSON-RPC message
115
- */
116
- private handleMessage(raw: string): void {
117
- try {
118
- const msg: MCPJsonRPCResponse = JSON.parse(raw);
119
-
120
- // Handle response
121
- const pending = this.pendingRequests.get(msg.id);
122
- if (pending) {
123
- this.pendingRequests.delete(msg.id);
124
- if (msg.error) {
125
- pending.reject(new Error(msg.error.message));
126
- } else {
127
- pending.resolve(msg.result);
128
- }
129
- return;
130
- }
131
- } catch {
132
- // Not JSON, ignore
133
- }
134
- }
135
-
136
- /**
137
- * S07: Send a JSON-RPC request
138
- */
139
- private sendRequest(method: string, params: any): Promise<any> {
140
- return new Promise((resolve, reject) => {
141
- if (!this.process?.connected) {
142
- reject(new Error('MCP process not connected'));
143
- return;
144
- }
145
-
146
- const id = ++this.requestId;
147
- this.pendingRequests.set(id, { resolve, reject });
148
-
149
- const request: MCPJsonRPCRequest = {
150
- jsonrpc: '2.0',
151
- id,
152
- method,
153
- params
154
- };
155
-
156
- this.process.stdin?.write(JSON.stringify(request) + '\n');
157
-
158
- // Timeout
159
- setTimeout(() => {
160
- if (this.pendingRequests.has(id)) {
161
- this.pendingRequests.delete(id);
162
- reject(new Error('MCP request timeout: ' + method));
163
- }
164
- }, 30000);
165
- });
166
- }
167
-
168
- /**
169
- * S07: Send a notification (no response expected)
170
- */
171
- private sendNotification(method: string, params: any): void {
172
- if (!this.process?.connected) return;
173
-
174
- const notification = {
175
- jsonrpc: '2.0',
176
- method,
177
- params
178
- };
179
-
180
- this.process.stdin?.write(JSON.stringify(notification) + '\n');
181
- }
182
-
183
- /**
184
- * S07: Call an MCP tool
185
- */
186
- async callTool(name: string, arguments_: Record<string, any>): Promise<ToolResult> {
187
- try {
188
- const result = await this.sendRequest('tools/call', {
189
- name,
190
- arguments: arguments_
191
- });
192
-
193
- return {
194
- success: true,
195
- output: typeof result === 'string' ? result : JSON.stringify(result)
196
- };
197
- } catch (error: any) {
198
- return {
199
- success: false,
200
- error: error.message
201
- };
202
- }
203
- }
204
-
205
- /**
206
- * S07: List tools from MCP server
207
- */
208
- private async listTools(): Promise<void> {
209
- try {
210
- const result = await this.sendRequest('tools/list', {});
211
- const tools: MCPTool[] = result.tools || [];
212
-
213
- this.tools.clear();
214
- for (const tool of tools) {
215
- this.tools.set(tool.name, tool);
216
- }
217
-
218
- console.log(`[MCP ${this.name}] Loaded ${tools.length} tools:`, [...this.tools.keys()].join(', '));
219
- } catch (error: any) {
220
- console.error(`[MCP ${this.name}] Failed to list tools:`, error.message);
221
- }
222
- }
223
-
224
- /**
225
- * S07: Get registered tools as agent Tool[]
226
- */
227
- getTools(): Tool[] {
228
- return [...this.tools.values()].map(mcpTool => ({
229
- name: this.name + ':' + mcpTool.name,
230
- description: mcpTool.description,
231
- parameters: Object.entries(mcpTool.inputSchema.properties || {}).map(([name, schema]: [string, any]) => ({
232
- name,
233
- type: schema.type || 'string',
234
- description: schema.description || '',
235
- required: (mcpTool.inputSchema.required || []).includes(name)
236
- })),
237
- execute: async (params: Record<string, any>): Promise<ToolResult> => {
238
- return this.callTool(mcpTool.name, params);
239
- }
240
- }));
241
- }
242
-
243
- /**
244
- * S07: Get tool names
245
- */
246
- getToolNames(): string[] {
247
- return [...this.tools.keys()];
248
- }
249
-
250
- /**
251
- * S07: Check if connected
252
- */
253
- isConnected(): boolean {
254
- return this.connected;
255
- }
256
-
257
- /**
258
- * S07: Disconnect from MCP server
259
- */
260
- disconnect(): void {
261
- if (this.process) {
262
- this.process.kill();
263
- this.process = null;
264
- }
265
- this.connected = false;
266
- this.tools.clear();
267
- this.pendingRequests.clear();
268
- }
269
- }
270
-
271
- // ==================== MCP Server Manager ====================
272
-
273
- export class MCPServerManager {
274
- private clients: Map<string, MCPClient> = new Map();
275
-
276
- /**
277
- * S07: Add and connect an MCP server
278
- */
279
- async addServer(name: string, command: string, args: string[]): Promise<void> {
280
- const client = new MCPClient(name);
281
- await client.connect(command, args);
282
- this.clients.set(name, client);
283
- }
284
-
285
- /**
286
- * S07: Get all tools from all servers
287
- */
288
- getAllTools(): Tool[] {
289
- const allTools: Tool[] = [];
290
- for (const client of this.clients.values()) {
291
- allTools.push(...client.getTools());
292
- }
293
- return allTools;
294
- }
295
-
296
- /**
297
- * S07: Get tool names from all servers
298
- */
299
- getAllToolNames(): string[] {
300
- const names: string[] = [];
301
- for (const [serverName, client] of this.clients) {
302
- for (const toolName of client.getToolNames()) {
303
- names.push(serverName + ':' + toolName);
304
- }
305
- }
306
- return names;
307
- }
308
-
309
- /**
310
- * S07: Disconnect a server
311
- */
312
- removeServer(name: string): void {
313
- const client = this.clients.get(name);
314
- if (client) {
315
- client.disconnect();
316
- this.clients.delete(name);
317
- }
318
- }
319
-
320
- /**
321
- * S07: Get server status
322
- */
323
- getStatus(): Record<string, boolean> {
324
- const status: Record<string, boolean> = {};
325
- for (const [name, client] of this.clients) {
326
- status[name] = client.isConnected();
327
- }
328
- return status;
329
- }
330
- }
@@ -1,123 +0,0 @@
1
- /**
2
- * System Prompt Builder - Dynamic prompt construction
3
- * Migrated from old src/core/system-prompt.ts
4
- */
5
-
6
- import { readFileSync, existsSync } from 'fs';
7
- import { join } from 'path';
8
- import type { Tool } from '../tools/types.js';
9
-
10
- export interface SystemPromptConfig {
11
- cwd?: string;
12
- tools?: Tool[];
13
- includeProjectMd?: boolean;
14
- permissionMode?: 'accept' | 'deny' | 'ask';
15
- date?: Date;
16
- }
17
-
18
- export class SystemPromptBuilder {
19
- private config: Required<SystemPromptConfig>;
20
-
21
- constructor(config: SystemPromptConfig = {}) {
22
- this.config = {
23
- cwd: config.cwd ?? process.cwd(),
24
- tools: config.tools ?? [],
25
- includeProjectMd: config.includeProjectMd ?? true,
26
- permissionMode: config.permissionMode ?? 'ask',
27
- date: config.date ?? new Date(),
28
- };
29
- }
30
-
31
- build(): string {
32
- const fragments: string[] = [
33
- this.buildIdentity(),
34
- this.buildToolInstructions(),
35
- this.buildEnvironment(),
36
- this.buildPermissionMode(),
37
- this.buildProjectInstructions(),
38
- this.buildDateInfo(),
39
- ];
40
- return fragments.filter(Boolean).join('\n\n');
41
- }
42
-
43
- private buildIdentity(): string {
44
- return [
45
- 'You are Thatgfsj Code, an interactive coding agent running in the user\'s terminal.',
46
- '',
47
- 'You have access to tools (file operations, shell commands, git, search) that let you',
48
- 'read, write, and modify files and run commands to help with coding tasks.',
49
- '',
50
- 'When working on a task:',
51
- '1. First understand what files are involved',
52
- '2. Read necessary files to understand the codebase',
53
- '3. Make changes using appropriate tools',
54
- '4. Verify the changes work',
55
- '',
56
- 'Be concise but thorough. Show your reasoning.',
57
- '',
58
- 'When using tools:',
59
- '- Prefer small, targeted operations over large batch changes',
60
- '- Confirm destructive operations (rm, git push --force, etc.)',
61
- '- Explain what you are going to do before doing it',
62
- ].join('\n');
63
- }
64
-
65
- private buildToolInstructions(): string {
66
- const tools = this.config.tools;
67
- if (tools.length === 0) {
68
- return '## Tools\n\nNo tools are currently registered.';
69
- }
70
-
71
- const toolDescs = tools.map(t => {
72
- const params = t.parameters
73
- .map(p => ` - ${p.name} (${p.type}${p.required ? ', required' : ''}): ${p.description}`)
74
- .join('\n');
75
- return `### ${t.name}\n${t.description}\n\nParameters:\n${params}`;
76
- }).join('\n\n');
77
-
78
- return `## Tools\n\nYou have access to the following tools:\n\n${toolDescs}\n\nTo use a tool, respond with a tool call. Each tool call must include the tool name and parameters as a JSON object.`;
79
- }
80
-
81
- private buildEnvironment(): string {
82
- return `## Environment\n\nWorking directory: ${this.config.cwd}`;
83
- }
84
-
85
- private buildPermissionMode(): string {
86
- const mode = this.config.permissionMode;
87
- const explanations: Record<string, string> = {
88
- accept: 'All tool calls are automatically allowed without confirmation.',
89
- deny: 'All tool calls are blocked. You may only read and discuss.',
90
- ask: 'Dangerous or destructive commands require user confirmation before execution.',
91
- };
92
- return `## Permission Mode\n\nCurrent mode: ${mode}\n\n${explanations[mode] || ''}`;
93
- }
94
-
95
- private buildProjectInstructions(): string {
96
- if (!this.config.includeProjectMd) return '';
97
-
98
- const cwd = this.config.cwd;
99
- const paths = [join(cwd, 'CLAUDE.md'), join(cwd, '.claude.md'), join(cwd, 'AGENTS.md')];
100
-
101
- for (const path of paths) {
102
- if (existsSync(path)) {
103
- try {
104
- const content = readFileSync(path, 'utf-8');
105
- return `## Project Instructions (from ${path.split(/[/\\]/).pop()})\n\n${content}`;
106
- } catch {
107
- // Ignore
108
- }
109
- }
110
- }
111
- return '';
112
- }
113
-
114
- private buildDateInfo(): string {
115
- const now = this.config.date;
116
- const iso = now.toISOString().replace('T', ' ').split('.')[0];
117
- return `## Current Time\n\n${iso}`;
118
- }
119
-
120
- setTools(tools: Tool[]): this { this.config.tools = tools; return this; }
121
- setCwd(cwd: string): this { this.config.cwd = cwd; return this; }
122
- setPermissionMode(mode: 'accept' | 'deny' | 'ask'): this { this.config.permissionMode = mode; return this; }
123
- }
@@ -1,103 +0,0 @@
1
- /**
2
- * Context Compactor - Progressive compression for conversation history
3
- * Migrated from old src/core/context-compactor.ts
4
- *
5
- * Strategy:
6
- * 1. Within limit: no compression
7
- * 2. Beyond limit: keep system + recent N turns + summarize middle
8
- */
9
-
10
- import type { ChatMessage } from '../types.js';
11
-
12
- export interface CompactorConfig {
13
- /** Max messages before compression kicks in */
14
- maxMessages?: number;
15
- /** How many recent turns to always preserve */
16
- preserveRecent?: number;
17
- }
18
-
19
- export interface CompressionResult {
20
- originalCount: number;
21
- compactedCount: number;
22
- removedCount: number;
23
- }
24
-
25
- export class ContextCompactor {
26
- private maxMessages: number;
27
- private preserveRecent: number;
28
-
29
- constructor(config: CompactorConfig = {}) {
30
- this.maxMessages = config.maxMessages ?? 50;
31
- this.preserveRecent = config.preserveRecent ?? 10;
32
- }
33
-
34
- /**
35
- * Compact messages if needed
36
- */
37
- compact(messages: ChatMessage[]): { compacted: ChatMessage[]; result: CompressionResult } {
38
- if (messages.length <= this.maxMessages) {
39
- return {
40
- compacted: messages,
41
- result: { originalCount: messages.length, compactedCount: messages.length, removedCount: 0 },
42
- };
43
- }
44
-
45
- const systemMsg = messages.find(m => m.role === 'system');
46
- const others = messages.filter(m => m.role !== 'system');
47
-
48
- if (others.length <= this.preserveRecent) {
49
- return {
50
- compacted: messages,
51
- result: { originalCount: messages.length, compactedCount: messages.length, removedCount: 0 },
52
- };
53
- }
54
-
55
- // Keep recent N turns
56
- const recent = others.slice(-this.preserveRecent);
57
-
58
- // Summarize the middle portion
59
- const middle = others.slice(0, -this.preserveRecent);
60
- const summary: ChatMessage = {
61
- role: 'system',
62
- content: `[Earlier conversation summary: ${middle.length} messages covering ${this.extractTopics(middle)}]`,
63
- };
64
-
65
- const compacted = systemMsg
66
- ? [systemMsg, summary, ...recent]
67
- : [summary, ...recent];
68
-
69
- return {
70
- compacted,
71
- result: {
72
- originalCount: messages.length,
73
- compactedCount: compacted.length,
74
- removedCount: messages.length - compacted.length,
75
- },
76
- };
77
- }
78
-
79
- /**
80
- * Auto-compact if messages exceed limit
81
- */
82
- autoCompact(messages: ChatMessage[]): { compacted: ChatMessage[]; result: CompressionResult } {
83
- return this.compact(messages);
84
- }
85
-
86
- /**
87
- * Estimate token count (rough: ~4 chars per token)
88
- */
89
- estimateTokens(messages: ChatMessage[]): number {
90
- return messages.reduce((sum, m) => sum + Math.ceil(m.content.length / 4) + 10, 0);
91
- }
92
-
93
- /**
94
- * Extract topic summary from messages
95
- */
96
- private extractTopics(msgs: ChatMessage[]): string {
97
- const topics = msgs
98
- .filter(m => m.role === 'user')
99
- .map(m => m.content.slice(0, 30))
100
- .slice(0, 3);
101
- return topics.join(', ') || 'various topics';
102
- }
103
- }
@@ -1,81 +0,0 @@
1
- /**
2
- * Session Manager - Manages conversation history
3
- * Migrated from old src/core/session.ts
4
- */
5
-
6
- import type { ChatMessage } from '../types.js';
7
- import { ContextCompactor } from './compactor.js';
8
-
9
- export class SessionManager {
10
- private messages: ChatMessage[] = [];
11
- private sessionId: string;
12
- private createdAt: Date;
13
- private compactor: ContextCompactor;
14
-
15
- constructor(maxMessages = 50) {
16
- this.sessionId = `session_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
17
- this.createdAt = new Date();
18
- this.compactor = new ContextCompactor({ maxMessages });
19
- }
20
-
21
- /**
22
- * Add a message to the session
23
- */
24
- addMessage(role: ChatMessage['role'], content: string, extras?: Partial<ChatMessage>): void {
25
- this.messages.push({ role, content, ...extras });
26
- }
27
-
28
- /**
29
- * Get all messages (copy)
30
- */
31
- getMessages(): ChatMessage[] {
32
- return [...this.messages];
33
- }
34
-
35
- /**
36
- * Get message count
37
- */
38
- getMessageCount(): number {
39
- return this.messages.length;
40
- }
41
-
42
- /**
43
- * Clear session history
44
- */
45
- clear(): void {
46
- this.messages = [];
47
- }
48
-
49
- /**
50
- * Truncate messages to fit context window
51
- */
52
- truncate(maxMessages?: number): void {
53
- if (maxMessages) {
54
- this.compactor = new ContextCompactor({ maxMessages });
55
- }
56
- const { compacted } = this.compactor.autoCompact(this.messages);
57
- this.messages = compacted;
58
- }
59
-
60
- /**
61
- * Get session ID
62
- */
63
- getId(): string {
64
- return this.sessionId;
65
- }
66
-
67
- /**
68
- * Get session info
69
- */
70
- getInfo(): { id: string; messageCount: number; createdAt: Date } {
71
- return {
72
- id: this.sessionId,
73
- messageCount: this.messages.length,
74
- createdAt: this.createdAt,
75
- };
76
- }
77
- }
78
-
79
- export { ContextCompactor } from './compactor.js';
80
- export type { CompactorConfig, CompressionResult } from './compactor.js';
81
- export * from './message.js';
@@ -1,42 +0,0 @@
1
- /**
2
- * Message types and utilities
3
- */
4
-
5
- import type { ChatMessage, Role } from '../types.js';
6
-
7
- export { ChatMessage, Role };
8
-
9
- /**
10
- * Create a message
11
- */
12
- export function createMessage(role: Role, content: string, extras?: Partial<ChatMessage>): ChatMessage {
13
- return { role, content, ...extras };
14
- }
15
-
16
- /**
17
- * Create a system message
18
- */
19
- export function systemMessage(content: string): ChatMessage {
20
- return { role: 'system', content };
21
- }
22
-
23
- /**
24
- * Create a user message
25
- */
26
- export function userMessage(content: string): ChatMessage {
27
- return { role: 'user', content };
28
- }
29
-
30
- /**
31
- * Create an assistant message
32
- */
33
- export function assistantMessage(content: string): ChatMessage {
34
- return { role: 'assistant', content };
35
- }
36
-
37
- /**
38
- * Create a tool result message
39
- */
40
- export function toolMessage(content: string, toolCallId: string, name: string): ChatMessage {
41
- return { role: 'tool', content, tool_call_id: toolCallId, name };
42
- }