ctxman 3.0.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 (190) hide show
  1. package/.ctxman/custom-profiles.example.json +20 -0
  2. package/.ctxman/llm-profiles.json +131 -0
  3. package/.ctxman/logs/ctxman-2026-07-02.log +156 -0
  4. package/.ctxman/self-knowledge/documents.lance/_transactions/0-b3dd1558-f95b-44b9-a154-18e8c330ae7a.txn +0 -0
  5. package/.ctxman/self-knowledge/documents.lance/_transactions/1-44bff6d4-e552-4010-a769-e09ad822698d.txn +0 -0
  6. package/.ctxman/self-knowledge/documents.lance/_transactions/10-37260794-5947-4ecb-b4c8-d732f58f40f1.txn +0 -0
  7. package/.ctxman/self-knowledge/documents.lance/_transactions/11-0d52a883-5518-463c-9b6d-986c3af89dfd.txn +0 -0
  8. package/.ctxman/self-knowledge/documents.lance/_transactions/12-ae354646-52f2-49c9-90fb-2e6ed8932663.txn +0 -0
  9. package/.ctxman/self-knowledge/documents.lance/_transactions/13-5d7d5e57-27da-498b-b734-091b9d38da13.txn +0 -0
  10. package/.ctxman/self-knowledge/documents.lance/_transactions/14-558ce928-810b-4252-a364-fdd1ee6f8a25.txn +0 -0
  11. package/.ctxman/self-knowledge/documents.lance/_transactions/15-27e3a58f-8b64-43b8-a9f4-e3369446968b.txn +0 -0
  12. package/.ctxman/self-knowledge/documents.lance/_transactions/16-a110c390-e5c8-4464-b976-bc7f5195fa15.txn +0 -0
  13. package/.ctxman/self-knowledge/documents.lance/_transactions/17-97513225-53de-4216-b61a-6337bd0cc4ad.txn +0 -0
  14. package/.ctxman/self-knowledge/documents.lance/_transactions/18-5ba450f0-c527-459c-bf4f-6d79b5e4285f.txn +0 -0
  15. package/.ctxman/self-knowledge/documents.lance/_transactions/19-600d3a63-5225-49e9-b8b7-30e037b564ab.txn +0 -0
  16. package/.ctxman/self-knowledge/documents.lance/_transactions/2-48a61b4e-92cf-4342-8376-914c1b99a9f9.txn +0 -0
  17. package/.ctxman/self-knowledge/documents.lance/_transactions/20-121dd912-5410-410e-84ff-82c7a23604a0.txn +0 -0
  18. package/.ctxman/self-knowledge/documents.lance/_transactions/3-bc6844ab-7ea3-4bb3-9ee1-538ce5664a9c.txn +0 -0
  19. package/.ctxman/self-knowledge/documents.lance/_transactions/4-d5e1754f-dbb5-454e-a9be-2a7da8d7bcf9.txn +0 -0
  20. package/.ctxman/self-knowledge/documents.lance/_transactions/5-4fae93df-0568-4b6f-8acf-8bef4bba6047.txn +0 -0
  21. package/.ctxman/self-knowledge/documents.lance/_transactions/6-4b1b8b87-068e-49a3-ba2b-d8dae628b252.txn +0 -0
  22. package/.ctxman/self-knowledge/documents.lance/_transactions/7-63d040fb-d2fa-4c0f-bed0-53411918a7b0.txn +0 -0
  23. package/.ctxman/self-knowledge/documents.lance/_transactions/8-c5628cf6-264c-420f-aab8-bc96a9083591.txn +0 -0
  24. package/.ctxman/self-knowledge/documents.lance/_transactions/9-c94570aa-5e53-4fcb-971f-cecc1d1d5492.txn +0 -0
  25. package/.ctxman/self-knowledge/documents.lance/_versions/1.manifest +0 -0
  26. package/.ctxman/self-knowledge/documents.lance/_versions/10.manifest +0 -0
  27. package/.ctxman/self-knowledge/documents.lance/_versions/11.manifest +0 -0
  28. package/.ctxman/self-knowledge/documents.lance/_versions/12.manifest +0 -0
  29. package/.ctxman/self-knowledge/documents.lance/_versions/13.manifest +0 -0
  30. package/.ctxman/self-knowledge/documents.lance/_versions/14.manifest +0 -0
  31. package/.ctxman/self-knowledge/documents.lance/_versions/15.manifest +0 -0
  32. package/.ctxman/self-knowledge/documents.lance/_versions/16.manifest +0 -0
  33. package/.ctxman/self-knowledge/documents.lance/_versions/17.manifest +0 -0
  34. package/.ctxman/self-knowledge/documents.lance/_versions/18.manifest +0 -0
  35. package/.ctxman/self-knowledge/documents.lance/_versions/19.manifest +0 -0
  36. package/.ctxman/self-knowledge/documents.lance/_versions/2.manifest +0 -0
  37. package/.ctxman/self-knowledge/documents.lance/_versions/20.manifest +0 -0
  38. package/.ctxman/self-knowledge/documents.lance/_versions/21.manifest +0 -0
  39. package/.ctxman/self-knowledge/documents.lance/_versions/3.manifest +0 -0
  40. package/.ctxman/self-knowledge/documents.lance/_versions/4.manifest +0 -0
  41. package/.ctxman/self-knowledge/documents.lance/_versions/5.manifest +0 -0
  42. package/.ctxman/self-knowledge/documents.lance/_versions/6.manifest +0 -0
  43. package/.ctxman/self-knowledge/documents.lance/_versions/7.manifest +0 -0
  44. package/.ctxman/self-knowledge/documents.lance/_versions/8.manifest +0 -0
  45. package/.ctxman/self-knowledge/documents.lance/_versions/9.manifest +0 -0
  46. package/.ctxman/self-knowledge/documents.lance/data/000010010011011101000010de8621405d9d5cb06540dbf02c.lance +0 -0
  47. package/.ctxman/self-knowledge/documents.lance/data/0000101001011100011000003fb62a4aa8978974075c144f1c.lance +0 -0
  48. package/.ctxman/self-knowledge/documents.lance/data/000011010000100111001011c6cc824d628f3bb1f4e04cd5d0.lance +0 -0
  49. package/.ctxman/self-knowledge/documents.lance/data/001000001000011001011100d8f74349ada090b332cd1df669.lance +0 -0
  50. package/.ctxman/self-knowledge/documents.lance/data/01000001111010001000010045ab44467bb1e7e4d8ae06bd58.lance +0 -0
  51. package/.ctxman/self-knowledge/documents.lance/data/01000101101110111110011131ef904241a89e1ffb6ddaf8e3.lance +0 -0
  52. package/.ctxman/self-knowledge/documents.lance/data/010010110000010000011010fbfcc145c6a8a827b28057a07e.lance +0 -0
  53. package/.ctxman/self-knowledge/documents.lance/data/1000011000101010001110003fb4f045c3835982efa1405324.lance +0 -0
  54. package/.ctxman/self-knowledge/documents.lance/data/100111011101110111101011f4396b410fa06af3b028d204e6.lance +0 -0
  55. package/.ctxman/self-knowledge/documents.lance/data/100111100111101000001100596b174e00995d6cc2969cc8dc.lance +0 -0
  56. package/.ctxman/self-knowledge/documents.lance/data/1010001100011000110010102ea16b484d887c7c9725feffd6.lance +0 -0
  57. package/.ctxman/self-knowledge/documents.lance/data/101101100010101111110111c5230944d9b3af7301b6392dda.lance +0 -0
  58. package/.ctxman/self-knowledge/documents.lance/data/1011011100100111111110105892bf41b5a530fedd7cf516f1.lance +0 -0
  59. package/.ctxman/self-knowledge/documents.lance/data/10111110000010001011110164e8774742bade87b483c10f36.lance +0 -0
  60. package/.ctxman/self-knowledge/documents.lance/data/1100000100010110001110103ffaca40a2a42c85067ebaf9ae.lance +0 -0
  61. package/.ctxman/self-knowledge/documents.lance/data/110000010001110110101110664bde4c76a78dfc14b05e83b8.lance +0 -0
  62. package/.ctxman/self-knowledge/documents.lance/data/11001100111000010100110050645c4281b1f35b2022234f7f.lance +0 -0
  63. package/.ctxman/self-knowledge/documents.lance/data/1101111011001100110111017214924a368f5719eab2246619.lance +0 -0
  64. package/.ctxman/self-knowledge/documents.lance/data/1110000111001010001000002150c24dcab653d39d07032e63.lance +0 -0
  65. package/.ctxman/self-knowledge/documents.lance/data/1110100000000100000011014d20534967a18b5c87721659ff.lance +0 -0
  66. package/.ctxman/self-knowledge/documents.lance/data/11110101111010000101011135a0114ef2b35dc6f1297a3381.lance +0 -0
  67. package/.ctxman/wizard-profiles/code-review/.contextignore +41 -0
  68. package/.ctxman/wizard-profiles/code-review/.contextinclude +30 -0
  69. package/.ctxman/wizard-profiles/code-review/.methodignore +26 -0
  70. package/.ctxman/wizard-profiles/code-review/.methodinclude +47 -0
  71. package/.ctxman/wizard-profiles/code-review/profile.json +26 -0
  72. package/.ctxman/wizard-profiles/documentation/.contextignore +21 -0
  73. package/.ctxman/wizard-profiles/documentation/.contextinclude +24 -0
  74. package/.ctxman/wizard-profiles/documentation/.methodignore +19 -0
  75. package/.ctxman/wizard-profiles/documentation/.methodinclude +44 -0
  76. package/.ctxman/wizard-profiles/documentation/profile.json +27 -0
  77. package/.ctxman/wizard-profiles/full/.contextignore +23 -0
  78. package/.ctxman/wizard-profiles/full/.contextinclude +38 -0
  79. package/.ctxman/wizard-profiles/full/.methodignore +5 -0
  80. package/.ctxman/wizard-profiles/full/.methodinclude +5 -0
  81. package/.ctxman/wizard-profiles/full/profile.json +28 -0
  82. package/.ctxman/wizard-profiles/llm-explain/.contextignore +25 -0
  83. package/.ctxman/wizard-profiles/llm-explain/.contextinclude +33 -0
  84. package/.ctxman/wizard-profiles/llm-explain/.methodignore +19 -0
  85. package/.ctxman/wizard-profiles/llm-explain/.methodinclude +48 -0
  86. package/.ctxman/wizard-profiles/llm-explain/profile.json +27 -0
  87. package/.ctxman/wizard-profiles/minimal/.contextignore +27 -0
  88. package/.ctxman/wizard-profiles/minimal/.contextinclude +14 -0
  89. package/.ctxman/wizard-profiles/minimal/.methodignore +22 -0
  90. package/.ctxman/wizard-profiles/minimal/.methodinclude +18 -0
  91. package/.ctxman/wizard-profiles/minimal/profile.json +26 -0
  92. package/.ctxman/wizard-profiles/security-audit/.contextignore +36 -0
  93. package/.ctxman/wizard-profiles/security-audit/.contextinclude +37 -0
  94. package/.ctxman/wizard-profiles/security-audit/.methodignore +29 -0
  95. package/.ctxman/wizard-profiles/security-audit/.methodinclude +60 -0
  96. package/.ctxman/wizard-profiles/security-audit/profile.json +34 -0
  97. package/README.md +1167 -0
  98. package/bin/cli.js +650 -0
  99. package/bin/cm-ask.js +95 -0
  100. package/bin/cm-gitingest.js +134 -0
  101. package/bin/cm-update.js +175 -0
  102. package/bin/mcp-server.js +31 -0
  103. package/ctxman.js +236 -0
  104. package/examples/README.md +298 -0
  105. package/examples/custom-llm-profiles.example.json +19 -0
  106. package/examples/wizard-profiles/code-review/.contextignore +41 -0
  107. package/examples/wizard-profiles/code-review/.contextinclude +30 -0
  108. package/examples/wizard-profiles/code-review/.methodignore +26 -0
  109. package/examples/wizard-profiles/code-review/.methodinclude +47 -0
  110. package/examples/wizard-profiles/code-review/profile.json +26 -0
  111. package/examples/wizard-profiles/documentation/.contextignore +21 -0
  112. package/examples/wizard-profiles/documentation/.contextinclude +24 -0
  113. package/examples/wizard-profiles/documentation/.methodignore +19 -0
  114. package/examples/wizard-profiles/documentation/.methodinclude +44 -0
  115. package/examples/wizard-profiles/documentation/profile.json +27 -0
  116. package/examples/wizard-profiles/full/.contextignore +23 -0
  117. package/examples/wizard-profiles/full/.contextinclude +38 -0
  118. package/examples/wizard-profiles/full/.methodignore +5 -0
  119. package/examples/wizard-profiles/full/.methodinclude +5 -0
  120. package/examples/wizard-profiles/full/profile.json +28 -0
  121. package/examples/wizard-profiles/llm-explain/.contextignore +25 -0
  122. package/examples/wizard-profiles/llm-explain/.contextinclude +33 -0
  123. package/examples/wizard-profiles/llm-explain/.methodignore +19 -0
  124. package/examples/wizard-profiles/llm-explain/.methodinclude +48 -0
  125. package/examples/wizard-profiles/llm-explain/profile.json +27 -0
  126. package/examples/wizard-profiles/minimal/.contextignore +27 -0
  127. package/examples/wizard-profiles/minimal/.contextinclude +14 -0
  128. package/examples/wizard-profiles/minimal/.methodignore +22 -0
  129. package/examples/wizard-profiles/minimal/.methodinclude +18 -0
  130. package/examples/wizard-profiles/minimal/profile.json +26 -0
  131. package/examples/wizard-profiles/security-audit/.contextignore +36 -0
  132. package/examples/wizard-profiles/security-audit/.contextinclude +37 -0
  133. package/examples/wizard-profiles/security-audit/.methodignore +29 -0
  134. package/examples/wizard-profiles/security-audit/.methodinclude +60 -0
  135. package/examples/wizard-profiles/security-audit/profile.json +34 -0
  136. package/index.js +68 -0
  137. package/lib/agents/pr-failure-agent.js +201 -0
  138. package/lib/analyzers/go-method-analyzer.js +126 -0
  139. package/lib/analyzers/method-analyzer.js +457 -0
  140. package/lib/analyzers/token-calculator.js +577 -0
  141. package/lib/api/mcp/prompts.js +319 -0
  142. package/lib/api/mcp/resources.js +269 -0
  143. package/lib/api/mcp/server.js +339 -0
  144. package/lib/api/mcp/transports/HttpSseTransport.js +63 -0
  145. package/lib/api/rest/server.js +405 -0
  146. package/lib/cache/CacheManager.js +388 -0
  147. package/lib/core/Analyzer.js +180 -0
  148. package/lib/core/ContextBuilder.js +325 -0
  149. package/lib/core/Reporter.js +270 -0
  150. package/lib/core/Scanner.js +129 -0
  151. package/lib/formatters/format-registry.js +419 -0
  152. package/lib/formatters/gitingest-formatter.js +746 -0
  153. package/lib/formatters/toon-formatter-v1.3.js +731 -0
  154. package/lib/formatters/toon-formatter.js +291 -0
  155. package/lib/integrations/git/BlameTracker.js +142 -0
  156. package/lib/integrations/git/DiffAnalyzer.js +260 -0
  157. package/lib/integrations/git/GitClient.js +336 -0
  158. package/lib/parsers/gitignore-parser.js +127 -0
  159. package/lib/parsers/method-filter-parser.js +50 -0
  160. package/lib/plugins/ExporterPlugin.js +102 -0
  161. package/lib/plugins/LanguagePlugin.js +100 -0
  162. package/lib/plugins/PluginManager.js +302 -0
  163. package/lib/rag/DataSourcePlugin.js +31 -0
  164. package/lib/rag/EmbeddingProvider.js +75 -0
  165. package/lib/rag/Indexer.js +83 -0
  166. package/lib/rag/VectorStoreFactory.js +24 -0
  167. package/lib/rag/sources/FileDataSource.js +70 -0
  168. package/lib/rag/stores/BaseVectorStore.js +43 -0
  169. package/lib/rag/stores/ChromaDBStore.js +85 -0
  170. package/lib/rag/stores/LanceDBStore.js +109 -0
  171. package/lib/rag/stores/PineconeStore.js +74 -0
  172. package/lib/ui/dashboard.js +109 -0
  173. package/lib/ui/index.js +15 -0
  174. package/lib/ui/progress-bar.js +110 -0
  175. package/lib/ui/select-input.js +51 -0
  176. package/lib/ui/wizard.js +359 -0
  177. package/lib/utils/clipboard-utils.js +66 -0
  178. package/lib/utils/config-utils.js +94 -0
  179. package/lib/utils/error-handler.js +145 -0
  180. package/lib/utils/file-utils.js +89 -0
  181. package/lib/utils/format-converter.js +325 -0
  182. package/lib/utils/git-utils.js +337 -0
  183. package/lib/utils/llm-detector.js +409 -0
  184. package/lib/utils/logger.js +278 -0
  185. package/lib/utils/token-utils.js +200 -0
  186. package/lib/utils/tokenizer-adapter.js +454 -0
  187. package/lib/utils/updater.js +565 -0
  188. package/lib/watch/FileWatcher.js +208 -0
  189. package/lib/watch/IncrementalAnalyzer.js +206 -0
  190. package/package.json +118 -0
