Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
1d0b442
chore: migrate workspace to nightly-2026-08-14 with Cranelift for dev…
w0wl0lxd Aug 14, 2026
93f0514
fix(ci): keep the Coverage job on LLVM codegen
w0wl0lxd Aug 14, 2026
1e763f9
fix(ci): keep the Linux Test job on LLVM codegen and fix nightly lints
w0wl0lxd Aug 14, 2026
4c926ae
fix: resolve nightly clippy lints and cargo config issues
w0wl0lxd Aug 14, 2026
04e2f88
fix: replace remaining disallowed unwrap_or uses flagged by nightly c…
w0wl0lxd Aug 15, 2026
9ca26b3
Merge remote-tracking branch 'origin/main' into HEAD
w0wl0lxd Aug 15, 2026
8cc2d7b
chore: drop rust-version inherit in n00n-git for nightly workspace
w0wl0lxd Aug 15, 2026
9a8b7f4
chore(lint): allow clippy::assert_is_empty for the nightly toolchain
w0wl0lxd Aug 15, 2026
a058c35
fix(redact): replace useless format! in test fixture
w0wl0lxd Aug 15, 2026
a77a4c4
refactor: replace identity map_or with unwrap_or_else and fix Result …
w0wl0lxd Aug 15, 2026
db3fec6
refactor: fix identity map_or call sites and allow result_large_err
w0wl0lxd Aug 15, 2026
c1b4ed3
refactor: convert remaining identity map_or calls in n00n-acp
w0wl0lxd Aug 15, 2026
b26a3dc
refactor: convert final identity map_or calls in theme
w0wl0lxd Aug 15, 2026
d844c87
refactor: apply newer nightly clippy suggestions across the UI and Lu…
w0wl0lxd Aug 15, 2026
0c19ae1
fix(ci): align release toolchain with the nightly pin and drop unused…
w0wl0lxd Aug 15, 2026
100ec05
Merge remote-tracking branch 'origin/main' into HEAD
w0wl0lxd Aug 15, 2026
8b7fa17
merge: bring in n00n-smell and drop its rust-version inherit for nightly
w0wl0lxd Aug 15, 2026
4d615d5
refactor: fix identity map_or in smell result preview
w0wl0lxd Aug 15, 2026
21c8f00
fix: address CodeRabbit review on the nightly migration
w0wl0lxd Aug 15, 2026
29bd01b
fix: scope result_large_err allows to the actual websocket functions
w0wl0lxd Aug 15, 2026
e01de2b
chore(lint): allow result_large_err workspace-wide after all
w0wl0lxd Aug 15, 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
3 changes: 2 additions & 1 deletion .github/workflows/benchmarks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
- uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # master
with:
toolchain: nightly-2026-08-14
components: rustfmt
- uses: Swatinem/rust-cache@23869a5bd66c73db3c0ac40331f3206eb23791dc # v2.9.1
with:
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ jobs:
- uses: 'actions/checkout@11d5960a326750d5838078e36cf38b85af677262' # v4
with:
persist-credentials: false
- uses: 'dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4' # stable
- uses: 'dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772' # master
with:
toolchain: nightly-2026-08-14
- uses: 'Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32' # v2
with:
shared-key: 'linux-stable'
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ jobs:
git config --global --add safe.directory /workspace
curl --proto "=https" --tlsv1.2 --retry 5 --retry-delay 2 \
--retry-all-errors -sSf https://sh.rustup.rs | \
sh -s -- -y --default-toolchain stable --target ${{ matrix.target }}
sh -s -- -y --default-toolchain nightly-2026-08-14 --target ${{ matrix.target }}
source "$HOME/.cargo/env"
cargo build --release --target ${{ matrix.target }}
'
Expand Down Expand Up @@ -106,7 +106,7 @@ jobs:
with:
persist-credentials: false
- name: Install Rust toolchain
run: rustup target add ${{ matrix.target }}
run: rustup toolchain install nightly-2026-08-14 --profile minimal --target ${{ matrix.target }}

