volute 0.4.0 → 0.6.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 +22 -22
- package/dist/agent-X7GJLBLW.js +79 -0
- package/dist/{agent-manager-AUCKMGPR.js → agent-manager-JDVXU3ON.js} +4 -4
- package/dist/channel-SMCNOIVQ.js +262 -0
- package/dist/chunk-AOKAQGO4.js +107 -0
- package/dist/{chunk-VRVVQIYY.js → chunk-AZEL2IEK.js} +1 -1
- package/dist/chunk-B3R6L2GW.js +24 -0
- package/dist/{chunk-MXUCNIBG.js → chunk-BX7KI4S3.js} +68 -3
- package/dist/{chunk-I6OHXCMV.js → chunk-G6ZNGLUX.js} +47 -9
- package/dist/{chunk-DNOXHLE5.js → chunk-H7AMDUIA.js} +1 -1
- package/dist/{chunk-YGFIWIOF.js → chunk-JR4UXCTO.js} +1 -1
- package/dist/{chunk-3C2XR4IY.js → chunk-UWHWAPGO.js} +120 -107
- package/dist/{chunk-SOZA2TLP.js → chunk-W76KWE23.js} +1 -1
- package/dist/{chunk-GSPKUPKU.js → chunk-XUA3JUFK.js} +2 -1
- package/dist/chunk-ZYGKG6VC.js +22 -0
- package/dist/chunk-ZZOOTYXK.js +583 -0
- package/dist/cli.js +83 -74
- package/dist/{connector-DKDJTLYZ.js → connector-Y7JPNROO.js} +11 -6
- package/dist/connectors/discord.js +34 -5
- package/dist/connectors/slack.js +36 -8
- package/dist/connectors/telegram.js +55 -6
- package/dist/create-G525LWEA.js +91 -0
- package/dist/{daemon-client-XR24PUJF.js → daemon-client-442IV43D.js} +2 -2
- package/dist/daemon.js +1273 -384
- package/dist/{delete-55MXCEY5.js → delete-2PH2CGDY.js} +7 -8
- package/dist/{down-3OB6UVAJ.js → down-FXWAN66A.js} +1 -1
- package/dist/{env-JB27UAC3.js → env-7GLUJCWS.js} +8 -5
- package/dist/{history-BKG74I43.js → history-H72ZUIBN.js} +3 -3
- package/dist/{import-4CI2ZUTJ.js → import-AVKQJDYC.js} +8 -8
- package/dist/{logs-NXFFGUKY.js → logs-EDGK26AK.js} +2 -2
- package/dist/message-SCOQDR3P.js +32 -0
- package/dist/{package-Z2SFO2SV.js → package-4DP4Y4UO.js} +1 -1
- package/dist/restart-O4ETYLJF.js +29 -0
- package/dist/{schedule-A35SH4HT.js → schedule-S6QVC5ON.js} +10 -5
- package/dist/send-G7PE4DOJ.js +72 -0
- package/dist/{setup-2FDVN7OF.js → setup-F4TCWVSP.js} +5 -5
- package/dist/{start-LDPMCMYT.js → start-VHQ7LNWM.js} +3 -3
- package/dist/{status-MVSQG54T.js → status-QAJWXKMZ.js} +3 -3
- package/dist/{stop-5PZTZCLL.js → stop-CAGCT5NI.js} +6 -7
- package/dist/{up-F7TMTLRE.js → up-CSX3ZUIU.js} +16 -4
- package/dist/update-XSIX3GGP.js +140 -0
- package/dist/update-check-5ZADDHCK.js +17 -0
- package/dist/{upgrade-6ZW2RD64.js → upgrade-YXKPWDRU.js} +16 -15
- package/dist/{variant-T64BKARF.js → variant-4Z6W3PP6.js} +15 -10
- package/dist/web-assets/assets/index-D5PzIndO.js +308 -0
- package/dist/web-assets/index.html +2 -2
- package/drizzle/0003_clean_ego.sql +12 -0
- package/drizzle/meta/0003_snapshot.json +417 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +1 -1
- package/templates/_base/.init/.config/hooks/startup-context.sh +19 -1
- package/templates/_base/.init/.config/scripts/session-reader.ts +59 -0
- package/templates/_base/_skills/sessions/SKILL.md +49 -0
- package/templates/_base/_skills/volute-agent/SKILL.md +114 -14
- package/templates/_base/home/.config/routes.json +10 -0
- package/templates/_base/home/VOLUTE.md +14 -35
- package/templates/_base/src/lib/format-prefix.ts +7 -1
- package/templates/_base/src/lib/router.ts +193 -19
- package/templates/_base/src/lib/routing.ts +55 -18
- package/templates/_base/src/lib/session-monitor.ts +400 -0
- package/templates/_base/src/lib/types.ts +5 -1
- package/templates/agent-sdk/.init/.config/routes.json +5 -0
- package/templates/agent-sdk/.init/CLAUDE.md +2 -2
- package/templates/agent-sdk/src/agent.ts +18 -1
- package/templates/agent-sdk/src/lib/hooks/session-context.ts +32 -0
- package/templates/agent-sdk/src/server.ts +8 -2
- package/templates/agent-sdk/volute-template.json +1 -1
- package/templates/pi/.init/.config/routes.json +5 -0
- package/templates/pi/.init/AGENTS.md +1 -1
- package/templates/pi/src/agent.ts +12 -4
- package/templates/pi/src/lib/session-context-extension.ts +33 -0
- package/templates/pi/src/server.ts +1 -1
- package/templates/pi/volute-template.json +1 -1
- package/dist/channel-DQ6UY7QB.js +0 -67
- package/dist/chunk-5OCWMTVS.js +0 -152
- package/dist/chunk-ZHCE4DPY.js +0 -110
- package/dist/create-ILVOG75A.js +0 -79
- package/dist/send-3U6OTKG7.js +0 -57
- package/dist/web-assets/assets/index-NS621maO.js +0 -296
- package/templates/agent-sdk/.init/.config/sessions.json +0 -4
- package/templates/pi/.init/.config/sessions.json +0 -1
- package/dist/{service-SA4TTMDU.js → service-HZNIDNJF.js} +3 -3
package/dist/cli.js
CHANGED
|
@@ -1,70 +1,54 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
+
import { homedir } from "os";
|
|
5
|
+
import { resolve } from "path";
|
|
6
|
+
if (!process.env.VOLUTE_HOME) {
|
|
7
|
+
process.env.VOLUTE_HOME = resolve(homedir(), ".volute");
|
|
8
|
+
}
|
|
4
9
|
var command = process.argv[2];
|
|
5
10
|
var args = process.argv.slice(3);
|
|
6
11
|
if (command === "--version" || command === "-v") {
|
|
7
|
-
const { default: pkg } = await import("./package-
|
|
12
|
+
const { default: pkg } = await import("./package-4DP4Y4UO.js");
|
|
8
13
|
console.log(pkg.version);
|
|
9
14
|
process.exit(0);
|
|
10
15
|
}
|
|
11
16
|
switch (command) {
|
|
12
|
-
case "
|
|
13
|
-
await import("./
|
|
14
|
-
break;
|
|
15
|
-
case "start":
|
|
16
|
-
await import("./start-LDPMCMYT.js").then((m) => m.run(args));
|
|
17
|
-
break;
|
|
18
|
-
case "stop":
|
|
19
|
-
await import("./stop-5PZTZCLL.js").then((m) => m.run(args));
|
|
20
|
-
break;
|
|
21
|
-
case "logs":
|
|
22
|
-
await import("./logs-NXFFGUKY.js").then((m) => m.run(args));
|
|
17
|
+
case "agent":
|
|
18
|
+
await import("./agent-X7GJLBLW.js").then((m) => m.run(args));
|
|
23
19
|
break;
|
|
24
|
-
case "
|
|
25
|
-
await import("./
|
|
20
|
+
case "message":
|
|
21
|
+
await import("./message-SCOQDR3P.js").then((m) => m.run(args));
|
|
26
22
|
break;
|
|
27
23
|
case "variant":
|
|
28
|
-
await import("./variant-
|
|
29
|
-
break;
|
|
30
|
-
case "send":
|
|
31
|
-
await import("./send-3U6OTKG7.js").then((m) => m.run(args));
|
|
32
|
-
break;
|
|
33
|
-
case "import":
|
|
34
|
-
await import("./import-4CI2ZUTJ.js").then((m) => m.run(args));
|
|
35
|
-
break;
|
|
36
|
-
case "delete":
|
|
37
|
-
await import("./delete-55MXCEY5.js").then((m) => m.run(args));
|
|
38
|
-
break;
|
|
39
|
-
case "env":
|
|
40
|
-
await import("./env-JB27UAC3.js").then((m) => m.run(args));
|
|
24
|
+
await import("./variant-4Z6W3PP6.js").then((m) => m.run(args));
|
|
41
25
|
break;
|
|
42
26
|
case "connector":
|
|
43
|
-
await import("./connector-
|
|
27
|
+
await import("./connector-Y7JPNROO.js").then((m) => m.run(args));
|
|
44
28
|
break;
|
|
45
29
|
case "channel":
|
|
46
|
-
await import("./channel-
|
|
30
|
+
await import("./channel-SMCNOIVQ.js").then((m) => m.run(args));
|
|
31
|
+
break;
|
|
32
|
+
case "schedule":
|
|
33
|
+
await import("./schedule-S6QVC5ON.js").then((m) => m.run(args));
|
|
47
34
|
break;
|
|
48
|
-
case "
|
|
49
|
-
await import("./
|
|
35
|
+
case "env":
|
|
36
|
+
await import("./env-7GLUJCWS.js").then((m) => m.run(args));
|
|
50
37
|
break;
|
|
51
38
|
case "up":
|
|
52
|
-
await import("./up-
|
|
39
|
+
await import("./up-CSX3ZUIU.js").then((m) => m.run(args));
|
|
53
40
|
break;
|
|
54
41
|
case "down":
|
|
55
|
-
await import("./down-
|
|
56
|
-
break;
|
|
57
|
-
case "schedule":
|
|
58
|
-
await import("./schedule-A35SH4HT.js").then((m) => m.run(args));
|
|
42
|
+
await import("./down-FXWAN66A.js").then((m) => m.run(args));
|
|
59
43
|
break;
|
|
60
|
-
case "
|
|
61
|
-
await import("./
|
|
44
|
+
case "setup":
|
|
45
|
+
await import("./setup-F4TCWVSP.js").then((m) => m.run(args));
|
|
62
46
|
break;
|
|
63
47
|
case "service":
|
|
64
|
-
await import("./service-
|
|
48
|
+
await import("./service-HZNIDNJF.js").then((m) => m.run(args));
|
|
65
49
|
break;
|
|
66
|
-
case "
|
|
67
|
-
await import("./
|
|
50
|
+
case "update":
|
|
51
|
+
await import("./update-XSIX3GGP.js").then((m) => m.run(args));
|
|
68
52
|
break;
|
|
69
53
|
case "--help":
|
|
70
54
|
case "-h":
|
|
@@ -72,45 +56,70 @@ switch (command) {
|
|
|
72
56
|
console.log(`volute \u2014 create and manage AI agents
|
|
73
57
|
|
|
74
58
|
Commands:
|
|
75
|
-
volute create <name>
|
|
76
|
-
volute start <name>
|
|
77
|
-
volute stop <name>
|
|
78
|
-
volute
|
|
79
|
-
volute
|
|
80
|
-
volute
|
|
81
|
-
volute
|
|
82
|
-
volute
|
|
83
|
-
volute
|
|
84
|
-
volute
|
|
85
|
-
|
|
86
|
-
volute
|
|
87
|
-
volute
|
|
88
|
-
|
|
89
|
-
volute
|
|
90
|
-
volute
|
|
91
|
-
volute
|
|
92
|
-
volute
|
|
93
|
-
|
|
94
|
-
volute
|
|
95
|
-
volute
|
|
96
|
-
|
|
97
|
-
volute
|
|
98
|
-
volute
|
|
99
|
-
volute
|
|
100
|
-
volute
|
|
101
|
-
volute
|
|
102
|
-
|
|
103
|
-
volute
|
|
59
|
+
volute agent create <name> Create a new agent
|
|
60
|
+
volute agent start <name> Start an agent (daemonized)
|
|
61
|
+
volute agent stop <name> Stop an agent
|
|
62
|
+
volute agent restart <name> Restart an agent
|
|
63
|
+
volute agent delete <name> [--force] Delete an agent (--force removes files)
|
|
64
|
+
volute agent list List all agents
|
|
65
|
+
volute agent status <name> Check agent status
|
|
66
|
+
volute agent logs <name> [--follow] Tail agent logs
|
|
67
|
+
volute agent upgrade <name> Upgrade agent to latest template
|
|
68
|
+
volute agent import <path> Import an OpenClaw workspace
|
|
69
|
+
|
|
70
|
+
volute message send <name> "<msg>" Send a message to an agent
|
|
71
|
+
volute message history [--agent <name>] View message history
|
|
72
|
+
|
|
73
|
+
volute variant create <name> Create a variant (worktree + server)
|
|
74
|
+
volute variant list List variants for an agent
|
|
75
|
+
volute variant merge <name> Merge a variant back
|
|
76
|
+
volute variant delete <name> Delete a variant
|
|
77
|
+
|
|
78
|
+
volute connector connect <type> Enable a connector for an agent
|
|
79
|
+
volute connector disconnect <type> Disable a connector for an agent
|
|
80
|
+
|
|
81
|
+
volute channel read <uri> Read recent messages from a channel
|
|
82
|
+
volute channel send <uri> "<msg>" Send a message to a channel
|
|
83
|
+
volute channel list [<platform>] List conversations on a platform
|
|
84
|
+
volute channel users <platform> List users on a platform
|
|
85
|
+
volute channel create <platform> ... Create a conversation on a platform
|
|
86
|
+
|
|
87
|
+
volute schedule list List schedules for an agent
|
|
88
|
+
volute schedule add ... Add a cron schedule
|
|
89
|
+
volute schedule remove ... Remove a schedule
|
|
90
|
+
|
|
91
|
+
volute env <set|get|list|remove> Manage environment variables
|
|
92
|
+
|
|
93
|
+
volute up [--port N] Start the daemon (default: 4200)
|
|
94
|
+
volute down Stop the daemon
|
|
95
|
+
|
|
96
|
+
volute service install [--port N] Install as system service (auto-start)
|
|
97
|
+
volute service uninstall Remove system service
|
|
98
|
+
volute service status Check service status
|
|
99
|
+
volute setup [--port N] [--host H] Install system service with user isolation
|
|
100
|
+
volute setup uninstall [--force] Remove system service + isolation
|
|
101
|
+
|
|
102
|
+
volute update Update to latest version
|
|
104
103
|
|
|
105
104
|
Options:
|
|
106
|
-
--version, -v
|
|
107
|
-
--help, -h
|
|
105
|
+
--version, -v Show version number
|
|
106
|
+
--help, -h Show this help message
|
|
108
107
|
|
|
109
|
-
Agent commands (variant, connector, schedule,
|
|
110
|
-
--agent <name> or VOLUTE_AGENT env var to identify the agent.`);
|
|
108
|
+
Agent-scoped commands (variant, connector, schedule, channel, message history)
|
|
109
|
+
use --agent <name> or VOLUTE_AGENT env var to identify the agent.`);
|
|
111
110
|
break;
|
|
112
111
|
default:
|
|
113
112
|
console.error(`Unknown command: ${command}
|
|
114
113
|
Run 'volute --help' for usage.`);
|
|
115
114
|
process.exit(1);
|
|
116
115
|
}
|
|
116
|
+
if (command !== "update") {
|
|
117
|
+
import("./update-check-5ZADDHCK.js").then((m) => m.checkForUpdate()).then((result) => {
|
|
118
|
+
if (result.updateAvailable) {
|
|
119
|
+
console.error(`
|
|
120
|
+
Update available: ${result.current} \u2192 ${result.latest}`);
|
|
121
|
+
console.error(" Run `volute update` to update\n");
|
|
122
|
+
}
|
|
123
|
+
}).catch(() => {
|
|
124
|
+
});
|
|
125
|
+
}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
resolveAgentName
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-AZEL2IEK.js";
|
|
5
5
|
import {
|
|
6
6
|
agentEnvPath,
|
|
7
7
|
readEnv,
|
|
8
8
|
writeEnv
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-H7AMDUIA.js";
|
|
10
10
|
import {
|
|
11
11
|
parseArgs
|
|
12
12
|
} from "./chunk-D424ZQGI.js";
|
|
13
13
|
import {
|
|
14
14
|
daemonFetch
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-JR4UXCTO.js";
|
|
16
16
|
import {
|
|
17
17
|
agentDir
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-UWHWAPGO.js";
|
|
19
19
|
import "./chunk-K3NQKI34.js";
|
|
20
20
|
|
|
21
21
|
// src/commands/connector.ts
|
|
@@ -28,13 +28,18 @@ async function run(args) {
|
|
|
28
28
|
case "disconnect":
|
|
29
29
|
await disconnectConnector(args.slice(1));
|
|
30
30
|
break;
|
|
31
|
+
case "--help":
|
|
32
|
+
case "-h":
|
|
33
|
+
case void 0:
|
|
34
|
+
printUsage();
|
|
35
|
+
break;
|
|
31
36
|
default:
|
|
32
37
|
printUsage();
|
|
33
|
-
process.exit(
|
|
38
|
+
process.exit(1);
|
|
34
39
|
}
|
|
35
40
|
}
|
|
36
41
|
function printUsage() {
|
|
37
|
-
console.
|
|
42
|
+
console.log(`Usage:
|
|
38
43
|
volute connector connect <type> [--agent <name>]
|
|
39
44
|
volute connector disconnect <type> [--agent <name>]`);
|
|
40
45
|
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
buildChannelSlug,
|
|
3
4
|
fireAndForget,
|
|
4
5
|
handleAgentMessage,
|
|
5
6
|
loadEnv,
|
|
6
7
|
loadFollowedChannels,
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
reportTyping,
|
|
9
|
+
slugify,
|
|
10
|
+
splitMessage,
|
|
11
|
+
writeChannelEntry
|
|
12
|
+
} from "../chunk-BX7KI4S3.js";
|
|
9
13
|
import "../chunk-K3NQKI34.js";
|
|
10
14
|
|
|
11
15
|
// src/connectors/discord.ts
|
|
@@ -32,7 +36,9 @@ var client = new Client({
|
|
|
32
36
|
GatewayIntentBits.Guilds,
|
|
33
37
|
GatewayIntentBits.GuildMessages,
|
|
34
38
|
GatewayIntentBits.MessageContent,
|
|
35
|
-
GatewayIntentBits.DirectMessages
|
|
39
|
+
GatewayIntentBits.DirectMessages,
|
|
40
|
+
GatewayIntentBits.GuildMessageTyping,
|
|
41
|
+
GatewayIntentBits.DirectMessageTyping
|
|
36
42
|
],
|
|
37
43
|
partials: [Partials.Channel]
|
|
38
44
|
});
|
|
@@ -88,8 +94,24 @@ client.on(Events.MessageCreate, async (message) => {
|
|
|
88
94
|
}
|
|
89
95
|
if (content.length === 0) return;
|
|
90
96
|
const senderName = message.author.displayName || message.author.username;
|
|
91
|
-
const channelKey = `discord:${message.channelId}`;
|
|
92
97
|
const channelName = !isDM && "name" in message.channel ? message.channel.name : void 0;
|
|
98
|
+
const channelKey = isDM ? buildChannelSlug("discord", {
|
|
99
|
+
isDM: true,
|
|
100
|
+
recipients: [message.author.username]
|
|
101
|
+
}) : buildChannelSlug("discord", {
|
|
102
|
+
channelName: channelName ?? message.channelId,
|
|
103
|
+
serverName: message.guild?.name
|
|
104
|
+
});
|
|
105
|
+
if (env.agentDir) {
|
|
106
|
+
writeChannelEntry(env.agentDir, channelKey, {
|
|
107
|
+
platformId: message.channelId,
|
|
108
|
+
platform: "discord",
|
|
109
|
+
name: channelName ? `#${channelName}` : void 0,
|
|
110
|
+
server: message.guild?.name,
|
|
111
|
+
type: isDM ? "dm" : "channel"
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
const participantCount = isDM ? 2 : message.guild?.memberCount;
|
|
93
115
|
const payload = {
|
|
94
116
|
content,
|
|
95
117
|
channel: channelKey,
|
|
@@ -97,7 +119,8 @@ client.on(Events.MessageCreate, async (message) => {
|
|
|
97
119
|
platform: "Discord",
|
|
98
120
|
...isDM ? { isDM: true } : {},
|
|
99
121
|
...channelName ? { channelName } : {},
|
|
100
|
-
...message.guild?.name ? {
|
|
122
|
+
...message.guild?.name ? { serverName: message.guild.name } : {},
|
|
123
|
+
...participantCount ? { participantCount } : {}
|
|
101
124
|
};
|
|
102
125
|
if (isFollowedChannel && !isMentioned) {
|
|
103
126
|
await fireAndForget(env, payload);
|
|
@@ -105,6 +128,12 @@ client.on(Events.MessageCreate, async (message) => {
|
|
|
105
128
|
}
|
|
106
129
|
await handleDiscordMessage(message, payload);
|
|
107
130
|
});
|
|
131
|
+
client.on(Events.TypingStart, (typing) => {
|
|
132
|
+
if (typing.user.bot) return;
|
|
133
|
+
const sender = typing.member?.displayName ?? typing.user.username ?? typing.user.id ?? "unknown";
|
|
134
|
+
const typingChannel = typing.guild ? `discord:${slugify(typing.guild.name)}/${slugify("name" in typing.channel ? String(typing.channel.name) : typing.channel.id)}` : `discord:@${slugify(typing.user.username ?? typing.user.id)}`;
|
|
135
|
+
reportTyping(env, typingChannel, sender, true);
|
|
136
|
+
});
|
|
108
137
|
async function handleDiscordMessage(message, payload) {
|
|
109
138
|
const channel = message.channel;
|
|
110
139
|
if (!("sendTyping" in channel)) return;
|
package/dist/connectors/slack.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
buildChannelSlug,
|
|
3
4
|
fireAndForget,
|
|
4
5
|
handleAgentMessage,
|
|
5
6
|
loadEnv,
|
|
6
7
|
loadFollowedChannels,
|
|
7
8
|
onShutdown,
|
|
8
|
-
splitMessage
|
|
9
|
-
|
|
9
|
+
splitMessage,
|
|
10
|
+
writeChannelEntry
|
|
11
|
+
} from "../chunk-BX7KI4S3.js";
|
|
10
12
|
import "../chunk-K3NQKI34.js";
|
|
11
13
|
|
|
12
14
|
// src/connectors/slack.ts
|
|
@@ -27,11 +29,12 @@ var app = new App({
|
|
|
27
29
|
appToken
|
|
28
30
|
});
|
|
29
31
|
var botUserId;
|
|
32
|
+
var serverName;
|
|
30
33
|
app.message(async ({ message, say }) => {
|
|
31
34
|
if (message.subtype) return;
|
|
32
35
|
if (!("user" in message) || !("text" in message)) return;
|
|
33
36
|
if ("bot_id" in message && message.bot_id) return;
|
|
34
|
-
const isDM = message.channel_type === "im";
|
|
37
|
+
const isDM = message.channel_type === "im" || message.channel_type === "mpim";
|
|
35
38
|
const isMentioned = !isDM && botUserId && message.text?.includes(`<@${botUserId}>`);
|
|
36
39
|
const isFollowedChannel = !isDM && followedChannelIds.has(message.channel);
|
|
37
40
|
if (!isDM && !isMentioned && !isFollowedChannel) return;
|
|
@@ -65,33 +68,55 @@ app.message(async ({ message, say }) => {
|
|
|
65
68
|
}
|
|
66
69
|
if (content.length === 0) return;
|
|
67
70
|
let channelName;
|
|
68
|
-
|
|
71
|
+
let numMembers;
|
|
72
|
+
if (message.channel_type !== "im") {
|
|
69
73
|
try {
|
|
70
74
|
const info = await app.client.conversations.info({
|
|
71
75
|
channel: message.channel
|
|
72
76
|
});
|
|
73
77
|
channelName = info.channel?.name;
|
|
78
|
+
numMembers = info.channel?.num_members;
|
|
74
79
|
} catch (err) {
|
|
75
|
-
console.warn(`Failed to get channel
|
|
80
|
+
console.warn(`Failed to get channel info: ${err}`);
|
|
76
81
|
}
|
|
77
82
|
}
|
|
78
83
|
let senderName = message.user;
|
|
84
|
+
let senderUsername = message.user;
|
|
79
85
|
try {
|
|
80
86
|
const userInfo = await app.client.users.info({
|
|
81
87
|
user: message.user
|
|
82
88
|
});
|
|
83
89
|
senderName = userInfo.user?.profile?.display_name || userInfo.user?.profile?.real_name || message.user;
|
|
90
|
+
senderUsername = userInfo.user?.name ?? message.user;
|
|
84
91
|
} catch (err) {
|
|
85
92
|
console.warn(`Failed to get user info: ${err}`);
|
|
86
93
|
}
|
|
87
|
-
const channelKey =
|
|
94
|
+
const channelKey = isDM ? buildChannelSlug("slack", {
|
|
95
|
+
isDM: true,
|
|
96
|
+
senderName: senderUsername
|
|
97
|
+
}) : buildChannelSlug("slack", {
|
|
98
|
+
channelName: channelName ?? message.channel,
|
|
99
|
+
serverName
|
|
100
|
+
});
|
|
101
|
+
if (env.agentDir) {
|
|
102
|
+
writeChannelEntry(env.agentDir, channelKey, {
|
|
103
|
+
platformId: message.channel,
|
|
104
|
+
platform: "slack",
|
|
105
|
+
name: channelName ? `#${channelName}` : void 0,
|
|
106
|
+
server: serverName,
|
|
107
|
+
type: isDM ? "dm" : "channel"
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
const participantCount = message.channel_type === "im" ? 2 : numMembers;
|
|
88
111
|
const payload = {
|
|
89
112
|
content,
|
|
90
113
|
channel: channelKey,
|
|
91
114
|
sender: senderName,
|
|
92
115
|
platform: "Slack",
|
|
93
116
|
...isDM ? { isDM: true } : {},
|
|
94
|
-
...channelName ? { channelName } : {}
|
|
117
|
+
...channelName ? { channelName } : {},
|
|
118
|
+
...serverName ? { serverName } : {},
|
|
119
|
+
...participantCount ? { participantCount } : {}
|
|
95
120
|
};
|
|
96
121
|
if (isFollowedChannel && !isMentioned) {
|
|
97
122
|
await fireAndForget(env, payload);
|
|
@@ -134,7 +159,10 @@ async function start() {
|
|
|
134
159
|
throw new Error("auth.test succeeded but returned no user_id");
|
|
135
160
|
}
|
|
136
161
|
botUserId = auth.user_id;
|
|
137
|
-
|
|
162
|
+
serverName = auth.team;
|
|
163
|
+
console.log(
|
|
164
|
+
`Connected to Slack as bot user ${botUserId}${serverName ? ` in ${serverName}` : ""}`
|
|
165
|
+
);
|
|
138
166
|
console.log(`Bridging to agent: ${env.agentName} via ${env.baseUrl}/message`);
|
|
139
167
|
if (followedChannelNames.length > 0) {
|
|
140
168
|
try {
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
buildChannelSlug,
|
|
3
4
|
fireAndForget,
|
|
4
5
|
handleAgentMessage,
|
|
5
6
|
loadEnv,
|
|
6
7
|
loadFollowedChannels,
|
|
7
|
-
splitMessage
|
|
8
|
-
|
|
8
|
+
splitMessage,
|
|
9
|
+
writeChannelEntry
|
|
10
|
+
} from "../chunk-BX7KI4S3.js";
|
|
9
11
|
import "../chunk-K3NQKI34.js";
|
|
10
12
|
|
|
11
13
|
// src/connectors/telegram.ts
|
|
@@ -40,13 +42,36 @@ bot.on(message("text"), async (ctx) => {
|
|
|
40
42
|
if (content.length === 0) return;
|
|
41
43
|
const senderName = ctx.message.from.first_name + (ctx.message.from.last_name ? ` ${ctx.message.from.last_name}` : "");
|
|
42
44
|
const chatTitle = "title" in ctx.chat ? ctx.chat.title : void 0;
|
|
45
|
+
let participantCount = isDM ? 2 : void 0;
|
|
46
|
+
if (!isDM) {
|
|
47
|
+
try {
|
|
48
|
+
participantCount = await ctx.telegram.getChatMembersCount(ctx.chat.id);
|
|
49
|
+
} catch (err) {
|
|
50
|
+
console.warn(`Failed to get member count for chat ${ctx.chat.id}: ${err}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const channelSlug = isDM ? buildChannelSlug("telegram", {
|
|
54
|
+
isDM: true,
|
|
55
|
+
senderName: ctx.message.from.username ?? ctx.message.from.first_name
|
|
56
|
+
}) : buildChannelSlug("telegram", {
|
|
57
|
+
channelName: chatTitle ?? String(ctx.chat.id)
|
|
58
|
+
});
|
|
59
|
+
if (env.agentDir) {
|
|
60
|
+
writeChannelEntry(env.agentDir, channelSlug, {
|
|
61
|
+
platformId: String(ctx.chat.id),
|
|
62
|
+
platform: "telegram",
|
|
63
|
+
name: chatTitle,
|
|
64
|
+
type: isDM ? "dm" : "channel"
|
|
65
|
+
});
|
|
66
|
+
}
|
|
43
67
|
const payload = {
|
|
44
68
|
content,
|
|
45
|
-
channel:
|
|
69
|
+
channel: channelSlug,
|
|
46
70
|
sender: senderName,
|
|
47
71
|
platform: "Telegram",
|
|
48
72
|
...isDM ? { isDM: true } : {},
|
|
49
|
-
...chatTitle ? { channelName: chatTitle } : {}
|
|
73
|
+
...chatTitle ? { channelName: chatTitle } : {},
|
|
74
|
+
...participantCount ? { participantCount } : {}
|
|
50
75
|
};
|
|
51
76
|
if (isFollowedChat && !isMentioned) {
|
|
52
77
|
await fireAndForget(env, payload);
|
|
@@ -88,12 +113,36 @@ bot.on(message("photo"), async (ctx) => {
|
|
|
88
113
|
if (content.length === 0) return;
|
|
89
114
|
const senderName = ctx.message.from.first_name + (ctx.message.from.last_name ? ` ${ctx.message.from.last_name}` : "");
|
|
90
115
|
const chatTitle = "title" in ctx.chat ? ctx.chat.title : void 0;
|
|
116
|
+
let participantCount = isDM ? 2 : void 0;
|
|
117
|
+
if (!isDM) {
|
|
118
|
+
try {
|
|
119
|
+
participantCount = await ctx.telegram.getChatMembersCount(ctx.chat.id);
|
|
120
|
+
} catch (err) {
|
|
121
|
+
console.warn(`Failed to get member count for chat ${ctx.chat.id}: ${err}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const channelSlug = isDM ? buildChannelSlug("telegram", {
|
|
125
|
+
isDM: true,
|
|
126
|
+
senderName: ctx.message.from.username ?? ctx.message.from.first_name
|
|
127
|
+
}) : buildChannelSlug("telegram", {
|
|
128
|
+
channelName: chatTitle ?? String(ctx.chat.id)
|
|
129
|
+
});
|
|
130
|
+
if (env.agentDir) {
|
|
131
|
+
writeChannelEntry(env.agentDir, channelSlug, {
|
|
132
|
+
platformId: String(ctx.chat.id),
|
|
133
|
+
platform: "telegram",
|
|
134
|
+
name: chatTitle,
|
|
135
|
+
type: isDM ? "dm" : "channel"
|
|
136
|
+
});
|
|
137
|
+
}
|
|
91
138
|
const payload = {
|
|
92
139
|
content,
|
|
93
|
-
channel:
|
|
140
|
+
channel: channelSlug,
|
|
94
141
|
sender: senderName,
|
|
95
142
|
platform: "Telegram",
|
|
96
|
-
...
|
|
143
|
+
...isDM ? { isDM: true } : {},
|
|
144
|
+
...chatTitle ? { channelName: chatTitle } : {},
|
|
145
|
+
...participantCount ? { participantCount } : {}
|
|
97
146
|
};
|
|
98
147
|
if (isFollowedChat) {
|
|
99
148
|
await fireAndForget(env, payload);
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
applyInitFiles,
|
|
4
|
+
composeTemplate,
|
|
5
|
+
copyTemplateToDir,
|
|
6
|
+
findTemplatesRoot,
|
|
7
|
+
listFiles
|
|
8
|
+
} from "./chunk-XUA3JUFK.js";
|
|
9
|
+
import {
|
|
10
|
+
parseArgs
|
|
11
|
+
} from "./chunk-D424ZQGI.js";
|
|
12
|
+
import {
|
|
13
|
+
chownAgentDir,
|
|
14
|
+
createAgentUser,
|
|
15
|
+
ensureVoluteGroup
|
|
16
|
+
} from "./chunk-W76KWE23.js";
|
|
17
|
+
import {
|
|
18
|
+
exec,
|
|
19
|
+
execInherit
|
|
20
|
+
} from "./chunk-5SKQ6J7T.js";
|
|
21
|
+
import {
|
|
22
|
+
addAgent,
|
|
23
|
+
agentDir,
|
|
24
|
+
ensureVoluteHome,
|
|
25
|
+
nextPort
|
|
26
|
+
} from "./chunk-UWHWAPGO.js";
|
|
27
|
+
import "./chunk-K3NQKI34.js";
|
|
28
|
+
|
|
29
|
+
// src/commands/create.ts
|
|
30
|
+
import { existsSync, rmSync } from "fs";
|
|
31
|
+
import { resolve } from "path";
|
|
32
|
+
var TEMPLATE_BRANCH = "volute/template";
|
|
33
|
+
async function run(args) {
|
|
34
|
+
const { positional, flags } = parseArgs(args, {
|
|
35
|
+
template: { type: "string" }
|
|
36
|
+
});
|
|
37
|
+
const name = positional[0];
|
|
38
|
+
const template = flags.template ?? "agent-sdk";
|
|
39
|
+
if (!name) {
|
|
40
|
+
console.error("Usage: volute agent create <name> [--template <name>]");
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
ensureVoluteHome();
|
|
44
|
+
const dest = agentDir(name);
|
|
45
|
+
if (existsSync(dest)) {
|
|
46
|
+
console.error(`Agent already exists: ${name}`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
const templatesRoot = findTemplatesRoot();
|
|
50
|
+
const { composedDir, manifest } = composeTemplate(templatesRoot, template);
|
|
51
|
+
try {
|
|
52
|
+
copyTemplateToDir(composedDir, dest, name, manifest);
|
|
53
|
+
applyInitFiles(dest);
|
|
54
|
+
const port = nextPort();
|
|
55
|
+
addAgent(name, port);
|
|
56
|
+
console.log("Installing dependencies...");
|
|
57
|
+
await execInherit("npm", ["install"], { cwd: dest });
|
|
58
|
+
try {
|
|
59
|
+
await exec("git", ["init"], { cwd: dest });
|
|
60
|
+
await initTemplateBranch(dest, composedDir, manifest);
|
|
61
|
+
} catch (err) {
|
|
62
|
+
rmSync(resolve(dest, ".git"), { recursive: true, force: true });
|
|
63
|
+
console.warn(
|
|
64
|
+
"\nWarning: git setup failed \u2014 variants and upgrades won't be available.",
|
|
65
|
+
"\nTo fix: ensure git is installed with user.name/user.email configured."
|
|
66
|
+
);
|
|
67
|
+
console.warn("Details:", err.message ?? err);
|
|
68
|
+
}
|
|
69
|
+
ensureVoluteGroup();
|
|
70
|
+
createAgentUser(name);
|
|
71
|
+
chownAgentDir(dest, name);
|
|
72
|
+
console.log(`
|
|
73
|
+
Created agent: ${name} (port ${port})`);
|
|
74
|
+
console.log(`
|
|
75
|
+
volute agent start ${name}`);
|
|
76
|
+
} finally {
|
|
77
|
+
rmSync(composedDir, { recursive: true, force: true });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async function initTemplateBranch(projectRoot, composedDir, manifest) {
|
|
81
|
+
const templateFiles = listFiles(composedDir).filter((f) => !f.startsWith(".init/") && !f.startsWith(".init\\")).map((f) => manifest.rename[f] ?? f);
|
|
82
|
+
await exec("git", ["checkout", "--orphan", TEMPLATE_BRANCH], { cwd: projectRoot });
|
|
83
|
+
await exec("git", ["add", "--", ...templateFiles], { cwd: projectRoot });
|
|
84
|
+
await exec("git", ["commit", "-m", "template update"], { cwd: projectRoot });
|
|
85
|
+
await exec("git", ["checkout", "-b", "main"], { cwd: projectRoot });
|
|
86
|
+
await exec("git", ["add", "-A"], { cwd: projectRoot });
|
|
87
|
+
await exec("git", ["commit", "-m", "initial commit"], { cwd: projectRoot });
|
|
88
|
+
}
|
|
89
|
+
export {
|
|
90
|
+
run
|
|
91
|
+
};
|