opencode-discord 1.4.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +38 -0
  2. package/index.ts +82 -23
  3. package/package.json +3 -2
package/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # opencode-discord
2
+
3
+ Discord Rich Presence plugin for [OpenCode](https://opencode.ai). Shows your AI coding activity in Discord.
4
+
5
+ > **Note:** This project is not built by the OpenCode team and is not affiliated with them in any way.
6
+
7
+ ## Install
8
+
9
+ Add to your `opencode.json`:
10
+
11
+ ```json
12
+ {
13
+ "plugin": ["opencode-discord"]
14
+ }
15
+ ```
16
+
17
+ Make sure Discord desktop is running. Your status will show contextual info like:
18
+
19
+ - **Waiting for response...** — AI is generating
20
+ - **Editing main.ts** — editing a file
21
+ - **Running terminal commands** — using bash
22
+ - **Reading config.json** — reading files
23
+ - **No active session** — idle
24
+
25
+ ## Rich Presence Assets
26
+
27
+ Upload these assets to your [Discord Application](https://discord.com/developers/applications) under Rich Presence > Art Assets:
28
+
29
+ | Name | Description |
30
+ |------|-------------|
31
+ | `opencode` | Large image (main logo) |
32
+ | `thinking` | Small image (AI generating) |
33
+ | `active` | Small image (session active) |
34
+ | `idle` | Small image (idle) |
35
+
36
+ ## License
37
+
38
+ MIT
package/index.ts CHANGED
@@ -3,31 +3,60 @@ import { Client } from "@xhayper/discord-rpc"
3
3
 
4
4
  const CLIENT_ID = process.env.DISCORD_CLIENT_ID ?? "1369345745815339008"
5
5
 
6
+ type Activity = "idle" | "thinking" | "editing" | "running" | "reading"
7
+
6
8
  export const DiscordStatus: Plugin = async ({ project }) => {
7
9
  const client = new Client({ clientId: CLIENT_ID })
8
10
  let connected = false
9
11
  let sessionActive = false
10
- let currentProject = project?.name ?? ""
12
+ let currentProject = project?.name ?? "Unknown Project"
11
13
  let startTimestamp = Date.now()
12
14
  let lastEditedFile: string | undefined
15
+ let activity: Activity = "idle"
16
+ let sessionCount = 0
17
+ let lastTool: string | undefined
13
18
 
14
19
  console.log(`[opencode-discord] init clientId=${CLIENT_ID} project=${currentProject}`)
15
20
 
16
21
  async function updatePresence() {
17
- console.log(`[opencode-discord] updatePresence connected=${connected} session=${sessionActive}`)
18
22
  if (!connected) return
19
23
 
20
- const details = sessionActive
21
- ? currentProject
22
- ? `Working on ${currentProject}`
23
- : "Working on a project"
24
- : "No active session"
24
+ let details: string
25
+ let state: string
26
+ let smallImageKey: string
27
+ let smallImageText: string
28
+
29
+ if (!sessionActive) {
30
+ details = "No active session"
31
+ state = currentProject
32
+ smallImageKey = "idle"
33
+ smallImageText = "Idle"
34
+ } else {
35
+ switch (activity) {
36
+ case "thinking":
37
+ details = "Waiting for response..."
38
+ break
39
+ case "editing":
40
+ details = lastEditedFile
41
+ ? `Editing ${lastEditedFile}`
42
+ : `Editing files`
43
+ break
44
+ case "running":
45
+ details = "Running terminal commands"
46
+ break
47
+ case "reading":
48
+ details = lastEditedFile
49
+ ? `Reading ${lastEditedFile}`
50
+ : "Reading files"
51
+ break
52
+ default:
53
+ details = "Session active"
54
+ }
25
55
 
26
- const state = sessionActive
27
- ? lastEditedFile
28
- ? `Editing ${lastEditedFile}`
29
- : "AI session active"
30
- : "Idle"
56
+ state = currentProject
57
+ smallImageKey = activity === "thinking" ? "thinking" : "active"
58
+ smallImageText = activity === "thinking" ? "Generating" : "Active"
59
+ }
31
60
 
32
61
  try {
33
62
  await client.user?.setActivity({
@@ -35,11 +64,14 @@ export const DiscordStatus: Plugin = async ({ project }) => {
35
64
  state,
36
65
  startTimestamp,
37
66
  largeImageKey: "opencode",
38
- largeImageText: "OpenCode",
39
- smallImageKey: sessionActive ? "ai" : "idle",
40
- smallImageText: sessionActive ? "AI Active" : "Idle",
67
+ largeImageText: `OpenCode · ${sessionCount} session${sessionCount !== 1 ? "s" : ""}`,
68
+ smallImageKey,
69
+ smallImageText,
70
+ buttons: [
71
+ { label: "OpenCode", url: "https://opencode.ai" },
72
+ ],
41
73
  })
42
- console.log(`[opencode-discord] presence set: ${details} / ${state}`)
74
+ console.log(`[opencode-discord] presence: ${details} / ${state}`)
43
75
  } catch (e) {
44
76
  console.error(`[opencode-discord] presence failed:`, e)
45
77
  }
@@ -72,27 +104,37 @@ export const DiscordStatus: Plugin = async ({ project }) => {
72
104
 
73
105
  return {
74
106
  event: async ({ event }) => {
75
- console.log(`[opencode-discord] event: ${event.type}`)
76
-
77
107
  switch (event.type) {
78
108
  case "session.created":
79
109
  sessionActive = true
110
+ sessionCount++
80
111
  startTimestamp = Date.now()
81
112
  lastEditedFile = undefined
113
+ activity = "thinking"
82
114
  break
83
115
 
84
116
  case "session.idle":
117
+ sessionActive = true
118
+ activity = "idle"
119
+ break
120
+
85
121
  case "session.error":
86
122
  sessionActive = false
87
- lastEditedFile = undefined
123
+ activity = "idle"
88
124
  break
89
125
 
90
126
  case "session.deleted":
91
127
  sessionActive = false
92
128
  lastEditedFile = undefined
129
+ activity = "idle"
130
+ break
131
+
132
+ case "session.compacted":
133
+ activity = "thinking"
93
134
  break
94
135
 
95
136
  case "file.edited":
137
+ activity = "editing"
96
138
  lastEditedFile =
97
139
  (event as any).file?.split("/").pop() ??
98
140
  (event as any).file
@@ -102,14 +144,31 @@ export const DiscordStatus: Plugin = async ({ project }) => {
102
144
  await updatePresence()
103
145
  },
104
146
 
147
+ "tool.execute.before": async (input) => {
148
+ lastTool = input.tool
149
+
150
+ if (input.tool === "bash") {
151
+ activity = "running"
152
+ } else if (input.tool === "edit" || input.tool === "write") {
153
+ activity = "editing"
154
+ const path = input.args?.filePath as string | undefined
155
+ if (path) lastEditedFile = path.split("/").pop() ?? path
156
+ } else if (input.tool === "read") {
157
+ activity = "reading"
158
+ const path = input.args?.filePath as string | undefined
159
+ if (path) lastEditedFile = path.split("/").pop() ?? path
160
+ }
161
+
162
+ await updatePresence()
163
+ },
164
+
105
165
  "tool.execute.after": async (input) => {
106
166
  if (input.tool === "edit" || input.tool === "write") {
167
+ activity = "editing"
107
168
  const path = input.args?.filePath as string | undefined
108
- if (path) {
109
- lastEditedFile = path.split("/").pop() ?? path
110
- }
111
- await updatePresence()
169
+ if (path) lastEditedFile = path.split("/").pop() ?? path
112
170
  }
171
+ await updatePresence()
113
172
  },
114
173
  }
115
174
  }
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "opencode-discord",
3
- "version": "1.4.0",
3
+ "version": "1.5.1",
4
4
  "description": "Discord Rich Presence plugin for OpenCode — shows your AI coding activity in Discord",
5
5
  "type": "module",
6
6
  "main": "index.ts",
7
7
  "files": [
8
- "index.ts"
8
+ "index.ts",
9
+ "README.md"
9
10
  ],
10
11
  "keywords": [
11
12
  "opencode",