diff --git a/.github/HOOKS.md b/.github/HOOKS.md index c5db72ce..fe123821 100644 --- a/.github/HOOKS.md +++ b/.github/HOOKS.md @@ -1,257 +1,64 @@ # Git Hooks -## Pre-Commit Hook: CodeScene Check +This repo uses Husky hooks from `.husky/`. Those files are the source of truth. -Il repository ha un pre-commit hook che verifica la qualità del codice prima di ogni commit. +## Installation -## Post-Commit Hook: Auto-Implement Design Changes +`pnpm install` runs the `prepare` script and installs the hooks into `.git/hooks`. -Quando committi modifiche a `ui-design.pen`, il post-commit hook: -1. Analizza automaticamente le modifiche (colori, typography, spacing, layout) -2. Spawna Claude Code in background per implementare le modifiche -3. Ti notifica quando l'implementazione è completa - ---- - -## Pre-Commit Hook Details - -### Cosa Fa - -1. **Analizza file staged** — controlla solo TypeScript/Rust modificati -2. **Confronta con base branch** — `origin/main` per branch, `HEAD~1` per main -3. **Avvisa per file grandi** — >500 linee modificate -4. **Suggerisce review** — con Claude Code + CodeScene MCP per analisi dettagliata - -### Bypass Hook - -Se sai cosa stai facendo: +If you need to reinstall them manually: ```bash -# Skip hook per questo commit -git commit --no-verify -m "your message" - -# O includi nel commit message -git commit -m "your message [skip codescene]" +pnpm exec husky ``` -### Installazione (già fatto per questa repo) +The hooks expect `node` and `pnpm` to be available. If they are installed via `nvm`, the hooks will try to load `~/.nvm/nvm.sh` automatically. -L'hook è già installato in `.git/hooks/pre-commit`. +## Policy -Se cloni la repo altrove, copia l'hook: -```bash -cp .github/hooks/pre-commit .git/hooks/pre-commit -chmod +x .git/hooks/pre-commit -``` +- Commit on `main` only. +- Push from `main` to `origin/main` only. +- Never use `--no-verify`. +- `.codescene-thresholds` is a ratchet. It can only move up. -### Esempio Output +## Pre-commit -#### ✅ Commit Normale -``` -🔍 Running CodeScene Code Health check... - Comparing against: origin/main - Analyzing code changes... -✅ CodeScene check passed - +42 -18 lines +`.husky/pre-commit` blocks commits unless all of the following are true: - 💡 For detailed code health analysis, run: - claude 'Check code health of this commit with CodeScene MCP' -``` +- `HEAD` is attached to `main` +- staged TypeScript files pass `pnpm lint --quiet` +- TypeScript passes `npx tsc --noEmit` +- frontend tests pass via `pnpm test --run --silent` +- current CodeScene Hotspot and Average health are both at or above `.codescene-thresholds` -#### ⚠️ File Grandi -``` -🔍 Running CodeScene Code Health check... - Comparing against: origin/main - Analyzing code changes... -⚠️ Large file changes detected (>500 lines): - - src/components/Editor.tsx - - src-tauri/src/vault.rs +If `CODESCENE_PAT` or `CODESCENE_PROJECT_ID` is missing, the CodeScene portion is skipped, but the rest of the hook still runs. - Consider: - - Breaking into smaller commits - - Reviewing with Claude Code + CodeScene MCP - - Running: claude 'Review code health of staged changes' +## Pre-push - Continue anyway? (y/N) -``` +`.husky/pre-push` blocks pushes unless all of the following are true: -### CodeScene MCP Integration +- the current branch is `main` +- every pushed branch ref is `refs/heads/main -> refs/heads/main` +- TypeScript and the Vite build pass +- frontend coverage passes +- Rust lint and Rust coverage pass when `src-tauri/` changed +- Playwright smoke tests pass when `tests/smoke/*.spec.ts` exists +- current CodeScene Hotspot and Average health are both at or above `.codescene-thresholds` -Per analisi dettagliata del code health, usa Claude Code: +If the remote CodeScene scores are better than the current thresholds, the hook updates `.codescene-thresholds`, stages it, and stops the push. Commit that file normally, then push again. The hook does not auto-commit or bypass itself. + +## Legacy Files + +The legacy `pre-commit` and `post-commit` files under `.github/hooks/` are archival only. Do not copy them into `.git/hooks`; use Husky and `.husky/` instead. `install-hooks.sh` remains as a reinstall helper that runs Husky. + +## Troubleshooting + +If a hook cannot find `node` or `pnpm`: ```bash -# Analizza staged changes -claude 'Check code health of staged changes with CodeScene MCP' - -# Analizza file specifico -claude 'What is the code health score of src/components/Editor.tsx?' - -# Pre-commit safeguard -claude 'Run pre_commit_code_health_safeguard on staged changes' +export NVM_DIR="$HOME/.nvm" +. "$NVM_DIR/nvm.sh" +nvm use node ``` -### Troubleshooting - -**Hook non si attiva:** -- Verifica che `.git/hooks/pre-commit` esista ed sia eseguibile -- `ls -la .git/hooks/pre-commit` — dovrebbe mostrare `-rwxr-xr-x` - -**Vuoi disabilitare temporaneamente:** -```bash -mv .git/hooks/pre-commit .git/hooks/pre-commit.disabled -``` - -**Vuoi riabilitare:** -```bash -mv .git/hooks/pre-commit.disabled .git/hooks/pre-commit -``` - -### Future Improvements - -Possibili miglioramenti: -- [ ] Integrazione diretta API CodeScene per score numerico -- [ ] Fail automatico se code health < soglia -- [ ] Cache dei risultati per evitare re-analisi -- [ ] Hook pre-push più pesante per analisi completa - ---- - -## Post-Commit Hook: Auto-Implement Design Changes - -### Cosa Fa - -Quando committi modifiche a `ui-design.pen`, il hook: - -1. **Analizza il diff** — usa `scripts/design-diff-analyzer.js` -2. **Identifica modifiche significative:** - - 🎨 Colori (fill, backgroundColor) - - 📝 Typography (fontSize, fontFamily) - - 📏 Spacing (padding, margin, gap) - - 🔲 Layout (nuovi componenti, riorganizzazioni) -3. **Spawna Claude Code** — in background via `openclaw sessions spawn` -4. **Auto-notifica** — quando l'implementazione è completa - -### Cosa Implementa - -| Tipo Modifica | Azione | -|--------------|--------| -| Colori | Aggiorna `src/theme.json` o CSS variables | -| Typography | Aggiorna `src/theme.json` typography | -| Spacing | Aggiorna `src/theme.json` spacing | -| Layout | Modifica/crea componenti React | -| Testi mockup | Nessuna azione (solo design) | - -### Esempio Output - -``` -🎨 Design file changed - analyzing... - -📋 Implementation tasks: - -1. [HIGH] Update color palette - - fill: $--muted-foreground → #666666 - - backgroundColor: #FFFFFF → #F5F5F5 - -Update src/theme.json or CSS variables to match the design. - -2. [MEDIUM] Update typography - - fontSize: 14px → 16px - -Update src/theme.json typography settings. - -🚀 Spawning Claude Code to implement changes... - -✅ Claude Code spawned - you'll be notified when implementation is complete -``` - -### Workflow Completo - -``` -You Post-Commit Hook Claude Code Brian (AI) - │ │ │ │ - ├─ Modify ui-design.pen │ │ │ - ├─ git add ui-design.pen │ │ │ - ├─ git commit │ │ │ - │ │ │ │ - │ ├─ Analyze diff │ │ - │ ├─ Generate tasks │ │ - │ ├─ Spawn Claude Code ────────> │ - │ │ │ │ - │ │ ├─ Implement changes │ - │ │ ├─ Test visually │ - │ │ ├─ Run tests │ - │ │ ├─ Commit │ - │ │ ├─ openclaw system event ────> - │ │ │ │ - │ │ │ ├─ Notify Telegram - │ <─────────────────────────────────────────────────────────────────────────────┘ - │ "✅ Design changes implemented and tested" -``` - -### Design Diff Analyzer - -Lo script `scripts/design-diff-analyzer.js` rileva: - -- **Color changes** — `"fill": "#OLD" → "#NEW"` -- **Font changes** — `"fontSize": 14 → 16` -- **Spacing** — `"padding": 8 → 12` -- **Content** — testi mockup (no implementation) - -Uso: -```bash -# Analizza ultimo commit -node scripts/design-diff-analyzer.js - -# Output JSON per automation -node scripts/design-diff-analyzer.js --json -``` - -### Disabilitare Temporaneamente - -Se vuoi committare il design senza auto-implementazione: - -```bash -# Disabilita hook -mv .git/hooks/post-commit .git/hooks/post-commit.disabled - -# Commit -git commit -m "design: update mockup" - -# Riabilita hook -mv .git/hooks/post-commit.disabled .git/hooks/post-commit -``` - -### Monitorare Claude Code - -Mentre Claude Code lavora in background: - -```bash -# Lista sub-agent attivi -openclaw sessions list --kinds isolated - -# Vedi log di un sub-agent -openclaw sessions history --session-key - -# Ferma sub-agent (se necessario) -openclaw subagents kill --target design-auto-implement -``` - -### Troubleshooting - -**Hook non parte:** -- Verifica che `ui-design.pen` sia effettivamente cambiato: `git diff HEAD~1 ui-design.pen` -- Verifica che lo script analyzer esista: `ls -la scripts/design-diff-analyzer.js` - -**Nessuna notifica:** -- Claude Code potrebbe essere ancora in esecuzione — controlla `openclaw sessions list` -- Verifica che il prompt includa `openclaw system event` al termine - -**Modifiche non implementate:** -- Controlla i log di Claude Code: `openclaw sessions history --session-key ` -- Il sub-agent viene auto-eliminato dopo completion (cleanup=delete) - -### Limitazioni - -- **Modifiche complesse** — layout completamente nuovi potrebbero richiedere intervento manuale -- **Timeout** — 10 minuti max (configurabile in hook) -- **Solo modifiche recenti** — analizza solo HEAD vs HEAD~1 +Then retry the commit or push. diff --git a/.github/hooks/install-hooks.sh b/.github/hooks/install-hooks.sh index 5c12ccd7..5b952c3c 100755 --- a/.github/hooks/install-hooks.sh +++ b/.github/hooks/install-hooks.sh @@ -1,25 +1,26 @@ #!/bin/bash -# Install git hooks for laputa-app +set -e -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -HOOKS_DIR="$(git rev-parse --git-dir)/hooks" +if ! command -v pnpm >/dev/null 2>&1 || ! command -v node >/dev/null 2>&1; then + export NVM_DIR="${NVM_DIR:-$HOME/.nvm}" + if [ -s "$NVM_DIR/nvm.sh" ]; then + # shellcheck disable=SC1090 + . "$NVM_DIR/nvm.sh" --no-use + nvm use --silent node >/dev/null 2>&1 || true + fi +fi -echo "Installing git hooks..." - -# Copy pre-commit hook -cp "$SCRIPT_DIR/pre-commit" "$HOOKS_DIR/pre-commit" -chmod +x "$HOOKS_DIR/pre-commit" -echo "✅ Installed pre-commit hook" - -# Copy post-commit hook -cp "$SCRIPT_DIR/post-commit" "$HOOKS_DIR/post-commit" -chmod +x "$HOOKS_DIR/post-commit" -echo "✅ Installed post-commit hook" +if ! command -v pnpm >/dev/null 2>&1 || ! command -v node >/dev/null 2>&1; then + echo "❌ node and pnpm must be available to install Husky hooks" + exit 1 +fi +echo "Installing Husky hooks from .husky/ ..." +pnpm exec husky +echo "✅ Husky hooks installed" echo "" -echo "Hooks installed:" -echo " - pre-commit: CodeScene code health check" -echo " - post-commit: Auto-implement design changes via Claude Code" +echo "Source of truth:" +echo " - .husky/pre-commit" +echo " - .husky/pre-push" echo "" -echo "To bypass pre-commit, use: git commit --no-verify" -echo "Or include [skip codescene] in your commit message" +echo "Never use --no-verify in this repo." diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5bb85fe4..45c6404f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,8 +2,6 @@ name: CI on: push: - branches: [main, experiment/*] - pull_request: branches: [main] jobs: @@ -82,16 +80,14 @@ jobs: # ── 3. Code Health (CodeScene — Hotspot + Average Code Health gates) ── # Enforces minimum floors on BOTH hotspot and average code health. - # Hotspot: weighted avg of most-edited files (9.6 current | target 9.8) - # Average: project-wide avg across all files (9.37 current | target 9.5) - # Both gates must pass — average catches regressions in non-hotspot files. - - name: Code Health gates (Hotspot ≥9.5 + Average ≥9.0) + # Thresholds come from .codescene-thresholds so CI and local hooks match. + - name: Code Health gates env: CODESCENE_PAT: ${{ secrets.CODESCENE_PAT }} CODESCENE_PROJECT_ID: ${{ secrets.CODESCENE_PROJECT_ID }} run: | - HOTSPOT_THRESHOLD=9.5 - AVERAGE_THRESHOLD=9.33 + HOTSPOT_THRESHOLD=$(grep '^HOTSPOT_THRESHOLD=' .codescene-thresholds | cut -d= -f2) + AVERAGE_THRESHOLD=$(grep '^AVERAGE_THRESHOLD=' .codescene-thresholds | cut -d= -f2) API_RESPONSE=$(curl -sf \ -H "Authorization: Bearer $CODESCENE_PAT" \ -H "Accept: application/json" \ diff --git a/.husky/pre-commit b/.husky/pre-commit index dd46e67e..57de9d25 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,6 +1,43 @@ #!/bin/sh -# Pre-commit: same checks as CI. Fix here, not in CI. +# Pre-commit: fast local gate before commit. Full suite runs in pre-push/CI. set -e + +ensure_node_tooling() { + if command -v node >/dev/null 2>&1 && command -v pnpm >/dev/null 2>&1; then + return 0 + fi + + NVM_DIR="${NVM_DIR:-$HOME/.nvm}" + if [ -s "$NVM_DIR/nvm.sh" ]; then + # shellcheck disable=SC1090 + . "$NVM_DIR/nvm.sh" --no-use + nvm use --silent node >/dev/null 2>&1 || true + fi + + if ! command -v node >/dev/null 2>&1 || ! command -v pnpm >/dev/null 2>&1; then + echo "❌ node and pnpm must be available before committing" + echo " Install them or make sure your nvm setup is available to git hooks." + exit 1 + fi +} + +require_main_branch() { + if ! git symbolic-ref -q HEAD >/dev/null 2>&1; then + echo "❌ Commits must happen on main. Detached HEAD is not allowed." + exit 1 + fi + + CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) + if [ "$CURRENT_BRANCH" != "main" ]; then + echo "❌ Commits must happen on main. Current branch: $CURRENT_BRANCH" + echo " Merge or cherry-pick your work onto main, then commit there." + exit 1 + fi +} + +require_main_branch +ensure_node_tooling + echo "🔍 Pre-commit checks..." # Lint + types (only if TS files staged) @@ -19,7 +56,9 @@ echo "✅ Pre-commit passed" # ── CodeScene Code Health gate ──────────────────────────────────────────── # Blocks commit if scores drop below thresholds in .codescene-thresholds. -# Thresholds are a ratchet — only go up, auto-updated after each successful push. +# Thresholds are a ratchet — only go up. +# When remote scores improve, pre-push updates .codescene-thresholds and stops +# so the new floor is committed with normal verified hooks. # Note: remote scores lag behind local changes (update after push + re-analysis). # If check fails: extract hooks, split components, reduce complexity. # Never use eslint-disable, #[allow(...)], or `as any`. diff --git a/.husky/pre-push b/.husky/pre-push index 8dc4e7c9..33afbb99 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -28,6 +28,64 @@ # ───────────────────────────────────────────────────────────────────────── set -e +ensure_node_tooling() { + if command -v node >/dev/null 2>&1 && command -v pnpm >/dev/null 2>&1; then + return 0 + fi + + NVM_DIR="${NVM_DIR:-$HOME/.nvm}" + if [ -s "$NVM_DIR/nvm.sh" ]; then + # shellcheck disable=SC1090 + . "$NVM_DIR/nvm.sh" --no-use + nvm use --silent node >/dev/null 2>&1 || true + fi + + if ! command -v node >/dev/null 2>&1 || ! command -v pnpm >/dev/null 2>&1; then + echo "❌ node and pnpm must be available before pushing" + echo " Install them or make sure your nvm setup is available to git hooks." + exit 1 + fi +} + +require_main_push() { + if ! git symbolic-ref -q HEAD >/dev/null 2>&1; then + echo "❌ Pushes must happen from main. Detached HEAD is not allowed." + exit 1 + fi + + CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) + if [ "$CURRENT_BRANCH" != "main" ]; then + echo "❌ Pushes must happen from main. Current branch: $CURRENT_BRANCH" + exit 1 + fi + + while IFS=' ' read -r LOCAL_REF LOCAL_SHA REMOTE_REF REMOTE_SHA; do + [ -z "$LOCAL_REF" ] && continue + + case "$LOCAL_REF:$REMOTE_REF" in + refs/heads/main:refs/heads/main) + ;; + refs/tags/*:refs/tags/*) + ;; + *) + echo "❌ Pushes must be main -> main only." + echo " Attempted: ${LOCAL_REF:-} -> ${REMOTE_REF:-}" + exit 1 + ;; + esac + done </dev/null | head -1) if [ -n "$SMOKE_FILES" ]; then echo "🎭 [4/5] Playwright smoke tests..." - SMOKE_OUTPUT=$(pnpm playwright:smoke 2>&1) || true + set +e + SMOKE_OUTPUT=$(pnpm playwright:smoke 2>&1) + SMOKE_STATUS=$? + set -e echo "$SMOKE_OUTPUT" | tail -20 - # Fail only on real failures (not flaky). Flaky = passed on retry. - if echo "$SMOKE_OUTPUT" | grep -qE '^\s+\d+ failed' && ! echo "$SMOKE_OUTPUT" | grep -qE '^\s+\d+ passed'; then + if [ "$SMOKE_STATUS" -ne 0 ]; then echo " ❌ Smoke tests FAILED" - exit 1 + exit "$SMOKE_STATUS" fi echo " ✅ Smoke tests OK" else @@ -112,10 +172,11 @@ fi # ── 5. CodeScene code health gate (ratchet) ────────────────────────────── # Thresholds live in .codescene-thresholds and only ever go UP (ratchet). -# After every successful push the file is updated if scores improved. +# If remote scores improved, the hook updates the file and stops so the new +# floor is committed with normal verified hooks before the next push. THRESHOLDS_FILE="$(git rev-parse --show-toplevel)/.codescene-thresholds" -HOTSPOT_MIN=9.5 -AVERAGE_MIN=9.31 +HOTSPOT_MIN=9.45 +AVERAGE_MIN=9.29 if [ -f "$THRESHOLDS_FILE" ]; then HOTSPOT_MIN=$(grep HOTSPOT_THRESHOLD "$THRESHOLDS_FILE" | cut -d= -f2) AVERAGE_MIN=$(grep AVERAGE_THRESHOLD "$THRESHOLDS_FILE" | cut -d= -f2) @@ -137,8 +198,9 @@ else else echo " Remote Hotspot Code Health: $HOTSPOT_SCORE (threshold: $HOTSPOT_MIN)" echo " Remote Average Code Health: $AVERAGE_SCORE (threshold: $AVERAGE_MIN)" + PYTHON_STATUS=0 python3 -c " -import sys, os +import sys hotspot = float('$HOTSPOT_SCORE') average = float('$AVERAGE_SCORE') @@ -161,8 +223,6 @@ else: if failed: sys.exit(1) -# Ratchet: update thresholds file if scores improved -# Truncate (floor) to 2 decimals so the threshold never exceeds the actual score import math thresholds_file = '$THRESHOLDS_FILE' new_hotspot = max(hotspot_min, math.floor(hotspot * 100) / 100) @@ -171,9 +231,16 @@ if new_hotspot > hotspot_min or new_average > average_min: with open(thresholds_file, 'w') as f: f.write(f'HOTSPOT_THRESHOLD={new_hotspot}\nAVERAGE_THRESHOLD={new_average}\n') print(f' 📈 Ratchet updated: Hotspot {hotspot_min} → {new_hotspot}, Average {average_min} → {new_average}') - # Stage and amend the thresholds update into the last commit would change history — instead just auto-commit it - os.system(f'git add {thresholds_file} && git commit -m \"chore: ratchet CodeScene thresholds to {new_hotspot}/{new_average}\" --no-verify 2>/dev/null || true') -" || exit 1 + sys.exit(3) +" || PYTHON_STATUS=$? + if [ "$PYTHON_STATUS" -ne 0 ] && [ "$PYTHON_STATUS" -ne 3 ]; then + exit "$PYTHON_STATUS" + fi + if [ "$PYTHON_STATUS" -eq 3 ]; then + git add "$THRESHOLDS_FILE" + echo " ❌ Commit the updated .codescene-thresholds with a normal verified commit, then push again." + exit 1 + fi fi fi diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..5b41578c --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,149 @@ +# AGENTS.md — Laputa App + +> Quick links: [Project Spec](docs/PROJECT-SPEC.md) · [Architecture](docs/ARCHITECTURE.md) · [Abstractions](docs/ABSTRACTIONS.md) · [Wireframes](ui-design.pen) + +--- + +## 1. Task Workflow + +### 1a. Pick up a task + +Run `/laputa-next-task` — fetches next task (To Rework first, then Open), moves to In Progress, returns full description. + +**Before writing a single line of code:** run `mcp__codescene__code_health_score` to check the current codebase health against `.codescene-thresholds`. If the score is already below the threshold, **stop and refactor first** — find the worst files with the MCP, improve them, commit, then start the task. Never start feature work on a codebase that is already below the gate. + +- Read task description and all comments fully +- For To Rework: the ❌ QA failed comment tells you exactly what to fix +- Check `docs/adr/` for relevant architecture decisions before structural choices +- Add a comment: `🚀 Starting work on this task. [Brief description of approach]` + +### 1b. Implement + +- Work on `main` branch — **no branches, no PRs, ever**. Pre-commit and pre-push block work from any other branch. +- Commit every 20–30 min: `feat:`, `fix:`, `refactor:`, `test:`, `docs:` +- **⛔ NEVER use --no-verify** +- For UI tasks: open `ui-design.pen` first, study visual language, design in light mode + +### 1c. When done + +**Phase 1 — Playwright (only for core user flows):** + +Write smoke test in `tests/smoke/.spec.ts` only if feature touches: vault open, note create/save/delete, search, wikilink navigation, git commit/push, conflict resolution. Do NOT write Playwright tests for cosmetic changes — use Vitest instead. Suite must stay under **10 minutes**. + +```bash +pnpm dev --port 5201 & +sleep 3 +BASE_URL="http://localhost:5201" npx playwright test tests/smoke/.spec.ts +``` + +**Phase 2 — Native app QA:** + +```bash +pnpm tauri dev & +sleep 10 +bash ~/.openclaw/skills/laputa-qa/scripts/focus-app.sh laputa +bash ~/.openclaw/skills/laputa-qa/scripts/screenshot.sh /tmp/qa-native.png +``` + +Use `osascript` for keyboard interactions. Write result as Todoist comment (✅ or ❌). **⚠️ WKWebView:** `osascript keystroke` blocked inside editor — rely on Playwright for text input features. + +After both phases pass, add a **completion comment** to the Todoist task before running `/laputa-done`. The comment must include: +- What was implemented (1–2 lines) +- QA: what was tested and how (Playwright / native screenshot / osascript) +- Refactoring: any files refactored to meet the CodeScene gate (or "none needed") +- ADRs: any new/updated ADRs (or "none") +- Docs: any updated docs (ARCHITECTURE.md, ABSTRACTIONS.md, etc.) (or "none") +- Code health: final Hotspot and Average scores after push + +Then run `/laputa-done ` → moves to In Review, notifies Brian, self-dispatches next task. + +--- + +## 2. Development Process + +### Commits & pushes + +- Push directly to `main` — no PRs, no branches. Pre-push blocks non-`main` pushes. +- Pre-push hook runs full check suite (build + tests + Playwright + CodeScene) +- **A task is NOT done until `git push origin main` succeeds.** If the hook blocks: read the error, fix it (clippy, tests, CodeScene, build), commit the fix, push again. **⛔ NEVER use --no-verify** + +### TDD (mandatory) + +Red → Green → Refactor → Commit. One cycle per commit. For bugs: write failing regression test first, then fix. Exception: pure CSS/layout changes. + +**Test quality (Kent Beck's Desiderata):** Isolated · Deterministic · Fast · Behavioral · Structure-insensitive · Specific · Predictive. Fix flaky tests first. Prefer E2E over unit tests for user flows. + +### Code health (mandatory) + +Pre-commit and pre-push hooks enforce **Hotspot Code Health** and **Average Code Health** ≥ thresholds in `.codescene-thresholds`. Both gates block commit/push. Thresholds are a **ratchet** — only go up. When pre-push sees improved remote scores, it updates `.codescene-thresholds`, stages it, and stops so you can commit the new floor with normal verified hooks before pushing again. Never add `// eslint-disable`, `#[allow(...)]`, or `as any`. + +**⛔ NEVER edit `.codescene-thresholds` to lower the values.** If the gate blocks you, improve the code — do not lower the bar. + +**Before every commit:** run `mcp__codescene__code_health_review` on files you touched and verify score is higher. **Boy Scout Rule:** every file you touch must leave with a higher score. + +**If CodeScene gate blocks your push:** use `mcp__codescene__code_health_score` to find the worst file, refactor it, commit, push again. Do NOT stop or wait for laputa-refactor — that is a background loop, not a substitute for fixing your own regressions. + +### Check suite (runs on every push) +```bash +pnpm lint && npx tsc --noEmit && pnpm test && pnpm test:coverage # frontend ≥70% +cargo test && cargo llvm-cov --manifest-path src-tauri/Cargo.toml --no-clean --fail-under-lines 85 +``` + +### ADRs & docs + +ADRs live in `docs/adr/`. Create in the same commit as the code. Never edit existing — create a new one that supersedes. Use `/create-adr`. **When:** new dependency, storage strategy, platform target, core abstraction, cross-cutting pattern. **Not for:** bug fixes, styling, refactors. + +After any Tauri command, new component/hook, data model change, or new integration: update `docs/ARCHITECTURE.md`, `docs/ABSTRACTIONS.md`, and/or `docs/GETTING-STARTED.md` in the same commit. + +--- + +## 3. Product Rules + +### User vault (`~/Laputa/`) + +Default to `demo-vault-v2/`. If you must use `~/Laputa/` for testing: **never commit changes** — always run `cd ~/Laputa && git checkout -- . && git clean -fd` when done. + +### UI design + +Open `ui-design.pen` first (light mode). Create `design/.pen` for the task; on completion merge into `ui-design.pen` and delete it. + +### UI components — mandatory rules + +**Always use shadcn/ui components.** Never use raw HTML form elements (``, ``, etc.) for user-facing UI. Every interactive element must use the shadcn/ui equivalent: + +| Need | Use | +|---|---| +| Text input | `Input` from shadcn/ui | +| Dropdown/select | `Select` from shadcn/ui | +| Date picker | `Calendar` + `Popover` from shadcn/ui (NOT native ``) | +| Button | `Button` from shadcn/ui | +| Autocomplete/combobox | Reuse existing combobox components from the app (check `src/components/`) | +| Wikilink picker | Reuse the wikilink autocomplete component already used in the editor and Properties panel | +| Emoji picker | Reuse the emoji picker component already used for note/type icons | +| Color picker | Reuse the color swatch picker used for type customization | +| Toggle/switch | `Switch` or `ToggleGroup` from shadcn/ui | +| Dialog/modal | `Dialog` from shadcn/ui | + +**When in doubt:** search `src/components/` for an existing component before building new. **Visual language:** all new UI must feel native to Laputa — if it looks like a browser default, it's wrong. + +--- + +## 4. Reference + +### macOS / Tauri gotchas + +- `Option+N` → special chars on macOS. Use `e.code` or `Cmd+N` +- Tauri menu accelerators: `MenuItemBuilder::new(label).accelerator("CmdOrCtrl+1")` +- `app.set_menu()` replaces the ENTIRE menu bar — include all submenus +- `mock-tauri.ts` silently swallows Tauri calls — not a substitute for native testing +### QA scripts + +```bash +bash ~/.openclaw/skills/laputa-qa/scripts/focus-app.sh laputa +bash ~/.openclaw/skills/laputa-qa/scripts/screenshot.sh /tmp/out.png +bash ~/.openclaw/skills/laputa-qa/scripts/shortcut.sh "command" "s" +``` + +### Diagrams + +Prefer Mermaid (`flowchart`, `sequenceDiagram`, `classDiagram`, `stateDiagram-v2`). ASCII only for spatial wireframe layouts. diff --git a/CLAUDE.md b/CLAUDE.md index 65f1d450..8aa98e3a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,149 +1,3 @@ -# CLAUDE.md — Laputa App +@AGENTS.md -> Quick links: [Project Spec](docs/PROJECT-SPEC.md) · [Architecture](docs/ARCHITECTURE.md) · [Abstractions](docs/ABSTRACTIONS.md) · [Wireframes](ui-design.pen) - ---- - -## 1. Task Workflow - -### 1a. Pick up a task - -Run `/laputa-next-task` — fetches next task (To Rework first, then Open), moves to In Progress, returns full description. - -**Before writing a single line of code:** run `mcp__codescene__code_health_score` to check the current codebase health against `.codescene-thresholds`. If the score is already below the threshold, **stop and refactor first** — find the worst files with the MCP, improve them, commit, then start the task. Never start feature work on a codebase that is already below the gate. - -- Read task description and all comments fully -- For To Rework: the ❌ QA failed comment tells you exactly what to fix -- Check `docs/adr/` for relevant architecture decisions before structural choices -- Add a comment: `🚀 Starting work on this task. [Brief description of approach]` - -### 1b. Implement - -- Work on `main` branch — **no branches, no PRs, ever** -- Commit every 20–30 min: `feat:`, `fix:`, `refactor:`, `test:`, `docs:` -- **⛔ NEVER use --no-verify** -- For UI tasks: open `ui-design.pen` first, study visual language, design in light mode - -### 1c. When done - -**Phase 1 — Playwright (only for core user flows):** - -Write smoke test in `tests/smoke/.spec.ts` only if feature touches: vault open, note create/save/delete, search, wikilink navigation, git commit/push, conflict resolution. Do NOT write Playwright tests for cosmetic changes — use Vitest instead. Suite must stay under **10 minutes**. - -```bash -pnpm dev --port 5201 & -sleep 3 -BASE_URL="http://localhost:5201" npx playwright test tests/smoke/.spec.ts -``` - -**Phase 2 — Native app QA:** - -```bash -pnpm tauri dev & -sleep 10 -bash ~/.openclaw/skills/laputa-qa/scripts/focus-app.sh laputa -bash ~/.openclaw/skills/laputa-qa/scripts/screenshot.sh /tmp/qa-native.png -``` - -Use `osascript` for keyboard interactions. Write result as Todoist comment (✅ or ❌). **⚠️ WKWebView:** `osascript keystroke` blocked inside editor — rely on Playwright for text input features. - -After both phases pass, add a **completion comment** to the Todoist task before running `/laputa-done`. The comment must include: -- What was implemented (1–2 lines) -- QA: what was tested and how (Playwright / native screenshot / osascript) -- Refactoring: any files refactored to meet the CodeScene gate (or "none needed") -- ADRs: any new/updated ADRs (or "none") -- Docs: any updated docs (ARCHITECTURE.md, ABSTRACTIONS.md, etc.) (or "none") -- Code health: final Hotspot and Average scores after push - -Then run `/laputa-done ` → moves to In Review, notifies Brian, self-dispatches next task. - ---- - -## 2. Development Process - -### Commits & pushes - -- Push directly to `main` — no PRs, no branches -- Pre-push hook runs full check suite (build + tests + Playwright + CodeScene) -- **A task is NOT done until `git push origin main` succeeds.** If the hook blocks: read the error, fix it (clippy, tests, CodeScene, build), commit the fix, push again. **⛔ NEVER use --no-verify** - -### TDD (mandatory) - -Red → Green → Refactor → Commit. One cycle per commit. For bugs: write failing regression test first, then fix. Exception: pure CSS/layout changes. - -**Test quality (Kent Beck's Desiderata):** Isolated · Deterministic · Fast · Behavioral · Structure-insensitive · Specific · Predictive. Fix flaky tests first. Prefer E2E over unit tests for user flows. - -### Code health (mandatory) - -Pre-commit and pre-push hooks enforce **Hotspot Code Health** and **Average Code Health** ≥ thresholds in `.codescene-thresholds`. Both gates block commit/push. Thresholds are a **ratchet** — only go up, auto-updated after each successful push. Never add `// eslint-disable`, `#[allow(...)]`, or `as any`. - -**⛔ NEVER edit `.codescene-thresholds` to lower the values.** If the gate blocks you, improve the code — do not lower the bar. - -**Before every commit:** run `mcp__codescene__code_health_review` on files you touched and verify score is higher. **Boy Scout Rule:** every file you touch must leave with a higher score. - -**If CodeScene gate blocks your push:** use `mcp__codescene__code_health_score` to find the worst file, refactor it, commit, push again. Do NOT stop or wait for laputa-refactor — that is a background loop, not a substitute for fixing your own regressions. - -### Check suite (runs on every push) -```bash -pnpm lint && npx tsc --noEmit && pnpm test && pnpm test:coverage # frontend ≥70% -cargo test && cargo llvm-cov --manifest-path src-tauri/Cargo.toml --no-clean --fail-under-lines 85 -``` - -### ADRs & docs - -ADRs live in `docs/adr/`. Create in the same commit as the code. Never edit existing — create a new one that supersedes. Use `/create-adr`. **When:** new dependency, storage strategy, platform target, core abstraction, cross-cutting pattern. **Not for:** bug fixes, styling, refactors. - -After any Tauri command, new component/hook, data model change, or new integration: update `docs/ARCHITECTURE.md`, `docs/ABSTRACTIONS.md`, and/or `docs/GETTING-STARTED.md` in the same commit. - ---- - -## 3. Product Rules - -### User vault (`~/Laputa/`) - -Default to `demo-vault-v2/`. If you must use `~/Laputa/` for testing: **never commit changes** — always run `cd ~/Laputa && git checkout -- . && git clean -fd` when done. - -### UI design - -Open `ui-design.pen` first (light mode). Create `design/.pen` for the task; on completion merge into `ui-design.pen` and delete it. - -### UI components — mandatory rules - -**Always use shadcn/ui components.** Never use raw HTML form elements (``, ``, etc.) for user-facing UI. Every interactive element must use the shadcn/ui equivalent: - -| Need | Use | -|---|---| -| Text input | `Input` from shadcn/ui | -| Dropdown/select | `Select` from shadcn/ui | -| Date picker | `Calendar` + `Popover` from shadcn/ui (NOT native ``) | -| Button | `Button` from shadcn/ui | -| Autocomplete/combobox | Reuse existing combobox components from the app (check `src/components/`) | -| Wikilink picker | Reuse the wikilink autocomplete component already used in the editor and Properties panel | -| Emoji picker | Reuse the emoji picker component already used for note/type icons | -| Color picker | Reuse the color swatch picker used for type customization | -| Toggle/switch | `Switch` or `ToggleGroup` from shadcn/ui | -| Dialog/modal | `Dialog` from shadcn/ui | - -**When in doubt:** search `src/components/` for an existing component before building new. **Visual language:** all new UI must feel native to Laputa — if it looks like a browser default, it's wrong. - ---- - -## 4. Reference - -### macOS / Tauri gotchas - -- `Option+N` → special chars on macOS. Use `e.code` or `Cmd+N` -- Tauri menu accelerators: `MenuItemBuilder::new(label).accelerator("CmdOrCtrl+1")` -- `app.set_menu()` replaces the ENTIRE menu bar — include all submenus -- `mock-tauri.ts` silently swallows Tauri calls — not a substitute for native testing -### QA scripts - -```bash -bash ~/.openclaw/skills/laputa-qa/scripts/focus-app.sh laputa -bash ~/.openclaw/skills/laputa-qa/scripts/screenshot.sh /tmp/out.png -bash ~/.openclaw/skills/laputa-qa/scripts/shortcut.sh "command" "s" -``` - -### Diagrams - -Prefer Mermaid (`flowchart`, `sequenceDiagram`, `classDiagram`, `stateDiagram-v2`). ASCII only for spatial wireframe layouts. +This file is a Claude Code compatibility shim. Keep shared agent instructions in `AGENTS.md`. diff --git a/README.md b/README.md index 5c6f8ced..75f7216c 100644 --- a/README.md +++ b/README.md @@ -24,9 +24,6 @@ Personal knowledge and life management desktop app built with Tauri v2 + React + # Install dependencies pnpm install -# Install git hooks (optional but recommended) -.github/hooks/install-hooks.sh - # Run dev server pnpm dev @@ -69,7 +66,7 @@ claude 'Check code health with CodeScene MCP' ## Development Workflow -See [CLAUDE.md](CLAUDE.md) for coding guidelines and workflow. +See [AGENTS.md](AGENTS.md) for coding guidelines and workflow. [CLAUDE.md](CLAUDE.md) remains as a compatibility shim for Claude Code. **Key principles:** - Small, atomic commits @@ -79,7 +76,7 @@ See [CLAUDE.md](CLAUDE.md) for coding guidelines and workflow. ## CI/CD -GitHub Actions runs on every push/PR: +GitHub Actions runs on every push to `main`: - ✅ Tests (frontend + Rust) - 📊 Coverage (70% threshold) - 🎨 Lint & format @@ -89,7 +86,7 @@ See [.github/SETUP.md](.github/SETUP.md) for CI/CD configuration. ## Git Hooks -Pre-commit hook checks code health before every commit. See [.github/HOOKS.md](.github/HOOKS.md) for details. +Husky installs the git hooks from `.husky/` during `pnpm install`. The repo enforces `main`-only commits and pushes; see [.github/HOOKS.md](.github/HOOKS.md) for details. ## License diff --git a/docs/GETTING-STARTED.md b/docs/GETTING-STARTED.md index aa7b2e67..936efa3c 100644 --- a/docs/GETTING-STARTED.md +++ b/docs/GETTING-STARTED.md @@ -177,7 +177,8 @@ laputa-app/ ├── tsconfig.json # TypeScript config ├── playwright.config.ts # E2E test config ├── ui-design.pen # Master design file -├── CLAUDE.md # Project instructions +├── AGENTS.md # Shared project instructions for coding agents +├── CLAUDE.md # Claude Code compatibility shim importing AGENTS.md └── docs/ # This documentation ``` diff --git a/getting-started-vault/AGENTS.md b/getting-started-vault/AGENTS.md new file mode 100644 index 00000000..75f14225 --- /dev/null +++ b/getting-started-vault/AGENTS.md @@ -0,0 +1,81 @@ +# AGENTS.md — Laputa Vault + +This is a [Laputa](https://github.com/refactoringhq/laputa-app) vault — a folder of markdown files with YAML frontmatter forming a personal knowledge graph. + +## Note structure + +Every note is a markdown file. The **first H1 heading in the body is the title** — there is no `title:` frontmatter field. + +```yaml +--- +is_a: TypeName # the note's type (must match the title of a type file in the vault) +url: https://... # example property +belongs_to: "[[other-note]]" +related_to: + - "[[note-a]]" + - "[[note-b]]" +--- + +# Note Title + +Body content in markdown. +``` + +System properties are prefixed with `_` (e.g. `_organized`, `_pinned`, `_icon`) — these are app-managed, do not set or show them to users unless specifically asked. + +## Types + +A type is a note with `is_a: Type`. Type files live in the vault root: + +```yaml +--- +is_a: Type +_icon: books # Phosphor icon name in kebab-case +_color: "#8b5cf6" # hex color +--- + +# TypeName +``` + +To find what types exist: look for files with `is_a: Type` in the vault root. + +## Relationships + +Any frontmatter property whose value is a wikilink is a relationship. Backlinks are computed automatically. + +Standard names: `belongs_to`, `related_to`, `has`. Custom names are valid. + +## Wikilinks + +- `[[filename]]` or `[[Note Title]]` — link by filename or title +- `[[filename|display text]]` — with custom display text +- Works in frontmatter values and markdown body + +## Views + +Saved filters live in `views/` as `.view.json` files: + +```json +{ + "title": "Active Notes", + "filters": [ + {"property": "is_a", "operator": "equals", "value": "Note"}, + {"property": "status", "operator": "equals", "value": "Active"} + ], + "sort": {"property": "title", "direction": "asc"} +} +``` + +## Filenames + +Use kebab-case: `my-note-title.md`. One note per file. + +## What you can do + +- Create/edit notes with correct frontmatter and H1 title +- Create new type files +- Add or modify relationships +- Create/edit views in `views/` +- Edit `AGENTS.md` (this file) + +Do not modify app configuration files — those are local to each installation. diff --git a/getting-started-vault/CLAUDE.md b/getting-started-vault/CLAUDE.md index a244d027..e035fbfa 100644 --- a/getting-started-vault/CLAUDE.md +++ b/getting-started-vault/CLAUDE.md @@ -1,81 +1,3 @@ -# CLAUDE.md — Laputa Vault +@AGENTS.md -This is a [Laputa](https://github.com/refactoringhq/laputa-app) vault — a folder of markdown files with YAML frontmatter forming a personal knowledge graph. - -## Note structure - -Every note is a markdown file. The **first H1 heading in the body is the title** — there is no `title:` frontmatter field. - -```yaml ---- -is_a: TypeName # the note's type (must match the title of a type file in the vault) -url: https://... # example property -belongs_to: "[[other-note]]" -related_to: - - "[[note-a]]" - - "[[note-b]]" ---- - -# Note Title - -Body content in markdown. -``` - -System properties are prefixed with `_` (e.g. `_organized`, `_pinned`, `_icon`) — these are app-managed, do not set or show them to users unless specifically asked. - -## Types - -A type is a note with `is_a: Type`. Type files live in the vault root: - -```yaml ---- -is_a: Type -_icon: books # Phosphor icon name in kebab-case -_color: "#8b5cf6" # hex color ---- - -# TypeName -``` - -To find what types exist: look for files with `is_a: Type` in the vault root. - -## Relationships - -Any frontmatter property whose value is a wikilink is a relationship. Backlinks are computed automatically. - -Standard names: `belongs_to`, `related_to`, `has`. Custom names are valid. - -## Wikilinks - -- `[[filename]]` or `[[Note Title]]` — link by filename or title -- `[[filename|display text]]` — with custom display text -- Works in frontmatter values and markdown body - -## Views - -Saved filters live in `views/` as `.view.json` files: - -```json -{ - "title": "Active Notes", - "filters": [ - {"property": "is_a", "operator": "equals", "value": "Note"}, - {"property": "status", "operator": "equals", "value": "Active"} - ], - "sort": {"property": "title", "direction": "asc"} -} -``` - -## Filenames - -Use kebab-case: `my-note-title.md`. One note per file. - -## What you can do - -- Create/edit notes with correct frontmatter and H1 title -- Create new type files -- Add or modify relationships -- Create/edit views in `views/` -- Edit `CLAUDE.md` (this file) - -Do not modify app configuration files — those are local to each installation. +This file is a Claude Code compatibility shim. Keep shared vault instructions in `AGENTS.md`. diff --git a/getting-started-vault/ai-and-git.md b/getting-started-vault/ai-and-git.md index b6fc48a9..2f497826 100644 --- a/getting-started-vault/ai-and-git.md +++ b/getting-started-vault/ai-and-git.md @@ -12,7 +12,7 @@ Laputa integrates with [Claude Code](https://docs.anthropic.com/claude-code) — claude "Create a note for the book Zero to One by Peter Thiel, with a rating and a topic" ``` -Claude understands Laputa's format (frontmatter, types, wikilinks, relationships) and creates or edits files accordingly. Your vault's `CLAUDE.md` file gives it full context. +Claude understands Laputa's format (frontmatter, types, wikilinks, relationships) and creates or edits files accordingly. Your vault's `AGENTS.md` file gives any coding agent full context, and `CLAUDE.md` imports it for Claude Code compatibility. ## Git sync