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.
Files changed (145) hide show
  1. package/README.md +28 -33
  2. package/dist/{activity-events-4O37J7PD.js → activity-events-BBIEA2F4.js} +2 -3
  3. package/dist/api.d.ts +886 -220
  4. package/dist/{archive-4ZQYK5MN.js → archive-UA4BDFXQ.js} +2 -2
  5. package/dist/{auth-HM2RSPY7.js → auth-D3OT2ARB.js} +3 -3
  6. package/dist/bridge-FQHZL3MC.js +206 -0
  7. package/dist/chat-MHJ3L6JQ.js +58 -0
  8. package/dist/{chunk-PHU4DEAJ.js → chunk-2WPW7OT6.js} +3 -3
  9. package/dist/{chunk-BOTQ25QT.js → chunk-2YP2TVDT.js} +138 -56
  10. package/dist/{chunk-DG7TO7EE.js → chunk-4WXYUOAK.js} +5 -7
  11. package/dist/{chunk-JTDFJWI2.js → chunk-AW7PFDVN.js} +5 -5
  12. package/dist/{chunk-2767L2RZ.js → chunk-EHYDTZTF.js} +6 -6
  13. package/dist/{chunk-ZSH4G2P5.js → chunk-GIE6CSN5.js} +17 -17
  14. package/dist/chunk-H7OZRFJB.js +432 -0
  15. package/dist/{chunk-ON3FF5JA.js → chunk-HDN7MNGD.js} +3 -3
  16. package/dist/chunk-IAYBDWVG.js +477 -0
  17. package/dist/chunk-IKRVFPWU.js +83 -0
  18. package/dist/{chunk-TRQEV3CD.js → chunk-JGFVMROS.js} +32 -6
  19. package/dist/{chunk-PHHKNGA3.js → chunk-JKOWNZ4P.js} +3 -3
  20. package/dist/{chunk-E7GOKNOT.js → chunk-K5NAC55T.js} +1 -1
  21. package/dist/{chunk-HFCBO2GL.js → chunk-KDGS53OS.js} +4 -4
  22. package/dist/chunk-KTLFDYPT.js +61 -0
  23. package/dist/{chunk-3AIBT4TW.js → chunk-LAC664WU.js} +30 -4
  24. package/dist/{chunk-PMX4EIJK.js → chunk-OQZH4PBB.js} +467 -1054
  25. package/dist/{chunk-SHSWYG2J.js → chunk-PHSAT7YL.js} +71 -58
  26. package/dist/chunk-RKQEHRBB.js +177 -0
  27. package/dist/{chunk-RVKR2R7F.js → chunk-SSI47XP2.js} +10 -2
  28. package/dist/chunk-T6HKBWXZ.js +23 -0
  29. package/dist/chunk-USUXRNVD.js +113 -0
  30. package/dist/{chunk-BFK6SOEJ.js → chunk-VIVMW2H2.js} +4 -4
  31. package/dist/{chunk-KTJGZ7M7.js → chunk-XBLSAVJF.js} +1 -1
  32. package/dist/chunk-ZYGKG6VC.js +22 -0
  33. package/dist/cli.js +51 -32
  34. package/dist/{cloud-sync-PPBBJDY6.js → cloud-sync-T7M3ESC3.js} +15 -12
  35. package/dist/connectors/discord-bridge.js +158 -0
  36. package/dist/connectors/slack-bridge.js +119 -0
  37. package/dist/connectors/telegram-bridge.js +133 -0
  38. package/dist/conversations-M2K4253F.js +55 -0
  39. package/dist/create-D7J73A6H.js +45 -0
  40. package/dist/{create-VDQJER52.js → create-QWV73WXD.js} +1 -1
  41. package/dist/{daemon-client-JOVQZ52X.js → daemon-client-I42FK2BF.js} +2 -2
  42. package/dist/{daemon-restart-FDNOZEAD.js → daemon-restart-M2QTYMEG.js} +7 -6
  43. package/dist/daemon.js +2247 -1085
  44. package/dist/db-IC4J52XQ.js +8 -0
  45. package/dist/{delete-2MRR4JX5.js → delete-4JYGD4VN.js} +1 -1
  46. package/dist/down-LVBXEULC.js +14 -0
  47. package/dist/{env-2FPOZK37.js → env-YJMUMFIY.js} +5 -5
  48. package/dist/{export-IKFAPRAO.js → export-BOJQWBMA.js} +4 -4
  49. package/dist/{file-KT3UIQM3.js → file-CR36YUPD.js} +4 -4
  50. package/dist/{history-46WZN5CN.js → history-XKRTAFS2.js} +7 -7
  51. package/dist/{import-TH26J76F.js → import-SRTQXBGH.js} +4 -4
  52. package/dist/join-J4QU42DL.js +66 -0
  53. package/dist/list-R73GENNL.js +40 -0
  54. package/dist/{log-6SGSSR3D.js → log-ABYNVYJ3.js} +4 -4
  55. package/dist/login-3QZNR2DF.js +46 -0
  56. package/dist/{login-UO6AOVEA.js → login-XX37I52P.js} +3 -3
  57. package/dist/logout-T53VKCPU.js +39 -0
  58. package/dist/{logout-UKD5LA37.js → logout-W4KOOBIT.js} +2 -2
  59. package/dist/{logs-HRBONI5I.js → logs-U35JR2KE.js} +7 -7
  60. package/dist/{merge-KSFJKX6T.js → merge-LNSMSAOF.js} +4 -4
  61. package/dist/message-delivery-LDXLGERA.js +25 -0
  62. package/dist/migrate-registry-to-db-XC7T5B7P.js +110 -0
  63. package/dist/{mind-YVWAHL2A.js → mind-DI33C74K.js} +25 -25
  64. package/dist/{mind-activity-tracker-NMDDEV3K.js → mind-activity-tracker-EN6XNXPF.js} +3 -4
  65. package/dist/{mind-manager-4NDNAYAB.js → mind-manager-M6EMUW5I.js} +6 -5
  66. package/dist/{mind-sleep-GHPTSAYN.js → mind-sleep-BTSWQNAC.js} +4 -4
  67. package/dist/{mind-wake-BJDJFMDF.js → mind-wake-SBAKIDVP.js} +4 -4
  68. package/dist/notes-XCER3I7M.js +220 -0
  69. package/dist/{package-3HF5MXU2.js → package-7WY6VKU3.js} +2 -1
  70. package/dist/{pages-Y6DRWUOJ.js → pages-6EBS6CBR.js} +2 -2
  71. package/dist/{publish-EEKTZBHW.js → publish-66UB2ZFY.js} +5 -5
  72. package/dist/{pull-D32SPFVU.js → pull-XCHJTM5M.js} +4 -4
  73. package/dist/read-36UFXN3G.js +46 -0
  74. package/dist/{register-U2UO6TC4.js → register-6B2CXTYM.js} +3 -3
  75. package/dist/{registry-D2BSQ2X5.js → registry-NDNOOYG4.js} +15 -9
  76. package/dist/{restart-5BMNV7KU.js → restart-6ESL3NBO.js} +6 -6
  77. package/dist/sandbox-TGBX22DS.js +19 -0
  78. package/dist/{schedule-YEFDLVMJ.js → schedule-QTJMFATP.js} +7 -7
  79. package/dist/{seed-6FEKB3YC.js → seed-SSUCYYDF.js} +2 -2
  80. package/dist/{send-IISDYFCL.js → send-ZNCJDSRP.js} +28 -36
  81. package/dist/service-6LIN3F3K.js +122 -0
  82. package/dist/setup-JG4QAEBV.js +371 -0
  83. package/dist/setup-JHL5ZEST.js +17 -0
  84. package/dist/{shared-LWMNTTZN.js → shared-ML5I4Q2A.js} +4 -4
  85. package/dist/{skill-T3EMR6IR.js → skill-AUAQTSP5.js} +7 -7
  86. package/dist/skills/dreaming/SKILL.md +68 -0
  87. package/dist/skills/dreaming/references/INSTALL.md +56 -0
  88. package/dist/skills/dreaming/scripts/dream.ts +289 -0
  89. package/dist/skills/dreaming/scripts/wake-context-dreams.sh +30 -0
  90. package/dist/skills/notes/SKILL.md +34 -0
  91. package/dist/skills/orientation/SKILL.md +3 -3
  92. package/dist/skills/volute-mind/SKILL.md +32 -30
  93. package/dist/sleep-manager-MWYHM5HV.js +29 -0
  94. package/dist/split-TKJ5OT3P.js +63 -0
  95. package/dist/{sprout-QJVGJDSH.js → sprout-IJVVKSJ2.js} +6 -7
  96. package/dist/{start-C7XITZ5O.js → start-EUJSS5R4.js} +4 -4
  97. package/dist/{status-SIRPLEZC.js → status-77YEPHMW.js} +5 -5
  98. package/dist/{status-LYS4NUOZ.js → status-7GA4SM4Y.js} +4 -4
  99. package/dist/{status-LV34BG6G.js → status-THLOBLWG.js} +2 -2
  100. package/dist/{stop-CVKBSLXY.js → stop-3XAITBBF.js} +6 -6
  101. package/dist/{tailscale-AJ4VL5XK.js → tailscale-NY5MUMY3.js} +1 -1
  102. package/dist/up-NKSMXBWR.js +17 -0
  103. package/dist/{update-7XCZMYBT.js → update-PTSH22AZ.js} +11 -11
  104. package/dist/{update-check-F5Z3ALXX.js → update-check-64FWC4Y2.js} +2 -2
  105. package/dist/{upgrade-7RUIXGOO.js → upgrade-HA47CS4C.js} +12 -5
  106. package/dist/variant-7TGZHOU3.js +41 -0
  107. package/dist/{version-notify-AZQMC32A.js → version-notify-5Z4MNR6M.js} +26 -28
  108. package/dist/web-assets/assets/index-CI5wgghI.css +1 -0
  109. package/dist/web-assets/assets/index-is5CvJWH.js +75 -0
  110. package/dist/web-assets/favicon.png +0 -0
  111. package/dist/web-assets/index.html +2 -2
  112. package/drizzle/0015_notes.sql +23 -0
  113. package/drizzle/0016_note_reactions_and_replies.sql +15 -0
  114. package/drizzle/0017_minds.sql +16 -0
  115. package/drizzle/meta/_journal.json +21 -0
  116. package/package.json +2 -1
  117. package/templates/_base/.init/.config/hooks/wake-context.sh +7 -0
  118. package/templates/_base/.init/.config/prompts.json +2 -2
  119. package/templates/_base/home/VOLUTE.md +5 -5
  120. package/templates/_base/src/lib/startup.ts +10 -2
  121. package/templates/claude/src/agent.ts +51 -1
  122. package/templates/claude/src/server.ts +1 -0
  123. package/templates/pi/package.json.tmpl +1 -0
  124. package/templates/pi/src/agent.ts +48 -1
  125. package/templates/pi/src/lib/subagents.ts +150 -0
  126. package/templates/pi/src/server.ts +1 -0
  127. package/dist/channel-HZOSHGNF.js +0 -260
  128. package/dist/chunk-33XAVCS4.js +0 -203
  129. package/dist/chunk-B2CPS4QU.js +0 -283
  130. package/dist/chunk-NWPT4ASZ.js +0 -89
  131. package/dist/chunk-SIAG3QMM.js +0 -42
  132. package/dist/chunk-WSLPZF72.js +0 -173
  133. package/dist/connector-M6XFI6GM.js +0 -147
  134. package/dist/connectors/discord.js +0 -177
  135. package/dist/connectors/slack.js +0 -181
  136. package/dist/connectors/telegram.js +0 -187
  137. package/dist/down-674SX2IZ.js +0 -14
  138. package/dist/message-delivery-XMGV3FUM.js +0 -23
  139. package/dist/service-FASYWLTC.js +0 -247
  140. package/dist/setup-BMLM2UTK.js +0 -230
  141. package/dist/sleep-manager-RKTFZPD3.js +0 -27
  142. package/dist/up-CJ26KQLN.js +0 -15
  143. package/dist/variant-UGREB4G5.js +0 -207
  144. package/dist/web-assets/assets/index-CGPSVu19.js +0 -69
  145. 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-3HF5MXU2.js");
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 "mind":
18
- await import("./mind-YVWAHL2A.js").then((m) => m.run(args));
26
+ case "setup":
27
+ await import("./setup-JG4QAEBV.js").then((m) => m.run(args));
19
28
  break;
