From 20164d29de7877e975019e57f10a5f74ce738182 Mon Sep 17 00:00:00 2001 From: Logan Lindquist Land Date: Wed, 11 Mar 2026 15:25:27 -0500 Subject: [PATCH] chore(deps): upgrade biome to v2.4.6 and @types/bun to 1.3.10 - Upgrade @biomejs/biome from 1.9.4 to 2.4.6 (major) - Upgrade @types/bun from 1.3.8 to 1.3.10 (patch) - Run biome migrate for v2 config changes - Apply biome v2 auto-fixes (import sorting, unused imports/vars) - Update .beads/.gitignore and README for Dolt backend --- .beads/.gitignore | 65 +++++++++++++++++++------------- .beads/README.md | 42 +++++++++++++++++++-- .beads/backup/backup_state.json | 13 +++++++ .beads/backup/comments.jsonl | 0 .beads/backup/config.jsonl | 11 ++++++ .beads/backup/dependencies.jsonl | 32 ++++++++++++++++ .beads/backup/events.jsonl | 47 +++++++++++++++++++++++ .beads/backup/issues.jsonl | 47 +++++++++++++++++++++++ .beads/backup/labels.jsonl | 0 .beads/hooks/post-checkout | 9 +++++ .beads/hooks/post-merge | 9 +++++ .beads/hooks/pre-commit | 9 +++++ .beads/hooks/pre-push | 9 +++++ .beads/hooks/prepare-commit-msg | 9 +++++ .beads/metadata.json | 8 ++-- .gitignore | 4 ++ biome.json | 15 +++++--- bun.lock | 26 ++++++------- package.json | 15 ++++++-- src/commands/index.ts | 4 +- src/lib/index.ts | 4 +- src/utils/format.ts | 2 +- test/utils/colors.test.ts | 4 +- 23 files changed, 322 insertions(+), 62 deletions(-) create mode 100644 .beads/backup/backup_state.json create mode 100644 .beads/backup/comments.jsonl create mode 100644 .beads/backup/config.jsonl create mode 100644 .beads/backup/dependencies.jsonl create mode 100644 .beads/backup/events.jsonl create mode 100644 .beads/backup/issues.jsonl create mode 100644 .beads/backup/labels.jsonl create mode 100755 .beads/hooks/post-checkout create mode 100755 .beads/hooks/post-merge create mode 100755 .beads/hooks/pre-commit create mode 100755 .beads/hooks/pre-push create mode 100755 .beads/hooks/prepare-commit-msg diff --git a/.beads/.gitignore b/.beads/.gitignore index 4a7a77d..ffb2317 100644 --- a/.beads/.gitignore +++ b/.beads/.gitignore @@ -1,39 +1,52 @@ -# SQLite databases -*.db -*.db?* -*.db-journal -*.db-wal -*.db-shm +# Dolt database (managed by Dolt, not git) +dolt/ +dolt-access.lock -# Daemon runtime files -daemon.lock -daemon.log -daemon.pid +# Runtime files bd.sock +bd.sock.startlock sync-state.json last-touched # Local version tracking (prevents upgrade notification spam after git ops) .local_version -# Legacy database files -db.sqlite -bd.db - # Worktree redirect file (contains relative path to main repo's .beads/) # Must not be committed as paths would be wrong in other clones redirect -# Merge artifacts (temporary files from 3-way merge) -beads.base.jsonl -beads.base.meta.json -beads.left.jsonl -beads.left.meta.json -beads.right.jsonl -beads.right.meta.json +# Sync state (local-only, per-machine) +# These files are machine-specific and should not be shared across clones +.sync.lock +export-state/ + +# Ephemeral store (SQLite - wisps/molecules, intentionally not versioned) +ephemeral.sqlite3 +ephemeral.sqlite3-journal +ephemeral.sqlite3-wal +ephemeral.sqlite3-shm -# NOTE: Do NOT add negation patterns (e.g., !issues.jsonl) here. -# They would override fork protection in .git/info/exclude, allowing -# contributors to accidentally commit upstream issue databases. -# The JSONL files (issues.jsonl, interactions.jsonl) and config files -# are tracked by git by default since no pattern above ignores them. +# Dolt server management (auto-started by bd) +dolt-server.pid +dolt-server.log +dolt-server.lock +dolt-server.port +dolt-server.activity +dolt-monitor.pid + +# Legacy files (from pre-Dolt versions) +*.db +*.db?* +*.db-journal +*.db-wal +*.db-shm +db.sqlite +bd.db +daemon.lock +daemon.log +daemon-*.log.gz +daemon.pid +# NOTE: Do NOT add negation patterns here. +# They would override fork protection in .git/info/exclude. +# Config files (metadata.json, config.yaml) are tracked by git by default +# since no pattern above ignores them. diff --git a/.beads/README.md b/.beads/README.md index 50f281f..2424304 100644 --- a/.beads/README.md +++ b/.beads/README.md @@ -70,12 +70,46 @@ bd init bd create "Try out Beads" ``` +## Dolt Backend + +Beads uses [Dolt](https://www.dolthub.com/) as its database engine. Dolt must be installed for beads to work. + +```bash +# Install Dolt +brew install dolt +``` + +The `.beads/` directory contains: +- **Dolt database** (the `dolt/` directory) +- **`issues.jsonl`** — JSONL backup of all issues (portable, used for recovery) +- **`dolt-server.lock`** — PID file for the Dolt SQL server daemon + +### Recovery / Re-importing Issues + +If beads stops working (e.g., "no beads database found" after a fresh clone, Dolt reinstall, or corrupted state), re-import from the JSONL backup: + +```bash +# Re-initialize and import all issues from JSONL backup +bd init --force --prefix --from-jsonl + +# For this project: +bd init --force --prefix uncov --from-jsonl +``` + +This reads `.beads/issues.jsonl` and rebuilds the Dolt database. The `--force` flag is required when `.beads/` already exists. + +### Stale Daemon + +If you see connection errors, the Dolt server daemon may have a stale PID. Check and kill it: + +```bash +cat .beads/dolt-server.lock # Shows the PID +kill # Kill stale process +bd list # Will restart the daemon automatically +``` + ## Learn More - **Documentation**: [github.com/steveyegge/beads/docs](https://github.com/steveyegge/beads/tree/main/docs) - **Quick Start Guide**: Run `bd quickstart` - **Examples**: [github.com/steveyegge/beads/examples](https://github.com/steveyegge/beads/tree/main/examples) - ---- - -*Beads: Issue tracking that moves at the speed of thought* ⚡ diff --git a/.beads/backup/backup_state.json b/.beads/backup/backup_state.json new file mode 100644 index 0000000..b4c3f07 --- /dev/null +++ b/.beads/backup/backup_state.json @@ -0,0 +1,13 @@ +{ + "last_dolt_commit": "ce2k10ue6864cd9gc024iqh08r99nhv6", + "last_event_id": 0, + "timestamp": "2026-03-11T20:20:20.327917Z", + "counts": { + "issues": 47, + "events": 47, + "comments": 0, + "dependencies": 32, + "labels": 0, + "config": 11 + } +} \ No newline at end of file diff --git a/.beads/backup/comments.jsonl b/.beads/backup/comments.jsonl new file mode 100644 index 0000000..e69de29 diff --git a/.beads/backup/config.jsonl b/.beads/backup/config.jsonl new file mode 100644 index 0000000..d105a1b --- /dev/null +++ b/.beads/backup/config.jsonl @@ -0,0 +1,11 @@ +{"key":"auto_compact_enabled","value":"false"} +{"key":"compact_batch_size","value":"50"} +{"key":"compact_parallel_workers","value":"5"} +{"key":"compact_tier1_days","value":"30"} +{"key":"compact_tier1_dep_levels","value":"2"} +{"key":"compact_tier2_commits","value":"100"} +{"key":"compact_tier2_days","value":"90"} +{"key":"compact_tier2_dep_levels","value":"5"} +{"key":"compaction_enabled","value":"false"} +{"key":"issue_prefix","value":"uncov"} +{"key":"schema_version","value":"6"} diff --git a/.beads/backup/dependencies.jsonl b/.beads/backup/dependencies.jsonl new file mode 100644 index 0000000..a2f8911 --- /dev/null +++ b/.beads/backup/dependencies.jsonl @@ -0,0 +1,32 @@ +{"created_at":"2026-02-03T02:56:18Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-kah","issue_id":"uncov-0lq","type":"blocks"} +{"created_at":"2026-02-03T02:56:18Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-kah","issue_id":"uncov-0ou","type":"blocks"} +{"created_at":"2026-02-03T02:56:17Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-fn0","issue_id":"uncov-2bo","type":"blocks"} +{"created_at":"2026-02-03T02:56:17Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-mv8","issue_id":"uncov-2bo","type":"blocks"} +{"created_at":"2026-02-03T02:56:17Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-ocy","issue_id":"uncov-2bo","type":"blocks"} +{"created_at":"2026-02-03T02:56:17Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-s2m","issue_id":"uncov-2bo","type":"blocks"} +{"created_at":"2026-02-03T02:56:16Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-brm","issue_id":"uncov-38c","type":"blocks"} +{"created_at":"2026-02-03T02:56:16Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-ocy","issue_id":"uncov-38c","type":"blocks"} +{"created_at":"2026-02-03T02:56:16Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-p0r","issue_id":"uncov-38c","type":"blocks"} +{"created_at":"2026-02-03T02:56:16Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-q77","issue_id":"uncov-38c","type":"blocks"} +{"created_at":"2026-02-03T02:56:18Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-38c","issue_id":"uncov-b90","type":"blocks"} +{"created_at":"2026-02-03T02:56:08Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-3ky","issue_id":"uncov-brm","type":"blocks"} +{"created_at":"2026-02-03T02:56:08Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-ed6","issue_id":"uncov-brm","type":"blocks"} +{"created_at":"2026-02-03T02:56:17Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-brm","issue_id":"uncov-e27","type":"blocks"} +{"created_at":"2026-02-03T02:56:17Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-mv8","issue_id":"uncov-e27","type":"blocks"} +{"created_at":"2026-02-03T02:56:18Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-ocy","issue_id":"uncov-e27","type":"blocks"} +{"created_at":"2026-02-03T02:56:17Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-p0r","issue_id":"uncov-e27","type":"blocks"} +{"created_at":"2026-02-03T02:56:07Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-3ky","issue_id":"uncov-ed6","type":"blocks"} +{"created_at":"2026-02-03T02:56:09Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-3ky","issue_id":"uncov-fn0","type":"blocks"} +{"created_at":"2026-02-03T02:56:09Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-ed6","issue_id":"uncov-fn0","type":"blocks"} +{"created_at":"2026-02-03T02:56:18Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-b90","issue_id":"uncov-kah","type":"blocks"} +{"created_at":"2026-02-03T02:56:08Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-3ky","issue_id":"uncov-mv8","type":"blocks"} +{"created_at":"2026-02-03T02:56:09Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-ed6","issue_id":"uncov-mv8","type":"blocks"} +{"created_at":"2026-02-03T02:56:07Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-3ky","issue_id":"uncov-ocy","type":"blocks"} +{"created_at":"2026-02-03T02:56:08Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-3ky","issue_id":"uncov-p0r","type":"blocks"} +{"created_at":"2026-02-03T02:56:08Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-ed6","issue_id":"uncov-p0r","type":"blocks"} +{"created_at":"2026-02-03T02:56:08Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-qu3","issue_id":"uncov-p0r","type":"blocks"} +{"created_at":"2026-02-03T02:56:18Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-38c","issue_id":"uncov-p2k","type":"blocks"} +{"created_at":"2026-02-03T02:56:07Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-3ky","issue_id":"uncov-q77","type":"blocks"} +{"created_at":"2026-02-03T02:56:07Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-3ky","issue_id":"uncov-qu3","type":"blocks"} +{"created_at":"2026-02-03T02:56:09Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-3ky","issue_id":"uncov-s2m","type":"blocks"} +{"created_at":"2026-02-03T02:56:09Z","created_by":"Logan Lindquist Land","depends_on_id":"uncov-ed6","issue_id":"uncov-s2m","type":"blocks"} diff --git a/.beads/backup/events.jsonl b/.beads/backup/events.jsonl new file mode 100644 index 0000000..7d4a50c --- /dev/null +++ b/.beads/backup/events.jsonl @@ -0,0 +1,47 @@ +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":1,"issue_id":"uncov-0lq","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":2,"issue_id":"uncov-0ou","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":3,"issue_id":"uncov-0xe","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":4,"issue_id":"uncov-17j","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":5,"issue_id":"uncov-19b","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":6,"issue_id":"uncov-1e5","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":7,"issue_id":"uncov-1yi","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":8,"issue_id":"uncov-2bo","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":9,"issue_id":"uncov-2ur","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":10,"issue_id":"uncov-38c","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":11,"issue_id":"uncov-38p","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":12,"issue_id":"uncov-3ky","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":13,"issue_id":"uncov-3te","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":14,"issue_id":"uncov-4bm","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":15,"issue_id":"uncov-4du","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":16,"issue_id":"uncov-54t","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":17,"issue_id":"uncov-5yk","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":18,"issue_id":"uncov-67r","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":19,"issue_id":"uncov-6no","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":20,"issue_id":"uncov-77g","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":21,"issue_id":"uncov-a4f","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":22,"issue_id":"uncov-b90","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":23,"issue_id":"uncov-bq5","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":24,"issue_id":"uncov-brm","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":25,"issue_id":"uncov-cgy","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":26,"issue_id":"uncov-e27","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":27,"issue_id":"uncov-ed6","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":28,"issue_id":"uncov-efk","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":29,"issue_id":"uncov-ejy","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":30,"issue_id":"uncov-eqy","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":31,"issue_id":"uncov-fn0","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":32,"issue_id":"uncov-iz5","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":33,"issue_id":"uncov-kah","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":34,"issue_id":"uncov-l2y","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":35,"issue_id":"uncov-mc5","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":36,"issue_id":"uncov-mv8","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":37,"issue_id":"uncov-o9j","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":38,"issue_id":"uncov-ocy","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":39,"issue_id":"uncov-p0r","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":40,"issue_id":"uncov-p2k","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":41,"issue_id":"uncov-q77","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":42,"issue_id":"uncov-qu3","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":43,"issue_id":"uncov-r6p","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":44,"issue_id":"uncov-s2m","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":45,"issue_id":"uncov-tr8","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":46,"issue_id":"uncov-uar","new_value":"","old_value":""} +{"actor":"Logan Lindquist Land","comment":null,"created_at":"2026-03-11T15:20:13Z","event_type":"created","id":47,"issue_id":"uncov-xg6","new_value":"","old_value":""} diff --git a/.beads/backup/issues.jsonl b/.beads/backup/issues.jsonl new file mode 100644 index 0000000..6cbb955 --- /dev/null +++ b/.beads/backup/issues.jsonl @@ -0,0 +1,47 @@ +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"install.sh implemented with all security fixes, passed code review","closed_at":"2026-02-03T14:19:50Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"d503440106ec0d45d8976ef97277d42098ef578ab4fa302ba48b85d6d7bd7d2d","created_at":"2026-02-03T02:55:05Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Create install.sh for curl-based installation.\n\n**Usage:**\n```bash\ncurl -fsSL https://raw.githubusercontent.com/llbbl/uncov/main/install.sh | bash\n```\n\n**Script Behavior:**\n1. Detect OS and architecture\n2. Download appropriate binary from GitHub releases\n3. Install to ~/.local/bin or /usr/local/bin\n4. Verify binary works (uncov --version)\n5. Print success message with PATH instructions if needed\n\n**Platform Detection:**\n```bash\nOS=$(uname -s | tr '[:upper:]' '[:lower:]')\nARCH=$(uname -m)\n# Map to our naming: darwin-arm64, darwin-x64, linux-x64\n```\n\n**Installation Locations:**\n1. If ~/.local/bin exists and is in PATH → install there\n2. Else if user has write access to /usr/local/bin → install there\n3. Else → install to ~/.local/bin and warn about PATH\n\n**Error Handling:**\n- Unsupported platform → clear error message\n- Download failed → retry once, then fail with URL\n- Checksum mismatch → fail with warning\n\n**Success Output:**\n```\nDetected: darwin-arm64\nDownloading uncov v0.1.0...\nInstalling to /usr/local/bin/uncov...\n✓ uncov v0.1.0 installed successfully\\!\n\nRun 'uncov --help' to get started.\n```","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-0lq","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":3,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Create install.sh script for easy binary installation","updated_at":"2026-02-03T14:19:50Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Homebrew tap scaffolded at github.com/llbbl/homebrew-uncov","closed_at":"2026-02-03T14:37:58Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"eab4fbc946ac3545887a7d383a741f6df835048042506f37bdceb4c90a62d25e","created_at":"2026-02-03T02:55:28Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Create Homebrew tap repository for easy macOS installation (v0.3.0 goal).\n\n**Repository:** homebrew-uncov (separate repo)\n\n**Formula: uncov.rb**\n```ruby\nclass Uncov \u003c Formula\n desc \"CLI tool to report files with low test coverage\"\n homepage \"https://github.com/llbbl/uncov\"\n version \"0.1.0\"\n\n on_macos do\n if Hardware::CPU.arm?\n url \"https://github.com/llbbl/uncov/releases/download/v0.1.0/uncov-darwin-arm64\"\n sha256 \"\u003csha256\u003e\"\n else\n url \"https://github.com/llbbl/uncov/releases/download/v0.1.0/uncov-darwin-x64\"\n sha256 \"\u003csha256\u003e\"\n end\n end\n\n on_linux do\n url \"https://github.com/llbbl/uncov/releases/download/v0.1.0/uncov-linux-x64\"\n sha256 \"\u003csha256\u003e\"\n end\n\n def install\n bin.install \"uncov-darwin-arm64\" =\u003e \"uncov\" if OS.mac? \u0026\u0026 Hardware::CPU.arm?\n bin.install \"uncov-darwin-x64\" =\u003e \"uncov\" if OS.mac? \u0026\u0026 !Hardware::CPU.arm?\n bin.install \"uncov-linux-x64\" =\u003e \"uncov\" if OS.linux?\n end\n\n test do\n assert_match \"uncov\", shell_output(\"#{bin}/uncov --version\")\n end\nend\n```\n\n**Installation:**\n```bash\nbrew tap llbbl/uncov\nbrew install uncov\n```\n\n**Automation:**\n- Update formula SHA256 on each release\n- Can be automated via GitHub Actions","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-0ou","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":4,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Create Homebrew tap for uncov distribution","updated_at":"2026-02-03T14:37:58Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T03:47:20Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"7055923bf40de0094c6dd765c75abf498126369fbcaf876103cc02ce100f7f5e","created_at":"2026-02-03T03:43:40Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"**Severity:** Low\n**Location:** src/cli.ts line 55-56\n\n**Issue:** Default coverage path 'coverage/coverage-summary.json' is a magic string.\n\n**The Fix:**\n```typescript\n// At top of file or in constants\nconst DEFAULT_COVERAGE_PATH = 'coverage/coverage-summary.json';\n\n// In parseArgs options:\n'coverage-path': {\n type: 'string',\n short: 'c',\n default: DEFAULT_COVERAGE_PATH,\n},\n```\n\n**Acceptance Criteria:**\n- Default path is a named constant\n- Constant is exported for use by other modules if needed","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-0xe","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":3,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix: Extract default coverage path to constant","updated_at":"2026-02-03T03:47:20Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T03:21:14Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"e9dfb1333198798d9b718a11a2670f84eeff777b213dce387f2a2651547117f9","created_at":"2026-02-03T03:16:17Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"**Issue:** The build script uses @ts-expect-error to suppress a type issue with Bun.build compile option. Should use CLI approach instead.\n\n**Location:** scripts/build.ts lines 39-40\n\n**The Fix:**\nUse CLI via Bun.spawn instead of Bun.build API:\n```typescript\nasync function build(): Promise\u003cvoid\u003e {\n const distDir = './dist';\n await mkdir(distDir, { recursive: true });\n\n console.log('Building uncov for all platforms...\\n');\n\n for (const { target, outfile } of TARGETS) {\n console.log(`Building ${target}...`);\n \n const proc = Bun.spawn([\n 'bun', 'build', '--compile',\n '--target', target,\n '--outfile', `${distDir}/${outfile}`,\n './src/cli.ts'\n ], {\n stdout: 'inherit',\n stderr: 'inherit',\n });\n \n const exitCode = await proc.exited;\n if (exitCode !== 0) {\n console.error(`Failed to build ${target}`);\n process.exit(1);\n }\n \n console.log(` -\u003e ${distDir}/${outfile}`);\n }\n\n console.log('\\nBuild complete!');\n}\n```\n\n**Acceptance Criteria:**\n- No @ts-expect-error in build script\n- `bun run scripts/build.ts` works correctly\n- Build produces binaries in dist/","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-17j","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix: Build script uses @ts-expect-error for compile option","updated_at":"2026-02-03T03:21:14Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:04:56Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"44dcfb462552b226c5fc9f7494b731e877a3de185dd7d4a83aa2c87715673d2c","created_at":"2026-02-03T13:02:41Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"**Severity:** Low\n**Location:** src/lib/config.ts (validatePartialConfig function)\n\n**Issue:** Validates threshold is a number but not within 0-100 range. Could accept -5 or 500.\n\n**The Fix:**\n```typescript\nif (typeof obj.threshold === 'number' \u0026\u0026 obj.threshold \u003e= 0 \u0026\u0026 obj.threshold \u003c= 100) {\n result.threshold = obj.threshold;\n}\n```\n\n**Acceptance Criteria:**\n- Threshold validated to 0-100 range\n- Invalid thresholds are ignored (use default)\n- Add tests for out-of-range values","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-19b","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":3,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix: Add threshold range validation in config","updated_at":"2026-02-03T13:04:56Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T03:46:28Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"81a2bb5ec8eafde8a6bb347d7a259c161158e76e0f3e9e2b72d0802f2d326eeb","created_at":"2026-02-03T03:43:39Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"**Severity:** Critical\n**Location:** src/utils/fs.ts (all file operations)\n\n**Issue:** File utilities accept arbitrary paths without validation. Could allow reading/writing files outside project directory via path traversal (e.g., `../../../etc/passwd`).\n\n**The Fix:**\n```typescript\nimport { resolve, relative, isAbsolute } from 'node:path';\n\nexport function validatePath(targetPath: string, baseDir: string = process.cwd()): string {\n const resolved = resolve(baseDir, targetPath);\n const relativePath = relative(baseDir, resolved);\n \n if (relativePath.startsWith('..') || isAbsolute(relativePath)) {\n throw new Error(`Path \"${targetPath}\" is outside allowed directory`);\n }\n \n return resolved;\n}\n```\n\nApply validation to readJson, writeJson, readText, writeText, appendLine.\n\n**Acceptance Criteria:**\n- validatePath function exists and is tested\n- File operations validate paths when baseDir is provided\n- Attempting to access `../../../etc/passwd` throws error\n- Tests cover path traversal attempts","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-1e5","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":0,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Critical: Add path validation to prevent directory traversal","updated_at":"2026-02-03T03:46:28Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:43:02Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"bc3545fa7726c3c5bff639059c45bfe43e0037b33f48e671d6069ade6f5a2c9d","created_at":"2026-02-03T13:32:32Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Add --verbose flag to show detailed information for troubleshooting.\n\n**Usage:**\n```bash\nuncov --verbose\nuncov init --verbose\nuncov check --verbose\n```\n\n**Verbose Output Examples:**\n\nFor report command:\n```\n[verbose] Loading config from /project\n[verbose] Config sources: CLI overrides, package.json\n[verbose] Final config: { threshold: 10, coveragePath: 'coverage/coverage-summary.json' }\n[verbose] Reading coverage from: /project/coverage/coverage-summary.json\n[verbose] Found 15 files in coverage data\n[verbose] Filtered to 3 files at or below 10% threshold\n\nFiles at or below 10% line coverage: 3\n...\n```\n\nFor init command:\n```\n[verbose] Working directory: /project\n[verbose] Checking for lockfiles...\n[verbose] Found: pnpm-lock.yaml\n[verbose] Detected package manager: pnpm\n[verbose] Reading package.json from: /project/package.json\n[verbose] Existing scripts: dev, build, test\n...\n```\n\n**Implementation:**\n1. Add 'verbose' to CLI parseArgs options (boolean, short: 'V')\n2. Create src/utils/logger.ts with verbose logging utility\n3. Pass verbose flag through to commands\n4. Add [verbose] prefixed logs at key decision points\n\n**Logger Utility:**\n```typescript\nexport function createLogger(verbose: boolean) {\n return {\n verbose: (msg: string) =\u003e verbose \u0026\u0026 console.error(`[verbose] ${msg}`),\n info: (msg: string) =\u003e console.log(msg),\n error: (msg: string) =\u003e console.error(msg),\n };\n}\n```\n\n**Note:** Verbose output goes to stderr so it doesn't interfere with --json output.\n\n**Tests:** Verify verbose flag produces expected output","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-1yi","is_template":0,"issue_type":"feature","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add --verbose flag for debug output","updated_at":"2026-02-03T13:43:02Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:18:54Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"afabe8016c4fabd68623c2559eef2a534588adf027d5210e686ef35aedfdd152","created_at":"2026-02-03T02:53:10Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Create src/commands/init.ts - the `uncov init` command for v0.2.0.\n\n**CLI Flags:**\n- `--force` - Overwrite existing configuration\n\n**Interactive Flow:**\n1. Detect package manager (pnpm \u003e bun \u003e npm \u003e yarn)\n2. Check for existing vitest config\n3. If exists and no --force: prompt to add coverage config\n4. If doesn't exist: create new vitest.config.ts\n5. Add scripts to package.json\n6. Add coverage/ to .gitignore\n\n**Actions Performed:**\n1. **Detect environment**\n - Package manager from lockfiles\n - Existing vitest/vite config\n\n2. **Update package.json**\n - Add `test:coverage`: 'vitest run --coverage'\n - Add `coverage:low`: 'uncov'\n - Skip existing scripts (report which)\n\n3. **Configure vitest**\n - Create or update vitest.config.ts with:\n ```typescript\n coverage: {\n provider: 'v8',\n reporter: ['text', 'json-summary'],\n reportsDirectory: './coverage',\n }\n ```\n\n4. **Update .gitignore**\n - Add 'coverage/' if not present\n\n**Output:**\n```\n✓ Detected package manager: pnpm\n✓ Added script: test:coverage\n✓ Added script: coverage:low\n✓ Updated vitest.config.ts with coverage settings\n✓ Added coverage/ to .gitignore\n\nRun 'pnpm test:coverage' to generate coverage, then 'uncov' to see low coverage files.\n```\n\n**Error Handling:**\n- No package.json → error with instructions\n- Existing coverage config without --force → warn and skip\n\n**Tests Required:** test/commands/init.test.ts","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-2bo","is_template":0,"issue_type":"feature","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement init command: bootstrap coverage configuration","updated_at":"2026-02-03T13:18:54Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T03:46:28Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"5869cf4d2b7383959d8b60be29af89da6ffbb0af166c3aed38ef2e1ce01f3f13","created_at":"2026-02-03T03:43:39Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"**Severity:** Critical\n**Location:** src/utils/fs.ts line 29, src/lib/coverage.ts\n\n**Issue:** `readJson\u003cT\u003e` uses `as T` type assertion without runtime validation. Malformed coverage-summary.json could cause runtime errors or security issues.\n\n**The Fix:**\nAdd validation functions in src/lib/coverage.ts:\n```typescript\nfunction isValidCoverageMetric(obj: unknown): obj is CoverageMetric {\n if (typeof obj \\!== 'object' || obj === null) return false;\n const metric = obj as Record\u003cstring, unknown\u003e;\n return (\n typeof metric.total === 'number' \u0026\u0026\n typeof metric.covered === 'number' \u0026\u0026\n typeof metric.pct === 'number'\n );\n}\n\nfunction isValidFileCoverage(obj: unknown): obj is FileCoverage {\n if (typeof obj \\!== 'object' || obj === null) return false;\n const coverage = obj as Record\u003cstring, unknown\u003e;\n return isValidCoverageMetric(coverage.lines);\n}\n\nexport function parseCoverageSummary(data: unknown): CoverageSummary {\n if (typeof data \\!== 'object' || data === null) {\n throw new Error('Coverage summary must be an object');\n }\n \n const summary = data as Record\u003cstring, unknown\u003e;\n \n if (\\!isValidFileCoverage(summary.total)) {\n throw new Error('Coverage summary missing valid \"total\" field');\n }\n \n return summary as CoverageSummary;\n}\n```\n\n**Acceptance Criteria:**\n- parseCoverageSummary validates structure at runtime\n- Invalid coverage data throws descriptive errors\n- coverage-summary-missing-fields.json fixture is used in tests\n- Tests verify error messages for various invalid inputs","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-2ur","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":0,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Critical: Add runtime validation for parsed JSON coverage data","updated_at":"2026-02-03T03:46:28Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:18:54Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"2bc216af54f4b6318bec86fc5de838c87dedaf084ce3dce7d37ca7a633ae8fd8","created_at":"2026-02-03T02:52:30Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Create src/commands/report.ts - the default command when running `uncov`.\n\n**CLI Flags:**\n- `--threshold \u003cn\u003e` (default: 10) - Show files at or below this line coverage %\n- `--fail` - Exit code 1 if any files below threshold\n- `--json` - Output JSON instead of table\n- `--coverage-path \u003cpath\u003e` (default: coverage/coverage-summary.json)\n\n**Implementation:**\n1. Parse CLI args using util.parseArgs\n2. Read coverage-summary.json via coverage.ts\n3. Filter files at or below threshold\n4. Sort by percentage ascending\n5. Format and output results\n6. Exit with appropriate code\n\n**Exit Codes:**\n- 0: Success (or low coverage found but --fail not set)\n- 1: Low coverage found AND --fail set\n- 2: Missing coverage file or config error\n\n**Output Formats:**\nTable (default):\n```\nFiles at or below 10% line coverage: 3\n\n 0.00% LH 0/LF 120 src/renderer.ts\n 5.26% LH 2/LF 38 src/bootstrap.ts\n 10.00% LH 10/LF 100 src/engine.ts\n```\n\nJSON (--json):\n```json\n[{\"path\": \"src/renderer.ts\", \"percentage\": 0, \"linesHit\": 0, \"linesFound\": 120}, ...]\n```\n\n**Tests Required:** test/commands/report.test.ts","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-38c","is_template":0,"issue_type":"feature","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement report command: default CLI command for coverage reporting","updated_at":"2026-02-03T13:18:54Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:04:56Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"67bca8223ec4e1d49f8abda9c9df3150f573a537699fd4dc7a416df84e431f28","created_at":"2026-02-03T13:02:40Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"**Severity:** Medium\n**Location:** src/lib/detect.ts (lines 58-67) and src/lib/vitest-config.ts (lines 11-20)\n\n**Issue:** Both files define the same list of config files to check (vitest.config.ts, vite.config.ts, etc.). Violates DRY.\n\n**The Fix:**\nCreate src/lib/constants.ts:\n```typescript\nexport const VITEST_CONFIG_FILES = [\n { file: 'vitest.config.ts', type: 'ts' },\n { file: 'vitest.config.js', type: 'js' },\n { file: 'vitest.config.mts', type: 'mts' },\n { file: 'vitest.config.mjs', type: 'mjs' },\n { file: 'vite.config.ts', type: 'ts' },\n { file: 'vite.config.js', type: 'js' },\n { file: 'vite.config.mts', type: 'mts' },\n { file: 'vite.config.mjs', type: 'mjs' },\n] as const;\n\nexport type VitestConfigType = (typeof VITEST_CONFIG_FILES)[number]['type'];\n```\n\nUpdate detect.ts and vitest-config.ts to import from constants.ts.\n\n**Acceptance Criteria:**\n- Constants extracted to shared module\n- Both files import from constants\n- No duplicate config lists\n- Tests still pass","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-38p","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix: Extract shared vitest config file list to constants","updated_at":"2026-02-03T13:04:56Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T03:21:14Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"40dd97d0a3dce83fa90f2457641f783026c411c4b1a40c16ca83e2adc8e2a42f","created_at":"2026-02-03T02:52:05Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Create the initial project structure as defined in the spec:\n\n**Directory Structure:**\n- src/cli.ts - Entry point with arg parsing\n- src/commands/ - Command implementations directory\n- src/lib/ - Core logic directory\n- src/utils/ - Helper utilities directory\n- test/ - Test directory\n- test/fixtures/ - Sample coverage files for testing\n- scripts/ - Build scripts directory\n\n**Base Files to Create:**\n- src/cli.ts with basic structure (parseArgs setup, command routing skeleton)\n- Export barrel files where needed\n\n**Acceptance Criteria:**\n- All directories exist\n- cli.ts has basic structure with parseArgs from util\n- Project compiles with `bun build`","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-3ky","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":0,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Project scaffolding: create src directory structure and base files","updated_at":"2026-02-03T03:21:14Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:04:56Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"19a34f92d4d2285007904eaabba0e4d850dcbfc8508bdaf4419bc03848551ed3","created_at":"2026-02-03T13:02:40Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"**Severity:** Medium\n**Location:** src/lib/vitest-config.ts (lines 43-65)\n\n**Issue:** Regex-based detection is overly broad. Matches any 'coverage' string including comments, imports, or unrelated variables. Can produce false positives.\n\n**The Fix:**\nImprove detection to look for actual coverage config blocks:\n```typescript\nexport function hasCoverageConfig(configPath: string): boolean {\n if (!fileExists(configPath)) {\n return false;\n }\n\n try {\n const content = readText(configPath);\n \n // Primary check: explicit coverage configuration block\n const hasCoverageBlock = /coverage\\s*:\\s*\\{/.test(content);\n if (hasCoverageBlock) {\n return true;\n }\n \n // Secondary check: coverage property assignment\n const hasCoverageProperty = /coverage\\s*:\\s*[a-zA-Z]/.test(content);\n return hasCoverageProperty;\n } catch {\n return false;\n }\n}\n```\n\nAdd JSDoc explaining heuristic nature.\n\n**Acceptance Criteria:**\n- More accurate detection of coverage config\n- JSDoc documents limitations\n- Tests updated for new behavior","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-3te","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix: Improve hasCoverageConfig detection accuracy","updated_at":"2026-02-03T13:04:56Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:43:01Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"a2014c300473d0fb273ac4f604ac9d23cc5ecf382e5b69830debe72f465e0584","created_at":"2026-02-03T13:32:29Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Add ANSI color codes to improve CLI readability. Zero dependencies - use escape codes directly.\n\n**Colors to Add:**\n- Red: Low coverage files, errors, failed checks\n- Green: Success messages, passing checks, files above threshold\n- Yellow: Warnings, skipped items, threshold boundary\n- Cyan: File paths, informational headers\n- Bold: Section headers, important values\n\n**Implementation:**\n\nCreate src/utils/colors.ts:\n```typescript\nconst isColorSupported = process.stdout.isTTY \u0026\u0026 !process.env.NO_COLOR;\n\nexport const colors = {\n red: (s: string) =\u003e isColorSupported ? `\\x1b[31m${s}\\x1b[0m` : s,\n green: (s: string) =\u003e isColorSupported ? `\\x1b[32m${s}\\x1b[0m` : s,\n yellow: (s: string) =\u003e isColorSupported ? `\\x1b[33m${s}\\x1b[0m` : s,\n cyan: (s: string) =\u003e isColorSupported ? `\\x1b[36m${s}\\x1b[0m` : s,\n bold: (s: string) =\u003e isColorSupported ? `\\x1b[1m${s}\\x1b[0m` : s,\n};\n```\n\n**Apply to:**\n- report command: Red for 0% files, yellow for low coverage, green header when no issues\n- init command: Green checkmarks, yellow for skipped, red for errors\n- check command: Green ✓ for pass, red ✗ for fail\n\n**Standards:**\n- Respect NO_COLOR env var (https://no-color.org/)\n- Detect TTY to disable colors when piped\n- Add --no-color flag as override\n\n**Tests:** test/utils/colors.test.ts","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-4bm","is_template":0,"issue_type":"feature","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add colorized terminal output with TTY detection","updated_at":"2026-02-03T13:43:01Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:56:51Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"07c5b47122ef28ffad9c7b2088382d16213c297eb07e4f0b9294bf2cebfbb22e","created_at":"2026-02-03T13:53:36Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"**Severity:** Medium (Performance)\n\nAdd Bun dependency caching to speed up CI:\n\n```yaml\n- name: Cache Bun dependencies\n uses: actions/cache@v4\n with:\n path: ~/.bun/install/cache\n key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb') }}\n restore-keys: |\n ${{ runner.os }}-bun-\n```\n\nAdd this before the 'Install dependencies' step in both test and build jobs.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-4du","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix: Add dependency caching to CI workflow","updated_at":"2026-02-03T13:56:51Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:04:56Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"85d082d98a04e1b15a6289b29bed524a6199c021bceb1775d782766e6eae026a","created_at":"2026-02-03T13:02:41Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"**Severity:** Low\n**Location:** src/lib/detect.ts (detectGitignore function)\n\n**Issue:** Only matches exact patterns. Misses valid gitignore patterns like 'coverage*', '**/coverage', 'coverage/**'.\n\n**The Fix:**\nExpand pattern matching:\n```typescript\nconst hasCoverage = lines.some((line) =\u003e {\n if (line.startsWith('#') || line === '') {\n return false;\n }\n // Match common coverage patterns\n return /^[/*]*coverage[/*]*$/.test(line) || \n line.startsWith('coverage') ||\n line.endsWith('/coverage') ||\n line.endsWith('/coverage/');\n});\n```\n\n**Acceptance Criteria:**\n- Matches coverage*, **/coverage, coverage/** patterns\n- Add tests for glob patterns","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-54t","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":3,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix: Improve gitignore pattern matching","updated_at":"2026-02-03T13:04:56Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:43:01Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"9ebd1e73797b0bbf2c3d59405d125ccdfab9485b67a5ec6542735a10d1410b5f","created_at":"2026-02-03T13:41:48Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"**Severity:** Medium\n\nAdd test coverage for --verbose flag in check and report commands.\n\nFor test/commands/check.test.ts:\n```typescript\ndescribe('with --verbose flag', () =\u003e {\n it('should output debug information to stderr', async () =\u003e {\n // Setup and call checkCommand({ verbose: true })\n // Verify stderr contains '[verbose]'\n });\n});\n```\n\nFor test/commands/report.test.ts:\n```typescript\ndescribe('with --verbose flag', () =\u003e {\n it('should output debug information to stderr', async () =\u003e {\n // Setup and call reportCommand({ verbose: true })\n // Verify stderr contains '[verbose]'\n });\n});\n```","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-5yk","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix: Add verbose flag tests for check and report commands","updated_at":"2026-02-03T13:43:01Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:43:01Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"61992ecc1ec13df9687e23bb7022bdd55f027a9a9656883be294bb7799e4d8cb","created_at":"2026-02-03T13:41:47Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"**Severity:** Low\n\nRemove the unused default `colors` instance from src/utils/colors.ts (line 64).\n\nAll commands correctly use `createColors(options.noColor)`. The default export is never used and could mislead developers.\n\nRemove:\n```typescript\nexport const colors = createColors();\n```","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-67r","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":3,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix: Remove unused colors default export","updated_at":"2026-02-03T13:43:01Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:43:01Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"2e6ee5226491c2727a93506d607e0f8b3711cb7538d7bf486c261057f82e47e6","created_at":"2026-02-03T13:41:46Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"**Severity:** Low\n\nRemove unused `Colors` and `Logger` type imports from:\n- src/commands/check.ts (lines 9, 11)\n- src/commands/init.ts (lines 8, 10)\n- src/commands/report.ts (lines 12, 15)\n\nChange from:\n```typescript\nimport { type Colors, createColors } from '../utils/colors';\nimport { type Logger, createLogger } from '../utils/logger';\n```\n\nTo:\n```typescript\nimport { createColors } from '../utils/colors';\nimport { createLogger } from '../utils/logger';\n```","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-6no","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":3,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix: Remove unused type imports from commands","updated_at":"2026-02-03T13:43:01Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T03:21:13Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"2fc50b4a2196997bd2d6867e597524b5e0b4e39977b97c59ca1aad242b901198","created_at":"2026-02-03T03:16:16Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"**Issue:** The formatting utilities (formatPercent, formatLines, formatFileLine, formatReport) have implementations but no unit tests. These pure functions are ideal for unit testing.\n\n**Location:** Create test/format.test.ts\n\n**Tests to Add:**\n```typescript\nimport { describe, expect, it } from 'bun:test';\nimport { formatPercent, formatLines, formatFileLine, formatReport } from '../src/utils/format';\n\ndescribe('formatPercent', () =\u003e {\n it('should format 0% correctly', () =\u003e {\n expect(formatPercent(0)).toBe(' 0.00%');\n });\n \n it('should format 100% correctly', () =\u003e {\n expect(formatPercent(100)).toBe('100.00%');\n });\n \n it('should format decimal percentages', () =\u003e {\n expect(formatPercent(5.26)).toBe(' 5.26%');\n });\n});\n\ndescribe('formatLines', () =\u003e {\n it('should format line counts with padding', () =\u003e {\n expect(formatLines(10, 100)).toBe('LH 10/LF 100');\n });\n});\n\ndescribe('formatReport', () =\u003e {\n it('should show message when no files below threshold', () =\u003e {\n expect(formatReport([], 10)).toBe('No files at or below 10% line coverage.');\n });\n});\n```\n\n**Acceptance Criteria:**\n- test/format.test.ts exists with comprehensive tests\n- All format functions have test coverage\n- Tests pass with `bun test`","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-77g","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add: Unit tests for format utilities","updated_at":"2026-02-03T03:21:13Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T03:19:02Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"609144f5c0f7b3f36c92c1ca0c7d2c9185f8c9cdbe20128d6f1b8c2fe9591974","created_at":"2026-02-03T03:14:50Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"**Issue:** Version string '0.1.0' is duplicated in package.json and cli.ts (line 11). Creates maintenance burden and version mismatch risk.\n\n**Location:** src/cli.ts line 11\n\n**The Fix:**\n```typescript\n// src/cli.ts - Import version from package.json\nimport pkg from '../package.json' with { type: 'json' };\n\nconst VERSION = pkg.version;\n```\n\n**Acceptance Criteria:**\n- VERSION constant reads from package.json\n- `bun run dev -- --version` shows correct version\n- No duplicate version strings in codebase","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-a4f","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix: Import version from package.json instead of hardcoding","updated_at":"2026-02-03T03:19:02Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:43:02Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"5fb4d310d207eeab487deed3d91e56234aa7045cfc5917a55cf5fc8a806d40fe","created_at":"2026-02-03T02:54:54Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Create scripts/build.ts for building cross-platform binaries.\n\n**Target Platforms:**\n- darwin-arm64 (macOS Apple Silicon)\n- darwin-x64 (macOS Intel)\n- linux-x64 (Linux)\n- windows-x64 (Windows)\n\n**Build Command:**\n```bash\nbun build --compile --target=bun-{platform}-{arch} --outfile=dist/uncov-{platform}-{arch}\n```\n\n**Script Features:**\n1. Clean dist/ directory before build\n2. Build for all platforms in parallel\n3. Report success/failure for each target\n4. Generate checksums (SHA256) for each binary\n\n**Output Structure:**\n```\ndist/\n├── uncov-darwin-arm64\n├── uncov-darwin-arm64.sha256\n├── uncov-darwin-x64\n├── uncov-darwin-x64.sha256\n├── uncov-linux-x64\n├── uncov-linux-x64.sha256\n├── uncov-windows-x64.exe\n└── uncov-windows-x64.exe.sha256\n```\n\n**Package.json Scripts:**\n```json\n{\n \"build:local\": \"bun build --compile --outfile=dist/uncov ./src/cli.ts\",\n \"build:all\": \"bun run scripts/build.ts\"\n}\n```\n\n**Tests:** Manual verification (build and run on local platform)","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-b90","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement build script for cross-platform binaries","updated_at":"2026-02-03T13:43:02Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T14:19:21Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"12b6cd8321b223884480f69c94b19011af6f547e32dec045cc3bbb7f31dd1f0b","created_at":"2026-02-03T14:19:05Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Lines 266-267: Warn user before attempting sudo. Add: warn \"Permission denied. Attempting install with sudo...\" before the sudo cp command.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-bq5","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Warn user before sudo escalation in install.sh","updated_at":"2026-02-03T14:19:21Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:04:56Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"e18f9b77492ecf34dab415d3935ab504585e78fc42ed499c4e882095f1a029a4","created_at":"2026-02-03T02:52:31Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Create src/lib/config.ts to handle configuration loading.\n\n**Config Sources (priority order):**\n1. CLI flags (highest priority)\n2. `uncov.config.json` in project root\n3. `uncov` field in `package.json`\n4. Defaults (lowest priority)\n\n**Config Schema:**\n```typescript\ninterface UncovConfig {\n threshold: number; // default: 10\n exclude: string[]; // glob patterns to exclude\n failOnLow: boolean; // default: false\n coveragePath: string; // default: 'coverage/coverage-summary.json'\n}\n```\n\n**Functions to Implement:**\n- `loadConfig(cliOverrides?: Partial\u003cUncovConfig\u003e): UncovConfig`\n- `findConfigFile(): string | null` - Look for uncov.config.json\n- `readPackageJsonConfig(): Partial\u003cUncovConfig\u003e | null`\n- `mergeConfigs(...configs: Partial\u003cUncovConfig\u003e[]): UncovConfig`\n\n**Config File Format:**\n```json\n{\n \"threshold\": 20,\n \"exclude\": [\"**/*.test.ts\", \"**/index.ts\"],\n \"failOnLow\": false\n}\n```\n\n**Tests Required:** test/lib/config.test.ts","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-brm","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement config.ts: read uncov configuration","updated_at":"2026-02-03T13:04:56Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T03:21:13Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"86e8a9b4c89b013d12a486247edcc52ab77e53c10ec24e9c7d6a9f5749bdce54","created_at":"2026-02-03T03:16:16Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"**Issue:** Tests spawn processes and check stdout but don't verify exit codes. Need to assert on exit codes for proper testing.\n\n**Location:** test/cli.test.ts (all test cases)\n\n**The Fix:**\n```typescript\nit('should show version with --version flag', async () =\u003e {\n const proc = Bun.spawn(['bun', 'run', './src/cli.ts', '--version'], {\n cwd: `${import.meta.dir}/..`,\n stdout: 'pipe',\n stderr: 'pipe',\n });\n \n const exitCode = await proc.exited;\n const output = await new Response(proc.stdout).text();\n \n expect(exitCode).toBe(0);\n expect(output.trim()).toBe('0.1.0');\n});\n```\n\n**Acceptance Criteria:**\n- All existing tests assert exit code 0\n- Add test for exit code 2 on invalid input\n- Tests check both stdout and exit codes","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-cgy","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Improve: Add exit code assertions to CLI tests","updated_at":"2026-02-03T03:21:13Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:18:54Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"7a07a3c0e5b00a734f101675eaaa3d3c5706c3f06863c18bc55ced7c868929cd","created_at":"2026-02-03T02:53:11Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Create src/commands/check.ts - the `uncov check` command for v0.3.0.\n\n**Purpose:** Verify coverage setup is correct (useful for CI).\n\n**Checks Performed:**\n1. **Vitest config exists and has coverage settings**\n - Look for vitest.config.* or vite.config.* with test section\n - Verify coverage.reporter includes 'json-summary'\n - Verify coverage.reportsDirectory is set\n\n2. **coverage-summary.json exists**\n - Check default path: coverage/coverage-summary.json\n - Or configured path from uncov config\n\n3. **Scripts are configured**\n - Check for test:coverage or similar script\n - Check for uncov script (optional)\n\n**Output (success):**\n```\n✓ Vitest config found: vitest.config.ts\n✓ Coverage reporter configured: json-summary\n✓ Coverage summary exists: coverage/coverage-summary.json\n✓ Scripts configured: test:coverage\n\nAll checks passed!\n```\n\n**Output (failure):**\n```\n✗ Coverage summary not found: coverage/coverage-summary.json\n Run 'pnpm test:coverage' to generate coverage data\n\n1 check failed\n```\n\n**Exit Codes:**\n- 0: All checks pass\n- 1: One or more checks failed\n- 2: Configuration error\n\n**Tests Required:** test/commands/check.test.ts","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-e27","is_template":0,"issue_type":"feature","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":3,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement check command: verify coverage setup","updated_at":"2026-02-03T13:18:54Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T03:47:20Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"eacfb380f20946d670ad699058c704503ba758d9c64ca663dc445ad7c0bc2f89","created_at":"2026-02-03T02:54:33Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Create src/utils/fs.ts for common file operations.\n\n**Functions to Implement:**\n\n`fileExists(path: string): boolean`\n- Check if file exists (sync)\n\n`readJson\u003cT\u003e(path: string): T`\n- Read and parse JSON file\n- Throw descriptive error on parse failure\n\n`writeJson(path: string, data: unknown): void`\n- Write JSON with 2-space indent\n- Ensure directory exists\n\n`readText(path: string): string`\n- Read text file contents\n\n`writeText(path: string, content: string): void`\n- Write text file\n- Ensure directory exists\n\n`ensureDir(path: string): void`\n- Create directory if it doesn't exist (recursive)\n\n`appendLine(path: string, line: string): void`\n- Append line to file (create if doesn't exist)\n- Handle trailing newline properly\n\n**Error Handling:**\n- All functions should throw descriptive errors\n- Include file path in error messages\n- Distinguish between 'not found' and 'permission denied'\n\n**Tests Required:** test/utils/fs.test.ts","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-ed6","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement fs.ts: file system helper utilities","updated_at":"2026-02-03T03:47:20Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:43:01Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"6fafc91c936dfdb8e2a64d1a31e5d71c53f3a98ab5de4629ded269ad7914c2cf","created_at":"2026-02-03T13:41:48Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"**Severity:** Medium\n\nAfter build succeeds, verify the binary file actually exists before generating checksum.\n\nIn scripts/build.ts, add check after successful build:\n```typescript\nif (exitCode === 0) {\n // Verify the binary was actually created\n if (!existsSync(outPath)) {\n return {\n target,\n outfile,\n success: false,\n error: 'Binary file was not created despite successful build',\n };\n }\n // Then generate checksum...\n}\n```","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-efk","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix: Add binary existence check in build script","updated_at":"2026-02-03T13:43:01Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T03:19:03Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"f6abbe748a5180d7399780331582f0bb62341c9f18a8dd9edd663f0a07cc2d06","created_at":"2026-02-03T03:15:52Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"**Issue:** The threshold is parsed with Number.parseInt() but there's no validation for non-numeric input, negative values, or values over 100.\n\n**Location:** src/cli.ts line 84\n\n**The Fix:**\n```typescript\nfunction parseCliArgs(args: string[]): ParsedArgs {\n // ... existing parseArgs code ...\n\n const thresholdRaw = values.threshold ?? '10';\n const threshold = Number.parseInt(thresholdRaw, 10);\n \n if (Number.isNaN(threshold)) {\n console.error(`Error: Invalid threshold value \"${thresholdRaw}\". Must be a number.`);\n process.exit(2);\n }\n \n if (threshold \u003c 0 || threshold \u003e 100) {\n console.error(`Error: Threshold must be between 0 and 100, got ${threshold}.`);\n process.exit(2);\n }\n\n return {\n // ... rest\n threshold,\n };\n}\n```\n\n**Acceptance Criteria:**\n- `uncov --threshold abc` shows error and exits 2\n- `uncov --threshold -10` shows error and exits 2\n- `uncov --threshold 150` shows error and exits 2\n- `uncov --threshold 50` works normally","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-ejy","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix: Add threshold argument validation","updated_at":"2026-02-03T03:19:03Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:56:51Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"c529dcac4af3a104afcce875c57f1c36f034b8cfedcd4ca5bfb5fbb9e68702eb","created_at":"2026-02-03T13:53:30Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"**Severity:** High (Security)\n\nMove `contents: write` permission from workflow level to only the release job.\n\n**Current (insecure):**\n```yaml\npermissions:\n contents: write # Applied to ALL jobs\n```\n\n**Fix:**\n```yaml\njobs:\n test:\n permissions:\n contents: read\n \n build:\n permissions:\n contents: read\n \n release:\n permissions:\n contents: write # Only release needs write\n```","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-eqy","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":0,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix: Move contents:write permission to release job only","updated_at":"2026-02-03T13:56:51Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:04:56Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"3f8d06ef7f6eb2a2bc8977d4fa15547978763e5a19c4436bfaee6eb433f4b021","created_at":"2026-02-03T02:52:50Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Create src/lib/package-json.ts for safely modifying package.json.\n\n**Functions to Implement:**\n\n`readPackageJson(path?: string): PackageJson`\n- Read and parse package.json\n- Handle missing file gracefully\n\n`writePackageJson(pkg: PackageJson, path?: string): void`\n- Write with consistent formatting (2-space indent)\n- Preserve existing formatting where possible\n\n`addScripts(scripts: Record\u003cstring, string\u003e): { added: string[]; skipped: string[] }`\n- Add scripts only if they don't exist\n- Return which were added vs skipped (already exist)\n\n`hasScript(name: string): boolean`\n- Check if a script exists\n\n**Scripts to Add (via init command):**\n```json\n{\n \"test:coverage\": \"vitest run --coverage\",\n \"coverage:low\": \"uncov\"\n}\n```\n\n**Safety:**\n- Never overwrite existing scripts without --force\n- Backup original before modification (optional)\n- Validate JSON before writing\n\n**Tests Required:** test/lib/package-json.test.ts","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-fn0","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement package-json.ts: safe package.json modification","updated_at":"2026-02-03T13:04:56Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T14:19:21Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"d1d9c4e5103cac1d67d584c0d75780de84b1cdb90d0285638212f3eefe7b6f10","created_at":"2026-02-03T14:19:05Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Line 186: Add error handling for mktemp failure. Change: TMP_DIR=$(mktemp -d) to: TMP_DIR=$(mktemp -d) || error \"Failed to create temporary directory\"","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-iz5","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add error handling for mktemp in install.sh","updated_at":"2026-02-03T14:19:21Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:56:51Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"b70ad44c3490700436b2ff2ba8e0653a22c1ea1c1b045c76f09b8bb710de89e9","created_at":"2026-02-03T02:54:54Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Create .github/workflows/ci.yml for automated testing and releases.\n\n**Workflow Triggers:**\n- Push to main\n- Pull requests to main\n- Tags matching v*.*.*\n\n**Jobs:**\n\n**1. Test Job**\n- Runs on: ubuntu-latest\n- Steps:\n - Checkout\n - Setup Bun\n - Install dependencies (bun install)\n - Run linter (bun run lint)\n - Run tests (bun test)\n\n**2. Build Job** (on tag push only)\n- Runs on: matrix of [ubuntu-latest, macos-latest, windows-latest]\n- Steps:\n - Checkout\n - Setup Bun\n - Build binary for platform\n - Upload artifact\n\n**3. Release Job** (on tag push, after build)\n- Create GitHub release\n- Upload all binary artifacts\n- Generate release notes from commits\n\n**Release Artifact Names:**\n- uncov-darwin-arm64\n- uncov-darwin-x64\n- uncov-linux-x64\n- uncov-windows-x64.exe\n\n**Matrix Strategy:**\n```yaml\nstrategy:\n matrix:\n include:\n - os: macos-latest\n target: darwin-arm64\n - os: macos-13\n target: darwin-x64\n - os: ubuntu-latest\n target: linux-x64\n - os: windows-latest\n target: windows-x64\n```","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-kah","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Create GitHub Actions CI workflow for testing and releases","updated_at":"2026-02-03T13:56:51Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:43:01Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"67793c04a5dd6a4788b5d012cd2210e55eaaad65ebfcf2edead357b4724156f6","created_at":"2026-02-03T13:32:29Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Add --dry-run flag to show what init would change without modifying files.\n\n**Usage:**\n```bash\nuncov init --dry-run\n```\n\n**Output Format:**\n```\nDry run - no files will be modified\n\nWould detect package manager: pnpm\nWould add script: test:coverage -\u003e 'vitest run --coverage'\nWould add script: coverage:low -\u003e 'uncov'\nWould create: vitest.config.ts\nWould append to .gitignore: coverage/\n\nRun without --dry-run to apply these changes.\n```\n\n**Implementation:**\n1. Add 'dry-run' to CLI parseArgs options (boolean flag)\n2. Pass dryRun option to initCommand()\n3. In initCommand, check dryRun before each write operation\n4. Use 'Would X' prefix for dry-run output vs '✓ X' for real execution\n5. Skip all writeText, appendLine, writePackageJson calls when dry-run\n\n**CLI Addition:**\n```typescript\n'dry-run': {\n type: 'boolean',\n default: false,\n},\n```\n\n**Tests:** Add dry-run tests to test/commands/init.test.ts\n- Verify no files are created/modified\n- Verify output shows 'Would' prefixes\n- Verify exit code is 0","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-l2y","is_template":0,"issue_type":"feature","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add --dry-run flag to init command","updated_at":"2026-02-03T13:43:01Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T14:19:21Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"97142953a926f34ea362241a1ff8f6ec3301f26f7ac24ef38c739210b4645767","created_at":"2026-02-03T14:18:59Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Replace cat | awk with awk directly in install.sh line 202. Change: EXPECTED_CHECKSUM=$(cat \"$TMP_CHECKSUM\" | awk '{print $1}') to: EXPECTED_CHECKSUM=$(awk '{print $1}' \"$TMP_CHECKSUM\")","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-mc5","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix UUOC in install.sh line 202","updated_at":"2026-02-03T14:19:21Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:04:56Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"49b11fe77e202a1830dd551ba68ac36fc3e8017c7045974ec2d6a6cfd172201c","created_at":"2026-02-03T02:52:49Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Create src/lib/detect.ts for detecting project environment.\n\n**Functions to Implement:**\n\n`detectPackageManager(): 'pnpm' | 'bun' | 'npm' | 'yarn'`\n- Check for lockfiles in priority order:\n 1. pnpm-lock.yaml → 'pnpm'\n 2. bun.lockb → 'bun'\n 3. package-lock.json → 'npm'\n 4. yarn.lock → 'yarn'\n- Default to 'npm' if none found\n\n`detectVitestConfig(): { path: string; type: 'ts' | 'js' | 'mts' | 'mjs' } | null`\n- Look for vitest.config.{ts,js,mts,mjs}\n- Also check vite.config.* with test section\n\n`detectExistingCoverageConfig(): boolean`\n- Check if vitest config already has coverage settings\n\n`detectGitignore(): { exists: boolean; hasCoverage: boolean }`\n- Check if .gitignore exists\n- Check if 'coverage/' or 'coverage' is already listed\n\n**Tests Required:** test/lib/detect.test.ts","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-mv8","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement detect.ts: package manager and config detection","updated_at":"2026-02-03T13:04:56Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T03:19:02Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"95280ed87eab9bedf30825c260540b37d3e2305a325d8d726f8000f216ccf342","created_at":"2026-02-03T03:14:50Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"**Issue:** There are two fileExists functions - one stub in detect.ts (line 28) and one implemented in utils/fs.ts (line 12). This violates DRY and will cause confusion.\n\n**Locations:**\n- src/lib/detect.ts line 28 (stub - REMOVE)\n- src/utils/fs.ts line 12 (implementation - KEEP)\n\n**The Fix:**\nRemove the stub from detect.ts and import from utils:\n```typescript\n// src/lib/detect.ts\nimport { fileExists } from '../utils/fs';\n\n// Then use fileExists() in detectPackageManager implementation\n```\n\n**Acceptance Criteria:**\n- Only one fileExists function exists (in utils/fs.ts)\n- detect.ts imports from utils/fs\n- No barrel export conflicts","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-o9j","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix: Remove duplicate fileExists function from detect.ts","updated_at":"2026-02-03T03:19:02Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T03:47:20Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"1845c10a5afab4cab53b1e0d42cff3091baf4270bfb5dce7d47379eafd02a047","created_at":"2026-02-03T02:52:31Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Complete src/cli.ts as the main entry point.\n\n**Responsibilities:**\n- Parse top-level args to determine command\n- Route to appropriate command handler\n- Handle --help and --version flags\n- Graceful error handling with user-friendly messages\n\n**Commands to Route:**\n- (default/no command) → report command\n- `init` → init command\n- `check` → check command\n\n**Global Flags:**\n- `--help, -h` - Show help text\n- `--version, -v` - Show version from package.json\n\n**Help Output:**\n```\nuncov - Report files with low test coverage\n\nUsage: uncov [command] [options]\n\nCommands:\n (default) Report files below coverage threshold\n init Bootstrap coverage configuration\n check Verify coverage setup\n\nOptions:\n --threshold \u003cn\u003e Coverage threshold percentage (default: 10)\n --fail Exit 1 if files below threshold\n --json Output as JSON\n --help, -h Show this help\n --version, -v Show version\n```\n\n**Error Handling:**\n- Unknown command → suggest similar, show help\n- Missing required args → show specific error + help\n\n**Tests Required:** test/cli.test.ts","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-ocy","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement CLI entry point with command routing","updated_at":"2026-02-03T03:47:20Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:04:56Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"99042d85d841efa02b8dee21fc16ffe62d2a0f36e9f67c0c0f95ec172b8c5a96","created_at":"2026-02-03T02:52:11Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Create src/lib/coverage.ts to parse Vitest/Istanbul coverage output.\n\n**Input Format:** coverage/coverage-summary.json (Istanbul standard)\n```json\n{\n \"total\": { \"lines\": { \"total\": 1000, \"covered\": 500, \"pct\": 50 }, ... },\n \"src/file.ts\": { \"lines\": { \"total\": 100, \"covered\": 10, \"pct\": 10 }, ... }\n}\n```\n\n**Functions to Implement:**\n- `parseCoverageSummary(path: string): CoverageData` - Read and parse JSON\n- `filterBelowThreshold(data: CoverageData, threshold: number): FileEntry[]` - Filter files at or below threshold\n- `sortByPercentage(files: FileEntry[]): FileEntry[]` - Sort ascending by coverage %\n\n**Types to Define:**\n- `CoverageData` - Parsed coverage structure\n- `FileEntry` - Single file with path, lines hit/found, percentage\n\n**Error Handling:**\n- File not found → throw descriptive error\n- Invalid JSON → throw descriptive error\n- Missing required fields → throw descriptive error\n\n**Tests Required:** test/lib/coverage.test.ts with fixture files","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-p0r","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement coverage.ts: parse Istanbul coverage-summary.json","updated_at":"2026-02-03T13:04:56Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:43:02Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"36af82fb5679a99ba2892c474a8dc44e6d36fb10441af00741ccb9dc9606bb64","created_at":"2026-02-03T02:55:29Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Create README.md with full documentation.\n\n**Sections:**\n\n**1. Header**\n- Project name and tagline\n- Badges (CI status, version, license)\n\n**2. Features**\n- Zero dependencies\n- Single binary\n- Cross-platform\n- No config required\n\n**3. Installation**\n- curl install script\n- Homebrew (when available)\n- Download from releases\n- Build from source\n\n**4. Quick Start**\n```bash\n# Generate coverage with vitest\npnpm test:coverage\n\n# Report low coverage files\nuncov\n\n# Files below 50% coverage\nuncov --threshold 50\n\n# Fail CI if low coverage\nuncov --fail\n```\n\n**5. Commands**\n- uncov (default) - detailed usage\n- uncov init - detailed usage\n- uncov check - detailed usage\n\n**6. Configuration**\n- uncov.config.json format\n- package.json format\n- CLI flags reference\n\n**7. Exit Codes**\n- Table of codes and meanings\n\n**8. Development**\n- Prerequisites (Bun)\n- Setup instructions\n- Running tests\n- Building locally\n\n**9. License**\n- MIT\n\n**Keep concise** - link to docs/spec.md for full details","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-p2k","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Write comprehensive README.md documentation","updated_at":"2026-02-03T13:43:02Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T03:47:20Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"949bdb60533301b53c3085cddf47e97b06a40dc2351daf735c7eb13bef9d904a","created_at":"2026-02-03T02:52:11Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Create src/utils/format.ts for consistent output formatting.\n\n**Functions to Implement:**\n\n`formatCoverageTable(files: FileEntry[]): string`\n- Format output like:\n ```\n Files at or below 10% line coverage: 3\n\n 0.00% LH 0/LF 120 src/renderer.ts\n 5.26% LH 2/LF 38 src/bootstrap.ts\n 10.00% LH 10/LF 100 src/engine.ts\n ```\n- Right-align percentage column\n- LH = lines hit, LF = lines found\n\n`formatJson(files: FileEntry[]): string`\n- JSON array output for --json flag\n- Include: path, percentage, linesHit, linesFound\n\n`formatSummary(count: number, threshold: number): string`\n- Header line: 'Files at or below X% line coverage: N'\n\n**Tests Required:** test/utils/format.test.ts","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-q77","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement format.ts: output formatting utilities","updated_at":"2026-02-03T03:47:20Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T03:47:20Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"ad229066e98b75852ed87028e7df208e658c71ec37783658eeee882e276d4201","created_at":"2026-02-03T02:55:28Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Create test/fixtures/ with sample Istanbul coverage data for testing.\n\n**Fixtures to Create:**\n\n**test/fixtures/coverage-summary-valid.json**\n- Standard valid coverage output\n- Multiple files with varying coverage (0%, 10%, 50%, 100%)\n- Include 'total' summary\n\n**test/fixtures/coverage-summary-empty.json**\n- Valid JSON but only 'total' with no individual files\n\n**test/fixtures/coverage-summary-all-covered.json**\n- All files at 100% coverage\n\n**test/fixtures/coverage-summary-all-zero.json**\n- All files at 0% coverage\n\n**test/fixtures/coverage-summary-invalid.json**\n- Malformed JSON for error testing\n\n**test/fixtures/coverage-summary-missing-fields.json**\n- Valid JSON but missing required fields\n\n**Sample Valid Structure:**\n```json\n{\n \"total\": {\n \"lines\": { \"total\": 1000, \"covered\": 450, \"skipped\": 0, \"pct\": 45 },\n \"statements\": { \"total\": 1000, \"covered\": 450, \"skipped\": 0, \"pct\": 45 },\n \"functions\": { \"total\": 100, \"covered\": 50, \"skipped\": 0, \"pct\": 50 },\n \"branches\": { \"total\": 200, \"covered\": 80, \"skipped\": 0, \"pct\": 40 }\n },\n \"src/renderer.ts\": {\n \"lines\": { \"total\": 120, \"covered\": 0, \"skipped\": 0, \"pct\": 0 },\n ...\n },\n \"src/engine.ts\": {\n \"lines\": { \"total\": 100, \"covered\": 10, \"skipped\": 0, \"pct\": 10 },\n ...\n }\n}\n```","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-qu3","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Create test fixtures: sample coverage-summary.json files","updated_at":"2026-02-03T03:47:20Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:56:51Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"9cc9a3087476acc2781fcc09ea89d6655f40c4519ba255713e7b99b125fe2b34","created_at":"2026-02-03T13:53:31Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"**Severity:** Medium (Reproducibility)\n\n1. Pin Bun version instead of using 'latest':\n```yaml\n- uses: oven-sh/setup-bun@v1\n with:\n bun-version: '1.1.42'\n```\n\n2. Commit bun.lockb lockfile\n\n3. Use --frozen-lockfile in CI:\n```yaml\n- name: Install dependencies\n run: bun install --frozen-lockfile\n```","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-r6p","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":0,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix: Pin Bun version and add lockfile","updated_at":"2026-02-03T13:56:51Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T13:04:56Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"87d847e7171dd1c8b773e8750adf22bf3cd9cf169cacdfc52fb2b676f85cd25a","created_at":"2026-02-03T02:52:50Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"Create src/lib/vitest-config.ts for vitest config management.\n\n**Functions to Implement:**\n\n`hasVitestConfig(): boolean`\n- Check for vitest.config.* or vite.config.* with test section\n\n`hasCoverageConfig(): boolean`\n- Check if coverage is already configured in vitest config\n\n`createVitestConfig(): string`\n- Generate new vitest.config.ts content:\n```typescript\nimport { defineConfig } from 'vitest/config';\n\nexport default defineConfig({\n test: {\n coverage: {\n provider: 'v8',\n reporter: ['text', 'json-summary'],\n reportsDirectory: './coverage',\n },\n },\n});\n```\n\n`patchVitestConfig(existingContent: string): string`\n- Add coverage config to existing vitest.config.ts\n- Use AST manipulation or careful string manipulation\n- Preserve existing config, only add coverage section\n\n**Edge Cases:**\n- vite.config.ts with test section (common pattern)\n- vitest.workspace.ts (workspace setups)\n- Already has partial coverage config\n\n**Tests Required:** test/lib/vitest-config.test.ts","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-s2m","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement vitest-config.ts: detect and modify vitest configuration","updated_at":"2026-02-03T13:04:56Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T03:47:20Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"69060be03596a0b90019519b7545d12b16f882ecc832b91e918e385865142ee4","created_at":"2026-02-03T03:43:40Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"**Severity:** Medium\n**Location:** src/utils/fs.ts lines 127-145\n\n**Issue:** Deprecated async wrappers (readJsonFile, writeJsonFile) are misleading:\n- Not truly async (no await, just wrapped in Promise)\n- Silently swallow errors by returning null\n- Have no tests\n\n**The Fix:**\nRemove the deprecated functions entirely (lines 126-145):\n```typescript\n// Delete these deprecated functions:\n// - readJsonFile\n// - writeJsonFile\n```\n\nAlso remove any exports of these functions from index.ts.\n\n**Acceptance Criteria:**\n- Deprecated async wrappers are removed\n- No references to removed functions\n- Lint passes","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-tr8","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix: Remove deprecated async wrappers from fs.ts","updated_at":"2026-02-03T03:47:20Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T14:19:21Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"d50fc246416ac7835f203a4c1320af26dd74b0607a5b7462b267a340d72f400e","created_at":"2026-02-03T14:19:05Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"In get_latest_version function, validate VERSION format after extraction. Add case statement to check for v[0-9]* or [0-9]* pattern, error on invalid format.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-uar","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Add version format validation in install.sh","updated_at":"2026-02-03T14:19:21Z","waiters":"","wisp_type":"","work_type":""} +{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-02-03T03:21:13Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"fcc1cd7140b59d0b57d2060b2e72d77ea5ba91f499662397a6722953b6794544","created_at":"2026-02-03T03:16:14Z","created_by":"loganlindquist","crystallizes":0,"defer_until":null,"description":"**Issue:** Running `uncov foobar` silently defaults to the report command. This confuses users who misspell commands.\n\n**Location:** src/cli.ts lines 71-78\n\n**The Fix:**\n```typescript\nconst command = positionals[0];\nlet parsedCommand: 'report' | 'init' | 'check' = 'report';\n\nif (command === 'init') {\n parsedCommand = 'init';\n} else if (command === 'check') {\n parsedCommand = 'check';\n} else if (command \u0026\u0026 command \\!== 'report') {\n console.error(`Unknown command: ${command}`);\n console.error(`Run 'uncov --help' for usage information.`);\n process.exit(2);\n}\n```\n\n**Acceptance Criteria:**\n- `uncov foobar` shows 'Unknown command: foobar' and exits 2\n- `uncov report` works normally\n- `uncov` (no command) defaults to report","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"uncov-xg6","is_template":0,"issue_type":"bug","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Fix: Add unrecognized command handling","updated_at":"2026-02-03T03:21:13Z","waiters":"","wisp_type":"","work_type":""} diff --git a/.beads/backup/labels.jsonl b/.beads/backup/labels.jsonl new file mode 100644 index 0000000..e69de29 diff --git a/.beads/hooks/post-checkout b/.beads/hooks/post-checkout new file mode 100755 index 0000000..3640ea6 --- /dev/null +++ b/.beads/hooks/post-checkout @@ -0,0 +1,9 @@ +#!/usr/bin/env sh +# --- BEGIN BEADS INTEGRATION v0.58.0 --- +# This section is managed by beads. Do not remove these markers. +if command -v bd >/dev/null 2>&1; then + export BD_GIT_HOOK=1 + bd hooks run post-checkout "$@" + _bd_exit=$?; if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi +fi +# --- END BEADS INTEGRATION --- diff --git a/.beads/hooks/post-merge b/.beads/hooks/post-merge new file mode 100755 index 0000000..b4f4998 --- /dev/null +++ b/.beads/hooks/post-merge @@ -0,0 +1,9 @@ +#!/usr/bin/env sh +# --- BEGIN BEADS INTEGRATION v0.58.0 --- +# This section is managed by beads. Do not remove these markers. +if command -v bd >/dev/null 2>&1; then + export BD_GIT_HOOK=1 + bd hooks run post-merge "$@" + _bd_exit=$?; if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi +fi +# --- END BEADS INTEGRATION --- diff --git a/.beads/hooks/pre-commit b/.beads/hooks/pre-commit new file mode 100755 index 0000000..5410562 --- /dev/null +++ b/.beads/hooks/pre-commit @@ -0,0 +1,9 @@ +#!/usr/bin/env sh +# --- BEGIN BEADS INTEGRATION v0.58.0 --- +# This section is managed by beads. Do not remove these markers. +if command -v bd >/dev/null 2>&1; then + export BD_GIT_HOOK=1 + bd hooks run pre-commit "$@" + _bd_exit=$?; if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi +fi +# --- END BEADS INTEGRATION --- diff --git a/.beads/hooks/pre-push b/.beads/hooks/pre-push new file mode 100755 index 0000000..1a3292d --- /dev/null +++ b/.beads/hooks/pre-push @@ -0,0 +1,9 @@ +#!/usr/bin/env sh +# --- BEGIN BEADS INTEGRATION v0.58.0 --- +# This section is managed by beads. Do not remove these markers. +if command -v bd >/dev/null 2>&1; then + export BD_GIT_HOOK=1 + bd hooks run pre-push "$@" + _bd_exit=$?; if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi +fi +# --- END BEADS INTEGRATION --- diff --git a/.beads/hooks/prepare-commit-msg b/.beads/hooks/prepare-commit-msg new file mode 100755 index 0000000..afd628c --- /dev/null +++ b/.beads/hooks/prepare-commit-msg @@ -0,0 +1,9 @@ +#!/usr/bin/env sh +# --- BEGIN BEADS INTEGRATION v0.58.0 --- +# This section is managed by beads. Do not remove these markers. +if command -v bd >/dev/null 2>&1; then + export BD_GIT_HOOK=1 + bd hooks run prepare-commit-msg "$@" + _bd_exit=$?; if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi +fi +# --- END BEADS INTEGRATION --- diff --git a/.beads/metadata.json b/.beads/metadata.json index 01c4bb3..31f5ec3 100644 --- a/.beads/metadata.json +++ b/.beads/metadata.json @@ -1,4 +1,6 @@ { - "database": "beads.db", - "jsonl_export": "issues.jsonl" -} + "database": "dolt", + "backend": "dolt", + "dolt_mode": "server", + "dolt_database": "uncov" +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8e971fd..a237e42 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,7 @@ coverage/ # Environment .env .env.local + +# Dolt database files (added by bd init) +.dolt/ +*.db diff --git a/biome.json b/biome.json index 8b12043..7fc5cfc 100644 --- a/biome.json +++ b/biome.json @@ -1,13 +1,11 @@ { - "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "$schema": "https://biomejs.dev/schemas/2.4.6/schema.json", "vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true }, - "organizeImports": { - "enabled": true - }, + "assist": { "actions": { "source": { "organizeImports": "on" } } }, "linter": { "enabled": true, "rules": { @@ -20,6 +18,13 @@ "lineWidth": 100 }, "files": { - "ignore": ["node_modules", "dist", "coverage", "test/fixtures/coverage-summary-invalid.json"] + "includes": [ + "**", + "!**/node_modules", + "!**/dist", + "!**/coverage", + "!**/test/fixtures/coverage-summary-invalid.json", + "!**/.beads" + ] } } diff --git a/bun.lock b/bun.lock index 0ac9625..e360089 100644 --- a/bun.lock +++ b/bun.lock @@ -5,35 +5,35 @@ "": { "name": "uncov", "devDependencies": { - "@biomejs/biome": "^1.9.4", - "@types/bun": "^1.2.4", + "@biomejs/biome": "^2.4.6", + "@types/bun": "^1.3.10", }, }, }, "packages": { - "@biomejs/biome": ["@biomejs/biome@1.9.4", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "1.9.4", "@biomejs/cli-darwin-x64": "1.9.4", "@biomejs/cli-linux-arm64": "1.9.4", "@biomejs/cli-linux-arm64-musl": "1.9.4", "@biomejs/cli-linux-x64": "1.9.4", "@biomejs/cli-linux-x64-musl": "1.9.4", "@biomejs/cli-win32-arm64": "1.9.4", "@biomejs/cli-win32-x64": "1.9.4" }, "bin": { "biome": "bin/biome" } }, "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog=="], + "@biomejs/biome": ["@biomejs/biome@2.4.6", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.6", "@biomejs/cli-darwin-x64": "2.4.6", "@biomejs/cli-linux-arm64": "2.4.6", "@biomejs/cli-linux-arm64-musl": "2.4.6", "@biomejs/cli-linux-x64": "2.4.6", "@biomejs/cli-linux-x64-musl": "2.4.6", "@biomejs/cli-win32-arm64": "2.4.6", "@biomejs/cli-win32-x64": "2.4.6" }, "bin": { "biome": "bin/biome" } }, "sha512-QnHe81PMslpy3mnpL8DnO2M4S4ZnYPkjlGCLWBZT/3R9M6b5daArWMMtEfP52/n174RKnwRIf3oT8+wc9ihSfQ=="], - "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@1.9.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw=="], + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-NW18GSyxr+8sJIqgoGwVp5Zqm4SALH4b4gftIA0n62PTuBs6G2tHlwNAOj0Vq0KKSs7Sf88VjjmHh0O36EnzrQ=="], - "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@1.9.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg=="], + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-4uiE/9tuI7cnjtY9b07RgS7gGyYOAfIAGeVJWEfeCnAarOAS7qVmuRyX6d7JTKw28/mt+rUzMasYeZ+0R/U1Mw=="], - "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g=="], + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-kMLaI7OF5GN1Q8Doymjro1P8rVEoy7BKQALNz6fiR8IC1WKduoNyteBtJlHT7ASIL0Cx2jR6VUOBIbcB1B8pew=="], - "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA=="], + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-F/JdB7eN22txiTqHM5KhIVt0jVkzZwVYrdTR1O3Y4auBOQcXxHK4dxULf4z43QyZI5tsnQJrRBHZy7wwtL+B3A=="], - "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg=="], + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.6", "", { "os": "linux", "cpu": "x64" }, "sha512-oHXmUFEoH8Lql1xfc3QkFLiC1hGR7qedv5eKNlC185or+o4/4HiaU7vYODAH3peRCfsuLr1g6v2fK9dFFOYdyw=="], - "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg=="], + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.6", "", { "os": "linux", "cpu": "x64" }, "sha512-C9s98IPDu7DYarjlZNuzJKTjVHN03RUnmHV5htvqsx6vEUXCDSJ59DNwjKVD5XYoSS4N+BYhq3RTBAL8X6svEg=="], - "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@1.9.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg=="], + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-xzThn87Pf3YrOGTEODFGONmqXpTwUNxovQb72iaUOdcw8sBSY3+3WD8Hm9IhMYLnPi0n32s3L3NWU6+eSjfqFg=="], - "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@1.9.4", "", { "os": "win32", "cpu": "x64" }, "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA=="], + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.6", "", { "os": "win32", "cpu": "x64" }, "sha512-7++XhnsPlr1HDbor5amovPjOH6vsrFOCdp93iKXhFn6bcMUI6soodj3WWKfgEO6JosKU1W5n3uky3WW9RlRjTg=="], - "@types/bun": ["@types/bun@1.3.8", "", { "dependencies": { "bun-types": "1.3.8" } }, "sha512-3LvWJ2q5GerAXYxO2mffLTqOzEu5qnhEAlh48Vnu8WQfnmSwbgagjGZV6BoHKJztENYEDn6QmVd949W4uESRJA=="], + "@types/bun": ["@types/bun@1.3.10", "", { "dependencies": { "bun-types": "1.3.10" } }, "sha512-0+rlrUrOrTSskibryHbvQkDOWRJwJZqZlxrUs1u4oOoTln8+WIXBPmAuCF35SWB2z4Zl3E84Nl/D0P7803nigQ=="], "@types/node": ["@types/node@25.2.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w=="], - "bun-types": ["bun-types@1.3.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-fL99nxdOWvV4LqjmC+8Q9kW3M4QTtTR1eePs94v5ctGqU8OeceWrSUaRw3JYb7tU3FkMIAjkueehrHPPPGKi5Q=="], + "bun-types": ["bun-types@1.3.10", "", { "dependencies": { "@types/node": "*" } }, "sha512-tcpfCCl6XWo6nCVnpcVrxQ+9AYN1iqMIzgrSKYMB/fjLtV2eyAVEg7AxQJuCq/26R6HpKWykQXuSOq/21RYcbg=="], "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], } diff --git a/package.json b/package.json index 1638c3d..ec92df1 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,9 @@ "bin": { "uncov": "./dist/cli.js" }, - "files": ["dist"], + "files": [ + "dist" + ], "scripts": { "dev": "bun run src/cli.ts", "test": "bun test", @@ -20,10 +22,15 @@ "coverage:low": "uncov" }, "devDependencies": { - "@biomejs/biome": "^1.9.4", - "@types/bun": "^1.2.4" + "@biomejs/biome": "^2.4.6", + "@types/bun": "^1.3.10" }, - "keywords": ["coverage", "vitest", "testing", "cli"], + "keywords": [ + "coverage", + "vitest", + "testing", + "cli" + ], "license": "MIT", "repository": { "type": "git", diff --git a/src/commands/index.ts b/src/commands/index.ts index 0224897..5ad413b 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -2,6 +2,6 @@ * Command exports */ -export { reportCommand, type ReportOptions } from "./report"; -export { initCommand, type InitOptions } from "./init"; export { checkCommand } from "./check"; +export { type InitOptions, initCommand } from "./init"; +export { type ReportOptions, reportCommand } from "./report"; diff --git a/src/lib/index.ts b/src/lib/index.ts index 40761c1..5e7f269 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -2,8 +2,8 @@ * Library exports */ -export * from "./coverage"; export * from "./config"; +export * from "./coverage"; +export * from "./detect"; export * from "./package-json"; export * from "./vitest-config"; -export * from "./detect"; diff --git a/src/utils/format.ts b/src/utils/format.ts index f934d6b..759c963 100644 --- a/src/utils/format.ts +++ b/src/utils/format.ts @@ -3,7 +3,7 @@ */ import type { ParsedFileCoverage } from "../lib/coverage"; -import { type Colors, createColors } from "./colors"; +import type { Colors } from "./colors"; /** * Format coverage percentage for display diff --git a/test/utils/colors.test.ts b/test/utils/colors.test.ts index 42f8377..69442b4 100644 --- a/test/utils/colors.test.ts +++ b/test/utils/colors.test.ts @@ -7,12 +7,12 @@ import { createColors, isColorSupported } from "../../src/utils/colors"; describe("colors", () => { let originalNoColor: string | undefined; - let originalIsTTY: boolean | undefined; + let _originalIsTTY: boolean | undefined; beforeEach(() => { // Save original values originalNoColor = process.env.NO_COLOR; - originalIsTTY = process.stdout.isTTY; + _originalIsTTY = process.stdout.isTTY; }); afterEach(() => {