volute 0.26.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 (127) hide show
  1. package/README.md +13 -13
  2. package/dist/{activity-events-ZMBAKLUF.js → activity-events-BBIEA2F4.js} +2 -3
  3. package/dist/api.d.ts +363 -168
  4. package/dist/{archive-4ZQYK5MN.js → archive-UA4BDFXQ.js} +2 -2
  5. package/dist/{auth-4TV573WE.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-5Y3PBKW6.js → chunk-2YP2TVDT.js} +138 -56
  10. package/dist/{chunk-USNBKHYG.js → chunk-4WXYUOAK.js} +4 -6
  11. package/dist/{chunk-YJA7P64S.js → chunk-AW7PFDVN.js} +5 -5
  12. package/dist/{chunk-OZFKBXD6.js → chunk-EHYDTZTF.js} +6 -6
  13. package/dist/{chunk-LX22GRG7.js → chunk-GIE6CSN5.js} +11 -8
  14. package/dist/{chunk-WBHMQ5OZ.js → chunk-H7OZRFJB.js} +192 -12
  15. package/dist/{chunk-ON3FF5JA.js → chunk-HDN7MNGD.js} +3 -3
  16. package/dist/chunk-IAYBDWVG.js +477 -0
  17. package/dist/{chunk-TZKJLDQN.js → chunk-IKRVFPWU.js} +14 -9
  18. package/dist/{chunk-WGOGUMPO.js → chunk-JGFVMROS.js} +13 -6
  19. package/dist/{chunk-3TV4GLFO.js → chunk-JKOWNZ4P.js} +3 -3
  20. package/dist/{chunk-NWI2425I.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-V63B7DX3.js → chunk-LAC664WU.js} +7 -4
  24. package/dist/{chunk-3CFRE2VC.js → chunk-OQZH4PBB.js} +337 -1061
  25. package/dist/{chunk-2VO7453N.js → chunk-PHSAT7YL.js} +30 -54
  26. package/dist/{chunk-XOXLRRR2.js → chunk-RKQEHRBB.js} +4 -3
  27. package/dist/chunk-T6HKBWXZ.js +23 -0
  28. package/dist/{chunk-UTL75LP6.js → chunk-USUXRNVD.js} +22 -22
  29. package/dist/{chunk-J2CO4WEV.js → chunk-VIVMW2H2.js} +4 -4
  30. package/dist/{chunk-KTJGZ7M7.js → chunk-XBLSAVJF.js} +1 -1
  31. package/dist/cli.js +31 -36
  32. package/dist/{cloud-sync-NI2K3C7G.js → cloud-sync-T7M3ESC3.js} +15 -14
  33. package/dist/connectors/discord-bridge.js +158 -0
  34. package/dist/connectors/slack-bridge.js +119 -0
  35. package/dist/connectors/telegram-bridge.js +133 -0
  36. package/dist/conversations-M2K4253F.js +55 -0
  37. package/dist/create-D7J73A6H.js +45 -0
  38. package/dist/{create-4YBRTTJS.js → create-QWV73WXD.js} +1 -1
  39. package/dist/{daemon-client-Z7FAJ6JW.js → daemon-client-I42FK2BF.js} +2 -2
  40. package/dist/{daemon-restart-BJZ3O4U4.js → daemon-restart-M2QTYMEG.js} +7 -7
  41. package/dist/daemon.js +1758 -1024
  42. package/dist/db-IC4J52XQ.js +8 -0
  43. package/dist/{delete-27OYNK25.js → delete-4JYGD4VN.js} +1 -1
  44. package/dist/down-LVBXEULC.js +14 -0
  45. package/dist/{env-M336ONDP.js → env-YJMUMFIY.js} +2 -2
  46. package/dist/{export-HP4G5DQC.js → export-BOJQWBMA.js} +4 -4
  47. package/dist/{file-HUDKTRAS.js → file-CR36YUPD.js} +4 -4
  48. package/dist/{history-B64GTFTD.js → history-XKRTAFS2.js} +5 -5
  49. package/dist/{import-XIB7UV4S.js → import-SRTQXBGH.js} +4 -4
  50. package/dist/join-J4QU42DL.js +66 -0
  51. package/dist/list-R73GENNL.js +40 -0
  52. package/dist/{log-PBFNILJ4.js → log-ABYNVYJ3.js} +4 -4
  53. package/dist/{login-B5E7N7MY.js → login-3QZNR2DF.js} +4 -4
  54. package/dist/{login-6U7U6BNG.js → login-XX37I52P.js} +2 -2
  55. package/dist/{logout-XSJRYS3U.js → logout-T53VKCPU.js} +4 -4
  56. package/dist/{logout-UKD5LA37.js → logout-W4KOOBIT.js} +2 -2
  57. package/dist/{logs-3CART7O7.js → logs-U35JR2KE.js} +5 -5
  58. package/dist/{merge-VK2HSKMA.js → merge-LNSMSAOF.js} +4 -4
  59. package/dist/message-delivery-LDXLGERA.js +25 -0
  60. package/dist/migrate-registry-to-db-XC7T5B7P.js +110 -0
  61. package/dist/{mind-HZ3QSDDJ.js → mind-DI33C74K.js} +25 -25
  62. package/dist/{mind-activity-tracker-4G6FURY2.js → mind-activity-tracker-EN6XNXPF.js} +3 -4
  63. package/dist/mind-manager-M6EMUW5I.js +18 -0
  64. package/dist/{mind-sleep-DTV7L44D.js → mind-sleep-BTSWQNAC.js} +4 -4
  65. package/dist/{mind-wake-PFN4FN3T.js → mind-wake-SBAKIDVP.js} +4 -4
  66. package/dist/{notes-37FW2UR2.js → notes-XCER3I7M.js} +11 -21
  67. package/dist/{package-VZWLXPHV.js → package-7WY6VKU3.js} +1 -1
  68. package/dist/{pages-DIIT5HMQ.js → pages-6EBS6CBR.js} +2 -2
  69. package/dist/{publish-HQV7YREB.js → publish-66UB2ZFY.js} +5 -5
  70. package/dist/{pull-2MB4SK3C.js → pull-XCHJTM5M.js} +4 -4
  71. package/dist/read-36UFXN3G.js +46 -0
  72. package/dist/{register-EFND67FQ.js → register-6B2CXTYM.js} +2 -2
  73. package/dist/{registry-D2BSQ2X5.js → registry-NDNOOYG4.js} +15 -9
  74. package/dist/{restart-CCK7D6TV.js → restart-6ESL3NBO.js} +5 -5
  75. package/dist/{sandbox-EHGFF52K.js → sandbox-TGBX22DS.js} +3 -3
  76. package/dist/{schedule-6F7ELB2M.js → schedule-QTJMFATP.js} +5 -5
  77. package/dist/{seed-E5OQGWX3.js → seed-SSUCYYDF.js} +2 -2
  78. package/dist/{send-IH6XZKPC.js → send-ZNCJDSRP.js} +25 -19
  79. package/dist/{service-LLBV3R7M.js → service-6LIN3F3K.js} +4 -4
  80. package/dist/{setup-F6TWFYGQ.js → setup-JG4QAEBV.js} +12 -12
  81. package/dist/{setup-YGAAIKKZ.js → setup-JHL5ZEST.js} +2 -2
  82. package/dist/{shared-UMO4S7CC.js → shared-ML5I4Q2A.js} +4 -4
  83. package/dist/{skill-42LGFBQC.js → skill-AUAQTSP5.js} +5 -5
  84. package/dist/skills/dreaming/references/INSTALL.md +2 -2
  85. package/dist/skills/orientation/SKILL.md +3 -3
  86. package/dist/skills/volute-mind/SKILL.md +32 -30
  87. package/dist/sleep-manager-MWYHM5HV.js +29 -0
  88. package/dist/split-TKJ5OT3P.js +63 -0
  89. package/dist/{sprout-QL74KR2X.js → sprout-IJVVKSJ2.js} +6 -7
  90. package/dist/{start-O5JQASRC.js → start-EUJSS5R4.js} +2 -2
  91. package/dist/{status-FZBEBM7Q.js → status-77YEPHMW.js} +5 -5
  92. package/dist/{status-WXD4HXRL.js → status-7GA4SM4Y.js} +4 -4
  93. package/dist/{status-LV34BG6G.js → status-THLOBLWG.js} +2 -2
  94. package/dist/{stop-2SOG5NYF.js → stop-3XAITBBF.js} +5 -5
  95. package/dist/{tailscale-AJ4VL5XK.js → tailscale-NY5MUMY3.js} +1 -1
  96. package/dist/up-NKSMXBWR.js +17 -0
  97. package/dist/{update-5VUDAI3D.js → update-PTSH22AZ.js} +9 -9
  98. package/dist/{update-check-F5Z3ALXX.js → update-check-64FWC4Y2.js} +2 -2
  99. package/dist/{upgrade-QCCO33BK.js → upgrade-HA47CS4C.js} +12 -5
  100. package/dist/variant-7TGZHOU3.js +41 -0
  101. package/dist/{version-notify-USFZBWMG.js → version-notify-5Z4MNR6M.js} +26 -30
  102. package/dist/web-assets/assets/index-CI5wgghI.css +1 -0
  103. package/dist/web-assets/assets/index-is5CvJWH.js +75 -0
  104. package/dist/web-assets/favicon.png +0 -0
  105. package/dist/web-assets/index.html +2 -2
  106. package/drizzle/0017_minds.sql +16 -0
  107. package/drizzle/meta/_journal.json +7 -0
  108. package/package.json +1 -1
  109. package/templates/_base/.init/.config/prompts.json +2 -2
  110. package/templates/_base/home/VOLUTE.md +5 -5
  111. package/templates/_base/src/lib/startup.ts +2 -2
  112. package/dist/channel-ZVZV42UD.js +0 -260
  113. package/dist/chunk-B2CPS4QU.js +0 -283
  114. package/dist/chunk-SIAG3QMM.js +0 -42
  115. package/dist/chunk-WSLPZF72.js +0 -173
  116. package/dist/connector-G722WXAU.js +0 -147
  117. package/dist/connectors/discord.js +0 -177
  118. package/dist/connectors/slack.js +0 -181
  119. package/dist/connectors/telegram.js +0 -187
  120. package/dist/down-7UKFMJJZ.js +0 -14
  121. package/dist/message-delivery-MS5JYPZX.js +0 -25
  122. package/dist/mind-manager-VVK67AY3.js +0 -19
  123. package/dist/sleep-manager-EE4NRN2Q.js +0 -29
  124. package/dist/up-SDMCSVI3.js +0 -17
  125. package/dist/variant-WWLDY6D5.js +0 -207
  126. package/dist/web-assets/assets/index-CUQ31ieL.js +0 -69
  127. package/dist/web-assets/assets/index-CW8NSl1o.css +0 -1
