diff --git a/.beads/README.md b/.beads/README.md index daac3c4e..d7831ff2 100644 --- a/.beads/README.md +++ b/.beads/README.md @@ -14,32 +14,32 @@ Beads is issue tracking that lives in your repo, making it perfect for AI coding ```bash # Create new issues -bd create "Add user authentication" +br create "Add user authentication" # View all issues -bd list +br list # View issue details -bd show +br show # Update issue status -bd update --status in_progress -bd update --status done +br update --status in_progress +br update --status done # Sync with git remote -bd sync +br sync ``` ## Daemon (Optional) -Beads has an optional background daemon (`bd daemon`) that auto-syncs issues with git. +Beads has an optional background daemon (`br daemon`) that auto-syncs issues with git. In this repo, the sync branch is configured as `main`. Running the daemon while you are on a different branch can cause `.beads/issues.jsonl` to be rewritten from `main`, leaving your working tree dirty and blocking `git pull --rebase`. Recommended workflow: -- Prefer manual sync: `bd sync` (default). -- If you use the daemon, run it only while you are on `main`, or run it in local-only mode: `bd daemon --start --local`. -- If `.beads/issues.jsonl` is changing unexpectedly, check/stop the daemon: `bd daemon --status` / `bd daemon --stop`. +- Prefer manual sync: `br sync` (default). +- If you use the daemon, run it only while you are on `main`, or run it in local-only mode: `br daemon --start --local`. +- If `.beads/issues.jsonl` is changing unexpectedly, check/stop the daemon: `br daemon --status` / `br daemon --stop`. ### Working with Issues @@ -75,16 +75,16 @@ Try Beads in your own projects: curl -sSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash # Initialize in your repo -bd init +br init # Create your first issue -bd create "Try out Beads" +br create "Try out Beads" ``` ## Learn More - **Documentation**: [github.com/steveyegge/beads/docs](https://github.com/steveyegge/beads/tree/main/docs) -- **Quick Start Guide**: Run `bd quickstart` +- **Quick Start Guide**: Run `br quickstart` - **Examples**: [github.com/steveyegge/beads/examples](https://github.com/steveyegge/beads/tree/main/examples) --- diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 3d3ac096..8df7a13f 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -742,6 +742,7 @@ {"id":"agentic_coding_flywheel_setup-zumu","title":"Reduce flakiness in production Playwright smoke tests","description":"Playwright production smoke tests used waitForLoadState(\"networkidle\") directly, which can be flaky on pages with long-lived background requests (analytics, etc). Add a helper that waits for domcontentloaded and then attempts networkidle with a short timeout, without failing if the page never becomes fully idle.","status":"closed","priority":3,"issue_type":"bug","created_at":"2025-12-25T06:26:18.185815Z","updated_at":"2025-12-25T06:26:46.273323Z","closed_at":"2025-12-25T06:26:46.273323Z","close_reason":"Implemented waitForPageSettled helper and replaced strict networkidle waits in production smoke tests.","source_repo":".","compaction_level":0,"dependencies":[{"issue_id":"agentic_coding_flywheel_setup-zumu","depends_on_id":"agentic_coding_flywheel_setup-dvt.6","type":"discovered-from","created_at":"2025-12-25T06:26:18.187139Z","created_by":"jemanuel","metadata":"{}","thread_id":""}]} {"id":"agentic_coding_flywheel_setup-zv33","title":"Random deep code exploration audit (Round 3)","description":"Random audit pass: trace manifest generator + installer security paths, then fix any concrete issues found (reserve files before edits).","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-25T09:37:22.568240Z","updated_at":"2025-12-25T09:54:51.415794Z","closed_at":"2025-12-25T09:54:51.415794Z","close_reason":"Fixed manifest generator verified_installer piping for bash/sh args (commit 5b0c67a); bun test + type-check passed.","source_repo":".","compaction_level":0} {"id":"agentic_coding_flywheel_setup-zwg3","title":"TASK: Add final completion certificate to onboard","description":"# TASK: Add final completion certificate to onboard\n\n## Context\nWhen user completes all 9 lessons, show a special completion screen.\n\n## Proposed Screen\n```\n╭─────────────────────────────────────────────────────────────╮\n│ │\n│ 🏆 ACFS ONBOARDING COMPLETE! │\n│ │\n│ Congratulations! You've completed all 9 lessons. │\n│ │\n│ You're now ready to: │\n│ • Launch AI agents with cc, cod, gmi │\n│ • Manage sessions with ntm │\n│ • Search code with rg │\n│ • Use the full flywheel workflow │\n│ │\n│ Next steps: │\n│ • Run 'acfs info' for quick reference │\n│ • Run 'acfs cheatsheet' for all commands │\n│ • Start a project with 'ntm new myproject && cc' │\n│ │\n│ Completed: $(date +'%Y-%m-%d %H:%M') │\n│ │\n│ Happy coding! 🚀 │\n│ │\n╰─────────────────────────────────────────────────────────────╯\n```\n\n## Implementation\n\n### Store Completion Timestamp\n```bash\n# In onboard_progress.json\n{\n \"completed_lessons\": [0,1,2,3,4,5,6,7,8],\n \"completed_at\": \"2025-01-15T14:30:00Z\"\n}\n```\n\n### Trigger Condition\nShow when:\n- User just completed lesson 8 (last)\n- OR user runs `onboard` when all lessons complete\n\n### Re-access\nUser can re-run `onboard` to see certificate again.\n\n## Acceptance Criteria\n- [ ] Certificate shown on final completion\n- [ ] Completion timestamp stored\n- [ ] Shows next steps recommendations\n- [ ] Accessible by running onboard again\n- [ ] Celebration emoji/styling","status":"closed","priority":3,"issue_type":"task","created_at":"2025-12-22T19:59:54.304099Z","updated_at":"2025-12-22T20:35:03.037145Z","closed_at":"2025-12-22T20:35:03.037145Z","close_reason":"View Certificate menu option added to onboard. Shows trophy option when all 9 lessons complete.","source_repo":".","compaction_level":0,"dependencies":[{"issue_id":"agentic_coding_flywheel_setup-zwg3","depends_on_id":"agentic_coding_flywheel_setup-kyhv","type":"blocks","created_at":"2025-12-22T20:00:16.782605Z","created_by":"jemanuel","metadata":"{}","thread_id":""}]} +{"id":"bd-10sv","title":"Fix SLB installation failure on Ubuntu 25.04","status":"closed","priority":1,"issue_type":"bug","created_at":"2026-02-03T14:38:30.188603390Z","created_by":"ubuntu","updated_at":"2026-02-03T14:42:35.650533697Z","closed_at":"2026-02-03T14:42:35.650514952Z","close_reason":"Fixed by installing SLB via .deb (commit 75a91c50)","source_repo":".","compaction_level":0,"original_size":0} {"id":"bd-12kj","title":"Deep exploration: WA (WezTerm Automata)","description":"## Goal\nPerform deep exploration of WA (Web Agent / WebView Automation) and revise its description on the flywheel/TLDR pages with comprehensive testing.\n\n## Phase 0: Pre-flight Verification (CRITICAL)\n\n### 0.1 Tool Existence Check\n```bash\n# Verify WA installation (check for common web automation paths)\n[[ -d /dp/web_agent ]] && echo \"PASS: wa repo exists\" || echo \"INFO: wa repo path differs\"\ncommand -v wa &>/dev/null && echo \"PASS: wa command available\" || echo \"INFO: wa not in PATH\"\n\n# Check browser automation dependencies\ncommand -v playwright &>/dev/null && echo \"INFO: playwright available\" || echo \"INFO: playwright not installed\"\ncommand -v chromium &>/dev/null && echo \"INFO: chromium available\" || echo \"INFO: chromium not installed\"\n```\n\n### 0.2 Content Snapshot (BEFORE State)\n```bash\nSNAPSHOT_DIR=/tmp/wa-exploration-snapshots-$(date +%Y%m%d-%H%M%S)\nmkdir -p $SNAPSHOT_DIR\ncp apps/web/lib/flywheel.ts $SNAPSHOT_DIR/flywheel.ts.before\ncp apps/web/lib/tldr-content.ts $SNAPSHOT_DIR/tldr-content.ts.before\necho \"Snapshots saved to $SNAPSHOT_DIR\"\n```\n\n### 0.3 TypeScript Interface Reference\nContent must match FlywheelTool interface:\n- id, name, tagline, description, deepDescription\n- features[], cliCommands[], connectsTo[]\n- integrationLevel, category, status\n\n## Phase 1: Research (GATHER CONTEXT)\n\n### 1.1 Primary Documentation\n- Find WA repo and read README\n- Check for browser automation docs, screenshot capabilities\n\n### 1.2 Code Investigation\n- Launch code investigation agent to understand:\n - Browser automation mechanism (Playwright? Puppeteer?)\n - Screenshot capture capabilities\n - Form filling and interaction\n - Integration with Claude chrome extension\n - Headless vs headed mode\n\n### 1.3 CLI Command Verification\n```bash\n# Verify each documented command works\nwa --help 2>&1 | head -20 || echo \"No wa command\"\n# Check for alternative names\nbrowser-agent --help 2>&1 | head -10 || echo \"No browser-agent\"\n```\n\n### 1.4 External Context Search\n- `/xf search 'web agent OR browser automation OR playwright'` - Twitter archive\n- `cass search 'wa browser screenshot' --robot --limit 10` - Past sessions\n\n### 1.5 Project State Review\n- Find WA repo location\n- Review recent commits\n\n## Phase 2: Analysis (SYNTHESIZE UNDERSTANDING)\n\n### 2.1 Core Capabilities Verification\nDocument findings for each area:\n- [ ] Browser automation engine\n- [ ] Screenshot capabilities\n- [ ] Form interaction\n- [ ] Claude extension integration\n- [ ] Headless operation\n\n### 2.2 Synergy Verification\nCross-reference these tools actually integrate:\n- [ ] claude-chrome - Chrome extension\n- [ ] mail - screenshot sharing\n- [ ] ntm - coordinated browser tasks\n\n### 2.3 Capability Verification\n```bash\n# Check for playwright installation\nnpx playwright --version 2>/dev/null || echo \"playwright not installed\"\n\n# Check for browser binaries\nls ~/.cache/ms-playwright/ 2>/dev/null | head -5 || echo \"No cached browsers\"\n```\n\n## Phase 3: Revision (UPDATE DESCRIPTIONS)\n\n### 3.1 Update apps/web/lib/flywheel.ts\nUpdate wa entry with VERIFIED information:\n- `tagline`: Browser automation\n- `description`: Web interaction capabilities\n- `deepDescription`: How automation works\n- `features`: Verified capabilities\n- `cliCommands`: Only commands that actually work\n- `connectsTo`: Only verified integrations\n\n### 3.2 Update apps/web/lib/tldr-content.ts\nUpdate TldrFlywheelTool entry with:\n- `briefDescription`: Technical summary\n- `bulletPoints`: Verified capabilities\n- `synergyExamples`: Working integration examples\n\n## Phase 4: Testing (VERIFY CHANGES)\n\n### 4.1 TypeScript Compilation\n```bash\ncd apps/web && npx tsc --noEmit 2>&1 | head -20\n```\n\n### 4.2 Unit Tests\n```bash\n# Test wa entry structure\nnode -e \"\nconst { flywheelTools } = require('./lib/flywheel');\nconst wa = flywheelTools.find(t => t.id === 'wa');\nconsole.log('Testing wa entry...');\nconsole.assert(wa, 'wa entry exists');\nconsole.assert(wa.features?.length > 0, 'has features');\nconsole.log('All assertions passed');\n\"\n```\n\n### 4.3 E2E Test: Browser Automation (Safe Mode)\n```bash\n#\\!/bin/bash\nset -euo pipefail\nLOG=/tmp/wa-e2e-$(date +%Y%m%d-%H%M%S).log\n\necho \"=== WA E2E Test ===\" | tee $LOG\necho \"Started: $(date)\" | tee -a $LOG\n\n# Test 1: Help/availability\necho \"Test 1: Help check...\" | tee -a $LOG\nwa --help 2>&1 | head -10 | tee -a $LOG || echo \"wa not available\"\n\n# Test 2: Screenshot capability\necho \"Test 2: Screenshot help...\" | tee -a $LOG\nwa screenshot --help 2>&1 | head -5 | tee -a $LOG || echo \"No screenshot command\"\n\necho \"=== All Tests Passed ===\" | tee -a $LOG\necho \"Log: $LOG\"\n```\n\n### 4.4 Content Diff Verification\n```bash\necho \"=== Changes Made ===\"\ndiff $SNAPSHOT_DIR/flywheel.ts.before apps/web/lib/flywheel.ts || true\ndiff $SNAPSHOT_DIR/tldr-content.ts.before apps/web/lib/tldr-content.ts || true\n```\n\n## Phase 5: Completion (FINALIZE)\n\n### 5.1 Rollback Procedure (if tests fail)\n```bash\ncp $SNAPSHOT_DIR/flywheel.ts.before apps/web/lib/flywheel.ts\ncp $SNAPSHOT_DIR/tldr-content.ts.before apps/web/lib/tldr-content.ts\necho \"Rolled back to pre-exploration state\"\n```\n\n### 5.2 Sync Changes\n```bash\nbr update bd-12kj --status done\nbr sync --flush-only\n```\n\n### 5.3 Final Verification\n- [ ] All tests pass\n- [ ] TypeScript compiles without errors\n- [ ] Browser capabilities documented correctly\n- [ ] No broken links or references","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-26T20:02:06.153300827Z","created_by":"ubuntu","updated_at":"2026-01-27T03:38:10.013400309Z","closed_at":"2026-01-27T03:38:10.013370132Z","close_reason":"done","source_repo":".","compaction_level":0,"original_size":0} {"id":"bd-1493","title":"Subtask: Update WizardNavigation to check validation","status":"closed","priority":2,"issue_type":"subtask","created_at":"2026-01-25T23:24:26.675842784Z","created_by":"ubuntu","updated_at":"2026-01-27T02:12:14.306857584Z","closed_at":"2026-01-27T02:12:14.306839079Z","close_reason":"Implemented as part of parent bd-2gys - wizard/layout.tsx uses useStepValidation for navigation","source_repo":".","compaction_level":0,"original_size":0,"dependencies":[{"issue_id":"bd-1493","depends_on_id":"bd-2gys","type":"blocks","created_at":"2026-01-25T23:25:59.783098123Z","created_by":"ubuntu"}]} {"id":"bd-14l5","title":"Subtask: Add validate() functions to wizard steps","status":"closed","priority":2,"issue_type":"subtask","created_at":"2026-01-25T23:23:49.345900022Z","created_by":"ubuntu","updated_at":"2026-01-27T02:12:31.374169403Z","closed_at":"2026-01-27T02:12:31.374148624Z","close_reason":"Core validators added in parent bd-2gys (OS selection, VPS creation). Infrastructure complete; additional validators can be added incrementally.","source_repo":".","compaction_level":0,"original_size":0,"dependencies":[{"issue_id":"bd-14l5","depends_on_id":"bd-2gys","type":"blocks","created_at":"2026-01-25T23:25:46.360792994Z","created_by":"ubuntu"}]} @@ -871,6 +872,7 @@ {"id":"bd-223z","title":"Subtask: Add --fix flag parsing to doctor command","status":"closed","priority":1,"issue_type":"subtask","created_at":"2026-01-25T23:20:40.947681729Z","created_by":"ubuntu","updated_at":"2026-01-25T23:45:04.875526830Z","closed_at":"2026-01-25T23:45:04.875275928Z","close_reason":"Duplicate of bd-31ps.6.2","source_repo":".","compaction_level":0,"original_size":0} {"id":"bd-22gc","title":"Deep exploration: SLB (Simultaneous Launch Button)","description":"## Goal\nPerform deep exploration of SLB (Simultaneous Launch Button) and revise its description on the flywheel/TLDR pages with comprehensive testing.\n\n## Phase 0: Pre-flight Verification (CRITICAL)\n\n### 0.1 Tool Existence Check\n```bash\n# Verify SLB installation\n[[ -d /dp/simultaneous_launch_button ]] && echo \"PASS: slb repo exists\" || { echo \"FAIL: slb repo missing\"; exit 1; }\ncommand -v slb &>/dev/null && echo \"PASS: slb command available\" || { echo \"FAIL: slb not in PATH\"; exit 1; }\n\n# Check if slb daemon/server is available\npgrep -f slb 2>/dev/null && echo \"INFO: slb process running\" || echo \"INFO: slb not currently running\"\n```\n\n### 0.2 Content Snapshot (BEFORE State)\n```bash\nSNAPSHOT_DIR=/tmp/slb-exploration-snapshots-$(date +%Y%m%d-%H%M%S)\nmkdir -p $SNAPSHOT_DIR\ncp apps/web/lib/flywheel.ts $SNAPSHOT_DIR/flywheel.ts.before\ncp apps/web/lib/tldr-content.ts $SNAPSHOT_DIR/tldr-content.ts.before\necho \"Snapshots saved to $SNAPSHOT_DIR\"\n```\n\n### 0.3 TypeScript Interface Reference\nContent must match FlywheelTool interface:\n- id, name, tagline, description, deepDescription\n- features[], cliCommands[], connectsTo[]\n- integrationLevel, category, status\n\n## Phase 1: Research (GATHER CONTEXT)\n\n### 1.1 Primary Documentation\n- `cat /dp/simultaneous_launch_button/README.md` - Read full README\n- Check for two-person rule docs, coordination protocol\n\n### 1.2 Code Investigation\n- Launch code investigation agent to understand:\n - Two-person rule implementation\n - Confirmation mechanism (how both agents confirm)\n - Timeout handling for confirmations\n - Integration with destructive command protection\n - Coordination protocol (messaging, locks)\n\n### 1.3 CLI Command Verification\n```bash\n# Verify each documented command works\nslb --help 2>&1 | head -20\nslb confirm --help 2>&1 | head -10\nslb status --help 2>&1 | head -10\n\n# Test actual functionality\nslb status 2>&1 | head -5\n```\n\n### 1.4 External Context Search\n- `/xf search 'slb OR simultaneous launch OR two-person rule'` - Twitter archive\n- `cass search 'slb coordination' --robot --limit 10` - Past sessions\n\n### 1.5 Project State Review\n- Check beads in /dp/simultaneous_launch_button/.beads/\n- Review recent commits: `cd /dp/simultaneous_launch_button && git log --oneline -20`\n\n## Phase 2: Analysis (SYNTHESIZE UNDERSTANDING)\n\n### 2.1 Core Capabilities Verification\nDocument findings for each area:\n- [ ] Two-person rule mechanism\n- [ ] Confirmation protocol and timeout\n- [ ] Command types requiring two-person approval\n- [ ] Integration with dcg (destructive command guard)\n- [ ] Recovery from failed confirmations\n\n### 2.2 Synergy Verification\nCross-reference these tools actually integrate:\n- [ ] dcg - destructive command protection\n- [ ] mail - confirmation messaging\n- [ ] ntm - multi-agent coordination\n\n### 2.3 Safety Verification\n```bash\n# Check what commands trigger two-person rule\ncat /dp/simultaneous_launch_button/config/*.yaml 2>/dev/null | head -20\n# Or check code for command patterns\ngrep -r \"dangerous\\|destructive\" /dp/simultaneous_launch_button/src/ 2>/dev/null | head -10\n```\n\n## Phase 3: Revision (UPDATE DESCRIPTIONS)\n\n### 3.1 Update apps/web/lib/flywheel.ts\nUpdate slb entry with VERIFIED information:\n- `tagline`: Two-person rule for dangerous commands\n- `description`: Coordination protocol\n- `deepDescription`: How confirmation works\n- `features`: Verified safety capabilities\n- `cliCommands`: Only commands that actually work\n- `connectsTo`: Only verified integrations (dcg, mail, ntm)\n\n### 3.2 Update apps/web/lib/tldr-content.ts\nUpdate TldrFlywheelTool entry with:\n- `briefDescription`: Technical summary\n- `bulletPoints`: Verified capabilities\n- `synergyExamples`: Working integration examples\n\n## Phase 4: Testing (VERIFY CHANGES)\n\n### 4.1 TypeScript Compilation\n```bash\ncd apps/web && npx tsc --noEmit 2>&1 | head -20\n```\n\n### 4.2 Unit Tests\n```bash\n# Test slb entry structure\nnode -e \"\nconst { flywheelTools } = require('./lib/flywheel');\nconst slb = flywheelTools.find(t => t.id === 'slb');\nconsole.log('Testing slb entry...');\nconsole.assert(slb, 'slb entry exists');\nconsole.assert(slb.features?.length > 0, 'has features');\nconsole.assert(slb.connectsTo?.includes('dcg'), 'connects to dcg');\nconsole.log('All assertions passed');\n\"\n```\n\n### 4.3 E2E Test: Coordination Flow (Safe Mode)\n```bash\n#\\!/bin/bash\nset -euo pipefail\nLOG=/tmp/slb-e2e-$(date +%Y%m%d-%H%M%S).log\n\necho \"=== SLB E2E Test ===\" | tee $LOG\necho \"Started: $(date)\" | tee -a $LOG\n\n# Test 1: Status check\necho \"Test 1: Status check...\" | tee -a $LOG\nslb status 2>&1 | tee -a $LOG\n\n# Test 2: Help for confirm\necho \"Test 2: Confirm help...\" | tee -a $LOG\nslb confirm --help 2>&1 | head -5 | tee -a $LOG\n\n# Test 3: List pending (if available)\necho \"Test 3: Pending operations...\" | tee -a $LOG\nslb pending 2>&1 | tee -a $LOG || echo \"No pending command\"\n\necho \"=== All Tests Passed ===\" | tee -a $LOG\necho \"Log: $LOG\"\n```\n\n### 4.4 Content Diff Verification\n```bash\necho \"=== Changes Made ===\"\ndiff $SNAPSHOT_DIR/flywheel.ts.before apps/web/lib/flywheel.ts || true\ndiff $SNAPSHOT_DIR/tldr-content.ts.before apps/web/lib/tldr-content.ts || true\n```\n\n## Phase 5: Completion (FINALIZE)\n\n### 5.1 Rollback Procedure (if tests fail)\n```bash\ncp $SNAPSHOT_DIR/flywheel.ts.before apps/web/lib/flywheel.ts\ncp $SNAPSHOT_DIR/tldr-content.ts.before apps/web/lib/tldr-content.ts\necho \"Rolled back to pre-exploration state\"\n```\n\n### 5.2 Sync Changes\n```bash\nbr update bd-22gc --status done\nbr sync --flush-only\n```\n\n### 5.3 Final Verification\n- [ ] All tests pass\n- [ ] TypeScript compiles without errors\n- [ ] Safety mechanisms documented correctly\n- [ ] Synergies are reciprocal (slb->dcg and dcg->slb)\n- [ ] No broken links or references","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-26T20:01:23.124119983Z","created_by":"ubuntu","updated_at":"2026-01-27T03:14:24.854921039Z","closed_at":"2026-01-27T03:14:24.854835038Z","source_repo":".","compaction_level":0,"original_size":0} {"id":"bd-29fl","title":"acfs status: One-line health summary command","description":"## Overview\nAdd `acfs status` command that outputs a single-line health summary, perfect for shell prompts or quick checks.\n\n## Current Problem\n- `acfs doctor` is verbose and takes time to run\n- No quick way to check \"is everything OK?\"\n- Shell prompt integration requires parseable output\n\n## Proposed Output Format\n```bash\n$ acfs status\nACFS OK: 26 tools, last update 2h ago\n\n$ acfs status # with issues\nACFS WARN: 2 outdated tools, doctor recommended\n```\n\n## Exit Codes\n- 0: Everything healthy\n- 1: Warnings (outdated tools, minor issues)\n- 2: Errors (missing tools, broken state)\n\n## Implementation Details\n1. New file: `scripts/commands/status.sh`\n2. Quick checks only (no network calls by default):\n - State file exists and valid\n - Required tools present in PATH\n - Last update timestamp\n3. Optional `--check-updates` for network-based checks\n\n## Machine-Readable Mode\n```bash\n$ acfs status --json\n{\"status\":\"ok\",\"tools\":26,\"last_update\":\"2026-01-25T21:00:00Z\",\"warnings\":[]}\n```\n\n## Shell Prompt Integration\n```bash\n# Add to .bashrc\nacfs_status() { acfs status --short 2>/dev/null || echo \"?\"; }\nPS1='$(acfs_status) \\w $ '\n```\n\n## Test Plan\n- [ ] Test exit codes for all states\n- [ ] Test --json output is valid JSON\n- [ ] Test runs in < 100ms (no network)\n- [ ] Test with missing state file\n- [ ] Test with outdated state\n\n## Files to Create\n- scripts/commands/status.sh","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-25T23:01:26.052120972Z","created_by":"ubuntu","updated_at":"2026-01-26T22:41:34.694666041Z","closed_at":"2026-01-26T22:41:34.694647606Z","close_reason":"Implemented scripts/lib/status.sh with --json, --short, --check-updates modes. Updated acfs.zshrc routing and help text.","source_repo":".","compaction_level":0,"original_size":0,"dependencies":[{"issue_id":"bd-29fl","depends_on_id":"bd-3y1n","type":"blocks","created_at":"2026-01-25T23:03:25.805296607Z","created_by":"ubuntu"}]} +{"id":"bd-29u5z","title":"Fresh eyes review pass","status":"closed","priority":2,"issue_type":"task","created_at":"2026-02-04T05:54:34.433670424Z","created_by":"ubuntu","updated_at":"2026-02-04T05:54:47.096734647Z","closed_at":"2026-02-04T05:54:47.096717745Z","close_reason":"Completed","source_repo":".","compaction_level":0,"original_size":0} {"id":"bd-2a8k","title":"ACFS update should self-update first","description":"The acfs update command should update ACFS itself (git pull) BEFORE updating any other components. Currently no self-update happens.\n\nCritical because:\n1. Bug fixes in update.sh won't apply without manual git pull\n2. Security fixes in checksums.yaml won't apply\n3. New tools in manifest won't be discovered\n\nFix: Add update_acfs_self() as FIRST operation that does git fetch/pull and re-execs if update.sh changed.","status":"closed","priority":1,"issue_type":"bug","created_at":"2026-01-21T21:16:03.928848634Z","created_by":"ubuntu","updated_at":"2026-01-21T21:46:31.334103730Z","closed_at":"2026-01-21T21:46:31.334032095Z","close_reason":"Completed","source_repo":".","compaction_level":0,"original_size":0,"labels":["critical","self-update","update"]} {"id":"bd-2bg3","title":"Deep exploration: CAAM (Coding Agent Account Manager)","description":"## Goal\nPerform deep exploration of CAAM (Coding Agent Account Manager) and revise its description on the flywheel/TLDR pages with comprehensive testing.\n\n## Phase 0: Pre-flight Verification (CRITICAL)\n\n### 0.1 Tool Existence Check\n```bash\n# Verify CAAM installation\n[[ -d /dp/coding_agent_account_manager ]] && echo \"PASS: caam repo exists\" || { echo \"FAIL: caam repo missing\"; exit 1; }\ncommand -v caam &>/dev/null && echo \"PASS: caam command available\" || { echo \"FAIL: caam not in PATH\"; exit 1; }\n\n# Check supported CLI tool availability\ncommand -v claude &>/dev/null && echo \"INFO: claude CLI available\"\ncommand -v codex &>/dev/null && echo \"INFO: codex CLI available\" || echo \"INFO: codex not installed\"\n```\n\n### 0.2 Content Snapshot (BEFORE State)\n```bash\nSNAPSHOT_DIR=/tmp/caam-exploration-snapshots-$(date +%Y%m%d-%H%M%S)\nmkdir -p $SNAPSHOT_DIR\ncp apps/web/lib/flywheel.ts $SNAPSHOT_DIR/flywheel.ts.before\ncp apps/web/lib/tldr-content.ts $SNAPSHOT_DIR/tldr-content.ts.before\necho \"Snapshots saved to $SNAPSHOT_DIR\"\n```\n\n### 0.3 TypeScript Interface Reference\nContent must match FlywheelTool interface:\n- id, name, tagline, description, deepDescription\n- features[], cliCommands[], connectsTo[]\n- integrationLevel, category, status\n\n## Phase 1: Research (GATHER CONTEXT)\n\n### 1.1 Primary Documentation\n- `cat /dp/coding_agent_account_manager/README.md` - Read full README\n- Check for account configuration docs, supported profiles\n\n### 1.2 Code Investigation\n- Launch code investigation agent to understand:\n - Account storage mechanism (encrypted? plaintext?)\n - Switching implementation (sub-100ms claim)\n - CLI profiles supported (Claude, GPT, Gemini, Codex)\n - Rate limit detection strategy\n - Environment variable management\n - Config file location and format\n\n### 1.3 CLI Command Verification\n```bash\n# Verify each documented command works\ncaam --help 2>&1 | head -20\ncaam list --help 2>&1 | head -10\ncaam switch --help 2>&1 | head -10\n\n# Test actual functionality\ncaam list 2>&1 | head -10\n```\n\n### 1.4 Performance Claim Verification\n```bash\n# Verify sub-100ms switching claim\necho \"Testing switch timing...\"\ntime (caam switch test-profile 2>/dev/null || echo \"No test profile\") 2>&1\n```\n\n### 1.5 External Context Search\n- `/xf search 'caam OR account manager OR rate limit'` - Twitter archive\n- `cass search 'caam account switching' --robot --limit 10` - Past sessions\n\n### 1.6 Project State Review\n- Check beads in /dp/coding_agent_account_manager/.beads/\n- Review recent commits: `cd /dp/coding_agent_account_manager && git log --oneline -20`\n\n## Phase 2: Analysis (SYNTHESIZE UNDERSTANDING)\n\n### 2.1 Core Capabilities Verification\nDocument findings for each area:\n- [ ] Account storage format (file location, encryption)\n- [ ] Switching mechanism and actual timing\n- [ ] Supported CLI profiles (complete list)\n- [ ] Rate limit detection method\n- [ ] Environment management approach\n\n### 2.2 Synergy Verification\nCross-reference these tools actually integrate:\n- [ ] ntm - multi-agent account coordination\n- [ ] slb - coordinated account switching\n- [ ] mail - account status messaging\n\n### 2.3 Claim Verification\n```bash\n# Verify sub-100ms claim with timing\nSTART=$(date +%s%N)\ncaam list >/dev/null 2>&1\nEND=$(date +%s%N)\nELAPSED=$(( (END - START) / 1000000 ))\necho \"caam list took: ${ELAPSED}ms\"\n\n# Check config location\nls -la ~/.config/caam/ 2>/dev/null || echo \"Config location differs\"\n```\n\n## Phase 3: Revision (UPDATE DESCRIPTIONS)\n\n### 3.1 Update apps/web/lib/flywheel.ts\nUpdate caam entry with VERIFIED information:\n- `tagline`: Accurate one-liner (verify sub-100ms claim)\n- `description`: Account management capabilities\n- `deepDescription`: How switching actually works\n- `features`: Verified account operations\n- `cliCommands`: Only commands that actually work\n- `connectsTo`: Only verified integrations\n\n### 3.2 Update apps/web/lib/tldr-content.ts\nUpdate TldrFlywheelTool entry with:\n- `briefDescription`: Technical summary\n- `bulletPoints`: Verified capabilities\n- `synergyExamples`: Working integration examples\n\n## Phase 4: Testing (VERIFY CHANGES)\n\n### 4.1 TypeScript Compilation\n```bash\ncd apps/web && npx tsc --noEmit 2>&1 | head -20\n```\n\n### 4.2 Unit Tests\n```bash\n# Test caam entry structure\nnode -e \"\nconst { flywheelTools } = require('./lib/flywheel');\nconst caam = flywheelTools.find(t => t.id === 'caam');\nconsole.log('Testing caam entry...');\nconsole.assert(caam, 'caam entry exists');\nconsole.assert(caam.features?.length > 0, 'has features');\nconsole.assert(caam.cliCommands?.length > 0, 'has commands');\nconsole.log('All assertions passed');\n\"\n```\n\n### 4.3 E2E Test: Account Operations\n```bash\n#\\!/bin/bash\nset -euo pipefail\nLOG=/tmp/caam-e2e-$(date +%Y%m%d-%H%M%S).log\n\necho \"=== CAAM E2E Test ===\" | tee $LOG\necho \"Started: $(date)\" | tee -a $LOG\n\n# Test 1: List accounts\necho \"Test 1: List accounts...\" | tee -a $LOG\ncaam list 2>&1 | tee -a $LOG\n\n# Test 2: Current account\necho \"Test 2: Current account...\" | tee -a $LOG\ncaam current 2>&1 | tee -a $LOG || echo \"No current command\"\n\n# Test 3: Help for add\necho \"Test 3: Add help...\" | tee -a $LOG\ncaam add --help 2>&1 | head -5 | tee -a $LOG\n\necho \"=== All Tests Passed ===\" | tee -a $LOG\necho \"Log: $LOG\"\n```\n\n### 4.4 Content Diff Verification\n```bash\necho \"=== Changes Made ===\"\ndiff $SNAPSHOT_DIR/flywheel.ts.before apps/web/lib/flywheel.ts || true\ndiff $SNAPSHOT_DIR/tldr-content.ts.before apps/web/lib/tldr-content.ts || true\n```\n\n## Phase 5: Completion (FINALIZE)\n\n### 5.1 Rollback Procedure (if tests fail)\n```bash\ncp $SNAPSHOT_DIR/flywheel.ts.before apps/web/lib/flywheel.ts\ncp $SNAPSHOT_DIR/tldr-content.ts.before apps/web/lib/tldr-content.ts\necho \"Rolled back to pre-exploration state\"\n```\n\n### 5.2 Sync Changes\n```bash\nbr update bd-2bg3 --status done\nbr sync --flush-only\n```\n\n### 5.3 Final Verification\n- [ ] All tests pass\n- [ ] TypeScript compiles without errors\n- [ ] Performance claims verified (sub-100ms)\n- [ ] Content matches verified tool capabilities\n- [ ] No broken links or references","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-26T20:01:18.982295810Z","created_by":"ubuntu","updated_at":"2026-01-27T03:27:47.367564776Z","closed_at":"2026-01-27T03:27:47.367538427Z","close_reason":"CAAM deep exploration complete: verified 50+ commands, added project-profile associations, caam run automatic failover, pick command with fzf","source_repo":".","compaction_level":0,"original_size":0} {"id":"bd-2cz8","title":"Deep exploration: APR (Automated Plan Reviser Pro)","description":"## Goal\nPerform deep exploration of APR (Automated Plan Reviser Pro) and revise its description on the flywheel/TLDR pages with comprehensive testing.\n\n## Phase 0: Pre-flight Verification (CRITICAL)\n\n### 0.1 Tool Existence Check\n```bash\n# Verify APR installation\n[[ -d /dp/automated_plan_reviser_pro ]] && echo \"PASS: apr repo exists\" || { echo \"FAIL: apr repo missing\"; exit 1; }\ncommand -v apr &>/dev/null && echo \"PASS: apr command available\" || { echo \"FAIL: apr not in PATH\"; exit 1; }\n\n# Check for Claude Code integration\n[[ -f ~/.claude/settings.json ]] && echo \"INFO: Claude settings exist\" || echo \"INFO: No Claude settings\"\n```\n\n### 0.2 Content Snapshot (BEFORE State)\n```bash\nSNAPSHOT_DIR=/tmp/apr-exploration-snapshots-$(date +%Y%m%d-%H%M%S)\nmkdir -p $SNAPSHOT_DIR\ncp apps/web/lib/flywheel.ts $SNAPSHOT_DIR/flywheel.ts.before\ncp apps/web/lib/tldr-content.ts $SNAPSHOT_DIR/tldr-content.ts.before\necho \"Snapshots saved to $SNAPSHOT_DIR\"\n```\n\n### 0.3 TypeScript Interface Reference\nContent must match FlywheelTool interface:\n- id, name, tagline, description, deepDescription\n- features[], cliCommands[], connectsTo[]\n- integrationLevel, category, status\n\n## Phase 1: Research (GATHER CONTEXT)\n\n### 1.1 Primary Documentation\n- `cat /dp/automated_plan_reviser_pro/README.md` - Read full README\n- Check for plan format docs, revision algorithm\n\n### 1.2 Code Investigation\n- Launch code investigation agent to understand:\n - Plan parsing mechanism\n - Revision algorithm (how it improves plans)\n - Integration with Claude Code planning\n - Diff generation for plan changes\n - Checkpoint/rollback support\n\n### 1.3 CLI Command Verification\n```bash\n# Verify each documented command works\napr --help 2>&1 | head -20\napr revise --help 2>&1 | head -10\napr diff --help 2>&1 | head -10\n\n# Test actual functionality\napr status 2>&1 | head -10 || echo \"No status command\"\n```\n\n### 1.4 External Context Search\n- `/xf search 'apr OR plan reviser OR automated planning'` - Twitter archive\n- `cass search 'apr plan revision' --robot --limit 10` - Past sessions\n\n### 1.5 Project State Review\n- Check beads in /dp/automated_plan_reviser_pro/.beads/\n- Review recent commits: `cd /dp/automated_plan_reviser_pro && git log --oneline -20`\n\n## Phase 2: Analysis (SYNTHESIZE UNDERSTANDING)\n\n### 2.1 Core Capabilities Verification\nDocument findings for each area:\n- [ ] Plan format specification\n- [ ] Revision algorithm details\n- [ ] Diff generation format\n- [ ] Checkpoint mechanism\n- [ ] Claude Code integration\n\n### 2.2 Synergy Verification\nCross-reference these tools actually integrate:\n- [ ] br (beads) - plan tracking\n- [ ] mail - plan review coordination\n- [ ] ntm - multi-agent planning\n\n### 2.3 Format Verification\n```bash\n# Check plan format examples\nfind /dp/automated_plan_reviser_pro -name \"*.plan\" -o -name \"example*.md\" 2>/dev/null | head -3 | xargs head -20\n\n# Check revision output format\napr revise --dry-run /tmp/test.plan 2>&1 | head -20 || echo \"No dry-run option\"\n```\n\n## Phase 3: Revision (UPDATE DESCRIPTIONS)\n\n### 3.1 Update apps/web/lib/flywheel.ts\nUpdate apr entry with VERIFIED information:\n- `tagline`: Automated plan improvement\n- `description`: Plan parsing and revision\n- `deepDescription`: How revision algorithm works\n- `features`: Verified capabilities\n- `cliCommands`: Only commands that actually work\n- `connectsTo`: Only verified integrations\n\n### 3.2 Update apps/web/lib/tldr-content.ts\nUpdate TldrFlywheelTool entry with:\n- `briefDescription`: Technical summary\n- `bulletPoints`: Verified capabilities\n- `synergyExamples`: Working integration examples\n\n## Phase 4: Testing (VERIFY CHANGES)\n\n### 4.1 TypeScript Compilation\n```bash\ncd apps/web && npx tsc --noEmit 2>&1 | head -20\n```\n\n### 4.2 Unit Tests\n```bash\n# Test apr entry structure\nnode -e \"\nconst { flywheelTools } = require('./lib/flywheel');\nconst apr = flywheelTools.find(t => t.id === 'apr');\nconsole.log('Testing apr entry...');\nconsole.assert(apr, 'apr entry exists');\nconsole.assert(apr.features?.length > 0, 'has features');\nconsole.assert(apr.cliCommands?.length > 0, 'has commands');\nconsole.log('All assertions passed');\n\"\n```\n\n### 4.3 E2E Test: Plan Revision\n```bash\n#\\!/bin/bash\nset -euo pipefail\nLOG=/tmp/apr-e2e-$(date +%Y%m%d-%H%M%S).log\n\necho \"=== APR E2E Test ===\" | tee $LOG\necho \"Started: $(date)\" | tee -a $LOG\n\n# Test 1: Help\necho \"Test 1: Help...\" | tee -a $LOG\napr --help 2>&1 | head -10 | tee -a $LOG\n\n# Test 2: Revise help\necho \"Test 2: Revise help...\" | tee -a $LOG\napr revise --help 2>&1 | head -5 | tee -a $LOG\n\n# Test 3: Diff help\necho \"Test 3: Diff help...\" | tee -a $LOG\napr diff --help 2>&1 | head -5 | tee -a $LOG || echo \"No diff command\"\n\necho \"=== All Tests Passed ===\" | tee -a $LOG\necho \"Log: $LOG\"\n```\n\n### 4.4 Content Diff Verification\n```bash\necho \"=== Changes Made ===\"\ndiff $SNAPSHOT_DIR/flywheel.ts.before apps/web/lib/flywheel.ts || true\ndiff $SNAPSHOT_DIR/tldr-content.ts.before apps/web/lib/tldr-content.ts || true\n```\n\n## Phase 5: Completion (FINALIZE)\n\n### 5.1 Rollback Procedure (if tests fail)\n```bash\ncp $SNAPSHOT_DIR/flywheel.ts.before apps/web/lib/flywheel.ts\ncp $SNAPSHOT_DIR/tldr-content.ts.before apps/web/lib/tldr-content.ts\necho \"Rolled back to pre-exploration state\"\n```\n\n### 5.2 Sync Changes\n```bash\nbr update bd-2cz8 --status done\nbr sync --flush-only\n```\n\n### 5.3 Final Verification\n- [ ] All tests pass\n- [ ] TypeScript compiles without errors\n- [ ] Plan format documented correctly\n- [ ] No broken links or references","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-26T20:02:24.581011487Z","created_by":"ubuntu","updated_at":"2026-01-27T03:20:12.144878838Z","closed_at":"2026-01-27T03:20:12.144848431Z","close_reason":"Deep exploration complete. Updated flywheel.ts and tldr-content.ts with verified APR information: iterative convergence pattern (architecture→refinement→polish), document bundling, convergence analytics with weighted scoring, pre-flight validation, auto-retry with backoff, session management, robot mode JSON API with semantic error codes, Claude Code integration. Fixed incorrect CLI commands (apr run not apr refine) and install command (removed non-existent --easy-mode). Build passes.","source_repo":".","compaction_level":0,"original_size":0} @@ -951,18 +953,37 @@ {"id":"bd-33vh.8","title":"End-to-end test: Fresh install + doctor confirms DCG, no git_safety_guard warnings","description":"## Task\n\nRun a complete end-to-end test to verify complete git_safety_guard removal with DETAILED LOGGING.\n\n## Test Script Location\n\nCreate: tests/e2e/test_git_safety_guard_removal.sh\n\n## Logging Requirements\n\nALL tests MUST:\n1. Log to timestamped file: /tmp/git_safety_guard_removal_$(date +%Y%m%d_%H%M%S).log\n2. Structured format: [TIMESTAMP] [LEVEL] [TEST_NAME] Message\n3. JSON results file\n\n## Test Environment\n\nUse Docker-based test harness: ./tests/vm/test_install_ubuntu.sh\n\n## Test Cases\n\n### Test Case 1: Fresh Install Verification\n```bash\n# After fresh install in Docker\nls -la ~/.acfs/claude/ # Should only show settings.json\nls -la ~/.acfs/claude/hooks/ 2>&1 # Should fail (directory doesn't exist)\nls -la ~/.claude/hooks/ 2>&1 # Should fail or be empty\n```\n\n### Test Case 2: Doctor Output Verification\n```bash\nacfs doctor 2>&1 | tee doctor_output.txt\n\n# Should NOT contain\n! grep -i 'git.safety.guard' doctor_output.txt\n\n# Should contain DCG check\ngrep -i 'DCG' doctor_output.txt\n```\n\n### Test Case 3: Install Log Verification\n- Should see: 'Installing DCG' or similar\n- Should NOT see: 'Git Safety Guard'\n\n### Test Case 4: Settings.json Verification\n```bash\ncat ~/.claude/settings.json 2>/dev/null\n# Should NOT contain 'git_safety_guard'\n```\n\n### Test Case 5: Codebase Audit\n```bash\n# No git_safety_guard in codebase\n! grep -ri 'git_safety_guard' --include='*.sh' --include='*.ts' --include='*.md' .\n```\n\n## Expected Results Table\n\n| Check | Expected |\n|-------|----------|\n| ~/.acfs/claude/hooks/ exists | NO |\n| ~/.claude/hooks/git_safety_guard.py exists | NO |\n| acfs doctor mentions 'Git safety guard' | NO |\n| acfs doctor mentions 'DCG' | YES |\n| install.sh log mentions 'Git Safety Guard' | NO |\n| install.sh log mentions 'DCG' | YES |\n\n## Acceptance Criteria\n\n1. Docker-based fresh install completes successfully\n2. No git_safety_guard warnings in doctor output\n3. DCG check present and passes\n4. Install logs use 'DCG' terminology\n5. No stale artifacts created\n6. Detailed timestamped log file generated\n7. JSON results file with pass/fail summary","status":"closed","priority":2,"issue_type":"task","estimated_minutes":45,"created_at":"2026-01-24T20:39:16.986042720Z","created_by":"ubuntu","updated_at":"2026-01-27T00:53:52.224631333Z","closed_at":"2026-01-27T00:53:52.224494725Z","close_reason":"Created E2E test for git_safety_guard removal with Docker integration","source_repo":".","compaction_level":0,"original_size":0,"labels":["e2e","qa","testing"],"dependencies":[{"issue_id":"bd-33vh.8","depends_on_id":"bd-33vh","type":"parent-child","created_at":"2026-01-24T20:39:16.986042720Z","created_by":"ubuntu"},{"issue_id":"bd-33vh.8","depends_on_id":"bd-33vh.1","type":"blocks","created_at":"2026-01-24T20:40:06.307562642Z","created_by":"ubuntu"},{"issue_id":"bd-33vh.8","depends_on_id":"bd-33vh.4","type":"blocks","created_at":"2026-01-24T20:40:09.087861241Z","created_by":"ubuntu"},{"issue_id":"bd-33vh.8","depends_on_id":"bd-33vh.6","type":"blocks","created_at":"2026-01-24T20:40:11.715678744Z","created_by":"ubuntu"}]} {"id":"bd-33vh.9","title":"Document migration path for existing users in CHANGELOG or release notes","description":"## Task Overview\n\nDocument the git_safety_guard → DCG migration for users who may be upgrading from older ACFS installations.\n\n## Target Audience\n\nUsers who installed ACFS before January 11, 2026 (commit f1fd501) and may:\n1. See 'Git safety guard' warnings in acfs doctor\n2. Have stale git_safety_guard.py files\n3. Be confused about the difference between the old and new systems\n\n## Documentation Locations\n\n### Option 1: Add to CHANGELOG.md (if exists)\n```markdown\n## [0.x.x] - 2026-01-xx\n\n### Changed\n- **BREAKING**: git_safety_guard replaced by DCG (Destructive Command Guard)\n\n### Migration\nIf you see 'Git safety guard' warnings after updating:\n1. Run `acfs update` to get the latest scripts\n2. Remove legacy files: `rm -f ~/.acfs/claude/hooks/git_safety_guard.py`\n3. Install DCG: `dcg install`\n4. Verify: `acfs doctor` should show DCG check, not git_safety_guard\n```\n\n### Option 2: Add migration section to README.md\n```markdown\n## Upgrading from Pre-January 2026 Installations\n\nIf you installed ACFS before January 11, 2026, you may have the old git_safety_guard system.\nThe replacement is DCG (Destructive Command Guard).\n\n### Symptoms of Old Installation\n- `acfs doctor` shows 'Git safety guard' warning\n- File exists: ~/.acfs/claude/hooks/git_safety_guard.py\n\n### Migration Steps\n1. Update ACFS: `acfs update --force`\n2. Install DCG: `dcg install`\n3. Verify: `acfs doctor` should show only DCG\n\nThe update process automatically cleans up legacy git_safety_guard files.\n```\n\n### Option 3: In-tool messaging (services-setup.sh)\nWhen user runs `acfs services-setup`, if legacy files detected:\n```\n⚠️ Legacy git_safety_guard detected\n This has been replaced by DCG (Destructive Command Guard).\n \n Cleaning up old files...\n ✓ Removed ~/.acfs/claude/hooks/git_safety_guard.py\n \n To configure DCG, select 'DCG' from the menu or run: dcg install\n```\n\n## Recommended Approach\n\nCombine Options 1 and 3:\n1. Document in CHANGELOG for release notes\n2. Add proactive cleanup messaging in services-setup.sh\n\n## Content Requirements\n\nDocumentation should explain:\n1. **What changed**: git_safety_guard.py removed, DCG introduced\n2. **Why**: Better performance (Rust vs Python), modular packs, dedicated maintenance\n3. **How to migrate**: Run acfs update, install dcg\n4. **How to verify**: acfs doctor shows DCG, no git_safety_guard warnings\n5. **Timeline**: When this changed (January 11, 2026)\n\n## Notes\n\n- Keep migration docs concise - most users won't need them\n- Focus on actionable steps, not history\n- Link to DCG section in README for full documentation","status":"closed","priority":3,"issue_type":"task","estimated_minutes":15,"created_at":"2026-01-24T20:39:38.244493576Z","created_by":"ubuntu","updated_at":"2026-01-27T00:33:17.644632289Z","closed_at":"2026-01-27T00:33:17.643021004Z","source_repo":".","compaction_level":0,"original_size":0,"labels":["documentation","migration","release"],"dependencies":[{"issue_id":"bd-33vh.9","depends_on_id":"bd-33vh","type":"parent-child","created_at":"2026-01-24T20:39:38.244493576Z","created_by":"ubuntu"},{"issue_id":"bd-33vh.9","depends_on_id":"bd-33vh.4","type":"blocks","created_at":"2026-01-24T20:40:03.529936278Z","created_by":"ubuntu"}]} {"id":"bd-34mf","title":"Optimize plan/list/print/dry-run fast paths","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-21T19:00:29.646180400Z","created_by":"ubuntu","updated_at":"2026-01-21T19:21:27.575225697Z","closed_at":"2026-01-21T19:21:27.575181604Z","close_reason":"Fast path optimization already implemented: source_generated_installers is skipped when running --list-modules, --print-plan, --dry-run, or --print modes. This avoids unnecessary script sourcing and initialization for operations that only need to display information.","source_repo":".","compaction_level":0,"original_size":0,"dependencies":[{"issue_id":"bd-34mf","depends_on_id":"bd-2z32","type":"discovered-from","created_at":"2026-01-21T19:00:29.676141538Z","created_by":"ubuntu"}]} +{"id":"bd-38l7j","title":"Regenerate manifest_index.sh to fix SHA256 drift","description":"scripts/generated/manifest_index.sh is out of sync with acfs.manifest.yaml. The manifest was modified in commits 44852195 (tru->toon rename) and 0a64aa63 (revert toon->tru) but manifest_index.sh was never regenerated.\n\nCurrent state:\n- manifest_index.sh line 9 has stale hash d7db51f0... (old)\n- manifest_index.sh line 10 has DUPLICATE ACFS_MANIFEST_SHA256 with hash 3f916ff3... (also stale)\n- Actual manifest SHA256 at HEAD is 3183c594... (or newer if working dir changes committed)\n- Bootstrap validation: grep ACFS_MANIFEST_SHA256 | head -n 1 picks stale value -> validation failure\n- Users pinning ACFS_REF get mismatched hashes between tag and HEAD\n\nREGENERATION PROCESS (well-documented, automated):\n cd packages/manifest && bun run generate\n This runs packages/manifest/src/generate.ts (1723 lines) which:\n - Reads acfs.manifest.yaml\n - Computes SHA256 via computeManifestSha256() (line 469)\n - Outputs to scripts/generated/ via generateManifestIndex() (line 855)\n - Deterministic output: same input always produces same output\n\nFIX:\n1. Run: cd packages/manifest && bun run generate\n2. Verify: scripts/generated/manifest_index.sh has exactly ONE ACFS_MANIFEST_SHA256 line\n3. Verify: SHA256 value matches sha256sum acfs.manifest.yaml\n4. Verify: bootstrap validation passes (test with curl | bash flow)\n\nPREVENTIVE MEASURES (add CI check to prevent future drift):\n5. Add to .github/workflows/installer.yml (or new manifest-check.yml):\n - name: Verify manifest_index.sh is up to date\n run: |\n cd packages/manifest && bun run generate --diff\n if \\! git diff --quiet scripts/generated/manifest_index.sh; then\n echo \"ERROR: manifest_index.sh is out of sync with acfs.manifest.yaml\"\n echo \"Run: cd packages/manifest && bun run generate\"\n exit 1\n fi\n\n6. Add duplicate-line check to scripts/hooks/pre-commit:\n DUPLICATE_SHA=$(grep -c \"^ACFS_MANIFEST_SHA256=\" scripts/generated/manifest_index.sh)\n if [[ \"$DUPLICATE_SHA\" -gt 1 ]]; then\n echo \"ERROR: manifest_index.sh has $DUPLICATE_SHA ACFS_MANIFEST_SHA256 lines (expected 1)\"\n exit 1\n fi\n\nTESTS:\n\nUnit Tests (tests/unit/test_manifest_sha256.sh):\n- test_single_sha256_line: grep -c ACFS_MANIFEST_SHA256 returns exactly 1\n- test_sha256_matches_file: SHA256 in manifest_index.sh matches sha256sum acfs.manifest.yaml\n- test_no_conflict_markers: no <<<< ==== >>>> markers in generated files\n- test_regeneration_idempotent: running bun run generate twice produces identical output\n\nIntegration Tests:\n- test_bootstrap_validation_passes: source manifest_index.sh then validate against actual file\n- test_pinned_ref_validation: simulate ACFS_REF=v0.6.0 install and verify SHA check\n\nE2E Tests (in CI canary or test_runner.sh):\n- test_curl_bash_install_validates_manifest: full curl | bash install validates manifest SHA256\n- test_offline_doctor_checks_manifest: acfs doctor verifies manifest integrity\n\nGitHub issue: #116","status":"open","priority":1,"issue_type":"bug","created_at":"2026-02-07T03:08:37.075159984Z","created_by":"ubuntu","updated_at":"2026-02-07T03:19:30.745290495Z","source_repo":".","compaction_level":0,"original_size":0} {"id":"bd-39ye","title":"NO_COLOR environment variable support","description":"## Overview\nRespect the NO_COLOR environment variable across all ACFS scripts per https://no-color.org/ standard.\n\n## Current Problem\n- Scripts use colors unconditionally\n- Users with accessibility needs can't disable colors\n- Piped output includes ANSI codes\n- Some terminals render colors poorly\n\n## NO_COLOR Standard\n- If NO_COLOR env var is set (any value), disable colors\n- Also disable for non-TTY output (pipes, redirects)\n- Simple, widely adopted convention\n\n## Implementation Details\n1. Create color helper functions in logging.sh\n2. Check NO_COLOR and TTY status once at startup\n3. All color output goes through these helpers\n\n## Color Helper Functions\n```bash\n# scripts/lib/colors.sh\n_init_colors() {\n if [[ -n \"${NO_COLOR:-}\" ]] || [[ ! -t 1 ]]; then\n RED='' GREEN='' YELLOW='' BLUE='' RESET=''\n else\n RED='\\033[0;31m' GREEN='\\033[0;32m'\n YELLOW='\\033[0;33m' BLUE='\\033[0;34m' RESET='\\033[0m'\n fi\n}\n\ncolor_print() {\n local color=\"$1\" msg=\"$2\"\n printf '%b%s%b\\n' \"${!color}\" \"$msg\" \"$RESET\"\n}\n```\n\n## Files to Audit\n- scripts/lib/logging.sh (main color usage)\n- scripts/lib/tui.sh (interactive elements)\n- scripts/install.sh (progress output)\n- All scripts that use printf with ANSI codes\n\n## Test Plan\n- [ ] Test NO_COLOR=1 disables all colors\n- [ ] Test piped output has no ANSI codes\n- [ ] Test colors work normally when NO_COLOR unset\n- [ ] Grep for raw ANSI codes to ensure none slip through\n\n## Files to Modify\n- scripts/lib/logging.sh (add color helpers)\n- All files using hardcoded ANSI codes","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-25T23:01:49.345301724Z","created_by":"ubuntu","updated_at":"2026-01-27T04:01:25.739562837Z","closed_at":"2026-01-27T04:01:25.739539473Z","close_reason":"done","source_repo":".","compaction_level":0,"original_size":0,"dependencies":[{"issue_id":"bd-39ye","depends_on_id":"bd-3y1n","type":"blocks","created_at":"2026-01-25T23:04:01.194662910Z","created_by":"ubuntu"}]} {"id":"bd-3aa6","title":"Prevent gcloud 'bv' from ever shadowing beads_viewer","description":"Summary\n- gcloud SDK installs a `bv` binary in `/home/ubuntu/google-cloud-sdk/bin`.\n- The SDK’s `path.zsh.inc` is sourced in `~/.zshrc.local`, so PATH can include gcloud’s `bv`.\n- User requirement: **gcloud’s `bv` must never, under any circumstances, intercept/be invoked instead of beads_viewer `bv`.**\n\nImpact\n- High risk of running the wrong `bv` in interactive shells, non-interactive shells, CI, or cron jobs.\n- Mis-executed `bv` can break bead workflows and cause confusion during incident response.\n\nEvidence (current environment)\n- `which -a bv` shows multiple `bv` binaries including gcloud’s:\n - `/home/ubuntu/google-cloud-sdk/bin/bv`\n - `/home/ubuntu/.local/bin/bv`\n - `/home/ubuntu/.bun/bin/bv`\n - `/home/ubuntu/go/bin/bv`\n- PATH is mutated by gcloud SDK via `path.zsh.inc` (sourced in `~/.zshrc.local`).\n\nRoot Cause\n- gcloud SDK ships a `bv` command (BigQuery-related) that collides with beads_viewer’s `bv`.\n- PATH ordering is not explicitly pinned to prefer user `bv` binaries.\n\nProposed Remediation (must enforce precedence)\n1) Prepend user bins ahead of gcloud in shell init:\n - `~/bin`, `~/.local/bin`, `~/.bun/bin`, `~/go/bin` must come before the SDK.\n2) Add an explicit `bv` shim at `~/bin/bv` that delegates to the preferred beads_viewer binary.\n3) Add a hard alias in shell init to force `bv` -> `~/.local/bin/bv` (or preferred).\n4) Add a health check command (or script) that fails if `command -v bv` resolves to gcloud.\n\nAcceptance Criteria\n- `command -v bv` resolves to user beads_viewer (not gcloud) in:\n - interactive shells\n - non-interactive shells (`zsh -lc`, cron)\n- `which -a bv` shows gcloud’s `bv` only after user paths.\n- Running `bv --version` matches beads_viewer’s version, not gcloud’s.\n\nNotes\n- The collision warning appears after `gcloud components update`.\n- This is a safety/operations issue, not a GA4 issue.","status":"closed","priority":1,"issue_type":"bug","created_at":"2026-01-25T00:42:06.371685930Z","created_by":"ubuntu","updated_at":"2026-01-26T23:22:24.883957326Z","closed_at":"2026-01-26T23:22:24.883935966Z","close_reason":"Implemented bv() protection function in acfs.zshrc that bypasses gcloud bv, added ~/bin to PATH, and enhanced doctor.sh to detect gcloud shadowing. Shellcheck passes.","source_repo":".","compaction_level":0,"original_size":0} +{"id":"bd-3co7k","title":"World-Class UI/UX Polish","description":"# World-Class UI/UX Polish Initiative\n\n## Overview\nElevate the ACFS web application from B+ (78/100) to A+ (95/100) grade UI/UX quality, matching Stripe-level polish and sophistication.\n\n## Background & Context\nThe web app (apps/web/) is a Next.js 16 application using:\n- Tailwind CSS for styling\n- Framer Motion for animations \n- shadcn/ui component patterns\n- OKLCH color space for perceptually uniform colors\n\n**Current State (After Initial Session):**\n- ✅ Touch targets meet Apple HIG (44px minimum)\n- ✅ Glassmorphism refined with hover states (blur 16px → 20px on hover)\n- ✅ Card shadows use layered elevation (Stripe-style)\n- ✅ Reduced motion support (useReducedMotion throughout)\n- ✅ EmptyState component created with staggered animations\n- ✅ 4-column grids on widescreen (xl:grid-cols-4)\n- ✅ CodeBlock with line hover highlighting\n- ✅ Gradient button variants added\n- ✅ Z-index normalized to standard scale\n\n**Remaining Work:**\n1. Design System Foundation (typography, animation variants)\n2. Core Components (BottomSheet, FormField, Alerts)\n3. Page Enhancements (scroll reveals, empty states, swipe)\n4. Mobile Experience (bottom sheets, navigation)\n\n## Goals\n1. **Desktop Excellence**: Micro-interactions that feel delightful\n2. **Mobile Excellence**: Native-feeling gestures and thumb-friendly layouts\n3. **Visual Sophistication**: Depth, layering, attention to detail\n4. **Performance**: Smooth 60fps animations, no jank\n5. **Accessibility**: WCAG AA compliance maintained\n\n## Success Criteria\n- Every interaction feels intentional and crafted\n- Mobile feels like a native app, not responsive website\n- Loading states are elegant, not just functional\n- Empty states are delightful, not disappointing\n\n## Key Files\n- apps/web/components/ui/ - Core UI components\n- apps/web/components/motion/ - Animation system\n- apps/web/lib/design-tokens.ts - Design tokens\n- apps/web/app/globals.css - Global styles\n- apps/web/lib/hooks/useScrollReveal.ts - Scroll animations\n\n## Reference Standards\n- Stripe Dashboard, Linear App, Vercel Dashboard\n- Apple Human Interface Guidelines","status":"closed","priority":1,"issue_type":"feature","created_at":"2026-02-03T19:53:00.455976257Z","created_by":"ubuntu","updated_at":"2026-02-04T04:55:08.197078236Z","closed_at":"2026-02-04T04:55:08.197057658Z","close_reason":"All sub-tasks complete","source_repo":".","compaction_level":0,"original_size":0,"labels":["epic","polish","ui","ux"],"comments":[{"id":53,"issue_id":"bd-3co7k","author":"Dicklesworthstone","text":"## Testing Strategy Overview\n\n### Unit Testing Approach\n- Each new component gets `__tests__/.test.tsx`\n- Tests verify: render, props handling, state transitions, ARIA attributes\n- Use Jest + React Testing Library\n- Mock framer-motion for unit tests when needed\n\n### E2E Testing Approach\n- Each feature gets `e2e/.spec.ts`\n- Tests include detailed `console.log('[E2E]...')` logging\n- Test reduced motion with `page.emulateMedia({ reducedMotion: 'reduce' })`\n- Test mobile with `page.setViewportSize({ width: 375, height: 812 })`\n- Test touch gestures with `page.mouse` swipe simulation\n\n### Test File Locations\n```\napps/web/\n├── components/\n│ ├── ui/__tests__/\n│ │ ├── bottom-sheet.test.tsx\n│ │ ├── form-field.test.tsx\n│ │ └── typography.test.tsx\n│ └── motion/__tests__/\n│ └── variants.test.ts\n├── lib/hooks/__tests__/\n│ ├── useScrollReveal.test.ts\n│ └── useSwipeScroll.test.ts\n└── e2e/\n ├── typography.spec.ts\n ├── animations.spec.ts\n ├── bottom-sheet.spec.ts\n ├── form-field.spec.ts\n ├── alert-card.spec.ts\n ├── button-loading.spec.ts\n ├── scroll-reveal.spec.ts\n ├── empty-states.spec.ts\n ├── swipe-scroll.spec.ts\n ├── jargon-mobile.spec.ts\n └── mobile-navigation.spec.ts\n```\n\n### Verification Commands\n```bash\n# Run unit tests\npnpm --filter @acfs/web test\n\n# Run E2E tests\npnpm --filter @acfs/web e2e\n\n# Run specific E2E test with logging\npnpm --filter @acfs/web e2e -- --grep \"BottomSheet\"\n```\n","created_at":"2026-02-03T20:11:54Z"}]} +{"id":"bd-3co7k.1","title":"Design System Foundation","description":"# Design System Foundation\n\n## Purpose\nEstablish the foundational design system improvements that other UI work depends on.\nThese changes affect multiple components and pages, so they must be done first.\n\n## Why This Matters\n- Typography scale affects all text rendering site-wide\n- Animation variants are imported by every animated component\n- Getting these right first prevents inconsistencies later\n\n## Scope\n1. Typography scale enhancement (add 6xl tier)\n2. Animation variants expansion in motion module\n\n## Files Affected\n- apps/web/app/globals.css (typography variables)\n- apps/web/components/motion/index.tsx (animation presets)\n- apps/web/lib/design-tokens.ts (token definitions)\n\n## Dependencies\nNone - this is foundational work.\n\n## Acceptance Criteria\n- Typography scale has 6xl tier with proper tracking/leading\n- Motion module exports additional easing variants\n- All changes documented in code comments","status":"closed","priority":1,"issue_type":"feature","created_at":"2026-02-03T19:53:09.969044715Z","created_by":"ubuntu","updated_at":"2026-02-03T20:20:58.006509187Z","closed_at":"2026-02-03T20:20:58.006489790Z","close_reason":"Both child tasks completed: Typography Scale (1.1) and Animation Variants (1.2)","source_repo":".","compaction_level":0,"original_size":0,"labels":["design-system","foundation"],"dependencies":[{"issue_id":"bd-3co7k.1","depends_on_id":"bd-3co7k","type":"parent-child","created_at":"2026-02-03T19:53:09.969044715Z","created_by":"ubuntu"}]} +{"id":"bd-3co7k.1.1","title":"Typography Scale Enhancement","description":"# Typography Scale Enhancement\n\n## Problem Statement\nCurrent typography scale tops out at 3xl (clamp to 3rem). For hero sections and \nlarge displays on widescreen, we need a 6xl tier that can scale up to 6rem while\nmaintaining proper letter-spacing and line-height.\n\n## Background\nStripe and Linear use dramatic typography contrast in hero sections. Our current\nscale doesn't allow for this level of visual impact on large screens.\n\n**Current Scale (from globals.css):**\n```css\n--text-3xl: clamp(1.875rem, 1.5rem + 1.5vw, 3rem);\n```\n\n**Desired Addition:**\n```css\n--text-6xl: clamp(3.5rem, 3rem + 3vw, 6rem);\n--tracking-6xl: -0.04em;\n--leading-6xl: 1;\n```\n\n## Implementation Details\n\n### Step 1: Add CSS Variables (globals.css)\nAdd to the fluid typography section (~lines 120-128):\n```css\n/* Extra large display text for hero sections */\n--text-5xl: clamp(2.5rem, 2rem + 2.5vw, 4.5rem);\n--text-6xl: clamp(3.5rem, 3rem + 3vw, 6rem);\n```\n\n### Step 2: Add Letter-Spacing Variables\nLarge text needs tighter tracking for visual balance:\n```css\n--tracking-5xl: -0.03em;\n--tracking-6xl: -0.04em;\n```\n\n### Step 3: Add Line-Height Variables\nDisplay text needs tighter leading:\n```css\n--leading-5xl: 1.1;\n--leading-6xl: 1;\n```\n\n### Step 4: Create Utility Classes\nAdd to Tailwind config or globals.css:\n```css\n.text-display-5xl {\n font-size: var(--text-5xl);\n letter-spacing: var(--tracking-5xl);\n line-height: var(--leading-5xl);\n}\n\n.text-display-6xl {\n font-size: var(--text-6xl);\n letter-spacing: var(--tracking-6xl);\n line-height: var(--leading-6xl);\n}\n```\n\n### Step 5: Update design-tokens.ts\nExport these values for use in JS if needed:\n```typescript\nexport const typography = {\n display: {\n '5xl': 'clamp(2.5rem, 2rem + 2.5vw, 4.5rem)',\n '6xl': 'clamp(3.5rem, 3rem + 3vw, 6rem)',\n },\n tracking: {\n '5xl': '-0.03em',\n '6xl': '-0.04em',\n },\n};\n```\n\n## Testing\n- View hero sections at 1920px, 2560px, and 3840px widths\n- Verify text scales smoothly without jumps\n- Check that tracking looks balanced at all sizes\n\n## Files to Modify\n- apps/web/app/globals.css (lines ~120-140)\n- apps/web/lib/design-tokens.ts (typography section)\n\n## Acceptance Criteria\n- [ ] 5xl and 6xl font size variables defined\n- [ ] Corresponding tracking variables defined\n- [ ] Corresponding leading variables defined\n- [ ] Utility classes created\n- [ ] Design tokens updated\n- [ ] No visual regressions on existing pages","status":"closed","priority":2,"issue_type":"task","assignee":"ubuntu","estimated_minutes":45,"created_at":"2026-02-03T19:53:29.124313366Z","created_by":"ubuntu","updated_at":"2026-02-03T20:19:29.223502664Z","closed_at":"2026-02-03T20:19:29.223484781Z","close_reason":"Added text-6xl, leading-6xl, tracking-6xl CSS variables and text-display-5xl/6xl utility classes in globals.css. Added displayTypography tokens to design-tokens.ts.","source_repo":".","compaction_level":0,"original_size":0,"labels":["css","design-tokens","typography"],"dependencies":[{"issue_id":"bd-3co7k.1.1","depends_on_id":"bd-3co7k.1","type":"parent-child","created_at":"2026-02-03T19:53:29.124313366Z","created_by":"ubuntu"}],"comments":[{"id":42,"issue_id":"bd-3co7k.1.1","author":"Dicklesworthstone","text":"## Testing Requirements\n\n### Unit Tests\nCreate: `apps/web/components/ui/__tests__/typography.test.tsx`\n\n```typescript\nimport { render } from '@testing-library/react';\n\ndescribe('Typography CSS Variables', () => {\n test('5xl/6xl font sizes scale correctly at breakpoints', async () => {\n // Test that clamp() values work across viewport sizes\n });\n \n test('tracking values are negative for large text', () => {\n // Verify --tracking-5xl and --tracking-6xl are negative\n });\n});\n```\n\n### E2E Tests\nCreate: `apps/web/e2e/typography.spec.ts`\n\n```typescript\nimport { test, expect } from '@playwright/test';\n\ntest.describe('Typography Scale', () => {\n test('hero text scales at breakpoints', async ({ page }) => {\n console.log('[E2E] Testing typography at 2560px');\n await page.setViewportSize({ width: 2560, height: 1440 });\n await page.goto('/');\n // Verify hero uses new 5xl/6xl classes\n });\n});\n```\n","created_at":"2026-02-03T20:04:11Z"}]} +{"id":"bd-3co7k.1.2","title":"Animation Variants Expansion","description":"# Animation Variants Expansion\n\n## Problem Statement\nThe current motion module (apps/web/components/motion/index.tsx) has good spring \npresets but lacks:\n1. Scroll-reveal specific variants\n2. Stagger container variants for different use cases\n3. Entrance animations for modals/sheets\n\n## Background\nStripe uses subtle, purposeful animations that feel expensive. Our current set\ncovers basics but we need more nuanced options for specific UI patterns.\n\n**Current Exports:**\n- springs: smooth, snappy, gentle, quick\n- easings: out, in, inOut\n- fadeUp, fadeScale, slideLeft, slideRight\n- staggerContainer, staggerFast, staggerSlow\n- buttonMotion, cardMotion, listItemMotion\n\n**Needed Additions:**\n- Modal/sheet entrance variants\n- Scroll reveal with blur effect\n- Scale-up entrance for badges/pills\n- Stagger variants with different delays\n\n## Implementation Details\n\n### Step 1: Add Modal Entrance Variants\n```typescript\n/** Modal entrance - scale and fade from center */\nexport const modalEntrance: Variants = {\n hidden: {\n opacity: 0,\n scale: 0.95,\n y: 10,\n },\n visible: {\n opacity: 1,\n scale: 1,\n y: 0,\n transition: springs.smooth,\n },\n exit: {\n opacity: 0,\n scale: 0.98,\n y: 5,\n transition: { duration: 0.15 },\n },\n};\n\n/** Bottom sheet entrance - slide from bottom */\nexport const sheetEntrance: Variants = {\n hidden: {\n y: \"100%\",\n opacity: 0.8,\n },\n visible: {\n y: 0,\n opacity: 1,\n transition: {\n type: \"spring\",\n stiffness: 300,\n damping: 30,\n },\n },\n exit: {\n y: \"100%\",\n opacity: 0.8,\n transition: { duration: 0.2 },\n },\n};\n```\n\n### Step 2: Add Scroll Reveal Variants\n```typescript\n/** Fade up with blur - premium reveal effect */\nexport const fadeUpBlur: Variants = {\n hidden: {\n opacity: 0,\n y: 30,\n filter: \"blur(10px)\",\n },\n visible: {\n opacity: 1,\n y: 0,\n filter: \"blur(0px)\",\n transition: springs.smooth,\n },\n};\n\n/** Scale up for badges/pills */\nexport const scaleUp: Variants = {\n hidden: {\n opacity: 0,\n scale: 0.8,\n },\n visible: {\n opacity: 1,\n scale: 1,\n transition: springs.snappy,\n },\n};\n```\n\n### Step 3: Add Micro-Stagger Variants\n```typescript\n/** Micro stagger for pill/tag lists */\nexport const staggerMicro: Variants = {\n hidden: {},\n visible: {\n transition: {\n staggerChildren: 0.02,\n delayChildren: 0,\n },\n },\n};\n\n/** Cascade stagger for dashboard cards */\nexport const staggerCascade: Variants = {\n hidden: {},\n visible: {\n transition: {\n staggerChildren: 0.08,\n delayChildren: 0.15,\n staggerDirection: 1,\n },\n },\n};\n```\n\n### Step 4: Add Presence Animation Helpers\n```typescript\n/** Get animation props that respect reduced motion */\nexport function getPresenceProps(\n variants: Variants,\n prefersReducedMotion: boolean\n): MotionProps {\n if (prefersReducedMotion) {\n return {\n initial: false,\n animate: \"visible\",\n };\n }\n return {\n initial: \"hidden\",\n animate: \"visible\",\n exit: \"exit\",\n variants,\n };\n}\n```\n\n## Testing\n- Test all new variants with reduced motion on/off\n- Verify no duplicate keyframe definitions\n- Check bundle size impact (should be minimal)\n\n## Files to Modify\n- apps/web/components/motion/index.tsx\n\n## Acceptance Criteria\n- [ ] Modal entrance variants (modalEntrance, sheetEntrance)\n- [ ] Scroll reveal variants (fadeUpBlur, scaleUp)\n- [ ] Stagger variants (staggerMicro, staggerCascade)\n- [ ] Helper function (getPresenceProps)\n- [ ] All variants respect reduced motion\n- [ ] TypeScript types exported","status":"closed","priority":1,"issue_type":"task","assignee":"ubuntu","estimated_minutes":60,"created_at":"2026-02-03T19:53:48.668949503Z","created_by":"ubuntu","updated_at":"2026-02-03T20:17:29.577011647Z","closed_at":"2026-02-03T20:17:29.576990727Z","close_reason":"Implemented modalEntrance, sheetEntrance, fadeUpBlur, scaleUp, staggerMicro, staggerCascade variants and getPresenceProps helper in motion/index.tsx","source_repo":".","compaction_level":0,"original_size":0,"labels":["animation","design-tokens","framer-motion"],"dependencies":[{"issue_id":"bd-3co7k.1.2","depends_on_id":"bd-3co7k.1","type":"parent-child","created_at":"2026-02-03T19:53:48.668949503Z","created_by":"ubuntu"}],"comments":[{"id":43,"issue_id":"bd-3co7k.1.2","author":"Dicklesworthstone","text":"## Testing Requirements\n\n### Unit Tests\nCreate: `apps/web/components/motion/__tests__/variants.test.ts`\n\n```typescript\nimport { modalEntrance, sheetEntrance, fadeUpBlur, getPresenceProps } from '../index';\n\ndescribe('Animation Variants', () => {\n describe('modalEntrance', () => {\n test('hidden state has opacity 0 and scale 0.95', () => {\n expect(modalEntrance.hidden).toMatchObject({ opacity: 0, scale: 0.95 });\n });\n \n test('visible state restores opacity and scale', () => {\n expect(modalEntrance.visible).toMatchObject({ opacity: 1, scale: 1 });\n });\n });\n\n describe('getPresenceProps', () => {\n test('returns immediate animation when reduced motion preferred', () => {\n const props = getPresenceProps(modalEntrance, true);\n expect(props.initial).toBe(false);\n });\n \n test('returns full animation when reduced motion not preferred', () => {\n const props = getPresenceProps(modalEntrance, false);\n expect(props.initial).toBe('hidden');\n });\n });\n});\n```\n\n### E2E Tests\nCreate: `apps/web/e2e/animations.spec.ts`\n\n```typescript\nimport { test, expect } from '@playwright/test';\n\ntest.describe('Animation Variants', () => {\n test('modal animations respect reduced motion', async ({ page }) => {\n console.log('[E2E] Testing with reduced motion emulation');\n await page.emulateMedia({ reducedMotion: 'reduce' });\n await page.goto('/glossary');\n // Trigger a modal and verify no animation\n });\n});\n```\n","created_at":"2026-02-03T20:04:20Z"}]} +{"id":"bd-3co7k.2","title":"Core Components Enhancement","description":"# Core Components Enhancement\n\n## Purpose\nCreate and enhance core UI components that will be used across multiple pages.\nThese components embody Stripe-level polish and serve as building blocks.\n\n## Why This Matters\n- BottomSheet enables native-feeling mobile modals\n- FormField with animations creates premium form experiences\n- Dismissible alerts with progress feel intentional, not bolted-on\n- Enhanced loading states make waiting feel shorter\n\n## Scope\n1. BottomSheet component for mobile modals\n2. FormField with animated floating labels\n3. Dismissible Alert with auto-dismiss progress\n4. Enhanced button loading states\n\n## Dependencies\n- Depends on: Design System Foundation (bd-3co7k.1)\n- Animation variants needed for smooth entrances\n\n## Files to Create/Modify\n- apps/web/components/ui/bottom-sheet.tsx (NEW)\n- apps/web/components/ui/form-field.tsx (NEW)\n- apps/web/components/alert-card.tsx (MODIFY)\n- apps/web/components/ui/button.tsx (MODIFY)\n\n## Acceptance Criteria\n- Components follow existing patterns in components/ui/\n- All components respect reduced motion preference\n- Touch targets meet Apple HIG (44px minimum)\n- Focus states visible for keyboard navigation\n- TypeScript types exported for consumers","status":"closed","priority":1,"issue_type":"feature","created_at":"2026-02-03T19:53:58.973436183Z","created_by":"ubuntu","updated_at":"2026-02-04T04:41:48.184837256Z","closed_at":"2026-02-04T04:41:48.184818420Z","close_reason":"Core components (BottomSheet, FormField, Alert, Button) complete","source_repo":".","compaction_level":0,"original_size":0,"labels":["components","ui"],"dependencies":[{"issue_id":"bd-3co7k.2","depends_on_id":"bd-3co7k","type":"parent-child","created_at":"2026-02-03T19:53:58.973436183Z","created_by":"ubuntu"},{"issue_id":"bd-3co7k.2","depends_on_id":"bd-3co7k.1","type":"blocks","created_at":"2026-02-03T19:54:14.883349379Z","created_by":"ubuntu"}]} +{"id":"bd-3co7k.2.1","title":"BottomSheet Component","description":"# BottomSheet Component\n\n## Problem Statement\nMobile modals that use traditional center-screen dialogs feel \"web-like\" rather \nthan native. iOS and Android users expect bottom sheets for contextual actions\nand detail views. Our current jargon.tsx uses a custom bottom sheet pattern that\nshould be extracted into a reusable component.\n\n## Background\n**Why Bottom Sheets Matter:**\n- Thumb-reachable on large phones\n- Natural gesture interaction (swipe down to dismiss)\n- Maintains context (partial view of underlying content)\n- Feels native on both iOS and Android\n\n**Current Pattern (jargon.tsx lines 298-331):**\n```tsx\n\n```\n\n## Implementation Details\n\n### Step 1: Create Component File\nLocation: apps/web/components/ui/bottom-sheet.tsx\n\n### Step 2: Component Interface\n```typescript\ninterface BottomSheetProps {\n /** Whether the sheet is open */\n open: boolean;\n /** Callback when sheet should close */\n onClose: () => void;\n /** Title for accessibility (aria-label) */\n title: string;\n /** Content to render inside the sheet */\n children: React.ReactNode;\n /** Maximum height (default: 80vh) */\n maxHeight?: string;\n /** Whether to show the drag handle */\n showHandle?: boolean;\n /** Whether to close on backdrop click (default: true) */\n closeOnBackdrop?: boolean;\n /** Whether to enable swipe-to-close (default: true) */\n swipeable?: boolean;\n /** Additional className for the sheet container */\n className?: string;\n}\n```\n\n### Step 3: Core Implementation\n```typescript\n\"use client\";\n\nimport { useEffect, useCallback } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { motion, AnimatePresence, useDragControls } from \"framer-motion\";\nimport { X } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport { sheetEntrance, springs } from \"@/components/motion\";\nimport { useReducedMotion } from \"@/lib/hooks/useReducedMotion\";\n\nexport function BottomSheet({\n open,\n onClose,\n title,\n children,\n maxHeight = \"80vh\",\n showHandle = true,\n closeOnBackdrop = true,\n swipeable = true,\n className,\n}: BottomSheetProps) {\n const prefersReducedMotion = useReducedMotion();\n const reducedMotion = prefersReducedMotion ?? false;\n const dragControls = useDragControls();\n\n // Escape key handling\n useEffect(() => {\n if (!open) return;\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") onClose();\n };\n document.addEventListener(\"keydown\", handleEscape);\n return () => document.removeEventListener(\"keydown\", handleEscape);\n }, [open, onClose]);\n\n // Lock body scroll when open\n useEffect(() => {\n if (open) {\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = \"\";\n };\n }\n }, [open]);\n\n // Swipe to close handler\n const handleDragEnd = useCallback(\n (_: unknown, info: { velocity: { y: number }; offset: { y: number } }) => {\n if (info.velocity.y > 500 || info.offset.y > 200) {\n onClose();\n }\n },\n [onClose]\n );\n\n if (typeof window === \"undefined\") return null;\n\n return createPortal(\n \n {open && (\n <>\n {/* Backdrop */}\n \n\n {/* Sheet */}\n \n {/* Drag handle */}\n {showHandle && (\n dragControls.start(e)}\n >\n
\n
\n )}\n\n {/* Close button */}\n \n \n \n\n {/* Content - scrollable with safe area padding */}\n \n {children}\n \n \n \n )}\n
,\n document.body\n );\n}\n```\n\n### Step 4: Export from ui/index.ts (if exists)\n\n### Step 5: Usage Example\n```tsx\nimport { BottomSheet } from \"@/components/ui/bottom-sheet\";\n\nfunction Example() {\n const [open, setOpen] = useState(false);\n \n return (\n setOpen(false)}\n title=\"Settings\"\n >\n

