comfy-qa 1.24.0 → 1.25.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/bot/cli.ts +145 -0
- package/package.json +3 -2
package/bot/cli.ts
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* qabot slack CLI — interact with Slack using Bot Token
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* qabot slack channels # list channels
|
|
7
|
+
* qabot slack history #channel 10 # show recent messages
|
|
8
|
+
* qabot slack send #channel "msg" # send a message
|
|
9
|
+
* qabot slack search "query" # search messages (needs xoxp token)
|
|
10
|
+
* qabot slack user U12345 # lookup user name
|
|
11
|
+
*
|
|
12
|
+
* Uses SLACK_BOT_TOKEN from .env.local (auto-loaded by Bun)
|
|
13
|
+
* For search: also needs SLACK_MCP_XOXP_TOKEN (User OAuth Token)
|
|
14
|
+
* Or: @snomiao/slack-cli via SLACK_MCP_XOXP_TOKEN for native search
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { WebClient } from "@slack/web-api";
|
|
18
|
+
|
|
19
|
+
const token = process.env.SLACK_BOT_TOKEN;
|
|
20
|
+
if (!token) {
|
|
21
|
+
console.error("SLACK_BOT_TOKEN not set in .env.local");
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const client = new WebClient(token);
|
|
26
|
+
const [subcmd, ...args] = process.argv.slice(2);
|
|
27
|
+
|
|
28
|
+
if (!subcmd || subcmd === "help" || subcmd === "--help") {
|
|
29
|
+
console.log(`qabot slack <command> [args]
|
|
30
|
+
|
|
31
|
+
Commands:
|
|
32
|
+
channels List public channels
|
|
33
|
+
history <channel> [limit] Show recent messages (default 10)
|
|
34
|
+
send <channel> <text> [ts] Send a message (optionally in thread)
|
|
35
|
+
search <query> Search messages (needs User Token)
|
|
36
|
+
replies <channel> <ts> Get thread replies
|
|
37
|
+
user <userId> Look up user display name
|
|
38
|
+
help Show this help
|
|
39
|
+
|
|
40
|
+
Channel: use #name or C... ID`);
|
|
41
|
+
process.exit(0);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function resolveChannel(ref: string): Promise<string> {
|
|
45
|
+
if (ref.startsWith("C") || ref.startsWith("D")) return ref;
|
|
46
|
+
const name = ref.replace(/^#/, "");
|
|
47
|
+
const resp = await client.conversations.list({ types: "public_channel,private_channel", limit: 200 });
|
|
48
|
+
const ch = resp.channels?.find((c) => c.name === name);
|
|
49
|
+
if (ch?.id) return ch.id;
|
|
50
|
+
throw new Error(`Channel "${ref}" not found`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function main() {
|
|
54
|
+
try {
|
|
55
|
+
switch (subcmd) {
|
|
56
|
+
case "channels":
|
|
57
|
+
case "list": {
|
|
58
|
+
const resp = await client.conversations.list({ types: "public_channel", limit: 100 });
|
|
59
|
+
for (const ch of resp.channels || []) {
|
|
60
|
+
const members = ch.num_members || 0;
|
|
61
|
+
console.log(`${ch.id} #${ch.name} (${members} members)`);
|
|
62
|
+
}
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
case "history":
|
|
67
|
+
case "h": {
|
|
68
|
+
if (!args[0]) { console.error("Usage: qabot slack history <channel> [limit]"); process.exit(1); }
|
|
69
|
+
const channelId = await resolveChannel(args[0]);
|
|
70
|
+
const limit = parseInt(args[1] || "10");
|
|
71
|
+
const resp = await client.conversations.history({ channel: channelId, limit });
|
|
72
|
+
for (const msg of (resp.messages || []).reverse()) {
|
|
73
|
+
const time = new Date(parseFloat(msg.ts!) * 1000).toLocaleString();
|
|
74
|
+
let name = msg.user || msg.bot_id || "?";
|
|
75
|
+
try { const u = await client.users.info({ user: msg.user! }); name = u.user?.real_name || u.user?.name || name; } catch {}
|
|
76
|
+
console.log(`[${time}] <${name}> ${(msg.text || "").slice(0, 300)}`);
|
|
77
|
+
}
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
case "send":
|
|
82
|
+
case "s": {
|
|
83
|
+
if (!args[0] || !args[1]) { console.error("Usage: qabot slack send <channel> <text> [thread_ts]"); process.exit(1); }
|
|
84
|
+
const channelId = await resolveChannel(args[0]);
|
|
85
|
+
const resp = await client.chat.postMessage({ channel: channelId, text: args[1], thread_ts: args[2] });
|
|
86
|
+
console.log(`Sent: ${resp.ts}`);
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
case "search":
|
|
91
|
+
case "q": {
|
|
92
|
+
// search.messages requires User Token (xoxp), not Bot Token
|
|
93
|
+
const xoxp = process.env.SLACK_MCP_XOXP_TOKEN;
|
|
94
|
+
if (!xoxp) {
|
|
95
|
+
// Try native slack-cli
|
|
96
|
+
try {
|
|
97
|
+
const slack = require("../lib/slack-cli");
|
|
98
|
+
const result = JSON.parse(await slack.search(args.join(" ")));
|
|
99
|
+
for (const m of (result.messages?.matches || []).slice(0, 20)) {
|
|
100
|
+
console.log(`#${m.channel?.name || "?"} <${m.username || "?"}> ${(m.text || "").slice(0, 200)}`);
|
|
101
|
+
}
|
|
102
|
+
break;
|
|
103
|
+
} catch {}
|
|
104
|
+
console.error("Search needs SLACK_MCP_XOXP_TOKEN (User OAuth Token)");
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
const searchClient = new WebClient(xoxp);
|
|
108
|
+
const resp = await searchClient.search.messages({ query: args.join(" ") });
|
|
109
|
+
for (const m of (resp.messages?.matches || []).slice(0, 20)) {
|
|
110
|
+
console.log(`#${(m as any).channel?.name || "?"} <${(m as any).username || "?"}> ${((m as any).text || "").slice(0, 200)}`);
|
|
111
|
+
}
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
case "replies":
|
|
116
|
+
case "r": {
|
|
117
|
+
if (!args[0] || !args[1]) { console.error("Usage: qabot slack replies <channel> <ts>"); process.exit(1); }
|
|
118
|
+
const channelId = await resolveChannel(args[0]);
|
|
119
|
+
const resp = await client.conversations.replies({ channel: channelId, ts: args[1] });
|
|
120
|
+
for (const msg of resp.messages || []) {
|
|
121
|
+
const time = new Date(parseFloat(msg.ts!) * 1000).toLocaleString();
|
|
122
|
+
console.log(`[${time}] <${msg.user || "?"}> ${(msg.text || "").slice(0, 300)}`);
|
|
123
|
+
}
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
case "user":
|
|
128
|
+
case "u": {
|
|
129
|
+
if (!args[0]) { console.error("Usage: qabot slack user <userId>"); process.exit(1); }
|
|
130
|
+
const resp = await client.users.info({ user: args[0] });
|
|
131
|
+
console.log(`${resp.user?.real_name || resp.user?.name || "?"} (${resp.user?.id})`);
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
default:
|
|
136
|
+
console.error(`Unknown: ${subcmd}. Run 'qabot slack help'`);
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|
|
139
|
+
} catch (err: any) {
|
|
140
|
+
console.error(`Error: ${err.message || err}`);
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
main();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "comfy-qa",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.25.0",
|
|
4
4
|
"description": "ComfyUI QA automation CLI",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"type": "module",
|
|
12
12
|
"bin": {
|
|
13
13
|
"comfy-qa": "./src/cli.ts",
|
|
14
|
-
"cmqa": "./src/cli.ts"
|
|
14
|
+
"cmqa": "./src/cli.ts",
|
|
15
|
+
"qabot": "./bot/cli.ts"
|
|
15
16
|
},
|
|
16
17
|
"files": [
|
|
17
18
|
"src/"
|