ctxman 3.0.0 → 3.1.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 (223) hide show
  1. package/.ctxman/llm-profiles.json +1067 -39
  2. package/.ctxman/profiles/backend-team.json +13 -0
  3. package/.ctxman/profiles/default.json +12 -0
  4. package/.ctxman/profiles/devops-team.json +21 -0
  5. package/.ctxman/profiles/frontend-team.json +20 -0
  6. package/.ctxman/templates/bug-fix.json +17 -0
  7. package/.ctxman/templates/code-review.json +9 -0
  8. package/.ctxman/templates/documentation.json +9 -0
  9. package/.ctxman/templates/feature.json +9 -0
  10. package/.ctxman/templates/full-context.json +9 -0
  11. package/.ctxman/templates/refactoring.json +18 -0
  12. package/.ctxman/templates/testing.json +9 -0
  13. package/.ctxman/wizard-profiles/security-audit/profile.json +7 -1
  14. package/LICENSE +21 -0
  15. package/README.md +380 -136
  16. package/bin/cli.js +1880 -529
  17. package/bin/cm-ask.js +18 -13
  18. package/bin/cm-audit.js +124 -0
  19. package/bin/cm-count.js +151 -0
  20. package/bin/cm-gitingest.js +128 -115
  21. package/bin/cm-map.js +242 -0
  22. package/bin/cm-mcp.js +293 -0
  23. package/bin/cm-pack.js +405 -0
  24. package/bin/cm-policy.js +170 -0
  25. package/bin/cm-pr.js +248 -0
  26. package/bin/cm-search.js +178 -0
  27. package/bin/cm-update.js +128 -128
  28. package/bin/cm-why.js +197 -0
  29. package/bin/mcp-server.js +8 -24
  30. package/ctxman.js +237 -183
  31. package/examples/README.md +19 -4
  32. package/examples/github-actions/ctxman-check.yml +49 -0
  33. package/examples/wizard-profiles/security-audit/profile.json +7 -1
  34. package/index.d.ts +1422 -0
  35. package/index.js +55 -31
  36. package/lib/agents/pr-failure-agent.js +48 -45
  37. package/lib/analyzers/ai-suggester.js +451 -0
  38. package/lib/analyzers/dependency-scanner.js +505 -0
  39. package/lib/analyzers/duplicate-detector.js +264 -0
  40. package/lib/analyzers/go-method-analyzer.js +151 -110
  41. package/lib/analyzers/import-tracker.js +431 -0
  42. package/lib/analyzers/method-analyzer.js +1055 -434
  43. package/lib/analyzers/performance-dashboard.js +683 -0
  44. package/lib/analyzers/token-calculator.js +895 -504
  45. package/lib/analyzers/unused-exports-detector.js +336 -0
  46. package/lib/api/mcp/install.js +424 -0
  47. package/lib/api/mcp/prompts.js +281 -281
  48. package/lib/api/mcp/resources.js +300 -241
  49. package/lib/api/mcp/sandbox.js +89 -0
  50. package/lib/api/mcp/server.js +675 -312
  51. package/lib/api/mcp/start.js +125 -0
  52. package/lib/api/mcp/transports/HttpSseTransport.js +60 -52
  53. package/lib/api/rest/server.js +105 -28
  54. package/lib/cache/CacheManager.js +9 -17
  55. package/lib/core/Analyzer.js +16 -10
  56. package/lib/core/ContextBuilder.js +19 -28
  57. package/lib/core/Reporter.js +15 -14
  58. package/lib/core/Scanner.js +81 -12
  59. package/lib/count/index.js +100 -0
  60. package/lib/formatters/format-registry.js +394 -372
  61. package/lib/formatters/gitingest-formatter.js +656 -621
  62. package/lib/formatters/toon-formatter-v1.3.js +637 -632
  63. package/lib/formatters/toon-formatter.js +239 -240
  64. package/lib/integrations/git/BlameTracker.js +4 -4
  65. package/lib/integrations/git/DiffAnalyzer.js +38 -31
  66. package/lib/integrations/git/GitClient.js +71 -53
  67. package/lib/lsp/server.js +311 -0
  68. package/lib/map/graph.js +299 -0
  69. package/lib/map/imports.js +233 -0
  70. package/lib/map/index.js +33 -0
  71. package/lib/map/rank.js +253 -0
  72. package/lib/map/render.js +346 -0
  73. package/lib/map/resolver.js +574 -0
  74. package/lib/pack/budget.js +111 -0
  75. package/lib/pack/code-lexer.js +360 -0
  76. package/lib/pack/compress.js +414 -0
  77. package/lib/pack/index.js +354 -0
  78. package/lib/pack/renderers/common.js +134 -0
  79. package/lib/pack/renderers/index.js +24 -0
  80. package/lib/pack/renderers/json.js +47 -0
  81. package/lib/pack/renderers/markdown.js +54 -0
  82. package/lib/pack/renderers/plain.js +38 -0
  83. package/lib/pack/renderers/xml.js +85 -0
  84. package/lib/pack/select.js +177 -0
  85. package/lib/pack/split.js +182 -0
  86. package/lib/pack/tree.js +35 -0
  87. package/lib/parsers/gitignore-parser.js +113 -107
  88. package/lib/parsers/method-filter-parser.js +50 -33
  89. package/lib/plugins/ExporterPlugin.js +3 -3
  90. package/lib/plugins/LanguagePlugin.js +3 -3
  91. package/lib/plugins/PluginManager.js +7 -13
  92. package/lib/policy/audit.js +294 -0
  93. package/lib/policy/enforce.js +125 -0
  94. package/lib/policy/ignore-files.js +169 -0
  95. package/lib/policy/index.js +52 -0
  96. package/lib/policy/policy.js +489 -0
  97. package/lib/pr/diff-parser.js +267 -0
  98. package/lib/pr/method-mapper.js +148 -0
  99. package/lib/pr/pr-context.js +829 -0
  100. package/lib/pr/pr-git.js +149 -0
  101. package/lib/pr/pr-renderer.js +644 -0
  102. package/lib/pr/related-tests.js +296 -0
  103. package/lib/rag/DataSourcePlugin.js +5 -5
  104. package/lib/rag/EmbeddingProvider.js +19 -8
  105. package/lib/rag/Indexer.js +14 -5
  106. package/lib/rag/VectorStoreFactory.js +3 -3
  107. package/lib/rag/sources/FileDataSource.js +6 -6
  108. package/lib/rag/stores/BaseVectorStore.js +5 -5
  109. package/lib/rag/stores/ChromaDBStore.js +10 -10
  110. package/lib/rag/stores/LanceDBStore.js +29 -19
  111. package/lib/rag/stores/PineconeStore.js +11 -9
  112. package/lib/search/bm25.js +433 -0
  113. package/lib/search/code-units.js +201 -0
  114. package/lib/search/symbols.js +189 -0
  115. package/lib/ui/dashboard.js +120 -89
  116. package/lib/ui/index.js +1 -6
  117. package/lib/ui/init-wizard-ui.js +550 -0
  118. package/lib/ui/progress-bar.js +94 -88
  119. package/lib/ui/select-input.js +40 -32
  120. package/lib/ui/template-selector.js +99 -0
  121. package/lib/ui/wizard.js +374 -329
  122. package/lib/utils/claude-token-counter.js +151 -0
  123. package/lib/utils/cli-output.js +17 -0
  124. package/lib/utils/clipboard-utils.js +49 -50
  125. package/lib/utils/config-utils.js +81 -66
  126. package/lib/utils/context-versioning.js +532 -0
  127. package/lib/utils/error-handler.js +112 -112
  128. package/lib/utils/file-utils.js +153 -69
  129. package/lib/utils/format-converter.js +356 -283
  130. package/lib/utils/git-utils.js +366 -294
  131. package/lib/utils/llm-cost-estimator.js +281 -0
  132. package/lib/utils/llm-detector.js +242 -78
  133. package/lib/utils/logger.js +243 -237
  134. package/lib/utils/messages.js +355 -0
  135. package/lib/utils/multi-repo-manager.js +364 -0
  136. package/lib/utils/profile-manager.js +380 -0
  137. package/lib/utils/safe-read.js +61 -0
  138. package/lib/utils/secret-redactor.js +61 -0
  139. package/lib/utils/snapshot-manager.js +679 -0
  140. package/lib/utils/template-manager.js +378 -0
  141. package/lib/utils/token-utils.js +201 -170
  142. package/lib/utils/tokenizer-adapter.js +421 -377
  143. package/lib/utils/updater.js +539 -506
  144. package/lib/watch/FileWatcher.js +12 -8
  145. package/lib/watch/IncrementalAnalyzer.js +7 -7
  146. package/lib/why/coupling.js +81 -0
  147. package/lib/why/errors.js +23 -0
  148. package/lib/why/git.js +169 -0
  149. package/lib/why/history.js +108 -0
  150. package/lib/why/index.js +720 -0
  151. package/lib/why/ownership.js +79 -0
  152. package/lib/why/paths.js +207 -0
  153. package/lib/why/references.js +259 -0
  154. package/lib/why/render.js +722 -0
  155. package/lib/why/search.js +358 -0
  156. package/lib/why/target.js +389 -0
  157. package/lib/wizards/config-generator.js +255 -0
  158. package/lib/wizards/project-detector.js +571 -0
  159. package/package.json +44 -10
  160. package/.ctxman/logs/ctxman-2026-07-02.log +0 -156
  161. package/.ctxman/self-knowledge/documents.lance/_transactions/0-b3dd1558-f95b-44b9-a154-18e8c330ae7a.txn +0 -0
  162. package/.ctxman/self-knowledge/documents.lance/_transactions/1-44bff6d4-e552-4010-a769-e09ad822698d.txn +0 -0
  163. package/.ctxman/self-knowledge/documents.lance/_transactions/10-37260794-5947-4ecb-b4c8-d732f58f40f1.txn +0 -0
  164. package/.ctxman/self-knowledge/documents.lance/_transactions/11-0d52a883-5518-463c-9b6d-986c3af89dfd.txn +0 -0
  165. package/.ctxman/self-knowledge/documents.lance/_transactions/12-ae354646-52f2-49c9-90fb-2e6ed8932663.txn +0 -0
  166. package/.ctxman/self-knowledge/documents.lance/_transactions/13-5d7d5e57-27da-498b-b734-091b9d38da13.txn +0 -0
  167. package/.ctxman/self-knowledge/documents.lance/_transactions/14-558ce928-810b-4252-a364-fdd1ee6f8a25.txn +0 -0
  168. package/.ctxman/self-knowledge/documents.lance/_transactions/15-27e3a58f-8b64-43b8-a9f4-e3369446968b.txn +0 -0
  169. package/.ctxman/self-knowledge/documents.lance/_transactions/16-a110c390-e5c8-4464-b976-bc7f5195fa15.txn +0 -0
  170. package/.ctxman/self-knowledge/documents.lance/_transactions/17-97513225-53de-4216-b61a-6337bd0cc4ad.txn +0 -0
  171. package/.ctxman/self-knowledge/documents.lance/_transactions/18-5ba450f0-c527-459c-bf4f-6d79b5e4285f.txn +0 -0
  172. package/.ctxman/self-knowledge/documents.lance/_transactions/19-600d3a63-5225-49e9-b8b7-30e037b564ab.txn +0 -0
  173. package/.ctxman/self-knowledge/documents.lance/_transactions/2-48a61b4e-92cf-4342-8376-914c1b99a9f9.txn +0 -0
  174. package/.ctxman/self-knowledge/documents.lance/_transactions/20-121dd912-5410-410e-84ff-82c7a23604a0.txn +0 -0
  175. package/.ctxman/self-knowledge/documents.lance/_transactions/3-bc6844ab-7ea3-4bb3-9ee1-538ce5664a9c.txn +0 -0
  176. package/.ctxman/self-knowledge/documents.lance/_transactions/4-d5e1754f-dbb5-454e-a9be-2a7da8d7bcf9.txn +0 -0
  177. package/.ctxman/self-knowledge/documents.lance/_transactions/5-4fae93df-0568-4b6f-8acf-8bef4bba6047.txn +0 -0
  178. package/.ctxman/self-knowledge/documents.lance/_transactions/6-4b1b8b87-068e-49a3-ba2b-d8dae628b252.txn +0 -0
  179. package/.ctxman/self-knowledge/documents.lance/_transactions/7-63d040fb-d2fa-4c0f-bed0-53411918a7b0.txn +0 -0
  180. package/.ctxman/self-knowledge/documents.lance/_transactions/8-c5628cf6-264c-420f-aab8-bc96a9083591.txn +0 -0
  181. package/.ctxman/self-knowledge/documents.lance/_transactions/9-c94570aa-5e53-4fcb-971f-cecc1d1d5492.txn +0 -0
  182. package/.ctxman/self-knowledge/documents.lance/_versions/1.manifest +0 -0
  183. package/.ctxman/self-knowledge/documents.lance/_versions/10.manifest +0 -0
  184. package/.ctxman/self-knowledge/documents.lance/_versions/11.manifest +0 -0
  185. package/.ctxman/self-knowledge/documents.lance/_versions/12.manifest +0 -0
  186. package/.ctxman/self-knowledge/documents.lance/_versions/13.manifest +0 -0
  187. package/.ctxman/self-knowledge/documents.lance/_versions/14.manifest +0 -0
  188. package/.ctxman/self-knowledge/documents.lance/_versions/15.manifest +0 -0
  189. package/.ctxman/self-knowledge/documents.lance/_versions/16.manifest +0 -0
  190. package/.ctxman/self-knowledge/documents.lance/_versions/17.manifest +0 -0
  191. package/.ctxman/self-knowledge/documents.lance/_versions/18.manifest +0 -0
  192. package/.ctxman/self-knowledge/documents.lance/_versions/19.manifest +0 -0
  193. package/.ctxman/self-knowledge/documents.lance/_versions/2.manifest +0 -0
  194. package/.ctxman/self-knowledge/documents.lance/_versions/20.manifest +0 -0
  195. package/.ctxman/self-knowledge/documents.lance/_versions/21.manifest +0 -0
  196. package/.ctxman/self-knowledge/documents.lance/_versions/3.manifest +0 -0
  197. package/.ctxman/self-knowledge/documents.lance/_versions/4.manifest +0 -0
  198. package/.ctxman/self-knowledge/documents.lance/_versions/5.manifest +0 -0
  199. package/.ctxman/self-knowledge/documents.lance/_versions/6.manifest +0 -0
  200. package/.ctxman/self-knowledge/documents.lance/_versions/7.manifest +0 -0
  201. package/.ctxman/self-knowledge/documents.lance/_versions/8.manifest +0 -0
  202. package/.ctxman/self-knowledge/documents.lance/_versions/9.manifest +0 -0
  203. package/.ctxman/self-knowledge/documents.lance/data/000010010011011101000010de8621405d9d5cb06540dbf02c.lance +0 -0
  204. package/.ctxman/self-knowledge/documents.lance/data/0000101001011100011000003fb62a4aa8978974075c144f1c.lance +0 -0
  205. package/.ctxman/self-knowledge/documents.lance/data/000011010000100111001011c6cc824d628f3bb1f4e04cd5d0.lance +0 -0
  206. package/.ctxman/self-knowledge/documents.lance/data/001000001000011001011100d8f74349ada090b332cd1df669.lance +0 -0
  207. package/.ctxman/self-knowledge/documents.lance/data/01000001111010001000010045ab44467bb1e7e4d8ae06bd58.lance +0 -0
  208. package/.ctxman/self-knowledge/documents.lance/data/01000101101110111110011131ef904241a89e1ffb6ddaf8e3.lance +0 -0
  209. package/.ctxman/self-knowledge/documents.lance/data/010010110000010000011010fbfcc145c6a8a827b28057a07e.lance +0 -0
  210. package/.ctxman/self-knowledge/documents.lance/data/1000011000101010001110003fb4f045c3835982efa1405324.lance +0 -0
  211. package/.ctxman/self-knowledge/documents.lance/data/100111011101110111101011f4396b410fa06af3b028d204e6.lance +0 -0
  212. package/.ctxman/self-knowledge/documents.lance/data/100111100111101000001100596b174e00995d6cc2969cc8dc.lance +0 -0
  213. package/.ctxman/self-knowledge/documents.lance/data/1010001100011000110010102ea16b484d887c7c9725feffd6.lance +0 -0
  214. package/.ctxman/self-knowledge/documents.lance/data/101101100010101111110111c5230944d9b3af7301b6392dda.lance +0 -0
  215. package/.ctxman/self-knowledge/documents.lance/data/1011011100100111111110105892bf41b5a530fedd7cf516f1.lance +0 -0
  216. package/.ctxman/self-knowledge/documents.lance/data/10111110000010001011110164e8774742bade87b483c10f36.lance +0 -0
  217. package/.ctxman/self-knowledge/documents.lance/data/1100000100010110001110103ffaca40a2a42c85067ebaf9ae.lance +0 -0
  218. package/.ctxman/self-knowledge/documents.lance/data/110000010001110110101110664bde4c76a78dfc14b05e83b8.lance +0 -0
  219. package/.ctxman/self-knowledge/documents.lance/data/11001100111000010100110050645c4281b1f35b2022234f7f.lance +0 -0
  220. package/.ctxman/self-knowledge/documents.lance/data/1101111011001100110111017214924a368f5719eab2246619.lance +0 -0
  221. package/.ctxman/self-knowledge/documents.lance/data/1110000111001010001000002150c24dcab653d39d07032e63.lance +0 -0
  222. package/.ctxman/self-knowledge/documents.lance/data/1110100000000100000011014d20534967a18b5c87721659ff.lance +0 -0
  223. package/.ctxman/self-knowledge/documents.lance/data/11110101111010000101011135a0114ef2b35dc6f1297a3381.lance +0 -0
