backeer-opencode 0.2.0 → 0.2.2

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.
@@ -0,0 +1,122 @@
1
+ import { limit, rememberBounded } from "./utilities.js"
2
+
3
+ const FEEDBACK_SYMBOLS = {
4
+ info: "•",
5
+ success: "✓",
6
+ applied: "✓",
7
+ warning: "!",
8
+ error: "×",
9
+ }
10
+
11
+ export async function sendSessionMessage(client, sessionID, text) {
12
+ if (typeof client?.session?.prompt !== "function") {
13
+ throw new Error("OpenCode session messaging is unavailable")
14
+ }
15
+ await client.session.prompt({
16
+ path: { id: sessionID },
17
+ body: {
18
+ noReply: true,
19
+ parts: [{ type: "text", text, ignored: true }],
20
+ },
21
+ })
22
+ }
23
+
24
+ export function formatBackeerFeedback(kind, message) {
25
+ const symbol = FEEDBACK_SYMBOLS[kind] ?? FEEDBACK_SYMBOLS.info
26
+ return `> **Backeer** ${symbol} ${limit(message, 300)}`
27
+ }
28
+
29
+ export function createConversationFeedback({ client, reporter }) {
30
+ const sessions = new Map()
31
+ let disposed = false
32
+
33
+ function sessionState(sessionID) {
34
+ let state = sessions.get(sessionID)
35
+ if (!state) {
36
+ state = { idle: false, flushing: false, queue: [], queued: new Set() }
37
+ rememberBounded(sessions, sessionID, state)
38
+ }
39
+ return state
40
+ }
41
+
42
+ async function flush(sessionID, state) {
43
+ if (disposed || state.flushing || !state.idle || state.queue.length === 0) return
44
+ state.flushing = true
45
+ try {
46
+ while (!disposed && state.idle && state.queue.length > 0) {
47
+ const item = state.queue[0]
48
+ try {
49
+ await sendSessionMessage(
50
+ client,
51
+ sessionID,
52
+ formatBackeerFeedback(item.kind, item.message),
53
+ )
54
+ state.queue.shift()
55
+ state.queued.delete(item.key)
56
+ } catch (error) {
57
+ state.idle = false
58
+ reporter.debug("Conversation feedback could not be displayed", error)
59
+ }
60
+ }
61
+ } finally {
62
+ state.flushing = false
63
+ }
64
+ }
65
+
66
+ function enqueue(kind, sessionID, message) {
67
+ if (disposed || typeof sessionID !== "string" || !sessionID || !message) return
68
+ const state = sessionState(sessionID)
69
+ const key = `${sessionID}:${kind}:${message}`
70
+ if (state.queued.has(key)) return
71
+
72
+ state.queue.push({ kind, message: limit(message, 300), key })
73
+ state.queued.add(key)
74
+ while (state.queue.length > 20) {
75
+ const removed = state.queue.shift()
76
+ state.queued.delete(removed.key)
77
+ }
78
+ if (state.idle) void flush(sessionID, state)
79
+ }
80
+
81
+ function setIdle(sessionID, idle) {
82
+ if (typeof sessionID !== "string" || !sessionID) return
83
+ const state = sessionState(sessionID)
84
+ state.idle = idle
85
+ if (idle) void flush(sessionID, state)
86
+ }
87
+
88
+ return {
89
+ info: (sessionID, message) => enqueue("info", sessionID, message),
90
+ success: (sessionID, message) => enqueue("success", sessionID, message),
91
+ applied: (sessionID, message) => enqueue("applied", sessionID, message),
92
+ warning: (sessionID, message) => enqueue("warning", sessionID, message),
93
+ error: (sessionID, message) => enqueue("error", sessionID, message),
94
+
95
+ handle(event) {
96
+ const sessionID = event?.properties?.sessionID
97
+ if (typeof sessionID !== "string") return
98
+
99
+ if (event.type === "session.status") {
100
+ const status = event.properties?.status?.type
101
+ if (status === "idle") setIdle(sessionID, true)
102
+ else if (status === "busy" || status === "retry") setIdle(sessionID, false)
103
+ } else if (event.type === "session.idle") {
104
+ setIdle(sessionID, true)
105
+ } else if (
106
+ event.type === "permission.asked" ||
107
+ event.type === "question.asked" ||
108
+ event.type === "question.v2.asked" ||
109
+ event.type === "todo.updated"
110
+ ) {
111
+ setIdle(sessionID, false)
112
+ } else if (event.type === "session.deleted") {
113
+ sessions.delete(sessionID)
114
+ }
115
+ },
116
+
117
+ dispose() {
118
+ disposed = true
119
+ sessions.clear()
120
+ },
121
+ }
122
+ }
package/src/updates.js CHANGED
@@ -1,4 +1,4 @@
1
- export const PLUGIN_VERSION = "0.2.0"
1
+ export const PLUGIN_VERSION = "0.2.2"
2
2
 
3
3
  const PACKAGE_NAME = "backeer-opencode"
4
4
  const NPM_REGISTRY_URL = "https://registry.npmjs.org"