claude-code-workflow 6.3.11 → 6.3.13
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/CLAUDE.md +33 -33
- package/.claude/agents/issue-plan-agent.md +77 -5
- package/.claude/agents/issue-queue-agent.md +122 -18
- package/.claude/commands/issue/execute.md +53 -40
- package/.claude/commands/issue/new.md +113 -11
- package/.claude/commands/issue/plan.md +112 -37
- package/.claude/commands/issue/queue.md +28 -18
- package/.claude/skills/software-manual/scripts/assemble_docsify.py +584 -0
- package/.claude/skills/software-manual/templates/css/docsify-base.css +984 -0
- package/.claude/skills/software-manual/templates/docsify-shell.html +466 -0
- package/.claude/workflows/cli-templates/schemas/issues-jsonl-schema.json +141 -168
- package/.claude/workflows/cli-templates/schemas/solution-schema.json +3 -2
- package/.codex/prompts/issue-execute.md +3 -3
- package/.codex/prompts/issue-queue.md +3 -3
- package/ccw/dist/commands/issue.d.ts.map +1 -1
- package/ccw/dist/commands/issue.js +2 -1
- package/ccw/dist/commands/issue.js.map +1 -1
- package/ccw/src/commands/issue.ts +2 -1
- package/ccw/src/templates/dashboard-css/33-cli-stream-viewer.css +580 -467
- package/ccw/src/templates/dashboard-js/components/cli-stream-viewer.js +532 -461
- package/ccw/src/templates/dashboard-js/components/notifications.js +774 -774
- package/ccw/src/templates/dashboard-js/i18n.js +4 -0
- package/ccw/src/templates/dashboard.html +10 -0
- package/ccw/src/tools/claude-cli-tools.ts +388 -388
- package/codex-lens/src/codexlens/__pycache__/config.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/config.py +19 -3
- package/codex-lens/src/codexlens/search/__pycache__/ranking.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/ranking.py +15 -4
- package/codex-lens/src/codexlens/semantic/__pycache__/vector_store.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/vector_store.py +57 -47
- package/codex-lens/src/codexlens/storage/__pycache__/registry.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/registry.py +114 -101
- package/package.json +83 -83
|
@@ -1,388 +1,388 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Claude CLI Tools Configuration Manager
|
|
3
|
-
* Manages .claude/cli-tools.json with fallback:
|
|
4
|
-
* 1. Project workspace: {projectDir}/.claude/cli-tools.json (priority)
|
|
5
|
-
* 2. Global: ~/.claude/cli-tools.json (fallback)
|
|
6
|
-
*/
|
|
7
|
-
import * as fs from 'fs';
|
|
8
|
-
import * as path from 'path';
|
|
9
|
-
import * as os from 'os';
|
|
10
|
-
|
|
11
|
-
// ========== Types ==========
|
|
12
|
-
|
|
13
|
-
export interface ClaudeCliTool {
|
|
14
|
-
enabled: boolean;
|
|
15
|
-
isBuiltin: boolean;
|
|
16
|
-
command: string;
|
|
17
|
-
description: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface ClaudeCacheSettings {
|
|
21
|
-
injectionMode: 'auto' | 'manual' | 'disabled';
|
|
22
|
-
defaultPrefix: string;
|
|
23
|
-
defaultSuffix: string;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface ClaudeCliToolsConfig {
|
|
27
|
-
$schema?: string;
|
|
28
|
-
version: string;
|
|
29
|
-
tools: Record<string, ClaudeCliTool>;
|
|
30
|
-
customEndpoints: Array<{
|
|
31
|
-
id: string;
|
|
32
|
-
name: string;
|
|
33
|
-
enabled: boolean;
|
|
34
|
-
}>;
|
|
35
|
-
defaultTool: string;
|
|
36
|
-
settings: {
|
|
37
|
-
promptFormat: 'plain' | 'yaml' | 'json';
|
|
38
|
-
smartContext: {
|
|
39
|
-
enabled: boolean;
|
|
40
|
-
maxFiles: number;
|
|
41
|
-
};
|
|
42
|
-
nativeResume: boolean;
|
|
43
|
-
recursiveQuery: boolean;
|
|
44
|
-
cache: ClaudeCacheSettings;
|
|
45
|
-
codeIndexMcp: 'codexlens' | 'ace' | 'none'; // Code Index MCP provider
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// ========== Default Config ==========
|
|
50
|
-
|
|
51
|
-
const DEFAULT_CONFIG: ClaudeCliToolsConfig = {
|
|
52
|
-
version: '1.0.0',
|
|
53
|
-
tools: {
|
|
54
|
-
gemini: {
|
|
55
|
-
enabled: true,
|
|
56
|
-
isBuiltin: true,
|
|
57
|
-
command: 'gemini',
|
|
58
|
-
description: 'Google AI for code analysis'
|
|
59
|
-
},
|
|
60
|
-
qwen: {
|
|
61
|
-
enabled: true,
|
|
62
|
-
isBuiltin: true,
|
|
63
|
-
command: 'qwen',
|
|
64
|
-
description: 'Alibaba AI assistant'
|
|
65
|
-
},
|
|
66
|
-
codex: {
|
|
67
|
-
enabled: true,
|
|
68
|
-
isBuiltin: true,
|
|
69
|
-
command: 'codex',
|
|
70
|
-
description: 'OpenAI code generation'
|
|
71
|
-
},
|
|
72
|
-
claude: {
|
|
73
|
-
enabled: true,
|
|
74
|
-
isBuiltin: true,
|
|
75
|
-
command: 'claude',
|
|
76
|
-
description: 'Anthropic AI assistant'
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
customEndpoints: [],
|
|
80
|
-
defaultTool: 'gemini',
|
|
81
|
-
settings: {
|
|
82
|
-
promptFormat: 'plain',
|
|
83
|
-
smartContext: {
|
|
84
|
-
enabled: false,
|
|
85
|
-
maxFiles: 10
|
|
86
|
-
},
|
|
87
|
-
nativeResume: true,
|
|
88
|
-
recursiveQuery: true,
|
|
89
|
-
cache: {
|
|
90
|
-
injectionMode: 'auto',
|
|
91
|
-
defaultPrefix: '',
|
|
92
|
-
defaultSuffix: ''
|
|
93
|
-
},
|
|
94
|
-
codeIndexMcp: 'codexlens' // Default to CodexLens
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
// ========== Helper Functions ==========
|
|
99
|
-
|
|
100
|
-
function getProjectConfigPath(projectDir: string): string {
|
|
101
|
-
return path.join(projectDir, '.claude', 'cli-tools.json');
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function getGlobalConfigPath(): string {
|
|
105
|
-
return path.join(os.homedir(), '.claude', 'cli-tools.json');
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Resolve config path with fallback:
|
|
110
|
-
* 1. Project: {projectDir}/.claude/cli-tools.json
|
|
111
|
-
* 2. Global: ~/.claude/cli-tools.json
|
|
112
|
-
* Returns { path, source } where source is 'project' | 'global' | 'default'
|
|
113
|
-
*/
|
|
114
|
-
function resolveConfigPath(projectDir: string): { path: string; source: 'project' | 'global' | 'default' } {
|
|
115
|
-
const projectPath = getProjectConfigPath(projectDir);
|
|
116
|
-
if (fs.existsSync(projectPath)) {
|
|
117
|
-
return { path: projectPath, source: 'project' };
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const globalPath = getGlobalConfigPath();
|
|
121
|
-
if (fs.existsSync(globalPath)) {
|
|
122
|
-
return { path: globalPath, source: 'global' };
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return { path: projectPath, source: 'default' };
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function ensureClaudeDir(projectDir: string): void {
|
|
129
|
-
const claudeDir = path.join(projectDir, '.claude');
|
|
130
|
-
if (!fs.existsSync(claudeDir)) {
|
|
131
|
-
fs.mkdirSync(claudeDir, { recursive: true });
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// ========== Main Functions ==========
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Load CLI tools configuration with fallback:
|
|
139
|
-
* 1. Project: {projectDir}/.claude/cli-tools.json
|
|
140
|
-
* 2. Global: ~/.claude/cli-tools.json
|
|
141
|
-
* 3. Default config
|
|
142
|
-
*/
|
|
143
|
-
export function loadClaudeCliTools(projectDir: string): ClaudeCliToolsConfig & { _source?: string } {
|
|
144
|
-
const resolved = resolveConfigPath(projectDir);
|
|
145
|
-
|
|
146
|
-
try {
|
|
147
|
-
if (resolved.source === 'default') {
|
|
148
|
-
// No config file found, return defaults
|
|
149
|
-
return { ...DEFAULT_CONFIG, _source: 'default' };
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const content = fs.readFileSync(resolved.path, 'utf-8');
|
|
153
|
-
const parsed = JSON.parse(content) as Partial<ClaudeCliToolsConfig>;
|
|
154
|
-
|
|
155
|
-
// Merge with defaults
|
|
156
|
-
const config = {
|
|
157
|
-
...DEFAULT_CONFIG,
|
|
158
|
-
...parsed,
|
|
159
|
-
tools: { ...DEFAULT_CONFIG.tools, ...(parsed.tools || {}) },
|
|
160
|
-
settings: {
|
|
161
|
-
...DEFAULT_CONFIG.settings,
|
|
162
|
-
...(parsed.settings || {}),
|
|
163
|
-
smartContext: {
|
|
164
|
-
...DEFAULT_CONFIG.settings.smartContext,
|
|
165
|
-
...(parsed.settings?.smartContext || {})
|
|
166
|
-
},
|
|
167
|
-
cache: {
|
|
168
|
-
...DEFAULT_CONFIG.settings.cache,
|
|
169
|
-
...(parsed.settings?.cache || {})
|
|
170
|
-
}
|
|
171
|
-
},
|
|
172
|
-
_source: resolved.source
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
console.log(`[claude-cli-tools] Loaded config from ${resolved.source}: ${resolved.path}`);
|
|
176
|
-
return config;
|
|
177
|
-
} catch (err) {
|
|
178
|
-
console.error('[claude-cli-tools] Error loading config:', err);
|
|
179
|
-
return { ...DEFAULT_CONFIG, _source: 'default' };
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Save CLI tools configuration to project .claude/cli-tools.json
|
|
185
|
-
* Always saves to project directory (not global)
|
|
186
|
-
*/
|
|
187
|
-
export function saveClaudeCliTools(projectDir: string, config: ClaudeCliToolsConfig & { _source?: string }): void {
|
|
188
|
-
ensureClaudeDir(projectDir);
|
|
189
|
-
const configPath = getProjectConfigPath(projectDir);
|
|
190
|
-
|
|
191
|
-
// Remove internal _source field before saving
|
|
192
|
-
const { _source, ...configToSave } = config;
|
|
193
|
-
|
|
194
|
-
try {
|
|
195
|
-
fs.writeFileSync(configPath, JSON.stringify(configToSave, null, 2), 'utf-8');
|
|
196
|
-
console.log(`[claude-cli-tools] Saved config to project: ${configPath}`);
|
|
197
|
-
} catch (err) {
|
|
198
|
-
console.error('[claude-cli-tools] Error saving config:', err);
|
|
199
|
-
throw new Error(`Failed to save CLI tools config: ${err}`);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Update enabled status for a specific tool
|
|
205
|
-
*/
|
|
206
|
-
export function updateClaudeToolEnabled(
|
|
207
|
-
projectDir: string,
|
|
208
|
-
toolName: string,
|
|
209
|
-
enabled: boolean
|
|
210
|
-
): ClaudeCliToolsConfig {
|
|
211
|
-
const config = loadClaudeCliTools(projectDir);
|
|
212
|
-
|
|
213
|
-
if (config.tools[toolName]) {
|
|
214
|
-
config.tools[toolName].enabled = enabled;
|
|
215
|
-
saveClaudeCliTools(projectDir, config);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
return config;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Update cache settings
|
|
223
|
-
*/
|
|
224
|
-
export function updateClaudeCacheSettings(
|
|
225
|
-
projectDir: string,
|
|
226
|
-
cacheSettings: Partial<ClaudeCacheSettings>
|
|
227
|
-
): ClaudeCliToolsConfig {
|
|
228
|
-
const config = loadClaudeCliTools(projectDir);
|
|
229
|
-
|
|
230
|
-
config.settings.cache = {
|
|
231
|
-
...config.settings.cache,
|
|
232
|
-
...cacheSettings
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
saveClaudeCliTools(projectDir, config);
|
|
236
|
-
return config;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Update default tool
|
|
241
|
-
*/
|
|
242
|
-
export function updateClaudeDefaultTool(
|
|
243
|
-
projectDir: string,
|
|
244
|
-
defaultTool: string
|
|
245
|
-
): ClaudeCliToolsConfig {
|
|
246
|
-
const config = loadClaudeCliTools(projectDir);
|
|
247
|
-
config.defaultTool = defaultTool;
|
|
248
|
-
saveClaudeCliTools(projectDir, config);
|
|
249
|
-
return config;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Add custom endpoint
|
|
254
|
-
*/
|
|
255
|
-
export function addClaudeCustomEndpoint(
|
|
256
|
-
projectDir: string,
|
|
257
|
-
endpoint: { id: string; name: string; enabled: boolean }
|
|
258
|
-
): ClaudeCliToolsConfig {
|
|
259
|
-
const config = loadClaudeCliTools(projectDir);
|
|
260
|
-
|
|
261
|
-
// Check if endpoint already exists
|
|
262
|
-
const existingIndex = config.customEndpoints.findIndex(e => e.id === endpoint.id);
|
|
263
|
-
if (existingIndex >= 0) {
|
|
264
|
-
config.customEndpoints[existingIndex] = endpoint;
|
|
265
|
-
} else {
|
|
266
|
-
config.customEndpoints.push(endpoint);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
saveClaudeCliTools(projectDir, config);
|
|
270
|
-
return config;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Remove custom endpoint
|
|
275
|
-
*/
|
|
276
|
-
export function removeClaudeCustomEndpoint(
|
|
277
|
-
projectDir: string,
|
|
278
|
-
endpointId: string
|
|
279
|
-
): ClaudeCliToolsConfig {
|
|
280
|
-
const config = loadClaudeCliTools(projectDir);
|
|
281
|
-
config.customEndpoints = config.customEndpoints.filter(e => e.id !== endpointId);
|
|
282
|
-
saveClaudeCliTools(projectDir, config);
|
|
283
|
-
return config;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Get config source info
|
|
288
|
-
*/
|
|
289
|
-
export function getClaudeCliToolsInfo(projectDir: string): {
|
|
290
|
-
projectPath: string;
|
|
291
|
-
globalPath: string;
|
|
292
|
-
activePath: string;
|
|
293
|
-
source: 'project' | 'global' | 'default';
|
|
294
|
-
} {
|
|
295
|
-
const resolved = resolveConfigPath(projectDir);
|
|
296
|
-
return {
|
|
297
|
-
projectPath: getProjectConfigPath(projectDir),
|
|
298
|
-
globalPath: getGlobalConfigPath(),
|
|
299
|
-
activePath: resolved.path,
|
|
300
|
-
source: resolved.source
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
/**
|
|
305
|
-
* Update Code Index MCP provider and switch CLAUDE.md reference
|
|
306
|
-
* Strategy: Only modify global user-level CLAUDE.md (~/.claude/CLAUDE.md)
|
|
307
|
-
* This is consistent with Chinese response and Windows platform settings
|
|
308
|
-
*/
|
|
309
|
-
export function updateCodeIndexMcp(
|
|
310
|
-
projectDir: string,
|
|
311
|
-
provider: 'codexlens' | 'ace' | 'none'
|
|
312
|
-
): { success: boolean; error?: string; config?: ClaudeCliToolsConfig } {
|
|
313
|
-
try {
|
|
314
|
-
// Update config
|
|
315
|
-
const config = loadClaudeCliTools(projectDir);
|
|
316
|
-
config.settings.codeIndexMcp = provider;
|
|
317
|
-
saveClaudeCliTools(projectDir, config);
|
|
318
|
-
|
|
319
|
-
// Only update global CLAUDE.md (consistent with Chinese response / Windows platform)
|
|
320
|
-
const globalClaudeMdPath = path.join(os.homedir(), '.claude', 'CLAUDE.md');
|
|
321
|
-
|
|
322
|
-
// Define patterns for all formats
|
|
323
|
-
const codexlensPattern = /@~\/\.claude\/workflows\/context-tools\.md/g;
|
|
324
|
-
const acePattern = /@~\/\.claude\/workflows\/context-tools-ace\.md/g;
|
|
325
|
-
const nonePattern = /@~\/\.claude\/workflows\/context-tools-none\.md/g;
|
|
326
|
-
|
|
327
|
-
// Determine target file based on provider
|
|
328
|
-
const targetFile = provider === 'ace'
|
|
329
|
-
? '@~/.claude/workflows/context-tools-ace.md'
|
|
330
|
-
: provider === 'none'
|
|
331
|
-
? '@~/.claude/workflows/context-tools-none.md'
|
|
332
|
-
: '@~/.claude/workflows/context-tools.md';
|
|
333
|
-
|
|
334
|
-
if (!fs.existsSync(globalClaudeMdPath)) {
|
|
335
|
-
// If global CLAUDE.md doesn't exist, check project-level
|
|
336
|
-
const projectClaudeMdPath = path.join(projectDir, '.claude', 'CLAUDE.md');
|
|
337
|
-
if (fs.existsSync(projectClaudeMdPath)) {
|
|
338
|
-
let content = fs.readFileSync(projectClaudeMdPath, 'utf-8');
|
|
339
|
-
|
|
340
|
-
// Replace any existing pattern with the target
|
|
341
|
-
content = content.replace(codexlensPattern, targetFile);
|
|
342
|
-
content = content.replace(acePattern, targetFile);
|
|
343
|
-
content = content.replace(nonePattern, targetFile);
|
|
344
|
-
|
|
345
|
-
fs.writeFileSync(projectClaudeMdPath, content, 'utf-8');
|
|
346
|
-
console.log(`[claude-cli-tools] Updated project CLAUDE.md to use ${provider} (no global CLAUDE.md found)`);
|
|
347
|
-
}
|
|
348
|
-
} else {
|
|
349
|
-
// Update global CLAUDE.md (primary target)
|
|
350
|
-
let content = fs.readFileSync(globalClaudeMdPath, 'utf-8');
|
|
351
|
-
|
|
352
|
-
// Replace any existing pattern with the target
|
|
353
|
-
content = content.replace(codexlensPattern, targetFile);
|
|
354
|
-
content = content.replace(acePattern, targetFile);
|
|
355
|
-
content = content.replace(nonePattern, targetFile);
|
|
356
|
-
|
|
357
|
-
fs.writeFileSync(globalClaudeMdPath, content, 'utf-8');
|
|
358
|
-
console.log(`[claude-cli-tools] Updated global CLAUDE.md to use ${provider}`);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
return { success: true, config };
|
|
362
|
-
} catch (err) {
|
|
363
|
-
console.error('[claude-cli-tools] Error updating Code Index MCP:', err);
|
|
364
|
-
return { success: false, error: (err as Error).message };
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
/**
|
|
369
|
-
* Get current Code Index MCP provider
|
|
370
|
-
*/
|
|
371
|
-
export function getCodeIndexMcp(projectDir: string): 'codexlens' | 'ace' | 'none' {
|
|
372
|
-
const config = loadClaudeCliTools(projectDir);
|
|
373
|
-
return config.settings.codeIndexMcp || 'codexlens';
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* Get the context-tools file path based on provider
|
|
378
|
-
*/
|
|
379
|
-
export function getContextToolsPath(provider: 'codexlens' | 'ace' | 'none'): string {
|
|
380
|
-
switch (provider) {
|
|
381
|
-
case 'ace':
|
|
382
|
-
return 'context-tools-ace.md';
|
|
383
|
-
case 'none':
|
|
384
|
-
return 'context-tools-none.md';
|
|
385
|
-
default:
|
|
386
|
-
return 'context-tools.md';
|
|
387
|
-
}
|
|
388
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Claude CLI Tools Configuration Manager
|
|
3
|
+
* Manages .claude/cli-tools.json with fallback:
|
|
4
|
+
* 1. Project workspace: {projectDir}/.claude/cli-tools.json (priority)
|
|
5
|
+
* 2. Global: ~/.claude/cli-tools.json (fallback)
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from 'fs';
|
|
8
|
+
import * as path from 'path';
|
|
9
|
+
import * as os from 'os';
|
|
10
|
+
|
|
11
|
+
// ========== Types ==========
|
|
12
|
+
|
|
13
|
+
export interface ClaudeCliTool {
|
|
14
|
+
enabled: boolean;
|
|
15
|
+
isBuiltin: boolean;
|
|
16
|
+
command: string;
|
|
17
|
+
description: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ClaudeCacheSettings {
|
|
21
|
+
injectionMode: 'auto' | 'manual' | 'disabled';
|
|
22
|
+
defaultPrefix: string;
|
|
23
|
+
defaultSuffix: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface ClaudeCliToolsConfig {
|
|
27
|
+
$schema?: string;
|
|
28
|
+
version: string;
|
|
29
|
+
tools: Record<string, ClaudeCliTool>;
|
|
30
|
+
customEndpoints: Array<{
|
|
31
|
+
id: string;
|
|
32
|
+
name: string;
|
|
33
|
+
enabled: boolean;
|
|
34
|
+
}>;
|
|
35
|
+
defaultTool: string;
|
|
36
|
+
settings: {
|
|
37
|
+
promptFormat: 'plain' | 'yaml' | 'json';
|
|
38
|
+
smartContext: {
|
|
39
|
+
enabled: boolean;
|
|
40
|
+
maxFiles: number;
|
|
41
|
+
};
|
|
42
|
+
nativeResume: boolean;
|
|
43
|
+
recursiveQuery: boolean;
|
|
44
|
+
cache: ClaudeCacheSettings;
|
|
45
|
+
codeIndexMcp: 'codexlens' | 'ace' | 'none'; // Code Index MCP provider
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ========== Default Config ==========
|
|
50
|
+
|
|
51
|
+
const DEFAULT_CONFIG: ClaudeCliToolsConfig = {
|
|
52
|
+
version: '1.0.0',
|
|
53
|
+
tools: {
|
|
54
|
+
gemini: {
|
|
55
|
+
enabled: true,
|
|
56
|
+
isBuiltin: true,
|
|
57
|
+
command: 'gemini',
|
|
58
|
+
description: 'Google AI for code analysis'
|
|
59
|
+
},
|
|
60
|
+
qwen: {
|
|
61
|
+
enabled: true,
|
|
62
|
+
isBuiltin: true,
|
|
63
|
+
command: 'qwen',
|
|
64
|
+
description: 'Alibaba AI assistant'
|
|
65
|
+
},
|
|
66
|
+
codex: {
|
|
67
|
+
enabled: true,
|
|
68
|
+
isBuiltin: true,
|
|
69
|
+
command: 'codex',
|
|
70
|
+
description: 'OpenAI code generation'
|
|
71
|
+
},
|
|
72
|
+
claude: {
|
|
73
|
+
enabled: true,
|
|
74
|
+
isBuiltin: true,
|
|
75
|
+
command: 'claude',
|
|
76
|
+
description: 'Anthropic AI assistant'
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
customEndpoints: [],
|
|
80
|
+
defaultTool: 'gemini',
|
|
81
|
+
settings: {
|
|
82
|
+
promptFormat: 'plain',
|
|
83
|
+
smartContext: {
|
|
84
|
+
enabled: false,
|
|
85
|
+
maxFiles: 10
|
|
86
|
+
},
|
|
87
|
+
nativeResume: true,
|
|
88
|
+
recursiveQuery: true,
|
|
89
|
+
cache: {
|
|
90
|
+
injectionMode: 'auto',
|
|
91
|
+
defaultPrefix: '',
|
|
92
|
+
defaultSuffix: ''
|
|
93
|
+
},
|
|
94
|
+
codeIndexMcp: 'codexlens' // Default to CodexLens
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// ========== Helper Functions ==========
|
|
99
|
+
|
|
100
|
+
function getProjectConfigPath(projectDir: string): string {
|
|
101
|
+
return path.join(projectDir, '.claude', 'cli-tools.json');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function getGlobalConfigPath(): string {
|
|
105
|
+
return path.join(os.homedir(), '.claude', 'cli-tools.json');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Resolve config path with fallback:
|
|
110
|
+
* 1. Project: {projectDir}/.claude/cli-tools.json
|
|
111
|
+
* 2. Global: ~/.claude/cli-tools.json
|
|
112
|
+
* Returns { path, source } where source is 'project' | 'global' | 'default'
|
|
113
|
+
*/
|
|
114
|
+
function resolveConfigPath(projectDir: string): { path: string; source: 'project' | 'global' | 'default' } {
|
|
115
|
+
const projectPath = getProjectConfigPath(projectDir);
|
|
116
|
+
if (fs.existsSync(projectPath)) {
|
|
117
|
+
return { path: projectPath, source: 'project' };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const globalPath = getGlobalConfigPath();
|
|
121
|
+
if (fs.existsSync(globalPath)) {
|
|
122
|
+
return { path: globalPath, source: 'global' };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return { path: projectPath, source: 'default' };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function ensureClaudeDir(projectDir: string): void {
|
|
129
|
+
const claudeDir = path.join(projectDir, '.claude');
|
|
130
|
+
if (!fs.existsSync(claudeDir)) {
|
|
131
|
+
fs.mkdirSync(claudeDir, { recursive: true });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ========== Main Functions ==========
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Load CLI tools configuration with fallback:
|
|
139
|
+
* 1. Project: {projectDir}/.claude/cli-tools.json
|
|
140
|
+
* 2. Global: ~/.claude/cli-tools.json
|
|
141
|
+
* 3. Default config
|
|
142
|
+
*/
|
|
143
|
+
export function loadClaudeCliTools(projectDir: string): ClaudeCliToolsConfig & { _source?: string } {
|
|
144
|
+
const resolved = resolveConfigPath(projectDir);
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
if (resolved.source === 'default') {
|
|
148
|
+
// No config file found, return defaults
|
|
149
|
+
return { ...DEFAULT_CONFIG, _source: 'default' };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const content = fs.readFileSync(resolved.path, 'utf-8');
|
|
153
|
+
const parsed = JSON.parse(content) as Partial<ClaudeCliToolsConfig>;
|
|
154
|
+
|
|
155
|
+
// Merge with defaults
|
|
156
|
+
const config = {
|
|
157
|
+
...DEFAULT_CONFIG,
|
|
158
|
+
...parsed,
|
|
159
|
+
tools: { ...DEFAULT_CONFIG.tools, ...(parsed.tools || {}) },
|
|
160
|
+
settings: {
|
|
161
|
+
...DEFAULT_CONFIG.settings,
|
|
162
|
+
...(parsed.settings || {}),
|
|
163
|
+
smartContext: {
|
|
164
|
+
...DEFAULT_CONFIG.settings.smartContext,
|
|
165
|
+
...(parsed.settings?.smartContext || {})
|
|
166
|
+
},
|
|
167
|
+
cache: {
|
|
168
|
+
...DEFAULT_CONFIG.settings.cache,
|
|
169
|
+
...(parsed.settings?.cache || {})
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
_source: resolved.source
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
console.log(`[claude-cli-tools] Loaded config from ${resolved.source}: ${resolved.path}`);
|
|
176
|
+
return config;
|
|
177
|
+
} catch (err) {
|
|
178
|
+
console.error('[claude-cli-tools] Error loading config:', err);
|
|
179
|
+
return { ...DEFAULT_CONFIG, _source: 'default' };
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Save CLI tools configuration to project .claude/cli-tools.json
|
|
185
|
+
* Always saves to project directory (not global)
|
|
186
|
+
*/
|
|
187
|
+
export function saveClaudeCliTools(projectDir: string, config: ClaudeCliToolsConfig & { _source?: string }): void {
|
|
188
|
+
ensureClaudeDir(projectDir);
|
|
189
|
+
const configPath = getProjectConfigPath(projectDir);
|
|
190
|
+
|
|
191
|
+
// Remove internal _source field before saving
|
|
192
|
+
const { _source, ...configToSave } = config;
|
|
193
|
+
|
|
194
|
+
try {
|
|
195
|
+
fs.writeFileSync(configPath, JSON.stringify(configToSave, null, 2), 'utf-8');
|
|
196
|
+
console.log(`[claude-cli-tools] Saved config to project: ${configPath}`);
|
|
197
|
+
} catch (err) {
|
|
198
|
+
console.error('[claude-cli-tools] Error saving config:', err);
|
|
199
|
+
throw new Error(`Failed to save CLI tools config: ${err}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Update enabled status for a specific tool
|
|
205
|
+
*/
|
|
206
|
+
export function updateClaudeToolEnabled(
|
|
207
|
+
projectDir: string,
|
|
208
|
+
toolName: string,
|
|
209
|
+
enabled: boolean
|
|
210
|
+
): ClaudeCliToolsConfig {
|
|
211
|
+
const config = loadClaudeCliTools(projectDir);
|
|
212
|
+
|
|
213
|
+
if (config.tools[toolName]) {
|
|
214
|
+
config.tools[toolName].enabled = enabled;
|
|
215
|
+
saveClaudeCliTools(projectDir, config);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return config;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Update cache settings
|
|
223
|
+
*/
|
|
224
|
+
export function updateClaudeCacheSettings(
|
|
225
|
+
projectDir: string,
|
|
226
|
+
cacheSettings: Partial<ClaudeCacheSettings>
|
|
227
|
+
): ClaudeCliToolsConfig {
|
|
228
|
+
const config = loadClaudeCliTools(projectDir);
|
|
229
|
+
|
|
230
|
+
config.settings.cache = {
|
|
231
|
+
...config.settings.cache,
|
|
232
|
+
...cacheSettings
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
saveClaudeCliTools(projectDir, config);
|
|
236
|
+
return config;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Update default tool
|
|
241
|
+
*/
|
|
242
|
+
export function updateClaudeDefaultTool(
|
|
243
|
+
projectDir: string,
|
|
244
|
+
defaultTool: string
|
|
245
|
+
): ClaudeCliToolsConfig {
|
|
246
|
+
const config = loadClaudeCliTools(projectDir);
|
|
247
|
+
config.defaultTool = defaultTool;
|
|
248
|
+
saveClaudeCliTools(projectDir, config);
|
|
249
|
+
return config;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Add custom endpoint
|
|
254
|
+
*/
|
|
255
|
+
export function addClaudeCustomEndpoint(
|
|
256
|
+
projectDir: string,
|
|
257
|
+
endpoint: { id: string; name: string; enabled: boolean }
|
|
258
|
+
): ClaudeCliToolsConfig {
|
|
259
|
+
const config = loadClaudeCliTools(projectDir);
|
|
260
|
+
|
|
261
|
+
// Check if endpoint already exists
|
|
262
|
+
const existingIndex = config.customEndpoints.findIndex(e => e.id === endpoint.id);
|
|
263
|
+
if (existingIndex >= 0) {
|
|
264
|
+
config.customEndpoints[existingIndex] = endpoint;
|
|
265
|
+
} else {
|
|
266
|
+
config.customEndpoints.push(endpoint);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
saveClaudeCliTools(projectDir, config);
|
|
270
|
+
return config;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Remove custom endpoint
|
|
275
|
+
*/
|
|
276
|
+
export function removeClaudeCustomEndpoint(
|
|
277
|
+
projectDir: string,
|
|
278
|
+
endpointId: string
|
|
279
|
+
): ClaudeCliToolsConfig {
|
|
280
|
+
const config = loadClaudeCliTools(projectDir);
|
|
281
|
+
config.customEndpoints = config.customEndpoints.filter(e => e.id !== endpointId);
|
|
282
|
+
saveClaudeCliTools(projectDir, config);
|
|
283
|
+
return config;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Get config source info
|
|
288
|
+
*/
|
|
289
|
+
export function getClaudeCliToolsInfo(projectDir: string): {
|
|
290
|
+
projectPath: string;
|
|
291
|
+
globalPath: string;
|
|
292
|
+
activePath: string;
|
|
293
|
+
source: 'project' | 'global' | 'default';
|
|
294
|
+
} {
|
|
295
|
+
const resolved = resolveConfigPath(projectDir);
|
|
296
|
+
return {
|
|
297
|
+
projectPath: getProjectConfigPath(projectDir),
|
|
298
|
+
globalPath: getGlobalConfigPath(),
|
|
299
|
+
activePath: resolved.path,
|
|
300
|
+
source: resolved.source
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Update Code Index MCP provider and switch CLAUDE.md reference
|
|
306
|
+
* Strategy: Only modify global user-level CLAUDE.md (~/.claude/CLAUDE.md)
|
|
307
|
+
* This is consistent with Chinese response and Windows platform settings
|
|
308
|
+
*/
|
|
309
|
+
export function updateCodeIndexMcp(
|
|
310
|
+
projectDir: string,
|
|
311
|
+
provider: 'codexlens' | 'ace' | 'none'
|
|
312
|
+
): { success: boolean; error?: string; config?: ClaudeCliToolsConfig } {
|
|
313
|
+
try {
|
|
314
|
+
// Update config
|
|
315
|
+
const config = loadClaudeCliTools(projectDir);
|
|
316
|
+
config.settings.codeIndexMcp = provider;
|
|
317
|
+
saveClaudeCliTools(projectDir, config);
|
|
318
|
+
|
|
319
|
+
// Only update global CLAUDE.md (consistent with Chinese response / Windows platform)
|
|
320
|
+
const globalClaudeMdPath = path.join(os.homedir(), '.claude', 'CLAUDE.md');
|
|
321
|
+
|
|
322
|
+
// Define patterns for all formats
|
|
323
|
+
const codexlensPattern = /@~\/\.claude\/workflows\/context-tools\.md/g;
|
|
324
|
+
const acePattern = /@~\/\.claude\/workflows\/context-tools-ace\.md/g;
|
|
325
|
+
const nonePattern = /@~\/\.claude\/workflows\/context-tools-none\.md/g;
|
|
326
|
+
|
|
327
|
+
// Determine target file based on provider
|
|
328
|
+
const targetFile = provider === 'ace'
|
|
329
|
+
? '@~/.claude/workflows/context-tools-ace.md'
|
|
330
|
+
: provider === 'none'
|
|
331
|
+
? '@~/.claude/workflows/context-tools-none.md'
|
|
332
|
+
: '@~/.claude/workflows/context-tools.md';
|
|
333
|
+
|
|
334
|
+
if (!fs.existsSync(globalClaudeMdPath)) {
|
|
335
|
+
// If global CLAUDE.md doesn't exist, check project-level
|
|
336
|
+
const projectClaudeMdPath = path.join(projectDir, '.claude', 'CLAUDE.md');
|
|
337
|
+
if (fs.existsSync(projectClaudeMdPath)) {
|
|
338
|
+
let content = fs.readFileSync(projectClaudeMdPath, 'utf-8');
|
|
339
|
+
|
|
340
|
+
// Replace any existing pattern with the target
|
|
341
|
+
content = content.replace(codexlensPattern, targetFile);
|
|
342
|
+
content = content.replace(acePattern, targetFile);
|
|
343
|
+
content = content.replace(nonePattern, targetFile);
|
|
344
|
+
|
|
345
|
+
fs.writeFileSync(projectClaudeMdPath, content, 'utf-8');
|
|
346
|
+
console.log(`[claude-cli-tools] Updated project CLAUDE.md to use ${provider} (no global CLAUDE.md found)`);
|
|
347
|
+
}
|
|
348
|
+
} else {
|
|
349
|
+
// Update global CLAUDE.md (primary target)
|
|
350
|
+
let content = fs.readFileSync(globalClaudeMdPath, 'utf-8');
|
|
351
|
+
|
|
352
|
+
// Replace any existing pattern with the target
|
|
353
|
+
content = content.replace(codexlensPattern, targetFile);
|
|
354
|
+
content = content.replace(acePattern, targetFile);
|
|
355
|
+
content = content.replace(nonePattern, targetFile);
|
|
356
|
+
|
|
357
|
+
fs.writeFileSync(globalClaudeMdPath, content, 'utf-8');
|
|
358
|
+
console.log(`[claude-cli-tools] Updated global CLAUDE.md to use ${provider}`);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
return { success: true, config };
|
|
362
|
+
} catch (err) {
|
|
363
|
+
console.error('[claude-cli-tools] Error updating Code Index MCP:', err);
|
|
364
|
+
return { success: false, error: (err as Error).message };
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Get current Code Index MCP provider
|
|
370
|
+
*/
|
|
371
|
+
export function getCodeIndexMcp(projectDir: string): 'codexlens' | 'ace' | 'none' {
|
|
372
|
+
const config = loadClaudeCliTools(projectDir);
|
|
373
|
+
return config.settings.codeIndexMcp || 'codexlens';
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Get the context-tools file path based on provider
|
|
378
|
+
*/
|
|
379
|
+
export function getContextToolsPath(provider: 'codexlens' | 'ace' | 'none'): string {
|
|
380
|
+
switch (provider) {
|
|
381
|
+
case 'ace':
|
|
382
|
+
return 'context-tools-ace.md';
|
|
383
|
+
case 'none':
|
|
384
|
+
return 'context-tools-none.md';
|
|
385
|
+
default:
|
|
386
|
+
return 'context-tools.md';
|
|
387
|
+
}
|
|
388
|
+
}
|