mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-10-26 22:37:03 +00:00
main
7 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
ffecfc744b |
feat(chat): show chat delivered to an agent to the human at its terminal (TASK-4071) (#2312)
* feat(chat): tee monitor chat lines to a per-session chat-seen log (TASK-4071) pad watch --stream --for-session appends every chat line it prints to ~/.pad/chat-seen/<harness-pid>.log (0600 in a 0700 dir, O_NOFOLLOW), capped at 256 KiB with one .1 generation, so the human at the agent's terminal can see it. No log when the pid is pad watch's own; pruning a session record removes its log. Claude-Session: https://claude.ai/code/session_017ofcsFmgnoVDPxeHwuxCjg * test(chat): pin the chat-seen tee, perms, rotation, prune and C2 (TASK-4071) Claude-Session: https://claude.ai/code/session_017ofcsFmgnoVDPxeHwuxCjg * test(chat): refuse a FIFO that has a reader (TASK-4071 M13) Claude-Session: https://claude.ai/code/session_017ofcsFmgnoVDPxeHwuxCjg * feat(plugin): show chat delivered to the agent in a band and a toast (TASK-4071) The pad mod tails ~/.pad/chat-seen/<harness pid>.log from the session's first use of Pad, starting at the end of the file, and shows new lines in a band above the prompt (the last three, until the person's next prompt) and one toast per burst. Lines rotated away between polls are not shown. Claude-Session: https://claude.ai/code/session_017ofcsFmgnoVDPxeHwuxCjg * refactor(plugin): one rotation guard in the chat-seen reader (TASK-4071 P5) Claude-Session: https://claude.ai/code/session_017ofcsFmgnoVDPxeHwuxCjg * fix(chat): report a log that is off on its first line, and say what prune and the monitor do with it (TASK-4071) The monitor prints nothing before it has something to deliver (DOC-2479), so the no-harness-pid line waits for the first chat line. The pad watch --stream --for-session and pad session prune help now describe the log. Claude-Session: https://claude.ai/code/session_017ofcsFmgnoVDPxeHwuxCjg * fix(chat): r1 findings on the chat-seen log and reader (TASK-4071) - Refuse a symlinked chat-seen directory instead of chmodding its target. - Reopen a log that was removed under the writer. - Remove .log.1 before rotating: Rename does not replace on Windows. - Reader: drop control characters and direction overrides before they reach the terminal; clip by code points; one toast per burst on the relay's clock; a stop during start leaves nothing running; a failed first read no longer replays the log. Claude-Session: https://claude.ai/code/session_017ofcsFmgnoVDPxeHwuxCjg * fix(plugin): r2 findings on the chat-seen reader (TASK-4071) - The first look skips what the log held at its stat, so a line written between that stat and the read still shows. - A stop during a poll no longer leaves the reader stuck after the next wake. - An unreadable moment (failed stat, a symlink) changes nothing, so it cannot cause a replay. - U+061C joins the stripped bidi controls. Claude-Session: https://claude.ai/code/session_017ofcsFmgnoVDPxeHwuxCjg * fix(plugin): r3 findings on the chat-seen reader (TASK-4071) - Start a log at zero only when the listing shows it absent; a first look that merely failed leaves the start to the first good read (R3-1). - Restore the byte-size rotation reset beside the character one: a log of multi-byte text can shrink in one while it grows in the other (R3-2). Claude-Session: https://claude.ai/code/session_017ofcsFmgnoVDPxeHwuxCjg |
||
|
|
f8756a0b5b |
feat(server,cli,plugin): agent presence — agent name, worker id and busy/idle activity (TASK-4040) (#2293)
* test: pin agent presence and worker-scoped session activity * feat: carry agent presence and track activity by user and worker * docs: describe worker presence and session activity states * fix: include hook activity examples in CLI help * fix(cli): keep session activity hooks silent on failures * fix(server): tolerate activity read failures in session lists * docs: place activity keys after presence registry details * fix(plugin): wire silent Claude Code activity hooks * docs: explain session busy-state hook limits * fix: bound the entire session activity command * fix: batch session activity reads across workers * docs: describe detached activity reports and timestamp ordering * fix: order worker activity atomically by client timestamp * fix: detach hook activity reports with captured timestamps * test: reproduce detached activity losing registered identity * fix: capture activity identity before detaching the reporter * test: isolate activity registry home on Windows * docs: clarify activity ordering and hook failure behavior * fix: bound activity reordering to ten seconds * fix: replace activity records with corrupt client timestamps * test: prove activity parent exits while child response is held * fix(session): derive activity reorder window from report bound * fix: replace non-string Redis session activity records * test: cover cleared and expired session activity ordering * test: cover older timestamp after legacy activity * test: cover corrupt activity nanos and malformed JSON * test: verify activity child deadline and process isolation * docs: clarify read-only tokens cannot report hook activity * test: strengthen session activity liveness and timing guarantees * test: pin malformed null session activity timestamps * test: harden session activity detach regression checks * test: skip activity process-group check when ps is unavailable * test: tie activity parent-exit bounds to the HTTP timeout * test: bound activity liveness checks by the child HTTP deadline * test: require ps for process-group checks in Go CI |
||
|
|
07215d4953 |
fix(plugin): session start runs nothing; presence and the arm check wait for the first use of Pad (TASK-3970) (#2249)
* fix(plugin): session start runs nothing; presence and the arm check wait for the first use of Pad (TASK-3970)
Dave: "the plugin should not be doing anything when a session is started."
session.start now only registers /pad-pane and restores the pane. It no
longer runs `pad session register` / `should-arm`, no longer spawns
pad-monitor.sh, and no longer starts the 5s refresh timer, which now runs
only while the pane is open.
wake() runs once per session, on the first pad Bash command, a Pad MCP tool
call, or opening the pane. The first pad command waits for registration
(never for should-arm), because register mints the worker id that leases key
on. A .pad.toml push.auto_arm opt-in is therefore read at first use.
Tests: session start runs no process and asks for no timer; non-pad Bash
wakes nothing; wake runs once; an MCP tool wakes it; registration happens
before the first pad command runs. Prose swept (skill, monitor script,
CLAUDE.md, registry comments); docs/plugin-releases.md gets the stuck-0.3.x
remedy.
Claude-Session: https://claude.ai/code/session_01EZ6hZzQiytCeBxXrtCWcVd
* fix(plugin): a pad command inside a shell string or after an assignment wakes the session (TASK-3970)
Hunter r1 F1: `bash -c "pad ..."`, `sh -c 'pad ...'` and `X=... pad` missed
the first-use match, so that call ran before presence was recorded. The
class now takes quotes and `=`; a false positive only wakes early.
Claude-Session: https://claude.ai/code/session_01EZ6hZzQiytCeBxXrtCWcVd
* fix(plugin): pad as a whole word, checked against a table of shapes (TASK-3970)
Round r2 found two more missed shapes (Codex: `\pad ...`; hunter: a bare
`pad` before a quote, `)` or `;`). Rather than add a third case, the match
is now `pad` as a whole word, not inside a longer name. watch.test.ts
tables 25 shapes that run pad and 8 that do not, and asserts that
registration ran before each matching command reached the tool
(Codex r2 note).
Claude-Session: https://claude.ai/code/session_01EZ6hZzQiytCeBxXrtCWcVd
* fix(plugin): a Pad MCP tool wakes the session whatever the server is called (TASK-3970)
Codex r3: the matcher required "pad" in the server part of the tool name,
so a Pad server registered under another name (work-tracker) was missed.
It now matches any mcp__<server>__pad_* tool. The tests table Pad tools
under four server names and four tools that are not Pad's, and add ./pad
and ../bin/pad to the Bash shapes.
Claude-Session: https://claude.ai/code/session_01EZ6hZzQiytCeBxXrtCWcVd
* fix(plugin): the pane refreshes after a Pad MCP edit under any server name (TASK-3970)
Hunter r4: the pane-refresh matcher still required "pad" in the server
name, so it disagreed with the wake matcher fixed in
|
||
|
|
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) (#1925)
* 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 |
||
|
|
9f9304b294 |
fix(plugin): the pane's copy link points at the server it talks to, not always Pad Cloud (BUG-3484) (#1899)
.pad.toml's url, else the CLI's configured server (pad server info), else the MCP server's own URL (Pad Cloud's MCP host maps to the app, a self-hosted /mcp to its base), else Pad Cloud. Claude-Session: https://claude.ai/code/session_01J9famMX8HvArgW2uo8mPRT |
||
|
|
09135d15c5 |
feat(plugin): the pane's Get started view: Pad Cloud, this machine, or your own server (PLAN-3490) (#1888)
* feat(plugin): the pane's Get started view: Pad Cloud, this machine, or your own server (PLAN-3490) When the pane can't reach Pad it guides setup instead of showing an error: what this machine has (the CLI, a linked folder), then three paths. Pad Cloud adds its MCP server to Claude Code (claude mcp add, user scope) on a confirmed second press and fills /reload-plugins; it is never listed in the plugin manifest, which would nag every session. This machine and your own server hand the work to Claude in the prompt, so permission prompts apply. Claude-Session: https://claude.ai/code/session_01J9famMX8HvArgW2uo8mPRT * feat(plugin): Desktop: 6px of space between the pane's top line and the view tabs Claude-Session: https://claude.ai/code/session_01J9famMX8HvArgW2uo8mPRT |
||
|
|
b66af1e624 |
feat(plugin): the Pad pane ships in the pad plugin (/pad-pane) (TASK-3486) (#1883)
Folds the pad-mod pane (IDEA-3477) into plugin/ so one install gives the skills, the monitor and the pane. plugin/hooks/register.js is the mod (Claude Code 2.1.287+; older versions ignore it); plugin/tests run with `claude plugin test plugin` (9 pass). The tool.call refresh can no longer disturb the call it watched. Claude-Session: https://claude.ai/code/session_01J9famMX8HvArgW2uo8mPRT |