volute 0.26.0 → 0.28.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 (141) hide show
  1. package/README.md +18 -18
  2. package/dist/accept-666DIZX2.js +41 -0
  3. package/dist/{activity-events-ZMBAKLUF.js → activity-events-BBIEA2F4.js} +2 -3
  4. package/dist/api.d.ts +510 -299
  5. package/dist/{archive-4ZQYK5MN.js → archive-UA4BDFXQ.js} +2 -2
  6. package/dist/bridge-FQHZL3MC.js +206 -0
  7. package/dist/chat-M4SX42JD.js +68 -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-3CFRE2VC.js → chunk-AAPXKR5V.js} +435 -1090
  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-WBHMQ5OZ.js → chunk-H7OZRFJB.js} +192 -12
  14. package/dist/{chunk-ON3FF5JA.js → chunk-HDN7MNGD.js} +3 -3
  15. package/dist/chunk-IAYBDWVG.js +477 -0
  16. package/dist/{chunk-TZKJLDQN.js → chunk-IKRVFPWU.js} +14 -9
  17. package/dist/{chunk-UTL75LP6.js → chunk-J4IBNXGJ.js} +20 -22
  18. package/dist/{chunk-WGOGUMPO.js → chunk-JGFVMROS.js} +13 -6
  19. package/dist/{chunk-NWI2425I.js → chunk-K5NAC55T.js} +1 -1
  20. package/dist/chunk-KTLFDYPT.js +61 -0
  21. package/dist/{chunk-V63B7DX3.js → chunk-LAC664WU.js} +7 -4
  22. package/dist/chunk-MD4C26II.js +128 -0
  23. package/dist/{chunk-USNBKHYG.js → chunk-NI5FFCCS.js} +12 -7
  24. package/dist/{chunk-3TV4GLFO.js → chunk-P72MVS4R.js} +4 -43
  25. package/dist/{chunk-2VO7453N.js → chunk-POSXWWTA.js} +30 -54
  26. package/dist/{chunk-XOXLRRR2.js → chunk-RKQEHRBB.js} +4 -3
  27. package/dist/{chunk-LX22GRG7.js → chunk-SGVNFZHW.js} +11 -8
  28. package/dist/chunk-T6HKBWXZ.js +23 -0
  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 +32 -49
  32. package/dist/{cloud-sync-NI2K3C7G.js → cloud-sync-HDL6PHZI.js} +14 -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-G4B2OYAB.js} +7 -7
  41. package/dist/daemon.js +1889 -1216
  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/files-M546TKVN.js +46 -0
  48. package/dist/{history-B64GTFTD.js → history-ALPTNB3I.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/{login-B5E7N7MY.js → login-3QZNR2DF.js} +4 -4
  53. package/dist/{login-6U7U6BNG.js → login-BKP3AFWN.js} +8 -18
  54. package/dist/logout-IQK7FNEK.js +20 -0
  55. package/dist/{logout-XSJRYS3U.js → logout-T53VKCPU.js} +4 -4
  56. package/dist/message-delivery-HV3S6HZV.js +24 -0
  57. package/dist/migrate-registry-to-db-XC7T5B7P.js +110 -0
  58. package/dist/{mind-HZ3QSDDJ.js → mind-S5V6CK5W.js} +29 -34
  59. package/dist/{mind-activity-tracker-4G6FURY2.js → mind-activity-tracker-EN6XNXPF.js} +3 -4
  60. package/dist/mind-list-UPJ75GPI.js +29 -0
  61. package/dist/mind-manager-S6ILZVX3.js +18 -0
  62. package/dist/{mind-sleep-DTV7L44D.js → mind-sleep-BTSWQNAC.js} +4 -4
  63. package/dist/mind-status-TK5AETEM.js +55 -0
  64. package/dist/{mind-wake-PFN4FN3T.js → mind-wake-SBAKIDVP.js} +4 -4
  65. package/dist/{notes-37FW2UR2.js → notes-XCER3I7M.js} +11 -21
  66. package/dist/{package-VZWLXPHV.js → package-CG4RWUGP.js} +1 -1
  67. package/dist/{pages-DIIT5HMQ.js → pages-KJDJX4TA.js} +5 -5
  68. package/dist/{publish-HQV7YREB.js → publish-ZZB33WP4.js} +9 -20
  69. package/dist/read-36UFXN3G.js +46 -0
  70. package/dist/{register-EFND67FQ.js → register-CHREOMJ3.js} +6 -25
  71. package/dist/{registry-D2BSQ2X5.js → registry-NDNOOYG4.js} +15 -9
  72. package/dist/reject-LXIZFJ4Q.js +39 -0
  73. package/dist/{restart-CCK7D6TV.js → restart-6ESL3NBO.js} +5 -5
  74. package/dist/{sandbox-EHGFF52K.js → sandbox-5BW5HPXM.js} +3 -3
  75. package/dist/{schedule-6F7ELB2M.js → schedule-QTJMFATP.js} +5 -5
  76. package/dist/{seed-E5OQGWX3.js → seed-SSUCYYDF.js} +2 -2
  77. package/dist/{send-IH6XZKPC.js → send-TAOEZ4NH.js} +87 -23
  78. package/dist/{setup-YGAAIKKZ.js → setup-JHL5ZEST.js} +2 -2
  79. package/dist/{setup-F6TWFYGQ.js → setup-RXYVGGT7.js} +9 -9
  80. package/dist/{skill-42LGFBQC.js → skill-AUAQTSP5.js} +5 -5
  81. package/dist/skills/dreaming/references/INSTALL.md +2 -2
  82. package/dist/skills/orientation/SKILL.md +3 -3
  83. package/dist/skills/shared-files/SKILL.md +44 -0
  84. package/dist/skills/shared-files/scripts/merge.ts +72 -0
  85. package/dist/skills/shared-files/scripts/pull.ts +52 -0
  86. package/dist/skills/volute-mind/SKILL.md +35 -34
  87. package/dist/sleep-manager-WMVG2VCL.js +28 -0
  88. package/dist/split-TKJ5OT3P.js +63 -0
  89. package/dist/{sprout-QL74KR2X.js → sprout-UNT7LKKE.js} +6 -7
  90. package/dist/{start-O5JQASRC.js → start-EUJSS5R4.js} +2 -2
  91. package/dist/status-NQJYR4BG.js +114 -0
  92. package/dist/{status-LV34BG6G.js → status-S7UUPNRW.js} +4 -14
  93. package/dist/{stop-2SOG5NYF.js → stop-3XAITBBF.js} +5 -5
  94. package/dist/systems-SMEFSHTA.js +60 -0
  95. package/dist/{tailscale-AJ4VL5XK.js → tailscale-NY5MUMY3.js} +1 -1
  96. package/dist/up-GM2JOH2Y.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-JDUF4HQJ.js} +24 -29
  102. package/dist/web-assets/assets/index-BZGvToHi.css +1 -0
  103. package/dist/web-assets/assets/index-Cz4TrpzB.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/logger.ts +0 -4
  112. package/templates/_base/src/lib/startup.ts +2 -2
  113. package/dist/auth-4TV573WE.js +0 -37
  114. package/dist/channel-ZVZV42UD.js +0 -260
  115. package/dist/chunk-B2CPS4QU.js +0 -283
  116. package/dist/chunk-HFCBO2GL.js +0 -50
  117. package/dist/chunk-RWKVSSLY.js +0 -26
  118. package/dist/chunk-SIAG3QMM.js +0 -42
  119. package/dist/chunk-WSLPZF72.js +0 -173
  120. package/dist/connector-G722WXAU.js +0 -147
  121. package/dist/connectors/discord.js +0 -177
  122. package/dist/connectors/slack.js +0 -181
  123. package/dist/connectors/telegram.js +0 -187
  124. package/dist/down-7UKFMJJZ.js +0 -14
  125. package/dist/file-HUDKTRAS.js +0 -204
  126. package/dist/log-PBFNILJ4.js +0 -39
  127. package/dist/logout-UKD5LA37.js +0 -18
  128. package/dist/logs-3CART7O7.js +0 -77
  129. package/dist/merge-VK2HSKMA.js +0 -46
  130. package/dist/message-delivery-MS5JYPZX.js +0 -25
  131. package/dist/mind-manager-VVK67AY3.js +0 -19
  132. package/dist/pull-2MB4SK3C.js +0 -39
  133. package/dist/service-LLBV3R7M.js +0 -122
  134. package/dist/shared-UMO4S7CC.js +0 -39
  135. package/dist/sleep-manager-EE4NRN2Q.js +0 -29
  136. package/dist/status-FZBEBM7Q.js +0 -70
  137. package/dist/status-WXD4HXRL.js +0 -35
  138. package/dist/up-SDMCSVI3.js +0 -17
  139. package/dist/variant-WWLDY6D5.js +0 -207
  140. package/dist/web-assets/assets/index-CUQ31ieL.js +0 -69
  141. package/dist/web-assets/assets/index-CW8NSl1o.css +0 -1
