ha-opencode 0.1.1 → 0.2.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/README.md +119 -236
- package/dist/commands.d.ts +13 -11
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +87 -135
- package/dist/commands.js.map +1 -1
- package/dist/ha-config.d.ts +42 -0
- package/dist/ha-config.d.ts.map +1 -0
- package/dist/ha-config.js +104 -0
- package/dist/ha-config.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +255 -83
- package/dist/index.js.map +1 -1
- package/dist/state.d.ts +20 -18
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +99 -108
- package/dist/state.js.map +1 -1
- package/dist/websocket.d.ts +113 -0
- package/dist/websocket.d.ts.map +1 -0
- package/dist/websocket.js +394 -0
- package/dist/websocket.js.map +1 -0
- package/package.json +6 -5
- package/blueprints/opencode_permission_response.yaml +0 -81
- package/blueprints/opencode_state_notifications.yaml +0 -191
- package/dist/cleanup.d.ts +0 -30
- package/dist/cleanup.d.ts.map +0 -1
- package/dist/cleanup.js +0 -125
- package/dist/cleanup.js.map +0 -1
- package/dist/config.d.ts +0 -28
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -18
- package/dist/config.js.map +0 -1
- package/dist/discovery.d.ts +0 -129
- package/dist/discovery.d.ts.map +0 -1
- package/dist/discovery.js +0 -257
- package/dist/discovery.js.map +0 -1
- package/dist/mqtt.d.ts +0 -16
- package/dist/mqtt.d.ts.map +0 -1
- package/dist/mqtt.js +0 -141
- package/dist/mqtt.js.map +0 -1
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
blueprint:
|
|
2
|
-
name: OpenCode State Notifications
|
|
3
|
-
description: >
|
|
4
|
-
Send notifications to your mobile device when OpenCode sessions need attention.
|
|
5
|
-
Notifies when:
|
|
6
|
-
- A task completes (idle after working)
|
|
7
|
-
- Permission is required (with approve/reject buttons)
|
|
8
|
-
- An error occurs
|
|
9
|
-
|
|
10
|
-
Works with both iOS and Android via the Home Assistant Companion app.
|
|
11
|
-
|
|
12
|
-
Requires the Permission Response Handler blueprint to handle approve/reject actions.
|
|
13
|
-
domain: automation
|
|
14
|
-
author: ha-opencode
|
|
15
|
-
source_url: https://github.com/your-repo/ha-opencode/blob/main/blueprints/opencode_state_notifications.yaml
|
|
16
|
-
input:
|
|
17
|
-
notify_service:
|
|
18
|
-
name: Notification Service
|
|
19
|
-
description: >
|
|
20
|
-
The notification service to use (e.g., notify.mobile_app_your_phone).
|
|
21
|
-
selector:
|
|
22
|
-
text:
|
|
23
|
-
default: "notify.mobile_app_phone"
|
|
24
|
-
|
|
25
|
-
notify_on_complete:
|
|
26
|
-
name: Notify on Task Complete
|
|
27
|
-
description: Send a notification when a task completes (idle after working).
|
|
28
|
-
default: true
|
|
29
|
-
selector:
|
|
30
|
-
boolean:
|
|
31
|
-
|
|
32
|
-
notify_on_permission:
|
|
33
|
-
name: Notify on Permission Required
|
|
34
|
-
description: Send a notification with approve/reject buttons when permission is needed.
|
|
35
|
-
default: true
|
|
36
|
-
selector:
|
|
37
|
-
boolean:
|
|
38
|
-
|
|
39
|
-
notify_on_error:
|
|
40
|
-
name: Notify on Error
|
|
41
|
-
description: Send a notification when an error occurs.
|
|
42
|
-
default: true
|
|
43
|
-
selector:
|
|
44
|
-
boolean:
|
|
45
|
-
|
|
46
|
-
notification_channel:
|
|
47
|
-
name: Notification Channel (Android)
|
|
48
|
-
description: >
|
|
49
|
-
Android notification channel name.
|
|
50
|
-
You can create channels in the Companion app settings.
|
|
51
|
-
default: "OpenCode"
|
|
52
|
-
selector:
|
|
53
|
-
text:
|
|
54
|
-
|
|
55
|
-
dashboard_path:
|
|
56
|
-
name: Dashboard Path
|
|
57
|
-
description: >
|
|
58
|
-
Path to your OpenCode dashboard for click action (e.g., /lovelace/opencode).
|
|
59
|
-
Leave empty to use default behavior.
|
|
60
|
-
default: "/lovelace/opencode"
|
|
61
|
-
selector:
|
|
62
|
-
text:
|
|
63
|
-
|
|
64
|
-
mode: parallel
|
|
65
|
-
max_exceeded: silent
|
|
66
|
-
|
|
67
|
-
trigger:
|
|
68
|
-
- platform: mqtt
|
|
69
|
-
topic: "opencode/+/state"
|
|
70
|
-
id: state_change
|
|
71
|
-
|
|
72
|
-
variables:
|
|
73
|
-
# The new state from the MQTT payload
|
|
74
|
-
new_state: "{{ trigger.payload }}"
|
|
75
|
-
|
|
76
|
-
# Extract device_id from topic: opencode/{device_id}/state
|
|
77
|
-
device_id: "{{ trigger.topic.split('/')[1] }}"
|
|
78
|
-
|
|
79
|
-
# Build the state_topic_base for entity lookup
|
|
80
|
-
state_topic_base: "opencode/{{ device_id }}"
|
|
81
|
-
|
|
82
|
-
# Find the device_id entity that has this state_topic_base in its attributes
|
|
83
|
-
device_id_entity: >
|
|
84
|
-
{% set ns = namespace(found='') %}
|
|
85
|
-
{% for entity in states.sensor %}
|
|
86
|
-
{% if entity.attributes.get('state_topic_base', '') == state_topic_base %}
|
|
87
|
-
{% set ns.found = entity.entity_id %}
|
|
88
|
-
{% endif %}
|
|
89
|
-
{% endfor %}
|
|
90
|
-
{{ ns.found }}
|
|
91
|
-
|
|
92
|
-
# Check if we found the entity
|
|
93
|
-
entity_found: "{{ device_id_entity != '' }}"
|
|
94
|
-
|
|
95
|
-
# Derive other entity IDs from the device_id entity (they share the same base)
|
|
96
|
-
entity_base: "{{ device_id_entity | replace('_device_id', '') if entity_found else '' }}"
|
|
97
|
-
state_entity: "{{ (entity_base ~ '_state') if entity_found else '' }}"
|
|
98
|
-
session_entity: "{{ (entity_base ~ '_session_title') if entity_found else '' }}"
|
|
99
|
-
|
|
100
|
-
# Get values from entities (with defaults)
|
|
101
|
-
previous_state: "{{ state_attr(state_entity, 'previous_state') | default('unknown') if entity_found else 'unknown' }}"
|
|
102
|
-
project_name: "{{ state_attr(device_id_entity, 'device_name') | default('OpenCode') if entity_found else 'OpenCode' }}"
|
|
103
|
-
command_topic: "{{ state_attr(device_id_entity, 'command_topic') | default('') if entity_found else '' }}"
|
|
104
|
-
permission_id: "{{ state_attr(state_entity, 'permission_id') | default('') if entity_found else '' }}"
|
|
105
|
-
permission_title: "{{ state_attr(state_entity, 'permission_title') | default('Permission needed') if entity_found else 'Permission needed' }}"
|
|
106
|
-
error_message: "{{ state_attr(state_entity, 'error_message') | default('An error occurred') if entity_found else 'An error occurred' }}"
|
|
107
|
-
session_title: "{{ states(session_entity) | default('Task finished') if entity_found else 'Task finished' }}"
|
|
108
|
-
|
|
109
|
-
# Determine if this is a transition we care about
|
|
110
|
-
was_working: "{{ previous_state == 'working' }}"
|
|
111
|
-
|
|
112
|
-
action:
|
|
113
|
-
# Log for debugging (can be removed later)
|
|
114
|
-
- service: system_log.write
|
|
115
|
-
data:
|
|
116
|
-
message: >
|
|
117
|
-
OpenCode notification trigger: new_state={{ new_state }}, previous_state={{ previous_state }},
|
|
118
|
-
device_id={{ device_id }}, entity_found={{ entity_found }}, was_working={{ was_working }}
|
|
119
|
-
level: info
|
|
120
|
-
logger: ha-opencode.blueprint
|
|
121
|
-
|
|
122
|
-
- choose:
|
|
123
|
-
# Permission Required (always notify, regardless of previous state)
|
|
124
|
-
- conditions:
|
|
125
|
-
- condition: template
|
|
126
|
-
value_template: "{{ new_state == 'waiting_permission' }}"
|
|
127
|
-
- condition: template
|
|
128
|
-
value_template: !input notify_on_permission
|
|
129
|
-
sequence:
|
|
130
|
-
# Small delay to let permission attributes arrive
|
|
131
|
-
- delay:
|
|
132
|
-
milliseconds: 500
|
|
133
|
-
- service: !input notify_service
|
|
134
|
-
data:
|
|
135
|
-
title: "OpenCode: Permission Required"
|
|
136
|
-
message: "{{ project_name }}: {{ permission_title }}"
|
|
137
|
-
data:
|
|
138
|
-
tag: "opencode-permission-{{ device_id }}"
|
|
139
|
-
channel: !input notification_channel
|
|
140
|
-
importance: high
|
|
141
|
-
priority: high
|
|
142
|
-
ttl: 0
|
|
143
|
-
clickAction: !input dashboard_path
|
|
144
|
-
url: !input dashboard_path
|
|
145
|
-
actions:
|
|
146
|
-
- action: "OPENCODE_APPROVE_{{ device_id }}"
|
|
147
|
-
title: "Approve"
|
|
148
|
-
- action: "OPENCODE_REJECT_{{ device_id }}"
|
|
149
|
-
title: "Reject"
|
|
150
|
-
# Pass data needed for permission response
|
|
151
|
-
action_data:
|
|
152
|
-
device_id: "{{ device_id }}"
|
|
153
|
-
permission_id: "{{ permission_id }}"
|
|
154
|
-
command_topic: "{{ command_topic }}"
|
|
155
|
-
|
|
156
|
-
# Error Occurred (only after working)
|
|
157
|
-
- conditions:
|
|
158
|
-
- condition: template
|
|
159
|
-
value_template: "{{ new_state == 'error' and was_working }}"
|
|
160
|
-
- condition: template
|
|
161
|
-
value_template: !input notify_on_error
|
|
162
|
-
sequence:
|
|
163
|
-
- service: !input notify_service
|
|
164
|
-
data:
|
|
165
|
-
title: "OpenCode: Error"
|
|
166
|
-
message: "{{ project_name }}: {{ error_message }}"
|
|
167
|
-
data:
|
|
168
|
-
tag: "opencode-error-{{ device_id }}"
|
|
169
|
-
channel: !input notification_channel
|
|
170
|
-
importance: high
|
|
171
|
-
priority: high
|
|
172
|
-
ttl: 0
|
|
173
|
-
clickAction: !input dashboard_path
|
|
174
|
-
url: !input dashboard_path
|
|
175
|
-
|
|
176
|
-
# Work Complete (idle after working)
|
|
177
|
-
- conditions:
|
|
178
|
-
- condition: template
|
|
179
|
-
value_template: "{{ new_state == 'idle' and was_working }}"
|
|
180
|
-
- condition: template
|
|
181
|
-
value_template: !input notify_on_complete
|
|
182
|
-
sequence:
|
|
183
|
-
- service: !input notify_service
|
|
184
|
-
data:
|
|
185
|
-
title: "OpenCode: Task Complete"
|
|
186
|
-
message: "{{ project_name }}: {{ session_title }}"
|
|
187
|
-
data:
|
|
188
|
-
tag: "opencode-complete-{{ device_id }}"
|
|
189
|
-
channel: !input notification_channel
|
|
190
|
-
clickAction: !input dashboard_path
|
|
191
|
-
url: !input dashboard_path
|
package/dist/cleanup.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { MqttWrapper } from "./mqtt.js";
|
|
2
|
-
import type { HaConfig } from "./config.js";
|
|
3
|
-
export interface CleanupConfig {
|
|
4
|
-
maxAgeDays: number;
|
|
5
|
-
haConfig: HaConfig;
|
|
6
|
-
}
|
|
7
|
-
export interface CleanupResult {
|
|
8
|
-
sessionsRemoved: number;
|
|
9
|
-
sessionIds: string[];
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Clean up stale OpenCode sessions from Home Assistant.
|
|
13
|
-
* Removes entities for sessions that haven't been active in `maxAgeDays` days.
|
|
14
|
-
*
|
|
15
|
-
* @param mqtt - MQTT client wrapper
|
|
16
|
-
* @param config - Cleanup configuration
|
|
17
|
-
* @returns Result with count and IDs of removed sessions
|
|
18
|
-
*/
|
|
19
|
-
export declare function cleanupStaleSessions(mqtt: MqttWrapper, config: CleanupConfig): Promise<CleanupResult>;
|
|
20
|
-
/**
|
|
21
|
-
* Manually trigger cleanup and publish results to MQTT.
|
|
22
|
-
* Called via the cleanup_stale_sessions command.
|
|
23
|
-
*/
|
|
24
|
-
export declare function cleanupStaleSessionsManual(mqtt: MqttWrapper, config: CleanupConfig): Promise<void>;
|
|
25
|
-
/**
|
|
26
|
-
* Run cleanup in the background (non-blocking).
|
|
27
|
-
* Logs results but doesn't throw on error.
|
|
28
|
-
*/
|
|
29
|
-
export declare function runCleanupInBackground(mqtt: MqttWrapper, config: CleanupConfig): void;
|
|
30
|
-
//# sourceMappingURL=cleanup.d.ts.map
|
package/dist/cleanup.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cleanup.d.ts","sourceRoot":"","sources":["../src/cleanup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG5C,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AA+ED;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,aAAa,CAAC,CA8BxB;AAED;;;GAGG;AACH,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,IAAI,CAAC,CAef;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,aAAa,GACpB,IAAI,CAYN"}
|
package/dist/cleanup.js
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
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
|
package/dist/cleanup.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cleanup.js","sourceRoot":"","sources":["../src/cleanup.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
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
|
package/dist/config.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
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.OPENCODE_MQTT_HOST || jsonConfig?.mqtt?.host || "localhost",
|
|
8
|
-
port: parseInt(process.env.OPENCODE_MQTT_PORT || String(jsonConfig?.mqtt?.port || 1883), 10),
|
|
9
|
-
username: process.env.OPENCODE_MQTT_USERNAME || jsonConfig?.mqtt?.username,
|
|
10
|
-
password: process.env.OPENCODE_MQTT_PASSWORD || jsonConfig?.mqtt?.password,
|
|
11
|
-
clientId: process.env.OPENCODE_MQTT_CLIENT_ID || jsonConfig?.mqtt?.clientId || `opencode-${hostname}-${timestamp}`,
|
|
12
|
-
},
|
|
13
|
-
ha: {
|
|
14
|
-
discoveryPrefix: process.env.OPENCODE_HA_DISCOVERY_PREFIX || jsonConfig?.ha?.discoveryPrefix || "homeassistant",
|
|
15
|
-
},
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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,kBAAkB,IAAI,UAAU,EAAE,IAAI,EAAE,IAAI,IAAI,WAAW;YAC7E,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;YAC5F,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,UAAU,EAAE,IAAI,EAAE,QAAQ;YAC1E,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,UAAU,EAAE,IAAI,EAAE,QAAQ;YAC1E,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,UAAU,EAAE,IAAI,EAAE,QAAQ,IAAI,YAAY,QAAQ,IAAI,SAAS,EAAE;SACnH;QACD,EAAE,EAAE;YACF,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,4BAA4B,IAAI,UAAU,EAAE,EAAE,EAAE,eAAe,IAAI,eAAe;SAChH;KACF,CAAC;AACJ,CAAC"}
|
package/dist/discovery.d.ts
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import type { MqttWrapper, MqttWillConfig } from "./mqtt.js";
|
|
2
|
-
import type { HaConfig } from "./config.js";
|
|
3
|
-
/**
|
|
4
|
-
* Extract the unique portion of a session ID by stripping the "ses_" prefix.
|
|
5
|
-
*/
|
|
6
|
-
export declare function extractSessionIdPart(sessionId: string): string;
|
|
7
|
-
/**
|
|
8
|
-
* Generate device ID from session ID.
|
|
9
|
-
*/
|
|
10
|
-
export declare function getDeviceIdForSession(sessionId: string): string;
|
|
11
|
-
/**
|
|
12
|
-
* Generate the availability topic for LWT configuration.
|
|
13
|
-
* This can be called before Discovery is instantiated.
|
|
14
|
-
*/
|
|
15
|
-
export declare function getAvailabilityTopicForSession(sessionId: string): string;
|
|
16
|
-
/**
|
|
17
|
-
* Create MQTT LWT (Last Will and Testament) config for availability tracking.
|
|
18
|
-
*/
|
|
19
|
-
export declare function createWillConfig(sessionId: string): MqttWillConfig;
|
|
20
|
-
export interface DeviceInfo {
|
|
21
|
-
identifiers: string[];
|
|
22
|
-
name: string;
|
|
23
|
-
manufacturer: string;
|
|
24
|
-
model: string;
|
|
25
|
-
sw_version: string;
|
|
26
|
-
}
|
|
27
|
-
declare const ENTITY_DEFINITIONS: readonly [{
|
|
28
|
-
readonly key: "device_id";
|
|
29
|
-
readonly name: "Device ID";
|
|
30
|
-
readonly icon: "mdi:identifier";
|
|
31
|
-
readonly hasAttributes: true;
|
|
32
|
-
}, {
|
|
33
|
-
readonly key: "state";
|
|
34
|
-
readonly name: "State";
|
|
35
|
-
readonly icon: "mdi:state-machine";
|
|
36
|
-
readonly hasAttributes: true;
|
|
37
|
-
}, {
|
|
38
|
-
readonly key: "session_title";
|
|
39
|
-
readonly name: "Session";
|
|
40
|
-
readonly icon: "mdi:message-text";
|
|
41
|
-
}, {
|
|
42
|
-
readonly key: "model";
|
|
43
|
-
readonly name: "Model";
|
|
44
|
-
readonly icon: "mdi:brain";
|
|
45
|
-
}, {
|
|
46
|
-
readonly key: "current_tool";
|
|
47
|
-
readonly name: "Current Tool";
|
|
48
|
-
readonly icon: "mdi:tools";
|
|
49
|
-
}, {
|
|
50
|
-
readonly key: "tokens_input";
|
|
51
|
-
readonly name: "Input Tokens";
|
|
52
|
-
readonly icon: "mdi:arrow-right-bold";
|
|
53
|
-
readonly unit: "tokens";
|
|
54
|
-
readonly state_class: "measurement";
|
|
55
|
-
}, {
|
|
56
|
-
readonly key: "tokens_output";
|
|
57
|
-
readonly name: "Output Tokens";
|
|
58
|
-
readonly icon: "mdi:arrow-left-bold";
|
|
59
|
-
readonly unit: "tokens";
|
|
60
|
-
readonly state_class: "measurement";
|
|
61
|
-
}, {
|
|
62
|
-
readonly key: "cost";
|
|
63
|
-
readonly name: "Cost";
|
|
64
|
-
readonly icon: "mdi:currency-usd";
|
|
65
|
-
readonly unit: "USD";
|
|
66
|
-
readonly state_class: "total_increasing";
|
|
67
|
-
}, {
|
|
68
|
-
readonly key: "last_activity";
|
|
69
|
-
readonly name: "Last Activity";
|
|
70
|
-
readonly icon: "mdi:clock-outline";
|
|
71
|
-
readonly device_class: "timestamp";
|
|
72
|
-
}, {
|
|
73
|
-
readonly key: "permission";
|
|
74
|
-
readonly name: "Permission Request";
|
|
75
|
-
readonly icon: "mdi:shield-alert";
|
|
76
|
-
readonly hasAttributes: true;
|
|
77
|
-
}];
|
|
78
|
-
export type EntityKey = (typeof ENTITY_DEFINITIONS)[number]["key"];
|
|
79
|
-
export interface PermissionInfo {
|
|
80
|
-
id: string;
|
|
81
|
-
type: string;
|
|
82
|
-
title: string;
|
|
83
|
-
sessionID: string;
|
|
84
|
-
messageID: string;
|
|
85
|
-
callID?: string;
|
|
86
|
-
pattern?: string | string[];
|
|
87
|
-
metadata: Record<string, unknown>;
|
|
88
|
-
}
|
|
89
|
-
export declare class Discovery {
|
|
90
|
-
private readonly mqtt;
|
|
91
|
-
private readonly haConfig;
|
|
92
|
-
readonly deviceId: string;
|
|
93
|
-
private device;
|
|
94
|
-
private readonly stateTopicBase;
|
|
95
|
-
private readonly sessionId;
|
|
96
|
-
private readonly projectName;
|
|
97
|
-
constructor(mqtt: MqttWrapper, haConfig: HaConfig, sessionId: string, projectName: string);
|
|
98
|
-
/**
|
|
99
|
-
* Update the device friendly name when session title becomes available.
|
|
100
|
-
* This re-publishes all entity configs with the updated device name.
|
|
101
|
-
*/
|
|
102
|
-
updateDeviceName(title: string): Promise<void>;
|
|
103
|
-
registerDevice(): Promise<void>;
|
|
104
|
-
private registerEntity;
|
|
105
|
-
getStateTopic(key: EntityKey): string;
|
|
106
|
-
getAttributesTopic(key: EntityKey): string;
|
|
107
|
-
getCommandTopic(): string;
|
|
108
|
-
getResponseTopic(): string;
|
|
109
|
-
getAvailabilityTopic(): string;
|
|
110
|
-
/**
|
|
111
|
-
* Publish online status. Call this after device registration.
|
|
112
|
-
*/
|
|
113
|
-
publishAvailable(): Promise<void>;
|
|
114
|
-
/**
|
|
115
|
-
* Publish offline status. Call this before graceful shutdown.
|
|
116
|
-
*/
|
|
117
|
-
publishUnavailable(): Promise<void>;
|
|
118
|
-
publishState(key: EntityKey, value: string | number): Promise<void>;
|
|
119
|
-
publishAttributes(key: EntityKey, attributes: Record<string, unknown>): Promise<void>;
|
|
120
|
-
publishDeviceInfo(): Promise<void>;
|
|
121
|
-
publishPermission(permission: PermissionInfo | null): Promise<void>;
|
|
122
|
-
unregisterDevice(): Promise<void>;
|
|
123
|
-
/**
|
|
124
|
-
* Get the list of all entity keys for cleanup purposes.
|
|
125
|
-
*/
|
|
126
|
-
static getEntityKeys(): readonly EntityKey[];
|
|
127
|
-
}
|
|
128
|
-
export {};
|
|
129
|
-
//# sourceMappingURL=discovery.d.ts.map
|
package/dist/discovery.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
|