Files

147 lines
7.0 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 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 itself** — `claude --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](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** — 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](docs/features/authentication.md).
## 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:
```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 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:
```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 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:
```sh
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.