Move to a terminal driven integration to have better interactions

This commit is contained in:
2026-08-11 17:10:26 -03:00
parent 89d1a06204
commit b05c28cff0
26 changed files with 679 additions and 4058 deletions
+45 -35
View File
@@ -6,14 +6,20 @@ 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.
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.
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.
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)
@@ -39,16 +45,20 @@ 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:
**Claude Code CLI**the facts this extension relies on:
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.
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
@@ -60,15 +70,11 @@ shells out to `claude auth login`. See [authentication](docs/features/authentica
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
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
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
```
@@ -96,28 +102,29 @@ 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:
**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 { ClaudeClient } = require("./Scripts/client.js");
const store = require("./Scripts/sessions-store.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`.
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.
**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.
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:
@@ -128,9 +135,12 @@ 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).
- `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.