diff --git a/CHANGELOG.md b/CHANGELOG.md index ddc336a..abdd517 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,14 @@ All notable changes to this project will be documented in this file. - A manual GameSwitcher pick still wins — it persists to `cc-active-game` and suppresses auto-derive (operator intent beats the heuristic). Un-overridden panels keep tracking the fleet across sessions. - **No backend/schema change:** a license's game(s) are the distinct games of its instances — the normalized source of truth. Deliberately did NOT add a `licenses.game` column (would duplicate `game_instances.game` and drift; see Lesson 20). +**Frontend — sidebar agent-health footer is now fleet-aware:** +- The shell footer read a single legacy `server.connection` (one `server_connections` row), which disagreed with the multi-host fleet. Repointed it at the fleet store: one host → hostname + status + last-heartbeat; multiple → `{online}/{total} online` + total instance count. Tone aggregates (all online → healthy, some → degraded, none → offline). Dropped the legacy `useServerStore` dependency from the shell entirely. + +**Frontend — removed dead `vuefinder` dependency:** +- VueFinder was replaced by the native instance-scoped file manager but the plugin (and its CSS) were still globally registered in `main.ts` and shipped in the bundle. Removed the dep + the three `main.ts` lines. Side effect: the main JS chunk dropped **588 kB → 165 kB** (vuefinder bundled an entire unused file-manager UI). + +**Recon note (not a change):** `corrosion.{license}.cmd.server` was on the cleanup list as "dead v1" — it is NOT. It remains the live license-level command path for all plugin/module config applies, plugin install, scheduled tasks, and legacy start/stop/restart, served only by the legacy Go agent. The Rust agent does not implement it yet — this is a **parity/migration gap** (Phase 2+), not dead code. Left intact. + **CI — signed host-agent build:** - Fixed the `Sign artifacts (minisign)` step (`Error while loading the secret key file`): a minisign secret key is two lines and CI secret storage mangles the embedded newline. The job now base64-decodes the secret (single-line, mangling-proof) with auto-detect fallback to a raw key. `MINISIGN_SECRET_KEY` must be stored as `base64 < secret.key | tr -d '\n'`. Verified end-to-end: `agent-v2.0.0-alpha.8` Linux + Windows binaries validate against the agent's embedded public key; tampered byte rejected. diff --git a/frontend/package-lock.json b/frontend/package-lock.json index ec9d0f5..2cef64e 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,20 +1,19 @@ { "name": "frontend", - "version": "0.0.0", + "version": "1.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "frontend", - "version": "0.0.0", + "version": "1.0.1", "dependencies": { "echarts": "^6.0.0", "lucide-vue-next": "^0.564.0", "pinia": "^3.0.4", "pinia-plugin-persistedstate": "^4.7.1", "vue": "^3.5.25", - "vue-router": "^5.0.2", - "vuefinder": "^4.1.1" + "vue-router": "^5.0.2" }, "devDependencies": { "@tailwindcss/vite": "^4.1.18", @@ -531,31 +530,6 @@ "node": ">=18" } }, - "node_modules/@floating-ui/core": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.4.tgz", - "integrity": "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==", - "license": "MIT", - "dependencies": { - "@floating-ui/utils": "^0.2.10" - } - }, - "node_modules/@floating-ui/dom": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.5.tgz", - "integrity": "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==", - "license": "MIT", - "dependencies": { - "@floating-ui/core": "^1.7.4", - "@floating-ui/utils": "^0.2.10" - } - }, - "node_modules/@floating-ui/utils": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", - "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", - "license": "MIT" - }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -601,71 +575,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@nanostores/i18n": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@nanostores/i18n/-/i18n-1.2.2.tgz", - "integrity": "sha512-5LLxl95+ZI46MrM/Kn7YjORKsD7+Xy2tgjZ7/oDT/BGPEiaBM9lK89/afeK+BqaQL0Xd9Xaa5MPuuVSyWAo+/w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "engines": { - "node": "^20.0.0 || >=22.0.0" - }, - "peerDependencies": { - "nanostores": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^1.0.0" - } - }, - "node_modules/@nanostores/persistent": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@nanostores/persistent/-/persistent-1.3.3.tgz", - "integrity": "sha512-+b4I8xrmjhKE3hQ9V7/b4Xa+MBMkM2P4Ulv33zFEF/+2Hucsb24vTjYiWR8R97y8YdRptmRKlL5Qwy0q1Jj5nQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "engines": { - "node": "^20.0.0 || >=22.0.0" - }, - "peerDependencies": { - "nanostores": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^1.0.0" - } - }, - "node_modules/@nanostores/vue": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@nanostores/vue/-/vue-1.0.1.tgz", - "integrity": "sha512-0VwubMTMvEdWQhVN4BAvDZ+vHQH3O1G9BaOfgrjfF4erqBsWScoK/zyaBeRfFjptNOb25947EFPHBZwEf9JcMg==", - "funding": [ - { - "type": "buymeacoffee", - "url": "https://buymeacoffee.com/euaaaio" - } - ], - "license": "MIT", - "engines": { - "node": "^20.0.0 || >=22.0.0" - }, - "peerDependencies": { - "@nanostores/logger": "^0.4.0 || ^1.0.0", - "@vue/devtools-api": ">=7.6.2", - "nanostores": "^0.11.3 || ^1.0.0", - "vue": ">=3.3.1" - }, - "peerDependenciesMeta": { - "@nanostores/logger": { - "optional": true - }, - "@vue/devtools-api": { - "optional": true - } - } - }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-rc.2", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.2.tgz", @@ -1295,95 +1204,6 @@ "vite": "^5.2.0 || ^6 || ^7" } }, - "node_modules/@tanstack/match-sorter-utils": { - "version": "8.19.4", - "resolved": "https://registry.npmjs.org/@tanstack/match-sorter-utils/-/match-sorter-utils-8.19.4.tgz", - "integrity": "sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg==", - "license": "MIT", - "dependencies": { - "remove-accents": "0.5.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/query-core": { - "version": "5.90.20", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.20.tgz", - "integrity": "sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/vue-query": { - "version": "5.92.9", - "resolved": "https://registry.npmjs.org/@tanstack/vue-query/-/vue-query-5.92.9.tgz", - "integrity": "sha512-jjAZcqKveyX0C4w/6zUqbnqk/XzuxNWaFsWjGTJWULVFizUNeLGME2gf9vVSDclIyiBhR13oZJPPs6fJgfpIJQ==", - "license": "MIT", - "dependencies": { - "@tanstack/match-sorter-utils": "^8.19.4", - "@tanstack/query-core": "5.90.20", - "@vue/devtools-api": "^6.6.3", - "vue-demi": "^0.14.10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "@vue/composition-api": "^1.1.2", - "vue": "^2.6.0 || ^3.3.0" - }, - "peerDependenciesMeta": { - "@vue/composition-api": { - "optional": true - } - } - }, - "node_modules/@tanstack/vue-query/node_modules/@vue/devtools-api": { - "version": "6.6.4", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", - "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", - "license": "MIT" - }, - "node_modules/@tanstack/vue-query/node_modules/vue-demi": { - "version": "0.14.10", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", - "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "vue-demi-fix": "bin/vue-demi-fix.js", - "vue-demi-switch": "bin/vue-demi-switch.js" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "@vue/composition-api": "^1.0.0-rc.1", - "vue": "^3.0.0-0 || ^2.6.0" - }, - "peerDependenciesMeta": { - "@vue/composition-api": { - "optional": true - } - } - }, - "node_modules/@transloadit/prettier-bytes": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@transloadit/prettier-bytes/-/prettier-bytes-0.3.5.tgz", - "integrity": "sha512-xF4A3d/ZyX2LJWeQZREZQw+qFX4TGQ8bGVP97OLRt6sPO6T0TNHBFTuRHOJh7RNmYOBmQ9MHxpolD9bXihpuVA==", - "license": "MIT" - }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1401,166 +1221,6 @@ "undici-types": "~7.16.0" } }, - "node_modules/@types/retry": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", - "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", - "license": "MIT" - }, - "node_modules/@uppy/companion-client": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@uppy/companion-client/-/companion-client-5.1.1.tgz", - "integrity": "sha512-DzrOWTbIZHvtgAFXBMYHk2wD27NjpBSVhY2tEiEIUhPd2CxbFRZjHM/N3HOt3VwZEAP471QWFLlJRWPcIY3A2Q==", - "license": "MIT", - "dependencies": { - "@uppy/utils": "^7.1.1", - "namespace-emitter": "^2.0.1", - "p-retry": "^6.1.0" - }, - "peerDependencies": { - "@uppy/core": "^5.1.1" - } - }, - "node_modules/@uppy/components": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@uppy/components/-/components-1.2.0.tgz", - "integrity": "sha512-rtIr+77Rw/q5Vw++xazF1dCg2d4A4zT9CV+ZyN8Rsx8xiIr2CxCR4TaHHBy+WeC0b7Mk6yNuJ0wUa34tFJ6pKg==", - "license": "MIT", - "dependencies": { - "clsx": "^2.1.1", - "dequal": "^2.0.3", - "preact": "^10.26.10", - "pretty-bytes": "^6.1.1" - }, - "peerDependencies": { - "@uppy/core": "^5.2.0", - "@uppy/image-editor": "^4.2.0", - "@uppy/screen-capture": "^5.1.0", - "@uppy/webcam": "^5.1.0" - }, - "peerDependenciesMeta": { - "@uppy/image-editor": { - "optional": true - }, - "@uppy/screen-capture": { - "optional": true - }, - "@uppy/webcam": { - "optional": true - } - } - }, - "node_modules/@uppy/core": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@uppy/core/-/core-5.2.0.tgz", - "integrity": "sha512-uvfNyz4cnaplt7LYJmEZHuqOuav0tKp4a9WKJIaH6iIj7XiqYvS2J5SEByexAlUFlzefOAyjzj4Ja2dd/8aMrw==", - "license": "MIT", - "dependencies": { - "@transloadit/prettier-bytes": "^0.3.4", - "@uppy/store-default": "^5.0.0", - "@uppy/utils": "^7.1.4", - "lodash": "^4.17.21", - "mime-match": "^1.0.2", - "namespace-emitter": "^2.0.1", - "nanoid": "^5.0.9", - "preact": "^10.5.13" - } - }, - "node_modules/@uppy/core/node_modules/nanoid": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz", - "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.js" - }, - "engines": { - "node": "^18 || >=20" - } - }, - "node_modules/@uppy/locales": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@uppy/locales/-/locales-5.1.1.tgz", - "integrity": "sha512-zSbDU27JzfdssRJoa5/xmGOsrEtS+2Z9j41weaoCa/NoK4wqZzkFNQ0Z44etbTg3PDVFakZVDu/Z+c+vsJCfdQ==", - "license": "MIT", - "dependencies": { - "@uppy/utils": "^7.1.5" - } - }, - "node_modules/@uppy/store-default": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@uppy/store-default/-/store-default-5.0.0.tgz", - "integrity": "sha512-hQtCSQ1yGiaval/wVYUWquYGDJ+bpQ7e4FhUUAsRQz1x1K+o7NBtjfp63O9I4Ks1WRoKunpkarZ+as09l02cPw==", - "license": "MIT" - }, - "node_modules/@uppy/utils": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/@uppy/utils/-/utils-7.1.5.tgz", - "integrity": "sha512-Vz4WGTjef6WebECGur4clWjpkET4o3bdvPMj1m2sD5cL+dTt69m+FIE5h5JD3HBMLEPTXPVkrXGMIFcbOYC12Q==", - "license": "MIT", - "dependencies": { - "lodash": "^4.17.21", - "preact": "^10.5.13" - } - }, - "node_modules/@uppy/vue": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@uppy/vue/-/vue-3.2.0.tgz", - "integrity": "sha512-BZiyUZxpadf3uUp8YzgwRZTIde/m9Ne4ILFygJg7ilFq/Qfb1pBVspG9FJoG23RbOiRuxd4JixwFh0gaFdfL+w==", - "license": "MIT", - "dependencies": { - "@uppy/components": "^1.2.0", - "preact": "^10.26.10", - "shallow-equal": "^3.0.0" - }, - "peerDependencies": { - "@uppy/core": "^5.2.0", - "@uppy/dashboard": "^5.1.1", - "@uppy/screen-capture": "^5.1.0", - "@uppy/status-bar": "^5.1.0", - "@uppy/webcam": "^5.1.0", - "vue": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@uppy/dashboard": { - "optional": true - }, - "@uppy/screen-capture": { - "optional": true - }, - "@uppy/status-bar": { - "optional": true - }, - "@uppy/webcam": { - "optional": true - } - } - }, - "node_modules/@uppy/xhr-upload": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@uppy/xhr-upload/-/xhr-upload-5.1.1.tgz", - "integrity": "sha512-Vp0HWVA8o+niC2uISxPt0pZ+95bHHkk9HzNaUTrff/vq+20Ln68BS2auJhc9ecJzI6SKAlGZ342dcTQ/onw0nA==", - "license": "MIT", - "dependencies": { - "@uppy/companion-client": "^5.1.1", - "@uppy/utils": "^7.1.5" - }, - "peerDependencies": { - "@uppy/core": "^5.2.0" - } - }, - "node_modules/@viselect/vanilla": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/@viselect/vanilla/-/vanilla-3.9.0.tgz", - "integrity": "sha512-E9eBgoi/crJ0SlZMAc+Yst7nU324LZ5LLvcXjzWEcrfllscdpTml2OLOKHC7O8Bbz19OybSLv6VexxnjlJrLxQ==", - "license": "MIT" - }, "node_modules/@vitejs/plugin-vue": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.4.tgz", @@ -1877,21 +1537,6 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/classnames": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", - "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", - "license": "MIT" - }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/confbox": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", @@ -1919,27 +1564,12 @@ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, - "node_modules/debounce": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", - "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", - "license": "MIT" - }, "node_modules/defu": { "version": "6.1.4", "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", "license": "MIT" }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -1950,12 +1580,6 @@ "node": ">=8" } }, - "node_modules/easy-bem": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/easy-bem/-/easy-bem-1.1.1.tgz", - "integrity": "sha512-GJRqdiy2h+EXy6a8E6R+ubmqUM08BK0FWNq41k24fup6045biQ8NXxoXimiwegMQvFFV3t1emADdGNL1TlS61A==", - "license": "MIT" - }, "node_modules/echarts": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/echarts/-/echarts-6.0.0.tgz", @@ -2091,18 +1715,6 @@ "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", "license": "MIT" }, - "node_modules/is-network-error": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.0.tgz", - "integrity": "sha512-6oIwpsgRfnDiyEDLMay/GqCl3HoAtH5+RUKW29gYkL0QA+ipzpDLA16yQs7/RHCSu+BwgbJaOUqa4A99qNVQVw==", - "license": "MIT", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-what": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", @@ -2427,12 +2039,6 @@ "url": "https://github.com/sponsors/antfu" } }, - "node_modules/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", - "license": "MIT" - }, "node_modules/lucide-vue-next": { "version": "0.564.0", "resolved": "https://registry.npmjs.org/lucide-vue-next/-/lucide-vue-next-0.564.0.tgz", @@ -2466,15 +2072,6 @@ "url": "https://github.com/sponsors/sxzz" } }, - "node_modules/mime-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/mime-match/-/mime-match-1.0.2.tgz", - "integrity": "sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==", - "license": "ISC", - "dependencies": { - "wildcard": "^1.1.0" - } - }, "node_modules/mitt": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", @@ -2516,12 +2113,6 @@ "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", "license": "MIT" }, - "node_modules/namespace-emitter": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/namespace-emitter/-/namespace-emitter-2.0.1.tgz", - "integrity": "sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==", - "license": "MIT" - }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -2540,44 +2131,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/nanostores": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/nanostores/-/nanostores-1.1.0.tgz", - "integrity": "sha512-yJBmDJr18xy47dbNVlHcgdPrulSn1nhSE6Ns9vTG+Nx9VPT6iV1MD6aQFp/t52zpf82FhLLTXAXr30NuCnxvwA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "engines": { - "node": "^20.0.0 || >=22.0.0" - } - }, - "node_modules/overlayscrollbars": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/overlayscrollbars/-/overlayscrollbars-2.14.0.tgz", - "integrity": "sha512-RjV0pqc79kYhQLC3vTcLRb5GLpI1n6qh0Oua3g+bGH4EgNOJHVBGP7u0zZtxoAa0dkHlAqTTSYRb9MMmxNLjig==", - "license": "MIT" - }, - "node_modules/p-retry": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", - "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", - "license": "MIT", - "dependencies": { - "@types/retry": "0.12.2", - "is-network-error": "^1.0.0", - "retry": "^0.13.1" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", @@ -2700,28 +2253,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/preact": { - "version": "10.28.4", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.28.4.tgz", - "integrity": "sha512-uKFfOHWuSNpRFVTnljsCluEFq57OKT+0QdOiQo8XWnQ/pSvg7OpX5eNOejELXJMWy+BwM2nobz0FkvzmnpCNsQ==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/preact" - } - }, - "node_modules/pretty-bytes": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz", - "integrity": "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==", - "license": "MIT", - "engines": { - "node": "^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/quansync": { "version": "0.2.11", "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", @@ -2751,21 +2282,6 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/remove-accents": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz", - "integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==", - "license": "MIT" - }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, "node_modules/rfdc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", @@ -2823,12 +2339,6 @@ "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", "license": "MIT" }, - "node_modules/shallow-equal": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-3.1.0.tgz", - "integrity": "sha512-pfVOw8QZIXpMbhBWvzBISicvToTiM5WBF1EeAUZDDSb5Dt29yl4AYbyywbJFSEsRUMr7gJaxqCdr4L3tQf9wVg==", - "license": "MIT" - }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -2959,16 +2469,6 @@ "url": "https://github.com/sponsors/sxzz" } }, - "node_modules/vanilla-lazyload": { - "version": "19.1.3", - "resolved": "https://registry.npmjs.org/vanilla-lazyload/-/vanilla-lazyload-19.1.3.tgz", - "integrity": "sha512-bBMERPu2AFJc35krS+8BOhq++c6dRfL6q368lJPnkS5U92fRQagTR3FsNta69/GukfZzDwDEjD5M3U7VuSiCDw==", - "license": "MIT", - "funding": { - "type": "individual", - "url": "https://ko-fi.com/verlok" - } - }, "node_modules/vite": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", @@ -3072,24 +2572,6 @@ } } }, - "node_modules/vue-advanced-cropper": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/vue-advanced-cropper/-/vue-advanced-cropper-2.8.9.tgz", - "integrity": "sha512-1jc5gO674kVGpJKekoaol6ZlwaF5VYDLSBwBOUpViW0IOrrRsyLw6XNszjEqgbavvqinlKNS6Kqlom3B5M72Tw==", - "license": "MIT", - "dependencies": { - "classnames": "^2.2.6", - "debounce": "^1.2.0", - "easy-bem": "^1.0.2" - }, - "engines": { - "node": ">=8", - "npm": ">=5" - }, - "peerDependencies": { - "vue": "^3.0.0" - } - }, "node_modules/vue-router": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.0.2.tgz", @@ -3174,28 +2656,6 @@ "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==", "license": "MIT" }, - "node_modules/vue-sonner": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/vue-sonner/-/vue-sonner-2.0.9.tgz", - "integrity": "sha512-i6BokNlNDL93fpzNxN/LZSn6D6MzlO+i3qXt6iVZne3x1k7R46d5HlFB4P8tYydhgqOrRbIZEsnRd3kG7qGXyw==", - "license": "MIT", - "peerDependencies": { - "@nuxt/kit": "^4.0.3", - "@nuxt/schema": "^4.0.3", - "nuxt": "^4.0.3" - }, - "peerDependenciesMeta": { - "@nuxt/kit": { - "optional": true - }, - "@nuxt/schema": { - "optional": true - }, - "nuxt": { - "optional": true - } - } - }, "node_modules/vue-tsc": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.2.4.tgz", @@ -3213,57 +2673,12 @@ "typescript": ">=5.0.0" } }, - "node_modules/vuefinder": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/vuefinder/-/vuefinder-4.1.1.tgz", - "integrity": "sha512-sRrDj7+jrSN4CCQCkBDhc4Z3ZEP2CHa3HibPsByy/yEj2BVH6G7Fn9fSJ3IjGEivYTdURc6DbusidU6Rg6/SqQ==", - "license": "MIT", - "dependencies": { - "@floating-ui/dom": "^1.7.4", - "@nanostores/i18n": "^1.2.2", - "@nanostores/persistent": "^1.1.0", - "@nanostores/vue": "^1.0.1", - "@tanstack/vue-query": "^5.90.2", - "@uppy/core": "^5.0.2", - "@uppy/locales": "^5.0.1", - "@uppy/vue": "^3.1.0", - "@uppy/xhr-upload": "^5.0.1", - "@viselect/vanilla": "^3.9.0", - "mitt": "^3.0.1", - "nanostores": "^1.0.1", - "overlayscrollbars": "^2.12.0", - "vanilla-lazyload": "^19.1.3", - "vue-advanced-cropper": "^2.8.9", - "vue-sonner": "^2.0.9" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/n1crack" - }, - "peerDependencies": { - "vue": "^3.5.22" - }, - "peerDependenciesMeta": { - "vue": { - "optional": false - } - } - }, "node_modules/webpack-virtual-modules": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", "license": "MIT" }, - "node_modules/wildcard": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-1.1.2.tgz", - "integrity": "sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==", - "license": "MIT" - }, "node_modules/yaml": { "version": "2.8.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index b5a0e2d..829737b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,8 +14,7 @@ "pinia": "^3.0.4", "pinia-plugin-persistedstate": "^4.7.1", "vue": "^3.5.25", - "vue-router": "^5.0.2", - "vuefinder": "^4.1.1" + "vue-router": "^5.0.2" }, "devDependencies": { "@tailwindcss/vite": "^4.1.18", diff --git a/frontend/src/components/layout/DashboardLayout.vue b/frontend/src/components/layout/DashboardLayout.vue index 69fd86f..eb59b59 100644 --- a/frontend/src/components/layout/DashboardLayout.vue +++ b/frontend/src/components/layout/DashboardLayout.vue @@ -9,7 +9,6 @@ import { ref, computed, watch, onMounted } from 'vue' import { RouterView, useRoute, useRouter } from 'vue-router' import { useAuthStore } from '@/stores/auth' -import { useServerStore } from '@/stores/server' import { useFleetStore } from '@/stores/fleet' import { useThemeGame, syncActiveGameFromFleet } from '@/composables/useThemeGame' import { useGameProfile } from '@/config/gameProfiles' @@ -31,7 +30,6 @@ import type { ActiveGame } from '@/composables/useThemeGame' const route = useRoute() const router = useRouter() const auth = useAuthStore() -const server = useServerStore() const fleet = useFleetStore() const { theme, activeGame, setActiveGame, toggleTheme } = useThemeGame() @@ -106,32 +104,43 @@ function hasVisibleItems(section: NavSection): boolean { return section.items.some(canShowNavItem) } -// ---- Agent health ---- -const hasAgent = computed(() => server.connection !== null) +// ---- Agent health — driven by the fleet, not the legacy single connection ---- +// Real hosts only (the fleet response appends a synthetic '__unassigned__' +// bucket for orphaned instances; summary counts already exclude it). +const realHosts = computed(() => fleet.hosts.filter((h) => h.id !== '__unassigned__')) +const hostCount = computed(() => fleet.summary.host_count) +const onlineHosts = computed(() => fleet.summary.online_host_count) +const instanceCount = computed(() => fleet.summary.instance_count) + +const hasAgent = computed(() => hostCount.value > 0) const agentTone = computed(() => { - const cs = server.connection?.connection_status - if (cs === 'connected') return 'online' as const - if (cs === 'degraded') return 'warn' as const - return 'offline' as const + if (onlineHosts.value === 0) return 'offline' as const + if (onlineHosts.value < hostCount.value) return 'warn' as const + return 'online' as const }) const agentLabel = computed(() => { - const cs = server.connection?.connection_status - if (cs === 'connected') return 'Healthy' - if (cs === 'degraded') return 'Degraded' - return 'Offline' + if (onlineHosts.value === 0) return 'Offline' + if (onlineHosts.value < hostCount.value) return 'Degraded' + return 'Healthy' }) -const agentName = computed(() => server.connection?.server_ip ?? 'Host agent') +// One host → its hostname; multiple → fleet count. +const agentName = computed(() => + hostCount.value === 1 ? (realHosts.value[0]?.hostname ?? 'Host agent') : `${hostCount.value} hosts`, +) const agentMetaLine = computed(() => { - const cs = server.connection?.connection_status - let line = cs === 'connected' ? 'Connected' : server.connection?.companion_last_seen - ? `Last seen ${safeDate(server.connection.companion_last_seen)}` - : 'Awaiting first heartbeat' - if (server.stats) { - line += ` · ${server.stats.player_count}/${server.stats.max_players} players` + const insts = `${instanceCount.value} ${instanceCount.value === 1 ? 'instance' : 'instances'}` + if (hostCount.value === 1) { + const h = realHosts.value[0] + const state = h?.status === 'connected' + ? 'Connected' + : h?.last_heartbeat_at + ? `Last seen ${safeDate(h.last_heartbeat_at)}` + : 'Awaiting first heartbeat' + return `${state} · ${insts}` } - return line + return `${onlineHosts.value}/${hostCount.value} online · ${insts}` }) // ---- Topbar ---- diff --git a/frontend/src/main.ts b/frontend/src/main.ts index 4acb41b..ebbdfe0 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -2,12 +2,10 @@ import { createApp } from 'vue' import { createPinia } from 'pinia' import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' -import { VueFinderPlugin } from 'vuefinder' import App from './App.vue' import router from './router' import { initThemeGame } from './composables/useThemeGame' import './style.css' -import 'vuefinder/dist/vuefinder.css' const app = createApp(App) @@ -16,7 +14,6 @@ pinia.use(piniaPluginPersistedstate) app.use(pinia) app.use(router) -app.use(VueFinderPlugin) // Apply the design-system theming contract (data-theme/data-game on ). initThemeGame()