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
@@ -0,0 +1,8 @@
1
+ /**
2
+ * REPL Module
3
+ * Interactive input/output handling
4
+ */
5
+ export { REPLInput } from './input.js';
6
+ export { REPLOutput } from './output.js';
7
+ export { REPLLoop } from './loop.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/repl/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * REPL Module
3
+ * Interactive input/output handling
4
+ */
5
+ export { REPLInput } from './input.js';
6
+ export { REPLOutput } from './output.js';
7
+ export { REPLLoop } from './loop.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/repl/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * REPL Input Handler
3
+ *
4
+ * 基于 @inquirer/input 实现,支持:
5
+ * - 方向键(含数字小键盘方向键)行内移动 / 跳转词首尾
6
+ * - Home / End / Backspace / Delete 行内编辑
7
+ * - Ctrl+A / Ctrl+E 跳到行首/行尾(emacs 风格)
8
+ * - Ctrl+C 中断当前输入(不清空整个会话),连续按两次空输入退出
9
+ * - 命令历史:本地维护 history 数组,通过 default 预填上一条
10
+ *
11
+ * 不再使用 Node 内置 readline 的 rl.question()——它在 Windows 终端下
12
+ * 对小键盘方向键的 ANSI 转义序列不友好,会导致光标无法移动 (Bug #1)。
13
+ */
14
+ export type PromptResult = {
15
+ kind: 'value';
16
+ value: string;
17
+ } | {
18
+ kind: 'cancelled';
19
+ };
20
+ export declare class REPLInput {
21
+ private history;
22
+ private historyIndex;
23
+ private currentDraft;
24
+ private defaultPrefix;
25
+ private consecutiveCancels;
26
+ /**
27
+ * Ask the user for input. Returns either a value or 'cancelled'.
28
+ * Loop decides what to do with cancellation (usually: continue session,
29
+ * unless user has cancelled an already-empty input twice in a row).
30
+ */
31
+ prompt(prefix?: string, abortSignal?: AbortSignal): Promise<PromptResult>;
32
+ /**
33
+ * Should we ask the loop to exit? Two consecutive Ctrl+C on empty input => exit.
34
+ */
35
+ shouldExitOnCancel(): boolean;
36
+ /**
37
+ * Programmatic cancel trigger (used by the global SIGINT handler in REPLLoop).
38
+ * Increments the cancel counter as if a Ctrl+C had been seen, and returns
39
+ * whether the loop should now exit. Idempotent across the prompt() flow:
40
+ * if the user has already entered a non-empty prompt this is a no-op for exit
41
+ * (the loop keeps running) — but for an empty REPL it eventually returns true.
42
+ */
43
+ requestCancel(): boolean;
44
+ /**
45
+ * Reset consecutive-cancel counter when the loop has decided to keep running.
46
+ */
47
+ resetCancelCounter(): void;
48
+ /**
49
+ * Decide what to prefill. Two modes:
50
+ * - 'history': when user is navigating up/down with arrows
51
+ * - 'draft': when user has cleared the input — preserve their draft
52
+ */
53
+ private computePrefill;
54
+ /**
55
+ * Save the user's in-progress draft so ↑↓ preserves their unsent typing.
56
+ */
57
+ saveDraft(text: string): void;
58
+ /**
59
+ * Navigate up in history (called from a global key listener, if needed).
60
+ */
61
+ historyUp(): string;
62
+ /**
63
+ * Navigate down in history.
64
+ */
65
+ historyDown(): string;
66
+ getHistory(): readonly string[];
67
+ clearHistory(): void;
68
+ }
69
+ //# sourceMappingURL=input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/repl/input.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,CAAC;AAE1B,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,kBAAkB,CAAa;IAEvC;;;;OAIG;IACG,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAqC/E;;OAEG;IACH,kBAAkB,IAAI,OAAO;IAI7B;;;;;;OAMG;IACH,aAAa,IAAI,OAAO;IAMxB;;OAEG;IACH,kBAAkB,IAAI,IAAI;IAI1B;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAQtB;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI7B;;OAEG;IACH,SAAS,IAAI,MAAM;IAOnB;;OAEG;IACH,WAAW,IAAI,MAAM;IAWrB,UAAU,IAAI,SAAS,MAAM,EAAE;IAI/B,YAAY,IAAI,IAAI;CAIrB"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * REPL Input Handler
3
+ *
4
+ * 基于 @inquirer/input 实现,支持:
5
+ * - 方向键(含数字小键盘方向键)行内移动 / 跳转词首尾
6
+ * - Home / End / Backspace / Delete 行内编辑
7
+ * - Ctrl+A / Ctrl+E 跳到行首/行尾(emacs 风格)
8
+ * - Ctrl+C 中断当前输入(不清空整个会话),连续按两次空输入退出
9
+ * - 命令历史:本地维护 history 数组,通过 default 预填上一条
10
+ *
11
+ * 不再使用 Node 内置 readline 的 rl.question()——它在 Windows 终端下
12
+ * 对小键盘方向键的 ANSI 转义序列不友好,会导致光标无法移动 (Bug #1)。
13
+ */
14
+ import input from '@inquirer/input';
15
+ import chalk from 'chalk';
16
+ const MAX_HISTORY = 200;
17
+ export class REPLInput {
18
+ history = [];
19
+ historyIndex = -1; // -1 表示"未在历史中浏览"
20
+ currentDraft = ''; // 离开历史时保留用户原始草稿
21
+ defaultPrefix = chalk.green('\n> ');
22
+ consecutiveCancels = 0; // 连续空输入 + Ctrl+C 计数,达到阈值退出
23
+ /**
24
+ * Ask the user for input. Returns either a value or 'cancelled'.
25
+ * Loop decides what to do with cancellation (usually: continue session,
26
+ * unless user has cancelled an already-empty input twice in a row).
27
+ */
28
+ async prompt(prefix, abortSignal) {
29
+ const prefill = this.computePrefill();
30
+ const previousDraft = prefill.kind === 'history' ? prefill.value : '';
31
+ // 用 abortSignal 绑到 inquirer:外面 Ctrl+C / 主进程事件可以取消
32
+ const value = await input({
33
+ message: prefix ?? this.defaultPrefix,
34
+ prefill: 'editable', // 关键:启用方向键 + 行内编辑,包括小键盘
35
+ default: previousDraft, // 历史预填
36
+ // Ctrl+C 由 @inquirer/input 抛出一个 symbol-like 错误,我们捕获为 cancelled
37
+ validate: () => true,
38
+ }, abortSignal ? { signal: abortSignal } : undefined).catch((err) => {
39
+ // 区分真实错误与用户取消;inquirer 用 ExitPromptError (name: 'ExitPromptError')
40
+ if (err && (err.name === 'ExitPromptError' || err.message?.includes('User force closed'))) {
41
+ return null;
42
+ }
43
+ throw err;
44
+ });
45
+ if (value === null || value === undefined) {
46
+ this.consecutiveCancels++;
47
+ return { kind: 'cancelled' };
48
+ }
49
+ const trimmed = value.trim();
50
+ if (trimmed.length > 0) {
51
+ // 避免把连续重复的内容都压入历史
52
+ if (this.history[this.history.length - 1] !== trimmed) {
53
+ this.history.push(trimmed);
54
+ if (this.history.length > MAX_HISTORY)
55
+ this.history.shift();
56
+ }
57
+ }
58
+ this.consecutiveCancels = 0;
59
+ return { kind: 'value', value: trimmed };
60
+ }
61
+ /**
62
+ * Should we ask the loop to exit? Two consecutive Ctrl+C on empty input => exit.
63
+ */
64
+ shouldExitOnCancel() {
65
+ return this.consecutiveCancels >= 2;
66
+ }
67
+ /**
68
+ * Programmatic cancel trigger (used by the global SIGINT handler in REPLLoop).
69
+ * Increments the cancel counter as if a Ctrl+C had been seen, and returns
70
+ * whether the loop should now exit. Idempotent across the prompt() flow:
71
+ * if the user has already entered a non-empty prompt this is a no-op for exit
72
+ * (the loop keeps running) — but for an empty REPL it eventually returns true.
73
+ */
74
+ requestCancel() {
75
+ // 模拟一次空输入 cancel:计为 1,下一次 SIGINT 累计到 2 即退出
76
+ this.consecutiveCancels++;
77
+ return this.shouldExitOnCancel();
78
+ }
79
+ /**
80
+ * Reset consecutive-cancel counter when the loop has decided to keep running.
81
+ */
82
+ resetCancelCounter() {
83
+ this.consecutiveCancels = 0;
84
+ }
85
+ /**
86
+ * Decide what to prefill. Two modes:
87
+ * - 'history': when user is navigating up/down with arrows
88
+ * - 'draft': when user has cleared the input — preserve their draft
89
+ */
90
+ computePrefill() {
91
+ if (this.historyIndex >= 0 && this.historyIndex < this.history.length) {
92
+ return { kind: 'history', value: this.history[this.historyIndex] };
93
+ }
94
+ if (this.currentDraft)
95
+ return { kind: 'draft', value: this.currentDraft };
96
+ return { kind: 'none', value: '' };
97
+ }
98
+ /**
99
+ * Save the user's in-progress draft so ↑↓ preserves their unsent typing.
100
+ */
101
+ saveDraft(text) {
102
+ this.currentDraft = text;
103
+ }
104
+ /**
105
+ * Navigate up in history (called from a global key listener, if needed).
106
+ */
107
+ historyUp() {
108
+ if (this.history.length === 0)
109
+ return this.currentDraft;
110
+ if (this.historyIndex < 0)
111
+ this.historyIndex = this.history.length;
112
+ if (this.historyIndex > 0)
113
+ this.historyIndex--;
114
+ return this.history[this.historyIndex] ?? '';
115
+ }
116
+ /**
117
+ * Navigate down in history.
118
+ */
119
+ historyDown() {
120
+ if (this.history.length === 0)
121
+ return this.currentDraft;
122
+ if (this.historyIndex >= this.history.length)
123
+ return this.currentDraft;
124
+ this.historyIndex++;
125
+ if (this.historyIndex >= this.history.length) {
126
+ this.historyIndex = this.history.length;
127
+ return this.currentDraft;
128
+ }
129
+ return this.history[this.historyIndex] ?? '';
130
+ }
131
+ getHistory() {
132
+ return this.history;
133
+ }
134
+ clearHistory() {
135
+ this.history = [];
136
+ this.historyIndex = -1;
137
+ }
138
+ }
139
+ //# sourceMappingURL=input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.js","sourceRoot":"","sources":["../../src/repl/input.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,184 @@
1
+ /**
2
+ * REPL Loop
3
+ * Main interactive loop with streaming support
4
+ *
5
+ * S07-fix:
6
+ * - 输入端换用 REPLInput (基于 @inquirer/input),支持方向键/小键盘
7
+ * - 流式输出保留完整内容(用户可滚动终端查看历史),不跳顶不刷屏
8
+ * - Ctrl+C 行为:有未提交内容=>清空当前输入;空输入两次=>退出
9
+ */
10
+ /**
11
+ * One entry in ~/.thatgfsj/models.json (added in 0.3.0).
12
+ */
13
+ export interface SavedModel {
14
+ /** Model id used in API requests, e.g. `Qwen3-32B` or `claude-sonnet-4-5`. */
15
+ id: string;
16
+ /** Unix ms timestamp when this entry was last written. Defaults to 0
17
+ * on legacy entries; `appendSavedModel` always overwrites it with
18
+ * `Date.now()` at write time. */
19
+ addedAt?: number;
20
+ /** Optional context-window length in MiB (the `ctx` field). */
21
+ ctx?: number;
22
+ /** Optional thinking-effort hint: 'none' | 'low' | 'medium' | 'high' | 'max'. */
23
+ thinking?: 'none' | 'low' | 'medium' | 'high' | 'max';
24
+ /** Optional free-form note (e.g. "Q4 quantized via openrouter"). */
25
+ note?: string;
26
+ }
27
+ export declare class REPLLoop {
28
+ private input;
29
+ private output;
30
+ private ai;
31
+ private session;
32
+ private running;
33
+ private streamAbort;
34
+ constructor();
35
+ /**
36
+ * Initialize the REPL
37
+ * S04: Use SystemPromptBuilder for dynamic prompt construction
38
+ */
39
+ init(): Promise<void>;
40
+ /**
41
+ * Start the REPL loop
42
+ */
43
+ start(): Promise<void>;
44
+ /**
45
+ * Handle built-in commands
46
+ *
47
+ * Accepts bare words, slash-prefixed forms (`/model`), AND Chinese aliases
48
+ * (`/模型`, `/提供商`, `/帮助`, `/清除`, `/退出`, `/历史`, `/工具`).
49
+ * The Chinese forms mirror thatgfsj-code@1.0.4 behaviour.
50
+ */
51
+ private handleCommand;
52
+ /**
53
+ * Process user input with AI (S01: streaming, no prompt reset)
54
+ *
55
+ * 关键修复:
56
+ * - 不再调用 rl.question,所以不会 reset 终端
57
+ * - chunk 直接 process.stdout.write,完整保留所有输出,用户可滚动查看
58
+ * - spinner 在第一个 chunk 到达时停止,然后正常流式
59
+ */
60
+ private processInput;
61
+ private showContext;
62
+ private showHistory;
63
+ private showTools;
64
+ private showProviders;
65
+ /**
66
+ * /model — main entry point for model management.
67
+ *
68
+ * 0.3.0 UX (per user feedback):
69
+ * - 先看到的是**已经保存的模型** (从 ~/.thatgfsj/models.json 读),
70
+ * 而不是内置 provider 列表。
71
+ * - 列表末尾是 `+ 添加新模型` 选项 → 触发完整向导
72
+ * (provider → api_key → baseUrl(可选,用于中转站) → model_name →
73
+ * context length (M) → thinking effort)。
74
+ * - 顶部有 `edit` 模式,可以重新修改任意已保存模型。
75
+ * - 选某条 saved model 后立即切换并退出;按 Enter 不变。
76
+ * - 兼容 0.2.x / 1.0.4 老 history:
77
+ * - 字符串数组会透明迁移成 {id,...} 形式。
78
+ * - 内置模型 (`Qwen3-32B` 之类) 也可选择,作为「saved + builtin」展示。
79
+ */
80
+ private handleModelSwitch;
81
+ /**
82
+ * Add-model wizard (0.3.0+):
83
+ * Step 1: Provider (内置 / custom_openai / custom_anthropic)
84
+ * Step 2: API Key (内置:给注册链接;custom:无)
85
+ * Step 3: Base URL (仅 custom_*;内置跳过)
86
+ * Step 4: 模型名称 (自由输入)
87
+ * Step 5: 上下文长度 (MiB,数字,默认 8)
88
+ * Step 6: 思考强度 (none / low / medium / high / max,默认 none)
89
+ *
90
+ * 完成后:写入 ~/.thatgfsj/models.json,顺便把新模型切到当前,
91
+ * 更新 AIEngine + 写入 ~/.thatgfsj/config.json model 字段。
92
+ */
93
+ private runAddModelWizard;
94
+ /**
95
+ * Edit-model wizard (0.3.0+): pick a saved model and update ctx /
96
+ * thinking / note without leaving the REPL.
97
+ */
98
+ private runEditModelWizard;
99
+ /**
100
+ * Persist a provider choice + custom baseUrl + apiKey into
101
+ * ~/.thatgfsj/config.json and reload AIEngine config. Differs from
102
+ * applyProviderSwitch in that this also writes a custom baseUrl.
103
+ */
104
+ private applyProviderSwitchInternal;
105
+ /**
106
+ * Read ~/.thatgfsj/models.json — a list of saved models the user has
107
+ * previously switched to or added. Starting from 0.3.0 each entry is
108
+ * `{ id, addedAt, ctx?, thinking?, note? }`. Older releases stored a
109
+ * flat array of strings; we transparently migrate that on read.
110
+ */
111
+ private loadModelHistory;
112
+ /**
113
+ * Read ~/.thatgfsj/models.json as a list of SavedModel entries.
114
+ * Migrates v0.2.x's `["id1","id2"]` shape into 0.3.0's `{id,...}` shape
115
+ * on the fly, leaving the on-disk file untouched until a write happens.
116
+ */
117
+ private loadSavedModels;
118
+ /**
119
+ * Legacy helper: append a model id to ~/.thatgfsj/models.json.
120
+ * New callers should prefer `appendSavedModel` so we don't lose
121
+ * ctx / thinking metadata.
122
+ */
123
+ private appendModelHistory;
124
+ /**
125
+ * Persist a SavedModel into ~/.thatgfsj/models.json, replacing any
126
+ * existing entry with the same id (case-insensitive). The original
127
+ * casing of the entry is preserved — i.e. if the user already has
128
+ * `Qwen3-32B` saved and types `qwen3-32b`, the canonical `Qwen3-32B`
129
+ * casing is kept. Newest entries go at the tail of the file.
130
+ */
131
+ private appendSavedModel;
132
+ /** Replace an existing saved model entry (matched by id). */
133
+ private replaceSavedModel;
134
+ /**
135
+ * /provider — interactive provider picker. After provider selection,
136
+ * delegates to /model so the user can also pick a new model for the new provider.
137
+ */
138
+ private handleProviderSwitch;
139
+ /**
140
+ * /edit [n] — short-hand for the edit wizard.
141
+ * `/edit` → list saved models, ask which to edit.
142
+ * `/edit 1` → jump to wizard for saved model #1.
143
+ * `/edit Qwen3-32B` → jump to wizard for the model whose id matches.
144
+ */
145
+ private runEditShortcut;
146
+ /**
147
+ * Persist a model choice and update the running AIEngine.
148
+ */
149
+ private applyModelSwitch;
150
+ /**
151
+ * Persist a provider choice (with the corresponding baseUrl from PROVIDERS
152
+ * map) and update the running AIEngine.
153
+ */
154
+ private applyProviderSwitch;
155
+ /**
156
+ * Read the on-disk config; if no file exists, derive a starting config
157
+ * from the current AIEngine state.
158
+ */
159
+ private readPersistedConfig;
160
+ private persistConfig;
161
+ /**
162
+ * Resolve either a numeric index or a model id to a model entry.
163
+ */
164
+ private resolveModelChoice;
165
+ /**
166
+ * Wrap readline in a one-shot prompt. Returns the trimmed answer, or
167
+ * `null` if the user pressed Ctrl+C (does not throw).
168
+ */
169
+ private askOnce;
170
+ /**
171
+ * Validate-and-collect a numeric choice within `[min..max]`. Accepts
172
+ * empty input as `defaultValue`. Returns `null` on Ctrl+C.
173
+ */
174
+ private askChoice;
175
+ /**
176
+ * Stop the REPL
177
+ */
178
+ stop(): void;
179
+ /**
180
+ * Handle interrupt (Ctrl+C) while streaming
181
+ */
182
+ interrupt(): void;
183
+ }
184
+ //# sourceMappingURL=loop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/repl/loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAiBH;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,8EAA8E;IAC9E,EAAE,EAAE,MAAM,CAAC;IACX;;sCAEkC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,QAAQ,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,CAAC;IACtD,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,QAAQ;IACnB,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,EAAE,CAAyB;IACnC,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,OAAO,CAAkB;IAEjC,OAAO,CAAC,WAAW,CAAgC;;IAOnD;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA4C3B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA6C5B;;;;;;OAMG;YACW,aAAa;IA8E3B;;;;;;;OAOG;YACW,YAAY;IAsD1B,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,aAAa;IAarB;;;;;;;;;;;;;;OAcG;YACW,iBAAiB;IA6H/B;;;;;;;;;;;OAWG;YACW,iBAAiB;IA0G/B;;;OAGG;YACW,kBAAkB;IA2ChC;;;;OAIG;YACW,2BAA2B;IAezC;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IAMxB;;;;OAIG;IACH,OAAO,CAAC,eAAe;IA6BvB;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAI1B;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;IAqBxB,6DAA6D;IAC7D,OAAO,CAAC,iBAAiB;IAezB;;;OAGG;YACW,oBAAoB;IAgGlC;;;;;OAKG;YACW,eAAe;IAgC7B;;OAEG;YACW,gBAAgB;IAS9B;;;OAGG;YACW,mBAAmB;IASjC;;;OAGG;YACW,mBAAmB;YA2BnB,aAAa;IAM3B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAU1B;;;OAGG;IACH,OAAO,CAAC,OAAO;IAoBf;;;OAGG;YACW,SAAS;IAWvB;;OAEG;IACH,IAAI,IAAI,IAAI;IASZ;;OAEG;IACH,SAAS,IAAI,IAAI;CAOlB"}