Skip to content

Commit 0ecde22

Browse files
committed
fix: restore bounded transport-first DING delivery
1 parent d4e4b97 commit 0ecde22

1 file changed

Lines changed: 29 additions & 14 deletions

File tree

src/ding.rs

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ const SUBJECT_MAX_CHARS: usize = 160;
3030
const SENDER_MAX_CHARS: usize = 80;
3131
const RECOVERY_POKE: &str = "[DING] unread st2 messages remain; check your inbox";
3232
const PTY_COMMAND_TIMEOUT: Duration = Duration::from_millis(600);
33+
#[allow(dead_code)]
3334
const COMPOSER_OBSERVATION_WINDOW: Duration = Duration::from_millis(450);
35+
#[allow(dead_code)]
3436
const COMPOSER_OBSERVATION_POLL: Duration = Duration::from_millis(10);
3537
/// A human or active turn can keep a staged notice unsafe for minutes. Retrying `pty peek` every
3638
/// inbox poll creates a short-lived child for each attempt, so keep the correctness fallback but
@@ -120,6 +122,20 @@ pub fn pty_submit_args(session: &str) -> Vec<String> {
120122
]
121123
}
122124

125+
/// Recovery delivery: one bounded PTY transaction containing paste and Return.
126+
pub fn pty_delivery_args(session: &str, text: &str) -> Vec<String> {
127+
vec![
128+
"send".into(),
129+
session.into(),
130+
"--seq".into(),
131+
bracketed_paste(text),
132+
"--seq".into(),
133+
"key:return".into(),
134+
"--with-delay".into(),
135+
"500".into(),
136+
]
137+
}
138+
123139
/// One delivery attempt either submitted the notice, owns a paste that must be retried by
124140
/// inspection only, or performed no input because the target was not positively safe.
125141
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -192,14 +208,13 @@ impl PtyPoker {
192208
text: &str,
193209
before_submit: &mut dyn FnMut() -> anyhow::Result<()>,
194210
) -> anyhow::Result<PokeOutcome> {
195-
observed_poke(
196-
text,
197-
&mut || self.peek(),
198-
&mut || self.run(pty_stage_args(&self.session, text), "send"),
199-
&mut || self.run(pty_submit_args(&self.session), "send"),
200-
&mut || thread::sleep(COMPOSER_OBSERVATION_POLL),
201-
before_submit,
202-
)
211+
// Recovery contract: PTY-alive delivery is transport-first. Keep one owned payload,
212+
// stage it once, wait a bounded interval, then submit exactly once; pane heuristics remain
213+
// diagnostic only and must not silently suppress messaging.
214+
self.run(pty_delivery_args(&self.session, text), "send")
215+
.map_err(|error| anyhow::anyhow!("staging DING payload: {error}"))?;
216+
before_submit()?;
217+
Ok(PokeOutcome::Delivered)
203218
}
204219
}
205220

@@ -209,12 +224,10 @@ impl Poker for PtyPoker {
209224
}
210225

211226
fn retry_staged(&self, text: &str) -> anyhow::Result<PokeOutcome> {
212-
observed_retry_staged(
213-
text,
214-
&mut || self.peek(),
215-
&mut || self.run(pty_submit_args(&self.session), "send"),
216-
&mut || Ok(()),
217-
)
227+
let _ = text;
228+
self.run(pty_submit_args(&self.session), "send")
229+
.map_err(|error| anyhow::anyhow!("submitting staged DING payload: {error}"))?;
230+
Ok(PokeOutcome::Delivered)
218231
}
219232

220233
fn adopt_staged(&self, candidates: &[String]) -> anyhow::Result<Option<String>> {
@@ -302,6 +315,7 @@ fn exact_staged_candidate(screen: &str, candidates: &[String]) -> Option<String>
302315
})
303316
}
304317

318+
#[allow(dead_code)]
305319
fn observed_poke(
306320
text: &str,
307321
peek: &mut dyn FnMut() -> anyhow::Result<String>,
@@ -413,6 +427,7 @@ fn submit_after_final_observation(
413427
}
414428

415429
/// Inspect-only retry for a payload whose paste command already started.
430+
#[allow(dead_code)]
416431
fn observed_retry_staged(
417432
text: &str,
418433
peek: &mut dyn FnMut() -> anyhow::Result<String>,

0 commit comments

Comments
 (0)