Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
117 commits
Select commit Hold shift + click to select a range
307be7b
Add claude-sdk-tools package with ReadFile, GrepFile, and EditFile tools
shellicar Apr 3, 2026
b024aa3
Initial set of tools
shellicar Apr 4, 2026
c417591
Export and use tools
shellicar Apr 4, 2026
f5399bc
More work on SDK tooling
shellicar Apr 4, 2026
46993f2
Persist conversation
shellicar Apr 4, 2026
8e081c5
Raise console log level
shellicar Apr 4, 2026
c801e9a
Refactor for tool pipeline
shellicar Apr 4, 2026
0ebea03
Linting
shellicar Apr 4, 2026
d540f80
Fix logging with SDK objects
shellicar Apr 4, 2026
a5e3569
Handle compaction content blocks
shellicar Apr 4, 2026
24e629a
Put compaction messages into assistant messages
shellicar Apr 4, 2026
0d50eb5
Change to JSONL format
shellicar Apr 4, 2026
a9a07ef
Fixes for tool schema
shellicar Apr 4, 2026
627311e
Add pipe tool.
shellicar Apr 4, 2026
4d0f24b
Add search files
shellicar Apr 4, 2026
f03e06a
Linting
shellicar Apr 4, 2026
29673e4
Disable betas for now
shellicar Apr 4, 2026
cb92b63
Add HTTP logging
shellicar Apr 4, 2026
d8ec208
Add tests for FS tools
shellicar Apr 4, 2026
a82ef0f
Fix root vitest config
shellicar Apr 4, 2026
d76b712
Redact sensitive values
shellicar Apr 4, 2026
11db73f
Fix truncation
shellicar Apr 4, 2026
f242338
Add Exec
shellicar Apr 4, 2026
0a763ff
Add basic permissions
shellicar Apr 4, 2026
8864499
Add and fix abort
shellicar Apr 4, 2026
cd375e2
Fix tests to use proper code path for tools
shellicar Apr 4, 2026
a456d7a
Fix exec independent
shellicar Apr 4, 2026
99f1afa
Use readline from core
shellicar Apr 4, 2026
9447ebb
Add abort
shellicar Apr 4, 2026
a962a0f
Fix auth token and handle compaction locally.
shellicar Apr 4, 2026
29f944d
Add expandPath and tests
shellicar Apr 4, 2026
36c0fdb
Refactor and extract screen functionality
shellicar Apr 4, 2026
a4158f1
Linting
shellicar Apr 4, 2026
3ba73a3
Improve rendering and refactor permissions
shellicar Apr 4, 2026
97d47ad
Bug fixes and improvements
shellicar Apr 4, 2026
87cf5c4
Decouple ~ expansion from the real OS in tests
shellicar Apr 4, 2026
90a777e
Move claude-cli to apps
shellicar Apr 4, 2026
d8e89d5
Implement block rendering
shellicar Apr 4, 2026
864b47a
Adjust rendering for blocks
shellicar Apr 4, 2026
c656c83
Fix for new path
shellicar Apr 4, 2026
92cd6c7
Improve block rendering
shellicar Apr 4, 2026
b3272ea
Extract ansi
shellicar Apr 4, 2026
7b3afd0
Improvements to cli layout
shellicar Apr 4, 2026
b43a642
SDK tools refactor
shellicar Apr 4, 2026
cc513fb
Fix vite project path
shellicar Apr 4, 2026
8482adc
Fix whitespace-only blocks and trailing newline in block render
shellicar Apr 4, 2026
b350558
Fix Edit file display
shellicar Apr 4, 2026
d295d34
Fix and refactor fs and exports
shellicar Apr 4, 2026
ac15d18
Refactor delete tools
shellicar Apr 4, 2026
a0024f3
Add code highlighting.
shellicar Apr 4, 2026
4618195
Remove ChainedToolStore and add defineTool factory
shellicar Apr 4, 2026
8d22394
Add shared tsconfig
shellicar Apr 4, 2026
c13763c
Show stop reason
shellicar Apr 4, 2026
d3d6e94
Display API errors
shellicar Apr 4, 2026
7e450ac
Add replace_text action to EditFile
shellicar Apr 4, 2026
f7f3cf7
Fix tsconfig export
shellicar Apr 4, 2026
3b63365
Rename EditFile → PreviewEdit and ConfirmEditFile → EditFile
shellicar Apr 4, 2026
acedc20
Replace hand-rolled generateDiff with diff library
shellicar Apr 4, 2026
dcf1312
fix: resolve biome lint errors in AppLayout.ts and logger.ts
shellicar Apr 5, 2026
ecf6ecc
feat: add previousPatchId chaining to PreviewEdit
shellicar Apr 5, 2026
771374c
fix: use edit.action in error messages instead of hardcoded 'replace_…
shellicar Apr 5, 2026
2fdeb93
docs: explain originalHash inheritance trade-off in PreviewEdit chain
shellicar Apr 5, 2026
40a5311
docs: clarify previousPatchId apply behaviour in schema description
shellicar Apr 5, 2026
060439d
fix: Grep now emits lineNumbers — 1-based positions of matched lines
shellicar Apr 5, 2026
3570921
fix: restore missing $ prefix in status line cost display
shellicar Apr 5, 2026
33a5663
fix: replace_text replacement string no longer interprets $ specially
shellicar Apr 5, 2026
b839d40
docs: add CLAUDE.md for claude-sdk-cli
shellicar Apr 5, 2026
8386c4d
feat: add context window display to status line
shellicar Apr 5, 2026
a39f57b
docs: add skills design document
shellicar Apr 5, 2026
ed57ec4
Prevent infinite retries
shellicar Apr 5, 2026
1025f8c
Update CLAUDE-me
shellicar Apr 5, 2026
8914b2f
feat: ref system — transformToolResult hook, RefStore, walkAndRef, Re…
shellicar Apr 5, 2026
5885a36
fix: exempt Ref tool from transformToolResult to prevent infinite ref…
shellicar Apr 5, 2026
a0aa494
feat: wire ref system into claude-sdk-cli app
shellicar Apr 5, 2026
5e461ea
fix: merge consecutive user messages in ConversationHistory
shellicar Apr 5, 2026
2bb2185
chore: increase ref threshold to 2k
shellicar Apr 5, 2026
48ecd7e
feat: ReadFile size guard + walkAndRef large string-array handling
shellicar Apr 5, 2026
9c48b72
docs: add CLAUDE.md for claude-sdk-tools
shellicar Apr 5, 2026
d85062c
feat: show context high-water mark at end of compaction block
shellicar Apr 5, 2026
22b07c3
Linting
shellicar Apr 5, 2026
8d2705a
docs: session log 2026-04-05 (feature/sdk-tooling)
shellicar Apr 5, 2026
574fe43
feat: Ref display with hint/size, per-tool result sizes and turn cost…
shellicar Apr 5, 2026
3e8e89d
fix: tools block merging and misleading per-turn cost display
shellicar Apr 5, 2026
30bf7d0
refactor: renderer merges consecutive same-type blocks; token delta r…
shellicar Apr 5, 2026
890f827
feat: add per-turn cost and debug log to tool batch annotation
shellicar Apr 5, 2026
d6cee0d
feat: marginal cost in tool annotation using calculateCost on token d…
shellicar Apr 5, 2026
6f420ef
feat: Ref schema start/limit with defaults, hint in response
shellicar Apr 5, 2026
8cfb586
fix: annotation lands in active tools block for back-to-back batches
shellicar Apr 5, 2026
70eeeff
fix: retry up to 2x when stop_reason is tool_use but no tool uses str…
shellicar Apr 5, 2026
a781aae
feat: cursor-aware editor with full keyboard navigation
shellicar Apr 5, 2026
48a7c1c
fix: render char under cursor in reverse-video instead of inserting s…
shellicar Apr 5, 2026
bfe5a5f
fix: ctrl+backspace/delete cross newline boundaries when at start/end…
shellicar Apr 5, 2026
bf2134c
docs: session log 2026-04-05 (continued)
shellicar Apr 5, 2026
d3218fc
feat: command mode skeleton (ctrl+/ to enter, ESC to exit, cmd bar)
shellicar Apr 5, 2026
eb039d1
feat: clipboard attachments via command mode (t=paste, d=delete, chip…
shellicar Apr 5, 2026
d7b34c9
feat: ConversationHistory.push(msg, {id?}) + remove(id) for tagged me…
shellicar Apr 5, 2026
0e78916
feat: IAnthropicAgent.injectContext/removeContext public API for skil…
shellicar Apr 5, 2026
56bc34f
refactor: IAnthropicAgent uses BetaMessageParam; thinking+pauseAfterC…
shellicar Apr 5, 2026
33473d4
docs: session log 2026-04-06 + update CLAUDE.md current state/archite…
shellicar Apr 5, 2026
da56c6f
feat: f command in command mode — reads clipboard as file path, attac…
shellicar Apr 5, 2026
f34fc02
test: ConversationHistory — push/merge/compaction/id-tag/remove (vite…
shellicar Apr 5, 2026
35a2479
fix: biome — flatten imports in index.ts, sort AnthropicAgent.ts impo…
shellicar Apr 5, 2026
1965956
Remove idiotic test error
shellicar Apr 5, 2026
4e42668
feat: command mode stays open; --version/--help flags; publishable @s…
shellicar Apr 5, 2026
fb53d1a
feat: f command reads Finder-copied files via osascript furl fallback
shellicar Apr 5, 2026
c346268
fix: trailing newline in clipboard.ts
shellicar Apr 5, 2026
f0ebefb
refactor: f command inserts resolved path into editor instead of load…
shellicar Apr 5, 2026
72840db
refactor: f attaches file/dir/missing as metadata object; [attachment…
shellicar Apr 5, 2026
77727cf
feat: f path-validation; 10KB text cap; p preview mode for attachments
shellicar Apr 5, 2026
ba216fe
fix: readClipboardPath falls through to osascript when pbpaste gives …
shellicar Apr 5, 2026
8c0ea02
test: add vitest + clipboard unit tests; fix looksLikePath to accept …
shellicar Apr 5, 2026
c574ded
feat: read VS Code 'Copy' clipboard via code/file-list JXA probe
shellicar Apr 5, 2026
4e0762d
debug: trace-level logging for each clipboard probe
shellicar Apr 5, 2026
a23dc53
fix: reject HFS artifacts from osascript furl (colons in path)
shellicar Apr 5, 2026
df01721
fix: stat-first in f handler; bare-relative looksLikePath; strict isL…
shellicar Apr 5, 2026
56e2515
Add more leniency for CI...
shellicar Apr 5, 2026
d85a031
docs: session log — f command + clipboard system (2026-04-05)
shellicar Apr 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 58 additions & 23 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,39 +66,67 @@ Every session has three phases: start, work, end.

<!-- BEGIN:REPO:current-state -->
## Current State
Branch: `feature/sdk-message-channel`
In-progress: PR shellicar/claude-cli#174 open, auto-merge enabled. SDK bidirectional communication feature.
Branch: `feature/sdk-tooling` — pushed, clean working tree.

Active development is in **`apps/claude-sdk-cli/`** — a TUI terminal app built on `@shellicar/claude-sdk`.

**Completed:**
- Full cursor-aware multi-line editor (`AppLayout.ts`)
- Clipboard text attachments via command mode (`ctrl+/` → `t` paste, `d` delete, chips in status bar)
- `ConversationHistory.push(msg, {id?})` + `remove(id)` for tagged message pruning
- `IAnthropicAgent.injectContext/removeContext` public API
- `RunAgentQuery.thinking` + `pauseAfterCompact` options; `AnthropicBeta` enum cleanup
- `BetaMessageParam` used directly in public interface (no more `JsonObject` casts)
- Ref tool + RefStore for large output ref-swapping
- Tool approval flow (auto-approve/deny/prompt)
- Compaction display with context high-water mark
- File attachments via `f` command: three-stage clipboard path reading (pbpaste / VS Code code/file-list JXA / osascript furl), stat-first handler, `file`/`dir`/`missing` chips

**In-progress / next:**
- Skills system (`ActivateSkill`/`DeactivateSkill`) — primitives in place; timing design issue unresolved (see `docs/skills-design.md`)
- Image attachments — `pngpaste` + clipboard image detection (deferred)
<!-- END:REPO:current-state -->

<!-- BEGIN:REPO:architecture -->
## Architecture

**Stack**: TypeScript, esbuild (bundler), `@anthropic-ai/claude-agent-sdk`. pnpm monorepo workspace with turbo. CLI package lives at `packages/claude-cli/`. SDK package lives at `packages/claude-sdk/` (see `packages/claude-sdk/CLAUDE.md` for architecture and known issues).
**Stack**: TypeScript, esbuild (bundler), `@anthropic-ai/sdk` (direct). pnpm monorepo with turbo. Two apps: active (`apps/claude-sdk-cli/`) and legacy (`apps/claude-cli/`).

**Entry point**: `packages/claude-cli/src/main.ts` parses CLI flags, creates `ClaudeCli`, calls `start()`
### Packages

**Key source files** (all under `packages/claude-cli/`):
| Package | Role |
|---------|------|
| `apps/claude-sdk-cli/` | **Active TUI CLI** — talks directly to `@shellicar/claude-sdk` |
| `apps/claude-cli/` | Legacy CLI using a different SDK path (not actively developed) |
| `packages/claude-sdk/` | Anthropic SDK wrapper: `IAnthropicAgent`, `AnthropicAgent`, `AgentRun`, `ConversationHistory`, `MessageStream` |
| `packages/claude-sdk-tools/` | Tool definitions: `Find`, `ReadFile`, `Grep`, `Head`, `Tail`, `Range`, `SearchFiles`, `Pipe`, `EditFile`, `PreviewEdit`, `CreateFile`, `DeleteFile`, `DeleteDirectory`, `Exec`, `Ref` |
| `packages/claude-core/` | Shared ANSI/terminal utilities: `sanitise`, `reflow`, `screen`, `status-line`, `viewport`, `renderer` |
| `packages/typescript-config/` | Shared tsconfig base |

### Key files in `apps/claude-sdk-cli/src/`

| File | Role |
|------|------|
| `entry/main.ts` | Entry point: creates agent, layout, starts readline loop |
| `AppLayout.ts` | TUI: full cursor editor, streaming display, compaction blocks, tool approval, command mode, attachment chips |
| `AttachmentStore.ts` | `TextAttachment \| FileAttachment` union; SHA-256 dedup; 10 KB text cap; `addFile(path, kind, size?)` |
| `clipboard.ts` | `readClipboardText()`; three-stage `readClipboardPath()` (pbpaste → VS Code code/file-list JXA → osascript furl); `looksLikePath`; `sanitiseFurlResult` |
| `runAgent.ts` | Wires agent to layout: sets up tools, beta flags, event handlers |
| `permissions.ts` | Tool auto-approve/deny rules |
| `redact.ts` | Strips sensitive values from tool inputs before display |
| `logger.ts` | Winston file logger (`claude-sdk-cli.log`) |

### Key files in `packages/claude-sdk/src/`

| File | Role |
|------|------|
| `src/ClaudeCli.ts` | Orchestrator, startup sequence, event loop, query cycle |
| `src/session.ts` | `QuerySession`, SDK wrapper, session/resume lifecycle |
| `src/AppState.ts` | Phase state machine (`idle`, `sending`, `thinking`, `idle`) |
| `src/terminal.ts` | ANSI terminal rendering, three-zone layout |
| `src/renderer.ts` | Pure editor content preparation (cursor math) |
| `src/StatusLineBuilder.ts` | Fluent builder for width-accurate ANSI status lines |
| `src/SessionManager.ts` | Session file I/O (`.claude/cli-session`) |
| `src/AuditWriter.ts` | JSONL event logger (`~/.claude/audit/<session-id>.jsonl`) |
| `src/files.ts` | `initFiles()` creates `.claude/` dir, returns `CliPaths` |
| `src/cli-config/` | Config subsystem, schema, loading, diffing, hot reload |
| `src/providers/` | `GitProvider`, `UsageProvider`, system prompt data sources |
| `src/PermissionManager.ts` | Tool approval queue and permission prompt UI |
| `src/PromptManager.ts` | `AskUserQuestion` dialog, single/multi-select + free text |
| `src/CommandMode.ts` | Ctrl+/ state machine for attachment and session operations |
| `src/SdkResult.ts` | Parses `SDKResultSuccess`, extracts errors, rate limits, token counts |
| `src/UsageTracker.ts` | Context usage and session cost tracking interface |
| `src/mcp/shellicar/autoApprove.ts` | Glob-based auto-approve for exec commands (`execAutoApprove` config) |
| `docs/sdk-findings.md` | SDK behaviour discoveries (session semantics, tool options, etc.) |
| `public/interfaces.ts` | `IAnthropicAgent` abstract class (public contract) |
| `public/types.ts` | `RunAgentQuery`, `SdkMessage` union, tool types |
| `public/enums.ts` | `AnthropicBeta` enum |
| `private/AgentRun.ts` | Single agent turn loop: streaming, tool dispatch, history management |
| `private/ConversationHistory.ts` | Persistent JSONL history with ID-tagged push/remove |
| `private/MessageStream.ts` | Stream event parser and emitter |
| `private/pricing.ts` | Token cost calculation |
<!-- END:REPO:architecture -->

<!-- BEGIN:REPO:conventions -->
Expand Down Expand Up @@ -178,13 +206,20 @@ Opt-in via `shellicarMcp: true` config. Registers an in-process MCP server (`she
<!-- END:REPO:known-debt -->

<!-- BEGIN:REPO:recent-decisions -->
- **f command clipboard system** (2026-04-05): Three-stage `readClipboardPath()` — (1) pbpaste filtered by `looksLikePath`, (2) VS Code `code/file-list` JXA probe (file:// URI → POSIX path), (3) osascript `furl` filtered by `sanitiseFurlResult`. Injectable `readClipboardPathCore` for tests. `looksLikePath` is permissive (accepts bare-relative like `apps/foo/bar.ts`); `isLikelyPath` in AppLayout is strict (explicit prefixes only) and only used for the missing-chip case. `sanitiseFurlResult` rejects paths containing `:` (HFS artifacts). `f` handler is stat-first: if the file exists attach it directly; only apply `isLikelyPath` if stat fails.
- **Clipboard text attachments** (2026-04-06): `ctrl+/` enters command mode; `t` reads clipboard via `pbpaste` and adds a `<document>` block attachment; `d` removes selected chip; `← →` select chips. On `ctrl+enter` submit, attachments are folded into the prompt as `<document>` XML blocks and cleared.
- **ConversationHistory ID tagging** (2026-04-06): `push(msg, { id? })` tags messages for later removal. `remove(id)` splices the last item with matching ID. IDs are session-scoped (not persisted). Used by `IAnthropicAgent.injectContext/removeContext` for skills context management.
- **IAnthropicAgent uses BetaMessageParam** (2026-04-06): `getHistory/loadHistory/injectContext` now use `BetaMessageParam` directly instead of `JsonObject` casts. `JsonObject`, `JsonValue`, `ContextMessage` types removed. `BetaMessageParam` re-exported from package index.
- **thinking/pauseAfterCompact as RunAgentQuery options** (2026-04-06): Both default off. `thinking: true` adds `{ type: 'adaptive' }` to the API body. `pauseAfterCompact: true` wires into `compact_20260112.pause_after_compaction`. When `pauseAfterCompact: true` and compaction fires, the agent sends `done` with `stopReason: 'pause_turn'` — user sees the summary and resumes manually (intentional UX).
- **Skills timing design issue** (2026-04-06): Documented in `docs/skills-design.md`. Calling `agent.injectContext()` from inside a tool handler merges the injected user message with the pending tool-results user message (consecutive merge policy). Resolution options documented; implementation deferred.
## Recent Decisions

- **Structured command execution via in-process MCP** (#99) — replaced freeform Bash with a structured Exec tool served by an in-process MCP server. Glob-based auto-approve (`execAutoApprove`) with custom zero-dep glob matcher (no minimatch dependency).
- **Exec tool extracted to `@shellicar/mcp-exec`** — schema, executor, pipeline, validation rules, and ANSI stripping moved to a published package. CLI retains only `autoApprove.ts` (CLI-specific config concern).
- **ZWJ sanitisation in layout pipeline**: `sanitiseZwj` strips U+200D before `wrapLine` measures width. Terminals render ZWJ sequences as individual emojis; `string-width` assumes composed form. Stripping at the layout boundary removes the mismatch.
- **Monorepo workspace conversion**: CLI source moved to `packages/claude-cli/`. Root package is private workspace with turbo, syncpack, biome, lefthook. Turbo orchestrates build/test/type-check. syncpack enforces version consistency. `.packagename` file at root holds the active package name for scripts and pre-push hooks.
- **SDK bidirectional channel** (`packages/claude-sdk/`): New package wrapping the Anthropic API. Uses `MessagePort` for bidirectional consumer/SDK communication. Tool validation (existence + input schema) happens before approval requests are sent. Approval requests are sent in bulk; tools execute in approval-arrival order.
- **Screen utilities extracted to `claude-core`**: `sanitise`, `reflow` (wrapLine/rewrapFromSegments/computeLineSegments), `screen` (Screen interface + StdoutScreen), `status-line` (StatusLineBuilder), `viewport` (Viewport), `renderer` (Renderer) all moved from `claude-cli` to `claude-core`. `claude-cli` now imports from `@shellicar/claude-core/*`. `tsconfig.json` in claude-core requires `"types": ["node"]` for process globals with moduleResolution bundler.
<!-- END:REPO:recent-decisions -->

<!-- BEGIN:REPO:extra -->
Expand Down
Loading
Loading