- name: Build
run: cargo build --release --target ${{ matrix.target }}
Expand Down
19 changes: 2 additions & 17 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,9 @@ jobs:
- uses: 'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1' # v7
with:
persist-credentials: false
- uses: 'dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4' # stable
- uses: 'dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772' # master
with:
toolchain: nightly-2026-08-14
components: llvm-tools-preview
- uses: 'Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32' # v2
with:
Expand All @@ -258,21 +259,6 @@ jobs:
files: lcov.info
fail_ci_if_error: false
token: ${{ secrets.CODECOV_TOKEN }}
msrv:
name: MSRV (1.97)
needs: changes
if: needs.changes.outputs.code == 'true'
runs-on: ubuntu-latest
steps:
- uses: 'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1' # v7
with:
persist-credentials: false
- uses: 'dtolnay/rust-toolchain@35a842e360814583e976785eeda0bd0655cb8e83' # 1.97.0
- uses: 'Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32' # v2
with:
shared-key: 'linux-msrv'
save-if: ${{ github.ref == 'refs/heads/main' }}
- run: cargo build --workspace --all-targets
rustdoc:
name: Rustdoc
needs: changes
Expand Down Expand Up @@ -304,7 +290,6 @@ jobs:
- build-windows
- test-windows
- coverage
- msrv
- rustdoc
runs-on: ubuntu-latest
steps:
Expand Down
9 changes: 5 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ homepage = "https://github.com/w0wl0lxd/n00n"
readme = "README.md"
keywords = ["ai", "agent", "cli", "tui", "coding"]
categories = ["command-line-utilities", "development-tools"]
rust-version = "1.97"

[[bin]]
name = "n00n"
Expand Down Expand Up @@ -89,7 +88,6 @@ edition = "2024"
authors = ["w0wl0lxd <w0wl0lxd@tuta.com>"]
license = "AGPL-3.0-only"
repository = "https://github.com/w0wl0lxd/n00n"
rust-version = "1.97"

[workspace.dependencies]
n00n-agent = { path = "n00n-agent" }
Expand Down Expand Up @@ -330,11 +328,14 @@ clone_on_ref_ptr = "deny"
redundant_clone = "deny"
manual_assert = "deny"
disallowed_methods = "deny"
# These style lints suggest `unwrap_or`/`unwrap_or_default`, which are
# disallowed above; allowing them avoids clippy auto-fix introducing banned methods.
# These style lints suggest `unwrap_or`/`unwrap_or_default`/`assert_eq!`,
# which the workspace bans or does not use at scale; allowing them avoids
# clippy auto-fix introducing banned methods or mass-rewriting test asserts.
unnecessary_lazy_evaluations = "allow"
unnecessary_map_or = "allow"
unwrap_or_default = "allow"
assert_is_empty = "allow"
result_large_err = "allow"

[profile.bench]
debug = true
1 change: 1 addition & 0 deletions changelog.d/nightly-toolchain-cranelift.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
n00n now builds on the pinned nightly-2026-08-14 Rust toolchain instead of stable. CI toolchain steps were switched to nightly, the MSRV job was removed since the pinned-nightly policy has no minimum supported version, and the `rust-version` field was dropped from all workspace manifests accordingly.
1 change: 0 additions & 1 deletion n00n-acp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ edition.workspace = true
license.workspace = true
authors.workspace = true
repository.workspace = true
rust-version.workspace = true

