claude-code-workflow 6.3.2 → 6.3.5
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 +9 -1
- package/.claude/commands/{clean.md → workflow/clean.md} +5 -5
- package/.claude/commands/workflow/docs/analyze.md +1467 -0
- package/.claude/commands/workflow/docs/copyright.md +1265 -0
- package/.claude/commands/workflow/lite-plan.md +1 -1
- package/.claude/commands/workflow/tools/conflict-resolution.md +76 -240
- package/.claude/commands/workflow/tools/task-generate-agent.md +81 -8
- package/.claude/skills/_shared/mermaid-utils.md +584 -0
- package/.claude/skills/copyright-docs/SKILL.md +132 -0
- package/.claude/skills/copyright-docs/phases/01-metadata-collection.md +78 -0
- package/.claude/skills/copyright-docs/phases/02-deep-analysis.md +454 -0
- package/.claude/skills/copyright-docs/phases/02.5-consolidation.md +192 -0
- package/.claude/skills/copyright-docs/phases/04-document-assembly.md +261 -0
- package/.claude/skills/copyright-docs/phases/05-compliance-refinement.md +192 -0
- package/.claude/skills/copyright-docs/specs/cpcc-requirements.md +121 -0
- package/.claude/skills/copyright-docs/templates/agent-base.md +200 -0
- package/.claude/skills/project-analyze/SKILL.md +162 -0
- package/.claude/skills/project-analyze/phases/01-requirements-discovery.md +79 -0
- package/.claude/skills/project-analyze/phases/02-project-exploration.md +75 -0
- package/.claude/skills/project-analyze/phases/03-deep-analysis.md +640 -0
- package/.claude/skills/project-analyze/phases/03.5-consolidation.md +208 -0
- package/.claude/skills/project-analyze/phases/04-report-generation.md +217 -0
- package/.claude/skills/project-analyze/phases/05-iterative-refinement.md +124 -0
- package/.claude/skills/project-analyze/specs/quality-standards.md +115 -0
- package/.claude/skills/project-analyze/specs/writing-style.md +152 -0
- package/.claude/workflows/cli-templates/schemas/conflict-resolution-schema.json +79 -65
- package/.claude/workflows/cli-tools-usage.md +515 -516
- package/README.md +11 -1
- package/ccw/dist/cli.d.ts.map +1 -1
- package/ccw/dist/cli.js +7 -1
- package/ccw/dist/cli.js.map +1 -1
- package/ccw/dist/commands/cli.d.ts +1 -1
- package/ccw/dist/commands/cli.d.ts.map +1 -1
- package/ccw/dist/commands/cli.js +116 -14
- package/ccw/dist/commands/cli.js.map +1 -1
- package/ccw/dist/core/routes/cli-routes.js +2 -2
- package/ccw/dist/core/routes/cli-routes.js.map +1 -1
- package/ccw/dist/tools/claude-cli-tools.d.ts +7 -3
- package/ccw/dist/tools/claude-cli-tools.d.ts.map +1 -1
- package/ccw/dist/tools/claude-cli-tools.js +31 -17
- package/ccw/dist/tools/claude-cli-tools.js.map +1 -1
- package/ccw/dist/tools/cli-executor.d.ts.map +1 -1
- package/ccw/dist/tools/cli-executor.js +19 -7
- package/ccw/dist/tools/cli-executor.js.map +1 -1
- package/ccw/dist/tools/cli-history-store.d.ts +33 -0
- package/ccw/dist/tools/cli-history-store.d.ts.map +1 -1
- package/ccw/dist/tools/cli-history-store.js +89 -5
- package/ccw/dist/tools/cli-history-store.js.map +1 -1
- package/ccw/dist/tools/smart-search.d.ts +25 -0
- package/ccw/dist/tools/smart-search.d.ts.map +1 -1
- package/ccw/dist/tools/smart-search.js +121 -17
- package/ccw/dist/tools/smart-search.js.map +1 -1
- package/ccw/src/cli.ts +264 -258
- package/ccw/src/commands/cli.ts +1009 -884
- package/ccw/src/core/routes/cli-routes.ts +3 -3
- package/ccw/src/templates/dashboard-js/components/cli-history.js +40 -13
- package/ccw/src/templates/dashboard-js/components/cli-status.js +26 -2
- package/ccw/src/templates/dashboard-js/views/cli-manager.js +5 -0
- package/ccw/src/templates/dashboard-js/views/history.js +19 -4
- package/ccw/src/tools/claude-cli-tools.ts +37 -20
- package/ccw/src/tools/cli-executor.ts +20 -7
- package/ccw/src/tools/cli-history-store.ts +125 -5
- package/ccw/src/tools/smart-search.ts +157 -16
- package/codex-lens/src/codexlens/__pycache__/config.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/config.py +8 -0
- package/codex-lens/src/codexlens/search/__pycache__/chain_search.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/hybrid_search.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/ranking.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/chain_search.py +71 -1
- package/codex-lens/src/codexlens/search/hybrid_search.py +144 -11
- package/codex-lens/src/codexlens/search/ranking.py +540 -274
- package/codex-lens/src/codexlens/semantic/__pycache__/chunker.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/chunker.py +55 -10
- package/codex-lens/src/codexlens/storage/__pycache__/dir_index.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/global_index.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/index_tree.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/dir_index.py +1888 -1850
- package/codex-lens/src/codexlens/storage/global_index.py +365 -0
- package/codex-lens/src/codexlens/storage/index_tree.py +83 -10
- package/package.json +2 -2
|
@@ -769,9 +769,9 @@ export async function handleCliRoutes(ctx: RouteContext): Promise<boolean> {
|
|
|
769
769
|
if (pathname === '/api/cli/code-index-mcp' && req.method === 'PUT') {
|
|
770
770
|
handlePostRequest(req, res, async (body: unknown) => {
|
|
771
771
|
try {
|
|
772
|
-
const { provider } = body as { provider: 'codexlens' | 'ace' };
|
|
773
|
-
if (!provider || !['codexlens', 'ace'].includes(provider)) {
|
|
774
|
-
return { error: 'Invalid provider. Must be "codexlens" or "
|
|
772
|
+
const { provider } = body as { provider: 'codexlens' | 'ace' | 'none' };
|
|
773
|
+
if (!provider || !['codexlens', 'ace', 'none'].includes(provider)) {
|
|
774
|
+
return { error: 'Invalid provider. Must be "codexlens", "ace", or "none"', status: 400 };
|
|
775
775
|
}
|
|
776
776
|
|
|
777
777
|
const result = updateCodeIndexMcp(initialPath, provider);
|
|
@@ -15,7 +15,9 @@ async function loadCliHistory(options = {}) {
|
|
|
15
15
|
const { limit = cliHistoryLimit, tool = cliHistoryFilter, status = null } = options;
|
|
16
16
|
|
|
17
17
|
// Use history-native endpoint to get native session info
|
|
18
|
-
|
|
18
|
+
// Use recursiveQueryEnabled setting (from cli-status.js) to control recursive query
|
|
19
|
+
const recursive = typeof recursiveQueryEnabled !== 'undefined' ? recursiveQueryEnabled : true;
|
|
20
|
+
let url = `/api/cli/history-native?path=${encodeURIComponent(projectPath)}&limit=${limit}&recursive=${recursive}`;
|
|
19
21
|
if (tool) url += `&tool=${tool}`;
|
|
20
22
|
if (status) url += `&status=${status}`;
|
|
21
23
|
if (cliHistorySearch) url += `&search=${encodeURIComponent(cliHistorySearch)}`;
|
|
@@ -36,9 +38,12 @@ async function loadCliHistory(options = {}) {
|
|
|
36
38
|
async function loadNativeSessionContent(executionId, sourceDir) {
|
|
37
39
|
try {
|
|
38
40
|
// If sourceDir provided, use it to build the correct path
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
// Check if sourceDir is absolute path (contains : or starts with /)
|
|
42
|
+
let basePath = projectPath;
|
|
43
|
+
if (sourceDir && sourceDir !== '.') {
|
|
44
|
+
const isAbsolute = sourceDir.includes(':') || sourceDir.startsWith('/');
|
|
45
|
+
basePath = isAbsolute ? sourceDir : projectPath + '/' + sourceDir;
|
|
46
|
+
}
|
|
42
47
|
const url = `/api/cli/native-session?path=${encodeURIComponent(basePath)}&id=${encodeURIComponent(executionId)}`;
|
|
43
48
|
const response = await fetch(url);
|
|
44
49
|
if (!response.ok) return null;
|
|
@@ -65,9 +70,12 @@ async function loadEnrichedConversation(executionId) {
|
|
|
65
70
|
async function loadExecutionDetail(executionId, sourceDir) {
|
|
66
71
|
try {
|
|
67
72
|
// If sourceDir provided, use it to build the correct path
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
// Check if sourceDir is absolute path (contains : or starts with /)
|
|
74
|
+
let basePath = projectPath;
|
|
75
|
+
if (sourceDir && sourceDir !== '.') {
|
|
76
|
+
const isAbsolute = sourceDir.includes(':') || sourceDir.startsWith('/');
|
|
77
|
+
basePath = isAbsolute ? sourceDir : projectPath + '/' + sourceDir;
|
|
78
|
+
}
|
|
71
79
|
const url = `/api/cli/execution?path=${encodeURIComponent(basePath)}&id=${encodeURIComponent(executionId)}`;
|
|
72
80
|
const response = await fetch(url);
|
|
73
81
|
if (!response.ok) throw new Error('Execution not found');
|
|
@@ -137,8 +145,9 @@ function renderCliHistory() {
|
|
|
137
145
|
</span>`
|
|
138
146
|
: '';
|
|
139
147
|
|
|
140
|
-
//
|
|
141
|
-
|
|
148
|
+
// Normalize and escape sourceDir for use in onclick
|
|
149
|
+
// Convert backslashes to forward slashes to prevent JS escape issues in onclick
|
|
150
|
+
const sourceDirEscaped = exec.sourceDir ? exec.sourceDir.replace(/\\/g, '/').replace(/'/g, "\\'") : '';
|
|
142
151
|
|
|
143
152
|
return `
|
|
144
153
|
<div class="cli-history-item ${hasNative ? 'has-native' : ''}">
|
|
@@ -155,11 +164,14 @@ function renderCliHistory() {
|
|
|
155
164
|
<div class="cli-history-meta">
|
|
156
165
|
<span><i data-lucide="clock" class="w-3 h-3"></i> ${timeAgo}</span>
|
|
157
166
|
<span><i data-lucide="timer" class="w-3 h-3"></i> ${duration}</span>
|
|
158
|
-
<span><i data-lucide="hash" class="w-3 h-3"></i> ${exec.id.split('-')
|
|
167
|
+
<span title="${exec.id}"><i data-lucide="hash" class="w-3 h-3"></i> ${exec.id.substring(0, 13)}...${exec.id.split('-').pop()}</span>
|
|
159
168
|
${turnBadge}
|
|
160
169
|
</div>
|
|
161
170
|
</div>
|
|
162
171
|
<div class="cli-history-actions">
|
|
172
|
+
<button class="btn-icon" onclick="event.stopPropagation(); copyCliExecutionId('${exec.id}')" title="Copy ID">
|
|
173
|
+
<i data-lucide="copy" class="w-3.5 h-3.5"></i>
|
|
174
|
+
</button>
|
|
163
175
|
${hasNative ? `
|
|
164
176
|
<button class="btn-icon" onclick="event.stopPropagation(); showNativeSessionDetail('${exec.id}', '${sourceDirEscaped}')" title="View Native Session">
|
|
165
177
|
<i data-lucide="file-json" class="w-3.5 h-3.5"></i>
|
|
@@ -431,9 +443,12 @@ function confirmDeleteExecution(executionId, sourceDir) {
|
|
|
431
443
|
async function deleteExecution(executionId, sourceDir) {
|
|
432
444
|
try {
|
|
433
445
|
// Build correct path - use sourceDir if provided for recursive items
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
446
|
+
// Check if sourceDir is absolute path (contains : or starts with /)
|
|
447
|
+
let basePath = projectPath;
|
|
448
|
+
if (sourceDir && sourceDir !== '.') {
|
|
449
|
+
const isAbsolute = sourceDir.includes(':') || sourceDir.startsWith('/');
|
|
450
|
+
basePath = isAbsolute ? sourceDir : projectPath + '/' + sourceDir;
|
|
451
|
+
}
|
|
437
452
|
|
|
438
453
|
const response = await fetch(`/api/cli/execution?path=${encodeURIComponent(basePath)}&id=${encodeURIComponent(executionId)}`, {
|
|
439
454
|
method: 'DELETE'
|
|
@@ -461,6 +476,18 @@ async function deleteExecution(executionId, sourceDir) {
|
|
|
461
476
|
}
|
|
462
477
|
|
|
463
478
|
// ========== Copy Functions ==========
|
|
479
|
+
async function copyCliExecutionId(executionId) {
|
|
480
|
+
if (navigator.clipboard) {
|
|
481
|
+
try {
|
|
482
|
+
await navigator.clipboard.writeText(executionId);
|
|
483
|
+
showRefreshToast('ID copied: ' + executionId, 'success');
|
|
484
|
+
} catch (err) {
|
|
485
|
+
console.error('Failed to copy ID:', err);
|
|
486
|
+
showRefreshToast('Failed to copy ID', 'error');
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
464
491
|
async function copyExecutionPrompt(executionId) {
|
|
465
492
|
const detail = await loadExecutionDetail(executionId);
|
|
466
493
|
if (!detail) {
|
|
@@ -21,9 +21,24 @@ let nativeResumeEnabled = localStorage.getItem('ccw-native-resume') !== 'false';
|
|
|
21
21
|
// Recursive Query settings (for hierarchical storage aggregation)
|
|
22
22
|
let recursiveQueryEnabled = localStorage.getItem('ccw-recursive-query') !== 'false'; // default true
|
|
23
23
|
|
|
24
|
-
// Code Index MCP provider (codexlens or
|
|
24
|
+
// Code Index MCP provider (codexlens, ace, or none)
|
|
25
25
|
let codeIndexMcpProvider = 'codexlens';
|
|
26
26
|
|
|
27
|
+
// ========== Helper Functions ==========
|
|
28
|
+
/**
|
|
29
|
+
* Get the context-tools filename based on provider
|
|
30
|
+
*/
|
|
31
|
+
function getContextToolsFileName(provider) {
|
|
32
|
+
switch (provider) {
|
|
33
|
+
case 'ace':
|
|
34
|
+
return 'context-tools-ace.md';
|
|
35
|
+
case 'none':
|
|
36
|
+
return 'context-tools-none.md';
|
|
37
|
+
default:
|
|
38
|
+
return 'context-tools.md';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
27
42
|
// ========== Initialization ==========
|
|
28
43
|
function initCliStatus() {
|
|
29
44
|
// Load all statuses in one call using aggregated endpoint
|
|
@@ -637,9 +652,17 @@ function renderCliStatus() {
|
|
|
637
652
|
onclick="setCodeIndexMcpProvider('ace')">
|
|
638
653
|
ACE
|
|
639
654
|
</button>
|
|
655
|
+
<button class="code-mcp-btn px-3 py-1.5 text-xs font-medium rounded-md transition-all ${codeIndexMcpProvider === 'none' ? 'bg-primary text-primary-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground'}"
|
|
656
|
+
onclick="setCodeIndexMcpProvider('none')">
|
|
657
|
+
None
|
|
658
|
+
</button>
|
|
640
659
|
</div>
|
|
641
660
|
</div>
|
|
642
661
|
<p class="cli-setting-desc">Code search provider (updates CLAUDE.md context-tools reference)</p>
|
|
662
|
+
<p class="cli-setting-desc text-xs text-muted-foreground mt-1">
|
|
663
|
+
<i data-lucide="file-text" class="w-3 h-3 inline-block mr-1"></i>
|
|
664
|
+
Current: <code class="bg-muted px-1 rounded">${getContextToolsFileName(codeIndexMcpProvider)}</code>
|
|
665
|
+
</p>
|
|
643
666
|
</div>
|
|
644
667
|
</div>
|
|
645
668
|
</div>
|
|
@@ -775,7 +798,8 @@ async function setCodeIndexMcpProvider(provider) {
|
|
|
775
798
|
if (window.claudeCliToolsConfig && window.claudeCliToolsConfig.settings) {
|
|
776
799
|
window.claudeCliToolsConfig.settings.codeIndexMcp = provider;
|
|
777
800
|
}
|
|
778
|
-
|
|
801
|
+
const providerName = provider === 'ace' ? 'ACE (Augment)' : provider === 'none' ? 'None (Built-in only)' : 'CodexLens';
|
|
802
|
+
showRefreshToast(`Code Index MCP switched to ${providerName}`, 'success');
|
|
779
803
|
// Re-render both CLI status and settings section
|
|
780
804
|
if (typeof renderCliStatus === 'function') renderCliStatus();
|
|
781
805
|
if (typeof renderCliSettingsSection === 'function') renderCliSettingsSection();
|
|
@@ -996,9 +996,14 @@ function renderCliSettingsSection() {
|
|
|
996
996
|
'<select class="cli-setting-select" onchange="setCodeIndexMcpProvider(this.value)">' +
|
|
997
997
|
'<option value="codexlens"' + (codeIndexMcpProvider === 'codexlens' ? ' selected' : '') + '>CodexLens</option>' +
|
|
998
998
|
'<option value="ace"' + (codeIndexMcpProvider === 'ace' ? ' selected' : '') + '>ACE (Augment)</option>' +
|
|
999
|
+
'<option value="none"' + (codeIndexMcpProvider === 'none' ? ' selected' : '') + '>None (Built-in)</option>' +
|
|
999
1000
|
'</select>' +
|
|
1000
1001
|
'</div>' +
|
|
1001
1002
|
'<p class="cli-setting-desc">' + t('cli.codeIndexMcpDesc') + '</p>' +
|
|
1003
|
+
'<p class="cli-setting-desc text-xs text-muted-foreground">' +
|
|
1004
|
+
'<i data-lucide="file-text" class="w-3 h-3 inline-block mr-1"></i>' +
|
|
1005
|
+
'Current: <code class="bg-muted px-1 rounded">' + getContextToolsFileName(codeIndexMcpProvider) + '</code>' +
|
|
1006
|
+
'</p>' +
|
|
1002
1007
|
'</div>' +
|
|
1003
1008
|
'</div>';
|
|
1004
1009
|
|
|
@@ -69,8 +69,10 @@ async function renderCliHistoryView() {
|
|
|
69
69
|
'</div>'
|
|
70
70
|
: '';
|
|
71
71
|
|
|
72
|
+
// Normalize sourceDir: convert backslashes to forward slashes for safe onclick handling
|
|
73
|
+
var normalizedSourceDir = (exec.sourceDir || '').replace(/\\/g, '/');
|
|
72
74
|
historyHtml += '<div class="history-item' + (isSelected ? ' history-item-selected' : '') + '" ' +
|
|
73
|
-
'onclick="' + (isMultiSelectMode ? 'toggleExecutionSelection(\'' + exec.id + '\')' : 'showExecutionDetail(\'' + exec.id +
|
|
75
|
+
'onclick="' + (isMultiSelectMode ? 'toggleExecutionSelection(\'' + exec.id + '\')' : 'showExecutionDetail(\'' + exec.id + '\', \'' + normalizedSourceDir.replace(/'/g, "\\'") + '\')') + '">' +
|
|
74
76
|
checkboxHtml +
|
|
75
77
|
'<div class="history-item-main">' +
|
|
76
78
|
'<div class="history-item-header">' +
|
|
@@ -87,14 +89,17 @@ async function renderCliHistoryView() {
|
|
|
87
89
|
'<div class="history-item-meta">' +
|
|
88
90
|
'<span class="history-time"><i data-lucide="clock" class="w-3 h-3"></i> ' + timeAgo + '</span>' +
|
|
89
91
|
'<span class="history-duration"><i data-lucide="timer" class="w-3 h-3"></i> ' + duration + '</span>' +
|
|
90
|
-
'<span class="history-id"><i data-lucide="hash" class="w-3 h-3"></i> ' + exec.id.split('-')
|
|
92
|
+
'<span class="history-id" title="' + exec.id + '"><i data-lucide="hash" class="w-3 h-3"></i> ' + exec.id.substring(0, 13) + '...' + exec.id.split('-').pop() + '</span>' +
|
|
91
93
|
'</div>' +
|
|
92
94
|
'</div>' +
|
|
93
95
|
'<div class="history-item-actions">' +
|
|
94
|
-
'<button class="btn-icon" onclick="event.stopPropagation();
|
|
96
|
+
'<button class="btn-icon" onclick="event.stopPropagation(); copyExecutionId(\'' + exec.id + '\')" title="Copy ID">' +
|
|
97
|
+
'<i data-lucide="copy" class="w-4 h-4"></i>' +
|
|
98
|
+
'</button>' +
|
|
99
|
+
'<button class="btn-icon" onclick="event.stopPropagation(); showExecutionDetail(\'' + exec.id + '\', \'' + normalizedSourceDir.replace(/'/g, "\\'") + '\')" title="View Details">' +
|
|
95
100
|
'<i data-lucide="eye" class="w-4 h-4"></i>' +
|
|
96
101
|
'</button>' +
|
|
97
|
-
'<button class="btn-icon btn-danger" onclick="event.stopPropagation(); confirmDeleteExecution(\'' + exec.id +
|
|
102
|
+
'<button class="btn-icon btn-danger" onclick="event.stopPropagation(); confirmDeleteExecution(\'' + exec.id + '\', \'' + normalizedSourceDir.replace(/'/g, "\\'") + '\')" title="Delete">' +
|
|
98
103
|
'<i data-lucide="trash-2" class="w-4 h-4"></i>' +
|
|
99
104
|
'</button>' +
|
|
100
105
|
'</div>' +
|
|
@@ -179,6 +184,16 @@ async function renderCliHistoryView() {
|
|
|
179
184
|
}
|
|
180
185
|
|
|
181
186
|
// ========== Actions ==========
|
|
187
|
+
async function copyExecutionId(executionId) {
|
|
188
|
+
try {
|
|
189
|
+
await navigator.clipboard.writeText(executionId);
|
|
190
|
+
showRefreshToast('ID copied: ' + executionId, 'success');
|
|
191
|
+
} catch (err) {
|
|
192
|
+
console.error('Failed to copy ID:', err);
|
|
193
|
+
showRefreshToast('Failed to copy ID', 'error');
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
182
197
|
async function filterCliHistoryView(tool) {
|
|
183
198
|
cliHistoryFilter = tool || null;
|
|
184
199
|
await loadCliHistory();
|
|
@@ -42,7 +42,7 @@ export interface ClaudeCliToolsConfig {
|
|
|
42
42
|
nativeResume: boolean;
|
|
43
43
|
recursiveQuery: boolean;
|
|
44
44
|
cache: ClaudeCacheSettings;
|
|
45
|
-
codeIndexMcp: 'codexlens' | 'ace'; // Code Index MCP provider
|
|
45
|
+
codeIndexMcp: 'codexlens' | 'ace' | 'none'; // Code Index MCP provider
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
48
|
|
|
@@ -308,7 +308,7 @@ export function getClaudeCliToolsInfo(projectDir: string): {
|
|
|
308
308
|
*/
|
|
309
309
|
export function updateCodeIndexMcp(
|
|
310
310
|
projectDir: string,
|
|
311
|
-
provider: 'codexlens' | 'ace'
|
|
311
|
+
provider: 'codexlens' | 'ace' | 'none'
|
|
312
312
|
): { success: boolean; error?: string; config?: ClaudeCliToolsConfig } {
|
|
313
313
|
try {
|
|
314
314
|
// Update config
|
|
@@ -319,21 +319,28 @@ export function updateCodeIndexMcp(
|
|
|
319
319
|
// Only update global CLAUDE.md (consistent with Chinese response / Windows platform)
|
|
320
320
|
const globalClaudeMdPath = path.join(os.homedir(), '.claude', 'CLAUDE.md');
|
|
321
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
|
+
|
|
322
334
|
if (!fs.existsSync(globalClaudeMdPath)) {
|
|
323
335
|
// If global CLAUDE.md doesn't exist, check project-level
|
|
324
336
|
const projectClaudeMdPath = path.join(projectDir, '.claude', 'CLAUDE.md');
|
|
325
337
|
if (fs.existsSync(projectClaudeMdPath)) {
|
|
326
338
|
let content = fs.readFileSync(projectClaudeMdPath, 'utf-8');
|
|
327
339
|
|
|
328
|
-
//
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
if (provider === 'ace') {
|
|
333
|
-
content = content.replace(codexlensPattern, '@~/.claude/workflows/context-tools-ace.md');
|
|
334
|
-
} else {
|
|
335
|
-
content = content.replace(acePattern, '@~/.claude/workflows/context-tools.md');
|
|
336
|
-
}
|
|
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);
|
|
337
344
|
|
|
338
345
|
fs.writeFileSync(projectClaudeMdPath, content, 'utf-8');
|
|
339
346
|
console.log(`[claude-cli-tools] Updated project CLAUDE.md to use ${provider} (no global CLAUDE.md found)`);
|
|
@@ -342,14 +349,10 @@ export function updateCodeIndexMcp(
|
|
|
342
349
|
// Update global CLAUDE.md (primary target)
|
|
343
350
|
let content = fs.readFileSync(globalClaudeMdPath, 'utf-8');
|
|
344
351
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
content = content.replace(codexlensPattern, '@~/.claude/workflows/context-tools-ace.md');
|
|
350
|
-
} else {
|
|
351
|
-
content = content.replace(acePattern, '@~/.claude/workflows/context-tools.md');
|
|
352
|
-
}
|
|
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);
|
|
353
356
|
|
|
354
357
|
fs.writeFileSync(globalClaudeMdPath, content, 'utf-8');
|
|
355
358
|
console.log(`[claude-cli-tools] Updated global CLAUDE.md to use ${provider}`);
|
|
@@ -365,7 +368,21 @@ export function updateCodeIndexMcp(
|
|
|
365
368
|
/**
|
|
366
369
|
* Get current Code Index MCP provider
|
|
367
370
|
*/
|
|
368
|
-
export function getCodeIndexMcp(projectDir: string): 'codexlens' | 'ace' {
|
|
371
|
+
export function getCodeIndexMcp(projectDir: string): 'codexlens' | 'ace' | 'none' {
|
|
369
372
|
const config = loadClaudeCliTools(projectDir);
|
|
370
373
|
return config.settings.codeIndexMcp || 'codexlens';
|
|
371
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
|
+
}
|
|
@@ -73,6 +73,7 @@ const ParamsSchema = z.object({
|
|
|
73
73
|
noNative: z.boolean().optional(), // Force prompt concatenation instead of native resume
|
|
74
74
|
category: z.enum(['user', 'internal', 'insight']).default('user'), // Execution category for tracking
|
|
75
75
|
parentExecutionId: z.string().optional(), // Parent execution ID for fork/retry scenarios
|
|
76
|
+
stream: z.boolean().default(false), // false = cache full output (default), true = stream output via callback
|
|
76
77
|
});
|
|
77
78
|
|
|
78
79
|
// Execution category types
|
|
@@ -863,24 +864,36 @@ async function executeCliTool(
|
|
|
863
864
|
const endTime = Date.now();
|
|
864
865
|
const duration = endTime - startTime;
|
|
865
866
|
|
|
866
|
-
// Determine status
|
|
867
|
+
// Determine status - prioritize output content over exit code
|
|
867
868
|
let status: 'success' | 'error' | 'timeout' = 'success';
|
|
868
869
|
if (timedOut) {
|
|
869
870
|
status = 'timeout';
|
|
870
871
|
} else if (code !== 0) {
|
|
871
|
-
//
|
|
872
|
-
if
|
|
872
|
+
// Non-zero exit code doesn't always mean failure
|
|
873
|
+
// Check if there's valid output (AI response) - treat as success
|
|
874
|
+
const hasValidOutput = stdout.trim().length > 0;
|
|
875
|
+
const hasFatalError = stderr.includes('FATAL') ||
|
|
876
|
+
stderr.includes('Authentication failed') ||
|
|
877
|
+
stderr.includes('API key') ||
|
|
878
|
+
stderr.includes('rate limit exceeded');
|
|
879
|
+
|
|
880
|
+
if (hasValidOutput && !hasFatalError) {
|
|
881
|
+
// Has output and no fatal errors - treat as success despite exit code
|
|
873
882
|
status = 'success';
|
|
874
883
|
} else {
|
|
875
884
|
status = 'error';
|
|
876
885
|
}
|
|
877
886
|
}
|
|
878
887
|
|
|
879
|
-
// Create new turn
|
|
888
|
+
// Create new turn - cache full output when not streaming (default)
|
|
889
|
+
const shouldCache = !parsed.data.stream;
|
|
880
890
|
const newTurnOutput = {
|
|
881
|
-
stdout: stdout.substring(0, 10240), // Truncate to 10KB
|
|
882
|
-
stderr: stderr.substring(0, 2048), // Truncate to 2KB
|
|
883
|
-
truncated: stdout.length > 10240 || stderr.length > 2048
|
|
891
|
+
stdout: stdout.substring(0, 10240), // Truncate preview to 10KB
|
|
892
|
+
stderr: stderr.substring(0, 2048), // Truncate preview to 2KB
|
|
893
|
+
truncated: stdout.length > 10240 || stderr.length > 2048,
|
|
894
|
+
cached: shouldCache,
|
|
895
|
+
stdout_full: shouldCache ? stdout : undefined,
|
|
896
|
+
stderr_full: shouldCache ? stderr : undefined
|
|
884
897
|
};
|
|
885
898
|
|
|
886
899
|
// Determine base turn number for merge scenarios
|
|
@@ -23,6 +23,9 @@ export interface ConversationTurn {
|
|
|
23
23
|
stdout: string;
|
|
24
24
|
stderr: string;
|
|
25
25
|
truncated: boolean;
|
|
26
|
+
cached?: boolean;
|
|
27
|
+
stdout_full?: string;
|
|
28
|
+
stderr_full?: string;
|
|
26
29
|
};
|
|
27
30
|
}
|
|
28
31
|
|
|
@@ -315,6 +318,28 @@ export class CliHistoryStore {
|
|
|
315
318
|
} catch (indexErr) {
|
|
316
319
|
console.warn('[CLI History] Turns timestamp index creation warning:', (indexErr as Error).message);
|
|
317
320
|
}
|
|
321
|
+
|
|
322
|
+
// Add cached output columns to turns table for non-streaming mode
|
|
323
|
+
const turnsInfo = this.db.prepare('PRAGMA table_info(turns)').all() as Array<{ name: string }>;
|
|
324
|
+
const hasCached = turnsInfo.some(col => col.name === 'cached');
|
|
325
|
+
const hasStdoutFull = turnsInfo.some(col => col.name === 'stdout_full');
|
|
326
|
+
const hasStderrFull = turnsInfo.some(col => col.name === 'stderr_full');
|
|
327
|
+
|
|
328
|
+
if (!hasCached) {
|
|
329
|
+
console.log('[CLI History] Migrating database: adding cached column to turns table...');
|
|
330
|
+
this.db.exec('ALTER TABLE turns ADD COLUMN cached INTEGER DEFAULT 0;');
|
|
331
|
+
console.log('[CLI History] Migration complete: cached column added');
|
|
332
|
+
}
|
|
333
|
+
if (!hasStdoutFull) {
|
|
334
|
+
console.log('[CLI History] Migrating database: adding stdout_full column to turns table...');
|
|
335
|
+
this.db.exec('ALTER TABLE turns ADD COLUMN stdout_full TEXT;');
|
|
336
|
+
console.log('[CLI History] Migration complete: stdout_full column added');
|
|
337
|
+
}
|
|
338
|
+
if (!hasStderrFull) {
|
|
339
|
+
console.log('[CLI History] Migrating database: adding stderr_full column to turns table...');
|
|
340
|
+
this.db.exec('ALTER TABLE turns ADD COLUMN stderr_full TEXT;');
|
|
341
|
+
console.log('[CLI History] Migration complete: stderr_full column added');
|
|
342
|
+
}
|
|
318
343
|
} catch (err) {
|
|
319
344
|
console.error('[CLI History] Migration error:', (err as Error).message);
|
|
320
345
|
// Don't throw - allow the store to continue working with existing schema
|
|
@@ -421,8 +446,8 @@ export class CliHistoryStore {
|
|
|
421
446
|
`);
|
|
422
447
|
|
|
423
448
|
const upsertTurn = this.db.prepare(`
|
|
424
|
-
INSERT INTO turns (conversation_id, turn_number, timestamp, prompt, duration_ms, status, exit_code, stdout, stderr, truncated)
|
|
425
|
-
VALUES (@conversation_id, @turn_number, @timestamp, @prompt, @duration_ms, @status, @exit_code, @stdout, @stderr, @truncated)
|
|
449
|
+
INSERT INTO turns (conversation_id, turn_number, timestamp, prompt, duration_ms, status, exit_code, stdout, stderr, truncated, cached, stdout_full, stderr_full)
|
|
450
|
+
VALUES (@conversation_id, @turn_number, @timestamp, @prompt, @duration_ms, @status, @exit_code, @stdout, @stderr, @truncated, @cached, @stdout_full, @stderr_full)
|
|
426
451
|
ON CONFLICT(conversation_id, turn_number) DO UPDATE SET
|
|
427
452
|
timestamp = @timestamp,
|
|
428
453
|
prompt = @prompt,
|
|
@@ -431,7 +456,10 @@ export class CliHistoryStore {
|
|
|
431
456
|
exit_code = @exit_code,
|
|
432
457
|
stdout = @stdout,
|
|
433
458
|
stderr = @stderr,
|
|
434
|
-
truncated = @truncated
|
|
459
|
+
truncated = @truncated,
|
|
460
|
+
cached = @cached,
|
|
461
|
+
stdout_full = @stdout_full,
|
|
462
|
+
stderr_full = @stderr_full
|
|
435
463
|
`);
|
|
436
464
|
|
|
437
465
|
const transaction = this.db.transaction(() => {
|
|
@@ -463,7 +491,10 @@ export class CliHistoryStore {
|
|
|
463
491
|
exit_code: turn.exit_code,
|
|
464
492
|
stdout: turn.output.stdout,
|
|
465
493
|
stderr: turn.output.stderr,
|
|
466
|
-
truncated: turn.output.truncated ? 1 : 0
|
|
494
|
+
truncated: turn.output.truncated ? 1 : 0,
|
|
495
|
+
cached: turn.output.cached ? 1 : 0,
|
|
496
|
+
stdout_full: turn.output.stdout_full || null,
|
|
497
|
+
stderr_full: turn.output.stderr_full || null
|
|
467
498
|
});
|
|
468
499
|
}
|
|
469
500
|
});
|
|
@@ -507,7 +538,10 @@ export class CliHistoryStore {
|
|
|
507
538
|
output: {
|
|
508
539
|
stdout: t.stdout || '',
|
|
509
540
|
stderr: t.stderr || '',
|
|
510
|
-
truncated: !!t.truncated
|
|
541
|
+
truncated: !!t.truncated,
|
|
542
|
+
cached: !!t.cached,
|
|
543
|
+
stdout_full: t.stdout_full || undefined,
|
|
544
|
+
stderr_full: t.stderr_full || undefined
|
|
511
545
|
}
|
|
512
546
|
}))
|
|
513
547
|
};
|
|
@@ -533,6 +567,92 @@ export class CliHistoryStore {
|
|
|
533
567
|
};
|
|
534
568
|
}
|
|
535
569
|
|
|
570
|
+
/**
|
|
571
|
+
* Get paginated cached output for a conversation turn
|
|
572
|
+
* @param conversationId - Conversation ID
|
|
573
|
+
* @param turnNumber - Turn number (default: latest turn)
|
|
574
|
+
* @param options - Pagination options
|
|
575
|
+
*/
|
|
576
|
+
getCachedOutput(
|
|
577
|
+
conversationId: string,
|
|
578
|
+
turnNumber?: number,
|
|
579
|
+
options: {
|
|
580
|
+
offset?: number; // Character offset (default: 0)
|
|
581
|
+
limit?: number; // Max characters to return (default: 10000)
|
|
582
|
+
outputType?: 'stdout' | 'stderr' | 'both'; // Which output to fetch
|
|
583
|
+
} = {}
|
|
584
|
+
): {
|
|
585
|
+
conversationId: string;
|
|
586
|
+
turnNumber: number;
|
|
587
|
+
stdout?: { content: string; totalBytes: number; offset: number; hasMore: boolean };
|
|
588
|
+
stderr?: { content: string; totalBytes: number; offset: number; hasMore: boolean };
|
|
589
|
+
cached: boolean;
|
|
590
|
+
prompt: string;
|
|
591
|
+
status: string;
|
|
592
|
+
timestamp: string;
|
|
593
|
+
} | null {
|
|
594
|
+
const { offset = 0, limit = 10000, outputType = 'both' } = options;
|
|
595
|
+
|
|
596
|
+
// Get turn (latest if not specified)
|
|
597
|
+
let turn;
|
|
598
|
+
if (turnNumber !== undefined) {
|
|
599
|
+
turn = this.db.prepare(`
|
|
600
|
+
SELECT * FROM turns WHERE conversation_id = ? AND turn_number = ?
|
|
601
|
+
`).get(conversationId, turnNumber) as any;
|
|
602
|
+
} else {
|
|
603
|
+
turn = this.db.prepare(`
|
|
604
|
+
SELECT * FROM turns WHERE conversation_id = ? ORDER BY turn_number DESC LIMIT 1
|
|
605
|
+
`).get(conversationId) as any;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
if (!turn) return null;
|
|
609
|
+
|
|
610
|
+
const result: {
|
|
611
|
+
conversationId: string;
|
|
612
|
+
turnNumber: number;
|
|
613
|
+
stdout?: { content: string; totalBytes: number; offset: number; hasMore: boolean };
|
|
614
|
+
stderr?: { content: string; totalBytes: number; offset: number; hasMore: boolean };
|
|
615
|
+
cached: boolean;
|
|
616
|
+
prompt: string;
|
|
617
|
+
status: string;
|
|
618
|
+
timestamp: string;
|
|
619
|
+
} = {
|
|
620
|
+
conversationId,
|
|
621
|
+
turnNumber: turn.turn_number,
|
|
622
|
+
cached: !!turn.cached,
|
|
623
|
+
prompt: turn.prompt,
|
|
624
|
+
status: turn.status,
|
|
625
|
+
timestamp: turn.timestamp
|
|
626
|
+
};
|
|
627
|
+
|
|
628
|
+
// Use full output if cached, otherwise use truncated
|
|
629
|
+
if (outputType === 'stdout' || outputType === 'both') {
|
|
630
|
+
const fullStdout = turn.cached ? (turn.stdout_full || '') : (turn.stdout || '');
|
|
631
|
+
const totalBytes = fullStdout.length;
|
|
632
|
+
const content = fullStdout.substring(offset, offset + limit);
|
|
633
|
+
result.stdout = {
|
|
634
|
+
content,
|
|
635
|
+
totalBytes,
|
|
636
|
+
offset,
|
|
637
|
+
hasMore: offset + limit < totalBytes
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
if (outputType === 'stderr' || outputType === 'both') {
|
|
642
|
+
const fullStderr = turn.cached ? (turn.stderr_full || '') : (turn.stderr || '');
|
|
643
|
+
const totalBytes = fullStderr.length;
|
|
644
|
+
const content = fullStderr.substring(offset, offset + limit);
|
|
645
|
+
result.stderr = {
|
|
646
|
+
content,
|
|
647
|
+
totalBytes,
|
|
648
|
+
offset,
|
|
649
|
+
hasMore: offset + limit < totalBytes
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
return result;
|
|
654
|
+
}
|
|
655
|
+
|
|
536
656
|
/**
|
|
537
657
|
* Query execution history
|
|
538
658
|
*/
|