claude-code-workflow 6.3.37 → 6.3.39

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 (173) hide show
  1. package/.claude/commands/workflow/lite-execute.md +2 -0
  2. package/.codex/agents/action-planning-agent.md +885 -0
  3. package/.codex/agents/ccw-loop-b-complete.md +227 -0
  4. package/.codex/agents/ccw-loop-b-debug.md +172 -0
  5. package/.codex/agents/ccw-loop-b-develop.md +147 -0
  6. package/.codex/agents/ccw-loop-b-init.md +82 -0
  7. package/.codex/agents/ccw-loop-b-validate.md +204 -0
  8. package/.codex/agents/ccw-loop-executor.md +260 -0
  9. package/.codex/agents/cli-discuss-agent.md +391 -0
  10. package/.codex/agents/cli-execution-agent.md +333 -0
  11. package/.codex/agents/cli-explore-agent.md +186 -0
  12. package/.codex/agents/cli-lite-planning-agent.md +736 -0
  13. package/.codex/agents/cli-planning-agent.md +562 -0
  14. package/.codex/agents/code-developer.md +408 -0
  15. package/.codex/agents/conceptual-planning-agent.md +321 -0
  16. package/.codex/agents/context-search-agent.md +585 -0
  17. package/.codex/agents/debug-explore-agent.md +436 -0
  18. package/.codex/agents/doc-generator.md +334 -0
  19. package/.codex/agents/issue-plan-agent.md +417 -0
  20. package/.codex/agents/issue-queue-agent.md +311 -0
  21. package/.codex/agents/memory-bridge.md +96 -0
  22. package/.codex/agents/test-context-search-agent.md +402 -0
  23. package/.codex/agents/test-fix-agent.md +359 -0
  24. package/.codex/agents/ui-design-agent.md +595 -0
  25. package/.codex/agents/universal-executor.md +135 -0
  26. package/.codex/prompts/clean.md +409 -0
  27. package/.codex/prompts/issue-discover-by-prompt.md +364 -0
  28. package/.codex/prompts/issue-discover.md +261 -0
  29. package/.codex/prompts/issue-execute.md +10 -0
  30. package/.codex/prompts/issue-new.md +285 -0
  31. package/.codex/prompts/issue-plan.md +161 -63
  32. package/.codex/prompts/issue-queue.md +298 -288
  33. package/.codex/prompts/lite-execute.md +627 -133
  34. package/.codex/prompts/lite-fix.md +670 -0
  35. package/.codex/prompts/lite-plan-a.md +337 -0
  36. package/.codex/prompts/lite-plan-b.md +485 -0
  37. package/.codex/prompts/{lite-plan.md → lite-plan-c.md} +601 -469
  38. package/.codex/skills/ccw-loop/README.md +171 -0
  39. package/.codex/skills/ccw-loop/SKILL.md +349 -0
  40. package/.codex/skills/ccw-loop/phases/actions/action-complete.md +269 -0
  41. package/.codex/skills/ccw-loop/phases/actions/action-debug.md +286 -0
  42. package/.codex/skills/ccw-loop/phases/actions/action-develop.md +183 -0
  43. package/.codex/skills/ccw-loop/phases/actions/action-init.md +164 -0
  44. package/.codex/skills/ccw-loop/phases/actions/action-menu.md +205 -0
  45. package/.codex/skills/ccw-loop/phases/actions/action-validate.md +250 -0
  46. package/.codex/skills/ccw-loop/phases/orchestrator.md +416 -0
  47. package/.codex/skills/ccw-loop/phases/state-schema.md +388 -0
  48. package/.codex/skills/ccw-loop/specs/action-catalog.md +182 -0
  49. package/.codex/skills/ccw-loop-b/README.md +301 -0
  50. package/.codex/skills/ccw-loop-b/SKILL.md +322 -0
  51. package/.codex/skills/ccw-loop-b/phases/orchestrator.md +257 -0
  52. package/.codex/skills/ccw-loop-b/phases/state-schema.md +181 -0
  53. package/.codex/skills/ccw-loop-b/specs/action-catalog.md +383 -0
  54. package/.codex/skills/parallel-dev-cycle/README.md +382 -0
  55. package/.codex/skills/parallel-dev-cycle/SKILL.md +512 -0
  56. package/.codex/skills/parallel-dev-cycle/phases/agents/code-developer.md +242 -0
  57. package/.codex/skills/parallel-dev-cycle/phases/agents/exploration-planner.md +285 -0
  58. package/.codex/skills/parallel-dev-cycle/phases/agents/requirements-analyst.md +285 -0
  59. package/.codex/skills/parallel-dev-cycle/phases/agents/validation-archivist.md +381 -0
  60. package/.codex/skills/parallel-dev-cycle/phases/orchestrator.md +696 -0
  61. package/.codex/skills/parallel-dev-cycle/phases/state-schema.md +436 -0
  62. package/.codex/skills/parallel-dev-cycle/specs/communication-optimization.md +423 -0
  63. package/.codex/skills/parallel-dev-cycle/specs/coordination-protocol.md +391 -0
  64. package/.codex/skills/parallel-dev-cycle/specs/versioning-strategy.md +330 -0
  65. package/ccw/dist/cli.d.ts.map +1 -1
  66. package/ccw/dist/cli.js +4 -0
  67. package/ccw/dist/cli.js.map +1 -1
  68. package/ccw/dist/commands/install.d.ts.map +1 -1
  69. package/ccw/dist/commands/install.js +39 -8
  70. package/ccw/dist/commands/install.js.map +1 -1
  71. package/ccw/dist/commands/issue.d.ts +3 -0
  72. package/ccw/dist/commands/issue.d.ts.map +1 -1
  73. package/ccw/dist/commands/issue.js +107 -0
  74. package/ccw/dist/commands/issue.js.map +1 -1
  75. package/ccw/dist/commands/upgrade.js +1 -1
  76. package/ccw/dist/commands/upgrade.js.map +1 -1
  77. package/ccw/dist/config/litellm-api-config-manager.d.ts.map +1 -1
  78. package/ccw/dist/config/litellm-api-config-manager.js +3 -2
  79. package/ccw/dist/config/litellm-api-config-manager.js.map +1 -1
  80. package/ccw/dist/core/memory-embedder-bridge.d.ts.map +1 -1
  81. package/ccw/dist/core/memory-embedder-bridge.js +2 -5
  82. package/ccw/dist/core/memory-embedder-bridge.js.map +1 -1
  83. package/ccw/dist/core/routes/cli-routes.js.map +1 -1
  84. package/ccw/dist/core/routes/codexlens/config-handlers.d.ts.map +1 -1
  85. package/ccw/dist/core/routes/codexlens/config-handlers.js +7 -6
  86. package/ccw/dist/core/routes/codexlens/config-handlers.js.map +1 -1
  87. package/ccw/dist/core/routes/codexlens/semantic-handlers.d.ts.map +1 -1
  88. package/ccw/dist/core/routes/codexlens/semantic-handlers.js +2 -2
  89. package/ccw/dist/core/routes/codexlens/semantic-handlers.js.map +1 -1
  90. package/ccw/dist/core/routes/graph-routes.d.ts.map +1 -1
  91. package/ccw/dist/core/routes/graph-routes.js +17 -2
  92. package/ccw/dist/core/routes/graph-routes.js.map +1 -1
  93. package/ccw/dist/core/routes/issue-routes.d.ts.map +1 -1
  94. package/ccw/dist/core/routes/issue-routes.js +280 -33
  95. package/ccw/dist/core/routes/issue-routes.js.map +1 -1
  96. package/ccw/dist/core/routes/loop-v2-routes.d.ts +9 -0
  97. package/ccw/dist/core/routes/loop-v2-routes.d.ts.map +1 -1
  98. package/ccw/dist/core/routes/loop-v2-routes.js +56 -4
  99. package/ccw/dist/core/routes/loop-v2-routes.js.map +1 -1
  100. package/ccw/dist/core/routes/system-routes.d.ts.map +1 -1
  101. package/ccw/dist/core/routes/system-routes.js +3 -2
  102. package/ccw/dist/core/routes/system-routes.js.map +1 -1
  103. package/ccw/dist/core/server.d.ts.map +1 -1
  104. package/ccw/dist/core/server.js +5 -3
  105. package/ccw/dist/core/server.js.map +1 -1
  106. package/ccw/dist/tools/claude-cli-tools.d.ts.map +1 -1
  107. package/ccw/dist/tools/claude-cli-tools.js +4 -3
  108. package/ccw/dist/tools/claude-cli-tools.js.map +1 -1
  109. package/ccw/dist/tools/cli-config-manager.d.ts +1 -0
  110. package/ccw/dist/tools/cli-config-manager.d.ts.map +1 -1
  111. package/ccw/dist/tools/cli-config-manager.js +2 -1
  112. package/ccw/dist/tools/cli-config-manager.js.map +1 -1
  113. package/ccw/dist/tools/codex-lens-lsp.d.ts.map +1 -1
  114. package/ccw/dist/tools/codex-lens-lsp.js +2 -5
  115. package/ccw/dist/tools/codex-lens-lsp.js.map +1 -1
  116. package/ccw/dist/tools/codex-lens.d.ts.map +1 -1
  117. package/ccw/dist/tools/codex-lens.js +22 -32
  118. package/ccw/dist/tools/codex-lens.js.map +1 -1
  119. package/ccw/dist/tools/litellm-client.d.ts +6 -0
  120. package/ccw/dist/tools/litellm-client.d.ts.map +1 -1
  121. package/ccw/dist/tools/litellm-client.js +15 -2
  122. package/ccw/dist/tools/litellm-client.js.map +1 -1
  123. package/ccw/dist/tools/loop-task-manager.d.ts +13 -2
  124. package/ccw/dist/tools/loop-task-manager.d.ts.map +1 -1
  125. package/ccw/dist/tools/loop-task-manager.js.map +1 -1
  126. package/ccw/dist/tools/native-session-discovery.d.ts.map +1 -1
  127. package/ccw/dist/tools/native-session-discovery.js +35 -7
  128. package/ccw/dist/tools/native-session-discovery.js.map +1 -1
  129. package/ccw/dist/utils/codexlens-path.d.ts +36 -0
  130. package/ccw/dist/utils/codexlens-path.d.ts.map +1 -0
  131. package/ccw/dist/utils/codexlens-path.js +56 -0
  132. package/ccw/dist/utils/codexlens-path.js.map +1 -0
  133. package/ccw/dist/utils/uv-manager.d.ts.map +1 -1
  134. package/ccw/dist/utils/uv-manager.js +3 -2
  135. package/ccw/dist/utils/uv-manager.js.map +1 -1
  136. package/ccw/src/cli.ts +4 -0
  137. package/ccw/src/commands/install.ts +51 -8
  138. package/ccw/src/commands/issue.ts +119 -0
  139. package/ccw/src/commands/upgrade.ts +1 -1
  140. package/ccw/src/config/litellm-api-config-manager.ts +3 -2
  141. package/ccw/src/core/memory-embedder-bridge.ts +2 -6
  142. package/ccw/src/core/routes/cli-routes.ts +1 -1
  143. package/ccw/src/core/routes/codexlens/config-handlers.ts +7 -6
  144. package/ccw/src/core/routes/codexlens/semantic-handlers.ts +2 -2
  145. package/ccw/src/core/routes/graph-routes.ts +18 -2
  146. package/ccw/src/core/routes/issue-routes.ts +308 -33
  147. package/ccw/src/core/routes/loop-v2-routes.ts +64 -6
  148. package/ccw/src/core/routes/system-routes.ts +3 -2
  149. package/ccw/src/core/server.ts +6 -3
  150. package/ccw/src/templates/dashboard-css/02-session.css +2 -0
  151. package/ccw/src/templates/dashboard-css/04-lite-tasks.css +103 -1
  152. package/ccw/src/templates/dashboard-css/32-issue-manager.css +32 -0
  153. package/ccw/src/templates/dashboard-js/components/cli-history.js +48 -48
  154. package/ccw/src/templates/dashboard-js/components/navigation.js +6 -0
  155. package/ccw/src/templates/dashboard-js/components/notifications.js +6 -0
  156. package/ccw/src/templates/dashboard-js/components/version-check.js +38 -0
  157. package/ccw/src/templates/dashboard-js/i18n.js +126 -0
  158. package/ccw/src/templates/dashboard-js/state.js +2 -0
  159. package/ccw/src/templates/dashboard-js/views/cli-manager.js +1 -1
  160. package/ccw/src/templates/dashboard-js/views/issue-manager.js +183 -1
  161. package/ccw/src/templates/dashboard-js/views/lite-tasks.js +55 -11
  162. package/ccw/src/templates/dashboard-js/views/loop-monitor.js +112 -11
  163. package/ccw/src/templates/dashboard.html +48 -2
  164. package/ccw/src/tools/claude-cli-tools.ts +4 -3
  165. package/ccw/src/tools/cli-config-manager.ts +3 -1
  166. package/ccw/src/tools/codex-lens-lsp.ts +2 -5
  167. package/ccw/src/tools/codex-lens.ts +27 -38
  168. package/ccw/src/tools/litellm-client.ts +16 -2
  169. package/ccw/src/tools/loop-task-manager.ts +13 -2
  170. package/ccw/src/tools/native-session-discovery.ts +38 -7
  171. package/ccw/src/utils/codexlens-path.ts +60 -0
  172. package/ccw/src/utils/uv-manager.ts +3 -2
  173. package/package.json +1 -1
