137 lines
6.3 KiB
Markdown
137 lines
6.3 KiB
Markdown
# CLAUDE.md
|
|
|
|
Context for working on this repository. Feature-level detail lives in
|
|
[`docs/features/`](docs/features/README.md) — read the relevant file there before
|
|
changing a subsystem.
|
|
|
|
## What this is
|
|
|
|
A Nova extension that puts Claude Code inside Panic's Nova editor: a sidebar for
|
|
the session, a live Markdown transcript, and tool approvals reviewed in the
|
|
editor.
|
|
|
|
It **drives the user's own `claude` executable** as a subprocess, speaking the
|
|
CLI's newline-delimited JSON protocol over stdio. There is no bundled copy of
|
|
Claude Code, no Node sidecar, no npm dependencies, and no network access of its
|
|
own.
|
|
|
|
## 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](docs/features/ide-bridge.md) 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.crypto` — **not 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** — see [session transport](docs/features/session-transport.md)
|
|
for the full protocol. The three facts that cost the most to find:
|
|
|
|
1. `--permission-prompt-tool stdio` is **required** for permission prompts to
|
|
reach the host, and is absent from `claude --help`. Without it every tool
|
|
needing approval is silently auto-denied.
|
|
2. One assistant message id arrives multiple times (per completed content block,
|
|
plus streaming deltas). They must be merged, not appended.
|
|
3. A `can_use_tool` control request **must always be answered**, including when
|
|
the handler throws — the CLI blocks on it and the session hangs otherwise.
|
|
|
|
**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](docs/features/authentication.md).
|
|
|
|
## Layout
|
|
|
|
```
|
|
extension.json manifest: sidebar, commands, config, entitlements
|
|
Scripts/
|
|
main.js Controller: lifecycle, commands, wiring
|
|
client.js CLI process + stream-json/control protocol
|
|
session.js conversation model (entries, tools, changed files)
|
|
permissions.js can_use_tool → approvals, plans, questions, proposals
|
|
transcript.js Markdown tab rendering
|
|
sidebar.js four TreeView providers
|
|
diff.js change reconstruction + unified diff
|
|
auth.js claude auth status/login/logout
|
|
cli.js binary resolution, environment, keychain
|
|
sessions-store.js reading ~/.claude/projects for resume
|
|
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:
|
|
|
|
```sh
|
|
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 transport and model can be
|
|
driven under Node against the *real* CLI. This caught four real bugs and is the
|
|
highest-value testing move available:
|
|
|
|
```js
|
|
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 { ClaudeClient } = require("./Scripts/client.js");
|
|
```
|
|
|
|
Then wire `onPermission` to scripted answers and send a prompt. Stub
|
|
`showChoicePalette` / `showActionPanel` / `showInputPanel` / `notifications.add`
|
|
to script UI decisions and assert on the resulting `PermissionResult`.
|
|
|
|
> 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.
|
|
|
|
**Live tests cost real money** — they run turns on the signed-in account. Use
|
|
`--model haiku` and one-line prompts; a full verification pass is a few tens of
|
|
cents.
|
|
|
|
Cheap checks that need no CLI:
|
|
|
|
```sh
|
|
for f in Scripts/*.js; do node --check "$f"; done
|
|
python3 -c "import json; json.load(open('extension.json'))"
|
|
```
|
|
|
|
## State
|
|
|
|
- Not yet committed. Not yet published. `min_runtime` is declared as `10`
|
|
(`nova.crypto` is the newest API touched, and it has a fallback).
|
|
- `nova extension validate` last passed cleanly on the schema; a later run
|
|
failed only on network reachability from a sandbox, not on the bundle.
|
|
- 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.
|