thatgfsj-code 2.2.9 → 3.0.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 (190) hide show
  1. package/CHANGELOG.md +15 -67
  2. package/dist/app/index.d.ts +28 -5
  3. package/dist/app/index.d.ts.map +1 -1
  4. package/dist/app/index.js +76 -10
  5. package/dist/app/index.js.map +1 -1
  6. package/dist/cache/fingerprint.d.ts +49 -0
  7. package/dist/cache/fingerprint.d.ts.map +1 -0
  8. package/dist/cache/fingerprint.js +100 -0
  9. package/dist/cache/fingerprint.js.map +1 -0
  10. package/dist/cache/index.d.ts +15 -0
  11. package/dist/cache/index.d.ts.map +1 -0
  12. package/dist/cache/index.js +15 -0
  13. package/dist/cache/index.js.map +1 -0
  14. package/dist/cache/smartModel.d.ts +40 -0
  15. package/dist/cache/smartModel.d.ts.map +1 -0
  16. package/dist/cache/smartModel.js +43 -0
  17. package/dist/cache/smartModel.js.map +1 -0
  18. package/dist/cache/stats.d.ts +93 -0
  19. package/dist/cache/stats.d.ts.map +1 -0
  20. package/dist/cache/stats.js +155 -0
  21. package/dist/cache/stats.js.map +1 -0
  22. package/dist/cache/volatile.d.ts +32 -0
  23. package/dist/cache/volatile.d.ts.map +1 -0
  24. package/dist/cache/volatile.js +44 -0
  25. package/dist/cache/volatile.js.map +1 -0
  26. package/dist/cmd/index.js +49 -57
  27. package/dist/cmd/index.js.map +1 -1
  28. package/dist/config/index.d.ts.map +1 -1
  29. package/dist/config/index.js +8 -0
  30. package/dist/config/index.js.map +1 -1
  31. package/dist/config/types.d.ts +14 -0
  32. package/dist/config/types.d.ts.map +1 -1
  33. package/dist/llm/anthropic.d.ts +55 -5
  34. package/dist/llm/anthropic.d.ts.map +1 -1
  35. package/dist/llm/anthropic.js +172 -26
  36. package/dist/llm/anthropic.js.map +1 -1
  37. package/dist/llm/index.d.ts +26 -8
  38. package/dist/llm/index.d.ts.map +1 -1
  39. package/dist/llm/index.js +83 -15
  40. package/dist/llm/index.js.map +1 -1
  41. package/dist/llm/openai.d.ts +28 -8
  42. package/dist/llm/openai.d.ts.map +1 -1
  43. package/dist/llm/openai.js +58 -8
  44. package/dist/llm/openai.js.map +1 -1
  45. package/dist/llm/provider.d.ts +40 -8
  46. package/dist/llm/provider.d.ts.map +1 -1
  47. package/dist/llm/provider.js +8 -1
  48. package/dist/llm/provider.js.map +1 -1
  49. package/dist/prompts/index.d.ts +32 -0
  50. package/dist/prompts/index.d.ts.map +1 -1
  51. package/dist/prompts/index.js +33 -11
  52. package/dist/prompts/index.js.map +1 -1
  53. package/dist/session/index.d.ts +32 -3
  54. package/dist/session/index.d.ts.map +1 -1
  55. package/dist/session/index.js +51 -36
  56. package/dist/session/index.js.map +1 -1
  57. package/dist/skills/brainstorming.js +33 -33
  58. package/dist/skills/code-review.js +35 -35
  59. package/dist/skills/executing-plans.js +18 -18
  60. package/dist/skills/frontend-design.js +25 -25
  61. package/dist/skills/git-workflow.js +26 -26
  62. package/dist/skills/improve-architecture.js +28 -28
  63. package/dist/skills/neuroweave.js +37 -37
  64. package/dist/skills/playwright.js +62 -62
  65. package/dist/skills/prototype.js +20 -20
  66. package/dist/skills/subagent.js +19 -19
  67. package/dist/skills/supabase.js +34 -34
  68. package/dist/skills/systematic-debugging.js +34 -34
  69. package/dist/skills/tdd.js +29 -29
  70. package/dist/skills/triage.js +25 -25
  71. package/dist/skills/verification.js +22 -22
  72. package/dist/skills/writing-plans.js +32 -32
  73. package/dist/tools/nwt.js +16 -16
  74. package/dist/tui/app.d.ts.map +1 -1
  75. package/dist/tui/app.js +9 -2
  76. package/dist/tui/app.js.map +1 -1
  77. package/dist/tui/components/Header.d.ts +8 -0
  78. package/dist/tui/components/Header.d.ts.map +1 -1
  79. package/dist/tui/components/Header.js +17 -4
  80. package/dist/tui/components/Header.js.map +1 -1
  81. package/dist/tui/components/InitWizard.d.ts +12 -1
  82. package/dist/tui/components/InitWizard.d.ts.map +1 -1
  83. package/dist/tui/components/InitWizard.js +58 -3
  84. package/dist/tui/components/InitWizard.js.map +1 -1
  85. package/dist/tui/components/ModelSelector.d.ts +3 -1
  86. package/dist/tui/components/ModelSelector.d.ts.map +1 -1
  87. package/dist/tui/components/ModelSelector.js +24 -7
  88. package/dist/tui/components/ModelSelector.js.map +1 -1
  89. package/dist/tui/components/ToolCall.d.ts.map +1 -1
  90. package/dist/tui/components/ToolCall.js +1 -6
  91. package/dist/tui/components/ToolCall.js.map +1 -1
  92. package/dist/tui/components/UserInput.d.ts.map +1 -1
  93. package/dist/tui/components/UserInput.js +20 -0
  94. package/dist/tui/components/UserInput.js.map +1 -1
  95. package/dist/tui/hooks/useChat.d.ts +22 -0
  96. package/dist/tui/hooks/useChat.d.ts.map +1 -1
  97. package/dist/tui/hooks/useChat.js +82 -46
  98. package/dist/tui/hooks/useChat.js.map +1 -1
  99. package/dist/tui/hooks/useCommands.d.ts.map +1 -1
  100. package/dist/tui/hooks/useCommands.js +57 -0
  101. package/dist/tui/hooks/useCommands.js.map +1 -1
  102. package/dist/tui/welcome.d.ts.map +1 -1
  103. package/dist/tui/welcome.js +2 -3
  104. package/dist/tui/welcome.js.map +1 -1
  105. package/dist/types.d.ts +79 -6
  106. package/dist/types.d.ts.map +1 -1
  107. package/dist/types.js +7 -0
  108. package/dist/types.js.map +1 -1
  109. package/dist/utils/stableStringify.d.ts +21 -0
  110. package/dist/utils/stableStringify.d.ts.map +1 -0
  111. package/dist/utils/stableStringify.js +53 -0
  112. package/dist/utils/stableStringify.js.map +1 -0
  113. package/dist/utils/thinking.d.ts.map +1 -1
  114. package/dist/utils/thinking.js +0 -3
  115. package/dist/utils/thinking.js.map +1 -1
  116. package/package.json +7 -6
  117. package/src/app/index.ts +189 -124
  118. package/src/cache/fingerprint.ts +101 -0
  119. package/src/cache/index.ts +15 -0
  120. package/src/cache/smartModel.ts +52 -0
  121. package/src/cache/stats.ts +199 -0
  122. package/src/cache/volatile.ts +47 -0
  123. package/src/cmd/index.tsx +288 -292
  124. package/src/config/index.ts +156 -148
  125. package/src/config/providers.ts +234 -234
  126. package/src/config/types.ts +67 -53
  127. package/src/hooks/index.ts +111 -111
  128. package/src/llm/anthropic.ts +388 -243
  129. package/src/llm/gemini.ts +169 -169
  130. package/src/llm/index.ts +265 -200
  131. package/src/llm/openai.ts +243 -196
  132. package/src/llm/provider.ts +66 -34
  133. package/src/prompts/index.ts +260 -220
  134. package/src/session/compactor.ts +103 -103
  135. package/src/session/index.ts +181 -168
  136. package/src/session/message.ts +42 -42
  137. package/src/skills/brainstorming.ts +43 -43
  138. package/src/skills/code-review.ts +45 -45
  139. package/src/skills/executing-plans.ts +27 -27
  140. package/src/skills/frontend-design.ts +35 -35
  141. package/src/skills/git-workflow.ts +36 -36
  142. package/src/skills/improve-architecture.ts +38 -38
  143. package/src/skills/index.ts +136 -136
  144. package/src/skills/neuroweave.ts +47 -47
  145. package/src/skills/playwright.ts +72 -72
  146. package/src/skills/prototype.ts +30 -30
  147. package/src/skills/subagent.ts +28 -28
  148. package/src/skills/supabase.ts +44 -44
  149. package/src/skills/systematic-debugging.ts +44 -44
  150. package/src/skills/tdd.ts +39 -39
  151. package/src/skills/triage.ts +35 -35
  152. package/src/skills/verification.ts +31 -31
  153. package/src/skills/writing-plans.ts +42 -42
  154. package/src/tools/nwt.ts +598 -598
  155. package/src/tools/types.ts +122 -122
  156. package/src/tui/app.tsx +200 -186
  157. package/src/tui/components/ChatList.tsx +41 -41
  158. package/src/tui/components/ChatMessage.tsx +54 -54
  159. package/src/tui/components/Header.tsx +56 -29
  160. package/src/tui/components/InitWizard.tsx +217 -132
  161. package/src/tui/components/Markdown.tsx +35 -35
  162. package/src/tui/components/ModelSelector.tsx +107 -87
  163. package/src/tui/components/StatusBar.tsx +30 -30
  164. package/src/tui/components/Thinking.tsx +17 -17
  165. package/src/tui/components/ToolCall.tsx +102 -107
  166. package/src/tui/components/UserInput.tsx +151 -131
  167. package/src/tui/hooks/useChat.ts +287 -238
  168. package/src/tui/hooks/useCommands.ts +234 -176
  169. package/src/tui/index.ts +6 -6
  170. package/src/tui/welcome.ts +177 -178
  171. package/src/types.ts +104 -42
  172. package/src/utils/diff.ts +71 -71
  173. package/src/utils/project.ts +99 -99
  174. package/src/utils/stableStringify.ts +47 -0
  175. package/src/utils/thinking.ts +118 -121
  176. package/tests/cache/fingerprint.test.ts +75 -0
  177. package/tests/cache/providerCatalog.test.ts +31 -0
  178. package/tests/cache/stableStringify.test.ts +43 -0
  179. package/tests/cache/stats.test.ts +146 -0
  180. package/tests/cache/volatile.test.ts +75 -0
  181. package/tests/smoke-pollution.mjs +78 -0
  182. package/tests/smoke-thinking.mjs +110 -0
  183. package/tests/smoke-tool-stream.mjs +69 -0
  184. package/tests/smoke-tool.mjs +117 -0
  185. package/.nwt/meta.json +0 -5
  186. package/dist/version.d.ts +0 -16
  187. package/dist/version.d.ts.map +0 -1
  188. package/dist/version.js +0 -16
  189. package/dist/version.js.map +0 -1
  190. package/src/version.ts +0 -16
