Sweep every first-party crate source (1956 .rs files) to the project comment guidelines: delete redundant restatements, decorative banners, change narration, and end-of-line comments; keep and tighten the crucial ones (invariants, bug rationale, SAFETY blocks, ported-source attribution). No functional code changed. Every edit is proven comment-only against the prior tree by a comment-stripping lexer (string/char/raw-string aware) plus a separate doctest-fence check. Where removing a comment made rustfmt or clippy want to re-lay-out adjacent code, the minimal triggering comment is restored so code tokens stay byte-identical. Gates green: cargo fmt --all --check (0 diffs), cargo check and cargo clippy --workspace --all-targets (0 warnings). Adds scripts/check_codegen_comment_guidelines.py — the enforcement gate for these guidelines (flags banners, end-of-line comments, change narration, and commented-out code).
85 lines
2.8 KiB
Rust
85 lines
2.8 KiB
Rust
//! Adjacent-tagged notification wire wrapper with a forward-compat
|
|
//! `Custom` shape.
|
|
//!
|
|
//! Adjacent tagging (`#[serde(tag = "shape", content = "value")]`) was
|
|
//! chosen over `#[serde(untagged)]` to eliminate the spoofing risk where
|
|
//! a `Custom` payload could silently match a known PascalCase variant.
|
|
//! The collision check ([`check_custom_kind`]) runs at
|
|
//! notification-emit time, not at registration time.
|
|
//!
|
|
//! Wire shape:
|
|
//!
|
|
//! ```jsonc
|
|
//! { "shape": "known", "value": { "type": "BashOutputChunk", ... } }
|
|
//! { "shape": "custom", "value": { "kind": "my_tool.progress", "payload": ... } }
|
|
//! ```
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(tag = "shape", content = "value", rename_all = "snake_case")]
|
|
pub enum WireToolNotification {
|
|
Known(serde_json::Value),
|
|
Custom(WireCustomNotification),
|
|
}
|
|
|
|
/// Free-form notification payload for kinds the computer hub does not
|
|
/// recognise. The `kind` MUST NOT collide with a known PascalCase variant
|
|
/// (see [`check_custom_kind`]).
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub struct WireCustomNotification {
|
|
pub kind: String,
|
|
pub payload: serde_json::Value,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
|
|
#[error("custom notification kind {kind:?} collides with a known variant")]
|
|
pub struct KnownVariantCollision {
|
|
pub kind: String,
|
|
}
|
|
|
|
/// PascalCase variant names of known notification types.
|
|
///
|
|
/// Source of truth lives upstream; keep this list in sync. The audit
|
|
/// test in `tests/notification_collision.rs` round-trips a representative
|
|
/// of every variant and asserts its `type` discriminator appears here, so
|
|
/// upstream additions cause a test failure rather than silent drift.
|
|
pub const KNOWN_NOTIFICATION_KINDS: &[&str] = &[
|
|
"BashOutputChunk",
|
|
"BashExecutionComplete",
|
|
"BashExecutionTimeout",
|
|
"BashExecutionBackgrounded",
|
|
"BashExecutionFailed",
|
|
"FileWritten",
|
|
"TaskCompleted",
|
|
"PlanModeEntered",
|
|
"PlanModeExited",
|
|
"UserQuestionAsked",
|
|
"LspServerStarting",
|
|
"LspServerReady",
|
|
"LspServerCrashed",
|
|
"LspServerRetrying",
|
|
"LspServerFailed",
|
|
"ScheduledTaskFired",
|
|
"ScheduledTaskRemoved",
|
|
"ScheduledTaskCreated",
|
|
"MonitorEvent",
|
|
];
|
|
|
|
pub const fn known_notification_kinds() -> &'static [&'static str] {
|
|
KNOWN_NOTIFICATION_KINDS
|
|
}
|
|
|
|
/// Reject custom notification kinds whose name shadows a known PascalCase
|
|
/// variant. An empty `kind` is accepted here; the producer is responsible
|
|
/// for validating that the field is non-empty.
|
|
pub fn check_custom_kind(kind: &str) -> Result<(), KnownVariantCollision> {
|
|
if KNOWN_NOTIFICATION_KINDS.contains(&kind) {
|
|
Err(KnownVariantCollision {
|
|
kind: kind.to_owned(),
|
|
})
|
|
} else {
|
|
Ok(())
|
|
}
|
|
}
|