147 lines
7.0 KiB
Markdown
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.
|