From 696a30051be54fc5b36a34c09e2f76b272677c17 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 10 Feb 2026 02:35:24 +0000 Subject: [PATCH 1/2] Fix lint failures, console.* convention violations, and CI Node version mismatch - Add docs/capacitor-native-app-plan.md to hex-lint ignore list (code examples naturally reference hex colors in Capacitor config) - Replace direct console.error/console.log calls with logger utility in historyView.js, profileCache.js, EventDetailsModal.js, ZapInterface.js, and notificationController.js - Update CI workflow from Node 20 to Node 22 to match package.json engines https://claude.ai/code/session_01LzErpH9FNw4hAPsjoYb1v9 --- .github/workflows/ci.yml | 10 +++++----- js/historyView.js | 4 ++-- js/state/profileCache.js | 2 +- js/ui/components/EventDetailsModal.js | 5 +++-- js/ui/dm/ZapInterface.js | 3 ++- js/ui/notificationController.js | 6 ++++-- scripts/check-hex.js | 3 ++- 7 files changed, 19 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 61f888f9..b6ce5e3f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: timeout-minutes: 45 strategy: matrix: - node-version: [20] + node-version: [22] steps: - name: Check out repository @@ -85,7 +85,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [20] + node-version: [22] shard: [1, 2, 3] steps: @@ -128,7 +128,7 @@ jobs: timeout-minutes: 20 strategy: matrix: - node-version: [20] + node-version: [22] steps: - name: Check out repository @@ -168,7 +168,7 @@ jobs: timeout-minutes: 30 strategy: matrix: - node-version: [20] + node-version: [22] steps: - name: Check out repository @@ -208,7 +208,7 @@ jobs: timeout-minutes: 45 strategy: matrix: - node-version: [20] + node-version: [22] steps: - name: Check out repository diff --git a/js/historyView.js b/js/historyView.js index 4adda743..3e052fa4 100644 --- a/js/historyView.js +++ b/js/historyView.js @@ -2154,7 +2154,7 @@ export function createWatchHistoryRenderer(config = {}) { if (typeof app?.showSuccess === "function") { app.showSuccess("Local watch history reset."); } else { - console.log("Local watch history reset."); + userLogger.info("[historyView] Local watch history reset."); } } catch (error) { const message = @@ -2165,7 +2165,7 @@ export function createWatchHistoryRenderer(config = {}) { if (typeof app?.showError === "function") { app.showError(message); } else { - console.error(message); + userLogger.error("[historyView]", message); } } }; diff --git a/js/state/profileCache.js b/js/state/profileCache.js index 14317b8b..8c13d1ae 100644 --- a/js/state/profileCache.js +++ b/js/state/profileCache.js @@ -414,7 +414,7 @@ class ProfileCache { try { listener(event, detail); } catch (error) { - console.error("[ProfileCache] Listener error", error); + userLogger.error("[ProfileCache] Listener error", error); } } } diff --git a/js/ui/components/EventDetailsModal.js b/js/ui/components/EventDetailsModal.js index c8c35dd2..56e10dc4 100644 --- a/js/ui/components/EventDetailsModal.js +++ b/js/ui/components/EventDetailsModal.js @@ -1,5 +1,6 @@ import { prepareStaticModal, openStaticModal, closeStaticModal } from "./staticModalAccessibility.js"; import { sanitizeProfileMediaUrl } from "../../utils/profileMedia.js"; +import { devLogger } from "../../utils/logger.js"; const DEFAULT_PROFILE_AVATAR = "assets/svg/default-profile.svg"; @@ -334,7 +335,7 @@ export class EventDetailsModal { } }) .catch((error) => { - console.error( + devLogger.error( "[EventDetailsModal] Failed to fetch raw event:", error, ); @@ -441,7 +442,7 @@ export class EventDetailsModal { } } } catch (e) { - console.error("Failed to load history", e); + devLogger.error("[EventDetailsModal] Failed to load history", e); } finally { this.isLoadingHistory = false; this.updateNavigationState(); diff --git a/js/ui/dm/ZapInterface.js b/js/ui/dm/ZapInterface.js index eb3a3ed6..dd54bb30 100644 --- a/js/ui/dm/ZapInterface.js +++ b/js/ui/dm/ZapInterface.js @@ -1,5 +1,6 @@ import { ZapReceiptList } from "./ZapReceiptList.js"; import { createAndPublishZapRequest, resolveZapRecipient } from "../../payments/zapRequests.js"; +import { userLogger } from "../../utils/logger.js"; function createElement(doc, tag, className, text) { const element = doc.createElement(tag); @@ -91,7 +92,7 @@ export function createZapInterface(doc, { contact, zapReceipts, onSendZap, zapCo throw new Error("No signer available"); } } catch (err) { - console.error(err); + userLogger.error("[ZapInterface] Failed to send zap:", err); statusDiv.textContent = "Failed to send zap"; statusDiv.className = "text-error text-xs text-center mt-1"; } finally { diff --git a/js/ui/notificationController.js b/js/ui/notificationController.js index 9b1d6d2f..5e86b8e0 100644 --- a/js/ui/notificationController.js +++ b/js/ui/notificationController.js @@ -1,3 +1,5 @@ +import { userLogger as _fallbackUserLogger, devLogger as _fallbackDevLogger } from "../utils/logger.js"; + export default class NotificationController { constructor({ portal, @@ -16,8 +18,8 @@ export default class NotificationController { this.statusContainer?.querySelector("[data-status-message]") || null; // Fallback loggers if not provided - this.userLogger = loggers.userLogger || { error: console.error, warn: console.warn, log: console.log, info: console.info }; - this.devLogger = loggers.devLogger || { error: console.error, warn: console.warn, log: console.log, info: console.info }; + this.userLogger = loggers.userLogger || _fallbackUserLogger; + this.devLogger = loggers.devLogger || _fallbackDevLogger; this.document = documentRef; this.window = windowRef; diff --git a/scripts/check-hex.js b/scripts/check-hex.js index 226d2a56..ee1a56b3 100755 --- a/scripts/check-hex.js +++ b/scripts/check-hex.js @@ -34,7 +34,8 @@ const IGNORED_GLOBS = [ '**/*.ai', 'releases/**', 'bitvid-working-webtorrent/**', - 'scripts/agent/**' + 'scripts/agent/**', + 'docs/capacitor-native-app-plan.md' ]; const gitArgs = [ From 1ebfefe9c8df856c60e35b794a8c21aaf9ffaeeb Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 10 Feb 2026 02:44:35 +0000 Subject: [PATCH 2/2] Add multi-agent coordination guide to AGENTS.md and CLAUDE.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AGENTS.md Section 12: subsystem boundary table, PR discipline rules, in-flight work reservation section, and signaling conventions for parallel AI agent workflows (Claude Code, Codex, Jules) - CLAUDE.md: document the unstable→beta→main promotion pipeline, add multi-agent workflow section with coordination rules for both agents and human maintainers, fix Node.js version reference (20→22) https://claude.ai/code/session_01LzErpH9FNw4hAPsjoYb1v9 --- AGENTS.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ CLAUDE.md | 49 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 95 insertions(+), 4 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 74420a57..6239f8fa 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -199,6 +199,56 @@ When moving a feature to a controller, follow these steps: --- +## 12. Multi-Agent Coordination + +This project uses multiple AI agents (Claude Code, OpenAI Codex, Google Jules) working in parallel. Without coordination, agents will create conflicting PRs, duplicate work, and cause painful merge conflicts. Follow these rules to keep things clean. + +### Before Starting Work + +1. **Check open PRs.** Run `gh pr list --state open` or check GitHub. If another agent already has a PR touching the same files or subsystem, do not create a competing PR. Instead, note the conflict and ask the maintainer how to proceed. +2. **Check this section for in-flight work.** The maintainer may list active work areas below. Respect these reservations. +3. **Read KNOWN_ISSUES.md.** Do not open PRs to fix issues already documented there unless explicitly asked. + +### Subsystem Boundaries + +To minimize merge conflicts, treat these as independent work zones. An agent should avoid touching files outside its assigned zone in a single PR: + +| Zone | Key Files | Description | +|------|-----------|-------------| +| **Nostr Core** | `js/nostr/client.js`, `js/nostr/adapters/`, `js/nostrClientFacade.js` | Protocol client, signers, relay management | +| **Event Schemas** | `js/nostrEventSchemas.js`, `docs/nostr-event-schemas.md` | Event definitions and documentation | +| **Playback** | `js/services/playbackService.js`, `js/playbackUtils.js`, `js/magnetUtils.js` | Video streaming, magnet handling | +| **UI Controllers** | `js/ui/` | Modal controllers, notification, components | +| **State** | `js/state/` | Profile cache, application state | +| **DMs** | `js/ui/dm/`, `js/nostr/dm/` | Direct messaging subsystem | +| **Moderation** | `js/moderation/`, `docs/moderation/` | Content moderation, reports, admin lists | +| **Build & CI** | `.github/workflows/`, `scripts/`, `tailwind.config.cjs` | CI pipeline, lint scripts, build tooling | +| **Styling** | `css/tokens.css`, `css/tailwind.source.css` | Design tokens and Tailwind source | +| **App Orchestrator** | `js/app.js`, `js/app/` | Main app wiring (high conflict risk — only one PR at a time) | + +**`js/app.js` is the highest-risk file.** It wires everything together. Never have two agent PRs modifying it simultaneously. + +### PR Discipline + +- **One subsystem per PR.** A PR that touches Nostr Core and UI Controllers is two PRs. Split them. +- **Small and mergeable.** Target PRs that can be reviewed in one sitting. If a refactor spans 10+ files, break it into sequential PRs. +- **Merge before branching.** Before starting new work on a subsystem, ensure all open PRs for that subsystem are merged or closed. +- **Rebase, don't stack.** Long-lived branches diverge fast with multiple agents. Rebase onto `unstable` frequently. + +### Signaling Work to Other Agents + +When you create a PR or start work, leave a clear signal: +- **PR title prefix**: Use a descriptive prefix like `[nostr-core]`, `[playback]`, `[ui]`, `[ci]` so the scope is visible at a glance. +- **PR description**: Include a "Files Modified" section listing the key files touched, so other agents can quickly detect conflicts. + +### Currently In-Flight Work + + + +_No reservations currently active._ + +--- + ## Next Please read these documents next. diff --git a/CLAUDE.md b/CLAUDE.md index e64cecf9..eb3f8d22 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,7 +13,7 @@ This document provides context and guidance for AI assistants working with the b - **WebTorrent**: P2P video streaming fallback - **Tailwind CSS**: Utility-first styling with custom design tokens - **Playwright**: E2E and visual regression testing -- **Node.js 20+**: Development environment +- **Node.js 22+**: Development environment ### License GPL-3.0-or-later (see `LICENSE`) @@ -383,10 +383,25 @@ rm css/tailwind.generated.css && npm run build:css --- -## Release Channels +## Release Channels & Promotion Pipeline -- **Main**: Production track — preserve UX, atomic commits, feature flags default off -- **Unstable**: Experimentation — gate risky features behind flags +Code flows through three branches with increasing stability: + +``` +unstable → beta → main + (dev) (soak) (prod) +``` + +| Branch | Purpose | CI Required | Manual QA | +|--------|---------|-------------|-----------| +| `unstable` | Active development, AI agent PRs land here | Yes | No | +| `beta` | Stabilization soak (hosted for testing) | Yes | Yes — hosted domain | +| `main` | Production | Yes | Verified via beta | + +**Promotion rules:** +- `unstable → beta`: After a batch of improvements passes CI and local testing +- `beta → main`: After weeks of soak time on the beta hosted domain with no regressions +- Never push directly to `main` or `beta` — always promote from the previous stage ### Emergency Response @@ -397,6 +412,32 @@ If a change breaks playback or magnet handling: --- +## Multi-Agent Development Workflow + +This project uses multiple AI coding agents working in parallel: +- **Claude Code** — Refactoring, convention enforcement, codebase-wide changes +- **OpenAI Codex** — Isolated feature implementation with clear specs +- **Google Jules** — Issue triage and straightforward bug fixes + +### Coordination Rules + +All agents **must** follow the subsystem boundaries and PR discipline rules in `AGENTS.md` Section 12. The key principles: + +1. **Check before you start.** Look at open PRs (`gh pr list`) before beginning work. If another agent has an open PR touching the same files, stop and flag the conflict. +2. **One subsystem per PR.** Don't mix unrelated changes. A lint fix and a feature addition are two separate PRs. +3. **`js/app.js` is single-writer.** Only one PR at a time should modify the main orchestrator. +4. **Merge fast, branch short.** Long-lived branches cause exponential merge pain with multiple agents. Keep PRs small and mergeable in one sitting. + +### For Human Maintainers + +When assigning work to agents: +- Update the "Currently In-Flight Work" section in `AGENTS.md` to reserve subsystems +- Avoid sending two agents at the same subsystem simultaneously +- Review and merge agent PRs promptly to keep the queue short — stale PRs compound conflicts +- Use PR title prefixes (`[nostr-core]`, `[ui]`, `[playback]`, etc.) to make scope visible + +--- + ## Key Documentation | Document | What It Covers |