@@ -5,8 +5,8 @@ import {
5
5
  extractArchive,
6
6
  isHomeOnlyArchive,
7
7
  readManifest
8
- } from "./chunk-KTJGZ7M7.js";
9
- import "./chunk-B2CPS4QU.js";
8
+ } from "./chunk-XBLSAVJF.js";
9
+ import "./chunk-H7OZRFJB.js";
10
10
  import "./chunk-K3NQKI34.js";
11
11
  export {
12
12
  addHistoryToArchive,
@@ -0,0 +1,206 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ daemonFetch
4
+ } from "./chunk-JGFVMROS.js";
5
+ import {
6
+ parseArgs
7
+ } from "./chunk-D424ZQGI.js";
8
+ import "./chunk-H7OZRFJB.js";
9
+ import "./chunk-K3NQKI34.js";
10
+
11
+ // src/commands/chat/bridge.ts
12
+ async function run(args) {
13
+ const subcommand = args[0];
14
+ const subArgs = args.slice(1);
15
+ switch (subcommand) {
16
+ case "add":
17
+ await bridgeAdd(subArgs);
18
+ break;
19
+ case "remove":
20
+ await bridgeRemove(subArgs);
21
+ break;
22
+ case "list":
23
+ await bridgeList();
24
+ break;
25
+ case "map":
26
+ await bridgeMap(subArgs);
27
+ break;
28
+ case "unmap":
29
+ await bridgeUnmap(subArgs);
30
+ break;
31
+ case "mappings":
32
+ await bridgeMappings(subArgs);
33
+ break;
34
+ case "--help":
35
+ case "-h":
36
+ case void 0:
37
+ console.log(`volute chat bridge \u2014 manage platform bridges
38
+
39
+ add <platform> Set up a bridge (e.g. discord, slack, telegram)
40
+ remove <platform> Remove a bridge
41
+ list Show bridges + status
42
+ map <platform>:<channel> <ch> Map external \u2192 Volute channel
43
+ unmap <platform>:<channel> Remove mapping
44
+ mappings [<platform>] List mappings`);
45
+ break;
46
+ default:
47
+ console.error(
48
+ `Unknown bridge subcommand: ${subcommand}
49
+ Run 'volute chat bridge --help' for usage.`
50
+ );
51
+ process.exit(1);
52
+ }
53
+ }
54
+ async function bridgeAdd(args) {
55
+ const { positional, flags } = parseArgs(args, {
56
+ "default-mind": { type: "string" }
57
+ });
58
+ const platform = positional[0];
59
+ if (!platform) {
60
+ console.error("Usage: volute chat bridge add <platform> --default-mind <name>");
61
+ process.exit(1);
62
+ }
63
+ const defaultMind = flags["default-mind"];
64
+ if (!defaultMind) {
65
+ console.error("--default-mind is required (mind to route DMs to)");
66
+ process.exit(1);
67
+ }
68
+ const res = await daemonFetch(`/api/bridges/${encodeURIComponent(platform)}`, {
69
+ method: "POST",
70
+ headers: { "Content-Type": "application/json" },
71
+ body: JSON.stringify({ defaultMind })
72
+ });
73
+ if (!res.ok) {
74
+ const data = await res.json().catch(() => ({}));
75
+ if (data.error === "missing_env" && data.missing) {
76
+ console.error(`Missing required environment variables:`);
77
+ for (const v of data.missing) {
78
+ console.error(` ${v.name} \u2014 ${v.description}`);
79
+ }
80
+ console.error(`
81
+ Set them with: volute env set <VAR> <value>`);
82
+ } else {
83
+ console.error(data.error ?? `Failed to add bridge: ${res.status}`);
84
+ }
85
+ process.exit(1);
86
+ }
87
+ console.log(`Bridge ${platform} enabled.`);
88
+ }
89
+ async function bridgeRemove(args) {
90
+ const platform = args[0];
91
+ if (!platform) {
92
+ console.error("Usage: volute chat bridge remove <platform>");
93
+ process.exit(1);
94
+ }
95
+ const res = await daemonFetch(`/api/bridges/${encodeURIComponent(platform)}`, {
96
+ method: "DELETE"
97
+ });
98
+ if (!res.ok) {
99
+ console.error(`Failed to remove bridge: ${res.status}`);
100
+ process.exit(1);
101
+ }
102
+ console.log(`Bridge ${platform} removed.`);
103
+ }
104
+ async function bridgeList() {
105
+ const res = await daemonFetch("/api/bridges");
106
+ if (!res.ok) {
107
+ console.error(`Failed to list bridges: ${res.status}`);
108
+ process.exit(1);
109
+ }
110
+ const bridges = await res.json();
111
+ if (bridges.length === 0) {
112
+ console.log("No bridges configured. Use 'volute chat bridge add <platform>' to set one up.");
113
+ return;
114
+ }
115
+ for (const b of bridges) {
116
+ const status = b.running ? "running" : b.enabled ? "stopped" : "disabled";
117
+ console.log(` ${b.displayName} (${b.platform}) ${status} default: ${b.defaultMind}`);
118
+ }
119
+ }
120
+ async function bridgeMap(args) {
121
+ const target = args[0];
122
+ const voluteChannel = args[1];
123
+ if (!target || !voluteChannel) {
124
+ console.error("Usage: volute chat bridge map <platform>:<channel> <volute-channel>");
125
+ process.exit(1);
126
+ }
127
+ const colonIdx = target.indexOf(":");
128
+ if (colonIdx < 1) {
129
+ console.error("Target must be in format platform:channel (e.g. discord:my-server/general)");
130
+ process.exit(1);
131
+ }
132
+ const platform = target.slice(0, colonIdx);
133
+ const externalChannel = target.slice(colonIdx + 1);
134
+ const res = await daemonFetch(`/api/bridges/${encodeURIComponent(platform)}/mappings`, {
135
+ method: "PUT",
136
+ headers: { "Content-Type": "application/json" },
137
+ body: JSON.stringify({ externalChannel, voluteChannel })
138
+ });
139
+ if (!res.ok) {
140
+ const data = await res.json().catch(() => ({}));
141
+ console.error(data.error ?? `Failed to set mapping: ${res.status}`);
142
+ process.exit(1);
143
+ }
144
+ console.log(`Mapped ${platform}:${externalChannel} \u2192 ${voluteChannel}`);
145
+ }
146
+ async function bridgeUnmap(args) {
147
+ const target = args[0];
148
+ if (!target) {
149
+ console.error("Usage: volute chat bridge unmap <platform>:<channel>");
150
+ process.exit(1);
151
+ }
152
+ const colonIdx = target.indexOf(":");
153
+ if (colonIdx < 1) {
154
+ console.error("Target must be in format platform:channel");
155
+ process.exit(1);
156
+ }
157
+ const platform = target.slice(0, colonIdx);
158
+ const externalChannel = target.slice(colonIdx + 1);
159
+ const res = await daemonFetch(
160
+ `/api/bridges/${encodeURIComponent(platform)}/mappings/${encodeURIComponent(externalChannel)}`,
161
+ { method: "DELETE" }
162
+ );
163
+ if (!res.ok) {
164
+ console.error(`Failed to remove mapping: ${res.status}`);
165
+ process.exit(1);
166
+ }
167
+ console.log(`Removed mapping for ${platform}:${externalChannel}`);
168
+ }
169
+ async function bridgeMappings(args) {
170
+ const platform = args[0];
171
+ if (platform) {
172
+ const res = await daemonFetch(`/api/bridges/${encodeURIComponent(platform)}/mappings`);
173
+ if (!res.ok) {
174
+ console.error(`Failed to get mappings: ${res.status}`);
175
+ process.exit(1);
176
+ }
177
+ const mappings = await res.json();
178
+ if (Object.keys(mappings).length === 0) {
179
+ console.log(`No mappings for ${platform}.`);
180
+ return;
181
+ }
182
+ for (const [external, volute] of Object.entries(mappings)) {
183
+ console.log(` ${platform}:${external} \u2192 ${volute}`);
184
+ }
185
+ } else {
186
+ const res = await daemonFetch("/api/bridges");
187
+ if (!res.ok) {
188
+ console.error(`Failed to list bridges: ${res.status}`);
189
+ process.exit(1);
190
+ }
191
+ const bridges = await res.json();
192
+ let found = false;
193
+ for (const b of bridges) {
194
+ for (const [external, volute] of Object.entries(b.channelMappings)) {
195
+ console.log(` ${b.platform}:${external} \u2192 ${volute}`);
196
+ found = true;
197
+ }
198
+ }
199
+ if (!found) {
200
+ console.log("No mappings configured.");
201
+ }
202
+ }
203
+ }
204
+ export {
205
+ run
206
+ };
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env node
2
+ import "./chunk-K3NQKI34.js";
3
+
4
+ // src/commands/chat.ts
5
+ async function run(args) {
6
+ const subcommand = args[0];
7
+ const subArgs = args.slice(1);
8
+ switch (subcommand) {
9
+ case "send":
10
+ await import("./send-TAOEZ4NH.js").then((m) => m.run(subArgs));
11
+ break;
12
+ case "list":
13
+ await import("./list-R73GENNL.js").then((m) => m.run(subArgs));
14
+ break;
15
+ case "read":
16
+ await import("./read-36UFXN3G.js").then((m) => m.run(subArgs));
17
+ break;
18
+ case "create":
19
+ await import("./create-D7J73A6H.js").then((m) => m.run(subArgs));
20
+ break;
21
+ case "bridge":
22
+ await import("./bridge-FQHZL3MC.js").then((m) => m.run(subArgs));
23
+ break;
24
+ case "files":
25
+ await import("./files-M546TKVN.js").then((m) => m.run(subArgs));
26
+ break;
27
+ case "accept":
28
+ await import("./accept-666DIZX2.js").then((m) => m.run(subArgs));
29
+ break;
30
+ case "reject":
31
+ await import("./reject-LXIZFJ4Q.js").then((m) => m.run(subArgs));
32
+ break;
33
+ case "--help":
34
+ case "-h":
35
+ case void 0:
36
+ console.log(`volute chat \u2014 conversations, files, and bridges
37
+
38
+ Messages:
39
+ send <target> "<msg>" Send a message (--image, --file)
40
+ list List conversations
41
+ read <conversation> [--limit] Read conversation messages
42
+ create --participants u1,u2 Create a conversation
43
+
44
+ Files:
45
+ files [--mind <name>] List pending incoming files
46
+ accept <id> [--mind] [--dest] Accept a pending file
47
+ reject <id> [--mind] Reject a pending file
48
+
49
+ Bridges:
50
+ bridge add <platform> Set up a bridge
51
+ bridge remove <platform> Remove a bridge
52
+ bridge list Show bridges + status
53
+ bridge map <p>:<ch> <volute> Map external \u2192 Volute channel
54
+ bridge unmap <p>:<ch> Remove mapping
55
+ bridge mappings [<platform>] List mappings
56
+
57
+ Send targets: @mindname for DMs, channel-name for conversations.
58
+ Mind-scoped commands use --mind <name> or VOLUTE_MIND env var.`);
59
+ break;
60
+ default:
61
+ console.error(`Unknown chat subcommand: ${subcommand}
62
+ Run 'volute chat --help' for usage.`);
63
+ process.exit(1);
64
+ }
65
+ }
66
+ export {
67
+ run
68
+ };
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  stateDir,
4
- voluteHome
5
- } from "./chunk-B2CPS4QU.js";
4
+ voluteSystemDir
5
+ } from "./chunk-H7OZRFJB.js";
6
6
 
