mirror of
https://github.com/codewhale-hq/Codewhale.git
synced 2026-11-09 01:49:49 -10:00
W1 / S02: delete zero-reference tui code, stale dead-code allows and three empty files
First slice of the crate-split execution brief (S02), run as one window. Tested at base 7478d51f9c; landed onf0c0bf2665(two upstream files, tui/diff_render.rs and tui/pager.rs, are disjoint from this change and were not recompiled with it). Engineering defaults for the open founder decisions (FD-12: hold published-crate pub removals) were set by the coordinating session under AGENTS.md source authority; the founder can overrule them. Deleted after re-proving zero references with git grep over the whole repo (crates, web, scripts, docs), not only crates/*.rs: - session_manager.rs journal_append_message (and its expect(dead_code)); - fleet/alerts.rs FleetAlertEvent::{restart_exhausted, needs_human, budget_exceeded}; - fleet/worker_runtime.rs explicit_fleet_provider (explicit_fleet_provider_id stays); - sandbox/policy.rs SandboxPolicy::has_full_disk_read_access, and the read_guard.rs module comment that named it; - plugins/manifest.rs ResolvedPluginComponents::all_paths (the now-empty impl), plugins/registry.rs list_enabled and enabled_plugins, plugins/marketplace/types.rs to_install_source (and its now-unused PluginInstallSource import); - tui/pet_watch/worker.rs Raster::same_picture (the now-empty impl); - client.rs OpenRouterModelItem name, created, expiration_date (never read, three expect(dead_code) gone; serde ignores the extra response keys); - lib.rs pub use of maybe_load_persisted_cache and all_catalog_models_for_provider; - ten superfluous allow(dead_code) in core/prefix_cache.rs (5), models/lib.rs (3), localization/lib.rs (2); - empty tracked files tui/src/model_registry.rs, tui/src/main.rs (autobins=false) and models/src/model_catalog.rs, plus the false model_registry entries in AGENTS.md and docs/skills/cw-slice/SKILL.md and two "model_registry follow-up" comments in core/engine.rs and core/engine/tool_catalog.rs. Kept on purpose (brief findings): sandbox/mod.rs PUBLIC_SANDBOX_BACKENDS (the website facts gate parses it); the pub use ... as pet alias. Removing the alias makes rustc report seven items in tui/ambient_life/pet_sim.rs as dead, two of which (braille_text, legacy_whale) the separately built pet/ crates use through #[path]; it needs a pet/ edit and pet/verify.sh, so it is deferred. FD-12 holds: session_tree children_of and append_*, goal_loop DEFAULT_GOAL_MAX_STEPS and the resource_telemetry trim are untouched. Measured (before at00be3d2e4f[lane B counter], after on this tree): - tui strict production lines 634,761 to 634,614 (-147); file-level [F] 943,686 to 943,539 (-147); count_lines.py. - largest cycle: 79 modules before and after (partition_report.py); no cycle edge was touched. - dead-code budget 209 to 195 (allow 132 to 122, expect 77 to 73), hand-edited in scripts/dead-code-budget.json to the measured number, no --update; blocking-call budget unchanged at 543 sites in 165 files; module_graph --check PASS (121 closure modules); node web/scripts/check-facts.mjs OK; rustfmt --check of tui/src/lib.rs (991 files), models, localization and core files clean. Verified (macOS, local only; no hosted CI, no Linux/Windows compile): - clippy -p codewhale-tui -p codewhale-core -p codewhale-models -p codewhale-localization -p codewhale-runtime --all-targets --all-features --locked -D warnings with CI's allowed lints: exit 0 (wall 954.9 s, user 938.7 s). The first pass found the orphaned import and the pet_sim exposure; both repaired before the final pass. - nextest of the same crates, filters core, models, localization and tui alerts, session_manager, openrouter, plugins::registry, marketplace, sandbox::policy, read_guard, pet_watch: 485 run, 485 passed, 14975 skipped (core 62, models 42, localization 54, alerts 9, session_manager 137, openrouter 40, plugins::registry 20, marketplace 48, sandbox::policy 15, read_guard 26, pet_watch 35). The test-profile tui build took 2634.9 s wall and 1340.6 s user at load average 27 to 40 from other sessions' processes, over the brief's 17 to 25 minute cap; user CPU is in line with a normal build. - The committed tree differs from the tested tree by one blank line removed in plugins/marketplace/types.rs (rustfmt, checked by rustfmt only) and by the two upstream files named above. Not verified: pet/verify.sh (untouched), web build, runtime-crate tests (no runtime file changed), the production-feature cli check. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
1 parent
f0c0bf2665
commit
b1fa6193b9
22 files changed
+12
-184
No files matched your search
@@ -183,7 +183,7 @@ casually it reads as taking the work even when credit is preserved.
|
||||
KV-cache effect: frozen prefix vs. append-only history. Never splice a
|
||||
volatile fact into the prefix; append it as a user-role message.
|
||||
- These active modules are repeatedly misidentified as dead; verify consumers
|
||||
before removal: `runtime/src/context_budget.rs`, `tui/src/model_registry.rs`,
|
||||
before removal: `runtime/src/context_budget.rs`,
|
||||
`runtime/src/prompt_zones.rs`, `tui/src/tools/remember.rs`, and
|
||||
`config/src/route/`. Native memory lives in `runtime/src/native_memory.rs`;
|
||||
`tools/remember.rs` is its capture path.
|
||||
|
||||
@@ -129,7 +129,6 @@ pub struct PrefixChange {
|
||||
pub tools_changed: bool,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl PrefixChange {
|
||||
/// Returns a human-readable description of what changed.
|
||||
pub fn description(&self) -> String {
|
||||
@@ -316,7 +315,6 @@ impl ToolCatalogCache {
|
||||
/// Drop every cached entry. Used by tool-registry mutation paths
|
||||
/// (e.g. plugin hot-reload, MCP attach) when the caller cannot
|
||||
/// easily prove the tool set is unchanged.
|
||||
#[allow(dead_code)] // observability; called by /cache flush and tests
|
||||
pub fn invalidate(&mut self) {
|
||||
self.by_identity.clear();
|
||||
self.insertion_order.clear();
|
||||
@@ -329,7 +327,6 @@ impl ToolCatalogCache {
|
||||
}
|
||||
|
||||
/// Returns `true` if the cache has no entries.
|
||||
#[allow(dead_code)] // observability; surfaced via /status
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.by_identity.is_empty()
|
||||
@@ -337,7 +334,6 @@ impl ToolCatalogCache {
|
||||
|
||||
/// Returns `(current_entries, capacity)` for observability. Surfaced via
|
||||
/// the `/status` chip in a follow-up; tests exercise the path.
|
||||
#[allow(dead_code)] // surfaced via /status in a follow-up; tests exercise it
|
||||
#[must_use]
|
||||
pub fn stats(&self) -> (usize, usize) {
|
||||
(self.len(), self.capacity)
|
||||
@@ -423,7 +419,6 @@ fn hash_json_value<H: Hasher>(value: &serde_json::Value, state: &mut H) {
|
||||
/// [`PrefixFingerprint::compute_with_tool_cache`] and pass the cache in
|
||||
/// directly, both to share state and to avoid the thread-local lookup
|
||||
/// on the hot path.
|
||||
#[allow(dead_code)]
|
||||
impl PrefixStabilityManager {
|
||||
/// Create a new manager and immediately pin the first fingerprint.
|
||||
pub fn new(system_text: &str, tools: Option<&[Tool]>) -> Self {
|
||||
|
||||
@@ -2823,7 +2823,6 @@ pub enum MessageId {
|
||||
ExecFlagAfterPrompt,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const ALL_MESSAGE_IDS: &[MessageId] = &[
|
||||
MessageId::MobileStreamReplayFailed,
|
||||
MessageId::MobileStreamCatchUpFailed,
|
||||
@@ -5585,7 +5584,6 @@ where
|
||||
Locale::En
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn truncate_to_width(text: &str, max_width: usize) -> String {
|
||||
if max_width == 0 {
|
||||
return String::new();
|
||||
|
||||
@@ -484,7 +484,6 @@ where
|
||||
Ok(Option::<String>::deserialize(deserializer)?.unwrap_or_default())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
#[serde(tag = "type")]
|
||||
/// Streaming event types for SSE responses.
|
||||
@@ -522,7 +521,6 @@ pub enum StreamEvent {
|
||||
Error { error: serde_json::Value },
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
#[serde(tag = "type")]
|
||||
/// Content block types used in streaming starts.
|
||||
@@ -590,7 +588,6 @@ pub enum Delta {
|
||||
ReasoningStateDelta { state: OpaqueReasoningState },
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
/// Delta payload for message-level updates.
|
||||
pub struct MessageDelta {
|
||||
|
||||
Whitespace-only changes.
@@ -4917,14 +4917,6 @@ struct ModelListItem {
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct OpenRouterModelItem {
|
||||
id: String,
|
||||
// Captured from OpenRouter for future display/deprecation surfaces. The
|
||||
// current CatalogOffering shape has no honest fields for these yet.
|
||||
#[serde(default)]
|
||||
#[expect(dead_code)]
|
||||
name: Option<String>,
|
||||
#[serde(default)]
|
||||
#[expect(dead_code)]
|
||||
created: Option<u64>,
|
||||
#[serde(default)]
|
||||
context_length: Option<u32>,
|
||||
#[serde(default)]
|
||||
@@ -4940,9 +4932,6 @@ struct OpenRouterModelItem {
|
||||
/// separated from image/video/rerank rows without guessing from the name.
|
||||
#[serde(default)]
|
||||
supported_endpoint_types: Option<Vec<String>>,
|
||||
#[serde(default)]
|
||||
#[expect(dead_code)]
|
||||
expiration_date: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
||||
@@ -6193,7 +6193,7 @@ impl Engine {
|
||||
self.config.disallowed_tools.clone(),
|
||||
self.config.max_tool_calls,
|
||||
// Model metadata wins once wired; today the hint is always None
|
||||
// and the [features] flags decide (model_registry follow-up).
|
||||
// and the [features] flags decide.
|
||||
tool_catalog::requested_tool_mode(None, &self.config.features),
|
||||
);
|
||||
if let Some(child) = self.child_host.as_ref() {
|
||||
|
||||
@@ -287,7 +287,7 @@ pub(crate) enum ToolMode {
|
||||
|
||||
/// Resolve the turn's tool mode: model hint first, `[features] code_mode`
|
||||
/// second, [`ToolMode::Direct`] otherwise. The engine passes `None` for the
|
||||
/// hint until per-model metadata is wired (model_registry follow-up).
|
||||
/// hint until per-model metadata is wired.
|
||||
pub(crate) fn requested_tool_mode(model_hint: Option<ToolMode>, features: &Features) -> ToolMode {
|
||||
model_hint.unwrap_or_else(|| {
|
||||
if features.enabled(Feature::CodeMode) {
|
||||
|
||||
@@ -168,54 +168,6 @@ impl FleetAlertEvent {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn restart_exhausted(
|
||||
run_id: FleetRunId,
|
||||
worker_id: impl Into<String>,
|
||||
task_id: impl Into<String>,
|
||||
reason: impl Into<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
class: FleetAlertEventClass::RestartExhausted,
|
||||
run_id,
|
||||
worker_id: Some(worker_id.into()),
|
||||
task_id: Some(task_id.into()),
|
||||
status: "failed".to_string(),
|
||||
reason: reason.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn needs_human(
|
||||
run_id: FleetRunId,
|
||||
worker_id: Option<String>,
|
||||
task_id: Option<String>,
|
||||
reason: impl Into<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
class: FleetAlertEventClass::NeedsHuman,
|
||||
run_id,
|
||||
worker_id,
|
||||
task_id,
|
||||
status: "needs_human".to_string(),
|
||||
reason: reason.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn budget_exceeded(
|
||||
run_id: FleetRunId,
|
||||
worker_id: Option<String>,
|
||||
task_id: Option<String>,
|
||||
reason: impl Into<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
class: FleetAlertEventClass::BudgetExceeded,
|
||||
run_id,
|
||||
worker_id,
|
||||
task_id,
|
||||
status: "budget_exceeded".to_string(),
|
||||
reason: reason.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verifier_failed(receipt: &FleetReceipt) -> Option<Self> {
|
||||
if receipt.failure_kind != Some(FleetTaskFailureKind::Verifier) {
|
||||
return None;
|
||||
|
||||
@@ -1237,28 +1237,6 @@ pub(crate) fn explicit_fleet_provider_id(agent_profile: Option<&AgentProfile>) -
|
||||
.map(str::to_string)
|
||||
}
|
||||
|
||||
/// The built-in provider a resolved agent profile EXPLICITLY pins, if any (#4093).
|
||||
///
|
||||
/// This returns `None` (never the DeepSeek default) when no profile names a
|
||||
/// provider, so call sites can leave `--provider` off the worker argv and
|
||||
/// preserve today's behavior for profile-less / provider-less workers (they
|
||||
/// resolve their provider from their own session default). EPIC #2608: never
|
||||
/// inferred from `model`.
|
||||
///
|
||||
/// `pub(crate)` so the interactive-TUI in-process spawn path
|
||||
/// (`tools::subagent`) resolves the pinned provider from the SAME
|
||||
/// explicit-only source as the headless `codewhale exec` launch route (#4193),
|
||||
/// instead of re-deriving it and risking a second, divergent policy. User-named
|
||||
/// custom providers intentionally return `None` here; launch paths that can
|
||||
/// carry strings should use [`explicit_fleet_provider_id`].
|
||||
pub(crate) fn explicit_fleet_provider(
|
||||
agent_profile: Option<&AgentProfile>,
|
||||
) -> Option<ProviderKind> {
|
||||
explicit_fleet_provider_id(agent_profile)
|
||||
.as_deref()
|
||||
.and_then(ProviderKind::parse)
|
||||
}
|
||||
|
||||
pub(crate) fn effective_fleet_reasoning_effort(
|
||||
agent_profile: Option<&AgentProfile>,
|
||||
) -> Option<String> {
|
||||
|
||||
@@ -64,7 +64,6 @@ mod model_profile;
|
||||
mod model_relevance;
|
||||
mod model_routing;
|
||||
mod models_dev_live;
|
||||
pub use models_dev_live::maybe_load_persisted_cache;
|
||||
mod network_policy;
|
||||
mod notify;
|
||||
mod oauth;
|
||||
@@ -77,7 +76,6 @@ mod project_context_cache;
|
||||
mod prompts;
|
||||
mod provider_catalog_live;
|
||||
mod provider_lake;
|
||||
pub use provider_lake::all_catalog_models_for_provider;
|
||||
mod provider_readiness;
|
||||
mod purge;
|
||||
pub mod reasoning_preference;
|
||||
|
||||
Whitespace-only changes.
Whitespace-only changes.
@@ -167,18 +167,6 @@ pub struct ResolvedPluginComponents {
|
||||
pub native: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
impl ResolvedPluginComponents {
|
||||
pub fn all_paths(&self) -> impl Iterator<Item = &PathBuf> {
|
||||
self.skills
|
||||
.iter()
|
||||
.chain(&self.commands)
|
||||
.chain(&self.agents)
|
||||
.chain(&self.hooks)
|
||||
.chain(&self.lsp)
|
||||
.chain(&self.native)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct PluginInventory {
|
||||
|
||||
@@ -22,7 +22,6 @@ use std::path::PathBuf;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::super::install::PluginInstallSource;
|
||||
use super::super::manifest::{PluginCompatibility, PluginInventory, PluginWhen};
|
||||
use super::super::types::PluginDiagnosticLevel;
|
||||
use codewhale_config::PluginId;
|
||||
@@ -251,14 +250,6 @@ impl MarketplaceInstallPlan {
|
||||
Self::Unsupported { reason, .. } => Some(reason.as_str()),
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn to_install_source(&self) -> Option<PluginInstallSource> {
|
||||
match self {
|
||||
Self::Supported { spec, .. } => PluginInstallSource::parse(spec).ok(),
|
||||
Self::Unsupported { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// What a catalog entry is.
|
||||
|
||||
@@ -422,21 +422,6 @@ impl PluginRegistry {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Compatibility name retained for the MCP adapter. Unlike the old
|
||||
/// registry this returns only trusted, active bundles.
|
||||
#[must_use]
|
||||
pub fn list_enabled(&self) -> Vec<&LoadedPlugin> {
|
||||
self.active_plugins()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn enabled_plugins(&self) -> Vec<&LoadedPlugin> {
|
||||
self.list()
|
||||
.into_iter()
|
||||
.filter(|plugin| plugin.enabled)
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_enabled(&self, selector: &str) -> bool {
|
||||
self.get(selector).is_some_and(|plugin| plugin.enabled)
|
||||
|
||||
@@ -140,24 +140,6 @@ impl SandboxPolicy {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true when the sandbox really does grant read of every file on
|
||||
/// disk — i.e. no read deny-list is in force.
|
||||
///
|
||||
/// Every posture, `read-only` included, grants full-disk *read*: the
|
||||
/// postures differ only in what they may write and whether they may reach
|
||||
/// the network. The read deny-list (S1, `super::read_guard`) is the only
|
||||
/// thing that narrows this, and it is defense-in-depth rather than a
|
||||
/// boundary — a hardlink or an indirect read (`ssh-agent`, `security`)
|
||||
/// walks around it.
|
||||
///
|
||||
/// Note the Seatbelt profile still emits the broad `(allow file-read*)`
|
||||
/// even when this returns `false`: SBPL is last-match-wins, so the deny
|
||||
/// rules appended after it are what actually narrow the grant. This
|
||||
/// function reports the *posture*, for labels and telemetry.
|
||||
pub fn has_full_disk_read_access(denied_read_subpaths: &[PathBuf]) -> bool {
|
||||
denied_read_subpaths.is_empty()
|
||||
}
|
||||
|
||||
/// Returns true if the policy allows writing to any file on the filesystem.
|
||||
pub fn has_full_disk_write_access(&self) -> bool {
|
||||
matches!(
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//!
|
||||
//! Every sandbox posture Codewhale ships — including `read-only` — grants the
|
||||
//! sandboxed process read access to the entire filesystem
|
||||
//! (`policy.rs::has_full_disk_read_access`). #5568 added the *plumbing* for an
|
||||
//! (`policy.rs`). #5568 added the *plumbing* for an
|
||||
//! opt-in deny-list (Seatbelt last-match-wins `deny file-read*` rules;
|
||||
//! bubblewrap masks), but the list shipped empty, so in practice nothing was
|
||||
//! denied. This module supplies (a) a curated default set covering the obvious
|
||||
|
||||
@@ -1274,17 +1274,6 @@ impl SavedSession {
|
||||
self.leaf_id = journal.leaf_id.clone();
|
||||
self.journal = Some(journal);
|
||||
}
|
||||
#[expect(dead_code)]
|
||||
pub fn journal_append_message(&mut self, message: Message) -> String {
|
||||
self.ensure_journal();
|
||||
let journal = self.journal.as_mut().expect("journal ensured");
|
||||
let id = journal.append_message(message.clone());
|
||||
self.leaf_id = journal.leaf_id.clone();
|
||||
self.messages = journal.to_messages();
|
||||
self.metadata.message_count = self.messages.len();
|
||||
self.metadata.updated_at = Utc::now();
|
||||
id
|
||||
}
|
||||
pub fn journal_branch_to(&mut self, entry_id: &str) -> Result<(), String> {
|
||||
self.ensure_journal();
|
||||
let journal = self.journal.as_mut().expect("journal ensured");
|
||||
|
||||
@@ -29,20 +29,6 @@ pub struct Raster {
|
||||
pub lit: f64,
|
||||
}
|
||||
|
||||
impl Raster {
|
||||
/// A hidden clock advance is not a new picture in reduced motion.
|
||||
pub fn same_picture(&self, other: &Self) -> bool {
|
||||
self.width == other.width
|
||||
&& self.height == other.height
|
||||
&& self.cells == other.cells
|
||||
&& self.channel == other.channel
|
||||
&& self.arch == other.arch
|
||||
&& self.hollow == other.hollow
|
||||
&& self.dozing == other.dozing
|
||||
&& self.lit == other.lit
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Command {
|
||||
Export,
|
||||
Observe {
|
||||
|
||||
@@ -60,7 +60,7 @@ Stage 2 of the loop: [cw-orient](../cw-orient/SKILL.md) → **slice** →
|
||||
- `crates/tui/src/core/` is a module inside the TUI crate. `crates/core` is a
|
||||
different crate that runs no turns. Do not confuse them.
|
||||
- Repeatedly misidentified as dead, verify consumers before removing:
|
||||
`runtime/src/context_budget.rs`, `tui/src/model_registry.rs`,
|
||||
`runtime/src/context_budget.rs`,
|
||||
`runtime/src/prompt_zones.rs`, `tui/src/tools/remember.rs`, `config/src/route/`.
|
||||
|
||||
4. **Read the scoped guidance for the files you will touch.** `crates/tui/AGENTS.md`
|
||||
|
||||
@@ -2,24 +2,24 @@
|
||||
"_comment": "Ceiling for dead-code suppressions across crates/, counting both `#[allow(dead_code)]` and `#[expect(dead_code)]`. `total` is the sum and is the ratcheted figure. It may go down freely; raising it needs a reviewer to say why in the PR. Regenerate with: python3 scripts/check-dead-code-budget.py --update",
|
||||
"_issue": "https://github.com/codewhale-hq/CodeWhale/issues/4785",
|
||||
"_expect_blind_spot": "Until #6241 this gate counted only the `allow` spelling, so rewriting an allow as an expect lowered the number without removing any dead code. The ceiling was re-based to the true combined count when that was fixed; it is not a regression.",
|
||||
"total": 209,
|
||||
"allow_total": 132,
|
||||
"expect_total": 77,
|
||||
"total": 195,
|
||||
"allow_total": 122,
|
||||
"expect_total": 73,
|
||||
"per_crate": {
|
||||
"cli": {
|
||||
"allow": 0,
|
||||
"expect": 1
|
||||
},
|
||||
"core": {
|
||||
"allow": 5,
|
||||
"allow": 0,
|
||||
"expect": 0
|
||||
},
|
||||
"localization": {
|
||||
"allow": 2,
|
||||
"allow": 0,
|
||||
"expect": 0
|
||||
},
|
||||
"models": {
|
||||
"allow": 3,
|
||||
"allow": 0,
|
||||
"expect": 0
|
||||
},
|
||||
"palette": {
|
||||
@@ -36,7 +36,7 @@
|
||||
},
|
||||
"tui": {
|
||||
"allow": 108,
|
||||
"expect": 73
|
||||
"expect": 69
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user