Spaces:
Sleeping
Sleeping
Commit
·
502af73
1
Parent(s):
cccfc29
updated
Browse files- .gitignore +2 -0
- trigo-web/.husky/pre-commit +1 -0
- trigo-web/README.md +16 -1
- trigo-web/app/package-lock.json +73 -1596
- trigo-web/app/src/App.vue +7 -4
- trigo-web/app/src/components/LayoutFrame.vue +29 -0
- trigo-web/app/src/components/SidebarMenu.vue +235 -0
- trigo-web/app/src/composables/useSocket.ts +24 -17
- trigo-web/app/src/composables/useTrigoAgent.ts +171 -0
- trigo-web/app/src/main.ts +10 -9
- trigo-web/app/src/router/index.ts +40 -5
- trigo-web/app/src/services/onnxInferencer.ts +68 -0
- trigo-web/app/src/services/trigoViewport.ts +301 -138
- trigo-web/app/src/stores/gameStore.ts +21 -29
- trigo-web/app/src/utils/TrigoGameFrontend.ts +1 -28
- trigo-web/app/src/utils/storage.ts +261 -0
- trigo-web/app/src/views/OnnxTestView.vue +511 -0
- trigo-web/app/src/views/TrigoAgentTestView.vue +711 -0
- trigo-web/app/src/views/TrigoTreeTestView.vue +1083 -0
- trigo-web/app/src/views/TrigoView.vue +1560 -1171
- trigo-web/app/test_capture.js +2 -2
- trigo-web/app/vite.config.ts +27 -3
- trigo-web/backend/src/server.ts +7 -3
- trigo-web/backend/src/services/gameManager.ts +5 -7
- trigo-web/backend/src/sockets/gameSocket.ts +4 -2
- trigo-web/backend/tsconfig.json +2 -7
- trigo-web/inc/modelInferencer.ts +465 -0
- trigo-web/inc/tgn/README.md +12 -10
- trigo-web/inc/tgn/tgn.jison +2 -2
- trigo-web/inc/tgn/tgnParser.ts +11 -21
- trigo-web/inc/trigo/ab0yz.ts +19 -13
- trigo-web/inc/trigo/game.ts +135 -68
- trigo-web/inc/trigo/gameUtils.ts +15 -49
- trigo-web/inc/trigo/index.ts +0 -1
- trigo-web/inc/trigo/parserInit.ts +9 -8
- trigo-web/inc/trigo/typeAdapters.ts +3 -12
- trigo-web/inc/trigoAgent.ts +262 -0
- trigo-web/inc/trigoTreeAgent.ts +415 -0
- trigo-web/inc/tsconfig.json +1 -1
- trigo-web/package-lock.json +1253 -799
- trigo-web/package.json +11 -1
- trigo-web/public/lib/tgnParser.cjs +1 -1
- trigo-web/tools/README.md +2 -2
- trigo-web/tools/migrateTGN.ts +291 -0
- trigo-web/vitest.config.ts +1 -1
- trigo-web/yarn.lock +517 -39
.gitignore
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
node_modules/
|
| 2 |
+
dist/
|
trigo-web/.husky/pre-commit
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
npm test
|
trigo-web/README.md
CHANGED
|
@@ -52,12 +52,14 @@ trigo-web/
|
|
| 52 |
### Installation
|
| 53 |
|
| 54 |
1. Clone the repository:
|
|
|
|
| 55 |
```bash
|
| 56 |
git clone [repository-url]
|
| 57 |
cd trigo-web
|
| 58 |
```
|
| 59 |
|
| 60 |
2. Install all dependencies:
|
|
|
|
| 61 |
```bash
|
| 62 |
npm run install:all
|
| 63 |
```
|
|
@@ -95,26 +97,31 @@ npm run build
|
|
| 95 |
The project includes comprehensive unit tests for the game logic (TrigoGame class).
|
| 96 |
|
| 97 |
**Run all tests once:**
|
|
|
|
| 98 |
```bash
|
| 99 |
npm run test:run
|
| 100 |
```
|
| 101 |
|
| 102 |
**Run tests in watch mode (auto-rerun on file changes):**
|
|
|
|
| 103 |
```bash
|
| 104 |
npm test
|
| 105 |
```
|
| 106 |
|
| 107 |
**Run tests with UI dashboard:**
|
|
|
|
| 108 |
```bash
|
| 109 |
npm run test:ui
|
| 110 |
```
|
| 111 |
|
| 112 |
**Run specific test file:**
|
|
|
|
| 113 |
```bash
|
| 114 |
npm exec vitest -- run tests/game/trigoGame.core.test.ts
|
| 115 |
```
|
| 116 |
|
| 117 |
**Test Coverage:**
|
|
|
|
| 118 |
- **109/109 tests passing (100%)**
|
| 119 |
- Core functionality (35 tests) - Drop, pass, surrender, reset
|
| 120 |
- History management (21 tests) - Undo, redo, jump to step
|
|
@@ -122,6 +129,7 @@ npm exec vitest -- run tests/game/trigoGame.core.test.ts
|
|
| 122 |
- State management (32 tests) - Serialization, callbacks, session storage
|
| 123 |
|
| 124 |
**Test Files Location:** `tests/game/`
|
|
|
|
| 125 |
- `trigoGame.core.test.ts` - Basic game operations
|
| 126 |
- `trigoGame.history.test.ts` - History and navigation
|
| 127 |
- `trigoGame.rules.test.ts` - Go game rules implementation
|
|
@@ -144,6 +152,7 @@ npm run format:check
|
|
| 144 |
## Technology Stack
|
| 145 |
|
| 146 |
### Frontend
|
|
|
|
| 147 |
- **Vue 3** - Progressive JavaScript framework
|
| 148 |
- **TypeScript** - Type-safe JavaScript
|
| 149 |
- **Three.js** - 3D graphics library for WebGL
|
|
@@ -154,6 +163,7 @@ npm run format:check
|
|
| 154 |
- **SASS** - CSS preprocessor
|
| 155 |
|
| 156 |
### Backend
|
|
|
|
| 157 |
- **Node.js** - JavaScript runtime
|
| 158 |
- **Express** - Web framework
|
| 159 |
- **Socket.io** - Real-time bidirectional communication
|
|
@@ -172,6 +182,7 @@ Trigo extends the traditional Go game into three dimensions:
|
|
| 172 |
## API Endpoints
|
| 173 |
|
| 174 |
### REST API
|
|
|
|
| 175 |
- `GET /health` - Health check
|
| 176 |
- `GET /api/rooms` - List active game rooms
|
| 177 |
- `GET /api/rooms/:roomId` - Get specific room details
|
|
@@ -179,6 +190,7 @@ Trigo extends the traditional Go game into three dimensions:
|
|
| 179 |
### WebSocket Events
|
| 180 |
|
| 181 |
#### Client → Server
|
|
|
|
| 182 |
- `joinRoom` - Join or create a game room
|
| 183 |
- `leaveRoom` - Leave current room
|
| 184 |
- `makeMove` - Make a game move
|
|
@@ -187,6 +199,7 @@ Trigo extends the traditional Go game into three dimensions:
|
|
| 187 |
- `chatMessage` - Send chat message
|
| 188 |
|
| 189 |
#### Server → Client
|
|
|
|
| 190 |
- `roomJoined` - Successfully joined room
|
| 191 |
- `gameUpdate` - Game state update
|
| 192 |
- `playerJoined` - Another player joined
|
|
@@ -197,6 +210,7 @@ Trigo extends the traditional Go game into three dimensions:
|
|
| 197 |
## Development Guidelines
|
| 198 |
|
| 199 |
### Code Style
|
|
|
|
| 200 |
- Uses Prettier for consistent formatting
|
| 201 |
- Tab indentation (following prototype style)
|
| 202 |
- Double quotes for strings
|
|
@@ -204,6 +218,7 @@ Trigo extends the traditional Go game into three dimensions:
|
|
| 204 |
- Semicolons always
|
| 205 |
|
| 206 |
### Git Workflow
|
|
|
|
| 207 |
1. Create feature branch from `main`
|
| 208 |
2. Make changes and test locally
|
| 209 |
3. Format code with `npm run format`
|
|
@@ -224,4 +239,4 @@ Contributions are welcome! Please read the contributing guidelines before submit
|
|
| 224 |
|
| 225 |
## Support
|
| 226 |
|
| 227 |
-
For issues, questions, or suggestions, please open an issue on GitHub.
|
|
|
|
| 52 |
### Installation
|
| 53 |
|
| 54 |
1. Clone the repository:
|
| 55 |
+
|
| 56 |
```bash
|
| 57 |
git clone [repository-url]
|
| 58 |
cd trigo-web
|
| 59 |
```
|
| 60 |
|
| 61 |
2. Install all dependencies:
|
| 62 |
+
|
| 63 |
```bash
|
| 64 |
npm run install:all
|
| 65 |
```
|
|
|
|
| 97 |
The project includes comprehensive unit tests for the game logic (TrigoGame class).
|
| 98 |
|
| 99 |
**Run all tests once:**
|
| 100 |
+
|
| 101 |
```bash
|
| 102 |
npm run test:run
|
| 103 |
```
|
| 104 |
|
| 105 |
**Run tests in watch mode (auto-rerun on file changes):**
|
| 106 |
+
|
| 107 |
```bash
|
| 108 |
npm test
|
| 109 |
```
|
| 110 |
|
| 111 |
**Run tests with UI dashboard:**
|
| 112 |
+
|
| 113 |
```bash
|
| 114 |
npm run test:ui
|
| 115 |
```
|
| 116 |
|
| 117 |
**Run specific test file:**
|
| 118 |
+
|
| 119 |
```bash
|
| 120 |
npm exec vitest -- run tests/game/trigoGame.core.test.ts
|
| 121 |
```
|
| 122 |
|
| 123 |
**Test Coverage:**
|
| 124 |
+
|
| 125 |
- **109/109 tests passing (100%)**
|
| 126 |
- Core functionality (35 tests) - Drop, pass, surrender, reset
|
| 127 |
- History management (21 tests) - Undo, redo, jump to step
|
|
|
|
| 129 |
- State management (32 tests) - Serialization, callbacks, session storage
|
| 130 |
|
| 131 |
**Test Files Location:** `tests/game/`
|
| 132 |
+
|
| 133 |
- `trigoGame.core.test.ts` - Basic game operations
|
| 134 |
- `trigoGame.history.test.ts` - History and navigation
|
| 135 |
- `trigoGame.rules.test.ts` - Go game rules implementation
|
|
|
|
| 152 |
## Technology Stack
|
| 153 |
|
| 154 |
### Frontend
|
| 155 |
+
|
| 156 |
- **Vue 3** - Progressive JavaScript framework
|
| 157 |
- **TypeScript** - Type-safe JavaScript
|
| 158 |
- **Three.js** - 3D graphics library for WebGL
|
|
|
|
| 163 |
- **SASS** - CSS preprocessor
|
| 164 |
|
| 165 |
### Backend
|
| 166 |
+
|
| 167 |
- **Node.js** - JavaScript runtime
|
| 168 |
- **Express** - Web framework
|
| 169 |
- **Socket.io** - Real-time bidirectional communication
|
|
|
|
| 182 |
## API Endpoints
|
| 183 |
|
| 184 |
### REST API
|
| 185 |
+
|
| 186 |
- `GET /health` - Health check
|
| 187 |
- `GET /api/rooms` - List active game rooms
|
| 188 |
- `GET /api/rooms/:roomId` - Get specific room details
|
|
|
|
| 190 |
### WebSocket Events
|
| 191 |
|
| 192 |
#### Client → Server
|
| 193 |
+
|
| 194 |
- `joinRoom` - Join or create a game room
|
| 195 |
- `leaveRoom` - Leave current room
|
| 196 |
- `makeMove` - Make a game move
|
|
|
|
| 199 |
- `chatMessage` - Send chat message
|
| 200 |
|
| 201 |
#### Server → Client
|
| 202 |
+
|
| 203 |
- `roomJoined` - Successfully joined room
|
| 204 |
- `gameUpdate` - Game state update
|
| 205 |
- `playerJoined` - Another player joined
|
|
|
|
| 210 |
## Development Guidelines
|
| 211 |
|
| 212 |
### Code Style
|
| 213 |
+
|
| 214 |
- Uses Prettier for consistent formatting
|
| 215 |
- Tab indentation (following prototype style)
|
| 216 |
- Double quotes for strings
|
|
|
|
| 218 |
- Semicolons always
|
| 219 |
|
| 220 |
### Git Workflow
|
| 221 |
+
|
| 222 |
1. Create feature branch from `main`
|
| 223 |
2. Make changes and test locally
|
| 224 |
3. Format code with `npm run format`
|
|
|
|
| 239 |
|
| 240 |
## Support
|
| 241 |
|
| 242 |
+
For issues, questions, or suggestions, please open an issue on GitHub.
|
trigo-web/app/package-lock.json
CHANGED
|
@@ -17,53 +17,12 @@
|
|
| 17 |
"devDependencies": {
|
| 18 |
"@types/three": "^0.156.0",
|
| 19 |
"@vitejs/plugin-vue": "^5.2.4",
|
| 20 |
-
"@vitest/ui": "^4.0.6",
|
| 21 |
-
"jsdom": "^27.1.0",
|
| 22 |
"sass-embedded": "^1.93.2",
|
| 23 |
"typescript": "^5.2.2",
|
| 24 |
"vite": "^5.4.21",
|
| 25 |
-
"vitest": "^4.0.6",
|
| 26 |
"vue-tsc": "^2.2.12"
|
| 27 |
}
|
| 28 |
},
|
| 29 |
-
"node_modules/@acemir/cssom": {
|
| 30 |
-
"version": "0.9.19",
|
| 31 |
-
"resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.19.tgz",
|
| 32 |
-
"integrity": "sha512-Pp2gAQXPZ2o7lt4j0IMwNRXqQ3pagxtDj5wctL5U2Lz4oV0ocDNlkgx4DpxfyKav4S/bePuI+SMqcBSUHLy9kg==",
|
| 33 |
-
"dev": true
|
| 34 |
-
},
|
| 35 |
-
"node_modules/@asamuzakjp/css-color": {
|
| 36 |
-
"version": "4.0.5",
|
| 37 |
-
"resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.0.5.tgz",
|
| 38 |
-
"integrity": "sha512-lMrXidNhPGsDjytDy11Vwlb6OIGrT3CmLg3VWNFyWkLWtijKl7xjvForlh8vuj0SHGjgl4qZEQzUmYTeQA2JFQ==",
|
| 39 |
-
"dev": true,
|
| 40 |
-
"dependencies": {
|
| 41 |
-
"@csstools/css-calc": "^2.1.4",
|
| 42 |
-
"@csstools/css-color-parser": "^3.1.0",
|
| 43 |
-
"@csstools/css-parser-algorithms": "^3.0.5",
|
| 44 |
-
"@csstools/css-tokenizer": "^3.0.4",
|
| 45 |
-
"lru-cache": "^11.2.1"
|
| 46 |
-
}
|
| 47 |
-
},
|
| 48 |
-
"node_modules/@asamuzakjp/dom-selector": {
|
| 49 |
-
"version": "6.7.4",
|
| 50 |
-
"resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.7.4.tgz",
|
| 51 |
-
"integrity": "sha512-buQDjkm+wDPXd6c13534URWZqbz0RP5PAhXZ+LIoa5LgwInT9HVJvGIJivg75vi8I13CxDGdTnz+aY5YUJlIAA==",
|
| 52 |
-
"dev": true,
|
| 53 |
-
"dependencies": {
|
| 54 |
-
"@asamuzakjp/nwsapi": "^2.3.9",
|
| 55 |
-
"bidi-js": "^1.0.3",
|
| 56 |
-
"css-tree": "^3.1.0",
|
| 57 |
-
"is-potential-custom-element-name": "^1.0.1",
|
| 58 |
-
"lru-cache": "^11.2.2"
|
| 59 |
-
}
|
| 60 |
-
},
|
| 61 |
-
"node_modules/@asamuzakjp/nwsapi": {
|
| 62 |
-
"version": "2.3.9",
|
| 63 |
-
"resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz",
|
| 64 |
-
"integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==",
|
| 65 |
-
"dev": true
|
| 66 |
-
},
|
| 67 |
"node_modules/@babel/helper-string-parser": {
|
| 68 |
"version": "7.27.1",
|
| 69 |
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
|
|
@@ -112,135 +71,6 @@
|
|
| 112 |
"integrity": "sha512-fdRs9PSrBF7QUntpZpq6BTw58fhgGJojgg39m9oFOJGZT+nip9b0so5cYY1oWl5pvemDLr0cPPsH46vwThEbpQ==",
|
| 113 |
"dev": true
|
| 114 |
},
|
| 115 |
-
"node_modules/@csstools/color-helpers": {
|
| 116 |
-
"version": "5.1.0",
|
| 117 |
-
"resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz",
|
| 118 |
-
"integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==",
|
| 119 |
-
"dev": true,
|
| 120 |
-
"funding": [
|
| 121 |
-
{
|
| 122 |
-
"type": "github",
|
| 123 |
-
"url": "https://github.com/sponsors/csstools"
|
| 124 |
-
},
|
| 125 |
-
{
|
| 126 |
-
"type": "opencollective",
|
| 127 |
-
"url": "https://opencollective.com/csstools"
|
| 128 |
-
}
|
| 129 |
-
],
|
| 130 |
-
"engines": {
|
| 131 |
-
"node": ">=18"
|
| 132 |
-
}
|
| 133 |
-
},
|
| 134 |
-
"node_modules/@csstools/css-calc": {
|
| 135 |
-
"version": "2.1.4",
|
| 136 |
-
"resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz",
|
| 137 |
-
"integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==",
|
| 138 |
-
"dev": true,
|
| 139 |
-
"funding": [
|
| 140 |
-
{
|
| 141 |
-
"type": "github",
|
| 142 |
-
"url": "https://github.com/sponsors/csstools"
|
| 143 |
-
},
|
| 144 |
-
{
|
| 145 |
-
"type": "opencollective",
|
| 146 |
-
"url": "https://opencollective.com/csstools"
|
| 147 |
-
}
|
| 148 |
-
],
|
| 149 |
-
"engines": {
|
| 150 |
-
"node": ">=18"
|
| 151 |
-
},
|
| 152 |
-
"peerDependencies": {
|
| 153 |
-
"@csstools/css-parser-algorithms": "^3.0.5",
|
| 154 |
-
"@csstools/css-tokenizer": "^3.0.4"
|
| 155 |
-
}
|
| 156 |
-
},
|
| 157 |
-
"node_modules/@csstools/css-color-parser": {
|
| 158 |
-
"version": "3.1.0",
|
| 159 |
-
"resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz",
|
| 160 |
-
"integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==",
|
| 161 |
-
"dev": true,
|
| 162 |
-
"funding": [
|
| 163 |
-
{
|
| 164 |
-
"type": "github",
|
| 165 |
-
"url": "https://github.com/sponsors/csstools"
|
| 166 |
-
},
|
| 167 |
-
{
|
| 168 |
-
"type": "opencollective",
|
| 169 |
-
"url": "https://opencollective.com/csstools"
|
| 170 |
-
}
|
| 171 |
-
],
|
| 172 |
-
"dependencies": {
|
| 173 |
-
"@csstools/color-helpers": "^5.1.0",
|
| 174 |
-
"@csstools/css-calc": "^2.1.4"
|
| 175 |
-
},
|
| 176 |
-
"engines": {
|
| 177 |
-
"node": ">=18"
|
| 178 |
-
},
|
| 179 |
-
"peerDependencies": {
|
| 180 |
-
"@csstools/css-parser-algorithms": "^3.0.5",
|
| 181 |
-
"@csstools/css-tokenizer": "^3.0.4"
|
| 182 |
-
}
|
| 183 |
-
},
|
| 184 |
-
"node_modules/@csstools/css-parser-algorithms": {
|
| 185 |
-
"version": "3.0.5",
|
| 186 |
-
"resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz",
|
| 187 |
-
"integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==",
|
| 188 |
-
"dev": true,
|
| 189 |
-
"funding": [
|
| 190 |
-
{
|
| 191 |
-
"type": "github",
|
| 192 |
-
"url": "https://github.com/sponsors/csstools"
|
| 193 |
-
},
|
| 194 |
-
{
|
| 195 |
-
"type": "opencollective",
|
| 196 |
-
"url": "https://opencollective.com/csstools"
|
| 197 |
-
}
|
| 198 |
-
],
|
| 199 |
-
"engines": {
|
| 200 |
-
"node": ">=18"
|
| 201 |
-
},
|
| 202 |
-
"peerDependencies": {
|
| 203 |
-
"@csstools/css-tokenizer": "^3.0.4"
|
| 204 |
-
}
|
| 205 |
-
},
|
| 206 |
-
"node_modules/@csstools/css-syntax-patches-for-csstree": {
|
| 207 |
-
"version": "1.0.15",
|
| 208 |
-
"resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.15.tgz",
|
| 209 |
-
"integrity": "sha512-q0p6zkVq2lJnmzZVPR33doA51G7YOja+FBvRdp5ISIthL0MtFCgYHHhR563z9WFGxcOn0WfjSkPDJ5Qig3H3Sw==",
|
| 210 |
-
"dev": true,
|
| 211 |
-
"funding": [
|
| 212 |
-
{
|
| 213 |
-
"type": "github",
|
| 214 |
-
"url": "https://github.com/sponsors/csstools"
|
| 215 |
-
},
|
| 216 |
-
{
|
| 217 |
-
"type": "opencollective",
|
| 218 |
-
"url": "https://opencollective.com/csstools"
|
| 219 |
-
}
|
| 220 |
-
],
|
| 221 |
-
"engines": {
|
| 222 |
-
"node": ">=18"
|
| 223 |
-
}
|
| 224 |
-
},
|
| 225 |
-
"node_modules/@csstools/css-tokenizer": {
|
| 226 |
-
"version": "3.0.4",
|
| 227 |
-
"resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz",
|
| 228 |
-
"integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==",
|
| 229 |
-
"dev": true,
|
| 230 |
-
"funding": [
|
| 231 |
-
{
|
| 232 |
-
"type": "github",
|
| 233 |
-
"url": "https://github.com/sponsors/csstools"
|
| 234 |
-
},
|
| 235 |
-
{
|
| 236 |
-
"type": "opencollective",
|
| 237 |
-
"url": "https://opencollective.com/csstools"
|
| 238 |
-
}
|
| 239 |
-
],
|
| 240 |
-
"engines": {
|
| 241 |
-
"node": ">=18"
|
| 242 |
-
}
|
| 243 |
-
},
|
| 244 |
"node_modules/@esbuild/aix-ppc64": {
|
| 245 |
"version": "0.21.5",
|
| 246 |
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
|
@@ -513,22 +343,6 @@
|
|
| 513 |
"node": ">=12"
|
| 514 |
}
|
| 515 |
},
|
| 516 |
-
"node_modules/@esbuild/netbsd-arm64": {
|
| 517 |
-
"version": "0.25.12",
|
| 518 |
-
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
|
| 519 |
-
"integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
|
| 520 |
-
"cpu": [
|
| 521 |
-
"arm64"
|
| 522 |
-
],
|
| 523 |
-
"dev": true,
|
| 524 |
-
"optional": true,
|
| 525 |
-
"os": [
|
| 526 |
-
"netbsd"
|
| 527 |
-
],
|
| 528 |
-
"engines": {
|
| 529 |
-
"node": ">=18"
|
| 530 |
-
}
|
| 531 |
-
},
|
| 532 |
"node_modules/@esbuild/netbsd-x64": {
|
| 533 |
"version": "0.21.5",
|
| 534 |
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
|
|
@@ -545,22 +359,6 @@
|
|
| 545 |
"node": ">=12"
|
| 546 |
}
|
| 547 |
},
|
| 548 |
-
"node_modules/@esbuild/openbsd-arm64": {
|
| 549 |
-
"version": "0.25.12",
|
| 550 |
-
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
|
| 551 |
-
"integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
|
| 552 |
-
"cpu": [
|
| 553 |
-
"arm64"
|
| 554 |
-
],
|
| 555 |
-
"dev": true,
|
| 556 |
-
"optional": true,
|
| 557 |
-
"os": [
|
| 558 |
-
"openbsd"
|
| 559 |
-
],
|
| 560 |
-
"engines": {
|
| 561 |
-
"node": ">=18"
|
| 562 |
-
}
|
| 563 |
-
},
|
| 564 |
"node_modules/@esbuild/openbsd-x64": {
|
| 565 |
"version": "0.21.5",
|
| 566 |
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
|
|
@@ -577,22 +375,6 @@
|
|
| 577 |
"node": ">=12"
|
| 578 |
}
|
| 579 |
},
|
| 580 |
-
"node_modules/@esbuild/openharmony-arm64": {
|
| 581 |
-
"version": "0.25.12",
|
| 582 |
-
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
|
| 583 |
-
"integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
|
| 584 |
-
"cpu": [
|
| 585 |
-
"arm64"
|
| 586 |
-
],
|
| 587 |
-
"dev": true,
|
| 588 |
-
"optional": true,
|
| 589 |
-
"os": [
|
| 590 |
-
"openharmony"
|
| 591 |
-
],
|
| 592 |
-
"engines": {
|
| 593 |
-
"node": ">=18"
|
| 594 |
-
}
|
| 595 |
-
},
|
| 596 |
"node_modules/@esbuild/sunos-x64": {
|
| 597 |
"version": "0.21.5",
|
| 598 |
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
|
|
@@ -958,12 +740,6 @@
|
|
| 958 |
"url": "https://opencollective.com/parcel"
|
| 959 |
}
|
| 960 |
},
|
| 961 |
-
"node_modules/@polka/url": {
|
| 962 |
-
"version": "1.0.0-next.29",
|
| 963 |
-
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz",
|
| 964 |
-
"integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==",
|
| 965 |
-
"dev": true
|
| 966 |
-
},
|
| 967 |
"node_modules/@rollup/rollup-android-arm-eabi": {
|
| 968 |
"version": "4.52.5",
|
| 969 |
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz",
|
|
@@ -1255,34 +1031,23 @@
|
|
| 1255 |
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
|
| 1256 |
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="
|
| 1257 |
},
|
| 1258 |
-
"node_modules/@standard-schema/spec": {
|
| 1259 |
-
"version": "1.0.0",
|
| 1260 |
-
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
|
| 1261 |
-
"integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
|
| 1262 |
-
"dev": true
|
| 1263 |
-
},
|
| 1264 |
-
"node_modules/@types/chai": {
|
| 1265 |
-
"version": "5.2.3",
|
| 1266 |
-
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz",
|
| 1267 |
-
"integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==",
|
| 1268 |
-
"dev": true,
|
| 1269 |
-
"dependencies": {
|
| 1270 |
-
"@types/deep-eql": "*",
|
| 1271 |
-
"assertion-error": "^2.0.1"
|
| 1272 |
-
}
|
| 1273 |
-
},
|
| 1274 |
-
"node_modules/@types/deep-eql": {
|
| 1275 |
-
"version": "4.0.2",
|
| 1276 |
-
"resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
|
| 1277 |
-
"integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
|
| 1278 |
-
"dev": true
|
| 1279 |
-
},
|
| 1280 |
"node_modules/@types/estree": {
|
| 1281 |
"version": "1.0.8",
|
| 1282 |
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
| 1283 |
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
| 1284 |
"dev": true
|
| 1285 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1286 |
"node_modules/@types/stats.js": {
|
| 1287 |
"version": "0.17.4",
|
| 1288 |
"resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz",
|
|
@@ -1320,111 +1085,6 @@
|
|
| 1320 |
"vue": "^3.2.25"
|
| 1321 |
}
|
| 1322 |
},
|
| 1323 |
-
"node_modules/@vitest/expect": {
|
| 1324 |
-
"version": "4.0.6",
|
| 1325 |
-
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.6.tgz",
|
| 1326 |
-
"integrity": "sha512-5j8UUlBVhOjhj4lR2Nt9sEV8b4WtbcYh8vnfhTNA2Kn5+smtevzjNq+xlBuVhnFGXiyPPNzGrOVvmyHWkS5QGg==",
|
| 1327 |
-
"dev": true,
|
| 1328 |
-
"dependencies": {
|
| 1329 |
-
"@standard-schema/spec": "^1.0.0",
|
| 1330 |
-
"@types/chai": "^5.2.2",
|
| 1331 |
-
"@vitest/spy": "4.0.6",
|
| 1332 |
-
"@vitest/utils": "4.0.6",
|
| 1333 |
-
"chai": "^6.0.1",
|
| 1334 |
-
"tinyrainbow": "^3.0.3"
|
| 1335 |
-
},
|
| 1336 |
-
"funding": {
|
| 1337 |
-
"url": "https://opencollective.com/vitest"
|
| 1338 |
-
}
|
| 1339 |
-
},
|
| 1340 |
-
"node_modules/@vitest/pretty-format": {
|
| 1341 |
-
"version": "4.0.6",
|
| 1342 |
-
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.6.tgz",
|
| 1343 |
-
"integrity": "sha512-4vptgNkLIA1W1Nn5X4x8rLJBzPiJwnPc+awKtfBE5hNMVsoAl/JCCPPzNrbf+L4NKgklsis5Yp2gYa+XAS442g==",
|
| 1344 |
-
"dev": true,
|
| 1345 |
-
"dependencies": {
|
| 1346 |
-
"tinyrainbow": "^3.0.3"
|
| 1347 |
-
},
|
| 1348 |
-
"funding": {
|
| 1349 |
-
"url": "https://opencollective.com/vitest"
|
| 1350 |
-
}
|
| 1351 |
-
},
|
| 1352 |
-
"node_modules/@vitest/runner": {
|
| 1353 |
-
"version": "4.0.6",
|
| 1354 |
-
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.6.tgz",
|
| 1355 |
-
"integrity": "sha512-trPk5qpd7Jj+AiLZbV/e+KiiaGXZ8ECsRxtnPnCrJr9OW2mLB72Cb824IXgxVz/mVU3Aj4VebY+tDTPn++j1Og==",
|
| 1356 |
-
"dev": true,
|
| 1357 |
-
"dependencies": {
|
| 1358 |
-
"@vitest/utils": "4.0.6",
|
| 1359 |
-
"pathe": "^2.0.3"
|
| 1360 |
-
},
|
| 1361 |
-
"funding": {
|
| 1362 |
-
"url": "https://opencollective.com/vitest"
|
| 1363 |
-
}
|
| 1364 |
-
},
|
| 1365 |
-
"node_modules/@vitest/snapshot": {
|
| 1366 |
-
"version": "4.0.6",
|
| 1367 |
-
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.6.tgz",
|
| 1368 |
-
"integrity": "sha512-PaYLt7n2YzuvxhulDDu6c9EosiRuIE+FI2ECKs6yvHyhoga+2TBWI8dwBjs+IeuQaMtZTfioa9tj3uZb7nev1g==",
|
| 1369 |
-
"dev": true,
|
| 1370 |
-
"dependencies": {
|
| 1371 |
-
"@vitest/pretty-format": "4.0.6",
|
| 1372 |
-
"magic-string": "^0.30.19",
|
| 1373 |
-
"pathe": "^2.0.3"
|
| 1374 |
-
},
|
| 1375 |
-
"funding": {
|
| 1376 |
-
"url": "https://opencollective.com/vitest"
|
| 1377 |
-
}
|
| 1378 |
-
},
|
| 1379 |
-
"node_modules/@vitest/spy": {
|
| 1380 |
-
"version": "4.0.6",
|
| 1381 |
-
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.6.tgz",
|
| 1382 |
-
"integrity": "sha512-g9jTUYPV1LtRPRCQfhbMintW7BTQz1n6WXYQYRQ25qkyffA4bjVXjkROokZnv7t07OqfaFKw1lPzqKGk1hmNuQ==",
|
| 1383 |
-
"dev": true,
|
| 1384 |
-
"funding": {
|
| 1385 |
-
"url": "https://opencollective.com/vitest"
|
| 1386 |
-
}
|
| 1387 |
-
},
|
| 1388 |
-
"node_modules/@vitest/ui": {
|
| 1389 |
-
"version": "4.0.6",
|
| 1390 |
-
"resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-4.0.6.tgz",
|
| 1391 |
-
"integrity": "sha512-1ekpBsYNUm0Xv/0YsTvoSRmiRkmzz9Pma7qQ3Ui76sg2gwp2/ewSWqx4W/HfaN5dF0E8iBbidFo1wGaeqXYIrQ==",
|
| 1392 |
-
"dev": true,
|
| 1393 |
-
"dependencies": {
|
| 1394 |
-
"@vitest/utils": "4.0.6",
|
| 1395 |
-
"fflate": "^0.8.2",
|
| 1396 |
-
"flatted": "^3.3.3",
|
| 1397 |
-
"pathe": "^2.0.3",
|
| 1398 |
-
"sirv": "^3.0.2",
|
| 1399 |
-
"tinyglobby": "^0.2.15",
|
| 1400 |
-
"tinyrainbow": "^3.0.3"
|
| 1401 |
-
},
|
| 1402 |
-
"funding": {
|
| 1403 |
-
"url": "https://opencollective.com/vitest"
|
| 1404 |
-
},
|
| 1405 |
-
"peerDependencies": {
|
| 1406 |
-
"vitest": "4.0.6"
|
| 1407 |
-
}
|
| 1408 |
-
},
|
| 1409 |
-
"node_modules/@vitest/ui/node_modules/fflate": {
|
| 1410 |
-
"version": "0.8.2",
|
| 1411 |
-
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
|
| 1412 |
-
"integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
|
| 1413 |
-
"dev": true
|
| 1414 |
-
},
|
| 1415 |
-
"node_modules/@vitest/utils": {
|
| 1416 |
-
"version": "4.0.6",
|
| 1417 |
-
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.6.tgz",
|
| 1418 |
-
"integrity": "sha512-bG43VS3iYKrMIZXBo+y8Pti0O7uNju3KvNn6DrQWhQQKcLavMB+0NZfO1/QBAEbq0MaQ3QjNsnnXlGQvsh0Z6A==",
|
| 1419 |
-
"dev": true,
|
| 1420 |
-
"dependencies": {
|
| 1421 |
-
"@vitest/pretty-format": "4.0.6",
|
| 1422 |
-
"tinyrainbow": "^3.0.3"
|
| 1423 |
-
},
|
| 1424 |
-
"funding": {
|
| 1425 |
-
"url": "https://opencollective.com/vitest"
|
| 1426 |
-
}
|
| 1427 |
-
},
|
| 1428 |
"node_modules/@volar/language-core": {
|
| 1429 |
"version": "2.4.15",
|
| 1430 |
"resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.15.tgz",
|
|
@@ -1581,45 +1241,18 @@
|
|
| 1581 |
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.22.tgz",
|
| 1582 |
"integrity": "sha512-F4yc6palwq3TT0u+FYf0Ns4Tfl9GRFURDN2gWG7L1ecIaS/4fCIuFOjMTnCyjsu/OK6vaDKLCrGAa+KvvH+h4w=="
|
| 1583 |
},
|
| 1584 |
-
"node_modules/agent-base": {
|
| 1585 |
-
"version": "7.1.4",
|
| 1586 |
-
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
|
| 1587 |
-
"integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
|
| 1588 |
-
"dev": true,
|
| 1589 |
-
"engines": {
|
| 1590 |
-
"node": ">= 14"
|
| 1591 |
-
}
|
| 1592 |
-
},
|
| 1593 |
"node_modules/alien-signals": {
|
| 1594 |
"version": "1.0.13",
|
| 1595 |
"resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-1.0.13.tgz",
|
| 1596 |
"integrity": "sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==",
|
| 1597 |
"dev": true
|
| 1598 |
},
|
| 1599 |
-
"node_modules/assertion-error": {
|
| 1600 |
-
"version": "2.0.1",
|
| 1601 |
-
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
|
| 1602 |
-
"integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
|
| 1603 |
-
"dev": true,
|
| 1604 |
-
"engines": {
|
| 1605 |
-
"node": ">=12"
|
| 1606 |
-
}
|
| 1607 |
-
},
|
| 1608 |
"node_modules/balanced-match": {
|
| 1609 |
"version": "1.0.2",
|
| 1610 |
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
| 1611 |
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
| 1612 |
"dev": true
|
| 1613 |
},
|
| 1614 |
-
"node_modules/bidi-js": {
|
| 1615 |
-
"version": "1.0.3",
|
| 1616 |
-
"resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz",
|
| 1617 |
-
"integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==",
|
| 1618 |
-
"dev": true,
|
| 1619 |
-
"dependencies": {
|
| 1620 |
-
"require-from-string": "^2.0.2"
|
| 1621 |
-
}
|
| 1622 |
-
},
|
| 1623 |
"node_modules/brace-expansion": {
|
| 1624 |
"version": "2.0.2",
|
| 1625 |
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
|
@@ -1648,15 +1281,6 @@
|
|
| 1648 |
"integrity": "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==",
|
| 1649 |
"dev": true
|
| 1650 |
},
|
| 1651 |
-
"node_modules/chai": {
|
| 1652 |
-
"version": "6.2.0",
|
| 1653 |
-
"resolved": "https://registry.npmjs.org/chai/-/chai-6.2.0.tgz",
|
| 1654 |
-
"integrity": "sha512-aUTnJc/JipRzJrNADXVvpVqi6CO0dn3nx4EVPxijri+fj3LUUDyZQOgVeW54Ob3Y1Xh9Iz8f+CgaCl8v0mn9bA==",
|
| 1655 |
-
"dev": true,
|
| 1656 |
-
"engines": {
|
| 1657 |
-
"node": ">=18"
|
| 1658 |
-
}
|
| 1659 |
-
},
|
| 1660 |
"node_modules/chokidar": {
|
| 1661 |
"version": "4.0.3",
|
| 1662 |
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
|
@@ -1679,51 +1303,11 @@
|
|
| 1679 |
"integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==",
|
| 1680 |
"dev": true
|
| 1681 |
},
|
| 1682 |
-
"node_modules/css-tree": {
|
| 1683 |
-
"version": "3.1.0",
|
| 1684 |
-
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz",
|
| 1685 |
-
"integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==",
|
| 1686 |
-
"dev": true,
|
| 1687 |
-
"dependencies": {
|
| 1688 |
-
"mdn-data": "2.12.2",
|
| 1689 |
-
"source-map-js": "^1.0.1"
|
| 1690 |
-
},
|
| 1691 |
-
"engines": {
|
| 1692 |
-
"node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
|
| 1693 |
-
}
|
| 1694 |
-
},
|
| 1695 |
-
"node_modules/cssstyle": {
|
| 1696 |
-
"version": "5.3.2",
|
| 1697 |
-
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.2.tgz",
|
| 1698 |
-
"integrity": "sha512-zDMqXh8Vs1CdRYZQ2M633m/SFgcjlu8RB8b/1h82i+6vpArF507NSYIWJHGlJaTWoS+imcnctmEz43txhbVkOw==",
|
| 1699 |
-
"dev": true,
|
| 1700 |
-
"dependencies": {
|
| 1701 |
-
"@asamuzakjp/css-color": "^4.0.3",
|
| 1702 |
-
"@csstools/css-syntax-patches-for-csstree": "^1.0.14",
|
| 1703 |
-
"css-tree": "^3.1.0"
|
| 1704 |
-
},
|
| 1705 |
-
"engines": {
|
| 1706 |
-
"node": ">=20"
|
| 1707 |
-
}
|
| 1708 |
-
},
|
| 1709 |
"node_modules/csstype": {
|
| 1710 |
"version": "3.1.3",
|
| 1711 |
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
| 1712 |
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
|
| 1713 |
},
|
| 1714 |
-
"node_modules/data-urls": {
|
| 1715 |
-
"version": "6.0.0",
|
| 1716 |
-
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-6.0.0.tgz",
|
| 1717 |
-
"integrity": "sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==",
|
| 1718 |
-
"dev": true,
|
| 1719 |
-
"dependencies": {
|
| 1720 |
-
"whatwg-mimetype": "^4.0.0",
|
| 1721 |
-
"whatwg-url": "^15.0.0"
|
| 1722 |
-
},
|
| 1723 |
-
"engines": {
|
| 1724 |
-
"node": ">=20"
|
| 1725 |
-
}
|
| 1726 |
-
},
|
| 1727 |
"node_modules/de-indent": {
|
| 1728 |
"version": "1.0.2",
|
| 1729 |
"resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
|
|
@@ -1746,12 +1330,6 @@
|
|
| 1746 |
}
|
| 1747 |
}
|
| 1748 |
},
|
| 1749 |
-
"node_modules/decimal.js": {
|
| 1750 |
-
"version": "10.6.0",
|
| 1751 |
-
"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz",
|
| 1752 |
-
"integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==",
|
| 1753 |
-
"dev": true
|
| 1754 |
-
},
|
| 1755 |
"node_modules/detect-libc": {
|
| 1756 |
"version": "1.0.3",
|
| 1757 |
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
|
@@ -1796,12 +1374,6 @@
|
|
| 1796 |
"url": "https://github.com/fb55/entities?sponsor=1"
|
| 1797 |
}
|
| 1798 |
},
|
| 1799 |
-
"node_modules/es-module-lexer": {
|
| 1800 |
-
"version": "1.7.0",
|
| 1801 |
-
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
|
| 1802 |
-
"integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
|
| 1803 |
-
"dev": true
|
| 1804 |
-
},
|
| 1805 |
"node_modules/esbuild": {
|
| 1806 |
"version": "0.21.5",
|
| 1807 |
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
|
|
@@ -1845,15 +1417,6 @@
|
|
| 1845 |
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
| 1846 |
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
|
| 1847 |
},
|
| 1848 |
-
"node_modules/expect-type": {
|
| 1849 |
-
"version": "1.2.2",
|
| 1850 |
-
"resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz",
|
| 1851 |
-
"integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==",
|
| 1852 |
-
"dev": true,
|
| 1853 |
-
"engines": {
|
| 1854 |
-
"node": ">=12.0.0"
|
| 1855 |
-
}
|
| 1856 |
-
},
|
| 1857 |
"node_modules/fflate": {
|
| 1858 |
"version": "0.6.10",
|
| 1859 |
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz",
|
|
@@ -1873,12 +1436,6 @@
|
|
| 1873 |
"node": ">=8"
|
| 1874 |
}
|
| 1875 |
},
|
| 1876 |
-
"node_modules/flatted": {
|
| 1877 |
-
"version": "3.3.3",
|
| 1878 |
-
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
|
| 1879 |
-
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
|
| 1880 |
-
"dev": true
|
| 1881 |
-
},
|
| 1882 |
"node_modules/fsevents": {
|
| 1883 |
"version": "2.3.3",
|
| 1884 |
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
|
@@ -1911,80 +1468,30 @@
|
|
| 1911 |
"he": "bin/he"
|
| 1912 |
}
|
| 1913 |
},
|
| 1914 |
-
"node_modules/
|
| 1915 |
-
"version": "
|
| 1916 |
-
"resolved": "https://registry.npmjs.org/
|
| 1917 |
-
"integrity": "sha512-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1918 |
"dev": true,
|
| 1919 |
-
"
|
| 1920 |
-
"whatwg-encoding": "^3.1.1"
|
| 1921 |
-
},
|
| 1922 |
"engines": {
|
| 1923 |
-
"node": ">=
|
| 1924 |
}
|
| 1925 |
},
|
| 1926 |
-
"node_modules/
|
| 1927 |
-
"version": "
|
| 1928 |
-
"resolved": "https://registry.npmjs.org/
|
| 1929 |
-
"integrity": "sha512-
|
| 1930 |
"dev": true,
|
|
|
|
| 1931 |
"dependencies": {
|
| 1932 |
-
"
|
| 1933 |
-
"debug": "^4.3.4"
|
| 1934 |
-
},
|
| 1935 |
-
"engines": {
|
| 1936 |
-
"node": ">= 14"
|
| 1937 |
-
}
|
| 1938 |
-
},
|
| 1939 |
-
"node_modules/https-proxy-agent": {
|
| 1940 |
-
"version": "7.0.6",
|
| 1941 |
-
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
|
| 1942 |
-
"integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
|
| 1943 |
-
"dev": true,
|
| 1944 |
-
"dependencies": {
|
| 1945 |
-
"agent-base": "^7.1.2",
|
| 1946 |
-
"debug": "4"
|
| 1947 |
-
},
|
| 1948 |
-
"engines": {
|
| 1949 |
-
"node": ">= 14"
|
| 1950 |
-
}
|
| 1951 |
-
},
|
| 1952 |
-
"node_modules/iconv-lite": {
|
| 1953 |
-
"version": "0.6.3",
|
| 1954 |
-
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
| 1955 |
-
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
| 1956 |
-
"dev": true,
|
| 1957 |
-
"dependencies": {
|
| 1958 |
-
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
| 1959 |
-
},
|
| 1960 |
-
"engines": {
|
| 1961 |
-
"node": ">=0.10.0"
|
| 1962 |
-
}
|
| 1963 |
-
},
|
| 1964 |
-
"node_modules/immutable": {
|
| 1965 |
-
"version": "5.1.4",
|
| 1966 |
-
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz",
|
| 1967 |
-
"integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==",
|
| 1968 |
-
"dev": true
|
| 1969 |
-
},
|
| 1970 |
-
"node_modules/is-extglob": {
|
| 1971 |
-
"version": "2.1.1",
|
| 1972 |
-
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
| 1973 |
-
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
| 1974 |
-
"dev": true,
|
| 1975 |
-
"optional": true,
|
| 1976 |
-
"engines": {
|
| 1977 |
-
"node": ">=0.10.0"
|
| 1978 |
-
}
|
| 1979 |
-
},
|
| 1980 |
-
"node_modules/is-glob": {
|
| 1981 |
-
"version": "4.0.3",
|
| 1982 |
-
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
| 1983 |
-
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
| 1984 |
-
"dev": true,
|
| 1985 |
-
"optional": true,
|
| 1986 |
-
"dependencies": {
|
| 1987 |
-
"is-extglob": "^2.1.1"
|
| 1988 |
},
|
| 1989 |
"engines": {
|
| 1990 |
"node": ">=0.10.0"
|
|
@@ -2000,81 +1507,6 @@
|
|
| 2000 |
"node": ">=0.12.0"
|
| 2001 |
}
|
| 2002 |
},
|
| 2003 |
-
"node_modules/is-potential-custom-element-name": {
|
| 2004 |
-
"version": "1.0.1",
|
| 2005 |
-
"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
|
| 2006 |
-
"integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
|
| 2007 |
-
"dev": true
|
| 2008 |
-
},
|
| 2009 |
-
"node_modules/jsdom": {
|
| 2010 |
-
"version": "27.1.0",
|
| 2011 |
-
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.1.0.tgz",
|
| 2012 |
-
"integrity": "sha512-Pcfm3eZ+eO4JdZCXthW9tCDT3nF4K+9dmeZ+5X39n+Kqz0DDIABRP5CAEOHRFZk8RGuC2efksTJxrjp8EXCunQ==",
|
| 2013 |
-
"dev": true,
|
| 2014 |
-
"dependencies": {
|
| 2015 |
-
"@acemir/cssom": "^0.9.19",
|
| 2016 |
-
"@asamuzakjp/dom-selector": "^6.7.3",
|
| 2017 |
-
"cssstyle": "^5.3.2",
|
| 2018 |
-
"data-urls": "^6.0.0",
|
| 2019 |
-
"decimal.js": "^10.6.0",
|
| 2020 |
-
"html-encoding-sniffer": "^4.0.0",
|
| 2021 |
-
"http-proxy-agent": "^7.0.2",
|
| 2022 |
-
"https-proxy-agent": "^7.0.6",
|
| 2023 |
-
"is-potential-custom-element-name": "^1.0.1",
|
| 2024 |
-
"parse5": "^8.0.0",
|
| 2025 |
-
"saxes": "^6.0.0",
|
| 2026 |
-
"symbol-tree": "^3.2.4",
|
| 2027 |
-
"tough-cookie": "^6.0.0",
|
| 2028 |
-
"w3c-xmlserializer": "^5.0.0",
|
| 2029 |
-
"webidl-conversions": "^8.0.0",
|
| 2030 |
-
"whatwg-encoding": "^3.1.1",
|
| 2031 |
-
"whatwg-mimetype": "^4.0.0",
|
| 2032 |
-
"whatwg-url": "^15.1.0",
|
| 2033 |
-
"ws": "^8.18.3",
|
| 2034 |
-
"xml-name-validator": "^5.0.0"
|
| 2035 |
-
},
|
| 2036 |
-
"engines": {
|
| 2037 |
-
"node": "^20.19.0 || ^22.12.0 || >=24.0.0"
|
| 2038 |
-
},
|
| 2039 |
-
"peerDependencies": {
|
| 2040 |
-
"canvas": "^3.0.0"
|
| 2041 |
-
},
|
| 2042 |
-
"peerDependenciesMeta": {
|
| 2043 |
-
"canvas": {
|
| 2044 |
-
"optional": true
|
| 2045 |
-
}
|
| 2046 |
-
}
|
| 2047 |
-
},
|
| 2048 |
-
"node_modules/jsdom/node_modules/ws": {
|
| 2049 |
-
"version": "8.18.3",
|
| 2050 |
-
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
|
| 2051 |
-
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
|
| 2052 |
-
"dev": true,
|
| 2053 |
-
"engines": {
|
| 2054 |
-
"node": ">=10.0.0"
|
| 2055 |
-
},
|
| 2056 |
-
"peerDependencies": {
|
| 2057 |
-
"bufferutil": "^4.0.1",
|
| 2058 |
-
"utf-8-validate": ">=5.0.2"
|
| 2059 |
-
},
|
| 2060 |
-
"peerDependenciesMeta": {
|
| 2061 |
-
"bufferutil": {
|
| 2062 |
-
"optional": true
|
| 2063 |
-
},
|
| 2064 |
-
"utf-8-validate": {
|
| 2065 |
-
"optional": true
|
| 2066 |
-
}
|
| 2067 |
-
}
|
| 2068 |
-
},
|
| 2069 |
-
"node_modules/lru-cache": {
|
| 2070 |
-
"version": "11.2.2",
|
| 2071 |
-
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz",
|
| 2072 |
-
"integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==",
|
| 2073 |
-
"dev": true,
|
| 2074 |
-
"engines": {
|
| 2075 |
-
"node": "20 || >=22"
|
| 2076 |
-
}
|
| 2077 |
-
},
|
| 2078 |
"node_modules/magic-string": {
|
| 2079 |
"version": "0.30.19",
|
| 2080 |
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz",
|
|
@@ -2083,12 +1515,6 @@
|
|
| 2083 |
"@jridgewell/sourcemap-codec": "^1.5.5"
|
| 2084 |
}
|
| 2085 |
},
|
| 2086 |
-
"node_modules/mdn-data": {
|
| 2087 |
-
"version": "2.12.2",
|
| 2088 |
-
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz",
|
| 2089 |
-
"integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==",
|
| 2090 |
-
"dev": true
|
| 2091 |
-
},
|
| 2092 |
"node_modules/meshoptimizer": {
|
| 2093 |
"version": "0.18.1",
|
| 2094 |
"resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz",
|
|
@@ -2124,15 +1550,6 @@
|
|
| 2124 |
"url": "https://github.com/sponsors/isaacs"
|
| 2125 |
}
|
| 2126 |
},
|
| 2127 |
-
"node_modules/mrmime": {
|
| 2128 |
-
"version": "2.0.1",
|
| 2129 |
-
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
|
| 2130 |
-
"integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==",
|
| 2131 |
-
"dev": true,
|
| 2132 |
-
"engines": {
|
| 2133 |
-
"node": ">=10"
|
| 2134 |
-
}
|
| 2135 |
-
},
|
| 2136 |
"node_modules/ms": {
|
| 2137 |
"version": "2.1.3",
|
| 2138 |
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
|
@@ -2168,42 +1585,12 @@
|
|
| 2168 |
"dev": true,
|
| 2169 |
"optional": true
|
| 2170 |
},
|
| 2171 |
-
"node_modules/parse5": {
|
| 2172 |
-
"version": "8.0.0",
|
| 2173 |
-
"resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz",
|
| 2174 |
-
"integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==",
|
| 2175 |
-
"dev": true,
|
| 2176 |
-
"dependencies": {
|
| 2177 |
-
"entities": "^6.0.0"
|
| 2178 |
-
},
|
| 2179 |
-
"funding": {
|
| 2180 |
-
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
| 2181 |
-
}
|
| 2182 |
-
},
|
| 2183 |
-
"node_modules/parse5/node_modules/entities": {
|
| 2184 |
-
"version": "6.0.1",
|
| 2185 |
-
"resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
|
| 2186 |
-
"integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
|
| 2187 |
-
"dev": true,
|
| 2188 |
-
"engines": {
|
| 2189 |
-
"node": ">=0.12"
|
| 2190 |
-
},
|
| 2191 |
-
"funding": {
|
| 2192 |
-
"url": "https://github.com/fb55/entities?sponsor=1"
|
| 2193 |
-
}
|
| 2194 |
-
},
|
| 2195 |
"node_modules/path-browserify": {
|
| 2196 |
"version": "1.0.1",
|
| 2197 |
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
|
| 2198 |
"integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
|
| 2199 |
"dev": true
|
| 2200 |
},
|
| 2201 |
-
"node_modules/pathe": {
|
| 2202 |
-
"version": "2.0.3",
|
| 2203 |
-
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
|
| 2204 |
-
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
|
| 2205 |
-
"dev": true
|
| 2206 |
-
},
|
| 2207 |
"node_modules/picocolors": {
|
| 2208 |
"version": "1.1.1",
|
| 2209 |
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
|
@@ -2270,15 +1657,6 @@
|
|
| 2270 |
"node": "^10 || ^12 || >=14"
|
| 2271 |
}
|
| 2272 |
},
|
| 2273 |
-
"node_modules/punycode": {
|
| 2274 |
-
"version": "2.3.1",
|
| 2275 |
-
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
| 2276 |
-
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
|
| 2277 |
-
"dev": true,
|
| 2278 |
-
"engines": {
|
| 2279 |
-
"node": ">=6"
|
| 2280 |
-
}
|
| 2281 |
-
},
|
| 2282 |
"node_modules/readdirp": {
|
| 2283 |
"version": "4.1.2",
|
| 2284 |
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
|
@@ -2293,15 +1671,6 @@
|
|
| 2293 |
"url": "https://paulmillr.com/funding/"
|
| 2294 |
}
|
| 2295 |
},
|
| 2296 |
-
"node_modules/require-from-string": {
|
| 2297 |
-
"version": "2.0.2",
|
| 2298 |
-
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
| 2299 |
-
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
|
| 2300 |
-
"dev": true,
|
| 2301 |
-
"engines": {
|
| 2302 |
-
"node": ">=0.10.0"
|
| 2303 |
-
}
|
| 2304 |
-
},
|
| 2305 |
"node_modules/rollup": {
|
| 2306 |
"version": "4.52.5",
|
| 2307 |
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz",
|
|
@@ -2352,12 +1721,6 @@
|
|
| 2352 |
"tslib": "^2.1.0"
|
| 2353 |
}
|
| 2354 |
},
|
| 2355 |
-
"node_modules/safer-buffer": {
|
| 2356 |
-
"version": "2.1.2",
|
| 2357 |
-
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
| 2358 |
-
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
| 2359 |
-
"dev": true
|
| 2360 |
-
},
|
| 2361 |
"node_modules/sass": {
|
| 2362 |
"version": "1.93.2",
|
| 2363 |
"resolved": "https://registry.npmjs.org/sass/-/sass-1.93.2.tgz",
|
|
@@ -2709,38 +2072,6 @@
|
|
| 2709 |
"node": ">=14.0.0"
|
| 2710 |
}
|
| 2711 |
},
|
| 2712 |
-
"node_modules/saxes": {
|
| 2713 |
-
"version": "6.0.0",
|
| 2714 |
-
"resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
|
| 2715 |
-
"integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
|
| 2716 |
-
"dev": true,
|
| 2717 |
-
"dependencies": {
|
| 2718 |
-
"xmlchars": "^2.2.0"
|
| 2719 |
-
},
|
| 2720 |
-
"engines": {
|
| 2721 |
-
"node": ">=v12.22.7"
|
| 2722 |
-
}
|
| 2723 |
-
},
|
| 2724 |
-
"node_modules/siginfo": {
|
| 2725 |
-
"version": "2.0.0",
|
| 2726 |
-
"resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
|
| 2727 |
-
"integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
|
| 2728 |
-
"dev": true
|
| 2729 |
-
},
|
| 2730 |
-
"node_modules/sirv": {
|
| 2731 |
-
"version": "3.0.2",
|
| 2732 |
-
"resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz",
|
| 2733 |
-
"integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==",
|
| 2734 |
-
"dev": true,
|
| 2735 |
-
"dependencies": {
|
| 2736 |
-
"@polka/url": "^1.0.0-next.24",
|
| 2737 |
-
"mrmime": "^2.0.0",
|
| 2738 |
-
"totalist": "^3.0.0"
|
| 2739 |
-
},
|
| 2740 |
-
"engines": {
|
| 2741 |
-
"node": ">=18"
|
| 2742 |
-
}
|
| 2743 |
-
},
|
| 2744 |
"node_modules/socket.io-client": {
|
| 2745 |
"version": "4.8.1",
|
| 2746 |
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz",
|
|
@@ -2775,18 +2106,6 @@
|
|
| 2775 |
"node": ">=0.10.0"
|
| 2776 |
}
|
| 2777 |
},
|
| 2778 |
-
"node_modules/stackback": {
|
| 2779 |
-
"version": "0.0.2",
|
| 2780 |
-
"resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
|
| 2781 |
-
"integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
|
| 2782 |
-
"dev": true
|
| 2783 |
-
},
|
| 2784 |
-
"node_modules/std-env": {
|
| 2785 |
-
"version": "3.10.0",
|
| 2786 |
-
"resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz",
|
| 2787 |
-
"integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==",
|
| 2788 |
-
"dev": true
|
| 2789 |
-
},
|
| 2790 |
"node_modules/supports-color": {
|
| 2791 |
"version": "8.1.1",
|
| 2792 |
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
|
@@ -2802,12 +2121,6 @@
|
|
| 2802 |
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
| 2803 |
}
|
| 2804 |
},
|
| 2805 |
-
"node_modules/symbol-tree": {
|
| 2806 |
-
"version": "3.2.4",
|
| 2807 |
-
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
|
| 2808 |
-
"integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
|
| 2809 |
-
"dev": true
|
| 2810 |
-
},
|
| 2811 |
"node_modules/sync-child-process": {
|
| 2812 |
"version": "1.0.2",
|
| 2813 |
"resolved": "https://registry.npmjs.org/sync-child-process/-/sync-child-process-1.0.2.tgz",
|
|
@@ -2834,90 +2147,6 @@
|
|
| 2834 |
"resolved": "https://registry.npmjs.org/three/-/three-0.156.1.tgz",
|
| 2835 |
"integrity": "sha512-kP7H0FK9d/k6t/XvQ9FO6i+QrePoDcNhwl0I02+wmUJRNSLCUIDMcfObnzQvxb37/0Uc9TDT0T1HgsRRrO6SYQ=="
|
| 2836 |
},
|
| 2837 |
-
"node_modules/tinybench": {
|
| 2838 |
-
"version": "2.9.0",
|
| 2839 |
-
"resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
|
| 2840 |
-
"integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
|
| 2841 |
-
"dev": true
|
| 2842 |
-
},
|
| 2843 |
-
"node_modules/tinyexec": {
|
| 2844 |
-
"version": "0.3.2",
|
| 2845 |
-
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
|
| 2846 |
-
"integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
|
| 2847 |
-
"dev": true
|
| 2848 |
-
},
|
| 2849 |
-
"node_modules/tinyglobby": {
|
| 2850 |
-
"version": "0.2.15",
|
| 2851 |
-
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
| 2852 |
-
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
|
| 2853 |
-
"dev": true,
|
| 2854 |
-
"dependencies": {
|
| 2855 |
-
"fdir": "^6.5.0",
|
| 2856 |
-
"picomatch": "^4.0.3"
|
| 2857 |
-
},
|
| 2858 |
-
"engines": {
|
| 2859 |
-
"node": ">=12.0.0"
|
| 2860 |
-
},
|
| 2861 |
-
"funding": {
|
| 2862 |
-
"url": "https://github.com/sponsors/SuperchupuDev"
|
| 2863 |
-
}
|
| 2864 |
-
},
|
| 2865 |
-
"node_modules/tinyglobby/node_modules/fdir": {
|
| 2866 |
-
"version": "6.5.0",
|
| 2867 |
-
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
| 2868 |
-
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
| 2869 |
-
"dev": true,
|
| 2870 |
-
"engines": {
|
| 2871 |
-
"node": ">=12.0.0"
|
| 2872 |
-
},
|
| 2873 |
-
"peerDependencies": {
|
| 2874 |
-
"picomatch": "^3 || ^4"
|
| 2875 |
-
},
|
| 2876 |
-
"peerDependenciesMeta": {
|
| 2877 |
-
"picomatch": {
|
| 2878 |
-
"optional": true
|
| 2879 |
-
}
|
| 2880 |
-
}
|
| 2881 |
-
},
|
| 2882 |
-
"node_modules/tinyglobby/node_modules/picomatch": {
|
| 2883 |
-
"version": "4.0.3",
|
| 2884 |
-
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
| 2885 |
-
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
| 2886 |
-
"dev": true,
|
| 2887 |
-
"engines": {
|
| 2888 |
-
"node": ">=12"
|
| 2889 |
-
},
|
| 2890 |
-
"funding": {
|
| 2891 |
-
"url": "https://github.com/sponsors/jonschlinkert"
|
| 2892 |
-
}
|
| 2893 |
-
},
|
| 2894 |
-
"node_modules/tinyrainbow": {
|
| 2895 |
-
"version": "3.0.3",
|
| 2896 |
-
"resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz",
|
| 2897 |
-
"integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==",
|
| 2898 |
-
"dev": true,
|
| 2899 |
-
"engines": {
|
| 2900 |
-
"node": ">=14.0.0"
|
| 2901 |
-
}
|
| 2902 |
-
},
|
| 2903 |
-
"node_modules/tldts": {
|
| 2904 |
-
"version": "7.0.17",
|
| 2905 |
-
"resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.17.tgz",
|
| 2906 |
-
"integrity": "sha512-Y1KQBgDd/NUc+LfOtKS6mNsC9CCaH+m2P1RoIZy7RAPo3C3/t8X45+zgut31cRZtZ3xKPjfn3TkGTrctC2TQIQ==",
|
| 2907 |
-
"dev": true,
|
| 2908 |
-
"dependencies": {
|
| 2909 |
-
"tldts-core": "^7.0.17"
|
| 2910 |
-
},
|
| 2911 |
-
"bin": {
|
| 2912 |
-
"tldts": "bin/cli.js"
|
| 2913 |
-
}
|
| 2914 |
-
},
|
| 2915 |
-
"node_modules/tldts-core": {
|
| 2916 |
-
"version": "7.0.17",
|
| 2917 |
-
"resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.17.tgz",
|
| 2918 |
-
"integrity": "sha512-DieYoGrP78PWKsrXr8MZwtQ7GLCUeLxihtjC1jZsW1DnvSMdKPitJSe8OSYDM2u5H6g3kWJZpePqkp43TfLh0g==",
|
| 2919 |
-
"dev": true
|
| 2920 |
-
},
|
| 2921 |
"node_modules/to-regex-range": {
|
| 2922 |
"version": "5.0.1",
|
| 2923 |
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
|
@@ -2931,39 +2160,6 @@
|
|
| 2931 |
"node": ">=8.0"
|
| 2932 |
}
|
| 2933 |
},
|
| 2934 |
-
"node_modules/totalist": {
|
| 2935 |
-
"version": "3.0.1",
|
| 2936 |
-
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
|
| 2937 |
-
"integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
|
| 2938 |
-
"dev": true,
|
| 2939 |
-
"engines": {
|
| 2940 |
-
"node": ">=6"
|
| 2941 |
-
}
|
| 2942 |
-
},
|
| 2943 |
-
"node_modules/tough-cookie": {
|
| 2944 |
-
"version": "6.0.0",
|
| 2945 |
-
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.0.tgz",
|
| 2946 |
-
"integrity": "sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==",
|
| 2947 |
-
"dev": true,
|
| 2948 |
-
"dependencies": {
|
| 2949 |
-
"tldts": "^7.0.5"
|
| 2950 |
-
},
|
| 2951 |
-
"engines": {
|
| 2952 |
-
"node": ">=16"
|
| 2953 |
-
}
|
| 2954 |
-
},
|
| 2955 |
-
"node_modules/tr46": {
|
| 2956 |
-
"version": "6.0.0",
|
| 2957 |
-
"resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz",
|
| 2958 |
-
"integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==",
|
| 2959 |
-
"dev": true,
|
| 2960 |
-
"dependencies": {
|
| 2961 |
-
"punycode": "^2.3.1"
|
| 2962 |
-
},
|
| 2963 |
-
"engines": {
|
| 2964 |
-
"node": ">=20"
|
| 2965 |
-
}
|
| 2966 |
-
},
|
| 2967 |
"node_modules/tslib": {
|
| 2968 |
"version": "2.8.1",
|
| 2969 |
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
|
@@ -2983,6 +2179,14 @@
|
|
| 2983 |
"node": ">=14.17"
|
| 2984 |
}
|
| 2985 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2986 |
"node_modules/varint": {
|
| 2987 |
"version": "6.0.0",
|
| 2988 |
"resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz",
|
|
@@ -3048,694 +2252,53 @@
|
|
| 3048 |
}
|
| 3049 |
}
|
| 3050 |
},
|
| 3051 |
-
"node_modules/
|
| 3052 |
-
"version": "
|
| 3053 |
-
"resolved": "https://registry.npmjs.org/
|
| 3054 |
-
"integrity": "sha512
|
| 3055 |
-
"dev": true
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3056 |
"dependencies": {
|
| 3057 |
-
"@
|
| 3058 |
-
"@
|
| 3059 |
-
"@
|
| 3060 |
-
"@
|
| 3061 |
-
"@
|
| 3062 |
-
"@vitest/spy": "4.0.6",
|
| 3063 |
-
"@vitest/utils": "4.0.6",
|
| 3064 |
-
"debug": "^4.4.3",
|
| 3065 |
-
"es-module-lexer": "^1.7.0",
|
| 3066 |
-
"expect-type": "^1.2.2",
|
| 3067 |
-
"magic-string": "^0.30.19",
|
| 3068 |
-
"pathe": "^2.0.3",
|
| 3069 |
-
"picomatch": "^4.0.3",
|
| 3070 |
-
"std-env": "^3.9.0",
|
| 3071 |
-
"tinybench": "^2.9.0",
|
| 3072 |
-
"tinyexec": "^0.3.2",
|
| 3073 |
-
"tinyglobby": "^0.2.15",
|
| 3074 |
-
"tinyrainbow": "^3.0.3",
|
| 3075 |
-
"vite": "^6.0.0 || ^7.0.0",
|
| 3076 |
-
"why-is-node-running": "^2.3.0"
|
| 3077 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3078 |
"bin": {
|
| 3079 |
-
"
|
|
|
|
| 3080 |
},
|
| 3081 |
"engines": {
|
| 3082 |
-
"node": "
|
| 3083 |
},
|
| 3084 |
"funding": {
|
| 3085 |
-
"url": "https://
|
| 3086 |
},
|
| 3087 |
"peerDependencies": {
|
| 3088 |
-
"@
|
| 3089 |
-
"
|
| 3090 |
-
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
|
| 3091 |
-
"@vitest/browser-playwright": "4.0.6",
|
| 3092 |
-
"@vitest/browser-preview": "4.0.6",
|
| 3093 |
-
"@vitest/browser-webdriverio": "4.0.6",
|
| 3094 |
-
"@vitest/ui": "4.0.6",
|
| 3095 |
-
"happy-dom": "*",
|
| 3096 |
-
"jsdom": "*"
|
| 3097 |
},
|
| 3098 |
"peerDependenciesMeta": {
|
| 3099 |
-
"@
|
| 3100 |
-
"optional": true
|
| 3101 |
-
},
|
| 3102 |
-
"@types/debug": {
|
| 3103 |
-
"optional": true
|
| 3104 |
-
},
|
| 3105 |
-
"@types/node": {
|
| 3106 |
-
"optional": true
|
| 3107 |
-
},
|
| 3108 |
-
"@vitest/browser-playwright": {
|
| 3109 |
-
"optional": true
|
| 3110 |
-
},
|
| 3111 |
-
"@vitest/browser-preview": {
|
| 3112 |
-
"optional": true
|
| 3113 |
-
},
|
| 3114 |
-
"@vitest/browser-webdriverio": {
|
| 3115 |
-
"optional": true
|
| 3116 |
-
},
|
| 3117 |
-
"@vitest/ui": {
|
| 3118 |
-
"optional": true
|
| 3119 |
-
},
|
| 3120 |
-
"happy-dom": {
|
| 3121 |
-
"optional": true
|
| 3122 |
-
},
|
| 3123 |
-
"jsdom": {
|
| 3124 |
-
"optional": true
|
| 3125 |
-
}
|
| 3126 |
-
}
|
| 3127 |
-
},
|
| 3128 |
-
"node_modules/vitest/node_modules/@esbuild/aix-ppc64": {
|
| 3129 |
-
"version": "0.25.12",
|
| 3130 |
-
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
|
| 3131 |
-
"integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
|
| 3132 |
-
"cpu": [
|
| 3133 |
-
"ppc64"
|
| 3134 |
-
],
|
| 3135 |
-
"dev": true,
|
| 3136 |
-
"optional": true,
|
| 3137 |
-
"os": [
|
| 3138 |
-
"aix"
|
| 3139 |
-
],
|
| 3140 |
-
"engines": {
|
| 3141 |
-
"node": ">=18"
|
| 3142 |
-
}
|
| 3143 |
-
},
|
| 3144 |
-
"node_modules/vitest/node_modules/@esbuild/android-arm": {
|
| 3145 |
-
"version": "0.25.12",
|
| 3146 |
-
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
|
| 3147 |
-
"integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
|
| 3148 |
-
"cpu": [
|
| 3149 |
-
"arm"
|
| 3150 |
-
],
|
| 3151 |
-
"dev": true,
|
| 3152 |
-
"optional": true,
|
| 3153 |
-
"os": [
|
| 3154 |
-
"android"
|
| 3155 |
-
],
|
| 3156 |
-
"engines": {
|
| 3157 |
-
"node": ">=18"
|
| 3158 |
-
}
|
| 3159 |
-
},
|
| 3160 |
-
"node_modules/vitest/node_modules/@esbuild/android-arm64": {
|
| 3161 |
-
"version": "0.25.12",
|
| 3162 |
-
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
|
| 3163 |
-
"integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
|
| 3164 |
-
"cpu": [
|
| 3165 |
-
"arm64"
|
| 3166 |
-
],
|
| 3167 |
-
"dev": true,
|
| 3168 |
-
"optional": true,
|
| 3169 |
-
"os": [
|
| 3170 |
-
"android"
|
| 3171 |
-
],
|
| 3172 |
-
"engines": {
|
| 3173 |
-
"node": ">=18"
|
| 3174 |
-
}
|
| 3175 |
-
},
|
| 3176 |
-
"node_modules/vitest/node_modules/@esbuild/android-x64": {
|
| 3177 |
-
"version": "0.25.12",
|
| 3178 |
-
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
|
| 3179 |
-
"integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
|
| 3180 |
-
"cpu": [
|
| 3181 |
-
"x64"
|
| 3182 |
-
],
|
| 3183 |
-
"dev": true,
|
| 3184 |
-
"optional": true,
|
| 3185 |
-
"os": [
|
| 3186 |
-
"android"
|
| 3187 |
-
],
|
| 3188 |
-
"engines": {
|
| 3189 |
-
"node": ">=18"
|
| 3190 |
-
}
|
| 3191 |
-
},
|
| 3192 |
-
"node_modules/vitest/node_modules/@esbuild/darwin-arm64": {
|
| 3193 |
-
"version": "0.25.12",
|
| 3194 |
-
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
|
| 3195 |
-
"integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
|
| 3196 |
-
"cpu": [
|
| 3197 |
-
"arm64"
|
| 3198 |
-
],
|
| 3199 |
-
"dev": true,
|
| 3200 |
-
"optional": true,
|
| 3201 |
-
"os": [
|
| 3202 |
-
"darwin"
|
| 3203 |
-
],
|
| 3204 |
-
"engines": {
|
| 3205 |
-
"node": ">=18"
|
| 3206 |
-
}
|
| 3207 |
-
},
|
| 3208 |
-
"node_modules/vitest/node_modules/@esbuild/darwin-x64": {
|
| 3209 |
-
"version": "0.25.12",
|
| 3210 |
-
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
|
| 3211 |
-
"integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
|
| 3212 |
-
"cpu": [
|
| 3213 |
-
"x64"
|
| 3214 |
-
],
|
| 3215 |
-
"dev": true,
|
| 3216 |
-
"optional": true,
|
| 3217 |
-
"os": [
|
| 3218 |
-
"darwin"
|
| 3219 |
-
],
|
| 3220 |
-
"engines": {
|
| 3221 |
-
"node": ">=18"
|
| 3222 |
-
}
|
| 3223 |
-
},
|
| 3224 |
-
"node_modules/vitest/node_modules/@esbuild/freebsd-arm64": {
|
| 3225 |
-
"version": "0.25.12",
|
| 3226 |
-
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
|
| 3227 |
-
"integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
|
| 3228 |
-
"cpu": [
|
| 3229 |
-
"arm64"
|
| 3230 |
-
],
|
| 3231 |
-
"dev": true,
|
| 3232 |
-
"optional": true,
|
| 3233 |
-
"os": [
|
| 3234 |
-
"freebsd"
|
| 3235 |
-
],
|
| 3236 |
-
"engines": {
|
| 3237 |
-
"node": ">=18"
|
| 3238 |
-
}
|
| 3239 |
-
},
|
| 3240 |
-
"node_modules/vitest/node_modules/@esbuild/freebsd-x64": {
|
| 3241 |
-
"version": "0.25.12",
|
| 3242 |
-
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
|
| 3243 |
-
"integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
|
| 3244 |
-
"cpu": [
|
| 3245 |
-
"x64"
|
| 3246 |
-
],
|
| 3247 |
-
"dev": true,
|
| 3248 |
-
"optional": true,
|
| 3249 |
-
"os": [
|
| 3250 |
-
"freebsd"
|
| 3251 |
-
],
|
| 3252 |
-
"engines": {
|
| 3253 |
-
"node": ">=18"
|
| 3254 |
-
}
|
| 3255 |
-
},
|
| 3256 |
-
"node_modules/vitest/node_modules/@esbuild/linux-arm": {
|
| 3257 |
-
"version": "0.25.12",
|
| 3258 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
|
| 3259 |
-
"integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
|
| 3260 |
-
"cpu": [
|
| 3261 |
-
"arm"
|
| 3262 |
-
],
|
| 3263 |
-
"dev": true,
|
| 3264 |
-
"optional": true,
|
| 3265 |
-
"os": [
|
| 3266 |
-
"linux"
|
| 3267 |
-
],
|
| 3268 |
-
"engines": {
|
| 3269 |
-
"node": ">=18"
|
| 3270 |
-
}
|
| 3271 |
-
},
|
| 3272 |
-
"node_modules/vitest/node_modules/@esbuild/linux-arm64": {
|
| 3273 |
-
"version": "0.25.12",
|
| 3274 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
|
| 3275 |
-
"integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
|
| 3276 |
-
"cpu": [
|
| 3277 |
-
"arm64"
|
| 3278 |
-
],
|
| 3279 |
-
"dev": true,
|
| 3280 |
-
"optional": true,
|
| 3281 |
-
"os": [
|
| 3282 |
-
"linux"
|
| 3283 |
-
],
|
| 3284 |
-
"engines": {
|
| 3285 |
-
"node": ">=18"
|
| 3286 |
-
}
|
| 3287 |
-
},
|
| 3288 |
-
"node_modules/vitest/node_modules/@esbuild/linux-ia32": {
|
| 3289 |
-
"version": "0.25.12",
|
| 3290 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
|
| 3291 |
-
"integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
|
| 3292 |
-
"cpu": [
|
| 3293 |
-
"ia32"
|
| 3294 |
-
],
|
| 3295 |
-
"dev": true,
|
| 3296 |
-
"optional": true,
|
| 3297 |
-
"os": [
|
| 3298 |
-
"linux"
|
| 3299 |
-
],
|
| 3300 |
-
"engines": {
|
| 3301 |
-
"node": ">=18"
|
| 3302 |
-
}
|
| 3303 |
-
},
|
| 3304 |
-
"node_modules/vitest/node_modules/@esbuild/linux-loong64": {
|
| 3305 |
-
"version": "0.25.12",
|
| 3306 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
|
| 3307 |
-
"integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
|
| 3308 |
-
"cpu": [
|
| 3309 |
-
"loong64"
|
| 3310 |
-
],
|
| 3311 |
-
"dev": true,
|
| 3312 |
-
"optional": true,
|
| 3313 |
-
"os": [
|
| 3314 |
-
"linux"
|
| 3315 |
-
],
|
| 3316 |
-
"engines": {
|
| 3317 |
-
"node": ">=18"
|
| 3318 |
-
}
|
| 3319 |
-
},
|
| 3320 |
-
"node_modules/vitest/node_modules/@esbuild/linux-mips64el": {
|
| 3321 |
-
"version": "0.25.12",
|
| 3322 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
|
| 3323 |
-
"integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
|
| 3324 |
-
"cpu": [
|
| 3325 |
-
"mips64el"
|
| 3326 |
-
],
|
| 3327 |
-
"dev": true,
|
| 3328 |
-
"optional": true,
|
| 3329 |
-
"os": [
|
| 3330 |
-
"linux"
|
| 3331 |
-
],
|
| 3332 |
-
"engines": {
|
| 3333 |
-
"node": ">=18"
|
| 3334 |
-
}
|
| 3335 |
-
},
|
| 3336 |
-
"node_modules/vitest/node_modules/@esbuild/linux-ppc64": {
|
| 3337 |
-
"version": "0.25.12",
|
| 3338 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
|
| 3339 |
-
"integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
|
| 3340 |
-
"cpu": [
|
| 3341 |
-
"ppc64"
|
| 3342 |
-
],
|
| 3343 |
-
"dev": true,
|
| 3344 |
-
"optional": true,
|
| 3345 |
-
"os": [
|
| 3346 |
-
"linux"
|
| 3347 |
-
],
|
| 3348 |
-
"engines": {
|
| 3349 |
-
"node": ">=18"
|
| 3350 |
-
}
|
| 3351 |
-
},
|
| 3352 |
-
"node_modules/vitest/node_modules/@esbuild/linux-riscv64": {
|
| 3353 |
-
"version": "0.25.12",
|
| 3354 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
|
| 3355 |
-
"integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
|
| 3356 |
-
"cpu": [
|
| 3357 |
-
"riscv64"
|
| 3358 |
-
],
|
| 3359 |
-
"dev": true,
|
| 3360 |
-
"optional": true,
|
| 3361 |
-
"os": [
|
| 3362 |
-
"linux"
|
| 3363 |
-
],
|
| 3364 |
-
"engines": {
|
| 3365 |
-
"node": ">=18"
|
| 3366 |
-
}
|
| 3367 |
-
},
|
| 3368 |
-
"node_modules/vitest/node_modules/@esbuild/linux-s390x": {
|
| 3369 |
-
"version": "0.25.12",
|
| 3370 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
|
| 3371 |
-
"integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
|
| 3372 |
-
"cpu": [
|
| 3373 |
-
"s390x"
|
| 3374 |
-
],
|
| 3375 |
-
"dev": true,
|
| 3376 |
-
"optional": true,
|
| 3377 |
-
"os": [
|
| 3378 |
-
"linux"
|
| 3379 |
-
],
|
| 3380 |
-
"engines": {
|
| 3381 |
-
"node": ">=18"
|
| 3382 |
-
}
|
| 3383 |
-
},
|
| 3384 |
-
"node_modules/vitest/node_modules/@esbuild/linux-x64": {
|
| 3385 |
-
"version": "0.25.12",
|
| 3386 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
|
| 3387 |
-
"integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
|
| 3388 |
-
"cpu": [
|
| 3389 |
-
"x64"
|
| 3390 |
-
],
|
| 3391 |
-
"dev": true,
|
| 3392 |
-
"optional": true,
|
| 3393 |
-
"os": [
|
| 3394 |
-
"linux"
|
| 3395 |
-
],
|
| 3396 |
-
"engines": {
|
| 3397 |
-
"node": ">=18"
|
| 3398 |
-
}
|
| 3399 |
-
},
|
| 3400 |
-
"node_modules/vitest/node_modules/@esbuild/netbsd-x64": {
|
| 3401 |
-
"version": "0.25.12",
|
| 3402 |
-
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
|
| 3403 |
-
"integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
|
| 3404 |
-
"cpu": [
|
| 3405 |
-
"x64"
|
| 3406 |
-
],
|
| 3407 |
-
"dev": true,
|
| 3408 |
-
"optional": true,
|
| 3409 |
-
"os": [
|
| 3410 |
-
"netbsd"
|
| 3411 |
-
],
|
| 3412 |
-
"engines": {
|
| 3413 |
-
"node": ">=18"
|
| 3414 |
-
}
|
| 3415 |
-
},
|
| 3416 |
-
"node_modules/vitest/node_modules/@esbuild/openbsd-x64": {
|
| 3417 |
-
"version": "0.25.12",
|
| 3418 |
-
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
|
| 3419 |
-
"integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
|
| 3420 |
-
"cpu": [
|
| 3421 |
-
"x64"
|
| 3422 |
-
],
|
| 3423 |
-
"dev": true,
|
| 3424 |
-
"optional": true,
|
| 3425 |
-
"os": [
|
| 3426 |
-
"openbsd"
|
| 3427 |
-
],
|
| 3428 |
-
"engines": {
|
| 3429 |
-
"node": ">=18"
|
| 3430 |
-
}
|
| 3431 |
-
},
|
| 3432 |
-
"node_modules/vitest/node_modules/@esbuild/sunos-x64": {
|
| 3433 |
-
"version": "0.25.12",
|
| 3434 |
-
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
|
| 3435 |
-
"integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
|
| 3436 |
-
"cpu": [
|
| 3437 |
-
"x64"
|
| 3438 |
-
],
|
| 3439 |
-
"dev": true,
|
| 3440 |
-
"optional": true,
|
| 3441 |
-
"os": [
|
| 3442 |
-
"sunos"
|
| 3443 |
-
],
|
| 3444 |
-
"engines": {
|
| 3445 |
-
"node": ">=18"
|
| 3446 |
-
}
|
| 3447 |
-
},
|
| 3448 |
-
"node_modules/vitest/node_modules/@esbuild/win32-arm64": {
|
| 3449 |
-
"version": "0.25.12",
|
| 3450 |
-
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
|
| 3451 |
-
"integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
|
| 3452 |
-
"cpu": [
|
| 3453 |
-
"arm64"
|
| 3454 |
-
],
|
| 3455 |
-
"dev": true,
|
| 3456 |
-
"optional": true,
|
| 3457 |
-
"os": [
|
| 3458 |
-
"win32"
|
| 3459 |
-
],
|
| 3460 |
-
"engines": {
|
| 3461 |
-
"node": ">=18"
|
| 3462 |
-
}
|
| 3463 |
-
},
|
| 3464 |
-
"node_modules/vitest/node_modules/@esbuild/win32-ia32": {
|
| 3465 |
-
"version": "0.25.12",
|
| 3466 |
-
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
|
| 3467 |
-
"integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
|
| 3468 |
-
"cpu": [
|
| 3469 |
-
"ia32"
|
| 3470 |
-
],
|
| 3471 |
-
"dev": true,
|
| 3472 |
-
"optional": true,
|
| 3473 |
-
"os": [
|
| 3474 |
-
"win32"
|
| 3475 |
-
],
|
| 3476 |
-
"engines": {
|
| 3477 |
-
"node": ">=18"
|
| 3478 |
-
}
|
| 3479 |
-
},
|
| 3480 |
-
"node_modules/vitest/node_modules/@esbuild/win32-x64": {
|
| 3481 |
-
"version": "0.25.12",
|
| 3482 |
-
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
|
| 3483 |
-
"integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
|
| 3484 |
-
"cpu": [
|
| 3485 |
-
"x64"
|
| 3486 |
-
],
|
| 3487 |
-
"dev": true,
|
| 3488 |
-
"optional": true,
|
| 3489 |
-
"os": [
|
| 3490 |
-
"win32"
|
| 3491 |
-
],
|
| 3492 |
-
"engines": {
|
| 3493 |
-
"node": ">=18"
|
| 3494 |
-
}
|
| 3495 |
-
},
|
| 3496 |
-
"node_modules/vitest/node_modules/@vitest/mocker": {
|
| 3497 |
-
"version": "4.0.6",
|
| 3498 |
-
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.6.tgz",
|
| 3499 |
-
"integrity": "sha512-3COEIew5HqdzBFEYN9+u0dT3i/NCwppLnO1HkjGfAP1Vs3vti1Hxm/MvcbC4DAn3Szo1M7M3otiAaT83jvqIjA==",
|
| 3500 |
-
"dev": true,
|
| 3501 |
-
"dependencies": {
|
| 3502 |
-
"@vitest/spy": "4.0.6",
|
| 3503 |
-
"estree-walker": "^3.0.3",
|
| 3504 |
-
"magic-string": "^0.30.19"
|
| 3505 |
-
},
|
| 3506 |
-
"funding": {
|
| 3507 |
-
"url": "https://opencollective.com/vitest"
|
| 3508 |
-
},
|
| 3509 |
-
"peerDependencies": {
|
| 3510 |
-
"msw": "^2.4.9",
|
| 3511 |
-
"vite": "^6.0.0 || ^7.0.0-0"
|
| 3512 |
-
},
|
| 3513 |
-
"peerDependenciesMeta": {
|
| 3514 |
-
"msw": {
|
| 3515 |
-
"optional": true
|
| 3516 |
-
},
|
| 3517 |
-
"vite": {
|
| 3518 |
-
"optional": true
|
| 3519 |
-
}
|
| 3520 |
-
}
|
| 3521 |
-
},
|
| 3522 |
-
"node_modules/vitest/node_modules/debug": {
|
| 3523 |
-
"version": "4.4.3",
|
| 3524 |
-
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
| 3525 |
-
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
| 3526 |
-
"dev": true,
|
| 3527 |
-
"dependencies": {
|
| 3528 |
-
"ms": "^2.1.3"
|
| 3529 |
-
},
|
| 3530 |
-
"engines": {
|
| 3531 |
-
"node": ">=6.0"
|
| 3532 |
-
},
|
| 3533 |
-
"peerDependenciesMeta": {
|
| 3534 |
-
"supports-color": {
|
| 3535 |
-
"optional": true
|
| 3536 |
-
}
|
| 3537 |
-
}
|
| 3538 |
-
},
|
| 3539 |
-
"node_modules/vitest/node_modules/esbuild": {
|
| 3540 |
-
"version": "0.25.12",
|
| 3541 |
-
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
|
| 3542 |
-
"integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
|
| 3543 |
-
"dev": true,
|
| 3544 |
-
"hasInstallScript": true,
|
| 3545 |
-
"bin": {
|
| 3546 |
-
"esbuild": "bin/esbuild"
|
| 3547 |
-
},
|
| 3548 |
-
"engines": {
|
| 3549 |
-
"node": ">=18"
|
| 3550 |
-
},
|
| 3551 |
-
"optionalDependencies": {
|
| 3552 |
-
"@esbuild/aix-ppc64": "0.25.12",
|
| 3553 |
-
"@esbuild/android-arm": "0.25.12",
|
| 3554 |
-
"@esbuild/android-arm64": "0.25.12",
|
| 3555 |
-
"@esbuild/android-x64": "0.25.12",
|
| 3556 |
-
"@esbuild/darwin-arm64": "0.25.12",
|
| 3557 |
-
"@esbuild/darwin-x64": "0.25.12",
|
| 3558 |
-
"@esbuild/freebsd-arm64": "0.25.12",
|
| 3559 |
-
"@esbuild/freebsd-x64": "0.25.12",
|
| 3560 |
-
"@esbuild/linux-arm": "0.25.12",
|
| 3561 |
-
"@esbuild/linux-arm64": "0.25.12",
|
| 3562 |
-
"@esbuild/linux-ia32": "0.25.12",
|
| 3563 |
-
"@esbuild/linux-loong64": "0.25.12",
|
| 3564 |
-
"@esbuild/linux-mips64el": "0.25.12",
|
| 3565 |
-
"@esbuild/linux-ppc64": "0.25.12",
|
| 3566 |
-
"@esbuild/linux-riscv64": "0.25.12",
|
| 3567 |
-
"@esbuild/linux-s390x": "0.25.12",
|
| 3568 |
-
"@esbuild/linux-x64": "0.25.12",
|
| 3569 |
-
"@esbuild/netbsd-arm64": "0.25.12",
|
| 3570 |
-
"@esbuild/netbsd-x64": "0.25.12",
|
| 3571 |
-
"@esbuild/openbsd-arm64": "0.25.12",
|
| 3572 |
-
"@esbuild/openbsd-x64": "0.25.12",
|
| 3573 |
-
"@esbuild/openharmony-arm64": "0.25.12",
|
| 3574 |
-
"@esbuild/sunos-x64": "0.25.12",
|
| 3575 |
-
"@esbuild/win32-arm64": "0.25.12",
|
| 3576 |
-
"@esbuild/win32-ia32": "0.25.12",
|
| 3577 |
-
"@esbuild/win32-x64": "0.25.12"
|
| 3578 |
-
}
|
| 3579 |
-
},
|
| 3580 |
-
"node_modules/vitest/node_modules/estree-walker": {
|
| 3581 |
-
"version": "3.0.3",
|
| 3582 |
-
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
|
| 3583 |
-
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
|
| 3584 |
-
"dev": true,
|
| 3585 |
-
"dependencies": {
|
| 3586 |
-
"@types/estree": "^1.0.0"
|
| 3587 |
-
}
|
| 3588 |
-
},
|
| 3589 |
-
"node_modules/vitest/node_modules/fdir": {
|
| 3590 |
-
"version": "6.5.0",
|
| 3591 |
-
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
| 3592 |
-
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
| 3593 |
-
"dev": true,
|
| 3594 |
-
"engines": {
|
| 3595 |
-
"node": ">=12.0.0"
|
| 3596 |
-
},
|
| 3597 |
-
"peerDependencies": {
|
| 3598 |
-
"picomatch": "^3 || ^4"
|
| 3599 |
-
},
|
| 3600 |
-
"peerDependenciesMeta": {
|
| 3601 |
-
"picomatch": {
|
| 3602 |
-
"optional": true
|
| 3603 |
-
}
|
| 3604 |
-
}
|
| 3605 |
-
},
|
| 3606 |
-
"node_modules/vitest/node_modules/picomatch": {
|
| 3607 |
-
"version": "4.0.3",
|
| 3608 |
-
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
| 3609 |
-
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
| 3610 |
-
"dev": true,
|
| 3611 |
-
"engines": {
|
| 3612 |
-
"node": ">=12"
|
| 3613 |
-
},
|
| 3614 |
-
"funding": {
|
| 3615 |
-
"url": "https://github.com/sponsors/jonschlinkert"
|
| 3616 |
-
}
|
| 3617 |
-
},
|
| 3618 |
-
"node_modules/vitest/node_modules/vite": {
|
| 3619 |
-
"version": "7.1.12",
|
| 3620 |
-
"resolved": "https://registry.npmjs.org/vite/-/vite-7.1.12.tgz",
|
| 3621 |
-
"integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==",
|
| 3622 |
-
"dev": true,
|
| 3623 |
-
"dependencies": {
|
| 3624 |
-
"esbuild": "^0.25.0",
|
| 3625 |
-
"fdir": "^6.5.0",
|
| 3626 |
-
"picomatch": "^4.0.3",
|
| 3627 |
-
"postcss": "^8.5.6",
|
| 3628 |
-
"rollup": "^4.43.0",
|
| 3629 |
-
"tinyglobby": "^0.2.15"
|
| 3630 |
-
},
|
| 3631 |
-
"bin": {
|
| 3632 |
-
"vite": "bin/vite.js"
|
| 3633 |
-
},
|
| 3634 |
-
"engines": {
|
| 3635 |
-
"node": "^20.19.0 || >=22.12.0"
|
| 3636 |
-
},
|
| 3637 |
-
"funding": {
|
| 3638 |
-
"url": "https://github.com/vitejs/vite?sponsor=1"
|
| 3639 |
-
},
|
| 3640 |
-
"optionalDependencies": {
|
| 3641 |
-
"fsevents": "~2.3.3"
|
| 3642 |
-
},
|
| 3643 |
-
"peerDependencies": {
|
| 3644 |
-
"@types/node": "^20.19.0 || >=22.12.0",
|
| 3645 |
-
"jiti": ">=1.21.0",
|
| 3646 |
-
"less": "^4.0.0",
|
| 3647 |
-
"lightningcss": "^1.21.0",
|
| 3648 |
-
"sass": "^1.70.0",
|
| 3649 |
-
"sass-embedded": "^1.70.0",
|
| 3650 |
-
"stylus": ">=0.54.8",
|
| 3651 |
-
"sugarss": "^5.0.0",
|
| 3652 |
-
"terser": "^5.16.0",
|
| 3653 |
-
"tsx": "^4.8.1",
|
| 3654 |
-
"yaml": "^2.4.2"
|
| 3655 |
-
},
|
| 3656 |
-
"peerDependenciesMeta": {
|
| 3657 |
-
"@types/node": {
|
| 3658 |
-
"optional": true
|
| 3659 |
-
},
|
| 3660 |
-
"jiti": {
|
| 3661 |
-
"optional": true
|
| 3662 |
-
},
|
| 3663 |
-
"less": {
|
| 3664 |
-
"optional": true
|
| 3665 |
-
},
|
| 3666 |
-
"lightningcss": {
|
| 3667 |
-
"optional": true
|
| 3668 |
-
},
|
| 3669 |
-
"sass": {
|
| 3670 |
-
"optional": true
|
| 3671 |
-
},
|
| 3672 |
-
"sass-embedded": {
|
| 3673 |
-
"optional": true
|
| 3674 |
-
},
|
| 3675 |
-
"stylus": {
|
| 3676 |
-
"optional": true
|
| 3677 |
-
},
|
| 3678 |
-
"sugarss": {
|
| 3679 |
-
"optional": true
|
| 3680 |
-
},
|
| 3681 |
-
"terser": {
|
| 3682 |
-
"optional": true
|
| 3683 |
-
},
|
| 3684 |
-
"tsx": {
|
| 3685 |
-
"optional": true
|
| 3686 |
-
},
|
| 3687 |
-
"yaml": {
|
| 3688 |
-
"optional": true
|
| 3689 |
-
}
|
| 3690 |
-
}
|
| 3691 |
-
},
|
| 3692 |
-
"node_modules/vscode-uri": {
|
| 3693 |
-
"version": "3.1.0",
|
| 3694 |
-
"resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz",
|
| 3695 |
-
"integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==",
|
| 3696 |
-
"dev": true
|
| 3697 |
-
},
|
| 3698 |
-
"node_modules/vue": {
|
| 3699 |
-
"version": "3.5.22",
|
| 3700 |
-
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.22.tgz",
|
| 3701 |
-
"integrity": "sha512-toaZjQ3a/G/mYaLSbV+QsQhIdMo9x5rrqIpYRObsJ6T/J+RyCSFwN2LHNVH9v8uIcljDNa3QzPVdv3Y6b9hAJQ==",
|
| 3702 |
-
"dependencies": {
|
| 3703 |
-
"@vue/compiler-dom": "3.5.22",
|
| 3704 |
-
"@vue/compiler-sfc": "3.5.22",
|
| 3705 |
-
"@vue/runtime-dom": "3.5.22",
|
| 3706 |
-
"@vue/server-renderer": "3.5.22",
|
| 3707 |
-
"@vue/shared": "3.5.22"
|
| 3708 |
-
},
|
| 3709 |
-
"peerDependencies": {
|
| 3710 |
-
"typescript": "*"
|
| 3711 |
-
},
|
| 3712 |
-
"peerDependenciesMeta": {
|
| 3713 |
-
"typescript": {
|
| 3714 |
-
"optional": true
|
| 3715 |
-
}
|
| 3716 |
-
}
|
| 3717 |
-
},
|
| 3718 |
-
"node_modules/vue-demi": {
|
| 3719 |
-
"version": "0.14.10",
|
| 3720 |
-
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
|
| 3721 |
-
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
|
| 3722 |
-
"hasInstallScript": true,
|
| 3723 |
-
"bin": {
|
| 3724 |
-
"vue-demi-fix": "bin/vue-demi-fix.js",
|
| 3725 |
-
"vue-demi-switch": "bin/vue-demi-switch.js"
|
| 3726 |
-
},
|
| 3727 |
-
"engines": {
|
| 3728 |
-
"node": ">=12"
|
| 3729 |
-
},
|
| 3730 |
-
"funding": {
|
| 3731 |
-
"url": "https://github.com/sponsors/antfu"
|
| 3732 |
-
},
|
| 3733 |
-
"peerDependencies": {
|
| 3734 |
-
"@vue/composition-api": "^1.0.0-rc.1",
|
| 3735 |
-
"vue": "^3.0.0-0 || ^2.6.0"
|
| 3736 |
-
},
|
| 3737 |
-
"peerDependenciesMeta": {
|
| 3738 |
-
"@vue/composition-api": {
|
| 3739 |
"optional": true
|
| 3740 |
}
|
| 3741 |
}
|
|
@@ -3770,77 +2333,6 @@
|
|
| 3770 |
"typescript": ">=5.0.0"
|
| 3771 |
}
|
| 3772 |
},
|
| 3773 |
-
"node_modules/w3c-xmlserializer": {
|
| 3774 |
-
"version": "5.0.0",
|
| 3775 |
-
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
|
| 3776 |
-
"integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==",
|
| 3777 |
-
"dev": true,
|
| 3778 |
-
"dependencies": {
|
| 3779 |
-
"xml-name-validator": "^5.0.0"
|
| 3780 |
-
},
|
| 3781 |
-
"engines": {
|
| 3782 |
-
"node": ">=18"
|
| 3783 |
-
}
|
| 3784 |
-
},
|
| 3785 |
-
"node_modules/webidl-conversions": {
|
| 3786 |
-
"version": "8.0.0",
|
| 3787 |
-
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.0.tgz",
|
| 3788 |
-
"integrity": "sha512-n4W4YFyz5JzOfQeA8oN7dUYpR+MBP3PIUsn2jLjWXwK5ASUzt0Jc/A5sAUZoCYFJRGF0FBKJ+1JjN43rNdsQzA==",
|
| 3789 |
-
"dev": true,
|
| 3790 |
-
"engines": {
|
| 3791 |
-
"node": ">=20"
|
| 3792 |
-
}
|
| 3793 |
-
},
|
| 3794 |
-
"node_modules/whatwg-encoding": {
|
| 3795 |
-
"version": "3.1.1",
|
| 3796 |
-
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
|
| 3797 |
-
"integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
|
| 3798 |
-
"dev": true,
|
| 3799 |
-
"dependencies": {
|
| 3800 |
-
"iconv-lite": "0.6.3"
|
| 3801 |
-
},
|
| 3802 |
-
"engines": {
|
| 3803 |
-
"node": ">=18"
|
| 3804 |
-
}
|
| 3805 |
-
},
|
| 3806 |
-
"node_modules/whatwg-mimetype": {
|
| 3807 |
-
"version": "4.0.0",
|
| 3808 |
-
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
|
| 3809 |
-
"integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
|
| 3810 |
-
"dev": true,
|
| 3811 |
-
"engines": {
|
| 3812 |
-
"node": ">=18"
|
| 3813 |
-
}
|
| 3814 |
-
},
|
| 3815 |
-
"node_modules/whatwg-url": {
|
| 3816 |
-
"version": "15.1.0",
|
| 3817 |
-
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-15.1.0.tgz",
|
| 3818 |
-
"integrity": "sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==",
|
| 3819 |
-
"dev": true,
|
| 3820 |
-
"dependencies": {
|
| 3821 |
-
"tr46": "^6.0.0",
|
| 3822 |
-
"webidl-conversions": "^8.0.0"
|
| 3823 |
-
},
|
| 3824 |
-
"engines": {
|
| 3825 |
-
"node": ">=20"
|
| 3826 |
-
}
|
| 3827 |
-
},
|
| 3828 |
-
"node_modules/why-is-node-running": {
|
| 3829 |
-
"version": "2.3.0",
|
| 3830 |
-
"resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
|
| 3831 |
-
"integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
|
| 3832 |
-
"dev": true,
|
| 3833 |
-
"dependencies": {
|
| 3834 |
-
"siginfo": "^2.0.0",
|
| 3835 |
-
"stackback": "0.0.2"
|
| 3836 |
-
},
|
| 3837 |
-
"bin": {
|
| 3838 |
-
"why-is-node-running": "cli.js"
|
| 3839 |
-
},
|
| 3840 |
-
"engines": {
|
| 3841 |
-
"node": ">=8"
|
| 3842 |
-
}
|
| 3843 |
-
},
|
| 3844 |
"node_modules/ws": {
|
| 3845 |
"version": "8.17.1",
|
| 3846 |
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
|
@@ -3861,21 +2353,6 @@
|
|
| 3861 |
}
|
| 3862 |
}
|
| 3863 |
},
|
| 3864 |
-
"node_modules/xml-name-validator": {
|
| 3865 |
-
"version": "5.0.0",
|
| 3866 |
-
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz",
|
| 3867 |
-
"integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==",
|
| 3868 |
-
"dev": true,
|
| 3869 |
-
"engines": {
|
| 3870 |
-
"node": ">=18"
|
| 3871 |
-
}
|
| 3872 |
-
},
|
| 3873 |
-
"node_modules/xmlchars": {
|
| 3874 |
-
"version": "2.2.0",
|
| 3875 |
-
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
|
| 3876 |
-
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
|
| 3877 |
-
"dev": true
|
| 3878 |
-
},
|
| 3879 |
"node_modules/xmlhttprequest-ssl": {
|
| 3880 |
"version": "2.1.2",
|
| 3881 |
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz",
|
|
|
|
| 17 |
"devDependencies": {
|
| 18 |
"@types/three": "^0.156.0",
|
| 19 |
"@vitejs/plugin-vue": "^5.2.4",
|
|
|
|
|
|
|
| 20 |
"sass-embedded": "^1.93.2",
|
| 21 |
"typescript": "^5.2.2",
|
| 22 |
"vite": "^5.4.21",
|
|
|
|
| 23 |
"vue-tsc": "^2.2.12"
|
| 24 |
}
|
| 25 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
"node_modules/@babel/helper-string-parser": {
|
| 27 |
"version": "7.27.1",
|
| 28 |
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
|
|
|
|
| 71 |
"integrity": "sha512-fdRs9PSrBF7QUntpZpq6BTw58fhgGJojgg39m9oFOJGZT+nip9b0so5cYY1oWl5pvemDLr0cPPsH46vwThEbpQ==",
|
| 72 |
"dev": true
|
| 73 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
"node_modules/@esbuild/aix-ppc64": {
|
| 75 |
"version": "0.21.5",
|
| 76 |
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
|
|
|
| 343 |
"node": ">=12"
|
| 344 |
}
|
| 345 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 346 |
"node_modules/@esbuild/netbsd-x64": {
|
| 347 |
"version": "0.21.5",
|
| 348 |
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
|
|
|
|
| 359 |
"node": ">=12"
|
| 360 |
}
|
| 361 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 362 |
"node_modules/@esbuild/openbsd-x64": {
|
| 363 |
"version": "0.21.5",
|
| 364 |
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
|
|
|
|
| 375 |
"node": ">=12"
|
| 376 |
}
|
| 377 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 378 |
"node_modules/@esbuild/sunos-x64": {
|
| 379 |
"version": "0.21.5",
|
| 380 |
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
|
|
|
|
| 740 |
"url": "https://opencollective.com/parcel"
|
| 741 |
}
|
| 742 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 743 |
"node_modules/@rollup/rollup-android-arm-eabi": {
|
| 744 |
"version": "4.52.5",
|
| 745 |
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz",
|
|
|
|
| 1031 |
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
|
| 1032 |
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="
|
| 1033 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1034 |
"node_modules/@types/estree": {
|
| 1035 |
"version": "1.0.8",
|
| 1036 |
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
| 1037 |
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
| 1038 |
"dev": true
|
| 1039 |
},
|
| 1040 |
+
"node_modules/@types/node": {
|
| 1041 |
+
"version": "24.10.1",
|
| 1042 |
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
|
| 1043 |
+
"integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
|
| 1044 |
+
"dev": true,
|
| 1045 |
+
"optional": true,
|
| 1046 |
+
"peer": true,
|
| 1047 |
+
"dependencies": {
|
| 1048 |
+
"undici-types": "~7.16.0"
|
| 1049 |
+
}
|
| 1050 |
+
},
|
| 1051 |
"node_modules/@types/stats.js": {
|
| 1052 |
"version": "0.17.4",
|
| 1053 |
"resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz",
|
|
|
|
| 1085 |
"vue": "^3.2.25"
|
| 1086 |
}
|
| 1087 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1088 |
"node_modules/@volar/language-core": {
|
| 1089 |
"version": "2.4.15",
|
| 1090 |
"resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.15.tgz",
|
|
|
|
| 1241 |
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.22.tgz",
|
| 1242 |
"integrity": "sha512-F4yc6palwq3TT0u+FYf0Ns4Tfl9GRFURDN2gWG7L1ecIaS/4fCIuFOjMTnCyjsu/OK6vaDKLCrGAa+KvvH+h4w=="
|
| 1243 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1244 |
"node_modules/alien-signals": {
|
| 1245 |
"version": "1.0.13",
|
| 1246 |
"resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-1.0.13.tgz",
|
| 1247 |
"integrity": "sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==",
|
| 1248 |
"dev": true
|
| 1249 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1250 |
"node_modules/balanced-match": {
|
| 1251 |
"version": "1.0.2",
|
| 1252 |
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
| 1253 |
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
| 1254 |
"dev": true
|
| 1255 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1256 |
"node_modules/brace-expansion": {
|
| 1257 |
"version": "2.0.2",
|
| 1258 |
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
|
|
|
| 1281 |
"integrity": "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==",
|
| 1282 |
"dev": true
|
| 1283 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1284 |
"node_modules/chokidar": {
|
| 1285 |
"version": "4.0.3",
|
| 1286 |
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
|
|
|
| 1303 |
"integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==",
|
| 1304 |
"dev": true
|
| 1305 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1306 |
"node_modules/csstype": {
|
| 1307 |
"version": "3.1.3",
|
| 1308 |
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
| 1309 |
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
|
| 1310 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1311 |
"node_modules/de-indent": {
|
| 1312 |
"version": "1.0.2",
|
| 1313 |
"resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
|
|
|
|
| 1330 |
}
|
| 1331 |
}
|
| 1332 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1333 |
"node_modules/detect-libc": {
|
| 1334 |
"version": "1.0.3",
|
| 1335 |
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
|
|
|
| 1374 |
"url": "https://github.com/fb55/entities?sponsor=1"
|
| 1375 |
}
|
| 1376 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1377 |
"node_modules/esbuild": {
|
| 1378 |
"version": "0.21.5",
|
| 1379 |
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
|
|
|
|
| 1417 |
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
| 1418 |
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
|
| 1419 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1420 |
"node_modules/fflate": {
|
| 1421 |
"version": "0.6.10",
|
| 1422 |
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz",
|
|
|
|
| 1436 |
"node": ">=8"
|
| 1437 |
}
|
| 1438 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1439 |
"node_modules/fsevents": {
|
| 1440 |
"version": "2.3.3",
|
| 1441 |
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
|
|
|
| 1468 |
"he": "bin/he"
|
| 1469 |
}
|
| 1470 |
},
|
| 1471 |
+
"node_modules/immutable": {
|
| 1472 |
+
"version": "5.1.4",
|
| 1473 |
+
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz",
|
| 1474 |
+
"integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==",
|
| 1475 |
+
"dev": true
|
| 1476 |
+
},
|
| 1477 |
+
"node_modules/is-extglob": {
|
| 1478 |
+
"version": "2.1.1",
|
| 1479 |
+
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
| 1480 |
+
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
| 1481 |
"dev": true,
|
| 1482 |
+
"optional": true,
|
|
|
|
|
|
|
| 1483 |
"engines": {
|
| 1484 |
+
"node": ">=0.10.0"
|
| 1485 |
}
|
| 1486 |
},
|
| 1487 |
+
"node_modules/is-glob": {
|
| 1488 |
+
"version": "4.0.3",
|
| 1489 |
+
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
| 1490 |
+
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
| 1491 |
"dev": true,
|
| 1492 |
+
"optional": true,
|
| 1493 |
"dependencies": {
|
| 1494 |
+
"is-extglob": "^2.1.1"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1495 |
},
|
| 1496 |
"engines": {
|
| 1497 |
"node": ">=0.10.0"
|
|
|
|
| 1507 |
"node": ">=0.12.0"
|
| 1508 |
}
|
| 1509 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1510 |
"node_modules/magic-string": {
|
| 1511 |
"version": "0.30.19",
|
| 1512 |
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz",
|
|
|
|
| 1515 |
"@jridgewell/sourcemap-codec": "^1.5.5"
|
| 1516 |
}
|
| 1517 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1518 |
"node_modules/meshoptimizer": {
|
| 1519 |
"version": "0.18.1",
|
| 1520 |
"resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz",
|
|
|
|
| 1550 |
"url": "https://github.com/sponsors/isaacs"
|
| 1551 |
}
|
| 1552 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1553 |
"node_modules/ms": {
|
| 1554 |
"version": "2.1.3",
|
| 1555 |
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
|
|
|
| 1585 |
"dev": true,
|
| 1586 |
"optional": true
|
| 1587 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1588 |
"node_modules/path-browserify": {
|
| 1589 |
"version": "1.0.1",
|
| 1590 |
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
|
| 1591 |
"integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
|
| 1592 |
"dev": true
|
| 1593 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1594 |
"node_modules/picocolors": {
|
| 1595 |
"version": "1.1.1",
|
| 1596 |
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
|
|
|
| 1657 |
"node": "^10 || ^12 || >=14"
|
| 1658 |
}
|
| 1659 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1660 |
"node_modules/readdirp": {
|
| 1661 |
"version": "4.1.2",
|
| 1662 |
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
|
|
|
| 1671 |
"url": "https://paulmillr.com/funding/"
|
| 1672 |
}
|
| 1673 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1674 |
"node_modules/rollup": {
|
| 1675 |
"version": "4.52.5",
|
| 1676 |
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz",
|
|
|
|
| 1721 |
"tslib": "^2.1.0"
|
| 1722 |
}
|
| 1723 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1724 |
"node_modules/sass": {
|
| 1725 |
"version": "1.93.2",
|
| 1726 |
"resolved": "https://registry.npmjs.org/sass/-/sass-1.93.2.tgz",
|
|
|
|
| 2072 |
"node": ">=14.0.0"
|
| 2073 |
}
|
| 2074 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2075 |
"node_modules/socket.io-client": {
|
| 2076 |
"version": "4.8.1",
|
| 2077 |
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz",
|
|
|
|
| 2106 |
"node": ">=0.10.0"
|
| 2107 |
}
|
| 2108 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2109 |
"node_modules/supports-color": {
|
| 2110 |
"version": "8.1.1",
|
| 2111 |
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
|
|
|
| 2121 |
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
| 2122 |
}
|
| 2123 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2124 |
"node_modules/sync-child-process": {
|
| 2125 |
"version": "1.0.2",
|
| 2126 |
"resolved": "https://registry.npmjs.org/sync-child-process/-/sync-child-process-1.0.2.tgz",
|
|
|
|
| 2147 |
"resolved": "https://registry.npmjs.org/three/-/three-0.156.1.tgz",
|
| 2148 |
"integrity": "sha512-kP7H0FK9d/k6t/XvQ9FO6i+QrePoDcNhwl0I02+wmUJRNSLCUIDMcfObnzQvxb37/0Uc9TDT0T1HgsRRrO6SYQ=="
|
| 2149 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2150 |
"node_modules/to-regex-range": {
|
| 2151 |
"version": "5.0.1",
|
| 2152 |
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
|
|
|
| 2160 |
"node": ">=8.0"
|
| 2161 |
}
|
| 2162 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2163 |
"node_modules/tslib": {
|
| 2164 |
"version": "2.8.1",
|
| 2165 |
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
|
|
|
| 2179 |
"node": ">=14.17"
|
| 2180 |
}
|
| 2181 |
},
|
| 2182 |
+
"node_modules/undici-types": {
|
| 2183 |
+
"version": "7.16.0",
|
| 2184 |
+
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
|
| 2185 |
+
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
|
| 2186 |
+
"dev": true,
|
| 2187 |
+
"optional": true,
|
| 2188 |
+
"peer": true
|
| 2189 |
+
},
|
| 2190 |
"node_modules/varint": {
|
| 2191 |
"version": "6.0.0",
|
| 2192 |
"resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz",
|
|
|
|
| 2252 |
}
|
| 2253 |
}
|
| 2254 |
},
|
| 2255 |
+
"node_modules/vscode-uri": {
|
| 2256 |
+
"version": "3.1.0",
|
| 2257 |
+
"resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz",
|
| 2258 |
+
"integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==",
|
| 2259 |
+
"dev": true
|
| 2260 |
+
},
|
| 2261 |
+
"node_modules/vue": {
|
| 2262 |
+
"version": "3.5.22",
|
| 2263 |
+
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.22.tgz",
|
| 2264 |
+
"integrity": "sha512-toaZjQ3a/G/mYaLSbV+QsQhIdMo9x5rrqIpYRObsJ6T/J+RyCSFwN2LHNVH9v8uIcljDNa3QzPVdv3Y6b9hAJQ==",
|
| 2265 |
"dependencies": {
|
| 2266 |
+
"@vue/compiler-dom": "3.5.22",
|
| 2267 |
+
"@vue/compiler-sfc": "3.5.22",
|
| 2268 |
+
"@vue/runtime-dom": "3.5.22",
|
| 2269 |
+
"@vue/server-renderer": "3.5.22",
|
| 2270 |
+
"@vue/shared": "3.5.22"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2271 |
},
|
| 2272 |
+
"peerDependencies": {
|
| 2273 |
+
"typescript": "*"
|
| 2274 |
+
},
|
| 2275 |
+
"peerDependenciesMeta": {
|
| 2276 |
+
"typescript": {
|
| 2277 |
+
"optional": true
|
| 2278 |
+
}
|
| 2279 |
+
}
|
| 2280 |
+
},
|
| 2281 |
+
"node_modules/vue-demi": {
|
| 2282 |
+
"version": "0.14.10",
|
| 2283 |
+
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
|
| 2284 |
+
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
|
| 2285 |
+
"hasInstallScript": true,
|
| 2286 |
"bin": {
|
| 2287 |
+
"vue-demi-fix": "bin/vue-demi-fix.js",
|
| 2288 |
+
"vue-demi-switch": "bin/vue-demi-switch.js"
|
| 2289 |
},
|
| 2290 |
"engines": {
|
| 2291 |
+
"node": ">=12"
|
| 2292 |
},
|
| 2293 |
"funding": {
|
| 2294 |
+
"url": "https://github.com/sponsors/antfu"
|
| 2295 |
},
|
| 2296 |
"peerDependencies": {
|
| 2297 |
+
"@vue/composition-api": "^1.0.0-rc.1",
|
| 2298 |
+
"vue": "^3.0.0-0 || ^2.6.0"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2299 |
},
|
| 2300 |
"peerDependenciesMeta": {
|
| 2301 |
+
"@vue/composition-api": {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2302 |
"optional": true
|
| 2303 |
}
|
| 2304 |
}
|
|
|
|
| 2333 |
"typescript": ">=5.0.0"
|
| 2334 |
}
|
| 2335 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2336 |
"node_modules/ws": {
|
| 2337 |
"version": "8.17.1",
|
| 2338 |
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
|
|
|
| 2353 |
}
|
| 2354 |
}
|
| 2355 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2356 |
"node_modules/xmlhttprequest-ssl": {
|
| 2357 |
"version": "2.1.2",
|
| 2358 |
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz",
|
trigo-web/app/src/App.vue
CHANGED
|
@@ -1,10 +1,12 @@
|
|
| 1 |
<template>
|
| 2 |
<div id="app">
|
| 3 |
-
<
|
| 4 |
</div>
|
| 5 |
</template>
|
| 6 |
|
| 7 |
-
<script setup lang="ts"
|
|
|
|
|
|
|
| 8 |
|
| 9 |
<style lang="scss">
|
| 10 |
* {
|
|
@@ -16,7 +18,8 @@
|
|
| 16 |
html,
|
| 17 |
body {
|
| 18 |
height: 100%;
|
| 19 |
-
font-family:
|
|
|
|
| 20 |
sans-serif;
|
| 21 |
}
|
| 22 |
|
|
@@ -24,4 +27,4 @@
|
|
| 24 |
height: 100vh;
|
| 25 |
background: #f5f5f5;
|
| 26 |
}
|
| 27 |
-
</style>
|
|
|
|
| 1 |
<template>
|
| 2 |
<div id="app">
|
| 3 |
+
<LayoutFrame />
|
| 4 |
</div>
|
| 5 |
</template>
|
| 6 |
|
| 7 |
+
<script setup lang="ts">
|
| 8 |
+
import LayoutFrame from "./components/LayoutFrame.vue";
|
| 9 |
+
</script>
|
| 10 |
|
| 11 |
<style lang="scss">
|
| 12 |
* {
|
|
|
|
| 18 |
html,
|
| 19 |
body {
|
| 20 |
height: 100%;
|
| 21 |
+
font-family:
|
| 22 |
+
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
|
| 23 |
sans-serif;
|
| 24 |
}
|
| 25 |
|
|
|
|
| 27 |
height: 100vh;
|
| 28 |
background: #f5f5f5;
|
| 29 |
}
|
| 30 |
+
</style>
|
trigo-web/app/src/components/LayoutFrame.vue
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<template>
|
| 2 |
+
<div class="layout-frame">
|
| 3 |
+
<SidebarMenu />
|
| 4 |
+
<div class="content-area">
|
| 5 |
+
<router-view />
|
| 6 |
+
</div>
|
| 7 |
+
</div>
|
| 8 |
+
</template>
|
| 9 |
+
|
| 10 |
+
<script setup lang="ts">
|
| 11 |
+
import SidebarMenu from "./SidebarMenu.vue";
|
| 12 |
+
</script>
|
| 13 |
+
|
| 14 |
+
<style lang="scss" scoped>
|
| 15 |
+
.layout-frame {
|
| 16 |
+
display: flex;
|
| 17 |
+
height: 100vh;
|
| 18 |
+
width: 100vw;
|
| 19 |
+
background: #f5f5f5;
|
| 20 |
+
overflow: hidden;
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
.content-area {
|
| 24 |
+
flex: 1;
|
| 25 |
+
display: flex;
|
| 26 |
+
flex-direction: column;
|
| 27 |
+
overflow: hidden;
|
| 28 |
+
}
|
| 29 |
+
</style>
|
trigo-web/app/src/components/SidebarMenu.vue
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<template>
|
| 2 |
+
<nav
|
| 3 |
+
class="sidebar-menu"
|
| 4 |
+
:class="{ expanded: isExpanded }"
|
| 5 |
+
@mouseenter="isExpanded = true"
|
| 6 |
+
@mouseleave="isExpanded = false"
|
| 7 |
+
>
|
| 8 |
+
<div
|
| 9 |
+
class="logo-section"
|
| 10 |
+
@click="handleLogoClick"
|
| 11 |
+
title="Click to test WebSocket connection"
|
| 12 |
+
>
|
| 13 |
+
<img src="@/assets/logo.png" alt="Trigo" class="logo clickable" />
|
| 14 |
+
<h1 class="app-title">Trigo</h1>
|
| 15 |
+
</div>
|
| 16 |
+
|
| 17 |
+
<div class="menu-tabs">
|
| 18 |
+
<router-link
|
| 19 |
+
v-for="tab in tabs"
|
| 20 |
+
:key="tab.path"
|
| 21 |
+
:to="tab.path"
|
| 22 |
+
class="tab-button"
|
| 23 |
+
:class="{ active: isActiveTab(tab.path) }"
|
| 24 |
+
>
|
| 25 |
+
<span class="tab-icon">{{ tab.icon }}</span>
|
| 26 |
+
<span class="tab-label">{{ tab.label }}</span>
|
| 27 |
+
</router-link>
|
| 28 |
+
</div>
|
| 29 |
+
|
| 30 |
+
<div class="sidebar-footer">
|
| 31 |
+
<p class="version">v1.0.0</p>
|
| 32 |
+
</div>
|
| 33 |
+
</nav>
|
| 34 |
+
</template>
|
| 35 |
+
|
| 36 |
+
<script setup lang="ts">
|
| 37 |
+
import { ref, computed } from "vue";
|
| 38 |
+
import { useRoute } from "vue-router";
|
| 39 |
+
import { useSocket } from "@/composables/useSocket";
|
| 40 |
+
|
| 41 |
+
interface Tab {
|
| 42 |
+
path: string;
|
| 43 |
+
label: string;
|
| 44 |
+
icon: string;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
const tabs: Tab[] = [
|
| 48 |
+
{ path: "/", label: "Single Game", icon: "🎮" },
|
| 49 |
+
{ path: "/vs-ai", label: "VS AI", icon: "🤖" },
|
| 50 |
+
{ path: "/vs-people", label: "VS People", icon: "👥" },
|
| 51 |
+
{ path: "/library", label: "Game Library", icon: "📚" }
|
| 52 |
+
];
|
| 53 |
+
|
| 54 |
+
const route = useRoute();
|
| 55 |
+
const isExpanded = ref(false);
|
| 56 |
+
|
| 57 |
+
const isActiveTab = (path: string): boolean => {
|
| 58 |
+
return route.path === path;
|
| 59 |
+
};
|
| 60 |
+
|
| 61 |
+
// WebSocket echo test
|
| 62 |
+
const { sendEcho, connected: socketConnected } = useSocket();
|
| 63 |
+
|
| 64 |
+
const handleLogoClick = async () => {
|
| 65 |
+
try {
|
| 66 |
+
console.log("[Echo Test] Sending echo request...");
|
| 67 |
+
console.log("[Echo Test] Socket connected:", socketConnected.value);
|
| 68 |
+
|
| 69 |
+
const response = await sendEcho("Echo test from Trigo sidebar!");
|
| 70 |
+
console.log("[Echo Test] Response:", response);
|
| 71 |
+
|
| 72 |
+
// Show alert with the response
|
| 73 |
+
alert(`WebSocket Echo Test\n\n${response}`);
|
| 74 |
+
} catch (error) {
|
| 75 |
+
console.error("[Echo Test] Error:", error);
|
| 76 |
+
alert(
|
| 77 |
+
`WebSocket Echo Test Failed\n\n${error instanceof Error ? error.message : String(error)}`
|
| 78 |
+
);
|
| 79 |
+
}
|
| 80 |
+
};
|
| 81 |
+
</script>
|
| 82 |
+
|
| 83 |
+
<style lang="scss" scoped>
|
| 84 |
+
.sidebar-menu {
|
| 85 |
+
width: 70px; // Collapsed width (icon only)
|
| 86 |
+
background: #2a2a2a;
|
| 87 |
+
display: flex;
|
| 88 |
+
flex-direction: column;
|
| 89 |
+
border-right: 1px solid #404040;
|
| 90 |
+
padding: 20px 0;
|
| 91 |
+
flex-shrink: 0;
|
| 92 |
+
transition: width 0.3s ease;
|
| 93 |
+
overflow: hidden;
|
| 94 |
+
position: relative;
|
| 95 |
+
|
| 96 |
+
&.expanded {
|
| 97 |
+
width: 220px; // Expanded width (icon + text)
|
| 98 |
+
}
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
.logo-section {
|
| 102 |
+
display: flex;
|
| 103 |
+
flex-direction: column;
|
| 104 |
+
align-items: center;
|
| 105 |
+
padding: 0 10px 30px;
|
| 106 |
+
border-bottom: 1px solid #404040;
|
| 107 |
+
margin-bottom: 20px;
|
| 108 |
+
min-height: 110px; // Prevent layout shift
|
| 109 |
+
cursor: pointer;
|
| 110 |
+
transition: background-color 0.2s ease;
|
| 111 |
+
|
| 112 |
+
&:hover {
|
| 113 |
+
background-color: rgba(255, 255, 255, 0.05);
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
&:active {
|
| 117 |
+
background-color: rgba(255, 255, 255, 0.1);
|
| 118 |
+
}
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
.logo {
|
| 122 |
+
width: 50px;
|
| 123 |
+
height: 50px;
|
| 124 |
+
margin-bottom: 12px;
|
| 125 |
+
border-radius: 8px;
|
| 126 |
+
flex-shrink: 0;
|
| 127 |
+
transition:
|
| 128 |
+
transform 0.2s ease,
|
| 129 |
+
opacity 0.2s ease;
|
| 130 |
+
|
| 131 |
+
&.clickable {
|
| 132 |
+
.logo-section:hover & {
|
| 133 |
+
transform: scale(1.1);
|
| 134 |
+
opacity: 0.9;
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
.logo-section:active & {
|
| 138 |
+
transform: scale(0.95);
|
| 139 |
+
}
|
| 140 |
+
}
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
.app-title {
|
| 144 |
+
font-size: 20px;
|
| 145 |
+
font-weight: 600;
|
| 146 |
+
color: #e0e0e0;
|
| 147 |
+
margin: 0;
|
| 148 |
+
white-space: nowrap;
|
| 149 |
+
opacity: 0;
|
| 150 |
+
transition: opacity 0.2s ease 0.1s;
|
| 151 |
+
|
| 152 |
+
.expanded & {
|
| 153 |
+
opacity: 1;
|
| 154 |
+
}
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
.menu-tabs {
|
| 158 |
+
flex: 1;
|
| 159 |
+
display: flex;
|
| 160 |
+
flex-direction: column;
|
| 161 |
+
gap: 4px;
|
| 162 |
+
padding: 0 10px;
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
.tab-button {
|
| 166 |
+
display: flex;
|
| 167 |
+
align-items: center;
|
| 168 |
+
gap: 12px;
|
| 169 |
+
padding: 14px 12px;
|
| 170 |
+
border-radius: 8px;
|
| 171 |
+
background: transparent;
|
| 172 |
+
color: #a0a0a0;
|
| 173 |
+
text-decoration: none;
|
| 174 |
+
font-size: 15px;
|
| 175 |
+
font-weight: 500;
|
| 176 |
+
cursor: pointer;
|
| 177 |
+
transition: all 0.2s ease;
|
| 178 |
+
border-left: 3px solid transparent;
|
| 179 |
+
position: relative;
|
| 180 |
+
white-space: nowrap;
|
| 181 |
+
|
| 182 |
+
&:hover {
|
| 183 |
+
background: #353535;
|
| 184 |
+
color: #e0e0e0;
|
| 185 |
+
}
|
| 186 |
+
|
| 187 |
+
&.active {
|
| 188 |
+
background: #3a3a3a;
|
| 189 |
+
color: #e94560;
|
| 190 |
+
border-left-color: #e94560;
|
| 191 |
+
|
| 192 |
+
.tab-icon {
|
| 193 |
+
transform: scale(1.1);
|
| 194 |
+
}
|
| 195 |
+
}
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
.tab-icon {
|
| 199 |
+
font-size: 22px;
|
| 200 |
+
line-height: 1;
|
| 201 |
+
transition: transform 0.2s ease;
|
| 202 |
+
min-width: 28px;
|
| 203 |
+
text-align: center;
|
| 204 |
+
flex-shrink: 0;
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
.tab-label {
|
| 208 |
+
flex: 1;
|
| 209 |
+
opacity: 0;
|
| 210 |
+
transition: opacity 0.2s ease 0.1s;
|
| 211 |
+
|
| 212 |
+
.expanded & {
|
| 213 |
+
opacity: 1;
|
| 214 |
+
}
|
| 215 |
+
}
|
| 216 |
+
|
| 217 |
+
.sidebar-footer {
|
| 218 |
+
padding: 20px 10px;
|
| 219 |
+
border-top: 1px solid #404040;
|
| 220 |
+
text-align: center;
|
| 221 |
+
}
|
| 222 |
+
|
| 223 |
+
.version {
|
| 224 |
+
font-size: 11px;
|
| 225 |
+
color: #606060;
|
| 226 |
+
margin: 0;
|
| 227 |
+
white-space: nowrap;
|
| 228 |
+
opacity: 0;
|
| 229 |
+
transition: opacity 0.2s ease 0.1s;
|
| 230 |
+
|
| 231 |
+
.expanded & {
|
| 232 |
+
opacity: 1;
|
| 233 |
+
}
|
| 234 |
+
}
|
| 235 |
+
</style>
|
trigo-web/app/src/composables/useSocket.ts
CHANGED
|
@@ -1,24 +1,31 @@
|
|
| 1 |
import { ref, onUnmounted } from "vue";
|
| 2 |
import { io, Socket } from "socket.io-client";
|
| 3 |
|
| 4 |
-
|
| 5 |
// Singleton socket instance
|
| 6 |
let socketInstance: Socket | null = null;
|
| 7 |
|
| 8 |
-
|
| 9 |
export function useSocket() {
|
| 10 |
const connected = ref(false);
|
| 11 |
const error = ref<string | null>(null);
|
| 12 |
|
| 13 |
-
|
| 14 |
// Get or create socket instance
|
| 15 |
const getSocket = (): Socket => {
|
| 16 |
if (!socketInstance) {
|
| 17 |
// Determine the server URL based on environment
|
| 18 |
-
const isDev = import.meta.env?.DEV ??
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
socketInstance = io(serverUrl, {
|
| 24 |
autoConnect: true,
|
|
@@ -48,7 +55,6 @@ export function useSocket() {
|
|
| 48 |
return socketInstance;
|
| 49 |
};
|
| 50 |
|
| 51 |
-
|
| 52 |
// Send echo test message
|
| 53 |
const sendEcho = (message: string): Promise<string> => {
|
| 54 |
return new Promise((resolve, reject) => {
|
|
@@ -60,13 +66,17 @@ export function useSocket() {
|
|
| 60 |
}
|
| 61 |
|
| 62 |
// Send echo request and wait for response
|
| 63 |
-
socket.emit(
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
}
|
| 69 |
-
|
| 70 |
|
| 71 |
// Timeout after 5 seconds
|
| 72 |
setTimeout(() => {
|
|
@@ -75,14 +85,12 @@ export function useSocket() {
|
|
| 75 |
});
|
| 76 |
};
|
| 77 |
|
| 78 |
-
|
| 79 |
// Clean up on unmount
|
| 80 |
onUnmounted(() => {
|
| 81 |
// Note: We don't disconnect the singleton instance
|
| 82 |
// It will be reused by other components
|
| 83 |
});
|
| 84 |
|
| 85 |
-
|
| 86 |
return {
|
| 87 |
socket: getSocket(),
|
| 88 |
connected,
|
|
@@ -91,7 +99,6 @@ export function useSocket() {
|
|
| 91 |
};
|
| 92 |
}
|
| 93 |
|
| 94 |
-
|
| 95 |
// Export function to manually disconnect (for cleanup)
|
| 96 |
export function disconnectSocket() {
|
| 97 |
if (socketInstance) {
|
|
|
|
| 1 |
import { ref, onUnmounted } from "vue";
|
| 2 |
import { io, Socket } from "socket.io-client";
|
| 3 |
|
|
|
|
| 4 |
// Singleton socket instance
|
| 5 |
let socketInstance: Socket | null = null;
|
| 6 |
|
|
|
|
| 7 |
export function useSocket() {
|
| 8 |
const connected = ref(false);
|
| 9 |
const error = ref<string | null>(null);
|
| 10 |
|
|
|
|
| 11 |
// Get or create socket instance
|
| 12 |
const getSocket = (): Socket => {
|
| 13 |
if (!socketInstance) {
|
| 14 |
// Determine the server URL based on environment
|
| 15 |
+
const isDev = import.meta.env?.DEV ?? import.meta.env?.MODE === "development";
|
| 16 |
+
|
| 17 |
+
let serverUrl: string;
|
| 18 |
+
if (isDev) {
|
| 19 |
+
// Development: Use same host as frontend, port 3000
|
| 20 |
+
// This allows accessing from local IP (e.g., 192.168.x.x:5173)
|
| 21 |
+
const currentHost = window.location.hostname;
|
| 22 |
+
serverUrl = `http://${currentHost}:3000`;
|
| 23 |
+
} else {
|
| 24 |
+
// Production: same origin
|
| 25 |
+
serverUrl = window.location.origin;
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
console.log("[Socket.io] Connecting to:", serverUrl);
|
| 29 |
|
| 30 |
socketInstance = io(serverUrl, {
|
| 31 |
autoConnect: true,
|
|
|
|
| 55 |
return socketInstance;
|
| 56 |
};
|
| 57 |
|
|
|
|
| 58 |
// Send echo test message
|
| 59 |
const sendEcho = (message: string): Promise<string> => {
|
| 60 |
return new Promise((resolve, reject) => {
|
|
|
|
| 66 |
}
|
| 67 |
|
| 68 |
// Send echo request and wait for response
|
| 69 |
+
socket.emit(
|
| 70 |
+
"echo",
|
| 71 |
+
{ message, timestamp: new Date().toISOString() },
|
| 72 |
+
(response: any) => {
|
| 73 |
+
if (response.error) {
|
| 74 |
+
reject(new Error(response.error));
|
| 75 |
+
} else {
|
| 76 |
+
resolve(response.message);
|
| 77 |
+
}
|
| 78 |
}
|
| 79 |
+
);
|
| 80 |
|
| 81 |
// Timeout after 5 seconds
|
| 82 |
setTimeout(() => {
|
|
|
|
| 85 |
});
|
| 86 |
};
|
| 87 |
|
|
|
|
| 88 |
// Clean up on unmount
|
| 89 |
onUnmounted(() => {
|
| 90 |
// Note: We don't disconnect the singleton instance
|
| 91 |
// It will be reused by other components
|
| 92 |
});
|
| 93 |
|
|
|
|
| 94 |
return {
|
| 95 |
socket: getSocket(),
|
| 96 |
connected,
|
|
|
|
| 99 |
};
|
| 100 |
}
|
| 101 |
|
|
|
|
| 102 |
// Export function to manually disconnect (for cleanup)
|
| 103 |
export function disconnectSocket() {
|
| 104 |
if (socketInstance) {
|
trigo-web/app/src/composables/useTrigoAgent.ts
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* Vue Composable for Trigo AI Agent
|
| 3 |
+
*
|
| 4 |
+
* Provides reactive interface to the ONNX-based AI agent for move generation.
|
| 5 |
+
* Features:
|
| 6 |
+
* - Lazy initialization (only loads when needed)
|
| 7 |
+
* - Reactive state tracking (ready, thinking, errors)
|
| 8 |
+
* - Automatic cleanup on unmount
|
| 9 |
+
* - Move generation with error handling
|
| 10 |
+
* - Uses tree agent with evaluation mode for efficient parallel move evaluation
|
| 11 |
+
*/
|
| 12 |
+
|
| 13 |
+
import { ref, onUnmounted } from "vue";
|
| 14 |
+
import { TrigoTreeAgent } from "@inc/trigoTreeAgent";
|
| 15 |
+
import { OnnxInferencer } from "@/services/onnxInferencer";
|
| 16 |
+
import type { TrigoGame } from "@inc/trigo/game";
|
| 17 |
+
import type { Position } from "@inc/trigo/types";
|
| 18 |
+
|
| 19 |
+
/**
|
| 20 |
+
* Composable for using the Trigo AI agent in Vue components
|
| 21 |
+
*/
|
| 22 |
+
export function useTrigoAgent() {
|
| 23 |
+
// Reactive state
|
| 24 |
+
const isReady = ref(false);
|
| 25 |
+
const isThinking = ref(false);
|
| 26 |
+
const error = ref<string | null>(null);
|
| 27 |
+
const lastMoveTime = ref<number>(0);
|
| 28 |
+
|
| 29 |
+
// Agent instance (created lazily)
|
| 30 |
+
let agent: TrigoTreeAgent | null = null;
|
| 31 |
+
let inferencer: OnnxInferencer | null = null;
|
| 32 |
+
|
| 33 |
+
/**
|
| 34 |
+
* Initialize the AI agent
|
| 35 |
+
* - Loads ONNX evaluation model and prepares for inference
|
| 36 |
+
* - Call this when entering VS AI mode
|
| 37 |
+
* - Safe to call multiple times (won't re-initialize)
|
| 38 |
+
*/
|
| 39 |
+
const initialize = async (): Promise<void> => {
|
| 40 |
+
if (isReady.value) {
|
| 41 |
+
console.log("[useTrigoAgent] Already initialized");
|
| 42 |
+
return;
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
error.value = null;
|
| 46 |
+
|
| 47 |
+
try {
|
| 48 |
+
console.log("[useTrigoAgent] Initializing tree agent with evaluation mode...");
|
| 49 |
+
|
| 50 |
+
// Create OnnxInferencer with evaluation model
|
| 51 |
+
inferencer = new OnnxInferencer({
|
| 52 |
+
modelPath: "/onnx/GPT2CausalLM_ep0015_evaluation.onnx",
|
| 53 |
+
vocabSize: 259,
|
| 54 |
+
seqLen: 2048 // Evaluation models support longer sequences
|
| 55 |
+
});
|
| 56 |
+
|
| 57 |
+
// Initialize ONNX model
|
| 58 |
+
await inferencer.initialize();
|
| 59 |
+
|
| 60 |
+
// Create tree agent with the inferencer
|
| 61 |
+
agent = new TrigoTreeAgent(inferencer);
|
| 62 |
+
|
| 63 |
+
isReady.value = true;
|
| 64 |
+
console.log("[useTrigoAgent] ✓ Tree agent ready");
|
| 65 |
+
} catch (err) {
|
| 66 |
+
const errorMessage =
|
| 67 |
+
err instanceof Error ? err.message : "Failed to initialize AI agent";
|
| 68 |
+
error.value = errorMessage;
|
| 69 |
+
console.error("[useTrigoAgent] Initialization failed:", err);
|
| 70 |
+
throw err;
|
| 71 |
+
}
|
| 72 |
+
};
|
| 73 |
+
|
| 74 |
+
/**
|
| 75 |
+
* Generate the next move for the AI player
|
| 76 |
+
*
|
| 77 |
+
* @param game - Current game instance
|
| 78 |
+
* @returns The selected move position, or null if no valid moves or pass move
|
| 79 |
+
* @throws Error if agent is not initialized
|
| 80 |
+
*/
|
| 81 |
+
const generateMove = async (game: TrigoGame): Promise<Position | null> => {
|
| 82 |
+
if (!agent) {
|
| 83 |
+
throw new Error("AI agent not initialized. Call initialize() first.");
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
if (!isReady.value) {
|
| 87 |
+
throw new Error("AI agent is not ready yet.");
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
if (isThinking.value) {
|
| 91 |
+
console.warn("[useTrigoAgent] Already generating a move, ignoring request");
|
| 92 |
+
return null;
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
error.value = null;
|
| 96 |
+
isThinking.value = true;
|
| 97 |
+
|
| 98 |
+
try {
|
| 99 |
+
console.log("[useTrigoAgent] Generating move with tree agent...");
|
| 100 |
+
const startTime = performance.now();
|
| 101 |
+
|
| 102 |
+
// Use tree agent to select best move
|
| 103 |
+
const move = await agent.selectBestMove(game);
|
| 104 |
+
|
| 105 |
+
const elapsed = performance.now() - startTime;
|
| 106 |
+
lastMoveTime.value = elapsed;
|
| 107 |
+
console.log(`[useTrigoAgent] ✓ Move generated in ${elapsed.toFixed(2)}ms`);
|
| 108 |
+
|
| 109 |
+
// Convert Move to Position (return null if pass move)
|
| 110 |
+
if (!move || move.isPass) {
|
| 111 |
+
console.log("[useTrigoAgent] AI chose to pass");
|
| 112 |
+
return null;
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
if (move.x !== undefined && move.y !== undefined && move.z !== undefined) {
|
| 116 |
+
return { x: move.x, y: move.y, z: move.z };
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
console.warn("[useTrigoAgent] Move has undefined coordinates:", move);
|
| 120 |
+
return null;
|
| 121 |
+
} catch (err) {
|
| 122 |
+
const errorMessage = err instanceof Error ? err.message : "Failed to generate move";
|
| 123 |
+
error.value = errorMessage;
|
| 124 |
+
console.error("[useTrigoAgent] Move generation failed:", err);
|
| 125 |
+
throw err;
|
| 126 |
+
} finally {
|
| 127 |
+
isThinking.value = false;
|
| 128 |
+
}
|
| 129 |
+
};
|
| 130 |
+
|
| 131 |
+
/**
|
| 132 |
+
* Check if the agent is initialized and ready
|
| 133 |
+
*/
|
| 134 |
+
const checkIsReady = (): boolean => {
|
| 135 |
+
return agent !== null && inferencer !== null;
|
| 136 |
+
};
|
| 137 |
+
|
| 138 |
+
/**
|
| 139 |
+
* Clean up resources when component unmounts
|
| 140 |
+
*/
|
| 141 |
+
const cleanup = (): void => {
|
| 142 |
+
if (agent || inferencer) {
|
| 143 |
+
console.log("[useTrigoAgent] Cleaning up...");
|
| 144 |
+
agent = null;
|
| 145 |
+
inferencer = null;
|
| 146 |
+
isReady.value = false;
|
| 147 |
+
isThinking.value = false;
|
| 148 |
+
error.value = null;
|
| 149 |
+
lastMoveTime.value = 0;
|
| 150 |
+
}
|
| 151 |
+
};
|
| 152 |
+
|
| 153 |
+
// Automatic cleanup on component unmount
|
| 154 |
+
onUnmounted(() => {
|
| 155 |
+
cleanup();
|
| 156 |
+
});
|
| 157 |
+
|
| 158 |
+
return {
|
| 159 |
+
// State
|
| 160 |
+
isReady,
|
| 161 |
+
isThinking,
|
| 162 |
+
error,
|
| 163 |
+
lastMoveTime,
|
| 164 |
+
|
| 165 |
+
// Methods
|
| 166 |
+
initialize,
|
| 167 |
+
generateMove,
|
| 168 |
+
checkIsReady,
|
| 169 |
+
cleanup
|
| 170 |
+
};
|
| 171 |
+
}
|
trigo-web/app/src/main.ts
CHANGED
|
@@ -5,7 +5,6 @@ import App from "./App.vue";
|
|
| 5 |
import router from "./router";
|
| 6 |
import { initializeParsers } from "@inc/trigo/parserInit";
|
| 7 |
|
| 8 |
-
|
| 9 |
const app = createApp(App);
|
| 10 |
const pinia = createPinia();
|
| 11 |
|
|
@@ -13,11 +12,13 @@ app.use(pinia);
|
|
| 13 |
app.use(router);
|
| 14 |
|
| 15 |
// Initialize parsers before mounting (required for TGN functionality)
|
| 16 |
-
initializeParsers()
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
|
|
|
|
|
|
|
|
| 5 |
import router from "./router";
|
| 6 |
import { initializeParsers } from "@inc/trigo/parserInit";
|
| 7 |
|
|
|
|
| 8 |
const app = createApp(App);
|
| 9 |
const pinia = createPinia();
|
| 10 |
|
|
|
|
| 12 |
app.use(router);
|
| 13 |
|
| 14 |
// Initialize parsers before mounting (required for TGN functionality)
|
| 15 |
+
initializeParsers()
|
| 16 |
+
.then(() => {
|
| 17 |
+
app.mount("#app");
|
| 18 |
+
})
|
| 19 |
+
.catch((error) => {
|
| 20 |
+
console.error("Failed to initialize parsers:", error);
|
| 21 |
+
// Still mount app even if parser initialization fails
|
| 22 |
+
// (parser will throw error when TGN features are used)
|
| 23 |
+
app.mount("#app");
|
| 24 |
+
});
|
trigo-web/app/src/router/index.ts
CHANGED
|
@@ -1,17 +1,52 @@
|
|
| 1 |
import { createRouter, createWebHistory } from "vue-router";
|
| 2 |
import TrigoView from "@/views/TrigoView.vue";
|
| 3 |
-
|
|
|
|
|
|
|
| 4 |
|
| 5 |
const router = createRouter({
|
| 6 |
history: createWebHistory(import.meta.env.BASE_URL),
|
| 7 |
routes: [
|
| 8 |
{
|
| 9 |
path: "/",
|
| 10 |
-
name: "
|
| 11 |
-
component: TrigoView
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
}
|
| 13 |
]
|
| 14 |
});
|
| 15 |
|
| 16 |
-
|
| 17 |
-
export default router;
|
|
|
|
| 1 |
import { createRouter, createWebHistory } from "vue-router";
|
| 2 |
import TrigoView from "@/views/TrigoView.vue";
|
| 3 |
+
import OnnxTestView from "@/views/OnnxTestView.vue";
|
| 4 |
+
import TrigoAgentTestView from "@/views/TrigoAgentTestView.vue";
|
| 5 |
+
import TrigoTreeTestView from "@/views/TrigoTreeTestView.vue";
|
| 6 |
|
| 7 |
const router = createRouter({
|
| 8 |
history: createWebHistory(import.meta.env.BASE_URL),
|
| 9 |
routes: [
|
| 10 |
{
|
| 11 |
path: "/",
|
| 12 |
+
name: "single-game",
|
| 13 |
+
component: TrigoView,
|
| 14 |
+
meta: { mode: "single" }
|
| 15 |
+
},
|
| 16 |
+
{
|
| 17 |
+
path: "/vs-ai",
|
| 18 |
+
name: "vs-ai",
|
| 19 |
+
component: TrigoView,
|
| 20 |
+
meta: { mode: "vs-ai" }
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
path: "/vs-people",
|
| 24 |
+
name: "vs-people",
|
| 25 |
+
component: TrigoView,
|
| 26 |
+
meta: { mode: "vs-people" }
|
| 27 |
+
},
|
| 28 |
+
{
|
| 29 |
+
path: "/library",
|
| 30 |
+
name: "library",
|
| 31 |
+
component: TrigoView,
|
| 32 |
+
meta: { mode: "library" }
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
path: "/onnx-test",
|
| 36 |
+
name: "onnx-test",
|
| 37 |
+
component: OnnxTestView
|
| 38 |
+
},
|
| 39 |
+
{
|
| 40 |
+
path: "/agent-test",
|
| 41 |
+
name: "agent-test",
|
| 42 |
+
component: TrigoAgentTestView
|
| 43 |
+
},
|
| 44 |
+
{
|
| 45 |
+
path: "/tree-test",
|
| 46 |
+
name: "tree-test",
|
| 47 |
+
component: TrigoTreeTestView
|
| 48 |
}
|
| 49 |
]
|
| 50 |
});
|
| 51 |
|
| 52 |
+
export default router;
|
|
|
trigo-web/app/src/services/onnxInferencer.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* ONNX Inferencer for Browser (Frontend Wrapper)
|
| 3 |
+
*
|
| 4 |
+
* This file imports onnxruntime-web and creates sessions,
|
| 5 |
+
* then injects them into the platform-agnostic inferencer.
|
| 6 |
+
*/
|
| 7 |
+
|
| 8 |
+
// IMPORTANT: Import onnxruntime-web first to register backends
|
| 9 |
+
import * as ort from "onnxruntime-web";
|
| 10 |
+
|
| 11 |
+
// Configure ONNX Runtime Web environment BEFORE creating any sessions
|
| 12 |
+
ort.env.wasm.numThreads = 1;
|
| 13 |
+
ort.env.wasm.simd = true;
|
| 14 |
+
|
| 15 |
+
// Import the common inferencer class AFTER onnxruntime-web is loaded
|
| 16 |
+
import { ModelInferencer, type InferencerConfig, type InferenceResult } from "@inc/modelInferencer";
|
| 17 |
+
|
| 18 |
+
/**
|
| 19 |
+
* Web-specific configuration for the inferencer
|
| 20 |
+
*/
|
| 21 |
+
export interface WebInferencerConfig extends Partial<InferencerConfig> {
|
| 22 |
+
modelPath: string;
|
| 23 |
+
executionProviders?: ("wasm" | "webgl" | "webgpu")[];
|
| 24 |
+
sessionOptions?: ort.InferenceSession.SessionOptions;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
/**
|
| 28 |
+
* ONNX Inferencer for Browser with Web-specific defaults
|
| 29 |
+
*/
|
| 30 |
+
export class OnnxInferencer extends ModelInferencer {
|
| 31 |
+
private modelPath: string;
|
| 32 |
+
private sessionOptions?: ort.InferenceSession.SessionOptions;
|
| 33 |
+
|
| 34 |
+
constructor(config: WebInferencerConfig) {
|
| 35 |
+
const { modelPath, executionProviders = ["wasm"], sessionOptions, ...baseConfig } = config;
|
| 36 |
+
|
| 37 |
+
// Pass ort.Tensor constructor to base class
|
| 38 |
+
super(ort.Tensor as any, baseConfig);
|
| 39 |
+
|
| 40 |
+
this.modelPath = modelPath;
|
| 41 |
+
this.sessionOptions = {
|
| 42 |
+
executionProviders: executionProviders,
|
| 43 |
+
graphOptimizationLevel: "all",
|
| 44 |
+
...sessionOptions
|
| 45 |
+
};
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
/**
|
| 49 |
+
* Initialize the inference session
|
| 50 |
+
*/
|
| 51 |
+
async initialize(): Promise<void> {
|
| 52 |
+
console.log("[OnnxInferencer] Initializing...");
|
| 53 |
+
console.log("[OnnxInferencer] Model path:", this.modelPath);
|
| 54 |
+
|
| 55 |
+
try {
|
| 56 |
+
const session = await ort.InferenceSession.create(this.modelPath, this.sessionOptions);
|
| 57 |
+
|
| 58 |
+
// Inject session into base class
|
| 59 |
+
this.setSession(session as any);
|
| 60 |
+
} catch (error) {
|
| 61 |
+
console.error("[OnnxInferencer] Failed to create session:", error);
|
| 62 |
+
throw error;
|
| 63 |
+
}
|
| 64 |
+
}
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
// Re-export types
|
| 68 |
+
export type { InferencerConfig, InferenceResult };
|
trigo-web/app/src/services/trigoViewport.ts
CHANGED
|
@@ -9,16 +9,16 @@ const COLORS = {
|
|
| 9 |
SCENE_CLEAR: 0x505055,
|
| 10 |
|
| 11 |
// Chess frame colors (three-tiered system)
|
| 12 |
-
FRAME_CREST: 0xff4d4d,
|
| 13 |
-
FRAME_SURFACE: 0xe6b380,
|
| 14 |
-
FRAME_INTERIOR: 0x999999,
|
| 15 |
|
| 16 |
// intersection point colors
|
| 17 |
POINT_DEFAULT: 0x4a90e2,
|
| 18 |
POINT_HOVERED: 0x00ff00,
|
| 19 |
POINT_HOVERED_DISABLED: 0xff0000,
|
| 20 |
POINT_AXIS_ALIGNED: 0xffaa00,
|
| 21 |
-
POINT_AIR_PATCH: 0x80e680,
|
| 22 |
|
| 23 |
// Stone colors
|
| 24 |
STONE_BLACK: 0x070707,
|
|
@@ -32,7 +32,7 @@ const COLORS = {
|
|
| 32 |
AMBIENT_LIGHT: 0xffffff,
|
| 33 |
DIRECTIONAL_LIGHT: 0xffffff,
|
| 34 |
HEMISPHERE_LIGHT_SKY: 0xeefaff,
|
| 35 |
-
HEMISPHERE_LIGHT_GROUND: 0x20201a
|
| 36 |
} as const;
|
| 37 |
|
| 38 |
// Opacity constants
|
|
@@ -46,22 +46,21 @@ const OPACITY = {
|
|
| 46 |
POINT_DEFAULT: 0.1,
|
| 47 |
POINT_HOVERED: 0.8,
|
| 48 |
POINT_AXIS_ALIGNED: 0.8,
|
| 49 |
-
POINT_AIR_PATCH: 0.24,
|
| 50 |
PREVIEW_STONE: 0.5,
|
| 51 |
PREVIEW_JOINT_BLACK: 0.5,
|
| 52 |
PREVIEW_JOINT_WHITE: 0.6,
|
| 53 |
DIMMED: 0.3,
|
| 54 |
DOMAIN_BLACK: 0.3,
|
| 55 |
-
DOMAIN_WHITE: 0.3
|
| 56 |
} as const;
|
| 57 |
|
| 58 |
// Shininess constants for stone materials
|
| 59 |
const SHININESS = {
|
| 60 |
STONE_BLACK: 120,
|
| 61 |
-
STONE_WHITE: 30
|
| 62 |
} as const;
|
| 63 |
|
| 64 |
-
|
| 65 |
// Geometric size constants
|
| 66 |
const SIZES = {
|
| 67 |
// Stone and point sizes (relative to grid spacing)
|
|
@@ -74,37 +73,33 @@ const SIZES = {
|
|
| 74 |
// Sphere detail (number of segments)
|
| 75 |
STONE_SEGMENTS: 32,
|
| 76 |
POINT_SEGMENTS: 8,
|
| 77 |
-
JOINT_SEGMENTS: 6
|
| 78 |
} as const;
|
| 79 |
|
| 80 |
-
|
| 81 |
// Camera and scene constants
|
| 82 |
const CAMERA = {
|
| 83 |
FOV: 70,
|
| 84 |
NEAR: 0.1,
|
| 85 |
FAR: 1000,
|
| 86 |
DISTANCE_MULTIPLIER: 1.1,
|
| 87 |
-
HEIGHT_RATIO: 0.8
|
| 88 |
} as const;
|
| 89 |
|
| 90 |
-
|
| 91 |
// Lighting intensity constants
|
| 92 |
const LIGHTING = {
|
| 93 |
AMBIENT_INTENSITY: 0.2,
|
| 94 |
DIRECTIONAL_MAIN_INTENSITY: 0.8,
|
| 95 |
DIRECTIONAL_FILL_INTENSITY: 0.3,
|
| 96 |
-
HEMISPHERE_INTENSITY: 0.8
|
| 97 |
} as const;
|
| 98 |
|
| 99 |
-
|
| 100 |
// Fog constants
|
| 101 |
const FOG = {
|
| 102 |
NEAR_FACTOR: 0.2,
|
| 103 |
FAR_FACTOR: 0.8,
|
| 104 |
-
MIN_NEAR: 0.1
|
| 105 |
} as const;
|
| 106 |
|
| 107 |
-
|
| 108 |
// Last stone highlight constants
|
| 109 |
const SHINING = {
|
| 110 |
FLICKER_SPEED: 0.0048,
|
|
@@ -112,10 +107,9 @@ const SHINING = {
|
|
| 112 |
BASE_INTENSITY_WHITE: 0.2,
|
| 113 |
BASE_INTENSITY_BLACK: 0.06,
|
| 114 |
FLICKER_INTENSITY_WHITE: 0.6,
|
| 115 |
-
FLICKER_INTENSITY_BLACK: 0.1
|
| 116 |
} as const;
|
| 117 |
|
| 118 |
-
|
| 119 |
export interface Stone {
|
| 120 |
position: { x: number; y: number; z: number };
|
| 121 |
color: "black" | "white";
|
|
@@ -172,7 +166,7 @@ export class TrigoViewport {
|
|
| 172 |
private inspectMode: boolean = false;
|
| 173 |
private ctrlKeyDown: boolean = false;
|
| 174 |
private highlightedGroup: Set<string> | null = null;
|
| 175 |
-
private airPatch: Set<string> | null = null;
|
| 176 |
private lastMouseEvent: MouseEvent | null = null;
|
| 177 |
|
| 178 |
// Domain visibility for territory display
|
|
@@ -181,7 +175,11 @@ export class TrigoViewport {
|
|
| 181 |
private blackDomain: Set<string> | null = null;
|
| 182 |
private whiteDomain: Set<string> | null = null;
|
| 183 |
|
| 184 |
-
constructor(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 185 |
this.canvas = canvas;
|
| 186 |
this.boardShape = boardShape;
|
| 187 |
this.callbacks = callbacks;
|
|
@@ -265,12 +263,17 @@ export class TrigoViewport {
|
|
| 265 |
}
|
| 266 |
|
| 267 |
private createPreviewStone(): void {
|
| 268 |
-
const geometry = new THREE.SphereGeometry(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 269 |
const material = new THREE.MeshPhongMaterial({
|
| 270 |
color: this.currentPlayerColor === "black" ? COLORS.STONE_BLACK : COLORS.STONE_WHITE,
|
| 271 |
transparent: true,
|
| 272 |
opacity: OPACITY.PREVIEW_STONE,
|
| 273 |
-
shininess:
|
|
|
|
| 274 |
});
|
| 275 |
this.previewStone = new THREE.Mesh(geometry, material);
|
| 276 |
this.previewStone.visible = false; // Hidden by default
|
|
@@ -280,8 +283,11 @@ export class TrigoViewport {
|
|
| 280 |
private updatePreviewStoneColor(): void {
|
| 281 |
if (!this.previewStone) return;
|
| 282 |
const material = this.previewStone.material as THREE.MeshPhongMaterial;
|
| 283 |
-
material.color.set(
|
| 284 |
-
|
|
|
|
|
|
|
|
|
|
| 285 |
}
|
| 286 |
|
| 287 |
private setupFog(): void {
|
|
@@ -329,22 +335,35 @@ export class TrigoViewport {
|
|
| 329 |
|
| 330 |
private setupLighting(): void {
|
| 331 |
// Ambient light
|
| 332 |
-
const ambientLight = new THREE.AmbientLight(
|
|
|
|
|
|
|
|
|
|
| 333 |
this.scene.add(ambientLight);
|
| 334 |
|
| 335 |
// Directional light (main)
|
| 336 |
-
const directionalLight1 = new THREE.DirectionalLight(
|
|
|
|
|
|
|
|
|
|
| 337 |
directionalLight1.position.set(10, 20, 10);
|
| 338 |
directionalLight1.castShadow = true;
|
| 339 |
this.scene.add(directionalLight1);
|
| 340 |
|
| 341 |
// Directional light (fill)
|
| 342 |
-
const directionalLight2 = new THREE.DirectionalLight(
|
|
|
|
|
|
|
|
|
|
| 343 |
directionalLight2.position.set(-10, -10, -10);
|
| 344 |
this.scene.add(directionalLight2);
|
| 345 |
|
| 346 |
// Hemisphere light for softer ambient
|
| 347 |
-
const hemisphereLight = new THREE.HemisphereLight(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 348 |
hemisphereLight.position.set(0, 20, 0);
|
| 349 |
this.scene.add(hemisphereLight);
|
| 350 |
}
|
|
@@ -380,16 +399,16 @@ export class TrigoViewport {
|
|
| 380 |
|
| 381 |
// Helper function to determine material based on border conditions
|
| 382 |
const getLineMaterial = (border1: boolean, border2: boolean): THREE.LineBasicMaterial => {
|
| 383 |
-
if (border1 && border2) return crestMaterial;
|
| 384 |
-
if (border1 || border2) return surfaceMaterial;
|
| 385 |
-
return interiorMaterial;
|
| 386 |
};
|
| 387 |
|
| 388 |
// X-axis lines (parallel to X)
|
| 389 |
for (let y = 0; y < sizeY; y++) {
|
| 390 |
for (let z = 0; z < sizeZ; z++) {
|
| 391 |
-
const border1 =
|
| 392 |
-
const border2 =
|
| 393 |
const material = getLineMaterial(border1, border2);
|
| 394 |
|
| 395 |
const points = [];
|
|
@@ -411,8 +430,8 @@ export class TrigoViewport {
|
|
| 411 |
// Y-axis lines (parallel to Y)
|
| 412 |
for (let x = 0; x < sizeX; x++) {
|
| 413 |
for (let z = 0; z < sizeZ; z++) {
|
| 414 |
-
const border1 =
|
| 415 |
-
const border2 =
|
| 416 |
const material = getLineMaterial(border1, border2);
|
| 417 |
|
| 418 |
const points = [];
|
|
@@ -435,8 +454,8 @@ export class TrigoViewport {
|
|
| 435 |
if (sizeZ >= 3) {
|
| 436 |
for (let x = 0; x < sizeX; x++) {
|
| 437 |
for (let y = 0; y < sizeY; y++) {
|
| 438 |
-
const border1 =
|
| 439 |
-
const border2 =
|
| 440 |
const material = getLineMaterial(border1, border2);
|
| 441 |
|
| 442 |
const points = [];
|
|
@@ -468,23 +487,17 @@ export class TrigoViewport {
|
|
| 468 |
const axisLength = maxOffset * 1.2;
|
| 469 |
const axesMaterial = [
|
| 470 |
new THREE.LineBasicMaterial({ color: 0xff0000 }), // X axis - red
|
| 471 |
-
new THREE.LineBasicMaterial({ color: 0x00ff00 })
|
| 472 |
];
|
| 473 |
|
| 474 |
// X axis
|
| 475 |
-
const xPoints = [
|
| 476 |
-
new THREE.Vector3(0, 0, 0),
|
| 477 |
-
new THREE.Vector3(axisLength, 0, 0)
|
| 478 |
-
];
|
| 479 |
const xGeometry = new THREE.BufferGeometry().setFromPoints(xPoints);
|
| 480 |
const xLine = new THREE.Line(xGeometry, axesMaterial[0]);
|
| 481 |
this.gridGroup.add(xLine);
|
| 482 |
|
| 483 |
// Y axis
|
| 484 |
-
const yPoints = [
|
| 485 |
-
new THREE.Vector3(0, 0, 0),
|
| 486 |
-
new THREE.Vector3(0, axisLength, 0)
|
| 487 |
-
];
|
| 488 |
const yGeometry = new THREE.BufferGeometry().setFromPoints(yPoints);
|
| 489 |
const yLine = new THREE.Line(yGeometry, axesMaterial[1]);
|
| 490 |
this.gridGroup.add(yLine);
|
|
@@ -499,7 +512,11 @@ export class TrigoViewport {
|
|
| 499 |
const offsetZ = ((sizeZ - 1) * spacing) / 2;
|
| 500 |
|
| 501 |
// Create small spheres at each grid intersection
|
| 502 |
-
const pointGeometry = new THREE.SphereGeometry(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 503 |
|
| 504 |
for (let x = 0; x < sizeX; x++) {
|
| 505 |
for (let y = 0; y < sizeY; y++) {
|
|
@@ -523,7 +540,6 @@ export class TrigoViewport {
|
|
| 523 |
}
|
| 524 |
}
|
| 525 |
|
| 526 |
-
|
| 527 |
private createJoints(): void {
|
| 528 |
const { x: sizeX, y: sizeY, z: sizeZ } = this.boardShape;
|
| 529 |
const spacing = this.gridSpacing;
|
|
@@ -544,7 +560,12 @@ export class TrigoViewport {
|
|
| 544 |
|
| 545 |
// Create X-axis joint (between current and next X position)
|
| 546 |
if (x < sizeX - 1) {
|
| 547 |
-
const geometry = new THREE.CylinderGeometry(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 548 |
const material = new THREE.MeshPhongMaterial({
|
| 549 |
color: COLORS.STONE_BLACK,
|
| 550 |
shininess: SHININESS.STONE_BLACK,
|
|
@@ -567,7 +588,12 @@ export class TrigoViewport {
|
|
| 567 |
|
| 568 |
// Create Y-axis joint (between current and next Y position)
|
| 569 |
if (y < sizeY - 1) {
|
| 570 |
-
const geometry = new THREE.CylinderGeometry(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 571 |
const material = new THREE.MeshPhongMaterial({
|
| 572 |
color: COLORS.STONE_BLACK,
|
| 573 |
shininess: SHININESS.STONE_BLACK,
|
|
@@ -590,7 +616,12 @@ export class TrigoViewport {
|
|
| 590 |
|
| 591 |
// Create Z-axis joint (between current and next Z position)
|
| 592 |
if (z < sizeZ - 1) {
|
| 593 |
-
const geometry = new THREE.CylinderGeometry(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 594 |
const material = new THREE.MeshPhongMaterial({
|
| 595 |
color: COLORS.STONE_BLACK,
|
| 596 |
shininess: SHININESS.STONE_BLACK,
|
|
@@ -617,7 +648,6 @@ export class TrigoViewport {
|
|
| 617 |
}
|
| 618 |
}
|
| 619 |
|
| 620 |
-
|
| 621 |
private createDomainCubes(): void {
|
| 622 |
const { x: sizeX, y: sizeY, z: sizeZ } = this.boardShape;
|
| 623 |
const spacing = this.gridSpacing;
|
|
@@ -642,7 +672,7 @@ export class TrigoViewport {
|
|
| 642 |
color: COLORS.STONE_BLACK,
|
| 643 |
transparent: true,
|
| 644 |
opacity: OPACITY.DOMAIN_BLACK,
|
| 645 |
-
depthWrite: false
|
| 646 |
});
|
| 647 |
|
| 648 |
const cube = new THREE.Mesh(geometry, material);
|
|
@@ -682,7 +712,11 @@ export class TrigoViewport {
|
|
| 682 |
const offsetZ = ((this.boardShape.z - 1) * spacing) / 2;
|
| 683 |
|
| 684 |
// Create stone geometry
|
| 685 |
-
const geometry = new THREE.SphereGeometry(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 686 |
const material = new THREE.MeshPhongMaterial({
|
| 687 |
color: color === "black" ? COLORS.STONE_BLACK : COLORS.STONE_WHITE,
|
| 688 |
shininess: color === "black" ? SHININESS.STONE_BLACK : SHININESS.STONE_WHITE,
|
|
@@ -692,11 +726,7 @@ export class TrigoViewport {
|
|
| 692 |
});
|
| 693 |
|
| 694 |
const stoneMesh = new THREE.Mesh(geometry, material);
|
| 695 |
-
stoneMesh.position.set(
|
| 696 |
-
x * spacing - offsetX,
|
| 697 |
-
y * spacing - offsetY,
|
| 698 |
-
z * spacing - offsetZ
|
| 699 |
-
);
|
| 700 |
|
| 701 |
const stone: Stone = {
|
| 702 |
position: { x, y, z },
|
|
@@ -768,7 +798,6 @@ export class TrigoViewport {
|
|
| 768 |
return this.stones.has(this.getStoneKey(x, y, z));
|
| 769 |
}
|
| 770 |
|
| 771 |
-
|
| 772 |
private refreshJoints(): void {
|
| 773 |
const { x: sizeX, y: sizeY, z: sizeZ } = this.boardShape;
|
| 774 |
|
|
@@ -790,9 +819,20 @@ export class TrigoViewport {
|
|
| 790 |
|
| 791 |
if (nextStone && nextStone.color === centerStone.color) {
|
| 792 |
const material = jointNodes.X.material as THREE.MeshPhongMaterial;
|
| 793 |
-
material.color.set(
|
| 794 |
-
|
| 795 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 796 |
material.opacity = 1.0;
|
| 797 |
material.transparent = false;
|
| 798 |
jointNodes.X.visible = true;
|
|
@@ -812,9 +852,20 @@ export class TrigoViewport {
|
|
| 812 |
|
| 813 |
if (nextStone && nextStone.color === centerStone.color) {
|
| 814 |
const material = jointNodes.Y.material as THREE.MeshPhongMaterial;
|
| 815 |
-
material.color.set(
|
| 816 |
-
|
| 817 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 818 |
material.opacity = 1.0;
|
| 819 |
material.transparent = false;
|
| 820 |
jointNodes.Y.visible = true;
|
|
@@ -834,9 +885,20 @@ export class TrigoViewport {
|
|
| 834 |
|
| 835 |
if (nextStone && nextStone.color === centerStone.color) {
|
| 836 |
const material = jointNodes.Z.material as THREE.MeshPhongMaterial;
|
| 837 |
-
material.color.set(
|
| 838 |
-
|
| 839 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 840 |
material.opacity = 1.0;
|
| 841 |
material.transparent = false;
|
| 842 |
jointNodes.Z.visible = true;
|
|
@@ -849,7 +911,8 @@ export class TrigoViewport {
|
|
| 849 |
}
|
| 850 |
|
| 851 |
// Show preview joints if hovering over this position
|
| 852 |
-
const isHovered =
|
|
|
|
| 853 |
this.hoveredPosition.x === x &&
|
| 854 |
this.hoveredPosition.y === y &&
|
| 855 |
this.hoveredPosition.z === z;
|
|
@@ -857,7 +920,10 @@ export class TrigoViewport {
|
|
| 857 |
if (isHovered && this.isGameActive && !centerStone) {
|
| 858 |
// Preview joints connecting to adjacent stones of current player's color
|
| 859 |
const previewColor = this.currentPlayerColor;
|
| 860 |
-
const previewOpacity =
|
|
|
|
|
|
|
|
|
|
| 861 |
|
| 862 |
// Check -X direction (left neighbor)
|
| 863 |
if (x > 0) {
|
|
@@ -866,10 +932,22 @@ export class TrigoViewport {
|
|
| 866 |
if (leftStone && leftStone.color === previewColor) {
|
| 867 |
const leftJointNodes = this.joints.get(leftKey);
|
| 868 |
if (leftJointNodes?.X) {
|
| 869 |
-
const material = leftJointNodes.X
|
| 870 |
-
|
| 871 |
-
material.
|
| 872 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 873 |
material.opacity = previewOpacity;
|
| 874 |
material.transparent = true;
|
| 875 |
leftJointNodes.X.visible = true;
|
|
@@ -884,10 +962,22 @@ export class TrigoViewport {
|
|
| 884 |
if (bottomStone && bottomStone.color === previewColor) {
|
| 885 |
const bottomJointNodes = this.joints.get(bottomKey);
|
| 886 |
if (bottomJointNodes?.Y) {
|
| 887 |
-
const material = bottomJointNodes.Y
|
| 888 |
-
|
| 889 |
-
material.
|
| 890 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 891 |
material.opacity = previewOpacity;
|
| 892 |
material.transparent = true;
|
| 893 |
bottomJointNodes.Y.visible = true;
|
|
@@ -902,10 +992,22 @@ export class TrigoViewport {
|
|
| 902 |
if (backStone && backStone.color === previewColor) {
|
| 903 |
const backJointNodes = this.joints.get(backKey);
|
| 904 |
if (backJointNodes?.Z) {
|
| 905 |
-
const material = backJointNodes.Z
|
| 906 |
-
|
| 907 |
-
material.
|
| 908 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 909 |
material.opacity = previewOpacity;
|
| 910 |
material.transparent = true;
|
| 911 |
backJointNodes.Z.visible = true;
|
|
@@ -919,9 +1021,20 @@ export class TrigoViewport {
|
|
| 919 |
const rightStone = this.stones.get(rightKey);
|
| 920 |
if (rightStone && rightStone.color === previewColor) {
|
| 921 |
const material = jointNodes.X.material as THREE.MeshPhongMaterial;
|
| 922 |
-
material.color.set(
|
| 923 |
-
|
| 924 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 925 |
material.opacity = previewOpacity;
|
| 926 |
material.transparent = true;
|
| 927 |
jointNodes.X.visible = true;
|
|
@@ -934,9 +1047,20 @@ export class TrigoViewport {
|
|
| 934 |
const topStone = this.stones.get(topKey);
|
| 935 |
if (topStone && topStone.color === previewColor) {
|
| 936 |
const material = jointNodes.Y.material as THREE.MeshPhongMaterial;
|
| 937 |
-
material.color.set(
|
| 938 |
-
|
| 939 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 940 |
material.opacity = previewOpacity;
|
| 941 |
material.transparent = true;
|
| 942 |
jointNodes.Y.visible = true;
|
|
@@ -949,9 +1073,20 @@ export class TrigoViewport {
|
|
| 949 |
const frontStone = this.stones.get(frontKey);
|
| 950 |
if (frontStone && frontStone.color === previewColor) {
|
| 951 |
const material = jointNodes.Z.material as THREE.MeshPhongMaterial;
|
| 952 |
-
material.color.set(
|
| 953 |
-
|
| 954 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 955 |
material.opacity = previewOpacity;
|
| 956 |
material.transparent = true;
|
| 957 |
jointNodes.Z.visible = true;
|
|
@@ -963,7 +1098,6 @@ export class TrigoViewport {
|
|
| 963 |
}
|
| 964 |
}
|
| 965 |
|
| 966 |
-
|
| 967 |
public setCurrentPlayer(color: "black" | "white"): void {
|
| 968 |
this.currentPlayerColor = color;
|
| 969 |
this.updatePreviewStoneColor();
|
|
@@ -973,7 +1107,6 @@ export class TrigoViewport {
|
|
| 973 |
this.isGameActive = active;
|
| 974 |
}
|
| 975 |
|
| 976 |
-
|
| 977 |
public hidePreviewStone(): void {
|
| 978 |
if (this.previewStone) {
|
| 979 |
this.previewStone.visible = false;
|
|
@@ -982,11 +1115,14 @@ export class TrigoViewport {
|
|
| 982 |
this.refreshJoints();
|
| 983 |
}
|
| 984 |
|
| 985 |
-
|
| 986 |
public setLastPlacedStone(x: number | null, y: number | null, z: number | null): void {
|
| 987 |
// Clear previous stone's emissive glow
|
| 988 |
if (this.lastPlacedStone) {
|
| 989 |
-
const prevKey = this.getStoneKey(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 990 |
const prevStone = this.stones.get(prevKey);
|
| 991 |
if (prevStone && prevStone.mesh) {
|
| 992 |
const prevMaterial = prevStone.mesh.material as THREE.MeshPhongMaterial;
|
|
@@ -1003,7 +1139,6 @@ export class TrigoViewport {
|
|
| 1003 |
}
|
| 1004 |
}
|
| 1005 |
|
| 1006 |
-
|
| 1007 |
// Domain visibility methods (for territory display)
|
| 1008 |
public setBlackDomainVisible(visible: boolean): void {
|
| 1009 |
if (this.blackDomainVisible !== visible) {
|
|
@@ -1048,9 +1183,13 @@ export class TrigoViewport {
|
|
| 1048 |
this.setWhiteDomainVisible(false);
|
| 1049 |
}
|
| 1050 |
|
| 1051 |
-
|
| 1052 |
public setBoardShape(shape: BoardShape): void {
|
| 1053 |
-
if (
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1054 |
|
| 1055 |
this.boardShape = shape;
|
| 1056 |
|
|
@@ -1145,7 +1284,7 @@ export class TrigoViewport {
|
|
| 1145 |
}
|
| 1146 |
|
| 1147 |
// Check if mouse is not hovering over canvas and cleanup
|
| 1148 |
-
if (!this.canvas.matches(
|
| 1149 |
// Hide preview stone when mouse is outside canvas
|
| 1150 |
if (this.previewStone) {
|
| 1151 |
this.previewStone.visible = false;
|
|
@@ -1202,8 +1341,11 @@ export class TrigoViewport {
|
|
| 1202 |
|
| 1203 |
// Remove previous highlight
|
| 1204 |
if (this.highlightedPoint) {
|
| 1205 |
-
(this.highlightedPoint.material as THREE.MeshBasicMaterial).color.set(
|
| 1206 |
-
|
|
|
|
|
|
|
|
|
|
| 1207 |
this.highlightedPoint = null;
|
| 1208 |
}
|
| 1209 |
|
|
@@ -1225,7 +1367,9 @@ export class TrigoViewport {
|
|
| 1225 |
|
| 1226 |
this.highlightedPoint = point;
|
| 1227 |
// Use green for valid/droppable, red for invalid (game inactive or violates rules)
|
| 1228 |
-
const hoverColor = isDroppable
|
|
|
|
|
|
|
| 1229 |
(point.material as THREE.MeshBasicMaterial).color.set(hoverColor);
|
| 1230 |
(point.material as THREE.MeshBasicMaterial).opacity = OPACITY.POINT_HOVERED;
|
| 1231 |
|
|
@@ -1338,7 +1482,7 @@ export class TrigoViewport {
|
|
| 1338 |
|
| 1339 |
// Update last placed stone highlight effect only when mouse is over canvas
|
| 1340 |
// Using :hover pseudo-class check for better accuracy
|
| 1341 |
-
if (this.canvas.matches && this.canvas.matches(
|
| 1342 |
this.updateLastStoneHighlight();
|
| 1343 |
}
|
| 1344 |
|
|
@@ -1358,7 +1502,9 @@ export class TrigoViewport {
|
|
| 1358 |
this.lastCameraDistance = cameraDistance;
|
| 1359 |
|
| 1360 |
// Calculate diagonal distance of the board
|
| 1361 |
-
const diagonal = Math.sqrt(
|
|
|
|
|
|
|
| 1362 |
const boardDiagonal = diagonal * this.gridSpacing;
|
| 1363 |
|
| 1364 |
// Update fog near and far based on camera distance +/- diagonal
|
|
@@ -1389,8 +1535,14 @@ export class TrigoViewport {
|
|
| 1389 |
const emissiveColor = new THREE.Color(...SHINING.EMISSIVE_COLOR);
|
| 1390 |
|
| 1391 |
// Scale intensity based on stone color (white stones get brighter glow)
|
| 1392 |
-
const baseIntensity =
|
| 1393 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1394 |
const intensity = flicker * flickerIntensity + baseIntensity;
|
| 1395 |
|
| 1396 |
material.emissive = emissiveColor;
|
|
@@ -1411,7 +1563,7 @@ export class TrigoViewport {
|
|
| 1411 |
|
| 1412 |
if (intersects.length > 0) {
|
| 1413 |
// Find the position of the clicked stone
|
| 1414 |
-
let clickedPosition: {x: number
|
| 1415 |
|
| 1416 |
for (const [, stone] of this.stones.entries()) {
|
| 1417 |
if (stone.mesh === intersects[0].object) {
|
|
@@ -1430,7 +1582,10 @@ export class TrigoViewport {
|
|
| 1430 |
|
| 1431 |
// Notify callback with group info
|
| 1432 |
if (this.callbacks.onInspectGroup) {
|
| 1433 |
-
this.callbacks.onInspectGroup(
|
|
|
|
|
|
|
|
|
|
| 1434 |
}
|
| 1435 |
}
|
| 1436 |
} else {
|
|
@@ -1443,7 +1598,7 @@ export class TrigoViewport {
|
|
| 1443 |
}
|
| 1444 |
}
|
| 1445 |
|
| 1446 |
-
private findConnectedGroup(startPos: {x: number
|
| 1447 |
const group = new Set<string>();
|
| 1448 |
const startKey = this.getStoneKey(startPos.x, startPos.y, startPos.z);
|
| 1449 |
const startStone = this.stones.get(startKey);
|
|
@@ -1451,7 +1606,7 @@ export class TrigoViewport {
|
|
| 1451 |
if (!startStone) return group;
|
| 1452 |
|
| 1453 |
const color = startStone.color;
|
| 1454 |
-
const queue: {x: number
|
| 1455 |
const visited = new Set<string>();
|
| 1456 |
|
| 1457 |
while (queue.length > 0) {
|
|
@@ -1468,19 +1623,24 @@ export class TrigoViewport {
|
|
| 1468 |
|
| 1469 |
// Check all 6 neighbors in 3D space
|
| 1470 |
const neighbors = [
|
| 1471 |
-
{x: pos.x + 1, y: pos.y, z: pos.z},
|
| 1472 |
-
{x: pos.x - 1, y: pos.y, z: pos.z},
|
| 1473 |
-
{x: pos.x, y: pos.y + 1, z: pos.z},
|
| 1474 |
-
{x: pos.x, y: pos.y - 1, z: pos.z},
|
| 1475 |
-
{x: pos.x, y: pos.y, z: pos.z + 1},
|
| 1476 |
-
{x: pos.x, y: pos.y, z: pos.z - 1}
|
| 1477 |
];
|
| 1478 |
|
| 1479 |
for (const neighbor of neighbors) {
|
| 1480 |
// Check if neighbor is within board bounds
|
| 1481 |
-
if (
|
| 1482 |
-
neighbor.
|
| 1483 |
-
neighbor.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1484 |
const neighborKey = this.getStoneKey(neighbor.x, neighbor.y, neighbor.z);
|
| 1485 |
if (!visited.has(neighborKey)) {
|
| 1486 |
queue.push(neighbor);
|
|
@@ -1497,24 +1657,29 @@ export class TrigoViewport {
|
|
| 1497 |
|
| 1498 |
// For each stone in the group, check its neighbors for empty positions
|
| 1499 |
for (const key of group) {
|
| 1500 |
-
const parts = key.split(
|
| 1501 |
-
const pos = {x: parts[0], y: parts[1], z: parts[2]};
|
| 1502 |
|
| 1503 |
// Check all 6 neighbors
|
| 1504 |
const neighbors = [
|
| 1505 |
-
{x: pos.x + 1, y: pos.y, z: pos.z},
|
| 1506 |
-
{x: pos.x - 1, y: pos.y, z: pos.z},
|
| 1507 |
-
{x: pos.x, y: pos.y + 1, z: pos.z},
|
| 1508 |
-
{x: pos.x, y: pos.y - 1, z: pos.z},
|
| 1509 |
-
{x: pos.x, y: pos.y, z: pos.z + 1},
|
| 1510 |
-
{x: pos.x, y: pos.y, z: pos.z - 1}
|
| 1511 |
];
|
| 1512 |
|
| 1513 |
for (const neighbor of neighbors) {
|
| 1514 |
// Check if neighbor is within bounds
|
| 1515 |
-
if (
|
| 1516 |
-
neighbor.
|
| 1517 |
-
neighbor.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1518 |
const neighborKey = this.getStoneKey(neighbor.x, neighbor.y, neighbor.z);
|
| 1519 |
// If neighbor is empty (not in stones map), it's a liberty
|
| 1520 |
if (!this.stones.has(neighborKey)) {
|
|
@@ -1527,7 +1692,6 @@ export class TrigoViewport {
|
|
| 1527 |
return { count: liberties.size, positions: liberties };
|
| 1528 |
}
|
| 1529 |
|
| 1530 |
-
|
| 1531 |
private updateStoneOpacity(): void {
|
| 1532 |
// Update opacity of all stones based on inspect mode
|
| 1533 |
this.stones.forEach((stone, key) => {
|
|
@@ -1558,7 +1722,6 @@ export class TrigoViewport {
|
|
| 1558 |
this.updateAirPatchVisualization();
|
| 1559 |
}
|
| 1560 |
|
| 1561 |
-
|
| 1562 |
private updateAirPatchVisualization(): void {
|
| 1563 |
// Reset all intersection points to default color
|
| 1564 |
this.intersectionPoints.children.forEach((child) => {
|
|
@@ -1591,8 +1754,10 @@ export class TrigoViewport {
|
|
| 1591 |
});
|
| 1592 |
}
|
| 1593 |
|
| 1594 |
-
|
| 1595 |
-
|
|
|
|
|
|
|
| 1596 |
// Update domain cube visibility based on territory and air patch
|
| 1597 |
this.domainCubes.forEach((cube, key) => {
|
| 1598 |
const material = cube.material as THREE.MeshBasicMaterial;
|
|
@@ -1620,7 +1785,6 @@ export class TrigoViewport {
|
|
| 1620 |
});
|
| 1621 |
}
|
| 1622 |
|
| 1623 |
-
|
| 1624 |
private onKeyDown(event: KeyboardEvent): void {
|
| 1625 |
// Ctrl key (17) or Meta key (91/93) for Mac
|
| 1626 |
if (event.ctrlKey || event.metaKey) {
|
|
@@ -1651,7 +1815,6 @@ export class TrigoViewport {
|
|
| 1651 |
}
|
| 1652 |
}
|
| 1653 |
|
| 1654 |
-
|
| 1655 |
public destroy(): void {
|
| 1656 |
this.isDestroyed = true;
|
| 1657 |
|
|
|
|
| 9 |
SCENE_CLEAR: 0x505055,
|
| 10 |
|
| 11 |
// Chess frame colors (three-tiered system)
|
| 12 |
+
FRAME_CREST: 0xff4d4d, // Red-tinted for edges/corners
|
| 13 |
+
FRAME_SURFACE: 0xe6b380, // Orange/yellow-tinted for face edges
|
| 14 |
+
FRAME_INTERIOR: 0x999999, // Gray for interior lines
|
| 15 |
|
| 16 |
// intersection point colors
|
| 17 |
POINT_DEFAULT: 0x4a90e2,
|
| 18 |
POINT_HOVERED: 0x00ff00,
|
| 19 |
POINT_HOVERED_DISABLED: 0xff0000,
|
| 20 |
POINT_AXIS_ALIGNED: 0xffaa00,
|
| 21 |
+
POINT_AIR_PATCH: 0x80e680, // Semi-transparent green for liberties in inspect mode
|
| 22 |
|
| 23 |
// Stone colors
|
| 24 |
STONE_BLACK: 0x070707,
|
|
|
|
| 32 |
AMBIENT_LIGHT: 0xffffff,
|
| 33 |
DIRECTIONAL_LIGHT: 0xffffff,
|
| 34 |
HEMISPHERE_LIGHT_SKY: 0xeefaff,
|
| 35 |
+
HEMISPHERE_LIGHT_GROUND: 0x20201a
|
| 36 |
} as const;
|
| 37 |
|
| 38 |
// Opacity constants
|
|
|
|
| 46 |
POINT_DEFAULT: 0.1,
|
| 47 |
POINT_HOVERED: 0.8,
|
| 48 |
POINT_AXIS_ALIGNED: 0.8,
|
| 49 |
+
POINT_AIR_PATCH: 0.24, // Semi-transparent for liberty visualization
|
| 50 |
PREVIEW_STONE: 0.5,
|
| 51 |
PREVIEW_JOINT_BLACK: 0.5,
|
| 52 |
PREVIEW_JOINT_WHITE: 0.6,
|
| 53 |
DIMMED: 0.3,
|
| 54 |
DOMAIN_BLACK: 0.3,
|
| 55 |
+
DOMAIN_WHITE: 0.3
|
| 56 |
} as const;
|
| 57 |
|
| 58 |
// Shininess constants for stone materials
|
| 59 |
const SHININESS = {
|
| 60 |
STONE_BLACK: 120,
|
| 61 |
+
STONE_WHITE: 30
|
| 62 |
} as const;
|
| 63 |
|
|
|
|
| 64 |
// Geometric size constants
|
| 65 |
const SIZES = {
|
| 66 |
// Stone and point sizes (relative to grid spacing)
|
|
|
|
| 73 |
// Sphere detail (number of segments)
|
| 74 |
STONE_SEGMENTS: 32,
|
| 75 |
POINT_SEGMENTS: 8,
|
| 76 |
+
JOINT_SEGMENTS: 6
|
| 77 |
} as const;
|
| 78 |
|
|
|
|
| 79 |
// Camera and scene constants
|
| 80 |
const CAMERA = {
|
| 81 |
FOV: 70,
|
| 82 |
NEAR: 0.1,
|
| 83 |
FAR: 1000,
|
| 84 |
DISTANCE_MULTIPLIER: 1.1,
|
| 85 |
+
HEIGHT_RATIO: 0.8
|
| 86 |
} as const;
|
| 87 |
|
|
|
|
| 88 |
// Lighting intensity constants
|
| 89 |
const LIGHTING = {
|
| 90 |
AMBIENT_INTENSITY: 0.2,
|
| 91 |
DIRECTIONAL_MAIN_INTENSITY: 0.8,
|
| 92 |
DIRECTIONAL_FILL_INTENSITY: 0.3,
|
| 93 |
+
HEMISPHERE_INTENSITY: 0.8
|
| 94 |
} as const;
|
| 95 |
|
|
|
|
| 96 |
// Fog constants
|
| 97 |
const FOG = {
|
| 98 |
NEAR_FACTOR: 0.2,
|
| 99 |
FAR_FACTOR: 0.8,
|
| 100 |
+
MIN_NEAR: 0.1
|
| 101 |
} as const;
|
| 102 |
|
|
|
|
| 103 |
// Last stone highlight constants
|
| 104 |
const SHINING = {
|
| 105 |
FLICKER_SPEED: 0.0048,
|
|
|
|
| 107 |
BASE_INTENSITY_WHITE: 0.2,
|
| 108 |
BASE_INTENSITY_BLACK: 0.06,
|
| 109 |
FLICKER_INTENSITY_WHITE: 0.6,
|
| 110 |
+
FLICKER_INTENSITY_BLACK: 0.1
|
| 111 |
} as const;
|
| 112 |
|
|
|
|
| 113 |
export interface Stone {
|
| 114 |
position: { x: number; y: number; z: number };
|
| 115 |
color: "black" | "white";
|
|
|
|
| 166 |
private inspectMode: boolean = false;
|
| 167 |
private ctrlKeyDown: boolean = false;
|
| 168 |
private highlightedGroup: Set<string> | null = null;
|
| 169 |
+
private airPatch: Set<string> | null = null; // Liberty positions for highlighted group
|
| 170 |
private lastMouseEvent: MouseEvent | null = null;
|
| 171 |
|
| 172 |
// Domain visibility for territory display
|
|
|
|
| 175 |
private blackDomain: Set<string> | null = null;
|
| 176 |
private whiteDomain: Set<string> | null = null;
|
| 177 |
|
| 178 |
+
constructor(
|
| 179 |
+
canvas: HTMLCanvasElement,
|
| 180 |
+
boardShape: BoardShape = { x: 5, y: 5, z: 5 },
|
| 181 |
+
callbacks: ViewportCallbacks = {}
|
| 182 |
+
) {
|
| 183 |
this.canvas = canvas;
|
| 184 |
this.boardShape = boardShape;
|
| 185 |
this.callbacks = callbacks;
|
|
|
|
| 263 |
}
|
| 264 |
|
| 265 |
private createPreviewStone(): void {
|
| 266 |
+
const geometry = new THREE.SphereGeometry(
|
| 267 |
+
SIZES.STONE_RADIUS * this.gridSpacing,
|
| 268 |
+
SIZES.STONE_SEGMENTS,
|
| 269 |
+
SIZES.STONE_SEGMENTS
|
| 270 |
+
);
|
| 271 |
const material = new THREE.MeshPhongMaterial({
|
| 272 |
color: this.currentPlayerColor === "black" ? COLORS.STONE_BLACK : COLORS.STONE_WHITE,
|
| 273 |
transparent: true,
|
| 274 |
opacity: OPACITY.PREVIEW_STONE,
|
| 275 |
+
shininess:
|
| 276 |
+
this.currentPlayerColor === "black" ? SHININESS.STONE_BLACK : SHININESS.STONE_WHITE
|
| 277 |
});
|
| 278 |
this.previewStone = new THREE.Mesh(geometry, material);
|
| 279 |
this.previewStone.visible = false; // Hidden by default
|
|
|
|
| 283 |
private updatePreviewStoneColor(): void {
|
| 284 |
if (!this.previewStone) return;
|
| 285 |
const material = this.previewStone.material as THREE.MeshPhongMaterial;
|
| 286 |
+
material.color.set(
|
| 287 |
+
this.currentPlayerColor === "black" ? COLORS.STONE_BLACK : COLORS.STONE_WHITE
|
| 288 |
+
);
|
| 289 |
+
material.shininess =
|
| 290 |
+
this.currentPlayerColor === "black" ? SHININESS.STONE_BLACK : SHININESS.STONE_WHITE;
|
| 291 |
}
|
| 292 |
|
| 293 |
private setupFog(): void {
|
|
|
|
| 335 |
|
| 336 |
private setupLighting(): void {
|
| 337 |
// Ambient light
|
| 338 |
+
const ambientLight = new THREE.AmbientLight(
|
| 339 |
+
COLORS.AMBIENT_LIGHT,
|
| 340 |
+
LIGHTING.AMBIENT_INTENSITY
|
| 341 |
+
);
|
| 342 |
this.scene.add(ambientLight);
|
| 343 |
|
| 344 |
// Directional light (main)
|
| 345 |
+
const directionalLight1 = new THREE.DirectionalLight(
|
| 346 |
+
COLORS.DIRECTIONAL_LIGHT,
|
| 347 |
+
LIGHTING.DIRECTIONAL_MAIN_INTENSITY
|
| 348 |
+
);
|
| 349 |
directionalLight1.position.set(10, 20, 10);
|
| 350 |
directionalLight1.castShadow = true;
|
| 351 |
this.scene.add(directionalLight1);
|
| 352 |
|
| 353 |
// Directional light (fill)
|
| 354 |
+
const directionalLight2 = new THREE.DirectionalLight(
|
| 355 |
+
COLORS.DIRECTIONAL_LIGHT,
|
| 356 |
+
LIGHTING.DIRECTIONAL_FILL_INTENSITY
|
| 357 |
+
);
|
| 358 |
directionalLight2.position.set(-10, -10, -10);
|
| 359 |
this.scene.add(directionalLight2);
|
| 360 |
|
| 361 |
// Hemisphere light for softer ambient
|
| 362 |
+
const hemisphereLight = new THREE.HemisphereLight(
|
| 363 |
+
COLORS.HEMISPHERE_LIGHT_SKY,
|
| 364 |
+
COLORS.HEMISPHERE_LIGHT_GROUND,
|
| 365 |
+
LIGHTING.HEMISPHERE_INTENSITY
|
| 366 |
+
);
|
| 367 |
hemisphereLight.position.set(0, 20, 0);
|
| 368 |
this.scene.add(hemisphereLight);
|
| 369 |
}
|
|
|
|
| 399 |
|
| 400 |
// Helper function to determine material based on border conditions
|
| 401 |
const getLineMaterial = (border1: boolean, border2: boolean): THREE.LineBasicMaterial => {
|
| 402 |
+
if (border1 && border2) return crestMaterial; // Both borders -> crest
|
| 403 |
+
if (border1 || border2) return surfaceMaterial; // One border -> surface
|
| 404 |
+
return interiorMaterial; // No borders -> interior
|
| 405 |
};
|
| 406 |
|
| 407 |
// X-axis lines (parallel to X)
|
| 408 |
for (let y = 0; y < sizeY; y++) {
|
| 409 |
for (let z = 0; z < sizeZ; z++) {
|
| 410 |
+
const border1 = y === 0 || y === sizeY - 1;
|
| 411 |
+
const border2 = z === 0 || z === sizeZ - 1;
|
| 412 |
const material = getLineMaterial(border1, border2);
|
| 413 |
|
| 414 |
const points = [];
|
|
|
|
| 430 |
// Y-axis lines (parallel to Y)
|
| 431 |
for (let x = 0; x < sizeX; x++) {
|
| 432 |
for (let z = 0; z < sizeZ; z++) {
|
| 433 |
+
const border1 = x === 0 || x === sizeX - 1;
|
| 434 |
+
const border2 = z === 0 || z === sizeZ - 1;
|
| 435 |
const material = getLineMaterial(border1, border2);
|
| 436 |
|
| 437 |
const points = [];
|
|
|
|
| 454 |
if (sizeZ >= 3) {
|
| 455 |
for (let x = 0; x < sizeX; x++) {
|
| 456 |
for (let y = 0; y < sizeY; y++) {
|
| 457 |
+
const border1 = x === 0 || x === sizeX - 1;
|
| 458 |
+
const border2 = y === 0 || y === sizeY - 1;
|
| 459 |
const material = getLineMaterial(border1, border2);
|
| 460 |
|
| 461 |
const points = [];
|
|
|
|
| 487 |
const axisLength = maxOffset * 1.2;
|
| 488 |
const axesMaterial = [
|
| 489 |
new THREE.LineBasicMaterial({ color: 0xff0000 }), // X axis - red
|
| 490 |
+
new THREE.LineBasicMaterial({ color: 0x00ff00 }) // Y axis - green
|
| 491 |
];
|
| 492 |
|
| 493 |
// X axis
|
| 494 |
+
const xPoints = [new THREE.Vector3(0, 0, 0), new THREE.Vector3(axisLength, 0, 0)];
|
|
|
|
|
|
|
|
|
|
| 495 |
const xGeometry = new THREE.BufferGeometry().setFromPoints(xPoints);
|
| 496 |
const xLine = new THREE.Line(xGeometry, axesMaterial[0]);
|
| 497 |
this.gridGroup.add(xLine);
|
| 498 |
|
| 499 |
// Y axis
|
| 500 |
+
const yPoints = [new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, axisLength, 0)];
|
|
|
|
|
|
|
|
|
|
| 501 |
const yGeometry = new THREE.BufferGeometry().setFromPoints(yPoints);
|
| 502 |
const yLine = new THREE.Line(yGeometry, axesMaterial[1]);
|
| 503 |
this.gridGroup.add(yLine);
|
|
|
|
| 512 |
const offsetZ = ((sizeZ - 1) * spacing) / 2;
|
| 513 |
|
| 514 |
// Create small spheres at each grid intersection
|
| 515 |
+
const pointGeometry = new THREE.SphereGeometry(
|
| 516 |
+
SIZES.INTERSECTION_POINT_RADIUS,
|
| 517 |
+
SIZES.POINT_SEGMENTS,
|
| 518 |
+
SIZES.POINT_SEGMENTS
|
| 519 |
+
);
|
| 520 |
|
| 521 |
for (let x = 0; x < sizeX; x++) {
|
| 522 |
for (let y = 0; y < sizeY; y++) {
|
|
|
|
| 540 |
}
|
| 541 |
}
|
| 542 |
|
|
|
|
| 543 |
private createJoints(): void {
|
| 544 |
const { x: sizeX, y: sizeY, z: sizeZ } = this.boardShape;
|
| 545 |
const spacing = this.gridSpacing;
|
|
|
|
| 560 |
|
| 561 |
// Create X-axis joint (between current and next X position)
|
| 562 |
if (x < sizeX - 1) {
|
| 563 |
+
const geometry = new THREE.CylinderGeometry(
|
| 564 |
+
jointRadius,
|
| 565 |
+
jointRadius,
|
| 566 |
+
jointLength,
|
| 567 |
+
SIZES.JOINT_SEGMENTS
|
| 568 |
+
);
|
| 569 |
const material = new THREE.MeshPhongMaterial({
|
| 570 |
color: COLORS.STONE_BLACK,
|
| 571 |
shininess: SHININESS.STONE_BLACK,
|
|
|
|
| 588 |
|
| 589 |
// Create Y-axis joint (between current and next Y position)
|
| 590 |
if (y < sizeY - 1) {
|
| 591 |
+
const geometry = new THREE.CylinderGeometry(
|
| 592 |
+
jointRadius,
|
| 593 |
+
jointRadius,
|
| 594 |
+
jointLength,
|
| 595 |
+
SIZES.JOINT_SEGMENTS
|
| 596 |
+
);
|
| 597 |
const material = new THREE.MeshPhongMaterial({
|
| 598 |
color: COLORS.STONE_BLACK,
|
| 599 |
shininess: SHININESS.STONE_BLACK,
|
|
|
|
| 616 |
|
| 617 |
// Create Z-axis joint (between current and next Z position)
|
| 618 |
if (z < sizeZ - 1) {
|
| 619 |
+
const geometry = new THREE.CylinderGeometry(
|
| 620 |
+
jointRadius,
|
| 621 |
+
jointRadius,
|
| 622 |
+
jointLength,
|
| 623 |
+
SIZES.JOINT_SEGMENTS
|
| 624 |
+
);
|
| 625 |
const material = new THREE.MeshPhongMaterial({
|
| 626 |
color: COLORS.STONE_BLACK,
|
| 627 |
shininess: SHININESS.STONE_BLACK,
|
|
|
|
| 648 |
}
|
| 649 |
}
|
| 650 |
|
|
|
|
| 651 |
private createDomainCubes(): void {
|
| 652 |
const { x: sizeX, y: sizeY, z: sizeZ } = this.boardShape;
|
| 653 |
const spacing = this.gridSpacing;
|
|
|
|
| 672 |
color: COLORS.STONE_BLACK,
|
| 673 |
transparent: true,
|
| 674 |
opacity: OPACITY.DOMAIN_BLACK,
|
| 675 |
+
depthWrite: false // Prevent z-fighting with stones
|
| 676 |
});
|
| 677 |
|
| 678 |
const cube = new THREE.Mesh(geometry, material);
|
|
|
|
| 712 |
const offsetZ = ((this.boardShape.z - 1) * spacing) / 2;
|
| 713 |
|
| 714 |
// Create stone geometry
|
| 715 |
+
const geometry = new THREE.SphereGeometry(
|
| 716 |
+
SIZES.STONE_RADIUS * this.gridSpacing,
|
| 717 |
+
SIZES.STONE_SEGMENTS,
|
| 718 |
+
SIZES.STONE_SEGMENTS
|
| 719 |
+
);
|
| 720 |
const material = new THREE.MeshPhongMaterial({
|
| 721 |
color: color === "black" ? COLORS.STONE_BLACK : COLORS.STONE_WHITE,
|
| 722 |
shininess: color === "black" ? SHININESS.STONE_BLACK : SHININESS.STONE_WHITE,
|
|
|
|
| 726 |
});
|
| 727 |
|
| 728 |
const stoneMesh = new THREE.Mesh(geometry, material);
|
| 729 |
+
stoneMesh.position.set(x * spacing - offsetX, y * spacing - offsetY, z * spacing - offsetZ);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 730 |
|
| 731 |
const stone: Stone = {
|
| 732 |
position: { x, y, z },
|
|
|
|
| 798 |
return this.stones.has(this.getStoneKey(x, y, z));
|
| 799 |
}
|
| 800 |
|
|
|
|
| 801 |
private refreshJoints(): void {
|
| 802 |
const { x: sizeX, y: sizeY, z: sizeZ } = this.boardShape;
|
| 803 |
|
|
|
|
| 819 |
|
| 820 |
if (nextStone && nextStone.color === centerStone.color) {
|
| 821 |
const material = jointNodes.X.material as THREE.MeshPhongMaterial;
|
| 822 |
+
material.color.set(
|
| 823 |
+
centerStone.color === "black"
|
| 824 |
+
? COLORS.STONE_BLACK
|
| 825 |
+
: COLORS.STONE_WHITE
|
| 826 |
+
);
|
| 827 |
+
material.shininess =
|
| 828 |
+
centerStone.color === "black"
|
| 829 |
+
? SHININESS.STONE_BLACK
|
| 830 |
+
: SHININESS.STONE_WHITE;
|
| 831 |
+
material.specular.set(
|
| 832 |
+
centerStone.color === "black"
|
| 833 |
+
? COLORS.STONE_BLACK_SPECULAR
|
| 834 |
+
: COLORS.STONE_WHITE_SPECULAR
|
| 835 |
+
);
|
| 836 |
material.opacity = 1.0;
|
| 837 |
material.transparent = false;
|
| 838 |
jointNodes.X.visible = true;
|
|
|
|
| 852 |
|
| 853 |
if (nextStone && nextStone.color === centerStone.color) {
|
| 854 |
const material = jointNodes.Y.material as THREE.MeshPhongMaterial;
|
| 855 |
+
material.color.set(
|
| 856 |
+
centerStone.color === "black"
|
| 857 |
+
? COLORS.STONE_BLACK
|
| 858 |
+
: COLORS.STONE_WHITE
|
| 859 |
+
);
|
| 860 |
+
material.shininess =
|
| 861 |
+
centerStone.color === "black"
|
| 862 |
+
? SHININESS.STONE_BLACK
|
| 863 |
+
: SHININESS.STONE_WHITE;
|
| 864 |
+
material.specular.set(
|
| 865 |
+
centerStone.color === "black"
|
| 866 |
+
? COLORS.STONE_BLACK_SPECULAR
|
| 867 |
+
: COLORS.STONE_WHITE_SPECULAR
|
| 868 |
+
);
|
| 869 |
material.opacity = 1.0;
|
| 870 |
material.transparent = false;
|
| 871 |
jointNodes.Y.visible = true;
|
|
|
|
| 885 |
|
| 886 |
if (nextStone && nextStone.color === centerStone.color) {
|
| 887 |
const material = jointNodes.Z.material as THREE.MeshPhongMaterial;
|
| 888 |
+
material.color.set(
|
| 889 |
+
centerStone.color === "black"
|
| 890 |
+
? COLORS.STONE_BLACK
|
| 891 |
+
: COLORS.STONE_WHITE
|
| 892 |
+
);
|
| 893 |
+
material.shininess =
|
| 894 |
+
centerStone.color === "black"
|
| 895 |
+
? SHININESS.STONE_BLACK
|
| 896 |
+
: SHININESS.STONE_WHITE;
|
| 897 |
+
material.specular.set(
|
| 898 |
+
centerStone.color === "black"
|
| 899 |
+
? COLORS.STONE_BLACK_SPECULAR
|
| 900 |
+
: COLORS.STONE_WHITE_SPECULAR
|
| 901 |
+
);
|
| 902 |
material.opacity = 1.0;
|
| 903 |
material.transparent = false;
|
| 904 |
jointNodes.Z.visible = true;
|
|
|
|
| 911 |
}
|
| 912 |
|
| 913 |
// Show preview joints if hovering over this position
|
| 914 |
+
const isHovered =
|
| 915 |
+
this.hoveredPosition &&
|
| 916 |
this.hoveredPosition.x === x &&
|
| 917 |
this.hoveredPosition.y === y &&
|
| 918 |
this.hoveredPosition.z === z;
|
|
|
|
| 920 |
if (isHovered && this.isGameActive && !centerStone) {
|
| 921 |
// Preview joints connecting to adjacent stones of current player's color
|
| 922 |
const previewColor = this.currentPlayerColor;
|
| 923 |
+
const previewOpacity =
|
| 924 |
+
previewColor === "black"
|
| 925 |
+
? OPACITY.PREVIEW_JOINT_BLACK
|
| 926 |
+
: OPACITY.PREVIEW_JOINT_WHITE;
|
| 927 |
|
| 928 |
// Check -X direction (left neighbor)
|
| 929 |
if (x > 0) {
|
|
|
|
| 932 |
if (leftStone && leftStone.color === previewColor) {
|
| 933 |
const leftJointNodes = this.joints.get(leftKey);
|
| 934 |
if (leftJointNodes?.X) {
|
| 935 |
+
const material = leftJointNodes.X
|
| 936 |
+
.material as THREE.MeshPhongMaterial;
|
| 937 |
+
material.color.set(
|
| 938 |
+
previewColor === "black"
|
| 939 |
+
? COLORS.STONE_BLACK
|
| 940 |
+
: COLORS.STONE_WHITE
|
| 941 |
+
);
|
| 942 |
+
material.shininess =
|
| 943 |
+
previewColor === "black"
|
| 944 |
+
? SHININESS.STONE_BLACK
|
| 945 |
+
: SHININESS.STONE_WHITE;
|
| 946 |
+
material.specular.set(
|
| 947 |
+
previewColor === "black"
|
| 948 |
+
? COLORS.STONE_BLACK_SPECULAR
|
| 949 |
+
: COLORS.STONE_WHITE_SPECULAR
|
| 950 |
+
);
|
| 951 |
material.opacity = previewOpacity;
|
| 952 |
material.transparent = true;
|
| 953 |
leftJointNodes.X.visible = true;
|
|
|
|
| 962 |
if (bottomStone && bottomStone.color === previewColor) {
|
| 963 |
const bottomJointNodes = this.joints.get(bottomKey);
|
| 964 |
if (bottomJointNodes?.Y) {
|
| 965 |
+
const material = bottomJointNodes.Y
|
| 966 |
+
.material as THREE.MeshPhongMaterial;
|
| 967 |
+
material.color.set(
|
| 968 |
+
previewColor === "black"
|
| 969 |
+
? COLORS.STONE_BLACK
|
| 970 |
+
: COLORS.STONE_WHITE
|
| 971 |
+
);
|
| 972 |
+
material.shininess =
|
| 973 |
+
previewColor === "black"
|
| 974 |
+
? SHININESS.STONE_BLACK
|
| 975 |
+
: SHININESS.STONE_WHITE;
|
| 976 |
+
material.specular.set(
|
| 977 |
+
previewColor === "black"
|
| 978 |
+
? COLORS.STONE_BLACK_SPECULAR
|
| 979 |
+
: COLORS.STONE_WHITE_SPECULAR
|
| 980 |
+
);
|
| 981 |
material.opacity = previewOpacity;
|
| 982 |
material.transparent = true;
|
| 983 |
bottomJointNodes.Y.visible = true;
|
|
|
|
| 992 |
if (backStone && backStone.color === previewColor) {
|
| 993 |
const backJointNodes = this.joints.get(backKey);
|
| 994 |
if (backJointNodes?.Z) {
|
| 995 |
+
const material = backJointNodes.Z
|
| 996 |
+
.material as THREE.MeshPhongMaterial;
|
| 997 |
+
material.color.set(
|
| 998 |
+
previewColor === "black"
|
| 999 |
+
? COLORS.STONE_BLACK
|
| 1000 |
+
: COLORS.STONE_WHITE
|
| 1001 |
+
);
|
| 1002 |
+
material.shininess =
|
| 1003 |
+
previewColor === "black"
|
| 1004 |
+
? SHININESS.STONE_BLACK
|
| 1005 |
+
: SHININESS.STONE_WHITE;
|
| 1006 |
+
material.specular.set(
|
| 1007 |
+
previewColor === "black"
|
| 1008 |
+
? COLORS.STONE_BLACK_SPECULAR
|
| 1009 |
+
: COLORS.STONE_WHITE_SPECULAR
|
| 1010 |
+
);
|
| 1011 |
material.opacity = previewOpacity;
|
| 1012 |
material.transparent = true;
|
| 1013 |
backJointNodes.Z.visible = true;
|
|
|
|
| 1021 |
const rightStone = this.stones.get(rightKey);
|
| 1022 |
if (rightStone && rightStone.color === previewColor) {
|
| 1023 |
const material = jointNodes.X.material as THREE.MeshPhongMaterial;
|
| 1024 |
+
material.color.set(
|
| 1025 |
+
previewColor === "black"
|
| 1026 |
+
? COLORS.STONE_BLACK
|
| 1027 |
+
: COLORS.STONE_WHITE
|
| 1028 |
+
);
|
| 1029 |
+
material.shininess =
|
| 1030 |
+
previewColor === "black"
|
| 1031 |
+
? SHININESS.STONE_BLACK
|
| 1032 |
+
: SHININESS.STONE_WHITE;
|
| 1033 |
+
material.specular.set(
|
| 1034 |
+
previewColor === "black"
|
| 1035 |
+
? COLORS.STONE_BLACK_SPECULAR
|
| 1036 |
+
: COLORS.STONE_WHITE_SPECULAR
|
| 1037 |
+
);
|
| 1038 |
material.opacity = previewOpacity;
|
| 1039 |
material.transparent = true;
|
| 1040 |
jointNodes.X.visible = true;
|
|
|
|
| 1047 |
const topStone = this.stones.get(topKey);
|
| 1048 |
if (topStone && topStone.color === previewColor) {
|
| 1049 |
const material = jointNodes.Y.material as THREE.MeshPhongMaterial;
|
| 1050 |
+
material.color.set(
|
| 1051 |
+
previewColor === "black"
|
| 1052 |
+
? COLORS.STONE_BLACK
|
| 1053 |
+
: COLORS.STONE_WHITE
|
| 1054 |
+
);
|
| 1055 |
+
material.shininess =
|
| 1056 |
+
previewColor === "black"
|
| 1057 |
+
? SHININESS.STONE_BLACK
|
| 1058 |
+
: SHININESS.STONE_WHITE;
|
| 1059 |
+
material.specular.set(
|
| 1060 |
+
previewColor === "black"
|
| 1061 |
+
? COLORS.STONE_BLACK_SPECULAR
|
| 1062 |
+
: COLORS.STONE_WHITE_SPECULAR
|
| 1063 |
+
);
|
| 1064 |
material.opacity = previewOpacity;
|
| 1065 |
material.transparent = true;
|
| 1066 |
jointNodes.Y.visible = true;
|
|
|
|
| 1073 |
const frontStone = this.stones.get(frontKey);
|
| 1074 |
if (frontStone && frontStone.color === previewColor) {
|
| 1075 |
const material = jointNodes.Z.material as THREE.MeshPhongMaterial;
|
| 1076 |
+
material.color.set(
|
| 1077 |
+
previewColor === "black"
|
| 1078 |
+
? COLORS.STONE_BLACK
|
| 1079 |
+
: COLORS.STONE_WHITE
|
| 1080 |
+
);
|
| 1081 |
+
material.shininess =
|
| 1082 |
+
previewColor === "black"
|
| 1083 |
+
? SHININESS.STONE_BLACK
|
| 1084 |
+
: SHININESS.STONE_WHITE;
|
| 1085 |
+
material.specular.set(
|
| 1086 |
+
previewColor === "black"
|
| 1087 |
+
? COLORS.STONE_BLACK_SPECULAR
|
| 1088 |
+
: COLORS.STONE_WHITE_SPECULAR
|
| 1089 |
+
);
|
| 1090 |
material.opacity = previewOpacity;
|
| 1091 |
material.transparent = true;
|
| 1092 |
jointNodes.Z.visible = true;
|
|
|
|
| 1098 |
}
|
| 1099 |
}
|
| 1100 |
|
|
|
|
| 1101 |
public setCurrentPlayer(color: "black" | "white"): void {
|
| 1102 |
this.currentPlayerColor = color;
|
| 1103 |
this.updatePreviewStoneColor();
|
|
|
|
| 1107 |
this.isGameActive = active;
|
| 1108 |
}
|
| 1109 |
|
|
|
|
| 1110 |
public hidePreviewStone(): void {
|
| 1111 |
if (this.previewStone) {
|
| 1112 |
this.previewStone.visible = false;
|
|
|
|
| 1115 |
this.refreshJoints();
|
| 1116 |
}
|
| 1117 |
|
|
|
|
| 1118 |
public setLastPlacedStone(x: number | null, y: number | null, z: number | null): void {
|
| 1119 |
// Clear previous stone's emissive glow
|
| 1120 |
if (this.lastPlacedStone) {
|
| 1121 |
+
const prevKey = this.getStoneKey(
|
| 1122 |
+
this.lastPlacedStone.x,
|
| 1123 |
+
this.lastPlacedStone.y,
|
| 1124 |
+
this.lastPlacedStone.z
|
| 1125 |
+
);
|
| 1126 |
const prevStone = this.stones.get(prevKey);
|
| 1127 |
if (prevStone && prevStone.mesh) {
|
| 1128 |
const prevMaterial = prevStone.mesh.material as THREE.MeshPhongMaterial;
|
|
|
|
| 1139 |
}
|
| 1140 |
}
|
| 1141 |
|
|
|
|
| 1142 |
// Domain visibility methods (for territory display)
|
| 1143 |
public setBlackDomainVisible(visible: boolean): void {
|
| 1144 |
if (this.blackDomainVisible !== visible) {
|
|
|
|
| 1183 |
this.setWhiteDomainVisible(false);
|
| 1184 |
}
|
| 1185 |
|
|
|
|
| 1186 |
public setBoardShape(shape: BoardShape): void {
|
| 1187 |
+
if (
|
| 1188 |
+
shape.x === this.boardShape.x &&
|
| 1189 |
+
shape.y === this.boardShape.y &&
|
| 1190 |
+
shape.z === this.boardShape.z
|
| 1191 |
+
)
|
| 1192 |
+
return;
|
| 1193 |
|
| 1194 |
this.boardShape = shape;
|
| 1195 |
|
|
|
|
| 1284 |
}
|
| 1285 |
|
| 1286 |
// Check if mouse is not hovering over canvas and cleanup
|
| 1287 |
+
if (!this.canvas.matches(":hover")) {
|
| 1288 |
// Hide preview stone when mouse is outside canvas
|
| 1289 |
if (this.previewStone) {
|
| 1290 |
this.previewStone.visible = false;
|
|
|
|
| 1341 |
|
| 1342 |
// Remove previous highlight
|
| 1343 |
if (this.highlightedPoint) {
|
| 1344 |
+
(this.highlightedPoint.material as THREE.MeshBasicMaterial).color.set(
|
| 1345 |
+
COLORS.POINT_DEFAULT
|
| 1346 |
+
);
|
| 1347 |
+
(this.highlightedPoint.material as THREE.MeshBasicMaterial).opacity =
|
| 1348 |
+
OPACITY.POINT_DEFAULT;
|
| 1349 |
this.highlightedPoint = null;
|
| 1350 |
}
|
| 1351 |
|
|
|
|
| 1367 |
|
| 1368 |
this.highlightedPoint = point;
|
| 1369 |
// Use green for valid/droppable, red for invalid (game inactive or violates rules)
|
| 1370 |
+
const hoverColor = isDroppable
|
| 1371 |
+
? COLORS.POINT_HOVERED
|
| 1372 |
+
: COLORS.POINT_HOVERED_DISABLED;
|
| 1373 |
(point.material as THREE.MeshBasicMaterial).color.set(hoverColor);
|
| 1374 |
(point.material as THREE.MeshBasicMaterial).opacity = OPACITY.POINT_HOVERED;
|
| 1375 |
|
|
|
|
| 1482 |
|
| 1483 |
// Update last placed stone highlight effect only when mouse is over canvas
|
| 1484 |
// Using :hover pseudo-class check for better accuracy
|
| 1485 |
+
if (this.canvas.matches && this.canvas.matches(":hover")) {
|
| 1486 |
this.updateLastStoneHighlight();
|
| 1487 |
}
|
| 1488 |
|
|
|
|
| 1502 |
this.lastCameraDistance = cameraDistance;
|
| 1503 |
|
| 1504 |
// Calculate diagonal distance of the board
|
| 1505 |
+
const diagonal = Math.sqrt(
|
| 1506 |
+
this.boardShape.x ** 2 + this.boardShape.y ** 2 + this.boardShape.z ** 2
|
| 1507 |
+
);
|
| 1508 |
const boardDiagonal = diagonal * this.gridSpacing;
|
| 1509 |
|
| 1510 |
// Update fog near and far based on camera distance +/- diagonal
|
|
|
|
| 1535 |
const emissiveColor = new THREE.Color(...SHINING.EMISSIVE_COLOR);
|
| 1536 |
|
| 1537 |
// Scale intensity based on stone color (white stones get brighter glow)
|
| 1538 |
+
const baseIntensity =
|
| 1539 |
+
stone.color === "white"
|
| 1540 |
+
? SHINING.BASE_INTENSITY_WHITE
|
| 1541 |
+
: SHINING.BASE_INTENSITY_BLACK;
|
| 1542 |
+
const flickerIntensity =
|
| 1543 |
+
stone.color === "white"
|
| 1544 |
+
? SHINING.FLICKER_INTENSITY_WHITE
|
| 1545 |
+
: SHINING.FLICKER_INTENSITY_BLACK;
|
| 1546 |
const intensity = flicker * flickerIntensity + baseIntensity;
|
| 1547 |
|
| 1548 |
material.emissive = emissiveColor;
|
|
|
|
| 1563 |
|
| 1564 |
if (intersects.length > 0) {
|
| 1565 |
// Find the position of the clicked stone
|
| 1566 |
+
let clickedPosition: { x: number; y: number; z: number } | null = null;
|
| 1567 |
|
| 1568 |
for (const [, stone] of this.stones.entries()) {
|
| 1569 |
if (stone.mesh === intersects[0].object) {
|
|
|
|
| 1582 |
|
| 1583 |
// Notify callback with group info
|
| 1584 |
if (this.callbacks.onInspectGroup) {
|
| 1585 |
+
this.callbacks.onInspectGroup(
|
| 1586 |
+
this.highlightedGroup.size,
|
| 1587 |
+
libertiesResult.count
|
| 1588 |
+
);
|
| 1589 |
}
|
| 1590 |
}
|
| 1591 |
} else {
|
|
|
|
| 1598 |
}
|
| 1599 |
}
|
| 1600 |
|
| 1601 |
+
private findConnectedGroup(startPos: { x: number; y: number; z: number }): Set<string> {
|
| 1602 |
const group = new Set<string>();
|
| 1603 |
const startKey = this.getStoneKey(startPos.x, startPos.y, startPos.z);
|
| 1604 |
const startStone = this.stones.get(startKey);
|
|
|
|
| 1606 |
if (!startStone) return group;
|
| 1607 |
|
| 1608 |
const color = startStone.color;
|
| 1609 |
+
const queue: { x: number; y: number; z: number }[] = [startPos];
|
| 1610 |
const visited = new Set<string>();
|
| 1611 |
|
| 1612 |
while (queue.length > 0) {
|
|
|
|
| 1623 |
|
| 1624 |
// Check all 6 neighbors in 3D space
|
| 1625 |
const neighbors = [
|
| 1626 |
+
{ x: pos.x + 1, y: pos.y, z: pos.z },
|
| 1627 |
+
{ x: pos.x - 1, y: pos.y, z: pos.z },
|
| 1628 |
+
{ x: pos.x, y: pos.y + 1, z: pos.z },
|
| 1629 |
+
{ x: pos.x, y: pos.y - 1, z: pos.z },
|
| 1630 |
+
{ x: pos.x, y: pos.y, z: pos.z + 1 },
|
| 1631 |
+
{ x: pos.x, y: pos.y, z: pos.z - 1 }
|
| 1632 |
];
|
| 1633 |
|
| 1634 |
for (const neighbor of neighbors) {
|
| 1635 |
// Check if neighbor is within board bounds
|
| 1636 |
+
if (
|
| 1637 |
+
neighbor.x >= 0 &&
|
| 1638 |
+
neighbor.x < this.boardShape.x &&
|
| 1639 |
+
neighbor.y >= 0 &&
|
| 1640 |
+
neighbor.y < this.boardShape.y &&
|
| 1641 |
+
neighbor.z >= 0 &&
|
| 1642 |
+
neighbor.z < this.boardShape.z
|
| 1643 |
+
) {
|
| 1644 |
const neighborKey = this.getStoneKey(neighbor.x, neighbor.y, neighbor.z);
|
| 1645 |
if (!visited.has(neighborKey)) {
|
| 1646 |
queue.push(neighbor);
|
|
|
|
| 1657 |
|
| 1658 |
// For each stone in the group, check its neighbors for empty positions
|
| 1659 |
for (const key of group) {
|
| 1660 |
+
const parts = key.split(",").map(Number);
|
| 1661 |
+
const pos = { x: parts[0], y: parts[1], z: parts[2] };
|
| 1662 |
|
| 1663 |
// Check all 6 neighbors
|
| 1664 |
const neighbors = [
|
| 1665 |
+
{ x: pos.x + 1, y: pos.y, z: pos.z },
|
| 1666 |
+
{ x: pos.x - 1, y: pos.y, z: pos.z },
|
| 1667 |
+
{ x: pos.x, y: pos.y + 1, z: pos.z },
|
| 1668 |
+
{ x: pos.x, y: pos.y - 1, z: pos.z },
|
| 1669 |
+
{ x: pos.x, y: pos.y, z: pos.z + 1 },
|
| 1670 |
+
{ x: pos.x, y: pos.y, z: pos.z - 1 }
|
| 1671 |
];
|
| 1672 |
|
| 1673 |
for (const neighbor of neighbors) {
|
| 1674 |
// Check if neighbor is within bounds
|
| 1675 |
+
if (
|
| 1676 |
+
neighbor.x >= 0 &&
|
| 1677 |
+
neighbor.x < this.boardShape.x &&
|
| 1678 |
+
neighbor.y >= 0 &&
|
| 1679 |
+
neighbor.y < this.boardShape.y &&
|
| 1680 |
+
neighbor.z >= 0 &&
|
| 1681 |
+
neighbor.z < this.boardShape.z
|
| 1682 |
+
) {
|
| 1683 |
const neighborKey = this.getStoneKey(neighbor.x, neighbor.y, neighbor.z);
|
| 1684 |
// If neighbor is empty (not in stones map), it's a liberty
|
| 1685 |
if (!this.stones.has(neighborKey)) {
|
|
|
|
| 1692 |
return { count: liberties.size, positions: liberties };
|
| 1693 |
}
|
| 1694 |
|
|
|
|
| 1695 |
private updateStoneOpacity(): void {
|
| 1696 |
// Update opacity of all stones based on inspect mode
|
| 1697 |
this.stones.forEach((stone, key) => {
|
|
|
|
| 1722 |
this.updateAirPatchVisualization();
|
| 1723 |
}
|
| 1724 |
|
|
|
|
| 1725 |
private updateAirPatchVisualization(): void {
|
| 1726 |
// Reset all intersection points to default color
|
| 1727 |
this.intersectionPoints.children.forEach((child) => {
|
|
|
|
| 1754 |
});
|
| 1755 |
}
|
| 1756 |
|
| 1757 |
+
private updateDomainCubesVisualization(
|
| 1758 |
+
blackDomain: Set<string> | null,
|
| 1759 |
+
whiteDomain: Set<string> | null
|
| 1760 |
+
): void {
|
| 1761 |
// Update domain cube visibility based on territory and air patch
|
| 1762 |
this.domainCubes.forEach((cube, key) => {
|
| 1763 |
const material = cube.material as THREE.MeshBasicMaterial;
|
|
|
|
| 1785 |
});
|
| 1786 |
}
|
| 1787 |
|
|
|
|
| 1788 |
private onKeyDown(event: KeyboardEvent): void {
|
| 1789 |
// Ctrl key (17) or Meta key (91/93) for Mac
|
| 1790 |
if (event.ctrlKey || event.metaKey) {
|
|
|
|
| 1815 |
}
|
| 1816 |
}
|
| 1817 |
|
|
|
|
| 1818 |
public destroy(): void {
|
| 1819 |
this.isDestroyed = true;
|
| 1820 |
|
trigo-web/app/src/stores/gameStore.ts
CHANGED
|
@@ -10,7 +10,6 @@ import type {
|
|
| 10 |
TerritoryResult
|
| 11 |
} from "../../../inc/trigo";
|
| 12 |
|
| 13 |
-
|
| 14 |
/**
|
| 15 |
* Game Store State
|
| 16 |
*
|
|
@@ -21,7 +20,6 @@ export interface GameState {
|
|
| 21 |
config: GameConfig;
|
| 22 |
}
|
| 23 |
|
| 24 |
-
|
| 25 |
/**
|
| 26 |
* Pinia store for game state management
|
| 27 |
*
|
|
@@ -36,7 +34,6 @@ export const useGameStore = defineStore("game", {
|
|
| 36 |
}
|
| 37 |
}),
|
| 38 |
|
| 39 |
-
|
| 40 |
getters: {
|
| 41 |
// Board state
|
| 42 |
board: (state): Stone[][][] => state.game.getBoard(),
|
|
@@ -67,7 +64,7 @@ export const useGameStore = defineStore("game", {
|
|
| 67 |
const counts = state.game.getCapturedCounts();
|
| 68 |
return {
|
| 69 |
black: counts.white, // Black captured white stones
|
| 70 |
-
white: counts.black
|
| 71 |
};
|
| 72 |
},
|
| 73 |
|
|
@@ -83,18 +80,23 @@ export const useGameStore = defineStore("game", {
|
|
| 83 |
},
|
| 84 |
|
| 85 |
// Position checks
|
| 86 |
-
isValidPosition:
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
},
|
| 96 |
|
| 97 |
-
|
| 98 |
actions: {
|
| 99 |
/**
|
| 100 |
* Initialize a new game
|
|
@@ -105,7 +107,6 @@ export const useGameStore = defineStore("game", {
|
|
| 105 |
this.saveToSessionStorage();
|
| 106 |
},
|
| 107 |
|
| 108 |
-
|
| 109 |
/**
|
| 110 |
* Start the game
|
| 111 |
*/
|
|
@@ -114,11 +115,14 @@ export const useGameStore = defineStore("game", {
|
|
| 114 |
this.saveToSessionStorage();
|
| 115 |
},
|
| 116 |
|
| 117 |
-
|
| 118 |
/**
|
| 119 |
* Make a move
|
| 120 |
*/
|
| 121 |
-
makeMove(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 122 |
// Check if game is active
|
| 123 |
if (!this.game.isGameActive()) {
|
| 124 |
console.warn("Game is not active");
|
|
@@ -142,7 +146,6 @@ export const useGameStore = defineStore("game", {
|
|
| 142 |
return { success: false };
|
| 143 |
},
|
| 144 |
|
| 145 |
-
|
| 146 |
/**
|
| 147 |
* Pass turn
|
| 148 |
*/
|
|
@@ -158,7 +161,6 @@ export const useGameStore = defineStore("game", {
|
|
| 158 |
return success;
|
| 159 |
},
|
| 160 |
|
| 161 |
-
|
| 162 |
/**
|
| 163 |
* Resign/surrender
|
| 164 |
*/
|
|
@@ -174,7 +176,6 @@ export const useGameStore = defineStore("game", {
|
|
| 174 |
return success;
|
| 175 |
},
|
| 176 |
|
| 177 |
-
|
| 178 |
/**
|
| 179 |
* Undo last move
|
| 180 |
*/
|
|
@@ -190,7 +191,6 @@ export const useGameStore = defineStore("game", {
|
|
| 190 |
return success;
|
| 191 |
},
|
| 192 |
|
| 193 |
-
|
| 194 |
/**
|
| 195 |
* Redo next move
|
| 196 |
*/
|
|
@@ -206,7 +206,6 @@ export const useGameStore = defineStore("game", {
|
|
| 206 |
return success;
|
| 207 |
},
|
| 208 |
|
| 209 |
-
|
| 210 |
/**
|
| 211 |
* Jump to specific move in history
|
| 212 |
*/
|
|
@@ -218,7 +217,6 @@ export const useGameStore = defineStore("game", {
|
|
| 218 |
return success;
|
| 219 |
},
|
| 220 |
|
| 221 |
-
|
| 222 |
/**
|
| 223 |
* Reset game to initial state
|
| 224 |
*/
|
|
@@ -227,7 +225,6 @@ export const useGameStore = defineStore("game", {
|
|
| 227 |
this.saveToSessionStorage();
|
| 228 |
},
|
| 229 |
|
| 230 |
-
|
| 231 |
/**
|
| 232 |
* Change board shape (only when game is idle)
|
| 233 |
*/
|
|
@@ -241,7 +238,6 @@ export const useGameStore = defineStore("game", {
|
|
| 241 |
return true;
|
| 242 |
},
|
| 243 |
|
| 244 |
-
|
| 245 |
/**
|
| 246 |
* Calculate territory
|
| 247 |
*/
|
|
@@ -249,7 +245,6 @@ export const useGameStore = defineStore("game", {
|
|
| 249 |
return this.game.computeTerritory();
|
| 250 |
},
|
| 251 |
|
| 252 |
-
|
| 253 |
/**
|
| 254 |
* Get neighboring positions (6 directions in 3D)
|
| 255 |
*/
|
|
@@ -266,7 +261,6 @@ export const useGameStore = defineStore("game", {
|
|
| 266 |
return neighbors.filter((pos) => this.isValidPosition(pos.x, pos.y, pos.z));
|
| 267 |
},
|
| 268 |
|
| 269 |
-
|
| 270 |
/**
|
| 271 |
* Save game state to session storage
|
| 272 |
*/
|
|
@@ -278,7 +272,6 @@ export const useGameStore = defineStore("game", {
|
|
| 278 |
}
|
| 279 |
},
|
| 280 |
|
| 281 |
-
|
| 282 |
/**
|
| 283 |
* Load game state from session storage
|
| 284 |
*/
|
|
@@ -295,7 +288,6 @@ export const useGameStore = defineStore("game", {
|
|
| 295 |
}
|
| 296 |
},
|
| 297 |
|
| 298 |
-
|
| 299 |
/**
|
| 300 |
* Clear saved game state
|
| 301 |
*/
|
|
|
|
| 10 |
TerritoryResult
|
| 11 |
} from "../../../inc/trigo";
|
| 12 |
|
|
|
|
| 13 |
/**
|
| 14 |
* Game Store State
|
| 15 |
*
|
|
|
|
| 20 |
config: GameConfig;
|
| 21 |
}
|
| 22 |
|
|
|
|
| 23 |
/**
|
| 24 |
* Pinia store for game state management
|
| 25 |
*
|
|
|
|
| 34 |
}
|
| 35 |
}),
|
| 36 |
|
|
|
|
| 37 |
getters: {
|
| 38 |
// Board state
|
| 39 |
board: (state): Stone[][][] => state.game.getBoard(),
|
|
|
|
| 64 |
const counts = state.game.getCapturedCounts();
|
| 65 |
return {
|
| 66 |
black: counts.white, // Black captured white stones
|
| 67 |
+
white: counts.black // White captured black stones
|
| 68 |
};
|
| 69 |
},
|
| 70 |
|
|
|
|
| 80 |
},
|
| 81 |
|
| 82 |
// Position checks
|
| 83 |
+
isValidPosition:
|
| 84 |
+
(state) =>
|
| 85 |
+
(x: number, y: number, z: number): boolean => {
|
| 86 |
+
return state.game.isValidPosition(x, y, z);
|
| 87 |
+
},
|
| 88 |
+
isEmpty:
|
| 89 |
+
(state) =>
|
| 90 |
+
(x: number, y: number, z: number): boolean => {
|
| 91 |
+
return state.game.isEmpty(x, y, z);
|
| 92 |
+
},
|
| 93 |
+
getStone:
|
| 94 |
+
(state) =>
|
| 95 |
+
(x: number, y: number, z: number): Stone => {
|
| 96 |
+
return state.game.getStoneAt(x, y, z) as Stone;
|
| 97 |
+
}
|
| 98 |
},
|
| 99 |
|
|
|
|
| 100 |
actions: {
|
| 101 |
/**
|
| 102 |
* Initialize a new game
|
|
|
|
| 107 |
this.saveToSessionStorage();
|
| 108 |
},
|
| 109 |
|
|
|
|
| 110 |
/**
|
| 111 |
* Start the game
|
| 112 |
*/
|
|
|
|
| 115 |
this.saveToSessionStorage();
|
| 116 |
},
|
| 117 |
|
|
|
|
| 118 |
/**
|
| 119 |
* Make a move
|
| 120 |
*/
|
| 121 |
+
makeMove(
|
| 122 |
+
x: number,
|
| 123 |
+
y: number,
|
| 124 |
+
z: number
|
| 125 |
+
): { success: boolean; capturedPositions?: Position[] } {
|
| 126 |
// Check if game is active
|
| 127 |
if (!this.game.isGameActive()) {
|
| 128 |
console.warn("Game is not active");
|
|
|
|
| 146 |
return { success: false };
|
| 147 |
},
|
| 148 |
|
|
|
|
| 149 |
/**
|
| 150 |
* Pass turn
|
| 151 |
*/
|
|
|
|
| 161 |
return success;
|
| 162 |
},
|
| 163 |
|
|
|
|
| 164 |
/**
|
| 165 |
* Resign/surrender
|
| 166 |
*/
|
|
|
|
| 176 |
return success;
|
| 177 |
},
|
| 178 |
|
|
|
|
| 179 |
/**
|
| 180 |
* Undo last move
|
| 181 |
*/
|
|
|
|
| 191 |
return success;
|
| 192 |
},
|
| 193 |
|
|
|
|
| 194 |
/**
|
| 195 |
* Redo next move
|
| 196 |
*/
|
|
|
|
| 206 |
return success;
|
| 207 |
},
|
| 208 |
|
|
|
|
| 209 |
/**
|
| 210 |
* Jump to specific move in history
|
| 211 |
*/
|
|
|
|
| 217 |
return success;
|
| 218 |
},
|
| 219 |
|
|
|
|
| 220 |
/**
|
| 221 |
* Reset game to initial state
|
| 222 |
*/
|
|
|
|
| 225 |
this.saveToSessionStorage();
|
| 226 |
},
|
| 227 |
|
|
|
|
| 228 |
/**
|
| 229 |
* Change board shape (only when game is idle)
|
| 230 |
*/
|
|
|
|
| 238 |
return true;
|
| 239 |
},
|
| 240 |
|
|
|
|
| 241 |
/**
|
| 242 |
* Calculate territory
|
| 243 |
*/
|
|
|
|
| 245 |
return this.game.computeTerritory();
|
| 246 |
},
|
| 247 |
|
|
|
|
| 248 |
/**
|
| 249 |
* Get neighboring positions (6 directions in 3D)
|
| 250 |
*/
|
|
|
|
| 261 |
return neighbors.filter((pos) => this.isValidPosition(pos.x, pos.y, pos.z));
|
| 262 |
},
|
| 263 |
|
|
|
|
| 264 |
/**
|
| 265 |
* Save game state to session storage
|
| 266 |
*/
|
|
|
|
| 272 |
}
|
| 273 |
},
|
| 274 |
|
|
|
|
| 275 |
/**
|
| 276 |
* Load game state from session storage
|
| 277 |
*/
|
|
|
|
| 288 |
}
|
| 289 |
},
|
| 290 |
|
|
|
|
| 291 |
/**
|
| 292 |
* Clear saved game state
|
| 293 |
*/
|
trigo-web/app/src/utils/TrigoGameFrontend.ts
CHANGED
|
@@ -18,7 +18,6 @@ import {
|
|
| 18 |
type GameResult
|
| 19 |
} from "../../../inc/trigo";
|
| 20 |
|
| 21 |
-
|
| 22 |
/**
|
| 23 |
* TrigoGameFrontend - Extended TrigoGame with frontend-friendly interfaces
|
| 24 |
*/
|
|
@@ -35,7 +34,6 @@ export class TrigoGameFrontend extends TrigoGame {
|
|
| 35 |
return this.drop(makePosition(x, y, z));
|
| 36 |
}
|
| 37 |
|
| 38 |
-
|
| 39 |
/**
|
| 40 |
* Get current player as string
|
| 41 |
*
|
|
@@ -45,7 +43,6 @@ export class TrigoGameFrontend extends TrigoGame {
|
|
| 45 |
return stoneToPlayer(this.getCurrentPlayer());
|
| 46 |
}
|
| 47 |
|
| 48 |
-
|
| 49 |
/**
|
| 50 |
* Get move history in frontend format
|
| 51 |
*
|
|
@@ -55,7 +52,6 @@ export class TrigoGameFrontend extends TrigoGame {
|
|
| 55 |
return stepsToMoves(this.getHistory());
|
| 56 |
}
|
| 57 |
|
| 58 |
-
|
| 59 |
/**
|
| 60 |
* Get stone at position, returns number format for frontend
|
| 61 |
*
|
|
@@ -68,7 +64,6 @@ export class TrigoGameFrontend extends TrigoGame {
|
|
| 68 |
return this.getStone(makePosition(x, y, z)) as number;
|
| 69 |
}
|
| 70 |
|
| 71 |
-
|
| 72 |
/**
|
| 73 |
* Check if position is valid
|
| 74 |
*
|
|
@@ -79,17 +74,9 @@ export class TrigoGameFrontend extends TrigoGame {
|
|
| 79 |
*/
|
| 80 |
isValidPosition(x: number, y: number, z: number): boolean {
|
| 81 |
const shape = this.getShape();
|
| 82 |
-
return
|
| 83 |
-
x >= 0 &&
|
| 84 |
-
x < shape.x &&
|
| 85 |
-
y >= 0 &&
|
| 86 |
-
y < shape.y &&
|
| 87 |
-
z >= 0 &&
|
| 88 |
-
z < shape.z
|
| 89 |
-
);
|
| 90 |
}
|
| 91 |
|
| 92 |
-
|
| 93 |
/**
|
| 94 |
* Check if position is empty
|
| 95 |
*
|
|
@@ -105,7 +92,6 @@ export class TrigoGameFrontend extends TrigoGame {
|
|
| 105 |
return this.getStoneAt(x, y, z) === 0;
|
| 106 |
}
|
| 107 |
|
| 108 |
-
|
| 109 |
/**
|
| 110 |
* Check if a move is valid at position
|
| 111 |
*
|
|
@@ -118,7 +104,6 @@ export class TrigoGameFrontend extends TrigoGame {
|
|
| 118 |
return this.isValidMove(makePosition(x, y, z));
|
| 119 |
}
|
| 120 |
|
| 121 |
-
|
| 122 |
/**
|
| 123 |
* Get opponent player
|
| 124 |
*
|
|
@@ -129,7 +114,6 @@ export class TrigoGameFrontend extends TrigoGame {
|
|
| 129 |
return current === "black" ? "white" : "black";
|
| 130 |
}
|
| 131 |
|
| 132 |
-
|
| 133 |
/**
|
| 134 |
* Check if undo is available
|
| 135 |
*
|
|
@@ -139,7 +123,6 @@ export class TrigoGameFrontend extends TrigoGame {
|
|
| 139 |
return this.getCurrentStep() > 0;
|
| 140 |
}
|
| 141 |
|
| 142 |
-
|
| 143 |
/**
|
| 144 |
* Undo move (convenience wrapper)
|
| 145 |
*
|
|
@@ -149,7 +132,6 @@ export class TrigoGameFrontend extends TrigoGame {
|
|
| 149 |
return this.undo();
|
| 150 |
}
|
| 151 |
|
| 152 |
-
|
| 153 |
/**
|
| 154 |
* Redo move (convenience wrapper)
|
| 155 |
*
|
|
@@ -159,7 +141,6 @@ export class TrigoGameFrontend extends TrigoGame {
|
|
| 159 |
return this.redo();
|
| 160 |
}
|
| 161 |
|
| 162 |
-
|
| 163 |
/**
|
| 164 |
* Jump to specific move in history
|
| 165 |
*
|
|
@@ -170,7 +151,6 @@ export class TrigoGameFrontend extends TrigoGame {
|
|
| 170 |
return this.jumpToStep(index);
|
| 171 |
}
|
| 172 |
|
| 173 |
-
|
| 174 |
/**
|
| 175 |
* Get total move count
|
| 176 |
*
|
|
@@ -180,7 +160,6 @@ export class TrigoGameFrontend extends TrigoGame {
|
|
| 180 |
return this.getCurrentStep();
|
| 181 |
}
|
| 182 |
|
| 183 |
-
|
| 184 |
/**
|
| 185 |
* Get current move index
|
| 186 |
*
|
|
@@ -190,7 +169,6 @@ export class TrigoGameFrontend extends TrigoGame {
|
|
| 190 |
return this.getCurrentStep();
|
| 191 |
}
|
| 192 |
|
| 193 |
-
|
| 194 |
/**
|
| 195 |
* Get board shape
|
| 196 |
*
|
|
@@ -200,7 +178,6 @@ export class TrigoGameFrontend extends TrigoGame {
|
|
| 200 |
return this.getShape();
|
| 201 |
}
|
| 202 |
|
| 203 |
-
|
| 204 |
/**
|
| 205 |
* Initialize game with board shape
|
| 206 |
*
|
|
@@ -216,7 +193,6 @@ export class TrigoGameFrontend extends TrigoGame {
|
|
| 216 |
}
|
| 217 |
}
|
| 218 |
|
| 219 |
-
|
| 220 |
/**
|
| 221 |
* Compute territory (convenience wrapper)
|
| 222 |
*
|
|
@@ -226,7 +202,6 @@ export class TrigoGameFrontend extends TrigoGame {
|
|
| 226 |
return this.getTerritory();
|
| 227 |
}
|
| 228 |
|
| 229 |
-
|
| 230 |
/**
|
| 231 |
* Get game status
|
| 232 |
*
|
|
@@ -236,7 +211,6 @@ export class TrigoGameFrontend extends TrigoGame {
|
|
| 236 |
return this.getGameStatus();
|
| 237 |
}
|
| 238 |
|
| 239 |
-
|
| 240 |
/**
|
| 241 |
* Get game result
|
| 242 |
*
|
|
@@ -246,7 +220,6 @@ export class TrigoGameFrontend extends TrigoGame {
|
|
| 246 |
return this.getGameResult();
|
| 247 |
}
|
| 248 |
|
| 249 |
-
|
| 250 |
/**
|
| 251 |
* Get consecutive pass count
|
| 252 |
*
|
|
|
|
| 18 |
type GameResult
|
| 19 |
} from "../../../inc/trigo";
|
| 20 |
|
|
|
|
| 21 |
/**
|
| 22 |
* TrigoGameFrontend - Extended TrigoGame with frontend-friendly interfaces
|
| 23 |
*/
|
|
|
|
| 34 |
return this.drop(makePosition(x, y, z));
|
| 35 |
}
|
| 36 |
|
|
|
|
| 37 |
/**
|
| 38 |
* Get current player as string
|
| 39 |
*
|
|
|
|
| 43 |
return stoneToPlayer(this.getCurrentPlayer());
|
| 44 |
}
|
| 45 |
|
|
|
|
| 46 |
/**
|
| 47 |
* Get move history in frontend format
|
| 48 |
*
|
|
|
|
| 52 |
return stepsToMoves(this.getHistory());
|
| 53 |
}
|
| 54 |
|
|
|
|
| 55 |
/**
|
| 56 |
* Get stone at position, returns number format for frontend
|
| 57 |
*
|
|
|
|
| 64 |
return this.getStone(makePosition(x, y, z)) as number;
|
| 65 |
}
|
| 66 |
|
|
|
|
| 67 |
/**
|
| 68 |
* Check if position is valid
|
| 69 |
*
|
|
|
|
| 74 |
*/
|
| 75 |
isValidPosition(x: number, y: number, z: number): boolean {
|
| 76 |
const shape = this.getShape();
|
| 77 |
+
return x >= 0 && x < shape.x && y >= 0 && y < shape.y && z >= 0 && z < shape.z;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
}
|
| 79 |
|
|
|
|
| 80 |
/**
|
| 81 |
* Check if position is empty
|
| 82 |
*
|
|
|
|
| 92 |
return this.getStoneAt(x, y, z) === 0;
|
| 93 |
}
|
| 94 |
|
|
|
|
| 95 |
/**
|
| 96 |
* Check if a move is valid at position
|
| 97 |
*
|
|
|
|
| 104 |
return this.isValidMove(makePosition(x, y, z));
|
| 105 |
}
|
| 106 |
|
|
|
|
| 107 |
/**
|
| 108 |
* Get opponent player
|
| 109 |
*
|
|
|
|
| 114 |
return current === "black" ? "white" : "black";
|
| 115 |
}
|
| 116 |
|
|
|
|
| 117 |
/**
|
| 118 |
* Check if undo is available
|
| 119 |
*
|
|
|
|
| 123 |
return this.getCurrentStep() > 0;
|
| 124 |
}
|
| 125 |
|
|
|
|
| 126 |
/**
|
| 127 |
* Undo move (convenience wrapper)
|
| 128 |
*
|
|
|
|
| 132 |
return this.undo();
|
| 133 |
}
|
| 134 |
|
|
|
|
| 135 |
/**
|
| 136 |
* Redo move (convenience wrapper)
|
| 137 |
*
|
|
|
|
| 141 |
return this.redo();
|
| 142 |
}
|
| 143 |
|
|
|
|
| 144 |
/**
|
| 145 |
* Jump to specific move in history
|
| 146 |
*
|
|
|
|
| 151 |
return this.jumpToStep(index);
|
| 152 |
}
|
| 153 |
|
|
|
|
| 154 |
/**
|
| 155 |
* Get total move count
|
| 156 |
*
|
|
|
|
| 160 |
return this.getCurrentStep();
|
| 161 |
}
|
| 162 |
|
|
|
|
| 163 |
/**
|
| 164 |
* Get current move index
|
| 165 |
*
|
|
|
|
| 169 |
return this.getCurrentStep();
|
| 170 |
}
|
| 171 |
|
|
|
|
| 172 |
/**
|
| 173 |
* Get board shape
|
| 174 |
*
|
|
|
|
| 178 |
return this.getShape();
|
| 179 |
}
|
| 180 |
|
|
|
|
| 181 |
/**
|
| 182 |
* Initialize game with board shape
|
| 183 |
*
|
|
|
|
| 193 |
}
|
| 194 |
}
|
| 195 |
|
|
|
|
| 196 |
/**
|
| 197 |
* Compute territory (convenience wrapper)
|
| 198 |
*
|
|
|
|
| 202 |
return this.getTerritory();
|
| 203 |
}
|
| 204 |
|
|
|
|
| 205 |
/**
|
| 206 |
* Get game status
|
| 207 |
*
|
|
|
|
| 211 |
return this.getGameStatus();
|
| 212 |
}
|
| 213 |
|
|
|
|
| 214 |
/**
|
| 215 |
* Get game result
|
| 216 |
*
|
|
|
|
| 220 |
return this.getGameResult();
|
| 221 |
}
|
| 222 |
|
|
|
|
| 223 |
/**
|
| 224 |
* Get consecutive pass count
|
| 225 |
*
|
trigo-web/app/src/utils/storage.ts
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* Frontend Storage Utility
|
| 3 |
+
*
|
| 4 |
+
* Provides a centralized API for storing and retrieving data in browser storage.
|
| 5 |
+
* Supports both sessionStorage and localStorage with type-safe operations.
|
| 6 |
+
*
|
| 7 |
+
* Features:
|
| 8 |
+
* - Type-safe storage operations
|
| 9 |
+
* - Automatic JSON serialization/deserialization
|
| 10 |
+
* - Error handling with fallback values
|
| 11 |
+
* - Namespaced keys to avoid collisions
|
| 12 |
+
* - Support for both session and local storage
|
| 13 |
+
*/
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
/**
|
| 17 |
+
* Storage type enum
|
| 18 |
+
*/
|
| 19 |
+
export enum StorageType {
|
| 20 |
+
SESSION = "session",
|
| 21 |
+
LOCAL = "local"
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
/**
|
| 26 |
+
* Storage keys enum - Add new keys here
|
| 27 |
+
*/
|
| 28 |
+
export enum StorageKey {
|
| 29 |
+
// Game state
|
| 30 |
+
GAME_STATE = "trigoGameState",
|
| 31 |
+
|
| 32 |
+
// AI settings
|
| 33 |
+
AI_PLAYER_COLOR = "trigoAIPlayerColor",
|
| 34 |
+
|
| 35 |
+
// User preferences (examples for future use)
|
| 36 |
+
// THEME = "trigoTheme",
|
| 37 |
+
// LANGUAGE = "trigoLanguage",
|
| 38 |
+
// BOARD_SHAPE = "trigoBoardShape",
|
| 39 |
+
// CAMERA_POSITION = "trigoCameraPosition",
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
/**
|
| 44 |
+
* Storage configuration
|
| 45 |
+
*/
|
| 46 |
+
interface StorageConfig {
|
| 47 |
+
type: StorageType;
|
| 48 |
+
prefix?: string; // Optional namespace prefix for all keys
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
/**
|
| 53 |
+
* Default configuration
|
| 54 |
+
*/
|
| 55 |
+
const DEFAULT_CONFIG: StorageConfig = {
|
| 56 |
+
type: StorageType.SESSION,
|
| 57 |
+
prefix: "" // No prefix by default, keys already have 'trigo' prefix
|
| 58 |
+
};
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
/**
|
| 62 |
+
* Get the appropriate storage instance
|
| 63 |
+
*/
|
| 64 |
+
function getStorage(type: StorageType): Storage {
|
| 65 |
+
return type === StorageType.SESSION ? sessionStorage : localStorage;
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
/**
|
| 70 |
+
* Build full storage key with optional prefix
|
| 71 |
+
*/
|
| 72 |
+
function buildKey(key: StorageKey, prefix?: string): string {
|
| 73 |
+
return prefix ? `${prefix}${key}` : key;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
/**
|
| 78 |
+
* Storage Manager Class
|
| 79 |
+
*/
|
| 80 |
+
export class StorageManager {
|
| 81 |
+
private config: StorageConfig;
|
| 82 |
+
|
| 83 |
+
constructor(config: Partial<StorageConfig> = {}) {
|
| 84 |
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
/**
|
| 88 |
+
* Get storage instance based on configuration
|
| 89 |
+
*/
|
| 90 |
+
private getStorageInstance(): Storage {
|
| 91 |
+
return getStorage(this.config.type);
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
/**
|
| 95 |
+
* Set a value in storage
|
| 96 |
+
* @param key - Storage key
|
| 97 |
+
* @param value - Value to store (will be JSON stringified)
|
| 98 |
+
* @returns true if successful, false otherwise
|
| 99 |
+
*/
|
| 100 |
+
set<T>(key: StorageKey, value: T): boolean {
|
| 101 |
+
try {
|
| 102 |
+
const storage = this.getStorageInstance();
|
| 103 |
+
const fullKey = buildKey(key, this.config.prefix);
|
| 104 |
+
const serialized = JSON.stringify(value);
|
| 105 |
+
storage.setItem(fullKey, serialized);
|
| 106 |
+
return true;
|
| 107 |
+
} catch (error) {
|
| 108 |
+
console.warn(`[Storage] Failed to set ${key}:`, error);
|
| 109 |
+
return false;
|
| 110 |
+
}
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
/**
|
| 114 |
+
* Get a value from storage
|
| 115 |
+
* @param key - Storage key
|
| 116 |
+
* @param defaultValue - Default value if key doesn't exist or parsing fails
|
| 117 |
+
* @returns Stored value or default value
|
| 118 |
+
*/
|
| 119 |
+
get<T>(key: StorageKey, defaultValue: T): T {
|
| 120 |
+
try {
|
| 121 |
+
const storage = this.getStorageInstance();
|
| 122 |
+
const fullKey = buildKey(key, this.config.prefix);
|
| 123 |
+
const item = storage.getItem(fullKey);
|
| 124 |
+
|
| 125 |
+
if (item === null) {
|
| 126 |
+
return defaultValue;
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
return JSON.parse(item) as T;
|
| 130 |
+
} catch (error) {
|
| 131 |
+
console.warn(`[Storage] Failed to get ${key}:`, error);
|
| 132 |
+
return defaultValue;
|
| 133 |
+
}
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
/**
|
| 137 |
+
* Get a string value directly (no JSON parsing)
|
| 138 |
+
* Useful for simple string values
|
| 139 |
+
*/
|
| 140 |
+
getString(key: StorageKey, defaultValue: string = ""): string {
|
| 141 |
+
try {
|
| 142 |
+
const storage = this.getStorageInstance();
|
| 143 |
+
const fullKey = buildKey(key, this.config.prefix);
|
| 144 |
+
return storage.getItem(fullKey) ?? defaultValue;
|
| 145 |
+
} catch (error) {
|
| 146 |
+
console.warn(`[Storage] Failed to get string ${key}:`, error);
|
| 147 |
+
return defaultValue;
|
| 148 |
+
}
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
/**
|
| 152 |
+
* Set a string value directly (no JSON stringification)
|
| 153 |
+
* Useful for simple string values
|
| 154 |
+
*/
|
| 155 |
+
setString(key: StorageKey, value: string): boolean {
|
| 156 |
+
try {
|
| 157 |
+
const storage = this.getStorageInstance();
|
| 158 |
+
const fullKey = buildKey(key, this.config.prefix);
|
| 159 |
+
storage.setItem(fullKey, value);
|
| 160 |
+
return true;
|
| 161 |
+
} catch (error) {
|
| 162 |
+
console.warn(`[Storage] Failed to set string ${key}:`, error);
|
| 163 |
+
return false;
|
| 164 |
+
}
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
/**
|
| 168 |
+
* Remove a value from storage
|
| 169 |
+
* @param key - Storage key
|
| 170 |
+
* @returns true if successful, false otherwise
|
| 171 |
+
*/
|
| 172 |
+
remove(key: StorageKey): boolean {
|
| 173 |
+
try {
|
| 174 |
+
const storage = this.getStorageInstance();
|
| 175 |
+
const fullKey = buildKey(key, this.config.prefix);
|
| 176 |
+
storage.removeItem(fullKey);
|
| 177 |
+
return true;
|
| 178 |
+
} catch (error) {
|
| 179 |
+
console.warn(`[Storage] Failed to remove ${key}:`, error);
|
| 180 |
+
return false;
|
| 181 |
+
}
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
/**
|
| 185 |
+
* Check if a key exists in storage
|
| 186 |
+
*/
|
| 187 |
+
has(key: StorageKey): boolean {
|
| 188 |
+
try {
|
| 189 |
+
const storage = this.getStorageInstance();
|
| 190 |
+
const fullKey = buildKey(key, this.config.prefix);
|
| 191 |
+
return storage.getItem(fullKey) !== null;
|
| 192 |
+
} catch (error) {
|
| 193 |
+
console.warn(`[Storage] Failed to check ${key}:`, error);
|
| 194 |
+
return false;
|
| 195 |
+
}
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
/**
|
| 199 |
+
* Clear all items from storage
|
| 200 |
+
* WARNING: This clears ALL items in the storage, not just trigo-related ones
|
| 201 |
+
*/
|
| 202 |
+
clear(): boolean {
|
| 203 |
+
try {
|
| 204 |
+
const storage = this.getStorageInstance();
|
| 205 |
+
storage.clear();
|
| 206 |
+
return true;
|
| 207 |
+
} catch (error) {
|
| 208 |
+
console.warn("[Storage] Failed to clear storage:", error);
|
| 209 |
+
return false;
|
| 210 |
+
}
|
| 211 |
+
}
|
| 212 |
+
|
| 213 |
+
/**
|
| 214 |
+
* Get the current storage type
|
| 215 |
+
*/
|
| 216 |
+
getStorageType(): StorageType {
|
| 217 |
+
return this.config.type;
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
/**
|
| 221 |
+
* Switch storage type
|
| 222 |
+
*/
|
| 223 |
+
setStorageType(type: StorageType): void {
|
| 224 |
+
this.config.type = type;
|
| 225 |
+
}
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
|
| 229 |
+
/**
|
| 230 |
+
* Default storage manager instance (sessionStorage)
|
| 231 |
+
*/
|
| 232 |
+
export const storage = new StorageManager();
|
| 233 |
+
|
| 234 |
+
|
| 235 |
+
/**
|
| 236 |
+
* Local storage manager instance
|
| 237 |
+
* Note: Named localStorageManager to avoid conflict with built-in localStorage
|
| 238 |
+
*/
|
| 239 |
+
export const localStorageManager = new StorageManager({ type: StorageType.LOCAL });
|
| 240 |
+
|
| 241 |
+
|
| 242 |
+
/**
|
| 243 |
+
* Example helper functions for future use:
|
| 244 |
+
*
|
| 245 |
+
* export function saveTheme(theme: "light" | "dark"): boolean {
|
| 246 |
+
* return localStorageManager.setString(StorageKey.THEME, theme);
|
| 247 |
+
* }
|
| 248 |
+
*
|
| 249 |
+
* export function loadTheme(): "light" | "dark" {
|
| 250 |
+
* const stored = localStorageManager.getString(StorageKey.THEME);
|
| 251 |
+
* return stored === "dark" ? "dark" : "light";
|
| 252 |
+
* }
|
| 253 |
+
*
|
| 254 |
+
* export function saveBoardShape(shape: { x: number; y: number; z: number }): boolean {
|
| 255 |
+
* return storage.set(StorageKey.BOARD_SHAPE, shape);
|
| 256 |
+
* }
|
| 257 |
+
*
|
| 258 |
+
* export function loadBoardShape(): { x: number; y: number; z: number } | null {
|
| 259 |
+
* return storage.get(StorageKey.BOARD_SHAPE, null);
|
| 260 |
+
* }
|
| 261 |
+
*/
|
trigo-web/app/src/views/OnnxTestView.vue
ADDED
|
@@ -0,0 +1,511 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<template>
|
| 2 |
+
<div class="onnx-test-view">
|
| 3 |
+
<div class="test-header">
|
| 4 |
+
<h1>ONNX Model Inferencer Test</h1>
|
| 5 |
+
<p class="subtitle">Testing GPT-2 Causal LM with ONNX Runtime Web</p>
|
| 6 |
+
</div>
|
| 7 |
+
|
| 8 |
+
<div class="test-body">
|
| 9 |
+
<!-- Model Status -->
|
| 10 |
+
<div class="test-section">
|
| 11 |
+
<h2>Model Status</h2>
|
| 12 |
+
<div class="status-info">
|
| 13 |
+
<div
|
| 14 |
+
class="status-item"
|
| 15 |
+
:class="{ ready: isInitialized, loading: isInitializing }"
|
| 16 |
+
>
|
| 17 |
+
<span class="status-label">Status:</span>
|
| 18 |
+
<span class="status-value">
|
| 19 |
+
{{
|
| 20 |
+
isInitialized
|
| 21 |
+
? "✓ Ready"
|
| 22 |
+
: isInitializing
|
| 23 |
+
? "⏳ Initializing..."
|
| 24 |
+
: "⚪ Not initialized"
|
| 25 |
+
}}
|
| 26 |
+
</span>
|
| 27 |
+
</div>
|
| 28 |
+
<div v-if="modelInfo" class="status-item">
|
| 29 |
+
<span class="status-label">Inputs:</span>
|
| 30 |
+
<span class="status-value">{{ modelInfo.inputs.join(", ") }}</span>
|
| 31 |
+
</div>
|
| 32 |
+
<div v-if="modelInfo" class="status-item">
|
| 33 |
+
<span class="status-label">Outputs:</span>
|
| 34 |
+
<span class="status-value">{{ modelInfo.outputs.join(", ") }}</span>
|
| 35 |
+
</div>
|
| 36 |
+
<div v-if="error" class="error-message">❌ Error: {{ error }}</div>
|
| 37 |
+
</div>
|
| 38 |
+
|
| 39 |
+
<button
|
| 40 |
+
class="btn btn-primary"
|
| 41 |
+
@click="initialize"
|
| 42 |
+
:disabled="isInitializing || isInitialized"
|
| 43 |
+
>
|
| 44 |
+
{{ isInitialized ? "Initialized" : "Initialize Model" }}
|
| 45 |
+
</button>
|
| 46 |
+
</div>
|
| 47 |
+
|
| 48 |
+
<!-- Basic Inference Test -->
|
| 49 |
+
<div class="test-section">
|
| 50 |
+
<h2>Test 1: Basic Inference</h2>
|
| 51 |
+
<p>Run a single forward pass with random input</p>
|
| 52 |
+
|
| 53 |
+
<button
|
| 54 |
+
class="btn btn-test"
|
| 55 |
+
@click="runBasicTest"
|
| 56 |
+
:disabled="!isInitialized || isRunning"
|
| 57 |
+
>
|
| 58 |
+
{{ isRunning ? "Running..." : "Run Basic Test" }}
|
| 59 |
+
</button>
|
| 60 |
+
|
| 61 |
+
<div v-if="basicTestResult" class="test-result">
|
| 62 |
+
<h3>Results:</h3>
|
| 63 |
+
<div class="result-item">
|
| 64 |
+
<span class="label">Inference Time:</span>
|
| 65 |
+
<span class="value">{{ basicTestResult.inferenceTime.toFixed(2) }}ms</span>
|
| 66 |
+
</div>
|
| 67 |
+
<div class="result-item">
|
| 68 |
+
<span class="label">Sample Tokens:</span>
|
| 69 |
+
<span class="value code"
|
| 70 |
+
>{{ basicTestResult.tokens.slice(0, 20).join(", ") }}...</span
|
| 71 |
+
>
|
| 72 |
+
</div>
|
| 73 |
+
<div class="result-item">
|
| 74 |
+
<span class="label">Sample Text:</span>
|
| 75 |
+
<span class="value code">{{ basicTestResult.text.slice(0, 100) }}...</span>
|
| 76 |
+
</div>
|
| 77 |
+
</div>
|
| 78 |
+
</div>
|
| 79 |
+
|
| 80 |
+
<!-- Text Generation Test -->
|
| 81 |
+
<div class="test-section">
|
| 82 |
+
<h2>Test 2: Text Generation</h2>
|
| 83 |
+
<p>Generate tokens autoregressively from a prompt</p>
|
| 84 |
+
|
| 85 |
+
<div class="input-group">
|
| 86 |
+
<label for="prompt">Prompt:</label>
|
| 87 |
+
<input
|
| 88 |
+
id="prompt"
|
| 89 |
+
v-model="prompt"
|
| 90 |
+
type="text"
|
| 91 |
+
placeholder="Enter prompt text..."
|
| 92 |
+
:disabled="!isInitialized"
|
| 93 |
+
/>
|
| 94 |
+
</div>
|
| 95 |
+
|
| 96 |
+
<div class="input-group">
|
| 97 |
+
<label for="numTokens">Number of Tokens:</label>
|
| 98 |
+
<input
|
| 99 |
+
id="numTokens"
|
| 100 |
+
v-model.number="numTokens"
|
| 101 |
+
type="number"
|
| 102 |
+
min="1"
|
| 103 |
+
max="50"
|
| 104 |
+
:disabled="!isInitialized"
|
| 105 |
+
/>
|
| 106 |
+
</div>
|
| 107 |
+
|
| 108 |
+
<button
|
| 109 |
+
class="btn btn-test"
|
| 110 |
+
@click="runGenerationTest"
|
| 111 |
+
:disabled="!isInitialized || isRunning || !prompt"
|
| 112 |
+
>
|
| 113 |
+
{{ isRunning ? "Generating..." : "Generate Text" }}
|
| 114 |
+
</button>
|
| 115 |
+
|
| 116 |
+
<div v-if="generationResult" class="test-result">
|
| 117 |
+
<h3>Generated Output:</h3>
|
| 118 |
+
<div class="result-item">
|
| 119 |
+
<span class="label">Avg Inference Time:</span>
|
| 120 |
+
<span class="value">{{ generationResult.inferenceTime.toFixed(2) }}ms</span>
|
| 121 |
+
</div>
|
| 122 |
+
<div class="result-item">
|
| 123 |
+
<span class="label">Tokens/sec:</span>
|
| 124 |
+
<span class="value">{{
|
| 125 |
+
(1000 / generationResult.inferenceTime).toFixed(2)
|
| 126 |
+
}}</span>
|
| 127 |
+
</div>
|
| 128 |
+
<div class="result-item full-width">
|
| 129 |
+
<span class="label">Token Sequence:</span>
|
| 130 |
+
<span class="value code">{{ generationResult.tokens.join(", ") }}</span>
|
| 131 |
+
</div>
|
| 132 |
+
<div class="result-item full-width">
|
| 133 |
+
<span class="label">Generated Text:</span>
|
| 134 |
+
<div class="generated-text">{{ generationResult.text }}</div>
|
| 135 |
+
</div>
|
| 136 |
+
</div>
|
| 137 |
+
</div>
|
| 138 |
+
|
| 139 |
+
<!-- Console Output -->
|
| 140 |
+
<div class="test-section">
|
| 141 |
+
<h2>Console Output</h2>
|
| 142 |
+
<p>Check the browser console (F12) for detailed logs</p>
|
| 143 |
+
<button class="btn btn-secondary" @click="clearConsole">Clear Console</button>
|
| 144 |
+
</div>
|
| 145 |
+
</div>
|
| 146 |
+
</div>
|
| 147 |
+
</template>
|
| 148 |
+
|
| 149 |
+
<script setup lang="ts">
|
| 150 |
+
import { ref } from "vue";
|
| 151 |
+
import { OnnxInferencer, type InferenceResult } from "@/services/onnxInferencer";
|
| 152 |
+
|
| 153 |
+
// Inferencer instance
|
| 154 |
+
let inferencer: OnnxInferencer | null = null;
|
| 155 |
+
|
| 156 |
+
// State
|
| 157 |
+
const isInitializing = ref(false);
|
| 158 |
+
const isInitialized = ref(false);
|
| 159 |
+
const isRunning = ref(false);
|
| 160 |
+
const error = ref<string | null>(null);
|
| 161 |
+
const modelInfo = ref<{ inputs: string[]; outputs: string[] } | null>(null);
|
| 162 |
+
|
| 163 |
+
// Test state
|
| 164 |
+
const basicTestResult = ref<InferenceResult | null>(null);
|
| 165 |
+
const generationResult = ref<InferenceResult | null>(null);
|
| 166 |
+
const prompt = ref("[Board 5x5]");
|
| 167 |
+
const numTokens = ref(10);
|
| 168 |
+
|
| 169 |
+
/**
|
| 170 |
+
* Initialize the inferencer
|
| 171 |
+
*/
|
| 172 |
+
const initialize = async () => {
|
| 173 |
+
isInitializing.value = true;
|
| 174 |
+
error.value = null;
|
| 175 |
+
|
| 176 |
+
try {
|
| 177 |
+
console.log("=".repeat(80));
|
| 178 |
+
console.log("Initializing ONNX Inferencer...");
|
| 179 |
+
console.log("=".repeat(80));
|
| 180 |
+
|
| 181 |
+
inferencer = new OnnxInferencer({
|
| 182 |
+
modelPath: "/onnx/GPT2CausalLM_ep0015_int8_seq2048_int8.onnx",
|
| 183 |
+
vocabSize: 259,
|
| 184 |
+
seqLen: 2048,
|
| 185 |
+
executionProviders: ["wasm"] // Use WebAssembly for compatibility
|
| 186 |
+
});
|
| 187 |
+
|
| 188 |
+
await inferencer.initialize();
|
| 189 |
+
|
| 190 |
+
modelInfo.value = inferencer.getModelInfo();
|
| 191 |
+
isInitialized.value = true;
|
| 192 |
+
|
| 193 |
+
console.log("✓ Initialization complete!");
|
| 194 |
+
console.log("=".repeat(80));
|
| 195 |
+
} catch (err) {
|
| 196 |
+
error.value = err instanceof Error ? err.message : "Unknown error";
|
| 197 |
+
console.error("Initialization failed:", err);
|
| 198 |
+
} finally {
|
| 199 |
+
isInitializing.value = false;
|
| 200 |
+
}
|
| 201 |
+
};
|
| 202 |
+
|
| 203 |
+
/**
|
| 204 |
+
* Run basic inference test
|
| 205 |
+
*/
|
| 206 |
+
const runBasicTest = async () => {
|
| 207 |
+
if (!inferencer) return;
|
| 208 |
+
|
| 209 |
+
isRunning.value = true;
|
| 210 |
+
error.value = null;
|
| 211 |
+
basicTestResult.value = null;
|
| 212 |
+
|
| 213 |
+
try {
|
| 214 |
+
console.log("\n" + "=".repeat(80));
|
| 215 |
+
console.log("Running Basic Inference Test...");
|
| 216 |
+
console.log("=".repeat(80));
|
| 217 |
+
|
| 218 |
+
const result = await inferencer.testBasicInference();
|
| 219 |
+
basicTestResult.value = result;
|
| 220 |
+
|
| 221 |
+
console.log("✓ Basic test complete!");
|
| 222 |
+
console.log("=".repeat(80));
|
| 223 |
+
} catch (err) {
|
| 224 |
+
error.value = err instanceof Error ? err.message : "Test failed";
|
| 225 |
+
console.error("Basic test failed:", err);
|
| 226 |
+
} finally {
|
| 227 |
+
isRunning.value = false;
|
| 228 |
+
}
|
| 229 |
+
};
|
| 230 |
+
|
| 231 |
+
/**
|
| 232 |
+
* Run text generation test
|
| 233 |
+
*/
|
| 234 |
+
const runGenerationTest = async () => {
|
| 235 |
+
if (!inferencer) return;
|
| 236 |
+
|
| 237 |
+
isRunning.value = true;
|
| 238 |
+
error.value = null;
|
| 239 |
+
generationResult.value = null;
|
| 240 |
+
|
| 241 |
+
try {
|
| 242 |
+
console.log("\n" + "=".repeat(80));
|
| 243 |
+
console.log("Running Text Generation Test...");
|
| 244 |
+
console.log("=".repeat(80));
|
| 245 |
+
|
| 246 |
+
const result = await inferencer.generateText(prompt.value, numTokens.value);
|
| 247 |
+
generationResult.value = result;
|
| 248 |
+
|
| 249 |
+
console.log("✓ Generation test complete!");
|
| 250 |
+
console.log("=".repeat(80));
|
| 251 |
+
} catch (err) {
|
| 252 |
+
error.value = err instanceof Error ? err.message : "Generation failed";
|
| 253 |
+
console.error("Generation test failed:", err);
|
| 254 |
+
} finally {
|
| 255 |
+
isRunning.value = false;
|
| 256 |
+
}
|
| 257 |
+
};
|
| 258 |
+
|
| 259 |
+
/**
|
| 260 |
+
* Clear browser console
|
| 261 |
+
*/
|
| 262 |
+
const clearConsole = () => {
|
| 263 |
+
console.clear();
|
| 264 |
+
console.log("Console cleared");
|
| 265 |
+
};
|
| 266 |
+
</script>
|
| 267 |
+
|
| 268 |
+
<style lang="scss" scoped>
|
| 269 |
+
.onnx-test-view {
|
| 270 |
+
display: flex;
|
| 271 |
+
flex-direction: column;
|
| 272 |
+
height: 100%;
|
| 273 |
+
background-color: #f5f5f5;
|
| 274 |
+
overflow: auto;
|
| 275 |
+
}
|
| 276 |
+
|
| 277 |
+
.test-header {
|
| 278 |
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
| 279 |
+
color: white;
|
| 280 |
+
padding: 2rem;
|
| 281 |
+
text-align: center;
|
| 282 |
+
|
| 283 |
+
h1 {
|
| 284 |
+
margin: 0 0 0.5rem 0;
|
| 285 |
+
font-size: 2rem;
|
| 286 |
+
font-weight: 700;
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
.subtitle {
|
| 290 |
+
margin: 0;
|
| 291 |
+
opacity: 0.9;
|
| 292 |
+
font-size: 1.1rem;
|
| 293 |
+
}
|
| 294 |
+
}
|
| 295 |
+
|
| 296 |
+
.test-body {
|
| 297 |
+
flex: 1;
|
| 298 |
+
padding: 2rem;
|
| 299 |
+
max-width: 1000px;
|
| 300 |
+
margin: 0 auto;
|
| 301 |
+
width: 100%;
|
| 302 |
+
}
|
| 303 |
+
|
| 304 |
+
.test-section {
|
| 305 |
+
background: white;
|
| 306 |
+
border-radius: 12px;
|
| 307 |
+
padding: 1.5rem;
|
| 308 |
+
margin-bottom: 1.5rem;
|
| 309 |
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
| 310 |
+
|
| 311 |
+
h2 {
|
| 312 |
+
margin: 0 0 0.5rem 0;
|
| 313 |
+
color: #333;
|
| 314 |
+
font-size: 1.3rem;
|
| 315 |
+
font-weight: 600;
|
| 316 |
+
}
|
| 317 |
+
|
| 318 |
+
p {
|
| 319 |
+
margin: 0 0 1rem 0;
|
| 320 |
+
color: #666;
|
| 321 |
+
}
|
| 322 |
+
}
|
| 323 |
+
|
| 324 |
+
.status-info {
|
| 325 |
+
background: #f8f9fa;
|
| 326 |
+
border-radius: 8px;
|
| 327 |
+
padding: 1rem;
|
| 328 |
+
margin-bottom: 1rem;
|
| 329 |
+
|
| 330 |
+
.status-item {
|
| 331 |
+
display: flex;
|
| 332 |
+
justify-content: space-between;
|
| 333 |
+
padding: 0.5rem 0;
|
| 334 |
+
border-bottom: 1px solid #e9ecef;
|
| 335 |
+
|
| 336 |
+
&:last-child {
|
| 337 |
+
border-bottom: none;
|
| 338 |
+
}
|
| 339 |
+
|
| 340 |
+
&.ready {
|
| 341 |
+
.status-value {
|
| 342 |
+
color: #28a745;
|
| 343 |
+
font-weight: 600;
|
| 344 |
+
}
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
+
&.loading {
|
| 348 |
+
.status-value {
|
| 349 |
+
color: #ffc107;
|
| 350 |
+
font-weight: 600;
|
| 351 |
+
}
|
| 352 |
+
}
|
| 353 |
+
|
| 354 |
+
.status-label {
|
| 355 |
+
font-weight: 600;
|
| 356 |
+
color: #666;
|
| 357 |
+
}
|
| 358 |
+
|
| 359 |
+
.status-value {
|
| 360 |
+
color: #333;
|
| 361 |
+
}
|
| 362 |
+
}
|
| 363 |
+
}
|
| 364 |
+
|
| 365 |
+
.error-message {
|
| 366 |
+
background: #fff3cd;
|
| 367 |
+
border: 1px solid #ffeaa7;
|
| 368 |
+
border-radius: 6px;
|
| 369 |
+
padding: 0.75rem;
|
| 370 |
+
color: #856404;
|
| 371 |
+
margin-top: 1rem;
|
| 372 |
+
}
|
| 373 |
+
|
| 374 |
+
.btn {
|
| 375 |
+
padding: 0.75rem 1.5rem;
|
| 376 |
+
border: none;
|
| 377 |
+
border-radius: 8px;
|
| 378 |
+
font-weight: 600;
|
| 379 |
+
font-size: 1rem;
|
| 380 |
+
cursor: pointer;
|
| 381 |
+
transition: all 0.3s ease;
|
| 382 |
+
|
| 383 |
+
&:disabled {
|
| 384 |
+
opacity: 0.5;
|
| 385 |
+
cursor: not-allowed;
|
| 386 |
+
}
|
| 387 |
+
|
| 388 |
+
&.btn-primary {
|
| 389 |
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
| 390 |
+
color: white;
|
| 391 |
+
|
| 392 |
+
&:hover:not(:disabled) {
|
| 393 |
+
transform: translateY(-2px);
|
| 394 |
+
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
|
| 395 |
+
}
|
| 396 |
+
}
|
| 397 |
+
|
| 398 |
+
&.btn-test {
|
| 399 |
+
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
| 400 |
+
color: white;
|
| 401 |
+
|
| 402 |
+
&:hover:not(:disabled) {
|
| 403 |
+
transform: translateY(-2px);
|
| 404 |
+
box-shadow: 0 4px 12px rgba(245, 87, 108, 0.4);
|
| 405 |
+
}
|
| 406 |
+
}
|
| 407 |
+
|
| 408 |
+
&.btn-secondary {
|
| 409 |
+
background: #6c757d;
|
| 410 |
+
color: white;
|
| 411 |
+
|
| 412 |
+
&:hover:not(:disabled) {
|
| 413 |
+
background: #5a6268;
|
| 414 |
+
}
|
| 415 |
+
}
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
+
.input-group {
|
| 419 |
+
margin-bottom: 1rem;
|
| 420 |
+
|
| 421 |
+
label {
|
| 422 |
+
display: block;
|
| 423 |
+
margin-bottom: 0.5rem;
|
| 424 |
+
font-weight: 600;
|
| 425 |
+
color: #333;
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
input {
|
| 429 |
+
width: 100%;
|
| 430 |
+
padding: 0.75rem;
|
| 431 |
+
border: 2px solid #e9ecef;
|
| 432 |
+
border-radius: 8px;
|
| 433 |
+
font-size: 1rem;
|
| 434 |
+
transition: border-color 0.3s ease;
|
| 435 |
+
|
| 436 |
+
&:focus {
|
| 437 |
+
outline: none;
|
| 438 |
+
border-color: #667eea;
|
| 439 |
+
}
|
| 440 |
+
|
| 441 |
+
&:disabled {
|
| 442 |
+
background-color: #f8f9fa;
|
| 443 |
+
cursor: not-allowed;
|
| 444 |
+
}
|
| 445 |
+
}
|
| 446 |
+
}
|
| 447 |
+
|
| 448 |
+
.test-result {
|
| 449 |
+
background: #f8f9fa;
|
| 450 |
+
border-radius: 8px;
|
| 451 |
+
padding: 1rem;
|
| 452 |
+
margin-top: 1rem;
|
| 453 |
+
|
| 454 |
+
h3 {
|
| 455 |
+
margin: 0 0 1rem 0;
|
| 456 |
+
color: #333;
|
| 457 |
+
font-size: 1.1rem;
|
| 458 |
+
}
|
| 459 |
+
|
| 460 |
+
.result-item {
|
| 461 |
+
display: flex;
|
| 462 |
+
justify-content: space-between;
|
| 463 |
+
align-items: flex-start;
|
| 464 |
+
padding: 0.5rem 0;
|
| 465 |
+
border-bottom: 1px solid #e9ecef;
|
| 466 |
+
|
| 467 |
+
&:last-child {
|
| 468 |
+
border-bottom: none;
|
| 469 |
+
}
|
| 470 |
+
|
| 471 |
+
&.full-width {
|
| 472 |
+
flex-direction: column;
|
| 473 |
+
gap: 0.5rem;
|
| 474 |
+
}
|
| 475 |
+
|
| 476 |
+
.label {
|
| 477 |
+
font-weight: 600;
|
| 478 |
+
color: #666;
|
| 479 |
+
min-width: 150px;
|
| 480 |
+
}
|
| 481 |
+
|
| 482 |
+
.value {
|
| 483 |
+
color: #333;
|
| 484 |
+
flex: 1;
|
| 485 |
+
text-align: right;
|
| 486 |
+
|
| 487 |
+
&.code {
|
| 488 |
+
font-family: "Courier New", monospace;
|
| 489 |
+
background: #fff;
|
| 490 |
+
padding: 0.25rem 0.5rem;
|
| 491 |
+
border-radius: 4px;
|
| 492 |
+
font-size: 0.9rem;
|
| 493 |
+
text-align: left;
|
| 494 |
+
}
|
| 495 |
+
}
|
| 496 |
+
}
|
| 497 |
+
|
| 498 |
+
.generated-text {
|
| 499 |
+
background: white;
|
| 500 |
+
border: 2px solid #e9ecef;
|
| 501 |
+
border-radius: 8px;
|
| 502 |
+
padding: 1rem;
|
| 503 |
+
font-family: "Courier New", monospace;
|
| 504 |
+
font-size: 0.95rem;
|
| 505 |
+
line-height: 1.6;
|
| 506 |
+
color: #333;
|
| 507 |
+
white-space: pre-wrap;
|
| 508 |
+
word-break: break-word;
|
| 509 |
+
}
|
| 510 |
+
}
|
| 511 |
+
</style>
|
trigo-web/app/src/views/TrigoAgentTestView.vue
ADDED
|
@@ -0,0 +1,711 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<template>
|
| 2 |
+
<div class="agent-test-view">
|
| 3 |
+
<div class="test-header">
|
| 4 |
+
<h1>Trigo AI Agent Test</h1>
|
| 5 |
+
<p class="subtitle">Testing ONNX-based Move Generation</p>
|
| 6 |
+
</div>
|
| 7 |
+
|
| 8 |
+
<div class="test-body">
|
| 9 |
+
<!-- Agent Status -->
|
| 10 |
+
<div class="test-section">
|
| 11 |
+
<h2>Agent Status</h2>
|
| 12 |
+
<div class="status-info">
|
| 13 |
+
<div
|
| 14 |
+
class="status-item"
|
| 15 |
+
:class="{ ready: isInitialized, loading: isInitializing }"
|
| 16 |
+
>
|
| 17 |
+
<span class="status-label">Status:</span>
|
| 18 |
+
<span class="status-value">
|
| 19 |
+
{{
|
| 20 |
+
isInitialized
|
| 21 |
+
? "✓ Ready"
|
| 22 |
+
: isInitializing
|
| 23 |
+
? "⏳ Initializing..."
|
| 24 |
+
: "⚪ Not initialized"
|
| 25 |
+
}}
|
| 26 |
+
</span>
|
| 27 |
+
</div>
|
| 28 |
+
<div v-if="error" class="error-message">❌ Error: {{ error }}</div>
|
| 29 |
+
</div>
|
| 30 |
+
|
| 31 |
+
<button
|
| 32 |
+
class="btn btn-primary"
|
| 33 |
+
@click="initialize"
|
| 34 |
+
:disabled="isInitializing || isInitialized"
|
| 35 |
+
>
|
| 36 |
+
{{ isInitialized ? "Initialized" : "Initialize Agent" }}
|
| 37 |
+
</button>
|
| 38 |
+
</div>
|
| 39 |
+
|
| 40 |
+
<!-- Game State -->
|
| 41 |
+
<div class="test-section">
|
| 42 |
+
<h2>Test Game State</h2>
|
| 43 |
+
<div class="game-info">
|
| 44 |
+
<div class="info-item">
|
| 45 |
+
<span class="label">Board Shape:</span>
|
| 46 |
+
<span class="value"
|
| 47 |
+
>{{ boardShape.x }}×{{ boardShape.y }}×{{ boardShape.z }}</span
|
| 48 |
+
>
|
| 49 |
+
</div>
|
| 50 |
+
<div class="info-item">
|
| 51 |
+
<span class="label">Current Player:</span>
|
| 52 |
+
<span class="value" :class="currentPlayer">{{ currentPlayer }}</span>
|
| 53 |
+
</div>
|
| 54 |
+
<div class="info-item">
|
| 55 |
+
<span class="label">Move Count:</span>
|
| 56 |
+
<span class="value">{{ moveHistory.length }}</span>
|
| 57 |
+
</div>
|
| 58 |
+
<div class="info-item">
|
| 59 |
+
<span class="label">Valid Moves:</span>
|
| 60 |
+
<span class="value">{{ validMovesCount }}</span>
|
| 61 |
+
</div>
|
| 62 |
+
</div>
|
| 63 |
+
|
| 64 |
+
<div class="game-controls">
|
| 65 |
+
<button class="btn btn-secondary" @click="resetGame">Reset Game</button>
|
| 66 |
+
<button
|
| 67 |
+
class="btn btn-secondary"
|
| 68 |
+
@click="makeRandomMove"
|
| 69 |
+
:disabled="!gameStarted"
|
| 70 |
+
>
|
| 71 |
+
Make Random Move
|
| 72 |
+
</button>
|
| 73 |
+
</div>
|
| 74 |
+
|
| 75 |
+
<!-- Current TGN -->
|
| 76 |
+
<div class="tgn-display">
|
| 77 |
+
<h3>Current TGN:</h3>
|
| 78 |
+
<pre class="tgn-content">{{ currentTGN }}</pre>
|
| 79 |
+
</div>
|
| 80 |
+
</div>
|
| 81 |
+
|
| 82 |
+
<!-- Move Generation Test -->
|
| 83 |
+
<div class="test-section">
|
| 84 |
+
<h2>Test: Generate AI Move</h2>
|
| 85 |
+
<p>Generate the best move for the current position using the AI agent</p>
|
| 86 |
+
|
| 87 |
+
<button
|
| 88 |
+
class="btn btn-test"
|
| 89 |
+
@click="testGenerateMove"
|
| 90 |
+
:disabled="!isInitialized || isGenerating || !gameStarted"
|
| 91 |
+
>
|
| 92 |
+
{{ isGenerating ? "Generating..." : "Generate Best Move" }}
|
| 93 |
+
</button>
|
| 94 |
+
|
| 95 |
+
<div v-if="moveResult" class="test-result">
|
| 96 |
+
<h3>Generated Move:</h3>
|
| 97 |
+
<div class="result-item">
|
| 98 |
+
<span class="label">Position:</span>
|
| 99 |
+
<span class="value code">{{ moveResult.position }}</span>
|
| 100 |
+
</div>
|
| 101 |
+
<div class="result-item">
|
| 102 |
+
<span class="label">TGN Notation:</span>
|
| 103 |
+
<span class="value code">{{ moveResult.notation }}</span>
|
| 104 |
+
</div>
|
| 105 |
+
<div class="result-item">
|
| 106 |
+
<span class="label">Generation Time:</span>
|
| 107 |
+
<span class="value">{{ moveResult.time.toFixed(2) }}ms</span>
|
| 108 |
+
</div>
|
| 109 |
+
<div class="result-item">
|
| 110 |
+
<span class="label">Valid Moves Evaluated:</span>
|
| 111 |
+
<span class="value">{{ moveResult.movesEvaluated }}</span>
|
| 112 |
+
</div>
|
| 113 |
+
|
| 114 |
+
<button class="btn btn-apply" @click="applyMove">Apply Move to Board</button>
|
| 115 |
+
</div>
|
| 116 |
+
</div>
|
| 117 |
+
|
| 118 |
+
<!-- Move History -->
|
| 119 |
+
<div class="test-section">
|
| 120 |
+
<h2>Move History</h2>
|
| 121 |
+
<div class="move-history">
|
| 122 |
+
<div v-if="moveHistory.length === 0" class="empty-state">No moves yet</div>
|
| 123 |
+
<div v-else class="move-list">
|
| 124 |
+
<div
|
| 125 |
+
v-for="(move, index) in moveHistory"
|
| 126 |
+
:key="index"
|
| 127 |
+
class="move-item"
|
| 128 |
+
:class="move.player"
|
| 129 |
+
>
|
| 130 |
+
<span class="move-number">{{ index + 1 }}.</span>
|
| 131 |
+
<span class="move-player">{{ move.player }}</span>
|
| 132 |
+
<span class="move-notation">{{ move.notation }}</span>
|
| 133 |
+
<span class="move-pos">{{ move.position }}</span>
|
| 134 |
+
</div>
|
| 135 |
+
</div>
|
| 136 |
+
</div>
|
| 137 |
+
</div>
|
| 138 |
+
|
| 139 |
+
<!-- Console Output -->
|
| 140 |
+
<div class="test-section">
|
| 141 |
+
<h2>Console Output</h2>
|
| 142 |
+
<p>Check the browser console (F12) for detailed logs</p>
|
| 143 |
+
<button class="btn btn-secondary" @click="clearConsole">Clear Console</button>
|
| 144 |
+
</div>
|
| 145 |
+
</div>
|
| 146 |
+
</div>
|
| 147 |
+
</template>
|
| 148 |
+
|
| 149 |
+
<script setup lang="ts">
|
| 150 |
+
import "onnxruntime-web";
|
| 151 |
+
|
| 152 |
+
import { ref, computed, shallowRef } from "vue";
|
| 153 |
+
import { OnnxInferencer } from "@/services/onnxInferencer";
|
| 154 |
+
import { TrigoAgent } from "@inc/trigoAgent";
|
| 155 |
+
import { TrigoGame } from "@inc/trigo/game";
|
| 156 |
+
import type { Position } from "@inc/trigo/types";
|
| 157 |
+
import { encodeAb0yz } from "@inc/trigo/ab0yz";
|
| 158 |
+
|
| 159 |
+
// Inferencer instance
|
| 160 |
+
let inferencer: OnnxInferencer | null = null;
|
| 161 |
+
|
| 162 |
+
// Agent instance
|
| 163 |
+
let agent: TrigoAgent | null = null;
|
| 164 |
+
|
| 165 |
+
// Game instance (use shallowRef for reactivity)
|
| 166 |
+
const game = shallowRef<TrigoGame | null>(null);
|
| 167 |
+
|
| 168 |
+
// State
|
| 169 |
+
const isInitializing = ref(false);
|
| 170 |
+
const isInitialized = ref(false);
|
| 171 |
+
const isGenerating = ref(false);
|
| 172 |
+
const error = ref<string | null>(null);
|
| 173 |
+
|
| 174 |
+
// Game state
|
| 175 |
+
const boardShape = ref({ x: 5, y: 5, z: 5 });
|
| 176 |
+
const currentPlayer = ref<"black" | "white">("black");
|
| 177 |
+
const moveHistory = ref<
|
| 178 |
+
Array<{
|
| 179 |
+
player: "black" | "white";
|
| 180 |
+
notation: string;
|
| 181 |
+
position: string;
|
| 182 |
+
}>
|
| 183 |
+
>([]);
|
| 184 |
+
const gameStarted = ref(false);
|
| 185 |
+
|
| 186 |
+
// Move generation result
|
| 187 |
+
const moveResult = ref<{
|
| 188 |
+
position: string;
|
| 189 |
+
notation: string;
|
| 190 |
+
time: number;
|
| 191 |
+
movesEvaluated: number;
|
| 192 |
+
rawPosition?: Position;
|
| 193 |
+
} | null>(null);
|
| 194 |
+
|
| 195 |
+
// Computed
|
| 196 |
+
const validMovesCount = computed(() => {
|
| 197 |
+
console.log("validMovesCount:", game);
|
| 198 |
+
if (!game.value) return 0;
|
| 199 |
+
return getValidMovesCount();
|
| 200 |
+
});
|
| 201 |
+
|
| 202 |
+
const currentTGN = computed(() => {
|
| 203 |
+
if (!game.value) return "[Board 5x5] *";
|
| 204 |
+
return game.value.toTGN();
|
| 205 |
+
});
|
| 206 |
+
|
| 207 |
+
/**
|
| 208 |
+
* Initialize the AI agent
|
| 209 |
+
*/
|
| 210 |
+
const initialize = async () => {
|
| 211 |
+
isInitializing.value = true;
|
| 212 |
+
error.value = null;
|
| 213 |
+
|
| 214 |
+
try {
|
| 215 |
+
console.log("=".repeat(80));
|
| 216 |
+
console.log("[TrigoAgentTest] Initializing AI agent...");
|
| 217 |
+
console.log("=".repeat(80));
|
| 218 |
+
|
| 219 |
+
// Create and initialize inferencer
|
| 220 |
+
inferencer = new OnnxInferencer({
|
| 221 |
+
modelPath: "/onnx/GPT2CausalLM_ep0015_int8_seq2048_int8.onnx",
|
| 222 |
+
vocabSize: 259,
|
| 223 |
+
seqLen: 2048
|
| 224 |
+
});
|
| 225 |
+
|
| 226 |
+
await inferencer.initialize();
|
| 227 |
+
|
| 228 |
+
// Create agent with inferencer
|
| 229 |
+
agent = new TrigoAgent(inferencer);
|
| 230 |
+
|
| 231 |
+
isInitialized.value = true;
|
| 232 |
+
|
| 233 |
+
// Initialize game
|
| 234 |
+
resetGame();
|
| 235 |
+
|
| 236 |
+
console.log("[TrigoAgentTest] ✓ Agent initialized successfully!");
|
| 237 |
+
console.log("=".repeat(80));
|
| 238 |
+
} catch (err) {
|
| 239 |
+
error.value = err instanceof Error ? err.message : "Unknown error";
|
| 240 |
+
console.error("[TrigoAgentTest] Initialization failed:", err);
|
| 241 |
+
} finally {
|
| 242 |
+
isInitializing.value = false;
|
| 243 |
+
}
|
| 244 |
+
};
|
| 245 |
+
|
| 246 |
+
/**
|
| 247 |
+
* Reset the game to initial state
|
| 248 |
+
*/
|
| 249 |
+
const resetGame = () => {
|
| 250 |
+
console.log("[TrigoAgentTest] Resetting game.value...");
|
| 251 |
+
|
| 252 |
+
game.value = new TrigoGame(boardShape.value);
|
| 253 |
+
currentPlayer.value = "black";
|
| 254 |
+
moveHistory.value = [];
|
| 255 |
+
gameStarted.value = true;
|
| 256 |
+
moveResult.value = null;
|
| 257 |
+
|
| 258 |
+
console.log("[TrigoAgentTest] ✓ Game reset");
|
| 259 |
+
};
|
| 260 |
+
|
| 261 |
+
/**
|
| 262 |
+
* Get count of valid moves (using efficient batch query)
|
| 263 |
+
*/
|
| 264 |
+
const getValidMovesCount = (): number => {
|
| 265 |
+
console.debug("getValidMovesCount:", game);
|
| 266 |
+
if (!game.value) return 0;
|
| 267 |
+
return game.value.validMovePositions().length;
|
| 268 |
+
};
|
| 269 |
+
|
| 270 |
+
/**
|
| 271 |
+
* Make a random move (for testing, using efficient batch query)
|
| 272 |
+
*/
|
| 273 |
+
const makeRandomMove = () => {
|
| 274 |
+
if (!game.value) return;
|
| 275 |
+
|
| 276 |
+
// Get all valid moves efficiently
|
| 277 |
+
const validMoves = game.value.validMovePositions();
|
| 278 |
+
|
| 279 |
+
if (validMoves.length === 0) {
|
| 280 |
+
console.log("[TrigoAgentTest] No valid moves available");
|
| 281 |
+
return;
|
| 282 |
+
}
|
| 283 |
+
|
| 284 |
+
// Pick random move
|
| 285 |
+
const move = validMoves[Math.floor(Math.random() * validMoves.length)];
|
| 286 |
+
const shape = game.value.getShape();
|
| 287 |
+
const notation = encodeAb0yz([move.x, move.y, move.z], [shape.x, shape.y, shape.z]);
|
| 288 |
+
|
| 289 |
+
// Make move
|
| 290 |
+
game.value.drop(move);
|
| 291 |
+
|
| 292 |
+
// Record in history
|
| 293 |
+
moveHistory.value.push({
|
| 294 |
+
player: currentPlayer.value,
|
| 295 |
+
notation,
|
| 296 |
+
position: `(${move.x}, ${move.y}, ${move.z})`
|
| 297 |
+
});
|
| 298 |
+
|
| 299 |
+
// Switch player
|
| 300 |
+
currentPlayer.value = currentPlayer.value === "black" ? "white" : "black";
|
| 301 |
+
|
| 302 |
+
console.log(`[TrigoAgentTest] Random move: ${notation} at ${move.x},${move.y},${move.z}`);
|
| 303 |
+
};
|
| 304 |
+
|
| 305 |
+
/**
|
| 306 |
+
* Test: Generate best move using AI
|
| 307 |
+
*/
|
| 308 |
+
const testGenerateMove = async () => {
|
| 309 |
+
if (!agent || !game) return;
|
| 310 |
+
|
| 311 |
+
isGenerating.value = true;
|
| 312 |
+
error.value = null;
|
| 313 |
+
moveResult.value = null;
|
| 314 |
+
|
| 315 |
+
try {
|
| 316 |
+
console.log("\n" + "=".repeat(80));
|
| 317 |
+
console.log("[TrigoAgentTest] Generating AI move...");
|
| 318 |
+
console.log(`[TrigoAgentTest] Current TGN: ${game.value.toTGN()}`);
|
| 319 |
+
console.log(`[TrigoAgentTest] Valid moves to evaluate: ${validMovesCount.value}`);
|
| 320 |
+
console.log("=".repeat(80));
|
| 321 |
+
|
| 322 |
+
const startTime = performance.now();
|
| 323 |
+
const position = await agent.selectBestMove(game.value);
|
| 324 |
+
const elapsed = performance.now() - startTime;
|
| 325 |
+
|
| 326 |
+
if (!position) {
|
| 327 |
+
error.value = "No valid moves found";
|
| 328 |
+
console.error("[TrigoAgentTest] No valid moves found");
|
| 329 |
+
return;
|
| 330 |
+
}
|
| 331 |
+
|
| 332 |
+
const notation = encodeAb0yz(
|
| 333 |
+
[position.x, position.y, position.z],
|
| 334 |
+
[boardShape.value.x, boardShape.value.y, boardShape.value.z]
|
| 335 |
+
);
|
| 336 |
+
|
| 337 |
+
moveResult.value = {
|
| 338 |
+
position: `(${position.x}, ${position.y}, ${position.z})`,
|
| 339 |
+
notation,
|
| 340 |
+
time: elapsed,
|
| 341 |
+
movesEvaluated: validMovesCount.value,
|
| 342 |
+
rawPosition: position
|
| 343 |
+
};
|
| 344 |
+
|
| 345 |
+
console.log("[TrigoAgentTest] ✓ Move generated successfully!");
|
| 346 |
+
console.log(
|
| 347 |
+
`[TrigoAgentTest] Best move: ${notation} at ${position.x},${position.y},${position.z}`
|
| 348 |
+
);
|
| 349 |
+
console.log(`[TrigoAgentTest] Generation time: ${elapsed.toFixed(2)}ms`);
|
| 350 |
+
console.log("=".repeat(80));
|
| 351 |
+
} catch (err) {
|
| 352 |
+
error.value = err instanceof Error ? err.message : "Generation failed";
|
| 353 |
+
console.error("[TrigoAgentTest] Move generation failed:", err);
|
| 354 |
+
} finally {
|
| 355 |
+
isGenerating.value = false;
|
| 356 |
+
}
|
| 357 |
+
};
|
| 358 |
+
|
| 359 |
+
/**
|
| 360 |
+
* Apply the generated move to the board
|
| 361 |
+
*/
|
| 362 |
+
const applyMove = () => {
|
| 363 |
+
if (!moveResult.value || !moveResult.value.rawPosition || !game) return;
|
| 364 |
+
|
| 365 |
+
const pos = moveResult.value.rawPosition;
|
| 366 |
+
|
| 367 |
+
// Make move
|
| 368 |
+
game.value.drop(pos);
|
| 369 |
+
|
| 370 |
+
// Record in history
|
| 371 |
+
moveHistory.value.push({
|
| 372 |
+
player: currentPlayer.value,
|
| 373 |
+
notation: moveResult.value.notation,
|
| 374 |
+
position: moveResult.value.position
|
| 375 |
+
});
|
| 376 |
+
|
| 377 |
+
// Switch player
|
| 378 |
+
currentPlayer.value = currentPlayer.value === "black" ? "white" : "black";
|
| 379 |
+
|
| 380 |
+
// Clear result
|
| 381 |
+
moveResult.value = null;
|
| 382 |
+
|
| 383 |
+
console.log(`[TrigoAgentTest] Move applied`);
|
| 384 |
+
};
|
| 385 |
+
|
| 386 |
+
/**
|
| 387 |
+
* Clear browser console
|
| 388 |
+
*/
|
| 389 |
+
const clearConsole = () => {
|
| 390 |
+
console.clear();
|
| 391 |
+
console.log("[TrigoAgentTest] Console cleared");
|
| 392 |
+
};
|
| 393 |
+
</script>
|
| 394 |
+
|
| 395 |
+
<style lang="scss" scoped>
|
| 396 |
+
.agent-test-view {
|
| 397 |
+
display: flex;
|
| 398 |
+
flex-direction: column;
|
| 399 |
+
height: 100%;
|
| 400 |
+
background-color: #f5f5f5;
|
| 401 |
+
overflow: auto;
|
| 402 |
+
}
|
| 403 |
+
|
| 404 |
+
.test-header {
|
| 405 |
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
| 406 |
+
color: white;
|
| 407 |
+
padding: 2rem;
|
| 408 |
+
text-align: center;
|
| 409 |
+
|
| 410 |
+
h1 {
|
| 411 |
+
margin: 0 0 0.5rem 0;
|
| 412 |
+
font-size: 2rem;
|
| 413 |
+
font-weight: 700;
|
| 414 |
+
}
|
| 415 |
+
|
| 416 |
+
.subtitle {
|
| 417 |
+
margin: 0;
|
| 418 |
+
opacity: 0.9;
|
| 419 |
+
font-size: 1.1rem;
|
| 420 |
+
}
|
| 421 |
+
}
|
| 422 |
+
|
| 423 |
+
.test-body {
|
| 424 |
+
flex: 1;
|
| 425 |
+
padding: 2rem;
|
| 426 |
+
max-width: 1200px;
|
| 427 |
+
margin: 0 auto;
|
| 428 |
+
width: 100%;
|
| 429 |
+
}
|
| 430 |
+
|
| 431 |
+
.test-section {
|
| 432 |
+
background: white;
|
| 433 |
+
border-radius: 12px;
|
| 434 |
+
padding: 1.5rem;
|
| 435 |
+
margin-bottom: 1.5rem;
|
| 436 |
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
| 437 |
+
|
| 438 |
+
h2 {
|
| 439 |
+
margin: 0 0 0.5rem 0;
|
| 440 |
+
color: #333;
|
| 441 |
+
font-size: 1.3rem;
|
| 442 |
+
font-weight: 600;
|
| 443 |
+
}
|
| 444 |
+
|
| 445 |
+
p {
|
| 446 |
+
margin: 0 0 1rem 0;
|
| 447 |
+
color: #666;
|
| 448 |
+
}
|
| 449 |
+
}
|
| 450 |
+
|
| 451 |
+
.status-info {
|
| 452 |
+
background: #f8f9fa;
|
| 453 |
+
border-radius: 8px;
|
| 454 |
+
padding: 1rem;
|
| 455 |
+
margin-bottom: 1rem;
|
| 456 |
+
|
| 457 |
+
.status-item {
|
| 458 |
+
display: flex;
|
| 459 |
+
justify-content: space-between;
|
| 460 |
+
padding: 0.5rem 0;
|
| 461 |
+
|
| 462 |
+
&.ready .status-value {
|
| 463 |
+
color: #28a745;
|
| 464 |
+
font-weight: 600;
|
| 465 |
+
}
|
| 466 |
+
|
| 467 |
+
&.loading .status-value {
|
| 468 |
+
color: #ffc107;
|
| 469 |
+
font-weight: 600;
|
| 470 |
+
}
|
| 471 |
+
|
| 472 |
+
.status-label {
|
| 473 |
+
font-weight: 600;
|
| 474 |
+
color: #666;
|
| 475 |
+
}
|
| 476 |
+
|
| 477 |
+
.status-value {
|
| 478 |
+
color: #333;
|
| 479 |
+
}
|
| 480 |
+
}
|
| 481 |
+
}
|
| 482 |
+
|
| 483 |
+
.error-message {
|
| 484 |
+
background: #fff3cd;
|
| 485 |
+
border: 1px solid #ffeaa7;
|
| 486 |
+
border-radius: 6px;
|
| 487 |
+
padding: 0.75rem;
|
| 488 |
+
color: #856404;
|
| 489 |
+
margin-top: 1rem;
|
| 490 |
+
}
|
| 491 |
+
|
| 492 |
+
.game-info {
|
| 493 |
+
background: #f8f9fa;
|
| 494 |
+
border-radius: 8px;
|
| 495 |
+
padding: 1rem;
|
| 496 |
+
margin-bottom: 1rem;
|
| 497 |
+
|
| 498 |
+
.info-item {
|
| 499 |
+
display: flex;
|
| 500 |
+
justify-content: space-between;
|
| 501 |
+
padding: 0.5rem 0;
|
| 502 |
+
border-bottom: 1px solid #e9ecef;
|
| 503 |
+
|
| 504 |
+
&:last-child {
|
| 505 |
+
border-bottom: none;
|
| 506 |
+
}
|
| 507 |
+
|
| 508 |
+
.label {
|
| 509 |
+
font-weight: 600;
|
| 510 |
+
color: #666;
|
| 511 |
+
}
|
| 512 |
+
|
| 513 |
+
.value {
|
| 514 |
+
color: #333;
|
| 515 |
+
font-weight: 500;
|
| 516 |
+
|
| 517 |
+
&.black {
|
| 518 |
+
color: #2c2c2c;
|
| 519 |
+
}
|
| 520 |
+
|
| 521 |
+
&.white {
|
| 522 |
+
color: #666;
|
| 523 |
+
}
|
| 524 |
+
}
|
| 525 |
+
}
|
| 526 |
+
}
|
| 527 |
+
|
| 528 |
+
.game-controls {
|
| 529 |
+
display: flex;
|
| 530 |
+
gap: 0.5rem;
|
| 531 |
+
margin-bottom: 1rem;
|
| 532 |
+
}
|
| 533 |
+
|
| 534 |
+
.tgn-display {
|
| 535 |
+
h3 {
|
| 536 |
+
margin: 0 0 0.5rem 0;
|
| 537 |
+
color: #333;
|
| 538 |
+
font-size: 1rem;
|
| 539 |
+
}
|
| 540 |
+
|
| 541 |
+
.tgn-content {
|
| 542 |
+
background: #2a2a2a;
|
| 543 |
+
color: #e0e0e0;
|
| 544 |
+
padding: 1rem;
|
| 545 |
+
border-radius: 8px;
|
| 546 |
+
font-family: "Courier New", monospace;
|
| 547 |
+
font-size: 0.9rem;
|
| 548 |
+
line-height: 1.6;
|
| 549 |
+
overflow-x: auto;
|
| 550 |
+
white-space: pre-wrap;
|
| 551 |
+
word-break: break-all;
|
| 552 |
+
}
|
| 553 |
+
}
|
| 554 |
+
|
| 555 |
+
.btn {
|
| 556 |
+
padding: 0.75rem 1.5rem;
|
| 557 |
+
border: none;
|
| 558 |
+
border-radius: 8px;
|
| 559 |
+
font-weight: 600;
|
| 560 |
+
font-size: 1rem;
|
| 561 |
+
cursor: pointer;
|
| 562 |
+
transition: all 0.3s ease;
|
| 563 |
+
|
| 564 |
+
&:disabled {
|
| 565 |
+
opacity: 0.5;
|
| 566 |
+
cursor: not-allowed;
|
| 567 |
+
}
|
| 568 |
+
|
| 569 |
+
&.btn-primary {
|
| 570 |
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
| 571 |
+
color: white;
|
| 572 |
+
|
| 573 |
+
&:hover:not(:disabled) {
|
| 574 |
+
transform: translateY(-2px);
|
| 575 |
+
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
|
| 576 |
+
}
|
| 577 |
+
}
|
| 578 |
+
|
| 579 |
+
&.btn-test {
|
| 580 |
+
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
| 581 |
+
color: white;
|
| 582 |
+
|
| 583 |
+
&:hover:not(:disabled) {
|
| 584 |
+
transform: translateY(-2px);
|
| 585 |
+
box-shadow: 0 4px 12px rgba(245, 87, 108, 0.4);
|
| 586 |
+
}
|
| 587 |
+
}
|
| 588 |
+
|
| 589 |
+
&.btn-secondary {
|
| 590 |
+
background: #6c757d;
|
| 591 |
+
color: white;
|
| 592 |
+
|
| 593 |
+
&:hover:not(:disabled) {
|
| 594 |
+
background: #5a6268;
|
| 595 |
+
}
|
| 596 |
+
}
|
| 597 |
+
|
| 598 |
+
&.btn-apply {
|
| 599 |
+
background: #28a745;
|
| 600 |
+
color: white;
|
| 601 |
+
margin-top: 1rem;
|
| 602 |
+
|
| 603 |
+
&:hover:not(:disabled) {
|
| 604 |
+
background: #218838;
|
| 605 |
+
transform: translateY(-2px);
|
| 606 |
+
box-shadow: 0 4px 12px rgba(40, 167, 69, 0.4);
|
| 607 |
+
}
|
| 608 |
+
}
|
| 609 |
+
}
|
| 610 |
+
|
| 611 |
+
.test-result {
|
| 612 |
+
background: #f8f9fa;
|
| 613 |
+
border-radius: 8px;
|
| 614 |
+
padding: 1rem;
|
| 615 |
+
margin-top: 1rem;
|
| 616 |
+
|
| 617 |
+
h3 {
|
| 618 |
+
margin: 0 0 1rem 0;
|
| 619 |
+
color: #333;
|
| 620 |
+
font-size: 1.1rem;
|
| 621 |
+
}
|
| 622 |
+
|
| 623 |
+
.result-item {
|
| 624 |
+
display: flex;
|
| 625 |
+
justify-content: space-between;
|
| 626 |
+
padding: 0.5rem 0;
|
| 627 |
+
border-bottom: 1px solid #e9ecef;
|
| 628 |
+
|
| 629 |
+
&:last-of-type {
|
| 630 |
+
border-bottom: none;
|
| 631 |
+
}
|
| 632 |
+
|
| 633 |
+
.label {
|
| 634 |
+
font-weight: 600;
|
| 635 |
+
color: #666;
|
| 636 |
+
}
|
| 637 |
+
|
| 638 |
+
.value {
|
| 639 |
+
color: #333;
|
| 640 |
+
|
| 641 |
+
&.code {
|
| 642 |
+
font-family: "Courier New", monospace;
|
| 643 |
+
background: #fff;
|
| 644 |
+
padding: 0.25rem 0.5rem;
|
| 645 |
+
border-radius: 4px;
|
| 646 |
+
font-size: 0.9rem;
|
| 647 |
+
}
|
| 648 |
+
}
|
| 649 |
+
}
|
| 650 |
+
}
|
| 651 |
+
|
| 652 |
+
.move-history {
|
| 653 |
+
background: #f8f9fa;
|
| 654 |
+
border-radius: 8px;
|
| 655 |
+
padding: 1rem;
|
| 656 |
+
max-height: 400px;
|
| 657 |
+
overflow-y: auto;
|
| 658 |
+
|
| 659 |
+
.empty-state {
|
| 660 |
+
text-align: center;
|
| 661 |
+
color: #999;
|
| 662 |
+
padding: 2rem;
|
| 663 |
+
font-style: italic;
|
| 664 |
+
}
|
| 665 |
+
|
| 666 |
+
.move-list {
|
| 667 |
+
display: flex;
|
| 668 |
+
flex-direction: column;
|
| 669 |
+
gap: 0.5rem;
|
| 670 |
+
}
|
| 671 |
+
|
| 672 |
+
.move-item {
|
| 673 |
+
display: grid;
|
| 674 |
+
grid-template-columns: 40px 80px 100px 1fr;
|
| 675 |
+
gap: 0.5rem;
|
| 676 |
+
padding: 0.5rem;
|
| 677 |
+
background: white;
|
| 678 |
+
border-radius: 6px;
|
| 679 |
+
border-left: 3px solid;
|
| 680 |
+
|
| 681 |
+
&.black {
|
| 682 |
+
border-color: #2c2c2c;
|
| 683 |
+
}
|
| 684 |
+
|
| 685 |
+
&.white {
|
| 686 |
+
border-color: #999;
|
| 687 |
+
}
|
| 688 |
+
|
| 689 |
+
.move-number {
|
| 690 |
+
color: #999;
|
| 691 |
+
font-weight: 600;
|
| 692 |
+
}
|
| 693 |
+
|
| 694 |
+
.move-player {
|
| 695 |
+
font-weight: 600;
|
| 696 |
+
text-transform: capitalize;
|
| 697 |
+
}
|
| 698 |
+
|
| 699 |
+
.move-notation {
|
| 700 |
+
font-family: "Courier New", monospace;
|
| 701 |
+
font-weight: 600;
|
| 702 |
+
}
|
| 703 |
+
|
| 704 |
+
.move-pos {
|
| 705 |
+
color: #666;
|
| 706 |
+
font-family: "Courier New", monospace;
|
| 707 |
+
font-size: 0.9rem;
|
| 708 |
+
}
|
| 709 |
+
}
|
| 710 |
+
}
|
| 711 |
+
</style>
|
trigo-web/app/src/views/TrigoTreeTestView.vue
ADDED
|
@@ -0,0 +1,1083 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<template>
|
| 2 |
+
<div class="tree-test-container">
|
| 3 |
+
<h1>Tree Attention Test - Trigo AI Agent</h1>
|
| 4 |
+
|
| 5 |
+
<div class="info-section">
|
| 6 |
+
<h2>Evaluation Mode with Tree Attention</h2>
|
| 7 |
+
<p>
|
| 8 |
+
This test uses the evaluation mode ONNX model to evaluate all valid moves in
|
| 9 |
+
parallel using tree attention. Each move is an independent branch that can only see
|
| 10 |
+
the prefix and itself.
|
| 11 |
+
</p>
|
| 12 |
+
</div>
|
| 13 |
+
|
| 14 |
+
<!-- Agent Status -->
|
| 15 |
+
<div class="status-section">
|
| 16 |
+
<h3>Agent Status</h3>
|
| 17 |
+
<div class="status-grid">
|
| 18 |
+
<div class="status-item">
|
| 19 |
+
<span class="label">Model:</span>
|
| 20 |
+
<span class="value">{{ modelPath }}</span>
|
| 21 |
+
</div>
|
| 22 |
+
<div class="status-item">
|
| 23 |
+
<span class="label">Status:</span>
|
| 24 |
+
<span class="value" :class="statusClass">{{ agentStatus }}</span>
|
| 25 |
+
</div>
|
| 26 |
+
<div class="status-item">
|
| 27 |
+
<span class="label">Vocab Size:</span>
|
| 28 |
+
<span class="value">{{ vocabSize }}</span>
|
| 29 |
+
</div>
|
| 30 |
+
</div>
|
| 31 |
+
<button
|
| 32 |
+
@click="initializeAgent"
|
| 33 |
+
:disabled="isInitializing || isReady"
|
| 34 |
+
class="btn-primary"
|
| 35 |
+
>
|
| 36 |
+
{{
|
| 37 |
+
isInitializing
|
| 38 |
+
? "Initializing..."
|
| 39 |
+
: isReady
|
| 40 |
+
? "✓ Agent Ready"
|
| 41 |
+
: "Initialize Agent"
|
| 42 |
+
}}
|
| 43 |
+
</button>
|
| 44 |
+
</div>
|
| 45 |
+
|
| 46 |
+
<!-- Game Board -->
|
| 47 |
+
<div class="board-section">
|
| 48 |
+
<h3>Game Board (5×5×5)</h3>
|
| 49 |
+
<div class="board-info">
|
| 50 |
+
<div class="info-item">
|
| 51 |
+
<span class="label">Current Player:</span>
|
| 52 |
+
<span class="value">{{ currentPlayer }}</span>
|
| 53 |
+
</div>
|
| 54 |
+
<div class="info-item">
|
| 55 |
+
<span class="label">Move Count:</span>
|
| 56 |
+
<span class="value">{{ moveCount }}</span>
|
| 57 |
+
</div>
|
| 58 |
+
<div class="info-item">
|
| 59 |
+
<span class="label">Valid Moves:</span>
|
| 60 |
+
<span class="value">{{ validMovesCount }}</span>
|
| 61 |
+
</div>
|
| 62 |
+
</div>
|
| 63 |
+
<div class="board-display">
|
| 64 |
+
<pre>{{ boardDisplay }}</pre>
|
| 65 |
+
</div>
|
| 66 |
+
<button @click="resetGame" class="btn-secondary">Reset Game</button>
|
| 67 |
+
</div>
|
| 68 |
+
|
| 69 |
+
<!-- Move Generation -->
|
| 70 |
+
<div class="generation-section">
|
| 71 |
+
<h3>Tree Attention Move Generation</h3>
|
| 72 |
+
<div class="button-group">
|
| 73 |
+
<button
|
| 74 |
+
@click="generateMoves"
|
| 75 |
+
:disabled="!isReady || isGenerating"
|
| 76 |
+
class="btn-primary btn-large"
|
| 77 |
+
>
|
| 78 |
+
{{ isGenerating ? "Generating..." : "Score All Moves (Tree Attention)" }}
|
| 79 |
+
</button>
|
| 80 |
+
<button
|
| 81 |
+
@click="generateBestMove"
|
| 82 |
+
:disabled="!isReady || isGenerating"
|
| 83 |
+
class="btn-primary btn-large"
|
| 84 |
+
>
|
| 85 |
+
{{ isGenerating ? "Generating..." : "Generate & Apply Best Move" }}
|
| 86 |
+
</button>
|
| 87 |
+
</div>
|
| 88 |
+
|
| 89 |
+
<div v-if="generationTime !== null" class="timing-info">
|
| 90 |
+
<strong>Generation Time:</strong> {{ generationTime }}ms
|
| 91 |
+
<span class="timing-detail">
|
| 92 |
+
(~{{ (generationTime / validMovesCount).toFixed(1) }}ms per move)
|
| 93 |
+
</span>
|
| 94 |
+
</div>
|
| 95 |
+
|
| 96 |
+
<div v-if="bestMoveApplied" class="success-info">
|
| 97 |
+
<strong>Best Move Applied:</strong> {{ bestMoveApplied }}
|
| 98 |
+
</div>
|
| 99 |
+
|
| 100 |
+
<!-- Scored Moves Display -->
|
| 101 |
+
<div v-if="scoredMoves.length > 0" class="moves-section">
|
| 102 |
+
<h4>Scored Moves (Top 20)</h4>
|
| 103 |
+
<div class="moves-table-container">
|
| 104 |
+
<table class="moves-table">
|
| 105 |
+
<thead>
|
| 106 |
+
<tr>
|
| 107 |
+
<th>Rank</th>
|
| 108 |
+
<th>Notation</th>
|
| 109 |
+
<th>Position</th>
|
| 110 |
+
<th>Log Prob</th>
|
| 111 |
+
<th>Probability</th>
|
| 112 |
+
<th>Action</th>
|
| 113 |
+
</tr>
|
| 114 |
+
</thead>
|
| 115 |
+
<tbody>
|
| 116 |
+
<tr
|
| 117 |
+
v-for="(scoredMove, index) in topMoves"
|
| 118 |
+
:key="index"
|
| 119 |
+
:class="{ 'top-move': index === 0 }"
|
| 120 |
+
>
|
| 121 |
+
<td>{{ index + 1 }}</td>
|
| 122 |
+
<td class="notation">{{ scoredMove.notation }}</td>
|
| 123 |
+
<td class="position">{{ formatPosition(scoredMove.move) }}</td>
|
| 124 |
+
<td class="score">{{ scoredMove.score.toFixed(3) }}</td>
|
| 125 |
+
<td class="probability">
|
| 126 |
+
{{ ((scoredMove.probability ?? 0) * 100).toFixed(4) }}%
|
| 127 |
+
</td>
|
| 128 |
+
<td>
|
| 129 |
+
<button @click="applyMove(scoredMove.move)" class="btn-small">
|
| 130 |
+
Apply
|
| 131 |
+
</button>
|
| 132 |
+
</td>
|
| 133 |
+
</tr>
|
| 134 |
+
</tbody>
|
| 135 |
+
</table>
|
| 136 |
+
</div>
|
| 137 |
+
</div>
|
| 138 |
+
|
| 139 |
+
<!-- Error Display -->
|
| 140 |
+
<div v-if="errorMessage" class="error-section">
|
| 141 |
+
<h4>Error</h4>
|
| 142 |
+
<pre>{{ errorMessage }}</pre>
|
| 143 |
+
</div>
|
| 144 |
+
</div>
|
| 145 |
+
|
| 146 |
+
<!-- Tree Visualization -->
|
| 147 |
+
<div v-if="treeVisualization" class="visualization-section">
|
| 148 |
+
<h3>Tree Structure Visualization</h3>
|
| 149 |
+
|
| 150 |
+
<!-- Move Details -->
|
| 151 |
+
<div class="move-details">
|
| 152 |
+
<h4>Move Details</h4>
|
| 153 |
+
<div class="details-grid">
|
| 154 |
+
<div
|
| 155 |
+
v-for="(move, index) in treeVisualization.moveData"
|
| 156 |
+
:key="index"
|
| 157 |
+
class="move-detail-item"
|
| 158 |
+
>
|
| 159 |
+
<span class="move-notation">{{ move.notation }}</span>
|
| 160 |
+
<span class="move-positions"
|
| 161 |
+
>parent={{ move.parentPos }}, leaf={{ move.leafPos }}</span
|
| 162 |
+
>
|
| 163 |
+
</div>
|
| 164 |
+
</div>
|
| 165 |
+
</div>
|
| 166 |
+
|
| 167 |
+
<!-- Token Sequence -->
|
| 168 |
+
<div class="token-sequence">
|
| 169 |
+
<h4>
|
| 170 |
+
Evaluated Token Sequence ({{ treeVisualization.evaluatedIds.length }} tokens)
|
| 171 |
+
</h4>
|
| 172 |
+
<div class="tokens-display">
|
| 173 |
+
<div
|
| 174 |
+
v-for="(tokenId, index) in treeVisualization.evaluatedIds"
|
| 175 |
+
:key="index"
|
| 176 |
+
class="token-item"
|
| 177 |
+
>
|
| 178 |
+
<div class="token-pos">{{ index }}</div>
|
| 179 |
+
<div class="token-char">{{ String.fromCharCode(tokenId) }}</div>
|
| 180 |
+
<div class="token-id">{{ tokenId }}</div>
|
| 181 |
+
</div>
|
| 182 |
+
</div>
|
| 183 |
+
</div>
|
| 184 |
+
|
| 185 |
+
<!-- Attention Mask Matrix -->
|
| 186 |
+
<div class="mask-matrix">
|
| 187 |
+
<h4>
|
| 188 |
+
Attention Mask Matrix ({{ Math.sqrt(treeVisualization.mask.length) }}×{{
|
| 189 |
+
Math.sqrt(treeVisualization.mask.length)
|
| 190 |
+
}})
|
| 191 |
+
</h4>
|
| 192 |
+
<div class="matrix-container">
|
| 193 |
+
<table class="matrix-table">
|
| 194 |
+
<thead>
|
| 195 |
+
<tr>
|
| 196 |
+
<th class="corner-cell"></th>
|
| 197 |
+
<th
|
| 198 |
+
v-for="(tokenId, col) in treeVisualization.evaluatedIds"
|
| 199 |
+
:key="col"
|
| 200 |
+
class="header-cell"
|
| 201 |
+
>
|
| 202 |
+
<div class="header-content">
|
| 203 |
+
<div class="header-pos">{{ col }}</div>
|
| 204 |
+
<div class="header-char">
|
| 205 |
+
{{ String.fromCharCode(tokenId) }}
|
| 206 |
+
</div>
|
| 207 |
+
</div>
|
| 208 |
+
</th>
|
| 209 |
+
</tr>
|
| 210 |
+
</thead>
|
| 211 |
+
<tbody>
|
| 212 |
+
<tr v-for="(tokenId, row) in treeVisualization.evaluatedIds" :key="row">
|
| 213 |
+
<th class="row-header">
|
| 214 |
+
<div class="row-content">
|
| 215 |
+
<div class="row-pos">{{ row }}</div>
|
| 216 |
+
<div class="row-char">
|
| 217 |
+
{{ String.fromCharCode(tokenId) }}
|
| 218 |
+
</div>
|
| 219 |
+
</div>
|
| 220 |
+
</th>
|
| 221 |
+
<td
|
| 222 |
+
v-for="col in treeVisualization.evaluatedIds.length"
|
| 223 |
+
:key="col - 1"
|
| 224 |
+
:class="getMaskCellClass(row, col - 1)"
|
| 225 |
+
:title="`[${row},${col - 1}] = ${getMaskValue(row, col - 1)}`"
|
| 226 |
+
>
|
| 227 |
+
{{ getMaskValue(row, col - 1) }}
|
| 228 |
+
</td>
|
| 229 |
+
</tr>
|
| 230 |
+
</tbody>
|
| 231 |
+
</table>
|
| 232 |
+
</div>
|
| 233 |
+
<div class="matrix-legend">
|
| 234 |
+
<span class="legend-item"
|
| 235 |
+
><span class="legend-box active"></span> 1 (can attend)</span
|
| 236 |
+
>
|
| 237 |
+
<span class="legend-item"
|
| 238 |
+
><span class="legend-box inactive"></span> 0 (cannot attend)</span
|
| 239 |
+
>
|
| 240 |
+
</div>
|
| 241 |
+
</div>
|
| 242 |
+
</div>
|
| 243 |
+
|
| 244 |
+
<!-- Debug Info -->
|
| 245 |
+
<div class="debug-section">
|
| 246 |
+
<h3>Debug Information</h3>
|
| 247 |
+
<div class="debug-content">
|
| 248 |
+
<div class="debug-item">
|
| 249 |
+
<span class="label">Current TGN:</span>
|
| 250 |
+
<pre class="debug-value">{{ currentTGN }}</pre>
|
| 251 |
+
</div>
|
| 252 |
+
</div>
|
| 253 |
+
</div>
|
| 254 |
+
</div>
|
| 255 |
+
</template>
|
| 256 |
+
|
| 257 |
+
<script setup lang="ts">
|
| 258 |
+
import { ref, computed, onMounted } from "vue";
|
| 259 |
+
import * as ort from "onnxruntime-web";
|
| 260 |
+
import { TrigoGame } from "../../../inc/trigo/game";
|
| 261 |
+
import { ModelInferencer } from "../../../inc/modelInferencer";
|
| 262 |
+
import { TrigoTreeAgent } from "../../../inc/trigoTreeAgent";
|
| 263 |
+
import type { ScoredMove } from "../../../inc/trigoTreeAgent";
|
| 264 |
+
import type { Move } from "../../../inc/trigo/types";
|
| 265 |
+
|
| 266 |
+
// Configuration
|
| 267 |
+
const modelPath = "/onnx/GPT2CausalLM_ep0015_evaluation.onnx";
|
| 268 |
+
const vocabSize = 259;
|
| 269 |
+
|
| 270 |
+
// State
|
| 271 |
+
const game = ref<TrigoGame>(new TrigoGame({ x: 5, y: 5, z: 5 }, {}));
|
| 272 |
+
const inferencer = ref<ModelInferencer | null>(null);
|
| 273 |
+
const agent = ref<TrigoTreeAgent | null>(null);
|
| 274 |
+
|
| 275 |
+
const isInitializing = ref(false);
|
| 276 |
+
const isReady = ref(false);
|
| 277 |
+
const isGenerating = ref(false);
|
| 278 |
+
|
| 279 |
+
const scoredMoves = ref<ScoredMove[]>([]);
|
| 280 |
+
const generationTime = ref<number | null>(null);
|
| 281 |
+
const errorMessage = ref<string>("");
|
| 282 |
+
const bestMoveApplied = ref<string>("");
|
| 283 |
+
|
| 284 |
+
// Tree visualization data
|
| 285 |
+
const treeVisualization = ref<{
|
| 286 |
+
evaluatedIds: number[];
|
| 287 |
+
mask: number[];
|
| 288 |
+
moveData: Array<{ notation: string; parentPos: number; leafPos: number }>;
|
| 289 |
+
} | null>(null);
|
| 290 |
+
|
| 291 |
+
// Computed properties
|
| 292 |
+
const agentStatus = computed(() => {
|
| 293 |
+
if (isReady.value) return "Ready";
|
| 294 |
+
if (isInitializing.value) return "Initializing...";
|
| 295 |
+
return "Not initialized";
|
| 296 |
+
});
|
| 297 |
+
|
| 298 |
+
const statusClass = computed(() => {
|
| 299 |
+
if (isReady.value) return "status-ready";
|
| 300 |
+
if (isInitializing.value) return "status-loading";
|
| 301 |
+
return "status-error";
|
| 302 |
+
});
|
| 303 |
+
|
| 304 |
+
const currentPlayer = computed(() => {
|
| 305 |
+
const player = game.value.getCurrentPlayer();
|
| 306 |
+
return player === 1 ? "Black" : "White";
|
| 307 |
+
});
|
| 308 |
+
|
| 309 |
+
const moveCount = computed(() => game.value.stepHistory.length);
|
| 310 |
+
|
| 311 |
+
const validMovesCount = computed(() => {
|
| 312 |
+
return game.value.validMovePositions().length + 1; // +1 for pass
|
| 313 |
+
});
|
| 314 |
+
|
| 315 |
+
const currentTGN = computed(() => game.value.toTGN());
|
| 316 |
+
|
| 317 |
+
// Compute normalized probabilities for scored moves (softmax across move dimension)
|
| 318 |
+
const movesWithProbability = computed(() => {
|
| 319 |
+
if (scoredMoves.value.length === 0) {
|
| 320 |
+
return [];
|
| 321 |
+
}
|
| 322 |
+
|
| 323 |
+
// Find max score for numerical stability
|
| 324 |
+
const maxScore = Math.max(...scoredMoves.value.map((m) => m.score));
|
| 325 |
+
|
| 326 |
+
// Compute exp(score - maxScore) for each move
|
| 327 |
+
const expScores = scoredMoves.value.map((m) => Math.exp(m.score - maxScore));
|
| 328 |
+
|
| 329 |
+
// Compute sum of exp scores
|
| 330 |
+
const sumExp = expScores.reduce((sum, exp) => sum + exp, 0);
|
| 331 |
+
|
| 332 |
+
// Return moves with normalized probabilities
|
| 333 |
+
return scoredMoves.value.map((move, i) => ({
|
| 334 |
+
...move,
|
| 335 |
+
probability: expScores[i] / sumExp
|
| 336 |
+
}));
|
| 337 |
+
});
|
| 338 |
+
|
| 339 |
+
const topMoves = computed(() => movesWithProbability.value.slice(0, 20));
|
| 340 |
+
|
| 341 |
+
const boardDisplay = computed(() => {
|
| 342 |
+
// Simple text representation of the board
|
| 343 |
+
const shape = game.value.getShape();
|
| 344 |
+
let display = `Board: ${shape.x}×${shape.y}×${shape.z}\n\n`;
|
| 345 |
+
display += `Moves played: ${moveCount.value}\n`;
|
| 346 |
+
display += `Current player: ${currentPlayer.value}\n`;
|
| 347 |
+
display += `Valid positions: ${validMovesCount.value - 1} (+ pass)\n`;
|
| 348 |
+
return display;
|
| 349 |
+
});
|
| 350 |
+
|
| 351 |
+
// Methods
|
| 352 |
+
async function initializeAgent() {
|
| 353 |
+
isInitializing.value = true;
|
| 354 |
+
errorMessage.value = "";
|
| 355 |
+
|
| 356 |
+
try {
|
| 357 |
+
console.log("Loading evaluation model:", modelPath);
|
| 358 |
+
|
| 359 |
+
// Create inference session
|
| 360 |
+
const session = await ort.InferenceSession.create(modelPath);
|
| 361 |
+
console.log("✓ Model loaded successfully");
|
| 362 |
+
|
| 363 |
+
// Create inferencer
|
| 364 |
+
const inf = new ModelInferencer(ort.Tensor as any, {
|
| 365 |
+
vocabSize,
|
| 366 |
+
seqLen: 2048,
|
| 367 |
+
modelPath
|
| 368 |
+
});
|
| 369 |
+
inf.setSession(session as any);
|
| 370 |
+
inferencer.value = inf;
|
| 371 |
+
|
| 372 |
+
// Create agent
|
| 373 |
+
agent.value = new TrigoTreeAgent(inf);
|
| 374 |
+
|
| 375 |
+
isReady.value = true;
|
| 376 |
+
console.log("✓ Agent initialized");
|
| 377 |
+
} catch (error) {
|
| 378 |
+
console.error("Failed to initialize agent:", error);
|
| 379 |
+
errorMessage.value = String(error);
|
| 380 |
+
isReady.value = false;
|
| 381 |
+
} finally {
|
| 382 |
+
isInitializing.value = false;
|
| 383 |
+
}
|
| 384 |
+
}
|
| 385 |
+
|
| 386 |
+
async function generateMoves() {
|
| 387 |
+
if (!agent.value || !isReady.value) {
|
| 388 |
+
errorMessage.value = "Agent not ready";
|
| 389 |
+
return;
|
| 390 |
+
}
|
| 391 |
+
|
| 392 |
+
isGenerating.value = true;
|
| 393 |
+
errorMessage.value = "";
|
| 394 |
+
scoredMoves.value = [];
|
| 395 |
+
generationTime.value = null;
|
| 396 |
+
|
| 397 |
+
try {
|
| 398 |
+
console.log("Generating moves with tree attention...");
|
| 399 |
+
const startTime = performance.now();
|
| 400 |
+
|
| 401 |
+
// Get all valid moves
|
| 402 |
+
const currentPlayer = game.value.getCurrentPlayer() === 1 ? "black" : "white";
|
| 403 |
+
const validPositions = game.value.validMovePositions();
|
| 404 |
+
const moves: Move[] = validPositions.map((pos) => ({
|
| 405 |
+
x: pos.x,
|
| 406 |
+
y: pos.y,
|
| 407 |
+
z: pos.z,
|
| 408 |
+
player: currentPlayer
|
| 409 |
+
}));
|
| 410 |
+
moves.push({ player: currentPlayer, isPass: true }); // Add pass
|
| 411 |
+
|
| 412 |
+
console.log(`Scoring ${moves.length} moves...`);
|
| 413 |
+
|
| 414 |
+
// Get tree structure for visualization
|
| 415 |
+
const treeStructure = agent.value.getTreeStructure(game.value, moves);
|
| 416 |
+
treeVisualization.value = {
|
| 417 |
+
evaluatedIds: treeStructure.evaluatedIds,
|
| 418 |
+
mask: treeStructure.mask,
|
| 419 |
+
moveData: treeStructure.moveData.map((m) => ({
|
| 420 |
+
notation: m.notation,
|
| 421 |
+
parentPos: m.parentPos,
|
| 422 |
+
leafPos: m.leafPos
|
| 423 |
+
}))
|
| 424 |
+
};
|
| 425 |
+
|
| 426 |
+
// Score all moves using tree attention
|
| 427 |
+
const scored = await agent.value.scoreMoves(game.value, moves);
|
| 428 |
+
const endTime = performance.now();
|
| 429 |
+
|
| 430 |
+
generationTime.value = Math.round(endTime - startTime);
|
| 431 |
+
scoredMoves.value = scored.sort((a, b) => b.score - a.score);
|
| 432 |
+
|
| 433 |
+
console.log(`✓ Scored ${scored.length} moves in ${generationTime.value}ms`);
|
| 434 |
+
console.log(
|
| 435 |
+
"Top 5 moves:",
|
| 436 |
+
movesWithProbability.value.slice(0, 5).map((m) => ({
|
| 437 |
+
notation: m.notation,
|
| 438 |
+
score: m.score.toFixed(3),
|
| 439 |
+
prob: ((m.probability ?? 0) * 100).toFixed(4) + "%"
|
| 440 |
+
}))
|
| 441 |
+
);
|
| 442 |
+
} catch (error) {
|
| 443 |
+
console.error("Failed to generate moves:", error);
|
| 444 |
+
errorMessage.value = String(error);
|
| 445 |
+
} finally {
|
| 446 |
+
isGenerating.value = false;
|
| 447 |
+
}
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
+
async function generateBestMove() {
|
| 451 |
+
if (!agent.value || !isReady.value) {
|
| 452 |
+
errorMessage.value = "Agent not ready";
|
| 453 |
+
return;
|
| 454 |
+
}
|
| 455 |
+
|
| 456 |
+
isGenerating.value = true;
|
| 457 |
+
errorMessage.value = "";
|
| 458 |
+
bestMoveApplied.value = "";
|
| 459 |
+
scoredMoves.value = [];
|
| 460 |
+
generationTime.value = null;
|
| 461 |
+
|
| 462 |
+
try {
|
| 463 |
+
console.log("Generating best move with tree attention...");
|
| 464 |
+
const startTime = performance.now();
|
| 465 |
+
|
| 466 |
+
// Use selectBestMove to get the best move
|
| 467 |
+
const bestMove = await agent.value.selectBestMove(game.value);
|
| 468 |
+
const endTime = performance.now();
|
| 469 |
+
|
| 470 |
+
generationTime.value = Math.round(endTime - startTime);
|
| 471 |
+
|
| 472 |
+
if (!bestMove) {
|
| 473 |
+
errorMessage.value = "No valid moves available";
|
| 474 |
+
return;
|
| 475 |
+
}
|
| 476 |
+
|
| 477 |
+
// Apply the best move
|
| 478 |
+
let success = false;
|
| 479 |
+
let moveNotation = "";
|
| 480 |
+
if (bestMove.isPass) {
|
| 481 |
+
success = game.value.pass();
|
| 482 |
+
moveNotation = "pass";
|
| 483 |
+
} else if (
|
| 484 |
+
bestMove.x !== undefined &&
|
| 485 |
+
bestMove.y !== undefined &&
|
| 486 |
+
bestMove.z !== undefined
|
| 487 |
+
) {
|
| 488 |
+
success = game.value.drop({ x: bestMove.x, y: bestMove.y, z: bestMove.z });
|
| 489 |
+
const shape = game.value.getShape();
|
| 490 |
+
const posArray = [bestMove.x, bestMove.y, bestMove.z];
|
| 491 |
+
const shapeArray = [shape.x, shape.y, shape.z];
|
| 492 |
+
// Import encodeAb0yz at the top if needed, or just show position
|
| 493 |
+
moveNotation = `(${bestMove.x}, ${bestMove.y}, ${bestMove.z})`;
|
| 494 |
+
}
|
| 495 |
+
|
| 496 |
+
if (success) {
|
| 497 |
+
bestMoveApplied.value = moveNotation;
|
| 498 |
+
console.log(`✓ Best move applied: ${moveNotation} in ${generationTime.value}ms`);
|
| 499 |
+
} else {
|
| 500 |
+
errorMessage.value = "Failed to apply best move";
|
| 501 |
+
}
|
| 502 |
+
} catch (error) {
|
| 503 |
+
console.error("Failed to generate best move:", error);
|
| 504 |
+
errorMessage.value = String(error);
|
| 505 |
+
} finally {
|
| 506 |
+
isGenerating.value = false;
|
| 507 |
+
}
|
| 508 |
+
}
|
| 509 |
+
|
| 510 |
+
function applyMove(move: Move) {
|
| 511 |
+
try {
|
| 512 |
+
let success = false;
|
| 513 |
+
if (move.isPass) {
|
| 514 |
+
success = game.value.pass();
|
| 515 |
+
} else if (move.x !== undefined && move.y !== undefined && move.z !== undefined) {
|
| 516 |
+
success = game.value.drop({ x: move.x, y: move.y, z: move.z });
|
| 517 |
+
}
|
| 518 |
+
|
| 519 |
+
if (success) {
|
| 520 |
+
console.log("✓ Move applied");
|
| 521 |
+
scoredMoves.value = [];
|
| 522 |
+
generationTime.value = null;
|
| 523 |
+
} else {
|
| 524 |
+
errorMessage.value = "Failed to apply move";
|
| 525 |
+
}
|
| 526 |
+
} catch (error) {
|
| 527 |
+
console.error("Error applying move:", error);
|
| 528 |
+
errorMessage.value = String(error);
|
| 529 |
+
}
|
| 530 |
+
}
|
| 531 |
+
|
| 532 |
+
function resetGame() {
|
| 533 |
+
game.value = new TrigoGame({ x: 5, y: 5, z: 5 }, {});
|
| 534 |
+
scoredMoves.value = [];
|
| 535 |
+
generationTime.value = null;
|
| 536 |
+
errorMessage.value = "";
|
| 537 |
+
bestMoveApplied.value = "";
|
| 538 |
+
console.log("✓ Game reset");
|
| 539 |
+
}
|
| 540 |
+
|
| 541 |
+
function formatPosition(move: Move): string {
|
| 542 |
+
if (move.isPass) return "Pass";
|
| 543 |
+
if (move.x !== undefined && move.y !== undefined && move.z !== undefined) {
|
| 544 |
+
return `(${move.x}, ${move.y}, ${move.z})`;
|
| 545 |
+
}
|
| 546 |
+
return "Unknown";
|
| 547 |
+
}
|
| 548 |
+
|
| 549 |
+
// Mask matrix helper functions
|
| 550 |
+
function getMaskValue(row: number, col: number): number {
|
| 551 |
+
if (!treeVisualization.value) return 0;
|
| 552 |
+
const m = treeVisualization.value.evaluatedIds.length;
|
| 553 |
+
return treeVisualization.value.mask[row * m + col];
|
| 554 |
+
}
|
| 555 |
+
|
| 556 |
+
function getMaskCellClass(row: number, col: number): string {
|
| 557 |
+
const value = getMaskValue(row, col);
|
| 558 |
+
return value === 1 ? "mask-cell mask-active" : "mask-cell mask-inactive";
|
| 559 |
+
}
|
| 560 |
+
|
| 561 |
+
// Lifecycle
|
| 562 |
+
onMounted(() => {
|
| 563 |
+
console.log("TrigoTreeTestView mounted");
|
| 564 |
+
});
|
| 565 |
+
</script>
|
| 566 |
+
|
| 567 |
+
<style scoped>
|
| 568 |
+
.tree-test-container {
|
| 569 |
+
max-width: 1200px;
|
| 570 |
+
margin: 0 auto;
|
| 571 |
+
padding: 2rem;
|
| 572 |
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
| 573 |
+
min-height: 100vh;
|
| 574 |
+
overflow-y: auto;
|
| 575 |
+
}
|
| 576 |
+
|
| 577 |
+
h1 {
|
| 578 |
+
color: #2c3e50;
|
| 579 |
+
margin-bottom: 1rem;
|
| 580 |
+
}
|
| 581 |
+
|
| 582 |
+
h2,
|
| 583 |
+
h3,
|
| 584 |
+
h4 {
|
| 585 |
+
color: #34495e;
|
| 586 |
+
margin-top: 2rem;
|
| 587 |
+
margin-bottom: 1rem;
|
| 588 |
+
}
|
| 589 |
+
|
| 590 |
+
.info-section {
|
| 591 |
+
background: #f8f9fa;
|
| 592 |
+
padding: 1.5rem;
|
| 593 |
+
border-radius: 8px;
|
| 594 |
+
margin-bottom: 2rem;
|
| 595 |
+
}
|
| 596 |
+
|
| 597 |
+
.info-section p {
|
| 598 |
+
margin: 0;
|
| 599 |
+
line-height: 1.6;
|
| 600 |
+
color: #555;
|
| 601 |
+
}
|
| 602 |
+
|
| 603 |
+
.status-section,
|
| 604 |
+
.board-section,
|
| 605 |
+
.generation-section,
|
| 606 |
+
.debug-section {
|
| 607 |
+
background: white;
|
| 608 |
+
border: 1px solid #e1e4e8;
|
| 609 |
+
border-radius: 8px;
|
| 610 |
+
padding: 1.5rem;
|
| 611 |
+
margin-bottom: 2rem;
|
| 612 |
+
}
|
| 613 |
+
|
| 614 |
+
.status-grid {
|
| 615 |
+
display: grid;
|
| 616 |
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
| 617 |
+
gap: 1rem;
|
| 618 |
+
margin-bottom: 1rem;
|
| 619 |
+
}
|
| 620 |
+
|
| 621 |
+
.status-item,
|
| 622 |
+
.info-item {
|
| 623 |
+
display: flex;
|
| 624 |
+
justify-content: space-between;
|
| 625 |
+
padding: 0.5rem;
|
| 626 |
+
background: #f8f9fa;
|
| 627 |
+
border-radius: 4px;
|
| 628 |
+
}
|
| 629 |
+
|
| 630 |
+
.label {
|
| 631 |
+
font-weight: 600;
|
| 632 |
+
color: #666;
|
| 633 |
+
}
|
| 634 |
+
|
| 635 |
+
.value {
|
| 636 |
+
color: #2c3e50;
|
| 637 |
+
}
|
| 638 |
+
|
| 639 |
+
.status-ready {
|
| 640 |
+
color: #28a745;
|
| 641 |
+
font-weight: 600;
|
| 642 |
+
}
|
| 643 |
+
|
| 644 |
+
.status-loading {
|
| 645 |
+
color: #ffc107;
|
| 646 |
+
font-weight: 600;
|
| 647 |
+
}
|
| 648 |
+
|
| 649 |
+
.status-error {
|
| 650 |
+
color: #dc3545;
|
| 651 |
+
font-weight: 600;
|
| 652 |
+
}
|
| 653 |
+
|
| 654 |
+
.board-info {
|
| 655 |
+
display: grid;
|
| 656 |
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
| 657 |
+
gap: 1rem;
|
| 658 |
+
margin-bottom: 1rem;
|
| 659 |
+
}
|
| 660 |
+
|
| 661 |
+
.board-display {
|
| 662 |
+
background: #f8f9fa;
|
| 663 |
+
border: 1px solid #e1e4e8;
|
| 664 |
+
border-radius: 4px;
|
| 665 |
+
padding: 1rem;
|
| 666 |
+
margin-bottom: 1rem;
|
| 667 |
+
}
|
| 668 |
+
|
| 669 |
+
.board-display pre {
|
| 670 |
+
margin: 0;
|
| 671 |
+
font-family: "Courier New", monospace;
|
| 672 |
+
font-size: 0.9rem;
|
| 673 |
+
color: #2c3e50;
|
| 674 |
+
}
|
| 675 |
+
|
| 676 |
+
.button-group {
|
| 677 |
+
display: flex;
|
| 678 |
+
gap: 1rem;
|
| 679 |
+
flex-wrap: wrap;
|
| 680 |
+
margin-bottom: 1rem;
|
| 681 |
+
}
|
| 682 |
+
|
| 683 |
+
.btn-primary,
|
| 684 |
+
.btn-secondary,
|
| 685 |
+
.btn-small {
|
| 686 |
+
padding: 0.75rem 1.5rem;
|
| 687 |
+
border: none;
|
| 688 |
+
border-radius: 4px;
|
| 689 |
+
font-size: 1rem;
|
| 690 |
+
font-weight: 600;
|
| 691 |
+
cursor: pointer;
|
| 692 |
+
transition: all 0.2s;
|
| 693 |
+
}
|
| 694 |
+
|
| 695 |
+
.btn-primary {
|
| 696 |
+
background: #007bff;
|
| 697 |
+
color: white;
|
| 698 |
+
}
|
| 699 |
+
|
| 700 |
+
.btn-primary:hover:not(:disabled) {
|
| 701 |
+
background: #0056b3;
|
| 702 |
+
}
|
| 703 |
+
|
| 704 |
+
.btn-primary:disabled {
|
| 705 |
+
background: #6c757d;
|
| 706 |
+
cursor: not-allowed;
|
| 707 |
+
opacity: 0.6;
|
| 708 |
+
}
|
| 709 |
+
|
| 710 |
+
.btn-secondary {
|
| 711 |
+
background: #6c757d;
|
| 712 |
+
color: white;
|
| 713 |
+
}
|
| 714 |
+
|
| 715 |
+
.btn-secondary:hover {
|
| 716 |
+
background: #545b62;
|
| 717 |
+
}
|
| 718 |
+
|
| 719 |
+
.btn-large {
|
| 720 |
+
padding: 1rem 2rem;
|
| 721 |
+
font-size: 1.1rem;
|
| 722 |
+
}
|
| 723 |
+
|
| 724 |
+
.btn-small {
|
| 725 |
+
padding: 0.25rem 0.75rem;
|
| 726 |
+
font-size: 0.875rem;
|
| 727 |
+
}
|
| 728 |
+
|
| 729 |
+
.timing-info {
|
| 730 |
+
margin-top: 1rem;
|
| 731 |
+
padding: 1rem;
|
| 732 |
+
background: #e7f5ff;
|
| 733 |
+
border-left: 4px solid #007bff;
|
| 734 |
+
border-radius: 4px;
|
| 735 |
+
}
|
| 736 |
+
|
| 737 |
+
.timing-detail {
|
| 738 |
+
color: #666;
|
| 739 |
+
font-size: 0.9rem;
|
| 740 |
+
margin-left: 0.5rem;
|
| 741 |
+
}
|
| 742 |
+
|
| 743 |
+
.success-info {
|
| 744 |
+
margin-top: 1rem;
|
| 745 |
+
padding: 1rem;
|
| 746 |
+
background: #d4edda;
|
| 747 |
+
border-left: 4px solid #28a745;
|
| 748 |
+
border-radius: 4px;
|
| 749 |
+
color: #155724;
|
| 750 |
+
font-weight: 600;
|
| 751 |
+
}
|
| 752 |
+
|
| 753 |
+
.moves-section {
|
| 754 |
+
margin-top: 2rem;
|
| 755 |
+
}
|
| 756 |
+
|
| 757 |
+
.moves-table-container {
|
| 758 |
+
overflow-x: auto;
|
| 759 |
+
margin-top: 1rem;
|
| 760 |
+
}
|
| 761 |
+
|
| 762 |
+
.moves-table {
|
| 763 |
+
width: 100%;
|
| 764 |
+
border-collapse: collapse;
|
| 765 |
+
font-size: 0.9rem;
|
| 766 |
+
}
|
| 767 |
+
|
| 768 |
+
.moves-table thead {
|
| 769 |
+
background: #f8f9fa;
|
| 770 |
+
}
|
| 771 |
+
|
| 772 |
+
.moves-table th {
|
| 773 |
+
padding: 0.75rem;
|
| 774 |
+
text-align: left;
|
| 775 |
+
font-weight: 600;
|
| 776 |
+
color: #495057;
|
| 777 |
+
border-bottom: 2px solid #dee2e6;
|
| 778 |
+
}
|
| 779 |
+
|
| 780 |
+
.moves-table td {
|
| 781 |
+
padding: 0.75rem;
|
| 782 |
+
border-bottom: 1px solid #dee2e6;
|
| 783 |
+
}
|
| 784 |
+
|
| 785 |
+
.moves-table tbody tr:hover {
|
| 786 |
+
background: #f8f9fa;
|
| 787 |
+
}
|
| 788 |
+
|
| 789 |
+
.moves-table .top-move {
|
| 790 |
+
background: #d4edda;
|
| 791 |
+
font-weight: 600;
|
| 792 |
+
}
|
| 793 |
+
|
| 794 |
+
.notation {
|
| 795 |
+
font-family: "Courier New", monospace;
|
| 796 |
+
font-weight: 600;
|
| 797 |
+
color: #007bff;
|
| 798 |
+
}
|
| 799 |
+
|
| 800 |
+
.position {
|
| 801 |
+
font-family: "Courier New", monospace;
|
| 802 |
+
color: #666;
|
| 803 |
+
}
|
| 804 |
+
|
| 805 |
+
.score {
|
| 806 |
+
font-family: "Courier New", monospace;
|
| 807 |
+
text-align: right;
|
| 808 |
+
}
|
| 809 |
+
|
| 810 |
+
.probability {
|
| 811 |
+
font-family: "Courier New", monospace;
|
| 812 |
+
text-align: right;
|
| 813 |
+
color: #28a745;
|
| 814 |
+
}
|
| 815 |
+
|
| 816 |
+
.error-section {
|
| 817 |
+
margin-top: 1rem;
|
| 818 |
+
padding: 1rem;
|
| 819 |
+
background: #f8d7da;
|
| 820 |
+
border: 1px solid #f5c6cb;
|
| 821 |
+
border-radius: 4px;
|
| 822 |
+
color: #721c24;
|
| 823 |
+
}
|
| 824 |
+
|
| 825 |
+
.error-section pre {
|
| 826 |
+
margin: 0.5rem 0 0 0;
|
| 827 |
+
white-space: pre-wrap;
|
| 828 |
+
word-wrap: break-word;
|
| 829 |
+
font-size: 0.9rem;
|
| 830 |
+
}
|
| 831 |
+
|
| 832 |
+
.debug-section {
|
| 833 |
+
background: #f8f9fa;
|
| 834 |
+
}
|
| 835 |
+
|
| 836 |
+
.debug-content {
|
| 837 |
+
display: flex;
|
| 838 |
+
flex-direction: column;
|
| 839 |
+
gap: 1rem;
|
| 840 |
+
}
|
| 841 |
+
|
| 842 |
+
.debug-item {
|
| 843 |
+
display: flex;
|
| 844 |
+
flex-direction: column;
|
| 845 |
+
gap: 0.5rem;
|
| 846 |
+
}
|
| 847 |
+
|
| 848 |
+
.debug-value {
|
| 849 |
+
background: white;
|
| 850 |
+
border: 1px solid #e1e4e8;
|
| 851 |
+
border-radius: 4px;
|
| 852 |
+
padding: 1rem;
|
| 853 |
+
margin: 0;
|
| 854 |
+
font-family: "Courier New", monospace;
|
| 855 |
+
font-size: 0.85rem;
|
| 856 |
+
overflow-x: auto;
|
| 857 |
+
color: #2c3e50;
|
| 858 |
+
}
|
| 859 |
+
|
| 860 |
+
/* Tree Visualization Styles */
|
| 861 |
+
.visualization-section {
|
| 862 |
+
background: white;
|
| 863 |
+
border: 1px solid #e1e4e8;
|
| 864 |
+
border-radius: 8px;
|
| 865 |
+
padding: 1.5rem;
|
| 866 |
+
margin-bottom: 2rem;
|
| 867 |
+
}
|
| 868 |
+
|
| 869 |
+
.move-details {
|
| 870 |
+
margin-bottom: 2rem;
|
| 871 |
+
}
|
| 872 |
+
|
| 873 |
+
.details-grid {
|
| 874 |
+
display: grid;
|
| 875 |
+
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
| 876 |
+
gap: 0.5rem;
|
| 877 |
+
margin-top: 1rem;
|
| 878 |
+
}
|
| 879 |
+
|
| 880 |
+
.move-detail-item {
|
| 881 |
+
display: flex;
|
| 882 |
+
flex-direction: column;
|
| 883 |
+
padding: 0.5rem;
|
| 884 |
+
background: #f8f9fa;
|
| 885 |
+
border-radius: 4px;
|
| 886 |
+
font-size: 0.85rem;
|
| 887 |
+
}
|
| 888 |
+
|
| 889 |
+
.move-notation {
|
| 890 |
+
font-family: "Courier New", monospace;
|
| 891 |
+
font-weight: 600;
|
| 892 |
+
color: #007bff;
|
| 893 |
+
font-size: 1rem;
|
| 894 |
+
}
|
| 895 |
+
|
| 896 |
+
.move-positions {
|
| 897 |
+
font-family: "Courier New", monospace;
|
| 898 |
+
color: #666;
|
| 899 |
+
font-size: 0.75rem;
|
| 900 |
+
margin-top: 0.25rem;
|
| 901 |
+
}
|
| 902 |
+
|
| 903 |
+
.token-sequence {
|
| 904 |
+
margin-bottom: 2rem;
|
| 905 |
+
}
|
| 906 |
+
|
| 907 |
+
.tokens-display {
|
| 908 |
+
display: flex;
|
| 909 |
+
flex-wrap: wrap;
|
| 910 |
+
gap: 0.5rem;
|
| 911 |
+
margin-top: 1rem;
|
| 912 |
+
}
|
| 913 |
+
|
| 914 |
+
.token-item {
|
| 915 |
+
display: flex;
|
| 916 |
+
flex-direction: column;
|
| 917 |
+
align-items: center;
|
| 918 |
+
padding: 0.5rem;
|
| 919 |
+
background: #e7f5ff;
|
| 920 |
+
border: 1px solid #007bff;
|
| 921 |
+
border-radius: 4px;
|
| 922 |
+
min-width: 50px;
|
| 923 |
+
}
|
| 924 |
+
|
| 925 |
+
.token-pos {
|
| 926 |
+
font-size: 0.7rem;
|
| 927 |
+
color: #666;
|
| 928 |
+
font-weight: 600;
|
| 929 |
+
}
|
| 930 |
+
|
| 931 |
+
.token-char {
|
| 932 |
+
font-family: "Courier New", monospace;
|
| 933 |
+
font-size: 1.2rem;
|
| 934 |
+
font-weight: 600;
|
| 935 |
+
color: #007bff;
|
| 936 |
+
margin: 0.25rem 0;
|
| 937 |
+
}
|
| 938 |
+
|
| 939 |
+
.token-id {
|
| 940 |
+
font-size: 0.7rem;
|
| 941 |
+
color: #666;
|
| 942 |
+
font-family: "Courier New", monospace;
|
| 943 |
+
}
|
| 944 |
+
|
| 945 |
+
.mask-matrix {
|
| 946 |
+
margin-top: 2rem;
|
| 947 |
+
}
|
| 948 |
+
|
| 949 |
+
.matrix-container {
|
| 950 |
+
overflow: auto;
|
| 951 |
+
margin-top: 1rem;
|
| 952 |
+
max-height: 600px;
|
| 953 |
+
border: 1px solid #e1e4e8;
|
| 954 |
+
border-radius: 4px;
|
| 955 |
+
}
|
| 956 |
+
|
| 957 |
+
.matrix-table {
|
| 958 |
+
border-collapse: collapse;
|
| 959 |
+
font-size: 0.75rem;
|
| 960 |
+
min-width: 100%;
|
| 961 |
+
}
|
| 962 |
+
|
| 963 |
+
.corner-cell {
|
| 964 |
+
background: #f8f9fa;
|
| 965 |
+
border: 1px solid #dee2e6;
|
| 966 |
+
position: sticky;
|
| 967 |
+
left: 0;
|
| 968 |
+
top: 0;
|
| 969 |
+
z-index: 3;
|
| 970 |
+
}
|
| 971 |
+
|
| 972 |
+
.header-cell {
|
| 973 |
+
background: #f8f9fa;
|
| 974 |
+
border: 1px solid #dee2e6;
|
| 975 |
+
padding: 0.5rem;
|
| 976 |
+
position: sticky;
|
| 977 |
+
top: 0;
|
| 978 |
+
z-index: 2;
|
| 979 |
+
text-align: center;
|
| 980 |
+
min-width: 40px;
|
| 981 |
+
}
|
| 982 |
+
|
| 983 |
+
.header-content {
|
| 984 |
+
display: flex;
|
| 985 |
+
flex-direction: column;
|
| 986 |
+
align-items: center;
|
| 987 |
+
}
|
| 988 |
+
|
| 989 |
+
.header-pos {
|
| 990 |
+
font-size: 0.65rem;
|
| 991 |
+
color: #666;
|
| 992 |
+
font-weight: 600;
|
| 993 |
+
}
|
| 994 |
+
|
| 995 |
+
.header-char {
|
| 996 |
+
font-family: "Courier New", monospace;
|
| 997 |
+
font-size: 0.9rem;
|
| 998 |
+
font-weight: 600;
|
| 999 |
+
color: #007bff;
|
| 1000 |
+
margin-top: 0.1rem;
|
| 1001 |
+
}
|
| 1002 |
+
|
| 1003 |
+
.row-header {
|
| 1004 |
+
background: #f8f9fa;
|
| 1005 |
+
border: 1px solid #dee2e6;
|
| 1006 |
+
padding: 0.5rem;
|
| 1007 |
+
position: sticky;
|
| 1008 |
+
left: 0;
|
| 1009 |
+
z-index: 1;
|
| 1010 |
+
text-align: center;
|
| 1011 |
+
min-width: 50px;
|
| 1012 |
+
}
|
| 1013 |
+
|
| 1014 |
+
.row-content {
|
| 1015 |
+
display: flex;
|
| 1016 |
+
flex-direction: column;
|
| 1017 |
+
align-items: center;
|
| 1018 |
+
}
|
| 1019 |
+
|
| 1020 |
+
.row-pos {
|
| 1021 |
+
font-size: 0.65rem;
|
| 1022 |
+
color: #666;
|
| 1023 |
+
font-weight: 600;
|
| 1024 |
+
}
|
| 1025 |
+
|
| 1026 |
+
.row-char {
|
| 1027 |
+
font-family: "Courier New", monospace;
|
| 1028 |
+
font-size: 0.9rem;
|
| 1029 |
+
font-weight: 600;
|
| 1030 |
+
color: #007bff;
|
| 1031 |
+
margin-top: 0.1rem;
|
| 1032 |
+
}
|
| 1033 |
+
|
| 1034 |
+
.mask-cell {
|
| 1035 |
+
border: 1px solid #dee2e6;
|
| 1036 |
+
padding: 0.5rem;
|
| 1037 |
+
text-align: center;
|
| 1038 |
+
font-family: "Courier New", monospace;
|
| 1039 |
+
font-weight: 600;
|
| 1040 |
+
font-size: 0.8rem;
|
| 1041 |
+
}
|
| 1042 |
+
|
| 1043 |
+
.mask-active {
|
| 1044 |
+
background: #d4edda;
|
| 1045 |
+
color: #155724;
|
| 1046 |
+
}
|
| 1047 |
+
|
| 1048 |
+
.mask-inactive {
|
| 1049 |
+
background: #f8f9fa;
|
| 1050 |
+
color: #ccc;
|
| 1051 |
+
}
|
| 1052 |
+
|
| 1053 |
+
.matrix-legend {
|
| 1054 |
+
display: flex;
|
| 1055 |
+
gap: 1.5rem;
|
| 1056 |
+
margin-top: 1rem;
|
| 1057 |
+
padding: 0.75rem;
|
| 1058 |
+
background: #f8f9fa;
|
| 1059 |
+
border-radius: 4px;
|
| 1060 |
+
}
|
| 1061 |
+
|
| 1062 |
+
.legend-item {
|
| 1063 |
+
display: flex;
|
| 1064 |
+
align-items: center;
|
| 1065 |
+
gap: 0.5rem;
|
| 1066 |
+
font-size: 0.85rem;
|
| 1067 |
+
}
|
| 1068 |
+
|
| 1069 |
+
.legend-box {
|
| 1070 |
+
width: 20px;
|
| 1071 |
+
height: 20px;
|
| 1072 |
+
border: 1px solid #dee2e6;
|
| 1073 |
+
border-radius: 3px;
|
| 1074 |
+
}
|
| 1075 |
+
|
| 1076 |
+
.legend-box.active {
|
| 1077 |
+
background: #d4edda;
|
| 1078 |
+
}
|
| 1079 |
+
|
| 1080 |
+
.legend-box.inactive {
|
| 1081 |
+
background: #f8f9fa;
|
| 1082 |
+
}
|
| 1083 |
+
</style>
|
trigo-web/app/src/views/TrigoView.vue
CHANGED
|
@@ -1,15 +1,67 @@
|
|
| 1 |
<template>
|
| 2 |
<div class="trigo-view">
|
| 3 |
<div class="view-header">
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
|
|
|
| 9 |
{{ currentPlayer === "black" ? "Black" : "White" }}'s Turn
|
| 10 |
</span>
|
| 11 |
<span class="move-count">Move: {{ moveCount }}</span>
|
| 12 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
</div>
|
| 14 |
|
| 15 |
<div class="view-body">
|
|
@@ -23,9 +75,15 @@
|
|
| 23 |
<!-- Inspect Mode Tooltip -->
|
| 24 |
<div class="inspect-tooltip" v-if="inspectInfo.visible">
|
| 25 |
<div class="tooltip-content">
|
| 26 |
-
<span class="tooltip-label"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
<span class="tooltip-divider">|</span>
|
| 28 |
-
<span class="tooltip-label"
|
|
|
|
|
|
|
| 29 |
</div>
|
| 30 |
</div>
|
| 31 |
</div>
|
|
@@ -34,19 +92,32 @@
|
|
| 34 |
<!-- Game Controls & Info Panel (Right) -->
|
| 35 |
<div class="controls-panel">
|
| 36 |
<!-- Score Display (Captured/Territory) -->
|
| 37 |
-
<div
|
| 38 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
<div class="score-display">
|
| 40 |
<button class="score-button black" :disabled="!gameStarted">
|
| 41 |
<span class="color-indicator black-stone"></span>
|
| 42 |
-
<span class="score">{{
|
|
|
|
|
|
|
| 43 |
</button>
|
| 44 |
<button class="score-button white" :disabled="!gameStarted">
|
| 45 |
<span class="color-indicator white-stone"></span>
|
| 46 |
-
<span class="score">{{
|
|
|
|
|
|
|
| 47 |
</button>
|
| 48 |
</div>
|
| 49 |
-
<button
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
Compute Territory
|
| 51 |
</button>
|
| 52 |
</div>
|
|
@@ -55,7 +126,11 @@
|
|
| 55 |
<div class="panel-section routine-section">
|
| 56 |
<h3 class="section-title">
|
| 57 |
Move History
|
| 58 |
-
<button
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
TGN
|
| 60 |
</button>
|
| 61 |
</h3>
|
|
@@ -83,7 +158,9 @@
|
|
| 83 |
@click="jumpToMove(round.blackIndex)"
|
| 84 |
>
|
| 85 |
<span class="stone-icon black"></span>
|
| 86 |
-
<span class="move-coords" v-if="!round.black.isPass">{{
|
|
|
|
|
|
|
| 87 |
<span class="move-label" v-else>pass</span>
|
| 88 |
</div>
|
| 89 |
<div
|
|
@@ -93,7 +170,9 @@
|
|
| 93 |
@click="jumpToMove(round.whiteIndex)"
|
| 94 |
>
|
| 95 |
<span class="stone-icon white"></span>
|
| 96 |
-
<span class="move-coords" v-if="!round.white.isPass">{{
|
|
|
|
|
|
|
| 97 |
<span class="move-label" v-else>pass</span>
|
| 98 |
</div>
|
| 99 |
<div v-else class="move-cell empty"></div>
|
|
@@ -142,7 +221,12 @@
|
|
| 142 |
<div class="setting-item">
|
| 143 |
<label for="board-shape">
|
| 144 |
Board Shape:
|
| 145 |
-
<span
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
</label>
|
| 147 |
<select id="board-shape" v-model="selectedBoardShape">
|
| 148 |
<option value="3*3*3">3×3×3</option>
|
|
@@ -193,1432 +277,1737 @@
|
|
| 193 |
</template>
|
| 194 |
|
| 195 |
<script setup lang="ts">
|
| 196 |
-
import { ref, onMounted, onUnmounted, watch, computed, nextTick } from "vue";
|
| 197 |
-
import {
|
| 198 |
-
import {
|
| 199 |
-
import {
|
| 200 |
-
import
|
| 201 |
-
import {
|
| 202 |
-
import {
|
| 203 |
-
import {
|
| 204 |
-
import
|
| 205 |
-
import {
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
const
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
const
|
| 214 |
-
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
const
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
const
|
| 264 |
-
const
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
const rounds: Array<{
|
| 273 |
-
black: any;
|
| 274 |
-
white: any | null;
|
| 275 |
-
blackIndex: number;
|
| 276 |
-
whiteIndex: number | null;
|
| 277 |
-
}> = [];
|
| 278 |
-
|
| 279 |
-
for (let i = 0; i < moveHistory.value.length; i += 2) {
|
| 280 |
-
const blackMove = moveHistory.value[i];
|
| 281 |
-
const whiteMove = moveHistory.value[i + 1] || null;
|
| 282 |
-
|
| 283 |
-
rounds.push({
|
| 284 |
-
black: blackMove,
|
| 285 |
-
white: whiteMove,
|
| 286 |
-
blackIndex: i + 1, // Convert array index to "moves applied" count
|
| 287 |
-
whiteIndex: whiteMove ? i + 2 : null // Convert array index to "moves applied" count
|
| 288 |
-
});
|
| 289 |
-
}
|
| 290 |
-
|
| 291 |
-
return rounds;
|
| 292 |
-
});
|
| 293 |
-
|
| 294 |
-
// Check if selected board shape differs from current game board shape
|
| 295 |
-
const isBoardShapeDirty = computed(() => {
|
| 296 |
-
const selectedShape = parseBoardShape(selectedBoardShape.value);
|
| 297 |
-
const currentShape = boardShape.value;
|
| 298 |
-
return selectedShape.x !== currentShape.x ||
|
| 299 |
-
selectedShape.y !== currentShape.y ||
|
| 300 |
-
selectedShape.z !== currentShape.z;
|
| 301 |
-
});
|
| 302 |
-
|
| 303 |
-
// Generate TGN content
|
| 304 |
-
const tgnContent = computed(() => {
|
| 305 |
-
return gameStore.game?.toTGN({
|
| 306 |
-
application: 'Trigo Demo v1.0',
|
| 307 |
-
date: new Date().toISOString().split('T')[0].replace(/-/g, '.')
|
| 308 |
-
}) || '';
|
| 309 |
-
});
|
| 310 |
-
|
| 311 |
-
// TGN validation computed properties
|
| 312 |
-
const tgnIsValid = computed(() => tgnValidationState.value === 'valid');
|
| 313 |
-
|
| 314 |
-
const tgnValidationClass = computed(() => {
|
| 315 |
-
if (tgnValidationState.value === 'idle') return 'idle';
|
| 316 |
-
if (tgnValidationState.value === 'valid') return 'valid';
|
| 317 |
-
return 'invalid';
|
| 318 |
-
});
|
| 319 |
-
|
| 320 |
-
const tgnValidationMessage = computed(() => {
|
| 321 |
-
if (tgnValidationState.value === 'idle') return 'Ready to validate';
|
| 322 |
-
if (tgnValidationState.value === 'valid') return '✓ Valid TGN';
|
| 323 |
-
return `✗ ${tgnValidationError.value}`;
|
| 324 |
-
});
|
| 325 |
-
|
| 326 |
-
// Debounced TGN validation (synchronous)
|
| 327 |
-
const onTGNEdit = () => {
|
| 328 |
-
// Clear existing timeout
|
| 329 |
-
if (tgnValidationTimeout) {
|
| 330 |
-
clearTimeout(tgnValidationTimeout);
|
| 331 |
-
}
|
| 332 |
|
| 333 |
-
//
|
| 334 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 335 |
|
| 336 |
-
|
| 337 |
-
|
| 338 |
-
const result = validateTGN(editableTGNContent.value);
|
| 339 |
|
| 340 |
-
|
| 341 |
-
|
| 342 |
-
|
| 343 |
-
|
| 344 |
-
|
| 345 |
-
|
| 346 |
-
|
| 347 |
-
|
| 348 |
-
|
|
|
|
| 349 |
|
| 350 |
-
//
|
| 351 |
-
const
|
| 352 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 353 |
|
| 354 |
-
|
| 355 |
-
|
| 356 |
|
| 357 |
-
|
| 358 |
-
|
|
|
|
|
|
|
|
|
|
| 359 |
|
| 360 |
-
|
| 361 |
-
|
|
|
|
|
|
|
|
|
|
| 362 |
|
| 363 |
-
|
| 364 |
-
|
| 365 |
-
|
| 366 |
-
|
| 367 |
-
|
| 368 |
}
|
| 369 |
|
| 370 |
-
//
|
| 371 |
-
|
| 372 |
-
} catch (err) {
|
| 373 |
-
console.error('Failed to apply TGN:', err);
|
| 374 |
-
tgnValidationState.value = 'invalid';
|
| 375 |
-
tgnValidationError.value = err instanceof Error ? err.message : 'Failed to apply TGN';
|
| 376 |
-
}
|
| 377 |
-
};
|
| 378 |
|
| 379 |
-
//
|
| 380 |
-
|
| 381 |
-
|
| 382 |
-
return;
|
| 383 |
|
| 384 |
-
|
| 385 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 386 |
|
| 387 |
-
|
| 388 |
-
|
| 389 |
-
|
| 390 |
-
viewport.addStone(x, y, z, stoneColor);
|
| 391 |
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
result.capturedPositions.forEach(pos => {
|
| 395 |
-
viewport.removeStone(pos.x, pos.y, pos.z);
|
| 396 |
-
});
|
| 397 |
-
console.log(`Captured ${result.capturedPositions.length} stone(s)`);
|
| 398 |
-
}
|
| 399 |
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
showTerritoryMode.value = false;
|
| 403 |
-
}
|
| 404 |
-
};
|
| 405 |
-
|
| 406 |
-
// Handle position hover
|
| 407 |
-
const handlePositionHover = (x: number | null, y: number | null, z: number | null) => {
|
| 408 |
-
if (x !== null && y !== null && z !== null) {
|
| 409 |
-
hoveredPosition.value = `(${x}, ${y}, ${z})`;
|
| 410 |
-
} else {
|
| 411 |
-
hoveredPosition.value = null;
|
| 412 |
-
}
|
| 413 |
-
};
|
| 414 |
-
|
| 415 |
-
// Check if a position is droppable (validates with game rules)
|
| 416 |
-
const isPositionDroppable = (x: number, y: number, z: number): boolean => {
|
| 417 |
-
const pos = { x, y, z };
|
| 418 |
-
const playerColor = currentPlayer.value === "black" ? StoneType.BLACK : StoneType.WHITE;
|
| 419 |
-
|
| 420 |
-
const validation = validateMove(
|
| 421 |
-
pos,
|
| 422 |
-
playerColor,
|
| 423 |
-
gameStore.board,
|
| 424 |
-
boardShape.value,
|
| 425 |
-
gameStore.lastCapturedPositions
|
| 426 |
-
);
|
| 427 |
-
|
| 428 |
-
return validation.valid;
|
| 429 |
-
};
|
| 430 |
-
|
| 431 |
-
// Handle inspect mode callback
|
| 432 |
-
const handleInspectGroup = (groupSize: number, liberties: number) => {
|
| 433 |
-
if (groupSize > 0) {
|
| 434 |
-
inspectInfo.value = {
|
| 435 |
-
visible: true,
|
| 436 |
-
groupSize,
|
| 437 |
-
liberties
|
| 438 |
-
};
|
| 439 |
-
} else {
|
| 440 |
-
inspectInfo.value = {
|
| 441 |
-
visible: false,
|
| 442 |
-
groupSize: 0,
|
| 443 |
-
liberties: 0
|
| 444 |
-
};
|
| 445 |
-
}
|
| 446 |
-
};
|
| 447 |
|
|
|
|
|
|
|
| 448 |
|
| 449 |
-
//
|
| 450 |
-
|
| 451 |
-
|
| 452 |
-
|
| 453 |
-
|
|
|
|
| 454 |
|
| 455 |
-
|
| 456 |
-
|
| 457 |
-
|
| 458 |
-
|
| 459 |
-
|
| 460 |
-
|
|
|
|
|
|
|
| 461 |
|
| 462 |
|
| 463 |
-
//
|
| 464 |
-
const
|
| 465 |
-
|
| 466 |
-
|
|
|
|
| 467 |
|
| 468 |
-
|
| 469 |
-
|
| 470 |
-
gameStore.startGame();
|
| 471 |
|
| 472 |
-
|
| 473 |
-
|
| 474 |
-
viewport.setBoardShape(shape);
|
| 475 |
-
viewport.clearBoard();
|
| 476 |
-
viewport.setGameActive(true);
|
| 477 |
|
| 478 |
-
|
| 479 |
-
|
| 480 |
-
|
| 481 |
|
| 482 |
-
|
| 483 |
-
|
| 484 |
-
whiteScore.value = 0;
|
| 485 |
-
showTerritoryMode.value = false;
|
| 486 |
|
| 487 |
-
|
| 488 |
-
|
| 489 |
-
|
| 490 |
-
|
| 491 |
|
| 492 |
-
|
| 493 |
-
|
| 494 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 495 |
|
| 496 |
-
if (success) {
|
| 497 |
-
// Check if game ended due to double pass
|
| 498 |
-
//if (gameStore.gameResult?.reason === "double-pass") {
|
| 499 |
-
// showGameResult();
|
| 500 |
-
//} else {
|
| 501 |
-
console.log(`${previousPlayer} passed (Pass count: ${gameStore.passCount})`);
|
| 502 |
-
//}
|
| 503 |
-
}
|
| 504 |
-
};
|
| 505 |
|
|
|
|
|
|
|
|
|
|
| 506 |
|
| 507 |
-
|
| 508 |
-
|
| 509 |
-
const confirmed = confirm(
|
| 510 |
-
`Are you sure ${currentPlayer.value} wants to resign?\n\nThis will end the game immediately.`
|
| 511 |
-
);
|
| 512 |
|
| 513 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 514 |
|
| 515 |
-
|
|
|
|
|
|
|
| 516 |
|
| 517 |
-
|
| 518 |
-
|
| 519 |
-
|
| 520 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 521 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 522 |
|
| 523 |
-
const showGameResult = () => {
|
| 524 |
-
const result = gameStore.gameResult;
|
| 525 |
-
if (!result) return;
|
| 526 |
|
| 527 |
-
//
|
| 528 |
-
|
| 529 |
-
|
| 530 |
-
|
| 531 |
|
| 532 |
-
|
| 533 |
-
|
| 534 |
-
message = `${result.winner === "black" ? "Black" : "White"} wins by resignation!\n\nGame continues for analysis.`;
|
| 535 |
-
} else if (result.reason === "double-pass") {
|
| 536 |
-
// Calculate final scores for double pass
|
| 537 |
-
const territory = gameStore.computeTerritory();
|
| 538 |
-
const blackTotal = territory.black + capturedStones.value.black;
|
| 539 |
-
const whiteTotal = territory.white + capturedStones.value.white;
|
| 540 |
|
| 541 |
-
|
| 542 |
-
whiteScore.value = whiteTotal;
|
| 543 |
|
| 544 |
-
|
| 545 |
-
|
| 546 |
-
|
| 547 |
-
|
| 548 |
-
|
| 549 |
-
message = `Game is a draw!\n\nBoth players: ${blackTotal} points\n\nGame continues for analysis.`;
|
| 550 |
}
|
| 551 |
-
}
|
| 552 |
|
| 553 |
-
setTimeout(() => {
|
| 554 |
-
alert(message);
|
| 555 |
-
}, 100);
|
| 556 |
-
};
|
| 557 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 558 |
|
| 559 |
-
|
| 560 |
-
|
|
|
|
| 561 |
|
| 562 |
-
|
| 563 |
-
if (showTerritoryMode.value) {
|
| 564 |
-
// Exit territory mode
|
| 565 |
if (viewport) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 566 |
viewport.hideDomainCubes();
|
| 567 |
}
|
| 568 |
-
|
| 569 |
-
// Reset scores
|
| 570 |
blackScore.value = 0;
|
| 571 |
whiteScore.value = 0;
|
| 572 |
-
|
| 573 |
-
}
|
| 574 |
|
| 575 |
-
|
| 576 |
-
const territory = gameStore.computeTerritory();
|
| 577 |
-
blackScore.value = territory.black + capturedStones.value.black;
|
| 578 |
-
whiteScore.value = territory.white + capturedStones.value.white;
|
| 579 |
|
| 580 |
-
|
| 581 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 582 |
|
| 583 |
-
|
| 584 |
-
|
| 585 |
-
const
|
| 586 |
-
const whiteDomain = new Set<string>();
|
| 587 |
|
| 588 |
-
|
| 589 |
-
|
| 590 |
-
|
| 591 |
-
|
| 592 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 593 |
|
| 594 |
-
|
| 595 |
-
|
| 596 |
-
|
| 597 |
-
|
|
|
|
| 598 |
|
| 599 |
-
|
| 600 |
-
viewport.setDomainData(blackDomain, whiteDomain);
|
| 601 |
-
viewport.setBlackDomainVisible(true);
|
| 602 |
-
viewport.setWhiteDomainVisible(true);
|
| 603 |
-
}
|
| 604 |
|
| 605 |
-
|
| 606 |
-
};
|
| 607 |
|
| 608 |
-
|
| 609 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 610 |
|
| 611 |
-
|
| 612 |
-
|
| 613 |
-
|
| 614 |
-
}
|
| 615 |
-
};
|
| 616 |
|
| 617 |
-
const
|
| 618 |
-
|
| 619 |
|
| 620 |
-
|
| 621 |
-
|
| 622 |
-
|
| 623 |
-
|
| 624 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 625 |
|
| 626 |
-
|
| 627 |
-
|
|
|
|
|
|
|
| 628 |
|
| 629 |
-
|
| 630 |
-
|
| 631 |
-
syncViewportWithStore();
|
| 632 |
|
| 633 |
-
//
|
| 634 |
-
viewport
|
| 635 |
-
|
| 636 |
-
|
| 637 |
-
|
| 638 |
-
|
| 639 |
-
|
| 640 |
-
}
|
| 641 |
-
|
| 642 |
-
|
| 643 |
-
|
| 644 |
-
|
| 645 |
-
|
| 646 |
-
|
| 647 |
-
|
| 648 |
-
|
| 649 |
-
|
| 650 |
-
|
| 651 |
-
|
| 652 |
-
|
| 653 |
-
// Add all stones that exist on the board
|
| 654 |
-
for (let x = 0; x < shape.x; x++) {
|
| 655 |
-
for (let y = 0; y < shape.y; y++) {
|
| 656 |
-
for (let z = 0; z < shape.z; z++) {
|
| 657 |
-
const stone = board[x][y][z];
|
| 658 |
-
if (stone === Stone.Black) {
|
| 659 |
-
viewport.addStone(x, y, z, "black");
|
| 660 |
-
} else if (stone === Stone.White) {
|
| 661 |
-
viewport.addStone(x, y, z, "white");
|
| 662 |
-
}
|
| 663 |
-
}
|
| 664 |
}
|
| 665 |
-
}
|
| 666 |
|
| 667 |
-
|
| 668 |
-
|
| 669 |
-
// So the last applied move is at array index (currentMoveIndex - 1)
|
| 670 |
-
if (currentMoveIndex.value > 0 && currentMoveIndex.value <= moveHistory.value.length) {
|
| 671 |
-
const lastMove = moveHistory.value[currentMoveIndex.value - 1];
|
| 672 |
-
viewport.setLastPlacedStone(lastMove.x, lastMove.y, lastMove.z);
|
| 673 |
-
} else {
|
| 674 |
-
// No moves applied or at START position
|
| 675 |
-
viewport.setLastPlacedStone(null, null, null);
|
| 676 |
-
}
|
| 677 |
-
};
|
| 678 |
|
| 679 |
-
|
| 680 |
-
|
| 681 |
-
|
| 682 |
-
viewport
|
| 683 |
-
|
| 684 |
-
|
| 685 |
-
|
| 686 |
-
// Watch currentMoveIndex to auto-scroll move history to keep current move visible
|
| 687 |
-
watch(currentMoveIndex, () => {
|
| 688 |
-
// Use nextTick to ensure DOM is updated before scrolling
|
| 689 |
-
nextTick(() => {
|
| 690 |
-
if (moveHistoryContainer.value) {
|
| 691 |
-
// Find the active move element
|
| 692 |
-
const activeElement = moveHistoryContainer.value.querySelector('.active');
|
| 693 |
-
if (activeElement) {
|
| 694 |
-
// Scroll the active element into view smoothly
|
| 695 |
-
activeElement.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
| 696 |
-
}
|
| 697 |
}
|
| 698 |
-
}
|
| 699 |
-
});
|
| 700 |
-
|
| 701 |
-
// Watch TGN modal to populate editable content when opened
|
| 702 |
-
watch(showTGNModal, (isVisible) => {
|
| 703 |
-
if (isVisible) {
|
| 704 |
-
// Populate with current game's TGN when modal opens
|
| 705 |
-
editableTGNContent.value = tgnContent.value;
|
| 706 |
-
tgnValidationState.value = 'valid'; // Current TGN is always valid
|
| 707 |
-
tgnValidationError.value = '';
|
| 708 |
-
}
|
| 709 |
-
});
|
| 710 |
|
|
|
|
|
|
|
| 711 |
|
| 712 |
-
|
| 713 |
-
|
| 714 |
-
|
|
|
|
|
|
|
| 715 |
|
| 716 |
-
|
| 717 |
-
|
| 718 |
|
| 719 |
-
|
| 720 |
-
|
| 721 |
-
|
| 722 |
-
const shape = parseBoardShape(selectedBoardShape.value);
|
| 723 |
|
| 724 |
-
|
| 725 |
-
|
| 726 |
-
|
| 727 |
-
|
| 728 |
-
|
| 729 |
-
|
| 730 |
-
|
|
|
|
| 731 |
|
| 732 |
-
//
|
| 733 |
-
|
| 734 |
-
|
| 735 |
-
onStoneClick: handleStoneClick,
|
| 736 |
-
onPositionHover: handlePositionHover,
|
| 737 |
-
isPositionDroppable: isPositionDroppable,
|
| 738 |
-
onInspectGroup: handleInspectGroup
|
| 739 |
-
});
|
| 740 |
-
console.log("TrigoViewport initialized");
|
| 741 |
|
| 742 |
-
//
|
| 743 |
-
|
| 744 |
|
| 745 |
-
//
|
| 746 |
-
|
| 747 |
-
|
| 748 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 749 |
}
|
| 750 |
-
}
|
| 751 |
|
| 752 |
-
|
| 753 |
-
|
| 754 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 755 |
if (viewport) {
|
| 756 |
-
viewport.
|
| 757 |
}
|
| 758 |
-
}
|
| 759 |
|
| 760 |
-
//
|
| 761 |
-
|
| 762 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 763 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 764 |
|
| 765 |
-
|
| 766 |
-
|
|
|
|
| 767 |
|
| 768 |
-
|
| 769 |
-
|
| 770 |
|
| 771 |
-
|
| 772 |
-
|
| 773 |
-
|
| 774 |
-
|
| 775 |
-
|
| 776 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 777 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 778 |
|
| 779 |
-
//
|
| 780 |
-
|
| 781 |
-
// Ignore if typing in an input field
|
| 782 |
-
if (event.target instanceof HTMLInputElement || event.target instanceof HTMLTextAreaElement) {
|
| 783 |
-
return;
|
| 784 |
-
}
|
| 785 |
|
| 786 |
-
|
| 787 |
-
|
| 788 |
-
|
| 789 |
-
|
| 790 |
}
|
| 791 |
-
break;
|
| 792 |
-
case "n": // New game
|
| 793 |
-
newGame();
|
| 794 |
-
break;
|
| 795 |
-
case "r": // Resign
|
| 796 |
-
if (gameStarted.value) {
|
| 797 |
-
resign();
|
| 798 |
-
}
|
| 799 |
-
break;
|
| 800 |
-
case "arrowleft": // Previous move
|
| 801 |
-
previousMove();
|
| 802 |
-
event.preventDefault();
|
| 803 |
-
break;
|
| 804 |
-
case "arrowright": // Next move
|
| 805 |
-
nextMove();
|
| 806 |
-
event.preventDefault();
|
| 807 |
-
break;
|
| 808 |
-
case "t": // Compute territory
|
| 809 |
-
if (gameStarted.value) {
|
| 810 |
-
computeTerritory();
|
| 811 |
-
}
|
| 812 |
-
break;
|
| 813 |
-
}
|
| 814 |
-
};
|
| 815 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 816 |
|
| 817 |
-
//
|
| 818 |
-
|
| 819 |
-
|
| 820 |
-
|
| 821 |
-
};
|
| 822 |
|
| 823 |
-
|
| 824 |
-
|
| 825 |
-
|
| 826 |
-
|
| 827 |
-
|
| 828 |
-
alert('TGN copied to clipboard!');
|
| 829 |
-
} else {
|
| 830 |
-
// Fallback for older browsers or non-secure contexts
|
| 831 |
-
const textarea = document.createElement('textarea');
|
| 832 |
-
textarea.value = tgnContent.value;
|
| 833 |
-
textarea.style.position = 'fixed';
|
| 834 |
-
textarea.style.opacity = '0';
|
| 835 |
-
document.body.appendChild(textarea);
|
| 836 |
-
textarea.select();
|
| 837 |
-
|
| 838 |
-
try {
|
| 839 |
-
document.execCommand('copy');
|
| 840 |
-
alert('TGN copied to clipboard!');
|
| 841 |
-
} catch (fallbackErr) {
|
| 842 |
-
console.error('Fallback copy failed:', fallbackErr);
|
| 843 |
-
alert('Failed to copy TGN. Please select and copy manually.');
|
| 844 |
-
} finally {
|
| 845 |
-
document.body.removeChild(textarea);
|
| 846 |
}
|
| 847 |
}
|
| 848 |
-
} catch (err) {
|
| 849 |
-
console.error('Failed to copy TGN:', err);
|
| 850 |
-
alert('Failed to copy TGN. Please select and copy manually.');
|
| 851 |
-
}
|
| 852 |
-
};
|
| 853 |
-
</script>
|
| 854 |
|
| 855 |
-
|
| 856 |
-
.
|
| 857 |
-
|
| 858 |
-
|
| 859 |
-
|
| 860 |
-
|
| 861 |
-
|
| 862 |
-
overflow: hidden;
|
| 863 |
-
|
| 864 |
-
.view-header {
|
| 865 |
-
display: flex;
|
| 866 |
-
justify-content: space-between;
|
| 867 |
-
align-items: center;
|
| 868 |
-
padding: 1rem 2rem;
|
| 869 |
-
background: linear-gradient(135deg, #505050 0%, #454545 100%);
|
| 870 |
-
border-bottom: 2px solid #606060;
|
| 871 |
-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
| 872 |
|
| 873 |
-
|
| 874 |
-
|
| 875 |
-
|
| 876 |
-
gap: 0.75rem;
|
| 877 |
|
| 878 |
-
|
| 879 |
-
|
| 880 |
-
height: 40px;
|
| 881 |
-
object-fit: contain;
|
| 882 |
-
}
|
| 883 |
|
| 884 |
-
|
| 885 |
-
|
| 886 |
-
font-weight: 700;
|
| 887 |
-
color: #e94560;
|
| 888 |
-
}
|
| 889 |
-
}
|
| 890 |
|
| 891 |
-
|
| 892 |
-
|
| 893 |
-
|
| 894 |
-
|
| 895 |
-
|
| 896 |
}
|
| 897 |
|
| 898 |
-
.
|
| 899 |
-
|
| 900 |
-
|
| 901 |
-
|
|
|
|
|
|
|
| 902 |
|
| 903 |
-
|
| 904 |
-
|
| 905 |
-
|
| 906 |
-
|
| 907 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 908 |
|
| 909 |
-
|
| 910 |
-
|
| 911 |
-
|
| 912 |
-
|
| 913 |
}
|
| 914 |
-
|
| 915 |
-
|
| 916 |
-
|
| 917 |
-
|
| 918 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 919 |
}
|
| 920 |
}
|
| 921 |
-
|
| 922 |
-
.
|
| 923 |
-
|
| 924 |
-
color: #a0a0a0;
|
| 925 |
-
}
|
| 926 |
}
|
| 927 |
-
}
|
|
|
|
| 928 |
|
| 929 |
-
|
|
|
|
| 930 |
display: flex;
|
| 931 |
-
flex:
|
|
|
|
|
|
|
|
|
|
| 932 |
overflow: hidden;
|
| 933 |
|
| 934 |
-
.
|
| 935 |
-
flex: 1;
|
| 936 |
display: flex;
|
| 937 |
-
align-items: center;
|
| 938 |
justify-content: center;
|
| 939 |
-
|
| 940 |
-
padding: 1rem;
|
| 941 |
-
|
| 942 |
-
|
| 943 |
-
|
| 944 |
-
width: 100%;
|
| 945 |
-
height: 100%;
|
| 946 |
-
position: relative;
|
| 947 |
-
border-radius: 8px;
|
| 948 |
-
overflow: hidden;
|
| 949 |
-
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
|
| 950 |
-
|
| 951 |
-
.viewport-canvas {
|
| 952 |
-
width: 100%;
|
| 953 |
-
height: 100%;
|
| 954 |
-
display: block;
|
| 955 |
-
background-color: #50505a;
|
| 956 |
-
}
|
| 957 |
-
|
| 958 |
-
.viewport-overlay {
|
| 959 |
-
position: absolute;
|
| 960 |
-
top: 0;
|
| 961 |
-
left: 0;
|
| 962 |
-
width: 100%;
|
| 963 |
-
height: 100%;
|
| 964 |
-
display: flex;
|
| 965 |
-
align-items: center;
|
| 966 |
-
justify-content: center;
|
| 967 |
-
pointer-events: none;
|
| 968 |
|
| 969 |
-
|
| 970 |
-
|
| 971 |
-
|
| 972 |
-
|
| 973 |
-
}
|
| 974 |
-
}
|
| 975 |
|
| 976 |
-
|
| 977 |
-
|
| 978 |
-
|
| 979 |
-
|
| 980 |
-
|
| 981 |
-
color: #111;
|
| 982 |
-
padding: 0.5rem 1rem;
|
| 983 |
-
border-radius: 8px;
|
| 984 |
-
font-size: 0.9rem;
|
| 985 |
-
font-weight: 600;
|
| 986 |
-
pointer-events: none;
|
| 987 |
-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
| 988 |
-
z-index: 100;
|
| 989 |
-
|
| 990 |
-
.tooltip-content {
|
| 991 |
-
display: flex;
|
| 992 |
-
align-items: center;
|
| 993 |
-
gap: 0.5rem;
|
| 994 |
|
| 995 |
-
|
| 996 |
-
|
|
|
|
|
|
|
| 997 |
}
|
| 998 |
|
| 999 |
-
|
| 1000 |
-
color: #
|
|
|
|
|
|
|
| 1001 |
}
|
| 1002 |
}
|
| 1003 |
-
}
|
| 1004 |
-
}
|
| 1005 |
-
}
|
| 1006 |
-
|
| 1007 |
-
.controls-panel {
|
| 1008 |
-
width: 320px;
|
| 1009 |
-
background-color: #3a3a3a;
|
| 1010 |
-
border-left: 2px solid #606060;
|
| 1011 |
-
display: flex;
|
| 1012 |
-
flex-direction: column;
|
| 1013 |
-
overflow: hidden;
|
| 1014 |
-
box-shadow: -4px 0 16px rgba(0, 0, 0, 0.3);
|
| 1015 |
-
|
| 1016 |
-
.panel-section {
|
| 1017 |
-
padding: 0.8rem;
|
| 1018 |
-
border-bottom: 1px solid #505050;
|
| 1019 |
-
position: relative;
|
| 1020 |
-
|
| 1021 |
-
.section-title {
|
| 1022 |
-
font-size: 0.7rem;
|
| 1023 |
-
font-weight: 600;
|
| 1024 |
-
color: #f0bcc5;
|
| 1025 |
-
text-transform: uppercase;
|
| 1026 |
-
letter-spacing: 1px;
|
| 1027 |
-
position: absolute;
|
| 1028 |
-
top: 0;
|
| 1029 |
-
left: 0.8rem;
|
| 1030 |
-
opacity: 0;
|
| 1031 |
-
transition: opacity 0.3s ease-in;
|
| 1032 |
-
}
|
| 1033 |
|
| 1034 |
-
|
| 1035 |
-
|
|
|
|
| 1036 |
}
|
| 1037 |
-
}
|
| 1038 |
|
| 1039 |
-
|
| 1040 |
-
|
| 1041 |
-
|
| 1042 |
-
|
| 1043 |
-
gap: 0.5rem;
|
| 1044 |
-
margin-bottom: 1rem;
|
| 1045 |
-
|
| 1046 |
-
.score-button {
|
| 1047 |
-
flex: 1;
|
| 1048 |
display: flex;
|
| 1049 |
align-items: center;
|
| 1050 |
-
justify-content: center;
|
| 1051 |
gap: 0.5rem;
|
| 1052 |
-
padding: 1rem;
|
| 1053 |
-
|
| 1054 |
border-radius: 8px;
|
| 1055 |
-
|
| 1056 |
-
cursor: default;
|
| 1057 |
transition: all 0.3s ease;
|
| 1058 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1059 |
&.black {
|
| 1060 |
-
|
| 1061 |
-
|
| 1062 |
-
border: 2px solid #fff;
|
| 1063 |
-
}
|
| 1064 |
}
|
| 1065 |
|
| 1066 |
&.white {
|
| 1067 |
-
|
| 1068 |
-
|
| 1069 |
-
border: 2px solid #000;
|
| 1070 |
-
}
|
| 1071 |
}
|
|
|
|
| 1072 |
|
| 1073 |
-
|
| 1074 |
-
|
| 1075 |
-
|
| 1076 |
-
border-radius: 50%;
|
| 1077 |
-
}
|
| 1078 |
|
| 1079 |
-
|
| 1080 |
-
|
| 1081 |
-
|
| 1082 |
-
color: #e0e0e0;
|
| 1083 |
}
|
| 1084 |
|
| 1085 |
-
|
| 1086 |
-
|
| 1087 |
}
|
| 1088 |
}
|
| 1089 |
-
}
|
| 1090 |
|
| 1091 |
-
|
| 1092 |
-
|
| 1093 |
-
|
| 1094 |
-
|
| 1095 |
-
|
| 1096 |
-
border: none;
|
| 1097 |
-
border-radius: 8px;
|
| 1098 |
-
font-weight: 600;
|
| 1099 |
-
cursor: pointer;
|
| 1100 |
-
transition: all 0.3s ease;
|
| 1101 |
|
| 1102 |
-
|
| 1103 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1104 |
}
|
|
|
|
| 1105 |
|
| 1106 |
-
|
| 1107 |
-
|
| 1108 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1109 |
}
|
| 1110 |
}
|
| 1111 |
|
| 1112 |
-
//
|
| 1113 |
-
&.
|
| 1114 |
-
.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1115 |
background-color: #3a3a3a;
|
| 1116 |
-
border-
|
| 1117 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1118 |
}
|
| 1119 |
}
|
| 1120 |
}
|
|
|
|
| 1121 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1122 |
|
| 1123 |
-
|
| 1124 |
-
.routine-section {
|
| 1125 |
flex: 1;
|
| 1126 |
display: flex;
|
| 1127 |
-
|
| 1128 |
-
|
|
|
|
|
|
|
|
|
|
| 1129 |
|
| 1130 |
-
.
|
| 1131 |
-
|
| 1132 |
-
|
| 1133 |
-
|
| 1134 |
border-radius: 8px;
|
| 1135 |
-
|
|
|
|
| 1136 |
|
| 1137 |
-
.
|
| 1138 |
-
|
| 1139 |
-
|
|
|
|
|
|
|
|
|
|
| 1140 |
|
| 1141 |
-
|
| 1142 |
-
|
| 1143 |
-
|
| 1144 |
-
|
| 1145 |
-
|
| 1146 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1147 |
|
| 1148 |
-
|
| 1149 |
-
|
| 1150 |
-
|
| 1151 |
-
|
| 1152 |
-
|
| 1153 |
-
|
| 1154 |
|
| 1155 |
-
|
| 1156 |
-
|
| 1157 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1158 |
|
| 1159 |
-
|
| 1160 |
-
|
| 1161 |
-
|
| 1162 |
-
|
| 1163 |
|
| 1164 |
-
|
| 1165 |
-
|
| 1166 |
-
color: #e94560;
|
| 1167 |
-
text-transform: uppercase;
|
| 1168 |
-
letter-spacing: 1px;
|
| 1169 |
-
}
|
| 1170 |
}
|
| 1171 |
|
| 1172 |
-
.
|
| 1173 |
-
color: #
|
| 1174 |
-
font-size: 0.9em;
|
| 1175 |
-
text-align: right;
|
| 1176 |
-
padding-right: 0.25rem;
|
| 1177 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1178 |
|
| 1179 |
-
|
| 1180 |
-
|
| 1181 |
-
|
| 1182 |
-
|
| 1183 |
-
|
| 1184 |
-
|
| 1185 |
-
|
| 1186 |
-
|
| 1187 |
-
background-color: #1a1a1a;
|
| 1188 |
|
| 1189 |
-
|
| 1190 |
-
|
| 1191 |
-
|
|
|
|
| 1192 |
|
| 1193 |
-
|
| 1194 |
-
|
| 1195 |
-
|
| 1196 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1197 |
|
| 1198 |
-
|
| 1199 |
-
|
| 1200 |
-
|
| 1201 |
-
|
| 1202 |
|
| 1203 |
-
|
| 1204 |
-
|
| 1205 |
-
|
| 1206 |
-
|
| 1207 |
-
|
|
|
|
| 1208 |
|
| 1209 |
-
|
| 1210 |
-
|
| 1211 |
-
|
| 1212 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1213 |
|
| 1214 |
-
|
| 1215 |
-
|
| 1216 |
-
|
| 1217 |
-
|
| 1218 |
}
|
|
|
|
| 1219 |
|
| 1220 |
-
|
| 1221 |
-
|
| 1222 |
-
|
| 1223 |
-
|
| 1224 |
}
|
|
|
|
| 1225 |
|
| 1226 |
-
|
| 1227 |
-
|
| 1228 |
-
|
| 1229 |
-
|
| 1230 |
-
text-transform: lowercase;
|
| 1231 |
-
}
|
| 1232 |
}
|
| 1233 |
-
}
|
| 1234 |
-
}
|
| 1235 |
-
}
|
| 1236 |
-
}
|
| 1237 |
|
| 1238 |
-
|
| 1239 |
-
|
| 1240 |
-
|
| 1241 |
-
|
| 1242 |
-
|
| 1243 |
|
| 1244 |
-
|
| 1245 |
-
|
| 1246 |
-
|
| 1247 |
-
|
| 1248 |
}
|
| 1249 |
|
| 1250 |
-
.
|
| 1251 |
-
|
|
|
|
|
|
|
|
|
|
| 1252 |
border: none;
|
| 1253 |
border-radius: 8px;
|
| 1254 |
font-weight: 600;
|
| 1255 |
cursor: pointer;
|
| 1256 |
transition: all 0.3s ease;
|
| 1257 |
-
|
|
|
|
|
|
|
|
|
|
| 1258 |
|
| 1259 |
&:disabled {
|
| 1260 |
opacity: 0.5;
|
| 1261 |
cursor: not-allowed;
|
| 1262 |
}
|
|
|
|
| 1263 |
|
| 1264 |
-
|
| 1265 |
-
|
| 1266 |
-
|
| 1267 |
-
|
| 1268 |
-
|
| 1269 |
-
|
| 1270 |
-
}
|
| 1271 |
}
|
|
|
|
|
|
|
| 1272 |
|
| 1273 |
-
|
| 1274 |
-
|
| 1275 |
-
|
|
|
|
|
|
|
| 1276 |
|
| 1277 |
-
|
| 1278 |
-
|
| 1279 |
-
|
| 1280 |
-
|
|
|
|
|
|
|
| 1281 |
|
| 1282 |
-
|
| 1283 |
-
|
| 1284 |
-
|
| 1285 |
-
|
| 1286 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1287 |
|
| 1288 |
-
|
| 1289 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1290 |
}
|
| 1291 |
}
|
| 1292 |
}
|
| 1293 |
}
|
| 1294 |
-
}
|
| 1295 |
-
|
| 1296 |
-
.settings-section {
|
| 1297 |
-
.settings-content {
|
| 1298 |
-
display: flex;
|
| 1299 |
-
flex-direction: column;
|
| 1300 |
-
gap: 1rem;
|
| 1301 |
|
| 1302 |
-
|
|
|
|
| 1303 |
display: flex;
|
| 1304 |
-
|
| 1305 |
-
|
| 1306 |
|
| 1307 |
-
|
| 1308 |
-
|
| 1309 |
-
color: #a0a0a0;
|
| 1310 |
display: flex;
|
| 1311 |
-
|
| 1312 |
-
gap: 0.3rem;
|
| 1313 |
-
|
| 1314 |
-
.dirty-indicator {
|
| 1315 |
-
color: #e94560;
|
| 1316 |
-
font-size: 1.2rem;
|
| 1317 |
-
font-weight: 700;
|
| 1318 |
-
animation: pulse 2s ease-in-out infinite;
|
| 1319 |
-
}
|
| 1320 |
}
|
| 1321 |
|
| 1322 |
-
|
| 1323 |
-
padding: 0.5rem;
|
| 1324 |
-
border:
|
| 1325 |
border-radius: 8px;
|
| 1326 |
-
background-color: #484848;
|
| 1327 |
-
color: #e0e0e0;
|
| 1328 |
-
cursor: pointer;
|
| 1329 |
font-weight: 600;
|
|
|
|
|
|
|
|
|
|
| 1330 |
|
| 1331 |
&:disabled {
|
| 1332 |
opacity: 0.5;
|
| 1333 |
cursor: not-allowed;
|
| 1334 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1335 |
}
|
| 1336 |
}
|
|
|
|
| 1337 |
|
| 1338 |
-
|
| 1339 |
-
|
| 1340 |
-
|
| 1341 |
-
|
| 1342 |
-
|
| 1343 |
-
border: none;
|
| 1344 |
-
border-radius: 8px;
|
| 1345 |
-
font-weight: 700;
|
| 1346 |
-
cursor: pointer;
|
| 1347 |
-
transition: all 0.3s ease;
|
| 1348 |
-
text-transform: uppercase;
|
| 1349 |
|
| 1350 |
-
|
| 1351 |
-
|
| 1352 |
-
|
| 1353 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1354 |
}
|
| 1355 |
}
|
| 1356 |
}
|
| 1357 |
}
|
| 1358 |
}
|
| 1359 |
}
|
| 1360 |
-
|
| 1361 |
-
|
| 1362 |
-
|
| 1363 |
-
|
| 1364 |
-
|
| 1365 |
-
|
| 1366 |
-
|
| 1367 |
-
|
| 1368 |
-
|
| 1369 |
-
|
| 1370 |
-
|
| 1371 |
-
|
| 1372 |
-
|
| 1373 |
-
|
| 1374 |
-
|
| 1375 |
-
|
| 1376 |
-
|
| 1377 |
-
|
| 1378 |
-
|
| 1379 |
-
|
| 1380 |
-
|
| 1381 |
-
|
| 1382 |
-
|
| 1383 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1384 |
}
|
| 1385 |
-
|
| 1386 |
-
|
| 1387 |
-
|
| 1388 |
-
|
| 1389 |
-
|
| 1390 |
-
|
| 1391 |
-
|
| 1392 |
-
|
| 1393 |
-
top: 0;
|
| 1394 |
-
left: 0;
|
| 1395 |
-
width: 100vw;
|
| 1396 |
-
height: 100vh;
|
| 1397 |
-
background-color: rgba(0, 0, 0, 0.7);
|
| 1398 |
-
display: flex;
|
| 1399 |
-
align-items: center;
|
| 1400 |
-
justify-content: center;
|
| 1401 |
-
z-index: 1000;
|
| 1402 |
-
backdrop-filter: blur(4px);
|
| 1403 |
-
|
| 1404 |
-
.tgn-modal-content {
|
| 1405 |
-
background-color: #3a3a3a;
|
| 1406 |
-
border-radius: 12px;
|
| 1407 |
-
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
|
| 1408 |
-
width: 90%;
|
| 1409 |
-
max-width: 600px;
|
| 1410 |
-
max-height: 80vh;
|
| 1411 |
display: flex;
|
| 1412 |
-
|
| 1413 |
-
|
|
|
|
|
|
|
| 1414 |
|
| 1415 |
-
.tgn-modal-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1416 |
display: flex;
|
| 1417 |
-
|
| 1418 |
-
|
| 1419 |
-
padding: 1rem 1.5rem;
|
| 1420 |
-
background-color: #2a2a2a;
|
| 1421 |
-
border-bottom: 1px solid #505050;
|
| 1422 |
-
|
| 1423 |
-
h3 {
|
| 1424 |
-
margin: 0;
|
| 1425 |
-
font-size: 1.2rem;
|
| 1426 |
-
font-weight: 600;
|
| 1427 |
-
color: #e0e0e0;
|
| 1428 |
-
}
|
| 1429 |
|
| 1430 |
-
.tgn-
|
| 1431 |
-
|
| 1432 |
-
|
| 1433 |
-
|
| 1434 |
-
|
| 1435 |
-
|
| 1436 |
-
|
| 1437 |
|
| 1438 |
-
|
| 1439 |
-
|
| 1440 |
-
|
|
|
|
|
|
|
| 1441 |
}
|
| 1442 |
|
| 1443 |
-
|
| 1444 |
-
|
| 1445 |
-
|
| 1446 |
-
|
| 1447 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1448 |
|
| 1449 |
-
|
| 1450 |
-
|
| 1451 |
-
|
| 1452 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1453 |
}
|
| 1454 |
-
}
|
| 1455 |
|
| 1456 |
-
|
| 1457 |
-
|
| 1458 |
-
|
| 1459 |
-
|
| 1460 |
-
|
| 1461 |
-
|
| 1462 |
-
|
| 1463 |
-
|
| 1464 |
-
|
| 1465 |
-
|
| 1466 |
-
|
| 1467 |
-
|
| 1468 |
-
|
| 1469 |
-
|
| 1470 |
|
| 1471 |
-
|
| 1472 |
-
|
| 1473 |
-
|
|
|
|
| 1474 |
}
|
| 1475 |
}
|
| 1476 |
-
}
|
| 1477 |
|
| 1478 |
-
|
| 1479 |
-
|
| 1480 |
-
|
| 1481 |
-
|
| 1482 |
|
| 1483 |
-
|
| 1484 |
-
|
| 1485 |
-
|
| 1486 |
-
|
| 1487 |
-
|
| 1488 |
-
|
| 1489 |
-
|
| 1490 |
-
|
| 1491 |
-
|
| 1492 |
-
|
| 1493 |
-
|
| 1494 |
-
|
| 1495 |
-
|
| 1496 |
-
|
| 1497 |
-
|
| 1498 |
-
|
| 1499 |
-
|
| 1500 |
-
|
| 1501 |
-
|
| 1502 |
-
|
|
|
|
|
|
|
| 1503 |
|
| 1504 |
-
|
| 1505 |
-
|
| 1506 |
-
|
| 1507 |
-
|
| 1508 |
|
| 1509 |
-
|
| 1510 |
-
|
| 1511 |
-
|
| 1512 |
-
|
| 1513 |
|
| 1514 |
-
|
| 1515 |
-
|
|
|
|
| 1516 |
}
|
| 1517 |
}
|
| 1518 |
-
}
|
| 1519 |
|
| 1520 |
-
|
| 1521 |
-
|
| 1522 |
-
|
| 1523 |
-
|
| 1524 |
-
|
| 1525 |
-
|
| 1526 |
|
| 1527 |
-
|
| 1528 |
-
|
| 1529 |
-
|
| 1530 |
-
|
| 1531 |
-
|
| 1532 |
-
|
| 1533 |
-
|
| 1534 |
-
|
| 1535 |
-
|
| 1536 |
-
&:disabled {
|
| 1537 |
-
opacity: 0.5;
|
| 1538 |
-
cursor: not-allowed;
|
| 1539 |
-
}
|
| 1540 |
|
| 1541 |
-
|
| 1542 |
-
|
| 1543 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1544 |
|
| 1545 |
-
|
| 1546 |
-
|
| 1547 |
-
|
| 1548 |
-
|
|
|
|
| 1549 |
}
|
| 1550 |
-
}
|
| 1551 |
|
| 1552 |
-
|
| 1553 |
-
|
| 1554 |
-
|
| 1555 |
|
| 1556 |
-
|
| 1557 |
-
|
| 1558 |
-
|
| 1559 |
-
|
|
|
|
| 1560 |
}
|
| 1561 |
-
}
|
| 1562 |
|
| 1563 |
-
|
| 1564 |
-
|
| 1565 |
-
|
| 1566 |
|
| 1567 |
-
|
| 1568 |
-
|
|
|
|
| 1569 |
}
|
| 1570 |
}
|
| 1571 |
}
|
| 1572 |
}
|
| 1573 |
}
|
| 1574 |
-
}
|
| 1575 |
|
| 1576 |
-
@keyframes pulse {
|
| 1577 |
-
|
| 1578 |
-
|
| 1579 |
-
|
| 1580 |
-
|
| 1581 |
-
|
| 1582 |
-
|
|
|
|
| 1583 |
}
|
| 1584 |
-
}
|
| 1585 |
|
| 1586 |
-
/* Scrollbar styling */
|
| 1587 |
-
.controls-panel {
|
| 1588 |
-
|
| 1589 |
-
|
| 1590 |
-
|
| 1591 |
|
| 1592 |
-
|
| 1593 |
-
|
| 1594 |
-
|
| 1595 |
|
| 1596 |
-
|
| 1597 |
-
|
| 1598 |
-
|
| 1599 |
|
| 1600 |
-
|
| 1601 |
-
|
|
|
|
| 1602 |
}
|
| 1603 |
}
|
| 1604 |
-
}
|
| 1605 |
|
| 1606 |
-
.routine-content {
|
| 1607 |
-
|
| 1608 |
-
|
| 1609 |
-
|
| 1610 |
|
| 1611 |
-
|
| 1612 |
-
|
| 1613 |
-
|
| 1614 |
|
| 1615 |
-
|
| 1616 |
-
|
| 1617 |
-
|
| 1618 |
|
| 1619 |
-
|
| 1620 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1621 |
}
|
| 1622 |
}
|
| 1623 |
-
}
|
| 1624 |
</style>
|
|
|
|
| 1 |
<template>
|
| 2 |
<div class="trigo-view">
|
| 3 |
<div class="view-header">
|
| 4 |
+
<!-- Single Game Mode: Current Player & Move Count -->
|
| 5 |
+
<div v-if="gameMode === 'single'" class="view-status">
|
| 6 |
+
<span
|
| 7 |
+
class="turn-indicator"
|
| 8 |
+
:class="{ black: currentPlayer === 'black', white: currentPlayer === 'white' }"
|
| 9 |
+
>
|
| 10 |
{{ currentPlayer === "black" ? "Black" : "White" }}'s Turn
|
| 11 |
</span>
|
| 12 |
<span class="move-count">Move: {{ moveCount }}</span>
|
| 13 |
</div>
|
| 14 |
+
|
| 15 |
+
<!-- VS AI Mode: Player Info & AI Status -->
|
| 16 |
+
<div v-else-if="gameMode === 'vs-ai'" class="view-status ai-mode">
|
| 17 |
+
<div class="player-info" :class="{ 'on-turn': currentPlayer === humanPlayerColor }">
|
| 18 |
+
<span class="player-label">You:</span>
|
| 19 |
+
<span
|
| 20 |
+
class="stone-icon"
|
| 21 |
+
:class="humanPlayerColor === 'black' ? 'black' : 'white'"
|
| 22 |
+
></span>
|
| 23 |
+
</div>
|
| 24 |
+
<button class="btn-swap-colors" @click="swapColors">⇄ Swap</button>
|
| 25 |
+
<div class="ai-status" :class="{ 'on-turn': currentPlayer === aiPlayerColor && !aiThinking }">
|
| 26 |
+
<span class="ai-indicator">🤖 AI:</span>
|
| 27 |
+
<span v-if="!aiReady" class="ai-level">Loading...</span>
|
| 28 |
+
<span v-else-if="aiThinking" class="ai-level ai-thinking">Thinking...</span>
|
| 29 |
+
<span v-else-if="aiError" class="ai-level ai-error">Error</span>
|
| 30 |
+
<span
|
| 31 |
+
v-else
|
| 32 |
+
class="stone-icon"
|
| 33 |
+
:class="aiPlayerColor === 'black' ? 'black' : 'white'"
|
| 34 |
+
></span>
|
| 35 |
+
</div>
|
| 36 |
+
<span class="move-count">Move: {{ moveCount }}</span>
|
| 37 |
+
<span v-if="lastMoveTime > 0" class="ai-time">({{ lastMoveTime.toFixed(0) }}ms)</span>
|
| 38 |
+
</div>
|
| 39 |
+
|
| 40 |
+
<!-- VS People Mode: Room & Players -->
|
| 41 |
+
<div v-else-if="gameMode === 'vs-people'" class="view-status people-mode">
|
| 42 |
+
<div class="room-info">
|
| 43 |
+
<span class="room-label">Room:</span>
|
| 44 |
+
<span class="room-code">ABC123</span>
|
| 45 |
+
</div>
|
| 46 |
+
<div class="players-info">
|
| 47 |
+
<span class="player-name">You (Black)</span>
|
| 48 |
+
<span class="vs-divider">vs</span>
|
| 49 |
+
<span class="player-name">Waiting...</span>
|
| 50 |
+
</div>
|
| 51 |
+
<span class="connection-status connected">🟢 Connected</span>
|
| 52 |
+
</div>
|
| 53 |
+
|
| 54 |
+
<!-- Library Mode: Game Info & Controls -->
|
| 55 |
+
<div v-else-if="gameMode === 'library'" class="view-status library-mode">
|
| 56 |
+
<div class="game-info">
|
| 57 |
+
<span class="game-title">Game #12345</span>
|
| 58 |
+
<span class="game-date">2025-01-18</span>
|
| 59 |
+
</div>
|
| 60 |
+
<div class="library-actions">
|
| 61 |
+
<button class="btn-library btn-load" title="Load Game">📂 Load</button>
|
| 62 |
+
<button class="btn-library btn-export" title="Export TGN">📤 Export</button>
|
| 63 |
+
</div>
|
| 64 |
+
</div>
|
| 65 |
</div>
|
| 66 |
|
| 67 |
<div class="view-body">
|
|
|
|
| 75 |
<!-- Inspect Mode Tooltip -->
|
| 76 |
<div class="inspect-tooltip" v-if="inspectInfo.visible">
|
| 77 |
<div class="tooltip-content">
|
| 78 |
+
<span class="tooltip-label"
|
| 79 |
+
>{{ inspectInfo.groupSize }} stone{{
|
| 80 |
+
inspectInfo.groupSize > 1 ? "s" : ""
|
| 81 |
+
}}</span
|
| 82 |
+
>
|
| 83 |
<span class="tooltip-divider">|</span>
|
| 84 |
+
<span class="tooltip-label"
|
| 85 |
+
>Liberties: {{ inspectInfo.liberties }}</span
|
| 86 |
+
>
|
| 87 |
</div>
|
| 88 |
</div>
|
| 89 |
</div>
|
|
|
|
| 92 |
<!-- Game Controls & Info Panel (Right) -->
|
| 93 |
<div class="controls-panel">
|
| 94 |
<!-- Score Display (Captured/Territory) -->
|
| 95 |
+
<div
|
| 96 |
+
class="panel-section score-section"
|
| 97 |
+
:class="{ 'show-territory': showTerritoryMode }"
|
| 98 |
+
>
|
| 99 |
+
<h3 class="section-title">
|
| 100 |
+
{{ showTerritoryMode ? "Territory" : "Captured" }}
|
| 101 |
+
</h3>
|
| 102 |
<div class="score-display">
|
| 103 |
<button class="score-button black" :disabled="!gameStarted">
|
| 104 |
<span class="color-indicator black-stone"></span>
|
| 105 |
+
<span class="score">{{
|
| 106 |
+
showTerritoryMode ? blackScore : capturedStones.black
|
| 107 |
+
}}</span>
|
| 108 |
</button>
|
| 109 |
<button class="score-button white" :disabled="!gameStarted">
|
| 110 |
<span class="color-indicator white-stone"></span>
|
| 111 |
+
<span class="score">{{
|
| 112 |
+
showTerritoryMode ? whiteScore : capturedStones.white
|
| 113 |
+
}}</span>
|
| 114 |
</button>
|
| 115 |
</div>
|
| 116 |
+
<button
|
| 117 |
+
class="compute-territory"
|
| 118 |
+
@click="computeTerritory"
|
| 119 |
+
:disabled="!gameStarted"
|
| 120 |
+
>
|
| 121 |
Compute Territory
|
| 122 |
</button>
|
| 123 |
</div>
|
|
|
|
| 126 |
<div class="panel-section routine-section">
|
| 127 |
<h3 class="section-title">
|
| 128 |
Move History
|
| 129 |
+
<button
|
| 130 |
+
class="btn-view-tgn"
|
| 131 |
+
@click="showTGNModal = true"
|
| 132 |
+
title="View TGN Notation"
|
| 133 |
+
>
|
| 134 |
TGN
|
| 135 |
</button>
|
| 136 |
</h3>
|
|
|
|
| 158 |
@click="jumpToMove(round.blackIndex)"
|
| 159 |
>
|
| 160 |
<span class="stone-icon black"></span>
|
| 161 |
+
<span class="move-coords" v-if="!round.black.isPass">{{
|
| 162 |
+
formatMoveCoords(round.black)
|
| 163 |
+
}}</span>
|
| 164 |
<span class="move-label" v-else>pass</span>
|
| 165 |
</div>
|
| 166 |
<div
|
|
|
|
| 170 |
@click="jumpToMove(round.whiteIndex)"
|
| 171 |
>
|
| 172 |
<span class="stone-icon white"></span>
|
| 173 |
+
<span class="move-coords" v-if="!round.white.isPass">{{
|
| 174 |
+
formatMoveCoords(round.white)
|
| 175 |
+
}}</span>
|
| 176 |
<span class="move-label" v-else>pass</span>
|
| 177 |
</div>
|
| 178 |
<div v-else class="move-cell empty"></div>
|
|
|
|
| 221 |
<div class="setting-item">
|
| 222 |
<label for="board-shape">
|
| 223 |
Board Shape:
|
| 224 |
+
<span
|
| 225 |
+
v-if="isBoardShapeDirty"
|
| 226 |
+
class="dirty-indicator"
|
| 227 |
+
title="Board shape will change on next game"
|
| 228 |
+
>*</span
|
| 229 |
+
>
|
| 230 |
</label>
|
| 231 |
<select id="board-shape" v-model="selectedBoardShape">
|
| 232 |
<option value="3*3*3">3×3×3</option>
|
|
|
|
| 277 |
</template>
|
| 278 |
|
| 279 |
<script setup lang="ts">
|
| 280 |
+
import { ref, onMounted, onUnmounted, watch, computed, nextTick } from "vue";
|
| 281 |
+
import { useRoute } from "vue-router";
|
| 282 |
+
import { TrigoViewport } from "@/services/trigoViewport";
|
| 283 |
+
import { useGameStore } from "@/stores/gameStore";
|
| 284 |
+
import { useTrigoAgent } from "@/composables/useTrigoAgent";
|
| 285 |
+
import { storeToRefs } from "pinia";
|
| 286 |
+
import type { BoardShape } from "../../../inc/trigo";
|
| 287 |
+
import { Stone, validateMove, StoneType, validateTGN } from "../../../inc/trigo";
|
| 288 |
+
import { TrigoGameFrontend } from "@/utils/TrigoGameFrontend";
|
| 289 |
+
import { encodeAb0yz } from "../../../inc/trigo/ab0yz";
|
| 290 |
+
import { storage, StorageKey } from "@/utils/storage";
|
| 291 |
+
|
| 292 |
+
// Get current route to determine game mode
|
| 293 |
+
const route = useRoute();
|
| 294 |
+
const gameMode = computed(() => (route.meta.mode as string) || "single");
|
| 295 |
+
|
| 296 |
+
// Helper functions for board shape parsing
|
| 297 |
+
const parseBoardShape = (shapeStr: string): BoardShape => {
|
| 298 |
+
const parts = shapeStr
|
| 299 |
+
.split(/[^\d]+/)
|
| 300 |
+
.filter(Boolean)
|
| 301 |
+
.map(Number);
|
| 302 |
+
return { x: parts[0] || 5, y: parts[1] || 5, z: parts[2] || 5 };
|
| 303 |
+
};
|
| 304 |
+
|
| 305 |
+
const printBoardShape = (shape: BoardShape): string => {
|
| 306 |
+
return `${shape.x}*${shape.y}*${shape.z}`;
|
| 307 |
+
};
|
| 308 |
+
|
| 309 |
+
// Format move coordinates using TGN notation
|
| 310 |
+
const formatMoveCoords = (move: { x: number; y: number; z: number }): string => {
|
| 311 |
+
const shape = boardShape.value;
|
| 312 |
+
return encodeAb0yz([move.x, move.y, move.z], [shape.x, shape.y, shape.z]);
|
| 313 |
+
};
|
| 314 |
+
|
| 315 |
+
// Use game store
|
| 316 |
+
const gameStore = useGameStore();
|
| 317 |
+
const {
|
| 318 |
+
currentPlayer,
|
| 319 |
+
moveHistory,
|
| 320 |
+
currentMoveIndex,
|
| 321 |
+
capturedStones,
|
| 322 |
+
gameStatus,
|
| 323 |
+
boardShape,
|
| 324 |
+
moveCount,
|
| 325 |
+
isGameActive,
|
| 326 |
+
passCount
|
| 327 |
+
} = storeToRefs(gameStore);
|
| 328 |
+
|
| 329 |
+
|
| 330 |
+
// AI Agent (for VS AI mode)
|
| 331 |
+
const aiAgent = useTrigoAgent();
|
| 332 |
+
const { isReady: aiReady, isThinking: aiThinking, error: aiError, lastMoveTime } = aiAgent;
|
| 333 |
+
|
| 334 |
+
// AI player color with session storage persistence
|
| 335 |
+
const loadAIColor = (): "black" | "white" => {
|
| 336 |
+
const stored = storage.getString(StorageKey.AI_PLAYER_COLOR);
|
| 337 |
+
return stored === "black" || stored === "white" ? stored : "white";
|
| 338 |
+
};
|
| 339 |
+
|
| 340 |
+
const aiPlayerColor = ref<"black" | "white">(loadAIColor());
|
| 341 |
+
const humanPlayerColor = computed(() => (aiPlayerColor.value === "white" ? "black" : "white"));
|
| 342 |
+
|
| 343 |
+
// Local state
|
| 344 |
+
const hoveredPosition = ref<string | null>(null);
|
| 345 |
+
const blackScore = ref(0);
|
| 346 |
+
const whiteScore = ref(0);
|
| 347 |
+
const isLoading = ref(true);
|
| 348 |
+
const selectedBoardShape = ref<string>(printBoardShape(boardShape.value));
|
| 349 |
+
const showTerritoryMode = ref(false);
|
| 350 |
+
const showTGNModal = ref(false);
|
| 351 |
+
const inspectInfo = ref({
|
| 352 |
+
visible: false,
|
| 353 |
+
groupSize: 0,
|
| 354 |
+
liberties: 0
|
| 355 |
+
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 356 |
|
| 357 |
+
// TGN Editor state
|
| 358 |
+
const editableTGNContent = ref<string>("");
|
| 359 |
+
const tgnValidationState = ref<"idle" | "valid" | "invalid">("idle");
|
| 360 |
+
const tgnValidationError = ref<string>("");
|
| 361 |
+
let tgnValidationTimeout: ReturnType<typeof setTimeout> | null = null;
|
| 362 |
+
|
| 363 |
+
// Canvas reference and viewport
|
| 364 |
+
const viewportCanvas = ref<HTMLCanvasElement | null>(null);
|
| 365 |
+
const moveHistoryContainer = ref<HTMLDivElement | null>(null);
|
| 366 |
+
let viewport: TrigoViewport | null = null;
|
| 367 |
+
let resizeObserver: ResizeObserver | null = null;
|
| 368 |
+
|
| 369 |
+
// Computed properties
|
| 370 |
+
const gameStarted = computed(() => isGameActive.value);
|
| 371 |
+
|
| 372 |
+
// Group moves into rounds (pairs of black and white moves)
|
| 373 |
+
const moveRounds = computed(() => {
|
| 374 |
+
const rounds: Array<{
|
| 375 |
+
black: any;
|
| 376 |
+
white: any | null;
|
| 377 |
+
blackIndex: number;
|
| 378 |
+
whiteIndex: number | null;
|
| 379 |
+
}> = [];
|
| 380 |
+
|
| 381 |
+
for (let i = 0; i < moveHistory.value.length; i += 2) {
|
| 382 |
+
const blackMove = moveHistory.value[i];
|
| 383 |
+
const whiteMove = moveHistory.value[i + 1] || null;
|
| 384 |
+
|
| 385 |
+
rounds.push({
|
| 386 |
+
black: blackMove,
|
| 387 |
+
white: whiteMove,
|
| 388 |
+
blackIndex: i + 1, // Convert array index to "moves applied" count
|
| 389 |
+
whiteIndex: whiteMove ? i + 2 : null // Convert array index to "moves applied" count
|
| 390 |
+
});
|
| 391 |
+
}
|
| 392 |
|
| 393 |
+
return rounds;
|
| 394 |
+
});
|
|
|
|
| 395 |
|
| 396 |
+
// Check if selected board shape differs from current game board shape
|
| 397 |
+
const isBoardShapeDirty = computed(() => {
|
| 398 |
+
const selectedShape = parseBoardShape(selectedBoardShape.value);
|
| 399 |
+
const currentShape = boardShape.value;
|
| 400 |
+
return (
|
| 401 |
+
selectedShape.x !== currentShape.x ||
|
| 402 |
+
selectedShape.y !== currentShape.y ||
|
| 403 |
+
selectedShape.z !== currentShape.z
|
| 404 |
+
);
|
| 405 |
+
});
|
| 406 |
|
| 407 |
+
// Generate TGN content
|
| 408 |
+
const tgnContent = computed(() => {
|
| 409 |
+
return (
|
| 410 |
+
gameStore.game?.toTGN({
|
| 411 |
+
application: "Trigo Demo v1.0",
|
| 412 |
+
date: new Date().toISOString().split("T")[0].replace(/-/g, ".")
|
| 413 |
+
}) || ""
|
| 414 |
+
);
|
| 415 |
+
});
|
| 416 |
|
| 417 |
+
// TGN validation computed properties
|
| 418 |
+
const tgnIsValid = computed(() => tgnValidationState.value === "valid");
|
| 419 |
|
| 420 |
+
const tgnValidationClass = computed(() => {
|
| 421 |
+
if (tgnValidationState.value === "idle") return "idle";
|
| 422 |
+
if (tgnValidationState.value === "valid") return "valid";
|
| 423 |
+
return "invalid";
|
| 424 |
+
});
|
| 425 |
|
| 426 |
+
const tgnValidationMessage = computed(() => {
|
| 427 |
+
if (tgnValidationState.value === "idle") return "Ready to validate";
|
| 428 |
+
if (tgnValidationState.value === "valid") return "✓ Valid TGN";
|
| 429 |
+
return `✗ ${tgnValidationError.value}`;
|
| 430 |
+
});
|
| 431 |
|
| 432 |
+
// Debounced TGN validation (synchronous)
|
| 433 |
+
const onTGNEdit = () => {
|
| 434 |
+
// Clear existing timeout
|
| 435 |
+
if (tgnValidationTimeout) {
|
| 436 |
+
clearTimeout(tgnValidationTimeout);
|
| 437 |
}
|
| 438 |
|
| 439 |
+
// Set validation state to idle while waiting for debounce
|
| 440 |
+
tgnValidationState.value = "idle";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 441 |
|
| 442 |
+
// Set new debounce timeout (300ms)
|
| 443 |
+
tgnValidationTimeout = setTimeout(() => {
|
| 444 |
+
const result = validateTGN(editableTGNContent.value);
|
|
|
|
| 445 |
|
| 446 |
+
if (result.valid) {
|
| 447 |
+
tgnValidationState.value = "valid";
|
| 448 |
+
tgnValidationError.value = "";
|
| 449 |
+
} else {
|
| 450 |
+
tgnValidationState.value = "invalid";
|
| 451 |
+
tgnValidationError.value = result.error || "Invalid TGN format";
|
| 452 |
+
}
|
| 453 |
+
}, 300);
|
| 454 |
+
};
|
| 455 |
|
| 456 |
+
// Apply TGN and update game state (synchronous)
|
| 457 |
+
const applyTGN = () => {
|
| 458 |
+
if (!tgnIsValid.value) return;
|
|
|
|
| 459 |
|
| 460 |
+
try {
|
| 461 |
+
const newGame = TrigoGameFrontend.fromTGN(editableTGNContent.value);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 462 |
|
| 463 |
+
// Update game store with the new TrigoGameFrontend instance
|
| 464 |
+
gameStore.game = newGame;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 465 |
|
| 466 |
+
// Save to session storage
|
| 467 |
+
gameStore.saveToSessionStorage();
|
| 468 |
|
| 469 |
+
// Update viewport with new board state
|
| 470 |
+
// The getters will automatically compute the new values from gameStore.game
|
| 471 |
+
if (viewport) {
|
| 472 |
+
viewport.setBoardShape(newGame.getShape());
|
| 473 |
+
syncViewportWithStore();
|
| 474 |
+
}
|
| 475 |
|
| 476 |
+
// Close modal
|
| 477 |
+
showTGNModal.value = false;
|
| 478 |
+
} catch (err) {
|
| 479 |
+
console.error("Failed to apply TGN:", err);
|
| 480 |
+
tgnValidationState.value = "invalid";
|
| 481 |
+
tgnValidationError.value = err instanceof Error ? err.message : "Failed to apply TGN";
|
| 482 |
+
}
|
| 483 |
+
};
|
| 484 |
|
| 485 |
|
| 486 |
+
// Generate and apply AI move
|
| 487 |
+
const generateAIMove = async () => {
|
| 488 |
+
if (!aiReady.value || aiThinking.value || !gameStarted.value) {
|
| 489 |
+
return;
|
| 490 |
+
}
|
| 491 |
|
| 492 |
+
try {
|
| 493 |
+
console.log("[TrigoView] Generating AI move...");
|
|
|
|
| 494 |
|
| 495 |
+
// Get AI move - pass the game instance directly from store
|
| 496 |
+
const aiMove = await aiAgent.generateMove(gameStore.game);
|
|
|
|
|
|
|
|
|
|
| 497 |
|
| 498 |
+
// Apply AI move if valid
|
| 499 |
+
if (aiMove) {
|
| 500 |
+
console.log(`[TrigoView] AI suggests move at (${aiMove.x}, ${aiMove.y}, ${aiMove.z})`);
|
| 501 |
|
| 502 |
+
// Make move in store
|
| 503 |
+
const result = gameStore.makeMove(aiMove.x, aiMove.y, aiMove.z);
|
|
|
|
|
|
|
| 504 |
|
| 505 |
+
if (result.success && viewport) {
|
| 506 |
+
// Add AI stone to viewport
|
| 507 |
+
const stoneColor = gameStore.opponentPlayer;
|
| 508 |
+
viewport.addStone(aiMove.x, aiMove.y, aiMove.z, stoneColor);
|
| 509 |
|
| 510 |
+
// Remove captured stones
|
| 511 |
+
if (result.capturedPositions && result.capturedPositions.length > 0) {
|
| 512 |
+
result.capturedPositions.forEach((pos: any) => {
|
| 513 |
+
viewport.removeStone(pos.x, pos.y, pos.z);
|
| 514 |
+
});
|
| 515 |
+
console.log(`[TrigoView] AI captured ${result.capturedPositions.length} stone(s)`);
|
| 516 |
+
}
|
| 517 |
+
|
| 518 |
+
console.log(`[TrigoView] AI move applied successfully (${lastMoveTime.value.toFixed(0)}ms)`);
|
| 519 |
+
}
|
| 520 |
+
} else {
|
| 521 |
+
console.log("[TrigoView] AI chose to pass");
|
| 522 |
+
// Handle AI pass if needed
|
| 523 |
+
}
|
| 524 |
+
} catch (err) {
|
| 525 |
+
console.error("[TrigoView] Failed to generate AI move:", err);
|
| 526 |
+
}
|
| 527 |
+
};
|
| 528 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 529 |
|
| 530 |
+
// Handle stone placement
|
| 531 |
+
const handleStoneClick = async (x: number, y: number, z: number) => {
|
| 532 |
+
if (!gameStarted.value) return;
|
| 533 |
|
| 534 |
+
// Make move in store
|
| 535 |
+
const result = gameStore.makeMove(x, y, z);
|
|
|
|
|
|
|
|
|
|
| 536 |
|
| 537 |
+
if (result.success && viewport) {
|
| 538 |
+
// Add stone to viewport (store already switched player, so use opponent)
|
| 539 |
+
const stoneColor = gameStore.opponentPlayer;
|
| 540 |
+
viewport.addStone(x, y, z, stoneColor);
|
| 541 |
+
|
| 542 |
+
// Remove captured stones from viewport
|
| 543 |
+
if (result.capturedPositions && result.capturedPositions.length > 0) {
|
| 544 |
+
result.capturedPositions.forEach((pos) => {
|
| 545 |
+
viewport.removeStone(pos.x, pos.y, pos.z);
|
| 546 |
+
});
|
| 547 |
+
console.log(`Captured ${result.capturedPositions.length} stone(s)`);
|
| 548 |
+
}
|
| 549 |
|
| 550 |
+
// Hide domain visualization and switch back to captured display after move
|
| 551 |
+
viewport.hideDomainCubes();
|
| 552 |
+
showTerritoryMode.value = false;
|
| 553 |
|
| 554 |
+
// VS AI mode: Generate AI move after player move if it's AI's turn
|
| 555 |
+
if (gameMode.value === "vs-ai" && aiReady.value && currentPlayer.value === aiPlayerColor.value) {
|
| 556 |
+
setTimeout(() => {
|
| 557 |
+
generateAIMove();
|
| 558 |
+
}, 100);
|
| 559 |
+
}
|
| 560 |
+
}
|
| 561 |
+
};
|
| 562 |
|
| 563 |
+
// Handle position hover
|
| 564 |
+
const handlePositionHover = (x: number | null, y: number | null, z: number | null) => {
|
| 565 |
+
if (x !== null && y !== null && z !== null) {
|
| 566 |
+
hoveredPosition.value = `(${x}, ${y}, ${z})`;
|
| 567 |
+
} else {
|
| 568 |
+
hoveredPosition.value = null;
|
| 569 |
+
}
|
| 570 |
+
};
|
| 571 |
+
|
| 572 |
+
// Check if a position is droppable (validates with game rules)
|
| 573 |
+
const isPositionDroppable = (x: number, y: number, z: number): boolean => {
|
| 574 |
+
const pos = { x, y, z };
|
| 575 |
+
const playerColor = currentPlayer.value === "black" ? StoneType.BLACK : StoneType.WHITE;
|
| 576 |
+
|
| 577 |
+
const validation = validateMove(
|
| 578 |
+
pos,
|
| 579 |
+
playerColor,
|
| 580 |
+
gameStore.board,
|
| 581 |
+
boardShape.value,
|
| 582 |
+
gameStore.lastCapturedPositions
|
| 583 |
+
);
|
| 584 |
+
|
| 585 |
+
return validation.valid;
|
| 586 |
+
};
|
| 587 |
+
|
| 588 |
+
// Handle inspect mode callback
|
| 589 |
+
const handleInspectGroup = (groupSize: number, liberties: number) => {
|
| 590 |
+
if (groupSize > 0) {
|
| 591 |
+
inspectInfo.value = {
|
| 592 |
+
visible: true,
|
| 593 |
+
groupSize,
|
| 594 |
+
liberties
|
| 595 |
+
};
|
| 596 |
+
} else {
|
| 597 |
+
inspectInfo.value = {
|
| 598 |
+
visible: false,
|
| 599 |
+
groupSize: 0,
|
| 600 |
+
liberties: 0
|
| 601 |
+
};
|
| 602 |
+
}
|
| 603 |
+
};
|
| 604 |
|
|
|
|
|
|
|
|
|
|
| 605 |
|
| 606 |
+
// Swap AI player color
|
| 607 |
+
const swapColors = () => {
|
| 608 |
+
// Swap the color
|
| 609 |
+
aiPlayerColor.value = aiPlayerColor.value === "white" ? "black" : "white";
|
| 610 |
|
| 611 |
+
// Save to storage
|
| 612 |
+
storage.setString(StorageKey.AI_PLAYER_COLOR, aiPlayerColor.value);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 613 |
|
| 614 |
+
console.log(`[TrigoView] AI color swapped to: ${aiPlayerColor.value}`);
|
|
|
|
| 615 |
|
| 616 |
+
// If game is started and it's now AI's turn, trigger AI move immediately
|
| 617 |
+
if (gameStarted.value && aiReady.value && currentPlayer.value === aiPlayerColor.value) {
|
| 618 |
+
setTimeout(() => {
|
| 619 |
+
generateAIMove();
|
| 620 |
+
}, 100);
|
|
|
|
| 621 |
}
|
| 622 |
+
};
|
| 623 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 624 |
|
| 625 |
+
// Game control methods
|
| 626 |
+
const newGame = () => {
|
| 627 |
+
// Parse selected board shape
|
| 628 |
+
const shape = parseBoardShape(selectedBoardShape.value);
|
| 629 |
|
| 630 |
+
// Initialize game in store
|
| 631 |
+
gameStore.initializeGame(shape);
|
| 632 |
+
gameStore.startGame();
|
| 633 |
|
| 634 |
+
// Update viewport with new board shape
|
|
|
|
|
|
|
| 635 |
if (viewport) {
|
| 636 |
+
viewport.setBoardShape(shape);
|
| 637 |
+
viewport.clearBoard();
|
| 638 |
+
viewport.setGameActive(true);
|
| 639 |
+
|
| 640 |
+
// Exit territory mode if active
|
| 641 |
viewport.hideDomainCubes();
|
| 642 |
}
|
| 643 |
+
|
| 644 |
+
// Reset scores and territory mode
|
| 645 |
blackScore.value = 0;
|
| 646 |
whiteScore.value = 0;
|
| 647 |
+
showTerritoryMode.value = false;
|
|
|
|
| 648 |
|
| 649 |
+
console.log(`Starting new game with board shape ${shape.x}×${shape.y}×${shape.z}`);
|
|
|
|
|
|
|
|
|
|
| 650 |
|
| 651 |
+
// VS AI mode: If AI plays black, generate first move
|
| 652 |
+
if (gameMode.value === "vs-ai" && aiPlayerColor.value === "black" && aiReady.value) {
|
| 653 |
+
setTimeout(() => {
|
| 654 |
+
generateAIMove();
|
| 655 |
+
}, 100);
|
| 656 |
+
}
|
| 657 |
+
};
|
| 658 |
|
| 659 |
+
const pass = () => {
|
| 660 |
+
const previousPlayer = currentPlayer.value;
|
| 661 |
+
const success = gameStore.pass();
|
|
|
|
| 662 |
|
| 663 |
+
if (success) {
|
| 664 |
+
// Check if game ended due to double pass
|
| 665 |
+
//if (gameStore.gameResult?.reason === "double-pass") {
|
| 666 |
+
// showGameResult();
|
| 667 |
+
//} else {
|
| 668 |
+
console.log(`${previousPlayer} passed (Pass count: ${gameStore.passCount})`);
|
| 669 |
+
//}
|
| 670 |
+
}
|
| 671 |
+
};
|
| 672 |
|
| 673 |
+
const resign = () => {
|
| 674 |
+
// Confirm resignation
|
| 675 |
+
const confirmed = confirm(
|
| 676 |
+
`Are you sure ${currentPlayer.value} wants to resign?\n\nThis will end the game immediately.`
|
| 677 |
+
);
|
| 678 |
|
| 679 |
+
if (!confirmed) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 680 |
|
| 681 |
+
//const success = gameStore.resign();
|
|
|
|
| 682 |
|
| 683 |
+
//if (success) {
|
| 684 |
+
// showGameResult();
|
| 685 |
+
//}
|
| 686 |
+
};
|
| 687 |
+
|
| 688 |
+
const showGameResult = () => {
|
| 689 |
+
const result = gameStore.gameResult;
|
| 690 |
+
if (!result) return;
|
| 691 |
+
|
| 692 |
+
// Don't set game as inactive - allow continued analysis
|
| 693 |
+
// if (viewport) {
|
| 694 |
+
// viewport.setGameActive(false);
|
| 695 |
+
// }
|
| 696 |
+
|
| 697 |
+
let message = "";
|
| 698 |
+
if (result.reason === "resignation") {
|
| 699 |
+
message = `${result.winner === "black" ? "Black" : "White"} wins by resignation!\n\nGame continues for analysis.`;
|
| 700 |
+
} else if (result.reason === "double-pass") {
|
| 701 |
+
// Calculate final scores for double pass
|
| 702 |
+
const territory = gameStore.computeTerritory();
|
| 703 |
+
const blackTotal = territory.black + capturedStones.value.black;
|
| 704 |
+
const whiteTotal = territory.white + capturedStones.value.white;
|
| 705 |
+
|
| 706 |
+
blackScore.value = blackTotal;
|
| 707 |
+
whiteScore.value = whiteTotal;
|
| 708 |
+
|
| 709 |
+
if (blackTotal > whiteTotal) {
|
| 710 |
+
message = `Black wins by ${blackTotal - whiteTotal} points!\n\nBlack: ${blackTotal} points\nWhite: ${whiteTotal} points\n\nGame continues for analysis.`;
|
| 711 |
+
} else if (whiteTotal > blackTotal) {
|
| 712 |
+
message = `White wins by ${whiteTotal - blackTotal} points!\n\nWhite: ${whiteTotal} points\nBlack: ${blackTotal} points\n\nGame continues for analysis.`;
|
| 713 |
+
} else {
|
| 714 |
+
message = `Game is a draw!\n\nBoth players: ${blackTotal} points\n\nGame continues for analysis.`;
|
| 715 |
+
}
|
| 716 |
+
}
|
| 717 |
|
| 718 |
+
setTimeout(() => {
|
| 719 |
+
alert(message);
|
| 720 |
+
}, 100);
|
| 721 |
+
};
|
|
|
|
| 722 |
|
| 723 |
+
const computeTerritory = () => {
|
| 724 |
+
if (!gameStarted.value) return;
|
| 725 |
|
| 726 |
+
// Toggle territory mode
|
| 727 |
+
if (showTerritoryMode.value) {
|
| 728 |
+
// Exit territory mode
|
| 729 |
+
if (viewport) {
|
| 730 |
+
viewport.hideDomainCubes();
|
| 731 |
+
}
|
| 732 |
+
showTerritoryMode.value = false;
|
| 733 |
+
// Reset scores to captured stones count
|
| 734 |
+
blackScore.value = 0;
|
| 735 |
+
whiteScore.value = 0;
|
| 736 |
+
return;
|
| 737 |
+
}
|
| 738 |
|
| 739 |
+
// Enter territory mode - Use store's territory calculation
|
| 740 |
+
const territory = gameStore.computeTerritory();
|
| 741 |
+
blackScore.value = territory.black + capturedStones.value.black;
|
| 742 |
+
whiteScore.value = territory.white + capturedStones.value.white;
|
| 743 |
|
| 744 |
+
// Switch to territory display mode
|
| 745 |
+
showTerritoryMode.value = true;
|
|
|
|
| 746 |
|
| 747 |
+
// Convert territory arrays to Sets of position keys for viewport
|
| 748 |
+
if (viewport) {
|
| 749 |
+
const blackDomain = new Set<string>();
|
| 750 |
+
const whiteDomain = new Set<string>();
|
| 751 |
+
|
| 752 |
+
// Use the calculated territory positions from the territory result
|
| 753 |
+
territory.blackTerritory.forEach((pos) => {
|
| 754 |
+
const key = `${pos.x},${pos.y},${pos.z}`;
|
| 755 |
+
blackDomain.add(key);
|
| 756 |
+
});
|
| 757 |
+
|
| 758 |
+
territory.whiteTerritory.forEach((pos) => {
|
| 759 |
+
const key = `${pos.x},${pos.y},${pos.z}`;
|
| 760 |
+
whiteDomain.add(key);
|
| 761 |
+
});
|
| 762 |
+
|
| 763 |
+
// Set domain data and show both domains
|
| 764 |
+
viewport.setDomainData(blackDomain, whiteDomain);
|
| 765 |
+
viewport.setBlackDomainVisible(true);
|
| 766 |
+
viewport.setWhiteDomainVisible(true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 767 |
}
|
|
|
|
| 768 |
|
| 769 |
+
console.log("Territory computed:", territory);
|
| 770 |
+
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 771 |
|
| 772 |
+
const previousMove = () => {
|
| 773 |
+
const success = gameStore.undoMove();
|
| 774 |
+
|
| 775 |
+
if (success && viewport) {
|
| 776 |
+
// Rebuild viewport from current board state
|
| 777 |
+
syncViewportWithStore();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 778 |
}
|
| 779 |
+
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 780 |
|
| 781 |
+
const nextMove = () => {
|
| 782 |
+
const success = gameStore.redoMove();
|
| 783 |
|
| 784 |
+
if (success && viewport) {
|
| 785 |
+
// Rebuild viewport from current board state
|
| 786 |
+
syncViewportWithStore();
|
| 787 |
+
}
|
| 788 |
+
};
|
| 789 |
|
| 790 |
+
const jumpToMove = (index: number) => {
|
| 791 |
+
const success = gameStore.jumpToMove(index);
|
| 792 |
|
| 793 |
+
if (success && viewport) {
|
| 794 |
+
// Rebuild viewport from current board state
|
| 795 |
+
syncViewportWithStore();
|
|
|
|
| 796 |
|
| 797 |
+
// Exit territory mode when navigating move history
|
| 798 |
+
viewport.hideDomainCubes();
|
| 799 |
+
showTerritoryMode.value = false;
|
| 800 |
+
// Reset scores to 0 when exiting territory mode
|
| 801 |
+
blackScore.value = 0;
|
| 802 |
+
whiteScore.value = 0;
|
| 803 |
+
}
|
| 804 |
+
};
|
| 805 |
|
| 806 |
+
// Sync viewport with store's board state
|
| 807 |
+
const syncViewportWithStore = () => {
|
| 808 |
+
if (!viewport) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 809 |
|
| 810 |
+
// Clear viewport
|
| 811 |
+
viewport.clearBoard();
|
| 812 |
|
| 813 |
+
// Read the actual board state from the store (which has captures applied)
|
| 814 |
+
const board = gameStore.board;
|
| 815 |
+
const shape = boardShape.value;
|
| 816 |
+
|
| 817 |
+
// Add all stones that exist on the board
|
| 818 |
+
for (let x = 0; x < shape.x; x++) {
|
| 819 |
+
for (let y = 0; y < shape.y; y++) {
|
| 820 |
+
for (let z = 0; z < shape.z; z++) {
|
| 821 |
+
const stone = board[x][y][z];
|
| 822 |
+
if (stone === Stone.Black) {
|
| 823 |
+
viewport.addStone(x, y, z, "black");
|
| 824 |
+
} else if (stone === Stone.White) {
|
| 825 |
+
viewport.addStone(x, y, z, "white");
|
| 826 |
+
}
|
| 827 |
+
}
|
| 828 |
+
}
|
| 829 |
}
|
|
|
|
| 830 |
|
| 831 |
+
// Set the last placed stone highlight based on current move index
|
| 832 |
+
// currentMoveIndex represents the number of moves applied (not array index)
|
| 833 |
+
// So the last applied move is at array index (currentMoveIndex - 1)
|
| 834 |
+
if (currentMoveIndex.value > 0 && currentMoveIndex.value <= moveHistory.value.length) {
|
| 835 |
+
const lastMove = moveHistory.value[currentMoveIndex.value - 1];
|
| 836 |
+
viewport.setLastPlacedStone(lastMove.x, lastMove.y, lastMove.z);
|
| 837 |
+
} else {
|
| 838 |
+
// No moves applied or at START position
|
| 839 |
+
viewport.setLastPlacedStone(null, null, null);
|
| 840 |
+
}
|
| 841 |
+
};
|
| 842 |
+
|
| 843 |
+
// Watch for current player changes to update viewport preview
|
| 844 |
+
watch(currentPlayer, (newPlayer) => {
|
| 845 |
if (viewport) {
|
| 846 |
+
viewport.setCurrentPlayer(newPlayer);
|
| 847 |
}
|
| 848 |
+
});
|
| 849 |
|
| 850 |
+
// Watch currentMoveIndex to auto-scroll move history to keep current move visible
|
| 851 |
+
watch(currentMoveIndex, () => {
|
| 852 |
+
// Use nextTick to ensure DOM is updated before scrolling
|
| 853 |
+
nextTick(() => {
|
| 854 |
+
if (moveHistoryContainer.value) {
|
| 855 |
+
// Find the active move element
|
| 856 |
+
const activeElement = moveHistoryContainer.value.querySelector(".active");
|
| 857 |
+
if (activeElement) {
|
| 858 |
+
// Scroll the active element into view smoothly
|
| 859 |
+
activeElement.scrollIntoView({ behavior: "smooth", block: "nearest" });
|
| 860 |
+
}
|
| 861 |
+
}
|
| 862 |
+
});
|
| 863 |
+
});
|
| 864 |
|
| 865 |
+
// Watch TGN modal to populate editable content when opened
|
| 866 |
+
watch(showTGNModal, (isVisible) => {
|
| 867 |
+
if (isVisible) {
|
| 868 |
+
// Populate with current game's TGN when modal opens
|
| 869 |
+
editableTGNContent.value = tgnContent.value;
|
| 870 |
+
tgnValidationState.value = "valid"; // Current TGN is always valid
|
| 871 |
+
tgnValidationError.value = "";
|
| 872 |
+
}
|
| 873 |
+
});
|
| 874 |
|
| 875 |
+
// Lifecycle hooks
|
| 876 |
+
onMounted(() => {
|
| 877 |
+
console.log("TrigoDemo component mounted");
|
| 878 |
|
| 879 |
+
// Try to restore game state from session storage
|
| 880 |
+
const restoredFromStorage = gameStore.loadFromSessionStorage();
|
| 881 |
|
| 882 |
+
// If not restored from storage, initialize new game
|
| 883 |
+
if (!restoredFromStorage) {
|
| 884 |
+
// Parse initial board shape
|
| 885 |
+
const shape = parseBoardShape(selectedBoardShape.value);
|
| 886 |
+
|
| 887 |
+
// Initialize game store
|
| 888 |
+
gameStore.initializeGame(shape);
|
| 889 |
+
} else {
|
| 890 |
+
// Update selected board shape to match restored state
|
| 891 |
+
selectedBoardShape.value = printBoardShape(boardShape.value);
|
| 892 |
+
console.log("Restored game state from session storage");
|
| 893 |
+
}
|
| 894 |
|
| 895 |
+
// Initialize Three.js viewport with current board shape
|
| 896 |
+
if (viewportCanvas.value) {
|
| 897 |
+
viewport = new TrigoViewport(viewportCanvas.value, boardShape.value, {
|
| 898 |
+
onStoneClick: handleStoneClick,
|
| 899 |
+
onPositionHover: handlePositionHover,
|
| 900 |
+
isPositionDroppable: isPositionDroppable,
|
| 901 |
+
onInspectGroup: handleInspectGroup
|
| 902 |
+
});
|
| 903 |
+
console.log("TrigoViewport initialized");
|
| 904 |
|
| 905 |
+
// Hide loading overlay after viewport is initialized
|
| 906 |
+
isLoading.value = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 907 |
|
| 908 |
+
// If game was restored, sync viewport with restored board state
|
| 909 |
+
if (restoredFromStorage) {
|
| 910 |
+
syncViewportWithStore();
|
| 911 |
+
viewport.setGameActive(isGameActive.value);
|
| 912 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 913 |
|
| 914 |
+
// Setup ResizeObserver to handle canvas resizing when sidebar expands/collapses
|
| 915 |
+
resizeObserver = new ResizeObserver((entries) => {
|
| 916 |
+
for (const entry of entries) {
|
| 917 |
+
if (entry.target === viewportCanvas.value && viewport) {
|
| 918 |
+
// Trigger viewport resize
|
| 919 |
+
const rect = viewportCanvas.value.getBoundingClientRect();
|
| 920 |
+
console.log(`Canvas resized: ${rect.width}x${rect.height}`);
|
| 921 |
+
|
| 922 |
+
// Call the viewport's resize handler directly
|
| 923 |
+
// The onWindowResize method updates camera aspect and renderer size
|
| 924 |
+
(viewport as any).onWindowResize();
|
| 925 |
+
}
|
| 926 |
+
}
|
| 927 |
+
});
|
| 928 |
|
| 929 |
+
// Observe the canvas element for size changes
|
| 930 |
+
resizeObserver.observe(viewportCanvas.value);
|
| 931 |
+
console.log("ResizeObserver attached to canvas");
|
| 932 |
+
}
|
|
|
|
| 933 |
|
| 934 |
+
// Start game automatically if not restored or was playing
|
| 935 |
+
if (!restoredFromStorage || gameStore.gameStatus === "idle") {
|
| 936 |
+
gameStore.startGame();
|
| 937 |
+
if (viewport) {
|
| 938 |
+
viewport.setGameActive(true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 939 |
}
|
| 940 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 941 |
|
| 942 |
+
// Initialize AI agent in VS AI mode
|
| 943 |
+
if (gameMode.value === "vs-ai") {
|
| 944 |
+
console.log("[TrigoView] Initializing AI agent for VS AI mode...");
|
| 945 |
+
aiAgent.initialize().catch((err) => {
|
| 946 |
+
console.error("[TrigoView] Failed to initialize AI agent:", err);
|
| 947 |
+
});
|
| 948 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 949 |
|
| 950 |
+
// Add keyboard shortcuts
|
| 951 |
+
window.addEventListener("keydown", handleKeyPress);
|
| 952 |
+
});
|
|
|
|
| 953 |
|
| 954 |
+
onUnmounted(() => {
|
| 955 |
+
console.log("TrigoDemo component unmounted");
|
|
|
|
|
|
|
|
|
|
| 956 |
|
| 957 |
+
// Remove keyboard shortcuts
|
| 958 |
+
window.removeEventListener("keydown", handleKeyPress);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 959 |
|
| 960 |
+
// Disconnect ResizeObserver
|
| 961 |
+
if (resizeObserver) {
|
| 962 |
+
resizeObserver.disconnect();
|
| 963 |
+
resizeObserver = null;
|
| 964 |
+
console.log("ResizeObserver disconnected");
|
| 965 |
}
|
| 966 |
|
| 967 |
+
// Cleanup Three.js resources
|
| 968 |
+
if (viewport) {
|
| 969 |
+
viewport.destroy();
|
| 970 |
+
viewport = null;
|
| 971 |
+
}
|
| 972 |
+
});
|
| 973 |
|
| 974 |
+
// Keyboard shortcuts handler
|
| 975 |
+
const handleKeyPress = (event: KeyboardEvent) => {
|
| 976 |
+
// Ignore if typing in an input field
|
| 977 |
+
if (
|
| 978 |
+
event.target instanceof HTMLInputElement ||
|
| 979 |
+
event.target instanceof HTMLTextAreaElement
|
| 980 |
+
) {
|
| 981 |
+
return;
|
| 982 |
+
}
|
| 983 |
|
| 984 |
+
switch (event.key.toLowerCase()) {
|
| 985 |
+
case "p": // Pass
|
| 986 |
+
if (gameStarted.value) {
|
| 987 |
+
pass();
|
| 988 |
}
|
| 989 |
+
break;
|
| 990 |
+
case "n": // New game
|
| 991 |
+
newGame();
|
| 992 |
+
break;
|
| 993 |
+
case "r": // Resign
|
| 994 |
+
if (gameStarted.value) {
|
| 995 |
+
resign();
|
| 996 |
+
}
|
| 997 |
+
break;
|
| 998 |
+
case "arrowleft": // Previous move
|
| 999 |
+
previousMove();
|
| 1000 |
+
event.preventDefault();
|
| 1001 |
+
break;
|
| 1002 |
+
case "arrowright": // Next move
|
| 1003 |
+
nextMove();
|
| 1004 |
+
event.preventDefault();
|
| 1005 |
+
break;
|
| 1006 |
+
case "t": // Compute territory
|
| 1007 |
+
if (gameStarted.value) {
|
| 1008 |
+
computeTerritory();
|
| 1009 |
+
}
|
| 1010 |
+
break;
|
| 1011 |
+
}
|
| 1012 |
+
};
|
| 1013 |
+
|
| 1014 |
+
// TGN Modal Methods
|
| 1015 |
+
const selectAllTGN = (event: Event) => {
|
| 1016 |
+
const textarea = event.target as HTMLTextAreaElement;
|
| 1017 |
+
textarea.select();
|
| 1018 |
+
};
|
| 1019 |
+
|
| 1020 |
+
const copyTGN = async () => {
|
| 1021 |
+
try {
|
| 1022 |
+
// Try modern clipboard API first
|
| 1023 |
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
| 1024 |
+
await navigator.clipboard.writeText(tgnContent.value);
|
| 1025 |
+
alert("TGN copied to clipboard!");
|
| 1026 |
+
} else {
|
| 1027 |
+
// Fallback for older browsers or non-secure contexts
|
| 1028 |
+
const textarea = document.createElement("textarea");
|
| 1029 |
+
textarea.value = tgnContent.value;
|
| 1030 |
+
textarea.style.position = "fixed";
|
| 1031 |
+
textarea.style.opacity = "0";
|
| 1032 |
+
document.body.appendChild(textarea);
|
| 1033 |
+
textarea.select();
|
| 1034 |
+
|
| 1035 |
+
try {
|
| 1036 |
+
document.execCommand("copy");
|
| 1037 |
+
alert("TGN copied to clipboard!");
|
| 1038 |
+
} catch (fallbackErr) {
|
| 1039 |
+
console.error("Fallback copy failed:", fallbackErr);
|
| 1040 |
+
alert("Failed to copy TGN. Please select and copy manually.");
|
| 1041 |
+
} finally {
|
| 1042 |
+
document.body.removeChild(textarea);
|
| 1043 |
}
|
| 1044 |
}
|
| 1045 |
+
} catch (err) {
|
| 1046 |
+
console.error("Failed to copy TGN:", err);
|
| 1047 |
+
alert("Failed to copy TGN. Please select and copy manually.");
|
|
|
|
|
|
|
| 1048 |
}
|
| 1049 |
+
};
|
| 1050 |
+
</script>
|
| 1051 |
|
| 1052 |
+
<style lang="scss" scoped>
|
| 1053 |
+
.trigo-view {
|
| 1054 |
display: flex;
|
| 1055 |
+
flex-direction: column;
|
| 1056 |
+
height: 100%;
|
| 1057 |
+
background-color: #404040;
|
| 1058 |
+
color: #e0e0e0;
|
| 1059 |
overflow: hidden;
|
| 1060 |
|
| 1061 |
+
.view-header {
|
|
|
|
| 1062 |
display: flex;
|
|
|
|
| 1063 |
justify-content: center;
|
| 1064 |
+
align-items: center;
|
| 1065 |
+
padding: 1rem 2rem;
|
| 1066 |
+
background: linear-gradient(135deg, #505050 0%, #454545 100%);
|
| 1067 |
+
border-bottom: 2px solid #606060;
|
| 1068 |
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1069 |
|
| 1070 |
+
.view-status {
|
| 1071 |
+
display: flex;
|
| 1072 |
+
gap: 2rem;
|
| 1073 |
+
align-items: center;
|
|
|
|
|
|
|
| 1074 |
|
| 1075 |
+
.turn-indicator {
|
| 1076 |
+
padding: 0.5rem 1rem;
|
| 1077 |
+
border-radius: 8px;
|
| 1078 |
+
font-weight: 600;
|
| 1079 |
+
transition: all 0.3s ease;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1080 |
|
| 1081 |
+
&.black {
|
| 1082 |
+
background-color: #2c2c2c;
|
| 1083 |
+
color: #fff;
|
| 1084 |
+
box-shadow: 0 0 10px rgba(255, 255, 255, 0.3);
|
| 1085 |
}
|
| 1086 |
|
| 1087 |
+
&.white {
|
| 1088 |
+
background-color: #f0f0f0;
|
| 1089 |
+
color: #000;
|
| 1090 |
+
box-shadow: 0 0 10px rgba(240, 240, 240, 0.3);
|
| 1091 |
}
|
| 1092 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1093 |
|
| 1094 |
+
.move-count {
|
| 1095 |
+
font-size: 1rem;
|
| 1096 |
+
color: #a0a0a0;
|
| 1097 |
}
|
|
|
|
| 1098 |
|
| 1099 |
+
// VS AI Mode Styles
|
| 1100 |
+
&.ai-mode {
|
| 1101 |
+
.player-info,
|
| 1102 |
+
.ai-status {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1103 |
display: flex;
|
| 1104 |
align-items: center;
|
|
|
|
| 1105 |
gap: 0.5rem;
|
| 1106 |
+
padding: 0.5rem 1rem;
|
| 1107 |
+
background-color: #3a3a3a;
|
| 1108 |
border-radius: 8px;
|
| 1109 |
+
border: 2px solid transparent;
|
|
|
|
| 1110 |
transition: all 0.3s ease;
|
| 1111 |
|
| 1112 |
+
&.on-turn {
|
| 1113 |
+
background-color: #4a4a4a;
|
| 1114 |
+
border-color: #60a5fa;
|
| 1115 |
+
box-shadow: 0 0 12px rgba(96, 165, 250, 0.4);
|
| 1116 |
+
}
|
| 1117 |
+
}
|
| 1118 |
+
|
| 1119 |
+
.player-label,
|
| 1120 |
+
.ai-indicator {
|
| 1121 |
+
color: #a0a0a0;
|
| 1122 |
+
font-weight: 500;
|
| 1123 |
+
}
|
| 1124 |
+
|
| 1125 |
+
.stone-icon {
|
| 1126 |
+
width: 20px;
|
| 1127 |
+
height: 20px;
|
| 1128 |
+
border-radius: 50%;
|
| 1129 |
+
flex-shrink: 0;
|
| 1130 |
+
|
| 1131 |
&.black {
|
| 1132 |
+
background-color: #2c2c2c;
|
| 1133 |
+
border: 2px solid #fff;
|
|
|
|
|
|
|
| 1134 |
}
|
| 1135 |
|
| 1136 |
&.white {
|
| 1137 |
+
background-color: #f0f0f0;
|
| 1138 |
+
border: 2px solid #000;
|
|
|
|
|
|
|
| 1139 |
}
|
| 1140 |
+
}
|
| 1141 |
|
| 1142 |
+
.ai-level {
|
| 1143 |
+
color: #60a5fa;
|
| 1144 |
+
font-weight: 600;
|
|
|
|
|
|
|
| 1145 |
|
| 1146 |
+
&.ai-thinking {
|
| 1147 |
+
color: #fbbf24;
|
| 1148 |
+
animation: pulse 1.5s ease-in-out infinite;
|
|
|
|
| 1149 |
}
|
| 1150 |
|
| 1151 |
+
&.ai-error {
|
| 1152 |
+
color: #ef4444;
|
| 1153 |
}
|
| 1154 |
}
|
|
|
|
| 1155 |
|
| 1156 |
+
.ai-time {
|
| 1157 |
+
color: #9ca3af;
|
| 1158 |
+
font-size: 0.875rem;
|
| 1159 |
+
font-style: italic;
|
| 1160 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1161 |
|
| 1162 |
+
.btn-swap-colors {
|
| 1163 |
+
padding: 0.4rem 0.8rem;
|
| 1164 |
+
background-color: #4b5563;
|
| 1165 |
+
color: #e5e7eb;
|
| 1166 |
+
border: none;
|
| 1167 |
+
border-radius: 6px;
|
| 1168 |
+
cursor: pointer;
|
| 1169 |
+
font-size: 0.875rem;
|
| 1170 |
+
font-weight: 600;
|
| 1171 |
+
transition: all 0.2s ease;
|
| 1172 |
+
|
| 1173 |
+
&:hover {
|
| 1174 |
+
background-color: #6b7280;
|
| 1175 |
+
transform: translateY(-1px);
|
| 1176 |
+
}
|
| 1177 |
+
|
| 1178 |
+
&:active {
|
| 1179 |
+
transform: translateY(0);
|
| 1180 |
+
}
|
| 1181 |
}
|
| 1182 |
+
}
|
| 1183 |
|
| 1184 |
+
// VS People Mode Styles
|
| 1185 |
+
&.people-mode {
|
| 1186 |
+
.room-info {
|
| 1187 |
+
display: flex;
|
| 1188 |
+
align-items: center;
|
| 1189 |
+
gap: 0.5rem;
|
| 1190 |
+
padding: 0.5rem 1rem;
|
| 1191 |
+
background-color: #3a3a3a;
|
| 1192 |
+
border-radius: 8px;
|
| 1193 |
+
}
|
| 1194 |
+
|
| 1195 |
+
.room-label {
|
| 1196 |
+
color: #a0a0a0;
|
| 1197 |
+
font-weight: 500;
|
| 1198 |
+
}
|
| 1199 |
+
|
| 1200 |
+
.room-code {
|
| 1201 |
+
color: #e94560;
|
| 1202 |
+
font-weight: 700;
|
| 1203 |
+
font-family: monospace;
|
| 1204 |
+
font-size: 1.1rem;
|
| 1205 |
+
}
|
| 1206 |
+
|
| 1207 |
+
.players-info {
|
| 1208 |
+
display: flex;
|
| 1209 |
+
align-items: center;
|
| 1210 |
+
gap: 0.75rem;
|
| 1211 |
+
padding: 0.5rem 1rem;
|
| 1212 |
+
background-color: #3a3a3a;
|
| 1213 |
+
border-radius: 8px;
|
| 1214 |
+
}
|
| 1215 |
+
|
| 1216 |
+
.player-name {
|
| 1217 |
+
color: #e0e0e0;
|
| 1218 |
+
font-weight: 600;
|
| 1219 |
+
}
|
| 1220 |
+
|
| 1221 |
+
.vs-divider {
|
| 1222 |
+
color: #606060;
|
| 1223 |
+
font-weight: 500;
|
| 1224 |
+
}
|
| 1225 |
+
|
| 1226 |
+
.connection-status {
|
| 1227 |
+
padding: 0.5rem 1rem;
|
| 1228 |
+
border-radius: 8px;
|
| 1229 |
+
font-weight: 600;
|
| 1230 |
+
font-size: 0.9rem;
|
| 1231 |
+
|
| 1232 |
+
&.connected {
|
| 1233 |
+
background-color: rgba(74, 222, 128, 0.15);
|
| 1234 |
+
color: #4ade80;
|
| 1235 |
+
}
|
| 1236 |
+
|
| 1237 |
+
&.disconnected {
|
| 1238 |
+
background-color: rgba(239, 68, 68, 0.15);
|
| 1239 |
+
color: #ef4444;
|
| 1240 |
+
}
|
| 1241 |
}
|
| 1242 |
}
|
| 1243 |
|
| 1244 |
+
// Library Mode Styles
|
| 1245 |
+
&.library-mode {
|
| 1246 |
+
.game-info {
|
| 1247 |
+
display: flex;
|
| 1248 |
+
align-items: center;
|
| 1249 |
+
gap: 1rem;
|
| 1250 |
+
padding: 0.5rem 1rem;
|
| 1251 |
background-color: #3a3a3a;
|
| 1252 |
+
border-radius: 8px;
|
| 1253 |
+
}
|
| 1254 |
+
|
| 1255 |
+
.game-title {
|
| 1256 |
+
color: #e0e0e0;
|
| 1257 |
+
font-weight: 600;
|
| 1258 |
+
font-size: 1.1rem;
|
| 1259 |
+
}
|
| 1260 |
+
|
| 1261 |
+
.game-date {
|
| 1262 |
+
color: #a0a0a0;
|
| 1263 |
+
font-weight: 500;
|
| 1264 |
+
font-family: monospace;
|
| 1265 |
+
}
|
| 1266 |
+
|
| 1267 |
+
.library-actions {
|
| 1268 |
+
display: flex;
|
| 1269 |
+
gap: 0.5rem;
|
| 1270 |
+
}
|
| 1271 |
+
|
| 1272 |
+
.btn-library {
|
| 1273 |
+
padding: 0.5rem 1rem;
|
| 1274 |
+
border: none;
|
| 1275 |
+
border-radius: 8px;
|
| 1276 |
+
font-weight: 600;
|
| 1277 |
+
font-size: 0.9rem;
|
| 1278 |
+
cursor: pointer;
|
| 1279 |
+
transition: all 0.3s ease;
|
| 1280 |
+
|
| 1281 |
+
&.btn-load {
|
| 1282 |
+
background-color: #2d4059;
|
| 1283 |
+
color: #e0e0e0;
|
| 1284 |
+
|
| 1285 |
+
&:hover {
|
| 1286 |
+
background-color: #3d5069;
|
| 1287 |
+
transform: translateY(-2px);
|
| 1288 |
+
box-shadow: 0 4px 12px rgba(45, 64, 89, 0.4);
|
| 1289 |
+
}
|
| 1290 |
+
}
|
| 1291 |
+
|
| 1292 |
+
&.btn-export {
|
| 1293 |
+
background-color: #e94560;
|
| 1294 |
+
color: #fff;
|
| 1295 |
+
|
| 1296 |
+
&:hover {
|
| 1297 |
+
background-color: #f95670;
|
| 1298 |
+
transform: translateY(-2px);
|
| 1299 |
+
box-shadow: 0 4px 12px rgba(233, 69, 96, 0.4);
|
| 1300 |
+
}
|
| 1301 |
+
}
|
| 1302 |
}
|
| 1303 |
}
|
| 1304 |
}
|
| 1305 |
+
}
|
| 1306 |
|
| 1307 |
+
.view-body {
|
| 1308 |
+
display: flex;
|
| 1309 |
+
flex: 1;
|
| 1310 |
+
overflow: hidden;
|
| 1311 |
|
| 1312 |
+
.board-container {
|
|
|
|
| 1313 |
flex: 1;
|
| 1314 |
display: flex;
|
| 1315 |
+
align-items: center;
|
| 1316 |
+
justify-content: center;
|
| 1317 |
+
background-color: #484848;
|
| 1318 |
+
padding: 1rem;
|
| 1319 |
+
position: relative;
|
| 1320 |
|
| 1321 |
+
.viewport-wrapper {
|
| 1322 |
+
width: 100%;
|
| 1323 |
+
height: 100%;
|
| 1324 |
+
position: relative;
|
| 1325 |
border-radius: 8px;
|
| 1326 |
+
overflow: hidden;
|
| 1327 |
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
|
| 1328 |
|
| 1329 |
+
.viewport-canvas {
|
| 1330 |
+
width: 100%;
|
| 1331 |
+
height: 100%;
|
| 1332 |
+
display: block;
|
| 1333 |
+
background-color: #50505a;
|
| 1334 |
+
}
|
| 1335 |
|
| 1336 |
+
.viewport-overlay {
|
| 1337 |
+
position: absolute;
|
| 1338 |
+
top: 0;
|
| 1339 |
+
left: 0;
|
| 1340 |
+
width: 100%;
|
| 1341 |
+
height: 100%;
|
| 1342 |
+
display: flex;
|
| 1343 |
+
align-items: center;
|
| 1344 |
+
justify-content: center;
|
| 1345 |
+
pointer-events: none;
|
| 1346 |
|
| 1347 |
+
.loading-text {
|
| 1348 |
+
color: rgba(255, 255, 255, 0.5);
|
| 1349 |
+
font-size: 1.2rem;
|
| 1350 |
+
animation: pulse 2s ease-in-out infinite;
|
| 1351 |
+
}
|
| 1352 |
+
}
|
| 1353 |
|
| 1354 |
+
.inspect-tooltip {
|
| 1355 |
+
position: absolute;
|
| 1356 |
+
top: 1rem;
|
| 1357 |
+
left: 1rem;
|
| 1358 |
+
background-color: rgba(255, 241, 176, 0.95);
|
| 1359 |
+
color: #111;
|
| 1360 |
+
padding: 0.5rem 1rem;
|
| 1361 |
+
border-radius: 8px;
|
| 1362 |
+
font-size: 0.9rem;
|
| 1363 |
+
font-weight: 600;
|
| 1364 |
+
pointer-events: none;
|
| 1365 |
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
| 1366 |
+
z-index: 100;
|
| 1367 |
|
| 1368 |
+
.tooltip-content {
|
| 1369 |
+
display: flex;
|
| 1370 |
+
align-items: center;
|
| 1371 |
+
gap: 0.5rem;
|
| 1372 |
|
| 1373 |
+
.tooltip-label {
|
| 1374 |
+
white-space: nowrap;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1375 |
}
|
| 1376 |
|
| 1377 |
+
.tooltip-divider {
|
| 1378 |
+
color: #888;
|
|
|
|
|
|
|
|
|
|
| 1379 |
}
|
| 1380 |
+
}
|
| 1381 |
+
}
|
| 1382 |
+
}
|
| 1383 |
+
}
|
| 1384 |
|
| 1385 |
+
.controls-panel {
|
| 1386 |
+
width: 320px;
|
| 1387 |
+
background-color: #3a3a3a;
|
| 1388 |
+
border-left: 2px solid #606060;
|
| 1389 |
+
display: flex;
|
| 1390 |
+
flex-direction: column;
|
| 1391 |
+
overflow: hidden;
|
| 1392 |
+
box-shadow: -4px 0 16px rgba(0, 0, 0, 0.3);
|
|
|
|
| 1393 |
|
| 1394 |
+
.panel-section {
|
| 1395 |
+
padding: 0.8rem;
|
| 1396 |
+
border-bottom: 1px solid #505050;
|
| 1397 |
+
position: relative;
|
| 1398 |
|
| 1399 |
+
.section-title {
|
| 1400 |
+
font-size: 0.7rem;
|
| 1401 |
+
font-weight: 600;
|
| 1402 |
+
color: #f0bcc5;
|
| 1403 |
+
text-transform: uppercase;
|
| 1404 |
+
letter-spacing: 1px;
|
| 1405 |
+
position: absolute;
|
| 1406 |
+
top: 0;
|
| 1407 |
+
left: 0.8rem;
|
| 1408 |
+
opacity: 0;
|
| 1409 |
+
transition: opacity 0.3s ease-in;
|
| 1410 |
+
}
|
| 1411 |
|
| 1412 |
+
&:hover .section-title {
|
| 1413 |
+
opacity: 0.6;
|
| 1414 |
+
}
|
| 1415 |
+
}
|
| 1416 |
|
| 1417 |
+
.score-section {
|
| 1418 |
+
// Default style (captured mode) - lighter background
|
| 1419 |
+
.score-display {
|
| 1420 |
+
display: flex;
|
| 1421 |
+
gap: 0.5rem;
|
| 1422 |
+
margin-bottom: 1rem;
|
| 1423 |
|
| 1424 |
+
.score-button {
|
| 1425 |
+
flex: 1;
|
| 1426 |
+
display: flex;
|
| 1427 |
+
align-items: center;
|
| 1428 |
+
justify-content: center;
|
| 1429 |
+
gap: 0.5rem;
|
| 1430 |
+
padding: 1rem;
|
| 1431 |
+
border: 2px solid #505050;
|
| 1432 |
+
border-radius: 8px;
|
| 1433 |
+
background-color: #484848;
|
| 1434 |
+
cursor: default;
|
| 1435 |
+
transition: all 0.3s ease;
|
| 1436 |
|
| 1437 |
+
&.black {
|
| 1438 |
+
.color-indicator {
|
| 1439 |
+
background-color: #2c2c2c;
|
| 1440 |
+
border: 2px solid #fff;
|
| 1441 |
}
|
| 1442 |
+
}
|
| 1443 |
|
| 1444 |
+
&.white {
|
| 1445 |
+
.color-indicator {
|
| 1446 |
+
background-color: #f0f0f0;
|
| 1447 |
+
border: 2px solid #000;
|
| 1448 |
}
|
| 1449 |
+
}
|
| 1450 |
|
| 1451 |
+
.color-indicator {
|
| 1452 |
+
width: 24px;
|
| 1453 |
+
height: 24px;
|
| 1454 |
+
border-radius: 50%;
|
|
|
|
|
|
|
| 1455 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1456 |
|
| 1457 |
+
.score {
|
| 1458 |
+
font-size: 1.5rem;
|
| 1459 |
+
font-weight: 700;
|
| 1460 |
+
color: #e0e0e0;
|
| 1461 |
+
}
|
| 1462 |
|
| 1463 |
+
&:disabled {
|
| 1464 |
+
opacity: 0.5;
|
| 1465 |
+
}
|
| 1466 |
+
}
|
| 1467 |
}
|
| 1468 |
|
| 1469 |
+
.compute-territory {
|
| 1470 |
+
width: 100%;
|
| 1471 |
+
padding: 0.75rem;
|
| 1472 |
+
background-color: #505050;
|
| 1473 |
+
color: #e0e0e0;
|
| 1474 |
border: none;
|
| 1475 |
border-radius: 8px;
|
| 1476 |
font-weight: 600;
|
| 1477 |
cursor: pointer;
|
| 1478 |
transition: all 0.3s ease;
|
| 1479 |
+
|
| 1480 |
+
&:hover:not(:disabled) {
|
| 1481 |
+
background-color: #606060;
|
| 1482 |
+
}
|
| 1483 |
|
| 1484 |
&:disabled {
|
| 1485 |
opacity: 0.5;
|
| 1486 |
cursor: not-allowed;
|
| 1487 |
}
|
| 1488 |
+
}
|
| 1489 |
|
| 1490 |
+
// Territory mode - darker background with glow
|
| 1491 |
+
&.show-territory {
|
| 1492 |
+
.score-display .score-button {
|
| 1493 |
+
background-color: #3a3a3a;
|
| 1494 |
+
border-color: #606060;
|
| 1495 |
+
box-shadow: 0 0 12px rgba(233, 69, 96, 0.3);
|
|
|
|
| 1496 |
}
|
| 1497 |
+
}
|
| 1498 |
+
}
|
| 1499 |
|
| 1500 |
+
.routine-section {
|
| 1501 |
+
flex: 1;
|
| 1502 |
+
display: flex;
|
| 1503 |
+
flex-direction: column;
|
| 1504 |
+
min-height: 0;
|
| 1505 |
|
| 1506 |
+
.routine-content {
|
| 1507 |
+
flex: 1;
|
| 1508 |
+
overflow-y: auto;
|
| 1509 |
+
background-color: #2a2a2a;
|
| 1510 |
+
border-radius: 8px;
|
| 1511 |
+
padding: 0.5rem;
|
| 1512 |
|
| 1513 |
+
.move-list {
|
| 1514 |
+
padding: 0;
|
| 1515 |
+
margin: 0;
|
| 1516 |
+
|
| 1517 |
+
.move-row {
|
| 1518 |
+
display: grid;
|
| 1519 |
+
grid-template-columns: 30px 1fr 1fr;
|
| 1520 |
+
gap: 0.25rem;
|
| 1521 |
+
margin-bottom: 0.25rem;
|
| 1522 |
+
align-items: center;
|
| 1523 |
+
|
| 1524 |
+
&.start-row {
|
| 1525 |
+
grid-template-columns: 30px 1fr;
|
| 1526 |
+
padding: 0.5rem;
|
| 1527 |
+
border-radius: 4px;
|
| 1528 |
+
cursor: pointer;
|
| 1529 |
+
transition: all 0.2s ease;
|
| 1530 |
+
|
| 1531 |
+
&:hover {
|
| 1532 |
+
background-color: #484848;
|
| 1533 |
+
}
|
| 1534 |
+
|
| 1535 |
+
&.active {
|
| 1536 |
+
background-color: #505050;
|
| 1537 |
+
border-left: 3px solid #e94560;
|
| 1538 |
+
}
|
| 1539 |
+
|
| 1540 |
+
.open-label {
|
| 1541 |
+
font-weight: 700;
|
| 1542 |
+
color: #e94560;
|
| 1543 |
+
text-transform: uppercase;
|
| 1544 |
+
letter-spacing: 1px;
|
| 1545 |
+
}
|
| 1546 |
+
}
|
| 1547 |
|
| 1548 |
+
.round-number {
|
| 1549 |
+
color: #808080;
|
| 1550 |
+
font-size: 0.9em;
|
| 1551 |
+
text-align: right;
|
| 1552 |
+
padding-right: 0.25rem;
|
| 1553 |
+
}
|
| 1554 |
+
|
| 1555 |
+
.move-cell {
|
| 1556 |
+
padding: 0.5rem;
|
| 1557 |
+
border-radius: 4px;
|
| 1558 |
+
cursor: pointer;
|
| 1559 |
+
transition: all 0.2s ease;
|
| 1560 |
+
display: flex;
|
| 1561 |
+
align-items: center;
|
| 1562 |
+
gap: 0.5rem;
|
| 1563 |
+
background-color: #1a1a1a;
|
| 1564 |
+
|
| 1565 |
+
&:hover:not(.empty) {
|
| 1566 |
+
background-color: #484848;
|
| 1567 |
+
}
|
| 1568 |
+
|
| 1569 |
+
&.active {
|
| 1570 |
+
background-color: #505050;
|
| 1571 |
+
border-left: 3px solid #e94560;
|
| 1572 |
+
}
|
| 1573 |
+
|
| 1574 |
+
&.empty {
|
| 1575 |
+
background-color: transparent;
|
| 1576 |
+
cursor: default;
|
| 1577 |
+
}
|
| 1578 |
+
|
| 1579 |
+
.stone-icon {
|
| 1580 |
+
width: 16px;
|
| 1581 |
+
height: 16px;
|
| 1582 |
+
border-radius: 50%;
|
| 1583 |
+
flex-shrink: 0;
|
| 1584 |
+
|
| 1585 |
+
&.black {
|
| 1586 |
+
background-color: #2c2c2c;
|
| 1587 |
+
border: 2px solid #fff;
|
| 1588 |
+
}
|
| 1589 |
+
|
| 1590 |
+
&.white {
|
| 1591 |
+
background-color: #f0f0f0;
|
| 1592 |
+
border: 2px solid #000;
|
| 1593 |
+
}
|
| 1594 |
+
}
|
| 1595 |
+
|
| 1596 |
+
.move-coords {
|
| 1597 |
+
color: #a0a0a0;
|
| 1598 |
+
font-family: monospace;
|
| 1599 |
+
font-size: 0.9em;
|
| 1600 |
+
}
|
| 1601 |
+
|
| 1602 |
+
.move-label {
|
| 1603 |
+
color: #60a5fa;
|
| 1604 |
+
font-weight: 600;
|
| 1605 |
+
font-size: 0.85em;
|
| 1606 |
+
text-transform: lowercase;
|
| 1607 |
+
}
|
| 1608 |
+
}
|
| 1609 |
}
|
| 1610 |
}
|
| 1611 |
}
|
| 1612 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1613 |
|
| 1614 |
+
.controls-section {
|
| 1615 |
+
.control-buttons {
|
| 1616 |
display: flex;
|
| 1617 |
+
flex-direction: column;
|
| 1618 |
+
gap: 1rem;
|
| 1619 |
|
| 1620 |
+
.play-controls,
|
| 1621 |
+
.history-controls {
|
|
|
|
| 1622 |
display: flex;
|
| 1623 |
+
gap: 0.5rem;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1624 |
}
|
| 1625 |
|
| 1626 |
+
.btn {
|
| 1627 |
+
padding: 0.75rem 1.5rem;
|
| 1628 |
+
border: none;
|
| 1629 |
border-radius: 8px;
|
|
|
|
|
|
|
|
|
|
| 1630 |
font-weight: 600;
|
| 1631 |
+
cursor: pointer;
|
| 1632 |
+
transition: all 0.3s ease;
|
| 1633 |
+
flex: 1;
|
| 1634 |
|
| 1635 |
&:disabled {
|
| 1636 |
opacity: 0.5;
|
| 1637 |
cursor: not-allowed;
|
| 1638 |
}
|
| 1639 |
+
|
| 1640 |
+
&.btn-pass {
|
| 1641 |
+
background-color: #2d4059;
|
| 1642 |
+
color: #e0e0e0;
|
| 1643 |
+
|
| 1644 |
+
&:hover:not(:disabled) {
|
| 1645 |
+
background-color: #3d5069;
|
| 1646 |
+
}
|
| 1647 |
+
}
|
| 1648 |
+
|
| 1649 |
+
&.btn-resign {
|
| 1650 |
+
background-color: #c23b22;
|
| 1651 |
+
color: #fff;
|
| 1652 |
+
|
| 1653 |
+
&:hover:not(:disabled) {
|
| 1654 |
+
background-color: #d44b32;
|
| 1655 |
+
}
|
| 1656 |
+
}
|
| 1657 |
+
|
| 1658 |
+
&.btn-icon {
|
| 1659 |
+
background-color: #505050;
|
| 1660 |
+
color: #e0e0e0;
|
| 1661 |
+
padding: 0.75rem;
|
| 1662 |
+
font-size: 1.2rem;
|
| 1663 |
+
|
| 1664 |
+
&:hover:not(:disabled) {
|
| 1665 |
+
background-color: #606060;
|
| 1666 |
+
}
|
| 1667 |
+
}
|
| 1668 |
}
|
| 1669 |
}
|
| 1670 |
+
}
|
| 1671 |
|
| 1672 |
+
.settings-section {
|
| 1673 |
+
.settings-content {
|
| 1674 |
+
display: flex;
|
| 1675 |
+
flex-direction: column;
|
| 1676 |
+
gap: 1rem;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1677 |
|
| 1678 |
+
.setting-item {
|
| 1679 |
+
display: flex;
|
| 1680 |
+
align-items: center;
|
| 1681 |
+
justify-content: space-between;
|
| 1682 |
+
|
| 1683 |
+
label {
|
| 1684 |
+
font-weight: 600;
|
| 1685 |
+
color: #a0a0a0;
|
| 1686 |
+
display: flex;
|
| 1687 |
+
align-items: center;
|
| 1688 |
+
gap: 0.3rem;
|
| 1689 |
+
|
| 1690 |
+
.dirty-indicator {
|
| 1691 |
+
color: #e94560;
|
| 1692 |
+
font-size: 1.2rem;
|
| 1693 |
+
font-weight: 700;
|
| 1694 |
+
animation: pulse 2s ease-in-out infinite;
|
| 1695 |
+
}
|
| 1696 |
+
}
|
| 1697 |
+
|
| 1698 |
+
select {
|
| 1699 |
+
padding: 0.5rem;
|
| 1700 |
+
border: 2px solid #505050;
|
| 1701 |
+
border-radius: 8px;
|
| 1702 |
+
background-color: #484848;
|
| 1703 |
+
color: #e0e0e0;
|
| 1704 |
+
cursor: pointer;
|
| 1705 |
+
font-weight: 600;
|
| 1706 |
+
|
| 1707 |
+
&:disabled {
|
| 1708 |
+
opacity: 0.5;
|
| 1709 |
+
cursor: not-allowed;
|
| 1710 |
+
}
|
| 1711 |
+
}
|
| 1712 |
+
}
|
| 1713 |
+
|
| 1714 |
+
.btn-new-game {
|
| 1715 |
+
width: 100%;
|
| 1716 |
+
padding: 0.75rem;
|
| 1717 |
+
background-color: #e94560;
|
| 1718 |
+
color: #fff;
|
| 1719 |
+
border: none;
|
| 1720 |
+
border-radius: 8px;
|
| 1721 |
+
font-weight: 700;
|
| 1722 |
+
cursor: pointer;
|
| 1723 |
+
transition: all 0.3s ease;
|
| 1724 |
+
text-transform: uppercase;
|
| 1725 |
+
|
| 1726 |
+
&:hover {
|
| 1727 |
+
background-color: #f95670;
|
| 1728 |
+
transform: translateY(-2px);
|
| 1729 |
+
box-shadow: 0 4px 12px rgba(233, 69, 96, 0.4);
|
| 1730 |
+
}
|
| 1731 |
}
|
| 1732 |
}
|
| 1733 |
}
|
| 1734 |
}
|
| 1735 |
}
|
| 1736 |
}
|
| 1737 |
+
|
| 1738 |
+
/* TGN Button and Modal Styles */
|
| 1739 |
+
.btn-view-tgn {
|
| 1740 |
+
position: absolute;
|
| 1741 |
+
top: 0;
|
| 1742 |
+
right: 0.8rem;
|
| 1743 |
+
padding: 0.25rem 0.5rem;
|
| 1744 |
+
background-color: transparent;
|
| 1745 |
+
color: #a0a0a0;
|
| 1746 |
+
border: 1px solid #505050;
|
| 1747 |
+
border-radius: 4px;
|
| 1748 |
+
font-size: 0.65rem;
|
| 1749 |
+
font-weight: 600;
|
| 1750 |
+
text-transform: uppercase;
|
| 1751 |
+
letter-spacing: 0.5px;
|
| 1752 |
+
cursor: pointer;
|
| 1753 |
+
transition: all 0.2s ease;
|
| 1754 |
+
opacity: 0;
|
| 1755 |
+
|
| 1756 |
+
&:hover {
|
| 1757 |
+
background-color: #505050;
|
| 1758 |
+
color: #e0e0e0;
|
| 1759 |
+
border-color: #606060;
|
| 1760 |
+
}
|
| 1761 |
+
}
|
| 1762 |
+
|
| 1763 |
+
.routine-section:hover .btn-view-tgn {
|
| 1764 |
+
opacity: 1;
|
| 1765 |
}
|
| 1766 |
+
|
| 1767 |
+
.tgn-modal {
|
| 1768 |
+
position: fixed;
|
| 1769 |
+
top: 0;
|
| 1770 |
+
left: 0;
|
| 1771 |
+
width: 100vw;
|
| 1772 |
+
height: 100vh;
|
| 1773 |
+
background-color: rgba(0, 0, 0, 0.7);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1774 |
display: flex;
|
| 1775 |
+
align-items: center;
|
| 1776 |
+
justify-content: center;
|
| 1777 |
+
z-index: 1000;
|
| 1778 |
+
backdrop-filter: blur(4px);
|
| 1779 |
|
| 1780 |
+
.tgn-modal-content {
|
| 1781 |
+
background-color: #3a3a3a;
|
| 1782 |
+
border-radius: 12px;
|
| 1783 |
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
|
| 1784 |
+
width: 90%;
|
| 1785 |
+
max-width: 600px;
|
| 1786 |
+
max-height: 80vh;
|
| 1787 |
display: flex;
|
| 1788 |
+
flex-direction: column;
|
| 1789 |
+
overflow: hidden;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1790 |
|
| 1791 |
+
.tgn-modal-header {
|
| 1792 |
+
display: flex;
|
| 1793 |
+
justify-content: space-between;
|
| 1794 |
+
align-items: center;
|
| 1795 |
+
padding: 1rem 1.5rem;
|
| 1796 |
+
background-color: #2a2a2a;
|
| 1797 |
+
border-bottom: 1px solid #505050;
|
| 1798 |
|
| 1799 |
+
h3 {
|
| 1800 |
+
margin: 0;
|
| 1801 |
+
font-size: 1.2rem;
|
| 1802 |
+
font-weight: 600;
|
| 1803 |
+
color: #e0e0e0;
|
| 1804 |
}
|
| 1805 |
|
| 1806 |
+
.tgn-status {
|
| 1807 |
+
font-size: 0.85rem;
|
| 1808 |
+
font-weight: 600;
|
| 1809 |
+
padding: 0.4rem 0.8rem;
|
| 1810 |
+
border-radius: 4px;
|
| 1811 |
+
white-space: nowrap;
|
| 1812 |
+
transition: all 0.3s ease;
|
| 1813 |
+
|
| 1814 |
+
&.idle {
|
| 1815 |
+
background-color: #505050;
|
| 1816 |
+
color: #a0a0a0;
|
| 1817 |
+
}
|
| 1818 |
|
| 1819 |
+
&.valid {
|
| 1820 |
+
background-color: rgba(74, 222, 128, 0.15);
|
| 1821 |
+
color: #4ade80;
|
| 1822 |
+
border: 1px solid rgba(74, 222, 128, 0.4);
|
| 1823 |
+
}
|
| 1824 |
+
|
| 1825 |
+
&.invalid {
|
| 1826 |
+
background-color: rgba(239, 68, 68, 0.15);
|
| 1827 |
+
color: #ef4444;
|
| 1828 |
+
border: 1px solid rgba(239, 68, 68, 0.4);
|
| 1829 |
+
}
|
| 1830 |
}
|
|
|
|
| 1831 |
|
| 1832 |
+
.btn-close {
|
| 1833 |
+
background: none;
|
| 1834 |
+
border: none;
|
| 1835 |
+
color: #a0a0a0;
|
| 1836 |
+
font-size: 1.5rem;
|
| 1837 |
+
cursor: pointer;
|
| 1838 |
+
padding: 0;
|
| 1839 |
+
width: 32px;
|
| 1840 |
+
height: 32px;
|
| 1841 |
+
display: flex;
|
| 1842 |
+
align-items: center;
|
| 1843 |
+
justify-content: center;
|
| 1844 |
+
border-radius: 4px;
|
| 1845 |
+
transition: all 0.2s ease;
|
| 1846 |
|
| 1847 |
+
&:hover {
|
| 1848 |
+
background-color: #505050;
|
| 1849 |
+
color: #e0e0e0;
|
| 1850 |
+
}
|
| 1851 |
}
|
| 1852 |
}
|
|
|
|
| 1853 |
|
| 1854 |
+
.tgn-modal-body {
|
| 1855 |
+
flex: 1;
|
| 1856 |
+
padding: 1.5rem;
|
| 1857 |
+
overflow: auto;
|
| 1858 |
|
| 1859 |
+
.tgn-textarea {
|
| 1860 |
+
width: 100%;
|
| 1861 |
+
height: 100%;
|
| 1862 |
+
min-height: 300px;
|
| 1863 |
+
background-color: #2a2a2a;
|
| 1864 |
+
color: #e0e0e0;
|
| 1865 |
+
border: 2px solid #505050;
|
| 1866 |
+
border-radius: 8px;
|
| 1867 |
+
padding: 1rem;
|
| 1868 |
+
font-family: "Courier New", Courier, monospace;
|
| 1869 |
+
font-size: 0.9rem;
|
| 1870 |
+
line-height: 1.6;
|
| 1871 |
+
resize: vertical;
|
| 1872 |
+
cursor: text;
|
| 1873 |
+
transition:
|
| 1874 |
+
border-color 0.3s ease,
|
| 1875 |
+
box-shadow 0.3s ease;
|
| 1876 |
+
|
| 1877 |
+
&:focus {
|
| 1878 |
+
outline: none;
|
| 1879 |
+
border-color: #e94560;
|
| 1880 |
+
}
|
| 1881 |
|
| 1882 |
+
&.valid {
|
| 1883 |
+
border-color: #4ade80;
|
| 1884 |
+
box-shadow: 0 0 8px rgba(74, 222, 128, 0.2);
|
| 1885 |
+
}
|
| 1886 |
|
| 1887 |
+
&.invalid {
|
| 1888 |
+
border-color: #ef4444;
|
| 1889 |
+
box-shadow: 0 0 8px rgba(239, 68, 68, 0.2);
|
| 1890 |
+
}
|
| 1891 |
|
| 1892 |
+
&.idle {
|
| 1893 |
+
border-color: #505050;
|
| 1894 |
+
}
|
| 1895 |
}
|
| 1896 |
}
|
|
|
|
| 1897 |
|
| 1898 |
+
.tgn-modal-footer {
|
| 1899 |
+
display: flex;
|
| 1900 |
+
gap: 0.5rem;
|
| 1901 |
+
padding: 1rem 1.5rem;
|
| 1902 |
+
background-color: #2a2a2a;
|
| 1903 |
+
border-top: 1px solid #505050;
|
| 1904 |
|
| 1905 |
+
.btn {
|
| 1906 |
+
flex: 1;
|
| 1907 |
+
padding: 0.75rem;
|
| 1908 |
+
border: none;
|
| 1909 |
+
border-radius: 8px;
|
| 1910 |
+
font-weight: 600;
|
| 1911 |
+
cursor: pointer;
|
| 1912 |
+
transition: all 0.3s ease;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1913 |
|
| 1914 |
+
&:disabled {
|
| 1915 |
+
opacity: 0.5;
|
| 1916 |
+
cursor: not-allowed;
|
| 1917 |
+
}
|
| 1918 |
+
|
| 1919 |
+
&.btn-apply {
|
| 1920 |
+
background-color: #4ade80;
|
| 1921 |
+
color: #000;
|
| 1922 |
|
| 1923 |
+
&:hover:not(:disabled) {
|
| 1924 |
+
background-color: #22c55e;
|
| 1925 |
+
transform: translateY(-2px);
|
| 1926 |
+
box-shadow: 0 4px 12px rgba(74, 222, 128, 0.4);
|
| 1927 |
+
}
|
| 1928 |
}
|
|
|
|
| 1929 |
|
| 1930 |
+
&.btn-copy {
|
| 1931 |
+
background-color: #e94560;
|
| 1932 |
+
color: #fff;
|
| 1933 |
|
| 1934 |
+
&:hover {
|
| 1935 |
+
background-color: #f95670;
|
| 1936 |
+
transform: translateY(-2px);
|
| 1937 |
+
box-shadow: 0 4px 12px rgba(233, 69, 96, 0.4);
|
| 1938 |
+
}
|
| 1939 |
}
|
|
|
|
| 1940 |
|
| 1941 |
+
&.btn-close-modal {
|
| 1942 |
+
background-color: #505050;
|
| 1943 |
+
color: #e0e0e0;
|
| 1944 |
|
| 1945 |
+
&:hover {
|
| 1946 |
+
background-color: #606060;
|
| 1947 |
+
}
|
| 1948 |
}
|
| 1949 |
}
|
| 1950 |
}
|
| 1951 |
}
|
| 1952 |
}
|
|
|
|
| 1953 |
|
| 1954 |
+
@keyframes pulse {
|
| 1955 |
+
0%,
|
| 1956 |
+
100% {
|
| 1957 |
+
opacity: 0.5;
|
| 1958 |
+
}
|
| 1959 |
+
50% {
|
| 1960 |
+
opacity: 1;
|
| 1961 |
+
}
|
| 1962 |
}
|
|
|
|
| 1963 |
|
| 1964 |
+
/* Scrollbar styling */
|
| 1965 |
+
.controls-panel {
|
| 1966 |
+
&::-webkit-scrollbar {
|
| 1967 |
+
width: 8px;
|
| 1968 |
+
}
|
| 1969 |
|
| 1970 |
+
&::-webkit-scrollbar-track {
|
| 1971 |
+
background: #2a2a2a;
|
| 1972 |
+
}
|
| 1973 |
|
| 1974 |
+
&::-webkit-scrollbar-thumb {
|
| 1975 |
+
background: #505050;
|
| 1976 |
+
border-radius: 4px;
|
| 1977 |
|
| 1978 |
+
&:hover {
|
| 1979 |
+
background: #606060;
|
| 1980 |
+
}
|
| 1981 |
}
|
| 1982 |
}
|
|
|
|
| 1983 |
|
| 1984 |
+
.routine-content {
|
| 1985 |
+
&::-webkit-scrollbar {
|
| 1986 |
+
width: 6px;
|
| 1987 |
+
}
|
| 1988 |
|
| 1989 |
+
&::-webkit-scrollbar-track {
|
| 1990 |
+
background: #2a2a2a;
|
| 1991 |
+
}
|
| 1992 |
|
| 1993 |
+
&::-webkit-scrollbar-thumb {
|
| 1994 |
+
background: #505050;
|
| 1995 |
+
border-radius: 3px;
|
| 1996 |
|
| 1997 |
+
&:hover {
|
| 1998 |
+
background: #606060;
|
| 1999 |
+
}
|
| 2000 |
+
}
|
| 2001 |
+
}
|
| 2002 |
+
|
| 2003 |
+
// Animations
|
| 2004 |
+
@keyframes pulse {
|
| 2005 |
+
0%,
|
| 2006 |
+
100% {
|
| 2007 |
+
opacity: 1;
|
| 2008 |
+
}
|
| 2009 |
+
50% {
|
| 2010 |
+
opacity: 0.5;
|
| 2011 |
}
|
| 2012 |
}
|
|
|
|
| 2013 |
</style>
|
trigo-web/app/test_capture.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
-
const { TrigoGame } = require(
|
| 2 |
-
const { StoneType } = require(
|
| 3 |
|
| 4 |
const game = new TrigoGame({ x: 5, y: 5, z: 1 });
|
| 5 |
game.startGame();
|
|
|
|
| 1 |
+
const { TrigoGame } = require("../../inc/trigo/trigoGame.js");
|
| 2 |
+
const { StoneType } = require("../../inc/trigo/game.js");
|
| 3 |
|
| 4 |
const game = new TrigoGame({ x: 5, y: 5, z: 1 });
|
| 5 |
game.startGame();
|
trigo-web/app/vite.config.ts
CHANGED
|
@@ -8,7 +8,24 @@ export default defineConfig(({ mode }) => {
|
|
| 8 |
const env = loadEnv(mode, process.cwd(), "");
|
| 9 |
|
| 10 |
return {
|
| 11 |
-
plugins: [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
// Point to parent project's public directory
|
| 13 |
publicDir: fileURLToPath(new URL("../public", import.meta.url)),
|
| 14 |
resolve: {
|
|
@@ -21,7 +38,14 @@ export default defineConfig(({ mode }) => {
|
|
| 21 |
host: env.VITE_HOST || "localhost",
|
| 22 |
port: parseInt(env.VITE_PORT) || 5173,
|
| 23 |
strictPort: true,
|
| 24 |
-
open: false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
},
|
| 26 |
build: {
|
| 27 |
rollupOptions: {
|
|
@@ -39,4 +63,4 @@ export default defineConfig(({ mode }) => {
|
|
| 39 |
"process.env": {}
|
| 40 |
}
|
| 41 |
};
|
| 42 |
-
});
|
|
|
|
| 8 |
const env = loadEnv(mode, process.cwd(), "");
|
| 9 |
|
| 10 |
return {
|
| 11 |
+
plugins: [
|
| 12 |
+
vue(),
|
| 13 |
+
// Plugin to set correct MIME types
|
| 14 |
+
{
|
| 15 |
+
name: "configure-server",
|
| 16 |
+
configureServer(server) {
|
| 17 |
+
server.middlewares.use((req, res, next) => {
|
| 18 |
+
if (req.url && req.url.endsWith(".wasm")) {
|
| 19 |
+
res.setHeader("Content-Type", "application/wasm");
|
| 20 |
+
}
|
| 21 |
+
if (req.url && req.url.endsWith(".mjs")) {
|
| 22 |
+
res.setHeader("Content-Type", "application/javascript");
|
| 23 |
+
}
|
| 24 |
+
next();
|
| 25 |
+
});
|
| 26 |
+
}
|
| 27 |
+
}
|
| 28 |
+
],
|
| 29 |
// Point to parent project's public directory
|
| 30 |
publicDir: fileURLToPath(new URL("../public", import.meta.url)),
|
| 31 |
resolve: {
|
|
|
|
| 38 |
host: env.VITE_HOST || "localhost",
|
| 39 |
port: parseInt(env.VITE_PORT) || 5173,
|
| 40 |
strictPort: true,
|
| 41 |
+
open: false,
|
| 42 |
+
fs: {
|
| 43 |
+
// Allow serving files from node_modules
|
| 44 |
+
allow: ["..", "../.."]
|
| 45 |
+
}
|
| 46 |
+
},
|
| 47 |
+
optimizeDeps: {
|
| 48 |
+
exclude: ["onnxruntime-web"]
|
| 49 |
},
|
| 50 |
build: {
|
| 51 |
rollupOptions: {
|
|
|
|
| 63 |
"process.env": {}
|
| 64 |
}
|
| 65 |
};
|
| 66 |
+
});
|
trigo-web/backend/src/server.ts
CHANGED
|
@@ -11,8 +11,12 @@ const app = express();
|
|
| 11 |
const httpServer = createServer(app);
|
| 12 |
const io = new Server(httpServer, {
|
| 13 |
cors: {
|
| 14 |
-
origin:
|
| 15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
}
|
| 17 |
});
|
| 18 |
|
|
@@ -73,4 +77,4 @@ httpServer.listen(PORT, HOST, () => {
|
|
| 73 |
console.log(`Server running on ${HOST}:${PORT}`);
|
| 74 |
console.log(`Health check: http://${HOST}:${PORT}/health`);
|
| 75 |
console.log(`Environment: ${process.env.NODE_ENV || "development"}`);
|
| 76 |
-
});
|
|
|
|
| 11 |
const httpServer = createServer(app);
|
| 12 |
const io = new Server(httpServer, {
|
| 13 |
cors: {
|
| 14 |
+
origin:
|
| 15 |
+
process.env.NODE_ENV === "production"
|
| 16 |
+
? process.env.CLIENT_URL || "http://localhost:5173"
|
| 17 |
+
: true, // Allow all origins in development
|
| 18 |
+
methods: ["GET", "POST"],
|
| 19 |
+
credentials: true
|
| 20 |
}
|
| 21 |
});
|
| 22 |
|
|
|
|
| 77 |
console.log(`Server running on ${HOST}:${PORT}`);
|
| 78 |
console.log(`Health check: http://${HOST}:${PORT}/health`);
|
| 79 |
console.log(`Environment: ${process.env.NODE_ENV || "development"}`);
|
| 80 |
+
});
|
trigo-web/backend/src/services/gameManager.ts
CHANGED
|
@@ -120,11 +120,7 @@ export class GameManager {
|
|
| 120 |
}
|
| 121 |
}
|
| 122 |
|
| 123 |
-
makeMove(
|
| 124 |
-
roomId: string,
|
| 125 |
-
playerId: string,
|
| 126 |
-
move: { x: number; y: number; z: number }
|
| 127 |
-
): boolean {
|
| 128 |
const room = this.rooms.get(roomId);
|
| 129 |
if (!room) return false;
|
| 130 |
|
|
@@ -277,7 +273,9 @@ export class GameManager {
|
|
| 277 |
}
|
| 278 |
|
| 279 |
room.gameState.gameStatus = "finished";
|
| 280 |
-
console.log(
|
|
|
|
|
|
|
| 281 |
|
| 282 |
return true;
|
| 283 |
}
|
|
@@ -326,4 +324,4 @@ export class GameManager {
|
|
| 326 |
private generateRoomId(): string {
|
| 327 |
return uuidv4().substring(0, 8).toUpperCase();
|
| 328 |
}
|
| 329 |
-
}
|
|
|
|
| 120 |
}
|
| 121 |
}
|
| 122 |
|
| 123 |
+
makeMove(roomId: string, playerId: string, move: { x: number; y: number; z: number }): boolean {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 124 |
const room = this.rooms.get(roomId);
|
| 125 |
if (!room) return false;
|
| 126 |
|
|
|
|
| 273 |
}
|
| 274 |
|
| 275 |
room.gameState.gameStatus = "finished";
|
| 276 |
+
console.log(
|
| 277 |
+
`Game ${roomId} ended. Black: ${territory.black}, White: ${territory.white}, Winner: ${room.gameState.winner}`
|
| 278 |
+
);
|
| 279 |
|
| 280 |
return true;
|
| 281 |
}
|
|
|
|
| 324 |
private generateRoomId(): string {
|
| 325 |
return uuidv4().substring(0, 8).toUpperCase();
|
| 326 |
}
|
| 327 |
+
}
|
trigo-web/backend/src/sockets/gameSocket.ts
CHANGED
|
@@ -9,7 +9,9 @@ export function setupSocketHandlers(io: Server, socket: Socket, gameManager: Gam
|
|
| 9 |
const { roomId, nickname } = data;
|
| 10 |
|
| 11 |
// Create or join room
|
| 12 |
-
const room = roomId
|
|
|
|
|
|
|
| 13 |
|
| 14 |
if (room) {
|
| 15 |
socket.join(room.id);
|
|
@@ -152,4 +154,4 @@ export function setupSocketHandlers(io: Server, socket: Socket, gameManager: Gam
|
|
| 152 |
});
|
| 153 |
}
|
| 154 |
});
|
| 155 |
-
}
|
|
|
|
| 9 |
const { roomId, nickname } = data;
|
| 10 |
|
| 11 |
// Create or join room
|
| 12 |
+
const room = roomId
|
| 13 |
+
? gameManager.joinRoom(roomId, socket.id, nickname)
|
| 14 |
+
: gameManager.createRoom(socket.id, nickname);
|
| 15 |
|
| 16 |
if (room) {
|
| 17 |
socket.join(room.id);
|
|
|
|
| 154 |
});
|
| 155 |
}
|
| 156 |
});
|
| 157 |
+
}
|
trigo-web/backend/tsconfig.json
CHANGED
|
@@ -19,16 +19,11 @@
|
|
| 19 |
"noImplicitAny": false
|
| 20 |
},
|
| 21 |
"include": ["src/**/*", "../inc/**/*"],
|
| 22 |
-
"exclude": [
|
| 23 |
-
"node_modules",
|
| 24 |
-
"dist",
|
| 25 |
-
"../inc/trigo/parserInit.ts",
|
| 26 |
-
"../inc/tgn/tgn.jison.cjs"
|
| 27 |
-
],
|
| 28 |
"ts-node": {
|
| 29 |
"esm": false,
|
| 30 |
"compilerOptions": {
|
| 31 |
"module": "commonjs"
|
| 32 |
}
|
| 33 |
}
|
| 34 |
-
}
|
|
|
|
| 19 |
"noImplicitAny": false
|
| 20 |
},
|
| 21 |
"include": ["src/**/*", "../inc/**/*"],
|
| 22 |
+
"exclude": ["node_modules", "dist", "../inc/trigo/parserInit.ts", "../inc/tgn/tgn.jison.cjs"],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
"ts-node": {
|
| 24 |
"esm": false,
|
| 25 |
"compilerOptions": {
|
| 26 |
"module": "commonjs"
|
| 27 |
}
|
| 28 |
}
|
| 29 |
+
}
|
trigo-web/inc/modelInferencer.ts
ADDED
|
@@ -0,0 +1,465 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* ONNX Model Inferencer (Frontend/Backend Common)
|
| 3 |
+
*
|
| 4 |
+
* Platform-agnostic inference logic that accepts ONNX session from platform-specific code.
|
| 5 |
+
* No direct dependency on onnxruntime packages - uses dependency injection pattern.
|
| 6 |
+
*
|
| 7 |
+
* Adapted from Node.js test_inference.js for cross-platform use
|
| 8 |
+
* Provides causal language model inference using GPT-2 ONNX model
|
| 9 |
+
*/
|
| 10 |
+
|
| 11 |
+
/**
|
| 12 |
+
* Minimal ONNX Tensor interface (platform-agnostic)
|
| 13 |
+
*/
|
| 14 |
+
export interface OnnxTensor {
|
| 15 |
+
readonly data: number[] | Float32Array | Int32Array | BigInt64Array | Uint8Array;
|
| 16 |
+
readonly dims: readonly number[];
|
| 17 |
+
readonly type: string;
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
/**
|
| 21 |
+
* Minimal ONNX Session interface (platform-agnostic)
|
| 22 |
+
*/
|
| 23 |
+
export interface OnnxSession {
|
| 24 |
+
readonly inputNames: readonly string[];
|
| 25 |
+
readonly outputNames: readonly string[];
|
| 26 |
+
run(feeds: Record<string, OnnxTensor>): Promise<Record<string, OnnxTensor>>;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
/**
|
| 30 |
+
* Tensor constructor interface (platform-specific)
|
| 31 |
+
*/
|
| 32 |
+
export interface TensorConstructor {
|
| 33 |
+
new (
|
| 34 |
+
type: string,
|
| 35 |
+
data: BigInt64Array | Float32Array | Int32Array | Uint8Array,
|
| 36 |
+
dims: number[]
|
| 37 |
+
): OnnxTensor;
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
/**
|
| 41 |
+
* Configuration for the inferencer
|
| 42 |
+
*/
|
| 43 |
+
export interface InferencerConfig {
|
| 44 |
+
vocabSize: number;
|
| 45 |
+
seqLen: number;
|
| 46 |
+
modelPath?: string; // Optional, for reference
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
/**
|
| 50 |
+
* Inference result containing generated tokens and metadata
|
| 51 |
+
*/
|
| 52 |
+
export interface InferenceResult {
|
| 53 |
+
tokens: number[];
|
| 54 |
+
text: string;
|
| 55 |
+
logits: Float32Array;
|
| 56 |
+
inferenceTime: number;
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
/**
|
| 60 |
+
* Evaluation mode inputs for tree attention
|
| 61 |
+
*/
|
| 62 |
+
export interface EvaluationInputs {
|
| 63 |
+
prefixIds: number[]; // Prefix sequence (causal context)
|
| 64 |
+
evaluatedIds: number[]; // Tokens to evaluate in tree
|
| 65 |
+
evaluatedMask: number[]; // Attention mask [m×m] flattened
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
/**
|
| 69 |
+
* Evaluation mode output
|
| 70 |
+
*/
|
| 71 |
+
export interface EvaluationOutput {
|
| 72 |
+
logits: Float32Array; // [m+1, vocab_size] flattened
|
| 73 |
+
numEvaluated: number; // m
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
/**
|
| 77 |
+
* Model Inferencer for Causal Language Model
|
| 78 |
+
* Compatible with both frontend (onnxruntime-web) and backend (onnxruntime-node)
|
| 79 |
+
*/
|
| 80 |
+
export class ModelInferencer {
|
| 81 |
+
private session: OnnxSession | null = null;
|
| 82 |
+
private config: InferencerConfig;
|
| 83 |
+
private TensorClass: TensorConstructor;
|
| 84 |
+
|
| 85 |
+
// TGN tokenizer: byte-level (0-255) + PAD(256) + START(257) + END(258)
|
| 86 |
+
private readonly PAD_TOKEN = 256;
|
| 87 |
+
private readonly START_TOKEN = 257;
|
| 88 |
+
private readonly END_TOKEN = 258;
|
| 89 |
+
|
| 90 |
+
constructor(TensorClass: TensorConstructor, config: Partial<InferencerConfig> = {}) {
|
| 91 |
+
this.TensorClass = TensorClass;
|
| 92 |
+
this.config = {
|
| 93 |
+
vocabSize: 259,
|
| 94 |
+
seqLen: 256,
|
| 95 |
+
...config
|
| 96 |
+
};
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
/**
|
| 100 |
+
* Set the inference session (created by platform-specific code)
|
| 101 |
+
*/
|
| 102 |
+
setSession(session: OnnxSession): void {
|
| 103 |
+
this.session = session;
|
| 104 |
+
console.log("[ModelInferencer] ✓ Session set successfully");
|
| 105 |
+
this.printModelInfo();
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
/**
|
| 109 |
+
* Run basic inference test
|
| 110 |
+
*/
|
| 111 |
+
async testBasicInference(): Promise<InferenceResult> {
|
| 112 |
+
if (!this.session) {
|
| 113 |
+
throw new Error("Inferencer not initialized. Call setSession() first.");
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
console.log("[ModelInferencer] Running basic inference test...");
|
| 117 |
+
|
| 118 |
+
const batchSize = 1;
|
| 119 |
+
const seqLen = this.config.seqLen;
|
| 120 |
+
|
| 121 |
+
// Create random input
|
| 122 |
+
const inputIds = this.createRandomInput(batchSize, seqLen);
|
| 123 |
+
const inputTensor = new this.TensorClass("int64", inputIds, [batchSize, seqLen]);
|
| 124 |
+
|
| 125 |
+
// Run inference
|
| 126 |
+
const startTime = performance.now();
|
| 127 |
+
const results = await this.session.run({ input_ids: inputTensor });
|
| 128 |
+
const inferenceTime = performance.now() - startTime;
|
| 129 |
+
|
| 130 |
+
// Get logits
|
| 131 |
+
const logits = results.logits;
|
| 132 |
+
|
| 133 |
+
// Validate output
|
| 134 |
+
this.validateOutput(logits, batchSize, seqLen);
|
| 135 |
+
|
| 136 |
+
// Get predictions
|
| 137 |
+
const predictions = this.getPredictions(logits.data as Float32Array, batchSize * seqLen);
|
| 138 |
+
|
| 139 |
+
// Convert tokens to text
|
| 140 |
+
const text = String.fromCharCode(...predictions.slice(0, 100));
|
| 141 |
+
|
| 142 |
+
console.log("[ModelInferencer] Inference completed:");
|
| 143 |
+
console.log(` Input shape: [${inputTensor.dims.join(", ")}]`);
|
| 144 |
+
console.log(` Output shape: [${logits.dims.join(", ")}]`);
|
| 145 |
+
console.log(` Output dtype: ${logits.type}`);
|
| 146 |
+
console.log(` Inference time: ${inferenceTime.toFixed(2)}ms`);
|
| 147 |
+
console.log(` Sample predictions: [${predictions.slice(0, 10).join(", ")}]`);
|
| 148 |
+
|
| 149 |
+
const logitsArray = Array.from(logits.data as Float32Array);
|
| 150 |
+
console.log(
|
| 151 |
+
` Logits range: [${Math.min(...logitsArray).toFixed(3)}, ${Math.max(...logitsArray).toFixed(3)}]`
|
| 152 |
+
);
|
| 153 |
+
|
| 154 |
+
return {
|
| 155 |
+
tokens: predictions,
|
| 156 |
+
text,
|
| 157 |
+
logits: logits.data as Float32Array,
|
| 158 |
+
inferenceTime
|
| 159 |
+
};
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
/**
|
| 163 |
+
* Generate tokens autoregressively from a prompt
|
| 164 |
+
*/
|
| 165 |
+
async generateText(prompt: string, numTokens: number = 10): Promise<InferenceResult> {
|
| 166 |
+
if (!this.session) {
|
| 167 |
+
throw new Error("Inferencer not initialized. Call setSession() first.");
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
console.log(`[ModelInferencer] Generating ${numTokens} tokens from prompt: "${prompt}"`);
|
| 171 |
+
|
| 172 |
+
// Convert prompt to token IDs (byte values)
|
| 173 |
+
const promptTokens = Array.from(prompt).map((c) => c.charCodeAt(0));
|
| 174 |
+
console.log(` Prompt tokens (${promptTokens.length}): [${promptTokens.join(", ")}]`);
|
| 175 |
+
|
| 176 |
+
// Start with prompt tokens
|
| 177 |
+
const sequence = [...promptTokens];
|
| 178 |
+
const times: number[] = [];
|
| 179 |
+
|
| 180 |
+
// Generate tokens
|
| 181 |
+
for (let i = 0; i < numTokens; i++) {
|
| 182 |
+
// Pad sequence to fixed length
|
| 183 |
+
const paddedSequence = this.padSequence(sequence, this.config.seqLen);
|
| 184 |
+
|
| 185 |
+
// Create input tensor
|
| 186 |
+
const inputIds = new BigInt64Array(paddedSequence.map((t) => BigInt(t)));
|
| 187 |
+
const inputTensor = new this.TensorClass("int64", inputIds, [1, this.config.seqLen]);
|
| 188 |
+
|
| 189 |
+
// Run inference
|
| 190 |
+
const startTime = performance.now();
|
| 191 |
+
const results = await this.session.run({ input_ids: inputTensor });
|
| 192 |
+
times.push(performance.now() - startTime);
|
| 193 |
+
|
| 194 |
+
// Get prediction at the last non-padded position
|
| 195 |
+
const logits = results.logits.data as Float32Array;
|
| 196 |
+
const lastPos = sequence.length - 1; // Position before padding
|
| 197 |
+
const offset = lastPos * this.config.vocabSize;
|
| 198 |
+
|
| 199 |
+
// Find token with highest logit
|
| 200 |
+
let maxIdx = 0;
|
| 201 |
+
let maxVal = logits[offset];
|
| 202 |
+
for (let j = 1; j < this.config.vocabSize; j++) {
|
| 203 |
+
if (logits[offset + j] > maxVal) {
|
| 204 |
+
maxVal = logits[offset + j];
|
| 205 |
+
maxIdx = j;
|
| 206 |
+
}
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
sequence.push(maxIdx);
|
| 210 |
+
|
| 211 |
+
// Stop if END token is generated
|
| 212 |
+
if (maxIdx === this.END_TOKEN) {
|
| 213 |
+
console.log(" Generated END token, stopping...");
|
| 214 |
+
break;
|
| 215 |
+
}
|
| 216 |
+
}
|
| 217 |
+
|
| 218 |
+
// Convert generated tokens to text
|
| 219 |
+
const generatedText = String.fromCharCode(...sequence);
|
| 220 |
+
|
| 221 |
+
const avgTime = times.reduce((a, b) => a + b, 0) / times.length;
|
| 222 |
+
console.log(`[ModelInferencer] Generation complete:`);
|
| 223 |
+
console.log(` Generated text: "${generatedText}"`);
|
| 224 |
+
console.log(` Token sequence (${sequence.length}): [${sequence.join(", ")}]`);
|
| 225 |
+
console.log(` Avg inference time: ${avgTime.toFixed(2)}ms`);
|
| 226 |
+
console.log(` Tokens/sec: ${(1000 / avgTime).toFixed(2)}`);
|
| 227 |
+
|
| 228 |
+
return {
|
| 229 |
+
tokens: sequence,
|
| 230 |
+
text: generatedText,
|
| 231 |
+
logits: new Float32Array(), // Not returning full logits for generation
|
| 232 |
+
inferenceTime: avgTime
|
| 233 |
+
};
|
| 234 |
+
}
|
| 235 |
+
|
| 236 |
+
/**
|
| 237 |
+
* Get model information
|
| 238 |
+
*/
|
| 239 |
+
getModelInfo(): { inputs: string[]; outputs: string[] } | null {
|
| 240 |
+
if (!this.session) return null;
|
| 241 |
+
|
| 242 |
+
return {
|
| 243 |
+
inputs: [...this.session.inputNames],
|
| 244 |
+
outputs: [...this.session.outputNames]
|
| 245 |
+
};
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
/**
|
| 249 |
+
* Get configuration
|
| 250 |
+
*/
|
| 251 |
+
getConfig(): InferencerConfig {
|
| 252 |
+
return this.config;
|
| 253 |
+
}
|
| 254 |
+
|
| 255 |
+
/**
|
| 256 |
+
* Run inference with token array input
|
| 257 |
+
* Returns raw logits as Float32Array
|
| 258 |
+
*/
|
| 259 |
+
async runInference(tokens: number[]): Promise<Float32Array> {
|
| 260 |
+
if (!this.session) {
|
| 261 |
+
throw new Error("Inferencer not initialized. Call setSession() first.");
|
| 262 |
+
}
|
| 263 |
+
|
| 264 |
+
const seqLen = this.config.seqLen;
|
| 265 |
+
|
| 266 |
+
// Prepend START_TOKEN to input
|
| 267 |
+
const tokensWithStart = [this.START_TOKEN, ...tokens];
|
| 268 |
+
|
| 269 |
+
// Pad to fixed length
|
| 270 |
+
const paddedTokens = new BigInt64Array(seqLen);
|
| 271 |
+
for (let i = 0; i < seqLen; i++) {
|
| 272 |
+
paddedTokens[i] =
|
| 273 |
+
i < tokensWithStart.length ? BigInt(tokensWithStart[i]) : BigInt(this.PAD_TOKEN);
|
| 274 |
+
}
|
| 275 |
+
|
| 276 |
+
// Create input tensor
|
| 277 |
+
const inputTensor = new this.TensorClass("int64", paddedTokens, [1, seqLen]);
|
| 278 |
+
|
| 279 |
+
// Run inference
|
| 280 |
+
const results = await this.session.run({ input_ids: inputTensor });
|
| 281 |
+
return results.logits.data as Float32Array;
|
| 282 |
+
}
|
| 283 |
+
|
| 284 |
+
|
| 285 |
+
/**
|
| 286 |
+
* Run tree attention inference (evaluation mode)
|
| 287 |
+
* For models exported with --evaluation flag
|
| 288 |
+
* @param inputs - Prefix, evaluated tokens, and attention mask
|
| 289 |
+
* @returns Logits for each evaluated position
|
| 290 |
+
*/
|
| 291 |
+
async runEvaluationInference(inputs: EvaluationInputs): Promise<EvaluationOutput> {
|
| 292 |
+
if (!this.session) {
|
| 293 |
+
throw new Error("Inferencer not initialized. Call setSession() first.");
|
| 294 |
+
}
|
| 295 |
+
|
| 296 |
+
const { prefixIds, evaluatedIds, evaluatedMask } = inputs;
|
| 297 |
+
const batchSize = 1;
|
| 298 |
+
const prefixLen = prefixIds.length;
|
| 299 |
+
const m = evaluatedIds.length;
|
| 300 |
+
|
| 301 |
+
// Convert to BigInt64Array for ONNX int64 tensors
|
| 302 |
+
const prefixIdsArray = new BigInt64Array(batchSize * prefixLen);
|
| 303 |
+
for (let i = 0; i < prefixLen; i++) {
|
| 304 |
+
prefixIdsArray[i] = BigInt(prefixIds[i]);
|
| 305 |
+
}
|
| 306 |
+
|
| 307 |
+
const evaluatedIdsArray = new BigInt64Array(batchSize * m);
|
| 308 |
+
for (let i = 0; i < m; i++) {
|
| 309 |
+
evaluatedIdsArray[i] = BigInt(evaluatedIds[i]);
|
| 310 |
+
}
|
| 311 |
+
|
| 312 |
+
// Mask is Float32Array
|
| 313 |
+
const maskArray = new Float32Array(m * m);
|
| 314 |
+
for (let i = 0; i < m * m; i++) {
|
| 315 |
+
maskArray[i] = evaluatedMask[i];
|
| 316 |
+
}
|
| 317 |
+
|
| 318 |
+
// Create ONNX tensors
|
| 319 |
+
const prefixIdsTensor = new this.TensorClass("int64", prefixIdsArray, [
|
| 320 |
+
batchSize,
|
| 321 |
+
prefixLen
|
| 322 |
+
]);
|
| 323 |
+
const evaluatedIdsTensor = new this.TensorClass("int64", evaluatedIdsArray, [batchSize, m]);
|
| 324 |
+
const evaluatedMaskTensor = new this.TensorClass("float32", maskArray, [1, m, m]);
|
| 325 |
+
|
| 326 |
+
// Run inference
|
| 327 |
+
const results = await this.session.run({
|
| 328 |
+
prefix_ids: prefixIdsTensor,
|
| 329 |
+
evaluated_ids: evaluatedIdsTensor,
|
| 330 |
+
evaluated_mask: evaluatedMaskTensor
|
| 331 |
+
});
|
| 332 |
+
|
| 333 |
+
// Extract logits
|
| 334 |
+
const logits = results.logits.data as Float32Array;
|
| 335 |
+
|
| 336 |
+
// Output shape: [batch, m+1, vocab_size]
|
| 337 |
+
// We return flattened array and num_evaluated for reshaping
|
| 338 |
+
return {
|
| 339 |
+
logits,
|
| 340 |
+
numEvaluated: m
|
| 341 |
+
};
|
| 342 |
+
}
|
| 343 |
+
|
| 344 |
+
|
| 345 |
+
/**
|
| 346 |
+
* Compute softmax for a single position's logits
|
| 347 |
+
* @param logits - Full logits array
|
| 348 |
+
* @param position - Which evaluated position (0 = last prefix, 1-m = evaluated tokens)
|
| 349 |
+
* @returns Probability distribution over vocabulary
|
| 350 |
+
*/
|
| 351 |
+
softmax(logits: Float32Array, position: number): Float32Array {
|
| 352 |
+
const vocabSize = this.config.vocabSize;
|
| 353 |
+
const offset = position * vocabSize;
|
| 354 |
+
const probs = new Float32Array(vocabSize);
|
| 355 |
+
|
| 356 |
+
// Find max for numerical stability
|
| 357 |
+
let maxLogit = -Infinity;
|
| 358 |
+
for (let i = 0; i < vocabSize; i++) {
|
| 359 |
+
maxLogit = Math.max(maxLogit, logits[offset + i]);
|
| 360 |
+
}
|
| 361 |
+
|
| 362 |
+
// Compute exp and sum
|
| 363 |
+
let sumExp = 0;
|
| 364 |
+
for (let i = 0; i < vocabSize; i++) {
|
| 365 |
+
probs[i] = Math.exp(logits[offset + i] - maxLogit);
|
| 366 |
+
sumExp += probs[i];
|
| 367 |
+
}
|
| 368 |
+
|
| 369 |
+
// Normalize
|
| 370 |
+
for (let i = 0; i < vocabSize; i++) {
|
| 371 |
+
probs[i] /= sumExp;
|
| 372 |
+
}
|
| 373 |
+
|
| 374 |
+
return probs;
|
| 375 |
+
}
|
| 376 |
+
|
| 377 |
+
|
| 378 |
+
/**
|
| 379 |
+
* Check if inferencer is ready
|
| 380 |
+
*/
|
| 381 |
+
isReady(): boolean {
|
| 382 |
+
return this.session !== null;
|
| 383 |
+
}
|
| 384 |
+
|
| 385 |
+
/**
|
| 386 |
+
* Destroy the session and free resources
|
| 387 |
+
*/
|
| 388 |
+
destroy(): void {
|
| 389 |
+
this.session = null;
|
| 390 |
+
console.log("[ModelInferencer] Session destroyed");
|
| 391 |
+
}
|
| 392 |
+
|
| 393 |
+
// Private helper methods
|
| 394 |
+
|
| 395 |
+
private printModelInfo(): void {
|
| 396 |
+
if (!this.session) return;
|
| 397 |
+
|
| 398 |
+
console.log("[ModelInferencer] Model Information:");
|
| 399 |
+
console.log(" Inputs:");
|
| 400 |
+
this.session.inputNames.forEach((name, i) => {
|
| 401 |
+
console.log(` [${i}] ${name}`);
|
| 402 |
+
});
|
| 403 |
+
console.log(" Outputs:");
|
| 404 |
+
this.session.outputNames.forEach((name, i) => {
|
| 405 |
+
console.log(` [${i}] ${name}`);
|
| 406 |
+
});
|
| 407 |
+
}
|
| 408 |
+
|
| 409 |
+
private createRandomInput(batchSize: number, seqLen: number): BigInt64Array {
|
| 410 |
+
const size = batchSize * seqLen;
|
| 411 |
+
const data = new BigInt64Array(size);
|
| 412 |
+
for (let i = 0; i < size; i++) {
|
| 413 |
+
data[i] = BigInt(Math.floor(Math.random() * this.config.vocabSize));
|
| 414 |
+
}
|
| 415 |
+
return data;
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
+
private padSequence(tokens: number[], targetLen: number): number[] {
|
| 419 |
+
const padded = [...tokens];
|
| 420 |
+
while (padded.length < targetLen) {
|
| 421 |
+
padded.push(this.PAD_TOKEN);
|
| 422 |
+
}
|
| 423 |
+
return padded.slice(0, targetLen); // Truncate if too long
|
| 424 |
+
}
|
| 425 |
+
|
| 426 |
+
private validateOutput(logits: OnnxTensor, batchSize: number, seqLen: number): void {
|
| 427 |
+
const expectedShape = [batchSize, seqLen, this.config.vocabSize];
|
| 428 |
+
|
| 429 |
+
if (logits.dims.length !== 3) {
|
| 430 |
+
throw new Error(`Expected 3D output, got ${logits.dims.length}D`);
|
| 431 |
+
}
|
| 432 |
+
|
| 433 |
+
if (
|
| 434 |
+
logits.dims[0] !== expectedShape[0] ||
|
| 435 |
+
logits.dims[1] !== expectedShape[1] ||
|
| 436 |
+
logits.dims[2] !== expectedShape[2]
|
| 437 |
+
) {
|
| 438 |
+
throw new Error(
|
| 439 |
+
`Shape mismatch! Expected [${expectedShape.join(", ")}], ` +
|
| 440 |
+
`got [${logits.dims.join(", ")}]`
|
| 441 |
+
);
|
| 442 |
+
}
|
| 443 |
+
|
| 444 |
+
if (logits.type !== "float32") {
|
| 445 |
+
throw new Error(`Expected float32 output, got ${logits.type}`);
|
| 446 |
+
}
|
| 447 |
+
}
|
| 448 |
+
|
| 449 |
+
private getPredictions(logitsData: Float32Array, numPositions: number): number[] {
|
| 450 |
+
const predictions: number[] = [];
|
| 451 |
+
for (let i = 0; i < numPositions; i++) {
|
| 452 |
+
let maxIdx = 0;
|
| 453 |
+
let maxVal = logitsData[i * this.config.vocabSize];
|
| 454 |
+
for (let j = 1; j < this.config.vocabSize; j++) {
|
| 455 |
+
const val = logitsData[i * this.config.vocabSize + j];
|
| 456 |
+
if (val > maxVal) {
|
| 457 |
+
maxVal = val;
|
| 458 |
+
maxIdx = j;
|
| 459 |
+
}
|
| 460 |
+
}
|
| 461 |
+
predictions.push(maxIdx);
|
| 462 |
+
}
|
| 463 |
+
return predictions;
|
| 464 |
+
}
|
| 465 |
+
}
|
trigo-web/inc/tgn/README.md
CHANGED
|
@@ -29,7 +29,7 @@ This will generate `tgn.jison.cjs` from `tgn.jison`.
|
|
| 29 |
Import the parser functions from the game module:
|
| 30 |
|
| 31 |
```typescript
|
| 32 |
-
import { TrigoGame, validateTGN, TGNParseError } from
|
| 33 |
|
| 34 |
// Parse TGN and create game instance
|
| 35 |
const tgn = `
|
|
@@ -37,24 +37,24 @@ const tgn = `
|
|
| 37 |
[Board 5x5x5]
|
| 38 |
|
| 39 |
1. 000 y00
|
| 40 |
-
2. 0y0
|
| 41 |
`;
|
| 42 |
|
| 43 |
try {
|
| 44 |
-
|
| 45 |
-
|
| 46 |
} catch (error) {
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
}
|
| 51 |
|
| 52 |
// Validate TGN without parsing
|
| 53 |
const result = validateTGN(tgn);
|
| 54 |
if (result.valid) {
|
| 55 |
-
|
| 56 |
} else {
|
| 57 |
-
|
| 58 |
}
|
| 59 |
```
|
| 60 |
|
|
@@ -78,7 +78,7 @@ Example:
|
|
| 78 |
|
| 79 |
1. 000 y00
|
| 80 |
2. 0y0 yy0
|
| 81 |
-
3. aaa
|
| 82 |
```
|
| 83 |
|
| 84 |
### Coordinate Notation (ab0yz)
|
|
@@ -88,12 +88,14 @@ Example:
|
|
| 88 |
- `z`, `y`, `x`, ... = positions from opposite edge toward center
|
| 89 |
|
| 90 |
Examples for 5×5×5 board:
|
|
|
|
| 91 |
- `000` = center (2,2,2)
|
| 92 |
- `aaa` = corner (0,0,0)
|
| 93 |
- `zzz` = opposite corner (4,4,4)
|
| 94 |
- `y00` = (4,2,2)
|
| 95 |
|
| 96 |
For 2D boards (e.g., 19×19×1), only two coordinates are used:
|
|
|
|
| 97 |
- `00` = center
|
| 98 |
- `aa` = corner
|
| 99 |
|
|
|
|
| 29 |
Import the parser functions from the game module:
|
| 30 |
|
| 31 |
```typescript
|
| 32 |
+
import { TrigoGame, validateTGN, TGNParseError } from "@inc/trigo/game";
|
| 33 |
|
| 34 |
// Parse TGN and create game instance
|
| 35 |
const tgn = `
|
|
|
|
| 37 |
[Board 5x5x5]
|
| 38 |
|
| 39 |
1. 000 y00
|
| 40 |
+
2. 0y0 Pass
|
| 41 |
`;
|
| 42 |
|
| 43 |
try {
|
| 44 |
+
const game = TrigoGame.fromTGN(tgn);
|
| 45 |
+
console.log("Game loaded successfully!");
|
| 46 |
} catch (error) {
|
| 47 |
+
if (error instanceof TGNParseError) {
|
| 48 |
+
console.error("Parse error at line", error.line);
|
| 49 |
+
}
|
| 50 |
}
|
| 51 |
|
| 52 |
// Validate TGN without parsing
|
| 53 |
const result = validateTGN(tgn);
|
| 54 |
if (result.valid) {
|
| 55 |
+
console.log("Valid TGN");
|
| 56 |
} else {
|
| 57 |
+
console.error("Invalid TGN:", result.error);
|
| 58 |
}
|
| 59 |
```
|
| 60 |
|
|
|
|
| 78 |
|
| 79 |
1. 000 y00
|
| 80 |
2. 0y0 yy0
|
| 81 |
+
3. aaa Pass
|
| 82 |
```
|
| 83 |
|
| 84 |
### Coordinate Notation (ab0yz)
|
|
|
|
| 88 |
- `z`, `y`, `x`, ... = positions from opposite edge toward center
|
| 89 |
|
| 90 |
Examples for 5×5×5 board:
|
| 91 |
+
|
| 92 |
- `000` = center (2,2,2)
|
| 93 |
- `aaa` = corner (0,0,0)
|
| 94 |
- `zzz` = opposite corner (4,4,4)
|
| 95 |
- `y00` = (4,2,2)
|
| 96 |
|
| 97 |
For 2D boards (e.g., 19×19×1), only two coordinates are used:
|
| 98 |
+
|
| 99 |
- `00` = center
|
| 100 |
- `aa` = corner
|
| 101 |
|
trigo-web/inc/tgn/tgn.jison
CHANGED
|
@@ -45,8 +45,8 @@
|
|
| 45 |
/* Move notation placeholders - will be expanded later */
|
| 46 |
[1-9][0-9]* return 'NUMBER'
|
| 47 |
"." return 'DOT'
|
| 48 |
-
"
|
| 49 |
-
"
|
| 50 |
"points" return 'POINTS'
|
| 51 |
"stones" return 'STONES'
|
| 52 |
|
|
|
|
| 45 |
/* Move notation placeholders - will be expanded later */
|
| 46 |
[1-9][0-9]* return 'NUMBER'
|
| 47 |
"." return 'DOT'
|
| 48 |
+
"Pass" return 'PASS'
|
| 49 |
+
"Resign" return 'RESIGN'
|
| 50 |
"points" return 'POINTS'
|
| 51 |
"stones" return 'STONES'
|
| 52 |
|
trigo-web/inc/tgn/tgnParser.ts
CHANGED
|
@@ -14,11 +14,10 @@
|
|
| 14 |
* Parsed move action - represents a single player's action in a round
|
| 15 |
*/
|
| 16 |
export interface ParsedMoveAction {
|
| 17 |
-
type:
|
| 18 |
-
position?: string;
|
| 19 |
}
|
| 20 |
|
| 21 |
-
|
| 22 |
/**
|
| 23 |
* Parsed move round - contains both black and white moves
|
| 24 |
*/
|
|
@@ -28,19 +27,17 @@ export interface ParsedMoveRound {
|
|
| 28 |
action_white?: ParsedMoveAction;
|
| 29 |
}
|
| 30 |
|
| 31 |
-
|
| 32 |
/**
|
| 33 |
* Parsed game result
|
| 34 |
*/
|
| 35 |
export interface ParsedGameResult {
|
| 36 |
-
Result: string;
|
| 37 |
Conquer?: {
|
| 38 |
n: number;
|
| 39 |
-
unit: string;
|
| 40 |
};
|
| 41 |
}
|
| 42 |
|
| 43 |
-
|
| 44 |
/**
|
| 45 |
* Parsed TGN tags (metadata)
|
| 46 |
*/
|
|
@@ -52,7 +49,7 @@ export interface ParsedTags {
|
|
| 52 |
Black?: string;
|
| 53 |
White?: string;
|
| 54 |
Result?: string;
|
| 55 |
-
Board?: number[];
|
| 56 |
Handicap?: string;
|
| 57 |
Rules?: string;
|
| 58 |
TimeControl?: string;
|
|
@@ -61,7 +58,6 @@ export interface ParsedTags {
|
|
| 61 |
[key: string]: string | number[] | ParsedGameResult | undefined;
|
| 62 |
}
|
| 63 |
|
| 64 |
-
|
| 65 |
/**
|
| 66 |
* Parser output structure
|
| 67 |
*/
|
|
@@ -71,7 +67,6 @@ export interface TGNParseResult {
|
|
| 71 |
success: boolean;
|
| 72 |
}
|
| 73 |
|
| 74 |
-
|
| 75 |
/**
|
| 76 |
* Parser error with position information
|
| 77 |
*/
|
|
@@ -83,15 +78,13 @@ export class TGNParseError extends Error {
|
|
| 83 |
public hash?: any
|
| 84 |
) {
|
| 85 |
super(message);
|
| 86 |
-
this.name =
|
| 87 |
}
|
| 88 |
}
|
| 89 |
|
| 90 |
-
|
| 91 |
// Will be set by initialization code or build process
|
| 92 |
let parserModule: any = null;
|
| 93 |
|
| 94 |
-
|
| 95 |
/**
|
| 96 |
* Set the parser module (called by initialization code)
|
| 97 |
* This allows the pre-built parser to be used
|
|
@@ -100,7 +93,6 @@ export function setParserModule(module: any): void {
|
|
| 100 |
parserModule = module;
|
| 101 |
}
|
| 102 |
|
| 103 |
-
|
| 104 |
/**
|
| 105 |
* Get the parser module
|
| 106 |
* Throws error if parser not loaded
|
|
@@ -108,14 +100,13 @@ export function setParserModule(module: any): void {
|
|
| 108 |
function getParser() {
|
| 109 |
if (!parserModule) {
|
| 110 |
throw new Error(
|
| 111 |
-
|
| 112 |
-
|
| 113 |
);
|
| 114 |
}
|
| 115 |
return parserModule;
|
| 116 |
}
|
| 117 |
|
| 118 |
-
|
| 119 |
/**
|
| 120 |
* Parse TGN string and return structured data
|
| 121 |
* Synchronous parsing (no async needed)
|
|
@@ -128,7 +119,7 @@ export function parseTGN(tgnString: string): TGNParseResult {
|
|
| 128 |
const parser = getParser();
|
| 129 |
|
| 130 |
if (!parser.parse) {
|
| 131 |
-
throw new Error(
|
| 132 |
}
|
| 133 |
|
| 134 |
try {
|
|
@@ -137,7 +128,7 @@ export function parseTGN(tgnString: string): TGNParseResult {
|
|
| 137 |
} catch (error: any) {
|
| 138 |
// Wrap jison errors with our custom error type
|
| 139 |
throw new TGNParseError(
|
| 140 |
-
error.message ||
|
| 141 |
error.hash?.line,
|
| 142 |
error.hash?.loc?.first_column,
|
| 143 |
error.hash
|
|
@@ -145,7 +136,6 @@ export function parseTGN(tgnString: string): TGNParseResult {
|
|
| 145 |
}
|
| 146 |
}
|
| 147 |
|
| 148 |
-
|
| 149 |
/**
|
| 150 |
* Validate TGN string without fully parsing
|
| 151 |
* Synchronous validation (no async needed)
|
|
@@ -160,7 +150,7 @@ export function validateTGN(tgnString: string): { valid: boolean; error?: string
|
|
| 160 |
} catch (error: any) {
|
| 161 |
return {
|
| 162 |
valid: false,
|
| 163 |
-
error: error.message ||
|
| 164 |
};
|
| 165 |
}
|
| 166 |
}
|
|
|
|
| 14 |
* Parsed move action - represents a single player's action in a round
|
| 15 |
*/
|
| 16 |
export interface ParsedMoveAction {
|
| 17 |
+
type: "move" | "pass" | "resign";
|
| 18 |
+
position?: string; // ab0yz coordinate notation
|
| 19 |
}
|
| 20 |
|
|
|
|
| 21 |
/**
|
| 22 |
* Parsed move round - contains both black and white moves
|
| 23 |
*/
|
|
|
|
| 27 |
action_white?: ParsedMoveAction;
|
| 28 |
}
|
| 29 |
|
|
|
|
| 30 |
/**
|
| 31 |
* Parsed game result
|
| 32 |
*/
|
| 33 |
export interface ParsedGameResult {
|
| 34 |
+
Result: string; // "black win" | "white win" | "draw" | "unknown"
|
| 35 |
Conquer?: {
|
| 36 |
n: number;
|
| 37 |
+
unit: string; // "points" | "stones"
|
| 38 |
};
|
| 39 |
}
|
| 40 |
|
|
|
|
| 41 |
/**
|
| 42 |
* Parsed TGN tags (metadata)
|
| 43 |
*/
|
|
|
|
| 49 |
Black?: string;
|
| 50 |
White?: string;
|
| 51 |
Result?: string;
|
| 52 |
+
Board?: number[]; // [x, y, z] or [x, y]
|
| 53 |
Handicap?: string;
|
| 54 |
Rules?: string;
|
| 55 |
TimeControl?: string;
|
|
|
|
| 58 |
[key: string]: string | number[] | ParsedGameResult | undefined;
|
| 59 |
}
|
| 60 |
|
|
|
|
| 61 |
/**
|
| 62 |
* Parser output structure
|
| 63 |
*/
|
|
|
|
| 67 |
success: boolean;
|
| 68 |
}
|
| 69 |
|
|
|
|
| 70 |
/**
|
| 71 |
* Parser error with position information
|
| 72 |
*/
|
|
|
|
| 78 |
public hash?: any
|
| 79 |
) {
|
| 80 |
super(message);
|
| 81 |
+
this.name = "TGNParseError";
|
| 82 |
}
|
| 83 |
}
|
| 84 |
|
|
|
|
| 85 |
// Will be set by initialization code or build process
|
| 86 |
let parserModule: any = null;
|
| 87 |
|
|
|
|
| 88 |
/**
|
| 89 |
* Set the parser module (called by initialization code)
|
| 90 |
* This allows the pre-built parser to be used
|
|
|
|
| 93 |
parserModule = module;
|
| 94 |
}
|
| 95 |
|
|
|
|
| 96 |
/**
|
| 97 |
* Get the parser module
|
| 98 |
* Throws error if parser not loaded
|
|
|
|
| 100 |
function getParser() {
|
| 101 |
if (!parserModule) {
|
| 102 |
throw new Error(
|
| 103 |
+
"TGN parser not loaded. Please ensure the parser has been built.\n" +
|
| 104 |
+
"Run: npm run build:parsers"
|
| 105 |
);
|
| 106 |
}
|
| 107 |
return parserModule;
|
| 108 |
}
|
| 109 |
|
|
|
|
| 110 |
/**
|
| 111 |
* Parse TGN string and return structured data
|
| 112 |
* Synchronous parsing (no async needed)
|
|
|
|
| 119 |
const parser = getParser();
|
| 120 |
|
| 121 |
if (!parser.parse) {
|
| 122 |
+
throw new Error("TGN parser parse method not available");
|
| 123 |
}
|
| 124 |
|
| 125 |
try {
|
|
|
|
| 128 |
} catch (error: any) {
|
| 129 |
// Wrap jison errors with our custom error type
|
| 130 |
throw new TGNParseError(
|
| 131 |
+
error.message || "Unknown parse error",
|
| 132 |
error.hash?.line,
|
| 133 |
error.hash?.loc?.first_column,
|
| 134 |
error.hash
|
|
|
|
| 136 |
}
|
| 137 |
}
|
| 138 |
|
|
|
|
| 139 |
/**
|
| 140 |
* Validate TGN string without fully parsing
|
| 141 |
* Synchronous validation (no async needed)
|
|
|
|
| 150 |
} catch (error: any) {
|
| 151 |
return {
|
| 152 |
valid: false,
|
| 153 |
+
error: error.message || "Unknown validation error"
|
| 154 |
};
|
| 155 |
}
|
| 156 |
}
|
trigo-web/inc/trigo/ab0yz.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
| 1 |
-
|
| 2 |
// remove ones at tail
|
| 3 |
-
const compactShape = (shape: number[]): number[] =>
|
| 4 |
-
|
| 5 |
|
| 6 |
/**
|
| 7 |
* Encode a position to TGN coordinate string.
|
|
@@ -32,7 +31,7 @@ const encodeAb0yz = (pos: number[], boardShape: number[]): string => {
|
|
| 32 |
|
| 33 |
if (index === center) {
|
| 34 |
// Center position
|
| 35 |
-
result.push(
|
| 36 |
} else if (index < center) {
|
| 37 |
// Left side: a, b, c, ...
|
| 38 |
result.push(String.fromCharCode(97 + index)); // 'a' = 97
|
|
@@ -43,10 +42,9 @@ const encodeAb0yz = (pos: number[], boardShape: number[]): string => {
|
|
| 43 |
}
|
| 44 |
}
|
| 45 |
|
| 46 |
-
return result.join(
|
| 47 |
};
|
| 48 |
|
| 49 |
-
|
| 50 |
/**
|
| 51 |
* Decode a TGN coordinate string to position array.
|
| 52 |
*
|
|
@@ -64,7 +62,9 @@ const decodeAb0yz = (code: string, boardShape: number[]): number[] => {
|
|
| 64 |
const compactedShape = compactShape(boardShape);
|
| 65 |
|
| 66 |
if (code.length !== compactedShape.length) {
|
| 67 |
-
throw new Error(
|
|
|
|
|
|
|
| 68 |
}
|
| 69 |
|
| 70 |
const result: number[] = [];
|
|
@@ -74,14 +74,15 @@ const decodeAb0yz = (code: string, boardShape: number[]): number[] => {
|
|
| 74 |
const size = compactedShape[i];
|
| 75 |
const center = (size - 1) / 2;
|
| 76 |
|
| 77 |
-
if (char ===
|
| 78 |
// Center position
|
| 79 |
console.assert(Number.isInteger(center));
|
| 80 |
result.push(center);
|
| 81 |
} else {
|
| 82 |
const charCode = char.charCodeAt(0);
|
| 83 |
|
| 84 |
-
if (charCode >= 97 && charCode <= 122) {
|
|
|
|
| 85 |
// Calculate distance from 'a' and 'z'
|
| 86 |
const distFromA = charCode - 97;
|
| 87 |
const distFromZ = 122 - charCode;
|
|
@@ -91,19 +92,25 @@ const decodeAb0yz = (code: string, boardShape: number[]): number[] => {
|
|
| 91 |
// Left side: a=0, b=1, c=2, ...
|
| 92 |
const index = distFromA;
|
| 93 |
if (index >= center) {
|
| 94 |
-
throw new Error(
|
|
|
|
|
|
|
| 95 |
}
|
| 96 |
result.push(index);
|
| 97 |
} else {
|
| 98 |
// Right side: z=size-1, y=size-2, x=size-3, ...
|
| 99 |
const index = size - 1 - distFromZ;
|
| 100 |
if (index <= center) {
|
| 101 |
-
throw new Error(
|
|
|
|
|
|
|
| 102 |
}
|
| 103 |
result.push(index);
|
| 104 |
}
|
| 105 |
} else {
|
| 106 |
-
throw new Error(
|
|
|
|
|
|
|
| 107 |
}
|
| 108 |
}
|
| 109 |
}
|
|
@@ -116,5 +123,4 @@ const decodeAb0yz = (code: string, boardShape: number[]): number[] => {
|
|
| 116 |
return result;
|
| 117 |
};
|
| 118 |
|
| 119 |
-
|
| 120 |
export { encodeAb0yz, decodeAb0yz };
|
|
|
|
|
|
|
| 1 |
// remove ones at tail
|
| 2 |
+
const compactShape = (shape: number[]): number[] =>
|
| 3 |
+
shape[shape.length - 1] === 1 ? compactShape(shape.slice(0, shape.length - 1)) : shape;
|
| 4 |
|
| 5 |
/**
|
| 6 |
* Encode a position to TGN coordinate string.
|
|
|
|
| 31 |
|
| 32 |
if (index === center) {
|
| 33 |
// Center position
|
| 34 |
+
result.push("0");
|
| 35 |
} else if (index < center) {
|
| 36 |
// Left side: a, b, c, ...
|
| 37 |
result.push(String.fromCharCode(97 + index)); // 'a' = 97
|
|
|
|
| 42 |
}
|
| 43 |
}
|
| 44 |
|
| 45 |
+
return result.join("");
|
| 46 |
};
|
| 47 |
|
|
|
|
| 48 |
/**
|
| 49 |
* Decode a TGN coordinate string to position array.
|
| 50 |
*
|
|
|
|
| 62 |
const compactedShape = compactShape(boardShape);
|
| 63 |
|
| 64 |
if (code.length !== compactedShape.length) {
|
| 65 |
+
throw new Error(
|
| 66 |
+
`Invalid TGN coordinate: "${code}" (must be ${compactedShape.length} characters for board shape ${boardShape.join("x")})`
|
| 67 |
+
);
|
| 68 |
}
|
| 69 |
|
| 70 |
const result: number[] = [];
|
|
|
|
| 74 |
const size = compactedShape[i];
|
| 75 |
const center = (size - 1) / 2;
|
| 76 |
|
| 77 |
+
if (char === "0") {
|
| 78 |
// Center position
|
| 79 |
console.assert(Number.isInteger(center));
|
| 80 |
result.push(center);
|
| 81 |
} else {
|
| 82 |
const charCode = char.charCodeAt(0);
|
| 83 |
|
| 84 |
+
if (charCode >= 97 && charCode <= 122) {
|
| 85 |
+
// 'a' to 'z'
|
| 86 |
// Calculate distance from 'a' and 'z'
|
| 87 |
const distFromA = charCode - 97;
|
| 88 |
const distFromZ = 122 - charCode;
|
|
|
|
| 92 |
// Left side: a=0, b=1, c=2, ...
|
| 93 |
const index = distFromA;
|
| 94 |
if (index >= center) {
|
| 95 |
+
throw new Error(
|
| 96 |
+
`Invalid TGN coordinate: "${code}" (position ${index} >= center ${center} on axis ${i})`
|
| 97 |
+
);
|
| 98 |
}
|
| 99 |
result.push(index);
|
| 100 |
} else {
|
| 101 |
// Right side: z=size-1, y=size-2, x=size-3, ...
|
| 102 |
const index = size - 1 - distFromZ;
|
| 103 |
if (index <= center) {
|
| 104 |
+
throw new Error(
|
| 105 |
+
`Invalid TGN coordinate: "${code}" (position ${index} <= center ${center} on axis ${i})`
|
| 106 |
+
);
|
| 107 |
}
|
| 108 |
result.push(index);
|
| 109 |
}
|
| 110 |
} else {
|
| 111 |
+
throw new Error(
|
| 112 |
+
`Invalid TGN coordinate: "${code}" (character '${char}' at position ${i} must be '0' or a-z)`
|
| 113 |
+
);
|
| 114 |
}
|
| 115 |
}
|
| 116 |
}
|
|
|
|
| 123 |
return result;
|
| 124 |
};
|
| 125 |
|
|
|
|
| 126 |
export { encodeAb0yz, decodeAb0yz };
|
trigo-web/inc/trigo/game.ts
CHANGED
|
@@ -15,34 +15,32 @@ import {
|
|
| 15 |
findCapturedGroups,
|
| 16 |
executeCaptures,
|
| 17 |
calculateTerritory,
|
|
|
|
|
|
|
| 18 |
type TerritoryResult
|
| 19 |
} from "./gameUtils";
|
| 20 |
import { encodeAb0yz, decodeAb0yz } from "./ab0yz";
|
| 21 |
import { parseTGN, validateTGN, TGNParseError } from "../tgn/tgnParser";
|
| 22 |
|
| 23 |
-
|
| 24 |
// Re-export StoneType for convenient access with TrigoGame
|
| 25 |
export { StoneType } from "./gameUtils";
|
| 26 |
|
| 27 |
-
|
| 28 |
/**
|
| 29 |
* Step Types - Different types of moves in the game
|
| 30 |
* Equivalent to trigo.Game.StepType in prototype
|
| 31 |
*/
|
| 32 |
export enum StepType {
|
| 33 |
-
DROP = 0,
|
| 34 |
-
PASS = 1,
|
| 35 |
SURRENDER = 2, // Resign/surrender
|
| 36 |
-
UNDO = 3
|
| 37 |
}
|
| 38 |
|
| 39 |
-
|
| 40 |
/**
|
| 41 |
* Game Status enumeration
|
| 42 |
*/
|
| 43 |
export type GameStatus = "idle" | "playing" | "paused" | "finished";
|
| 44 |
|
| 45 |
-
|
| 46 |
/**
|
| 47 |
* Game Result information
|
| 48 |
*/
|
|
@@ -52,20 +50,18 @@ export interface GameResult {
|
|
| 52 |
score?: TerritoryResult;
|
| 53 |
}
|
| 54 |
|
| 55 |
-
|
| 56 |
/**
|
| 57 |
* Step - Represents a single move in the game
|
| 58 |
* Equivalent to step objects in prototype's StepHistory
|
| 59 |
*/
|
| 60 |
export interface Step {
|
| 61 |
type: StepType;
|
| 62 |
-
position?: Position;
|
| 63 |
-
player: Stone;
|
| 64 |
capturedPositions?: Position[]; // Stones captured by this move
|
| 65 |
-
timestamp: number;
|
| 66 |
}
|
| 67 |
|
| 68 |
-
|
| 69 |
/**
|
| 70 |
* Game Callbacks - Event handlers for game state changes
|
| 71 |
* Equivalent to Callbacks in prototype's trigo.Game constructor
|
|
@@ -78,7 +74,6 @@ export interface GameCallbacks {
|
|
| 78 |
onTerritoryChange?: (territory: TerritoryResult) => void;
|
| 79 |
}
|
| 80 |
|
| 81 |
-
|
| 82 |
/**
|
| 83 |
* TrigoGame - Main game class managing state, history, and logic
|
| 84 |
*
|
|
@@ -114,7 +109,6 @@ export class TrigoGame {
|
|
| 114 |
private territoryDirty: boolean = true;
|
| 115 |
private cachedTerritory: TerritoryResult | null = null;
|
| 116 |
|
| 117 |
-
|
| 118 |
/**
|
| 119 |
* Constructor
|
| 120 |
* Equivalent to trigo.Game constructor (lines 75-85)
|
|
@@ -131,7 +125,6 @@ export class TrigoGame {
|
|
| 131 |
this.passCount = 0;
|
| 132 |
}
|
| 133 |
|
| 134 |
-
|
| 135 |
/**
|
| 136 |
* Create an empty board
|
| 137 |
*/
|
|
@@ -149,7 +142,6 @@ export class TrigoGame {
|
|
| 149 |
return board;
|
| 150 |
}
|
| 151 |
|
| 152 |
-
|
| 153 |
/**
|
| 154 |
* Reset the game to initial state
|
| 155 |
* Equivalent to Game.reset() (lines 153-163)
|
|
@@ -167,16 +159,59 @@ export class TrigoGame {
|
|
| 167 |
this.passCount = 0;
|
| 168 |
}
|
| 169 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
|
| 171 |
/**
|
| 172 |
* Get current board state (read-only)
|
| 173 |
*/
|
| 174 |
getBoard(): Stone[][][] {
|
| 175 |
// Return a deep copy to prevent external modification
|
| 176 |
-
return this.board.map(plane => plane.map(row => [...row]));
|
| 177 |
}
|
| 178 |
|
| 179 |
-
|
| 180 |
/**
|
| 181 |
* Get stone at specific position
|
| 182 |
* Equivalent to Game.stone() (lines 95-97)
|
|
@@ -185,7 +220,6 @@ export class TrigoGame {
|
|
| 185 |
return this.board[pos.x][pos.y][pos.z];
|
| 186 |
}
|
| 187 |
|
| 188 |
-
|
| 189 |
/**
|
| 190 |
* Get current player
|
| 191 |
*/
|
|
@@ -193,7 +227,6 @@ export class TrigoGame {
|
|
| 193 |
return this.currentPlayer;
|
| 194 |
}
|
| 195 |
|
| 196 |
-
|
| 197 |
/**
|
| 198 |
* Get current step number
|
| 199 |
* Equivalent to Game.currentStep() (lines 99-101)
|
|
@@ -202,7 +235,6 @@ export class TrigoGame {
|
|
| 202 |
return this.currentStepIndex;
|
| 203 |
}
|
| 204 |
|
| 205 |
-
|
| 206 |
/**
|
| 207 |
* Get move history
|
| 208 |
* Equivalent to Game.routine() (lines 103-105)
|
|
@@ -211,7 +243,6 @@ export class TrigoGame {
|
|
| 211 |
return [...this.stepHistory];
|
| 212 |
}
|
| 213 |
|
| 214 |
-
|
| 215 |
/**
|
| 216 |
* Get last move
|
| 217 |
* Equivalent to Game.lastStep() (lines 107-110)
|
|
@@ -223,7 +254,6 @@ export class TrigoGame {
|
|
| 223 |
return null;
|
| 224 |
}
|
| 225 |
|
| 226 |
-
|
| 227 |
/**
|
| 228 |
* Get board shape
|
| 229 |
* Equivalent to Game.shape() (lines 87-89)
|
|
@@ -232,7 +262,6 @@ export class TrigoGame {
|
|
| 232 |
return { ...this.shape };
|
| 233 |
}
|
| 234 |
|
| 235 |
-
|
| 236 |
/**
|
| 237 |
* Get game status
|
| 238 |
*/
|
|
@@ -240,7 +269,6 @@ export class TrigoGame {
|
|
| 240 |
return this.gameStatus;
|
| 241 |
}
|
| 242 |
|
| 243 |
-
|
| 244 |
/**
|
| 245 |
* Set game status
|
| 246 |
*/
|
|
@@ -248,7 +276,6 @@ export class TrigoGame {
|
|
| 248 |
this.gameStatus = status;
|
| 249 |
}
|
| 250 |
|
| 251 |
-
|
| 252 |
/**
|
| 253 |
* Get game result
|
| 254 |
*/
|
|
@@ -256,7 +283,6 @@ export class TrigoGame {
|
|
| 256 |
return this.gameResult;
|
| 257 |
}
|
| 258 |
|
| 259 |
-
|
| 260 |
/**
|
| 261 |
* Get consecutive pass count
|
| 262 |
*/
|
|
@@ -264,7 +290,6 @@ export class TrigoGame {
|
|
| 264 |
return this.passCount;
|
| 265 |
}
|
| 266 |
|
| 267 |
-
|
| 268 |
/**
|
| 269 |
* Recalculate consecutive pass count based on current history
|
| 270 |
* Counts consecutive PASS steps from the end of current history
|
|
@@ -282,7 +307,6 @@ export class TrigoGame {
|
|
| 282 |
}
|
| 283 |
}
|
| 284 |
|
| 285 |
-
|
| 286 |
/**
|
| 287 |
* Start the game
|
| 288 |
*/
|
|
@@ -292,7 +316,6 @@ export class TrigoGame {
|
|
| 292 |
}
|
| 293 |
}
|
| 294 |
|
| 295 |
-
|
| 296 |
/**
|
| 297 |
* Check if game is active
|
| 298 |
*/
|
|
@@ -300,7 +323,6 @@ export class TrigoGame {
|
|
| 300 |
return this.gameStatus === "playing";
|
| 301 |
}
|
| 302 |
|
| 303 |
-
|
| 304 |
/**
|
| 305 |
* Check if a move is valid
|
| 306 |
* Equivalent to Game.isDropable() and Game.isValidStep() (lines 112-151)
|
|
@@ -310,6 +332,59 @@ export class TrigoGame {
|
|
| 310 |
return validateMove(pos, playerColor, this.board, this.shape, this.lastCapturedPositions);
|
| 311 |
}
|
| 312 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 313 |
|
| 314 |
/**
|
| 315 |
* Reset pass count (called when a stone is placed)
|
|
@@ -318,7 +393,6 @@ export class TrigoGame {
|
|
| 318 |
this.passCount = 0;
|
| 319 |
}
|
| 320 |
|
| 321 |
-
|
| 322 |
/**
|
| 323 |
* Place a stone (drop move)
|
| 324 |
* Equivalent to Game.drop() and Game.appendStone() (lines 181-273)
|
|
@@ -375,7 +449,6 @@ export class TrigoGame {
|
|
| 375 |
return true;
|
| 376 |
}
|
| 377 |
|
| 378 |
-
|
| 379 |
/**
|
| 380 |
* Pass turn
|
| 381 |
* Equivalent to PASS step type in prototype
|
|
@@ -422,8 +495,12 @@ export class TrigoGame {
|
|
| 422 |
|
| 423 |
// Trigger win callback
|
| 424 |
if (this.callbacks.onWin) {
|
| 425 |
-
const winnerStone =
|
| 426 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 427 |
this.callbacks.onWin(winnerStone);
|
| 428 |
}
|
| 429 |
}
|
|
@@ -431,13 +508,12 @@ export class TrigoGame {
|
|
| 431 |
return true;
|
| 432 |
}
|
| 433 |
|
| 434 |
-
|
| 435 |
/**
|
| 436 |
* Surrender/resign
|
| 437 |
* Equivalent to Game.step() with SURRENDER type (lines 176-178)
|
| 438 |
*/
|
| 439 |
surrender(): boolean {
|
| 440 |
-
const surrenderingPlayer = this.currentPlayer;
|
| 441 |
|
| 442 |
const step: Step = {
|
| 443 |
type: StepType.SURRENDER,
|
|
@@ -464,7 +540,6 @@ export class TrigoGame {
|
|
| 464 |
return true;
|
| 465 |
}
|
| 466 |
|
| 467 |
-
|
| 468 |
/**
|
| 469 |
* Undo last move
|
| 470 |
* Equivalent to Game.repent() (lines 197-230)
|
|
@@ -481,7 +556,8 @@ export class TrigoGame {
|
|
| 481 |
// Revert the move
|
| 482 |
if (lastStep.type === StepType.DROP && lastStep.position) {
|
| 483 |
// Remove the placed stone
|
| 484 |
-
this.board[lastStep.position.x][lastStep.position.y][lastStep.position.z] =
|
|
|
|
| 485 |
|
| 486 |
// Restore captured stones
|
| 487 |
if (lastStep.capturedPositions) {
|
|
@@ -519,7 +595,6 @@ export class TrigoGame {
|
|
| 519 |
return true;
|
| 520 |
}
|
| 521 |
|
| 522 |
-
|
| 523 |
/**
|
| 524 |
* Redo next move (after undo)
|
| 525 |
*
|
|
@@ -536,7 +611,8 @@ export class TrigoGame {
|
|
| 536 |
// Re-apply the move
|
| 537 |
if (nextStep.type === StepType.DROP && nextStep.position) {
|
| 538 |
// Place the stone
|
| 539 |
-
this.board[nextStep.position.x][nextStep.position.y][nextStep.position.z] =
|
|
|
|
| 540 |
|
| 541 |
// Re-execute captures if there were any
|
| 542 |
if (nextStep.capturedPositions) {
|
|
@@ -560,13 +636,15 @@ export class TrigoGame {
|
|
| 560 |
|
| 561 |
// Trigger callback
|
| 562 |
if (this.callbacks.onStepAdvance) {
|
| 563 |
-
this.callbacks.onStepAdvance(
|
|
|
|
|
|
|
|
|
|
| 564 |
}
|
| 565 |
|
| 566 |
return true;
|
| 567 |
}
|
| 568 |
|
| 569 |
-
|
| 570 |
/**
|
| 571 |
* Check if redo is available
|
| 572 |
*/
|
|
@@ -574,7 +652,6 @@ export class TrigoGame {
|
|
| 574 |
return this.currentStepIndex < this.stepHistory.length;
|
| 575 |
}
|
| 576 |
|
| 577 |
-
|
| 578 |
/**
|
| 579 |
* Jump to specific step in history
|
| 580 |
* Rebuilds board state after applying the first 'index' moves
|
|
@@ -656,7 +733,6 @@ export class TrigoGame {
|
|
| 656 |
return true;
|
| 657 |
}
|
| 658 |
|
| 659 |
-
|
| 660 |
/**
|
| 661 |
* Advance to next step
|
| 662 |
* Equivalent to Game.stepAdvance() (lines 279-287)
|
|
@@ -680,7 +756,6 @@ export class TrigoGame {
|
|
| 680 |
}
|
| 681 |
}
|
| 682 |
|
| 683 |
-
|
| 684 |
/**
|
| 685 |
* Get territory calculation
|
| 686 |
* Equivalent to Game.blackDomain() and Game.whiteDomain() (lines 232-244)
|
|
@@ -695,7 +770,6 @@ export class TrigoGame {
|
|
| 695 |
return this.cachedTerritory;
|
| 696 |
}
|
| 697 |
|
| 698 |
-
|
| 699 |
/**
|
| 700 |
* Get captured stone counts up to current position in history
|
| 701 |
* Only counts captures that have been played (up to currentStepIndex)
|
|
@@ -720,7 +794,6 @@ export class TrigoGame {
|
|
| 720 |
return counts;
|
| 721 |
}
|
| 722 |
|
| 723 |
-
|
| 724 |
/**
|
| 725 |
* Serialize game state to JSON
|
| 726 |
* Equivalent to Game.serialize() (lines 250-252)
|
|
@@ -738,7 +811,6 @@ export class TrigoGame {
|
|
| 738 |
};
|
| 739 |
}
|
| 740 |
|
| 741 |
-
|
| 742 |
/**
|
| 743 |
* Load game state from JSON
|
| 744 |
*/
|
|
@@ -780,7 +852,6 @@ export class TrigoGame {
|
|
| 780 |
}
|
| 781 |
}
|
| 782 |
|
| 783 |
-
|
| 784 |
/**
|
| 785 |
* Get game statistics
|
| 786 |
*/
|
|
@@ -818,7 +889,6 @@ export class TrigoGame {
|
|
| 818 |
};
|
| 819 |
}
|
| 820 |
|
| 821 |
-
|
| 822 |
/**
|
| 823 |
* Save game state to sessionStorage
|
| 824 |
*
|
|
@@ -842,7 +912,6 @@ export class TrigoGame {
|
|
| 842 |
return false;
|
| 843 |
}
|
| 844 |
|
| 845 |
-
|
| 846 |
/**
|
| 847 |
* Load game state from sessionStorage
|
| 848 |
*
|
|
@@ -871,7 +940,6 @@ export class TrigoGame {
|
|
| 871 |
return false;
|
| 872 |
}
|
| 873 |
|
| 874 |
-
|
| 875 |
/**
|
| 876 |
* Clear saved game state from sessionStorage
|
| 877 |
*
|
|
@@ -890,7 +958,6 @@ export class TrigoGame {
|
|
| 890 |
}
|
| 891 |
}
|
| 892 |
|
| 893 |
-
|
| 894 |
/**
|
| 895 |
* Export game to TGN (Trigo Game Notation) format
|
| 896 |
*
|
|
@@ -950,16 +1017,17 @@ export class TrigoGame {
|
|
| 950 |
const diff = Math.abs(black - white);
|
| 951 |
resultStr += `${diff}points`;
|
| 952 |
} else if (this.gameResult.reason === "resignation") {
|
| 953 |
-
resultStr += "
|
| 954 |
}
|
| 955 |
|
| 956 |
lines.push(`[Result "${resultStr}"]`);
|
| 957 |
}
|
| 958 |
|
| 959 |
// Add board size (without quotes - parser expects unquoted board shape)
|
| 960 |
-
const boardStr =
|
| 961 |
-
|
| 962 |
-
|
|
|
|
| 963 |
lines.push(`[Board ${boardStr}]`);
|
| 964 |
|
| 965 |
// Add optional metadata
|
|
@@ -993,9 +1061,9 @@ export class TrigoGame {
|
|
| 993 |
const coord = encodeAb0yz(pos, boardShape);
|
| 994 |
moveStr += coord;
|
| 995 |
} else if (step.type === StepType.PASS) {
|
| 996 |
-
moveStr += "
|
| 997 |
} else if (step.type === StepType.SURRENDER) {
|
| 998 |
-
moveStr += "
|
| 999 |
}
|
| 1000 |
|
| 1001 |
moves.push(moveStr);
|
|
@@ -1035,7 +1103,6 @@ export class TrigoGame {
|
|
| 1035 |
return lines.join("\n");
|
| 1036 |
}
|
| 1037 |
|
| 1038 |
-
|
| 1039 |
/**
|
| 1040 |
* Import game from TGN (Trigo Game Notation) format
|
| 1041 |
*
|
|
@@ -1103,7 +1170,6 @@ export class TrigoGame {
|
|
| 1103 |
return game;
|
| 1104 |
}
|
| 1105 |
|
| 1106 |
-
|
| 1107 |
/**
|
| 1108 |
* Apply a parsed move action to the game
|
| 1109 |
* Private helper method for fromTGN
|
|
@@ -1111,12 +1177,15 @@ export class TrigoGame {
|
|
| 1111 |
* @param action Parsed move action from TGN parser
|
| 1112 |
* @param boardShape Board dimensions for coordinate decoding
|
| 1113 |
*/
|
| 1114 |
-
private _applyParsedMove(
|
| 1115 |
-
|
|
|
|
|
|
|
|
|
|
| 1116 |
this.pass();
|
| 1117 |
-
} else if (action.type ===
|
| 1118 |
this.surrender();
|
| 1119 |
-
} else if (action.type ===
|
| 1120 |
// Decode ab0yz coordinate to Position
|
| 1121 |
const coords = decodeAb0yz(action.position, [boardShape.x, boardShape.y, boardShape.z]);
|
| 1122 |
const position: Position = {
|
|
@@ -1131,7 +1200,5 @@ export class TrigoGame {
|
|
| 1131 |
}
|
| 1132 |
}
|
| 1133 |
|
| 1134 |
-
|
| 1135 |
// Re-export parser utilities for convenience
|
| 1136 |
export { validateTGN, TGNParseError } from "../tgn/tgnParser";
|
| 1137 |
-
|
|
|
|
| 15 |
findCapturedGroups,
|
| 16 |
executeCaptures,
|
| 17 |
calculateTerritory,
|
| 18 |
+
isKoViolation,
|
| 19 |
+
isSuicideMove,
|
| 20 |
type TerritoryResult
|
| 21 |
} from "./gameUtils";
|
| 22 |
import { encodeAb0yz, decodeAb0yz } from "./ab0yz";
|
| 23 |
import { parseTGN, validateTGN, TGNParseError } from "../tgn/tgnParser";
|
| 24 |
|
|
|
|
| 25 |
// Re-export StoneType for convenient access with TrigoGame
|
| 26 |
export { StoneType } from "./gameUtils";
|
| 27 |
|
|
|
|
| 28 |
/**
|
| 29 |
* Step Types - Different types of moves in the game
|
| 30 |
* Equivalent to trigo.Game.StepType in prototype
|
| 31 |
*/
|
| 32 |
export enum StepType {
|
| 33 |
+
DROP = 0, // Place a stone
|
| 34 |
+
PASS = 1, // Pass turn
|
| 35 |
SURRENDER = 2, // Resign/surrender
|
| 36 |
+
UNDO = 3 // Undo last move (called "REPENT" in prototype)
|
| 37 |
}
|
| 38 |
|
|
|
|
| 39 |
/**
|
| 40 |
* Game Status enumeration
|
| 41 |
*/
|
| 42 |
export type GameStatus = "idle" | "playing" | "paused" | "finished";
|
| 43 |
|
|
|
|
| 44 |
/**
|
| 45 |
* Game Result information
|
| 46 |
*/
|
|
|
|
| 50 |
score?: TerritoryResult;
|
| 51 |
}
|
| 52 |
|
|
|
|
| 53 |
/**
|
| 54 |
* Step - Represents a single move in the game
|
| 55 |
* Equivalent to step objects in prototype's StepHistory
|
| 56 |
*/
|
| 57 |
export interface Step {
|
| 58 |
type: StepType;
|
| 59 |
+
position?: Position; // Only for DROP moves
|
| 60 |
+
player: Stone; // Which player made this move
|
| 61 |
capturedPositions?: Position[]; // Stones captured by this move
|
| 62 |
+
timestamp: number; // When the move was made
|
| 63 |
}
|
| 64 |
|
|
|
|
| 65 |
/**
|
| 66 |
* Game Callbacks - Event handlers for game state changes
|
| 67 |
* Equivalent to Callbacks in prototype's trigo.Game constructor
|
|
|
|
| 74 |
onTerritoryChange?: (territory: TerritoryResult) => void;
|
| 75 |
}
|
| 76 |
|
|
|
|
| 77 |
/**
|
| 78 |
* TrigoGame - Main game class managing state, history, and logic
|
| 79 |
*
|
|
|
|
| 109 |
private territoryDirty: boolean = true;
|
| 110 |
private cachedTerritory: TerritoryResult | null = null;
|
| 111 |
|
|
|
|
| 112 |
/**
|
| 113 |
* Constructor
|
| 114 |
* Equivalent to trigo.Game constructor (lines 75-85)
|
|
|
|
| 125 |
this.passCount = 0;
|
| 126 |
}
|
| 127 |
|
|
|
|
| 128 |
/**
|
| 129 |
* Create an empty board
|
| 130 |
*/
|
|
|
|
| 142 |
return board;
|
| 143 |
}
|
| 144 |
|
|
|
|
| 145 |
/**
|
| 146 |
* Reset the game to initial state
|
| 147 |
* Equivalent to Game.reset() (lines 153-163)
|
|
|
|
| 159 |
this.passCount = 0;
|
| 160 |
}
|
| 161 |
|
| 162 |
+
/**
|
| 163 |
+
* Clone the game state (deep copy)
|
| 164 |
+
* Creates an independent copy with all state preserved
|
| 165 |
+
*/
|
| 166 |
+
clone(): TrigoGame {
|
| 167 |
+
const cloned = new TrigoGame(this.shape, {});
|
| 168 |
+
|
| 169 |
+
// Deep copy board
|
| 170 |
+
cloned.board = this.board.map((plane) => plane.map((row) => [...row]));
|
| 171 |
+
|
| 172 |
+
// Copy game state
|
| 173 |
+
cloned.currentPlayer = this.currentPlayer;
|
| 174 |
+
cloned.currentStepIndex = this.currentStepIndex;
|
| 175 |
+
cloned.gameStatus = this.gameStatus;
|
| 176 |
+
cloned.passCount = this.passCount;
|
| 177 |
+
|
| 178 |
+
// Deep copy step history
|
| 179 |
+
cloned.stepHistory = this.stepHistory.map((step) => ({
|
| 180 |
+
...step,
|
| 181 |
+
position: step.position ? { ...step.position } : undefined,
|
| 182 |
+
capturedPositions: step.capturedPositions
|
| 183 |
+
? step.capturedPositions.map((pos) => ({ ...pos }))
|
| 184 |
+
: []
|
| 185 |
+
}));
|
| 186 |
+
|
| 187 |
+
// Deep copy last captured positions
|
| 188 |
+
cloned.lastCapturedPositions = this.lastCapturedPositions
|
| 189 |
+
? this.lastCapturedPositions.map((pos) => ({ ...pos }))
|
| 190 |
+
: null;
|
| 191 |
+
|
| 192 |
+
// Copy game result
|
| 193 |
+
if (this.gameResult) {
|
| 194 |
+
cloned.gameResult = {
|
| 195 |
+
...this.gameResult,
|
| 196 |
+
score: this.gameResult.score ? { ...this.gameResult.score } : undefined
|
| 197 |
+
};
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
// Territory cache will be recalculated on demand
|
| 201 |
+
cloned.territoryDirty = true;
|
| 202 |
+
cloned.cachedTerritory = null;
|
| 203 |
+
|
| 204 |
+
return cloned;
|
| 205 |
+
}
|
| 206 |
|
| 207 |
/**
|
| 208 |
* Get current board state (read-only)
|
| 209 |
*/
|
| 210 |
getBoard(): Stone[][][] {
|
| 211 |
// Return a deep copy to prevent external modification
|
| 212 |
+
return this.board.map((plane) => plane.map((row) => [...row]));
|
| 213 |
}
|
| 214 |
|
|
|
|
| 215 |
/**
|
| 216 |
* Get stone at specific position
|
| 217 |
* Equivalent to Game.stone() (lines 95-97)
|
|
|
|
| 220 |
return this.board[pos.x][pos.y][pos.z];
|
| 221 |
}
|
| 222 |
|
|
|
|
| 223 |
/**
|
| 224 |
* Get current player
|
| 225 |
*/
|
|
|
|
| 227 |
return this.currentPlayer;
|
| 228 |
}
|
| 229 |
|
|
|
|
| 230 |
/**
|
| 231 |
* Get current step number
|
| 232 |
* Equivalent to Game.currentStep() (lines 99-101)
|
|
|
|
| 235 |
return this.currentStepIndex;
|
| 236 |
}
|
| 237 |
|
|
|
|
| 238 |
/**
|
| 239 |
* Get move history
|
| 240 |
* Equivalent to Game.routine() (lines 103-105)
|
|
|
|
| 243 |
return [...this.stepHistory];
|
| 244 |
}
|
| 245 |
|
|
|
|
| 246 |
/**
|
| 247 |
* Get last move
|
| 248 |
* Equivalent to Game.lastStep() (lines 107-110)
|
|
|
|
| 254 |
return null;
|
| 255 |
}
|
| 256 |
|
|
|
|
| 257 |
/**
|
| 258 |
* Get board shape
|
| 259 |
* Equivalent to Game.shape() (lines 87-89)
|
|
|
|
| 262 |
return { ...this.shape };
|
| 263 |
}
|
| 264 |
|
|
|
|
| 265 |
/**
|
| 266 |
* Get game status
|
| 267 |
*/
|
|
|
|
| 269 |
return this.gameStatus;
|
| 270 |
}
|
| 271 |
|
|
|
|
| 272 |
/**
|
| 273 |
* Set game status
|
| 274 |
*/
|
|
|
|
| 276 |
this.gameStatus = status;
|
| 277 |
}
|
| 278 |
|
|
|
|
| 279 |
/**
|
| 280 |
* Get game result
|
| 281 |
*/
|
|
|
|
| 283 |
return this.gameResult;
|
| 284 |
}
|
| 285 |
|
|
|
|
| 286 |
/**
|
| 287 |
* Get consecutive pass count
|
| 288 |
*/
|
|
|
|
| 290 |
return this.passCount;
|
| 291 |
}
|
| 292 |
|
|
|
|
| 293 |
/**
|
| 294 |
* Recalculate consecutive pass count based on current history
|
| 295 |
* Counts consecutive PASS steps from the end of current history
|
|
|
|
| 307 |
}
|
| 308 |
}
|
| 309 |
|
|
|
|
| 310 |
/**
|
| 311 |
* Start the game
|
| 312 |
*/
|
|
|
|
| 316 |
}
|
| 317 |
}
|
| 318 |
|
|
|
|
| 319 |
/**
|
| 320 |
* Check if game is active
|
| 321 |
*/
|
|
|
|
| 323 |
return this.gameStatus === "playing";
|
| 324 |
}
|
| 325 |
|
|
|
|
| 326 |
/**
|
| 327 |
* Check if a move is valid
|
| 328 |
* Equivalent to Game.isDropable() and Game.isValidStep() (lines 112-151)
|
|
|
|
| 332 |
return validateMove(pos, playerColor, this.board, this.shape, this.lastCapturedPositions);
|
| 333 |
}
|
| 334 |
|
| 335 |
+
/**
|
| 336 |
+
* Get all valid move positions for current player (efficient batch query)
|
| 337 |
+
*
|
| 338 |
+
* This method is optimized to avoid repeated validation checks by:
|
| 339 |
+
* 1. Only checking empty positions
|
| 340 |
+
* 2. Skipping bounds checking (iterator is already within bounds)
|
| 341 |
+
* 3. Using low-level validation functions directly
|
| 342 |
+
* 4. Batching board state access
|
| 343 |
+
*
|
| 344 |
+
* @param player - Optional player color (defaults to current player)
|
| 345 |
+
* @returns Array of all valid move positions
|
| 346 |
+
*/
|
| 347 |
+
validMovePositions(player?: Stone): Position[] {
|
| 348 |
+
const playerColor = player || this.currentPlayer;
|
| 349 |
+
const validPositions: Position[] = [];
|
| 350 |
+
|
| 351 |
+
// Iterate through all board positions (bounds are guaranteed)
|
| 352 |
+
for (let x = 0; x < this.shape.x; x++) {
|
| 353 |
+
for (let y = 0; y < this.shape.y; y++) {
|
| 354 |
+
for (let z = 0; z < this.shape.z; z++) {
|
| 355 |
+
// Skip occupied positions (quick filter)
|
| 356 |
+
if (this.board[x][y][z] !== StoneType.EMPTY) {
|
| 357 |
+
continue;
|
| 358 |
+
}
|
| 359 |
+
|
| 360 |
+
const pos: Position = { x, y, z };
|
| 361 |
+
|
| 362 |
+
// Check Ko violation (using low-level function)
|
| 363 |
+
if (
|
| 364 |
+
isKoViolation(
|
| 365 |
+
pos,
|
| 366 |
+
playerColor,
|
| 367 |
+
this.board,
|
| 368 |
+
this.shape,
|
| 369 |
+
this.lastCapturedPositions
|
| 370 |
+
)
|
| 371 |
+
) {
|
| 372 |
+
continue;
|
| 373 |
+
}
|
| 374 |
+
|
| 375 |
+
// Check suicide rule (using low-level function)
|
| 376 |
+
if (isSuicideMove(pos, playerColor, this.board, this.shape)) {
|
| 377 |
+
continue;
|
| 378 |
+
}
|
| 379 |
+
|
| 380 |
+
// Position is valid
|
| 381 |
+
validPositions.push(pos);
|
| 382 |
+
}
|
| 383 |
+
}
|
| 384 |
+
}
|
| 385 |
+
|
| 386 |
+
return validPositions;
|
| 387 |
+
}
|
| 388 |
|
| 389 |
/**
|
| 390 |
* Reset pass count (called when a stone is placed)
|
|
|
|
| 393 |
this.passCount = 0;
|
| 394 |
}
|
| 395 |
|
|
|
|
| 396 |
/**
|
| 397 |
* Place a stone (drop move)
|
| 398 |
* Equivalent to Game.drop() and Game.appendStone() (lines 181-273)
|
|
|
|
| 449 |
return true;
|
| 450 |
}
|
| 451 |
|
|
|
|
| 452 |
/**
|
| 453 |
* Pass turn
|
| 454 |
* Equivalent to PASS step type in prototype
|
|
|
|
| 495 |
|
| 496 |
// Trigger win callback
|
| 497 |
if (this.callbacks.onWin) {
|
| 498 |
+
const winnerStone =
|
| 499 |
+
winner === "black"
|
| 500 |
+
? StoneType.BLACK
|
| 501 |
+
: winner === "white"
|
| 502 |
+
? StoneType.WHITE
|
| 503 |
+
: StoneType.EMPTY;
|
| 504 |
this.callbacks.onWin(winnerStone);
|
| 505 |
}
|
| 506 |
}
|
|
|
|
| 508 |
return true;
|
| 509 |
}
|
| 510 |
|
|
|
|
| 511 |
/**
|
| 512 |
* Surrender/resign
|
| 513 |
* Equivalent to Game.step() with SURRENDER type (lines 176-178)
|
| 514 |
*/
|
| 515 |
surrender(): boolean {
|
| 516 |
+
const surrenderingPlayer = this.currentPlayer; // Remember who surrendered
|
| 517 |
|
| 518 |
const step: Step = {
|
| 519 |
type: StepType.SURRENDER,
|
|
|
|
| 540 |
return true;
|
| 541 |
}
|
| 542 |
|
|
|
|
| 543 |
/**
|
| 544 |
* Undo last move
|
| 545 |
* Equivalent to Game.repent() (lines 197-230)
|
|
|
|
| 556 |
// Revert the move
|
| 557 |
if (lastStep.type === StepType.DROP && lastStep.position) {
|
| 558 |
// Remove the placed stone
|
| 559 |
+
this.board[lastStep.position.x][lastStep.position.y][lastStep.position.z] =
|
| 560 |
+
StoneType.EMPTY;
|
| 561 |
|
| 562 |
// Restore captured stones
|
| 563 |
if (lastStep.capturedPositions) {
|
|
|
|
| 595 |
return true;
|
| 596 |
}
|
| 597 |
|
|
|
|
| 598 |
/**
|
| 599 |
* Redo next move (after undo)
|
| 600 |
*
|
|
|
|
| 611 |
// Re-apply the move
|
| 612 |
if (nextStep.type === StepType.DROP && nextStep.position) {
|
| 613 |
// Place the stone
|
| 614 |
+
this.board[nextStep.position.x][nextStep.position.y][nextStep.position.z] =
|
| 615 |
+
nextStep.player;
|
| 616 |
|
| 617 |
// Re-execute captures if there were any
|
| 618 |
if (nextStep.capturedPositions) {
|
|
|
|
| 636 |
|
| 637 |
// Trigger callback
|
| 638 |
if (this.callbacks.onStepAdvance) {
|
| 639 |
+
this.callbacks.onStepAdvance(
|
| 640 |
+
nextStep,
|
| 641 |
+
this.stepHistory.slice(0, this.currentStepIndex)
|
| 642 |
+
);
|
| 643 |
}
|
| 644 |
|
| 645 |
return true;
|
| 646 |
}
|
| 647 |
|
|
|
|
| 648 |
/**
|
| 649 |
* Check if redo is available
|
| 650 |
*/
|
|
|
|
| 652 |
return this.currentStepIndex < this.stepHistory.length;
|
| 653 |
}
|
| 654 |
|
|
|
|
| 655 |
/**
|
| 656 |
* Jump to specific step in history
|
| 657 |
* Rebuilds board state after applying the first 'index' moves
|
|
|
|
| 733 |
return true;
|
| 734 |
}
|
| 735 |
|
|
|
|
| 736 |
/**
|
| 737 |
* Advance to next step
|
| 738 |
* Equivalent to Game.stepAdvance() (lines 279-287)
|
|
|
|
| 756 |
}
|
| 757 |
}
|
| 758 |
|
|
|
|
| 759 |
/**
|
| 760 |
* Get territory calculation
|
| 761 |
* Equivalent to Game.blackDomain() and Game.whiteDomain() (lines 232-244)
|
|
|
|
| 770 |
return this.cachedTerritory;
|
| 771 |
}
|
| 772 |
|
|
|
|
| 773 |
/**
|
| 774 |
* Get captured stone counts up to current position in history
|
| 775 |
* Only counts captures that have been played (up to currentStepIndex)
|
|
|
|
| 794 |
return counts;
|
| 795 |
}
|
| 796 |
|
|
|
|
| 797 |
/**
|
| 798 |
* Serialize game state to JSON
|
| 799 |
* Equivalent to Game.serialize() (lines 250-252)
|
|
|
|
| 811 |
};
|
| 812 |
}
|
| 813 |
|
|
|
|
| 814 |
/**
|
| 815 |
* Load game state from JSON
|
| 816 |
*/
|
|
|
|
| 852 |
}
|
| 853 |
}
|
| 854 |
|
|
|
|
| 855 |
/**
|
| 856 |
* Get game statistics
|
| 857 |
*/
|
|
|
|
| 889 |
};
|
| 890 |
}
|
| 891 |
|
|
|
|
| 892 |
/**
|
| 893 |
* Save game state to sessionStorage
|
| 894 |
*
|
|
|
|
| 912 |
return false;
|
| 913 |
}
|
| 914 |
|
|
|
|
| 915 |
/**
|
| 916 |
* Load game state from sessionStorage
|
| 917 |
*
|
|
|
|
| 940 |
return false;
|
| 941 |
}
|
| 942 |
|
|
|
|
| 943 |
/**
|
| 944 |
* Clear saved game state from sessionStorage
|
| 945 |
*
|
|
|
|
| 958 |
}
|
| 959 |
}
|
| 960 |
|
|
|
|
| 961 |
/**
|
| 962 |
* Export game to TGN (Trigo Game Notation) format
|
| 963 |
*
|
|
|
|
| 1017 |
const diff = Math.abs(black - white);
|
| 1018 |
resultStr += `${diff}points`;
|
| 1019 |
} else if (this.gameResult.reason === "resignation") {
|
| 1020 |
+
resultStr += "Resign";
|
| 1021 |
}
|
| 1022 |
|
| 1023 |
lines.push(`[Result "${resultStr}"]`);
|
| 1024 |
}
|
| 1025 |
|
| 1026 |
// Add board size (without quotes - parser expects unquoted board shape)
|
| 1027 |
+
const boardStr =
|
| 1028 |
+
this.shape.z === 1
|
| 1029 |
+
? `${this.shape.x}x${this.shape.y}` // 2D board
|
| 1030 |
+
: `${this.shape.x}x${this.shape.y}x${this.shape.z}`; // 3D board
|
| 1031 |
lines.push(`[Board ${boardStr}]`);
|
| 1032 |
|
| 1033 |
// Add optional metadata
|
|
|
|
| 1061 |
const coord = encodeAb0yz(pos, boardShape);
|
| 1062 |
moveStr += coord;
|
| 1063 |
} else if (step.type === StepType.PASS) {
|
| 1064 |
+
moveStr += "Pass";
|
| 1065 |
} else if (step.type === StepType.SURRENDER) {
|
| 1066 |
+
moveStr += "Resign";
|
| 1067 |
}
|
| 1068 |
|
| 1069 |
moves.push(moveStr);
|
|
|
|
| 1103 |
return lines.join("\n");
|
| 1104 |
}
|
| 1105 |
|
|
|
|
| 1106 |
/**
|
| 1107 |
* Import game from TGN (Trigo Game Notation) format
|
| 1108 |
*
|
|
|
|
| 1170 |
return game;
|
| 1171 |
}
|
| 1172 |
|
|
|
|
| 1173 |
/**
|
| 1174 |
* Apply a parsed move action to the game
|
| 1175 |
* Private helper method for fromTGN
|
|
|
|
| 1177 |
* @param action Parsed move action from TGN parser
|
| 1178 |
* @param boardShape Board dimensions for coordinate decoding
|
| 1179 |
*/
|
| 1180 |
+
private _applyParsedMove(
|
| 1181 |
+
action: { type: string; position?: string },
|
| 1182 |
+
boardShape: BoardShape
|
| 1183 |
+
): void {
|
| 1184 |
+
if (action.type === "pass") {
|
| 1185 |
this.pass();
|
| 1186 |
+
} else if (action.type === "resign") {
|
| 1187 |
this.surrender();
|
| 1188 |
+
} else if (action.type === "move" && action.position) {
|
| 1189 |
// Decode ab0yz coordinate to Position
|
| 1190 |
const coords = decodeAb0yz(action.position, [boardShape.x, boardShape.y, boardShape.z]);
|
| 1191 |
const position: Position = {
|
|
|
|
| 1200 |
}
|
| 1201 |
}
|
| 1202 |
|
|
|
|
| 1203 |
// Re-export parser utilities for convenience
|
| 1204 |
export { validateTGN, TGNParseError } from "../tgn/tgnParser";
|
|
|
trigo-web/inc/trigo/gameUtils.ts
CHANGED
|
@@ -13,7 +13,6 @@ export const StoneType = {
|
|
| 13 |
WHITE: 2 as Stone
|
| 14 |
};
|
| 15 |
|
| 16 |
-
|
| 17 |
/**
|
| 18 |
* Get the enemy color of a given stone
|
| 19 |
*
|
|
@@ -25,19 +24,20 @@ export function getEnemyColor(color: Stone): Stone {
|
|
| 25 |
return StoneType.EMPTY;
|
| 26 |
}
|
| 27 |
|
| 28 |
-
|
| 29 |
/**
|
| 30 |
* Check if a position is within board bounds
|
| 31 |
*/
|
| 32 |
export function isInBounds(pos: Position, shape: BoardShape): boolean {
|
| 33 |
return (
|
| 34 |
-
pos.x >= 0 &&
|
| 35 |
-
pos.
|
| 36 |
-
pos.
|
|
|
|
|
|
|
|
|
|
| 37 |
);
|
| 38 |
}
|
| 39 |
|
| 40 |
-
|
| 41 |
/**
|
| 42 |
* Get all neighboring positions (up to 6 in 3D: ±x, ±y, ±z)
|
| 43 |
*
|
|
@@ -71,7 +71,6 @@ export function getNeighbors(pos: Position, shape: BoardShape): Position[] {
|
|
| 71 |
return neighbors;
|
| 72 |
}
|
| 73 |
|
| 74 |
-
|
| 75 |
/**
|
| 76 |
* Compare two positions for equality
|
| 77 |
*/
|
|
@@ -79,7 +78,6 @@ export function positionsEqual(p1: Position, p2: Position): boolean {
|
|
| 79 |
return p1.x === p2.x && p1.y === p2.y && p1.z === p2.z;
|
| 80 |
}
|
| 81 |
|
| 82 |
-
|
| 83 |
/**
|
| 84 |
* Coordinate Set - manages a set of positions (stones in a group or liberties)
|
| 85 |
*/
|
|
@@ -123,7 +121,6 @@ export class CoordSet {
|
|
| 123 |
}
|
| 124 |
}
|
| 125 |
|
| 126 |
-
|
| 127 |
/**
|
| 128 |
* Patch - represents a connected group of same-colored stones
|
| 129 |
*
|
|
@@ -168,15 +165,10 @@ export class Patch {
|
|
| 168 |
}
|
| 169 |
}
|
| 170 |
|
| 171 |
-
|
| 172 |
/**
|
| 173 |
* Find the connected group of stones at a given position
|
| 174 |
*/
|
| 175 |
-
export function findGroup(
|
| 176 |
-
pos: Position,
|
| 177 |
-
board: Stone[][][],
|
| 178 |
-
shape: BoardShape
|
| 179 |
-
): Patch {
|
| 180 |
const color = board[pos.x][pos.y][pos.z];
|
| 181 |
const group = new Patch(color);
|
| 182 |
|
|
@@ -212,7 +204,6 @@ export function findGroup(
|
|
| 212 |
return group;
|
| 213 |
}
|
| 214 |
|
| 215 |
-
|
| 216 |
/**
|
| 217 |
* Get all neighboring groups (different from current position's color)
|
| 218 |
*/
|
|
@@ -247,20 +238,14 @@ export function getNeighborGroups(
|
|
| 247 |
return groups;
|
| 248 |
}
|
| 249 |
|
| 250 |
-
|
| 251 |
/**
|
| 252 |
* Check if a group would be captured (has no liberties)
|
| 253 |
*/
|
| 254 |
-
export function isGroupCaptured(
|
| 255 |
-
group: Patch,
|
| 256 |
-
board: Stone[][][],
|
| 257 |
-
shape: BoardShape
|
| 258 |
-
): boolean {
|
| 259 |
const liberties = group.getLiberties(board, shape);
|
| 260 |
return liberties.size() === 0;
|
| 261 |
}
|
| 262 |
|
| 263 |
-
|
| 264 |
/**
|
| 265 |
* Find all groups that would be captured by placing a stone at position
|
| 266 |
*
|
|
@@ -297,7 +282,6 @@ export function findCapturedGroups(
|
|
| 297 |
return captured;
|
| 298 |
}
|
| 299 |
|
| 300 |
-
|
| 301 |
/**
|
| 302 |
* Check if placing a stone at position would result in self-capture (suicide)
|
| 303 |
*
|
|
@@ -328,7 +312,6 @@ export function isSuicideMove(
|
|
| 328 |
return liberties.size() === 0;
|
| 329 |
}
|
| 330 |
|
| 331 |
-
|
| 332 |
/**
|
| 333 |
* Ko Detection - check if move would recreate previous board state
|
| 334 |
*
|
|
@@ -370,15 +353,11 @@ export function isKoViolation(
|
|
| 370 |
return false;
|
| 371 |
}
|
| 372 |
|
| 373 |
-
|
| 374 |
/**
|
| 375 |
* Execute captures on the board
|
| 376 |
* Returns the positions of captured stones
|
| 377 |
*/
|
| 378 |
-
export function executeCaptures(
|
| 379 |
-
capturedGroups: Patch[],
|
| 380 |
-
board: Stone[][][]
|
| 381 |
-
): Position[] {
|
| 382 |
const capturedPositions: Position[] = [];
|
| 383 |
|
| 384 |
for (const group of capturedGroups) {
|
|
@@ -391,7 +370,6 @@ export function executeCaptures(
|
|
| 391 |
return capturedPositions;
|
| 392 |
}
|
| 393 |
|
| 394 |
-
|
| 395 |
/**
|
| 396 |
* Territory Calculation
|
| 397 |
*
|
|
@@ -408,7 +386,6 @@ export interface TerritoryResult {
|
|
| 408 |
neutralTerritory: Position[];
|
| 409 |
}
|
| 410 |
|
| 411 |
-
|
| 412 |
/**
|
| 413 |
* Find all connected empty positions starting from a position
|
| 414 |
*/
|
|
@@ -445,7 +422,6 @@ function findEmptyRegion(
|
|
| 445 |
return region;
|
| 446 |
}
|
| 447 |
|
| 448 |
-
|
| 449 |
/**
|
| 450 |
* Determine which player owns an empty region
|
| 451 |
* Returns BLACK, WHITE, or EMPTY (neutral/dame)
|
|
@@ -453,21 +429,17 @@ function findEmptyRegion(
|
|
| 453 |
* Equivalent to PatchList.spaceDomain() in prototype (lines 561-585)
|
| 454 |
* An empty region belongs to a player if ALL bordering stones are that color
|
| 455 |
*/
|
| 456 |
-
function determineRegionOwner(
|
| 457 |
-
region: CoordSet,
|
| 458 |
-
board: Stone[][][],
|
| 459 |
-
shape: BoardShape
|
| 460 |
-
): Stone {
|
| 461 |
let owner: Stone = StoneType.EMPTY;
|
| 462 |
-
let solved = false;
|
| 463 |
|
| 464 |
region.forEach((pos) => {
|
| 465 |
-
if (solved) return;
|
| 466 |
|
| 467 |
const neighbors = getNeighbors(pos, shape);
|
| 468 |
|
| 469 |
for (const neighbor of neighbors) {
|
| 470 |
-
if (solved) break;
|
| 471 |
|
| 472 |
const stone = board[neighbor.x][neighbor.y][neighbor.z];
|
| 473 |
|
|
@@ -478,7 +450,7 @@ function determineRegionOwner(
|
|
| 478 |
} else if (owner !== stone) {
|
| 479 |
// Found a different colored stone - region is neutral
|
| 480 |
owner = StoneType.EMPTY;
|
| 481 |
-
solved = true;
|
| 482 |
}
|
| 483 |
}
|
| 484 |
}
|
|
@@ -487,7 +459,6 @@ function determineRegionOwner(
|
|
| 487 |
return owner;
|
| 488 |
}
|
| 489 |
|
| 490 |
-
|
| 491 |
/**
|
| 492 |
* Calculate territory for both players
|
| 493 |
*
|
|
@@ -498,10 +469,7 @@ function determineRegionOwner(
|
|
| 498 |
* 1. First pass: Add all stones to their player's territory, collect empty regions
|
| 499 |
* 2. Second pass: Determine ownership of each empty region
|
| 500 |
*/
|
| 501 |
-
export function calculateTerritory(
|
| 502 |
-
board: Stone[][][],
|
| 503 |
-
shape: BoardShape
|
| 504 |
-
): TerritoryResult {
|
| 505 |
const result: TerritoryResult = {
|
| 506 |
black: 0,
|
| 507 |
white: 0,
|
|
@@ -556,7 +524,6 @@ export function calculateTerritory(
|
|
| 556 |
return result;
|
| 557 |
}
|
| 558 |
|
| 559 |
-
|
| 560 |
/**
|
| 561 |
* Validate if a move is legal
|
| 562 |
*
|
|
@@ -568,7 +535,6 @@ export interface MoveValidation {
|
|
| 568 |
reason?: string;
|
| 569 |
}
|
| 570 |
|
| 571 |
-
|
| 572 |
export function validateMove(
|
| 573 |
pos: Position,
|
| 574 |
playerColor: Stone,
|
|
|
|
| 13 |
WHITE: 2 as Stone
|
| 14 |
};
|
| 15 |
|
|
|
|
| 16 |
/**
|
| 17 |
* Get the enemy color of a given stone
|
| 18 |
*
|
|
|
|
| 24 |
return StoneType.EMPTY;
|
| 25 |
}
|
| 26 |
|
|
|
|
| 27 |
/**
|
| 28 |
* Check if a position is within board bounds
|
| 29 |
*/
|
| 30 |
export function isInBounds(pos: Position, shape: BoardShape): boolean {
|
| 31 |
return (
|
| 32 |
+
pos.x >= 0 &&
|
| 33 |
+
pos.x < shape.x &&
|
| 34 |
+
pos.y >= 0 &&
|
| 35 |
+
pos.y < shape.y &&
|
| 36 |
+
pos.z >= 0 &&
|
| 37 |
+
pos.z < shape.z
|
| 38 |
);
|
| 39 |
}
|
| 40 |
|
|
|
|
| 41 |
/**
|
| 42 |
* Get all neighboring positions (up to 6 in 3D: ±x, ±y, ±z)
|
| 43 |
*
|
|
|
|
| 71 |
return neighbors;
|
| 72 |
}
|
| 73 |
|
|
|
|
| 74 |
/**
|
| 75 |
* Compare two positions for equality
|
| 76 |
*/
|
|
|
|
| 78 |
return p1.x === p2.x && p1.y === p2.y && p1.z === p2.z;
|
| 79 |
}
|
| 80 |
|
|
|
|
| 81 |
/**
|
| 82 |
* Coordinate Set - manages a set of positions (stones in a group or liberties)
|
| 83 |
*/
|
|
|
|
| 121 |
}
|
| 122 |
}
|
| 123 |
|
|
|
|
| 124 |
/**
|
| 125 |
* Patch - represents a connected group of same-colored stones
|
| 126 |
*
|
|
|
|
| 165 |
}
|
| 166 |
}
|
| 167 |
|
|
|
|
| 168 |
/**
|
| 169 |
* Find the connected group of stones at a given position
|
| 170 |
*/
|
| 171 |
+
export function findGroup(pos: Position, board: Stone[][][], shape: BoardShape): Patch {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 172 |
const color = board[pos.x][pos.y][pos.z];
|
| 173 |
const group = new Patch(color);
|
| 174 |
|
|
|
|
| 204 |
return group;
|
| 205 |
}
|
| 206 |
|
|
|
|
| 207 |
/**
|
| 208 |
* Get all neighboring groups (different from current position's color)
|
| 209 |
*/
|
|
|
|
| 238 |
return groups;
|
| 239 |
}
|
| 240 |
|
|
|
|
| 241 |
/**
|
| 242 |
* Check if a group would be captured (has no liberties)
|
| 243 |
*/
|
| 244 |
+
export function isGroupCaptured(group: Patch, board: Stone[][][], shape: BoardShape): boolean {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 245 |
const liberties = group.getLiberties(board, shape);
|
| 246 |
return liberties.size() === 0;
|
| 247 |
}
|
| 248 |
|
|
|
|
| 249 |
/**
|
| 250 |
* Find all groups that would be captured by placing a stone at position
|
| 251 |
*
|
|
|
|
| 282 |
return captured;
|
| 283 |
}
|
| 284 |
|
|
|
|
| 285 |
/**
|
| 286 |
* Check if placing a stone at position would result in self-capture (suicide)
|
| 287 |
*
|
|
|
|
| 312 |
return liberties.size() === 0;
|
| 313 |
}
|
| 314 |
|
|
|
|
| 315 |
/**
|
| 316 |
* Ko Detection - check if move would recreate previous board state
|
| 317 |
*
|
|
|
|
| 353 |
return false;
|
| 354 |
}
|
| 355 |
|
|
|
|
| 356 |
/**
|
| 357 |
* Execute captures on the board
|
| 358 |
* Returns the positions of captured stones
|
| 359 |
*/
|
| 360 |
+
export function executeCaptures(capturedGroups: Patch[], board: Stone[][][]): Position[] {
|
|
|
|
|
|
|
|
|
|
| 361 |
const capturedPositions: Position[] = [];
|
| 362 |
|
| 363 |
for (const group of capturedGroups) {
|
|
|
|
| 370 |
return capturedPositions;
|
| 371 |
}
|
| 372 |
|
|
|
|
| 373 |
/**
|
| 374 |
* Territory Calculation
|
| 375 |
*
|
|
|
|
| 386 |
neutralTerritory: Position[];
|
| 387 |
}
|
| 388 |
|
|
|
|
| 389 |
/**
|
| 390 |
* Find all connected empty positions starting from a position
|
| 391 |
*/
|
|
|
|
| 422 |
return region;
|
| 423 |
}
|
| 424 |
|
|
|
|
| 425 |
/**
|
| 426 |
* Determine which player owns an empty region
|
| 427 |
* Returns BLACK, WHITE, or EMPTY (neutral/dame)
|
|
|
|
| 429 |
* Equivalent to PatchList.spaceDomain() in prototype (lines 561-585)
|
| 430 |
* An empty region belongs to a player if ALL bordering stones are that color
|
| 431 |
*/
|
| 432 |
+
function determineRegionOwner(region: CoordSet, board: Stone[][][], shape: BoardShape): Stone {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 433 |
let owner: Stone = StoneType.EMPTY;
|
| 434 |
+
let solved = false; // Flag to break out when we find mixed colors
|
| 435 |
|
| 436 |
region.forEach((pos) => {
|
| 437 |
+
if (solved) return; // Skip if already determined to be neutral
|
| 438 |
|
| 439 |
const neighbors = getNeighbors(pos, shape);
|
| 440 |
|
| 441 |
for (const neighbor of neighbors) {
|
| 442 |
+
if (solved) break; // Skip if already determined to be neutral
|
| 443 |
|
| 444 |
const stone = board[neighbor.x][neighbor.y][neighbor.z];
|
| 445 |
|
|
|
|
| 450 |
} else if (owner !== stone) {
|
| 451 |
// Found a different colored stone - region is neutral
|
| 452 |
owner = StoneType.EMPTY;
|
| 453 |
+
solved = true; // Mark as solved so we stop checking
|
| 454 |
}
|
| 455 |
}
|
| 456 |
}
|
|
|
|
| 459 |
return owner;
|
| 460 |
}
|
| 461 |
|
|
|
|
| 462 |
/**
|
| 463 |
* Calculate territory for both players
|
| 464 |
*
|
|
|
|
| 469 |
* 1. First pass: Add all stones to their player's territory, collect empty regions
|
| 470 |
* 2. Second pass: Determine ownership of each empty region
|
| 471 |
*/
|
| 472 |
+
export function calculateTerritory(board: Stone[][][], shape: BoardShape): TerritoryResult {
|
|
|
|
|
|
|
|
|
|
| 473 |
const result: TerritoryResult = {
|
| 474 |
black: 0,
|
| 475 |
white: 0,
|
|
|
|
| 524 |
return result;
|
| 525 |
}
|
| 526 |
|
|
|
|
| 527 |
/**
|
| 528 |
* Validate if a move is legal
|
| 529 |
*
|
|
|
|
| 535 |
reason?: string;
|
| 536 |
}
|
| 537 |
|
|
|
|
| 538 |
export function validateMove(
|
| 539 |
pos: Position,
|
| 540 |
playerColor: Stone,
|
trigo-web/inc/trigo/index.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
| 1 |
-
|
| 2 |
export * from "./types";
|
| 3 |
export * from "./gameUtils";
|
| 4 |
export * from "./game";
|
|
|
|
|
|
|
| 1 |
export * from "./types";
|
| 2 |
export * from "./gameUtils";
|
| 3 |
export * from "./game";
|
trigo-web/inc/trigo/parserInit.ts
CHANGED
|
@@ -16,7 +16,6 @@
|
|
| 16 |
|
| 17 |
import { setParserModule } from "../tgn/tgnParser";
|
| 18 |
|
| 19 |
-
|
| 20 |
/**
|
| 21 |
* Check if we're in a browser environment
|
| 22 |
*/
|
|
@@ -24,15 +23,17 @@ function isBrowser(): boolean {
|
|
| 24 |
return typeof window !== "undefined" && typeof document !== "undefined";
|
| 25 |
}
|
| 26 |
|
| 27 |
-
|
| 28 |
/**
|
| 29 |
* Check if we're in a Node.js environment
|
| 30 |
*/
|
| 31 |
function isNode(): boolean {
|
| 32 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
}
|
| 34 |
|
| 35 |
-
|
| 36 |
/**
|
| 37 |
* Initialize all parsers for use in the application
|
| 38 |
* Should be called once at application startup
|
|
@@ -55,7 +56,6 @@ export async function initializeParsers(): Promise<void> {
|
|
| 55 |
}
|
| 56 |
}
|
| 57 |
|
| 58 |
-
|
| 59 |
/**
|
| 60 |
* Initialize parsers for browser environment
|
| 61 |
* Loads parsers from /lib/ which is served by Vite in dev and included in build
|
|
@@ -82,7 +82,9 @@ async function initializeParsersForBrowser(): Promise<void> {
|
|
| 82 |
|
| 83 |
// We need 'require' to be defined (but can be a dummy)
|
| 84 |
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
| 85 |
-
const require = function() {
|
|
|
|
|
|
|
| 86 |
|
| 87 |
// Eval in a scope where module, exports, and require are defined
|
| 88 |
// eslint-disable-next-line no-eval
|
|
@@ -92,7 +94,7 @@ async function initializeParsersForBrowser(): Promise<void> {
|
|
| 92 |
// So module.exports.parser is the actual parser instance
|
| 93 |
const parser = module.exports.parser;
|
| 94 |
|
| 95 |
-
if (!parser || typeof parser.parse !==
|
| 96 |
throw new Error("Parser loaded but parse method not available");
|
| 97 |
}
|
| 98 |
|
|
@@ -103,7 +105,6 @@ async function initializeParsersForBrowser(): Promise<void> {
|
|
| 103 |
}
|
| 104 |
}
|
| 105 |
|
| 106 |
-
|
| 107 |
/**
|
| 108 |
* Initialize parsers for Node.js environment
|
| 109 |
* Loads parsers from project's public/lib directory
|
|
|
|
| 16 |
|
| 17 |
import { setParserModule } from "../tgn/tgnParser";
|
| 18 |
|
|
|
|
| 19 |
/**
|
| 20 |
* Check if we're in a browser environment
|
| 21 |
*/
|
|
|
|
| 23 |
return typeof window !== "undefined" && typeof document !== "undefined";
|
| 24 |
}
|
| 25 |
|
|
|
|
| 26 |
/**
|
| 27 |
* Check if we're in a Node.js environment
|
| 28 |
*/
|
| 29 |
function isNode(): boolean {
|
| 30 |
+
return (
|
| 31 |
+
typeof process !== "undefined" &&
|
| 32 |
+
!!(process as any).versions &&
|
| 33 |
+
!!(process as any).versions.node
|
| 34 |
+
);
|
| 35 |
}
|
| 36 |
|
|
|
|
| 37 |
/**
|
| 38 |
* Initialize all parsers for use in the application
|
| 39 |
* Should be called once at application startup
|
|
|
|
| 56 |
}
|
| 57 |
}
|
| 58 |
|
|
|
|
| 59 |
/**
|
| 60 |
* Initialize parsers for browser environment
|
| 61 |
* Loads parsers from /lib/ which is served by Vite in dev and included in build
|
|
|
|
| 82 |
|
| 83 |
// We need 'require' to be defined (but can be a dummy)
|
| 84 |
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
| 85 |
+
const require = function () {
|
| 86 |
+
throw new Error("require not available in browser");
|
| 87 |
+
};
|
| 88 |
|
| 89 |
// Eval in a scope where module, exports, and require are defined
|
| 90 |
// eslint-disable-next-line no-eval
|
|
|
|
| 94 |
// So module.exports.parser is the actual parser instance
|
| 95 |
const parser = module.exports.parser;
|
| 96 |
|
| 97 |
+
if (!parser || typeof parser.parse !== "function") {
|
| 98 |
throw new Error("Parser loaded but parse method not available");
|
| 99 |
}
|
| 100 |
|
|
|
|
| 105 |
}
|
| 106 |
}
|
| 107 |
|
|
|
|
| 108 |
/**
|
| 109 |
* Initialize parsers for Node.js environment
|
| 110 |
* Loads parsers from project's public/lib directory
|
trigo-web/inc/trigo/typeAdapters.ts
CHANGED
|
@@ -11,7 +11,6 @@ import type { Stone, Position, Player, Move } from "./types";
|
|
| 11 |
import { StoneType } from "./game";
|
| 12 |
import type { Step } from "./game";
|
| 13 |
|
| 14 |
-
|
| 15 |
/**
|
| 16 |
* Convert Player string to Stone number
|
| 17 |
*
|
|
@@ -22,7 +21,6 @@ export function playerToStone(player: Player): Stone {
|
|
| 22 |
return player === "black" ? StoneType.BLACK : StoneType.WHITE;
|
| 23 |
}
|
| 24 |
|
| 25 |
-
|
| 26 |
/**
|
| 27 |
* Convert Stone number to Player string
|
| 28 |
*
|
|
@@ -39,7 +37,6 @@ export function stoneToPlayer(stone: Stone): Player {
|
|
| 39 |
return "black";
|
| 40 |
}
|
| 41 |
|
| 42 |
-
|
| 43 |
/**
|
| 44 |
* Convert Step (TrigoGame format) to Move (frontend format)
|
| 45 |
*
|
|
@@ -60,14 +57,14 @@ export function stepToMove(step: Step): Move {
|
|
| 60 |
}
|
| 61 |
|
| 62 |
// If it's a PASS move, set flag
|
| 63 |
-
if (step.type === 1) {
|
|
|
|
| 64 |
move.isPass = true;
|
| 65 |
}
|
| 66 |
|
| 67 |
return move;
|
| 68 |
}
|
| 69 |
|
| 70 |
-
|
| 71 |
/**
|
| 72 |
* Convert array of Steps to array of Moves
|
| 73 |
*
|
|
@@ -78,7 +75,6 @@ export function stepsToMoves(steps: Step[]): Move[] {
|
|
| 78 |
return steps.map(stepToMove);
|
| 79 |
}
|
| 80 |
|
| 81 |
-
|
| 82 |
/**
|
| 83 |
* Convert board (Stone[][][]) to frontend format (number[][][])
|
| 84 |
*
|
|
@@ -89,14 +85,9 @@ export function stepsToMoves(steps: Step[]): Move[] {
|
|
| 89 |
* @returns Frontend board format
|
| 90 |
*/
|
| 91 |
export function boardToNumbers(board: Stone[][][]): number[][][] {
|
| 92 |
-
return board.map(plane =>
|
| 93 |
-
plane.map(row =>
|
| 94 |
-
row.map(cell => cell as number)
|
| 95 |
-
)
|
| 96 |
-
);
|
| 97 |
}
|
| 98 |
|
| 99 |
-
|
| 100 |
/**
|
| 101 |
* Helper: Create Position object from coordinates
|
| 102 |
*
|
|
|
|
| 11 |
import { StoneType } from "./game";
|
| 12 |
import type { Step } from "./game";
|
| 13 |
|
|
|
|
| 14 |
/**
|
| 15 |
* Convert Player string to Stone number
|
| 16 |
*
|
|
|
|
| 21 |
return player === "black" ? StoneType.BLACK : StoneType.WHITE;
|
| 22 |
}
|
| 23 |
|
|
|
|
| 24 |
/**
|
| 25 |
* Convert Stone number to Player string
|
| 26 |
*
|
|
|
|
| 37 |
return "black";
|
| 38 |
}
|
| 39 |
|
|
|
|
| 40 |
/**
|
| 41 |
* Convert Step (TrigoGame format) to Move (frontend format)
|
| 42 |
*
|
|
|
|
| 57 |
}
|
| 58 |
|
| 59 |
// If it's a PASS move, set flag
|
| 60 |
+
if (step.type === 1) {
|
| 61 |
+
// StepType.PASS
|
| 62 |
move.isPass = true;
|
| 63 |
}
|
| 64 |
|
| 65 |
return move;
|
| 66 |
}
|
| 67 |
|
|
|
|
| 68 |
/**
|
| 69 |
* Convert array of Steps to array of Moves
|
| 70 |
*
|
|
|
|
| 75 |
return steps.map(stepToMove);
|
| 76 |
}
|
| 77 |
|
|
|
|
| 78 |
/**
|
| 79 |
* Convert board (Stone[][][]) to frontend format (number[][][])
|
| 80 |
*
|
|
|
|
| 85 |
* @returns Frontend board format
|
| 86 |
*/
|
| 87 |
export function boardToNumbers(board: Stone[][][]): number[][][] {
|
| 88 |
+
return board.map((plane) => plane.map((row) => row.map((cell) => cell as number)));
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
}
|
| 90 |
|
|
|
|
| 91 |
/**
|
| 92 |
* Helper: Create Position object from coordinates
|
| 93 |
*
|
trigo-web/inc/trigoAgent.ts
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* Trigo AI Agent - Language Model-based Move Selection (Frontend/Backend Common)
|
| 3 |
+
*
|
| 4 |
+
* Platform-agnostic AI agent that accepts ONNX session from platform-specific code.
|
| 5 |
+
* No direct dependency on onnxruntime packages - uses dependency injection pattern.
|
| 6 |
+
*
|
| 7 |
+
* Uses ONNX language model to score and select moves by:
|
| 8 |
+
* 1. Getting all valid moves for current position
|
| 9 |
+
* 2. Scoring each move by appending it to TGN and computing token probabilities
|
| 10 |
+
* 3. Selecting move with highest probability (argmax)
|
| 11 |
+
*/
|
| 12 |
+
|
| 13 |
+
import { ModelInferencer } from "./modelInferencer";
|
| 14 |
+
import { TrigoGame, StoneType } from "./trigo/game";
|
| 15 |
+
import type { Move, Stone } from "./trigo/types";
|
| 16 |
+
|
| 17 |
+
/**
|
| 18 |
+
* Configuration for the AI agent
|
| 19 |
+
*/
|
| 20 |
+
export interface TrigoAgentConfig {
|
| 21 |
+
vocabSize?: number;
|
| 22 |
+
seqLen?: number;
|
| 23 |
+
temperature?: number;
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
/**
|
| 27 |
+
* Move score result
|
| 28 |
+
*/
|
| 29 |
+
export interface MoveScore {
|
| 30 |
+
move: Move;
|
| 31 |
+
score: number;
|
| 32 |
+
logProb: number;
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
/**
|
| 36 |
+
* Trigo AI Agent for move generation
|
| 37 |
+
* Compatible with both frontend (onnxruntime-web) and backend (onnxruntime-node)
|
| 38 |
+
*/
|
| 39 |
+
export class TrigoAgent {
|
| 40 |
+
private inferencer: ModelInferencer;
|
| 41 |
+
|
| 42 |
+
constructor(inferencer: ModelInferencer) {
|
| 43 |
+
this.inferencer = inferencer;
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
/**
|
| 47 |
+
* Check if agent is initialized (checks if inferencer has a session)
|
| 48 |
+
*/
|
| 49 |
+
isInitialized(): boolean {
|
| 50 |
+
// Agent is initialized if the inferencer has been set up
|
| 51 |
+
return this.inferencer !== null;
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
/**
|
| 55 |
+
* Convert Stone type to player string
|
| 56 |
+
*/
|
| 57 |
+
private stoneToPlayer(stone: Stone): "black" | "white" {
|
| 58 |
+
if (stone === StoneType.BLACK) return "black";
|
| 59 |
+
if (stone === StoneType.WHITE) return "white";
|
| 60 |
+
throw new Error(`Invalid stone type: ${stone}`);
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
/**
|
| 64 |
+
* Convert string to token IDs (byte-level encoding)
|
| 65 |
+
*/
|
| 66 |
+
private stringToTokens(text: string): number[] {
|
| 67 |
+
return Array.from(text).map((char) => char.charCodeAt(0));
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
/**
|
| 71 |
+
* Compute softmax probabilities from logits
|
| 72 |
+
*/
|
| 73 |
+
private softmax(logits: Float32Array, vocabSize: number): Float32Array {
|
| 74 |
+
const probs = new Float32Array(vocabSize);
|
| 75 |
+
let maxLogit = -Infinity;
|
| 76 |
+
|
| 77 |
+
// Find max for numerical stability
|
| 78 |
+
for (let i = 0; i < vocabSize; i++) {
|
| 79 |
+
if (logits[i] > maxLogit) {
|
| 80 |
+
maxLogit = logits[i];
|
| 81 |
+
}
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
// Compute exp and sum
|
| 85 |
+
let sum = 0;
|
| 86 |
+
for (let i = 0; i < vocabSize; i++) {
|
| 87 |
+
probs[i] = Math.exp(logits[i] - maxLogit);
|
| 88 |
+
sum += probs[i];
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
// Normalize
|
| 92 |
+
for (let i = 0; i < vocabSize; i++) {
|
| 93 |
+
probs[i] /= sum;
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
return probs;
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
/**
|
| 100 |
+
* Score a candidate move by computing token probabilities
|
| 101 |
+
*
|
| 102 |
+
* Clones the game, applies the move, generates new TGN, and computes
|
| 103 |
+
* the probability of the move tokens.
|
| 104 |
+
*/
|
| 105 |
+
async scoreMove(game: TrigoGame, move: Move): Promise<number> {
|
| 106 |
+
// Clone the game
|
| 107 |
+
const clonedGame = game.clone();
|
| 108 |
+
|
| 109 |
+
// Apply the move to the cloned game
|
| 110 |
+
let success: boolean;
|
| 111 |
+
if (move.isPass) {
|
| 112 |
+
success = clonedGame.pass();
|
| 113 |
+
} else if (move.x !== undefined && move.y !== undefined && move.z !== undefined) {
|
| 114 |
+
success = clonedGame.drop({ x: move.x, y: move.y, z: move.z });
|
| 115 |
+
} else {
|
| 116 |
+
// Invalid move format
|
| 117 |
+
return -1000;
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
if (!success) {
|
| 121 |
+
// Invalid move, return very low probability
|
| 122 |
+
return -1000;
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
// Generate TGN from both original and cloned game
|
| 126 |
+
const newTGN = clonedGame.toTGN().trim();
|
| 127 |
+
|
| 128 |
+
// Extract the move substring
|
| 129 |
+
// The move should be the new content added after the current TGN
|
| 130 |
+
const moveTokens = this.extractMoveTokens(newTGN);
|
| 131 |
+
|
| 132 |
+
if (moveTokens.length === 0) {
|
| 133 |
+
// Could not extract move, return low probability
|
| 134 |
+
return -100;
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
// Convert new TGN to tokens
|
| 138 |
+
const tokens = this.stringToTokens(newTGN);
|
| 139 |
+
|
| 140 |
+
// Get configuration
|
| 141 |
+
const config = this.inferencer.getConfig();
|
| 142 |
+
const seqLen = config.seqLen;
|
| 143 |
+
const vocabSize = config.vocabSize;
|
| 144 |
+
|
| 145 |
+
// Truncate if too long
|
| 146 |
+
if (tokens.length > seqLen) {
|
| 147 |
+
tokens.splice(0, tokens.length - seqLen);
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
// Run inference (START_TOKEN will be prepended by inferencer)
|
| 151 |
+
const logits = await this.inferencer.runInference(tokens);
|
| 152 |
+
|
| 153 |
+
// Compute probability for the move tokens
|
| 154 |
+
// Note: inferencer prepends START_TOKEN, so positions are offset by +1
|
| 155 |
+
// Token sequence: [START_TOKEN, ...tokens, PAD, PAD, ...]
|
| 156 |
+
// Position in output: token_i is at position i+1 in the padded sequence
|
| 157 |
+
|
| 158 |
+
// Find where move tokens start in original token sequence
|
| 159 |
+
const moveStartInTokens = tokens.length - moveTokens.length;
|
| 160 |
+
|
| 161 |
+
let logProb = 0;
|
| 162 |
+
for (let i = 0; i < moveTokens.length; i++) {
|
| 163 |
+
// Position of this move token in the original tokens array
|
| 164 |
+
const tokenPos = moveStartInTokens + i;
|
| 165 |
+
|
| 166 |
+
// Skip if position is out of bounds
|
| 167 |
+
// Logits at position tokenPos predict the token at tokenPos+1
|
| 168 |
+
if (tokenPos < 0 || tokenPos >= tokens.length) continue;
|
| 169 |
+
|
| 170 |
+
const offset = tokenPos * vocabSize;
|
| 171 |
+
const tokenLogits = logits.slice(offset, offset + vocabSize);
|
| 172 |
+
const probs = this.softmax(tokenLogits, vocabSize);
|
| 173 |
+
|
| 174 |
+
const tokenId = moveTokens[i];
|
| 175 |
+
const prob = probs[tokenId];
|
| 176 |
+
|
| 177 |
+
if (prob > 0) {
|
| 178 |
+
logProb += Math.log(prob);
|
| 179 |
+
} else {
|
| 180 |
+
// If probability is zero, assign very low prob
|
| 181 |
+
logProb += -100;
|
| 182 |
+
}
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
+
return logProb;
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
/**
|
| 189 |
+
* Extract move tokens from TGN difference
|
| 190 |
+
* Returns the tokens that were added between currentTGN and newTGN
|
| 191 |
+
*/
|
| 192 |
+
private extractMoveTokens(tgn: string): number[] {
|
| 193 |
+
const moveCapture = tgn.match(/[Pa-z0]+$/);
|
| 194 |
+
|
| 195 |
+
return this.stringToTokens(moveCapture ? moveCapture[0] : "");
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
/**
|
| 199 |
+
* Select the best move using the language model
|
| 200 |
+
*
|
| 201 |
+
* Scores all valid moves and returns the one with highest probability (argmax).
|
| 202 |
+
*/
|
| 203 |
+
async selectBestMove(game: TrigoGame): Promise<Move | null> {
|
| 204 |
+
if (!this.isInitialized()) {
|
| 205 |
+
throw new Error("Agent not initialized. Pass initialized inferencer to constructor.");
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
console.log("[TrigoAgent] Selecting move...");
|
| 209 |
+
|
| 210 |
+
// Get current player as string
|
| 211 |
+
const currentPlayer = this.stoneToPlayer(game.getCurrentPlayer());
|
| 212 |
+
|
| 213 |
+
// Get all valid moves
|
| 214 |
+
const validMoves: Move[] = game.validMovePositions().map((pos) => ({
|
| 215 |
+
x: pos.x,
|
| 216 |
+
y: pos.y,
|
| 217 |
+
z: pos.z,
|
| 218 |
+
player: currentPlayer
|
| 219 |
+
}));
|
| 220 |
+
validMoves.push({ player: currentPlayer, isPass: true }); // Add pass move
|
| 221 |
+
|
| 222 |
+
if (validMoves.length === 0) {
|
| 223 |
+
console.log("[TrigoAgent] No valid moves available");
|
| 224 |
+
return null;
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
console.log(`[TrigoAgent] Evaluating ${validMoves.length} valid moves...`);
|
| 228 |
+
|
| 229 |
+
// Score each move
|
| 230 |
+
const scores: MoveScore[] = [];
|
| 231 |
+
for (const move of validMoves) {
|
| 232 |
+
const logProb = await this.scoreMove(game, move);
|
| 233 |
+
|
| 234 |
+
scores.push({
|
| 235 |
+
move,
|
| 236 |
+
score: Math.exp(logProb), // Convert log prob to probability
|
| 237 |
+
logProb
|
| 238 |
+
});
|
| 239 |
+
}
|
| 240 |
+
|
| 241 |
+
// Find best move (argmax)
|
| 242 |
+
scores.sort((a, b) => b.logProb - a.logProb);
|
| 243 |
+
const bestMove = scores[0];
|
| 244 |
+
console.debug("scores:", scores);
|
| 245 |
+
|
| 246 |
+
console.log("[TrigoAgent] Best move:", bestMove.move, "score:", bestMove.score.toFixed(6));
|
| 247 |
+
console.log("[TrigoAgent] Top 5 moves:");
|
| 248 |
+
for (let i = 0; i < Math.min(5, scores.length); i++) {
|
| 249 |
+
console.log(` ${i + 1}. ${scores[i].move}: ${scores[i].score.toFixed(6)}`);
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
return bestMove.move;
|
| 253 |
+
}
|
| 254 |
+
|
| 255 |
+
/**
|
| 256 |
+
* Clean up resources
|
| 257 |
+
*/
|
| 258 |
+
destroy(): void {
|
| 259 |
+
this.inferencer.destroy();
|
| 260 |
+
console.log("[TrigoAgent] Destroyed");
|
| 261 |
+
}
|
| 262 |
+
}
|
trigo-web/inc/trigoTreeAgent.ts
ADDED
|
@@ -0,0 +1,415 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* Trigo Tree Agent - AI agent using tree attention for efficient move evaluation
|
| 3 |
+
*
|
| 4 |
+
* Uses evaluation mode ONNX model to score all valid moves in parallel.
|
| 5 |
+
* Organizes moves as a prefix tree where branches with same head token are merged.
|
| 6 |
+
*/
|
| 7 |
+
|
| 8 |
+
import { ModelInferencer } from "./modelInferencer";
|
| 9 |
+
import type { EvaluationInputs } from "./modelInferencer";
|
| 10 |
+
import { TrigoGame, StoneType } from "./trigo/game";
|
| 11 |
+
import type { Move, Stone, Position } from "./trigo/types";
|
| 12 |
+
import { encodeAb0yz } from "./trigo/ab0yz";
|
| 13 |
+
|
| 14 |
+
export interface ScoredMove {
|
| 15 |
+
move: Move;
|
| 16 |
+
score: number; // Log probability
|
| 17 |
+
notation: string; // TGN notation (e.g., "ab0")
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
export class TrigoTreeAgent {
|
| 21 |
+
private inferencer: ModelInferencer;
|
| 22 |
+
|
| 23 |
+
constructor(inferencer: ModelInferencer) {
|
| 24 |
+
this.inferencer = inferencer;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
/**
|
| 28 |
+
* Convert Stone type to player string
|
| 29 |
+
*/
|
| 30 |
+
private stoneToPlayer(stone: Stone): "black" | "white" {
|
| 31 |
+
if (stone === StoneType.BLACK) return "black";
|
| 32 |
+
if (stone === StoneType.WHITE) return "white";
|
| 33 |
+
throw new Error(`Invalid stone type: ${stone}`);
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
/**
|
| 37 |
+
* Encode a position to TGN notation (3 characters for 5×5×5 board)
|
| 38 |
+
*/
|
| 39 |
+
private positionToTGN(pos: Position, shape: { x: number; y: number; z: number }): string {
|
| 40 |
+
const posArray = [pos.x, pos.y, pos.z];
|
| 41 |
+
const shapeArray = [shape.x, shape.y, shape.z];
|
| 42 |
+
return encodeAb0yz(posArray, shapeArray);
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
/**
|
| 46 |
+
* Convert string to byte tokens (ASCII encoding)
|
| 47 |
+
*/
|
| 48 |
+
private stringToTokens(str: string): number[] {
|
| 49 |
+
const tokens: number[] = [];
|
| 50 |
+
for (let i = 0; i < str.length; i++) {
|
| 51 |
+
tokens.push(str.charCodeAt(i));
|
| 52 |
+
}
|
| 53 |
+
return tokens;
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
/**
|
| 57 |
+
* Build prefix tree from token arrays using recursive merging
|
| 58 |
+
* Merges branches with the same token at EVERY level
|
| 59 |
+
*
|
| 60 |
+
* Algorithm:
|
| 61 |
+
* 1. Group sequences by their first token
|
| 62 |
+
* 2. For each group:
|
| 63 |
+
* - Create one node for the shared first token
|
| 64 |
+
* - Extract remaining tokens (residues)
|
| 65 |
+
* - Recursively build subtree from residues
|
| 66 |
+
* 3. Combine all subtrees and build attention mask
|
| 67 |
+
*
|
| 68 |
+
* Example for ["aa", "ab", "ba", "bb"]:
|
| 69 |
+
* Level 1: Group by first token → 'a': ["a","b"], 'b': ["a","b"]
|
| 70 |
+
* Level 2: Within 'a' group, build subtree for ["a","b"]
|
| 71 |
+
* Within 'b' group, build subtree for ["a","b"]
|
| 72 |
+
* Result: Two branches, each with properly merged second-level nodes
|
| 73 |
+
*
|
| 74 |
+
* @param tokenArrays - Array of token arrays
|
| 75 |
+
* @returns Flattened token array (length m), mask matrix (m×m), and move-to-position mapping
|
| 76 |
+
*/
|
| 77 |
+
private buildPrefixTree(tokenArrays: number[][]): {
|
| 78 |
+
evaluatedIds: number[];
|
| 79 |
+
mask: number[];
|
| 80 |
+
moveToLeafPos: number[];
|
| 81 |
+
} {
|
| 82 |
+
type Seq = { moveIndex: number; tokens: number[] };
|
| 83 |
+
|
| 84 |
+
interface Node {
|
| 85 |
+
token: number;
|
| 86 |
+
pos: number;
|
| 87 |
+
parent: number | null;
|
| 88 |
+
children: Node[];
|
| 89 |
+
moveEnds: number[];
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
let nextPos = 0;
|
| 93 |
+
|
| 94 |
+
// --- Build prefix tree through recursive grouping ---
|
| 95 |
+
function build(seqs: Seq[], parent: number | null): Node[] {
|
| 96 |
+
// group by token
|
| 97 |
+
const groups = new Map<number, Seq[]>();
|
| 98 |
+
for (const s of seqs) {
|
| 99 |
+
if (s.tokens.length === 0) continue;
|
| 100 |
+
const t = s.tokens[0];
|
| 101 |
+
if (!groups.has(t)) groups.set(t, []);
|
| 102 |
+
groups.get(t)!.push(s);
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
const levelNodes: Node[] = [];
|
| 106 |
+
|
| 107 |
+
for (const [token, group] of groups) {
|
| 108 |
+
const pos = nextPos++;
|
| 109 |
+
const node: Node = {
|
| 110 |
+
token,
|
| 111 |
+
pos,
|
| 112 |
+
parent,
|
| 113 |
+
children: [],
|
| 114 |
+
moveEnds: []
|
| 115 |
+
};
|
| 116 |
+
|
| 117 |
+
// split residues
|
| 118 |
+
const ends: number[] = [];
|
| 119 |
+
const residues: Seq[] = [];
|
| 120 |
+
|
| 121 |
+
for (const g of group) {
|
| 122 |
+
if (g.tokens.length === 1) ends.push(g.moveIndex);
|
| 123 |
+
else residues.push({ moveIndex: g.moveIndex, tokens: g.tokens.slice(1) });
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
node.moveEnds = ends;
|
| 127 |
+
|
| 128 |
+
// create sub nodes recursively
|
| 129 |
+
if (residues.length > 0) {
|
| 130 |
+
node.children = build(residues, pos);
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
levelNodes.push(node);
|
| 134 |
+
}
|
| 135 |
+
return levelNodes;
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
// Build roots
|
| 139 |
+
const seqs = tokenArrays.map((t, i) => ({ moveIndex: i, tokens: t }));
|
| 140 |
+
const roots = build(seqs, null);
|
| 141 |
+
const total = nextPos;
|
| 142 |
+
|
| 143 |
+
// --- Flatten tree ---
|
| 144 |
+
const evaluatedIds = new Array<number>(total);
|
| 145 |
+
const parent = new Array<number | null>(total).fill(null);
|
| 146 |
+
const moveToLeafPos = new Array<number>(tokenArrays.length).fill(-1);
|
| 147 |
+
|
| 148 |
+
function dfs(n: Node) {
|
| 149 |
+
evaluatedIds[n.pos] = n.token;
|
| 150 |
+
parent[n.pos] = n.parent;
|
| 151 |
+
|
| 152 |
+
for (const m of n.moveEnds) moveToLeafPos[m] = n.pos;
|
| 153 |
+
for (const c of n.children) dfs(c);
|
| 154 |
+
}
|
| 155 |
+
for (const r of roots) dfs(r);
|
| 156 |
+
|
| 157 |
+
// --- Build ancestor mask ---
|
| 158 |
+
const mask = new Array(total * total).fill(0);
|
| 159 |
+
for (let i = 0; i < total; i++) {
|
| 160 |
+
let p = i;
|
| 161 |
+
while (p !== null) {
|
| 162 |
+
mask[i * total + p] = 1;
|
| 163 |
+
p = parent[p]!;
|
| 164 |
+
}
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
return { evaluatedIds, mask, moveToLeafPos };
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
/**
|
| 171 |
+
* Build tree structure for all valid moves
|
| 172 |
+
* Returns prefix tokens and tree structure for batch evaluation
|
| 173 |
+
*/
|
| 174 |
+
private buildMoveTree(
|
| 175 |
+
game: TrigoGame,
|
| 176 |
+
moves: Move[]
|
| 177 |
+
): {
|
| 178 |
+
prefixTokens: number[];
|
| 179 |
+
evaluatedIds: number[];
|
| 180 |
+
mask: number[];
|
| 181 |
+
moveData: Array<{ move: Move; notation: string; leafPos: number; parentPos: number }>;
|
| 182 |
+
} {
|
| 183 |
+
// Get current TGN as prefix
|
| 184 |
+
const currentTGN = game.toTGN().trim();
|
| 185 |
+
|
| 186 |
+
// Build prefix (everything up to next move)
|
| 187 |
+
const lines = currentTGN.split("\n");
|
| 188 |
+
const lastLine = lines[lines.length - 1];
|
| 189 |
+
|
| 190 |
+
let prefix: string;
|
| 191 |
+
if (lastLine.match(/^\d+\./)) {
|
| 192 |
+
// Last line is a move number, include it
|
| 193 |
+
prefix = currentTGN + " ";
|
| 194 |
+
} else if (lastLine.trim() === "") {
|
| 195 |
+
// Empty line, add move number
|
| 196 |
+
const moveMatches = currentTGN.match(/\d+\.\s/g);
|
| 197 |
+
const moveNumber = moveMatches ? moveMatches.length + 1 : 1;
|
| 198 |
+
const isBlackTurn = game.getCurrentPlayer() === StoneType.BLACK;
|
| 199 |
+
if (isBlackTurn) {
|
| 200 |
+
prefix = currentTGN + `${moveNumber}. `;
|
| 201 |
+
} else {
|
| 202 |
+
prefix = currentTGN + " ";
|
| 203 |
+
}
|
| 204 |
+
} else {
|
| 205 |
+
// Last line has moves, add space
|
| 206 |
+
prefix = currentTGN + " ";
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
const prefixTokens = this.stringToTokens(prefix);
|
| 210 |
+
|
| 211 |
+
// Encode each move to tokens (only first 2 tokens)
|
| 212 |
+
const shape = game.getShape();
|
| 213 |
+
const movesWithTokens = moves.map((move) => {
|
| 214 |
+
let notation: string;
|
| 215 |
+
if (move.isPass) {
|
| 216 |
+
notation = "Pass";
|
| 217 |
+
} else if (move.x !== undefined && move.y !== undefined && move.z !== undefined) {
|
| 218 |
+
notation = this.positionToTGN({ x: move.x, y: move.y, z: move.z }, shape);
|
| 219 |
+
} else {
|
| 220 |
+
throw new Error("Invalid move: missing coordinates");
|
| 221 |
+
}
|
| 222 |
+
|
| 223 |
+
// Exclude the last token
|
| 224 |
+
const fullTokens = this.stringToTokens(notation);
|
| 225 |
+
const tokens = fullTokens.slice(0, fullTokens.length - 1);
|
| 226 |
+
|
| 227 |
+
return { move, notation, tokens };
|
| 228 |
+
});
|
| 229 |
+
|
| 230 |
+
// Build prefix tree
|
| 231 |
+
const tokenArrays = movesWithTokens.map((m) => m.tokens);
|
| 232 |
+
const { evaluatedIds, mask, moveToLeafPos } = this.buildPrefixTree(tokenArrays);
|
| 233 |
+
|
| 234 |
+
// Build move data with leaf positions and parent positions
|
| 235 |
+
const moveData = movesWithTokens.map((m, index) => {
|
| 236 |
+
const leafPos = moveToLeafPos[index];
|
| 237 |
+
// Find parent position (root position for this move)
|
| 238 |
+
// Parent is the first token position
|
| 239 |
+
const firstToken = m.tokens[0];
|
| 240 |
+
let parentPos = -1;
|
| 241 |
+
for (let i = 0; i < evaluatedIds.length; i++) {
|
| 242 |
+
if (evaluatedIds[i] === firstToken && i < leafPos) {
|
| 243 |
+
// This is a potential parent
|
| 244 |
+
// Check if it's in the same branch by checking mask
|
| 245 |
+
// If leafPos can see position i, then i might be the parent
|
| 246 |
+
if (mask[leafPos * evaluatedIds.length + i] === 1.0 && i !== leafPos) {
|
| 247 |
+
// Find the closest parent (maximum index less than leafPos that leaf can see)
|
| 248 |
+
if (i > parentPos) {
|
| 249 |
+
parentPos = i;
|
| 250 |
+
}
|
| 251 |
+
}
|
| 252 |
+
}
|
| 253 |
+
}
|
| 254 |
+
|
| 255 |
+
return {
|
| 256 |
+
move: m.move,
|
| 257 |
+
notation: m.notation,
|
| 258 |
+
leafPos,
|
| 259 |
+
parentPos
|
| 260 |
+
};
|
| 261 |
+
});
|
| 262 |
+
|
| 263 |
+
return { prefixTokens, evaluatedIds, mask, moveData };
|
| 264 |
+
}
|
| 265 |
+
|
| 266 |
+
/**
|
| 267 |
+
* Get tree structure for visualization (public method)
|
| 268 |
+
*/
|
| 269 |
+
getTreeStructure(
|
| 270 |
+
game: TrigoGame,
|
| 271 |
+
moves: Move[]
|
| 272 |
+
): {
|
| 273 |
+
evaluatedIds: number[];
|
| 274 |
+
mask: number[];
|
| 275 |
+
moveData: Array<{ move: Move; notation: string; leafPos: number; parentPos: number }>;
|
| 276 |
+
} {
|
| 277 |
+
return this.buildMoveTree(game, moves);
|
| 278 |
+
}
|
| 279 |
+
|
| 280 |
+
/**
|
| 281 |
+
* Select best move using tree attention
|
| 282 |
+
* Evaluates all valid moves in a single inference call
|
| 283 |
+
*/
|
| 284 |
+
async selectBestMove(game: TrigoGame): Promise<Move | null> {
|
| 285 |
+
if (!this.inferencer.isReady()) {
|
| 286 |
+
throw new Error("Inferencer not initialized");
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
// Get current player as string
|
| 290 |
+
const currentPlayer = this.stoneToPlayer(game.getCurrentPlayer());
|
| 291 |
+
|
| 292 |
+
// Get all valid moves
|
| 293 |
+
const validMoves: Move[] = game.validMovePositions().map((pos) => ({
|
| 294 |
+
x: pos.x,
|
| 295 |
+
y: pos.y,
|
| 296 |
+
z: pos.z,
|
| 297 |
+
player: currentPlayer
|
| 298 |
+
}));
|
| 299 |
+
validMoves.push({ player: currentPlayer, isPass: true }); // Add pass move
|
| 300 |
+
|
| 301 |
+
if (validMoves.length === 0) {
|
| 302 |
+
return null;
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
// Score all moves using tree attention
|
| 306 |
+
const scoredMoves = await this.scoreMoves(game, validMoves);
|
| 307 |
+
|
| 308 |
+
// Return move with highest score
|
| 309 |
+
if (scoredMoves.length === 0) {
|
| 310 |
+
return null;
|
| 311 |
+
}
|
| 312 |
+
|
| 313 |
+
scoredMoves.sort((a, b) => b.score - a.score);
|
| 314 |
+
return scoredMoves[0].move;
|
| 315 |
+
}
|
| 316 |
+
|
| 317 |
+
/**
|
| 318 |
+
* Score all moves using tree attention (batch evaluation)
|
| 319 |
+
*/
|
| 320 |
+
async scoreMoves(game: TrigoGame, moves: Move[]): Promise<ScoredMove[]> {
|
| 321 |
+
if (moves.length === 0) {
|
| 322 |
+
return [];
|
| 323 |
+
}
|
| 324 |
+
|
| 325 |
+
// Build tree structure
|
| 326 |
+
const { prefixTokens, evaluatedIds, mask, moveData } = this.buildMoveTree(game, moves);
|
| 327 |
+
|
| 328 |
+
console.debug(`Tree structure: ${evaluatedIds.length} nodes for ${moveData.length} moves`);
|
| 329 |
+
console.debug(`Evaluated IDs:`, evaluatedIds.map((id) => String.fromCharCode(id)).join(""));
|
| 330 |
+
//console.debug(
|
| 331 |
+
// `Move positions:`,
|
| 332 |
+
// moveData.map((m) => `${m.notation}@${m.leafPos}(parent=${m.parentPos})`)
|
| 333 |
+
//);
|
| 334 |
+
|
| 335 |
+
// Prepare inputs for evaluation
|
| 336 |
+
const inputs: EvaluationInputs = {
|
| 337 |
+
prefixIds: prefixTokens,
|
| 338 |
+
evaluatedIds: evaluatedIds,
|
| 339 |
+
evaluatedMask: mask
|
| 340 |
+
};
|
| 341 |
+
|
| 342 |
+
// Run inference
|
| 343 |
+
const output = await this.inferencer.runEvaluationInference(inputs);
|
| 344 |
+
const { logits, numEvaluated } = output;
|
| 345 |
+
|
| 346 |
+
console.debug(`Inference output: ${numEvaluated} evaluated positions`);
|
| 347 |
+
|
| 348 |
+
// Score each move by accumulating log probabilities for all tokens in the path
|
| 349 |
+
// For each move, traverse the full path from root to leaf and sum log probabilities
|
| 350 |
+
const scoredMoves: ScoredMove[] = [];
|
| 351 |
+
|
| 352 |
+
// Cache softmax results for each output position to avoid recomputation
|
| 353 |
+
const softmaxCache = new Map<number, Float32Array>();
|
| 354 |
+
const getSoftmax = (outputPos: number): Float32Array => {
|
| 355 |
+
if (!softmaxCache.has(outputPos)) {
|
| 356 |
+
softmaxCache.set(outputPos, this.inferencer.softmax(logits, outputPos));
|
| 357 |
+
}
|
| 358 |
+
return softmaxCache.get(outputPos)!;
|
| 359 |
+
};
|
| 360 |
+
|
| 361 |
+
for (const data of moveData) {
|
| 362 |
+
let logProb = 0;
|
| 363 |
+
|
| 364 |
+
// Reconstruct the full path from root to leaf using the mask
|
| 365 |
+
// The mask tells us which positions each position can attend to (ancestors)
|
| 366 |
+
// We need to find all positions from root (or first move token) to leaf
|
| 367 |
+
const leafPos = data.leafPos;
|
| 368 |
+
const path: number[] = [0];
|
| 369 |
+
|
| 370 |
+
// Build path by finding all ancestors that this leaf can see
|
| 371 |
+
// Start from position 0 and find all positions up to leafPos that are in the path
|
| 372 |
+
for (let pos = 0; pos <= leafPos; pos++) {
|
| 373 |
+
// Check if leaf can see this position (it's an ancestor or self)
|
| 374 |
+
if (mask[leafPos * evaluatedIds.length + pos] === 1) {
|
| 375 |
+
path.push(pos + 1);
|
| 376 |
+
}
|
| 377 |
+
}
|
| 378 |
+
//console.debug("path:", data.notation, "->", path);
|
| 379 |
+
|
| 380 |
+
// Now accumulate log probabilities for all transitions in the path
|
| 381 |
+
// For each token in the path, we need P(token[i] | context up to token[i-1])
|
| 382 |
+
// The logits at output position j predict the NEXT token after position j
|
| 383 |
+
// So to get P(token at position i | context), we look at output from parent position
|
| 384 |
+
for (let i = 0; i < path.length; i++) {
|
| 385 |
+
const currentPos = path[i];
|
| 386 |
+
const currentToken = data.notation.charCodeAt(i);
|
| 387 |
+
|
| 388 |
+
// Subsequent tokens: predicted from previous position
|
| 389 |
+
// The output at prevPos predicts the token at currentPos
|
| 390 |
+
|
| 391 |
+
console.assert(currentPos <= numEvaluated, `Output position ${currentPos} exceeds numEvaluated ${numEvaluated}`);
|
| 392 |
+
|
| 393 |
+
if (currentPos <= numEvaluated) {
|
| 394 |
+
const probs = getSoftmax(currentPos);
|
| 395 |
+
const prob = probs[currentToken];
|
| 396 |
+
|
| 397 |
+
if (prob > 0)
|
| 398 |
+
logProb += Math.log(prob);
|
| 399 |
+
else
|
| 400 |
+
logProb += -100;
|
| 401 |
+
}
|
| 402 |
+
else
|
| 403 |
+
logProb += -100;
|
| 404 |
+
}
|
| 405 |
+
|
| 406 |
+
scoredMoves.push({
|
| 407 |
+
move: data.move,
|
| 408 |
+
score: logProb,
|
| 409 |
+
notation: data.notation
|
| 410 |
+
});
|
| 411 |
+
}
|
| 412 |
+
|
| 413 |
+
return scoredMoves;
|
| 414 |
+
}
|
| 415 |
+
}
|
trigo-web/inc/tsconfig.json
CHANGED
|
@@ -13,4 +13,4 @@
|
|
| 13 |
},
|
| 14 |
"include": ["**/*.ts", "**/*.d.ts"],
|
| 15 |
"exclude": ["node_modules", "dist"]
|
| 16 |
-
}
|
|
|
|
| 13 |
},
|
| 14 |
"include": ["**/*.ts", "**/*.d.ts"],
|
| 15 |
"exclude": ["node_modules", "dist"]
|
| 16 |
+
}
|
trigo-web/package-lock.json
CHANGED
|
@@ -16,14 +16,19 @@
|
|
| 16 |
"concurrently": "^7.6.0",
|
| 17 |
"eslint-config-prettier": "^10.1.8",
|
| 18 |
"eslint-plugin-prettier": "^5.5.4",
|
|
|
|
| 19 |
"jison": "^0.4.18",
|
| 20 |
"jsdom": "^27.1.0",
|
|
|
|
|
|
|
|
|
|
| 21 |
"prettier": "^3.6.2",
|
| 22 |
"tsx": "^4.20.6",
|
| 23 |
"typescript": "^5.2.2",
|
| 24 |
"vite": "^5.4.21",
|
| 25 |
"vitest": "^4.0.6",
|
| 26 |
"vue": "^3.3.4",
|
|
|
|
| 27 |
"yargs": "^18.0.0"
|
| 28 |
}
|
| 29 |
},
|
|
@@ -250,9 +255,9 @@
|
|
| 250 |
}
|
| 251 |
},
|
| 252 |
"node_modules/@esbuild/aix-ppc64": {
|
| 253 |
-
"version": "0.
|
| 254 |
-
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.
|
| 255 |
-
"integrity": "sha512-
|
| 256 |
"cpu": [
|
| 257 |
"ppc64"
|
| 258 |
],
|
|
@@ -262,13 +267,13 @@
|
|
| 262 |
"aix"
|
| 263 |
],
|
| 264 |
"engines": {
|
| 265 |
-
"node": ">=
|
| 266 |
}
|
| 267 |
},
|
| 268 |
"node_modules/@esbuild/android-arm": {
|
| 269 |
-
"version": "0.
|
| 270 |
-
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.
|
| 271 |
-
"integrity": "sha512-
|
| 272 |
"cpu": [
|
| 273 |
"arm"
|
| 274 |
],
|
|
@@ -278,13 +283,13 @@
|
|
| 278 |
"android"
|
| 279 |
],
|
| 280 |
"engines": {
|
| 281 |
-
"node": ">=
|
| 282 |
}
|
| 283 |
},
|
| 284 |
"node_modules/@esbuild/android-arm64": {
|
| 285 |
-
"version": "0.
|
| 286 |
-
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.
|
| 287 |
-
"integrity": "sha512-
|
| 288 |
"cpu": [
|
| 289 |
"arm64"
|
| 290 |
],
|
|
@@ -294,13 +299,13 @@
|
|
| 294 |
"android"
|
| 295 |
],
|
| 296 |
"engines": {
|
| 297 |
-
"node": ">=
|
| 298 |
}
|
| 299 |
},
|
| 300 |
"node_modules/@esbuild/android-x64": {
|
| 301 |
-
"version": "0.
|
| 302 |
-
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.
|
| 303 |
-
"integrity": "sha512-
|
| 304 |
"cpu": [
|
| 305 |
"x64"
|
| 306 |
],
|
|
@@ -310,13 +315,13 @@
|
|
| 310 |
"android"
|
| 311 |
],
|
| 312 |
"engines": {
|
| 313 |
-
"node": ">=
|
| 314 |
}
|
| 315 |
},
|
| 316 |
"node_modules/@esbuild/darwin-arm64": {
|
| 317 |
-
"version": "0.
|
| 318 |
-
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.
|
| 319 |
-
"integrity": "sha512-
|
| 320 |
"cpu": [
|
| 321 |
"arm64"
|
| 322 |
],
|
|
@@ -326,13 +331,13 @@
|
|
| 326 |
"darwin"
|
| 327 |
],
|
| 328 |
"engines": {
|
| 329 |
-
"node": ">=
|
| 330 |
}
|
| 331 |
},
|
| 332 |
"node_modules/@esbuild/darwin-x64": {
|
| 333 |
-
"version": "0.
|
| 334 |
-
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.
|
| 335 |
-
"integrity": "sha512-
|
| 336 |
"cpu": [
|
| 337 |
"x64"
|
| 338 |
],
|
|
@@ -342,13 +347,13 @@
|
|
| 342 |
"darwin"
|
| 343 |
],
|
| 344 |
"engines": {
|
| 345 |
-
"node": ">=
|
| 346 |
}
|
| 347 |
},
|
| 348 |
"node_modules/@esbuild/freebsd-arm64": {
|
| 349 |
-
"version": "0.
|
| 350 |
-
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.
|
| 351 |
-
"integrity": "sha512-
|
| 352 |
"cpu": [
|
| 353 |
"arm64"
|
| 354 |
],
|
|
@@ -358,13 +363,13 @@
|
|
| 358 |
"freebsd"
|
| 359 |
],
|
| 360 |
"engines": {
|
| 361 |
-
"node": ">=
|
| 362 |
}
|
| 363 |
},
|
| 364 |
"node_modules/@esbuild/freebsd-x64": {
|
| 365 |
-
"version": "0.
|
| 366 |
-
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.
|
| 367 |
-
"integrity": "sha512-
|
| 368 |
"cpu": [
|
| 369 |
"x64"
|
| 370 |
],
|
|
@@ -374,13 +379,13 @@
|
|
| 374 |
"freebsd"
|
| 375 |
],
|
| 376 |
"engines": {
|
| 377 |
-
"node": ">=
|
| 378 |
}
|
| 379 |
},
|
| 380 |
"node_modules/@esbuild/linux-arm": {
|
| 381 |
-
"version": "0.
|
| 382 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.
|
| 383 |
-
"integrity": "sha512-
|
| 384 |
"cpu": [
|
| 385 |
"arm"
|
| 386 |
],
|
|
@@ -390,13 +395,13 @@
|
|
| 390 |
"linux"
|
| 391 |
],
|
| 392 |
"engines": {
|
| 393 |
-
"node": ">=
|
| 394 |
}
|
| 395 |
},
|
| 396 |
"node_modules/@esbuild/linux-arm64": {
|
| 397 |
-
"version": "0.
|
| 398 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.
|
| 399 |
-
"integrity": "sha512-
|
| 400 |
"cpu": [
|
| 401 |
"arm64"
|
| 402 |
],
|
|
@@ -406,13 +411,13 @@
|
|
| 406 |
"linux"
|
| 407 |
],
|
| 408 |
"engines": {
|
| 409 |
-
"node": ">=
|
| 410 |
}
|
| 411 |
},
|
| 412 |
"node_modules/@esbuild/linux-ia32": {
|
| 413 |
-
"version": "0.
|
| 414 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.
|
| 415 |
-
"integrity": "sha512-
|
| 416 |
"cpu": [
|
| 417 |
"ia32"
|
| 418 |
],
|
|
@@ -422,13 +427,13 @@
|
|
| 422 |
"linux"
|
| 423 |
],
|
| 424 |
"engines": {
|
| 425 |
-
"node": ">=
|
| 426 |
}
|
| 427 |
},
|
| 428 |
"node_modules/@esbuild/linux-loong64": {
|
| 429 |
-
"version": "0.
|
| 430 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.
|
| 431 |
-
"integrity": "sha512-
|
| 432 |
"cpu": [
|
| 433 |
"loong64"
|
| 434 |
],
|
|
@@ -438,13 +443,13 @@
|
|
| 438 |
"linux"
|
| 439 |
],
|
| 440 |
"engines": {
|
| 441 |
-
"node": ">=
|
| 442 |
}
|
| 443 |
},
|
| 444 |
"node_modules/@esbuild/linux-mips64el": {
|
| 445 |
-
"version": "0.
|
| 446 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.
|
| 447 |
-
"integrity": "sha512-
|
| 448 |
"cpu": [
|
| 449 |
"mips64el"
|
| 450 |
],
|
|
@@ -454,13 +459,13 @@
|
|
| 454 |
"linux"
|
| 455 |
],
|
| 456 |
"engines": {
|
| 457 |
-
"node": ">=
|
| 458 |
}
|
| 459 |
},
|
| 460 |
"node_modules/@esbuild/linux-ppc64": {
|
| 461 |
-
"version": "0.
|
| 462 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.
|
| 463 |
-
"integrity": "sha512-
|
| 464 |
"cpu": [
|
| 465 |
"ppc64"
|
| 466 |
],
|
|
@@ -470,13 +475,13 @@
|
|
| 470 |
"linux"
|
| 471 |
],
|
| 472 |
"engines": {
|
| 473 |
-
"node": ">=
|
| 474 |
}
|
| 475 |
},
|
| 476 |
"node_modules/@esbuild/linux-riscv64": {
|
| 477 |
-
"version": "0.
|
| 478 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.
|
| 479 |
-
"integrity": "sha512-
|
| 480 |
"cpu": [
|
| 481 |
"riscv64"
|
| 482 |
],
|
|
@@ -486,13 +491,13 @@
|
|
| 486 |
"linux"
|
| 487 |
],
|
| 488 |
"engines": {
|
| 489 |
-
"node": ">=
|
| 490 |
}
|
| 491 |
},
|
| 492 |
"node_modules/@esbuild/linux-s390x": {
|
| 493 |
-
"version": "0.
|
| 494 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.
|
| 495 |
-
"integrity": "sha512-
|
| 496 |
"cpu": [
|
| 497 |
"s390x"
|
| 498 |
],
|
|
@@ -502,13 +507,13 @@
|
|
| 502 |
"linux"
|
| 503 |
],
|
| 504 |
"engines": {
|
| 505 |
-
"node": ">=
|
| 506 |
}
|
| 507 |
},
|
| 508 |
"node_modules/@esbuild/linux-x64": {
|
| 509 |
-
"version": "0.
|
| 510 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.
|
| 511 |
-
"integrity": "sha512-
|
| 512 |
"cpu": [
|
| 513 |
"x64"
|
| 514 |
],
|
|
@@ -518,7 +523,7 @@
|
|
| 518 |
"linux"
|
| 519 |
],
|
| 520 |
"engines": {
|
| 521 |
-
"node": ">=
|
| 522 |
}
|
| 523 |
},
|
| 524 |
"node_modules/@esbuild/netbsd-arm64": {
|
|
@@ -538,9 +543,9 @@
|
|
| 538 |
}
|
| 539 |
},
|
| 540 |
"node_modules/@esbuild/netbsd-x64": {
|
| 541 |
-
"version": "0.
|
| 542 |
-
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.
|
| 543 |
-
"integrity": "sha512-
|
| 544 |
"cpu": [
|
| 545 |
"x64"
|
| 546 |
],
|
|
@@ -550,7 +555,7 @@
|
|
| 550 |
"netbsd"
|
| 551 |
],
|
| 552 |
"engines": {
|
| 553 |
-
"node": ">=
|
| 554 |
}
|
| 555 |
},
|
| 556 |
"node_modules/@esbuild/openbsd-arm64": {
|
|
@@ -570,9 +575,9 @@
|
|
| 570 |
}
|
| 571 |
},
|
| 572 |
"node_modules/@esbuild/openbsd-x64": {
|
| 573 |
-
"version": "0.
|
| 574 |
-
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.
|
| 575 |
-
"integrity": "sha512-
|
| 576 |
"cpu": [
|
| 577 |
"x64"
|
| 578 |
],
|
|
@@ -582,7 +587,7 @@
|
|
| 582 |
"openbsd"
|
| 583 |
],
|
| 584 |
"engines": {
|
| 585 |
-
"node": ">=
|
| 586 |
}
|
| 587 |
},
|
| 588 |
"node_modules/@esbuild/openharmony-arm64": {
|
|
@@ -602,9 +607,9 @@
|
|
| 602 |
}
|
| 603 |
},
|
| 604 |
"node_modules/@esbuild/sunos-x64": {
|
| 605 |
-
"version": "0.
|
| 606 |
-
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.
|
| 607 |
-
"integrity": "sha512-
|
| 608 |
"cpu": [
|
| 609 |
"x64"
|
| 610 |
],
|
|
@@ -614,13 +619,13 @@
|
|
| 614 |
"sunos"
|
| 615 |
],
|
| 616 |
"engines": {
|
| 617 |
-
"node": ">=
|
| 618 |
}
|
| 619 |
},
|
| 620 |
"node_modules/@esbuild/win32-arm64": {
|
| 621 |
-
"version": "0.
|
| 622 |
-
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.
|
| 623 |
-
"integrity": "sha512-
|
| 624 |
"cpu": [
|
| 625 |
"arm64"
|
| 626 |
],
|
|
@@ -630,13 +635,13 @@
|
|
| 630 |
"win32"
|
| 631 |
],
|
| 632 |
"engines": {
|
| 633 |
-
"node": ">=
|
| 634 |
}
|
| 635 |
},
|
| 636 |
"node_modules/@esbuild/win32-ia32": {
|
| 637 |
-
"version": "0.
|
| 638 |
-
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.
|
| 639 |
-
"integrity": "sha512-
|
| 640 |
"cpu": [
|
| 641 |
"ia32"
|
| 642 |
],
|
|
@@ -646,13 +651,13 @@
|
|
| 646 |
"win32"
|
| 647 |
],
|
| 648 |
"engines": {
|
| 649 |
-
"node": ">=
|
| 650 |
}
|
| 651 |
},
|
| 652 |
"node_modules/@esbuild/win32-x64": {
|
| 653 |
-
"version": "0.
|
| 654 |
-
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.
|
| 655 |
-
"integrity": "sha512-
|
| 656 |
"cpu": [
|
| 657 |
"x64"
|
| 658 |
],
|
|
@@ -662,7 +667,7 @@
|
|
| 662 |
"win32"
|
| 663 |
],
|
| 664 |
"engines": {
|
| 665 |
-
"node": ">=
|
| 666 |
}
|
| 667 |
},
|
| 668 |
"node_modules/@eslint-community/eslint-utils": {
|
|
@@ -885,6 +890,70 @@
|
|
| 885 |
"integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==",
|
| 886 |
"dev": true
|
| 887 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 888 |
"node_modules/@rollup/rollup-android-arm-eabi": {
|
| 889 |
"version": "4.52.5",
|
| 890 |
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz",
|
|
@@ -1342,6 +1411,32 @@
|
|
| 1342 |
"url": "https://opencollective.com/vitest"
|
| 1343 |
}
|
| 1344 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1345 |
"node_modules/@vue/compiler-core": {
|
| 1346 |
"version": "3.5.22",
|
| 1347 |
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.22.tgz",
|
|
@@ -1404,6 +1499,29 @@
|
|
| 1404 |
"@vue/shared": "3.5.22"
|
| 1405 |
}
|
| 1406 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1407 |
"node_modules/@vue/reactivity": {
|
| 1408 |
"version": "3.5.22",
|
| 1409 |
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.22.tgz",
|
|
@@ -1477,6 +1595,15 @@
|
|
| 1477 |
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
| 1478 |
}
|
| 1479 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1480 |
"node_modules/agent-base": {
|
| 1481 |
"version": "7.1.4",
|
| 1482 |
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
|
|
@@ -1503,6 +1630,12 @@
|
|
| 1503 |
"url": "https://github.com/sponsors/epoberezkin"
|
| 1504 |
}
|
| 1505 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1506 |
"node_modules/amdefine": {
|
| 1507 |
"version": "1.0.1",
|
| 1508 |
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
|
|
@@ -1513,6 +1646,21 @@
|
|
| 1513 |
"node": ">=0.4.2"
|
| 1514 |
}
|
| 1515 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1516 |
"node_modules/ansi-regex": {
|
| 1517 |
"version": "6.2.2",
|
| 1518 |
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
|
|
@@ -1572,6 +1720,13 @@
|
|
| 1572 |
"require-from-string": "^2.0.2"
|
| 1573 |
}
|
| 1574 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1575 |
"node_modules/brace-expansion": {
|
| 1576 |
"version": "1.1.12",
|
| 1577 |
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
|
@@ -1583,10 +1738,22 @@
|
|
| 1583 |
"concat-map": "0.0.1"
|
| 1584 |
}
|
| 1585 |
},
|
| 1586 |
-
"node_modules/
|
| 1587 |
-
"version": "3.
|
| 1588 |
-
"resolved": "https://registry.npmjs.org/
|
| 1589 |
-
"integrity": "sha512-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1590 |
"dev": true,
|
| 1591 |
"peer": true,
|
| 1592 |
"engines": {
|
|
@@ -1618,6 +1785,18 @@
|
|
| 1618 |
"url": "https://github.com/chalk/chalk?sponsor=1"
|
| 1619 |
}
|
| 1620 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1621 |
"node_modules/cjson": {
|
| 1622 |
"version": "0.3.0",
|
| 1623 |
"resolved": "https://registry.npmjs.org/cjson/-/cjson-0.3.0.tgz",
|
|
@@ -1630,6 +1809,53 @@
|
|
| 1630 |
"node": ">= 0.3.0"
|
| 1631 |
}
|
| 1632 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1633 |
"node_modules/cliui": {
|
| 1634 |
"version": "9.0.1",
|
| 1635 |
"resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz",
|
|
@@ -1662,6 +1888,12 @@
|
|
| 1662 |
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
| 1663 |
"dev": true
|
| 1664 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1665 |
"node_modules/colors": {
|
| 1666 |
"version": "0.5.1",
|
| 1667 |
"resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz",
|
|
@@ -1671,6 +1903,15 @@
|
|
| 1671 |
"node": ">=0.1.90"
|
| 1672 |
}
|
| 1673 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1674 |
"node_modules/concat-map": {
|
| 1675 |
"version": "0.0.1",
|
| 1676 |
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
|
@@ -1760,21 +2001,6 @@
|
|
| 1760 |
"node": ">=8"
|
| 1761 |
}
|
| 1762 |
},
|
| 1763 |
-
"node_modules/concurrently/node_modules/supports-color": {
|
| 1764 |
-
"version": "8.1.1",
|
| 1765 |
-
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
| 1766 |
-
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
|
| 1767 |
-
"dev": true,
|
| 1768 |
-
"dependencies": {
|
| 1769 |
-
"has-flag": "^4.0.0"
|
| 1770 |
-
},
|
| 1771 |
-
"engines": {
|
| 1772 |
-
"node": ">=10"
|
| 1773 |
-
},
|
| 1774 |
-
"funding": {
|
| 1775 |
-
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
| 1776 |
-
}
|
| 1777 |
-
},
|
| 1778 |
"node_modules/concurrently/node_modules/wrap-ansi": {
|
| 1779 |
"version": "7.0.0",
|
| 1780 |
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
|
@@ -1926,6 +2152,46 @@
|
|
| 1926 |
"dev": true,
|
| 1927 |
"peer": true
|
| 1928 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1929 |
"node_modules/ebnf-parser": {
|
| 1930 |
"version": "0.1.10",
|
| 1931 |
"resolved": "https://registry.npmjs.org/ebnf-parser/-/ebnf-parser-0.1.10.tgz",
|
|
@@ -1950,48 +2216,87 @@
|
|
| 1950 |
"url": "https://github.com/fb55/entities?sponsor=1"
|
| 1951 |
}
|
| 1952 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1953 |
"node_modules/es-module-lexer": {
|
| 1954 |
"version": "1.7.0",
|
| 1955 |
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
|
| 1956 |
"integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
|
| 1957 |
"dev": true
|
| 1958 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1959 |
"node_modules/esbuild": {
|
| 1960 |
-
"version": "0.
|
| 1961 |
-
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.
|
| 1962 |
-
"integrity": "sha512-
|
| 1963 |
"dev": true,
|
| 1964 |
"hasInstallScript": true,
|
| 1965 |
"bin": {
|
| 1966 |
"esbuild": "bin/esbuild"
|
| 1967 |
},
|
| 1968 |
"engines": {
|
| 1969 |
-
"node": ">=
|
| 1970 |
},
|
| 1971 |
"optionalDependencies": {
|
| 1972 |
-
"@esbuild/aix-ppc64": "0.
|
| 1973 |
-
"@esbuild/android-arm": "0.
|
| 1974 |
-
"@esbuild/android-arm64": "0.
|
| 1975 |
-
"@esbuild/android-x64": "0.
|
| 1976 |
-
"@esbuild/darwin-arm64": "0.
|
| 1977 |
-
"@esbuild/darwin-x64": "0.
|
| 1978 |
-
"@esbuild/freebsd-arm64": "0.
|
| 1979 |
-
"@esbuild/freebsd-x64": "0.
|
| 1980 |
-
"@esbuild/linux-arm": "0.
|
| 1981 |
-
"@esbuild/linux-arm64": "0.
|
| 1982 |
-
"@esbuild/linux-ia32": "0.
|
| 1983 |
-
"@esbuild/linux-loong64": "0.
|
| 1984 |
-
"@esbuild/linux-mips64el": "0.
|
| 1985 |
-
"@esbuild/linux-ppc64": "0.
|
| 1986 |
-
"@esbuild/linux-riscv64": "0.
|
| 1987 |
-
"@esbuild/linux-s390x": "0.
|
| 1988 |
-
"@esbuild/linux-x64": "0.
|
| 1989 |
-
"@esbuild/netbsd-
|
| 1990 |
-
"@esbuild/
|
| 1991 |
-
"@esbuild/
|
| 1992 |
-
"@esbuild/
|
| 1993 |
-
"@esbuild/
|
| 1994 |
-
"@esbuild/
|
|
|
|
|
|
|
|
|
|
| 1995 |
}
|
| 1996 |
},
|
| 1997 |
"node_modules/escalade": {
|
|
@@ -2008,7 +2313,6 @@
|
|
| 2008 |
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
| 2009 |
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
| 2010 |
"dev": true,
|
| 2011 |
-
"peer": true,
|
| 2012 |
"engines": {
|
| 2013 |
"node": ">=10"
|
| 2014 |
},
|
|
@@ -2273,6 +2577,12 @@
|
|
| 2273 |
"node": ">=0.10.0"
|
| 2274 |
}
|
| 2275 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2276 |
"node_modules/expect-type": {
|
| 2277 |
"version": "1.2.2",
|
| 2278 |
"resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz",
|
|
@@ -2345,6 +2655,18 @@
|
|
| 2345 |
"node": ">=16.0.0"
|
| 2346 |
}
|
| 2347 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2348 |
"node_modules/find-up": {
|
| 2349 |
"version": "5.0.0",
|
| 2350 |
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
|
|
@@ -2376,6 +2698,12 @@
|
|
| 2376 |
"node": ">=16"
|
| 2377 |
}
|
| 2378 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2379 |
"node_modules/flatted": {
|
| 2380 |
"version": "3.3.3",
|
| 2381 |
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
|
|
@@ -2442,6 +2770,23 @@
|
|
| 2442 |
"node": ">=10.13.0"
|
| 2443 |
}
|
| 2444 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2445 |
"node_modules/globals": {
|
| 2446 |
"version": "14.0.0",
|
| 2447 |
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
|
|
@@ -2455,6 +2800,40 @@
|
|
| 2455 |
"url": "https://github.com/sponsors/sindresorhus"
|
| 2456 |
}
|
| 2457 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2458 |
"node_modules/has-flag": {
|
| 2459 |
"version": "4.0.0",
|
| 2460 |
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
|
@@ -2464,6 +2843,18 @@
|
|
| 2464 |
"node": ">=8"
|
| 2465 |
}
|
| 2466 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2467 |
"node_modules/html-encoding-sniffer": {
|
| 2468 |
"version": "4.0.0",
|
| 2469 |
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
|
|
@@ -2502,6 +2893,21 @@
|
|
| 2502 |
"node": ">= 14"
|
| 2503 |
}
|
| 2504 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2505 |
"node_modules/iconv-lite": {
|
| 2506 |
"version": "0.6.3",
|
| 2507 |
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
|
@@ -2583,6 +2989,15 @@
|
|
| 2583 |
"node": ">=0.10.0"
|
| 2584 |
}
|
| 2585 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2586 |
"node_modules/is-potential-custom-element-name": {
|
| 2587 |
"version": "1.0.1",
|
| 2588 |
"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
|
|
@@ -2707,6 +3122,12 @@
|
|
| 2707 |
"dev": true,
|
| 2708 |
"peer": true
|
| 2709 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2710 |
"node_modules/jsonlint": {
|
| 2711 |
"version": "1.6.0",
|
| 2712 |
"resolved": "https://registry.npmjs.org/jsonlint/-/jsonlint-1.6.0.tgz",
|
|
@@ -2771,24 +3192,65 @@
|
|
| 2771 |
"integrity": "sha512-DuAEISsr1H4LOpmFLkyMc8YStiRWZCO8hMsoXAXSbgyfvs2WQhSt0+/FBv3ZU/JBFZMGcE+FWzEBSzwUU7U27w==",
|
| 2772 |
"dev": true
|
| 2773 |
},
|
| 2774 |
-
"node_modules/
|
| 2775 |
-
"version": "
|
| 2776 |
-
"resolved": "https://registry.npmjs.org/
|
| 2777 |
-
"integrity": "sha512-
|
| 2778 |
"dev": true,
|
| 2779 |
-
"peer": true,
|
| 2780 |
"dependencies": {
|
| 2781 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2782 |
},
|
| 2783 |
"engines": {
|
| 2784 |
-
"node": ">=
|
| 2785 |
},
|
| 2786 |
"funding": {
|
| 2787 |
-
"url": "https://
|
| 2788 |
}
|
| 2789 |
},
|
| 2790 |
-
"node_modules/
|
| 2791 |
-
"version": "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2792 |
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
| 2793 |
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
| 2794 |
"dev": true
|
|
@@ -2800,6 +3262,31 @@
|
|
| 2800 |
"dev": true,
|
| 2801 |
"peer": true
|
| 2802 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2803 |
"node_modules/lru-cache": {
|
| 2804 |
"version": "11.2.2",
|
| 2805 |
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz",
|
|
@@ -2818,12 +3305,61 @@
|
|
| 2818 |
"@jridgewell/sourcemap-codec": "^1.5.5"
|
| 2819 |
}
|
| 2820 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2821 |
"node_modules/mdn-data": {
|
| 2822 |
"version": "2.12.2",
|
| 2823 |
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz",
|
| 2824 |
"integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==",
|
| 2825 |
"dev": true
|
| 2826 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2827 |
"node_modules/minimatch": {
|
| 2828 |
"version": "3.1.2",
|
| 2829 |
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
|
@@ -2852,6 +3388,24 @@
|
|
| 2852 |
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
| 2853 |
"dev": true
|
| 2854 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2855 |
"node_modules/nanoid": {
|
| 2856 |
"version": "3.3.11",
|
| 2857 |
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
|
@@ -2891,6 +3445,67 @@
|
|
| 2891 |
"node": "*"
|
| 2892 |
}
|
| 2893 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2894 |
"node_modules/optionator": {
|
| 2895 |
"version": "0.9.4",
|
| 2896 |
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
|
@@ -2966,6 +3581,12 @@
|
|
| 2966 |
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
| 2967 |
}
|
| 2968 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2969 |
"node_modules/path-exists": {
|
| 2970 |
"version": "4.0.0",
|
| 2971 |
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
|
@@ -3010,6 +3631,24 @@
|
|
| 3010 |
"url": "https://github.com/sponsors/jonschlinkert"
|
| 3011 |
}
|
| 3012 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3013 |
"node_modules/postcss": {
|
| 3014 |
"version": "8.5.6",
|
| 3015 |
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
|
@@ -3075,6 +3714,30 @@
|
|
| 3075 |
"node": ">=6.0.0"
|
| 3076 |
}
|
| 3077 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3078 |
"node_modules/punycode": {
|
| 3079 |
"version": "2.3.1",
|
| 3080 |
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
|
@@ -3121,6 +3784,45 @@
|
|
| 3121 |
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
|
| 3122 |
}
|
| 3123 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3124 |
"node_modules/rollup": {
|
| 3125 |
"version": "4.52.5",
|
| 3126 |
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz",
|
|
@@ -3189,6 +3891,39 @@
|
|
| 3189 |
"node": ">=v12.22.7"
|
| 3190 |
}
|
| 3191 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3192 |
"node_modules/shebang-command": {
|
| 3193 |
"version": "2.0.0",
|
| 3194 |
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
|
@@ -3230,6 +3965,18 @@
|
|
| 3230 |
"integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
|
| 3231 |
"dev": true
|
| 3232 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3233 |
"node_modules/sirv": {
|
| 3234 |
"version": "3.0.2",
|
| 3235 |
"resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz",
|
|
@@ -3244,6 +3991,49 @@
|
|
| 3244 |
"node": ">=18"
|
| 3245 |
}
|
| 3246 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3247 |
"node_modules/source-map": {
|
| 3248 |
"version": "0.1.43",
|
| 3249 |
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
|
|
@@ -3272,6 +4062,12 @@
|
|
| 3272 |
"integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==",
|
| 3273 |
"dev": true
|
| 3274 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3275 |
"node_modules/stackback": {
|
| 3276 |
"version": "0.0.2",
|
| 3277 |
"resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
|
|
@@ -3284,6 +4080,15 @@
|
|
| 3284 |
"integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==",
|
| 3285 |
"dev": true
|
| 3286 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3287 |
"node_modules/string-width": {
|
| 3288 |
"version": "7.2.0",
|
| 3289 |
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
|
|
@@ -3330,15 +4135,18 @@
|
|
| 3330 |
}
|
| 3331 |
},
|
| 3332 |
"node_modules/supports-color": {
|
| 3333 |
-
"version": "
|
| 3334 |
-
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-
|
| 3335 |
-
"integrity": "sha512-
|
| 3336 |
"dev": true,
|
| 3337 |
"dependencies": {
|
| 3338 |
"has-flag": "^4.0.0"
|
| 3339 |
},
|
| 3340 |
"engines": {
|
| 3341 |
-
"node": ">=
|
|
|
|
|
|
|
|
|
|
| 3342 |
}
|
| 3343 |
},
|
| 3344 |
"node_modules/symbol-tree": {
|
|
@@ -3417,6 +4225,18 @@
|
|
| 3417 |
"integrity": "sha512-DieYoGrP78PWKsrXr8MZwtQ7GLCUeLxihtjC1jZsW1DnvSMdKPitJSe8OSYDM2u5H6g3kWJZpePqkp43TfLh0g==",
|
| 3418 |
"dev": true
|
| 3419 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3420 |
"node_modules/totalist": {
|
| 3421 |
"version": "3.0.1",
|
| 3422 |
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
|
|
@@ -3484,426 +4304,29 @@
|
|
| 3484 |
"fsevents": "~2.3.3"
|
| 3485 |
}
|
| 3486 |
},
|
| 3487 |
-
"node_modules/
|
| 3488 |
-
"version": "0.
|
| 3489 |
-
"resolved": "https://registry.npmjs.org
|
| 3490 |
-
"integrity": "sha512-
|
| 3491 |
-
"cpu": [
|
| 3492 |
-
"ppc64"
|
| 3493 |
-
],
|
| 3494 |
"dev": true,
|
| 3495 |
-
"
|
| 3496 |
-
"
|
| 3497 |
-
"
|
| 3498 |
-
|
| 3499 |
"engines": {
|
| 3500 |
-
"node": ">=
|
| 3501 |
-
}
|
| 3502 |
-
},
|
| 3503 |
-
"node_modules/tsx/node_modules/@esbuild/android-arm": {
|
| 3504 |
-
"version": "0.25.12",
|
| 3505 |
-
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
|
| 3506 |
-
"integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
|
| 3507 |
-
"cpu": [
|
| 3508 |
-
"arm"
|
| 3509 |
-
],
|
| 3510 |
-
"dev": true,
|
| 3511 |
-
"optional": true,
|
| 3512 |
-
"os": [
|
| 3513 |
-
"android"
|
| 3514 |
-
],
|
| 3515 |
-
"engines": {
|
| 3516 |
-
"node": ">=18"
|
| 3517 |
-
}
|
| 3518 |
-
},
|
| 3519 |
-
"node_modules/tsx/node_modules/@esbuild/android-arm64": {
|
| 3520 |
-
"version": "0.25.12",
|
| 3521 |
-
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
|
| 3522 |
-
"integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
|
| 3523 |
-
"cpu": [
|
| 3524 |
-
"arm64"
|
| 3525 |
-
],
|
| 3526 |
-
"dev": true,
|
| 3527 |
-
"optional": true,
|
| 3528 |
-
"os": [
|
| 3529 |
-
"android"
|
| 3530 |
-
],
|
| 3531 |
-
"engines": {
|
| 3532 |
-
"node": ">=18"
|
| 3533 |
-
}
|
| 3534 |
-
},
|
| 3535 |
-
"node_modules/tsx/node_modules/@esbuild/android-x64": {
|
| 3536 |
-
"version": "0.25.12",
|
| 3537 |
-
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
|
| 3538 |
-
"integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
|
| 3539 |
-
"cpu": [
|
| 3540 |
-
"x64"
|
| 3541 |
-
],
|
| 3542 |
-
"dev": true,
|
| 3543 |
-
"optional": true,
|
| 3544 |
-
"os": [
|
| 3545 |
-
"android"
|
| 3546 |
-
],
|
| 3547 |
-
"engines": {
|
| 3548 |
-
"node": ">=18"
|
| 3549 |
-
}
|
| 3550 |
-
},
|
| 3551 |
-
"node_modules/tsx/node_modules/@esbuild/darwin-arm64": {
|
| 3552 |
-
"version": "0.25.12",
|
| 3553 |
-
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
|
| 3554 |
-
"integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
|
| 3555 |
-
"cpu": [
|
| 3556 |
-
"arm64"
|
| 3557 |
-
],
|
| 3558 |
-
"dev": true,
|
| 3559 |
-
"optional": true,
|
| 3560 |
-
"os": [
|
| 3561 |
-
"darwin"
|
| 3562 |
-
],
|
| 3563 |
-
"engines": {
|
| 3564 |
-
"node": ">=18"
|
| 3565 |
-
}
|
| 3566 |
-
},
|
| 3567 |
-
"node_modules/tsx/node_modules/@esbuild/darwin-x64": {
|
| 3568 |
-
"version": "0.25.12",
|
| 3569 |
-
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
|
| 3570 |
-
"integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
|
| 3571 |
-
"cpu": [
|
| 3572 |
-
"x64"
|
| 3573 |
-
],
|
| 3574 |
-
"dev": true,
|
| 3575 |
-
"optional": true,
|
| 3576 |
-
"os": [
|
| 3577 |
-
"darwin"
|
| 3578 |
-
],
|
| 3579 |
-
"engines": {
|
| 3580 |
-
"node": ">=18"
|
| 3581 |
-
}
|
| 3582 |
-
},
|
| 3583 |
-
"node_modules/tsx/node_modules/@esbuild/freebsd-arm64": {
|
| 3584 |
-
"version": "0.25.12",
|
| 3585 |
-
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
|
| 3586 |
-
"integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
|
| 3587 |
-
"cpu": [
|
| 3588 |
-
"arm64"
|
| 3589 |
-
],
|
| 3590 |
-
"dev": true,
|
| 3591 |
-
"optional": true,
|
| 3592 |
-
"os": [
|
| 3593 |
-
"freebsd"
|
| 3594 |
-
],
|
| 3595 |
-
"engines": {
|
| 3596 |
-
"node": ">=18"
|
| 3597 |
-
}
|
| 3598 |
-
},
|
| 3599 |
-
"node_modules/tsx/node_modules/@esbuild/freebsd-x64": {
|
| 3600 |
-
"version": "0.25.12",
|
| 3601 |
-
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
|
| 3602 |
-
"integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
|
| 3603 |
-
"cpu": [
|
| 3604 |
-
"x64"
|
| 3605 |
-
],
|
| 3606 |
-
"dev": true,
|
| 3607 |
-
"optional": true,
|
| 3608 |
-
"os": [
|
| 3609 |
-
"freebsd"
|
| 3610 |
-
],
|
| 3611 |
-
"engines": {
|
| 3612 |
-
"node": ">=18"
|
| 3613 |
-
}
|
| 3614 |
-
},
|
| 3615 |
-
"node_modules/tsx/node_modules/@esbuild/linux-arm": {
|
| 3616 |
-
"version": "0.25.12",
|
| 3617 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
|
| 3618 |
-
"integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
|
| 3619 |
-
"cpu": [
|
| 3620 |
-
"arm"
|
| 3621 |
-
],
|
| 3622 |
-
"dev": true,
|
| 3623 |
-
"optional": true,
|
| 3624 |
-
"os": [
|
| 3625 |
-
"linux"
|
| 3626 |
-
],
|
| 3627 |
-
"engines": {
|
| 3628 |
-
"node": ">=18"
|
| 3629 |
-
}
|
| 3630 |
-
},
|
| 3631 |
-
"node_modules/tsx/node_modules/@esbuild/linux-arm64": {
|
| 3632 |
-
"version": "0.25.12",
|
| 3633 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
|
| 3634 |
-
"integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
|
| 3635 |
-
"cpu": [
|
| 3636 |
-
"arm64"
|
| 3637 |
-
],
|
| 3638 |
-
"dev": true,
|
| 3639 |
-
"optional": true,
|
| 3640 |
-
"os": [
|
| 3641 |
-
"linux"
|
| 3642 |
-
],
|
| 3643 |
-
"engines": {
|
| 3644 |
-
"node": ">=18"
|
| 3645 |
-
}
|
| 3646 |
-
},
|
| 3647 |
-
"node_modules/tsx/node_modules/@esbuild/linux-ia32": {
|
| 3648 |
-
"version": "0.25.12",
|
| 3649 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
|
| 3650 |
-
"integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
|
| 3651 |
-
"cpu": [
|
| 3652 |
-
"ia32"
|
| 3653 |
-
],
|
| 3654 |
-
"dev": true,
|
| 3655 |
-
"optional": true,
|
| 3656 |
-
"os": [
|
| 3657 |
-
"linux"
|
| 3658 |
-
],
|
| 3659 |
-
"engines": {
|
| 3660 |
-
"node": ">=18"
|
| 3661 |
-
}
|
| 3662 |
-
},
|
| 3663 |
-
"node_modules/tsx/node_modules/@esbuild/linux-loong64": {
|
| 3664 |
-
"version": "0.25.12",
|
| 3665 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
|
| 3666 |
-
"integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
|
| 3667 |
-
"cpu": [
|
| 3668 |
-
"loong64"
|
| 3669 |
-
],
|
| 3670 |
-
"dev": true,
|
| 3671 |
-
"optional": true,
|
| 3672 |
-
"os": [
|
| 3673 |
-
"linux"
|
| 3674 |
-
],
|
| 3675 |
-
"engines": {
|
| 3676 |
-
"node": ">=18"
|
| 3677 |
-
}
|
| 3678 |
-
},
|
| 3679 |
-
"node_modules/tsx/node_modules/@esbuild/linux-mips64el": {
|
| 3680 |
-
"version": "0.25.12",
|
| 3681 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
|
| 3682 |
-
"integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
|
| 3683 |
-
"cpu": [
|
| 3684 |
-
"mips64el"
|
| 3685 |
-
],
|
| 3686 |
-
"dev": true,
|
| 3687 |
-
"optional": true,
|
| 3688 |
-
"os": [
|
| 3689 |
-
"linux"
|
| 3690 |
-
],
|
| 3691 |
-
"engines": {
|
| 3692 |
-
"node": ">=18"
|
| 3693 |
-
}
|
| 3694 |
-
},
|
| 3695 |
-
"node_modules/tsx/node_modules/@esbuild/linux-ppc64": {
|
| 3696 |
-
"version": "0.25.12",
|
| 3697 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
|
| 3698 |
-
"integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
|
| 3699 |
-
"cpu": [
|
| 3700 |
-
"ppc64"
|
| 3701 |
-
],
|
| 3702 |
-
"dev": true,
|
| 3703 |
-
"optional": true,
|
| 3704 |
-
"os": [
|
| 3705 |
-
"linux"
|
| 3706 |
-
],
|
| 3707 |
-
"engines": {
|
| 3708 |
-
"node": ">=18"
|
| 3709 |
-
}
|
| 3710 |
-
},
|
| 3711 |
-
"node_modules/tsx/node_modules/@esbuild/linux-riscv64": {
|
| 3712 |
-
"version": "0.25.12",
|
| 3713 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
|
| 3714 |
-
"integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
|
| 3715 |
-
"cpu": [
|
| 3716 |
-
"riscv64"
|
| 3717 |
-
],
|
| 3718 |
-
"dev": true,
|
| 3719 |
-
"optional": true,
|
| 3720 |
-
"os": [
|
| 3721 |
-
"linux"
|
| 3722 |
-
],
|
| 3723 |
-
"engines": {
|
| 3724 |
-
"node": ">=18"
|
| 3725 |
-
}
|
| 3726 |
-
},
|
| 3727 |
-
"node_modules/tsx/node_modules/@esbuild/linux-s390x": {
|
| 3728 |
-
"version": "0.25.12",
|
| 3729 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
|
| 3730 |
-
"integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
|
| 3731 |
-
"cpu": [
|
| 3732 |
-
"s390x"
|
| 3733 |
-
],
|
| 3734 |
-
"dev": true,
|
| 3735 |
-
"optional": true,
|
| 3736 |
-
"os": [
|
| 3737 |
-
"linux"
|
| 3738 |
-
],
|
| 3739 |
-
"engines": {
|
| 3740 |
-
"node": ">=18"
|
| 3741 |
-
}
|
| 3742 |
-
},
|
| 3743 |
-
"node_modules/tsx/node_modules/@esbuild/linux-x64": {
|
| 3744 |
-
"version": "0.25.12",
|
| 3745 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
|
| 3746 |
-
"integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
|
| 3747 |
-
"cpu": [
|
| 3748 |
-
"x64"
|
| 3749 |
-
],
|
| 3750 |
-
"dev": true,
|
| 3751 |
-
"optional": true,
|
| 3752 |
-
"os": [
|
| 3753 |
-
"linux"
|
| 3754 |
-
],
|
| 3755 |
-
"engines": {
|
| 3756 |
-
"node": ">=18"
|
| 3757 |
-
}
|
| 3758 |
-
},
|
| 3759 |
-
"node_modules/tsx/node_modules/@esbuild/netbsd-x64": {
|
| 3760 |
-
"version": "0.25.12",
|
| 3761 |
-
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
|
| 3762 |
-
"integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
|
| 3763 |
-
"cpu": [
|
| 3764 |
-
"x64"
|
| 3765 |
-
],
|
| 3766 |
-
"dev": true,
|
| 3767 |
-
"optional": true,
|
| 3768 |
-
"os": [
|
| 3769 |
-
"netbsd"
|
| 3770 |
-
],
|
| 3771 |
-
"engines": {
|
| 3772 |
-
"node": ">=18"
|
| 3773 |
-
}
|
| 3774 |
-
},
|
| 3775 |
-
"node_modules/tsx/node_modules/@esbuild/openbsd-x64": {
|
| 3776 |
-
"version": "0.25.12",
|
| 3777 |
-
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
|
| 3778 |
-
"integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
|
| 3779 |
-
"cpu": [
|
| 3780 |
-
"x64"
|
| 3781 |
-
],
|
| 3782 |
-
"dev": true,
|
| 3783 |
-
"optional": true,
|
| 3784 |
-
"os": [
|
| 3785 |
-
"openbsd"
|
| 3786 |
-
],
|
| 3787 |
-
"engines": {
|
| 3788 |
-
"node": ">=18"
|
| 3789 |
-
}
|
| 3790 |
-
},
|
| 3791 |
-
"node_modules/tsx/node_modules/@esbuild/sunos-x64": {
|
| 3792 |
-
"version": "0.25.12",
|
| 3793 |
-
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
|
| 3794 |
-
"integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
|
| 3795 |
-
"cpu": [
|
| 3796 |
-
"x64"
|
| 3797 |
-
],
|
| 3798 |
-
"dev": true,
|
| 3799 |
-
"optional": true,
|
| 3800 |
-
"os": [
|
| 3801 |
-
"sunos"
|
| 3802 |
-
],
|
| 3803 |
-
"engines": {
|
| 3804 |
-
"node": ">=18"
|
| 3805 |
-
}
|
| 3806 |
-
},
|
| 3807 |
-
"node_modules/tsx/node_modules/@esbuild/win32-arm64": {
|
| 3808 |
-
"version": "0.25.12",
|
| 3809 |
-
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
|
| 3810 |
-
"integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
|
| 3811 |
-
"cpu": [
|
| 3812 |
-
"arm64"
|
| 3813 |
-
],
|
| 3814 |
-
"dev": true,
|
| 3815 |
-
"optional": true,
|
| 3816 |
-
"os": [
|
| 3817 |
-
"win32"
|
| 3818 |
-
],
|
| 3819 |
-
"engines": {
|
| 3820 |
-
"node": ">=18"
|
| 3821 |
-
}
|
| 3822 |
-
},
|
| 3823 |
-
"node_modules/tsx/node_modules/@esbuild/win32-ia32": {
|
| 3824 |
-
"version": "0.25.12",
|
| 3825 |
-
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
|
| 3826 |
-
"integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
|
| 3827 |
-
"cpu": [
|
| 3828 |
-
"ia32"
|
| 3829 |
-
],
|
| 3830 |
-
"dev": true,
|
| 3831 |
-
"optional": true,
|
| 3832 |
-
"os": [
|
| 3833 |
-
"win32"
|
| 3834 |
-
],
|
| 3835 |
-
"engines": {
|
| 3836 |
-
"node": ">=18"
|
| 3837 |
-
}
|
| 3838 |
-
},
|
| 3839 |
-
"node_modules/tsx/node_modules/@esbuild/win32-x64": {
|
| 3840 |
-
"version": "0.25.12",
|
| 3841 |
-
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
|
| 3842 |
-
"integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
|
| 3843 |
-
"cpu": [
|
| 3844 |
-
"x64"
|
| 3845 |
-
],
|
| 3846 |
-
"dev": true,
|
| 3847 |
-
"optional": true,
|
| 3848 |
-
"os": [
|
| 3849 |
-
"win32"
|
| 3850 |
-
],
|
| 3851 |
-
"engines": {
|
| 3852 |
-
"node": ">=18"
|
| 3853 |
}
|
| 3854 |
},
|
| 3855 |
-
"node_modules/
|
| 3856 |
-
"version": "0.
|
| 3857 |
-
"resolved": "https://registry.npmjs.org/
|
| 3858 |
-
"integrity": "sha512-
|
| 3859 |
"dev": true,
|
| 3860 |
-
"hasInstallScript": true,
|
| 3861 |
-
"bin": {
|
| 3862 |
-
"esbuild": "bin/esbuild"
|
| 3863 |
-
},
|
| 3864 |
"engines": {
|
| 3865 |
-
"node": ">=
|
| 3866 |
-
},
|
| 3867 |
-
"optionalDependencies": {
|
| 3868 |
-
"@esbuild/aix-ppc64": "0.25.12",
|
| 3869 |
-
"@esbuild/android-arm": "0.25.12",
|
| 3870 |
-
"@esbuild/android-arm64": "0.25.12",
|
| 3871 |
-
"@esbuild/android-x64": "0.25.12",
|
| 3872 |
-
"@esbuild/darwin-arm64": "0.25.12",
|
| 3873 |
-
"@esbuild/darwin-x64": "0.25.12",
|
| 3874 |
-
"@esbuild/freebsd-arm64": "0.25.12",
|
| 3875 |
-
"@esbuild/freebsd-x64": "0.25.12",
|
| 3876 |
-
"@esbuild/linux-arm": "0.25.12",
|
| 3877 |
-
"@esbuild/linux-arm64": "0.25.12",
|
| 3878 |
-
"@esbuild/linux-ia32": "0.25.12",
|
| 3879 |
-
"@esbuild/linux-loong64": "0.25.12",
|
| 3880 |
-
"@esbuild/linux-mips64el": "0.25.12",
|
| 3881 |
-
"@esbuild/linux-ppc64": "0.25.12",
|
| 3882 |
-
"@esbuild/linux-riscv64": "0.25.12",
|
| 3883 |
-
"@esbuild/linux-s390x": "0.25.12",
|
| 3884 |
-
"@esbuild/linux-x64": "0.25.12",
|
| 3885 |
-
"@esbuild/netbsd-arm64": "0.25.12",
|
| 3886 |
-
"@esbuild/netbsd-x64": "0.25.12",
|
| 3887 |
-
"@esbuild/openbsd-arm64": "0.25.12",
|
| 3888 |
-
"@esbuild/openbsd-x64": "0.25.12",
|
| 3889 |
-
"@esbuild/openharmony-arm64": "0.25.12",
|
| 3890 |
-
"@esbuild/sunos-x64": "0.25.12",
|
| 3891 |
-
"@esbuild/win32-arm64": "0.25.12",
|
| 3892 |
-
"@esbuild/win32-ia32": "0.25.12",
|
| 3893 |
-
"@esbuild/win32-x64": "0.25.12"
|
| 3894 |
-
}
|
| 3895 |
-
},
|
| 3896 |
-
"node_modules/type-check": {
|
| 3897 |
-
"version": "0.4.0",
|
| 3898 |
-
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
| 3899 |
-
"integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
|
| 3900 |
-
"dev": true,
|
| 3901 |
-
"peer": true,
|
| 3902 |
-
"dependencies": {
|
| 3903 |
-
"prelude-ls": "^1.2.1"
|
| 3904 |
},
|
| 3905 |
-
"
|
| 3906 |
-
"
|
| 3907 |
}
|
| 3908 |
},
|
| 3909 |
"node_modules/typescript": {
|
|
@@ -4003,87 +4426,10 @@
|
|
| 4003 |
}
|
| 4004 |
}
|
| 4005 |
},
|
| 4006 |
-
"node_modules/
|
| 4007 |
-
"version": "
|
| 4008 |
-
"resolved": "https://registry.npmjs.org/
|
| 4009 |
-
"integrity": "sha512-
|
| 4010 |
-
"dev": true,
|
| 4011 |
-
"dependencies": {
|
| 4012 |
-
"@vitest/expect": "4.0.6",
|
| 4013 |
-
"@vitest/mocker": "4.0.6",
|
| 4014 |
-
"@vitest/pretty-format": "4.0.6",
|
| 4015 |
-
"@vitest/runner": "4.0.6",
|
| 4016 |
-
"@vitest/snapshot": "4.0.6",
|
| 4017 |
-
"@vitest/spy": "4.0.6",
|
| 4018 |
-
"@vitest/utils": "4.0.6",
|
| 4019 |
-
"debug": "^4.4.3",
|
| 4020 |
-
"es-module-lexer": "^1.7.0",
|
| 4021 |
-
"expect-type": "^1.2.2",
|
| 4022 |
-
"magic-string": "^0.30.19",
|
| 4023 |
-
"pathe": "^2.0.3",
|
| 4024 |
-
"picomatch": "^4.0.3",
|
| 4025 |
-
"std-env": "^3.9.0",
|
| 4026 |
-
"tinybench": "^2.9.0",
|
| 4027 |
-
"tinyexec": "^0.3.2",
|
| 4028 |
-
"tinyglobby": "^0.2.15",
|
| 4029 |
-
"tinyrainbow": "^3.0.3",
|
| 4030 |
-
"vite": "^6.0.0 || ^7.0.0",
|
| 4031 |
-
"why-is-node-running": "^2.3.0"
|
| 4032 |
-
},
|
| 4033 |
-
"bin": {
|
| 4034 |
-
"vitest": "vitest.mjs"
|
| 4035 |
-
},
|
| 4036 |
-
"engines": {
|
| 4037 |
-
"node": "^20.0.0 || ^22.0.0 || >=24.0.0"
|
| 4038 |
-
},
|
| 4039 |
-
"funding": {
|
| 4040 |
-
"url": "https://opencollective.com/vitest"
|
| 4041 |
-
},
|
| 4042 |
-
"peerDependencies": {
|
| 4043 |
-
"@edge-runtime/vm": "*",
|
| 4044 |
-
"@types/debug": "^4.1.12",
|
| 4045 |
-
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
|
| 4046 |
-
"@vitest/browser-playwright": "4.0.6",
|
| 4047 |
-
"@vitest/browser-preview": "4.0.6",
|
| 4048 |
-
"@vitest/browser-webdriverio": "4.0.6",
|
| 4049 |
-
"@vitest/ui": "4.0.6",
|
| 4050 |
-
"happy-dom": "*",
|
| 4051 |
-
"jsdom": "*"
|
| 4052 |
-
},
|
| 4053 |
-
"peerDependenciesMeta": {
|
| 4054 |
-
"@edge-runtime/vm": {
|
| 4055 |
-
"optional": true
|
| 4056 |
-
},
|
| 4057 |
-
"@types/debug": {
|
| 4058 |
-
"optional": true
|
| 4059 |
-
},
|
| 4060 |
-
"@types/node": {
|
| 4061 |
-
"optional": true
|
| 4062 |
-
},
|
| 4063 |
-
"@vitest/browser-playwright": {
|
| 4064 |
-
"optional": true
|
| 4065 |
-
},
|
| 4066 |
-
"@vitest/browser-preview": {
|
| 4067 |
-
"optional": true
|
| 4068 |
-
},
|
| 4069 |
-
"@vitest/browser-webdriverio": {
|
| 4070 |
-
"optional": true
|
| 4071 |
-
},
|
| 4072 |
-
"@vitest/ui": {
|
| 4073 |
-
"optional": true
|
| 4074 |
-
},
|
| 4075 |
-
"happy-dom": {
|
| 4076 |
-
"optional": true
|
| 4077 |
-
},
|
| 4078 |
-
"jsdom": {
|
| 4079 |
-
"optional": true
|
| 4080 |
-
}
|
| 4081 |
-
}
|
| 4082 |
-
},
|
| 4083 |
-
"node_modules/vitest/node_modules/@esbuild/aix-ppc64": {
|
| 4084 |
-
"version": "0.25.12",
|
| 4085 |
-
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
|
| 4086 |
-
"integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
|
| 4087 |
"cpu": [
|
| 4088 |
"ppc64"
|
| 4089 |
],
|
|
@@ -4093,13 +4439,13 @@
|
|
| 4093 |
"aix"
|
| 4094 |
],
|
| 4095 |
"engines": {
|
| 4096 |
-
"node": ">=
|
| 4097 |
}
|
| 4098 |
},
|
| 4099 |
-
"node_modules/
|
| 4100 |
-
"version": "0.
|
| 4101 |
-
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.
|
| 4102 |
-
"integrity": "sha512-
|
| 4103 |
"cpu": [
|
| 4104 |
"arm"
|
| 4105 |
],
|
|
@@ -4109,13 +4455,13 @@
|
|
| 4109 |
"android"
|
| 4110 |
],
|
| 4111 |
"engines": {
|
| 4112 |
-
"node": ">=
|
| 4113 |
}
|
| 4114 |
},
|
| 4115 |
-
"node_modules/
|
| 4116 |
-
"version": "0.
|
| 4117 |
-
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.
|
| 4118 |
-
"integrity": "sha512-
|
| 4119 |
"cpu": [
|
| 4120 |
"arm64"
|
| 4121 |
],
|
|
@@ -4125,13 +4471,13 @@
|
|
| 4125 |
"android"
|
| 4126 |
],
|
| 4127 |
"engines": {
|
| 4128 |
-
"node": ">=
|
| 4129 |
}
|
| 4130 |
},
|
| 4131 |
-
"node_modules/
|
| 4132 |
-
"version": "0.
|
| 4133 |
-
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.
|
| 4134 |
-
"integrity": "sha512-
|
| 4135 |
"cpu": [
|
| 4136 |
"x64"
|
| 4137 |
],
|
|
@@ -4141,13 +4487,13 @@
|
|
| 4141 |
"android"
|
| 4142 |
],
|
| 4143 |
"engines": {
|
| 4144 |
-
"node": ">=
|
| 4145 |
}
|
| 4146 |
},
|
| 4147 |
-
"node_modules/
|
| 4148 |
-
"version": "0.
|
| 4149 |
-
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.
|
| 4150 |
-
"integrity": "sha512-
|
| 4151 |
"cpu": [
|
| 4152 |
"arm64"
|
| 4153 |
],
|
|
@@ -4157,13 +4503,13 @@
|
|
| 4157 |
"darwin"
|
| 4158 |
],
|
| 4159 |
"engines": {
|
| 4160 |
-
"node": ">=
|
| 4161 |
}
|
| 4162 |
},
|
| 4163 |
-
"node_modules/
|
| 4164 |
-
"version": "0.
|
| 4165 |
-
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.
|
| 4166 |
-
"integrity": "sha512-
|
| 4167 |
"cpu": [
|
| 4168 |
"x64"
|
| 4169 |
],
|
|
@@ -4173,13 +4519,13 @@
|
|
| 4173 |
"darwin"
|
| 4174 |
],
|
| 4175 |
"engines": {
|
| 4176 |
-
"node": ">=
|
| 4177 |
}
|
| 4178 |
},
|
| 4179 |
-
"node_modules/
|
| 4180 |
-
"version": "0.
|
| 4181 |
-
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.
|
| 4182 |
-
"integrity": "sha512-
|
| 4183 |
"cpu": [
|
| 4184 |
"arm64"
|
| 4185 |
],
|
|
@@ -4189,13 +4535,13 @@
|
|
| 4189 |
"freebsd"
|
| 4190 |
],
|
| 4191 |
"engines": {
|
| 4192 |
-
"node": ">=
|
| 4193 |
}
|
| 4194 |
},
|
| 4195 |
-
"node_modules/
|
| 4196 |
-
"version": "0.
|
| 4197 |
-
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.
|
| 4198 |
-
"integrity": "sha512-
|
| 4199 |
"cpu": [
|
| 4200 |
"x64"
|
| 4201 |
],
|
|
@@ -4205,13 +4551,13 @@
|
|
| 4205 |
"freebsd"
|
| 4206 |
],
|
| 4207 |
"engines": {
|
| 4208 |
-
"node": ">=
|
| 4209 |
}
|
| 4210 |
},
|
| 4211 |
-
"node_modules/
|
| 4212 |
-
"version": "0.
|
| 4213 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.
|
| 4214 |
-
"integrity": "sha512-
|
| 4215 |
"cpu": [
|
| 4216 |
"arm"
|
| 4217 |
],
|
|
@@ -4221,13 +4567,13 @@
|
|
| 4221 |
"linux"
|
| 4222 |
],
|
| 4223 |
"engines": {
|
| 4224 |
-
"node": ">=
|
| 4225 |
}
|
| 4226 |
},
|
| 4227 |
-
"node_modules/
|
| 4228 |
-
"version": "0.
|
| 4229 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.
|
| 4230 |
-
"integrity": "sha512-
|
| 4231 |
"cpu": [
|
| 4232 |
"arm64"
|
| 4233 |
],
|
|
@@ -4237,13 +4583,13 @@
|
|
| 4237 |
"linux"
|
| 4238 |
],
|
| 4239 |
"engines": {
|
| 4240 |
-
"node": ">=
|
| 4241 |
}
|
| 4242 |
},
|
| 4243 |
-
"node_modules/
|
| 4244 |
-
"version": "0.
|
| 4245 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.
|
| 4246 |
-
"integrity": "sha512-
|
| 4247 |
"cpu": [
|
| 4248 |
"ia32"
|
| 4249 |
],
|
|
@@ -4253,13 +4599,13 @@
|
|
| 4253 |
"linux"
|
| 4254 |
],
|
| 4255 |
"engines": {
|
| 4256 |
-
"node": ">=
|
| 4257 |
}
|
| 4258 |
},
|
| 4259 |
-
"node_modules/
|
| 4260 |
-
"version": "0.
|
| 4261 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.
|
| 4262 |
-
"integrity": "sha512-
|
| 4263 |
"cpu": [
|
| 4264 |
"loong64"
|
| 4265 |
],
|
|
@@ -4269,13 +4615,13 @@
|
|
| 4269 |
"linux"
|
| 4270 |
],
|
| 4271 |
"engines": {
|
| 4272 |
-
"node": ">=
|
| 4273 |
}
|
| 4274 |
},
|
| 4275 |
-
"node_modules/
|
| 4276 |
-
"version": "0.
|
| 4277 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.
|
| 4278 |
-
"integrity": "sha512-
|
| 4279 |
"cpu": [
|
| 4280 |
"mips64el"
|
| 4281 |
],
|
|
@@ -4285,13 +4631,13 @@
|
|
| 4285 |
"linux"
|
| 4286 |
],
|
| 4287 |
"engines": {
|
| 4288 |
-
"node": ">=
|
| 4289 |
}
|
| 4290 |
},
|
| 4291 |
-
"node_modules/
|
| 4292 |
-
"version": "0.
|
| 4293 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.
|
| 4294 |
-
"integrity": "sha512-
|
| 4295 |
"cpu": [
|
| 4296 |
"ppc64"
|
| 4297 |
],
|
|
@@ -4301,13 +4647,13 @@
|
|
| 4301 |
"linux"
|
| 4302 |
],
|
| 4303 |
"engines": {
|
| 4304 |
-
"node": ">=
|
| 4305 |
}
|
| 4306 |
},
|
| 4307 |
-
"node_modules/
|
| 4308 |
-
"version": "0.
|
| 4309 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.
|
| 4310 |
-
"integrity": "sha512-
|
| 4311 |
"cpu": [
|
| 4312 |
"riscv64"
|
| 4313 |
],
|
|
@@ -4317,13 +4663,13 @@
|
|
| 4317 |
"linux"
|
| 4318 |
],
|
| 4319 |
"engines": {
|
| 4320 |
-
"node": ">=
|
| 4321 |
}
|
| 4322 |
},
|
| 4323 |
-
"node_modules/
|
| 4324 |
-
"version": "0.
|
| 4325 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.
|
| 4326 |
-
"integrity": "sha512-
|
| 4327 |
"cpu": [
|
| 4328 |
"s390x"
|
| 4329 |
],
|
|
@@ -4333,13 +4679,13 @@
|
|
| 4333 |
"linux"
|
| 4334 |
],
|
| 4335 |
"engines": {
|
| 4336 |
-
"node": ">=
|
| 4337 |
}
|
| 4338 |
},
|
| 4339 |
-
"node_modules/
|
| 4340 |
-
"version": "0.
|
| 4341 |
-
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.
|
| 4342 |
-
"integrity": "sha512-
|
| 4343 |
"cpu": [
|
| 4344 |
"x64"
|
| 4345 |
],
|
|
@@ -4349,13 +4695,13 @@
|
|
| 4349 |
"linux"
|
| 4350 |
],
|
| 4351 |
"engines": {
|
| 4352 |
-
"node": ">=
|
| 4353 |
}
|
| 4354 |
},
|
| 4355 |
-
"node_modules/
|
| 4356 |
-
"version": "0.
|
| 4357 |
-
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.
|
| 4358 |
-
"integrity": "sha512-
|
| 4359 |
"cpu": [
|
| 4360 |
"x64"
|
| 4361 |
],
|
|
@@ -4365,13 +4711,13 @@
|
|
| 4365 |
"netbsd"
|
| 4366 |
],
|
| 4367 |
"engines": {
|
| 4368 |
-
"node": ">=
|
| 4369 |
}
|
| 4370 |
},
|
| 4371 |
-
"node_modules/
|
| 4372 |
-
"version": "0.
|
| 4373 |
-
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.
|
| 4374 |
-
"integrity": "sha512-
|
| 4375 |
"cpu": [
|
| 4376 |
"x64"
|
| 4377 |
],
|
|
@@ -4381,13 +4727,13 @@
|
|
| 4381 |
"openbsd"
|
| 4382 |
],
|
| 4383 |
"engines": {
|
| 4384 |
-
"node": ">=
|
| 4385 |
}
|
| 4386 |
},
|
| 4387 |
-
"node_modules/
|
| 4388 |
-
"version": "0.
|
| 4389 |
-
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.
|
| 4390 |
-
"integrity": "sha512-
|
| 4391 |
"cpu": [
|
| 4392 |
"x64"
|
| 4393 |
],
|
|
@@ -4397,13 +4743,13 @@
|
|
| 4397 |
"sunos"
|
| 4398 |
],
|
| 4399 |
"engines": {
|
| 4400 |
-
"node": ">=
|
| 4401 |
}
|
| 4402 |
},
|
| 4403 |
-
"node_modules/
|
| 4404 |
-
"version": "0.
|
| 4405 |
-
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.
|
| 4406 |
-
"integrity": "sha512-
|
| 4407 |
"cpu": [
|
| 4408 |
"arm64"
|
| 4409 |
],
|
|
@@ -4413,13 +4759,13 @@
|
|
| 4413 |
"win32"
|
| 4414 |
],
|
| 4415 |
"engines": {
|
| 4416 |
-
"node": ">=
|
| 4417 |
}
|
| 4418 |
},
|
| 4419 |
-
"node_modules/
|
| 4420 |
-
"version": "0.
|
| 4421 |
-
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.
|
| 4422 |
-
"integrity": "sha512-
|
| 4423 |
"cpu": [
|
| 4424 |
"ia32"
|
| 4425 |
],
|
|
@@ -4429,13 +4775,13 @@
|
|
| 4429 |
"win32"
|
| 4430 |
],
|
| 4431 |
"engines": {
|
| 4432 |
-
"node": ">=
|
| 4433 |
}
|
| 4434 |
},
|
| 4435 |
-
"node_modules/
|
| 4436 |
-
"version": "0.
|
| 4437 |
-
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.
|
| 4438 |
-
"integrity": "sha512-
|
| 4439 |
"cpu": [
|
| 4440 |
"x64"
|
| 4441 |
],
|
|
@@ -4445,7 +4791,122 @@
|
|
| 4445 |
"win32"
|
| 4446 |
],
|
| 4447 |
"engines": {
|
| 4448 |
-
"node": ">=
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4449 |
}
|
| 4450 |
},
|
| 4451 |
"node_modules/vitest/node_modules/@vitest/mocker": {
|
|
@@ -4474,47 +4935,6 @@
|
|
| 4474 |
}
|
| 4475 |
}
|
| 4476 |
},
|
| 4477 |
-
"node_modules/vitest/node_modules/esbuild": {
|
| 4478 |
-
"version": "0.25.12",
|
| 4479 |
-
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
|
| 4480 |
-
"integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
|
| 4481 |
-
"dev": true,
|
| 4482 |
-
"hasInstallScript": true,
|
| 4483 |
-
"bin": {
|
| 4484 |
-
"esbuild": "bin/esbuild"
|
| 4485 |
-
},
|
| 4486 |
-
"engines": {
|
| 4487 |
-
"node": ">=18"
|
| 4488 |
-
},
|
| 4489 |
-
"optionalDependencies": {
|
| 4490 |
-
"@esbuild/aix-ppc64": "0.25.12",
|
| 4491 |
-
"@esbuild/android-arm": "0.25.12",
|
| 4492 |
-
"@esbuild/android-arm64": "0.25.12",
|
| 4493 |
-
"@esbuild/android-x64": "0.25.12",
|
| 4494 |
-
"@esbuild/darwin-arm64": "0.25.12",
|
| 4495 |
-
"@esbuild/darwin-x64": "0.25.12",
|
| 4496 |
-
"@esbuild/freebsd-arm64": "0.25.12",
|
| 4497 |
-
"@esbuild/freebsd-x64": "0.25.12",
|
| 4498 |
-
"@esbuild/linux-arm": "0.25.12",
|
| 4499 |
-
"@esbuild/linux-arm64": "0.25.12",
|
| 4500 |
-
"@esbuild/linux-ia32": "0.25.12",
|
| 4501 |
-
"@esbuild/linux-loong64": "0.25.12",
|
| 4502 |
-
"@esbuild/linux-mips64el": "0.25.12",
|
| 4503 |
-
"@esbuild/linux-ppc64": "0.25.12",
|
| 4504 |
-
"@esbuild/linux-riscv64": "0.25.12",
|
| 4505 |
-
"@esbuild/linux-s390x": "0.25.12",
|
| 4506 |
-
"@esbuild/linux-x64": "0.25.12",
|
| 4507 |
-
"@esbuild/netbsd-arm64": "0.25.12",
|
| 4508 |
-
"@esbuild/netbsd-x64": "0.25.12",
|
| 4509 |
-
"@esbuild/openbsd-arm64": "0.25.12",
|
| 4510 |
-
"@esbuild/openbsd-x64": "0.25.12",
|
| 4511 |
-
"@esbuild/openharmony-arm64": "0.25.12",
|
| 4512 |
-
"@esbuild/sunos-x64": "0.25.12",
|
| 4513 |
-
"@esbuild/win32-arm64": "0.25.12",
|
| 4514 |
-
"@esbuild/win32-ia32": "0.25.12",
|
| 4515 |
-
"@esbuild/win32-x64": "0.25.12"
|
| 4516 |
-
}
|
| 4517 |
-
},
|
| 4518 |
"node_modules/vitest/node_modules/estree-walker": {
|
| 4519 |
"version": "3.0.3",
|
| 4520 |
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
|
|
@@ -4598,6 +5018,12 @@
|
|
| 4598 |
}
|
| 4599 |
}
|
| 4600 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4601 |
"node_modules/vue": {
|
| 4602 |
"version": "3.5.22",
|
| 4603 |
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.22.tgz",
|
|
@@ -4619,6 +5045,22 @@
|
|
| 4619 |
}
|
| 4620 |
}
|
| 4621 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4622 |
"node_modules/w3c-xmlserializer": {
|
| 4623 |
"version": "5.0.0",
|
| 4624 |
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
|
|
@@ -4790,6 +5232,18 @@
|
|
| 4790 |
"node": ">=10"
|
| 4791 |
}
|
| 4792 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4793 |
"node_modules/yargs": {
|
| 4794 |
"version": "18.0.0",
|
| 4795 |
"resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz",
|
|
|
|
| 16 |
"concurrently": "^7.6.0",
|
| 17 |
"eslint-config-prettier": "^10.1.8",
|
| 18 |
"eslint-plugin-prettier": "^5.5.4",
|
| 19 |
+
"husky": "^9.1.7",
|
| 20 |
"jison": "^0.4.18",
|
| 21 |
"jsdom": "^27.1.0",
|
| 22 |
+
"lint-staged": "^16.2.7",
|
| 23 |
+
"onnxruntime-node": "1.23.2",
|
| 24 |
+
"onnxruntime-web": "1.23.2",
|
| 25 |
"prettier": "^3.6.2",
|
| 26 |
"tsx": "^4.20.6",
|
| 27 |
"typescript": "^5.2.2",
|
| 28 |
"vite": "^5.4.21",
|
| 29 |
"vitest": "^4.0.6",
|
| 30 |
"vue": "^3.3.4",
|
| 31 |
+
"vue-tsc": "^3.1.3",
|
| 32 |
"yargs": "^18.0.0"
|
| 33 |
}
|
| 34 |
},
|
|
|
|
| 255 |
}
|
| 256 |
},
|
| 257 |
"node_modules/@esbuild/aix-ppc64": {
|
| 258 |
+
"version": "0.25.12",
|
| 259 |
+
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
|
| 260 |
+
"integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
|
| 261 |
"cpu": [
|
| 262 |
"ppc64"
|
| 263 |
],
|
|
|
|
| 267 |
"aix"
|
| 268 |
],
|
| 269 |
"engines": {
|
| 270 |
+
"node": ">=18"
|
| 271 |
}
|
| 272 |
},
|
| 273 |
"node_modules/@esbuild/android-arm": {
|
| 274 |
+
"version": "0.25.12",
|
| 275 |
+
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
|
| 276 |
+
"integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
|
| 277 |
"cpu": [
|
| 278 |
"arm"
|
| 279 |
],
|
|
|
|
| 283 |
"android"
|
| 284 |
],
|
| 285 |
"engines": {
|
| 286 |
+
"node": ">=18"
|
| 287 |
}
|
| 288 |
},
|
| 289 |
"node_modules/@esbuild/android-arm64": {
|
| 290 |
+
"version": "0.25.12",
|
| 291 |
+
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
|
| 292 |
+
"integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
|
| 293 |
"cpu": [
|
| 294 |
"arm64"
|
| 295 |
],
|
|
|
|
| 299 |
"android"
|
| 300 |
],
|
| 301 |
"engines": {
|
| 302 |
+
"node": ">=18"
|
| 303 |
}
|
| 304 |
},
|
| 305 |
"node_modules/@esbuild/android-x64": {
|
| 306 |
+
"version": "0.25.12",
|
| 307 |
+
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
|
| 308 |
+
"integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
|
| 309 |
"cpu": [
|
| 310 |
"x64"
|
| 311 |
],
|
|
|
|
| 315 |
"android"
|
| 316 |
],
|
| 317 |
"engines": {
|
| 318 |
+
"node": ">=18"
|
| 319 |
}
|
| 320 |
},
|
| 321 |
"node_modules/@esbuild/darwin-arm64": {
|
| 322 |
+
"version": "0.25.12",
|
| 323 |
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
|
| 324 |
+
"integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
|
| 325 |
"cpu": [
|
| 326 |
"arm64"
|
| 327 |
],
|
|
|
|
| 331 |
"darwin"
|
| 332 |
],
|
| 333 |
"engines": {
|
| 334 |
+
"node": ">=18"
|
| 335 |
}
|
| 336 |
},
|
| 337 |
"node_modules/@esbuild/darwin-x64": {
|
| 338 |
+
"version": "0.25.12",
|
| 339 |
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
|
| 340 |
+
"integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
|
| 341 |
"cpu": [
|
| 342 |
"x64"
|
| 343 |
],
|
|
|
|
| 347 |
"darwin"
|
| 348 |
],
|
| 349 |
"engines": {
|
| 350 |
+
"node": ">=18"
|
| 351 |
}
|
| 352 |
},
|
| 353 |
"node_modules/@esbuild/freebsd-arm64": {
|
| 354 |
+
"version": "0.25.12",
|
| 355 |
+
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
|
| 356 |
+
"integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
|
| 357 |
"cpu": [
|
| 358 |
"arm64"
|
| 359 |
],
|
|
|
|
| 363 |
"freebsd"
|
| 364 |
],
|
| 365 |
"engines": {
|
| 366 |
+
"node": ">=18"
|
| 367 |
}
|
| 368 |
},
|
| 369 |
"node_modules/@esbuild/freebsd-x64": {
|
| 370 |
+
"version": "0.25.12",
|
| 371 |
+
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
|
| 372 |
+
"integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
|
| 373 |
"cpu": [
|
| 374 |
"x64"
|
| 375 |
],
|
|
|
|
| 379 |
"freebsd"
|
| 380 |
],
|
| 381 |
"engines": {
|
| 382 |
+
"node": ">=18"
|
| 383 |
}
|
| 384 |
},
|
| 385 |
"node_modules/@esbuild/linux-arm": {
|
| 386 |
+
"version": "0.25.12",
|
| 387 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
|
| 388 |
+
"integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
|
| 389 |
"cpu": [
|
| 390 |
"arm"
|
| 391 |
],
|
|
|
|
| 395 |
"linux"
|
| 396 |
],
|
| 397 |
"engines": {
|
| 398 |
+
"node": ">=18"
|
| 399 |
}
|
| 400 |
},
|
| 401 |
"node_modules/@esbuild/linux-arm64": {
|
| 402 |
+
"version": "0.25.12",
|
| 403 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
|
| 404 |
+
"integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
|
| 405 |
"cpu": [
|
| 406 |
"arm64"
|
| 407 |
],
|
|
|
|
| 411 |
"linux"
|
| 412 |
],
|
| 413 |
"engines": {
|
| 414 |
+
"node": ">=18"
|
| 415 |
}
|
| 416 |
},
|
| 417 |
"node_modules/@esbuild/linux-ia32": {
|
| 418 |
+
"version": "0.25.12",
|
| 419 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
|
| 420 |
+
"integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
|
| 421 |
"cpu": [
|
| 422 |
"ia32"
|
| 423 |
],
|
|
|
|
| 427 |
"linux"
|
| 428 |
],
|
| 429 |
"engines": {
|
| 430 |
+
"node": ">=18"
|
| 431 |
}
|
| 432 |
},
|
| 433 |
"node_modules/@esbuild/linux-loong64": {
|
| 434 |
+
"version": "0.25.12",
|
| 435 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
|
| 436 |
+
"integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
|
| 437 |
"cpu": [
|
| 438 |
"loong64"
|
| 439 |
],
|
|
|
|
| 443 |
"linux"
|
| 444 |
],
|
| 445 |
"engines": {
|
| 446 |
+
"node": ">=18"
|
| 447 |
}
|
| 448 |
},
|
| 449 |
"node_modules/@esbuild/linux-mips64el": {
|
| 450 |
+
"version": "0.25.12",
|
| 451 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
|
| 452 |
+
"integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
|
| 453 |
"cpu": [
|
| 454 |
"mips64el"
|
| 455 |
],
|
|
|
|
| 459 |
"linux"
|
| 460 |
],
|
| 461 |
"engines": {
|
| 462 |
+
"node": ">=18"
|
| 463 |
}
|
| 464 |
},
|
| 465 |
"node_modules/@esbuild/linux-ppc64": {
|
| 466 |
+
"version": "0.25.12",
|
| 467 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
|
| 468 |
+
"integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
|
| 469 |
"cpu": [
|
| 470 |
"ppc64"
|
| 471 |
],
|
|
|
|
| 475 |
"linux"
|
| 476 |
],
|
| 477 |
"engines": {
|
| 478 |
+
"node": ">=18"
|
| 479 |
}
|
| 480 |
},
|
| 481 |
"node_modules/@esbuild/linux-riscv64": {
|
| 482 |
+
"version": "0.25.12",
|
| 483 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
|
| 484 |
+
"integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
|
| 485 |
"cpu": [
|
| 486 |
"riscv64"
|
| 487 |
],
|
|
|
|
| 491 |
"linux"
|
| 492 |
],
|
| 493 |
"engines": {
|
| 494 |
+
"node": ">=18"
|
| 495 |
}
|
| 496 |
},
|
| 497 |
"node_modules/@esbuild/linux-s390x": {
|
| 498 |
+
"version": "0.25.12",
|
| 499 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
|
| 500 |
+
"integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
|
| 501 |
"cpu": [
|
| 502 |
"s390x"
|
| 503 |
],
|
|
|
|
| 507 |
"linux"
|
| 508 |
],
|
| 509 |
"engines": {
|
| 510 |
+
"node": ">=18"
|
| 511 |
}
|
| 512 |
},
|
| 513 |
"node_modules/@esbuild/linux-x64": {
|
| 514 |
+
"version": "0.25.12",
|
| 515 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
|
| 516 |
+
"integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
|
| 517 |
"cpu": [
|
| 518 |
"x64"
|
| 519 |
],
|
|
|
|
| 523 |
"linux"
|
| 524 |
],
|
| 525 |
"engines": {
|
| 526 |
+
"node": ">=18"
|
| 527 |
}
|
| 528 |
},
|
| 529 |
"node_modules/@esbuild/netbsd-arm64": {
|
|
|
|
| 543 |
}
|
| 544 |
},
|
| 545 |
"node_modules/@esbuild/netbsd-x64": {
|
| 546 |
+
"version": "0.25.12",
|
| 547 |
+
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
|
| 548 |
+
"integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
|
| 549 |
"cpu": [
|
| 550 |
"x64"
|
| 551 |
],
|
|
|
|
| 555 |
"netbsd"
|
| 556 |
],
|
| 557 |
"engines": {
|
| 558 |
+
"node": ">=18"
|
| 559 |
}
|
| 560 |
},
|
| 561 |
"node_modules/@esbuild/openbsd-arm64": {
|
|
|
|
| 575 |
}
|
| 576 |
},
|
| 577 |
"node_modules/@esbuild/openbsd-x64": {
|
| 578 |
+
"version": "0.25.12",
|
| 579 |
+
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
|
| 580 |
+
"integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
|
| 581 |
"cpu": [
|
| 582 |
"x64"
|
| 583 |
],
|
|
|
|
| 587 |
"openbsd"
|
| 588 |
],
|
| 589 |
"engines": {
|
| 590 |
+
"node": ">=18"
|
| 591 |
}
|
| 592 |
},
|
| 593 |
"node_modules/@esbuild/openharmony-arm64": {
|
|
|
|
| 607 |
}
|
| 608 |
},
|
| 609 |
"node_modules/@esbuild/sunos-x64": {
|
| 610 |
+
"version": "0.25.12",
|
| 611 |
+
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
|
| 612 |
+
"integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
|
| 613 |
"cpu": [
|
| 614 |
"x64"
|
| 615 |
],
|
|
|
|
| 619 |
"sunos"
|
| 620 |
],
|
| 621 |
"engines": {
|
| 622 |
+
"node": ">=18"
|
| 623 |
}
|
| 624 |
},
|
| 625 |
"node_modules/@esbuild/win32-arm64": {
|
| 626 |
+
"version": "0.25.12",
|
| 627 |
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
|
| 628 |
+
"integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
|
| 629 |
"cpu": [
|
| 630 |
"arm64"
|
| 631 |
],
|
|
|
|
| 635 |
"win32"
|
| 636 |
],
|
| 637 |
"engines": {
|
| 638 |
+
"node": ">=18"
|
| 639 |
}
|
| 640 |
},
|
| 641 |
"node_modules/@esbuild/win32-ia32": {
|
| 642 |
+
"version": "0.25.12",
|
| 643 |
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
|
| 644 |
+
"integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
|
| 645 |
"cpu": [
|
| 646 |
"ia32"
|
| 647 |
],
|
|
|
|
| 651 |
"win32"
|
| 652 |
],
|
| 653 |
"engines": {
|
| 654 |
+
"node": ">=18"
|
| 655 |
}
|
| 656 |
},
|
| 657 |
"node_modules/@esbuild/win32-x64": {
|
| 658 |
+
"version": "0.25.12",
|
| 659 |
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
|
| 660 |
+
"integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
|
| 661 |
"cpu": [
|
| 662 |
"x64"
|
| 663 |
],
|
|
|
|
| 667 |
"win32"
|
| 668 |
],
|
| 669 |
"engines": {
|
| 670 |
+
"node": ">=18"
|
| 671 |
}
|
| 672 |
},
|
| 673 |
"node_modules/@eslint-community/eslint-utils": {
|
|
|
|
| 890 |
"integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==",
|
| 891 |
"dev": true
|
| 892 |
},
|
| 893 |
+
"node_modules/@protobufjs/aspromise": {
|
| 894 |
+
"version": "1.1.2",
|
| 895 |
+
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
|
| 896 |
+
"integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
|
| 897 |
+
"dev": true
|
| 898 |
+
},
|
| 899 |
+
"node_modules/@protobufjs/base64": {
|
| 900 |
+
"version": "1.1.2",
|
| 901 |
+
"resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
|
| 902 |
+
"integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
|
| 903 |
+
"dev": true
|
| 904 |
+
},
|
| 905 |
+
"node_modules/@protobufjs/codegen": {
|
| 906 |
+
"version": "2.0.4",
|
| 907 |
+
"resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
|
| 908 |
+
"integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==",
|
| 909 |
+
"dev": true
|
| 910 |
+
},
|
| 911 |
+
"node_modules/@protobufjs/eventemitter": {
|
| 912 |
+
"version": "1.1.0",
|
| 913 |
+
"resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
|
| 914 |
+
"integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==",
|
| 915 |
+
"dev": true
|
| 916 |
+
},
|
| 917 |
+
"node_modules/@protobufjs/fetch": {
|
| 918 |
+
"version": "1.1.0",
|
| 919 |
+
"resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
|
| 920 |
+
"integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
|
| 921 |
+
"dev": true,
|
| 922 |
+
"dependencies": {
|
| 923 |
+
"@protobufjs/aspromise": "^1.1.1",
|
| 924 |
+
"@protobufjs/inquire": "^1.1.0"
|
| 925 |
+
}
|
| 926 |
+
},
|
| 927 |
+
"node_modules/@protobufjs/float": {
|
| 928 |
+
"version": "1.0.2",
|
| 929 |
+
"resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
|
| 930 |
+
"integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
|
| 931 |
+
"dev": true
|
| 932 |
+
},
|
| 933 |
+
"node_modules/@protobufjs/inquire": {
|
| 934 |
+
"version": "1.1.0",
|
| 935 |
+
"resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
|
| 936 |
+
"integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==",
|
| 937 |
+
"dev": true
|
| 938 |
+
},
|
| 939 |
+
"node_modules/@protobufjs/path": {
|
| 940 |
+
"version": "1.1.2",
|
| 941 |
+
"resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
|
| 942 |
+
"integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
|
| 943 |
+
"dev": true
|
| 944 |
+
},
|
| 945 |
+
"node_modules/@protobufjs/pool": {
|
| 946 |
+
"version": "1.1.0",
|
| 947 |
+
"resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
|
| 948 |
+
"integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
|
| 949 |
+
"dev": true
|
| 950 |
+
},
|
| 951 |
+
"node_modules/@protobufjs/utf8": {
|
| 952 |
+
"version": "1.1.0",
|
| 953 |
+
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
|
| 954 |
+
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
|
| 955 |
+
"dev": true
|
| 956 |
+
},
|
| 957 |
"node_modules/@rollup/rollup-android-arm-eabi": {
|
| 958 |
"version": "4.52.5",
|
| 959 |
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz",
|
|
|
|
| 1411 |
"url": "https://opencollective.com/vitest"
|
| 1412 |
}
|
| 1413 |
},
|
| 1414 |
+
"node_modules/@volar/language-core": {
|
| 1415 |
+
"version": "2.4.23",
|
| 1416 |
+
"resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.23.tgz",
|
| 1417 |
+
"integrity": "sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==",
|
| 1418 |
+
"dev": true,
|
| 1419 |
+
"dependencies": {
|
| 1420 |
+
"@volar/source-map": "2.4.23"
|
| 1421 |
+
}
|
| 1422 |
+
},
|
| 1423 |
+
"node_modules/@volar/source-map": {
|
| 1424 |
+
"version": "2.4.23",
|
| 1425 |
+
"resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.23.tgz",
|
| 1426 |
+
"integrity": "sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q==",
|
| 1427 |
+
"dev": true
|
| 1428 |
+
},
|
| 1429 |
+
"node_modules/@volar/typescript": {
|
| 1430 |
+
"version": "2.4.23",
|
| 1431 |
+
"resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.23.tgz",
|
| 1432 |
+
"integrity": "sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==",
|
| 1433 |
+
"dev": true,
|
| 1434 |
+
"dependencies": {
|
| 1435 |
+
"@volar/language-core": "2.4.23",
|
| 1436 |
+
"path-browserify": "^1.0.1",
|
| 1437 |
+
"vscode-uri": "^3.0.8"
|
| 1438 |
+
}
|
| 1439 |
+
},
|
| 1440 |
"node_modules/@vue/compiler-core": {
|
| 1441 |
"version": "3.5.22",
|
| 1442 |
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.22.tgz",
|
|
|
|
| 1499 |
"@vue/shared": "3.5.22"
|
| 1500 |
}
|
| 1501 |
},
|
| 1502 |
+
"node_modules/@vue/language-core": {
|
| 1503 |
+
"version": "3.1.3",
|
| 1504 |
+
"resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.1.3.tgz",
|
| 1505 |
+
"integrity": "sha512-KpR1F/eGAG9D1RZ0/T6zWJs6dh/pRLfY5WupecyYKJ1fjVmDMgTPw9wXmKv2rBjo4zCJiOSiyB8BDP1OUwpMEA==",
|
| 1506 |
+
"dev": true,
|
| 1507 |
+
"dependencies": {
|
| 1508 |
+
"@volar/language-core": "2.4.23",
|
| 1509 |
+
"@vue/compiler-dom": "^3.5.0",
|
| 1510 |
+
"@vue/shared": "^3.5.0",
|
| 1511 |
+
"alien-signals": "^3.0.0",
|
| 1512 |
+
"muggle-string": "^0.4.1",
|
| 1513 |
+
"path-browserify": "^1.0.1",
|
| 1514 |
+
"picomatch": "^4.0.2"
|
| 1515 |
+
},
|
| 1516 |
+
"peerDependencies": {
|
| 1517 |
+
"typescript": "*"
|
| 1518 |
+
},
|
| 1519 |
+
"peerDependenciesMeta": {
|
| 1520 |
+
"typescript": {
|
| 1521 |
+
"optional": true
|
| 1522 |
+
}
|
| 1523 |
+
}
|
| 1524 |
+
},
|
| 1525 |
"node_modules/@vue/reactivity": {
|
| 1526 |
"version": "3.5.22",
|
| 1527 |
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.22.tgz",
|
|
|
|
| 1595 |
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
| 1596 |
}
|
| 1597 |
},
|
| 1598 |
+
"node_modules/adm-zip": {
|
| 1599 |
+
"version": "0.5.16",
|
| 1600 |
+
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz",
|
| 1601 |
+
"integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==",
|
| 1602 |
+
"dev": true,
|
| 1603 |
+
"engines": {
|
| 1604 |
+
"node": ">=12.0"
|
| 1605 |
+
}
|
| 1606 |
+
},
|
| 1607 |
"node_modules/agent-base": {
|
| 1608 |
"version": "7.1.4",
|
| 1609 |
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
|
|
|
|
| 1630 |
"url": "https://github.com/sponsors/epoberezkin"
|
| 1631 |
}
|
| 1632 |
},
|
| 1633 |
+
"node_modules/alien-signals": {
|
| 1634 |
+
"version": "3.1.0",
|
| 1635 |
+
"resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-3.1.0.tgz",
|
| 1636 |
+
"integrity": "sha512-yufC6VpSy8tK3I0lO67pjumo5JvDQVQyr38+3OHqe6CHl1t2VZekKZ7EKKZSqk0cRmE7U7tfZbpXiKNzuc+ckg==",
|
| 1637 |
+
"dev": true
|
| 1638 |
+
},
|
| 1639 |
"node_modules/amdefine": {
|
| 1640 |
"version": "1.0.1",
|
| 1641 |
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
|
|
|
|
| 1646 |
"node": ">=0.4.2"
|
| 1647 |
}
|
| 1648 |
},
|
| 1649 |
+
"node_modules/ansi-escapes": {
|
| 1650 |
+
"version": "7.2.0",
|
| 1651 |
+
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz",
|
| 1652 |
+
"integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==",
|
| 1653 |
+
"dev": true,
|
| 1654 |
+
"dependencies": {
|
| 1655 |
+
"environment": "^1.0.0"
|
| 1656 |
+
},
|
| 1657 |
+
"engines": {
|
| 1658 |
+
"node": ">=18"
|
| 1659 |
+
},
|
| 1660 |
+
"funding": {
|
| 1661 |
+
"url": "https://github.com/sponsors/sindresorhus"
|
| 1662 |
+
}
|
| 1663 |
+
},
|
| 1664 |
"node_modules/ansi-regex": {
|
| 1665 |
"version": "6.2.2",
|
| 1666 |
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
|
|
|
|
| 1720 |
"require-from-string": "^2.0.2"
|
| 1721 |
}
|
| 1722 |
},
|
| 1723 |
+
"node_modules/boolean": {
|
| 1724 |
+
"version": "3.2.0",
|
| 1725 |
+
"resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz",
|
| 1726 |
+
"integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==",
|
| 1727 |
+
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
|
| 1728 |
+
"dev": true
|
| 1729 |
+
},
|
| 1730 |
"node_modules/brace-expansion": {
|
| 1731 |
"version": "1.1.12",
|
| 1732 |
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
|
|
|
| 1738 |
"concat-map": "0.0.1"
|
| 1739 |
}
|
| 1740 |
},
|
| 1741 |
+
"node_modules/braces": {
|
| 1742 |
+
"version": "3.0.3",
|
| 1743 |
+
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
| 1744 |
+
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
| 1745 |
+
"dev": true,
|
| 1746 |
+
"dependencies": {
|
| 1747 |
+
"fill-range": "^7.1.1"
|
| 1748 |
+
},
|
| 1749 |
+
"engines": {
|
| 1750 |
+
"node": ">=8"
|
| 1751 |
+
}
|
| 1752 |
+
},
|
| 1753 |
+
"node_modules/callsites": {
|
| 1754 |
+
"version": "3.1.0",
|
| 1755 |
+
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
| 1756 |
+
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
|
| 1757 |
"dev": true,
|
| 1758 |
"peer": true,
|
| 1759 |
"engines": {
|
|
|
|
| 1785 |
"url": "https://github.com/chalk/chalk?sponsor=1"
|
| 1786 |
}
|
| 1787 |
},
|
| 1788 |
+
"node_modules/chalk/node_modules/supports-color": {
|
| 1789 |
+
"version": "7.2.0",
|
| 1790 |
+
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
| 1791 |
+
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
| 1792 |
+
"dev": true,
|
| 1793 |
+
"dependencies": {
|
| 1794 |
+
"has-flag": "^4.0.0"
|
| 1795 |
+
},
|
| 1796 |
+
"engines": {
|
| 1797 |
+
"node": ">=8"
|
| 1798 |
+
}
|
| 1799 |
+
},
|
| 1800 |
"node_modules/cjson": {
|
| 1801 |
"version": "0.3.0",
|
| 1802 |
"resolved": "https://registry.npmjs.org/cjson/-/cjson-0.3.0.tgz",
|
|
|
|
| 1809 |
"node": ">= 0.3.0"
|
| 1810 |
}
|
| 1811 |
},
|
| 1812 |
+
"node_modules/cli-cursor": {
|
| 1813 |
+
"version": "5.0.0",
|
| 1814 |
+
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
|
| 1815 |
+
"integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
|
| 1816 |
+
"dev": true,
|
| 1817 |
+
"dependencies": {
|
| 1818 |
+
"restore-cursor": "^5.0.0"
|
| 1819 |
+
},
|
| 1820 |
+
"engines": {
|
| 1821 |
+
"node": ">=18"
|
| 1822 |
+
},
|
| 1823 |
+
"funding": {
|
| 1824 |
+
"url": "https://github.com/sponsors/sindresorhus"
|
| 1825 |
+
}
|
| 1826 |
+
},
|
| 1827 |
+
"node_modules/cli-truncate": {
|
| 1828 |
+
"version": "5.1.1",
|
| 1829 |
+
"resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.1.1.tgz",
|
| 1830 |
+
"integrity": "sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==",
|
| 1831 |
+
"dev": true,
|
| 1832 |
+
"dependencies": {
|
| 1833 |
+
"slice-ansi": "^7.1.0",
|
| 1834 |
+
"string-width": "^8.0.0"
|
| 1835 |
+
},
|
| 1836 |
+
"engines": {
|
| 1837 |
+
"node": ">=20"
|
| 1838 |
+
},
|
| 1839 |
+
"funding": {
|
| 1840 |
+
"url": "https://github.com/sponsors/sindresorhus"
|
| 1841 |
+
}
|
| 1842 |
+
},
|
| 1843 |
+
"node_modules/cli-truncate/node_modules/string-width": {
|
| 1844 |
+
"version": "8.1.0",
|
| 1845 |
+
"resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.0.tgz",
|
| 1846 |
+
"integrity": "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==",
|
| 1847 |
+
"dev": true,
|
| 1848 |
+
"dependencies": {
|
| 1849 |
+
"get-east-asian-width": "^1.3.0",
|
| 1850 |
+
"strip-ansi": "^7.1.0"
|
| 1851 |
+
},
|
| 1852 |
+
"engines": {
|
| 1853 |
+
"node": ">=20"
|
| 1854 |
+
},
|
| 1855 |
+
"funding": {
|
| 1856 |
+
"url": "https://github.com/sponsors/sindresorhus"
|
| 1857 |
+
}
|
| 1858 |
+
},
|
| 1859 |
"node_modules/cliui": {
|
| 1860 |
"version": "9.0.1",
|
| 1861 |
"resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz",
|
|
|
|
| 1888 |
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
| 1889 |
"dev": true
|
| 1890 |
},
|
| 1891 |
+
"node_modules/colorette": {
|
| 1892 |
+
"version": "2.0.20",
|
| 1893 |
+
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
|
| 1894 |
+
"integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
|
| 1895 |
+
"dev": true
|
| 1896 |
+
},
|
| 1897 |
"node_modules/colors": {
|
| 1898 |
"version": "0.5.1",
|
| 1899 |
"resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz",
|
|
|
|
| 1903 |
"node": ">=0.1.90"
|
| 1904 |
}
|
| 1905 |
},
|
| 1906 |
+
"node_modules/commander": {
|
| 1907 |
+
"version": "14.0.2",
|
| 1908 |
+
"resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz",
|
| 1909 |
+
"integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==",
|
| 1910 |
+
"dev": true,
|
| 1911 |
+
"engines": {
|
| 1912 |
+
"node": ">=20"
|
| 1913 |
+
}
|
| 1914 |
+
},
|
| 1915 |
"node_modules/concat-map": {
|
| 1916 |
"version": "0.0.1",
|
| 1917 |
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
|
|
|
| 2001 |
"node": ">=8"
|
| 2002 |
}
|
| 2003 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2004 |
"node_modules/concurrently/node_modules/wrap-ansi": {
|
| 2005 |
"version": "7.0.0",
|
| 2006 |
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
|
|
|
| 2152 |
"dev": true,
|
| 2153 |
"peer": true
|
| 2154 |
},
|
| 2155 |
+
"node_modules/define-data-property": {
|
| 2156 |
+
"version": "1.1.4",
|
| 2157 |
+
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
|
| 2158 |
+
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
|
| 2159 |
+
"dev": true,
|
| 2160 |
+
"dependencies": {
|
| 2161 |
+
"es-define-property": "^1.0.0",
|
| 2162 |
+
"es-errors": "^1.3.0",
|
| 2163 |
+
"gopd": "^1.0.1"
|
| 2164 |
+
},
|
| 2165 |
+
"engines": {
|
| 2166 |
+
"node": ">= 0.4"
|
| 2167 |
+
},
|
| 2168 |
+
"funding": {
|
| 2169 |
+
"url": "https://github.com/sponsors/ljharb"
|
| 2170 |
+
}
|
| 2171 |
+
},
|
| 2172 |
+
"node_modules/define-properties": {
|
| 2173 |
+
"version": "1.2.1",
|
| 2174 |
+
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
|
| 2175 |
+
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
|
| 2176 |
+
"dev": true,
|
| 2177 |
+
"dependencies": {
|
| 2178 |
+
"define-data-property": "^1.0.1",
|
| 2179 |
+
"has-property-descriptors": "^1.0.0",
|
| 2180 |
+
"object-keys": "^1.1.1"
|
| 2181 |
+
},
|
| 2182 |
+
"engines": {
|
| 2183 |
+
"node": ">= 0.4"
|
| 2184 |
+
},
|
| 2185 |
+
"funding": {
|
| 2186 |
+
"url": "https://github.com/sponsors/ljharb"
|
| 2187 |
+
}
|
| 2188 |
+
},
|
| 2189 |
+
"node_modules/detect-node": {
|
| 2190 |
+
"version": "2.1.0",
|
| 2191 |
+
"resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz",
|
| 2192 |
+
"integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
|
| 2193 |
+
"dev": true
|
| 2194 |
+
},
|
| 2195 |
"node_modules/ebnf-parser": {
|
| 2196 |
"version": "0.1.10",
|
| 2197 |
"resolved": "https://registry.npmjs.org/ebnf-parser/-/ebnf-parser-0.1.10.tgz",
|
|
|
|
| 2216 |
"url": "https://github.com/fb55/entities?sponsor=1"
|
| 2217 |
}
|
| 2218 |
},
|
| 2219 |
+
"node_modules/environment": {
|
| 2220 |
+
"version": "1.1.0",
|
| 2221 |
+
"resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz",
|
| 2222 |
+
"integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==",
|
| 2223 |
+
"dev": true,
|
| 2224 |
+
"engines": {
|
| 2225 |
+
"node": ">=18"
|
| 2226 |
+
},
|
| 2227 |
+
"funding": {
|
| 2228 |
+
"url": "https://github.com/sponsors/sindresorhus"
|
| 2229 |
+
}
|
| 2230 |
+
},
|
| 2231 |
+
"node_modules/es-define-property": {
|
| 2232 |
+
"version": "1.0.1",
|
| 2233 |
+
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
| 2234 |
+
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
| 2235 |
+
"dev": true,
|
| 2236 |
+
"engines": {
|
| 2237 |
+
"node": ">= 0.4"
|
| 2238 |
+
}
|
| 2239 |
+
},
|
| 2240 |
+
"node_modules/es-errors": {
|
| 2241 |
+
"version": "1.3.0",
|
| 2242 |
+
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
| 2243 |
+
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
| 2244 |
+
"dev": true,
|
| 2245 |
+
"engines": {
|
| 2246 |
+
"node": ">= 0.4"
|
| 2247 |
+
}
|
| 2248 |
+
},
|
| 2249 |
"node_modules/es-module-lexer": {
|
| 2250 |
"version": "1.7.0",
|
| 2251 |
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
|
| 2252 |
"integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
|
| 2253 |
"dev": true
|
| 2254 |
},
|
| 2255 |
+
"node_modules/es6-error": {
|
| 2256 |
+
"version": "4.1.1",
|
| 2257 |
+
"resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
|
| 2258 |
+
"integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
|
| 2259 |
+
"dev": true
|
| 2260 |
+
},
|
| 2261 |
"node_modules/esbuild": {
|
| 2262 |
+
"version": "0.25.12",
|
| 2263 |
+
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
|
| 2264 |
+
"integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
|
| 2265 |
"dev": true,
|
| 2266 |
"hasInstallScript": true,
|
| 2267 |
"bin": {
|
| 2268 |
"esbuild": "bin/esbuild"
|
| 2269 |
},
|
| 2270 |
"engines": {
|
| 2271 |
+
"node": ">=18"
|
| 2272 |
},
|
| 2273 |
"optionalDependencies": {
|
| 2274 |
+
"@esbuild/aix-ppc64": "0.25.12",
|
| 2275 |
+
"@esbuild/android-arm": "0.25.12",
|
| 2276 |
+
"@esbuild/android-arm64": "0.25.12",
|
| 2277 |
+
"@esbuild/android-x64": "0.25.12",
|
| 2278 |
+
"@esbuild/darwin-arm64": "0.25.12",
|
| 2279 |
+
"@esbuild/darwin-x64": "0.25.12",
|
| 2280 |
+
"@esbuild/freebsd-arm64": "0.25.12",
|
| 2281 |
+
"@esbuild/freebsd-x64": "0.25.12",
|
| 2282 |
+
"@esbuild/linux-arm": "0.25.12",
|
| 2283 |
+
"@esbuild/linux-arm64": "0.25.12",
|
| 2284 |
+
"@esbuild/linux-ia32": "0.25.12",
|
| 2285 |
+
"@esbuild/linux-loong64": "0.25.12",
|
| 2286 |
+
"@esbuild/linux-mips64el": "0.25.12",
|
| 2287 |
+
"@esbuild/linux-ppc64": "0.25.12",
|
| 2288 |
+
"@esbuild/linux-riscv64": "0.25.12",
|
| 2289 |
+
"@esbuild/linux-s390x": "0.25.12",
|
| 2290 |
+
"@esbuild/linux-x64": "0.25.12",
|
| 2291 |
+
"@esbuild/netbsd-arm64": "0.25.12",
|
| 2292 |
+
"@esbuild/netbsd-x64": "0.25.12",
|
| 2293 |
+
"@esbuild/openbsd-arm64": "0.25.12",
|
| 2294 |
+
"@esbuild/openbsd-x64": "0.25.12",
|
| 2295 |
+
"@esbuild/openharmony-arm64": "0.25.12",
|
| 2296 |
+
"@esbuild/sunos-x64": "0.25.12",
|
| 2297 |
+
"@esbuild/win32-arm64": "0.25.12",
|
| 2298 |
+
"@esbuild/win32-ia32": "0.25.12",
|
| 2299 |
+
"@esbuild/win32-x64": "0.25.12"
|
| 2300 |
}
|
| 2301 |
},
|
| 2302 |
"node_modules/escalade": {
|
|
|
|
| 2313 |
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
| 2314 |
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
| 2315 |
"dev": true,
|
|
|
|
| 2316 |
"engines": {
|
| 2317 |
"node": ">=10"
|
| 2318 |
},
|
|
|
|
| 2577 |
"node": ">=0.10.0"
|
| 2578 |
}
|
| 2579 |
},
|
| 2580 |
+
"node_modules/eventemitter3": {
|
| 2581 |
+
"version": "5.0.1",
|
| 2582 |
+
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
|
| 2583 |
+
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
|
| 2584 |
+
"dev": true
|
| 2585 |
+
},
|
| 2586 |
"node_modules/expect-type": {
|
| 2587 |
"version": "1.2.2",
|
| 2588 |
"resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz",
|
|
|
|
| 2655 |
"node": ">=16.0.0"
|
| 2656 |
}
|
| 2657 |
},
|
| 2658 |
+
"node_modules/fill-range": {
|
| 2659 |
+
"version": "7.1.1",
|
| 2660 |
+
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
| 2661 |
+
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
| 2662 |
+
"dev": true,
|
| 2663 |
+
"dependencies": {
|
| 2664 |
+
"to-regex-range": "^5.0.1"
|
| 2665 |
+
},
|
| 2666 |
+
"engines": {
|
| 2667 |
+
"node": ">=8"
|
| 2668 |
+
}
|
| 2669 |
+
},
|
| 2670 |
"node_modules/find-up": {
|
| 2671 |
"version": "5.0.0",
|
| 2672 |
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
|
|
|
|
| 2698 |
"node": ">=16"
|
| 2699 |
}
|
| 2700 |
},
|
| 2701 |
+
"node_modules/flatbuffers": {
|
| 2702 |
+
"version": "25.9.23",
|
| 2703 |
+
"resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-25.9.23.tgz",
|
| 2704 |
+
"integrity": "sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ==",
|
| 2705 |
+
"dev": true
|
| 2706 |
+
},
|
| 2707 |
"node_modules/flatted": {
|
| 2708 |
"version": "3.3.3",
|
| 2709 |
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
|
|
|
|
| 2770 |
"node": ">=10.13.0"
|
| 2771 |
}
|
| 2772 |
},
|
| 2773 |
+
"node_modules/global-agent": {
|
| 2774 |
+
"version": "3.0.0",
|
| 2775 |
+
"resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz",
|
| 2776 |
+
"integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==",
|
| 2777 |
+
"dev": true,
|
| 2778 |
+
"dependencies": {
|
| 2779 |
+
"boolean": "^3.0.1",
|
| 2780 |
+
"es6-error": "^4.1.1",
|
| 2781 |
+
"matcher": "^3.0.0",
|
| 2782 |
+
"roarr": "^2.15.3",
|
| 2783 |
+
"semver": "^7.3.2",
|
| 2784 |
+
"serialize-error": "^7.0.1"
|
| 2785 |
+
},
|
| 2786 |
+
"engines": {
|
| 2787 |
+
"node": ">=10.0"
|
| 2788 |
+
}
|
| 2789 |
+
},
|
| 2790 |
"node_modules/globals": {
|
| 2791 |
"version": "14.0.0",
|
| 2792 |
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
|
|
|
|
| 2800 |
"url": "https://github.com/sponsors/sindresorhus"
|
| 2801 |
}
|
| 2802 |
},
|
| 2803 |
+
"node_modules/globalthis": {
|
| 2804 |
+
"version": "1.0.4",
|
| 2805 |
+
"resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
|
| 2806 |
+
"integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
|
| 2807 |
+
"dev": true,
|
| 2808 |
+
"dependencies": {
|
| 2809 |
+
"define-properties": "^1.2.1",
|
| 2810 |
+
"gopd": "^1.0.1"
|
| 2811 |
+
},
|
| 2812 |
+
"engines": {
|
| 2813 |
+
"node": ">= 0.4"
|
| 2814 |
+
},
|
| 2815 |
+
"funding": {
|
| 2816 |
+
"url": "https://github.com/sponsors/ljharb"
|
| 2817 |
+
}
|
| 2818 |
+
},
|
| 2819 |
+
"node_modules/gopd": {
|
| 2820 |
+
"version": "1.2.0",
|
| 2821 |
+
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
| 2822 |
+
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
| 2823 |
+
"dev": true,
|
| 2824 |
+
"engines": {
|
| 2825 |
+
"node": ">= 0.4"
|
| 2826 |
+
},
|
| 2827 |
+
"funding": {
|
| 2828 |
+
"url": "https://github.com/sponsors/ljharb"
|
| 2829 |
+
}
|
| 2830 |
+
},
|
| 2831 |
+
"node_modules/guid-typescript": {
|
| 2832 |
+
"version": "1.0.9",
|
| 2833 |
+
"resolved": "https://registry.npmjs.org/guid-typescript/-/guid-typescript-1.0.9.tgz",
|
| 2834 |
+
"integrity": "sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ==",
|
| 2835 |
+
"dev": true
|
| 2836 |
+
},
|
| 2837 |
"node_modules/has-flag": {
|
| 2838 |
"version": "4.0.0",
|
| 2839 |
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
|
|
|
| 2843 |
"node": ">=8"
|
| 2844 |
}
|
| 2845 |
},
|
| 2846 |
+
"node_modules/has-property-descriptors": {
|
| 2847 |
+
"version": "1.0.2",
|
| 2848 |
+
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
| 2849 |
+
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
|
| 2850 |
+
"dev": true,
|
| 2851 |
+
"dependencies": {
|
| 2852 |
+
"es-define-property": "^1.0.0"
|
| 2853 |
+
},
|
| 2854 |
+
"funding": {
|
| 2855 |
+
"url": "https://github.com/sponsors/ljharb"
|
| 2856 |
+
}
|
| 2857 |
+
},
|
| 2858 |
"node_modules/html-encoding-sniffer": {
|
| 2859 |
"version": "4.0.0",
|
| 2860 |
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
|
|
|
|
| 2893 |
"node": ">= 14"
|
| 2894 |
}
|
| 2895 |
},
|
| 2896 |
+
"node_modules/husky": {
|
| 2897 |
+
"version": "9.1.7",
|
| 2898 |
+
"resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz",
|
| 2899 |
+
"integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==",
|
| 2900 |
+
"dev": true,
|
| 2901 |
+
"bin": {
|
| 2902 |
+
"husky": "bin.js"
|
| 2903 |
+
},
|
| 2904 |
+
"engines": {
|
| 2905 |
+
"node": ">=18"
|
| 2906 |
+
},
|
| 2907 |
+
"funding": {
|
| 2908 |
+
"url": "https://github.com/sponsors/typicode"
|
| 2909 |
+
}
|
| 2910 |
+
},
|
| 2911 |
"node_modules/iconv-lite": {
|
| 2912 |
"version": "0.6.3",
|
| 2913 |
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
|
|
|
| 2989 |
"node": ">=0.10.0"
|
| 2990 |
}
|
| 2991 |
},
|
| 2992 |
+
"node_modules/is-number": {
|
| 2993 |
+
"version": "7.0.0",
|
| 2994 |
+
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
| 2995 |
+
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
| 2996 |
+
"dev": true,
|
| 2997 |
+
"engines": {
|
| 2998 |
+
"node": ">=0.12.0"
|
| 2999 |
+
}
|
| 3000 |
+
},
|
| 3001 |
"node_modules/is-potential-custom-element-name": {
|
| 3002 |
"version": "1.0.1",
|
| 3003 |
"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
|
|
|
|
| 3122 |
"dev": true,
|
| 3123 |
"peer": true
|
| 3124 |
},
|
| 3125 |
+
"node_modules/json-stringify-safe": {
|
| 3126 |
+
"version": "5.0.1",
|
| 3127 |
+
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
|
| 3128 |
+
"integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
|
| 3129 |
+
"dev": true
|
| 3130 |
+
},
|
| 3131 |
"node_modules/jsonlint": {
|
| 3132 |
"version": "1.6.0",
|
| 3133 |
"resolved": "https://registry.npmjs.org/jsonlint/-/jsonlint-1.6.0.tgz",
|
|
|
|
| 3192 |
"integrity": "sha512-DuAEISsr1H4LOpmFLkyMc8YStiRWZCO8hMsoXAXSbgyfvs2WQhSt0+/FBv3ZU/JBFZMGcE+FWzEBSzwUU7U27w==",
|
| 3193 |
"dev": true
|
| 3194 |
},
|
| 3195 |
+
"node_modules/lint-staged": {
|
| 3196 |
+
"version": "16.2.7",
|
| 3197 |
+
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.2.7.tgz",
|
| 3198 |
+
"integrity": "sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==",
|
| 3199 |
"dev": true,
|
|
|
|
| 3200 |
"dependencies": {
|
| 3201 |
+
"commander": "^14.0.2",
|
| 3202 |
+
"listr2": "^9.0.5",
|
| 3203 |
+
"micromatch": "^4.0.8",
|
| 3204 |
+
"nano-spawn": "^2.0.0",
|
| 3205 |
+
"pidtree": "^0.6.0",
|
| 3206 |
+
"string-argv": "^0.3.2",
|
| 3207 |
+
"yaml": "^2.8.1"
|
| 3208 |
+
},
|
| 3209 |
+
"bin": {
|
| 3210 |
+
"lint-staged": "bin/lint-staged.js"
|
| 3211 |
},
|
| 3212 |
"engines": {
|
| 3213 |
+
"node": ">=20.17"
|
| 3214 |
},
|
| 3215 |
"funding": {
|
| 3216 |
+
"url": "https://opencollective.com/lint-staged"
|
| 3217 |
}
|
| 3218 |
},
|
| 3219 |
+
"node_modules/listr2": {
|
| 3220 |
+
"version": "9.0.5",
|
| 3221 |
+
"resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz",
|
| 3222 |
+
"integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==",
|
| 3223 |
+
"dev": true,
|
| 3224 |
+
"dependencies": {
|
| 3225 |
+
"cli-truncate": "^5.0.0",
|
| 3226 |
+
"colorette": "^2.0.20",
|
| 3227 |
+
"eventemitter3": "^5.0.1",
|
| 3228 |
+
"log-update": "^6.1.0",
|
| 3229 |
+
"rfdc": "^1.4.1",
|
| 3230 |
+
"wrap-ansi": "^9.0.0"
|
| 3231 |
+
},
|
| 3232 |
+
"engines": {
|
| 3233 |
+
"node": ">=20.0.0"
|
| 3234 |
+
}
|
| 3235 |
+
},
|
| 3236 |
+
"node_modules/locate-path": {
|
| 3237 |
+
"version": "6.0.0",
|
| 3238 |
+
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
| 3239 |
+
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
|
| 3240 |
+
"dev": true,
|
| 3241 |
+
"peer": true,
|
| 3242 |
+
"dependencies": {
|
| 3243 |
+
"p-locate": "^5.0.0"
|
| 3244 |
+
},
|
| 3245 |
+
"engines": {
|
| 3246 |
+
"node": ">=10"
|
| 3247 |
+
},
|
| 3248 |
+
"funding": {
|
| 3249 |
+
"url": "https://github.com/sponsors/sindresorhus"
|
| 3250 |
+
}
|
| 3251 |
+
},
|
| 3252 |
+
"node_modules/lodash": {
|
| 3253 |
+
"version": "4.17.21",
|
| 3254 |
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
| 3255 |
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
| 3256 |
"dev": true
|
|
|
|
| 3262 |
"dev": true,
|
| 3263 |
"peer": true
|
| 3264 |
},
|
| 3265 |
+
"node_modules/log-update": {
|
| 3266 |
+
"version": "6.1.0",
|
| 3267 |
+
"resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz",
|
| 3268 |
+
"integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==",
|
| 3269 |
+
"dev": true,
|
| 3270 |
+
"dependencies": {
|
| 3271 |
+
"ansi-escapes": "^7.0.0",
|
| 3272 |
+
"cli-cursor": "^5.0.0",
|
| 3273 |
+
"slice-ansi": "^7.1.0",
|
| 3274 |
+
"strip-ansi": "^7.1.0",
|
| 3275 |
+
"wrap-ansi": "^9.0.0"
|
| 3276 |
+
},
|
| 3277 |
+
"engines": {
|
| 3278 |
+
"node": ">=18"
|
| 3279 |
+
},
|
| 3280 |
+
"funding": {
|
| 3281 |
+
"url": "https://github.com/sponsors/sindresorhus"
|
| 3282 |
+
}
|
| 3283 |
+
},
|
| 3284 |
+
"node_modules/long": {
|
| 3285 |
+
"version": "5.3.2",
|
| 3286 |
+
"resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
|
| 3287 |
+
"integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
|
| 3288 |
+
"dev": true
|
| 3289 |
+
},
|
| 3290 |
"node_modules/lru-cache": {
|
| 3291 |
"version": "11.2.2",
|
| 3292 |
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz",
|
|
|
|
| 3305 |
"@jridgewell/sourcemap-codec": "^1.5.5"
|
| 3306 |
}
|
| 3307 |
},
|
| 3308 |
+
"node_modules/matcher": {
|
| 3309 |
+
"version": "3.0.0",
|
| 3310 |
+
"resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz",
|
| 3311 |
+
"integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==",
|
| 3312 |
+
"dev": true,
|
| 3313 |
+
"dependencies": {
|
| 3314 |
+
"escape-string-regexp": "^4.0.0"
|
| 3315 |
+
},
|
| 3316 |
+
"engines": {
|
| 3317 |
+
"node": ">=10"
|
| 3318 |
+
}
|
| 3319 |
+
},
|
| 3320 |
"node_modules/mdn-data": {
|
| 3321 |
"version": "2.12.2",
|
| 3322 |
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz",
|
| 3323 |
"integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==",
|
| 3324 |
"dev": true
|
| 3325 |
},
|
| 3326 |
+
"node_modules/micromatch": {
|
| 3327 |
+
"version": "4.0.8",
|
| 3328 |
+
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
| 3329 |
+
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
| 3330 |
+
"dev": true,
|
| 3331 |
+
"dependencies": {
|
| 3332 |
+
"braces": "^3.0.3",
|
| 3333 |
+
"picomatch": "^2.3.1"
|
| 3334 |
+
},
|
| 3335 |
+
"engines": {
|
| 3336 |
+
"node": ">=8.6"
|
| 3337 |
+
}
|
| 3338 |
+
},
|
| 3339 |
+
"node_modules/micromatch/node_modules/picomatch": {
|
| 3340 |
+
"version": "2.3.1",
|
| 3341 |
+
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
| 3342 |
+
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
| 3343 |
+
"dev": true,
|
| 3344 |
+
"engines": {
|
| 3345 |
+
"node": ">=8.6"
|
| 3346 |
+
},
|
| 3347 |
+
"funding": {
|
| 3348 |
+
"url": "https://github.com/sponsors/jonschlinkert"
|
| 3349 |
+
}
|
| 3350 |
+
},
|
| 3351 |
+
"node_modules/mimic-function": {
|
| 3352 |
+
"version": "5.0.1",
|
| 3353 |
+
"resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
|
| 3354 |
+
"integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==",
|
| 3355 |
+
"dev": true,
|
| 3356 |
+
"engines": {
|
| 3357 |
+
"node": ">=18"
|
| 3358 |
+
},
|
| 3359 |
+
"funding": {
|
| 3360 |
+
"url": "https://github.com/sponsors/sindresorhus"
|
| 3361 |
+
}
|
| 3362 |
+
},
|
| 3363 |
"node_modules/minimatch": {
|
| 3364 |
"version": "3.1.2",
|
| 3365 |
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
|
|
|
| 3388 |
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
| 3389 |
"dev": true
|
| 3390 |
},
|
| 3391 |
+
"node_modules/muggle-string": {
|
| 3392 |
+
"version": "0.4.1",
|
| 3393 |
+
"resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz",
|
| 3394 |
+
"integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==",
|
| 3395 |
+
"dev": true
|
| 3396 |
+
},
|
| 3397 |
+
"node_modules/nano-spawn": {
|
| 3398 |
+
"version": "2.0.0",
|
| 3399 |
+
"resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-2.0.0.tgz",
|
| 3400 |
+
"integrity": "sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==",
|
| 3401 |
+
"dev": true,
|
| 3402 |
+
"engines": {
|
| 3403 |
+
"node": ">=20.17"
|
| 3404 |
+
},
|
| 3405 |
+
"funding": {
|
| 3406 |
+
"url": "https://github.com/sindresorhus/nano-spawn?sponsor=1"
|
| 3407 |
+
}
|
| 3408 |
+
},
|
| 3409 |
"node_modules/nanoid": {
|
| 3410 |
"version": "3.3.11",
|
| 3411 |
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
|
|
|
| 3445 |
"node": "*"
|
| 3446 |
}
|
| 3447 |
},
|
| 3448 |
+
"node_modules/object-keys": {
|
| 3449 |
+
"version": "1.1.1",
|
| 3450 |
+
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
| 3451 |
+
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
|
| 3452 |
+
"dev": true,
|
| 3453 |
+
"engines": {
|
| 3454 |
+
"node": ">= 0.4"
|
| 3455 |
+
}
|
| 3456 |
+
},
|
| 3457 |
+
"node_modules/onetime": {
|
| 3458 |
+
"version": "7.0.0",
|
| 3459 |
+
"resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
|
| 3460 |
+
"integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
|
| 3461 |
+
"dev": true,
|
| 3462 |
+
"dependencies": {
|
| 3463 |
+
"mimic-function": "^5.0.0"
|
| 3464 |
+
},
|
| 3465 |
+
"engines": {
|
| 3466 |
+
"node": ">=18"
|
| 3467 |
+
},
|
| 3468 |
+
"funding": {
|
| 3469 |
+
"url": "https://github.com/sponsors/sindresorhus"
|
| 3470 |
+
}
|
| 3471 |
+
},
|
| 3472 |
+
"node_modules/onnxruntime-common": {
|
| 3473 |
+
"version": "1.23.2",
|
| 3474 |
+
"resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.23.2.tgz",
|
| 3475 |
+
"integrity": "sha512-5LFsC9Dukzp2WV6kNHYLNzp8sT6V02IubLCbzw2Xd6X5GOlr65gAX6xiJwyi2URJol/s71gaQLC5F2C25AAR2w==",
|
| 3476 |
+
"dev": true
|
| 3477 |
+
},
|
| 3478 |
+
"node_modules/onnxruntime-node": {
|
| 3479 |
+
"version": "1.23.2",
|
| 3480 |
+
"resolved": "https://registry.npmjs.org/onnxruntime-node/-/onnxruntime-node-1.23.2.tgz",
|
| 3481 |
+
"integrity": "sha512-OBTsG0W8ddBVOeVVVychpVBS87A9YV5sa2hJ6lc025T97Le+J4v++PwSC4XFs1C62SWyNdof0Mh4KvnZgtt4aw==",
|
| 3482 |
+
"dev": true,
|
| 3483 |
+
"hasInstallScript": true,
|
| 3484 |
+
"os": [
|
| 3485 |
+
"win32",
|
| 3486 |
+
"darwin",
|
| 3487 |
+
"linux"
|
| 3488 |
+
],
|
| 3489 |
+
"dependencies": {
|
| 3490 |
+
"adm-zip": "^0.5.16",
|
| 3491 |
+
"global-agent": "^3.0.0",
|
| 3492 |
+
"onnxruntime-common": "1.23.2"
|
| 3493 |
+
}
|
| 3494 |
+
},
|
| 3495 |
+
"node_modules/onnxruntime-web": {
|
| 3496 |
+
"version": "1.23.2",
|
| 3497 |
+
"resolved": "https://registry.npmjs.org/onnxruntime-web/-/onnxruntime-web-1.23.2.tgz",
|
| 3498 |
+
"integrity": "sha512-T09JUtMn+CZLk3mFwqiH0lgQf+4S7+oYHHtk6uhaYAAJI95bTcKi5bOOZYwORXfS/RLZCjDDEXGWIuOCAFlEjg==",
|
| 3499 |
+
"dev": true,
|
| 3500 |
+
"dependencies": {
|
| 3501 |
+
"flatbuffers": "^25.1.24",
|
| 3502 |
+
"guid-typescript": "^1.0.9",
|
| 3503 |
+
"long": "^5.2.3",
|
| 3504 |
+
"onnxruntime-common": "1.23.2",
|
| 3505 |
+
"platform": "^1.3.6",
|
| 3506 |
+
"protobufjs": "^7.2.4"
|
| 3507 |
+
}
|
| 3508 |
+
},
|
| 3509 |
"node_modules/optionator": {
|
| 3510 |
"version": "0.9.4",
|
| 3511 |
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
|
|
|
| 3581 |
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
| 3582 |
}
|
| 3583 |
},
|
| 3584 |
+
"node_modules/path-browserify": {
|
| 3585 |
+
"version": "1.0.1",
|
| 3586 |
+
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
|
| 3587 |
+
"integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
|
| 3588 |
+
"dev": true
|
| 3589 |
+
},
|
| 3590 |
"node_modules/path-exists": {
|
| 3591 |
"version": "4.0.0",
|
| 3592 |
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
|
|
|
| 3631 |
"url": "https://github.com/sponsors/jonschlinkert"
|
| 3632 |
}
|
| 3633 |
},
|
| 3634 |
+
"node_modules/pidtree": {
|
| 3635 |
+
"version": "0.6.0",
|
| 3636 |
+
"resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz",
|
| 3637 |
+
"integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==",
|
| 3638 |
+
"dev": true,
|
| 3639 |
+
"bin": {
|
| 3640 |
+
"pidtree": "bin/pidtree.js"
|
| 3641 |
+
},
|
| 3642 |
+
"engines": {
|
| 3643 |
+
"node": ">=0.10"
|
| 3644 |
+
}
|
| 3645 |
+
},
|
| 3646 |
+
"node_modules/platform": {
|
| 3647 |
+
"version": "1.3.6",
|
| 3648 |
+
"resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz",
|
| 3649 |
+
"integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==",
|
| 3650 |
+
"dev": true
|
| 3651 |
+
},
|
| 3652 |
"node_modules/postcss": {
|
| 3653 |
"version": "8.5.6",
|
| 3654 |
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
|
|
|
| 3714 |
"node": ">=6.0.0"
|
| 3715 |
}
|
| 3716 |
},
|
| 3717 |
+
"node_modules/protobufjs": {
|
| 3718 |
+
"version": "7.5.4",
|
| 3719 |
+
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz",
|
| 3720 |
+
"integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==",
|
| 3721 |
+
"dev": true,
|
| 3722 |
+
"hasInstallScript": true,
|
| 3723 |
+
"dependencies": {
|
| 3724 |
+
"@protobufjs/aspromise": "^1.1.2",
|
| 3725 |
+
"@protobufjs/base64": "^1.1.2",
|
| 3726 |
+
"@protobufjs/codegen": "^2.0.4",
|
| 3727 |
+
"@protobufjs/eventemitter": "^1.1.0",
|
| 3728 |
+
"@protobufjs/fetch": "^1.1.0",
|
| 3729 |
+
"@protobufjs/float": "^1.0.2",
|
| 3730 |
+
"@protobufjs/inquire": "^1.1.0",
|
| 3731 |
+
"@protobufjs/path": "^1.1.2",
|
| 3732 |
+
"@protobufjs/pool": "^1.1.0",
|
| 3733 |
+
"@protobufjs/utf8": "^1.1.0",
|
| 3734 |
+
"@types/node": ">=13.7.0",
|
| 3735 |
+
"long": "^5.0.0"
|
| 3736 |
+
},
|
| 3737 |
+
"engines": {
|
| 3738 |
+
"node": ">=12.0.0"
|
| 3739 |
+
}
|
| 3740 |
+
},
|
| 3741 |
"node_modules/punycode": {
|
| 3742 |
"version": "2.3.1",
|
| 3743 |
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
|
|
|
| 3784 |
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
|
| 3785 |
}
|
| 3786 |
},
|
| 3787 |
+
"node_modules/restore-cursor": {
|
| 3788 |
+
"version": "5.1.0",
|
| 3789 |
+
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
|
| 3790 |
+
"integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
|
| 3791 |
+
"dev": true,
|
| 3792 |
+
"dependencies": {
|
| 3793 |
+
"onetime": "^7.0.0",
|
| 3794 |
+
"signal-exit": "^4.1.0"
|
| 3795 |
+
},
|
| 3796 |
+
"engines": {
|
| 3797 |
+
"node": ">=18"
|
| 3798 |
+
},
|
| 3799 |
+
"funding": {
|
| 3800 |
+
"url": "https://github.com/sponsors/sindresorhus"
|
| 3801 |
+
}
|
| 3802 |
+
},
|
| 3803 |
+
"node_modules/rfdc": {
|
| 3804 |
+
"version": "1.4.1",
|
| 3805 |
+
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
|
| 3806 |
+
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
|
| 3807 |
+
"dev": true
|
| 3808 |
+
},
|
| 3809 |
+
"node_modules/roarr": {
|
| 3810 |
+
"version": "2.15.4",
|
| 3811 |
+
"resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz",
|
| 3812 |
+
"integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==",
|
| 3813 |
+
"dev": true,
|
| 3814 |
+
"dependencies": {
|
| 3815 |
+
"boolean": "^3.0.1",
|
| 3816 |
+
"detect-node": "^2.0.4",
|
| 3817 |
+
"globalthis": "^1.0.1",
|
| 3818 |
+
"json-stringify-safe": "^5.0.1",
|
| 3819 |
+
"semver-compare": "^1.0.0",
|
| 3820 |
+
"sprintf-js": "^1.1.2"
|
| 3821 |
+
},
|
| 3822 |
+
"engines": {
|
| 3823 |
+
"node": ">=8.0"
|
| 3824 |
+
}
|
| 3825 |
+
},
|
| 3826 |
"node_modules/rollup": {
|
| 3827 |
"version": "4.52.5",
|
| 3828 |
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz",
|
|
|
|
| 3891 |
"node": ">=v12.22.7"
|
| 3892 |
}
|
| 3893 |
},
|
| 3894 |
+
"node_modules/semver": {
|
| 3895 |
+
"version": "7.7.3",
|
| 3896 |
+
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
|
| 3897 |
+
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
|
| 3898 |
+
"dev": true,
|
| 3899 |
+
"bin": {
|
| 3900 |
+
"semver": "bin/semver.js"
|
| 3901 |
+
},
|
| 3902 |
+
"engines": {
|
| 3903 |
+
"node": ">=10"
|
| 3904 |
+
}
|
| 3905 |
+
},
|
| 3906 |
+
"node_modules/semver-compare": {
|
| 3907 |
+
"version": "1.0.0",
|
| 3908 |
+
"resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
|
| 3909 |
+
"integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==",
|
| 3910 |
+
"dev": true
|
| 3911 |
+
},
|
| 3912 |
+
"node_modules/serialize-error": {
|
| 3913 |
+
"version": "7.0.1",
|
| 3914 |
+
"resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz",
|
| 3915 |
+
"integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==",
|
| 3916 |
+
"dev": true,
|
| 3917 |
+
"dependencies": {
|
| 3918 |
+
"type-fest": "^0.13.1"
|
| 3919 |
+
},
|
| 3920 |
+
"engines": {
|
| 3921 |
+
"node": ">=10"
|
| 3922 |
+
},
|
| 3923 |
+
"funding": {
|
| 3924 |
+
"url": "https://github.com/sponsors/sindresorhus"
|
| 3925 |
+
}
|
| 3926 |
+
},
|
| 3927 |
"node_modules/shebang-command": {
|
| 3928 |
"version": "2.0.0",
|
| 3929 |
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
|
|
|
| 3965 |
"integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
|
| 3966 |
"dev": true
|
| 3967 |
},
|
| 3968 |
+
"node_modules/signal-exit": {
|
| 3969 |
+
"version": "4.1.0",
|
| 3970 |
+
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
| 3971 |
+
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
|
| 3972 |
+
"dev": true,
|
| 3973 |
+
"engines": {
|
| 3974 |
+
"node": ">=14"
|
| 3975 |
+
},
|
| 3976 |
+
"funding": {
|
| 3977 |
+
"url": "https://github.com/sponsors/isaacs"
|
| 3978 |
+
}
|
| 3979 |
+
},
|
| 3980 |
"node_modules/sirv": {
|
| 3981 |
"version": "3.0.2",
|
| 3982 |
"resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz",
|
|
|
|
| 3991 |
"node": ">=18"
|
| 3992 |
}
|
| 3993 |
},
|
| 3994 |
+
"node_modules/slice-ansi": {
|
| 3995 |
+
"version": "7.1.2",
|
| 3996 |
+
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz",
|
| 3997 |
+
"integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==",
|
| 3998 |
+
"dev": true,
|
| 3999 |
+
"dependencies": {
|
| 4000 |
+
"ansi-styles": "^6.2.1",
|
| 4001 |
+
"is-fullwidth-code-point": "^5.0.0"
|
| 4002 |
+
},
|
| 4003 |
+
"engines": {
|
| 4004 |
+
"node": ">=18"
|
| 4005 |
+
},
|
| 4006 |
+
"funding": {
|
| 4007 |
+
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
|
| 4008 |
+
}
|
| 4009 |
+
},
|
| 4010 |
+
"node_modules/slice-ansi/node_modules/ansi-styles": {
|
| 4011 |
+
"version": "6.2.3",
|
| 4012 |
+
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
|
| 4013 |
+
"integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
|
| 4014 |
+
"dev": true,
|
| 4015 |
+
"engines": {
|
| 4016 |
+
"node": ">=12"
|
| 4017 |
+
},
|
| 4018 |
+
"funding": {
|
| 4019 |
+
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
| 4020 |
+
}
|
| 4021 |
+
},
|
| 4022 |
+
"node_modules/slice-ansi/node_modules/is-fullwidth-code-point": {
|
| 4023 |
+
"version": "5.1.0",
|
| 4024 |
+
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz",
|
| 4025 |
+
"integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==",
|
| 4026 |
+
"dev": true,
|
| 4027 |
+
"dependencies": {
|
| 4028 |
+
"get-east-asian-width": "^1.3.1"
|
| 4029 |
+
},
|
| 4030 |
+
"engines": {
|
| 4031 |
+
"node": ">=18"
|
| 4032 |
+
},
|
| 4033 |
+
"funding": {
|
| 4034 |
+
"url": "https://github.com/sponsors/sindresorhus"
|
| 4035 |
+
}
|
| 4036 |
+
},
|
| 4037 |
"node_modules/source-map": {
|
| 4038 |
"version": "0.1.43",
|
| 4039 |
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
|
|
|
|
| 4062 |
"integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==",
|
| 4063 |
"dev": true
|
| 4064 |
},
|
| 4065 |
+
"node_modules/sprintf-js": {
|
| 4066 |
+
"version": "1.1.3",
|
| 4067 |
+
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
|
| 4068 |
+
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
|
| 4069 |
+
"dev": true
|
| 4070 |
+
},
|
| 4071 |
"node_modules/stackback": {
|
| 4072 |
"version": "0.0.2",
|
| 4073 |
"resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
|
|
|
|
| 4080 |
"integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==",
|
| 4081 |
"dev": true
|
| 4082 |
},
|
| 4083 |
+
"node_modules/string-argv": {
|
| 4084 |
+
"version": "0.3.2",
|
| 4085 |
+
"resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz",
|
| 4086 |
+
"integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==",
|
| 4087 |
+
"dev": true,
|
| 4088 |
+
"engines": {
|
| 4089 |
+
"node": ">=0.6.19"
|
| 4090 |
+
}
|
| 4091 |
+
},
|
| 4092 |
"node_modules/string-width": {
|
| 4093 |
"version": "7.2.0",
|
| 4094 |
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
|
|
|
|
| 4135 |
}
|
| 4136 |
},
|
| 4137 |
"node_modules/supports-color": {
|
| 4138 |
+
"version": "8.1.1",
|
| 4139 |
+
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
| 4140 |
+
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
|
| 4141 |
"dev": true,
|
| 4142 |
"dependencies": {
|
| 4143 |
"has-flag": "^4.0.0"
|
| 4144 |
},
|
| 4145 |
"engines": {
|
| 4146 |
+
"node": ">=10"
|
| 4147 |
+
},
|
| 4148 |
+
"funding": {
|
| 4149 |
+
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
| 4150 |
}
|
| 4151 |
},
|
| 4152 |
"node_modules/symbol-tree": {
|
|
|
|
| 4225 |
"integrity": "sha512-DieYoGrP78PWKsrXr8MZwtQ7GLCUeLxihtjC1jZsW1DnvSMdKPitJSe8OSYDM2u5H6g3kWJZpePqkp43TfLh0g==",
|
| 4226 |
"dev": true
|
| 4227 |
},
|
| 4228 |
+
"node_modules/to-regex-range": {
|
| 4229 |
+
"version": "5.0.1",
|
| 4230 |
+
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
| 4231 |
+
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
| 4232 |
+
"dev": true,
|
| 4233 |
+
"dependencies": {
|
| 4234 |
+
"is-number": "^7.0.0"
|
| 4235 |
+
},
|
| 4236 |
+
"engines": {
|
| 4237 |
+
"node": ">=8.0"
|
| 4238 |
+
}
|
| 4239 |
+
},
|
| 4240 |
"node_modules/totalist": {
|
| 4241 |
"version": "3.0.1",
|
| 4242 |
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
|
|
|
|
| 4304 |
"fsevents": "~2.3.3"
|
| 4305 |
}
|
| 4306 |
},
|
| 4307 |
+
"node_modules/type-check": {
|
| 4308 |
+
"version": "0.4.0",
|
| 4309 |
+
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
| 4310 |
+
"integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
|
|
|
|
|
|
|
|
|
|
| 4311 |
"dev": true,
|
| 4312 |
+
"peer": true,
|
| 4313 |
+
"dependencies": {
|
| 4314 |
+
"prelude-ls": "^1.2.1"
|
| 4315 |
+
},
|
| 4316 |
"engines": {
|
| 4317 |
+
"node": ">= 0.8.0"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4318 |
}
|
| 4319 |
},
|
| 4320 |
+
"node_modules/type-fest": {
|
| 4321 |
+
"version": "0.13.1",
|
| 4322 |
+
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
|
| 4323 |
+
"integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==",
|
| 4324 |
"dev": true,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4325 |
"engines": {
|
| 4326 |
+
"node": ">=10"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4327 |
},
|
| 4328 |
+
"funding": {
|
| 4329 |
+
"url": "https://github.com/sponsors/sindresorhus"
|
| 4330 |
}
|
| 4331 |
},
|
| 4332 |
"node_modules/typescript": {
|
|
|
|
| 4426 |
}
|
| 4427 |
}
|
| 4428 |
},
|
| 4429 |
+
"node_modules/vite/node_modules/@esbuild/aix-ppc64": {
|
| 4430 |
+
"version": "0.21.5",
|
| 4431 |
+
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
| 4432 |
+
"integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4433 |
"cpu": [
|
| 4434 |
"ppc64"
|
| 4435 |
],
|
|
|
|
| 4439 |
"aix"
|
| 4440 |
],
|
| 4441 |
"engines": {
|
| 4442 |
+
"node": ">=12"
|
| 4443 |
}
|
| 4444 |
},
|
| 4445 |
+
"node_modules/vite/node_modules/@esbuild/android-arm": {
|
| 4446 |
+
"version": "0.21.5",
|
| 4447 |
+
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
|
| 4448 |
+
"integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
|
| 4449 |
"cpu": [
|
| 4450 |
"arm"
|
| 4451 |
],
|
|
|
|
| 4455 |
"android"
|
| 4456 |
],
|
| 4457 |
"engines": {
|
| 4458 |
+
"node": ">=12"
|
| 4459 |
}
|
| 4460 |
},
|
| 4461 |
+
"node_modules/vite/node_modules/@esbuild/android-arm64": {
|
| 4462 |
+
"version": "0.21.5",
|
| 4463 |
+
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
|
| 4464 |
+
"integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
|
| 4465 |
"cpu": [
|
| 4466 |
"arm64"
|
| 4467 |
],
|
|
|
|
| 4471 |
"android"
|
| 4472 |
],
|
| 4473 |
"engines": {
|
| 4474 |
+
"node": ">=12"
|
| 4475 |
}
|
| 4476 |
},
|
| 4477 |
+
"node_modules/vite/node_modules/@esbuild/android-x64": {
|
| 4478 |
+
"version": "0.21.5",
|
| 4479 |
+
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
|
| 4480 |
+
"integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
|
| 4481 |
"cpu": [
|
| 4482 |
"x64"
|
| 4483 |
],
|
|
|
|
| 4487 |
"android"
|
| 4488 |
],
|
| 4489 |
"engines": {
|
| 4490 |
+
"node": ">=12"
|
| 4491 |
}
|
| 4492 |
},
|
| 4493 |
+
"node_modules/vite/node_modules/@esbuild/darwin-arm64": {
|
| 4494 |
+
"version": "0.21.5",
|
| 4495 |
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
|
| 4496 |
+
"integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
|
| 4497 |
"cpu": [
|
| 4498 |
"arm64"
|
| 4499 |
],
|
|
|
|
| 4503 |
"darwin"
|
| 4504 |
],
|
| 4505 |
"engines": {
|
| 4506 |
+
"node": ">=12"
|
| 4507 |
}
|
| 4508 |
},
|
| 4509 |
+
"node_modules/vite/node_modules/@esbuild/darwin-x64": {
|
| 4510 |
+
"version": "0.21.5",
|
| 4511 |
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
|
| 4512 |
+
"integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
|
| 4513 |
"cpu": [
|
| 4514 |
"x64"
|
| 4515 |
],
|
|
|
|
| 4519 |
"darwin"
|
| 4520 |
],
|
| 4521 |
"engines": {
|
| 4522 |
+
"node": ">=12"
|
| 4523 |
}
|
| 4524 |
},
|
| 4525 |
+
"node_modules/vite/node_modules/@esbuild/freebsd-arm64": {
|
| 4526 |
+
"version": "0.21.5",
|
| 4527 |
+
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
|
| 4528 |
+
"integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
|
| 4529 |
"cpu": [
|
| 4530 |
"arm64"
|
| 4531 |
],
|
|
|
|
| 4535 |
"freebsd"
|
| 4536 |
],
|
| 4537 |
"engines": {
|
| 4538 |
+
"node": ">=12"
|
| 4539 |
}
|
| 4540 |
},
|
| 4541 |
+
"node_modules/vite/node_modules/@esbuild/freebsd-x64": {
|
| 4542 |
+
"version": "0.21.5",
|
| 4543 |
+
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
|
| 4544 |
+
"integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
|
| 4545 |
"cpu": [
|
| 4546 |
"x64"
|
| 4547 |
],
|
|
|
|
| 4551 |
"freebsd"
|
| 4552 |
],
|
| 4553 |
"engines": {
|
| 4554 |
+
"node": ">=12"
|
| 4555 |
}
|
| 4556 |
},
|
| 4557 |
+
"node_modules/vite/node_modules/@esbuild/linux-arm": {
|
| 4558 |
+
"version": "0.21.5",
|
| 4559 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
|
| 4560 |
+
"integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
|
| 4561 |
"cpu": [
|
| 4562 |
"arm"
|
| 4563 |
],
|
|
|
|
| 4567 |
"linux"
|
| 4568 |
],
|
| 4569 |
"engines": {
|
| 4570 |
+
"node": ">=12"
|
| 4571 |
}
|
| 4572 |
},
|
| 4573 |
+
"node_modules/vite/node_modules/@esbuild/linux-arm64": {
|
| 4574 |
+
"version": "0.21.5",
|
| 4575 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
|
| 4576 |
+
"integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
|
| 4577 |
"cpu": [
|
| 4578 |
"arm64"
|
| 4579 |
],
|
|
|
|
| 4583 |
"linux"
|
| 4584 |
],
|
| 4585 |
"engines": {
|
| 4586 |
+
"node": ">=12"
|
| 4587 |
}
|
| 4588 |
},
|
| 4589 |
+
"node_modules/vite/node_modules/@esbuild/linux-ia32": {
|
| 4590 |
+
"version": "0.21.5",
|
| 4591 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
|
| 4592 |
+
"integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
|
| 4593 |
"cpu": [
|
| 4594 |
"ia32"
|
| 4595 |
],
|
|
|
|
| 4599 |
"linux"
|
| 4600 |
],
|
| 4601 |
"engines": {
|
| 4602 |
+
"node": ">=12"
|
| 4603 |
}
|
| 4604 |
},
|
| 4605 |
+
"node_modules/vite/node_modules/@esbuild/linux-loong64": {
|
| 4606 |
+
"version": "0.21.5",
|
| 4607 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
|
| 4608 |
+
"integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
|
| 4609 |
"cpu": [
|
| 4610 |
"loong64"
|
| 4611 |
],
|
|
|
|
| 4615 |
"linux"
|
| 4616 |
],
|
| 4617 |
"engines": {
|
| 4618 |
+
"node": ">=12"
|
| 4619 |
}
|
| 4620 |
},
|
| 4621 |
+
"node_modules/vite/node_modules/@esbuild/linux-mips64el": {
|
| 4622 |
+
"version": "0.21.5",
|
| 4623 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
|
| 4624 |
+
"integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
|
| 4625 |
"cpu": [
|
| 4626 |
"mips64el"
|
| 4627 |
],
|
|
|
|
| 4631 |
"linux"
|
| 4632 |
],
|
| 4633 |
"engines": {
|
| 4634 |
+
"node": ">=12"
|
| 4635 |
}
|
| 4636 |
},
|
| 4637 |
+
"node_modules/vite/node_modules/@esbuild/linux-ppc64": {
|
| 4638 |
+
"version": "0.21.5",
|
| 4639 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
|
| 4640 |
+
"integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
|
| 4641 |
"cpu": [
|
| 4642 |
"ppc64"
|
| 4643 |
],
|
|
|
|
| 4647 |
"linux"
|
| 4648 |
],
|
| 4649 |
"engines": {
|
| 4650 |
+
"node": ">=12"
|
| 4651 |
}
|
| 4652 |
},
|
| 4653 |
+
"node_modules/vite/node_modules/@esbuild/linux-riscv64": {
|
| 4654 |
+
"version": "0.21.5",
|
| 4655 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
|
| 4656 |
+
"integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
|
| 4657 |
"cpu": [
|
| 4658 |
"riscv64"
|
| 4659 |
],
|
|
|
|
| 4663 |
"linux"
|
| 4664 |
],
|
| 4665 |
"engines": {
|
| 4666 |
+
"node": ">=12"
|
| 4667 |
}
|
| 4668 |
},
|
| 4669 |
+
"node_modules/vite/node_modules/@esbuild/linux-s390x": {
|
| 4670 |
+
"version": "0.21.5",
|
| 4671 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
|
| 4672 |
+
"integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
|
| 4673 |
"cpu": [
|
| 4674 |
"s390x"
|
| 4675 |
],
|
|
|
|
| 4679 |
"linux"
|
| 4680 |
],
|
| 4681 |
"engines": {
|
| 4682 |
+
"node": ">=12"
|
| 4683 |
}
|
| 4684 |
},
|
| 4685 |
+
"node_modules/vite/node_modules/@esbuild/linux-x64": {
|
| 4686 |
+
"version": "0.21.5",
|
| 4687 |
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
|
| 4688 |
+
"integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
|
| 4689 |
"cpu": [
|
| 4690 |
"x64"
|
| 4691 |
],
|
|
|
|
| 4695 |
"linux"
|
| 4696 |
],
|
| 4697 |
"engines": {
|
| 4698 |
+
"node": ">=12"
|
| 4699 |
}
|
| 4700 |
},
|
| 4701 |
+
"node_modules/vite/node_modules/@esbuild/netbsd-x64": {
|
| 4702 |
+
"version": "0.21.5",
|
| 4703 |
+
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
|
| 4704 |
+
"integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
|
| 4705 |
"cpu": [
|
| 4706 |
"x64"
|
| 4707 |
],
|
|
|
|
| 4711 |
"netbsd"
|
| 4712 |
],
|
| 4713 |
"engines": {
|
| 4714 |
+
"node": ">=12"
|
| 4715 |
}
|
| 4716 |
},
|
| 4717 |
+
"node_modules/vite/node_modules/@esbuild/openbsd-x64": {
|
| 4718 |
+
"version": "0.21.5",
|
| 4719 |
+
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
|
| 4720 |
+
"integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
|
| 4721 |
"cpu": [
|
| 4722 |
"x64"
|
| 4723 |
],
|
|
|
|
| 4727 |
"openbsd"
|
| 4728 |
],
|
| 4729 |
"engines": {
|
| 4730 |
+
"node": ">=12"
|
| 4731 |
}
|
| 4732 |
},
|
| 4733 |
+
"node_modules/vite/node_modules/@esbuild/sunos-x64": {
|
| 4734 |
+
"version": "0.21.5",
|
| 4735 |
+
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
|
| 4736 |
+
"integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
|
| 4737 |
"cpu": [
|
| 4738 |
"x64"
|
| 4739 |
],
|
|
|
|
| 4743 |
"sunos"
|
| 4744 |
],
|
| 4745 |
"engines": {
|
| 4746 |
+
"node": ">=12"
|
| 4747 |
}
|
| 4748 |
},
|
| 4749 |
+
"node_modules/vite/node_modules/@esbuild/win32-arm64": {
|
| 4750 |
+
"version": "0.21.5",
|
| 4751 |
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
|
| 4752 |
+
"integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
|
| 4753 |
"cpu": [
|
| 4754 |
"arm64"
|
| 4755 |
],
|
|
|
|
| 4759 |
"win32"
|
| 4760 |
],
|
| 4761 |
"engines": {
|
| 4762 |
+
"node": ">=12"
|
| 4763 |
}
|
| 4764 |
},
|
| 4765 |
+
"node_modules/vite/node_modules/@esbuild/win32-ia32": {
|
| 4766 |
+
"version": "0.21.5",
|
| 4767 |
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
|
| 4768 |
+
"integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
|
| 4769 |
"cpu": [
|
| 4770 |
"ia32"
|
| 4771 |
],
|
|
|
|
| 4775 |
"win32"
|
| 4776 |
],
|
| 4777 |
"engines": {
|
| 4778 |
+
"node": ">=12"
|
| 4779 |
}
|
| 4780 |
},
|
| 4781 |
+
"node_modules/vite/node_modules/@esbuild/win32-x64": {
|
| 4782 |
+
"version": "0.21.5",
|
| 4783 |
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
|
| 4784 |
+
"integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
|
| 4785 |
"cpu": [
|
| 4786 |
"x64"
|
| 4787 |
],
|
|
|
|
| 4791 |
"win32"
|
| 4792 |
],
|
| 4793 |
"engines": {
|
| 4794 |
+
"node": ">=12"
|
| 4795 |
+
}
|
| 4796 |
+
},
|
| 4797 |
+
"node_modules/vite/node_modules/esbuild": {
|
| 4798 |
+
"version": "0.21.5",
|
| 4799 |
+
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
|
| 4800 |
+
"integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
|
| 4801 |
+
"dev": true,
|
| 4802 |
+
"hasInstallScript": true,
|
| 4803 |
+
"bin": {
|
| 4804 |
+
"esbuild": "bin/esbuild"
|
| 4805 |
+
},
|
| 4806 |
+
"engines": {
|
| 4807 |
+
"node": ">=12"
|
| 4808 |
+
},
|
| 4809 |
+
"optionalDependencies": {
|
| 4810 |
+
"@esbuild/aix-ppc64": "0.21.5",
|
| 4811 |
+
"@esbuild/android-arm": "0.21.5",
|
| 4812 |
+
"@esbuild/android-arm64": "0.21.5",
|
| 4813 |
+
"@esbuild/android-x64": "0.21.5",
|
| 4814 |
+
"@esbuild/darwin-arm64": "0.21.5",
|
| 4815 |
+
"@esbuild/darwin-x64": "0.21.5",
|
| 4816 |
+
"@esbuild/freebsd-arm64": "0.21.5",
|
| 4817 |
+
"@esbuild/freebsd-x64": "0.21.5",
|
| 4818 |
+
"@esbuild/linux-arm": "0.21.5",
|
| 4819 |
+
"@esbuild/linux-arm64": "0.21.5",
|
| 4820 |
+
"@esbuild/linux-ia32": "0.21.5",
|
| 4821 |
+
"@esbuild/linux-loong64": "0.21.5",
|
| 4822 |
+
"@esbuild/linux-mips64el": "0.21.5",
|
| 4823 |
+
"@esbuild/linux-ppc64": "0.21.5",
|
| 4824 |
+
"@esbuild/linux-riscv64": "0.21.5",
|
| 4825 |
+
"@esbuild/linux-s390x": "0.21.5",
|
| 4826 |
+
"@esbuild/linux-x64": "0.21.5",
|
| 4827 |
+
"@esbuild/netbsd-x64": "0.21.5",
|
| 4828 |
+
"@esbuild/openbsd-x64": "0.21.5",
|
| 4829 |
+
"@esbuild/sunos-x64": "0.21.5",
|
| 4830 |
+
"@esbuild/win32-arm64": "0.21.5",
|
| 4831 |
+
"@esbuild/win32-ia32": "0.21.5",
|
| 4832 |
+
"@esbuild/win32-x64": "0.21.5"
|
| 4833 |
+
}
|
| 4834 |
+
},
|
| 4835 |
+
"node_modules/vitest": {
|
| 4836 |
+
"version": "4.0.6",
|
| 4837 |
+
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.6.tgz",
|
| 4838 |
+
"integrity": "sha512-gR7INfiVRwnEOkCk47faros/9McCZMp5LM+OMNWGLaDBSvJxIzwjgNFufkuePBNaesGRnLmNfW+ddbUJRZn0nQ==",
|
| 4839 |
+
"dev": true,
|
| 4840 |
+
"dependencies": {
|
| 4841 |
+
"@vitest/expect": "4.0.6",
|
| 4842 |
+
"@vitest/mocker": "4.0.6",
|
| 4843 |
+
"@vitest/pretty-format": "4.0.6",
|
| 4844 |
+
"@vitest/runner": "4.0.6",
|
| 4845 |
+
"@vitest/snapshot": "4.0.6",
|
| 4846 |
+
"@vitest/spy": "4.0.6",
|
| 4847 |
+
"@vitest/utils": "4.0.6",
|
| 4848 |
+
"debug": "^4.4.3",
|
| 4849 |
+
"es-module-lexer": "^1.7.0",
|
| 4850 |
+
"expect-type": "^1.2.2",
|
| 4851 |
+
"magic-string": "^0.30.19",
|
| 4852 |
+
"pathe": "^2.0.3",
|
| 4853 |
+
"picomatch": "^4.0.3",
|
| 4854 |
+
"std-env": "^3.9.0",
|
| 4855 |
+
"tinybench": "^2.9.0",
|
| 4856 |
+
"tinyexec": "^0.3.2",
|
| 4857 |
+
"tinyglobby": "^0.2.15",
|
| 4858 |
+
"tinyrainbow": "^3.0.3",
|
| 4859 |
+
"vite": "^6.0.0 || ^7.0.0",
|
| 4860 |
+
"why-is-node-running": "^2.3.0"
|
| 4861 |
+
},
|
| 4862 |
+
"bin": {
|
| 4863 |
+
"vitest": "vitest.mjs"
|
| 4864 |
+
},
|
| 4865 |
+
"engines": {
|
| 4866 |
+
"node": "^20.0.0 || ^22.0.0 || >=24.0.0"
|
| 4867 |
+
},
|
| 4868 |
+
"funding": {
|
| 4869 |
+
"url": "https://opencollective.com/vitest"
|
| 4870 |
+
},
|
| 4871 |
+
"peerDependencies": {
|
| 4872 |
+
"@edge-runtime/vm": "*",
|
| 4873 |
+
"@types/debug": "^4.1.12",
|
| 4874 |
+
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
|
| 4875 |
+
"@vitest/browser-playwright": "4.0.6",
|
| 4876 |
+
"@vitest/browser-preview": "4.0.6",
|
| 4877 |
+
"@vitest/browser-webdriverio": "4.0.6",
|
| 4878 |
+
"@vitest/ui": "4.0.6",
|
| 4879 |
+
"happy-dom": "*",
|
| 4880 |
+
"jsdom": "*"
|
| 4881 |
+
},
|
| 4882 |
+
"peerDependenciesMeta": {
|
| 4883 |
+
"@edge-runtime/vm": {
|
| 4884 |
+
"optional": true
|
| 4885 |
+
},
|
| 4886 |
+
"@types/debug": {
|
| 4887 |
+
"optional": true
|
| 4888 |
+
},
|
| 4889 |
+
"@types/node": {
|
| 4890 |
+
"optional": true
|
| 4891 |
+
},
|
| 4892 |
+
"@vitest/browser-playwright": {
|
| 4893 |
+
"optional": true
|
| 4894 |
+
},
|
| 4895 |
+
"@vitest/browser-preview": {
|
| 4896 |
+
"optional": true
|
| 4897 |
+
},
|
| 4898 |
+
"@vitest/browser-webdriverio": {
|
| 4899 |
+
"optional": true
|
| 4900 |
+
},
|
| 4901 |
+
"@vitest/ui": {
|
| 4902 |
+
"optional": true
|
| 4903 |
+
},
|
| 4904 |
+
"happy-dom": {
|
| 4905 |
+
"optional": true
|
| 4906 |
+
},
|
| 4907 |
+
"jsdom": {
|
| 4908 |
+
"optional": true
|
| 4909 |
+
}
|
| 4910 |
}
|
| 4911 |
},
|
| 4912 |
"node_modules/vitest/node_modules/@vitest/mocker": {
|
|
|
|
| 4935 |
}
|
| 4936 |
}
|
| 4937 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4938 |
"node_modules/vitest/node_modules/estree-walker": {
|
| 4939 |
"version": "3.0.3",
|
| 4940 |
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
|
|
|
|
| 5018 |
}
|
| 5019 |
}
|
| 5020 |
},
|
| 5021 |
+
"node_modules/vscode-uri": {
|
| 5022 |
+
"version": "3.1.0",
|
| 5023 |
+
"resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz",
|
| 5024 |
+
"integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==",
|
| 5025 |
+
"dev": true
|
| 5026 |
+
},
|
| 5027 |
"node_modules/vue": {
|
| 5028 |
"version": "3.5.22",
|
| 5029 |
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.22.tgz",
|
|
|
|
| 5045 |
}
|
| 5046 |
}
|
| 5047 |
},
|
| 5048 |
+
"node_modules/vue-tsc": {
|
| 5049 |
+
"version": "3.1.3",
|
| 5050 |
+
"resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.1.3.tgz",
|
| 5051 |
+
"integrity": "sha512-StMNfZHwPIXQgY3KxPKM0Jsoc8b46mDV3Fn2UlHCBIwRJApjqrSwqeMYgWf0zpN+g857y74pv7GWuBm+UqQe1w==",
|
| 5052 |
+
"dev": true,
|
| 5053 |
+
"dependencies": {
|
| 5054 |
+
"@volar/typescript": "2.4.23",
|
| 5055 |
+
"@vue/language-core": "3.1.3"
|
| 5056 |
+
},
|
| 5057 |
+
"bin": {
|
| 5058 |
+
"vue-tsc": "bin/vue-tsc.js"
|
| 5059 |
+
},
|
| 5060 |
+
"peerDependencies": {
|
| 5061 |
+
"typescript": ">=5.0.0"
|
| 5062 |
+
}
|
| 5063 |
+
},
|
| 5064 |
"node_modules/w3c-xmlserializer": {
|
| 5065 |
"version": "5.0.0",
|
| 5066 |
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
|
|
|
|
| 5232 |
"node": ">=10"
|
| 5233 |
}
|
| 5234 |
},
|
| 5235 |
+
"node_modules/yaml": {
|
| 5236 |
+
"version": "2.8.1",
|
| 5237 |
+
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz",
|
| 5238 |
+
"integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==",
|
| 5239 |
+
"dev": true,
|
| 5240 |
+
"bin": {
|
| 5241 |
+
"yaml": "bin.mjs"
|
| 5242 |
+
},
|
| 5243 |
+
"engines": {
|
| 5244 |
+
"node": ">= 14.6"
|
| 5245 |
+
}
|
| 5246 |
+
},
|
| 5247 |
"node_modules/yargs": {
|
| 5248 |
"version": "18.0.0",
|
| 5249 |
"resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz",
|
trigo-web/package.json
CHANGED
|
@@ -19,7 +19,9 @@
|
|
| 19 |
"test": "vitest",
|
| 20 |
"test:ui": "vitest --ui",
|
| 21 |
"test:run": "vitest run",
|
| 22 |
-
"generate:games": "tsx tools/generateRandomGames.ts"
|
|
|
|
|
|
|
| 23 |
},
|
| 24 |
"keywords": [
|
| 25 |
"game",
|
|
@@ -31,6 +33,9 @@
|
|
| 31 |
],
|
| 32 |
"author": "",
|
| 33 |
"license": "MIT",
|
|
|
|
|
|
|
|
|
|
| 34 |
"devDependencies": {
|
| 35 |
"@types/node": "^24.10.0",
|
| 36 |
"@types/yargs": "^17.0.34",
|
|
@@ -39,14 +44,19 @@
|
|
| 39 |
"concurrently": "^7.6.0",
|
| 40 |
"eslint-config-prettier": "^10.1.8",
|
| 41 |
"eslint-plugin-prettier": "^5.5.4",
|
|
|
|
| 42 |
"jison": "^0.4.18",
|
| 43 |
"jsdom": "^27.1.0",
|
|
|
|
|
|
|
|
|
|
| 44 |
"prettier": "^3.6.2",
|
| 45 |
"tsx": "^4.20.6",
|
| 46 |
"typescript": "^5.2.2",
|
| 47 |
"vite": "^5.4.21",
|
| 48 |
"vitest": "^4.0.6",
|
| 49 |
"vue": "^3.3.4",
|
|
|
|
| 50 |
"yargs": "^18.0.0"
|
| 51 |
}
|
| 52 |
}
|
|
|
|
| 19 |
"test": "vitest",
|
| 20 |
"test:ui": "vitest --ui",
|
| 21 |
"test:run": "vitest run",
|
| 22 |
+
"generate:games": "tsx tools/generateRandomGames.ts",
|
| 23 |
+
"migrate:tgn": "tsx tools/migrateTGN.ts",
|
| 24 |
+
"prepare": "cd .. && husky"
|
| 25 |
},
|
| 26 |
"keywords": [
|
| 27 |
"game",
|
|
|
|
| 33 |
],
|
| 34 |
"author": "",
|
| 35 |
"license": "MIT",
|
| 36 |
+
"lint-staged": {
|
| 37 |
+
"**/*.{js,ts,vue,json,md,scss,css}": []
|
| 38 |
+
},
|
| 39 |
"devDependencies": {
|
| 40 |
"@types/node": "^24.10.0",
|
| 41 |
"@types/yargs": "^17.0.34",
|
|
|
|
| 44 |
"concurrently": "^7.6.0",
|
| 45 |
"eslint-config-prettier": "^10.1.8",
|
| 46 |
"eslint-plugin-prettier": "^5.5.4",
|
| 47 |
+
"husky": "^9.1.7",
|
| 48 |
"jison": "^0.4.18",
|
| 49 |
"jsdom": "^27.1.0",
|
| 50 |
+
"lint-staged": "^16.2.7",
|
| 51 |
+
"onnxruntime-node": "1.23.2",
|
| 52 |
+
"onnxruntime-web": "1.23.2",
|
| 53 |
"prettier": "^3.6.2",
|
| 54 |
"tsx": "^4.20.6",
|
| 55 |
"typescript": "^5.2.2",
|
| 56 |
"vite": "^5.4.21",
|
| 57 |
"vitest": "^4.0.6",
|
| 58 |
"vue": "^3.3.4",
|
| 59 |
+
"vue-tsc": "^3.1.3",
|
| 60 |
"yargs": "^18.0.0"
|
| 61 |
}
|
| 62 |
}
|
trigo-web/public/lib/tgnParser.cjs
CHANGED
|
@@ -759,7 +759,7 @@ case 34:return 'INVALID'
|
|
| 759 |
break;
|
| 760 |
}
|
| 761 |
},
|
| 762 |
-
rules: [/^(?:\s+)/,/^(?:\n)/,/^(?:;[^\n]*)/,/^(?:\{[^}]*\})/,/^(?:\[)/,/^(?:\])/,/^(?:"([^\\\"]|\\.)*")/,/^(?:Event\b)/,/^(?:Site\b)/,/^(?:Date\b)/,/^(?:Round\b)/,/^(?:Black\b)/,/^(?:White\b)/,/^(?:Result\b)/,/^(?:Board\b)/,/^(?:Handicap\b)/,/^(?:Rules\b)/,/^(?:TimeControl\b)/,/^(?:Annotator\b)/,/^(?:Application\b)/,/^(?:B\+)/,/^(?:W\+)/,/^(?:=)/,/^(?:\*)/,/^(?:[1-9][0-9]*)/,/^(?:\.)/,/^(?:
|
| 763 |
conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34],"inclusive":true}}
|
| 764 |
});
|
| 765 |
return lexer;
|
|
|
|
| 759 |
break;
|
| 760 |
}
|
| 761 |
},
|
| 762 |
+
rules: [/^(?:\s+)/,/^(?:\n)/,/^(?:;[^\n]*)/,/^(?:\{[^}]*\})/,/^(?:\[)/,/^(?:\])/,/^(?:"([^\\\"]|\\.)*")/,/^(?:Event\b)/,/^(?:Site\b)/,/^(?:Date\b)/,/^(?:Round\b)/,/^(?:Black\b)/,/^(?:White\b)/,/^(?:Result\b)/,/^(?:Board\b)/,/^(?:Handicap\b)/,/^(?:Rules\b)/,/^(?:TimeControl\b)/,/^(?:Annotator\b)/,/^(?:Application\b)/,/^(?:B\+)/,/^(?:W\+)/,/^(?:=)/,/^(?:\*)/,/^(?:[1-9][0-9]*)/,/^(?:\.)/,/^(?:Pass\b)/,/^(?:Resign\b)/,/^(?:points\b)/,/^(?:stones\b)/,/^(?:[x](?=[1-9]))/,/^(?:[a-z0]+)/,/^(?:[A-Z][A-Za-z0-9_]*)/,/^(?:$)/,/^(?:.)/],
|
| 763 |
conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34],"inclusive":true}}
|
| 764 |
});
|
| 765 |
return lexer;
|
trigo-web/tools/README.md
CHANGED
|
@@ -90,8 +90,8 @@ tools/output/
|
|
| 90 |
1. 000 y00
|
| 91 |
2. 0y0 yy0
|
| 92 |
3. aaa zzz
|
| 93 |
-
4.
|
| 94 |
-
5. z0z
|
| 95 |
```
|
| 96 |
|
| 97 |
### Performance
|
|
|
|
| 90 |
1. 000 y00
|
| 91 |
2. 0y0 yy0
|
| 92 |
3. aaa zzz
|
| 93 |
+
4. Pass 0az
|
| 94 |
+
5. z0z Pass
|
| 95 |
```
|
| 96 |
|
| 97 |
### Performance
|
trigo-web/tools/migrateTGN.ts
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env tsx
|
| 2 |
+
/**
|
| 3 |
+
* TGN Migration Tool
|
| 4 |
+
*
|
| 5 |
+
* Converts old TGN files with lowercase "pass" and "resign" to uppercase "Pass" and "Resign"
|
| 6 |
+
* to match the updated TGN specification.
|
| 7 |
+
*
|
| 8 |
+
* Usage:
|
| 9 |
+
* npm run migrate:tgn -- <directory>
|
| 10 |
+
* npm run migrate:tgn -- <directory> --dry-run
|
| 11 |
+
* npm run migrate:tgn -- <directory> --backup
|
| 12 |
+
*/
|
| 13 |
+
|
| 14 |
+
import * as fs from "fs";
|
| 15 |
+
import * as path from "path";
|
| 16 |
+
import yargs from "yargs";
|
| 17 |
+
import { hideBin } from "yargs/helpers";
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
interface MigrationOptions {
|
| 21 |
+
directory: string;
|
| 22 |
+
dryRun: boolean;
|
| 23 |
+
backup: boolean;
|
| 24 |
+
recursive: boolean;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
interface MigrationStats {
|
| 28 |
+
filesScanned: number;
|
| 29 |
+
filesModified: number;
|
| 30 |
+
passReplacements: number;
|
| 31 |
+
resignReplacements: number;
|
| 32 |
+
errors: string[];
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
/**
|
| 37 |
+
* Check if a file is a TGN file
|
| 38 |
+
*/
|
| 39 |
+
function isTGNFile(filePath: string): boolean {
|
| 40 |
+
return path.extname(filePath).toLowerCase() === ".tgn";
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
/**
|
| 45 |
+
* Find all TGN files in a directory
|
| 46 |
+
*/
|
| 47 |
+
function findTGNFiles(dir: string, recursive: boolean): string[] {
|
| 48 |
+
const files: string[] = [];
|
| 49 |
+
|
| 50 |
+
try {
|
| 51 |
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
| 52 |
+
|
| 53 |
+
for (const entry of entries) {
|
| 54 |
+
const fullPath = path.join(dir, entry.name);
|
| 55 |
+
|
| 56 |
+
if (entry.isDirectory() && recursive) {
|
| 57 |
+
files.push(...findTGNFiles(fullPath, recursive));
|
| 58 |
+
} else if (entry.isFile() && isTGNFile(fullPath)) {
|
| 59 |
+
files.push(fullPath);
|
| 60 |
+
}
|
| 61 |
+
}
|
| 62 |
+
} catch (error) {
|
| 63 |
+
console.error(`Error reading directory ${dir}:`, error);
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
return files;
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
/**
|
| 71 |
+
* Migrate TGN content from lowercase to uppercase
|
| 72 |
+
*/
|
| 73 |
+
function migrateTGNContent(content: string): { newContent: string; passCount: number; resignCount: number } {
|
| 74 |
+
let passCount = 0;
|
| 75 |
+
let resignCount = 0;
|
| 76 |
+
|
| 77 |
+
// Replace "pass" with "Pass" (as a standalone word in move notation)
|
| 78 |
+
// Use word boundary to avoid replacing "pass" in other contexts
|
| 79 |
+
const newContent = content
|
| 80 |
+
.replace(/\bpass\b/g, () => {
|
| 81 |
+
passCount++;
|
| 82 |
+
return "Pass";
|
| 83 |
+
})
|
| 84 |
+
.replace(/\bresign\b/g, () => {
|
| 85 |
+
resignCount++;
|
| 86 |
+
return "Resign";
|
| 87 |
+
});
|
| 88 |
+
|
| 89 |
+
return { newContent, passCount, resignCount };
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
/**
|
| 94 |
+
* Create backup of a file
|
| 95 |
+
*/
|
| 96 |
+
function backupFile(filePath: string): string {
|
| 97 |
+
const backupPath = filePath + ".backup";
|
| 98 |
+
fs.copyFileSync(filePath, backupPath);
|
| 99 |
+
return backupPath;
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
/**
|
| 104 |
+
* Migrate a single TGN file
|
| 105 |
+
*/
|
| 106 |
+
function migrateFile(
|
| 107 |
+
filePath: string,
|
| 108 |
+
options: MigrationOptions,
|
| 109 |
+
stats: MigrationStats
|
| 110 |
+
): void {
|
| 111 |
+
stats.filesScanned++;
|
| 112 |
+
|
| 113 |
+
try {
|
| 114 |
+
// Read file content
|
| 115 |
+
const content = fs.readFileSync(filePath, "utf-8");
|
| 116 |
+
|
| 117 |
+
// Migrate content
|
| 118 |
+
const { newContent, passCount, resignCount } = migrateTGNContent(content);
|
| 119 |
+
|
| 120 |
+
// Check if file needs migration
|
| 121 |
+
if (passCount === 0 && resignCount === 0) {
|
| 122 |
+
return; // File already up to date
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
// Update statistics
|
| 126 |
+
stats.passReplacements += passCount;
|
| 127 |
+
stats.resignReplacements += resignCount;
|
| 128 |
+
stats.filesModified++;
|
| 129 |
+
|
| 130 |
+
// Log changes
|
| 131 |
+
console.log(`\n📄 ${path.basename(filePath)}`);
|
| 132 |
+
if (passCount > 0) {
|
| 133 |
+
console.log(` ✓ Replaced ${passCount} "pass" → "Pass"`);
|
| 134 |
+
}
|
| 135 |
+
if (resignCount > 0) {
|
| 136 |
+
console.log(` ✓ Replaced ${resignCount} "resign" → "Resign"`);
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
// Skip write in dry-run mode
|
| 140 |
+
if (options.dryRun) {
|
| 141 |
+
console.log(" (dry-run: no changes written)");
|
| 142 |
+
return;
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
// Create backup if requested
|
| 146 |
+
if (options.backup) {
|
| 147 |
+
const backupPath = backupFile(filePath);
|
| 148 |
+
console.log(` 📦 Backup created: ${path.basename(backupPath)}`);
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
// Write migrated content
|
| 152 |
+
fs.writeFileSync(filePath, newContent, "utf-8");
|
| 153 |
+
console.log(` ✅ File updated`);
|
| 154 |
+
} catch (error) {
|
| 155 |
+
const errorMsg = `Error processing ${filePath}: ${error}`;
|
| 156 |
+
stats.errors.push(errorMsg);
|
| 157 |
+
console.error(` ❌ ${errorMsg}`);
|
| 158 |
+
}
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
/**
|
| 163 |
+
* Main migration function
|
| 164 |
+
*/
|
| 165 |
+
function migrateTGNFiles(options: MigrationOptions): MigrationStats {
|
| 166 |
+
const stats: MigrationStats = {
|
| 167 |
+
filesScanned: 0,
|
| 168 |
+
filesModified: 0,
|
| 169 |
+
passReplacements: 0,
|
| 170 |
+
resignReplacements: 0,
|
| 171 |
+
errors: []
|
| 172 |
+
};
|
| 173 |
+
|
| 174 |
+
console.log("🔄 TGN Migration Tool");
|
| 175 |
+
console.log("=" .repeat(50));
|
| 176 |
+
console.log(`Directory: ${options.directory}`);
|
| 177 |
+
console.log(`Recursive: ${options.recursive}`);
|
| 178 |
+
console.log(`Dry run: ${options.dryRun}`);
|
| 179 |
+
console.log(`Backup: ${options.backup}`);
|
| 180 |
+
console.log("=" .repeat(50));
|
| 181 |
+
|
| 182 |
+
// Check if directory exists
|
| 183 |
+
if (!fs.existsSync(options.directory)) {
|
| 184 |
+
console.error(`❌ Directory not found: ${options.directory}`);
|
| 185 |
+
process.exit(1);
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
// Find all TGN files
|
| 189 |
+
const files = findTGNFiles(options.directory, options.recursive);
|
| 190 |
+
|
| 191 |
+
if (files.length === 0) {
|
| 192 |
+
console.log("\n⚠️ No TGN files found.");
|
| 193 |
+
return stats;
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
console.log(`\n📁 Found ${files.length} TGN file(s)\n`);
|
| 197 |
+
|
| 198 |
+
// Migrate each file
|
| 199 |
+
for (const file of files) {
|
| 200 |
+
migrateFile(file, options, stats);
|
| 201 |
+
}
|
| 202 |
+
|
| 203 |
+
// Print summary
|
| 204 |
+
console.log("\n" + "=".repeat(50));
|
| 205 |
+
console.log("📊 Migration Summary");
|
| 206 |
+
console.log("=".repeat(50));
|
| 207 |
+
console.log(`Files scanned: ${stats.filesScanned}`);
|
| 208 |
+
console.log(`Files modified: ${stats.filesModified}`);
|
| 209 |
+
console.log(`Total "pass" → "Pass": ${stats.passReplacements}`);
|
| 210 |
+
console.log(`Total "resign" → "Resign": ${stats.resignReplacements}`);
|
| 211 |
+
|
| 212 |
+
if (stats.errors.length > 0) {
|
| 213 |
+
console.log(`\n❌ Errors: ${stats.errors.length}`);
|
| 214 |
+
stats.errors.forEach((error) => console.error(` - ${error}`));
|
| 215 |
+
}
|
| 216 |
+
|
| 217 |
+
if (options.dryRun) {
|
| 218 |
+
console.log("\n⚠️ Dry run mode - no files were modified");
|
| 219 |
+
} else if (stats.filesModified > 0) {
|
| 220 |
+
console.log("\n✅ Migration completed successfully!");
|
| 221 |
+
} else {
|
| 222 |
+
console.log("\n✨ All files are already up to date!");
|
| 223 |
+
}
|
| 224 |
+
|
| 225 |
+
return stats;
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
|
| 229 |
+
/**
|
| 230 |
+
* CLI Entry Point
|
| 231 |
+
*/
|
| 232 |
+
async function main() {
|
| 233 |
+
const argv = await yargs(hideBin(process.argv))
|
| 234 |
+
.usage("Usage: $0 <directory> [options]")
|
| 235 |
+
.command("$0 <directory>", "Migrate TGN files to uppercase Pass/Resign format", (yargs) => {
|
| 236 |
+
return yargs.positional("directory", {
|
| 237 |
+
describe: "Directory containing TGN files",
|
| 238 |
+
type: "string",
|
| 239 |
+
demandOption: true
|
| 240 |
+
});
|
| 241 |
+
})
|
| 242 |
+
.option("dry-run", {
|
| 243 |
+
alias: "n",
|
| 244 |
+
type: "boolean",
|
| 245 |
+
default: false,
|
| 246 |
+
description: "Preview changes without modifying files"
|
| 247 |
+
})
|
| 248 |
+
.option("backup", {
|
| 249 |
+
alias: "b",
|
| 250 |
+
type: "boolean",
|
| 251 |
+
default: false,
|
| 252 |
+
description: "Create .backup files before modifying"
|
| 253 |
+
})
|
| 254 |
+
.option("recursive", {
|
| 255 |
+
alias: "r",
|
| 256 |
+
type: "boolean",
|
| 257 |
+
default: false,
|
| 258 |
+
description: "Process subdirectories recursively"
|
| 259 |
+
})
|
| 260 |
+
.example([
|
| 261 |
+
["$0 output", "Migrate all TGN files in output directory"],
|
| 262 |
+
["$0 output --dry-run", "Preview changes without modifying files"],
|
| 263 |
+
["$0 output --backup", "Create backups before modifying"],
|
| 264 |
+
["$0 output --recursive", "Process all subdirectories"]
|
| 265 |
+
])
|
| 266 |
+
.help("h")
|
| 267 |
+
.alias("h", "help")
|
| 268 |
+
.strict()
|
| 269 |
+
.parse();
|
| 270 |
+
|
| 271 |
+
const options: MigrationOptions = {
|
| 272 |
+
directory: argv.directory as string,
|
| 273 |
+
dryRun: argv["dry-run"] as boolean,
|
| 274 |
+
backup: argv.backup as boolean,
|
| 275 |
+
recursive: argv.recursive as boolean
|
| 276 |
+
};
|
| 277 |
+
|
| 278 |
+
migrateTGNFiles(options);
|
| 279 |
+
}
|
| 280 |
+
|
| 281 |
+
|
| 282 |
+
// Run the CLI when executed directly
|
| 283 |
+
if (process.argv[1] === new URL(import.meta.url).pathname) {
|
| 284 |
+
main().catch((error) => {
|
| 285 |
+
console.error("Fatal error:", error);
|
| 286 |
+
process.exit(1);
|
| 287 |
+
});
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
|
| 291 |
+
export { migrateTGNFiles, migrateTGNContent, MigrationOptions, MigrationStats };
|
trigo-web/vitest.config.ts
CHANGED
|
@@ -23,7 +23,7 @@ export default defineConfig({
|
|
| 23 |
test: {
|
| 24 |
globals: true,
|
| 25 |
environment: 'node', // Changed from jsdom to node since we're testing pure logic
|
| 26 |
-
include: ['tests
|
| 27 |
},
|
| 28 |
resolve: {
|
| 29 |
alias: {
|
|
|
|
| 23 |
test: {
|
| 24 |
globals: true,
|
| 25 |
environment: 'node', // Changed from jsdom to node since we're testing pure logic
|
| 26 |
+
include: ['tests/**/*.test.ts'], // All tests
|
| 27 |
},
|
| 28 |
resolve: {
|
| 29 |
alias: {
|
trigo-web/yarn.lock
CHANGED
|
@@ -213,6 +213,59 @@
|
|
| 213 |
resolved "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz"
|
| 214 |
integrity sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==
|
| 215 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 216 |
"@rollup/[email protected]":
|
| 217 |
version "4.52.5"
|
| 218 |
resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz"
|
|
@@ -251,7 +304,7 @@
|
|
| 251 |
resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz"
|
| 252 |
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
|
| 253 |
|
| 254 |
-
"@types/node@^18.0.0 || >=20.0.0", "@types/node@^20.0.0 || ^22.0.0 || >=24.0.0", "@types/node@^20.19.0 || >=22.12.0", "@types/node@^24.10.0":
|
| 255 |
version "24.10.0"
|
| 256 |
resolved "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz"
|
| 257 |
integrity sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==
|
|
@@ -346,6 +399,27 @@
|
|
| 346 |
"@vitest/pretty-format" "4.0.6"
|
| 347 |
tinyrainbow "^3.0.3"
|
| 348 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 349 |
"@vue/[email protected]":
|
| 350 |
version "3.5.22"
|
| 351 |
resolved "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.22.tgz"
|
|
@@ -357,7 +431,7 @@
|
|
| 357 |
estree-walker "^2.0.2"
|
| 358 |
source-map-js "^1.2.1"
|
| 359 |
|
| 360 |
-
"@vue/[email protected]":
|
| 361 |
version "3.5.22"
|
| 362 |
resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.22.tgz"
|
| 363 |
integrity sha512-W8RknzUM1BLkypvdz10OVsGxnMAuSIZs9Wdx1vzA3mL5fNMN15rhrSCLiTm6blWeACwUwizzPVqGJgOGBEN/hA==
|
|
@@ -388,6 +462,19 @@
|
|
| 388 |
"@vue/compiler-dom" "3.5.22"
|
| 389 |
"@vue/shared" "3.5.22"
|
| 390 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 391 |
"@vue/[email protected]":
|
| 392 |
version "3.5.22"
|
| 393 |
resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.22.tgz"
|
|
@@ -421,7 +508,7 @@
|
|
| 421 |
"@vue/compiler-ssr" "3.5.22"
|
| 422 |
"@vue/shared" "3.5.22"
|
| 423 |
|
| 424 |
-
"@vue/[email protected]":
|
| 425 |
version "3.5.22"
|
| 426 |
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.5.22.tgz"
|
| 427 |
integrity sha512-F4yc6palwq3TT0u+FYf0Ns4Tfl9GRFURDN2gWG7L1ecIaS/4fCIuFOjMTnCyjsu/OK6vaDKLCrGAa+KvvH+h4w==
|
|
@@ -436,6 +523,11 @@ acorn-jsx@^5.3.2:
|
|
| 436 |
resolved "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz"
|
| 437 |
integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==
|
| 438 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 439 |
agent-base@^7.1.0, agent-base@^7.1.2:
|
| 440 |
version "7.1.4"
|
| 441 |
resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz"
|
|
@@ -451,11 +543,23 @@ ajv@^6.12.4:
|
|
| 451 |
json-schema-traverse "^0.4.1"
|
| 452 |
uri-js "^4.2.2"
|
| 453 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 454 |
amdefine@>=0.0.4:
|
| 455 |
version "1.0.1"
|
| 456 |
resolved "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz"
|
| 457 |
integrity sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==
|
| 458 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 459 |
ansi-regex@^5.0.1:
|
| 460 |
version "5.0.1"
|
| 461 |
resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz"
|
|
@@ -500,6 +604,11 @@ bidi-js@^1.0.3:
|
|
| 500 |
dependencies:
|
| 501 |
require-from-string "^2.0.2"
|
| 502 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 503 |
brace-expansion@^1.1.7:
|
| 504 |
version "1.1.12"
|
| 505 |
resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz"
|
|
@@ -508,6 +617,13 @@ brace-expansion@^1.1.7:
|
|
| 508 |
balanced-match "^1.0.0"
|
| 509 |
concat-map "0.0.1"
|
| 510 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 511 |
callsites@^3.0.0:
|
| 512 |
version "3.1.0"
|
| 513 |
resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz"
|
|
@@ -533,6 +649,21 @@ [email protected]:
|
|
| 533 |
dependencies:
|
| 534 |
jsonlint "1.6.0"
|
| 535 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 536 |
cliui@^8.0.1:
|
| 537 |
version "8.0.1"
|
| 538 |
resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz"
|
|
@@ -563,11 +694,21 @@ color-name@~1.1.4:
|
|
| 563 |
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
|
| 564 |
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
| 565 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 566 | |
| 567 |
version "0.5.1"
|
| 568 |
resolved "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz"
|
| 569 |
integrity sha512-XjsuUwpDeY98+yz959OlUK6m7mLBM+1MEG5oaenfuQnNnrQk1WvtcvFgN3FNDP3f2NmZ211t0mNEfSEN1h0eIg==
|
| 570 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 571 | |
| 572 |
version "0.0.1"
|
| 573 |
resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
|
|
@@ -651,6 +792,29 @@ deep-is@^0.1.3:
|
|
| 651 |
resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz"
|
| 652 |
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
|
| 653 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 654 | |
| 655 |
version "0.1.10"
|
| 656 |
resolved "https://registry.npmjs.org/ebnf-parser/-/ebnf-parser-0.1.10.tgz"
|
|
@@ -676,11 +840,31 @@ entities@^6.0.0:
|
|
| 676 |
resolved "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz"
|
| 677 |
integrity sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==
|
| 678 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 679 |
es-module-lexer@^1.7.0:
|
| 680 |
version "1.7.0"
|
| 681 |
resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz"
|
| 682 |
integrity sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==
|
| 683 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 684 |
esbuild@^0.21.3:
|
| 685 |
version "0.21.5"
|
| 686 |
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz"
|
|
@@ -710,39 +894,7 @@ esbuild@^0.21.3:
|
|
| 710 |
"@esbuild/win32-ia32" "0.21.5"
|
| 711 |
"@esbuild/win32-x64" "0.21.5"
|
| 712 |
|
| 713 |
-
esbuild@^0.25.0:
|
| 714 |
-
version "0.25.12"
|
| 715 |
-
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz"
|
| 716 |
-
integrity sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==
|
| 717 |
-
optionalDependencies:
|
| 718 |
-
"@esbuild/aix-ppc64" "0.25.12"
|
| 719 |
-
"@esbuild/android-arm" "0.25.12"
|
| 720 |
-
"@esbuild/android-arm64" "0.25.12"
|
| 721 |
-
"@esbuild/android-x64" "0.25.12"
|
| 722 |
-
"@esbuild/darwin-arm64" "0.25.12"
|
| 723 |
-
"@esbuild/darwin-x64" "0.25.12"
|
| 724 |
-
"@esbuild/freebsd-arm64" "0.25.12"
|
| 725 |
-
"@esbuild/freebsd-x64" "0.25.12"
|
| 726 |
-
"@esbuild/linux-arm" "0.25.12"
|
| 727 |
-
"@esbuild/linux-arm64" "0.25.12"
|
| 728 |
-
"@esbuild/linux-ia32" "0.25.12"
|
| 729 |
-
"@esbuild/linux-loong64" "0.25.12"
|
| 730 |
-
"@esbuild/linux-mips64el" "0.25.12"
|
| 731 |
-
"@esbuild/linux-ppc64" "0.25.12"
|
| 732 |
-
"@esbuild/linux-riscv64" "0.25.12"
|
| 733 |
-
"@esbuild/linux-s390x" "0.25.12"
|
| 734 |
-
"@esbuild/linux-x64" "0.25.12"
|
| 735 |
-
"@esbuild/netbsd-arm64" "0.25.12"
|
| 736 |
-
"@esbuild/netbsd-x64" "0.25.12"
|
| 737 |
-
"@esbuild/openbsd-arm64" "0.25.12"
|
| 738 |
-
"@esbuild/openbsd-x64" "0.25.12"
|
| 739 |
-
"@esbuild/openharmony-arm64" "0.25.12"
|
| 740 |
-
"@esbuild/sunos-x64" "0.25.12"
|
| 741 |
-
"@esbuild/win32-arm64" "0.25.12"
|
| 742 |
-
"@esbuild/win32-ia32" "0.25.12"
|
| 743 |
-
"@esbuild/win32-x64" "0.25.12"
|
| 744 |
-
|
| 745 |
-
esbuild@~0.25.0:
|
| 746 |
version "0.25.12"
|
| 747 |
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz"
|
| 748 |
integrity sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==
|
|
@@ -926,6 +1078,11 @@ esutils@~1.0.0:
|
|
| 926 |
resolved "https://registry.npmjs.org/esutils/-/esutils-1.0.0.tgz"
|
| 927 |
integrity sha512-x/iYH53X3quDwfHRz4y8rn4XcEwwCJeWsul9pF1zldMbGtgOtMNBEOuYWwB1EQlK2LRa1fev3YAgym/RElp5Cg==
|
| 928 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 929 |
expect-type@^1.2.2:
|
| 930 |
version "1.2.2"
|
| 931 |
resolved "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz"
|
|
@@ -968,6 +1125,13 @@ file-entry-cache@^8.0.0:
|
|
| 968 |
dependencies:
|
| 969 |
flat-cache "^4.0.0"
|
| 970 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 971 |
find-up@^5.0.0:
|
| 972 |
version "5.0.0"
|
| 973 |
resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz"
|
|
@@ -984,6 +1148,11 @@ flat-cache@^4.0.0:
|
|
| 984 |
flatted "^3.2.9"
|
| 985 |
keyv "^4.5.4"
|
| 986 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 987 |
flatted@^3.2.9, flatted@^3.3.3:
|
| 988 |
version "3.3.3"
|
| 989 |
resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz"
|
|
@@ -994,7 +1163,7 @@ get-caller-file@^2.0.5:
|
|
| 994 |
resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz"
|
| 995 |
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
|
| 996 |
|
| 997 |
-
get-east-asian-width@^1.0.0:
|
| 998 |
version "1.4.0"
|
| 999 |
resolved "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz"
|
| 1000 |
integrity sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==
|
|
@@ -1013,16 +1182,53 @@ glob-parent@^6.0.2:
|
|
| 1013 |
dependencies:
|
| 1014 |
is-glob "^4.0.3"
|
| 1015 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1016 |
globals@^14.0.0:
|
| 1017 |
version "14.0.0"
|
| 1018 |
resolved "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz"
|
| 1019 |
integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==
|
| 1020 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1021 |
has-flag@^4.0.0:
|
| 1022 |
version "4.0.0"
|
| 1023 |
resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz"
|
| 1024 |
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
|
| 1025 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1026 |
html-encoding-sniffer@^4.0.0:
|
| 1027 |
version "4.0.0"
|
| 1028 |
resolved "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz"
|
|
@@ -1046,6 +1252,11 @@ https-proxy-agent@^7.0.6:
|
|
| 1046 |
agent-base "^7.1.2"
|
| 1047 |
debug "4"
|
| 1048 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1049 | |
| 1050 |
version "0.6.3"
|
| 1051 |
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz"
|
|
@@ -1081,6 +1292,13 @@ is-fullwidth-code-point@^3.0.0:
|
|
| 1081 |
resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz"
|
| 1082 |
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
|
| 1083 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1084 |
is-glob@^4.0.0, is-glob@^4.0.3:
|
| 1085 |
version "4.0.3"
|
| 1086 |
resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz"
|
|
@@ -1088,6 +1306,11 @@ is-glob@^4.0.0, is-glob@^4.0.3:
|
|
| 1088 |
dependencies:
|
| 1089 |
is-extglob "^2.1.1"
|
| 1090 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1091 |
is-potential-custom-element-name@^1.0.1:
|
| 1092 |
version "1.0.1"
|
| 1093 |
resolved "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz"
|
|
@@ -1168,6 +1391,11 @@ json-stable-stringify-without-jsonify@^1.0.1:
|
|
| 1168 |
resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz"
|
| 1169 |
integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
|
| 1170 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1171 | |
| 1172 |
version "1.6.0"
|
| 1173 |
resolved "https://registry.npmjs.org/jsonlint/-/jsonlint-1.6.0.tgz"
|
|
@@ -1206,6 +1434,31 @@ lex-parser@~0.1.3, [email protected]:
|
|
| 1206 |
resolved "https://registry.npmjs.org/lex-parser/-/lex-parser-0.1.4.tgz"
|
| 1207 |
integrity sha512-DuAEISsr1H4LOpmFLkyMc8YStiRWZCO8hMsoXAXSbgyfvs2WQhSt0+/FBv3ZU/JBFZMGcE+FWzEBSzwUU7U27w==
|
| 1208 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1209 |
locate-path@^6.0.0:
|
| 1210 |
version "6.0.0"
|
| 1211 |
resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz"
|
|
@@ -1223,6 +1476,22 @@ lodash@^4.17.21:
|
|
| 1223 |
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
|
| 1224 |
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
| 1225 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1226 |
lru-cache@^11.2.1, lru-cache@^11.2.2:
|
| 1227 |
version "11.2.2"
|
| 1228 |
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz"
|
|
@@ -1235,11 +1504,31 @@ magic-string@^0.30.19:
|
|
| 1235 |
dependencies:
|
| 1236 |
"@jridgewell/sourcemap-codec" "^1.5.5"
|
| 1237 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1238 | |
| 1239 |
version "2.12.2"
|
| 1240 |
resolved "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz"
|
| 1241 |
integrity sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==
|
| 1242 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1243 |
minimatch@^3.1.2:
|
| 1244 |
version "3.1.2"
|
| 1245 |
resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
|
|
@@ -1257,6 +1546,16 @@ ms@^2.1.3:
|
|
| 1257 |
resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
|
| 1258 |
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
| 1259 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1260 |
nanoid@^3.3.11:
|
| 1261 |
version "3.3.11"
|
| 1262 |
resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz"
|
|
@@ -1275,6 +1574,44 @@ natural-compare@^1.4.0:
|
|
| 1275 |
colors "0.5.x"
|
| 1276 |
underscore "1.1.x"
|
| 1277 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1278 |
optionator@^0.9.3:
|
| 1279 |
version "0.9.4"
|
| 1280 |
resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz"
|
|
@@ -1315,6 +1652,11 @@ parse5@^8.0.0:
|
|
| 1315 |
dependencies:
|
| 1316 |
entities "^6.0.0"
|
| 1317 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1318 |
path-exists@^4.0.0:
|
| 1319 |
version "4.0.0"
|
| 1320 |
resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz"
|
|
@@ -1335,11 +1677,26 @@ picocolors@^1.1.1:
|
|
| 1335 |
resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz"
|
| 1336 |
integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
|
| 1337 |
|
| 1338 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1339 |
version "4.0.3"
|
| 1340 |
resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz"
|
| 1341 |
integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==
|
| 1342 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1343 |
postcss@^8.4.43, postcss@^8.5.6:
|
| 1344 |
version "8.5.6"
|
| 1345 |
resolved "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz"
|
|
@@ -1366,6 +1723,24 @@ prettier@^3.6.2, prettier@>=3.0.0:
|
|
| 1366 |
resolved "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz"
|
| 1367 |
integrity sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==
|
| 1368 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1369 |
punycode@^2.1.0, punycode@^2.3.1:
|
| 1370 |
version "2.3.1"
|
| 1371 |
resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz"
|
|
@@ -1391,6 +1766,31 @@ resolve-pkg-maps@^1.0.0:
|
|
| 1391 |
resolved "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz"
|
| 1392 |
integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==
|
| 1393 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1394 |
rollup@^4.20.0, rollup@^4.43.0:
|
| 1395 |
version "4.52.5"
|
| 1396 |
resolved "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz"
|
|
@@ -1441,6 +1841,23 @@ saxes@^6.0.0:
|
|
| 1441 |
dependencies:
|
| 1442 |
xmlchars "^2.2.0"
|
| 1443 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1444 |
shebang-command@^2.0.0:
|
| 1445 |
version "2.0.0"
|
| 1446 |
resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz"
|
|
@@ -1463,6 +1880,11 @@ siginfo@^2.0.0:
|
|
| 1463 |
resolved "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz"
|
| 1464 |
integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==
|
| 1465 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1466 |
sirv@^3.0.2:
|
| 1467 |
version "3.0.2"
|
| 1468 |
resolved "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz"
|
|
@@ -1472,6 +1894,14 @@ sirv@^3.0.2:
|
|
| 1472 |
mrmime "^2.0.0"
|
| 1473 |
totalist "^3.0.0"
|
| 1474 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1475 |
source-map-js@^1.0.1, source-map-js@^1.2.1:
|
| 1476 |
version "1.2.1"
|
| 1477 |
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz"
|
|
@@ -1489,6 +1919,11 @@ spawn-command@^0.0.2-1:
|
|
| 1489 |
resolved "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz"
|
| 1490 |
integrity sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==
|
| 1491 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1492 | |
| 1493 |
version "0.0.2"
|
| 1494 |
resolved "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz"
|
|
@@ -1499,6 +1934,11 @@ std-env@^3.9.0:
|
|
| 1499 |
resolved "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz"
|
| 1500 |
integrity sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==
|
| 1501 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1502 |
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
| 1503 |
version "4.2.3"
|
| 1504 |
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
|
|
@@ -1517,6 +1957,14 @@ string-width@^7.0.0, string-width@^7.2.0:
|
|
| 1517 |
get-east-asian-width "^1.0.0"
|
| 1518 |
strip-ansi "^7.1.0"
|
| 1519 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1520 |
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
| 1521 |
version "6.0.1"
|
| 1522 |
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
|
|
@@ -1597,6 +2045,13 @@ tldts@^7.0.5:
|
|
| 1597 |
dependencies:
|
| 1598 |
tldts-core "^7.0.17"
|
| 1599 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1600 |
totalist@^3.0.0:
|
| 1601 |
version "3.0.1"
|
| 1602 |
resolved "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz"
|
|
@@ -1643,7 +2098,12 @@ type-check@^0.4.0, type-check@~0.4.0:
|
|
| 1643 |
dependencies:
|
| 1644 |
prelude-ls "^1.2.1"
|
| 1645 |
|
| 1646 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1647 |
version "5.9.3"
|
| 1648 |
resolved "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz"
|
| 1649 |
integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==
|
|
@@ -1716,6 +2176,19 @@ vitest@^4.0.6, [email protected]:
|
|
| 1716 |
vite "^6.0.0 || ^7.0.0"
|
| 1717 |
why-is-node-running "^2.3.0"
|
| 1718 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1719 |
vue@^3.2.25, vue@^3.3.4, [email protected]:
|
| 1720 |
version "3.5.22"
|
| 1721 |
resolved "https://registry.npmjs.org/vue/-/vue-3.5.22.tgz"
|
|
@@ -1817,6 +2290,11 @@ y18n@^5.0.5:
|
|
| 1817 |
resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz"
|
| 1818 |
integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
|
| 1819 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1820 |
yargs-parser@^21.1.1:
|
| 1821 |
version "21.1.1"
|
| 1822 |
resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz"
|
|
|
|
| 213 |
resolved "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz"
|
| 214 |
integrity sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==
|
| 215 |
|
| 216 |
+
"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
|
| 217 |
+
version "1.1.2"
|
| 218 |
+
resolved "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz"
|
| 219 |
+
integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==
|
| 220 |
+
|
| 221 |
+
"@protobufjs/base64@^1.1.2":
|
| 222 |
+
version "1.1.2"
|
| 223 |
+
resolved "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz"
|
| 224 |
+
integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==
|
| 225 |
+
|
| 226 |
+
"@protobufjs/codegen@^2.0.4":
|
| 227 |
+
version "2.0.4"
|
| 228 |
+
resolved "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz"
|
| 229 |
+
integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==
|
| 230 |
+
|
| 231 |
+
"@protobufjs/eventemitter@^1.1.0":
|
| 232 |
+
version "1.1.0"
|
| 233 |
+
resolved "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz"
|
| 234 |
+
integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==
|
| 235 |
+
|
| 236 |
+
"@protobufjs/fetch@^1.1.0":
|
| 237 |
+
version "1.1.0"
|
| 238 |
+
resolved "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz"
|
| 239 |
+
integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==
|
| 240 |
+
dependencies:
|
| 241 |
+
"@protobufjs/aspromise" "^1.1.1"
|
| 242 |
+
"@protobufjs/inquire" "^1.1.0"
|
| 243 |
+
|
| 244 |
+
"@protobufjs/float@^1.0.2":
|
| 245 |
+
version "1.0.2"
|
| 246 |
+
resolved "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz"
|
| 247 |
+
integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==
|
| 248 |
+
|
| 249 |
+
"@protobufjs/inquire@^1.1.0":
|
| 250 |
+
version "1.1.0"
|
| 251 |
+
resolved "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz"
|
| 252 |
+
integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==
|
| 253 |
+
|
| 254 |
+
"@protobufjs/path@^1.1.2":
|
| 255 |
+
version "1.1.2"
|
| 256 |
+
resolved "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz"
|
| 257 |
+
integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==
|
| 258 |
+
|
| 259 |
+
"@protobufjs/pool@^1.1.0":
|
| 260 |
+
version "1.1.0"
|
| 261 |
+
resolved "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz"
|
| 262 |
+
integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==
|
| 263 |
+
|
| 264 |
+
"@protobufjs/utf8@^1.1.0":
|
| 265 |
+
version "1.1.0"
|
| 266 |
+
resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz"
|
| 267 |
+
integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
|
| 268 |
+
|
| 269 |
"@rollup/[email protected]":
|
| 270 |
version "4.52.5"
|
| 271 |
resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz"
|
|
|
|
| 304 |
resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz"
|
| 305 |
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
|
| 306 |
|
| 307 |
+
"@types/node@^18.0.0 || >=20.0.0", "@types/node@^20.0.0 || ^22.0.0 || >=24.0.0", "@types/node@^20.19.0 || >=22.12.0", "@types/node@^24.10.0", "@types/node@>=13.7.0":
|
| 308 |
version "24.10.0"
|
| 309 |
resolved "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz"
|
| 310 |
integrity sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==
|
|
|
|
| 399 |
"@vitest/pretty-format" "4.0.6"
|
| 400 |
tinyrainbow "^3.0.3"
|
| 401 |
|
| 402 |
+
"@volar/[email protected]":
|
| 403 |
+
version "2.4.23"
|
| 404 |
+
resolved "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.23.tgz"
|
| 405 |
+
integrity sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==
|
| 406 |
+
dependencies:
|
| 407 |
+
"@volar/source-map" "2.4.23"
|
| 408 |
+
|
| 409 |
+
"@volar/[email protected]":
|
| 410 |
+
version "2.4.23"
|
| 411 |
+
resolved "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.23.tgz"
|
| 412 |
+
integrity sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q==
|
| 413 |
+
|
| 414 |
+
"@volar/[email protected]":
|
| 415 |
+
version "2.4.23"
|
| 416 |
+
resolved "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.23.tgz"
|
| 417 |
+
integrity sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==
|
| 418 |
+
dependencies:
|
| 419 |
+
"@volar/language-core" "2.4.23"
|
| 420 |
+
path-browserify "^1.0.1"
|
| 421 |
+
vscode-uri "^3.0.8"
|
| 422 |
+
|
| 423 |
"@vue/[email protected]":
|
| 424 |
version "3.5.22"
|
| 425 |
resolved "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.22.tgz"
|
|
|
|
| 431 |
estree-walker "^2.0.2"
|
| 432 |
source-map-js "^1.2.1"
|
| 433 |
|
| 434 |
+
"@vue/compiler-dom@^3.5.0", "@vue/compiler-dom@3.5.22":
|
| 435 |
version "3.5.22"
|
| 436 |
resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.22.tgz"
|
| 437 |
integrity sha512-W8RknzUM1BLkypvdz10OVsGxnMAuSIZs9Wdx1vzA3mL5fNMN15rhrSCLiTm6blWeACwUwizzPVqGJgOGBEN/hA==
|
|
|
|
| 462 |
"@vue/compiler-dom" "3.5.22"
|
| 463 |
"@vue/shared" "3.5.22"
|
| 464 |
|
| 465 |
+
"@vue/[email protected]":
|
| 466 |
+
version "3.1.3"
|
| 467 |
+
resolved "https://registry.npmjs.org/@vue/language-core/-/language-core-3.1.3.tgz"
|
| 468 |
+
integrity sha512-KpR1F/eGAG9D1RZ0/T6zWJs6dh/pRLfY5WupecyYKJ1fjVmDMgTPw9wXmKv2rBjo4zCJiOSiyB8BDP1OUwpMEA==
|
| 469 |
+
dependencies:
|
| 470 |
+
"@volar/language-core" "2.4.23"
|
| 471 |
+
"@vue/compiler-dom" "^3.5.0"
|
| 472 |
+
"@vue/shared" "^3.5.0"
|
| 473 |
+
alien-signals "^3.0.0"
|
| 474 |
+
muggle-string "^0.4.1"
|
| 475 |
+
path-browserify "^1.0.1"
|
| 476 |
+
picomatch "^4.0.2"
|
| 477 |
+
|
| 478 |
"@vue/[email protected]":
|
| 479 |
version "3.5.22"
|
| 480 |
resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.22.tgz"
|
|
|
|
| 508 |
"@vue/compiler-ssr" "3.5.22"
|
| 509 |
"@vue/shared" "3.5.22"
|
| 510 |
|
| 511 |
+
"@vue/shared@^3.5.0", "@vue/shared@3.5.22":
|
| 512 |
version "3.5.22"
|
| 513 |
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.5.22.tgz"
|
| 514 |
integrity sha512-F4yc6palwq3TT0u+FYf0Ns4Tfl9GRFURDN2gWG7L1ecIaS/4fCIuFOjMTnCyjsu/OK6vaDKLCrGAa+KvvH+h4w==
|
|
|
|
| 523 |
resolved "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz"
|
| 524 |
integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==
|
| 525 |
|
| 526 |
+
adm-zip@^0.5.16:
|
| 527 |
+
version "0.5.16"
|
| 528 |
+
resolved "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz"
|
| 529 |
+
integrity sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==
|
| 530 |
+
|
| 531 |
agent-base@^7.1.0, agent-base@^7.1.2:
|
| 532 |
version "7.1.4"
|
| 533 |
resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz"
|
|
|
|
| 543 |
json-schema-traverse "^0.4.1"
|
| 544 |
uri-js "^4.2.2"
|
| 545 |
|
| 546 |
+
alien-signals@^3.0.0:
|
| 547 |
+
version "3.1.0"
|
| 548 |
+
resolved "https://registry.npmjs.org/alien-signals/-/alien-signals-3.1.0.tgz"
|
| 549 |
+
integrity sha512-yufC6VpSy8tK3I0lO67pjumo5JvDQVQyr38+3OHqe6CHl1t2VZekKZ7EKKZSqk0cRmE7U7tfZbpXiKNzuc+ckg==
|
| 550 |
+
|
| 551 |
amdefine@>=0.0.4:
|
| 552 |
version "1.0.1"
|
| 553 |
resolved "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz"
|
| 554 |
integrity sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==
|
| 555 |
|
| 556 |
+
ansi-escapes@^7.0.0:
|
| 557 |
+
version "7.2.0"
|
| 558 |
+
resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz"
|
| 559 |
+
integrity sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==
|
| 560 |
+
dependencies:
|
| 561 |
+
environment "^1.0.0"
|
| 562 |
+
|
| 563 |
ansi-regex@^5.0.1:
|
| 564 |
version "5.0.1"
|
| 565 |
resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz"
|
|
|
|
| 604 |
dependencies:
|
| 605 |
require-from-string "^2.0.2"
|
| 606 |
|
| 607 |
+
boolean@^3.0.1:
|
| 608 |
+
version "3.2.0"
|
| 609 |
+
resolved "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz"
|
| 610 |
+
integrity sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==
|
| 611 |
+
|
| 612 |
brace-expansion@^1.1.7:
|
| 613 |
version "1.1.12"
|
| 614 |
resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz"
|
|
|
|
| 617 |
balanced-match "^1.0.0"
|
| 618 |
concat-map "0.0.1"
|
| 619 |
|
| 620 |
+
braces@^3.0.3:
|
| 621 |
+
version "3.0.3"
|
| 622 |
+
resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz"
|
| 623 |
+
integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
|
| 624 |
+
dependencies:
|
| 625 |
+
fill-range "^7.1.1"
|
| 626 |
+
|
| 627 |
callsites@^3.0.0:
|
| 628 |
version "3.1.0"
|
| 629 |
resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz"
|
|
|
|
| 649 |
dependencies:
|
| 650 |
jsonlint "1.6.0"
|
| 651 |
|
| 652 |
+
cli-cursor@^5.0.0:
|
| 653 |
+
version "5.0.0"
|
| 654 |
+
resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz"
|
| 655 |
+
integrity sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==
|
| 656 |
+
dependencies:
|
| 657 |
+
restore-cursor "^5.0.0"
|
| 658 |
+
|
| 659 |
+
cli-truncate@^5.0.0:
|
| 660 |
+
version "5.1.1"
|
| 661 |
+
resolved "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.1.1.tgz"
|
| 662 |
+
integrity sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==
|
| 663 |
+
dependencies:
|
| 664 |
+
slice-ansi "^7.1.0"
|
| 665 |
+
string-width "^8.0.0"
|
| 666 |
+
|
| 667 |
cliui@^8.0.1:
|
| 668 |
version "8.0.1"
|
| 669 |
resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz"
|
|
|
|
| 694 |
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
|
| 695 |
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
| 696 |
|
| 697 |
+
colorette@^2.0.20:
|
| 698 |
+
version "2.0.20"
|
| 699 |
+
resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz"
|
| 700 |
+
integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==
|
| 701 |
+
|
| 702 | |
| 703 |
version "0.5.1"
|
| 704 |
resolved "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz"
|
| 705 |
integrity sha512-XjsuUwpDeY98+yz959OlUK6m7mLBM+1MEG5oaenfuQnNnrQk1WvtcvFgN3FNDP3f2NmZ211t0mNEfSEN1h0eIg==
|
| 706 |
|
| 707 |
+
commander@^14.0.2:
|
| 708 |
+
version "14.0.2"
|
| 709 |
+
resolved "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz"
|
| 710 |
+
integrity sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==
|
| 711 |
+
|
| 712 | |
| 713 |
version "0.0.1"
|
| 714 |
resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
|
|
|
|
| 792 |
resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz"
|
| 793 |
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
|
| 794 |
|
| 795 |
+
define-data-property@^1.0.1:
|
| 796 |
+
version "1.1.4"
|
| 797 |
+
resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz"
|
| 798 |
+
integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
|
| 799 |
+
dependencies:
|
| 800 |
+
es-define-property "^1.0.0"
|
| 801 |
+
es-errors "^1.3.0"
|
| 802 |
+
gopd "^1.0.1"
|
| 803 |
+
|
| 804 |
+
define-properties@^1.2.1:
|
| 805 |
+
version "1.2.1"
|
| 806 |
+
resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz"
|
| 807 |
+
integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==
|
| 808 |
+
dependencies:
|
| 809 |
+
define-data-property "^1.0.1"
|
| 810 |
+
has-property-descriptors "^1.0.0"
|
| 811 |
+
object-keys "^1.1.1"
|
| 812 |
+
|
| 813 |
+
detect-node@^2.0.4:
|
| 814 |
+
version "2.1.0"
|
| 815 |
+
resolved "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz"
|
| 816 |
+
integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==
|
| 817 |
+
|
| 818 | |
| 819 |
version "0.1.10"
|
| 820 |
resolved "https://registry.npmjs.org/ebnf-parser/-/ebnf-parser-0.1.10.tgz"
|
|
|
|
| 840 |
resolved "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz"
|
| 841 |
integrity sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==
|
| 842 |
|
| 843 |
+
environment@^1.0.0:
|
| 844 |
+
version "1.1.0"
|
| 845 |
+
resolved "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz"
|
| 846 |
+
integrity sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==
|
| 847 |
+
|
| 848 |
+
es-define-property@^1.0.0:
|
| 849 |
+
version "1.0.1"
|
| 850 |
+
resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz"
|
| 851 |
+
integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==
|
| 852 |
+
|
| 853 |
+
es-errors@^1.3.0:
|
| 854 |
+
version "1.3.0"
|
| 855 |
+
resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz"
|
| 856 |
+
integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
|
| 857 |
+
|
| 858 |
es-module-lexer@^1.7.0:
|
| 859 |
version "1.7.0"
|
| 860 |
resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz"
|
| 861 |
integrity sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==
|
| 862 |
|
| 863 |
+
es6-error@^4.1.1:
|
| 864 |
+
version "4.1.1"
|
| 865 |
+
resolved "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz"
|
| 866 |
+
integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==
|
| 867 |
+
|
| 868 |
esbuild@^0.21.3:
|
| 869 |
version "0.21.5"
|
| 870 |
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz"
|
|
|
|
| 894 |
"@esbuild/win32-ia32" "0.21.5"
|
| 895 |
"@esbuild/win32-x64" "0.21.5"
|
| 896 |
|
| 897 |
+
esbuild@^0.25.0, esbuild@~0.25.0:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 898 |
version "0.25.12"
|
| 899 |
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz"
|
| 900 |
integrity sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==
|
|
|
|
| 1078 |
resolved "https://registry.npmjs.org/esutils/-/esutils-1.0.0.tgz"
|
| 1079 |
integrity sha512-x/iYH53X3quDwfHRz4y8rn4XcEwwCJeWsul9pF1zldMbGtgOtMNBEOuYWwB1EQlK2LRa1fev3YAgym/RElp5Cg==
|
| 1080 |
|
| 1081 |
+
eventemitter3@^5.0.1:
|
| 1082 |
+
version "5.0.1"
|
| 1083 |
+
resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz"
|
| 1084 |
+
integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==
|
| 1085 |
+
|
| 1086 |
expect-type@^1.2.2:
|
| 1087 |
version "1.2.2"
|
| 1088 |
resolved "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz"
|
|
|
|
| 1125 |
dependencies:
|
| 1126 |
flat-cache "^4.0.0"
|
| 1127 |
|
| 1128 |
+
fill-range@^7.1.1:
|
| 1129 |
+
version "7.1.1"
|
| 1130 |
+
resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz"
|
| 1131 |
+
integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
|
| 1132 |
+
dependencies:
|
| 1133 |
+
to-regex-range "^5.0.1"
|
| 1134 |
+
|
| 1135 |
find-up@^5.0.0:
|
| 1136 |
version "5.0.0"
|
| 1137 |
resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz"
|
|
|
|
| 1148 |
flatted "^3.2.9"
|
| 1149 |
keyv "^4.5.4"
|
| 1150 |
|
| 1151 |
+
flatbuffers@^25.1.24:
|
| 1152 |
+
version "25.9.23"
|
| 1153 |
+
resolved "https://registry.npmjs.org/flatbuffers/-/flatbuffers-25.9.23.tgz"
|
| 1154 |
+
integrity sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ==
|
| 1155 |
+
|
| 1156 |
flatted@^3.2.9, flatted@^3.3.3:
|
| 1157 |
version "3.3.3"
|
| 1158 |
resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz"
|
|
|
|
| 1163 |
resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz"
|
| 1164 |
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
|
| 1165 |
|
| 1166 |
+
get-east-asian-width@^1.0.0, get-east-asian-width@^1.3.0, get-east-asian-width@^1.3.1:
|
| 1167 |
version "1.4.0"
|
| 1168 |
resolved "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz"
|
| 1169 |
integrity sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==
|
|
|
|
| 1182 |
dependencies:
|
| 1183 |
is-glob "^4.0.3"
|
| 1184 |
|
| 1185 |
+
global-agent@^3.0.0:
|
| 1186 |
+
version "3.0.0"
|
| 1187 |
+
resolved "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz"
|
| 1188 |
+
integrity sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==
|
| 1189 |
+
dependencies:
|
| 1190 |
+
boolean "^3.0.1"
|
| 1191 |
+
es6-error "^4.1.1"
|
| 1192 |
+
matcher "^3.0.0"
|
| 1193 |
+
roarr "^2.15.3"
|
| 1194 |
+
semver "^7.3.2"
|
| 1195 |
+
serialize-error "^7.0.1"
|
| 1196 |
+
|
| 1197 |
globals@^14.0.0:
|
| 1198 |
version "14.0.0"
|
| 1199 |
resolved "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz"
|
| 1200 |
integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==
|
| 1201 |
|
| 1202 |
+
globalthis@^1.0.1:
|
| 1203 |
+
version "1.0.4"
|
| 1204 |
+
resolved "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz"
|
| 1205 |
+
integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==
|
| 1206 |
+
dependencies:
|
| 1207 |
+
define-properties "^1.2.1"
|
| 1208 |
+
gopd "^1.0.1"
|
| 1209 |
+
|
| 1210 |
+
gopd@^1.0.1:
|
| 1211 |
+
version "1.2.0"
|
| 1212 |
+
resolved "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz"
|
| 1213 |
+
integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==
|
| 1214 |
+
|
| 1215 |
+
guid-typescript@^1.0.9:
|
| 1216 |
+
version "1.0.9"
|
| 1217 |
+
resolved "https://registry.npmjs.org/guid-typescript/-/guid-typescript-1.0.9.tgz"
|
| 1218 |
+
integrity sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ==
|
| 1219 |
+
|
| 1220 |
has-flag@^4.0.0:
|
| 1221 |
version "4.0.0"
|
| 1222 |
resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz"
|
| 1223 |
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
|
| 1224 |
|
| 1225 |
+
has-property-descriptors@^1.0.0:
|
| 1226 |
+
version "1.0.2"
|
| 1227 |
+
resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz"
|
| 1228 |
+
integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
|
| 1229 |
+
dependencies:
|
| 1230 |
+
es-define-property "^1.0.0"
|
| 1231 |
+
|
| 1232 |
html-encoding-sniffer@^4.0.0:
|
| 1233 |
version "4.0.0"
|
| 1234 |
resolved "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz"
|
|
|
|
| 1252 |
agent-base "^7.1.2"
|
| 1253 |
debug "4"
|
| 1254 |
|
| 1255 |
+
husky@^9.1.7:
|
| 1256 |
+
version "9.1.7"
|
| 1257 |
+
resolved "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz"
|
| 1258 |
+
integrity sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==
|
| 1259 |
+
|
| 1260 | |
| 1261 |
version "0.6.3"
|
| 1262 |
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz"
|
|
|
|
| 1292 |
resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz"
|
| 1293 |
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
|
| 1294 |
|
| 1295 |
+
is-fullwidth-code-point@^5.0.0:
|
| 1296 |
+
version "5.1.0"
|
| 1297 |
+
resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz"
|
| 1298 |
+
integrity sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==
|
| 1299 |
+
dependencies:
|
| 1300 |
+
get-east-asian-width "^1.3.1"
|
| 1301 |
+
|
| 1302 |
is-glob@^4.0.0, is-glob@^4.0.3:
|
| 1303 |
version "4.0.3"
|
| 1304 |
resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz"
|
|
|
|
| 1306 |
dependencies:
|
| 1307 |
is-extglob "^2.1.1"
|
| 1308 |
|
| 1309 |
+
is-number@^7.0.0:
|
| 1310 |
+
version "7.0.0"
|
| 1311 |
+
resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz"
|
| 1312 |
+
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
|
| 1313 |
+
|
| 1314 |
is-potential-custom-element-name@^1.0.1:
|
| 1315 |
version "1.0.1"
|
| 1316 |
resolved "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz"
|
|
|
|
| 1391 |
resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz"
|
| 1392 |
integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
|
| 1393 |
|
| 1394 |
+
json-stringify-safe@^5.0.1:
|
| 1395 |
+
version "5.0.1"
|
| 1396 |
+
resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
|
| 1397 |
+
integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==
|
| 1398 |
+
|
| 1399 | |
| 1400 |
version "1.6.0"
|
| 1401 |
resolved "https://registry.npmjs.org/jsonlint/-/jsonlint-1.6.0.tgz"
|
|
|
|
| 1434 |
resolved "https://registry.npmjs.org/lex-parser/-/lex-parser-0.1.4.tgz"
|
| 1435 |
integrity sha512-DuAEISsr1H4LOpmFLkyMc8YStiRWZCO8hMsoXAXSbgyfvs2WQhSt0+/FBv3ZU/JBFZMGcE+FWzEBSzwUU7U27w==
|
| 1436 |
|
| 1437 |
+
lint-staged@^16.2.7:
|
| 1438 |
+
version "16.2.7"
|
| 1439 |
+
resolved "https://registry.npmjs.org/lint-staged/-/lint-staged-16.2.7.tgz"
|
| 1440 |
+
integrity sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==
|
| 1441 |
+
dependencies:
|
| 1442 |
+
commander "^14.0.2"
|
| 1443 |
+
listr2 "^9.0.5"
|
| 1444 |
+
micromatch "^4.0.8"
|
| 1445 |
+
nano-spawn "^2.0.0"
|
| 1446 |
+
pidtree "^0.6.0"
|
| 1447 |
+
string-argv "^0.3.2"
|
| 1448 |
+
yaml "^2.8.1"
|
| 1449 |
+
|
| 1450 |
+
listr2@^9.0.5:
|
| 1451 |
+
version "9.0.5"
|
| 1452 |
+
resolved "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz"
|
| 1453 |
+
integrity sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==
|
| 1454 |
+
dependencies:
|
| 1455 |
+
cli-truncate "^5.0.0"
|
| 1456 |
+
colorette "^2.0.20"
|
| 1457 |
+
eventemitter3 "^5.0.1"
|
| 1458 |
+
log-update "^6.1.0"
|
| 1459 |
+
rfdc "^1.4.1"
|
| 1460 |
+
wrap-ansi "^9.0.0"
|
| 1461 |
+
|
| 1462 |
locate-path@^6.0.0:
|
| 1463 |
version "6.0.0"
|
| 1464 |
resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz"
|
|
|
|
| 1476 |
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
|
| 1477 |
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
| 1478 |
|
| 1479 |
+
log-update@^6.1.0:
|
| 1480 |
+
version "6.1.0"
|
| 1481 |
+
resolved "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz"
|
| 1482 |
+
integrity sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==
|
| 1483 |
+
dependencies:
|
| 1484 |
+
ansi-escapes "^7.0.0"
|
| 1485 |
+
cli-cursor "^5.0.0"
|
| 1486 |
+
slice-ansi "^7.1.0"
|
| 1487 |
+
strip-ansi "^7.1.0"
|
| 1488 |
+
wrap-ansi "^9.0.0"
|
| 1489 |
+
|
| 1490 |
+
long@^5.0.0, long@^5.2.3:
|
| 1491 |
+
version "5.3.2"
|
| 1492 |
+
resolved "https://registry.npmjs.org/long/-/long-5.3.2.tgz"
|
| 1493 |
+
integrity sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==
|
| 1494 |
+
|
| 1495 |
lru-cache@^11.2.1, lru-cache@^11.2.2:
|
| 1496 |
version "11.2.2"
|
| 1497 |
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz"
|
|
|
|
| 1504 |
dependencies:
|
| 1505 |
"@jridgewell/sourcemap-codec" "^1.5.5"
|
| 1506 |
|
| 1507 |
+
matcher@^3.0.0:
|
| 1508 |
+
version "3.0.0"
|
| 1509 |
+
resolved "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz"
|
| 1510 |
+
integrity sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==
|
| 1511 |
+
dependencies:
|
| 1512 |
+
escape-string-regexp "^4.0.0"
|
| 1513 |
+
|
| 1514 | |
| 1515 |
version "2.12.2"
|
| 1516 |
resolved "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz"
|
| 1517 |
integrity sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==
|
| 1518 |
|
| 1519 |
+
micromatch@^4.0.8:
|
| 1520 |
+
version "4.0.8"
|
| 1521 |
+
resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz"
|
| 1522 |
+
integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
|
| 1523 |
+
dependencies:
|
| 1524 |
+
braces "^3.0.3"
|
| 1525 |
+
picomatch "^2.3.1"
|
| 1526 |
+
|
| 1527 |
+
mimic-function@^5.0.0:
|
| 1528 |
+
version "5.0.1"
|
| 1529 |
+
resolved "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz"
|
| 1530 |
+
integrity sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==
|
| 1531 |
+
|
| 1532 |
minimatch@^3.1.2:
|
| 1533 |
version "3.1.2"
|
| 1534 |
resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
|
|
|
|
| 1546 |
resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
|
| 1547 |
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
| 1548 |
|
| 1549 |
+
muggle-string@^0.4.1:
|
| 1550 |
+
version "0.4.1"
|
| 1551 |
+
resolved "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz"
|
| 1552 |
+
integrity sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==
|
| 1553 |
+
|
| 1554 |
+
nano-spawn@^2.0.0:
|
| 1555 |
+
version "2.0.0"
|
| 1556 |
+
resolved "https://registry.npmjs.org/nano-spawn/-/nano-spawn-2.0.0.tgz"
|
| 1557 |
+
integrity sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==
|
| 1558 |
+
|
| 1559 |
nanoid@^3.3.11:
|
| 1560 |
version "3.3.11"
|
| 1561 |
resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz"
|
|
|
|
| 1574 |
colors "0.5.x"
|
| 1575 |
underscore "1.1.x"
|
| 1576 |
|
| 1577 |
+
object-keys@^1.1.1:
|
| 1578 |
+
version "1.1.1"
|
| 1579 |
+
resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz"
|
| 1580 |
+
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
|
| 1581 |
+
|
| 1582 |
+
onetime@^7.0.0:
|
| 1583 |
+
version "7.0.0"
|
| 1584 |
+
resolved "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz"
|
| 1585 |
+
integrity sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==
|
| 1586 |
+
dependencies:
|
| 1587 |
+
mimic-function "^5.0.0"
|
| 1588 |
+
|
| 1589 | |
| 1590 |
+
version "1.23.2"
|
| 1591 |
+
resolved "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.23.2.tgz"
|
| 1592 |
+
integrity sha512-5LFsC9Dukzp2WV6kNHYLNzp8sT6V02IubLCbzw2Xd6X5GOlr65gAX6xiJwyi2URJol/s71gaQLC5F2C25AAR2w==
|
| 1593 |
+
|
| 1594 | |
| 1595 |
+
version "1.23.2"
|
| 1596 |
+
resolved "https://registry.npmjs.org/onnxruntime-node/-/onnxruntime-node-1.23.2.tgz"
|
| 1597 |
+
integrity sha512-OBTsG0W8ddBVOeVVVychpVBS87A9YV5sa2hJ6lc025T97Le+J4v++PwSC4XFs1C62SWyNdof0Mh4KvnZgtt4aw==
|
| 1598 |
+
dependencies:
|
| 1599 |
+
adm-zip "^0.5.16"
|
| 1600 |
+
global-agent "^3.0.0"
|
| 1601 |
+
onnxruntime-common "1.23.2"
|
| 1602 |
+
|
| 1603 | |
| 1604 |
+
version "1.23.2"
|
| 1605 |
+
resolved "https://registry.npmjs.org/onnxruntime-web/-/onnxruntime-web-1.23.2.tgz"
|
| 1606 |
+
integrity sha512-T09JUtMn+CZLk3mFwqiH0lgQf+4S7+oYHHtk6uhaYAAJI95bTcKi5bOOZYwORXfS/RLZCjDDEXGWIuOCAFlEjg==
|
| 1607 |
+
dependencies:
|
| 1608 |
+
flatbuffers "^25.1.24"
|
| 1609 |
+
guid-typescript "^1.0.9"
|
| 1610 |
+
long "^5.2.3"
|
| 1611 |
+
onnxruntime-common "1.23.2"
|
| 1612 |
+
platform "^1.3.6"
|
| 1613 |
+
protobufjs "^7.2.4"
|
| 1614 |
+
|
| 1615 |
optionator@^0.9.3:
|
| 1616 |
version "0.9.4"
|
| 1617 |
resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz"
|
|
|
|
| 1652 |
dependencies:
|
| 1653 |
entities "^6.0.0"
|
| 1654 |
|
| 1655 |
+
path-browserify@^1.0.1:
|
| 1656 |
+
version "1.0.1"
|
| 1657 |
+
resolved "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz"
|
| 1658 |
+
integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==
|
| 1659 |
+
|
| 1660 |
path-exists@^4.0.0:
|
| 1661 |
version "4.0.0"
|
| 1662 |
resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz"
|
|
|
|
| 1677 |
resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz"
|
| 1678 |
integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
|
| 1679 |
|
| 1680 |
+
picomatch@^2.3.1:
|
| 1681 |
+
version "2.3.1"
|
| 1682 |
+
resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
|
| 1683 |
+
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
| 1684 |
+
|
| 1685 |
+
"picomatch@^3 || ^4", picomatch@^4.0.2, picomatch@^4.0.3:
|
| 1686 |
version "4.0.3"
|
| 1687 |
resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz"
|
| 1688 |
integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==
|
| 1689 |
|
| 1690 |
+
pidtree@^0.6.0:
|
| 1691 |
+
version "0.6.0"
|
| 1692 |
+
resolved "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz"
|
| 1693 |
+
integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==
|
| 1694 |
+
|
| 1695 |
+
platform@^1.3.6:
|
| 1696 |
+
version "1.3.6"
|
| 1697 |
+
resolved "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz"
|
| 1698 |
+
integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==
|
| 1699 |
+
|
| 1700 |
postcss@^8.4.43, postcss@^8.5.6:
|
| 1701 |
version "8.5.6"
|
| 1702 |
resolved "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz"
|
|
|
|
| 1723 |
resolved "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz"
|
| 1724 |
integrity sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==
|
| 1725 |
|
| 1726 |
+
protobufjs@^7.2.4:
|
| 1727 |
+
version "7.5.4"
|
| 1728 |
+
resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz"
|
| 1729 |
+
integrity sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==
|
| 1730 |
+
dependencies:
|
| 1731 |
+
"@protobufjs/aspromise" "^1.1.2"
|
| 1732 |
+
"@protobufjs/base64" "^1.1.2"
|
| 1733 |
+
"@protobufjs/codegen" "^2.0.4"
|
| 1734 |
+
"@protobufjs/eventemitter" "^1.1.0"
|
| 1735 |
+
"@protobufjs/fetch" "^1.1.0"
|
| 1736 |
+
"@protobufjs/float" "^1.0.2"
|
| 1737 |
+
"@protobufjs/inquire" "^1.1.0"
|
| 1738 |
+
"@protobufjs/path" "^1.1.2"
|
| 1739 |
+
"@protobufjs/pool" "^1.1.0"
|
| 1740 |
+
"@protobufjs/utf8" "^1.1.0"
|
| 1741 |
+
"@types/node" ">=13.7.0"
|
| 1742 |
+
long "^5.0.0"
|
| 1743 |
+
|
| 1744 |
punycode@^2.1.0, punycode@^2.3.1:
|
| 1745 |
version "2.3.1"
|
| 1746 |
resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz"
|
|
|
|
| 1766 |
resolved "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz"
|
| 1767 |
integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==
|
| 1768 |
|
| 1769 |
+
restore-cursor@^5.0.0:
|
| 1770 |
+
version "5.1.0"
|
| 1771 |
+
resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz"
|
| 1772 |
+
integrity sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==
|
| 1773 |
+
dependencies:
|
| 1774 |
+
onetime "^7.0.0"
|
| 1775 |
+
signal-exit "^4.1.0"
|
| 1776 |
+
|
| 1777 |
+
rfdc@^1.4.1:
|
| 1778 |
+
version "1.4.1"
|
| 1779 |
+
resolved "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz"
|
| 1780 |
+
integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==
|
| 1781 |
+
|
| 1782 |
+
roarr@^2.15.3:
|
| 1783 |
+
version "2.15.4"
|
| 1784 |
+
resolved "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz"
|
| 1785 |
+
integrity sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==
|
| 1786 |
+
dependencies:
|
| 1787 |
+
boolean "^3.0.1"
|
| 1788 |
+
detect-node "^2.0.4"
|
| 1789 |
+
globalthis "^1.0.1"
|
| 1790 |
+
json-stringify-safe "^5.0.1"
|
| 1791 |
+
semver-compare "^1.0.0"
|
| 1792 |
+
sprintf-js "^1.1.2"
|
| 1793 |
+
|
| 1794 |
rollup@^4.20.0, rollup@^4.43.0:
|
| 1795 |
version "4.52.5"
|
| 1796 |
resolved "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz"
|
|
|
|
| 1841 |
dependencies:
|
| 1842 |
xmlchars "^2.2.0"
|
| 1843 |
|
| 1844 |
+
semver-compare@^1.0.0:
|
| 1845 |
+
version "1.0.0"
|
| 1846 |
+
resolved "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz"
|
| 1847 |
+
integrity sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==
|
| 1848 |
+
|
| 1849 |
+
semver@^7.3.2:
|
| 1850 |
+
version "7.7.3"
|
| 1851 |
+
resolved "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz"
|
| 1852 |
+
integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==
|
| 1853 |
+
|
| 1854 |
+
serialize-error@^7.0.1:
|
| 1855 |
+
version "7.0.1"
|
| 1856 |
+
resolved "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz"
|
| 1857 |
+
integrity sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==
|
| 1858 |
+
dependencies:
|
| 1859 |
+
type-fest "^0.13.1"
|
| 1860 |
+
|
| 1861 |
shebang-command@^2.0.0:
|
| 1862 |
version "2.0.0"
|
| 1863 |
resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz"
|
|
|
|
| 1880 |
resolved "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz"
|
| 1881 |
integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==
|
| 1882 |
|
| 1883 |
+
signal-exit@^4.1.0:
|
| 1884 |
+
version "4.1.0"
|
| 1885 |
+
resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz"
|
| 1886 |
+
integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
|
| 1887 |
+
|
| 1888 |
sirv@^3.0.2:
|
| 1889 |
version "3.0.2"
|
| 1890 |
resolved "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz"
|
|
|
|
| 1894 |
mrmime "^2.0.0"
|
| 1895 |
totalist "^3.0.0"
|
| 1896 |
|
| 1897 |
+
slice-ansi@^7.1.0:
|
| 1898 |
+
version "7.1.2"
|
| 1899 |
+
resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz"
|
| 1900 |
+
integrity sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==
|
| 1901 |
+
dependencies:
|
| 1902 |
+
ansi-styles "^6.2.1"
|
| 1903 |
+
is-fullwidth-code-point "^5.0.0"
|
| 1904 |
+
|
| 1905 |
source-map-js@^1.0.1, source-map-js@^1.2.1:
|
| 1906 |
version "1.2.1"
|
| 1907 |
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz"
|
|
|
|
| 1919 |
resolved "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz"
|
| 1920 |
integrity sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==
|
| 1921 |
|
| 1922 |
+
sprintf-js@^1.1.2:
|
| 1923 |
+
version "1.1.3"
|
| 1924 |
+
resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz"
|
| 1925 |
+
integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==
|
| 1926 |
+
|
| 1927 | |
| 1928 |
version "0.0.2"
|
| 1929 |
resolved "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz"
|
|
|
|
| 1934 |
resolved "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz"
|
| 1935 |
integrity sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==
|
| 1936 |
|
| 1937 |
+
string-argv@^0.3.2:
|
| 1938 |
+
version "0.3.2"
|
| 1939 |
+
resolved "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz"
|
| 1940 |
+
integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==
|
| 1941 |
+
|
| 1942 |
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
| 1943 |
version "4.2.3"
|
| 1944 |
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
|
|
|
|
| 1957 |
get-east-asian-width "^1.0.0"
|
| 1958 |
strip-ansi "^7.1.0"
|
| 1959 |
|
| 1960 |
+
string-width@^8.0.0:
|
| 1961 |
+
version "8.1.0"
|
| 1962 |
+
resolved "https://registry.npmjs.org/string-width/-/string-width-8.1.0.tgz"
|
| 1963 |
+
integrity sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==
|
| 1964 |
+
dependencies:
|
| 1965 |
+
get-east-asian-width "^1.3.0"
|
| 1966 |
+
strip-ansi "^7.1.0"
|
| 1967 |
+
|
| 1968 |
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
| 1969 |
version "6.0.1"
|
| 1970 |
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
|
|
|
|
| 2045 |
dependencies:
|
| 2046 |
tldts-core "^7.0.17"
|
| 2047 |
|
| 2048 |
+
to-regex-range@^5.0.1:
|
| 2049 |
+
version "5.0.1"
|
| 2050 |
+
resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz"
|
| 2051 |
+
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
|
| 2052 |
+
dependencies:
|
| 2053 |
+
is-number "^7.0.0"
|
| 2054 |
+
|
| 2055 |
totalist@^3.0.0:
|
| 2056 |
version "3.0.1"
|
| 2057 |
resolved "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz"
|
|
|
|
| 2098 |
dependencies:
|
| 2099 |
prelude-ls "^1.2.1"
|
| 2100 |
|
| 2101 |
+
type-fest@^0.13.1:
|
| 2102 |
+
version "0.13.1"
|
| 2103 |
+
resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz"
|
| 2104 |
+
integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==
|
| 2105 |
+
|
| 2106 |
+
typescript@*, typescript@^5.2.2, typescript@>=5.0.0:
|
| 2107 |
version "5.9.3"
|
| 2108 |
resolved "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz"
|
| 2109 |
integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==
|
|
|
|
| 2176 |
vite "^6.0.0 || ^7.0.0"
|
| 2177 |
why-is-node-running "^2.3.0"
|
| 2178 |
|
| 2179 |
+
vscode-uri@^3.0.8:
|
| 2180 |
+
version "3.1.0"
|
| 2181 |
+
resolved "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz"
|
| 2182 |
+
integrity sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==
|
| 2183 |
+
|
| 2184 |
+
vue-tsc@^3.1.3:
|
| 2185 |
+
version "3.1.3"
|
| 2186 |
+
resolved "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.1.3.tgz"
|
| 2187 |
+
integrity sha512-StMNfZHwPIXQgY3KxPKM0Jsoc8b46mDV3Fn2UlHCBIwRJApjqrSwqeMYgWf0zpN+g857y74pv7GWuBm+UqQe1w==
|
| 2188 |
+
dependencies:
|
| 2189 |
+
"@volar/typescript" "2.4.23"
|
| 2190 |
+
"@vue/language-core" "3.1.3"
|
| 2191 |
+
|
| 2192 |
vue@^3.2.25, vue@^3.3.4, [email protected]:
|
| 2193 |
version "3.5.22"
|
| 2194 |
resolved "https://registry.npmjs.org/vue/-/vue-3.5.22.tgz"
|
|
|
|
| 2290 |
resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz"
|
| 2291 |
integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
|
| 2292 |
|
| 2293 |
+
yaml@^2.4.2, yaml@^2.8.1:
|
| 2294 |
+
version "2.8.1"
|
| 2295 |
+
resolved "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz"
|
| 2296 |
+
integrity sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==
|
| 2297 |
+
|
| 2298 |
yargs-parser@^21.1.1:
|
| 2299 |
version "21.1.1"
|
| 2300 |
resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz"
|