refactor(core): split jcode-app-core into jcode-base + jcode-app-core (Phase B)

Split the 191K-loc application core into two separately-compiled rustc
units along its internal library dependency DAG:

- jcode-base (foundational layer, ~57K nontest loc / 58 modules): provider,
  auth, config, session, message, memory, telemetry, prompt, storage, and
  their supporting leaves. This is the downward-closed set the upper layer
  depends on (zero non-test edges back up to app-core).
- jcode-app-core (upper layer, ~77K nontest loc): the server/tool/agent SCC
  plus presentation-adjacent leaves (ambient, notifications, channel,
  external_auth, replay, setup_hints, update, ...). It re-exports jcode-base
  via , so every existing  path keeps
  resolving across both crates and the root jcode facade.

Measured peak rustc VmHWM (selfdev):
  baseline monolith        3.18  GiB
  Phase A app-core         2.643 GiB
  Phase B jcode-base       1.505 GiB
  Phase B jcode-app-core   1.621 GiB
  root jcode (cli+tui)     1.407 GiB
Largest compilation unit: 3.18 -> 1.62 GiB (-49%), and the three big units
are now balanced (1.41-1.62 GiB), well under the 15 GiB/no-swap OOM threshold
even with parallel jobs.

Mechanics:
- New crate crates/jcode-base (deps cloned from app-core; owns the jemalloc +
  embeddings features since process_memory/embedding moved here; pdf stays in
  app-core with tool/read.rs). Dev-dependency on jcode-app-core for the single
  cross-layer test (provider/gemini_tests.rs builds a tool::Registry); Cargo
  permits dev-dependency cycles and they do not affect the lib build.
- app-core forwards jemalloc/embeddings features to jcode-base; keeps pdf.
- git mv of 58 base modules (+ their #[path]-included *_tests.rs files,
  memory_prompt.rs, session_tests/) preserving history.
- Promote the cross-boundary provider state cluster (ProviderRuntimeState,
  ProviderStateEvent, ProviderModelSelectionSource + observed/apply/
  selected_model/selection_generation/user_selected_after) and
  process_title::set_server_title from pub(crate) to pub.
- Move the mission-continuation prompt asset's accessor into base's prompt
  module (pub const MISSION_CONTINUATION_TEMPLATE) since the asset lives with
  the other prompt templates; mission.rs (app-core) now references it.

