codeep 3.3.0 → 3.3.2
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.
- package/dist/config/index.d.ts +13 -0
- package/dist/config/index.js +10 -2
- package/dist/renderer/commands/helpers.d.ts +4 -0
- package/dist/renderer/commands/helpers.js +2 -1
- package/dist/renderer/commands/registry.d.ts +23 -6
- package/dist/renderer/commands/registry.js +128 -26
- package/dist/renderer/commands.js +18 -11
- package/dist/utils/tokenTracker.d.ts +18 -0
- package/dist/utils/tokenTracker.js +56 -11
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -1
package/dist/config/index.d.ts
CHANGED
|
@@ -183,6 +183,19 @@ export declare function initializeAsProject(path: string): boolean;
|
|
|
183
183
|
* Check if folder was manually initialized as project
|
|
184
184
|
*/
|
|
185
185
|
export declare function isManuallyInitializedProject(path: string): boolean;
|
|
186
|
+
/**
|
|
187
|
+
* Create config with fallback logic
|
|
188
|
+
* 1. Try standard Conf location (~/.config/codeep-nodejs on Linux, etc.)
|
|
189
|
+
* 2. If not writable, use .codeep in current working directory
|
|
190
|
+
*/
|
|
191
|
+
/**
|
|
192
|
+
* What a fresh install starts on. Exported so a test can hold the pair to the
|
|
193
|
+
* catalogue: the model had stayed `glm-5.2` after Z.AI's default moved to
|
|
194
|
+
* `glm-5.3`, so new users started a flagship behind what the website promised,
|
|
195
|
+
* and nothing failed because 5.2 still works.
|
|
196
|
+
*/
|
|
197
|
+
export declare const DEFAULT_PROVIDER = "z.ai";
|
|
198
|
+
export declare const DEFAULT_MODEL = "glm-5.3";
|
|
186
199
|
export declare const config: Conf<ConfigSchema>;
|
|
187
200
|
export declare const LANGUAGES: Record<string, string>;
|
|
188
201
|
export declare const PROTOCOLS: Record<string, string>;
|
package/dist/config/index.js
CHANGED
|
@@ -138,12 +138,20 @@ function isWritable(dir) {
|
|
|
138
138
|
* 1. Try standard Conf location (~/.config/codeep-nodejs on Linux, etc.)
|
|
139
139
|
* 2. If not writable, use .codeep in current working directory
|
|
140
140
|
*/
|
|
141
|
+
/**
|
|
142
|
+
* What a fresh install starts on. Exported so a test can hold the pair to the
|
|
143
|
+
* catalogue: the model had stayed `glm-5.2` after Z.AI's default moved to
|
|
144
|
+
* `glm-5.3`, so new users started a flagship behind what the website promised,
|
|
145
|
+
* and nothing failed because 5.2 still works.
|
|
146
|
+
*/
|
|
147
|
+
export const DEFAULT_PROVIDER = 'z.ai';
|
|
148
|
+
export const DEFAULT_MODEL = 'glm-5.3';
|
|
141
149
|
function createConfig() {
|
|
142
150
|
const defaults = {
|
|
143
151
|
apiKey: '',
|
|
144
152
|
migrationVersion: 0,
|
|
145
|
-
provider:
|
|
146
|
-
model:
|
|
153
|
+
provider: DEFAULT_PROVIDER,
|
|
154
|
+
model: DEFAULT_MODEL,
|
|
147
155
|
agentMode: 'on',
|
|
148
156
|
ollamaUrl: 'http://localhost:11434',
|
|
149
157
|
ollamaNativeApi: false,
|
|
@@ -85,6 +85,10 @@ export interface StatsCache {
|
|
|
85
85
|
cacheReadTokens: number;
|
|
86
86
|
cacheCreationTokens: number;
|
|
87
87
|
estimatedSavingsUsd: number;
|
|
88
|
+
/** Rates that applied, from getCacheStats. Absent → no rate is quoted rather
|
|
89
|
+
* than assuming Anthropic's 0.1×, which was wrong for DeepSeek, Kimi, Qwen
|
|
90
|
+
* and Fable 5.1. */
|
|
91
|
+
cacheReadRates?: number[];
|
|
88
92
|
}
|
|
89
93
|
export interface PricingRow {
|
|
90
94
|
model: string;
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* coverage.
|
|
9
9
|
*/
|
|
10
10
|
import { isFlatFeeProvider } from '../../config/providers.js';
|
|
11
|
+
import { formatCacheReadRates } from '../../utils/tokenTracker.js';
|
|
11
12
|
/** Snippet window: chars of context before / after the match. */
|
|
12
13
|
export const SEARCH_SNIPPET_BEFORE = 30;
|
|
13
14
|
export const SEARCH_SNIPPET_AFTER = 50;
|
|
@@ -166,7 +167,7 @@ export function formatStatsReport(args) {
|
|
|
166
167
|
}
|
|
167
168
|
if (cache.cacheReadTokens > 0 || cache.cacheCreationTokens > 0) {
|
|
168
169
|
lines.push('', '### Prompt caching');
|
|
169
|
-
lines.push(`Cache reads: ${fmt(cache.cacheReadTokens)} tokens
|
|
170
|
+
lines.push(`Cache reads: ${fmt(cache.cacheReadTokens)} tokens${formatCacheReadRates(cache.cacheReadRates ?? [])}`);
|
|
170
171
|
if (cache.cacheCreationTokens > 0) {
|
|
171
172
|
lines.push(`Cache writes: ${fmt(cache.cacheCreationTokens)} tokens (billed at 1.25× input rate)`);
|
|
172
173
|
}
|
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Single source of truth for Codeep slash commands.
|
|
2
|
+
* Single source of truth for Codeep's TUI slash commands.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* `
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* The `/` autocomplete in `App.ts` and alias resolution in the dispatcher
|
|
5
|
+
* (`commands.ts`) derive from this registry. Adding a command means:
|
|
6
|
+
*
|
|
7
|
+
* 1. an entry in `COMMANDS` below;
|
|
8
|
+
* 2. a handler — a `case` in `renderer/commands.ts`, a `case` in `App.ts`, or
|
|
9
|
+
* a built-in skill of the same name;
|
|
10
|
+
* 3. a row in `HELP_LAYOUT` at the bottom of this file;
|
|
11
|
+
* 4. `npm run export:commands`, which regenerates the website's command
|
|
12
|
+
* reference (`Codeep-web/src/data/commands.json`) from this file.
|
|
13
|
+
*
|
|
14
|
+
* `registry.test.ts` fails if 2 or 3 is missed: a command offered in the
|
|
15
|
+
* autocomplete with no handler answers "Unknown command" (this is how
|
|
16
|
+
* `/account` shipped broken), and one missing from `HELP_LAYOUT` is invisible
|
|
17
|
+
* in `/help` and on the website.
|
|
18
|
+
*
|
|
19
|
+
* The ACP server (VS Code, Zed) is NOT derived from here: it keeps its own
|
|
20
|
+
* `AVAILABLE_COMMANDS` list in `acp/server.ts` and resolves its own aliases,
|
|
21
|
+
* so a command added here is not automatically offered to editors.
|
|
9
22
|
*
|
|
10
23
|
* ## What lives here vs. elsewhere
|
|
11
24
|
*
|
|
@@ -76,7 +89,11 @@ export declare const ALL_ALIASES: ReadonlySet<string>;
|
|
|
76
89
|
export interface HelpItemSpec {
|
|
77
90
|
/** Visible key in `/help`, including the leading `/`. */
|
|
78
91
|
key: string;
|
|
92
|
+
/** One line, sized for the terminal. */
|
|
79
93
|
description: string;
|
|
94
|
+
/** Longer explanation used on the website's command reference instead of
|
|
95
|
+
* `description`, where a terminal row is too short to say what matters. */
|
|
96
|
+
web?: string;
|
|
80
97
|
}
|
|
81
98
|
export interface HelpCategorySpec {
|
|
82
99
|
title: string;
|
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Single source of truth for Codeep slash commands.
|
|
2
|
+
* Single source of truth for Codeep's TUI slash commands.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* `
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* The `/` autocomplete in `App.ts` and alias resolution in the dispatcher
|
|
5
|
+
* (`commands.ts`) derive from this registry. Adding a command means:
|
|
6
|
+
*
|
|
7
|
+
* 1. an entry in `COMMANDS` below;
|
|
8
|
+
* 2. a handler — a `case` in `renderer/commands.ts`, a `case` in `App.ts`, or
|
|
9
|
+
* a built-in skill of the same name;
|
|
10
|
+
* 3. a row in `HELP_LAYOUT` at the bottom of this file;
|
|
11
|
+
* 4. `npm run export:commands`, which regenerates the website's command
|
|
12
|
+
* reference (`Codeep-web/src/data/commands.json`) from this file.
|
|
13
|
+
*
|
|
14
|
+
* `registry.test.ts` fails if 2 or 3 is missed: a command offered in the
|
|
15
|
+
* autocomplete with no handler answers "Unknown command" (this is how
|
|
16
|
+
* `/account` shipped broken), and one missing from `HELP_LAYOUT` is invisible
|
|
17
|
+
* in `/help` and on the website.
|
|
18
|
+
*
|
|
19
|
+
* The ACP server (VS Code, Zed) is NOT derived from here: it keeps its own
|
|
20
|
+
* `AVAILABLE_COMMANDS` list in `acp/server.ts` and resolves its own aliases,
|
|
21
|
+
* so a command added here is not automatically offered to editors.
|
|
9
22
|
*
|
|
10
23
|
* ## What lives here vs. elsewhere
|
|
11
24
|
*
|
|
@@ -67,13 +80,12 @@ export const COMMANDS = [
|
|
|
67
80
|
{ name: 'settings', description: 'Open settings', category: 'general' },
|
|
68
81
|
{ name: 'version', description: 'Show version', category: 'general' },
|
|
69
82
|
{ name: 'update', description: 'Check for updates', category: 'general' },
|
|
70
|
-
{
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
},
|
|
83
|
+
{ name: 'cost', description: 'Token usage & cost this session', category: 'general' },
|
|
84
|
+
// Its own command, not an alias of /cost. From 2026-06-24 it was
|
|
85
|
+
// `aliases: ['stats']` on /cost, and the dispatcher resolves aliases before
|
|
86
|
+
// the switch — so /stats printed the /cost report and its own handler (per-
|
|
87
|
+
// model breakdown, cache summary, pricing table) never ran.
|
|
88
|
+
{ name: 'stats', description: 'Detailed session view — per-model breakdown, cache, and pricing table', category: 'general' },
|
|
77
89
|
{ name: 'clear', description: 'Clear chat', category: 'general', hidden: true },
|
|
78
90
|
{ name: 'exit', description: 'Quit application', category: 'general', hidden: true },
|
|
79
91
|
// ── sessions ───────────────────────────────────────────────────────────────
|
|
@@ -220,7 +232,7 @@ export const COMMANDS = [
|
|
|
220
232
|
{ name: 'commands', description: 'List custom slash commands in .codeep/commands/*.md', category: 'extensions' },
|
|
221
233
|
{ name: 'web-cache', aliases: ['webcache'], description: 'Show @web fetch cache stats (alias: /web-cache clear)', category: 'extensions' },
|
|
222
234
|
// ── cloud & account ────────────────────────────────────────────────────────
|
|
223
|
-
{ name: 'account', description: '
|
|
235
|
+
{ name: 'account', description: 'Show whether this machine is linked to codeep.dev, and how to link it', category: 'cloud' },
|
|
224
236
|
{ name: 'tasks', description: 'List/add/done/delete codeep.dev tasks', category: 'cloud', usage: ['add <title> [--bug|--feature]'] },
|
|
225
237
|
{ name: 'sync', description: 'Sync learning preferences and profiles to codeep.dev', category: 'cloud' },
|
|
226
238
|
{ name: 'telemetry', description: 'Show or toggle automatic cloud telemetry (on/off)', category: 'cloud' },
|
|
@@ -229,7 +241,11 @@ export const COMMANDS = [
|
|
|
229
241
|
{ name: 'context-save', description: 'Save conversation', category: 'cloud', hidden: true },
|
|
230
242
|
{ name: 'context-load', description: 'Load conversation', category: 'cloud', hidden: true },
|
|
231
243
|
{ name: 'context-clear', description: 'Clear saved context', category: 'cloud', hidden: true },
|
|
232
|
-
|
|
244
|
+
// ACP-only. acp/commands.ts handles /save (an editor has no autosave); the TUI
|
|
245
|
+
// saves sessions on its own and has no handler, so this stays hidden — offering
|
|
246
|
+
// it in the terminal would only answer "Unknown command". Registered because
|
|
247
|
+
// registry.test.ts requires every ACP case label to be.
|
|
248
|
+
{ name: 'save', description: 'Save current session (VS Code / Zed only)', category: 'cloud', hidden: true },
|
|
233
249
|
// ── code generation ────────────────────────────────────────────────────────
|
|
234
250
|
{ name: 'build', description: 'Build the project', category: 'codegen' },
|
|
235
251
|
{ name: 'deploy', description: 'Build and deploy', category: 'codegen' },
|
|
@@ -333,7 +349,10 @@ export const HELP_LAYOUT = [
|
|
|
333
349
|
{ key: '/settings', description: 'Open settings' },
|
|
334
350
|
{ key: '/version', description: 'Show version' },
|
|
335
351
|
{ key: '/update', description: 'Check for updates' },
|
|
336
|
-
{ key: '/
|
|
352
|
+
{ key: '/cost', description: 'Token usage & cost this session',
|
|
353
|
+
web: 'Token usage and estimated cost this session, per provider and model, with prompt-cache savings' },
|
|
354
|
+
{ key: '/stats', description: 'Detailed view — per-model breakdown, cache, pricing table',
|
|
355
|
+
web: 'Detailed session view — per-model breakdown, plan-aware totals, prompt-cache reads and writes, and the per-1M pricing table' },
|
|
337
356
|
{ key: '/clear', description: 'Clear chat' },
|
|
338
357
|
{ key: '/exit', description: 'Quit application' },
|
|
339
358
|
],
|
|
@@ -345,11 +364,15 @@ export const HELP_LAYOUT = [
|
|
|
345
364
|
{ key: '/new', description: 'Start new session' },
|
|
346
365
|
{ key: '/rename <name>', description: 'Rename current session' },
|
|
347
366
|
{ key: '/search <term>', description: 'Search the current session' },
|
|
348
|
-
{ key: '/recall <query>', description: 'Search across ALL saved sessions (cross-session)'
|
|
349
|
-
|
|
367
|
+
{ key: '/recall <query>', description: 'Search across ALL saved sessions (cross-session)',
|
|
368
|
+
web: 'Search across all saved sessions, ranked by relevance and recency' },
|
|
369
|
+
{ key: '/recall … --resume', description: 'Load the top-matching session directly',
|
|
370
|
+
web: 'Load the top-matching session directly, skipping the picker' },
|
|
350
371
|
{ key: '/recall … --summarize', description: 'LLM recap of what you did across matches' },
|
|
372
|
+
{ key: '/cloud', description: 'List and resume sessions synced from other devices' },
|
|
351
373
|
{ key: '/export [md|json|txt]', description: 'Export chat' },
|
|
352
|
-
{ key: '/compact [keepN]', description: 'AI-summarize older messages to free up context (keeps last N)'
|
|
374
|
+
{ key: '/compact [keepN]', description: 'AI-summarize older messages to free up context (keeps last N)',
|
|
375
|
+
web: 'AI-summarize older messages to free up context, keeping the last N (default 4)' },
|
|
353
376
|
],
|
|
354
377
|
},
|
|
355
378
|
{
|
|
@@ -357,7 +380,8 @@ export const HELP_LAYOUT = [
|
|
|
357
380
|
items: [
|
|
358
381
|
{ key: '/checkpoint [name]', description: 'Snapshot conversation + provider/model + git HEAD' },
|
|
359
382
|
{ key: '/checkpoints', description: 'List saved checkpoints in this workspace' },
|
|
360
|
-
{ key: '/rewind <id>', description: 'Restore conversation from a checkpoint'
|
|
383
|
+
{ key: '/rewind <id>', description: 'Restore conversation from a checkpoint',
|
|
384
|
+
web: 'Restore a checkpoint — conversation and provider/model; files roll back via the git command printed afterwards' },
|
|
361
385
|
{ key: '/checkpoint delete <id>', description: 'Delete a saved checkpoint' },
|
|
362
386
|
],
|
|
363
387
|
},
|
|
@@ -387,6 +411,9 @@ export const HELP_LAYOUT = [
|
|
|
387
411
|
{ key: '/amend', description: 'Amend last commit' },
|
|
388
412
|
{ key: '/branch', description: 'Create/manage branches' },
|
|
389
413
|
{ key: '/stash', description: 'Stash changes' },
|
|
414
|
+
{ key: '/unstash', description: 'Apply and drop the most recent stash' },
|
|
415
|
+
{ key: '/pr', description: 'Create a pull request description' },
|
|
416
|
+
{ key: '/changelog', description: 'Generate changelog from recent commits' },
|
|
390
417
|
{ key: '/init', description: 'Initialize project (.codeep/ folder)' },
|
|
391
418
|
{ key: '/scan', description: 'Scan project structure' },
|
|
392
419
|
{ key: '/memory <note>', description: 'Add note to project intelligence' },
|
|
@@ -414,19 +441,58 @@ export const HELP_LAYOUT = [
|
|
|
414
441
|
title: 'Skills (Shortcuts)',
|
|
415
442
|
items: [
|
|
416
443
|
{ key: '/test (/t)', description: 'Generate/run tests' },
|
|
444
|
+
{ key: '/test-fix', description: 'Fix failing tests' },
|
|
445
|
+
{ key: '/coverage', description: 'Run/analyze test coverage' },
|
|
446
|
+
{ key: '/e2e', description: 'Generate end-to-end tests' },
|
|
447
|
+
{ key: '/mock', description: 'Generate mock data for testing' },
|
|
417
448
|
{ key: '/docs (/d)', description: 'Open web docs for a command' },
|
|
449
|
+
{ key: '/readme', description: 'Generate or update README' },
|
|
450
|
+
{ key: '/api-docs', description: 'Generate API documentation' },
|
|
418
451
|
{ key: '/refactor (/r)', description: 'Improve code quality' },
|
|
419
452
|
{ key: '/fix (/f)', description: 'Debug and fix issues' },
|
|
420
453
|
{ key: '/explain (/e)', description: 'Explain code' },
|
|
421
454
|
{ key: '/optimize (/o)', description: 'Optimize performance' },
|
|
422
455
|
{ key: '/debug (/b)', description: 'Debug problems' },
|
|
423
456
|
{ key: '/security', description: 'Security audit (SQLi, XSS, secrets, auth)' },
|
|
424
|
-
{ key: '/
|
|
457
|
+
{ key: '/types', description: 'Add or improve TypeScript types' },
|
|
458
|
+
{ key: '/cleanup', description: 'Clean up code (remove unused, format)' },
|
|
459
|
+
{ key: '/modernize', description: 'Update code to use modern syntax' },
|
|
460
|
+
{ key: '/migrate', description: 'Migrate code to newer version' },
|
|
461
|
+
{ key: '/split', description: 'Split a large file into smaller modules' },
|
|
462
|
+
{ key: '/log', description: 'Add logging to code' },
|
|
463
|
+
{ key: '/translate', description: 'Translate code comments to English' },
|
|
464
|
+
{ key: '/skills', description: 'List all skills' },
|
|
465
|
+
{ key: '/skills <query>', description: 'Search skills by keyword' },
|
|
466
|
+
{ key: '/skills bundles', description: 'List skill bundles (project + global)' },
|
|
467
|
+
{ key: '/skills create-bundle <name>', description: 'Scaffold a bundle in .codeep/skills/' },
|
|
468
|
+
{ key: '/skills show <name>', description: "Print a bundle's SKILL.md" },
|
|
469
|
+
{ key: '/skills browse [query]', description: 'Search the marketplace at codeep.dev/skills' },
|
|
470
|
+
{ key: '/skills install <owner>/<slug>', description: 'Install a marketplace bundle into the project' },
|
|
471
|
+
{ key: '/skills publish <name> [--public]', description: 'Share a bundle to codeep.dev' },
|
|
472
|
+
{ key: '/skills unpublish <owner>/<slug>', description: 'Remove a bundle you published' },
|
|
473
|
+
],
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
title: 'Code Generation',
|
|
477
|
+
items: [
|
|
425
478
|
{ key: '/component <name>', description: 'Generate UI component' },
|
|
426
479
|
{ key: '/api <name>', description: 'Generate API endpoint' },
|
|
480
|
+
{ key: '/hook', description: 'Generate a React hook' },
|
|
481
|
+
{ key: '/service', description: 'Generate a service/utility module' },
|
|
482
|
+
{ key: '/page', description: 'Generate a new page/route' },
|
|
483
|
+
{ key: '/form', description: 'Generate a form with validation' },
|
|
484
|
+
{ key: '/crud', description: 'Generate full CRUD for an entity' },
|
|
427
485
|
{ key: '/docker', description: 'Generate Dockerfile + compose' },
|
|
428
|
-
{ key: '/
|
|
429
|
-
{ key: '/
|
|
486
|
+
{ key: '/ci', description: 'Generate CI/CD configuration' },
|
|
487
|
+
{ key: '/env', description: 'Setup environment configuration' },
|
|
488
|
+
{ key: '/k8s', description: 'Generate Kubernetes manifests' },
|
|
489
|
+
{ key: '/terraform', description: 'Generate Terraform configuration' },
|
|
490
|
+
{ key: '/nginx', description: 'Generate Nginx configuration' },
|
|
491
|
+
{ key: '/monitor', description: 'Add monitoring and observability' },
|
|
492
|
+
{ key: '/build', description: 'Build the project' },
|
|
493
|
+
{ key: '/deploy', description: 'Build and deploy' },
|
|
494
|
+
{ key: '/release', description: 'Create a new release' },
|
|
495
|
+
{ key: '/publish', description: 'Publish package to npm' },
|
|
430
496
|
],
|
|
431
497
|
},
|
|
432
498
|
{
|
|
@@ -441,16 +507,33 @@ export const HELP_LAYOUT = [
|
|
|
441
507
|
{ key: '/login', description: 'Login with API key' },
|
|
442
508
|
{ key: '/logout', description: 'Logout from provider' },
|
|
443
509
|
{ key: '/profile save <name>', description: 'Save current provider+model as profile' },
|
|
510
|
+
{ key: '/profile load <name>', description: 'Load a saved profile' },
|
|
444
511
|
{ key: '/profile list', description: 'List saved profiles' },
|
|
445
|
-
{ key: '/
|
|
512
|
+
{ key: '/profile delete <name>', description: 'Delete a saved profile' },
|
|
513
|
+
{ key: '/openrouter', description: 'OpenRouter routing prefs (prefer/ignore providers, fallbacks, privacy)',
|
|
514
|
+
web: 'OpenRouter routing preferences: show, prefer or ignore upstream providers, fallbacks on/off, privacy strict/allow, clear' },
|
|
446
515
|
{ key: '/personality', description: 'List personalities and custom bots with model, tools, and scope' },
|
|
447
516
|
{ key: '/personality <name>', description: 'Activate a personality or custom bot. /personality off to clear.' },
|
|
448
|
-
{ key: '/me', description: 'Your user profile (reply language, style, stack) — adapts the agent to you'
|
|
517
|
+
{ key: '/me', description: 'Your user profile (reply language, style, stack) — adapts the agent to you',
|
|
518
|
+
web: 'Your user profile — reply language, style, stack — injected into every run on every surface' },
|
|
449
519
|
{ key: '/me init [project]', description: 'Scaffold a profile template (global, or for this project). /me off to disable' },
|
|
450
520
|
{ key: '/me learn [on|off]', description: 'Learn durable prefs from this session now; on/off toggles auto-learn. /me forget clears it' },
|
|
451
521
|
{ key: '/me sync', description: 'Push your profile to the codeep.dev dashboard (and pull on a fresh machine)' },
|
|
452
|
-
{ key: '/agents', description: 'List sub-agents the agent can delegate to (researcher / reviewer / tester / your own)'
|
|
522
|
+
{ key: '/agents', description: 'List sub-agents the agent can delegate to (researcher / reviewer / tester / your own)',
|
|
523
|
+
web: 'List the sub-agents the agent can delegate to — planner, researcher, reviewer, tester, or your own in .codeep/agents/' },
|
|
453
524
|
{ key: '/insights [--days N]', description: 'Activity summary — runs, files, tools, projects over the last N days (default 7)' },
|
|
525
|
+
{ key: '/telegram', description: 'Set up answering confirmations on your phone' },
|
|
526
|
+
{ key: '/telegram on|off', description: 'Turn Telegram approvals on or off' },
|
|
527
|
+
{ key: '/audit', description: 'What agents did here — runs, tools, and what the boundary refused' },
|
|
528
|
+
{ key: '/audit on|off', description: 'Turn the project audit record on or off' },
|
|
529
|
+
],
|
|
530
|
+
},
|
|
531
|
+
{
|
|
532
|
+
title: 'Thinking',
|
|
533
|
+
items: [
|
|
534
|
+
{ key: '/thinking (/effort)', description: 'Show the thinking tier and what this model supports' },
|
|
535
|
+
{ key: '/thinking <auto|low|medium|high|max>', description: 'Set how hard the model reasons',
|
|
536
|
+
web: "Set the reasoning-effort tier. Auto uses each model's own default; other tiers are clamped to the levels the current provider and model actually distinguish, so an unsupported value is never sent. Models with no graded control ignore it." },
|
|
454
537
|
],
|
|
455
538
|
},
|
|
456
539
|
{
|
|
@@ -468,6 +551,25 @@ export const HELP_LAYOUT = [
|
|
|
468
551
|
{ key: '/mcp prompt <server> <name>', description: 'Materialize a prompt with arguments (key=value)' },
|
|
469
552
|
{ key: '/hooks', description: 'List installed lifecycle hooks (.codeep/hooks/<event>.sh)' },
|
|
470
553
|
{ key: '/commands', description: 'List custom slash commands (.codeep/commands/*.md)' },
|
|
554
|
+
{ key: '/web-cache', description: 'Show @web fetch cache stats' },
|
|
555
|
+
{ key: '/web-cache clear', description: 'Clear the @web fetch cache' },
|
|
556
|
+
],
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
title: 'Cloud & Account',
|
|
560
|
+
items: [
|
|
561
|
+
{ key: '/account', description: 'Is this machine linked to codeep.dev? How to link it',
|
|
562
|
+
web: 'Show whether this machine is linked to codeep.dev. Linking runs in your shell as `codeep account`, and the approval link it prints can be opened on any device where you are already signed in' },
|
|
563
|
+
{ key: '/tasks', description: 'List codeep.dev tasks' },
|
|
564
|
+
{ key: '/tasks add <title> [--bug|--feature] [--desc <text>]', description: 'Create a task on the dashboard' },
|
|
565
|
+
{ key: '/tasks done <n>', description: 'Mark task #n as done' },
|
|
566
|
+
{ key: '/tasks delete <n>', description: 'Delete task #n' },
|
|
567
|
+
{ key: '/sync', description: 'Sync learning preferences and profiles to codeep.dev' },
|
|
568
|
+
{ key: '/sync learning', description: 'Sync only learning preferences' },
|
|
569
|
+
{ key: '/sync profiles', description: 'Sync only saved profiles' },
|
|
570
|
+
{ key: '/telemetry [on|off]', description: 'Show or toggle automatic cloud telemetry' },
|
|
571
|
+
{ key: '/keysync [on|off]', description: 'Show or toggle syncing API keys to codeep.dev',
|
|
572
|
+
web: 'Show or toggle syncing API keys to codeep.dev. Off by default — keys stay in your OS keychain unless you opt in' },
|
|
471
573
|
],
|
|
472
574
|
},
|
|
473
575
|
{
|
|
@@ -288,7 +288,6 @@ export async function handleCommand(command, args, ctx) {
|
|
|
288
288
|
}
|
|
289
289
|
break;
|
|
290
290
|
}
|
|
291
|
-
case 'effort':
|
|
292
291
|
case 'thinking': {
|
|
293
292
|
const providerId = config.get('provider');
|
|
294
293
|
const model = config.get('model');
|
|
@@ -302,7 +301,7 @@ export async function handleCommand(command, args, ctx) {
|
|
|
302
301
|
ctx.app.notify('Thinking effort: auto — each model uses its own default.');
|
|
303
302
|
}
|
|
304
303
|
else if (!supported) {
|
|
305
|
-
ctx.app.notify(`Thinking effort set to "${sub}", but ${model} has no graded thinking control — it will be ignored until you switch to a model that does (e.g. Opus 5, GPT-5.x, Gemini 3, DeepSeek V4, Kimi K3).`);
|
|
304
|
+
ctx.app.notify(`Thinking effort set to "${sub}", but ${model} has no graded thinking control — it will be ignored until you switch to a model that does (e.g. Opus 5, GPT-5.x or GPT-6, Gemini 3, DeepSeek V4.1 Flash, GLM-5.x, Kimi K3).`);
|
|
306
305
|
}
|
|
307
306
|
else {
|
|
308
307
|
// Tell the user what THIS model will actually run (the tier may
|
|
@@ -377,7 +376,6 @@ export async function handleCommand(command, args, ctx) {
|
|
|
377
376
|
runAgentTask(args.join(' '), true, ctx, () => null, () => { });
|
|
378
377
|
break;
|
|
379
378
|
}
|
|
380
|
-
case 'd':
|
|
381
379
|
case 'docs': {
|
|
382
380
|
// Open per-command web docs in the system browser. Lets the inline
|
|
383
381
|
// /help stay terse (single-line entries) while users who want the
|
|
@@ -1771,21 +1769,13 @@ Format: use headers per category, only include categories where you found issues
|
|
|
1771
1769
|
break;
|
|
1772
1770
|
}
|
|
1773
1771
|
// Built-in skill shortcuts
|
|
1774
|
-
case 'c':
|
|
1775
1772
|
case 'commit':
|
|
1776
|
-
case 't':
|
|
1777
1773
|
case 'test':
|
|
1778
|
-
case 'r':
|
|
1779
1774
|
case 'refactor':
|
|
1780
|
-
case 'f':
|
|
1781
1775
|
case 'fix':
|
|
1782
|
-
case 'e':
|
|
1783
1776
|
case 'explain':
|
|
1784
|
-
case 'o':
|
|
1785
1777
|
case 'optimize':
|
|
1786
|
-
case 'b':
|
|
1787
1778
|
case 'debug':
|
|
1788
|
-
case 'p':
|
|
1789
1779
|
case 'push':
|
|
1790
1780
|
case 'pull':
|
|
1791
1781
|
case 'amend':
|
|
@@ -2025,6 +2015,23 @@ Describe what this skill does. The agent reads this body verbatim when it invoke
|
|
|
2025
2015
|
});
|
|
2026
2016
|
break;
|
|
2027
2017
|
}
|
|
2018
|
+
case 'account': {
|
|
2019
|
+
// Linking cannot run here: `codeep account` prints to stdout and exits the
|
|
2020
|
+
// process when it finishes, which would tear down the TUI. Before this
|
|
2021
|
+
// case existed the autocomplete offered /account and it answered
|
|
2022
|
+
// "Unknown command" — so this says where the flow runs, and what state
|
|
2023
|
+
// the machine is in now.
|
|
2024
|
+
const { getSyncToken, getGithubId } = await import('../config/index.js');
|
|
2025
|
+
const linked = Boolean(getSyncToken());
|
|
2026
|
+
const githubId = getGithubId();
|
|
2027
|
+
ctx.app.addMessage({
|
|
2028
|
+
role: 'system',
|
|
2029
|
+
content: linked
|
|
2030
|
+
? `## codeep.dev account\n\nThis machine is **linked**${githubId ? ` (GitHub id ${githubId})` : ''}. Usage and sessions sync to your dashboard.\n\nTo cut it off, use **Settings → Connected devices** on codeep.dev.`
|
|
2031
|
+
: `## codeep.dev account\n\nThis machine is **not linked**.\n\nQuit Codeep and run this in your shell:\n\n\`\`\`bash\ncodeep account\n\`\`\`\n\nIt prints a one-time approval link. You can open it on **any** device where you are already signed in to codeep.dev — it does not have to be this machine, so there is no need to sign in to GitHub here.`,
|
|
2032
|
+
});
|
|
2033
|
+
break;
|
|
2034
|
+
}
|
|
2028
2035
|
case 'tasks': {
|
|
2029
2036
|
const { fetchTasks, markTaskDone, generateProjectId } = await import('../utils/codeepCloud.js');
|
|
2030
2037
|
const { setTaskContext, clearTaskContext } = await import('../utils/taskContext.js');
|
|
@@ -93,6 +93,21 @@ export interface ProviderCostBreakdown {
|
|
|
93
93
|
cacheReadTokens: number;
|
|
94
94
|
estimatedCost: number;
|
|
95
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* What a cached prompt token costs, as a fraction of the model's input rate.
|
|
98
|
+
* Model first (a property of the model), then provider, then the default.
|
|
99
|
+
*
|
|
100
|
+
* One lookup for everything that needs it. Cost used this chain while savings
|
|
101
|
+
* hardcoded 0.1, so every provider priced differently from Anthropic had a
|
|
102
|
+
* cost and a "saved" figure that disagreed with each other.
|
|
103
|
+
*/
|
|
104
|
+
export declare function cacheReadRateFor(model: string, provider: string | undefined): number;
|
|
105
|
+
/**
|
|
106
|
+
* The rate note for a report. One rate reads as "0.02×"; a session mixing
|
|
107
|
+
* providers reads as a range, because any single number there would be wrong
|
|
108
|
+
* for part of it.
|
|
109
|
+
*/
|
|
110
|
+
export declare function formatCacheReadRates(rates: readonly number[]): string;
|
|
96
111
|
/**
|
|
97
112
|
* Get cost breakdown grouped by provider/model.
|
|
98
113
|
*
|
|
@@ -120,6 +135,9 @@ export interface CacheStats {
|
|
|
120
135
|
/** True when EVERY cached token came from a flat-fee plan — there is no
|
|
121
136
|
* metered spend to have saved against. */
|
|
122
137
|
isEntirelyFlatFeeCache: boolean;
|
|
138
|
+
/** The read rate of each metered record that read from cache, so a report
|
|
139
|
+
* can state the rate that actually applied instead of assuming 0.1×. */
|
|
140
|
+
cacheReadRates: number[];
|
|
123
141
|
}
|
|
124
142
|
export declare function getCacheStats(): CacheStats;
|
|
125
143
|
/**
|
|
@@ -127,9 +127,10 @@ const MODEL_PRICING = {
|
|
|
127
127
|
// rate, so it carries PEAK — an over-estimate by design. The previous rows
|
|
128
128
|
// (0.435/0.87 and 0.14/0.28) were two to four and a half times below today's
|
|
129
129
|
// peak and so under-reported, which is the one direction this table must not
|
|
130
|
-
// err in. Cache hits
|
|
131
|
-
// `
|
|
132
|
-
//
|
|
130
|
+
// err in. Cache hits are read (DeepSeek reports them both nested as
|
|
131
|
+
// `prompt_tokens_details.cached_tokens` and top-level as
|
|
132
|
+
// `prompt_cache_hit_tokens`) and billed at DeepSeek's own hit rate — see
|
|
133
|
+
// CACHE_READ_RATE below.
|
|
133
134
|
'deepseek-flash': { inputPer1M: 0.30, outputPer1M: 1.20 },
|
|
134
135
|
// Retired V4 Flash is served by V4.1 Flash and billed at its price.
|
|
135
136
|
'deepseek-v4-flash': { inputPer1M: 0.30, outputPer1M: 1.20 },
|
|
@@ -250,8 +251,12 @@ export function extractOpenAIUsage(data) {
|
|
|
250
251
|
// later. Reading only the nested form zeroed every Kimi cache hit, so the
|
|
251
252
|
// cached portion of a run billed at the full cache-miss rate — five times
|
|
252
253
|
// what it costs — with nothing anywhere to say so.
|
|
254
|
+
// DeepSeek sends the same number twice — nested `cached_tokens` and
|
|
255
|
+
// top-level `prompt_cache_hit_tokens` — so the nested read already covers
|
|
256
|
+
// it; the top-level field is a last resort, never added to the other.
|
|
253
257
|
const nested = data.usage.prompt_tokens_details?.cached_tokens;
|
|
254
|
-
const
|
|
258
|
+
const topLevel = data.usage.cached_tokens ?? data.usage.prompt_cache_hit_tokens;
|
|
259
|
+
const cached = (typeof nested === 'number' ? nested : topLevel) || 0;
|
|
255
260
|
return {
|
|
256
261
|
promptTokens: data.usage.prompt_tokens || 0,
|
|
257
262
|
completionTokens: data.usage.completion_tokens || 0,
|
|
@@ -301,8 +306,16 @@ export function extractAnthropicUsage(data) {
|
|
|
301
306
|
*/
|
|
302
307
|
const MODEL_CACHE_READ_RATE = {
|
|
303
308
|
'claude-fable-5-1': 0.025,
|
|
309
|
+
// V4 Pro's own ratio: $0.044 hit against $1.32 miss (peak; off-peak halves
|
|
310
|
+
// both, so the ratio holds). Historical — V4 Pro routes to V4.1 Flash from
|
|
311
|
+
// 2026-09-14 and configs holding it are migrated.
|
|
312
|
+
'deepseek-v4-pro': 0.044 / 1.32,
|
|
304
313
|
};
|
|
305
314
|
const CACHE_READ_RATE = {
|
|
315
|
+
// V4.1 Flash: $0.006 hit against $0.30 miss at peak, $0.003 against $0.15
|
|
316
|
+
// off-peak — 0.02 either way. Without an entry DeepSeek fell to the 0.1
|
|
317
|
+
// default and every cached token billed at five times its price.
|
|
318
|
+
'deepseek': 0.02,
|
|
306
319
|
'kimi': 0.2,
|
|
307
320
|
'kimi-api': 0.2,
|
|
308
321
|
'qwen': 0.2,
|
|
@@ -313,6 +326,33 @@ const CACHE_READ_RATE = {
|
|
|
313
326
|
};
|
|
314
327
|
/** Anthropic's ratio, and the safest guess for a provider we have not priced. */
|
|
315
328
|
const DEFAULT_CACHE_READ_RATE = 0.1;
|
|
329
|
+
/**
|
|
330
|
+
* What a cached prompt token costs, as a fraction of the model's input rate.
|
|
331
|
+
* Model first (a property of the model), then provider, then the default.
|
|
332
|
+
*
|
|
333
|
+
* One lookup for everything that needs it. Cost used this chain while savings
|
|
334
|
+
* hardcoded 0.1, so every provider priced differently from Anthropic had a
|
|
335
|
+
* cost and a "saved" figure that disagreed with each other.
|
|
336
|
+
*/
|
|
337
|
+
export function cacheReadRateFor(model, provider) {
|
|
338
|
+
return MODEL_CACHE_READ_RATE[model]
|
|
339
|
+
?? CACHE_READ_RATE[provider?.trim().toLowerCase() ?? '']
|
|
340
|
+
?? DEFAULT_CACHE_READ_RATE;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* The rate note for a report. One rate reads as "0.02×"; a session mixing
|
|
344
|
+
* providers reads as a range, because any single number there would be wrong
|
|
345
|
+
* for part of it.
|
|
346
|
+
*/
|
|
347
|
+
export function formatCacheReadRates(rates) {
|
|
348
|
+
const fmt = (r) => `${Number(r.toFixed(3))}×`;
|
|
349
|
+
const distinct = [...new Set(rates.map(r => Number(r.toFixed(4))))].sort((a, b) => a - b);
|
|
350
|
+
if (distinct.length === 0)
|
|
351
|
+
return '';
|
|
352
|
+
if (distinct.length === 1)
|
|
353
|
+
return ` (billed at ${fmt(distinct[0])} input rate)`;
|
|
354
|
+
return ` (billed at ${fmt(distinct[0])}–${fmt(distinct[distinct.length - 1])} input rate, by model)`;
|
|
355
|
+
}
|
|
316
356
|
/**
|
|
317
357
|
* Get cost breakdown grouped by provider/model.
|
|
318
358
|
*
|
|
@@ -346,9 +386,7 @@ export function getCostBreakdown(startIndex = 0) {
|
|
|
346
386
|
// prompt tokens bill at the standard 1.0× rate.
|
|
347
387
|
const cacheCreate = record.cacheCreationTokens ?? 0;
|
|
348
388
|
const cacheRead = record.cacheReadTokens ?? 0;
|
|
349
|
-
const cacheReadRate =
|
|
350
|
-
?? CACHE_READ_RATE[record.provider?.trim().toLowerCase()]
|
|
351
|
-
?? DEFAULT_CACHE_READ_RATE;
|
|
389
|
+
const cacheReadRate = cacheReadRateFor(record.model, record.provider);
|
|
352
390
|
const uncachedPrompt = Math.max(0, record.promptTokens - cacheCreate - cacheRead);
|
|
353
391
|
existing.estimatedCost +=
|
|
354
392
|
(uncachedPrompt / 1_000_000) * pricing.inputPer1M
|
|
@@ -367,6 +405,7 @@ export function getCacheStats() {
|
|
|
367
405
|
let savings = 0;
|
|
368
406
|
let flatFeeCached = 0;
|
|
369
407
|
let meteredCached = 0;
|
|
408
|
+
const readRates = [];
|
|
370
409
|
for (const record of currentRecords()) {
|
|
371
410
|
const cached = (record.cacheCreationTokens ?? 0) + (record.cacheReadTokens ?? 0);
|
|
372
411
|
cacheCreate += record.cacheCreationTokens ?? 0;
|
|
@@ -380,11 +419,16 @@ export function getCacheStats() {
|
|
|
380
419
|
}
|
|
381
420
|
meteredCached += cached;
|
|
382
421
|
// Savings = what cache-read tokens would have cost at full input rate,
|
|
383
|
-
// minus what they
|
|
384
|
-
//
|
|
422
|
+
// minus what they cost at the model's own read rate. This hardcoded 0.9
|
|
423
|
+
// (a 0.1 read) for every provider, so Kimi and Qwen (0.2) over-reported
|
|
424
|
+
// savings while DeepSeek (0.02) and Fable 5.1 (0.025) under-reported them.
|
|
425
|
+
// (Cache creation is a slight *penalty* of 0.25× — netted in.)
|
|
385
426
|
const pricing = MODEL_PRICING[record.model];
|
|
386
427
|
if (pricing) {
|
|
387
|
-
const
|
|
428
|
+
const readRate = cacheReadRateFor(record.model, record.provider);
|
|
429
|
+
if ((record.cacheReadTokens ?? 0) > 0)
|
|
430
|
+
readRates.push(readRate);
|
|
431
|
+
const cReadSaved = ((record.cacheReadTokens ?? 0) / 1_000_000) * pricing.inputPer1M * (1 - readRate);
|
|
388
432
|
const cCreateCost = ((record.cacheCreationTokens ?? 0) / 1_000_000) * pricing.inputPer1M * 0.25;
|
|
389
433
|
savings += cReadSaved - cCreateCost;
|
|
390
434
|
}
|
|
@@ -395,6 +439,7 @@ export function getCacheStats() {
|
|
|
395
439
|
estimatedSavingsUsd: Math.max(0, savings),
|
|
396
440
|
hasFlatFeeCacheUsage: flatFeeCached > 0,
|
|
397
441
|
isEntirelyFlatFeeCache: flatFeeCached > 0 && meteredCached === 0,
|
|
442
|
+
cacheReadRates: readRates,
|
|
398
443
|
};
|
|
399
444
|
}
|
|
400
445
|
/**
|
|
@@ -506,7 +551,7 @@ export function formatCostReport() {
|
|
|
506
551
|
// The billing multipliers only describe a metered account. On a plan
|
|
507
552
|
// nothing is billed per token, so quoting a rate there would be as invented
|
|
508
553
|
// as the per-model prices this report already refuses to show.
|
|
509
|
-
const readNote = cache.isEntirelyFlatFeeCache ? '' :
|
|
554
|
+
const readNote = cache.isEntirelyFlatFeeCache ? '' : formatCacheReadRates(cache.cacheReadRates);
|
|
510
555
|
const writeNote = cache.isEntirelyFlatFeeCache ? '' : ' (billed at 1.25× input rate)';
|
|
511
556
|
lines.push(`**Cache reads:** ${formatTokenCount(cache.cacheReadTokens)} tokens${readNote}`);
|
|
512
557
|
if (cache.cacheCreationTokens > 0) {
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "3.3.
|
|
1
|
+
export declare const VERSION = "3.3.2";
|
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 = '3.3.
|
|
4
|
+
export const VERSION = '3.3.2';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeep",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.2",
|
|
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",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"test:coverage": "vitest run --coverage",
|
|
18
18
|
"version": "node scripts/gen-version.js && git add src/version.ts",
|
|
19
19
|
"export:catalogue": "node --import tsx scripts/export-catalogue.ts",
|
|
20
|
+
"export:commands": "node --import tsx scripts/export-commands.ts",
|
|
20
21
|
"release": "node scripts/release.js"
|
|
21
22
|
},
|
|
22
23
|
"repository": {
|