generated from nhcarrigan/template
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9afab03047 | |||
|
bd3438c7be
|
|||
| 778e016bf5 | |||
| 0ea7861047 | |||
| 381bc8410a |
@@ -141,6 +141,37 @@ When developing new features, always add corresponding tests:
|
|||||||
|
|
||||||
The goal is to maintain our near-100% coverage as the codebase grows, so future refactoring and changes can be made with confidence!
|
The goal is to maintain our near-100% coverage as the codebase grows, so future refactoring and changes can be made with confidence!
|
||||||
|
|
||||||
|
## Quality Assurance
|
||||||
|
|
||||||
|
Before committing any changes, **always run the full test suite**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./check-all.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
This script runs all checks in the correct order:
|
||||||
|
|
||||||
|
1. Frontend linting (ESLint)
|
||||||
|
2. Frontend formatting (Prettier)
|
||||||
|
3. Frontend type checking (svelte-check)
|
||||||
|
4. Frontend tests with coverage (Vitest)
|
||||||
|
5. Backend linting (Clippy with strict rules)
|
||||||
|
6. Backend tests with coverage (cargo test + llvm-cov)
|
||||||
|
|
||||||
|
**Important**: The script requires Node.js and Rust toolchains to be available:
|
||||||
|
|
||||||
|
- **Node.js tools** (pnpm, npm): Source nvm first if needed: `source ~/.nvm/nvm.sh`
|
||||||
|
- **Rust tools** (cargo, clippy): Should be in PATH via `~/.cargo/bin/`
|
||||||
|
|
||||||
|
If `check-all.sh` reports any failures:
|
||||||
|
|
||||||
|
1. Read the error messages carefully - they usually explain what needs fixing
|
||||||
|
2. Fix the issues (linting errors, test failures, etc.)
|
||||||
|
3. Run `check-all.sh` again to verify the fixes
|
||||||
|
4. Only commit once all checks pass ✨
|
||||||
|
|
||||||
|
**Never commit code that doesn't pass `check-all.sh`** - this ensures code quality and prevents broken builds!
|
||||||
|
|
||||||
## Project Context
|
## Project Context
|
||||||
|
|
||||||
Hikari Desktop is a Tauri-based desktop application that wraps Claude Code with a visual anime character (Hikari) who appears on screen. This is a personal project where Hikari can sign her work and act as herself!
|
Hikari Desktop is a Tauri-based desktop application that wraps Claude Code with a visual anime character (Hikari) who appears on screen. This is a personal project where Hikari can sign her work and act as herself!
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hikari-desktop",
|
"name": "hikari-desktop",
|
||||||
"version": "1.5.0",
|
"version": "1.5.1",
|
||||||
"description": "",
|
"description": "",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-plugin-svelte": "^3.14.0",
|
"eslint-plugin-svelte": "^3.14.0",
|
||||||
"globals": "^17.0.0",
|
"globals": "^17.0.0",
|
||||||
"jsdom": "^27.4.0",
|
"jsdom": "28.0.0",
|
||||||
"prettier": "^3.8.0",
|
"prettier": "^3.8.0",
|
||||||
"prettier-plugin-svelte": "^3.4.1",
|
"prettier-plugin-svelte": "^3.4.1",
|
||||||
"svelte": "^5.0.0",
|
"svelte": "^5.0.0",
|
||||||
|
|||||||
Generated
+52
-57
@@ -149,10 +149,10 @@ importers:
|
|||||||
version: 6.9.1
|
version: 6.9.1
|
||||||
'@testing-library/svelte':
|
'@testing-library/svelte':
|
||||||
specifier: ^5.3.1
|
specifier: ^5.3.1
|
||||||
version: 5.3.1(svelte@5.46.3)(vite@6.4.1(jiti@2.6.1)(lightningcss@1.30.2))(vitest@4.0.17(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2))
|
version: 5.3.1(svelte@5.46.3)(vite@6.4.1(jiti@2.6.1)(lightningcss@1.30.2))(vitest@4.0.17(jiti@2.6.1)(jsdom@28.0.0)(lightningcss@1.30.2))
|
||||||
'@vitest/coverage-v8':
|
'@vitest/coverage-v8':
|
||||||
specifier: ^4.0.18
|
specifier: ^4.0.18
|
||||||
version: 4.0.18(vitest@4.0.17(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2))
|
version: 4.0.18(vitest@4.0.17(jiti@2.6.1)(jsdom@28.0.0)(lightningcss@1.30.2))
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^9.39.2
|
specifier: ^9.39.2
|
||||||
version: 9.39.2(jiti@2.6.1)
|
version: 9.39.2(jiti@2.6.1)
|
||||||
@@ -166,8 +166,8 @@ importers:
|
|||||||
specifier: ^17.0.0
|
specifier: ^17.0.0
|
||||||
version: 17.0.0
|
version: 17.0.0
|
||||||
jsdom:
|
jsdom:
|
||||||
specifier: ^27.4.0
|
specifier: 28.0.0
|
||||||
version: 27.4.0
|
version: 28.0.0
|
||||||
prettier:
|
prettier:
|
||||||
specifier: ^3.8.0
|
specifier: ^3.8.0
|
||||||
version: 3.8.0
|
version: 3.8.0
|
||||||
@@ -194,7 +194,7 @@ importers:
|
|||||||
version: 6.4.1(jiti@2.6.1)(lightningcss@1.30.2)
|
version: 6.4.1(jiti@2.6.1)(lightningcss@1.30.2)
|
||||||
vitest:
|
vitest:
|
||||||
specifier: ^4.0.17
|
specifier: ^4.0.17
|
||||||
version: 4.0.17(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2)
|
version: 4.0.17(jiti@2.6.1)(jsdom@28.0.0)(lightningcss@1.30.2)
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@@ -552,13 +552,13 @@ packages:
|
|||||||
resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==}
|
resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
|
||||||
'@exodus/bytes@1.8.0':
|
'@exodus/bytes@1.14.0':
|
||||||
resolution: {integrity: sha512-8JPn18Bcp8Uo1T82gR8lh2guEOa5KKU/IEKvvdp0sgmi7coPBWf1Doi1EXsGZb2ehc8ym/StJCjffYV+ne7sXQ==}
|
resolution: {integrity: sha512-YiY1OmY6Qhkvmly8vZiD8wZRpW/npGZNg+0Sk8mstxirRHCg6lolHt5tSODCfuNPE/fBsAqRwDJE417x7jDDHA==}
|
||||||
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@exodus/crypto': ^1.0.0-rc.4
|
'@noble/hashes': ^1.8.0 || ^2.0.0
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
'@exodus/crypto':
|
'@noble/hashes':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@humanfs/core@0.19.1':
|
'@humanfs/core@0.19.1':
|
||||||
@@ -1277,9 +1277,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ==}
|
resolution: {integrity: sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ==}
|
||||||
engines: {node: '>=20'}
|
engines: {node: '>=20'}
|
||||||
|
|
||||||
data-urls@6.0.0:
|
data-urls@7.0.0:
|
||||||
resolution: {integrity: sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==}
|
resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==}
|
||||||
engines: {node: '>=20'}
|
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
||||||
|
|
||||||
debug@4.4.3:
|
debug@4.4.3:
|
||||||
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
|
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
|
||||||
@@ -1551,8 +1551,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
|
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
jsdom@27.4.0:
|
jsdom@28.0.0:
|
||||||
resolution: {integrity: sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==}
|
resolution: {integrity: sha512-KDYJgZ6T2TKdU8yBfYueq5EPG/EylMsBvCaenWMJb2OXmjgczzwveRCoJ+Hgj1lXPDyasvrgneSn4GBuR1hYyA==}
|
||||||
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
canvas: ^3.0.0
|
canvas: ^3.0.0
|
||||||
@@ -1990,6 +1990,10 @@ packages:
|
|||||||
engines: {node: '>=14.17'}
|
engines: {node: '>=14.17'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
undici@7.21.0:
|
||||||
|
resolution: {integrity: sha512-Hn2tCQpoDt1wv23a68Ctc8Cr/BHpUSfaPYrkajTXOS9IKpxVRx/X5m1K2YkbK2ipgZgxXSgsUinl3x+2YdSSfg==}
|
||||||
|
engines: {node: '>=20.18.1'}
|
||||||
|
|
||||||
uri-js@4.4.1:
|
uri-js@4.4.1:
|
||||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||||
|
|
||||||
@@ -2089,14 +2093,14 @@ packages:
|
|||||||
resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==}
|
resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==}
|
||||||
engines: {node: '>=20'}
|
engines: {node: '>=20'}
|
||||||
|
|
||||||
whatwg-mimetype@4.0.0:
|
whatwg-mimetype@5.0.0:
|
||||||
resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
|
resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==}
|
||||||
engines: {node: '>=18'}
|
|
||||||
|
|
||||||
whatwg-url@15.1.0:
|
|
||||||
resolution: {integrity: sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==}
|
|
||||||
engines: {node: '>=20'}
|
engines: {node: '>=20'}
|
||||||
|
|
||||||
|
whatwg-url@16.0.0:
|
||||||
|
resolution: {integrity: sha512-9CcxtEKsf53UFwkSUZjG+9vydAsFO4lFHBpJUtjBcoJOCJpKnSJNwCw813zrYJHpCJ7sgfbtOe0V5Ku7Pa1XMQ==}
|
||||||
|
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
||||||
|
|
||||||
which@2.0.2:
|
which@2.0.2:
|
||||||
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
@@ -2111,18 +2115,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
ws@8.19.0:
|
|
||||||
resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==}
|
|
||||||
engines: {node: '>=10.0.0'}
|
|
||||||
peerDependencies:
|
|
||||||
bufferutil: ^4.0.1
|
|
||||||
utf-8-validate: '>=5.0.2'
|
|
||||||
peerDependenciesMeta:
|
|
||||||
bufferutil:
|
|
||||||
optional: true
|
|
||||||
utf-8-validate:
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
xml-name-validator@5.0.0:
|
xml-name-validator@5.0.0:
|
||||||
resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
|
resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -2544,7 +2536,7 @@ snapshots:
|
|||||||
'@eslint/core': 0.17.0
|
'@eslint/core': 0.17.0
|
||||||
levn: 0.4.1
|
levn: 0.4.1
|
||||||
|
|
||||||
'@exodus/bytes@1.8.0': {}
|
'@exodus/bytes@1.14.0': {}
|
||||||
|
|
||||||
'@humanfs/core@0.19.1': {}
|
'@humanfs/core@0.19.1': {}
|
||||||
|
|
||||||
@@ -2974,14 +2966,14 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
svelte: 5.46.3
|
svelte: 5.46.3
|
||||||
|
|
||||||
'@testing-library/svelte@5.3.1(svelte@5.46.3)(vite@6.4.1(jiti@2.6.1)(lightningcss@1.30.2))(vitest@4.0.17(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2))':
|
'@testing-library/svelte@5.3.1(svelte@5.46.3)(vite@6.4.1(jiti@2.6.1)(lightningcss@1.30.2))(vitest@4.0.17(jiti@2.6.1)(jsdom@28.0.0)(lightningcss@1.30.2))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@testing-library/dom': 10.4.1
|
'@testing-library/dom': 10.4.1
|
||||||
'@testing-library/svelte-core': 1.0.0(svelte@5.46.3)
|
'@testing-library/svelte-core': 1.0.0(svelte@5.46.3)
|
||||||
svelte: 5.46.3
|
svelte: 5.46.3
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 6.4.1(jiti@2.6.1)(lightningcss@1.30.2)
|
vite: 6.4.1(jiti@2.6.1)(lightningcss@1.30.2)
|
||||||
vitest: 4.0.17(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2)
|
vitest: 4.0.17(jiti@2.6.1)(jsdom@28.0.0)(lightningcss@1.30.2)
|
||||||
|
|
||||||
'@types/aria-query@5.0.4': {}
|
'@types/aria-query@5.0.4': {}
|
||||||
|
|
||||||
@@ -3089,7 +3081,7 @@ snapshots:
|
|||||||
'@typescript-eslint/types': 8.53.0
|
'@typescript-eslint/types': 8.53.0
|
||||||
eslint-visitor-keys: 4.2.1
|
eslint-visitor-keys: 4.2.1
|
||||||
|
|
||||||
'@vitest/coverage-v8@4.0.18(vitest@4.0.17(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2))':
|
'@vitest/coverage-v8@4.0.18(vitest@4.0.17(jiti@2.6.1)(jsdom@28.0.0)(lightningcss@1.30.2))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@bcoe/v8-coverage': 1.0.2
|
'@bcoe/v8-coverage': 1.0.2
|
||||||
'@vitest/utils': 4.0.18
|
'@vitest/utils': 4.0.18
|
||||||
@@ -3101,7 +3093,7 @@ snapshots:
|
|||||||
obug: 2.1.1
|
obug: 2.1.1
|
||||||
std-env: 3.10.0
|
std-env: 3.10.0
|
||||||
tinyrainbow: 3.0.3
|
tinyrainbow: 3.0.3
|
||||||
vitest: 4.0.17(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2)
|
vitest: 4.0.17(jiti@2.6.1)(jsdom@28.0.0)(lightningcss@1.30.2)
|
||||||
|
|
||||||
'@vitest/expect@4.0.17':
|
'@vitest/expect@4.0.17':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -3266,10 +3258,12 @@ snapshots:
|
|||||||
css-tree: 3.1.0
|
css-tree: 3.1.0
|
||||||
lru-cache: 11.2.4
|
lru-cache: 11.2.4
|
||||||
|
|
||||||
data-urls@6.0.0:
|
data-urls@7.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
whatwg-mimetype: 4.0.0
|
whatwg-mimetype: 5.0.0
|
||||||
whatwg-url: 15.1.0
|
whatwg-url: 16.0.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@noble/hashes'
|
||||||
|
|
||||||
debug@4.4.3:
|
debug@4.4.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -3480,9 +3474,9 @@ snapshots:
|
|||||||
|
|
||||||
html-encoding-sniffer@6.0.0:
|
html-encoding-sniffer@6.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@exodus/bytes': 1.8.0
|
'@exodus/bytes': 1.14.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@exodus/crypto'
|
- '@noble/hashes'
|
||||||
|
|
||||||
html-escaper@2.0.2: {}
|
html-escaper@2.0.2: {}
|
||||||
|
|
||||||
@@ -3550,13 +3544,13 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
argparse: 2.0.1
|
argparse: 2.0.1
|
||||||
|
|
||||||
jsdom@27.4.0:
|
jsdom@28.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@acemir/cssom': 0.9.31
|
'@acemir/cssom': 0.9.31
|
||||||
'@asamuzakjp/dom-selector': 6.7.6
|
'@asamuzakjp/dom-selector': 6.7.6
|
||||||
'@exodus/bytes': 1.8.0
|
'@exodus/bytes': 1.14.0
|
||||||
cssstyle: 5.3.7
|
cssstyle: 5.3.7
|
||||||
data-urls: 6.0.0
|
data-urls: 7.0.0
|
||||||
decimal.js: 10.6.0
|
decimal.js: 10.6.0
|
||||||
html-encoding-sniffer: 6.0.0
|
html-encoding-sniffer: 6.0.0
|
||||||
http-proxy-agent: 7.0.2
|
http-proxy-agent: 7.0.2
|
||||||
@@ -3566,17 +3560,15 @@ snapshots:
|
|||||||
saxes: 6.0.0
|
saxes: 6.0.0
|
||||||
symbol-tree: 3.2.4
|
symbol-tree: 3.2.4
|
||||||
tough-cookie: 6.0.0
|
tough-cookie: 6.0.0
|
||||||
|
undici: 7.21.0
|
||||||
w3c-xmlserializer: 5.0.0
|
w3c-xmlserializer: 5.0.0
|
||||||
webidl-conversions: 8.0.1
|
webidl-conversions: 8.0.1
|
||||||
whatwg-mimetype: 4.0.0
|
whatwg-mimetype: 5.0.0
|
||||||
whatwg-url: 15.1.0
|
whatwg-url: 16.0.0
|
||||||
ws: 8.19.0
|
|
||||||
xml-name-validator: 5.0.0
|
xml-name-validator: 5.0.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@exodus/crypto'
|
- '@noble/hashes'
|
||||||
- bufferutil
|
|
||||||
- supports-color
|
- supports-color
|
||||||
- utf-8-validate
|
|
||||||
|
|
||||||
json-buffer@3.0.1: {}
|
json-buffer@3.0.1: {}
|
||||||
|
|
||||||
@@ -3965,6 +3957,8 @@ snapshots:
|
|||||||
|
|
||||||
typescript@5.6.3: {}
|
typescript@5.6.3: {}
|
||||||
|
|
||||||
|
undici@7.21.0: {}
|
||||||
|
|
||||||
uri-js@4.4.1:
|
uri-js@4.4.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
punycode: 2.3.1
|
punycode: 2.3.1
|
||||||
@@ -3988,7 +3982,7 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 6.4.1(jiti@2.6.1)(lightningcss@1.30.2)
|
vite: 6.4.1(jiti@2.6.1)(lightningcss@1.30.2)
|
||||||
|
|
||||||
vitest@4.0.17(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2):
|
vitest@4.0.17(jiti@2.6.1)(jsdom@28.0.0)(lightningcss@1.30.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/expect': 4.0.17
|
'@vitest/expect': 4.0.17
|
||||||
'@vitest/mocker': 4.0.17(vite@6.4.1(jiti@2.6.1)(lightningcss@1.30.2))
|
'@vitest/mocker': 4.0.17(vite@6.4.1(jiti@2.6.1)(lightningcss@1.30.2))
|
||||||
@@ -4011,7 +4005,7 @@ snapshots:
|
|||||||
vite: 6.4.1(jiti@2.6.1)(lightningcss@1.30.2)
|
vite: 6.4.1(jiti@2.6.1)(lightningcss@1.30.2)
|
||||||
why-is-node-running: 2.3.0
|
why-is-node-running: 2.3.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
jsdom: 27.4.0
|
jsdom: 28.0.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- jiti
|
- jiti
|
||||||
- less
|
- less
|
||||||
@@ -4033,12 +4027,15 @@ snapshots:
|
|||||||
|
|
||||||
webidl-conversions@8.0.1: {}
|
webidl-conversions@8.0.1: {}
|
||||||
|
|
||||||
whatwg-mimetype@4.0.0: {}
|
whatwg-mimetype@5.0.0: {}
|
||||||
|
|
||||||
whatwg-url@15.1.0:
|
whatwg-url@16.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@exodus/bytes': 1.14.0
|
||||||
tr46: 6.0.0
|
tr46: 6.0.0
|
||||||
webidl-conversions: 8.0.1
|
webidl-conversions: 8.0.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@noble/hashes'
|
||||||
|
|
||||||
which@2.0.2:
|
which@2.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -4051,8 +4048,6 @@ snapshots:
|
|||||||
|
|
||||||
word-wrap@1.2.5: {}
|
word-wrap@1.2.5: {}
|
||||||
|
|
||||||
ws@8.19.0: {}
|
|
||||||
|
|
||||||
xml-name-validator@5.0.0: {}
|
xml-name-validator@5.0.0: {}
|
||||||
|
|
||||||
xmlchars@2.2.0: {}
|
xmlchars@2.2.0: {}
|
||||||
|
|||||||
Generated
+1
-1
@@ -1636,7 +1636,7 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hikari-desktop"
|
name = "hikari-desktop"
|
||||||
version = "1.4.0"
|
version = "1.5.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"dirs 5.0.1",
|
"dirs 5.0.1",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "hikari-desktop"
|
name = "hikari-desktop"
|
||||||
version = "1.5.0"
|
version = "1.5.1"
|
||||||
description = "Hikari - Claude Code Visual Assistant"
|
description = "Hikari - Claude Code Visual Assistant"
|
||||||
authors = ["Naomi Carrigan"]
|
authors = ["Naomi Carrigan"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|||||||
+159
-14
@@ -49,6 +49,59 @@ fn wsl_path_to_windows(wsl_path: &str) -> Option<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a Command instance for executing Claude CLI commands
|
||||||
|
/// On Windows, this will use WSL to execute the command
|
||||||
|
/// On other platforms, it executes directly
|
||||||
|
fn create_claude_command() -> std::process::Command {
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
{
|
||||||
|
// Use `which` inside WSL to find the claude binary dynamically
|
||||||
|
// Non-login shells launched by `wsl` don't inherit the full user PATH,
|
||||||
|
// so we need to use a login shell to get the correct PATH
|
||||||
|
let which_output = std::process::Command::new("wsl")
|
||||||
|
.args(["-e", "bash", "-l", "-c", "which claude"])
|
||||||
|
.output();
|
||||||
|
|
||||||
|
match which_output {
|
||||||
|
Ok(output) if output.status.success() => {
|
||||||
|
let claude_path = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
||||||
|
let mut cmd = std::process::Command::new("wsl");
|
||||||
|
cmd.arg(claude_path);
|
||||||
|
cmd
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// Fallback to just "claude" if which fails
|
||||||
|
// This maintains backwards compatibility
|
||||||
|
let mut cmd = std::process::Command::new("wsl");
|
||||||
|
cmd.arg("claude");
|
||||||
|
cmd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
{
|
||||||
|
// Use `which` to find the claude binary dynamically
|
||||||
|
// This works regardless of how Claude Code was installed (standalone, npm, etc.)
|
||||||
|
// and avoids hardcoding paths
|
||||||
|
let which_output = std::process::Command::new("which")
|
||||||
|
.arg("claude")
|
||||||
|
.output();
|
||||||
|
|
||||||
|
match which_output {
|
||||||
|
Ok(output) if output.status.success() => {
|
||||||
|
let claude_path = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
||||||
|
std::process::Command::new(claude_path)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// Fallback to just "claude" if which fails
|
||||||
|
// This maintains backwards compatibility
|
||||||
|
std::process::Command::new("claude")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn start_claude(
|
pub async fn start_claude(
|
||||||
bridge_manager: State<'_, SharedBridgeManager>,
|
bridge_manager: State<'_, SharedBridgeManager>,
|
||||||
@@ -1166,6 +1219,55 @@ pub struct MemoryFilesResponse {
|
|||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn list_memory_files() -> Result<MemoryFilesResponse, String> {
|
pub async fn list_memory_files() -> Result<MemoryFilesResponse, String> {
|
||||||
|
// On Windows, we need to look in the WSL home directory
|
||||||
|
// On Linux/Mac, use the native home directory
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
{
|
||||||
|
list_memory_files_via_wsl().await
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
{
|
||||||
|
list_memory_files_native().await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List memory files via WSL (for Windows)
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
async fn list_memory_files_via_wsl() -> Result<MemoryFilesResponse, String> {
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
// Use WSL to find all memory files in the WSL home directory
|
||||||
|
// This script finds all "memory" directories and lists their files
|
||||||
|
let script = r#"
|
||||||
|
find ~/.claude/projects -type d -name memory 2>/dev/null | while read dir; do
|
||||||
|
find "$dir" -maxdepth 1 -type f 2>/dev/null
|
||||||
|
done | sort
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let output = Command::new("wsl")
|
||||||
|
.args(["-e", "bash", "-l", "-c", script])
|
||||||
|
.output()
|
||||||
|
.map_err(|e| format!("Failed to execute WSL command: {}", e))?;
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||||
|
return Err(format!("Failed to list memory files: {}", stderr));
|
||||||
|
}
|
||||||
|
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
let files: Vec<String> = stdout
|
||||||
|
.lines()
|
||||||
|
.filter(|line| !line.trim().is_empty())
|
||||||
|
.map(|line| line.trim().to_string())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(MemoryFilesResponse { files })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List memory files using native filesystem (for Linux/Mac)
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
async fn list_memory_files_native() -> Result<MemoryFilesResponse, String> {
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
// Get the .claude directory in the user's home
|
// Get the .claude directory in the user's home
|
||||||
@@ -1233,7 +1335,7 @@ pub async fn list_memory_files() -> Result<MemoryFilesResponse, String> {
|
|||||||
pub async fn get_claude_version() -> Result<String, String> {
|
pub async fn get_claude_version() -> Result<String, String> {
|
||||||
tracing::debug!("Getting Claude CLI version");
|
tracing::debug!("Getting Claude CLI version");
|
||||||
|
|
||||||
let output = std::process::Command::new("claude")
|
let output = create_claude_command()
|
||||||
.arg("--version")
|
.arg("--version")
|
||||||
.output();
|
.output();
|
||||||
|
|
||||||
@@ -1323,7 +1425,7 @@ fn parse_plugin_list(stdout: &str) -> Vec<PluginInfo> {
|
|||||||
pub async fn list_plugins() -> Result<Vec<PluginInfo>, String> {
|
pub async fn list_plugins() -> Result<Vec<PluginInfo>, String> {
|
||||||
tracing::debug!("Listing Claude Code plugins");
|
tracing::debug!("Listing Claude Code plugins");
|
||||||
|
|
||||||
let output = std::process::Command::new("claude")
|
let output = create_claude_command()
|
||||||
.arg("plugin")
|
.arg("plugin")
|
||||||
.arg("list")
|
.arg("list")
|
||||||
.output();
|
.output();
|
||||||
@@ -1352,7 +1454,7 @@ pub async fn list_plugins() -> Result<Vec<PluginInfo>, String> {
|
|||||||
pub async fn install_plugin(plugin_name: String) -> Result<String, String> {
|
pub async fn install_plugin(plugin_name: String) -> Result<String, String> {
|
||||||
tracing::debug!("Installing plugin: {}", plugin_name);
|
tracing::debug!("Installing plugin: {}", plugin_name);
|
||||||
|
|
||||||
let output = std::process::Command::new("claude")
|
let output = create_claude_command()
|
||||||
.arg("plugin")
|
.arg("plugin")
|
||||||
.arg("install")
|
.arg("install")
|
||||||
.arg(&plugin_name)
|
.arg(&plugin_name)
|
||||||
@@ -1381,7 +1483,7 @@ pub async fn install_plugin(plugin_name: String) -> Result<String, String> {
|
|||||||
pub async fn uninstall_plugin(plugin_name: String) -> Result<String, String> {
|
pub async fn uninstall_plugin(plugin_name: String) -> Result<String, String> {
|
||||||
tracing::debug!("Uninstalling plugin: {}", plugin_name);
|
tracing::debug!("Uninstalling plugin: {}", plugin_name);
|
||||||
|
|
||||||
let output = std::process::Command::new("claude")
|
let output = create_claude_command()
|
||||||
.arg("plugin")
|
.arg("plugin")
|
||||||
.arg("uninstall")
|
.arg("uninstall")
|
||||||
.arg(&plugin_name)
|
.arg(&plugin_name)
|
||||||
@@ -1410,7 +1512,7 @@ pub async fn uninstall_plugin(plugin_name: String) -> Result<String, String> {
|
|||||||
pub async fn enable_plugin(plugin_name: String) -> Result<String, String> {
|
pub async fn enable_plugin(plugin_name: String) -> Result<String, String> {
|
||||||
tracing::debug!("Enabling plugin: {}", plugin_name);
|
tracing::debug!("Enabling plugin: {}", plugin_name);
|
||||||
|
|
||||||
let output = std::process::Command::new("claude")
|
let output = create_claude_command()
|
||||||
.arg("plugin")
|
.arg("plugin")
|
||||||
.arg("enable")
|
.arg("enable")
|
||||||
.arg(&plugin_name)
|
.arg(&plugin_name)
|
||||||
@@ -1439,7 +1541,7 @@ pub async fn enable_plugin(plugin_name: String) -> Result<String, String> {
|
|||||||
pub async fn disable_plugin(plugin_name: String) -> Result<String, String> {
|
pub async fn disable_plugin(plugin_name: String) -> Result<String, String> {
|
||||||
tracing::debug!("Disabling plugin: {}", plugin_name);
|
tracing::debug!("Disabling plugin: {}", plugin_name);
|
||||||
|
|
||||||
let output = std::process::Command::new("claude")
|
let output = create_claude_command()
|
||||||
.arg("plugin")
|
.arg("plugin")
|
||||||
.arg("disable")
|
.arg("disable")
|
||||||
.arg(&plugin_name)
|
.arg(&plugin_name)
|
||||||
@@ -1468,7 +1570,7 @@ pub async fn disable_plugin(plugin_name: String) -> Result<String, String> {
|
|||||||
pub async fn update_plugin(plugin_name: String) -> Result<String, String> {
|
pub async fn update_plugin(plugin_name: String) -> Result<String, String> {
|
||||||
tracing::debug!("Updating plugin: {}", plugin_name);
|
tracing::debug!("Updating plugin: {}", plugin_name);
|
||||||
|
|
||||||
let output = std::process::Command::new("claude")
|
let output = create_claude_command()
|
||||||
.arg("plugin")
|
.arg("plugin")
|
||||||
.arg("update")
|
.arg("update")
|
||||||
.arg(&plugin_name)
|
.arg(&plugin_name)
|
||||||
@@ -1540,7 +1642,7 @@ fn parse_marketplace_list(stdout: &str) -> Vec<MarketplaceInfo> {
|
|||||||
pub async fn list_marketplaces() -> Result<Vec<MarketplaceInfo>, String> {
|
pub async fn list_marketplaces() -> Result<Vec<MarketplaceInfo>, String> {
|
||||||
tracing::debug!("Listing plugin marketplaces");
|
tracing::debug!("Listing plugin marketplaces");
|
||||||
|
|
||||||
let output = std::process::Command::new("claude")
|
let output = create_claude_command()
|
||||||
.arg("plugin")
|
.arg("plugin")
|
||||||
.arg("marketplace")
|
.arg("marketplace")
|
||||||
.arg("list")
|
.arg("list")
|
||||||
@@ -1573,7 +1675,7 @@ pub async fn list_marketplaces() -> Result<Vec<MarketplaceInfo>, String> {
|
|||||||
pub async fn add_marketplace(source: String) -> Result<String, String> {
|
pub async fn add_marketplace(source: String) -> Result<String, String> {
|
||||||
tracing::debug!("Adding marketplace: {}", source);
|
tracing::debug!("Adding marketplace: {}", source);
|
||||||
|
|
||||||
let output = std::process::Command::new("claude")
|
let output = create_claude_command()
|
||||||
.arg("plugin")
|
.arg("plugin")
|
||||||
.arg("marketplace")
|
.arg("marketplace")
|
||||||
.arg("add")
|
.arg("add")
|
||||||
@@ -1606,7 +1708,7 @@ pub async fn add_marketplace(source: String) -> Result<String, String> {
|
|||||||
pub async fn remove_marketplace(name: String) -> Result<String, String> {
|
pub async fn remove_marketplace(name: String) -> Result<String, String> {
|
||||||
tracing::debug!("Removing marketplace: {}", name);
|
tracing::debug!("Removing marketplace: {}", name);
|
||||||
|
|
||||||
let output = std::process::Command::new("claude")
|
let output = create_claude_command()
|
||||||
.arg("plugin")
|
.arg("plugin")
|
||||||
.arg("marketplace")
|
.arg("marketplace")
|
||||||
.arg("remove")
|
.arg("remove")
|
||||||
@@ -1746,7 +1848,7 @@ fn parse_mcp_server_list(stdout: &str) -> Vec<McpServerInfo> {
|
|||||||
pub async fn list_mcp_servers() -> Result<Vec<McpServerInfo>, String> {
|
pub async fn list_mcp_servers() -> Result<Vec<McpServerInfo>, String> {
|
||||||
tracing::debug!("Listing MCP servers");
|
tracing::debug!("Listing MCP servers");
|
||||||
|
|
||||||
let output = std::process::Command::new("claude")
|
let output = create_claude_command()
|
||||||
.arg("mcp")
|
.arg("mcp")
|
||||||
.arg("list")
|
.arg("list")
|
||||||
.output();
|
.output();
|
||||||
@@ -1788,7 +1890,7 @@ pub async fn get_mcp_server(name: String) -> Result<McpServerInfo, String> {
|
|||||||
pub async fn remove_mcp_server(name: String) -> Result<String, String> {
|
pub async fn remove_mcp_server(name: String) -> Result<String, String> {
|
||||||
tracing::debug!("Removing MCP server: {}", name);
|
tracing::debug!("Removing MCP server: {}", name);
|
||||||
|
|
||||||
let output = std::process::Command::new("claude")
|
let output = create_claude_command()
|
||||||
.arg("mcp")
|
.arg("mcp")
|
||||||
.arg("remove")
|
.arg("remove")
|
||||||
.arg(&name)
|
.arg(&name)
|
||||||
@@ -1823,7 +1925,7 @@ pub async fn add_mcp_server(
|
|||||||
) -> Result<String, String> {
|
) -> Result<String, String> {
|
||||||
tracing::debug!("Adding MCP server: {} with transport {}", name, transport);
|
tracing::debug!("Adding MCP server: {} with transport {}", name, transport);
|
||||||
|
|
||||||
let mut cmd = std::process::Command::new("claude");
|
let mut cmd = create_claude_command();
|
||||||
cmd.arg("mcp").arg("add");
|
cmd.arg("mcp").arg("add");
|
||||||
|
|
||||||
// Add transport flag
|
// Add transport flag
|
||||||
@@ -1871,7 +1973,7 @@ pub async fn add_mcp_server(
|
|||||||
pub async fn get_mcp_server_details(name: String) -> Result<String, String> {
|
pub async fn get_mcp_server_details(name: String) -> Result<String, String> {
|
||||||
tracing::debug!("Getting detailed info for MCP server: {}", name);
|
tracing::debug!("Getting detailed info for MCP server: {}", name);
|
||||||
|
|
||||||
let output = std::process::Command::new("claude")
|
let output = create_claude_command()
|
||||||
.arg("mcp")
|
.arg("mcp")
|
||||||
.arg("get")
|
.arg("get")
|
||||||
.arg(&name)
|
.arg(&name)
|
||||||
@@ -1908,6 +2010,49 @@ mod tests {
|
|||||||
tokio::runtime::Runtime::new().unwrap().block_on(f)
|
tokio::runtime::Runtime::new().unwrap().block_on(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== create_claude_command tests ====================
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
fn test_create_claude_command_windows() {
|
||||||
|
// On Windows, should create a command that uses wsl with full path to claude
|
||||||
|
// The path is resolved dynamically via `which` in a login shell
|
||||||
|
let cmd = create_claude_command();
|
||||||
|
let program = cmd.get_program();
|
||||||
|
|
||||||
|
assert_eq!(program, "wsl");
|
||||||
|
|
||||||
|
// Verify the first argument is a path to claude (full path from `which`)
|
||||||
|
// or fallback to just "claude" if which fails
|
||||||
|
let args: Vec<&std::ffi::OsStr> = cmd.get_args().collect();
|
||||||
|
assert_eq!(args.len(), 1);
|
||||||
|
|
||||||
|
let arg_str = args[0].to_string_lossy();
|
||||||
|
assert!(
|
||||||
|
arg_str.contains("claude"),
|
||||||
|
"Expected argument to contain 'claude', got: {}",
|
||||||
|
arg_str
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
fn test_create_claude_command_linux() {
|
||||||
|
// On Linux/Mac, should create a command that uses the full path to claude
|
||||||
|
// (resolved via `which` command)
|
||||||
|
let cmd = create_claude_command();
|
||||||
|
let program = cmd.get_program();
|
||||||
|
|
||||||
|
// The program should be the full path to claude (from `which`)
|
||||||
|
// or fallback to "claude" if which fails
|
||||||
|
let program_str = program.to_string_lossy();
|
||||||
|
assert!(
|
||||||
|
program_str.ends_with("claude"),
|
||||||
|
"Expected program to end with 'claude', got: {}",
|
||||||
|
program_str
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== validate_directory tests ====================
|
// ==================== validate_directory tests ====================
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -129,6 +129,11 @@ impl WslBridge {
|
|||||||
return Err("Process already running".to_string());
|
return Err("Process already running".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if Claude binary is installed before attempting to start
|
||||||
|
if Command::new("which").arg("claude").output().ok().is_none_or(|output| !output.status.success()) {
|
||||||
|
return Err("Claude Code is not installed. Please install it using:\n\ncurl -fsSL https://claude.ai/install.sh | bash".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
// Load saved achievements and stats when starting a new session
|
// Load saved achievements and stats when starting a new session
|
||||||
let app_clone = app.clone();
|
let app_clone = app.clone();
|
||||||
let stats = self.stats.clone();
|
let stats = self.stats.clone();
|
||||||
@@ -1868,6 +1873,22 @@ mod tests {
|
|||||||
assert!(!bridge.is_running());
|
assert!(!bridge.is_running());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_claude_binary_check_command_structure() {
|
||||||
|
// Test that we're using the correct command to check for Claude binary
|
||||||
|
let output = Command::new("which").arg("claude").output();
|
||||||
|
|
||||||
|
// The command should execute successfully (even if claude is not found)
|
||||||
|
// We're just verifying the command structure is valid
|
||||||
|
assert!(output.is_ok(), "which command should execute without error");
|
||||||
|
|
||||||
|
// Verify the check logic returns a boolean
|
||||||
|
// This is the same logic used in start() to check if claude is installed
|
||||||
|
let _result = output.ok().is_none_or(|o| !o.status.success());
|
||||||
|
// If claude is not installed, _result will be true (show error)
|
||||||
|
// If claude is installed, _result will be false (proceed with connection)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_create_shared_bridge_manager() {
|
fn test_create_shared_bridge_manager() {
|
||||||
use crate::bridge_manager::create_shared_bridge_manager;
|
use crate::bridge_manager::create_shared_bridge_manager;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "hikari-desktop",
|
"productName": "hikari-desktop",
|
||||||
"version": "1.5.0",
|
"version": "1.5.1",
|
||||||
"identifier": "com.naomi.hikari-desktop",
|
"identifier": "com.naomi.hikari-desktop",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "pnpm dev",
|
"beforeDevCommand": "pnpm dev",
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { invoke } from "@tauri-apps/api/core";
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
import { readTextFile } from "@tauri-apps/plugin-fs";
|
|
||||||
import Markdown from "./Markdown.svelte";
|
import Markdown from "./Markdown.svelte";
|
||||||
|
|
||||||
let memoryFiles: string[] = $state([]);
|
let memoryFiles: string[] = $state([]);
|
||||||
@@ -33,7 +32,8 @@
|
|||||||
isLoading = true;
|
isLoading = true;
|
||||||
error = null;
|
error = null;
|
||||||
try {
|
try {
|
||||||
const content = await readTextFile(filePath);
|
// Use our backend command instead of Tauri plugin to handle WSL paths
|
||||||
|
const content = await invoke<string>("read_file_content", { path: filePath });
|
||||||
fileContent = content;
|
fileContent = content;
|
||||||
selectedFile = filePath;
|
selectedFile = filePath;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
Reference in New Issue
Block a user