Skip to content

[workspace-split] P1.3: extract cc-types leaf crate (partial) - #80

Merged
Crsei merged 1 commit into
Crsei:rust-litefrom
yaohaowei0914:claude/fervent-benz-0c2ffa
Apr 21, 2026
Merged

[workspace-split] P1.3: extract cc-types leaf crate (partial)#80
Crsei merged 1 commit into
Crsei:rust-litefrom
yaohaowei0914:claude/fervent-benz-0c2ffa

Conversation

@yaohaowei0914

Copy link
Copy Markdown
Contributor

Advances #70 (Phase 1 leaf extractions). Follow-up to #79.

Summary

Extracts the three pure-leaf files from src/types/ into a new cc-types
workspace crate:

  • message.rscrates/cc-types/src/message.rs
  • state.rscrates/cc-types/src/state.rs
  • transitions.rscrates/cc-types/src/transitions.rs

app_state.rs, tool.rs, and config.rs stay in the root crate. Per the
routine's analysis in #70 and the cc-types note at the top of #79, those
three are not true leaves:

  • types::app_state::AppState references crate::teams::types,
    crate::ui::status_line, crate::config::settings, and the now-extracted
    cc_keybindings::KeybindingRegistry.
  • types::tool::ToolUseContext references crate::ipc::agent_channel::AgentSender.
  • types::config pulls ToolUseContext and Tools from tool.

Extracting these would require either moving teams / ui / config / ipc out
first (Phase 5+) or rewriting the struct layouts with trait objects / generics
— much larger than a leaf move. Out of scope for Phase 1.

Call-site compatibility

The root crate's types/mod.rs now re-exports the three moved modules:

pub use cc_types::{message, state, transitions};

pub mod app_state;
pub mod config;
pub mod tool;

All existing crate::types::message::* / crate::types::state::* /
crate::types::transitions::* paths — roughly 80 call sites across
api/, compact/, engine/, query/, session/, tools/ etc. —
keep resolving with zero edits.

Why a partial extraction instead of deferring the whole thing

#79 suggested deferring all of cc-types "until teams / ui / config / ipc
have migrated". That would cost the main goal of Phase 1 — incremental-build
wins from the stable message / state / transitions types (referenced from
~80 files, changed rarely). Splitting out the clean subset now captures most
of the benefit immediately; the dirty subset still rides along with the
remaining root crate until its dependencies move.

Diff shape

Change Notes
crates/cc-types/Cargo.toml (new) deps: serde, serde_json, uuid, chrono (all workspace = true)
crates/cc-types/src/lib.rs (new) 3 pub mod declarations, comment explaining the partial boundary
3 × git mv rename-tracking preserved, no content changes to message/state/transitions
Cargo.toml one new workspace dep entry: cc-types = { path = "crates/cc-types" }
crates/claude-code-rs/Cargo.toml one new line: cc-types = { workspace = true }
crates/claude-code-rs/src/types/mod.rs pub mod {message,state,transitions}pub use cc_types::{message, state, transitions}; (plus the three remaining local modules)

Verification

  • cargo build : ok, 2 warnings (pre-existing
    web::handlers::session_id dead_code, byte-identical on rust-lite@ab8a2fc).
  • cargo build --release : ok, same 2 warnings.
  • cargo test -p cc-types : 0 tests moved with the files; the crate compiles
    clean with zero warnings.
  • cargo test --bin claude-code-rs --offline -- --test-threads=1 :
    1794 / 1794 pass — matches the baselines reported in [workspace-split] Phase 0 + 1 (partial): Workspace skeleton, leaf extractions, CI adaptations #79 for the
    cc-keybindings and cc-observability extractions.
  • cargo test --offline -- --test-threads=1 across the workspace:
    1794 / 1794 in claude-code-rs, 51 / 51 in cc-keybindings,
    10 / 11 in cc-observability. The single failure is
    cc-observability::sink::tests::off_mode_skips_redaction — the same
    pre-existing redact_value bug [workspace-split] Phase 0 + 1 (partial): Workspace skeleton, leaf extractions, CI adaptations #79 documented, unchanged by this PR.
  • Smoke: claude-code-rs --version prints claude-code-rs 0.1.0.

