devbrain-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +26 -0
  3. package/dist/bin.d.ts +2 -0
  4. package/dist/bin.js +48 -0
  5. package/dist/commands/context.command.d.ts +16 -0
  6. package/dist/commands/context.command.js +36 -0
  7. package/dist/commands/init.command.d.ts +16 -0
  8. package/dist/commands/init.command.js +57 -0
  9. package/dist/commands/learn.command.d.ts +17 -0
  10. package/dist/commands/learn.command.js +72 -0
  11. package/dist/pipeline/command.pipeline.d.ts +28 -0
  12. package/dist/pipeline/command.pipeline.js +65 -0
  13. package/dist/ui/logger.d.ts +13 -0
  14. package/dist/ui/logger.js +31 -0
  15. package/node_modules/@devbrain/core/dist/analysis/analyzer.interface.d.ts +10 -0
  16. package/node_modules/@devbrain/core/dist/analysis/analyzer.interface.js +2 -0
  17. package/node_modules/@devbrain/core/dist/analysis/analyzer.registry.d.ts +20 -0
  18. package/node_modules/@devbrain/core/dist/analysis/analyzer.registry.js +67 -0
  19. package/node_modules/@devbrain/core/dist/analysis/analyzers/build-gradle.analyzer.d.ts +14 -0
  20. package/node_modules/@devbrain/core/dist/analysis/analyzers/build-gradle.analyzer.js +53 -0
  21. package/node_modules/@devbrain/core/dist/analysis/analyzers/docker.analyzer.d.ts +14 -0
  22. package/node_modules/@devbrain/core/dist/analysis/analyzers/docker.analyzer.js +38 -0
  23. package/node_modules/@devbrain/core/dist/analysis/analyzers/git.analyzer.d.ts +14 -0
  24. package/node_modules/@devbrain/core/dist/analysis/analyzers/git.analyzer.js +54 -0
  25. package/node_modules/@devbrain/core/dist/analysis/analyzers/package-json.analyzer.d.ts +14 -0
  26. package/node_modules/@devbrain/core/dist/analysis/analyzers/package-json.analyzer.js +72 -0
  27. package/node_modules/@devbrain/core/dist/analysis/analyzers/pom-xml.analyzer.d.ts +14 -0
  28. package/node_modules/@devbrain/core/dist/analysis/analyzers/pom-xml.analyzer.js +70 -0
  29. package/node_modules/@devbrain/core/dist/analysis/analyzers/readme.analyzer.d.ts +17 -0
  30. package/node_modules/@devbrain/core/dist/analysis/analyzers/readme.analyzer.js +65 -0
  31. package/node_modules/@devbrain/core/dist/analysis/analyzers/requirements-txt.analyzer.d.ts +14 -0
  32. package/node_modules/@devbrain/core/dist/analysis/analyzers/requirements-txt.analyzer.js +62 -0
  33. package/node_modules/@devbrain/core/dist/analysis/analyzers/tsconfig.analyzer.d.ts +14 -0
  34. package/node_modules/@devbrain/core/dist/analysis/analyzers/tsconfig.analyzer.js +47 -0
  35. package/node_modules/@devbrain/core/dist/analysis/scanner.d.ts +21 -0
  36. package/node_modules/@devbrain/core/dist/analysis/scanner.js +81 -0
  37. package/node_modules/@devbrain/core/dist/context/context.service.d.ts +17 -0
  38. package/node_modules/@devbrain/core/dist/context/context.service.js +72 -0
  39. package/node_modules/@devbrain/core/dist/filesystem/filesystem.service.d.ts +29 -0
  40. package/node_modules/@devbrain/core/dist/filesystem/filesystem.service.js +87 -0
  41. package/node_modules/@devbrain/core/dist/index.d.ts +14 -0
  42. package/node_modules/@devbrain/core/dist/index.js +16 -0
  43. package/node_modules/@devbrain/core/dist/memory/memory.service.d.ts +19 -0
  44. package/node_modules/@devbrain/core/dist/memory/memory.service.js +158 -0
  45. package/node_modules/@devbrain/core/package.json +22 -0
  46. package/node_modules/@devbrain/shared/dist/constants.d.ts +6 -0
  47. package/node_modules/@devbrain/shared/dist/constants.js +15 -0
  48. package/node_modules/@devbrain/shared/dist/errors.d.ts +38 -0
  49. package/node_modules/@devbrain/shared/dist/errors.js +64 -0
  50. package/node_modules/@devbrain/shared/dist/index.d.ts +3 -0
  51. package/node_modules/@devbrain/shared/dist/index.js +4 -0
  52. package/node_modules/@devbrain/shared/dist/types.d.ts +52 -0
  53. package/node_modules/@devbrain/shared/dist/types.js +2 -0
  54. package/node_modules/@devbrain/shared/package.json +14 -0
  55. package/package.json +65 -0
