Skip to content
This repository was archived by the owner on May 23, 2026. It is now read-only.

Commit dea09ae

Browse files
committed
fix(discord): wire presence refresh
Install the shipped tagline pool during enable and invoke the Discord update wrapper from the tmux status bar so enabled presence keeps updating.
1 parent 5f8958a commit dea09ae

4 files changed

Lines changed: 104 additions & 0 deletions

File tree

cmd/oca/discord.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ func newDiscordEnableCmd(state *commandState) *cobra.Command {
7979
if err := writeDiscordWrapper(paths.Wrapper, state.configPath); err != nil {
8080
return newCLIError(3, "discord enable: %w", err)
8181
}
82+
if err := installDiscordTaglines(paths.Taglines); err != nil {
83+
return newCLIError(3, "discord enable: %w", err)
84+
}
8285
if err := writeDiscordStatus(paths.Status, discordStatus{Enabled: true, Mode: mode, AppID: appID, Wrapper: paths.Wrapper}); err != nil {
8386
return newCLIError(3, "discord enable: %w", err)
8487
}
@@ -197,6 +200,40 @@ func writeDiscordWrapper(path, configPath string) error {
197200
return os.WriteFile(path, []byte(script), 0o700)
198201
}
199202

203+
func installDiscordTaglines(path string) error {
204+
source := resolveDiscordTaglinesAsset()
205+
if source == "" {
206+
return nil
207+
}
208+
data, err := os.ReadFile(source)
209+
if err != nil {
210+
return err
211+
}
212+
if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil {
213+
return err
214+
}
215+
return os.WriteFile(path, data, 0o600)
216+
}
217+
218+
func resolveDiscordTaglinesAsset() string {
219+
filename := filepath.Join("discord", "taglines.toml")
220+
var candidates []string
221+
if root := os.Getenv("OCA_ASSETS_ROOT"); root != "" {
222+
candidates = append(candidates, filepath.Join(root, filename))
223+
}
224+
if exe, err := os.Executable(); err == nil {
225+
candidates = append(candidates, filepath.Join(filepath.Dir(exe), "..", "assets", filename))
226+
}
227+
candidates = append(candidates, filepath.Join("assets", filename))
228+
229+
for _, candidate := range candidates {
230+
if info, err := os.Stat(candidate); err == nil && !info.IsDir() {
231+
return candidate
232+
}
233+
}
234+
return ""
235+
}
236+
200237
func writeDiscordStatus(path string, status discordStatus) error {
201238
if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil {
202239
return err

cmd/oca/discord_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ func TestDiscordEnableWritesWrapperAndStatus(t *testing.T) {
1616
tmp := t.TempDir()
1717
stackPath := writeDiscordTestStack(t, tmp)
1818
t.Setenv("OCA_CACHE_DIR", filepath.Join(tmp, "cache"))
19+
t.Setenv("OCA_ASSETS_ROOT", filepath.Join(tmp, "assets"))
20+
assetPath := filepath.Join(tmp, "assets", "discord", "taglines.toml")
21+
if err := os.MkdirAll(filepath.Dir(assetPath), 0o755); err != nil {
22+
t.Fatal(err)
23+
}
24+
if err := os.WriteFile(assetPath, []byte("taglines = [\"Focused delivery\", \"Spec-driven work\"]\n"), 0o644); err != nil {
25+
t.Fatal(err)
26+
}
1927

2028
var stdout bytes.Buffer
2129
cmd := newRootCmd(commandOptions{Stdout: &stdout, Stderr: &stdout, Environment: brand.Environment{IsTTY: false}})
@@ -35,6 +43,13 @@ func TestDiscordEnableWritesWrapperAndStatus(t *testing.T) {
3543
if status.Mode != "builtin" {
3644
t.Fatalf("mode = %q, want builtin", status.Mode)
3745
}
46+
taglines, err := os.ReadFile(paths.Taglines)
47+
if err != nil {
48+
t.Fatalf("taglines not installed: %v", err)
49+
}
50+
if !strings.Contains(string(taglines), "Focused delivery") {
51+
t.Fatalf("taglines content = %q", string(taglines))
52+
}
3853
if !strings.Contains(stdout.String(), "Discord Rich Presence enabled") {
3954
t.Fatalf("stdout missing enabled message: %q", stdout.String())
4055
}

lib/status_bar.sh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,35 @@ _oca_status_date() {
5353
printf '%s' "$(date '+%Y-%m-%d')"
5454
}
5555

56+
_oca_cache_dir() {
57+
if [[ -n "${OCA_CACHE_DIR:-}" ]]; then
58+
printf '%s' "$OCA_CACHE_DIR"
59+
return 0
60+
fi
61+
if [[ -n "${XDG_RUNTIME_DIR:-}" ]]; then
62+
printf '%s/opencode-advance' "$XDG_RUNTIME_DIR"
63+
return 0
64+
fi
65+
printf '%s/opencode-advance-%s' "${TMPDIR:-/tmp}" "${USER:-unknown}"
66+
}
67+
68+
_oca_discord_update() {
69+
local wrapper
70+
wrapper="$(_oca_cache_dir)/discord/discord-update.sh"
71+
if [[ -x "$wrapper" ]]; then
72+
"$wrapper" >/dev/null 2>&1 &
73+
fi
74+
}
75+
5676
# ── Row Builders ───────────────────────────────────────────
5777

5878
# Row 0: [session_name] │ [git branch] │ [ADV state] │ [host] [time]
5979
oca_status_row0() {
6080
local session_name="$1"
6181
local pane_path="$2"
6282

83+
_oca_discord_update
84+
6385
# Session name (left)
6486
printf '%s' "$(_oca_status_color '#8B9FE0')"
6587
printf ' %s' "$session_name"
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)
5+
TMP_DIR=$(mktemp -d)
6+
trap 'rm -rf "$TMP_DIR"' EXIT
7+
8+
export OCA_CACHE_DIR="$TMP_DIR/cache"
9+
mkdir -p "$OCA_CACHE_DIR/discord"
10+
cat >"$OCA_CACHE_DIR/discord/discord-update.sh" <<'SH'
11+
#!/usr/bin/env sh
12+
printf invoked >"$OCA_CACHE_DIR/discord/hook-ran"
13+
SH
14+
chmod +x "$OCA_CACHE_DIR/discord/discord-update.sh"
15+
16+
bash "$ROOT_DIR/lib/status_bar.sh" row0 oca-test "$ROOT_DIR" >/dev/null
17+
18+
for _ in 1 2 3 4 5; do
19+
if [[ -f "$OCA_CACHE_DIR/discord/hook-ran" ]]; then
20+
break
21+
fi
22+
sleep 0.1
23+
done
24+
25+
if [[ "$(cat "$OCA_CACHE_DIR/discord/hook-ran" 2>/dev/null || true)" != "invoked" ]]; then
26+
echo "FAIL: Discord update wrapper was not invoked by status bar" >&2
27+
exit 1
28+
fi
29+
30+
echo "discord status hook test passed"

0 commit comments

Comments
 (0)