[dependencies]
n00n-agent = { workspace = true }
Expand Down
10 changes: 3 additions & 7 deletions n00n-acp/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,7 @@ fn start_event_pump(

fn next_request_id(counter: &AtomicI64) -> Option<RequestId> {
counter
.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |id| id.checked_add(1))
.try_update(Ordering::Relaxed, Ordering::Relaxed, |id| id.checked_add(1))
.ok()
.and_then(|id| id.checked_add(1))
.map(RequestId::Number)
Expand Down Expand Up @@ -694,12 +694,8 @@ fn no_session() -> AcpError {
}

fn parse_params<T: serde::de::DeserializeOwned>(raw: &Value) -> Result<T, AcpError> {
serde_json::from_value(
raw.get("params")
.cloned()
.map_or(Value::Null, std::convert::identity),
)
.map_err(|e| AcpError::invalid_params().data(json_str(&e)))
serde_json::from_value(raw.get("params").cloned().unwrap_or_else(|| Value::Null))
.map_err(|e| AcpError::invalid_params().data(json_str(&e)))
}

fn json_str(e: &impl std::fmt::Display) -> Value {
Expand Down
2 changes: 1 addition & 1 deletion n00n-acp/src/translate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ fn fenced(text: &str) -> String {
.split(|c: char| c != '`')
.map(str::len)
.max()
.map_or(0, std::convert::identity);
.unwrap_or_else(|| 0);
let fence = "`".repeat(MIN_FENCE_LEN.max(longest_backtick_run + 1));
format!("{fence}\n{text}\n{fence}")
}
Expand Down
1 change: 0 additions & 1 deletion n00n-agent/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ edition.workspace = true
license.workspace = true
authors.workspace = true
repository.workspace = true
rust-version.workspace = true

[dependencies]
n00n-providers = { workspace = true }
Expand Down
5 changes: 2 additions & 3 deletions n00n-agent/src/agent/tool_dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,7 @@ fn skill_policy_denied(name: &str, ctx: &ToolContext) -> Option<String> {
}

fn is_skill_tool_call(name: &str) -> bool {
name.strip_prefix("functions.").map_or(name, |value| value)
== crate::skill_policy::SKILL_TOOL_NAME
name.strip_prefix("functions.").unwrap_or_else(|| name) == crate::skill_policy::SKILL_TOOL_NAME
}

fn is_subagent_failure(event: &ToolDoneEvent, ctx: &ToolContext) -> bool {
Expand Down Expand Up @@ -366,7 +365,7 @@ async fn run_authorized(
fusion_delegate_authorized: bool,
) -> ToolDoneEvent {
// GPT-5.6 was likely trained on Codex sessions where tools are `functions.<name>`
let name = name.strip_prefix("functions.").map_or(name, |value| value);
let name = name.strip_prefix("functions.").unwrap_or_else(|| name);
if !ctx.tool_filter.matches(name) {
return tool_done_error(id, Arc::from(name), TOOL_FILTER_DENIED.into());
}
Expand Down
1 change: 0 additions & 1 deletion n00n-codegraph/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ edition.workspace = true
authors.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true

# Targets CodeGraph 1.5.0 CLI for command expansion (callers, callees, impact, affected, node, query, sync, files)
# Falls back to CLI when native SQLite queries are not available
Expand Down
1 change: 0 additions & 1 deletion n00n-config-macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ edition.workspace = true
license.workspace = true
authors.workspace = true
repository.workspace = true
rust-version.workspace = true

[lib]
proc-macro = true
Expand Down
1 change: 0 additions & 1 deletion n00n-config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ edition.workspace = true
license.workspace = true
authors.workspace = true
repository.workspace = true
rust-version.workspace = true

[dependencies]
n00n-config-macro = { workspace = true }
Expand Down
56 changes: 31 additions & 25 deletions n00n-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ impl CompactionBuffer {
match self {
Self::Tokens(n) => n,
Self::Percent(p) => u32::try_from(u64::from(context_window) * u64::from(p) / 100)
.map_or(u32::MAX, |v| v),
.unwrap_or_else(|_| u32::MAX),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
}
}
Expand Down Expand Up @@ -990,7 +990,9 @@ impl UiConfig {
splash_animation: f.splash_animation.is_none_or(|v| v),
mascot: f.mascot.is_none_or(|v| v),
scrollbar: f.scrollbar.is_none_or(|v| v),
flash_duration_ms: f.flash_duration_ms.map_or(DEFAULT_FLASH_DURATION_MS, |v| v),
flash_duration_ms: f
.flash_duration_ms
.unwrap_or_else(|| DEFAULT_FLASH_DURATION_MS),
typewriter_ms_per_char: f
.typewriter_ms_per_char
.unwrap_or_else(|| DEFAULT_TYPEWRITER_MS_PER_CHAR),
Expand Down Expand Up @@ -1066,17 +1068,17 @@ impl ToolOutputLines {
let d = Self::DEFAULT;
let f = f.unwrap_or_else(ToolOutputLinesFile::default);
Self {
bash: f.bash.map_or(d.bash, |v| v),
code_execution: f.code_execution.map_or(d.code_execution, |v| v),
task: f.task.map_or(d.task, |v| v),
workflow: f.workflow.map_or(d.workflow, |v| v),
index: f.index.map_or(d.index, |v| v),
grep: f.grep.map_or(d.grep, |v| v),
explore: f.explore.map_or(d.explore, |v| v),
read: f.read.map_or(d.read, |v| v),
write: f.write.map_or(d.write, |v| v),
web: f.web.map_or(d.web, |v| v),
other: f.other.map_or(d.other, |v| v),
bash: f.bash.unwrap_or_else(|| d.bash),
code_execution: f.code_execution.unwrap_or_else(|| d.code_execution),
task: f.task.unwrap_or_else(|| d.task),
workflow: f.workflow.unwrap_or_else(|| d.workflow),
index: f.index.unwrap_or_else(|| d.index),
grep: f.grep.unwrap_or_else(|| d.grep),
explore: f.explore.unwrap_or_else(|| d.explore),
read: f.read.unwrap_or_else(|| d.read),
write: f.write.unwrap_or_else(|| d.write),
web: f.web.unwrap_or_else(|| d.web),
other: f.other.unwrap_or_else(|| d.other),
}
}

Expand Down Expand Up @@ -1246,7 +1248,7 @@ impl AgentConfig {

let fusion = if let Some(ff) = file.fusion {
FusionConfig {
enabled: ff.enabled.map_or(false, |enabled| enabled),
enabled: ff.enabled.unwrap_or_else(|| false),
lead_model: ff
.lead_model
.unwrap_or_else(|| DEFAULT_FUSION_LEAD_MODEL.to_owned()),
Expand All @@ -1258,7 +1260,7 @@ impl AgentConfig {
.unwrap_or_else(|| DEFAULT_FUSION_SIDEKICK_THINKING.to_owned()),
sidekick_tier: ff
.sidekick_tier
.map_or(crate::providers::Tier::Weak, |tier| tier),
.unwrap_or_else(|| crate::providers::Tier::Weak),
}
} else {
FusionConfig::default()
Expand All @@ -1268,10 +1270,10 @@ impl AgentConfig {
no_rtk,
max_output_bytes: file
.max_output_bytes
.map_or(DEFAULT_MAX_OUTPUT_BYTES, |v| v),
.unwrap_or_else(|| DEFAULT_MAX_OUTPUT_BYTES),
max_output_lines: file
.max_output_lines
.map_or(DEFAULT_MAX_OUTPUT_LINES, |v| v),
.unwrap_or_else(|| DEFAULT_MAX_OUTPUT_LINES),
max_continuation_turns: file
.max_continuation_turns
.unwrap_or_else(|| DEFAULT_MAX_CONTINUATION_TURNS),
Expand Down Expand Up @@ -1357,19 +1359,19 @@ impl ProviderConfig {
default_model: f.default_model,
connect_timeout: Duration::from_secs(
f.connect_timeout_secs
.map_or(DEFAULT_CONNECT_TIMEOUT_SECS, |v| v),
.unwrap_or_else(|| DEFAULT_CONNECT_TIMEOUT_SECS),
),
low_speed_timeout: Duration::from_secs(
f.low_speed_timeout_secs
.map_or(DEFAULT_LOW_SPEED_TIMEOUT_SECS, |v| v),
.unwrap_or_else(|| DEFAULT_LOW_SPEED_TIMEOUT_SECS),
),
stream_timeout: Duration::from_secs(
f.stream_timeout_secs
.map_or(DEFAULT_STREAM_TIMEOUT_SECS, |v| v),
.unwrap_or_else(|| DEFAULT_STREAM_TIMEOUT_SECS),
),
openai_coding_plan_slots: f
.openai_coding_plan_slots
.map_or(DEFAULT_OPENAI_CODING_PLAN_SLOTS, |slots| slots),
.unwrap_or_else(|| DEFAULT_OPENAI_CODING_PLAN_SLOTS),
}
}

Expand Down Expand Up @@ -1434,11 +1436,15 @@ impl Default for StorageConfig {
impl StorageConfig {
fn from_file(f: &StorageFileConfig) -> Self {
Self {
max_log_bytes: f.max_log_bytes_mb.map_or(DEFAULT_MAX_LOG_BYTES_MB, |v| v) * 1024 * 1024,
max_log_files: f.max_log_files.map_or(DEFAULT_MAX_LOG_FILES, |v| v),
max_log_bytes: f
.max_log_bytes_mb
.unwrap_or_else(|| DEFAULT_MAX_LOG_BYTES_MB)
* 1024
* 1024,
max_log_files: f.max_log_files.unwrap_or_else(|| DEFAULT_MAX_LOG_FILES),
input_history_size: f
.input_history_size
.map_or(DEFAULT_INPUT_HISTORY_SIZE, |v| v),
.unwrap_or_else(|| DEFAULT_INPUT_HISTORY_SIZE),
}
}
}
Expand Down Expand Up @@ -1753,7 +1759,7 @@ fn build_permissions(
global: &PermissionsFileConfig,
project: &PermissionsFileConfig,
) -> PermissionsConfig {
let global_default = global.default.map_or(DefaultEffect::Prompt, |v| v);
let global_default = global.default.unwrap_or_else(|| DefaultEffect::Prompt);
let default = if let Some(d) = project.default
&& d != DefaultEffect::Allow
{
Expand Down
1 change: 0 additions & 1 deletion n00n-daemon/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ description = "On-device agent control plane: registry, UDS NDJSON protocol, wor
license.workspace = true
authors.workspace = true
repository.workspace = true
rust-version.workspace = true

[dependencies]
n00n-storage = { workspace = true }
Expand Down
1 change: 0 additions & 1 deletion n00n-docgen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ edition.workspace = true
authors.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true

[[bin]]
name = "n00n-docgen"
Expand Down
1 change: 0 additions & 1 deletion n00n-git/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ edition.workspace = true
authors.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true
description = "Native git operations using gix/gitoxide for n00n"

[[bin]]
Expand Down
1 change: 0 additions & 1 deletion n00n-highlight/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ edition.workspace = true
authors.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true

[dependencies]
serde_json = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion n00n-highlight/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ pub fn syntax_for_path(path: &str) -> &'static SyntaxReference {
.ok()
.flatten()
.unwrap_or_else(|| {
let ext = path.rsplit('.').next().map_or(path, |ext| ext);
let ext = path.rsplit('.').next().unwrap_or_else(|| path);
syntax_for_token(ext)
})
}
Expand Down
1 change: 0 additions & 1 deletion n00n-interpreter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ edition.workspace = true
license.workspace = true
authors.workspace = true
repository.workspace = true
rust-version.workspace = true

[dependencies]
monty = { workspace = true }
Expand Down
1 change: 0 additions & 1 deletion n00n-lua-macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ edition.workspace = true
license.workspace = true
authors.workspace = true
repository.workspace = true
rust-version.workspace = true

[lib]
proc-macro = true
Expand Down
Loading
Loading