@@ -0,0 +1,208 @@
1
+ /**
2
+ * FileWatcher - Real-Time File Watching Module
3
+ * v3.0.0 - Watch mode
4
+ *
5
+ * Responsibilities:
6
+ * - Watch file system for changes
7
+ * - Debounce rapid changes
8
+ * - Emit change events
9
+ * - Support ignore patterns
10
+ */
11
+
12
+ import fs from 'fs';
13
+ import path from 'path';
14
+ import { EventEmitter } from 'events';
15
+ import GitIgnoreParser from '../parsers/gitignore-parser.js';
16
+ import { getLogger } from '../utils/logger.js';
17
+
18
+ const logger = getLogger('FileWatcher');
19
+
20
+ export class FileWatcher extends EventEmitter {
21
+ constructor(rootPath, options = {}) {
22
+ super();
23
+
24
+ this.rootPath = rootPath;
25
+ this.options = {
26
+ debounce: 1000, // 1 second debounce
27
+ recursive: true,
28
+ ignorePatterns: [],
29
+ ...options
30
+ };
31
+
32
+ // Initialize GitIgnoreParser with correct file paths
33
+ const gitignorePath = path.join(rootPath, '.gitignore');
34
+ const contextIgnorePath = path.join(rootPath, '.contextignore');
35
+ const contextIncludePath = path.join(rootPath, '.contextinclude');
36
+
37
+ this.gitIgnore = new GitIgnoreParser(gitignorePath, contextIgnorePath, contextIncludePath);
38
+ this.watchers = [];
39
+ this.debounceTimers = new Map();
40
+ this.isWatching = false;
41
+
42
+ this.stats = {
43
+ totalChanges: 0,
44
+ ignoredChanges: 0,
45
+ errors: 0
46
+ };
47
+ }
48
+
49
+ /**
50
+ * Start watching
51
+ */
52
+ start() {
53
+ if (this.isWatching) {
54
+ logger.warn('Already watching');
55
+ return;
56
+ }
57
+
58
+ logger.info(`Starting file watch: ${this.rootPath}`);
59
+
60
+ try {
61
+ const watcher = fs.watch(
62
+ this.rootPath,
63
+ { recursive: this.options.recursive },
64
+ (eventType, filename) => {
65
+ this.handleFileChange(eventType, filename);
66
+ }
67
+ );
68
+
69
+ this.watchers.push(watcher);
70
+ this.isWatching = true;
71
+
72
+ this.emit('watch:started', { path: this.rootPath });
73
+ logger.info('Watch mode started');
74
+
75
+ } catch (error) {
76
+ logger.error(`Failed to start watch: ${error.message}`);
77
+ this.emit('watch:error', { error });
78
+ throw error;
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Stop watching
84
+ */
85
+ stop() {
86
+ if (!this.isWatching) {
87
+ return;
88
+ }
89
+
90
+ logger.info('Stopping file watch...');
91
+
92
+ // Close all watchers
93
+ for (const watcher of this.watchers) {
94
+ watcher.close();
95
+ }
96
+
97
+ // Clear debounce timers
98
+ for (const timer of this.debounceTimers.values()) {
99
+ clearTimeout(timer);
100
+ }
101
+
102
+ this.watchers = [];
103
+ this.debounceTimers.clear();
104
+ this.isWatching = false;
105
+
106
+ this.emit('watch:stopped');
107
+ logger.info('Watch mode stopped');
108
+ }
109
+
110
+ /**
111
+ * Handle file change event
112
+ * @param {string} eventType - 'rename' or 'change'
113
+ * @param {string} filename - Changed file name
114
+ */
115
+ handleFileChange(eventType, filename) {
116
+ if (!filename) return;
117
+
118
+ const filePath = path.join(this.rootPath, filename);
119
+ const relativePath = path.relative(this.rootPath, filePath);
120
+
121
+ // Check ignore patterns
122
+ if (this.shouldIgnore(relativePath)) {
123
+ this.stats.ignoredChanges++;
124
+ return;
125
+ }
126
+
127
+ this.stats.totalChanges++;
128
+
129
+ // Debounce rapid changes
130
+ if (this.debounceTimers.has(filePath)) {
131
+ clearTimeout(this.debounceTimers.get(filePath));
132
+ }
133
+
134
+ const timer = setTimeout(() => {
135
+ this.debounceTimers.delete(filePath);
136
+ this.emitFileChange(eventType, filePath, relativePath);
137
+ }, this.options.debounce);
138
+
139
+ this.debounceTimers.set(filePath, timer);
140
+ }
141
+
142
+ /**
143
+ * Emit file change event
144
+ * @param {string} eventType
145
+ * @param {string} filePath
146
+ * @param {string} relativePath
147
+ */
148
+ emitFileChange(eventType, filePath, relativePath) {
149
+ logger.debug(`File ${eventType}: ${relativePath}`);
150
+
151
+ const event = {
152
+ type: eventType,
153
+ path: filePath,
154
+ relativePath: relativePath,
155
+ timestamp: Date.now(),
156
+ exists: fs.existsSync(filePath)
157
+ };
158
+
159
+ // Add file stats if exists
160
+ if (event.exists) {
161
+ try {
162
+ const stats = fs.statSync(filePath);
163
+ event.size = stats.size;
164
+ event.modified = stats.mtime;
165
+ } catch (error) {
166
+ // Stats not available
167
+ }
168
+ }
169
+
170
+ this.emit('file:changed', event);
171
+ }
172
+
173
+ /**
174
+ * Check if file should be ignored
175
+ * @param {string} relativePath
176
+ * @returns {boolean}
177
+ */
178
+ shouldIgnore(relativePath) {
179
+ // Use GitIgnoreParser for ignore rules
180
+ return !this.gitIgnore.shouldIncludeFile(relativePath);
181
+ }
182
+
183
+ /**
184
+ * Get watch statistics
185
+ * @returns {object}
186
+ */
187
+ getStats() {
188
+ return {
189
+ ...this.stats,
190
+ isWatching: this.isWatching,
191
+ activeWatchers: this.watchers.length,
192
+ pendingDebounce: this.debounceTimers.size
193
+ };
194
+ }
195
+
196
+ /**
197
+ * Reset statistics
198
+ */
199
+ resetStats() {
200
+ this.stats = {
201
+ totalChanges: 0,
202
+ ignoredChanges: 0,
203
+ errors: 0
204
+ };
205
+ }
206
+ }
207
+
208
+ export default FileWatcher;
@@ -0,0 +1,206 @@
1
+ /**
2
+ * IncrementalAnalyzer - Incremental Analysis Module
3
+ * v3.0.0 - Watch mode
4
+ *
5
+ * Responsibilities:
6
+ * - Perform incremental analysis on file changes
7
+ * - Update aggregate statistics
8
+ * - Emit analysis events
9
+ * - Optimize for performance
10
+ */
11
+
12
+ import { EventEmitter } from 'events';
13
+ import { Analyzer } from '../core/Analyzer.js';
14
+ import { getLogger } from '../utils/logger.js';
15
+
16
+ const logger = getLogger('IncrementalAnalyzer');
17
+
18
+ export class IncrementalAnalyzer extends EventEmitter {
19
+ constructor(options = {}) {
20
+ super();
21
+
22
+ this.options = {
23
+ autoAnalyze: true,
24
+ ...options
25
+ };
26
+
27
+ this.analyzer = new Analyzer(options);
28
+ this.fileCache = new Map(); // Cache of file analyses
29
+ this.aggregateStats = null;
30
+ }
31
+
32
+ /**
33
+ * Analyze changed file and update stats
34
+ * @param {FileChangeEvent} changeEvent
35
+ */
36
+ async analyzeChange(changeEvent) {
37
+ logger.debug(`Analyzing change: ${changeEvent.relativePath}`);
38
+
39
+ const startTime = Date.now();
40
+
41
+ try {
42
+ // If file deleted, remove from cache
43
+ if (!changeEvent.exists) {
44
+ this.handleFileDeleted(changeEvent);
45
+ return;
46
+ }
47
+
48
+ // Analyze file
49
+ const fileInfo = {
50
+ path: changeEvent.path,
51
+ relativePath: changeEvent.relativePath,
52
+ name: path.basename(changeEvent.path),
53
+ extension: path.extname(changeEvent.path),
54
+ size: changeEvent.size,
55
+ modified: changeEvent.modified
56
+ };
57
+
58
+ const analysis = await this.analyzer.analyzeFile(fileInfo);
59
+
60
+ if (analysis) {
61
+ // Update cache
62
+ const oldAnalysis = this.fileCache.get(changeEvent.path);
63
+ this.fileCache.set(changeEvent.path, analysis);
64
+
65
+ // Update aggregate stats
66
+ this.updateAggregateStats(oldAnalysis, analysis);
67
+
68
+ const elapsed = Date.now() - startTime;
69
+
70
+ this.emit('analysis:complete', {
71
+ file: changeEvent.relativePath,
72
+ analysis,
73
+ elapsed,
74
+ cached: false
75
+ });
76
+
77
+ logger.debug(`Analysis complete: ${changeEvent.relativePath} (${elapsed}ms)`);
78
+ }
79
+
80
+ } catch (error) {
81
+ logger.error(`Analysis failed for ${changeEvent.relativePath}: ${error.message}`);
82
+ this.emit('analysis:error', {
83
+ file: changeEvent.relativePath,
84
+ error
85
+ });
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Handle file deletion
91
+ * @param {FileChangeEvent} changeEvent
92
+ */
93
+ handleFileDeleted(changeEvent) {
94
+ const oldAnalysis = this.fileCache.get(changeEvent.path);
95
+
96
+ if (oldAnalysis) {
97
+ // Remove from cache
98
+ this.fileCache.delete(changeEvent.path);
99
+
100
+ // Update stats (subtract)
101
+ if (this.aggregateStats) {
102
+ this.aggregateStats.totalFiles--;
103
+ this.aggregateStats.totalTokens -= oldAnalysis.tokens;
104
+ this.aggregateStats.totalSize -= oldAnalysis.size;
105
+
106
+ // Update language stats
107
+ const lang = oldAnalysis.language;
108
+ if (this.aggregateStats.byLanguage[lang]) {
109
+ this.aggregateStats.byLanguage[lang].files--;
110
+ this.aggregateStats.byLanguage[lang].tokens -= oldAnalysis.tokens;
111
+ this.aggregateStats.byLanguage[lang].size -= oldAnalysis.size;
112
+ }
113
+ }
114
+
115
+ this.emit('file:deleted', {
116
+ file: changeEvent.relativePath,
117
+ oldTokens: oldAnalysis.tokens
118
+ });
119
+
120
+ logger.debug(`File deleted from cache: ${changeEvent.relativePath}`);
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Update aggregate statistics
126
+ * @param {FileAnalysis|null} oldAnalysis
127
+ * @param {FileAnalysis} newAnalysis
128
+ */
129
+ updateAggregateStats(oldAnalysis, newAnalysis) {
130
+ if (!this.aggregateStats) {
131
+ this.aggregateStats = this.analyzer.getStats();
132
+ }
133
+
134
+ // Subtract old values if exists
135
+ if (oldAnalysis) {
136
+ this.aggregateStats.totalTokens -= oldAnalysis.tokens;
137
+ this.aggregateStats.totalSize -= oldAnalysis.size;
138
+
139
+ const oldLang = oldAnalysis.language;
140
+ if (this.aggregateStats.byLanguage[oldLang]) {
141
+ this.aggregateStats.byLanguage[oldLang].tokens -= oldAnalysis.tokens;
142
+ this.aggregateStats.byLanguage[oldLang].size -= oldAnalysis.size;
143
+ }
144
+ } else {
145
+ // New file
146
+ this.aggregateStats.totalFiles++;
147
+ }
148
+
149
+ // Add new values
150
+ this.aggregateStats.totalTokens += newAnalysis.tokens;
151
+ this.aggregateStats.totalSize += newAnalysis.size;
152
+
153
+ const lang = newAnalysis.language;
154
+ if (!this.aggregateStats.byLanguage[lang]) {
155
+ this.aggregateStats.byLanguage[lang] = { files: 0, tokens: 0, size: 0 };
156
+ }
157
+
158
+ if (!oldAnalysis) {
159
+ this.aggregateStats.byLanguage[lang].files++;
160
+ }
161
+
162
+ this.aggregateStats.byLanguage[lang].tokens += newAnalysis.tokens;
163
+ this.aggregateStats.byLanguage[lang].size += newAnalysis.size;
164
+
165
+ // Emit stats update
166
+ this.emit('stats:updated', this.aggregateStats);
167
+ }
168
+
169
+ /**
170
+ * Get current aggregate statistics
171
+ * @returns {object}
172
+ */
173
+ getStats() {
174
+ return this.aggregateStats || this.analyzer.getStats();
175
+ }
176
+
177
+ /**
178
+ * Get cached file analysis
179
+ * @param {string} filePath
180
+ * @returns {FileAnalysis|null}
181
+ */
182
+ getCachedAnalysis(filePath) {
183
+ return this.fileCache.get(filePath) || null;
184
+ }
185
+
186
+ /**
187
+ * Clear cache
188
+ */
189
+ clearCache() {
190
+ this.fileCache.clear();
191
+ logger.info('Analysis cache cleared');
192
+ }
193
+
194
+ /**
195
+ * Get cache statistics
196
+ * @returns {object}
197
+ */
198
+ getCacheStats() {
199
+ return {
200
+ cachedFiles: this.fileCache.size,
201
+ cacheSize: this.fileCache.size * 1024 // Rough estimate
202
+ };
203
+ }
204
+ }
205
+
206
+ export default IncrementalAnalyzer;
package/package.json ADDED
@@ -0,0 +1,118 @@
1
+ {
2
+ "name": "ctxman",
3
+ "version": "3.0.0",
4
+ "description": "AI Development Platform with plugin architecture, Git integration, REST API, watch mode, LLM optimization, and support for 14+ languages. Features include TOON format (40-50% token reduction), real-time analysis, and comprehensive context generation.",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "bin": {
8
+ "ctxman": "bin/cli.js"
9
+ },
10
+ "exports": {
11
+ ".": "./index.js"
12
+ },
13
+ "scripts": {
14
+ "test": "vitest run",
15
+ "test:watch": "vitest",
16
+ "test:coverage": "vitest run --coverage",
17
+ "lint": "eslint .",
18
+ "lint:fix": "eslint . --fix",
19
+ "format": "prettier --write .",
20
+ "analyze": "node bin/cli.js",
21
+ "analyze:cli": "node bin/cli.js --cli",
22
+ "analyze:methods": "node bin/cli.js --cli --method-level",
23
+ "analyze:gitingest": "node bin/cli.js --cli --gitingest",
24
+ "serve": "node bin/cli.js serve",
25
+ "watch": "node bin/cli.js watch",
26
+ "github": "node bin/cm-gitingest.js",
27
+ "install:local": "bash scripts/install.sh",
28
+ "uninstall:local": "bash scripts/uninstall.sh",
29
+ "install:windows": "powershell -ExecutionPolicy Bypass -File scripts/install.ps1",
30
+ "uninstall:windows": "powershell -ExecutionPolicy Bypass -File scripts/uninstall.ps1",
31
+ "update:check": "node bin/cm-update.js check",
32
+ "update:install": "node bin/cm-update.js install",
33
+ "update:rollback": "node bin/cm-update.js rollback",
34
+ "update:channel": "node bin/cm-update.js channel",
35
+ "build": "echo 'No build step required'",
36
+ "build:deb": "make build-deb",
37
+ "prepublishOnly": "npm test",
38
+ "mcp": "node bin/mcp-server.js",
39
+ "postinstall": "node -e \"console.log('\\n✅ Ctxman installed! Run: ctxman --help\\n')\""
40
+ },
41
+ "keywords": [
42
+ "code",
43
+ "analysis",
44
+ "llm",
45
+ "context",
46
+ "plugin-system",
47
+ "git-integration",
48
+ "api-server",
49
+ "watch-mode",
50
+ "method-level",
51
+ "javascript",
52
+ "typescript",
53
+ "rust",
54
+ "csharp",
55
+ "go",
56
+ "java",
57
+ "python",
58
+ "php",
59
+ "ruby",
60
+ "kotlin",
61
+ "swift",
62
+ "cpp",
63
+ "scala",
64
+ "multi-language",
65
+ "ast",
66
+ "tiktoken",
67
+ "optimizer",
68
+ "gitingest",
69
+ "real-time",
70
+ "caching",
71
+ "platform"
72
+ ],
73
+ "author": "Hakkı Sağdıç",
74
+ "license": "MIT",
75
+ "engines": {
76
+ "node": ">=20.0.0"
77
+ },
78
+ "dependencies": {
79
+ "@lancedb/lancedb": "^0.23.0",
80
+ "@modelcontextprotocol/sdk": "^1.21.1",
81
+ "@toon-format/toon": "^0.7.0",
82
+ "@xenova/transformers": "^2.17.2",
83
+ "cors": "^2.8.5",
84
+ "express": "^5.1.0",
85
+ "ink": "^6.4.0",
86
+ "ink-spinner": "^5.0.0",
87
+ "ink-text-input": "^6.0.0",
88
+ "react": "^19.2.0",
89
+ "vitest": "^4.0.18",
90
+ "zod": "^4.1.12"
91
+ },
92
+ "files": [
93
+ "index.js",
94
+ "ctxman.js",
95
+ "lib/",
96
+ "bin/",
97
+ ".ctxman/",
98
+ "examples/",
99
+ "README.md",
100
+ "LICENSE"
101
+ ],
102
+ "devDependencies": {
103
+ "@anthropic-ai/tokenizer": "^0.0.4",
104
+ "@playwright/test": "^1.58.1",
105
+ "@vitejs/plugin-vue": "^6.0.2",
106
+ "@vitest/coverage-v8": "^4.0.18",
107
+ "@vitest/ui": "^4.0.18",
108
+ "@vue/test-utils": "^2.4.6",
109
+ "c8": "^10.1.3",
110
+ "eslint": "^9.39.1",
111
+ "llama3-tokenizer-js": "^1.2.0",
112
+ "prettier": "^3.6.2",
113
+ "supertest": "^7.2.2",
114
+ "tiktoken": "^1.0.22",
115
+ "vite": "^7.2.4",
116
+ "vue": "^3.5.24"
117
+ }
118
+ }