Compare commits

...
6 Commits
Author SHA1 Message Date
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
12 changed files with 553 additions and 19 deletions

No files matched your search

+3
View File
@@ -45,6 +45,8 @@ jobs:
run: | run: |
version=$(node -p "require('./package.json').version") version=$(node -p "require('./package.json').version")
echo "version=$version" >> "$GITHUB_OUTPUT" 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 if git ls-remote --exit-code --tags origin "refs/tags/v$version" >/dev/null 2>&1; then
echo "released=true" >> "$GITHUB_OUTPUT" echo "released=true" >> "$GITHUB_OUTPUT"
else else
@@ -55,6 +57,7 @@ jobs:
run: npx electron-builder --win --publish never run: npx electron-builder --win --publish never
env: env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BUILD_NUMBER: ${{ steps.ver.outputs.build }}
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
name: EveFlow-Windows-v${{ steps.ver.outputs.version }} name: EveFlow-Windows-v${{ steps.ver.outputs.version }}
+1 -1
View File
@@ -76,7 +76,7 @@ function createTray(): void {
try { try {
const iconPath = app.isPackaged const iconPath = app.isPackaged
? path.join(process.resourcesPath, 'icon.png') ? path.join(process.resourcesPath, 'icon.png')
: path.join(__dirname, '..', '..', 'build', 'icon.png'); : path.join(__dirname, '..', 'build', 'icon.png');
let image = nativeImage.createFromPath(iconPath); let image = nativeImage.createFromPath(iconPath);
if (image.isEmpty()) image = nativeImage.createEmpty(); if (image.isEmpty()) image = nativeImage.createEmpty();
else image = image.resize({ width: 16, height: 16 }); 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`); 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)) { if (fs.existsSync(builtIndex)) {
await win.loadFile(builtIndex); await win.loadFile(builtIndex);
return; return;
+485
View File
@@ -25,6 +25,7 @@
"cross-env": "^10.0.0", "cross-env": "^10.0.0",
"electron": "^44.1.1", "electron": "^44.1.1",
"electron-builder": "^26.15.3", "electron-builder": "^26.15.3",
"esbuild": "^0.28.2",
"jsdom": "^30.0.1", "jsdom": "^30.0.1",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"vite": "^8.2.2", "vite": "^8.2.2",
@@ -595,6 +596,448 @@
"dev": true, "dev": true,
"license": "MIT" "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": { "node_modules/@exodus/bytes": {
"version": "1.15.1", "version": "1.15.1",
"resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz", "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz",
@@ -3027,6 +3470,48 @@
"license": "MIT", "license": "MIT",
"optional": true "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": { "node_modules/escalade": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+6 -4
View File
@@ -1,22 +1,23 @@
{ {
"name": "eveflow", "name": "eveflow",
"version": "2.0.0", "version": "2.0.0.1",
"description": "JARVIS-style desktop HUD for Hermes Agent: voice, streaming runs, scheduled jobs, skills and telemetry", "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, "private": true,
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"dev": "vite --host 127.0.0.1 --port 5173 --strictPort", "dev": "vite --host 127.0.0.1 --port 5173 --strictPort",
"build": "npm run typecheck && npm run build:renderer && npm run build:electron", "build": "npm run typecheck && npm run build:renderer && npm run build:electron",
"build:renderer": "vite build", "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", "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.electron.json --noEmit",
"test": "vitest run", "test": "vitest run",
"test:watch": "vitest", "test:watch": "vitest",
"electron": "electron .", "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 .\"", "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", "preview": "vite preview",
"dist": "npm run build && electron-builder --win --publish never" "dist": "npm run build && electron-builder --win --publish never",
"typecheck:electron": "tsc -p tsconfig.electron.json --noEmit"
}, },
"build": { "build": {
"appId": "com.romik3.eveflow", "appId": "com.romik3.eveflow",
@@ -70,6 +71,7 @@
"cross-env": "^10.0.0", "cross-env": "^10.0.0",
"electron": "^44.1.1", "electron": "^44.1.1",
"electron-builder": "^26.15.3", "electron-builder": "^26.15.3",
"esbuild": "^0.28.2",
"jsdom": "^30.0.1", "jsdom": "^30.0.1",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"vite": "^8.2.2", "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'
});
+4
View File
@@ -36,6 +36,10 @@ function useBoot(): boolean {
void useHermes.getState().refreshWebhook(); void useHermes.getState().refreshWebhook();
const api = bridge(); 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) { if (api) {
disposers.push(api.hermes.onPush(handlePush)); disposers.push(api.hermes.onPush(handlePush));
disposers.push( disposers.push(
+3 -3
View File
@@ -28,11 +28,11 @@ export function Telemetry() {
<Activity size={14} /> <Activity size={14} />
<span>Système</span> <span>Système</span>
<span className="spacer" /> <span className="spacer" />
<span className="chip">{m.hostname}</span> <span className="chip">{m.live ? m.hostname : 'HORS PONT'}</span>
</header> </header>
<div className="telemetry"> <div className="telemetry">
<Gauge value={m.cpuLoad} max={100} label="CPU" display={`${Math.round(m.cpuLoad)}%`} warn={90} /> <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={`${Math.round(m.memUsedPct)}%`} warn={92} /> <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.fps} max={60} label="FPS" display={`${m.fps}`} />
<Gauge value={m.cpuFreqMhz} max={5500} label="GHz" display={m.cpuFreqMhz ? (m.cpuFreqMhz / 1000).toFixed(1) : '—'} /> <Gauge value={m.cpuFreqMhz} max={5500} label="GHz" display={m.cpuFreqMhz ? (m.cpuFreqMhz / 1000).toFixed(1) : '—'} />
</div> </div>
+8 -4
View File
@@ -60,11 +60,15 @@ export function SettingsDrawer({ onClose }: Props) {
let caps = ''; let caps = '';
try { try {
const c = await client.capabilities(); const c = await client.capabilities();
caps = ` · ${String(c.model ?? '')} · ${Object.entries(c.features ?? {}).filter(([, v]) => v === true).length} fonctions`; caps = ` · modèle ${String(c.model ?? '?')} · ${Object.entries(c.features ?? {}).filter(([, v]) => v === true).length} fonctions`;
} catch { } catch (err) {
caps = ' · capabilities indisponibles'; 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(); void hermesStore.connect();
} catch (err) { } catch (err) {
setHermesTest({ status: 'fail', message: (err as Error).message }); 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 { export interface LiveMetrics extends SystemMetrics {
fps: number; fps: number;
/** false until the main process delivered real measurements */
live: boolean;
} }
const EMPTY: LiveMetrics = { const EMPTY: LiveMetrics = {
@@ -16,7 +18,8 @@ const EMPTY: LiveMetrics = {
memUsedPct: 0, memUsedPct: 0,
memTotalGb: 0, memTotalGb: 0,
uptimeSec: 0, uptimeSec: 0,
fps: 60 fps: 60,
live: false
}; };
export function useMetrics(enabled = true, intervalMs = 2000): LiveMetrics { export function useMetrics(enabled = true, intervalMs = 2000): LiveMetrics {
@@ -43,7 +46,7 @@ export function useMetrics(enabled = true, intervalMs = 2000): LiveMetrics {
const api = bridge(); const api = bridge();
const poll = () => { const poll = () => {
if (!api) return; 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(); poll();
const timer = setInterval(poll, intervalMs); const timer = setInterval(poll, intervalMs);
+12 -3
View File
@@ -397,9 +397,10 @@ export class HermesClient {
}); });
let fullText = ''; let fullText = '';
let toolsAllowed = useTools;
for (let iteration = 0; iteration < 6 && !aborted; iteration++) { for (let iteration = 0; iteration < 6 && !aborted; iteration++) {
const payload: Rec = { model: this.config.model || 'hermes-agent', messages, stream: true }; const payload: Rec = { model: this.config.model || 'hermes-agent', messages, stream: true };
if (useTools) { if (toolsAllowed) {
payload.tools = options.localToolDefinitions; payload.tools = options.localToolDefinitions;
payload.tool_choice = 'auto'; payload.tool_choice = 'auto';
} }
@@ -435,7 +436,15 @@ export class HermesClient {
currentHandle = handle; currentHandle = handle;
if (!handle.start.ok) { if (!handle.start.ok) {
await handle.done.catch(() => undefined); 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; ready = true;
const rotated = handle.start.headers['x-hermes-session-id']; const rotated = handle.start.headers['x-hermes-session-id'];
@@ -445,7 +454,7 @@ export class HermesClient {
parser.end(); parser.end();
fullText += iterationText; fullText += iterationText;
if (finishReason === 'tool_calls' && useTools && toolCalls.size > 0 && !aborted) { if (finishReason === 'tool_calls' && toolsAllowed && toolCalls.size > 0 && !aborted) {
const calls = [...toolCalls.values()]; const calls = [...toolCalls.values()];
messages.push({ messages.push({
role: 'assistant', role: 'assistant',
+6 -1
View File
@@ -91,7 +91,12 @@ export const useHermes = create<HermesStore>((set, get) => ({
webhook: null, webhook: null,
busy: false, 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 () => { connect: async () => {
const config = useSettings.getState().settings.hermes; const config = useSettings.getState().settings.hermes;