<feed xmlns='http://www.w3.org/2005/Atom'>
<title>dotemacs/modules/slack-config.el, branch main</title>
<subtitle>My Emacs configuration
</subtitle>
<id>https://git.cjennings.net/dotemacs/atom?h=main</id>
<link rel='self' href='https://git.cjennings.net/dotemacs/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/'/>
<updated>2026-05-26T19:21:20+00:00</updated>
<entry>
<title>feat(slack): open rooms in another window, never the selected one</title>
<updated>2026-05-26T19:21:20+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-26T19:21:20+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=6c7f9ae225b91dee81a04d2271a6648924c0f3cf'/>
<id>urn:sha1:6c7f9ae225b91dee81a04d2271a6648924c0f3cf</id>
<content type='text'>
slack-buffer-function defaulted to switch-to-buffer-other-window, which gives no real guarantee about placement: with three or more panes it picks a least-recently-used window, and it offers nothing that keeps Slack out of the window point is in. So opening a room in a split could land it wherever, including over the buffer I was working in.

I set slack-buffer-function to cj/slack--display-buffer, a pop-to-buffer call with inhibit-same-window and a reuse / use-some-window / pop-up-window action list. In a split it reuses one of the other windows and leaves the selected window alone; with a lone window it splits. Tests cover both the split-placement case and the selected-window-preserved invariant.
</content>
</entry>
<entry>
<title>docs(load-graph): classify remaining domain and optional modules</title>
<updated>2026-05-24T22:01:40+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-24T22:01:40+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=f84bba186dca1543f9c5f02c03af355188b6e87c'/>
<id>urn:sha1:f84bba186dca1543f9c5f02c03af355188b6e87c</id>
<content type='text'>
Final classification batch: the last 19 modules — linear-config, local-repository, lorem-optimum, mail-config, markdown-config, music-config, pdf-config, quick-video-capture, reconcile-open-repos, restclient-config, slack-config, system-commands, telega-config, tramp-config, transcription-config, video-audio-recording, vterm-config, weather-config, wrap-up. I annotated each header, added a Batch 9 table to the inventory, and extended the validation allowlist. 101 of 102 modules are now classified; only elfeed-config remains, deferred on its test fix.

Two more hidden dependencies turned up. video-audio-recording uses the boundp shim for its C-; r binding, and mail-config registers C-; e directly without requiring keybindings, so it errors standalone rather than degrading. Both recorded for Phase 2.
</content>
</entry>
<entry>
<title>refactor(auth): consolidate the auth-source secret lookup into one helper</title>
<updated>2026-05-23T00:32:32+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-23T00:32:32+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=f6e5885b47e3ab244b293f4e478af7e520180710'/>
<id>urn:sha1:f6e5885b47e3ab244b293f4e478af7e520180710</id>
<content type='text'>
The auth-source-search + funcall-the-secret block was copied four times: calendar-sync--calendar-url, cj/auth-source-secret (ai-config), cj/--auth-source-password (transcription), and cj/slack--get-credential. Each searched authinfo, pulled :secret, and called it when the netrc backend returned a function.

I pulled that into cj/auth-source-secret-value in system-lib (a leaf, so calendar-sync doesn't have to depend on ai-config and drag in the gptel stack). It takes an optional user and returns the secret or nil. The four callers now delegate to it: ai-config layers its required-secret error on top, and the others keep their nil-on-miss behavior. With the direct auth-source-search calls gone, I dropped the now-unused (require 'auth-source) from transcription, slack, and calendar-sync. The helper's autoload covers it.

The transcription tests that exercise the delegated path stay green, and the primitive and the error wrapper get their own tests.
</content>
</entry>
<entry>
<title>refactor(integrations): five hygiene fixes from the module-by-module re-review</title>
<updated>2026-05-16T09:01:04+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-16T09:01:04+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=500687f8d7d5b87ceb33fd959e545746ec9db1ba'/>
<id>urn:sha1:500687f8d7d5b87ceb33fd959e545746ec9db1ba</id>
<content type='text'>
- markdown-config.el: two related fixes on `markdown-preview'.
  First, the URL was `https://localhost:8080/imp' but simple-httpd
  serves plaintext on port 8080 -- the browser hit a TLS handshake
  against a non-TLS listener and the preview never rendered.  Changed
  to `http://' and switched from `browse-url-generic' to plain
  `browse-url' so the user's default protocol handler picks the
  browser.  Second, the function used to start the network listener
  as a side effect of opening a preview; that's split into a
  separate `cj/markdown-preview-server-start' command and
  `markdown-preview' now signals a `user-error' (with the recovery
  command in the message) when the server isn't running.

- slack-config.el: wrap the
  `which-key-add-keymap-based-replacements' call in
  `with-eval-after-load 'which-key'.  Matches the pattern other
  config modules use and means a slow / missing which-key load
  won't block requiring slack-config.

