@anhnguyen02/catlas 0.1.2

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 (70) hide show
  1. package/README.md +59 -0
  2. package/dist/assembler/context-assembler.d.ts +17 -0
  3. package/dist/assembler/context-assembler.d.ts.map +1 -0
  4. package/dist/assembler/context-assembler.js +18 -0
  5. package/dist/assembler/context-assembler.js.map +1 -0
  6. package/dist/cli.d.ts +3 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +113 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/detector/project-detector.d.ts +10 -0
  11. package/dist/detector/project-detector.d.ts.map +1 -0
  12. package/dist/detector/project-detector.js +171 -0
  13. package/dist/detector/project-detector.js.map +1 -0
  14. package/dist/exporter/markdown.d.ts +5 -0
  15. package/dist/exporter/markdown.d.ts.map +1 -0
  16. package/dist/exporter/markdown.js +106 -0
  17. package/dist/exporter/markdown.js.map +1 -0
  18. package/dist/extractor/ctags-runner.d.ts +8 -0
  19. package/dist/extractor/ctags-runner.d.ts.map +1 -0
  20. package/dist/extractor/ctags-runner.js +99 -0
  21. package/dist/extractor/ctags-runner.js.map +1 -0
  22. package/dist/extractor/import-graph.d.ts +6 -0
  23. package/dist/extractor/import-graph.d.ts.map +1 -0
  24. package/dist/extractor/import-graph.js +127 -0
  25. package/dist/extractor/import-graph.js.map +1 -0
  26. package/dist/extractor/module-graph.d.ts +16 -0
  27. package/dist/extractor/module-graph.d.ts.map +1 -0
  28. package/dist/extractor/module-graph.js +108 -0
  29. package/dist/extractor/module-graph.js.map +1 -0
  30. package/dist/ranker/priority-ranker.d.ts +15 -0
  31. package/dist/ranker/priority-ranker.d.ts.map +1 -0
  32. package/dist/ranker/priority-ranker.js +49 -0
  33. package/dist/ranker/priority-ranker.js.map +1 -0
  34. package/dist/scanner/file-classifier.d.ts +9 -0
  35. package/dist/scanner/file-classifier.d.ts.map +1 -0
  36. package/dist/scanner/file-classifier.js +21 -0
  37. package/dist/scanner/file-classifier.js.map +1 -0
  38. package/dist/scanner/role-detector.d.ts +9 -0
  39. package/dist/scanner/role-detector.d.ts.map +1 -0
  40. package/dist/scanner/role-detector.js +39 -0
  41. package/dist/scanner/role-detector.js.map +1 -0
  42. package/dist/scanner/tree-builder.d.ts +8 -0
  43. package/dist/scanner/tree-builder.d.ts.map +1 -0
  44. package/dist/scanner/tree-builder.js +13 -0
  45. package/dist/scanner/tree-builder.js.map +1 -0
  46. package/dist/scanner/tree-walker.d.ts +7 -0
  47. package/dist/scanner/tree-walker.d.ts.map +1 -0
  48. package/dist/scanner/tree-walker.js +43 -0
  49. package/dist/scanner/tree-walker.js.map +1 -0
  50. package/dist/types.d.ts +34 -0
  51. package/dist/types.d.ts.map +1 -0
  52. package/dist/types.js +2 -0
  53. package/dist/types.js.map +1 -0
  54. package/dist/utils/cache.d.ts +18 -0
  55. package/dist/utils/cache.d.ts.map +1 -0
  56. package/dist/utils/cache.js +50 -0
  57. package/dist/utils/cache.js.map +1 -0
  58. package/dist/utils/diff.d.ts +10 -0
  59. package/dist/utils/diff.d.ts.map +1 -0
  60. package/dist/utils/diff.js +43 -0
  61. package/dist/utils/diff.js.map +1 -0
  62. package/dist/utils/gitignore.d.ts +9 -0
  63. package/dist/utils/gitignore.d.ts.map +1 -0
  64. package/dist/utils/gitignore.js +35 -0
  65. package/dist/utils/gitignore.js.map +1 -0
  66. package/dist/utils/logger.d.ts +7 -0
  67. package/dist/utils/logger.d.ts.map +1 -0
  68. package/dist/utils/logger.js +33 -0
  69. package/dist/utils/logger.js.map +1 -0
  70. package/package.json +51 -0
