Compare commits

..
8 Commits
Author SHA1 Message Date
LogiFlow af1e3d8aae build: numéro de release 2.0.0.1 injecté au packaging (#9)
build: numéro de release 2.0.0.1 injecté au packaging (electron-builder exige un semver)
2026-09-03 17:47:50 +02:00
Claude 2471add00b build: four-part releaseVersion (2.0.0.1) injected at packaging time
electron-builder refuses a non-semver package.json version, so the published
number lives in package.json releaseVersion and scripts/dist.mjs passes it as
extraMetadata.version (plus the hotfix digit as Windows build number). The
workflow tags and names the release from the same field.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Wn5VX9HNbJ7N54hR24u9Y
2026-09-03 15:47:32 +00:00
LogiFlow 35437e2d51 chore: version 2.0.0.1 et télémétrie sans fausses valeurs (#8)
chore: version 2.0.0.1 (schéma correctif à quatre chiffres) et télémétrie sans fausses valeurs
2026-09-03 17:43:37 +02:00
Claude e2c67a5770 chore: hotfix versioning 2.0.0.1 and honest telemetry placeholders when the bridge is missing
- Version numbers gain a fourth hotfix component (2.0.0.1); the workflow maps it to the
  Windows file build number.
- The system panel shows dashes instead of 0% until real measurements arrive from the
  main process.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Wn5VX9HNbJ7N54hR24u9Y
2026-09-03 15:43:19 +00:00
LogiFlow 050ae20773 fix: modèle Hermes par défaut et repli sans outils client (v2.0.2) (#7)
fix: modèle Hermes par défaut et repli sans outils client (v2.0.2)
2026-09-03 17:40:44 +02:00
Claude 2a471e11a4 fix: default Hermes model from /v1/models and retry chat completions without client tools on HTTP 400 (v2.0.2)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Wn5VX9HNbJ7N54hR24u9Y
2026-09-03 15:40:21 +00:00
LogiFlow b5357c5abd fix: charger le pont Electron dans l'application installée (v2.0.1) (#6)
fix: charger le pont Electron dans l'application installée (v2.0.1)
2026-09-03 17:38:58 +02:00
Claude c73114eb0d fix: bundle the Electron preload so the sandboxed bridge loads in packaged builds (v2.0.1)
The preload script imported ../shared/ipc at runtime; sandboxed preloads cannot
require local modules, so window.eveflow was never exposed in the installed app
and every request fell back to browser fetch (Failed to fetch, LOCALHOST metrics).
Main and preload are now bundled with esbuild into single files in dist-electron/.

Also: explicit error banner when the bridge is missing inside Electron, and a more
precise connection test message (transport path, capabilities status).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Wn5VX9HNbJ7N54hR24u9Y
2026-09-03 15:38:36 +00:00
14 changed files with 573 additions and 22 deletions

No files matched your search

+5 -2
View File
@@ -43,8 +43,10 @@ jobs:
id: ver
shell: bash
run: |
version=$(node -p "require('./package.json').version")
version=$(node -p "const p=require('./package.json'); p.releaseVersion || p.version")
echo "version=$version" >> "$GITHUB_OUTPUT"
# Fourth component (hotfix number, e.g. 2.0.0.1) becomes the Windows file build number.
echo "build=$(echo "$version" | cut -d. -f4)" >> "$GITHUB_OUTPUT"
if git ls-remote --exit-code --tags origin "refs/tags/v$version" >/dev/null 2>&1; then
echo "released=true" >> "$GITHUB_OUTPUT"
else
@@ -52,9 +54,10 @@ jobs:
fi
- run: npm run build
- name: Package Windows EXE
run: npx electron-builder --win --publish never
run: npm run dist -- --win --publish never
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BUILD_NUMBER: ${{ steps.ver.outputs.build }}
- uses: actions/upload-artifact@v4
with:
name: EveFlow-Windows-v${{ steps.ver.outputs.version }}
+2 -2
View File
@@ -96,13 +96,13 @@ npm run typecheck # renderer + main process
Sans Electron, `npm run dev` puis `http://127.0.0.1:5173/` (ou `?mode=compact`) permet de travailler l'interface dans un navigateur ; les appels réseau passent alors directement par `fetch` (CORS requis côté serveur).
## Packaging Windows
## Packaging Windows et versions
```bash
npm run dist
```
L'installateur NSIS est produit dans `out/`. Le workflow GitHub Actions construit l'exécutable sur chaque tag `v*`.
L'installateur NSIS est produit dans `out/`. Le numéro de version publié est `releaseVersion` dans `package.json` (quatre chiffres, ex. `2.0.0.1` : le quatrième chiffre sert aux petits correctifs). `version` reste la base à trois chiffres exigée par electron-builder. À chaque fusion sur master, le workflow GitHub Actions crée le tag et la release Windows si ce numéro n'a pas encore été publié.
---
+1 -1
View File
@@ -76,7 +76,7 @@ function createTray(): void {
try {
const iconPath = app.isPackaged
? path.join(process.resourcesPath, 'icon.png')
: path.join(__dirname, '..', '..', 'build', 'icon.png');
: path.join(__dirname, '..', 'build', 'icon.png');
let image = nativeImage.createFromPath(iconPath);
if (image.isEmpty()) image = nativeImage.createEmpty();
else image = image.resize({ width: 16, height: 16 });
+1 -1
View File
@@ -37,7 +37,7 @@ async function loadRenderer(win: BrowserWindow): Promise<void> {
log('WARN', 'window', `dev server unreachable (${(err as Error).message}), loading built bundle`);
}
}
const builtIndex = path.join(__dirname, '..', '..', 'dist', 'index.html');
const builtIndex = path.join(__dirname, '..', 'dist', 'index.html');
if (fs.existsSync(builtIndex)) {
await win.loadFile(builtIndex);
return;
+485
View File
@@ -25,6 +25,7 @@
"cross-env": "^10.0.0",
"electron": "^44.1.1",
"electron-builder": "^26.15.3",
"esbuild": "^0.28.2",
"jsdom": "^30.0.1",
"typescript": "^5.9.3",
"vite": "^8.2.2",
@@ -595,6 +596,448 @@
"dev": true,
"license": "MIT"
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz",
"integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz",
"integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz",
"integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz",
"integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz",
"integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz",
"integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz",
"integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz",
"integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz",
"integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz",
"integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz",
"integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz",
"integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz",
"integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz",
"integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz",
"integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz",
"integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz",
"integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz",
"integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz",
"integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz",
"integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz",
"integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openharmony-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz",
"integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openharmony"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz",
"integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz",
"integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz",
"integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz",
"integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@exodus/bytes": {
"version": "1.15.1",
"resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz",
@@ -3027,6 +3470,48 @@
"license": "MIT",
"optional": true
},
"node_modules/esbuild": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz",
"integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.28.2",
"@esbuild/android-arm": "0.28.2",
"@esbuild/android-arm64": "0.28.2",
"@esbuild/android-x64": "0.28.2",
"@esbuild/darwin-arm64": "0.28.2",
"@esbuild/darwin-x64": "0.28.2",
"@esbuild/freebsd-arm64": "0.28.2",
"@esbuild/freebsd-x64": "0.28.2",
"@esbuild/linux-arm": "0.28.2",
"@esbuild/linux-arm64": "0.28.2",
"@esbuild/linux-ia32": "0.28.2",
"@esbuild/linux-loong64": "0.28.2",
"@esbuild/linux-mips64el": "0.28.2",
"@esbuild/linux-ppc64": "0.28.2",
"@esbuild/linux-riscv64": "0.28.2",
"@esbuild/linux-s390x": "0.28.2",
"@esbuild/linux-x64": "0.28.2",
"@esbuild/netbsd-arm64": "0.28.2",
"@esbuild/netbsd-x64": "0.28.2",
"@esbuild/openbsd-arm64": "0.28.2",
"@esbuild/openbsd-x64": "0.28.2",
"@esbuild/openharmony-arm64": "0.28.2",
"@esbuild/sunos-x64": "0.28.2",
"@esbuild/win32-arm64": "0.28.2",
"@esbuild/win32-ia32": "0.28.2",
"@esbuild/win32-x64": "0.28.2"
}
},
"node_modules/escalade": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+6 -3
View File
@@ -1,22 +1,24 @@
{
"name": "eveflow",
"version": "2.0.0",
"releaseVersion": "2.0.0.1",
"description": "JARVIS-style desktop HUD for Hermes Agent: voice, streaming runs, scheduled jobs, skills and telemetry",
"main": "dist-electron/electron/main.js",
"main": "dist-electron/main.js",
"private": true,
"license": "MIT",
"scripts": {
"dev": "vite --host 127.0.0.1 --port 5173 --strictPort",
"build": "npm run typecheck && npm run build:renderer && npm run build:electron",
"build:renderer": "vite build",
"build:electron": "tsc -p tsconfig.electron.json",
"build:electron": "node scripts/build-electron.mjs",
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.electron.json --noEmit",
"test": "vitest run",
"test:watch": "vitest",
"electron": "electron .",
"start": "npm run build:electron && concurrently -k -s first \"npm run dev\" \"wait-on http://127.0.0.1:5173 && cross-env NODE_ENV=development VITE_DEV_SERVER_URL=http://127.0.0.1:5173 electron .\"",
"preview": "vite preview",
"dist": "npm run build && electron-builder --win --publish never"
"dist": "node scripts/dist.mjs",
"typecheck:electron": "tsc -p tsconfig.electron.json --noEmit"
},
"build": {
"appId": "com.romik3.eveflow",
@@ -70,6 +72,7 @@
"cross-env": "^10.0.0",
"electron": "^44.1.1",
"electron-builder": "^26.15.3",
"esbuild": "^0.28.2",
"jsdom": "^30.0.1",
"typescript": "^5.9.3",
"vite": "^8.2.2",
+19
View File
@@ -0,0 +1,19 @@
// Bundles the Electron main and preload scripts into single CommonJS files.
// The preload runs in a sandboxed renderer where `require()` of local modules is forbidden,
// so everything it imports must be inlined.
import { build } from 'esbuild';
import { rmSync } from 'node:fs';
rmSync('dist-electron', { recursive: true, force: true });
await build({
entryPoints: ['electron/main.ts', 'electron/preload.ts'],
outdir: 'dist-electron',
bundle: true,
platform: 'node',
format: 'cjs',
target: 'node22',
external: ['electron'],
sourcemap: false,
logLevel: 'info'
});
+16
View File
@@ -0,0 +1,16 @@
// Packages the app with electron-builder using the four-part release version
// (package.json "releaseVersion", e.g. 2.0.0.1). package.json "version" must stay semver.
import { spawnSync } from 'node:child_process';
import { readFileSync } from 'node:fs';
const pkg = JSON.parse(readFileSync('package.json', 'utf8'));
const release = pkg.releaseVersion || pkg.version;
const build = release.split('.')[3] ?? '0';
const args = process.argv.slice(2);
if (!args.some((a) => a.startsWith('--win') || a.startsWith('--linux') || a.startsWith('--mac'))) args.unshift('--win');
const result = spawnSync('npx', ['electron-builder', ...args, `--config.extraMetadata.version=${release}`], {
stdio: 'inherit',
shell: process.platform === 'win32',
env: { ...process.env, BUILD_NUMBER: process.env.BUILD_NUMBER ?? build }
});
process.exit(result.status ?? 1);
+4
View File
@@ -36,6 +36,10 @@ function useBoot(): boolean {
void useHermes.getState().refreshWebhook();
const api = bridge();
if (!api && /Electron/i.test(navigator.userAgent)) {
useChat.getState().setError("Pont Electron indisponible : le script preload n'a pas été chargé. Réinstallez EveFlow ou consultez eveflow.log.");
Log.error('app', 'window.eveflow missing inside Electron');
}
if (api) {
disposers.push(api.hermes.onPush(handlePush));
disposers.push(
+3 -3
View File
@@ -28,11 +28,11 @@ export function Telemetry() {
<Activity size={14} />
<span>Système</span>
<span className="spacer" />
<span className="chip">{m.hostname}</span>
<span className="chip">{m.live ? m.hostname : 'HORS PONT'}</span>
</header>
<div className="telemetry">
<Gauge value={m.cpuLoad} max={100} label="CPU" display={`${Math.round(m.cpuLoad)}%`} warn={90} />
<Gauge value={m.memUsedPct} max={100} label="RAM" display={`${Math.round(m.memUsedPct)}%`} warn={92} />
<Gauge value={m.cpuLoad} max={100} label="CPU" display={m.live ? `${Math.round(m.cpuLoad)}%` : '—'} warn={90} />
<Gauge value={m.memUsedPct} max={100} label="RAM" display={m.live ? `${Math.round(m.memUsedPct)}%` : '—'} warn={92} />
<Gauge value={m.fps} max={60} label="FPS" display={`${m.fps}`} />
<Gauge value={m.cpuFreqMhz} max={5500} label="GHz" display={m.cpuFreqMhz ? (m.cpuFreqMhz / 1000).toFixed(1) : '—'} />
</div>
+8 -4
View File
@@ -60,11 +60,15 @@ export function SettingsDrawer({ onClose }: Props) {
let caps = '';
try {
const c = await client.capabilities();
caps = ` · ${String(c.model ?? '')} · ${Object.entries(c.features ?? {}).filter(([, v]) => v === true).length} fonctions`;
} catch {
caps = ' · capabilities indisponibles';
caps = ` · modèle ${String(c.model ?? '?')} · ${Object.entries(c.features ?? {}).filter(([, v]) => v === true).length} fonctions`;
} catch (err) {
const message = (err as Error).message;
caps = /404/.test(message)
? ' · /v1/capabilities absent (Hermes ancien : transport chat completions)'
: ` · capabilities : ${message}`;
}
setHermesTest({ status: 'ok', message: `${health.status}${caps}` });
const via = bridge() ? 'via Electron' : 'via navigateur';
setHermesTest({ status: 'ok', message: `${health.status} (${via})${caps}` });
void hermesStore.connect();
} catch (err) {
setHermesTest({ status: 'fail', message: (err as Error).message });
+5 -2
View File
@@ -4,6 +4,8 @@ import { bridge } from '../lib/bridge';
export interface LiveMetrics extends SystemMetrics {
fps: number;
/** false until the main process delivered real measurements */
live: boolean;
}
const EMPTY: LiveMetrics = {
@@ -16,7 +18,8 @@ const EMPTY: LiveMetrics = {
memUsedPct: 0,
memTotalGb: 0,
uptimeSec: 0,
fps: 60
fps: 60,
live: false
};
export function useMetrics(enabled = true, intervalMs = 2000): LiveMetrics {
@@ -43,7 +46,7 @@ export function useMetrics(enabled = true, intervalMs = 2000): LiveMetrics {
const api = bridge();
const poll = () => {
if (!api) return;
api.system.metrics().then((m) => setMetrics((prev) => ({ ...prev, ...m }))).catch(() => undefined);
api.system.metrics().then((m) => setMetrics((prev) => ({ ...prev, ...m, live: true }))).catch(() => undefined);
};
poll();
const timer = setInterval(poll, intervalMs);
+12 -3
View File
@@ -397,9 +397,10 @@ export class HermesClient {
});
let fullText = '';
let toolsAllowed = useTools;
for (let iteration = 0; iteration < 6 && !aborted; iteration++) {
const payload: Rec = { model: this.config.model || 'hermes-agent', messages, stream: true };
if (useTools) {
if (toolsAllowed) {
payload.tools = options.localToolDefinitions;
payload.tool_choice = 'auto';
}
@@ -435,7 +436,15 @@ export class HermesClient {
currentHandle = handle;
if (!handle.start.ok) {
await handle.done.catch(() => undefined);
throw new HttpError(handle.start.status, errorMessage(handle.start.status, errorChunks.join('')));
const detail = errorMessage(handle.start.status, errorChunks.join(''));
// Some Hermes builds reject client-side tool definitions: retry once without them.
if (toolsAllowed && handle.start.status === 400 && iteration === 0) {
Log.warn('hermes', `chat completions rejected the tools payload (${detail}); retrying without local tools`);
toolsAllowed = false;
iteration--;
continue;
}
throw new HttpError(handle.start.status, detail);
}
ready = true;
const rotated = handle.start.headers['x-hermes-session-id'];
@@ -445,7 +454,7 @@ export class HermesClient {
parser.end();
fullText += iterationText;
if (finishReason === 'tool_calls' && useTools && toolCalls.size > 0 && !aborted) {
if (finishReason === 'tool_calls' && toolsAllowed && toolCalls.size > 0 && !aborted) {
const calls = [...toolCalls.values()];
messages.push({
role: 'assistant',
+6 -1
View File
@@ -91,7 +91,12 @@ export const useHermes = create<HermesStore>((set, get) => ({
webhook: null,
busy: false,
client: () => new HermesClient(useSettings.getState().settings.hermes),
client: () => {
const config = useSettings.getState().settings.hermes;
// Without an explicit model, use the alias advertised by /v1/models (Hermes rejects unknown names).
const model = config.model.trim() || get().models[0]?.id || '';
return new HermesClient({ ...config, model });
},
connect: async () => {
const config = useSettings.getState().settings.hermes;