Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
34 changes: 31 additions & 3 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ Every session has three phases: start, work, end.

<!-- BEGIN:REPO:current-state -->
## Current State
Branch: `main` — clean working tree.
Branch: `fix/packaging` — PR #230 open, auto-merge enabled.

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

Expand All @@ -88,8 +88,12 @@ Three-layer State / Renderer / ScreenCoordinator (MVVM) model. All 13 steps ship
- Config loading (`sdk-config.json`, Zod schema, `SdkConfigWatcher` hot reload) — PR #222
- Git state delta injection between turns (`GitStateMonitor`, `gitSnapshot`, `gitDelta`) — PR #225
- ANSI escape sequences no longer split at `wrapLine` boundaries — PR #223
- `systemReminder` bug fix (was re-sent on every tool-result turn) — PR #228
- CLAUDE.md files loaded as cached reminders (`ClaudeMdLoader`) — PR #229

**No branch in progress.** Next unstarted items in backlog: CLAUDE.md loading (#226), plain-text tool output (#221), improved tool descriptions (#209).
**PR #230 in review:** Switch packages from custom `build.ts` scripts to tsup. ESM + CJS + DTS per package, correct exports maps, sourcemaps working (fixes debugger breakpoints).

Next unstarted items in backlog: CLAUDE.md loading (#226), plain-text tool output (#221), improved tool descriptions (#209).
<!-- END:REPO:current-state -->

<!-- BEGIN:REPO:vision -->
Expand Down Expand Up @@ -169,9 +173,33 @@ Full detail: `.claude/five-banana-pillars.md`
- **No abstract classes as DI tokens** in this codebase — components are concrete classes wired in `ClaudeCli`
- **No TUI framework** — raw ANSI escape sequences on `process.stdout` only
- **JSONL** for audit log — one `{ timestamp, ...SDKMessage }` per line, all types except `stream_event`
- Build output: `dist/` via esbuild
- Build output: `dist/esm/` and `dist/cjs/` via tsup (ESM + CJS + DTS)
<!-- END:REPO:conventions -->

<!-- BEGIN:REPO:releases -->
## Releases & Changelog

This is a monorepo with per-package releases.

**Tag format**: `<package-name>@<version>` — the package name is the last segment of the npm scope (e.g. `@shellicar/claude-sdk` → tag `claude-sdk@1.0.0-beta.1`). The legacy `claude-cli` app uses unscoped tags (`1.0.0-alpha.74`).

**PR labels**: every PR needs both a type label (`bug` / `enhancement` / `documentation`) and a `pkg:` label for each package it touches (`pkg: claude-core`, `pkg: claude-sdk`, `pkg: claude-sdk-tools`, `pkg: claude-sdk-cli`, `pkg: claude-cli`). A PR touching all packages gets all five `pkg:` labels.

**`changes.jsonl`** lives at the root of each package. Add an entry on every PR that touches the package:
```jsonl
{"description":"Human-readable change","category":"added|changed|deprecated|removed|fixed|security"}
```
`category` is required; valid values come from `changes.config.json`. Do not add issue or PR references at the top level: link backward to issues via `metadata` if needed.

Release markers: `{"type":"release","version":"1.0.0-beta.1","date":"YYYY-MM-DD"}`

**`CHANGELOG.md`** is maintained from `changes.jsonl` when cutting a release. The publish workflow (`npm-publish.yml`) requires the top version entry to match the release tag.

**Milestone**: `1.0` (not `1.0.0` — that is the milestone name on GitHub).

**@shellicar/changes tooling**: `changes.config.json` (repo root) defines valid category keys. `schema/shellicar-changes.json` is generated from it via `pnpm tsx scripts/src/generate-schema.ts` (run from `scripts/`). Validate all files with `pnpm tsx scripts/src/validate-changes.ts`; CI runs this automatically.
<!-- END:REPO:releases -->

<!-- BEGIN:REPO:linting-formatting -->
## Linting & Formatting

Expand Down
8 changes: 8 additions & 0 deletions .claude/sdk-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://raw.githubusercontent.com/shellicar/claude-cli/main/schema/sdk-config.schema.json",
"model": "claude-sonnet-4-6",
"historyReplay": {
"enabled": true,
"showThinking": false
}
}
115 changes: 115 additions & 0 deletions .claude/sessions/2026-04-09.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,118 @@ claude-sdk, 426 in claude-sdk-cli, all passing.
Wait for PRs #228 and #229 to be reviewed and merged. After merge, update `Current
State` in the harness to reflect `main` branch and close the feature. Next unstarted
backlog items: plain-text tool output (#221), improved tool descriptions (#209).


---

## Session 3 — Switch packages to tsup, PR #230

### Context

Picked up mid-session from a previous context window. All staged changes for
`fix/packaging` were already in place but uncommitted. The summary covered the
full history of decisions (bundle mode, clean strategy, entryNames, entry glob
per package).

### Build verified and committed

Ran `pnpm --filter './packages/*' build`, type-check, and app builds — all
passed cleanly. Committed as `257c95b` "Switch packages from custom build
scripts to tsup".

### Post-rebase check

User merged PRs #228/#229 and rebased `fix/packaging` onto updated main. After
rebase, `src/entry/nodeFs.ts` had moved to `src/fs/nodeFs.ts`, a new
`src/entry/fs.ts` public entry was added, and `editFilePair.ts` had been
temporarily broken (exporting `createEditFilePair` instead of the instantiated
pair). User manually restored the correct state. Full build + type-check +
app builds all passed after the fix.

### Biome CI failures on push

Pre-push hook (lefthook → biome) blocked with 8 errors. Initial attempt used
`biome check --write .` on the whole repo — wrong approach because it applies
fixes at all severity levels (info/warning/error) across all 312 files, not
just the 36 in the diff. Reverted those changes on user's instruction.

Correct approach: `pnpm run ci` (which runs `biome ci --diagnostic-level=error`)
to see exactly what blocks. Fixed only those 8 errors:

- Three `tsup.config.ts` files: arrow function body style (`=> ({` → `=>\n ({`)
- `claude-sdk-tools/package.json`: 7-space indent → 6-space in `./RefStore` and `./fs` export entries
- `apps/claude-sdk-cli/package.json`: missing trailing newline
- `apps/claude-sdk-cli/src/runAgent.ts`: import sort order (AppLayout before AuditWriter)
- `packages/claude-sdk/src/private/AgentRun.ts`: remove unused `CacheTtl` import (left over from cache TTL refactor rebased in)
- `packages/claude-sdk/src/private/MessageStream.ts`: ternary formatting (also from the rebased refactor)

Pushed cleanly. Pre-push hook passed: 36 files checked, 0 errors.

### PR #230 opened

https://github.com/shellicar/claude-cli/pull/230 — "Switch packages from
custom build scripts to tsup". Milestone `1.0`, reviewer `bananabot9000`,
assignee `shellicar`, label `enhancement`, auto-merge (squash) enabled.

## What's next

Wait for PR #230 to be reviewed and merged. After merge, update `Current State`
in the harness. Next unstarted backlog items: CLAUDE.md loading (#226),
plain-text tool output (#221), improved tool descriptions (#209).


---

# Session 2026-04-09 (continued)

## What was done

### @shellicar/changes tooling built and committed

Full toolchain for `changes.jsonl` validation across the monorepo:

**`changes.config.json`** at repo root defines the valid categories:
`feature`, `fix`, `breaking`, `deprecation`, `security`, `performance`.

**`scripts/src/generate-schema.ts`** reads that config and generates
`schema/shellicar-changes.json` via Zod + `zod-to-json-schema`. Key details:
- `category` is required in this repo (stricter than the base spec default)
- Both `ChangeEntry` and `ReleaseMarker` use `.strict()` (additionalProperties: false)
- Schema is a bound artifact: regenerate it if the config changes

**`scripts/src/validate-changes.ts`** validates all `**/changes.jsonl` files
against the generated schema via ajv. No-args mode globs the repo; pass
specific paths to validate those only. Exits 1 on validation failures,
exits 2 if glob finds no files.

**CI** (`.github/workflows/node.js.yml`) runs the validator automatically.

### changes.jsonl files added/updated

- `packages/claude-core/changes.jsonl`: fix entry for tsup packaging work (PR #230)
- `packages/claude-sdk/changes.jsonl`: same
- `packages/claude-sdk-tools/changes.jsonl`: existing feature entries preserved;
two new entries appended (tsup fix + `./fs` export feature)

All entries: no top-level `issue` field (links go backward to issues, never
forward to PRs; use `metadata` for platform refs per spec principle 3).

### CLAUDE.md updated (both files)

- Fixed category enum: `feature|fix|breaking|deprecation|security|performance`
- Removed `"issue":"#NNN"` from the example
- Added note that `category` is required
- Added note that issue links go in `metadata`, not top-level
- Added `@shellicar/changes Tooling` section explaining the toolchain

## Note

`shellicar-changes.md` (the spec reference doc) was accidentally committed
via `git add -A`. It is the upstream spec document shared as session context.
Add it to `.gitignore` or remove it from the repo as desired.

## What's next

PR #230 is open with auto-merge. After it merges, update `Current State`
in the harness. Next unstarted backlog items: CLAUDE.md loading (#226),
plain-text tool output (#221), improved tool descriptions (#209).
1 change: 1 addition & 0 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ jobs:
- run: pnpm run --if-present type-check --only
- run: pnpm run --if-present test --only
- run: pnpm run ci
- run: pnpm --filter scripts run validate
63 changes: 62 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,73 @@ All work is tracking toward the `1.0.0` milestone.

Every PR must include:

- **Milestone**: `1.0.0`
- **Milestone**: `1.0`
- **Reviewer**: `bananabot9000`
- **Assignee**: `shellicar`
- **Label**: one of `bug`, `enhancement`, or `documentation` (pick the most appropriate)
- **Package label(s)**: add a `pkg: <name>` label for every package the PR touches. Labels exist for `claude-core`, `claude-sdk`, `claude-sdk-tools`, `claude-sdk-cli`, `claude-cli`. A PR touching all packages gets all five.
- **Auto-merge**: enable with `gh pr merge --auto --squash`

## Changelog

This is a monorepo. Each publishable package has its own release lifecycle:

- **Tags** use the format `<package-name>@<version>` (e.g. `claude-sdk@1.0.0-beta.1`). The package name is the last segment of the npm name — `@shellicar/claude-sdk` → `claude-sdk`.
- Each package has a `changes.jsonl` and a `CHANGELOG.md`.
- **`changes.jsonl`** records individual changes as they land. Add an entry for every PR that touches the package:
```jsonl
{"description":"What changed","category":"added|changed|deprecated|removed|fixed|security"}
```
`category` is required; valid values come from `changes.config.json`. Do not add issue or PR references at the top level: link backward to issues via `metadata` if needed.

Release markers look like: `{"type":"release","version":"1.0.0-beta.1","date":"YYYY-MM-DD"}`
- **`CHANGELOG.md`** is updated from `changes.jsonl` entries when cutting a release. The publish workflow validates that the top entry matches the release tag version.
- The **root `CHANGELOG.md`** covers the legacy `claude-cli` app (unscoped tags like `1.0.0-alpha.74`).

## @shellicar/changes

This repo uses the `@shellicar/changes` toolchain for per-package changelogs. All scripts live in `scripts/src/` and run with `pnpm tsx scripts/src/<script>.ts` from the repo root.

### Config

`changes.config.json` at the repo root defines the valid category keys and their display names. The generated schema is bound to this config — regenerate the schema whenever this file changes.

### Schema

`schema/shellicar-changes.json` is a generated JSON Schema artifact. Each line in a `changes.jsonl` must be one of:

**Change entry**
- `description` (required): human-readable string; may include markdown including backticks and links
- `category` (required): must match a key in `changes.config.json`
- `metadata` (optional): open bag; two recognised keys:
- `issue` — integer GitHub issue number, rendered as `(#NNN)` in the changelog
- `ghsa` — GitHub Security Advisory ID string, rendered as a linked `([GHSA-XXXX](https://github.com/advisories/GHSA-XXXX))` suffix

**Release marker**
- `type`: `"release"`
- `version`: semver string
- `date`: `YYYY-MM-DD`
- `tag` (optional): explicit Git tag; defaults to `<package-name>@<version>`. Set for packages with legacy unscoped tags (e.g. `claude-cli` historical alpha releases).

### Scripts

**`generate-schema.ts`** — regenerates `schema/shellicar-changes.json` from Zod definitions + `changes.config.json`. Must be run from the `scripts/` directory.
```
pnpm tsx scripts/src/generate-schema.ts
```

**`validate-changes.ts`** — validates every `**/changes.jsonl` in the repo against the schema via ajv. Pass specific paths to validate those only. CI runs this on every push.
```
pnpm tsx scripts/src/validate-changes.ts
pnpm tsx scripts/src/validate-changes.ts packages/claude-sdk/changes.jsonl
```

**`generate-changelog.ts`** — generates `CHANGELOG.md` for a package from its `changes.jsonl`. Reads entries top-to-bottom; entries before each release marker belong to that release; entries after the last marker become `[Unreleased]`. Within each release, entries are grouped by category in config order. Run this after adding entries and before cutting a release.
```
pnpm tsx scripts/src/generate-changelog.ts <package-dir>
pnpm tsx scripts/src/generate-changelog.ts packages/claude-sdk-tools
```

## Branch Naming

Use the following prefixes:
Expand Down
Loading
Loading