@@ -0,0 +1,43 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import ignore from 'ignore';
4
+ export class TreeWalker {
5
+ ig = ignore();
6
+ rootDir;
7
+ constructor(rootDir) {
8
+ this.rootDir = rootDir;
9
+ // Basic defaults
10
+ // Generic defaults — framework output dirs and dependency dirs
11
+ this.ig.add(['node_modules', '.git', 'dist', 'build', '.output', '.nuxt', '.next', '__pycache__', '.venv', 'venv', 'target', 'vendor', '.idea', '.vscode', 'coverage']);
12
+ const gitignorePath = path.join(rootDir, '.gitignore');
13
+ if (fs.existsSync(gitignorePath)) {
14
+ this.ig.add(fs.readFileSync(gitignorePath, 'utf-8'));
15
+ }
16
+ }
17
+ walk(dir = this.rootDir) {
18
+ let results = [];
19
+ const list = fs.readdirSync(dir, { withFileTypes: true });
20
+ for (const file of list) {
21
+ const fullPath = path.join(dir, file.name);
22
+ const relPath = path.relative(this.rootDir, fullPath);
23
+ const isDir = file.isDirectory();
24
+ // Always use POSIX paths for ignore matching
25
+ const posixPath = relPath.split(path.sep).join('/');
26
+ const checkPath = isDir ? posixPath + '/' : posixPath;
27
+ if (this.ig.ignores(checkPath)) {
28
+ continue;
29
+ }
30
+ if (isDir) {
31
+ results = results.concat(this.walk(fullPath));
32
+ }
33
+ else {
34
+ // Only keep code files for now
35
+ if (posixPath.match(/\.(ts|js|tsx|jsx|vue|py|go|php|java|kt|rs|rb|swift|c|cpp|h)$/)) {
36
+ results.push(relPath.split(path.sep).join('/'));
37
+ }
38
+ }
39
+ }
40
+ return results;
41
+ }
42
+ }
43
+ //# sourceMappingURL=tree-walker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree-walker.js","sourceRoot":"","sources":["../../src/scanner/tree-walker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,MAAM,MAAM,QAAQ,CAAA;AAE3B,MAAM,OAAO,UAAU;IACb,EAAE,GAAG,MAAM,EAAE,CAAA;IACb,OAAO,CAAQ;IAEvB,YAAY,OAAe;QACzB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,iBAAiB;QACjB,+DAA+D;QAC/D,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,CAAA;QAEvK,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAA;QACtD,IAAI,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;YACjC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC,CAAA;QACtD,CAAC;IACH,CAAC;IAEM,IAAI,CAAC,MAAc,IAAI,CAAC,OAAO;QACpC,IAAI,OAAO,GAAa,EAAE,CAAA;QAC1B,MAAM,IAAI,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAA;QAEzD,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;YACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;YAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;YAErD,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAA;YAEhC,6CAA6C;YAC7C,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACnD,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,CAAC,SAAS,CAAA;YAErD,IAAI,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC/B,SAAQ;YACV,CAAC;YAED,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAA;YAC/C,CAAC;iBAAM,CAAC;gBACN,+BAA+B;gBAC/B,IAAI,SAAS,CAAC,KAAK,CAAC,8DAA8D,CAAC,EAAE,CAAC;oBACpF,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;gBACjD,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAA;IAChB,CAAC;CACF"}
@@ -0,0 +1,34 @@
1
+ export type FileRole = 'entry' | 'page' | 'api-route' | 'service' | 'repository' | 'composable' | 'component' | 'config' | 'internal' | 'util' | 'unknown';
2
+ export interface ProjectProfile {
3
+ language: string;
4
+ framework: string;
5
+ projectName?: string;
6
+ description?: string;
7
+ entryPoints?: string[];
8
+ dependencies?: Record<string, string>;
9
+ scripts?: Record<string, string>;
10
+ }
11
+ export interface ModuleNode {
12
+ path: string;
13
+ fileCount: number;
14
+ dependsOn: string[];
15
+ dependedBy: string[];
16
+ }
17
+ export interface ExtractedSymbol {
18
+ name: string;
19
+ kind: 'function' | 'class' | 'interface' | 'type' | 'variable' | 'method' | 'component' | 'alias' | 'constant' | 'unknown';
20
+ signature: string;
21
+ line: number;
22
+ isExported: boolean;
23
+ fileRole: FileRole;
24
+ path: string;
25
+ inDegree: number;
26
+ }
27
+ export interface FileData {
28
+ path: string;
29
+ role: FileRole;
30
+ symbols: ExtractedSymbol[];
31
+ imports: string[];
32
+ inDegree: number;
33
+ }
34
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAChB,OAAO,GACP,MAAM,GACN,WAAW,GACX,SAAS,GACT,YAAY,GACZ,YAAY,GACZ,WAAW,GACX,QAAQ,GACR,UAAU,GACV,MAAM,GACN,SAAS,CAAA;AAEb,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACjC;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,UAAU,EAAE,MAAM,EAAE,CAAA;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,UAAU,GAAG,OAAO,GAAG,WAAW,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,CAAA;IAC1H,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,OAAO,CAAA;IACnB,QAAQ,EAAE,QAAQ,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,QAAQ,CAAA;IACd,OAAO,EAAE,eAAe,EAAE,CAAA;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;CACjB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,18 @@
1
+ export interface CacheEntry {
2
+ hash: string;
3
+ timestamp: string;
4
+ result: unknown;
5
+ }
6
+ /**
7
+ * Get SHA-256 hash of file content
8
+ */
9
+ export declare function hashFile(filePath: string): string;
10
+ /**
11
+ * Read cached result for a file. Returns null if cache miss or file changed.
12
+ */
13
+ export declare function readCache(rootDir: string, relativePath: string, currentHash: string): unknown | null;
14
+ /**
15
+ * Write result to cache for a file.
16
+ */
17
+ export declare function writeCache(rootDir: string, relativePath: string, hash: string, result: unknown): void;
18
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,OAAO,CAAA;CAChB;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGjD;AAUD;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAWpG;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAWrG"}
@@ -0,0 +1,50 @@
1
+ import * as crypto from 'node:crypto';
2
+ import * as fs from 'node:fs';
3
+ import * as path from 'node:path';
4
+ const CACHE_DIR = '.code-atlas/cache';
5
+ /**
6
+ * Get SHA-256 hash of file content
7
+ */
8
+ export function hashFile(filePath) {
9
+ const content = fs.readFileSync(filePath, 'utf-8');
10
+ return crypto.createHash('sha256').update(content).digest('hex');
11
+ }
12
+ /**
13
+ * Get cache file path for a given source file
14
+ */
15
+ function getCachePath(rootDir, relativePath) {
16
+ const safeName = relativePath.replace(/[/\\]/g, '__');
17
+ return path.join(rootDir, CACHE_DIR, `${safeName}.json`);
18
+ }
19
+ /**
20
+ * Read cached result for a file. Returns null if cache miss or file changed.
21
+ */
22
+ export function readCache(rootDir, relativePath, currentHash) {
23
+ const cachePath = getCachePath(rootDir, relativePath);
24
+ if (!fs.existsSync(cachePath))
25
+ return null;
26
+ try {
27
+ const entry = JSON.parse(fs.readFileSync(cachePath, 'utf-8'));
28
+ if (entry.hash === currentHash)
29
+ return entry.result;
30
+ return null;
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ }
36
+ /**
37
+ * Write result to cache for a file.
38
+ */
39
+ export function writeCache(rootDir, relativePath, hash, result) {
40
+ const cachePath = getCachePath(rootDir, relativePath);
41
+ const cacheDir = path.dirname(cachePath);
42
+ fs.mkdirSync(cacheDir, { recursive: true });
43
+ const entry = {
44
+ hash,
45
+ timestamp: new Date().toISOString(),
46
+ result,
47
+ };
48
+ fs.writeFileSync(cachePath, JSON.stringify(entry, null, 2));
49
+ }
50
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAA;AAC7B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AAEjC,MAAM,SAAS,GAAG,mBAAmB,CAAA;AAQrC;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,QAAgB;IACvC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IAClD,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AAClE,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,OAAe,EAAE,YAAoB;IACzD,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;IACrD,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,QAAQ,OAAO,CAAC,CAAA;AAC1D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,OAAe,EAAE,YAAoB,EAAE,WAAmB;IAClF,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,EAAE,YAAY,CAAC,CAAA;IACrD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAA;IAE1C,IAAI,CAAC;QACH,MAAM,KAAK,GAAe,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAA;QACzE,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW;YAAE,OAAO,KAAK,CAAC,MAAM,CAAA;QACnD,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,YAAoB,EAAE,IAAY,EAAE,MAAe;IAC7F,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,EAAE,YAAY,CAAC,CAAA;IACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IACxC,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAE3C,MAAM,KAAK,GAAe;QACxB,IAAI;QACJ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,MAAM;KACP,CAAA;IACD,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;AAC7D,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Get list of files changed since last scan (git diff).
3
+ * Returns null if no previous scan or not a git repo.
4
+ */
5
+ export declare function getChangedFiles(rootDir: string): string[] | null;
6
+ /**
7
+ * Save current HEAD commit hash as the last scan reference.
8
+ */
9
+ export declare function saveScanMeta(rootDir: string): void;
10
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/utils/diff.ts"],"names":[],"mappings":"AAWA;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CAehE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAkBlD"}
@@ -0,0 +1,43 @@
1
+ import { execSync } from 'node:child_process';
2
+ import * as fs from 'node:fs';
3
+ import * as path from 'node:path';
4
+ const META_FILE = '.code-atlas/meta.json';
5
+ /**
6
+ * Get list of files changed since last scan (git diff).
7
+ * Returns null if no previous scan or not a git repo.
8
+ */
9
+ export function getChangedFiles(rootDir) {
10
+ const metaPath = path.join(rootDir, META_FILE);
11
+ if (!fs.existsSync(metaPath))
12
+ return null;
13
+ try {
14
+ const meta = JSON.parse(fs.readFileSync(metaPath, 'utf-8'));
15
+ const output = execSync(`git diff --name-only ${meta.lastScanCommit} HEAD`, { cwd: rootDir, encoding: 'utf-8' });
16
+ return output.trim().split('\n').filter(Boolean);
17
+ }
18
+ catch {
19
+ return null;
20
+ }
21
+ }
22
+ /**
23
+ * Save current HEAD commit hash as the last scan reference.
24
+ */
25
+ export function saveScanMeta(rootDir) {
26
+ try {
27
+ const commit = execSync('git rev-parse HEAD', {
28
+ cwd: rootDir,
29
+ encoding: 'utf-8'
30
+ }).trim();
31
+ const meta = {
32
+ lastScanCommit: commit,
33
+ lastScanDate: new Date().toISOString(),
34
+ };
35
+ const metaDir = path.dirname(path.join(rootDir, META_FILE));
36
+ fs.mkdirSync(metaDir, { recursive: true });
37
+ fs.writeFileSync(path.join(rootDir, META_FILE), JSON.stringify(meta, null, 2));
38
+ }
39
+ catch {
40
+ // Not a git repo — skip
41
+ }
42
+ }
43
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/utils/diff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAC7C,OAAO,KAAK,EAAE,MAAM,SAAS,CAAA;AAC7B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AAEjC,MAAM,SAAS,GAAG,uBAAuB,CAAA;AAOzC;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;IAE9C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAA;IAEzC,IAAI,CAAC;QACH,MAAM,IAAI,GAAa,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAA;QACrE,MAAM,MAAM,GAAG,QAAQ,CACrB,wBAAwB,IAAI,CAAC,cAAc,OAAO,EAClD,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CACpC,CAAA;QACD,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,oBAAoB,EAAE;YAC5C,GAAG,EAAE,OAAO;YACZ,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC,IAAI,EAAE,CAAA;QAET,MAAM,IAAI,GAAa;YACrB,cAAc,EAAE,MAAM;YACtB,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACvC,CAAA;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAA;QAC3D,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC1C,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;IAChF,CAAC;IAAC,MAAM,CAAC;QACP,wBAAwB;IAC1B,CAAC;AACH,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Parse .gitignore file and return an `ignore` instance
3
+ */
4
+ export declare function parseGitignore(rootDir: string): string[];
5
+ /**
6
+ * Auto-append `.code-atlas/raw/` to .gitignore if not present.
7
+ */
8
+ export declare function ensureGitignore(rootDir: string): void;
9
+ //# sourceMappingURL=gitignore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitignore.d.ts","sourceRoot":"","sources":["../../src/utils/gitignore.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CASxD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAarD"}
@@ -0,0 +1,35 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ const GITIGNORE_MARKER = '# code-atlas';
4
+ const RAW_DIR_ENTRY = '.code-atlas/raw/';
5
+ /**
6
+ * Parse .gitignore file and return an `ignore` instance
7
+ */
8
+ export function parseGitignore(rootDir) {
9
+ const gitignorePath = path.join(rootDir, '.gitignore');
10
+ if (!fs.existsSync(gitignorePath))
11
+ return [];
12
+ const content = fs.readFileSync(gitignorePath, 'utf-8');
13
+ return content
14
+ .split('\n')
15
+ .map(line => line.trim())
16
+ .filter(line => line && !line.startsWith('#'));
17
+ }
18
+ /**
19
+ * Auto-append `.code-atlas/raw/` to .gitignore if not present.
20
+ */
21
+ export function ensureGitignore(rootDir) {
22
+ const gitignorePath = path.join(rootDir, '.gitignore');
23
+ if (fs.existsSync(gitignorePath)) {
24
+ const content = fs.readFileSync(gitignorePath, 'utf-8');
25
+ if (content.includes(RAW_DIR_ENTRY))
26
+ return;
27
+ const appendText = `\n${GITIGNORE_MARKER}\n${RAW_DIR_ENTRY}\n`;
28
+ fs.appendFileSync(gitignorePath, appendText);
29
+ }
30
+ else {
31
+ const content = `${GITIGNORE_MARKER}\n${RAW_DIR_ENTRY}\n`;
32
+ fs.writeFileSync(gitignorePath, content);
33
+ }
34
+ }
35
+ //# sourceMappingURL=gitignore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitignore.js","sourceRoot":"","sources":["../../src/utils/gitignore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAA;AAC7B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AAEjC,MAAM,gBAAgB,GAAG,cAAc,CAAA;AACvC,MAAM,aAAa,GAAG,kBAAkB,CAAA;AAExC;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAA;IACtD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC;QAAE,OAAO,EAAE,CAAA;IAE5C,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAA;IACvD,OAAO,OAAO;SACX,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SACxB,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAA;AAClD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAA;IAEtD,IAAI,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAA;QACvD,IAAI,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;YAAE,OAAM;QAE3C,MAAM,UAAU,GAAG,KAAK,gBAAgB,KAAK,aAAa,IAAI,CAAA;QAC9D,EAAE,CAAC,cAAc,CAAC,aAAa,EAAE,UAAU,CAAC,CAAA;IAC9C,CAAC;SAAM,CAAC;QACN,MAAM,OAAO,GAAG,GAAG,gBAAgB,KAAK,aAAa,IAAI,CAAA;QACzD,EAAE,CAAC,aAAa,CAAC,aAAa,EAAE,OAAO,CAAC,CAAA;IAC1C,CAAC;AACH,CAAC"}
@@ -0,0 +1,7 @@
1
+ type LogLevel = 'info' | 'success' | 'warn' | 'error' | 'debug';
2
+ export declare function setVerbose(v: boolean): void;
3
+ export declare function log(level: LogLevel, message: string, detail?: string): void;
4
+ export declare function logStep(step: number, total: number, message: string): void;
5
+ export declare function logDivider(): void;
6
+ export {};
7
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAEA,KAAK,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAA;AAY/D,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,QAEpC;AAED,wBAAgB,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,QAepE;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,QAEnE;AAED,wBAAgB,UAAU,SAEzB"}
@@ -0,0 +1,33 @@
1
+ import chalk from 'chalk';
2
+ const ICONS = {
3
+ info: '📋',
4
+ success: '✅',
5
+ warn: '⚠️',
6
+ error: '❌',
7
+ debug: '🔍',
8
+ };
9
+ let verbose = false;
10
+ export function setVerbose(v) {
11
+ verbose = v;
12
+ }
13
+ export function log(level, message, detail) {
14
+ if (level === 'debug' && !verbose)
15
+ return;
16
+ const icon = ICONS[level];
17
+ const colorFn = level === 'error' ? chalk.red :
18
+ level === 'warn' ? chalk.yellow :
19
+ level === 'success' ? chalk.green :
20
+ level === 'debug' ? chalk.gray :
21
+ chalk.blue;
22
+ console.log(`${icon} ${colorFn(message)}`);
23
+ if (detail) {
24
+ console.log(chalk.gray(` ${detail}`));
25
+ }
26
+ }
27
+ export function logStep(step, total, message) {
28
+ console.log(chalk.cyan(`[${step}/${total}]`) + ` ${message}`);
29
+ }
30
+ export function logDivider() {
31
+ console.log(chalk.gray('─'.repeat(50)));
32
+ }
33
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,MAAM,KAAK,GAA6B;IACtC,IAAI,EAAE,IAAI;IACV,OAAO,EAAE,GAAG;IACZ,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,GAAG;IACV,KAAK,EAAE,IAAI;CACZ,CAAA;AAED,IAAI,OAAO,GAAG,KAAK,CAAA;AAEnB,MAAM,UAAU,UAAU,CAAC,CAAU;IACnC,OAAO,GAAG,CAAC,CAAA;AACb,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,KAAe,EAAE,OAAe,EAAE,MAAe;IACnE,IAAI,KAAK,KAAK,OAAO,IAAI,CAAC,OAAO;QAAE,OAAM;IAEzC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAA;IACzB,MAAM,OAAO,GACX,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACjC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBACnC,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBAChC,KAAK,CAAC,IAAI,CAAA;IAEZ,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IAC1C,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC,CAAA;IACzC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,KAAa,EAAE,OAAe;IAClE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,KAAK,GAAG,CAAC,GAAG,IAAI,OAAO,EAAE,CAAC,CAAA;AAC/D,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;AACzC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@anhnguyen02/catlas",
3
+ "version": "0.1.2",
4
+ "description": "AI-First Codebase Context Generator — instantly maps your codebase for Cursor, Claude, and Aider",
5
+ "type": "module",
6
+ "bin": {
7
+ "catlas": "./dist/cli.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "prepack": "npm run build",
14
+ "build": "tsc",
15
+ "dev": "tsx src/cli.ts",
16
+ "test": "vitest run",
17
+ "test:watch": "vitest"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/anhnv02/catlas.git"
22
+ },
23
+ "keywords": [
24
+ "ai",
25
+ "codebase",
26
+ "context",
27
+ "atlas",
28
+ "llm",
29
+ "cursor",
30
+ "aider",
31
+ "claude",
32
+ "static-analysis"
33
+ ],
34
+ "author": "Anh Nguyen",
35
+ "license": "MIT",
36
+ "bugs": {
37
+ "url": "https://github.com/anhnv02/catlas/issues"
38
+ },
39
+ "homepage": "https://github.com/anhnv02/catlas#readme",
40
+ "devDependencies": {
41
+ "@types/node": "^22.0.0",
42
+ "@types/picomatch": "^4.0.2",
43
+ "typescript": "^5.7.0",
44
+ "vitest": "^3.0.0"
45
+ },
46
+ "dependencies": {
47
+ "chalk": "^5.6.2",
48
+ "commander": "^13.0.0",
49
+ "ignore": "^7.0.5"
50
+ }
51
+ }