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
|
@@ -33,6 +33,15 @@ import {
|
|
|
33
33
|
getFullConfigResponse,
|
|
34
34
|
PREDEFINED_MODELS
|
|
35
35
|
} from '../../tools/cli-config-manager.js';
|
|
36
|
+
import {
|
|
37
|
+
loadClaudeCliTools,
|
|
38
|
+
saveClaudeCliTools,
|
|
39
|
+
updateClaudeToolEnabled,
|
|
40
|
+
updateClaudeCacheSettings,
|
|
41
|
+
getClaudeCliToolsInfo,
|
|
42
|
+
addClaudeCustomEndpoint,
|
|
43
|
+
removeClaudeCustomEndpoint
|
|
44
|
+
} from '../../tools/claude-cli-tools.js';
|
|
36
45
|
|
|
37
46
|
export interface RouteContext {
|
|
38
47
|
pathname: string;
|
|
@@ -204,6 +213,93 @@ export async function handleCliRoutes(ctx: RouteContext): Promise<boolean> {
|
|
|
204
213
|
}
|
|
205
214
|
}
|
|
206
215
|
|
|
216
|
+
// API: Get all custom endpoints
|
|
217
|
+
if (pathname === '/api/cli/endpoints' && req.method === 'GET') {
|
|
218
|
+
try {
|
|
219
|
+
const config = loadClaudeCliTools(initialPath);
|
|
220
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
221
|
+
res.end(JSON.stringify({ endpoints: config.customEndpoints || [] }));
|
|
222
|
+
} catch (err) {
|
|
223
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
224
|
+
res.end(JSON.stringify({ error: (err as Error).message }));
|
|
225
|
+
}
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// API: Add/Update custom endpoint
|
|
230
|
+
if (pathname === '/api/cli/endpoints' && req.method === 'POST') {
|
|
231
|
+
handlePostRequest(req, res, async (body: unknown) => {
|
|
232
|
+
try {
|
|
233
|
+
const { id, name, enabled } = body as { id: string; name: string; enabled: boolean };
|
|
234
|
+
if (!id || !name) {
|
|
235
|
+
return { error: 'id and name are required', status: 400 };
|
|
236
|
+
}
|
|
237
|
+
const config = addClaudeCustomEndpoint(initialPath, { id, name, enabled: enabled !== false });
|
|
238
|
+
|
|
239
|
+
broadcastToClients({
|
|
240
|
+
type: 'CLI_ENDPOINT_UPDATED',
|
|
241
|
+
payload: { endpoint: { id, name, enabled }, timestamp: new Date().toISOString() }
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
return { success: true, endpoints: config.customEndpoints };
|
|
245
|
+
} catch (err) {
|
|
246
|
+
return { error: (err as Error).message, status: 500 };
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// API: Update custom endpoint enabled status
|
|
253
|
+
if (pathname.match(/^\/api\/cli\/endpoints\/[^/]+$/) && req.method === 'PUT') {
|
|
254
|
+
const endpointId = pathname.split('/').pop() || '';
|
|
255
|
+
handlePostRequest(req, res, async (body: unknown) => {
|
|
256
|
+
try {
|
|
257
|
+
const { enabled, name } = body as { enabled?: boolean; name?: string };
|
|
258
|
+
const config = loadClaudeCliTools(initialPath);
|
|
259
|
+
const endpoint = config.customEndpoints.find(e => e.id === endpointId);
|
|
260
|
+
|
|
261
|
+
if (!endpoint) {
|
|
262
|
+
return { error: 'Endpoint not found', status: 404 };
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (typeof enabled === 'boolean') endpoint.enabled = enabled;
|
|
266
|
+
if (name) endpoint.name = name;
|
|
267
|
+
|
|
268
|
+
saveClaudeCliTools(initialPath, config);
|
|
269
|
+
|
|
270
|
+
broadcastToClients({
|
|
271
|
+
type: 'CLI_ENDPOINT_UPDATED',
|
|
272
|
+
payload: { endpoint, timestamp: new Date().toISOString() }
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
return { success: true, endpoint };
|
|
276
|
+
} catch (err) {
|
|
277
|
+
return { error: (err as Error).message, status: 500 };
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// API: Delete custom endpoint
|
|
284
|
+
if (pathname.match(/^\/api\/cli\/endpoints\/[^/]+$/) && req.method === 'DELETE') {
|
|
285
|
+
const endpointId = pathname.split('/').pop() || '';
|
|
286
|
+
try {
|
|
287
|
+
const config = removeClaudeCustomEndpoint(initialPath, endpointId);
|
|
288
|
+
|
|
289
|
+
broadcastToClients({
|
|
290
|
+
type: 'CLI_ENDPOINT_DELETED',
|
|
291
|
+
payload: { endpointId, timestamp: new Date().toISOString() }
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
295
|
+
res.end(JSON.stringify({ success: true, endpoints: config.customEndpoints }));
|
|
296
|
+
} catch (err) {
|
|
297
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
298
|
+
res.end(JSON.stringify({ error: (err as Error).message }));
|
|
299
|
+
}
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
|
|
207
303
|
// API: CLI Execution History
|
|
208
304
|
if (pathname === '/api/cli/history') {
|
|
209
305
|
const projectPath = url.searchParams.get('path') || initialPath;
|
|
@@ -558,5 +654,101 @@ export async function handleCliRoutes(ctx: RouteContext): Promise<boolean> {
|
|
|
558
654
|
return true;
|
|
559
655
|
}
|
|
560
656
|
|
|
657
|
+
// API: Get CLI Tools Config from .claude/cli-tools.json (with fallback to global)
|
|
658
|
+
if (pathname === '/api/cli/tools-config' && req.method === 'GET') {
|
|
659
|
+
try {
|
|
660
|
+
const config = loadClaudeCliTools(initialPath);
|
|
661
|
+
const info = getClaudeCliToolsInfo(initialPath);
|
|
662
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
663
|
+
res.end(JSON.stringify({
|
|
664
|
+
...config,
|
|
665
|
+
_configInfo: info
|
|
666
|
+
}));
|
|
667
|
+
} catch (err) {
|
|
668
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
669
|
+
res.end(JSON.stringify({ error: (err as Error).message }));
|
|
670
|
+
}
|
|
671
|
+
return true;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// API: Update CLI Tools Config
|
|
675
|
+
if (pathname === '/api/cli/tools-config' && req.method === 'PUT') {
|
|
676
|
+
handlePostRequest(req, res, async (body: unknown) => {
|
|
677
|
+
try {
|
|
678
|
+
const updates = body as Partial<any>;
|
|
679
|
+
const config = loadClaudeCliTools(initialPath);
|
|
680
|
+
|
|
681
|
+
// Merge updates
|
|
682
|
+
const updatedConfig = {
|
|
683
|
+
...config,
|
|
684
|
+
...updates,
|
|
685
|
+
tools: { ...config.tools, ...(updates.tools || {}) },
|
|
686
|
+
settings: {
|
|
687
|
+
...config.settings,
|
|
688
|
+
...(updates.settings || {}),
|
|
689
|
+
cache: {
|
|
690
|
+
...config.settings.cache,
|
|
691
|
+
...(updates.settings?.cache || {})
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
};
|
|
695
|
+
|
|
696
|
+
saveClaudeCliTools(initialPath, updatedConfig);
|
|
697
|
+
|
|
698
|
+
broadcastToClients({
|
|
699
|
+
type: 'CLI_TOOLS_CONFIG_UPDATED',
|
|
700
|
+
payload: { config: updatedConfig, timestamp: new Date().toISOString() }
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
return { success: true, config: updatedConfig };
|
|
704
|
+
} catch (err) {
|
|
705
|
+
return { error: (err as Error).message, status: 500 };
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
return true;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// API: Update specific tool enabled status
|
|
712
|
+
const toolsConfigMatch = pathname.match(/^\/api\/cli\/tools-config\/([a-zA-Z0-9_-]+)$/);
|
|
713
|
+
if (toolsConfigMatch && req.method === 'PUT') {
|
|
714
|
+
const toolName = toolsConfigMatch[1];
|
|
715
|
+
handlePostRequest(req, res, async (body: unknown) => {
|
|
716
|
+
try {
|
|
717
|
+
const { enabled } = body as { enabled: boolean };
|
|
718
|
+
const config = updateClaudeToolEnabled(initialPath, toolName, enabled);
|
|
719
|
+
|
|
720
|
+
broadcastToClients({
|
|
721
|
+
type: 'CLI_TOOL_TOGGLED',
|
|
722
|
+
payload: { tool: toolName, enabled, timestamp: new Date().toISOString() }
|
|
723
|
+
});
|
|
724
|
+
|
|
725
|
+
return { success: true, config };
|
|
726
|
+
} catch (err) {
|
|
727
|
+
return { error: (err as Error).message, status: 500 };
|
|
728
|
+
}
|
|
729
|
+
});
|
|
730
|
+
return true;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
// API: Update cache settings
|
|
734
|
+
if (pathname === '/api/cli/tools-config/cache' && req.method === 'PUT') {
|
|
735
|
+
handlePostRequest(req, res, async (body: unknown) => {
|
|
736
|
+
try {
|
|
737
|
+
const cacheSettings = body as { injectionMode?: string; defaultPrefix?: string; defaultSuffix?: string };
|
|
738
|
+
const config = updateClaudeCacheSettings(initialPath, cacheSettings as any);
|
|
739
|
+
|
|
740
|
+
broadcastToClients({
|
|
741
|
+
type: 'CLI_CACHE_SETTINGS_UPDATED',
|
|
742
|
+
payload: { cache: config.settings.cache, timestamp: new Date().toISOString() }
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
return { success: true, config };
|
|
746
|
+
} catch (err) {
|
|
747
|
+
return { error: (err as Error).message, status: 500 };
|
|
748
|
+
}
|
|
749
|
+
});
|
|
750
|
+
return true;
|
|
751
|
+
}
|
|
752
|
+
|
|
561
753
|
return false;
|
|
562
754
|
}
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
bootstrapVenv,
|
|
10
10
|
executeCodexLens,
|
|
11
11
|
checkSemanticStatus,
|
|
12
|
+
ensureLiteLLMEmbedderReady,
|
|
12
13
|
installSemantic,
|
|
13
14
|
detectGpuSupport,
|
|
14
15
|
uninstallCodexLens,
|
|
@@ -80,10 +81,22 @@ export async function handleCodexLensRoutes(ctx: RouteContext): Promise<boolean>
|
|
|
80
81
|
// API: CodexLens Index List - Get all indexed projects with details
|
|
81
82
|
if (pathname === '/api/codexlens/indexes') {
|
|
82
83
|
try {
|
|
83
|
-
//
|
|
84
|
-
const
|
|
84
|
+
// Check if CodexLens is installed first (without auto-installing)
|
|
85
|
+
const venvStatus = await checkVenvStatus();
|
|
86
|
+
if (!venvStatus.ready) {
|
|
87
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
88
|
+
res.end(JSON.stringify({ success: true, indexes: [], totalSize: 0, totalSizeFormatted: '0 B' }));
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Execute all CLI commands in parallel
|
|
93
|
+
const [configResult, projectsResult, statusResult] = await Promise.all([
|
|
94
|
+
executeCodexLens(['config', '--json']),
|
|
95
|
+
executeCodexLens(['projects', 'list', '--json']),
|
|
96
|
+
executeCodexLens(['status', '--json'])
|
|
97
|
+
]);
|
|
98
|
+
|
|
85
99
|
let indexDir = '';
|
|
86
|
-
|
|
87
100
|
if (configResult.success) {
|
|
88
101
|
try {
|
|
89
102
|
const config = extractJSON(configResult.output);
|
|
@@ -96,8 +109,6 @@ export async function handleCodexLensRoutes(ctx: RouteContext): Promise<boolean>
|
|
|
96
109
|
}
|
|
97
110
|
}
|
|
98
111
|
|
|
99
|
-
// Get project list using 'projects list' command
|
|
100
|
-
const projectsResult = await executeCodexLens(['projects', 'list', '--json']);
|
|
101
112
|
let indexes: any[] = [];
|
|
102
113
|
let totalSize = 0;
|
|
103
114
|
let vectorIndexCount = 0;
|
|
@@ -107,7 +118,8 @@ export async function handleCodexLensRoutes(ctx: RouteContext): Promise<boolean>
|
|
|
107
118
|
try {
|
|
108
119
|
const projectsData = extractJSON(projectsResult.output);
|
|
109
120
|
if (projectsData.success && Array.isArray(projectsData.result)) {
|
|
110
|
-
const {
|
|
121
|
+
const { stat, readdir } = await import('fs/promises');
|
|
122
|
+
const { existsSync } = await import('fs');
|
|
111
123
|
const { basename, join } = await import('path');
|
|
112
124
|
|
|
113
125
|
for (const project of projectsData.result) {
|
|
@@ -128,15 +140,14 @@ export async function handleCodexLensRoutes(ctx: RouteContext): Promise<boolean>
|
|
|
128
140
|
// Try to get actual index size from index_root
|
|
129
141
|
if (project.index_root && existsSync(project.index_root)) {
|
|
130
142
|
try {
|
|
131
|
-
const
|
|
132
|
-
const files = readdirSync(project.index_root);
|
|
143
|
+
const files = await readdir(project.index_root);
|
|
133
144
|
for (const file of files) {
|
|
134
145
|
try {
|
|
135
146
|
const filePath = join(project.index_root, file);
|
|
136
|
-
const
|
|
137
|
-
projectSize +=
|
|
138
|
-
if (!lastModified ||
|
|
139
|
-
lastModified =
|
|
147
|
+
const fileStat = await stat(filePath);
|
|
148
|
+
projectSize += fileStat.size;
|
|
149
|
+
if (!lastModified || fileStat.mtime > lastModified) {
|
|
150
|
+
lastModified = fileStat.mtime;
|
|
140
151
|
}
|
|
141
152
|
// Check for vector/embedding files
|
|
142
153
|
if (file.includes('vector') || file.includes('embedding') ||
|
|
@@ -186,8 +197,7 @@ export async function handleCodexLensRoutes(ctx: RouteContext): Promise<boolean>
|
|
|
186
197
|
}
|
|
187
198
|
}
|
|
188
199
|
|
|
189
|
-
//
|
|
190
|
-
const statusResult = await executeCodexLens(['status', '--json']);
|
|
200
|
+
// Parse summary stats from status command (already fetched in parallel)
|
|
191
201
|
let statusSummary: any = {};
|
|
192
202
|
|
|
193
203
|
if (statusResult.success) {
|
|
@@ -242,6 +252,71 @@ export async function handleCodexLensRoutes(ctx: RouteContext): Promise<boolean>
|
|
|
242
252
|
return true;
|
|
243
253
|
}
|
|
244
254
|
|
|
255
|
+
// API: CodexLens Dashboard Init - Aggregated endpoint for page initialization
|
|
256
|
+
if (pathname === '/api/codexlens/dashboard-init') {
|
|
257
|
+
try {
|
|
258
|
+
const venvStatus = await checkVenvStatus();
|
|
259
|
+
|
|
260
|
+
if (!venvStatus.ready) {
|
|
261
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
262
|
+
res.end(JSON.stringify({
|
|
263
|
+
installed: false,
|
|
264
|
+
status: venvStatus,
|
|
265
|
+
config: { index_dir: '~/.codexlens/indexes', index_count: 0 },
|
|
266
|
+
semantic: { available: false }
|
|
267
|
+
}));
|
|
268
|
+
return true;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Parallel fetch all initialization data
|
|
272
|
+
const [configResult, statusResult, semanticStatus] = await Promise.all([
|
|
273
|
+
executeCodexLens(['config', '--json']),
|
|
274
|
+
executeCodexLens(['status', '--json']),
|
|
275
|
+
checkSemanticStatus()
|
|
276
|
+
]);
|
|
277
|
+
|
|
278
|
+
// Parse config
|
|
279
|
+
let config = { index_dir: '~/.codexlens/indexes', index_count: 0 };
|
|
280
|
+
if (configResult.success) {
|
|
281
|
+
try {
|
|
282
|
+
const configData = extractJSON(configResult.output);
|
|
283
|
+
if (configData.success && configData.result) {
|
|
284
|
+
config.index_dir = configData.result.index_dir || configData.result.index_root || config.index_dir;
|
|
285
|
+
}
|
|
286
|
+
} catch (e) {
|
|
287
|
+
console.error('[CodexLens] Failed to parse config for dashboard init:', e.message);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Parse status
|
|
292
|
+
let statusData: any = {};
|
|
293
|
+
if (statusResult.success) {
|
|
294
|
+
try {
|
|
295
|
+
const status = extractJSON(statusResult.output);
|
|
296
|
+
if (status.success && status.result) {
|
|
297
|
+
config.index_count = status.result.projects_count || 0;
|
|
298
|
+
statusData = status.result;
|
|
299
|
+
}
|
|
300
|
+
} catch (e) {
|
|
301
|
+
console.error('[CodexLens] Failed to parse status for dashboard init:', e.message);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
306
|
+
res.end(JSON.stringify({
|
|
307
|
+
installed: true,
|
|
308
|
+
status: venvStatus,
|
|
309
|
+
config,
|
|
310
|
+
semantic: semanticStatus,
|
|
311
|
+
statusData
|
|
312
|
+
}));
|
|
313
|
+
} catch (err) {
|
|
314
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
315
|
+
res.end(JSON.stringify({ success: false, error: err.message }));
|
|
316
|
+
}
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
319
|
+
|
|
245
320
|
// API: CodexLens Bootstrap (Install)
|
|
246
321
|
if (pathname === '/api/codexlens/bootstrap' && req.method === 'POST') {
|
|
247
322
|
handlePostRequest(req, res, async () => {
|
|
@@ -290,14 +365,24 @@ export async function handleCodexLensRoutes(ctx: RouteContext): Promise<boolean>
|
|
|
290
365
|
// API: CodexLens Config - GET (Get current configuration with index count)
|
|
291
366
|
if (pathname === '/api/codexlens/config' && req.method === 'GET') {
|
|
292
367
|
try {
|
|
368
|
+
// Check if CodexLens is installed first (without auto-installing)
|
|
369
|
+
const venvStatus = await checkVenvStatus();
|
|
370
|
+
|
|
371
|
+
let responseData = { index_dir: '~/.codexlens/indexes', index_count: 0 };
|
|
372
|
+
|
|
373
|
+
// If not installed, return default config without executing CodexLens
|
|
374
|
+
if (!venvStatus.ready) {
|
|
375
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
376
|
+
res.end(JSON.stringify(responseData));
|
|
377
|
+
return true;
|
|
378
|
+
}
|
|
379
|
+
|
|
293
380
|
// Fetch both config and status to merge index_count
|
|
294
381
|
const [configResult, statusResult] = await Promise.all([
|
|
295
382
|
executeCodexLens(['config', '--json']),
|
|
296
383
|
executeCodexLens(['status', '--json'])
|
|
297
384
|
]);
|
|
298
385
|
|
|
299
|
-
let responseData = { index_dir: '~/.codexlens/indexes', index_count: 0 };
|
|
300
|
-
|
|
301
386
|
// Parse config (extract JSON from output that may contain log messages)
|
|
302
387
|
if (configResult.success) {
|
|
303
388
|
try {
|
|
@@ -388,9 +473,17 @@ export async function handleCodexLensRoutes(ctx: RouteContext): Promise<boolean>
|
|
|
388
473
|
// API: CodexLens Init (Initialize workspace index)
|
|
389
474
|
if (pathname === '/api/codexlens/init' && req.method === 'POST') {
|
|
390
475
|
handlePostRequest(req, res, async (body) => {
|
|
391
|
-
const { path: projectPath, indexType = 'vector', embeddingModel = 'code' } = body;
|
|
476
|
+
const { path: projectPath, indexType = 'vector', embeddingModel = 'code', embeddingBackend = 'fastembed', maxWorkers = 1 } = body;
|
|
392
477
|
const targetPath = projectPath || initialPath;
|
|
393
478
|
|
|
479
|
+
// Ensure LiteLLM backend dependencies are installed before running the CLI
|
|
480
|
+
if (indexType !== 'normal' && embeddingBackend === 'litellm') {
|
|
481
|
+
const installResult = await ensureLiteLLMEmbedderReady();
|
|
482
|
+
if (!installResult.success) {
|
|
483
|
+
return { success: false, error: installResult.error || 'Failed to prepare LiteLLM embedder', status: 500 };
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
394
487
|
// Build CLI arguments based on index type
|
|
395
488
|
const args = ['init', targetPath, '--json'];
|
|
396
489
|
if (indexType === 'normal') {
|
|
@@ -398,6 +491,14 @@ export async function handleCodexLensRoutes(ctx: RouteContext): Promise<boolean>
|
|
|
398
491
|
} else {
|
|
399
492
|
// Add embedding model selection for vector index
|
|
400
493
|
args.push('--embedding-model', embeddingModel);
|
|
494
|
+
// Add embedding backend if not using default fastembed
|
|
495
|
+
if (embeddingBackend && embeddingBackend !== 'fastembed') {
|
|
496
|
+
args.push('--embedding-backend', embeddingBackend);
|
|
497
|
+
}
|
|
498
|
+
// Add max workers for concurrent API calls (useful for litellm backend)
|
|
499
|
+
if (maxWorkers && maxWorkers > 1) {
|
|
500
|
+
args.push('--max-workers', String(maxWorkers));
|
|
501
|
+
}
|
|
401
502
|
}
|
|
402
503
|
|
|
403
504
|
// Broadcast start event
|
|
@@ -552,6 +653,8 @@ export async function handleCodexLensRoutes(ctx: RouteContext): Promise<boolean>
|
|
|
552
653
|
const query = url.searchParams.get('query') || '';
|
|
553
654
|
const limit = parseInt(url.searchParams.get('limit') || '20', 10);
|
|
554
655
|
const mode = url.searchParams.get('mode') || 'exact'; // exact, fuzzy, hybrid, vector
|
|
656
|
+
const maxContentLength = parseInt(url.searchParams.get('max_content_length') || '200', 10);
|
|
657
|
+
const extraFilesCount = parseInt(url.searchParams.get('extra_files_count') || '10', 10);
|
|
555
658
|
const projectPath = url.searchParams.get('path') || initialPath;
|
|
556
659
|
|
|
557
660
|
if (!query) {
|
|
@@ -561,15 +664,46 @@ export async function handleCodexLensRoutes(ctx: RouteContext): Promise<boolean>
|
|
|
561
664
|
}
|
|
562
665
|
|
|
563
666
|
try {
|
|
564
|
-
|
|
667
|
+
// Request more results to support split (full content + extra files)
|
|
668
|
+
const totalToFetch = limit + extraFilesCount;
|
|
669
|
+
const args = ['search', query, '--path', projectPath, '--limit', totalToFetch.toString(), '--mode', mode, '--json'];
|
|
565
670
|
|
|
566
671
|
const result = await executeCodexLens(args, { cwd: projectPath });
|
|
567
672
|
|
|
568
673
|
if (result.success) {
|
|
569
674
|
try {
|
|
570
675
|
const parsed = extractJSON(result.output);
|
|
676
|
+
const allResults = parsed.result?.results || [];
|
|
677
|
+
|
|
678
|
+
// Truncate content and split results
|
|
679
|
+
const truncateContent = (content: string | null | undefined): string => {
|
|
680
|
+
if (!content) return '';
|
|
681
|
+
if (content.length <= maxContentLength) return content;
|
|
682
|
+
return content.slice(0, maxContentLength) + '...';
|
|
683
|
+
};
|
|
684
|
+
|
|
685
|
+
// Split results: first N with full content, rest as file paths only
|
|
686
|
+
const resultsWithContent = allResults.slice(0, limit).map((r: any) => ({
|
|
687
|
+
...r,
|
|
688
|
+
content: truncateContent(r.content || r.excerpt),
|
|
689
|
+
excerpt: truncateContent(r.excerpt || r.content),
|
|
690
|
+
}));
|
|
691
|
+
|
|
692
|
+
const extraResults = allResults.slice(limit, limit + extraFilesCount);
|
|
693
|
+
const extraFiles = [...new Set(extraResults.map((r: any) => r.path || r.file))];
|
|
694
|
+
|
|
571
695
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
572
|
-
res.end(JSON.stringify({
|
|
696
|
+
res.end(JSON.stringify({
|
|
697
|
+
success: true,
|
|
698
|
+
results: resultsWithContent,
|
|
699
|
+
extra_files: extraFiles.length > 0 ? extraFiles : undefined,
|
|
700
|
+
metadata: {
|
|
701
|
+
total: allResults.length,
|
|
702
|
+
limit,
|
|
703
|
+
max_content_length: maxContentLength,
|
|
704
|
+
extra_files_count: extraFilesCount,
|
|
705
|
+
},
|
|
706
|
+
}));
|
|
573
707
|
} catch {
|
|
574
708
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
575
709
|
res.end(JSON.stringify({ success: true, results: [], output: result.output }));
|
|
@@ -682,6 +816,87 @@ export async function handleCodexLensRoutes(ctx: RouteContext): Promise<boolean>
|
|
|
682
816
|
return true;
|
|
683
817
|
}
|
|
684
818
|
|
|
819
|
+
// API: List available GPU devices for selection
|
|
820
|
+
if (pathname === '/api/codexlens/gpu/list' && req.method === 'GET') {
|
|
821
|
+
try {
|
|
822
|
+
// Check if CodexLens is installed first (without auto-installing)
|
|
823
|
+
const venvStatus = await checkVenvStatus();
|
|
824
|
+
if (!venvStatus.ready) {
|
|
825
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
826
|
+
res.end(JSON.stringify({ success: true, devices: [], selected_device_id: null }));
|
|
827
|
+
return true;
|
|
828
|
+
}
|
|
829
|
+
const result = await executeCodexLens(['gpu-list', '--json']);
|
|
830
|
+
if (result.success) {
|
|
831
|
+
try {
|
|
832
|
+
const parsed = extractJSON(result.output);
|
|
833
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
834
|
+
res.end(JSON.stringify(parsed));
|
|
835
|
+
} catch {
|
|
836
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
837
|
+
res.end(JSON.stringify({ success: true, devices: [], output: result.output }));
|
|
838
|
+
}
|
|
839
|
+
} else {
|
|
840
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
841
|
+
res.end(JSON.stringify({ success: false, error: result.error }));
|
|
842
|
+
}
|
|
843
|
+
} catch (err) {
|
|
844
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
845
|
+
res.end(JSON.stringify({ success: false, error: err.message }));
|
|
846
|
+
}
|
|
847
|
+
return true;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// API: Select GPU device for embedding
|
|
851
|
+
if (pathname === '/api/codexlens/gpu/select' && req.method === 'POST') {
|
|
852
|
+
handlePostRequest(req, res, async (body) => {
|
|
853
|
+
const { device_id } = body;
|
|
854
|
+
|
|
855
|
+
if (device_id === undefined || device_id === null) {
|
|
856
|
+
return { success: false, error: 'device_id is required', status: 400 };
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
try {
|
|
860
|
+
const result = await executeCodexLens(['gpu-select', String(device_id), '--json']);
|
|
861
|
+
if (result.success) {
|
|
862
|
+
try {
|
|
863
|
+
const parsed = extractJSON(result.output);
|
|
864
|
+
return parsed;
|
|
865
|
+
} catch {
|
|
866
|
+
return { success: true, message: 'GPU selected', output: result.output };
|
|
867
|
+
}
|
|
868
|
+
} else {
|
|
869
|
+
return { success: false, error: result.error, status: 500 };
|
|
870
|
+
}
|
|
871
|
+
} catch (err) {
|
|
872
|
+
return { success: false, error: err.message, status: 500 };
|
|
873
|
+
}
|
|
874
|
+
});
|
|
875
|
+
return true;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
// API: Reset GPU selection to auto-detection
|
|
879
|
+
if (pathname === '/api/codexlens/gpu/reset' && req.method === 'POST') {
|
|
880
|
+
handlePostRequest(req, res, async () => {
|
|
881
|
+
try {
|
|
882
|
+
const result = await executeCodexLens(['gpu-reset', '--json']);
|
|
883
|
+
if (result.success) {
|
|
884
|
+
try {
|
|
885
|
+
const parsed = extractJSON(result.output);
|
|
886
|
+
return parsed;
|
|
887
|
+
} catch {
|
|
888
|
+
return { success: true, message: 'GPU selection reset', output: result.output };
|
|
889
|
+
}
|
|
890
|
+
} else {
|
|
891
|
+
return { success: false, error: result.error, status: 500 };
|
|
892
|
+
}
|
|
893
|
+
} catch (err) {
|
|
894
|
+
return { success: false, error: err.message, status: 500 };
|
|
895
|
+
}
|
|
896
|
+
});
|
|
897
|
+
return true;
|
|
898
|
+
}
|
|
899
|
+
|
|
685
900
|
// API: CodexLens Semantic Search Install (with GPU mode support)
|
|
686
901
|
if (pathname === '/api/codexlens/semantic/install' && req.method === 'POST') {
|
|
687
902
|
handlePostRequest(req, res, async (body) => {
|
|
@@ -721,6 +936,13 @@ export async function handleCodexLensRoutes(ctx: RouteContext): Promise<boolean>
|
|
|
721
936
|
// API: CodexLens Model List (list available embedding models)
|
|
722
937
|
if (pathname === '/api/codexlens/models' && req.method === 'GET') {
|
|
723
938
|
try {
|
|
939
|
+
// Check if CodexLens is installed first (without auto-installing)
|
|
940
|
+
const venvStatus = await checkVenvStatus();
|
|
941
|
+
if (!venvStatus.ready) {
|
|
942
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
943
|
+
res.end(JSON.stringify({ success: false, error: 'CodexLens not installed' }));
|
|
944
|
+
return true;
|
|
945
|
+
}
|
|
724
946
|
const result = await executeCodexLens(['model-list', '--json']);
|
|
725
947
|
if (result.success) {
|
|
726
948
|
try {
|