codeep 2.7.0 → 2.9.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.
- package/README.md +1 -1
- package/dist/acp/commands.js +1 -0
- package/dist/api/index.js +4 -2
- package/dist/config/index.d.ts +13 -0
- package/dist/config/index.js +25 -0
- package/dist/config/providers.d.ts +1 -0
- package/dist/config/providers.js +13 -3
- package/dist/renderer/App.js +1 -0
- package/dist/renderer/commands.js +30 -1
- package/dist/renderer/components/Settings.js +10 -0
- package/dist/renderer/main.js +73 -44
- package/dist/utils/agentChat.js +7 -3
- package/dist/utils/codeepCloud.d.ts +6 -0
- package/dist/utils/codeepCloud.js +16 -0
- package/dist/utils/tokenTracker.js +2 -4
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,7 +50,7 @@ custom slash commands, lifecycle hooks, checkpoints, `/cost`,
|
|
|
50
50
|
### Multi-Provider Support
|
|
51
51
|
- **Z.AI (ZhipuAI)** — GLM models (Coding Plan & pay-per-use API, international & China)
|
|
52
52
|
- **OpenAI** — GPT models (flagship, Mini, Nano)
|
|
53
|
-
- **Anthropic** — Claude models (Opus, Sonnet, Haiku)
|
|
53
|
+
- **Anthropic** — Claude models (Fable, Opus, Sonnet, Haiku)
|
|
54
54
|
- **DeepSeek** — DeepSeek models (Pro, Flash)
|
|
55
55
|
- **Google AI** — Gemini models (Pro, Flash)
|
|
56
56
|
- **MiniMax** — MiniMax models (Coding Plan & pay-per-use API, international & China)
|
package/dist/acp/commands.js
CHANGED
|
@@ -1443,6 +1443,7 @@ function buildHelp() {
|
|
|
1443
1443
|
'| `/login <provider> <key>` | Set API key for a provider |',
|
|
1444
1444
|
'| `/apikey [key]` | Show or set API key |',
|
|
1445
1445
|
'| `/telemetry [on\\|off]` | Show or toggle automatic cloud telemetry |',
|
|
1446
|
+
'| `/keysync [on\\|off]` | Show or toggle syncing API keys to codeep.dev |',
|
|
1446
1447
|
'| `/lang [code]` | Set response language (`en`, `hr`, `auto`…) |',
|
|
1447
1448
|
'| `/grant` | Grant write access for workspace |',
|
|
1448
1449
|
'',
|
package/dist/api/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as http from 'node:http';
|
|
|
2
2
|
import * as https from 'node:https';
|
|
3
3
|
import { config, getApiKey, resolveBaseUrl } from '../config/index.js';
|
|
4
4
|
import { withRetry, isNetworkError } from '../utils/retry.js';
|
|
5
|
-
import { getProvider, getProviderBaseUrl, getProviderAuthHeader, usesMaxCompletionTokens, requiresDefaultTemperature } from '../config/providers.js';
|
|
5
|
+
import { getProvider, getProviderBaseUrl, getProviderAuthHeader, usesMaxCompletionTokens, requiresDefaultTemperature, modelRejectsSamplingParams } from '../config/providers.js';
|
|
6
6
|
import { logApiRequest, logApiResponse } from '../utils/logger.js';
|
|
7
7
|
import { loadProjectIntelligence, generateContextFromIntelligence } from '../utils/projectIntelligence.js';
|
|
8
8
|
import { loadProjectRules } from '../utils/agent.js';
|
|
@@ -655,7 +655,9 @@ async function chatAnthropic(message, history, model, apiKey, onChunk, abortSign
|
|
|
655
655
|
model,
|
|
656
656
|
messages,
|
|
657
657
|
max_tokens: maxTokens,
|
|
658
|
-
temperature
|
|
658
|
+
// Fable 5 / Opus 4.7+ reject temperature with a 400 — omit it there
|
|
659
|
+
// (omission means API default on every Claude model).
|
|
660
|
+
...(modelRejectsSamplingParams(model) ? {} : { temperature }),
|
|
659
661
|
stream,
|
|
660
662
|
...cachedSystem,
|
|
661
663
|
}),
|
package/dist/config/index.d.ts
CHANGED
|
@@ -104,6 +104,12 @@ interface ConfigSchema {
|
|
|
104
104
|
* transcripts, progress, memory notes). Default true; set false to opt out.
|
|
105
105
|
* The CODEEP_NO_TELEMETRY / DO_NOT_TRACK env vars also force it off. */
|
|
106
106
|
telemetry: boolean;
|
|
107
|
+
/** Opt-in to syncing API keys to codeep.dev (`codeep account push`/`sync`).
|
|
108
|
+
* OFF by default — keys live only in the OS keychain unless you enable this.
|
|
109
|
+
* Synced keys are stored server-readable (AES from a server-held secret), so
|
|
110
|
+
* this is an explicit consent switch. Enable via `/keysync on` or Settings;
|
|
111
|
+
* the CODEEP_NO_KEY_SYNC env var forces it off (org-policy hard switch). */
|
|
112
|
+
syncKeysToCloud: boolean;
|
|
107
113
|
githubId: string;
|
|
108
114
|
githubUsername: string;
|
|
109
115
|
syncToken: string;
|
|
@@ -176,6 +182,13 @@ export declare function isTelemetryEnabled(): boolean;
|
|
|
176
182
|
* the /telemetry command explain why a toggle had no effect.
|
|
177
183
|
*/
|
|
178
184
|
export declare function telemetryForcedOffByEnv(): boolean;
|
|
185
|
+
export declare function isKeySyncEnabled(): boolean;
|
|
186
|
+
/**
|
|
187
|
+
* True when CODEEP_NO_KEY_SYNC is forcing key sync off — so the `syncKeysToCloud`
|
|
188
|
+
* flag can't turn it back on. Lets the /keysync command explain why a toggle had
|
|
189
|
+
* no effect.
|
|
190
|
+
*/
|
|
191
|
+
export declare function keySyncForcedOffByEnv(): boolean;
|
|
179
192
|
/**
|
|
180
193
|
* Clear API key for a specific provider
|
|
181
194
|
*/
|
package/dist/config/index.js
CHANGED
|
@@ -188,6 +188,7 @@ function createConfig() {
|
|
|
188
188
|
keysSecured: false,
|
|
189
189
|
apiKeys: {},
|
|
190
190
|
telemetry: true,
|
|
191
|
+
syncKeysToCloud: false,
|
|
191
192
|
githubId: '',
|
|
192
193
|
githubUsername: '',
|
|
193
194
|
syncToken: '',
|
|
@@ -550,6 +551,30 @@ export function isTelemetryEnabled() {
|
|
|
550
551
|
export function telemetryForcedOffByEnv() {
|
|
551
552
|
return envForcesTelemetryOff();
|
|
552
553
|
}
|
|
554
|
+
/**
|
|
555
|
+
* Whether syncing API keys to the cloud is allowed. OFF by default (opt-in):
|
|
556
|
+
* unlike telemetry, this also gates the EXPLICIT `codeep account push` and the
|
|
557
|
+
* key-download half of `account sync`, because pushing a key stores it
|
|
558
|
+
* server-readable. The CODEEP_NO_KEY_SYNC env var forces it off as an
|
|
559
|
+
* org-policy hard switch the config flag can't override.
|
|
560
|
+
*/
|
|
561
|
+
function envForcesKeySyncOff() {
|
|
562
|
+
const off = (v) => !!v && !/^(0|false|no|off)$/i.test(v.trim());
|
|
563
|
+
return off(process.env.CODEEP_NO_KEY_SYNC);
|
|
564
|
+
}
|
|
565
|
+
export function isKeySyncEnabled() {
|
|
566
|
+
if (envForcesKeySyncOff())
|
|
567
|
+
return false;
|
|
568
|
+
return config.get('syncKeysToCloud') === true; // default OFF — must be explicitly true
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* True when CODEEP_NO_KEY_SYNC is forcing key sync off — so the `syncKeysToCloud`
|
|
572
|
+
* flag can't turn it back on. Lets the /keysync command explain why a toggle had
|
|
573
|
+
* no effect.
|
|
574
|
+
*/
|
|
575
|
+
export function keySyncForcedOffByEnv() {
|
|
576
|
+
return envForcesKeySyncOff();
|
|
577
|
+
}
|
|
553
578
|
/**
|
|
554
579
|
* Clear API key for a specific provider
|
|
555
580
|
*/
|
|
@@ -68,6 +68,7 @@ export declare function usesMaxCompletionTokens(providerId: string): boolean;
|
|
|
68
68
|
* (e.g. OpenAI GPT-5+ only accepts the default of 1).
|
|
69
69
|
*/
|
|
70
70
|
export declare function requiresDefaultTemperature(providerId: string): boolean;
|
|
71
|
+
export declare function modelRejectsSamplingParams(model: string): boolean;
|
|
71
72
|
/**
|
|
72
73
|
* Returns the effective max output tokens for a provider, capped by the provider's limit.
|
|
73
74
|
* Falls back to the requested value if no provider limit is set.
|
package/dist/config/providers.js
CHANGED
|
@@ -243,9 +243,8 @@ export const PROVIDERS = {
|
|
|
243
243
|
},
|
|
244
244
|
},
|
|
245
245
|
models: [
|
|
246
|
-
{ id: 'claude-
|
|
247
|
-
{ id: 'claude-opus-4-
|
|
248
|
-
{ id: 'claude-opus-4-6', name: 'Claude Opus 4.6', description: 'Older generation Opus' },
|
|
246
|
+
{ id: 'claude-fable-5', name: 'Claude Fable 5', description: 'Most powerful — new tier above Opus' },
|
|
247
|
+
{ id: 'claude-opus-4-8', name: 'Claude Opus 4.8', description: 'Most capable Opus model' },
|
|
249
248
|
{ id: 'claude-sonnet-4-6', name: 'Claude Sonnet', description: 'Best balance of speed and intelligence' },
|
|
250
249
|
{ id: 'claude-haiku-4-5-20251001', name: 'Claude Haiku', description: 'Fastest and most affordable' },
|
|
251
250
|
],
|
|
@@ -448,6 +447,17 @@ export function usesMaxCompletionTokens(providerId) {
|
|
|
448
447
|
export function requiresDefaultTemperature(providerId) {
|
|
449
448
|
return PROVIDERS[providerId]?.requiresDefaultTemperature ?? false;
|
|
450
449
|
}
|
|
450
|
+
/**
|
|
451
|
+
* Models that reject sampling parameters (temperature/top_p/top_k) with a 400.
|
|
452
|
+
* Anthropic removed them on Fable 5 and Opus 4.7+; older Claude models still
|
|
453
|
+
* accept them, so this must be a MODEL-level check, not a provider-level one
|
|
454
|
+
* (requiresDefaultTemperature can't express it). Omitting the field is always
|
|
455
|
+
* safe — the API treats omission as default.
|
|
456
|
+
*/
|
|
457
|
+
const SAMPLING_PARAMS_REJECTED = ['claude-fable-5', 'claude-opus-4-8', 'claude-opus-4-7'];
|
|
458
|
+
export function modelRejectsSamplingParams(model) {
|
|
459
|
+
return SAMPLING_PARAMS_REJECTED.some(id => model === id || model.startsWith(`${id}-`));
|
|
460
|
+
}
|
|
451
461
|
/**
|
|
452
462
|
* Returns the effective max output tokens for a provider, capped by the provider's limit.
|
|
453
463
|
* Falls back to the requested value if no provider limit is set.
|
package/dist/renderer/App.js
CHANGED
|
@@ -83,6 +83,7 @@ const COMMAND_DESCRIPTIONS = {
|
|
|
83
83
|
'tasks': 'Show pending tasks from codeep.dev dashboard',
|
|
84
84
|
'sync': 'Sync learning preferences and profiles to codeep.dev',
|
|
85
85
|
'telemetry': 'Show or toggle automatic cloud telemetry (on/off)',
|
|
86
|
+
'keysync': 'Show or toggle syncing API keys to codeep.dev (on/off)',
|
|
86
87
|
// 2.0 — surfaced for `/` autocomplete; documented in /help too.
|
|
87
88
|
'compact': 'Summarize older messages to free up context',
|
|
88
89
|
'commands': 'List custom slash commands in .codeep/commands/*.md',
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* decoupled from global state. Import-heavy commands use dynamic imports
|
|
6
6
|
* to keep startup time low.
|
|
7
7
|
*/
|
|
8
|
-
import { config, getCurrentProvider, getModelsForCurrentProvider, PROTOCOLS, LANGUAGES, setProvider, setApiKey, clearApiKey, getApiKey, isTelemetryEnabled, telemetryForcedOffByEnv, saveSession, startNewSession, loadSession, listSessionsWithInfo, deleteSession, renameSession, setProjectPermission, saveProfile, loadProfile, applyProfile, listProfiles, deleteProfile, initializeAsProject, isManuallyInitializedProject, } from '../config/index.js';
|
|
8
|
+
import { config, getCurrentProvider, getModelsForCurrentProvider, PROTOCOLS, LANGUAGES, setProvider, setApiKey, clearApiKey, getApiKey, isTelemetryEnabled, telemetryForcedOffByEnv, isKeySyncEnabled, keySyncForcedOffByEnv, saveSession, startNewSession, loadSession, listSessionsWithInfo, deleteSession, renameSession, setProjectPermission, saveProfile, loadProfile, applyProfile, listProfiles, deleteProfile, initializeAsProject, isManuallyInitializedProject, } from '../config/index.js';
|
|
9
9
|
import { getProjectContext } from '../utils/project.js';
|
|
10
10
|
import { getCurrentVersion } from '../utils/update.js';
|
|
11
11
|
import { getProviderList, getProvider } from '../config/providers.js';
|
|
@@ -274,6 +274,35 @@ export async function handleCommand(command, args, ctx) {
|
|
|
274
274
|
ctx.app.addMessage({ role: 'system', content: tLines.join('\n') });
|
|
275
275
|
break;
|
|
276
276
|
}
|
|
277
|
+
case 'keysync': {
|
|
278
|
+
const sub = args[0]?.toLowerCase();
|
|
279
|
+
const envOff = keySyncForcedOffByEnv();
|
|
280
|
+
if (sub === 'on' || sub === 'off') {
|
|
281
|
+
if (envOff) {
|
|
282
|
+
ctx.app.notify('Cloud key sync is forced OFF by CODEEP_NO_KEY_SYNC — unset that env var to change it.');
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
config.set('syncKeysToCloud', sub === 'on');
|
|
286
|
+
ctx.app.notify(sub === 'on'
|
|
287
|
+
? 'Cloud key sync on — `codeep account push/sync` will now upload/download API keys. Note: synced keys are stored server-readable on codeep.dev.'
|
|
288
|
+
: 'Cloud key sync off — API keys stay in your OS keychain only. (Run `codeep account purge-keys` to also wipe any keys already on the server.)');
|
|
289
|
+
break;
|
|
290
|
+
}
|
|
291
|
+
if (sub && sub !== 'status') {
|
|
292
|
+
ctx.app.notify('Usage: /keysync · /keysync on · /keysync off');
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
const flag = config.get('syncKeysToCloud') === true;
|
|
296
|
+
const kLines = ['## Cloud key sync', ''];
|
|
297
|
+
kLines.push(`**State** ${isKeySyncEnabled() ? 'on' : 'off'}`);
|
|
298
|
+
kLines.push(`**Flag** syncKeysToCloud = ${flag}`);
|
|
299
|
+
if (envOff)
|
|
300
|
+
kLines.push('**Env** forced off by CODEEP_NO_KEY_SYNC (overrides the flag)');
|
|
301
|
+
kLines.push('');
|
|
302
|
+
kLines.push('OFF by default. API keys live only in your OS keychain unless you turn this on. When on, `codeep account push`/`sync` upload/download keys, which are stored **server-readable** on codeep.dev. Toggle with `/keysync on` or `/keysync off`; wipe server copies with `codeep account purge-keys`.');
|
|
303
|
+
ctx.app.addMessage({ role: 'system', content: kLines.join('\n') });
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
277
306
|
case 'grant': {
|
|
278
307
|
setProjectPermission(ctx.projectPath, true, true);
|
|
279
308
|
ctx.setHasWriteAccess(true);
|
|
@@ -250,6 +250,16 @@ export const SETTINGS = [
|
|
|
250
250
|
{ value: false, label: 'Off' },
|
|
251
251
|
],
|
|
252
252
|
},
|
|
253
|
+
{
|
|
254
|
+
key: 'syncKeysToCloud',
|
|
255
|
+
label: 'Sync API Keys to Cloud (server-readable)',
|
|
256
|
+
getValue: () => config.get('syncKeysToCloud') === true,
|
|
257
|
+
type: 'select',
|
|
258
|
+
options: [
|
|
259
|
+
{ value: false, label: 'Off (keychain only)' },
|
|
260
|
+
{ value: true, label: 'On (push/sync to codeep.dev)' },
|
|
261
|
+
],
|
|
262
|
+
},
|
|
253
263
|
];
|
|
254
264
|
/**
|
|
255
265
|
* Format value for display
|
package/dist/renderer/main.js
CHANGED
|
@@ -404,8 +404,9 @@ Codeep - AI-powered coding assistant TUI
|
|
|
404
404
|
Usage:
|
|
405
405
|
codeep Start interactive chat
|
|
406
406
|
codeep account Link CLI to your codeep.dev dashboard
|
|
407
|
-
codeep account sync Pull
|
|
408
|
-
codeep account push Push
|
|
407
|
+
codeep account sync Pull personalities + commands + profile (+ keys if cloud key sync is on)
|
|
408
|
+
codeep account push Push personalities + commands + profile (+ keys if cloud key sync is on)
|
|
409
|
+
codeep account purge-keys Delete all your API keys stored on codeep.dev (cloud only; local keychain untouched)
|
|
409
410
|
codeep acp Start ACP server (for Zed editor integration)
|
|
410
411
|
codeep review Offline code review for CI (--json, --fail-on, --rules, --ai)
|
|
411
412
|
codeep hook install Install a git pre-commit hook running \`codeep review\`
|
|
@@ -425,9 +426,7 @@ Commands (in chat):
|
|
|
425
426
|
if (args[0] === 'account') {
|
|
426
427
|
const sub = args[1];
|
|
427
428
|
if (sub === 'sync' || sub === 'pull') {
|
|
428
|
-
|
|
429
|
-
const { pullKeys } = await import('../utils/codeepCloud.js');
|
|
430
|
-
const { getSyncToken, setApiKey, loadAllApiKeys: loadKeys } = await import('../config/index.js');
|
|
429
|
+
const { getSyncToken, setApiKey, loadAllApiKeys: loadKeys, isKeySyncEnabled } = await import('../config/index.js');
|
|
431
430
|
if (!getSyncToken()) {
|
|
432
431
|
console.log('\n Not linked to codeep.dev. Run: codeep account\n');
|
|
433
432
|
process.exit(1);
|
|
@@ -436,28 +435,36 @@ Commands (in chat):
|
|
|
436
435
|
// key. Otherwise the first setApiKey flips keysSecured=true and any local
|
|
437
436
|
// legacy plaintext keys would never migrate (orphaned, invisible).
|
|
438
437
|
await loadKeys();
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
if (
|
|
442
|
-
|
|
443
|
-
process.
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
438
|
+
// API keys are opt-in (default OFF). Pull them only when cloud key sync is
|
|
439
|
+
// enabled; the personal config below always syncs (no secrets).
|
|
440
|
+
if (isKeySyncEnabled()) {
|
|
441
|
+
const { pullKeys } = await import('../utils/codeepCloud.js');
|
|
442
|
+
process.stdout.write(' Pulling keys from codeep.dev...');
|
|
443
|
+
const keys = await pullKeys();
|
|
444
|
+
if (!keys) {
|
|
445
|
+
console.log(' failed.\n Check your connection or re-link with: codeep account\n');
|
|
446
|
+
process.exit(1);
|
|
447
|
+
}
|
|
448
|
+
const count = Object.keys(keys).length;
|
|
449
|
+
if (count === 0) {
|
|
450
|
+
console.log(' no keys found.\n Add keys at codeep.dev/dashboard');
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
let synced = 0;
|
|
454
|
+
for (const [provider, key] of Object.entries(keys)) {
|
|
455
|
+
try {
|
|
456
|
+
await setApiKey(key, provider);
|
|
457
|
+
synced++;
|
|
458
|
+
}
|
|
459
|
+
catch {
|
|
460
|
+
console.log(`\n Warning: could not securely store the key for ${provider}.`);
|
|
461
|
+
}
|
|
458
462
|
}
|
|
463
|
+
console.log(` synced ${synced} key${synced !== 1 ? 's' : ''}.`);
|
|
459
464
|
}
|
|
460
|
-
|
|
465
|
+
}
|
|
466
|
+
else {
|
|
467
|
+
console.log(' Cloud key sync is off — skipping API keys. Enable with: /keysync on');
|
|
461
468
|
}
|
|
462
469
|
// Also pull portable personal config — personalities + custom commands +
|
|
463
470
|
// the user profile. Additive merge (never clobbers local files).
|
|
@@ -478,29 +485,38 @@ Commands (in chat):
|
|
|
478
485
|
process.exit(0);
|
|
479
486
|
}
|
|
480
487
|
if (sub === 'push') {
|
|
481
|
-
|
|
482
|
-
const { pushKeys } = await import('../utils/codeepCloud.js');
|
|
483
|
-
const { getSyncToken, getApiKey } = await import('../config/index.js');
|
|
484
|
-
const { PROVIDERS } = await import('../config/providers.js');
|
|
488
|
+
const { getSyncToken, getApiKey, isKeySyncEnabled } = await import('../config/index.js');
|
|
485
489
|
if (!getSyncToken()) {
|
|
486
490
|
console.log('\n Not linked to codeep.dev. Run: codeep account\n');
|
|
487
491
|
process.exit(1);
|
|
488
492
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
493
|
+
// API keys are opt-in (default OFF). Push them only when cloud key sync is
|
|
494
|
+
// enabled; the personal config below always pushes (no secrets).
|
|
495
|
+
let keyPushFailed = false;
|
|
496
|
+
if (isKeySyncEnabled()) {
|
|
497
|
+
const { pushKeys } = await import('../utils/codeepCloud.js');
|
|
498
|
+
const { PROVIDERS } = await import('../config/providers.js');
|
|
499
|
+
await loadAllApiKeys();
|
|
500
|
+
const keys = {};
|
|
501
|
+
for (const providerId of Object.keys(PROVIDERS)) {
|
|
502
|
+
const key = getApiKey(providerId);
|
|
503
|
+
if (key)
|
|
504
|
+
keys[providerId] = key;
|
|
505
|
+
}
|
|
506
|
+
const count = Object.keys(keys).length;
|
|
507
|
+
if (count === 0) {
|
|
508
|
+
console.log(' No local API keys to push.');
|
|
509
|
+
}
|
|
510
|
+
else {
|
|
511
|
+
process.stdout.write(` Pushing ${count} key${count !== 1 ? 's' : ''} to codeep.dev...`);
|
|
512
|
+
const ok = await pushKeys(keys);
|
|
513
|
+
console.log(ok ? ' done.' : ' failed.');
|
|
514
|
+
keyPushFailed = !ok;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
else {
|
|
518
|
+
console.log(' Cloud key sync is off — skipping API keys. Enable with: /keysync on');
|
|
519
|
+
}
|
|
504
520
|
// Also push portable personal config — personalities + commands + profile.
|
|
505
521
|
const { pushPersonalities, pushCommands, pushUserProfile } = await import('../utils/codeepCloud.js');
|
|
506
522
|
const pCount = await pushPersonalities();
|
|
@@ -515,6 +531,19 @@ Commands (in chat):
|
|
|
515
531
|
console.log(' Pushed your profile (about you).');
|
|
516
532
|
}
|
|
517
533
|
console.log('');
|
|
534
|
+
process.exit(keyPushFailed ? 1 : 0);
|
|
535
|
+
}
|
|
536
|
+
if (sub === 'purge-keys') {
|
|
537
|
+
const { getSyncToken } = await import('../config/index.js');
|
|
538
|
+
if (!getSyncToken()) {
|
|
539
|
+
console.log('\n Not linked to codeep.dev. Run: codeep account\n');
|
|
540
|
+
process.exit(1);
|
|
541
|
+
}
|
|
542
|
+
const { purgeKeys } = await import('../utils/codeepCloud.js');
|
|
543
|
+
process.stdout.write(' Deleting all your API keys from codeep.dev...');
|
|
544
|
+
const ok = await purgeKeys();
|
|
545
|
+
console.log(ok ? ' done. (Local keychain keys are untouched.)' : ' failed.');
|
|
546
|
+
console.log('');
|
|
518
547
|
process.exit(ok ? 0 : 1);
|
|
519
548
|
}
|
|
520
549
|
const { runAccountFlow } = await import('../utils/codeepCloud.js');
|
package/dist/utils/agentChat.js
CHANGED
|
@@ -17,7 +17,7 @@ import { createHash } from 'crypto';
|
|
|
17
17
|
import { config, getApiKey, resolveBaseUrl } from '../config/index.js';
|
|
18
18
|
import { loadProjectIntelligence, generateContextFromIntelligence } from './projectIntelligence.js';
|
|
19
19
|
import { syncProgress, generateProjectId } from './codeepCloud.js';
|
|
20
|
-
import { getProviderAuthHeader, supportsNativeTools, getEffectiveMaxTokens, usesMaxCompletionTokens, requiresDefaultTemperature, isNoApiKeyProvider } from '../config/providers.js';
|
|
20
|
+
import { getProviderAuthHeader, supportsNativeTools, getEffectiveMaxTokens, usesMaxCompletionTokens, requiresDefaultTemperature, modelRejectsSamplingParams, isNoApiKeyProvider } from '../config/providers.js';
|
|
21
21
|
import { recordTokenUsage, extractOpenAIUsage, extractAnthropicUsage } from './tokenTracker.js';
|
|
22
22
|
import { parseOpenAIToolCalls, parseAnthropicToolCalls, parseToolCalls } from './toolParsing.js';
|
|
23
23
|
import { formatToolDefinitions, getOpenAITools, getAnthropicTools } from './tools.js';
|
|
@@ -357,7 +357,9 @@ additionalTools) {
|
|
|
357
357
|
let endpoint;
|
|
358
358
|
let body;
|
|
359
359
|
const useStreaming = Boolean(onChunk);
|
|
360
|
-
|
|
360
|
+
// Provider-level guard (OpenAI GPT-5+) OR model-level guard — Anthropic's
|
|
361
|
+
// Fable 5 / Opus 4.7+ reject temperature with a 400; omission is safe.
|
|
362
|
+
const tempParam = (requiresDefaultTemperature(providerId) || modelRejectsSamplingParams(model)) ? {} : { temperature: config.get('temperature') };
|
|
361
363
|
if (protocol === 'openai') {
|
|
362
364
|
const maxTok = getEffectiveMaxTokens(providerId, Math.max(config.get('maxTokens'), 16384));
|
|
363
365
|
const tokParam = usesMaxCompletionTokens(providerId) ? { max_completion_tokens: maxTok } : { max_tokens: maxTok };
|
|
@@ -549,7 +551,9 @@ export async function agentChatFallback(messages, systemPrompt, onChunk, abortSi
|
|
|
549
551
|
try {
|
|
550
552
|
let endpoint;
|
|
551
553
|
let body;
|
|
552
|
-
|
|
554
|
+
// Provider-level guard (OpenAI GPT-5+) OR model-level guard — Anthropic's
|
|
555
|
+
// Fable 5 / Opus 4.7+ reject temperature with a 400; omission is safe.
|
|
556
|
+
const tempParam = (requiresDefaultTemperature(providerId) || modelRejectsSamplingParams(model)) ? {} : { temperature: config.get('temperature') };
|
|
553
557
|
if (protocol === 'openai') {
|
|
554
558
|
const maxTok = getEffectiveMaxTokens(providerId, Math.max(config.get('maxTokens'), 16384));
|
|
555
559
|
const tokParam = usesMaxCompletionTokens(providerId) ? { max_completion_tokens: maxTok } : { max_tokens: maxTok };
|
|
@@ -65,6 +65,12 @@ export declare function pullKeys(): Promise<Record<string, string> | null>;
|
|
|
65
65
|
* Returns true on success.
|
|
66
66
|
*/
|
|
67
67
|
export declare function pushKeys(keys: Record<string, string>): Promise<boolean>;
|
|
68
|
+
/**
|
|
69
|
+
* Purge ALL of the user's API keys stored on codeep.dev (cloud-only — local
|
|
70
|
+
* keychain keys are untouched). A clean exit for anyone who synced keys and
|
|
71
|
+
* later wants them off the server. Returns true on success.
|
|
72
|
+
*/
|
|
73
|
+
export declare function purgeKeys(): Promise<boolean>;
|
|
68
74
|
export declare const pullPersonalities: () => Promise<number | null>;
|
|
69
75
|
export declare const pushPersonalities: () => Promise<number | null>;
|
|
70
76
|
export declare const pullCommands: () => Promise<number | null>;
|
|
@@ -221,6 +221,22 @@ export async function pushKeys(keys) {
|
|
|
221
221
|
});
|
|
222
222
|
return res?.ok ?? false;
|
|
223
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Purge ALL of the user's API keys stored on codeep.dev (cloud-only — local
|
|
226
|
+
* keychain keys are untouched). A clean exit for anyone who synced keys and
|
|
227
|
+
* later wants them off the server. Returns true on success.
|
|
228
|
+
*/
|
|
229
|
+
export async function purgeKeys() {
|
|
230
|
+
const syncToken = getSyncToken();
|
|
231
|
+
if (!syncToken)
|
|
232
|
+
return false;
|
|
233
|
+
const res = await fetchWithRetry(`${API_BASE}/api/keys`, {
|
|
234
|
+
method: 'DELETE',
|
|
235
|
+
headers: { 'Content-Type': 'application/json', 'x-sync-token': syncToken },
|
|
236
|
+
body: JSON.stringify({ all: true }),
|
|
237
|
+
});
|
|
238
|
+
return res?.ok ?? false;
|
|
239
|
+
}
|
|
224
240
|
// ─── Portable personal config sync (personalities + commands) ──────────────────
|
|
225
241
|
//
|
|
226
242
|
// Both are name → raw-.md-body bundles stored in a global dir
|
|
@@ -16,9 +16,8 @@ const MODEL_CONTEXT_WINDOWS = {
|
|
|
16
16
|
'gpt-5.4-mini': 400_000,
|
|
17
17
|
'gpt-5.4-nano': 400_000,
|
|
18
18
|
// Anthropic
|
|
19
|
+
'claude-fable-5': 1_000_000,
|
|
19
20
|
'claude-opus-4-8': 1_000_000,
|
|
20
|
-
'claude-opus-4-7': 1_000_000,
|
|
21
|
-
'claude-opus-4-6': 1_000_000,
|
|
22
21
|
'claude-sonnet-4-6': 1_000_000,
|
|
23
22
|
'claude-haiku-4-5-20251001': 200_000,
|
|
24
23
|
// DeepSeek
|
|
@@ -52,9 +51,8 @@ const MODEL_PRICING = {
|
|
|
52
51
|
'gpt-5.4-mini': { inputPer1M: 0.75, outputPer1M: 4.50 },
|
|
53
52
|
'gpt-5.4-nano': { inputPer1M: 0.20, outputPer1M: 1.25 },
|
|
54
53
|
// Anthropic
|
|
54
|
+
'claude-fable-5': { inputPer1M: 10.00, outputPer1M: 50.00 },
|
|
55
55
|
'claude-opus-4-8': { inputPer1M: 5.00, outputPer1M: 25.00 },
|
|
56
|
-
'claude-opus-4-7': { inputPer1M: 5.00, outputPer1M: 25.00 },
|
|
57
|
-
'claude-opus-4-6': { inputPer1M: 5.00, outputPer1M: 25.00 },
|
|
58
56
|
'claude-sonnet-4-6': { inputPer1M: 3.00, outputPer1M: 15.00 },
|
|
59
57
|
'claude-haiku-4-5-20251001': { inputPer1M: 1.00, outputPer1M: 5.00 },
|
|
60
58
|
// DeepSeek (cache-miss input pricing)
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "2.
|
|
1
|
+
export declare const VERSION = "2.9.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.
|
|
4
|
+
export const VERSION = '2.9.0';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeep",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.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",
|