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
package/bin/cm-ask.js ADDED
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env node
2
+ import { VectorStoreFactory } from '../lib/rag/VectorStoreFactory.js';
3
+ import { EmbeddingProvider, TransformersEmbeddingProvider } from '../lib/rag/EmbeddingProvider.js';
4
+ import { Indexer } from '../lib/rag/Indexer.js';
5
+ import { FileDataSource } from '../lib/rag/sources/FileDataSource.js';
6
+ import path from 'path';
7
+ import fs from 'fs/promises';
8
+ import { TokenizerManager } from '../lib/utils/tokenizer-adapter.js';
9
+
10
+ async function main() {
11
+ const args = process.argv.slice(2);
12
+ const query = args.join(' ');
13
+
14
+ if (!query) {
15
+ console.error('Usage: ctxman ask "Your query here"');
16
+ process.exit(1);
17
+ }
18
+
19
+ // 1. Initialize RAG Components
20
+ let provider;
21
+ try {
22
+ // Try to load local transformers
23
+ provider = new TransformersEmbeddingProvider();
24
+ // Lazy init will handle model download on first use
25
+ } catch (e) {
26
+ console.error('⚠️ Failed to initialize embedding provider:', e.message);
27
+ process.exit(1);
28
+ }
29
+
30
+ // Use LanceDB in .ctxman/self-knowledge
31
+ const storePath = path.join(process.cwd(), '.ctxman', 'self-knowledge');
32
+ const store = VectorStoreFactory.create('lancedb', provider, { path: storePath });
33
+
34
+ // 2. Check if indexed
35
+ const isIndexed = await checkIndexExists(storePath);
36
+
37
+ if (!isIndexed) {
38
+ console.log('📚 Index not found. Auto-indexing current project...');
39
+ await indexProject(store);
40
+ }
41
+
42
+ // 3. Search
43
+ console.log(`🔍 Searching for: "${query}"...`);
44
+ const results = await store.search(query, 5); // Get top 5
45
+
46
+ if (results.length === 0) {
47
+ console.log('❌ No relevant context found.');
48
+ return;
49
+ }
50
+
51
+ // 4. Display Results (or feed to LLM if we had one configured)
52
+ console.log(`\nFound ${results.length} relevant snippets:\n`);
53
+
54
+ results.forEach((r, i) => {
55
+ console.log(`[${i+1}] ${r.metadata.filename} (Score: ${r.score?.toFixed(4)})`);
56
+ console.log('─'.repeat(40));
57
+ // Show a small snippet around the match if possible, but we stored full text.
58
+ // Let's just show the first 200 chars or so.
59
+ console.log(r.text.substring(0, 300).replace(/\n/g, ' ') + '...');
60
+ console.log('\n');
61
+ });
62
+
63
+ // Future: Pass `results` to an LLM API to generate a real answer.
64
+ // For now, this validates the retrieval pipeline works from CLI.
65
+ }
66
+
67
+ async function checkIndexExists(storePath) {
68
+ try {
69
+ await fs.access(storePath);
70
+ // Also check if it has tables (LanceDB creates folders)
71
+ const files = await fs.readdir(storePath);
72
+ return files.length > 0;
73
+ } catch {
74
+ return false;
75
+ }
76
+ }
77
+
78
+ async function indexProject(store) {
79
+ const indexer = new Indexer(store);
80
+ const fileSource = new FileDataSource();
81
+ indexer.registerSource(fileSource);
82
+
83
+ console.log('⏳ Indexing files (this may take a moment)...');
84
+ await indexer.index('local-files', {
85
+ targetDir: process.cwd(),
86
+ include: ['.js', '.md', '.ts', '.json'], // Configurable?
87
+ exclude: ['node_modules', '.git', 'dist', 'coverage', '.ctxman']
88
+ });
89
+ console.log('✅ Indexing complete.');
90
+ }
91
+
92
+ main().catch(err => {
93
+ console.error('❌ Error:', err);
94
+ process.exit(1);
95
+ });
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * GitHub GitIngest Command
4
+ * Generate GitIngest digest from GitHub repositories
5
+ */
6
+
7
+ const GitUtils = require('../lib/utils/git-utils');
8
+ const { getLogger } = require('../lib/utils/logger');
9
+
10
+ const logger = getLogger({ level: 'info' });
11
+
12
+ async function main() {
13
+ const args = process.argv.slice(2);
14
+
15
+ if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
16
+ printHelp();
17
+ return;
18
+ }
19
+
20
+ const url = args[0];
21
+ const verbose = args.includes('--verbose') || args.includes('-v');
22
+ const keepClone = args.includes('--keep-clone');
23
+ const shallow = !args.includes('--full-clone');
24
+
25
+ // Parse options
26
+ const outputIndex = args.findIndex(arg => arg === '--output' || arg === '-o');
27
+ const outputFile = outputIndex !== -1 ? args[outputIndex + 1] : null;
28
+
29
+ const branchIndex = args.findIndex(arg => arg === '--branch' || arg === '-b');
30
+ const branch = branchIndex !== -1 ? args[branchIndex + 1] : 'main';
31
+
32
+ const chunkSize = args.includes('--chunk-size')
33
+ ? parseInt(args[args.findIndex(arg => arg === '--chunk-size') + 1])
34
+ : null;
35
+
36
+ try {
37
+ console.log('╔════════════════════════════════════════════════════════╗');
38
+ console.log('║ GitHub GitIngest Generator v2.3.6 ║');
39
+ console.log('╚════════════════════════════════════════════════════════╝\n');
40
+
41
+ const gitUtils = new GitUtils({
42
+ verbose,
43
+ outputDir: 'docs'
44
+ });
45
+
46
+ // Get repository info first
47
+ console.log('📋 Fetching repository information...');
48
+ const repoInfo = gitUtils.parseGitHubURL(url);
49
+ repoInfo.branch = branch; // Override branch if specified
50
+
51
+ const repoData = await gitUtils.getRepositoryInfo(repoInfo);
52
+ console.log(`\n📊 Repository Info:`);
53
+ console.log(` Name: ${repoData.fullName}`);
54
+ console.log(` Description: ${repoData.description || 'N/A'}`);
55
+ console.log(` Stars: ⭐ ${repoData.stars.toLocaleString()}`);
56
+ console.log(` Language: ${repoData.language || 'Multiple'}`);
57
+ console.log(` Default Branch: ${repoData.defaultBranch}`);
58
+
59
+ // Generate GitIngest
60
+ const options = {
61
+ outputFile,
62
+ cleanup: !keepClone,
63
+ shallow,
64
+ formatterOptions: chunkSize ? {
65
+ chunking: {
66
+ enabled: true,
67
+ maxTokensPerChunk: chunkSize
68
+ }
69
+ } : {}
70
+ };
71
+
72
+ const stats = await gitUtils.generateFromGitHub(url, options);
73
+
74
+ // Log to file
75
+ logger.info('GitHub GitIngest generated', {
76
+ repository: stats.repository,
77
+ outputFile: stats.outputFile,
78
+ files: stats.files,
79
+ tokens: stats.tokens
80
+ });
81
+
82
+ console.log('\n✅ Complete!\n');
83
+
84
+ // Show next steps
85
+ console.log('📝 Next steps:');
86
+ console.log(` 1. View digest: cat "${stats.outputFile}"`);
87
+ console.log(` 2. Use in LLM: Copy to clipboard`);
88
+ console.log(` 3. Cleanup: npm run clean\n`);
89
+
90
+ } catch (error) {
91
+ console.error('\n❌ Error:', error.message);
92
+ logger.error('GitHub GitIngest failed', { error: error.message });
93
+ process.exit(1);
94
+ }
95
+ }
96
+
97
+ function printHelp() {
98
+ console.log('GitHub GitIngest Generator - Generate digest from GitHub repositories\n');
99
+ console.log('Usage: ctxman github <url> [options]\n');
100
+ console.log('Arguments:');
101
+ console.log(' url GitHub repository URL or owner/repo\n');
102
+ console.log('Options:');
103
+ console.log(' -o, --output FILE Output file path (default: docs/{repo}-gitingest-{hash}.txt)');
104
+ console.log(' -b, --branch BRANCH Branch to clone (default: main)');
105
+ console.log(' -v, --verbose Verbose output');
106
+ console.log(' --keep-clone Keep cloned repository (don\'t cleanup)');
107
+ console.log(' --full-clone Full clone (default: shallow)');
108
+ console.log(' --chunk-size TOKENS Enable chunking with max tokens per chunk');
109
+ console.log(' -h, --help Show this help\n');
110
+ console.log('URL Formats:');
111
+ console.log(' https://github.com/owner/repo');
112
+ console.log(' https://github.com/owner/repo.git');
113
+ console.log(' git@github.com:owner/repo.git');
114
+ console.log(' github.com/owner/repo');
115
+ console.log(' owner/repo\n');
116
+ console.log('Examples:');
117
+ console.log(' # Basic usage');
118
+ console.log(' ctxman github https://github.com/facebook/react\n');
119
+ console.log(' # Short format');
120
+ console.log(' ctxman github facebook/react\n');
121
+ console.log(' # Specific branch');
122
+ console.log(' ctxman github vercel/next.js --branch canary\n');
123
+ console.log(' # Custom output location');
124
+ console.log(' ctxman github angular/angular -o docs/angular-digest.txt\n');
125
+ console.log(' # With chunking');
126
+ console.log(' ctxman github microsoft/vscode --chunk-size 100000\n');
127
+ console.log(' # Keep clone for inspection');
128
+ console.log(' ctxman github nodejs/node --keep-clone --verbose\n');
129
+ console.log('Output:');
130
+ console.log(' Generated digest file in docs/ directory');
131
+ console.log(' Automatic cleanup of temporary clone (unless --keep-clone)\n');
132
+ }
133
+
134
+ main();
@@ -0,0 +1,175 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Ctxman - Update Command
4
+ * Handles version updates and channel switching
5
+ */
6
+
7
+ const Updater = require('../lib/utils/updater');
8
+ const { getLogger } = require('../lib/utils/logger');
9
+
10
+ const logger = getLogger({ level: 'info' });
11
+
12
+ async function main() {
13
+ const args = process.argv.slice(2);
14
+
15
+ // Parse command
16
+ const command = args[0];
17
+
18
+ const updater = new Updater();
19
+
20
+ switch (command) {
21
+ case 'check':
22
+ await checkForUpdates(updater);
23
+ break;
24
+
25
+ case 'install':
26
+ await installUpdate(updater);
27
+ break;
28
+
29
+ case 'rollback':
30
+ await rollbackVersion(updater);
31
+ break;
32
+
33
+ case 'channel':
34
+ await switchChannel(updater, args[1]);
35
+ break;
36
+
37
+ case 'info':
38
+ showUpdateInfo(updater);
39
+ break;
40
+
41
+ default:
42
+ // Default: check and optionally install
43
+ await checkAndUpdate(updater);
44
+ break;
45
+ }
46
+ }
47
+
48
+ async function checkForUpdates(updater) {
49
+ console.log('🔍 Checking for updates...\n');
50
+
51
+ const updateInfo = await updater.checkForUpdates();
52
+
53
+ if (updateInfo.error) {
54
+ logger.error('Failed to check for updates', { error: updateInfo.error });
55
+ console.log(`\n❌ ${updateInfo.message}`);
56
+ return;
57
+ }
58
+
59
+ if (updateInfo.available) {
60
+ console.log('✨ Update available!\n');
61
+ console.log(` Current: ${updateInfo.currentVersion}`);
62
+ console.log(` Latest: ${updateInfo.latestVersion}`);
63
+ console.log(` Channel: ${updateInfo.channel}\n`);
64
+
65
+ if (updateInfo.releaseNotes) {
66
+ console.log('📝 Release Notes:');
67
+ console.log(' ' + updateInfo.releaseNotes.split('\n').join('\n '));
68
+ console.log('');
69
+ }
70
+
71
+ console.log('To install: ctxman update install\n');
72
+ } else {
73
+ console.log('✓ You are using the latest version\n');
74
+ console.log(` Version: ${updateInfo.currentVersion}`);
75
+ console.log(` Channel: ${updater.channel}\n`);
76
+ }
77
+ }
78
+
79
+ async function installUpdate(updater) {
80
+ console.log('📦 Installing update...\n');
81
+
82
+ const updateInfo = await updater.checkForUpdates();
83
+
84
+ if (!updateInfo.available) {
85
+ console.log('✓ Already using the latest version\n');
86
+ return;
87
+ }
88
+
89
+ const result = await updater.installUpdate(updateInfo);
90
+
91
+ if (result.success) {
92
+ console.log('\n✅ Update installed successfully!\n');
93
+ logger.info('Update installed', {
94
+ from: updateInfo.currentVersion,
95
+ to: updateInfo.latestVersion
96
+ });
97
+ } else if (result.manualUpdateRequired) {
98
+ logger.warn('Manual update required');
99
+ } else {
100
+ console.log('\n❌ Update failed\n');
101
+ logger.error('Update failed', { error: result.error });
102
+ }
103
+ }
104
+
105
+ async function switchChannel(updater, newChannel) {
106
+ if (!newChannel) {
107
+ console.log('❌ Please specify a channel: stable or insider\n');
108
+ console.log('Usage: ctxman update channel <stable|insider>\n');
109
+ return;
110
+ }
111
+
112
+ try {
113
+ console.log(`🔄 Switching to ${newChannel} channel...\n`);
114
+
115
+ const updateInfo = await updater.switchChannel(newChannel);
116
+
117
+ logger.info('Channel switched', { channel: newChannel });
118
+
119
+ if (updateInfo.available) {
120
+ console.log(`\n✨ Update available on ${newChannel} channel!\n`);
121
+ console.log(` Latest: ${updateInfo.latestVersion}\n`);
122
+ console.log('To install: ctxman update install\n');
123
+ }
124
+ } catch (error) {
125
+ console.log(`\n❌ ${error.message}\n`);
126
+ logger.error('Failed to switch channel', { error: error.message });
127
+ }
128
+ }
129
+
130
+ async function rollbackVersion(updater) {
131
+ console.log('🔄 Rolling back to previous version...\n');
132
+
133
+ const result = await updater.rollback();
134
+
135
+ if (result.success) {
136
+ console.log(`\n✅ Successfully rolled back to v${result.restoredVersion}\n`);
137
+ logger.info('Version rolled back', {
138
+ restoredVersion: result.restoredVersion
139
+ });
140
+ } else {
141
+ console.log(`\n❌ Rollback failed: ${result.error}\n`);
142
+ logger.error('Rollback failed', { error: result.error });
143
+ }
144
+ }
145
+
146
+ function showUpdateInfo(updater) {
147
+ console.log('ℹ️ Update Configuration\n');
148
+ console.log(` Current version: ${updater.currentVersion}`);
149
+ console.log(` Update channel: ${updater.channel}`);
150
+ console.log(` Auto-update: ${updater.autoUpdate ? 'Enabled' : 'Disabled'}\n`);
151
+
152
+ console.log('Available commands:\n');
153
+ console.log(' ctxman update check - Check for updates');
154
+ console.log(' ctxman update install - Install latest update');
155
+ console.log(' ctxman update rollback - Rollback to previous version');
156
+ console.log(' ctxman update channel - Switch update channel');
157
+ console.log(' ctxman update info - Show this information\n');
158
+
159
+ console.log('Channels:\n');
160
+ console.log(' stable - Stable releases (recommended)');
161
+ console.log(' insider - Pre-release builds (bleeding edge)\n');
162
+ }
163
+
164
+ async function checkAndUpdate(updater) {
165
+ const updateInfo = await updater.checkAndNotify();
166
+
167
+ if (updateInfo && updateInfo.available) {
168
+ console.log('Run "ctxman update install" to update\n');
169
+ }
170
+ }
171
+
172
+ main().catch(error => {
173
+ console.error('Update command failed:', error.message);
174
+ process.exit(1);
175
+ });
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+
3
+ import MCPServer from "../lib/api/mcp/server.js";
4
+ import { HttpSseTransport } from "../lib/api/mcp/transports/HttpSseTransport.js";
5
+
6
+ const args = process.argv.slice(2);
7
+ const transportType = args.includes("--transport=sse") ? "sse" : "stdio";
8
+ const port = args.find(arg => arg.startsWith("--port="))?.split("=")[1] || 3000;
9
+ const apiKey = args.find(arg => arg.startsWith("--api-key="))?.split("=")[1];
10
+
11
+ const server = new MCPServer();
12
+
13
+ async function main() {
14
+ try {
15
+ if (transportType === "sse") {
16
+ const transport = new HttpSseTransport({
17
+ port: parseInt(port),
18
+ auth: apiKey ? { apiKey } : undefined
19
+ });
20
+ await transport.start();
21
+ await server.start(transport.transport);
22
+ } else {
23
+ await server.start();
24
+ }
25
+ } catch (error) {
26
+ console.error("Fatal error running MCP server:", error);
27
+ process.exit(1);
28
+ }
29
+ }
30
+
31
+ main();
package/ctxman.js ADDED
@@ -0,0 +1,236 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Ctxman - Main Orchestrator
5
+ * LLM context optimization with method-level filtering and GitIngest support
6
+ */
7
+
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+ import TokenCalculator from './lib/analyzers/token-calculator.js';
11
+ import GitIngestFormatter from './lib/formatters/gitingest-formatter.js';
12
+ import TokenUtils from './lib/utils/token-utils.js';
13
+
14
+ /**
15
+ * Generate GitIngest digest from token-analysis-report.json
16
+ */
17
+ function generateDigestFromReport(reportPath) {
18
+ console.log('📄 Loading token analysis report...');
19
+
20
+ if (!fs.existsSync(reportPath)) {
21
+ console.error(`❌ Error: Report file not found: ${reportPath}`);
22
+ process.exit(1);
23
+ }
24
+
25
+ try {
26
+ const report = JSON.parse(fs.readFileSync(reportPath, 'utf8'));
27
+
28
+ if (!report.metadata || !report.summary || !report.files) {
29
+ console.error('❌ Error: Invalid report format. Missing required fields.');
30
+ process.exit(1);
31
+ }
32
+
33
+ const projectRoot = report.metadata.projectRoot || process.cwd();
34
+
35
+ console.log(`✅ Report loaded: ${report.files.length} files`);
36
+ console.log('📄 Generating GitIngest digest from report...\n');
37
+
38
+ const formatter = new GitIngestFormatter(
39
+ projectRoot,
40
+ report.summary,
41
+ report.files
42
+ );
43
+
44
+ const digestPath = path.join(process.cwd(), 'digest.txt');
45
+ const digestSize = formatter.saveToFile(digestPath);
46
+
47
+ console.log(`💾 GitIngest digest saved to: digest.txt`);
48
+ console.log(`📊 Digest size: ${(digestSize / 1024).toFixed(1)} KB`);
49
+ console.log(`✨ Generated from: ${path.basename(reportPath)}`);
50
+
51
+ } catch (error) {
52
+ console.error(`❌ Error processing report: ${error.message}`);
53
+ process.exit(1);
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Generate GitIngest digest from llm-context.json
59
+ */
60
+ function generateDigestFromContext(contextPath) {
61
+ console.log('📄 Loading LLM context file...');
62
+
63
+ if (!fs.existsSync(contextPath)) {
64
+ console.error(`❌ Error: Context file not found: ${contextPath}`);
65
+ process.exit(1);
66
+ }
67
+
68
+ try {
69
+ const context = JSON.parse(fs.readFileSync(contextPath, 'utf8'));
70
+
71
+ if (!context.project || !context.paths) {
72
+ console.error('❌ Error: Invalid context format. Missing required fields.');
73
+ process.exit(1);
74
+ }
75
+
76
+ console.log(`✅ Context loaded: ${context.project.totalFiles} files`);
77
+ console.log('📄 Generating GitIngest digest from context...\n');
78
+
79
+ // Extract files from context.paths structure
80
+ const files = [];
81
+ for (const [dirPath, fileNames] of Object.entries(context.paths)) {
82
+ for (const fileName of fileNames) {
83
+ const relativePath = dirPath === '/'
84
+ ? fileName
85
+ : `${dirPath}${fileName}`;
86
+
87
+ const fullPath = path.join(process.cwd(), relativePath);
88
+
89
+ if (fs.existsSync(fullPath)) {
90
+ const stats = fs.statSync(fullPath);
91
+ files.push({
92
+ path: fullPath,
93
+ relativePath: relativePath,
94
+ sizeBytes: stats.size,
95
+ tokens: 0,
96
+ lines: 0
97
+ });
98
+ }
99
+ }
100
+ }
101
+
102
+ console.log(`📁 Found ${files.length} accessible files`);
103
+
104
+ const stats = {
105
+ totalFiles: files.length,
106
+ totalTokens: context.project.totalTokens,
107
+ totalBytes: files.reduce((sum, f) => sum + f.sizeBytes, 0),
108
+ totalLines: 0
109
+ };
110
+
111
+ const formatter = new GitIngestFormatter(
112
+ process.cwd(),
113
+ stats,
114
+ files
115
+ );
116
+
117
+ const digestPath = path.join(process.cwd(), 'digest.txt');
118
+ const digestSize = formatter.saveToFile(digestPath);
119
+
120
+ console.log(`💾 GitIngest digest saved to: digest.txt`);
121
+ console.log(`📊 Digest size: ${(digestSize / 1024).toFixed(1)} KB`);
122
+ console.log(`✨ Generated from: ${path.basename(contextPath)}`);
123
+
124
+ } catch (error) {
125
+ console.error(`❌ Error processing context: ${error.message}`);
126
+ process.exit(1);
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Main execution
132
+ */
133
+ async function main(args = process.argv.slice(2)) {
134
+ if (args.includes('--help') || args.includes('-h')) {
135
+ printHelp();
136
+ return;
137
+ }
138
+
139
+ // Handle --gitingest-from-report
140
+ const reportFlagIndex = args.indexOf('--gitingest-from-report');
141
+ if (reportFlagIndex !== -1) {
142
+ const reportPath = args[reportFlagIndex + 1] || 'token-analysis-report.json';
143
+ generateDigestFromReport(reportPath);
144
+ return;
145
+ }
146
+
147
+ // Handle --gitingest-from-context
148
+ const contextFlagIndex = args.indexOf('--gitingest-from-context');
149
+ if (contextFlagIndex !== -1) {
150
+ const contextPath = args[contextFlagIndex + 1] || 'llm-context.json';
151
+ generateDigestFromContext(contextPath);
152
+ return;
153
+ }
154
+
155
+ const options = {
156
+ saveReport: args.includes('--save-report') || args.includes('-s'),
157
+ verbose: args.includes('--verbose') || args.includes('-v'),
158
+ contextExport: args.includes('--context-export'),
159
+ contextToClipboard: args.includes('--context-clipboard'),
160
+ methodLevel: args.includes('--method-level') || args.includes('-m'),
161
+ gitingest: args.includes('--gitingest') || args.includes('-g')
162
+ };
163
+
164
+ printStartupInfo();
165
+
166
+ const calculator = new TokenCalculator(process.cwd(), options);
167
+ await calculator.run();
168
+ }
169
+
170
+ function printStartupInfo() {
171
+ console.log('🚀 Code Analyzer by Hakkı Sağdıç');
172
+ console.log('='.repeat(50));
173
+ console.log('📋 Available options:');
174
+ console.log(' --save-report, -s Save detailed JSON report');
175
+ console.log(' --verbose, -v Show included files and directories');
176
+ console.log(' --context-export Generate LLM context file list');
177
+ console.log(' --context-clipboard Copy context to clipboard');
178
+ console.log(' --method-level, -m Enable method-level analysis');
179
+ console.log(' --gitingest, -g Generate GitIngest-style digest');
180
+ console.log(' --help, -h Show this help message');
181
+
182
+ if (!TokenUtils.hasExactCounting()) {
183
+ console.log('\n💡 For exact token counts, install tiktoken: npm install tiktoken');
184
+ }
185
+ console.log();
186
+ }
187
+
188
+ function printHelp() {
189
+ console.log('Ctxman - LLM context optimization with method-level filtering');
190
+ console.log();
191
+ console.log('Usage: ctxman [options]');
192
+ console.log(' node ctxman.js [options] # Direct usage');
193
+ console.log();
194
+ console.log('Options:');
195
+ console.log(' -s, --save-report Save detailed JSON report');
196
+ console.log(' -v, --verbose Show all included files');
197
+ console.log(' --context-export Generate LLM context file');
198
+ console.log(' --context-clipboard Copy context to clipboard');
199
+ console.log(' -m, --method-level Enable method-level analysis');
200
+ console.log(' -g, --gitingest Generate GitIngest-style digest');
201
+ console.log(' --gitingest-from-report <file> Generate digest from report JSON');
202
+ console.log(' --gitingest-from-context <file> Generate digest from context JSON');
203
+ console.log(' -h, --help Show this help');
204
+ console.log();
205
+ console.log('Method-level Configuration:');
206
+ console.log(' .methodinclude Include only specified methods');
207
+ console.log(' .methodignore Exclude specified methods');
208
+ console.log();
209
+ console.log('Examples:');
210
+ console.log(' # Standard workflow');
211
+ console.log(' ctxman # Interactive export selection');
212
+ console.log(' ctxman --save-report # Save JSON report');
213
+ console.log(' ctxman --gitingest # Generate digest.txt');
214
+ console.log(' ctxman -g -s # Both digest + report');
215
+ console.log();
216
+ console.log(' # Generate digest from existing JSON files (fast, no re-scan)');
217
+ console.log(' ctxman --gitingest-from-report token-analysis-report.json');
218
+ console.log(' ctxman --gitingest-from-context llm-context.json');
219
+ console.log();
220
+ console.log(' # Two-step workflow');
221
+ console.log(' ctxman -s # Step 1: Analyze and save report');
222
+ console.log(' ctxman --gitingest-from-report token-analysis-report.json');
223
+ console.log(' # Step 2: Generate digest (instant)');
224
+ }
225
+
226
+ // ESM entry point check
227
+ if (import.meta.url === `file://${process.argv[1]}`) {
228
+ main();
229
+ }
230
+
231
+ export {
232
+ TokenCalculator,
233
+ generateDigestFromReport,
234
+ generateDigestFromContext,
235
+ main
236
+ };