CLAUDE.md · diff

git:20261010.7dc4715 to git:20261010.c49ded1

1 added, 209 removed. Audit A to B.

- # The Cockpit That Drives AI
-
- ## Development
-
- - **Dev Server Port**: 3456 (run `npm run dev`)
- - **Tech Stack**: Next.js 16, React, TypeScript, TailwindCSS
- - **Isolating an instance**: `COCKPIT_HOME=~/.cockpit-dev npm run dev` points
- the whole data dir (config, projects, history) somewhere else — use it rather
- than testing against a live `~/.cockpit`. Note that only ONE dev server can
- run per repo checkout (Next holds a lock on `.next/`), so `PORT` alone does
- not buy a second instance; a running prod `cockpit` also refuses a second
- boot unless isolated this way.
-
- ## UI Layout
-
- - **Three-panel swipe mode**: Uses `SwipeableViewContainer` (translateX) to place three panels side by side, with left/right swipe to switch:
- - Panel 1 **Agent** (Chat)
- - Panel 2 **Explorer** (File browser)
- - Panel 3 **Console** (Terminal + browser bubbles)
- - **All three panels are always rendered simultaneously**; switching panels is just a CSS transform translation — components are never unmounted/remounted
- - **UI component considerations**: When building menus, modals, and floating popovers, be mindful of the three-panel layout:
- - Positioning calculations must account for the boundaries of the current panel
- - z-index levels must be managed consistently
- - Prevent components from overflowing into adjacent panels
-
- ## React Performance Conventions
-
- All three panels + every open chat tab stay mounted, so one state change (session
- switch, WS push, terminal tick) re-renders large sibling subtrees. Props to a
- `memo`'d heavy renderer (chat `MessageBubble`, Explorer previews, Console bubbles)
- must be **referentially stable** — one unstable prop silently defeats the `memo`:
-
- - Callbacks → `useCallback`; if a dep churns every render (`fileTree`, live
- `sessionId`), use a ref indirection so the passed-down identity never changes.
- - Objects/arrays (e.g. `extra={{…}}`) → `useMemo`. Inside `.map()` extract a
- `memo`'d row (see `ConsoleBubbleRow`) fed stable callbacks + per-item booleans.
- - Expensive per-render work → `useMemo([content])`; never parse/format an
- O(document) blob inline in JSX.
-
- ## Effect Conventions
-
- All IO / side-effects / dependencies / errors go through the
- `Effect<A, E, R>` paradigm. See **`EFFECT.md`** for the full contract:
- - Tagged Error types (DBError / WSError / FSError / AgentError / ...)
- - Service Tag + Layer.scoped templates for connection pools / subprocesses
- - API route / WebSocket handler templates
- - React bridging (`useEffectQuery` / `BrowserRuntime.runPromise`)
- - `Effect.withSpan` / `CockpitConfig` / Logger conventions
- - Server vs Browser bundle boundary rules
-
- When adding any new IO operation (HTTP route, DB query, WS handler,
- client-side fetch), **first match a template in EFFECT.md §3-§7**; do not
- write raw `fetch` / `try-catch` / `setInterval` in business code.
-
- ## Project Structure
-
- Business code lives in `packages/`; `src/` is intentionally minimal
- framework boot. See `MODULES.md` for the dependency rules.
-
- - `/src/app/` - Next.js routing only (page.tsx + layout.tsx + one-line
- `route.ts` shims that re-export from feature packages)
- - `/src/lib/` - Server bootstrap: `wsServer.ts` (WS server),
- `fileWatcher.ts` (fs watcher)
- - `/packages/feature/` - Self-contained domain features:
- - `agent/` - Chat domain (Claude/Ollama/Codex/Kimi/DeepSeek/GLM), scheduled
- tasks, slash commands, sidebar panels, tool-call snapshots (shadow git
- per project under `~/.cockpit/snapshots/`, per-call diff viewer)
- - `comments/` - Code annotation API + hooks
- - `console/` - Terminal + browser bubbles + DB bubbles (Postgres / MySQL
- / Redis / Neo4j / MongoDB / Bash)
- - `explorer/` - File browser + code rendering (DiffView, CodeViewer,
- InteractiveMarkdownPreview, PreviewModal) + git + LSP
- - `skills/` - SKILL.md parser + slash autocomplete + cross-frame bus
- - `workspace/` - Application integrator (Workspace, TabManager,
- Providers, SettingsModal, NoteModal, SessionBrowser)
- - `/packages/shared/` - Cross-feature infrastructure:
- - `i18n/` - Translation dictionary + i18next singleton
- - `ui/` - UI primitives (Toast, MarkdownRenderer, Tooltip,
- codeHighlighter, Swipeable*, useViMode, useWebSocket, …)
- - `utils/` - Pure utilities (paths, ollamaEnv, platform, shortId)
- - `/apps/` - Built-in HTML apps (`file-viewer/`). Deliberately NOT under
- `public/` — they are served by a route so the bash SDK can be injected
- (see **HTML Apps Runtime**)
- - `/public/html-lib/` - Same-origin hosted frontend libs for HTML apps
- (React, ReactDOM, Babel, `theme.css`, and the standalone
- markdown / json / csv / pdf widget bundles). Regenerated by
- `scripts/build-html-lib.mjs` on every `predev` / `prebuild`
- - `/skills/` - Builtin slash-command prompts, one `SKILL.md` per command
- (`/qa`, `/cr`, …). English only, **no TypeScript involved**: the directory
- set IS the registry — both dispatch (`slashCommands.ts`) and the
- autocomplete route read it, so adding a command is `mkdir skills/<cmd>` +
- one file. Shipped in `package.json#files`, so anything added here lands in
- the npm package. Project-internal playbooks go in `/docs/skills/` instead.
- - `/chrome-extension/` - Chrome extension (Manifest V3, independent
- sub-project)
- - `/bin/` - CLI entry points (`cockpit.mjs`, `postinstall.mjs`)
-
- ## HTML Apps Runtime
-
- Two address spaces, one route
- (`packages/feature/explorer/src/server/api/apps.ts`):
-
- - `/apps/builtin/<name>/index.html` — apps shipped in `/apps/`
- - `/apps/local/<abs path>` — any file on this machine; this is also the
- plain local-file server (relative sub-resources, images, css)
-
- **SDK injection has no marker**: every `.html` served by this route gets
- `window.cockpit`. Nothing to opt into, nothing to forget. `cockpit-name` is
- purely a registry concern (panel card + `/name`) and has no bearing on what
- runs.
-
- **Do not add a marker back.** Two earlier designs gated injection on one (a URL
- flag, then a meta tag) and both failed silently — the header comment in
- `apps.ts` records how, so the mistake isn't repeated.
-
- Making it unconditional is free because **injection was never a security
- boundary**: any page served here is same-origin and can open its own WebSocket
- to `/ws/bash` regardless. **The real gate is the same-origin check on that
- upgrade** (`src/lib/wsServer.ts`), which means the security decision is *what
- you choose to preview*, not what we inject.
-
- Say the consequence out loud when working here: **previewing any local `.html`
- runs it**, with full shell access. The iframe carries no `sandbox` attribute
- (matching the console browser bubble), so a previewed page can also navigate
- the whole Cockpit window away. Surfaces that preview unreviewed content — e.g.
- a `.html` straight out of a git diff — are making that call for the user.
-
- When working in this area:
-
- - **Built-in apps must only use capabilities user apps have** —
- `window.cockpit.bash`, `/html-lib/*`, and the `cockpit-*` meta tags. No
- privileged endpoints, no internal postMessage protocols. They double as the
- reference implementations for the `/html` skill, so a shortcut taken here
- becomes advice users cannot follow.
- - **Root-relative paths 404** except `/html-lib/*` and `/apps/*`, which the
- server hosts. Same-level relative refs (`./app.jsx`) and CDN URLs resolve
- normally.
- - **Markdown images**: rewrite relative srcs to `/apps/local/<abs>`, never to
- `data:` URLs — react-markdown's `defaultUrlTransform` drops every protocol
- outside http/https/mailto/xmpp, silently leaving the `<img>` with no `src`
- at all, in both the `![](…)` and raw-HTML forms.
- - **Never hand-assemble these URLs.** The builders and their reverse
- (`toLocalAppUrl` / `toFileViewerUrl` / `fromLocalAppUrl`, plus the per-segment
- encoding Windows paths depend on) live in
- `packages/shared/utils/src/htmlBashSdk.ts`.
- - Directory URLs hit Next's trailingSlash redirect, after which the shell's
- relative `./app.jsx` fetch resolves one level too high and 404s — always
- spell out `index.html`.
-
- ## Key Features
-
- - File browser with virtual scrolling and syntax highlighting (Shiki)
- - Git status and history integration
- - Per-tool-call project snapshots (shadow git per cwd, one commit per
- mutating tool call, 7-day retention; message FileDiff icon opens the
- per-call diff viewer)
- - Git blame view
- - Code search with Cmd+F (case sensitive / whole word matching)
- - ESC key exits blame view first, then closes modal (3s debounce)
-
- ## Commands
-
- ```bash
- npm run dev # Start dev server on port 3456
- npm run build # Build for production
- npm run setup # Build + npm link
- npm run lint # Run ESLint
- cockpit # Start production server on port 3457 (prefer this — primary entry)
- cockpit-dev # Start dev server on port 3456 (dev only; no short alias)
- cockpit -v # Show version
- ```
-
- ## npm Publish
-
- Publishing is done via GitHub Actions — **never publish locally with `npm publish`**.
-
- ```bash
- npm version patch # Bump version (patch/minor/major)
- git push origin main # Push commit
- git push origin v<version> # Push tag → triggers CI publish
- ```
-
- The `v*` tag push triggers `.github/workflows/publish.yml` which:
- 1. Builds the project
- 2. Publishes to npm (`@surething/cockpit`) with provenance
- 3. Creates a GitHub Release with auto-generated notes
-
- ## Project Characteristics
-
- - **Purely local application**: All API request latency is under 10ms
- - **No API caching needed**: Local requests are fast enough that caching provides negligible performance gains while introducing data consistency issues
-
- ## Claude Code Usage Guidelines
-
- - **Browser testing**: Use `evaluate_script` for DOM manipulation; avoid `take_screenshot` (consumes excessive tokens)
- - **Minimize screenshots**: Only take screenshots when visual confirmation is truly needed
- - **MCP tools**: Do not use MCP tools unless the user explicitly requests it (e.g., "use xxx")
- - **Git commits**: Do not auto-commit code; only commit when the user explicitly says "commit"
- - **English everywhere in code**: Write commit messages (subject and body), code comments, and CLI/console log output entirely in English; Chinese may appear only in quoted literals (e.g. UI copy, example prompts). Conversation replies stay in Chinese
-
- <!-- cdd:begin -->
- ## cdd (Constraint-Driven Development)
-
- - Constraints live in `constraints/`. Changing one is a constraint change and needs human review; never weaken a constraint to make a check pass.
- - cdd config lives in `.cdd/` (hidden directory): `config.json` and `baseline.json` decide how changes are judged. Editing them is a constraint change too — do not edit them to get a pass.
- - Before committing, run `cdd change` to classify the change as A/B/C/D. A type-D change (incident fix) must add a new constraint that fails before the fix.
- - Where checks run: local self-check (default) · commit hook · CI — same command in each. Which ones this repo actually wires up is defined by its own hook / CI config.
- <!-- cdd:end -->
-
+ AGENTS.md