codeep 2.13.2 → 2.15.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 (62) hide show
  1. package/README.md +35 -24
  2. package/dist/acp/commands.js +22 -1
  3. package/dist/acp/server.js +278 -251
  4. package/dist/config/index.d.ts +10 -0
  5. package/dist/config/index.js +2 -2
  6. package/dist/config/providers.js +35 -22
  7. package/dist/renderer/App.d.ts +0 -30
  8. package/dist/renderer/App.js +149 -659
  9. package/dist/renderer/agentExecution.d.ts +2 -1
  10. package/dist/renderer/agentExecution.js +10 -6
  11. package/dist/renderer/commands/helpers.d.ts +63 -0
  12. package/dist/renderer/commands/helpers.js +108 -0
  13. package/dist/renderer/commands/registry.js +5 -0
  14. package/dist/renderer/commands.d.ts +4 -0
  15. package/dist/renderer/commands.js +183 -64
  16. package/dist/renderer/components/ActionFormatting.d.ts +17 -0
  17. package/dist/renderer/components/ActionFormatting.js +67 -0
  18. package/dist/renderer/components/Autocomplete.d.ts +33 -0
  19. package/dist/renderer/components/Autocomplete.js +40 -0
  20. package/dist/renderer/components/Intro.d.ts +9 -0
  21. package/dist/renderer/components/Intro.js +5 -15
  22. package/dist/renderer/components/MessageFormatter.d.ts +96 -0
  23. package/dist/renderer/components/MessageFormatter.js +375 -0
  24. package/dist/renderer/components/Permission.d.ts +4 -0
  25. package/dist/renderer/components/Permission.js +1 -1
  26. package/dist/renderer/components/Status.d.ts +4 -0
  27. package/dist/renderer/components/Status.js +2 -3
  28. package/dist/renderer/components/WelcomeFormatter.d.ts +19 -0
  29. package/dist/renderer/components/WelcomeFormatter.js +79 -0
  30. package/dist/renderer/components/uiConstants.d.ts +8 -0
  31. package/dist/renderer/components/uiConstants.js +24 -0
  32. package/dist/renderer/inputParsing.d.ts +22 -0
  33. package/dist/renderer/inputParsing.js +28 -0
  34. package/dist/renderer/layout.d.ts +215 -0
  35. package/dist/renderer/layout.js +326 -0
  36. package/dist/renderer/main.d.ts +2 -1
  37. package/dist/renderer/main.js +45 -10
  38. package/dist/renderer/ollamaHint.d.ts +12 -0
  39. package/dist/renderer/ollamaHint.js +29 -0
  40. package/dist/utils/agentChat.js +28 -2
  41. package/dist/utils/codeepCloud.d.ts +54 -0
  42. package/dist/utils/codeepCloud.js +95 -0
  43. package/dist/utils/export.d.ts +12 -0
  44. package/dist/utils/export.js +3 -3
  45. package/dist/utils/hooks.d.ts +26 -0
  46. package/dist/utils/hooks.js +69 -1
  47. package/dist/utils/keychain.js +45 -29
  48. package/dist/utils/logger.d.ts +12 -0
  49. package/dist/utils/logger.js +1 -1
  50. package/dist/utils/mcpConfig.d.ts +26 -0
  51. package/dist/utils/mcpConfig.js +109 -4
  52. package/dist/utils/skillBundles.d.ts +14 -0
  53. package/dist/utils/skillBundles.js +3 -3
  54. package/dist/utils/skillBundlesCloud.d.ts +7 -0
  55. package/dist/utils/skillBundlesCloud.js +1 -1
  56. package/dist/utils/tokenTracker.d.ts +30 -3
  57. package/dist/utils/tokenTracker.js +71 -13
  58. package/dist/utils/toolParsing.d.ts +11 -0
  59. package/dist/utils/toolParsing.js +6 -0
  60. package/dist/version.d.ts +1 -1
  61. package/dist/version.js +1 -1
  62. package/package.json +2 -2
