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.
Files changed (208) hide show
  1. package/.claude/CLAUDE.md +16 -1
  2. package/.claude/workflows/cli-templates/protocols/analysis-protocol.md +11 -4
  3. package/.claude/workflows/cli-templates/protocols/write-protocol.md +10 -75
  4. package/.claude/workflows/cli-tools-usage.md +14 -24
  5. package/.codex/AGENTS.md +51 -1
  6. package/.codex/prompts/compact.md +378 -0
  7. package/.gemini/GEMINI.md +57 -20
  8. package/ccw/dist/cli.d.ts.map +1 -1
  9. package/ccw/dist/cli.js +21 -8
  10. package/ccw/dist/cli.js.map +1 -1
  11. package/ccw/dist/commands/cli.d.ts +2 -0
  12. package/ccw/dist/commands/cli.d.ts.map +1 -1
  13. package/ccw/dist/commands/cli.js +129 -8
  14. package/ccw/dist/commands/cli.js.map +1 -1
  15. package/ccw/dist/commands/hook.d.ts.map +1 -1
  16. package/ccw/dist/commands/hook.js +3 -2
  17. package/ccw/dist/commands/hook.js.map +1 -1
  18. package/ccw/dist/config/litellm-api-config-manager.d.ts +180 -0
  19. package/ccw/dist/config/litellm-api-config-manager.d.ts.map +1 -0
  20. package/ccw/dist/config/litellm-api-config-manager.js +770 -0
  21. package/ccw/dist/config/litellm-api-config-manager.js.map +1 -0
  22. package/ccw/dist/config/provider-models.d.ts +73 -0
  23. package/ccw/dist/config/provider-models.d.ts.map +1 -0
  24. package/ccw/dist/config/provider-models.js +172 -0
  25. package/ccw/dist/config/provider-models.js.map +1 -0
  26. package/ccw/dist/core/cache-manager.d.ts.map +1 -1
  27. package/ccw/dist/core/cache-manager.js +3 -5
  28. package/ccw/dist/core/cache-manager.js.map +1 -1
  29. package/ccw/dist/core/dashboard-generator.d.ts.map +1 -1
  30. package/ccw/dist/core/dashboard-generator.js +3 -1
  31. package/ccw/dist/core/dashboard-generator.js.map +1 -1
  32. package/ccw/dist/core/routes/cli-routes.d.ts.map +1 -1
  33. package/ccw/dist/core/routes/cli-routes.js +169 -0
  34. package/ccw/dist/core/routes/cli-routes.js.map +1 -1
  35. package/ccw/dist/core/routes/codexlens-routes.d.ts.map +1 -1
  36. package/ccw/dist/core/routes/codexlens-routes.js +234 -18
  37. package/ccw/dist/core/routes/codexlens-routes.js.map +1 -1
  38. package/ccw/dist/core/routes/hooks-routes.d.ts.map +1 -1
  39. package/ccw/dist/core/routes/hooks-routes.js +30 -32
  40. package/ccw/dist/core/routes/hooks-routes.js.map +1 -1
  41. package/ccw/dist/core/routes/litellm-api-routes.d.ts +21 -0
  42. package/ccw/dist/core/routes/litellm-api-routes.d.ts.map +1 -0
  43. package/ccw/dist/core/routes/litellm-api-routes.js +780 -0
  44. package/ccw/dist/core/routes/litellm-api-routes.js.map +1 -0
  45. package/ccw/dist/core/routes/litellm-routes.d.ts +20 -0
  46. package/ccw/dist/core/routes/litellm-routes.d.ts.map +1 -0
  47. package/ccw/dist/core/routes/litellm-routes.js +85 -0
  48. package/ccw/dist/core/routes/litellm-routes.js.map +1 -0
  49. package/ccw/dist/core/routes/mcp-routes.js +2 -2
  50. package/ccw/dist/core/routes/mcp-routes.js.map +1 -1
  51. package/ccw/dist/core/routes/status-routes.d.ts.map +1 -1
  52. package/ccw/dist/core/routes/status-routes.js +39 -0
  53. package/ccw/dist/core/routes/status-routes.js.map +1 -1
  54. package/ccw/dist/core/routes/system-routes.js +1 -1
  55. package/ccw/dist/core/routes/system-routes.js.map +1 -1
  56. package/ccw/dist/core/server.d.ts.map +1 -1
  57. package/ccw/dist/core/server.js +15 -1
  58. package/ccw/dist/core/server.js.map +1 -1
  59. package/ccw/dist/mcp-server/index.js +1 -1
  60. package/ccw/dist/mcp-server/index.js.map +1 -1
  61. package/ccw/dist/tools/claude-cli-tools.d.ts +82 -0
  62. package/ccw/dist/tools/claude-cli-tools.d.ts.map +1 -0
  63. package/ccw/dist/tools/claude-cli-tools.js +216 -0
  64. package/ccw/dist/tools/claude-cli-tools.js.map +1 -0
  65. package/ccw/dist/tools/cli-executor.d.ts.map +1 -1
  66. package/ccw/dist/tools/cli-executor.js +76 -14
  67. package/ccw/dist/tools/cli-executor.js.map +1 -1
  68. package/ccw/dist/tools/codex-lens.d.ts +9 -2
  69. package/ccw/dist/tools/codex-lens.d.ts.map +1 -1
  70. package/ccw/dist/tools/codex-lens.js +114 -9
  71. package/ccw/dist/tools/codex-lens.js.map +1 -1
  72. package/ccw/dist/tools/context-cache-store.d.ts +136 -0
  73. package/ccw/dist/tools/context-cache-store.d.ts.map +1 -0
  74. package/ccw/dist/tools/context-cache-store.js +256 -0
  75. package/ccw/dist/tools/context-cache-store.js.map +1 -0
  76. package/ccw/dist/tools/context-cache.d.ts +56 -0
  77. package/ccw/dist/tools/context-cache.d.ts.map +1 -0
  78. package/ccw/dist/tools/context-cache.js +294 -0
  79. package/ccw/dist/tools/context-cache.js.map +1 -0
  80. package/ccw/dist/tools/core-memory.d.ts.map +1 -1
  81. package/ccw/dist/tools/core-memory.js +33 -19
  82. package/ccw/dist/tools/core-memory.js.map +1 -1
  83. package/ccw/dist/tools/index.d.ts.map +1 -1
  84. package/ccw/dist/tools/index.js +2 -0
  85. package/ccw/dist/tools/index.js.map +1 -1
  86. package/ccw/dist/tools/litellm-client.d.ts +85 -0
  87. package/ccw/dist/tools/litellm-client.d.ts.map +1 -0
  88. package/ccw/dist/tools/litellm-client.js +188 -0
  89. package/ccw/dist/tools/litellm-client.js.map +1 -0
  90. package/ccw/dist/tools/litellm-executor.d.ts +34 -0
  91. package/ccw/dist/tools/litellm-executor.d.ts.map +1 -0
  92. package/ccw/dist/tools/litellm-executor.js +192 -0
  93. package/ccw/dist/tools/litellm-executor.js.map +1 -0
  94. package/ccw/dist/tools/pattern-parser.d.ts +55 -0
  95. package/ccw/dist/tools/pattern-parser.d.ts.map +1 -0
  96. package/ccw/dist/tools/pattern-parser.js +237 -0
  97. package/ccw/dist/tools/pattern-parser.js.map +1 -0
  98. package/ccw/dist/tools/smart-search.d.ts +1 -0
  99. package/ccw/dist/tools/smart-search.d.ts.map +1 -1
  100. package/ccw/dist/tools/smart-search.js +117 -41
  101. package/ccw/dist/tools/smart-search.js.map +1 -1
  102. package/ccw/dist/types/litellm-api-config.d.ts +294 -0
  103. package/ccw/dist/types/litellm-api-config.d.ts.map +1 -0
  104. package/ccw/dist/types/litellm-api-config.js +8 -0
  105. package/ccw/dist/types/litellm-api-config.js.map +1 -0
  106. package/ccw/src/cli.ts +258 -244
  107. package/ccw/src/commands/cli.ts +153 -9
  108. package/ccw/src/commands/hook.ts +3 -2
  109. package/ccw/src/config/.litellm-api-config-manager.ts.2025-12-23T11-57-43-727Z.bak +441 -0
  110. package/ccw/src/config/litellm-api-config-manager.ts +1012 -0
  111. package/ccw/src/config/provider-models.ts +222 -0
  112. package/ccw/src/core/cache-manager.ts +292 -294
  113. package/ccw/src/core/dashboard-generator.ts +3 -1
  114. package/ccw/src/core/routes/cli-routes.ts +192 -0
  115. package/ccw/src/core/routes/codexlens-routes.ts +241 -19
  116. package/ccw/src/core/routes/hooks-routes.ts +399 -405
  117. package/ccw/src/core/routes/litellm-api-routes.ts +930 -0
  118. package/ccw/src/core/routes/litellm-routes.ts +107 -0
  119. package/ccw/src/core/routes/mcp-routes.ts +1271 -1271
  120. package/ccw/src/core/routes/status-routes.ts +51 -0
  121. package/ccw/src/core/routes/system-routes.ts +1 -1
  122. package/ccw/src/core/server.ts +15 -1
  123. package/ccw/src/mcp-server/index.ts +1 -1
  124. package/ccw/src/templates/dashboard-css/12-cli-legacy.css +44 -0
  125. package/ccw/src/templates/dashboard-css/31-api-settings.css +2265 -0
  126. package/ccw/src/templates/dashboard-js/components/cli-history.js +15 -8
  127. package/ccw/src/templates/dashboard-js/components/cli-status.js +323 -9
  128. package/ccw/src/templates/dashboard-js/components/navigation.js +329 -313
  129. package/ccw/src/templates/dashboard-js/i18n.js +583 -1
  130. package/ccw/src/templates/dashboard-js/views/api-settings.js +3362 -0
  131. package/ccw/src/templates/dashboard-js/views/cli-manager.js +199 -24
  132. package/ccw/src/templates/dashboard-js/views/codexlens-manager.js +1265 -27
  133. package/ccw/src/templates/dashboard.html +840 -831
  134. package/ccw/src/tools/claude-cli-tools.ts +300 -0
  135. package/ccw/src/tools/cli-executor.ts +83 -14
  136. package/ccw/src/tools/codex-lens.ts +146 -9
  137. package/ccw/src/tools/context-cache-store.ts +368 -0
  138. package/ccw/src/tools/context-cache.ts +393 -0
  139. package/ccw/src/tools/core-memory.ts +33 -19
  140. package/ccw/src/tools/index.ts +2 -0
  141. package/ccw/src/tools/litellm-client.ts +246 -0
  142. package/ccw/src/tools/litellm-executor.ts +241 -0
  143. package/ccw/src/tools/pattern-parser.ts +329 -0
  144. package/ccw/src/tools/smart-search.ts +142 -41
  145. package/ccw/src/types/litellm-api-config.ts +402 -0
  146. package/ccw-litellm/README.md +180 -0
  147. package/ccw-litellm/pyproject.toml +35 -0
  148. package/ccw-litellm/src/ccw_litellm/__init__.py +47 -0
  149. package/ccw-litellm/src/ccw_litellm/__pycache__/__init__.cpython-313.pyc +0 -0
  150. package/ccw-litellm/src/ccw_litellm/__pycache__/cli.cpython-313.pyc +0 -0
  151. package/ccw-litellm/src/ccw_litellm/cli.py +108 -0
  152. package/ccw-litellm/src/ccw_litellm/clients/__init__.py +12 -0
  153. package/ccw-litellm/src/ccw_litellm/clients/__pycache__/__init__.cpython-313.pyc +0 -0
  154. package/ccw-litellm/src/ccw_litellm/clients/__pycache__/litellm_embedder.cpython-313.pyc +0 -0
  155. package/ccw-litellm/src/ccw_litellm/clients/__pycache__/litellm_llm.cpython-313.pyc +0 -0
  156. package/ccw-litellm/src/ccw_litellm/clients/litellm_embedder.py +251 -0
  157. package/ccw-litellm/src/ccw_litellm/clients/litellm_llm.py +165 -0
  158. package/ccw-litellm/src/ccw_litellm/config/__init__.py +22 -0
  159. package/ccw-litellm/src/ccw_litellm/config/__pycache__/__init__.cpython-313.pyc +0 -0
  160. package/ccw-litellm/src/ccw_litellm/config/__pycache__/loader.cpython-313.pyc +0 -0
  161. package/ccw-litellm/src/ccw_litellm/config/__pycache__/models.cpython-313.pyc +0 -0
  162. package/ccw-litellm/src/ccw_litellm/config/loader.py +316 -0
  163. package/ccw-litellm/src/ccw_litellm/config/models.py +130 -0
  164. package/ccw-litellm/src/ccw_litellm/interfaces/__init__.py +14 -0
  165. package/ccw-litellm/src/ccw_litellm/interfaces/__pycache__/__init__.cpython-313.pyc +0 -0
  166. package/ccw-litellm/src/ccw_litellm/interfaces/__pycache__/embedder.cpython-313.pyc +0 -0
  167. package/ccw-litellm/src/ccw_litellm/interfaces/__pycache__/llm.cpython-313.pyc +0 -0
  168. package/ccw-litellm/src/ccw_litellm/interfaces/embedder.py +52 -0
  169. package/ccw-litellm/src/ccw_litellm/interfaces/llm.py +45 -0
  170. package/codex-lens/src/codexlens/__pycache__/config.cpython-313.pyc +0 -0
  171. package/codex-lens/src/codexlens/cli/__pycache__/commands.cpython-313.pyc +0 -0
  172. package/codex-lens/src/codexlens/cli/__pycache__/embedding_manager.cpython-313.pyc +0 -0
  173. package/codex-lens/src/codexlens/cli/__pycache__/model_manager.cpython-313.pyc +0 -0
  174. package/codex-lens/src/codexlens/cli/__pycache__/output.cpython-313.pyc +0 -0
  175. package/codex-lens/src/codexlens/cli/commands.py +378 -23
  176. package/codex-lens/src/codexlens/cli/embedding_manager.py +660 -56
  177. package/codex-lens/src/codexlens/cli/model_manager.py +31 -18
  178. package/codex-lens/src/codexlens/cli/output.py +12 -1
  179. package/codex-lens/src/codexlens/config.py +93 -0
  180. package/codex-lens/src/codexlens/search/__pycache__/chain_search.cpython-313.pyc +0 -0
  181. package/codex-lens/src/codexlens/search/__pycache__/hybrid_search.cpython-313.pyc +0 -0
  182. package/codex-lens/src/codexlens/search/__pycache__/ranking.cpython-313.pyc +0 -0
  183. package/codex-lens/src/codexlens/search/chain_search.py +6 -2
  184. package/codex-lens/src/codexlens/search/hybrid_search.py +44 -21
  185. package/codex-lens/src/codexlens/search/ranking.py +1 -1
  186. package/codex-lens/src/codexlens/semantic/__init__.py +42 -0
  187. package/codex-lens/src/codexlens/semantic/__pycache__/__init__.cpython-313.pyc +0 -0
  188. package/codex-lens/src/codexlens/semantic/__pycache__/base.cpython-313.pyc +0 -0
  189. package/codex-lens/src/codexlens/semantic/__pycache__/chunker.cpython-313.pyc +0 -0
  190. package/codex-lens/src/codexlens/semantic/__pycache__/embedder.cpython-313.pyc +0 -0
  191. package/codex-lens/src/codexlens/semantic/__pycache__/factory.cpython-313.pyc +0 -0
  192. package/codex-lens/src/codexlens/semantic/__pycache__/gpu_support.cpython-313.pyc +0 -0
  193. package/codex-lens/src/codexlens/semantic/__pycache__/litellm_embedder.cpython-313.pyc +0 -0
  194. package/codex-lens/src/codexlens/semantic/__pycache__/vector_store.cpython-313.pyc +0 -0
  195. package/codex-lens/src/codexlens/semantic/base.py +61 -0
  196. package/codex-lens/src/codexlens/semantic/chunker.py +43 -20
  197. package/codex-lens/src/codexlens/semantic/embedder.py +60 -13
  198. package/codex-lens/src/codexlens/semantic/factory.py +98 -0
  199. package/codex-lens/src/codexlens/semantic/gpu_support.py +225 -3
  200. package/codex-lens/src/codexlens/semantic/litellm_embedder.py +144 -0
  201. package/codex-lens/src/codexlens/semantic/rotational_embedder.py +434 -0
  202. package/codex-lens/src/codexlens/semantic/vector_store.py +33 -8
  203. package/codex-lens/src/codexlens/storage/__pycache__/path_mapper.cpython-313.pyc +0 -0
  204. package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_004_dual_fts.cpython-313.pyc +0 -0
  205. package/codex-lens/src/codexlens/storage/path_mapper.py +27 -1
  206. package/package.json +15 -5
  207. package/.codex/prompts.zip +0 -0
  208. package/ccw/package.json +0 -65
