commit 83c52bc0115e662ac1d387971e3ab2feb9b31254 Author: Zero Date: Sat May 16 10:01:25 2026 -0500 Initial extract: templates + methodology guide from Ideation Public, version-controlled source of truth for TeamIDE's project templates, coding conventions, and the build-plan → PM scaffolding rules. Mounted read-only by TeamIDE's planner agent at runtime. Extracted from the personal Ideation repo as a precondition for workspace-projects-agent-spec.md §9.4. Personal Ideation stays private; this repo holds only the publishable methodology. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d316085 --- /dev/null +++ b/LICENSE @@ -0,0 +1,27 @@ +MIT Transparency License + +Copyright (c) Corey Herrera + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software without any modification, +exemption or additional provision. All operational distributions, including +executables, embedded installations, package repositories, container images, +and network deployments must preserve their users' access to original source, +documentation, build scripts, configuration, and modifications necessary to +reproduce the intended implementation, in order to promote operational +transparency for the betterment of humanity. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f7d3893 --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +# TeamIDE Methodology + +Project templates, coding conventions, and the build-plan → PM scaffolding rules that [TeamIDE](https://teamide.dev)'s planner agent reads at run time. + +This repo is the public, version-controlled source of truth for **how a TeamIDE project gets shaped**: + +- `claude.md` — the methodology guide: how to plan a project, the spec/plan/PM-file pipeline, naming conventions, the file structure every project follows, and the docs/InternalDocs split. +- `templates/coding-best-practices.md` — universal coding rules (descriptive names, small functions, library-first design, file-header convention, no auto-save). +- `templates/claude.md` — the standard project CLAUDE.md template (copied and customized into every new project). +- `templates/TauriStarter/` — a working Tauri + Quasar + Vite desktop-app starter. +- `templates/ResearchStarter/` — a hypothesis-first R&D starter. +- `templates/teamide/` — `.teamide/project.yml` and `.teamide/plans/` / `.teamide/tasks/` scaffolding. +- `templates/docs/` — documentation templates (`feature-*.md`, `getting-started.md`, etc.). + +## How TeamIDE consumes this + +TeamIDE clones this repo to `~/TeamIDE/.data/methodology/` on first launch and refreshes it on demand (manual button in the planner UI, or `git pull` on app start — TBD). The planner agent has **read-only** access to this directory. Writes outside its working dir are forbidden by the prompt. + +If you want to customize TeamIDE's planner with your own templates or conventions, fork this repo and point TeamIDE at your fork (configurable in the planner settings). + +## Status + +Living document — extracted from an earlier private repo on 2026-05-16 to support TeamIDE's planner/conductor agent pipeline (see TeamIDE's `workspace-projects-agent-spec.md` §9.4). + +## License + +[MIT Transparency License](./LICENSE) — same as TeamIDE itself. diff --git a/claude.md b/claude.md new file mode 100644 index 0000000..ae3e859 --- /dev/null +++ b/claude.md @@ -0,0 +1,1048 @@ +# Ideas Repo - Project Planning & Scaffolding + +This repo is for discussing, planning, and scaffolding project ideas. **No actual development happens here** - once a project is set up, it gets cloned elsewhere for building. + +## Related Workspaces + +| Workspace | Path | Purpose | +| ---------- | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | +| Tech Radar | /Users/davidherrera/TeamIDE/dcherrera/tech-radar | Personal tech radar for evaluating tools and technologies. Reference files here when making tech stack decisions for new projects. | + +## Purpose + +When the user comes here with a project idea: + +1. Discuss and refine the idea + +2. **Create the project folder FIRST** (e.g., `mkdir ProjectName`) + +3. Create planning docs inside the project folder: + + - **App projects:** `build_spec.md` and `build_plan.md` + + - **Research projects:** `goals.md` and optionally `spec.md` + +4. Scaffold the rest of the project (CLAUDE.md, structure, etc.) + +5. Init git, create GitHub repo, push + +6. Delete from this workspace (project now lives in its own repo) + +## CRITICAL: Project Folder Rule + +**ALWAYS create a project folder FIRST before writing any spec or plan files.** + +``` +# CORRECT - create folder first, then files inside it +mkdir /path/to/workspace/ProjectName +# App projects: create build_spec.md and build_plan.md INSIDE ProjectName/ +# Research projects: create goals.md and spec.md INSIDE ProjectName/ + +# WRONG - never create spec/plan files at the workspace root +# Don't do: /path/to/workspace/build_spec.md +# Don't do: /path/to/workspace/goals.md +``` + +Every project gets its own folder from the very beginning. Planning docs (`build_spec.md`/`build_plan.md` for apps, `goals.md`/`spec.md` for research) belong inside that project folder, not at the workspace root. + +## Templates Location + +``` +Ideation/templates/ +├── claude.md # Standard project guidelines (copy + customize) +├── coding-best-practices.md # Coding conventions & style guide (copy as-is, read at Phase 1) +├── README.md # Standard README structure (copy + customize) +├── LICENSE # MIT Transparency License (copy as-is) +├── .gitignore # Standard ignores (copy as-is) +├── build.sh # Build script template (copy + customize app config) +├── scripts/ +│ └── console-logger.ts # Tauri console logging boot file +├── docs/ # Documentation templates +│ ├── README.md # Docs index with table of contents +│ ├── TEMPLATE-feature.md # Template for feature documentation +│ ├── getting-started.md # Installation & setup guide +│ ├── architecture.md # Tech stack & architecture +│ ├── development.md # Development workflow guide +│ └── deployment.md # Build & deployment guide +│ +│ # Starter Templates (complete working projects) +├── TauriStarter/ # Tauri + Quasar + Vite desktop app +├── ResearchStarter/ # R&D / research / experimental projects +├── [FutureStarter]/ # More starter templates to come... +│ +│ # TeamIDE PM integration +└── teamide/ + ├── project.yml # .teamide/project.yml template (copy + update name) + └── README.md # Explanation of PM file generation +``` + +### Starter Templates + +Starter templates are complete, working projects ready to build immediately. Each includes its own CLAUDE.md with full project guidelines. + +| Template | Use Case | +| --------------- | --------------------------------------------------- | +| TauriStarter | Cross-platform desktop apps (macOS, Windows, Linux) | +| ResearchStarter | Research, experiments, and R&D investigations | +| More coming... | Web apps, native iOS/macOS, etc. | + +## Workflow: Using a Starter Template + +Use this workflow when a starter template exists for your project type (e.g., TauriStarter for desktop apps). + +### Phase 1: Planning (in Ideation) + +1. **Discuss the idea** - Refine requirements, features, scope + +2. **Create the spec** - Write `build_spec.md` covering everything about the app + +3. **Create the plan** - Write `build_plan.md` with phased task checklist + +**For ResearchStarter projects:** Write `goals.md` (success criteria, anti-goals, kill gates) instead of `build_spec.md`. Optionally write `spec.md` if there's a concrete system to design. Milestone planning uses `docs/TEMPLATE-milestone.md` instead of `build_plan.md`. + +### Phase 2: Scaffolding (in Ideation) + +#### 1\. Copy the starter template + +``` +cp -r /Users/davidherrera/Obsidian/Ideation/templates/[StarterTemplate] /Users/davidherrera/Obsidian/Ideation/[ProjectName] +cd /Users/davidherrera/Obsidian/Ideation/[ProjectName] +cp ../templates/coding-best-practices.md ./coding-best-practices.md +``` + +#### 2\. Add spec and plan files + +**App projects:** \`\`\`bash + +# Move/copy the spec and plan we created during planning + +mv ../build_spec.md ./build_spec.md mv ../build_plan.md ./build_plan.md \`\`\` + +**Research projects (ResearchStarter):** The template already includes `goals.md` and `spec.md` — just fill them in with the content from Phase 1 planning. No need to move files. + +#### 2.5. Generate TeamIDE PM files + +Generate `.teamide/` project management files from `build_plan.md` so the project arrives at its dev repo with a ready-made task board. See the **TeamIDE PM Files** section below for the full conversion rules. + +1. Copy `templates/teamide/project.yml` to `[ProjectName]/.teamide/project.yml` and update the `name:` field + +2. Create `.teamide/plans/` and `.teamide/tasks/` directories + +3. For each Phase heading in `build_plan.md`, create a plan file in `.teamide/plans/` + +4. For each task line in `build_plan.md`, create a task file in `.teamide/tasks/` linked to its plan + +**Research projects:** Use milestones from `docs/` instead of phases from `build_plan.md`. Each milestone becomes a plan, each task within it becomes a task file. + +#### 3\. Customize the project + +Each starter template has a **Customization Checklist** in its CLAUDE.md. Follow that checklist to update project name, identifiers, etc. + +#### 4\. Customize CLAUDE.md + +Edit the "Project-Specific Configuration" section at the bottom with: + +- Project name + +- Description + +- Backend URLs (if applicable) + +- Database schema (if applicable) + +- TeamIDE workspace ID (if applicable) + +#### 5\. Configure .gitignore for repo visibility + +See "Project Dev Files" section below for private vs public repos. + +#### 6\. Initialize git and create GitHub repo + +``` +git init +git add -A +git commit -m "Initial project setup" +gh repo create dcherrera/[ProjectName] --private --source=. --push --description "Brief description" +``` + +**Note**: All repos are created under `dcherrera` and are **private** by default. + +### Phase 3: Development (outside Ideation) + +#### 1\. Clone to development folder + +``` +cd ~/Software # or wherever you do development +git clone https://github.com/dcherrera/[ProjectName].git +cd [ProjectName] +``` + +#### 2\. Install dependencies and start building + +Follow the starter template's README or CLAUDE.md for build instructions. + +**From this point on, all development happens in the cloned repo, not in Ideation.** + +#### 3\. Clean up Ideation + +After cloning, remove the scaffolded project from Ideation: + +``` +rm -rf /Users/davidherrera/Obsidian/Ideation/[ProjectName] +``` + +Ideation's job is done - the project now lives in its own repo. + +## Workflow: Creating a Project Without a Starter Template + +Use this when no starter template exists for your project type. You'll copy individual template files instead. + +### Phase 1: Planning (in Ideation) + +Same as above - discuss, create spec, create plan. + +### Phase 2: Scaffolding (in Ideation) + +#### 1\. Create the project folder + +``` +mkdir /Users/davidherrera/Obsidian/Ideation/[ProjectName] +cd /Users/davidherrera/Obsidian/Ideation/[ProjectName] +``` + +#### 2\. Copy base templates + +``` +cp ../templates/claude.md ./CLAUDE.md +cp ../templates/coding-best-practices.md ./coding-best-practices.md +cp ../templates/README.md ./README.md +cp ../templates/LICENSE ./LICENSE +cp ../templates/.gitignore ./.gitignore +cp -r ../templates/docs ./docs +mkdir -p screenshots app InternalDocs +touch app/.gitkeep +``` + +#### 3\. Add spec and plan, customize, create repo + +Same as starter template workflow steps 2-6 (including step 2.5 — generate TeamIDE PM files). + +### Phase 3: Development (outside Ideation) + +Same as starter template workflow - clone to dev folder, build there, clean up Ideation. + +## Project Structure (Required) + +Every project follows this structure for future modularity: + +``` +ProjectName/ # git root +├── README.md # Public-facing documentation (for GitHub + portfolio) +├── LICENSE # MIT Transparency License +├── CLAUDE.md # Project guidelines + config +├── coding-best-practices.md # Coding conventions (read before Phase 1) +├── build_spec.md # Full project specification +├── build_plan.md # Phased task checklist +├── .gitignore +├── docs/ # Public-facing documentation (parsed to HTML for website) +│ ├── README.md # Docs index with table of contents +│ ├── getting-started.md +│ ├── architecture.md +│ ├── development.md +│ ├── deployment.md +│ └── feature-*.md # Feature documentation (added per phase) +├── InternalDocs/ # Internal development documentation (not public) +│ └── ... # Design decisions, technical debt, internal API docs +├── screenshots/ # Project screenshots +│ ├── hero.png # Main screenshot (used in portfolio card) +│ ├── demo.gif # Animated demo (optional) +│ └── feature-*.png # Feature-specific screenshots +└── app/ # ALL project code lives here + ├── src/ + ├── src-tauri/ # For Tauri apps + ├── nhost/ # For Nhost backend + ├── docker-compose.yml + └── ... +``` + +**Why this structure?** The goal is modularity - eventually enabling drag-and-drop of components between projects. The `app/` subfolder keeps code separate from planning docs. `docs/` is public-facing (parsed to HTML for the website). `InternalDocs/` is for internal development context only. + +### Research Project Variant + +Research projects (using ResearchStarter) follow a different structure: + +``` +ProjectName/ # git root +├── README.md # Project overview +├── LICENSE # MIT Transparency License +├── CLAUDE.md # Project guidelines + config +├── coding-best-practices.md # Coding conventions (read before Phase 1) +├── goals.md # Success criteria (replaces build_spec.md) +├── spec.md # Technical specification (optional) +├── conclusions.md # Living findings document +├── open_questions.md # Unresolved questions tracker +├── .gitignore +├── experiments/ # Experiment code (numbered runs) +├── results/ # Experiment results documentation +├── data/ # Datasets (gitignored) +├── literature/ # Paper notes & prior art +├── src/ # Implementation code (when research produces software) +├── tests/ # Test suite +├── docs/ # Public-facing documentation (parsed to HTML for website) +│ ├── README.md +│ ├── getting-started.md +│ └── architecture.md +├── InternalDocs/ # Internal development documentation (not public) +│ └── ... +└── screenshots/ # Visuals for README / portfolio +``` + +**Key differences from app projects:** `experiments/` + `src/` replace `app/`, `goals.md` replaces `build_spec.md`, milestone-based planning replaces `build_plan.md`, and `results/`/`literature/`/`conclusions.md`/`open_questions.md` support the research workflow. + +## Standard Tech Stack (Default) + +**Tauri Desktop Apps (use TauriStarter):** + +- **Frontend**: Quasar Framework (Vue 3) + Vite + +- **Desktop**: Tauri (Rust) - Cross-platform builds (macOS, Windows, Linux) + +- **State**: Pinia + +- **Backend** (optional): Nhost (self-hosted or cloud) + +**Web Apps:** + +- **Frontend**: Quasar Framework (Vue 3) - SPA mode + +- **Backend**: Nhost (self-hosted via Docker) + + - PostgreSQL, Hasura GraphQL, Auth, Storage, Functions + +- **Containerization**: Docker / Docker Compose + +**Native Apps (when needed):** + +- **macOS/iOS**: Swift, SwiftUI, AppKit/UIKit + +- **Cross-platform**: Evaluate per project + +## Starter Template: TauriStarter + +For cross-platform desktop apps (macOS, Windows, Linux). + +The TauriStarter template includes: + +- **Working Tauri + Quasar + Vite setup** - Ready to build immediately + +- **Console logging** - Frontend `console.log()` captured to log files + +- **Build script** - `./build.sh -dev -open` for consistent builds + +- **Placeholder icons** - All platform icons included (replace with your own) + +- **Full CLAUDE.md** - Complete project guidelines including: + + - Build script documentation + + - Testing changes reminders + + - Database/Nhost rules (if using backend) + + - Commit rules + + - Customization checklist + +### Build Script (build.sh) + +All Tauri projects use the standardized `build.sh` script: + +``` +cd app +./build.sh -dev -open # Build dev and open app +./build.sh -prod # Build prod and install to ~/Applications +./build.sh logs # View latest console log (last 100 lines) +./build.sh clean # Clean build artifacts (preserves logs) +./build.sh clean-logs # Remove all logs +``` + +**Key features:** + +- **Build-and-run** - No hot reload, but dev = prod (what you test = what ships) + +- **Separate dev/prod** - Different bundle IDs, can run simultaneously + +- **Automatic logging** - All build and console output saved to `build/logs/` and `build/console/` + +- **Non-blocking** - Script exits after launching app + +### Console Logging + +Frontend `console.log()` is automatically captured: + +``` +console.log() → console-logger.ts → invoke('log_to_stdout') → Rust println!() → stdout → build.sh logs +``` + +**When debugging issues:** + +1. Run `./build.sh logs` to see last 100 lines of console output + +2. Full logs: `cat build/console/console_latest.log` + +3. Build errors: `cat build/logs/build_latest.log` + +## Starter Template: ResearchStarter + +For research, experiments, and R&D investigations. + +The ResearchStarter template includes: + +- **Full R&D methodology** - Hypothesis-first workflow, kill gates, experiment tracking + +- **Structured experiment tracking** - Numbered runs, results docs, literature reviews + +- **Research planning files** - `goals.md`, `spec.md`, `conclusions.md`, `open_questions.md` + +- **Templates for everything** - Experiment plans, results docs, paper reviews, milestones + +- **Full CLAUDE.md** - Complete research methodology including: + + - Research pipeline and document layers + + - 11 key principles (hypothesis-first, kill gates, constraint-driven design, etc.) + + - Experiment naming conventions and results documentation rules + + - Milestone format with dependency graphs + + - Customization checklist + +### Key Differences from App Templates + +| Aspect | App Templates (TauriStarter) | ResearchStarter | +| ------------- | ----------------------------- | -------------------------------------------------- | +| Planning | build_spec.md + build_plan.md | goals.md + milestone plans | +| Code location | app/ | experiments/ + src/ | +| Feature docs | docs/feature-*.md | results/experiment_N_results.md | +| Doc templates | TEMPLATE-feature.md | TEMPLATE-experiment-plan.md, TEMPLATE-milestone.md | +| Extra files | — | conclusions.md, open_questions.md, literature/ | +| Methodology | Build-and-ship | Hypothesis → experiment → analyze → conclude | + +## build_spec.md Format + +> **Research projects:** Use `goals.md` instead. It covers success criteria, anti-goals, kill gates, and fallback plans. See the ResearchStarter template. + +The spec should cover everything about the app: + +- Problem it solves + +- Target users + +- All features and functionality + +- User flows + +- Data model / entities + +- Integrations + +- UI/UX requirements + +- Any constraints or requirements + +## build_plan.md Format + +> **Research projects:** Use milestone-based planning instead. See `docs/TEMPLATE-milestone.md` in the ResearchStarter template for the format, including dependency graphs and kill gates. + +Phased task list with checkboxes. **Each phase ends with documentation and a plan update.** + +**Every phase MUST end with these three steps:** + +1. **Document** — Update both `docs/` (public) and `InternalDocs/` (internal) as appropriate + +2. **Update build plan** — Check off completed tasks in `build_plan.md`, note any scope changes, deferred items, or new tasks discovered during the phase + +3. **Update PM tasks** — Mark completed `.teamide/tasks/` files as `status: done`. When all tasks in a plan are done, update the plan's status. If new tasks were discovered, create new task files and add them to the plan. + +``` +# Build Plan: [Project Name] + +## Phase 1: Foundation +- ☐ **Read `coding-best-practices.md`** before writing any code +- ☐ Initialize project from TauriStarter +- ☐ Customize app name and icons +- ☐ Set up backend (if needed) +- ☐ ... +- ☐ **Document**: Update `docs/getting-started.md` and `docs/architecture.md`. Add initial design decisions to `InternalDocs/` +- ☐ **Update plan & tasks**: Check off completed tasks in this file. Update `.teamide/tasks/` statuses to `done`. Note any changes or deferred items. + +## Phase 2: Core Features +- ☐ Task 1 +- ☐ Task 2 +- ☐ ... +- ☐ **Document**: Create `docs/feature-[name].md`, update docs index. Add internal API docs or design decisions to `InternalDocs/` +- ☐ **Update plan & tasks**: Check off completed tasks in this file. Update `.teamide/tasks/` statuses to `done`. Note any changes or deferred items. + +## Phase 3: [Feature Name] +- ☐ Task 1 +- ☐ Task 2 +- ☐ ... +- ☐ **Document**: Create `docs/feature-[name].md`, update docs index. Add internal API docs or design decisions to `InternalDocs/` +- ☐ **Update plan & tasks**: Check off completed tasks in this file. Update `.teamide/tasks/` statuses to `done`. Note any changes or deferred items. + +## Phase N: Polish & Release +- ☐ Final testing +- ☐ ... +- ☐ **Document**: Review and finalize all `docs/`. Review `InternalDocs/` for accuracy, update `docs/deployment.md` +- ☐ **Update plan & tasks**: Final review — all tasks checked off and marked `done`, deferred items documented, plan status updated to `complete` +``` + +## TeamIDE PM Files + +When scaffolding a project, generate `.teamide/` files from `build_plan.md` so the project has a ready-made task board when cloned. + +### Directory Structure + +Every phase lives inside a **plan group folder** under `plans/`. The group folder represents the larger plan (e.g. "initial build", "v2 refactor") that owns those phases. TeamIDE's Plans tab renders one card per group; clicking the card drills into the phase list. + +``` +ProjectName/.teamide/ +├── project.yml # Project config (from template) +├── plans/ +│ └── / # One folder per larger plan +│ ├── phase-1-slug.md # One per build_plan.md phase +│ └── phase-2-slug.md +└── tasks/ + ├── task-slug-a.md # One per checkbox line (flat — tasks are not nested) + └── task-slug-b.md +``` + +For a single-plan project, use a single group folder named after the project's primary plan (default: `build`): + +``` +.teamide/plans/build/ +├── phase-1-foundation.md +├── phase-2-core-features.md +└── phase-3-polish.md +``` + +For a multi-plan project, use a `# Plan:` H1 divider in `build_plan.md` (see Multi-Plan Projects below) and create one folder per `# Plan:` heading. + +### Conversion Rules + +**Mapping:** + +| build_plan.md | .teamide/ | +| ---------------------------------- | ----------------------------------------------- | +| `# Plan: ` H1 heading | plans// (folder) | +| `## Phase N: ` heading | plans//phase-N-slug.md | +| `- [ ]` task line | tasks/task-slug.md | +| First phase in any group | Plan status: active | +| Subsequent phases | Plan status: draft | +| Phase number (N) | Plan order: N | +| Task position within phase | Task order: 1, 2, 3... | +| All tasks | Task status: backlog | +| Sub-bullets / context under a task | Task markdown body | + +**Slugification:** Lowercase, spaces to hyphens, strip special characters, `.md` extension. Example: `## Phase 3: iCloud Sync` → `phase-3-icloud-sync.md`, `- [ ] Create CameraManager class` → `create-cameramanager-class.md`. Plan group slugs follow the same rule: `# Plan: Initial Build` → `initial-build/`. + +**Default group slug:** if `build_plan.md` has no `# Plan:` headings, generate everything under `plans/build/`. + +### Multi-Plan Projects + +When a project has more than one larger plan (e.g. the initial build *and* a follow-on refactor), use `# Plan:` H1 dividers in `build_plan.md`. Each `# Plan:` opens a new group folder; every `## Phase` below it lands inside that folder. + +``` +# Plan: Initial Build +## Phase 1: Foundation +- [ ] Set up Tauri project +## Phase 2: Core CRUD +- [ ] Build user model + +# Plan: v2 Refactor +## Phase 1: Schema Migration +- [ ] Add new user_roles table +``` + +Generates: + +``` +.teamide/plans/ +├── initial-build/ +│ ├── phase-1-foundation.md +│ └── phase-2-core-crud.md +└── v2-refactor/ + └── phase-1-schema-migration.md +``` + +Phase numbering restarts within each group. Task back-references (`plan:` frontmatter) still use the phase file's basename — keep phase filenames globally unique across groups for now (e.g. `phase-1-foundation.md` vs `phase-1-schema-migration.md`). + +### Plan File Format + +`.teamide/plans/phase-N-slug.md`: + +``` +--- +title: "Phase N: Phase Name" +status: active +order: 1 +tasks: + - task-slug-a.md + - task-slug-b.md +--- +Phase description (optional — copy any paragraph text below the phase heading in build_plan.md). +``` + +- Phase 1 gets `status: active`, all others get `status: draft` + +- `order:` matches the phase number (1, 2, 3...) for correct display ordering + +- `tasks:` lists all task filenames belonging to this phase + +### Task File Format + +`.teamide/tasks/task-slug.md`: + +``` +--- +title: Task description from the checkbox line +status: backlog +plan: phase-N-slug.md +order: 1 +--- +Context and details about this task go here. + +- Implementation note or sub-step +- Another detail or consideration +- Any relevant technical context +``` + +- `title:` is the text after `- [ ]` in build_plan.md + +- `plan:` back-references the parent plan filename (bidirectional link) + +- `order:` sequential number (1-based) controlling display order within the plan + +- All tasks start as `status: backlog` + +- **The body MUST contain context** — any sub-bullets, notes, or detail text beneath the task line in `build_plan.md` belongs in the task body. If the plan has context like implementation notes, API details, or technical considerations under a task, that content goes in the markdown body of the task file. Empty task bodies are not acceptable. + +### System-managed timestamps + +TeamIDE's backend auto-manages four timestamp fields on every PM file. **Scaffolding flows MUST NOT set these** — the backend stamps them on every write. Documented here so you understand the data shape and don't accidentally include them in generated files. + +| Field | Format | When set | +|---|---|---| +| `created_at` | ISO 8601 UTC (`2026-05-15T14:30:00.000Z`) | Once, at file creation. Never updated. | +| `updated_at` | ISO 8601 UTC | Every write (PUT or PATCH). | +| `status_changed_at` | ISO 8601 UTC | Any write that changes `status`. | +| `finished_at` | ISO 8601 UTC, or absent | Set when `status` transitions to `done`. Cleared when transitioning back off `done`. Reflects current state, not history. | + +Scaffolded task files should leave all four absent. The first PATCH or PUT through TeamIDE adds them. For brand-new task files written directly to disk (e.g. an agent creating tasks during a run), TeamIDE will fill `created_at`, `updated_at`, and `status_changed_at` on next read/edit. + +### User-editable date fields + +Tasks may carry two user-editable date fields, both stored as ISO 8601 UTC: + +| Field | Meaning | +|---|---| +| `start_date` | When work on the task is scheduled to begin. Optional. Used by the timeline view to position the start of a task's range. | +| `due_date` | When the task is due. Optional. Used by table / kanban / timeline / calendar for scheduling and urgency colors. Replaces the legacy `due:` field. Both `start_date` and `due_date` are optional — tasks without dates show in "Unscheduled" lanes on the timeline. | + +Format examples: + +```yaml +start_date: 2026-05-15T00:00:00.000Z # date only, no specific time +due_date: 2026-05-20T14:30:00.000Z # specific time +``` + +When the time component is midnight UTC, TeamIDE renders the chip as date-only ("05/15/2026"). When the time is set, the chip shows date and time ("05/15/2026 2:30 PM"). Storage is always full ISO; display is US format. + +**Legacy compatibility**: files using the old `due:` field continue to render correctly. On next save through TeamIDE the field is renamed to `due_date`. No migration script needed. + +### Soft-deleted files (`deleted_at`) + +TeamIDE's PM views (kanban, table, timeline, calendar, activity feed) recognize an optional `deleted_at` frontmatter field on any plan/task/note file. When set to an ISO timestamp, the file is treated as "trashed" — it stays on disk and in git history but is filtered out of every PM view. + +- **Scaffolding** — do NOT include `deleted_at` when generating plan/task files from a build plan. New files start visible. + +- **Soft-delete trigger** — only the user can soft-delete (via "Move to Trash" in the PM file editor, the upcoming bulk-delete in the table view, or any other PM surface). Agents and scaffolding flows should never write `deleted_at` themselves. + +- **Recovery** — open the file in the Code module's file tree and either remove the entire `deleted_at: ...` line (recommended — cleanest) or blank the value (`deleted_at:` with nothing after it). The filter treats any falsy value as "not deleted" so both work. The file reappears in every view on next reload. + +- **Hard delete** — the only path that physically removes a file is the Code module's file tree. PM surfaces always soft-delete. + +Example trashed task: + +``` +--- +title: Add caching to /pm/all-tasks +status: in-progress +plan: phase-3-caching.md +order: 2 +deleted_at: 2026-05-13T22:14:08Z +--- +Task body still here. +``` + +### project.yml Setup + +1. Copy `templates/teamide/project.yml` to `[ProjectName]/.teamide/project.yml` + +2. Replace `PROJECT_NAME` with the actual project name + +### Example + +Given this `build_plan.md`: + +``` +## Phase 1: Project Setup +- ☐ Create Xcode project + - Use SwiftUI App lifecycle + - Set deployment target to iOS 17+ +- ☐ Configure bundle ID + - Format: com.dcherrera.appname +- ☐ Add dependencies + - AVFoundation, Photos framework + +## Phase 2: Camera Engine +- ☐ Create CameraManager class + - Singleton managing AVCaptureSession + - Handle authorization flow +- ☐ Implement single-camera recording +``` + +Generate (no `# Plan:` headings → default `build` group): + +``` +.teamide/ +├── project.yml +├── plans/ +│ └── build/ +│ ├── phase-1-project-setup.md # status: active, order: 1, tasks: [...] +│ └── phase-2-camera-engine.md # status: draft, order: 2, tasks: [...] +└── tasks/ + ├── create-xcode-project.md # status: backlog, order: 1, plan: phase-1-... + ├── configure-bundle-id.md # status: backlog, order: 2, plan: phase-1-... + ├── add-dependencies.md # status: backlog, order: 3, plan: phase-1-... + ├── create-cameramanager-class.md # status: backlog, order: 1, plan: phase-2-... + └── implement-single-camera-recording.md # status: backlog, order: 2, plan: phase-2-... +``` + +**Task file with body context** — e.g. `create-xcode-project.md`: + +``` +--- +title: Create Xcode project +status: backlog +plan: phase-1-project-setup.md +order: 1 +--- +- Use SwiftUI App lifecycle +- Set deployment target to iOS 17+ +``` + +### Phase Closing Tasks + +At the end of each phase: + +1. **Create public feature docs** — For each significant feature, create `docs/feature-[name].md` using the template + +2. **Update the docs index** — Add links to new docs in `docs/README.md` table of contents + +3. **Update related public docs** — Keep `architecture.md`, `development.md` current as the project evolves + +4. **Update internal docs** — Add design decisions, internal API docs, technical debt notes to `InternalDocs/` + +5. **Update build plan** — Check off completed tasks in `build_plan.md`, note scope changes, deferred items, or new tasks discovered + +6. **Update PM tasks** — Mark completed `.teamide/tasks/` files as `status: done`. When all tasks in a plan are done, update the plan's status to `complete`. Create new task files for any tasks discovered during the phase. + +## Documentation Workflow + +**Every phase ends with documentation.** This ensures features are documented while fresh and the docs stay current. + +### docs/ vs InternalDocs/ + +| Directory | Audience | Purpose | Parsed for website? | +| ------------- | ---------- | ----------------------------------------------------------------------------------------------- | ------------------- | +| docs/ | Public | User-facing app documentation — getting started, features, architecture | Yes | +| InternalDocs/ | Developers | Internal dev context — design decisions, technical debt, internal API contracts, Claude context | No | + +**`docs/`** contains ONLY what the public needs. It gets parsed into HTML and served on the app website. No internal implementation details, no dev-only context. + +**`InternalDocs/`** contains everything internal — design rationale, known technical debt, internal API documentation, integration notes, debugging guides, anything that helps the development team but doesn't belong in public docs. + +Both directories are committed to git. + +### Documentation Structure + +``` +docs/ # Public-facing (parsed to HTML for website) +├── README.md # Index with table of contents (MAIN ENTRY POINT) +├── TEMPLATE-feature.md # Template for new feature docs (don't link this) +├── getting-started.md # Installation & setup +├── architecture.md # Tech stack & design decisions +├── development.md # Development workflow +├── deployment.md # Build & deployment +└── feature-*.md # Feature-specific documentation + +InternalDocs/ # Internal development only (not public) +└── ... # Design decisions, tech debt, internal API docs +``` + +### After Each Phase + +1. **Identify what to document** - New features, components, integrations + +2. **Create feature docs** - Copy `TEMPLATE-feature.md` to `feature-[name].md` + +3. **Update the index** - Add links to `docs/README.md` table of contents + +4. **Update core docs** - Keep `architecture.md`, `development.md` current + +5. **Update internal docs** - Add design decisions, technical debt notes, or internal API docs to `InternalDocs/` as needed + +### Naming Convention + +| Type | Pattern | Example | +| ---------------- | --------------------- | ------------------------- | +| Feature docs | feature-[name].md | feature-authentication.md | +| Component docs | component-[name].md | component-sidebar.md | +| Integration docs | integration-[name].md | integration-nhost.md | +| Guide docs | guide-[topic].md | guide-testing.md | + +### Documentation vs README vs InternalDocs + +| docs/ | README.md | InternalDocs/ | +| ----------------------------- | ------------------------------ | ----------------------------- | +| Public app documentation | High-level overview | Internal dev context | +| Parsed to HTML for website | GitHub / portfolio face | Never published | +| User-facing features & guides | Features list, getting started | Design decisions, tech debt | +| How to use the app | What the app is | How/why it was built this way | + +- **`docs/`** = public documentation, parsed to HTML and served on the app website + +- **`README.md`** = the public face of the project for GitHub and portfolio + +- **`InternalDocs/`** = internal development context, committed but never published + +## README Guidelines + +Every project needs a README.md that serves two purposes: + +1. **GitHub documentation** - For visitors and contributors + +2. **Portfolio content** - Can be pulled into StaticPortfolioGenerator + +### README Structure + +Use the template from `templates/README.md`. Key sections: + +| Section | Purpose | +| --------------- | ------------------------------------------------- | +| Title + Tagline | Project name and one-line description | +| Hero Screenshot | Main visual (hero.png) | +| Overview | 2-3 paragraphs explaining what/why | +| Features | Bulleted list of key features | +| Screenshots | Additional visuals with captions | +| Tech Stack | Technologies used | +| Getting Started | Prerequisites, installation, usage | +| Development | Dev setup instructions | +| Status | Active / Maintained / Paused / Archived / Concept | +| License | Link to LICENSE file | + +### When to Update README + +- **Project creation** - Initialize from template + +- **New features** - Add to Features section + +- **UI changes** - Update screenshots + +- **Status changes** - Update Status section + +- **Before making public** - Full review and polish + +## Screenshots + +Screenshots live in the `screenshots/` folder at the project root. + +### Naming Convention + +| Filename | Purpose | +| ------------------ | ----------------------------------------------------------- | +| hero.png | Main screenshot - used in portfolio cards and README header | +| demo.gif | Animated demo showing the app in action (optional) | +| feature-[name].png | Feature-specific screenshots (e.g., feature-dashboard.png) | + +### Image URLs in README + +Use raw GitHub URLs so images work everywhere: + +``` +![Hero](https://raw.githubusercontent.com/dcherrera/ProjectName/main/screenshots/hero.png) +``` + +### Screenshot Tips + +- **Dimensions**: Aim for 16:9 or 16:10 aspect ratio + +- **Resolution**: 1920x1080 or 1280x720 recommended + +- **Format**: PNG for UI screenshots, GIF for animations + +- **Content**: Show real/realistic data, not lorem ipsum + +- **Dark mode**: Match the app's default theme + +## Commit Rules (for all projects) + +- Never mention Claude, AI, or generated code in commits + +- Write as the developer, first person + +- Concise and descriptive + +## Project Dev Files + +**App projects:** `CLAUDE.md`, `coding-best-practices.md`, `build_spec.md`, `build_plan.md` **Research projects:** `CLAUDE.md`, `coding-best-practices.md`, `goals.md`, `spec.md`, `conclusions.md`, `open_questions.md` + +These files contain project planning and AI assistant context. How to handle them depends on repo visibility: + +### Private Repos (Default) + +**Commit these files to git.** Since the repo is private, there's no risk of exposing internal documentation. + +``` +# .gitignore - DO NOT ignore these files +# CLAUDE.md - tracked +# build_spec.md - tracked +# build_plan.md - tracked +``` + +### Open Source / Public Repos + +**Add these files to .gitignore.** They contain internal development context that shouldn't be public. + +``` +# .gitignore - ADD these lines (app projects) +CLAUDE.md +coding-best-practices.md +build_spec.md +build_plan.md + +# .gitignore - ADD these lines (research projects) +CLAUDE.md +coding-best-practices.md +goals.md +spec.md +conclusions.md +open_questions.md +``` + +**Before making a private repo public:** + +1. Add the files to `.gitignore` + +2. Remove them from git tracking: `git rm --cached CLAUDE.md coding-best-practices.md build_spec.md build_plan.md` (or the research equivalents) + +3. Keep the local copies (they're now untracked) + +4. Commit the `.gitignore` change + +5. Then change repo visibility + +### Summary + +**App projects:** + +| Repo Type | CLAUDE.md | coding-best-practices.md | build_spec.md | build_plan.md | +| ---------- | ---------- | ------------------------ | ------------- | ------------- | +| Private | Commit | Commit | Commit | Commit | +| Public/OSS | .gitignore | .gitignore | .gitignore | .gitignore | + +**Research projects:** + +| Repo Type | CLAUDE.md | coding-best-practices.md | goals.md | spec.md | conclusions.md | open_questions.md | +| ---------- | ---------- | ------------------------ | ---------- | ---------- | -------------- | ----------------- | +| Private | Commit | Commit | Commit | Commit | Commit | Commit | +| Public/OSS | .gitignore | .gitignore | .gitignore | .gitignore | .gitignore | .gitignore | + +## Dockerized Frontend for Production + +When deploying a fully dockerized web project (not Tauri), the frontend needs its own service in docker-compose: + +### 1\. Create `app/Dockerfile.frontend` + +``` +# Build stage +FROM node:20-alpine AS build +WORKDIR /app +COPY package*.json ./ +RUN npm install +COPY . . +RUN npm run build + +# Production stage +FROM nginx:alpine +COPY --from=build /app/dist /usr/share/nginx/html +COPY nginx.conf /etc/nginx/conf.d/default.conf +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] +``` + +### 2\. Create `app/nginx.conf` + +``` +server { + listen 80; + server_name localhost; + root /usr/share/nginx/html; + index index.html; + + location / { + try_files $uri $uri/ /index.html; + } + + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } +} +``` + +### 3\. Add frontend service to `docker-compose.yml` + +``` +frontend: + build: + context: . + dockerfile: Dockerfile.frontend + depends_on: + graphql: + condition: service_healthy + auth: + condition: service_healthy + labels: + traefik.enable: "true" + traefik.http.routers.frontend.rule: Host(`${FRONTEND_URL:-app.localhost}`) + traefik.http.routers.frontend.entrypoints: web + traefik.http.services.frontend.loadbalancer.server.port: "80" + restart: always +``` + +## TeamIDE Hosting + +Projects are deployed via TeamIDE to teamide.dev. + +- Use `teamide_deploy` to deploy changes + +- Use `teamide_set_env_vars` to configure environment variables + +- Use `teamide_get_logs` to check build status + +To get workspace IDs, run: `bash teamide workspace list ` + +Each project should document its workspace ID in the project-specific CLAUDE.md. diff --git a/templates/.gitignore b/templates/.gitignore new file mode 100644 index 0000000..d0c47e3 --- /dev/null +++ b/templates/.gitignore @@ -0,0 +1,32 @@ +# Environment files +.env +.env.* +!.env.example + +# Nhost secrets +app/nhost/.secrets + +# Node +node_modules/ +npm-debug.log* +yarn-error.log* +# Note: Never ignore lock files (package-lock.json, yarn.lock, pnpm-lock.yaml) +# They are required for reproducible builds + +# Build output +dist/ +.quasar/ + +# IDE +.idea/ +.vscode/ +*.swp +*.swo + +# OS +.DS_Store +Thumbs.db + +# Logs +*.log +logs/ diff --git a/templates/LICENSE b/templates/LICENSE new file mode 100644 index 0000000..d316085 --- /dev/null +++ b/templates/LICENSE @@ -0,0 +1,27 @@ +MIT Transparency License + +Copyright (c) Corey Herrera + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software without any modification, +exemption or additional provision. All operational distributions, including +executables, embedded installations, package repositories, container images, +and network deployments must preserve their users' access to original source, +documentation, build scripts, configuration, and modifications necessary to +reproduce the intended implementation, in order to promote operational +transparency for the betterment of humanity. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/templates/README.md b/templates/README.md new file mode 100644 index 0000000..3d7d51b --- /dev/null +++ b/templates/README.md @@ -0,0 +1,73 @@ +# Project Name + +> One-line tagline describing what this project does + +![Hero Screenshot](https://raw.githubusercontent.com/dcherrera/ProjectName/main/screenshots/hero.png) + +## Overview + +Brief description of what the project does and the problem it solves. Keep this to 2-3 paragraphs max. + +Explain the motivation - why does this exist? What pain point does it address? + +## Features + +- **Feature 1** - Brief description +- **Feature 2** - Brief description +- **Feature 3** - Brief description + +## Screenshots + +![Feature Demo](https://raw.githubusercontent.com/dcherrera/ProjectName/main/screenshots/demo.gif) + +![Feature Name](https://raw.githubusercontent.com/dcherrera/ProjectName/main/screenshots/feature-name.png) + +## Tech Stack + +- **Frontend**: Vue 3, TypeScript, Quasar +- **Backend**: Nhost (PostgreSQL, Hasura, Auth) +- **Desktop**: Tauri (if applicable) + +## Getting Started + +### Prerequisites + +- Node.js 18+ +- npm or yarn + +### Installation + +```bash +git clone https://github.com/dcherrera/ProjectName.git +cd ProjectName/app +npm install +``` + +### Usage + +```bash +npm run dev +``` + +## Development + +```bash +# Run development server +npm run dev + +# Build for production +npm run build + +# Run tests +npm test +``` + +## Status + +**Active** - Currently in development + + + +## License + +[MIT Transparency License](LICENSE) diff --git a/templates/ResearchStarter/.gitignore b/templates/ResearchStarter/.gitignore new file mode 100644 index 0000000..492cdf2 --- /dev/null +++ b/templates/ResearchStarter/.gitignore @@ -0,0 +1,64 @@ +# Data files (large, not committed) +data/ + +# Environment files +.env +.env.* +!.env.example + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.egg-info/ +*.egg +dist/ +build/ +.eggs/ +*.whl +venv/ +.venv/ + +# Rust +target/ + +# Node +node_modules/ +npm-debug.log* +yarn-error.log* + +# Model weights & checkpoints +*.pt +*.pth +*.ckpt +*.safetensors +*.bin +*.onnx +*.h5 +checkpoints/ +weights/ + +# Jupyter +.ipynb_checkpoints/ +*.ipynb_metadata/ + +# IDE +.idea/ +.vscode/ +*.swp +*.swo + +# OS +.DS_Store +Thumbs.db + +# Logs +*.log +logs/ + +# Build artifacts +*.o +*.so +*.dylib +*.a +*.out diff --git a/templates/ResearchStarter/CLAUDE.md b/templates/ResearchStarter/CLAUDE.md new file mode 100644 index 0000000..d9b121c --- /dev/null +++ b/templates/ResearchStarter/CLAUDE.md @@ -0,0 +1,387 @@ +# Research Project Guidelines + +## Project Structure + +``` +ProjectName/ +├── README.md # Project overview (public-facing) +├── LICENSE # MIT Transparency License +├── CLAUDE.md # AI assistant guidelines + project config +├── goals.md # Success criteria (what does "done" look like?) +├── spec.md # Technical specification (optional) +├── conclusions.md # Living findings document +├── open_questions.md # Unresolved questions tracker +├── .gitignore +├── experiments/ # Experiment code (numbered runs) +│ ├── run1-baseline.ext +│ ├── run2-variable-change.ext +│ └── ... +├── results/ # Experiment results documentation +│ ├── TEMPLATE-results.md # Template for new results docs +│ └── experiment_N_results.md # One per experiment group +├── data/ # Datasets (gitignored — large files) +├── literature/ # Paper notes & prior art +│ ├── TEMPLATE-paper.md # Template for paper reviews +│ └── paper-name.md +├── src/ # Implementation code (when research produces software) +├── tests/ # Test suite +├── docs/ # Technical documentation +│ ├── README.md # Docs index +│ ├── TEMPLATE-experiment-plan.md +│ ├── TEMPLATE-milestone.md +│ ├── getting-started.md +│ └── architecture.md +└── screenshots/ # Visuals for README / portfolio +``` + +## TeamIDE Project Management + +If this project was scaffolded from Ideation, `.teamide/` PM files (plans, tasks, project.yml) should already exist — generated from milestone definitions during scaffolding. See the Ideation workspace's `claude.md` for the PM generation workflow and format details. + +## Terminology + +| Term | Meaning | +|------|---------| +| **goals.md** | What success looks like — pass/fail criteria, anti-goals, kill gates | +| **spec.md** | Technical specification for the system being built or studied (optional) | +| **conclusions.md** | Living findings — updated after each experiment phase | +| **open_questions.md** | Unresolved questions with context and leads | +| **experiment** | A numbered run in `experiments/` with a hypothesis | +| **results doc** | Structured write-up in `results/` documenting what happened | +| **milestone** | A dependency-tracked unit of work with success criteria | + +## The Research Pipeline + +``` +Vision doc --> Math/tradeoff analysis --> Milestone plan --> Implementation --> Tests pass +(speculative) (constrained) (prescriptive) (code) (done) +``` + +Each stage has a different document type and level of commitment. Ideas flow left to right and can be killed at any stage. + +## Document Layers + +### Layer 1: Vision Documents + +Thinking documents. Speculative, conversational, organized around questions and hypotheses. These live at the repo root or in topic-specific folders. + +**Purpose:** Capture the frontier of thinking. These are allowed to be wrong. + +**Examples:** Mathematical explorations, system architecture visions, training/data blueprints, goal documents. + +### Layer 2: Specs & Plans + +Prescriptive. Designed to be turned directly into implementation tasks. Live in `docs/` or as top-level files (`spec.md`). + +**Purpose:** Bridge between "what if" and "what to build." Every spec includes tasks, API surface, success criteria, and test cases. + +### Layer 3: Research Subprojects + +Active investigations with clear experiment plans and validation gates. Each gets its own directory or subfolder within `experiments/` with a README explaining the hypothesis, experiment design, and expected outcomes. + +### Layer 4: Architecture Docs + +Written after implementation. Describe how things actually work, not how they were planned. Live in `docs/architecture.md`. + +**Purpose:** Let a new developer understand the system without reading source code. + +## Key Patterns + +### 1. Hypothesis First (Non-Negotiable) + +**Every experiment requires a written hypothesis before any code runs.** No hypothesis, no experiment. + +The hypothesis states what you expect to happen and why — it forces you to think before you compute. + +```markdown +## Hypothesis +Increasing batch size from 1 to 32 will reduce gradient noise enough for +convergence, because individual gradient samples have high variance but +batch-averaged gradients should be stable. + +## Expected Outcome +Loss should decrease monotonically with batch=32, vs oscillating with batch=1. +If loss still oscillates with batch=32, the variance problem is fundamental, +not just a sample-size issue. +``` + +Without a hypothesis, you don't know what the experiment is testing. You'll see a number and not know if it's good or bad. + +**The scientific method, applied:** +1. **Observe** — notice something in your data, results, or literature +2. **Question** — formulate a specific question about what you observed +3. **Hypothesize** — predict an answer and state WHY you expect it +4. **Experiment** — design a run that can confirm or reject the hypothesis +5. **Analyze** — compare results to the prediction +6. **Conclude** — state what was learned, update your mental model +7. **Repeat** — the conclusion feeds the next observation + +### 2. Kill Gates + +Research questions get structured investigation with kill gates: + +``` +Phase 1: Literature review (what exists?) +Phase 2: Build minimal viable module +Phase 3: Integration experiments (defined matrix of configs) +Phase 4: Investigate properties (hypothesis-based, only if Phase 3 passes) +Phase 5: Optimization (only if Phase 4 is promising) +``` + +Each phase is a gate. If Phase 3 fails, Phase 4 doesn't happen. This prevents sunk-cost fallacy on dead-end research. + +### 3. Constraint-Driven Design + +Start with hard limits. Let them drive architecture. + +```markdown +## Constraints +- [Your hardware/budget/time limit here] +- [Your performance requirement here] +- [Your compatibility requirement here] + +## Design (driven by above) +- [Architecture decision that follows from constraints] +``` + +Don't design the ideal system then optimize. Design around your actual constraints from day one. + +### 4. Explicit Deferral + +Every milestone says what it's NOT doing and why: + +```markdown +**Deferred:** [Feature/capability]. +**Reason:** [Why it's not worth doing now]. +``` + +Three categories for all work items: +- **Active/Concrete** — being built now, with tests +- **Outlined** — architectural sketch, no code yet +- **Deferred** — recognized need, explicitly postponed with rationale + +This prevents scope creep while preserving ideas for later. + +### 5. Tradeoff Tables + +Every complex decision gets a table showing the option space: + +```markdown +| Option | Pros | Cons | When to pick | +|-----------|------------------|-----------------------|----------------| +| Option A | Simple, fast | Doesn't scale past N | Prototyping | +| Option B | Scales well | Complex to implement | Production | +| Option C | Best performance | Vendor lock-in | If budget > $X | +``` + +No "we chose X because it's better." Instead: "here's the tradeoff space, here's what we picked and why." + +### 6. Testable Success Criteria + +Every milestone ends with a concrete, falsifiable statement: + +```markdown +**Success Criteria:** +- [System] does [specific thing] in [specific time/resource bound] +- [N] tests pass with zero warnings +- [Specific scenario] produces [specific measurable result] +``` + +Not "it should work" — specific numbers, specific scenarios. + +### 7. Math First, Code Second + +Abstract ideas get mathematical or formal framing before any code is written: + +``` +Idea (what if we tried X?) + --> Formalization (what does X actually mean mathematically?) + --> Existing work (has anyone done this? what libraries exist?) + --> Experiment plan (how would we test this?) + --> Validation gate (what result would make us continue vs abandon?) +``` + +This filters out ideas that sound good but don't survive formalization. + +### 8. Documentation as Specification + +Write implementation-ready docs before coding: + +1. Write detailed spec in markdown (API signatures, wire formats, data structures) +2. Implement against the spec +3. Test against the spec's success criteria +4. Update the spec if reality diverges + +The spec IS the source of truth. Code follows docs, not the other way around. + +## Experiment Tracking + +All experiments live in the `experiments/` folder and follow strict naming and documentation conventions. + +### Naming Convention + +Experiments are numbered sequentially with a descriptive kebab-case suffix: + +``` +experiments/ +├── run1-batch-gradient-baseline.c +├── run2-per-sample-online.c +├── run3-leaky-relu-activation.c +├── run4-temperature-annealing.c +└── ... +``` + +Rules: +- Prefix: `run-` where N is sequential (run1, run2, run3...) +- Suffix: short kebab-case description of what this run changes vs the previous +- One variable changed per run when possible (isolation) +- If a run is a variant of another, use sub-numbering: `run9b-normalization-lower-temp` +- Run numbering stays globally sequential across the whole project — don't restart at run1 inside subfolders + +When a single experiment direction spawns many runs, group them in a subfolder inside `experiments/`: + +``` +experiments/ +├── run1-baseline.ext +├── run2-different-approach.ext +├── scaling-study/ # Subfolder for related runs +│ ├── run3-small-scale.ext +│ ├── run4-medium-scale.ext +│ └── run5-large-scale.ext +└── ... +``` + +### Results Documentation + +Every experiment's results are documented in `results/`. One results file per experiment or per logical group: + +``` +results/ +├── experiment_1_results.md +├── experiment_2_results.md +└── ... +``` + +Use `results/TEMPLATE-results.md` as the starting point for each results file. + +### Key Rules for Results + +1. **Every run gets a row in the summary table** — even failed runs. Especially failed runs. +2. **Link to source files** — reference experiment files as `experiments/run1-descriptive-name.ext` +3. **Include raw output** — paste actual terminal output. Don't just summarize. +4. **One finding per discovery** — each finding gets its own subsection with a bold **Verdict** line +5. **Comparison tables for pivots** — when switching approaches, add a side-by-side comparison table +6. **Strikethrough completed next steps** — mark done items with `~~strikethrough~~` and add **DONE** +7. **Decision points with kill gates** — define upfront what results would make you continue, pivot, or abandon +8. **Literature context** — compare your results to published work + +### Running Experiments + +**All experiments MUST be run in the background** so the user can continue chatting while they execute. Never run a build or training run in the foreground — it blocks the conversation. Use background execution and check on results later. + +## Milestone Format + +Every implementation milestone follows this structure: + +```markdown +### Milestone X.Y: Title — [STATUS] + +**What:** One-sentence summary of the deliverable. + +**Tasks:** +- [ ] Task with enough detail that someone else could do it +- [ ] Another task + +**Completed.** [Summary paragraph when done.] + +**Deferred:** [What was intentionally left out and why.] + +**New Files:** + +| File | What | +|------|------| +| path/to/file | One-line description | + +**API Surface:** +[Function signatures or interface definitions] + +**Depends on:** Milestone X.Y-1 + +**Success Criteria:** [Falsifiable statement with numbers] + +**Test Cases:** +1. [Specific scenario] — [expected result] +2. [Specific scenario] — [expected result] +``` + +### Dependency Graphs + +Milestones form a dependency chain. Visualize it: + +``` +Phase 1: 1.1 --> 1.2 --> 1.3 --> 1.4 --> 1.5 + | | +Phase 2: v v + 2.1 --> 2.2 --> 2.3 --> 2.4 +``` + +This makes it obvious what can be parallelized and what blocks what. + +## Principles + +1. **Hypothesis before experiment** — no code runs without a written prediction of what will happen and why. This is the most important rule. +2. **Speculation is welcome but quarantined** — vision docs are clearly marked as exploratory +3. **Implementation follows specs** — not the reverse +4. **Deferral is first-class** — saying "not now" with a reason is as important as saying "yes" +5. **Constraints are features** — limits drive creative solutions rather than being obstacles +6. **Tests are the definition of done** — not "it compiles" but "N tests pass with zero warnings" +7. **Tradeoffs are documented** — future-you can understand why decisions were made +8. **Kill gates protect your time** — research that fails a gate gets abandoned, not propped up +9. **Every experiment is tracked** — numbered, named, with raw output in results files. Failed runs are documented just as thoroughly as successes. +10. **One variable per run** — isolate changes so you know what caused the result. Sub-number variants (run9b) when testing minor tweaks. +11. **Experiments run in the background** — never block the user's ability to chat. All builds, training runs, and long-running processes execute in the background. + +## Commit Rules + +- Never mention Claude, AI, or generated code in commits +- Write as the developer, first person +- Concise and descriptive + +## Customization Checklist + +When creating a new project from this template: + +- [ ] Update `README.md` with project name, problem, idea, approaches +- [ ] Fill in `goals.md` with success criteria from the project plan +- [ ] Fill in `spec.md` if the project has a technical specification (otherwise delete it) +- [ ] Set up `open_questions.md` with initial research questions +- [ ] Create initial experiment plans in `docs/` using `TEMPLATE-experiment-plan.md` +- [ ] Add project-specific entries to `.gitignore` (language-specific, data formats, etc.) +- [ ] Update the "Project-Specific Configuration" section below +- [ ] Initialize git and create GitHub repo + +--- + +# Project-Specific Configuration + + + +## Project Name + +[PROJECT_NAME] + +## Description + +[Brief description of the research project] + +## Research Question + +[The core question this project investigates] + +## Tech Stack + +[Languages, frameworks, libraries being used] + +## TeamIDE Workspace ID + +[Workspace ID if deployed via TeamIDE] diff --git a/templates/ResearchStarter/LICENSE b/templates/ResearchStarter/LICENSE new file mode 100644 index 0000000..d316085 --- /dev/null +++ b/templates/ResearchStarter/LICENSE @@ -0,0 +1,27 @@ +MIT Transparency License + +Copyright (c) Corey Herrera + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software without any modification, +exemption or additional provision. All operational distributions, including +executables, embedded installations, package repositories, container images, +and network deployments must preserve their users' access to original source, +documentation, build scripts, configuration, and modifications necessary to +reproduce the intended implementation, in order to promote operational +transparency for the betterment of humanity. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/templates/ResearchStarter/README.md b/templates/ResearchStarter/README.md new file mode 100644 index 0000000..4ced281 --- /dev/null +++ b/templates/ResearchStarter/README.md @@ -0,0 +1,67 @@ +# [Project Name] + +> One-line description of what this research investigates. + +## The Problem + +[What problem exists. Why current solutions are insufficient. 2-3 paragraphs max.] + +## The Idea + +[Your proposed approach. What makes it different. Include a diagram or table if helpful.] + +## Current Status + +[What works, what doesn't, what's next. Update this as the project progresses.] + +| Component | Status | Key Metric | +|-----------|--------|------------| +| ... | ... | ... | + +## Research Approaches + +[List each approach being investigated with pros/cons.] + +### Approach 1: [Name] +- **Pro:** ... +- **Con:** ... +- **Open question:** ... + +## Experiment Plan + +[Numbered list of planned experiments with goals.] + +### Experiment 1: [Name] +**Goal:** [One sentence.] +- [Details] +- [Key question this answers] + +## Success Criteria + +[What results would make this research succeed vs fail.] + +1. [Criterion with specific number] +2. [Criterion with specific number] + +If no approach meets these criteria: [fallback plan]. + +## Folder Structure + +``` +ProjectName/ +├── experiments/ # Numbered experiment runs +├── results/ # Experiment results documentation +├── data/ # Datasets (gitignored) +├── literature/ # Paper notes & prior art +├── src/ # Implementation code +├── tests/ # Test suite +└── docs/ # Technical documentation +``` + +## References + +- [Paper/resource](URL) — one-line note + +## License + +[MIT Transparency License](LICENSE) diff --git a/templates/ResearchStarter/conclusions.md b/templates/ResearchStarter/conclusions.md new file mode 100644 index 0000000..a1df986 --- /dev/null +++ b/templates/ResearchStarter/conclusions.md @@ -0,0 +1,27 @@ +# Conclusions: [Project Name] + +## Status: In Progress + +## Key Findings + +### Finding 1: [Title] +**Discovered in:** [Experiment N, Phase X] +**Summary:** [One paragraph] +**Evidence:** See `results/experiment_N_results.md` +**Impact:** [How this changes our approach] + +## What Worked + +1. [Approach/technique that succeeded and why] + +## What Didn't Work + +1. [Approach/technique that failed and why — this is equally valuable] + +## Final Recommendation + +[What to do with these findings. Ship it? Pivot? Integrate into another project?] + +## Open Questions Remaining + +1. [Question that this research didn't answer] diff --git a/templates/ResearchStarter/docs/README.md b/templates/ResearchStarter/docs/README.md new file mode 100644 index 0000000..6724610 --- /dev/null +++ b/templates/ResearchStarter/docs/README.md @@ -0,0 +1,42 @@ +# Documentation + +> Technical documentation for [Project Name] + +## Table of Contents + +### Getting Started +- [Setup Guide](./getting-started.md) + +### Research + + + +### Architecture +- [Architecture](./architecture.md) — Post-implementation technical design + +### Templates +- [Experiment Plan Template](./TEMPLATE-experiment-plan.md) — For planning new experiments +- [Milestone Template](./TEMPLATE-milestone.md) — For milestone-based planning + +--- + +## Documentation Guidelines + +### Adding New Documentation + +After completing an experiment phase or milestone: + +1. Create a new `.md` file in this folder +2. Add a link to the Table of Contents above +3. Use the appropriate template: + - [Experiment plan template](./TEMPLATE-experiment-plan.md) — For planning experiments + - [Milestone template](./TEMPLATE-milestone.md) — For implementation milestones + +### Naming Convention + +| Type | Pattern | Example | +|------|---------|---------| +| Experiment plans | `experiment-N-plan.md` | `experiment-1-plan.md` | +| Milestone docs | `milestone-N-name.md` | `milestone-1-foundation.md` | +| Topic research | `research-[topic].md` | `research-gradient-methods.md` | +| Guide docs | `guide-[topic].md` | `guide-data-preparation.md` | diff --git a/templates/ResearchStarter/docs/TEMPLATE-experiment-plan.md b/templates/ResearchStarter/docs/TEMPLATE-experiment-plan.md new file mode 100644 index 0000000..1516f09 --- /dev/null +++ b/templates/ResearchStarter/docs/TEMPLATE-experiment-plan.md @@ -0,0 +1,21 @@ +# Run N: [Descriptive Name] + +## Hypothesis + +[What we expect to happen and why.] + +## Setup + +- **Architecture:** [Model/system description] +- **Key change vs previous run:** [What's different] +- **Config:** [Hyperparameters, settings] + +## Expected Outcome + +[What result would confirm or reject the hypothesis.] + +## Run Command + +```bash +[How to build and run this experiment] +``` diff --git a/templates/ResearchStarter/docs/TEMPLATE-milestone.md b/templates/ResearchStarter/docs/TEMPLATE-milestone.md new file mode 100644 index 0000000..5134b72 --- /dev/null +++ b/templates/ResearchStarter/docs/TEMPLATE-milestone.md @@ -0,0 +1,66 @@ +# Milestone Plan: [Project Name] + +## Dependency Graph + +``` +Phase 1: 1.1 --> 1.2 --> 1.3 + | +Phase 2: v + 2.1 --> 2.2 --> 2.3 +``` + +--- + +## Phase 1: [Phase Name] + +### Milestone 1.1: [Title] — PENDING + +**What:** [One-sentence summary of the deliverable.] + +**Tasks:** +- [ ] Task with enough detail that someone else could do it +- [ ] Another task + +**Deferred:** [What was intentionally left out and why.] + +**New Files:** + +| File | What | +|------|------| +| path/to/file | One-line description | + +**API Surface:** +[Function signatures or interface definitions, if applicable] + +**Depends on:** None + +**Success Criteria:** [Falsifiable statement with numbers] + +**Test Cases:** +1. [Specific scenario] — [expected result] +2. [Specific scenario] — [expected result] + +### Milestone 1.2: [Title] — PENDING + +**What:** ... + +**Depends on:** Milestone 1.1 + +... + +--- + +## Phase 2: [Phase Name] + +### Milestone 2.1: [Title] — PENDING + +**Depends on:** Milestone 1.2 + +... + +--- + +## Kill Gates + +- **After Phase 1:** If [condition], abandon [approach] and [fallback action] +- **After Phase 2:** If [condition], pivot to [alternative] diff --git a/templates/ResearchStarter/docs/architecture.md b/templates/ResearchStarter/docs/architecture.md new file mode 100644 index 0000000..414b352 --- /dev/null +++ b/templates/ResearchStarter/docs/architecture.md @@ -0,0 +1,35 @@ +# Architecture + +> Technical architecture for [Project Name] + +**Note:** This document is written after implementation. It describes how things actually work, not how they were planned. For the original design, see [spec.md](../spec.md). + +## Tech Stack + +| Layer | Technology | Purpose | +|-------|------------|---------| +| [Layer] | [Technology] | [Purpose] | + +## System Design + +[Diagrams, data flow, component interactions.] + +## Key Design Decisions + +### [Decision 1] + +**Context:** [Why this decision was needed] + +**Decision:** [What was decided] + +**Consequences:** [Trade-offs and implications] + +## Data Model + +[Describe main entities, formats, and relationships] + +## External Dependencies + +| Dependency | Purpose | Documentation | +|------------|---------|---------------| +| [Library] | [Purpose] | [Link] | diff --git a/templates/ResearchStarter/docs/getting-started.md b/templates/ResearchStarter/docs/getting-started.md new file mode 100644 index 0000000..4425b9e --- /dev/null +++ b/templates/ResearchStarter/docs/getting-started.md @@ -0,0 +1,47 @@ +# Getting Started + +> Setup guide for [Project Name] + +## Prerequisites + +- [Language runtime / compiler] +- [Package manager] +- [Additional prerequisites] + +## Installation + +```bash +# Clone the repository +git clone https://github.com/dcherrera/[ProjectName].git +cd [ProjectName] + +# Install dependencies +[install command] +``` + +## Running Experiments + +```bash +# Run a specific experiment +[command to run experiment] + +# View results +[command to view output] +``` + +## Project Layout + +| Folder | Purpose | +|--------|---------| +| `experiments/` | Experiment code (numbered runs) | +| `results/` | Experiment results documentation | +| `data/` | Datasets (gitignored) | +| `literature/` | Paper notes & prior art | +| `src/` | Implementation code | +| `tests/` | Test suite | + +## Next Steps + +- Read [goals.md](../goals.md) to understand success criteria +- Check [open_questions.md](../open_questions.md) for current research questions +- Review [Architecture](./architecture.md) for technical design diff --git a/templates/ResearchStarter/experiments/.gitkeep b/templates/ResearchStarter/experiments/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/templates/ResearchStarter/goals.md b/templates/ResearchStarter/goals.md new file mode 100644 index 0000000..bc6bdd5 --- /dev/null +++ b/templates/ResearchStarter/goals.md @@ -0,0 +1,36 @@ +# Goals: [Project Name] + +## Primary Goal + +[One sentence: what does this research need to achieve to be worth the time?] + +## Success Criteria + +These are pass/fail — either you hit them or you don't. + +1. [Specific measurable criterion] +2. [Specific measurable criterion] +3. [Specific measurable criterion] + +## Stretch Goals + +Nice to have, not required for success. + +1. [Stretch criterion] + +## Anti-Goals + +What this project is NOT trying to do. Prevents scope creep. + +1. [Explicit non-goal] +2. [Explicit non-goal] + +## Fallback Plan + +If no approach meets the success criteria: +- [What you'll do instead] + +## Timeline + +- **Phase 1 deadline:** [Date or "N weeks from start"] +- **Kill gate:** If Phase 1 doesn't pass by [deadline], [action] diff --git a/templates/ResearchStarter/literature/.gitkeep b/templates/ResearchStarter/literature/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/templates/ResearchStarter/literature/TEMPLATE-paper.md b/templates/ResearchStarter/literature/TEMPLATE-paper.md new file mode 100644 index 0000000..4a9ab73 --- /dev/null +++ b/templates/ResearchStarter/literature/TEMPLATE-paper.md @@ -0,0 +1,11 @@ +# [Paper Title] ([Author Year]) + +**Link:** [URL] + +**Key idea:** [One sentence] + +**Relevance:** [How it relates to our research] + +**What they got:** [Their results] + +**What we can use:** [Actionable takeaway] diff --git a/templates/ResearchStarter/open_questions.md b/templates/ResearchStarter/open_questions.md new file mode 100644 index 0000000..ebef216 --- /dev/null +++ b/templates/ResearchStarter/open_questions.md @@ -0,0 +1,17 @@ +# Open Questions: [Project Name] + +## Active Questions + +### Q1: [Question] +**Context:** [Why this matters] +**Blocking:** [What can't proceed until this is answered, if anything] +**Leads:** [Any partial answers or places to look] + +## Answered Questions + + + diff --git a/templates/ResearchStarter/results/.gitkeep b/templates/ResearchStarter/results/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/templates/ResearchStarter/results/TEMPLATE-results.md b/templates/ResearchStarter/results/TEMPLATE-results.md new file mode 100644 index 0000000..88652ad --- /dev/null +++ b/templates/ResearchStarter/results/TEMPLATE-results.md @@ -0,0 +1,81 @@ +# Experiment N Results: [Short Title] + +## Phase [A/B/C...] — [Phase Name] + +### Setup + +- **Architecture:** [Model/system description] +- **Source:** `experiments/run1-descriptive-name.ext` +- **Config:** [Key hyperparameters or settings] + +--- + +## Summary of All Runs + +| Run | Key Variable | Config | Best Metric | Key Finding | +|-----|-------------|--------|-------------|-------------| +| 1 | baseline | ... | ... | [One-line takeaway] | +| 2 | changed X | ... | ... | [One-line takeaway] | +| 3 | changed Y | ... | ... | [One-line takeaway] | + +--- + +## Detailed Findings + +### Finding 1: [Descriptive Title] + +**Runs [N-M]** ([what was varied]) + +[Explanation of what happened and why. Include raw output.] + +``` +[Raw output from the run — config, per-epoch metrics, final results] +``` + +**Verdict:** [One-line conclusion. Bold the action item.] + +### Finding 2: [Next Discovery] + +... + +--- + +## Current Best Result + +**Run N: [Short description of the winning config]** + +``` +[Full output of the best run] +``` + +--- + +## Conclusions + +[What the phase proved or disproved. Structural insights, not just numbers.] + +1. **[Finding]:** [Explanation] +2. **[Finding]:** [Explanation] +3. **[Finding]:** [Explanation] + +--- + +## Next Steps + +Priority order: + +1. ~~**Run N: [Description]**~~ — **DONE.** [Result summary.] +2. **Run N+1: [Description]** — *Next up.* [Why this is the next thing to try.] +3. **Run N+2: [Description]** — [Brief rationale.] + +**Decision points:** +- **>[Target] achieved:** Proceed to [next phase] +- **Stuck at [range]:** [What that means and what to try] +- **Below [floor] after remaining runs:** [Kill gate — abandon or pivot] + +### Literature Context + +| Method | Result | Notes | +|--------|--------|-------| +| [Existing work] | [Their result] | [How it compares] | +| **Us (Run N)** | **[Our result]** | **[Where we stand]** | diff --git a/templates/ResearchStarter/screenshots/.gitkeep b/templates/ResearchStarter/screenshots/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/templates/ResearchStarter/spec.md b/templates/ResearchStarter/spec.md new file mode 100644 index 0000000..96ccffa --- /dev/null +++ b/templates/ResearchStarter/spec.md @@ -0,0 +1,37 @@ +# Spec: [System/Component Name] + +## Overview + +[What this system does. One paragraph.] + +## Constraints + +- [Hard limit 1] +- [Hard limit 2] +- [Hard limit 3] + +## Architecture + +[System design. Diagrams, data flow, component interactions.] + +## API Surface + +[Function signatures, data formats, wire protocols — whatever the system exposes.] + +``` +// Example +void system_do_thing(input_t *in, output_t *out); +``` + +## Data Formats + +[File formats, serialization, storage layout.] + +## Integration Points + +[How this system connects to other projects or systems.] + +## Open Design Questions + +- [Question that needs resolution before implementation] +- [Question] diff --git a/templates/ResearchStarter/src/.gitkeep b/templates/ResearchStarter/src/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/templates/ResearchStarter/tests/.gitkeep b/templates/ResearchStarter/tests/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/templates/TauriStarter/.gitignore b/templates/TauriStarter/.gitignore new file mode 100644 index 0000000..5689610 --- /dev/null +++ b/templates/TauriStarter/.gitignore @@ -0,0 +1,36 @@ +# Environment files +.env +.env.* +!.env.example + +# Nhost secrets +app/nhost/.secrets + +# Node +node_modules/ +npm-debug.log* +yarn-error.log* +# Note: Never ignore lock files (package-lock.json, yarn.lock, pnpm-lock.yaml) +# They are required for reproducible builds + +# Build output +dist/ +.quasar/ +build/ + +# Tauri / Rust +app/src-tauri/target/ + +# IDE +.idea/ +.vscode/ +*.swp +*.swo + +# OS +.DS_Store +Thumbs.db + +# Logs +*.log +logs/ diff --git a/templates/TauriStarter/CLAUDE.md b/templates/TauriStarter/CLAUDE.md new file mode 100644 index 0000000..564fa42 --- /dev/null +++ b/templates/TauriStarter/CLAUDE.md @@ -0,0 +1,537 @@ +# Project Guidelines + +## Protecting This File + +**IMPORTANT**: This file (CLAUDE.md) can be lost during branch operations! + +Git doesn't protect untracked/ignored files during `git checkout` or branch switches. Before major git operations: +```bash +cp CLAUDE.md CLAUDE.md.backup +``` + +## Project Structure + +This project follows a standardized structure for Tauri desktop apps. + +``` +ProjectRoot/ +├── CLAUDE.md # AI assistant guidelines +├── README.md # Project documentation +├── build_spec.md # Full project specification +├── build_plan.md # Phased task checklist +├── .gitignore +├── docs/ # Technical documentation +│ ├── README.md # Docs index with table of contents +│ ├── getting-started.md +│ ├── architecture.md +│ ├── development.md +│ ├── deployment.md +│ └── feature-*.md # Feature docs (added per phase) +└── app/ # ALL project code lives here + ├── build.sh # Build script + ├── package.json + ├── vite.config.ts + ├── tsconfig.json + ├── index.html + ├── src/ + │ ├── main.ts + │ ├── App.vue + │ ├── boot/ + │ │ └── console-logger.ts + │ ├── components/ + │ ├── composables/ + │ ├── css/ + │ ├── layouts/ + │ ├── pages/ + │ ├── router/ + │ ├── stores/ + │ ├── services/ + │ └── types/ + └── src-tauri/ + ├── Cargo.toml + ├── tauri.conf.json + ├── icons/ + └── src/ + └── main.rs +``` + +## TeamIDE Project Management + +If this project was scaffolded from Ideation, `.teamide/` PM files (plans, tasks, project.yml) should already exist — generated from `build_plan.md` during scaffolding. See the Ideation workspace's `claude.md` for the PM generation workflow and format details. + +## Terminology + +- **"build spec"** or **"spec"** refers to `build_spec.md` - the full project description +- **"build plan"** or **"plan"** refers to `build_plan.md` - the phased task checklist + +## Onboarding Questions (Ask at Project Start) + +At the start of every new project conversation, gather these details before writing any code: + +1. **Brand colors & fonts** - Primary, secondary, accent colors. Typography preferences. Any existing brand guidelines or color palette? +2. **App personality & tone** - Formal or casual? Dark or light default theme? Dense or spacious layout? Any design inspiration or reference apps? +3. **Target platform** - Desktop-first, mobile-first, or responsive? Specific OS targets (macOS, Windows, Linux)? Minimum screen sizes? +4. **Auth requirements** - Login method (email/password, OAuth, magic link)? User roles and permissions? Public or private app? + +Don't assume defaults for any of these. Ask, get answers, then document them in the Project-Specific Configuration section at the bottom of this file. + +## Tech Stack + +- **Frontend**: Quasar Framework (Vue 3) + Vite +- **Desktop**: Tauri (Rust) - Cross-platform builds (macOS, Windows, Linux) +- **State**: Pinia +- **Routing**: Vue Router +- **Backend** (optional): Nhost (self-hosted or cloud) + - PostgreSQL - Database + - Hasura - GraphQL API + - Auth - Authentication service + - Storage - File storage + - Functions - Serverless functions (Node.js) + +## Testing Changes (CRITICAL) + +**After every code editing session, you MUST rebuild the app so the user can test your changes.** + +```bash +cd app +./build.sh -dev -open +``` + +### Why This Matters + +- This uses a **build-and-run** approach, not hot reload +- Your code changes are NOT visible until you rebuild +- Always rebuild before asking the user to test +- If the user reports issues, check the logs first: `./build.sh logs` + +## Build Script + +**Always use `build.sh` for building the app.** This ensures consistent builds and logging for collaborative debugging. + +```bash +cd app + +./build.sh -dev -open # Build dev and open app +./build.sh -prod # Build prod to build/prod/ +./build.sh -install # Build prod and open Finder for drag-to-Applications +./build.sh logs # View latest console output (last 100 lines) +./build.sh clean # Clean build artifacts (preserves logs) +./build.sh clean-logs # Remove all logs +``` + +### Commands + +| Command | Description | +|---------|-------------| +| `-dev` | Development build. Bundle ID: `com.[app].dev` | +| `-prod` | Production build. Builds to `build/prod/`. | +| `-install` | Build prod and open Finder for drag-to-Applications. | +| `-open` | Open the app after building (use with `-dev` or `-prod`) | +| `-secure` | Build without automation (no HTTP server on port 9876) | +| `logs` | Show last 100 lines of console output | +| `clean` | Remove build artifacts (preserves logs) | +| `clean-logs` | Remove all log files | + +### Why Build-and-Run (No Hot Reload) + +This project uses a **build-and-run** approach instead of hot reload: + +| Aspect | Hot Reload | Build-and-Run | +|--------|------------|---------------| +| Speed | Instant updates | Full rebuild required | +| Dev/Prod parity | Different environments | Identical to production | +| Debugging | Dev-only issues possible | What you test = what ships | +| Logging | Console only | Full logs to files | + +The tradeoff is slower iteration, but you always test exactly what will ship. + +### What the Build Does + +1. **Build with Tauri** - `npx tauri build` does all of the following: + - Build frontend (`npm run build` → `dist/`) + - Build Rust binary with embedded frontend + - Create .app bundle in `src-tauri/target/release/bundle/macos/` +2. **Copy to build folder** - Copies bundle to `build/dev/` or `build/prod/` +3. **Update Info.plist** - Sets correct bundle ID for dev/prod +4. **Install (prod only)** - Copies to `~/Applications` + +**Important**: Using `npx tauri build` ensures the frontend is properly embedded in the binary. Manual `cargo build --release` does NOT embed the frontend. + +### Build Output + +Builds are organized in separate folders: + +``` +app/build/ +├── dev/ +│ └── AppName.app # Dev build (bundle ID: .dev) +├── prod/ +│ └── AppName.app # Prod build +├── logs/ +│ ├── build_dev_*.log # Build output logs +│ └── build_latest.log # Symlink to latest +└── console/ + ├── console_*.log # App runtime console output + └── console_latest.log # Symlink to latest +``` + +Dev and prod have different bundle IDs, so both can run simultaneously. + +### Logging + +All build output and app console output is logged: + +- **Build logs**: `build/logs/build_latest.log` - compilation output, errors +- **Console logs**: `build/console/console_latest.log` - runtime `console.log()`, errors + +When debugging, run `./build.sh logs` to see the latest console output. + +### Console Logging (Already Configured) + +This template includes console logging out of the box. Frontend `console.log()` calls are forwarded to Rust and captured in log files. + +**How it works:** +``` +console.log() → console-logger.ts → invoke('log_to_stdout') → Rust println!() → stdout → build.sh logs +``` + +## Automation Plugin (Already Configured) + +This template includes an automation HTTP server for external testing and AI-assisted development. + +**How it works:** +``` +External Tool (curl) → HTTP Server (port 9876) → Rust → JavaScript → DOM +``` + +### Automation API + +When the app is running, these endpoints are available: + +```bash +# Health check +curl http://localhost:9876/automation/health + +# Execute a command +curl -X POST http://localhost:9876/automation/execute \ + -H "Content-Type: application/json" \ + -d '{"command": "click", "args": {"selector": "#my-button"}}' + +# Take a screenshot +curl http://localhost:9876/automation/screenshot --output screenshot.png +``` + +### Available Commands + +| Command | Args | Description | +|---------|------|-------------| +| `navigate` | `{path}` | Navigate to route | +| `click` | `{selector}` | Click element | +| `type` | `{selector, text}` | Type into input | +| `getText` | `{selector}` | Get element text | +| `getValue` | `{selector}` | Get input value | +| `exists` | `{selector}` | Check if element exists | +| `waitFor` | `{selector, timeout?}` | Wait for element | +| `getUrl` | `{}` | Get current URL | +| `screenshot` | - | Capture page (via endpoint) | + +Full command list in `src/automation/README.md`. + +### Disabling Automation + +**Option 1: Build flag (recommended)** + +Use the `-secure` flag to build without automation: + +```bash +./build.sh -prod -secure # Production build without automation +``` + +**Option 2: Permanently disable** + +Remove `automation` from the default features in `Cargo.toml`: + +```toml +[features] +default = ["custom-protocol"] # Remove "automation" +``` + +### When to Clean + +Run `./build.sh clean` when: +- Switching between major dependency versions +- Build errors reference stale/cached files +- Rust compilation issues after Tauri config changes +- Before creating a fresh production build + +## Node.js Environment + +**Node.js version**: Always match Debian stable (currently Node.js 18.x for Debian 12 Bookworm) + +Check current Debian stable Node version: https://packages.debian.org/stable/nodejs + +**Package manager**: Use npm. Commit lock files for reproducible builds. + +Rules: +- Always commit `package-lock.json` - required for deterministic installs +- Never ignore lock files (`package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`) +- Use `npm install` to install dependencies +- Use `npm run + + diff --git a/templates/TauriStarter/app/package-lock.json b/templates/TauriStarter/app/package-lock.json new file mode 100644 index 0000000..f2502e9 --- /dev/null +++ b/templates/TauriStarter/app/package-lock.json @@ -0,0 +1,2019 @@ +{ + "name": "tauri-starter", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "tauri-starter", + "version": "0.1.0", + "dependencies": { + "@quasar/extras": "^1.16.9", + "pinia": "^2.1.7", + "quasar": "^2.14.2", + "vue": "^3.4.18", + "vue-router": "^4.2.5" + }, + "devDependencies": { + "@quasar/vite-plugin": "^1.10.0", + "@tauri-apps/api": "^1.5.3", + "@tauri-apps/cli": "^1.5.11", + "@types/node": "^20.11.16", + "@vitejs/plugin-vue": "^5.2.4", + "sass": "^1.70.0", + "typescript": "^5.3.3", + "vite": "^5.0.12" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", + "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.6" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@parcel/watcher": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@quasar/extras": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@quasar/extras/-/extras-1.17.0.tgz", + "integrity": "sha512-KqAHdSJfIDauiR1nJ8rqHWT0diqD0QradZKoVIZJAilHAvgwyPIY7MbyR2z4RIMkUIMUSqBZcbshMpEw+9A30w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://donate.quasar.dev" + } + }, + "node_modules/@quasar/vite-plugin": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@quasar/vite-plugin/-/vite-plugin-1.10.0.tgz", + "integrity": "sha512-4PJoTclz4ZjAfyqe0+hlkKcFJt0e2NX3Ac3hy8ILqUPdtZ24nCo5/xEHvTxZGBQMKRPwwePbO8CVs4n9EKJEug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "type": "github", + "url": "https://donate.quasar.dev" + }, + "peerDependencies": { + "@vitejs/plugin-vue": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0", + "quasar": "^2.16.0", + "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", + "vue": "^3.0.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.56.0.tgz", + "integrity": "sha512-LNKIPA5k8PF1+jAFomGe3qN3bbIgJe/IlpDBwuVjrDKrJhVWywgnJvflMt/zkbVNLFtF1+94SljYQS6e99klnw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.56.0.tgz", + "integrity": "sha512-lfbVUbelYqXlYiU/HApNMJzT1E87UPGvzveGg2h0ktUNlOCxKlWuJ9jtfvs1sKHdwU4fzY7Pl8sAl49/XaEk6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.56.0.tgz", + "integrity": "sha512-EgxD1ocWfhoD6xSOeEEwyE7tDvwTgZc8Bss7wCWe+uc7wO8G34HHCUH+Q6cHqJubxIAnQzAsyUsClt0yFLu06w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.56.0.tgz", + "integrity": "sha512-1vXe1vcMOssb/hOF8iv52A7feWW2xnu+c8BV4t1F//m9QVLTfNVpEdja5ia762j/UEJe2Z1jAmEqZAK42tVW3g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.56.0.tgz", + "integrity": "sha512-bof7fbIlvqsyv/DtaXSck4VYQ9lPtoWNFCB/JY4snlFuJREXfZnm+Ej6yaCHfQvofJDXLDMTVxWscVSuQvVWUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.56.0.tgz", + "integrity": "sha512-KNa6lYHloW+7lTEkYGa37fpvPq+NKG/EHKM8+G/g9WDU7ls4sMqbVRV78J6LdNuVaeeK5WB9/9VAFbKxcbXKYg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.56.0.tgz", + "integrity": "sha512-E8jKK87uOvLrrLN28jnAAAChNq5LeCd2mGgZF+fGF5D507WlG/Noct3lP/QzQ6MrqJ5BCKNwI9ipADB6jyiq2A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.56.0.tgz", + "integrity": "sha512-jQosa5FMYF5Z6prEpTCCmzCXz6eKr/tCBssSmQGEeozA9tkRUty/5Vx06ibaOP9RCrW1Pvb8yp3gvZhHwTDsJw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.56.0.tgz", + "integrity": "sha512-uQVoKkrC1KGEV6udrdVahASIsaF8h7iLG0U0W+Xn14ucFwi6uS539PsAr24IEF9/FoDtzMeeJXJIBo5RkbNWvQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.56.0.tgz", + "integrity": "sha512-vLZ1yJKLxhQLFKTs42RwTwa6zkGln+bnXc8ueFGMYmBTLfNu58sl5/eXyxRa2RarTkJbXl8TKPgfS6V5ijNqEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.56.0.tgz", + "integrity": "sha512-FWfHOCub564kSE3xJQLLIC/hbKqHSVxy8vY75/YHHzWvbJL7aYJkdgwD/xGfUlL5UV2SB7otapLrcCj2xnF1dg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.56.0.tgz", + "integrity": "sha512-z1EkujxIh7nbrKL1lmIpqFTc/sr0u8Uk0zK/qIEFldbt6EDKWFk/pxFq3gYj4Bjn3aa9eEhYRlL3H8ZbPT1xvA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.56.0.tgz", + "integrity": "sha512-iNFTluqgdoQC7AIE8Q34R3AuPrJGJirj5wMUErxj22deOcY7XwZRaqYmB6ZKFHoVGqRcRd0mqO+845jAibKCkw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.56.0.tgz", + "integrity": "sha512-MtMeFVlD2LIKjp2sE2xM2slq3Zxf9zwVuw0jemsxvh1QOpHSsSzfNOTH9uYW9i1MXFxUSMmLpeVeUzoNOKBaWg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.56.0.tgz", + "integrity": "sha512-in+v6wiHdzzVhYKXIk5U74dEZHdKN9KH0Q4ANHOTvyXPG41bajYRsy7a8TPKbYPl34hU7PP7hMVHRvv/5aCSew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.56.0.tgz", + "integrity": "sha512-yni2raKHB8m9NQpI9fPVwN754mn6dHQSbDTwxdr9SE0ks38DTjLMMBjrwvB5+mXrX+C0npX0CVeCUcvvvD8CNQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.56.0.tgz", + "integrity": "sha512-zhLLJx9nQPu7wezbxt2ut+CI4YlXi68ndEve16tPc/iwoylWS9B3FxpLS2PkmfYgDQtosah07Mj9E0khc3Y+vQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.56.0.tgz", + "integrity": "sha512-MVC6UDp16ZSH7x4rtuJPAEoE1RwS8N4oK9DLHy3FTEdFoUTCFVzMfJl/BVJ330C+hx8FfprA5Wqx4FhZXkj2Kw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.56.0.tgz", + "integrity": "sha512-ZhGH1eA4Qv0lxaV00azCIS1ChedK0V32952Md3FtnxSqZTBTd6tgil4nZT5cU8B+SIw3PFYkvyR4FKo2oyZIHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.56.0.tgz", + "integrity": "sha512-O16XcmyDeFI9879pEcmtWvD/2nyxR9mF7Gs44lf1vGGx8Vg2DRNx11aVXBEqOQhWb92WN4z7fW/q4+2NYzCbBA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.56.0.tgz", + "integrity": "sha512-LhN/Reh+7F3RCgQIRbgw8ZMwUwyqJM+8pXNT6IIJAqm2IdKkzpCh/V9EdgOMBKuebIrzswqy4ATlrDgiOwbRcQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.56.0.tgz", + "integrity": "sha512-kbFsOObXp3LBULg1d3JIUQMa9Kv4UitDmpS+k0tinPBz3watcUiV2/LUDMMucA6pZO3WGE27P7DsfaN54l9ing==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.56.0.tgz", + "integrity": "sha512-vSSgny54D6P4vf2izbtFm/TcWYedw7f8eBrOiGGecyHyQB9q4Kqentjaj8hToe+995nob/Wv48pDqL5a62EWtg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.56.0.tgz", + "integrity": "sha512-FeCnkPCTHQJFbiGG49KjV5YGW/8b9rrXAM2Mz2kiIoktq2qsJxRD5giEMEOD2lPdgs72upzefaUvS+nc8E3UzQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.56.0.tgz", + "integrity": "sha512-H8AE9Ur/t0+1VXujj90w0HrSOuv0Nq9r1vSZF2t5km20NTfosQsGGUXDaKdQZzwuLts7IyL1fYT4hM95TI9c4g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tauri-apps/api": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.6.0.tgz", + "integrity": "sha512-rqI++FWClU5I2UBp4HXFvl+sBWkdigBkxnpJDQUWttNyG7IZP4FwQGhTNL5EOw0vI8i6eSAJ5frLqO7n7jbJdg==", + "dev": true, + "license": "Apache-2.0 OR MIT", + "engines": { + "node": ">= 14.6.0", + "npm": ">= 6.6.0", + "yarn": ">= 1.19.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + } + }, + "node_modules/@tauri-apps/cli": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-1.6.3.tgz", + "integrity": "sha512-q46umd6QLRKDd4Gg6WyZBGa2fWvk0pbeUA5vFomm4uOs1/17LIciHv2iQ4UD+2Yv5H7AO8YiE1t50V0POiEGEw==", + "dev": true, + "license": "Apache-2.0 OR MIT", + "dependencies": { + "semver": ">=7.5.2" + }, + "bin": { + "tauri": "tauri.js" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + }, + "optionalDependencies": { + "@tauri-apps/cli-darwin-arm64": "1.6.3", + "@tauri-apps/cli-darwin-x64": "1.6.3", + "@tauri-apps/cli-linux-arm-gnueabihf": "1.6.3", + "@tauri-apps/cli-linux-arm64-gnu": "1.6.3", + "@tauri-apps/cli-linux-arm64-musl": "1.6.3", + "@tauri-apps/cli-linux-x64-gnu": "1.6.3", + "@tauri-apps/cli-linux-x64-musl": "1.6.3", + "@tauri-apps/cli-win32-arm64-msvc": "1.6.3", + "@tauri-apps/cli-win32-ia32-msvc": "1.6.3", + "@tauri-apps/cli-win32-x64-msvc": "1.6.3" + } + }, + "node_modules/@tauri-apps/cli-darwin-arm64": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.6.3.tgz", + "integrity": "sha512-fQN6IYSL8bG4NvkdKE4sAGF4dF/QqqQq4hOAU+t8ksOzHJr0hUlJYfncFeJYutr/MMkdF7hYKadSb0j5EE9r0A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-darwin-x64": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.6.3.tgz", + "integrity": "sha512-1yTXZzLajKAYINJOJhZfmMhCzweHSgKQ3bEgJSn6t+1vFkOgY8Yx4oFgWcybrrWI5J1ZLZAl47+LPOY81dLcyA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.6.3.tgz", + "integrity": "sha512-CjTEr9r9xgjcvos09AQw8QMRPuH152B1jvlZt4PfAsyJNPFigzuwed5/SF7XAd8bFikA7zArP4UT12RdBxrx7w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-gnu": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.6.3.tgz", + "integrity": "sha512-G9EUUS4M8M/Jz1UKZqvJmQQCKOzgTb8/0jZKvfBuGfh5AjFBu8LHvlFpwkKVm1l4951Xg4ulUp6P9Q7WRJ9XSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-musl": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.6.3.tgz", + "integrity": "sha512-MuBTHJyNpZRbPVG8IZBN8+Zs7aKqwD22tkWVBcL1yOGL4zNNTJlkfL+zs5qxRnHlUsn6YAlbW/5HKocfpxVwBw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-gnu": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.6.3.tgz", + "integrity": "sha512-Uvi7M+NK3tAjCZEY1WGel+dFlzJmqcvu3KND+nqa22762NFmOuBIZ4KJR/IQHfpEYqKFNUhJfCGnpUDfiC3Oxg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-musl": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.6.3.tgz", + "integrity": "sha512-rc6B342C0ra8VezB/OJom9j/N+9oW4VRA4qMxS2f4bHY2B/z3J9NPOe6GOILeg4v/CV62ojkLsC3/K/CeF3fqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-arm64-msvc": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-1.6.3.tgz", + "integrity": "sha512-cSH2qOBYuYC4UVIFtrc1YsGfc5tfYrotoHrpTvRjUGu0VywvmyNk82+ZsHEnWZ2UHmu3l3lXIGRqSWveLln0xg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-ia32-msvc": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.6.3.tgz", + "integrity": "sha512-T8V6SJQqE4PSWmYBl0ChQVmS6AR2hXFHURH2DwAhgSGSQ6uBXgwlYFcfIeQpBQA727K2Eq8X2hGfvmoySyHMRw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-x64-msvc": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.6.3.tgz", + "integrity": "sha512-HUkWZ+lYHI/Gjkh2QjHD/OBDpqLVmvjZGpLK9losur1Eg974Jip6k+vsoTUxQBCBDfj30eDBct9E1FvXOspWeg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.30.tgz", + "integrity": "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", + "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.27.tgz", + "integrity": "sha512-gnSBQjZA+//qDZen+6a2EdHqJ68Z7uybrMf3SPjEGgG4dicklwDVmMC1AeIHxtLVPT7sn6sH1KOO+tS6gwOUeQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@vue/shared": "3.5.27", + "entities": "^7.0.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.27.tgz", + "integrity": "sha512-oAFea8dZgCtVVVTEC7fv3T5CbZW9BxpFzGGxC79xakTr6ooeEqmRuvQydIiDAkglZEAd09LgVf1RoDnL54fu5w==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.27", + "@vue/shared": "3.5.27" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.27.tgz", + "integrity": "sha512-sHZu9QyDPeDmN/MRoshhggVOWE5WlGFStKFwu8G52swATgSny27hJRWteKDSUUzUH+wp+bmeNbhJnEAel/auUQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@vue/compiler-core": "3.5.27", + "@vue/compiler-dom": "3.5.27", + "@vue/compiler-ssr": "3.5.27", + "@vue/shared": "3.5.27", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.27.tgz", + "integrity": "sha512-Sj7h+JHt512fV1cTxKlYhg7qxBvack+BGncSpH+8vnN+KN95iPIcqB5rsbblX40XorP+ilO7VIKlkuu3Xq2vjw==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.27", + "@vue/shared": "3.5.27" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" + }, + "node_modules/@vue/reactivity": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.27.tgz", + "integrity": "sha512-vvorxn2KXfJ0nBEnj4GYshSgsyMNFnIQah/wczXlsNXt+ijhugmW+PpJ2cNPe4V6jpnBcs0MhCODKllWG+nvoQ==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.27" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.27.tgz", + "integrity": "sha512-fxVuX/fzgzeMPn/CLQecWeDIFNt3gQVhxM0rW02Tvp/YmZfXQgcTXlakq7IMutuZ/+Ogbn+K0oct9J3JZfyk3A==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.27", + "@vue/shared": "3.5.27" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.27.tgz", + "integrity": "sha512-/QnLslQgYqSJ5aUmb5F0z0caZPGHRB8LEAQ1s81vHFM5CBfnun63rxhvE/scVb/j3TbBuoZwkJyiLCkBluMpeg==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.27", + "@vue/runtime-core": "3.5.27", + "@vue/shared": "3.5.27", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.27.tgz", + "integrity": "sha512-qOz/5thjeP1vAFc4+BY3Nr6wxyLhpeQgAE/8dDtKo6a6xdk+L4W46HDZgNmLOBUDEkFXV3G7pRiUqxjX0/2zWA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.27", + "@vue/shared": "3.5.27" + }, + "peerDependencies": { + "vue": "3.5.27" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.27.tgz", + "integrity": "sha512-dXr/3CgqXsJkZ0n9F3I4elY8wM9jMJpP3pvRG52r6m0tu/MsAFIe6JpXVGeNMd/D9F4hQynWT8Rfuj0bdm9kFQ==", + "license": "MIT" + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/immutable": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz", + "integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pinia": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.3.1.tgz", + "integrity": "sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.3", + "vue-demi": "^0.14.10" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "typescript": ">=4.4.4", + "vue": "^2.7.0 || ^3.5.11" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/quasar": { + "version": "2.18.6", + "resolved": "https://registry.npmjs.org/quasar/-/quasar-2.18.6.tgz", + "integrity": "sha512-ZlK+vJXOBPSFDCNQDBDNwSI+AHoqaFPxK8ve6mhsYLhMKWI5b8zsGY9VU1xYjngO2aBvU4fvGWXy4tTbzrBk8Q==", + "license": "MIT", + "engines": { + "node": ">= 10.18.1", + "npm": ">= 6.13.4", + "yarn": ">= 1.21.1" + }, + "funding": { + "type": "github", + "url": "https://donate.quasar.dev" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/rollup": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.56.0.tgz", + "integrity": "sha512-9FwVqlgUHzbXtDg9RCMgodF3Ua4Na6Gau+Sdt9vyCN4RhHfVKX2DCHy3BjMLTDd47ITDhYAnTwGulWTblJSDLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.56.0", + "@rollup/rollup-android-arm64": "4.56.0", + "@rollup/rollup-darwin-arm64": "4.56.0", + "@rollup/rollup-darwin-x64": "4.56.0", + "@rollup/rollup-freebsd-arm64": "4.56.0", + "@rollup/rollup-freebsd-x64": "4.56.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.56.0", + "@rollup/rollup-linux-arm-musleabihf": "4.56.0", + "@rollup/rollup-linux-arm64-gnu": "4.56.0", + "@rollup/rollup-linux-arm64-musl": "4.56.0", + "@rollup/rollup-linux-loong64-gnu": "4.56.0", + "@rollup/rollup-linux-loong64-musl": "4.56.0", + "@rollup/rollup-linux-ppc64-gnu": "4.56.0", + "@rollup/rollup-linux-ppc64-musl": "4.56.0", + "@rollup/rollup-linux-riscv64-gnu": "4.56.0", + "@rollup/rollup-linux-riscv64-musl": "4.56.0", + "@rollup/rollup-linux-s390x-gnu": "4.56.0", + "@rollup/rollup-linux-x64-gnu": "4.56.0", + "@rollup/rollup-linux-x64-musl": "4.56.0", + "@rollup/rollup-openbsd-x64": "4.56.0", + "@rollup/rollup-openharmony-arm64": "4.56.0", + "@rollup/rollup-win32-arm64-msvc": "4.56.0", + "@rollup/rollup-win32-ia32-msvc": "4.56.0", + "@rollup/rollup-win32-x64-gnu": "4.56.0", + "@rollup/rollup-win32-x64-msvc": "4.56.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/sass": { + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.3.tgz", + "integrity": "sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.27.tgz", + "integrity": "sha512-aJ/UtoEyFySPBGarREmN4z6qNKpbEguYHMmXSiOGk69czc+zhs0NF6tEFrY8TZKAl8N/LYAkd4JHVd5E/AsSmw==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.27", + "@vue/compiler-sfc": "3.5.27", + "@vue/runtime-dom": "3.5.27", + "@vue/server-renderer": "3.5.27", + "@vue/shared": "3.5.27" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/vue-router": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz", + "integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + } + } +} diff --git a/templates/TauriStarter/app/package.json b/templates/TauriStarter/app/package.json new file mode 100644 index 0000000..851bba3 --- /dev/null +++ b/templates/TauriStarter/app/package.json @@ -0,0 +1,31 @@ +{ + "name": "tauri-starter", + "version": "0.1.0", + "description": "Quasar + Vite + Tauri starter template", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview", + "tauri:dev": "tauri dev", + "tauri:build": "tauri build" + }, + "dependencies": { + "@quasar/extras": "^1.16.9", + "pinia": "^2.1.7", + "quasar": "^2.14.2", + "vue": "^3.4.18", + "vue-router": "^4.2.5" + }, + "devDependencies": { + "@quasar/vite-plugin": "^1.10.0", + "@tauri-apps/api": "^1.5.3", + "@tauri-apps/cli": "^1.5.11", + "@types/node": "^20.11.16", + "@vitejs/plugin-vue": "^5.2.4", + "sass": "^1.70.0", + "typescript": "^5.3.3", + "vite": "^5.0.12" + } +} diff --git a/templates/TauriStarter/app/src-tauri/Cargo.lock b/templates/TauriStarter/app/src-tauri/Cargo.lock new file mode 100644 index 0000000..0091bb8 --- /dev/null +++ b/templates/TauriStarter/app/src-tauri/Cargo.lock @@ -0,0 +1,4003 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "atk" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3d816ce6f0e2909a96830d6911c2aff044370b1ef92d7f267b43bae5addedd" +dependencies = [ + "atk-sys", + "bitflags 1.3.2", + "glib", + "libc", +] + +[[package]] +name = "atk-sys" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58aeb089fb698e06db8089971c7ee317ab9644bade33383f63631437b03aafb6" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps 6.2.2", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "brotli" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a334ef7c9e23abf0ce748e8cd309037da93e606ad52eb372e4ce327a0dcfbdfd" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + +[[package]] +name = "bytemuck" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" + +[[package]] +name = "cairo-rs" +version = "0.15.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c76ee391b03d35510d9fa917357c7f1855bd9a6659c95a1b392e33f49b3369bc" +dependencies = [ + "bitflags 1.3.2", + "cairo-sys-rs", + "glib", + "libc", + "thiserror", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8" +dependencies = [ + "glib-sys", + "libc", + "system-deps 6.2.2", +] + +[[package]] +name = "cargo_toml" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "599aa35200ffff8f04c1925aa1acc92fa2e08874379ef42e210a80e527e60838" +dependencies = [ + "serde", + "toml 0.7.8", +] + +[[package]] +name = "cc" +version = "1.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6354c81bbfd62d9cfa9cb3c773c2b7b2a3a482d569de977fd0e961f6e7c00583" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfb" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +dependencies = [ + "byteorder", + "fnv", + "uuid", +] + +[[package]] +name = "cfg-expr" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3431df59f28accaf4cb4eed4a9acc66bea3f3c3753aa6cdc2f024174ef232af7" +dependencies = [ + "smallvec", +] + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chrono" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "cocoa" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a" +dependencies = [ + "bitflags 1.3.2", + "block", + "cocoa-foundation", + "core-foundation", + "core-graphics", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" +dependencies = [ + "bitflags 1.3.2", + "block", + "core-foundation", + "core-graphics-types", + "libc", + "objc", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cssparser" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa 0.4.8", + "matches", + "phf 0.8.0", + "proc-macro2", + "quote", + "smallvec", + "syn 1.0.109", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.114", +] + +[[package]] +name = "ctor" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +dependencies = [ + "quote", + "syn 2.0.114", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.114", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "deranged" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +dependencies = [ + "powerfmt", + "serde_core", +] + +[[package]] +name = "derive_more" +version = "0.99.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.114", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "dtoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "embed-resource" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d506610004cfc74a6f5ee7e8c632b355de5eca1f03ee5e5e0ec11b77d4eb3d61" +dependencies = [ + "cc", + "memchr", + "rustc_version", + "toml 0.8.23", + "vswhom", + "winreg", +] + +[[package]] +name = "embed_plist" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "field-offset" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" +dependencies = [ + "memoffset", + "rustc_version", +] + +[[package]] +name = "filetime" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" +dependencies = [ + "cfg-if", + "libc", + "libredox", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" + +[[package]] +name = "flate2" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fluent-uri" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17c704e9dbe1ddd863da1e6ff3567795087b1eb201ce80d8fa81162e1516500d" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" +dependencies = [ + "mac", + "new_debug_unreachable", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-macro", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "gdk" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6e05c1f572ab0e1f15be94217f0dc29088c248b14f792a5ff0af0d84bcda9e8" +dependencies = [ + "bitflags 1.3.2", + "cairo-rs", + "gdk-pixbuf", + "gdk-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad38dd9cc8b099cceecdf41375bb6d481b1b5a7cd5cd603e10a69a9383f8619a" +dependencies = [ + "bitflags 1.3.2", + "gdk-pixbuf-sys", + "gio", + "glib", + "libc", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "140b2f5378256527150350a8346dbdb08fadc13453a7a2d73aecd5fab3c402a7" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps 6.2.2", +] + +[[package]] +name = "gdk-sys" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e7a08c1e8f06f4177fb7e51a777b8c1689f743a7bc11ea91d44d2226073a88" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps 6.2.2", +] + +[[package]] +name = "gdkwayland-sys" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cca49a59ad8cfdf36ef7330fe7bdfbe1d34323220cc16a0de2679ee773aee2c2" +dependencies = [ + "gdk-sys", + "glib-sys", + "gobject-sys", + "libc", + "pkg-config", + "system-deps 6.2.2", +] + +[[package]] +name = "gdkx11-sys" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b7f8c7a84b407aa9b143877e267e848ff34106578b64d1e0a24bf550716178" +dependencies = [ + "gdk-sys", + "glib-sys", + "libc", + "system-deps 6.2.2", + "x11", +] + +[[package]] +name = "generator" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" +dependencies = [ + "cc", + "libc", + "log", + "rustversion", + "windows 0.48.0", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "gio" +version = "0.15.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68fdbc90312d462781a395f7a16d96a2b379bb6ef8cd6310a2df272771c4283b" +dependencies = [ + "bitflags 1.3.2", + "futures-channel", + "futures-core", + "futures-io", + "gio-sys", + "glib", + "libc", + "once_cell", + "thiserror", +] + +[[package]] +name = "gio-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32157a475271e2c4a023382e9cab31c4584ee30a97da41d3c4e9fdd605abcf8d" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps 6.2.2", + "winapi", +] + +[[package]] +name = "glib" +version = "0.15.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edb0306fbad0ab5428b0ca674a23893db909a98582969c9b537be4ced78c505d" +dependencies = [ + "bitflags 1.3.2", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "once_cell", + "smallvec", + "thiserror", +] + +[[package]] +name = "glib-macros" +version = "0.15.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10c6ae9f6fa26f4fb2ac16b528d138d971ead56141de489f8111e259b9df3c4a" +dependencies = [ + "anyhow", + "heck 0.4.1", + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "glib-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4" +dependencies = [ + "libc", + "system-deps 6.2.2", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "globset" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "gobject-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d57ce44246becd17153bd035ab4d32cfee096a657fc01f2231c9278378d1e0a" +dependencies = [ + "glib-sys", + "libc", + "system-deps 6.2.2", +] + +[[package]] +name = "gtk" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e3004a2d5d6d8b5057d2b57b3712c9529b62e82c77f25c1fecde1fd5c23bd0" +dependencies = [ + "atk", + "bitflags 1.3.2", + "cairo-rs", + "field-offset", + "futures-channel", + "gdk", + "gdk-pixbuf", + "gio", + "glib", + "gtk-sys", + "gtk3-macros", + "libc", + "once_cell", + "pango", + "pkg-config", +] + +[[package]] +name = "gtk-sys" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5bc2f0587cba247f60246a0ca11fe25fb733eabc3de12d1965fc07efab87c84" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps 6.2.2", +] + +[[package]] +name = "gtk3-macros" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "684c0456c086e8e7e9af73ec5b84e35938df394712054550e81558d21c44ab0d" +dependencies = [ + "anyhow", + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "html5ever" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" +dependencies = [ + "log", + "mac", + "markup5ever", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa 1.0.17", +] + +[[package]] +name = "http-range" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" + +[[package]] +name = "iana-time-zone" +version = "0.1.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ico" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc50b891e4acf8fe0e71ef88ec43ad82ee07b3810ad09de10f1d01f072ed4b98" +dependencies = [ + "byteorder", + "png", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "ignore" +version = "0.4.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata", + "same-file", + "walkdir", + "winapi-util", +] + +[[package]] +name = "image" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "num-traits", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "infer" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f551f8c3a39f68f986517db0d1759de85881894fdc7db798bd2a9df9cb04b7fc" +dependencies = [ + "cfb", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "javascriptcore-rs" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf053e7843f2812ff03ef5afe34bb9c06ffee120385caad4f6b9967fcd37d41c" +dependencies = [ + "bitflags 1.3.2", + "glib", + "javascriptcore-rs-sys", +] + +[[package]] +name = "javascriptcore-rs-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "905fbb87419c5cde6e3269537e4ea7d46431f3008c5d057e915ef3f115e7793c" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps 5.0.0", +] + +[[package]] +name = "jni" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "js-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "json-patch" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b1fb8864823fad91877e6caea0baca82e49e8db50f8e5c9f9a453e27d3330fc" +dependencies = [ + "jsonptr", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "jsonptr" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c6e529149475ca0b2820835d3dce8fcc41c6b943ca608d32f35b449255e4627" +dependencies = [ + "fluent-uri", + "serde", + "serde_json", +] + +[[package]] +name = "kuchikiki" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8" +dependencies = [ + "cssparser", + "html5ever", + "indexmap 1.9.3", + "matches", + "selectors", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + +[[package]] +name = "libredox" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +dependencies = [ + "bitflags 2.10.0", + "libc", + "redox_syscall 0.7.0", +] + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "loom" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "serde", + "serde_json", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "markup5ever" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" +dependencies = [ + "log", + "phf 0.10.1", + "phf_codegen 0.10.0", + "string_cache", + "string_cache_codegen", + "tendril", +] + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "ndk" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" +dependencies = [ + "bitflags 1.3.2", + "jni-sys", + "ndk-sys", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num-conv" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", + "objc_exception", +] + +[[package]] +name = "objc_exception" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +dependencies = [ + "cc", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "open" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2078c0039e6a54a0c42c28faa984e115fb4c2d5bf2208f77d1961002df8576f8" +dependencies = [ + "pathdiff", + "windows-sys 0.42.0", +] + +[[package]] +name = "pango" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e4045548659aee5313bde6c582b0d83a627b7904dd20dc2d9ef0895d414e4f" +dependencies = [ + "bitflags 1.3.2", + "glib", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2a00081cde4661982ed91d80ef437c20eacaf6aa1a5962c0279ae194662c3aa" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps 6.2.2", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.18", + "smallvec", + "windows-link", +] + +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "phf" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +dependencies = [ + "phf_macros 0.8.0", + "phf_shared 0.8.0", + "proc-macro-hack", +] + +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_shared 0.10.0", +] + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros 0.11.3", + "phf_shared 0.11.3", +] + +[[package]] +name = "phf_codegen" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", +] + +[[package]] +name = "phf_codegen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", +] + +[[package]] +name = "phf_generator" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" +dependencies = [ + "phf_shared 0.8.0", + "rand 0.7.3", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared 0.10.0", + "rand 0.8.5", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared 0.11.3", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "phf_shared" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" +dependencies = [ + "siphasher 0.3.11", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher 0.3.11", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher 1.0.2", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "plist" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07" +dependencies = [ + "base64 0.22.1", + "indexmap 2.13.0", + "quick-xml", + "serde", + "time", +] + +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-xml" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", + "rand_pcg", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_pcg" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "raw-window-handle" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.10.0", +] + +[[package]] +name = "redox_syscall" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" +dependencies = [ + "bitflags 2.10.0", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "regex" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +dependencies = [ + "bitflags 2.10.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54e910108742c57a770f492731f99be216a52fadd361b06c8fb59d74ccc267d2" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "selectors" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" +dependencies = [ + "bitflags 1.3.2", + "cssparser", + "derive_more", + "fxhash", + "log", + "matches", + "phf 0.8.0", + "phf_codegen 0.8.0", + "precomputed-hash", + "servo_arc", + "smallvec", + "thin-slice", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "indexmap 2.13.0", + "itoa 1.0.17", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_with" +version = "3.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.13.0", + "schemars 0.9.0", + "schemars 1.2.0", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "serialize-to-javascript" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5" +dependencies = [ + "serde", + "serde_json", + "serialize-to-javascript-impl", +] + +[[package]] +name = "serialize-to-javascript-impl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "servo_arc" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" +dependencies = [ + "nodrop", + "stable_deref_trait", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd-adler32" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "siphasher" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" + +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "soup2" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b4d76501d8ba387cf0fefbe055c3e0a59891d09f0f995ae4e4b16f6b60f3c0" +dependencies = [ + "bitflags 1.3.2", + "gio", + "glib", + "libc", + "once_cell", + "soup2-sys", +] + +[[package]] +name = "soup2-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "009ef427103fcb17f802871647a7fa6c60cbb654b4c4e4c0ac60a31c5f6dc9cf" +dependencies = [ + "bitflags 1.3.2", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps 5.0.0", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "state" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbe866e1e51e8260c9eed836a042a5e7f6726bb2b411dffeaa712e19c388f23b" +dependencies = [ + "loom", +] + +[[package]] +name = "string_cache" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" +dependencies = [ + "new_debug_unreachable", + "parking_lot", + "phf_shared 0.11.3", + "precomputed-hash", + "serde", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", + "proc-macro2", + "quote", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "system-deps" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18db855554db7bd0e73e06cf7ba3df39f97812cb11d3f75e71c39bf45171797e" +dependencies = [ + "cfg-expr 0.9.1", + "heck 0.3.3", + "pkg-config", + "toml 0.5.11", + "version-compare 0.0.11", +] + +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr 0.15.8", + "heck 0.5.0", + "pkg-config", + "toml 0.8.23", + "version-compare 0.2.1", +] + +[[package]] +name = "tao" +version = "0.16.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d298c441a1da46e28e8ad8ec205aab7fd8cd71b9d10e05454224eef422e1ae" +dependencies = [ + "bitflags 1.3.2", + "cairo-rs", + "cc", + "cocoa", + "core-foundation", + "core-graphics", + "crossbeam-channel", + "dispatch", + "gdk", + "gdk-pixbuf", + "gdk-sys", + "gdkwayland-sys", + "gdkx11-sys", + "gio", + "glib", + "glib-sys", + "gtk", + "image", + "instant", + "jni", + "lazy_static", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "objc", + "once_cell", + "parking_lot", + "png", + "raw-window-handle", + "scopeguard", + "serde", + "tao-macros", + "unicode-segmentation", + "uuid", + "windows 0.39.0", + "windows-implement 0.39.0", + "x11-dl", +] + +[[package]] +name = "tao-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "tar" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "tauri" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae1f57c291a6ab8e1d2e6b8ad0a35ff769c9925deb8a89de85425ff08762d0c" +dependencies = [ + "anyhow", + "cocoa", + "dirs-next", + "dunce", + "embed_plist", + "encoding_rs", + "flate2", + "futures-util", + "getrandom 0.2.17", + "glib", + "glob", + "gtk", + "heck 0.5.0", + "http", + "ignore", + "log", + "objc", + "once_cell", + "open", + "percent-encoding", + "plist", + "rand 0.8.5", + "raw-window-handle", + "regex", + "semver", + "serde", + "serde_json", + "serde_repr", + "serialize-to-javascript", + "state", + "tar", + "tauri-macros", + "tauri-runtime", + "tauri-runtime-wry", + "tauri-utils", + "tempfile", + "thiserror", + "tokio", + "url", + "uuid", + "webkit2gtk", + "webview2-com", + "windows 0.39.0", +] + +[[package]] +name = "tauri-build" +version = "1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2db08694eec06f53625cfc6fff3a363e084e5e9a238166d2989996413c346453" +dependencies = [ + "anyhow", + "cargo_toml", + "dirs-next", + "heck 0.5.0", + "json-patch", + "semver", + "serde", + "serde_json", + "tauri-utils", + "tauri-winres", + "walkdir", +] + +[[package]] +name = "tauri-codegen" +version = "1.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53438d78c4a037ffe5eafa19e447eea599bedfb10844cb08ec53c2471ac3ac3f" +dependencies = [ + "base64 0.21.7", + "brotli", + "ico", + "json-patch", + "plist", + "png", + "proc-macro2", + "quote", + "regex", + "semver", + "serde", + "serde_json", + "sha2", + "tauri-utils", + "thiserror", + "time", + "uuid", + "walkdir", +] + +[[package]] +name = "tauri-macros" +version = "1.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233988ac08c1ed3fe794cd65528d48d8f7ed4ab3895ca64cdaa6ad4d00c45c0b" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 1.0.109", + "tauri-codegen", + "tauri-utils", +] + +[[package]] +name = "tauri-runtime" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8066855882f00172935e3fa7d945126580c34dcbabab43f5d4f0c2398a67d47b" +dependencies = [ + "gtk", + "http", + "http-range", + "rand 0.8.5", + "raw-window-handle", + "serde", + "serde_json", + "tauri-utils", + "thiserror", + "url", + "uuid", + "webview2-com", + "windows 0.39.0", +] + +[[package]] +name = "tauri-runtime-wry" +version = "0.14.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce361fec1e186705371f1c64ae9dd2a3a6768bc530d0a2d5e75a634bb416ad4d" +dependencies = [ + "cocoa", + "gtk", + "percent-encoding", + "rand 0.8.5", + "raw-window-handle", + "tauri-runtime", + "tauri-utils", + "uuid", + "webkit2gtk", + "webview2-com", + "windows 0.39.0", + "wry", +] + +[[package]] +name = "tauri-starter" +version = "0.1.0" +dependencies = [ + "chrono", + "serde", + "serde_json", + "tauri", + "tauri-build", +] + +[[package]] +name = "tauri-utils" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c357952645e679de02cd35007190fcbce869b93ffc61b029f33fe02648453774" +dependencies = [ + "brotli", + "ctor", + "dunce", + "glob", + "heck 0.5.0", + "html5ever", + "infer", + "json-patch", + "kuchikiki", + "log", + "memchr", + "phf 0.11.3", + "proc-macro2", + "quote", + "semver", + "serde", + "serde_json", + "serde_with", + "thiserror", + "url", + "walkdir", + "windows-version", +] + +[[package]] +name = "tauri-winres" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5993dc129e544393574288923d1ec447c857f3f644187f4fbf7d9a875fbfc4fb" +dependencies = [ + "embed-resource", + "toml 0.7.8", +] + +[[package]] +name = "tempfile" +version = "3.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" +dependencies = [ + "fastrand", + "getrandom 0.3.4", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "tendril" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +dependencies = [ + "futf", + "mac", + "utf-8", +] + +[[package]] +name = "thin-slice" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9da98b7d9b7dad93488a84b8248efc35352b0b2657397d4167e7ad67e5d535e5" +dependencies = [ + "deranged", + "itoa 1.0.17", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc610bac2dcee56805c99642447d4c5dbde4d01f752ffea0199aee1f601dc4" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +dependencies = [ + "bytes", + "pin-project-lite", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.19.15", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.27", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.13.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap 2.13.0", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow 0.7.14", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f" +dependencies = [ + "getrandom 0.3.4", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "version-compare" +version = "0.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b" + +[[package]] +name = "version-compare" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vswhom" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" +dependencies = [ + "libc", + "vswhom-sys", +] + +[[package]] +name = "vswhom-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.114", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "webkit2gtk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8f859735e4a452aeb28c6c56a852967a8a76c8eb1cc32dbf931ad28a13d6370" +dependencies = [ + "bitflags 1.3.2", + "cairo-rs", + "gdk", + "gdk-sys", + "gio", + "gio-sys", + "glib", + "glib-sys", + "gobject-sys", + "gtk", + "gtk-sys", + "javascriptcore-rs", + "libc", + "once_cell", + "soup2", + "webkit2gtk-sys", +] + +[[package]] +name = "webkit2gtk-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d76ca6ecc47aeba01ec61e480139dda143796abcae6f83bcddf50d6b5b1dcf3" +dependencies = [ + "atk-sys", + "bitflags 1.3.2", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "gtk-sys", + "javascriptcore-rs-sys", + "libc", + "pango-sys", + "pkg-config", + "soup2-sys", + "system-deps 6.2.2", +] + +[[package]] +name = "webview2-com" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4a769c9f1a64a8734bde70caafac2b96cada12cd4aefa49196b3a386b8b4178" +dependencies = [ + "webview2-com-macros", + "webview2-com-sys", + "windows 0.39.0", + "windows-implement 0.39.0", +] + +[[package]] +name = "webview2-com-macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaebe196c01691db62e9e4ca52c5ef1e4fd837dcae27dae3ada599b5a8fd05ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "webview2-com-sys" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac48ef20ddf657755fdcda8dfed2a7b4fc7e4581acce6fe9b88c3d64f29dee7" +dependencies = [ + "regex", + "serde", + "serde_json", + "thiserror", + "windows 0.39.0", + "windows-bindgen", + "windows-metadata", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1c4bd0a50ac6020f65184721f758dba47bb9fbc2133df715ec74a237b26794a" +dependencies = [ + "windows-implement 0.39.0", + "windows_aarch64_msvc 0.39.0", + "windows_i686_gnu 0.39.0", + "windows_i686_msvc 0.39.0", + "windows_x86_64_gnu 0.39.0", + "windows_x86_64_msvc 0.39.0", +] + +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-bindgen" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68003dbd0e38abc0fb85b939240f4bce37c43a5981d3df37ccbaaa981b47cb41" +dependencies = [ + "windows-metadata", + "windows-tokens", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement 0.60.2", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba01f98f509cb5dc05f4e5fc95e535f78260f15fea8fe1a8abdd08f774f1cee7" +dependencies = [ + "syn 1.0.109", + "windows-tokens", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-metadata" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ee5e275231f07c6e240d14f34e1b635bf1faa1c76c57cfd59a5cdb9848e4278" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-tokens" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f838de2fe15fe6bac988e74b798f26499a8b21a9d97edec321e79b28d1d7f597" + +[[package]] +name = "windows-version" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7711666096bd4096ffa835238905bb33fb87267910e154b18b44eaabb340f2" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763fc57100a5f7042e3057e7e8d9bdd7860d330070251a73d003563a3bb49e1b" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bc7cbfe58828921e10a9f446fcaaf649204dcfe6c1ddd712c5eebae6bda1106" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6868c165637d653ae1e8dc4d82c25d4f97dd6605eaa8d784b5c6e0ab2a252b65" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e4d40883ae9cae962787ca76ba76390ffa29214667a111db9e0a1ad8377e809" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "wry" +version = "0.24.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c55c80b12287eb1ff7c365fc2f7a5037cb6181bd44c9fce81c8d1cf7605ffad6" +dependencies = [ + "base64 0.13.1", + "block", + "cocoa", + "core-graphics", + "crossbeam-channel", + "dunce", + "gdk", + "gio", + "glib", + "gtk", + "html5ever", + "http", + "kuchikiki", + "libc", + "log", + "objc", + "objc_id", + "once_cell", + "serde", + "serde_json", + "sha2", + "soup2", + "tao", + "thiserror", + "url", + "webkit2gtk", + "webkit2gtk-sys", + "webview2-com", + "windows 0.39.0", + "windows-implement 0.39.0", +] + +[[package]] +name = "x11" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71ddd76bcebeed25db614f82bf31a9f4222d3fbba300e6fb6c00afa26cbd4d9d" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8187381b52e32220d50b255276aa16a084ec0a9017a0ca2152a1f55c539758d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "zmij" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02aae0f83f69aafc94776e879363e9771d7ecbffe2c7fbb6c14c5e00dfe88439" diff --git a/templates/TauriStarter/app/src-tauri/Cargo.toml b/templates/TauriStarter/app/src-tauri/Cargo.toml new file mode 100644 index 0000000..94271b9 --- /dev/null +++ b/templates/TauriStarter/app/src-tauri/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "tauri-starter" +version = "0.1.0" +description = "Tauri Starter App" +authors = ["you"] +license = "" +repository = "" +edition = "2021" + +[build-dependencies] +tauri-build = { version = "1.5", features = [] } + +[dependencies] +tauri = { version = "1.6", features = ["shell-open"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +chrono = "0.4" +tiny_http = "0.12" # For automation HTTP server + +[features] +default = ["custom-protocol", "automation"] +custom-protocol = ["tauri/custom-protocol"] +automation = [] # Enable automation HTTP server on port 9876 diff --git a/templates/TauriStarter/app/src-tauri/build.rs b/templates/TauriStarter/app/src-tauri/build.rs new file mode 100644 index 0000000..d860e1e --- /dev/null +++ b/templates/TauriStarter/app/src-tauri/build.rs @@ -0,0 +1,3 @@ +fn main() { + tauri_build::build() +} diff --git a/templates/TauriStarter/app/src-tauri/icons/128x128.png b/templates/TauriStarter/app/src-tauri/icons/128x128.png new file mode 100644 index 0000000..17b190b Binary files /dev/null and b/templates/TauriStarter/app/src-tauri/icons/128x128.png differ diff --git a/templates/TauriStarter/app/src-tauri/icons/128x128@2x.png b/templates/TauriStarter/app/src-tauri/icons/128x128@2x.png new file mode 100644 index 0000000..0eec412 Binary files /dev/null and b/templates/TauriStarter/app/src-tauri/icons/128x128@2x.png differ diff --git a/templates/TauriStarter/app/src-tauri/icons/32x32.png b/templates/TauriStarter/app/src-tauri/icons/32x32.png new file mode 100644 index 0000000..450a9dc Binary files /dev/null and b/templates/TauriStarter/app/src-tauri/icons/32x32.png differ diff --git a/templates/TauriStarter/app/src-tauri/icons/Square107x107Logo.png b/templates/TauriStarter/app/src-tauri/icons/Square107x107Logo.png new file mode 100644 index 0000000..769c274 Binary files /dev/null and b/templates/TauriStarter/app/src-tauri/icons/Square107x107Logo.png differ diff --git a/templates/TauriStarter/app/src-tauri/icons/Square142x142Logo.png b/templates/TauriStarter/app/src-tauri/icons/Square142x142Logo.png new file mode 100644 index 0000000..26bdbe3 Binary files /dev/null and b/templates/TauriStarter/app/src-tauri/icons/Square142x142Logo.png differ diff --git a/templates/TauriStarter/app/src-tauri/icons/Square150x150Logo.png b/templates/TauriStarter/app/src-tauri/icons/Square150x150Logo.png new file mode 100644 index 0000000..7ced2ac Binary files /dev/null and b/templates/TauriStarter/app/src-tauri/icons/Square150x150Logo.png differ diff --git a/templates/TauriStarter/app/src-tauri/icons/Square284x284Logo.png b/templates/TauriStarter/app/src-tauri/icons/Square284x284Logo.png new file mode 100644 index 0000000..69e4c8f Binary files /dev/null and b/templates/TauriStarter/app/src-tauri/icons/Square284x284Logo.png differ diff --git a/templates/TauriStarter/app/src-tauri/icons/Square30x30Logo.png b/templates/TauriStarter/app/src-tauri/icons/Square30x30Logo.png new file mode 100644 index 0000000..0f5f0ea Binary files /dev/null and b/templates/TauriStarter/app/src-tauri/icons/Square30x30Logo.png differ diff --git a/templates/TauriStarter/app/src-tauri/icons/Square310x310Logo.png b/templates/TauriStarter/app/src-tauri/icons/Square310x310Logo.png new file mode 100644 index 0000000..e2fd515 Binary files /dev/null and b/templates/TauriStarter/app/src-tauri/icons/Square310x310Logo.png differ diff --git a/templates/TauriStarter/app/src-tauri/icons/Square44x44Logo.png b/templates/TauriStarter/app/src-tauri/icons/Square44x44Logo.png new file mode 100644 index 0000000..4dd16bc Binary files /dev/null and b/templates/TauriStarter/app/src-tauri/icons/Square44x44Logo.png differ diff --git a/templates/TauriStarter/app/src-tauri/icons/Square71x71Logo.png b/templates/TauriStarter/app/src-tauri/icons/Square71x71Logo.png new file mode 100644 index 0000000..dd8dbc6 Binary files /dev/null and b/templates/TauriStarter/app/src-tauri/icons/Square71x71Logo.png differ diff --git a/templates/TauriStarter/app/src-tauri/icons/Square89x89Logo.png b/templates/TauriStarter/app/src-tauri/icons/Square89x89Logo.png new file mode 100644 index 0000000..17fa405 Binary files /dev/null and b/templates/TauriStarter/app/src-tauri/icons/Square89x89Logo.png differ diff --git a/templates/TauriStarter/app/src-tauri/icons/StoreLogo.png b/templates/TauriStarter/app/src-tauri/icons/StoreLogo.png new file mode 100644 index 0000000..3e789b2 Binary files /dev/null and b/templates/TauriStarter/app/src-tauri/icons/StoreLogo.png differ diff --git a/templates/TauriStarter/app/src-tauri/icons/icon.icns b/templates/TauriStarter/app/src-tauri/icons/icon.icns new file mode 100644 index 0000000..49baf01 Binary files /dev/null and b/templates/TauriStarter/app/src-tauri/icons/icon.icns differ diff --git a/templates/TauriStarter/app/src-tauri/icons/icon.ico b/templates/TauriStarter/app/src-tauri/icons/icon.ico new file mode 100644 index 0000000..08b823c Binary files /dev/null and b/templates/TauriStarter/app/src-tauri/icons/icon.ico differ diff --git a/templates/TauriStarter/app/src-tauri/icons/icon.png b/templates/TauriStarter/app/src-tauri/icons/icon.png new file mode 100644 index 0000000..4237076 Binary files /dev/null and b/templates/TauriStarter/app/src-tauri/icons/icon.png differ diff --git a/templates/TauriStarter/app/src-tauri/src/automation/README.md b/templates/TauriStarter/app/src-tauri/src/automation/README.md new file mode 100644 index 0000000..e1da6e1 --- /dev/null +++ b/templates/TauriStarter/app/src-tauri/src/automation/README.md @@ -0,0 +1,166 @@ +# Tauri Automation Plugin + +A lightweight, reusable automation layer for Tauri applications. Enables external tools to interact with your app via HTTP API. + +## Features + +- **HTTP API** on `localhost:9876` for external automation +- **Navigation**: Route to pages +- **Element interaction**: Click, type, clear, select +- **Reading**: Get text, values, attributes, check existence +- **Waiting**: Wait for elements with timeout +- **Screenshots**: Capture page as PNG +- **Debug mode only**: Automatically disabled in release builds + +## Architecture + +``` +┌─────────────────┐ HTTP ┌──────────────────┐ +│ External Tool │ ───────────▶ │ Rust HTTP Server │ +│ (curl, tests) │ │ (port 9876) │ +└─────────────────┘ └────────┬─────────┘ + │ + │ Tauri Command + ▼ + ┌──────────────────┐ + │ JavaScript │ + │ Automation │ + │ Service │ + └────────┬─────────┘ + │ + │ DOM APIs + ▼ + ┌──────────────────┐ + │ WebView │ + │ (Your App) │ + └──────────────────┘ +``` + +## HTTP API + +### Endpoints + +| Method | Path | Description | +|--------|------|-------------| +| POST | `/automation/execute` | Execute a command | +| GET | `/automation/screenshot` | Capture screenshot (PNG) | +| GET | `/automation/health` | Health check | + +### Commands + +```bash +# Navigate to a route +curl -X POST http://localhost:9876/automation/execute \ + -H "Content-Type: application/json" \ + -d '{"command": "navigate", "args": {"path": "/profile"}}' + +# Click an element +curl -X POST http://localhost:9876/automation/execute \ + -H "Content-Type: application/json" \ + -d '{"command": "click", "args": {"selector": "#submit-btn"}}' + +# Type into an input +curl -X POST http://localhost:9876/automation/execute \ + -H "Content-Type: application/json" \ + -d '{"command": "type", "args": {"selector": "#email", "text": "test@example.com"}}' + +# Get element text +curl -X POST http://localhost:9876/automation/execute \ + -H "Content-Type: application/json" \ + -d '{"command": "getText", "args": {"selector": ".heading"}}' + +# Wait for element +curl -X POST http://localhost:9876/automation/execute \ + -H "Content-Type: application/json" \ + -d '{"command": "waitFor", "args": {"selector": ".loaded", "timeout": 5000}}' + +# Take screenshot +curl http://localhost:9876/automation/screenshot --output screenshot.png + +# Health check +curl http://localhost:9876/automation/health +``` + +### Available Commands + +| Command | Args | Returns | Description | +|---------|------|---------|-------------| +| `navigate` | `{path}` | `null` | Navigate to route | +| `click` | `{selector}` | `null` | Click element | +| `type` | `{selector, text}` | `null` | Type into input | +| `clear` | `{selector}` | `null` | Clear input value | +| `getText` | `{selector}` | `string` | Get element text | +| `getValue` | `{selector}` | `string` | Get input value | +| `getAttribute` | `{selector, attribute}` | `string` | Get attribute | +| `exists` | `{selector}` | `boolean` | Check if element exists | +| `waitFor` | `{selector, timeout?}` | `boolean` | Wait for element (default 5s) | +| `select` | `{selector, value}` | `null` | Select dropdown option | +| `check` | `{selector}` | `null` | Check checkbox | +| `uncheck` | `{selector}` | `null` | Uncheck checkbox | +| `getUrl` | `{}` | `string` | Get current URL | +| `getTitle` | `{}` | `string` | Get page title | +| `eval` | `{script}` | `any` | Evaluate JavaScript | + +## Installation (Adding to Another Project) + +### 1. Copy Rust files + +Copy `src-tauri/src/automation/` to your project's `src-tauri/src/`. + +### 2. Update Cargo.toml + +Add dependencies: +```toml +[dependencies] +tokio = { version = "1", features = ["rt-multi-thread", "macros"] } +warp = "0.3" +serde_json = "1.0" +``` + +### 3. Update main.rs + +```rust +#[cfg(debug_assertions)] +mod automation; + +fn main() { + let mut builder = tauri::Builder::default(); + + #[cfg(debug_assertions)] + { + builder = builder + .plugin(automation::init()) + .invoke_handler(tauri::generate_handler![ + automation::commands::execute_automation + ]); + } + + builder + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} +``` + +### 4. Copy JS files + +Copy `src/automation/` to your project's `src/`. + +### 5. Initialize in App.vue + +```typescript +import { initAutomation } from './automation' + +onMounted(() => { + initAutomation() +}) +``` + +## Security + +- **Debug builds only**: The HTTP server only runs in debug builds (`#[cfg(debug_assertions)]`) +- **Localhost only**: Server binds to `127.0.0.1`, not accessible externally +- **No auth**: Designed for local development/testing only + +## License + +MIT - Use freely in your projects. diff --git a/templates/TauriStarter/app/src-tauri/src/automation/mod.rs b/templates/TauriStarter/app/src-tauri/src/automation/mod.rs new file mode 100644 index 0000000..ae4513e --- /dev/null +++ b/templates/TauriStarter/app/src-tauri/src/automation/mod.rs @@ -0,0 +1,78 @@ +//! Tauri Automation Plugin +//! +//! Provides HTTP API for external automation of the application. +//! Enabled via the "automation" feature flag. + +pub mod server; + +use std::sync::{Arc, Mutex}; +use tauri::{ + plugin::{Builder, TauriPlugin}, + Manager, Runtime, Window, +}; + +/// Shared state for automation +pub struct AutomationState { + pub window: Arc>>>, +} + +impl Default for AutomationState { + fn default() -> Self { + Self { + window: Arc::new(Mutex::new(None)), + } + } +} + +/// Initialize the automation plugin +pub fn init() -> TauriPlugin { + Builder::new("automation") + .setup(|app| { + let state = AutomationState::default(); + app.manage(state); + + // Start HTTP server in background thread + let app_handle = app.clone(); + std::thread::spawn(move || { + server::start_server(app_handle); + }); + + println!("[Automation] Plugin initialized - HTTP server starting on port 9876"); + Ok(()) + }) + .build() +} + +/// Execute an automation command via JavaScript evaluation +pub fn execute_command(window: &Window, command: &str, args: &serde_json::Value) -> Result { + let args_json = serde_json::to_string(args).map_err(|e| e.to_string())?; + + let script = format!( + r#" + (async function() {{ + try {{ + if (typeof window.__TAURI_AUTOMATION__ === 'undefined') {{ + return JSON.stringify({{ error: 'Automation not initialized. Call initAutomation() first.' }}); + }} + const result = await window.__TAURI_AUTOMATION__.execute('{}', {}); + return JSON.stringify({{ success: true, result: result }}); + }} catch (e) {{ + return JSON.stringify({{ error: e.message || String(e) }}); + }} + }})() + "#, + command, + args_json + ); + + // Execute JavaScript and get result + let result = window.eval(&script); + + match result { + Ok(_) => { + // For Tauri 1.x, eval doesn't return a value directly + Ok(serde_json::json!({ "success": true, "note": "Command sent to webview" })) + } + Err(e) => Err(format!("Failed to execute script: {}", e)) + } +} diff --git a/templates/TauriStarter/app/src-tauri/src/automation/server.rs b/templates/TauriStarter/app/src-tauri/src/automation/server.rs new file mode 100644 index 0000000..755c2f8 --- /dev/null +++ b/templates/TauriStarter/app/src-tauri/src/automation/server.rs @@ -0,0 +1,326 @@ +//! HTTP server for automation commands + +use std::io::Read; +use std::sync::Mutex; +use tauri::{AppHandle, Manager}; +use tiny_http::{Server, Response, Header, Method}; + +const PORT: u16 = 9876; + +// Global screenshot buffer (simple approach without lazy_static) +static SCREENSHOT_DATA: Mutex> = Mutex::new(None); + +pub fn set_screenshot_data(data: String) { + if let Ok(mut guard) = SCREENSHOT_DATA.lock() { + *guard = Some(data); + } +} + +pub fn take_screenshot_data() -> Option { + if let Ok(mut guard) = SCREENSHOT_DATA.lock() { + guard.take() + } else { + None + } +} + +/// Start the HTTP server +pub fn start_server(app_handle: AppHandle) { + let addr = format!("127.0.0.1:{}", PORT); + + let server = match Server::http(&addr) { + Ok(s) => s, + Err(e) => { + eprintln!("[Automation] Failed to start server on {}: {}", addr, e); + return; + } + }; + + println!("[Automation] HTTP server listening on http://{}", addr); + + for mut request in server.incoming_requests() { + let method = request.method().clone(); + let url = request.url().to_string(); + + println!("[Automation] {} {}", method, url); + + let response = match (&method, url.as_str()) { + // Health check + (&Method::Get, "/automation/health") => { + json_response(serde_json::json!({ + "status": "ok", + "port": PORT, + "version": "1.0.0" + })) + } + + // Execute command + (&Method::Post, "/automation/execute") => { + handle_execute(&app_handle, &mut request) + } + + // Screenshot + (&Method::Get, "/automation/screenshot") => { + handle_screenshot(&app_handle) + } + + // CORS preflight + (&Method::Options, _) => { + cors_response() + } + + // 404 + _ => { + json_response_with_status( + serde_json::json!({ "error": "Not found" }), + 404 + ) + } + }; + + if let Err(e) = request.respond(response) { + eprintln!("[Automation] Failed to send response: {}", e); + } + } +} + +/// Handle execute command request +fn handle_execute( + app_handle: &AppHandle, + request: &mut tiny_http::Request, +) -> Response>> { + // Read body + let mut body = String::new(); + if let Err(e) = request.as_reader().read_to_string(&mut body) { + return json_response_with_status( + serde_json::json!({ "error": format!("Failed to read body: {}", e) }), + 400 + ); + } + + // Parse JSON + let payload: serde_json::Value = match serde_json::from_str(&body) { + Ok(v) => v, + Err(e) => { + return json_response_with_status( + serde_json::json!({ "error": format!("Invalid JSON: {}", e) }), + 400 + ); + } + }; + + let command = match payload.get("command").and_then(|v| v.as_str()) { + Some(c) => c.to_string(), + None => { + return json_response_with_status( + serde_json::json!({ "error": "Missing 'command' field" }), + 400 + ); + } + }; + + let args = payload.get("args").cloned().unwrap_or(serde_json::json!({})); + + // Get the main window + let window = match app_handle.get_window("main") { + Some(w) => w, + None => { + return json_response_with_status( + serde_json::json!({ "error": "Main window not found" }), + 500 + ); + } + }; + + // Build JavaScript to execute + let args_json = serde_json::to_string(&args).unwrap_or_else(|_| "{}".to_string()); + let script = format!( + r#" + (async function() {{ + if (typeof window.__TAURI_AUTOMATION__ === 'undefined') {{ + console.error('[Automation] Not initialized'); + return; + }} + try {{ + const result = await window.__TAURI_AUTOMATION__.execute('{}', {}); + window.__TAURI_AUTOMATION__._lastResult = {{ success: true, result: result }}; + }} catch (e) {{ + window.__TAURI_AUTOMATION__._lastResult = {{ success: false, error: e.message || String(e) }}; + }} + }})(); + "#, + command, + args_json + ); + + // Execute the script + if let Err(e) = window.eval(&script) { + return json_response_with_status( + serde_json::json!({ "error": format!("Script execution failed: {}", e) }), + 500 + ); + } + + // Wait a bit for async commands to complete + std::thread::sleep(std::time::Duration::from_millis(100)); + + // Return success - the result is stored in the webview for debugging + json_response(serde_json::json!({ + "success": true, + "message": "Command executed", + "command": command + })) +} + +/// Handle screenshot request +fn handle_screenshot(app_handle: &AppHandle) -> Response>> { + let window = match app_handle.get_window("main") { + Some(w) => w, + None => { + return json_response_with_status( + serde_json::json!({ "error": "Main window not found" }), + 500 + ); + } + }; + + // Request screenshot from JS + let script = r#" + (async function() { + if (typeof window.__TAURI_AUTOMATION__ === 'undefined') { + console.error('[Automation] Not initialized'); + return; + } + try { + await window.__TAURI_AUTOMATION__.captureAndSend(); + } catch (e) { + console.error('[Automation] Screenshot failed:', e); + } + })(); + "#; + + if let Err(e) = window.eval(script) { + return json_response_with_status( + serde_json::json!({ "error": format!("Screenshot request failed: {}", e) }), + 500 + ); + } + + // Wait for JS to send the screenshot data + // html2canvas can take a while, especially on first load + std::thread::sleep(std::time::Duration::from_millis(2000)); + + // Check if we have screenshot data + if let Some(data_url) = take_screenshot_data() { + // Parse data URL: data:image/png;base64,.... + if let Some(base64_data) = data_url.strip_prefix("data:image/png;base64,") { + match base64_decode(base64_data) { + Ok(bytes) => { + return png_response(bytes); + } + Err(e) => { + return json_response_with_status( + serde_json::json!({ "error": format!("Base64 decode failed: {}", e) }), + 500 + ); + } + } + } + } + + json_response_with_status( + serde_json::json!({ "error": "Screenshot not available. Make sure html2canvas is loaded." }), + 500 + ) +} + +/// Simple base64 decoder +fn base64_decode(input: &str) -> Result, String> { + let input = input.trim(); + let chars: Vec = input.chars().filter(|c| !c.is_whitespace()).collect(); + + const ALPHABET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + let mut output = Vec::new(); + let mut buffer: u32 = 0; + let mut bits_collected = 0; + + for c in chars { + if c == '=' { + break; + } + + let value = ALPHABET.iter().position(|&x| x == c as u8) + .ok_or_else(|| format!("Invalid base64 character: {}", c))? as u32; + + buffer = (buffer << 6) | value; + bits_collected += 6; + + if bits_collected >= 8 { + bits_collected -= 8; + output.push((buffer >> bits_collected) as u8); + buffer &= (1 << bits_collected) - 1; + } + } + + Ok(output) +} + +/// Create a JSON response +fn json_response(data: serde_json::Value) -> Response>> { + json_response_with_status(data, 200) +} + +/// Create a JSON response with status +fn json_response_with_status(data: serde_json::Value, status: u16) -> Response>> { + let body = serde_json::to_vec(&data).unwrap_or_else(|_| b"{}".to_vec()); + let len = body.len(); + let cursor = std::io::Cursor::new(body); + + Response::new( + tiny_http::StatusCode(status), + vec![ + Header::from_bytes(&b"Content-Type"[..], &b"application/json"[..]).unwrap(), + Header::from_bytes(&b"Access-Control-Allow-Origin"[..], &b"*"[..]).unwrap(), + Header::from_bytes(&b"Access-Control-Allow-Methods"[..], &b"GET, POST, OPTIONS"[..]).unwrap(), + Header::from_bytes(&b"Access-Control-Allow-Headers"[..], &b"Content-Type"[..]).unwrap(), + ], + cursor, + Some(len), + None, + ) +} + +/// Create a PNG response +fn png_response(data: Vec) -> Response>> { + let len = data.len(); + let cursor = std::io::Cursor::new(data); + + Response::new( + tiny_http::StatusCode(200), + vec![ + Header::from_bytes(&b"Content-Type"[..], &b"image/png"[..]).unwrap(), + Header::from_bytes(&b"Access-Control-Allow-Origin"[..], &b"*"[..]).unwrap(), + ], + cursor, + Some(len), + None, + ) +} + +/// CORS preflight response +fn cors_response() -> Response>> { + let cursor = std::io::Cursor::new(Vec::new()); + + Response::new( + tiny_http::StatusCode(204), + vec![ + Header::from_bytes(&b"Access-Control-Allow-Origin"[..], &b"*"[..]).unwrap(), + Header::from_bytes(&b"Access-Control-Allow-Methods"[..], &b"GET, POST, OPTIONS"[..]).unwrap(), + Header::from_bytes(&b"Access-Control-Allow-Headers"[..], &b"Content-Type"[..]).unwrap(), + ], + cursor, + Some(0), + None, + ) +} diff --git a/templates/TauriStarter/app/src-tauri/src/main.rs b/templates/TauriStarter/app/src-tauri/src/main.rs new file mode 100644 index 0000000..48078cd --- /dev/null +++ b/templates/TauriStarter/app/src-tauri/src/main.rs @@ -0,0 +1,52 @@ +// Prevents additional console window on Windows in release +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +use chrono::Local; + +// Automation module - enabled via feature flag +#[cfg(feature = "automation")] +mod automation; + +/// Log frontend console messages to stdout with timestamp +#[tauri::command] +fn log_to_stdout(level: String, message: String) { + let timestamp = Local::now().format("%Y-%m-%d %H:%M:%S%.3f"); + println!("[{}] [{}] {}", timestamp, level, message); +} + +/// Example command - replace with your own +#[tauri::command] +fn greet(name: &str) -> String { + format!("Hello, {}! Welcome to Tauri.", name) +} + +/// Receive screenshot data from JS automation +#[cfg(feature = "automation")] +#[tauri::command] +fn automation_screenshot_data(data: String) { + automation::server::set_screenshot_data(data); +} + +#[cfg(feature = "automation")] +fn main() { + tauri::Builder::default() + .plugin(automation::init()) + .invoke_handler(tauri::generate_handler![ + log_to_stdout, + greet, + automation_screenshot_data + ]) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} + +#[cfg(not(feature = "automation"))] +fn main() { + tauri::Builder::default() + .invoke_handler(tauri::generate_handler![ + log_to_stdout, + greet + ]) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} diff --git a/templates/TauriStarter/app/src-tauri/tauri.conf.json b/templates/TauriStarter/app/src-tauri/tauri.conf.json new file mode 100644 index 0000000..e3f8739 --- /dev/null +++ b/templates/TauriStarter/app/src-tauri/tauri.conf.json @@ -0,0 +1,46 @@ +{ + "build": { + "beforeDevCommand": "npm run dev", + "beforeBuildCommand": "npm run build", + "devPath": "http://localhost:9000", + "distDir": "../dist" + }, + "package": { + "productName": "TauriStarter", + "version": "0.1.0" + }, + "tauri": { + "allowlist": { + "all": false, + "shell": { + "open": true + } + }, + "bundle": { + "active": true, + "targets": "all", + "identifier": "com.tauristarter.app", + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ] + }, + "security": { + "csp": null + }, + "windows": [ + { + "fullscreen": false, + "resizable": true, + "title": "Tauri Starter", + "width": 1200, + "height": 800, + "minWidth": 800, + "minHeight": 600 + } + ] + } +} diff --git a/templates/TauriStarter/app/src/App.vue b/templates/TauriStarter/app/src/App.vue new file mode 100644 index 0000000..4a9aed7 --- /dev/null +++ b/templates/TauriStarter/app/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/templates/TauriStarter/app/src/automation/README.md b/templates/TauriStarter/app/src/automation/README.md new file mode 100644 index 0000000..5ec0e78 --- /dev/null +++ b/templates/TauriStarter/app/src/automation/README.md @@ -0,0 +1,141 @@ +# Automation Service (JavaScript) + +Frontend automation service that handles DOM manipulation commands from the Rust backend. + +## Files + +| File | Purpose | +|------|---------| +| `index.ts` | Main service initialization and screenshot capture | +| `commands.ts` | All DOM automation commands | + +## Setup + +Initialize in your app's entry point (App.vue or main.ts): + +```typescript +import { initAutomation } from './automation' + +// In your app setup (only runs in dev) +initAutomation() +``` + +## Available Commands + +### Navigation +- `navigate` - Navigate to a Vue Router path + +### Element Interaction +- `click` - Click an element +- `type` - Type text into an input +- `clear` - Clear an input value +- `select` - Select dropdown option +- `check` - Check a checkbox +- `uncheck` - Uncheck a checkbox +- `focus` - Focus an element +- `blur` - Blur an element +- `pressKey` - Simulate key press +- `submit` - Submit a form +- `scrollTo` - Scroll to element + +### Reading +- `getText` - Get element text content +- `getValue` - Get input value +- `getAttribute` - Get element attribute +- `exists` - Check if element exists +- `getElements` - Get all matching elements +- `getHtml` - Get element HTML +- `getUrl` - Get current URL +- `getTitle` - Get page title + +### Waiting +- `waitFor` - Wait for element to appear +- `wait` - Wait for specified milliseconds + +### Advanced +- `eval` - Execute arbitrary JavaScript + +## Adding Custom Commands + +Add new commands to `commands.ts`: + +```typescript +export const commands: Record = { + // ... existing commands + + async myCustomCommand(args): Promise { + const value = args.value as string + // Your implementation + }, +} +``` + +## Screenshot Support + +Screenshots use html2canvas, loaded dynamically from CDN: +- https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js + +For offline use, bundle html2canvas: +```bash +npm install html2canvas +``` + +Then update `index.ts` to import directly instead of CDN loading. + +## Vue Router Integration + +The `navigate` command tries to use Vue Router. For this to work, you need to expose the router on the window object. Update your `main.ts`: + +```typescript +const app = createApp(App) +app.use(router) + +// Expose for automation +if (import.meta.env.DEV) { + (window as any).__VUE_APP__ = app +} + +app.mount('#app') +``` + +## Selectors + +All selector arguments use standard CSS selectors: + +```bash +# By ID +{"selector": "#my-id"} + +# By class +{"selector": ".my-class"} + +# By attribute +{"selector": "[data-testid='submit']"} + +# Combined +{"selector": "form#login .btn-primary"} + +# Quasar components often need to target inner elements +{"selector": ".q-input input"} +{"selector": ".q-btn"} +``` + +## Tips for Quasar + +Quasar components have specific DOM structures: + +| Component | Selector for inner element | +|-----------|---------------------------| +| q-input | `.q-input input` or `.q-input textarea` | +| q-select | `.q-select` (click to open) | +| q-btn | `.q-btn` | +| q-checkbox | `.q-checkbox` | +| q-tab | `.q-tab` | + +Use `data-testid` attributes for reliable selectors: +```vue + +``` +```bash +{"selector": "[data-testid='submit-btn']"} +``` diff --git a/templates/TauriStarter/app/src/automation/commands.ts b/templates/TauriStarter/app/src/automation/commands.ts new file mode 100644 index 0000000..d92b76e --- /dev/null +++ b/templates/TauriStarter/app/src/automation/commands.ts @@ -0,0 +1,387 @@ +/** + * Automation Commands + * + * DOM manipulation commands for automated testing. + */ + +export type CommandArgs = Record +export type CommandResult = unknown + +type CommandHandler = (args: CommandArgs) => Promise + +// Router type for type safety +interface VueRouter { + push: (path: string) => Promise + currentRoute: { value: { path: string } } +} + +// Get Vue Router instance from the app +function getRouter(): VueRouter | undefined { + // Access the router from the app instance stored on window + const app = (window as unknown as { __VUE_APP__?: { config: { globalProperties: { $router: VueRouter } } } }).__VUE_APP__ + return app?.config.globalProperties.$router +} + +/** + * Wait for an element to appear in the DOM + */ +async function waitForElement(selector: string, timeout = 5000): Promise { + const start = Date.now() + + while (Date.now() - start < timeout) { + const element = document.querySelector(selector) + if (element) return element + await new Promise(r => setTimeout(r, 100)) + } + + return null +} + +/** + * Get an element or throw + */ +function getElement(selector: string): Element { + const element = document.querySelector(selector) + if (!element) { + throw new Error(`Element not found: ${selector}`) + } + return element +} + +/** + * Simulate realistic typing into an input + */ +function simulateTyping(element: HTMLInputElement | HTMLTextAreaElement, text: string): void { + element.focus() + element.value = text + + // Dispatch events to trigger Vue reactivity + element.dispatchEvent(new Event('input', { bubbles: true })) + element.dispatchEvent(new Event('change', { bubbles: true })) +} + +/** + * Available automation commands + */ +export const commands: Record = { + /** + * Navigate to a route + */ + async navigate(args): Promise { + const path = args.path as string + if (!path) throw new Error('Missing path argument') + + const router = getRouter() + if (router) { + await router.push(path) + } else { + // Fallback: use window.location + window.location.hash = path + } + + // Wait for navigation to complete + await new Promise(r => setTimeout(r, 100)) + }, + + /** + * Click an element + */ + async click(args): Promise { + const selector = args.selector as string + if (!selector) throw new Error('Missing selector argument') + + const element = await waitForElement(selector, 5000) + if (!element) throw new Error(`Element not found: ${selector}`) + + // Scroll into view + element.scrollIntoView({ behavior: 'instant', block: 'center' }) + await new Promise(r => setTimeout(r, 50)) + + // Click + ;(element as HTMLElement).click() + + // Wait for any resulting actions + await new Promise(r => setTimeout(r, 100)) + }, + + /** + * Type text into an input + */ + async type(args): Promise { + const selector = args.selector as string + const text = args.text as string + if (!selector) throw new Error('Missing selector argument') + if (text === undefined) throw new Error('Missing text argument') + + const element = await waitForElement(selector, 5000) + if (!element) throw new Error(`Element not found: ${selector}`) + + if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) { + simulateTyping(element, text) + } else { + throw new Error(`Element is not an input: ${selector}`) + } + }, + + /** + * Clear an input + */ + async clear(args): Promise { + const selector = args.selector as string + if (!selector) throw new Error('Missing selector argument') + + const element = getElement(selector) + + if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) { + simulateTyping(element, '') + } else { + throw new Error(`Element is not an input: ${selector}`) + } + }, + + /** + * Get element text content + */ + async getText(args): Promise { + const selector = args.selector as string + if (!selector) throw new Error('Missing selector argument') + + const element = await waitForElement(selector, 5000) + if (!element) throw new Error(`Element not found: ${selector}`) + + return element.textContent?.trim() || '' + }, + + /** + * Get input value + */ + async getValue(args): Promise { + const selector = args.selector as string + if (!selector) throw new Error('Missing selector argument') + + const element = getElement(selector) + + if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement) { + return element.value + } + + throw new Error(`Element is not an input: ${selector}`) + }, + + /** + * Get element attribute + */ + async getAttribute(args): Promise { + const selector = args.selector as string + const attribute = args.attribute as string + if (!selector) throw new Error('Missing selector argument') + if (!attribute) throw new Error('Missing attribute argument') + + const element = getElement(selector) + return element.getAttribute(attribute) + }, + + /** + * Check if element exists + */ + async exists(args): Promise { + const selector = args.selector as string + if (!selector) throw new Error('Missing selector argument') + + return document.querySelector(selector) !== null + }, + + /** + * Wait for element to appear + */ + async waitFor(args): Promise { + const selector = args.selector as string + const timeout = (args.timeout as number) || 5000 + if (!selector) throw new Error('Missing selector argument') + + const element = await waitForElement(selector, timeout) + return element !== null + }, + + /** + * Select dropdown option + */ + async select(args): Promise { + const selector = args.selector as string + const value = args.value as string + if (!selector) throw new Error('Missing selector argument') + if (value === undefined) throw new Error('Missing value argument') + + const element = getElement(selector) + + if (element instanceof HTMLSelectElement) { + element.value = value + element.dispatchEvent(new Event('change', { bubbles: true })) + } else { + throw new Error(`Element is not a select: ${selector}`) + } + }, + + /** + * Check a checkbox + */ + async check(args): Promise { + const selector = args.selector as string + if (!selector) throw new Error('Missing selector argument') + + const element = getElement(selector) + + if (element instanceof HTMLInputElement && element.type === 'checkbox') { + if (!element.checked) { + element.click() + } + } else { + throw new Error(`Element is not a checkbox: ${selector}`) + } + }, + + /** + * Uncheck a checkbox + */ + async uncheck(args): Promise { + const selector = args.selector as string + if (!selector) throw new Error('Missing selector argument') + + const element = getElement(selector) + + if (element instanceof HTMLInputElement && element.type === 'checkbox') { + if (element.checked) { + element.click() + } + } else { + throw new Error(`Element is not a checkbox: ${selector}`) + } + }, + + /** + * Get current URL/route + */ + async getUrl(): Promise { + return window.location.href + }, + + /** + * Get page title + */ + async getTitle(): Promise { + return document.title + }, + + /** + * Evaluate arbitrary JavaScript + */ + async eval(args): Promise { + const script = args.script as string + if (!script) throw new Error('Missing script argument') + + // Use Function constructor to evaluate in global scope + const fn = new Function(`return (async () => { ${script} })()`) + return await fn() + }, + + /** + * Get all elements matching selector + */ + async getElements(args): Promise<{ count: number; texts: string[] }> { + const selector = args.selector as string + if (!selector) throw new Error('Missing selector argument') + + const elements = document.querySelectorAll(selector) + const texts = Array.from(elements).map(el => el.textContent?.trim() || '') + + return { count: elements.length, texts } + }, + + /** + * Scroll to element + */ + async scrollTo(args): Promise { + const selector = args.selector as string + if (!selector) throw new Error('Missing selector argument') + + const element = getElement(selector) + element.scrollIntoView({ behavior: 'smooth', block: 'center' }) + + await new Promise(r => setTimeout(r, 300)) + }, + + /** + * Get page HTML + */ + async getHtml(args): Promise { + const selector = (args.selector as string) || 'body' + const element = getElement(selector) + return element.innerHTML + }, + + /** + * Wait for a specified time + */ + async wait(args): Promise { + const ms = (args.ms as number) || 1000 + await new Promise(r => setTimeout(r, ms)) + }, + + /** + * Focus an element + */ + async focus(args): Promise { + const selector = args.selector as string + if (!selector) throw new Error('Missing selector argument') + + const element = getElement(selector) as HTMLElement + element.focus() + }, + + /** + * Blur (unfocus) an element + */ + async blur(args): Promise { + const selector = args.selector as string + if (!selector) throw new Error('Missing selector argument') + + const element = getElement(selector) as HTMLElement + element.blur() + }, + + /** + * Press a key + */ + async pressKey(args): Promise { + const key = args.key as string + const selector = args.selector as string + if (!key) throw new Error('Missing key argument') + + const target = selector ? getElement(selector) : document.activeElement || document.body + + target.dispatchEvent(new KeyboardEvent('keydown', { key, bubbles: true })) + target.dispatchEvent(new KeyboardEvent('keyup', { key, bubbles: true })) + }, + + /** + * Submit a form + */ + async submit(args): Promise { + const selector = args.selector as string + if (!selector) throw new Error('Missing selector argument') + + const element = getElement(selector) + + if (element instanceof HTMLFormElement) { + element.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true })) + } else { + // Find parent form + const form = element.closest('form') + if (form) { + form.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true })) + } else { + throw new Error('No form found') + } + } + }, +} diff --git a/templates/TauriStarter/app/src/automation/index.ts b/templates/TauriStarter/app/src/automation/index.ts new file mode 100644 index 0000000..dbe97aa --- /dev/null +++ b/templates/TauriStarter/app/src/automation/index.ts @@ -0,0 +1,116 @@ +/** + * Tauri Automation Service + * + * Provides automation capabilities for external testing tools. + * Only active in development builds. + */ + +import { invoke } from '@tauri-apps/api/tauri' +import { commands, type CommandArgs, type CommandResult } from './commands' + +declare global { + interface Window { + __TAURI_AUTOMATION__: AutomationService + } +} + +export interface AutomationService { + execute: (command: string, args: CommandArgs) => Promise + screenshot: () => Promise + captureAndSend: () => Promise + _lastResult: { success: boolean; result?: unknown; error?: string } | null +} + +/** + * Initialize the automation service + * Call this once when your app starts + * Note: Automation is controlled by Rust feature flag, JS side always initializes + */ +export function initAutomation(): void { + console.log('[Automation] Initializing...') + + const service: AutomationService = { + _lastResult: null, + + /** + * Execute an automation command + */ + async execute(command: string, args: CommandArgs = {}): Promise { + console.log(`[Automation] Executing: ${command}`, args) + + const handler = commands[command] + if (!handler) { + throw new Error(`Unknown command: ${command}`) + } + + try { + const result = await handler(args) + console.log(`[Automation] Result:`, result) + return result + } catch (error) { + console.error(`[Automation] Error:`, error) + throw error + } + }, + + /** + * Capture screenshot and return as data URL + */ + async screenshot(): Promise { + // Dynamically import html2canvas + const html2canvas = await loadHtml2Canvas() + const canvas = await html2canvas(document.body, { + backgroundColor: '#121212', + scale: 1, + logging: false, + useCORS: true, + }) + return canvas.toDataURL('image/png') + }, + + /** + * Capture screenshot and send to Rust backend + */ + async captureAndSend(): Promise { + try { + const dataUrl = await this.screenshot() + await invoke('automation_screenshot_data', { data: dataUrl }) + console.log('[Automation] Screenshot sent to backend') + } catch (error) { + console.error('[Automation] Screenshot capture failed:', error) + throw error + } + }, + } + + // Expose globally for Rust to call via eval + window.__TAURI_AUTOMATION__ = service + + console.log('[Automation] Ready. HTTP API available at http://localhost:9876') +} + +/** + * Dynamically load html2canvas from CDN + */ +async function loadHtml2Canvas(): Promise { + if ((window as unknown as { html2canvas?: unknown }).html2canvas) { + return (window as unknown as { html2canvas: typeof import('html2canvas').default }).html2canvas + } + + return new Promise((resolve, reject) => { + const script = document.createElement('script') + script.src = 'https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js' + script.onload = () => { + const h2c = (window as unknown as { html2canvas: typeof import('html2canvas').default }).html2canvas + if (h2c) { + resolve(h2c) + } else { + reject(new Error('html2canvas failed to load')) + } + } + script.onerror = () => reject(new Error('Failed to load html2canvas')) + document.head.appendChild(script) + }) +} + +export { commands } from './commands' diff --git a/templates/TauriStarter/app/src/boot/console-logger.ts b/templates/TauriStarter/app/src/boot/console-logger.ts new file mode 100644 index 0000000..d24687f --- /dev/null +++ b/templates/TauriStarter/app/src/boot/console-logger.ts @@ -0,0 +1,52 @@ +// Console logger for Tauri - forwards console.log to Rust for file logging +// This allows us to capture frontend logs when running as a desktop app + +import { invoke } from '@tauri-apps/api/tauri' + +// Check if running in Tauri environment +function isTauri (): boolean { + return typeof window !== 'undefined' && '__TAURI__' in window +} + +export function setupConsoleLogger () { + // Only activate in Tauri environment + if (!isTauri()) { + return + } + + const originalLog = console.log + const originalWarn = console.warn + const originalError = console.error + + const sendToRust = (level: string, args: unknown[]) => { + const message = args.map(arg => { + if (typeof arg === 'object') { + try { + return JSON.stringify(arg) + } catch { + return String(arg) + } + } + return String(arg) + }).join(' ') + + invoke('log_to_stdout', { level, message }).catch(() => { + // Silently fail if Rust command not available + }) + } + + console.log = (...args: unknown[]) => { + originalLog.apply(console, args) + sendToRust('INFO', args) + } + + console.warn = (...args: unknown[]) => { + originalWarn.apply(console, args) + sendToRust('WARN', args) + } + + console.error = (...args: unknown[]) => { + originalError.apply(console, args) + sendToRust('ERROR', args) + } +} diff --git a/templates/TauriStarter/app/src/components/.gitkeep b/templates/TauriStarter/app/src/components/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/templates/TauriStarter/app/src/css/app.scss b/templates/TauriStarter/app/src/css/app.scss new file mode 100644 index 0000000..4857efe --- /dev/null +++ b/templates/TauriStarter/app/src/css/app.scss @@ -0,0 +1,2 @@ +// App-specific styles +// Add your custom styles here diff --git a/templates/TauriStarter/app/src/css/quasar-variables.scss b/templates/TauriStarter/app/src/css/quasar-variables.scss new file mode 100644 index 0000000..9aee270 --- /dev/null +++ b/templates/TauriStarter/app/src/css/quasar-variables.scss @@ -0,0 +1,14 @@ +// Quasar SCSS variables +// Customize colors, breakpoints, etc. + +$primary : #1976D2; +$secondary : #26A69A; +$accent : #9C27B0; + +$dark : #1D1D1D; +$dark-page : #121212; + +$positive : #21BA45; +$negative : #C10015; +$info : #31CCEC; +$warning : #F2C037; diff --git a/templates/TauriStarter/app/src/layouts/MainLayout.vue b/templates/TauriStarter/app/src/layouts/MainLayout.vue new file mode 100644 index 0000000..7ca0da1 --- /dev/null +++ b/templates/TauriStarter/app/src/layouts/MainLayout.vue @@ -0,0 +1,54 @@ + + + diff --git a/templates/TauriStarter/app/src/main.ts b/templates/TauriStarter/app/src/main.ts new file mode 100644 index 0000000..f0616b5 --- /dev/null +++ b/templates/TauriStarter/app/src/main.ts @@ -0,0 +1,49 @@ +import { createApp } from 'vue' +import { createPinia } from 'pinia' +import { Quasar, Notify, Dialog, Loading } from 'quasar' +import router from './router' +import { setupConsoleLogger } from './boot/console-logger' + +// Import Quasar css +import '@quasar/extras/roboto-font/roboto-font.css' +import '@quasar/extras/material-icons/material-icons.css' +import 'quasar/src/css/index.sass' + +// Import app styles +import './css/app.scss' + +// Import root component +import App from './App.vue' + +// Setup console logger for Tauri +setupConsoleLogger() + +const app = createApp(App) + +app.use(createPinia()) +app.use(router) +app.use(Quasar, { + plugins: { + Notify, + Dialog, + Loading + }, + config: { + dark: 'auto' + } +}) + +// Mount the app +app.mount('#q-app') + +// Expose Vue app for automation +;(window as unknown as { __VUE_APP__: typeof app }).__VUE_APP__ = app + +// Initialize automation service after app is mounted +setTimeout(() => { + import('./automation').then(({ initAutomation }) => { + initAutomation() + }).catch(err => { + console.warn('[Automation] Failed to load:', err) + }) +}, 100) diff --git a/templates/TauriStarter/app/src/pages/ErrorNotFound.vue b/templates/TauriStarter/app/src/pages/ErrorNotFound.vue new file mode 100644 index 0000000..e5dc8cc --- /dev/null +++ b/templates/TauriStarter/app/src/pages/ErrorNotFound.vue @@ -0,0 +1,17 @@ + + + diff --git a/templates/TauriStarter/app/src/pages/IndexPage.vue b/templates/TauriStarter/app/src/pages/IndexPage.vue new file mode 100644 index 0000000..30d517e --- /dev/null +++ b/templates/TauriStarter/app/src/pages/IndexPage.vue @@ -0,0 +1,34 @@ + + + diff --git a/templates/TauriStarter/app/src/router/index.ts b/templates/TauriStarter/app/src/router/index.ts new file mode 100644 index 0000000..3237d43 --- /dev/null +++ b/templates/TauriStarter/app/src/router/index.ts @@ -0,0 +1,22 @@ +import { createRouter, createWebHistory } from 'vue-router' + +const routes = [ + { + path: '/', + component: () => import('layouts/MainLayout.vue'), + children: [ + { path: '', component: () => import('pages/IndexPage.vue') } + ] + }, + { + path: '/:catchAll(.*)*', + component: () => import('pages/ErrorNotFound.vue') + } +] + +const router = createRouter({ + history: createWebHistory(), + routes +}) + +export default router diff --git a/templates/TauriStarter/app/src/stores/example.ts b/templates/TauriStarter/app/src/stores/example.ts new file mode 100644 index 0000000..c5eeaa8 --- /dev/null +++ b/templates/TauriStarter/app/src/stores/example.ts @@ -0,0 +1,26 @@ +import { defineStore } from 'pinia' +import { ref, computed } from 'vue' + +export const useExampleStore = defineStore('example', () => { + // State + const count = ref(0) + + // Getters + const doubleCount = computed(() => count.value * 2) + + // Actions + function increment () { + count.value++ + } + + function reset () { + count.value = 0 + } + + return { + count, + doubleCount, + increment, + reset + } +}) diff --git a/templates/TauriStarter/app/tsconfig.json b/templates/TauriStarter/app/tsconfig.json new file mode 100644 index 0000000..4f76754 --- /dev/null +++ b/templates/TauriStarter/app/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "preserve", + "strict": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "noFallthroughCasesInSwitch": true, + "baseUrl": ".", + "paths": { + "src/*": ["src/*"], + "components/*": ["src/components/*"], + "layouts/*": ["src/layouts/*"], + "pages/*": ["src/pages/*"], + "stores/*": ["src/stores/*"], + "boot/*": ["src/boot/*"] + } + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"], + "exclude": ["node_modules", "dist", "src-tauri"] +} diff --git a/templates/TauriStarter/app/vite.config.ts b/templates/TauriStarter/app/vite.config.ts new file mode 100644 index 0000000..9a9fb3d --- /dev/null +++ b/templates/TauriStarter/app/vite.config.ts @@ -0,0 +1,31 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import { quasar, transformAssetUrls } from '@quasar/vite-plugin' +import { fileURLToPath } from 'node:url' + +export default defineConfig({ + plugins: [ + vue({ + template: { transformAssetUrls } + }), + quasar({ + sassVariables: 'src/css/quasar-variables.scss' + }) + ], + resolve: { + alias: { + src: fileURLToPath(new URL('./src', import.meta.url)), + components: fileURLToPath(new URL('./src/components', import.meta.url)), + layouts: fileURLToPath(new URL('./src/layouts', import.meta.url)), + pages: fileURLToPath(new URL('./src/pages', import.meta.url)), + stores: fileURLToPath(new URL('./src/stores', import.meta.url)), + boot: fileURLToPath(new URL('./src/boot', import.meta.url)) + } + }, + server: { + port: 9000, + strictPort: false + }, + clearScreen: false, + envPrefix: ['VITE_', 'TAURI_'] +}) diff --git a/templates/TauriStarter/docs/README.md b/templates/TauriStarter/docs/README.md new file mode 100644 index 0000000..4546f90 --- /dev/null +++ b/templates/TauriStarter/docs/README.md @@ -0,0 +1,50 @@ +# Documentation + +> Technical documentation for [Project Name] + +## Table of Contents + +### Getting Started +- [Installation & Setup](./getting-started.md) + +### Features + + +### Architecture +- [Tech Stack & Architecture](./architecture.md) + +### Development +- [Development Guide](./development.md) +- [Build & Deployment](./deployment.md) + +--- + +## Documentation Guidelines + +### Adding New Documentation + +After completing a feature or phase, add documentation: + +1. Create a new `.md` file in this folder using the naming convention below +2. Add a link to the Table of Contents above +3. Use the appropriate template as a starting point: + - [Feature template](./TEMPLATE-feature.md) - For documenting features + - [Build plan template](./TEMPLATE-build-plan.md) - For creating structured build plans + +### Naming Convention + +| Type | Pattern | Example | +|------|---------|---------| +| Feature docs | `feature-[name].md` | `feature-authentication.md` | +| Component docs | `component-[name].md` | `component-sidebar.md` | +| Integration docs | `integration-[name].md` | `integration-nhost.md` | +| Guide docs | `guide-[topic].md` | `guide-testing.md` | +| Build plans | `[name]-build-plan.md` | `auth-build-plan.md` | + +### Documentation Structure + +Each feature doc should include: +- **Overview** - What the feature does +- **Usage** - How to use it (with code examples) +- **Configuration** - Available options/settings +- **Related** - Links to related features/components diff --git a/templates/TauriStarter/docs/TEMPLATE-build-plan.md b/templates/TauriStarter/docs/TEMPLATE-build-plan.md new file mode 100644 index 0000000..baa88e2 --- /dev/null +++ b/templates/TauriStarter/docs/TEMPLATE-build-plan.md @@ -0,0 +1,121 @@ +# [Project Name] - Build Plan + +## Executor Config +```yaml +default_branch_prefix: feat/phase +test_before_commit: true +require_passing_tests: true +max_test_retries: 3 +``` + +## Phase 1: [Phase Name] +**repo**: [repository-name] +**branch**: feat/phase-1-[slug] + +### 1.1 [Task Name] +- **task**: [Description of what to do. Be specific and actionable. + Include context about existing code to use or patterns to follow.] +- **test**: `[command to verify success]` +- **commit**: "[Commit message]" + +### 1.2 [Task Name] +- **task**: [Description] +- **test**: `[test command]` +- **commit**: "[Commit message]" + +### 1.3 Documentation +- **task**: Update documentation for phase 1 changes. + Add any new files to docs/ folder. +- **test**: none +- **commit**: "Document phase 1" + +--- + +## Phase 2: [Phase Name] +**repo**: [repository-name] +**branch**: feat/phase-2-[slug] +**depends_on**: Phase 1 + +### 2.1 [Task Name] +- **task**: [Description] +- **test**: `[test command]` +- **commit**: "[Commit message]" + +### 2.2 Documentation +- **task**: Update documentation for phase 2 changes. +- **test**: none +- **commit**: "Document phase 2" + +--- + +## Current Status + +**Phase**: 1 - [Phase Name] +**Task**: [Current task] + +--- + +## Template Instructions + +> Remove this section when using this template + +### Plan Format + +Each plan consists of: + +1. **Executor Config** (optional) - YAML block with settings +2. **Phases** - Major milestones (`## Phase N: Name`) +3. **Tasks** - Individual work items (`### N.N Task Name`) + +### Phase Metadata + +| Field | Required | Description | +|-------|----------|-------------| +| `**repo**` | Yes | Repository to work in | +| `**branch**` | No | Branch to create (default: `{prefix}-{N}`) | +| `**depends_on**` | No | Phase that must complete first | + +### Task Fields + +| Field | Required | Description | +|-------|----------|-------------| +| `- **task**` | Yes | What the agent should do | +| `- **test**` | No | Command to verify (`none` to skip) | +| `- **commit**` | No | Commit message (agent decides if omitted) | + +### Writing Good Tasks + +**Be specific:** +```markdown +# Bad +- **task**: Add authentication + +# Good +- **task**: Add JWT authentication with /api/login and /api/logout endpoints. + Use bcrypt for password hashing. Store tokens in httpOnly cookies. +``` + +**Include context:** +```markdown +- **task**: Create dashboard component at /dashboard showing: + - User's recent activity (last 10 items) + - Account settings link + Use the existing UserCard component for the header. +``` + +**Use testable tests:** +```markdown +# Bad +- **test**: Check that it works + +# Good +- **test**: `pnpm test && pnpm build` +``` + +### Tips + +1. **One thing per task** - Don't combine unrelated work +2. **Tests are checkpoints** - Use them to verify progress +3. **Commits are savepoints** - Small, focused commits +4. **Phases are milestones** - Each should be independently useful +5. **End phases with docs** - Document as you go diff --git a/templates/TauriStarter/docs/TEMPLATE-feature.md b/templates/TauriStarter/docs/TEMPLATE-feature.md new file mode 100644 index 0000000..4ac5860 --- /dev/null +++ b/templates/TauriStarter/docs/TEMPLATE-feature.md @@ -0,0 +1,60 @@ +# Feature Name + +> Brief one-line description of what this feature does + +## Overview + +Explain what this feature does and why it exists. Include: +- The problem it solves +- Key capabilities +- When to use it + +## Usage + +### Basic Example + +```typescript +// Code example showing basic usage +``` + +### Advanced Example + +```typescript +// Code example showing advanced/common patterns +``` + +## Configuration + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `option1` | `string` | `""` | Description of option | +| `option2` | `boolean` | `false` | Description of option | + +## Components + +List the main components involved in this feature: + +| Component | Location | Purpose | +|-----------|----------|---------| +| `ComponentName` | `src/components/ComponentName.vue` | Brief description | + +## Data Flow + +Describe how data flows through this feature (if applicable): + +``` +User Action → Component → Store → API → Database + ↑ ↓ + UI Update ← ← ← ← Response +``` + +## Related + +- [Related Feature](./feature-related.md) +- [Related Component](./component-related.md) + +## Changelog + +| Date | Change | +|------|--------| +| YYYY-MM-DD | Initial implementation | diff --git a/templates/TauriStarter/docs/architecture.md b/templates/TauriStarter/docs/architecture.md new file mode 100644 index 0000000..947dac9 --- /dev/null +++ b/templates/TauriStarter/docs/architecture.md @@ -0,0 +1,61 @@ +# Architecture + +> Technical architecture and design decisions for [Project Name] + +## Tech Stack + +| Layer | Technology | Purpose | +|-------|------------|---------| +| Frontend | Vue 3 + Quasar | UI framework | +| State | Pinia | State management | +| Routing | Vue Router | Client-side routing | +| Desktop | Tauri | Native desktop wrapper | +| Backend | Nhost | Auth, database, storage | + +## Project Structure + +``` +app/ +├── src/ +│ ├── boot/ # Initialization scripts +│ ├── components/ # Reusable Vue components +│ ├── composables/ # Vue composables (shared logic) +│ ├── layouts/ # Page layouts +│ ├── pages/ # Route pages +│ ├── router/ # Route definitions +│ ├── stores/ # Pinia stores +│ ├── services/ # API services +│ └── types/ # TypeScript types +├── src-tauri/ # Tauri/Rust code +└── build.sh # Build script +``` + +## Key Design Decisions + +### [Decision 1] + +**Context**: [Why this decision was needed] + +**Decision**: [What was decided] + +**Consequences**: [Trade-offs and implications] + +### [Decision 2] + +... + +## Data Model + +[Describe main entities and relationships] + +``` +Entity1 ──────< Entity2 + │ + └──────< Entity3 +``` + +## External Integrations + +| Service | Purpose | Documentation | +|---------|---------|---------------| +| [Service] | [Purpose] | [Link] | diff --git a/templates/TauriStarter/docs/deployment.md b/templates/TauriStarter/docs/deployment.md new file mode 100644 index 0000000..a671797 --- /dev/null +++ b/templates/TauriStarter/docs/deployment.md @@ -0,0 +1,78 @@ +# Build & Deployment + +> Build process and deployment instructions for [Project Name] + +## Build Commands + +```bash +cd app + +# Development build +./build.sh -dev -open + +# Production build (installs to ~/Applications) +./build.sh -prod + +# Clean build artifacts +./build.sh clean +``` + +## Build Output + +``` +app/build/ +├── dev/ +│ └── [AppName].app # Development build +├── prod/ +│ └── [AppName].app # Production build +├── logs/ +│ └── build_latest.log # Build output +└── console/ + └── console_latest.log # Runtime logs +``` + +## Production Build + +### macOS + +1. Build the production version: + ```bash + ./build.sh -prod + ``` + +2. The app is automatically installed to `~/Applications/` + +### Distribution + +[Add distribution instructions - notarization, signing, etc.] + +## TeamIDE Deployment + +If using TeamIDE for hosting: + +```bash +# Deploy changes +teamide_deploy + +# Set environment variables +teamide_set_env_vars + +# Check logs +teamide_get_logs +``` + +**Workspace ID**: `[your-workspace-id]` + +## Environment Variables + +### Required for Production + +```env +# List production environment variables +``` + +### Optional + +```env +# List optional environment variables +``` diff --git a/templates/TauriStarter/docs/development.md b/templates/TauriStarter/docs/development.md new file mode 100644 index 0000000..8e3de58 --- /dev/null +++ b/templates/TauriStarter/docs/development.md @@ -0,0 +1,72 @@ +# Development Guide + +> Development workflow and practices for [Project Name] + +## Development Workflow + +### Build and Run + +This project uses a **build-and-run** approach (not hot reload): + +```bash +cd app +./build.sh -dev -open # Build and launch +./build.sh logs # View console output +``` + +### Why Build-and-Run? + +- **Dev = Prod** - What you test is what ships +- **Full logging** - Console output captured to files +- **No dev-only bugs** - Identical to production environment + +## Making Changes + +### Adding a New Feature + +1. Create components in `src/components/` +2. Add pages in `src/pages/` +3. Register routes in `src/router/` +4. Add state management in `src/stores/` +5. **Rebuild to test**: `./build.sh -dev -open` +6. **Document the feature** in `docs/` + +### Adding a Tauri Command + +1. Add the command in `src-tauri/src/main.rs` +2. Register it in the `invoke_handler` +3. Call from frontend with `invoke('command_name', { args })` + +## Debugging + +### Console Logs + +```bash +./build.sh logs # Last 100 lines +cat build/console/console_latest.log # Full log +``` + +### Build Errors + +```bash +cat build/logs/build_latest.log +``` + +### Common Issues + +| Issue | Solution | +|-------|----------| +| Build fails with cache errors | `./build.sh clean && ./build.sh -dev -open` | +| Changes not appearing | Rebuild - this is build-and-run, not hot reload | +| Console logs missing | Check `console-logger.ts` is in boot files | + +## Code Style + +- **Components**: PascalCase (`UserProfile.vue`) +- **Composables**: camelCase with `use` prefix (`useAuth.ts`) +- **Stores**: camelCase (`userStore.ts`) +- **Types**: PascalCase (`UserProfile.ts`) + +## Testing + +[Add testing instructions when implemented] diff --git a/templates/TauriStarter/docs/getting-started.md b/templates/TauriStarter/docs/getting-started.md new file mode 100644 index 0000000..512a475 --- /dev/null +++ b/templates/TauriStarter/docs/getting-started.md @@ -0,0 +1,52 @@ +# Getting Started + +> Installation and initial setup guide for [Project Name] + +## Prerequisites + +- Node.js 18+ +- npm +- [Additional prerequisites] + +## Installation + +```bash +# Clone the repository +git clone https://github.com/dcherrera/[ProjectName].git +cd [ProjectName]/app + +# Install dependencies +npm install +``` + +## Configuration + +1. Copy the environment template: + ```bash + cp .env.example .env + ``` + +2. Configure required environment variables: + ```env + # Required + VARIABLE_NAME=value + ``` + +## Running the App + +### Development + +```bash +./build.sh -dev -open +``` + +### Production + +```bash +./build.sh -prod +``` + +## Next Steps + +- [Architecture Overview](./architecture.md) - Understand the codebase structure +- [Development Guide](./development.md) - Learn the development workflow diff --git a/templates/build.sh b/templates/build.sh new file mode 100755 index 0000000..9a4505a --- /dev/null +++ b/templates/build.sh @@ -0,0 +1,330 @@ +#!/bin/bash +# +# Desktop Build Script Template (Tauri) +# Builds the Tauri desktop app for macOS +# +# Usage: +# ./build.sh -dev # Development build (runs from build folder) +# ./build.sh -dev -open # Development build and open app +# ./build.sh -prod # Production build (builds to build/prod/) +# ./build.sh -install # Build and open Finder for drag-to-Applications +# ./build.sh clean # Clean build folder (preserves logs) +# ./build.sh clean-logs # Clean all logs +# ./build.sh logs # View latest console log +# +# ============================================================ +# PROJECT CONFIGURATION - Customize these for your project +# ============================================================ +APP_NAME="MyApp" # Display name of the app +BUNDLE_ID_BASE="com.myapp.app" # Base bundle ID +VERSION="0.1.0" # App version +BINARY_NAME="my-app" # Rust binary name (usually lowercase with hyphens) +# ============================================================ + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +log() { echo -e "${BLUE}[Build]${NC} $1"; } +success() { echo -e "${GREEN}[Build]${NC} $1"; } +warn() { echo -e "${YELLOW}[Build]${NC} $1"; } +error() { echo -e "${RED}[Build]${NC} $1"; exit 1; } + +# Paths +TAURI_DIR="$SCRIPT_DIR/src-tauri" + +# Build folder structure +BUILD_DIR="$SCRIPT_DIR/build" +DEV_BUILD_DIR="$BUILD_DIR/dev" +PROD_BUILD_DIR="$BUILD_DIR/prod" +LOGS_DIR="$BUILD_DIR/logs" +CONSOLE_DIR="$BUILD_DIR/console" +PROD_INSTALL_DIR="$HOME/Applications" + +# Timestamp for log files +TIMESTAMP=$(date +"%Y%m%d_%H%M%S") + +# Parse arguments +BUILD_MODE="" +OPEN_APP=false +SHOW_INSTALL=false +CLEAN_BUILD=false +CLEAN_LOGS=false +SHOW_LOGS=false + +while [[ $# -gt 0 ]]; do + case $1 in + -prod|--prod|--production) + BUILD_MODE="prod" + shift + ;; + -dev|--dev|--development) + BUILD_MODE="dev" + shift + ;; + -open|--open) + OPEN_APP=true + shift + ;; + -install|--install) + SHOW_INSTALL=true + BUILD_MODE="prod" + shift + ;; + clean|--clean) + CLEAN_BUILD=true + shift + ;; + clean-logs|--clean-logs) + CLEAN_LOGS=true + shift + ;; + logs|--logs) + SHOW_LOGS=true + shift + ;; + -h|--help) + echo "$APP_NAME Build Script" + echo "" + echo "Usage: $0 [-dev|-prod] [-open] [clean|clean-logs|logs]" + echo "" + echo "Build Commands:" + echo " -dev, --dev Development build (runs from build folder)" + echo " -prod, --prod Production build (builds to build/prod/)" + echo " -install Build prod and open Finder for drag-to-Applications" + echo " -open, --open Open the app after building" + echo "" + echo "Other Commands:" + echo " clean Clean build artifacts (preserves logs)" + echo " clean-logs Remove all logs" + echo " logs Show latest console log (last 100 lines)" + echo " -h, --help Show this help" + echo "" + echo "Build folders:" + echo " Dev: $DEV_BUILD_DIR" + echo " Prod: $PROD_BUILD_DIR (also installs to $PROD_INSTALL_DIR)" + echo " Logs: $LOGS_DIR" + echo " Console: $CONSOLE_DIR" + echo "" + echo "Examples:" + echo " ./build.sh -dev -open # Build dev and open app" + echo " ./build.sh -prod # Build prod to build/prod/" + echo " ./build.sh -install # Build and open Finder to drag to Applications" + echo " ./build.sh logs # View latest console output" + exit 0 + ;; + *) + error "Unknown option: $1. Use --help for usage." + ;; + esac +done + +# Handle logs command +if [ "$SHOW_LOGS" = true ]; then + if [ -f "$CONSOLE_DIR/console_latest.log" ]; then + log "Latest console log:" + echo "----------------------------------------" + tail -100 "$CONSOLE_DIR/console_latest.log" + else + warn "No console logs found at $CONSOLE_DIR/console_latest.log" + fi + exit 0 +fi + +# Handle clean-logs command +if [ "$CLEAN_LOGS" = true ]; then + log "Cleaning logs..." + rm -rf "$LOGS_DIR" "$CONSOLE_DIR" + success "Logs cleaned!" + exit 0 +fi + +# Handle clean command +if [ "$CLEAN_BUILD" = true ]; then + log "Cleaning build folder (preserving logs)..." + + # Backup logs + if [ -d "$LOGS_DIR" ]; then + mv "$LOGS_DIR" "$SCRIPT_DIR/.logs_backup" 2>/dev/null || true + fi + if [ -d "$CONSOLE_DIR" ]; then + mv "$CONSOLE_DIR" "$SCRIPT_DIR/.console_backup" 2>/dev/null || true + fi + + # Clean build dir + rm -rf "$BUILD_DIR" + + # Clean other build artifacts + rm -rf "$SCRIPT_DIR/dist" + rm -rf "$SCRIPT_DIR/.quasar" + rm -rf "$TAURI_DIR/target" + + # Restore logs + mkdir -p "$BUILD_DIR" + if [ -d "$SCRIPT_DIR/.logs_backup" ]; then + mv "$SCRIPT_DIR/.logs_backup" "$LOGS_DIR" + fi + if [ -d "$SCRIPT_DIR/.console_backup" ]; then + mv "$SCRIPT_DIR/.console_backup" "$CONSOLE_DIR" + fi + + success "Build folder cleaned!" + exit 0 +fi + +# Require a build mode if not running a command +if [ -z "$BUILD_MODE" ]; then + error "No build mode specified. Use -dev or -prod. See --help for usage." +fi + +# Create log directories +mkdir -p "$LOGS_DIR" +mkdir -p "$CONSOLE_DIR" + +# Set up logging +BUILD_LOG="$LOGS_DIR/build_${BUILD_MODE}_$TIMESTAMP.log" +CONSOLE_LOG="$CONSOLE_DIR/console_$TIMESTAMP.log" + +# Create symlinks to latest logs +ln -sf "build_${BUILD_MODE}_$TIMESTAMP.log" "$LOGS_DIR/build_latest.log" +ln -sf "console_$TIMESTAMP.log" "$CONSOLE_DIR/console_latest.log" + +# Logging function that writes to both console and file +log_both() { + echo -e "${BLUE}[Build]${NC} $1" + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$BUILD_LOG" +} + +# Set paths based on build mode +if [ "$BUILD_MODE" = "prod" ]; then + APP_BUNDLE="$PROD_BUILD_DIR/$APP_NAME.app" + INSTALL_BUNDLE="$PROD_INSTALL_DIR/$APP_NAME.app" + BUNDLE_ID="$BUNDLE_ID_BASE" +else + APP_BUNDLE="$DEV_BUILD_DIR/$APP_NAME.app" + INSTALL_BUNDLE="" + BUNDLE_ID="${BUNDLE_ID_BASE}.dev" +fi + +log_both "==========================================" +log_both "Building $APP_NAME ($BUILD_MODE mode)" +log_both "==========================================" +log_both "Build log: $BUILD_LOG" +log_both "Console log: $CONSOLE_LOG" + +# Create build directories +mkdir -p "$DEV_BUILD_DIR" +mkdir -p "$PROD_BUILD_DIR" + +# Kill existing instances before building +log_both "Stopping existing instances..." +pkill -f "$DEV_BUILD_DIR/$APP_NAME.app/Contents/MacOS" 2>/dev/null || true +pkill -f "$PROD_BUILD_DIR/$APP_NAME.app/Contents/MacOS" 2>/dev/null || true +pkill -f "$PROD_INSTALL_DIR/$APP_NAME.app/Contents/MacOS" 2>/dev/null || true +sleep 1 + +# Check dependencies +command -v node >/dev/null 2>&1 || error "Node.js is required but not installed" +command -v cargo >/dev/null 2>&1 || error "Rust/Cargo is required but not installed" + +# Step 1: Install npm dependencies if needed +if [ ! -d "$SCRIPT_DIR/node_modules" ]; then + log_both "Installing npm dependencies..." + npm install 2>&1 | tee -a "$BUILD_LOG" +fi + +# Step 2: Build with Tauri (builds frontend + Rust + creates bundle) +log_both "Building with Tauri (this embeds frontend into binary)..." +cd "$SCRIPT_DIR" +if [ "$SHOW_INSTALL" = true ]; then + # No --ci flag: opens Finder window for drag-to-Applications + npx tauri build 2>&1 | tee -a "$BUILD_LOG" +else + # --ci flag: suppress Finder window + npx tauri build --ci 2>&1 | tee -a "$BUILD_LOG" +fi + +# Find the generated app bundle +TAURI_BUNDLE_DIR="$TAURI_DIR/target/release/bundle/macos" +TAURI_APP_BUNDLE="$TAURI_BUNDLE_DIR/$APP_NAME.app" + +if [ ! -d "$TAURI_APP_BUNDLE" ]; then + error "Tauri build failed - app bundle not found at $TAURI_APP_BUNDLE" +fi + +# Step 3: Copy the Tauri-built bundle to our build directory +log_both "Copying app bundle to $APP_BUNDLE..." +rm -rf "$APP_BUNDLE" +cp -R "$TAURI_APP_BUNDLE" "$APP_BUNDLE" + +# Step 4: Update Info.plist with our bundle ID (dev vs prod) +log_both "Updating Info.plist with bundle ID: $BUNDLE_ID..." +if [ "$BUILD_MODE" = "dev" ]; then + DISPLAY_NAME="$APP_NAME (Dev)" +else + DISPLAY_NAME="$APP_NAME" +fi + +# Use PlistBuddy to update the plist +/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $BUNDLE_ID" "$APP_BUNDLE/Contents/Info.plist" +/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName $DISPLAY_NAME" "$APP_BUNDLE/Contents/Info.plist" 2>/dev/null || \ + /usr/libexec/PlistBuddy -c "Add :CFBundleDisplayName string $DISPLAY_NAME" "$APP_BUNDLE/Contents/Info.plist" + +# Step 5: For prod, also install to ~/Applications +if [ "$BUILD_MODE" = "prod" ] && [ -n "$INSTALL_BUNDLE" ]; then + log_both "Installing to $INSTALL_BUNDLE..." + pkill -f "$INSTALL_BUNDLE/Contents/MacOS" 2>/dev/null || true + sleep 1 + rm -rf "$INSTALL_BUNDLE" + mkdir -p "$PROD_INSTALL_DIR" + cp -R "$APP_BUNDLE" "$INSTALL_BUNDLE" + touch "$INSTALL_BUNDLE" +fi + +# Touch the app to update Finder cache +touch "$APP_BUNDLE" + +# Build complete +log_both "==========================================" +success "Build Complete!" +log_both "==========================================" +echo "" +echo " Build folder: $BUILD_DIR" +echo " App bundle: $APP_BUNDLE" +echo " Mode: $BUILD_MODE" +echo " Bundle ID: $BUNDLE_ID" +if [ "$BUILD_MODE" = "prod" ] && [ -n "$INSTALL_BUNDLE" ]; then + echo " Installed to: $INSTALL_BUNDLE" +fi +echo "" +echo " Build log: $BUILD_LOG" +echo " Console log: $CONSOLE_LOG" +echo "" + +# Open the app and capture console output +if [ "$OPEN_APP" = true ]; then + log_both "Opening app (console output will be logged)..." + + # Run the app and capture output to console log + "$APP_BUNDLE/Contents/MacOS/$BINARY_NAME" 2>&1 | while IFS= read -r line; do + echo "$line" + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $line" >> "$CONSOLE_LOG" + done & + + echo " App is running. Console output logged to:" + echo " $CONSOLE_LOG" + echo "" + echo " View logs with: ./build.sh logs" +else + echo " To run: open \"$APP_BUNDLE\"" + echo " Or with logging: \"$APP_BUNDLE/Contents/MacOS/$BINARY_NAME\" 2>&1 | tee -a \"$CONSOLE_LOG\"" +fi +echo "" diff --git a/templates/claude.md b/templates/claude.md new file mode 100644 index 0000000..5ab34f7 --- /dev/null +++ b/templates/claude.md @@ -0,0 +1,623 @@ +# Project Guidelines + +## Protecting This File + +**IMPORTANT**: This file (claude.md) is gitignored and can be lost during branch operations! + +Git doesn't protect untracked/ignored files during `git checkout` or branch switches. Before major git operations: +```bash +cp claude.md claude.md.backup +``` + +## Coding Best Practices (CRITICAL) + +**Read `coding-best-practices.md` before writing any code.** It contains personal coding conventions that apply to every project — naming rules, file/function size limits, folder nesting patterns, persistence rules, and language-specific structure guides. Those rules override defaults and must be followed. + +### File Header Check Rule + +**Every time you open a file to work on it, check the file header first.** Look for outstanding `@todo` items, unresolved `@issues`, or outdated `@status` notes. If any are completed or resolved, clean them up before doing other work. If a TODO is relevant to the current task, address it. This ensures nothing falls through the cracks. + +## Project Structure (CRITICAL) + +This project follows a standardized structure for future modularity. The long-term goal is to enable drag-and-drop of components between projects. **This structure must be followed.** + +``` +ProjectRoot/ # git root +├── claude.md # (gitignored) AI assistant guidelines +├── coding-best-practices.md # Coding conventions (read before Phase 1) +├── build_spec.md # (gitignored) Full project specification +├── build_plan.md # (gitignored) Phased task checklist +├── .gitignore +├── docs/ # Public-facing documentation (parsed to HTML for website) +│ ├── README.md # Docs index with table of contents +│ ├── getting-started.md +│ ├── architecture.md +│ ├── development.md +│ ├── deployment.md +│ └── feature-*.md # Feature docs (added per phase) +├── InternalDocs/ # Internal development documentation (not public) +│ └── ... # Design decisions, technical debt, internal API docs +└── app/ # ALL project code lives here + ├── src/ + │ ├── assets/ # Static assets + │ ├── boot/ # Quasar boot files (nhost init, etc.) + │ ├── components/ # Vue components + │ ├── composables/ # Vue composables + │ ├── layouts/ # Page layouts + │ ├── pages/ # Route pages + │ ├── router/ # Vue Router config + │ ├── stores/ # Pinia stores + │ ├── services/ # API services + │ └── types/ # TypeScript types + ├── nhost/ # Nhost configuration + │ ├── functions/ # Serverless functions + │ ├── migrations/ # Database migrations + │ └── metadata/ # Hasura metadata + ├── public/ # Public static files + ├── docker-compose.yml + ├── .env # Dev environment (gitignored) + └── .env.prod # Prod environment (gitignored) +``` + +## Terminology + +- **"build spec"** or **"spec"** refers to `build_spec.md` - the full project description +- **"build plan"** or **"plan"** refers to `build_plan.md` - the phased task checklist + +## Onboarding Questions (Ask at Project Start) + +At the start of every new project conversation, gather these details before writing any code: + +1. **Brand colors & fonts** - Primary, secondary, accent colors. Typography preferences. Any existing brand guidelines or color palette? +2. **App personality & tone** - Formal or casual? Dark or light default theme? Dense or spacious layout? Any design inspiration or reference apps? +3. **Target platform** - Desktop-first, mobile-first, or responsive? Specific OS targets (macOS, Windows, Linux)? Minimum screen sizes? +4. **Auth requirements** - Login method (email/password, OAuth, magic link)? User roles and permissions? Public or private app? + +Don't assume defaults for any of these. Ask, get answers, then document them in the Project-Specific Configuration section at the bottom of this file. + +## Tech Stack + +- **Frontend**: Quasar Framework (Vue 3) - SPA mode +- **Desktop** (optional): Tauri (Rust) - Cross-platform builds (macOS, Windows, Linux) +- **Backend**: Nhost (self-hosted via Docker) + - PostgreSQL - Database + - Hasura - GraphQL API + - Auth - Authentication service + - Storage - File storage + - Functions - Serverless functions (Node.js) +- **Containerization**: Docker / Docker Compose + +### Tauri Desktop Apps + +When building desktop apps with Tauri: +- Add `src-tauri/` folder inside `app/` +- Use the build-and-run approach (no hot reload) for consistent dev/prod builds +- Separate bundle IDs for dev and prod (can run both simultaneously) + +## Testing Changes (CRITICAL) + +**After every code editing session, you MUST rebuild the app so the user can test your changes.** + +```bash +cd app +./build.sh -dev -open +``` + +### Why This Matters + +- This uses a **build-and-run** approach, not hot reload +- Your code changes are NOT visible until you rebuild +- Always rebuild before asking the user to test +- If the user reports issues, check the logs first: `./build.sh logs` + +## Build Script + +**Always use `build.sh` for building the app.** This ensures consistent builds and logging for collaborative debugging. + +```bash +cd app + +./build.sh -dev -open # Build dev and open app +./build.sh -prod # Build prod to build/prod/ +./build.sh -install # Build prod and open Finder for drag-to-Applications +./build.sh logs # View latest console output (last 100 lines) +./build.sh clean # Clean build artifacts (preserves logs) +./build.sh clean-logs # Remove all logs +``` + +### Commands + +| Command | Description | +|---------|-------------| +| `-dev` | Development build. Bundle ID: `com.[app].dev` | +| `-prod` | Production build. Builds to `build/prod/`. | +| `-install` | Build prod and open Finder for drag-to-Applications. | +| `-open` | Open the app after building (use with `-dev` or `-prod`) | +| `logs` | Show last 100 lines of console output | +| `clean` | Remove build artifacts (preserves logs) | +| `clean-logs` | Remove all log files | + +### Why Build-and-Run (No Hot Reload) + +This project uses a **build-and-run** approach instead of hot reload: + +| Aspect | Hot Reload | Build-and-Run | +|--------|------------|---------------| +| Speed | Instant updates | Full rebuild required | +| Dev/Prod parity | Different environments | Identical to production | +| Debugging | Dev-only issues possible | What you test = what ships | +| Logging | Console only | Full logs to files | + +The tradeoff is slower iteration, but you always test exactly what will ship. + +### What the Build Does + +1. **Build with Tauri** - `npx tauri build` does all of the following: + - Build frontend (`npm run build` → `dist/spa/`) + - Build Rust binary with embedded frontend + - Create .app bundle in `src-tauri/target/release/bundle/macos/` +2. **Copy to build folder** - Copies bundle to `build/dev/` or `build/prod/` +3. **Update Info.plist** - Sets correct bundle ID for dev/prod +4. **Install (prod only)** - Copies to `~/Applications` + +**Important**: Using `npx tauri build` ensures the frontend is properly embedded in the binary. Manual `cargo build --release` does NOT embed the frontend. + +### Build Output + +Builds are organized in separate folders: + +``` +app/build/ +├── dev/ +│ └── AppName.app # Dev build (bundle ID: .dev) +├── prod/ +│ └── AppName.app # Prod build +├── logs/ +│ ├── build_dev_*.log # Build output logs +│ └── build_latest.log # Symlink to latest +└── console/ + ├── console_*.log # App runtime console output + └── console_latest.log # Symlink to latest +``` + +Dev and prod have different bundle IDs, so both can run simultaneously. + +### Logging + +All build output and app console output is logged: + +- **Build logs**: `build/logs/build_latest.log` - compilation output, errors +- **Console logs**: `build/console/console_latest.log` - runtime `console.log()`, errors + +When debugging, run `./build.sh logs` to see the latest console output. + +### Console Logging Setup (Tauri) + +For frontend `console.log()` to appear in the logs, you need: + +1. **Boot file** - Copy `templates/scripts/console-logger.ts` to `app/src/boot/` +2. **Register boot** - Add `'console-logger'` to `boot` array in `quasar.config.js` +3. **Rust command** - Add `log_to_stdout` command to `src-tauri/src/commands.rs` +4. **Cargo dep** - Add `chrono = "0.4"` to `Cargo.toml` + +The console-logger.ts template includes the Rust code you need to add. + +**How it works:** +``` +console.log() → console-logger.ts → invoke('log_to_stdout') → Rust println!() → stdout → build.sh logs +``` + +### When to Clean + +Run `./build.sh clean` when: +- Switching between major dependency versions +- Build errors reference stale/cached files +- Rust compilation issues after Tauri config changes +- Before creating a fresh production build + +## Node.js Environment + +**Node.js version**: Always match Debian stable (currently Node.js 18.x for Debian 12 Bookworm) + +Check current Debian stable Node version: https://packages.debian.org/stable/nodejs + +**Package manager**: Use npm. Commit lock files for reproducible builds. + +Rules: +- Always commit `package-lock.json` - required for deterministic installs +- Never ignore lock files (`package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`) +- Use `npm install` to install dependencies +- Use `npm run + + +``` + +Within `