feat: bootstrap CLI and shared @atbb/atproto package (#41)
* docs: bootstrap CLI design for first-time forum setup
Adds design document for `atbb init` CLI command that automates
forum bootstrapping — creating the forum record on the PDS, seeding
default roles, and assigning the first Owner. Includes extraction
of ForumAgent into shared `packages/atproto` package.
* docs: bootstrap CLI implementation plan
12-task TDD implementation plan for atbb init command. Covers
packages/atproto extraction, packages/cli scaffolding, bootstrap
steps (create-forum, seed-roles, assign-owner), and Dockerfile updates.
* feat: extract @atbb/atproto shared package with error helpers
Create packages/atproto as a shared AT Protocol utilities package.
Extract error classification helpers (isProgrammingError, isNetworkError,
isAuthError, isDatabaseError) from appview into the shared package,
consolidating patterns from errors.ts and forum-agent.ts. The appview
errors.ts becomes a re-export shim for backward compatibility.
* refactor: move ForumAgent to @atbb/atproto shared package
Move ForumAgent class and tests from appview to packages/atproto.
Replace inline isAuthError/isNetworkError with imports from errors.ts.
Add ETIMEDOUT pattern to isNetworkError for Node.js socket errors.
Update app-context.ts import and app-context test mock path.
* feat: add identity resolution helper to @atbb/atproto
Add resolveIdentity() that accepts either a DID (returns as-is) or a
handle (resolves via PDS resolveHandle). Used by the CLI to let
operators specify the forum owner by handle or DID.
* chore: scaffold @atbb/cli package with citty
* feat(cli): add config loader and preflight environment checks
* feat(cli): implement create-forum bootstrap step
* feat(cli): implement seed-roles bootstrap step
* feat(cli): implement assign-owner bootstrap step
* feat(cli): wire up init command with interactive prompts and flag overrides
* chore: update Dockerfile to include atproto and cli packages
* fix(cli): make config test hermetic for CI environment
Explicitly stub env vars to empty strings instead of relying on a clean
environment. CI sets DATABASE_URL for its PostgreSQL service container,
so vi.unstubAllEnvs() alone is insufficient — it only reverses previous
stubs, not real env vars.
* fix(cli): address code review feedback on bootstrap flow
1. Fix bootstrap ordering: seedDefaultRoles now inserts into DB after
PDS write, so assignOwnerRole can find the Owner role immediately
without waiting for the firehose.
2. Fix membership ownership: assignOwnerRole no longer writes to the
forum DID's PDS repo (wrong owner per data model). Instead, inserts
membership directly into DB. The PDS record will be created when the
user logs in via OAuth.
3. Fix bare catch in createForumRecord: now discriminates RecordNotFound
from network/auth/programming errors. Only proceeds to create when
the record genuinely doesn't exist.
4. Remove fabricated cid:"pending": no longer writes PDS records with
fake CIDs. Direct DB inserts use "bootstrap" sentinel to indicate
CLI-created records.
5. Fix DB connection leak: init command creates postgres client directly
and calls sql.end() on all exit paths (success + error).
Also: createForumRecord now inserts forum into DB after PDS write,
ensuring downstream steps can reference it.
* fix: upgrade bootstrap memberships to real PDS records on first login
When the CLI creates a bootstrap membership (cid="bootstrap"), the
appview now detects it on first OAuth login and upgrades it by writing
a real PDS record to the user's repo, then updating the DB row with
the actual rkey/cid while preserving the roleUri.