20
- case "send":
21
- await import("./send-IISDYFCL.js").then((m) => m.run(args));
29
+ case "mind":
30
+ await import("./mind-DI33C74K.js").then((m) => m.run(args));
22
31
  break;
23
- case "history":
24
- await import("./history-46WZN5CN.js").then((m) => m.run(args));
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-UGREB4G5.js").then((m) => m.run(args));
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-YEFDLVMJ.js").then((m) => m.run(args));
39
+ await import("./schedule-QTJMFATP.js").then((m) => m.run(args));
34
40
  break;
35
41
  case "skill":
36
- await import("./skill-T3EMR6IR.js").then((m) => m.run(args));
42
+ await import("./skill-AUAQTSP5.js").then((m) => m.run(args));
37
43
  break;
38
44
  case "shared":
39
- await import("./shared-LWMNTTZN.js").then((m) => m.run(args));
45
+ await import("./shared-ML5I4Q2A.js").then((m) => m.run(args));
40
46
  break;
41
47
  case "file":
42
- await import("./file-KT3UIQM3.js").then((m) => m.run(args));
48
+ await import("./file-CR36YUPD.js").then((m) => m.run(args));
43
49
  break;
44
50
  case "env":
45
- await import("./env-2FPOZK37.js").then((m) => m.run(args));
51
+ await import("./env-YJMUMFIY.js").then((m) => m.run(args));
46
52
  break;
