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/LICENSE +21 -0
- package/README.md +315 -0
- package/blueprints/opencode_permission_response.yaml +81 -0
- package/blueprints/opencode_state_notifications.yaml +191 -0
- package/dist/cleanup.d.ts +30 -0
- package/dist/cleanup.d.ts.map +1 -0
- package/dist/cleanup.js +125 -0
- package/dist/cleanup.js.map +1 -0
- package/dist/commands.d.ts +24 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +309 -0
- package/dist/commands.js.map +1 -0
- package/dist/config.d.ts +28 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +18 -0
- package/dist/config.js.map +1 -0
- package/dist/discovery.d.ts +129 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +257 -0
- package/dist/discovery.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +175 -0
- package/dist/index.js.map +1 -0
- package/dist/mqtt.d.ts +16 -0
- package/dist/mqtt.d.ts.map +1 -0
- package/dist/mqtt.js +141 -0
- package/dist/mqtt.js.map +1 -0
- package/dist/notify.d.ts +11 -0
- package/dist/notify.d.ts.map +1 -0
- package/dist/notify.js +20 -0
- package/dist/notify.js.map +1 -0
- package/dist/state.d.ts +42 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +282 -0
- package/dist/state.js.map +1 -0
- package/package.json +53 -0
package/dist/cleanup.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { Discovery } from "./discovery.js";
|
|
2
|
+
const CLEANUP_RESPONSE_TOPIC = "opencode/cleanup/response";
|
|
3
|
+
/**
|
|
4
|
+
* Find all OpenCode sessions by subscribing to last_activity topics.
|
|
5
|
+
* Returns a map of deviceId -> last activity timestamp.
|
|
6
|
+
*/
|
|
7
|
+
async function discoverSessions(mqtt, timeoutMs = 5000) {
|
|
8
|
+
const sessions = new Map();
|
|
9
|
+
return new Promise((resolve) => {
|
|
10
|
+
const topic = "opencode/+/last_activity";
|
|
11
|
+
let timeoutId;
|
|
12
|
+
const handleMessage = (_topic, payload) => {
|
|
13
|
+
// Extract device ID from topic: opencode/{deviceId}/last_activity
|
|
14
|
+
const match = _topic.match(/^opencode\/([^/]+)\/last_activity$/);
|
|
15
|
+
if (match) {
|
|
16
|
+
const deviceId = match[1];
|
|
17
|
+
const timestamp = new Date(payload);
|
|
18
|
+
if (!isNaN(timestamp.getTime())) {
|
|
19
|
+
sessions.set(deviceId, timestamp);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
// Subscribe and collect retained messages
|
|
24
|
+
mqtt.subscribe(topic, handleMessage).then(() => {
|
|
25
|
+
// Wait for retained messages to arrive, then resolve
|
|
26
|
+
timeoutId = setTimeout(async () => {
|
|
27
|
+
try {
|
|
28
|
+
await mqtt.unsubscribe(topic);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// Ignore unsubscribe errors
|
|
32
|
+
}
|
|
33
|
+
resolve(sessions);
|
|
34
|
+
}, timeoutMs);
|
|
35
|
+
}).catch(() => {
|
|
36
|
+
clearTimeout(timeoutId);
|
|
37
|
+
resolve(sessions);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Remove a stale session's entities from Home Assistant.
|
|
43
|
+
*/
|
|
44
|
+
async function removeSession(mqtt, deviceId, haConfig) {
|
|
45
|
+
const entityKeys = Discovery.getEntityKeys();
|
|
46
|
+
const discoveryPrefix = haConfig.discoveryPrefix;
|
|
47
|
+
// Publish empty config to remove each entity from HA
|
|
48
|
+
for (const key of entityKeys) {
|
|
49
|
+
const configTopic = `${discoveryPrefix}/sensor/${deviceId}/${key}/config`;
|
|
50
|
+
await mqtt.publish(configTopic, "", true);
|
|
51
|
+
}
|
|
52
|
+
// Clear retained state messages
|
|
53
|
+
const stateTopicBase = `opencode/${deviceId}`;
|
|
54
|
+
for (const key of entityKeys) {
|
|
55
|
+
await mqtt.publish(`${stateTopicBase}/${key}`, "", true);
|
|
56
|
+
// Also clear attributes topics for entities that have them
|
|
57
|
+
if (key === "device_id" || key === "state" || key === "permission") {
|
|
58
|
+
await mqtt.publish(`${stateTopicBase}/${key}/attributes`, "", true);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Clear availability topic
|
|
62
|
+
await mqtt.publish(`${stateTopicBase}/availability`, "", true);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Clean up stale OpenCode sessions from Home Assistant.
|
|
66
|
+
* Removes entities for sessions that haven't been active in `maxAgeDays` days.
|
|
67
|
+
*
|
|
68
|
+
* @param mqtt - MQTT client wrapper
|
|
69
|
+
* @param config - Cleanup configuration
|
|
70
|
+
* @returns Result with count and IDs of removed sessions
|
|
71
|
+
*/
|
|
72
|
+
export async function cleanupStaleSessions(mqtt, config) {
|
|
73
|
+
const maxAgeMs = config.maxAgeDays * 24 * 60 * 60 * 1000;
|
|
74
|
+
const cutoffDate = new Date(Date.now() - maxAgeMs);
|
|
75
|
+
// Discover all sessions
|
|
76
|
+
const sessions = await discoverSessions(mqtt);
|
|
77
|
+
const removedSessionIds = [];
|
|
78
|
+
for (const [deviceId, lastActivity] of sessions) {
|
|
79
|
+
if (lastActivity < cutoffDate) {
|
|
80
|
+
try {
|
|
81
|
+
await removeSession(mqtt, deviceId, config.haConfig);
|
|
82
|
+
removedSessionIds.push(deviceId);
|
|
83
|
+
console.log(`[ha-opencode] Cleaned up stale session: ${deviceId} (last active: ${lastActivity.toISOString()})`);
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
console.error(`[ha-opencode] Failed to clean up session ${deviceId}:`, err);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
sessionsRemoved: removedSessionIds.length,
|
|
92
|
+
sessionIds: removedSessionIds,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Manually trigger cleanup and publish results to MQTT.
|
|
97
|
+
* Called via the cleanup_stale_sessions command.
|
|
98
|
+
*/
|
|
99
|
+
export async function cleanupStaleSessionsManual(mqtt, config) {
|
|
100
|
+
const result = await cleanupStaleSessions(mqtt, config);
|
|
101
|
+
// Publish result to global cleanup response topic
|
|
102
|
+
await mqtt.publish(CLEANUP_RESPONSE_TOPIC, {
|
|
103
|
+
type: "cleanup_result",
|
|
104
|
+
sessions_removed: result.sessionsRemoved,
|
|
105
|
+
session_ids: result.sessionIds,
|
|
106
|
+
max_age_days: config.maxAgeDays,
|
|
107
|
+
timestamp: new Date().toISOString(),
|
|
108
|
+
}, false);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Run cleanup in the background (non-blocking).
|
|
112
|
+
* Logs results but doesn't throw on error.
|
|
113
|
+
*/
|
|
114
|
+
export function runCleanupInBackground(mqtt, config) {
|
|
115
|
+
cleanupStaleSessions(mqtt, config)
|
|
116
|
+
.then((result) => {
|
|
117
|
+
if (result.sessionsRemoved > 0) {
|
|
118
|
+
console.log(`[ha-opencode] Cleanup complete: removed ${result.sessionsRemoved} stale session(s)`);
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
.catch((err) => {
|
|
122
|
+
console.error("[ha-opencode] Background cleanup failed:", err);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=cleanup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleanup.js","sourceRoot":"","sources":["../src/cleanup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { OpencodeClient } from "@opencode-ai/sdk";
|
|
2
|
+
import type { MqttWrapper } from "./mqtt.js";
|
|
3
|
+
import type { Discovery } from "./discovery.js";
|
|
4
|
+
import type { StateTracker } from "./state.js";
|
|
5
|
+
import type { HaConfig } from "./config.js";
|
|
6
|
+
export declare class CommandHandler {
|
|
7
|
+
private readonly mqtt;
|
|
8
|
+
private readonly discovery;
|
|
9
|
+
private readonly state;
|
|
10
|
+
private readonly client;
|
|
11
|
+
private readonly haConfig;
|
|
12
|
+
constructor(mqtt: MqttWrapper, discovery: Discovery, state: StateTracker, client: OpencodeClient, haConfig: HaConfig);
|
|
13
|
+
start(): Promise<void>;
|
|
14
|
+
private handleMessage;
|
|
15
|
+
private processCommand;
|
|
16
|
+
private handleCleanup;
|
|
17
|
+
private handlePrompt;
|
|
18
|
+
private handleGetAgents;
|
|
19
|
+
private handleGetHistory;
|
|
20
|
+
private handleGetHistorySince;
|
|
21
|
+
private fetchSessionHistory;
|
|
22
|
+
private handlePermissionResponse;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AA2F5C,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAc;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;gBAGlC,IAAI,EAAE,WAAW,EACjB,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,QAAQ;IASd,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAK5B,OAAO,CAAC,aAAa;YA4BP,cAAc;YAyBd,aAAa;YAkBb,YAAY;YAgCZ,eAAe;YA6Bf,gBAAgB;YA4BhB,qBAAqB;YAwCrB,mBAAmB;YAkFnB,wBAAwB;CA4CvC"}
|
package/dist/commands.js
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import { notify } from "./notify.js";
|
|
2
|
+
import { cleanupStaleSessionsManual } from "./cleanup.js";
|
|
3
|
+
export class CommandHandler {
|
|
4
|
+
mqtt;
|
|
5
|
+
discovery;
|
|
6
|
+
state;
|
|
7
|
+
client;
|
|
8
|
+
haConfig;
|
|
9
|
+
constructor(mqtt, discovery, state, client, haConfig) {
|
|
10
|
+
this.mqtt = mqtt;
|
|
11
|
+
this.discovery = discovery;
|
|
12
|
+
this.state = state;
|
|
13
|
+
this.client = client;
|
|
14
|
+
this.haConfig = haConfig;
|
|
15
|
+
}
|
|
16
|
+
async start() {
|
|
17
|
+
const commandTopic = this.discovery.getCommandTopic();
|
|
18
|
+
await this.mqtt.subscribe(commandTopic, this.handleMessage.bind(this));
|
|
19
|
+
}
|
|
20
|
+
handleMessage(_topic, payload) {
|
|
21
|
+
let command;
|
|
22
|
+
try {
|
|
23
|
+
command = JSON.parse(payload);
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
console.error("[ha-opencode] Invalid command JSON:", payload);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (!command.command) {
|
|
30
|
+
console.error("[ha-opencode] Command missing 'command' field:", payload);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
// Trigger Kitty terminal alert for incoming command (skip noisy history requests)
|
|
34
|
+
if (!["get_history", "get_history_since", "get_agents"].includes(command.command)) {
|
|
35
|
+
notify("HA Command Received", `Command: ${command.command}`);
|
|
36
|
+
}
|
|
37
|
+
// Handle command asynchronously
|
|
38
|
+
this.processCommand(command).catch((err) => {
|
|
39
|
+
console.error("[ha-opencode] Error processing command:", err);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
async processCommand(command) {
|
|
43
|
+
switch (command.command) {
|
|
44
|
+
case "permission_response":
|
|
45
|
+
await this.handlePermissionResponse(command);
|
|
46
|
+
break;
|
|
47
|
+
case "prompt":
|
|
48
|
+
await this.handlePrompt(command);
|
|
49
|
+
break;
|
|
50
|
+
case "get_history":
|
|
51
|
+
await this.handleGetHistory(command);
|
|
52
|
+
break;
|
|
53
|
+
case "get_history_since":
|
|
54
|
+
await this.handleGetHistorySince(command);
|
|
55
|
+
break;
|
|
56
|
+
case "cleanup_stale_sessions":
|
|
57
|
+
await this.handleCleanup(command);
|
|
58
|
+
break;
|
|
59
|
+
case "get_agents":
|
|
60
|
+
await this.handleGetAgents(command);
|
|
61
|
+
break;
|
|
62
|
+
default:
|
|
63
|
+
notify("Unknown Command", `Unrecognized: ${command.command}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async handleCleanup(command) {
|
|
67
|
+
const maxAgeDays = command.max_age_days ?? 7;
|
|
68
|
+
notify("Cleanup Started", `Removing sessions older than ${maxAgeDays} days`);
|
|
69
|
+
try {
|
|
70
|
+
await cleanupStaleSessionsManual(this.mqtt, {
|
|
71
|
+
maxAgeDays,
|
|
72
|
+
haConfig: this.haConfig,
|
|
73
|
+
});
|
|
74
|
+
notify("Cleanup Complete", "Check opencode/cleanup/response for results");
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
const errorMsg = err instanceof Error ? err.message : "Unknown error";
|
|
78
|
+
notify("Cleanup Failed", errorMsg);
|
|
79
|
+
console.error("[ha-opencode] Failed to run cleanup:", err);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async handlePrompt(command) {
|
|
83
|
+
if (!command.text || command.text.trim() === "") {
|
|
84
|
+
notify("Prompt Error", "Empty prompt text");
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// Get session ID - use provided one or fall back to current session
|
|
88
|
+
const sessionId = command.session_id || this.state.getCurrentSessionId();
|
|
89
|
+
if (!sessionId) {
|
|
90
|
+
notify("Prompt Error", "No active session");
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const agentInfo = command.agent ? ` [${command.agent}]` : "";
|
|
94
|
+
notify("Prompt Received", command.text.substring(0, 50) + (command.text.length > 50 ? "..." : "") + agentInfo);
|
|
95
|
+
try {
|
|
96
|
+
await this.client.session.prompt({
|
|
97
|
+
path: { id: sessionId },
|
|
98
|
+
body: {
|
|
99
|
+
agent: command.agent,
|
|
100
|
+
parts: [{ type: "text", text: command.text }],
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
const errorMsg = err instanceof Error ? err.message : "Unknown error";
|
|
106
|
+
notify("Prompt Failed", errorMsg);
|
|
107
|
+
console.error("[ha-opencode] Failed to send prompt:", err);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
async handleGetAgents(command) {
|
|
111
|
+
try {
|
|
112
|
+
const result = await this.client.app.agents();
|
|
113
|
+
if (!result.data) {
|
|
114
|
+
notify("Agents Error", "No agents data returned");
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const agents = result.data.map(agent => ({
|
|
118
|
+
name: agent.name,
|
|
119
|
+
description: agent.description,
|
|
120
|
+
mode: agent.mode,
|
|
121
|
+
}));
|
|
122
|
+
const response = {
|
|
123
|
+
type: "agents",
|
|
124
|
+
request_id: command.request_id,
|
|
125
|
+
agents,
|
|
126
|
+
};
|
|
127
|
+
await this.mqtt.publish(this.discovery.getResponseTopic(), response, false);
|
|
128
|
+
// Skip notification - agents requests are frequent and noisy
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
// Only log, don't notify - agents requests are frequent
|
|
132
|
+
console.error("[ha-opencode] Failed to fetch agents:", err);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async handleGetHistory(command) {
|
|
136
|
+
const sessionId = command.session_id || this.state.getCurrentSessionId();
|
|
137
|
+
if (!sessionId) {
|
|
138
|
+
// Skip notification - history requests are frequent and noisy
|
|
139
|
+
console.warn("[ha-opencode] History request with no active session");
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
const history = await this.fetchSessionHistory(sessionId);
|
|
144
|
+
const response = {
|
|
145
|
+
type: "history",
|
|
146
|
+
request_id: command.request_id,
|
|
147
|
+
session_id: sessionId,
|
|
148
|
+
session_title: history.title,
|
|
149
|
+
messages: history.messages,
|
|
150
|
+
fetched_at: new Date().toISOString(),
|
|
151
|
+
};
|
|
152
|
+
await this.mqtt.publish(this.discovery.getResponseTopic(), response, false);
|
|
153
|
+
// Skip notification - history requests are frequent and noisy
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
// Only log, don't notify - history requests are frequent
|
|
157
|
+
console.error("[ha-opencode] Failed to fetch history:", err);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async handleGetHistorySince(command) {
|
|
161
|
+
const sessionId = command.session_id || this.state.getCurrentSessionId();
|
|
162
|
+
if (!sessionId) {
|
|
163
|
+
// Skip notification - history requests are frequent and noisy
|
|
164
|
+
console.warn("[ha-opencode] History since request with no active session");
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (!command.since) {
|
|
168
|
+
console.warn("[ha-opencode] History since request missing 'since' timestamp");
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const sinceDate = new Date(command.since);
|
|
172
|
+
if (isNaN(sinceDate.getTime())) {
|
|
173
|
+
console.warn("[ha-opencode] History since request with invalid 'since' timestamp:", command.since);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
const history = await this.fetchSessionHistory(sessionId, sinceDate);
|
|
178
|
+
const response = {
|
|
179
|
+
type: "history",
|
|
180
|
+
request_id: command.request_id,
|
|
181
|
+
session_id: sessionId,
|
|
182
|
+
session_title: history.title,
|
|
183
|
+
messages: history.messages,
|
|
184
|
+
fetched_at: new Date().toISOString(),
|
|
185
|
+
since: command.since,
|
|
186
|
+
};
|
|
187
|
+
await this.mqtt.publish(this.discovery.getResponseTopic(), response, false);
|
|
188
|
+
// Skip notification - history requests are frequent and noisy
|
|
189
|
+
}
|
|
190
|
+
catch (err) {
|
|
191
|
+
// Only log, don't notify - history requests are frequent
|
|
192
|
+
console.error("[ha-opencode] Failed to fetch history:", err);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async fetchSessionHistory(sessionId, since) {
|
|
196
|
+
// Get session info
|
|
197
|
+
const sessionResult = await this.client.session.get({
|
|
198
|
+
path: { id: sessionId },
|
|
199
|
+
});
|
|
200
|
+
const sessionTitle = sessionResult.data?.title || "Untitled";
|
|
201
|
+
// Get all messages
|
|
202
|
+
const messagesResult = await this.client.session.messages({
|
|
203
|
+
path: { id: sessionId },
|
|
204
|
+
});
|
|
205
|
+
const messages = [];
|
|
206
|
+
for (const msg of messagesResult.data || []) {
|
|
207
|
+
const info = msg.info;
|
|
208
|
+
const parts = msg.parts || [];
|
|
209
|
+
// Get timestamp from the message - time.created is a Unix timestamp in milliseconds
|
|
210
|
+
const createdMs = info.time?.created;
|
|
211
|
+
const timestamp = createdMs ? new Date(createdMs).toISOString() : new Date().toISOString();
|
|
212
|
+
const msgDate = new Date(timestamp);
|
|
213
|
+
// Filter by since date if provided
|
|
214
|
+
if (since && msgDate <= since) {
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
// Convert parts to our structured format
|
|
218
|
+
const historyParts = [];
|
|
219
|
+
for (const part of parts) {
|
|
220
|
+
if (part.type === "text") {
|
|
221
|
+
historyParts.push({
|
|
222
|
+
type: "text",
|
|
223
|
+
content: part.text || "",
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
else if (part.type === "tool") {
|
|
227
|
+
// Tool call from assistant - safely access state properties
|
|
228
|
+
const toolState = part.state;
|
|
229
|
+
historyParts.push({
|
|
230
|
+
type: "tool_call",
|
|
231
|
+
tool_name: part.tool || "unknown",
|
|
232
|
+
tool_id: part.id,
|
|
233
|
+
tool_args: part.args,
|
|
234
|
+
tool_output: toolState?.output,
|
|
235
|
+
tool_error: toolState?.error,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
else if (part.type === "file") {
|
|
239
|
+
historyParts.push({
|
|
240
|
+
type: "image",
|
|
241
|
+
content: part.filename || part.url || "",
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
historyParts.push({
|
|
246
|
+
type: "other",
|
|
247
|
+
content: JSON.stringify(part),
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
const historyMsg = {
|
|
252
|
+
id: info.id,
|
|
253
|
+
role: info.role,
|
|
254
|
+
timestamp,
|
|
255
|
+
parts: historyParts,
|
|
256
|
+
};
|
|
257
|
+
// Add assistant-specific metadata
|
|
258
|
+
if (info.role === "assistant") {
|
|
259
|
+
historyMsg.model = info.modelID;
|
|
260
|
+
historyMsg.provider = info.providerID;
|
|
261
|
+
historyMsg.tokens_input = info.tokens?.input ? Number(info.tokens.input) : undefined;
|
|
262
|
+
historyMsg.tokens_output = info.tokens?.output ? Number(info.tokens.output) : undefined;
|
|
263
|
+
historyMsg.cost = info.cost ? Number(info.cost) : undefined;
|
|
264
|
+
}
|
|
265
|
+
messages.push(historyMsg);
|
|
266
|
+
}
|
|
267
|
+
return { title: sessionTitle, messages };
|
|
268
|
+
}
|
|
269
|
+
async handlePermissionResponse(command) {
|
|
270
|
+
const pendingPermission = this.state.getPendingPermission();
|
|
271
|
+
if (!pendingPermission) {
|
|
272
|
+
notify("Permission Error", "No pending permission");
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
// Validate permission ID matches
|
|
276
|
+
if (command.permission_id && command.permission_id !== pendingPermission.id) {
|
|
277
|
+
notify("Permission Error", "Permission ID mismatch");
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
// Validate response value
|
|
281
|
+
const validResponses = ["once", "always", "reject"];
|
|
282
|
+
if (!validResponses.includes(command.response)) {
|
|
283
|
+
notify("Permission Error", `Invalid response: ${command.response}`);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
try {
|
|
287
|
+
await this.client.postSessionIdPermissionsPermissionId({
|
|
288
|
+
path: {
|
|
289
|
+
id: pendingPermission.sessionID,
|
|
290
|
+
permissionID: pendingPermission.id,
|
|
291
|
+
},
|
|
292
|
+
body: {
|
|
293
|
+
response: command.response,
|
|
294
|
+
},
|
|
295
|
+
});
|
|
296
|
+
// Notify user of successful permission response
|
|
297
|
+
const responseLabel = command.response === "once" ? "Approved (once)"
|
|
298
|
+
: command.response === "always" ? "Approved (always)"
|
|
299
|
+
: "Rejected";
|
|
300
|
+
notify("Permission Response", responseLabel);
|
|
301
|
+
await this.state.clearPermission();
|
|
302
|
+
}
|
|
303
|
+
catch (err) {
|
|
304
|
+
notify("Permission Error", "Failed to send response");
|
|
305
|
+
console.error("[ha-opencode] Failed to send permission response:", err);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
//# sourceMappingURL=commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface MqttConfig {
|
|
2
|
+
host: string;
|
|
3
|
+
port: number;
|
|
4
|
+
username?: string;
|
|
5
|
+
password?: string;
|
|
6
|
+
clientId: string;
|
|
7
|
+
}
|
|
8
|
+
export interface HaConfig {
|
|
9
|
+
discoveryPrefix: string;
|
|
10
|
+
}
|
|
11
|
+
export interface PluginConfig {
|
|
12
|
+
mqtt: MqttConfig;
|
|
13
|
+
ha: HaConfig;
|
|
14
|
+
}
|
|
15
|
+
export interface JsonConfig {
|
|
16
|
+
mqtt?: {
|
|
17
|
+
host?: string;
|
|
18
|
+
port?: number;
|
|
19
|
+
username?: string;
|
|
20
|
+
password?: string;
|
|
21
|
+
clientId?: string;
|
|
22
|
+
};
|
|
23
|
+
ha?: {
|
|
24
|
+
discoveryPrefix?: string;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export declare function loadConfig(jsonConfig?: JsonConfig): PluginConfig;
|
|
28
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACvB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,CAAC;IACjB,EAAE,EAAE,QAAQ,CAAC;CACd;AAGD,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE;QACL,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,EAAE,CAAC,EAAE;QACH,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH;AAED,wBAAgB,UAAU,CAAC,UAAU,CAAC,EAAE,UAAU,GAAG,YAAY,CAiBhE"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function loadConfig(jsonConfig) {
|
|
2
|
+
const hostname = process.env.HOSTNAME || "unknown";
|
|
3
|
+
const timestamp = Date.now().toString(36);
|
|
4
|
+
// Env vars take precedence over JSON config
|
|
5
|
+
return {
|
|
6
|
+
mqtt: {
|
|
7
|
+
host: process.env.MQTT_HOST || jsonConfig?.mqtt?.host || "localhost",
|
|
8
|
+
port: parseInt(process.env.MQTT_PORT || String(jsonConfig?.mqtt?.port || 1883), 10),
|
|
9
|
+
username: process.env.MQTT_USERNAME || jsonConfig?.mqtt?.username,
|
|
10
|
+
password: process.env.MQTT_PASSWORD || jsonConfig?.mqtt?.password,
|
|
11
|
+
clientId: process.env.MQTT_CLIENT_ID || jsonConfig?.mqtt?.clientId || `opencode-${hostname}-${timestamp}`,
|
|
12
|
+
},
|
|
13
|
+
ha: {
|
|
14
|
+
discoveryPrefix: process.env.HA_DISCOVERY_PREFIX || jsonConfig?.ha?.discoveryPrefix || "homeassistant",
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AA+BA,MAAM,UAAU,UAAU,CAAC,UAAuB;IAChD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,SAAS,CAAC;IACnD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAE1C,4CAA4C;IAC5C,OAAO;QACL,IAAI,EAAE;YACJ,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,UAAU,EAAE,IAAI,EAAE,IAAI,IAAI,WAAW;YACpE,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;YACnF,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,UAAU,EAAE,IAAI,EAAE,QAAQ;YACjE,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,UAAU,EAAE,IAAI,EAAE,QAAQ;YACjE,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,UAAU,EAAE,IAAI,EAAE,QAAQ,IAAI,YAAY,QAAQ,IAAI,SAAS,EAAE;SAC1G;QACD,EAAE,EAAE;YACF,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,UAAU,EAAE,EAAE,EAAE,eAAe,IAAI,eAAe;SACvG;KACF,CAAC;AACJ,CAAC"}
|