claude-code-workflow 6.2.7 → 6.3.0
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 +16 -1
- package/.claude/workflows/cli-templates/protocols/analysis-protocol.md +11 -4
- package/.claude/workflows/cli-templates/protocols/write-protocol.md +10 -75
- package/.claude/workflows/cli-tools-usage.md +14 -24
- package/.codex/AGENTS.md +51 -1
- package/.codex/prompts/compact.md +378 -0
- package/.gemini/GEMINI.md +57 -20
- package/ccw/dist/cli.d.ts.map +1 -1
- package/ccw/dist/cli.js +21 -8
- package/ccw/dist/cli.js.map +1 -1
- package/ccw/dist/commands/cli.d.ts +2 -0
- package/ccw/dist/commands/cli.d.ts.map +1 -1
- package/ccw/dist/commands/cli.js +129 -8
- package/ccw/dist/commands/cli.js.map +1 -1
- package/ccw/dist/commands/hook.d.ts.map +1 -1
- package/ccw/dist/commands/hook.js +3 -2
- package/ccw/dist/commands/hook.js.map +1 -1
- package/ccw/dist/config/litellm-api-config-manager.d.ts +180 -0
- package/ccw/dist/config/litellm-api-config-manager.d.ts.map +1 -0
- package/ccw/dist/config/litellm-api-config-manager.js +770 -0
- package/ccw/dist/config/litellm-api-config-manager.js.map +1 -0
- package/ccw/dist/config/provider-models.d.ts +73 -0
- package/ccw/dist/config/provider-models.d.ts.map +1 -0
- package/ccw/dist/config/provider-models.js +172 -0
- package/ccw/dist/config/provider-models.js.map +1 -0
- package/ccw/dist/core/cache-manager.d.ts.map +1 -1
- package/ccw/dist/core/cache-manager.js +3 -5
- package/ccw/dist/core/cache-manager.js.map +1 -1
- package/ccw/dist/core/dashboard-generator.d.ts.map +1 -1
- package/ccw/dist/core/dashboard-generator.js +3 -1
- package/ccw/dist/core/dashboard-generator.js.map +1 -1
- package/ccw/dist/core/routes/cli-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/cli-routes.js +169 -0
- package/ccw/dist/core/routes/cli-routes.js.map +1 -1
- package/ccw/dist/core/routes/codexlens-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/codexlens-routes.js +234 -18
- package/ccw/dist/core/routes/codexlens-routes.js.map +1 -1
- package/ccw/dist/core/routes/hooks-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/hooks-routes.js +30 -32
- package/ccw/dist/core/routes/hooks-routes.js.map +1 -1
- package/ccw/dist/core/routes/litellm-api-routes.d.ts +21 -0
- package/ccw/dist/core/routes/litellm-api-routes.d.ts.map +1 -0
- package/ccw/dist/core/routes/litellm-api-routes.js +780 -0
- package/ccw/dist/core/routes/litellm-api-routes.js.map +1 -0
- package/ccw/dist/core/routes/litellm-routes.d.ts +20 -0
- package/ccw/dist/core/routes/litellm-routes.d.ts.map +1 -0
- package/ccw/dist/core/routes/litellm-routes.js +85 -0
- package/ccw/dist/core/routes/litellm-routes.js.map +1 -0
- package/ccw/dist/core/routes/mcp-routes.js +2 -2
- package/ccw/dist/core/routes/mcp-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 +39 -0
- package/ccw/dist/core/routes/status-routes.js.map +1 -1
- package/ccw/dist/core/routes/system-routes.js +1 -1
- 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 +15 -1
- package/ccw/dist/core/server.js.map +1 -1
- package/ccw/dist/mcp-server/index.js +1 -1
- package/ccw/dist/mcp-server/index.js.map +1 -1
- package/ccw/dist/tools/claude-cli-tools.d.ts +82 -0
- package/ccw/dist/tools/claude-cli-tools.d.ts.map +1 -0
- package/ccw/dist/tools/claude-cli-tools.js +216 -0
- package/ccw/dist/tools/claude-cli-tools.js.map +1 -0
- package/ccw/dist/tools/cli-executor.d.ts.map +1 -1
- package/ccw/dist/tools/cli-executor.js +76 -14
- package/ccw/dist/tools/cli-executor.js.map +1 -1
- package/ccw/dist/tools/codex-lens.d.ts +9 -2
- package/ccw/dist/tools/codex-lens.d.ts.map +1 -1
- package/ccw/dist/tools/codex-lens.js +114 -9
- package/ccw/dist/tools/codex-lens.js.map +1 -1
- package/ccw/dist/tools/context-cache-store.d.ts +136 -0
- package/ccw/dist/tools/context-cache-store.d.ts.map +1 -0
- package/ccw/dist/tools/context-cache-store.js +256 -0
- package/ccw/dist/tools/context-cache-store.js.map +1 -0
- package/ccw/dist/tools/context-cache.d.ts +56 -0
- package/ccw/dist/tools/context-cache.d.ts.map +1 -0
- package/ccw/dist/tools/context-cache.js +294 -0
- package/ccw/dist/tools/context-cache.js.map +1 -0
- package/ccw/dist/tools/core-memory.d.ts.map +1 -1
- package/ccw/dist/tools/core-memory.js +33 -19
- package/ccw/dist/tools/core-memory.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 +85 -0
- package/ccw/dist/tools/litellm-client.d.ts.map +1 -0
- package/ccw/dist/tools/litellm-client.js +188 -0
- package/ccw/dist/tools/litellm-client.js.map +1 -0
- package/ccw/dist/tools/litellm-executor.d.ts +34 -0
- package/ccw/dist/tools/litellm-executor.d.ts.map +1 -0
- package/ccw/dist/tools/litellm-executor.js +192 -0
- package/ccw/dist/tools/litellm-executor.js.map +1 -0
- package/ccw/dist/tools/pattern-parser.d.ts +55 -0
- package/ccw/dist/tools/pattern-parser.d.ts.map +1 -0
- package/ccw/dist/tools/pattern-parser.js +237 -0
- package/ccw/dist/tools/pattern-parser.js.map +1 -0
- package/ccw/dist/tools/smart-search.d.ts +1 -0
- package/ccw/dist/tools/smart-search.d.ts.map +1 -1
- package/ccw/dist/tools/smart-search.js +117 -41
- package/ccw/dist/tools/smart-search.js.map +1 -1
- package/ccw/dist/types/litellm-api-config.d.ts +294 -0
- package/ccw/dist/types/litellm-api-config.d.ts.map +1 -0
- package/ccw/dist/types/litellm-api-config.js +8 -0
- package/ccw/dist/types/litellm-api-config.js.map +1 -0
- package/ccw/src/cli.ts +258 -244
- package/ccw/src/commands/cli.ts +153 -9
- package/ccw/src/commands/hook.ts +3 -2
- package/ccw/src/config/.litellm-api-config-manager.ts.2025-12-23T11-57-43-727Z.bak +441 -0
- package/ccw/src/config/litellm-api-config-manager.ts +1012 -0
- package/ccw/src/config/provider-models.ts +222 -0
- package/ccw/src/core/cache-manager.ts +292 -294
- package/ccw/src/core/dashboard-generator.ts +3 -1
- package/ccw/src/core/routes/cli-routes.ts +192 -0
- package/ccw/src/core/routes/codexlens-routes.ts +241 -19
- package/ccw/src/core/routes/hooks-routes.ts +399 -405
- package/ccw/src/core/routes/litellm-api-routes.ts +930 -0
- package/ccw/src/core/routes/litellm-routes.ts +107 -0
- package/ccw/src/core/routes/mcp-routes.ts +1271 -1271
- package/ccw/src/core/routes/status-routes.ts +51 -0
- package/ccw/src/core/routes/system-routes.ts +1 -1
- package/ccw/src/core/server.ts +15 -1
- package/ccw/src/mcp-server/index.ts +1 -1
- package/ccw/src/templates/dashboard-css/12-cli-legacy.css +44 -0
- package/ccw/src/templates/dashboard-css/31-api-settings.css +2265 -0
- package/ccw/src/templates/dashboard-js/components/cli-history.js +15 -8
- package/ccw/src/templates/dashboard-js/components/cli-status.js +323 -9
- package/ccw/src/templates/dashboard-js/components/navigation.js +329 -313
- package/ccw/src/templates/dashboard-js/i18n.js +583 -1
- package/ccw/src/templates/dashboard-js/views/api-settings.js +3362 -0
- package/ccw/src/templates/dashboard-js/views/cli-manager.js +199 -24
- package/ccw/src/templates/dashboard-js/views/codexlens-manager.js +1265 -27
- package/ccw/src/templates/dashboard.html +840 -831
- package/ccw/src/tools/claude-cli-tools.ts +300 -0
- package/ccw/src/tools/cli-executor.ts +83 -14
- package/ccw/src/tools/codex-lens.ts +146 -9
- package/ccw/src/tools/context-cache-store.ts +368 -0
- package/ccw/src/tools/context-cache.ts +393 -0
- package/ccw/src/tools/core-memory.ts +33 -19
- package/ccw/src/tools/index.ts +2 -0
- package/ccw/src/tools/litellm-client.ts +246 -0
- package/ccw/src/tools/litellm-executor.ts +241 -0
- package/ccw/src/tools/pattern-parser.ts +329 -0
- package/ccw/src/tools/smart-search.ts +142 -41
- package/ccw/src/types/litellm-api-config.ts +402 -0
- package/ccw-litellm/README.md +180 -0
- package/ccw-litellm/pyproject.toml +35 -0
- package/ccw-litellm/src/ccw_litellm/__init__.py +47 -0
- package/ccw-litellm/src/ccw_litellm/__pycache__/__init__.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/__pycache__/cli.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/cli.py +108 -0
- package/ccw-litellm/src/ccw_litellm/clients/__init__.py +12 -0
- package/ccw-litellm/src/ccw_litellm/clients/__pycache__/__init__.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/clients/__pycache__/litellm_embedder.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/clients/__pycache__/litellm_llm.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/clients/litellm_embedder.py +251 -0
- package/ccw-litellm/src/ccw_litellm/clients/litellm_llm.py +165 -0
- package/ccw-litellm/src/ccw_litellm/config/__init__.py +22 -0
- package/ccw-litellm/src/ccw_litellm/config/__pycache__/__init__.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/config/__pycache__/loader.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/config/__pycache__/models.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/config/loader.py +316 -0
- package/ccw-litellm/src/ccw_litellm/config/models.py +130 -0
- package/ccw-litellm/src/ccw_litellm/interfaces/__init__.py +14 -0
- package/ccw-litellm/src/ccw_litellm/interfaces/__pycache__/__init__.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/interfaces/__pycache__/embedder.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/interfaces/__pycache__/llm.cpython-313.pyc +0 -0
- package/ccw-litellm/src/ccw_litellm/interfaces/embedder.py +52 -0
- package/ccw-litellm/src/ccw_litellm/interfaces/llm.py +45 -0
- package/codex-lens/src/codexlens/__pycache__/config.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/commands.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/embedding_manager.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/model_manager.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/output.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/commands.py +378 -23
- package/codex-lens/src/codexlens/cli/embedding_manager.py +660 -56
- package/codex-lens/src/codexlens/cli/model_manager.py +31 -18
- package/codex-lens/src/codexlens/cli/output.py +12 -1
- package/codex-lens/src/codexlens/config.py +93 -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 +6 -2
- package/codex-lens/src/codexlens/search/hybrid_search.py +44 -21
- package/codex-lens/src/codexlens/search/ranking.py +1 -1
- package/codex-lens/src/codexlens/semantic/__init__.py +42 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/base.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/chunker.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/embedder.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/factory.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/gpu_support.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/litellm_embedder.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/vector_store.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/base.py +61 -0
- package/codex-lens/src/codexlens/semantic/chunker.py +43 -20
- package/codex-lens/src/codexlens/semantic/embedder.py +60 -13
- package/codex-lens/src/codexlens/semantic/factory.py +98 -0
- package/codex-lens/src/codexlens/semantic/gpu_support.py +225 -3
- package/codex-lens/src/codexlens/semantic/litellm_embedder.py +144 -0
- package/codex-lens/src/codexlens/semantic/rotational_embedder.py +434 -0
- package/codex-lens/src/codexlens/semantic/vector_store.py +33 -8
- package/codex-lens/src/codexlens/storage/__pycache__/path_mapper.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_004_dual_fts.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/path_mapper.py +27 -1
- package/package.json +15 -5
- package/.codex/prompts.zip +0 -0
- package/ccw/package.json +0 -65
|
@@ -29,10 +29,12 @@ const ParamsSchema = z.object({
|
|
|
29
29
|
path: z.string().optional(),
|
|
30
30
|
paths: z.array(z.string()).default([]),
|
|
31
31
|
contextLines: z.number().default(0),
|
|
32
|
-
maxResults: z.number().default(
|
|
32
|
+
maxResults: z.number().default(5), // Default 5 with full content
|
|
33
33
|
includeHidden: z.boolean().default(false),
|
|
34
34
|
languages: z.array(z.string()).optional(),
|
|
35
|
-
limit: z.number().default(
|
|
35
|
+
limit: z.number().default(5), // Default 5 with full content
|
|
36
|
+
extraFilesCount: z.number().default(10), // Additional file-only results
|
|
37
|
+
maxContentLength: z.number().default(200), // Max content length for truncation (50-2000)
|
|
36
38
|
offset: z.number().default(0), // NEW: Pagination offset (start_index)
|
|
37
39
|
enrich: z.boolean().default(false),
|
|
38
40
|
// Search modifiers for ripgrep mode
|
|
@@ -163,6 +165,35 @@ function scoreByTokenMatch(results, tokens) {
|
|
|
163
165
|
function stripAnsi(str) {
|
|
164
166
|
return str.replace(/\x1b\[[0-9;]*m/g, '');
|
|
165
167
|
}
|
|
168
|
+
/** Default maximum content length to return (avoid excessive output) */
|
|
169
|
+
const DEFAULT_MAX_CONTENT_LENGTH = 200;
|
|
170
|
+
/**
|
|
171
|
+
* Truncate content to specified length with ellipsis
|
|
172
|
+
* @param content - The content to truncate
|
|
173
|
+
* @param maxLength - Maximum length (default: 200)
|
|
174
|
+
*/
|
|
175
|
+
function truncateContent(content, maxLength = DEFAULT_MAX_CONTENT_LENGTH) {
|
|
176
|
+
if (!content)
|
|
177
|
+
return '';
|
|
178
|
+
if (content.length <= maxLength)
|
|
179
|
+
return content;
|
|
180
|
+
return content.slice(0, maxLength) + '...';
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Split results into full content results and extra file-only results
|
|
184
|
+
* Generic function supporting both SemanticMatch and ExactMatch types
|
|
185
|
+
* @param allResults - All search results (must have 'file' property)
|
|
186
|
+
* @param fullContentLimit - Number of results with full content (default: 5)
|
|
187
|
+
* @param extraFilesCount - Number of additional file-only results (default: 10)
|
|
188
|
+
*/
|
|
189
|
+
function splitResultsWithExtraFiles(allResults, fullContentLimit = 5, extraFilesCount = 10) {
|
|
190
|
+
// First N results with full content
|
|
191
|
+
const results = allResults.slice(0, fullContentLimit);
|
|
192
|
+
// Next M results as file paths only (deduplicated)
|
|
193
|
+
const extraResults = allResults.slice(fullContentLimit, fullContentLimit + extraFilesCount);
|
|
194
|
+
const extra_files = [...new Set(extraResults.map(r => r.file))];
|
|
195
|
+
return { results, extra_files };
|
|
196
|
+
}
|
|
166
197
|
/**
|
|
167
198
|
* Check if CodexLens index exists for current directory
|
|
168
199
|
* @param path - Directory path to check
|
|
@@ -190,6 +221,17 @@ async function checkIndexStatus(path = '.') {
|
|
|
190
221
|
const embeddingsData = status.embeddings || {};
|
|
191
222
|
const embeddingsCoverage = embeddingsData.coverage_percent || 0;
|
|
192
223
|
const has_embeddings = embeddingsCoverage >= 50; // Threshold: 50%
|
|
224
|
+
const totalChunks = embeddingsData.total_chunks || 0;
|
|
225
|
+
// Extract model info if available
|
|
226
|
+
const modelInfoData = embeddingsData.model_info;
|
|
227
|
+
const modelInfo = modelInfoData ? {
|
|
228
|
+
model_profile: modelInfoData.model_profile,
|
|
229
|
+
model_name: modelInfoData.model_name,
|
|
230
|
+
embedding_dim: modelInfoData.embedding_dim,
|
|
231
|
+
backend: modelInfoData.backend,
|
|
232
|
+
created_at: modelInfoData.created_at,
|
|
233
|
+
updated_at: modelInfoData.updated_at,
|
|
234
|
+
} : undefined;
|
|
193
235
|
let warning;
|
|
194
236
|
if (!indexed) {
|
|
195
237
|
warning = 'No CodexLens index found. Run smart_search(action="init") to create index for better search results.';
|
|
@@ -205,6 +247,9 @@ async function checkIndexStatus(path = '.') {
|
|
|
205
247
|
has_embeddings,
|
|
206
248
|
file_count: status.total_files,
|
|
207
249
|
embeddings_coverage_percent: embeddingsCoverage,
|
|
250
|
+
total_chunks: totalChunks,
|
|
251
|
+
// Ensure model_info is null instead of undefined so it's included in JSON
|
|
252
|
+
model_info: modelInfo ?? null,
|
|
208
253
|
warning,
|
|
209
254
|
};
|
|
210
255
|
}
|
|
@@ -514,7 +559,7 @@ async function executeAutoMode(params) {
|
|
|
514
559
|
* Supports tokenized multi-word queries with OR matching and result ranking
|
|
515
560
|
*/
|
|
516
561
|
async function executeRipgrepMode(params) {
|
|
517
|
-
const { query, paths = [], contextLines = 0, maxResults = 10, includeHidden = false, path = '.', regex = true, caseSensitive = true, tokenize = true } = params;
|
|
562
|
+
const { query, paths = [], contextLines = 0, maxResults = 5, extraFilesCount = 10, maxContentLength = 200, includeHidden = false, path = '.', regex = true, caseSensitive = true, tokenize = true } = params;
|
|
518
563
|
if (!query) {
|
|
519
564
|
return {
|
|
520
565
|
success: false,
|
|
@@ -523,6 +568,8 @@ async function executeRipgrepMode(params) {
|
|
|
523
568
|
}
|
|
524
569
|
// Check if ripgrep is available
|
|
525
570
|
const hasRipgrep = checkToolAvailability('rg');
|
|
571
|
+
// Calculate total to fetch for split (full content + extra files)
|
|
572
|
+
const totalToFetch = maxResults + extraFilesCount;
|
|
526
573
|
// If ripgrep not available, fall back to CodexLens exact mode
|
|
527
574
|
if (!hasRipgrep) {
|
|
528
575
|
const readyStatus = await ensureCodexLensReady();
|
|
@@ -533,7 +580,7 @@ async function executeRipgrepMode(params) {
|
|
|
533
580
|
};
|
|
534
581
|
}
|
|
535
582
|
// Use CodexLens exact mode as fallback
|
|
536
|
-
const args = ['search', query, '--limit',
|
|
583
|
+
const args = ['search', query, '--limit', totalToFetch.toString(), '--mode', 'exact', '--json'];
|
|
537
584
|
const result = await executeCodexLens(args, { cwd: path });
|
|
538
585
|
if (!result.success) {
|
|
539
586
|
return {
|
|
@@ -548,23 +595,26 @@ async function executeRipgrepMode(params) {
|
|
|
548
595
|
};
|
|
549
596
|
}
|
|
550
597
|
// Parse results
|
|
551
|
-
let
|
|
598
|
+
let allResults = [];
|
|
552
599
|
try {
|
|
553
600
|
const parsed = JSON.parse(stripAnsi(result.output || '{}'));
|
|
554
601
|
const data = parsed.result?.results || parsed.results || parsed;
|
|
555
|
-
|
|
602
|
+
allResults = (Array.isArray(data) ? data : []).map((item) => ({
|
|
556
603
|
file: item.path || item.file,
|
|
557
604
|
score: item.score || 0,
|
|
558
|
-
content: item.
|
|
605
|
+
content: truncateContent(item.content || item.excerpt, maxContentLength),
|
|
559
606
|
symbol: item.symbol || null,
|
|
560
607
|
}));
|
|
561
608
|
}
|
|
562
609
|
catch {
|
|
563
610
|
// Keep empty results
|
|
564
611
|
}
|
|
612
|
+
// Split results: first N with full content, rest as file paths only
|
|
613
|
+
const { results, extra_files } = splitResultsWithExtraFiles(allResults, maxResults, extraFilesCount);
|
|
565
614
|
return {
|
|
566
615
|
success: true,
|
|
567
616
|
results,
|
|
617
|
+
extra_files: extra_files.length > 0 ? extra_files : undefined,
|
|
568
618
|
metadata: {
|
|
569
619
|
mode: 'ripgrep',
|
|
570
620
|
backend: 'codexlens-fallback',
|
|
@@ -574,12 +624,12 @@ async function executeRipgrepMode(params) {
|
|
|
574
624
|
},
|
|
575
625
|
};
|
|
576
626
|
}
|
|
577
|
-
// Use ripgrep
|
|
627
|
+
// Use ripgrep - request more results to support split
|
|
578
628
|
const { command, args, tokens } = buildRipgrepCommand({
|
|
579
629
|
query,
|
|
580
630
|
paths: paths.length > 0 ? paths : [path],
|
|
581
631
|
contextLines,
|
|
582
|
-
maxResults,
|
|
632
|
+
maxResults: totalToFetch, // Fetch more to support split
|
|
583
633
|
includeHidden,
|
|
584
634
|
regex,
|
|
585
635
|
caseSensitive,
|
|
@@ -600,13 +650,13 @@ async function executeRipgrepMode(params) {
|
|
|
600
650
|
stderr += data.toString();
|
|
601
651
|
});
|
|
602
652
|
child.on('close', (code) => {
|
|
603
|
-
const
|
|
653
|
+
const allResults = [];
|
|
604
654
|
const lines = stdout.split('\n').filter((line) => line.trim());
|
|
605
655
|
// Limit total results to prevent memory overflow (--max-count only limits per-file)
|
|
606
|
-
const effectiveLimit =
|
|
656
|
+
const effectiveLimit = totalToFetch > 0 ? totalToFetch : 500;
|
|
607
657
|
for (const line of lines) {
|
|
608
658
|
// Stop collecting if we've reached the limit
|
|
609
|
-
if (
|
|
659
|
+
if (allResults.length >= effectiveLimit) {
|
|
610
660
|
resultLimitReached = true;
|
|
611
661
|
break;
|
|
612
662
|
}
|
|
@@ -621,7 +671,7 @@ async function executeRipgrepMode(params) {
|
|
|
621
671
|
: 1,
|
|
622
672
|
content: item.data.lines.text.trim(),
|
|
623
673
|
};
|
|
624
|
-
|
|
674
|
+
allResults.push(match);
|
|
625
675
|
}
|
|
626
676
|
}
|
|
627
677
|
catch {
|
|
@@ -633,8 +683,10 @@ async function executeRipgrepMode(params) {
|
|
|
633
683
|
const isWindowsDeviceError = stderr.includes('os error 1') || stderr.includes('函数不正确');
|
|
634
684
|
// Apply token-based scoring and sorting for multi-word queries
|
|
635
685
|
// Results matching more tokens are ranked higher (exact matches first)
|
|
636
|
-
const scoredResults = tokens.length > 1 ? scoreByTokenMatch(
|
|
686
|
+
const scoredResults = tokens.length > 1 ? scoreByTokenMatch(allResults, tokens) : allResults;
|
|
637
687
|
if (code === 0 || code === 1 || (isWindowsDeviceError && scoredResults.length > 0)) {
|
|
688
|
+
// Split results: first N with full content, rest as file paths only
|
|
689
|
+
const { results, extra_files } = splitResultsWithExtraFiles(scoredResults, maxResults, extraFilesCount);
|
|
638
690
|
// Build warning message for various conditions
|
|
639
691
|
const warnings = [];
|
|
640
692
|
if (resultLimitReached) {
|
|
@@ -645,11 +697,12 @@ async function executeRipgrepMode(params) {
|
|
|
645
697
|
}
|
|
646
698
|
resolve({
|
|
647
699
|
success: true,
|
|
648
|
-
results
|
|
700
|
+
results,
|
|
701
|
+
extra_files: extra_files.length > 0 ? extra_files : undefined,
|
|
649
702
|
metadata: {
|
|
650
703
|
mode: 'ripgrep',
|
|
651
704
|
backend: 'ripgrep',
|
|
652
|
-
count:
|
|
705
|
+
count: results.length,
|
|
653
706
|
query,
|
|
654
707
|
tokens: tokens.length > 1 ? tokens : undefined, // Include tokens in metadata for debugging
|
|
655
708
|
tokenized: tokens.length > 1,
|
|
@@ -657,7 +710,7 @@ async function executeRipgrepMode(params) {
|
|
|
657
710
|
},
|
|
658
711
|
});
|
|
659
712
|
}
|
|
660
|
-
else if (isWindowsDeviceError &&
|
|
713
|
+
else if (isWindowsDeviceError && allResults.length === 0) {
|
|
661
714
|
// Windows device error but no results - might be the only issue
|
|
662
715
|
resolve({
|
|
663
716
|
success: true,
|
|
@@ -693,7 +746,7 @@ async function executeRipgrepMode(params) {
|
|
|
693
746
|
* Requires index
|
|
694
747
|
*/
|
|
695
748
|
async function executeCodexLensExactMode(params) {
|
|
696
|
-
const { query, path = '.', maxResults = 10, enrich = false } = params;
|
|
749
|
+
const { query, path = '.', maxResults = 5, extraFilesCount = 10, maxContentLength = 200, enrich = false } = params;
|
|
697
750
|
if (!query) {
|
|
698
751
|
return {
|
|
699
752
|
success: false,
|
|
@@ -710,7 +763,9 @@ async function executeCodexLensExactMode(params) {
|
|
|
710
763
|
}
|
|
711
764
|
// Check index status
|
|
712
765
|
const indexStatus = await checkIndexStatus(path);
|
|
713
|
-
|
|
766
|
+
// Request more results to support split (full content + extra files)
|
|
767
|
+
const totalToFetch = maxResults + extraFilesCount;
|
|
768
|
+
const args = ['search', query, '--limit', totalToFetch.toString(), '--mode', 'exact', '--json'];
|
|
714
769
|
if (enrich) {
|
|
715
770
|
args.push('--enrich');
|
|
716
771
|
}
|
|
@@ -729,14 +784,14 @@ async function executeCodexLensExactMode(params) {
|
|
|
729
784
|
};
|
|
730
785
|
}
|
|
731
786
|
// Parse results
|
|
732
|
-
let
|
|
787
|
+
let allResults = [];
|
|
733
788
|
try {
|
|
734
789
|
const parsed = JSON.parse(stripAnsi(result.output || '{}'));
|
|
735
790
|
const data = parsed.result?.results || parsed.results || parsed;
|
|
736
|
-
|
|
791
|
+
allResults = (Array.isArray(data) ? data : []).map((item) => ({
|
|
737
792
|
file: item.path || item.file,
|
|
738
793
|
score: item.score || 0,
|
|
739
|
-
content: item.
|
|
794
|
+
content: truncateContent(item.content || item.excerpt, maxContentLength),
|
|
740
795
|
symbol: item.symbol || null,
|
|
741
796
|
}));
|
|
742
797
|
}
|
|
@@ -744,8 +799,8 @@ async function executeCodexLensExactMode(params) {
|
|
|
744
799
|
// Keep empty results
|
|
745
800
|
}
|
|
746
801
|
// Fallback to fuzzy mode if exact returns no results
|
|
747
|
-
if (
|
|
748
|
-
const fuzzyArgs = ['search', query, '--limit',
|
|
802
|
+
if (allResults.length === 0) {
|
|
803
|
+
const fuzzyArgs = ['search', query, '--limit', totalToFetch.toString(), '--mode', 'fuzzy', '--json'];
|
|
749
804
|
if (enrich) {
|
|
750
805
|
fuzzyArgs.push('--enrich');
|
|
751
806
|
}
|
|
@@ -754,20 +809,23 @@ async function executeCodexLensExactMode(params) {
|
|
|
754
809
|
try {
|
|
755
810
|
const parsed = JSON.parse(stripAnsi(fuzzyResult.output || '{}'));
|
|
756
811
|
const data = parsed.result?.results || parsed.results || parsed;
|
|
757
|
-
|
|
812
|
+
allResults = (Array.isArray(data) ? data : []).map((item) => ({
|
|
758
813
|
file: item.path || item.file,
|
|
759
814
|
score: item.score || 0,
|
|
760
|
-
content: item.
|
|
815
|
+
content: truncateContent(item.content || item.excerpt, maxContentLength),
|
|
761
816
|
symbol: item.symbol || null,
|
|
762
817
|
}));
|
|
763
818
|
}
|
|
764
819
|
catch {
|
|
765
820
|
// Keep empty results
|
|
766
821
|
}
|
|
767
|
-
if (
|
|
822
|
+
if (allResults.length > 0) {
|
|
823
|
+
// Split results: first N with full content, rest as file paths only
|
|
824
|
+
const { results, extra_files } = splitResultsWithExtraFiles(allResults, maxResults, extraFilesCount);
|
|
768
825
|
return {
|
|
769
826
|
success: true,
|
|
770
827
|
results,
|
|
828
|
+
extra_files: extra_files.length > 0 ? extra_files : undefined,
|
|
771
829
|
metadata: {
|
|
772
830
|
mode: 'exact',
|
|
773
831
|
backend: 'codexlens',
|
|
@@ -781,9 +839,12 @@ async function executeCodexLensExactMode(params) {
|
|
|
781
839
|
}
|
|
782
840
|
}
|
|
783
841
|
}
|
|
842
|
+
// Split results: first N with full content, rest as file paths only
|
|
843
|
+
const { results, extra_files } = splitResultsWithExtraFiles(allResults, maxResults, extraFilesCount);
|
|
784
844
|
return {
|
|
785
845
|
success: true,
|
|
786
846
|
results,
|
|
847
|
+
extra_files: extra_files.length > 0 ? extra_files : undefined,
|
|
787
848
|
metadata: {
|
|
788
849
|
mode: 'exact',
|
|
789
850
|
backend: 'codexlens',
|
|
@@ -799,7 +860,7 @@ async function executeCodexLensExactMode(params) {
|
|
|
799
860
|
* Requires index with embeddings
|
|
800
861
|
*/
|
|
801
862
|
async function executeHybridMode(params) {
|
|
802
|
-
const { query, path = '.', maxResults = 10, enrich = false } = params;
|
|
863
|
+
const { query, path = '.', maxResults = 5, extraFilesCount = 10, maxContentLength = 200, enrich = false } = params;
|
|
803
864
|
if (!query) {
|
|
804
865
|
return {
|
|
805
866
|
success: false,
|
|
@@ -816,7 +877,9 @@ async function executeHybridMode(params) {
|
|
|
816
877
|
}
|
|
817
878
|
// Check index status
|
|
818
879
|
const indexStatus = await checkIndexStatus(path);
|
|
819
|
-
|
|
880
|
+
// Request more results to support split (full content + extra files)
|
|
881
|
+
const totalToFetch = maxResults + extraFilesCount;
|
|
882
|
+
const args = ['search', query, '--limit', totalToFetch.toString(), '--mode', 'hybrid', '--json'];
|
|
820
883
|
if (enrich) {
|
|
821
884
|
args.push('--enrich');
|
|
822
885
|
}
|
|
@@ -835,13 +898,13 @@ async function executeHybridMode(params) {
|
|
|
835
898
|
};
|
|
836
899
|
}
|
|
837
900
|
// Parse results
|
|
838
|
-
let
|
|
901
|
+
let allResults = [];
|
|
839
902
|
let baselineInfo = null;
|
|
840
903
|
let initialCount = 0;
|
|
841
904
|
try {
|
|
842
905
|
const parsed = JSON.parse(stripAnsi(result.output || '{}'));
|
|
843
906
|
const data = parsed.result?.results || parsed.results || parsed;
|
|
844
|
-
|
|
907
|
+
allResults = (Array.isArray(data) ? data : []).map((item) => {
|
|
845
908
|
const rawScore = item.score || 0;
|
|
846
909
|
// Hybrid mode returns distance scores (lower is better).
|
|
847
910
|
// Convert to similarity scores (higher is better) for consistency.
|
|
@@ -850,24 +913,24 @@ async function executeHybridMode(params) {
|
|
|
850
913
|
return {
|
|
851
914
|
file: item.path || item.file,
|
|
852
915
|
score: similarityScore,
|
|
853
|
-
content: item.
|
|
916
|
+
content: truncateContent(item.content || item.excerpt, maxContentLength),
|
|
854
917
|
symbol: item.symbol || null,
|
|
855
918
|
};
|
|
856
919
|
});
|
|
857
|
-
initialCount =
|
|
920
|
+
initialCount = allResults.length;
|
|
858
921
|
// Post-processing pipeline to improve semantic search quality
|
|
859
922
|
// 0. Filter dominant baseline scores (hot spot detection)
|
|
860
|
-
const baselineResult = filterDominantBaselineScores(
|
|
861
|
-
|
|
923
|
+
const baselineResult = filterDominantBaselineScores(allResults);
|
|
924
|
+
allResults = baselineResult.filteredResults;
|
|
862
925
|
baselineInfo = baselineResult.baselineInfo;
|
|
863
926
|
// 1. Filter noisy files (coverage, node_modules, etc.)
|
|
864
|
-
|
|
927
|
+
allResults = filterNoisyFiles(allResults);
|
|
865
928
|
// 2. Boost results containing query keywords
|
|
866
|
-
|
|
929
|
+
allResults = applyKeywordBoosting(allResults, query);
|
|
867
930
|
// 3. Enforce score diversity (penalize identical scores)
|
|
868
|
-
|
|
931
|
+
allResults = enforceScoreDiversity(allResults);
|
|
869
932
|
// 4. Re-sort by adjusted scores
|
|
870
|
-
|
|
933
|
+
allResults.sort((a, b) => b.score - a.score);
|
|
871
934
|
}
|
|
872
935
|
catch {
|
|
873
936
|
return {
|
|
@@ -883,14 +946,17 @@ async function executeHybridMode(params) {
|
|
|
883
946
|
},
|
|
884
947
|
};
|
|
885
948
|
}
|
|
949
|
+
// Split results: first N with full content, rest as file paths only
|
|
950
|
+
const { results, extra_files } = splitResultsWithExtraFiles(allResults, maxResults, extraFilesCount);
|
|
886
951
|
// Build metadata with baseline info if detected
|
|
887
952
|
let note = 'Hybrid mode uses RRF fusion (exact + fuzzy + vector) for best results';
|
|
888
953
|
if (baselineInfo) {
|
|
889
|
-
note += ` | Filtered ${initialCount -
|
|
954
|
+
note += ` | Filtered ${initialCount - allResults.length} hot-spot results with baseline score ~${baselineInfo.score.toFixed(4)}`;
|
|
890
955
|
}
|
|
891
956
|
return {
|
|
892
957
|
success: true,
|
|
893
958
|
results,
|
|
959
|
+
extra_files: extra_files.length > 0 ? extra_files : undefined,
|
|
894
960
|
metadata: {
|
|
895
961
|
mode: 'hybrid',
|
|
896
962
|
backend: 'codexlens',
|
|
@@ -1258,7 +1324,7 @@ export const schema = {
|
|
|
1258
1324
|
mode: {
|
|
1259
1325
|
type: 'string',
|
|
1260
1326
|
enum: SEARCH_MODES,
|
|
1261
|
-
description: 'Search mode: auto
|
|
1327
|
+
description: 'Search mode: auto, hybrid (best quality), exact (CodexLens FTS), ripgrep (fast, no index), priority (fallback chain)',
|
|
1262
1328
|
default: 'auto',
|
|
1263
1329
|
},
|
|
1264
1330
|
output_mode: {
|
|
@@ -1294,6 +1360,16 @@ export const schema = {
|
|
|
1294
1360
|
description: 'Alias for maxResults (default: 20)',
|
|
1295
1361
|
default: 20,
|
|
1296
1362
|
},
|
|
1363
|
+
extraFilesCount: {
|
|
1364
|
+
type: 'number',
|
|
1365
|
+
description: 'Number of additional file-only results (paths without content)',
|
|
1366
|
+
default: 10,
|
|
1367
|
+
},
|
|
1368
|
+
maxContentLength: {
|
|
1369
|
+
type: 'number',
|
|
1370
|
+
description: 'Maximum content length for truncation (50-2000)',
|
|
1371
|
+
default: 200,
|
|
1372
|
+
},
|
|
1297
1373
|
offset: {
|
|
1298
1374
|
type: 'number',
|
|
1299
1375
|
description: 'Pagination offset - skip first N results (default: 0)',
|