volute 0.25.0 → 0.27.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 +28 -33
- package/dist/{activity-events-4O37J7PD.js → activity-events-BBIEA2F4.js} +2 -3
- package/dist/api.d.ts +886 -220
- package/dist/{archive-4ZQYK5MN.js → archive-UA4BDFXQ.js} +2 -2
- package/dist/{auth-HM2RSPY7.js → auth-D3OT2ARB.js} +3 -3
- package/dist/bridge-FQHZL3MC.js +206 -0
- package/dist/chat-MHJ3L6JQ.js +58 -0
- package/dist/{chunk-PHU4DEAJ.js → chunk-2WPW7OT6.js} +3 -3
- package/dist/{chunk-BOTQ25QT.js → chunk-2YP2TVDT.js} +138 -56
- package/dist/{chunk-DG7TO7EE.js → chunk-4WXYUOAK.js} +5 -7
- package/dist/{chunk-JTDFJWI2.js → chunk-AW7PFDVN.js} +5 -5
- package/dist/{chunk-2767L2RZ.js → chunk-EHYDTZTF.js} +6 -6
- package/dist/{chunk-ZSH4G2P5.js → chunk-GIE6CSN5.js} +17 -17
- package/dist/chunk-H7OZRFJB.js +432 -0
- package/dist/{chunk-ON3FF5JA.js → chunk-HDN7MNGD.js} +3 -3
- package/dist/chunk-IAYBDWVG.js +477 -0
- package/dist/chunk-IKRVFPWU.js +83 -0
- package/dist/{chunk-TRQEV3CD.js → chunk-JGFVMROS.js} +32 -6
- package/dist/{chunk-PHHKNGA3.js → chunk-JKOWNZ4P.js} +3 -3
- package/dist/{chunk-E7GOKNOT.js → chunk-K5NAC55T.js} +1 -1
- package/dist/{chunk-HFCBO2GL.js → chunk-KDGS53OS.js} +4 -4
- package/dist/chunk-KTLFDYPT.js +61 -0
- package/dist/{chunk-3AIBT4TW.js → chunk-LAC664WU.js} +30 -4
- package/dist/{chunk-PMX4EIJK.js → chunk-OQZH4PBB.js} +467 -1054
- package/dist/{chunk-SHSWYG2J.js → chunk-PHSAT7YL.js} +71 -58
- package/dist/chunk-RKQEHRBB.js +177 -0
- package/dist/{chunk-RVKR2R7F.js → chunk-SSI47XP2.js} +10 -2
- package/dist/chunk-T6HKBWXZ.js +23 -0
- package/dist/chunk-USUXRNVD.js +113 -0
- package/dist/{chunk-BFK6SOEJ.js → chunk-VIVMW2H2.js} +4 -4
- package/dist/{chunk-KTJGZ7M7.js → chunk-XBLSAVJF.js} +1 -1
- package/dist/chunk-ZYGKG6VC.js +22 -0
- package/dist/cli.js +51 -32
- package/dist/{cloud-sync-PPBBJDY6.js → cloud-sync-T7M3ESC3.js} +15 -12
- package/dist/connectors/discord-bridge.js +158 -0
- package/dist/connectors/slack-bridge.js +119 -0
- package/dist/connectors/telegram-bridge.js +133 -0
- package/dist/conversations-M2K4253F.js +55 -0
- package/dist/create-D7J73A6H.js +45 -0
- package/dist/{create-VDQJER52.js → create-QWV73WXD.js} +1 -1
- package/dist/{daemon-client-JOVQZ52X.js → daemon-client-I42FK2BF.js} +2 -2
- package/dist/{daemon-restart-FDNOZEAD.js → daemon-restart-M2QTYMEG.js} +7 -6
- package/dist/daemon.js +2247 -1085
- package/dist/db-IC4J52XQ.js +8 -0
- package/dist/{delete-2MRR4JX5.js → delete-4JYGD4VN.js} +1 -1
- package/dist/down-LVBXEULC.js +14 -0
- package/dist/{env-2FPOZK37.js → env-YJMUMFIY.js} +5 -5
- package/dist/{export-IKFAPRAO.js → export-BOJQWBMA.js} +4 -4
- package/dist/{file-KT3UIQM3.js → file-CR36YUPD.js} +4 -4
- package/dist/{history-46WZN5CN.js → history-XKRTAFS2.js} +7 -7
- package/dist/{import-TH26J76F.js → import-SRTQXBGH.js} +4 -4
- package/dist/join-J4QU42DL.js +66 -0
- package/dist/list-R73GENNL.js +40 -0
- package/dist/{log-6SGSSR3D.js → log-ABYNVYJ3.js} +4 -4
- package/dist/login-3QZNR2DF.js +46 -0
- package/dist/{login-UO6AOVEA.js → login-XX37I52P.js} +3 -3
- package/dist/logout-T53VKCPU.js +39 -0
- package/dist/{logout-UKD5LA37.js → logout-W4KOOBIT.js} +2 -2
- package/dist/{logs-HRBONI5I.js → logs-U35JR2KE.js} +7 -7
- package/dist/{merge-KSFJKX6T.js → merge-LNSMSAOF.js} +4 -4
- package/dist/message-delivery-LDXLGERA.js +25 -0
- package/dist/migrate-registry-to-db-XC7T5B7P.js +110 -0
- package/dist/{mind-YVWAHL2A.js → mind-DI33C74K.js} +25 -25
- package/dist/{mind-activity-tracker-NMDDEV3K.js → mind-activity-tracker-EN6XNXPF.js} +3 -4
- package/dist/{mind-manager-4NDNAYAB.js → mind-manager-M6EMUW5I.js} +6 -5
- package/dist/{mind-sleep-GHPTSAYN.js → mind-sleep-BTSWQNAC.js} +4 -4
- package/dist/{mind-wake-BJDJFMDF.js → mind-wake-SBAKIDVP.js} +4 -4
- package/dist/notes-XCER3I7M.js +220 -0
- package/dist/{package-3HF5MXU2.js → package-7WY6VKU3.js} +2 -1
- package/dist/{pages-Y6DRWUOJ.js → pages-6EBS6CBR.js} +2 -2
- package/dist/{publish-EEKTZBHW.js → publish-66UB2ZFY.js} +5 -5
- package/dist/{pull-D32SPFVU.js → pull-XCHJTM5M.js} +4 -4
- package/dist/read-36UFXN3G.js +46 -0
- package/dist/{register-U2UO6TC4.js → register-6B2CXTYM.js} +3 -3
- package/dist/{registry-D2BSQ2X5.js → registry-NDNOOYG4.js} +15 -9
- package/dist/{restart-5BMNV7KU.js → restart-6ESL3NBO.js} +6 -6
- package/dist/sandbox-TGBX22DS.js +19 -0
- package/dist/{schedule-YEFDLVMJ.js → schedule-QTJMFATP.js} +7 -7
- package/dist/{seed-6FEKB3YC.js → seed-SSUCYYDF.js} +2 -2
- package/dist/{send-IISDYFCL.js → send-ZNCJDSRP.js} +28 -36
- package/dist/service-6LIN3F3K.js +122 -0
- package/dist/setup-JG4QAEBV.js +371 -0
- package/dist/setup-JHL5ZEST.js +17 -0
- package/dist/{shared-LWMNTTZN.js → shared-ML5I4Q2A.js} +4 -4
- package/dist/{skill-T3EMR6IR.js → skill-AUAQTSP5.js} +7 -7
- package/dist/skills/dreaming/SKILL.md +68 -0
- package/dist/skills/dreaming/references/INSTALL.md +56 -0
- package/dist/skills/dreaming/scripts/dream.ts +289 -0
- package/dist/skills/dreaming/scripts/wake-context-dreams.sh +30 -0
- package/dist/skills/notes/SKILL.md +34 -0
- package/dist/skills/orientation/SKILL.md +3 -3
- package/dist/skills/volute-mind/SKILL.md +32 -30
- package/dist/sleep-manager-MWYHM5HV.js +29 -0
- package/dist/split-TKJ5OT3P.js +63 -0
- package/dist/{sprout-QJVGJDSH.js → sprout-IJVVKSJ2.js} +6 -7
- package/dist/{start-C7XITZ5O.js → start-EUJSS5R4.js} +4 -4
- package/dist/{status-SIRPLEZC.js → status-77YEPHMW.js} +5 -5
- package/dist/{status-LYS4NUOZ.js → status-7GA4SM4Y.js} +4 -4
- package/dist/{status-LV34BG6G.js → status-THLOBLWG.js} +2 -2
- package/dist/{stop-CVKBSLXY.js → stop-3XAITBBF.js} +6 -6
- package/dist/{tailscale-AJ4VL5XK.js → tailscale-NY5MUMY3.js} +1 -1
- package/dist/up-NKSMXBWR.js +17 -0
- package/dist/{update-7XCZMYBT.js → update-PTSH22AZ.js} +11 -11
- package/dist/{update-check-F5Z3ALXX.js → update-check-64FWC4Y2.js} +2 -2
- package/dist/{upgrade-7RUIXGOO.js → upgrade-HA47CS4C.js} +12 -5
- package/dist/variant-7TGZHOU3.js +41 -0
- package/dist/{version-notify-AZQMC32A.js → version-notify-5Z4MNR6M.js} +26 -28
- package/dist/web-assets/assets/index-CI5wgghI.css +1 -0
- package/dist/web-assets/assets/index-is5CvJWH.js +75 -0
- package/dist/web-assets/favicon.png +0 -0
- package/dist/web-assets/index.html +2 -2
- package/drizzle/0015_notes.sql +23 -0
- package/drizzle/0016_note_reactions_and_replies.sql +15 -0
- package/drizzle/0017_minds.sql +16 -0
- package/drizzle/meta/_journal.json +21 -0
- package/package.json +2 -1
- package/templates/_base/.init/.config/hooks/wake-context.sh +7 -0
- package/templates/_base/.init/.config/prompts.json +2 -2
- package/templates/_base/home/VOLUTE.md +5 -5
- package/templates/_base/src/lib/startup.ts +10 -2
- package/templates/claude/src/agent.ts +51 -1
- package/templates/claude/src/server.ts +1 -0
- package/templates/pi/package.json.tmpl +1 -0
- package/templates/pi/src/agent.ts +48 -1
- package/templates/pi/src/lib/subagents.ts +150 -0
- package/templates/pi/src/server.ts +1 -0
- package/dist/channel-HZOSHGNF.js +0 -260
- package/dist/chunk-33XAVCS4.js +0 -203
- package/dist/chunk-B2CPS4QU.js +0 -283
- package/dist/chunk-NWPT4ASZ.js +0 -89
- package/dist/chunk-SIAG3QMM.js +0 -42
- package/dist/chunk-WSLPZF72.js +0 -173
- package/dist/connector-M6XFI6GM.js +0 -147
- package/dist/connectors/discord.js +0 -177
- package/dist/connectors/slack.js +0 -181
- package/dist/connectors/telegram.js +0 -187
- package/dist/down-674SX2IZ.js +0 -14
- package/dist/message-delivery-XMGV3FUM.js +0 -23
- package/dist/service-FASYWLTC.js +0 -247
- package/dist/setup-BMLM2UTK.js +0 -230
- package/dist/sleep-manager-RKTFZPD3.js +0 -27
- package/dist/up-CJ26KQLN.js +0 -15
- package/dist/variant-UGREB4G5.js +0 -207
- package/dist/web-assets/assets/index-CGPSVu19.js +0 -69
- package/dist/web-assets/assets/index-V_rNDsM8.css +0 -1
package/dist/cli.js
CHANGED
|
@@ -9,64 +9,79 @@ if (!process.env.VOLUTE_HOME) {
|
|
|
9
9
|
var command = process.argv[2];
|
|
10
10
|
var args = process.argv.slice(3);
|
|
11
11
|
if (command === "--version" || command === "-v") {
|
|
12
|
-
const { default: pkg } = await import("./package-
|
|
12
|
+
const { default: pkg } = await import("./package-7WY6VKU3.js");
|
|
13
13
|
console.log(pkg.version);
|
|
14
14
|
process.exit(0);
|
|
15
15
|
}
|
|
16
|
+
var ungatedCommands = /* @__PURE__ */ new Set(["setup", "--help", "-h", "--version", "-v", "update", void 0]);
|
|
17
|
+
if (!ungatedCommands.has(command)) {
|
|
18
|
+
const { isSetupComplete, migrateSetupConfig } = await import("./setup-JHL5ZEST.js");
|
|
19
|
+
migrateSetupConfig();
|
|
20
|
+
if (!isSetupComplete()) {
|
|
21
|
+
console.error("Volute is not set up. Run `volute setup` first.");
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
16
25
|
switch (command) {
|
|
17
|
-
case "
|
|
18
|
-
await import("./
|
|
26
|
+
case "setup":
|
|
27
|
+
await import("./setup-JG4QAEBV.js").then((m) => m.run(args));
|
|
19
28
|
break;
|
|
20
|
-
case "
|
|
21
|
-
await import("./
|
|
29
|
+
case "mind":
|
|
30
|
+
await import("./mind-DI33C74K.js").then((m) => m.run(args));
|
|
22
31
|
break;
|
|
23
|
-
case "
|
|
24
|
-
await import("./
|
|
32
|
+
case "chat":
|
|
33
|
+
await import("./chat-MHJ3L6JQ.js").then((m) => m.run(args));
|
|
25
34
|
break;
|
|
26
35
|
case "variant":
|
|
27
|
-
await import("./variant-
|
|
28
|
-
break;
|
|
29
|
-
case "channel":
|
|
30
|
-
await import("./channel-HZOSHGNF.js").then((m) => m.run(args));
|
|
36
|
+
await import("./variant-7TGZHOU3.js").then((m) => m.run(args));
|
|
31
37
|
break;
|
|
32
38
|
case "schedule":
|
|
33
|
-
await import("./schedule-
|
|
39
|
+
await import("./schedule-QTJMFATP.js").then((m) => m.run(args));
|
|
34
40
|
break;
|
|
35
41
|
case "skill":
|
|
36
|
-
await import("./skill-
|
|
42
|
+
await import("./skill-AUAQTSP5.js").then((m) => m.run(args));
|
|
37
43
|
break;
|
|
38
44
|
case "shared":
|
|
39
|
-
await import("./shared-
|
|
45
|
+
await import("./shared-ML5I4Q2A.js").then((m) => m.run(args));
|
|
40
46
|
break;
|
|
41
47
|
case "file":
|
|
42
|
-
await import("./file-
|
|
48
|
+
await import("./file-CR36YUPD.js").then((m) => m.run(args));
|
|
43
49
|
break;
|
|
44
50
|
case "env":
|
|
45
|
-
await import("./env-
|
|
51
|
+
await import("./env-YJMUMFIY.js").then((m) => m.run(args));
|
|
46
52
|
break;
|
|
47
53
|
case "up":
|
|
48
|
-
await import("./up-
|
|
54
|
+
await import("./up-NKSMXBWR.js").then((m) => m.run(args));
|
|
49
55
|
break;
|
|
50
56
|
case "down":
|
|
51
|
-
await import("./down-
|
|
57
|
+
await import("./down-LVBXEULC.js").then((m) => m.run(args));
|
|
52
58
|
break;
|
|
53
59
|
case "restart":
|
|
54
|
-
await import("./daemon-restart-
|
|
60
|
+
await import("./daemon-restart-M2QTYMEG.js").then((m) => m.run(args));
|
|
55
61
|
break;
|
|
56
62
|
case "service":
|
|
57
|
-
await import("./service-
|
|
63
|
+
await import("./service-6LIN3F3K.js").then((m) => m.run(args));
|
|
58
64
|
break;
|
|
59
65
|
case "update":
|
|
60
|
-
await import("./update-
|
|
66
|
+
await import("./update-PTSH22AZ.js").then((m) => m.run(args));
|
|
61
67
|
break;
|
|
62
68
|
case "status":
|
|
63
|
-
await import("./status-
|
|
69
|
+
await import("./status-77YEPHMW.js").then((m) => m.run(args));
|
|
70
|
+
break;
|
|
71
|
+
case "notes":
|
|
72
|
+
await import("./notes-XCER3I7M.js").then((m) => m.run(args));
|
|
64
73
|
break;
|
|
65
74
|
case "pages":
|
|
66
|
-
await import("./pages-
|
|
75
|
+
await import("./pages-6EBS6CBR.js").then((m) => m.run(args));
|
|
67
76
|
break;
|
|
68
77
|
case "auth":
|
|
69
|
-
await import("./auth-
|
|
78
|
+
await import("./auth-D3OT2ARB.js").then((m) => m.run(args));
|
|
79
|
+
break;
|
|
80
|
+
case "login":
|
|
81
|
+
await import("./login-3QZNR2DF.js").then((m) => m.run(args));
|
|
82
|
+
break;
|
|
83
|
+
case "logout":
|
|
84
|
+
await import("./logout-T53VKCPU.js").then((m) => m.run(args));
|
|
70
85
|
break;
|
|
71
86
|
case "--help":
|
|
72
87
|
case "-h":
|
|
@@ -74,8 +89,10 @@ switch (command) {
|
|
|
74
89
|
console.log(`volute \u2014 create and manage AI minds
|
|
75
90
|
|
|
76
91
|
Common:
|
|
77
|
-
send <target> "<msg>"
|
|
78
|
-
history [--channel <ch>]
|
|
92
|
+
chat send <target> "<msg>" Send a message
|
|
93
|
+
chat history [--channel <ch>] View activity history
|
|
94
|
+
chat list / read / create Manage conversations
|
|
95
|
+
chat bridge Manage platform bridges
|
|
79
96
|
status Show system status
|
|
80
97
|
|
|
81
98
|
Mind:
|
|
@@ -84,25 +101,27 @@ Mind:
|
|
|
84
101
|
mind start/stop/restart [name] Control a mind
|
|
85
102
|
mind list List all minds
|
|
86
103
|
mind status [name] Check a mind's status
|
|
87
|
-
mind connect/disconnect <type> Manage connectors
|
|
88
104
|
mind logs [name] [--follow] Tail mind logs
|
|
89
105
|
mind sprout Complete orientation
|
|
106
|
+
mind split/join Create and merge experimental splits
|
|
90
107
|
mind upgrade/import/export Lifecycle operations
|
|
91
108
|
|
|
92
109
|
Configuration:
|
|
93
|
-
|
|
94
|
-
variant Create and merge experimental variants
|
|
110
|
+
chat Conversations, messages, and platform bridges
|
|
95
111
|
schedule Manage cron schedules
|
|
96
112
|
skill Browse and install skills
|
|
97
113
|
env Manage environment variables
|
|
98
114
|
file Mind-to-mind file sharing
|
|
99
115
|
shared Collaborative shared repository
|
|
116
|
+
notes Read and write notes
|
|
100
117
|
pages Publish web pages
|
|
101
118
|
|
|
102
119
|
System:
|
|
120
|
+
setup First-time setup
|
|
103
121
|
up / down / restart Daemon control
|
|
122
|
+
login / logout CLI authentication
|
|
104
123
|
update Update volute
|
|
105
|
-
service
|
|
124
|
+
service status Check service status
|
|
106
125
|
auth register/login/logout volute.systems account
|
|
107
126
|
|
|
108
127
|
Options:
|
|
@@ -111,7 +130,7 @@ Options:
|
|
|
111
130
|
|
|
112
131
|
Run 'volute <command> --help' for details.
|
|
113
132
|
|
|
114
|
-
Mind-scoped commands (
|
|
133
|
+
Mind-scoped commands (chat, schedule, file, skill, shared, pages)
|
|
115
134
|
use --mind <name> or VOLUTE_MIND env var to identify the mind.`);
|
|
116
135
|
break;
|
|
117
136
|
default:
|
|
@@ -120,7 +139,7 @@ Run 'volute --help' for usage.`);
|
|
|
120
139
|
process.exit(1);
|
|
121
140
|
}
|
|
122
141
|
if (command !== "update") {
|
|
123
|
-
import("./update-check-
|
|
142
|
+
import("./update-check-64FWC4Y2.js").then((m) => m.checkForUpdate()).then((result) => {
|
|
124
143
|
if (result.updateAvailable) {
|
|
125
144
|
console.error(`
|
|
126
145
|
Update available: ${result.current} \u2192 ${result.latest}`);
|
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
deliverMessage
|
|
3
|
+
deliverMessage
|
|
4
|
+
} from "./chunk-OQZH4PBB.js";
|
|
5
|
+
import "./chunk-KDGS53OS.js";
|
|
6
|
+
import "./chunk-K5NAC55T.js";
|
|
7
|
+
import "./chunk-PHSAT7YL.js";
|
|
8
|
+
import "./chunk-USUXRNVD.js";
|
|
9
|
+
import {
|
|
4
10
|
getAuthHeaders,
|
|
5
11
|
getWebhookUrl
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-BFK6SOEJ.js";
|
|
10
|
-
import "./chunk-SHSWYG2J.js";
|
|
11
|
-
import "./chunk-SIAG3QMM.js";
|
|
12
|
-
import "./chunk-PHU4DEAJ.js";
|
|
13
|
-
import "./chunk-33XAVCS4.js";
|
|
12
|
+
} from "./chunk-IAYBDWVG.js";
|
|
13
|
+
import "./chunk-VIVMW2H2.js";
|
|
14
|
+
import "./chunk-2WPW7OT6.js";
|
|
14
15
|
import {
|
|
15
16
|
logger_default
|
|
16
17
|
} from "./chunk-YUIHSKR6.js";
|
|
17
|
-
import "./chunk-
|
|
18
|
-
import "./chunk-
|
|
19
|
-
import "./chunk-
|
|
18
|
+
import "./chunk-AW7PFDVN.js";
|
|
19
|
+
import "./chunk-RKQEHRBB.js";
|
|
20
|
+
import "./chunk-IKRVFPWU.js";
|
|
21
|
+
import "./chunk-T6HKBWXZ.js";
|
|
22
|
+
import "./chunk-H7OZRFJB.js";
|
|
20
23
|
import "./chunk-K3NQKI34.js";
|
|
21
24
|
|
|
22
25
|
// src/lib/cloud-sync.ts
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
loadBridgeEnv,
|
|
4
|
+
onShutdown,
|
|
5
|
+
sendToBridge
|
|
6
|
+
} from "../chunk-KTLFDYPT.js";
|
|
7
|
+
import {
|
|
8
|
+
slugify
|
|
9
|
+
} from "../chunk-T6HKBWXZ.js";
|
|
10
|
+
import "../chunk-K3NQKI34.js";
|
|
11
|
+
|
|
12
|
+
// src/connectors/discord-bridge.ts
|
|
13
|
+
import { Client, Events, GatewayIntentBits, Partials } from "discord.js";
|
|
14
|
+
var env = loadBridgeEnv();
|
|
15
|
+
var token = process.env.DISCORD_TOKEN;
|
|
16
|
+
if (!token) {
|
|
17
|
+
console.error("Missing required env var: DISCORD_TOKEN");
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
var TYPING_INTERVAL_MS = 8e3;
|
|
21
|
+
var client = new Client({
|
|
22
|
+
intents: [
|
|
23
|
+
GatewayIntentBits.Guilds,
|
|
24
|
+
GatewayIntentBits.GuildMessages,
|
|
25
|
+
GatewayIntentBits.MessageContent,
|
|
26
|
+
GatewayIntentBits.DirectMessages,
|
|
27
|
+
GatewayIntentBits.GuildMessageTyping,
|
|
28
|
+
GatewayIntentBits.DirectMessageTyping
|
|
29
|
+
],
|
|
30
|
+
partials: [Partials.Channel]
|
|
31
|
+
});
|
|
32
|
+
onShutdown(() => {
|
|
33
|
+
client.destroy();
|
|
34
|
+
});
|
|
35
|
+
client.once(Events.ClientReady, (c) => {
|
|
36
|
+
console.log(`Discord bridge connected as ${c.user.tag}`);
|
|
37
|
+
});
|
|
38
|
+
client.on(Events.MessageCreate, async (message) => {
|
|
39
|
+
if (message.author.bot) return;
|
|
40
|
+
const isDM = !message.guild;
|
|
41
|
+
const content = [];
|
|
42
|
+
let text = message.content;
|
|
43
|
+
if (!isDM && message.mentions.has(client.user)) {
|
|
44
|
+
text = text.replace(new RegExp(`<@!?${client.user.id}>`, "g"), "").trim();
|
|
45
|
+
}
|
|
46
|
+
if (text) content.push({ type: "text", text });
|
|
47
|
+
for (const attachment of message.attachments.values()) {
|
|
48
|
+
if (!attachment.contentType?.startsWith("image/")) continue;
|
|
49
|
+
try {
|
|
50
|
+
const res = await fetch(attachment.url);
|
|
51
|
+
const buffer = Buffer.from(await res.arrayBuffer());
|
|
52
|
+
content.push({
|
|
53
|
+
type: "image",
|
|
54
|
+
media_type: attachment.contentType,
|
|
55
|
+
data: buffer.toString("base64")
|
|
56
|
+
});
|
|
57
|
+
} catch (err) {
|
|
58
|
+
console.error(`Failed to download attachment: ${err}`);
|
|
59
|
+
content.push({ type: "text", text: "[Image attachment could not be loaded]" });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (content.length === 0) return;
|
|
63
|
+
const displayName = message.author.displayName || message.author.username;
|
|
64
|
+
const platformUserId = message.author.username;
|
|
65
|
+
const channelName = !isDM && "name" in message.channel ? message.channel.name : void 0;
|
|
66
|
+
const externalChannel = isDM ? `@${slugify(message.author.username)}` : channelName && message.guild ? `${slugify(message.guild.name)}/${slugify(channelName)}` : message.channelId;
|
|
67
|
+
if (isDM) {
|
|
68
|
+
const channel = message.channel;
|
|
69
|
+
if ("sendTyping" in channel) {
|
|
70
|
+
const typingInterval = setInterval(() => {
|
|
71
|
+
channel.sendTyping().catch(() => {
|
|
72
|
+
});
|
|
73
|
+
}, TYPING_INTERVAL_MS);
|
|
74
|
+
channel.sendTyping().catch(() => {
|
|
75
|
+
});
|
|
76
|
+
try {
|
|
77
|
+
const result = await sendToBridge(env, {
|
|
78
|
+
content,
|
|
79
|
+
platformUserId,
|
|
80
|
+
displayName,
|
|
81
|
+
externalChannel,
|
|
82
|
+
isDM: true
|
|
83
|
+
});
|
|
84
|
+
if (!result.ok) {
|
|
85
|
+
message.reply(result.error ?? "Failed to process message").catch((err) => {
|
|
86
|
+
console.error(`Failed to send error reply: ${err}`);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
} finally {
|
|
90
|
+
clearInterval(typingInterval);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
const isMentioned = message.mentions.has(client.user);
|
|
95
|
+
if (isMentioned) {
|
|
96
|
+
const channel = message.channel;
|
|
97
|
+
if ("sendTyping" in channel) {
|
|
98
|
+
const typingInterval = setInterval(() => {
|
|
99
|
+
channel.sendTyping().catch(() => {
|
|
100
|
+
});
|
|
101
|
+
}, TYPING_INTERVAL_MS);
|
|
102
|
+
channel.sendTyping().catch(() => {
|
|
103
|
+
});
|
|
104
|
+
try {
|
|
105
|
+
const result = await sendToBridge(env, {
|
|
106
|
+
content,
|
|
107
|
+
platformUserId,
|
|
108
|
+
displayName,
|
|
109
|
+
externalChannel,
|
|
110
|
+
isDM: false
|
|
111
|
+
});
|
|
112
|
+
if (!result.ok) {
|
|
113
|
+
message.reply(result.error ?? "Failed to process message").catch((err) => {
|
|
114
|
+
console.error(`Failed to send error reply: ${err}`);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
} finally {
|
|
118
|
+
clearInterval(typingInterval);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
const result = await sendToBridge(env, {
|
|
123
|
+
content,
|
|
124
|
+
platformUserId,
|
|
125
|
+
displayName,
|
|
126
|
+
externalChannel,
|
|
127
|
+
isDM: false
|
|
128
|
+
});
|
|
129
|
+
if (!result.ok) {
|
|
130
|
+
message.reply(result.error ?? "Failed to process message").catch((err) => {
|
|
131
|
+
console.error(`Failed to send error reply: ${err}`);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
async function loginWithRetry() {
|
|
138
|
+
try {
|
|
139
|
+
await client.login(token);
|
|
140
|
+
} catch (err) {
|
|
141
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
142
|
+
const match = msg.match(/resets at (.+)/);
|
|
143
|
+
if (match) {
|
|
144
|
+
const resetAt = new Date(match[1]);
|
|
145
|
+
const waitMs = resetAt.getTime() - Date.now();
|
|
146
|
+
if (waitMs > 0) {
|
|
147
|
+
console.error(`Session limit hit, waiting until ${resetAt.toISOString()}...`);
|
|
148
|
+
await new Promise((r) => setTimeout(r, waitMs + 5e3));
|
|
149
|
+
return loginWithRetry();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
throw err;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
loginWithRetry().catch((err) => {
|
|
156
|
+
console.error("Failed to connect to Discord:", err);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
});
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
loadBridgeEnv,
|
|
4
|
+
onShutdown,
|
|
5
|
+
sendToBridge
|
|
6
|
+
} from "../chunk-KTLFDYPT.js";
|
|
7
|
+
import {
|
|
8
|
+
slugify
|
|
9
|
+
} from "../chunk-T6HKBWXZ.js";
|
|
10
|
+
import "../chunk-K3NQKI34.js";
|
|
11
|
+
|
|
12
|
+
// src/connectors/slack-bridge.ts
|
|
13
|
+
import { App } from "@slack/bolt";
|
|
14
|
+
var env = loadBridgeEnv();
|
|
15
|
+
var botToken = process.env.SLACK_BOT_TOKEN;
|
|
16
|
+
var appToken = process.env.SLACK_APP_TOKEN;
|
|
17
|
+
if (!botToken || !appToken) {
|
|
18
|
+
console.error("Missing required env vars: SLACK_BOT_TOKEN, SLACK_APP_TOKEN");
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
var app = new App({
|
|
22
|
+
token: botToken,
|
|
23
|
+
socketMode: true,
|
|
24
|
+
appToken
|
|
25
|
+
});
|
|
26
|
+
var botUserId;
|
|
27
|
+
var serverName;
|
|
28
|
+
app.message(async ({ message }) => {
|
|
29
|
+
if (message.subtype) return;
|
|
30
|
+
if (!("user" in message) || !("text" in message)) return;
|
|
31
|
+
if ("bot_id" in message && message.bot_id) return;
|
|
32
|
+
const isDM = message.channel_type === "im" || message.channel_type === "mpim";
|
|
33
|
+
let text = message.text ?? "";
|
|
34
|
+
if (!isDM && botUserId && text.includes(`<@${botUserId}>`)) {
|
|
35
|
+
text = text.replace(new RegExp(`<@${botUserId}>`, "g"), "").trim();
|
|
36
|
+
}
|
|
37
|
+
const content = [];
|
|
38
|
+
if (text) content.push({ type: "text", text });
|
|
39
|
+
if ("files" in message && message.files) {
|
|
40
|
+
for (const file of message.files) {
|
|
41
|
+
if (!file.mimetype?.startsWith("image/") || !file.url_private) continue;
|
|
42
|
+
try {
|
|
43
|
+
const res = await fetch(file.url_private, {
|
|
44
|
+
headers: { Authorization: `Bearer ${botToken}` }
|
|
45
|
+
});
|
|
46
|
+
if (!res.ok) {
|
|
47
|
+
console.warn(`Failed to download Slack file: HTTP ${res.status}`);
|
|
48
|
+
content.push({ type: "text", text: "[Image attachment could not be loaded]" });
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const buffer = Buffer.from(await res.arrayBuffer());
|
|
52
|
+
content.push({
|
|
53
|
+
type: "image",
|
|
54
|
+
media_type: file.mimetype,
|
|
55
|
+
data: buffer.toString("base64")
|
|
56
|
+
});
|
|
57
|
+
} catch (err) {
|
|
58
|
+
console.error(`Failed to download attachment: ${err}`);
|
|
59
|
+
content.push({ type: "text", text: "[Image attachment could not be loaded]" });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (content.length === 0) return;
|
|
64
|
+
let displayName = message.user;
|
|
65
|
+
let senderUsername = message.user;
|
|
66
|
+
try {
|
|
67
|
+
const userInfo = await app.client.users.info({
|
|
68
|
+
user: message.user
|
|
69
|
+
});
|
|
70
|
+
displayName = userInfo.user?.profile?.display_name || userInfo.user?.profile?.real_name || message.user;
|
|
71
|
+
senderUsername = userInfo.user?.name ?? message.user;
|
|
72
|
+
} catch (err) {
|
|
73
|
+
console.warn(`Failed to get user info: ${err}`);
|
|
74
|
+
}
|
|
75
|
+
let channelName;
|
|
76
|
+
if (!isDM) {
|
|
77
|
+
try {
|
|
78
|
+
const info = await app.client.conversations.info({
|
|
79
|
+
channel: message.channel
|
|
80
|
+
});
|
|
81
|
+
channelName = info.channel?.name;
|
|
82
|
+
} catch (err) {
|
|
83
|
+
console.warn(`Failed to get channel info: ${err}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const externalChannel = isDM ? `@${slugify(senderUsername)}` : channelName && serverName ? `${slugify(serverName)}/${slugify(channelName)}` : message.channel;
|
|
87
|
+
const result = await sendToBridge(env, {
|
|
88
|
+
content,
|
|
89
|
+
platformUserId: senderUsername,
|
|
90
|
+
displayName,
|
|
91
|
+
externalChannel,
|
|
92
|
+
isDM
|
|
93
|
+
});
|
|
94
|
+
if (!result.ok) {
|
|
95
|
+
app.client.chat.postMessage({
|
|
96
|
+
channel: message.channel,
|
|
97
|
+
text: result.error ?? "Failed to process message"
|
|
98
|
+
}).catch((err) => {
|
|
99
|
+
console.warn(`[slack-bridge] failed to send error reply: ${err}`);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
async function start() {
|
|
104
|
+
await app.start();
|
|
105
|
+
const auth = await app.client.auth.test();
|
|
106
|
+
if (!auth.user_id) {
|
|
107
|
+
throw new Error("auth.test succeeded but returned no user_id");
|
|
108
|
+
}
|
|
109
|
+
botUserId = auth.user_id;
|
|
110
|
+
serverName = auth.team;
|
|
111
|
+
console.log(`Slack bridge connected as ${botUserId}${serverName ? ` in ${serverName}` : ""}`);
|
|
112
|
+
}
|
|
113
|
+
onShutdown(async () => {
|
|
114
|
+
await app.stop();
|
|
115
|
+
});
|
|
116
|
+
start().catch((err) => {
|
|
117
|
+
console.error("Failed to start Slack bridge:", err);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
});
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
loadBridgeEnv,
|
|
4
|
+
onShutdown,
|
|
5
|
+
sendToBridge
|
|
6
|
+
} from "../chunk-KTLFDYPT.js";
|
|
7
|
+
import {
|
|
8
|
+
slugify
|
|
9
|
+
} from "../chunk-T6HKBWXZ.js";
|
|
10
|
+
import "../chunk-K3NQKI34.js";
|
|
11
|
+
|
|
12
|
+
// src/connectors/telegram-bridge.ts
|
|
13
|
+
import { Telegraf } from "telegraf";
|
|
14
|
+
import { message } from "telegraf/filters";
|
|
15
|
+
var env = loadBridgeEnv();
|
|
16
|
+
var botToken = process.env.TELEGRAM_BOT_TOKEN;
|
|
17
|
+
if (!botToken) {
|
|
18
|
+
console.error("Missing required env var: TELEGRAM_BOT_TOKEN");
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
var TYPING_INTERVAL_MS = 5e3;
|
|
22
|
+
var bot = new Telegraf(botToken);
|
|
23
|
+
bot.on(message("text"), async (ctx) => {
|
|
24
|
+
if (ctx.message.from.is_bot) return;
|
|
25
|
+
const isDM = ctx.chat.type === "private";
|
|
26
|
+
const botUsername = ctx.botInfo.username;
|
|
27
|
+
let text = ctx.message.text;
|
|
28
|
+
if (!isDM && botUsername) {
|
|
29
|
+
const isMentioned = ctx.message.entities?.some(
|
|
30
|
+
(e) => e.type === "mention" && ctx.message.text.substring(e.offset, e.offset + e.length) === `@${botUsername}`
|
|
31
|
+
);
|
|
32
|
+
if (isMentioned) {
|
|
33
|
+
text = text.replace(new RegExp(`@${botUsername}`, "g"), "").trim();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const content = [];
|
|
37
|
+
if (text) content.push({ type: "text", text });
|
|
38
|
+
if (content.length === 0) return;
|
|
39
|
+
const displayName = ctx.message.from.first_name + (ctx.message.from.last_name ? ` ${ctx.message.from.last_name}` : "");
|
|
40
|
+
const platformUserId = ctx.message.from.username ?? String(ctx.message.from.id);
|
|
41
|
+
const chatTitle = "title" in ctx.chat ? ctx.chat.title : void 0;
|
|
42
|
+
const externalChannel = isDM ? `@${slugify(platformUserId)}` : chatTitle ? slugify(chatTitle) : String(ctx.chat.id);
|
|
43
|
+
if (isDM) {
|
|
44
|
+
const typingInterval = setInterval(() => {
|
|
45
|
+
bot.telegram.sendChatAction(ctx.chat.id, "typing").catch(() => {
|
|
46
|
+
});
|
|
47
|
+
}, TYPING_INTERVAL_MS);
|
|
48
|
+
bot.telegram.sendChatAction(ctx.chat.id, "typing").catch(() => {
|
|
49
|
+
});
|
|
50
|
+
try {
|
|
51
|
+
const result = await sendToBridge(env, {
|
|
52
|
+
content,
|
|
53
|
+
platformUserId,
|
|
54
|
+
displayName,
|
|
55
|
+
externalChannel,
|
|
56
|
+
isDM: true
|
|
57
|
+
});
|
|
58
|
+
if (!result.ok) {
|
|
59
|
+
ctx.reply(result.error ?? "Failed to process message").catch((err) => {
|
|
60
|
+
console.error(`Failed to send error reply: ${err}`);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
} finally {
|
|
64
|
+
clearInterval(typingInterval);
|
|
65
|
+
}
|
|
66
|
+
} else {
|
|
67
|
+
const result = await sendToBridge(env, {
|
|
68
|
+
content,
|
|
69
|
+
platformUserId,
|
|
70
|
+
displayName,
|
|
71
|
+
externalChannel,
|
|
72
|
+
isDM: false
|
|
73
|
+
});
|
|
74
|
+
if (!result.ok) {
|
|
75
|
+
ctx.reply(result.error ?? "Failed to process message").catch((err) => {
|
|
76
|
+
console.error(`Failed to send error reply: ${err}`);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
bot.on(message("photo"), async (ctx) => {
|
|
82
|
+
if (ctx.message.from.is_bot) return;
|
|
83
|
+
const isDM = ctx.chat.type === "private";
|
|
84
|
+
const content = [];
|
|
85
|
+
const caption = ctx.message.caption;
|
|
86
|
+
if (caption) content.push({ type: "text", text: caption });
|
|
87
|
+
const photos = ctx.message.photo;
|
|
88
|
+
const largest = photos[photos.length - 1];
|
|
89
|
+
try {
|
|
90
|
+
const fileUrl = await ctx.telegram.getFileLink(largest.file_id);
|
|
91
|
+
const res = await fetch(fileUrl.href);
|
|
92
|
+
if (res.ok) {
|
|
93
|
+
const buffer = Buffer.from(await res.arrayBuffer());
|
|
94
|
+
content.push({
|
|
95
|
+
type: "image",
|
|
96
|
+
media_type: "image/jpeg",
|
|
97
|
+
data: buffer.toString("base64")
|
|
98
|
+
});
|
|
99
|
+
} else {
|
|
100
|
+
console.warn(`Failed to download Telegram photo: HTTP ${res.status}`);
|
|
101
|
+
content.push({ type: "text", text: "[Image attachment could not be loaded]" });
|
|
102
|
+
}
|
|
103
|
+
} catch (err) {
|
|
104
|
+
console.error(`Failed to download photo: ${err}`);
|
|
105
|
+
content.push({ type: "text", text: "[Image attachment could not be loaded]" });
|
|
106
|
+
}
|
|
107
|
+
if (content.length === 0) return;
|
|
108
|
+
const displayName = ctx.message.from.first_name + (ctx.message.from.last_name ? ` ${ctx.message.from.last_name}` : "");
|
|
109
|
+
const platformUserId = ctx.message.from.username ?? String(ctx.message.from.id);
|
|
110
|
+
const chatTitle = "title" in ctx.chat ? ctx.chat.title : void 0;
|
|
111
|
+
const externalChannel = isDM ? `@${slugify(platformUserId)}` : chatTitle ? slugify(chatTitle) : String(ctx.chat.id);
|
|
112
|
+
const result = await sendToBridge(env, {
|
|
113
|
+
content,
|
|
114
|
+
platformUserId,
|
|
115
|
+
displayName,
|
|
116
|
+
externalChannel,
|
|
117
|
+
isDM
|
|
118
|
+
});
|
|
119
|
+
if (!result.ok) {
|
|
120
|
+
ctx.reply(result.error ?? "Failed to process message").catch((err) => {
|
|
121
|
+
console.error(`Failed to send error reply: ${err}`);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
bot.launch().then(() => {
|
|
126
|
+
console.log(`Telegram bridge connected as @${bot.botInfo?.username}`);
|
|
127
|
+
}).catch((err) => {
|
|
128
|
+
console.error("Failed to start Telegram bridge:", err);
|
|
129
|
+
process.exit(1);
|
|
130
|
+
});
|
|
131
|
+
onShutdown(() => {
|
|
132
|
+
bot.stop("SIGTERM");
|
|
133
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
addMessage,
|
|
4
|
+
addParticipant,
|
|
5
|
+
createChannel,
|
|
6
|
+
createConversation,
|
|
7
|
+
deleteConversation,
|
|
8
|
+
deleteConversationForUser,
|
|
9
|
+
findDMConversation,
|
|
10
|
+
getChannelByName,
|
|
11
|
+
getConversation,
|
|
12
|
+
getMessages,
|
|
13
|
+
getMessagesPaginated,
|
|
14
|
+
getOrCreateConversation,
|
|
15
|
+
getParticipants,
|
|
16
|
+
getUnreadCounts,
|
|
17
|
+
isParticipant,
|
|
18
|
+
isParticipantOrOwner,
|
|
19
|
+
joinChannel,
|
|
20
|
+
leaveChannel,
|
|
21
|
+
listChannels,
|
|
22
|
+
listConversationsForUser,
|
|
23
|
+
listConversationsWithParticipants,
|
|
24
|
+
markConversationRead,
|
|
25
|
+
removeParticipant
|
|
26
|
+
} from "./chunk-IAYBDWVG.js";
|
|
27
|
+
import "./chunk-VIVMW2H2.js";
|
|
28
|
+
import "./chunk-YUIHSKR6.js";
|
|
29
|
+
import "./chunk-H7OZRFJB.js";
|
|
30
|
+
import "./chunk-K3NQKI34.js";
|
|
31
|
+
export {
|
|
32
|
+
addMessage,
|
|
33
|
+
addParticipant,
|
|
34
|
+
createChannel,
|
|
35
|
+
createConversation,
|
|
36
|
+
deleteConversation,
|
|
37
|
+
deleteConversationForUser,
|
|
38
|
+
findDMConversation,
|
|
39
|
+
getChannelByName,
|
|
40
|
+
getConversation,
|
|
41
|
+
getMessages,
|
|
42
|
+
getMessagesPaginated,
|
|
43
|
+
getOrCreateConversation,
|
|
44
|
+
getParticipants,
|
|
45
|
+
getUnreadCounts,
|
|
46
|
+
isParticipant,
|
|
47
|
+
isParticipantOrOwner,
|
|
48
|
+
joinChannel,
|
|
49
|
+
leaveChannel,
|
|
50
|
+
listChannels,
|
|
51
|
+
listConversationsForUser,
|
|
52
|
+
listConversationsWithParticipants,
|
|
53
|
+
markConversationRead,
|
|
54
|
+
removeParticipant
|
|
55
|
+
};
|