diff --git a/.agent/skills/project_overview/SKILL.md b/.agent/skills/project_overview/SKILL.md new file mode 100644 index 0000000..3c5e317 --- /dev/null +++ b/.agent/skills/project_overview/SKILL.md @@ -0,0 +1,88 @@ +--- +name: antigravity-manager +description: Comprehensive guide to Antigravity Manager architecture, workflows, and development. Use this to understand how to work on the project. +--- + +# Antigravity Manager Developer Guide + +## 🏗️ Architecture Overview + +Antigravity Manager is a hybrid Desktop Application built with Electron, React, and NestJS. It follows a modular architecture where the frontend (Renderer) communicates with the backend (Main) via type-safe IPC (ORPC). + +```mermaid +graph TD + User[User Interface] -->|React/Vite| Renderer[Renderer Process] + Renderer -->|ORPC Client| IPC[IPC Layer] + IPC -->|ORPC Router| Main[Main Process] + Main -->|Bootstraps| Server[NestJS Server] + Main -->|Calls| Services[Service Layer] + Services -->|Read/Write| DB[(SQLite Database)] + Services -->|HTTP| Cloud[Cloud APIs (Google/Anthropic)] +``` + +### Key Technologies + +- **Frontend**: React 19, TailwindCSS v4, TanStack Router, TanStack Query. +- **Backend**: Electron (Main), NestJS (Core Logic), Better-SQLite3 (Data). +- **Communication**: ORPC (Type-safe IPC wrapper around Electron IPC). +- **Build**: Electron Forge + Vite. + +## 📂 Directory Structure + +- `src/main.ts`: Electron Main Process entry point. +- `src/preload.ts`: Bridge between Main and Renderer. +- `src/renderer.tsx`: React App entry point. +- `src/components/`: Reusable React UI components (Radix UI based). +- `src/ipc/`: IPC Routers and Handlers (Domain logic). + - `router.ts`: Main ORPC router definition. + - `account/`, `cloud/`, `database/`: Domain-specific handlers. +- `src/server/`: NestJS application modules (proxies/gateways). +- `src/services/`: Core business logic (framework agnostic). + - `GoogleAPIService.ts`: Gemini/Cloud interactions. + - `AutoSwitchService.ts`: Account rotation logic. +- `src/routes/`: Frontend routing definitions (File-based). + +## 🚀 Development Workflow + +### Prerequisites + +- Node.js 18+ +- npm (Project uses `package-lock.json`) + +### Common Commands + +- **Start Dev Server**: `npm start` +- **Lint Code**: `npm run lint` +- **Unit Test**: `npm run test:unit` +- **E2E Test**: `npm run test:e2e` +- **Build Production**: `npm run make` + +## 🧠 Core Concepts + +### IPC Communication (ORPC) + +The project uses `orpc` for type-safe communication. + +- **Define**: Create a router in `src/ipc/router.ts` with Zod schemas. +- **Implement**: Add logic in handlers (e.g., `src/ipc/account/handler.ts`). +- **Call**: Use the generated client in React components. + +### Database Access + +Data is stored in a local SQLite file (`test.db` in dev, user data in prod). + +- Use `Better-SQLite3` for direct access. +- Logic should be encapsulated in `src/services` or `src/ipc`. + +### Account Management + +- Accounts are added via OAuth (Google/Claude). +- `GoogleAPIService` handles token exchange and refreshing. +- `AutoSwitchService` monitors usage and switches active accounts automatically. + +## ⚠️ Critical Rules + +1. **Type Safety**: strict TypeScript usage; Zod for runtime validation. +2. **Components**: Use `src/components/ui` (Radix primitives) for consistency. +3. **Async**: Handle all IPC/DB calls asynchronously with try/catch. +4. **Security**: Never commit secrets. API keys are user-provided or encrypted locally. diff --git a/.agent/workflows/openspec-apply.md b/.agent/workflows/openspec-apply.md index b0154dd..3983daa 100644 --- a/.agent/workflows/openspec-apply.md +++ b/.agent/workflows/openspec-apply.md @@ -1,14 +1,18 @@ --- description: Implement an approved OpenSpec change and keep tasks in sync. --- + + **Guardrails** + - Favor straightforward, minimal implementations first and add complexity only when it is requested or clearly required. - Keep changes tightly scoped to the requested outcome. - Refer to `openspec/AGENTS.md` (located inside the `openspec/` directory—run `ls openspec` or `openspec update` if you don't see it) if you need additional OpenSpec conventions or clarifications. **Steps** Track these steps as TODOs and complete them one by one. + 1. Read `changes//proposal.md`, `design.md` (if present), and `tasks.md` to confirm scope and acceptance criteria. 2. Work through tasks sequentially, keeping edits minimal and focused on the requested change. 3. Confirm completion before updating statuses—make sure every item in `tasks.md` is finished. @@ -16,5 +20,6 @@ Track these steps as TODOs and complete them one by one. 5. Reference `openspec list` or `openspec show ` when additional context is required. **Reference** + - Use `openspec show --json --deltas-only` if you need additional context from the proposal while implementing. diff --git a/.agent/workflows/openspec-archive.md b/.agent/workflows/openspec-archive.md index 38dcc81..069842a 100644 --- a/.agent/workflows/openspec-archive.md +++ b/.agent/workflows/openspec-archive.md @@ -1,13 +1,17 @@ --- description: Archive a deployed OpenSpec change and update specs. --- + + **Guardrails** + - Favor straightforward, minimal implementations first and add complexity only when it is requested or clearly required. - Keep changes tightly scoped to the requested outcome. - Refer to `openspec/AGENTS.md` (located inside the `openspec/` directory—run `ls openspec` or `openspec update` if you don't see it) if you need additional OpenSpec conventions or clarifications. **Steps** + 1. Determine the change ID to archive: - If this prompt already includes a specific change ID (for example inside a `` block populated by slash-command arguments), use that value after trimming whitespace. - If the conversation references a change loosely (for example by title or summary), run `openspec list` to surface likely IDs, share the relevant candidates, and confirm which one the user intends. @@ -19,6 +23,7 @@ description: Archive a deployed OpenSpec change and update specs. 5. Validate with `openspec validate --strict` and inspect with `openspec show ` if anything looks off. **Reference** + - Use `openspec list` to confirm change IDs before archiving. - Inspect refreshed specs with `openspec list --specs` and address any validation issues before handing off. diff --git a/.agent/workflows/openspec-proposal.md b/.agent/workflows/openspec-proposal.md index db8a95a..33ab714 100644 --- a/.agent/workflows/openspec-proposal.md +++ b/.agent/workflows/openspec-proposal.md @@ -1,8 +1,11 @@ --- description: Scaffold a new OpenSpec change and validate strictly. --- + + **Guardrails** + - Favor straightforward, minimal implementations first and add complexity only when it is requested or clearly required. - Keep changes tightly scoped to the requested outcome. - Refer to `openspec/AGENTS.md` (located inside the `openspec/` directory—run `ls openspec` or `openspec update` if you don't see it) if you need additional OpenSpec conventions or clarifications. @@ -10,6 +13,7 @@ description: Scaffold a new OpenSpec change and validate strictly. - Do not write any code during the proposal stage. Only create design documents (proposal.md, tasks.md, design.md, and spec deltas). Implementation happens in the apply stage after approval. **Steps** + 1. Review `openspec/project.md`, run `openspec list` and `openspec list --specs`, and inspect related code or docs (e.g., via `rg`/`ls`) to ground the proposal in current behaviour; note any gaps that require clarification. 2. Choose a unique verb-led `change-id` and scaffold `proposal.md`, `tasks.md`, and `design.md` (when needed) under `openspec/changes//`. 3. Map the change into concrete capabilities or requirements, breaking multi-scope efforts into distinct spec deltas with clear relationships and sequencing. @@ -19,6 +23,7 @@ description: Scaffold a new OpenSpec change and validate strictly. 7. Validate with `openspec validate --strict` and resolve every issue before sharing the proposal. **Reference** + - Use `openspec show --json --deltas-only` or `openspec show --type spec` to inspect details when validation fails. - Search existing requirements with `rg -n "Requirement:|Scenario:" openspec/specs` before writing new ones. - Explore the codebase with `rg `, `ls`, or direct file reads so proposals align with current implementation realities. diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index aff82a1..db9ba41 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -1,6 +1,6 @@ version: 2 updates: - - package-ecosystem: "npm" - directory: "/" + - package-ecosystem: 'npm' + directory: '/' schedule: - interval: "weekly" + interval: 'weekly' diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 634f3c2..c845691 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -1,7 +1,7 @@ name-template: 'v$RESOLVED_VERSION' tag-template: 'v$RESOLVED_VERSION' categories: - - title: '🚀 What''s new' + - title: "🚀 What's new" labels: - 'feature' - 'feat' diff --git a/AGENTS.md b/AGENTS.md index a8861dc..ae9eb95 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -106,7 +106,6 @@ Keep this managed block so 'openspec update' can refresh the instructions. - `npm run test:e2e` - 运行 Playwright 端到端测试 - `npm run test:all` - 运行所有测试 - ### 运行单个测试 (Running Single Tests) - 单元测试: `npm run test:unit path/to/test.test.ts` diff --git a/CHANGELOG.md b/CHANGELOG.md index 47cc5c0..cffdfc3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,53 +17,53 @@ ### 🐛 Bug Fixes -* "Check Quota Now" button not refreshing UI after polling ([#42](https://github.com/Draculabo/AntigravityManager/issues/42)) ([e959ee3](https://github.com/Draculabo/AntigravityManager/commit/e959ee346e7c26a8a4c5b7deefa5bd2452153f9d)) +- "Check Quota Now" button not refreshing UI after polling ([#42](https://github.com/Draculabo/AntigravityManager/issues/42)) ([e959ee3](https://github.com/Draculabo/AntigravityManager/commit/e959ee346e7c26a8a4c5b7deefa5bd2452153f9d)) ### 📝 Documentation -* remove beta download links from README ([5a21680](https://github.com/Draculabo/AntigravityManager/commit/5a2168030eac4ddeffa1c3b002b2de48b6a11a8f)) +- remove beta download links from README ([5a21680](https://github.com/Draculabo/AntigravityManager/commit/5a2168030eac4ddeffa1c3b002b2de48b6a11a8f)) ## [0.3.4](https://github.com/Draculabo/AntigravityManager/compare/v0.3.3...v0.3.4) (2026-01-26) ### 🐛 Bug Fixes -* **security:** add safeStorage fallback for production builds ([#38](https://github.com/Draculabo/AntigravityManager/issues/38)) ([#43](https://github.com/Draculabo/AntigravityManager/issues/43)) ([0208058](https://github.com/Draculabo/AntigravityManager/commit/02080588b764ed88a5831152a3a1249f1d077d29)) +- **security:** add safeStorage fallback for production builds ([#38](https://github.com/Draculabo/AntigravityManager/issues/38)) ([#43](https://github.com/Draculabo/AntigravityManager/issues/43)) ([0208058](https://github.com/Draculabo/AntigravityManager/commit/02080588b764ed88a5831152a3a1249f1d077d29)) ### 📝 Documentation -* update beta release link ([d5ee08d](https://github.com/Draculabo/AntigravityManager/commit/d5ee08d5a06a915a8b82f680b38e2f532105498c)) +- update beta release link ([d5ee08d](https://github.com/Draculabo/AntigravityManager/commit/d5ee08d5a06a915a8b82f680b38e2f532105498c)) ## [0.3.4-beta.1](https://github.com/Draculabo/AntigravityManager/compare/v0.3.3...v0.3.4-beta.1) (2026-01-25) ### 🐛 Bug Fixes -* **security:** add safeStorage fallback for production builds ([#38](https://github.com/Draculabo/AntigravityManager/issues/38)) ([92dc2f6](https://github.com/Draculabo/AntigravityManager/commit/92dc2f6f2169eb1a32950694387f2333ea2de682)) +- **security:** add safeStorage fallback for production builds ([#38](https://github.com/Draculabo/AntigravityManager/issues/38)) ([92dc2f6](https://github.com/Draculabo/AntigravityManager/commit/92dc2f6f2169eb1a32950694387f2333ea2de682)) ## [0.3.3](https://github.com/Draculabo/AntigravityManager/compare/v0.3.2...v0.3.3) (2026-01-25) ### 🐛 Bug Fixes -* accept lowercase antigravity in process detection ([0d4e2ab](https://github.com/Draculabo/AntigravityManager/commit/0d4e2ab21f37704e09ef1a67c181c48b42df1180)) +- accept lowercase antigravity in process detection ([0d4e2ab](https://github.com/Draculabo/AntigravityManager/commit/0d4e2ab21f37704e09ef1a67c181c48b42df1180)) ### 📝 Documentation -* add beta download link to readme ([f15bb48](https://github.com/Draculabo/AntigravityManager/commit/f15bb48fdda10fda3c2382941ee0ce51204f750a)) -* clean up changelog duplicate ([22265e1](https://github.com/Draculabo/AntigravityManager/commit/22265e153c9d394229aa48afdc5948044b74e842)) +- add beta download link to readme ([f15bb48](https://github.com/Draculabo/AntigravityManager/commit/f15bb48fdda10fda3c2382941ee0ce51204f750a)) +- clean up changelog duplicate ([22265e1](https://github.com/Draculabo/AntigravityManager/commit/22265e153c9d394229aa48afdc5948044b74e842)) ## [0.3.2](https://github.com/Draculabo/AntigravityManager/compare/v0.3.1...v0.3.2) (2026-01-25) ### 🐛 Bug Fixes -* handle keychain hint and suppress pgrep spam ([bd3d41a](https://github.com/Draculabo/AntigravityManager/commit/bd3d41aed17bafe9d684c5c421bad8b90afa19a8)) +- handle keychain hint and suppress pgrep spam ([bd3d41a](https://github.com/Draculabo/AntigravityManager/commit/bd3d41aed17bafe9d684c5c421bad8b90afa19a8)) ### 📝 Documentation -* add macOS self-signing workaround for Keychain issues ([01e3f8f](https://github.com/Draculabo/AntigravityManager/commit/01e3f8f8fd6dacc5eed214ed4b505d6d85f4bcff)) +- add macOS self-signing workaround for Keychain issues ([01e3f8f](https://github.com/Draculabo/AntigravityManager/commit/01e3f8f8fd6dacc5eed214ed4b505d6d85f4bcff)) ### 🔧 Continuous Integration -* setup semantic release configuration and github actions workflow ([d2945a6](https://github.com/Draculabo/AntigravityManager/commit/d2945a6e8a14d75f577716183cdff093443d9636)) -* trigger publish on release published event ([6a07bc0](https://github.com/Draculabo/AntigravityManager/commit/6a07bc0a10a5ad802777e007cfd7390852119b15)) +- setup semantic release configuration and github actions workflow ([d2945a6](https://github.com/Draculabo/AntigravityManager/commit/d2945a6e8a14d75f577716183cdff093443d9636)) +- trigger publish on release published event ([6a07bc0](https://github.com/Draculabo/AntigravityManager/commit/6a07bc0a10a5ad802777e007cfd7390852119b15)) ## [0.3.1] - 2026-01-25 diff --git a/eslint.config.mjs b/eslint.config.mjs index 924246a..d26237e 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -25,4 +25,14 @@ export default defineConfig([ reactHooks.configs.flat.recommended, eslintPluginPrettierRecommended, ...tseslint.configs.recommended, + { + rules: { + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-empty-object-type': 'off', + '@typescript-eslint/ban-ts-comment': 'off', + 'no-empty-pattern': 'off', + 'prefer-const': 'off', + }, + }, ]); diff --git a/package-lock.json b/package-lock.json index 7823b6a..ded95aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,7 @@ "@radix-ui/react-toast": "^1.2.15", "@radix-ui/react-toggle": "^1.1.9", "@radix-ui/react-toggle-group": "^1.1.11", + "@radix-ui/react-tooltip": "^1.2.8", "@tailwindcss/vite": "^4.1.17", "@tanstack/react-query": "^5.90.7", "@tanstack/react-router": "^1.139.3", @@ -64,6 +65,7 @@ "undici": "^7.16.0", "update-electron-app": "^3.1.1", "uuid": "^13.0.0", + "yaml": "^2.8.2", "zod": "^4.1.12" }, "devDependencies": { @@ -292,6 +294,7 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -981,6 +984,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -1024,6 +1028,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" } @@ -1760,6 +1765,7 @@ "integrity": "sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "chalk": "^4.1.1", "fs-extra": "^9.0.1", @@ -3063,6 +3069,7 @@ "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.3.tgz", "integrity": "sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@grpc/proto-loader": "^0.8.0", "@js-sdsl/ordered-map": "^4.4.2" @@ -3801,6 +3808,7 @@ "integrity": "sha512-yl43JD/86CIj3Mz5mvvLJqAOfIup7ncxfJ0Btnl0/v5TouVUyeEdcpknfgc+yMevS/48oH9WAkkw93m7otLb/A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@inquirer/checkbox": "^3.0.1", "@inquirer/confirm": "^4.0.1", @@ -4010,6 +4018,7 @@ "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.10.tgz", "integrity": "sha512-NoBzJFtq1bzHGia5Q5NO1pJNpx530nupbEu/auCWOFCGL5y8Zo8kiG28EXTCDfIhQgregEtn1Cs6H8WSLUC8kg==", "license": "MIT", + "peer": true, "dependencies": { "file-type": "21.1.1", "iterare": "1.2.1", @@ -4042,6 +4051,7 @@ "integrity": "sha512-LYpaacSb8X9dcRpeZxA7Mvi5Aozv11s6028ZNoVKY2j/fyThLd+xrkksg3u+sw7F8mipFaxS/LuVpoHQ/MrACg==", "hasInstallScript": true, "license": "MIT", + "peer": true, "dependencies": { "@nuxt/opencollective": "0.4.1", "fast-safe-stringify": "2.1.1", @@ -4082,6 +4092,7 @@ "resolved": "https://registry.npmjs.org/@nestjs/microservices/-/microservices-11.1.11.tgz", "integrity": "sha512-nqOdHk0QHmaloWTBb+6enT+OIT5atqjEHWKaaSoQfAlJVGa7FVhgdNVcWBdDcPtNQM6hCTc8VGgQHIRDDhjFOw==", "license": "MIT", + "peer": true, "dependencies": { "iterare": "1.2.1", "tslib": "2.8.1" @@ -4140,6 +4151,7 @@ "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.1.11.tgz", "integrity": "sha512-kyABSskdMRIAMWL0SlbwtDy4yn59RL4HDdwHDz/fxWuv7/53YP8Y2DtV3/sHqY5Er0msMVTZrM38MjqXhYL7gw==", "license": "MIT", + "peer": true, "dependencies": { "cors": "2.8.5", "express": "5.2.1", @@ -4314,6 +4326,7 @@ "integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@octokit/auth-token": "^4.0.0", "@octokit/graphql": "^7.1.0", @@ -6609,6 +6622,96 @@ } } }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", + "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-callback-ref": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", @@ -7384,6 +7487,7 @@ "integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.3", @@ -8134,6 +8238,7 @@ "dev": true, "hasInstallScript": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.25" @@ -8667,6 +8772,7 @@ "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.139.12.tgz", "integrity": "sha512-qrIxb8c6XXih6MERZKKwdnYg0OannsQLJ/s+4/wRqKqGCG+QmvAMvnmNP7bfYLgFKi+KsE27HqUkHaSpZSenwQ==", "license": "MIT", + "peer": true, "dependencies": { "@tanstack/history": "1.139.0", "@tanstack/react-store": "^0.8.0", @@ -8737,6 +8843,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -8858,6 +8965,7 @@ "resolved": "https://registry.npmjs.org/@tanstack/router-core/-/router-core-1.139.12.tgz", "integrity": "sha512-HCDi4fpnAFeDDogT0C61yd2nJn0FrIyFDhyHG3xJji8emdn8Ni4rfyrN4Av46xKkXTPUGdbsqih45+uuNtunew==", "license": "MIT", + "peer": true, "dependencies": { "@tanstack/history": "1.139.0", "@tanstack/store": "^0.8.0", @@ -8926,6 +9034,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -9326,8 +9435,7 @@ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/babel__core": { "version": "7.20.5", @@ -9524,6 +9632,7 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -9548,6 +9657,7 @@ "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -9558,6 +9668,7 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "devOptional": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -9668,6 +9779,7 @@ "integrity": "sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.48.0", "@typescript-eslint/types": "8.48.0", @@ -10247,6 +10359,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "devOptional": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -11007,6 +11120,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", @@ -11365,13 +11479,15 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/class-validator": { "version": "0.14.3", "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.3.tgz", "integrity": "sha512-rXXekcjofVN1LTOSw+u4u9WXVEUvNBVjORW154q/IdmYWy1nMbOU9aNtZB0t8m+FJQ9q91jlr2f9CwwUFdFMRA==", "license": "MIT", + "peer": true, "dependencies": { "@types/validator": "^13.15.3", "libphonenumber-js": "^1.11.1", @@ -12000,6 +12116,16 @@ "node": ">=8" } }, + "node_modules/conventional-changelog-gitmoji-config/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/conventional-changelog-writer": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-8.2.0.tgz", @@ -12281,7 +12407,8 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/data-urls": { "version": "6.0.0", @@ -12616,8 +12743,7 @@ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/dot-prop": { "version": "5.3.0", @@ -13869,6 +13995,7 @@ "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -13929,6 +14056,7 @@ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", + "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -15935,6 +16063,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.28.4" }, @@ -18298,7 +18427,6 @@ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "lz-string": "bin/bin.js" } @@ -18449,6 +18577,7 @@ "integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==", "dev": true, "license": "MIT", + "peer": true, "bin": { "marked": "bin/marked.js" }, @@ -21147,6 +21276,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -22314,6 +22444,7 @@ "integrity": "sha512-QgODejq9K3OzoBbuyobZlUhznP5SKwPqp+6Q6xw6o8gnhr4O85L2U915iM2IDcfF2NPXVaM9zlo9tdwipnYwzg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -22422,7 +22553,6 @@ "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -22438,7 +22568,6 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -22773,6 +22902,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -22782,6 +22912,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -22821,8 +22952,7 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/react-refresh": { "version": "0.17.0", @@ -23209,7 +23339,8 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", - "license": "Apache-2.0" + "license": "Apache-2.0", + "peer": true }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", @@ -23546,6 +23677,7 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -23704,6 +23836,7 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -23757,6 +23890,7 @@ "integrity": "sha512-6qGjWccl5yoyugHt3jTgztJ9Y0JVzyH8/Voc/D8PlLat9pwxQYXz7W1Dpnq5h0/G5GCYGUaDSlYcyk3AMh5A6g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@semantic-release/commit-analyzer": "^13.0.1", "@semantic-release/error": "^4.0.0", @@ -24324,6 +24458,7 @@ "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.4.0.tgz", "integrity": "sha512-BdrNXdzlofomLTiRnwJTSEAaGKyHHZkbMXIywOh7zlzp4uZnXErEwl9XZ+N1hJSNpeTtNxWvVwN0wUzAIQ4Hpg==", "license": "MIT", + "peer": true, "engines": { "node": ">=10" } @@ -24857,7 +24992,6 @@ "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.10.tgz", "integrity": "sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.1.0", "seroval": "~1.3.0", @@ -24879,7 +25013,6 @@ "resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.3.3.tgz", "integrity": "sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w==", "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -25488,7 +25621,8 @@ "version": "4.1.17", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.17.tgz", "integrity": "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/tailwindcss-animate": { "version": "1.0.7", @@ -25686,6 +25820,7 @@ "integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==", "devOptional": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", @@ -25912,6 +26047,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -26174,6 +26310,7 @@ "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "~0.25.0", "get-tsconfig": "^4.7.5" @@ -26367,6 +26504,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "devOptional": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -26818,6 +26956,7 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -27407,6 +27546,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -27420,6 +27560,7 @@ "integrity": "sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -27907,6 +28048,7 @@ "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "devOptional": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10.0.0" }, @@ -27983,13 +28125,19 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "license": "ISC", + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, "engines": { - "node": ">= 6" + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, "node_modules/yargs": { @@ -28113,6 +28261,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz", "integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index 0cb953d..3393933 100644 --- a/package.json +++ b/package.json @@ -107,6 +107,7 @@ "@radix-ui/react-toast": "^1.2.15", "@radix-ui/react-toggle": "^1.1.9", "@radix-ui/react-toggle-group": "^1.1.11", + "@radix-ui/react-tooltip": "^1.2.8", "@tailwindcss/vite": "^4.1.17", "@tanstack/react-query": "^5.90.7", "@tanstack/react-router": "^1.139.3", @@ -138,6 +139,7 @@ "undici": "^7.16.0", "update-electron-app": "^3.1.1", "uuid": "^13.0.0", + "yaml": "^2.8.2", "zod": "^4.1.12" } } diff --git a/src/components/StatusBar.tsx b/src/components/StatusBar.tsx index a34098c..c7f3ba4 100644 --- a/src/components/StatusBar.tsx +++ b/src/components/StatusBar.tsx @@ -3,10 +3,15 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { isProcessRunning, startAntigravity, closeAntigravity } from '@/actions/process'; import { Button } from '@/components/ui/button'; import { cn } from '@/lib/utils'; -import { Play, Square, Loader2 } from 'lucide-react'; +import { Play, Square, Loader2, Power } from 'lucide-react'; import { useTranslation } from 'react-i18next'; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'; -export const StatusBar: React.FC = () => { +interface StatusBarProps { + isCollapsed?: boolean; +} + +export const StatusBar: React.FC = ({ isCollapsed = false }) => { const { t } = useTranslation(); const queryClient = useQueryClient(); @@ -40,26 +45,78 @@ export const StatusBar: React.FC = () => { const isPending = startMutation.isPending || stopMutation.isPending; + // Collapsed View + if (isCollapsed) { + return ( +
+ + + + + + +
+

