Files

7.0 KiB

CLAUDE.md

Context for working on this repository. Feature-level detail lives in docs/features/ — read the relevant file there before changing a subsystem.

What this is

A Nova extension that launches and tracks Claude Code sessions for a project. Chat happens in a terminal, not in Nova. The extension prepares launch commands, lists the project's sessions, and manages the account behind them.

There is no bundled copy of Claude Code, no Node sidecar, no npm dependencies, and no network access of its own.

The extension used to drive the conversation itselfclaude --print over the stream-json protocol, rendered into a Markdown tab, with approvals, plan review and question answering in Nova panels. That was removed after real use: modal panels truncate long questions and lose their input when you click away. The implementation is preserved in commit 89d1a06; its transport notes and the editable-proposal flow are the starting point for the IDE bridge. Do not reintroduce panel-based chat.

Hard constraints (do not re-derive these)

Nova extension API

Constraint Consequence
No webview / HTML UI for extensions The chat surface is a Markdown tab, not a rendered view
Sidebar sections are TreeView only No text fields, forms, or the multi-line box Nova's own Source Control sidebar has
No WebSocket in the JS runtime The IDE bridge needs a Node sidecar
No terminal API Cannot create a terminal or send it text
No diff viewer API Diffs are rendered text; proposals are editable staged files
Cannot close tabs programmatically Never promise to clean up a tab
Can only read its own IssueCollection No access to other extensions' diagnostics
No multi-line input Long-form input = open a scratch document
Commands may only be placed in editor, extensions, command-palette, text No file-browser context menu
Untitled documents cannot be saved without a dialog Stage real files when a save gesture matters

The runtime is JavaScriptCore with fetch, Streams, TextEncoder/Decoder, setTimeout, nova.cryptonot Node. No require of npm packages; only relative require("./x.js") between Scripts/ files.

Type definitions worth having open: npm pack @types/nova-editor-node (it is a single index.d.ts, and is more precise than the website).

Claude Code CLI — the facts this extension relies on:

  1. Sessions are stored as ~/.claude/projects/<slug>/<session-id>.jsonl, where the slug is the project path with / and . flattened to -. This is the CLI's own store, so terminal-started sessions appear in the sidebar too.
  2. claude --resume <id> resumes from any terminal; --remote-control enables driving a session from elsewhere. Nothing extra is needed to support either — a launched session is an ordinary CLI session.
  3. claude auth status --json gives structured account state.

If you ever need to drive the CLI programmatically again, commit 89d1a06 documents the stream-json and control protocols in detail — including that --permission-prompt-tool stdio is required and undocumented, without which every permission-requiring tool is silently auto-denied.

Policy — do not implement claude.ai OAuth in this extension. Anthropic's Agent SDK terms bar third-party products from offering claude.ai login. Sign-in shells out to claude auth login. See authentication.

Layout

extension.json          manifest: sidebar, commands, config, entitlements
Scripts/
  main.js               Controller: lifecycle, commands, wiring
  launch.js             building and copying the launch command
  sessions-store.js     reading ~/.claude/projects
  sidebar.js            Status and Sessions TreeView providers
  auth.js               claude auth status/login/logout
  cli.js                binary resolution, environment, keychain
  util.js               conf, throttle, Signal, runCommand, processWriter
docs/features/          one file per capability; read before changing one

Conventions

  • 4-space indent, CommonJS, no build step, no dependencies.
  • Comments explain why, especially where a workaround encodes an API limitation. Several exist purely to stop a future reader "simplifying" a constraint back into a bug.
  • User-visible strings are sentence case and plain English; no jargon from the protocol leaks into the UI (friendlyToolName, modeLabel).
  • Config keys are namespaced claudenova.*; read them through util.conf(), which prefers the workspace value.

Testing

The extension has never been run inside Nova. Everything below is verified outside it; a first in-Nova run is still owed. Load it with:

nova extension validate .    # manifest + bundle (makes network calls — needs connectivity)
nova extension activate .    # load into Nova for development

Logs (nova.inDevMode() output) appear in Nova's Extension Console.

Node harness. The Nova API is stubbable, so the extension can be exercised under Node — including against real session files on disk. This caught several real bugs and is the highest-value testing move available:

global.Process = class { /* wrap child_process.spawn; onStdout/onStderr/onDidExit */ };
global.Range = class { constructor(start, end) { this.start = start; this.end = end; } };
global.nova = { environment: process.env, path, fs, workspace, extension, crypto,
                inDevMode: () => true, /* … */ };
const store = require("./Scripts/sessions-store.js");

Point nova.workspace.path at a directory that really has sessions, stub clipboard.writeText to capture output, and assert on the built command. Stub showChoicePalette / showActionPanel / notifications.add to script UI. nova.fs.open needs a working readline() — session labels depend on it.

The harness scripts from the build session lived in a temporary scratchpad and are gone. Recreating them in a Tests/ folder is the obvious next improvement.

Nothing in the current feature set spends tokens: the extension builds command strings and reads files. (If you add code that runs turns, use --model haiku and one-line prompts — a verification pass costs a few tens of cents.)

Cheap checks that need no CLI:

for f in Scripts/*.js; do node --check "$f"; done
python3 -c "import json; json.load(open('extension.json'))"

State

  • 89d1a06 is the in-editor-chat implementation, kept for the IDE bridge. The terminal-first rewrite on top of it is uncommitted.
  • Not published. min_runtime is declared as 10.
  • nova extension validate last passed cleanly on the schema; a later run failed only on network reachability from a sandbox, not on the bundle.
  • Never run inside Nova yet by this project's tooling — the user has run earlier builds; verify UI changes in the app.
  • Icons are generated by a script (a tapered starburst rendered to PNG with a pure-stdlib encoder); regenerate rather than hand-editing if sizes change.