@@ -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
+ };
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ resolveMindName
4
+ } from "./chunk-NAOW2CLO.js";
5
+ import {
6
+ daemonFetch
7
+ } from "./chunk-JGFVMROS.js";
8
+ import {
9
+ parseArgs
10
+ } from "./chunk-D424ZQGI.js";
11
+ import "./chunk-H7OZRFJB.js";
12
+ import "./chunk-K3NQKI34.js";
13
+
14
+ // src/commands/chat/create.ts
15
+ async function run(args) {
16
+ const { flags } = parseArgs(args, {
17
+ mind: { type: "string" },
18
+ participants: { type: "string" },
19
+ name: { type: "string" }
20
+ });
21
+ if (!flags.participants) {
22
+ console.error('Usage: volute chat create --participants u1,u2 [--name "..."] [--mind <name>]');
23
+ process.exit(1);
24
+ }
25
+ const mindName = resolveMindName(flags);
26
+ const participants = flags.participants.split(",").map((p) => p.trim());
27
+ const res = await daemonFetch(`/api/minds/${encodeURIComponent(mindName)}/conversations`, {
28
+ method: "POST",
29
+ headers: { "Content-Type": "application/json" },
30
+ body: JSON.stringify({
31
+ participantNames: participants,
32
+ title: flags.name
33
+ })
34
+ });
35
+ if (!res.ok) {
36
+ const data = await res.json().catch(() => ({}));
37
+ console.error(data.error ?? `Failed to create conversation: ${res.status}`);
38
+ process.exit(1);
39
+ }
40
+ const conv = await res.json();
41
+ console.log(`Created conversation: ${conv.id}`);
42
+ }
43
+ export {
44
+ run
45
+ };
@@ -17,7 +17,7 @@ async function run(args) {
17
17
  process.exit(1);
18
18
  }
19
19
  const skills = flags.skills === "none" ? [] : flags.skills ? flags.skills.split(",") : void 0;
20
- const { daemonFetch } = await import("./daemon-client-Z7FAJ6JW.js");
20
+ const { daemonFetch } = await import("./daemon-client-I42FK2BF.js");
21
21
  const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
22
22
  const client = getClient();
23
23
  const res = await daemonFetch(urlOf(client.api.minds.$url()), {
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  daemonFetch
4
- } from "./chunk-WGOGUMPO.js";
5
- import "./chunk-B2CPS4QU.js";
4
+ } from "./chunk-JGFVMROS.js";
5
+ import "./chunk-H7OZRFJB.js";
6
6
  import "./chunk-K3NQKI34.js";
7
7
  export {
8
8
  daemonFetch
@@ -1,22 +1,22 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  run
4
- } from "./chunk-LX22GRG7.js";
4
+ } from "./chunk-GIE6CSN5.js";
5
5
  import {
6
6
  stopDaemon
7
- } from "./chunk-OZFKBXD6.js";
7
+ } from "./chunk-EHYDTZTF.js";
8
8
  import {
9
9
  getServiceMode,
10
10
  modeLabel,
11
11
  pollHealth,
12
12
  readDaemonConfig,
13
13
  restartService
14
- } from "./chunk-V63B7DX3.js";
15
- import "./chunk-YJA7P64S.js";
16
- import "./chunk-XOXLRRR2.js";
14
+ } from "./chunk-LAC664WU.js";
15
+ import "./chunk-AW7PFDVN.js";
16
+ import "./chunk-RKQEHRBB.js";
17
+ import "./chunk-IKRVFPWU.js";
17
18
  import "./chunk-D424ZQGI.js";
18
- import "./chunk-TZKJLDQN.js";
19
- import "./chunk-B2CPS4QU.js";
19
+ import "./chunk-H7OZRFJB.js";
20
20
  import "./chunk-K3NQKI34.js";
21
21
 
22
22
  // src/commands/daemon-restart.ts