moshi-opencode-hooks 1.0.13 → 1.0.15

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 +2 -16
  2. package/index.ts +26 -6
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -2,8 +2,6 @@
2
2
 
3
3
  OpenCode plugin that sends real-time events to the [Moshi](https://getmoshi.app) iOS app for live activity integration.
4
4
 
5
- ![Live Activity](https://img.shields.io/badge/Live%20Activity-Moshi-blue)
6
-
7
5
  ## Motivation
8
6
 
9
7
  [Moshi](https://getmoshi.app) is an iOS SSH app that provides live activity widgets on the lock screen and Dynamic Island. While it already supports Cloud Code, this plugin brings the same live activity experience to [OpenCode](https://opencode.ai) users.
@@ -36,27 +34,15 @@ Add to `~/.config/opencode/opencode.json`:
36
34
  }
37
35
  ```
38
36
 
39
- ## Events
40
-
41
- The plugin sends these events to Moshi:
42
-
43
- | OpenCode Event | Moshi Display |
44
- |----------------|--------------|
45
- | `session.created` | Session started |
46
- | `tool.execute.before` | Running tool (Bash, Edit, Write, Read, Glob, Grep, Task) |
47
- | `tool.execute.after` | Tool finished |
48
- | `permission.ask` | Permission required |
49
- | `session.idle` | Task complete |
50
-
51
37
  ## Requirements
52
38
 
53
39
  - [OpenCode](https://opencode.ai)
54
- - [Moshi iOS app](https://getmoshi.app) with Cloud Code subscription
40
+ - [Moshi iOS app](https://getmoshi.app) with Pro subscription
55
41
 
56
42
  ## Moshi Token
57
43
 
58
44
  Get your token from the Moshi iOS app:
59
- 1. Open Moshi → Settings → Coding Agents
45
+ 1. Open Moshi → Settings → Agent Hooks
60
46
  2. Copy the hook token
61
47
 
62
48
  ## Uninstall
package/index.ts CHANGED
@@ -4,12 +4,13 @@ import type { Plugin } from "@opencode-ai/plugin"
4
4
 
5
5
  const TOKEN_PATH = `${homedir()}/.config/moshi/token`
6
6
  const API_URL = "https://api.getmoshi.app/api/v1/agent-events"
7
- const INTERESTING_TOOLS = new Set(["bash", "edit", "write", "read", "glob", "grep", "task", "question", "apply_patch"])
7
+ const INTERESTING_TOOLS = new Set(["bash", "edit", "write", "read", "glob", "grep", "task", "question", "apply_patch", "webfetch", "websearch"])
8
8
 
9
9
  interface HookState {
10
10
  model?: string
11
11
  lastToolName?: string
12
12
  lastStopTime?: number
13
+ isSubagent?: boolean
13
14
  }
14
15
 
15
16
  interface AgentEvent {
@@ -121,6 +122,14 @@ function formatToolName(toolName: string): string {
121
122
  return toolName.charAt(0).toUpperCase() + toolName.slice(1)
122
123
  }
123
124
 
125
+ function formatModelName(model: string | undefined): string | undefined {
126
+ if (!model) return undefined
127
+ return model.replace(/^claude-/, "")
128
+ }
129
+
130
+ const pkg = await import("./package.json", { assert: { type: "json" } })
131
+ const VERSION = pkg.default.version
132
+
124
133
  export const MoshiHooks: Plugin = async ({ client, directory }) => {
125
134
  const setupEventSubscription = async () => {
126
135
  try {
@@ -134,13 +143,17 @@ export const MoshiHooks: Plugin = async ({ client, directory }) => {
134
143
  const state = await readState(sessionId)
135
144
 
136
145
  if (event.type === "session.created") {
146
+ const isSubagent = await isSubagentSession(sessionId)
137
147
  await writeState(sessionId, {
138
148
  model: (event as any).properties?.model,
149
+ isSubagent,
139
150
  })
140
151
  continue
141
152
  }
142
153
 
143
154
  if (event.type === "session.idle") {
155
+ if (state.isSubagent) continue
156
+
144
157
  const now = Date.now() / 1000
145
158
  if (state.lastStopTime && now - state.lastStopTime < 5) continue
146
159
 
@@ -155,7 +168,7 @@ export const MoshiHooks: Plugin = async ({ client, directory }) => {
155
168
  message: "",
156
169
  eventId: crypto.randomUUID(),
157
170
  projectName,
158
- modelName: state.model,
171
+ modelName: formatModelName(state.model),
159
172
  toolName: state.lastToolName,
160
173
  }
161
174
  await sendAgentEvent(client, token, evt)
@@ -180,6 +193,11 @@ export const MoshiHooks: Plugin = async ({ client, directory }) => {
180
193
  }
181
194
 
182
195
  return {
196
+ "tui.toast.show": async (_input: unknown, output: any) => {
197
+ output.message = `moshi-opencode-hooks v${VERSION} is active`
198
+ output.type = "info"
199
+ },
200
+
183
201
  "tool.execute.before": async (input, output) => {
184
202
  const token = await loadToken()
185
203
  if (!token) return
@@ -208,7 +226,7 @@ export const MoshiHooks: Plugin = async ({ client, directory }) => {
208
226
  message: lines.join("\n---\n").slice(0, 512),
209
227
  eventId: crypto.randomUUID(),
210
228
  projectName,
211
- modelName: state.model,
229
+ modelName: formatModelName(state.model),
212
230
  toolName: tool,
213
231
  }
214
232
  await sendAgentEvent(client, token, evt)
@@ -224,7 +242,7 @@ export const MoshiHooks: Plugin = async ({ client, directory }) => {
224
242
  message: "",
225
243
  eventId: crypto.randomUUID(),
226
244
  projectName,
227
- modelName: state.model,
245
+ modelName: formatModelName(state.model),
228
246
  toolName: tool,
229
247
  }
230
248
  await sendAgentEvent(client, token, evt)
@@ -252,7 +270,7 @@ export const MoshiHooks: Plugin = async ({ client, directory }) => {
252
270
  message: "",
253
271
  eventId: crypto.randomUUID(),
254
272
  projectName,
255
- modelName: state.model,
273
+ modelName: formatModelName(state.model),
256
274
  toolName: tool,
257
275
  }
258
276
  await sendAgentEvent(client, token, evt)
@@ -264,6 +282,8 @@ export const MoshiHooks: Plugin = async ({ client, directory }) => {
264
282
 
265
283
  const sessionID = (input as any).sessionID ?? "unknown"
266
284
  const state = await readState(sessionID)
285
+ if (state.isSubagent) return
286
+
267
287
  const projectName = directory ? basename(directory) : undefined
268
288
 
269
289
  const prompt = (input as any).prompt ?? ""
@@ -277,7 +297,7 @@ export const MoshiHooks: Plugin = async ({ client, directory }) => {
277
297
  message: prompt.slice(0, 256),
278
298
  eventId: crypto.randomUUID(),
279
299
  projectName,
280
- modelName: state.model,
300
+ modelName: formatModelName(state.model),
281
301
  }
282
302
  await sendAgentEvent(client, token, evt)
283
303
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "moshi-opencode-hooks",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "OpenCode plugin for Moshi live activity integration",
5
5
  "repository": {
6
6
  "type": "git",