- ai-vterm.el: pass the inner shell-command-string through
  `shell-quote-argument' before wrapping in the tmux invocation.
  The default value with embedded double quotes was safe under the
  prior literal-single-quote wrap, but a user-customized
  `cj/ai-vterm-agent-command' containing a single quote silently
  broke the shell parse.  Two existing tests updated to tolerate
  the post-quote escape shape; new regression test asserts a
  single-quote-bearing custom command survives.

- eshell-config.el: scope the `TERM=xterm-256color' override to
  eshell-spawned processes only via an `eshell-mode' hook that
  prepends to a buffer-local `process-environment'.  The previous
  global `setenv' at config-time changed `TERM' for every
  subsequent `start-process' across the Emacs session, so any
  subprocess (not just eshell pipelines) inherited
  `xterm-256color' regardless of whether the receiver could
  interpret the escapes.
</content>
</entry>
<entry>
<title>fix(slack): error when adding a reaction outside a Slack buffer</title>
<updated>2026-05-12T05:42:52+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-12T05:42:52+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=8cb30ef6efd06464ab1153b99261a3f626149f97'/>
<id>urn:sha1:8cb30ef6efd06464ab1153b99261a3f626149f97</id>
<content type='text'>
`cj/slack-message-add-reaction' wrapped its whole body in `when-let*' on `slack-current-buffer', so invoking C-; S ! outside a Slack message view did nothing at all, and with no message it looked like the key wasn't even bound. It now `user-error's "Not in a Slack buffer". A test covers the case.
</content>
</entry>
<entry>
<title>fix(slack): harden and curate the C-; S ! reaction workflow</title>
<updated>2026-05-11T22:17:54+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-05-11T22:17:54+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=bbd1b73cbaf1716734b1193467564a0c7122dec7'/>
<id>urn:sha1:bbd1b73cbaf1716734b1193467564a0c7122dec7</id>
<content type='text'>
Two problems with `C-; S !'. First, emacs-slack's `slack-reaction-echo-description' runs in a buffer-local `post-command-hook' and can error on every keystroke when a reaction widget's text properties are malformed, which makes it hard to leave the Slack buffer or recover with C-g. It's now wrapped in `condition-case' that, on error, removes the hook from that buffer's local `post-command-hook' and messages once. Second, without emojify the upstream reaction picker is a flat completing-read over 1600+ names. `cj/slack-message-add-reaction' now offers a curated common list (`thumbsup', `pray', `eyes', `white_check_mark', `heart', `joy', `thinking_face', `rocket', `tada') with "Other..." delegating back to `slack-message-reaction-input' for the full set. Tests cover the hook hardening, the curated picker, and the `C-; S !' rebinding.
</content>
</entry>
<entry>
<title>fix(slack): disable emojify in lui buffers, add org cache reset command</title>
<updated>2026-03-16T17:27:42+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-03-16T17:27:42+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=0a2258db2ce5b80b3cc8553c21ea2d37e4b44157'/>
<id>urn:sha1:0a2258db2ce5b80b3cc8553c21ea2d37e4b44157</id>
<content type='text'>
Disable slack-buffer-emojify to prevent wrong-type-argument listp errors
on emoji characters during lui-scroll-post-command recenter. Add C-; O c
to reset org-element cache across all org-mode buffers.
</content>
</entry>
<entry>
<title>fix(slack): add error visibility to notification handler</title>
<updated>2026-03-14T17:55:48+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-03-14T17:55:48+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=759b654c89e62dab207888bf5615ea8dc3874dfa'/>
<id>urn:sha1:759b654c89e62dab207888bf5615ea8dc3874dfa</id>
<content type='text'>
Websocket library silently swallows callback errors via condition-case.
Wrap cj/slack-notify in condition-case to surface errors in *Messages*.
Add cj/slack-test-notify command for pipeline verification.
</content>
</entry>
<entry>
<title>fix(slack): fix notification bug, add close-all-buffers command</title>
<updated>2026-03-10T13:03:13+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-03-10T13:03:13+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=3b48ec037d47e85526320b15d0b86c5f3a83cb16'/>
<id>urn:sha1:3b48ec037d47e85526320b15d0b86c5f3a83cb16</id>
<content type='text'>
Pass missing team arg to slack-message-mentioned-p (was breaking all
channel notifications). Add cj/slack-close-all-buffers on C-; S Q.
</content>
</entry>
<entry>
<title>fix(slack): fix notification and mark-as-read bugs</title>
<updated>2026-03-06T20:50:31+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-03-06T20:50:31+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/dotemacs/commit/?id=a1ed2b361c70af0154548646169ab590bc386d68'/>
<id>urn:sha1:a1ed2b361c70af0154548646169ab590bc386d68</id>
<content type='text'>
Notifications silently failed: slack-room-im-p (nonexistent) replaced
with slack-im-p; slack-message-to-string replaced with slack-message-body.
Mark-as-read bound to nonexistent function; added cj/slack-mark-read-and-bury.
</content>
</entry>
</feed>
