mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-10-26 06:19:49 +00:00
5c598a18d3
* feat(plugin): no event monitor at session start; an opted-in session's watch starts from the mod, and an unarmed one shows nothing (TASK-3513) Every session with the plugin opened with "Monitor ... ended without producing output", and Claude explaining it: the "always" monitor ran pad-monitor.sh, which exits when the session has not consented, and Claude Code reports any monitor that exits. Monitors take only "always" or "on-skill-invoke", with no condition and no silent exit. The plugin is already a mod (the pane). Its session.start now: - records presence (`pad session register`), silently, as the monitor did; - asks `pad session should-arm`, PLAN-2613's gate, unchanged (.pad.toml push.auto_arm stays the per-project opt-in); - only when armed, spawns pad-monitor.sh ($.process.spawn) and relays its stdout lines with $.prompt.submit, coalescing a burst into one message per idle window. An unarmed session runs nothing and shows nothing: no process, no line, no notice. session.end stops the stream, except /clear and /resume, which keep the process, the socket consent is keyed on, and do not refire session.start. Measured (Claude Code 2.1.295): CLAUDE_CODE_MESSAGING_SOCKET reaches a mod's processes, so consent and the wrapper's lockfile key match the connect monitor's; CLAUDE_PID and CLAUDECODE do not, so the mod passes PAD_SESSION_PID (its children's parent is the session process) and CLAUDECODE=1. - monitors.json: pad-events-auto removed; /pad:connect keeps its on-skill-invoke monitor, the explicit path and the path where mods do not load. The lockfile still keeps the two from streaming twice. - pad-monitor.sh: runs the stream as a child the traps can name, so a caller that stops the script stops the stream too. - SKILL.md and README: no "always-on wrapper"; the two delivery forms. Tests (claude plugin test plugin, 18 pass, the pane's included): unarmed registers and starts/shows nothing; no CLI; the CLI calls carry the session pid; armed relays one message per burst (stderr dropped); survives /clear and /resume; any other end relays nothing after it. Controls: dropping the gate fails 2, ending on /clear fails 1, and the relay's ownership check was found by its test (a late chunk relayed). Hand-check in an interactive session (tmux, --plugin-dir): unarmed start shows nothing and registers with the right pid; armed start spawns the wrapper and stream under the session process; a submitted line renders as "The pad plugin sent a message:"; the stream survives /clear; /exit takes the wrapper, the stream and the lockfile with it. Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS * fix(plugin): a session that ends while the CLI answers starts no watch (TASK-3513, codex r1) Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS * fix(plugin): a flush the session's end overtook relays nothing more (TASK-3513, codex r2) Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS * fix(plugin): pad-monitor.sh frees its lock only once the stream has closed (TASK-3513, codex r3) Measured with a stand-in pad whose stream takes 1s to close on TERM: the lock stays held through the close and is gone after, with no process left. Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS * fix(plugin): a burst of watch lines goes to Claude after it goes quiet, capped at 10s (TASK-3513, codex r4) Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS