[workspace-split] P1.3: extract cc-types leaf crate (partial) - #80
Merged
Merged
Conversation
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.
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.
13 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Advances #70 (Phase 1 leaf extractions). Follow-up to #79.
Summary
Extracts the three pure-leaf files from
src/types/into a newcc-typesworkspace crate:
message.rs→crates/cc-types/src/message.rsstate.rs→crates/cc-types/src/state.rstransitions.rs→crates/cc-types/src/transitions.rsapp_state.rs,tool.rs, andconfig.rsstay in the root crate. Per theroutine's analysis in #70 and the
cc-typesnote at the top of #79, thosethree are not true leaves:
types::app_state::AppStatereferencescrate::teams::types,crate::ui::status_line,crate::config::settings, and the now-extractedcc_keybindings::KeybindingRegistry.types::tool::ToolUseContextreferencescrate::ipc::agent_channel::AgentSender.types::configpullsToolUseContextandToolsfromtool.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.rsnow re-exports the three moved modules:All existing
crate::types::message::*/crate::types::state::*/crate::types::transitions::*paths — roughly 80 call sites acrossapi/,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 / ipchave 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
crates/cc-types/Cargo.toml(new)serde,serde_json,uuid,chrono(allworkspace = true)crates/cc-types/src/lib.rs(new)pub moddeclarations, comment explaining the partial boundarygit mvCargo.tomlcc-types = { path = "crates/cc-types" }crates/claude-code-rs/Cargo.tomlcc-types = { workspace = true }crates/claude-code-rs/src/types/mod.rspub mod {message,state,transitions}→pub use cc_types::{message, state, transitions};(plus the three remaining local modules)Verification
cargo build: ok, 2 warnings (pre-existingweb::handlers::session_iddead_code, byte-identical onrust-lite@ab8a2fc).cargo build --release: ok, same 2 warnings.cargo test -p cc-types: 0 tests moved with the files; the crate compilesclean 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-keybindingsandcc-observabilityextractions.cargo test --offline -- --test-threads=1across the workspace:1794 / 1794 in
claude-code-rs, 51 / 51 incc-keybindings,10 / 11 in
cc-observability. The single failure iscc-observability::sink::tests::off_mode_skips_redaction— the samepre-existing
redact_valuebug [workspace-split] Phase 0 + 1 (partial): Workspace skeleton, leaf extractions, CI adaptations #79 documented, unchanged by this PR.claude-code-rs --versionprintsclaude-code-rs 0.1.0.Phase 1 checklist status (#70)
crates/cc-keybindings/([workspace-split] Phase 0 + 1 (partial): Workspace skeleton, leaf extractions, CI adaptations #79,9fd7229)crates/cc-observability/([workspace-split] Phase 0 + 1 (partial): Workspace skeleton, leaf extractions, CI adaptations #79,ef45df3)crates/cc-types/— partial, this PRmessage.rs/state.rs/transitions.rsextractedapp_state.rs/tool.rs/config.rsdeferred to Phase 5+src/types/{message,state,transitions}.rsremoved from root cratesrc/types/{app_state,tool,config}.rsstill present (by design)Test plan
cargo buildcargo build --releasecargo test --bin claude-code-rs --offline -- --test-threads=1cargo test -p cc-typesclaude-code-rs --versionsmoke testKnown caveats / follow-ups (unchanged from #79)
cc-observability::sink::tests::off_mode_skips_redactionstill flakes —pre-existing, tracked in [workspace-split] Phase 0 + 1 (partial): Workspace skeleton, leaf extractions, CI adaptations #79's description. Not touched here.
section remain open.
cc-typesshould be amended — thisPR's
lib.rscomment and commit message capture the revised reality,but the design doc file itself has not been updated here to keep the
diff surface minimal.
Refs #70. Part of #68.
🤖 Generated with Claude Code