claude-code-workflow 6.3.19 → 6.3.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/.claude/agents/issue-plan-agent.md +31 -2
  2. package/.claude/commands/issue/new.md +92 -2
  3. package/.claude/commands/issue/plan.md +3 -2
  4. package/.codex/prompts/issue-execute.md +5 -0
  5. package/ccw/dist/core/routes/litellm-api-routes.d.ts.map +1 -1
  6. package/ccw/dist/core/routes/litellm-api-routes.js +8 -0
  7. package/ccw/dist/core/routes/litellm-api-routes.js.map +1 -1
  8. package/ccw/dist/core/server.d.ts.map +1 -1
  9. package/ccw/dist/core/server.js +5 -0
  10. package/ccw/dist/core/server.js.map +1 -1
  11. package/ccw/dist/core/services/api-key-tester.d.ts +11 -0
  12. package/ccw/dist/core/services/api-key-tester.d.ts.map +1 -1
  13. package/ccw/dist/core/services/api-key-tester.js +30 -10
  14. package/ccw/dist/core/services/api-key-tester.js.map +1 -1
  15. package/ccw/dist/core/services/health-check-service.d.ts +6 -0
  16. package/ccw/dist/core/services/health-check-service.d.ts.map +1 -1
  17. package/ccw/dist/core/services/health-check-service.js +22 -0
  18. package/ccw/dist/core/services/health-check-service.js.map +1 -1
  19. package/ccw/src/core/routes/litellm-api-routes.ts +8 -0
  20. package/ccw/src/core/server.ts +6 -0
  21. package/ccw/src/core/services/api-key-tester.ts +33 -10
  22. package/ccw/src/core/services/health-check-service.ts +26 -0
  23. package/ccw/src/templates/dashboard-js/api.js +1 -1
  24. package/ccw/src/templates/dashboard-js/components/cli-status.js +7 -7
  25. package/ccw/src/templates/dashboard-js/components/hook-manager.js +2 -2
  26. package/ccw/src/templates/dashboard-js/components/index-manager.js +2 -2
  27. package/ccw/src/templates/dashboard-js/components/mcp-manager.js +16 -16
  28. package/ccw/src/templates/dashboard-js/components/storage-manager.js +2 -2
  29. package/ccw/src/templates/dashboard-js/components/task-queue-sidebar.js +1 -1
  30. package/ccw/src/templates/dashboard-js/i18n.js +10 -0
  31. package/ccw/src/templates/dashboard-js/views/cli-manager.js +1 -1
  32. package/ccw/src/templates/dashboard-js/views/codexlens-manager.js +12 -2
  33. package/ccw/src/templates/dashboard-js/views/memory.js +1 -1
  34. package/ccw/src/templates/dashboard-js/views/prompt-history.js +1 -1
  35. package/codex-lens/src/codexlens/__pycache__/config.cpython-312.pyc +0 -0
  36. package/codex-lens/src/codexlens/__pycache__/config.cpython-313.pyc +0 -0
  37. package/codex-lens/src/codexlens/__pycache__/env_config.cpython-312.pyc +0 -0
  38. package/codex-lens/src/codexlens/__pycache__/env_config.cpython-313.pyc +0 -0
  39. package/codex-lens/src/codexlens/cli/__pycache__/embedding_manager.cpython-312.pyc +0 -0
  40. package/codex-lens/src/codexlens/cli/__pycache__/embedding_manager.cpython-313.pyc +0 -0
  41. package/codex-lens/src/codexlens/cli/embedding_manager.py +13 -4
  42. package/codex-lens/src/codexlens/config.py +35 -0
  43. package/codex-lens/src/codexlens/env_config.py +6 -0
  44. package/codex-lens/src/codexlens/search/__pycache__/chain_search.cpython-312.pyc +0 -0
  45. package/codex-lens/src/codexlens/search/__pycache__/chain_search.cpython-313.pyc +0 -0
  46. package/codex-lens/src/codexlens/search/__pycache__/ranking.cpython-312.pyc +0 -0
  47. package/codex-lens/src/codexlens/search/__pycache__/ranking.cpython-313.pyc +0 -0
  48. package/codex-lens/src/codexlens/search/chain_search.py +10 -0
  49. package/codex-lens/src/codexlens/search/ranking.py +50 -0
  50. package/codex-lens/src/codexlens/semantic/__pycache__/chunker.cpython-313.pyc +0 -0
  51. package/codex-lens/src/codexlens/semantic/chunker.py +328 -23
  52. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/__init__.cpython-312.pyc +0 -0
  53. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/api_reranker.cpython-312.pyc +0 -0
  54. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/base.cpython-312.pyc +0 -0
  55. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/factory.cpython-312.pyc +0 -0
  56. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/fastembed_reranker.cpython-312.pyc +0 -0
  57. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/legacy.cpython-312.pyc +0 -0
  58. package/codex-lens/src/codexlens/semantic/reranker/__pycache__/onnx_reranker.cpython-312.pyc +0 -0
  59. package/codex-lens/src/codexlens/storage/__pycache__/index_tree.cpython-312.pyc +0 -0
  60. package/codex-lens/src/codexlens/storage/__pycache__/index_tree.cpython-313.pyc +0 -0
  61. package/codex-lens/src/codexlens/storage/index_tree.py +46 -2
  62. package/package.json +1 -1
