vg-coder-cli 1.0.16 → 2.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.
- package/CHANGELOG.md +59 -0
- package/PUBLISHING.md +86 -0
- package/README.md +92 -318
- package/SYSTEM_PROMPT.md +157 -0
- package/init-nx-monorepo.sh +107 -0
- package/package.json +11 -4
- package/src/server/api-server.js +6 -1
- package/src/server/views/dashboard.html +69 -4
- package/vg/.vscode/extensions.json +8 -0
- package/vg/.vscode/launch.json +23 -0
- package/vg/README.md +85 -0
- package/vg/apps/api/project.json +83 -0
- package/vg/apps/api/src/app/analyze.controller.ts +17 -0
- package/vg/apps/api/src/app/analyze.service.ts +57 -0
- package/vg/apps/api/src/app/app.controller.ts +12 -0
- package/vg/apps/api/src/app/app.module.ts +29 -0
- package/vg/apps/api/src/app/app.service.ts +8 -0
- package/vg/apps/api/src/app/clean.controller.ts +40 -0
- package/vg/apps/api/src/app/execute.controller.ts +19 -0
- package/vg/apps/api/src/app/execute.service.ts +46 -0
- package/vg/apps/api/src/app/info.controller.ts +12 -0
- package/vg/apps/api/src/app/info.service.ts +65 -0
- package/vg/apps/api/src/assets/.gitkeep +0 -0
- package/vg/apps/api/src/main.ts +28 -0
- package/vg/apps/api/webpack.config.js +25 -0
- package/vg/apps/api-e2e/jest.config.cts +18 -0
- package/vg/apps/api-e2e/project.json +17 -0
- package/vg/apps/api-e2e/src/support/global-setup.ts +16 -0
- package/vg/apps/api-e2e/src/support/global-teardown.ts +10 -0
- package/vg/apps/api-e2e/src/support/test-setup.ts +9 -0
- package/vg/apps/ng-app/jest.config.ts +21 -0
- package/vg/apps/ng-app/project.json +110 -0
- package/vg/apps/ng-app/proxy.conf.json +8 -0
- package/vg/apps/ng-app/public/favicon.ico +0 -0
- package/vg/apps/ng-app/src/app/app.config.ts +17 -0
- package/vg/apps/ng-app/src/app/app.html +1 -0
- package/vg/apps/ng-app/src/app/app.routes.ts +7 -0
- package/vg/apps/ng-app/src/app/app.scss +0 -0
- package/vg/apps/ng-app/src/app/app.ts +12 -0
- package/vg/apps/ng-app/src/app/dashboard/dashboard.component.html +87 -0
- package/vg/apps/ng-app/src/app/dashboard/dashboard.component.scss +290 -0
- package/vg/apps/ng-app/src/app/dashboard/dashboard.component.ts +236 -0
- package/vg/apps/ng-app/src/app/nx-welcome.ts +872 -0
- package/vg/apps/ng-app/src/app/services/api.service.ts +28 -0
- package/vg/apps/ng-app/src/index.html +13 -0
- package/vg/apps/ng-app/src/main.ts +5 -0
- package/vg/apps/ng-app/src/styles.scss +1 -0
- package/vg/apps/ng-app/src/test-setup.ts +6 -0
- package/vg/jest.config.ts +6 -0
- package/vg/nx.json +85 -0
- package/vg/package-lock.json +30707 -0
- package/vg/package.json +75 -0
- package/vg/packages/client/data-access/README.md +7 -0
- package/vg/packages/client/data-access/jest.config.ts +21 -0
- package/vg/packages/client/data-access/project.json +21 -0
- package/vg/packages/client/data-access/src/index.ts +1 -0
- package/vg/packages/client/data-access/src/lib/data-access/data-access.html +1 -0
- package/vg/packages/client/data-access/src/lib/data-access/data-access.scss +0 -0
- package/vg/packages/client/data-access/src/lib/data-access/data-access.ts +9 -0
- package/vg/packages/client/data-access/src/test-setup.ts +6 -0
- package/vg/packages/core/README.md +11 -0
- package/vg/packages/core/jest.config.ts +10 -0
- package/vg/packages/core/package.json +11 -0
- package/vg/packages/core/project.json +26 -0
- package/vg/packages/core/src/index.ts +6 -0
- package/vg/packages/core/src/lib/core.ts +3 -0
- package/vg/packages/core/src/lib/detectors/project-detector.ts +343 -0
- package/vg/packages/core/src/lib/ignore/ignore-manager.ts +315 -0
- package/vg/packages/core/src/lib/scanner/file-scanner.ts +675 -0
- package/vg/packages/core/src/lib/tokenizer/token-manager.ts +435 -0
- package/vg/packages/core/src/lib/utils/bash-executor.ts +146 -0
- package/vg/packages/shared/data-types/README.md +11 -0
- package/vg/packages/shared/data-types/jest.config.ts +10 -0
- package/vg/packages/shared/data-types/package.json +11 -0
- package/vg/packages/shared/data-types/project.json +26 -0
- package/vg/packages/shared/data-types/src/index.ts +1 -0
- package/vg/packages/shared/data-types/src/lib/data-types.ts +3 -0
- package/vg/start-dev.sh +22 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Controller, Get } from '@nestjs/common';
|
|
2
|
+
import { AppService } from './app.service';
|
|
3
|
+
|
|
4
|
+
@Controller()
|
|
5
|
+
export class AppController {
|
|
6
|
+
constructor(private readonly appService: AppService) {}
|
|
7
|
+
|
|
8
|
+
@Get()
|
|
9
|
+
getData() {
|
|
10
|
+
return this.appService.getData();
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Module } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
import { AppController } from './app.controller';
|
|
4
|
+
import { AppService } from './app.service';
|
|
5
|
+
import { AnalyzeController } from './analyze.controller';
|
|
6
|
+
import { AnalyzeService } from './analyze.service';
|
|
7
|
+
import { ExecuteController } from './execute.controller';
|
|
8
|
+
import { ExecuteService } from './execute.service';
|
|
9
|
+
import { InfoController } from './info.controller';
|
|
10
|
+
import { InfoService } from './info.service';
|
|
11
|
+
import { CleanController } from './clean.controller';
|
|
12
|
+
|
|
13
|
+
@Module({
|
|
14
|
+
imports: [],
|
|
15
|
+
controllers: [
|
|
16
|
+
AppController,
|
|
17
|
+
AnalyzeController,
|
|
18
|
+
ExecuteController,
|
|
19
|
+
InfoController,
|
|
20
|
+
CleanController
|
|
21
|
+
],
|
|
22
|
+
providers: [
|
|
23
|
+
AppService,
|
|
24
|
+
AnalyzeService,
|
|
25
|
+
ExecuteService,
|
|
26
|
+
InfoService
|
|
27
|
+
],
|
|
28
|
+
})
|
|
29
|
+
export class AppModule { }
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Controller, Delete, Body, BadRequestException, InternalServerErrorException, Logger } from '@nestjs/common';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as fs from 'fs-extra';
|
|
4
|
+
|
|
5
|
+
@Controller('clean')
|
|
6
|
+
export class CleanController {
|
|
7
|
+
private readonly logger = new Logger(CleanController.name);
|
|
8
|
+
|
|
9
|
+
@Delete()
|
|
10
|
+
async clean(@Body() body: { output: string }) {
|
|
11
|
+
try {
|
|
12
|
+
if (!body.output) {
|
|
13
|
+
throw new BadRequestException('Missing required field: output');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const outputPath = path.resolve(body.output);
|
|
17
|
+
|
|
18
|
+
if (await fs.pathExists(outputPath)) {
|
|
19
|
+
await fs.remove(outputPath);
|
|
20
|
+
this.logger.log(`✓ Cleaned: ${outputPath}`);
|
|
21
|
+
return {
|
|
22
|
+
success: true,
|
|
23
|
+
message: `Cleaned: ${outputPath}`
|
|
24
|
+
};
|
|
25
|
+
} else {
|
|
26
|
+
return {
|
|
27
|
+
success: true,
|
|
28
|
+
message: 'Output directory does not exist'
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
} catch (error: any) {
|
|
33
|
+
this.logger.error('Error cleaning:', error);
|
|
34
|
+
if (error instanceof BadRequestException) {
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
throw new InternalServerErrorException(error.message || 'Failed to clean');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Controller, Post, Body, Res, HttpStatus } from '@nestjs/common';
|
|
2
|
+
import { Response } from 'express';
|
|
3
|
+
import { ExecuteService } from './execute.service';
|
|
4
|
+
|
|
5
|
+
@Controller('execute')
|
|
6
|
+
export class ExecuteController {
|
|
7
|
+
constructor(private readonly executeService: ExecuteService) { }
|
|
8
|
+
|
|
9
|
+
@Post()
|
|
10
|
+
async execute(@Body() body: { bash: string }, @Res() res: Response) {
|
|
11
|
+
const result = await this.executeService.executeScript(body.bash);
|
|
12
|
+
|
|
13
|
+
if (result.success) {
|
|
14
|
+
res.status(HttpStatus.OK).json(result);
|
|
15
|
+
} else {
|
|
16
|
+
res.status(HttpStatus.BAD_REQUEST).json(result);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Injectable, BadRequestException, InternalServerErrorException, Logger } from '@nestjs/common';
|
|
2
|
+
import { BashExecutor } from '@vg/core';
|
|
3
|
+
|
|
4
|
+
@Injectable()
|
|
5
|
+
export class ExecuteService {
|
|
6
|
+
private readonly logger = new Logger(ExecuteService.name);
|
|
7
|
+
private workingDir = process.cwd();
|
|
8
|
+
|
|
9
|
+
async executeScript(bash: string) {
|
|
10
|
+
try {
|
|
11
|
+
if (!bash) {
|
|
12
|
+
throw new BadRequestException('Missing required field: bash');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
this.logger.log(`Executing bash script (${bash.length} chars)...`);
|
|
16
|
+
|
|
17
|
+
// Create executor with working directory
|
|
18
|
+
const executor = new BashExecutor(this.workingDir);
|
|
19
|
+
|
|
20
|
+
// Execute script (validates syntax first, then executes)
|
|
21
|
+
const result = await executor.execute(bash);
|
|
22
|
+
|
|
23
|
+
if (result.success) {
|
|
24
|
+
this.logger.log(`✓ Bash execution completed in ${result.executionTime}ms`);
|
|
25
|
+
return result;
|
|
26
|
+
} else {
|
|
27
|
+
// Check if it's a syntax error
|
|
28
|
+
const isSyntaxError = result.syntaxError;
|
|
29
|
+
this.logger.error(`✗ Bash execution failed: ${result.error || 'Exit code ' + result.exitCode}`);
|
|
30
|
+
|
|
31
|
+
// Return result even if failed, controller will handle status
|
|
32
|
+
return {
|
|
33
|
+
...result,
|
|
34
|
+
syntaxError: isSyntaxError
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
} catch (error: any) {
|
|
39
|
+
this.logger.error('Error executing bash:', error);
|
|
40
|
+
if (error instanceof BadRequestException) {
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
throw new InternalServerErrorException(error.message || 'Execution failed');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Controller, Get, Query } from '@nestjs/common';
|
|
2
|
+
import { InfoService } from './info.service';
|
|
3
|
+
|
|
4
|
+
@Controller('info')
|
|
5
|
+
export class InfoController {
|
|
6
|
+
constructor(private readonly infoService: InfoService) { }
|
|
7
|
+
|
|
8
|
+
@Get()
|
|
9
|
+
async getInfo(@Query('path') path: string) {
|
|
10
|
+
return this.infoService.getProjectInfo(path);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Injectable, BadRequestException, NotFoundException, InternalServerErrorException, Logger } from '@nestjs/common';
|
|
2
|
+
import { ProjectDetector, FileScanner, TokenManager } from '@vg/core';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import * as fs from 'fs-extra';
|
|
5
|
+
|
|
6
|
+
@Injectable()
|
|
7
|
+
export class InfoService {
|
|
8
|
+
private readonly logger = new Logger(InfoService.name);
|
|
9
|
+
|
|
10
|
+
async getProjectInfo(projectPath: string) {
|
|
11
|
+
try {
|
|
12
|
+
if (!projectPath) {
|
|
13
|
+
throw new BadRequestException('Missing required query parameter: path');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const resolvedPath = path.resolve(projectPath);
|
|
17
|
+
|
|
18
|
+
if (!await fs.pathExists(resolvedPath)) {
|
|
19
|
+
throw new NotFoundException(`Project path does not exist: ${projectPath}`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Detect project
|
|
23
|
+
const detector = new ProjectDetector(resolvedPath);
|
|
24
|
+
const projectInfo = await detector.detectAll();
|
|
25
|
+
|
|
26
|
+
// Quick scan
|
|
27
|
+
const scanner = new FileScanner(resolvedPath);
|
|
28
|
+
const scanResult = await scanner.scanProject();
|
|
29
|
+
|
|
30
|
+
// Token analysis
|
|
31
|
+
const tokenManager = new TokenManager();
|
|
32
|
+
const tokenAnalysis = tokenManager.analyzeFiles(scanResult.files);
|
|
33
|
+
tokenManager.cleanup();
|
|
34
|
+
|
|
35
|
+
const extensions = [...new Set(scanResult.files.map(f => f.extension))].filter(Boolean);
|
|
36
|
+
|
|
37
|
+
this.logger.log(`✓ Info retrieved for: ${resolvedPath}`);
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
path: resolvedPath,
|
|
41
|
+
primaryType: projectInfo.primary,
|
|
42
|
+
detectedTechnologies: projectInfo.detected,
|
|
43
|
+
stats: {
|
|
44
|
+
totalFiles: scanResult.stats.processedFiles,
|
|
45
|
+
totalSize: scanResult.files.reduce((sum, f) => sum + f.size, 0),
|
|
46
|
+
totalLines: scanResult.files.reduce((sum, f) => sum + f.lines, 0),
|
|
47
|
+
extensions: extensions
|
|
48
|
+
},
|
|
49
|
+
tokens: {
|
|
50
|
+
total: tokenAnalysis.summary.totalTokens,
|
|
51
|
+
averagePerFile: tokenAnalysis.summary.averageTokensPerFile,
|
|
52
|
+
filesExceedingLimit: tokenAnalysis.summary.filesExceedingLimit,
|
|
53
|
+
estimatedChunks: tokenAnalysis.summary.estimatedChunks
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
} catch (error: any) {
|
|
58
|
+
this.logger.error('Error getting info:', error);
|
|
59
|
+
if (error instanceof BadRequestException || error instanceof NotFoundException) {
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
throw new InternalServerErrorException(error.message || 'Failed to get project info');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This is not a production server yet!
|
|
3
|
+
* This is only a minimal backend to get started.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Logger } from '@nestjs/common';
|
|
7
|
+
import { NestFactory } from '@nestjs/core';
|
|
8
|
+
import { AppModule } from './app/app.module';
|
|
9
|
+
|
|
10
|
+
async function bootstrap() {
|
|
11
|
+
const app = await NestFactory.create(AppModule);
|
|
12
|
+
|
|
13
|
+
// Enable CORS
|
|
14
|
+
app.enableCors({
|
|
15
|
+
origin: ['http://localhost:4200'],
|
|
16
|
+
credentials: true,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const globalPrefix = 'api';
|
|
20
|
+
app.setGlobalPrefix(globalPrefix);
|
|
21
|
+
const port = process.env.PORT || 3000;
|
|
22
|
+
await app.listen(port);
|
|
23
|
+
Logger.log(
|
|
24
|
+
`🚀 Application is running on: http://localhost:${port}/${globalPrefix}`
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
bootstrap();
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
|
|
2
|
+
const { join } = require('path');
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
output: {
|
|
6
|
+
path: join(__dirname, '../../dist/apps/api'),
|
|
7
|
+
clean: true,
|
|
8
|
+
...(process.env.NODE_ENV !== 'production' && {
|
|
9
|
+
devtoolModuleFilenameTemplate: '[absolute-resource-path]',
|
|
10
|
+
}),
|
|
11
|
+
},
|
|
12
|
+
plugins: [
|
|
13
|
+
new NxAppWebpackPlugin({
|
|
14
|
+
target: 'node',
|
|
15
|
+
compiler: 'tsc',
|
|
16
|
+
main: './src/main.ts',
|
|
17
|
+
tsConfig: './tsconfig.app.json',
|
|
18
|
+
assets: ['./src/assets'],
|
|
19
|
+
optimization: false,
|
|
20
|
+
outputHashing: 'none',
|
|
21
|
+
generatePackageJson: true,
|
|
22
|
+
sourceMaps: true,
|
|
23
|
+
}),
|
|
24
|
+
],
|
|
25
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
displayName: 'api-e2e',
|
|
3
|
+
preset: '../../jest.preset.js',
|
|
4
|
+
globalSetup: '<rootDir>/src/support/global-setup.ts',
|
|
5
|
+
globalTeardown: '<rootDir>/src/support/global-teardown.ts',
|
|
6
|
+
setupFiles: ['<rootDir>/src/support/test-setup.ts'],
|
|
7
|
+
testEnvironment: 'node',
|
|
8
|
+
transform: {
|
|
9
|
+
'^.+\\.[tj]s$': [
|
|
10
|
+
'ts-jest',
|
|
11
|
+
{
|
|
12
|
+
tsconfig: '<rootDir>/tsconfig.spec.json',
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
},
|
|
16
|
+
moduleFileExtensions: ['ts', 'js', 'html'],
|
|
17
|
+
coverageDirectory: '../../coverage/api-e2e',
|
|
18
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "api-e2e",
|
|
3
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
+
"implicitDependencies": ["api"],
|
|
5
|
+
"projectType": "application",
|
|
6
|
+
"targets": {
|
|
7
|
+
"e2e": {
|
|
8
|
+
"executor": "@nx/jest:jest",
|
|
9
|
+
"outputs": ["{workspaceRoot}/coverage/{e2eProjectRoot}"],
|
|
10
|
+
"options": {
|
|
11
|
+
"jestConfig": "apps/api-e2e/jest.config.cts",
|
|
12
|
+
"passWithNoTests": true
|
|
13
|
+
},
|
|
14
|
+
"dependsOn": ["api:build", "api:serve"]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { waitForPortOpen } from '@nx/node/utils';
|
|
2
|
+
|
|
3
|
+
/* eslint-disable */
|
|
4
|
+
var __TEARDOWN_MESSAGE__: string;
|
|
5
|
+
|
|
6
|
+
module.exports = async function () {
|
|
7
|
+
// Start services that that the app needs to run (e.g. database, docker-compose, etc.).
|
|
8
|
+
console.log('\nSetting up...\n');
|
|
9
|
+
|
|
10
|
+
const host = process.env.HOST ?? 'localhost';
|
|
11
|
+
const port = process.env.PORT ? Number(process.env.PORT) : 3000;
|
|
12
|
+
await waitForPortOpen(port, { host });
|
|
13
|
+
|
|
14
|
+
// Hint: Use `globalThis` to pass variables to global teardown.
|
|
15
|
+
globalThis.__TEARDOWN_MESSAGE__ = '\nTearing down...\n';
|
|
16
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { killPort } from '@nx/node/utils';
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
module.exports = async function () {
|
|
5
|
+
// Put clean up logic here (e.g. stopping services, docker-compose, etc.).
|
|
6
|
+
// Hint: `globalThis` is shared between setup and teardown.
|
|
7
|
+
const port = process.env.PORT ? Number(process.env.PORT) : 3000;
|
|
8
|
+
await killPort(port);
|
|
9
|
+
console.log(globalThis.__TEARDOWN_MESSAGE__);
|
|
10
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
|
|
4
|
+
module.exports = async function () {
|
|
5
|
+
// Configure axios for tests to use.
|
|
6
|
+
const host = process.env.HOST ?? 'localhost';
|
|
7
|
+
const port = process.env.PORT ?? '3000';
|
|
8
|
+
axios.defaults.baseURL = `http://${host}:${port}`;
|
|
9
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
displayName: 'ng-app',
|
|
3
|
+
preset: '../../jest.preset.js',
|
|
4
|
+
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
|
|
5
|
+
coverageDirectory: '../../coverage/apps/ng-app',
|
|
6
|
+
transform: {
|
|
7
|
+
'^.+\\.(ts|mjs|js|html)$': [
|
|
8
|
+
'jest-preset-angular',
|
|
9
|
+
{
|
|
10
|
+
tsconfig: '<rootDir>/tsconfig.spec.json',
|
|
11
|
+
stringifyContentPathRegex: '\\.(html|svg)$',
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
},
|
|
15
|
+
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
|
|
16
|
+
snapshotSerializers: [
|
|
17
|
+
'jest-preset-angular/build/serializers/no-ng-attributes',
|
|
18
|
+
'jest-preset-angular/build/serializers/ng-snapshot',
|
|
19
|
+
'jest-preset-angular/build/serializers/html-comment',
|
|
20
|
+
],
|
|
21
|
+
};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ng-app",
|
|
3
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
+
"projectType": "application",
|
|
5
|
+
"prefix": "app",
|
|
6
|
+
"sourceRoot": "apps/ng-app/src",
|
|
7
|
+
"tags": [
|
|
8
|
+
"scope:client",
|
|
9
|
+
"type:app"
|
|
10
|
+
],
|
|
11
|
+
"targets": {
|
|
12
|
+
"build": {
|
|
13
|
+
"executor": "@angular/build:application",
|
|
14
|
+
"outputs": [
|
|
15
|
+
"{options.outputPath}"
|
|
16
|
+
],
|
|
17
|
+
"options": {
|
|
18
|
+
"outputPath": "dist/apps/ng-app",
|
|
19
|
+
"browser": "apps/ng-app/src/main.ts",
|
|
20
|
+
"polyfills": [
|
|
21
|
+
"zone.js"
|
|
22
|
+
],
|
|
23
|
+
"tsConfig": "apps/ng-app/tsconfig.app.json",
|
|
24
|
+
"inlineStyleLanguage": "scss",
|
|
25
|
+
"assets": [
|
|
26
|
+
{
|
|
27
|
+
"glob": "**/*",
|
|
28
|
+
"input": "apps/ng-app/public"
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"styles": [
|
|
32
|
+
"apps/ng-app/src/styles.scss"
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
"configurations": {
|
|
36
|
+
"production": {
|
|
37
|
+
"budgets": [
|
|
38
|
+
{
|
|
39
|
+
"type": "initial",
|
|
40
|
+
"maximumWarning": "500kb",
|
|
41
|
+
"maximumError": "1mb"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"type": "anyComponentStyle",
|
|
45
|
+
"maximumWarning": "4kb",
|
|
46
|
+
"maximumError": "8kb"
|
|
47
|
+
}
|
|
48
|
+
],
|
|
49
|
+
"outputHashing": "all"
|
|
50
|
+
},
|
|
51
|
+
"development": {
|
|
52
|
+
"optimization": false,
|
|
53
|
+
"extractLicenses": false,
|
|
54
|
+
"sourceMap": true
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"defaultConfiguration": "production"
|
|
58
|
+
},
|
|
59
|
+
"serve": {
|
|
60
|
+
"continuous": true,
|
|
61
|
+
"executor": "@angular/build:dev-server",
|
|
62
|
+
"options": {
|
|
63
|
+
"proxyConfig": "apps/ng-app/proxy.conf.json"
|
|
64
|
+
},
|
|
65
|
+
"configurations": {
|
|
66
|
+
"production": {
|
|
67
|
+
"buildTarget": "ng-app:build:production"
|
|
68
|
+
},
|
|
69
|
+
"development": {
|
|
70
|
+
"buildTarget": "ng-app:build:development"
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"defaultConfiguration": "development",
|
|
74
|
+
"dependsOn": [
|
|
75
|
+
{
|
|
76
|
+
"target": "serve",
|
|
77
|
+
"projects": "api"
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
"extract-i18n": {
|
|
82
|
+
"executor": "@angular/build:extract-i18n",
|
|
83
|
+
"options": {
|
|
84
|
+
"buildTarget": "ng-app:build"
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"lint": {
|
|
88
|
+
"executor": "@nx/eslint:lint"
|
|
89
|
+
},
|
|
90
|
+
"test": {
|
|
91
|
+
"executor": "@nx/jest:jest",
|
|
92
|
+
"outputs": [
|
|
93
|
+
"{workspaceRoot}/coverage/{projectRoot}"
|
|
94
|
+
],
|
|
95
|
+
"options": {
|
|
96
|
+
"jestConfig": "apps/ng-app/jest.config.ts",
|
|
97
|
+
"tsConfig": "apps/ng-app/tsconfig.spec.json"
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
"serve-static": {
|
|
101
|
+
"continuous": true,
|
|
102
|
+
"executor": "@nx/web:file-server",
|
|
103
|
+
"options": {
|
|
104
|
+
"buildTarget": "ng-app:build",
|
|
105
|
+
"staticFilePath": "dist/apps/ng-app/browser",
|
|
106
|
+
"spa": true
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ApplicationConfig,
|
|
3
|
+
provideBrowserGlobalErrorListeners,
|
|
4
|
+
provideZoneChangeDetection,
|
|
5
|
+
} from '@angular/core';
|
|
6
|
+
import { provideRouter } from '@angular/router';
|
|
7
|
+
import { provideHttpClient } from '@angular/common/http';
|
|
8
|
+
import { appRoutes } from './app.routes';
|
|
9
|
+
|
|
10
|
+
export const appConfig: ApplicationConfig = {
|
|
11
|
+
providers: [
|
|
12
|
+
provideBrowserGlobalErrorListeners(),
|
|
13
|
+
provideZoneChangeDetection({ eventCoalescing: true }),
|
|
14
|
+
provideRouter(appRoutes),
|
|
15
|
+
provideHttpClient(),
|
|
16
|
+
],
|
|
17
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<router-outlet></router-outlet>
|
|
File without changes
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { RouterModule } from '@angular/router';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
imports: [RouterModule],
|
|
6
|
+
selector: 'app-root',
|
|
7
|
+
templateUrl: './app.html',
|
|
8
|
+
styleUrl: './app.scss',
|
|
9
|
+
})
|
|
10
|
+
export class App {
|
|
11
|
+
protected title = 'ng-app';
|
|
12
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<div class="container">
|
|
2
|
+
<div class="header">
|
|
3
|
+
<h1>🚀 VG Coder API Dashboard</h1>
|
|
4
|
+
<p>Phân tích dự án và thực thi bash scripts</p>
|
|
5
|
+
<span class="status" id="status">● Server Running</span>
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
<!-- System Prompt Section -->
|
|
9
|
+
<div class="system-prompt-card">
|
|
10
|
+
<div class="system-prompt-header" (click)="toggleSystemPrompt()">
|
|
11
|
+
<h2>
|
|
12
|
+
<span>📝</span>
|
|
13
|
+
<span>AI System Prompt</span>
|
|
14
|
+
</h2>
|
|
15
|
+
<span class="toggle-icon" [class.open]="isPromptOpen">▼</span>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="system-prompt-content" [class.open]="isPromptOpen">
|
|
18
|
+
<div class="prompt-text">{{ systemPrompt }}</div>
|
|
19
|
+
<button class="btn btn-copy" (click)="copySystemPrompt()">
|
|
20
|
+
<span>📋</span>
|
|
21
|
+
<span>Copy System Prompt</span>
|
|
22
|
+
</button>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<div class="endpoints">
|
|
27
|
+
<!-- Analyze -->
|
|
28
|
+
<div class="endpoint-card">
|
|
29
|
+
<div class="endpoint-header">
|
|
30
|
+
<span class="method post">POST</span>
|
|
31
|
+
<span class="endpoint-path">/api/analyze</span>
|
|
32
|
+
</div>
|
|
33
|
+
<p class="endpoint-desc">📊 Phân tích dự án và lấy toàn bộ source code</p>
|
|
34
|
+
<div class="form-group">
|
|
35
|
+
<label>📁 Project Path:</label>
|
|
36
|
+
<input type="text" [(ngModel)]="analyzePath" placeholder=".">
|
|
37
|
+
</div>
|
|
38
|
+
<div class="btn-group">
|
|
39
|
+
<button class="btn" (click)="analyze()" [disabled]="analyzeLoading">
|
|
40
|
+
<span *ngIf="!analyzeLoading">📥</span>
|
|
41
|
+
<span *ngIf="analyzeLoading" class="loading"></span>
|
|
42
|
+
<span>{{ analyzeLoading ? 'Loading...' : 'Download File' }}</span>
|
|
43
|
+
</button>
|
|
44
|
+
<button class="btn btn-copy" (click)="copyAnalyzeResult()">
|
|
45
|
+
<span>📋</span>
|
|
46
|
+
<span>Copy to Clipboard</span>
|
|
47
|
+
</button>
|
|
48
|
+
</div>
|
|
49
|
+
<div class="response" *ngIf="analyzeResult" [class.success]="true">
|
|
50
|
+
<pre>{{ analyzeResult | slice:0:500 }}...</pre>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<!-- Execute Bash -->
|
|
55
|
+
<div class="endpoint-card">
|
|
56
|
+
<div class="endpoint-header">
|
|
57
|
+
<span class="method post">POST</span>
|
|
58
|
+
<span class="endpoint-path">/api/execute</span>
|
|
59
|
+
</div>
|
|
60
|
+
<p class="endpoint-desc">⚡ Thực thi bash script với syntax validation</p>
|
|
61
|
+
<div class="form-group">
|
|
62
|
+
<label>💻 Bash Script:</label>
|
|
63
|
+
<textarea [(ngModel)]="bashScript"
|
|
64
|
+
placeholder="mkdir -p $(dirname "src/test.js") cat <<'EOF' > src/test.js console.log('Hello World'); EOF"></textarea>
|
|
65
|
+
</div>
|
|
66
|
+
<div class="btn-group">
|
|
67
|
+
<button class="btn" (click)="execute()" [disabled]="executeLoading">
|
|
68
|
+
<span *ngIf="!executeLoading">▶️</span>
|
|
69
|
+
<span *ngIf="executeLoading" class="loading"></span>
|
|
70
|
+
<span>{{ executeLoading ? 'Executing...' : 'Execute Script' }}</span>
|
|
71
|
+
</button>
|
|
72
|
+
<button class="btn" (click)="executeFromClipboard()" [disabled]="executeLoading">
|
|
73
|
+
<span>📋</span>
|
|
74
|
+
<span>Execute from Clipboard</span>
|
|
75
|
+
</button>
|
|
76
|
+
</div>
|
|
77
|
+
<div class="response" *ngIf="executeResult" [class.success]="executeResult.success"
|
|
78
|
+
[class.error]="!executeResult.success">
|
|
79
|
+
<pre>{{ executeResult | json }}</pre>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<div class="toast" [class.show]="showToast" [ngClass]="toastType">
|
|
86
|
+
{{ toastMessage }}
|
|
87
|
+
</div>
|