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
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pattern Parser - Parse @expression patterns to file lists
|
|
3
|
+
* Supports glob patterns like @src/**.ts, @CLAUDE.md, @../shared/**
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { glob } from 'glob';
|
|
7
|
+
import { resolve, isAbsolute, normalize } from 'path';
|
|
8
|
+
import { existsSync, statSync, readFileSync } from 'fs';
|
|
9
|
+
|
|
10
|
+
/** Result of parsing @patterns */
|
|
11
|
+
export interface PatternParseResult {
|
|
12
|
+
files: string[]; // Matched file paths (absolute)
|
|
13
|
+
patterns: string[]; // Original patterns
|
|
14
|
+
errors: string[]; // Parse errors
|
|
15
|
+
stats: {
|
|
16
|
+
total_files: number;
|
|
17
|
+
total_patterns: number;
|
|
18
|
+
matched_patterns: number;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Options for pattern parsing */
|
|
23
|
+
export interface PatternParseOptions {
|
|
24
|
+
cwd?: string; // Working directory
|
|
25
|
+
includeDirs?: string[]; // Additional directories to include
|
|
26
|
+
ignore?: string[]; // Ignore patterns
|
|
27
|
+
maxFiles?: number; // Max files to return (default: 1000)
|
|
28
|
+
followSymlinks?: boolean; // Follow symlinks (default: false)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Default ignore patterns */
|
|
32
|
+
const DEFAULT_IGNORE = [
|
|
33
|
+
'**/node_modules/**',
|
|
34
|
+
'**/.git/**',
|
|
35
|
+
'**/dist/**',
|
|
36
|
+
'**/build/**',
|
|
37
|
+
'**/.next/**',
|
|
38
|
+
'**/__pycache__/**',
|
|
39
|
+
'**/*.pyc',
|
|
40
|
+
'**/venv/**',
|
|
41
|
+
'**/.venv/**',
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Extract pattern from @expression
|
|
46
|
+
* Example: "@src/**.ts" -> "src/**.ts"
|
|
47
|
+
*/
|
|
48
|
+
function extractPattern(expression: string): string | null {
|
|
49
|
+
const trimmed = expression.trim();
|
|
50
|
+
if (!trimmed.startsWith('@')) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
return trimmed.slice(1);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Check if a pattern is a glob pattern or exact file
|
|
58
|
+
*/
|
|
59
|
+
function isGlobPattern(pattern: string): boolean {
|
|
60
|
+
return pattern.includes('*') || pattern.includes('?') || pattern.includes('{') || pattern.includes('[');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Validate that a path is within allowed directories
|
|
65
|
+
*/
|
|
66
|
+
function isPathAllowed(filePath: string, allowedDirs: string[]): boolean {
|
|
67
|
+
const normalized = normalize(filePath);
|
|
68
|
+
return allowedDirs.some(dir => normalized.startsWith(normalize(dir)));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Build allowed directories list from options
|
|
73
|
+
*/
|
|
74
|
+
function buildAllowedDirs(cwd: string, includeDirs?: string[]): string[] {
|
|
75
|
+
const allowed = [cwd];
|
|
76
|
+
|
|
77
|
+
if (includeDirs) {
|
|
78
|
+
for (const dir of includeDirs) {
|
|
79
|
+
const absDir = isAbsolute(dir) ? dir : resolve(cwd, dir);
|
|
80
|
+
if (existsSync(absDir) && statSync(absDir).isDirectory()) {
|
|
81
|
+
allowed.push(absDir);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return allowed.map(d => normalize(d));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Parse @expressions and return matched files
|
|
91
|
+
*/
|
|
92
|
+
export async function parsePatterns(
|
|
93
|
+
patterns: string[],
|
|
94
|
+
options: PatternParseOptions = {}
|
|
95
|
+
): Promise<PatternParseResult> {
|
|
96
|
+
const {
|
|
97
|
+
cwd = process.cwd(),
|
|
98
|
+
includeDirs = [],
|
|
99
|
+
ignore = [],
|
|
100
|
+
maxFiles = 1000,
|
|
101
|
+
followSymlinks = false,
|
|
102
|
+
} = options;
|
|
103
|
+
|
|
104
|
+
const result: PatternParseResult = {
|
|
105
|
+
files: [],
|
|
106
|
+
patterns: [],
|
|
107
|
+
errors: [],
|
|
108
|
+
stats: {
|
|
109
|
+
total_files: 0,
|
|
110
|
+
total_patterns: patterns.length,
|
|
111
|
+
matched_patterns: 0,
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// Build allowed directories
|
|
116
|
+
const allowedDirs = buildAllowedDirs(cwd, includeDirs);
|
|
117
|
+
|
|
118
|
+
// Merge ignore patterns
|
|
119
|
+
const allIgnore = [...DEFAULT_IGNORE, ...ignore];
|
|
120
|
+
|
|
121
|
+
// Track unique files
|
|
122
|
+
const fileSet = new Set<string>();
|
|
123
|
+
|
|
124
|
+
for (const expr of patterns) {
|
|
125
|
+
const pattern = extractPattern(expr);
|
|
126
|
+
|
|
127
|
+
if (!pattern) {
|
|
128
|
+
result.errors.push(`Invalid pattern: ${expr} (must start with @)`);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
result.patterns.push(pattern);
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
if (isGlobPattern(pattern)) {
|
|
136
|
+
// Glob pattern - use glob package
|
|
137
|
+
// Determine base directory for pattern
|
|
138
|
+
let baseDir = cwd;
|
|
139
|
+
let globPattern = pattern;
|
|
140
|
+
|
|
141
|
+
// Handle relative paths like ../shared/**
|
|
142
|
+
if (pattern.startsWith('../') || pattern.startsWith('./')) {
|
|
143
|
+
const parts = pattern.split('/');
|
|
144
|
+
const pathParts: string[] = [];
|
|
145
|
+
let i = 0;
|
|
146
|
+
|
|
147
|
+
// Extract path prefix
|
|
148
|
+
while (i < parts.length && (parts[i] === '..' || parts[i] === '.')) {
|
|
149
|
+
pathParts.push(parts[i]);
|
|
150
|
+
i++;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Keep non-glob path parts
|
|
154
|
+
while (i < parts.length && !isGlobPattern(parts[i])) {
|
|
155
|
+
pathParts.push(parts[i]);
|
|
156
|
+
i++;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Resolve base directory
|
|
160
|
+
if (pathParts.length > 0) {
|
|
161
|
+
baseDir = resolve(cwd, pathParts.join('/'));
|
|
162
|
+
globPattern = parts.slice(i).join('/') || '**/*';
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Check if base directory is allowed
|
|
167
|
+
if (!isPathAllowed(baseDir, allowedDirs)) {
|
|
168
|
+
result.errors.push(`Pattern ${expr}: base directory not in allowed paths`);
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Execute glob using the glob package
|
|
173
|
+
const matches = await glob(globPattern, {
|
|
174
|
+
cwd: baseDir,
|
|
175
|
+
absolute: true,
|
|
176
|
+
nodir: true,
|
|
177
|
+
follow: followSymlinks,
|
|
178
|
+
ignore: allIgnore,
|
|
179
|
+
dot: false,
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
let matchCount = 0;
|
|
183
|
+
for (const file of matches) {
|
|
184
|
+
// Validate each file is in allowed directories
|
|
185
|
+
if (isPathAllowed(file, allowedDirs)) {
|
|
186
|
+
fileSet.add(file);
|
|
187
|
+
matchCount++;
|
|
188
|
+
if (fileSet.size >= maxFiles) break;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (matchCount > 0) {
|
|
193
|
+
result.stats.matched_patterns++;
|
|
194
|
+
}
|
|
195
|
+
} else {
|
|
196
|
+
// Exact file path
|
|
197
|
+
const absPath = isAbsolute(pattern) ? pattern : resolve(cwd, pattern);
|
|
198
|
+
|
|
199
|
+
// Validate path is allowed
|
|
200
|
+
if (!isPathAllowed(absPath, allowedDirs)) {
|
|
201
|
+
result.errors.push(`Pattern ${expr}: path not in allowed directories`);
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Check file exists
|
|
206
|
+
if (existsSync(absPath) && statSync(absPath).isFile()) {
|
|
207
|
+
fileSet.add(absPath);
|
|
208
|
+
result.stats.matched_patterns++;
|
|
209
|
+
} else {
|
|
210
|
+
result.errors.push(`Pattern ${expr}: file not found`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
} catch (err) {
|
|
214
|
+
result.errors.push(`Pattern ${expr}: ${(err as Error).message}`);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Check max files limit
|
|
218
|
+
if (fileSet.size >= maxFiles) {
|
|
219
|
+
result.errors.push(`Max files limit (${maxFiles}) reached`);
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
result.files = Array.from(fileSet);
|
|
225
|
+
result.stats.total_files = result.files.length;
|
|
226
|
+
|
|
227
|
+
return result;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Pack files into a single content string with metadata headers
|
|
232
|
+
*/
|
|
233
|
+
export async function packFiles(
|
|
234
|
+
files: string[],
|
|
235
|
+
options: {
|
|
236
|
+
includeMetadata?: boolean;
|
|
237
|
+
separator?: string;
|
|
238
|
+
maxFileSize?: number; // Max size per file in bytes (default: 1MB)
|
|
239
|
+
} = {}
|
|
240
|
+
): Promise<{
|
|
241
|
+
content: string;
|
|
242
|
+
packedFiles: string[];
|
|
243
|
+
skippedFiles: string[];
|
|
244
|
+
totalBytes: number;
|
|
245
|
+
}> {
|
|
246
|
+
const {
|
|
247
|
+
includeMetadata = true,
|
|
248
|
+
separator = '\n\n',
|
|
249
|
+
maxFileSize = 1024 * 1024, // 1MB default
|
|
250
|
+
} = options;
|
|
251
|
+
|
|
252
|
+
const parts: string[] = [];
|
|
253
|
+
const packedFiles: string[] = [];
|
|
254
|
+
const skippedFiles: string[] = [];
|
|
255
|
+
let totalBytes = 0;
|
|
256
|
+
|
|
257
|
+
for (const file of files) {
|
|
258
|
+
try {
|
|
259
|
+
const stats = statSync(file);
|
|
260
|
+
|
|
261
|
+
// Skip files that are too large
|
|
262
|
+
if (stats.size > maxFileSize) {
|
|
263
|
+
skippedFiles.push(file);
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const content = readFileSync(file, 'utf-8');
|
|
268
|
+
|
|
269
|
+
if (includeMetadata) {
|
|
270
|
+
// Add file header with metadata
|
|
271
|
+
const header = [
|
|
272
|
+
`=== FILE: ${file} ===`,
|
|
273
|
+
`Size: ${stats.size} bytes`,
|
|
274
|
+
`Modified: ${stats.mtime.toISOString()}`,
|
|
275
|
+
'---',
|
|
276
|
+
].join('\n');
|
|
277
|
+
parts.push(header + '\n' + content);
|
|
278
|
+
} else {
|
|
279
|
+
parts.push(content);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
packedFiles.push(file);
|
|
283
|
+
totalBytes += content.length;
|
|
284
|
+
} catch {
|
|
285
|
+
skippedFiles.push(file);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
content: parts.join(separator),
|
|
291
|
+
packedFiles,
|
|
292
|
+
skippedFiles,
|
|
293
|
+
totalBytes,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Parse patterns and pack files in one call
|
|
299
|
+
*/
|
|
300
|
+
export async function parseAndPack(
|
|
301
|
+
patterns: string[],
|
|
302
|
+
options: PatternParseOptions & {
|
|
303
|
+
includeMetadata?: boolean;
|
|
304
|
+
separator?: string;
|
|
305
|
+
maxFileSize?: number;
|
|
306
|
+
} = {}
|
|
307
|
+
): Promise<{
|
|
308
|
+
content: string;
|
|
309
|
+
parseResult: PatternParseResult;
|
|
310
|
+
packedFiles: string[];
|
|
311
|
+
skippedFiles: string[];
|
|
312
|
+
totalBytes: number;
|
|
313
|
+
}> {
|
|
314
|
+
const parseResult = await parsePatterns(patterns, options);
|
|
315
|
+
|
|
316
|
+
const packResult = await packFiles(parseResult.files, {
|
|
317
|
+
includeMetadata: options.includeMetadata,
|
|
318
|
+
separator: options.separator,
|
|
319
|
+
maxFileSize: options.maxFileSize,
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
return {
|
|
323
|
+
content: packResult.content,
|
|
324
|
+
parseResult,
|
|
325
|
+
packedFiles: packResult.packedFiles,
|
|
326
|
+
skippedFiles: packResult.skippedFiles,
|
|
327
|
+
totalBytes: packResult.totalBytes,
|
|
328
|
+
};
|
|
329
|
+
}
|