@@ -33,9 +33,13 @@ async function loadCliHistory(options = {}) {
33
33
  }
34
34
 
35
35
  // Load native session content for a specific execution
36
- async function loadNativeSessionContent(executionId) {
36
+ async function loadNativeSessionContent(executionId, sourceDir) {
37
37
  try {
38
- const url = `/api/cli/native-session?path=${encodeURIComponent(projectPath)}&id=${encodeURIComponent(executionId)}`;
38
+ // If sourceDir provided, use it to build the correct path
39
+ const basePath = sourceDir && sourceDir !== '.'
40
+ ? projectPath + '/' + sourceDir
41
+ : projectPath;
42
+ const url = `/api/cli/native-session?path=${encodeURIComponent(basePath)}&id=${encodeURIComponent(executionId)}`;
39
43
  const response = await fetch(url);
40
44
  if (!response.ok) return null;
41
45
  return await response.json();
@@ -133,9 +137,12 @@ function renderCliHistory() {
133
137
  </span>`
134
138
  : '';
135
139
 
140
+ // Escape sourceDir for use in onclick
141
+ const sourceDirEscaped = exec.sourceDir ? exec.sourceDir.replace(/'/g, "\\'") : '';
142
+
136
143
  return `
137
144
  <div class="cli-history-item ${hasNative ? 'has-native' : ''}">
138
- <div class="cli-history-item-content" onclick="showExecutionDetail('${exec.id}')">
145
+ <div class="cli-history-item-content" onclick="showExecutionDetail('${exec.id}', '${sourceDirEscaped}')">
139
146
  <div class="cli-history-item-header">
140
147
  <span class="cli-tool-tag cli-tool-${exec.tool}">${exec.tool.toUpperCase()}</span>
141
148
  <span class="cli-mode-tag">${exec.mode || 'analysis'}</span>
@@ -154,14 +161,14 @@ function renderCliHistory() {
154
161
  </div>
155
162
  <div class="cli-history-actions">
156
163
  ${hasNative ? `
157
- <button class="btn-icon" onclick="event.stopPropagation(); showNativeSessionDetail('${exec.id}')" title="View Native Session">
164
+ <button class="btn-icon" onclick="event.stopPropagation(); showNativeSessionDetail('${exec.id}', '${sourceDirEscaped}')" title="View Native Session">
158
165
  <i data-lucide="file-json" class="w-3.5 h-3.5"></i>
159
166
  </button>
160
167
  ` : ''}
161
- <button class="btn-icon" onclick="event.stopPropagation(); showExecutionDetail('${exec.id}')" title="View Details">
168
+ <button class="btn-icon" onclick="event.stopPropagation(); showExecutionDetail('${exec.id}', '${sourceDirEscaped}')" title="View Details">
162
169
  <i data-lucide="eye" class="w-3.5 h-3.5"></i>
163
170
  </button>
164
- <button class="btn-icon btn-danger" onclick="event.stopPropagation(); confirmDeleteExecution('${exec.id}')" title="Delete">
171
+ <button class="btn-icon btn-danger" onclick="event.stopPropagation(); confirmDeleteExecution('${exec.id}', '${sourceDirEscaped}')" title="Delete">
165
172
  <i data-lucide="trash-2" class="w-3.5 h-3.5"></i>
166
173
  </button>
167
174
  </div>
@@ -650,9 +657,9 @@ async function copyConcatenatedPrompt(executionId) {
650
657
  /**
651
658
  * Show native session detail modal with full conversation content
652
659
  */
653
- async function showNativeSessionDetail(executionId) {
660
+ async function showNativeSessionDetail(executionId, sourceDir) {
654
661
  // Load native session content
655
- const nativeSession = await loadNativeSessionContent(executionId);
662
+ const nativeSession = await loadNativeSessionContent(executionId, sourceDir);
656
663
 
657
664
  if (!nativeSession) {
658
665
  showRefreshToast('Native session not found', 'error');
@@ -5,8 +5,11 @@
5
5
  let cliToolStatus = { gemini: {}, qwen: {}, codex: {}, claude: {} };
6
6
  let codexLensStatus = { ready: false };
7
7
  let semanticStatus = { available: false };
8
+ let ccwInstallStatus = { installed: true, workflowsInstalled: true, missingFiles: [], installPath: '' };
8
9
  let defaultCliTool = 'gemini';
9
10
  let promptConcatFormat = localStorage.getItem('ccw-prompt-format') || 'plain'; // plain, yaml, json
11
+ let cliToolsConfig = {}; // CLI tools enable/disable config
12
+ let apiEndpoints = []; // API endpoints from LiteLLM config
10
13
 
11
14
  // Smart Context settings
12
15
  let smartContextEnabled = localStorage.getItem('ccw-smart-context') === 'true';
@@ -38,10 +41,18 @@ async function loadAllStatuses() {
38
41
  cliToolStatus = data.cli || { gemini: {}, qwen: {}, codex: {}, claude: {} };
39
42
  codexLensStatus = data.codexLens || { ready: false };
40
43
  semanticStatus = data.semantic || { available: false };
44
+ ccwInstallStatus = data.ccwInstall || { installed: true, workflowsInstalled: true, missingFiles: [], installPath: '' };
45
+
46
+ // Load CLI tools config and API endpoints
47
+ await Promise.all([
48
+ loadCliToolsConfig(),
49
+ loadApiEndpoints()
50
+ ]);
41
51
 
42
52
  // Update badges
43
53
  updateCliBadge();
44
54
  updateCodexLensBadge();
55
+ updateCcwInstallBadge();
45
56
 
46
57
  return data;
47
58
  } catch (err) {
@@ -118,6 +129,54 @@ async function loadCodexLensStatus() {
118
129
  }
119
130
  }
120
131
 
132
+ /**
133
+ * Load CodexLens dashboard data using aggregated endpoint (single API call)
134
+ * This is optimized for the CodexLens Manager page initialization
135
+ * @returns {Promise<object|null>} Dashboard init data or null on error
136
+ */
137
+ async function loadCodexLensDashboardInit() {
138
+ try {
139
+ const response = await fetch('/api/codexlens/dashboard-init');
140
+ if (!response.ok) throw new Error('Failed to load CodexLens dashboard init');
141
+ const data = await response.json();
142
+
143
+ // Update status variables from aggregated response
144
+ codexLensStatus = data.status || { ready: false };
145
+ semanticStatus = data.semantic || { available: false };
146
+
147
+ // Expose to window for other modules
148
+ if (!window.cliToolsStatus) {
149
+ window.cliToolsStatus = {};
150
+ }
151
+ window.cliToolsStatus.codexlens = {
152
+ installed: data.installed || false,
153
+ version: data.status?.version || null,
154
+ installedModels: [],
155
+ config: data.config || {},
156
+ semantic: data.semantic || {}
157
+ };
158
+
159
+ // Store config globally for easy access
160
+ window.codexLensConfig = data.config || {};
161
+ window.codexLensStatusData = data.statusData || {};
162
+
163
+ // Update badges
164
+ updateCodexLensBadge();
165
+
166
+ console.log('[CLI Status] CodexLens dashboard init loaded:', {
167
+ installed: data.installed,
168
+ version: data.status?.version,
169
+ semanticAvailable: data.semantic?.available
170
+ });
171
+
172
+ return data;
173
+ } catch (err) {
174
+ console.error('Failed to load CodexLens dashboard init:', err);
175
+ // Fallback to individual calls
176
+ return await loadCodexLensStatus();
177
+ }
178
+ }
179
+
121
180
  /**
122
181
  * Legacy: Load semantic status individually
123
182
  */
@@ -165,6 +224,67 @@ async function loadInstalledModels() {
165
224
  }
166
225
  }
167
226
 
227
+ /**
228
+ * Load CLI tools config from .claude/cli-tools.json (project or global fallback)
229
+ */
230
+ async function loadCliToolsConfig() {
231
+ try {
232
+ const response = await fetch('/api/cli/tools-config');
233
+ if (!response.ok) return null;
234
+ const data = await response.json();
235
+ // Store full config and extract tools for backward compatibility
236
+ cliToolsConfig = data.tools || {};
237
+ window.claudeCliToolsConfig = data; // Full config available globally
238
+
239
+ // Load default tool from config
240
+ if (data.defaultTool) {
241
+ defaultCliTool = data.defaultTool;
242
+ }
243
+
244
+ console.log('[CLI Config] Loaded from:', data._configInfo?.source || 'unknown', '| Default:', data.defaultTool);
245
+ return data;
246
+ } catch (err) {
247
+ console.error('Failed to load CLI tools config:', err);
248
+ return null;
249
+ }
250
+ }
251
+
252
+ /**
253
+ * Update CLI tool enabled status
254
+ */
255
+ async function updateCliToolEnabled(tool, enabled) {
256
+ try {
257
+ const response = await fetch('/api/cli/tools-config/' + tool, {
258
+ method: 'PUT',
259
+ headers: { 'Content-Type': 'application/json' },
260
+ body: JSON.stringify({ enabled: enabled })
261
+ });
262
+ if (!response.ok) throw new Error('Failed to update');
263
+ showRefreshToast(tool + (enabled ? ' enabled' : ' disabled'), 'success');
264
+ return await response.json();
265
+ } catch (err) {
266
+ console.error('Failed to update CLI tool:', err);
267
+ showRefreshToast('Failed to update ' + tool, 'error');
268
+ return null;
269
+ }
270
+ }
271
+
272
+ /**
273
+ * Load API endpoints from LiteLLM config
274
+ */
275
+ async function loadApiEndpoints() {
276
+ try {
277
+ const response = await fetch('/api/litellm-api/endpoints');
278
+ if (!response.ok) return [];
279
+ const data = await response.json();
280
+ apiEndpoints = data.endpoints || [];
281
+ return apiEndpoints;
282
+ } catch (err) {
283
+ console.error('Failed to load API endpoints:', err);
284
+ return [];
285
+ }
286
+ }
287
+
168
288
  // ========== Badge Update ==========
169
289
  function updateCliBadge() {
170
290
  const badge = document.getElementById('badgeCliTools');
@@ -187,6 +307,25 @@ function updateCodexLensBadge() {
187
307
  }
188
308
  }
189
309
 
310
+ function updateCcwInstallBadge() {
311
+ const badge = document.getElementById('badgeCcwInstall');
312
+ if (badge) {
313
+ if (ccwInstallStatus.installed) {
314
+ badge.textContent = t('status.installed');
315
+ badge.classList.add('text-success');
316
+ badge.classList.remove('text-warning', 'text-destructive');
317
+ } else if (ccwInstallStatus.workflowsInstalled === false) {
318
+ badge.textContent = t('status.incomplete');
319
+ badge.classList.add('text-warning');
320
+ badge.classList.remove('text-success', 'text-destructive');
321
+ } else {
322
+ badge.textContent = t('status.notInstalled');
323
+ badge.classList.add('text-destructive');
324
+ badge.classList.remove('text-success', 'text-warning');
325
+ }
326
+ }
327
+ }
328
+
190
329
  // ========== Rendering ==========
191
330
  function renderCliStatus() {
192
331
  const container = document.getElementById('cli-status-panel');
@@ -212,25 +351,41 @@ function renderCliStatus() {
212
351
  const status = cliToolStatus[tool] || {};
213
352
  const isAvailable = status.available;
214
353
  const isDefault = defaultCliTool === tool;
354
+ const config = cliToolsConfig[tool] || { enabled: true };
355
+ const isEnabled = config.enabled !== false;
356
+ const canSetDefault = isAvailable && isEnabled && !isDefault;
215
357
 
216
358
  return `
217
- <div class="cli-tool-card tool-${tool} ${isAvailable ? 'available' : 'unavailable'}">
359
+ <div class="cli-tool-card tool-${tool} ${isAvailable ? 'available' : 'unavailable'} ${!isEnabled ? 'disabled' : ''}">
218
360
  <div class="cli-tool-header">
219
- <span class="cli-tool-status ${isAvailable ? 'status-available' : 'status-unavailable'}"></span>
361
+ <span class="cli-tool-status ${isAvailable && isEnabled ? 'status-available' : 'status-unavailable'}"></span>
220
362
  <span class="cli-tool-name">${tool.charAt(0).toUpperCase() + tool.slice(1)}</span>
221
363
  ${isDefault ? '<span class="cli-tool-badge">Default</span>' : ''}
364
+ ${!isEnabled && isAvailable ? '<span class="cli-tool-badge-disabled">Disabled</span>' : ''}
222
365
  </div>
223
366
  <div class="cli-tool-desc text-xs text-muted-foreground mt-1">
224
367
  ${toolDescriptions[tool]}
225
368
  </div>
226
- <div class="cli-tool-info mt-2">
227
- ${isAvailable
228
- ? `<span class="text-success flex items-center gap-1"><i data-lucide="check-circle" class="w-3 h-3"></i> Ready</span>`
229
- : `<span class="text-muted-foreground flex items-center gap-1"><i data-lucide="circle-dashed" class="w-3 h-3"></i> Not Installed</span>`
230
- }
369
+ <div class="cli-tool-info mt-2 flex items-center justify-between">
370
+ <div>
371
+ ${isAvailable
372
+ ? (isEnabled
373
+ ? `<span class="text-success flex items-center gap-1"><i data-lucide="check-circle" class="w-3 h-3"></i> Ready</span>`
374
+ : `<span class="text-warning flex items-center gap-1"><i data-lucide="pause-circle" class="w-3 h-3"></i> Disabled</span>`)
375
+ : `<span class="text-muted-foreground flex items-center gap-1"><i data-lucide="circle-dashed" class="w-3 h-3"></i> Not Installed</span>`
376
+ }
377
+ </div>
231
378
  </div>
232
- <div class="cli-tool-actions mt-3">
233
- ${isAvailable && !isDefault
379
+ <div class="cli-tool-actions mt-3 flex gap-2">
380
+ ${isAvailable ? (isEnabled
381
+ ? `<button class="btn-sm btn-outline-warning flex items-center gap-1" onclick="toggleCliTool('${tool}', false)">
382
+ <i data-lucide="pause" class="w-3 h-3"></i> Disable
383
+ </button>`
384
+ : `<button class="btn-sm btn-outline-success flex items-center gap-1" onclick="toggleCliTool('${tool}', true)">
385
+ <i data-lucide="play" class="w-3 h-3"></i> Enable
386
+ </button>`
387
+ ) : ''}
388
+ ${canSetDefault
234
389
  ? `<button class="btn-sm btn-outline flex items-center gap-1" onclick="setDefaultCliTool('${tool}')">
235
390
  <i data-lucide="star" class="w-3 h-3"></i> Set Default
236
391
  </button>`
@@ -310,11 +465,75 @@ function renderCliStatus() {
310
465
  </div>
311
466
  ` : '';
312
467
 
468
+ // CCW Installation Status card (show warning if not fully installed)
469
+ const ccwInstallHtml = !ccwInstallStatus.installed ? `
470
+ <div class="cli-tool-card tool-ccw-install unavailable" style="border: 1px solid var(--warning); background: rgba(var(--warning-rgb), 0.05);">
471
+ <div class="cli-tool-header">
472
+ <span class="cli-tool-status status-unavailable" style="background: var(--warning);"></span>
473
+ <span class="cli-tool-name">${t('status.ccwInstall')}</span>
474
+ <span class="badge px-1.5 py-0.5 text-xs rounded bg-warning/20 text-warning">${t('status.required')}</span>
475
+ </div>
476
+ <div class="cli-tool-desc text-xs text-muted-foreground mt-1">
477
+ ${t('status.ccwInstallDesc')}
478
+ </div>
479
+ <div class="cli-tool-info mt-2">
480
+ <span class="text-warning flex items-center gap-1">
481
+ <i data-lucide="alert-triangle" class="w-3 h-3"></i>
482
+ ${ccwInstallStatus.missingFiles.length} ${t('status.filesMissing')}
483
+ </span>
484
+ </div>
485
+ <div class="cli-tool-actions flex flex-col gap-2 mt-3">
486
+ <div class="text-xs text-muted-foreground">
487
+ <p class="mb-1">${t('status.missingFiles')}:</p>
488
+ <ul class="list-disc list-inside text-xs opacity-70">
489
+ ${ccwInstallStatus.missingFiles.slice(0, 3).map(f => `<li>${f}</li>`).join('')}
490
+ ${ccwInstallStatus.missingFiles.length > 3 ? `<li>+${ccwInstallStatus.missingFiles.length - 3} more...</li>` : ''}
491
+ </ul>
492
+ </div>
493
+ <div class="bg-muted/50 rounded p-2 mt-2">
494
+ <p class="text-xs font-medium mb-1">${t('status.runToFix')}:</p>
495
+ <code class="text-xs bg-background px-2 py-1 rounded block">ccw install</code>
496
+ </div>
497
+ </div>
498
+ </div>
499
+ ` : '';
500
+
501
+ // API Endpoints section
502
+ const apiEndpointsHtml = apiEndpoints.length > 0 ? `
503
+ <div class="cli-api-endpoints-section" style="margin-top: 1.5rem;">
504
+ <div class="cli-section-header" style="display: flex; align-items: center; gap: 0.5rem; margin-bottom: 1rem;">
505
+ <h4 style="display: flex; align-items: center; gap: 0.5rem; font-weight: 600; margin: 0;">
506
+ <i data-lucide="link" class="w-4 h-4"></i> API Endpoints
507
+ </h4>
508
+ <span class="badge" style="padding: 0.125rem 0.5rem; font-size: 0.75rem; border-radius: 0.25rem; background: var(--muted); color: var(--muted-foreground);">${apiEndpoints.length}</span>
509
+ </div>
510
+ <div class="cli-endpoints-list" style="display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 0.75rem;">
511
+ ${apiEndpoints.map(ep => `
512
+ <div class="cli-endpoint-card ${ep.enabled ? 'available' : 'unavailable'}" style="padding: 0.75rem; border: 1px solid var(--border); border-radius: 0.5rem; background: var(--card);">
513
+ <div class="cli-endpoint-header" style="display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem;">
514
+ <span class="cli-tool-status ${ep.enabled ? 'status-available' : 'status-unavailable'}" style="width: 8px; height: 8px; border-radius: 50%; background: ${ep.enabled ? 'var(--success)' : 'var(--muted-foreground)'}; flex-shrink: 0;"></span>
515
+ <span class="cli-endpoint-id" style="font-weight: 500; font-size: 0.875rem;">${ep.id}</span>
516
+ </div>
517
+ <div class="cli-endpoint-info" style="margin-top: 0.25rem;">
518
+ <span class="text-xs text-muted-foreground" style="font-size: 0.75rem; color: var(--muted-foreground);">${ep.model}</span>
519
+ </div>
520
+ </div>
521
+ `).join('')}
522
+ </div>
523
+ </div>
524
+ ` : '';
525
+
526
+ // Config source info
527
+ const configInfo = window.claudeCliToolsConfig?._configInfo || {};
528
+ const configSourceLabel = configInfo.source === 'project' ? 'Project' : configInfo.source === 'global' ? 'Global' : 'Default';
529
+ const configSourceClass = configInfo.source === 'project' ? 'text-success' : configInfo.source === 'global' ? 'text-primary' : 'text-muted-foreground';
530
+
313
531
  // CLI Settings section
314
532
  const settingsHtml = `
315
533
  <div class="cli-settings-section">
316
534
  <div class="cli-settings-header">
317
535
  <h4><i data-lucide="settings" class="w-3.5 h-3.5"></i> Settings</h4>
536
+ <span class="badge text-xs ${configSourceClass}" title="${configInfo.activePath || ''}">${configSourceLabel}</span>
318
537
  </div>
319
538
  <div class="cli-settings-grid">
320
539
  <div class="cli-setting-item">
@@ -381,6 +600,20 @@ function renderCliStatus() {
381
600
  </div>
382
601
  <p class="cli-setting-desc">Maximum files to include in smart context</p>
383
602
  </div>
603
+ <div class="cli-setting-item">
604
+ <label class="cli-setting-label">
605
+ <i data-lucide="hard-drive" class="w-3 h-3"></i>
606
+ Cache Injection
607
+ </label>
608
+ <div class="cli-setting-control">
609
+ <select class="cli-setting-select" onchange="setCacheInjectionMode(this.value)">
610
+ <option value="auto" ${getCacheInjectionMode() === 'auto' ? 'selected' : ''}>Auto</option>
611
+ <option value="manual" ${getCacheInjectionMode() === 'manual' ? 'selected' : ''}>Manual</option>
612
+ <option value="disabled" ${getCacheInjectionMode() === 'disabled' ? 'selected' : ''}>Disabled</option>
613
+ </select>
614
+ </div>
615
+ <p class="cli-setting-desc">Cache prefix/suffix injection mode for prompts</p>
616
+ </div>
384
617
  </div>
385
618
  </div>
386
619
  `;
@@ -392,11 +625,13 @@ function renderCliStatus() {
392
625
  <i data-lucide="refresh-cw" class="w-4 h-4"></i>
393
626
  </button>
394
627
  </div>
628
+ ${ccwInstallHtml}
395
629
  <div class="cli-tools-grid">
396
630
  ${toolsHtml}
397
631
  ${codexLensHtml}
398
632
  ${semanticHtml}
399
633
  </div>
634
+ ${apiEndpointsHtml}
400
635
  ${settingsHtml}
401
636
  `;
402
637
 
@@ -408,7 +643,30 @@ function renderCliStatus() {
408
643
 
409
644
  // ========== Actions ==========
410
645
  function setDefaultCliTool(tool) {
646
+ // Validate: tool must be available and enabled
647
+ const status = cliToolStatus[tool] || {};
648
+ const config = cliToolsConfig[tool] || { enabled: true };
649
+
650
+ if (!status.available) {
651
+ showRefreshToast(`Cannot set ${tool} as default: not installed`, 'error');
652
+ return;
653
+ }
654
+
655
+ if (config.enabled === false) {
656
+ showRefreshToast(`Cannot set ${tool} as default: tool is disabled`, 'error');
657
+ return;
658
+ }
659
+
411
660
  defaultCliTool = tool;
661
+ // Save to config
662
+ if (window.claudeCliToolsConfig) {
663
+ window.claudeCliToolsConfig.defaultTool = tool;
664
+ fetch('/api/cli/tools-config', {
665
+ method: 'PUT',
666
+ headers: { 'Content-Type': 'application/json' },
667
+ body: JSON.stringify({ defaultTool: tool })
668
+ }).catch(err => console.error('Failed to save default tool:', err));
669
+ }
412
670
  renderCliStatus();
413
671
  showRefreshToast(`Default CLI tool set to ${tool}`, 'success');
414
672
  }
@@ -449,11 +707,67 @@ function setRecursiveQueryEnabled(enabled) {
449
707
  showRefreshToast(`Recursive Query ${enabled ? 'enabled' : 'disabled'}`, 'success');
450
708
  }
451
709
 
710
+ function getCacheInjectionMode() {
711
+ if (window.claudeCliToolsConfig && window.claudeCliToolsConfig.settings) {
712
+ return window.claudeCliToolsConfig.settings.cache?.injectionMode || 'auto';
713
+ }
714
+ return localStorage.getItem('ccw-cache-injection-mode') || 'auto';
715
+ }
716
+
717
+ async function setCacheInjectionMode(mode) {
718
+ try {
719
+ const response = await fetch('/api/cli/tools-config/cache', {
720
+ method: 'PUT',
721
+ headers: { 'Content-Type': 'application/json' },
722
+ body: JSON.stringify({ injectionMode: mode })
723
+ });
724
+ if (response.ok) {
725
+ localStorage.setItem('ccw-cache-injection-mode', mode);
726
+ if (window.claudeCliToolsConfig) {
727
+ window.claudeCliToolsConfig.settings.cache.injectionMode = mode;
728
+ }
729
+ showRefreshToast(`Cache injection mode set to ${mode}`, 'success');
730
+ } else {
731
+ showRefreshToast('Failed to update cache settings', 'error');
732
+ }
733
+ } catch (err) {
734
+ console.error('Failed to update cache settings:', err);
735
+ showRefreshToast('Failed to update cache settings', 'error');
736
+ }
737
+ }
738
+
452
739
  async function refreshAllCliStatus() {
453
740
  await loadAllStatuses();
454
741
  renderCliStatus();
455
742
  }
456
743
 
744
+ async function toggleCliTool(tool, enabled) {
745
+ // If disabling the current default tool, switch to another available+enabled tool
746
+ if (!enabled && defaultCliTool === tool) {
747
+ const tools = ['gemini', 'qwen', 'codex', 'claude'];
748
+ const newDefault = tools.find(t => {
749
+ if (t === tool) return false;
750
+ const status = cliToolStatus[t] || {};
751
+ const config = cliToolsConfig[t] || { enabled: true };
752
+ return status.available && config.enabled !== false;
753
+ });
754
+
755
+ if (newDefault) {
756
+ defaultCliTool = newDefault;
757
+ if (window.claudeCliToolsConfig) {
758
+ window.claudeCliToolsConfig.defaultTool = newDefault;
759
+ }
760
+ showRefreshToast(`Default tool switched to ${newDefault}`, 'info');
761
+ } else {
762
+ showRefreshToast(`Warning: No other enabled tool available for default`, 'warning');
763
+ }
764
+ }
765
+
766
+ await updateCliToolEnabled(tool, enabled);
767
+ await loadAllStatuses();
768
+ renderCliStatus();
769
+ }
770
+
457
771
  function installCodexLens() {
458
772
  openCodexLensInstallWizard();
459
773
  }