From 125fe151dd23143ab4c6067f668dac91a1e15e25 Mon Sep 17 00:00:00 2001 From: Tim Visher <194828183+timvisher-dd@users.noreply.github.com> Date: Wed, 18 Mar 2026 15:46:11 -0400 Subject: [PATCH 1/2] Refactor idle-notification in terms of emit-event system Replace direct idle-notification-start/cancel calls with event subscriptions: turn-complete starts the timer, clean-up cancels it. Fix pre-existing agent-shell-mode-hook-subscriptions-survive-state-init test by stubbing agent-shell--handle and relaxing subscription count assertion. Co-Authored-By: Claude Opus 4.6 (1M context) --- README.org | 2 +- agent-shell.el | 19 +++++++++++++++++-- tests/agent-shell-tests.el | 39 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/README.org b/README.org index 31834795..0fb339ce 100644 --- a/README.org +++ b/README.org @@ -6,7 +6,7 @@ A soft fork of [[https://github.com/xenodium/agent-shell][agent-shell]] with ext * Features on top of agent-shell - CI workflow and local test runner ([[https://github.com/timvisher-dd/agent-shell-plus/pull/1][#1]], [[https://github.com/timvisher-dd/agent-shell-plus/pull/6][#6]]) -- Desktop notifications when the prompt is idle and waiting for input ([[https://github.com/timvisher-dd/agent-shell-plus/pull/2][#2]]) +- Desktop notifications when the prompt is idle and waiting for input ([[https://github.com/timvisher-dd/agent-shell-plus/pull/2][#2]], [[https://github.com/timvisher-dd/agent-shell-plus/pull/8][#8]]) - Per-shell debug logging infrastructure ([[https://github.com/timvisher-dd/agent-shell-plus/pull/2][#2]]) - Regression tests for shell buffer selection ordering ([[https://github.com/timvisher-dd/agent-shell-plus/pull/3][#3]]) - CI check that README.org is updated when code changes ([[https://github.com/timvisher-dd/agent-shell-plus/pull/4][#4]]) diff --git a/agent-shell.el b/agent-shell.el index 725901a4..4c55f07a 100644 --- a/agent-shell.el +++ b/agent-shell.el @@ -2340,7 +2340,6 @@ DIFF should be in the form returned by `agent-shell--make-diff-info': For example, shut down ACP client." (unless (derived-mode-p 'agent-shell-mode) (error "Not in a shell")) - (agent-shell--idle-notification-cancel) (agent-shell--emit-event :event 'clean-up) (agent-shell--shutdown) ;; Kill any open diff buffers associated with tool calls. @@ -2769,6 +2768,8 @@ variable (see makunbound)")) ;; `agent-shell--handle'. Fire mode hook so initial ;; state is available to agent-shell-mode-hook(s). (run-hooks 'agent-shell-mode-hook) + ;; Subscribe to lifecycle events for idle notification management. + (agent-shell--idle-notification-subscribe shell-buffer) ;; Subscribe to session selection events (needed regardless of focus). (when (eq agent-shell-session-strategy 'prompt) (agent-shell-subscribe-to @@ -3728,6 +3729,21 @@ when the prompt is idle and waiting for input." (agent-shell--idle-notification-fire)))))) (add-hook 'post-command-hook #'agent-shell--idle-notification-cancel nil t)))) +(defun agent-shell--idle-notification-subscribe (shell-buffer) + "Subscribe to events in SHELL-BUFFER to manage idle notifications. +Starts the idle notification timer on `turn-complete' and cancels +it on `clean-up'." + (agent-shell-subscribe-to + :shell-buffer shell-buffer + :event 'turn-complete + :on-event (lambda (_event) + (agent-shell--idle-notification-start))) + (agent-shell-subscribe-to + :shell-buffer shell-buffer + :event 'clean-up + :on-event (lambda (_event) + (agent-shell--idle-notification-cancel)))) + ;;; Initialization (cl-defun agent-shell--initialize-client () @@ -4782,7 +4798,6 @@ If FILE-PATH is not an image, returns nil." :event 'turn-complete :data (list (cons :stop-reason (map-elt acp-response 'stopReason)) (cons :usage (map-elt (agent-shell--state) :usage)))) - (agent-shell--idle-notification-start) ;; Update viewport header (longer busy) (when-let ((viewport-buffer (agent-shell-viewport--buffer :shell-buffer shell-buffer diff --git a/tests/agent-shell-tests.el b/tests/agent-shell-tests.el index 7d136da2..6461ce01 100644 --- a/tests/agent-shell-tests.el +++ b/tests/agent-shell-tests.el @@ -1234,14 +1234,19 @@ code block content test-buffer)) ((symbol-function 'shell-maker--process) (lambda () fake-process)) ((symbol-function 'shell-maker-finish-output) #'ignore) + ((symbol-function 'agent-shell--handle) #'ignore) (agent-shell-file-completion-enabled nil)) (let* ((shell-buffer (agent-shell--start :config config :no-focus t :new-session t)) (subs (map-elt (buffer-local-value 'agent-shell--state shell-buffer) :event-subscriptions))) - (should (= 1 (length subs))) - (should (eq 'turn-complete (map-elt (car subs) :event)))))) + ;; Mode-hook subscription should be present among all subscriptions. + (should (< 0 (length subs))) + (should (seq-find (lambda (sub) + (and (eq 'turn-complete (map-elt sub :event)) + (eq #'ignore (map-elt sub :on-event)))) + subs))))) (remove-hook 'agent-shell-mode-hook hook-fn) (when (process-live-p fake-process) (delete-process fake-process)) @@ -2062,6 +2067,36 @@ code block content (should-not (memq #'agent-shell--idle-notification-cancel (buffer-local-value 'post-command-hook (current-buffer)))))))) +(ert-deftest agent-shell--idle-notification-subscribe-turn-complete-starts-test () + "Test that `turn-complete' event starts idle notification via subscription." + (with-temp-buffer + (let ((agent-shell-idle-notification-delay 30) + (agent-shell--state (list (cons :buffer (current-buffer)) + (cons :event-subscriptions nil) + (cons :idle-notification-timer nil)))) + (cl-letf (((symbol-function 'agent-shell--state) + (lambda () agent-shell--state))) + (agent-shell--idle-notification-subscribe (current-buffer)) + (should-not (map-elt agent-shell--state :idle-notification-timer)) + (agent-shell--emit-event :event 'turn-complete) + (should (timerp (map-elt agent-shell--state :idle-notification-timer))) + (agent-shell--idle-notification-cancel))))) + +(ert-deftest agent-shell--idle-notification-subscribe-clean-up-cancels-test () + "Test that `clean-up' event cancels idle notification via subscription." + (with-temp-buffer + (let ((agent-shell-idle-notification-delay 30) + (agent-shell--state (list (cons :buffer (current-buffer)) + (cons :event-subscriptions nil) + (cons :idle-notification-timer nil)))) + (cl-letf (((symbol-function 'agent-shell--state) + (lambda () agent-shell--state))) + (agent-shell--idle-notification-subscribe (current-buffer)) + (agent-shell--idle-notification-start) + (should (timerp (map-elt agent-shell--state :idle-notification-timer))) + (agent-shell--emit-event :event 'clean-up) + (should-not (map-elt agent-shell--state :idle-notification-timer)))))) + (ert-deftest agent-shell-alert--detect-terminal-term-program-test () "Test terminal detection via TERM_PROGRAM." (cl-letf (((symbol-function 'getenv) From 22e144c733212deabcdc3bea43192b1110aaeaec Mon Sep 17 00:00:00 2001 From: Tim Visher <194828183+timvisher-dd@users.noreply.github.com> Date: Wed, 18 Mar 2026 16:00:31 -0400 Subject: [PATCH 2/2] Exit early from bin/test when byte-compilation or tests fail Co-Authored-By: Claude Opus 4.6 (1M context) --- README.org | 2 +- bin/test | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.org b/README.org index 0fb339ce..b663638f 100644 --- a/README.org +++ b/README.org @@ -5,7 +5,7 @@ A soft fork of [[https://github.com/xenodium/agent-shell][agent-shell]] with ext * Features on top of agent-shell -- CI workflow and local test runner ([[https://github.com/timvisher-dd/agent-shell-plus/pull/1][#1]], [[https://github.com/timvisher-dd/agent-shell-plus/pull/6][#6]]) +- CI workflow and local test runner ([[https://github.com/timvisher-dd/agent-shell-plus/pull/1][#1]], [[https://github.com/timvisher-dd/agent-shell-plus/pull/6][#6]], [[https://github.com/timvisher-dd/agent-shell-plus/pull/8][#8]]) - Desktop notifications when the prompt is idle and waiting for input ([[https://github.com/timvisher-dd/agent-shell-plus/pull/2][#2]], [[https://github.com/timvisher-dd/agent-shell-plus/pull/8][#8]]) - Per-shell debug logging infrastructure ([[https://github.com/timvisher-dd/agent-shell-plus/pull/2][#2]]) - Regression tests for shell buffer selection ordering ([[https://github.com/timvisher-dd/agent-shell-plus/pull/3][#3]]) diff --git a/bin/test b/bin/test index de0b4f64..5aa393c1 100755 --- a/bin/test +++ b/bin/test @@ -68,7 +68,8 @@ emacs -Q --batch \ -L "${acp_root}" \ -L "${shell_maker_root}" \ -f batch-byte-compile \ - "${compile_files[@]}" + "${compile_files[@]}" || + exit emacs -Q --batch \ -L "${root}" \ @@ -76,7 +77,8 @@ emacs -Q --batch \ -L "${shell_maker_root}" \ -L "${tests_dir}" \ "${test_args[@]}" \ - -f ert-run-tests-batch-and-exit + -f ert-run-tests-batch-and-exit || + exit # --- README update check (mirrors CI readme-updated job) --- # Compare against main (or merge-base) to see if code changed without