Build: cargo check/build -p jcode --bin jcode exit 0; binary runs.
This commit is contained in:
jeremy
2026-05-29 04:28:36 -07:00
parent 4dd91a9c6c
commit 4aec863e24
213 changed files with 434 additions and 127 deletions
Generated
+131 -24
View File
@@ -3426,6 +3426,137 @@ dependencies = [
"jcode-auth-types",
"jcode-azure-auth",
"jcode-background-types",
"jcode-base",
"jcode-batch-types",
"jcode-build-meta",
"jcode-build-support",
"jcode-compaction-core",
"jcode-config-types",
"jcode-core",
"jcode-gateway-types",
"jcode-import-core",
"jcode-logging",
"jcode-memory-types",
"jcode-message-types",
"jcode-notify-email",
"jcode-overnight-core",
"jcode-pdf",
"jcode-plan",
"jcode-protocol",
"jcode-provider-core",
"jcode-provider-gemini",
"jcode-provider-metadata",
"jcode-provider-openai",
"jcode-provider-openrouter",
"jcode-selfdev-types",
"jcode-session-types",
"jcode-side-panel-types",
"jcode-storage",
"jcode-swarm-core",
"jcode-task-types",
"jcode-terminal-image",
"jcode-terminal-launch",
"jcode-tool-core",
"jcode-tool-types",
"jcode-tui-account-picker",
"jcode-tui-core",
"jcode-tui-markdown",
"jcode-tui-mermaid",
"jcode-tui-messages",
"jcode-tui-render",
"jcode-tui-session-picker",
"jcode-tui-style",
"jcode-tui-tool-display",
"jcode-tui-usage-overlay",
"jcode-tui-workspace",
"jcode-update-core",
"jcode-usage-types",
"libc",
"open",
"proctitle",
"qrcode",
"rand 0.9.3",
"ratatui",
"regex",
"reqwest",
"rustls 0.23.37",
"serde",
"serde_json",
"serde_yaml",
"sha2 0.10.9",
"similar",
"tar",
"tempfile",
"thiserror 1.0.69",
"tokio",
"tokio-stream",
"tokio-tungstenite",
"toml",
"unicode-width 0.2.0",
"url",
"urlencoding",
"uuid",
"walkdir",
"windows-sys 0.59.0",
]
[[package]]
name = "jcode-auth-types"
version = "0.1.0"
dependencies = [
"serde",
]
[[package]]
name = "jcode-azure-auth"
version = "0.1.0"
dependencies = [
"anyhow",
"azure_core",
"azure_identity",
]
[[package]]
name = "jcode-background-types"
version = "0.1.0"
dependencies = [
"serde",
]
[[package]]
name = "jcode-base"
version = "0.1.0"
dependencies = [
"agentgrep",
"anyhow",
"arboard",
"async-trait",
"aws-config",
"aws-credential-types",
"aws-sdk-bedrock",
"aws-sdk-bedrockruntime",
"aws-sdk-sts",
"aws-smithy-types",
"aws-types",
"base64 0.22.1",
"bytes",
"chrono",
"clap",
"crossterm",
"dirs",
"flate2",
"futures",
"glob",
"global-hotkey",
"hex",
"ignore",
"image",
"jcode-agent-runtime",
"jcode-ambient-types",
"jcode-app-core",
"jcode-auth-types",
"jcode-azure-auth",
"jcode-background-types",
"jcode-batch-types",
"jcode-build-meta",
"jcode-build-support",
@@ -3440,7 +3571,6 @@ dependencies = [
"jcode-message-types",
"jcode-notify-email",
"jcode-overnight-core",
"jcode-pdf",
"jcode-plan",
"jcode-protocol",
"jcode-provider-core",
@@ -3503,29 +3633,6 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "jcode-auth-types"
version = "0.1.0"
dependencies = [
"serde",
]
[[package]]
name = "jcode-azure-auth"
version = "0.1.0"
dependencies = [
"anyhow",
"azure_core",
"azure_identity",
]
[[package]]
name = "jcode-background-types"
version = "0.1.0"
dependencies = [
"serde",
]
[[package]]
name = "jcode-batch-types"
version = "0.1.0"
+2
View File
@@ -9,6 +9,8 @@ autobins = false
members = [
".",
"crates/jcode-agent-runtime",
"crates/jcode-app-core",
"crates/jcode-base",
"crates/jcode-build-meta",
"crates/jcode-ambient-types",
"crates/jcode-auth-types",
+16 -19
View File
@@ -15,10 +15,9 @@ name = "jcode_app_core"
path = "src/lib.rs"
[dependencies]
# Memory allocator (reduces fragmentation for long-running server)
tikv-jemallocator = { version = "0.6", features = ["unprefixed_malloc_on_supported_platforms"], optional = true }
tikv-jemalloc-ctl = { version = "0.6", optional = true }
tikv-jemalloc-sys = { version = "0.6", optional = true }
# NOTE: the jemalloc allocator stats live in `jcode-base` (process_memory) and
# local embeddings live in `jcode-base` (embedding); this crate forwards those
# features to jcode-base rather than depending on the backing crates directly.
# Async runtime
tokio = { version = "1", features = ["fs", "io-std", "io-util", "macros", "net", "process", "rt-multi-thread", "signal", "sync", "time"] }
@@ -56,8 +55,8 @@ urlencoding = "2" # URL encoding for web search
uuid = { version = "1", features = ["v4", "v5"] }
proctitle = "0.1"
# Embeddings (local inference) - behind feature flag (163 crates, slow to compile)
jcode-embedding = { path = "../jcode-embedding", optional = true }
# Embeddings (local inference) live in jcode-base; this crate forwards the
# `embeddings` feature to jcode-base rather than depending on jcode-embedding.
jcode-gateway-types = { path = "../jcode-gateway-types" }
jcode-import-core = { path = "../jcode-import-core" }
jcode-logging = { path = "../jcode-logging" }
@@ -114,6 +113,11 @@ jcode-background-types = { path = "../jcode-background-types" }
jcode-batch-types = { path = "../jcode-batch-types" }
jcode-build-support = { path = "../jcode-build-support" }
jcode-build-meta = { path = "../jcode-build-meta" }
# Foundational layer (provider, auth, config, session, message, memory, ...).
# Re-exported via `pub use jcode_base::*` in lib.rs. default-features=false so
# this crate controls jcode-base's optional features (see [features] below).
jcode-base = { path = "../jcode-base", default-features = false }
jcode-compaction-core = { path = "../jcode-compaction-core" }
jcode-config-types = { path = "../jcode-config-types" }
jcode-core = { path = "../jcode-core" }
@@ -147,19 +151,12 @@ aws-sdk-sts = "1.103.0"
[features]
default = ["pdf", "embeddings"]
jemalloc = [
"dep:tikv-jemallocator",
"dep:tikv-jemalloc-ctl",
"dep:tikv-jemalloc-sys",
"tikv-jemallocator/stats",
"tikv-jemalloc-ctl/stats",
]
jemalloc-prof = [
"jemalloc",
"tikv-jemallocator/profiling",
"tikv-jemalloc-ctl/profiling",
]
embeddings = ["dep:jcode-embedding"]
# jemalloc allocator stats live in jcode-base (process_memory); forward there.
jemalloc = ["jcode-base/jemalloc"]
jemalloc-prof = ["jcode-base/jemalloc-prof"]
# local embeddings live in jcode-base (embedding); forward there.
embeddings = ["jcode-base/embeddings"]
# PDF text extraction lives in this crate (tool/read.rs).
pdf = ["dep:jcode-pdf"]
[target.'cfg(windows)'.dependencies]
+13 -71
View File
@@ -6,102 +6,44 @@
clippy::useless_conversion
)]
//! Application core for jcode.
//! Application core for jcode (upper layer).
//!
//! This crate holds every non-presentation module (server, agent, provider,
//! auth, session, tool, config, memory, telemetry, ...) that used to live in
//! the monolithic root `jcode` crate. It is compiled as its own rustc unit so
//! the largest compilation unit (and its peak memory) is much smaller.
//!
//! The root `jcode` crate (cli + tui + bin) re-exports this crate's modules via
//! `pub use jcode_app_core::*`, so existing `crate::<module>` paths continue to
//! resolve unchanged.
//! This crate holds the server/tool/agent layer and its presentation-adjacent
//! leaves. The foundational layer it builds on (provider, auth, config, session,
//! message, memory, telemetry, ...) lives in the `jcode-base` crate and is
//! re-exported here via `pub use jcode_base::*`, so every existing
//! `crate::<module>` path (e.g. `crate::config`, `crate::provider`) keeps
//! resolving unchanged across this crate and the root `jcode` crate, which in
//! turn re-exports this crate via `pub use jcode_app_core::*`.
// Foundational layer: re-export every `jcode-base` module so `crate::<module>`
// paths resolve here exactly as they did before the split.
pub use jcode_base::*;
// Upper layer (server / tool / agent and supporting leaves).
pub mod agent;
pub mod ambient;
pub mod ambient_runner;
pub mod ambient_scheduler;
pub mod auth;
pub mod background;
pub mod browser;
pub mod build;
pub mod bus;
pub mod cache_tracker;
pub mod catchup;
pub mod channel;
pub mod client_input;
pub mod compaction;
pub mod config;
pub mod copilot_usage;
pub mod dictation;
#[cfg(feature = "embeddings")]
pub mod embedding;
#[cfg(not(feature = "embeddings"))]
pub mod embedding_stub;
#[cfg(not(feature = "embeddings"))]
pub use embedding_stub as embedding;
pub mod env;
pub mod external_auth;
pub mod gateway;
pub mod generated_image;
pub mod gmail;
pub mod goal;
pub mod id;
pub mod import;
pub mod live_tests;
pub mod logging;
pub mod login_qr;
pub mod mcp;
pub mod memory;
pub mod memory_agent;
pub mod memory_graph;
pub mod memory_log;
pub mod memory_types;
pub mod message;
pub mod mission;
pub mod network_retry;
pub mod notifications;
pub mod overnight;
pub mod perf;
pub mod plan;
pub mod platform;
pub mod process_memory;
pub mod process_title;
pub mod prompt;
pub mod protocol;
pub mod provider;
pub mod provider_catalog;
pub mod registry;
pub mod replay;
pub mod restart_snapshot;
pub mod runtime_memory_log;
pub mod safety;
pub mod secret_input;
pub mod server;
pub mod server_spawn;
pub mod session;
pub mod session_launch;
pub mod session_rebuild;
pub mod session_list_cache;
pub mod setup_hints;
pub mod side_panel;
pub mod sidecar;
pub mod skill;
pub mod soft_interrupt_store;
pub mod ssh_remote;
pub mod startup_profile;
pub mod stdin_detect;
pub mod storage;
pub mod subscription_catalog;
pub mod telegram;
pub mod telemetry;
pub mod terminal_launch;
pub mod todo;
pub mod tool;
pub mod transport;
pub mod update;
pub mod usage;
pub mod util;
use std::sync::Mutex;
+1 -1
View File
@@ -3,7 +3,7 @@ use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
const MISSION_CONTINUATION_TEMPLATE: &str = include_str!("prompt/mission_continuation.md");
use crate::prompt::MISSION_CONTINUATION_TEMPLATE;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
+175
View File
@@ -0,0 +1,175 @@
[package]
name = "jcode-base"
version = "0.1.0"
edition = "2024"
publish = false
# Foundational layer of the jcode application core: the downward-closed set of
# modules (provider, auth, config, session, message, memory, telemetry, ...)
# that the server/tool/agent layer depends on. Split out of `jcode-app-core` so
# the two halves compile as separate rustc units, halving peak compile memory.
# `jcode-app-core` re-exports this crate (`pub use jcode_base::*`) so that every
# existing `crate::<module>` path keeps resolving unchanged.
[lib]
name = "jcode_base"
path = "src/lib.rs"
[dependencies]
# Memory allocator (reduces fragmentation for long-running server)
tikv-jemallocator = { version = "0.6", features = ["unprefixed_malloc_on_supported_platforms"], optional = true }
tikv-jemalloc-ctl = { version = "0.6", optional = true }
tikv-jemalloc-sys = { version = "0.6", optional = true }
# Async runtime
tokio = { version = "1", features = ["fs", "io-std", "io-util", "macros", "net", "process", "rt-multi-thread", "signal", "sync", "time"] }
futures = "0.3"
async-trait = "0.1"
# HTTP client
reqwest = { version = "0.12", features = ["json", "stream", "blocking"] }
rustls = { version = "0.23", default-features = false, features = ["aws_lc_rs"] }
tokio-tungstenite = { version = "0.24", default-features = false, features = ["connect", "rustls-tls-native-roots"] }
# Serialization
serde = { version = "1", features = ["derive"] }
serde_json = { version = "1", features = ["raw_value"] }
serde_yaml = "0.9"
toml = "0.8"
# CLI
clap = { version = "4", features = ["derive"] }
# File operations
glob = "0.3"
ignore = "0.4" # gitignore-aware file walking
walkdir = "2"
similar = "2" # diffing for edits
# Utilities
dirs = "5" # home directory
anyhow = "1"
thiserror = "1"
libc = "0.2" # Unix system calls (flock)
chrono = { version = "0.4", features = ["serde"] }
regex = "1"
urlencoding = "2" # URL encoding for web search
uuid = { version = "1", features = ["v4", "v5"] }
proctitle = "0.1"
# Embeddings (local inference) - behind feature flag (163 crates, slow to compile)
jcode-embedding = { path = "../jcode-embedding", optional = true }
jcode-gateway-types = { path = "../jcode-gateway-types" }
jcode-import-core = { path = "../jcode-import-core" }
jcode-logging = { path = "../jcode-logging" }
# OAuth
base64 = "0.22"
sha2 = "0.10"
rand = "0.9.3"
hex = "0.4"
url = "2"
open = "5" # Open URLs in browser
jcode-auth-types = { path = "../jcode-auth-types" }
jcode-azure-auth = { path = "../jcode-azure-auth" }
jcode-agent-runtime = { path = "../jcode-agent-runtime" }
jcode-ambient-types = { path = "../jcode-ambient-types" }
jcode-notify-email = { path = "../jcode-notify-email" }
jcode-provider-metadata = { path = "../jcode-provider-metadata" }
jcode-provider-core = { path = "../jcode-provider-core" }
jcode-provider-openai = { path = "../jcode-provider-openai" }
jcode-provider-openrouter = { path = "../jcode-provider-openrouter" }
jcode-provider-gemini = { path = "../jcode-provider-gemini" }
jcode-tui-markdown = { path = "../jcode-tui-markdown" }
jcode-tui-messages = { path = "../jcode-tui-messages" }
jcode-tui-core = { path = "../jcode-tui-core" }
jcode-tui-mermaid = { path = "../jcode-tui-mermaid" }
jcode-tui-account-picker = { path = "../jcode-tui-account-picker" }
jcode-tui-render = { path = "../jcode-tui-render" }
jcode-tui-session-picker = { path = "../jcode-tui-session-picker", features = ["serde"] }
jcode-tui-style = { path = "../jcode-tui-style" }
jcode-tui-tool-display = { path = "../jcode-tui-tool-display" }
jcode-tui-usage-overlay = { path = "../jcode-tui-usage-overlay" }
jcode-update-core = { path = "../jcode-update-core" }
jcode-terminal-launch = { path = "../jcode-terminal-launch" }
jcode-terminal-image = { path = "../jcode-terminal-image" }
jcode-tui-workspace = { path = "../jcode-tui-workspace" }
jcode-usage-types = { path = "../jcode-usage-types" }
# Streaming
tokio-stream = "0.1"
bytes = "1"
# TUI
ratatui = "0.30"
crossterm = { version = "0.29", features = ["event-stream"] }
arboard = "3" # Clipboard support
image = { version = "0.25", default-features = false, features = ["png", "jpeg"] } # Only PNG/JPEG (skip avif/rav1e, exr, gif, tiff, etc)
# Markdown & syntax highlighting
unicode-width = "0.2" # Unicode character display width
# NOTE: PDF text extraction (jcode-pdf) lives in the upper jcode-app-core crate
# (tool/read.rs), not here.
jcode-background-types = { path = "../jcode-background-types" }
jcode-batch-types = { path = "../jcode-batch-types" }
jcode-build-support = { path = "../jcode-build-support" }
jcode-build-meta = { path = "../jcode-build-meta" }
jcode-compaction-core = { path = "../jcode-compaction-core" }
jcode-config-types = { path = "../jcode-config-types" }
jcode-core = { path = "../jcode-core" }
jcode-memory-types = { path = "../jcode-memory-types" }
jcode-message-types = { path = "../jcode-message-types" }
jcode-overnight-core = { path = "../jcode-overnight-core" }
jcode-plan = { path = "../jcode-plan" }
jcode-swarm-core = { path = "../jcode-swarm-core" }
jcode-protocol = { path = "../jcode-protocol" }
jcode-selfdev-types = { path = "../jcode-selfdev-types" }
jcode-session-types = { path = "../jcode-session-types" }
jcode-storage = { path = "../jcode-storage" }
jcode-task-types = { path = "../jcode-task-types" }
jcode-tool-core = { path = "../jcode-tool-core" }
jcode-tool-types = { path = "../jcode-tool-types" }
jcode-side-panel-types = { path = "../jcode-side-panel-types" }
# Archive extraction (for auto-update)
flate2 = "1"
tar = "0.4"
tempfile = "3"
agentgrep = { git = "https://github.com/1jehuang/agentgrep.git", tag = "v0.1.2" }
qrcode = { version = "0.14.1", default-features = false }
aws-config = "1.8.16"
aws-credential-types = "1.2.14"
aws-sdk-bedrockruntime = "1.130.0"
aws-types = "1.3.15"
aws-smithy-types = "1.4.7"
aws-sdk-bedrock = "1.141.0"
aws-sdk-sts = "1.103.0"
[features]
default = ["embeddings"]
jemalloc = [
"dep:tikv-jemallocator",
"dep:tikv-jemalloc-ctl",
"dep:tikv-jemalloc-sys",
"tikv-jemallocator/stats",
"tikv-jemalloc-ctl/stats",
]
jemalloc-prof = [
"jemalloc",
"tikv-jemallocator/profiling",
"tikv-jemalloc-ctl/profiling",
]
embeddings = ["dep:jcode-embedding"]
[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.59", features = ["Win32_Foundation", "Win32_System_Threading"] }
[target.'cfg(target_os = "macos")'.dependencies]
global-hotkey = "0.7"
[dev-dependencies]
# Cross-layer test (provider/gemini_tests.rs builds a tool::Registry, which lives
# in the upper jcode-app-core layer). Dev-dependency cycles are permitted by
# Cargo and do not affect the library build.
jcode-app-core = { path = "../jcode-app-core", default-features = false }
+82
View File
@@ -0,0 +1,82 @@
//! `jcode-base`: foundational layer of the jcode application core.
//!
//! This crate holds the downward-closed set of modules that the upper
//! server/tool/agent layer (`jcode-app-core`) depends on: provider, auth,
//! config, session, message, memory, telemetry, and their supporting leaves.
//! Splitting it out lets the two halves compile as separate rustc units so the
//! largest compilation unit (and its peak memory) is roughly halved.
//!
//! `jcode-app-core` re-exports this crate via `pub use jcode_base::*`, so every
//! existing `crate::<module>` path in the upper layers keeps resolving.
#![allow(
unknown_lints,
clippy::collapsible_match,
clippy::manual_checked_ops,
clippy::unnecessary_sort_by,
clippy::useless_conversion
)]
pub mod auth;
pub mod background;
pub mod browser;
pub mod build;
pub mod bus;
pub mod cache_tracker;
pub mod client_input;
pub mod compaction;
pub mod config;
pub mod copilot_usage;
pub mod dictation;
pub mod env;
pub mod gateway;
pub mod generated_image;
pub mod gmail;
pub mod goal;
pub mod id;
pub mod import;
pub mod live_tests;
pub mod logging;
pub mod login_qr;
pub mod mcp;
pub mod memory;
pub mod memory_agent;
pub mod memory_graph;
pub mod memory_log;
pub mod memory_types;
pub mod message;
pub mod plan;
pub mod platform;
pub mod process_memory;
pub mod process_title;
pub mod prompt;
pub mod protocol;
pub mod provider;
pub mod provider_catalog;
pub mod registry;
pub mod runtime_memory_log;
pub mod safety;
pub mod secret_input;
pub mod session;
pub mod session_list_cache;
pub mod side_panel;
pub mod sidecar;
pub mod skill;
pub mod soft_interrupt_store;
pub mod stdin_detect;
pub mod storage;
pub mod subscription_catalog;
pub mod telegram;
pub mod telemetry;
pub mod terminal_launch;
pub mod todo;
pub mod transport;
pub mod usage;
pub mod util;
#[cfg(feature = "embeddings")]
pub mod embedding;
#[cfg(not(feature = "embeddings"))]
pub mod embedding_stub;
#[cfg(not(feature = "embeddings"))]
pub use embedding_stub as embedding;

Some files were not shown because too many files have changed in this diff Show More