47
53
  case "up":
48
- await import("./up-CJ26KQLN.js").then((m) => m.run(args));
54
+ await import("./up-NKSMXBWR.js").then((m) => m.run(args));
49
55
  break;
50
56
  case "down":
51
- await import("./down-674SX2IZ.js").then((m) => m.run(args));
57
+ await import("./down-LVBXEULC.js").then((m) => m.run(args));
52
58
  break;
53
59
  case "restart":
54
- await import("./daemon-restart-FDNOZEAD.js").then((m) => m.run(args));
60
+ await import("./daemon-restart-M2QTYMEG.js").then((m) => m.run(args));
55
61
  break;
56
62
  case "service":
57
- await import("./service-FASYWLTC.js").then((m) => m.run(args));
63
+ await import("./service-6LIN3F3K.js").then((m) => m.run(args));
58
64
  break;
59
65
  case "update":
60
- await import("./update-7XCZMYBT.js").then((m) => m.run(args));
66
+ await import("./update-PTSH22AZ.js").then((m) => m.run(args));
61
67
  break;
62
68
  case "status":
63
- await import("./status-SIRPLEZC.js").then((m) => m.run(args));
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-Y6DRWUOJ.js").then((m) => m.run(args));
75
+ await import("./pages-6EBS6CBR.js").then((m) => m.run(args));
67
76
  break;
68
77
  case "auth":
69
- await import("./auth-HM2RSPY7.js").then((m) => m.run(args));
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>" Send a message
78
- history [--channel <ch>] View activity history
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
- channel Read, list, and manage channels
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 install/uninstall Auto-start 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 (send, history, variant, schedule, channel, file, skill, shared, pages)
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-F5Z3ALXX.js").then((m) => m.checkForUpdate()).then((result) => {
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-PMX4EIJK.js";
7
- import "./chunk-HFCBO2GL.js";
8
- import "./chunk-E7GOKNOT.js";
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-JTDFJWI2.js";
18
- import "./chunk-NWPT4ASZ.js";
19
- import "./chunk-B2CPS4QU.js";
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
+ };