7
7
  // src/lib/env.ts
8
8
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
9
9
  import { dirname, resolve } from "path";
10
10
  function sharedEnvPath() {
11
- return resolve(voluteHome(), "env.json");
11
+ return resolve(voluteSystemDir(), "env.json");
12
12
  }
13
13
  function mindEnvPath(mindName) {
14
14
  return resolve(stateDir(mindName), "env.json");
@@ -1,32 +1,105 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- readVoluteConfig,
4
- writeVoluteConfig
5
- } from "./chunk-SIAG3QMM.js";
6
- import {
7
- mindEnvPath,
8
3
  readEnv,
4
+ sharedEnvPath,
9
5
  writeEnv
10
- } from "./chunk-PHU4DEAJ.js";
6
+ } from "./chunk-2WPW7OT6.js";
7
+ import {
8
+ logger_default
9
+ } from "./chunk-YUIHSKR6.js";
11
10
  import {
12
11
  parseArgs
13
12
  } from "./chunk-D424ZQGI.js";
13
+ import {
14
+ voluteSystemDir
15
+ } from "./chunk-H7OZRFJB.js";
14
16
 
15
17
  // src/commands/import.ts
16
18
  import {
17
19
  closeSync,
18
- existsSync,
20
+ existsSync as existsSync2,
19
21
  mkdirSync,
20
22
  openSync,
21
23
  readdirSync,
22
- readFileSync,
24
+ readFileSync as readFileSync2,
23
25
  readSync,
24
26
  rmSync,
25
27
  statSync,
26
- writeFileSync
28
+ writeFileSync as writeFileSync2
27
29
  } from "fs";