@@ -46,6 +46,18 @@ export declare function getPricingTable(): {
46
46
  inputPer1M: number;
47
47
  outputPer1M: number;
48
48
  }[];
49
+ /** An isolated token-record buffer for one scope (e.g. one ACP session). */
50
+ export type TokenScope = TokenRecord[];
51
+ /** Create a fresh, empty scope buffer (one per ACP session). */
52
+ export declare function createTokenScope(): TokenScope;
53
+ /**
54
+ * Run `fn` with `scope` as the active token-record buffer. Every
55
+ * recordTokenUsage() call made within `fn`'s async flow (including across
56
+ * awaits) accumulates into `scope`, and reads (getCostBreakdown/…) made in the
57
+ * same flow see only `scope`. Used by the ACP server to isolate per-session
58
+ * usage without threading a session id through the deep API layer.
59
+ */
60
+ export declare function runWithTokenScope<T>(scope: TokenScope, fn: () => T): T;
49
61
  /**
50
62
  * Record token usage from an API response. The optional `actualCostUsd`
51
63
  * argument lets aggregator providers (OpenRouter) pass through the
@@ -76,9 +88,14 @@ export interface ProviderCostBreakdown {
76
88
  estimatedCost: number;
77
89
  }
78
90
  /**
79
- * Get cost breakdown grouped by provider/model
91
+ * Get cost breakdown grouped by provider/model.
92
+ *
93
+ * `startIndex` lets callers price only the records appended since a marker (see
94
+ * getRecordCount) — used to report a single run/prompt's delta to cloud
95
+ * telemetry WITHOUT wiping the session-cumulative store the status bar and
96
+ * `/cost` read. Defaults to 0 (the whole current scope).
80
97
  */
81
- export declare function getCostBreakdown(): ProviderCostBreakdown[];
98
+ export declare function getCostBreakdown(startIndex?: number): ProviderCostBreakdown[];
82
99
  /**
83
100
  * Aggregate Anthropic prompt-caching stats for the current session.
84
101
  * Returns the breakdown plus an estimate of what the input billing would
@@ -105,7 +122,17 @@ export declare function getLastUsage(): TokenRecord | null;
105
122
  */
106
123
  export declare function formatTokenCount(tokens: number): string;
107
124
  /**
108
- * Reset session tracking
125
+ * Number of records in the current scope. Capture before a run/prompt and pass
126
+ * it to getCostBreakdown(startIndex) to price just that run's delta (for cloud
127
+ * telemetry) without wiping the cumulative store the status bar and `/cost`
128
+ * read.
129
+ */
130
+ export declare function getRecordCount(): number;
131
+ /**
132
+ * Reset the current scope's tracking. Production run/prompt paths no longer
133
+ * call this (they use getRecordCount + getCostBreakdown(startIndex) so the
134
+ * session-cumulative totals survive); retained for the test suite, which uses
135
+ * it to isolate the process-wide default buffer between cases.
109
136
  */
110
137
  export declare function resetTokenTracking(): void;
111
138
  /**
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Token and cost tracking for API usage
3
3
  */
4
+ import { AsyncLocalStorage } from 'node:async_hooks';
4
5
  // Context window sizes per model (in tokens).
5
6
  // Keep this table in lockstep with `providers.ts` — entries for models that
6
7
  // aren't in the provider catalogue only show up if a user types an id by hand
