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.
Files changed (208) hide show
  1. package/.claude/CLAUDE.md +16 -1
  2. package/.claude/workflows/cli-templates/protocols/analysis-protocol.md +11 -4
  3. package/.claude/workflows/cli-templates/protocols/write-protocol.md +10 -75
  4. package/.claude/workflows/cli-tools-usage.md +14 -24
  5. package/.codex/AGENTS.md +51 -1
  6. package/.codex/prompts/compact.md +378 -0
  7. package/.gemini/GEMINI.md +57 -20
  8. package/ccw/dist/cli.d.ts.map +1 -1
  9. package/ccw/dist/cli.js +21 -8
  10. package/ccw/dist/cli.js.map +1 -1
  11. package/ccw/dist/commands/cli.d.ts +2 -0
  12. package/ccw/dist/commands/cli.d.ts.map +1 -1
  13. package/ccw/dist/commands/cli.js +129 -8
  14. package/ccw/dist/commands/cli.js.map +1 -1
  15. package/ccw/dist/commands/hook.d.ts.map +1 -1
  16. package/ccw/dist/commands/hook.js +3 -2
  17. package/ccw/dist/commands/hook.js.map +1 -1
  18. package/ccw/dist/config/litellm-api-config-manager.d.ts +180 -0
  19. package/ccw/dist/config/litellm-api-config-manager.d.ts.map +1 -0
  20. package/ccw/dist/config/litellm-api-config-manager.js +770 -0
  21. package/ccw/dist/config/litellm-api-config-manager.js.map +1 -0
  22. package/ccw/dist/config/provider-models.d.ts +73 -0
  23. package/ccw/dist/config/provider-models.d.ts.map +1 -0
  24. package/ccw/dist/config/provider-models.js +172 -0
  25. package/ccw/dist/config/provider-models.js.map +1 -0
  26. package/ccw/dist/core/cache-manager.d.ts.map +1 -1
  27. package/ccw/dist/core/cache-manager.js +3 -5
  28. package/ccw/dist/core/cache-manager.js.map +1 -1
  29. package/ccw/dist/core/dashboard-generator.d.ts.map +1 -1
  30. package/ccw/dist/core/dashboard-generator.js +3 -1
  31. package/ccw/dist/core/dashboard-generator.js.map +1 -1
  32. package/ccw/dist/core/routes/cli-routes.d.ts.map +1 -1
  33. package/ccw/dist/core/routes/cli-routes.js +169 -0
  34. package/ccw/dist/core/routes/cli-routes.js.map +1 -1
  35. package/ccw/dist/core/routes/codexlens-routes.d.ts.map +1 -1
  36. package/ccw/dist/core/routes/codexlens-routes.js +234 -18
  37. package/ccw/dist/core/routes/codexlens-routes.js.map +1 -1
  38. package/ccw/dist/core/routes/hooks-routes.d.ts.map +1 -1
  39. package/ccw/dist/core/routes/hooks-routes.js +30 -32
  40. package/ccw/dist/core/routes/hooks-routes.js.map +1 -1
  41. package/ccw/dist/core/routes/litellm-api-routes.d.ts +21 -0
  42. package/ccw/dist/core/routes/litellm-api-routes.d.ts.map +1 -0
  43. package/ccw/dist/core/routes/litellm-api-routes.js +780 -0
  44. package/ccw/dist/core/routes/litellm-api-routes.js.map +1 -0
  45. package/ccw/dist/core/routes/litellm-routes.d.ts +20 -0
  46. package/ccw/dist/core/routes/litellm-routes.d.ts.map +1 -0
  47. package/ccw/dist/core/routes/litellm-routes.js +85 -0
  48. package/ccw/dist/core/routes/litellm-routes.js.map +1 -0
  49. package/ccw/dist/core/routes/mcp-routes.js +2 -2
  50. package/ccw/dist/core/routes/mcp-routes.js.map +1 -1
  51. package/ccw/dist/core/routes/status-routes.d.ts.map +1 -1
  52. package/ccw/dist/core/routes/status-routes.js +39 -0
  53. package/ccw/dist/core/routes/status-routes.js.map +1 -1
  54. package/ccw/dist/core/routes/system-routes.js +1 -1
  55. package/ccw/dist/core/routes/system-routes.js.map +1 -1
  56. package/ccw/dist/core/server.d.ts.map +1 -1
  57. package/ccw/dist/core/server.js +15 -1
  58. package/ccw/dist/core/server.js.map +1 -1
  59. package/ccw/dist/mcp-server/index.js +1 -1
  60. package/ccw/dist/mcp-server/index.js.map +1 -1
  61. package/ccw/dist/tools/claude-cli-tools.d.ts +82 -0
  62. package/ccw/dist/tools/claude-cli-tools.d.ts.map +1 -0
  63. package/ccw/dist/tools/claude-cli-tools.js +216 -0
  64. package/ccw/dist/tools/claude-cli-tools.js.map +1 -0
  65. package/ccw/dist/tools/cli-executor.d.ts.map +1 -1
  66. package/ccw/dist/tools/cli-executor.js +76 -14
  67. package/ccw/dist/tools/cli-executor.js.map +1 -1
  68. package/ccw/dist/tools/codex-lens.d.ts +9 -2
  69. package/ccw/dist/tools/codex-lens.d.ts.map +1 -1
  70. package/ccw/dist/tools/codex-lens.js +114 -9
  71. package/ccw/dist/tools/codex-lens.js.map +1 -1
  72. package/ccw/dist/tools/context-cache-store.d.ts +136 -0
  73. package/ccw/dist/tools/context-cache-store.d.ts.map +1 -0
  74. package/ccw/dist/tools/context-cache-store.js +256 -0
  75. package/ccw/dist/tools/context-cache-store.js.map +1 -0
  76. package/ccw/dist/tools/context-cache.d.ts +56 -0
  77. package/ccw/dist/tools/context-cache.d.ts.map +1 -0
  78. package/ccw/dist/tools/context-cache.js +294 -0
  79. package/ccw/dist/tools/context-cache.js.map +1 -0
  80. package/ccw/dist/tools/core-memory.d.ts.map +1 -1
  81. package/ccw/dist/tools/core-memory.js +33 -19
  82. package/ccw/dist/tools/core-memory.js.map +1 -1
  83. package/ccw/dist/tools/index.d.ts.map +1 -1
  84. package/ccw/dist/tools/index.js +2 -0
  85. package/ccw/dist/tools/index.js.map +1 -1
  86. package/ccw/dist/tools/litellm-client.d.ts +85 -0
  87. package/ccw/dist/tools/litellm-client.d.ts.map +1 -0
  88. package/ccw/dist/tools/litellm-client.js +188 -0
  89. package/ccw/dist/tools/litellm-client.js.map +1 -0
  90. package/ccw/dist/tools/litellm-executor.d.ts +34 -0
  91. package/ccw/dist/tools/litellm-executor.d.ts.map +1 -0
  92. package/ccw/dist/tools/litellm-executor.js +192 -0
  93. package/ccw/dist/tools/litellm-executor.js.map +1 -0
  94. package/ccw/dist/tools/pattern-parser.d.ts +55 -0
  95. package/ccw/dist/tools/pattern-parser.d.ts.map +1 -0
  96. package/ccw/dist/tools/pattern-parser.js +237 -0
  97. package/ccw/dist/tools/pattern-parser.js.map +1 -0
  98. package/ccw/dist/tools/smart-search.d.ts +1 -0
  99. package/ccw/dist/tools/smart-search.d.ts.map +1 -1
  100. package/ccw/dist/tools/smart-search.js +117 -41
  101. package/ccw/dist/tools/smart-search.js.map +1 -1
  102. package/ccw/dist/types/litellm-api-config.d.ts +294 -0
  103. package/ccw/dist/types/litellm-api-config.d.ts.map +1 -0
  104. package/ccw/dist/types/litellm-api-config.js +8 -0
  105. package/ccw/dist/types/litellm-api-config.js.map +1 -0
  106. package/ccw/src/cli.ts +258 -244
  107. package/ccw/src/commands/cli.ts +153 -9
  108. package/ccw/src/commands/hook.ts +3 -2
  109. package/ccw/src/config/.litellm-api-config-manager.ts.2025-12-23T11-57-43-727Z.bak +441 -0
  110. package/ccw/src/config/litellm-api-config-manager.ts +1012 -0
  111. package/ccw/src/config/provider-models.ts +222 -0
  112. package/ccw/src/core/cache-manager.ts +292 -294
  113. package/ccw/src/core/dashboard-generator.ts +3 -1
  114. package/ccw/src/core/routes/cli-routes.ts +192 -0
  115. package/ccw/src/core/routes/codexlens-routes.ts +241 -19
  116. package/ccw/src/core/routes/hooks-routes.ts +399 -405
  117. package/ccw/src/core/routes/litellm-api-routes.ts +930 -0
  118. package/ccw/src/core/routes/litellm-routes.ts +107 -0
  119. package/ccw/src/core/routes/mcp-routes.ts +1271 -1271
  120. package/ccw/src/core/routes/status-routes.ts +51 -0
  121. package/ccw/src/core/routes/system-routes.ts +1 -1
  122. package/ccw/src/core/server.ts +15 -1
  123. package/ccw/src/mcp-server/index.ts +1 -1
  124. package/ccw/src/templates/dashboard-css/12-cli-legacy.css +44 -0
  125. package/ccw/src/templates/dashboard-css/31-api-settings.css +2265 -0
  126. package/ccw/src/templates/dashboard-js/components/cli-history.js +15 -8
  127. package/ccw/src/templates/dashboard-js/components/cli-status.js +323 -9
  128. package/ccw/src/templates/dashboard-js/components/navigation.js +329 -313
  129. package/ccw/src/templates/dashboard-js/i18n.js +583 -1
  130. package/ccw/src/templates/dashboard-js/views/api-settings.js +3362 -0
  131. package/ccw/src/templates/dashboard-js/views/cli-manager.js +199 -24
  132. package/ccw/src/templates/dashboard-js/views/codexlens-manager.js +1265 -27
  133. package/ccw/src/templates/dashboard.html +840 -831
  134. package/ccw/src/tools/claude-cli-tools.ts +300 -0
  135. package/ccw/src/tools/cli-executor.ts +83 -14
  136. package/ccw/src/tools/codex-lens.ts +146 -9
  137. package/ccw/src/tools/context-cache-store.ts +368 -0
  138. package/ccw/src/tools/context-cache.ts +393 -0
  139. package/ccw/src/tools/core-memory.ts +33 -19
  140. package/ccw/src/tools/index.ts +2 -0
  141. package/ccw/src/tools/litellm-client.ts +246 -0
  142. package/ccw/src/tools/litellm-executor.ts +241 -0
  143. package/ccw/src/tools/pattern-parser.ts +329 -0
  144. package/ccw/src/tools/smart-search.ts +142 -41
  145. package/ccw/src/types/litellm-api-config.ts +402 -0
  146. package/ccw-litellm/README.md +180 -0
  147. package/ccw-litellm/pyproject.toml +35 -0
  148. package/ccw-litellm/src/ccw_litellm/__init__.py +47 -0
  149. package/ccw-litellm/src/ccw_litellm/__pycache__/__init__.cpython-313.pyc +0 -0
  150. package/ccw-litellm/src/ccw_litellm/__pycache__/cli.cpython-313.pyc +0 -0
  151. package/ccw-litellm/src/ccw_litellm/cli.py +108 -0
  152. package/ccw-litellm/src/ccw_litellm/clients/__init__.py +12 -0
  153. package/ccw-litellm/src/ccw_litellm/clients/__pycache__/__init__.cpython-313.pyc +0 -0
  154. package/ccw-litellm/src/ccw_litellm/clients/__pycache__/litellm_embedder.cpython-313.pyc +0 -0
  155. package/ccw-litellm/src/ccw_litellm/clients/__pycache__/litellm_llm.cpython-313.pyc +0 -0
  156. package/ccw-litellm/src/ccw_litellm/clients/litellm_embedder.py +251 -0
  157. package/ccw-litellm/src/ccw_litellm/clients/litellm_llm.py +165 -0
  158. package/ccw-litellm/src/ccw_litellm/config/__init__.py +22 -0
  159. package/ccw-litellm/src/ccw_litellm/config/__pycache__/__init__.cpython-313.pyc +0 -0
  160. package/ccw-litellm/src/ccw_litellm/config/__pycache__/loader.cpython-313.pyc +0 -0
  161. package/ccw-litellm/src/ccw_litellm/config/__pycache__/models.cpython-313.pyc +0 -0
  162. package/ccw-litellm/src/ccw_litellm/config/loader.py +316 -0
  163. package/ccw-litellm/src/ccw_litellm/config/models.py +130 -0
  164. package/ccw-litellm/src/ccw_litellm/interfaces/__init__.py +14 -0
  165. package/ccw-litellm/src/ccw_litellm/interfaces/__pycache__/__init__.cpython-313.pyc +0 -0
  166. package/ccw-litellm/src/ccw_litellm/interfaces/__pycache__/embedder.cpython-313.pyc +0 -0
  167. package/ccw-litellm/src/ccw_litellm/interfaces/__pycache__/llm.cpython-313.pyc +0 -0
  168. package/ccw-litellm/src/ccw_litellm/interfaces/embedder.py +52 -0
  169. package/ccw-litellm/src/ccw_litellm/interfaces/llm.py +45 -0
  170. package/codex-lens/src/codexlens/__pycache__/config.cpython-313.pyc +0 -0
  171. package/codex-lens/src/codexlens/cli/__pycache__/commands.cpython-313.pyc +0 -0
  172. package/codex-lens/src/codexlens/cli/__pycache__/embedding_manager.cpython-313.pyc +0 -0
  173. package/codex-lens/src/codexlens/cli/__pycache__/model_manager.cpython-313.pyc +0 -0
  174. package/codex-lens/src/codexlens/cli/__pycache__/output.cpython-313.pyc +0 -0
  175. package/codex-lens/src/codexlens/cli/commands.py +378 -23
  176. package/codex-lens/src/codexlens/cli/embedding_manager.py +660 -56
  177. package/codex-lens/src/codexlens/cli/model_manager.py +31 -18
  178. package/codex-lens/src/codexlens/cli/output.py +12 -1
  179. package/codex-lens/src/codexlens/config.py +93 -0
  180. package/codex-lens/src/codexlens/search/__pycache__/chain_search.cpython-313.pyc +0 -0
  181. package/codex-lens/src/codexlens/search/__pycache__/hybrid_search.cpython-313.pyc +0 -0
  182. package/codex-lens/src/codexlens/search/__pycache__/ranking.cpython-313.pyc +0 -0
  183. package/codex-lens/src/codexlens/search/chain_search.py +6 -2
  184. package/codex-lens/src/codexlens/search/hybrid_search.py +44 -21
  185. package/codex-lens/src/codexlens/search/ranking.py +1 -1
  186. package/codex-lens/src/codexlens/semantic/__init__.py +42 -0
  187. package/codex-lens/src/codexlens/semantic/__pycache__/__init__.cpython-313.pyc +0 -0
  188. package/codex-lens/src/codexlens/semantic/__pycache__/base.cpython-313.pyc +0 -0
  189. package/codex-lens/src/codexlens/semantic/__pycache__/chunker.cpython-313.pyc +0 -0
  190. package/codex-lens/src/codexlens/semantic/__pycache__/embedder.cpython-313.pyc +0 -0
  191. package/codex-lens/src/codexlens/semantic/__pycache__/factory.cpython-313.pyc +0 -0
  192. package/codex-lens/src/codexlens/semantic/__pycache__/gpu_support.cpython-313.pyc +0 -0
  193. package/codex-lens/src/codexlens/semantic/__pycache__/litellm_embedder.cpython-313.pyc +0 -0
  194. package/codex-lens/src/codexlens/semantic/__pycache__/vector_store.cpython-313.pyc +0 -0
  195. package/codex-lens/src/codexlens/semantic/base.py +61 -0
  196. package/codex-lens/src/codexlens/semantic/chunker.py +43 -20
  197. package/codex-lens/src/codexlens/semantic/embedder.py +60 -13
  198. package/codex-lens/src/codexlens/semantic/factory.py +98 -0
  199. package/codex-lens/src/codexlens/semantic/gpu_support.py +225 -3
  200. package/codex-lens/src/codexlens/semantic/litellm_embedder.py +144 -0
  201. package/codex-lens/src/codexlens/semantic/rotational_embedder.py +434 -0
  202. package/codex-lens/src/codexlens/semantic/vector_store.py +33 -8
  203. package/codex-lens/src/codexlens/storage/__pycache__/path_mapper.cpython-313.pyc +0 -0
  204. package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_004_dual_fts.cpython-313.pyc +0 -0
  205. package/codex-lens/src/codexlens/storage/path_mapper.py +27 -1
  206. package/package.json +15 -5
  207. package/.codex/prompts.zip +0 -0
  208. 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
+ }