28
30
  import { homedir, tmpdir } from "os";
29
- import { basename, resolve } from "path";
31
+ import { basename, resolve as resolve2 } from "path";
32
+
33
+ // src/lib/bridges.ts
34
+ import { existsSync, readFileSync, writeFileSync } from "fs";
35
+ import { resolve } from "path";
36
+ function bridgesPath() {
37
+ return resolve(voluteSystemDir(), "bridges.json");
38
+ }
39
+ function readBridgesConfig() {
40
+ const path = bridgesPath();
41
+ if (!existsSync(path)) return {};
42
+ try {
43
+ return JSON.parse(readFileSync(path, "utf-8"));
44
+ } catch (err) {
45
+ logger_default.error(
46
+ `bridges.json is corrupt or unreadable at ${path} \u2014 all bridges disabled`,
47
+ logger_default.errorData(err)
48
+ );
49
+ return {};
50
+ }
51
+ }
52
+ function writeBridgesConfig(config) {
53
+ writeFileSync(bridgesPath(), `${JSON.stringify(config, null, 2)}
54
+ `, { mode: 384 });
55
+ }
56
+ function getBridgeConfig(platform) {
57
+ const config = readBridgesConfig();
58
+ return config[platform] ?? null;
59
+ }
60
+ function setBridgeConfig(platform, bridge) {
61
+ const config = readBridgesConfig();
62
+ config[platform] = bridge;
63
+ writeBridgesConfig(config);
64
+ }
65
+ function removeBridgeConfig(platform) {
66
+ const config = readBridgesConfig();
67
+ delete config[platform];
68
+ writeBridgesConfig(config);
69
+ }
70
+ function setChannelMapping(platform, externalChannel, voluteChannel) {
71
+ const config = readBridgesConfig();
72
+ const bridge = config[platform];
73
+ if (!bridge) throw new Error(`Bridge not configured for ${platform}`);
74
+ bridge.channelMappings[externalChannel] = voluteChannel;
75
+ writeBridgesConfig(config);
76
+ }
77
+ function removeChannelMapping(platform, externalChannel) {
78
+ const config = readBridgesConfig();
79
+ const bridge = config[platform];
80
+ if (!bridge) return;
81
+ delete bridge.channelMappings[externalChannel];
82
+ writeBridgesConfig(config);
83
+ }
84
+ function resolveChannelMapping(platform, externalChannel) {
85
+ const bridge = getBridgeConfig(platform);
86
+ if (!bridge) return null;
87
+ return bridge.channelMappings[externalChannel] ?? null;
88
+ }
89
+ function findBridgeForChannel(voluteChannelName) {
90
+ const config = readBridgesConfig();
91
+ for (const [platform, bridge] of Object.entries(config)) {
92
+ if (!bridge.enabled) continue;
93
+ for (const [external, volute] of Object.entries(bridge.channelMappings)) {
94
+ if (volute === voluteChannelName) {
95
+ return { platform, externalChannel: external };
96
+ }
97
+ }
98
+ }
99
+ return null;
100
+ }
101
+
102
+ // src/commands/import.ts
30
103
  async function run(args) {
31
104
  const { positional, flags } = parseArgs(args, {
32
105
  name: { type: "string" },
@@ -35,11 +108,11 @@ async function run(args) {
35
108
  });
36
109
  const inputPath = positional[0];
37
110
  if (inputPath && (inputPath.endsWith(".volute") || isZipFile(inputPath))) {
38
- await importArchive(resolve(inputPath), flags.name);
111
+ await importArchive(resolve2(inputPath), flags.name);
39
112
  return;
40
113
  }
41
114
  const wsDir = resolveWorkspace(inputPath);
42
- const { daemonFetch } = await import("./daemon-client-Z7FAJ6JW.js");
115
+ const { daemonFetch } = await import("./daemon-client-I42FK2BF.js");
43
116
  const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
44
117
  const client = getClient();
45
118
  const res = await daemonFetch(urlOf(client.api.minds.import.$url()), {
@@ -63,8 +136,8 @@ ${data.message ?? `Imported mind: ${data.name} (port ${data.port})`}`);
63
136
  volute mind start ${data.name}`);
64
137
  }
65
138
  function isZipFile(path) {
66
- const resolved = resolve(path);
67
- if (!existsSync(resolved)) return false;
139
+ const resolved = resolve2(path);
140
+ if (!existsSync2(resolved)) return false;
68
141
  const fd = openSync(resolved, "r");
69
142
  try {
70
143
  const buf = Buffer.alloc(4);
@@ -75,12 +148,12 @@ function isZipFile(path) {
75
148
  }
76
149
  }
77
150
  async function importArchive(archivePath, nameOverride) {
78
- if (!existsSync(archivePath)) {
151
+ if (!existsSync2(archivePath)) {
79
152
  console.error(`File not found: ${archivePath}`);
80
153
  process.exit(1);
81
154
  }
82
- const { extractArchive } = await import("./archive-4ZQYK5MN.js");
83
- const tempDir = resolve(tmpdir(), `volute-import-${Date.now()}`);
155
+ const { extractArchive } = await import("./archive-UA4BDFXQ.js");
156
+ const tempDir = resolve2(tmpdir(), `volute-import-${Date.now()}`);
84
157
  mkdirSync(tempDir, { recursive: true });
85
158
  let extracted;
86
159
  try {
@@ -91,7 +164,7 @@ async function importArchive(archivePath, nameOverride) {
91
164
  process.exit(1);
92
165
  }
93
166
  try {
94
- const { daemonFetch } = await import("./daemon-client-Z7FAJ6JW.js");
167
+ const { daemonFetch } = await import("./daemon-client-I42FK2BF.js");
95
168
  const { getClient, urlOf } = await import("./api-client-YPKOZP2O.js");
96
169
  const client = getClient();
97
170
  const res = await daemonFetch(urlOf(client.api.minds.import.$url()), {
@@ -119,20 +192,20 @@ ${data.message ?? `Imported mind: ${data.name} (port ${data.port})`}`);
119
192
  }
120
193
  function resolveWorkspace(explicitPath) {
121
194
  if (explicitPath) {
122
- const wsDir = resolve(explicitPath);
123
- if (!existsSync(resolve(wsDir, "SOUL.md")) || !existsSync(resolve(wsDir, "IDENTITY.md"))) {
195
+ const wsDir = resolve2(explicitPath);
196
+ if (!existsSync2(resolve2(wsDir, "SOUL.md")) || !existsSync2(resolve2(wsDir, "IDENTITY.md"))) {
124
197
  console.error("Not a valid OpenClaw workspace: missing SOUL.md or IDENTITY.md");
125
198
  process.exit(1);
126
199
  }
127
200
  return wsDir;
128
201
  }
129
202
  const cwd = process.cwd();
130
- if (existsSync(resolve(cwd, "SOUL.md")) && existsSync(resolve(cwd, "IDENTITY.md"))) {
203
+ if (existsSync2(resolve2(cwd, "SOUL.md")) && existsSync2(resolve2(cwd, "IDENTITY.md"))) {
131
204
  console.log(`Using workspace: ${cwd}`);
132
205
  return cwd;
133
206
  }
134
- const openclawWs = resolve(homedir(), ".openclaw/workspace");
135
- if (existsSync(resolve(openclawWs, "SOUL.md")) && existsSync(resolve(openclawWs, "IDENTITY.md"))) {
207
+ const openclawWs = resolve2(homedir(), ".openclaw/workspace");
208
+ if (existsSync2(resolve2(openclawWs, "SOUL.md")) && existsSync2(resolve2(openclawWs, "IDENTITY.md"))) {
136
209
  console.log(`Using workspace: ${openclawWs}`);
137
210
  return openclawWs;
138
211
  }
@@ -142,16 +215,16 @@ function resolveWorkspace(explicitPath) {
142
215
  process.exit(1);
143
216
  }
144
217
  function findOpenClawSession(workspaceDir) {
145
- const ocAgentsDir = resolve(homedir(), ".openclaw/agents");
146
- if (!existsSync(ocAgentsDir)) return void 0;
218
+ const ocAgentsDir = resolve2(homedir(), ".openclaw/agents");
219
+ if (!existsSync2(ocAgentsDir)) return void 0;
147
220
  const matches = [];
148
221
  try {
149
222
  for (const entry of readdirSync(ocAgentsDir)) {
150
- const sessionsDir = resolve(ocAgentsDir, entry, "sessions");
151
- if (!existsSync(sessionsDir)) continue;
223
+ const sessionsDir = resolve2(ocAgentsDir, entry, "sessions");
224
+ if (!existsSync2(sessionsDir)) continue;
152
225
  for (const file of readdirSync(sessionsDir)) {
153
226
  if (!file.endsWith(".jsonl")) continue;
154
- const fullPath = resolve(sessionsDir, file);
227
+ const fullPath = resolve2(sessionsDir, file);
155
228
  if (sessionMatchesWorkspace(fullPath, workspaceDir)) {
156
229
  matches.push({ path: fullPath, mtime: statSync(fullPath).mtimeMs });
157
230
  }
@@ -168,19 +241,19 @@ function findOpenClawSession(workspaceDir) {
168
241
  }
169
242
  function sessionMatchesWorkspace(sessionPath, workspaceDir) {
170
243
  try {
171
- const fd = readFileSync(sessionPath, "utf-8");
244
+ const fd = readFileSync2(sessionPath, "utf-8");
172
245
  const firstLine = fd.slice(0, fd.indexOf("\n"));
173
246
  const header = JSON.parse(firstLine);
174
- return header.type === "session" && resolve(header.cwd) === resolve(workspaceDir);
247
+ return header.type === "session" && resolve2(header.cwd) === resolve2(workspaceDir);
175
248
  } catch {
176
249
  return false;
177
250
  }
178
251
  }
179
252
  function importPiSession(sessionFile, mindDirPath) {
180
- const homeDir = resolve(mindDirPath, "home");
181
- const piSessionDir = resolve(mindDirPath, ".mind/pi-sessions/main");
253
+ const homeDir = resolve2(mindDirPath, "home");
254
+ const piSessionDir = resolve2(mindDirPath, ".mind/pi-sessions/main");
182
255
  mkdirSync(piSessionDir, { recursive: true });
183
- const content = readFileSync(sessionFile, "utf-8");
256
+ const content = readFileSync2(sessionFile, "utf-8");
184
257
  const lines = content.trim().split("\n");
185
258
  try {
186
259
  const header = JSON.parse(lines[0]);
@@ -191,47 +264,48 @@ function importPiSession(sessionFile, mindDirPath) {
191
264
  } catch {
192
265
  }
193
266
  const filename = basename(sessionFile);
194
- const destPath = resolve(piSessionDir, filename);
195
- writeFileSync(destPath, `${lines.join("\n")}
267
+ const destPath = resolve2(piSessionDir, filename);
268
+ writeFileSync2(destPath, `${lines.join("\n")}
196
269
  `);
197
270
  console.log(`Imported session (${lines.length} entries)`);
198
271
  }
199
- function importOpenClawConnectors(name, mindDirPath) {
200
- const configPath = resolve(homedir(), ".openclaw/openclaw.json");
201
- if (!existsSync(configPath)) return;
272
+ function importOpenClawConnectors(name, _mindDirPath) {
273
+ const configPath = resolve2(homedir(), ".openclaw/openclaw.json");
274
+ if (!existsSync2(configPath)) return;
202
275
  let config;
203
276
  try {
204
- config = JSON.parse(readFileSync(configPath, "utf-8"));
277
+ config = JSON.parse(readFileSync2(configPath, "utf-8"));
205
278
  } catch (err) {
206
279
  console.warn("Warning: failed to parse openclaw.json:", err);
207
280
  return;
208
281
  }
209
282
  const discord = config.channels?.discord;
210
283
  if (!discord?.enabled || !discord.token) return;
211
- const envPath = mindEnvPath(name);
284
+ const envPath = sharedEnvPath();
212
285
  const env = readEnv(envPath);
213
- env.DISCORD_TOKEN = discord.token;
214
- writeEnv(envPath, env);
215
- const channelNames = /* @__PURE__ */ new Set();
286
+ if (!env.DISCORD_TOKEN) {
287
+ env.DISCORD_TOKEN = discord.token;
288
+ writeEnv(envPath, env);
289
+ }
290
+ const channelMappings = {};
216
291
  if (discord.guilds) {
217
292
  for (const guild of Object.values(discord.guilds)) {
218
293
  if (!guild.channels) continue;
219
- for (const [name2, ch] of Object.entries(guild.channels)) {
220
- if (ch.allow) channelNames.add(name2);
294
+ for (const [channelName, ch] of Object.entries(guild.channels)) {
295
+ if (ch.allow) {
296
+ channelMappings[channelName] = channelName;
297
+ }
221
298
  }
222
299
  }
223
300
  }
224
- const voluteConfig = readVoluteConfig(mindDirPath) ?? {};
225
- const connectors = new Set(voluteConfig.connectors ?? []);
226
- connectors.add("discord");
227
- voluteConfig.connectors = [...connectors];
228
- if (channelNames.size > 0) {
229
- voluteConfig.discord = { channels: [...channelNames] };
230
- }
231
- writeVoluteConfig(mindDirPath, voluteConfig);
232
- console.log("Imported Discord connector config");
233
- if (channelNames.size > 0) {
234
- console.log(`Imported followed channels: ${[...channelNames].join(", ")}`);
301
+ setBridgeConfig("discord", {
302
+ enabled: true,
303
+ defaultMind: name,
304
+ channelMappings
305
+ });
306
+ console.log(`Imported Discord as system bridge (default mind: ${name})`);
307
+ if (Object.keys(channelMappings).length > 0) {
308
+ console.log(`Mapped channels: ${Object.keys(channelMappings).join(", ")}`);
235
309
  }
236
310
  }
237
311
  function parseNameFromIdentity(identity) {
@@ -245,6 +319,14 @@ function parseNameFromIdentity(identity) {
245
319
  }
246
320
 
247
321
  export {
322
+ readBridgesConfig,
323
+ getBridgeConfig,
324
+ setBridgeConfig,
325
+ removeBridgeConfig,
326
+ setChannelMapping,
327
+ removeChannelMapping,
328
+ resolveChannelMapping,
329
+ findBridgeForChannel,
248
330
  run,
249
331
  findOpenClawSession,
250
332
  sessionMatchesWorkspace,