@@ -1,148 +1,156 @@
1
- /**
2
- * Config Manager - Handles configuration loading and saving
3
- * Supports custom providers (relay stations / 中转站)
4
- */
5
-
6
- import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
7
- import { join, dirname } from 'path';
8
- import { homedir } from 'os';
9
- import type { Config, AIConfig, ProviderName } from './types.js';
10
- import { PROVIDERS, getApiKeyFromEnv, isCustomProvider } from './providers.js';
11
-
12
- const DEFAULT_CONFIG: Config = {
13
- model: 'Qwen/Qwen2.5-7B-Instruct',
14
- apiKey: '',
15
- temperature: 0.7,
16
- maxTokens: 4096,
17
- contextLength: 50,
18
- provider: 'siliconflow',
19
- };
20
-
21
- export class ConfigManager {
22
- private configPath: string;
23
- private config: Config;
24
-
25
- private constructor(configPath: string, config: Config) {
26
- this.configPath = configPath;
27
- this.config = config;
28
- }
29
-
30
- /**
31
- * Load configuration from file + environment variables
32
- */
33
- static async load(): Promise<ConfigManager> {
34
- const configDir = join(homedir(), '.thatgfsj');
35
- const configPath = join(configDir, 'config.json');
36
-
37
- let config = { ...DEFAULT_CONFIG };
38
-
39
- // Load from file
40
- try {
41
- if (existsSync(configPath)) {
42
- const data = readFileSync(configPath, 'utf-8');
43
- config = { ...config, ...JSON.parse(data) };
44
- }
45
- } catch {
46
- // Use defaults if file is corrupted
47
- }
48
-
49
- // Resolve provider
50
- config = ConfigManager.resolveProvider(config);
51
-
52
- return new ConfigManager(configPath, config);
53
- }
54
-
55
- /**
56
- * Resolve provider settings: API key from env, base URL, model
57
- */
58
- private static resolveProvider(config: Config): Config {
59
- const provider = config.provider || 'siliconflow';
60
- const providerConfig = PROVIDERS[provider];
61
-
62
- if (!providerConfig) {
63
- return { ...config, provider: 'siliconflow', baseUrl: PROVIDERS.siliconflow.baseUrl };
64
- }
65
-
66
- // Model: env MODEL > config > provider default
67
- const model = process.env.MODEL || config.model || providerConfig.defaultModel;
68
-
69
- // API key: env > config
70
- let apiKey = config.apiKey;
71
- if (provider === 'ollama') {
72
- apiKey = '';
73
- } else if (!apiKey) {
74
- apiKey = getApiKeyFromEnv(provider);
75
- }
76
-
77
- // Base URL: config > env > provider default
78
- let baseUrl = config.baseUrl;
79
- if (!baseUrl) {
80
- // Check env for custom base URL
81
- if (provider === 'custom_openai') {
82
- baseUrl = process.env.CUSTOM_BASE_URL || '';
83
- } else if (provider === 'custom_anthropic') {
84
- baseUrl = process.env.CUSTOM_BASE_URL || '';
85
- } else {
86
- baseUrl = providerConfig.baseUrl;
87
- }
88
- }
89
-
90
- return { ...config, provider, baseUrl, model, apiKey: apiKey || '' };
91
- }
92
-
93
- /**
94
- * Get the current config
95
- */
96
- get(): Config {
97
- return { ...this.config };
98
- }
99
-
100
- /**
101
- * Get AIConfig for LLM providers
102
- */
103
- getAIConfig(): AIConfig {
104
- return {
105
- model: this.config.model,
106
- apiKey: this.config.apiKey,
107
- temperature: this.config.temperature,
108
- maxTokens: this.config.maxTokens,
109
- baseUrl: this.config.baseUrl,
110
- provider: this.config.provider,
111
- };
112
- }
113
-
114
- /**
115
- * Get provider format (openai | anthropic | gemini)
116
- */
117
- getProviderFormat(): 'openai' | 'anthropic' | 'gemini' {
118
- return PROVIDERS[this.config.provider]?.format || 'openai';
119
- }
120
-
121
- /**
122
- * Update config and save to file
123
- */
124
- async save(updates: Partial<Config>): Promise<void> {
125
- this.config = { ...this.config, ...updates };
126
-
127
- const dir = dirname(this.configPath);
128
- if (!existsSync(dir)) {
129
- mkdirSync(dir, { recursive: true });
130
- }
131
-
132
- writeFileSync(this.configPath, JSON.stringify(this.config, null, 2));
133
- }
134
-
135
- /**
136
- * Check if an API key is configured
137
- */
138
- hasApiKey(): boolean {
139
- return !!this.config.apiKey;
140
- }
141
-
142
- /**
143
- * Check if using a custom provider
144
- */
145
- isCustomProvider(): boolean {
146
- return isCustomProvider(this.config.provider);
147
- }
148
- }
1
+ /**
2
+ * Config Manager - Handles configuration loading and saving
3
+ * Supports custom providers (relay stations / 中转站)
4
+ */
5
+
6
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
7
+ import { join, dirname } from 'path';
8
+ import { homedir } from 'os';
9
+ import type { Config, AIConfig, ProviderName } from './types.js';
10
+ import { PROVIDERS, getApiKeyFromEnv, isCustomProvider } from './providers.js';
11
+
12
+ const DEFAULT_CONFIG: Config = {
13
+ model: 'Qwen/Qwen2.5-7B-Instruct',
14
+ apiKey: '',
15
+ temperature: 0.7,
16
+ maxTokens: 4096,
17
+ contextLength: 50,
18
+ provider: 'siliconflow',
19
+ // v3.0.0: prompt cache policy. Default = enabled, 5m TTL, auto strategy
20
+ // (Anthropic gets explicit cache_control markers; everything else falls
21
+ // through to the provider's built-in caching).
22
+ cache: {
23
+ enabled: true,
24
+ ttl: '5m',
25
+ strategy: 'auto',
26
+ },
27
+ };
28
+
29
+ export class ConfigManager {
30
+ private configPath: string;
31
+ private config: Config;
32
+
33
+ private constructor(configPath: string, config: Config) {
34
+ this.configPath = configPath;
35
+ this.config = config;
36
+ }
37
+
38
+ /**
39
+ * Load configuration from file + environment variables
40
+ */
41
+ static async load(): Promise<ConfigManager> {
42
+ const configDir = join(homedir(), '.thatgfsj');
43
+ const configPath = join(configDir, 'config.json');
44
+
45
+ let config = { ...DEFAULT_CONFIG };
46
+
47
+ // Load from file
48
+ try {
49
+ if (existsSync(configPath)) {
50
+ const data = readFileSync(configPath, 'utf-8');
51
+ config = { ...config, ...JSON.parse(data) };
52
+ }
53
+ } catch {
54
+ // Use defaults if file is corrupted
55
+ }
56
+
57
+ // Resolve provider
58
+ config = ConfigManager.resolveProvider(config);
59
+
60
+ return new ConfigManager(configPath, config);
61
+ }
62
+
63
+ /**
64
+ * Resolve provider settings: API key from env, base URL, model
65
+ */
66
+ private static resolveProvider(config: Config): Config {
67
+ const provider = config.provider || 'siliconflow';
68
+ const providerConfig = PROVIDERS[provider];
69
+
70
+ if (!providerConfig) {
71
+ return { ...config, provider: 'siliconflow', baseUrl: PROVIDERS.siliconflow.baseUrl };
72
+ }
73
+
74
+ // Model: env MODEL > config > provider default
75
+ const model = process.env.MODEL || config.model || providerConfig.defaultModel;
76
+
77
+ // API key: env > config
78
+ let apiKey = config.apiKey;
79
+ if (provider === 'ollama') {
80
+ apiKey = '';
81
+ } else if (!apiKey) {
82
+ apiKey = getApiKeyFromEnv(provider);
83
+ }
84
+
85
+ // Base URL: config > env > provider default
86
+ let baseUrl = config.baseUrl;
87
+ if (!baseUrl) {
88
+ // Check env for custom base URL
89
+ if (provider === 'custom_openai') {
90
+ baseUrl = process.env.CUSTOM_BASE_URL || '';
91
+ } else if (provider === 'custom_anthropic') {
92
+ baseUrl = process.env.CUSTOM_BASE_URL || '';
93
+ } else {
94
+ baseUrl = providerConfig.baseUrl;
95
+ }
96
+ }
97
+
98
+ return { ...config, provider, baseUrl, model, apiKey: apiKey || '' };
99
+ }
100
+
101
+ /**
102
+ * Get the current config
103
+ */
104
+ get(): Config {
105
+ return { ...this.config };
106
+ }
107
+
108
+ /**
109
+ * Get AIConfig for LLM providers
110
+ */
111
+ getAIConfig(): AIConfig {
112
+ return {
113
+ model: this.config.model,
114
+ apiKey: this.config.apiKey,
115
+ temperature: this.config.temperature,
116
+ maxTokens: this.config.maxTokens,
117
+ baseUrl: this.config.baseUrl,
118
+ provider: this.config.provider,
119
+ };
120
+ }
121
+
122
+ /**
123
+ * Get provider format (openai | anthropic | gemini)
124
+ */
125
+ getProviderFormat(): 'openai' | 'anthropic' | 'gemini' {
126
+ return PROVIDERS[this.config.provider]?.format || 'openai';
127
+ }
128
+
129
+ /**
130
+ * Update config and save to file
131
+ */
132
+ async save(updates: Partial<Config>): Promise<void> {
133
+ this.config = { ...this.config, ...updates };
134
+
135
+ const dir = dirname(this.configPath);
136
+ if (!existsSync(dir)) {
137
+ mkdirSync(dir, { recursive: true });
138
+ }
139
+
140
+ writeFileSync(this.configPath, JSON.stringify(this.config, null, 2));
141
+ }
142
+
143
+ /**
144
+ * Check if an API key is configured
145
+ */
146
+ hasApiKey(): boolean {
147
+ return !!this.config.apiKey;
148
+ }
149
+
150
+ /**
151
+ * Check if using a custom provider
152
+ */
153
+ isCustomProvider(): boolean {
154
+ return isCustomProvider(this.config.provider);
155
+ }
156
+ }