Settings

\n {/* Content */}\n \n );\n}\n```\n\n## Testing\n- Test on iOS Safari (swipe behavior, safe areas)\n- Test on Android Chrome (swipe behavior)\n- Test with VoiceOver/TalkBack\n- Test escape key dismissal\n- Test backdrop click dismissal\n- Test with reduced motion enabled\n- Verify body scroll lock works\n- Test nested scrollable content\n\n## Files to Create\n- apps/web/components/ui/bottom-sheet.tsx\n\n## Acceptance Criteria\n- [ ] Component renders via portal\n- [ ] Swipe-to-close gesture works (drag Y > 200px or velocity > 500)\n- [ ] Escape key dismisses\n- [ ] Backdrop click dismisses (configurable)\n- [ ] Body scroll locked when open\n- [ ] Safe area padding applied (pb-safe)\n- [ ] Reduced motion fallback (opacity instead of slide)\n- [ ] Close button meets 44px touch target\n- [ ] Drag handle is grabbable\n- [ ] ARIA attributes correct (role=dialog, aria-modal, aria-label)\n- [ ] Works on iOS Safari and Android Chrome","status":"closed","priority":1,"issue_type":"task","estimated_minutes":90,"created_at":"2026-02-03T19:54:49.371133469Z","created_by":"ubuntu","updated_at":"2026-02-04T04:41:40.883735525Z","closed_at":"2026-02-04T04:41:40.883709336Z","close_reason":"BottomSheet component already meets acceptance","source_repo":".","compaction_level":0,"original_size":0,"labels":["component","mobile","sheet"],"dependencies":[{"issue_id":"bd-3co7k.2.1","depends_on_id":"bd-3co7k.1.2","type":"blocks","created_at":"2026-02-03T20:10:29.474913004Z","created_by":"ubuntu"},{"issue_id":"bd-3co7k.2.1","depends_on_id":"bd-3co7k.2","type":"parent-child","created_at":"2026-02-03T19:54:49.371133469Z","created_by":"ubuntu"}],"comments":[{"id":44,"issue_id":"bd-3co7k.2.1","author":"Dicklesworthstone","text":"## Testing Requirements\n\n### Unit Tests\nCreate: `apps/web/components/ui/__tests__/bottom-sheet.test.tsx`\n\n```typescript\nimport { render, screen, fireEvent, waitFor } from '@testing-library/react';\nimport userEvent from '@testing-library/user-event';\nimport { BottomSheet } from '../bottom-sheet';\n\ndescribe('BottomSheet', () => {\n const mockOnClose = jest.fn();\n \n beforeEach(() => {\n mockOnClose.mockClear();\n });\n\n test('renders content when open', () => {\n render(\n \n

Sheet content

\n
\n );\n expect(screen.getByText('Sheet content')).toBeInTheDocument();\n });\n\n test('does not render when closed', () => {\n render(\n \n

Sheet content

\n
\n );\n expect(screen.queryByText('Sheet content')).not.toBeInTheDocument();\n });\n\n test('calls onClose when backdrop clicked', async () => {\n render(\n \n

Content

\n
\n );\n const backdrop = screen.getByRole('presentation', { hidden: true });\n fireEvent.click(backdrop);\n expect(mockOnClose).toHaveBeenCalledTimes(1);\n });\n\n test('calls onClose on Escape key', async () => {\n render(\n \n

Content

\n
\n );\n fireEvent.keyDown(document, { key: 'Escape' });\n expect(mockOnClose).toHaveBeenCalledTimes(1);\n });\n\n test('close button meets 44px touch target', () => {\n render(\n \n

Content

\n
\n );\n const closeButton = screen.getByRole('button', { name: /close/i });\n const styles = getComputedStyle(closeButton);\n expect(parseInt(styles.minHeight) || parseInt(styles.height)).toBeGreaterThanOrEqual(44);\n });\n\n test('has correct ARIA attributes', () => {\n render(\n \n

Content

\n
\n );\n const dialog = screen.getByRole('dialog');\n expect(dialog).toHaveAttribute('aria-modal', 'true');\n expect(dialog).toHaveAttribute('aria-label', 'Test Sheet');\n });\n});\n```\n\n### E2E Tests\nCreate: `apps/web/e2e/bottom-sheet.spec.ts`\n\n```typescript\nimport { test, expect } from '@playwright/test';\n\ntest.describe('BottomSheet Component', () => {\n test.beforeEach(async ({ page }) => {\n await page.setViewportSize({ width: 375, height: 812 }); // iPhone X\n console.log('[E2E] Set mobile viewport for bottom sheet tests');\n });\n\n test('opens from bottom with animation', async ({ page }) => {\n await page.goto('/glossary');\n console.log('[E2E] Navigated to glossary');\n \n // Click a jargon term to open bottom sheet\n await page.getByText('API').first().click();\n console.log('[E2E] Clicked jargon term');\n \n // Verify sheet appears\n const sheet = page.getByRole('dialog');\n await expect(sheet).toBeVisible();\n console.log('[E2E] Bottom sheet visible');\n });\n\n test('swipe down closes sheet', async ({ page }) => {\n await page.goto('/glossary');\n await page.getByText('API').first().click();\n \n const sheet = page.getByRole('dialog');\n await expect(sheet).toBeVisible();\n \n // Simulate swipe down\n const box = await sheet.boundingBox();\n if (box) {\n await page.mouse.move(box.x + box.width / 2, box.y + 50);\n await page.mouse.down();\n await page.mouse.move(box.x + box.width / 2, box.y + 300, { steps: 10 });\n await page.mouse.up();\n console.log('[E2E] Performed swipe gesture');\n }\n \n await expect(sheet).not.toBeVisible({ timeout: 1000 });\n console.log('[E2E] Sheet dismissed via swipe');\n });\n\n test('escape key closes sheet', async ({ page }) => {\n await page.goto('/glossary');\n await page.getByText('API').first().click();\n \n await expect(page.getByRole('dialog')).toBeVisible();\n await page.keyboard.press('Escape');\n console.log('[E2E] Pressed Escape');\n \n await expect(page.getByRole('dialog')).not.toBeVisible();\n console.log('[E2E] Sheet dismissed via Escape');\n });\n});\n```\n","created_at":"2026-02-03T20:04:34Z"}]} +{"id":"bd-3co7k.2.2","title":"FormField with Animated Labels","description":"# FormField with Animated Labels\n\n## Problem Statement\nForm inputs in the app use standard labels positioned above inputs. For a premium\nfeel, we should support Material Design-style floating labels that animate from\nplaceholder position to label position when focused or filled.\n\n## Background\n**Why Animated Labels Matter:**\n- Saves vertical space (label shares space with placeholder)\n- Provides clear visual feedback on focus\n- Feels modern and polished\n- Common pattern users recognize from native apps\n\n**Current State:**\n- Basic input styling in globals.css\n- No animated label component exists\n- Checkbox component has aria-invalid support\n\n## Implementation Details\n\n### Step 1: Create Component File\nLocation: apps/web/components/ui/form-field.tsx\n\n### Step 2: Component Interface\n```typescript\ninterface FormFieldProps {\n /** Input name for form submission */\n name: string;\n /** Label text (becomes floating label) */\n label: string;\n /** Input type (text, email, password, etc.) */\n type?: \"text\" | \"email\" | \"password\" | \"url\" | \"tel\" | \"number\";\n /** Current value (controlled) */\n value: string;\n /** Change handler */\n onChange: (value: string) => void;\n /** Blur handler */\n onBlur?: () => void;\n /** Error message (shows error state when truthy) */\n error?: string;\n /** Helper text (shown below input when no error) */\n helperText?: string;\n /** Whether field is required */\n required?: boolean;\n /** Whether field is disabled */\n disabled?: boolean;\n /** Placeholder (optional, label acts as placeholder when empty) */\n placeholder?: string;\n /** Character count limit (shows counter when set) */\n maxLength?: number;\n /** Additional className */\n className?: string;\n /** Input ref for focus management */\n inputRef?: React.Ref;\n}\n```\n\n### Step 3: Core Implementation\n```typescript\n\"use client\";\n\nimport { useState, useId } from \"react\";\nimport { motion, AnimatePresence } from \"@/components/motion\";\nimport { cn } from \"@/lib/utils\";\nimport { useReducedMotion } from \"@/lib/hooks/useReducedMotion\";\n\nexport function FormField({\n name,\n label,\n type = \"text\",\n value,\n onChange,\n onBlur,\n error,\n helperText,\n required,\n disabled,\n placeholder,\n maxLength,\n className,\n inputRef,\n}: FormFieldProps) {\n const id = useId();\n const [isFocused, setIsFocused] = useState(false);\n const prefersReducedMotion = useReducedMotion();\n const reducedMotion = prefersReducedMotion ?? false;\n\n const hasValue = value.length > 0;\n const isFloating = isFocused || hasValue;\n const showError = !!error;\n\n const handleFocus = () => setIsFocused(true);\n const handleBlur = () => {\n setIsFocused(false);\n onBlur?.();\n };\n\n return (\n
\n {/* Input container with floating label */}\n \n {/* Floating label */}\n \n {label}\n {required && *}\n \n\n {/* Input */}\n onChange(e.target.value)}\n onFocus={handleFocus}\n onBlur={handleBlur}\n disabled={disabled}\n required={required}\n maxLength={maxLength}\n placeholder={isFloating ? placeholder : undefined}\n aria-invalid={showError}\n aria-describedby={error ? `${id}-error` : helperText ? `${id}-helper` : undefined}\n className={cn(\n \"w-full bg-transparent px-4 pt-6 pb-2 text-base\",\n \"outline-none placeholder:text-muted-foreground/50\",\n \"rounded-xl\", // Match container border radius\n disabled && \"cursor-not-allowed\"\n )}\n />\n
\n\n {/* Helper/Error text and character counter */}\n
\n \n {showError ? (\n \n {error}\n \n ) : helperText ? (\n \n {helperText}\n \n ) : (\n \n )}\n \n\n {maxLength && (\n = maxLength ? \"text-destructive\" : \"text-muted-foreground\"\n )}\n >\n {value.length}/{maxLength}\n \n )}\n
\n \n );\n}\n```\n\n### Step 4: Create Textarea Variant (Optional)\nSimilar to FormField but for textarea elements with auto-resize.\n\n## Testing\n- Test focus/blur states\n- Test with value vs empty\n- Test error state transitions\n- Test character counter at limit\n- Test with disabled state\n- Test reduced motion (no transform animation)\n- Test with screen reader (VoiceOver)\n- Test keyboard navigation (Tab focus)\n\n## Files to Create\n- apps/web/components/ui/form-field.tsx\n\n## Acceptance Criteria\n- [ ] Label floats up when focused or has value\n- [ ] Smooth 150ms transition (respects reduced motion)\n- [ ] Error state shows red border and error message\n- [ ] Helper text shows when no error\n- [ ] Character counter shows when maxLength set\n- [ ] Counter turns red at limit\n- [ ] ARIA attributes correct (aria-invalid, aria-describedby)\n- [ ] Keyboard focusable\n- [ ] Required indicator shows asterisk\n- [ ] Disabled state has reduced opacity and cursor","status":"closed","priority":2,"issue_type":"task","estimated_minutes":75,"created_at":"2026-02-03T19:55:19.777223232Z","created_by":"ubuntu","updated_at":"2026-02-04T04:32:59.790178156Z","closed_at":"2026-02-04T04:32:59.790140665Z","close_reason":"Implemented FormField component","source_repo":".","compaction_level":0,"original_size":0,"labels":["animation","component","forms"],"dependencies":[{"issue_id":"bd-3co7k.2.2","depends_on_id":"bd-3co7k.2","type":"parent-child","created_at":"2026-02-03T19:55:19.777223232Z","created_by":"ubuntu"}],"comments":[{"id":45,"issue_id":"bd-3co7k.2.2","author":"Dicklesworthstone","text":"## Testing Requirements\n\n### Unit Tests\nCreate: `apps/web/components/ui/__tests__/form-field.test.tsx`\n\n```typescript\nimport { render, screen, fireEvent } from '@testing-library/react';\nimport userEvent from '@testing-library/user-event';\nimport { FormField } from '../form-field';\n\ndescribe('FormField', () => {\n const defaultProps = {\n name: 'email',\n label: 'Email',\n value: '',\n onChange: jest.fn(),\n };\n\n test('renders with label', () => {\n render();\n expect(screen.getByLabelText('Email')).toBeInTheDocument();\n });\n\n test('label floats when focused', async () => {\n render();\n const input = screen.getByLabelText('Email');\n await userEvent.click(input);\n // Label should have different styling when floating\n const label = screen.getByText('Email');\n expect(label).toHaveClass('text-xs'); // or check computed style\n });\n\n test('label floats when has value', () => {\n render();\n const label = screen.getByText('Email');\n expect(label).toHaveClass('text-xs');\n });\n\n test('shows error state with message', () => {\n render();\n expect(screen.getByRole('alert')).toHaveTextContent('Invalid email');\n });\n\n test('shows character counter when maxLength set', () => {\n render();\n expect(screen.getByText('5/100')).toBeInTheDocument();\n });\n\n test('counter turns red at limit', () => {\n render();\n const counter = screen.getByText('5/5');\n expect(counter).toHaveClass('text-destructive');\n });\n\n test('has correct aria-invalid when error', () => {\n render();\n expect(screen.getByLabelText('Email')).toHaveAttribute('aria-invalid', 'true');\n });\n\n test('required indicator shows asterisk', () => {\n render();\n expect(screen.getByText('*')).toBeInTheDocument();\n });\n});\n```\n\n### E2E Tests\nCreate: `apps/web/e2e/form-field.spec.ts`\n\n```typescript\nimport { test, expect } from '@playwright/test';\n\ntest.describe('FormField Component', () => {\n test('animated label floats on focus', async ({ page }) => {\n await page.goto('/wizard/os-selection'); // Page with form fields\n console.log('[E2E] Navigated to wizard');\n \n const input = page.locator('input[type=\"text\"]').first();\n const label = input.locator('xpath=preceding-sibling::label');\n \n // Get initial position\n const initialPos = await label.boundingBox();\n console.log('[E2E] Initial label position:', initialPos?.y);\n \n // Focus input\n await input.focus();\n await page.waitForTimeout(200); // Wait for animation\n \n // Get floated position\n const floatedPos = await label.boundingBox();\n console.log('[E2E] Floated label position:', floatedPos?.y);\n \n // Label should have moved up\n expect(floatedPos!.y).toBeLessThan(initialPos!.y);\n });\n});\n```\n","created_at":"2026-02-03T20:04:48Z"}]} +{"id":"bd-3co7k.2.3","title":"Dismissible Alert with Progress","description":"# Dismissible Alert with Progress\n\n## Problem Statement\nCurrent AlertCard component (apps/web/components/alert-card.tsx) shows static \nalerts without:\n1. Dismiss button (manual close)\n2. Auto-dismiss with countdown progress\n3. Animated exit when dismissed\n\nStripe and Linear use dismissible alerts with progress indicators that feel \nintentional rather than intrusive.\n\n## Background\n**Current AlertCard Features:**\n- Multiple variants (info, success, warning, error)\n- Collapsible details section\n- Good visual design with gradients\n\n**Missing Features:**\n- No dismiss button\n- No auto-dismiss timer\n- No exit animation\n- No stacking/queue behavior\n\n## Implementation Details\n\n### Step 1: Extend AlertCard Interface\nAdd to existing AlertCard in apps/web/components/alert-card.tsx:\n\n```typescript\ninterface AlertCardProps {\n // ... existing props ...\n \n /** Whether the alert can be dismissed */\n dismissible?: boolean;\n /** Callback when dismissed */\n onDismiss?: () => void;\n /** Auto-dismiss after this many milliseconds (0 = no auto-dismiss) */\n autoDismissMs?: number;\n /** Whether to show countdown progress bar when auto-dismissing */\n showProgress?: boolean;\n}\n```\n\n### Step 2: Add Dismiss Button\n```tsx\n{dismissible && (\n \n \n \n)}\n```\n\n### Step 3: Add Auto-Dismiss Logic\n```tsx\nuseEffect(() => {\n if (!autoDismissMs || autoDismissMs <= 0) return;\n \n const timeout = setTimeout(() => {\n onDismiss?.();\n }, autoDismissMs);\n \n return () => clearTimeout(timeout);\n}, [autoDismissMs, onDismiss]);\n```\n\n### Step 4: Add Progress Bar\n```tsx\n{showProgress && autoDismissMs > 0 && (\n \n)}\n```\n\n### Step 5: Wrap with AnimatePresence for Exit\nConsumer wraps with AnimatePresence:\n```tsx\n\n {showAlert && (\n \n )}\n\n```\n\nOr integrate motion props into AlertCard:\n```tsx\nexport function AlertCard({\n // ... props\n}: AlertCardProps) {\n const prefersReducedMotion = useReducedMotion();\n \n return (\n \n );\n}\n```\n\n### Step 6: Add Pause-on-Hover (Optional Enhancement)\n```tsx\nconst [isPaused, setIsPaused] = useState(false);\n\n// Pause countdown on hover\n setIsPaused(true)}\n onMouseLeave={() => setIsPaused(false)}\n>\n {/* Progress bar uses isPaused to stop animation */}\n\n```\n\n## Testing\n- Test dismiss button click\n- Test auto-dismiss countdown\n- Test progress bar animation (smooth, linear)\n- Test pause on hover (if implemented)\n- Test exit animation\n- Test with reduced motion\n- Test keyboard accessibility (Escape to dismiss?)\n- Test screen reader announcement\n\n## Files to Modify\n- apps/web/components/alert-card.tsx\n\n## Acceptance Criteria\n- [ ] Dismiss button shown when dismissible=true\n- [ ] Dismiss button meets touch target (min 32px, recommend 44px)\n- [ ] onDismiss callback fires on dismiss\n- [ ] Auto-dismiss works with autoDismissMs prop\n- [ ] Progress bar shows countdown (when showProgress=true)\n- [ ] Progress bar is linear, not eased\n- [ ] Exit animation smooth (respects reduced motion)\n- [ ] Pause on hover (nice-to-have)\n- [ ] ARIA label on dismiss button","status":"closed","priority":2,"issue_type":"task","estimated_minutes":60,"created_at":"2026-02-03T19:55:43.252390805Z","created_by":"ubuntu","updated_at":"2026-02-04T04:33:02.857823904Z","closed_at":"2026-02-04T04:33:02.857800500Z","close_reason":"Added dismissible alerts with progress","source_repo":".","compaction_level":0,"original_size":0,"labels":["alerts","animation","component"],"dependencies":[{"issue_id":"bd-3co7k.2.3","depends_on_id":"bd-3co7k.2","type":"parent-child","created_at":"2026-02-03T19:55:43.252390805Z","created_by":"ubuntu"}],"comments":[{"id":46,"issue_id":"bd-3co7k.2.3","author":"Dicklesworthstone","text":"## Testing Requirements\n\n### Unit Tests\nCreate: `apps/web/components/__tests__/alert-card.test.tsx`\n\n```typescript\nimport { render, screen, fireEvent, act } from '@testing-library/react';\nimport { AlertCard } from '../alert-card';\n\ndescribe('AlertCard Dismissible Features', () => {\n const defaultProps = {\n title: 'Test Alert',\n message: 'This is a test',\n };\n\n jest.useFakeTimers();\n\n test('shows dismiss button when dismissible', () => {\n render( {}} />);\n expect(screen.getByRole('button', { name: /dismiss/i })).toBeInTheDocument();\n });\n\n test('calls onDismiss when button clicked', () => {\n const onDismiss = jest.fn();\n render();\n fireEvent.click(screen.getByRole('button', { name: /dismiss/i }));\n expect(onDismiss).toHaveBeenCalledTimes(1);\n });\n\n test('auto-dismisses after specified time', () => {\n const onDismiss = jest.fn();\n render();\n \n act(() => {\n jest.advanceTimersByTime(4999);\n });\n expect(onDismiss).not.toHaveBeenCalled();\n \n act(() => {\n jest.advanceTimersByTime(1);\n });\n expect(onDismiss).toHaveBeenCalledTimes(1);\n });\n\n test('progress bar animates during countdown', () => {\n render();\n const progressBar = screen.getByTestId('progress-bar');\n expect(progressBar).toBeInTheDocument();\n });\n\n test('dismiss button meets touch target size', () => {\n render( {}} />);\n const button = screen.getByRole('button', { name: /dismiss/i });\n const styles = getComputedStyle(button);\n expect(parseInt(styles.minWidth) || parseInt(styles.width)).toBeGreaterThanOrEqual(32);\n });\n});\n```\n\n### E2E Tests\nCreate: `apps/web/e2e/alert-card.spec.ts`\n\n```typescript\nimport { test, expect } from '@playwright/test';\n\ntest.describe('AlertCard Dismissible', () => {\n test('dismiss button closes alert', async ({ page }) => {\n // Navigate to a page with dismissible alerts\n await page.goto('/wizard/os-selection');\n console.log('[E2E] Looking for dismissible alert');\n \n const alert = page.locator('[role=\"alert\"]').first();\n if (await alert.isVisible()) {\n const dismissBtn = alert.getByRole('button', { name: /dismiss/i });\n await dismissBtn.click();\n console.log('[E2E] Clicked dismiss button');\n await expect(alert).not.toBeVisible({ timeout: 1000 });\n }\n });\n\n test('auto-dismiss countdown shows progress', async ({ page }) => {\n // This test requires triggering an auto-dismissing alert\n await page.goto('/');\n console.log('[E2E] Checking for progress bar on auto-dismiss alerts');\n // Implementation depends on where auto-dismiss alerts appear\n });\n});\n```\n","created_at":"2026-02-03T20:04:59Z"}]} +{"id":"bd-3co7k.2.4","title":"Enhanced Button Loading States","description":"# Enhanced Button Loading States\n\n## Problem Statement\nCurrent button loading state (apps/web/components/ui/button.tsx) shows a simple\nspinning Loader2 icon. For world-class polish, the loading state should:\n1. Have a shimmer/pulse effect on the button itself\n2. Optionally show progress percentage\n3. Animate between states smoothly\n\n## Background\n**Current Implementation (lines 99-114):**\n```tsx\nconst LoadingSpinner = () => (\n \n);\n\nif (loading) {\n return (\n <>\n \n {loadingText && {loadingText}}\n \n );\n}\n```\n\n**Issues:**\n- No visual shimmer on button background\n- Spinner is basic rotate animation\n- No progress indicator option\n- No smooth transition between loading/not-loading\n\n## Implementation Details\n\n### Step 1: Add Loading Progress Prop\n```typescript\ninterface ButtonProps {\n // ... existing props ...\n \n /** Progress percentage (0-100) when loading - shows determinate progress */\n loadingProgress?: number;\n}\n```\n\n### Step 2: Enhance Button Background During Loading\nAdd a shimmer overlay when loading:\n```tsx\n{loading && (\n \n {/* Shimmer effect */}\n
\n \n)}\n```\n\n### Step 3: Enhance Spinner Animation\nReplace basic spin with a more refined animation:\n```tsx\nconst LoadingSpinner = ({ className }: { className?: string }) => (\n \n \n \n);\n```\n\nOr use a custom spinner SVG with gradient:\n```tsx\nconst LoadingSpinner = () => (\n \n \n \n \n);\n```\n\n### Step 4: Add Progress Bar Option\nWhen loadingProgress is provided:\n```tsx\n{loading && typeof loadingProgress === \"number\" && (\n
\n \n
\n)}\n```\n\n### Step 5: Smooth State Transition\nWrap content with AnimatePresence for smooth swap:\n```tsx\n\n {loading ? (\n \n \n {loadingText && {loadingText}}\n \n ) : (\n \n {children}\n \n )}\n\n```\n\n### Step 6: Add Pulse Effect to Disabled Loading Button\n```tsx\nclassName={cn(\n buttonVariants({ variant, size }),\n loading && \"animate-pulse opacity-90\",\n className\n)}\n```\n\n## Testing\n- Test loading state transition (smooth, no jump)\n- Test with loadingText\n- Test with loadingProgress (0-100)\n- Test shimmer effect visibility\n- Test with reduced motion (no shimmer, simple fade)\n- Test all button variants in loading state\n- Test disabled + loading combination\n\n## Files to Modify\n- apps/web/components/ui/button.tsx\n\n## Acceptance Criteria\n- [ ] Loading state has subtle shimmer effect on background\n- [ ] Transition between loading/not-loading is animated (fade + scale)\n- [ ] loadingProgress prop shows determinate progress bar\n- [ ] Progress bar animates smoothly\n- [ ] Spinner rotation is smooth (not janky)\n- [ ] Reduced motion: no shimmer, simple opacity transition\n- [ ] All button variants look good in loading state\n- [ ] Button remains same size during loading (no layout shift)","status":"closed","priority":2,"issue_type":"task","estimated_minutes":45,"created_at":"2026-02-03T19:56:06.111850561Z","created_by":"ubuntu","updated_at":"2026-02-04T04:33:07.733457511Z","closed_at":"2026-02-04T04:33:07.733428787Z","close_reason":"Enhanced button loading states","source_repo":".","compaction_level":0,"original_size":0,"labels":["animation","button","component","loading"],"dependencies":[{"issue_id":"bd-3co7k.2.4","depends_on_id":"bd-3co7k.2","type":"parent-child","created_at":"2026-02-03T19:56:06.111850561Z","created_by":"ubuntu"}],"comments":[{"id":47,"issue_id":"bd-3co7k.2.4","author":"Dicklesworthstone","text":"## Testing Requirements\n\n### Unit Tests\nCreate: `apps/web/components/ui/__tests__/button-loading.test.tsx`\n\n```typescript\nimport { render, screen } from '@testing-library/react';\nimport { Button } from '../button';\n\ndescribe('Button Loading States', () => {\n test('shows spinner when loading', () => {\n render();\n expect(screen.getByRole('button')).toContainElement(screen.getByTestId('loading-spinner'));\n });\n\n test('shows loadingText when provided', () => {\n render();\n expect(screen.getByText('Saving...')).toBeInTheDocument();\n });\n\n test('maintains button size during loading (no layout shift)', () => {\n const { rerender, container } = render();\n const initialWidth = container.firstChild?.clientWidth;\n \n rerender();\n const loadingWidth = container.firstChild?.clientWidth;\n \n expect(loadingWidth).toBe(initialWidth);\n });\n\n test('shows progress bar when loadingProgress provided', () => {\n render();\n const progressBar = screen.getByTestId('progress-bar');\n expect(progressBar).toHaveStyle({ width: '50%' });\n });\n\n test('button is disabled during loading', () => {\n render();\n expect(screen.getByRole('button')).toBeDisabled();\n });\n\n test('shimmer effect present during loading', () => {\n render();\n const button = screen.getByRole('button');\n // Check for shimmer class or animation\n expect(button.querySelector('[class*=\"shimmer\"]')).toBeInTheDocument();\n });\n});\n```\n\n### E2E Tests\nCreate: `apps/web/e2e/button-loading.spec.ts`\n\n```typescript\nimport { test, expect } from '@playwright/test';\n\ntest.describe('Button Loading States', () => {\n test('loading transition is smooth', async ({ page }) => {\n await page.goto('/wizard/result');\n console.log('[E2E] Navigated to wizard result page');\n \n // Find a button that triggers loading\n const button = page.getByRole('button', { name: /download/i });\n const initialBox = await button.boundingBox();\n console.log('[E2E] Initial button dimensions:', initialBox);\n \n await button.click();\n await page.waitForTimeout(100); // Wait for loading state\n \n const loadingBox = await button.boundingBox();\n console.log('[E2E] Loading button dimensions:', loadingBox);\n \n // Size should be the same (no layout shift)\n expect(loadingBox?.width).toBeCloseTo(initialBox!.width, 0);\n });\n\n test('loading respects reduced motion', async ({ page }) => {\n await page.emulateMedia({ reducedMotion: 'reduce' });\n await page.goto('/wizard/result');\n console.log('[E2E] Testing with reduced motion');\n \n // Loading should still work but without shimmer animation\n const button = page.getByRole('button', { name: /download/i });\n await button.click();\n \n // Verify button shows loading state\n await expect(button).toBeDisabled();\n });\n});\n```\n","created_at":"2026-02-03T20:05:11Z"}]} +{"id":"bd-3co7k.3","title":"Page-Level Enhancements","description":"# Page-Level Enhancements\n\n## Purpose\nApply the enhanced components and design system improvements to actual pages.\nThis is where the polish becomes visible to users.\n\n## Why This Matters\n- Components alone don't create great UX - their application does\n- Scroll-triggered reveals create dynamic, engaging pages\n- Consistent empty states across pages feel professional\n- Swipe gestures make content browsing feel native\n\n## Scope\n1. Scroll reveal animations on landing page sections\n2. Empty states for glossary and learn pages\n3. Swipe gestures for carousels/horizontal scrolling\n\n## Dependencies\n- Depends on: Core Components Enhancement (bd-3co7k.2)\n- Needs EmptyState component (already done)\n- Needs animation variants (from Design System)\n\n## Pages to Enhance\n- apps/web/app/page.tsx (landing page)\n- apps/web/app/glossary/page.tsx\n- apps/web/app/learn/glossary/page.tsx\n- apps/web/app/learn/page.tsx\n\n## Acceptance Criteria\n- Landing page sections animate on scroll\n- All empty search states use EmptyState component\n- Horizontal scrollable areas support swipe gestures\n- No jank or performance issues on scroll","status":"closed","priority":1,"issue_type":"feature","created_at":"2026-02-03T19:56:17.764302018Z","created_by":"ubuntu","updated_at":"2026-02-04T04:50:12.025628574Z","closed_at":"2026-02-04T04:50:12.025610150Z","close_reason":"Page-level enhancements complete","source_repo":".","compaction_level":0,"original_size":0,"labels":["enhancements","pages"],"dependencies":[{"issue_id":"bd-3co7k.3","depends_on_id":"bd-3co7k","type":"parent-child","created_at":"2026-02-03T19:56:17.764302018Z","created_by":"ubuntu"},{"issue_id":"bd-3co7k.3","depends_on_id":"bd-3co7k.2","type":"blocks","created_at":"2026-02-03T19:56:23.839030770Z","created_by":"ubuntu"}]} +{"id":"bd-3co7k.3.1","title":"Landing Page Scroll Reveal Animations","description":"# Landing Page Scroll Reveal Animations\n\n## Problem Statement\nThe landing page (apps/web/app/page.tsx) has good static design but sections \nappear instantly rather than revealing as the user scrolls. Scroll-triggered\nreveals create a dynamic, engaging experience that feels premium.\n\n## Background\n**Current State:**\n- useScrollReveal hook exists but is underutilized\n- Some sections use basic fade-in on mount\n- No staggered reveals within sections\n\n**Reference:**\n- Stripe.com: Sections fade and slide up as they enter viewport\n- Linear.app: Features cascade in with staggered timing\n- Vercel.com: Smooth parallax effects on scroll\n\n## Implementation Details\n\n### Step 1: Identify Sections to Animate\nReview page.tsx and identify major sections:\n1. Hero section (~line 100-200)\n2. Features grid (~line 300-400)\n3. Tool showcase section\n4. Testimonials/social proof\n5. CTA section\n6. Footer\n\n### Step 2: Apply useScrollReveal to Each Section\n```tsx\nimport { useScrollReveal, staggerDelay } from \"@/lib/hooks/useScrollReveal\";\n\nfunction FeaturesSection() {\n const { ref, isInView } = useScrollReveal({ threshold: 0.1 });\n\n return (\n
\n \n

Features

\n \n \n
\n {features.map((feature, i) => (\n \n \n \n ))}\n
\n
\n );\n}\n```\n\n### Step 3: Use staggerContainer for Grid Items\n```tsx\n\n {features.map((feature) => (\n \n \n \n ))}\n\n```\n\n### Step 4: Add Blur Effect for Premium Reveals\nUsing the new fadeUpBlur variant:\n```tsx\n\n```\n\n### Step 5: Different Effects for Different Sections\n- Hero: Immediate (no scroll trigger, already visible)\n- Features: Fade up with stagger\n- Tool showcase: Slide in from sides alternating\n- Testimonials: Scale up with blur\n- CTA: Fade up (simple)\n\n### Step 6: Performance Optimization\n- Use CSS will-change sparingly\n- Ensure animations use transform/opacity only (GPU accelerated)\n- Don't animate too many elements simultaneously\n- Use triggerOnce: true to avoid re-triggering\n\n### Step 7: Reduced Motion Support\nThe useScrollReveal hook already handles this:\n```typescript\nconst shouldShowImmediately =\n disabled || prefersReducedMotion || typeof IntersectionObserver === \"undefined\";\n\nreturn {\n isInView: shouldShowImmediately || isInViewState,\n};\n```\n\n## Testing\n- Test scroll down through all sections\n- Test quick scroll (animations should complete, not stack)\n- Test slow scroll (animations trigger at right time)\n- Test with reduced motion (all content visible immediately)\n- Test on mobile (touch scroll)\n- Test performance (no jank, maintain 60fps)\n- Test in Safari (IntersectionObserver support)\n\n## Files to Modify\n- apps/web/app/page.tsx\n\n## Acceptance Criteria\n- [ ] Each major section has scroll-triggered reveal\n- [ ] Grid items stagger their entrance (0.1s between items)\n- [ ] At least one section uses fadeUpBlur for premium feel\n- [ ] Animations only trigger once (don't replay on scroll up)\n- [ ] Reduced motion users see all content immediately\n- [ ] No layout shift as content animates in\n- [ ] Performance stays at 60fps during scroll\n- [ ] Works on iOS Safari and Android Chrome","status":"closed","priority":1,"issue_type":"task","estimated_minutes":90,"created_at":"2026-02-03T19:56:49.076279621Z","created_by":"ubuntu","updated_at":"2026-02-04T04:50:01.528146972Z","closed_at":"2026-02-04T04:50:01.528124409Z","close_reason":"Landing page sections already use scroll reveals","source_repo":".","compaction_level":0,"original_size":0,"labels":["animation","landing-page","scroll"],"dependencies":[{"issue_id":"bd-3co7k.3.1","depends_on_id":"bd-3co7k.1.2","type":"blocks","created_at":"2026-02-03T20:10:30.513348480Z","created_by":"ubuntu"},{"issue_id":"bd-3co7k.3.1","depends_on_id":"bd-3co7k.3","type":"parent-child","created_at":"2026-02-03T19:56:49.076279621Z","created_by":"ubuntu"}],"comments":[{"id":48,"issue_id":"bd-3co7k.3.1","author":"Dicklesworthstone","text":"## Testing Requirements\n\n### Unit Tests\nCreate: `apps/web/lib/hooks/__tests__/useScrollReveal.test.ts`\n\n```typescript\nimport { renderHook } from '@testing-library/react';\nimport { useScrollReveal } from '../useScrollReveal';\n\n// Mock IntersectionObserver\nconst mockIntersectionObserver = jest.fn();\nmockIntersectionObserver.mockReturnValue({\n observe: () => null,\n unobserve: () => null,\n disconnect: () => null,\n});\nwindow.IntersectionObserver = mockIntersectionObserver;\n\ndescribe('useScrollReveal', () => {\n test('returns ref and isInView state', () => {\n const { result } = renderHook(() => useScrollReveal());\n expect(result.current.ref).toBeDefined();\n expect(typeof result.current.isInView).toBe('boolean');\n });\n\n test('creates IntersectionObserver with correct options', () => {\n renderHook(() => useScrollReveal({ threshold: 0.2, rootMargin: '-50px' }));\n expect(mockIntersectionObserver).toHaveBeenCalledWith(\n expect.any(Function),\n expect.objectContaining({ threshold: 0.2, rootMargin: '-50px' })\n );\n });\n\n test('returns true immediately when reduced motion preferred', () => {\n // Mock matchMedia for reduced motion\n window.matchMedia = jest.fn().mockImplementation((query) => ({\n matches: query === '(prefers-reduced-motion: reduce)',\n addEventListener: jest.fn(),\n removeEventListener: jest.fn(),\n }));\n\n const { result } = renderHook(() => useScrollReveal());\n expect(result.current.isInView).toBe(true);\n });\n});\n```\n\n### E2E Tests\nCreate: `apps/web/e2e/scroll-reveal.spec.ts`\n\n```typescript\nimport { test, expect } from '@playwright/test';\n\ntest.describe('Scroll Reveal Animations', () => {\n test('sections animate as they enter viewport', async ({ page }) => {\n await page.goto('/');\n console.log('[E2E] Loaded landing page');\n \n // Scroll to features section\n const featuresSection = page.locator('section').filter({ hasText: 'Features' });\n \n // Check initial state (should be hidden/transparent)\n const initialOpacity = await featuresSection.evaluate(el => \n getComputedStyle(el).opacity\n );\n console.log('[E2E] Initial opacity:', initialOpacity);\n \n // Scroll into view\n await featuresSection.scrollIntoViewIfNeeded();\n await page.waitForTimeout(500); // Wait for animation\n \n // Check animated state\n const animatedOpacity = await featuresSection.evaluate(el => \n getComputedStyle(el).opacity\n );\n console.log('[E2E] Animated opacity:', animatedOpacity);\n \n expect(parseFloat(animatedOpacity)).toBeGreaterThan(parseFloat(initialOpacity));\n });\n\n test('grid items stagger their entrance', async ({ page }) => {\n await page.goto('/');\n \n // Get all feature cards\n const cards = page.locator('[data-testid=\"feature-card\"]');\n const count = await cards.count();\n console.log('[E2E] Found', count, 'feature cards');\n \n // Scroll to feature section\n await cards.first().scrollIntoViewIfNeeded();\n \n // Check cards animate in sequence (staggered)\n for (let i = 0; i < Math.min(count, 3); i++) {\n await page.waitForTimeout(100 * i);\n const opacity = await cards.nth(i).evaluate(el => \n getComputedStyle(el).opacity\n );\n console.log(\\`[E2E] Card \\${i} opacity after \\${100 * i}ms: \\${opacity}\\`);\n }\n });\n\n test('animations skip with reduced motion', async ({ page }) => {\n await page.emulateMedia({ reducedMotion: 'reduce' });\n await page.goto('/');\n console.log('[E2E] Testing with reduced motion');\n \n // All content should be immediately visible\n const section = page.locator('section').first();\n const opacity = await section.evaluate(el => \n getComputedStyle(el).opacity\n );\n expect(opacity).toBe('1');\n });\n});\n```\n","created_at":"2026-02-03T20:05:24Z"}]} +{"id":"bd-3co7k.3.2","title":"Empty States for Glossary and Learn Pages","description":"# Empty States for Glossary and Learn Pages\n\n## Problem Statement\nThe glossary pages (apps/web/app/glossary/page.tsx and apps/web/app/learn/glossary/page.tsx)\nshow basic \"No terms found\" text when search returns no results. We should use the new\nEmptyState component for a consistent, polished experience.\n\n## Background\n**Current State (glossary/page.tsx ~line 270-276):**\n```tsx\n{filtered.length === 0 ? (\n \n

\n No matches. Try a different search or switch back to{\" \"}\n All.\n

\n
\n) : (\n```\n\n**Current State (learn/glossary/page.tsx ~line 450):**\n```\nNo terms found\n```\n\n**Tools Page (already updated):**\nUses EmptyState component with Search icon, title, description, and action button.\n\n## Implementation Details\n\n### Step 1: Update apps/web/app/glossary/page.tsx\n\nAdd import:\n```tsx\nimport { EmptyState } from \"@/components/ui/empty-state\";\nimport { Button } from \"@/components/ui/button\";\nimport { BookOpen } from \"lucide-react\"; // or Search\n```\n\nReplace the \"No matches\" section:\n```tsx\n{filtered.length === 0 ? (\n {\n setQuery(\"\");\n setCategory(\"all\");\n }}\n >\n Clear filters\n \n }\n />\n) : (\n```\n\n### Step 2: Update apps/web/app/learn/glossary/page.tsx\n\nSimilar update - find the \"No terms found\" text and replace:\n```tsx\n{filteredTerms.length === 0 ? (\n setSearchQuery(\"\")}>\n Clear search\n \n }\n />\n) : (\n```\n\n### Step 3: Review Other Pages for Empty States\nCheck if any other pages need EmptyState:\n- apps/web/app/troubleshooting/page.tsx (search results)\n- apps/web/app/learn/page.tsx (if filtering lessons)\n\n### Step 4: Ensure Consistent Styling\nAll empty states should:\n- Use appropriate icon for context (BookOpen for glossary, Search for generic)\n- Have clear, helpful title\n- Have actionable description\n- Provide a way to reset/clear filters\n\n## Testing\n- Test search with no results on each page\n- Test category filter with no results (glossary)\n- Test \"Clear filters\" button functionality\n- Test reduced motion (EmptyState respects it)\n- Test on mobile (should look good)\n\n## Files to Modify\n- apps/web/app/glossary/page.tsx\n- apps/web/app/learn/glossary/page.tsx\n- Possibly: apps/web/app/troubleshooting/page.tsx\n\n## Acceptance Criteria\n- [ ] glossary/page.tsx uses EmptyState component\n- [ ] learn/glossary/page.tsx uses EmptyState component\n- [ ] All empty states have appropriate icons\n- [ ] All empty states have clear filter/reset buttons\n- [ ] Animations are smooth (or instant with reduced motion)\n- [ ] Mobile layout looks good","status":"closed","priority":2,"issue_type":"task","estimated_minutes":45,"created_at":"2026-02-03T19:57:07.454473104Z","created_by":"ubuntu","updated_at":"2026-02-04T04:50:04.858943686Z","closed_at":"2026-02-04T04:50:04.858922676Z","close_reason":"Replaced glossary empty states with EmptyState component","source_repo":".","compaction_level":0,"original_size":0,"labels":["empty-state","glossary","learn"],"dependencies":[{"issue_id":"bd-3co7k.3.2","depends_on_id":"bd-3co7k.3","type":"parent-child","created_at":"2026-02-03T19:57:07.454473104Z","created_by":"ubuntu"}],"comments":[{"id":49,"issue_id":"bd-3co7k.3.2","author":"Dicklesworthstone","text":"## Testing Requirements\n\n### Unit Tests\nAlready exists: `apps/web/components/ui/__tests__/empty-state.test.tsx`\n\nVerify coverage for:\n```typescript\ndescribe('EmptyState', () => {\n test('renders icon, title, and description', () => {\n render();\n expect(screen.getByRole('heading', { name: 'No results' })).toBeInTheDocument();\n });\n\n test('renders action button when provided', () => {\n render(\n Clear}\n />\n );\n expect(screen.getByRole('button', { name: 'Clear' })).toBeInTheDocument();\n });\n\n test('variant=\"compact\" applies smaller sizing', () => {\n const { container } = render(\n \n );\n expect(container.firstChild).toHaveClass('py-10');\n });\n});\n```\n\n### E2E Tests\nCreate: `apps/web/e2e/empty-states.spec.ts`\n\n```typescript\nimport { test, expect } from '@playwright/test';\n\ntest.describe('Empty States', () => {\n test('glossary shows empty state for no results', async ({ page }) => {\n await page.goto('/glossary');\n console.log('[E2E] Navigated to glossary');\n \n // Search for something that won't match\n const searchInput = page.getByPlaceholder(/search/i);\n await searchInput.fill('xyzabc123nonexistent');\n console.log('[E2E] Searched for nonexistent term');\n \n // Verify empty state appears\n await expect(page.getByText('No terms found')).toBeVisible();\n console.log('[E2E] Empty state displayed');\n \n // Verify clear button works\n const clearBtn = page.getByRole('button', { name: /clear/i });\n await clearBtn.click();\n console.log('[E2E] Clicked clear button');\n \n // Results should appear again\n await expect(page.locator('[data-testid=\"glossary-term\"]').first()).toBeVisible();\n });\n\n test('tools page shows empty state for no results', async ({ page }) => {\n await page.goto('/tools');\n console.log('[E2E] Navigated to tools');\n \n const searchInput = page.getByPlaceholder(/search/i);\n await searchInput.fill('xyznonexistent');\n \n await expect(page.getByText('No tools found')).toBeVisible();\n console.log('[E2E] Empty state displayed on tools page');\n });\n\n test('empty state respects reduced motion', async ({ page }) => {\n await page.emulateMedia({ reducedMotion: 'reduce' });\n await page.goto('/glossary');\n \n const searchInput = page.getByPlaceholder(/search/i);\n await searchInput.fill('xyznonexistent');\n \n // Should be immediately visible (no fade-in delay)\n const emptyState = page.getByText('No terms found');\n await expect(emptyState).toBeVisible();\n console.log('[E2E] Empty state visible immediately with reduced motion');\n });\n});\n```\n","created_at":"2026-02-03T20:05:38Z"}]} +{"id":"bd-3co7k.3.3","title":"Swipe Gestures for Horizontal Scrolling","description":"# Swipe Gestures for Horizontal Scrolling\n\n## Problem Statement\nHorizontal scrollable areas (carousels, feature grids on mobile) rely on native \nscroll behavior. Adding explicit swipe gesture support with snap points and \nvisual feedback creates a more native-feeling experience.\n\n## Background\n**Current State:**\n- Stepper component has swipe support via @use-gesture/react\n- Other horizontal scrollable areas use CSS scroll-snap\n- No visual indicator of swipe progress or direction\n\n**@use-gesture/react Usage (stepper.tsx ~line 169-193):**\n```tsx\nconst bind = useDrag(\n ({ movement: [mx], velocity: [vx], direction: [dx], cancel }) => {\n // Handle swipe logic\n },\n { axis: \"x\", filterTaps: true }\n);\n```\n\n## Implementation Details\n\n### Step 1: Identify Swipeable Areas\nReview the app for horizontal scrollable content:\n1. Mobile feature cards on landing page\n2. Tool categories on /tldr or /tools (if horizontal)\n3. Lesson cards on /learn (mobile)\n4. Any carousel components\n\n### Step 2: Create useSwipeScroll Hook\n```typescript\n// apps/web/lib/hooks/useSwipeScroll.ts\n\nimport { useRef, useCallback } from \"react\";\nimport { useDrag } from \"@use-gesture/react\";\nimport { useReducedMotion } from \"./useReducedMotion\";\n\ninterface UseSwipeScrollOptions {\n /** Minimum swipe distance to trigger navigation */\n threshold?: number;\n /** Items per \"page\" for snap calculation */\n itemsPerPage?: number;\n /** Callback when page changes */\n onPageChange?: (page: number) => void;\n}\n\nexport function useSwipeScroll(options: UseSwipeScrollOptions = {}) {\n const {\n threshold = 50,\n itemsPerPage = 1,\n onPageChange,\n } = options;\n\n const containerRef = useRef(null);\n const prefersReducedMotion = useReducedMotion();\n const [currentPage, setCurrentPage] = useState(0);\n\n const scrollToPage = useCallback((page: number) => {\n if (!containerRef.current) return;\n \n const container = containerRef.current;\n const itemWidth = container.scrollWidth / totalItems;\n const targetScroll = page * itemWidth * itemsPerPage;\n \n container.scrollTo({\n left: targetScroll,\n behavior: prefersReducedMotion ? \"auto\" : \"smooth\",\n });\n \n setCurrentPage(page);\n onPageChange?.(page);\n }, [itemsPerPage, prefersReducedMotion, onPageChange]);\n\n const bind = useDrag(\n ({ movement: [mx], velocity: [vx], direction: [dx], last }) => {\n if (!last) return;\n \n const shouldNavigate = Math.abs(mx) > threshold || Math.abs(vx) > 0.5;\n if (!shouldNavigate) return;\n \n const nextPage = dx < 0 ? currentPage + 1 : currentPage - 1;\n scrollToPage(Math.max(0, nextPage));\n },\n { axis: \"x\", filterTaps: true, pointer: { touch: true } }\n );\n\n return {\n containerRef,\n bind,\n currentPage,\n scrollToPage,\n };\n}\n```\n\n### Step 3: Add Visual Swipe Indicator\nShow dots or line indicator for current position:\n```tsx\nfunction SwipeIndicator({ current, total }: { current: number; total: number }) {\n return (\n
\n {Array.from({ length: total }).map((_, i) => (\n \n ))}\n
\n );\n}\n```\n\n### Step 4: Apply to Mobile Feature Cards\n```tsx\nfunction MobileFeatureCarousel({ features }) {\n const { containerRef, bind, currentPage } = useSwipeScroll({\n itemsPerPage: 1,\n });\n\n return (\n
\n \n {features.map((feature) => (\n
\n \n
\n ))}\n
\n \n
\n );\n}\n```\n\n### Step 5: Add CSS for Smooth Scrolling\n```css\n/* In globals.css */\n.scrollbar-hide {\n -ms-overflow-style: none;\n scrollbar-width: none;\n}\n.scrollbar-hide::-webkit-scrollbar {\n display: none;\n}\n\n.snap-x {\n scroll-snap-type: x mandatory;\n}\n\n.snap-center {\n scroll-snap-align: center;\n}\n\n.snap-start {\n scroll-snap-align: start;\n}\n```\n\n## Testing\n- Test swipe left/right on mobile\n- Test swipe velocity (quick flick should navigate)\n- Test swipe threshold (small swipe should not navigate)\n- Test indicator updates correctly\n- Test with reduced motion (instant snap, no animation)\n- Test on iOS Safari (touch-action compatibility)\n- Test on Android Chrome\n- Test with mouse drag on desktop (should work)\n\n## Files to Create/Modify\n- apps/web/lib/hooks/useSwipeScroll.ts (NEW)\n- apps/web/app/page.tsx (apply to mobile sections)\n- apps/web/app/globals.css (snap utilities if not present)\n\n## Acceptance Criteria\n- [ ] useSwipeScroll hook created\n- [ ] Swipe left/right navigates between items\n- [ ] Velocity-based navigation (quick flick)\n- [ ] Visual indicator shows current position\n- [ ] Indicator animates smoothly\n- [ ] Reduced motion: instant navigation\n- [ ] Works on iOS Safari and Android Chrome\n- [ ] Falls back gracefully on desktop (native scroll or mouse drag)","status":"closed","priority":3,"issue_type":"task","estimated_minutes":60,"created_at":"2026-02-03T19:57:34.493424120Z","created_by":"ubuntu","updated_at":"2026-02-04T04:50:07.956223155Z","closed_at":"2026-02-04T04:50:07.956197046Z","close_reason":"Added swipe drag support to landing page horizontal scroller","source_repo":".","compaction_level":0,"original_size":0,"labels":["gestures","mobile","swipe"],"dependencies":[{"issue_id":"bd-3co7k.3.3","depends_on_id":"bd-3co7k.3","type":"parent-child","created_at":"2026-02-03T19:57:34.493424120Z","created_by":"ubuntu"}],"comments":[{"id":50,"issue_id":"bd-3co7k.3.3","author":"Dicklesworthstone","text":"## Testing Requirements\n\n### Unit Tests\nCreate: `apps/web/lib/hooks/__tests__/useSwipeScroll.test.ts`\n\n```typescript\nimport { renderHook, act } from '@testing-library/react';\nimport { useSwipeScroll } from '../useSwipeScroll';\n\ndescribe('useSwipeScroll', () => {\n test('returns containerRef and currentPage', () => {\n const { result } = renderHook(() => useSwipeScroll());\n expect(result.current.containerRef).toBeDefined();\n expect(result.current.currentPage).toBe(0);\n });\n\n test('scrollToPage updates currentPage', () => {\n const { result } = renderHook(() => useSwipeScroll());\n act(() => {\n result.current.scrollToPage(2);\n });\n expect(result.current.currentPage).toBe(2);\n });\n\n test('calls onPageChange callback', () => {\n const onPageChange = jest.fn();\n const { result } = renderHook(() => useSwipeScroll({ onPageChange }));\n act(() => {\n result.current.scrollToPage(1);\n });\n expect(onPageChange).toHaveBeenCalledWith(1);\n });\n\n test('respects threshold for swipe navigation', () => {\n const { result } = renderHook(() => useSwipeScroll({ threshold: 100 }));\n // Simulate drag that doesn't meet threshold\n // Page should not change\n expect(result.current.currentPage).toBe(0);\n });\n});\n```\n\n### E2E Tests\nCreate: `apps/web/e2e/swipe-scroll.spec.ts`\n\n```typescript\nimport { test, expect } from '@playwright/test';\n\ntest.describe('Swipe Scroll', () => {\n test.beforeEach(async ({ page }) => {\n await page.setViewportSize({ width: 375, height: 812 });\n console.log('[E2E] Set mobile viewport');\n });\n\n test('swipe navigates between carousel items', async ({ page }) => {\n await page.goto('/');\n console.log('[E2E] Loaded landing page');\n \n // Find swipeable carousel\n const carousel = page.locator('[data-testid=\"feature-carousel\"]');\n if (await carousel.isVisible()) {\n const box = await carousel.boundingBox();\n \n // Check initial indicator\n const indicator = page.locator('[data-testid=\"swipe-indicator\"]');\n const initialActive = await indicator.locator('.bg-primary').count();\n console.log('[E2E] Initial active indicators:', initialActive);\n \n // Perform swipe left\n if (box) {\n await page.mouse.move(box.x + box.width * 0.8, box.y + box.height / 2);\n await page.mouse.down();\n await page.mouse.move(box.x + box.width * 0.2, box.y + box.height / 2, { steps: 10 });\n await page.mouse.up();\n console.log('[E2E] Performed swipe left');\n }\n \n await page.waitForTimeout(300); // Wait for animation\n \n // Check indicator updated\n // (Implementation-specific verification)\n }\n });\n\n test('quick flick navigates via velocity', async ({ page }) => {\n await page.goto('/');\n \n const carousel = page.locator('[data-testid=\"feature-carousel\"]');\n if (await carousel.isVisible()) {\n const box = await carousel.boundingBox();\n \n // Quick flick (fast movement, short distance)\n if (box) {\n await page.mouse.move(box.x + box.width * 0.6, box.y + box.height / 2);\n await page.mouse.down();\n await page.mouse.move(box.x + box.width * 0.4, box.y + box.height / 2, { steps: 2 });\n await page.mouse.up();\n console.log('[E2E] Performed quick flick');\n }\n \n // Should still navigate due to velocity\n }\n });\n});\n```\n","created_at":"2026-02-03T20:05:49Z"}]} +{"id":"bd-3co7k.4","title":"Mobile Experience Optimization","description":"# Mobile Experience Optimization\n\n## Purpose\nMake the mobile experience feel like a native app rather than a responsive website.\nThis goes beyond just \"working on mobile\" to \"delighting on mobile.\"\n\n## Why This Matters\n- Over 50% of web traffic is mobile\n- Mobile users have different expectations (gestures, bottom navigation)\n- Native-feeling apps build trust and engagement\n- Poor mobile experience reflects poorly on the overall product\n\n## Scope\n1. Convert jargon modal to BottomSheet on mobile\n2. Mobile navigation improvements (thumb-friendly layout)\n3. Pull-to-refresh patterns (if applicable)\n\n## Dependencies\n- Depends on: Page-Level Enhancements (bd-3co7k.3)\n- Needs BottomSheet component from Core Components\n\n## Key Considerations\n- Safe areas (notch, home indicator) must be handled\n- Touch targets must be minimum 44px\n- Primary actions should be in thumb zone (bottom 1/3)\n- Gestures should match platform conventions\n\n## Reference\n- Apple Human Interface Guidelines (iOS)\n- Material Design Guidelines (Android)\n- Both platforms prefer bottom sheets for contextual content\n\n## Acceptance Criteria\n- Mobile experience feels native\n- All modals use BottomSheet on mobile viewports\n- Primary CTAs are in thumb-friendly positions\n- Safe areas properly handled on all fixed elements","status":"closed","priority":1,"issue_type":"feature","created_at":"2026-02-03T19:57:48.037864500Z","created_by":"ubuntu","updated_at":"2026-02-04T04:54:56.926556941Z","closed_at":"2026-02-04T04:54:56.926539007Z","close_reason":"Mobile experience updates complete","source_repo":".","compaction_level":0,"original_size":0,"labels":["mobile","optimization","ux"],"dependencies":[{"issue_id":"bd-3co7k.4","depends_on_id":"bd-3co7k","type":"parent-child","created_at":"2026-02-03T19:57:48.037864500Z","created_by":"ubuntu"},{"issue_id":"bd-3co7k.4","depends_on_id":"bd-3co7k.3","type":"blocks","created_at":"2026-02-03T19:57:52.847112217Z","created_by":"ubuntu"}]} +{"id":"bd-3co7k.4.1","title":"Convert Jargon Modal to BottomSheet","description":"# Convert Jargon Modal to BottomSheet\n\n## Problem Statement\nThe jargon component (apps/web/components/jargon.tsx) currently has a custom \nbottom sheet implementation for mobile. Once the BottomSheet component is \ncreated, jargon.tsx should use it for consistency and reduced code duplication.\n\n## Background\n**Current Implementation (jargon.tsx ~lines 282-336):**\nThe component already shows a bottom sheet on mobile, but it's custom-built:\n- Has escape key handling\n- Has swipe-to-close (sort of)\n- Has backdrop\n- Has drag handle\n\nThe new BottomSheet component will provide:\n- Better swipe gesture handling via useDrag\n- Consistent animation timing\n- Proper focus management\n- Accessibility improvements\n\n## Implementation Details\n\n### Step 1: Import BottomSheet\n```tsx\nimport { BottomSheet } from \"@/components/ui/bottom-sheet\";\n```\n\n### Step 2: Replace Custom Mobile Sheet\nFind the mobile sheet section (~lines 282-336) and replace with:\n\n**Before:**\n```tsx\n{/* Mobile Bottom Sheet - rendered via portal to escape stacking contexts */}\n{canUsePortal && createPortal(\n \n {isOpen && isMobile && (\n <>\n {/* Backdrop */}\n \n {/* Sheet */}\n \n {/* Handle */}\n {/* Close button */}\n {/* Content */}\n \n \n )}\n ,\n document.body\n)}\n```\n\n**After:**\n```tsx\n{/* Mobile Bottom Sheet */}\n setIsOpen(false)}\n title={`${jargonData.term} definition`}\n>\n \n\n```\n\n### Step 3: Remove Redundant Code\n- Remove custom backdrop rendering for mobile\n- Remove custom drag handle for mobile\n- Remove custom close button for mobile (BottomSheet provides it)\n- Keep desktop tooltip logic unchanged\n\n### Step 4: Ensure Desktop Tooltip Unchanged\nThe desktop tooltip (lines 232-280) should remain as-is since it's a hover popup,\nnot a modal. Only the mobile experience changes.\n\n### Step 5: Update State Management\nThe isOpen state now only controls mobile BottomSheet when isMobile is true.\nDesktop tooltip uses separate hover logic.\n\n## Testing\n- Test jargon term click on mobile (opens BottomSheet)\n- Test swipe down to close\n- Test escape key to close\n- Test backdrop click to close\n- Test close button\n- Test scroll within sheet content\n- Test desktop tooltip (unchanged)\n- Test reduced motion\n\n## Files to Modify\n- apps/web/components/jargon.tsx\n\n## Acceptance Criteria\n- [ ] Mobile jargon uses BottomSheet component\n- [ ] All previous functionality preserved (escape, backdrop, close)\n- [ ] Swipe-to-close works (via BottomSheet)\n- [ ] Desktop tooltip unchanged\n- [ ] Content scrollable within sheet\n- [ ] Safe area padding applied (via BottomSheet)\n- [ ] No visual regressions\n- [ ] Code is significantly simpler (DRY)","status":"closed","priority":2,"issue_type":"task","estimated_minutes":45,"created_at":"2026-02-03T19:58:12.921817316Z","created_by":"ubuntu","updated_at":"2026-02-04T04:54:47.225540804Z","closed_at":"2026-02-04T04:54:47.225522790Z","close_reason":"Jargon mobile uses shared BottomSheet","source_repo":".","compaction_level":0,"original_size":0,"labels":["bottom-sheet","jargon","mobile"],"dependencies":[{"issue_id":"bd-3co7k.4.1","depends_on_id":"bd-3co7k.2.1","type":"blocks","created_at":"2026-02-03T20:03:28.889039582Z","created_by":"ubuntu"},{"issue_id":"bd-3co7k.4.1","depends_on_id":"bd-3co7k.4","type":"parent-child","created_at":"2026-02-03T19:58:12.921817316Z","created_by":"ubuntu"}],"comments":[{"id":51,"issue_id":"bd-3co7k.4.1","author":"Dicklesworthstone","text":"## Testing Requirements\n\n### Unit Tests\nNo new unit tests needed - this task refactors existing code to use the BottomSheet component.\nVerify existing jargon tests still pass.\n\n### E2E Tests\nCreate: `apps/web/e2e/jargon-mobile.spec.ts`\n\n```typescript\nimport { test, expect } from '@playwright/test';\n\ntest.describe('Jargon BottomSheet on Mobile', () => {\n test.beforeEach(async ({ page }) => {\n await page.setViewportSize({ width: 375, height: 812 });\n await page.goto('/glossary');\n console.log('[E2E] Set mobile viewport and navigated to glossary');\n });\n\n test('clicking jargon term opens BottomSheet', async ({ page }) => {\n // Find a jargon-wrapped term\n const jargonTerm = page.locator('[data-jargon]').first();\n await jargonTerm.click();\n console.log('[E2E] Clicked jargon term');\n \n // Verify BottomSheet appears (not a centered modal)\n const sheet = page.getByRole('dialog');\n await expect(sheet).toBeVisible();\n \n // Verify it's positioned at bottom\n const box = await sheet.boundingBox();\n const viewport = page.viewportSize();\n console.log('[E2E] Sheet bottom:', box!.y + box!.height, 'Viewport height:', viewport!.height);\n \n // Sheet bottom should be near viewport bottom\n expect(box!.y + box!.height).toBeGreaterThan(viewport!.height - 50);\n });\n\n test('swipe down closes BottomSheet', async ({ page }) => {\n const jargonTerm = page.locator('[data-jargon]').first();\n await jargonTerm.click();\n \n const sheet = page.getByRole('dialog');\n await expect(sheet).toBeVisible();\n \n // Swipe down\n const box = await sheet.boundingBox();\n if (box) {\n await page.mouse.move(box.x + box.width / 2, box.y + 50);\n await page.mouse.down();\n await page.mouse.move(box.x + box.width / 2, box.y + 300, { steps: 10 });\n await page.mouse.up();\n console.log('[E2E] Performed swipe down');\n }\n \n await expect(sheet).not.toBeVisible({ timeout: 1000 });\n console.log('[E2E] Sheet dismissed');\n });\n\n test('desktop still uses tooltip (not BottomSheet)', async ({ page }) => {\n await page.setViewportSize({ width: 1440, height: 900 });\n await page.goto('/glossary');\n console.log('[E2E] Set desktop viewport');\n \n const jargonTerm = page.locator('[data-jargon]').first();\n await jargonTerm.hover();\n \n // Should see tooltip, not dialog\n const tooltip = page.locator('[role=\"tooltip\"]');\n await expect(tooltip).toBeVisible({ timeout: 500 });\n console.log('[E2E] Tooltip visible on desktop');\n \n // Dialog should NOT appear\n const dialog = page.getByRole('dialog');\n await expect(dialog).not.toBeVisible();\n });\n\n test('content scrollable within sheet', async ({ page }) => {\n const jargonTerm = page.locator('[data-jargon]').first();\n await jargonTerm.click();\n \n const sheet = page.getByRole('dialog');\n await expect(sheet).toBeVisible();\n \n // Try scrolling within the sheet content\n const scrollable = sheet.locator('[class*=\"overflow-y-auto\"]');\n if (await scrollable.isVisible()) {\n await scrollable.evaluate(el => el.scrollTop = 100);\n const scrollTop = await scrollable.evaluate(el => el.scrollTop);\n console.log('[E2E] Sheet content scrollTop:', scrollTop);\n // Should be scrollable if content is long enough\n }\n });\n});\n```\n","created_at":"2026-02-03T20:06:04Z"}]} +{"id":"bd-3co7k.4.2","title":"Mobile Navigation Thumb-Zone Optimization","description":"# Mobile Navigation Thumb-Zone Optimization\n\n## Problem Statement\nPrimary navigation and CTAs should be in the \"thumb zone\" - the bottom third of\nthe screen where users can easily reach with one hand. Currently, some navigation\nelements are at the top of the screen, requiring uncomfortable reaches on large phones.\n\n## Background\n**Thumb Zone Studies:**\n- 75% of users operate phones with one hand\n- Bottom of screen is most comfortable to reach\n- Top corners are \"danger zones\" (hard to reach)\n- iOS tab bar and Android navigation bar are both at bottom\n\n**Current State:**\n- Wizard has bottom stepper (good!)\n- Main navigation header is at top (standard but not optimal for mobile)\n- Some inline CTAs are mid-page (OK for content flow)\n- Fixed bottom actions exist in some places\n\n**Goal:**\n- Ensure primary actions are reachable\n- Consider sticky bottom CTA on key conversion pages\n- Audit all fixed elements for safe area handling\n\n## Implementation Details\n\n### Step 1: Audit Fixed Bottom Elements\nCheck all pages for fixed/sticky bottom elements:\n```bash\ngrep -r \"fixed.*bottom\\|sticky.*bottom\" apps/web/\n```\n\nEnsure all have:\n- `pb-safe` or `pb-[env(safe-area-inset-bottom)]`\n- Minimum 44px touch targets\n- Proper z-index layering\n\n### Step 2: Add Sticky Bottom CTA to Key Pages\nFor high-conversion pages (wizard completion, learn start), consider:\n```tsx\n{/* Sticky bottom CTA - mobile only */}\n
\n
\n \n
\n
\n\n{/* Spacer to prevent content overlap */}\n
\n```\n\n### Step 3: Evaluate Bottom Tab Navigation (Optional)\nFor the learning hub (/learn), consider bottom tab navigation on mobile:\n```tsx\n// Mobile only - shows at bottom\n\n```\n\nNote: This is a significant UX change and may be out of scope.\n\n### Step 4: Mobile Header Simplification\nOn mobile, the header could be simplified:\n- Logo/title\n- Hamburger menu (opens full-screen nav)\n- Remove secondary links (move to menu)\n\nThis reduces visual clutter and keeps focus on content.\n\n### Step 5: Safe Area Audit\nCheck all fixed elements have proper safe area handling:\n\n**Files to check:**\n- apps/web/app/wizard/layout.tsx (stepper)\n- apps/web/components/jargon.tsx (bottom sheet)\n- apps/web/app/layout.tsx (header?)\n- Any page with fixed CTAs\n\n**Pattern:**\n```tsx\nclassName=\"pb-safe\" // or\nclassName=\"pb-[calc(1rem+env(safe-area-inset-bottom))]\"\n```\n\n### Step 6: Touch Target Audit\nFind any touch targets under 44px on mobile:\n```bash\ngrep -r \"h-8\\|w-8\\|h-6\\|w-6\" apps/web/components/\n```\n\nIncrease to h-10/w-10 minimum or add padding.\n\n## Testing\n- Test on iPhone with notch (safe area bottom)\n- Test on iPhone without notch\n- Test on Android with gesture navigation\n- Test reach-ability of primary CTAs\n- Test sticky bottom CTA doesn't overlap content\n- Test bottom navigation (if implemented)\n\n## Files to Modify\n- apps/web/app/wizard/layout.tsx (audit)\n- apps/web/app/layout.tsx (possible mobile header changes)\n- Various pages (add sticky CTAs if needed)\n\n## Acceptance Criteria\n- [ ] All fixed bottom elements have safe area padding\n- [ ] All touch targets are minimum 44px\n- [ ] Primary CTAs are reachable on large phones\n- [ ] No content hidden behind fixed elements\n- [ ] Sticky bottom CTAs (if added) are useful, not annoying\n- [ ] Header works well on mobile (simplified if needed)","status":"closed","priority":2,"issue_type":"task","estimated_minutes":60,"created_at":"2026-02-03T19:58:37.718786555Z","created_by":"ubuntu","updated_at":"2026-02-04T04:54:53.196270734Z","closed_at":"2026-02-04T04:54:53.196247600Z","close_reason":"Added mobile thumb-zone nav to glossary","source_repo":".","compaction_level":0,"original_size":0,"labels":["mobile","navigation","ux"],"dependencies":[{"issue_id":"bd-3co7k.4.2","depends_on_id":"bd-3co7k.4","type":"parent-child","created_at":"2026-02-03T19:58:37.718786555Z","created_by":"ubuntu"}],"comments":[{"id":52,"issue_id":"bd-3co7k.4.2","author":"Dicklesworthstone","text":"## Testing Requirements\n\n### Unit Tests\nNo specific unit tests - this is primarily an audit and CSS adjustments task.\n\n### E2E Tests\nCreate: `apps/web/e2e/mobile-navigation.spec.ts`\n\n```typescript\nimport { test, expect } from '@playwright/test';\n\ntest.describe('Mobile Navigation & Thumb Zone', () => {\n test.beforeEach(async ({ page }) => {\n // iPhone 14 Pro Max viewport (largest common phone)\n await page.setViewportSize({ width: 430, height: 932 });\n console.log('[E2E] Set large phone viewport');\n });\n\n test('all fixed bottom elements have safe area padding', async ({ page }) => {\n await page.goto('/wizard/os-selection');\n console.log('[E2E] Navigated to wizard');\n \n // Find fixed bottom elements\n const fixedBottom = page.locator('[class*=\"fixed\"][class*=\"bottom\"]');\n const count = await fixedBottom.count();\n console.log('[E2E] Found', count, 'fixed bottom elements');\n \n for (let i = 0; i < count; i++) {\n const el = fixedBottom.nth(i);\n const paddingBottom = await el.evaluate(el => \n getComputedStyle(el).paddingBottom\n );\n console.log(\\`[E2E] Element \\${i} paddingBottom: \\${paddingBottom}\\`);\n // Should have some padding for safe area\n expect(parseInt(paddingBottom)).toBeGreaterThan(0);\n }\n });\n\n test('all touch targets meet 44px minimum', async ({ page }) => {\n await page.goto('/');\n \n // Find all buttons and links\n const interactives = page.locator('button, a[href], [role=\"button\"]');\n const count = await interactives.count();\n console.log('[E2E] Checking', count, 'interactive elements');\n \n let violations = 0;\n for (let i = 0; i < Math.min(count, 20); i++) { // Check first 20\n const el = interactives.nth(i);\n const box = await el.boundingBox();\n if (box && (box.width < 44 || box.height < 44)) {\n const text = await el.textContent();\n console.log(\\`[E2E] Touch target violation: \"\\${text?.slice(0, 20)}\" is \\${box.width}x\\${box.height}\\`);\n violations++;\n }\n }\n \n console.log('[E2E] Total touch target violations:', violations);\n // Allow some violations for inline links, but flag major issues\n expect(violations).toBeLessThan(5);\n });\n\n test('primary CTAs are in thumb zone', async ({ page }) => {\n await page.goto('/');\n \n // Find primary CTA buttons\n const ctaButtons = page.locator('button[class*=\"primary\"], a[class*=\"primary\"]');\n const viewport = page.viewportSize()!;\n const thumbZoneY = viewport.height * 0.67; // Bottom third\n \n const count = await ctaButtons.count();\n console.log('[E2E] Found', count, 'primary CTAs');\n \n for (let i = 0; i < count; i++) {\n const box = await ctaButtons.nth(i).boundingBox();\n if (box) {\n const isInThumbZone = box.y > thumbZoneY;\n console.log(\\`[E2E] CTA \\${i} at y=\\${box.y}, in thumb zone: \\${isInThumbZone}\\`);\n }\n }\n });\n\n test('no content hidden behind fixed elements', async ({ page }) => {\n await page.goto('/wizard/os-selection');\n \n // Scroll to bottom\n await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));\n await page.waitForTimeout(200);\n \n // Check last content element is visible above fixed footer\n const lastContent = page.locator('main > *:last-child');\n const contentBox = await lastContent.boundingBox();\n \n const fixedBottom = page.locator('[class*=\"fixed\"][class*=\"bottom\"]').first();\n const fixedBox = await fixedBottom.boundingBox();\n \n if (contentBox && fixedBox) {\n console.log('[E2E] Content ends at:', contentBox.y + contentBox.height);\n console.log('[E2E] Fixed element starts at:', fixedBox.y);\n \n // Content should end before fixed element starts\n expect(contentBox.y + contentBox.height).toBeLessThanOrEqual(fixedBox.y + 10);\n }\n });\n});\n```\n","created_at":"2026-02-03T20:06:20Z"}]} {"id":"bd-3fd3","title":"JFP: Switch installer to official CLI + checksums","description":"Align JFP install with official CLI script and checksum verification.\\n\\nScope:\\n- Update acfs.manifest.yaml stack.jeffreysprompts to use verified_installer with official install CLI (https://jeffreysprompts.com/install-cli.sh).\\n- Add checksums.yaml entry for jfp installer (compute sha256 via scripts/lib/security.sh --checksum).\\n- Regenerate scripts if needed (packages/manifest).\\n\\nValidation:\\n- bun run generate:validate (packages/manifest) if convenient; otherwise note not run.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-21T09:45:44.088710307Z","created_by":"ubuntu","updated_at":"2026-01-21T09:52:51.548924906Z","closed_at":"2026-01-21T09:52:51.548479497Z","close_reason":"Completed","source_repo":".","compaction_level":0,"original_size":0} {"id":"bd-3hg8","title":"Fix Codex CLI install (npm 404 @openai/codex version)","status":"closed","priority":1,"issue_type":"bug","created_at":"2026-01-21T19:25:19.742598724Z","created_by":"ubuntu","updated_at":"2026-01-21T21:59:54.187519815Z","closed_at":"2026-01-21T21:59:54.187473077Z","close_reason":"Added pinned version fallback (0.87.0) to both install.sh and update.sh when @latest and unversioned npm installs fail due to transient 404s","source_repo":".","compaction_level":0,"original_size":0,"dependencies":[{"issue_id":"bd-3hg8","depends_on_id":"bd-pkta","type":"discovered-from","created_at":"2026-01-21T19:25:19.772924267Z","created_by":"ubuntu"}]} {"id":"bd-3jd9","title":"acfs export-config: Export current config command","description":"## Overview\nAdd `acfs export-config` command to export current ACFS configuration for backup or migration to another machine.\n\n## Use Cases\n- Backup before reinstall\n- Share config with teammates\n- Migrate to new VPS\n- Version control your setup\n\n## Export Format\n```yaml\n# acfs-config-export.yaml\n# Generated: 2026-01-25T23:00:00Z\n# Hostname: my-vps\n# ACFS Version: 1.0.0\n\nmodules:\n - core\n - dev\n - shell\n\ntools:\n rust: { version: \"1.79.0\", installed: true }\n bun: { version: \"1.1.38\", installed: true }\n zoxide: { version: \"0.9.4\", installed: true }\n\nsettings:\n shell: zsh\n editor: nvim\n theme: dark\n```\n\n## Commands\n```bash\nacfs export-config # Print to stdout\nacfs export-config > my-config.yaml # Save to file\nacfs export-config --json # JSON format\nacfs export-config --minimal # Just module list\n```\n\n## Import (Future)\n```bash\n# Future enhancement (not in this bead)\nacfs import-config my-config.yaml\n```\n\n## Implementation Details\n1. Read current state.json\n2. Query installed tool versions\n3. Format as YAML or JSON\n4. Add metadata (timestamp, hostname, version)\n5. Exclude sensitive data (tokens, keys)\n\n## Sensitive Data Handling\n- NEVER export: SSH keys, API tokens, passwords\n- NEVER export: Full paths containing username\n- DO export: Tool selections, versions, preferences\n\n## Test Plan\n- [ ] Test YAML output is valid\n- [ ] Test JSON output is valid\n- [ ] Test no sensitive data in output\n- [ ] Test --minimal output\n- [ ] Test output on fresh install\n\n## Files to Create\n- scripts/commands/export-config.sh","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-25T23:02:44.767369417Z","created_by":"ubuntu","updated_at":"2026-01-27T03:42:00.984354669Z","closed_at":"2026-01-27T03:42:00.984336184Z","close_reason":"Implemented acfs export-config command: YAML/JSON/minimal output, tool version detection for 30+ tools, secure (no sensitive data). Created export-config.sh and updated acfs.zshrc.","source_repo":".","compaction_level":0,"original_size":0,"dependencies":[{"issue_id":"bd-3jd9","depends_on_id":"bd-3y1n","type":"blocks","created_at":"2026-01-25T23:04:58.683105133Z","created_by":"ubuntu"}]} {"id":"bd-3k2f","title":"Subtask: Add remediation logging to doctor","status":"closed","priority":2,"issue_type":"subtask","created_at":"2026-01-25T23:21:16.780150760Z","created_by":"ubuntu","updated_at":"2026-01-27T02:13:26.380121120Z","closed_at":"2026-01-27T02:13:26.380102184Z","close_reason":"Already implemented in doctor_fix.sh - DOCTOR_FIX_LOG with doctor_fix_log() function provides comprehensive remediation logging","source_repo":".","compaction_level":0,"original_size":0} +{"id":"bd-3kng","title":"Fix zoxide installation to avoid GitHub API rate limits in CI","status":"closed","priority":1,"issue_type":"bug","created_at":"2026-02-03T06:03:35.130030786Z","created_by":"ubuntu","updated_at":"2026-02-03T06:04:43.963205020Z","closed_at":"2026-02-03T06:04:43.963186034Z","close_reason":"Fixed by preferring apt install for zoxide (commit 7b3b5357)","source_repo":".","compaction_level":0,"original_size":0} {"id":"bd-3kug","title":"Deep exploration: BV (Beads Viewer)","description":"## Goal\nPerform deep exploration of BV (Beads Viewer) and revise its description with comprehensive testing.\n\n## Phase 0: Pre-flight Verification\n\n```bash\n#!/bin/bash\nLOG=/tmp/bv-preflight.log\necho \"=== BV Pre-flight ===\" | tee $LOG\n\n[[ -d /dp/beads_viewer ]] && echo \"PASS: Directory exists\" || exit 1\ncommand -v bv &>/dev/null && echo \"PASS: bv installed\" || echo \"WARN: bv not in PATH\"\nbv --version 2>&1 | tee -a $LOG\n\nSNAPSHOT_DIR=/tmp/bv-exploration-snapshots\nmkdir -p $SNAPSHOT_DIR\ncp /data/projects/agentic_coding_flywheel_setup/apps/web/lib/flywheel.ts $SNAPSHOT_DIR/flywheel.ts.before\ncp /data/projects/agentic_coding_flywheel_setup/apps/web/lib/tldr-content.ts $SNAPSHOT_DIR/tldr-content.ts.before\n```\n\n## Phase 1: Research\n\n### 1.1 Documentation\n- cat /dp/beads_viewer/README.md\n- Check AGENTS.md if exists\n\n### 1.2 Code Investigation\n- Graph algorithms: PageRank, Betweenness, HITS, Eigenvector\n- Robot modes: --robot-triage, --robot-suggest, --robot-insights, --robot-next\n- How it reads br/bd JSONL data\n- Output JSON schemas\n- Critical path computation\n\n### 1.3 Verify Algorithms\n```bash\n#!/bin/bash\necho \"=== BV Algorithm Verification ===\"\nbv --robot-triage 2>&1 | jq '.triage.recommendations[0].breakdown.pagerank' && echo \"PASS: PageRank\" || echo \"FAIL\"\nbv --robot-triage 2>&1 | jq '.triage.recommendations[0].breakdown.betweenness' && echo \"PASS: Betweenness\" || echo \"FAIL\"\nbv --robot-triage >/dev/null 2>&1 && echo \"PASS: --robot-triage\" || echo \"FAIL\"\nbv --robot-suggest >/dev/null 2>&1 && echo \"PASS: --robot-suggest\" || echo \"FAIL\"\nbv --robot-insights >/dev/null 2>&1 && echo \"PASS: --robot-insights\" || echo \"FAIL\"\n```\n\n### 1.4 External Context\n- /xf search 'bv OR beads_viewer'\n- cass search 'bv triage pagerank' --robot --limit 10\n\n## Phase 2: Analysis\n\nDocument with VERIFICATION:\n- [ ] PageRank: VERIFIED working\n- [ ] Betweenness: VERIFIED working\n- [ ] HITS: VERIFIED working\n- [ ] Eigenvector: VERIFIED working\n- [ ] Robot modes: list VERIFIED working modes\n- [ ] Tech stack: ACTUAL language (Rust)\n- [ ] Synergies VERIFIED:\n - [ ] br: reads JSONL from br\n - [ ] mail: any integration?\n - [ ] ntm: any integration?\n\n## Phase 3: Revision\n\nUpdate with VERIFIED capabilities only:\n- Only list algorithms that actually work\n- Only list robot modes that are implemented\n- Only list synergies that exist\n\n## Phase 4: Testing\n\n```bash\ncd /data/projects/agentic_coding_flywheel_setup/apps/web\nbun run type-check 2>&1 | tee /tmp/bv-typecheck.log\nbun run lint 2>&1 | tee /tmp/bv-lint.log\nbun run build 2>&1 | tee /tmp/bv-build.log\n\n# E2E\nlsof -t -i :3000 | xargs kill 2>/dev/null; sleep 2\nbun run dev &\nsleep 10\ncurl -sL http://localhost:3000/flywheel | grep -qi 'bv' && echo \"PASS\" || echo \"FAIL\"\ncurl -sL http://localhost:3000/tldr | grep -qi 'bv' && echo \"PASS\" || echo \"FAIL\"\nkill %1\n```\n\n## Phase 5: Commit\n\n```bash\ngit add apps/web/lib/flywheel.ts apps/web/lib/tldr-content.ts\ngit commit -m \"docs(flywheel): update BV with verified graph algorithms\n\n- Verified PageRank, Betweenness, HITS implementations\n- Verified robot mode commands\n- Tested against actual bv output\n\nCo-Authored-By: Claude Opus 4.5 \"\n\nbr update bd-3kug --status closed\nbr sync --flush-only && git add .beads/ && git push\n```\n\n## Acceptance Criteria\n- [ ] All graph algorithms VERIFIED\n- [ ] All robot modes VERIFIED\n- [ ] Tech stack VERIFIED\n- [ ] All tests PASS\n- [ ] Pushed","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-26T20:00:41.614753229Z","created_by":"ubuntu","updated_at":"2026-01-27T02:42:21.606122487Z","closed_at":"2026-01-27T02:42:21.606099433Z","close_reason":"Verified and updated BV entry in flywheel.ts and tldr-content.ts","source_repo":".","compaction_level":0,"original_size":0} {"id":"bd-3ljs","title":"Deep exploration: NTM (Named Tmux Manager)","description":"## Goal\nPerform deep exploration of NTM (Named Tmux Manager) and revise its description on the flywheel/TLDR pages with comprehensive testing and validation.\n\n## Phase 0: Pre-flight Verification (CRITICAL)\n\n### 0.1 Tool Existence Check\n```bash\n#!/bin/bash\nLOG=/tmp/ntm-preflight.log\necho \"=== NTM Pre-flight Check: $(date) ===\" | tee $LOG\n\n# Verify tool directory exists\nif [[ -d /dp/ntm ]]; then\n echo \"PASS: /dp/ntm directory exists\" | tee -a $LOG\nelse\n echo \"FAIL: /dp/ntm directory NOT FOUND - aborting\" | tee -a $LOG\n exit 1\nfi\n\n# Verify README exists\nif [[ -f /dp/ntm/README.md ]]; then\n echo \"PASS: README.md exists\" | tee -a $LOG\nelse\n echo \"WARN: README.md not found\" | tee -a $LOG\nfi\n\n# Verify tool is installed and executable\nif command -v ntm &>/dev/null; then\n echo \"PASS: ntm command available: $(which ntm)\" | tee -a $LOG\n ntm --version 2>&1 | tee -a $LOG || echo \"No --version flag\" | tee -a $LOG\nelse\n echo \"WARN: ntm command not in PATH\" | tee -a $LOG\nfi\n```\n\n### 0.2 Content Snapshot (BEFORE State)\n```bash\n#!/bin/bash\nSNAPSHOT_DIR=/tmp/ntm-exploration-snapshots\nmkdir -p $SNAPSHOT_DIR\n\n# Capture current state for diff comparison later\ncp /data/projects/agentic_coding_flywheel_setup/apps/web/lib/flywheel.ts $SNAPSHOT_DIR/flywheel.ts.before\ncp /data/projects/agentic_coding_flywheel_setup/apps/web/lib/tldr-content.ts $SNAPSHOT_DIR/tldr-content.ts.before\n\n# Extract current NTM entry from flywheel.ts for reference\ngrep -A 100 \"id: 'ntm'\" /data/projects/agentic_coding_flywheel_setup/apps/web/lib/flywheel.ts | head -100 > $SNAPSHOT_DIR/ntm-flywheel-entry.before.txt\n\necho \"Snapshots saved to $SNAPSHOT_DIR\"\nls -la $SNAPSHOT_DIR\n```\n\n### 0.3 Verify TypeScript Interfaces\n```bash\n# Check the FlywheelTool interface we must conform to\ngrep -A 30 \"export interface FlywheelTool\" /data/projects/agentic_coding_flywheel_setup/apps/web/lib/flywheel.ts\ngrep -A 30 \"export interface TldrFlywheelTool\" /data/projects/agentic_coding_flywheel_setup/apps/web/lib/tldr-content.ts\n```\n\n## Phase 1: Research (GATHER CONTEXT)\n\n### 1.1 Primary Documentation\n```bash\n# Read full README with line count for reference\nwc -l /dp/ntm/README.md\ncat /dp/ntm/README.md\n\n# Check for additional docs\nls -la /dp/ntm/docs/ 2>/dev/null || echo \"No docs/ directory\"\ncat /dp/ntm/AGENTS.md 2>/dev/null || echo \"No AGENTS.md\"\ncat /dp/ntm/CONTRIBUTING.md 2>/dev/null || echo \"No CONTRIBUTING.md\"\n```\n\n### 1.2 Code Investigation\n- Launch code investigation agent to understand:\n - Architecture and key files (main entry point, core modules)\n - Tmux session naming and management logic\n - How it spawns and tracks agent sessions\n - Integration points with other flywheel tools\n - Key CLI commands: `ntm spawn`, `ntm list`, `ntm kill`, `ntm attach`\n - Configuration files and defaults\n\n### 1.3 External Context Search\n```bash\n# Twitter archive search\n/xf search 'ntm OR \"named tmux manager\" OR \"tmux session\"' 2>&1 | head -50\n\n# Past agent session insights \ncass search 'ntm tmux spawn' --robot --limit 10 2>&1\n\n# Look for practical use cases\ncass search 'ntm workflow' --robot --limit 5 2>&1\n```\n\n### 1.4 Project State Review\n```bash\n# Check beads\nls -la /dp/ntm/.beads/ 2>/dev/null || echo \"No .beads directory\"\nbr list 2>/dev/null | grep -i ntm || echo \"No ntm-related beads found\"\n\n# Recent commits\ncd /dp/ntm && git log --oneline -20 && cd -\n\n# Any plan documents\nfind /dp/ntm -name \"*.md\" -type f 2>/dev/null | head -10\n```\n\n### 1.5 CLI Command Inventory\n```bash\n# Get actual CLI help\nntm --help 2>&1 || echo \"ntm --help failed\"\nntm help 2>&1 || echo \"ntm help failed\"\n\n# List actual subcommands available\nntm 2>&1 | head -30\n```\n\n## Phase 2: Analysis (SYNTHESIZE UNDERSTANDING)\n\nDocument findings for each area (fill in during research):\n- [ ] Core functionality: [describe tmux session management]\n- [ ] Key commands verified working: [list commands tested]\n- [ ] Synergies VERIFIED (not assumed):\n - [ ] mail: [how does ntm use mail? does it?]\n - [ ] caam: [how does ntm use caam for account switching?] \n - [ ] slb: [any slb integration?]\n - [ ] srps: [resource protection integration?]\n - [ ] ru: [repo update integration?]\n- [ ] Tech stack verified: [language, dependencies]\n- [ ] Performance characteristics: [startup time, memory usage]\n- [ ] Known limitations discovered: [list any]\n\n## Phase 3: Revision (UPDATE DESCRIPTIONS)\n\n### 3.1 Update apps/web/lib/flywheel.ts\nUpdate the ntm entry ensuring TypeScript interface compliance:\n```typescript\n// Required fields per FlywheelTool interface:\n{\n id: 'ntm', // must be lowercase, unique\n name: string, // full name\n shortName: string, // abbreviated\n href: string, // valid URL or path\n icon: LucideIcon, // must be valid Lucide icon\n color: string, // valid Tailwind color\n tagline: string, // concise (<80 chars)\n description: string, // 1-2 sentences\n deepDescription: string, // detailed explanation\n connectsTo: string[], // VERIFIED synergy IDs only\n connectionDescriptions: Record, // must match connectsTo\n stars: number, // GitHub stars\n features: string[], // VERIFIED features only\n cliCommands: { command: string; description: string }[], // TESTED commands\n installCommand: string, // working install command\n language: string, // actual language\n}\n```\n\n### 3.2 Update apps/web/lib/tldr-content.ts \nUpdate ensuring TldrFlywheelTool interface compliance:\n```typescript\n{\n id: 'ntm',\n name: string,\n shortName: string,\n href: string,\n icon: LucideIcon,\n color: string,\n category: 'core' | 'supporting',\n stars: number,\n whatItDoes: string, // clear, accurate\n whyItsUseful: string, // real value proposition\n implementationHighlights: string[], // verified technical details\n synergies: string[], // VERIFIED connections only\n techStack: string[], // actual technologies\n keyFeatures: string[], // verified features\n useCases: string[], // realistic scenarios\n}\n```\n\n### 3.3 Cross-reference Validation\n```bash\n# After updating NTM synergies, verify reciprocal connections exist\n# If NTM lists \"caam\" in connectsTo, then caam entry must list \"ntm\"\nSYNERGIES=$(grep -A5 \"id: 'ntm'\" /data/projects/agentic_coding_flywheel_setup/apps/web/lib/flywheel.ts | grep -o \"connectsTo.*\" | head -1)\necho \"NTM synergies: $SYNERGIES\"\n\n# Check each synergy has reciprocal\nfor tool in caam mail slb; do\n if grep -A10 \"id: '$tool'\" /data/projects/agentic_coding_flywheel_setup/apps/web/lib/flywheel.ts | grep -q \"ntm\"; then\n echo \"PASS: $tool lists ntm as synergy\"\n else\n echo \"WARN: $tool does NOT list ntm - may need update\"\n fi\ndone\n```\n\n### 3.4 De-slopify\n- Run `/de-slopify` on all revised descriptions\n- Remove: \"harness\", \"empower\", \"leverage\", \"robust\", \"seamless\", \"cutting-edge\"\n- Ensure authentic, technically accurate voice\n- Verify no placeholder text remains\n\n## Phase 4: Testing (VERIFY QUALITY)\n\n### 4.1 Static Analysis\n```bash\n#!/bin/bash\nLOG=/tmp/ntm-static-analysis.log\necho \"=== NTM Static Analysis: $(date) ===\" | tee $LOG\n\ncd /data/projects/agentic_coding_flywheel_setup/apps/web\n\necho \"--- Type Check ---\" | tee -a $LOG\nbun run type-check 2>&1 | tee -a $LOG\nTYPE_EXIT=$?\necho \"Type Check Exit Code: $TYPE_EXIT\" | tee -a $LOG\n\necho \"--- Lint Check ---\" | tee -a $LOG \nbun run lint 2>&1 | tee -a $LOG\nLINT_EXIT=$?\necho \"Lint Exit Code: $LINT_EXIT\" | tee -a $LOG\n\nif [[ $TYPE_EXIT -ne 0 ]] || [[ $LINT_EXIT -ne 0 ]]; then\n echo \"FAIL: Static analysis failed - DO NOT PROCEED\" | tee -a $LOG\n exit 1\nfi\necho \"PASS: Static analysis succeeded\" | tee -a $LOG\n```\n\n### 4.2 Build Verification\n```bash\n#!/bin/bash\nLOG=/tmp/ntm-build.log\necho \"=== NTM Build Test: $(date) ===\" | tee $LOG\n\ncd /data/projects/agentic_coding_flywheel_setup/apps/web\nbun run build 2>&1 | tee -a $LOG\nBUILD_EXIT=$?\necho \"Build Exit Code: $BUILD_EXIT\" | tee -a $LOG\n\nif [[ $BUILD_EXIT -ne 0 ]]; then\n echo \"FAIL: Build failed - ROLLBACK REQUIRED\" | tee -a $LOG\n echo \"Restoring from snapshot...\" | tee -a $LOG\n cp /tmp/ntm-exploration-snapshots/flywheel.ts.before lib/flywheel.ts\n cp /tmp/ntm-exploration-snapshots/tldr-content.ts.before lib/tldr-content.ts\n exit 1\nfi\necho \"PASS: Build succeeded\" | tee -a $LOG\n```\n\n### 4.3 E2E Visual Verification\n```bash\n#!/bin/bash\nLOG=/tmp/ntm-e2e.log\necho \"=== NTM E2E Test: $(date) ===\" | tee $LOG\n\ncd /data/projects/agentic_coding_flywheel_setup/apps/web\n\n# Check if port 3000 is already in use\nif lsof -i :3000 &>/dev/null; then\n echo \"WARN: Port 3000 already in use, killing existing process\" | tee -a $LOG\n kill $(lsof -t -i :3000) 2>/dev/null\n sleep 2\nfi\n\n# Start dev server\nbun run dev &\nDEV_PID=$!\necho \"Dev server PID: $DEV_PID\" | tee -a $LOG\n\n# Wait for server to be ready (with timeout)\necho \"Waiting for server...\" | tee -a $LOG\nfor i in {1..30}; do\n if curl -s --max-time 2 http://localhost:3000 &>/dev/null; then\n echo \"Server ready after ${i}s\" | tee -a $LOG\n break\n fi\n sleep 1\ndone\n\n# Test flywheel page\necho \"--- Testing /flywheel ---\" | tee -a $LOG\nFLYWHEEL_RESP=$(curl -sL --max-time 10 http://localhost:3000/flywheel 2>&1)\nif echo \"$FLYWHEEL_RESP\" | grep -qi 'ntm'; then\n echo \"PASS: NTM found on /flywheel\" | tee -a $LOG\nelse\n echo \"FAIL: NTM not found on /flywheel\" | tee -a $LOG\nfi\n\n# Test tldr page\necho \"--- Testing /tldr ---\" | tee -a $LOG\nTLDR_RESP=$(curl -sL --max-time 10 http://localhost:3000/tldr 2>&1)\nif echo \"$TLDR_RESP\" | grep -qi 'ntm'; then\n echo \"PASS: NTM found on /tldr\" | tee -a $LOG\nelse\n echo \"FAIL: NTM not found on /tldr\" | tee -a $LOG\nfi\n\n# Check for console errors (look in dev server output)\necho \"--- Checking for errors ---\" | tee -a $LOG\nif echo \"$FLYWHEEL_RESP\" | grep -qi 'error\\|exception'; then\n echo \"WARN: Possible errors detected in response\" | tee -a $LOG\nfi\n\n# Cleanup\nkill $DEV_PID 2>/dev/null\necho \"=== E2E Complete ===\" | tee -a $LOG\n```\n\n### 4.4 Unit Tests: Content Integrity\n```bash\n#!/bin/bash\nLOG=/tmp/ntm-unit-tests.log\necho \"=== NTM Content Unit Tests: $(date) ===\" | tee $LOG\n\ncd /data/projects/agentic_coding_flywheel_setup/apps/web\n\n# Test 1: NTM entry exists in flywheel.ts\necho \"Test 1: NTM entry exists in flywheel.ts\" | tee -a $LOG\nif grep -q \"id: 'ntm'\" lib/flywheel.ts; then\n echo \" PASS\" | tee -a $LOG\nelse\n echo \" FAIL: ntm entry not found\" | tee -a $LOG\nfi\n\n# Test 2: Required fields are non-empty\necho \"Test 2: Required fields non-empty\" | tee -a $LOG\nNTM_ENTRY=$(grep -A 50 \"id: 'ntm'\" lib/flywheel.ts | head -50)\nfor field in tagline description deepDescription; do\n if echo \"$NTM_ENTRY\" | grep -q \"$field: '[^']\\+'\"; then\n echo \" PASS: $field is non-empty\" | tee -a $LOG\n else\n echo \" WARN: $field may be empty\" | tee -a $LOG\n fi\ndone\n\n# Test 3: connectsTo and connectionDescriptions match\necho \"Test 3: Synergy consistency\" | tee -a $LOG\nCONNECTS=$(echo \"$NTM_ENTRY\" | grep -o \"connectsTo: \\[.*\\]\" | head -1)\necho \" connectsTo: $CONNECTS\" | tee -a $LOG\n\n# Test 4: cliCommands have both command and description\necho \"Test 4: CLI commands complete\" | tee -a $LOG\nif echo \"$NTM_ENTRY\" | grep -q \"cliCommands:\"; then\n echo \" PASS: cliCommands field exists\" | tee -a $LOG\nelse\n echo \" FAIL: cliCommands missing\" | tee -a $LOG\nfi\n\n# Test 5: NTM in tldr-content.ts\necho \"Test 5: NTM in tldr-content.ts\" | tee -a $LOG\nif grep -q \"id: 'ntm'\" lib/tldr-content.ts; then\n echo \" PASS: NTM in tldr-content.ts\" | tee -a $LOG\nelse\n echo \" FAIL: NTM not in tldr-content.ts\" | tee -a $LOG\nfi\n\n# Test 6: Diff from original (should have changes)\necho \"Test 6: Content actually changed\" | tee -a $LOG\nif diff -q lib/flywheel.ts /tmp/ntm-exploration-snapshots/flywheel.ts.before &>/dev/null; then\n echo \" WARN: flywheel.ts unchanged - was update applied?\" | tee -a $LOG\nelse\n echo \" PASS: flywheel.ts has changes\" | tee -a $LOG\n diff --brief lib/flywheel.ts /tmp/ntm-exploration-snapshots/flywheel.ts.before | tee -a $LOG\nfi\n\necho \"=== Unit Tests Complete ===\" | tee -a $LOG\n```\n\n### 4.5 CLI Command Verification\n```bash\n#!/bin/bash\nLOG=/tmp/ntm-cli-tests.log\necho \"=== NTM CLI Command Tests: $(date) ===\" | tee $LOG\n\n# Test each CLI command mentioned in the updated content\n# Extract commands from flywheel.ts and verify they work\n\necho \"Testing ntm commands...\" | tee -a $LOG\n\n# Test: ntm list (should work without error)\necho \"--- ntm list ---\" | tee -a $LOG\nntm list 2>&1 | tee -a $LOG\necho \"Exit code: $?\" | tee -a $LOG\n\n# Test: ntm --help\necho \"--- ntm --help ---\" | tee -a $LOG\nntm --help 2>&1 | tee -a $LOG\necho \"Exit code: $?\" | tee -a $LOG\n\n# Add more command tests based on documented commands\necho \"=== CLI Tests Complete ===\" | tee -a $LOG\n```\n\n### 4.6 Consolidated Test Results Log\n```bash\n#!/bin/bash\nRESULTS=/tmp/ntm-exploration-test-results.log\necho \"=============================================\" > $RESULTS\necho \" NTM DEEP EXPLORATION TEST RESULTS\" >> $RESULTS \necho \"=============================================\" >> $RESULTS\necho \"Date: $(date)\" >> $RESULTS\necho \"Agent: $(whoami)\" >> $RESULTS\necho \"\" >> $RESULTS\n\necho \"=== PRE-FLIGHT ===\" >> $RESULTS\ncat /tmp/ntm-preflight.log >> $RESULTS 2>/dev/null || echo \"No preflight log\" >> $RESULTS\necho \"\" >> $RESULTS\n\necho \"=== STATIC ANALYSIS ===\" >> $RESULTS\ngrep -E \"PASS|FAIL|Exit Code\" /tmp/ntm-static-analysis.log >> $RESULTS 2>/dev/null\necho \"\" >> $RESULTS\n\necho \"=== BUILD ===\" >> $RESULTS\ngrep -E \"PASS|FAIL|Exit Code\" /tmp/ntm-build.log >> $RESULTS 2>/dev/null\necho \"\" >> $RESULTS\n\necho \"=== E2E ===\" >> $RESULTS\ngrep -E \"PASS|FAIL|WARN\" /tmp/ntm-e2e.log >> $RESULTS 2>/dev/null\necho \"\" >> $RESULTS\n\necho \"=== UNIT TESTS ===\" >> $RESULTS\ngrep -E \"PASS|FAIL|WARN\" /tmp/ntm-unit-tests.log >> $RESULTS 2>/dev/null\necho \"\" >> $RESULTS\n\necho \"=== CLI TESTS ===\" >> $RESULTS\ngrep -E \"Exit code\" /tmp/ntm-cli-tests.log >> $RESULTS 2>/dev/null\necho \"\" >> $RESULTS\n\necho \"=== CONTENT DIFF ===\" >> $RESULTS\ndiff /tmp/ntm-exploration-snapshots/flywheel.ts.before /data/projects/agentic_coding_flywheel_setup/apps/web/lib/flywheel.ts >> $RESULTS 2>/dev/null | head -50\necho \"\" >> $RESULTS\n\necho \"=============================================\" >> $RESULTS\necho \" SUMMARY\" >> $RESULTS\necho \"=============================================\" >> $RESULTS\nPASS_COUNT=$(grep -c \"PASS\" $RESULTS)\nFAIL_COUNT=$(grep -c \"FAIL\" $RESULTS)\nWARN_COUNT=$(grep -c \"WARN\" $RESULTS)\necho \"PASS: $PASS_COUNT\" >> $RESULTS\necho \"FAIL: $FAIL_COUNT\" >> $RESULTS\necho \"WARN: $WARN_COUNT\" >> $RESULTS\n\nif [[ $FAIL_COUNT -gt 0 ]]; then\n echo \"\" >> $RESULTS\n echo \"!!! FAILURES DETECTED - DO NOT COMMIT !!!\" >> $RESULTS\nfi\n\ncat $RESULTS\n```\n\n## Phase 5: Commit (FINALIZE)\n\n### 5.1 Pre-commit Validation\n```bash\n# Only proceed if all tests pass\nFAIL_COUNT=$(grep -c \"FAIL\" /tmp/ntm-exploration-test-results.log)\nif [[ $FAIL_COUNT -gt 0 ]]; then\n echo \"ABORT: $FAIL_COUNT failures detected\"\n echo \"Review /tmp/ntm-exploration-test-results.log\"\n exit 1\nfi\n```\n\n### 5.2 Stage and Commit\n```bash\ncd /data/projects/agentic_coding_flywheel_setup\ngit add apps/web/lib/flywheel.ts apps/web/lib/tldr-content.ts\ngit diff --cached --stat # Review what is being committed\n\ngit commit -m \"docs(flywheel): update NTM descriptions with verified, accurate content\n\nResearch completed:\n- Read /dp/ntm/README.md and source code\n- Verified CLI commands work: ntm list, ntm spawn, etc.\n- Searched cass and xf for usage patterns\n- Reviewed project beads and recent commits\n\nContent updates:\n- Updated tagline, description, and deepDescription\n- Verified all CLI commands work correctly \n- Updated synergies based on ACTUAL integrations (not assumed)\n- Verified reciprocal synergies exist\n- Passed type-check, lint, and build verification\n\nTest results: /tmp/ntm-exploration-test-results.log\n\nCo-Authored-By: Claude Opus 4.5 \"\n```\n\n### 5.3 Update Beads and Push\n```bash\nbr update bd-3ljs --status closed\nbr sync --flush-only\ngit add .beads/\ngit commit -m \"chore(beads): mark NTM exploration complete\"\ngit push\n```\n\n### 5.4 Rollback Procedure (if needed)\n```bash\n# If issues discovered after commit:\ngit revert HEAD~2 # Revert both commits\n# OR restore from snapshot:\ncp /tmp/ntm-exploration-snapshots/flywheel.ts.before apps/web/lib/flywheel.ts\ncp /tmp/ntm-exploration-snapshots/tldr-content.ts.before apps/web/lib/tldr-content.ts\ngit add . && git commit -m \"revert: rollback NTM exploration changes\"\n```\n\n## Acceptance Criteria\n- [ ] Pre-flight verification passed (tool exists, is installed)\n- [ ] Content snapshot captured for rollback capability \n- [ ] All Phase 4 tests pass (type-check, lint, build, E2E, unit tests, CLI)\n- [ ] ZERO failures in test results log\n- [ ] No type errors or lint warnings introduced\n- [ ] Build succeeds without errors\n- [ ] Both /flywheel and /tldr pages render correctly with NTM entry\n- [ ] All CLI commands listed are VERIFIED working\n- [ ] All synergies are VERIFIED (not assumed)\n- [ ] Reciprocal synergies confirmed in connected tools\n- [ ] Content de-slopified\n- [ ] Changes committed with detailed message\n- [ ] Changes pushed to remote\n- [ ] Bead marked closed\n","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-26T20:00:27.642077588Z","created_by":"ubuntu","updated_at":"2026-01-27T02:28:51.058346825Z","closed_at":"2026-01-27T02:28:51.058307801Z","close_reason":"Deep exploration complete: Updated NTM entries in flywheel.ts and tldr-content.ts with verified info from README.md (80+ commands, robot mode integrations, synergies with bv/br/dcg). Added reciprocal ntm synergy to bv entry. Build passes.","source_repo":".","compaction_level":0,"original_size":0} {"id":"bd-3lzu","title":"JFP: Add flywheel tool entry + metrics","description":"Add JeffreysPrompts (jfp) to the Flywheel page tool data.\\n\\nScope:\\n- Update apps/web/lib/flywheel.ts: add a FlywheelTool entry for jfp with description, connections (ms, apr, cm), CLI commands, installCommand, and metadata.\\n- Adjust flywheelDescription.subtitle/toolCount to match the new tool count.\\n\\nValidation:\\n- bun run build (apps/web) if convenient; otherwise note not run.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-21T09:45:20.274651468Z","created_by":"ubuntu","updated_at":"2026-01-21T09:50:01.878875498Z","closed_at":"2026-01-21T09:50:01.878824732Z","close_reason":"Completed","source_repo":".","compaction_level":0,"original_size":0} {"id":"bd-3moq","title":"Subtask: Add remediate() functions to doctor checks","status":"closed","priority":1,"issue_type":"subtask","created_at":"2026-01-25T23:19:52.953602121Z","created_by":"ubuntu","updated_at":"2026-01-25T23:44:38.331339230Z","closed_at":"2026-01-25T23:44:38.331179739Z","close_reason":"Duplicate of bd-31ps.6.2","source_repo":".","compaction_level":0,"original_size":0} {"id":"bd-3nbx","title":"acfs doctor --fix: Auto-remediation mode","description":"## Overview\nAdd `--fix` flag to `acfs doctor` that automatically remediates detected issues instead of just reporting them.\n\n## Current Behavior\n- `acfs doctor` runs health checks and reports problems\n- User must manually fix each issue based on suggestions\n- High friction for beginners who don't know HOW to fix things\n\n## Proposed Behavior\n- `acfs doctor --fix` attempts automatic remediation\n- Safe fixes only: reinstall tools, fix permissions, regenerate configs\n- Never destructive: won't delete user data or change system settings\n- Falls back to manual instructions for unsafe operations\n\n## Implementation Details\n1. Modify `scripts/lib/doctor.sh` check functions to return remediation commands\n2. Add `--fix` flag parsing to `scripts/commands/doctor.sh`\n3. Each check needs: detect(), describe(), remediate()\n4. Remediation functions wrapped in confirmation prompts\n5. Dry-run mode: `--fix --dry-run` shows what would be done\n\n## Safety Constraints\n- NEVER delete user files\n- NEVER modify ~/.bashrc or ~/.zshrc without backup\n- Always confirm before system-level changes\n- Log all remediation actions to ~/.local/share/acfs/doctor.log\n\n## Test Plan\n- [ ] Unit tests for each remediation function\n- [ ] E2E test: break tool, run doctor --fix, verify fixed\n- [ ] Test --dry-run shows correct actions\n- [ ] Test unsafe operations fall back to manual\n\n## Files to Modify\n- scripts/lib/doctor.sh (add remediate functions)\n- scripts/commands/doctor.sh (add --fix flag)\n- New: scripts/lib/remediation.sh (shared remediation helpers)","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-25T23:01:11.394425192Z","created_by":"ubuntu","updated_at":"2026-01-26T23:31:50.786428028Z","closed_at":"2026-01-26T23:31:50.786408852Z","close_reason":"acfs doctor --fix already fully implemented: doctor_fix.sh with 6 fixers (path ordering, config copy, DCG hook, symlink create, plugin clone, ACFS sourcing), dry-run mode, undo support via autofix.sh, 25 passing unit tests","source_repo":".","compaction_level":0,"original_size":0} {"id":"bd-3opa","title":"Deep exploration: Brenner Bot","description":"## Goal\nPerform deep exploration of Brenner Bot and revise its description on the flywheel/TLDR pages with comprehensive testing.\n\n## Phase 0: Pre-flight Verification (CRITICAL)\n\n### 0.1 Tool Existence Check\n```bash\n# Verify Brenner installation\n[[ -d /dp/brenner_bot ]] && echo \"PASS: brenner repo exists\" || { echo \"FAIL: brenner repo missing\"; exit 1; }\ncommand -v brenner &>/dev/null && echo \"PASS: brenner command available\" || { echo \"FAIL: brenner not in PATH\"; exit 1; }\n\n# Check corpus location\n[[ -d ~/.local/share/brenner/corpus ]] && echo \"INFO: Corpus exists\" || echo \"INFO: No corpus yet\"\n```\n\n### 0.2 Content Snapshot (BEFORE State)\n```bash\nSNAPSHOT_DIR=/tmp/brenner-exploration-snapshots-$(date +%Y%m%d-%H%M%S)\nmkdir -p $SNAPSHOT_DIR\ncp apps/web/lib/flywheel.ts $SNAPSHOT_DIR/flywheel.ts.before\ncp apps/web/lib/tldr-content.ts $SNAPSHOT_DIR/tldr-content.ts.before\necho \"Snapshots saved to $SNAPSHOT_DIR\"\n```\n\n### 0.3 TypeScript Interface Reference\nContent must match FlywheelTool interface:\n- id, name, tagline, description, deepDescription\n- features[], cliCommands[], connectsTo[]\n- integrationLevel, category, status\n\n## Phase 1: Research (GATHER CONTEXT)\n\n### 1.1 Primary Documentation\n- `cat /dp/brenner_bot/README.md` - Read full README\n- Check for research methodology docs, corpus format\n\n### 1.2 Code Investigation\n- Launch code investigation agent to understand:\n - Research session management\n - Hypothesis tracking system\n - Corpus organization and search\n - Multi-agent research swarms\n - Integration with Claude Code\n\n### 1.3 CLI Command Verification\n```bash\n# Verify each documented command works\nbrenner --help 2>&1 | head -20\nbrenner search --help 2>&1 | head -10\nbrenner hypothesis --help 2>&1 | head -10\n\n# Test actual functionality\nbrenner list 2>&1 | head -10\n```\n\n### 1.4 External Context Search\n- `/xf search 'brenner bot OR research session OR hypothesis'` - Twitter archive\n- `cass search 'brenner research' --robot --limit 10` - Past sessions\n\n### 1.5 Project State Review\n- Check beads in /dp/brenner_bot/.beads/\n- Review recent commits: `cd /dp/brenner_bot && git log --oneline -20`\n\n## Phase 2: Analysis (SYNTHESIZE UNDERSTANDING)\n\n### 2.1 Core Capabilities Verification\nDocument findings for each area:\n- [ ] Research session structure\n- [ ] Hypothesis tracking format\n- [ ] Corpus organization\n- [ ] Search capabilities\n- [ ] Multi-agent coordination\n\n### 2.2 Synergy Verification\nCross-reference these tools actually integrate:\n- [ ] cass - session mining\n- [ ] xf - external research\n- [ ] mail - research coordination\n- [ ] ntm - multi-agent research\n\n### 2.3 Corpus Verification\n```bash\n# Check corpus structure\nls -la ~/.local/share/brenner/corpus/ 2>/dev/null | head -10 || echo \"No corpus yet\"\n\n# Check hypothesis tracking\nbrenner hypotheses 2>&1 | head -10 || echo \"No hypotheses command\"\n```\n\n## Phase 3: Revision (UPDATE DESCRIPTIONS)\n\n### 3.1 Update apps/web/lib/flywheel.ts\nUpdate brenner entry with VERIFIED information:\n- `tagline`: Research session management\n- `description`: Hypothesis-driven research\n- `deepDescription`: How research workflow works\n- `features`: Verified capabilities\n- `cliCommands`: Only commands that actually work\n- `connectsTo`: Only verified integrations\n\n### 3.2 Update apps/web/lib/tldr-content.ts\nUpdate TldrFlywheelTool entry with:\n- `briefDescription`: Technical summary\n- `bulletPoints`: Verified capabilities\n- `synergyExamples`: Working integration examples\n\n## Phase 4: Testing (VERIFY CHANGES)\n\n### 4.1 TypeScript Compilation\n```bash\ncd apps/web && npx tsc --noEmit 2>&1 | head -20\n```\n\n### 4.2 Unit Tests\n```bash\n# Test brenner entry structure\nnode -e \"\nconst { flywheelTools } = require('./lib/flywheel');\nconst brenner = flywheelTools.find(t => t.id === 'brenner');\nconsole.log('Testing brenner entry...');\nconsole.assert(brenner, 'brenner entry exists');\nconsole.assert(brenner.features?.length > 0, 'has features');\nconsole.assert(brenner.cliCommands?.length > 0, 'has commands');\nconsole.log('All assertions passed');\n\"\n```\n\n### 4.3 E2E Test: Research Workflow\n```bash\n#\\!/bin/bash\nset -euo pipefail\nLOG=/tmp/brenner-e2e-$(date +%Y%m%d-%H%M%S).log\n\necho \"=== Brenner E2E Test ===\" | tee $LOG\necho \"Started: $(date)\" | tee -a $LOG\n\n# Test 1: List research sessions\necho \"Test 1: List sessions...\" | tee -a $LOG\nbrenner list 2>&1 | head -10 | tee -a $LOG\n\n# Test 2: Search corpus\necho \"Test 2: Search...\" | tee -a $LOG\nbrenner search \"test\" --limit 3 2>&1 | tee -a $LOG || echo \"No search results\"\n\n# Test 3: Hypotheses\necho \"Test 3: Hypotheses...\" | tee -a $LOG\nbrenner hypothesis list 2>&1 | head -5 | tee -a $LOG || echo \"No hypothesis command\"\n\necho \"=== All Tests Passed ===\" | tee -a $LOG\necho \"Log: $LOG\"\n```\n\n### 4.4 Content Diff Verification\n```bash\necho \"=== Changes Made ===\"\ndiff $SNAPSHOT_DIR/flywheel.ts.before apps/web/lib/flywheel.ts || true\ndiff $SNAPSHOT_DIR/tldr-content.ts.before apps/web/lib/tldr-content.ts || true\n```\n\n## Phase 5: Completion (FINALIZE)\n\n### 5.1 Rollback Procedure (if tests fail)\n```bash\ncp $SNAPSHOT_DIR/flywheel.ts.before apps/web/lib/flywheel.ts\ncp $SNAPSHOT_DIR/tldr-content.ts.before apps/web/lib/tldr-content.ts\necho \"Rolled back to pre-exploration state\"\n```\n\n### 5.2 Sync Changes\n```bash\nbr update bd-3opa --status done\nbr sync --flush-only\n```\n\n### 5.3 Final Verification\n- [ ] All tests pass\n- [ ] TypeScript compiles without errors\n- [ ] Research workflow documented correctly\n- [ ] No broken links or references","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-26T20:02:10.138573259Z","created_by":"ubuntu","updated_at":"2026-01-27T03:39:55.530222451Z","closed_at":"2026-01-27T03:39:55.530196993Z","close_reason":"done","source_repo":".","compaction_level":0,"original_size":0} +{"id":"bd-3te83","title":"Add ARM64 Linux binary to meta_skill releases","description":"meta_skill v0.1.0 release is missing aarch64-unknown-linux-gnu binary. When acfs doctor runs on ARM64 Linux (AWS Graviton, Raspberry Pi), the install script tries to download ms-0.1.0-aarch64-unknown-linux-gnu.tar.gz which 404s.\n\nCurrent release binaries:\n- aarch64-apple-darwin (ARM64 macOS) present\n- x86_64-unknown-linux-gnu (x86_64 Linux) present\n- x86_64-pc-windows-msvc (Windows) present\n- aarch64-unknown-linux-gnu (ARM64 Linux) MISSING\n\nROOT CAUSE: In /data/projects/meta_skill/.github/workflows/release.yml (lines 91-95), the ARM64 Linux target is commented out with note: \"ARM Linux cross-compile requires vendored OpenSSL - see Cargo.toml\"\n\nFIX (in meta_skill repo at /data/projects/meta_skill):\n1. Uncomment the aarch64-unknown-linux-gnu target in .github/workflows/release.yml:\n - target: aarch64-unknown-linux-gnu\n os: ubuntu-latest\n archive: tar.gz\n cross: true\n2. Add cross-compilation support:\n - Install cross tool: cargo install cross --locked\n - Build with: cross build --release --target aarch64-unknown-linux-gnu --locked\n - OR: add openssl = { version = \"0.10\", features = [\"vendored\"] } to Cargo.toml\n3. Cut new meta_skill release (v0.1.2+) that includes ARM64 Linux binary\n\nFIX (in ACFS repo):\n4. Update acfs doctor to show clear message when ARM64 Linux binary unavailable:\n \"meta_skill ARM64 Linux binary not yet available. Install manually from https://github.com/.../releases or build from source: cargo install meta_skill\"\n5. Update acfs.manifest.yaml meta_skill entry to note ARM64 Linux support status\n\nTESTS:\n\nBuild Tests (in meta_skill CI):\n- test_arm64_linux_build: cross build --target aarch64-unknown-linux-gnu succeeds\n- test_arm64_binary_runs: run binary in ARM64 Docker container (docker run --platform linux/arm64)\n- test_release_includes_arm64: after release, verify aarch64-unknown-linux-gnu.tar.gz asset exists\n\nIntegration Tests (in ACFS):\n- test_doctor_arm64_graceful: on ARM64 Linux, acfs doctor shows helpful message (not crash)\n- test_install_arm64: full install script on ARM64 container successfully installs meta_skill\n\nE2E Tests:\n- test_arm64_graviton: run full ACFS install on AWS Graviton instance (or GitHub ARM runner)\n\nGitHub issue: #115","status":"open","priority":2,"issue_type":"bug","created_at":"2026-02-07T03:08:40.264250256Z","created_by":"ubuntu","updated_at":"2026-02-07T03:19:37.259411249Z","source_repo":".","compaction_level":0,"original_size":0} {"id":"bd-3ucd","title":"state.sh: remove duplicate helper block + add guard","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-21T07:11:24.447472677Z","created_by":"ubuntu","updated_at":"2026-01-21T07:21:24.823507314Z","closed_at":"2026-01-21T07:21:24.823357592Z","close_reason":"Removed duplicate helper block in state.sh and added guard comment; shellcheck run","source_repo":".","compaction_level":0,"original_size":0} {"id":"bd-3ukl","title":"Deep exploration: DCG (Destructive Command Guard)","description":"## Goal\nPerform deep exploration of DCG (Destructive Command Guard) and revise its description on the flywheel/TLDR pages with comprehensive testing.\n\n## Phase 0: Pre-flight Verification (CRITICAL)\n\n### 0.1 Tool Existence Check\n```bash\n# Verify DCG installation\n[[ -d /dp/destructive_command_guard ]] && echo \"PASS: dcg repo exists\" || { echo \"FAIL: dcg repo missing\"; exit 1; }\ncommand -v dcg &>/dev/null && echo \"PASS: dcg command available\" || { echo \"FAIL: dcg not in PATH\"; exit 1; }\n\n# Check if dcg is integrated with shell\ngrep -q dcg ~/.bashrc ~/.zshrc 2>/dev/null && echo \"INFO: dcg in shell config\" || echo \"INFO: dcg shell integration unclear\"\n```\n\n### 0.2 Content Snapshot (BEFORE State)\n```bash\nSNAPSHOT_DIR=/tmp/dcg-exploration-snapshots-$(date +%Y%m%d-%H%M%S)\nmkdir -p $SNAPSHOT_DIR\ncp apps/web/lib/flywheel.ts $SNAPSHOT_DIR/flywheel.ts.before\ncp apps/web/lib/tldr-content.ts $SNAPSHOT_DIR/tldr-content.ts.before\necho \"Snapshots saved to $SNAPSHOT_DIR\"\n```\n\n### 0.3 TypeScript Interface Reference\nContent must match FlywheelTool interface:\n- id, name, tagline, description, deepDescription\n- features[], cliCommands[], connectsTo[]\n- integrationLevel, category, status\n\n## Phase 1: Research (GATHER CONTEXT)\n\n### 1.1 Primary Documentation\n- `cat /dp/destructive_command_guard/README.md` - Read full README\n- Check for pattern docs, whitelist configuration\n\n### 1.2 Code Investigation\n- Launch code investigation agent to understand:\n - Command interception mechanism (preexec hook? wrapper?)\n - Dangerous command patterns (rm -rf, git reset --hard, etc.)\n - Whitelist/blacklist configuration\n - Integration with Claude Code hooks\n - Escape hatch for legitimate use\n\n### 1.3 CLI Command Verification\n```bash\n# Verify each documented command works\ndcg --help 2>&1 | head -20\ndcg status --help 2>&1 | head -10\ndcg whitelist --help 2>&1 | head -10\n\n# Test actual functionality (safe test)\ndcg status 2>&1 | head -10\n```\n\n### 1.4 Pattern Verification\n```bash\n# Check what patterns are blocked\ncat /dp/destructive_command_guard/patterns/*.yaml 2>/dev/null | head -30\n# Or check code for pattern definitions\ngrep -r \"rm -rf\\|git reset\\|DROP TABLE\" /dp/destructive_command_guard/ 2>/dev/null | head -10\n```\n\n### 1.5 External Context Search\n- `/xf search 'dcg OR destructive command OR guard'` - Twitter archive\n- `cass search 'dcg blocked command' --robot --limit 10` - Past sessions\n\n### 1.6 Project State Review\n- Check beads in /dp/destructive_command_guard/.beads/\n- Review recent commits: `cd /dp/destructive_command_guard && git log --oneline -20`\n\n## Phase 2: Analysis (SYNTHESIZE UNDERSTANDING)\n\n### 2.1 Core Capabilities Verification\nDocument findings for each area:\n- [ ] Command interception mechanism\n- [ ] Complete list of blocked patterns\n- [ ] Whitelist configuration format\n- [ ] Claude Code hooks integration\n- [ ] Override/escape mechanism\n\n### 2.2 Synergy Verification\nCross-reference these tools actually integrate:\n- [ ] slb - two-person rule escalation\n- [ ] mail - alert messaging\n- [ ] ntm - agent coordination\n\n### 2.3 Claim Verification\n```bash\n# Count blocked patterns\ngrep -c \"pattern\\|regex\" /dp/destructive_command_guard/patterns/*.yaml 2>/dev/null | awk -F: '{sum+=} END {print \"Total patterns: \" sum}'\n\n# Verify hook mechanism\ngrep -l \"preexec\\|precmd\" /dp/destructive_command_guard/**/*.{sh,zsh} 2>/dev/null | head -3\n```\n\n## Phase 3: Revision (UPDATE DESCRIPTIONS)\n\n### 3.1 Update apps/web/lib/flywheel.ts\nUpdate dcg entry with VERIFIED information:\n- `tagline`: Accurate one-liner\n- `description`: Command interception mechanism\n- `deepDescription`: How blocking works\n- `features`: Verified blocked commands list\n- `cliCommands`: Only commands that actually work\n- `connectsTo`: Only verified integrations\n\n### 3.2 Update apps/web/lib/tldr-content.ts\nUpdate TldrFlywheelTool entry with:\n- `briefDescription`: Technical summary\n- `bulletPoints`: Verified capabilities\n- `synergyExamples`: Working integration examples\n\n## Phase 4: Testing (VERIFY CHANGES)\n\n### 4.1 TypeScript Compilation\n```bash\ncd apps/web && npx tsc --noEmit 2>&1 | head -20\n```\n\n### 4.2 Unit Tests\n```bash\n# Test dcg entry structure\nnode -e \"\nconst { flywheelTools } = require('./lib/flywheel');\nconst dcg = flywheelTools.find(t => t.id === 'dcg');\nconsole.log('Testing dcg entry...');\nconsole.assert(dcg, 'dcg entry exists');\nconsole.assert(dcg.features?.length > 0, 'has features');\nconsole.assert(dcg.connectsTo?.includes('slb'), 'connects to slb');\nconsole.log('All assertions passed');\n\"\n```\n\n### 4.3 E2E Test: Guard Verification (Safe Mode)\n```bash\n#\\!/bin/bash\nset -euo pipefail\nLOG=/tmp/dcg-e2e-$(date +%Y%m%d-%H%M%S).log\n\necho \"=== DCG E2E Test ===\" | tee $LOG\necho \"Started: $(date)\" | tee -a $LOG\n\n# Test 1: Status check\necho \"Test 1: Status check...\" | tee -a $LOG\ndcg status 2>&1 | tee -a $LOG\n\n# Test 2: List blocked patterns\necho \"Test 2: List patterns...\" | tee -a $LOG\ndcg list 2>&1 | head -10 | tee -a $LOG || echo \"No list command\"\n\n# Test 3: Whitelist view\necho \"Test 3: Whitelist...\" | tee -a $LOG\ndcg whitelist --show 2>&1 | head -5 | tee -a $LOG || echo \"No whitelist command\"\n\necho \"=== All Tests Passed ===\" | tee -a $LOG\necho \"Log: $LOG\"\n```\n\n### 4.4 Content Diff Verification\n```bash\necho \"=== Changes Made ===\"\ndiff $SNAPSHOT_DIR/flywheel.ts.before apps/web/lib/flywheel.ts || true\ndiff $SNAPSHOT_DIR/tldr-content.ts.before apps/web/lib/tldr-content.ts || true\n```\n\n## Phase 5: Completion (FINALIZE)\n\n### 5.1 Rollback Procedure (if tests fail)\n```bash\ncp $SNAPSHOT_DIR/flywheel.ts.before apps/web/lib/flywheel.ts\ncp $SNAPSHOT_DIR/tldr-content.ts.before apps/web/lib/tldr-content.ts\necho \"Rolled back to pre-exploration state\"\n```\n\n### 5.2 Sync Changes\n```bash\nbr update bd-3ukl --status done\nbr sync --flush-only\n```\n\n### 5.3 Final Verification\n- [ ] All tests pass\n- [ ] TypeScript compiles without errors\n- [ ] Blocked patterns documented completely\n- [ ] Synergies are reciprocal (dcg->slb and slb->dcg)\n- [ ] No broken links or references","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-26T20:01:27.806155248Z","created_by":"ubuntu","updated_at":"2026-01-27T03:29:33.713449879Z","closed_at":"2026-01-27T03:29:33.713422467Z","close_reason":"DCG deep exploration complete: added heredoc/inline script scanning, smart context detection, agent-specific trust profiles, MCP server mode, dcg scan for CI","source_repo":".","compaction_level":0,"original_size":0} {"id":"bd-3vx8","title":"Optimize runtime install phases (apt/bun/cargo/etc) based on profiling","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-21T19:00:39.996743538Z","created_by":"ubuntu","updated_at":"2026-01-22T01:16:40.415209476Z","closed_at":"2026-01-22T01:16:40.415131199Z","close_reason":"Verified: Batched cargo install optimization is implemented in install.sh at line 3009-3038. Tools (du-dust, lsd, bat, fd-find, ripgrep) are now batch-installed with a single cargo command, reducing index downloads and enabling parallel compilation.","source_repo":".","compaction_level":0,"original_size":0,"dependencies":[{"issue_id":"bd-3vx8","depends_on_id":"bd-2z32","type":"discovered-from","created_at":"2026-01-21T19:00:40.029703844Z","created_by":"ubuntu"}]} @@ -973,6 +994,7 @@ {"id":"bd-iucu","title":"SRPS integration: lesson, webapp, and tests","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-21T09:34:20.834248192Z","created_by":"ubuntu","updated_at":"2026-01-21T09:35:05.899207498Z","closed_at":"2026-01-21T09:35:05.899159768Z","close_reason":"Completed: SRPS integration committed","source_repo":".","compaction_level":0,"original_size":0} {"id":"bd-jt48","title":"Deep exploration: BR (beads_rust)","description":"## Goal\nPerform deep exploration of BR (beads_rust) and revise its description with comprehensive testing.\n\n## Phase 0: Pre-flight Verification\n\n```bash\n#!/bin/bash\nLOG=/tmp/br-preflight.log\necho \"=== BR Pre-flight ===\" | tee $LOG\n\n[[ -d /dp/beads_rust ]] && echo \"PASS: Directory exists\" || exit 1\ncommand -v br &>/dev/null && echo \"PASS: br installed: $(which br)\" || echo \"WARN: br not in PATH\"\nbr --version 2>&1 | tee -a $LOG\n\nSNAPSHOT_DIR=/tmp/br-exploration-snapshots\nmkdir -p $SNAPSHOT_DIR\ncp /data/projects/agentic_coding_flywheel_setup/apps/web/lib/flywheel.ts $SNAPSHOT_DIR/flywheel.ts.before\ncp /data/projects/agentic_coding_flywheel_setup/apps/web/lib/tldr-content.ts $SNAPSHOT_DIR/tldr-content.ts.before\n```\n\n## Phase 1: Research\n\n### 1.1 Documentation\n```bash\ncat /dp/beads_rust/README.md\ncat /dp/beads_rust/AGENTS.md 2>/dev/null\n```\n\n### 1.2 Code Investigation\n- JSONL schema: examine actual .beads/issues.jsonl format\n- Dependency system: blocks/blocked_by implementation\n- Auto-flush mechanism: when/how it triggers\n- bd alias: how it works\n- CLI commands: full inventory\n\n### 1.3 Verify CLI Commands\n```bash\n#!/bin/bash\necho \"=== BR CLI Verification ===\" | tee /tmp/br-cli.log\n\nbr --help 2>&1 | tee -a /tmp/br-cli.log\nbr create --help 2>&1 && echo \"PASS: br create\" || echo \"FAIL\"\nbr update --help 2>&1 && echo \"PASS: br update\" || echo \"FAIL\"\nbr show --help 2>&1 && echo \"PASS: br show\" || echo \"FAIL\"\nbr list --help 2>&1 && echo \"PASS: br list\" || echo \"FAIL\"\nbr sync --help 2>&1 && echo \"PASS: br sync\" || echo \"FAIL\"\nbr ready 2>&1 && echo \"PASS: br ready\" || echo \"FAIL\"\nbr blocked 2>&1 && echo \"PASS: br blocked\" || echo \"FAIL\"\n\n# Test bd alias\ncommand -v bd &>/dev/null && echo \"PASS: bd alias exists\" || echo \"WARN: bd alias missing\"\n```\n\n### 1.4 Verify JSONL Schema\n```bash\n# Examine actual schema from a real bead\nhead -1 /data/projects/agentic_coding_flywheel_setup/.beads/issues.jsonl | jq . 2>/dev/null | tee /tmp/br-schema.json\n```\n\n### 1.5 External Context\n```bash\n/xf search 'beads_rust OR br cli OR issue tracking' 2>&1 | head -30\ncass search 'br beads issue' --robot --limit 10 2>&1\n```\n\n## Phase 2: Analysis\n\nDocument with VERIFICATION:\n- [ ] JSONL schema fields: [list actual fields from schema]\n- [ ] CLI commands VERIFIED: create, update, show, list, sync, ready, blocked\n- [ ] bd alias: VERIFIED working ✓/✗\n- [ ] Auto-flush: trigger conditions verified\n- [ ] Tech stack: Rust VERIFIED\n- [ ] Synergies VERIFIED:\n - [ ] bv: bv reads br data ✓/✗\n - [ ] mail: any integration ✓/✗\n - [ ] ntm: any integration ✓/✗\n\n## Phase 3: Revision\n\nUpdate with VERIFIED content:\n- List only commands that actually work\n- Document actual JSONL schema fields\n- Only list verified synergies\n\n## Phase 4: Testing\n\n```bash\n#!/bin/bash\ncd /data/projects/agentic_coding_flywheel_setup/apps/web\n\nbun run type-check 2>&1 | tee /tmp/br-typecheck.log\nbun run lint 2>&1 | tee /tmp/br-lint.log\nbun run build 2>&1 | tee /tmp/br-build.log\n\nlsof -t -i :3000 | xargs kill 2>/dev/null; sleep 2\nbun run dev &\nsleep 10\ncurl -sL http://localhost:3000/flywheel | grep -qi 'br' && echo \"PASS\" || echo \"FAIL\"\ncurl -sL http://localhost:3000/tldr | grep -qi 'br' && echo \"PASS\" || echo \"FAIL\"\nkill %1\n\nRESULTS=/tmp/br-exploration-test-results.log\ncat /tmp/br-cli.log > $RESULTS\ngrep -E \"PASS|FAIL\" /tmp/br-*.log >> $RESULTS\n```\n\n## Phase 5: Commit\n\n```bash\n[[ $(grep -c \"FAIL\" /tmp/br-exploration-test-results.log) -gt 0 ]] && exit 1\n\ngit add apps/web/lib/flywheel.ts apps/web/lib/tldr-content.ts\ngit commit -m \"docs(flywheel): update BR with verified CLI commands and schema\n\n- Verified all CLI commands work\n- Documented actual JSONL schema\n- Verified bd alias\n- Tested auto-flush behavior\n\nCo-Authored-By: Claude Opus 4.5 \"\n\nbr update bd-jt48 --status closed\nbr sync --flush-only && git add .beads/ && git push\n```\n\n## Acceptance Criteria\n- [ ] CLI commands VERIFIED\n- [ ] JSONL schema documented\n- [ ] bd alias VERIFIED\n- [ ] All tests PASS\n- [ ] Pushed\n","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-26T20:00:46.192044397Z","created_by":"ubuntu","updated_at":"2026-01-27T05:34:18.534127728Z","closed_at":"2026-01-27T05:34:18.534103483Z","close_reason":"Deep exploration completed by EmeraldCrane. Verified SQLite+JSONL hybrid, 40 commands, non-invasive design.","source_repo":".","compaction_level":0,"original_size":0} {"id":"bd-ltmu","title":"JFP: Add Learning Hub lesson metadata","description":"Expose the JFP lesson in the Learning Hub list.\\n\\nScope:\\n- Update apps/web/lib/lessons.ts to include a jfp lesson entry (slug jfp) pointing to the existing lesson component and content.\\n- Ensure TOTAL_LESSONS remains accurate and ordering remains sensible.\\n\\nValidation:\\n- bun run build (apps/web) if convenient; otherwise note not run.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-21T09:45:35.798383561Z","created_by":"ubuntu","updated_at":"2026-01-21T09:50:13.516596379Z","closed_at":"2026-01-21T09:50:13.516542527Z","close_reason":"Completed","source_repo":".","compaction_level":0,"original_size":0} +{"id":"bd-mhmdd","title":"Deep code audit & fixes","status":"closed","priority":1,"issue_type":"task","created_at":"2026-02-04T05:11:08.707179681Z","created_by":"ubuntu","updated_at":"2026-02-04T05:19:45.700648014Z","closed_at":"2026-02-04T05:19:45.700625381Z","close_reason":"Completed","source_repo":".","compaction_level":0,"original_size":0} {"id":"bd-nvmp","title":"Add jfp installer checksum so manifest generator can run","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-21T20:48:57.335271911Z","created_by":"ubuntu","updated_at":"2026-01-21T21:47:44.408444370Z","closed_at":"2026-01-21T21:47:44.408383265Z","close_reason":"Already fixed (checksums.yaml includes jfp; generate:validate passes)","source_repo":".","compaction_level":0,"original_size":0,"dependencies":[{"issue_id":"bd-nvmp","depends_on_id":"bd-3hg8","type":"discovered-from","created_at":"2026-01-21T20:48:57.430830777Z","created_by":"ubuntu"}]} {"id":"bd-pkta","title":"Profile full installer runtime in Docker (baseline + hotspots)","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-21T19:00:21.329191150Z","created_by":"ubuntu","updated_at":"2026-01-22T01:25:55.941958502Z","closed_at":"2026-01-22T01:25:55.940359722Z","close_reason":"Profiling completed via state.json analysis. Baseline: 1078s total. Hotspots identified: (1) cli_tools 455s/42.2% - apt packages, GitHub releases, lazygit/lazydocker builds; (2) languages 372s/34.5% - rust/cargo compilation (batched cargo install already implemented in bd-3vx8); (3) stack 96s/8.9% - Dicklesworthstone tool downloads. Optimization priority: cli_tools phase which has most room for parallelization of apt operations and binary downloads.","source_repo":".","compaction_level":0,"original_size":0,"dependencies":[{"issue_id":"bd-pkta","depends_on_id":"bd-2z32","type":"discovered-from","created_at":"2026-01-21T19:00:21.367573510Z","created_by":"ubuntu"}]} {"id":"bd-q6eb","title":"Create GIIL lesson: Deep dive into Get Image from Internet Link tool","status":"closed","priority":2,"issue_type":"feature","created_at":"2026-01-27T06:22:19.855457223Z","created_by":"ubuntu","updated_at":"2026-01-27T06:26:42.806142774Z","closed_at":"2026-01-27T06:26:42.806124219Z","close_reason":"GIIL lesson already exists and is fully integrated: TSX component at apps/web/components/lessons/giil-lesson.tsx, registered in lessons.ts, and exported from index.tsx.","source_repo":".","compaction_level":0,"original_size":0} diff --git a/.github/workflows/installer-canary-strict.yml b/.github/workflows/installer-canary-strict.yml index 22383c04..be9e2fbd 100644 --- a/.github/workflows/installer-canary-strict.yml +++ b/.github/workflows/installer-canary-strict.yml @@ -31,18 +31,21 @@ jobs: env: ACFS_CHECKSUMS_REF: main run: | - set -o pipefail chmod +x ./tests/vm/test_install_ubuntu.sh + UBUNTU="${{ inputs.ubuntu || 'all' }}" + MODE="${{ inputs.mode || 'vibe' }}" + + rc=0 if [[ "${{ github.event_name }}" == "schedule" ]]; then - ./tests/vm/test_install_ubuntu.sh --all --mode "vibe" --strict 2>&1 | tee canary.log - elif [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ inputs.ubuntu }}" == "all" ]]; then - ./tests/vm/test_install_ubuntu.sh --all --mode "${{ inputs.mode }}" --strict 2>&1 | tee canary.log + (set -o pipefail; ./tests/vm/test_install_ubuntu.sh --all --mode "vibe" --strict 2>&1 | tee canary.log) || rc=$? + elif [[ "${{ github.event_name }}" == "workflow_dispatch" && "$UBUNTU" == "all" ]]; then + (set -o pipefail; ./tests/vm/test_install_ubuntu.sh --all --mode "$MODE" --strict 2>&1 | tee canary.log) || rc=$? else - ./tests/vm/test_install_ubuntu.sh --ubuntu "${{ inputs.ubuntu }}" --mode "${{ inputs.mode }}" --strict 2>&1 | tee canary.log + (set -o pipefail; ./tests/vm/test_install_ubuntu.sh --ubuntu "$UBUNTU" --mode "$MODE" --strict 2>&1 | tee canary.log) || rc=$? fi - echo "exit_code=${PIPESTATUS[0]}" >> "$GITHUB_OUTPUT" + echo "exit_code=$rc" >> "$GITHUB_OUTPUT" - name: Detect checksum mismatch id: detect diff --git a/.github/workflows/installer-canary.yml b/.github/workflows/installer-canary.yml index 6791c2ee..553bef7e 100644 --- a/.github/workflows/installer-canary.yml +++ b/.github/workflows/installer-canary.yml @@ -28,8 +28,11 @@ jobs: run: | chmod +x ./tests/vm/test_install_ubuntu.sh - if [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ inputs.ubuntu }}" == "all" ]]; then - ./tests/vm/test_install_ubuntu.sh --all --mode "${{ inputs.mode }}" + UBUNTU="${{ inputs.ubuntu || '24.04' }}" + MODE="${{ inputs.mode || 'vibe' }}" + + if [[ "${{ github.event_name }}" == "workflow_dispatch" && "$UBUNTU" == "all" ]]; then + ./tests/vm/test_install_ubuntu.sh --all --mode "$MODE" else - ./tests/vm/test_install_ubuntu.sh --ubuntu "${{ inputs.ubuntu }}" --mode "${{ inputs.mode }}" + ./tests/vm/test_install_ubuntu.sh --ubuntu "$UBUNTU" --mode "$MODE" fi diff --git a/.github/workflows/installer-notification-receiver.yml b/.github/workflows/installer-notification-receiver.yml index 7fbf126b..cc4541fd 100644 --- a/.github/workflows/installer-notification-receiver.yml +++ b/.github/workflows/installer-notification-receiver.yml @@ -491,21 +491,29 @@ jobs: TOOL_NAME="${{ needs.validate-dispatch.outputs.tool_name }}" SOURCE_REPO="${{ needs.validate-dispatch.outputs.source_repo }}" - gh pr create \ - --base main \ - --head "auto/remove-${TOOL_NAME}" \ - --title "chore(checksums): Remove $TOOL_NAME" \ - --body "## Tool Removal: $TOOL_NAME + cat > /tmp/removal-pr-body.md << 'PREOF' + ## Tool Removal: $TOOL_NAME + + This PR removes **$TOOL_NAME** from checksums.yaml. + + ### Reason + The upstream repository ($SOURCE_REPO) has indicated the installer should be removed. -This PR removes **$TOOL_NAME** from checksums.yaml. + ### Checklist + - [ ] Confirmed tool is no longer needed + - [ ] Verified this is intentional, not an error -### Reason -The upstream repository ($SOURCE_REPO) has indicated the installer should be removed. + --- + *Generated by ACFS Installer Notification Receiver* + PREOF -### Checklist -- [ ] Confirmed tool is no longer needed -- [ ] Verified this is intentional, not an error + # Substitute variables in the template + sed -i "s/\$TOOL_NAME/$TOOL_NAME/g" /tmp/removal-pr-body.md + sed -i "s|\$SOURCE_REPO|$SOURCE_REPO|g" /tmp/removal-pr-body.md ---- -*Generated by ACFS Installer Notification Receiver*" \ + gh pr create \ + --base main \ + --head "auto/remove-${TOOL_NAME}" \ + --title "chore(checksums): Remove $TOOL_NAME" \ + --body-file /tmp/removal-pr-body.md \ --label "automated,checksum-removal,needs-review" diff --git a/.github/workflows/installer.yml b/.github/workflows/installer.yml index 4149a553..a497c62c 100644 --- a/.github/workflows/installer.yml +++ b/.github/workflows/installer.yml @@ -309,6 +309,18 @@ jobs: su - ubuntu -c "zsh -ic 'dcg doctor'" su - ubuntu -c "zsh -ic 'ru --version'" su - ubuntu -c "zsh -ic 'onboard --help'" + # beads_rust (required) - issue tracking + su - ubuntu -c "zsh -ic 'br --version'" + # New stack tools (bd-1ega) + su - ubuntu -c "zsh -ic 'ms --version'" + su - ubuntu -c "zsh -ic 'apr --help || true'" + su - ubuntu -c "zsh -ic 'jfp --version || true'" + su - ubuntu -c "zsh -ic 'pt --help || true'" + su - ubuntu -c "zsh -ic 'brenner --version || brenner --help || true'" + su - ubuntu -c "zsh -ic 'rch --version || rch --help || true'" + su - ubuntu -c "zsh -ic 'wa --version || wa --help || true'" + su - ubuntu -c "zsh -ic 'sysmoni --version || sysmoni --help || true'" + # Agents su - ubuntu -c "zsh -ic 'claude --version'" su - ubuntu -c "zsh -ic 'codex --version'" su - ubuntu -c "zsh -ic 'gemini --version'" diff --git a/.gitignore b/.gitignore index 8b30576a..ad6b1415 100644 --- a/.gitignore +++ b/.gitignore @@ -123,3 +123,6 @@ a.out .vercel .env*.local tests/artifacts/ + +# Stray bv/CLI artifacts (malformed flag creates files like --graph-format.svg) +--graph-format* diff --git a/.shellcheckrc b/.shellcheckrc index 805fab39..4fb94f74 100644 --- a/.shellcheckrc +++ b/.shellcheckrc @@ -3,4 +3,39 @@ # SC2015: Note that A && B || C is not if-then-else. C may run when A is true. # We use this pattern intentionally for error handling (e.g., cmd || true) -disable=SC2015 +# +# SC2317: Command appears to be unreachable. Check usage (or ignore if invoked indirectly). +# We use dynamic function calls via function references (e.g., "$fix_function" "fix") +# +# SC2016: Expressions don't expand in single quotes, use double quotes for that. +# Intentional - we use single quotes to pass literal strings to subshells +# +# SC1091: Not following: file was not specified as input +# Dynamic sourcing of related scripts is intentional +# +# SC2059: Don't use variables in printf format string +# Intentional - we use ANSI color variables in format strings +# +# SC2034: Variable appears unused +# Many variables are used by sourcing scripts or for documentation +# +# SC2155: Declare and assign separately to avoid masking return values +# Acceptable risk in simple cases where the command always succeeds +# +# SC2030/SC2031: Variable modified in subshell +# Intentional pattern in pipeline processing +# SC2086: Double quote to prevent globbing and word splitting +# Intentional word splitting in some cases for argument expansion +# +# SC2002: Useless cat +# Sometimes cat is clearer for readability in pipelines +# +# SC2076: Remove quotes from right-hand side of =~ +# SC2128: Expanding an array without an index +# SC2178: Variable was used as an array but is now assigned a string +# SC2120/SC2119: Function references arguments, but none are ever passed +# These are pre-existing patterns in newproj TUI code +# +# SC2001/SC2028/SC2129/SC2153/SC2181/SC2295: Style and info-level suggestions +# Accepted patterns in this codebase +disable=SC2015,SC2317,SC2016,SC1091,SC2059,SC2034,SC2155,SC2030,SC2031,SC2086,SC2002,SC2076,SC2128,SC2178,SC2120,SC2119,SC2001,SC2028,SC2129,SC2153,SC2181,SC2295 diff --git a/AGENTS.md b/AGENTS.md index 3110151a..bbb6fabd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -366,13 +366,10 @@ shellcheck install.sh scripts/lib/*.sh All issue tracking goes through **Beads**. No other TODO systems. -**Note:** `bd` is a backward-compatibility alias (installed by `acfs/zsh/acfs.zshrc`) for the beads_rust CLI: `br`. -The primary command is `br`. The old `bd` (golang beads) is deprecated but aliased for compatibility. - Key invariants: - `.beads/` is authoritative state and **must always be committed** with code changes. -- Do not edit `.beads/*.jsonl` directly; only via `br` / `bd`. +- Do not edit `.beads/*.jsonl` directly; only via `br`. ### Basics @@ -425,7 +422,7 @@ Agent workflow: Sync: -- Run `br sync --flush-only` (or `bd sync --flush-only`) to export to `.beads/issues.jsonl` without git operations. +- Run `br sync --flush-only` to export to `.beads/issues.jsonl` without git operations. - Then run `git add .beads/ && git commit -m "Update beads"` to commit changes. Never: diff --git a/CHANGELOG.md b/CHANGELOG.md index ddc49751..7a2104f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,58 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- **BREAKING**: `git_safety_guard` replaced by **DCG (Destructive Command Guard)** + - The legacy `git_safety_guard.py` hook has been fully removed + - DCG is now the only supported command safety mechanism + - Automatic cleanup of legacy files during `acfs update` + +### Migration: git_safety_guard → DCG + +If you installed ACFS before January 11, 2026, your installation may have legacy `git_safety_guard` files. + +**Symptoms of old installation:** +- `acfs doctor` shows "Git safety guard" warning +- Files exist at `~/.acfs/claude/hooks/git_safety_guard.py` or `~/.claude/hooks/` + +**Migration steps:** +1. Run `acfs update` - this automatically removes legacy files +2. Install DCG: `dcg install` +3. Verify: `acfs doctor` should show only DCG check (no git_safety_guard warnings) + +**Why DCG?** +- Built in Rust for sub-millisecond latency (vs Python startup overhead) +- Modular pack system for extensibility +- Dedicated repository and maintenance at [dcg](https://github.com/Dicklesworthstone/destructive_command_guard) + ### Added +- **New Flywheel Tools**: + - **beads_rust (br)** - Rust port of issue tracker, replaces golang beads + - `bd` alias maintained for backward compatibility + - Companion **bv** (beads_viewer) for graph-aware task triage + - **meta_skill (ms)** - Knowledge management and skill distribution + - **remote_compilation_helper (rch)** - Build acceleration for agent swarms + - **wezterm_automata (wa)** - Multi-agent orchestration via WezTerm + - **brenner_bot** - Research session CLI and orchestration + +- **Utility Tools** (9 new): + - **toon_rust (tru)** - Token-optimized notation format + - **rust_proxy** - Transparent proxy routing + - **rano** - Network observer for AI CLIs + - **xf** - X (Twitter) archive search + - **markdown_web_browser (mdwb)** - Website to Markdown converter + - **process_triage (pt)** - Zombie process detector + - **aadc** - ASCII diagram corrector + - **source_to_prompt_tui (s2p)** - Code to LLM prompt generator + - **coding_agent_usage_tracker (caut)** - LLM provider usage tracker + +- **E2E Testing**: New comprehensive test suite at `tests/e2e/test_new_tools_e2e.sh` + - Verifies all 16 new tools install correctly + - Integration tests for acfs doctor, bd alias, flywheel.ts + - JSON output for CI integration + - **Automatic Ubuntu Upgrade**: The installer now automatically upgrades Ubuntu to 25.10 before running the main ACFS installation - Detects current Ubuntu version and calculates sequential upgrade path - Handles reboots automatically via systemd resume service diff --git a/README.md b/README.md index b280bd1f..b25abeb3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Agentic Coding Flywheel Setup (ACFS) -![Version](https://img.shields.io/badge/Version-0.5.0-bd93f9?style=for-the-badge) +![Version](https://img.shields.io/badge/Version-0.6.0-bd93f9?style=for-the-badge) ![Platform](https://img.shields.io/badge/Platform-Ubuntu%2025.10-6272a4?style=for-the-badge) ![License](https://img.shields.io/badge/License-MIT-50fa7b?style=for-the-badge) ![Shell](https://img.shields.io/badge/Shell-Bash-ff79c6?style=for-the-badge) @@ -508,11 +508,29 @@ curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/agentic_coding_f This checks: - OS compatibility (Ubuntu 22.04+; installer upgrades to 25.10) - Architecture (x86_64 or ARM64) -- Memory and disk space +- Memory and disk space (minimum 4GB RAM, 10GB free disk) - Network connectivity to required URLs - APT lock status - Potential conflicts (nvm, pyenv, existing ACFS) +**Network checks performed:** +| Check | What it verifies | Fix if failing | +|-------|------------------|----------------| +| DNS resolution | Can resolve github.com, raw.githubusercontent.com | Check `/etc/resolv.conf` or add `8.8.8.8` | +| GitHub HTTPS | Can reach github.com:443 | Check firewall, proxy, or VPN settings | +| Installer URLs | Raw GitHub, Homebrew, Oh-My-Zsh, Rust, etc. | May need to retry; transient failures OK | +| APT mirrors | Default Ubuntu mirror reachable | Check `/etc/apt/sources.list` or try different mirror | + +**Common preflight failures:** + +| Error | Cause | Solution | +|-------|-------|----------| +| "Cannot resolve github.com" | DNS misconfigured | Add `nameserver 8.8.8.8` to `/etc/resolv.conf` | +| "Cannot reach github.com" | Firewall blocking HTTPS | Allow outbound port 443 | +| "APT mirror slow or unreachable" | Regional mirror down | Edit `/etc/apt/sources.list` to use `archive.ubuntu.com` | +| "APT lock held" | Another apt process running | Wait for it to finish or `sudo kill ` | +| "Insufficient disk space" | Less than 10GB free | Clean up with `sudo apt autoremove` or expand disk | + ### Console Output The installer uses semantic colors for progress visibility: @@ -677,7 +695,7 @@ acfs continue # View upgrade progress after reboot ### `acfs newproj` — New Project Wizard -Create a new project directory with ACFS defaults (git init, optional bd, Claude settings, AGENTS.md). +Create a new project directory with ACFS defaults (git init, optional br/beads, Claude settings, AGENTS.md). The interactive wizard is recommended for beginners. Interactive wizard (recommended): @@ -690,7 +708,7 @@ acfs newproj -i myapp # Prefill project name The wizard guides you through: - Project naming and location - Tech stack detection/selection -- Feature selection (bd, Claude settings, AGENTS.md, UBS ignore) +- Feature selection (br/beads, Claude settings, AGENTS.md, UBS ignore) - AGENTS.md customization preview
@@ -765,7 +783,7 @@ CLI mode (automation): ```bash acfs newproj myapp acfs newproj myapp /custom/path -acfs newproj myapp --no-bd +acfs newproj myapp --no-br ``` Notes: @@ -976,6 +994,17 @@ Plan (Beads) ──> Coordinate (Agent Mail) ──> Execute (NTM + Agents) | Memory-Augmented Debugging | Past solutions for current bugs | 15 min | | Coordinated Feature Dev | Multiple agents, one feature | 2+ hours | +### Tool Status Page + +The [Tool Status page](https://agent-flywheel.com/tools) provides a searchable catalog of all installed tools: + +- **Search & Filter**: Find tools by name, CLI command, features, or tech stack +- **Category Browsing**: Filter by "Flywheel Stack" (core agentic tools) or "Utilities" +- **Tool Details**: Each card shows the tool name, CLI command, GitHub stars, features, and tech stack +- **Live Data**: Content is auto-generated from `acfs.manifest.yaml` — never manually edited + +This page helps users discover tools they may not know about and understand how each fits into the agentic coding workflow. + ### Interactive Website Components The wizard website includes specialized components for guiding beginners: @@ -1320,7 +1349,20 @@ $ acfs doctor ### Generated Doctor Checks -Doctor checks can be generated from the manifest (`scripts/generated/doctor_checks.sh`) to keep verification logic close to `acfs.manifest.yaml`. Today, the user-facing `acfs doctor` command is implemented in `scripts/lib/doctor.sh` and does not yet consume the generated `doctor_checks.sh` output. +Doctor checks are generated from the manifest (`scripts/generated/doctor_checks.sh`) to keep verification logic close to `acfs.manifest.yaml`. The `acfs doctor` command automatically sources these generated checks to verify all manifest-defined tools. + +**How it works:** +1. The manifest generator creates `doctor_checks.sh` with verify commands for each module +2. `acfs doctor` sources this file and runs each verification check +3. Failed checks display a **fix suggestion** with the exact command to reinstall + +**Example output with fix suggestion:** +``` + ✗ tools.lazygit - Lazygit terminal UI not found + Fix: acfs install --only tools.lazygit +``` + +This architecture ensures doctor checks stay in sync with the installer—if a tool is in the manifest, it will be verified. ### Options @@ -3558,6 +3600,84 @@ This section covers common issues and their solutions. For quick debugging, star | No internet | "curl: (6) Could not resolve host" | Check DNS, try `ping google.com` | | Old bash | Syntax errors | Upgrade to bash 4+ | +### Installation Failure Recovery + +When the installer fails mid-way through, it provides an **auto-resume hint** with a precise command to continue from where it left off. + +**What you'll see on failure:** + +``` +[ERROR] ACFS installation failed! + +To debug: + 1. Check the log: cat /var/log/acfs/install.log + 2. If installed, run: acfs doctor (try as ubuntu) + +╔══════════════════════════════════════════════════════════════╗ +║ To resume installation from this point: ║ +╚══════════════════════════════════════════════════════════════╝ + + curl -sSL https://raw.githubusercontent.com/Dicklesworthstone/.../install.sh | bash -s -- --resume --yes + + Failed phase: phase_9 + Failed step: install_stack +``` + +**Key features of the resume hint:** + +| Feature | Description | +|---------|-------------| +| **Pinned commit** | Uses exact SHA from original run for reproducibility | +| **Preserved flags** | Includes all original flags (--skip-*, --mode, --strict) | +| **Automatic detection** | Reads failed phase/step from `~/.acfs/state.json` | +| **Copyable command** | Ready to paste and run immediately | + +**Manual recovery steps:** + +1. **Review the error**: + ```bash + # Check the full log + cat /var/log/acfs/install.log | tail -50 + + # Or search for ERROR + grep -i error /var/log/acfs/install.log + ``` + +2. **Run diagnostics**: + ```bash + # As the target user (ubuntu) + acfs doctor + + # If running as root + sudo -u ubuntu -i bash -lc 'acfs doctor' + ``` + +3. **Resume installation**: + ```bash + # Use the exact command from the failure output + # Or use the generic resume command: + curl -sSL https://acfs.sh | bash -s -- --resume --yes --mode vibe + ``` + +4. **Check state file** (advanced): + ```bash + # View current installation state + cat ~/.acfs/state.json | jq . + + # See the stored resume hint + jq '.resume_hint' ~/.acfs/state.json + ``` + +**Common failure scenarios:** + +| Scenario | Typical Cause | Recovery | +|----------|---------------|----------| +| Network timeout | Transient connectivity | Wait, then resume | +| APT lock held | Unattended-upgrades | Wait 2-3 min, resume | +| Disk full | Insufficient space | Free space, resume | +| SSH disconnect | Session timeout | Reconnect, resume | +| Tool install failed | Upstream unavailable | Check status, resume | + ### APT Lock Errors **Symptom**: `E: Could not get lock /var/lib/dpkg/lock-frontend` @@ -3580,6 +3700,165 @@ This section covers common issues and their solutions. For quick debugging, star sudo apt-get update ``` +### Install Logs & Summary JSON + +Every ACFS install run produces two artifacts for debugging and tooling: + +**Log File Location:** +``` +~/.acfs/logs/install-YYYYMMDD_HHMMSS.log +``` + +The log file captures all stderr output from the installer, with: +- Header containing version, date, and mode +- All progress messages and errors +- ANSI colors stripped after completion +- Footer with completion timestamp + +**Summary JSON Location:** +``` +~/.acfs/logs/install_summary_YYYYMMDD_HHMMSS.json +``` + +**Summary JSON Schema (v1):** +```json +{ + "schema_version": 1, + "status": "success", // "success" or "failure" + "timestamp": "2026-01-27T...", // ISO 8601 + "total_seconds": 1200, // Wall clock time + "environment": { + "acfs_version": "0.9.0", + "mode": "vibe", + "ubuntu_version": "25.04", + "target_user": "ubuntu", + "target_home": "/home/ubuntu" + }, + "phases": [ + {"id": "phase_0", "duration_seconds": 5}, + {"id": "phase_1", "duration_seconds": 45}, + // ... completed phases in order + ], + "failure": null, // null on success, or: + // "failure": { + // "phase": "phase_9", + // "step": "install_stack", + // "error": "curl failed with exit code 7", + // "resume_hint": "curl -sSL ... | bash -s -- --resume --yes" + // } + "log_file": "/home/ubuntu/.acfs/logs/install-20260127_120000.log" +} +``` + +**Accessing logs:** +```bash +# Find the latest log +ls -lt ~/.acfs/logs/install-*.log | head -1 + +# Find the latest summary +ls -lt ~/.acfs/logs/install_summary_*.json | head -1 + +# Parse summary JSON +jq . ~/.acfs/logs/install_summary_*.json | head -1 + +# Get failed phase (if any) +jq '.failure // "No failure"' ~/.acfs/logs/install_summary_*.json | tail -1 + +# Get phase timings +jq '.phases[] | "\(.id): \(.duration_seconds)s"' ~/.acfs/logs/install_summary_*.json | tail -1 +``` + +**Sharing logs for support:** + +```bash +# Create a support bundle (strips sensitive data) +acfs support-bundle > support-bundle.txt + +# Or manually share (review for secrets first): +cat ~/.acfs/logs/install-*.log | tail -200 # Last 200 lines +cat ~/.acfs/logs/install_summary_*.json | tail -1 # Latest summary +``` + +### Support Bundle Command + +The `acfs support-bundle` command collects all diagnostic data into a single archive for troubleshooting. + +**Usage:** +```bash +acfs support-bundle [options] +``` + +**Options:** + +| Option | Description | +|--------|-------------| +| `--verbose, -v` | Show detailed output during collection | +| `--output, -o DIR` | Output directory (default: `~/.acfs/support`) | +| `--no-redact` | Disable secret redaction (WARNING: bundle may contain secrets) | +| `--help, -h` | Show help | + +**Output files:** +``` +~/.acfs/support// # Unpacked bundle directory +~/.acfs/support/.tar.gz # Compressed archive (shareable) +~/.acfs/support//manifest.json # Bundle manifest +``` + +**What's collected:** + +| File | Description | +|------|-------------| +| `state.json` | Installation state and checkpoints | +| `VERSION` | ACFS version | +| `checksums.yaml` | Upstream verification checksums | +| `logs/install-*.log` | Recent install logs (up to 10) | +| `logs/install_summary_*.json` | Recent install summaries | +| `doctor.json` | Health check results | +| `versions.json` | Installed tool versions | +| `environment.json` | OS, memory, disk, user info | +| `os-release` | Linux distribution info | +| `journal-acfs.log` | Systemd journal for ACFS services | +| `config/.zshrc` | Shell configuration | + +**Security & Redaction:** + +By default, sensitive data is automatically redacted: + +| Pattern | Example | Redacted To | +|---------|---------|-------------| +| OpenAI API keys | `sk-abc123...` | `` | +| AWS keys | `AKIAIOSFODNN...` | `` | +| GitHub tokens | `ghp_xxxx...` | `` | +| Vault tokens | `hvs.xxxx...` | `` | +| Slack tokens | `xoxb-xxxx...` | `` | +| Bearer tokens | `Bearer xxx...` | `Bearer ` | +| JWTs | `eyJhbGc...` | `` | +| Passwords | `"password": "..."` | `"password": ""` | + +**Example workflow:** + +```bash +# Create support bundle +acfs support-bundle + +# Output: ~/.acfs/support/20260127_120000.tar.gz + +# Share the archive when filing an issue +# The archive is safe to share (secrets redacted) +``` + +**Disable redaction (use with caution):** +```bash +# WARNING: Bundle may contain API keys, tokens, and passwords +acfs support-bundle --no-redact +``` + +**When to use:** +- Installation failed and you need to share logs +- Filing a GitHub issue about ACFS +- Diagnosing tool installation problems +- Sharing system state with support + ### Shell Not Changing to zsh **Symptom**: Still seeing bash prompt after install. @@ -3654,6 +3933,42 @@ gemini # Follow Google login flow export PATH="$HOME/.bun/bin:$HOME/.local/bin:$HOME/.cargo/bin:$PATH" ``` +### Doctor Shows Missing Tools + +**Symptom**: `acfs doctor` shows failed checks for tools you expected to be installed. + +**Understanding doctor output:** + +Doctor checks are generated directly from the manifest, so they verify the exact same tools the installer provides. When a check fails, doctor shows a copy-pasteable fix command: + +``` + ✗ tools.lazygit - Lazygit terminal UI not found + Fix: acfs install --only tools.lazygit +``` + +**Solutions**: + +1. **Re-run the specific module** (use the fix suggestion): + ```bash + acfs install --only tools.lazygit # Install just that tool + acfs install --only lang.go # Install a language runtime + acfs install --only stack.dcg # Install a stack tool + ``` + +2. **Re-run an entire phase** (for multiple failures in one category): + ```bash + acfs install --only-phase 4 # Re-run Phase 4: Tools + acfs install --only-phase 8 # Re-run Phase 8: Stack + ``` + +3. **Run auto-fix mode** (applies safe, deterministic fixes): + ```bash + acfs doctor --fix + acfs doctor --fix --dry-run # Preview fixes first + ``` + +**Note**: Doctor checks match the manifest verify commands exactly. If a tool was skipped during installation (e.g., using `--mode safe`), the check will fail. This is expected—run `acfs doctor` to see which tools are missing and decide which to install. + ### Tmux Configuration Errors **Symptom**: Tmux won't start or shows config errors. diff --git a/VERSION b/VERSION index 8f0916f7..a918a2aa 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.5.0 +0.6.0 diff --git a/acfs.manifest.yaml b/acfs.manifest.yaml index 4a7c3e4b..1603fe0e 100644 --- a/acfs.manifest.yaml +++ b/acfs.manifest.yaml @@ -179,6 +179,17 @@ modules: CURL_ARGS=(--proto '=https' --proto-redir '=https' -fsSL) fi curl "${CURL_ARGS[@]}" -o ~/.acfs/zsh/acfs.zshrc "${ACFS_RAW}/acfs/zsh/acfs.zshrc" + - | + # Install ACFS shell completions (zsh) + ACFS_RAW="${ACFS_RAW:-https://raw.githubusercontent.com/Dicklesworthstone/agentic_coding_flywheel_setup/main}" + mkdir -p ~/.acfs/completions + CURL_ARGS=(-fsSL) + if curl --help all 2>/dev/null | grep -q -- '--proto'; then + CURL_ARGS=(--proto '=https' --proto-redir '=https' -fsSL) + fi + curl "${CURL_ARGS[@]}" -o ~/.acfs/completions/_acfs "${ACFS_RAW}/scripts/completions/_acfs" + # Also install bash completions for users who switch shells + curl "${CURL_ARGS[@]}" -o ~/.acfs/completions/acfs.bash "${ACFS_RAW}/scripts/completions/acfs.bash" - | # Install pre-configured Powerlevel10k settings (prevents config wizard on first login) ACFS_RAW="${ACFS_RAW:-https://raw.githubusercontent.com/Dicklesworthstone/agentic_coding_flywheel_setup/main}" @@ -1262,7 +1273,7 @@ modules: language: "Rust" stars: 128 cli_name: "br" - cli_aliases: ["bd"] + cli_aliases: [] command_example: "br ready --json" dependencies: - lang.rust @@ -2208,6 +2219,77 @@ modules: verify: - command -v acfs-update + - id: acfs.nightly + description: Nightly auto-update timer (systemd) + category: acfs + phase: 10 + run_as: target_user + optional: true + enabled_by_default: true + generated: false + tags: [orchestration, maintenance] + dependencies: + - acfs.update + installed_check: + run_as: target_user + command: "systemctl --user is-enabled acfs-nightly-update.timer 2>/dev/null" + install: + - mkdir -p ~/.acfs/scripts ~/.config/systemd/user + - | + # Install nightly update wrapper script + if [[ -n "${ACFS_BOOTSTRAP_DIR:-}" ]] && [[ -f "${ACFS_BOOTSTRAP_DIR}/scripts/lib/nightly_update.sh" ]]; then + cp "${ACFS_BOOTSTRAP_DIR}/scripts/lib/nightly_update.sh" ~/.acfs/scripts/nightly-update.sh + elif [[ -f "scripts/lib/nightly_update.sh" ]]; then + cp "scripts/lib/nightly_update.sh" ~/.acfs/scripts/nightly-update.sh + else + ACFS_RAW="${ACFS_RAW:-https://raw.githubusercontent.com/Dicklesworthstone/agentic_coding_flywheel_setup/main}" + CURL_ARGS=(-fsSL) + if curl --help all 2>/dev/null | grep -q -- '--proto'; then + CURL_ARGS=(--proto '=https' --proto-redir '=https' -fsSL) + fi + curl "${CURL_ARGS[@]}" "${ACFS_RAW}/scripts/lib/nightly_update.sh" -o ~/.acfs/scripts/nightly-update.sh + fi + chmod +x ~/.acfs/scripts/nightly-update.sh + - | + # Install systemd timer unit + if [[ -n "${ACFS_BOOTSTRAP_DIR:-}" ]] && [[ -f "${ACFS_BOOTSTRAP_DIR}/scripts/templates/acfs-nightly-update.timer" ]]; then + cp "${ACFS_BOOTSTRAP_DIR}/scripts/templates/acfs-nightly-update.timer" ~/.config/systemd/user/acfs-nightly-update.timer + elif [[ -f "scripts/templates/acfs-nightly-update.timer" ]]; then + cp "scripts/templates/acfs-nightly-update.timer" ~/.config/systemd/user/acfs-nightly-update.timer + else + ACFS_RAW="${ACFS_RAW:-https://raw.githubusercontent.com/Dicklesworthstone/agentic_coding_flywheel_setup/main}" + CURL_ARGS=(-fsSL) + if curl --help all 2>/dev/null | grep -q -- '--proto'; then + CURL_ARGS=(--proto '=https' --proto-redir '=https' -fsSL) + fi + curl "${CURL_ARGS[@]}" "${ACFS_RAW}/scripts/templates/acfs-nightly-update.timer" -o ~/.config/systemd/user/acfs-nightly-update.timer + fi + - | + # Install systemd service unit + if [[ -n "${ACFS_BOOTSTRAP_DIR:-}" ]] && [[ -f "${ACFS_BOOTSTRAP_DIR}/scripts/templates/acfs-nightly-update.service" ]]; then + cp "${ACFS_BOOTSTRAP_DIR}/scripts/templates/acfs-nightly-update.service" ~/.config/systemd/user/acfs-nightly-update.service + elif [[ -f "scripts/templates/acfs-nightly-update.service" ]]; then + cp "scripts/templates/acfs-nightly-update.service" ~/.config/systemd/user/acfs-nightly-update.service + else + ACFS_RAW="${ACFS_RAW:-https://raw.githubusercontent.com/Dicklesworthstone/agentic_coding_flywheel_setup/main}" + CURL_ARGS=(-fsSL) + if curl --help all 2>/dev/null | grep -q -- '--proto'; then + CURL_ARGS=(--proto '=https' --proto-redir '=https' -fsSL) + fi + curl "${CURL_ARGS[@]}" "${ACFS_RAW}/scripts/templates/acfs-nightly-update.service" -o ~/.config/systemd/user/acfs-nightly-update.service + fi + - | + # Reload systemd and enable the timer + systemctl --user daemon-reload + systemctl --user enable --now acfs-nightly-update.timer + verify: + - systemctl --user is-enabled acfs-nightly-update.timer + notes: + - "Runs acfs-update --yes --quiet daily at 4am with pre-flight health checks" + - "Skips if load average > nproc or disk < 2GB free" + - "Safe cleanup of build artifacts when disk < 5GB" + - "Logs to ~/.acfs/logs/updates/nightly-*.log" + - id: acfs.doctor description: ACFS doctor command for health checks category: acfs diff --git a/acfs/onboard/docs/ntm/command_palette.md b/acfs/onboard/docs/ntm/command_palette.md index 36018066..09d8ae96 100644 --- a/acfs/onboard/docs/ntm/command_palette.md +++ b/acfs/onboard/docs/ntm/command_palette.md @@ -94,7 +94,7 @@ Pick the next bead you can actually do usefully now and start coding on it immed OK, so start systematically and methodically and meticulously and diligently executing those remaining beads tasks that you created in the optimal logical order! Don't forget to mark beads as you work on them. ### do_all_of_it | Do All Of It -OK, please do ALL of that now. Track work via bd beads (no markdown TODO lists): create/claim/update/close beads as you go so nothing gets lost, and keep communicating via Agent Mail when you start/finish work. +OK, please do ALL of that now. Track work via br beads (no markdown TODO lists): create/claim/update/close beads as you go so nothing gets lost, and keep communicating via Agent Mail when you start/finish work. ## Git & Operations diff --git a/acfs/onboard/lessons/16_beads_rust.md b/acfs/onboard/lessons/16_beads_rust.md index 07463cc2..2747c5fe 100644 --- a/acfs/onboard/lessons/16_beads_rust.md +++ b/acfs/onboard/lessons/16_beads_rust.md @@ -15,7 +15,7 @@ beads_rust (`br`) is a local-first issue tracker designed for AI agents. Issues - JSON output for agent consumption - Works offline, syncs on commit -> **Note:** The `bd` alias is available for backward compatibility with the original golang beads. +> **Note:** `br` is the primary command for beads_rust issue tracking. --- @@ -116,16 +116,6 @@ bv --robot-insights --- -## The bd Alias - -For backward compatibility, `bd` is aliased to `br`: - -```bash -# These are equivalent: -bd list --status open -br list --status open -``` - --- ## Quick Reference diff --git a/acfs/onboard/lessons/20_newproj.md b/acfs/onboard/lessons/20_newproj.md index 088e582a..47baf401 100644 --- a/acfs/onboard/lessons/20_newproj.md +++ b/acfs/onboard/lessons/20_newproj.md @@ -76,7 +76,7 @@ Creates `~/code/myproject`. | Flag | Effect | |------|--------| | `--interactive` | TUI wizard (recommended for first use) | -| `--no-bd` | Skip beads initialization | +| `--no-br` | Skip beads initialization | | `--no-claude` | Skip Claude settings | | `--no-agents` | Skip AGENTS.md creation | diff --git a/acfs/tmux/tmux.conf b/acfs/tmux/tmux.conf index 8ee8432d..48b989bf 100644 --- a/acfs/tmux/tmux.conf +++ b/acfs/tmux/tmux.conf @@ -9,8 +9,13 @@ set -g mouse on # Set default terminal for proper color support -set -g default-terminal "screen-256color" +# tmux-256color enables bracketed paste, styled underlines, and other modern features +# that screen-256color lacks (see tmux FAQ and terminfo docs) +set -g default-terminal "tmux-256color" set -ga terminal-overrides ",*256col*:Tc" +# Allow passthrough sequences (kitty graphics, sixel, etc.) and cursor shape overrides +set -g allow-passthrough on +set -ga terminal-overrides ",*:Ss=\\E[%p1%d q:Se=\\E[2 q" # Start windows and panes at 1, not 0 set -g base-index 1 diff --git a/acfs/zsh/acfs.zshrc b/acfs/zsh/acfs.zshrc index 707542be..3d507ee2 100644 --- a/acfs/zsh/acfs.zshrc +++ b/acfs/zsh/acfs.zshrc @@ -23,6 +23,8 @@ if [[ -n "$TERM" ]] && ! infocmp "$TERM" &>/dev/null; then fi # --- Paths (early) --- +# User ~/bin takes highest precedence (for custom shims) +[[ -d "$HOME/bin" ]] && export PATH="$HOME/bin:$PATH" export PATH="$HOME/.cargo/bin:$PATH" # Go (support both apt-style and /usr/local/go) @@ -372,6 +374,28 @@ acfs() { return 1 fi ;; + changelog|changes|log) + if [[ -f "$acfs_home/scripts/lib/changelog.sh" ]]; then + bash "$acfs_home/scripts/lib/changelog.sh" "$@" + elif [[ -x "$acfs_bin" ]]; then + "$acfs_bin" changelog "$@" + else + echo "Error: changelog.sh not found" + echo "Re-run the ACFS installer to get the latest scripts" + return 1 + fi + ;; + export-config|export) + if [[ -f "$acfs_home/scripts/lib/export-config.sh" ]]; then + bash "$acfs_home/scripts/lib/export-config.sh" "$@" + elif [[ -x "$acfs_bin" ]]; then + "$acfs_bin" export-config "$@" + else + echo "Error: export-config.sh not found" + echo "Re-run the ACFS installer to get the latest scripts" + return 1 + fi + ;; version|-v|--version) if [[ -f "$acfs_home/VERSION" ]]; then cat "$acfs_home/VERSION" @@ -385,7 +409,7 @@ acfs() { echo "Usage: acfs " echo "" echo "Commands:" - echo " newproj Create new project (git, bd, AGENTS.md, Claude settings)" + echo " newproj Create new project (git, br, AGENTS.md, Claude settings)" echo " Use 'acfs newproj -i' for interactive TUI wizard" echo " info Quick system overview (hostname, IP, uptime, progress)" echo " cheatsheet Command reference (aliases, shortcuts)" @@ -396,6 +420,8 @@ acfs() { echo " status Quick one-line health summary (fast, no network)" echo " session List/export/import agent sessions (cass)" echo " support-bundle Collect diagnostic data for troubleshooting" + echo " changelog Show recent changes (--all, --since 7d, --json)" + echo " export-config Export config for backup/migration (--json, --minimal)" echo " update Update ACFS tools to latest versions" echo " version Show ACFS version" echo " help Show this help message" @@ -418,6 +444,14 @@ acfs() { esac } +# --- ACFS Tab Completion (zsh) --- +# Load acfs completions if the function is available +if [[ -f "$HOME/.acfs/completions/_acfs" ]]; then + # Add to fpath before compinit, or load directly if compinit already ran + fpath=("$HOME/.acfs/completions" $fpath) + autoload -Uz _acfs 2>/dev/null +fi + # --- Agent aliases (dangerously enabled by design) --- alias cc='NODE_OPTIONS="--max-old-space-size=32768" ~/.local/bin/claude --dangerously-skip-permissions' alias cod='codex --dangerously-bypass-approvals-and-sandbox' @@ -428,8 +462,16 @@ alias bdev='bun run dev' alias bl='bun run lint' alias bt='bun run type-check' -# Beads shortcuts: alias old bd command to new br (beads_rust) -alias bd='br' +# --- br (beads_rust) alias guard --- +# Older ACFS versions incorrectly aliased br='bun run dev'. Remove stale alias if br binary exists. +# whence -p finds the binary path, ignoring aliases/functions (zsh-specific) +if whence -p br &>/dev/null && alias br &>/dev/null; then + unalias br 2>/dev/null +fi +# bd is the legacy Go beads binary name; alias it to br (beads_rust) +if whence -p br &>/dev/null; then + alias bd='br' +fi # MCP Agent Mail helper (installer usually adds `am`, but keep a fallback) alias am='cd ~/mcp_agent_mail 2>/dev/null && scripts/run_server_with_token.sh || echo "mcp_agent_mail not found in ~/mcp_agent_mail"' @@ -454,3 +496,34 @@ bindkey "^[[H" beginning-of-line bindkey "^[[F" end-of-line bindkey "^[[1~" beginning-of-line bindkey "^[[4~" end-of-line + +# --- Beads Viewer (bv) protection --- +# Prevent gcloud's 'bv' (BigQuery Visualizer) from shadowing beads_viewer. +# This function ensures the correct bv is always invoked, regardless of PATH order. +# Must be defined AFTER .zshrc.local is sourced (where gcloud SDK may modify PATH). +bv() { + local bv_bin="" + # Check known locations in order of preference + for candidate in "$HOME/.local/bin/bv" "$HOME/.bun/bin/bv" "$HOME/go/bin/bv" "$HOME/.cargo/bin/bv"; do + if [[ -x "$candidate" ]]; then + bv_bin="$candidate" + break + fi + done + # Fallback: search PATH but skip gcloud's bv + if [[ -z "$bv_bin" ]]; then + while IFS= read -r p; do + if [[ "$p" != *"google-cloud-sdk"* ]]; then + bv_bin="$p" + break + fi + done < <(whence -ap bv 2>/dev/null) + fi + if [[ -n "$bv_bin" ]]; then + "$bv_bin" "$@" + else + echo "Error: beads_viewer (bv) not found. Install with:" >&2 + echo " curl -fsSL https://raw.githubusercontent.com/Dicklesworthstone/beads_viewer/main/install.sh | bash" >&2 + return 1 + fi +} diff --git a/apps/web/app/flywheel/page.tsx b/apps/web/app/flywheel/page.tsx index ba0d1cbe..6b22244b 100644 --- a/apps/web/app/flywheel/page.tsx +++ b/apps/web/app/flywheel/page.tsx @@ -585,7 +585,7 @@ function ToolCard({ tool, index }: { tool: FlywheelTool; index: number }) { {/* Install command */} {tool.installCommand && (
- + {tool.installCommand.length > 60 ? tool.installCommand.slice(0, 60) + "..." : tool.installCommand} diff --git a/apps/web/app/globals.css b/apps/web/app/globals.css index 56b38d65..c3b80e42 100644 --- a/apps/web/app/globals.css +++ b/apps/web/app/globals.css @@ -74,7 +74,8 @@ --secondary-foreground: oklch(0.85 0.01 260); --muted: oklch(0.16 0.015 260); - --muted-foreground: oklch(0.6 0.02 260); + /* WCAG AA compliant: 0.7 on 0.16 bg = ~5.5:1 contrast ratio */ + --muted-foreground: oklch(0.7 0.02 260); /* Warm amber accent */ --accent: oklch(0.78 0.16 75); @@ -115,7 +116,8 @@ /* ============================================ Typography Scale - Fluid (1.25 Major Third) ============================================ */ - --text-xs: clamp(0.6875rem, 0.65rem + 0.15vw, 0.75rem); + /* Minimum 12px for accessibility (0.75rem) */ + --text-xs: clamp(0.75rem, 0.7rem + 0.15vw, 0.8125rem); --text-sm: clamp(0.8125rem, 0.775rem + 0.2vw, 0.875rem); --text-base: clamp(1rem, 0.95rem + 0.25vw, 1.125rem); --text-lg: clamp(1.125rem, 1.05rem + 0.4vw, 1.375rem); @@ -124,6 +126,7 @@ --text-3xl: clamp(2rem, 1.75rem + 1.25vw, 3rem); --text-4xl: clamp(2.5rem, 2.1rem + 2vw, 4rem); --text-5xl: clamp(3rem, 2.5rem + 2.5vw, 5rem); + --text-6xl: clamp(3.5rem, 3rem + 3vw, 6rem); /* Line heights per tier (tighter for headlines) */ --leading-xs: 1.6; @@ -135,6 +138,7 @@ --leading-3xl: 1.2; --leading-4xl: 1.1; --leading-5xl: 1.05; + --leading-6xl: 1; /* Letter spacing (looser for small, tighter for headlines) */ --tracking-xs: 0.025em; @@ -146,6 +150,7 @@ --tracking-3xl: -0.025em; --tracking-4xl: -0.03em; --tracking-5xl: -0.035em; + --tracking-6xl: -0.04em; /* ============================================ Spacing System - 8px Base Unit @@ -218,7 +223,8 @@ --secondary: oklch(0.94 0.01 260); --secondary-foreground: oklch(0.2 0.02 260); --muted: oklch(0.94 0.01 260); - --muted-foreground: oklch(0.45 0.02 260); + /* WCAG AA compliant: 0.4 on 0.94 bg = ~5:1 contrast ratio */ + --muted-foreground: oklch(0.4 0.02 260); --accent: oklch(0.65 0.18 75); --accent-foreground: oklch(0.15 0.02 260); --destructive: oklch(0.55 0.25 25); @@ -513,18 +519,32 @@ Component Utilities ============================================ */ -/* Glass morphism effect */ +/* Glass morphism effect - Stripe-level refinement */ .glass { - background: oklch(0.14 0.02 260 / 0.8); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); - border: 1px solid oklch(0.3 0.02 260 / 0.3); + background: oklch(0.14 0.02 260 / 0.85); + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + border: 1px solid oklch(0.35 0.02 260 / 0.4); + transition: backdrop-filter 200ms ease, border-color 200ms ease, background 200ms ease; +} + +.glass:hover { + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + border-color: oklch(0.4 0.02 260 / 0.5); + background: oklch(0.15 0.02 260 / 0.88); } .glass-subtle { background: oklch(0.14 0.02 260 / 0.6); - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); + transition: backdrop-filter 200ms ease; +} + +.glass-subtle:hover { + backdrop-filter: blur(14px); + -webkit-backdrop-filter: blur(14px); } /* Glow effects */ @@ -562,6 +582,19 @@ background-clip: text; } +/* Display typography - for hero sections and large displays */ +.text-display-5xl { + font-size: var(--text-5xl); + letter-spacing: var(--tracking-5xl); + line-height: var(--leading-5xl); +} + +.text-display-6xl { + font-size: var(--text-6xl); + letter-spacing: var(--tracking-6xl); + line-height: var(--leading-6xl); +} + /* Terminal styling */ .terminal-window { background: oklch(0.08 0.015 260); diff --git a/apps/web/app/glossary/page.tsx b/apps/web/app/glossary/page.tsx index 60179f65..628b4c5d 100644 --- a/apps/web/app/glossary/page.tsx +++ b/apps/web/app/glossary/page.tsx @@ -5,6 +5,7 @@ import { useCallback, useEffect, useMemo, useState } from "react"; import { BookOpen, ChevronDown, Home, Search, Terminal, X } from "lucide-react"; import { Card } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; +import { EmptyState } from "@/components/ui/empty-state"; import { jargonDictionary } from "@/lib/jargon"; import { cn } from "@/lib/utils"; @@ -139,6 +140,10 @@ export default function GlossaryPage() { }, [entries, query, category]); const clearQuery = useCallback(() => setQuery(""), []); + const resetFilters = useCallback(() => { + setQuery(""); + setCategory("all"); + }, []); // If the user lands on /glossary#some-key, scroll to it and open the entry. useEffect(() => { @@ -177,7 +182,7 @@ export default function GlossaryPage() {
-
+
{/* Header */}
setQuery(e.target.value)} placeholder="Search terms (e.g., SSH, tmux, API key)…" + aria-label="Search glossary terms" className="w-full rounded-xl border border-border/50 bg-background px-9 py-2 text-sm outline-none transition-colors focus:border-primary/50 focus:ring-2 focus:ring-primary/20" /> {query.length > 0 && ( @@ -268,11 +274,23 @@ export default function GlossaryPage() { {/* Results */}
{filtered.length === 0 ? ( - -

- No matches. Try a different search or switch back to{" "} - All. -

+ + + Reset filters + + } + variant="compact" + /> ) : ( filtered.map((entry) => ( @@ -281,16 +299,16 @@ export default function GlossaryPage() { id={entry.key} className="group overflow-hidden rounded-2xl border border-border/50 bg-card/60" > - +

{entry.term}

- + #{entry.key} - + {CATEGORY_LABELS[entry.category]}
@@ -371,6 +389,24 @@ export default function GlossaryPage() { )}
+ + {/* Mobile thumb-zone nav */} +
+
+ + +
+
); } diff --git a/apps/web/app/learn/[slug]/lesson-content.tsx b/apps/web/app/learn/[slug]/lesson-content.tsx index eeca0cae..3ab5f5bc 100644 --- a/apps/web/app/learn/[slug]/lesson-content.tsx +++ b/apps/web/app/learn/[slug]/lesson-content.tsx @@ -133,7 +133,7 @@ function LessonSidebar({ Learning Hub - + ACFS Academy
@@ -183,7 +183,7 @@ function LessonSidebar({
- {completedLessons.length} of {LESSONS.length} + {completedLessons.length} of {LESSONS.length} {LESSONS.length - completedLessons.length} remaining
@@ -227,7 +227,7 @@ function LessonSidebar({ ? "bg-gradient-to-br from-emerald-400 to-emerald-600 border-emerald-400/50 text-white shadow-[0_0_20px_rgba(16,185,129,0.5)]" : isCurrent ? "bg-gradient-to-br from-primary to-violet-500 border-primary/50 text-white shadow-[0_0_20px_rgba(var(--primary-rgb),0.5)]" - : "bg-white/[0.05] border-white/10 text-white/40 group-hover:border-white/30 group-hover:bg-white/[0.08] group-hover:text-white/70" + : "bg-white/[0.05] border-white/10 text-white/60 group-hover:border-white/30 group-hover:bg-white/[0.08] group-hover:text-white/80" }`} > {isCompleted ? ( @@ -249,7 +249,7 @@ function LessonSidebar({ }`}> {lesson.title} - + {lesson.duration} @@ -257,7 +257,7 @@ function LessonSidebar({ {/* Active indicator */} {isCurrent && ( -
+
NOW
@@ -273,7 +273,7 @@ function LessonSidebar({
@@ -453,8 +453,8 @@ export function LessonContent({ lesson }: Props) {
{lesson.id + 1} - / - {LESSONS.length} + / + {LESSONS.length}
@@ -512,7 +512,7 @@ export function LessonContent({ lesson }: Props) {
{/* Animated accent */}
-
+
@@ -564,7 +564,7 @@ export function LessonContent({ lesson }: Props) {
@@ -650,15 +650,15 @@ export function LessonContent({ lesson }: Props) { {prevLesson ? ( -
+
-
Previous
+
Previous
{prevLesson.title}
@@ -669,12 +669,12 @@ export function LessonContent({ lesson }: Props) { {nextLesson ? ( -
+
-
Next
+
Next
{nextLesson.title}
diff --git a/apps/web/app/learn/commands/page.tsx b/apps/web/app/learn/commands/page.tsx index 2328978c..ae36b974 100644 --- a/apps/web/app/learn/commands/page.tsx +++ b/apps/web/app/learn/commands/page.tsx @@ -159,10 +159,10 @@ const COMMANDS: CommandEntry[] = [ learnMoreHref: "/learn/ntm-palette", }, { - name: "bd", + name: "br", fullName: "Beads CLI", description: "Create/update issues and dependencies", - example: "bd ready", + example: "br ready", category: "stack", learnMoreHref: "/learn/tools/beads", }, @@ -506,7 +506,7 @@ function CategoryCard({ {cmd.name} - + {cmd.fullName}
@@ -517,7 +517,7 @@ function CategoryCard({
#{anchorId} @@ -668,14 +668,14 @@ export default function CommandReferencePage() {
- + setSearchQuery(e.target.value)} - className="w-full rounded-xl border border-white/[0.08] bg-white/[0.03] py-4 pl-14 pr-5 text-white placeholder:text-white/30 backdrop-blur-xl transition-all duration-300 focus:border-primary/50 focus:bg-white/[0.05] focus:outline-none focus:shadow-[0_0_30px_rgba(var(--primary-rgb),0.15)]" + className="w-full rounded-xl border border-white/[0.08] bg-white/[0.03] py-4 pl-14 pr-5 text-white placeholder:text-white/50 backdrop-blur-xl transition-all duration-300 focus:border-primary/50 focus:bg-white/[0.05] focus:outline-none focus:shadow-[0_0_30px_rgba(var(--primary-rgb),0.15)]" />
@@ -731,10 +731,10 @@ export default function CommandReferencePage() {
- +
-

+

No commands match your search.

diff --git a/apps/web/app/learn/glossary/page.tsx b/apps/web/app/learn/glossary/page.tsx index 2cd5ec94..5d75ac6f 100644 --- a/apps/web/app/learn/glossary/page.tsx +++ b/apps/web/app/learn/glossary/page.tsx @@ -5,6 +5,7 @@ import { useMemo, useState, type ReactNode } from "react"; import { ArrowLeft, BookOpen, Home, Search, Wrench, ShieldCheck, Type, FileQuestion, Sparkles, ChevronDown, ChevronRight } from "lucide-react"; import { getAllTerms, type JargonTerm } from "@/lib/jargon"; import { motion, springs, staggerContainer, fadeUp } from "@/components/motion"; +import { EmptyState } from "@/components/ui/empty-state"; type GlossaryCategory = "concepts" | "tools" | "protocols" | "acronyms"; type CategoryFilter = "all" | GlossaryCategory; @@ -20,7 +21,7 @@ function toAnchorId(value: string): string { const TOOL_TERMS = new Set([ "tmux", "zsh", "bash", "bun", "uv", "cargo", "rust", "go", "git", "gh", "lazygit", "rg", "ripgrep", "fzf", "direnv", "zoxide", "atuin", "ntm", - "bv", "bd", "ubs", "cass", "cm", "caam", "slb", "dcg", "vault", "wrangler", + "bv", "br", "ubs", "cass", "cm", "caam", "slb", "dcg", "vault", "wrangler", "supabase", "vercel", "postgres", ]); @@ -153,7 +154,7 @@ function TermCard({ term }: { term: JargonTerm }) {

#{anchorId} @@ -356,13 +357,13 @@ export default function GlossaryPage() {
- + setSearchQuery(e.target.value)} - className="w-full rounded-xl border border-white/[0.08] bg-white/[0.03] py-4 pl-14 pr-5 text-white placeholder:text-white/30 backdrop-blur-xl transition-all duration-300 focus:border-primary/50 focus:bg-white/[0.05] focus:outline-none focus:shadow-[0_0_30px_rgba(var(--primary-rgb),0.15)]" + className="w-full rounded-xl border border-white/[0.08] bg-white/[0.03] py-4 pl-14 pr-5 text-white placeholder:text-white/50 backdrop-blur-xl transition-all duration-300 focus:border-primary/50 focus:bg-white/[0.05] focus:outline-none focus:shadow-[0_0_30px_rgba(var(--primary-rgb),0.15)]" />
@@ -392,7 +393,7 @@ export default function GlossaryPage() { {/* Count display */} -
-
-
- -
-
-

- No terms found -

-

- Try adjusting your search or category filter to find what you're looking for. -

- { - setSearchQuery(""); - setCategory("all"); - }} - className="rounded-full bg-gradient-to-r from-primary/20 to-violet-500/20 border border-primary/30 px-6 py-3 text-sm font-medium text-white transition-all duration-300 hover:from-primary/30 hover:to-violet-500/30 hover:shadow-[0_0_30px_rgba(var(--primary-rgb),0.3)]" - whileHover={{ scale: 1.05 }} - whileTap={{ scale: 0.95 }} - transition={springs.snappy} - > - Clear filters - + { + setSearchQuery(""); + setCategory("all"); + }} + className="rounded-full bg-gradient-to-r from-primary/20 to-violet-500/20 border border-primary/30 px-6 py-3 text-sm font-medium text-white transition-all duration-300 hover:from-primary/30 hover:to-violet-500/30 hover:shadow-[0_0_30px_rgba(var(--primary-rgb),0.3)]" + whileHover={{ scale: 1.05 }} + whileTap={{ scale: 0.95 }} + transition={springs.snappy} + > + Clear filters + + } + iconContainerClassName="bg-white/[0.05] border border-white/[0.08] shadow-[0_0_30px_rgba(255,255,255,0.08)]" + iconClassName="text-white/60" + titleClassName="text-white" + descriptionClassName="text-white/50" + variant="default" + /> )} diff --git a/apps/web/app/learn/page.tsx b/apps/web/app/learn/page.tsx index c6384f3a..6fc107de 100644 --- a/apps/web/app/learn/page.tsx +++ b/apps/web/app/learn/page.tsx @@ -86,7 +86,7 @@ function LessonCard({ > {/* Ambient glow on hover */} {isAccessible && ( -
+
)} {/* Top gradient line */} @@ -149,7 +149,7 @@ function LessonCard({ {/* Hover arrow */} {isAccessible && ( - + )}
@@ -267,9 +267,9 @@ export default function LearnDashboard() {
- j + j / - k + k {" "}to navigate

All Lessons

-
+
{LESSONS.map((lesson, index) => { const status = getLessonStatus(lesson.id, completedLessons); const accessibleIndex = accessibleLessons.findIndex( @@ -522,7 +522,7 @@ export default function LearnDashboard() { {item.desc}
- + ))} diff --git a/apps/web/app/learn/tools/[tool]/tool-data.tsx b/apps/web/app/learn/tools/[tool]/tool-data.tsx index 6d98ff79..d1da4915 100644 --- a/apps/web/app/learn/tools/[tool]/tool-data.tsx +++ b/apps/web/app/learn/tools/[tool]/tool-data.tsx @@ -105,7 +105,7 @@ export const TOOLS: Record = { glowColor: "rgba(52,211,153,0.4)", docsUrl: "https://github.com/Dicklesworthstone/beads_viewer", docsLabel: "GitHub", - quickCommand: "bd ready", + quickCommand: "br ready", relatedTools: ["agent-mail", "ubs"], }, "agent-mail": { diff --git a/apps/web/app/learn/tools/[tool]/tool-page-content.tsx b/apps/web/app/learn/tools/[tool]/tool-page-content.tsx index 57597b21..a1a68678 100644 --- a/apps/web/app/learn/tools/[tool]/tool-page-content.tsx +++ b/apps/web/app/learn/tools/[tool]/tool-page-content.tsx @@ -70,7 +70,7 @@ function RelatedToolCard({ toolId }: { toolId: ToolId }) {
diff --git a/apps/web/app/wizard/accounts/page.tsx b/apps/web/app/wizard/accounts/page.tsx index 4a379bf0..56b5c010 100644 --- a/apps/web/app/wizard/accounts/page.tsx +++ b/apps/web/app/wizard/accounts/page.tsx @@ -102,7 +102,7 @@ function ServiceCard({ service, isChecked, onToggle }: ServiceCardProps) { /> @@ -171,7 +171,7 @@ function ServiceCard({ service, isChecked, onToggle }: ServiceCardProps) { After install:{" "} - + {service.postInstallCommand} diff --git a/apps/web/app/wizard/generate-ssh-key/page.tsx b/apps/web/app/wizard/generate-ssh-key/page.tsx index b9f95eb3..9b96da83 100644 --- a/apps/web/app/wizard/generate-ssh-key/page.tsx +++ b/apps/web/app/wizard/generate-ssh-key/page.tsx @@ -5,6 +5,7 @@ import { useRouter } from "next/navigation"; import { Key, ShieldCheck, ExternalLink } from "lucide-react"; import { Button } from "@/components/ui/button"; import { CommandCard } from "@/components/command-card"; +import { CodeBlock } from "@/components/ui/code-block"; import { AlertCard, DetailsSection, OutputPreview } from "@/components/alert-card"; import { markStepComplete } from "@/lib/wizardSteps"; import { useWizardAnalytics } from "@/lib/hooks/useWizardAnalytics"; @@ -416,9 +417,9 @@ export default function GenerateSSHKeyPage() { Your public key looks something like this: - - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGx... acfs - +
+ +
Make sure you copy the WHOLE thing, from "ssh-ed25519" to "acfs"!
@@ -436,9 +437,9 @@ export default function GenerateSSHKeyPage() {

"Permission denied": Try this command first, then run the ssh-keygen command again: - - mkdir -p ~/.ssh && chmod 700 ~/.ssh - +
+ +
"File already exists": You already have a key! You can use your existing key, or type "y" and press Enter to overwrite it.

diff --git a/apps/web/app/wizard/install-terminal/page.tsx b/apps/web/app/wizard/install-terminal/page.tsx index 71484a36..596aeaa3 100644 --- a/apps/web/app/wizard/install-terminal/page.tsx +++ b/apps/web/app/wizard/install-terminal/page.tsx @@ -5,6 +5,7 @@ import { useRouter } from "next/navigation"; import { ExternalLink, Terminal, Check } from "lucide-react"; import { Button } from "@/components/ui/button"; import { CommandCard } from "@/components/command-card"; +import { CodeBlock } from "@/components/ui/code-block"; import { AlertCard } from "@/components/alert-card"; import { OutputPreview } from "@/components/alert-card"; import { TrackedLink } from "@/components/tracked-link"; @@ -369,9 +370,9 @@ function WindowsContent() {
In the Windows Terminal window, type exactly: - - ssh -V - +
+ +
That's "ssh" (lowercase), a space, a dash, and a capital "V" diff --git a/apps/web/app/wizard/launch-onboarding/page.tsx b/apps/web/app/wizard/launch-onboarding/page.tsx index 8905cefb..2400f42f 100644 --- a/apps/web/app/wizard/launch-onboarding/page.tsx +++ b/apps/web/app/wizard/launch-onboarding/page.tsx @@ -572,7 +572,7 @@ export default function LaunchOnboardingPage() { {/* SSH Config tip */}
- + 💡 Pro tip: Set up SSH config for easier access
@@ -643,7 +643,7 @@ export default function LaunchOnboardingPage() { {/* Manual editing escape hatch */}
- + How to edit files manually (when AI gets something wrong)
diff --git a/apps/web/app/wizard/layout.tsx b/apps/web/app/wizard/layout.tsx index 89875417..2c84300b 100644 --- a/apps/web/app/wizard/layout.tsx +++ b/apps/web/app/wizard/layout.tsx @@ -127,7 +127,7 @@ export default function WizardLayout({ diff --git a/apps/web/app/wizard/run-installer/page.tsx b/apps/web/app/wizard/run-installer/page.tsx index e75d6e9f..ee57f0ec 100644 --- a/apps/web/app/wizard/run-installer/page.tsx +++ b/apps/web/app/wizard/run-installer/page.tsx @@ -253,7 +253,7 @@ export default function RunInstallerPage() { View install.sh source @@ -262,7 +262,7 @@ export default function RunInstallerPage() { Full repository diff --git a/apps/web/app/wizard/windows-terminal-setup/page.tsx b/apps/web/app/wizard/windows-terminal-setup/page.tsx index 66a05c6a..d40266b5 100644 --- a/apps/web/app/wizard/windows-terminal-setup/page.tsx +++ b/apps/web/app/wizard/windows-terminal-setup/page.tsx @@ -15,6 +15,7 @@ import { } from "lucide-react"; import { Button } from "@/components/ui/button"; import { AlertCard, OutputPreview } from "@/components/alert-card"; +import { CodeBlock } from "@/components/ui/code-block"; import { useVPSIP } from "@/lib/userPreferences"; import { withCurrentSearch } from "@/lib/utils"; import { @@ -174,9 +175,7 @@ export default function WindowsTerminalSetupPage() {

Name:

- - My VPS - +

(or whatever name you prefer, like "ACFS Server" or "Ubuntu VPS")

@@ -206,9 +205,7 @@ export default function WindowsTerminalSetupPage() {

Starting directory (optional):

- - %USERPROFILE% - +

Icon (optional):

diff --git a/apps/web/app/workflow/page.tsx b/apps/web/app/workflow/page.tsx index c2cb62e1..12b060a2 100644 --- a/apps/web/app/workflow/page.tsx +++ b/apps/web/app/workflow/page.tsx @@ -106,7 +106,7 @@ function CollapsibleSection({
{title} {badge && ( - + {badge} )} @@ -408,7 +408,7 @@ const PROMPT_BEST_OF_ALL_WORLDS = `I asked 3 competing LLMs to do the exact same const PROMPT_100_IDEAS = `OK so now I want you to come up with your top 10 most brilliant ideas for adding extremely powerful and cool functionality that will make this system far more compelling, useful, intuitive, versatile, powerful, robust, reliable, etc for the users. Use ultrathink. But be pragmatic and don't think of features that will be extremely hard to implement or which aren't necessarily worth the additional complexity burden they would introduce. But I don't want you to just think of 10 ideas: I want you to seriously think hard and come up with one HUNDRED ideas and then only tell me your 10 VERY BEST and most brilliant, clever, and radically innovative and powerful ideas.`; -const PROMPT_CREATE_BEADS = `OK so please take ALL of that and elaborate on it more and then create a comprehensive and granular set of beads for all this with tasks, subtasks, and dependency structure overlaid, with detailed comments so that the whole thing is totally self-contained and self-documenting (including relevant background, reasoning/justification, considerations, etc.-- anything we'd want our "future self" to know about the goals and intentions and thought process and how it serves the over-arching goals of the project.) Use the \`bd\` tool repeatedly to create the actual beads. Use ultrathink.`; +const PROMPT_CREATE_BEADS = `OK so please take ALL of that and elaborate on it more and then create a comprehensive and granular set of beads for all this with tasks, subtasks, and dependency structure overlaid, with detailed comments so that the whole thing is totally self-contained and self-documenting (including relevant background, reasoning/justification, considerations, etc.-- anything we'd want our "future self" to know about the goals and intentions and thought process and how it serves the over-arching goals of the project.) Use the \`br\` tool repeatedly to create the actual beads. Use ultrathink.`; const PROMPT_REVIEW_BEADS = `Check over each bead super carefully-- are you sure it makes sense? Is it optimal? Could we change anything to make the system work better for users? If so, revise the beads. It's a lot easier and faster to operate in "plan space" before we start implementing these things! Use ultrathink.`; @@ -450,7 +450,7 @@ const PROMPT_IMPROVE_README = `What else can we put in there to make the README const PROMPT_DO_GH_FLOW = `Do all the GitHub stuff: commit, deploy, create tag, bump version, release, monitor gh actions, compute checksums, etc.`; -const PROMPT_DO_ALL_OF_IT = `OK, please do ALL of that now. Track work via bd beads (no markdown TODO lists): create/claim/update/close beads as you go so nothing gets lost, and keep communicating via Agent Mail when you start/finish work.`; +const PROMPT_DO_ALL_OF_IT = `OK, please do ALL of that now. Track work via br beads (no markdown TODO lists): create/claim/update/close beads as you go so nothing gets lost, and keep communicating via Agent Mail when you start/finish work.`; const PROMPT_CHECK_MAIL = `Be sure to check your agent mail and to promptly respond if needed to any messages, and also acknowledge any contact requests; make sure you know the names of all active agents using the MCP Agent Mail system.`; @@ -638,7 +638,7 @@ export default function WorkflowPage() {
- Ecosystem + Ecosystem

The Self-Reinforcing Flywheel

@@ -666,7 +666,7 @@ export default function WorkflowPage() {
{tool.name} - {tool.desc} + {tool.desc}
))} @@ -789,15 +789,15 @@ export default function WorkflowPage() {

Deterministic triage output (recommended)

- bd ready + br ready

Show beads ready to work on

- bd stats + br stats

Project statistics overview

- bd blocked + br blocked

Show blocked issues

@@ -862,11 +862,11 @@ export default function WorkflowPage() {

Key coordination tools agents use:

- bd update ID --status=in_progress + br update ID --status=in_progress

Claim a bead before working

- bd close ID + br close ID

Mark a bead complete

diff --git a/apps/web/components/agent-commands/AgentCardContent.tsx b/apps/web/components/agent-commands/AgentCardContent.tsx index 09c3c282..bc6ccef3 100644 --- a/apps/web/components/agent-commands/AgentCardContent.tsx +++ b/apps/web/components/agent-commands/AgentCardContent.tsx @@ -2,7 +2,7 @@ import { useState } from "react"; import { Copy, Check, Terminal, Sparkles, Code2 } from "lucide-react"; -import { motion, AnimatePresence, springs } from "@/components/motion"; +import { motion, AnimatePresence, springs, useReducedMotion } from "@/components/motion"; import { CommandCard } from "@/components/command-card"; import { cn } from "@/lib/utils"; import type { AgentInfo } from "./AgentHeroCard"; @@ -31,6 +31,8 @@ export function AgentCardContent({ agent, isExpanded }: AgentCardContentProps) { const [activeTab, setActiveTab] = useState("examples"); const [copiedAlias, setCopiedAlias] = useState(null); const personality = agentPersonalities[agent.id]; + const prefersReducedMotion = useReducedMotion(); + const reducedMotion = prefersReducedMotion ?? false; const handleCopy = async (text: string) => { try { @@ -55,10 +57,10 @@ export function AgentCardContent({ agent, isExpanded }: AgentCardContentProps) { {isExpanded && (
@@ -93,18 +95,18 @@ export function AgentCardContent({ agent, isExpanded }: AgentCardContentProps) { {activeTab === "examples" && ( {agent.examples.map((example, i) => (