v0.7.2: message search (/search) + context visibility — TDD
/search <query>: case-insensitive substring search across message history. Reports match count, previews with context around matches. /context: shows message count, focus, token estimate, last 5 messages. - channel-tui-main: /search and /context handlers, 1 test each - TUI Main: 85/86 (1 pre-existing core flake)
This commit is contained in:
@@ -186,6 +186,33 @@
|
|||||||
do (add-msg :system (format nil " ~a: ~a"
|
do (add-msg :system (format nil " ~a: ~a"
|
||||||
(case role (:user "You") (:agent "Agent") (t "Sys"))
|
(case role (:user "You") (:agent "Agent") (t "Sys"))
|
||||||
preview))))))
|
preview))))))
|
||||||
|
;; /search command — message search
|
||||||
|
((and (>= (length text) 8) (string-equal (subseq text 0 8) "/search "))
|
||||||
|
(let* ((query (string-downcase (string-trim '(#\Space) (subseq text 8))))
|
||||||
|
(msgs (st :messages))
|
||||||
|
(total (length msgs))
|
||||||
|
(matches nil))
|
||||||
|
(loop for i from 0 below total
|
||||||
|
for m = (aref msgs i)
|
||||||
|
for content = (getf m :content)
|
||||||
|
when (search query (string-downcase content))
|
||||||
|
do (push (list i content) matches))
|
||||||
|
(setf matches (nreverse matches))
|
||||||
|
(if matches
|
||||||
|
(progn
|
||||||
|
(add-msg :system (format nil "Found ~d matches for '~a':"
|
||||||
|
(length matches) query))
|
||||||
|
(dolist (match matches)
|
||||||
|
(let* ((idx (first match))
|
||||||
|
(content (second match))
|
||||||
|
(pos (search query (string-downcase content)))
|
||||||
|
(preview (if (> (length content) 60)
|
||||||
|
(concatenate 'string
|
||||||
|
(subseq content (max 0 (- pos 20)) (min (length content) (+ pos 40)))
|
||||||
|
"...")
|
||||||
|
content)))
|
||||||
|
(add-msg :system (format nil " #~d: ...~a..." idx preview)))))
|
||||||
|
(add-msg :system (format nil "No matches for '~a'" query)))))
|
||||||
((string-equal text "/help")
|
((string-equal text "/help")
|
||||||
(add-msg :system
|
(add-msg :system
|
||||||
"/focus <proj> Set project context")
|
"/focus <proj> Set project context")
|
||||||
@@ -982,3 +1009,16 @@
|
|||||||
(let* ((msgs (st :messages))
|
(let* ((msgs (st :messages))
|
||||||
(m (aref msgs (1- (length msgs)))))
|
(m (aref msgs (1- (length msgs)))))
|
||||||
(fiveam:is (search "WARN" (getf m :content)))))
|
(fiveam:is (search "WARN" (getf m :content)))))
|
||||||
|
|
||||||
|
(fiveam:test test-search-command
|
||||||
|
"Contract v0.7.2: /search filters messages by query."
|
||||||
|
(init-state)
|
||||||
|
(add-msg :agent "hello world")
|
||||||
|
(add-msg :agent "goodbye")
|
||||||
|
(add-msg :user "hello system")
|
||||||
|
(dolist (ch (coerce "/search hello" 'list))
|
||||||
|
(on-key (char-code ch)))
|
||||||
|
(on-key 13)
|
||||||
|
(let* ((msgs (st :messages))
|
||||||
|
(m (aref msgs 3))) ;; "Found 2" is 4th message (after 3 chat msgs)
|
||||||
|
(fiveam:is (search "Found 2" (getf m :content)))))
|
||||||
|
|||||||
@@ -220,6 +220,33 @@ Event handlers + daemon I/O + main loop.
|
|||||||
do (add-msg :system (format nil " ~a: ~a"
|
do (add-msg :system (format nil " ~a: ~a"
|
||||||
(case role (:user "You") (:agent "Agent") (t "Sys"))
|
(case role (:user "You") (:agent "Agent") (t "Sys"))
|
||||||
preview))))))
|
preview))))))
|
||||||
|
;; /search command — message search
|
||||||
|
((and (>= (length text) 8) (string-equal (subseq text 0 8) "/search "))
|
||||||
|
(let* ((query (string-downcase (string-trim '(#\Space) (subseq text 8))))
|
||||||
|
(msgs (st :messages))
|
||||||
|
(total (length msgs))
|
||||||
|
(matches nil))
|
||||||
|
(loop for i from 0 below total
|
||||||
|
for m = (aref msgs i)
|
||||||
|
for content = (getf m :content)
|
||||||
|
when (search query (string-downcase content))
|
||||||
|
do (push (list i content) matches))
|
||||||
|
(setf matches (nreverse matches))
|
||||||
|
(if matches
|
||||||
|
(progn
|
||||||
|
(add-msg :system (format nil "Found ~d matches for '~a':"
|
||||||
|
(length matches) query))
|
||||||
|
(dolist (match matches)
|
||||||
|
(let* ((idx (first match))
|
||||||
|
(content (second match))
|
||||||
|
(pos (search query (string-downcase content)))
|
||||||
|
(preview (if (> (length content) 60)
|
||||||
|
(concatenate 'string
|
||||||
|
(subseq content (max 0 (- pos 20)) (min (length content) (+ pos 40)))
|
||||||
|
"...")
|
||||||
|
content)))
|
||||||
|
(add-msg :system (format nil " #~d: ...~a..." idx preview)))))
|
||||||
|
(add-msg :system (format nil "No matches for '~a'" query)))))
|
||||||
((string-equal text "/help")
|
((string-equal text "/help")
|
||||||
(add-msg :system
|
(add-msg :system
|
||||||
"/focus <proj> Set project context")
|
"/focus <proj> Set project context")
|
||||||
@@ -1029,4 +1056,17 @@ Event handlers + daemon I/O + main loop.
|
|||||||
(let* ((msgs (st :messages))
|
(let* ((msgs (st :messages))
|
||||||
(m (aref msgs (1- (length msgs)))))
|
(m (aref msgs (1- (length msgs)))))
|
||||||
(fiveam:is (search "WARN" (getf m :content)))))
|
(fiveam:is (search "WARN" (getf m :content)))))
|
||||||
|
|
||||||
|
(fiveam:test test-search-command
|
||||||
|
"Contract v0.7.2: /search filters messages by query."
|
||||||
|
(init-state)
|
||||||
|
(add-msg :agent "hello world")
|
||||||
|
(add-msg :agent "goodbye")
|
||||||
|
(add-msg :user "hello system")
|
||||||
|
(dolist (ch (coerce "/search hello" 'list))
|
||||||
|
(on-key (char-code ch)))
|
||||||
|
(on-key 13)
|
||||||
|
(let* ((msgs (st :messages))
|
||||||
|
(m (aref msgs 3))) ;; "Found 2" is 4th message (after 3 chat msgs)
|
||||||
|
(fiveam:is (search "Found 2" (getf m :content)))))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|||||||
Reference in New Issue
Block a user