@@ -278,6 +278,50 @@
278
278
  display: block;
279
279
  animation: spin 1s linear infinite;
280
280
  }
281
+ .check-icon-loading {
282
+ display: none;
283
+ }
284
+
285
+ /* Version Badge */
286
+ .version-badge {
287
+ display: none;
288
+ position: absolute;
289
+ top: -2px;
290
+ right: -2px;
291
+ min-width: 16px;
292
+ height: 16px;
293
+ padding: 0 4px;
294
+ background: hsl(var(--destructive));
295
+ color: white;
296
+ border-radius: 8px;
297
+ font-size: 0.625rem;
298
+ font-weight: 600;
299
+ align-items: center;
300
+ justify-content: center;
301
+ pointer-events: none;
302
+ z-index: 10;
303
+ }
304
+ .version-badge.has-update {
305
+ display: flex;
306
+ animation: badgePulse 2s ease-in-out infinite;
307
+ }
308
+ .version-badge.checking {
309
+ display: flex;
310
+ background: hsl(var(--muted) / 0.8);
311
+ }
312
+ .version-badge.checking::after {
313
+ content: '...';
314
+ animation: dots 1.5s steps(4, end) infinite;
315
+ }
316
+ @keyframes badgePulse {
317
+ 0%, 100% { transform: scale(1); }
318
+ 50% { transform: scale(1.15); }
319
+ }
320
+ @keyframes dots {
321
+ 0%, 20% { content: '.'; }
322
+ 40% { content: '..'; }
323
+ 60%, 100% { content: '...'; }
324
+ }
281
325
 