@@ -10,12 +11,17 @@ const MODEL_CONTEXT_WINDOWS = {
10
11
  'glm-5.2': 200_000,
11
12
  'glm-5-turbo': 202_752,
12
13
  // OpenAI
14
+ 'gpt-5.6-sol': 1_050_000,
15
+ 'gpt-5.6-terra': 1_050_000,
16
+ 'gpt-5.6-luna': 1_050_000,
13
17
  'gpt-5.5': 1_200_000,
14
18
  'gpt-5.4': 1_050_000,
15
19
  'gpt-5.4-mini': 400_000,
16
20
  // Anthropic
21
+ 'claude-fable-5': 1_000_000,
17
22
  'claude-opus-4-8': 1_000_000,
18
23
  'claude-sonnet-4-6': 1_000_000,
24
+ 'claude-sonnet-5': 1_000_000,
19
25
  'claude-haiku-4-5-20251001': 200_000,
20
26
  // DeepSeek
21
27
  'deepseek-v4-pro': 1_000_000,
@@ -23,6 +29,7 @@ const MODEL_CONTEXT_WINDOWS = {
23
29
  // Google
24
30
  'gemini-3.1-pro-preview': 1_048_576,
25
31
  'gemini-3.5-flash': 1_000_000,
32
+ 'gemini-3.1-flash-lite': 1_048_576,
26
33
  'gemini-3-flash-preview': 1_000_000,
27
34
  // MiniMax
28
35
  'MiniMax-M3': 524_288,
@@ -33,6 +40,7 @@ const MODEL_CONTEXT_WINDOWS = {
33
40
  'kimi-k2.5': 262_144,
34
41
  'kimi-for-coding': 262_144,
35
42
  // Grok (xAI)
43
+ 'grok-4.5': 500_000,
36
44
  'grok-build-0.1': 256_000,
37
45
  'grok-4.3': 1_000_000,
38
46
  'grok-code-fast-1': 256_000,
@@ -41,7 +49,7 @@ const MODEL_CONTEXT_WINDOWS = {
41
49
  'qwen3-coder-plus': 262_144,
42
50
  'qwen3-coder-next': 262_144,
43
51
  'qwen3-coder-flash': 262_144,
44
- 'qwen3-max': 262_144,
52
+ 'qwen3.7-max': 1_000_000,
45
53
  'Qwen/Qwen3-Coder-480B-A35B-Instruct': 262_144,
46
54
  };
47
55
  const DEFAULT_CONTEXT_WINDOW = 128_000;
@@ -63,12 +71,17 @@ const MODEL_PRICING = {
63
71
  'glm-5.2': { inputPer1M: 1.00, outputPer1M: 3.20 },
64
72
  'glm-5-turbo': { inputPer1M: 1.20, outputPer1M: 4.00 },
65
73
  // OpenAI
74
+ 'gpt-5.6-sol': { inputPer1M: 5.00, outputPer1M: 30.00 },
75
+ 'gpt-5.6-terra': { inputPer1M: 2.50, outputPer1M: 15.00 },
76
+ 'gpt-5.6-luna': { inputPer1M: 1.00, outputPer1M: 6.00 },
66
77
  'gpt-5.5': { inputPer1M: 5.00, outputPer1M: 30.00 },
67
78
  'gpt-5.4': { inputPer1M: 2.50, outputPer1M: 15.00 },
68
79
  'gpt-5.4-mini': { inputPer1M: 0.75, outputPer1M: 4.50 },
69
80
  // Anthropic
81
+ 'claude-fable-5': { inputPer1M: 10.00, outputPer1M: 50.00 },
70
82
  'claude-opus-4-8': { inputPer1M: 5.00, outputPer1M: 25.00 },
71
83
  'claude-sonnet-4-6': { inputPer1M: 3.00, outputPer1M: 15.00 },
84
+ 'claude-sonnet-5': { inputPer1M: 3.00, outputPer1M: 15.00 },
72
85
  'claude-haiku-4-5-20251001': { inputPer1M: 1.00, outputPer1M: 5.00 },
73
86
  // DeepSeek (cache-miss input pricing)
74
87
  'deepseek-v4-pro': { inputPer1M: 1.74, outputPer1M: 3.48 },
@@ -76,6 +89,7 @@ const MODEL_PRICING = {
76
89
  // Google
77
90
  'gemini-3.1-pro-preview': { inputPer1M: 2.00, outputPer1M: 12.00 },
78
91
  'gemini-3.5-flash': { inputPer1M: 1.50, outputPer1M: 9.00 },
92
+ 'gemini-3.1-flash-lite': { inputPer1M: 0.25, outputPer1M: 1.50 },
79
93
  'gemini-3-flash-preview': { inputPer1M: 0.50, outputPer1M: 3.00 },
80
94
  // MiniMax
81
95
  'MiniMax-M3': { inputPer1M: 0.60, outputPer1M: 2.40 },
@@ -87,6 +101,7 @@ const MODEL_PRICING = {
87
101
  'kimi-k2.5': { inputPer1M: 0.40, outputPer1M: 1.90 },
88
102
  'kimi-for-coding': { inputPer1M: 0.60, outputPer1M: 2.50 },
89
103
  // Grok (xAI)
104
+ 'grok-4.5': { inputPer1M: 2.00, outputPer1M: 6.00 },
90
105
  'grok-build-0.1': { inputPer1M: 1.00, outputPer1M: 2.00 },
91
106
  'grok-4.3': { inputPer1M: 1.25, outputPer1M: 2.50 },
92
107
  'grok-code-fast-1': { inputPer1M: 0.20, outputPer1M: 1.50 },
@@ -96,15 +111,34 @@ const MODEL_PRICING = {
96
111
  'qwen3-coder-plus': { inputPer1M: 0.28, outputPer1M: 1.65 },
97
112
  'qwen3-coder-next': { inputPer1M: 0.28, outputPer1M: 1.65 },
98
113
  'qwen3-coder-flash': { inputPer1M: 0.10, outputPer1M: 0.50 },
99
- 'qwen3-max': { inputPer1M: 1.20, outputPer1M: 6.00 },
114
+ 'qwen3.7-max': { inputPer1M: 2.50, outputPer1M: 7.50 },
100
115
  // ModelScope free tier — no per-token charge.
101
116
  'Qwen/Qwen3-Coder-480B-A35B-Instruct': { inputPer1M: 0, outputPer1M: 0 },
102
117
  };
103
118
  export function getPricingTable() {
104
119
  return Object.entries(MODEL_PRICING).map(([model, p]) => ({ model, ...p }));
105
120
  }
106
- // Session-level accumulator
107
- const records = [];
121
+ const defaultRecords = [];
122
+ const recordsStore = new AsyncLocalStorage();
123
+ /** The record buffer for the current async flow (a scope's buffer inside
124
+ * runWithTokenScope, otherwise the process-wide default). */
125
+ function currentRecords() {
126
+ return recordsStore.getStore() ?? defaultRecords;
127
+ }
128
+ /** Create a fresh, empty scope buffer (one per ACP session). */
129
+ export function createTokenScope() {
130
+ return [];
131
+ }
132
+ /**
133
+ * Run `fn` with `scope` as the active token-record buffer. Every
134
+ * recordTokenUsage() call made within `fn`'s async flow (including across
135
+ * awaits) accumulates into `scope`, and reads (getCostBreakdown/…) made in the
136
+ * same flow see only `scope`. Used by the ACP server to isolate per-session
137
+ * usage without threading a session id through the deep API layer.
138
+ */
139
+ export function runWithTokenScope(scope, fn) {
140
+ return recordsStore.run(scope, fn);
141
+ }
108
142
  /**
109
143
  * Record token usage from an API response. The optional `actualCostUsd`
110
144
  * argument lets aggregator providers (OpenRouter) pass through the
@@ -113,7 +147,7 @@ const records = [];
113
147
  * for every OpenRouter-listed model — there are 100+).
114
148
  */
115
149
  export function recordTokenUsage(usage, model, provider, actualCostUsd) {
116
- records.push({
150
+ currentRecords().push({
117
151
  timestamp: Date.now(),
118
152
  promptTokens: usage.promptTokens,
119
153
  completionTokens: usage.completionTokens,
@@ -130,10 +164,16 @@ export function recordTokenUsage(usage, model, provider, actualCostUsd) {
130
164
  */
131
165
  export function extractOpenAIUsage(data) {
132
166
  if (data?.usage) {
167
+ // OpenAI-protocol `prompt_tokens` is INCLUSIVE of cached prompt tokens
168
+ // (DeepSeek/OpenAI report cache hits in prompt_tokens_details.cached_tokens).
169
+ // Surface them so getCostBreakdown bills cache reads at the discounted
170
+ // rate instead of the full cache-miss input rate.
171
+ const cached = data.usage.prompt_tokens_details?.cached_tokens || 0;
133
172
  return {
134
173
  promptTokens: data.usage.prompt_tokens || 0,
135
174
  completionTokens: data.usage.completion_tokens || 0,
136
175
  totalTokens: data.usage.total_tokens || 0,
176
+ cacheReadTokens: cached || undefined,
137
177
  };
138
178
  }
139
179
  return null;
@@ -161,11 +201,16 @@ export function extractAnthropicUsage(data) {
161
201
  return null;
162
202
  }
163
203
  /**
164
- * Get cost breakdown grouped by provider/model
204
+ * Get cost breakdown grouped by provider/model.
205
+ *
206
+ * `startIndex` lets callers price only the records appended since a marker (see
207
+ * getRecordCount) — used to report a single run/prompt's delta to cloud
208
+ * telemetry WITHOUT wiping the session-cumulative store the status bar and
209
+ * `/cost` read. Defaults to 0 (the whole current scope).
165
210
  */
166
- export function getCostBreakdown() {
211
+ export function getCostBreakdown(startIndex = 0) {
167
212
  const grouped = new Map();
168
- for (const record of records) {
213
+ for (const record of currentRecords().slice(startIndex)) {
169
214
  const key = `${record.provider}/${record.model}`;
170
215
  const existing = grouped.get(key) ?? { provider: record.provider, model: record.model, promptTokens: 0, completionTokens: 0, cacheCreationTokens: 0, cacheReadTokens: 0, estimatedCost: 0 };
171
216
  existing.promptTokens += record.promptTokens;
@@ -203,7 +248,7 @@ export function getCacheStats() {
203
248
  let cacheCreate = 0;
204
249
  let cacheRead = 0;
205
250
  let savings = 0;
206
- for (const record of records) {
251
+ for (const record of currentRecords()) {
207
252
  cacheCreate += record.cacheCreationTokens ?? 0;
208
253
  cacheRead += record.cacheReadTokens ?? 0;
209
254
  // Savings = what cache-read tokens would have cost at full input rate,
@@ -227,7 +272,7 @@ export function getSessionStats() {
227
272
  let totalTokens = 0;
228
273
  let totalCacheCreationTokens = 0;
229
274
  let totalCacheReadTokens = 0;
230
- for (const record of records) {
275
+ for (const record of currentRecords()) {
231
276
  totalPromptTokens += record.promptTokens;
232
277
  totalCompletionTokens += record.completionTokens;
233
278
  totalTokens += record.totalTokens;
@@ -239,7 +284,7 @@ export function getSessionStats() {
239
284
  totalPromptTokens,
240
285
  totalCompletionTokens,
241
286
  totalTokens,
242
- requestCount: records.length,
287
+ requestCount: currentRecords().length,
243
288
  estimatedCost,
244
289
  totalCacheCreationTokens,
245
290
  totalCacheReadTokens,
@@ -249,6 +294,7 @@ export function getSessionStats() {
249
294
  * Get last request usage
250
295
  */
251
296
  export function getLastUsage() {
297
+ const records = currentRecords();
252
298
  return records.length > 0 ? records[records.length - 1] : null;
253
299
  }
254
300
  /**
@@ -262,10 +308,22 @@ export function formatTokenCount(tokens) {
262
308
  return (tokens / 1000000).toFixed(2) + 'M';
263
309
  }
264
310
  /**
265
- * Reset session tracking
311
+ * Number of records in the current scope. Capture before a run/prompt and pass
312
+ * it to getCostBreakdown(startIndex) to price just that run's delta (for cloud
313
+ * telemetry) without wiping the cumulative store the status bar and `/cost`
314
+ * read.
315
+ */
316
+ export function getRecordCount() {
317
+ return currentRecords().length;
318
+ }
319
+ /**
320
+ * Reset the current scope's tracking. Production run/prompt paths no longer
321
+ * call this (they use getRecordCount + getCostBreakdown(startIndex) so the
322
+ * session-cumulative totals survive); retained for the test suite, which uses
323
+ * it to isolate the process-wide default buffer between cases.
266
324
  */
267
325
  export function resetTokenTracking() {
268
- records.length = 0;
326
+ currentRecords().length = 0;
269
327
  }
270
328
  /**
271
329
  * Format a session cost report as a Markdown block. Used by `/cost` in both
@@ -9,10 +9,21 @@ import { ToolCall } from './tools';
9
9
  * Normalize tool name to lowercase with underscores
10
10
  */
11
11
  export declare function normalizeToolName(name: string): string;
12
+ /**
13
+ * Extract parameters from truncated/partial JSON for tool calls.
14
+ * Fallback when JSON.parse fails due to API truncation.
15
+ */
16
+ declare function extractPartialToolParams(toolName: string, rawArgs: string): Record<string, unknown> | null;
12
17
  export declare function parseOpenAIToolCalls(toolCalls: unknown[]): ToolCall[];
13
18
  export declare function parseAnthropicToolCalls(content: unknown[]): ToolCall[];
19
+ declare function tryExtractParams(str: string): Record<string, unknown> | null;
20
+ declare function tryParseToolCall(str: string): ToolCall | null;
14
21
  /**
15
22
  * Parse tool calls from LLM response text.
16
23
  * Supports: <tool_call>, <toolcall>, ```tool blocks, inline JSON.
17
24
  */
18
25
  export declare function parseToolCalls(response: string): ToolCall[];
26
+ export declare const _extractPartialToolParamsForTest: typeof extractPartialToolParams;
27
+ export declare const _tryExtractParamsForTest: typeof tryExtractParams;
28
+ export declare const _tryParseToolCallForTest: typeof tryParseToolCall;
29
+ export {};
@@ -319,3 +319,9 @@ export function parseToolCalls(response) {
319
319
  }
320
320
  return toolCalls;
321
321
  }
322
+ // Test seams — these helpers are otherwise file-private; export them under
323
+ // a `_forTest` suffix so the parser internals can be exercised directly
324
+ // without going through the full response-parsing pipeline.
325
+ export const _extractPartialToolParamsForTest = extractPartialToolParams;
326
+ export const _tryExtractParamsForTest = tryExtractParams;
327
+ export const _tryParseToolCallForTest = tryParseToolCall;
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "2.13.2";
1
+ export declare const VERSION = "2.15.0";
package/dist/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  // AUTO-GENERATED by scripts/gen-version.js — do not edit by hand.
2
2
  // Baked from package.json at build time so the bun-compiled binary reports
3
3
  // the right version (it has no package.json on disk to read at runtime).
4
- export const VERSION = '2.13.2';
4
+ export const VERSION = '2.15.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeep",
3
- "version": "2.13.2",
3
+ "version": "2.15.0",
4
4
  "description": "AI-powered coding assistant built for the terminal. Multiple LLM providers, project-aware context, and a seamless development workflow.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -37,10 +37,10 @@
37
37
  },
38
38
  "homepage": "https://codeep.dev",
39
39
  "dependencies": {
40
+ "@napi-rs/keyring": "^1.3.0",
40
41
  "clipboardy": "^4.0.0",
41
42
  "conf": "^13.1.0",
42
43
  "js-yaml": "^4.1.0",
43
- "keytar": "^7.9.0",
44
44
  "open": "^10.0.0"
45
45
  },
46
46
  "devDependencies": {