chore: initialize beadboard baseline
This commit is contained in:
commit
292a72f861
30 changed files with 2983 additions and 0 deletions
44
.beads/.gitignore
vendored
Normal file
44
.beads/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
# SQLite databases
|
||||
*.db
|
||||
*.db?*
|
||||
*.db-journal
|
||||
*.db-wal
|
||||
*.db-shm
|
||||
|
||||
# Daemon runtime files
|
||||
daemon.lock
|
||||
daemon.log
|
||||
daemon.pid
|
||||
bd.sock
|
||||
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
|
||||
sync_base.jsonl
|
||||
|
||||
# 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.
|
||||
81
.beads/README.md
Normal file
81
.beads/README.md
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
# Beads - AI-Native Issue Tracking
|
||||
|
||||
Welcome to Beads! This repository uses **Beads** for issue tracking - a modern, AI-native tool designed to live directly in your codebase alongside your code.
|
||||
|
||||
## What is Beads?
|
||||
|
||||
Beads is issue tracking that lives in your repo, making it perfect for AI coding agents and developers who want their issues close to their code. No web UI required - everything works through the CLI and integrates seamlessly with git.
|
||||
|
||||
**Learn more:** [github.com/steveyegge/beads](https://github.com/steveyegge/beads)
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Essential Commands
|
||||
|
||||
```bash
|
||||
# Create new issues
|
||||
bd create "Add user authentication"
|
||||
|
||||
# View all issues
|
||||
bd list
|
||||
|
||||
# View issue details
|
||||
bd show <issue-id>
|
||||
|
||||
# Update issue status
|
||||
bd update <issue-id> --status in_progress
|
||||
bd update <issue-id> --status done
|
||||
|
||||
# Sync with git remote
|
||||
bd sync
|
||||
```
|
||||
|
||||
### Working with Issues
|
||||
|
||||
Issues in Beads are:
|
||||
- **Git-native**: Stored in `.beads/issues.jsonl` and synced like code
|
||||
- **AI-friendly**: CLI-first design works perfectly with AI coding agents
|
||||
- **Branch-aware**: Issues can follow your branch workflow
|
||||
- **Always in sync**: Auto-syncs with your commits
|
||||
|
||||
## Why Beads?
|
||||
|
||||
✨ **AI-Native Design**
|
||||
- Built specifically for AI-assisted development workflows
|
||||
- CLI-first interface works seamlessly with AI coding agents
|
||||
- No context switching to web UIs
|
||||
|
||||
🚀 **Developer Focused**
|
||||
- Issues live in your repo, right next to your code
|
||||
- Works offline, syncs when you push
|
||||
- Fast, lightweight, and stays out of your way
|
||||
|
||||
🔧 **Git Integration**
|
||||
- Automatic sync with git commits
|
||||
- Branch-aware issue tracking
|
||||
- Intelligent JSONL merge resolution
|
||||
|
||||
## Get Started with Beads
|
||||
|
||||
Try Beads in your own projects:
|
||||
|
||||
```bash
|
||||
# Install Beads
|
||||
curl -sSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash
|
||||
|
||||
# Initialize in your repo
|
||||
bd init
|
||||
|
||||
# Create your first issue
|
||||
bd create "Try out Beads"
|
||||
```
|
||||
|
||||
## Learn More
|
||||
|
||||
- **Documentation**: [github.com/steveyegge/beads/docs](https://github.com/steveyegge/beads/tree/main/docs)
|
||||
- **Quick Start Guide**: Run `bd quickstart`
|
||||
- **Examples**: [github.com/steveyegge/beads/examples](https://github.com/steveyegge/beads/tree/main/examples)
|
||||
|
||||
---
|
||||
|
||||
*Beads: Issue tracking that moves at the speed of thought* ⚡
|
||||
62
.beads/config.yaml
Normal file
62
.beads/config.yaml
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# Beads Configuration File
|
||||
# This file configures default behavior for all bd commands in this repository
|
||||
# All settings can also be set via environment variables (BD_* prefix)
|
||||
# or overridden with command-line flags
|
||||
|
||||
# Issue prefix for this repository (used by bd init)
|
||||
# If not set, bd init will auto-detect from directory name
|
||||
# Example: issue-prefix: "myproject" creates issues like "myproject-1", "myproject-2", etc.
|
||||
# issue-prefix: ""
|
||||
|
||||
# Use no-db mode: load from JSONL, no SQLite, write back after each command
|
||||
# When true, bd will use .beads/issues.jsonl as the source of truth
|
||||
# instead of SQLite database
|
||||
# no-db: false
|
||||
|
||||
# Disable daemon for RPC communication (forces direct database access)
|
||||
# no-daemon: false
|
||||
|
||||
# Disable auto-flush of database to JSONL after mutations
|
||||
# no-auto-flush: false
|
||||
|
||||
# Disable auto-import from JSONL when it's newer than database
|
||||
# no-auto-import: false
|
||||
|
||||
# Enable JSON output by default
|
||||
# json: false
|
||||
|
||||
# Default actor for audit trails (overridden by BD_ACTOR or --actor)
|
||||
# actor: ""
|
||||
|
||||
# Path to database (overridden by BEADS_DB or --db)
|
||||
# db: ""
|
||||
|
||||
# Auto-start daemon if not running (can also use BEADS_AUTO_START_DAEMON)
|
||||
# auto-start-daemon: true
|
||||
|
||||
# Debounce interval for auto-flush (can also use BEADS_FLUSH_DEBOUNCE)
|
||||
# flush-debounce: "5s"
|
||||
|
||||
# Git branch for beads commits (bd sync will commit to this branch)
|
||||
# IMPORTANT: Set this for team projects so all clones use the same sync branch.
|
||||
# This setting persists across clones (unlike database config which is gitignored).
|
||||
# Can also use BEADS_SYNC_BRANCH env var for local override.
|
||||
# If not set, bd sync will require you to run 'bd config set sync.branch <branch>'.
|
||||
# sync-branch: "beads-sync"
|
||||
|
||||
# Multi-repo configuration (experimental - bd-307)
|
||||
# Allows hydrating from multiple repositories and routing writes to the correct JSONL
|
||||
# repos:
|
||||
# primary: "." # Primary repo (where this database lives)
|
||||
# additional: # Additional repos to hydrate from (read-only)
|
||||
# - ~/beads-planning # Personal planning repo
|
||||
# - ~/work-planning # Work planning repo
|
||||
|
||||
# Integration settings (access with 'bd config get/set')
|
||||
# These are stored in the database, not in this file:
|
||||
# - jira.url
|
||||
# - jira.project
|
||||
# - linear.url
|
||||
# - linear.api-key
|
||||
# - github.org
|
||||
# - github.repo
|
||||
0
.beads/interactions.jsonl
Normal file
0
.beads/interactions.jsonl
Normal file
48
.beads/issues.jsonl
Normal file
48
.beads/issues.jsonl
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
{"id":"bb-29x","title":"Quality Gates, Testing, and Performance Validation","description":"Establish verification confidence through unit/integration tests, boundary tests, and performance baselines for parser and realtime workflows.","acceptance_criteria":"Core functionality is covered by automated checks and target baselines are recorded.","status":"open","priority":1,"issue_type":"epic","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:15.8368971-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:15.8368971-08:00","labels":["perf","quality","testing"],"dependencies":[{"issue_id":"bb-29x","depends_on_id":"bb-ymg","type":"blocks","created_at":"2026-02-11T17:12:23.6722466-08:00","created_by":"zenchantlive"},{"issue_id":"bb-29x","depends_on_id":"bb-xhm","type":"blocks","created_at":"2026-02-11T17:12:24.1823625-08:00","created_by":"zenchantlive"},{"issue_id":"bb-29x","depends_on_id":"bb-bvn","type":"blocks","created_at":"2026-02-11T17:12:24.6873031-08:00","created_by":"zenchantlive"},{"issue_id":"bb-29x","depends_on_id":"bb-u6f","type":"blocks","created_at":"2026-02-11T17:12:25.193566-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-29x.1","title":"Implement unit tests for parser, pathing, scanner, and bd bridge","description":"Add focused fast tests for foundational modules and error handling paths.","acceptance_criteria":"Unit tests cover nominal and edge-case logic for each foundational module.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:16.6578316-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:16.6578316-08:00","labels":["tests","unit"],"dependencies":[{"issue_id":"bb-29x.1","depends_on_id":"bb-29x","type":"parent-child","created_at":"2026-02-11T17:12:16.6594181-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-29x.2","title":"Implement API integration tests for read, mutate, and SSE routes","description":"Validate route contracts and interaction boundaries across read/write/realtime layers.","acceptance_criteria":"Integration suite verifies route behavior and error semantics.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:17.4912736-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:17.4912736-08:00","labels":["integration","tests"],"dependencies":[{"issue_id":"bb-29x.2","depends_on_id":"bb-29x","type":"parent-child","created_at":"2026-02-11T17:12:17.4923012-08:00","created_by":"zenchantlive"},{"issue_id":"bb-29x.2","depends_on_id":"bb-29x.1","type":"blocks","created_at":"2026-02-11T17:12:38.9423299-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-29x.3","title":"Record parser and realtime performance baseline against PRD targets","description":"Measure parse latency and update propagation using realistic sample sizes and document outcomes.","acceptance_criteria":"Performance report exists with methodology and observed timings.","status":"open","priority":2,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:18.3210495-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:18.3210495-08:00","labels":["benchmark","perf"],"dependencies":[{"issue_id":"bb-29x.3","depends_on_id":"bb-29x","type":"parent-child","created_at":"2026-02-11T17:12:18.3220949-08:00","created_by":"zenchantlive"},{"issue_id":"bb-29x.3","depends_on_id":"bb-29x.2","type":"blocks","created_at":"2026-02-11T17:12:39.4534943-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-29x.4","title":"Document operational runbook and boundary rationale","description":"Write architecture docs covering scanner policy, bd bridge behavior, and consistency guardrails for future maintainers.","acceptance_criteria":"Runbook documents startup, troubleshooting, and boundary rules.","status":"open","priority":2,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:19.1385778-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:19.1385778-08:00","labels":["docs","runbook"],"dependencies":[{"issue_id":"bb-29x.4","depends_on_id":"bb-29x","type":"parent-child","created_at":"2026-02-11T17:12:19.1402086-08:00","created_by":"zenchantlive"},{"issue_id":"bb-29x.4","depends_on_id":"bb-29x.2","type":"blocks","created_at":"2026-02-11T17:12:39.9591458-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-6aj","title":"Project Registry and Multi-Project Scanner","description":"Support multiple Windows project roots using profile-scoped registry storage and safe discovery scanning tuned for developer machines.","acceptance_criteria":"Projects can be added/removed/listed and discovered via scanner with deterministic normalization.","status":"open","priority":0,"issue_type":"epic","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:47.7205517-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:11:47.7205517-08:00","labels":["multi-project","scanner"],"dependencies":[{"issue_id":"bb-6aj","depends_on_id":"bb-92d","type":"blocks","created_at":"2026-02-11T17:12:19.6374139-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-6aj.1","title":"Persist project registry in %USERPROFILE%\\\\.beadboard\\\\projects.json","description":"Implement read/write management for registry file in user profile path, isolated from repository files and safe for local machine usage.","acceptance_criteria":"Registry file is created lazily and survives app restarts.","status":"open","priority":0,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:48.5403111-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:11:48.5403111-08:00","labels":["config","registry"],"dependencies":[{"issue_id":"bb-6aj.1","depends_on_id":"bb-6aj","type":"parent-child","created_at":"2026-02-11T17:11:48.5419102-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-6aj.2","title":"Implement registry API for add/remove/list operations","description":"Expose robust API endpoints with path validation and normalized identity checks to prevent duplicates.","acceptance_criteria":"API supports add, remove, list and returns clear validation errors.","status":"open","priority":0,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:49.3542564-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:11:49.3542564-08:00","labels":["api","registry"],"dependencies":[{"issue_id":"bb-6aj.2","depends_on_id":"bb-6aj","type":"parent-child","created_at":"2026-02-11T17:11:49.3558158-08:00","created_by":"zenchantlive"},{"issue_id":"bb-6aj.2","depends_on_id":"bb-6aj.1","type":"blocks","created_at":"2026-02-11T17:12:26.7117348-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-6aj.3","title":"Build scanner with profile-root default and depth/ignore controls","description":"Scan %USERPROFILE% and user-defined roots for .beads directories with bounded recursion and ignore patterns to protect performance.","acceptance_criteria":"Scanner discovers projects without traversing entire drives by default.","status":"open","priority":0,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:50.1925005-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:11:50.1925005-08:00","labels":["performance","scanner"],"dependencies":[{"issue_id":"bb-6aj.3","depends_on_id":"bb-6aj","type":"parent-child","created_at":"2026-02-11T17:11:50.1940841-08:00","created_by":"zenchantlive"},{"issue_id":"bb-6aj.3","depends_on_id":"bb-6aj.1","type":"blocks","created_at":"2026-02-11T17:12:27.2225981-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-6aj.3.1","title":"Add explicit full-drive scan mode for C:/D: by user action","description":"Provide an opt-in scan mode for full drive enumeration while retaining safe defaults and progress reporting expectations.","acceptance_criteria":"Full-drive scan is only activated explicitly, never by default startup logic.","status":"open","priority":2,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:51.0244174-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:11:51.0244174-08:00","labels":["optional","scanner"],"dependencies":[{"issue_id":"bb-6aj.3.1","depends_on_id":"bb-6aj.3","type":"parent-child","created_at":"2026-02-11T17:11:51.0259617-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-6aj.4","title":"Implement aggregate project issue context model","description":"Define normalized project identity payload attached to every issue for cross-project Kanban, timeline, and session views.","acceptance_criteria":"Aggregated read output always includes stable project metadata.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:51.8518922-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:11:51.8518922-08:00","labels":["aggregation","data-model"],"dependencies":[{"issue_id":"bb-6aj.4","depends_on_id":"bb-6aj","type":"parent-child","created_at":"2026-02-11T17:11:51.8534893-08:00","created_by":"zenchantlive"},{"issue_id":"bb-6aj.4","depends_on_id":"bb-6aj.2","type":"blocks","created_at":"2026-02-11T17:12:27.7270195-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-92d","title":"Foundation and Read/Write Boundary","description":"Establish the Windows-native Next.js foundation, canonical Beads schema handling, and strict data boundaries: read from JSONL, write only via bd.exe. This epic defines the non-negotiable invariants that all later work must preserve.","acceptance_criteria":"App boots on Windows, schema/parser contracts exist, and no direct issues.jsonl write path exists in code.","status":"closed","priority":0,"issue_type":"epic","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:41.0756295-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:28:27.8108066-08:00","closed_at":"2026-02-11T17:28:27.8108066-08:00","close_reason":"Completed foundation milestone: bootstrap, licensing/docs, schema contracts, parser, windows path normalization, and write-boundary guardrails.","labels":["beadboard","foundation","windows"]}
|
||||
{"id":"bb-92d.1","title":"Bootstrap Next.js 15 + React 19 + TypeScript strict","description":"Initialize project scaffold with strict TypeScript, App Router baseline, and repeatable scripts for lint/typecheck/test in PowerShell.","acceptance_criteria":"npm install and dev startup work on Windows; strict type checking enabled.","status":"closed","priority":0,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:41.9363647-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:23:14.0089901-08:00","closed_at":"2026-02-11T17:23:14.0089901-08:00","close_reason":"Bootstrapped Next.js 15 + React 19 + strict TypeScript; install/typecheck/dev startup verified on Windows.","labels":["foundation","nextjs"],"dependencies":[{"issue_id":"bb-92d.1","depends_on_id":"bb-92d","type":"parent-child","created_at":"2026-02-11T17:11:41.9379355-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-92d.2","title":"Add MIT license and baseline repository docs","description":"Add LICENSE and baseline docs that state Windows-native support, read/write boundaries, and required runtime dependencies.","acceptance_criteria":"MIT license present and docs describe core architecture constraints.","status":"closed","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:42.7699961-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:23:50.7519159-08:00","closed_at":"2026-02-11T17:23:50.7519159-08:00","close_reason":"Added MIT license and baseline repository documentation with architecture boundary rules.","labels":["docs","license"],"dependencies":[{"issue_id":"bb-92d.2","depends_on_id":"bb-92d","type":"parent-child","created_at":"2026-02-11T17:11:42.7715653-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-92d.3","title":"Define canonical Beads TypeScript schema types","description":"Implement comprehensive issue types covering ids, status, priority, dependencies, timestamps, metadata, and session fields used by dashboard views.","acceptance_criteria":"All required PRD fields are represented and reused across parser/API/UI layers.","status":"closed","priority":0,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:43.6016519-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:24:57.9851942-08:00","closed_at":"2026-02-11T17:24:57.9851942-08:00","close_reason":"Added canonical Beads TypeScript schema contracts and validated via typecheck contract test.","labels":["schema","types"],"dependencies":[{"issue_id":"bb-92d.3","depends_on_id":"bb-92d","type":"parent-child","created_at":"2026-02-11T17:11:43.6032338-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-92d.4","title":"Implement JSONL parser with defaults and malformed-line tolerance","description":"Parse one JSON object per line, skip blank/malformed lines, apply default status/type/priority, preserve priority=0, and filter tombstones by default.","acceptance_criteria":"Parser tests cover malformed lines, defaults, and tombstone behavior.","status":"closed","priority":0,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:44.4153013-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:26:37.2602624-08:00","closed_at":"2026-02-11T17:26:37.2602624-08:00","close_reason":"Implemented JSONL parser with schema defaults, malformed-line tolerance, and tombstone filtering options.","labels":["jsonl","parser"],"dependencies":[{"issue_id":"bb-92d.4","depends_on_id":"bb-92d","type":"parent-child","created_at":"2026-02-11T17:11:44.4168806-08:00","created_by":"zenchantlive"},{"issue_id":"bb-92d.4","depends_on_id":"bb-92d.3","type":"blocks","created_at":"2026-02-11T17:12:25.6958301-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-92d.4.1","title":"Add parser tests for priority=0, tombstone filtering, and dependency parsing","description":"Create focused tests that protect parser behavior for critical edge cases and dependency structures used by graph/timeline views.","acceptance_criteria":"Tests fail before implementation and pass after parser is complete.","status":"closed","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:45.2638563-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:26:36.8997779-08:00","closed_at":"2026-02-11T17:26:36.8997779-08:00","close_reason":"Added parser behavior tests for defaults, malformed lines, tombstones, and priority=0.","labels":["parser","tests"],"dependencies":[{"issue_id":"bb-92d.4.1","depends_on_id":"bb-92d.4","type":"parent-child","created_at":"2026-02-11T17:11:45.2654252-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-92d.5","title":"Implement Windows path normalization utilities","description":"Create centralized helpers for canonical path keys, display formatting, and cross-drive normalization to avoid duplicate project identities.","acceptance_criteria":"Canonicalization is consistent for C:\\ and D:\\ style paths.","status":"closed","priority":0,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:46.0751161-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:27:27.7164974-08:00","closed_at":"2026-02-11T17:27:27.7164974-08:00","close_reason":"Implemented Windows path normalization utilities with canonicalization, keying, and display transformations.","labels":["paths","windows"],"dependencies":[{"issue_id":"bb-92d.5","depends_on_id":"bb-92d","type":"parent-child","created_at":"2026-02-11T17:11:46.0767429-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-92d.6","title":"Add guardrail test preventing direct writes to .beads/issues.jsonl","description":"Enforce read/write boundary by scanning source for forbidden direct file write patterns targeting Beads issue files.","acceptance_criteria":"Guardrail test fails on boundary violations and passes when write path uses bd bridge only.","status":"closed","priority":0,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:46.9013352-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:28:27.4699395-08:00","closed_at":"2026-02-11T17:28:27.4699395-08:00","close_reason":"Added guardrail scanner and automated test to block direct writes to .beads/issues.jsonl.","labels":["guardrail","safety"],"dependencies":[{"issue_id":"bb-92d.6","depends_on_id":"bb-92d","type":"parent-child","created_at":"2026-02-11T17:11:46.9029535-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-ag8","title":"TEMP_DELETE_ME","status":"closed","priority":4,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:10:04.5765506-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:10:10.3812634-08:00","closed_at":"2026-02-11T17:10:10.3812634-08:00","close_reason":"cleanup temp test issue"}
|
||||
{"id":"bb-bvn","title":"Dependency Graph (React Flow)","description":"Visualize issue relationships and blocked chains through an interactive graph backed by parsed dependency edges.","acceptance_criteria":"Graph renders dependencies correctly and supports navigation to issue details.","status":"open","priority":2,"issue_type":"epic","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:09.2057278-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:09.2057278-08:00","labels":["graph","react-flow"],"dependencies":[{"issue_id":"bb-bvn","depends_on_id":"bb-trz","type":"blocks","created_at":"2026-02-11T17:12:22.6642419-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-bvn.1","title":"Parse dependency edges and build adjacency structures","description":"Extract edges for blocks, parent, relates_to, duplicates, and supersedes to support graph rendering and analysis.","acceptance_criteria":"Adjacency output is complete and consistent for all supported edge types.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:10.0434044-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:10.0434044-08:00","labels":["graph","parser"],"dependencies":[{"issue_id":"bb-bvn.1","depends_on_id":"bb-bvn","type":"parent-child","created_at":"2026-02-11T17:12:10.0449367-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-bvn.2","title":"Implement React Flow graph view with pan/zoom/select interactions","description":"Render nodes and edges with interactive navigation and issue selection integration.","acceptance_criteria":"Users can pan, zoom, and select nodes to inspect linked issue context.","status":"open","priority":2,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:10.8683725-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:10.8683725-08:00","labels":["graph","ui"],"dependencies":[{"issue_id":"bb-bvn.2","depends_on_id":"bb-bvn","type":"parent-child","created_at":"2026-02-11T17:12:10.8694189-08:00","created_by":"zenchantlive"},{"issue_id":"bb-bvn.2","depends_on_id":"bb-bvn.1","type":"blocks","created_at":"2026-02-11T17:12:36.8736785-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-bvn.3","title":"Add blocked-chain highlighting and cycle anomaly signaling","description":"Improve graph decision support by emphasizing blocked paths and flagging unexpected cycle conditions.","acceptance_criteria":"Blocked paths and cycle warnings are visible and actionable.","status":"open","priority":2,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:11.687878-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:11.687878-08:00","labels":["analysis","graph"],"dependencies":[{"issue_id":"bb-bvn.3","depends_on_id":"bb-bvn","type":"parent-child","created_at":"2026-02-11T17:12:11.6890831-08:00","created_by":"zenchantlive"},{"issue_id":"bb-bvn.3","depends_on_id":"bb-bvn.2","type":"blocks","created_at":"2026-02-11T17:12:37.378326-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-tpc","title":"Live File Watching and SSE Transport","description":"Deliver real-time dashboard updates by watching Beads issue files and streaming one-way change notifications via SSE.","acceptance_criteria":"File changes trigger UI refresh without manual reload and reconnect behavior is stable.","status":"open","priority":0,"issue_type":"epic","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:52.6737283-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:11:52.6737283-08:00","labels":["realtime","sse","watcher"],"dependencies":[{"issue_id":"bb-tpc","depends_on_id":"bb-6aj","type":"blocks","created_at":"2026-02-11T17:12:20.1444149-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-tpc.1","title":"Implement chokidar watch manager for registered projects","description":"Start/stop watchers per active project and ensure watcher lifecycle tracks registry changes without leaking handles.","acceptance_criteria":"Watcher list updates correctly when projects are added or removed.","status":"open","priority":0,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:53.5050717-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:11:53.5050717-08:00","labels":["chokidar","watcher"],"dependencies":[{"issue_id":"bb-tpc.1","depends_on_id":"bb-tpc","type":"parent-child","created_at":"2026-02-11T17:11:53.5071586-08:00","created_by":"zenchantlive"},{"issue_id":"bb-tpc.1","depends_on_id":"bb-6aj.2","type":"blocks","created_at":"2026-02-11T17:12:28.2304516-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-tpc.2","title":"Add debounce/coalescing and transient lock handling for file change bursts","description":"Coalesce rapid updates from agent activity and handle temporary read lock contention without surfacing noisy errors.","acceptance_criteria":"Burst writes produce stable event cadence and no hard failures from temporary locks.","status":"open","priority":0,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:54.315119-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:11:54.315119-08:00","labels":["stability","watcher"],"dependencies":[{"issue_id":"bb-tpc.2","depends_on_id":"bb-tpc","type":"parent-child","created_at":"2026-02-11T17:11:54.3172104-08:00","created_by":"zenchantlive"},{"issue_id":"bb-tpc.2","depends_on_id":"bb-tpc.1","type":"blocks","created_at":"2026-02-11T17:12:28.7308524-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-tpc.3","title":"Implement SSE events API endpoint with heartbeat and event IDs","description":"Create SSE route supporting keepalive heartbeats and resumable event consumption patterns for browser clients.","acceptance_criteria":"SSE stream remains alive and clients can reconnect automatically.","status":"open","priority":0,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:55.1518352-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:11:55.1518352-08:00","labels":["api","sse"],"dependencies":[{"issue_id":"bb-tpc.3","depends_on_id":"bb-tpc","type":"parent-child","created_at":"2026-02-11T17:11:55.1533991-08:00","created_by":"zenchantlive"},{"issue_id":"bb-tpc.3","depends_on_id":"bb-tpc.2","type":"blocks","created_at":"2026-02-11T17:12:29.2599782-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-tpc.4","title":"Build frontend SSE client with scoped React Query invalidation","description":"Consume server events and invalidate only affected query keys, limiting unnecessary re-fetches in multi-project mode.","acceptance_criteria":"Changed project views refresh while unrelated views remain stable.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:56.0008015-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:11:56.0008015-08:00","labels":["frontend","react-query"],"dependencies":[{"issue_id":"bb-tpc.4","depends_on_id":"bb-tpc","type":"parent-child","created_at":"2026-02-11T17:11:56.0024218-08:00","created_by":"zenchantlive"},{"issue_id":"bb-tpc.4","depends_on_id":"bb-tpc.3","type":"blocks","created_at":"2026-02-11T17:12:29.768818-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-trz","title":"Kanban Experience (Baseline Dashboard)","description":"Ship a production-ready Kanban baseline inspired by prototype behavior but backed by real Beads project data and strict typing.","acceptance_criteria":"Users can inspect and filter live Beads issues through stable Kanban workflows.","status":"open","priority":1,"issue_type":"epic","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:56.8115491-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:11:56.8115491-08:00","labels":["kanban","ui"],"dependencies":[{"issue_id":"bb-trz","depends_on_id":"bb-92d","type":"blocks","created_at":"2026-02-11T17:12:20.6480287-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-trz.1","title":"Implement Kanban column layout for Beads statuses","description":"Render columns for open, in_progress, blocked, deferred, and closed with responsive behavior and clear status counts.","acceptance_criteria":"All statuses map correctly and render with stable ordering.","status":"in_progress","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:57.6278082-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:41:44.604363-08:00","labels":["columns","kanban"],"dependencies":[{"issue_id":"bb-trz.1","depends_on_id":"bb-trz","type":"parent-child","created_at":"2026-02-11T17:11:57.6288535-08:00","created_by":"zenchantlive"},{"issue_id":"bb-trz.1","depends_on_id":"bb-92d.4","type":"blocks","created_at":"2026-02-11T17:12:30.2796473-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-trz.2","title":"Build bead cards with priority/type/labels/assignee/dependency metadata","description":"Design compact cards exposing the most actionable issue metadata while preserving readability at high board density.","acceptance_criteria":"Cards show id, priority, type, labels, assignee, and dependency indicators.","status":"in_progress","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:58.4435327-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:41:46.1569931-08:00","labels":["cards","kanban"],"dependencies":[{"issue_id":"bb-trz.2","depends_on_id":"bb-trz","type":"parent-child","created_at":"2026-02-11T17:11:58.4450798-08:00","created_by":"zenchantlive"},{"issue_id":"bb-trz.2","depends_on_id":"bb-trz.1","type":"blocks","created_at":"2026-02-11T17:12:30.7837277-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-trz.3","title":"Implement detail slide-out panel with full issue metadata","description":"Add focused issue detail panel showing description, timestamps, dependencies, and lifecycle fields used by power users.","acceptance_criteria":"Selecting a card opens detail panel with complete issue context.","status":"in_progress","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:11:59.2746013-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:41:44.9885171-08:00","labels":["details","kanban"],"dependencies":[{"issue_id":"bb-trz.3","depends_on_id":"bb-trz","type":"parent-child","created_at":"2026-02-11T17:11:59.2756402-08:00","created_by":"zenchantlive"},{"issue_id":"bb-trz.3","depends_on_id":"bb-trz.2","type":"blocks","created_at":"2026-02-11T17:12:31.2944-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-trz.4","title":"Add search/filter/stats controls for status/type/priority/labels","description":"Provide fast filtering and at-a-glance counts, including critical issue indicators, for daily planning and triage workflows.","acceptance_criteria":"Search and filters apply consistently across board and counts.","status":"in_progress","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:00.0927161-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:41:45.8866335-08:00","labels":["filters","stats"],"dependencies":[{"issue_id":"bb-trz.4","depends_on_id":"bb-trz","type":"parent-child","created_at":"2026-02-11T17:12:00.0942721-08:00","created_by":"zenchantlive"},{"issue_id":"bb-trz.4","depends_on_id":"bb-trz.2","type":"blocks","created_at":"2026-02-11T17:12:31.798413-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-u6f","title":"Agent Session Views and Metrics","description":"Group work by agent session and actor fields to provide auditability and practical productivity insights for asynchronous coding workflows.","acceptance_criteria":"Session-based summaries and detail views are available per project and aggregate contexts.","status":"open","priority":2,"issue_type":"epic","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:12.5083912-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:12.5083912-08:00","labels":["agents","sessions"],"dependencies":[{"issue_id":"bb-u6f","depends_on_id":"bb-tpc","type":"blocks","created_at":"2026-02-11T17:12:23.1727361-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-u6f.1","title":"Extract and normalize session identity fields from issue data","description":"Derive session grouping from closed_by_session, assignee, and created_by with robust fallback semantics.","acceptance_criteria":"Issues are consistently assigned to session buckets when data exists.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:13.3239834-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:13.3239834-08:00","labels":["agents","data"],"dependencies":[{"issue_id":"bb-u6f.1","depends_on_id":"bb-u6f","type":"parent-child","created_at":"2026-02-11T17:12:13.3255058-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-u6f.2","title":"Build session list and detail views for claimed/completed/open outcomes","description":"Present session-level issue outcomes and navigation for operational review and accountability.","acceptance_criteria":"Users can inspect session summaries and drill into individual session issue sets.","status":"open","priority":2,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:14.1559358-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:14.1559358-08:00","labels":["agents","ui"],"dependencies":[{"issue_id":"bb-u6f.2","depends_on_id":"bb-u6f","type":"parent-child","created_at":"2026-02-11T17:12:14.157502-08:00","created_by":"zenchantlive"},{"issue_id":"bb-u6f.2","depends_on_id":"bb-u6f.1","type":"blocks","created_at":"2026-02-11T17:12:37.9045555-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-u6f.3","title":"Add baseline productivity metrics (completion rate, throughput, active span)","description":"Compute lightweight operational metrics from session issue events and timestamps.","acceptance_criteria":"Metrics are available with documented definitions and caveats.","status":"open","priority":2,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:15.0144056-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:15.0144056-08:00","labels":["agents","metrics"],"dependencies":[{"issue_id":"bb-u6f.3","depends_on_id":"bb-u6f","type":"parent-child","created_at":"2026-02-11T17:12:15.0155323-08:00","created_by":"zenchantlive"},{"issue_id":"bb-u6f.3","depends_on_id":"bb-u6f.2","type":"blocks","created_at":"2026-02-11T17:12:38.4424336-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-xhm","title":"Timeline and Activity Feed","description":"Provide a chronological activity view derived from issue snapshots and updates, enabling users to review agent/system activity over time.","acceptance_criteria":"Users can inspect chronological issue lifecycle events with useful filtering.","status":"open","priority":2,"issue_type":"epic","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:05.8525088-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:05.8525088-08:00","labels":["activity","timeline"],"dependencies":[{"issue_id":"bb-xhm","depends_on_id":"bb-tpc","type":"blocks","created_at":"2026-02-11T17:12:22.1602338-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-xhm.1","title":"Define activity event model for created/updated/closed/reopened actions","description":"Create stable event schema to represent issue lifecycle transitions and their project/session attribution.","acceptance_criteria":"Event model supports all required timeline activity types.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:06.6781387-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:06.6781387-08:00","labels":["model","timeline"],"dependencies":[{"issue_id":"bb-xhm.1","depends_on_id":"bb-xhm","type":"parent-child","created_at":"2026-02-11T17:12:06.6791721-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-xhm.2","title":"Implement snapshot diffing for derived timeline events","description":"Compare periodic snapshots and watcher updates to infer meaningful change events without requiring write interception.","acceptance_criteria":"Diff engine emits deterministic event records for relevant field changes.","status":"open","priority":2,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:07.5007059-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:07.5007059-08:00","labels":["diff","timeline"],"dependencies":[{"issue_id":"bb-xhm.2","depends_on_id":"bb-xhm","type":"parent-child","created_at":"2026-02-11T17:12:07.501756-08:00","created_by":"zenchantlive"},{"issue_id":"bb-xhm.2","depends_on_id":"bb-xhm.1","type":"blocks","created_at":"2026-02-11T17:12:35.3430513-08:00","created_by":"zenchantlive"},{"issue_id":"bb-xhm.2","depends_on_id":"bb-tpc.2","type":"blocks","created_at":"2026-02-11T17:12:35.8495336-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-xhm.3","title":"Build timeline UI with date grouping and project/assignee/event filters","description":"Render reverse-chronological feed suitable for morning review workflows with practical filter controls.","acceptance_criteria":"Timeline view supports grouping and filter combinations with acceptable performance.","status":"open","priority":2,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:08.3834905-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:08.3834905-08:00","labels":["timeline","ui"],"dependencies":[{"issue_id":"bb-xhm.3","depends_on_id":"bb-xhm","type":"parent-child","created_at":"2026-02-11T17:12:08.3851144-08:00","created_by":"zenchantlive"},{"issue_id":"bb-xhm.3","depends_on_id":"bb-xhm.2","type":"blocks","created_at":"2026-02-11T17:12:36.3627477-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-ymg","title":"CLI Write-Back via bd.exe","description":"Enable safe issue mutations from UI by routing all write operations through bd.exe and reflecting results through realtime reconciliation.","acceptance_criteria":"No direct JSONL writes exist; all mutations use bd commands and recover cleanly from failures.","status":"open","priority":1,"issue_type":"epic","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:00.9164956-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:00.9164956-08:00","labels":["bd-cli","mutation"],"dependencies":[{"issue_id":"bb-ymg","depends_on_id":"bb-trz","type":"blocks","created_at":"2026-02-11T17:12:21.1512868-08:00","created_by":"zenchantlive"},{"issue_id":"bb-ymg","depends_on_id":"bb-tpc","type":"blocks","created_at":"2026-02-11T17:12:21.6536312-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-ymg.1","title":"Implement bd bridge using child_process.execFile with project-scoped cwd","description":"Wrap bd execution with command argument safety, Windows path compatibility, stdout/stderr parsing, and project-specific current working directory.","acceptance_criteria":"Bridge executes supported bd commands and returns structured result/error payloads.","status":"open","priority":0,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:01.7327732-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:01.7327732-08:00","labels":["bridge","execfile"],"dependencies":[{"issue_id":"bb-ymg.1","depends_on_id":"bb-ymg","type":"parent-child","created_at":"2026-02-11T17:12:01.7343468-08:00","created_by":"zenchantlive"},{"issue_id":"bb-ymg.1","depends_on_id":"bb-6aj.2","type":"blocks","created_at":"2026-02-11T17:12:32.3039711-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-ymg.1.1","title":"Resolve bd.exe location from PATH and configuration fallback","description":"Add detection logic for bd executable and actionable errors when not found, including setup guidance.","acceptance_criteria":"Missing bd path returns clear setup instructions and diagnostics.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:02.5593205-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:02.5593205-08:00","labels":["bridge","setup"],"dependencies":[{"issue_id":"bb-ymg.1.1","depends_on_id":"bb-ymg.1","type":"parent-child","created_at":"2026-02-11T17:12:02.5603636-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-ymg.2","title":"Implement mutation API for create/update/close/reopen/comment operations","description":"Expose strict server-side mutation endpoints translating UI actions to corresponding bd commands with validated arguments.","acceptance_criteria":"All required mutation operations execute via bd and return normalized responses.","status":"open","priority":0,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:03.3757503-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:03.3757503-08:00","labels":["api","mutation"],"dependencies":[{"issue_id":"bb-ymg.2","depends_on_id":"bb-ymg","type":"parent-child","created_at":"2026-02-11T17:12:03.377343-08:00","created_by":"zenchantlive"},{"issue_id":"bb-ymg.2","depends_on_id":"bb-ymg.1","type":"blocks","created_at":"2026-02-11T17:12:32.810993-08:00","created_by":"zenchantlive"},{"issue_id":"bb-ymg.2","depends_on_id":"bb-ymg.1.1","type":"blocks","created_at":"2026-02-11T17:12:33.313807-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-ymg.3","title":"Add optimistic updates with rollback and SSE reconciliation","description":"Apply immediate UI updates for responsiveness, rollback on command failure, and reconcile with watcher-triggered authoritative state updates.","acceptance_criteria":"Failed mutations restore previous UI state and emit meaningful error feedback.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:04.1956393-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:04.1956393-08:00","labels":["optimistic","state"],"dependencies":[{"issue_id":"bb-ymg.3","depends_on_id":"bb-ymg","type":"parent-child","created_at":"2026-02-11T17:12:04.1966728-08:00","created_by":"zenchantlive"},{"issue_id":"bb-ymg.3","depends_on_id":"bb-ymg.2","type":"blocks","created_at":"2026-02-11T17:12:33.8246167-08:00","created_by":"zenchantlive"}]}
|
||||
{"id":"bb-ymg.4","title":"Implement drag-and-drop status transitions mapped to bd commands","description":"Map card moves to valid status transitions and use close/reopen semantics where applicable instead of direct file manipulation.","acceptance_criteria":"DnD transitions call proper bd commands and reject invalid transitions safely.","status":"open","priority":1,"issue_type":"task","owner":"jordanlive121@gmail.com","created_at":"2026-02-11T17:12:05.0129676-08:00","created_by":"zenchantlive","updated_at":"2026-02-11T17:12:05.0129676-08:00","labels":["dnd","kanban"],"dependencies":[{"issue_id":"bb-ymg.4","depends_on_id":"bb-ymg","type":"parent-child","created_at":"2026-02-11T17:12:05.014527-08:00","created_by":"zenchantlive"},{"issue_id":"bb-ymg.4","depends_on_id":"bb-ymg.2","type":"blocks","created_at":"2026-02-11T17:12:34.329788-08:00","created_by":"zenchantlive"},{"issue_id":"bb-ymg.4","depends_on_id":"bb-trz.1","type":"blocks","created_at":"2026-02-11T17:12:34.8422542-08:00","created_by":"zenchantlive"}]}
|
||||
4
.beads/metadata.json
Normal file
4
.beads/metadata.json
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"database": "beads.db",
|
||||
"jsonl_export": "issues.jsonl"
|
||||
}
|
||||
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
# Use bd merge for beads JSONL files
|
||||
.beads/issues.jsonl merge=beads
|
||||
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
node_modules/
|
||||
.next/
|
||||
*.tsbuildinfo
|
||||
.worktrees/
|
||||
worktrees/
|
||||
40
AGENTS.md
Normal file
40
AGENTS.md
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# Agent Instructions
|
||||
|
||||
This project uses **bd** (beads) for issue tracking. Run `bd onboard` to get started.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
```bash
|
||||
bd ready # Find available work
|
||||
bd show <id> # View issue details
|
||||
bd update <id> --status in_progress # Claim work
|
||||
bd close <id> # Complete work
|
||||
bd sync # Sync with git
|
||||
```
|
||||
|
||||
## Landing the Plane (Session Completion)
|
||||
|
||||
**When ending a work session**, you MUST complete ALL steps below. Work is NOT complete until `git push` succeeds.
|
||||
|
||||
**MANDATORY WORKFLOW:**
|
||||
|
||||
1. **File issues for remaining work** - Create issues for anything that needs follow-up
|
||||
2. **Run quality gates** (if code changed) - Tests, linters, builds
|
||||
3. **Update issue status** - Close finished work, update in-progress items
|
||||
4. **PUSH TO REMOTE** - This is MANDATORY:
|
||||
```bash
|
||||
git pull --rebase
|
||||
bd sync
|
||||
git push
|
||||
git status # MUST show "up to date with origin"
|
||||
```
|
||||
5. **Clean up** - Clear stashes, prune remote branches
|
||||
6. **Verify** - All changes committed AND pushed
|
||||
7. **Hand off** - Provide context for next session
|
||||
|
||||
**CRITICAL RULES:**
|
||||
- Work is NOT complete until `git push` succeeds
|
||||
- NEVER stop before pushing - that leaves work stranded locally
|
||||
- NEVER say "ready to push when you are" - YOU must push
|
||||
- If push fails, resolve and retry until it succeeds
|
||||
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2026 Zenchant
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
23
README.md
Normal file
23
README.md
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# BeadBoard
|
||||
|
||||
Windows-native Beads dashboard built with Next.js 15, React 19, and TypeScript.
|
||||
|
||||
## Core Rules
|
||||
- Read source of truth from `.beads/issues.jsonl`.
|
||||
- Perform all writes through `bd.exe`.
|
||||
- Never write directly to `.beads/issues.jsonl`.
|
||||
- Use Windows-safe path normalization for all project path operations.
|
||||
|
||||
## Stack
|
||||
- Next.js 15 (App Router)
|
||||
- React 19
|
||||
- TypeScript (strict)
|
||||
|
||||
## Local Development
|
||||
- `npm install`
|
||||
- `npm run dev`
|
||||
- `npm run typecheck`
|
||||
- `npm run test`
|
||||
|
||||
## Scope
|
||||
BeadBoard provides Kanban, dependency graph, timeline, and agent-session views over one or more registered Windows project roots.
|
||||
260
docs/plans/2026-02-12-beadboard-implementation-plan.md
Normal file
260
docs/plans/2026-02-12-beadboard-implementation-plan.md
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
# BeadBoard Implementation Plan
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**Goal:** Build a Windows-native Beads dashboard that reads `.beads/issues.jsonl` directly and performs all mutations through `bd.exe`.
|
||||
|
||||
**Architecture:** The app uses Next.js App Router APIs for filesystem reads, project scanning, watcher lifecycle, SSE broadcasting, and CLI mutation bridging. Frontend uses React Query for server-state synchronization and Zustand for UI-local state plus optimistic transition coordination. Windows path normalization is centralized and enforced at all boundaries to prevent cross-drive and casing inconsistencies.
|
||||
|
||||
**Tech Stack:** Next.js 15, React 19, TypeScript (strict), Tailwind CSS, Zustand, TanStack Query, chokidar, React Flow, `child_process.execFile`.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Repository Bootstrap and Runtime Guardrails
|
||||
|
||||
**Files:**
|
||||
- Create: `package.json`
|
||||
- Create: `tsconfig.json`
|
||||
- Create: `next.config.ts`
|
||||
- Create: `LICENSE`
|
||||
- Create: `src/app/layout.tsx`
|
||||
- Create: `src/app/page.tsx`
|
||||
|
||||
**Step 1: Write failing environment checks**
|
||||
- Add a smoke test placeholder for app boot and runtime config verification.
|
||||
|
||||
**Step 2: Run verification to confirm missing implementation**
|
||||
- Run: `npm run test` (expected to fail before setup).
|
||||
|
||||
**Step 3: Implement minimal app bootstrap**
|
||||
- Initialize Next.js 15 + React 19 + TypeScript strict setup.
|
||||
- Add MIT license file.
|
||||
|
||||
**Step 4: Re-run checks**
|
||||
- Run: `npm run lint` and `npm run typecheck`.
|
||||
|
||||
**Step 5: Commit**
|
||||
- Commit message: `chore: bootstrap beadboard foundation`
|
||||
|
||||
### Task 2: Canonical Types and JSONL Parser
|
||||
|
||||
**Files:**
|
||||
- Create: `src/lib/types.ts`
|
||||
- Create: `src/lib/parser.ts`
|
||||
- Create: `tests/lib/parser.test.ts`
|
||||
|
||||
**Step 1: Write failing parser tests**
|
||||
- Cover defaults, malformed lines, tombstone filtering, `priority=0` preservation.
|
||||
|
||||
**Step 2: Run targeted test**
|
||||
- Run: `npm run test -- tests/lib/parser.test.ts` (expected fail).
|
||||
|
||||
**Step 3: Implement parser + DTO normalization**
|
||||
- Parse one JSON object per line, skip malformed lines, apply defaults.
|
||||
|
||||
**Step 4: Run tests**
|
||||
- Run parser tests and full typecheck.
|
||||
|
||||
**Step 5: Commit**
|
||||
- Commit message: `feat: add beads schema and robust jsonl parser`
|
||||
|
||||
### Task 3: Windows Pathing + Project Registry
|
||||
|
||||
**Files:**
|
||||
- Create: `src/lib/pathing.ts`
|
||||
- Create: `src/lib/projects-registry.ts`
|
||||
- Create: `src/app/api/projects/route.ts`
|
||||
- Test: `tests/lib/pathing.test.ts`
|
||||
|
||||
**Step 1: Write failing path tests**
|
||||
- Validate canonicalization for `C:\` and `D:\`, stable key generation.
|
||||
|
||||
**Step 2: Implement path utility + registry persistence**
|
||||
- Use `%USERPROFILE%\\.beadboard\\projects.json` as registry location.
|
||||
|
||||
**Step 3: Implement API route**
|
||||
- Support add/list/remove with validation and normalized identity.
|
||||
|
||||
**Step 4: Verify**
|
||||
- Run path tests + API handler tests.
|
||||
|
||||
**Step 5: Commit**
|
||||
- Commit message: `feat: add windows path normalization and project registry`
|
||||
|
||||
### Task 4: Read API and Multi-Project Aggregation
|
||||
|
||||
**Files:**
|
||||
- Create: `src/app/api/beads/route.ts`
|
||||
- Create: `src/lib/read-service.ts`
|
||||
- Test: `tests/api/beads-route.test.ts`
|
||||
|
||||
**Step 1: Write failing API tests**
|
||||
- Single project read, aggregate read, filter params, error behavior.
|
||||
|
||||
**Step 2: Implement read service**
|
||||
- Read `.beads/issues.jsonl` directly via `fs`.
|
||||
|
||||
**Step 3: Implement route layer**
|
||||
- Query support for project, status, type, priority, assignee, label.
|
||||
|
||||
**Step 4: Verify**
|
||||
- Run route tests and typecheck.
|
||||
|
||||
**Step 5: Commit**
|
||||
- Commit message: `feat: add beads read api for single and aggregate views`
|
||||
|
||||
### Task 5: Scanner and Discovery Controls
|
||||
|
||||
**Files:**
|
||||
- Create: `src/lib/scanner.ts`
|
||||
- Create: `src/app/api/scan/route.ts`
|
||||
- Test: `tests/lib/scanner.test.ts`
|
||||
|
||||
**Step 1: Write failing scanner tests**
|
||||
- Depth limits, ignore patterns, profile-root default behavior.
|
||||
|
||||
**Step 2: Implement scanner**
|
||||
- Default root `%USERPROFILE%`, plus user-added roots.
|
||||
- Add explicit full-drive mode action.
|
||||
|
||||
**Step 3: Implement scan API**
|
||||
- Trigger scan + return discovered project candidates.
|
||||
|
||||
**Step 4: Verify**
|
||||
- Run scanner tests.
|
||||
|
||||
**Step 5: Commit**
|
||||
- Commit message: `feat: add windows-safe project scanner and scan api`
|
||||
|
||||
### Task 6: Watcher + SSE Event Bus
|
||||
|
||||
**Files:**
|
||||
- Create: `src/lib/watcher.ts`
|
||||
- Create: `src/lib/sse-bus.ts`
|
||||
- Create: `src/app/api/events/route.ts`
|
||||
- Test: `tests/lib/watcher.test.ts`
|
||||
|
||||
**Step 1: Write failing watcher tests**
|
||||
- Debounced change emission, lock retry behavior, multi-project handling.
|
||||
|
||||
**Step 2: Implement watcher manager**
|
||||
- Chokidar watchers for registered projects.
|
||||
|
||||
**Step 3: Implement SSE endpoint**
|
||||
- Heartbeat, reconnect-safe events, project-scoped payloads.
|
||||
|
||||
**Step 4: Verify**
|
||||
- Run watcher/event tests.
|
||||
|
||||
**Step 5: Commit**
|
||||
- Commit message: `feat: add live file watching and sse updates`
|
||||
|
||||
### Task 7: bd.exe Mutation Bridge + API
|
||||
|
||||
**Files:**
|
||||
- Create: `src/lib/bd-bridge.ts`
|
||||
- Create: `src/app/api/mutate/route.ts`
|
||||
- Test: `tests/lib/bd-bridge.test.ts`
|
||||
|
||||
**Step 1: Write failing bridge tests**
|
||||
- Command invocation, cwd routing, stdout/stderr error mapping.
|
||||
|
||||
**Step 2: Implement execFile bridge**
|
||||
- Resolve `bd.exe` from PATH, enforce project CWD, parse outputs.
|
||||
|
||||
**Step 3: Implement mutate API**
|
||||
- `create`, `update`, `close`, `reopen`, `comment` actions.
|
||||
|
||||
**Step 4: Verify**
|
||||
- Run bridge tests and mutation route tests.
|
||||
|
||||
**Step 5: Commit**
|
||||
- Commit message: `feat: add bd cli mutation bridge and api`
|
||||
|
||||
### Task 8: Frontend State and Realtime Sync
|
||||
|
||||
**Files:**
|
||||
- Create: `src/lib/query-client.ts`
|
||||
- Create: `src/lib/store.ts`
|
||||
- Create: `src/lib/sse-client.ts`
|
||||
- Modify: `src/app/layout.tsx`
|
||||
|
||||
**Step 1: Write failing state tests**
|
||||
- Query invalidation + optimistic rollback cases.
|
||||
|
||||
**Step 2: Implement Query + Zustand providers**
|
||||
- Distinguish server cache from UI-local state.
|
||||
|
||||
**Step 3: Implement SSE client integration**
|
||||
- Auto reconnect and scoped invalidation for changed projects.
|
||||
|
||||
**Step 4: Verify**
|
||||
- Run state/integration tests.
|
||||
|
||||
**Step 5: Commit**
|
||||
- Commit message: `feat: wire react-query zustand and realtime invalidation`
|
||||
|
||||
### Task 9: Feature Views (Kanban, Graph, Timeline, Sessions)
|
||||
|
||||
**Files:**
|
||||
- Create: `src/components/kanban/*`
|
||||
- Create: `src/components/graph/*`
|
||||
- Create: `src/components/timeline/*`
|
||||
- Create: `src/components/agents/*`
|
||||
- Create: `src/app/graph/page.tsx`
|
||||
- Create: `src/app/timeline/page.tsx`
|
||||
- Create: `src/app/agents/page.tsx`
|
||||
|
||||
**Step 1: Write failing UI tests**
|
||||
- Column rendering, card detail open, graph node interaction, timeline grouping.
|
||||
|
||||
**Step 2: Implement Kanban baseline**
|
||||
- Columns, card metadata, details panel, filters/stats.
|
||||
|
||||
**Step 3: Implement Graph with React Flow**
|
||||
- Edges from dependencies, pan/zoom/select, blocked-chain highlighting.
|
||||
|
||||
**Step 4: Implement Timeline + Session views**
|
||||
- Derived activity and session grouping/metrics.
|
||||
|
||||
**Step 5: Verify**
|
||||
- Run component tests and visual smoke check.
|
||||
|
||||
**Step 6: Commit**
|
||||
- Commit message: `feat: deliver dashboard views for kanban graph timeline and sessions`
|
||||
|
||||
### Task 10: Quality Gates and Boundary Enforcement
|
||||
|
||||
**Files:**
|
||||
- Create: `tests/guards/no-direct-jsonl-write.test.ts`
|
||||
- Create: `docs/architecture/read-write-boundary.md`
|
||||
- Modify: `package.json`
|
||||
|
||||
**Step 1: Write failing guard test**
|
||||
- Detect direct writes to `.beads/issues.jsonl` in application code.
|
||||
|
||||
**Step 2: Implement boundary guard tooling**
|
||||
- Add CI script and local verification command.
|
||||
|
||||
**Step 3: Add performance checks**
|
||||
- Parser benchmark and SSE latency smoke measurements.
|
||||
|
||||
**Step 4: Verify full pipeline**
|
||||
- Run `npm run lint && npm run typecheck && npm run test`.
|
||||
|
||||
**Step 5: Commit**
|
||||
- Commit message: `chore: enforce read-write boundaries and quality gates`
|
||||
|
||||
## Execution Sequence and Parallelization
|
||||
- Sequential core chain: Task 1 -> Task 2 -> Task 3 -> Task 4 -> Task 6 -> Task 7 -> Task 8
|
||||
- Parallel branch A (after Task 3): Task 5
|
||||
- Parallel branch B (after Task 4 and Task 8): Task 9
|
||||
- Final gate: Task 10
|
||||
|
||||
## Completion Criteria
|
||||
- Windows-native workflow validated in PowerShell/CMD
|
||||
- Reads from JSONL only
|
||||
- Mutations executed only via `bd.exe`
|
||||
- Real-time updates delivered via SSE
|
||||
- Kanban, Graph, Timeline, Agent Session views functional
|
||||
- Boundary guard test prevents direct JSONL writes
|
||||
162
docs/plans/2026-02-12-beadboard-prd.md
Normal file
162
docs/plans/2026-02-12-beadboard-prd.md
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
# BeadBoard Product Requirements Document (PRD)
|
||||
|
||||
Version: 1.1
|
||||
Date: February 12, 2026
|
||||
License: MIT
|
||||
|
||||
## 1. Product Summary
|
||||
BeadBoard is a Windows-native web dashboard for Beads that provides a unified interface for Kanban planning, dependency visualization, timeline auditing, and agent-session tracking across multiple projects.
|
||||
|
||||
The app must run without WSL and without Unix-only shell assumptions. It reads Beads data directly from `.beads/issues.jsonl` and performs all mutations through `bd.exe`.
|
||||
|
||||
## 2. Problem Statement
|
||||
Current Beads ecosystem tools are often Unix/macOS oriented, creating friction for Windows-native development flows. Users need:
|
||||
- Native Windows path support (`C:\...`, `D:\...`)
|
||||
- Multi-project visibility in one dashboard
|
||||
- Real-time monitoring of agent activity
|
||||
- A strict read/write boundary that preserves Beads/Dolt consistency
|
||||
|
||||
## 3. Goals
|
||||
- Build a modern dashboard on Next.js 15 + React 19 + TypeScript
|
||||
- Use `.beads/issues.jsonl` as source of truth for reads
|
||||
- Use `bd.exe` exclusively for writes (`create`, `update`, `close`, `comment`, `reopen`)
|
||||
- Provide real-time updates via file watching + SSE
|
||||
- Support multi-project workflows across Windows-native paths
|
||||
|
||||
## 4. Non-Negotiable Constraints
|
||||
- Stack: Next.js 15, React 19, TypeScript (strict)
|
||||
- Platform: Windows native (no WSL assumptions)
|
||||
- Reads: parse `.beads/issues.jsonl` directly
|
||||
- Writes: must route through `bd.exe` via `child_process.execFile`
|
||||
- Never write directly to `issues.jsonl`
|
||||
- License: MIT
|
||||
|
||||
## 5. Architecture
|
||||
### 5.1 Frontend
|
||||
- React 19 UI with Tailwind
|
||||
- Views: Kanban, Dependency Graph, Timeline, Agent Sessions
|
||||
- State: React Query (server/cache) + Zustand (UI state, optimistic UI state coordination)
|
||||
|
||||
### 5.2 Backend (Next.js App Router API)
|
||||
- Read layer: Node `fs` + JSONL parser
|
||||
- Watch layer: `chokidar` on project `.beads` files
|
||||
- Transport: Server-Sent Events (SSE) for one-way real-time updates
|
||||
- Write layer: `child_process.execFile` wrapper over `bd.exe`
|
||||
|
||||
### 5.3 Path and Project Handling
|
||||
- Project root for this repo: `C:\Users\Zenchant\codex\beadboard`
|
||||
- User project registry stored in profile path: `%USERPROFILE%\\.beadboard\\projects.json`
|
||||
- Normalize paths with Windows-safe utilities before comparison/storage
|
||||
- Display paths in readable normalized form while preserving canonical behavior
|
||||
|
||||
## 6. Approved Product Decisions
|
||||
- Graph library: React Flow (faster delivery for interactive DAG use cases)
|
||||
- Mutation scope in phase 1: include comments and reopen in addition to create/update/close
|
||||
- Demo clip is reference-only (not a runtime mode)
|
||||
- Auto-scan policy:
|
||||
- Default: auto-scan `%USERPROFILE%` and user-added roots
|
||||
- Optional: explicit “scan all drives” action for broader discovery
|
||||
|
||||
## 7. Core Functional Requirements
|
||||
### 7.1 Kanban Board
|
||||
- Status columns: `open`, `in_progress`, `blocked`, `deferred`, `closed`
|
||||
- Card metadata: id, priority, type, labels, assignee, dependency count
|
||||
- Detail panel with full bead metadata
|
||||
- Search/filter by text, type, priority, label
|
||||
|
||||
### 7.2 Multi-Project Support
|
||||
- Register/remove project roots
|
||||
- Discover `.beads` directories under approved scan roots
|
||||
- Switch between per-project and aggregate views
|
||||
|
||||
### 7.3 Real-Time Updates
|
||||
- Watch `issues.jsonl` changes with debounce
|
||||
- Publish change events via SSE
|
||||
- Client auto-reconnect and query invalidation on relevant updates
|
||||
|
||||
### 7.4 Dependency Graph
|
||||
- Parse dependency edges (`blocks`, `parent`, `relates_to`, `duplicates`, `supersedes`)
|
||||
- Render interactive graph with pan/zoom/select
|
||||
- Highlight blocked chains and flag cycles/anomalies
|
||||
|
||||
### 7.5 Timeline / Activity Feed
|
||||
- Derive timeline events from snapshots + updates
|
||||
- Group chronologically
|
||||
- Filter by project, agent/session, and event type
|
||||
|
||||
### 7.6 Agent Session View
|
||||
- Group issues by `closed_by_session`, `assignee`, `created_by`
|
||||
- Display claimed/completed/open outcomes per session
|
||||
|
||||
### 7.7 CLI Write-Back
|
||||
- Mutations must execute `bd.exe` in target project CWD
|
||||
- Supported operations:
|
||||
- Create bead
|
||||
- Update bead fields/status
|
||||
- Close bead with reason
|
||||
- Reopen bead
|
||||
- Add comment
|
||||
- Optimistic UI updates with rollback on CLI failure
|
||||
|
||||
## 8. Data Handling Requirements
|
||||
- Input format: JSONL (one object per line)
|
||||
- Ignore blank lines
|
||||
- Skip malformed JSON lines safely
|
||||
- Apply defaults:
|
||||
- `status = open` when absent
|
||||
- `issue_type = task` when absent
|
||||
- `priority = 2` when absent (`0` is valid and must be preserved)
|
||||
- Exclude `tombstone` from standard views unless explicitly requested
|
||||
|
||||
## 9. Quality, Reliability, and Safety
|
||||
- Strict read/write boundary tests must verify no direct JSONL write path exists
|
||||
- Graceful handling for:
|
||||
- File locks/transient read failures
|
||||
- Missing `bd.exe`
|
||||
- Command failures with actionable errors
|
||||
- All logic must remain Windows-safe and avoid Unix-only assumptions
|
||||
|
||||
## 10. Performance Targets
|
||||
- Startup/render readiness target: < 2s (local dev expectation)
|
||||
- Parse performance target: < 100ms for 1000 beads
|
||||
- Live update propagation target: < 500ms from file change to UI refresh
|
||||
- Scan performance: practical defaults with bounded recursion and ignore rules
|
||||
|
||||
## 11. Scope by Priority
|
||||
### P0
|
||||
- Foundation, schema/types, path normalization
|
||||
- JSONL read layer and API
|
||||
- Registry + scanner
|
||||
- Watcher + SSE
|
||||
|
||||
### P1
|
||||
- Kanban UI
|
||||
- CLI mutation bridge and APIs (including comments/reopen)
|
||||
- Optimistic update/rollback
|
||||
- Hardening + test coverage for boundaries
|
||||
|
||||
### P2
|
||||
- Timeline
|
||||
- Dependency Graph
|
||||
- Agent Session views
|
||||
|
||||
## 12. Out of Scope (Initial Release)
|
||||
- Full-drive auto-scan by default
|
||||
- WebSocket transport
|
||||
- Direct DB replacement for JSONL source of truth
|
||||
- Any direct write to `.beads/issues.jsonl`
|
||||
|
||||
## 13. Risks and Mitigations
|
||||
- Risk: stale/partial views during rapid CLI writes
|
||||
Mitigation: debounce + SSE invalidation + eventual re-read reconciliation
|
||||
- Risk: path mismatch across different Windows forms
|
||||
Mitigation: centralized normalization and canonical path keys
|
||||
- Risk: CLI output format drift
|
||||
Mitigation: tolerant parsing and startup version checks
|
||||
|
||||
## 14. Acceptance Criteria (System-Level)
|
||||
- Runs natively on Windows PowerShell/CMD without WSL
|
||||
- Reads from `.beads/issues.jsonl` successfully for registered projects
|
||||
- All writes performed via `bd.exe` and reflected back via watcher/SSE
|
||||
- Kanban, Timeline, Graph, and Agent Session views function against real bead data
|
||||
- No direct `issues.jsonl` write implementation exists in app code
|
||||
226
docs/plans/2026-02-12-parallel-agent-dispatch.md
Normal file
226
docs/plans/2026-02-12-parallel-agent-dispatch.md
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
# BeadBoard Parallel Agent Dispatch Plan
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**Goal:** Run the next BeadBoard implementation phase in parallel with low merge risk, while preserving strict read/write boundaries (`issues.jsonl` read-only, writes only through `bd.exe`).
|
||||
|
||||
**Architecture:** Split work by subsystem with clear file ownership: registry persistence + API, scanner, and Kanban UI baseline. Keep each agent on dependency-safe beads and synchronize through an integration lead at checkpoints.
|
||||
|
||||
**Tech Stack:** Next.js 15, React 19, TypeScript strict, Node `fs`, Windows path utilities, React Query, Zustand.
|
||||
|
||||
---
|
||||
|
||||
## Parallelization Model
|
||||
|
||||
### Agent Roles
|
||||
|
||||
1. **Agent A (Registry/API Track)**
|
||||
- Primary beads: `bb-6aj.1`, then `bb-6aj.2`
|
||||
- Scope: profile-scoped project registry + API endpoints for add/remove/list
|
||||
- Files expected:
|
||||
- `src/lib/registry.ts`
|
||||
- `src/app/api/projects/route.ts`
|
||||
- tests under `tests/lib/` and `tests/api/`
|
||||
|
||||
2. **Agent B (Kanban UI Track)**
|
||||
- Primary beads: `bb-trz.1`, then `bb-trz.2`, then `bb-trz.3`, then `bb-trz.4`
|
||||
- Scope: tracer bullet 1 Kanban baseline (demo-inspired UI with production typing)
|
||||
- Files expected:
|
||||
- `src/app/page.tsx`
|
||||
- `src/components/kanban/*`
|
||||
- `src/components/shared/*`
|
||||
- UI tests under `tests/`
|
||||
|
||||
3. **Agent C (Scanner Track)**
|
||||
- Primary beads: `bb-6aj.3`, then `bb-6aj.3.1` (optional if time remains)
|
||||
- Scope: bounded scanner rooted at `%USERPROFILE%` with explicit full-drive opt-in mode
|
||||
- Files expected:
|
||||
- `src/lib/scanner.ts`
|
||||
- `src/app/api/scan/route.ts` (if created in this phase)
|
||||
- tests under `tests/lib/`
|
||||
|
||||
4. **Lead Agent (Integrator/Verifier)**
|
||||
- No primary feature bead; owns integration + verification
|
||||
- Scope: merges, resolves small conflicts, runs checks, updates bead states
|
||||
|
||||
---
|
||||
|
||||
## Dependency Rules (Do Not Break)
|
||||
|
||||
1. `bb-6aj.2` must start only after `bb-6aj.1` is complete (hard dependency).
|
||||
2. `bb-6aj.3` depends on `bb-6aj.1` (hard dependency).
|
||||
3. `bb-trz.2` depends on `bb-trz.1`.
|
||||
4. `bb-trz.3` and `bb-trz.4` depend on `bb-trz.2`.
|
||||
5. No direct writes to `.beads/issues.jsonl` under any condition.
|
||||
|
||||
---
|
||||
|
||||
## Checkpoint Sequence
|
||||
|
||||
### Checkpoint 0: Branch Preparation
|
||||
1. Create feature branches from current baseline:
|
||||
- `feat/registry-api`
|
||||
- `feat/kanban-baseline`
|
||||
- `feat/scanner`
|
||||
2. Each agent works only in its branch.
|
||||
|
||||
### Checkpoint 1: Foundation Delivery
|
||||
1. Agent A finishes `bb-6aj.1`.
|
||||
2. Agent B finishes `bb-trz.1`.
|
||||
3. Agent C remains blocked until `bb-6aj.1` closes, then starts `bb-6aj.3`.
|
||||
4. Lead verifies:
|
||||
- `npm run typecheck`
|
||||
- `npm run test`
|
||||
|
||||
### Checkpoint 2: Mid-Phase Delivery
|
||||
1. Agent A completes `bb-6aj.2`.
|
||||
2. Agent B completes `bb-trz.2`.
|
||||
3. Agent C completes `bb-6aj.3`.
|
||||
4. Lead rebases/merges and reruns:
|
||||
- `npm run typecheck`
|
||||
- `npm run test`
|
||||
- `npm run dev` (startup sanity)
|
||||
|
||||
### Checkpoint 3: Tracer-1 Completion
|
||||
1. Agent B completes `bb-trz.3` and `bb-trz.4`.
|
||||
2. Lead runs manual UI smoke for Kanban baseline.
|
||||
3. Lead optionally uses browser automation for verification once app is up.
|
||||
|
||||
---
|
||||
|
||||
## Agent Prompt Pack
|
||||
|
||||
### Prompt: Agent A (Registry/API)
|
||||
|
||||
```text
|
||||
You are Agent A on BeadBoard.
|
||||
|
||||
Mission:
|
||||
1) Complete bb-6aj.1
|
||||
2) Complete bb-6aj.2
|
||||
|
||||
Constraints:
|
||||
- Windows-native paths only
|
||||
- Persist registry at %USERPROFILE%\.beadboard\projects.json
|
||||
- Normalize paths safely (no Unix assumptions)
|
||||
- No direct writes to .beads/issues.jsonl
|
||||
- Maintain strict TS types and add tests
|
||||
|
||||
Deliverables:
|
||||
- src/lib/registry.ts (or equivalent)
|
||||
- src/app/api/projects/route.ts with add/remove/list
|
||||
- tests covering malformed paths, duplicate normalization, lazy file creation
|
||||
- bead updates with concise implementation notes
|
||||
|
||||
Verification before close:
|
||||
- npm run typecheck
|
||||
- npm run test
|
||||
```
|
||||
|
||||
### Prompt: Agent B (Kanban Baseline)
|
||||
|
||||
```text
|
||||
You are Agent B on BeadBoard.
|
||||
|
||||
Mission:
|
||||
1) Complete bb-trz.1
|
||||
2) Complete bb-trz.2
|
||||
3) Complete bb-trz.3
|
||||
4) Complete bb-trz.4
|
||||
|
||||
Constraints:
|
||||
- Rebuild demo style as production Next.js/TS components
|
||||
- Use real parser data path, no sample-data-only architecture
|
||||
- Preserve status ordering: open, in_progress, blocked, deferred, closed
|
||||
- Read boundary only; all writes are future bd bridge work
|
||||
- Keep components modular and typed
|
||||
|
||||
Deliverables:
|
||||
- Kanban columns
|
||||
- Card component with id/priority/type/labels/assignee/dep count
|
||||
- Detail panel with timestamps/dependencies
|
||||
- Search/filter/stats controls
|
||||
- tests for rendering and filtering behavior
|
||||
|
||||
Verification before close:
|
||||
- npm run typecheck
|
||||
- npm run test
|
||||
- npm run dev (manual check of kanban page)
|
||||
```
|
||||
|
||||
### Prompt: Agent C (Scanner)
|
||||
|
||||
```text
|
||||
You are Agent C on BeadBoard.
|
||||
|
||||
Mission:
|
||||
1) Complete bb-6aj.3
|
||||
2) Optionally complete bb-6aj.3.1 if time permits
|
||||
|
||||
Constraints:
|
||||
- Default scan root is %USERPROFILE%, not full-drive crawl
|
||||
- Implement bounded recursion and ignore patterns
|
||||
- Explicit full-drive scan must be opt-in only
|
||||
- Windows-safe path normalization throughout
|
||||
- No shell-specific assumptions
|
||||
|
||||
Deliverables:
|
||||
- src/lib/scanner.ts
|
||||
- optional scan API route if needed for invoking scanner
|
||||
- tests for depth limit, ignore behavior, and root selection
|
||||
|
||||
Verification before close:
|
||||
- npm run typecheck
|
||||
- npm run test
|
||||
```
|
||||
|
||||
### Prompt: Lead Agent (Integration)
|
||||
|
||||
```text
|
||||
You are Lead Agent for BeadBoard integration.
|
||||
|
||||
Mission:
|
||||
1) Integrate outputs from Agent A/B/C at checkpoints
|
||||
2) Keep bead statuses accurate
|
||||
3) Run verification and capture failures with file-level notes
|
||||
|
||||
Rules:
|
||||
- Do not mask failing tests
|
||||
- Resolve merge conflicts without changing boundary contracts
|
||||
- Ensure no direct writes to .beads/issues.jsonl
|
||||
|
||||
Verification gates:
|
||||
- npm run typecheck
|
||||
- npm run test
|
||||
- npm run dev startup check
|
||||
|
||||
Completion condition:
|
||||
- Tracer bullet 1 Kanban baseline visible and functional
|
||||
- Registry + scanner foundations merged and passing checks
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## First Task to Start Now
|
||||
|
||||
1. Start **Agent A** on `bb-6aj.1` (unblocks both `bb-6aj.2` and `bb-6aj.3`).
|
||||
2. In parallel, start **Agent B** on `bb-trz.1`.
|
||||
3. Start **Agent C** only after `bb-6aj.1` is closed.
|
||||
|
||||
---
|
||||
|
||||
## Run Commands (Lead)
|
||||
|
||||
```powershell
|
||||
# show ready tasks
|
||||
bd ready
|
||||
|
||||
# claim task
|
||||
bd update bb-6aj.1 --claim
|
||||
|
||||
# run verification
|
||||
npm run typecheck
|
||||
npm run test
|
||||
npm run dev
|
||||
```
|
||||
|
||||
4
next-env.d.ts
vendored
Normal file
4
next-env.d.ts
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file is auto-generated by Next.js type tooling.
|
||||
9
next.config.ts
Normal file
9
next.config.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import type { NextConfig } from 'next';
|
||||
import path from 'node:path';
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
reactStrictMode: true,
|
||||
outputFileTracingRoot: path.join(process.cwd()),
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
1508
package-lock.json
generated
Normal file
1508
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
26
package.json
Normal file
26
package.json
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "beadboard",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "node --test tests/bootstrap.test.mjs && node --import tsx --test tests/lib/parser.test.ts && node --import tsx --test tests/lib/pathing.test.ts && node --test tests/guards/no-direct-jsonl-write.test.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "15.5.7",
|
||||
"react": "19.2.1",
|
||||
"react-dom": "19.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.10.0",
|
||||
"@types/react": "^19.0.0",
|
||||
"@types/react-dom": "^19.0.0",
|
||||
"tsx": "^4.21.0",
|
||||
"typescript": "^5.7.2"
|
||||
}
|
||||
}
|
||||
15
src/app/layout.tsx
Normal file
15
src/app/layout.tsx
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import type { Metadata } from 'next';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'BeadBoard',
|
||||
description: 'Windows-native Beads dashboard',
|
||||
};
|
||||
|
||||
export default function RootLayout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
7
src/app/page.tsx
Normal file
7
src/app/page.tsx
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
export default function Page() {
|
||||
return (
|
||||
<main>
|
||||
<h1>BeadBoard</h1>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
85
src/lib/parser.ts
Normal file
85
src/lib/parser.ts
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
import type { BeadDependency, BeadIssue, ParseableBeadIssue } from './types';
|
||||
|
||||
export interface ParseIssuesOptions {
|
||||
includeTombstones?: boolean;
|
||||
}
|
||||
|
||||
function normalizeDependencies(value: unknown): BeadDependency[] {
|
||||
if (!Array.isArray(value)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return value
|
||||
.map((item) => {
|
||||
if (!item || typeof item !== 'object') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const dep = item as { type?: unknown; target?: unknown };
|
||||
if (typeof dep.type !== 'string' || typeof dep.target !== 'string') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
type: dep.type as BeadDependency['type'],
|
||||
target: dep.target,
|
||||
};
|
||||
})
|
||||
.filter((dep): dep is BeadDependency => dep !== null);
|
||||
}
|
||||
|
||||
function normalizeIssue(raw: ParseableBeadIssue): BeadIssue {
|
||||
return {
|
||||
id: raw.id,
|
||||
title: raw.title,
|
||||
description: typeof raw.description === 'string' ? raw.description : null,
|
||||
status: (raw.status ?? 'open') as BeadIssue['status'],
|
||||
priority: typeof raw.priority === 'number' ? raw.priority : 2,
|
||||
issue_type: (raw.issue_type ?? 'task') as BeadIssue['issue_type'],
|
||||
assignee: typeof raw.assignee === 'string' ? raw.assignee : null,
|
||||
owner: typeof raw.owner === 'string' ? raw.owner : null,
|
||||
labels: Array.isArray(raw.labels) ? raw.labels.filter((x): x is string => typeof x === 'string') : [],
|
||||
dependencies: normalizeDependencies(raw.dependencies),
|
||||
created_at: typeof raw.created_at === 'string' ? raw.created_at : '',
|
||||
updated_at: typeof raw.updated_at === 'string' ? raw.updated_at : '',
|
||||
closed_at: typeof raw.closed_at === 'string' ? raw.closed_at : null,
|
||||
close_reason: typeof raw.close_reason === 'string' ? raw.close_reason : null,
|
||||
closed_by_session: typeof raw.closed_by_session === 'string' ? raw.closed_by_session : null,
|
||||
created_by: typeof raw.created_by === 'string' ? raw.created_by : null,
|
||||
due_at: typeof raw.due_at === 'string' ? raw.due_at : null,
|
||||
estimated_minutes: typeof raw.estimated_minutes === 'number' ? raw.estimated_minutes : null,
|
||||
external_ref: typeof raw.external_ref === 'string' ? raw.external_ref : null,
|
||||
metadata: typeof raw.metadata === 'object' && raw.metadata !== null ? (raw.metadata as Record<string, unknown>) : {},
|
||||
};
|
||||
}
|
||||
|
||||
export function parseIssuesJsonl(text: string, options: ParseIssuesOptions = {}): BeadIssue[] {
|
||||
const includeTombstones = options.includeTombstones ?? false;
|
||||
const issues: BeadIssue[] = [];
|
||||
|
||||
for (const line of text.split(/\r?\n/)) {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
const parsed = JSON.parse(trimmed) as ParseableBeadIssue;
|
||||
if (!parsed.id || !parsed.title) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const normalized = normalizeIssue(parsed);
|
||||
if (!includeTombstones && normalized.status === 'tombstone') {
|
||||
continue;
|
||||
}
|
||||
|
||||
issues.push(normalized);
|
||||
} catch {
|
||||
// Skip malformed lines to keep parser resilient against partial writes.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return issues;
|
||||
}
|
||||
36
src/lib/pathing.ts
Normal file
36
src/lib/pathing.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import path from 'node:path';
|
||||
|
||||
function normalizeDriveLetter(input: string): string {
|
||||
if (/^[a-z]:/.test(input)) {
|
||||
return `${input[0].toUpperCase()}${input.slice(1)}`;
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
function trimTrailingSeparator(input: string): string {
|
||||
if (/^[A-Za-z]:\\$/.test(input)) {
|
||||
return input;
|
||||
}
|
||||
|
||||
return input.replace(/[\\/]+$/, '');
|
||||
}
|
||||
|
||||
export function canonicalizeWindowsPath(input: string): string {
|
||||
const withBackslashes = input.replaceAll('/', '\\');
|
||||
const normalized = path.win32.normalize(withBackslashes);
|
||||
const withDriveCase = normalizeDriveLetter(normalized);
|
||||
return trimTrailingSeparator(withDriveCase);
|
||||
}
|
||||
|
||||
export function windowsPathKey(input: string): string {
|
||||
return canonicalizeWindowsPath(input).toLowerCase();
|
||||
}
|
||||
|
||||
export function toDisplayPath(input: string): string {
|
||||
return canonicalizeWindowsPath(input).replaceAll('\\', '/');
|
||||
}
|
||||
|
||||
export function sameWindowsPath(a: string, b: string): boolean {
|
||||
return windowsPathKey(a) === windowsPathKey(b);
|
||||
}
|
||||
61
src/lib/types.ts
Normal file
61
src/lib/types.ts
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
export const BEAD_STATUSES = [
|
||||
'open',
|
||||
'in_progress',
|
||||
'blocked',
|
||||
'deferred',
|
||||
'closed',
|
||||
'tombstone',
|
||||
'pinned',
|
||||
'hooked',
|
||||
] as const;
|
||||
|
||||
export type BeadStatus = (typeof BEAD_STATUSES)[number];
|
||||
|
||||
export const BEAD_DEPENDENCY_TYPES = [
|
||||
'blocks',
|
||||
'parent',
|
||||
'relates_to',
|
||||
'duplicates',
|
||||
'supersedes',
|
||||
'replies_to',
|
||||
] as const;
|
||||
|
||||
export type BeadDependencyType = (typeof BEAD_DEPENDENCY_TYPES)[number];
|
||||
|
||||
export const CORE_ISSUE_TYPES = ['task', 'bug', 'feature', 'epic', 'chore'] as const;
|
||||
|
||||
export type CoreIssueType = (typeof CORE_ISSUE_TYPES)[number];
|
||||
export type BeadIssueType = CoreIssueType | (string & {});
|
||||
|
||||
export interface BeadDependency {
|
||||
type: BeadDependencyType;
|
||||
target: string;
|
||||
}
|
||||
|
||||
export interface BeadIssue {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string | null;
|
||||
status: BeadStatus;
|
||||
priority: number;
|
||||
issue_type: BeadIssueType;
|
||||
assignee: string | null;
|
||||
owner: string | null;
|
||||
labels: string[];
|
||||
dependencies: BeadDependency[];
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
closed_at: string | null;
|
||||
close_reason: string | null;
|
||||
closed_by_session: string | null;
|
||||
created_by: string | null;
|
||||
due_at: string | null;
|
||||
estimated_minutes: number | null;
|
||||
external_ref: string | null;
|
||||
metadata: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface ParseableBeadIssue extends Partial<BeadIssue> {
|
||||
id: string;
|
||||
title: string;
|
||||
}
|
||||
30
tests/bootstrap.test.mjs
Normal file
30
tests/bootstrap.test.mjs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
|
||||
const requiredFiles = [
|
||||
'package.json',
|
||||
'tsconfig.json',
|
||||
'next.config.ts',
|
||||
'src/app/layout.tsx',
|
||||
'src/app/page.tsx',
|
||||
];
|
||||
|
||||
test('bootstrap scaffold files exist', () => {
|
||||
for (const file of requiredFiles) {
|
||||
assert.equal(fs.existsSync(file), true, `missing file: ${file}`);
|
||||
}
|
||||
});
|
||||
|
||||
test('package.json has next/react/typescript scripts and deps', () => {
|
||||
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
|
||||
|
||||
assert.equal(pkg.dependencies.next?.startsWith('15'), true, 'next@15 required');
|
||||
assert.equal(pkg.dependencies.react?.startsWith('19'), true, 'react@19 required');
|
||||
assert.equal(pkg.dependencies['react-dom']?.startsWith('19'), true, 'react-dom@19 required');
|
||||
assert.equal(pkg.devDependencies.typescript?.length > 0, true, 'typescript required');
|
||||
assert.equal(typeof pkg.scripts.dev, 'string', 'dev script required');
|
||||
assert.equal(typeof pkg.scripts.build, 'string', 'build script required');
|
||||
assert.equal(typeof pkg.scripts.start, 'string', 'start script required');
|
||||
assert.equal(typeof pkg.scripts.typecheck, 'string', 'typecheck script required');
|
||||
});
|
||||
9
tests/guards/no-direct-jsonl-write.test.mjs
Normal file
9
tests/guards/no-direct-jsonl-write.test.mjs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
import { scanForDirectIssuesJsonlWrites } from '../../tools/guardrails/no-direct-jsonl-write.mjs';
|
||||
|
||||
test('source tree contains no direct write calls targeting .beads/issues.jsonl', () => {
|
||||
const violations = scanForDirectIssuesJsonlWrites('src');
|
||||
assert.deepEqual(violations, []);
|
||||
});
|
||||
51
tests/lib/parser.test.ts
Normal file
51
tests/lib/parser.test.ts
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
import { parseIssuesJsonl } from '../../src/lib/parser';
|
||||
|
||||
test('parseIssuesJsonl applies defaults and preserves priority 0', () => {
|
||||
const input = [
|
||||
JSON.stringify({ id: 'bb-1', title: 'One', priority: 0 }),
|
||||
JSON.stringify({ id: 'bb-2', title: 'Two' }),
|
||||
].join('\n');
|
||||
|
||||
const result = parseIssuesJsonl(input);
|
||||
|
||||
assert.equal(result.length, 2);
|
||||
assert.equal(result[0].priority, 0);
|
||||
assert.equal(result[0].status, 'open');
|
||||
assert.equal(result[0].issue_type, 'task');
|
||||
assert.equal(result[1].priority, 2);
|
||||
});
|
||||
|
||||
test('parseIssuesJsonl skips malformed and blank lines', () => {
|
||||
const input = [' ', '{bad json', JSON.stringify({ id: 'bb-3', title: 'Three' })].join('\n');
|
||||
|
||||
const result = parseIssuesJsonl(input);
|
||||
|
||||
assert.equal(result.length, 1);
|
||||
assert.equal(result[0].id, 'bb-3');
|
||||
});
|
||||
|
||||
test('parseIssuesJsonl filters tombstones by default', () => {
|
||||
const input = [
|
||||
JSON.stringify({ id: 'bb-4', title: 'Live', status: 'open' }),
|
||||
JSON.stringify({ id: 'bb-5', title: 'Gone', status: 'tombstone' }),
|
||||
].join('\n');
|
||||
|
||||
const result = parseIssuesJsonl(input);
|
||||
|
||||
assert.equal(result.length, 1);
|
||||
assert.equal(result[0].id, 'bb-4');
|
||||
});
|
||||
|
||||
test('parseIssuesJsonl can include tombstones when requested', () => {
|
||||
const input = [
|
||||
JSON.stringify({ id: 'bb-4', title: 'Live', status: 'open' }),
|
||||
JSON.stringify({ id: 'bb-5', title: 'Gone', status: 'tombstone' }),
|
||||
].join('\n');
|
||||
|
||||
const result = parseIssuesJsonl(input, { includeTombstones: true });
|
||||
|
||||
assert.equal(result.length, 2);
|
||||
});
|
||||
30
tests/lib/pathing.test.ts
Normal file
30
tests/lib/pathing.test.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
import {
|
||||
canonicalizeWindowsPath,
|
||||
windowsPathKey,
|
||||
toDisplayPath,
|
||||
sameWindowsPath,
|
||||
} from '../../src/lib/pathing';
|
||||
|
||||
test('canonicalizeWindowsPath normalizes separators and drive casing', () => {
|
||||
const input = 'c:/Users/Zenchant/codex/beadboard/';
|
||||
const result = canonicalizeWindowsPath(input);
|
||||
assert.equal(result, 'C:\\Users\\Zenchant\\codex\\beadboard');
|
||||
});
|
||||
|
||||
test('windowsPathKey is case-insensitive stable key', () => {
|
||||
const a = windowsPathKey('C:/Users/Zenchant/codex/beadboard');
|
||||
const b = windowsPathKey('c:\\users\\zenchant\\codex\\beadboard\\');
|
||||
assert.equal(a, b);
|
||||
});
|
||||
|
||||
test('toDisplayPath renders forward slashes for UI readability', () => {
|
||||
const display = toDisplayPath('C:\\Users\\Zenchant\\codex\\beadboard');
|
||||
assert.equal(display, 'C:/Users/Zenchant/codex/beadboard');
|
||||
});
|
||||
|
||||
test('sameWindowsPath handles case/separator differences', () => {
|
||||
assert.equal(sameWindowsPath('D:/Repos/One', 'd:\\repos\\one\\'), true);
|
||||
});
|
||||
49
tests/types/beads-types-contract.ts
Normal file
49
tests/types/beads-types-contract.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import type {
|
||||
BeadIssue,
|
||||
BeadStatus,
|
||||
BeadDependencyType,
|
||||
BeadIssueType,
|
||||
BeadDependency,
|
||||
ParseableBeadIssue,
|
||||
} from '../../src/lib/types';
|
||||
|
||||
const status: BeadStatus = 'open';
|
||||
const depType: BeadDependencyType = 'blocks';
|
||||
const issueType: BeadIssueType = 'task';
|
||||
|
||||
const dependency: BeadDependency = {
|
||||
type: depType,
|
||||
target: 'bb-123',
|
||||
};
|
||||
|
||||
const issue: BeadIssue = {
|
||||
id: 'bb-123',
|
||||
title: 'Test issue',
|
||||
status,
|
||||
priority: 0,
|
||||
issue_type: issueType,
|
||||
description: 'schema contract',
|
||||
assignee: 'agent',
|
||||
owner: 'owner@example.com',
|
||||
labels: ['test'],
|
||||
dependencies: [dependency],
|
||||
created_at: '2026-02-12T00:00:00Z',
|
||||
updated_at: '2026-02-12T00:00:00Z',
|
||||
closed_at: null,
|
||||
close_reason: null,
|
||||
closed_by_session: null,
|
||||
created_by: 'zenchantlive',
|
||||
due_at: null,
|
||||
estimated_minutes: null,
|
||||
external_ref: null,
|
||||
metadata: {},
|
||||
};
|
||||
|
||||
const parseable: ParseableBeadIssue = {
|
||||
id: issue.id,
|
||||
title: issue.title,
|
||||
};
|
||||
|
||||
if (!parseable.id || !parseable.title) {
|
||||
throw new Error('invalid parseable issue contract');
|
||||
}
|
||||
64
tools/guardrails/no-direct-jsonl-write.mjs
Normal file
64
tools/guardrails/no-direct-jsonl-write.mjs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
const WRITE_APIS = [
|
||||
'writeFile',
|
||||
'writeFileSync',
|
||||
'appendFile',
|
||||
'appendFileSync',
|
||||
'createWriteStream',
|
||||
];
|
||||
|
||||
function listFilesRecursive(dir) {
|
||||
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
||||
const files = [];
|
||||
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(dir, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
files.push(...listFilesRecursive(fullPath));
|
||||
} else if (/\.(ts|tsx|js|mjs|cjs)$/i.test(entry.name)) {
|
||||
files.push(fullPath);
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
function findLineNumber(source, index) {
|
||||
const prefix = source.slice(0, index);
|
||||
return prefix.split(/\r?\n/).length;
|
||||
}
|
||||
|
||||
export function scanForDirectIssuesJsonlWrites(rootDir) {
|
||||
if (!fs.existsSync(rootDir)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const files = listFilesRecursive(rootDir);
|
||||
const violations = [];
|
||||
|
||||
for (const filePath of files) {
|
||||
const source = fs.readFileSync(filePath, 'utf8');
|
||||
const lowered = source.toLowerCase();
|
||||
|
||||
if (!lowered.includes('issues.jsonl')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const api of WRITE_APIS) {
|
||||
const regex = new RegExp(`${api}\\s*\\([\\s\\S]{0,300}?issues\\.jsonl`, 'gi');
|
||||
let match = regex.exec(source);
|
||||
while (match) {
|
||||
violations.push({
|
||||
file: filePath.replaceAll('\\\\', '/'),
|
||||
line: findLineNumber(source, match.index),
|
||||
snippet: match[0].slice(0, 160),
|
||||
});
|
||||
match = regex.exec(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return violations;
|
||||
}
|
||||
20
tsconfig.json
Normal file
20
tsconfig.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"lib": ["dom", "dom.iterable", "es2022"],
|
||||
"allowJs": false,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [{ "name": "next" }]
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue