0xkobold 0.2.0 → 0.3.1
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/HEARTBEAT.md +40 -58
- package/README.md +387 -337
- package/dist/package.json +11 -3
- package/dist/src/auth/device-auth.js +202 -0
- package/dist/src/auth/device-auth.js.map +1 -0
- package/dist/src/auth/index.js +3 -0
- package/dist/src/auth/index.js.map +1 -0
- package/dist/src/channels/index.js +8 -0
- package/dist/src/channels/index.js.map +1 -0
- package/dist/src/channels/slack/webhook.js +128 -0
- package/dist/src/channels/slack/webhook.js.map +1 -0
- package/dist/src/channels/telegram/bot.js +223 -0
- package/dist/src/channels/telegram/bot.js.map +1 -0
- package/dist/src/channels/whatsapp/integration.js +325 -0
- package/dist/src/channels/whatsapp/integration.js.map +1 -0
- package/dist/src/cli/commands/check.js +69 -0
- package/dist/src/cli/commands/check.js.map +1 -0
- package/dist/src/cli/commands/init.js +134 -79
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/migrate.js +24 -0
- package/dist/src/cli/commands/migrate.js.map +1 -0
- package/dist/src/cli/commands/tailscale.js +81 -0
- package/dist/src/cli/commands/tailscale.js.map +1 -0
- package/dist/src/cli/commands/telegram.js +111 -0
- package/dist/src/cli/commands/telegram.js.map +1 -0
- package/dist/src/cli/commands/tui.js +40 -22
- package/dist/src/cli/commands/tui.js.map +1 -1
- package/dist/src/cli/commands/whatsapp.js +116 -0
- package/dist/src/cli/commands/whatsapp.js.map +1 -0
- package/dist/src/cli/program.js +22 -0
- package/dist/src/cli/program.js.map +1 -1
- package/dist/src/config/index.js +2 -9
- package/dist/src/config/index.js.map +1 -1
- package/dist/src/config/manager.js +222 -0
- package/dist/src/config/manager.js.map +1 -0
- package/dist/src/documents/index.js +3 -0
- package/dist/src/documents/index.js.map +1 -0
- package/dist/src/documents/pdf.js +168 -0
- package/dist/src/documents/pdf.js.map +1 -0
- package/dist/src/gateway/client.js +318 -0
- package/dist/src/gateway/client.js.map +1 -0
- package/dist/src/infra/index.js +3 -0
- package/dist/src/infra/index.js.map +1 -0
- package/dist/src/infra/tailscale.js +163 -0
- package/dist/src/infra/tailscale.js.map +1 -0
- package/dist/src/media/audio.js +130 -0
- package/dist/src/media/audio.js.map +1 -0
- package/dist/src/media/index.js +4 -0
- package/dist/src/media/index.js.map +1 -0
- package/dist/src/media/vision.js +131 -0
- package/dist/src/media/vision.js.map +1 -0
- package/dist/src/migration/openclaw.js +498 -0
- package/dist/src/migration/openclaw.js.map +1 -0
- package/dist/src/sandbox/docker-runner.js +228 -0
- package/dist/src/sandbox/docker-runner.js.map +1 -0
- package/dist/src/sandbox/index.js +3 -0
- package/dist/src/sandbox/index.js.map +1 -0
- package/dist/src/skills/builtin/duplicate-detector.js +469 -0
- package/dist/src/skills/builtin/duplicate-detector.js.map +1 -0
- package/dist/src/skills/index.js +2 -0
- package/dist/src/skills/index.js.map +1 -1
- package/package.json +11 -3
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gateway Client - Remote/VPS Support
|
|
3
|
+
*
|
|
4
|
+
* Connect to remote or local gateway server for distributed architecture.
|
|
5
|
+
* Based on kod/OpenClaw client architecture - simplified for 0xKobold.
|
|
6
|
+
*/
|
|
7
|
+
import { EventEmitter } from "events";
|
|
8
|
+
import { homedir } from "os";
|
|
9
|
+
import { join } from "path";
|
|
10
|
+
import * as fs from "node:fs/promises";
|
|
11
|
+
export const GATEWAY_STATE = {
|
|
12
|
+
DISCONNECTED: "disconnected",
|
|
13
|
+
CONNECTING: "connecting",
|
|
14
|
+
CONNECTED: "connected",
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* GatewayClient - WebSocket client for connecting to local or remote gateway
|
|
18
|
+
*
|
|
19
|
+
* Architecture:
|
|
20
|
+
* - Local mode: Connects to ws://localhost:7777
|
|
21
|
+
* - Remote mode: Connects to wss://your-vps.com:7777
|
|
22
|
+
* - Handles auth tokens (local storage in ~/.0xkobold/)
|
|
23
|
+
* - Auto-reconnect with exponential backoff
|
|
24
|
+
* - Heartbeat/ping-pong for connection health
|
|
25
|
+
*/
|
|
26
|
+
export class GatewayClient extends EventEmitter {
|
|
27
|
+
ws = null;
|
|
28
|
+
config;
|
|
29
|
+
state = GATEWAY_STATE.DISCONNECTED;
|
|
30
|
+
reconnectTimer;
|
|
31
|
+
pingTimer;
|
|
32
|
+
reconnectCount = 0;
|
|
33
|
+
pendingMessages = [];
|
|
34
|
+
messageId = 0;
|
|
35
|
+
constructor(config) {
|
|
36
|
+
super();
|
|
37
|
+
this.config = {
|
|
38
|
+
url: config.url,
|
|
39
|
+
autoReconnect: config.autoReconnect ?? true,
|
|
40
|
+
reconnectDelay: config.reconnectDelay ?? 1000,
|
|
41
|
+
reconnectAttempts: config.reconnectAttempts ?? 10,
|
|
42
|
+
token: config.token,
|
|
43
|
+
deviceToken: config.deviceToken,
|
|
44
|
+
password: config.password,
|
|
45
|
+
clientName: config.clientName ?? "0xKobold-Client",
|
|
46
|
+
clientVersion: config.clientVersion ?? "0.3.0",
|
|
47
|
+
deviceId: config.deviceId ?? "unknown",
|
|
48
|
+
capabilities: config.capabilities ?? ["chat", "files", "heartbeat"],
|
|
49
|
+
onConnect: config.onConnect,
|
|
50
|
+
onDisconnect: config.onDisconnect,
|
|
51
|
+
onMessage: config.onMessage,
|
|
52
|
+
onError: config.onError,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Connect to gateway
|
|
57
|
+
*/
|
|
58
|
+
async connect() {
|
|
59
|
+
if (this.state === GATEWAY_STATE.CONNECTED) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
this.state = GATEWAY_STATE.CONNECTING;
|
|
63
|
+
this.emit("stateChange", this.state);
|
|
64
|
+
try {
|
|
65
|
+
// Determine protocol (ws:// vs wss://)
|
|
66
|
+
const isSecure = this.config.url.startsWith("wss://");
|
|
67
|
+
const wsUrl = this.config.url;
|
|
68
|
+
console.log(`[GatewayClient] Connecting to ${isSecure ? "secure" : "insecure"} WebSocket...`);
|
|
69
|
+
console.log(`[GatewayClient] URL: ${wsUrl}`);
|
|
70
|
+
// Create WebSocket
|
|
71
|
+
this.ws = new WebSocket(wsUrl);
|
|
72
|
+
// Setup handlers
|
|
73
|
+
this.ws.onopen = () => this.handleOpen();
|
|
74
|
+
this.ws.onclose = (event) => this.handleClose(event.code, event.reason);
|
|
75
|
+
this.ws.onerror = (err) => this.handleError(new Error(String(err)));
|
|
76
|
+
this.ws.onmessage = (msg) => this.handleMessage(msg.data);
|
|
77
|
+
// Wait for connection
|
|
78
|
+
await this.waitForConnection();
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
this.handleError(err);
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Disconnect from gateway
|
|
88
|
+
*/
|
|
89
|
+
disconnect() {
|
|
90
|
+
this.clearTimers();
|
|
91
|
+
if (this.ws) {
|
|
92
|
+
this.ws.close(1000, "Client disconnect");
|
|
93
|
+
this.ws = null;
|
|
94
|
+
}
|
|
95
|
+
this.state = GATEWAY_STATE.DISCONNECTED;
|
|
96
|
+
this.emit("stateChange", this.state);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Send message to gateway
|
|
100
|
+
*/
|
|
101
|
+
send(message) {
|
|
102
|
+
const fullMessage = {
|
|
103
|
+
...message,
|
|
104
|
+
id: this.generateMessageId(),
|
|
105
|
+
timestamp: Date.now(),
|
|
106
|
+
};
|
|
107
|
+
if (this.state === GATEWAY_STATE.CONNECTED && this.ws) {
|
|
108
|
+
this.ws.send(JSON.stringify(fullMessage));
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
// Queue for later
|
|
112
|
+
this.pendingMessages.push(fullMessage);
|
|
113
|
+
}
|
|
114
|
+
return fullMessage.id;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Send chat request
|
|
118
|
+
*/
|
|
119
|
+
chat(message, context) {
|
|
120
|
+
return this.send({
|
|
121
|
+
type: "request",
|
|
122
|
+
channel: "chat",
|
|
123
|
+
payload: {
|
|
124
|
+
message,
|
|
125
|
+
context,
|
|
126
|
+
capabilities: this.config.capabilities,
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Send ping to check connection
|
|
132
|
+
*/
|
|
133
|
+
ping() {
|
|
134
|
+
this.send({
|
|
135
|
+
type: "ping",
|
|
136
|
+
payload: { timestamp: Date.now() },
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Get current state
|
|
141
|
+
*/
|
|
142
|
+
getState() {
|
|
143
|
+
return this.state;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Check if connected
|
|
147
|
+
*/
|
|
148
|
+
isConnected() {
|
|
149
|
+
return this.state === GATEWAY_STATE.CONNECTED;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Load cached device token from disk
|
|
153
|
+
*/
|
|
154
|
+
static async loadDeviceToken() {
|
|
155
|
+
const tokenPath = join(homedir(), ".0xkobold", ".device-token");
|
|
156
|
+
try {
|
|
157
|
+
const token = await fs.readFile(tokenPath, "utf-8");
|
|
158
|
+
return token.trim();
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Save device token to disk
|
|
166
|
+
*/
|
|
167
|
+
static async saveDeviceToken(token) {
|
|
168
|
+
const tokenPath = join(homedir(), ".0xkobold", ".device-token");
|
|
169
|
+
await fs.mkdir(join(homedir(), ".0xkobold"), { recursive: true });
|
|
170
|
+
await fs.writeFile(tokenPath, token, "utf-8");
|
|
171
|
+
await fs.chmod(tokenPath, 0o600); // Secure permissions
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Clear saved device token
|
|
175
|
+
*/
|
|
176
|
+
static async clearDeviceToken() {
|
|
177
|
+
const tokenPath = join(homedir(), ".0xkobold", ".device-token");
|
|
178
|
+
try {
|
|
179
|
+
await fs.unlink(tokenPath);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
// Ignore if doesn't exist
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// Private methods
|
|
186
|
+
handleOpen() {
|
|
187
|
+
console.log("[GatewayClient] Connected successfully");
|
|
188
|
+
this.state = GATEWAY_STATE.CONNECTED;
|
|
189
|
+
this.reconnectCount = 0;
|
|
190
|
+
// Send authentication
|
|
191
|
+
this.sendAuth();
|
|
192
|
+
// Process queued messages
|
|
193
|
+
this.processPendingMessages();
|
|
194
|
+
// Start heartbeat
|
|
195
|
+
this.startHeartbeat();
|
|
196
|
+
this.emit("connected");
|
|
197
|
+
this.config.onConnect?.();
|
|
198
|
+
}
|
|
199
|
+
handleClose(code, reason) {
|
|
200
|
+
console.log(`[GatewayClient] Disconnected: ${code} - ${reason}`);
|
|
201
|
+
this.state = GATEWAY_STATE.DISCONNECTED;
|
|
202
|
+
this.emit("disconnected", code, reason);
|
|
203
|
+
this.config.onDisconnect?.(code, reason);
|
|
204
|
+
this.clearTimers();
|
|
205
|
+
// Attempt reconnect if enabled
|
|
206
|
+
if (this.config.autoReconnect && this.reconnectCount < this.config.reconnectAttempts) {
|
|
207
|
+
this.scheduleReconnect();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
handleError(err) {
|
|
211
|
+
console.error("[GatewayClient] Error:", err.message);
|
|
212
|
+
this.emit("error", err);
|
|
213
|
+
this.config.onError?.(err);
|
|
214
|
+
}
|
|
215
|
+
handleMessage(data) {
|
|
216
|
+
try {
|
|
217
|
+
const message = JSON.parse(data.toString());
|
|
218
|
+
// Handle ping/pong
|
|
219
|
+
if (message.type === "pong") {
|
|
220
|
+
this.emit("pong", message);
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
this.emit("message", message);
|
|
224
|
+
this.config.onMessage?.(message);
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
console.error("[GatewayClient] Failed to parse message:", err);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
sendAuth() {
|
|
231
|
+
const authPayload = {
|
|
232
|
+
client: this.config.clientName,
|
|
233
|
+
version: this.config.clientVersion,
|
|
234
|
+
deviceId: this.config.deviceId,
|
|
235
|
+
capabilities: this.config.capabilities,
|
|
236
|
+
};
|
|
237
|
+
if (this.config.token) {
|
|
238
|
+
authPayload.token = this.config.token;
|
|
239
|
+
}
|
|
240
|
+
if (this.config.deviceToken) {
|
|
241
|
+
authPayload.deviceToken = this.config.deviceToken;
|
|
242
|
+
}
|
|
243
|
+
if (this.config.password) {
|
|
244
|
+
authPayload.password = this.config.password;
|
|
245
|
+
}
|
|
246
|
+
this.send({
|
|
247
|
+
type: "request",
|
|
248
|
+
channel: "auth",
|
|
249
|
+
payload: authPayload,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
waitForConnection() {
|
|
253
|
+
return new Promise((resolve, reject) => {
|
|
254
|
+
const timeout = setTimeout(() => {
|
|
255
|
+
reject(new Error("Connection timeout"));
|
|
256
|
+
}, 10000);
|
|
257
|
+
const onConnect = () => {
|
|
258
|
+
clearTimeout(timeout);
|
|
259
|
+
this.off("error", onError);
|
|
260
|
+
resolve();
|
|
261
|
+
};
|
|
262
|
+
const onError = (err) => {
|
|
263
|
+
clearTimeout(timeout);
|
|
264
|
+
this.off("connected", onConnect);
|
|
265
|
+
reject(err);
|
|
266
|
+
};
|
|
267
|
+
this.once("connected", onConnect);
|
|
268
|
+
this.once("error", onError);
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
scheduleReconnect() {
|
|
272
|
+
this.reconnectCount++;
|
|
273
|
+
const delay = this.config.reconnectDelay * Math.min(this.reconnectCount, 5);
|
|
274
|
+
console.log(`[GatewayClient] Reconnecting in ${delay}ms (attempt ${this.reconnectCount})`);
|
|
275
|
+
this.reconnectTimer = setTimeout(() => {
|
|
276
|
+
this.connect();
|
|
277
|
+
}, delay);
|
|
278
|
+
}
|
|
279
|
+
startHeartbeat() {
|
|
280
|
+
this.pingTimer = setInterval(() => {
|
|
281
|
+
if (this.isConnected()) {
|
|
282
|
+
this.ping();
|
|
283
|
+
}
|
|
284
|
+
}, 30000); // Ping every 30s
|
|
285
|
+
}
|
|
286
|
+
processPendingMessages() {
|
|
287
|
+
while (this.pendingMessages.length > 0) {
|
|
288
|
+
const msg = this.pendingMessages.shift();
|
|
289
|
+
if (msg && this.ws) {
|
|
290
|
+
this.ws.send(JSON.stringify(msg));
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
clearTimers() {
|
|
295
|
+
if (this.reconnectTimer) {
|
|
296
|
+
clearTimeout(this.reconnectTimer);
|
|
297
|
+
this.reconnectTimer = undefined;
|
|
298
|
+
}
|
|
299
|
+
if (this.pingTimer) {
|
|
300
|
+
clearInterval(this.pingTimer);
|
|
301
|
+
this.pingTimer = undefined;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
generateMessageId() {
|
|
305
|
+
return `msg-${Date.now()}-${++this.messageId}`;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
// Factory for creating client with auto-loaded token
|
|
309
|
+
export async function createGatewayClient(url, options) {
|
|
310
|
+
const deviceToken = await GatewayClient.loadDeviceToken();
|
|
311
|
+
return new GatewayClient({
|
|
312
|
+
url,
|
|
313
|
+
deviceToken: deviceToken ?? undefined,
|
|
314
|
+
...options,
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
export default GatewayClient;
|
|
318
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/gateway/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/infra/index.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,OAAO,EACL,oBAAoB,EACpB,uBAAuB,GAGxB,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tailscale Integration - v0.3.0
|
|
3
|
+
*
|
|
4
|
+
* Zero-config VPN for secure remote gateway access.
|
|
5
|
+
* No port forwarding required, works through NAT/firewalls.
|
|
6
|
+
*/
|
|
7
|
+
import { spawn } from "node:child_process";
|
|
8
|
+
import { EventEmitter } from "events";
|
|
9
|
+
class TailscaleIntegration extends EventEmitter {
|
|
10
|
+
config;
|
|
11
|
+
connected = false;
|
|
12
|
+
constructor(config = {}) {
|
|
13
|
+
super();
|
|
14
|
+
this.config = {
|
|
15
|
+
enabled: false,
|
|
16
|
+
autoStart: true,
|
|
17
|
+
advertiseExitNode: false,
|
|
18
|
+
...config,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Check if Tailscale is installed
|
|
23
|
+
*/
|
|
24
|
+
async isInstalled() {
|
|
25
|
+
try {
|
|
26
|
+
const result = await this.execCommand("tailscale", ["version"]);
|
|
27
|
+
return result.success;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Check if Tailscale is running
|
|
35
|
+
*/
|
|
36
|
+
async isRunning() {
|
|
37
|
+
try {
|
|
38
|
+
const result = await this.execCommand("tailscale", ["status", "--json"]);
|
|
39
|
+
if (!result.success)
|
|
40
|
+
return false;
|
|
41
|
+
const status = JSON.parse(result.stdout);
|
|
42
|
+
return status?.Self?.Online || false;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get Tailscale status
|
|
50
|
+
*/
|
|
51
|
+
async getStatus() {
|
|
52
|
+
const installed = await this.isInstalled();
|
|
53
|
+
const running = installed ? await this.isRunning() : false;
|
|
54
|
+
if (running) {
|
|
55
|
+
try {
|
|
56
|
+
const result = await this.execCommand("tailscale", ["status", "--json"]);
|
|
57
|
+
const status = JSON.parse(result.stdout);
|
|
58
|
+
return {
|
|
59
|
+
installed,
|
|
60
|
+
running,
|
|
61
|
+
connected: status?.Self?.Online || false,
|
|
62
|
+
myIP: status?.Self?.TailscaleIPs?.[0],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return { installed, running, connected: false };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return { installed, running, connected: false };
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Start Tailscale daemon
|
|
73
|
+
*/
|
|
74
|
+
async start() {
|
|
75
|
+
const status = await this.getStatus();
|
|
76
|
+
if (!status.installed) {
|
|
77
|
+
console.log("⚠️ Tailscale not installed");
|
|
78
|
+
console.log(" Install: https://tailscale.com/download");
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
if (status.running) {
|
|
82
|
+
console.log("✅ Tailscale already running");
|
|
83
|
+
this.emit("ready", { ip: status.myIP });
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
console.log("🚀 Starting Tailscale...");
|
|
87
|
+
let result;
|
|
88
|
+
if (process.platform === "darwin") {
|
|
89
|
+
result = await this.execCommand("sudo", ["tailscaled", "--daemon"]);
|
|
90
|
+
}
|
|
91
|
+
else if (process.platform === "linux") {
|
|
92
|
+
result = await this.execCommand("sudo", ["systemctl", "start", "tailscaled"]);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
console.log("⚠️ Windows not yet supported for auto-start");
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
if (result.success) {
|
|
99
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
100
|
+
const newStatus = await this.getStatus();
|
|
101
|
+
if (newStatus.running) {
|
|
102
|
+
console.log(`✅ Tailscale ready: ${newStatus.myIP}`);
|
|
103
|
+
this.emit("ready", { ip: newStatus.myIP });
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Get my Tailscale IP
|
|
111
|
+
*/
|
|
112
|
+
async getMyIP() {
|
|
113
|
+
const result = await this.execCommand("tailscale", ["ip", "-4"]);
|
|
114
|
+
if (result.success) {
|
|
115
|
+
return result.stdout.trim();
|
|
116
|
+
}
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Generate gateway URL for this device
|
|
121
|
+
*/
|
|
122
|
+
async getGatewayURL(port = 7777) {
|
|
123
|
+
const ip = await this.getMyIP();
|
|
124
|
+
if (!ip)
|
|
125
|
+
return undefined;
|
|
126
|
+
return `wss://${ip}:${port}`;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Execute command helper
|
|
130
|
+
*/
|
|
131
|
+
execCommand(cmd, args) {
|
|
132
|
+
return new Promise((resolve) => {
|
|
133
|
+
const child = spawn(cmd, args, {
|
|
134
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
135
|
+
});
|
|
136
|
+
let stdout = "";
|
|
137
|
+
let stderr = "";
|
|
138
|
+
child.stdout?.on("data", (data) => {
|
|
139
|
+
stdout += data.toString();
|
|
140
|
+
});
|
|
141
|
+
child.stderr?.on("data", (data) => {
|
|
142
|
+
stderr += data.toString();
|
|
143
|
+
});
|
|
144
|
+
child.on("exit", (code) => {
|
|
145
|
+
resolve({ success: code === 0, stdout, stderr });
|
|
146
|
+
});
|
|
147
|
+
child.on("error", () => {
|
|
148
|
+
resolve({ success: false, stdout, stderr });
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Singleton
|
|
154
|
+
let instance = null;
|
|
155
|
+
export function getTailscaleIntegration(config) {
|
|
156
|
+
if (!instance) {
|
|
157
|
+
instance = new TailscaleIntegration(config);
|
|
158
|
+
}
|
|
159
|
+
return instance;
|
|
160
|
+
}
|
|
161
|
+
export { TailscaleIntegration };
|
|
162
|
+
export default TailscaleIntegration;
|
|
163
|
+
//# sourceMappingURL=tailscale.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tailscale.js","sourceRoot":"","sources":["../../../src/infra/tailscale.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audio Transcription - v0.3.0
|
|
3
|
+
*
|
|
4
|
+
* Speech-to-text using Whisper API or local inference.
|
|
5
|
+
*/
|
|
6
|
+
import OpenAI from "openai";
|
|
7
|
+
import * as fs from "node:fs/promises";
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
import { spawn } from "node:child_process";
|
|
10
|
+
export class AudioTranscriber {
|
|
11
|
+
config;
|
|
12
|
+
openai;
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.config = {
|
|
15
|
+
model: config.provider === "openai" ? "whisper-1" : "base",
|
|
16
|
+
responseFormat: "json",
|
|
17
|
+
...config,
|
|
18
|
+
};
|
|
19
|
+
if (config.provider === "openai" && config.apiKey) {
|
|
20
|
+
this.openai = new OpenAI({ apiKey: config.apiKey });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Transcribe audio file
|
|
25
|
+
*/
|
|
26
|
+
async transcribeFile(audioPath) {
|
|
27
|
+
if (this.config.provider === "openai") {
|
|
28
|
+
return this.transcribeWithOpenAI(audioPath);
|
|
29
|
+
}
|
|
30
|
+
return this.transcribeLocal(audioPath);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Transcribe audio buffer
|
|
34
|
+
*/
|
|
35
|
+
async transcribeBuffer(audioBuffer, filename = "audio.mp3") {
|
|
36
|
+
// Save to temp file
|
|
37
|
+
const tempPath = `/tmp/transcribe-${Date.now()}-${filename}`;
|
|
38
|
+
await fs.writeFile(tempPath, audioBuffer);
|
|
39
|
+
try {
|
|
40
|
+
return await this.transcribeFile(tempPath);
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
await fs.unlink(tempPath).catch(() => { });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Transcribe with OpenAI Whisper
|
|
48
|
+
*/
|
|
49
|
+
async transcribeWithOpenAI(audioPath) {
|
|
50
|
+
if (!this.openai) {
|
|
51
|
+
throw new Error("OpenAI client not initialized");
|
|
52
|
+
}
|
|
53
|
+
// Read file as buffer
|
|
54
|
+
const buffer = await fs.readFile(audioPath);
|
|
55
|
+
const blob = new Blob([buffer], { type: "audio/mpeg" });
|
|
56
|
+
const file = new File([blob], path.basename(audioPath), { type: "audio/mpeg" });
|
|
57
|
+
const response = await this.openai.audio.transcriptions.create({
|
|
58
|
+
file: file,
|
|
59
|
+
model: this.config.model,
|
|
60
|
+
language: this.config.language,
|
|
61
|
+
response_format: this.config.responseFormat,
|
|
62
|
+
});
|
|
63
|
+
const result = {
|
|
64
|
+
text: typeof response === "string" ? response : response.text,
|
|
65
|
+
language: this.config.language,
|
|
66
|
+
};
|
|
67
|
+
// Parse verbose JSON if available
|
|
68
|
+
if (typeof response === "object" && "segments" in response) {
|
|
69
|
+
result.segments = response.segments?.map((seg) => ({
|
|
70
|
+
id: seg.id,
|
|
71
|
+
start: seg.start,
|
|
72
|
+
end: seg.end,
|
|
73
|
+
text: seg.text,
|
|
74
|
+
}));
|
|
75
|
+
result.duration = response.duration;
|
|
76
|
+
}
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Local transcription (placeholder for future local Whisper)
|
|
81
|
+
*/
|
|
82
|
+
async transcribeLocal(audioPath) {
|
|
83
|
+
// Placeholder: would use local whisper.cpp or similar
|
|
84
|
+
throw new Error("Local transcription not yet implemented. Use OpenAI provider.");
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Convert audio format using ffmpeg
|
|
88
|
+
*/
|
|
89
|
+
async convertAudio(inputPath, outputFormat = "mp3") {
|
|
90
|
+
const outputPath = inputPath.replace(/\.[^.]+$/, `.${outputFormat}`);
|
|
91
|
+
return new Promise((resolve, reject) => {
|
|
92
|
+
const ffmpeg = spawn("ffmpeg", [
|
|
93
|
+
"-i", inputPath,
|
|
94
|
+
"-ar", "16000",
|
|
95
|
+
"-ac", "1",
|
|
96
|
+
"-f", outputFormat,
|
|
97
|
+
outputPath,
|
|
98
|
+
]);
|
|
99
|
+
ffmpeg.on("close", (code) => {
|
|
100
|
+
if (code === 0) {
|
|
101
|
+
resolve(outputPath);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
reject(new Error(`ffmpeg exited with code ${code}`));
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
ffmpeg.on("error", (err) => {
|
|
108
|
+
if (err.message.includes("ENOENT")) {
|
|
109
|
+
reject(new Error("ffmpeg not found. Install ffmpeg to convert audio."));
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
reject(err);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Helper functions
|
|
119
|
+
export async function transcribeAudio(audioPath, config) {
|
|
120
|
+
const transcriber = new AudioTranscriber(config);
|
|
121
|
+
return transcriber.transcribeFile(audioPath);
|
|
122
|
+
}
|
|
123
|
+
export async function transcribeVoiceNote(audioPath, apiKey) {
|
|
124
|
+
const result = await transcribeAudio(audioPath, {
|
|
125
|
+
provider: "openai",
|
|
126
|
+
apiKey,
|
|
127
|
+
});
|
|
128
|
+
return result.text;
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=audio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio.js","sourceRoot":"","sources":["../../../src/media/audio.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/media/index.ts"],"names":[],"mappings":"AAAA,wBAAwB;AACxB,OAAO,EACL,cAAc,EACd,YAAY,GAGb,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,mBAAmB,GAGpB,MAAM,YAAY,CAAC"}
|