282
326
  /* Auto-Update Toggle Switch */
283
327
  .auto-update-switch {
@@ -390,7 +434,7 @@
390
434
  <!-- Auto-Update Controls -->
391
435
  <div class="flex items-center gap-2 border-l border-border pl-2">
392
436
  <!-- Check Now Button -->
393
- <button class="tooltip-bottom p-1.5 text-muted-foreground hover:text-foreground hover:bg-hover rounded" id="checkUpdateNow" data-tooltip="Check for updates now" onclick="checkForUpdatesNow()">
437
+ <button class="tooltip-bottom p-1.5 text-muted-foreground hover:text-foreground hover:bg-hover rounded relative" id="checkUpdateNow" data-tooltip="Check for updates now" onclick="checkForUpdatesNow()">
394
438
  <!-- Download Icon (default) -->
395
439
  <svg class="check-icon-default" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
396
440
  <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
@@ -398,9 +442,11 @@
398
442
  <line x1="12" y1="15" x2="12" y2="3"/>
399
443
  </svg>
400
444
  <!-- Loading Icon (checking state) -->
401
- <svg class="check-icon-loading hidden" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
445
+ <svg class="check-icon-loading" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
402
446
  <path d="M21 12a9 9 0 1 1-6.219-8.56"/>
403
447
  </svg>
448
+ <!-- Version Available Badge -->
449
+ <span class="version-badge" id="versionBadge"></span>
404
450
  </button>
405
451
  <!-- Auto-Update Toggle Switch -->
406
452
  <label class="tooltip-bottom auto-update-switch" data-tooltip="Auto-update">
@@ -268,7 +268,8 @@ function ensureToolTags(tool: Partial<ClaudeCliTool>): ClaudeCliTool {
268
268
  enabled: tool.enabled ?? true,
269
269
  primaryModel: tool.primaryModel,
270
270
  secondaryModel: tool.secondaryModel,
271
- tags: tool.tags ?? []
271
+ tags: tool.tags ?? [],
272
+ envFile: tool.envFile
272
273
  };
273
274
  }
