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.
Files changed (78) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/PUBLISHING.md +86 -0
  3. package/README.md +92 -318
  4. package/SYSTEM_PROMPT.md +157 -0
  5. package/init-nx-monorepo.sh +107 -0
  6. package/package.json +11 -4
  7. package/src/server/api-server.js +6 -1
  8. package/src/server/views/dashboard.html +69 -4
  9. package/vg/.vscode/extensions.json +8 -0
  10. package/vg/.vscode/launch.json +23 -0
  11. package/vg/README.md +85 -0
  12. package/vg/apps/api/project.json +83 -0
  13. package/vg/apps/api/src/app/analyze.controller.ts +17 -0
  14. package/vg/apps/api/src/app/analyze.service.ts +57 -0
  15. package/vg/apps/api/src/app/app.controller.ts +12 -0
  16. package/vg/apps/api/src/app/app.module.ts +29 -0
  17. package/vg/apps/api/src/app/app.service.ts +8 -0
  18. package/vg/apps/api/src/app/clean.controller.ts +40 -0
  19. package/vg/apps/api/src/app/execute.controller.ts +19 -0
  20. package/vg/apps/api/src/app/execute.service.ts +46 -0
  21. package/vg/apps/api/src/app/info.controller.ts +12 -0
  22. package/vg/apps/api/src/app/info.service.ts +65 -0
  23. package/vg/apps/api/src/assets/.gitkeep +0 -0
  24. package/vg/apps/api/src/main.ts +28 -0
  25. package/vg/apps/api/webpack.config.js +25 -0
  26. package/vg/apps/api-e2e/jest.config.cts +18 -0
  27. package/vg/apps/api-e2e/project.json +17 -0
  28. package/vg/apps/api-e2e/src/support/global-setup.ts +16 -0
  29. package/vg/apps/api-e2e/src/support/global-teardown.ts +10 -0
  30. package/vg/apps/api-e2e/src/support/test-setup.ts +9 -0
  31. package/vg/apps/ng-app/jest.config.ts +21 -0
  32. package/vg/apps/ng-app/project.json +110 -0
  33. package/vg/apps/ng-app/proxy.conf.json +8 -0
  34. package/vg/apps/ng-app/public/favicon.ico +0 -0
  35. package/vg/apps/ng-app/src/app/app.config.ts +17 -0
  36. package/vg/apps/ng-app/src/app/app.html +1 -0
  37. package/vg/apps/ng-app/src/app/app.routes.ts +7 -0
  38. package/vg/apps/ng-app/src/app/app.scss +0 -0
  39. package/vg/apps/ng-app/src/app/app.ts +12 -0
  40. package/vg/apps/ng-app/src/app/dashboard/dashboard.component.html +87 -0
  41. package/vg/apps/ng-app/src/app/dashboard/dashboard.component.scss +290 -0
  42. package/vg/apps/ng-app/src/app/dashboard/dashboard.component.ts +236 -0
  43. package/vg/apps/ng-app/src/app/nx-welcome.ts +872 -0
  44. package/vg/apps/ng-app/src/app/services/api.service.ts +28 -0
  45. package/vg/apps/ng-app/src/index.html +13 -0
  46. package/vg/apps/ng-app/src/main.ts +5 -0
  47. package/vg/apps/ng-app/src/styles.scss +1 -0
  48. package/vg/apps/ng-app/src/test-setup.ts +6 -0
  49. package/vg/jest.config.ts +6 -0
  50. package/vg/nx.json +85 -0
  51. package/vg/package-lock.json +30707 -0
  52. package/vg/package.json +75 -0
  53. package/vg/packages/client/data-access/README.md +7 -0
  54. package/vg/packages/client/data-access/jest.config.ts +21 -0
  55. package/vg/packages/client/data-access/project.json +21 -0
  56. package/vg/packages/client/data-access/src/index.ts +1 -0
  57. package/vg/packages/client/data-access/src/lib/data-access/data-access.html +1 -0
  58. package/vg/packages/client/data-access/src/lib/data-access/data-access.scss +0 -0
  59. package/vg/packages/client/data-access/src/lib/data-access/data-access.ts +9 -0
  60. package/vg/packages/client/data-access/src/test-setup.ts +6 -0
  61. package/vg/packages/core/README.md +11 -0
  62. package/vg/packages/core/jest.config.ts +10 -0
  63. package/vg/packages/core/package.json +11 -0
  64. package/vg/packages/core/project.json +26 -0
  65. package/vg/packages/core/src/index.ts +6 -0
  66. package/vg/packages/core/src/lib/core.ts +3 -0
  67. package/vg/packages/core/src/lib/detectors/project-detector.ts +343 -0
  68. package/vg/packages/core/src/lib/ignore/ignore-manager.ts +315 -0
  69. package/vg/packages/core/src/lib/scanner/file-scanner.ts +675 -0
  70. package/vg/packages/core/src/lib/tokenizer/token-manager.ts +435 -0
  71. package/vg/packages/core/src/lib/utils/bash-executor.ts +146 -0
  72. package/vg/packages/shared/data-types/README.md +11 -0
  73. package/vg/packages/shared/data-types/jest.config.ts +10 -0
  74. package/vg/packages/shared/data-types/package.json +11 -0
  75. package/vg/packages/shared/data-types/project.json +26 -0
  76. package/vg/packages/shared/data-types/src/index.ts +1 -0
  77. package/vg/packages/shared/data-types/src/lib/data-types.ts +3 -0
  78. 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,8 @@
1
+ import { Injectable } from '@nestjs/common';
2
+
3
+ @Injectable()
4
+ export class AppService {
5
+ getData(): { message: string } {
6
+ return { message: 'Hello API' };
7
+ }
8
+ }
@@ -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
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "/api": {
3
+ "target": "http://localhost:3000",
4
+ "secure": false,
5
+ "logLevel": "debug",
6
+ "changeOrigin": true
7
+ }
8
+ }
@@ -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>
@@ -0,0 +1,7 @@
1
+ import { Route } from '@angular/router';
2
+ import { DashboardComponent } from './dashboard/dashboard.component';
3
+
4
+ export const appRoutes: Route[] = [
5
+ { path: '', component: DashboardComponent },
6
+ { path: '**', redirectTo: '' }
7
+ ];
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 &quot;src/test.js&quot;)&#10;cat <<'EOF' > src/test.js&#10;console.log('Hello World');&#10;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>