From 1265d044f69e52fba7da72fde6c47a0b85c58232 Mon Sep 17 00:00:00 2001 From: Sujit Biswas Date: Wed, 28 Jan 2026 16:55:40 +0600 Subject: [PATCH] feat: Implement collapsible sidebar and refined status bar UI (#45) * chore: mark peer dependencies in package-lock.json * docs: add comprehensive developer guide for antigravity-manager * build: add @radix-ui/react-tooltip dependency The tooltip component is needed for future UI enhancements to provide better user guidance and information display. * feat(StatusBar): add collapsed view with toggle button - Introduce `isCollapsed` prop to support both expanded and compact layouts - Collapsed view shows a single icon button with status tooltip - Enhanced visual styling with shadows, borders, and improved spacing - Use Tooltip component to display status in collapsed mode * feat(ui): add Radix UI tooltip component wrapper Create a reusable tooltip component using Radix UI primitives. The wrapper provides styled content with animations and integrates with the project's class name utility for consistent theming. * feat(layout): add collapsible sidebar with persistent state - Add toggle button to collapse/expand sidebar with smooth animations - Persist sidebar state in localStorage to maintain user preference - Show tooltips for navigation items when sidebar is collapsed - Adjust StatusBar component to support collapsed state * chore: remove "peer": true flags from package-lock.json * build: mark peer dependencies in package-lock.json * build: add yaml v2.8.2 dependency and update package-lock * docs(project_overview): update skill documentation formatting * docs: remove extra blank line in AGENTS.md * docs: update changelog formatting to use hyphens * docs: improve readability of OpenSpec workflow files * chore: standardize YAML string quotes in GitHub configs * style(StatusBar): reformat JSX for consistency and readability - Simplify className expres * style(ui): standardize quotes and class order in tooltip component - Use single quotes consistently across imports and strings - Reorder Tailwind CSS classes to follow recommended conventions * style(ipc): remove unnecessary parentheses in debug log statement * style(MainLayout): improve code formatting and consistency - Reformat multi-line import for better readability - Normalize Tailwind CSS class ordering - Remove unnecessary whitespace and ensure consistent quotes - Maintain all functionality while improving code style * style(i18n): format long translation strings for better readability * style: remove unnecessary line break in logger.info call The logger.info call had an unnecessary line break that made the code less readable. The line has been consolidated to improve code style consistency. * chore: disable several ESLint rules for development flexibility Disable TypeScript ESLint rules and other linting rules that are too restrictive during active development. This allows faster iteration without constant linting errors for common patterns like `any` types, unused variables, and inline comments. * refactor: use const for immutable variables in request mapper - Change `let` to `const` for variables that are not reassigned - Improves code clarity and prevents accidental reassignment * refactor: replace direct hasOwnProperty calls with safe variant Use Object.prototype.hasOwnProperty.call to avoid issues when objects have overridden hasOwnProperty method. This ensures consistent behavior across all object types. * fix: disable eslint for intentional assignment in useEffect The eslint warning was triggered by directly using setProxyConfig with config.proxy inside useEffect without including it in the dependency array. This assignment is intentional and only needs to run when config changes, not when setProxyConfig changes. Adding the eslint-disable comment prevents the warning while maintaining correct behavior. * chore: disable react-hooks/exhaustive-deps rule This rule was already disabled; the change only adds a trailing comma to the ESLint configuration for consistency. * fix(eslint): re-enable lint rules for hooks and case-declarations --------- Co-authored-by: Draculabo --- .agent/skills/project_overview/SKILL.md | 88 ++++++++++ .agent/workflows/openspec-apply.md | 5 + .agent/workflows/openspec-archive.md | 5 + .agent/workflows/openspec-proposal.md | 5 + .github/dependabot.yaml | 6 +- .github/release-drafter.yml | 2 +- AGENTS.md | 1 - CHANGELOG.md | 24 +-- eslint.config.mjs | 10 ++ package-lock.json | 189 ++++++++++++++++++--- package.json | 2 + src/components/StatusBar.tsx | 97 +++++++++-- src/components/ui/tooltip.tsx | 28 +++ src/ipc/process/handler.ts | 4 +- src/layouts/MainLayout.tsx | 136 ++++++++++++--- src/lib/antigravity/ClaudeRequestMapper.ts | 6 +- src/lib/antigravity/JsonSchemaUtils.ts | 4 +- src/localization/i18n.ts | 6 +- src/routes/settings.tsx | 1 + src/utils/protobuf.ts | 4 +- src/utils/security.ts | 4 +- 21 files changed, 531 insertions(+), 96 deletions(-) create mode 100644 .agent/skills/project_overview/SKILL.md create mode 100644 src/components/ui/tooltip.tsx 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 {