diff --git a/.env.example b/.env.example deleted file mode 100644 index bd16935..0000000 --- a/.env.example +++ /dev/null @@ -1,10 +0,0 @@ -# App Configuration -NODE_ENV=development -PORT=3000 - -# API Keys (optional) -# ANTHROPIC_API_KEY= -# OPENAI_API_KEY= - -# Database (if applicable) -# DATABASE_URL=sqlite:./data/local.db diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ab51419..335d66c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,55 +5,37 @@ on: branches: ["**"] pull_request: -jobs: - frontend: - name: Frontend Checks - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v7 - - - name: Setup Node - uses: actions/setup-node@v7 - with: - node-version: 22 - cache: npm - - - name: Install dependencies - run: npm ci - - - name: Run canonical frontend verification - run: npm run verify:required:frontend - - - name: Upload frontend QA artifacts - if: always() - uses: actions/upload-artifact@v7 - with: - name: frontend-qa-artifacts - path: artifacts/*.* - if-no-files-found: ignore +permissions: + contents: read - tauri-backend: - name: Tauri Backend + Bundle +jobs: + checks: + name: Checks and app bundle runs-on: macos-latest steps: - name: Checkout - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - name: Setup Node - uses: actions/setup-node@v7 + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7 with: - node-version: 22 + node-version-file: .node-version cache: npm + - name: Setup pinned npm + run: npm install --global npm@12.2.0 + - name: Setup Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@e2a55d2ffb04f378e9626c28d38b36d230d1e12f # rust 1.98.1 + with: + toolchain: 1.98.1 + components: rustfmt, clippy - name: Install dependencies run: npm ci - - name: Run smoke tests - run: DESKTOP_PET_STRICT_RUST=1 npm run test:smoke + - name: Run checks + run: make check - - name: Run canonical Tauri verification - run: DESKTOP_PET_STRICT_RUST=1 npm run verify:required:tauri + - name: Build macOS app bundle + run: npm run tauri -- build --bundles app diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a57d7c2..36bbce0 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -7,7 +7,7 @@ on: branches: [main] workflow_dispatch: schedule: - - cron: '37 8 * * 1' + - cron: "37 8 * * 1" permissions: contents: read @@ -25,12 +25,12 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - name: Initialize CodeQL - uses: github/codeql-action/init@v4 + uses: github/codeql-action/init@24c54180a607b1449ed407dd24f251e4e9147c8d # v4 with: languages: ${{ matrix.language }} - name: Perform CodeQL analysis - uses: github/codeql-action/analyze@v4 + uses: github/codeql-action/analyze@24c54180a607b1449ed407dd24f251e4e9147c8d # v4 diff --git a/.github/workflows/git-hygiene.yml b/.github/workflows/git-hygiene.yml index bca9f80..2656f37 100644 --- a/.github/workflows/git-hygiene.yml +++ b/.github/workflows/git-hygiene.yml @@ -12,17 +12,17 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: fetch-depth: 0 - - uses: wagoid/commitlint-github-action@b948419dd99f3fd78a6548d48f94e3df7f6bf3ed + - uses: wagoid/commitlint-github-action@b948419dd99f3fd78a6548d48f94e3df7f6bf3ed # v6 pr-title: runs-on: ubuntu-latest permissions: pull-requests: read steps: - - uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 + - uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -37,7 +37,7 @@ jobs: # guard accepts / and /, this copy accepted # neither, so a branch the local hook blessed failed here. One rule, one # place, pinned by the guard's own test suite. - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - run: bash scripts/git/guard-branch.sh secrets: @@ -45,9 +45,9 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: fetch-depth: 0 - - uses: gitleaks/gitleaks-action@e0c47f4f8be36e29cdc102c57e68cb5cbf0e8d1e + - uses: gitleaks/gitleaks-action@e0c47f4f8be36e29cdc102c57e68cb5cbf0e8d1e # v3 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/lockfile-rationale.yml b/.github/workflows/lockfile-rationale.yml index 18409c9..c6bc426 100644 --- a/.github/workflows/lockfile-rationale.yml +++ b/.github/workflows/lockfile-rationale.yml @@ -12,10 +12,10 @@ jobs: contents: read pull-requests: read steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 - - uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46 id: changed - - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 + - uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7 if: contains(steps.changed.outputs.all_changed_files, 'pnpm-lock.yaml') || contains(steps.changed.outputs.all_changed_files, 'package-lock.json') || contains(steps.changed.outputs.all_changed_files, 'yarn.lock') with: script: | diff --git a/.github/workflows/perf-enforced.yml b/.github/workflows/perf-enforced.yml index 9891c5e..7ce1a76 100644 --- a/.github/workflows/perf-enforced.yml +++ b/.github/workflows/perf-enforced.yml @@ -14,11 +14,14 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@v7 - - uses: actions/setup-node@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7 with: - node-version: 22 + node-version-file: .node-version cache: npm + + - name: Setup pinned npm + run: npm install --global npm@12.2.0 - run: npm ci - run: npm run build - run: npm run perf:bundle:gate @@ -32,11 +35,14 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@v7 - - uses: actions/setup-node@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7 with: - node-version: 22 + node-version-file: .node-version cache: npm + + - name: Setup pinned npm + run: npm install --global npm@12.2.0 - run: npm ci - run: npm run perf:build:gate @@ -46,59 +52,23 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - run: ASSET_MAX_BYTES=250000 bash scripts/perf/check-assets.sh - perf-memory: - if: ${{ vars.PERF_PROFILE == 'production' }} - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - uses: actions/checkout@v7 - - uses: actions/setup-node@v7 - with: - node-version: 22 - cache: npm - - run: npm ci - - run: MEMORY_MAX_DELTA_MB=5 npm run perf:memory - perf-lighthouse: if: ${{ vars.PERF_PROFILE == 'production' }} runs-on: ubuntu-latest permissions: contents: read steps: - - uses: actions/checkout@v7 - - uses: actions/setup-node@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7 with: - node-version: 22 + node-version-file: .node-version cache: npm + + - name: Setup pinned npm + run: npm install --global npm@12.2.0 - run: npm ci - run: npm run build - run: npm run perf:lhci:prod - - perf-api: - if: ${{ vars.PERF_PROFILE == 'production' && vars.PERF_BASE_URL != '' }} - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - uses: actions/checkout@v7 - - uses: grafana/setup-k6-action@v1 - - run: k6 run tests/perf/api.k6.js --summary-export=.perf-results/api-summary.json - env: - BASE_URL: ${{ vars.PERF_BASE_URL }} - API_P95_MS: "250" - API_P99_MS: "700" - - perf-db: - if: ${{ vars.PERF_PROFILE == 'production' && vars.PERF_DATABASE_URL != '' }} - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - uses: actions/checkout@v7 - - name: Install PostgreSQL client - run: sudo apt-get update && sudo apt-get install -y postgresql-client - - run: psql "${{ vars.PERF_DATABASE_URL }}" -f scripts/perf/db/check-pg-stat.sql diff --git a/.github/workflows/perf-foundation.yml b/.github/workflows/perf-foundation.yml index 01ab1e5..986d73b 100644 --- a/.github/workflows/perf-foundation.yml +++ b/.github/workflows/perf-foundation.yml @@ -11,11 +11,14 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@v7 - - uses: actions/setup-node@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7 with: - node-version: 22 + node-version-file: .node-version cache: npm + + - name: Setup pinned npm + run: npm install --global npm@12.2.0 - run: npm ci - run: npm run build - run: npm run perf:bundle @@ -25,11 +28,14 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@v7 - - uses: actions/setup-node@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7 with: - node-version: 22 + node-version-file: .node-version cache: npm + + - name: Setup pinned npm + run: npm install --global npm@12.2.0 - run: npm ci - run: npm run perf:build @@ -38,11 +44,14 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@v7 - - uses: actions/setup-node@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7 with: - node-version: 22 + node-version-file: .node-version cache: npm + + - name: Setup pinned npm + run: npm install --global npm@12.2.0 - run: npm ci - run: npm run build - run: npm run perf:lhci @@ -52,41 +61,5 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - run: bash scripts/perf/check-assets.sh - - perf-memory: - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - uses: actions/checkout@v7 - - uses: actions/setup-node@v7 - with: - node-version: 22 - cache: npm - - run: npm ci - - run: npm run perf:memory - - perf-api: - if: ${{ vars.PERF_BASE_URL != '' }} - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - uses: actions/checkout@v7 - - uses: grafana/setup-k6-action@v1 - - run: k6 run tests/perf/api.k6.js --summary-export=.perf-results/api-summary.json - env: - BASE_URL: ${{ vars.PERF_BASE_URL }} - - perf-db: - if: ${{ vars.PERF_DATABASE_URL != '' }} - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - uses: actions/checkout@v7 - - name: Install PostgreSQL client - run: sudo apt-get update && sudo apt-get install -y postgresql-client - - run: psql "${{ vars.PERF_DATABASE_URL }}" -f scripts/perf/db/check-pg-stat.sql diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a7b8c75..2db4270 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,16 +25,22 @@ jobs: APPLE_API_KEY_BASE64: ${{ secrets.APPLE_API_KEY_BASE64 }} steps: - name: Checkout - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - name: Setup Node - uses: actions/setup-node@v7 + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7 with: - node-version: 22 + node-version-file: .node-version cache: npm + - name: Setup pinned npm + run: npm install --global npm@12.2.0 + - name: Setup Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@e2a55d2ffb04f378e9626c28d38b36d230d1e12f # rust 1.98.1 + with: + toolchain: 1.98.1 + components: rustfmt, clippy - name: Install dependencies run: npm ci @@ -52,7 +58,7 @@ jobs: run: npm run release:updater:package - name: Upload release artifacts - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 with: name: desktop-pet-macos path: | @@ -66,7 +72,7 @@ jobs: - name: Publish GitHub Release (tag builds only) if: startsWith(github.ref, 'refs/tags/') - uses: softprops/action-gh-release@v3 + uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3 with: files: | src-tauri/target/release/bundle/dmg/*.dmg @@ -75,7 +81,7 @@ jobs: - name: Publish updater release assets (tag builds only) if: startsWith(github.ref, 'refs/tags/') && hashFiles('artifacts/release/updater-assets.tar.gz') != '' - uses: softprops/action-gh-release@v3 + uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3 with: files: | artifacts/release/updater-artifacts.txt diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index bf8c45c..204ed0c 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -17,16 +17,22 @@ jobs: DESKTOP_PET_SKIP_GITLEAKS: "1" steps: - name: Checkout - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - name: Setup Node - uses: actions/setup-node@v7 + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7 with: - node-version: 22 + node-version-file: .node-version cache: npm + - name: Setup pinned npm + run: npm install --global npm@12.2.0 + - name: Setup Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@e2a55d2ffb04f378e9626c28d38b36d230d1e12f # rust 1.98.1 + with: + toolchain: 1.98.1 + components: rustfmt, clippy - name: Install dependencies run: npm ci @@ -43,13 +49,13 @@ jobs: - name: Run strict secret scan if: env.DESKTOP_PET_SKIP_GITLEAKS != '1' - uses: gitleaks/gitleaks-action@v3 + uses: gitleaks/gitleaks-action@e0c47f4f8be36e29cdc102c57e68cb5cbf0e8d1e # v3 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload security artifacts if: always() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 with: name: security-scan-artifacts path: artifacts/security/* diff --git a/.gitignore b/.gitignore index 1dda7dc..daad5f6 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ src-tauri/target/ .perf-results/ .DS_Store *.dmg +.npm-cache/ +.local-cargo-home/ +.local-rustup/ diff --git a/.node-version b/.node-version new file mode 100644 index 0000000..de889f8 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +22.23.3 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..6c5f4fe --- /dev/null +++ b/.prettierignore @@ -0,0 +1,9 @@ +node_modules/ +dist/ +src-tauri/target/ +src-tauri/gen/ +target/ +artifacts/ +.perf-results/ +.perf-baselines/ +.npm-cache/ diff --git a/AGENTS.md b/AGENTS.md index a4eec2f..c12e8b2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,57 +1,36 @@ - +# Purpose -## Communication Contract +DesktopPet is a local desktop companion built with Tauri and React. Keep persistence explicit and protect user data during migrations and imports. -- Inherit global Codex communication and reporting rules from `/Users/d/.codex/AGENTS.override.md` and `/Users/d/.codex/policies/communication/BigPictureReportingV1.md`. -- Repo-specific instructions below add project constraints only; do not restate global voice or status-reporting rules here. - +# Layout -## Inherited Operating Rules +- `src/`: React interface, hooks, domain types, and frontend tests. +- `src-tauri/`: Tauri commands, Rust models, persistence, and backend tests. +- `scripts/`: build, performance budget, security, and release helpers. +- `docs/`: product contracts and release history. -- Inherit global git, review/fix, testing, docs, skill-use, and reporting gates from `/Users/d/.codex/AGENTS.md` and active session instructions. -- Use `.codex/verify.commands` and `.codex/scripts/run_verify_commands.sh` as this repo-local verification authority when present. -- Keep the project-specific portfolio constraints below as the source of truth for runtime, privacy, and release risks. +# Setup - -# Portfolio Context +- Node.js 22.23.3 and npm 12.2.0 (see `package.json`). +- Rust 1.98.1 with `rustfmt` and `clippy` (see `src-tauri/rust-toolchain.toml`). +- Run `npm ci` to install frontend dependencies. +- Native desktop builds also need the Tauri prerequisites for the host operating system. -## What This Project Is +# Checks -DesktopPet is a Tauri desktop companion that turns focus sessions into a pet progression loop. A transparent always-on-top pet overlay, controls panel, Pomodoro presets, XP/coins, quests, shop unlocks, and focus guardrails work together as a local desktop productivity game. +- `make check` runs formatting, TypeScript, Vitest, Rust formatting, Clippy, Rust tests, and the frontend build. +- `npm run security:scan` runs the separate network-dependent security checks. +- Preserve failures and report the command and output; do not weaken checks to make them pass. -## Current State +# Boundaries -The repo is active desktop product work. Existing local changes are PR-template metadata, so context recovery should stay documentation-only. +- Do not add automatic focus interventions from configured rules without genuine observations and an explicit product decision. +- Keep local persistence as the source of truth; do not introduce a remote API or database without approval. +- Preserve unrelated work and user data. Do not publish, deploy, sign, notarize, or release as part of routine changes. +- Do not access the user's Downloads folder. -## Stack +# Delivery -| Layer | Technology | -|-------|------------| -| Shell | Tauri 2 (Rust backend) | -| Language | TypeScript + React | -| Bundler | Vite | -| Testing | Vitest | -| Styling | Tailwind CSS | - -## How To Run - -```bash -# Frontend development -npm run dev - -# Frontend production build -npm run build -``` - -## Known Risks - -- Focus guardrails affect user workflow; avoid blocking behavior without clear controls and tests. -- Pet, quest, shop, and focus-session state crosses TypeScript stores and the Rust layer, so keep persistence boundaries explicit. -- Transparent always-on-top windows can be fragile on desktop platforms; verify overlay behavior after UI changes. -- Keep PR-template drift separate from product changes. - -## Next Recommended Move - -Resolve the PR-template drift separately, then verify overlay, Pomodoro, quest/shop, and focus-guardrail flows before shipping behavior changes. - - +- Keep changes small and reviewable, with focused tests for changed behavior. +- Use conventional commit subjects: `feat`, `fix`, `refactor`, `perf`, `docs`, `test`, `build`, `ci`, `chore`, or `revert`. +- Verify the final diff and explain checks and any remaining limits. diff --git a/CHANGELOG.md b/CHANGELOG.md index 62c6624..9fdd304 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.0.0] - 2026-03-22 ### Added + - Initial Desktop Pet / Pomodoro Buddy - Streamlined UI with penguin icon and minimal floating pet - Deepen pet interactions, customization, and guardrails @@ -29,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Pre-signing handoff documentation ### Fixed + - Honor DesktopPEt gitleaks skip flag - Stabilize overlay recovery and app flows - Increase pet window size to fit all evolution stages @@ -38,6 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Normalize import settings and preserve loadout FIFO ### Changed + - Harden verification and packaging for release - Complete audit hardening and ops tooling - Cover backup and diagnostics settings flows diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..43c994c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 4c38b83..22be14d 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -13,19 +13,19 @@ identity and orientation. Examples of behavior that contributes to a positive environment: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members Examples of unacceptable behavior: -* The use of sexualized language or imagery, and sexual attention or advances of any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting +- The use of sexualized language or imagery, and sexual attention or advances of any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information without explicit permission +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement diff --git a/Makefile b/Makefile index 49ecf1f..cd865d6 100644 --- a/Makefile +++ b/Makefile @@ -1,19 +1,35 @@ -.PHONY: dev build test lint clean install +.PHONY: dev build test lint clean install check install: - pnpm install + npm ci dev: - pnpm dev + npm run dev build: - pnpm build + npm run build test: - pnpm test + npm test lint: - pnpm lint + npm run lint clean: rm -rf node_modules dist .next .turbo + +check: + @missing=0; for tool in node npm cargo; do \ + if ! command -v $$tool >/dev/null 2>&1; then echo "Missing $$tool; install Node.js 22.23.3 and the pinned Rust toolchain first."; missing=1; fi; \ + done; test $$missing -eq 0 || exit 1 + npm run lint + npm run typecheck + npm test + npm run test:pack-qa + cd src-tauri && cargo fmt --all -- --check + cd src-tauri && cargo clippy --locked --all-targets -- -D warnings + cd src-tauri && cargo test --locked + npm run build + npm run check:performance-budget + npm run perf:bundle:gate + npm run perf:assets diff --git a/README.md b/README.md index c0ad607..4e06fb9 100644 --- a/README.md +++ b/README.md @@ -12,15 +12,16 @@ DesktopPet is a Tauri-powered desktop companion that floats above your windows a - **Pomodoro integration** — 15/5, 25/5, and 50/10 presets with XP and coin rewards on completion - **Pet progression** — evolution stages, care stats, personality state, and 20+ unlockable achievements - **Shop + quests** — accessory catalog, rolling events, and active quests with completion rewards -- **Focus guardrails** — allowlist/blocklist host matching with timer messages, pause interventions, and event history +- **Focus guardrails** — explicit evaluation of supplied host observations against allowlists and blocklists - **Customization** — skins, scenes, themes, saved loadouts, and a photo booth for shareable pet cards ## Quick Start ### Prerequisites -- Node.js 22.13+ on the 22.x line and npm (the CI runtime; required by the locked Vite/jsdom toolchain). -- For native desktop work: Rust `stable`, Cargo, and the [Tauri prerequisites for your OS](https://v2.tauri.app/start/prerequisites/). `Cargo.toml` declares Rust 1.77.2, but the locked dependency graph may require a newer toolchain. +- Node.js 22.23.3 and npm 12.2.0. +- Rust 1.98.1 with Cargo, `rustfmt`, and `clippy` for native checks. +- For native desktop work, install the [Tauri prerequisites for your OS](https://v2.tauri.app/start/prerequisites/). - Use the Tauri CLI pinned in `package.json` through `npm run tauri`; no global CLI installation is needed. ### Installation @@ -46,17 +47,31 @@ npm run tauri -- dev npm run build ``` -See the [execution contract](docs/execution-contract.md) for focused tests, format/typecheck checks, native builds, strict verification and conditional browser/desktop checks. +Run `make check` for the repository checks. Run `npm run security:scan` separately for network-dependent security scans. -## Tech Stack +## Status -| Layer | Technology | -| -------- | ---------------------- | -| Shell | Tauri 2 (Rust backend) | -| Language | TypeScript + React | -| Bundler | Vite | -| Testing | Vitest | -| Styling | Tailwind CSS | +### Stack + +| Layer | Technology | +| ------- | --------------------------- | +| Shell | Tauri 2 with a Rust backend | +| UI | React 19 and TypeScript 7 | +| Bundler | Vite 8 | +| Tests | Vitest | +| Styling | Tailwind CSS | + +### Known risks + +- Focus guardrails evaluate only hosts explicitly provided by the application. The desktop app does not detect activity in other apps or browsers. +- Transparent, always-on-top windows can vary across desktop environments and need platform-specific manual verification. +- Backup imports replace local application state after schema validation; keep a separate backup before importing important data. + +### Next steps + +- Run `make check` before proposing changes. +- Verify overlay behavior and focus-session flows on the target desktop platform before a release. +- CI builds the macOS `.app` bundle; DMG creation, signing, and notarization are release-only work. ## Architecture diff --git a/SECURITY.md b/SECURITY.md index f51e103..3590edf 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -7,6 +7,7 @@ Please **do not** open a public GitHub issue for security vulnerabilities. Open a [GitHub Security Advisory](../../security/advisories/new) or email the maintainer directly. Include: + - Description of the vulnerability - Steps to reproduce - Potential impact diff --git a/commitlint.config.mjs b/commitlint.config.mjs index 6509d3b..772f426 100644 --- a/commitlint.config.mjs +++ b/commitlint.config.mjs @@ -2,7 +2,22 @@ export default { extends: ["@commitlint/config-conventional"], rules: { - "type-enum": [2, "always", ["feat", "fix", "refactor", "perf", "docs", "test", "build", "ci", "chore", "revert"]], + "type-enum": [ + 2, + "always", + [ + "feat", + "fix", + "refactor", + "perf", + "docs", + "test", + "build", + "ci", + "chore", + "revert", + ], + ], "header-max-length": [2, "always", 72], "subject-empty": [2, "never"], "subject-full-stop": [2, "never", "."], diff --git a/docs/PORTFOLIO-DISPOSITION.md b/docs/PORTFOLIO-DISPOSITION.md index b7ed040..6973c23 100644 --- a/docs/PORTFOLIO-DISPOSITION.md +++ b/docs/PORTFOLIO-DISPOSITION.md @@ -26,6 +26,7 @@ Developer ID signing + notarization credentials**, which is operator-only work. For the full detail, see (in this order): + - `docs/release-candidate-status.md` - `docs/macos-signing-handoff.md` - `docs/release-runbook.md` @@ -37,11 +38,11 @@ system what to do given those. ## Portfolio operating system instructions -| Aspect | Posture | -|---|---| -| Portfolio status | `Release Frozen` (not `Cold Storage`, not `Active`) | -| Review cadence | Suspend overdue counting | -| Next review trigger | When Apple signing credentials become available, or when the operator explicitly decides to ship unsigned (not currently planned) | +| Aspect | Posture | +| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Portfolio status | `Release Frozen` (not `Cold Storage`, not `Active`) | +| Review cadence | Suspend overdue counting | +| Next review trigger | When Apple signing credentials become available, or when the operator explicitly decides to ship unsigned (not currently planned) | | Resurface conditions | (a) signing credentials configured in CI, or (b) operator decides to abandon ship and switch to `Cold Storage` with disposition `RC reached, ship abandoned` | --- @@ -60,7 +61,7 @@ system what to do given those. The distinction matters because portfolio reviews should treat these differently. Active projects get attention. Cold projects get -ignored. Frozen projects get *neither* — they sit until the unblocking +ignored. Frozen projects get _neither_ — they sit until the unblocking condition flips, then move quickly. --- @@ -89,7 +90,7 @@ When portfolio operating system flips this row to `Active`: 1. Delete the abandoned `codex/*` WIP branches that accumulated during the freeze — they don't reflect the shipping artifact. 2. Re-verify on current toolchain: `npm install && npm run - verify:required && npm run verify:required:tauri`. +verify:required && npm run verify:required:tauri`. 3. Re-run the packaged-app smoke checks listed in `release-candidate-status.md`. 4. Only then proceed to signing — do not assume the 2026-03-14 build @@ -99,11 +100,11 @@ When portfolio operating system flips this row to `Active`: ## Last known reference -| Field | Value | -|---|---| -| Last commit on `main` | `d7fcfd3` docs(release): add pre-signing handoff | -| Date | 2026-03-14 | -| Build verification status | green | -| Smoke test status | green | -| Blocker | Apple signing + notarization (operator-only) | -| Local WIP branches | several `codex/*` branches, not reflected in shipping artifact, safe to delete on reactivation | +| Field | Value | +| ------------------------- | ---------------------------------------------------------------------------------------------- | +| Last commit on `main` | `d7fcfd3` docs(release): add pre-signing handoff | +| Date | 2026-03-14 | +| Build verification status | green | +| Smoke test status | green | +| Blocker | Apple signing + notarization (operator-only) | +| Local WIP branches | several `codex/*` branches, not reflected in shipping artifact, safe to delete on reactivation | diff --git a/docs/release-candidate-status.md b/docs/release-candidate-status.md index 4d3b4e3..5aa0e27 100644 --- a/docs/release-candidate-status.md +++ b/docs/release-candidate-status.md @@ -1,63 +1,5 @@ -# Unsigned Release Candidate Status +# Historical release candidate notes -Last updated: 2026-03-14 +This document records a release-candidate assessment from March 2026. Its build, smoke-test, signing, and distribution statements describe that historical assessment only; they are not evidence of current readiness. -## Current Decision - -DesktopPEt is at an unsigned macOS release-candidate state. - -Go for pre-signing handoff: - -- Yes - -Go for final public distribution: - -- Not yet - -## What Is Proven - -- Canonical verification passes: - - `npm run verify:required` - - `npm run verify:required:tauri` -- Release artifact validation passes: - - `npm run release:artifacts:validate` - - `npm run release:updater:package` (clean skip because updater assets are not enabled yet) -- Unsigned macOS artifacts build successfully: - - `src-tauri/target/release/bundle/macos/Desktop Pet.app` - - `src-tauri/target/release/bundle/dmg/Desktop Pet_1.0.0_aarch64.dmg` -- Live smoke checks passed in both `tauri dev` and the packaged `.app`: - - pet and panel windows launch - - timer preset changes apply - - timer start, pause, resume, and reset work - - backup export works - - reset returns the app to defaults - - backup import restores prior timer state - - pet window recovery keeps the overlay reachable - -## Evidence - -- Release manifest: - - `artifacts/release/tauri-artifacts.txt` -- Release checksums: - - `artifacts/release/tauri-artifacts-sha256.txt` -- Pack QA report: - - `artifacts/pack-qa-report.md` -- Performance budget report: - - `artifacts/performance-budget-report.md` - -## Remaining Blocker - -The only material blocker for final distribution is Apple signing and notarization setup. - -Missing release inputs are documented in: - -- `docs/macos-signing-handoff.md` - -## Non-Blocking Notes - -- Updater packaging currently skips because no updater metadata or signatures are being produced. -- Release-hardening and product-fix work is recorded in commits `83c1e91` and `3a5f4f6`. - -## Recommended Next Action - -Use `docs/macos-signing-handoff.md` to provision Apple credentials, run signing preflight, build a signed/notarized bundle, and rerun artifact validation. +The old verification details and artifact claims have been removed because their evidence is not maintained with this document. For current checks, run `make check`. macOS signing and notarization remain release-only work and are not automated by the repository. diff --git a/package-lock.json b/package-lock.json index 67f1687..b8489e2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,6 @@ "dependencies": { "@tauri-apps/api": "2.12.1", "@tauri-apps/plugin-clipboard-manager": "^2.4.1", - "@tauri-apps/plugin-store": "^2.5.0", "react": "^19.3.0", "react-dom": "^19.3.0" }, @@ -36,6 +35,10 @@ "typescript": "^7.0.2", "vite": "^8.2.2", "vitest": "^5.0.3" + }, + "engines": { + "node": "22.23.3", + "npm": "12.2.0" } }, "node_modules/@adobe/css-tools": { @@ -2091,8 +2094,8 @@ "integrity": "sha512-DeyFHa3wynpyoqTDikDEDGTJIq4LQ5USfolQGRmGIWT6JMADyxZBTDa5cAdT3tDg73rUXufPaCwN7aXBos4OnQ==", "license": "Apache-2.0 OR MIT", "funding": { - "url": "https://opencollective.com/tauri", - "type": "opencollective" + "type": "opencollective", + "url": "https://opencollective.com/tauri" } }, "node_modules/@tauri-apps/cli": { @@ -2336,15 +2339,6 @@ "@tauri-apps/api": "^2.12.0" } }, - "node_modules/@tauri-apps/plugin-store": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-store/-/plugin-store-2.5.0.tgz", - "integrity": "sha512-+ykjiQwMJCSk/U2enHA8peKBWgDKgrP7JfZnGwQpqzwA0nVtKTc0LCyxWr2whOrcQoQqtUdr9NVdDZpfKpT1Xw==", - "license": "MIT OR Apache-2.0", - "dependencies": { - "@tauri-apps/api": "^2.12.0" - } - }, "node_modules/@testing-library/dom": { "version": "10.4.1", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", diff --git a/package.json b/package.json index 681165b..b2332ef 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,11 @@ "name": "desktoppet", "version": "1.0.0", "private": true, + "packageManager": "npm@12.2.0", + "engines": { + "node": "22.23.3", + "npm": "12.2.0" + }, "scripts": { "dev": "node ./node_modules/vite/bin/vite.js", "dev:lean": "bash ./scripts/lean-dev.sh", @@ -14,8 +19,6 @@ "test:pack-qa": "node ./scripts/pack_qa.mjs", "test": "node ./node_modules/vitest/vitest.mjs run", "test:watch": "node ./node_modules/vitest/vitest.mjs", - "test:ui": "node ./node_modules/vitest/vitest.mjs --ui", - "test:coverage": "node ./node_modules/vitest/vitest.mjs run --coverage", "test:rust": "./scripts/tauri-rust-test.sh", "test:rust:release": "./scripts/tauri-rust-test.sh --release", "test:all": "npm test && npm run test:rust", @@ -28,7 +31,7 @@ "release:updater:package": "bash ./scripts/release/package-updater-assets.sh", "security:scan": "bash ./scripts/security/run-security-scans.sh", "test:tauri-preflight": "./scripts/tauri-preflight.sh", - "verify:required:frontend": "npm run typecheck && npm test && npm run test:smoke:frontend && npm run test:pack-qa && npm run build && npm run check:performance-budget && npm run perf:build:gate && npm run perf:bundle:gate && npm run perf:assets && npm run perf:memory && npm run perf:summary && npm run security:scan", + "verify:required:frontend": "npm run typecheck && npm test && npm run build && npm run check:performance-budget && npm run perf:bundle:gate && npm run perf:assets", "verify:required:tauri": "npm run test:tauri-preflight && npm run test:rust && npm run tauri:build:checked", "verify:required:tauri:strict:temp": "bash ./scripts/verify-tauri-strict-temp.sh", "verify:required": "npm run verify:required:frontend && npm run verify:required:tauri", @@ -52,7 +55,6 @@ "perf:bundle:gate": "npm run perf:bundle && if [ \"${DESKTOP_PET_STRICT_PERF:-0}\" = \"1\" ]; then node scripts/perf/compare-metric.mjs .perf-baselines/bundle.json .perf-results/bundle.json totalBytes 0.08; else echo \"Skipping strict perf regression compare (set DESKTOP_PET_STRICT_PERF=1 to enforce).\"; fi", "perf:baseline:update": "bash ./scripts/perf/update-baselines.sh", "perf:assets": "bash scripts/perf/check-assets.sh", - "perf:memory": "node --expose-gc scripts/perf/memory-smoke.mjs", "perf:lhci": "bash ./scripts/perf/lhci.sh", "perf:lhci:prod": "LHCI_PROFILE=production bash ./scripts/perf/lhci.sh", "perf:summary": "node scripts/perf/summarize.mjs", @@ -61,7 +63,6 @@ "dependencies": { "@tauri-apps/api": "2.12.1", "@tauri-apps/plugin-clipboard-manager": "^2.4.1", - "@tauri-apps/plugin-store": "^2.5.0", "react": "^19.3.0", "react-dom": "^19.3.0" }, diff --git a/pet.html b/pet.html index 6565853..e2ce21a 100644 --- a/pet.html +++ b/pet.html @@ -5,7 +5,9 @@ Desktop Pet