274
275
 
@@ -438,9 +439,9 @@ export function loadClaudeCliTools(projectDir: string): ClaudeCliToolsConfig & {
438
439
  const migrated = migrateConfig(parsed, projectDir);
439
440
  const needsSave = migrated.version !== parsed.version;
440
441
 
441
- // Merge tools with defaults and ensure required fields exist
442
+ // Load user-configured tools only (defaults NOT merged)
442
443
  const mergedTools: Record<string, ClaudeCliTool> = {};
443
- for (const [key, tool] of Object.entries({ ...DEFAULT_TOOLS_CONFIG.tools, ...(migrated.tools || {}) })) {
444
+ for (const [key, tool] of Object.entries(migrated.tools || {})) {
444
445
  mergedTools[key] = {
445
446
  ...ensureToolTags(tool),
446
447
  type: tool.type ?? 'builtin',
@@ -29,6 +29,7 @@ export interface CliToolConfig {
29
29
  primaryModel: string;
30
30
  secondaryModel: string;
31
31
  tags?: string[];
32
+ envFile?: string | null;
32
33
  }
33
34
 
34
35
  export interface CliConfig {
@@ -184,7 +185,8 @@ export function getFullConfigResponse(baseDir: string): {
184
185
  enabled: tool.enabled,
185
186
  primaryModel: tool.primaryModel ?? '',
186
187
  secondaryModel: tool.secondaryModel ?? '',
187
- tags: tool.tags
188
+ tags: tool.tags,
189
+ envFile: tool.envFile
188
190
  };
189
191
  }
190
192
 
@@ -12,14 +12,11 @@ import { z } from 'zod';
12
12
  import type { ToolSchema, ToolResult } from '../types/tool.js';
13
13
  import { spawn } from 'child_process';
14
14
  import { join } from 'path';
15
- import { homedir } from 'os';
16
15
  import { getProjectRoot } from '../utils/path-validator.js';
16
+ import { getCodexLensPython } from '../utils/codexlens-path.js';
17
17
 
18
18
  // CodexLens venv configuration
19
- const CODEXLENS_VENV =
20
- process.platform === 'win32'
21
- ? join(homedir(), '.codexlens', 'venv', 'Scripts', 'python.exe')
22
- : join(homedir(), '.codexlens', 'venv', 'bin', 'python');
19
+ const CODEXLENS_VENV = getCodexLensPython();
23
20
 
24
21
  // Define Zod schema for validation
25
22
  const ParamsSchema = z.object({
@@ -24,6 +24,12 @@ import {
24
24
  isUvAvailable,
25
25
  createCodexLensUvManager,
26
26
  } from '../utils/uv-manager.js';
27
+ import {
28
+ getCodexLensDataDir,
29
+ getCodexLensVenvDir,
30
+ getCodexLensPython,
31
+ getCodexLensPip,
32
+ } from '../utils/codexlens-path.js';
27
33
 
28
34
  // Get directory of this module
29
35
  const __filename = fileURLToPath(import.meta.url);
@@ -109,14 +115,6 @@ function findLocalCcwLitellmPath(): string | null {
109
115
  return findLocalPackagePath('ccw-litellm');
110
116
  }
111
117
 
112
- // CodexLens configuration
113
- const CODEXLENS_DATA_DIR = join(homedir(), '.codexlens');
114
- const CODEXLENS_VENV = join(CODEXLENS_DATA_DIR, 'venv');
115
- const VENV_PYTHON =
116
- process.platform === 'win32'
117
- ? join(CODEXLENS_VENV, 'Scripts', 'python.exe')
118
- : join(CODEXLENS_VENV, 'bin', 'python');
119
-
120
118
  // Bootstrap status cache
121
119
  let bootstrapChecked = false;
122
120
  let bootstrapReady = false;
@@ -245,7 +243,7 @@ async function checkVenvStatus(force = false): Promise<ReadyStatus> {
245
243
  }
246
244
 
247
245
  // Check venv exists
248
- if (!existsSync(CODEXLENS_VENV)) {
246
+ if (!existsSync(getCodexLensVenvDir())) {
249
247
  const result = { ready: false, error: 'Venv not found' };
250
248
  venvStatusCache = { status: result, timestamp: Date.now() };
251
249
  console.log(`[PERF][CodexLens] checkVenvStatus (no venv): ${Date.now() - funcStart}ms`);
@@ -253,7 +251,7 @@ async function checkVenvStatus(force = false): Promise<ReadyStatus> {
253
251
  }
254
252
 
255
253
  // Check python executable exists
256
- if (!existsSync(VENV_PYTHON)) {
254
+ if (!existsSync(getCodexLensPython())) {
257
255
  const result = { ready: false, error: 'Python executable not found in venv' };
258
256
  venvStatusCache = { status: result, timestamp: Date.now() };
259
257
  console.log(`[PERF][CodexLens] checkVenvStatus (no python): ${Date.now() - funcStart}ms`);
@@ -265,7 +263,7 @@ async function checkVenvStatus(force = false): Promise<ReadyStatus> {
265
263
  console.log('[PERF][CodexLens] checkVenvStatus spawning Python...');
266
264
 
267
265
  return new Promise((resolve) => {
268
- const child = spawn(VENV_PYTHON, ['-c', 'import codexlens; import watchdog; print(codexlens.__version__)'], {
266
+ const child = spawn(getCodexLensPython(), ['-c', 'import codexlens; import watchdog; print(codexlens.__version__)'], {
269
267
  stdio: ['ignore', 'pipe', 'pipe'],
270
268
  timeout: 10000,
271
269
  });
@@ -377,7 +375,7 @@ try:
377
375
  except Exception as e:
378
376
  print(json.dumps({"available": False, "error": str(e)}))
379
377
  `;
380
- const child = spawn(VENV_PYTHON, ['-c', checkCode], {
378
+ const child = spawn(getCodexLensPython(), ['-c', checkCode], {
381
379
  stdio: ['ignore', 'pipe', 'pipe'],
382
380
  timeout: 15000,
383
381
  });
@@ -438,7 +436,7 @@ async function ensureLiteLLMEmbedderReady(): Promise<BootstrapResult> {
438
436
 
439
437
  // Check if ccw_litellm can be imported
440
438
  const importStatus = await new Promise<{ ok: boolean; error?: string }>((resolve) => {
441
- const child = spawn(VENV_PYTHON, ['-c', 'import ccw_litellm; print("OK")'], {
439
+ const child = spawn(getCodexLensPython(), ['-c', 'import ccw_litellm; print("OK")'], {
442
440
  stdio: ['ignore', 'pipe', 'pipe'],
443
441
  timeout: 15000,
444
442
  });
@@ -502,10 +500,7 @@ async function ensureLiteLLMEmbedderReady(): Promise<BootstrapResult> {
502
500
  }
503
501
 
504
502
  // Fallback: Use pip for installation
505
- const pipPath =
506
- process.platform === 'win32'
507
- ? join(CODEXLENS_VENV, 'Scripts', 'pip.exe')
508
- : join(CODEXLENS_VENV, 'bin', 'pip');
503
+ const pipPath = getCodexLensPip();
509
504
 
510
505
  try {
511
506
  if (localPath) {
@@ -552,10 +547,7 @@ interface PythonEnvInfo {
552
547
  * DirectML requires: 64-bit Python, version 3.8-3.12
553
548
  */
554
549
  async function checkPythonEnvForDirectML(): Promise<PythonEnvInfo> {
555
- const pythonPath =
556
- process.platform === 'win32'
557
- ? join(CODEXLENS_VENV, 'Scripts', 'python.exe')
558
- : join(CODEXLENS_VENV, 'bin', 'python');
550
+ const pythonPath = getCodexLensPython();
559
551
 
560
552
  if (!existsSync(pythonPath)) {
561
553
  return { version: '', majorMinor: '', architecture: 0, compatible: false, error: 'Python not found in venv' };
@@ -800,10 +792,7 @@ async function installSemantic(gpuMode: GpuMode = 'cpu'): Promise<BootstrapResul
800
792
  console.log(`[CodexLens] Python ${pythonEnv.version} (${pythonEnv.architecture}-bit) - DirectML compatible`);
801
793
  }
802
794
 
803
- const pipPath =
804
- process.platform === 'win32'
805
- ? join(CODEXLENS_VENV, 'Scripts', 'pip.exe')
806
- : join(CODEXLENS_VENV, 'bin', 'pip');
795
+ const pipPath = getCodexLensPip();
807
796
 
808
797
  // IMPORTANT: Uninstall all onnxruntime variants first to prevent conflicts
809
798
  // Having multiple onnxruntime packages causes provider detection issues
@@ -933,16 +922,18 @@ async function bootstrapVenv(): Promise<BootstrapResult> {
933
922
 
934
923
  // Fall back to pip logic...
935
924
  // Ensure data directory exists
936
- if (!existsSync(CODEXLENS_DATA_DIR)) {
937
- mkdirSync(CODEXLENS_DATA_DIR, { recursive: true });
925
+ const dataDir = getCodexLensDataDir();
926
+ const venvDir = getCodexLensVenvDir();
927
+ if (!existsSync(dataDir)) {
928
+ mkdirSync(dataDir, { recursive: true });
938
929
  }
939
930
 
940
931
  // Create venv if not exists
941
- if (!existsSync(CODEXLENS_VENV)) {
932
+ if (!existsSync(venvDir)) {
942
933
  try {
943
934
  console.log('[CodexLens] Creating virtual environment...');
944
935
  const pythonCmd = getSystemPython();
945
- execSync(`${pythonCmd} -m venv "${CODEXLENS_VENV}"`, { stdio: 'inherit', timeout: EXEC_TIMEOUTS.PROCESS_SPAWN });
936
+ execSync(`${pythonCmd} -m venv "${venvDir}"`, { stdio: 'inherit', timeout: EXEC_TIMEOUTS.PROCESS_SPAWN });
946
937
  } catch (err) {
947
938
  return { success: false, error: `Failed to create venv: ${(err as Error).message}` };
948
939
  }
@@ -951,10 +942,7 @@ async function bootstrapVenv(): Promise<BootstrapResult> {
951
942
  // Install codex-lens
952
943
  try {
953
944
  console.log('[CodexLens] Installing codex-lens package...');
954
- const pipPath =
955
- process.platform === 'win32'
956
- ? join(CODEXLENS_VENV, 'Scripts', 'pip.exe')
957
- : join(CODEXLENS_VENV, 'bin', 'pip');
945
+ const pipPath = getCodexLensPip();
958
946
 
959
947
  // Try local path - codex-lens is local-only, not published to PyPI
960
948
  const codexLensPath = findLocalCodexLensPath();
@@ -1131,7 +1119,7 @@ async function executeCodexLens(args: string[], options: ExecuteOptions = {}): P
1131
1119
  // spawn's cwd option handles drive changes correctly on Windows
1132
1120
  const spawnArgs = ['-m', 'codexlens', ...args];
1133
1121
 
1134
- const child = spawn(VENV_PYTHON, spawnArgs, {
1122
+ const child = spawn(getCodexLensPython(), spawnArgs, {
1135
1123
  cwd,
1136
1124
  shell: false, // CRITICAL: Prevent command injection
1137
1125
  timeout,
@@ -1674,7 +1662,7 @@ export async function handler(params: Record<string, unknown>): Promise<ToolResu
1674
1662
  async function uninstallCodexLens(): Promise<BootstrapResult> {
1675
1663
  try {
1676
1664
  // Check if venv exists
1677
- if (!existsSync(CODEXLENS_VENV)) {
1665
+ if (!existsSync(getCodexLensVenvDir())) {
1678
1666
  return { success: false, error: 'CodexLens not installed (venv not found)' };
1679
1667
  }
1680
1668
 
@@ -1694,7 +1682,8 @@ async function uninstallCodexLens(): Promise<BootstrapResult> {
1694
1682
  await new Promise(resolve => setTimeout(resolve, 500));
1695
1683
  }
1696
1684
 
1697
- console.log(`[CodexLens] Removing directory: ${CODEXLENS_DATA_DIR}`);
1685
+ const dataDir = getCodexLensDataDir();
1686
+ console.log(`[CodexLens] Removing directory: ${dataDir}`);
1698
1687
 
1699
1688
  // Remove the entire .codexlens directory with retry logic for locked files
1700
1689
  const fs = await import('fs');
@@ -1729,7 +1718,7 @@ async function uninstallCodexLens(): Promise<BootstrapResult> {
1729
1718
  }
1730
1719
  };
1731
1720
 
1732
- await removeWithRetry(CODEXLENS_DATA_DIR);
1721
+ await removeWithRetry(dataDir);
1733
1722
 
1734
1723
  // Reset bootstrap cache
1735
1724
  bootstrapChecked = false;
@@ -1827,7 +1816,7 @@ export {
1827
1816
 
1828
1817
  // Export Python path for direct spawn usage (e.g., watcher)
1829
1818
  export function getVenvPythonPath(): string {
1830
- return VENV_PYTHON;
1819
+ return getCodexLensPython();
1831
1820
  }
1832
1821
 
1833
1822
  export type { GpuMode, PythonEnvInfo };
@@ -12,7 +12,7 @@
12
12
  import { spawn } from 'child_process';
13
13
  import { existsSync } from 'fs';
14
14
  import { join } from 'path';
15
- import { homedir } from 'os';
15
+ import { getCodexLensPython, getCodexLensVenvDir } from '../utils/codexlens-path.js';
16
16
 
17
17
  export interface LiteLLMConfig {
18
18
  pythonPath?: string; // Default: CodexLens venv Python
@@ -22,7 +22,7 @@ export interface LiteLLMConfig {
22
22
 
23
23
  // Platform-specific constants for CodexLens venv
24
24
  const IS_WINDOWS = process.platform === 'win32';
25
- const CODEXLENS_VENV = join(homedir(), '.codexlens', 'venv');
25
+ const CODEXLENS_VENV = getCodexLensVenvDir();
26
26
  const VENV_BIN_DIR = IS_WINDOWS ? 'Scripts' : 'bin';
27
27
  const PYTHON_EXECUTABLE = IS_WINDOWS ? 'python.exe' : 'python';
28
28
 
@@ -40,6 +40,20 @@ export function getCodexLensVenvPython(): string {
40
40
  return 'python';
41
41
  }
42
42
 
43
+ /**
44
+ * Get the Python path from CodexLens venv using centralized path utility
45
+ * Falls back to system 'python' if venv doesn't exist
46
+ * @returns Path to Python executable
47
+ */
48
+ export function getCodexLensPythonPath(): string {
49
+ const codexLensPython = getCodexLensPython();
50
+ if (existsSync(codexLensPython)) {
51
+ return codexLensPython;
52
+ }
53
+ // Fallback to system Python if venv not available
54
+ return 'python';
55
+ }
56
+
43
57
  export interface ChatMessage {
44
58
  role: 'system' | 'user' | 'assistant';
45
59
  content: string;
@@ -22,8 +22,19 @@ export interface LoopTask {
22
22
  /** Task description (what to do) */
23
23
  description: string;
24
24
 
25
- /** CLI tool to use */
26
- tool: 'bash' | 'gemini' | 'codex' | 'qwen' | 'claude';
25
+ /**
26
+ * CLI tool to use
27
+ *
28
+ * Should be one of the enabled tools from cli-tools.json:
29
+ * - 'bash' (always available)
30
+ * - Builtin tools: 'gemini', 'qwen', 'codex', 'claude', 'opencode'
31
+ * - CLI wrappers: 'doubao', etc. (if enabled)
32
+ * - API endpoints: custom tools (if enabled)
33
+ *
34
+ * Note: Validation is performed at the API layer (loop-v2-routes.ts)
35
+ * to ensure tool is enabled before saving.
36
+ */
37
+ tool: string;
27
38
 
28
39
  /** Execution mode */
29
40
  mode: 'analysis' | 'write' | 'review';
@@ -232,6 +232,19 @@ function encodeQwenProjectPath(projectDir: string): string {
232
232
  .replace(/_/g, '-');
233
233
  }
234
234
 
235
+ /**
236
+ * Encode a path to Claude Code's project folder name format
237
+ * D:\Claude_dms3 -> D--Claude-dms3 (same as Qwen)
238
+ * Rules: : -> -, \ -> -, _ -> -
239
+ */
240
+ function encodeClaudeProjectPath(projectDir: string): string {
241
+ const absolutePath = resolve(projectDir);
242
+ return absolutePath
243
+ .replace(/:/g, '-')
244
+ .replace(/\\/g, '-')
245
+ .replace(/_/g, '-');
246
+ }
247
+
235
248
  /**
236
249
  * Qwen Session Discoverer
237
250
  * New path: ~/.qwen/projects/<path-encoded>/chats/<uuid>.jsonl
@@ -576,9 +589,10 @@ class ClaudeSessionDiscoverer extends SessionDiscoverer {
576
589
  // If workingDir provided, only look in that project's folder
577
590
  let projectDirs: string[];
578
591
  if (workingDir) {
579
- const projectHash = calculateProjectHash(workingDir);
580
- const projectPath = join(this.basePath, projectHash);
581
- projectDirs = existsSync(projectPath) ? [projectHash] : [];
592
+ // Claude Code uses path encoding (D:\path -> D--path) not SHA256 hash
593
+ const encodedPath = encodeClaudeProjectPath(workingDir);
594
+ const projectPath = join(this.basePath, encodedPath);
595
+ projectDirs = existsSync(projectPath) ? [encodedPath] : [];
582
596
  } else {
583
597
  projectDirs = readdirSync(this.basePath).filter(d => {
584
598
  const fullPath = join(this.basePath, d);
@@ -652,6 +666,7 @@ class ClaudeSessionDiscoverer extends SessionDiscoverer {
652
666
  /**
653
667
  * Extract first user message from Claude Code session file (.jsonl)
654
668
  * Format: {"type":"user","message":{"role":"user","content":"..."},"isMeta":false,...}
669
+ * Content can be: string | array of {type,text} | array of {type,source} etc.
655
670
  */
656
671
  extractFirstUserMessage(filePath: string): string | null {
657
672
  try {
@@ -661,14 +676,30 @@ class ClaudeSessionDiscoverer extends SessionDiscoverer {
661
676
  for (const line of lines) {
662
677
  try {
663
678
  const entry = JSON.parse(line);
664
- // Claude Code format: type="user", message.role="user", message.content="..."
679
+ // Claude Code format: type="user", message.role="user", message.content can be string or array
665
680
  // Skip meta messages and command messages
666
681
  if (entry.type === 'user' &&
667
682
  entry.message?.role === 'user' &&
668
683
  entry.message?.content &&
669
- !entry.isMeta &&
670
- !entry.message.content.startsWith('<command-')) {
671
- return entry.message.content;
684
+ !entry.isMeta) {
685
+
686
+ const msgContent = entry.message.content;
687
+
688
+ // Handle string content (simple case)
689
+ if (typeof msgContent === 'string') {
690
+ if (!msgContent.startsWith('<command-') && !msgContent.includes('<local-command')) {
691
+ return msgContent;
692
+ }
693
+ }
694
+ // Handle array content (can contain text, image, tool_result, etc.)
695
+ else if (Array.isArray(msgContent)) {
696
+ for (const item of msgContent) {
697
+ // Look for text items
698
+ if (item.type === 'text' && item.text) {
699
+ return item.text;
700
+ }
701
+ }
702
+ }
672
703
  }
673
704
  } catch { /* skip invalid lines */ }
674
705
  }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * CodexLens Path Utilities
3
+ *
4
+ * Provides centralized path resolution for CodexLens data directory,
5
+ * respecting the CODEXLENS_DATA_DIR environment variable.
6
+ *
7
+ * Priority order (matching Python implementation):
8
+ * 1. CODEXLENS_DATA_DIR environment variable
9
+ * 2. Default: ~/.codexlens
10
+ */
11
+
12
+ import { join } from 'path';
13
+ import { homedir } from 'os';
14
+
15
+ /**
16
+ * Get the CodexLens data directory.
17
+ * Respects CODEXLENS_DATA_DIR environment variable.
18
+ *
19
+ * @returns Path to CodexLens data directory
20
+ */
21
+ export function getCodexLensDataDir(): string {
22
+ const envOverride = process.env.CODEXLENS_DATA_DIR;
23
+ if (envOverride) {
24
+ return envOverride;
25
+ }
26
+ return join(homedir(), '.codexlens');
27
+ }
28
+
29
+ /**
30
+ * Get the CodexLens virtual environment path.
31
+ *
32
+ * @returns Path to CodexLens venv directory
33
+ */
34
+ export function getCodexLensVenvDir(): string {
35
+ return join(getCodexLensDataDir(), 'venv');
36
+ }
37
+
38
+ /**
39
+ * Get the Python executable path in the CodexLens venv.
40
+ *
41
+ * @returns Path to python executable
42
+ */
43
+ export function getCodexLensPython(): string {
44
+ const venvDir = getCodexLensVenvDir();
45
+ return process.platform === 'win32'
46
+ ? join(venvDir, 'Scripts', 'python.exe')
47
+ : join(venvDir, 'bin', 'python');
48
+ }
49
+
50
+ /**
51
+ * Get the pip executable path in the CodexLens venv.
52
+ *
53
+ * @returns Path to pip executable
54
+ */
55
+ export function getCodexLensPip(): string {
56
+ const venvDir = getCodexLensVenvDir();
57
+ return process.platform === 'win32'
58
+ ? join(venvDir, 'Scripts', 'pip.exe')
59
+ : join(venvDir, 'bin', 'pip');
60
+ }
@@ -14,6 +14,7 @@ import { existsSync, mkdirSync } from 'fs';
14
14
  import { join, dirname } from 'path';
15
15
  import { homedir, platform, arch } from 'os';
16
16
  import { EXEC_TIMEOUTS } from './exec-constants.js';
17
+ import { getCodexLensDataDir, getCodexLensVenvDir } from './codexlens-path.js';
17
18
 
18
19
  /**
19
20
  * Configuration for UvManager
@@ -767,9 +768,9 @@ export class UvManager {
767
768
  * @returns Configured UvManager instance
768
769
  */
769
770
  export function createCodexLensUvManager(dataDir?: string): UvManager {
770
- const baseDir = dataDir ?? join(homedir(), '.codexlens');
771
+ const baseDir = dataDir ?? getCodexLensDataDir();
771
772
  return new UvManager({
772
- venvPath: join(baseDir, 'venv'),
773
+ venvPath: getCodexLensVenvDir(),
773
774
  pythonVersion: '>=3.10,<3.13', // onnxruntime compatibility
774
775
  });
775
776
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-workflow",
3
- "version": "6.3.37",
3
+ "version": "6.3.39",
4
4
  "description": "JSON-driven multi-agent development framework with intelligent CLI orchestration (Gemini/Qwen/Codex), context-first architecture, and automated workflow execution",
5
5
  "type": "module",
6
6
  "main": "ccw/src/index.js",