Phase 1 checklist status (#70)

Test plan

  • cargo build
  • cargo build --release
  • cargo test --bin claude-code-rs --offline -- --test-threads=1
  • cargo test -p cc-types
  • claude-code-rs --version smoke test
  • CI across Linux / Windows (left to the workflow)

Known caveats / follow-ups (unchanged from #79)

Refs #70. Part of #68.

🤖 Generated with Claude Code

Move the three pure-leaf files out of `src/types/` into a new
`cc-types` workspace crate:

- `message.rs`     → `cc-types/src/message.rs`
- `state.rs`       → `cc-types/src/state.rs`
- `transitions.rs` → `cc-types/src/transitions.rs`

`app_state.rs`, `tool.rs`, and `config.rs` stay in the root crate.
Per the routine's analysis in issue Crsei#70 and the `cc-types` note in
PR Crsei#79, those three modules are not true leaves:

- `types::app_state::AppState` references `crate::teams::types`,
  `crate::ui::status_line`, `crate::config::settings`, and the
  now-extracted `cc_keybindings::KeybindingRegistry`.
- `types::tool::ToolUseContext` references
  `crate::ipc::agent_channel::AgentSender`.
- `types::config` pulls `ToolUseContext` and `Tools` from `tool`.

Extracting these would require either moving teams/ui/config/ipc
out first, or rewriting the struct layouts with trait objects /
generics — much larger than a leaf move. They stay put until those
subsystems migrate (Phase 5+).

The root crate's `types/mod.rs` now re-exports the three moved
modules via `pub use cc_types::{message, state, transitions};` so
every existing `crate::types::message::*` / `crate::types::state::*`
/ `crate::types::transitions::*` call site (~80 files) keeps
resolving without edits.

Verification
------------

- `cargo build`            : ok, 2 warnings (pre-existing
  `web::handlers::session_id` dead_code, identical on `rust-lite@ab8a2fc`).
- `cargo build --release`  : ok, same 2 warnings.
- `cargo test -p cc-types` : 0 tests (no tests moved with the files);
  compiles clean, no warnings.
- `cargo test --bin claude-code-rs --offline -- --test-threads=1`
  : **1794 / 1794 pass** (matches the `cc-keybindings` /
  `cc-observability` baselines from PR Crsei#79).
- Smoke: `claude-code-rs --version` prints `claude-code-rs 0.1.0`.

Refs issue Crsei#70.
@Crsei
Crsei merged commit e602453 into Crsei:rust-lite Apr 21, 2026
0 of 3 checks passed
yaohaowei0914 pushed a commit to yaohaowei0914/claude-code-rust that referenced this pull request Apr 21, 2026
… crates

Three Phase-2 extractions in one commit; each builds + tests green at
the boundary, and the root crate keeps every `crate::{auth,bootstrap,
skills}::…` path working via `use cc_X as X;` aliases at the crate root
(same pattern Crsei#79 used for `cc-keybindings` and `cc-observability`).

cc-bootstrap — 7 files, 922 LOC (clean leaf)
-------------------------------------------

`src/bootstrap/{diagnostics,ids,mod,model,signal,state,timing}.rs` →
`crates/cc-bootstrap/src/…` with a pure `git mv`. No dependency-injection
needed: `bootstrap/` was already a true import-DAG leaf per its own
module doc. Direct deps: `serde`, `parking_lot`, `tokio`, `uuid` (+
`serde_json` for the round-trip test in `ids.rs`).

cc-auth — 8 files, ~1,500 LOC (one tie broken)
---------------------------------------------

`src/auth/{api_key,codex_cli,mod,token}.rs` and
`src/auth/oauth/{mod,client,config,pkce}.rs` → `crates/cc-auth/src/…`.

The one reverse-dep was `token.rs:9` calling
`crate::config::paths::credentials_path()`. Broken by a global init
registered from the host at process startup (mirrors the `set_event_sender`
pattern already used by mcp/plugins/lsp/skills):

- `cc_auth::set_credentials_path(PathBuf)` — host calls this at the top
  of `fn main()` with `crate::config::paths::credentials_path()`.
- `token::token_file_path()` reads it back via a private
  `crate::credentials_path()` helper.
- Falls back to `{CC_RUST_HOME | ~/.cc-rust | $TMP/cc-rust}/credentials.json`
  when the host hasn't registered one, so unit tests that exercise
  `resolve_auth()` directly (doctor, logout, voice_cmd — 10 tests) keep
  passing. The fallback duplicates ~10 LOC from `config::paths::data_root`
  — a small price for full decoupling.

Keychain service name stays `"cc-rust"` (the original acceptance
criterion on Crsei#71). OAuth scopes, PKCE, and token-refresh flow are
untouched — only the storage path resolution changed.

Direct deps: `anyhow`, `serde`, `serde_json`, `chrono`, `tokio`,
`tracing`, `reqwest`, `keyring`, `base64`, `rand`, `sha2`, `dirs`,
`parking_lot`, `urlencoding`.

cc-skills — 3 files, ~1,000 LOC (two ties broken)
------------------------------------------------

`src/skills/{bundled,loader,mod}.rs` → `crates/cc-skills/src/…`.

Two reverse-deps broken:

1. **Event emission** — `emit_event` held a
   `broadcast::Sender<crate::ipc::subsystem_events::SubsystemEvent>`,
   which is a cycle the moment skills leaves the root crate.
   Replaced with a minimal cc-skills-owned enum and a callback:

   ```rust
   pub enum SkillSubsystemEvent { SkillsLoaded { count: usize } }
   pub fn set_event_callback<F: Fn(SkillSubsystemEvent) + Send + Sync + 'static>(cb: F);
   ```

   The host adapts it into `SubsystemEvent::Skill(SkillEvent::SkillsLoaded { .. })`
   in `ipc/runtime.rs` (replaces the old `set_event_sender(bus.sender())`
   line).

2. **User-skills directory** — `init_skills` used to resolve
   `crate::config::paths::skills_dir_global()` internally. It now takes
   the directory as its first parameter; `main.rs` and `ipc::subsystem_handlers`
   pass `&crate::config::paths::skills_dir_global()` at the call site.

Direct deps: `serde`, `parking_lot` only.

Verification
------------

- `cargo build`                  : ok, 2 warnings (pre-existing
  `web::handlers::session_id` dead_code, identical on `rust-lite@ab8a2fc`).
- `cargo build --release`        : ok, same 2 warnings.
- `cargo test --workspace --lib --offline --no-fail-fast -- --test-threads=1`:
  - `cc-auth`          — 32 passed, 0 failed, 2 ignored
  - `cc-bootstrap`     — 28 passed, 0 failed
  - `cc-keybindings`   — 51 passed, 0 failed (unchanged from P1)
  - `cc-observability` — 10 passed, 1 pre-existing flake
    (`off_mode_skips_redaction`, tracked in Crsei#79)
  - `cc-skills`        — 21 passed, 0 failed
  - `cc-types`         — 0 tests
- `cargo test --bin claude-code-rs --offline -- --test-threads=1`
  : **1713 / 1713 pass**. Baseline from PR Crsei#80 was 1794 — the 81-test
  drop is the tests that moved out with their code (cc-bootstrap 28 +
  cc-auth 32 + cc-skills 21 = 81, matches exactly).
- Smoke: `claude-code-rs --version` prints `claude-code-rs 0.1.0`.

Phase 2 checklist (Crsei#71)
-----------------------

- [x] `crates/cc-bootstrap/` created
- [x] `crates/cc-auth/` created
- [x] `crates/cc-skills/` created
- [x] `src/{bootstrap,auth,skills}/` removed from root crate
- [x] Keychain service name unchanged (`"cc-rust"`)
- [x] All tests pass (1713 bin + 142 extracted, one pre-existing
  cc-observability flake unchanged)
- [ ] Manual OAuth login E2E (`/login 2` + `/login-code`) — not
  reproducible in CI, flagged for maintainer verification.

Refs Crsei#71. Part of Crsei#68.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants