valence-cli 1.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.
Potentially problematic release.
This version of valence-cli might be problematic. Click here for more details.
- package/README.md +98 -0
- package/bin/valence.js +2 -0
- package/dist/commands/build.d.ts +5 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +79 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +44 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/generate.d.ts +2 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +110 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/lifecycle.d.ts +3 -0
- package/dist/commands/lifecycle.d.ts.map +1 -0
- package/dist/commands/lifecycle.js +23 -0
- package/dist/commands/lifecycle.js.map +1 -0
- package/dist/commands/publish.d.ts +2 -0
- package/dist/commands/publish.d.ts.map +1 -0
- package/dist/commands/publish.js +100 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +476 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/logger.d.ts +10 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +58 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Valence CLI
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="https://img.shields.io/badge/Angular-DD0031?style=for-the-badge&logo=angular&logoColor=white" alt="Angular" />
|
|
5
|
+
<img src="https://img.shields.io/badge/Electron-47848F?style=for-the-badge&logo=electron&logoColor=white" alt="Electron" />
|
|
6
|
+
<img src="https://img.shields.io/badge/Babylon.js-BBBBBB?style=for-the-badge&logo=babylondotjs&logoColor=white" alt="Babylon.js" />
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
> **The ultimate scaffolding tool for hybrid 3D applications.**
|
|
10
|
+
|
|
11
|
+
**Valence CLI** automates the creation and management of high-performance desktop applications using **Angular**, **Electron**, and **Babylon.js**. It provides a robust, pre-configured environment with TypeScript support, build orchestration, and "production-ready" defaults.
|
|
12
|
+
|
|
13
|
+
## 🚀 Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g valence-cli
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## ✨ Quick Start
|
|
20
|
+
|
|
21
|
+
Create a new project with the **Valence Identity** template (includes 3D scene, SVG logo, and debug HUD):
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
valence new my-game
|
|
25
|
+
cd my-game
|
|
26
|
+
valence start
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 🛠Commands
|
|
30
|
+
|
|
31
|
+
### `valence new <name>`
|
|
32
|
+
Scaffolds a new project with:
|
|
33
|
+
- **Angular**: Latest CLI, SCSS, Routing.
|
|
34
|
+
- **Electron**: TypeScript Main/Preload processes, securely configured.
|
|
35
|
+
- **Babylon.js**: Core dependencies pre-installed.
|
|
36
|
+
- **Forge**: configured for building `.exe` / `.zip` / installers.
|
|
37
|
+
- **Template**: Includes a rotating plane, FPS counter, and camera position tracker.
|
|
38
|
+
|
|
39
|
+
### `valence start`
|
|
40
|
+
Runs the application in **Development Mode**:
|
|
41
|
+
- Cleans previous builds.
|
|
42
|
+
- Builds Angular (Dev config).
|
|
43
|
+
- Compiles Electron (TypeScript).
|
|
44
|
+
- Launches Electron window with live reload enabled.
|
|
45
|
+
|
|
46
|
+
### `valence build`
|
|
47
|
+
Compiles the application for **Production**:
|
|
48
|
+
- Outputs to `dist/browser` (Angular) and `dist/electron` (Main Process).
|
|
49
|
+
- Optimizes assets.
|
|
50
|
+
- Enforces relative paths (`baseHref="./"`) for Electron compatibility.
|
|
51
|
+
|
|
52
|
+
### `valence package`
|
|
53
|
+
Packages the application for distribution:
|
|
54
|
+
- Runs `valence build`.
|
|
55
|
+
- Executes **Electron Forge** to generate installers (e.g., Windows Squirrel.exe, Zip).
|
|
56
|
+
- Artifacts saved to `out/`.
|
|
57
|
+
|
|
58
|
+
### `valence publish`
|
|
59
|
+
Automates the release pipeline:
|
|
60
|
+
1. Bumps project version (patch).
|
|
61
|
+
2. Updates `README.md` version badges.
|
|
62
|
+
3. Builds & Packages.
|
|
63
|
+
4. Generates `RELEASES_README.md` entry.
|
|
64
|
+
5. Publishes via Electron Forge (e.g., to GitHub Releases).
|
|
65
|
+
|
|
66
|
+
### `valence generate scene <name>`
|
|
67
|
+
*Alias: `valence g scene <name>`*
|
|
68
|
+
Scaffolds a new **Babylon.js Scene component** in `src/app/scenes/<name>`:
|
|
69
|
+
- Pre-wired `Engine` and `Scene` creation.
|
|
70
|
+
- Includes Camera, Light, and Resize event handling.
|
|
71
|
+
- Ready for 3D logic immediately.
|
|
72
|
+
|
|
73
|
+
### `valence doctor`
|
|
74
|
+
Diagnoses your development environment:
|
|
75
|
+
- Checks Node.js & NPM versions.
|
|
76
|
+
- Verifies Git installation.
|
|
77
|
+
- Checks for global Angular CLI (optional).
|
|
78
|
+
|
|
79
|
+
## 📂 Project Structure
|
|
80
|
+
|
|
81
|
+
Valence enforces a clean, separated structure:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
my-project/
|
|
85
|
+
├── electron/
|
|
86
|
+
│ ├── main.ts # Main Process (Source)
|
|
87
|
+
│ ├── preload.ts # Preload Script (Source)
|
|
88
|
+
│ └── tsconfig.json # Electron TS Config
|
|
89
|
+
├── src/ # Angular App (Renderer)
|
|
90
|
+
├── dist/ # Build Output
|
|
91
|
+
│ ├── browser/ # Angular Compilation
|
|
92
|
+
│ └── electron/ # Electron Transpilation
|
|
93
|
+
├── forge.config.js # Packaging Config
|
|
94
|
+
└── package.json
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## License
|
|
98
|
+
MIT
|
package/bin/valence.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,KAAK,GAAU,mCAAiD;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAO,kBAiGlH,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import * as fs from 'fs-extra';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { execa } from 'execa';
|
|
5
|
+
import { runStage, execWithScrollingLogger } from '../utils/logger.js';
|
|
6
|
+
export const build = async ({ lint: shouldLint = true, dev: isDev = false } = {}) => {
|
|
7
|
+
// 1. Cleanup
|
|
8
|
+
await runStage('Package Dist Cleanup', async (spinner) => {
|
|
9
|
+
const distDir = path.join(process.cwd(), 'dist');
|
|
10
|
+
if (await fs.pathExists(distDir)) {
|
|
11
|
+
await fs.remove(distDir);
|
|
12
|
+
}
|
|
13
|
+
const cacheDir = path.join(process.cwd(), '.angular');
|
|
14
|
+
if (await fs.pathExists(cacheDir)) {
|
|
15
|
+
await fs.remove(cacheDir);
|
|
16
|
+
}
|
|
17
|
+
return chalk.bold.white('Cleanup Complete');
|
|
18
|
+
});
|
|
19
|
+
// 2. Linting
|
|
20
|
+
if (shouldLint) {
|
|
21
|
+
await runStage('Linting', async (spinner) => {
|
|
22
|
+
try {
|
|
23
|
+
// Using inherit stdio for linting to show full output
|
|
24
|
+
spinner.stop();
|
|
25
|
+
console.log(chalk.yellow('\nRunning Lint...\n'));
|
|
26
|
+
await execa('ng', ['lint'], { stdio: 'inherit' });
|
|
27
|
+
spinner.start();
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
spinner.start();
|
|
31
|
+
throw new Error('Linting failed.');
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
// 3. Components Build
|
|
36
|
+
await runStage('Preparing App Components', async (spinner) => {
|
|
37
|
+
let angularStatus = 'Waiting...';
|
|
38
|
+
let electronStatus = 'Waiting...';
|
|
39
|
+
const updateSpinner = () => {
|
|
40
|
+
spinner.text = `Preparing App Components\n ${chalk.bold.white('Angular')}: ${chalk.yellow(angularStatus)}\n ${chalk.bold.white('Electron')}: ${chalk.yellow(electronStatus)}`;
|
|
41
|
+
};
|
|
42
|
+
// Chain 1: Angular Build
|
|
43
|
+
const angularChain = async () => {
|
|
44
|
+
const config = isDev ? 'development' : 'production';
|
|
45
|
+
angularStatus = 'Building...';
|
|
46
|
+
updateSpinner();
|
|
47
|
+
// We rely on angular.json having outputPath set to 'dist/browser' by our 'new' command.
|
|
48
|
+
// If the user changed it, this might drift, but 'valence build' implies controlled structure.
|
|
49
|
+
// We can enforce --outputPath=dist/browser to be safe?
|
|
50
|
+
// Yes, forcing it ensures 'valence build' works as expected even if they messed up angular.json
|
|
51
|
+
await execWithScrollingLogger(spinner, 'ng', ['build', '--configuration', config, '--base-href', './', '--output-path', 'dist/browser'], { title: 'Building Components...', truncate: false }, (line) => {
|
|
52
|
+
angularStatus = line.length > 50 ? line.substring(0, 47) + '...' : line;
|
|
53
|
+
updateSpinner();
|
|
54
|
+
});
|
|
55
|
+
angularStatus = chalk.bold.white('Done');
|
|
56
|
+
updateSpinner();
|
|
57
|
+
};
|
|
58
|
+
// Chain 2: Electron TS
|
|
59
|
+
const electronChain = async () => {
|
|
60
|
+
electronStatus = 'Compiling TS...';
|
|
61
|
+
updateSpinner();
|
|
62
|
+
if (!fs.existsSync(path.join(process.cwd(), 'electron', 'tsconfig.json'))) {
|
|
63
|
+
throw new Error('Electron tsconfig.json not found in electron/ directory');
|
|
64
|
+
}
|
|
65
|
+
await execWithScrollingLogger(spinner, 'tsc', ['-p', 'electron/tsconfig.json'], { title: 'Compiling Electron...' }, (line) => {
|
|
66
|
+
electronStatus = line.length > 50 ? line.substring(0, 47) + '...' : line;
|
|
67
|
+
updateSpinner();
|
|
68
|
+
});
|
|
69
|
+
// No renaming needed if we just output to dist/electron via tsconfig
|
|
70
|
+
electronStatus = chalk.bold.white('Done');
|
|
71
|
+
updateSpinner();
|
|
72
|
+
};
|
|
73
|
+
// Run sequentially
|
|
74
|
+
await angularChain();
|
|
75
|
+
await electronChain();
|
|
76
|
+
return chalk.bold.white('App components built');
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAC9B,OAAO,EAAE,QAAQ,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAEvE,MAAM,CAAC,MAAM,KAAK,GAAG,KAAK,EAAE,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,KAAK,KAAwC,EAAE,EAAE,EAAE;IAErH,aAAa;IACb,MAAM,QAAQ,CAAC,sBAAsB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACvD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC;QACjD,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACjC,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,UAAU,CAAC,CAAC;QACtD,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAClC,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5B,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,aAAa;IACb,IAAI,UAAU,EAAE,CAAC;QACb,MAAM,QAAQ,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YAC1C,IAAI,CAAC;gBACD,sDAAsD;gBACtD,OAAO,CAAC,IAAI,EAAE,CAAC;gBACf,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC;gBACjD,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;gBAClD,OAAO,CAAC,KAAK,EAAE,CAAC;YACpB,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACT,OAAO,CAAC,KAAK,EAAE,CAAC;gBAChB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;YACvC,CAAC;QACH,CAAC,CAAC,CAAC;IACP,CAAC;IAED,sBAAsB;IACtB,MAAM,QAAQ,CAAC,0BAA0B,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAC3D,IAAI,aAAa,GAAG,YAAY,CAAC;QACjC,IAAI,cAAc,GAAG,YAAY,CAAC;QAElC,MAAM,aAAa,GAAG,GAAG,EAAE;YACzB,OAAO,CAAC,IAAI,GAAG,iCAAiC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC;QACtL,CAAC,CAAC;QAEF,yBAAyB;QACzB,MAAM,YAAY,GAAG,KAAK,IAAI,EAAE;YAC9B,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,YAAY,CAAC;YACpD,aAAa,GAAG,aAAa,CAAC;YAC9B,aAAa,EAAE,CAAC;YAEhB,wFAAwF;YACxF,8FAA8F;YAC9F,uDAAuD;YACvD,gGAAgG;YAEhG,MAAM,uBAAuB,CAC3B,OAAO,EACP,IAAI,EACJ,CAAC,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,eAAe,EAAE,cAAc,CAAC,EAC1F,EAAE,KAAK,EAAE,wBAAwB,EAAE,QAAQ,EAAE,KAAK,EAAE,EACpD,CAAC,IAAI,EAAE,EAAE;gBACP,aAAa,GAAG,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;gBACxE,aAAa,EAAE,CAAC;YAClB,CAAC,CACF,CAAC;YACF,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACzC,aAAa,EAAE,CAAC;QAClB,CAAC,CAAC;QAEF,uBAAuB;QACvB,MAAM,aAAa,GAAG,KAAK,IAAI,EAAE;YAC/B,cAAc,GAAG,iBAAiB,CAAC;YACnC,aAAa,EAAE,CAAC;YAEhB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC;gBACzE,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;YAC9E,CAAC;YAED,MAAM,uBAAuB,CAC3B,OAAO,EACP,KAAK,EACL,CAAC,IAAI,EAAE,wBAAwB,CAAC,EAChC,EAAE,KAAK,EAAE,uBAAuB,EAAE,EAClC,CAAC,IAAI,EAAE,EAAE;gBACP,cAAc,GAAG,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;gBACzE,aAAa,EAAE,CAAC;YAClB,CAAC,CACF,CAAC;YAEF,qEAAqE;YAErE,cAAc,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAC1C,aAAa,EAAE,CAAC;QAClB,CAAC,CAAC;QAEF,mBAAmB;QACnB,MAAM,YAAY,EAAE,CAAC;QACrB,MAAM,aAAa,EAAE,CAAC;QAEtB,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,MAAM,qBA0ClB,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { execa } from 'execa';
|
|
3
|
+
import { runStage } from '../utils/logger.js';
|
|
4
|
+
export const doctor = async () => {
|
|
5
|
+
console.log(chalk.bold.blue('Valence CLI - Doctor'));
|
|
6
|
+
console.log('Diagnosing environment...\n');
|
|
7
|
+
await runStage('Checking Node.js & NPM', async () => {
|
|
8
|
+
try {
|
|
9
|
+
const { stdout: nodeV } = await execa('node', ['-v']);
|
|
10
|
+
console.log(chalk.green(` ✓ Node.js: ${nodeV}`));
|
|
11
|
+
const { stdout: npmV } = await execa('npm', ['-v']);
|
|
12
|
+
console.log(chalk.green(` ✓ NPM: ${npmV}`));
|
|
13
|
+
return 'Node/NPM Check Passed';
|
|
14
|
+
}
|
|
15
|
+
catch (e) {
|
|
16
|
+
throw new Error('Node or NPM missing');
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
await runStage('Checking Git', async () => {
|
|
20
|
+
try {
|
|
21
|
+
const { stdout: gitV } = await execa('git', ['--version']);
|
|
22
|
+
console.log(chalk.green(` ✓ Git: ${gitV}`));
|
|
23
|
+
return 'Git Check Passed';
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
throw new Error('Git missing');
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
await runStage('Checking Global Angular CLI', async () => {
|
|
30
|
+
try {
|
|
31
|
+
// Check if 'ng' is in path
|
|
32
|
+
const { stdout } = await execa('ng', ['version']);
|
|
33
|
+
// Just basic check
|
|
34
|
+
console.log(chalk.green(` ✓ Angular CLI found globally`));
|
|
35
|
+
return 'Angular Check Passed';
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
console.warn(chalk.yellow(' ! Angular CLI not found globally (using local version via npx is fine)'));
|
|
39
|
+
return 'Global Angular CLI not found (Optional)';
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
console.log(chalk.bold.green('\nDiagnosis Complete. System looks good.'));
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAC9B,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,MAAM,CAAC,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE;IAC7B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC;IACrD,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;IAE3C,MAAM,QAAQ,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;QAChD,IAAI,CAAC;YACD,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;YACtD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,iBAAiB,KAAK,EAAE,CAAC,CAAC,CAAC;YAEnD,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;YACpD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,CAAC;YAE9C,OAAO,uBAAuB,CAAC;QACnC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;QAC3C,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,QAAQ,CAAC,cAAc,EAAE,KAAK,IAAI,EAAE;QACtC,IAAI,CAAC;YACD,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;YAC3D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,CAAC;YAC9C,OAAO,kBAAkB,CAAC;QAC9B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,aAAa,CAAC,CAAC;QACnC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,QAAQ,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;QACrD,IAAI,CAAC;YACD,2BAA2B;YAC3B,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;YAClD,mBAAmB;YACnB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC,CAAC;YAC5D,OAAO,sBAAsB,CAAC;QAClC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACT,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,2EAA2E,CAAC,CAAC,CAAC;YACxG,OAAO,yCAAyC,CAAC;QACrD,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC,CAAC;AAC9E,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,aAAa,GAAU,MAAM,MAAM,kBA+G/C,CAAC"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import * as fs from 'fs-extra';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import { execa } from 'execa';
|
|
6
|
+
export const generateScene = async (name) => {
|
|
7
|
+
// 1. Validate we are in a project
|
|
8
|
+
if (!fs.existsSync(path.join(process.cwd(), 'angular.json'))) {
|
|
9
|
+
console.error(chalk.red('Error: Not an Angular project root.'));
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
const startCase = (str) => str.replace(/-/g, ' ').replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()).replace(/\s/g, '');
|
|
13
|
+
const componentName = startCase(name) + 'Component'; // e.g. my-level -> MyLevelComponent
|
|
14
|
+
const selector = 'app-' + name.toLowerCase();
|
|
15
|
+
console.log(chalk.blue(`Generating Babylon.js scene: ${name}...`));
|
|
16
|
+
// 2. Use Angular CLI to basic scaffold (ensures registration/module updates if needed)
|
|
17
|
+
// We target a 'scenes' folder convention
|
|
18
|
+
try {
|
|
19
|
+
await execa('npx', ['ng', 'g', 'c', `scenes/${name}`, '--style', 'scss', '--skip-tests'], { stdio: 'inherit' });
|
|
20
|
+
}
|
|
21
|
+
catch (e) {
|
|
22
|
+
console.error(chalk.red('Angular CLI generation failed.'));
|
|
23
|
+
throw e;
|
|
24
|
+
}
|
|
25
|
+
// 3. Overwrite the component with Babylon template
|
|
26
|
+
const componentPath = path.join(process.cwd(), 'src/app/scenes', name, `${name}.component.ts`);
|
|
27
|
+
const templatePath = path.join(process.cwd(), 'src/app/scenes', name, `${name}.component.html`);
|
|
28
|
+
const stylePath = path.join(process.cwd(), 'src/app/scenes', name, `${name}.component.scss`);
|
|
29
|
+
const tsContent = `import { Component, ElementRef, AfterViewInit, ViewChild, OnDestroy, NgZone } from '@angular/core';
|
|
30
|
+
import { Engine, Scene, FreeCamera, Vector3, HemisphericLight, MeshBuilder } from '@babylonjs/core';
|
|
31
|
+
|
|
32
|
+
@Component({
|
|
33
|
+
selector: '${selector}',
|
|
34
|
+
standalone: true,
|
|
35
|
+
imports: [],
|
|
36
|
+
templateUrl: './${name}.component.html',
|
|
37
|
+
styleUrl: './${name}.component.scss'
|
|
38
|
+
})
|
|
39
|
+
export class ${componentName} implements AfterViewInit, OnDestroy {
|
|
40
|
+
@ViewChild('renderCanvas', { static: true }) canvasRef!: ElementRef<HTMLCanvasElement>;
|
|
41
|
+
|
|
42
|
+
private engine!: Engine;
|
|
43
|
+
private scene!: Scene;
|
|
44
|
+
|
|
45
|
+
constructor(private ngZone: NgZone) {}
|
|
46
|
+
|
|
47
|
+
ngAfterViewInit(): void {
|
|
48
|
+
this.ngZone.runOutsideAngular(() => {
|
|
49
|
+
this.initBabylon();
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private initBabylon(): void {
|
|
54
|
+
const canvas = this.canvasRef.nativeElement;
|
|
55
|
+
this.engine = new Engine(canvas, true);
|
|
56
|
+
this.scene = this.createScene();
|
|
57
|
+
|
|
58
|
+
this.engine.runRenderLoop(() => {
|
|
59
|
+
this.scene.render();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
window.addEventListener('resize', () => {
|
|
63
|
+
this.engine.resize();
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private createScene(): Scene {
|
|
68
|
+
const scene = new Scene(this.engine);
|
|
69
|
+
|
|
70
|
+
// Camera
|
|
71
|
+
const camera = new FreeCamera('camera1', new Vector3(0, 5, -10), scene);
|
|
72
|
+
camera.setTarget(Vector3.Zero());
|
|
73
|
+
camera.attachControl(this.canvasRef.nativeElement, true);
|
|
74
|
+
|
|
75
|
+
// Light
|
|
76
|
+
const light = new HemisphericLight('light1', new Vector3(0, 1, 0), scene);
|
|
77
|
+
light.intensity = 0.7;
|
|
78
|
+
|
|
79
|
+
// Example Ground
|
|
80
|
+
const ground = MeshBuilder.CreateGround('ground', { width: 6, height: 6 }, scene);
|
|
81
|
+
|
|
82
|
+
// Example Sphere
|
|
83
|
+
const sphere = MeshBuilder.CreateSphere('sphere', { diameter: 2, segments: 32 }, scene);
|
|
84
|
+
sphere.position.y = 1;
|
|
85
|
+
|
|
86
|
+
return scene;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
ngOnDestroy(): void {
|
|
90
|
+
if (this.engine) {
|
|
91
|
+
this.engine.dispose();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
`;
|
|
96
|
+
// HTML Content - Full sized canvas
|
|
97
|
+
const htmlContent = `<canvas #renderCanvas></canvas>`;
|
|
98
|
+
// SCSS Content - Full size
|
|
99
|
+
const scssContent = `canvas {
|
|
100
|
+
width: 100%;
|
|
101
|
+
height: 100%;
|
|
102
|
+
touch-action: none; // Prevent scroll on mobile
|
|
103
|
+
outline: none;
|
|
104
|
+
}`;
|
|
105
|
+
await fs.writeFile(componentPath, tsContent);
|
|
106
|
+
await fs.writeFile(templatePath, htmlContent);
|
|
107
|
+
await fs.writeFile(stylePath, scssContent);
|
|
108
|
+
console.log(chalk.green(`Scene ${name} generated successfully!`));
|
|
109
|
+
};
|
|
110
|
+
//# sourceMappingURL=generate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../src/commands/lifecycle.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,KAAK,qBASjB,CAAC;AAEF,eAAO,MAAM,IAAI,qBAQhB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { execa } from 'execa';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import * as fs from 'fs-extra';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import { build } from './build.js';
|
|
6
|
+
export const start = async () => {
|
|
7
|
+
// Dev start
|
|
8
|
+
await build({ lint: false, dev: true });
|
|
9
|
+
console.log(chalk.bold.white('Launching Application...'));
|
|
10
|
+
await execa('electron-forge', ['start'], {
|
|
11
|
+
env: { ELECTRON_ENABLE_LOGGING: 'true' },
|
|
12
|
+
stdio: 'inherit',
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
export const pack = async () => {
|
|
16
|
+
await build();
|
|
17
|
+
const outDir = path.join(process.cwd(), 'out');
|
|
18
|
+
if (await fs.pathExists(outDir))
|
|
19
|
+
await fs.remove(outDir);
|
|
20
|
+
console.log(chalk.bold.white('\nRunning Electron Forge Package...'));
|
|
21
|
+
await execa('electron-forge', ['package'], { stdio: 'inherit' });
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../src/commands/lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAC9B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,MAAM,CAAC,MAAM,KAAK,GAAG,KAAK,IAAI,EAAE;IAC5B,YAAY;IACZ,MAAM,KAAK,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;IAExC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC,CAAC;IAC1D,MAAM,KAAK,CAAC,gBAAgB,EAAE,CAAC,OAAO,CAAC,EAAE;QACrC,GAAG,EAAE,EAAE,uBAAuB,EAAE,MAAM,EAAE;QACxC,KAAK,EAAE,SAAS;KACnB,CAAC,CAAC;AACP,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE;IAC3B,MAAM,KAAK,EAAE,CAAC;IAEd,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,CAAC;IAC/C,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,MAAM,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAEzD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC,CAAC;IACrE,MAAM,KAAK,CAAC,gBAAgB,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;AACrE,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../src/commands/publish.ts"],"names":[],"mappings":"AA8DA,eAAO,MAAM,OAAO,qBA+CnB,CAAC"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { execa } from 'execa';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import * as fs from 'fs-extra';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import { runStage } from '../utils/logger.js';
|
|
6
|
+
import { build } from './build.js';
|
|
7
|
+
const updateReadme = async (version, packageJson) => {
|
|
8
|
+
await runStage('Updating README', async () => {
|
|
9
|
+
const v = version || packageJson.version;
|
|
10
|
+
// Assuming README is in current WD
|
|
11
|
+
const p = path.join(process.cwd(), 'README.md');
|
|
12
|
+
try {
|
|
13
|
+
if (await fs.pathExists(p)) {
|
|
14
|
+
let c = await fs.readFile(p, 'utf8');
|
|
15
|
+
// Regex to look for existing badge with ANY version number (from package.mjs)
|
|
16
|
+
const regex = /img\.shields\.io\/badge\/version-([\d\.]+)-blue/g;
|
|
17
|
+
if (regex.test(c)) {
|
|
18
|
+
c = c.replace(regex, `img.shields.io/badge/version-${v}-blue`);
|
|
19
|
+
await fs.writeFile(p, c);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch (e) {
|
|
24
|
+
console.warn('Failed to update README version badge', e);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
const createReleasesReadme = async (version) => {
|
|
29
|
+
const readmePath = path.join(process.cwd(), 'RELEASES_README.md');
|
|
30
|
+
const date = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
|
|
31
|
+
const header = `<p align="center">
|
|
32
|
+
<img src="https://raw.githubusercontent.com/Kryklin/tcs-hive/main/public/logos/logo.png" alt="Logo" width="150" />
|
|
33
|
+
</p>
|
|
34
|
+
|
|
35
|
+
<p align="center">
|
|
36
|
+
<img src="https://img.shields.io/badge/Angular_20-DD0031?style=for-the-badge&logo=angular&logoColor=white" alt="Angular" />
|
|
37
|
+
<img src="https://img.shields.io/badge/Electron_39-47848F?style=for-the-badge&logo=electron&logoColor=white" alt="Electron" />
|
|
38
|
+
<img src="https://img.shields.io/badge/Release_Channel-Stable-2ea44f?style=for-the-badge&logo=github&logoColor=white" alt="Release Channel" />
|
|
39
|
+
</p>
|
|
40
|
+
|
|
41
|
+
# 🚀 Release Notes
|
|
42
|
+
|
|
43
|
+
`;
|
|
44
|
+
const entry = `## v${version}\n**Released**: ${date}\n\n- Automated release build.\n- See commit history for changes.\n\n---\n\n`;
|
|
45
|
+
let content = entry;
|
|
46
|
+
if (await fs.pathExists(readmePath)) {
|
|
47
|
+
const existing = await fs.readFile(readmePath, 'utf8');
|
|
48
|
+
if (!existing.includes('# 🚀 Release Notes')) {
|
|
49
|
+
content = header + entry + existing;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
content = existing.replace('# 🚀 Release Notes\n\n', `# 🚀 Release Notes\n\n${entry}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
content = header + entry;
|
|
57
|
+
}
|
|
58
|
+
await fs.writeFile(readmePath, content);
|
|
59
|
+
};
|
|
60
|
+
export const publish = async () => {
|
|
61
|
+
if (!process.env.GITHUB_TOKEN) {
|
|
62
|
+
console.error('GITHUB_TOKEN missing');
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
// 1. Auto-Bump Version
|
|
66
|
+
console.log(chalk.bold.blue('Bumping Version...'));
|
|
67
|
+
await execa('npm', ['version', 'patch', '--no-git-tag-version'], { stdio: 'inherit' });
|
|
68
|
+
// Reload package.json
|
|
69
|
+
const packageJson = await fs.readJson(path.join(process.cwd(), 'package.json'));
|
|
70
|
+
const newVersion = packageJson.version;
|
|
71
|
+
console.log(chalk.green(`Version bumped to ${newVersion}`));
|
|
72
|
+
// 2. Update README badge
|
|
73
|
+
await updateReadme(newVersion, packageJson);
|
|
74
|
+
// 3. Build with new version (Lint required)
|
|
75
|
+
await build({ lint: true });
|
|
76
|
+
const outDir = path.join(process.cwd(), 'out');
|
|
77
|
+
if (await fs.pathExists(outDir))
|
|
78
|
+
await fs.remove(outDir);
|
|
79
|
+
await createReleasesReadme(newVersion);
|
|
80
|
+
// Sync README to Releases Repo (Optional, if this logic is desired generally)
|
|
81
|
+
await runStage('Syncing Release README', async (spinner) => {
|
|
82
|
+
// NOTE: This seems very specific to the user's workflow in package.mjs.
|
|
83
|
+
// We should probably keep it if they asked for "all this incorporated".
|
|
84
|
+
const tempDir = path.join(process.cwd(), 'temp_release_repo');
|
|
85
|
+
// The repo URL was hardcoded in package.mjs.
|
|
86
|
+
// We might want to make this configurable or check if user has this env var or config.
|
|
87
|
+
// For now, I will include it but wrap in try/catch or conditional if generic.
|
|
88
|
+
// Actually, let's look at package.mjs again. It hardcodes `tcs-hive-releases`.
|
|
89
|
+
// If this is a general tool, hardcoding is bad.
|
|
90
|
+
// BUT the user said "see how this script handles... incorporate into cli tool".
|
|
91
|
+
// If the CLI is FOR this specific project type, maybe it's fine.
|
|
92
|
+
// However, the CLI is "Valence CLI" creating new projects.
|
|
93
|
+
// Hardcoding a specific repo for releases is definitely not correct for a generic CLI tool.
|
|
94
|
+
// I will Comment this out or skip it unless provided via config.
|
|
95
|
+
spinner.succeed('Release README updated locally. (Skipping remote sync in generic CLI)');
|
|
96
|
+
});
|
|
97
|
+
console.log(chalk.bold.white('\nRunning Electron Forge Publish...'));
|
|
98
|
+
await execa('electron-forge', ['publish'], { stdio: 'inherit' });
|
|
99
|
+
};
|
|
100
|
+
//# sourceMappingURL=publish.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.js","sourceRoot":"","sources":["../../src/commands/publish.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import * as shell from 'shelljs';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import { build } from './commands/build.js';
|
|
7
|
+
import { start, pack } from './commands/lifecycle.js';
|
|
8
|
+
import { publish } from './commands/publish.js';
|
|
9
|
+
import { generateScene } from './commands/generate.js';
|
|
10
|
+
import { doctor } from './commands/doctor.js';
|
|
11
|
+
const program = new Command();
|
|
12
|
+
program
|
|
13
|
+
.version('1.0.0')
|
|
14
|
+
.description('Valence CLI - Scaffolding for Angular + Electron + Babylon.js');
|
|
15
|
+
program
|
|
16
|
+
.command('doctor')
|
|
17
|
+
.description('Check your environment for dependencies')
|
|
18
|
+
.action(async () => {
|
|
19
|
+
await doctor();
|
|
20
|
+
});
|
|
21
|
+
program
|
|
22
|
+
.command('generate <type> <name>')
|
|
23
|
+
.alias('g')
|
|
24
|
+
.description('Generate a new component (type: scene)')
|
|
25
|
+
.action(async (type, name) => {
|
|
26
|
+
if (type === 'scene') {
|
|
27
|
+
await generateScene(name);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
console.log(chalk.red(`Unknown type: ${type}. Supported types: scene`));
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
program
|
|
34
|
+
.command('build')
|
|
35
|
+
.description('Build the project (Angular + Electron)')
|
|
36
|
+
.option('--no-lint', 'Skip linting')
|
|
37
|
+
.option('--dev', 'Build for development')
|
|
38
|
+
.action(async (options) => {
|
|
39
|
+
await build({ lint: options.lint, dev: options.dev });
|
|
40
|
+
});
|
|
41
|
+
program
|
|
42
|
+
.command('start')
|
|
43
|
+
.description('Start the project in development mode')
|
|
44
|
+
.action(async () => {
|
|
45
|
+
await start();
|
|
46
|
+
});
|
|
47
|
+
program
|
|
48
|
+
.command('package')
|
|
49
|
+
.description('Package the application using Electron Forge')
|
|
50
|
+
.action(async () => {
|
|
51
|
+
await pack();
|
|
52
|
+
});
|
|
53
|
+
program
|
|
54
|
+
.command('publish')
|
|
55
|
+
.description('Publish the application (Bump version, Build, Forge Publish)')
|
|
56
|
+
.action(async () => {
|
|
57
|
+
await publish();
|
|
58
|
+
});
|
|
59
|
+
program
|
|
60
|
+
.command('new <name>')
|
|
61
|
+
.description('Create a new project')
|
|
62
|
+
.action(async (name) => {
|
|
63
|
+
console.log(chalk.blue(`Creating new project: ${name}`));
|
|
64
|
+
if (!shell.which('git')) {
|
|
65
|
+
shell.echo('Sorry, this script requires git');
|
|
66
|
+
shell.exit(1);
|
|
67
|
+
}
|
|
68
|
+
if (!shell.which('npm')) {
|
|
69
|
+
shell.echo('Sorry, this script requires npm');
|
|
70
|
+
shell.exit(1);
|
|
71
|
+
}
|
|
72
|
+
// 1. Scaffold Angular Project
|
|
73
|
+
console.log(chalk.green('Scaffolding Angular project...'));
|
|
74
|
+
// Using npx to ensure we use a recent version of Angular CLI without requiring global install
|
|
75
|
+
// --skip-git because we might want to do our own init, or let the user do it.
|
|
76
|
+
// --directory . to create in current dir if name matches, but here we want a subfolder.
|
|
77
|
+
const ngCommand = `npx -y @angular/cli new ${name} --directory ${name} --style scss --routing --ssr=false --skip-git`;
|
|
78
|
+
if (shell.exec(ngCommand).code !== 0) {
|
|
79
|
+
shell.echo('Error: Angular CLI failed');
|
|
80
|
+
shell.exit(1);
|
|
81
|
+
}
|
|
82
|
+
const projectPath = path.join(process.cwd(), name);
|
|
83
|
+
shell.cd(projectPath);
|
|
84
|
+
// 2. Install Babylon.js
|
|
85
|
+
console.log(chalk.green('Installing Babylon.js...'));
|
|
86
|
+
shell.exec('npm install babylonjs @babylonjs/core @babylonjs/loaders');
|
|
87
|
+
// 3. Setup Electron
|
|
88
|
+
console.log(chalk.green('Setting up Electron...'));
|
|
89
|
+
shell.exec('npm install --save-dev electron electron-forge @electron-forge/cli @electron-forge/maker-squirrel @electron-forge/maker-zip');
|
|
90
|
+
// Create Electron folder
|
|
91
|
+
const electronDir = path.join(projectPath, 'electron');
|
|
92
|
+
if (!fs.existsSync(electronDir)) {
|
|
93
|
+
fs.mkdirSync(electronDir);
|
|
94
|
+
}
|
|
95
|
+
// Electron Main Process (TypeScript)
|
|
96
|
+
const electronMain = `
|
|
97
|
+
import { app, BrowserWindow } from 'electron';
|
|
98
|
+
import * as path from 'path';
|
|
99
|
+
|
|
100
|
+
function createWindow () {
|
|
101
|
+
const win = new BrowserWindow({
|
|
102
|
+
width: 800,
|
|
103
|
+
height: 600,
|
|
104
|
+
webPreferences: {
|
|
105
|
+
preload: path.join(__dirname, 'preload.js'),
|
|
106
|
+
nodeIntegration: true,
|
|
107
|
+
contextIsolation: false
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const isDev = process.env.NODE_ENV === 'development';
|
|
112
|
+
|
|
113
|
+
if (isDev) {
|
|
114
|
+
win.loadURL('http://localhost:4200');
|
|
115
|
+
win.webContents.openDevTools();
|
|
116
|
+
} else {
|
|
117
|
+
// Path to angular build output.
|
|
118
|
+
// If angular builds to dist/browser, we are in dist/electron/main.js
|
|
119
|
+
// So ../browser/index.html is correct relative path from __dirname
|
|
120
|
+
win.loadFile(path.join(__dirname, '../browser/index.html'));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
app.whenReady().then(() => {
|
|
125
|
+
createWindow();
|
|
126
|
+
|
|
127
|
+
app.on('activate', () => {
|
|
128
|
+
if (BrowserWindow.getAllWindows().length === 0) {
|
|
129
|
+
createWindow();
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
app.on('window-all-closed', () => {
|
|
135
|
+
if (process.platform !== 'darwin') {
|
|
136
|
+
app.quit();
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
`;
|
|
140
|
+
fs.writeFileSync(path.join(electronDir, 'main.ts'), electronMain.trim());
|
|
141
|
+
// Electron Preload (TypeScript)
|
|
142
|
+
const electronPreload = `
|
|
143
|
+
window.addEventListener('DOMContentLoaded', () => {
|
|
144
|
+
const replaceText = (selector: string, text: string) => {
|
|
145
|
+
const element = document.getElementById(selector);
|
|
146
|
+
if (element) element.innerText = text;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
for (const type of ['chrome', 'node', 'electron']) {
|
|
150
|
+
replaceText(\`\${type}-version\`, process.versions[type as keyof NodeJS.ProcessVersions] || '');
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
`;
|
|
154
|
+
fs.writeFileSync(path.join(electronDir, 'preload.ts'), electronPreload.trim());
|
|
155
|
+
// Electron tsconfig
|
|
156
|
+
const electronTsConfig = {
|
|
157
|
+
"compilerOptions": {
|
|
158
|
+
"module": "commonjs",
|
|
159
|
+
"target": "es2020",
|
|
160
|
+
"outDir": "../dist/electron",
|
|
161
|
+
"rootDir": ".",
|
|
162
|
+
"sourceMap": true,
|
|
163
|
+
"strict": true
|
|
164
|
+
},
|
|
165
|
+
"include": [
|
|
166
|
+
"**/*.ts"
|
|
167
|
+
]
|
|
168
|
+
};
|
|
169
|
+
fs.writeFileSync(path.join(electronDir, 'tsconfig.json'), JSON.stringify(electronTsConfig, null, 2));
|
|
170
|
+
// 4. Create forge.config.js
|
|
171
|
+
console.log(chalk.green('Creating forge.config.js...'));
|
|
172
|
+
const forgeConfig = `
|
|
173
|
+
module.exports = {
|
|
174
|
+
packagerConfig: {},
|
|
175
|
+
rebuildConfig: {},
|
|
176
|
+
makers: [
|
|
177
|
+
{
|
|
178
|
+
name: '@electron-forge/maker-squirrel',
|
|
179
|
+
config: {},
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
name: '@electron-forge/maker-zip',
|
|
183
|
+
platforms: ['darwin', 'win32'],
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
name: '@electron-forge/maker-deb',
|
|
187
|
+
config: {},
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
name: '@electron-forge/maker-rpm',
|
|
191
|
+
config: {},
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
};
|
|
195
|
+
`;
|
|
196
|
+
fs.writeFileSync(path.join(projectPath, 'forge.config.js'), forgeConfig.trim());
|
|
197
|
+
// 5. Configure Angular Output Path
|
|
198
|
+
console.log(chalk.green('Configuring Angular build output...'));
|
|
199
|
+
const angularJsonPath = path.join(projectPath, 'angular.json');
|
|
200
|
+
try {
|
|
201
|
+
const angularJson = JSON.parse(fs.readFileSync(angularJsonPath, 'utf8'));
|
|
202
|
+
// Angular 17+ structure often has projects[name].architect.build.options.outputPath
|
|
203
|
+
// We want to set it to 'dist/browser' (or similar, but simple 'dist' might conflict if we want dist/electron too)
|
|
204
|
+
// Let's use 'dist/browser'
|
|
205
|
+
if (angularJson.projects && angularJson.projects[name] && angularJson.projects[name].architect && angularJson.projects[name].architect.build) {
|
|
206
|
+
angularJson.projects[name].architect.build.options.outputPath = 'dist/browser';
|
|
207
|
+
angularJson.projects[name].architect.build.options.baseHref = './';
|
|
208
|
+
fs.writeFileSync(angularJsonPath, JSON.stringify(angularJson, null, 2));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
catch (e) {
|
|
212
|
+
console.warn(chalk.yellow('Could not auto-configure angular.json output path. You may need to set it manually.'));
|
|
213
|
+
}
|
|
214
|
+
// 6. Configure Package.json
|
|
215
|
+
console.log(chalk.green('Configuring package.json...'));
|
|
216
|
+
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
217
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
218
|
+
packageJson.main = 'dist/electron/main.js';
|
|
219
|
+
// Scripts - delegation to valence is best for DX, or standard npm scripts
|
|
220
|
+
packageJson.scripts['start'] = 'valence start';
|
|
221
|
+
packageJson.scripts['build'] = 'valence build';
|
|
222
|
+
packageJson.scripts['package'] = 'valence package';
|
|
223
|
+
packageJson.scripts['publish'] = 'valence publish';
|
|
224
|
+
// Keep standard ones as fallbacks or underlying checks
|
|
225
|
+
packageJson.scripts['ng'] = 'ng';
|
|
226
|
+
// Remove inline forge config if present (we use file now)
|
|
227
|
+
if (packageJson.config && packageJson.config.forge) {
|
|
228
|
+
delete packageJson.config.forge;
|
|
229
|
+
}
|
|
230
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
231
|
+
// 7. Template Enhancement (Rich Default)
|
|
232
|
+
console.log(chalk.green('Enhancing default template...'));
|
|
233
|
+
// standard body reset
|
|
234
|
+
const stylesScssPath = path.join(projectPath, 'src/styles.scss');
|
|
235
|
+
const stylesContent = `
|
|
236
|
+
html, body {
|
|
237
|
+
margin: 0;
|
|
238
|
+
padding: 0;
|
|
239
|
+
width: 100%;
|
|
240
|
+
height: 100%;
|
|
241
|
+
overflow: hidden;
|
|
242
|
+
background-color: #1a1a1a;
|
|
243
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
244
|
+
}
|
|
245
|
+
`;
|
|
246
|
+
fs.writeFileSync(stylesScssPath, stylesContent.trim());
|
|
247
|
+
// AppComponent TS
|
|
248
|
+
const appComponentPath = path.join(projectPath, 'src/app/app.component.ts');
|
|
249
|
+
const appComponentTs = `
|
|
250
|
+
import { Component, ElementRef, AfterViewInit, ViewChild, OnDestroy, NgZone } from '@angular/core';
|
|
251
|
+
import { CommonModule } from '@angular/common';
|
|
252
|
+
import { RouterOutlet } from '@angular/router';
|
|
253
|
+
import { Engine, Scene, FreeCamera, Vector3, HemisphericLight, MeshBuilder, Color4, Mesh } from 'babylonjs';
|
|
254
|
+
|
|
255
|
+
@Component({
|
|
256
|
+
selector: 'app-root',
|
|
257
|
+
standalone: true,
|
|
258
|
+
imports: [CommonModule, RouterOutlet],
|
|
259
|
+
templateUrl: './app.component.html',
|
|
260
|
+
styleUrl: './app.component.scss'
|
|
261
|
+
})
|
|
262
|
+
export class AppComponent implements AfterViewInit, OnDestroy {
|
|
263
|
+
@ViewChild('renderCanvas', { static: true }) canvasRef!: ElementRef<HTMLCanvasElement>;
|
|
264
|
+
|
|
265
|
+
private engine!: Engine;
|
|
266
|
+
private scene!: Scene;
|
|
267
|
+
private plane!: Mesh;
|
|
268
|
+
|
|
269
|
+
// Debug Stats
|
|
270
|
+
public fps: string = '0';
|
|
271
|
+
public cameraPos: { x: string, y: string, z: string } = { x: '0.00', y: '0.00', z: '0.00' };
|
|
272
|
+
|
|
273
|
+
constructor(private ngZone: NgZone) {}
|
|
274
|
+
|
|
275
|
+
ngAfterViewInit(): void {
|
|
276
|
+
this.ngZone.runOutsideAngular(() => {
|
|
277
|
+
this.initBabylon();
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
// UI Update Loop (Low Frequency)
|
|
281
|
+
setInterval(() => {
|
|
282
|
+
if (this.engine) {
|
|
283
|
+
this.fps = this.engine.getFps().toFixed(0);
|
|
284
|
+
if (this.scene && this.scene.activeCamera) {
|
|
285
|
+
const p = this.scene.activeCamera.position;
|
|
286
|
+
this.cameraPos = {
|
|
287
|
+
x: p.x.toFixed(2),
|
|
288
|
+
y: p.y.toFixed(2),
|
|
289
|
+
z: p.z.toFixed(2)
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
// Trigger change detection manually if needed, or rely on Zone.js if we were inside zone.
|
|
293
|
+
// Since we are updating properties bound in template, and we are inside a setInterval which is patched by Zone.js,
|
|
294
|
+
// Angular should detect this automatically.
|
|
295
|
+
}
|
|
296
|
+
}, 500);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
private initBabylon(): void {
|
|
300
|
+
const canvas = this.canvasRef.nativeElement;
|
|
301
|
+
this.engine = new Engine(canvas, true);
|
|
302
|
+
this.scene = this.createScene();
|
|
303
|
+
|
|
304
|
+
this.engine.runRenderLoop(() => {
|
|
305
|
+
this.scene.render();
|
|
306
|
+
if (this.plane) {
|
|
307
|
+
this.plane.rotation.y += 0.01;
|
|
308
|
+
this.plane.rotation.x += 0.005;
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
window.addEventListener('resize', () => {
|
|
313
|
+
this.engine.resize();
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
private createScene(): Scene {
|
|
318
|
+
const scene = new Scene(this.engine);
|
|
319
|
+
scene.clearColor = new Color4(0.1, 0.1, 0.1, 1);
|
|
320
|
+
|
|
321
|
+
// Camera
|
|
322
|
+
const camera = new FreeCamera('camera1', new Vector3(0, 0, -5), scene);
|
|
323
|
+
camera.setTarget(Vector3.Zero());
|
|
324
|
+
camera.attachControl(this.canvasRef.nativeElement, true);
|
|
325
|
+
|
|
326
|
+
// Light
|
|
327
|
+
const light = new HemisphericLight('light1', new Vector3(0, 1, 0), scene);
|
|
328
|
+
light.intensity = 0.7;
|
|
329
|
+
|
|
330
|
+
// Rotating Plane
|
|
331
|
+
this.plane = MeshBuilder.CreatePlane('plane', { size: 2 }, scene);
|
|
332
|
+
// Double sided
|
|
333
|
+
this.plane.material = new (window as any).BABYLON.StandardMaterial('mat', scene);
|
|
334
|
+
(this.plane.material as any).backFaceCulling = false;
|
|
335
|
+
(this.plane.material as any).diffuseColor = new Color4(0.4, 0.8, 1, 1);
|
|
336
|
+
(this.plane.material as any).wireframe = true;
|
|
337
|
+
|
|
338
|
+
return scene;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
ngOnDestroy(): void {
|
|
342
|
+
if (this.engine) {
|
|
343
|
+
this.engine.dispose();
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
`;
|
|
348
|
+
fs.writeFileSync(appComponentPath, appComponentTs.trim());
|
|
349
|
+
// AppComponent HTML
|
|
350
|
+
const appComponentHtml = `
|
|
351
|
+
<div class="app-container">
|
|
352
|
+
<canvas #renderCanvas id="renderCanvas"></canvas>
|
|
353
|
+
|
|
354
|
+
<!-- UI Overlay -->
|
|
355
|
+
<div class="ui-overlay">
|
|
356
|
+
<div class="logo-container">
|
|
357
|
+
<svg width="150" height="150" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
|
|
358
|
+
<defs>
|
|
359
|
+
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
360
|
+
<stop offset="0%" style="stop-color:#DD0031;stop-opacity:1" />
|
|
361
|
+
<stop offset="50%" style="stop-color:#47848F;stop-opacity:1" />
|
|
362
|
+
<stop offset="100%" style="stop-color:#ffffff;stop-opacity:1" />
|
|
363
|
+
</linearGradient>
|
|
364
|
+
<filter id="glow">
|
|
365
|
+
<feGaussianBlur stdDeviation="2.5" result="coloredBlur"/>
|
|
366
|
+
<feMerge>
|
|
367
|
+
<feMergeNode in="coloredBlur"/>
|
|
368
|
+
<feMergeNode in="SourceGraphic"/>
|
|
369
|
+
</feMerge>
|
|
370
|
+
</filter>
|
|
371
|
+
</defs>
|
|
372
|
+
<!-- Stylized V / Triangle Structure -->
|
|
373
|
+
<path d="M100 20 L180 170 L20 170 Z" fill="none" stroke="url(#grad1)" stroke-width="8" filter="url(#glow)" />
|
|
374
|
+
<circle cx="100" cy="90" r="30" fill="rgba(255,255,255,0.1)" stroke="white" stroke-width="2" />
|
|
375
|
+
<text x="100" y="195" font-family="Arial" font-size="24" fill="white" text-anchor="middle" font-weight="bold" letter-spacing="4">VALENCE</text>
|
|
376
|
+
</svg>
|
|
377
|
+
</div>
|
|
378
|
+
|
|
379
|
+
<div class="debug-panel">
|
|
380
|
+
<div class="stat-row"><span class="label">FPS:</span> <span class="value">{{ fps }}</span></div>
|
|
381
|
+
<div class="stat-row"><span class="label">POS:</span> <span class="value">X:{{ cameraPos.x }} Y:{{ cameraPos.y }} Z:{{ cameraPos.z }}</span></div>
|
|
382
|
+
<div class="stat-row info"><small>Angular + Electron + Babylon</small></div>
|
|
383
|
+
<div class="instructions">Use Arrow Keys / Mouse Drag to move</div>
|
|
384
|
+
</div>
|
|
385
|
+
</div>
|
|
386
|
+
</div>
|
|
387
|
+
`;
|
|
388
|
+
fs.writeFileSync(path.join(projectPath, 'src/app/app.component.html'), appComponentHtml.trim());
|
|
389
|
+
// AppComponent SCSS
|
|
390
|
+
const appComponentScss = `
|
|
391
|
+
.app-container {
|
|
392
|
+
width: 100vw;
|
|
393
|
+
height: 100vh;
|
|
394
|
+
position: relative;
|
|
395
|
+
overflow: hidden;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
#renderCanvas {
|
|
399
|
+
width: 100%;
|
|
400
|
+
height: 100%;
|
|
401
|
+
touch-action: none;
|
|
402
|
+
outline: none;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
.ui-overlay {
|
|
406
|
+
position: absolute;
|
|
407
|
+
top: 0;
|
|
408
|
+
left: 0;
|
|
409
|
+
width: 100%;
|
|
410
|
+
height: 100%;
|
|
411
|
+
pointer-events: none; // Let clicks pass to canvas
|
|
412
|
+
|
|
413
|
+
display: flex;
|
|
414
|
+
flex-direction: column;
|
|
415
|
+
justify-content: space-between;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.logo-container {
|
|
419
|
+
padding: 2rem;
|
|
420
|
+
opacity: 0.8;
|
|
421
|
+
animation: float 6s ease-in-out infinite;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.debug-panel {
|
|
425
|
+
position: absolute;
|
|
426
|
+
top: 2rem;
|
|
427
|
+
right: 2rem;
|
|
428
|
+
background: rgba(0, 0, 0, 0.7);
|
|
429
|
+
border-left: 4px solid #47848F;
|
|
430
|
+
padding: 1rem;
|
|
431
|
+
border-radius: 4px;
|
|
432
|
+
color: #fff;
|
|
433
|
+
font-family: 'Consolas', 'Monaco', monospace;
|
|
434
|
+
backdrop-filter: blur(5px);
|
|
435
|
+
pointer-events: auto; // Allow selecting text
|
|
436
|
+
|
|
437
|
+
.stat-row {
|
|
438
|
+
display: flex;
|
|
439
|
+
justify-content: space-between;
|
|
440
|
+
margin-bottom: 0.5rem;
|
|
441
|
+
min-width: 200px;
|
|
442
|
+
|
|
443
|
+
.label {
|
|
444
|
+
color: #aaa;
|
|
445
|
+
margin-right: 1rem;
|
|
446
|
+
}
|
|
447
|
+
.value {
|
|
448
|
+
color: #4dbf00;
|
|
449
|
+
font-weight: bold;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
.info {
|
|
453
|
+
margin-top: 1rem;
|
|
454
|
+
padding-top: 0.5rem;
|
|
455
|
+
border-top: 1px solid #333;
|
|
456
|
+
text-align: right;
|
|
457
|
+
opacity: 0.7;
|
|
458
|
+
}
|
|
459
|
+
.instructions {
|
|
460
|
+
margin-top: 0.5rem;
|
|
461
|
+
font-size: 0.8rem;
|
|
462
|
+
color: #ddd;
|
|
463
|
+
text-align: right;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
@keyframes float {
|
|
468
|
+
0% { transform: translateY(0px); }
|
|
469
|
+
50% { transform: translateY(-10px); }
|
|
470
|
+
100% { transform: translateY(0px); }
|
|
471
|
+
}
|
|
472
|
+
`;
|
|
473
|
+
fs.writeFileSync(path.join(projectPath, 'src/app/app.component.scss'), appComponentScss.trim());
|
|
474
|
+
});
|
|
475
|
+
program.parse(process.argv);
|
|
476
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Ora } from 'ora';
|
|
2
|
+
import { type Options } from 'execa';
|
|
3
|
+
export declare const wait: (ms: number) => Promise<unknown>;
|
|
4
|
+
export declare const runStage: (title: string, taskFn: (spinner: Ora) => Promise<string | void>) => Promise<void>;
|
|
5
|
+
export declare const execWithScrollingLogger: (parentSpinner: Ora, command: string, args: string[], options?: Options & {
|
|
6
|
+
title?: string;
|
|
7
|
+
truncate?: boolean;
|
|
8
|
+
rows?: number;
|
|
9
|
+
}, onData?: (line: string, spinner: Ora) => void) => Promise<any>;
|
|
10
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AACA,OAAY,EAAE,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAS,KAAK,OAAO,EAAE,MAAM,OAAO,CAAC;AAI5C,eAAO,MAAM,IAAI,GAAI,IAAI,MAAM,qBAAsD,CAAC;AAEtF,eAAO,MAAM,QAAQ,GAAU,OAAO,MAAM,EAAE,QAAQ,CAAC,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,kBAY7F,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAChC,eAAe,GAAG,EAClB,SAAS,MAAM,EACf,MAAM,MAAM,EAAE,EACd,UAAS,OAAO,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,EAC7E,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,IAAI,KAC9C,OAAO,CAAC,GAAG,CAmCb,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora, {} from 'ora';
|
|
3
|
+
import { execa } from 'execa';
|
|
4
|
+
import * as fs from 'fs-extra';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
export const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
7
|
+
export const runStage = async (title, taskFn) => {
|
|
8
|
+
const spinner = ora({ text: chalk.bold.white(title), color: 'yellow', spinner: 'dots' }).start();
|
|
9
|
+
const startTime = Date.now();
|
|
10
|
+
try {
|
|
11
|
+
const successMessage = await taskFn(spinner);
|
|
12
|
+
const elapsed = Date.now() - startTime;
|
|
13
|
+
if (elapsed < 2000)
|
|
14
|
+
await wait(2000 - elapsed);
|
|
15
|
+
spinner.succeed(successMessage || chalk.bold.white(title + ' Completed'));
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
spinner.fail(chalk.bold.red(title + ' Failed'));
|
|
19
|
+
throw error;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
export const execWithScrollingLogger = async (parentSpinner, command, args, options = {}, onData) => {
|
|
23
|
+
const child = execa(command, args, { ...options, all: true, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
24
|
+
const logBuffer = [];
|
|
25
|
+
const maxLines = options.rows || 10;
|
|
26
|
+
if (child.all) {
|
|
27
|
+
child.all.on('data', (chunk) => {
|
|
28
|
+
const lines = chunk
|
|
29
|
+
.toString()
|
|
30
|
+
.split('\n')
|
|
31
|
+
.filter((l) => l.trim());
|
|
32
|
+
if (lines.length > 0) {
|
|
33
|
+
if (onData) {
|
|
34
|
+
onData(lines[lines.length - 1], parentSpinner);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
for (const line of lines) {
|
|
38
|
+
const trimmed = line.trim();
|
|
39
|
+
const shouldTruncate = options.truncate !== false;
|
|
40
|
+
logBuffer.push(shouldTruncate && trimmed.length > 120 ? trimmed.substring(0, 117) + '...' : trimmed);
|
|
41
|
+
if (logBuffer.length > maxLines)
|
|
42
|
+
logBuffer.shift();
|
|
43
|
+
}
|
|
44
|
+
parentSpinner.text = `${chalk.bold.white(options.title || 'Processing')}\n${logBuffer.map((l) => chalk.yellow(' -> ' + l)).join('\n')}`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
return await child;
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
if (e.all)
|
|
54
|
+
console.error(chalk.red('\nErrors:\n' + e.all));
|
|
55
|
+
throw e;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "valence-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"valence": "./bin/valence.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"bin",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"prepublishOnly": "npm run build",
|
|
17
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"angular",
|
|
21
|
+
"electron",
|
|
22
|
+
"babylonjs",
|
|
23
|
+
"cli",
|
|
24
|
+
"scaffold",
|
|
25
|
+
"gamedev",
|
|
26
|
+
"3d"
|
|
27
|
+
],
|
|
28
|
+
"author": "Valence Team",
|
|
29
|
+
"license": "ISC",
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@types/figlet": "^1.7.0",
|
|
32
|
+
"@types/fs-extra": "^11.0.4",
|
|
33
|
+
"chalk": "^5.4.1",
|
|
34
|
+
"commander": "^13.1.0",
|
|
35
|
+
"execa": "^9.6.1",
|
|
36
|
+
"figlet": "^1.9.4",
|
|
37
|
+
"fs-extra": "^11.3.3",
|
|
38
|
+
"inquirer": "^12.3.2",
|
|
39
|
+
"ora": "^9.0.0",
|
|
40
|
+
"shelljs": "^0.8.5",
|
|
41
|
+
"typescript": "^5.7.3"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^22.10.6",
|
|
45
|
+
"@types/shelljs": "^0.8.15"
|
|
46
|
+
},
|
|
47
|
+
"type": "module"
|
|
48
|
+
}
|