+ {isLoading + ? t('status.checking') + : isRunning + ? t('status.running') + : t('status.stopped')} +

+ + + +
+ ); + } + + // Expanded View return (
-
+
{isLoading ? ( - + ) : isRunning ? ( -
+
) : ( -
+
)} - - {isLoading ? t('status.checking') : isRunning ? t('status.running') : t('status.stopped')} - +
+ Status + + {isLoading + ? t('status.checking') + : isRunning + ? t('status.running') + : t('status.stopped')} + +
); diff --git a/src/components/ui/tooltip.tsx b/src/components/ui/tooltip.tsx new file mode 100644 index 0000000..41d8ec2 --- /dev/null +++ b/src/components/ui/tooltip.tsx @@ -0,0 +1,28 @@ +import * as React from 'react'; +import * as TooltipPrimitive from '@radix-ui/react-tooltip'; + +import { cn } from '@/lib/utils'; + +const TooltipProvider = TooltipPrimitive.Provider; + +const Tooltip = TooltipPrimitive.Root; + +const TooltipTrigger = TooltipPrimitive.Trigger; + +const TooltipContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + +)); +TooltipContent.displayName = TooltipPrimitive.Content.displayName; + +export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }; diff --git a/src/ipc/process/handler.ts b/src/ipc/process/handler.ts index 5fda5b8..1d56082 100644 --- a/src/ipc/process/handler.ts +++ b/src/ipc/process/handler.ts @@ -100,9 +100,7 @@ export async function isProcessRunning(): Promise { logger.debug('No Antigravity process found (pgrep returned 1)'); } - logger.debug( - `Found ${processes.length} processes matching 'Antigravity/antigravity'`, - ); + logger.debug(`Found ${processes.length} processes matching 'Antigravity/antigravity'`); for (const proc of processes) { // Skip self diff --git a/src/layouts/MainLayout.tsx b/src/layouts/MainLayout.tsx index 036b426..b46d7d5 100644 --- a/src/layouts/MainLayout.tsx +++ b/src/layouts/MainLayout.tsx @@ -1,14 +1,34 @@ -import React from 'react'; +import React, { useState, useEffect } from 'react'; import { Link, Outlet, useLocation } from '@tanstack/react-router'; import { cn } from '@/lib/utils'; import { StatusBar } from '@/components/StatusBar'; -import { LayoutDashboard, Settings, Network, Rocket } from 'lucide-react'; +import { + LayoutDashboard, + Settings, + Network, + Rocket, + ChevronLeft, + ChevronRight, +} from 'lucide-react'; import { useTranslation } from 'react-i18next'; +import { Button } from '@/components/ui/button'; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'; export const MainLayout: React.FC = () => { const location = useLocation(); const { t } = useTranslation(); + // Initialize state from localStorage if available, default to false (expanded) + const [isCollapsed, setIsCollapsed] = useState(() => { + const saved = localStorage.getItem('sidebar-collapsed'); + return saved ? JSON.parse(saved) : false; + }); + + // Persist state changes + useEffect(() => { + localStorage.setItem('sidebar-collapsed', JSON.stringify(isCollapsed)); + }, [isCollapsed]); + const navItems = [ { to: '/', @@ -31,42 +51,104 @@ export const MainLayout: React.FC = () => {
{/* Sidebar */} -
+
+
+ Manager +
+
+ + -
- +
+
{/* Content Area */} -
+
diff --git a/src/lib/antigravity/ClaudeRequestMapper.ts b/src/lib/antigravity/ClaudeRequestMapper.ts index c240630..249ef10 100644 --- a/src/lib/antigravity/ClaudeRequestMapper.ts +++ b/src/lib/antigravity/ClaudeRequestMapper.ts @@ -51,7 +51,7 @@ export function transformClaudeRequestIn( const toolIdToName = new Map(); // 1. System Instruction - let systemInstruction = buildSystemInstruction(claudeReq.system, claudeReq.model); + const systemInstruction = buildSystemInstruction(claudeReq.system, claudeReq.model); // Map model name const mappedModel = hasWebSearchTool @@ -100,7 +100,7 @@ export function transformClaudeRequestIn( ); // 3. Tools - let tools = buildTools(claudeReq.tools, hasWebSearchTool); + const tools = buildTools(claudeReq.tools, hasWebSearchTool); // 5. Safety Settings const safetySettings = [ @@ -152,7 +152,7 @@ export function transformClaudeRequestIn( delete innerRequest.systemInstruction; // 3. Clean generationConfig - let genConfig = innerRequest.generationConfig || {}; + const genConfig = innerRequest.generationConfig || {}; delete genConfig.thinkingConfig; delete genConfig.responseMimeType; delete genConfig.responseModalities; diff --git a/src/lib/antigravity/JsonSchemaUtils.ts b/src/lib/antigravity/JsonSchemaUtils.ts index 778cc86..b2bb11c 100644 --- a/src/lib/antigravity/JsonSchemaUtils.ts +++ b/src/lib/antigravity/JsonSchemaUtils.ts @@ -67,7 +67,7 @@ function flattenRefs(map: any, defs: Record) { // Recursively process all children for (const k in map) { - if (map.hasOwnProperty(k)) { + if (Object.prototype.hasOwnProperty.call(map, k)) { const v = map[k]; if (typeof v === 'object' && v !== null) { flattenRefs(v, defs); @@ -91,7 +91,7 @@ function cleanJsonSchemaRecursive(value: any) { // 1. Recursively process all children first to ensure nested structures are cleaned for (const k in map) { - if (map.hasOwnProperty(k)) { + if (Object.prototype.hasOwnProperty.call(map, k)) { cleanJsonSchemaRecursive(map[k]); } } diff --git a/src/localization/i18n.ts b/src/localization/i18n.ts index 2b119d4..56a983c 100644 --- a/src/localization/i18n.ts +++ b/src/localization/i18n.ts @@ -337,8 +337,10 @@ i18n generic: '发生未知错误。', keychainUnavailable: 'Keychain 不可用。', keychainHint: { - translocation: '检测到 macOS App Translocation。请将应用移动到 /Applications 后重试。', - keychainDenied: 'Keychain 访问被拒绝。应用可能未签名,可参考 README 的“macOS 自签”说明。', + translocation: + '检测到 macOS App Translocation。请将应用移动到 /Applications 后重试。', + keychainDenied: + 'Keychain 访问被拒绝。应用可能未签名,可参考 README 的“macOS 自签”说明。', signNotarize: '请在可用时使用已签名并公证的版本。', }, dataMigrationFailed: '旧版账号数据无法解密。', diff --git a/src/routes/settings.tsx b/src/routes/settings.tsx index 28d1ddb..a719ee4 100644 --- a/src/routes/settings.tsx +++ b/src/routes/settings.tsx @@ -33,6 +33,7 @@ function SettingsPage() { // Sync config to local state when loaded useEffect(() => { if (config) { + // eslint-disable-next-line setProxyConfig(config.proxy); } }, [config]); diff --git a/src/utils/protobuf.ts b/src/utils/protobuf.ts index 3660e90..b4e0ddf 100644 --- a/src/utils/protobuf.ts +++ b/src/utils/protobuf.ts @@ -40,9 +40,11 @@ export class ProtobufUtils { return this.readVarint(data, offset).nextOffset; case 1: // 64-bit return offset + 8; - case 2: // Length-delimited + case 2: { + // Length-delimited const { value: length, nextOffset } = this.readVarint(data, offset); return nextOffset + Number(length); + } case 5: // 32-bit return offset + 4; default: diff --git a/src/utils/security.ts b/src/utils/security.ts index b44c37f..ccafc0d 100644 --- a/src/utils/security.ts +++ b/src/utils/security.ts @@ -446,9 +446,7 @@ export async function decryptWithMigration( ); } if (reencrypted) { - logger.info( - `Security: Re-encrypted data from ${fallback.source} to ${primary.source}`, - ); + logger.info(`Security: Re-encrypted data from ${fallback.source} to ${primary.source}`); } return { value, reencrypted, usedFallback: fallback.source }; } catch {