claude-code-workflow 6.2.7 → 6.3.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/.claude/CLAUDE.md +16 -1
- package/.claude/workflows/cli-templates/protocols/analysis-protocol.md +11 -4
- package/.claude/workflows/cli-templates/protocols/write-protocol.md +10 -75
- package/.claude/workflows/cli-tools-usage.md +14 -24
- package/.codex/AGENTS.md +51 -1
- package/.codex/prompts/compact.md +378 -0
- package/.gemini/GEMINI.md +57 -20
- package/ccw/dist/cli.d.ts.map +1 -1
- package/ccw/dist/cli.js +21 -8
- package/ccw/dist/cli.js.map +1 -1
- package/ccw/dist/commands/cli.d.ts +2 -0
- package/ccw/dist/commands/cli.d.ts.map +1 -1
- package/ccw/dist/commands/cli.js +129 -8
- package/ccw/dist/commands/cli.js.map +1 -1
- package/ccw/dist/commands/hook.d.ts.map +1 -1
- package/ccw/dist/commands/hook.js +3 -2
- package/ccw/dist/commands/hook.js.map +1 -1
- package/ccw/dist/config/litellm-api-config-manager.d.ts +180 -0
- package/ccw/dist/config/litellm-api-config-manager.d.ts.map +1 -0
- package/ccw/dist/config/litellm-api-config-manager.js +770 -0
- package/ccw/dist/config/litellm-api-config-manager.js.map +1 -0
- package/ccw/dist/config/provider-models.d.ts +73 -0
- package/ccw/dist/config/provider-models.d.ts.map +1 -0
- package/ccw/dist/config/provider-models.js +172 -0
- package/ccw/dist/config/provider-models.js.map +1 -0
- package/ccw/dist/core/cache-manager.d.ts.map +1 -1
- package/ccw/dist/core/cache-manager.js +3 -5
- package/ccw/dist/core/cache-manager.js.map +1 -1
- package/ccw/dist/core/dashboard-generator.d.ts.map +1 -1
- package/ccw/dist/core/dashboard-generator.js +3 -1
- package/ccw/dist/core/dashboard-generator.js.map +1 -1
- package/ccw/dist/core/routes/cli-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/cli-routes.js +169 -0
- package/ccw/dist/core/routes/cli-routes.js.map +1 -1
- package/ccw/dist/core/routes/codexlens-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/codexlens-routes.js +234 -18
- package/ccw/dist/core/routes/codexlens-routes.js.map +1 -1
- package/ccw/dist/core/routes/hooks-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/hooks-routes.js +30 -32
- package/ccw/dist/core/routes/hooks-routes.js.map +1 -1
- package/ccw/dist/core/routes/litellm-api-routes.d.ts +21 -0
- package/ccw/dist/core/routes/litellm-api-routes.d.ts.map +1 -0
- package/ccw/dist/core/routes/litellm-api-routes.js +780 -0
- package/ccw/dist/core/routes/litellm-api-routes.js.map +1 -0
- package/ccw/dist/core/routes/litellm-routes.d.ts +20 -0
- package/ccw/dist/core/routes/litellm-routes.d.ts.map +1 -0
- package/ccw/dist/core/routes/litellm-routes.js +85 -0
- package/ccw/dist/core/routes/litellm-routes.js.map +1 -0
- package/ccw/dist/core/routes/mcp-routes.js +2 -2
- package/ccw/dist/core/routes/mcp-routes.js.map +1 -1
- package/ccw/dist/core/routes/status-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/status-routes.js +39 -0
- package/ccw/dist/core/routes/status-routes.js.map +1 -1
- package/ccw/dist/core/routes/system-routes.js +1 -1
- package/ccw/dist/core/routes/system-routes.js.map +1 -1
- package/ccw/dist/core/server.d.ts.map +1 -1
- package/ccw/dist/core/server.js +15 -1
- package/ccw/dist/core/server.js.map +1 -1
- package/ccw/dist/mcp-server/index.js +1 -1
- package/ccw/dist/mcp-server/index.js.map +1 -1
- package/ccw/dist/tools/claude-cli-tools.d.ts +82 -0
- package/ccw/dist/tools/claude-cli-tools.d.ts.map +1 -0
- package/ccw/dist/tools/claude-cli-tools.js +216 -0
- package/ccw/dist/tools/claude-cli-tools.js.map +1 -0
- package/ccw/dist/tools/cli-executor.d.ts.map +1 -1
- package/ccw/dist/tools/cli-executor.js +76 -14
- package/ccw/dist/tools/cli-executor.js.map +1 -1
- package/ccw/dist/tools/codex-lens.d.ts +9 -2
- package/ccw/dist/tools/codex-lens.d.ts.map +1 -1
- package/ccw/dist/tools/codex-lens.js +114 -9
- package/ccw/dist/tools/codex-lens.js.map +1 -1
- package/ccw/dist/tools/context-cache-store.d.ts +136 -0
- package/ccw/dist/tools/context-cache-store.d.ts.map +1 -0
- package/ccw/dist/tools/context-cache-store.js +256 -0
- package/ccw/dist/tools/context-cache-store.js.map +1 -0
- package/ccw/dist/tools/context-cache.d.ts +56 -0
- package/ccw/dist/tools/context-cache.d.ts.map +1 -0
- package/ccw/dist/tools/context-cache.js +294 -0
- package/ccw/dist/tools/context-cache.js.map +1 -0
- package/ccw/dist/tools/core-memory.d.ts.map +1 -1
- package/ccw/dist/tools/core-memory.js +33 -19
- package/ccw/dist/tools/core-memory.js.map +1 -1
- package/ccw/dist/tools/index.d.ts.map +1 -1
- package/ccw/dist/tools/index.js +2 -0
- package/ccw/dist/tools/index.js.map +1 -1
- package/ccw/dist/tools/litellm-client.d.ts +85 -0
- package/ccw/dist/tools/litellm-client.d.ts.map +1 -0
- package/ccw/dist/tools/litellm-client.js +188 -0
- package/ccw/dist/tools/litellm-client.js.map +1 -0
- package/ccw/dist/tools/litellm-executor.d.ts +34 -0
- package/ccw/dist/tools/litellm-executor.d.ts.map +1 -0
- package/ccw/dist/tools/litellm-executor.js +192 -0
- package/ccw/dist/tools/litellm-executor.js.map +1 -0
- package/ccw/dist/tools/pattern-parser.d.ts +55 -0
- package/ccw/dist/tools/pattern-parser.d.ts.map +1 -0
- package/ccw/dist/tools/pattern-parser.js +237 -0
- package/ccw/dist/tools/pattern-parser.js.map +1 -0
- package/ccw/dist/tools/smart-search.d.ts +1 -0
- package/ccw/dist/tools/smart-search.d.ts.map +1 -1
- package/ccw/dist/tools/smart-search.js +117 -41
- package/ccw/dist/tools/smart-search.js.map +1 -1
- package/ccw/dist/types/litellm-api-config.d.ts +294 -0
- package/ccw/dist/types/litellm-api-config.d.ts.map +1 -0
- package/ccw/dist/types/litellm-api-config.js +8 -0
- package/ccw/dist/types/litellm-api-config.js.map +1 -0
- package/ccw/src/cli.ts +258 -244
- package/ccw/src/commands/cli.ts +153 -9
- package/ccw/src/commands/hook.ts +3 -2
- package/ccw/src/config/.litellm-api-config-manager.ts.2025-12-23T11-57-43-727Z.bak +441 -0
- package/ccw/src/config/litellm-api-config-manager.ts +1012 -0
- package/ccw/src/config/provider-models.ts +222 -0
- package/ccw/src/core/cache-manager.ts +292 -294
- package/ccw/src/core/dashboard-generator.ts +3 -1
- package/ccw/src/core/routes/cli-routes.ts +192 -0
- package/ccw/src/core/routes/codexlens-routes.ts +241 -19
- package/ccw/src/core/routes/hooks-routes.ts +399 -405
- package/ccw/src/core/routes/litellm-api-routes.ts +930 -0
- package/ccw/src/core/routes/litellm-routes.ts +107 -0
- package/ccw/src/core/routes/mcp-routes.ts +1271 -1271
- package/ccw/src/core/routes/status-routes.ts +51 -0
- package/ccw/src/core/routes/system-routes.ts +1 -1
- package/ccw/src/core/server.ts +15 -1
- package/ccw/src/mcp-server/index.ts +1 -1
- package/ccw/src/templates/dashboard-css/12-cli-legacy.css +44 -0
- package/ccw/src/templates/dashboard-css/31-api-settings.css +2265 -0
- package/ccw/src/templates/dashboard-js/components/cli-history.js +15 -8
- package/ccw/src/templates/dashboard-js/components/cli-status.js +323 -9
- package/ccw/src/templates/dashboard-js/components/navigation.js +329 -313
- package/ccw/src/templates/dashboard-js/i18n.js +583 -1
- package/ccw/src/templates/dashboard-js/views/api-settings.js +3362 -0
- package/ccw/src/templates/dashboard-js/views/cli-manager.js +199 -24
- package/ccw/src/templates/dashboard-js/views/codexlens-manager.js +1265 -27
- package/ccw/src/templates/dashboard.html +840 -831
- package/ccw/src/tools/claude-cli-tools.ts +300 -0
- package/ccw/src/tools/cli-executor.ts +83 -14
- package/ccw/src/tools/codex-lens.ts +146 -9
- package/ccw/src/tools/context-cache-store.ts +368 -0
- package/ccw/src/tools/context-cache.ts +393 -0
- package/ccw/src/tools/core-memory.ts +33 -19
- package/ccw/src/tools/index.ts +2 -0
- package/ccw/src/tools/litellm-client.ts +246 -0
- package/ccw/src/tools/litellm-executor.ts +241 -0
- package/ccw/src/tools/pattern-parser.ts +329 -0
- package/ccw/src/tools/smart-search.ts +142 -41
- package/ccw/src/types/litellm-api-config.ts +402 -0
- package/ccw-litellm/README.md +180 -0
- package/ccw-litellm/pyproject.toml +35 -0
- package/ccw-litellm/src/ccw_litellm/__init__.py +47 -0
- package/ccw-litellm/src/ccw_litellm/__pycache__/__init__.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/__pycache__/cli.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/cli.py +108 -0
- package/ccw-litellm/src/ccw_litellm/clients/__init__.py +12 -0
- package/ccw-litellm/src/ccw_litellm/clients/__pycache__/__init__.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/clients/__pycache__/litellm_embedder.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/clients/__pycache__/litellm_llm.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/clients/litellm_embedder.py +251 -0
- package/ccw-litellm/src/ccw_litellm/clients/litellm_llm.py +165 -0
- package/ccw-litellm/src/ccw_litellm/config/__init__.py +22 -0
- package/ccw-litellm/src/ccw_litellm/config/__pycache__/__init__.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/config/__pycache__/loader.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/config/__pycache__/models.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/config/loader.py +316 -0
- package/ccw-litellm/src/ccw_litellm/config/models.py +130 -0
- package/ccw-litellm/src/ccw_litellm/interfaces/__init__.py +14 -0
- package/ccw-litellm/src/ccw_litellm/interfaces/__pycache__/__init__.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/interfaces/__pycache__/embedder.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/interfaces/__pycache__/llm.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/interfaces/embedder.py +52 -0
- package/ccw-litellm/src/ccw_litellm/interfaces/llm.py +45 -0
- package/codex-lens/src/codexlens/__pycache__/config.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/commands.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/embedding_manager.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/model_manager.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/output.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/commands.py +378 -23
- package/codex-lens/src/codexlens/cli/embedding_manager.py +660 -56
- package/codex-lens/src/codexlens/cli/model_manager.py +31 -18
- package/codex-lens/src/codexlens/cli/output.py +12 -1
- package/codex-lens/src/codexlens/config.py +93 -0
- package/codex-lens/src/codexlens/search/__pycache__/chain_search.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/hybrid_search.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/ranking.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/chain_search.py +6 -2
- package/codex-lens/src/codexlens/search/hybrid_search.py +44 -21
- package/codex-lens/src/codexlens/search/ranking.py +1 -1
- package/codex-lens/src/codexlens/semantic/__init__.py +42 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/base.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/chunker.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/embedder.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/factory.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/gpu_support.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/litellm_embedder.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/vector_store.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/base.py +61 -0
- package/codex-lens/src/codexlens/semantic/chunker.py +43 -20
- package/codex-lens/src/codexlens/semantic/embedder.py +60 -13
- package/codex-lens/src/codexlens/semantic/factory.py +98 -0
- package/codex-lens/src/codexlens/semantic/gpu_support.py +225 -3
- package/codex-lens/src/codexlens/semantic/litellm_embedder.py +144 -0
- package/codex-lens/src/codexlens/semantic/rotational_embedder.py +434 -0
- package/codex-lens/src/codexlens/semantic/vector_store.py +33 -8
- package/codex-lens/src/codexlens/storage/__pycache__/path_mapper.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_004_dual_fts.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/path_mapper.py +27 -1
- package/package.json +15 -5
- package/.codex/prompts.zip +0 -0
- package/ccw/package.json +0 -65
package/ccw/src/commands/cli.ts
CHANGED
|
@@ -78,6 +78,14 @@ interface CliExecOptions {
|
|
|
78
78
|
resume?: string | boolean; // true = last, string = execution ID, comma-separated for merge
|
|
79
79
|
id?: string; // Custom execution ID (e.g., IMPL-001-step1)
|
|
80
80
|
noNative?: boolean; // Force prompt concatenation instead of native resume
|
|
81
|
+
cache?: string | boolean; // Cache: true = auto from CONTEXT, string = comma-separated patterns/content
|
|
82
|
+
injectMode?: 'none' | 'full' | 'progressive'; // Inject mode for cached content
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Cache configuration parsed from --cache */
|
|
86
|
+
interface CacheConfig {
|
|
87
|
+
patterns?: string[]; // @patterns to pack (items starting with @)
|
|
88
|
+
content?: string; // Additional text content (items not starting with @)
|
|
81
89
|
}
|
|
82
90
|
|
|
83
91
|
interface HistoryOptions {
|
|
@@ -91,7 +99,7 @@ interface StorageOptions {
|
|
|
91
99
|
project?: string;
|
|
92
100
|
cliHistory?: boolean;
|
|
93
101
|
memory?: boolean;
|
|
94
|
-
|
|
102
|
+
storageCache?: boolean;
|
|
95
103
|
config?: boolean;
|
|
96
104
|
force?: boolean;
|
|
97
105
|
}
|
|
@@ -173,15 +181,15 @@ async function showStorageInfo(): Promise<void> {
|
|
|
173
181
|
* Clean storage
|
|
174
182
|
*/
|
|
175
183
|
async function cleanStorage(options: StorageOptions): Promise<void> {
|
|
176
|
-
const { all, project, force, cliHistory, memory,
|
|
184
|
+
const { all, project, force, cliHistory, memory, storageCache, config } = options;
|
|
177
185
|
|
|
178
186
|
// Determine what to clean
|
|
179
187
|
const cleanTypes = {
|
|
180
|
-
cliHistory: cliHistory || (!cliHistory && !memory && !
|
|
181
|
-
memory: memory || (!cliHistory && !memory && !
|
|
182
|
-
cache:
|
|
188
|
+
cliHistory: cliHistory || (!cliHistory && !memory && !storageCache && !config),
|
|
189
|
+
memory: memory || (!cliHistory && !memory && !storageCache && !config),
|
|
190
|
+
cache: storageCache || (!cliHistory && !memory && !storageCache && !config),
|
|
183
191
|
config: config || false, // Config requires explicit flag
|
|
184
|
-
all: !cliHistory && !memory && !
|
|
192
|
+
all: !cliHistory && !memory && !storageCache && !config
|
|
185
193
|
};
|
|
186
194
|
|
|
187
195
|
if (project) {
|
|
@@ -383,7 +391,7 @@ async function statusAction(): Promise<void> {
|
|
|
383
391
|
* @param {Object} options - CLI options
|
|
384
392
|
*/
|
|
385
393
|
async function execAction(positionalPrompt: string | undefined, options: CliExecOptions): Promise<void> {
|
|
386
|
-
const { prompt: optionPrompt, file, tool = 'gemini', mode = 'analysis', model, cd, includeDirs, timeout, noStream, resume, id, noNative } = options;
|
|
394
|
+
const { prompt: optionPrompt, file, tool = 'gemini', mode = 'analysis', model, cd, includeDirs, timeout, noStream, resume, id, noNative, cache, injectMode } = options;
|
|
387
395
|
|
|
388
396
|
// Priority: 1. --file, 2. --prompt/-p option, 3. positional argument
|
|
389
397
|
let finalPrompt: string | undefined;
|
|
@@ -421,6 +429,128 @@ async function execAction(positionalPrompt: string | undefined, options: CliExec
|
|
|
421
429
|
|
|
422
430
|
const prompt_to_use = finalPrompt || '';
|
|
423
431
|
|
|
432
|
+
// Handle cache option: pack @patterns and/or content
|
|
433
|
+
let cacheSessionId: string | undefined;
|
|
434
|
+
let actualPrompt = prompt_to_use;
|
|
435
|
+
|
|
436
|
+
if (cache) {
|
|
437
|
+
const { handler: contextCacheHandler } = await import('../tools/context-cache.js');
|
|
438
|
+
|
|
439
|
+
// Parse cache config from comma-separated string
|
|
440
|
+
// Items starting with @ are patterns, others are text content
|
|
441
|
+
let cacheConfig: CacheConfig = {};
|
|
442
|
+
|
|
443
|
+
if (cache === true) {
|
|
444
|
+
// --cache without value: auto-extract from CONTEXT field
|
|
445
|
+
const contextMatch = prompt_to_use.match(/CONTEXT:\s*([^\n]+)/i);
|
|
446
|
+
if (contextMatch) {
|
|
447
|
+
const contextLine = contextMatch[1];
|
|
448
|
+
const patternMatches = contextLine.matchAll(/@[^\s|]+/g);
|
|
449
|
+
cacheConfig.patterns = Array.from(patternMatches).map(m => m[0]);
|
|
450
|
+
}
|
|
451
|
+
} else if (typeof cache === 'string') {
|
|
452
|
+
// Parse comma-separated items: @patterns and text content
|
|
453
|
+
const items = cache.split(',').map(s => s.trim()).filter(Boolean);
|
|
454
|
+
const patterns: string[] = [];
|
|
455
|
+
const contentParts: string[] = [];
|
|
456
|
+
|
|
457
|
+
for (const item of items) {
|
|
458
|
+
if (item.startsWith('@')) {
|
|
459
|
+
patterns.push(item);
|
|
460
|
+
} else {
|
|
461
|
+
contentParts.push(item);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (patterns.length > 0) {
|
|
466
|
+
cacheConfig.patterns = patterns;
|
|
467
|
+
}
|
|
468
|
+
if (contentParts.length > 0) {
|
|
469
|
+
cacheConfig.content = contentParts.join('\n');
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// Also extract patterns from CONTEXT if not provided
|
|
474
|
+
if ((!cacheConfig.patterns || cacheConfig.patterns.length === 0) && prompt_to_use) {
|
|
475
|
+
const contextMatch = prompt_to_use.match(/CONTEXT:\s*([^\n]+)/i);
|
|
476
|
+
if (contextMatch) {
|
|
477
|
+
const contextLine = contextMatch[1];
|
|
478
|
+
const patternMatches = contextLine.matchAll(/@[^\s|]+/g);
|
|
479
|
+
cacheConfig.patterns = Array.from(patternMatches).map(m => m[0]);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Pack if we have patterns or content
|
|
484
|
+
if ((cacheConfig.patterns && cacheConfig.patterns.length > 0) || cacheConfig.content) {
|
|
485
|
+
const patternCount = cacheConfig.patterns?.length || 0;
|
|
486
|
+
const hasContent = !!cacheConfig.content;
|
|
487
|
+
console.log(chalk.gray(` Caching: ${patternCount} pattern(s)${hasContent ? ' + text content' : ''}...`));
|
|
488
|
+
|
|
489
|
+
const cacheResult = await contextCacheHandler({
|
|
490
|
+
operation: 'pack',
|
|
491
|
+
patterns: cacheConfig.patterns,
|
|
492
|
+
content: cacheConfig.content,
|
|
493
|
+
cwd: cd || process.cwd(),
|
|
494
|
+
include_dirs: includeDirs ? includeDirs.split(',') : undefined,
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
if (cacheResult.success && cacheResult.result) {
|
|
498
|
+
const packResult = cacheResult.result as { session_id: string; files_packed: number; total_bytes: number };
|
|
499
|
+
cacheSessionId = packResult.session_id;
|
|
500
|
+
console.log(chalk.gray(` Cached: ${packResult.files_packed} files, ${packResult.total_bytes} bytes`));
|
|
501
|
+
console.log(chalk.gray(` Session: ${cacheSessionId}`));
|
|
502
|
+
|
|
503
|
+
// Determine inject mode:
|
|
504
|
+
// --inject-mode explicitly set > tool default (codex=full, others=none)
|
|
505
|
+
const effectiveInjectMode = injectMode ?? (tool === 'codex' ? 'full' : 'none');
|
|
506
|
+
|
|
507
|
+
if (effectiveInjectMode !== 'none' && cacheSessionId) {
|
|
508
|
+
if (effectiveInjectMode === 'full') {
|
|
509
|
+
// Read full cache content
|
|
510
|
+
const readResult = await contextCacheHandler({
|
|
511
|
+
operation: 'read',
|
|
512
|
+
session_id: cacheSessionId,
|
|
513
|
+
offset: 0,
|
|
514
|
+
limit: 1024 * 1024, // 1MB max
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
if (readResult.success && readResult.result) {
|
|
518
|
+
const { content: cachedContent, total_bytes } = readResult.result as { content: string; total_bytes: number };
|
|
519
|
+
console.log(chalk.gray(` Injecting ${total_bytes} bytes (full mode)...`));
|
|
520
|
+
actualPrompt = `=== CACHED CONTEXT (${packResult.files_packed} files) ===\n${cachedContent}\n\n=== USER PROMPT ===\n${prompt_to_use}`;
|
|
521
|
+
}
|
|
522
|
+
} else if (effectiveInjectMode === 'progressive') {
|
|
523
|
+
// Progressive mode: read first page only (64KB default)
|
|
524
|
+
const pageLimit = 65536;
|
|
525
|
+
const readResult = await contextCacheHandler({
|
|
526
|
+
operation: 'read',
|
|
527
|
+
session_id: cacheSessionId,
|
|
528
|
+
offset: 0,
|
|
529
|
+
limit: pageLimit,
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
if (readResult.success && readResult.result) {
|
|
533
|
+
const { content: cachedContent, total_bytes, has_more, next_offset } = readResult.result as {
|
|
534
|
+
content: string; total_bytes: number; has_more: boolean; next_offset: number | null
|
|
535
|
+
};
|
|
536
|
+
console.log(chalk.gray(` Injecting ${cachedContent.length}/${total_bytes} bytes (progressive mode)...`));
|
|
537
|
+
|
|
538
|
+
const moreInfo = has_more
|
|
539
|
+
? `\n[... ${total_bytes - cachedContent.length} more bytes available via: context_cache(operation="read", session_id="${cacheSessionId}", offset=${next_offset}) ...]`
|
|
540
|
+
: '';
|
|
541
|
+
|
|
542
|
+
actualPrompt = `=== CACHED CONTEXT (${packResult.files_packed} files, progressive) ===\n${cachedContent}${moreInfo}\n\n=== USER PROMPT ===\n${prompt_to_use}`;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
console.log();
|
|
548
|
+
} else {
|
|
549
|
+
console.log(chalk.yellow(` Cache warning: ${cacheResult.error}`));
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
424
554
|
// Parse resume IDs for merge scenario
|
|
425
555
|
const resumeIds = resume && typeof resume === 'string' ? resume.split(',').map(s => s.trim()).filter(Boolean) : [];
|
|
426
556
|
const isMerge = resumeIds.length > 1;
|
|
@@ -462,7 +592,7 @@ async function execAction(positionalPrompt: string | undefined, options: CliExec
|
|
|
462
592
|
try {
|
|
463
593
|
const result = await cliExecutorTool.execute({
|
|
464
594
|
tool,
|
|
465
|
-
prompt:
|
|
595
|
+
prompt: actualPrompt,
|
|
466
596
|
mode,
|
|
467
597
|
model,
|
|
468
598
|
cd,
|
|
@@ -725,14 +855,28 @@ export async function cliCommand(
|
|
|
725
855
|
console.log(chalk.gray(' --model <model> Model override'));
|
|
726
856
|
console.log(chalk.gray(' --cd <path> Working directory'));
|
|
727
857
|
console.log(chalk.gray(' --includeDirs <dirs> Additional directories'));
|
|
728
|
-
console.log(chalk.gray(' --timeout <ms> Timeout (default:
|
|
858
|
+
console.log(chalk.gray(' --timeout <ms> Timeout (default: 0=disabled)'));
|
|
729
859
|
console.log(chalk.gray(' --resume [id] Resume previous session'));
|
|
860
|
+
console.log(chalk.gray(' --cache <items> Cache: comma-separated @patterns and text'));
|
|
861
|
+
console.log(chalk.gray(' --inject-mode <m> Inject mode: none, full, progressive'));
|
|
862
|
+
console.log();
|
|
863
|
+
console.log(' Cache format:');
|
|
864
|
+
console.log(chalk.gray(' --cache "@src/**/*.ts,@CLAUDE.md" # @patterns to pack'));
|
|
865
|
+
console.log(chalk.gray(' --cache "@src/**/*,extra context" # patterns + text content'));
|
|
866
|
+
console.log(chalk.gray(' --cache # auto from CONTEXT field'));
|
|
867
|
+
console.log();
|
|
868
|
+
console.log(' Inject modes:');
|
|
869
|
+
console.log(chalk.gray(' none: cache only, no injection (default for gemini/qwen)'));
|
|
870
|
+
console.log(chalk.gray(' full: inject all cached content (default for codex)'));
|
|
871
|
+
console.log(chalk.gray(' progressive: inject first 64KB with MCP continuation hint'));
|
|
730
872
|
console.log();
|
|
731
873
|
console.log(' Examples:');
|
|
732
874
|
console.log(chalk.gray(' ccw cli -p "Analyze auth module" --tool gemini'));
|
|
733
875
|
console.log(chalk.gray(' ccw cli -f prompt.txt --tool codex --mode write'));
|
|
734
876
|
console.log(chalk.gray(' ccw cli -p "$(cat template.md)" --tool gemini'));
|
|
735
877
|
console.log(chalk.gray(' ccw cli --resume --tool gemini'));
|
|
878
|
+
console.log(chalk.gray(' ccw cli -p "..." --cache "@src/**/*.ts" --tool codex'));
|
|
879
|
+
console.log(chalk.gray(' ccw cli -p "..." --cache "@src/**/*" --inject-mode progressive --tool gemini'));
|
|
736
880
|
console.log();
|
|
737
881
|
}
|
|
738
882
|
}
|
package/ccw/src/commands/hook.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import chalk from 'chalk';
|
|
7
7
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
8
8
|
import { join, dirname } from 'path';
|
|
9
|
-
import {
|
|
9
|
+
import { homedir } from 'os';
|
|
10
10
|
|
|
11
11
|
interface HookOptions {
|
|
12
12
|
stdin?: boolean;
|
|
@@ -53,9 +53,10 @@ async function readStdin(): Promise<string> {
|
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
55
|
* Get session state file path
|
|
56
|
+
* Uses ~/.claude/.ccw-sessions/ for reliable persistence across sessions
|
|
56
57
|
*/
|
|
57
58
|
function getSessionStateFile(sessionId: string): string {
|
|
58
|
-
const stateDir = join(
|
|
59
|
+
const stateDir = join(homedir(), '.claude', '.ccw-sessions');
|
|
59
60
|
if (!existsSync(stateDir)) {
|
|
60
61
|
mkdirSync(stateDir, { recursive: true });
|
|
61
62
|
}
|
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LiteLLM API Config Manager
|
|
3
|
+
* Manages provider credentials, endpoint configurations, and model discovery
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
8
|
+
import { homedir } from 'os';
|
|
9
|
+
|
|
10
|
+
// ===========================
|
|
11
|
+
// Type Definitions
|
|
12
|
+
// ===========================
|
|
13
|
+
|
|
14
|
+
export type ProviderType =
|
|
15
|
+
| 'openai'
|
|
16
|
+
| 'anthropic'
|
|
17
|
+
| 'google'
|
|
18
|
+
| 'cohere'
|
|
19
|
+
| 'azure'
|
|
20
|
+
| 'bedrock'
|
|
21
|
+
| 'vertexai'
|
|
22
|
+
| 'huggingface'
|
|
23
|
+
| 'ollama'
|
|
24
|
+
| 'custom';
|
|
25
|
+
|
|
26
|
+
export interface ProviderCredential {
|
|
27
|
+
id: string;
|
|
28
|
+
name: string;
|
|
29
|
+
type: ProviderType;
|
|
30
|
+
apiKey?: string;
|
|
31
|
+
baseUrl?: string;
|
|
32
|
+
apiVersion?: string;
|
|
33
|
+
region?: string;
|
|
34
|
+
projectId?: string;
|
|
35
|
+
organizationId?: string;
|
|
36
|
+
enabled: boolean;
|
|
37
|
+
metadata?: Record<string, any>;
|
|
38
|
+
createdAt: string;
|
|
39
|
+
updatedAt: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface EndpointConfig {
|
|
43
|
+
id: string;
|
|
44
|
+
name: string;
|
|
45
|
+
providerId: string;
|
|
46
|
+
model: string;
|
|
47
|
+
alias?: string;
|
|
48
|
+
temperature?: number;
|
|
49
|
+
maxTokens?: number;
|
|
50
|
+
topP?: number;
|
|
51
|
+
enabled: boolean;
|
|
52
|
+
metadata?: Record<string, any>;
|
|
53
|
+
createdAt: string;
|
|
54
|
+
updatedAt: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface ModelInfo {
|
|
58
|
+
id: string;
|
|
59
|
+
name: string;
|
|
60
|
+
provider: ProviderType;
|
|
61
|
+
contextWindow: number;
|
|
62
|
+
supportsFunctions: boolean;
|
|
63
|
+
supportsStreaming: boolean;
|
|
64
|
+
inputCostPer1k?: number;
|
|
65
|
+
outputCostPer1k?: number;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface LiteLLMApiConfig {
|
|
69
|
+
version: string;
|
|
70
|
+
providers: ProviderCredential[];
|
|
71
|
+
endpoints: EndpointConfig[];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ===========================
|
|
75
|
+
// Model Definitions
|
|
76
|
+
// ===========================
|
|
77
|
+
|
|
78
|
+
export const PROVIDER_MODELS: Record<ProviderType, ModelInfo[]> = {
|
|
79
|
+
openai: [
|
|
80
|
+
{
|
|
81
|
+
id: 'gpt-4-turbo',
|
|
82
|
+
name: 'GPT-4 Turbo',
|
|
83
|
+
provider: 'openai',
|
|
84
|
+
contextWindow: 128000,
|
|
85
|
+
supportsFunctions: true,
|
|
86
|
+
supportsStreaming: true,
|
|
87
|
+
inputCostPer1k: 0.01,
|
|
88
|
+
outputCostPer1k: 0.03,
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: 'gpt-4',
|
|
92
|
+
name: 'GPT-4',
|
|
93
|
+
provider: 'openai',
|
|
94
|
+
contextWindow: 8192,
|
|
95
|
+
supportsFunctions: true,
|
|
96
|
+
supportsStreaming: true,
|
|
97
|
+
inputCostPer1k: 0.03,
|
|
98
|
+
outputCostPer1k: 0.06,
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
id: 'gpt-3.5-turbo',
|
|
102
|
+
name: 'GPT-3.5 Turbo',
|
|
103
|
+
provider: 'openai',
|
|
104
|
+
contextWindow: 16385,
|
|
105
|
+
supportsFunctions: true,
|
|
106
|
+
supportsStreaming: true,
|
|
107
|
+
inputCostPer1k: 0.0005,
|
|
108
|
+
outputCostPer1k: 0.0015,
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
anthropic: [
|
|
112
|
+
{
|
|
113
|
+
id: 'claude-3-opus-20240229',
|
|
114
|
+
name: 'Claude 3 Opus',
|
|
115
|
+
provider: 'anthropic',
|
|
116
|
+
contextWindow: 200000,
|
|
117
|
+
supportsFunctions: true,
|
|
118
|
+
supportsStreaming: true,
|
|
119
|
+
inputCostPer1k: 0.015,
|
|
120
|
+
outputCostPer1k: 0.075,
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
id: 'claude-3-sonnet-20240229',
|
|
124
|
+
name: 'Claude 3 Sonnet',
|
|
125
|
+
provider: 'anthropic',
|
|
126
|
+
contextWindow: 200000,
|
|
127
|
+
supportsFunctions: true,
|
|
128
|
+
supportsStreaming: true,
|
|
129
|
+
inputCostPer1k: 0.003,
|
|
130
|
+
outputCostPer1k: 0.015,
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
id: 'claude-3-haiku-20240307',
|
|
134
|
+
name: 'Claude 3 Haiku',
|
|
135
|
+
provider: 'anthropic',
|
|
136
|
+
contextWindow: 200000,
|
|
137
|
+
supportsFunctions: true,
|
|
138
|
+
supportsStreaming: true,
|
|
139
|
+
inputCostPer1k: 0.00025,
|
|
140
|
+
outputCostPer1k: 0.00125,
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
google: [
|
|
144
|
+
{
|
|
145
|
+
id: 'gemini-pro',
|
|
146
|
+
name: 'Gemini Pro',
|
|
147
|
+
provider: 'google',
|
|
148
|
+
contextWindow: 32768,
|
|
149
|
+
supportsFunctions: true,
|
|
150
|
+
supportsStreaming: true,
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
id: 'gemini-pro-vision',
|
|
154
|
+
name: 'Gemini Pro Vision',
|
|
155
|
+
provider: 'google',
|
|
156
|
+
contextWindow: 16384,
|
|
157
|
+
supportsFunctions: false,
|
|
158
|
+
supportsStreaming: true,
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
cohere: [
|
|
162
|
+
{
|
|
163
|
+
id: 'command',
|
|
164
|
+
name: 'Command',
|
|
165
|
+
provider: 'cohere',
|
|
166
|
+
contextWindow: 4096,
|
|
167
|
+
supportsFunctions: false,
|
|
168
|
+
supportsStreaming: true,
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
id: 'command-light',
|
|
172
|
+
name: 'Command Light',
|
|
173
|
+
provider: 'cohere',
|
|
174
|
+
contextWindow: 4096,
|
|
175
|
+
supportsFunctions: false,
|
|
176
|
+
supportsStreaming: true,
|
|
177
|
+
},
|
|
178
|
+
],
|
|
179
|
+
azure: [],
|
|
180
|
+
bedrock: [],
|
|
181
|
+
vertexai: [],
|
|
182
|
+
huggingface: [],
|
|
183
|
+
ollama: [],
|
|
184
|
+
custom: [],
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
// ===========================
|
|
188
|
+
// Config File Management
|
|
189
|
+
// ===========================
|
|
190
|
+
|
|
191
|
+
const CONFIG_DIR = join(homedir(), '.claude', 'litellm');
|
|
192
|
+
const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
|
|
193
|
+
|
|
194
|
+
function ensureConfigDir(): void {
|
|
195
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
196
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function loadConfig(): LiteLLMApiConfig {
|
|
201
|
+
ensureConfigDir();
|
|
202
|
+
|
|
203
|
+
if (!existsSync(CONFIG_FILE)) {
|
|
204
|
+
const defaultConfig: LiteLLMApiConfig = {
|
|
205
|
+
version: '1.0.0',
|
|
206
|
+
providers: [],
|
|
207
|
+
endpoints: [],
|
|
208
|
+
};
|
|
209
|
+
saveConfig(defaultConfig);
|
|
210
|
+
return defaultConfig;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
try {
|
|
214
|
+
const content = readFileSync(CONFIG_FILE, 'utf-8');
|
|
215
|
+
return JSON.parse(content);
|
|
216
|
+
} catch (err) {
|
|
217
|
+
throw new Error(`Failed to load config: ${(err as Error).message}`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function saveConfig(config: LiteLLMApiConfig): void {
|
|
222
|
+
ensureConfigDir();
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf-8');
|
|
226
|
+
} catch (err) {
|
|
227
|
+
throw new Error(`Failed to save config: ${(err as Error).message}`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// ===========================
|
|
232
|
+
// Provider Management
|
|
233
|
+
// ===========================
|
|
234
|
+
|
|
235
|
+
export function getAllProviders(): ProviderCredential[] {
|
|
236
|
+
const config = loadConfig();
|
|
237
|
+
return config.providers;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export function getProvider(id: string): ProviderCredential | null {
|
|
241
|
+
const config = loadConfig();
|
|
242
|
+
return config.providers.find((p) => p.id === id) || null;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export function createProvider(
|
|
246
|
+
data: Omit<ProviderCredential, 'id' | 'createdAt' | 'updatedAt'>
|
|
247
|
+
): ProviderCredential {
|
|
248
|
+
const config = loadConfig();
|
|
249
|
+
|
|
250
|
+
const now = new Date().toISOString();
|
|
251
|
+
const provider: ProviderCredential = {
|
|
252
|
+
...data,
|
|
253
|
+
id: `provider-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
254
|
+
createdAt: now,
|
|
255
|
+
updatedAt: now,
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
config.providers.push(provider);
|
|
259
|
+
saveConfig(config);
|
|
260
|
+
|
|
261
|
+
return provider;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function updateProvider(
|
|
265
|
+
id: string,
|
|
266
|
+
updates: Partial<ProviderCredential>
|
|
267
|
+
): ProviderCredential | null {
|
|
268
|
+
const config = loadConfig();
|
|
269
|
+
|
|
270
|
+
const index = config.providers.findIndex((p) => p.id === id);
|
|
271
|
+
if (index === -1) {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const updated: ProviderCredential = {
|
|
276
|
+
...config.providers[index],
|
|
277
|
+
...updates,
|
|
278
|
+
id,
|
|
279
|
+
updatedAt: new Date().toISOString(),
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
config.providers[index] = updated;
|
|
283
|
+
saveConfig(config);
|
|
284
|
+
|
|
285
|
+
return updated;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export function deleteProvider(id: string): { success: boolean } {
|
|
289
|
+
const config = loadConfig();
|
|
290
|
+
|
|
291
|
+
const index = config.providers.findIndex((p) => p.id === id);
|
|
292
|
+
if (index === -1) {
|
|
293
|
+
return { success: false };
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
config.providers.splice(index, 1);
|
|
297
|
+
|
|
298
|
+
// Also delete endpoints using this provider
|
|
299
|
+
config.endpoints = config.endpoints.filter((e) => e.providerId !== id);
|
|
300
|
+
|
|
301
|
+
saveConfig(config);
|
|
302
|
+
|
|
303
|
+
return { success: true };
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export async function testProviderConnection(
|
|
307
|
+
providerId: string
|
|
308
|
+
): Promise<{ success: boolean; error?: string }> {
|
|
309
|
+
const provider = getProvider(providerId);
|
|
310
|
+
|
|
311
|
+
if (!provider) {
|
|
312
|
+
return { success: false, error: 'Provider not found' };
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (!provider.enabled) {
|
|
316
|
+
return { success: false, error: 'Provider is disabled' };
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Basic validation
|
|
320
|
+
if (!provider.apiKey && provider.type !== 'ollama' && provider.type !== 'custom') {
|
|
321
|
+
return { success: false, error: 'API key is required for this provider type' };
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// TODO: Implement actual provider connection testing using litellm-client
|
|
325
|
+
// For now, just validate the configuration
|
|
326
|
+
return { success: true };
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// ===========================
|
|
330
|
+
// Endpoint Management
|
|
331
|
+
// ===========================
|
|
332
|
+
|
|
333
|
+
export function getAllEndpoints(): EndpointConfig[] {
|
|
334
|
+
const config = loadConfig();
|
|
335
|
+
return config.endpoints;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export function getEndpoint(id: string): EndpointConfig | null {
|
|
339
|
+
const config = loadConfig();
|
|
340
|
+
return config.endpoints.find((e) => e.id === id) || null;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export function createEndpoint(
|
|
344
|
+
data: Omit<EndpointConfig, 'id' | 'createdAt' | 'updatedAt'>
|
|
345
|
+
): EndpointConfig {
|
|
346
|
+
const config = loadConfig();
|
|
347
|
+
|
|
348
|
+
// Validate provider exists
|
|
349
|
+
const provider = config.providers.find((p) => p.id === data.providerId);
|
|
350
|
+
if (!provider) {
|
|
351
|
+
throw new Error('Provider not found');
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const now = new Date().toISOString();
|
|
355
|
+
const endpoint: EndpointConfig = {
|
|
356
|
+
...data,
|
|
357
|
+
id: `endpoint-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
358
|
+
createdAt: now,
|
|
359
|
+
updatedAt: now,
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
config.endpoints.push(endpoint);
|
|
363
|
+
saveConfig(config);
|
|
364
|
+
|
|
365
|
+
return endpoint;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export function updateEndpoint(
|
|
369
|
+
id: string,
|
|
370
|
+
updates: Partial<EndpointConfig>
|
|
371
|
+
): EndpointConfig | null {
|
|
372
|
+
const config = loadConfig();
|
|
373
|
+
|
|
374
|
+
const index = config.endpoints.findIndex((e) => e.id === id);
|
|
375
|
+
if (index === -1) {
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Validate provider if being updated
|
|
380
|
+
if (updates.providerId) {
|
|
381
|
+
const provider = config.providers.find((p) => p.id === updates.providerId);
|
|
382
|
+
if (!provider) {
|
|
383
|
+
throw new Error('Provider not found');
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
const updated: EndpointConfig = {
|
|
388
|
+
...config.endpoints[index],
|
|
389
|
+
...updates,
|
|
390
|
+
id,
|
|
391
|
+
updatedAt: new Date().toISOString(),
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
config.endpoints[index] = updated;
|
|
395
|
+
saveConfig(config);
|
|
396
|
+
|
|
397
|
+
return updated;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
export function deleteEndpoint(id: string): { success: boolean } {
|
|
401
|
+
const config = loadConfig();
|
|
402
|
+
|
|
403
|
+
const index = config.endpoints.findIndex((e) => e.id === id);
|
|
404
|
+
if (index === -1) {
|
|
405
|
+
return { success: false };
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
config.endpoints.splice(index, 1);
|
|
409
|
+
saveConfig(config);
|
|
410
|
+
|
|
411
|
+
return { success: true };
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// ===========================
|
|
415
|
+
// Model Discovery
|
|
416
|
+
// ===========================
|
|
417
|
+
|
|
418
|
+
export function getModelsForProviderType(providerType: ProviderType): ModelInfo[] | null {
|
|
419
|
+
return PROVIDER_MODELS[providerType] || null;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
export function getAllModels(): Record<ProviderType, ModelInfo[]> {
|
|
423
|
+
return PROVIDER_MODELS;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// ===========================
|
|
427
|
+
// Config Access
|
|
428
|
+
// ===========================
|
|
429
|
+
|
|
430
|
+
export function getFullConfig(): LiteLLMApiConfig {
|
|
431
|
+
return loadConfig();
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
export function resetConfig(): void {
|
|
435
|
+
const defaultConfig: LiteLLMApiConfig = {
|
|
436
|
+
version: '1.0.0',
|
|
437
|
+
providers: [],
|
|
438
|
+
endpoints: [],
|
|
439
|
+
};
|
|
440
|
+
saveConfig(defaultConfig);
|
|
441
|
+
}
|