From c1e934f2b2e158b83982ce71571b040850bf05c9 Mon Sep 17 00:00:00 2001 From: cirry <812852553@qq.com> Date: Mon, 13 Apr 2026 00:25:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AF=B9=E8=AF=9D=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=EF=BC=8C=E4=B8=8A=E4=BC=A0=E9=99=84=E4=BB=B6=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E5=BC=80=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .junie/AGENTS.md | 133 ++++ index.html | 2 +- package-lock.json | 1107 +++++++++++++++++++++++++- package.json | 7 +- src/renderer/views/chat/ChatView.vue | 132 ++- src/renderer/views/home/HomeView.vue | 154 +++- 6 files changed, 1491 insertions(+), 44 deletions(-) create mode 100644 .junie/AGENTS.md diff --git a/.junie/AGENTS.md b/.junie/AGENTS.md new file mode 100644 index 0000000..d6e2f20 --- /dev/null +++ b/.junie/AGENTS.md @@ -0,0 +1,133 @@ +# Zhiju AI Assistant — Developer Notes + +## Project Overview + +Electron desktop app (Electron Forge + Vite + Vue 3) that wraps a locally-spawned `opencode` binary (located in `resources/`). The renderer is a Vue 3 SPA; the main process manages the `opencode` child process and exposes IPC to the renderer via a preload script. + +--- + +## Build & Configuration + +### Prerequisites +- Node.js ≥ 18 +- The `opencode` binary must exist at `resources/windows/x64/opencode.exe` (Windows) before packaging. It is **not** committed to the repo — obtain it separately. + +### Install dependencies +```bash +npm install +``` + +### Run in development +```bash +npm start +``` +This uses `electron-forge start`, which runs Vite for the renderer and launches Electron. Hot-reload is active for the renderer; changes to `src/main/index.js` or `src/preload/index.js` require a manual restart. + +### Package / distribute +```bash +npm run make # builds installers for the current platform +npm run package # produces an unpackaged app directory +``` +Packaged output lands in `out/`. The `opencode.exe` binary is bundled via `extraResource` in `forge.config.js` and unpacked from ASAR at runtime. + +### Vite configs +| File | Purpose | +|---|---| +| `vite.main.config.mjs` | Main process bundle | +| `vite.preload.config.mjs` | Preload script bundle | +| `vite.renderer.config.mjs` | Renderer (Vue SPA), alias `@` → `src/renderer` | + +--- + +## Architecture Notes + +- **Main process** (`src/main/index.js`): spawns `opencode` binary, resolves a free port starting at `4096`, waits for TCP readiness, then injects `window.__opencodeBaseUrl` into the renderer via `executeJavaScript`. Also runs Bonjour service discovery. +- **Preload** (`src/preload/index.js`): bridges IPC between main and renderer using `contextBridge`. +- **Renderer** (`src/renderer/`): Vue 3 + Pinia + Vue Router. HTTP calls go through `src/renderer/http/` (axios-based). SSE streaming is handled in `src/renderer/http/sse.js`. +- **URL constants** (`src/renderer/http/url.js`): single source of truth for all API endpoint paths. `getBaseUrl()` reads `window.__opencodeBaseUrl` (injected by main) with fallback to `http://127.0.0.1:4096`. +- **Crypto** (`src/renderer/utils/crypto.js`): passwords are Base64-encoded then RSA-encrypted (public key hardcoded) before being sent to the login API. + +--- + +## Testing + +### Framework +[Vitest](https://vitest.dev/) — chosen for native Vite/ESM compatibility, zero extra config needed. + +### Run all tests +```bash +npm test # vitest run (single pass, CI-friendly) +npm run test:watch # vitest watch mode (development) +``` + +Or directly: +```bash +npx vitest run +``` + +### Writing tests +- Place test files alongside the source file as `*.test.js` (Vitest picks them up automatically). +- For pure utility/logic modules (e.g. `url.js`, `crypto.js`) no additional setup is needed. +- Modules that depend on `window`, `electron`, or Pinia require mocking. Use `vi.stubGlobal` for `window` properties and `vi.mock` for module mocks. + +### Example: testing `url.js` +```js +// src/renderer/http/url.test.js +import { describe, it, expect } from 'vitest'; +import url from './url.js'; + +describe('url constants', () => { + it('session.detail returns correct path', () => { + expect(url.session.detail('abc123')).toBe('/session/abc123'); + }); + + it('message.send returns correct path', () => { + expect(url.message.send('sess1')).toBe('/session/sess1/message'); + }); +}); +``` + +Run with: +```bash +npx vitest run src/renderer/http/url.test.js +``` + +### Testing modules that use `window.__opencodeBaseUrl` +```js +import { vi, describe, it, expect, beforeEach } from 'vitest'; + +beforeEach(() => { + vi.stubGlobal('__opencodeBaseUrl', 'http://127.0.0.1:5000'); +}); + +// import and test getBaseUrl() etc. +``` + +--- + +## Code Style + +- **Formatter**: Prettier (config in `package.json` defaults). Run `npm run format` to auto-fix, `npm run format:check` for CI check. +- **Commit messages**: enforced by commitlint (`@commitlint/config-conventional`). Use conventional commits: `feat:`, `fix:`, `chore:`, etc. +- **Pre-commit hook**: husky + lint-staged runs Prettier on staged `*.js` and `*.vue` files automatically. +- **No ESLint** is configured — only Prettier for formatting. +- Vue components use the Composition API (`