@@ -3,6 +3,26 @@
3
3
  * Shared module for testing API key connectivity across different provider types.
4
4
  * Used by both manual testing (litellm-api-routes.ts) and health check service.
5
5
  */
6
+ /**
7
+ * Validate API base URL format
8
+ * Note: This is a local development tool, so we allow localhost and internal networks
9
+ * for users who run local API gateways or proxies.
10
+ * @param url - The URL to validate
11
+ * @returns Object with valid flag and optional error message
12
+ */
13
+ export function validateApiBaseUrl(url) {
14
+ try {
15
+ const parsed = new URL(url);
16
+ // Must be HTTP or HTTPS
17
+ if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
18
+ return { valid: false, error: 'URL must use HTTP or HTTPS protocol' };
19
+ }
20
+ return { valid: true };
21
+ }
22
+ catch {
23
+ return { valid: false, error: 'Invalid URL format' };
24
+ }
25
+ }
6
26
  /**
7
27
  * Get default API base URL for a provider type
8
28
  */
@@ -23,24 +43,24 @@ export function getDefaultApiBase(providerType) {
23
43
  * @returns TestResult indicating if the key is valid
24
44
  */
25
45
  export async function testApiKeyConnection(providerType, apiBase, apiKey, timeout = 10000) {
46
+ // Validate URL to prevent SSRF
47
+ const urlValidation = validateApiBaseUrl(apiBase);
48
+ if (!urlValidation.valid) {
49
+ return { valid: false, error: urlValidation.error };
50
+ }
26
51
  const controller = new AbortController();
27
52
  const timeoutId = setTimeout(() => controller.abort(), timeout);
28
53
  const startTime = Date.now();
29
54
  try {
30
55
  if (providerType === 'anthropic') {
31
- // Anthropic format: POST /v1/messages with minimal payload
32
- const response = await fetch(`${apiBase}/messages`, {
33
- method: 'POST',
56
+ // Anthropic format: Use /v1/models endpoint (no cost, no model dependency)
57
+ // This validates the API key without making a billable request
58
+ const response = await fetch(`${apiBase}/models`, {
59
+ method: 'GET',
34
60
  headers: {
35
- 'Content-Type': 'application/json',
36
61
  'x-api-key': apiKey,
37
62
  'anthropic-version': '2023-06-01',
38
63
  },
39
- body: JSON.stringify({
40
- model: 'claude-3-haiku-20240307',
41
- max_tokens: 1,
42
- messages: [{ role: 'user', content: 'Hi' }],
43
- }),
44
64
  signal: controller.signal,
45
65
  });
46
66
  clearTimeout(timeoutId);
@@ -51,7 +71,7 @@ export async function testApiKeyConnection(providerType, apiBase, apiKey, timeou
51
71
  // Parse error response
52
72
  const errorBody = await response.json().catch(() => ({}));
53
73
  const errorMessage = errorBody?.error?.message || response.statusText;
54
- // 401 = invalid API key, other 4xx might be valid key with other issues
74
+ // 401 = invalid API key
55
75
  if (response.status === 401) {
56
76
  return { valid: false, error: 'Invalid API key' };
57
77
  }
@@ -1 +1 @@
1
- {"version":3,"file":"api-key-tester.js","sourceRoot":"","sources":["../../../src/core/services/api-key-tester.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api-key-tester.js","sourceRoot":"","sources":["../../../src/core/services/api-key-tester.ts"],"names":[],"mappings":"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"}
@@ -74,6 +74,12 @@ export declare class HealthCheckService {
74
74
  * Get list of provider IDs currently being monitored
75
75
  */
76
76
  getMonitoredProviders(): string[];
77
+ /**
78
+ * Clean up all state for a deleted provider
79
+ * Call this when a provider is deleted to prevent memory leaks
80
+ * @param providerId - The provider ID to clean up
81
+ */
82
+ cleanupProvider(providerId: string): void;
77
83
  }
78
84
  /**
79
85
  * Get the singleton health check service instance
@@ -1 +1 @@
1
- {"version":3,"file":"health-check-service.d.ts","sourceRoot":"","sources":["../../../src/core/services/health-check-service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAmBH;;;GAGG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAqB;IAE5C,8DAA8D;IAC9D,OAAO,CAAC,MAAM,CAA0C;IAExD,kFAAkF;IAClF,OAAO,CAAC,SAAS,CAA0C;IAE3D,2CAA2C;IAC3C,OAAO,CAAC,OAAO,CAAc;IAE7B,yDAAyD;IACzD,OAAO,CAAC,iBAAiB,CAA0B;IAEnD,OAAO;IAEP;;OAEG;IACH,MAAM,CAAC,WAAW,IAAI,kBAAkB;IAOxC;;;OAGG;IACH,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAoC1C;;;OAGG;IACH,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IASzC;;;OAGG;IACH,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAoB3C;;OAEG;IACH,mBAAmB,IAAI,IAAI;IAS3B;;;OAGG;IACG,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqDzD;;OAEG;YACW,cAAc;IAyD5B;;OAEG;IACH,OAAO,CAAC,eAAe;IA0BvB;;OAEG;IACH,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,KAAK,CAAC;QACjD,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;QAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,UAAU,EAAE,OAAO,CAAC;KACrB,CAAC;IAmBF;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,qBAAqB,IAAI,MAAM,EAAE;CAGlC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,kBAAkB,CAE1D"}
1
+ {"version":3,"file":"health-check-service.d.ts","sourceRoot":"","sources":["../../../src/core/services/health-check-service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAmBH;;;GAGG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAqB;IAE5C,8DAA8D;IAC9D,OAAO,CAAC,MAAM,CAA0C;IAExD,kFAAkF;IAClF,OAAO,CAAC,SAAS,CAA0C;IAE3D,2CAA2C;IAC3C,OAAO,CAAC,OAAO,CAAc;IAE7B,yDAAyD;IACzD,OAAO,CAAC,iBAAiB,CAA0B;IAEnD,OAAO;IAEP;;OAEG;IACH,MAAM,CAAC,WAAW,IAAI,kBAAkB;IAOxC;;;OAGG;IACH,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAoC1C;;;OAGG;IACH,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IASzC;;;OAGG;IACH,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAoB3C;;OAEG;IACH,mBAAmB,IAAI,IAAI;IAS3B;;;OAGG;IACG,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqDzD;;OAEG;YACW,cAAc;IAyD5B;;OAEG;IACH,OAAO,CAAC,eAAe;IA0BvB;;OAEG;IACH,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,KAAK,CAAC;QACjD,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;QAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,UAAU,EAAE,OAAO,CAAC;KACrB,CAAC;IAmBF;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,qBAAqB,IAAI,MAAM,EAAE;IAIjC;;;;OAIG;IACH,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;CAoB1C;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,kBAAkB,CAE1D"}
@@ -261,6 +261,28 @@ export class HealthCheckService {
261
261
  getMonitoredProviders() {
262
262
  return Array.from(this.timers.keys());
263
263
  }
264
+ /**
265
+ * Clean up all state for a deleted provider
266
+ * Call this when a provider is deleted to prevent memory leaks
267
+ * @param providerId - The provider ID to clean up
268
+ */
269
+ cleanupProvider(providerId) {
270
+ // Stop health check timer
271
+ this.stopHealthCheck(providerId);
272
+ // Remove all key states for this provider
273
+ const keysToRemove = [];
274
+ for (const key of this.keyStates.keys()) {
275
+ if (key.startsWith(`${providerId}:`)) {
276
+ keysToRemove.push(key);
277
+ }
278
+ }
279
+ for (const key of keysToRemove) {
280
+ this.keyStates.delete(key);
281
+ }
282
+ if (keysToRemove.length > 0) {
283
+ console.log(`[HealthCheck] Cleaned up ${keysToRemove.length} key state(s) for deleted provider ${providerId}`);
284
+ }
285
+ }
264
286
  }
265
287
  /**
266
288
  * Get the singleton health check service instance
@@ -1 +1 @@
1
- {"version":3,"file":"health-check-service.js","sourceRoot":"","sources":["../../../src/core/services/health-check-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"health-check-service.js","sourceRoot":"","sources":["../../../src/core/services/health-check-service.ts"],"names":[],"mappings":"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"}
@@ -292,6 +292,14 @@ export async function handleLiteLLMApiRoutes(ctx: RouteContext): Promise<boolean
292
292
  return true;
293
293
  }
294
294
 
295
+ // Clean up health check service state for deleted provider
296
+ try {
297
+ const { getHealthCheckService } = await import('../services/health-check-service.js');
298
+ getHealthCheckService().cleanupProvider(providerId);
299
+ } catch (cleanupErr) {
300
+ console.warn('[Provider Delete] Failed to cleanup health check state:', cleanupErr);
301
+ }
302
+
295
303
  broadcastToClients({
296
304
  type: 'LITELLM_PROVIDER_DELETED',
297
305
  payload: { providerId, timestamp: new Date().toISOString() }
@@ -640,6 +640,12 @@ export async function startServer(options: ServerOptions = {}): Promise<http.Ser
640
640
  try {
641
641
  const healthCheckService = getHealthCheckService();
642
642
  healthCheckService.startAllHealthChecks(initialPath);
643
+
644
+ // Graceful shutdown: stop health checks when server closes
645
+ server.on('close', () => {
646
+ console.log('[Server] Shutting down health check service...');
647
+ healthCheckService.stopAllHealthChecks();
648
+ });
643
649
  } catch (err) {
644
650
  console.warn('[Server] Failed to start health check service:', err);
645
651
  }
@@ -6,6 +6,28 @@
6
6
 
7
7
  import type { ProviderType } from '../../types/litellm-api-config.js';
8
8
 
9
+ /**
10
+ * Validate API base URL format
11
+ * Note: This is a local development tool, so we allow localhost and internal networks
12
+ * for users who run local API gateways or proxies.
13
+ * @param url - The URL to validate
14
+ * @returns Object with valid flag and optional error message
15
+ */
16
+ export function validateApiBaseUrl(url: string): { valid: boolean; error?: string } {
17
+ try {
18
+ const parsed = new URL(url);
19
+
20
+ // Must be HTTP or HTTPS
21
+ if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
22
+ return { valid: false, error: 'URL must use HTTP or HTTPS protocol' };
23
+ }
24
+
25
+ return { valid: true };
26
+ } catch {
27
+ return { valid: false, error: 'Invalid URL format' };
28
+ }
29
+ }
30
+
9
31
  /**
10
32
  * Result of an API key connection test
11
33
  */
@@ -44,25 +66,26 @@ export async function testApiKeyConnection(
44
66
  apiKey: string,
45
67
  timeout: number = 10000
46
68
  ): Promise<TestResult> {
69
+ // Validate URL to prevent SSRF
70
+ const urlValidation = validateApiBaseUrl(apiBase);
71
+ if (!urlValidation.valid) {
72
+ return { valid: false, error: urlValidation.error };
73
+ }
74
+
47
75
  const controller = new AbortController();
48
76
  const timeoutId = setTimeout(() => controller.abort(), timeout);
49
77
  const startTime = Date.now();
50
78
 
51
79
  try {
52
80
  if (providerType === 'anthropic') {
53
- // Anthropic format: POST /v1/messages with minimal payload
54
- const response = await fetch(`${apiBase}/messages`, {
55
- method: 'POST',
81
+ // Anthropic format: Use /v1/models endpoint (no cost, no model dependency)
82
+ // This validates the API key without making a billable request
83
+ const response = await fetch(`${apiBase}/models`, {
84
+ method: 'GET',
56
85
  headers: {
57
- 'Content-Type': 'application/json',
58
86
  'x-api-key': apiKey,
59
87
  'anthropic-version': '2023-06-01',
60
88
  },
61
- body: JSON.stringify({
62
- model: 'claude-3-haiku-20240307',
63
- max_tokens: 1,
64
- messages: [{ role: 'user', content: 'Hi' }],
65
- }),
66
89
  signal: controller.signal,
67
90
  });
68
91
 
@@ -77,7 +100,7 @@ export async function testApiKeyConnection(
77
100
  const errorBody = await response.json().catch(() => ({}));
78
101
  const errorMessage = (errorBody as any)?.error?.message || response.statusText;
79
102
 
80
- // 401 = invalid API key, other 4xx might be valid key with other issues
103
+ // 401 = invalid API key
81
104
  if (response.status === 401) {
82
105
  return { valid: false, error: 'Invalid API key' };
83
106
  }
@@ -330,6 +330,32 @@ export class HealthCheckService {
330
330
  getMonitoredProviders(): string[] {
331
331
  return Array.from(this.timers.keys());
332
332
  }
333
+
334
+ /**
335
+ * Clean up all state for a deleted provider
336
+ * Call this when a provider is deleted to prevent memory leaks
337
+ * @param providerId - The provider ID to clean up
338
+ */
339
+ cleanupProvider(providerId: string): void {
340
+ // Stop health check timer
341
+ this.stopHealthCheck(providerId);
342
+
343
+ // Remove all key states for this provider
344
+ const keysToRemove: string[] = [];
345
+ for (const key of this.keyStates.keys()) {
346
+ if (key.startsWith(`${providerId}:`)) {
347
+ keysToRemove.push(key);
348
+ }
349
+ }
350
+
351
+ for (const key of keysToRemove) {
352
+ this.keyStates.delete(key);
353
+ }
354
+
355
+ if (keysToRemove.length > 0) {
356
+ console.log(`[HealthCheck] Cleaned up ${keysToRemove.length} key state(s) for deleted provider ${providerId}`);
357
+ }
358
+ }
333
359
  }
334
360
 
335
361
  /**
@@ -174,7 +174,7 @@ function refreshRecentPaths() {
174
174
  */
175
175
  async function removeRecentPathFromList(path) {
176
176
  try {
177
- const response = await fetch('/api/remove-recent-path', {
177
+ const response = await csrfFetch('/api/remove-recent-path', {
178
178
  method: 'POST',
179
179
  headers: { 'Content-Type': 'application/json' },
180
180
  body: JSON.stringify({ path })
@@ -350,7 +350,7 @@ async function loadCliToolsConfig() {
350
350
  */
351
351
  async function updateCliToolEnabled(tool, enabled) {
352
352
  try {
353
- const response = await fetch('/api/cli/tools-config/' + tool, {
353
+ const response = await csrfFetch('/api/cli/tools-config/' + tool, {
354
354
  method: 'PUT',
355
355
  headers: { 'Content-Type': 'application/json' },
356
356
  body: JSON.stringify({ enabled: enabled })
@@ -796,7 +796,7 @@ function setDefaultCliTool(tool) {
796
796
  // Save to config
797
797
  if (window.claudeCliToolsConfig) {
798
798
  window.claudeCliToolsConfig.defaultTool = tool;
799
- fetch('/api/cli/tools-config', {
799
+ csrfFetch('/api/cli/tools-config', {
800
800
  method: 'PUT',
801
801
  headers: { 'Content-Type': 'application/json' },
802
802
  body: JSON.stringify({ defaultTool: tool })
@@ -851,7 +851,7 @@ function getCacheInjectionMode() {
851
851
 
852
852
  async function setCacheInjectionMode(mode) {
853
853
  try {
854
- const response = await fetch('/api/cli/tools-config/cache', {
854
+ const response = await csrfFetch('/api/cli/tools-config/cache', {
855
855
  method: 'PUT',
856
856
  headers: { 'Content-Type': 'application/json' },
857
857
  body: JSON.stringify({ injectionMode: mode })
@@ -1021,7 +1021,7 @@ async function startCodexLensInstall() {
1021
1021
  }, 1500);
1022
1022
 
1023
1023
  try {
1024
- const response = await fetch('/api/codexlens/bootstrap', {
1024
+ const response = await csrfFetch('/api/codexlens/bootstrap', {
1025
1025
  method: 'POST',
1026
1026
  headers: { 'Content-Type': 'application/json' },
1027
1027
  body: JSON.stringify({})
@@ -1171,7 +1171,7 @@ async function startCodexLensUninstall() {
1171
1171
  }, 500);
1172
1172
 
1173
1173
  try {
1174
- const response = await fetch('/api/codexlens/uninstall', {
1174
+ const response = await csrfFetch('/api/codexlens/uninstall', {
1175
1175
  method: 'POST',
1176
1176
  headers: { 'Content-Type': 'application/json' },
1177
1177
  body: JSON.stringify({})
@@ -1257,7 +1257,7 @@ async function initCodexLensIndex() {
1257
1257
  console.log('[CodexLens] Initializing index for path:', targetPath);
1258
1258
 
1259
1259
  try {
1260
- const response = await fetch('/api/codexlens/init', {
1260
+ const response = await csrfFetch('/api/codexlens/init', {
1261
1261
  method: 'POST',
1262
1262
  headers: { 'Content-Type': 'application/json' },
1263
1263
  body: JSON.stringify({ path: targetPath })
@@ -1424,7 +1424,7 @@ async function startSemanticInstall() {
1424
1424
  }, 2000);
1425
1425
 
1426
1426
  try {
1427
- const response = await fetch('/api/codexlens/semantic/install', {
1427
+ const response = await csrfFetch('/api/codexlens/semantic/install', {
1428
1428
  method: 'POST',
1429
1429
  headers: { 'Content-Type': 'application/json' },
1430
1430
  body: JSON.stringify({})
@@ -449,7 +449,7 @@ async function saveHook(scope, event, hookData) {
449
449
  // Convert to Claude Code format before saving
450
450
  const convertedHookData = convertToClaudeCodeFormat(hookData);
451
451
 
452
- const response = await fetch('/api/hooks', {
452
+ const response = await csrfFetch('/api/hooks', {
453
453
  method: 'POST',
454
454
  headers: { 'Content-Type': 'application/json' },
455
455
  body: JSON.stringify({
@@ -478,7 +478,7 @@ async function saveHook(scope, event, hookData) {
478
478
 
479
479
  async function removeHook(scope, event, hookIndex) {
480
480
  try {
481
- const response = await fetch('/api/hooks', {
481
+ const response = await csrfFetch('/api/hooks', {
482
482
  method: 'DELETE',
483
483
  headers: { 'Content-Type': 'application/json' },
484
484
  body: JSON.stringify({
@@ -252,7 +252,7 @@ async function cleanIndexProject(projectId) {
252
252
 
253
253
  // The project ID is the directory name in the index folder
254
254
  // We need to construct the full path or use a clean API
255
- const response = await fetch('/api/codexlens/clean', {
255
+ const response = await csrfFetch('/api/codexlens/clean', {
256
256
  method: 'POST',
257
257
  headers: { 'Content-Type': 'application/json' },
258
258
  body: JSON.stringify({ projectId: projectId })
@@ -282,7 +282,7 @@ async function cleanAllIndexesConfirm() {
282
282
  try {
283
283
  showRefreshToast(t('index.cleaning') || 'Cleaning indexes...', 'info');
284
284
 
285
- const response = await fetch('/api/codexlens/clean', {
285
+ const response = await csrfFetch('/api/codexlens/clean', {
286
286
  method: 'POST',
287
287
  headers: { 'Content-Type': 'application/json' },
288
288
  body: JSON.stringify({ all: true })
@@ -91,7 +91,7 @@ function getCliMode() {
91
91
  */
92
92
  async function addCodexMcpServer(serverName, serverConfig) {
93
93
  try {
94
- const response = await fetch('/api/codex-mcp-add', {
94
+ const response = await csrfFetch('/api/codex-mcp-add', {
95
95
  method: 'POST',
96
96
  headers: { 'Content-Type': 'application/json' },
97
97
  body: JSON.stringify({
@@ -123,7 +123,7 @@ async function addCodexMcpServer(serverName, serverConfig) {
123
123
  */
124
124
  async function removeCodexMcpServer(serverName) {
125
125
  try {
126
- const response = await fetch('/api/codex-mcp-remove', {
126
+ const response = await csrfFetch('/api/codex-mcp-remove', {
127
127
  method: 'POST',
128
128
  headers: { 'Content-Type': 'application/json' },
129
129
  body: JSON.stringify({ serverName })
@@ -152,7 +152,7 @@ async function removeCodexMcpServer(serverName) {
152
152
  */
153
153
  async function toggleCodexMcpServer(serverName, enabled) {
154
154
  try {
155
- const response = await fetch('/api/codex-mcp-toggle', {
155
+ const response = await csrfFetch('/api/codex-mcp-toggle', {
156
156
  method: 'POST',
157
157
  headers: { 'Content-Type': 'application/json' },
158
158
  body: JSON.stringify({ serverName, enabled })
@@ -205,7 +205,7 @@ async function copyCodexServerToClaude(serverName, serverConfig) {
205
205
 
206
206
  async function toggleMcpServer(serverName, enable) {
207
207
  try {
208
- const response = await fetch('/api/mcp-toggle', {
208
+ const response = await csrfFetch('/api/mcp-toggle', {
209
209
  method: 'POST',
210
210
  headers: { 'Content-Type': 'application/json' },
211
211
  body: JSON.stringify({
@@ -239,7 +239,7 @@ async function copyMcpServerToProject(serverName, serverConfig, configType = nul
239
239
  configType = preferredProjectConfigType;
240
240
  }
241
241
 
242
- const response = await fetch('/api/mcp-copy-server', {
242
+ const response = await csrfFetch('/api/mcp-copy-server', {
243
243
  method: 'POST',
244
244
  headers: { 'Content-Type': 'application/json' },
245
245
  body: JSON.stringify({
@@ -316,7 +316,7 @@ function showConfigTypeDialog() {
316
316
 
317
317
  async function removeMcpServerFromProject(serverName) {
318
318
  try {
319
- const response = await fetch('/api/mcp-remove-server', {
319
+ const response = await csrfFetch('/api/mcp-remove-server', {
320
320
  method: 'POST',
321
321
  headers: { 'Content-Type': 'application/json' },
322
322
  body: JSON.stringify({
@@ -343,7 +343,7 @@ async function removeMcpServerFromProject(serverName) {
343
343
 
344
344
  async function addGlobalMcpServer(serverName, serverConfig) {
345
345
  try {
346
- const response = await fetch('/api/mcp-add-global-server', {
346
+ const response = await csrfFetch('/api/mcp-add-global-server', {
347
347
  method: 'POST',
348
348
  headers: { 'Content-Type': 'application/json' },
349
349
  body: JSON.stringify({
@@ -370,7 +370,7 @@ async function addGlobalMcpServer(serverName, serverConfig) {
370
370
 
371
371
  async function removeGlobalMcpServer(serverName) {
372
372
  try {
373
- const response = await fetch('/api/mcp-remove-global-server', {
373
+ const response = await csrfFetch('/api/mcp-remove-global-server', {
374
374
  method: 'POST',
375
375
  headers: { 'Content-Type': 'application/json' },
376
376
  body: JSON.stringify({
@@ -809,7 +809,7 @@ async function submitMcpCreateFromJson() {
809
809
 
810
810
  for (const [name, config] of Object.entries(servers)) {
811
811
  try {
812
- const response = await fetch('/api/mcp-copy-server', {
812
+ const response = await csrfFetch('/api/mcp-copy-server', {
813
813
  method: 'POST',
814
814
  headers: { 'Content-Type': 'application/json' },
815
815
  body: JSON.stringify({
@@ -854,7 +854,7 @@ async function createMcpServerWithConfig(name, serverConfig, scope = 'project')
854
854
 
855
855
  if (scope === 'codex') {
856
856
  // Create in Codex config.toml
857
- response = await fetch('/api/codex-mcp-add', {
857
+ response = await csrfFetch('/api/codex-mcp-add', {
858
858
  method: 'POST',
859
859
  headers: { 'Content-Type': 'application/json' },
860
860
  body: JSON.stringify({
@@ -864,7 +864,7 @@ async function createMcpServerWithConfig(name, serverConfig, scope = 'project')
864
864
  });
865
865
  scopeLabel = 'Codex';
866
866
  } else if (scope === 'global') {
867
- response = await fetch('/api/mcp-add-global-server', {
867
+ response = await csrfFetch('/api/mcp-add-global-server', {
868
868
  method: 'POST',
869
869
  headers: { 'Content-Type': 'application/json' },
870
870
  body: JSON.stringify({
@@ -874,7 +874,7 @@ async function createMcpServerWithConfig(name, serverConfig, scope = 'project')
874
874
  });
875
875
  scopeLabel = 'global';
876
876
  } else {
877
- response = await fetch('/api/mcp-copy-server', {
877
+ response = await csrfFetch('/api/mcp-copy-server', {
878
878
  method: 'POST',
879
879
  headers: { 'Content-Type': 'application/json' },
880
880
  body: JSON.stringify({
@@ -1006,7 +1006,7 @@ async function installCcwToolsMcp(scope = 'workspace') {
1006
1006
 
1007
1007
  if (scope === 'global') {
1008
1008
  // Install to global (~/.claude.json mcpServers)
1009
- const response = await fetch('/api/mcp-add-global-server', {
1009
+ const response = await csrfFetch('/api/mcp-add-global-server', {
1010
1010
  method: 'POST',
1011
1011
  headers: { 'Content-Type': 'application/json' },
1012
1012
  body: JSON.stringify({
@@ -1028,7 +1028,7 @@ async function installCcwToolsMcp(scope = 'workspace') {
1028
1028
  } else {
1029
1029
  // Install to workspace (use preferredProjectConfigType)
1030
1030
  const configType = preferredProjectConfigType;
1031
- const response = await fetch('/api/mcp-copy-server', {
1031
+ const response = await csrfFetch('/api/mcp-copy-server', {
1032
1032
  method: 'POST',
1033
1033
  headers: { 'Content-Type': 'application/json' },
1034
1034
  body: JSON.stringify({
@@ -1074,7 +1074,7 @@ async function updateCcwToolsMcp(scope = 'workspace') {
1074
1074
 
1075
1075
  if (scope === 'global') {
1076
1076
  // Update global (~/.claude.json mcpServers)
1077
- const response = await fetch('/api/mcp-add-global-server', {
1077
+ const response = await csrfFetch('/api/mcp-add-global-server', {
1078
1078
  method: 'POST',
1079
1079
  headers: { 'Content-Type': 'application/json' },
1080
1080
  body: JSON.stringify({
@@ -1096,7 +1096,7 @@ async function updateCcwToolsMcp(scope = 'workspace') {
1096
1096
  } else {
1097
1097
  // Update workspace (use preferredProjectConfigType)
1098
1098
  const configType = preferredProjectConfigType;
1099
- const response = await fetch('/api/mcp-copy-server', {
1099
+ const response = await csrfFetch('/api/mcp-copy-server', {
1100
1100
  method: 'POST',
1101
1101
  headers: { 'Content-Type': 'application/json' },
1102
1102
  body: JSON.stringify({
@@ -415,7 +415,7 @@ async function cleanProjectStorage(projectId) {
415
415
  }
416
416
 
417
417
  try {
418
- const res = await fetch('/api/storage/clean', {
418
+ const res = await csrfFetch('/api/storage/clean', {
419
419
  method: 'POST',
420
420
  headers: { 'Content-Type': 'application/json' },
421
421
  body: JSON.stringify({ projectId })
@@ -451,7 +451,7 @@ async function cleanAllStorageConfirm() {
451
451
  }
452
452
 
453
453
  try {
454
- const res = await fetch('/api/storage/clean', {
454
+ const res = await csrfFetch('/api/storage/clean', {
455
455
  method: 'POST',
456
456
  headers: { 'Content-Type': 'application/json' },
457
457
  body: JSON.stringify({ all: true })
@@ -568,7 +568,7 @@ async function executeSidebarUpdateTask(taskId) {
568
568
  }
569
569
 
570
570
  try {
571
- const response = await fetch('/api/update-claude-md', {
571
+ const response = await csrfFetch('/api/update-claude-md', {
572
572
  method: 'POST',
573
573
  headers: { 'Content-Type': 'application/json' },
574
574
  body: JSON.stringify({
@@ -294,6 +294,7 @@ const i18n = {
294
294
  'codexlens.envGroup.reranker': 'Reranker Configuration',
295
295
  'codexlens.envGroup.concurrency': 'Concurrency Settings',
296
296
  'codexlens.envGroup.cascade': 'Cascade Search Settings',
297
+ 'codexlens.envGroup.chunking': 'Chunking Options',
297
298
  'codexlens.envGroup.llm': 'LLM Features',
298
299
  // Environment variable field labels
299
300
  'codexlens.envField.backend': 'Backend',
@@ -313,6 +314,10 @@ const i18n = {
313
314
  'codexlens.envField.searchStrategy': 'Search Strategy',
314
315
  'codexlens.envField.coarseK': 'Coarse K (1st stage)',
315
316
  'codexlens.envField.fineK': 'Fine K (final)',
317
+ 'codexlens.envField.stripComments': 'Strip Comments',
318
+ 'codexlens.envField.stripDocstrings': 'Strip Docstrings',
319
+ 'codexlens.envField.testFilePenalty': 'Test File Penalty',
320
+ 'codexlens.envField.docstringWeight': 'Docstring Weight',
316
321
  'codexlens.usingApiReranker': 'Using API Reranker',
317
322
  'codexlens.currentModel': 'Current Model',
318
323
  'codexlens.localModels': 'Local Models',
@@ -2443,6 +2448,7 @@ const i18n = {
2443
2448
  'codexlens.envGroup.reranker': '重排序配置',
2444
2449
  'codexlens.envGroup.concurrency': '并发设置',
2445
2450
  'codexlens.envGroup.cascade': '级联搜索设置',
2451
+ 'codexlens.envGroup.chunking': '分块选项',
2446
2452
  'codexlens.envGroup.llm': 'LLM 功能',
2447
2453
  // 环境变量字段标签
2448
2454
  'codexlens.envField.backend': '后端',
@@ -2462,6 +2468,10 @@ const i18n = {
2462
2468
  'codexlens.envField.searchStrategy': '搜索策略',
2463
2469
  'codexlens.envField.coarseK': '粗筛 K (第一阶段)',
2464
2470
  'codexlens.envField.fineK': '精筛 K (最终)',
2471
+ 'codexlens.envField.stripComments': '去除注释',
2472
+ 'codexlens.envField.stripDocstrings': '去除文档字符串',
2473
+ 'codexlens.envField.testFilePenalty': '测试文件惩罚',
2474
+ 'codexlens.envField.docstringWeight': '文档字符串权重',
2465
2475
  'codexlens.usingApiReranker': '使用 API 重排序',
2466
2476
  'codexlens.currentModel': '当前模型',
2467
2477
  'codexlens.localModels': '本地模型',
@@ -2752,7 +2752,7 @@ async function installSemanticDeps() {
2752
2752
  '<div class="text-sm text-muted-foreground animate-pulse">' + t('codexlens.installingDeps') + '</div>';
2753
2753
 
2754
2754
  try {
2755
- var response = await fetch('/api/codexlens/semantic/install', { method: 'POST' });
2755
+ var response = await csrfFetch('/api/codexlens/semantic/install', { method: 'POST' });
2756
2756
  var result = await response.json();
2757
2757
 
2758
2758
  if (result.success) {