visionclaw 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/README.md +116 -0
- package/dist/agent/context.d.ts +56 -0
- package/dist/agent/context.d.ts.map +1 -0
- package/dist/agent/context.js +142 -0
- package/dist/agent/context.js.map +1 -0
- package/dist/agent/loop.d.ts +18 -0
- package/dist/agent/loop.d.ts.map +1 -0
- package/dist/agent/loop.js +323 -0
- package/dist/agent/loop.js.map +1 -0
- package/dist/agent/session.d.ts +49 -0
- package/dist/agent/session.d.ts.map +1 -0
- package/dist/agent/session.js +200 -0
- package/dist/agent/session.js.map +1 -0
- package/dist/agent/system-prompt.d.ts +10 -0
- package/dist/agent/system-prompt.d.ts.map +1 -0
- package/dist/agent/system-prompt.js +167 -0
- package/dist/agent/system-prompt.js.map +1 -0
- package/dist/calendar/google-calendar.d.ts +46 -0
- package/dist/calendar/google-calendar.d.ts.map +1 -0
- package/dist/calendar/google-calendar.js +132 -0
- package/dist/calendar/google-calendar.js.map +1 -0
- package/dist/calendar/scheduler.d.ts +7 -0
- package/dist/calendar/scheduler.d.ts.map +1 -0
- package/dist/calendar/scheduler.js +33 -0
- package/dist/calendar/scheduler.js.map +1 -0
- package/dist/channels/discord.d.ts +19 -0
- package/dist/channels/discord.d.ts.map +1 -0
- package/dist/channels/discord.js +169 -0
- package/dist/channels/discord.js.map +1 -0
- package/dist/channels/gmail.d.ts +31 -0
- package/dist/channels/gmail.d.ts.map +1 -0
- package/dist/channels/gmail.js +300 -0
- package/dist/channels/gmail.js.map +1 -0
- package/dist/channels/interface.d.ts +45 -0
- package/dist/channels/interface.d.ts.map +1 -0
- package/dist/channels/interface.js +2 -0
- package/dist/channels/interface.js.map +1 -0
- package/dist/channels/manager.d.ts +36 -0
- package/dist/channels/manager.d.ts.map +1 -0
- package/dist/channels/manager.js +108 -0
- package/dist/channels/manager.js.map +1 -0
- package/dist/channels/queue.d.ts +17 -0
- package/dist/channels/queue.d.ts.map +1 -0
- package/dist/channels/queue.js +85 -0
- package/dist/channels/queue.js.map +1 -0
- package/dist/channels/slack.d.ts +17 -0
- package/dist/channels/slack.d.ts.map +1 -0
- package/dist/channels/slack.js +142 -0
- package/dist/channels/slack.js.map +1 -0
- package/dist/channels/sms.d.ts +19 -0
- package/dist/channels/sms.d.ts.map +1 -0
- package/dist/channels/sms.js +111 -0
- package/dist/channels/sms.js.map +1 -0
- package/dist/channels/telegram.d.ts +28 -0
- package/dist/channels/telegram.d.ts.map +1 -0
- package/dist/channels/telegram.js +246 -0
- package/dist/channels/telegram.js.map +1 -0
- package/dist/channels/whatsapp.d.ts +28 -0
- package/dist/channels/whatsapp.d.ts.map +1 -0
- package/dist/channels/whatsapp.js +292 -0
- package/dist/channels/whatsapp.js.map +1 -0
- package/dist/config/index.d.ts +24 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +104 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/types.d.ts +227 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +45 -0
- package/dist/config/types.js.map +1 -0
- package/dist/files.d.ts +20 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +82 -0
- package/dist/files.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +76 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +384 -0
- package/dist/logger.js.map +1 -0
- package/dist/memory/store.d.ts +24 -0
- package/dist/memory/store.d.ts.map +1 -0
- package/dist/memory/store.js +71 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/obs/server.d.ts +10 -0
- package/dist/obs/server.d.ts.map +1 -0
- package/dist/obs/server.js +406 -0
- package/dist/obs/server.js.map +1 -0
- package/dist/onboarding/google-auth.d.ts +11 -0
- package/dist/onboarding/google-auth.d.ts.map +1 -0
- package/dist/onboarding/google-auth.js +113 -0
- package/dist/onboarding/google-auth.js.map +1 -0
- package/dist/onboarding/index.d.ts +2 -0
- package/dist/onboarding/index.d.ts.map +1 -0
- package/dist/onboarding/index.js +213 -0
- package/dist/onboarding/index.js.map +1 -0
- package/dist/onboarding/macos-permissions.d.ts +37 -0
- package/dist/onboarding/macos-permissions.d.ts.map +1 -0
- package/dist/onboarding/macos-permissions.js +207 -0
- package/dist/onboarding/macos-permissions.js.map +1 -0
- package/dist/skills/install.d.ts +7 -0
- package/dist/skills/install.d.ts.map +1 -0
- package/dist/skills/install.js +63 -0
- package/dist/skills/install.js.map +1 -0
- package/dist/tools/browser.d.ts +7 -0
- package/dist/tools/browser.d.ts.map +1 -0
- package/dist/tools/browser.js +202 -0
- package/dist/tools/browser.js.map +1 -0
- package/dist/tools/calendar.d.ts +12 -0
- package/dist/tools/calendar.d.ts.map +1 -0
- package/dist/tools/calendar.js +210 -0
- package/dist/tools/calendar.js.map +1 -0
- package/dist/tools/computer-use.d.ts +28 -0
- package/dist/tools/computer-use.d.ts.map +1 -0
- package/dist/tools/computer-use.js +311 -0
- package/dist/tools/computer-use.js.map +1 -0
- package/dist/tools/coordinate-resolver.d.ts +26 -0
- package/dist/tools/coordinate-resolver.d.ts.map +1 -0
- package/dist/tools/coordinate-resolver.js +157 -0
- package/dist/tools/coordinate-resolver.js.map +1 -0
- package/dist/tools/desktop-executor.d.ts +52 -0
- package/dist/tools/desktop-executor.d.ts.map +1 -0
- package/dist/tools/desktop-executor.js +202 -0
- package/dist/tools/desktop-executor.js.map +1 -0
- package/dist/tools/finish.d.ts +5 -0
- package/dist/tools/finish.d.ts.map +1 -0
- package/dist/tools/finish.js +18 -0
- package/dist/tools/finish.js.map +1 -0
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +37 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/memory.d.ts +14 -0
- package/dist/tools/memory.d.ts.map +1 -0
- package/dist/tools/memory.js +269 -0
- package/dist/tools/memory.js.map +1 -0
- package/dist/tools/notify.d.ts +12 -0
- package/dist/tools/notify.d.ts.map +1 -0
- package/dist/tools/notify.js +108 -0
- package/dist/tools/notify.js.map +1 -0
- package/dist/tools/screenshot.d.ts +7 -0
- package/dist/tools/screenshot.d.ts.map +1 -0
- package/dist/tools/screenshot.js +189 -0
- package/dist/tools/screenshot.js.map +1 -0
- package/dist/tools/skill.d.ts +8 -0
- package/dist/tools/skill.d.ts.map +1 -0
- package/dist/tools/skill.js +133 -0
- package/dist/tools/skill.js.map +1 -0
- package/dist/tools/upgrade.d.ts +5 -0
- package/dist/tools/upgrade.d.ts.map +1 -0
- package/dist/tools/upgrade.js +89 -0
- package/dist/tools/upgrade.js.map +1 -0
- package/dist/tools/wait.d.ts +5 -0
- package/dist/tools/wait.d.ts.map +1 -0
- package/dist/tools/wait.js +21 -0
- package/dist/tools/wait.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-calendar.js","sourceRoot":"","sources":["../../src/calendar/google-calendar.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { VisionClawConfig } from "../config/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Get a summary of upcoming calendar events for context injection.
|
|
4
|
+
* Called on each agent wake to inform the agent of due/upcoming tasks.
|
|
5
|
+
*/
|
|
6
|
+
export declare function getCalendarSummary(config: VisionClawConfig): Promise<string>;
|
|
7
|
+
//# sourceMappingURL=scheduler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/calendar/scheduler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAI3D;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,MAAM,CAAC,CA+BjB"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { logger } from "../logger.js";
|
|
2
|
+
import { GoogleCalendarClient } from "./google-calendar.js";
|
|
3
|
+
/**
|
|
4
|
+
* Get a summary of upcoming calendar events for context injection.
|
|
5
|
+
* Called on each agent wake to inform the agent of due/upcoming tasks.
|
|
6
|
+
*/
|
|
7
|
+
export async function getCalendarSummary(config) {
|
|
8
|
+
try {
|
|
9
|
+
const client = new GoogleCalendarClient(config);
|
|
10
|
+
const now = new Date();
|
|
11
|
+
const futureWindow = new Date(now.getTime() + 24 * 60 * 60 * 1000 // Next 24 hours
|
|
12
|
+
);
|
|
13
|
+
const events = await client.listUpcomingEvents(now, futureWindow);
|
|
14
|
+
if (events.length === 0) {
|
|
15
|
+
return "";
|
|
16
|
+
}
|
|
17
|
+
const lines = events.map((event) => {
|
|
18
|
+
const start = event.start?.dateTime ?? event.start?.date ?? "unknown";
|
|
19
|
+
const end = event.end?.dateTime ?? event.end?.date ?? "";
|
|
20
|
+
const summary = event.summary ?? "(no title)";
|
|
21
|
+
const description = event.description
|
|
22
|
+
? ` - ${event.description.substring(0, 100)}`
|
|
23
|
+
: "";
|
|
24
|
+
return `- ${start}${end ? ` to ${end}` : ""}: ${summary}${description}`;
|
|
25
|
+
});
|
|
26
|
+
return lines.join("\n");
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
logger.warn(`Calendar summary failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
30
|
+
return "";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=scheduler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/calendar/scheduler.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE5D;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,MAAwB;IAExB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,oBAAoB,CAAC,MAAM,CAAC,CAAC;QAChD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,YAAY,GAAG,IAAI,IAAI,CAC3B,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,gBAAgB;SACrD,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;QAElE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YACjC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,EAAE,QAAQ,IAAI,KAAK,CAAC,KAAK,EAAE,IAAI,IAAI,SAAS,CAAC;YACtE,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,EAAE,QAAQ,IAAI,KAAK,CAAC,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC;YACzD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,IAAI,YAAY,CAAC;YAC9C,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW;gBACnC,CAAC,CAAC,MAAM,KAAK,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;gBAC7C,CAAC,CAAC,EAAE,CAAC;YACP,OAAO,KAAK,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,GAAG,WAAW,EAAE,CAAC;QAC1E,CAAC,CAAC,CAAC;QAEH,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,CACT,4BAA4B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC/E,CAAC;QACF,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import type { VisionClawConfig } from "../config/types.js";
|
|
3
|
+
import type { ChannelAdapter, MessageAttachment } from "./interface.js";
|
|
4
|
+
/**
|
|
5
|
+
* Discord channel adapter.
|
|
6
|
+
* Connects via WebSocket gateway -- no public URL needed.
|
|
7
|
+
* Supports multimodal inbound (images, files) and outbound (images, files).
|
|
8
|
+
*/
|
|
9
|
+
export declare class DiscordAdapter extends EventEmitter implements ChannelAdapter {
|
|
10
|
+
readonly name = "discord";
|
|
11
|
+
private config;
|
|
12
|
+
private client;
|
|
13
|
+
constructor(config: VisionClawConfig);
|
|
14
|
+
start(): Promise<void>;
|
|
15
|
+
stop(): Promise<void>;
|
|
16
|
+
sendMessage(to: string, message: string, attachments?: MessageAttachment[]): Promise<void>;
|
|
17
|
+
private processInboundMessage;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=discord.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discord.d.ts","sourceRoot":"","sources":["../../src/channels/discord.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAW3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAkB,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExF;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,YAAa,YAAW,cAAc;IACxE,QAAQ,CAAC,IAAI,aAAa;IAC1B,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,MAAM,CAAuB;gBAEzB,MAAM,EAAE,gBAAgB;IAK9B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAwCtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAOrB,WAAW,CACf,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,iBAAiB,EAAE,GAChC,OAAO,CAAC,IAAI,CAAC;YA4DF,qBAAqB;CAiEpC"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import { Client, GatewayIntentBits, Partials, AttachmentBuilder, } from "discord.js";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import { logger } from "../logger.js";
|
|
5
|
+
import { uploadMedia } from "../files.js";
|
|
6
|
+
/**
|
|
7
|
+
* Discord channel adapter.
|
|
8
|
+
* Connects via WebSocket gateway -- no public URL needed.
|
|
9
|
+
* Supports multimodal inbound (images, files) and outbound (images, files).
|
|
10
|
+
*/
|
|
11
|
+
export class DiscordAdapter extends EventEmitter {
|
|
12
|
+
name = "discord";
|
|
13
|
+
config;
|
|
14
|
+
client = null;
|
|
15
|
+
constructor(config) {
|
|
16
|
+
super();
|
|
17
|
+
this.config = config;
|
|
18
|
+
}
|
|
19
|
+
async start() {
|
|
20
|
+
const discordConfig = this.config.channels.discord;
|
|
21
|
+
if (!discordConfig?.botToken) {
|
|
22
|
+
throw new Error("Discord bot token not configured");
|
|
23
|
+
}
|
|
24
|
+
this.client = new Client({
|
|
25
|
+
intents: [
|
|
26
|
+
GatewayIntentBits.Guilds,
|
|
27
|
+
GatewayIntentBits.GuildMessages,
|
|
28
|
+
GatewayIntentBits.DirectMessages,
|
|
29
|
+
GatewayIntentBits.MessageContent,
|
|
30
|
+
],
|
|
31
|
+
partials: [Partials.Channel], // Required for DMs
|
|
32
|
+
});
|
|
33
|
+
const allowedChannelIds = discordConfig.allowedChannelIds;
|
|
34
|
+
this.client.on("messageCreate", (msg) => {
|
|
35
|
+
// Ignore bot's own messages
|
|
36
|
+
if (msg.author.bot)
|
|
37
|
+
return;
|
|
38
|
+
// Filter by allowed channels/DMs if configured
|
|
39
|
+
if (allowedChannelIds.length > 0 && !allowedChannelIds.includes(msg.channelId)) {
|
|
40
|
+
// Allow DMs through regardless
|
|
41
|
+
if (!msg.channel.isDMBased())
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
// Process asynchronously to allow media downloads
|
|
45
|
+
void this.processInboundMessage(msg);
|
|
46
|
+
});
|
|
47
|
+
this.client.on("error", (err) => {
|
|
48
|
+
this.emit("error", err);
|
|
49
|
+
});
|
|
50
|
+
await this.client.login(discordConfig.botToken);
|
|
51
|
+
logger.channel("discord", `Logged in as ${this.client.user?.tag ?? "unknown"}`);
|
|
52
|
+
}
|
|
53
|
+
async stop() {
|
|
54
|
+
if (this.client) {
|
|
55
|
+
await this.client.destroy();
|
|
56
|
+
this.client = null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async sendMessage(to, message, attachments) {
|
|
60
|
+
if (!this.client) {
|
|
61
|
+
throw new Error("Discord client not started");
|
|
62
|
+
}
|
|
63
|
+
const channel = await this.client.channels.fetch(to);
|
|
64
|
+
if (!channel?.isTextBased()) {
|
|
65
|
+
throw new Error(`Discord channel ${to} is not a text channel`);
|
|
66
|
+
}
|
|
67
|
+
if (!("send" in channel)) {
|
|
68
|
+
throw new Error(`Cannot send to Discord channel ${to}`);
|
|
69
|
+
}
|
|
70
|
+
// Build Discord attachments from local paths or URLs
|
|
71
|
+
const discordAttachments = [];
|
|
72
|
+
if (attachments) {
|
|
73
|
+
for (const att of attachments) {
|
|
74
|
+
if (att.localPath && fs.existsSync(att.localPath)) {
|
|
75
|
+
discordAttachments.push(new AttachmentBuilder(att.localPath, {
|
|
76
|
+
name: att.filename ?? att.localPath.split("/").pop(),
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
else if (att.url) {
|
|
80
|
+
discordAttachments.push(new AttachmentBuilder(att.url, {
|
|
81
|
+
name: att.filename ?? "attachment",
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Split long messages (Discord has a 2000 char limit)
|
|
87
|
+
const MAX_LENGTH = 2000;
|
|
88
|
+
if (message.trim()) {
|
|
89
|
+
if (message.length <= MAX_LENGTH) {
|
|
90
|
+
await channel.send({
|
|
91
|
+
content: message,
|
|
92
|
+
files: discordAttachments,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
// Send attachments with first chunk
|
|
97
|
+
const chunks = [];
|
|
98
|
+
for (let i = 0; i < message.length; i += MAX_LENGTH) {
|
|
99
|
+
chunks.push(message.substring(i, i + MAX_LENGTH));
|
|
100
|
+
}
|
|
101
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
102
|
+
await channel.send({
|
|
103
|
+
content: chunks[i],
|
|
104
|
+
files: i === 0 ? discordAttachments : undefined,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else if (discordAttachments.length > 0) {
|
|
110
|
+
await channel.send({ files: discordAttachments });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
async processInboundMessage(msg) {
|
|
114
|
+
try {
|
|
115
|
+
const senderDisplay = `${msg.author.displayName} (${msg.author.id})`;
|
|
116
|
+
const commandMessage = {
|
|
117
|
+
id: `discord-${msg.id}`,
|
|
118
|
+
channel: "discord",
|
|
119
|
+
sender: senderDisplay,
|
|
120
|
+
text: msg.content,
|
|
121
|
+
attachments: [],
|
|
122
|
+
timestamp: msg.createdAt.toISOString(),
|
|
123
|
+
meta: {
|
|
124
|
+
channelId: msg.channelId,
|
|
125
|
+
guildId: msg.guildId,
|
|
126
|
+
authorId: msg.author.id,
|
|
127
|
+
username: msg.author.username,
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
// Download attachments and upload to S3
|
|
131
|
+
for (const att of msg.attachments.values()) {
|
|
132
|
+
const mimeType = att.contentType ?? "application/octet-stream";
|
|
133
|
+
const filename = att.name;
|
|
134
|
+
let publicUrl;
|
|
135
|
+
try {
|
|
136
|
+
const response = await fetch(att.url);
|
|
137
|
+
if (response.ok) {
|
|
138
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
139
|
+
const s3Url = await uploadMedia(buffer, filename, mimeType);
|
|
140
|
+
publicUrl = s3Url ?? undefined;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
logger.warn(`Discord: Failed to download attachment: ${err instanceof Error ? err.message : String(err)}`);
|
|
145
|
+
}
|
|
146
|
+
const type = mimeType.startsWith("image/")
|
|
147
|
+
? "image"
|
|
148
|
+
: mimeType.startsWith("audio/")
|
|
149
|
+
? "audio"
|
|
150
|
+
: mimeType.startsWith("video/")
|
|
151
|
+
? "video"
|
|
152
|
+
: "file";
|
|
153
|
+
commandMessage.attachments.push({
|
|
154
|
+
type,
|
|
155
|
+
url: publicUrl ?? att.url,
|
|
156
|
+
filename,
|
|
157
|
+
mimeType,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
if (commandMessage.text || commandMessage.attachments.length > 0) {
|
|
161
|
+
this.emit("message", commandMessage);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
logger.warn(`Discord: Error processing message: ${err instanceof Error ? err.message : String(err)}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=discord.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discord.js","sourceRoot":"","sources":["../../src/channels/discord.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import type { VisionClawConfig } from "../config/types.js";
|
|
3
|
+
import type { ChannelAdapter, MessageAttachment } from "./interface.js";
|
|
4
|
+
/**
|
|
5
|
+
* Gmail channel adapter.
|
|
6
|
+
* Uses the agent's dedicated Gmail account to receive and send emails.
|
|
7
|
+
*
|
|
8
|
+
* On startup, captures the current historyId and only processes
|
|
9
|
+
* messages that arrive AFTER that point via the Gmail History API.
|
|
10
|
+
* This prevents old unread emails from flooding the agent.
|
|
11
|
+
*/
|
|
12
|
+
export declare class GmailAdapter extends EventEmitter implements ChannelAdapter {
|
|
13
|
+
readonly name = "gmail";
|
|
14
|
+
private config;
|
|
15
|
+
private gmail;
|
|
16
|
+
private pollInterval;
|
|
17
|
+
private lastHistoryId;
|
|
18
|
+
private processedMessageIds;
|
|
19
|
+
private initialized;
|
|
20
|
+
constructor(config: VisionClawConfig);
|
|
21
|
+
start(): Promise<void>;
|
|
22
|
+
stop(): Promise<void>;
|
|
23
|
+
sendMessage(to: string, message: string, attachments?: MessageAttachment[]): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Poll for new messages using the Gmail History API.
|
|
26
|
+
* Only fetches messages added since the last known historyId,
|
|
27
|
+
* so old unread emails are never processed.
|
|
28
|
+
*/
|
|
29
|
+
private pollForMessages;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=gmail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gmail.d.ts","sourceRoot":"","sources":["../../src/channels/gmail.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQ3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAkB,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExF;;;;;;;GAOG;AACH,qBAAa,YAAa,SAAQ,YAAa,YAAW,cAAc;IACtE,QAAQ,CAAC,IAAI,WAAW;IACxB,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,YAAY,CAA+C;IACnE,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,mBAAmB,CAAqB;IAChD,OAAO,CAAC,WAAW,CAAS;gBAEhB,MAAM,EAAE,gBAAgB;IA4B9B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB5B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAQf,WAAW,CACf,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,iBAAiB,EAAE,GAChC,OAAO,CAAC,IAAI,CAAC;IAehB;;;;OAIG;YACW,eAAe;CAwF9B"}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { EventEmitter } from "node:events";
|
|
3
|
+
import { google } from "googleapis";
|
|
4
|
+
import { loadGoogleTokens, saveGoogleTokens, } from "../config/index.js";
|
|
5
|
+
import { logger } from "../logger.js";
|
|
6
|
+
import { uploadMedia } from "../files.js";
|
|
7
|
+
/**
|
|
8
|
+
* Gmail channel adapter.
|
|
9
|
+
* Uses the agent's dedicated Gmail account to receive and send emails.
|
|
10
|
+
*
|
|
11
|
+
* On startup, captures the current historyId and only processes
|
|
12
|
+
* messages that arrive AFTER that point via the Gmail History API.
|
|
13
|
+
* This prevents old unread emails from flooding the agent.
|
|
14
|
+
*/
|
|
15
|
+
export class GmailAdapter extends EventEmitter {
|
|
16
|
+
name = "gmail";
|
|
17
|
+
config;
|
|
18
|
+
gmail;
|
|
19
|
+
pollInterval = null;
|
|
20
|
+
lastHistoryId = null;
|
|
21
|
+
processedMessageIds = new Set();
|
|
22
|
+
initialized = false;
|
|
23
|
+
constructor(config) {
|
|
24
|
+
super();
|
|
25
|
+
this.config = config;
|
|
26
|
+
const tokens = loadGoogleTokens();
|
|
27
|
+
const oauth2Client = new google.auth.OAuth2(config.googleClientId, config.googleClientSecret);
|
|
28
|
+
oauth2Client.setCredentials({
|
|
29
|
+
access_token: tokens.access_token,
|
|
30
|
+
refresh_token: tokens.refresh_token,
|
|
31
|
+
token_type: tokens.token_type,
|
|
32
|
+
expiry_date: tokens.expiry_date,
|
|
33
|
+
});
|
|
34
|
+
oauth2Client.on("tokens", (newTokens) => {
|
|
35
|
+
const existing = loadGoogleTokens();
|
|
36
|
+
saveGoogleTokens({
|
|
37
|
+
...existing,
|
|
38
|
+
access_token: newTokens.access_token ?? existing.access_token,
|
|
39
|
+
expiry_date: newTokens.expiry_date ?? existing.expiry_date,
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
this.gmail = google.gmail({ version: "v1", auth: oauth2Client });
|
|
43
|
+
}
|
|
44
|
+
async start() {
|
|
45
|
+
// Capture current historyId as our baseline.
|
|
46
|
+
// We will only process messages that arrive AFTER this point.
|
|
47
|
+
try {
|
|
48
|
+
const profile = await this.gmail.users.getProfile({ userId: "me" });
|
|
49
|
+
this.lastHistoryId = profile.data.historyId ?? null;
|
|
50
|
+
this.initialized = true;
|
|
51
|
+
logger.channel("gmail", `Baseline historyId: ${this.lastHistoryId}`);
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
logger.warn(`Gmail: Could not get initial history ID: ${err instanceof Error ? err.message : String(err)}`);
|
|
55
|
+
}
|
|
56
|
+
// Poll for new messages every 30 seconds
|
|
57
|
+
this.pollInterval = setInterval(() => {
|
|
58
|
+
this.pollForMessages().catch((err) => {
|
|
59
|
+
this.emit("error", err instanceof Error ? err : new Error(String(err)));
|
|
60
|
+
});
|
|
61
|
+
}, 30_000);
|
|
62
|
+
}
|
|
63
|
+
stop() {
|
|
64
|
+
if (this.pollInterval) {
|
|
65
|
+
clearInterval(this.pollInterval);
|
|
66
|
+
this.pollInterval = null;
|
|
67
|
+
}
|
|
68
|
+
return Promise.resolve();
|
|
69
|
+
}
|
|
70
|
+
async sendMessage(to, message, attachments) {
|
|
71
|
+
const raw = createRawEmail({
|
|
72
|
+
from: this.config.gmail,
|
|
73
|
+
to,
|
|
74
|
+
subject: "Message from " + this.config.agentName,
|
|
75
|
+
body: message,
|
|
76
|
+
attachments,
|
|
77
|
+
});
|
|
78
|
+
await this.gmail.users.messages.send({
|
|
79
|
+
userId: "me",
|
|
80
|
+
requestBody: { raw },
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Poll for new messages using the Gmail History API.
|
|
85
|
+
* Only fetches messages added since the last known historyId,
|
|
86
|
+
* so old unread emails are never processed.
|
|
87
|
+
*/
|
|
88
|
+
async pollForMessages() {
|
|
89
|
+
if (!this.initialized || !this.lastHistoryId) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
// Use History API to get only messages added since our last checkpoint
|
|
94
|
+
const historyRes = await this.gmail.users.history.list({
|
|
95
|
+
userId: "me",
|
|
96
|
+
startHistoryId: this.lastHistoryId,
|
|
97
|
+
historyTypes: ["messageAdded"],
|
|
98
|
+
labelId: "INBOX",
|
|
99
|
+
});
|
|
100
|
+
// Update historyId for next poll
|
|
101
|
+
if (historyRes.data.historyId) {
|
|
102
|
+
this.lastHistoryId = historyRes.data.historyId;
|
|
103
|
+
}
|
|
104
|
+
const history = historyRes.data.history ?? [];
|
|
105
|
+
// Extract new message IDs from history records
|
|
106
|
+
const newMessageIds = [];
|
|
107
|
+
for (const record of history) {
|
|
108
|
+
const added = record.messagesAdded ?? [];
|
|
109
|
+
for (const item of added) {
|
|
110
|
+
const msgId = item.message?.id;
|
|
111
|
+
if (msgId && !this.processedMessageIds.has(msgId)) {
|
|
112
|
+
newMessageIds.push(msgId);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (newMessageIds.length === 0) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
logger.channel("gmail", `${newMessageIds.length} new message(s) detected`);
|
|
120
|
+
for (const msgId of newMessageIds) {
|
|
121
|
+
this.processedMessageIds.add(msgId);
|
|
122
|
+
// Keep the set from growing unbounded
|
|
123
|
+
if (this.processedMessageIds.size > 1000) {
|
|
124
|
+
const entries = Array.from(this.processedMessageIds);
|
|
125
|
+
this.processedMessageIds = new Set(entries.slice(-500));
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const full = await this.gmail.users.messages.get({
|
|
129
|
+
userId: "me",
|
|
130
|
+
id: msgId,
|
|
131
|
+
format: "full",
|
|
132
|
+
});
|
|
133
|
+
// Always mark as read to prevent re-processing
|
|
134
|
+
await this.gmail.users.messages.modify({
|
|
135
|
+
userId: "me",
|
|
136
|
+
id: msgId,
|
|
137
|
+
requestBody: { removeLabelIds: ["UNREAD"] },
|
|
138
|
+
});
|
|
139
|
+
const commandMessage = await parseGmailMessage(full.data, msgId, this.gmail);
|
|
140
|
+
if (commandMessage) {
|
|
141
|
+
this.emit("message", commandMessage);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
logger.warn(`Gmail: Error processing message ${msgId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
151
|
+
// If historyId is too old, Gmail returns 404. Reset baseline.
|
|
152
|
+
if (errMsg.includes("404") || errMsg.includes("historyId")) {
|
|
153
|
+
logger.warn("Gmail: History expired, resetting baseline");
|
|
154
|
+
try {
|
|
155
|
+
const profile = await this.gmail.users.getProfile({ userId: "me" });
|
|
156
|
+
this.lastHistoryId = profile.data.historyId ?? null;
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
// noop
|
|
160
|
+
}
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
logger.warn(`Gmail poll error: ${errMsg}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Parse a Gmail API message into a CommandMessage.
|
|
169
|
+
* Downloads attachments and uploads them to S3.
|
|
170
|
+
*/
|
|
171
|
+
async function parseGmailMessage(msg, id, gmail) {
|
|
172
|
+
const headers = msg.payload?.headers ?? [];
|
|
173
|
+
const from = headers.find((h) => h.name?.toLowerCase() === "from")?.value ?? "unknown";
|
|
174
|
+
const subject = headers.find((h) => h.name?.toLowerCase() === "subject")?.value ?? "";
|
|
175
|
+
const date = headers.find((h) => h.name?.toLowerCase() === "date")?.value ?? "";
|
|
176
|
+
// Extract body text and attachments from parts
|
|
177
|
+
let body = "";
|
|
178
|
+
const attachments = [];
|
|
179
|
+
if (msg.payload?.body?.data) {
|
|
180
|
+
body = Buffer.from(msg.payload.body.data, "base64url").toString("utf-8");
|
|
181
|
+
}
|
|
182
|
+
if (msg.payload?.parts) {
|
|
183
|
+
for (const part of msg.payload.parts) {
|
|
184
|
+
// Text body
|
|
185
|
+
if (part.mimeType === "text/plain" && part.body?.data && !body) {
|
|
186
|
+
body = Buffer.from(part.body.data, "base64url").toString("utf-8");
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
// Attachment with attachmentId
|
|
190
|
+
const attachmentId = part.body?.attachmentId;
|
|
191
|
+
const filename = part.filename ?? "";
|
|
192
|
+
const mimeType = part.mimeType ?? "application/octet-stream";
|
|
193
|
+
if (attachmentId && filename) {
|
|
194
|
+
try {
|
|
195
|
+
const attRes = await gmail.users.messages.attachments.get({
|
|
196
|
+
userId: "me",
|
|
197
|
+
messageId: id,
|
|
198
|
+
id: attachmentId,
|
|
199
|
+
});
|
|
200
|
+
if (attRes.data.data) {
|
|
201
|
+
const buffer = Buffer.from(attRes.data.data, "base64url");
|
|
202
|
+
const url = await uploadMedia(buffer, filename, mimeType);
|
|
203
|
+
const type = mimeType.startsWith("image/")
|
|
204
|
+
? "image"
|
|
205
|
+
: mimeType.startsWith("audio/")
|
|
206
|
+
? "audio"
|
|
207
|
+
: mimeType.startsWith("video/")
|
|
208
|
+
? "video"
|
|
209
|
+
: "file";
|
|
210
|
+
attachments.push({ type, url: url ?? undefined, filename, mimeType });
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
catch (err) {
|
|
214
|
+
logger.warn(`Gmail: Failed to download attachment ${filename}: ${err instanceof Error ? err.message : String(err)}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// If no plain text body, summarize from subject only
|
|
220
|
+
if (!body.trim()) {
|
|
221
|
+
if (!subject.trim() && attachments.length === 0) {
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
body = attachments.length > 0 ? "(attachments only)" : "(no text body)";
|
|
225
|
+
}
|
|
226
|
+
return {
|
|
227
|
+
id,
|
|
228
|
+
channel: "gmail",
|
|
229
|
+
sender: from,
|
|
230
|
+
text: subject ? `[Subject: ${subject}]\n${body}` : body,
|
|
231
|
+
attachments,
|
|
232
|
+
timestamp: date.trim() ? date : new Date().toISOString(),
|
|
233
|
+
meta: { subject, messageId: msg.id, threadId: msg.threadId },
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Create a base64url-encoded raw email for the Gmail API.
|
|
238
|
+
* Supports optional file attachments via MIME multipart.
|
|
239
|
+
*/
|
|
240
|
+
function createRawEmail(options) {
|
|
241
|
+
const hasAttachments = options.attachments && options.attachments.length > 0;
|
|
242
|
+
if (!hasAttachments) {
|
|
243
|
+
// Simple text email
|
|
244
|
+
const email = [
|
|
245
|
+
`From: ${options.from}`,
|
|
246
|
+
`To: ${options.to}`,
|
|
247
|
+
`Subject: ${options.subject}`,
|
|
248
|
+
`Content-Type: text/plain; charset=utf-8`,
|
|
249
|
+
"",
|
|
250
|
+
options.body,
|
|
251
|
+
].join("\r\n");
|
|
252
|
+
return Buffer.from(email).toString("base64url");
|
|
253
|
+
}
|
|
254
|
+
// Multipart MIME email with attachments
|
|
255
|
+
const boundary = `----VisionClaw${Date.now()}`;
|
|
256
|
+
const parts = [];
|
|
257
|
+
parts.push(`From: ${options.from}`);
|
|
258
|
+
parts.push(`To: ${options.to}`);
|
|
259
|
+
parts.push(`Subject: ${options.subject}`);
|
|
260
|
+
parts.push(`MIME-Version: 1.0`);
|
|
261
|
+
parts.push(`Content-Type: multipart/mixed; boundary="${boundary}"`);
|
|
262
|
+
parts.push("");
|
|
263
|
+
// Text body part
|
|
264
|
+
parts.push(`--${boundary}`);
|
|
265
|
+
parts.push(`Content-Type: text/plain; charset=utf-8`);
|
|
266
|
+
parts.push("");
|
|
267
|
+
parts.push(options.body);
|
|
268
|
+
// Attachment parts
|
|
269
|
+
for (const att of options.attachments ?? []) {
|
|
270
|
+
let b64Data = null;
|
|
271
|
+
const filename = att.filename ?? "attachment";
|
|
272
|
+
const mimeType = att.mimeType ?? "application/octet-stream";
|
|
273
|
+
if (att.localPath && fs.existsSync(att.localPath)) {
|
|
274
|
+
// Read local file and encode as base64
|
|
275
|
+
b64Data = fs.readFileSync(att.localPath).toString("base64");
|
|
276
|
+
}
|
|
277
|
+
else if (att.base64) {
|
|
278
|
+
b64Data = att.base64;
|
|
279
|
+
}
|
|
280
|
+
else if (att.url) {
|
|
281
|
+
// Include URL as a link (can't inline remote URLs in MIME)
|
|
282
|
+
parts.push(`--${boundary}`);
|
|
283
|
+
parts.push(`Content-Type: text/plain; charset=utf-8`);
|
|
284
|
+
parts.push("");
|
|
285
|
+
parts.push(`[Attachment: ${filename}] ${att.url}`);
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
if (b64Data) {
|
|
289
|
+
parts.push(`--${boundary}`);
|
|
290
|
+
parts.push(`Content-Type: ${mimeType}`);
|
|
291
|
+
parts.push(`Content-Transfer-Encoding: base64`);
|
|
292
|
+
parts.push(`Content-Disposition: attachment; filename="${filename}"`);
|
|
293
|
+
parts.push("");
|
|
294
|
+
parts.push(b64Data);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
parts.push(`--${boundary}--`);
|
|
298
|
+
return Buffer.from(parts.join("\r\n")).toString("base64url");
|
|
299
|
+
}
|
|
300
|
+
//# sourceMappingURL=gmail.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gmail.js","sourceRoot":"","sources":["../../src/channels/gmail.ts"],"names":[],"mappings":"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"}
|