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.
- package/.claude/commands/workflow/lite-execute.md +2 -0
- package/.codex/agents/action-planning-agent.md +885 -0
- package/.codex/agents/ccw-loop-b-complete.md +227 -0
- package/.codex/agents/ccw-loop-b-debug.md +172 -0
- package/.codex/agents/ccw-loop-b-develop.md +147 -0
- package/.codex/agents/ccw-loop-b-init.md +82 -0
- package/.codex/agents/ccw-loop-b-validate.md +204 -0
- package/.codex/agents/ccw-loop-executor.md +260 -0
- package/.codex/agents/cli-discuss-agent.md +391 -0
- package/.codex/agents/cli-execution-agent.md +333 -0
- package/.codex/agents/cli-explore-agent.md +186 -0
- package/.codex/agents/cli-lite-planning-agent.md +736 -0
- package/.codex/agents/cli-planning-agent.md +562 -0
- package/.codex/agents/code-developer.md +408 -0
- package/.codex/agents/conceptual-planning-agent.md +321 -0
- package/.codex/agents/context-search-agent.md +585 -0
- package/.codex/agents/debug-explore-agent.md +436 -0
- package/.codex/agents/doc-generator.md +334 -0
- package/.codex/agents/issue-plan-agent.md +417 -0
- package/.codex/agents/issue-queue-agent.md +311 -0
- package/.codex/agents/memory-bridge.md +96 -0
- package/.codex/agents/test-context-search-agent.md +402 -0
- package/.codex/agents/test-fix-agent.md +359 -0
- package/.codex/agents/ui-design-agent.md +595 -0
- package/.codex/agents/universal-executor.md +135 -0
- package/.codex/prompts/clean.md +409 -0
- package/.codex/prompts/issue-discover-by-prompt.md +364 -0
- package/.codex/prompts/issue-discover.md +261 -0
- package/.codex/prompts/issue-execute.md +10 -0
- package/.codex/prompts/issue-new.md +285 -0
- package/.codex/prompts/issue-plan.md +161 -63
- package/.codex/prompts/issue-queue.md +298 -288
- package/.codex/prompts/lite-execute.md +627 -133
- package/.codex/prompts/lite-fix.md +670 -0
- package/.codex/prompts/lite-plan-a.md +337 -0
- package/.codex/prompts/lite-plan-b.md +485 -0
- package/.codex/prompts/{lite-plan.md → lite-plan-c.md} +601 -469
- package/.codex/skills/ccw-loop/README.md +171 -0
- package/.codex/skills/ccw-loop/SKILL.md +349 -0
- package/.codex/skills/ccw-loop/phases/actions/action-complete.md +269 -0
- package/.codex/skills/ccw-loop/phases/actions/action-debug.md +286 -0
- package/.codex/skills/ccw-loop/phases/actions/action-develop.md +183 -0
- package/.codex/skills/ccw-loop/phases/actions/action-init.md +164 -0
- package/.codex/skills/ccw-loop/phases/actions/action-menu.md +205 -0
- package/.codex/skills/ccw-loop/phases/actions/action-validate.md +250 -0
- package/.codex/skills/ccw-loop/phases/orchestrator.md +416 -0
- package/.codex/skills/ccw-loop/phases/state-schema.md +388 -0
- package/.codex/skills/ccw-loop/specs/action-catalog.md +182 -0
- package/.codex/skills/ccw-loop-b/README.md +301 -0
- package/.codex/skills/ccw-loop-b/SKILL.md +322 -0
- package/.codex/skills/ccw-loop-b/phases/orchestrator.md +257 -0
- package/.codex/skills/ccw-loop-b/phases/state-schema.md +181 -0
- package/.codex/skills/ccw-loop-b/specs/action-catalog.md +383 -0
- package/.codex/skills/parallel-dev-cycle/README.md +382 -0
- package/.codex/skills/parallel-dev-cycle/SKILL.md +512 -0
- package/.codex/skills/parallel-dev-cycle/phases/agents/code-developer.md +242 -0
- package/.codex/skills/parallel-dev-cycle/phases/agents/exploration-planner.md +285 -0
- package/.codex/skills/parallel-dev-cycle/phases/agents/requirements-analyst.md +285 -0
- package/.codex/skills/parallel-dev-cycle/phases/agents/validation-archivist.md +381 -0
- package/.codex/skills/parallel-dev-cycle/phases/orchestrator.md +696 -0
- package/.codex/skills/parallel-dev-cycle/phases/state-schema.md +436 -0
- package/.codex/skills/parallel-dev-cycle/specs/communication-optimization.md +423 -0
- package/.codex/skills/parallel-dev-cycle/specs/coordination-protocol.md +391 -0
- package/.codex/skills/parallel-dev-cycle/specs/versioning-strategy.md +330 -0
- package/ccw/dist/cli.d.ts.map +1 -1
- package/ccw/dist/cli.js +4 -0
- package/ccw/dist/cli.js.map +1 -1
- package/ccw/dist/commands/install.d.ts.map +1 -1
- package/ccw/dist/commands/install.js +39 -8
- package/ccw/dist/commands/install.js.map +1 -1
- package/ccw/dist/commands/issue.d.ts +3 -0
- package/ccw/dist/commands/issue.d.ts.map +1 -1
- package/ccw/dist/commands/issue.js +107 -0
- package/ccw/dist/commands/issue.js.map +1 -1
- package/ccw/dist/commands/upgrade.js +1 -1
- package/ccw/dist/commands/upgrade.js.map +1 -1
- package/ccw/dist/config/litellm-api-config-manager.d.ts.map +1 -1
- package/ccw/dist/config/litellm-api-config-manager.js +3 -2
- package/ccw/dist/config/litellm-api-config-manager.js.map +1 -1
- package/ccw/dist/core/memory-embedder-bridge.d.ts.map +1 -1
- package/ccw/dist/core/memory-embedder-bridge.js +2 -5
- package/ccw/dist/core/memory-embedder-bridge.js.map +1 -1
- package/ccw/dist/core/routes/cli-routes.js.map +1 -1
- package/ccw/dist/core/routes/codexlens/config-handlers.d.ts.map +1 -1
- package/ccw/dist/core/routes/codexlens/config-handlers.js +7 -6
- package/ccw/dist/core/routes/codexlens/config-handlers.js.map +1 -1
- package/ccw/dist/core/routes/codexlens/semantic-handlers.d.ts.map +1 -1
- package/ccw/dist/core/routes/codexlens/semantic-handlers.js +2 -2
- package/ccw/dist/core/routes/codexlens/semantic-handlers.js.map +1 -1
- package/ccw/dist/core/routes/graph-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/graph-routes.js +17 -2
- package/ccw/dist/core/routes/graph-routes.js.map +1 -1
- package/ccw/dist/core/routes/issue-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/issue-routes.js +280 -33
- package/ccw/dist/core/routes/issue-routes.js.map +1 -1
- package/ccw/dist/core/routes/loop-v2-routes.d.ts +9 -0
- package/ccw/dist/core/routes/loop-v2-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/loop-v2-routes.js +56 -4
- package/ccw/dist/core/routes/loop-v2-routes.js.map +1 -1
- package/ccw/dist/core/routes/system-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/system-routes.js +3 -2
- package/ccw/dist/core/routes/system-routes.js.map +1 -1
- package/ccw/dist/core/server.d.ts.map +1 -1
- package/ccw/dist/core/server.js +5 -3
- package/ccw/dist/core/server.js.map +1 -1
- package/ccw/dist/tools/claude-cli-tools.d.ts.map +1 -1
- package/ccw/dist/tools/claude-cli-tools.js +4 -3
- package/ccw/dist/tools/claude-cli-tools.js.map +1 -1
- package/ccw/dist/tools/cli-config-manager.d.ts +1 -0
- package/ccw/dist/tools/cli-config-manager.d.ts.map +1 -1
- package/ccw/dist/tools/cli-config-manager.js +2 -1
- package/ccw/dist/tools/cli-config-manager.js.map +1 -1
- package/ccw/dist/tools/codex-lens-lsp.d.ts.map +1 -1
- package/ccw/dist/tools/codex-lens-lsp.js +2 -5
- package/ccw/dist/tools/codex-lens-lsp.js.map +1 -1
- package/ccw/dist/tools/codex-lens.d.ts.map +1 -1
- package/ccw/dist/tools/codex-lens.js +22 -32
- package/ccw/dist/tools/codex-lens.js.map +1 -1
- package/ccw/dist/tools/litellm-client.d.ts +6 -0
- package/ccw/dist/tools/litellm-client.d.ts.map +1 -1
- package/ccw/dist/tools/litellm-client.js +15 -2
- package/ccw/dist/tools/litellm-client.js.map +1 -1
- package/ccw/dist/tools/loop-task-manager.d.ts +13 -2
- package/ccw/dist/tools/loop-task-manager.d.ts.map +1 -1
- package/ccw/dist/tools/loop-task-manager.js.map +1 -1
- package/ccw/dist/tools/native-session-discovery.d.ts.map +1 -1
- package/ccw/dist/tools/native-session-discovery.js +35 -7
- package/ccw/dist/tools/native-session-discovery.js.map +1 -1
- package/ccw/dist/utils/codexlens-path.d.ts +36 -0
- package/ccw/dist/utils/codexlens-path.d.ts.map +1 -0
- package/ccw/dist/utils/codexlens-path.js +56 -0
- package/ccw/dist/utils/codexlens-path.js.map +1 -0
- package/ccw/dist/utils/uv-manager.d.ts.map +1 -1
- package/ccw/dist/utils/uv-manager.js +3 -2
- package/ccw/dist/utils/uv-manager.js.map +1 -1
- package/ccw/src/cli.ts +4 -0
- package/ccw/src/commands/install.ts +51 -8
- package/ccw/src/commands/issue.ts +119 -0
- package/ccw/src/commands/upgrade.ts +1 -1
- package/ccw/src/config/litellm-api-config-manager.ts +3 -2
- package/ccw/src/core/memory-embedder-bridge.ts +2 -6
- package/ccw/src/core/routes/cli-routes.ts +1 -1
- package/ccw/src/core/routes/codexlens/config-handlers.ts +7 -6
- package/ccw/src/core/routes/codexlens/semantic-handlers.ts +2 -2
- package/ccw/src/core/routes/graph-routes.ts +18 -2
- package/ccw/src/core/routes/issue-routes.ts +308 -33
- package/ccw/src/core/routes/loop-v2-routes.ts +64 -6
- package/ccw/src/core/routes/system-routes.ts +3 -2
- package/ccw/src/core/server.ts +6 -3
- package/ccw/src/templates/dashboard-css/02-session.css +2 -0
- package/ccw/src/templates/dashboard-css/04-lite-tasks.css +103 -1
- package/ccw/src/templates/dashboard-css/32-issue-manager.css +32 -0
- package/ccw/src/templates/dashboard-js/components/cli-history.js +48 -48
- package/ccw/src/templates/dashboard-js/components/navigation.js +6 -0
- package/ccw/src/templates/dashboard-js/components/notifications.js +6 -0
- package/ccw/src/templates/dashboard-js/components/version-check.js +38 -0
- package/ccw/src/templates/dashboard-js/i18n.js +126 -0
- package/ccw/src/templates/dashboard-js/state.js +2 -0
- package/ccw/src/templates/dashboard-js/views/cli-manager.js +1 -1
- package/ccw/src/templates/dashboard-js/views/issue-manager.js +183 -1
- package/ccw/src/templates/dashboard-js/views/lite-tasks.js +55 -11
- package/ccw/src/templates/dashboard-js/views/loop-monitor.js +112 -11
- package/ccw/src/templates/dashboard.html +48 -2
- package/ccw/src/tools/claude-cli-tools.ts +4 -3
- package/ccw/src/tools/cli-config-manager.ts +3 -1
- package/ccw/src/tools/codex-lens-lsp.ts +2 -5
- package/ccw/src/tools/codex-lens.ts +27 -38
- package/ccw/src/tools/litellm-client.ts +16 -2
- package/ccw/src/tools/loop-task-manager.ts +13 -2
- package/ccw/src/tools/native-session-discovery.ts +38 -7
- package/ccw/src/utils/codexlens-path.ts +60 -0
- package/ccw/src/utils/uv-manager.ts +3 -2
- 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
|
|
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
|
-
//
|
|
442
|
+
// Load user-configured tools only (defaults NOT merged)
|
|
442
443
|
const mergedTools: Record<string, ClaudeCliTool> = {};
|
|
443
|
-
for (const [key, tool] of Object.entries(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
937
|
-
|
|
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(
|
|
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 "${
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
|
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 {
|
|
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 =
|
|
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
|
-
/**
|
|
26
|
-
|
|
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
|
-
|
|
580
|
-
const
|
|
581
|
-
|
|
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
|
-
|
|
671
|
-
|
|
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 ??
|
|
771
|
+
const baseDir = dataDir ?? getCodexLensDataDir();
|
|
771
772
|
return new UvManager({
|
|
772
|
-
venvPath:
|
|
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.
|
|
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",
|