thatgfsj-code 2.2.9 → 3.0.0

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 (182) 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 +69 -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/ToolCall.d.ts.map +1 -1
  86. package/dist/tui/components/ToolCall.js +1 -6
  87. package/dist/tui/components/ToolCall.js.map +1 -1
  88. package/dist/tui/hooks/useChat.d.ts +22 -0
  89. package/dist/tui/hooks/useChat.d.ts.map +1 -1
  90. package/dist/tui/hooks/useChat.js +82 -46
  91. package/dist/tui/hooks/useChat.js.map +1 -1
  92. package/dist/tui/hooks/useCommands.d.ts.map +1 -1
  93. package/dist/tui/hooks/useCommands.js +57 -0
  94. package/dist/tui/hooks/useCommands.js.map +1 -1
  95. package/dist/tui/welcome.d.ts.map +1 -1
  96. package/dist/tui/welcome.js +2 -3
  97. package/dist/tui/welcome.js.map +1 -1
  98. package/dist/types.d.ts +79 -6
  99. package/dist/types.d.ts.map +1 -1
  100. package/dist/types.js +7 -0
  101. package/dist/types.js.map +1 -1
  102. package/dist/utils/stableStringify.d.ts +21 -0
  103. package/dist/utils/stableStringify.d.ts.map +1 -0
  104. package/dist/utils/stableStringify.js +53 -0
  105. package/dist/utils/stableStringify.js.map +1 -0
  106. package/dist/utils/thinking.d.ts.map +1 -1
  107. package/dist/utils/thinking.js +0 -3
  108. package/dist/utils/thinking.js.map +1 -1
  109. package/package.json +6 -6
  110. package/src/app/index.ts +180 -124
  111. package/src/cache/fingerprint.ts +101 -0
  112. package/src/cache/index.ts +15 -0
  113. package/src/cache/smartModel.ts +52 -0
  114. package/src/cache/stats.ts +199 -0
  115. package/src/cache/volatile.ts +47 -0
  116. package/src/cmd/index.tsx +288 -292
  117. package/src/config/index.ts +156 -148
  118. package/src/config/providers.ts +234 -234
  119. package/src/config/types.ts +67 -53
  120. package/src/hooks/index.ts +111 -111
  121. package/src/llm/anthropic.ts +388 -243
  122. package/src/llm/gemini.ts +169 -169
  123. package/src/llm/index.ts +265 -200
  124. package/src/llm/openai.ts +243 -196
  125. package/src/llm/provider.ts +66 -34
  126. package/src/prompts/index.ts +260 -220
  127. package/src/session/compactor.ts +103 -103
  128. package/src/session/index.ts +181 -168
  129. package/src/session/message.ts +42 -42
  130. package/src/skills/brainstorming.ts +43 -43
  131. package/src/skills/code-review.ts +45 -45
  132. package/src/skills/executing-plans.ts +27 -27
  133. package/src/skills/frontend-design.ts +35 -35
  134. package/src/skills/git-workflow.ts +36 -36
  135. package/src/skills/improve-architecture.ts +38 -38
  136. package/src/skills/index.ts +136 -136
  137. package/src/skills/neuroweave.ts +47 -47
  138. package/src/skills/playwright.ts +72 -72
  139. package/src/skills/prototype.ts +30 -30
  140. package/src/skills/subagent.ts +28 -28
  141. package/src/skills/supabase.ts +44 -44
  142. package/src/skills/systematic-debugging.ts +44 -44
  143. package/src/skills/tdd.ts +39 -39
  144. package/src/skills/triage.ts +35 -35
  145. package/src/skills/verification.ts +31 -31
  146. package/src/skills/writing-plans.ts +42 -42
  147. package/src/tools/nwt.ts +598 -598
  148. package/src/tools/types.ts +122 -122
  149. package/src/tui/app.tsx +199 -186
  150. package/src/tui/components/ChatList.tsx +41 -41
  151. package/src/tui/components/ChatMessage.tsx +54 -54
  152. package/src/tui/components/Header.tsx +56 -29
  153. package/src/tui/components/InitWizard.tsx +217 -132
  154. package/src/tui/components/Markdown.tsx +35 -35
  155. package/src/tui/components/ModelSelector.tsx +87 -87
  156. package/src/tui/components/StatusBar.tsx +30 -30
  157. package/src/tui/components/Thinking.tsx +17 -17
  158. package/src/tui/components/ToolCall.tsx +102 -107
  159. package/src/tui/components/UserInput.tsx +131 -131
  160. package/src/tui/hooks/useChat.ts +287 -238
  161. package/src/tui/hooks/useCommands.ts +234 -176
  162. package/src/tui/index.ts +6 -6
  163. package/src/tui/welcome.ts +177 -178
  164. package/src/types.ts +104 -42
  165. package/src/utils/diff.ts +71 -71
  166. package/src/utils/project.ts +99 -99
  167. package/src/utils/stableStringify.ts +47 -0
  168. package/src/utils/thinking.ts +118 -121
  169. package/tests/cache/fingerprint.test.ts +75 -0
  170. package/tests/cache/stableStringify.test.ts +43 -0
  171. package/tests/cache/stats.test.ts +146 -0
  172. package/tests/cache/volatile.test.ts +75 -0
  173. package/tests/smoke-pollution.mjs +78 -0
  174. package/tests/smoke-thinking.mjs +110 -0
  175. package/tests/smoke-tool-stream.mjs +69 -0
  176. package/tests/smoke-tool.mjs +117 -0
  177. package/.nwt/meta.json +0 -5
  178. package/dist/version.d.ts +0 -16
  179. package/dist/version.d.ts.map +0 -1
  180. package/dist/version.js +0 -16
  181. package/dist/version.js.map +0 -1
  182. 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
+ }