package/index.d.ts ADDED
@@ -0,0 +1,1422 @@
1
+ /**
2
+ * Ctxman - AI Development Platform
3
+ * TypeScript definitions for programmatic API
4
+ */
5
+
6
+ // ============================================
7
+ // Analyzers
8
+ // ============================================
9
+
10
+ /**
11
+ * Token Calculator Options
12
+ */
13
+ export interface TokenCalculatorOptions {
14
+ verbose?: boolean;
15
+ compactContext?: boolean;
16
+ methodLevel?: boolean;
17
+ saveReport?: boolean;
18
+ contextExport?: boolean;
19
+ contextToClipboard?: boolean;
20
+ gitingest?: boolean;
21
+ targetModel?: string;
22
+ dashboard?: boolean;
23
+ }
24
+
25
+ /**
26
+ * File analysis result
27
+ */
28
+ export interface FileInfo {
29
+ path: string;
30
+ relativePath: string;
31
+ sizeBytes: number;
32
+ tokens: number;
33
+ lines: number;
34
+ extension: string;
35
+ error?: string;
36
+ methods?: MethodInfo[];
37
+ }
38
+
39
+ /**
40
+ * Method information
41
+ */
42
+ export interface MethodInfo {
43
+ name: string;
44
+ line: number;
45
+ file: string;
46
+ tokens?: number;
47
+ content?: string;
48
+ }
49
+
50
+ /**
51
+ * Extension statistics
52
+ */
53
+ export interface ExtensionStats {
54
+ count: number;
55
+ tokens: number;
56
+ bytes: number;
57
+ lines: number;
58
+ }
59
+
60
+ /**
61
+ * Directory statistics
62
+ */
63
+ export interface DirectoryStats {
64
+ count: number;
65
+ tokens: number;
66
+ bytes: number;
67
+ lines: number;
68
+ }
69
+
70
+ /**
71
+ * Analysis statistics
72
+ */
73
+ export interface AnalysisStats {
74
+ totalFiles: number;
75
+ totalTokens: number;
76
+ totalBytes: number;
77
+ totalLines: number;
78
+ ignoredFiles: number;
79
+ calculatorIgnoredFiles: number;
80
+ byExtension: Record<string, ExtensionStats>;
81
+ byDirectory: Record<string, DirectoryStats>;
82
+ largestFiles: FileInfo[];
83
+ }
84
+
85
+ /**
86
+ * Method statistics
87
+ */
88
+ export interface MethodStats {
89
+ totalMethods: number;
90
+ includedMethods: number;
91
+ methodTokens: Record<string, number>;
92
+ }
93
+
94
+ /**
95
+ * LLM Context
96
+ */
97
+ export interface LLMContext {
98
+ project: {
99
+ root: string;
100
+ totalFiles: number;
101
+ totalTokens: number;
102
+ };
103
+ paths?: Record<string, string[]>;
104
+ methods?: Record<string, MethodInfo[]>;
105
+ methodStats?: MethodStats;
106
+ }
107
+
108
+ /**
109
+ * Token Calculator class
110
+ * Main class for analyzing projects and calculating tokens
111
+ */
112
+ export class TokenCalculator {
113
+ constructor(projectRoot: string, options?: TokenCalculatorOptions);
114
+
115
+ projectRoot: string;
116
+ options: TokenCalculatorOptions;
117
+ stats: AnalysisStats;
118
+ methodStats: MethodStats;
119
+
120
+ calculateTokens(content: string, filePath: string): number;
121
+ isTextFile(filePath: string): boolean;
122
+ isCodeFile(filePath: string): boolean;
123
+ analyzeFile(filePath: string): FileInfo;
124
+ scanDirectory(dir: string): string[];
125
+ analyze(): FileInfo[];
126
+ analyzeFiles(files: string[]): FileInfo[];
127
+ updateStats(fileInfo: FileInfo): void;
128
+ generateLLMContext(analysisResults: FileInfo[] | { files: FileInfo[] }): LLMContext;
129
+ exportContextToClipboard(context: LLMContext): void;
130
+ saveContextToFile(context: LLMContext): void;
131
+ saveDetailedReport(analysisResults: FileInfo[]): void;
132
+ saveGitIngestDigest(analysisResults: FileInfo[]): void;
133
+ run(): AnalysisStats;
134
+ }
135
+
136
+ /**
137
+ * @deprecated Use TokenCalculator instead
138
+ */
139
+ export class TokenAnalyzer extends TokenCalculator {}
140
+
141
+ /**
142
+ * Method Analyzer class
143
+ * Extracts methods from multiple programming languages
144
+ */
145
+ export class MethodAnalyzer {
146
+ extractMethods(content: string, filePath: string): MethodInfo[];
147
+ extractMethodContent(content: string, methodName: string): string | null;
148
+ extractJavaScriptMethods(content: string, filePath: string): MethodInfo[];
149
+ extractRustMethods(content: string, filePath: string): MethodInfo[];
150
+ extractJavaMethods(content: string, filePath: string): MethodInfo[];
151
+ extractCSharpMethods(content: string, filePath: string): MethodInfo[];
152
+ extractPythonMethods(content: string, filePath: string): MethodInfo[];
153
+ extractPHPMethods(content: string, filePath: string): MethodInfo[];
154
+ extractRubyMethods(content: string, filePath: string): MethodInfo[];
155
+ extractKotlinMethods(content: string, filePath: string): MethodInfo[];
156
+ extractSwiftMethods(content: string, filePath: string): MethodInfo[];
157
+ extractCPlusPlusMethods(content: string, filePath: string): MethodInfo[];
158
+ extractScalaMethods(content: string, filePath: string): MethodInfo[];
159
+ }
160
+
161
+ // ============================================
162
+ // Parsers
163
+ // ============================================
164
+
165
+ /**
166
+ * GitIgnore Pattern
167
+ */
168
+ export interface GitIgnorePattern {
169
+ regex: RegExp;
170
+ isNegation: boolean;
171
+ original: string;
172
+ isDirectory: boolean;
173
+ }
174
+
175
+ /**
176
+ * GitIgnore Parser class
177
+ * Parses .gitignore, .contextignore, and .contextinclude files
178
+ */
179
+ export class GitIgnoreParser {
180
+ constructor(gitignorePath?: string, contextIgnorePath?: string, contextIncludePath?: string);
181
+
182
+ patterns: GitIgnorePattern[];
183
+ contextPatterns: GitIgnorePattern[];
184
+ hasIncludeFile: boolean;
185
+ _lastIgnoreReason: string | null;
186
+
187
+ loadPatterns(
188
+ gitignorePath: string,
189
+ contextIgnorePath?: string,
190
+ contextIncludePath?: string
191
+ ): void;
192
+ parsePatternFile(filePath: string): GitIgnorePattern[];
193
+ convertToRegex(pattern: string): GitIgnorePattern;
194
+ isIgnored(filePath: string, relativePath: string): boolean;
195
+ testPatterns(patterns: GitIgnorePattern[], relativePath: string, reason: string): boolean;
196
+ }
197
+
198
+ /**
199
+ * Method Filter Pattern
200
+ */
201
+ export interface MethodFilterPattern {
202
+ pattern: string;
203
+ regex: RegExp;
204
+ }
205
+
206
+ /**
207
+ * Method Filter Parser class
208
+ * Parses .methodinclude and .methodignore files
209
+ */
210
+ export class MethodFilterParser {
211
+ constructor(methodIncludePath?: string, methodIgnorePath?: string);
212
+
213
+ includePatterns: MethodFilterPattern[];
214
+ ignorePatterns: MethodFilterPattern[];
215
+ hasIncludeFile: boolean;
216
+
217
+ parseMethodFile(filePath: string): MethodFilterPattern[];
218
+ shouldIncludeMethod(methodName: string, fileName: string): boolean;
219
+ }
220
+
221
+ // ============================================
222
+ // Formatters
223
+ // ============================================
224
+
225
+ /**
226
+ * GitIngest Formatter Options
227
+ */
228
+ export interface GitIngestFormatterOptions {
229
+ chunking?: {
230
+ enabled?: boolean;
231
+ strategy?: 'smart' | 'size' | 'file' | 'directory' | 'dependency';
232
+ maxTokensPerChunk?: number;
233
+ overlap?: number;
234
+ preserveContext?: boolean;
235
+ includeMetadata?: boolean;
236
+ crossReferences?: boolean;
237
+ };
238
+ }
239
+
240
+ /**
241
+ * Chunk data for large repositories
242
+ */
243
+ export interface ChunkData {
244
+ id: string;
245
+ index: number;
246
+ total: number;
247
+ content: string;
248
+ files: string[];
249
+ tokens: number;
250
+ metadata: Record<string, unknown>;
251
+ hasOverlap?: boolean;
252
+ overlapFiles?: string[];
253
+ }
254
+
255
+ /**
256
+ * GitIngest Formatter class
257
+ * Formats analyzed code into a single prompt-friendly text file
258
+ */
259
+ export class GitIngestFormatter {
260
+ constructor(
261
+ projectRoot: string,
262
+ stats: AnalysisStats,
263
+ analysisResults: FileInfo[],
264
+ options?: GitIngestFormatterOptions
265
+ );
266
+
267
+ projectRoot: string;
268
+ stats: AnalysisStats;
269
+ analysisResults: FileInfo[];
270
+ options: GitIngestFormatterOptions;
271
+ chunking: GitIngestFormatterOptions['chunking'] & {
272
+ enabled: boolean;
273
+ strategy: string;
274
+ maxTokensPerChunk: number;
275
+ overlap: number;
276
+ preserveContext: boolean;
277
+ includeMetadata: boolean;
278
+ crossReferences: boolean;
279
+ };
280
+ methodFilterEnabled: boolean;
281
+ methodAnalyzer?: MethodAnalyzer;
282
+ methodFilter?: MethodFilterParser | null;
283
+
284
+ generateDigest(): string;
285
+ generateChunkedDigest(): ChunkData[];
286
+ createChunks(): Array<{
287
+ files: FileInfo[];
288
+ tokens: number;
289
+ directories?: Set<string>;
290
+ metadata?: Record<string, unknown>;
291
+ }>;
292
+ saveToFile(outputPath: string): number;
293
+ }
294
+
295
+ /**
296
+ * Toon Formatter Options
297
+ */
298
+ export interface ToonFormatterOptions {
299
+ indent?: number;
300
+ delimiter?: ',' | '\t' | '|';
301
+ lengthMarker?: boolean;
302
+ }
303
+
304
+ /**
305
+ * Toon Formatter class
306
+ * Tabular Object Oriented Notation formatter (40-50% token reduction)
307
+ */
308
+ export class ToonFormatter {
309
+ constructor(options?: ToonFormatterOptions);
310
+
311
+ options: ToonFormatterOptions & {
312
+ indent: number;
313
+ delimiter: string;
314
+ lengthMarker: boolean;
315
+ };
316
+ indentChar: string;
317
+
318
+ encode(data: unknown, options?: ToonFormatterOptions): string;
319
+ encodeAsync(data: unknown, options?: ToonFormatterOptions): Promise<string>;
320
+ encodeSync(data: unknown, options?: ToonFormatterOptions): string;
321
+ decode(toonString: string, options?: ToonFormatterOptions): unknown;
322
+ decodeAsync(toonString: string, options?: ToonFormatterOptions): Promise<unknown>;
323
+ validate(toonString: string): { valid: boolean; errors: string[] };
324
+ estimateTokens(toonString: string): number;
325
+ optimize(toonString: string): string;
326
+ minify(toonString: string): string;
327
+ compareWithJSON(data: unknown): {
328
+ toon: string;
329
+ json: string;
330
+ toonSize: number;
331
+ jsonSize: number;
332
+ savings: number;
333
+ savingsPercentage: number;
334
+ toonTokens: number;
335
+ jsonTokens: number;
336
+ };
337
+ compareWithOfficial(
338
+ data: unknown,
339
+ options?: ToonFormatterOptions
340
+ ): Promise<{
341
+ custom: string;
342
+ official: string;
343
+ customSize: number;
344
+ officialSize: number;
345
+ difference: number;
346
+ officialIsBetter: boolean;
347
+ }>;
348
+ }
349
+
350
+ /**
351
+ * Format Info
352
+ */
353
+ export interface FormatInfo {
354
+ name: string;
355
+ description: string;
356
+ extension: string;
357
+ mimeType: string;
358
+ }
359
+
360
+ /**
361
+ * Format Encoder Function
362
+ */
363
+ export type FormatEncoder = (data: unknown, options?: Record<string, unknown>) => string;
364
+
365
+ /**
366
+ * Format Registration
367
+ */
368
+ export interface FormatRegistration {
369
+ name: string;
370
+ description: string;
371
+ extension: string;
372
+ mimeType: string;
373
+ encoder: FormatEncoder;
374
+ }
375
+
376
+ /**
377
+ * Format Registry class
378
+ * Central registry for all output format exporters
379
+ */
380
+ export class FormatRegistry {
381
+ constructor();
382
+
383
+ formatters: Map<string, FormatRegistration>;
384
+
385
+ register(name: string, formatter: FormatRegistration): void;
386
+ get(name: string): FormatRegistration;
387
+ has(name: string): boolean;
388
+ listFormats(): string[];
389
+ getInfo(name: string): FormatInfo;
390
+ getAllInfo(): Record<string, FormatInfo>;
391
+ encode(name: string, data: unknown, options?: Record<string, unknown>): string;
392
+ encodeYAML(data: unknown, indent?: number): string;
393
+ encodeMarkdown(data: unknown): string;
394
+ encodeCSV(data: unknown): string;
395
+ encodeXML(data: unknown, indent?: number): string;
396
+ suggestFormat(data: unknown): string;
397
+ }
398
+
399
+ // ============================================
400
+ // Utils
401
+ // ============================================
402
+
403
+ /**
404
+ * Token Utils class
405
+ * Token counting and formatting utilities
406
+ */
407
+ export class TokenUtils {
408
+ static calculateForModel(content: string, modelName: string): Promise<number>;
409
+ static calculate(content: string, filePath: string): number;
410
+ static estimate(content: string, filePath: string): number;
411
+ static format(tokens: number): string;
412
+ static getMethodForModel(modelName: string): Promise<string>;
413
+ static getMethod(): string;
414
+ static isExact(): boolean;
415
+ static hasExactCounting(): boolean;
416
+ static getAvailableTokenizers(): Promise<Array<{ name: string; available: boolean }>>;
417
+ static detectTokenizer(modelName: string): Promise<string>;
418
+ static getTelemetry(): Promise<Record<string, unknown>>;
419
+ static resetTelemetry(): Promise<void>;
420
+ }
421
+
422
+ /**
423
+ * File Utils class
424
+ * File type detection and utilities
425
+ */
426
+ export class FileUtils {
427
+ static isText(filePath: string): boolean;
428
+ static isCode(filePath: string): boolean;
429
+ static getType(filePath: string): 'code' | 'config' | 'doc' | 'style' | 'other';
430
+ static getExtension(filePath: string): string;
431
+ }
432
+
433
+ /**
434
+ * Clipboard Utils class
435
+ * Cross-platform clipboard utilities
436
+ */
437
+ export class ClipboardUtils {
438
+ static copy(text: string): boolean;
439
+ static isAvailable(): boolean;
440
+ static getCommand(): string;
441
+ }
442
+
443
+ /**
444
+ * Config Utils class
445
+ * Configuration file utilities
446
+ */
447
+ export class ConfigUtils {
448
+ static findConfigFile(projectRoot: string, filename: string): string | undefined;
449
+ static initMethodFilter(projectRoot: string): MethodFilterParser | null;
450
+ static detectMethodFilters(projectRoot: string): boolean;
451
+ static initGitIgnore(projectRoot: string): GitIgnoreParser;
452
+ static getConfigPaths(projectRoot: string): {
453
+ gitignore: string;
454
+ contextIgnore: string | undefined;
455
+ contextInclude: string | undefined;
456
+ methodInclude: string | undefined;
457
+ methodIgnore: string | undefined;
458
+ };
459
+ }
460
+
461
+ /**
462
+ * Conversion Result
463
+ */
464
+ export interface ConversionResult {
465
+ output: string;
466
+ metadata: {
467
+ inputSize: number;
468
+ outputSize: number;
469
+ savings: number;
470
+ savingsPercentage: number;
471
+ fromFormat: string;
472
+ toFormat: string;
473
+ };
474
+ }
475
+
476
+ /**
477
+ * File Conversion Result
478
+ */
479
+ export interface FileConversionResult {
480
+ inputFile: string;
481
+ outputFile: string;
482
+ fromFormat: string;
483
+ toFormat: string;
484
+ inputSize: number;
485
+ outputSize: number;
486
+ savings: number;
487
+ savingsPercent: string;
488
+ }
489
+
490
+ /**
491
+ * Batch Conversion Item
492
+ */
493
+ export interface BatchConversionItem {
494
+ input: string;
495
+ output: string;
496
+ from?: string;
497
+ to?: string;
498
+ }
499
+
500
+ /**
501
+ * Batch Conversion Result
502
+ */
503
+ export interface BatchConversionResult {
504
+ success: boolean;
505
+ inputFile?: string;
506
+ outputFile?: string;
507
+ error?: string;
508
+ fromFormat?: string;
509
+ toFormat?: string;
510
+ inputSize?: number;
511
+ outputSize?: number;
512
+ savings?: number;
513
+ savingsPercent?: string;
514
+ }
515
+
516
+ /**
517
+ * Format Converter class
518
+ * Convert between different output formats
519
+ */
520
+ export class FormatConverter {
521
+ constructor();
522
+
523
+ registry: FormatRegistry;
524
+ toonFormatter: ToonFormatter;
525
+
526
+ convert(input: string, fromFormat: string, toFormat: string): ConversionResult;
527
+ parse(input: string, format: string): unknown;
528
+ encode(data: unknown, format: string): string;
529
+ parseYAML(yamlString: string): Record<string, unknown>;
530
+ parseCSV(csvString: string): { headers: string[]; rows: Record<string, string>[] };
531
+ convertFile(
532
+ inputFile: string,
533
+ outputFile: string,
534
+ fromFormat?: string | null,
535
+ toFormat?: string | null
536
+ ): FileConversionResult;
537
+ extensionToFormat(ext: string): string;
538
+ batchConvert(files: BatchConversionItem[]): BatchConversionResult[];
539
+ getSupportedConversions(): {
540
+ fullySupported: string[];
541
+ partialSupport: string[];
542
+ planned: string[];
543
+ };
544
+ }
545
+
546
+ /**
547
+ * Error Handler Options
548
+ */
549
+ export interface ErrorHandlerOptions {
550
+ verbose?: boolean;
551
+ logFile?: string | null;
552
+ }
553
+
554
+ /**
555
+ * Error Handler class
556
+ * Enhanced error handling and user-friendly messages
557
+ */
558
+ export class ErrorHandler {
559
+ constructor(options?: ErrorHandlerOptions);
560
+
561
+ verbose: boolean;
562
+ logFile: string | null;
563
+
564
+ handleFormatError(error: Error, format: string): void;
565
+ handleFileError(error: Error & { code?: string }, filePath: string): void;
566
+ handleParseError(error: Error, format: string, content?: string): void;
567
+ handleValidationError(errors: string[], context: string): void;
568
+ logError(message: string, error: Error | { errors?: string[] }): void;
569
+ wrapAsync<T extends (...args: unknown[]) => Promise<unknown>>(fn: T, context: string): T;
570
+ validateFormat(format: string, supportedFormats: string[]): void;
571
+ createUserMessage(error: Error & { code?: string }, context?: string): string;
572
+ }
573
+
574
+ /**
575
+ * Logger Options
576
+ */
577
+ export interface LoggerOptions {
578
+ level?: 'error' | 'warn' | 'info' | 'debug' | 'trace';
579
+ logToFile?: boolean;
580
+ logDir?: string;
581
+ logFile?: string;
582
+ silent?: boolean;
583
+ }
584
+
585
+ /**
586
+ * Logger class
587
+ * Centralized logging with multiple levels and file output
588
+ */
589
+ export class Logger {
590
+ constructor(options?: LoggerOptions);
591
+
592
+ level: string;
593
+ logToFile: boolean;
594
+ logDir: string;
595
+ logFile: string;
596
+ silent: boolean;
597
+ levels: Record<string, number>;
598
+ colors: Record<string, string>;
599
+ icons: Record<string, string>;
600
+
601
+ initializeLogDirectory(): void;
602
+ getDateString(): string;
603
+ getTimestamp(): string;
604
+ shouldLog(level: string): boolean;
605
+ formatMessage(
606
+ level: string,
607
+ message: string,
608
+ meta?: Record<string, unknown>
609
+ ): {
610
+ consoleMessage: string;
611
+ fileMessage: string;
612
+ };
613
+ writeToFile(message: string): void;
614
+ log(level: string, message: string, meta?: Record<string, unknown>): void;
615
+ error(message: string, meta?: Record<string, unknown>): void;
616
+ warn(message: string, meta?: Record<string, unknown>): void;
617
+ info(message: string, meta?: Record<string, unknown>): void;
618
+ debug(message: string, meta?: Record<string, unknown>): void;
619
+ trace(message: string, meta?: Record<string, unknown>): void;
620
+ custom(icon: string, level: string, message: string, meta?: Record<string, unknown>): void;
621
+ group(title: string): void;
622
+ groupEnd(): void;
623
+ time(label: string): void;
624
+ timeEnd(label: string): void;
625
+ clearOldLogs(daysToKeep?: number): void;
626
+ getLogFilePath(): string;
627
+ getRecentLogs(lines?: number): string[];
628
+ }
629
+
630
+ /**
631
+ * Get or create default logger instance
632
+ */
633
+ export function getLogger(options?: LoggerOptions): Logger;
634
+
635
+ /**
636
+ * Create a new logger instance
637
+ */
638
+ export function createLogger(options?: LoggerOptions): Logger;
639
+
640
+ /**
641
+ * Updater Options
642
+ */
643
+ export interface UpdaterOptions {
644
+ channel?: 'stable' | 'insider';
645
+ autoUpdate?: boolean;
646
+ checkInterval?: number;
647
+ configDir?: string;
648
+ }
649
+
650
+ /**
651
+ * Update Info
652
+ */
653
+ export interface UpdateInfo {
654
+ available: boolean;
655
+ currentVersion?: string;
656
+ latestVersion?: string;
657
+ channel?: string;
658
+ releaseNotes?: string;
659
+ downloadUrl?: string;
660
+ publishedAt?: string;
661
+ message?: string;
662
+ error?: string;
663
+ }
664
+
665
+ /**
666
+ * Install Result
667
+ */
668
+ export interface InstallResult {
669
+ success: boolean;
670
+ oldVersion?: string;
671
+ newVersion?: string;
672
+ backupPath?: string;
673
+ error?: string;
674
+ manualUpdateRequired?: boolean;
675
+ instructions?: string;
676
+ }
677
+
678
+ /**
679
+ * Rollback Result
680
+ */
681
+ export interface RollbackResult {
682
+ success: boolean;
683
+ restoredVersion?: string;
684
+ error?: string;
685
+ }
686
+
687
+ /**
688
+ * Updater class
689
+ * Auto-update system with version channels
690
+ */
691
+ export class Updater {
692
+ constructor(options?: UpdaterOptions);
693
+
694
+ currentVersion: string;
695
+ channel: 'stable' | 'insider';
696
+ autoUpdate: boolean;
697
+ checkInterval: number;
698
+ configDir: string;
699
+ updateCacheFile: string;
700
+ endpoints: {
701
+ stable: string;
702
+ insider: string;
703
+ version: string;
704
+ };
705
+
706
+ getCurrentVersion(): string;
707
+ fetchJSON(url: string): Promise<unknown>;
708
+ compareVersions(v1: string, v2: string): -1 | 0 | 1;
709
+ checkForUpdates(): Promise<UpdateInfo>;
710
+ getLatestVersion(): Promise<{
711
+ version: string;
712
+ releaseNotes: string;
713
+ downloadUrl: string;
714
+ publishedAt: string;
715
+ assets: unknown[];
716
+ } | null>;
717
+ installUpdate(updateInfo: UpdateInfo): Promise<InstallResult>;
718
+ detectInstallationType(): 'global' | 'local' | 'source' | 'unknown';
719
+ getInstallDir(): string | null;
720
+ createBackup(): string;
721
+ rollback(): Promise<RollbackResult>;
722
+ switchChannel(newChannel: 'stable' | 'insider'): Promise<UpdateInfo>;
723
+ saveConfig(config: { channel?: string; autoUpdate?: boolean }): void;
724
+ getUpdateCache(): Record<string, unknown> | null;
725
+ saveUpdateCache(data: Record<string, unknown>): void;
726
+ shouldCheckForUpdates(): boolean;
727
+ checkAndNotify(): Promise<UpdateInfo>;
728
+ showUpdateNotification(updateInfo: UpdateInfo): void;
729
+ }
730
+
731
+ /**
732
+ * Git Utils Options
733
+ */
734
+ export interface GitUtilsOptions {
735
+ tempDir?: string;
736
+ outputDir?: string;
737
+ verbose?: boolean;
738
+ }
739
+
740
+ /**
741
+ * GitHub Repository Info
742
+ */
743
+ export interface GitHubRepoInfo {
744
+ owner: string;
745
+ repo: string;
746
+ branch: string;
747
+ fullName: string;
748
+ cloneUrl: string;
749
+ apiUrl: string;
750
+ rawUrl: string;
751
+ originalUrl: string;
752
+ }
753
+
754
+ /**
755
+ * Repository Generation Stats
756
+ */
757
+ export interface RepoGenerationStats {
758
+ repository: string;
759
+ branch: string;
760
+ url: string;
761
+ localPath: string;
762
+ outputFile: string;
763
+ digestSize: number;
764
+ digestSizeKB: string;
765
+ files: number;
766
+ tokens: number;
767
+ lines: number;
768
+ }
769
+
770
+ /**
771
+ * Repository Info from API
772
+ */
773
+ export interface RepositoryAPIInfo {
774
+ name: string;
775
+ fullName: string;
776
+ description: string;
777
+ stars: number;
778
+ forks: number;
779
+ defaultBranch: string;
780
+ size: number;
781
+ language: string;
782
+ updatedAt: string;
783
+ }
784
+
785
+ /**
786
+ * Cached Repository
787
+ */
788
+ export interface CachedRepo {
789
+ name: string;
790
+ path: string;
791
+ size: number;
792
+ }
793
+
794
+ /**
795
+ * Git Utils class
796
+ * GitHub URL parsing, repository cloning, and GitIngest generation
797
+ */
798
+ export class GitUtils {
799
+ constructor(options?: GitUtilsOptions);
800
+
801
+ tempDir: string;
802
+ outputDir: string;
803
+ verbose: boolean;
804
+
805
+ parseGitHubURL(url: string): GitHubRepoInfo;
806
+ isGitInstalled(): boolean;
807
+ cloneRepository(
808
+ repoInfo: GitHubRepoInfo,
809
+ options?: { shallow?: boolean; depth?: number }
810
+ ): string;
811
+ generateFromGitHub(
812
+ url: string,
813
+ options?: {
814
+ outputFile?: string;
815
+ cleanup?: boolean;
816
+ shallow?: boolean;
817
+ analyzerOptions?: TokenCalculatorOptions;
818
+ formatterOptions?: GitIngestFormatterOptions;
819
+ }
820
+ ): Promise<RepoGenerationStats>;
821
+ fetchFileFromGitHub(url: string): Promise<string>;
822
+ getRepositoryInfo(repoInfo: GitHubRepoInfo): Promise<RepositoryAPIInfo>;
823
+ cleanupTemp(): void;
824
+ listCachedRepos(): CachedRepo[];
825
+ getDirectorySize(dir: string): number;
826
+ }
827
+
828
+ // ============================================
829
+ // Orchestrator Functions
830
+ // ============================================
831
+
832
+ /**
833
+ * Generate GitIngest digest from token-analysis-report.json
834
+ */
835
+ export function generateDigestFromReport(reportPath: string): void;
836
+
837
+ /**
838
+ * Generate GitIngest digest from llm-context.json
839
+ */
840
+ export function generateDigestFromContext(contextPath: string): void;
841
+
842
+ // ============================================
843
+ // Repository Map (ctxman map)
844
+ // ============================================
845
+
846
+ /**
847
+ * A function or method of a mapped file
848
+ */
849
+ export interface RepoMapMethod {
850
+ name: string;
851
+ /** 1-based line of the declaration */
852
+ line: number;
853
+ /** Declaration on one line, secrets redacted unless `redact: false` */
854
+ signature: string;
855
+ }
856
+
857
+ /**
858
+ * A source file of the repository graph
859
+ */
860
+ export interface RepoGraphNode {
861
+ /** Project-relative path with forward slashes */
862
+ path: string;
863
+ language: string;
864
+ bytes: number;
865
+ methods: RepoMapMethod[];
866
+ /** Mentions of this file's function names in other files (shared between definers) */
867
+ symbolRefs: number;
868
+ /** Imports that named no file of the project (packages, standard library) */
869
+ unresolvedImports: number;
870
+ }
871
+
872
+ /**
873
+ * Import edge, importer -> imported. A package-wide import (Go, Java wildcard, C# using)
874
+ * spreads weight 1 over the files of the package.
875
+ */
876
+ export interface RepoGraphEdge {
877
+ from: string;
878
+ to: string;
879
+ weight: number;
880
+ }
881
+
882
+ export interface RepoGraph {
883
+ /** Absolute project root */
884
+ root: string;
885
+ nodes: RepoGraphNode[];
886
+ edges: RepoGraphEdge[];
887
+ history: {
888
+ available: boolean;
889
+ requested: number;
890
+ commits: number;
891
+ /** Commits touching each file */
892
+ counts: Record<string, number>;
893
+ reason?: string;
894
+ };
895
+ stats: {
896
+ scannedFiles: number;
897
+ files: number;
898
+ edges: number;
899
+ unresolvedImports: number;
900
+ skipped: Array<{ path: string; reason: string }>;
901
+ redactions: Record<string, number>;
902
+ timings: Record<string, number>;
903
+ };
904
+ }
905
+
906
+ export interface RepoGraphOptions {
907
+ /** Commits of git history to mine for change frequency (default 300, 0 disables) */
908
+ history?: number;
909
+ /** Mask secrets in signatures (default true) */
910
+ redact?: boolean;
911
+ /** Leave out larger files (default 512 KiB) */
912
+ maxFileBytes?: number;
913
+ }
914
+
915
+ export interface RankWeights {
916
+ pagerank?: number;
917
+ history?: number;
918
+ symbols?: number;
919
+ }
920
+
921
+ export interface RankOptions {
922
+ /** Files or folders (project-relative or absolute) to personalise PageRank toward */
923
+ focus?: string[];
924
+ /** Blend of the normalised components (default 0.70 / 0.25 / 0.05) */
925
+ weights?: RankWeights;
926
+ /** PageRank damping (default 0.85) */
927
+ damping?: number;
928
+ }
929
+
930
+ export interface RankedFile {
931
+ path: string;
932
+ /** 1 = best */
933
+ rank: number;
934
+ /** Blended score in [0, 1] */
935
+ score: number;
936
+ /** Raw PageRank (all files sum to 1) */
937
+ pagerank: number;
938
+ /** Commits touching the file among the mined history */
939
+ changes: number;
940
+ symbolRefs: number;
941
+ focus: boolean;
942
+ /** Each component scaled to [0, 1] */
943
+ components: { pagerank: number; history: number; symbols: number };
944
+ }
945
+
946
+ export interface RepoMapOptions extends RepoGraphOptions, RankOptions {
947
+ /** Token budget of the rendered map (default 2048) */
948
+ tokens?: number;
949
+ /** Order of the files in the output (default 'rank') */
950
+ order?: 'rank' | 'path';
951
+ /** Highest-ranked file last (rank order only) */
952
+ importantLast?: boolean;
953
+ style?: 'text' | 'markdown' | 'json' | 'dot';
954
+ /** Render the dependency edges instead of the map */
955
+ graph?: boolean;
956
+ }
957
+
958
+ export interface RepoMapFile {
959
+ path: string;
960
+ rank: number;
961
+ score: number;
962
+ /** Tokens of the whole file */
963
+ tokens: number;
964
+ methods: Array<RepoMapMethod & { tokens: number }>;
965
+ }
966
+
967
+ export interface RepoMapResult {
968
+ output: string;
969
+ style: string;
970
+ budget: number;
971
+ /** Tokens of the rendered map (for json: of the same map rendered as text) */
972
+ tokens: number;
973
+ /** Files in the map, in output order */
974
+ files: RepoMapFile[];
975
+ /** Every file, best first */
976
+ ranked: RankedFile[];
977
+ graph: RepoGraph;
978
+ /** Files that did not fit the budget */
979
+ skipped: number;
980
+ warnings: string[];
981
+ stats: RepoGraph['stats'];
982
+ }
983
+
984
+ /**
985
+ * Scan a project (respecting .gitignore/.contextignore/.contextinclude) and build its
986
+ * file dependency graph from imports
987
+ */
988
+ export function buildRepoGraph(root: string, options?: RepoGraphOptions): RepoGraph;
989
+
990
+ /**
991
+ * Rank the files of a graph, best first: PageRank blended with git change frequency and
992
+ * symbol references
993
+ */
994
+ export function rankFiles(graph: RepoGraph, options?: RankOptions): RankedFile[];
995
+
996
+ /**
997
+ * Build, rank and render the repository map of a project within a token budget
998
+ */
999
+ export function renderRepoMap(root: string, options?: RepoMapOptions): RepoMapResult;
1000
+
1001
+ // ============================================
1002
+ // Pull-request review context
1003
+ // ============================================
1004
+
1005
+ export type PrContextStyle = 'markdown' | 'xml' | 'json';
1006
+
1007
+ export interface PrContextOptions {
1008
+ /** Base revision (default: origin/HEAD, else main, else master; HEAD with staged/working) */
1009
+ base?: string;
1010
+ /** Head revision (default: HEAD) */
1011
+ head?: string;
1012
+ /** Compare the index instead of a head commit */
1013
+ staged?: boolean;
1014
+ /** Compare the working tree (untracked files included) instead of a head commit */
1015
+ working?: boolean;
1016
+ /** Context lines in the diff (default: 3) */
1017
+ unified?: number;
1018
+ /** Include the unified diff (default: true) */
1019
+ diff?: boolean;
1020
+ /** Include the related tests' contents */
1021
+ withTests?: boolean;
1022
+ /** Include the changed files' full contents */
1023
+ withFiles?: boolean;
1024
+ /** Question appended at the end */
1025
+ ask?: string;
1026
+ /** Instructions appended at the end */
1027
+ instructions?: string;
1028
+ /** Maximum tokens of the output; lower-priority material is dropped first */
1029
+ budget?: number;
1030
+ /** Output style (default: markdown) */
1031
+ style?: PrContextStyle;
1032
+ /** Mask secrets in contents, diff and commit messages (default: true) */
1033
+ redact?: boolean;
1034
+ /** Skip file contents larger than this for methods and full contents (default: 1 MiB) */
1035
+ maxFileBytes?: number;
1036
+ /** Most related tests to list (default: 50) */
1037
+ maxRelatedTests?: number;
1038
+ }
1039
+
1040
+ export interface PrRevision {
1041
+ ref: string;
1042
+ sha: string | null;
1043
+ short: string | null;
1044
+ }
1045
+
1046
+ export interface PrChangedFile {
1047
+ /** A, M, D, R, C or T */
1048
+ status: string;
1049
+ path: string;
1050
+ oldPath: string | null;
1051
+ similarity: number | null;
1052
+ additions: number;
1053
+ deletions: number;
1054
+ binary: boolean;
1055
+ untracked: boolean;
1056
+ /** Filter that keeps the file's content out (.contextignore, ...), or null */
1057
+ excluded: string | null;
1058
+ }
1059
+
1060
+ export interface PrMethod {
1061
+ file: string;
1062
+ name: string;
1063
+ start: number;
1064
+ end: number;
1065
+ }
1066
+
1067
+ export interface PrChangedMethod extends PrMethod {
1068
+ change: 'added' | 'modified';
1069
+ changedLines: number;
1070
+ source: string;
1071
+ sourceDropped: boolean;
1072
+ }
1073
+
1074
+ export interface PrCommit {
1075
+ sha: string;
1076
+ short: string;
1077
+ author: string;
1078
+ date: string;
1079
+ subject: string;
1080
+ body: string;
1081
+ }
1082
+
1083
+ export interface PrRelatedTest {
1084
+ path: string;
1085
+ reasons: string[];
1086
+ changed: boolean;
1087
+ excluded: string | null;
1088
+ }
1089
+
1090
+ export interface PrContextResult {
1091
+ /** The rendered context */
1092
+ output: string;
1093
+ /** Tokens of `output` */
1094
+ tokens: number;
1095
+ style: PrContextStyle;
1096
+ mode: 'range' | 'staged' | 'working';
1097
+ base: PrRevision;
1098
+ head: PrRevision;
1099
+ mergeBase: { sha: string; short: string };
1100
+ /** Directory the change was limited to ('' for the whole repository) */
1101
+ scope: string;
1102
+ stats: {
1103
+ commits: number;
1104
+ files: number;
1105
+ byStatus: Record<string, number>;
1106
+ additions: number;
1107
+ deletions: number;
1108
+ excluded: number;
1109
+ changedMethods: number;
1110
+ addedMethods: number;
1111
+ deletedMethods: number;
1112
+ relatedTests: number;
1113
+ };
1114
+ /** Tokens per rendered section */
1115
+ sections: Record<string, number>;
1116
+ budget: { limit: number; dropped: string[]; over: boolean } | null;
1117
+ commits: PrCommit[];
1118
+ files: PrChangedFile[];
1119
+ methods: { changed: PrChangedMethod[]; deleted: PrMethod[] };
1120
+ relatedTests: PrRelatedTest[];
1121
+ /** Redacted matches per secret type */
1122
+ redactions: Record<string, number>;
1123
+ warnings: string[];
1124
+ }
1125
+
1126
+ /**
1127
+ * Build review context for a branch (merge base of base and head up to head), the staged
1128
+ * changes or the working tree
1129
+ */
1130
+ export function buildPrContext(root?: string, options?: PrContextOptions): Promise<PrContextResult>;
1131
+
1132
+ // ============================================
1133
+ // ctxman why
1134
+ // ============================================
1135
+
1136
+ /**
1137
+ * Target of explainHistory() given as an object instead of "file:symbol" / "file#L1-L9"
1138
+ */
1139
+ export interface ExplainHistoryTarget {
1140
+ file: string;
1141
+ /** Function, method or class: "total", "Cart.total", "Cart::total" */
1142
+ symbol?: string;
1143
+ startLine?: number;
1144
+ endLine?: number;
1145
+ }
1146
+
1147
+ export interface ExplainHistoryOptions {
1148
+ /** Commits to include (default 20) */
1149
+ limit?: number;
1150
+ /** Only commits after this date, in git's date syntax */
1151
+ since?: string;
1152
+ /** Explain the code as of this revision instead of the working tree */
1153
+ rev?: string;
1154
+ /** Include each commit's diff of the target */
1155
+ patches?: boolean;
1156
+ /** Commits of the file examined for co-changes (default 500, 0 = off) */
1157
+ couplingWindow?: number;
1158
+ /** Co-changed files listed (default 10) */
1159
+ couplingTop?: number;
1160
+ /** Commits touching more files are ignored for coupling (default 50) */
1161
+ maxFilesPerCommit?: number;
1162
+ /** Related text snippets listed (default 20) */
1163
+ maxRelated?: number;
1164
+ /** Test files listed (default 10) */
1165
+ maxTests?: number;
1166
+ style?: 'markdown' | 'xml' | 'json';
1167
+ /** Maximum tokens of the output */
1168
+ budget?: number;
1169
+ /** Question appended at the end of the document */
1170
+ ask?: string;
1171
+ /** Mask secrets (default true) */
1172
+ redact?: boolean;
1173
+ /** Directory relative target paths start from (default: root) */
1174
+ cwd?: string;
1175
+ }
1176
+
1177
+ export interface WhyCommit {
1178
+ sha: string;
1179
+ shortSha: string;
1180
+ /** Author date, ISO 8601 in UTC: 2024-01-02T10:00:00Z */
1181
+ date: string;
1182
+ author: string;
1183
+ email: string;
1184
+ merge: boolean;
1185
+ subject: string;
1186
+ body: string;
1187
+ /** Issue / ticket ids this commit mentions */
1188
+ refs: string[];
1189
+ patch?: string;
1190
+ /** Oldest commit a shallow clone has: its parents were not fetched */
1191
+ shallowBoundary?: boolean;
1192
+ }
1193
+
1194
+ export interface WhyIssueReference {
1195
+ /** "#12", or "owner/repo#12" for another repository */
1196
+ id: string;
1197
+ number: number;
1198
+ repo: string | null;
1199
+ kind: 'issue' | 'pr' | 'mr';
1200
+ /** Referred to with fixes / closes / resolves */
1201
+ closes: boolean;
1202
+ url: string | null;
1203
+ commits: string[];
1204
+ }
1205
+
1206
+ export interface ExplainHistoryData {
1207
+ target: {
1208
+ path: string;
1209
+ symbol: string | null;
1210
+ kind: string | null;
1211
+ line: number | null;
1212
+ resolvedBy: string | null;
1213
+ startLine: number | null;
1214
+ endLine: number | null;
1215
+ totalLines: number;
1216
+ wholeFile: boolean;
1217
+ binary: boolean;
1218
+ revision: string;
1219
+ symbolsInRange: string[];
1220
+ contentOmitted: string | null;
1221
+ source: string | null;
1222
+ };
1223
+ repository: { remote: string | null; provider: string | null; shallow: boolean };
1224
+ history: {
1225
+ mode: 'range' | 'funcname' | 'file' | 'none';
1226
+ startLine: number | null;
1227
+ endLine: number | null;
1228
+ funcname?: string;
1229
+ since: string | null;
1230
+ limit: number;
1231
+ limitReached: boolean;
1232
+ reason?: string;
1233
+ commits: WhyCommit[];
1234
+ };
1235
+ references: {
1236
+ issues: WhyIssueReference[];
1237
+ tickets: Array<{ id: string; commits: string[] }>;
1238
+ cves: Array<{ id: string; commits: string[] }>;
1239
+ urls: Array<{ url: string; commits: string[] }>;
1240
+ coAuthors: Array<{ value: string; commits: string[] }>;
1241
+ reviewers: Array<{ value: string; commits: string[] }>;
1242
+ };
1243
+ ownership: {
1244
+ startLine: number | null;
1245
+ endLine: number | null;
1246
+ totalLines: number;
1247
+ /** ISO 8601 in UTC, like the dates below */
1248
+ lastChanged: string | null;
1249
+ authors: Array<{
1250
+ name: string;
1251
+ lines: number;
1252
+ share: number;
1253
+ commits: number;
1254
+ lastTouched: string | null;
1255
+ }>;
1256
+ } | null;
1257
+ coupling: {
1258
+ window: number;
1259
+ targetChanges: number;
1260
+ skippedLargeCommits: number;
1261
+ maxFilesPerCommit: number;
1262
+ totalFiles: number;
1263
+ files: Array<{ path: string; count: number; confidence: number; exists: boolean }>;
1264
+ } | null;
1265
+ related: Array<{
1266
+ path: string;
1267
+ line: number;
1268
+ kind: 'adr' | 'changelog' | 'doc' | 'comment';
1269
+ mentions: 'symbol' | 'file';
1270
+ heading: string | null;
1271
+ snippet: string;
1272
+ }>;
1273
+ notes: Array<{ line: number; tag: string; text: string; author?: string }>;
1274
+ tests: Array<{
1275
+ path: string;
1276
+ references: 'symbol' | 'file';
1277
+ matches: Array<{ line: number; text: string }>;
1278
+ totalMatches: number;
1279
+ }>;
1280
+ warnings: string[];
1281
+ question: string | null;
1282
+ }
1283
+
1284
+ export interface ExplainHistoryResult {
1285
+ /** The rendered document */
1286
+ text: string;
1287
+ style: 'markdown' | 'xml' | 'json';
1288
+ tokens: number;
1289
+ budget: number | null;
1290
+ /** Items dropped to fit the budget, per section */
1291
+ omitted: Record<string, number>;
1292
+ warnings: string[];
1293
+ /** Everything collected (before budget trimming, after redaction) */
1294
+ data: ExplainHistoryData;
1295
+ }
1296
+
1297
+ /**
1298
+ * Explain why code looks the way it does, from the local git history: commits, referenced
1299
+ * issues and tickets, ownership, co-changed files, related docs, notes and tests.
1300
+ * Errors carry a `code` (NOT_A_GIT_REPO, PATH_OUTSIDE_ROOT, FILE_NOT_FOUND, NOT_TRACKED,
1301
+ * SYMBOL_NOT_FOUND, INVALID_RANGE, INVALID_REF, BUDGET_TOO_SMALL, ...)
1302
+ * @param root - Project directory inside a git work tree
1303
+ * @param target - "file", "file:symbol", "file#L10-L40" or an object
1304
+ */
1305
+ export function explainHistory(
1306
+ root: string,
1307
+ target: string | ExplainHistoryTarget,
1308
+ options?: ExplainHistoryOptions
1309
+ ): Promise<ExplainHistoryResult>;
1310
+ // Packed file contents (`ctxman pack`)
1311
+ // ============================================
1312
+
1313
+ export type PackStyle = 'xml' | 'markdown' | 'plain' | 'json';
1314
+
1315
+ export interface PackOptions {
1316
+ /** Output style (default: xml, Anthropic's `<documents>` long-context format) */
1317
+ style?: PackStyle;
1318
+ /** Gitignore-style globs: keep only matching files */
1319
+ include?: string[];
1320
+ /** Gitignore-style globs: leave matching files out */
1321
+ exclude?: string[];
1322
+ /**
1323
+ * Explicit file list instead of scanning the root. Entries must lie inside the root
1324
+ * (PATH_OUTSIDE_ROOT otherwise); .gitignore/.contextignore/.contextinclude still apply.
1325
+ */
1326
+ files?: string[];
1327
+ /** Base directory for relative `files` entries (default: the root) */
1328
+ cwd?: string;
1329
+ /** Absolute paths to leave out (e.g. the output file) */
1330
+ excludeFiles?: string[];
1331
+ /** Skip files larger than this many bytes (default: 1 MiB) */
1332
+ maxFileSize?: number;
1333
+ /** Directory tree at the top (default: true) */
1334
+ tree?: boolean;
1335
+ /** Text at the top */
1336
+ header?: string;
1337
+ /** Text at the end, after the files (long documents first, the query last) */
1338
+ instructions?: string;
1339
+ /** Number every line with its original line number */
1340
+ lineNumbers?: boolean;
1341
+ /** Keep signatures, replace function bodies with a one-line placeholder */
1342
+ compress?: boolean;
1343
+ /** Mask secrets (default: true) */
1344
+ redact?: boolean;
1345
+ /**
1346
+ * Token limit for the whole rendered document: the highest-ranked files (ranking of
1347
+ * `ctxman map`) are packed first, the others are listed as omitted
1348
+ */
1349
+ budget?: number;
1350
+ /** Token limit per part: adds `parts` to the result */
1351
+ split?: number;
1352
+ /** Count with this model's tiktoken encoding and report the fit in `model` */
1353
+ targetModel?: string;
1354
+ }
1355
+
1356
+ export interface PackedFile {
1357
+ /** Project-relative path with `/` separators */
1358
+ path: string;
1359
+ /** Tokens of the file's content as packed (after compression, numbering, redaction) */
1360
+ tokens: number;
1361
+ /** Lines of the original file */
1362
+ lines: number;
1363
+ compressed: boolean;
1364
+ }
1365
+
1366
+ export interface PackPart {
1367
+ /** 1-based part number */
1368
+ index: number;
1369
+ text: string;
1370
+ tokens: number;
1371
+ /** Files in the part; pieces of a file split by lines read "path (lines a-b)" */
1372
+ files: string[];
1373
+ }
1374
+
1375
+ export interface PackModelFit {
1376
+ id: string;
1377
+ name: string;
1378
+ vendor: string;
1379
+ /** tiktoken encoding used ('estimate' without tiktoken) */
1380
+ encoding: string;
1381
+ /** Whether the encoding is the model's own tokenizer */
1382
+ exact: boolean;
1383
+ contextWindow: number;
1384
+ maxRecommendedInput: number | null;
1385
+ fits: boolean;
1386
+ percentOfWindow: number;
1387
+ }
1388
+
1389
+ export interface PackResult {
1390
+ /** The whole document (also when it is split) */
1391
+ text: string;
1392
+ style: PackStyle;
1393
+ /** tiktoken encoding of every count ('estimate' without tiktoken) */
1394
+ encoding: string;
1395
+ /** Tokens of `text` */
1396
+ totalTokens: number;
1397
+ files: PackedFile[];
1398
+ /** Files left out by the budget, most important first */
1399
+ omitted: Array<{ path: string; tokens: number }>;
1400
+ /** Files not packed: binary, too-large, unreadable, missing, not-a-file, ignored */
1401
+ skipped: Array<{ path: string; reason: string }>;
1402
+ redactions: { total: number; byType: Record<string, number> };
1403
+ compression: {
1404
+ files: number;
1405
+ bodies: number;
1406
+ originalTokens: number;
1407
+ compressedTokens: number;
1408
+ savedTokens: number;
1409
+ } | null;
1410
+ budget: { limit: number; used: number } | null;
1411
+ model: PackModelFit | null;
1412
+ parts: PackPart[] | null;
1413
+ /** Files larger than a part on their own, split by lines */
1414
+ splitFiles: Array<{ path: string; pieces: number }>;
1415
+ }
1416
+
1417
+ /**
1418
+ * Pack the contents of a project's files into one document. Rejects with a PackError
1419
+ * (`code`: ROOT_NOT_FOUND, PATH_OUTSIDE_ROOT, INVALID_OPTION, UNKNOWN_MODEL,
1420
+ * BUDGET_TOO_SMALL, SPLIT_TOO_SMALL).
1421
+ */
1422
+ export function packContext(root: string, options?: PackOptions): Promise<PackResult>;