@@ -0,0 +1,38 @@
1
+ import { join } from 'node:path';
2
+ import { FilesystemService } from '../../filesystem/filesystem.service.js';
3
+ /**
4
+ * Analyzer for Dockerfile.
5
+ */
6
+ export class DockerfileAnalyzer {
7
+ fsService;
8
+ id = 'dockerfile';
9
+ name = 'Dockerfile Analyzer';
10
+ constructor(fsService = new FilesystemService()) {
11
+ this.fsService = fsService;
12
+ }
13
+ async supports(project) {
14
+ return project.files.some((f) => f === 'Dockerfile' || f.endsWith('.dockerfile'));
15
+ }
16
+ async analyze(project) {
17
+ const dockerfile = project.files.find((f) => f === 'Dockerfile' || f.endsWith('.dockerfile'));
18
+ const path = join(project.cwd, dockerfile);
19
+ const content = await this.fsService.read(path);
20
+ const fromMatch = content.match(/^FROM\s+(.+)$/im);
21
+ const baseImage = fromMatch ? fromMatch[1].trim() : 'unknown';
22
+ const ports = [];
23
+ const portMatches = content.matchAll(/^EXPOSE\s+(.+)$/gim);
24
+ for (const match of portMatches) {
25
+ ports.push(...match[1].trim().split(/\s+/));
26
+ }
27
+ return {
28
+ analyzerId: this.id,
29
+ analyzerName: this.name,
30
+ data: {
31
+ baseImage,
32
+ exposedPorts: ports,
33
+ technologies: ['Docker'],
34
+ },
35
+ };
36
+ }
37
+ }
38
+ //# sourceMappingURL=docker.analyzer.js.map
@@ -0,0 +1,14 @@
1
+ import { ProjectContext, AnalysisResult } from '@devbrain/shared';
2
+ import { Analyzer } from '../analyzer.interface.js';
3
+ import { FilesystemService } from '../../filesystem/filesystem.service.js';
4
+ /**
5
+ * Analyzer for Git repository metrics.
6
+ */
7
+ export declare class GitAnalyzer implements Analyzer {
8
+ private readonly fsService;
9
+ readonly id = "git";
10
+ readonly name = "Git Repository Analyzer";
11
+ constructor(fsService?: FilesystemService);
12
+ supports(project: ProjectContext): Promise<boolean>;
13
+ analyze(project: ProjectContext): Promise<AnalysisResult>;
14
+ }
@@ -0,0 +1,54 @@
1
+ import { join } from 'node:path';
2
+ import { simpleGit } from 'simple-git';
3
+ import { FilesystemService } from '../../filesystem/filesystem.service.js';
4
+ /**
5
+ * Analyzer for Git repository metrics.
6
+ */
7
+ export class GitAnalyzer {
8
+ fsService;
9
+ id = 'git';
10
+ name = 'Git Repository Analyzer';
11
+ constructor(fsService = new FilesystemService()) {
12
+ this.fsService = fsService;
13
+ }
14
+ async supports(project) {
15
+ // Check if .git directory/metadata exists
16
+ const gitHeadPath = join(project.cwd, '.git/HEAD');
17
+ return await this.fsService.exists(gitHeadPath);
18
+ }
19
+ async analyze(project) {
20
+ const git = simpleGit({ baseDir: project.cwd });
21
+ let branch = 'unknown';
22
+ let commits = [];
23
+ let remotes = [];
24
+ try {
25
+ const status = await git.status();
26
+ branch = status.current || 'unknown';
27
+ const log = await git.log({ maxCount: 5 });
28
+ commits = log.all.map((c) => ({
29
+ hash: c.hash.substring(0, 7),
30
+ date: c.date,
31
+ message: c.message,
32
+ author: c.author_name,
33
+ }));
34
+ const rawRemotes = await git.getRemotes(true);
35
+ remotes = rawRemotes.map((r) => ({
36
+ name: r.name,
37
+ refs: r.refs,
38
+ }));
39
+ }
40
+ catch {
41
+ // Graceful fallback if git commands fail
42
+ }
43
+ return {
44
+ analyzerId: this.id,
45
+ analyzerName: this.name,
46
+ data: {
47
+ branch,
48
+ recentCommits: commits,
49
+ remotes,
50
+ },
51
+ };
52
+ }
53
+ }
54
+ //# sourceMappingURL=git.analyzer.js.map
@@ -0,0 +1,14 @@
1
+ import { ProjectContext, AnalysisResult } from '@devbrain/shared';
2
+ import { Analyzer } from '../analyzer.interface.js';
3
+ import { FilesystemService } from '../../filesystem/filesystem.service.js';
4
+ /**
5
+ * Analyzer for package.json files.
6
+ */
7
+ export declare class PackageJsonAnalyzer implements Analyzer {
8
+ private readonly fsService;
9
+ readonly id = "package-json";
10
+ readonly name = "package.json Analyzer";
11
+ constructor(fsService?: FilesystemService);
12
+ supports(project: ProjectContext): Promise<boolean>;
13
+ analyze(project: ProjectContext): Promise<AnalysisResult>;
14
+ }
@@ -0,0 +1,72 @@
1
+ import { join } from 'node:path';
2
+ import { FilesystemService } from '../../filesystem/filesystem.service.js';
3
+ /**
4
+ * Analyzer for package.json files.
5
+ */
6
+ export class PackageJsonAnalyzer {
7
+ fsService;
8
+ id = 'package-json';
9
+ name = 'package.json Analyzer';
10
+ constructor(fsService = new FilesystemService()) {
11
+ this.fsService = fsService;
12
+ }
13
+ async supports(project) {
14
+ return project.files.some((f) => f === 'package.json');
15
+ }
16
+ async analyze(project) {
17
+ const packageJsonFile = project.files.find((f) => f === 'package.json');
18
+ const packageJsonPath = join(project.cwd, packageJsonFile);
19
+ const data = await this.fsService.readJson(packageJsonPath);
20
+ const name = data.name || 'unnamed';
21
+ const version = data.version || '0.0.0';
22
+ const scripts = Object.keys(data.scripts || {});
23
+ const dependencies = Object.keys(data.dependencies || {});
24
+ const devDependencies = Object.keys(data.devDependencies || {});
25
+ // Infer technologies and frameworks
26
+ const technologies = ['Node.js'];
27
+ const frameworks = [];
28
+ if (devDependencies.includes('typescript') || dependencies.includes('typescript')) {
29
+ technologies.push('TypeScript');
30
+ }
31
+ else {
32
+ technologies.push('JavaScript');
33
+ }
34
+ const frameworkMap = {
35
+ next: 'Next.js',
36
+ react: 'React',
37
+ vue: 'Vue',
38
+ nuxt: 'Nuxt',
39
+ svelte: 'Svelte',
40
+ express: 'Express',
41
+ fastify: 'Fastify',
42
+ hono: 'Hono',
43
+ nest: 'NestJS',
44
+ };
45
+ const allDeps = [...dependencies, ...devDependencies];
46
+ for (const [depKey, fwName] of Object.entries(frameworkMap)) {
47
+ if (allDeps.some((d) => d.includes(depKey))) {
48
+ frameworks.push(fwName);
49
+ }
50
+ }
51
+ return {
52
+ analyzerId: this.id,
53
+ analyzerName: this.name,
54
+ data: {
55
+ name,
56
+ version,
57
+ scripts,
58
+ dependencies: data.dependencies || {},
59
+ devDependencies: data.devDependencies || {},
60
+ engines: data.engines || {},
61
+ workspaces: data.workspaces || null,
62
+ technologies,
63
+ frameworks,
64
+ metadata: {
65
+ projectLanguage: technologies.includes('TypeScript') ? 'TypeScript' : 'JavaScript',
66
+ projectFramework: frameworks[0] || 'Node.js base',
67
+ },
68
+ },
69
+ };
70
+ }
71
+ }
72
+ //# sourceMappingURL=package-json.analyzer.js.map
@@ -0,0 +1,14 @@
1
+ import { ProjectContext, AnalysisResult } from '@devbrain/shared';
2
+ import { Analyzer } from '../analyzer.interface.js';
3
+ import { FilesystemService } from '../../filesystem/filesystem.service.js';
4
+ /**
5
+ * Analyzer for Maven pom.xml configuration files.
6
+ */
7
+ export declare class PomXmlAnalyzer implements Analyzer {
8
+ private readonly fsService;
9
+ readonly id = "pom-xml";
10
+ readonly name = "Maven POM Analyzer";
11
+ constructor(fsService?: FilesystemService);
12
+ supports(project: ProjectContext): Promise<boolean>;
13
+ analyze(project: ProjectContext): Promise<AnalysisResult>;
14
+ }
@@ -0,0 +1,70 @@
1
+ import { join } from 'node:path';
2
+ import { XMLParser } from 'fast-xml-parser';
3
+ import { FilesystemService } from '../../filesystem/filesystem.service.js';
4
+ /**
5
+ * Analyzer for Maven pom.xml configuration files.
6
+ */
7
+ export class PomXmlAnalyzer {
8
+ fsService;
9
+ id = 'pom-xml';
10
+ name = 'Maven POM Analyzer';
11
+ constructor(fsService = new FilesystemService()) {
12
+ this.fsService = fsService;
13
+ }
14
+ async supports(project) {
15
+ return project.files.some((f) => f === 'pom.xml');
16
+ }
17
+ async analyze(project) {
18
+ const file = project.files.find((f) => f === 'pom.xml');
19
+ const path = join(project.cwd, file);
20
+ const content = await this.fsService.read(path);
21
+ let groupId = 'unknown';
22
+ let artifactId = 'unknown';
23
+ let version = 'unknown';
24
+ const dependencies = [];
25
+ const frameworks = [];
26
+ try {
27
+ const parser = new XMLParser();
28
+ const xml = parser.parse(content);
29
+ const projectNode = xml.project || {};
30
+ groupId = projectNode.groupId || projectNode.parent?.groupId || 'unknown';
31
+ artifactId = projectNode.artifactId || 'unknown';
32
+ version = projectNode.version || projectNode.parent?.version || 'unknown';
33
+ // Parse dependencies
34
+ let depsList = projectNode.dependencies?.dependency;
35
+ if (depsList) {
36
+ if (!Array.isArray(depsList)) {
37
+ depsList = [depsList];
38
+ }
39
+ for (const dep of depsList) {
40
+ if (dep.artifactId) {
41
+ dependencies.push(dep.artifactId);
42
+ if (dep.artifactId.includes('spring-boot')) {
43
+ frameworks.push('Spring Boot');
44
+ }
45
+ }
46
+ }
47
+ }
48
+ }
49
+ catch {
50
+ // Graceful fallback
51
+ }
52
+ return {
53
+ analyzerId: this.id,
54
+ analyzerName: this.name,
55
+ data: {
56
+ groupId,
57
+ artifactId,
58
+ version,
59
+ dependencies,
60
+ frameworks,
61
+ technologies: ['Java', 'Maven'],
62
+ metadata: {
63
+ projectLanguage: 'Java',
64
+ projectFramework: frameworks[0] || 'Java Maven base',
65
+ },
66
+ },
67
+ };
68
+ }
69
+ }
70
+ //# sourceMappingURL=pom-xml.analyzer.js.map
@@ -0,0 +1,17 @@
1
+ import { ProjectContext, AnalysisResult } from '@devbrain/shared';
2
+ import { Analyzer } from '../analyzer.interface.js';
3
+ import { FilesystemService } from '../../filesystem/filesystem.service.js';
4
+ /**
5
+ * Analyzer for README files.
6
+ */
7
+ export declare class ReadmeAnalyzer implements Analyzer {
8
+ private readonly fsService;
9
+ readonly id = "readme";
10
+ readonly name = "README.md Analyzer";
11
+ constructor(fsService?: FilesystemService);
12
+ supports(project: ProjectContext): Promise<boolean>;
13
+ analyze(project: ProjectContext): Promise<AnalysisResult>;
14
+ private extractTitle;
15
+ private extractSections;
16
+ private extractDescription;
17
+ }
@@ -0,0 +1,65 @@
1
+ import { join } from 'node:path';
2
+ import { FilesystemService } from '../../filesystem/filesystem.service.js';
3
+ /**
4
+ * Analyzer for README files.
5
+ */
6
+ export class ReadmeAnalyzer {
7
+ fsService;
8
+ id = 'readme';
9
+ name = 'README.md Analyzer';
10
+ constructor(fsService = new FilesystemService()) {
11
+ this.fsService = fsService;
12
+ }
13
+ async supports(project) {
14
+ return project.files.some((f) => f.toLowerCase() === 'readme.md');
15
+ }
16
+ async analyze(project) {
17
+ const readmeFile = project.files.find((f) => f.toLowerCase() === 'readme.md');
18
+ const readmePath = join(project.cwd, readmeFile);
19
+ const content = await this.fsService.read(readmePath);
20
+ const title = this.extractTitle(content);
21
+ const sections = this.extractSections(content);
22
+ const description = this.extractDescription(content);
23
+ return {
24
+ analyzerId: this.id,
25
+ analyzerName: this.name,
26
+ data: {
27
+ title,
28
+ description,
29
+ sections,
30
+ },
31
+ };
32
+ }
33
+ extractTitle(content) {
34
+ const titleMatch = content.match(/^#\s+(.+)$/m);
35
+ return titleMatch ? titleMatch[1].trim() : 'Untitled Project';
36
+ }
37
+ extractSections(content) {
38
+ const sectionMatches = content.matchAll(/^##\s+(.+)$/gm);
39
+ return Array.from(sectionMatches).map((m) => m[1].trim());
40
+ }
41
+ extractDescription(content) {
42
+ const lines = content.split('\n');
43
+ let foundTitle = false;
44
+ const descriptionParagraphs = [];
45
+ for (const line of lines) {
46
+ const trimmed = line.trim();
47
+ if (trimmed.startsWith('# ')) {
48
+ foundTitle = true;
49
+ continue;
50
+ }
51
+ if (foundTitle) {
52
+ if (trimmed.startsWith('## ') || trimmed.startsWith('# ')) {
53
+ break; // Next section starts, stop extracting description
54
+ }
55
+ if (trimmed && !trimmed.startsWith('!') && !trimmed.startsWith('[')) {
56
+ descriptionParagraphs.push(trimmed);
57
+ if (descriptionParagraphs.length >= 2)
58
+ break; // Limit to first two descriptive paragraphs
59
+ }
60
+ }
61
+ }
62
+ return descriptionParagraphs.join(' ');
63
+ }
64
+ }
65
+ //# sourceMappingURL=readme.analyzer.js.map
@@ -0,0 +1,14 @@
1
+ import { ProjectContext, AnalysisResult } from '@devbrain/shared';
2
+ import { Analyzer } from '../analyzer.interface.js';
3
+ import { FilesystemService } from '../../filesystem/filesystem.service.js';
4
+ /**
5
+ * Analyzer for Python requirements.txt files.
6
+ */
7
+ export declare class RequirementsTxtAnalyzer implements Analyzer {
8
+ private readonly fsService;
9
+ readonly id = "requirements-txt";
10
+ readonly name = "Python Requirements Analyzer";
11
+ constructor(fsService?: FilesystemService);
12
+ supports(project: ProjectContext): Promise<boolean>;
13
+ analyze(project: ProjectContext): Promise<AnalysisResult>;
14
+ }
@@ -0,0 +1,62 @@
1
+ import { join } from 'node:path';
2
+ import { FilesystemService } from '../../filesystem/filesystem.service.js';
3
+ /**
4
+ * Analyzer for Python requirements.txt files.
5
+ */
6
+ export class RequirementsTxtAnalyzer {
7
+ fsService;
8
+ id = 'requirements-txt';
9
+ name = 'Python Requirements Analyzer';
10
+ constructor(fsService = new FilesystemService()) {
11
+ this.fsService = fsService;
12
+ }
13
+ async supports(project) {
14
+ return project.files.some((f) => f === 'requirements.txt');
15
+ }
16
+ async analyze(project) {
17
+ const file = project.files.find((f) => f === 'requirements.txt');
18
+ const path = join(project.cwd, file);
19
+ const content = await this.fsService.read(path);
20
+ const dependencies = [];
21
+ const lines = content.split(/\r?\n/);
22
+ for (let line of lines) {
23
+ line = line.trim();
24
+ if (!line || line.startsWith('#')) {
25
+ continue;
26
+ }
27
+ // Simple parse: package==version, package>=version, etc.
28
+ const match = line.match(/^([a-zA-Z0-9_\-[\]]+)/);
29
+ if (match) {
30
+ dependencies.push(match[1]);
31
+ }
32
+ }
33
+ // Infer frameworks
34
+ const frameworks = [];
35
+ const frameworkMap = {
36
+ django: 'Django',
37
+ fastapi: 'FastAPI',
38
+ flask: 'Flask',
39
+ tornado: 'Tornado',
40
+ };
41
+ for (const dep of dependencies) {
42
+ const lowerDep = dep.toLowerCase();
43
+ if (frameworkMap[lowerDep]) {
44
+ frameworks.push(frameworkMap[lowerDep]);
45
+ }
46
+ }
47
+ return {
48
+ analyzerId: this.id,
49
+ analyzerName: this.name,
50
+ data: {
51
+ dependencies,
52
+ frameworks,
53
+ technologies: ['Python'],
54
+ metadata: {
55
+ projectLanguage: 'Python',
56
+ projectFramework: frameworks[0] || 'Python base',
57
+ },
58
+ },
59
+ };
60
+ }
61
+ }
62
+ //# sourceMappingURL=requirements-txt.analyzer.js.map
@@ -0,0 +1,14 @@
1
+ import { ProjectContext, AnalysisResult } from '@devbrain/shared';
2
+ import { Analyzer } from '../analyzer.interface.js';
3
+ import { FilesystemService } from '../../filesystem/filesystem.service.js';
4
+ /**
5
+ * Analyzer for tsconfig.json configurations.
6
+ */
7
+ export declare class TsconfigAnalyzer implements Analyzer {
8
+ private readonly fsService;
9
+ readonly id = "tsconfig";
10
+ readonly name = "TypeScript Configuration Analyzer";
11
+ constructor(fsService?: FilesystemService);
12
+ supports(project: ProjectContext): Promise<boolean>;
13
+ analyze(project: ProjectContext): Promise<AnalysisResult>;
14
+ }
@@ -0,0 +1,47 @@
1
+ import { join } from 'node:path';
2
+ import { FilesystemService } from '../../filesystem/filesystem.service.js';
3
+ /**
4
+ * Analyzer for tsconfig.json configurations.
5
+ */
6
+ export class TsconfigAnalyzer {
7
+ fsService;
8
+ id = 'tsconfig';
9
+ name = 'TypeScript Configuration Analyzer';
10
+ constructor(fsService = new FilesystemService()) {
11
+ this.fsService = fsService;
12
+ }
13
+ async supports(project) {
14
+ return project.files.some((f) => f === 'tsconfig.json');
15
+ }
16
+ async analyze(project) {
17
+ const tsconfigFile = project.files.find((f) => f === 'tsconfig.json');
18
+ const tsconfigPath = join(project.cwd, tsconfigFile);
19
+ const rawContent = await this.fsService.read(tsconfigPath);
20
+ // Strip comments to allow parsing json with comments
21
+ const cleanJson = rawContent.replace(/\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/gm, '$1').trim();
22
+ let compilerOptions = {};
23
+ let references = [];
24
+ try {
25
+ const parsed = JSON.parse(cleanJson);
26
+ compilerOptions = parsed.compilerOptions || {};
27
+ references = parsed.references || [];
28
+ }
29
+ catch {
30
+ // Fallback if parsing fails
31
+ }
32
+ return {
33
+ analyzerId: this.id,
34
+ analyzerName: this.name,
35
+ data: {
36
+ target: compilerOptions.target || 'default',
37
+ module: compilerOptions.module || 'default',
38
+ moduleResolution: compilerOptions.moduleResolution || 'default',
39
+ strict: compilerOptions.strict ?? false,
40
+ jsx: compilerOptions.jsx || 'none',
41
+ referencesCount: references.length,
42
+ technologies: ['TypeScript'],
43
+ },
44
+ };
45
+ }
46
+ }
47
+ //# sourceMappingURL=tsconfig.analyzer.js.map
@@ -0,0 +1,21 @@
1
+ import { FilesystemService } from '../filesystem/filesystem.service.js';
2
+ export interface ScanOptions {
3
+ ignore?: string[];
4
+ followSymlinks?: boolean;
5
+ respectGitignore?: boolean;
6
+ }
7
+ /**
8
+ * Service for scanning repositories and finding files while respecting configuration filters.
9
+ */
10
+ export declare class RepositoryScanner {
11
+ private readonly fsService;
12
+ constructor(fsService?: FilesystemService);
13
+ /**
14
+ * Scans a workspace directory recursively and returns all matching relative file paths.
15
+ */
16
+ scan(cwd: string, options?: ScanOptions): Promise<string[]>;
17
+ /**
18
+ * Helper to translate standard .gitignore patterns into fast-glob rules.
19
+ */
20
+ private parseGitignore;
21
+ }
@@ -0,0 +1,81 @@
1
+ import fg from 'fast-glob';
2
+ import { join } from 'node:path';
3
+ import { FilesystemService } from '../filesystem/filesystem.service.js';
4
+ import { DEFAULT_IGNORE_PATTERNS } from '@devbrain/shared';
5
+ /**
6
+ * Service for scanning repositories and finding files while respecting configuration filters.
7
+ */
8
+ export class RepositoryScanner {
9
+ fsService;
10
+ constructor(fsService = new FilesystemService()) {
11
+ this.fsService = fsService;
12
+ }
13
+ /**
14
+ * Scans a workspace directory recursively and returns all matching relative file paths.
15
+ */
16
+ async scan(cwd, options = {}) {
17
+ const ignoreList = [...(options.ignore || DEFAULT_IGNORE_PATTERNS)];
18
+ // Respect .gitignore if configured
19
+ if (options.respectGitignore !== false) {
20
+ const gitignorePath = join(cwd, '.gitignore');
21
+ if (await this.fsService.exists(gitignorePath)) {
22
+ try {
23
+ const gitignoreContent = await this.fsService.read(gitignorePath);
24
+ const gitignoreRules = this.parseGitignore(gitignoreContent);
25
+ ignoreList.push(...gitignoreRules);
26
+ }
27
+ catch {
28
+ // Fallback silently if gitignore reading fails
29
+ }
30
+ }
31
+ }
32
+ // fast-glob parameters
33
+ const files = await fg('**/*', {
34
+ cwd,
35
+ ignore: ignoreList,
36
+ followSymbolicLinks: options.followSymlinks ?? false,
37
+ dot: true, // Scan hidden files like .gitignore or .git
38
+ onlyFiles: true,
39
+ });
40
+ return files;
41
+ }
42
+ /**
43
+ * Helper to translate standard .gitignore patterns into fast-glob rules.
44
+ */
45
+ parseGitignore(content) {
46
+ const rules = [];
47
+ const lines = content.split(/\r?\n/);
48
+ for (let line of lines) {
49
+ line = line.trim();
50
+ // Skip empty lines and comments
51
+ if (!line || line.startsWith('#')) {
52
+ continue;
53
+ }
54
+ // Negative patterns are not directly handled by basic fast-glob ignores,
55
+ // but simple exclusions are translated.
56
+ let pattern = line;
57
+ if (pattern.startsWith('!')) {
58
+ continue; // Skip negative ignores for simplicity in scanner v0.1
59
+ }
60
+ if (pattern.startsWith('/')) {
61
+ pattern = pattern.substring(1);
62
+ }
63
+ // If it has no slash and is not a wildcard, it can be anywhere in the directory hierarchy
64
+ if (!pattern.includes('/')) {
65
+ rules.push(`**/${pattern}`);
66
+ rules.push(`**/${pattern}/**`);
67
+ }
68
+ else {
69
+ if (pattern.endsWith('/')) {
70
+ rules.push(`${pattern}**`);
71
+ }
72
+ else {
73
+ rules.push(pattern);
74
+ rules.push(`${pattern}/**`);
75
+ }
76
+ }
77
+ }
78
+ return rules;
79
+ }
80
+ }
81
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1,17 @@
1
+ import { FilesystemService } from '../filesystem/filesystem.service.js';
2
+ /**
3
+ * Service responsible for reading generated project memory and consolidating it into an optimized AI prompt context.
4
+ */
5
+ export declare class ContextService {
6
+ private readonly fsService;
7
+ constructor(fsService?: FilesystemService);
8
+ /**
9
+ * Reads memory markdown files, validates existence, and compiles them into a single token-efficient string.
10
+ */
11
+ buildContext(memoryDir: string): Promise<string>;
12
+ /**
13
+ * Formats and converts absolute top-level headers (#) to sub-headers (##)
14
+ * to maintain a single root h1 structure and optimizes whitespaces.
15
+ */
16
+ private normalizeHeadings;
17
+ }