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
10 changes: 6 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -586,11 +586,13 @@ The mobile app lives in `mobile/` — a Flutter app using Riverpod + Hooks.
over raw `Theme.of(context)` calls.
- **Keep widgets small and composable.** One public widget per file; push
private sub-widgets (`_Foo`) into sibling `part` files under a
`<page>/` folder rather than growing the page file. Hard ceiling:
**1000 lines/file**, enforced across Desktop, Web, and Mobile by the
`<page>/` folder rather than growing the page file. Mobile's hard ceiling is
**1200 lines/file**, enforced with the other surface-specific limits by the
repository-level `just file-size-check` gate (`just check`, CI, and every
pre-push). If the guard trips, **split the file — never bump the limit or add
an override to slip under it.**
pre-push). If an individual file trips the guard, **split the file — never
bump a surface limit or add an override merely to admit that file.**
Deliberate repository-wide policy revisions must update the enforced rules,
tests, and guidance together.
- Feature modules must not import from other feature modules — only from
`shared/`.
- Use `Grid` tokens for spacing, `Radii` for border radius.
Expand Down
66 changes: 13 additions & 53 deletions desktop/scripts/check-file-sizes.mjs
Original file line number Diff line number Diff line change
@@ -1,61 +1,21 @@
import { realpathSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { runFileSizeCheck } from "../../scripts/check-file-sizes-core.mjs";
import { rules } from "./file-size-policy.mjs";

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const projectRoot = path.resolve(__dirname, "..");
const scriptPath = realpathSync(fileURLToPath(import.meta.url));
const projectRoot = path.resolve(path.dirname(scriptPath), "..");

const MAX_LINES = 1000;

const rules = [
{ root: "src-tauri/src", extensions: new Set([".rs"]), maxLines: MAX_LINES },
// Workspace member crates. Without this the ratchet's only Rust root is
// `src-tauri/src`, and a crate under `src-tauri/crates/` is born outside the
// repo's one size discipline -- silently, since the check still exits 0.
{
root: "src-tauri/crates",
extensions: new Set([".rs"]),
maxLines: MAX_LINES,
},
{
root: "src/app",
extensions: new Set([".ts", ".tsx"]),
maxLines: MAX_LINES,
},
{
root: "src/features",
extensions: new Set([".ts", ".tsx"]),
maxLines: MAX_LINES,
},
{
root: "src/shared/api",
extensions: new Set([".ts", ".tsx"]),
maxLines: MAX_LINES,
},
{
root: "src/shared/context",
extensions: new Set([".ts", ".tsx"]),
maxLines: MAX_LINES,
},
{
root: "src/shared/lib",
extensions: new Set([".ts", ".tsx"]),
maxLines: MAX_LINES,
},
{
root: "src/shared/ui",
extensions: new Set([".ts", ".tsx"]),
maxLines: MAX_LINES,
},
{
root: "src/shared/styles",
extensions: new Set([".css"]),
maxLines: MAX_LINES,
},
];

await runFileSizeCheck({
export const policy = {
projectRoot,
rules,
label: "Desktop",
});
};

if (
process.argv[1] &&
realpathSync(path.resolve(process.argv[1])) === scriptPath
) {
await runFileSizeCheck(policy);
}
53 changes: 53 additions & 0 deletions desktop/scripts/file-size-policy.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
const DESKTOP_FRONTEND_MAX_LINES = 1200;
const DESKTOP_RUST_MAX_LINES = 1500;

export const rules = [
{
root: "src-tauri/src",
extensions: new Set([".rs"]),
maxLines: DESKTOP_RUST_MAX_LINES,
},
// Workspace member crates. Without this the ratchet's only Rust root is
// `src-tauri/src`, and a crate under `src-tauri/crates/` is born outside the
// repo's one size discipline -- silently, since the check still exits 0.
{
root: "src-tauri/crates",
extensions: new Set([".rs"]),
maxLines: DESKTOP_RUST_MAX_LINES,
},
{
root: "src/app",
extensions: new Set([".ts", ".tsx"]),
maxLines: DESKTOP_FRONTEND_MAX_LINES,
},
{
root: "src/features",
extensions: new Set([".ts", ".tsx"]),
maxLines: DESKTOP_FRONTEND_MAX_LINES,
},
{
root: "src/shared/api",
extensions: new Set([".ts", ".tsx"]),
maxLines: DESKTOP_FRONTEND_MAX_LINES,
},
{
root: "src/shared/context",
extensions: new Set([".ts", ".tsx"]),
maxLines: DESKTOP_FRONTEND_MAX_LINES,
},
{
root: "src/shared/lib",
extensions: new Set([".ts", ".tsx"]),
maxLines: DESKTOP_FRONTEND_MAX_LINES,
},
{
root: "src/shared/ui",
extensions: new Set([".ts", ".tsx"]),
maxLines: DESKTOP_FRONTEND_MAX_LINES,
},
{
root: "src/shared/styles",
extensions: new Set([".css"]),
maxLines: DESKTOP_FRONTEND_MAX_LINES,
},
];
2 changes: 1 addition & 1 deletion desktop/src-tauri/src/archive/metric_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
//! via [`AgentMetricIndexRow::from_payload`].
//!
//! Kept in a sibling file (not `store.rs`) to keep that file under the
//! 1000-line gate, per the existing `pipeline.rs` precedent.
//! 1500-line gate, per the existing `pipeline.rs` precedent.

use rusqlite::{params, Connection, OptionalExtension};

Expand Down
2 changes: 1 addition & 1 deletion desktop/src-tauri/src/archive/mod_agent_metric_tests.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Kind-44200 (NIP-AM agent turn metric) archive and `get_agent_usage_series`
//! integration tests for `archive/mod.rs`.
//!
//! Kept in a sibling file so `mod_tests.rs` stays under the 1000-line gate;
//! Kept in a sibling file so `mod_tests.rs` stays under the 1500-line gate;
//! `#[path]`-included from there so the shared fixtures (`in_memory`,
//! `add_sub`, `candidate`, `make_observer_frame`, `run_batch_sync_with_keys`)
//! stay private to `mod_tests`.
Expand Down
4 changes: 2 additions & 2 deletions desktop/src-tauri/src/archive/mod_tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Unit and integration tests for `archive/mod.rs`.
//!
//! Kept in a sibling file so `mod.rs` stays under the 1000-line gate;
//! Kept in a sibling file so `mod.rs` stays under the 1500-line gate;
//! `#[path]`-included from there.

use super::pipeline::BucketWithResult;
Expand Down Expand Up @@ -622,7 +622,7 @@ fn test_commit_archive_rolls_back_when_scope_write_would_fail() {
}

// Kind-44200 agent-turn-metric coverage lives in a sibling file to keep this
// one under the 1000-line gate; nested here (not in `mod.rs`) so it inherits
// one under the 1500-line gate; nested here (not in `mod.rs`) so it inherits
// the shared fixtures above through `use super::*`.
#[path = "mod_agent_metric_tests.rs"]
mod agent_metric;
Expand Down
2 changes: 1 addition & 1 deletion desktop/src-tauri/src/archive/pipeline.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Archive pipeline — three-phase plan/query/commit split.
//!
//! Separated from `mod.rs` to keep that file under the 1000-line gate.
//! Separated from `mod.rs` to keep that file under the 1500-line gate.
//!
//! # Send-safety
//!
Expand Down
2 changes: 1 addition & 1 deletion desktop/src-tauri/src/archive/retention.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
//! Phase-2 prune scan, the get/set accessors for the observer window, and the
//! PRAGMA-based size readout. The prune worker itself lands in Phase 2.
//!
//! Kept in a sibling file (not `store.rs`) to respect the 1000-line gate, per
//! Kept in a sibling file (not `store.rs`) to respect the 1500-line gate, per
//! the existing `metric_store.rs` / `pipeline.rs` / `store_migrations.rs`
//! precedent.

Expand Down
2 changes: 1 addition & 1 deletion desktop/src-tauri/src/archive/retention_tests.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Behavior tests for the observer-retention setting, the size readout, and the
//! M4 migration.
//!
//! Kept in a sibling file so `retention.rs` stays under the 1000-line gate;
//! Kept in a sibling file so `retention.rs` stays under the 1500-line gate;
//! `#[path]`-included from there. `super::*` brings the retention API (and its
//! `rusqlite::{params, Connection}` imports) into scope; `super::super::store`
//! reaches the neighbouring subscription mutators and the base `SCHEMA`.
Expand Down
2 changes: 1 addition & 1 deletion desktop/src-tauri/src/archive/store_migration_tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Migration tests for `archive/store.rs` — M1: harness column.
//!
//! Kept in a sibling file so `store_tests.rs` stays under the 1000-line gate;
//! Kept in a sibling file so `store_tests.rs` stays under the 1500-line gate;
//! `#[path]`-included from `store.rs`.

use super::*;
Expand Down
2 changes: 1 addition & 1 deletion desktop/src-tauri/src/archive/store_migrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//! `archive_migrations`, so a migration that already ran is a no-op.
//!
//! Kept in a sibling file (not `store.rs`) to keep that file under the
//! 1000-line gate, per the existing `metric_store.rs` / `pipeline.rs`
//! 1500-line gate, per the existing `metric_store.rs` / `pipeline.rs`
//! precedent.

use rusqlite::{params, Connection};
Expand Down
2 changes: 1 addition & 1 deletion desktop/src-tauri/src/archive/store_tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Unit tests for `archive/store.rs`.
//!
//! Kept in a sibling file so `store.rs` stays under the 1000-line gate;
//! Kept in a sibling file so `store.rs` stays under the 1500-line gate;
//! `#[path]`-included from there.

use super::*;
Expand Down
2 changes: 1 addition & 1 deletion desktop/src-tauri/src/commands/agent_config_tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! Unit tests for `commands/agent_config.rs` (split to keep `agent_config.rs`
//! under the 1000-line file-size ratchet).
//! under the 1500-line file-size ratchet).
//!
//! Included via `#[path = "agent_config_tests.rs"] mod tests;` at the bottom of
//! `agent_config.rs`, so `use super::*` gives access to all items in that module.
Expand Down
2 changes: 1 addition & 1 deletion desktop/src-tauri/src/commands/personas/card/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! Unit tests for `card.rs` — split into a child module file so the parent
//! stays under the 1000-line gate (same layout as `snapshot/tests.rs`).
//! stays under the 1500-line gate (same layout as `snapshot/tests.rs`).

use super::*;
use std::collections::BTreeMap;
Expand Down
2 changes: 1 addition & 1 deletion desktop/src-tauri/src/commands/personas/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! and their supporting helpers.
//!
//! Import-side commands and helpers live in `snapshot::import` to keep this
//! file under the 1000-line gate.
//! file under the 1500-line gate.
//!
//! Split from `personas/mod.rs` to keep that file under the line-count gate.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Import-side helpers for `buzz-agent-snapshot v1`.
//!
//! Extracted from `snapshot.rs` to keep that file under the 1000-line gate.
//! Extracted from `snapshot.rs` to keep that file under the 1500-line gate.
//! The Tauri commands here (`preview_agent_snapshot_import`,
//! `confirm_agent_snapshot_import`) are re-exported from `snapshot.rs` and
//! registered in `lib.rs` through the same `personas::` path as the export
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Export-size guard tests for `validate_snapshot_encode_size`.
//!
//! Kept in a sibling file so `snapshot/tests.rs` stays under the
//! 1000-line gate; `#[path]`-included from there as a child module,
//! 1500-line gate; `#[path]`-included from there as a child module,
//! so `super::*` still resolves to the shared test imports.
//!
//! Tests call `validate_snapshot_encode_size` directly so they prove the
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Locked-card import tests for `decode_snapshot_for_import`.
//!
//! Kept in a sibling file so `snapshot/tests.rs` stays under the
//! 1000-line gate; `#[path]`-included from there as a child module,
//! 1500-line gate; `#[path]`-included from there as a child module,
//! so `super::*` still resolves to the shared test helpers.

use super::*;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Tests for `memory_entries_from_listing` — the shared level → entries
//! selection used by both snapshot export and card minting. Split from
//! `tests.rs` to keep that file under the 1000-line gate; `#[path]`-included
//! `tests.rs` to keep that file under the 1500-line gate; `#[path]`-included
//! from there as a child module, so `super::*` resolves to `tests`'s parent
//! scope re-exports.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Unit tests for `managed_agents/agent_snapshot.rs`.
//!
//! Kept in a sibling file so `agent_snapshot.rs` stays under the
//! 1000-line gate; `#[path]`-included from there.
//! 1500-line gate; `#[path]`-included from there.

use super::*;
use crate::managed_agents::types::{BackendKind, ManagedAgentRecord, RespondTo};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! Unit tests for `config_bridge/reader.rs` (kept in a sibling file so
//! `reader.rs` stays under the 1000-line budget; `#[path]`-included from
//! `reader.rs` stays under the 1500-line budget; `#[path]`-included from
//! there).

use std::{collections::BTreeMap, path::Path, sync::Mutex};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! Additional tests for `config_bridge/reader.rs` — split out to keep
//! `reader_tests.rs` under the 1000-line file-size ratchet.
//! `reader_tests.rs` under the 1500-line file-size ratchet.
//!
//! Included as `mod ext` inside `reader_tests.rs`, so `use super::*` gives
//! access to all helpers and types from that module.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! B5 effort lifecycle tests split out of `spawn_snapshot/tests.rs` to hold
//! that file under the 1000-line file-size ratchet.
//! that file under the 1500-line file-size ratchet.
//!
//! Included as `mod ext` inside `tests.rs`, so `use super::*` gives access to
//! its `record`, `snap`, and `record_with_env_effort` helpers.
Expand Down
2 changes: 1 addition & 1 deletion desktop/src-tauri/src/managed_agents/storage_tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Unit tests for `managed_agents/storage.rs`.
//!
//! Kept in a sibling file so `storage.rs` stays closer to the 1000-line gate;
//! Kept in a sibling file so `storage.rs` stays closer to the 1500-line gate;
//! `#[path]`-included from there.

use std::cell::RefCell;
Expand Down
2 changes: 1 addition & 1 deletion desktop/src-tauri/src/managed_agents/teams_tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Unit tests for `managed_agents/teams.rs`.
//!
//! Kept in a sibling file so `teams.rs` stays under the 1000-line gate;
//! Kept in a sibling file so `teams.rs` stays under the 1500-line gate;
//! `#[path]`-included from there.

use super::{
Expand Down
10 changes: 5 additions & 5 deletions desktop/src/features/agents/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,8 @@ with a TypeScript lookup table or an id comparison in a component.
place that resolves it for dialog surfaces and publishes it through
`ui/AgentRunLocationContext.tsx`; the field reads that context and lets an
explicit `runLocation` prop win. Do **not** thread the value as a prop
through `AgentDefinitionDialog` / `AgentInstanceEditDialog` — both are
already over the 1000-line ceiling, and neither uses the value itself.
through `AgentDefinitionDialog` / `AgentInstanceEditDialog` — neither uses
the value itself, and the shared context keeps the dialog boundary stable.
Surfaces rendered outside `AgentDialog` (e.g. `EditRespondToDialog`) pass the
prop directly. Local names "your
computer, including files, accounts, and connected tools"; remote names "the
Expand Down Expand Up @@ -216,9 +216,9 @@ with a TypeScript lookup table or an id comparison in a component.
cosmetic — the Rust command rejects non-local backends because remote effort
is set at deploy time via `policy_env`. Because it reads its inputs from the
config surface the dialog already fetches (`useAgentConfigSurface`) and owns
its own mutation, it does **not** thread new props through the over-1000-line
dialog (see rule 11): keep effort state inside the section component, never
as dialog-level props. The read-only display is the `thinkingEffort`
its own mutation, it does **not** thread new props through the dialog (see
rule 11): keep effort state inside the section component, never as
dialog-level props. The read-only display is the `thinkingEffort`
normalized field rendered by `AgentConfigPanel` via `NormalizedRow`, which
already shows both facts — `field.value` (canonical, the effort the next
spawn will launch with) and, when a running ACP session differs,
Expand Down
Loading