ha-opencode 0.1.0

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.
package/dist/mqtt.js ADDED
@@ -0,0 +1,141 @@
1
+ import mqtt from "mqtt";
2
+ export async function connectMqtt(config, will) {
3
+ const options = {
4
+ clientId: config.clientId,
5
+ clean: true,
6
+ connectTimeout: 10000,
7
+ reconnectPeriod: 5000,
8
+ };
9
+ if (config.username) {
10
+ options.username = config.username;
11
+ }
12
+ if (config.password) {
13
+ options.password = config.password;
14
+ }
15
+ // Configure Last Will and Testament (LWT) for availability tracking
16
+ if (will) {
17
+ options.will = {
18
+ topic: will.topic,
19
+ payload: Buffer.from(will.payload),
20
+ qos: 1,
21
+ retain: will.retain,
22
+ };
23
+ }
24
+ const url = `mqtt://${config.host}:${config.port}`;
25
+ return new Promise((resolve, reject) => {
26
+ const client = mqtt.connect(url, options);
27
+ let connected = false;
28
+ const timeout = setTimeout(() => {
29
+ if (!connected) {
30
+ client.end(true);
31
+ reject(new Error(`MQTT connection timeout to ${url}`));
32
+ }
33
+ }, options.connectTimeout);
34
+ client.on("connect", () => {
35
+ connected = true;
36
+ clearTimeout(timeout);
37
+ resolve(createWrapper(client));
38
+ });
39
+ client.on("error", (err) => {
40
+ if (!connected) {
41
+ clearTimeout(timeout);
42
+ client.end(true); // Stop reconnection attempts
43
+ reject(err);
44
+ }
45
+ });
46
+ });
47
+ }
48
+ /**
49
+ * Check if a topic matches a pattern with MQTT wildcards.
50
+ * + matches a single level, # matches multiple levels.
51
+ */
52
+ function topicMatchesPattern(topic, pattern) {
53
+ const topicParts = topic.split("/");
54
+ const patternParts = pattern.split("/");
55
+ for (let i = 0; i < patternParts.length; i++) {
56
+ const patternPart = patternParts[i];
57
+ if (patternPart === "#") {
58
+ // # matches everything from this point
59
+ return true;
60
+ }
61
+ if (i >= topicParts.length) {
62
+ // Topic is shorter than pattern
63
+ return false;
64
+ }
65
+ if (patternPart !== "+" && patternPart !== topicParts[i]) {
66
+ // Not a wildcard and doesn't match
67
+ return false;
68
+ }
69
+ }
70
+ // Pattern and topic must be same length (unless pattern ends with #)
71
+ return topicParts.length === patternParts.length;
72
+ }
73
+ function createWrapper(client) {
74
+ const handlers = new Map();
75
+ client.on("message", (topic, payload) => {
76
+ // Check all registered patterns for a match
77
+ for (const [pattern, handler] of handlers) {
78
+ if (topicMatchesPattern(topic, pattern)) {
79
+ try {
80
+ handler(topic, payload.toString());
81
+ }
82
+ catch (err) {
83
+ console.error(`[ha-opencode] Error handling message on ${topic}:`, err);
84
+ }
85
+ break; // Only call first matching handler
86
+ }
87
+ }
88
+ });
89
+ return {
90
+ publish(topic, payload, retain = false) {
91
+ return new Promise((resolve, reject) => {
92
+ const message = typeof payload === "string" ? payload : JSON.stringify(payload);
93
+ client.publish(topic, message, { qos: 1, retain }, (err) => {
94
+ if (err) {
95
+ reject(err);
96
+ }
97
+ else {
98
+ resolve();
99
+ }
100
+ });
101
+ });
102
+ },
103
+ subscribe(topic, handler) {
104
+ return new Promise((resolve, reject) => {
105
+ client.subscribe(topic, { qos: 1 }, (err) => {
106
+ if (err) {
107
+ reject(err);
108
+ }
109
+ else {
110
+ handlers.set(topic, handler);
111
+ resolve();
112
+ }
113
+ });
114
+ });
115
+ },
116
+ unsubscribe(topic) {
117
+ return new Promise((resolve, reject) => {
118
+ client.unsubscribe(topic, (err) => {
119
+ if (err) {
120
+ reject(err);
121
+ }
122
+ else {
123
+ handlers.delete(topic);
124
+ resolve();
125
+ }
126
+ });
127
+ });
128
+ },
129
+ isConnected() {
130
+ return client.connected;
131
+ },
132
+ close() {
133
+ return new Promise((resolve) => {
134
+ client.end(false, {}, () => {
135
+ resolve();
136
+ });
137
+ });
138
+ },
139
+ };
140
+ }
141
+ //# sourceMappingURL=mqtt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mqtt.js","sourceRoot":"","sources":["../src/mqtt.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Cross-platform terminal notification utilities.
3
+ * Uses Kitty's OSC 99 protocol with BEL fallback.
4
+ * @see https://sw.kovidgoyal.net/kitty/desktop-notifications/
5
+ */
6
+ /**
7
+ * Trigger a terminal notification.
8
+ * Uses OSC 99 (Kitty's native notification protocol) with BEL fallback.
9
+ */
10
+ export declare function notify(title: string, message: string): void;
11
+ //# sourceMappingURL=notify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notify.d.ts","sourceRoot":"","sources":["../src/notify.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;GAGG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAW3D"}
package/dist/notify.js ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Cross-platform terminal notification utilities.
3
+ * Uses Kitty's OSC 99 protocol with BEL fallback.
4
+ * @see https://sw.kovidgoyal.net/kitty/desktop-notifications/
5
+ */
6
+ /**
7
+ * Trigger a terminal notification.
8
+ * Uses OSC 99 (Kitty's native notification protocol) with BEL fallback.
9
+ */
10
+ export function notify(title, message) {
11
+ // OSC 99 - Kitty desktop notification protocol
12
+ // Format: ESC ] 99 ; i=<id>:d=0:p=title ; <body> BEL
13
+ const id = Date.now().toString();
14
+ const osc99 = `\x1b]99;i=${id}:d=0:p=title;${title}\x07\x1b]99;i=${id}:d=1:p=body;${message}\x07`;
15
+ // Write OSC 99 notification
16
+ process.stdout.write(osc99);
17
+ // Also trigger terminal bell (BEL) for audible alert
18
+ process.stdout.write("\x07");
19
+ }
20
+ //# sourceMappingURL=notify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notify.js","sourceRoot":"","sources":["../src/notify.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;GAGG;AACH,MAAM,UAAU,MAAM,CAAC,KAAa,EAAE,OAAe;IACnD,+CAA+C;IAC/C,qDAAqD;IACrD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;IACjC,MAAM,KAAK,GAAG,aAAa,EAAE,gBAAgB,KAAK,iBAAiB,EAAE,eAAe,OAAO,MAAM,CAAC;IAElG,4BAA4B;IAC5B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAE5B,qDAAqD;IACrD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,42 @@
1
+ import type { Event } from "@opencode-ai/sdk";
2
+ import type { Discovery, PermissionInfo } from "./discovery.js";
3
+ export declare class StateTracker {
4
+ private readonly discovery;
5
+ private state;
6
+ private pendingPermission;
7
+ private currentSessionId;
8
+ private deviceNameUpdated;
9
+ constructor(discovery: Discovery);
10
+ getCurrentSessionId(): string | null;
11
+ /**
12
+ * Check if we have a valid session title for updating the device friendly name.
13
+ */
14
+ private hasValidTitle;
15
+ /**
16
+ * Initialize the state tracker.
17
+ * Registers the device with Home Assistant immediately since we have the session ID.
18
+ */
19
+ initialize(): Promise<void>;
20
+ getPendingPermission(): PermissionInfo | null;
21
+ handleEvent(event: Event): Promise<void>;
22
+ private onSessionCreated;
23
+ private onSessionUpdated;
24
+ /**
25
+ * Update the device friendly name in Home Assistant if we have a valid title
26
+ * and haven't done so yet.
27
+ */
28
+ private maybeUpdateDeviceName;
29
+ private onSessionIdle;
30
+ private onSessionError;
31
+ private onMessageUpdated;
32
+ private onMessagePartUpdated;
33
+ private onPermissionUpdated;
34
+ private onPermissionReplied;
35
+ clearPermission(): Promise<void>;
36
+ private updateActivity;
37
+ private updateState;
38
+ private publishStateAttributes;
39
+ private publish;
40
+ private publishAll;
41
+ }
42
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAc,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAa,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAmB3E,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,iBAAiB,CAAS;gBAEtB,SAAS,EAAE,SAAS;IAkBhC,mBAAmB,IAAI,MAAM,GAAG,IAAI;IAIpC;;OAEG;IACH,OAAO,CAAC,aAAa;IAUrB;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IASjC,oBAAoB,IAAI,cAAc,GAAG,IAAI;IAIvC,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;YAyChC,gBAAgB;YAqBhB,gBAAgB;IAoB9B;;;OAGG;YACW,qBAAqB;YASrB,aAAa;YAWb,cAAc;YAmBd,gBAAgB;YAiChB,oBAAoB;YAoCpB,mBAAmB;YAuBnB,mBAAmB;IAW3B,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtC,OAAO,CAAC,cAAc;YAIR,WAAW;YAiBX,sBAAsB;YAUtB,OAAO;YAWP,UAAU;CAUzB"}
package/dist/state.js ADDED
@@ -0,0 +1,282 @@
1
+ import { hostname } from "os";
2
+ export class StateTracker {
3
+ discovery;
4
+ state;
5
+ pendingPermission = null;
6
+ currentSessionId = null;
7
+ deviceNameUpdated = false;
8
+ constructor(discovery) {
9
+ this.discovery = discovery;
10
+ this.state = {
11
+ state: "idle",
12
+ previousState: null,
13
+ sessionTitle: "Untitled",
14
+ model: "unknown",
15
+ currentTool: "none",
16
+ tokensInput: 0,
17
+ tokensOutput: 0,
18
+ cost: 0,
19
+ lastActivity: new Date().toISOString(),
20
+ agent: null,
21
+ currentAgent: null,
22
+ errorMessage: null,
23
+ };
24
+ }
25
+ getCurrentSessionId() {
26
+ return this.currentSessionId;
27
+ }
28
+ /**
29
+ * Check if we have a valid session title for updating the device friendly name.
30
+ */
31
+ hasValidTitle() {
32
+ const title = this.state.sessionTitle;
33
+ return !!(title &&
34
+ title !== "No active session" &&
35
+ title !== "Untitled" &&
36
+ title.toLowerCase() !== "unknown");
37
+ }
38
+ /**
39
+ * Initialize the state tracker.
40
+ * Registers the device with Home Assistant immediately since we have the session ID.
41
+ */
42
+ async initialize() {
43
+ await this.discovery.registerDevice();
44
+ await this.discovery.publishDeviceInfo();
45
+ await this.discovery.publishAvailable();
46
+ await this.publishAll();
47
+ await this.publishStateAttributes();
48
+ await this.discovery.publishPermission(null);
49
+ }
50
+ getPendingPermission() {
51
+ return this.pendingPermission;
52
+ }
53
+ async handleEvent(event) {
54
+ try {
55
+ switch (event.type) {
56
+ case "session.created":
57
+ await this.onSessionCreated(event);
58
+ break;
59
+ case "session.updated":
60
+ await this.onSessionUpdated(event);
61
+ break;
62
+ case "session.idle":
63
+ await this.onSessionIdle(event);
64
+ break;
65
+ case "session.error":
66
+ await this.onSessionError(event);
67
+ break;
68
+ case "message.updated":
69
+ await this.onMessageUpdated(event);
70
+ break;
71
+ case "message.part.updated":
72
+ await this.onMessagePartUpdated(event);
73
+ break;
74
+ case "permission.updated":
75
+ await this.onPermissionUpdated(event);
76
+ break;
77
+ case "permission.replied":
78
+ await this.onPermissionReplied(event);
79
+ break;
80
+ }
81
+ }
82
+ catch (err) {
83
+ console.error(`[ha-opencode] Error in handleEvent for '${event.type}':`, err);
84
+ console.error(`[ha-opencode] Event properties:`, JSON.stringify(event.properties, null, 2));
85
+ throw err;
86
+ }
87
+ }
88
+ async onSessionCreated(event) {
89
+ this.currentSessionId = event.properties.info.id;
90
+ this.state.sessionTitle = event.properties.info.title || "Untitled";
91
+ this.state.tokensInput = 0;
92
+ this.state.tokensOutput = 0;
93
+ this.state.cost = 0;
94
+ this.updateActivity();
95
+ // Check if we got a valid title on creation
96
+ await this.maybeUpdateDeviceName();
97
+ await this.publish("session_title", this.state.sessionTitle);
98
+ await this.updateState("idle");
99
+ await this.publish("tokens_input", this.state.tokensInput);
100
+ await this.publish("tokens_output", this.state.tokensOutput);
101
+ await this.publish("cost", this.state.cost);
102
+ await this.publish("last_activity", this.state.lastActivity);
103
+ }
104
+ async onSessionUpdated(event) {
105
+ const title = event.properties.info.title;
106
+ const titleChanged = title && title !== this.state.sessionTitle;
107
+ if (titleChanged) {
108
+ this.state.sessionTitle = title;
109
+ }
110
+ this.updateActivity();
111
+ // Update device friendly name when we get a valid title
112
+ await this.maybeUpdateDeviceName();
113
+ if (titleChanged) {
114
+ await this.publish("session_title", this.state.sessionTitle);
115
+ }
116
+ await this.publish("last_activity", this.state.lastActivity);
117
+ }
118
+ /**
119
+ * Update the device friendly name in Home Assistant if we have a valid title
120
+ * and haven't done so yet.
121
+ */
122
+ async maybeUpdateDeviceName() {
123
+ if (!this.deviceNameUpdated && this.hasValidTitle()) {
124
+ await this.discovery.updateDeviceName(this.state.sessionTitle);
125
+ // Also update device_id attributes with new device name
126
+ await this.discovery.publishDeviceInfo();
127
+ this.deviceNameUpdated = true;
128
+ }
129
+ }
130
+ async onSessionIdle(_event) {
131
+ this.state.currentTool = "none";
132
+ this.updateActivity();
133
+ await this.updateState("idle");
134
+ await this.publish("current_tool", this.state.currentTool);
135
+ await this.publish("last_activity", this.state.lastActivity);
136
+ }
137
+ async onSessionError(event) {
138
+ this.updateActivity();
139
+ // Capture error message if available
140
+ const error = event.properties.error;
141
+ if (error && typeof error === "object" && "message" in error) {
142
+ this.state.errorMessage = String(error.message);
143
+ }
144
+ else if (error && typeof error === "object" && "name" in error) {
145
+ this.state.errorMessage = String(error.name);
146
+ }
147
+ else {
148
+ this.state.errorMessage = "Unknown error";
149
+ }
150
+ await this.updateState("error");
151
+ await this.publish("last_activity", this.state.lastActivity);
152
+ }
153
+ async onMessageUpdated(event) {
154
+ const message = event.properties.info;
155
+ if (message.role === "user") {
156
+ // Track primary agent from user message
157
+ if (message.agent && message.agent !== this.state.agent) {
158
+ this.state.agent = message.agent;
159
+ // Reset current agent when new user message arrives
160
+ this.state.currentAgent = null;
161
+ await this.publishStateAttributes();
162
+ }
163
+ }
164
+ else if (message.role === "assistant") {
165
+ // Update model info
166
+ this.state.model = `${message.providerID}/${message.modelID}`;
167
+ await this.publish("model", this.state.model);
168
+ // Update token counts and cost
169
+ // Note: SDK may return Decimal objects, so convert to primitives
170
+ this.state.tokensInput = Number(message.tokens.input);
171
+ this.state.tokensOutput = Number(message.tokens.output);
172
+ this.state.cost = Number(message.cost);
173
+ await this.publish("tokens_input", this.state.tokensInput);
174
+ await this.publish("tokens_output", this.state.tokensOutput);
175
+ await this.publish("cost", this.state.cost);
176
+ }
177
+ this.updateActivity();
178
+ await this.publish("last_activity", this.state.lastActivity);
179
+ }
180
+ async onMessagePartUpdated(event) {
181
+ const part = event.properties.part;
182
+ // When receiving text parts with deltas, the model is actively working
183
+ if (part.type === "text" && event.properties.delta) {
184
+ await this.updateState("working");
185
+ }
186
+ // Track agent/sub-agent switching
187
+ if (part.type === "agent") {
188
+ if (part.name !== this.state.currentAgent) {
189
+ this.state.currentAgent = part.name;
190
+ await this.publishStateAttributes();
191
+ }
192
+ }
193
+ // Track tool execution
194
+ if (part.type === "tool") {
195
+ const toolState = part.state;
196
+ if (toolState.status === "running") {
197
+ this.state.currentTool = part.tool;
198
+ await this.updateState("working");
199
+ await this.publish("current_tool", this.state.currentTool);
200
+ }
201
+ else if (toolState.status === "completed" || toolState.status === "error") {
202
+ this.state.currentTool = "none";
203
+ await this.publish("current_tool", this.state.currentTool);
204
+ }
205
+ }
206
+ this.updateActivity();
207
+ await this.publish("last_activity", this.state.lastActivity);
208
+ }
209
+ async onPermissionUpdated(event) {
210
+ const permission = event.properties;
211
+ this.pendingPermission = {
212
+ id: permission.id,
213
+ type: permission.type,
214
+ title: permission.title,
215
+ sessionID: permission.sessionID,
216
+ messageID: permission.messageID,
217
+ callID: permission.callID,
218
+ pattern: permission.pattern,
219
+ metadata: permission.metadata,
220
+ };
221
+ this.updateActivity();
222
+ await this.updateState("waiting_permission");
223
+ await this.publish("last_activity", this.state.lastActivity);
224
+ await this.discovery.publishPermission(this.pendingPermission);
225
+ }
226
+ async onPermissionReplied(_event) {
227
+ this.pendingPermission = null;
228
+ this.updateActivity();
229
+ await this.updateState("working");
230
+ await this.publish("last_activity", this.state.lastActivity);
231
+ await this.discovery.publishPermission(null);
232
+ }
233
+ async clearPermission() {
234
+ this.pendingPermission = null;
235
+ await this.discovery.publishPermission(null);
236
+ }
237
+ updateActivity() {
238
+ this.state.lastActivity = new Date().toISOString();
239
+ }
240
+ async updateState(newState) {
241
+ if (this.state.state !== newState) {
242
+ this.state.previousState = this.state.state;
243
+ this.state.state = newState;
244
+ // Clear error message when transitioning away from error state
245
+ if (newState !== "error") {
246
+ this.state.errorMessage = null;
247
+ }
248
+ // IMPORTANT: Publish attributes BEFORE state so that when HA automation
249
+ // triggers on state topic, the previous_state attribute is already available
250
+ await this.publishStateAttributes();
251
+ await this.publish("state", this.state.state);
252
+ }
253
+ }
254
+ async publishStateAttributes() {
255
+ await this.discovery.publishAttributes("state", {
256
+ previous_state: this.state.previousState,
257
+ agent: this.state.agent,
258
+ current_agent: this.state.currentAgent,
259
+ hostname: hostname(),
260
+ error_message: this.state.errorMessage,
261
+ });
262
+ }
263
+ async publish(key, value) {
264
+ try {
265
+ await this.discovery.publishState(key, value);
266
+ }
267
+ catch (err) {
268
+ console.error(`[ha-opencode] Failed to publish ${key}:`, err);
269
+ }
270
+ }
271
+ async publishAll() {
272
+ await this.publish("state", this.state.state);
273
+ await this.publish("session_title", this.state.sessionTitle);
274
+ await this.publish("model", this.state.model);
275
+ await this.publish("current_tool", this.state.currentTool);
276
+ await this.publish("tokens_input", this.state.tokensInput);
277
+ await this.publish("tokens_output", this.state.tokensOutput);
278
+ await this.publish("cost", this.state.cost);
279
+ await this.publish("last_activity", this.state.lastActivity);
280
+ }
281
+ }
282
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "ha-opencode",
3
+ "version": "0.1.0",
4
+ "description": "OpenCode plugin for Home Assistant integration via MQTT",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "blueprints",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://gitlab.com/opencode-home-assistant/opencode-plugin.git"
17
+ },
18
+ "homepage": "https://gitlab.com/opencode-home-assistant/opencode-plugin#readme",
19
+ "bugs": {
20
+ "url": "https://gitlab.com/opencode-home-assistant/opencode-plugin/-/issues"
21
+ },
22
+ "scripts": {
23
+ "build": "tsc",
24
+ "dev": "tsc --watch",
25
+ "test": "vitest run",
26
+ "test:watch": "vitest",
27
+ "test:coverage": "vitest run --coverage",
28
+ "prepublishOnly": "npm run build && npm test"
29
+ },
30
+ "keywords": [
31
+ "opencode",
32
+ "home-assistant",
33
+ "mqtt",
34
+ "plugin"
35
+ ],
36
+ "author": "Stephen Golub",
37
+ "license": "MIT",
38
+ "dependencies": {
39
+ "mqtt": "^5.10.0",
40
+ "source-map-support": "^0.5.21"
41
+ },
42
+ "devDependencies": {
43
+ "@opencode-ai/plugin": "^1.0.23",
44
+ "@types/node": "^22.0.0",
45
+ "@types/source-map-support": "^0.5.10",
46
+ "@vitest/coverage-v8": "^4.0.16",
47
+ "typescript": "^5.7.0",
48
+ "vitest": "^4.0.16"
49
+ },
50
+ "peerDependencies": {
51
+ "@opencode-ai/plugin": ">=1.0.0"
52
+ }
53
+ }