claude-code-workflow 6.3.24 → 6.3.26
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/issue/discover-by-prompt.md +764 -0
- package/.claude/skills/text-formatter/SKILL.md +196 -0
- package/.claude/skills/text-formatter/phases/01-input-collection.md +111 -0
- package/.claude/skills/text-formatter/phases/02-content-analysis.md +248 -0
- package/.claude/skills/text-formatter/phases/03-format-transform.md +245 -0
- package/.claude/skills/text-formatter/phases/04-output-preview.md +183 -0
- package/.claude/skills/text-formatter/specs/callout-types.md +293 -0
- package/.claude/skills/text-formatter/specs/element-mapping.md +226 -0
- package/.claude/skills/text-formatter/specs/format-rules.md +273 -0
- package/.claude/skills/text-formatter/templates/bbcode-template.md +350 -0
- package/ccw/dist/core/routes/help-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/help-routes.js +43 -7
- package/ccw/dist/core/routes/help-routes.js.map +1 -1
- package/ccw/dist/core/routes/litellm-api-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/litellm-api-routes.js +31 -5
- package/ccw/dist/core/routes/litellm-api-routes.js.map +1 -1
- package/ccw/dist/core/routes/memory-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/memory-routes.js +73 -0
- package/ccw/dist/core/routes/memory-routes.js.map +1 -1
- package/ccw/dist/core/routes/status-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/status-routes.js +36 -4
- package/ccw/dist/core/routes/status-routes.js.map +1 -1
- package/ccw/dist/core/server.d.ts.map +1 -1
- package/ccw/dist/core/server.js +58 -0
- package/ccw/dist/core/server.js.map +1 -1
- package/ccw/dist/core/services/api-key-tester.d.ts.map +1 -1
- package/ccw/dist/core/services/api-key-tester.js +8 -3
- package/ccw/dist/core/services/api-key-tester.js.map +1 -1
- package/ccw/dist/tools/claude-cli-tools.d.ts +7 -0
- package/ccw/dist/tools/claude-cli-tools.d.ts.map +1 -1
- package/ccw/dist/tools/claude-cli-tools.js +11 -1
- package/ccw/dist/tools/claude-cli-tools.js.map +1 -1
- package/ccw/dist/tools/cli-executor-core.d.ts +11 -0
- package/ccw/dist/tools/cli-executor-core.d.ts.map +1 -1
- package/ccw/dist/tools/cli-executor-core.js +89 -2
- package/ccw/dist/tools/cli-executor-core.js.map +1 -1
- package/ccw/dist/tools/codex-lens.d.ts +2 -1
- package/ccw/dist/tools/codex-lens.d.ts.map +1 -1
- package/ccw/dist/tools/codex-lens.js +51 -8
- package/ccw/dist/tools/codex-lens.js.map +1 -1
- package/ccw/dist/tools/index.d.ts.map +1 -1
- package/ccw/dist/tools/index.js +2 -0
- package/ccw/dist/tools/index.js.map +1 -1
- package/ccw/dist/tools/litellm-client.d.ts +6 -0
- package/ccw/dist/tools/litellm-client.d.ts.map +1 -1
- package/ccw/dist/tools/litellm-client.js +22 -1
- package/ccw/dist/tools/litellm-client.js.map +1 -1
- package/ccw/dist/tools/litellm-executor.js +2 -2
- package/ccw/dist/tools/litellm-executor.js.map +1 -1
- package/ccw/dist/tools/memory-update-queue.d.ts +172 -0
- package/ccw/dist/tools/memory-update-queue.d.ts.map +1 -0
- package/ccw/dist/tools/memory-update-queue.js +431 -0
- package/ccw/dist/tools/memory-update-queue.js.map +1 -0
- package/ccw/src/core/routes/help-routes.ts +46 -7
- package/ccw/src/core/routes/litellm-api-routes.ts +35 -4
- package/ccw/src/core/routes/memory-routes.ts +84 -0
- package/ccw/src/core/routes/status-routes.ts +39 -4
- package/ccw/src/core/server.ts +62 -0
- package/ccw/src/core/services/api-key-tester.ts +9 -3
- package/ccw/src/templates/dashboard-css/21-cli-toolmgmt.css +45 -0
- package/ccw/src/templates/dashboard-js/components/cli-status.js +36 -5
- package/ccw/src/templates/dashboard-js/components/hook-manager.js +42 -81
- package/ccw/src/templates/dashboard-js/components/mcp-manager.js +170 -28
- package/ccw/src/templates/dashboard-js/components/notifications.js +14 -4
- package/ccw/src/templates/dashboard-js/i18n.js +26 -0
- package/ccw/src/templates/dashboard-js/views/cli-manager.js +72 -2
- package/ccw/src/templates/dashboard-js/views/codexlens-manager.js +11 -1
- package/ccw/src/tools/claude-cli-tools.ts +17 -1
- package/ccw/src/tools/cli-executor-core.ts +103 -2
- package/ccw/src/tools/codex-lens.ts +63 -8
- package/ccw/src/tools/index.ts +2 -0
- package/ccw/src/tools/litellm-client.ts +25 -3
- package/ccw/src/tools/litellm-executor.ts +2 -2
- package/ccw/src/tools/memory-update-queue.js +499 -0
- package/package.json +91 -91
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
import { z } from 'zod';
|
|
7
7
|
import type { ToolSchema, ToolResult } from '../types/tool.js';
|
|
8
8
|
import { spawn, ChildProcess } from 'child_process';
|
|
9
|
+
import * as fs from 'fs';
|
|
10
|
+
import * as path from 'path';
|
|
11
|
+
import * as os from 'os';
|
|
9
12
|
import { validatePath } from '../utils/path-resolver.js';
|
|
10
13
|
import { escapeWindowsArg } from '../utils/shell-escape.js';
|
|
11
14
|
import { buildCommand, checkToolAvailability, clearToolCache, debugLog, errorLog, type NativeResumeConfig, type ToolAvailability } from './cli-executor-utils.js';
|
|
@@ -82,7 +85,73 @@ import { findEndpointById } from '../config/litellm-api-config-manager.js';
|
|
|
82
85
|
|
|
83
86
|
// CLI Settings (CLI封装) integration
|
|
84
87
|
import { loadEndpointSettings, getSettingsFilePath, findEndpoint } from '../config/cli-settings-manager.js';
|
|
85
|
-
import { loadClaudeCliTools } from './claude-cli-tools.js';
|
|
88
|
+
import { loadClaudeCliTools, getToolConfig } from './claude-cli-tools.js';
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Parse .env file content into key-value pairs
|
|
92
|
+
* Supports: KEY=value, KEY="value", KEY='value', comments (#), empty lines
|
|
93
|
+
*/
|
|
94
|
+
function parseEnvFile(content: string): Record<string, string> {
|
|
95
|
+
const env: Record<string, string> = {};
|
|
96
|
+
const lines = content.split(/\r?\n/);
|
|
97
|
+
|
|
98
|
+
for (const line of lines) {
|
|
99
|
+
// Skip empty lines and comments
|
|
100
|
+
const trimmed = line.trim();
|
|
101
|
+
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
102
|
+
|
|
103
|
+
// Find first = sign
|
|
104
|
+
const eqIndex = trimmed.indexOf('=');
|
|
105
|
+
if (eqIndex === -1) continue;
|
|
106
|
+
|
|
107
|
+
const key = trimmed.substring(0, eqIndex).trim();
|
|
108
|
+
let value = trimmed.substring(eqIndex + 1).trim();
|
|
109
|
+
|
|
110
|
+
// Remove surrounding quotes if present
|
|
111
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
112
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
113
|
+
value = value.slice(1, -1);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (key) {
|
|
117
|
+
env[key] = value;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return env;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Load environment variables from .env file
|
|
126
|
+
* Supports ~ for home directory expansion
|
|
127
|
+
*/
|
|
128
|
+
function loadEnvFile(envFilePath: string): Record<string, string> {
|
|
129
|
+
try {
|
|
130
|
+
// Expand ~ to home directory
|
|
131
|
+
let resolvedPath = envFilePath;
|
|
132
|
+
if (resolvedPath.startsWith('~')) {
|
|
133
|
+
resolvedPath = path.join(os.homedir(), resolvedPath.slice(1));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Resolve relative paths
|
|
137
|
+
if (!path.isAbsolute(resolvedPath)) {
|
|
138
|
+
resolvedPath = path.resolve(resolvedPath);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
142
|
+
debugLog('ENV_FILE', `Env file not found: ${resolvedPath}`);
|
|
143
|
+
return {};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const content = fs.readFileSync(resolvedPath, 'utf-8');
|
|
147
|
+
const envVars = parseEnvFile(content);
|
|
148
|
+
debugLog('ENV_FILE', `Loaded ${Object.keys(envVars).length} env vars from ${resolvedPath}`);
|
|
149
|
+
return envVars;
|
|
150
|
+
} catch (err) {
|
|
151
|
+
errorLog('ENV_FILE', `Failed to load env file: ${envFilePath}`, err as Error);
|
|
152
|
+
return {};
|
|
153
|
+
}
|
|
154
|
+
}
|
|
86
155
|
|
|
87
156
|
/**
|
|
88
157
|
* Execute Claude CLI with custom settings file (CLI封装)
|
|
@@ -746,6 +815,19 @@ async function executeCliTool(
|
|
|
746
815
|
const commandToSpawn = isWindows ? escapeWindowsArg(command) : command;
|
|
747
816
|
const argsToSpawn = isWindows ? args.map(escapeWindowsArg) : args;
|
|
748
817
|
|
|
818
|
+
// Load custom environment variables from envFile if configured (for gemini/qwen)
|
|
819
|
+
const toolConfig = getToolConfig(workingDir, tool);
|
|
820
|
+
let customEnv: Record<string, string> = {};
|
|
821
|
+
if (toolConfig.envFile) {
|
|
822
|
+
customEnv = loadEnvFile(toolConfig.envFile);
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// Merge custom env with process.env (custom env takes precedence)
|
|
826
|
+
const spawnEnv = {
|
|
827
|
+
...process.env,
|
|
828
|
+
...customEnv
|
|
829
|
+
};
|
|
830
|
+
|
|
749
831
|
debugLog('SPAWN', `Spawning process`, {
|
|
750
832
|
command,
|
|
751
833
|
args,
|
|
@@ -754,13 +836,16 @@ async function executeCliTool(
|
|
|
754
836
|
useStdin,
|
|
755
837
|
platform: process.platform,
|
|
756
838
|
fullCommand: `${command} ${args.join(' ')}`,
|
|
839
|
+
hasCustomEnv: Object.keys(customEnv).length > 0,
|
|
840
|
+
customEnvKeys: Object.keys(customEnv),
|
|
757
841
|
...(isWindows ? { escapedCommand: commandToSpawn, escapedArgs: argsToSpawn, escapedFullCommand: `${commandToSpawn} ${argsToSpawn.join(' ')}` } : {})
|
|
758
842
|
});
|
|
759
843
|
|
|
760
844
|
const child = spawn(commandToSpawn, argsToSpawn, {
|
|
761
845
|
cwd: workingDir,
|
|
762
846
|
shell: isWindows, // Enable shell on Windows for .cmd files
|
|
763
|
-
stdio: [useStdin ? 'pipe' : 'ignore', 'pipe', 'pipe']
|
|
847
|
+
stdio: [useStdin ? 'pipe' : 'ignore', 'pipe', 'pipe'],
|
|
848
|
+
env: spawnEnv
|
|
764
849
|
});
|
|
765
850
|
|
|
766
851
|
// Track current child process for cleanup on interruption
|
|
@@ -1190,6 +1275,9 @@ export {
|
|
|
1190
1275
|
* - api-endpoint: Check LiteLLM endpoint configuration exists
|
|
1191
1276
|
*/
|
|
1192
1277
|
export async function getCliToolsStatus(): Promise<Record<string, ToolAvailability>> {
|
|
1278
|
+
const funcStart = Date.now();
|
|
1279
|
+
debugLog('PERF', 'getCliToolsStatus START');
|
|
1280
|
+
|
|
1193
1281
|
// Default built-in tools
|
|
1194
1282
|
const builtInTools = ['gemini', 'qwen', 'codex', 'claude', 'opencode'];
|
|
1195
1283
|
|
|
@@ -1202,6 +1290,7 @@ export async function getCliToolsStatus(): Promise<Record<string, ToolAvailabili
|
|
|
1202
1290
|
}
|
|
1203
1291
|
let toolsInfo: ToolInfo[] = builtInTools.map(name => ({ name, type: 'builtin' }));
|
|
1204
1292
|
|
|
1293
|
+
const configLoadStart = Date.now();
|
|
1205
1294
|
try {
|
|
1206
1295
|
// Dynamic import to avoid circular dependencies
|
|
1207
1296
|
const { loadClaudeCliTools } = await import('./claude-cli-tools.js');
|
|
@@ -1225,11 +1314,15 @@ export async function getCliToolsStatus(): Promise<Record<string, ToolAvailabili
|
|
|
1225
1314
|
// Fallback to built-in tools if config load fails
|
|
1226
1315
|
debugLog('cli-executor', `Using built-in tools (config load failed: ${(e as Error).message})`);
|
|
1227
1316
|
}
|
|
1317
|
+
debugLog('PERF', `Config load: ${Date.now() - configLoadStart}ms, tools: ${toolsInfo.length}`);
|
|
1228
1318
|
|
|
1229
1319
|
const results: Record<string, ToolAvailability> = {};
|
|
1320
|
+
const toolTimings: Record<string, number> = {};
|
|
1230
1321
|
|
|
1322
|
+
const checksStart = Date.now();
|
|
1231
1323
|
await Promise.all(toolsInfo.map(async (toolInfo) => {
|
|
1232
1324
|
const { name, type, enabled, id } = toolInfo;
|
|
1325
|
+
const toolStart = Date.now();
|
|
1233
1326
|
|
|
1234
1327
|
// Check availability based on tool type
|
|
1235
1328
|
if (type === 'cli-wrapper') {
|
|
@@ -1271,8 +1364,13 @@ export async function getCliToolsStatus(): Promise<Record<string, ToolAvailabili
|
|
|
1271
1364
|
// For builtin: check system PATH availability
|
|
1272
1365
|
results[name] = await checkToolAvailability(name);
|
|
1273
1366
|
}
|
|
1367
|
+
|
|
1368
|
+
toolTimings[name] = Date.now() - toolStart;
|
|
1274
1369
|
}));
|
|
1275
1370
|
|
|
1371
|
+
debugLog('PERF', `Tool checks: ${Date.now() - checksStart}ms | Individual: ${JSON.stringify(toolTimings)}`);
|
|
1372
|
+
debugLog('PERF', `getCliToolsStatus TOTAL: ${Date.now() - funcStart}ms`);
|
|
1373
|
+
|
|
1276
1374
|
return results;
|
|
1277
1375
|
}
|
|
1278
1376
|
|
|
@@ -1520,6 +1618,9 @@ export type { PromptFormat, ConcatOptions } from './cli-prompt-builder.js';
|
|
|
1520
1618
|
// Export utility functions and tool definition for backward compatibility
|
|
1521
1619
|
export { executeCliTool, checkToolAvailability, clearToolCache };
|
|
1522
1620
|
|
|
1621
|
+
// Export env file utilities for testing
|
|
1622
|
+
export { parseEnvFile, loadEnvFile };
|
|
1623
|
+
|
|
1523
1624
|
// Export prompt concatenation utilities
|
|
1524
1625
|
export { PromptConcatenator, createPromptConcatenator, buildPrompt, buildMultiTurnPrompt } from './cli-prompt-builder.js';
|
|
1525
1626
|
|
|
@@ -49,6 +49,14 @@ interface VenvStatusCache {
|
|
|
49
49
|
let venvStatusCache: VenvStatusCache | null = null;
|
|
50
50
|
const VENV_STATUS_TTL = 5 * 60 * 1000; // 5 minutes TTL
|
|
51
51
|
|
|
52
|
+
// Semantic status cache with TTL (same as venv cache)
|
|
53
|
+
interface SemanticStatusCache {
|
|
54
|
+
status: SemanticStatus;
|
|
55
|
+
timestamp: number;
|
|
56
|
+
}
|
|
57
|
+
let semanticStatusCache: SemanticStatusCache | null = null;
|
|
58
|
+
const SEMANTIC_STATUS_TTL = 5 * 60 * 1000; // 5 minutes TTL
|
|
59
|
+
|
|
52
60
|
// Track running indexing process for cancellation
|
|
53
61
|
let currentIndexingProcess: ReturnType<typeof spawn> | null = null;
|
|
54
62
|
let currentIndexingAborted = false;
|
|
@@ -147,8 +155,12 @@ function clearVenvStatusCache(): void {
|
|
|
147
155
|
* @returns Ready status
|
|
148
156
|
*/
|
|
149
157
|
async function checkVenvStatus(force = false): Promise<ReadyStatus> {
|
|
158
|
+
const funcStart = Date.now();
|
|
159
|
+
console.log('[PERF][CodexLens] checkVenvStatus START');
|
|
160
|
+
|
|
150
161
|
// Use cached result if available and not expired
|
|
151
162
|
if (!force && venvStatusCache && (Date.now() - venvStatusCache.timestamp < VENV_STATUS_TTL)) {
|
|
163
|
+
console.log(`[PERF][CodexLens] checkVenvStatus CACHE HIT: ${Date.now() - funcStart}ms`);
|
|
152
164
|
return venvStatusCache.status;
|
|
153
165
|
}
|
|
154
166
|
|
|
@@ -156,6 +168,7 @@ async function checkVenvStatus(force = false): Promise<ReadyStatus> {
|
|
|
156
168
|
if (!existsSync(CODEXLENS_VENV)) {
|
|
157
169
|
const result = { ready: false, error: 'Venv not found' };
|
|
158
170
|
venvStatusCache = { status: result, timestamp: Date.now() };
|
|
171
|
+
console.log(`[PERF][CodexLens] checkVenvStatus (no venv): ${Date.now() - funcStart}ms`);
|
|
159
172
|
return result;
|
|
160
173
|
}
|
|
161
174
|
|
|
@@ -163,12 +176,16 @@ async function checkVenvStatus(force = false): Promise<ReadyStatus> {
|
|
|
163
176
|
if (!existsSync(VENV_PYTHON)) {
|
|
164
177
|
const result = { ready: false, error: 'Python executable not found in venv' };
|
|
165
178
|
venvStatusCache = { status: result, timestamp: Date.now() };
|
|
179
|
+
console.log(`[PERF][CodexLens] checkVenvStatus (no python): ${Date.now() - funcStart}ms`);
|
|
166
180
|
return result;
|
|
167
181
|
}
|
|
168
182
|
|
|
169
|
-
// Check codexlens
|
|
183
|
+
// Check codexlens and core dependencies are importable
|
|
184
|
+
const spawnStart = Date.now();
|
|
185
|
+
console.log('[PERF][CodexLens] checkVenvStatus spawning Python...');
|
|
186
|
+
|
|
170
187
|
return new Promise((resolve) => {
|
|
171
|
-
const child = spawn(VENV_PYTHON, ['-c', 'import codexlens; print(codexlens.__version__)'], {
|
|
188
|
+
const child = spawn(VENV_PYTHON, ['-c', 'import codexlens; import watchdog; print(codexlens.__version__)'], {
|
|
172
189
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
173
190
|
timeout: 10000,
|
|
174
191
|
});
|
|
@@ -192,29 +209,54 @@ async function checkVenvStatus(force = false): Promise<ReadyStatus> {
|
|
|
192
209
|
}
|
|
193
210
|
// Cache the result
|
|
194
211
|
venvStatusCache = { status: result, timestamp: Date.now() };
|
|
212
|
+
console.log(`[PERF][CodexLens] checkVenvStatus Python spawn: ${Date.now() - spawnStart}ms | TOTAL: ${Date.now() - funcStart}ms | ready: ${result.ready}`);
|
|
195
213
|
resolve(result);
|
|
196
214
|
});
|
|
197
215
|
|
|
198
216
|
child.on('error', (err) => {
|
|
199
217
|
const result = { ready: false, error: `Failed to check venv: ${err.message}` };
|
|
200
218
|
venvStatusCache = { status: result, timestamp: Date.now() };
|
|
219
|
+
console.log(`[PERF][CodexLens] checkVenvStatus ERROR: ${Date.now() - funcStart}ms`);
|
|
201
220
|
resolve(result);
|
|
202
221
|
});
|
|
203
222
|
});
|
|
204
223
|
}
|
|
205
224
|
|
|
225
|
+
/**
|
|
226
|
+
* Clear semantic status cache (call after install/uninstall operations)
|
|
227
|
+
*/
|
|
228
|
+
function clearSemanticStatusCache(): void {
|
|
229
|
+
semanticStatusCache = null;
|
|
230
|
+
}
|
|
231
|
+
|
|
206
232
|
/**
|
|
207
233
|
* Check if semantic search dependencies are installed
|
|
234
|
+
* @param force - Force refresh cache (default: false)
|
|
208
235
|
* @returns Semantic status
|
|
209
236
|
*/
|
|
210
|
-
async function checkSemanticStatus(): Promise<SemanticStatus> {
|
|
237
|
+
async function checkSemanticStatus(force = false): Promise<SemanticStatus> {
|
|
238
|
+
const funcStart = Date.now();
|
|
239
|
+
console.log('[PERF][CodexLens] checkSemanticStatus START');
|
|
240
|
+
|
|
241
|
+
// Use cached result if available and not expired
|
|
242
|
+
if (!force && semanticStatusCache && (Date.now() - semanticStatusCache.timestamp < SEMANTIC_STATUS_TTL)) {
|
|
243
|
+
console.log(`[PERF][CodexLens] checkSemanticStatus CACHE HIT: ${Date.now() - funcStart}ms`);
|
|
244
|
+
return semanticStatusCache.status;
|
|
245
|
+
}
|
|
246
|
+
|
|
211
247
|
// First check if CodexLens is installed
|
|
212
248
|
const venvStatus = await checkVenvStatus();
|
|
213
249
|
if (!venvStatus.ready) {
|
|
214
|
-
|
|
250
|
+
const result: SemanticStatus = { available: false, error: 'CodexLens not installed' };
|
|
251
|
+
semanticStatusCache = { status: result, timestamp: Date.now() };
|
|
252
|
+
console.log(`[PERF][CodexLens] checkSemanticStatus (no venv): ${Date.now() - funcStart}ms`);
|
|
253
|
+
return result;
|
|
215
254
|
}
|
|
216
255
|
|
|
217
256
|
// Check semantic module availability and accelerator info
|
|
257
|
+
const spawnStart = Date.now();
|
|
258
|
+
console.log('[PERF][CodexLens] checkSemanticStatus spawning Python...');
|
|
259
|
+
|
|
218
260
|
return new Promise((resolve) => {
|
|
219
261
|
const checkCode = `
|
|
220
262
|
import sys
|
|
@@ -274,21 +316,31 @@ except Exception as e:
|
|
|
274
316
|
const output = stdout.trim();
|
|
275
317
|
try {
|
|
276
318
|
const result = JSON.parse(output);
|
|
277
|
-
|
|
319
|
+
console.log(`[PERF][CodexLens] checkSemanticStatus Python spawn: ${Date.now() - spawnStart}ms | TOTAL: ${Date.now() - funcStart}ms | available: ${result.available}`);
|
|
320
|
+
const status: SemanticStatus = {
|
|
278
321
|
available: result.available || false,
|
|
279
322
|
backend: result.backend,
|
|
280
323
|
accelerator: result.accelerator || 'CPU',
|
|
281
324
|
providers: result.providers || [],
|
|
282
325
|
litellmAvailable: result.litellm_available || false,
|
|
283
326
|
error: result.error
|
|
284
|
-
}
|
|
327
|
+
};
|
|
328
|
+
// Cache the result
|
|
329
|
+
semanticStatusCache = { status, timestamp: Date.now() };
|
|
330
|
+
resolve(status);
|
|
285
331
|
} catch {
|
|
286
|
-
|
|
332
|
+
console.log(`[PERF][CodexLens] checkSemanticStatus PARSE ERROR: ${Date.now() - funcStart}ms`);
|
|
333
|
+
const errorStatus: SemanticStatus = { available: false, error: output || stderr || 'Unknown error' };
|
|
334
|
+
semanticStatusCache = { status: errorStatus, timestamp: Date.now() };
|
|
335
|
+
resolve(errorStatus);
|
|
287
336
|
}
|
|
288
337
|
});
|
|
289
338
|
|
|
290
339
|
child.on('error', (err) => {
|
|
291
|
-
|
|
340
|
+
console.log(`[PERF][CodexLens] checkSemanticStatus ERROR: ${Date.now() - funcStart}ms`);
|
|
341
|
+
const errorStatus: SemanticStatus = { available: false, error: `Check failed: ${err.message}` };
|
|
342
|
+
semanticStatusCache = { status: errorStatus, timestamp: Date.now() };
|
|
343
|
+
resolve(errorStatus);
|
|
292
344
|
});
|
|
293
345
|
});
|
|
294
346
|
}
|
|
@@ -583,6 +635,7 @@ async function bootstrapWithUv(gpuMode: GpuMode = 'cpu'): Promise<BootstrapResul
|
|
|
583
635
|
|
|
584
636
|
// Clear cache after successful installation
|
|
585
637
|
clearVenvStatusCache();
|
|
638
|
+
clearSemanticStatusCache();
|
|
586
639
|
console.log(`[CodexLens] Bootstrap with UV complete (${gpuMode} mode)`);
|
|
587
640
|
return { success: true, message: `Installed with UV (${gpuMode} mode)` };
|
|
588
641
|
}
|
|
@@ -878,6 +931,7 @@ async function bootstrapVenv(): Promise<BootstrapResult> {
|
|
|
878
931
|
|
|
879
932
|
// Clear cache after successful installation
|
|
880
933
|
clearVenvStatusCache();
|
|
934
|
+
clearSemanticStatusCache();
|
|
881
935
|
return { success: true };
|
|
882
936
|
} catch (err) {
|
|
883
937
|
return { success: false, error: `Failed to install codexlens: ${(err as Error).message}` };
|
|
@@ -1631,6 +1685,7 @@ async function uninstallCodexLens(): Promise<BootstrapResult> {
|
|
|
1631
1685
|
bootstrapChecked = false;
|
|
1632
1686
|
bootstrapReady = false;
|
|
1633
1687
|
clearVenvStatusCache();
|
|
1688
|
+
clearSemanticStatusCache();
|
|
1634
1689
|
|
|
1635
1690
|
console.log('[CodexLens] CodexLens uninstalled successfully');
|
|
1636
1691
|
return { success: true, message: 'CodexLens uninstalled successfully' };
|
package/ccw/src/tools/index.ts
CHANGED
|
@@ -30,6 +30,7 @@ import type { ProgressInfo } from './codex-lens.js';
|
|
|
30
30
|
import { uiGeneratePreviewTool } from './ui-generate-preview.js';
|
|
31
31
|
import { uiInstantiatePrototypesTool } from './ui-instantiate-prototypes.js';
|
|
32
32
|
import { updateModuleClaudeTool } from './update-module-claude.js';
|
|
33
|
+
import { memoryQueueTool } from './memory-update-queue.js';
|
|
33
34
|
|
|
34
35
|
interface LegacyTool {
|
|
35
36
|
name: string;
|
|
@@ -366,6 +367,7 @@ registerTool(toLegacyTool(skillContextLoaderMod));
|
|
|
366
367
|
registerTool(uiGeneratePreviewTool);
|
|
367
368
|
registerTool(uiInstantiatePrototypesTool);
|
|
368
369
|
registerTool(updateModuleClaudeTool);
|
|
370
|
+
registerTool(memoryQueueTool);
|
|
369
371
|
|
|
370
372
|
// Export for external tool registration
|
|
371
373
|
export { registerTool };
|
|
@@ -10,14 +10,36 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { spawn } from 'child_process';
|
|
13
|
-
import {
|
|
13
|
+
import { existsSync } from 'fs';
|
|
14
|
+
import { join } from 'path';
|
|
15
|
+
import { homedir } from 'os';
|
|
14
16
|
|
|
15
17
|
export interface LiteLLMConfig {
|
|
16
|
-
pythonPath?: string; // Default
|
|
18
|
+
pythonPath?: string; // Default: CodexLens venv Python
|
|
17
19
|
configPath?: string; // Configuration file path
|
|
18
20
|
timeout?: number; // Default 60000ms
|
|
19
21
|
}
|
|
20
22
|
|
|
23
|
+
// Platform-specific constants for CodexLens venv
|
|
24
|
+
const IS_WINDOWS = process.platform === 'win32';
|
|
25
|
+
const CODEXLENS_VENV = join(homedir(), '.codexlens', 'venv');
|
|
26
|
+
const VENV_BIN_DIR = IS_WINDOWS ? 'Scripts' : 'bin';
|
|
27
|
+
const PYTHON_EXECUTABLE = IS_WINDOWS ? 'python.exe' : 'python';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Get the Python path from CodexLens venv
|
|
31
|
+
* Falls back to system 'python' if venv doesn't exist
|
|
32
|
+
* @returns Path to Python executable
|
|
33
|
+
*/
|
|
34
|
+
export function getCodexLensVenvPython(): string {
|
|
35
|
+
const venvPython = join(CODEXLENS_VENV, VENV_BIN_DIR, PYTHON_EXECUTABLE);
|
|
36
|
+
if (existsSync(venvPython)) {
|
|
37
|
+
return venvPython;
|
|
38
|
+
}
|
|
39
|
+
// Fallback to system Python if venv not available
|
|
40
|
+
return 'python';
|
|
41
|
+
}
|
|
42
|
+
|
|
21
43
|
export interface ChatMessage {
|
|
22
44
|
role: 'system' | 'user' | 'assistant';
|
|
23
45
|
content: string;
|
|
@@ -51,7 +73,7 @@ export class LiteLLMClient {
|
|
|
51
73
|
private timeout: number;
|
|
52
74
|
|
|
53
75
|
constructor(config: LiteLLMConfig = {}) {
|
|
54
|
-
this.pythonPath = config.pythonPath ||
|
|
76
|
+
this.pythonPath = config.pythonPath || getCodexLensVenvPython();
|
|
55
77
|
this.configPath = config.configPath;
|
|
56
78
|
this.timeout = config.timeout || 60000;
|
|
57
79
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Integrates with context-cache for file packing and LiteLLM client for API calls
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { getLiteLLMClient } from './litellm-client.js';
|
|
6
|
+
import { getLiteLLMClient, getCodexLensVenvPython } from './litellm-client.js';
|
|
7
7
|
import { handler as contextCacheHandler } from './context-cache.js';
|
|
8
8
|
import {
|
|
9
9
|
findEndpointById,
|
|
@@ -179,7 +179,7 @@ export async function executeLiteLLMEndpoint(
|
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
const client = getLiteLLMClient({
|
|
182
|
-
pythonPath:
|
|
182
|
+
pythonPath: getCodexLensVenvPython(),
|
|
183
183
|
timeout: 120000, // 2 minutes
|
|
184
184
|
});
|
|
185
185
|
|