@sojaner/telex 0.1.15
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 +502 -0
- package/config.example.json +7 -0
- package/dist/agents.js +94 -0
- package/dist/agents.js.map +1 -0
- package/dist/ask.js +200 -0
- package/dist/ask.js.map +1 -0
- package/dist/cli.js +206 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.js +50 -0
- package/dist/config.js.map +1 -0
- package/dist/index.js +168 -0
- package/dist/index.js.map +1 -0
- package/dist/registry.js +62 -0
- package/dist/registry.js.map +1 -0
- package/dist/setup.js +125 -0
- package/dist/setup.js.map +1 -0
- package/dist/telegram.js +205 -0
- package/dist/telegram.js.map +1 -0
- package/package.json +40 -0
package/dist/ask.js
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { TelegramError, escapeHtml, MAX_MESSAGE_LEN } from "./telegram.js";
|
|
2
|
+
let counter = 0;
|
|
3
|
+
const nextRequestId = () => `${Date.now().toString(36)}${(counter++).toString(36)}`;
|
|
4
|
+
/** Telegram truncates long inline-button labels, so long choices move into the body as a numbered list. */
|
|
5
|
+
const LABEL_LIMIT = 24;
|
|
6
|
+
export function compose(input) {
|
|
7
|
+
const options = input.options ?? [];
|
|
8
|
+
const numbered = options.some((o) => o.length > LABEL_LIMIT);
|
|
9
|
+
const list = numbered ? `\n\n${options.map((o, i) => `${i + 1}. ${escapeHtml(o)}`).join("\n")}` : "";
|
|
10
|
+
return {
|
|
11
|
+
text: `<b>${escapeHtml(input.project)}</b>\n\n${input.message}${list}`,
|
|
12
|
+
buttonLabels: numbered ? options.map((_, i) => String(i + 1)) : options,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/** Split on line boundaries where possible; the parse-mode fallback covers chunks that break a tag. */
|
|
16
|
+
export function chunk(text, limit = MAX_MESSAGE_LEN) {
|
|
17
|
+
const out = [];
|
|
18
|
+
let rest = text;
|
|
19
|
+
while (rest.length > limit) {
|
|
20
|
+
const cut = rest.lastIndexOf("\n", limit) > limit / 2 ? rest.lastIndexOf("\n", limit) : limit;
|
|
21
|
+
out.push(rest.slice(0, cut));
|
|
22
|
+
rest = rest.slice(cut).replace(/^\n/, "");
|
|
23
|
+
}
|
|
24
|
+
out.push(rest);
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
/** Send, wait for the user, then always leave the message in a settled state. */
|
|
28
|
+
export async function ask(session, chatId, input) {
|
|
29
|
+
const requestId = nextRequestId();
|
|
30
|
+
const options = input.options ?? [];
|
|
31
|
+
if (options.length && input.expectText)
|
|
32
|
+
throw new Error("telex: use either options or expect_text, not both");
|
|
33
|
+
const { text, buttonLabels } = compose(input);
|
|
34
|
+
const keyboard = options.length
|
|
35
|
+
? buttonLabels.map((label, i) => [{ text: label, callback_data: `telex:${requestId}:${i}` }])
|
|
36
|
+
: input.expectText
|
|
37
|
+
? [[{ text: "✍️ Reply", callback_data: `telex:${requestId}:text` }]]
|
|
38
|
+
: [];
|
|
39
|
+
// Only the final chunk carries the keyboard, so the buttons sit under the whole question.
|
|
40
|
+
const chunks = chunk(text);
|
|
41
|
+
let sent;
|
|
42
|
+
for (const [i, part] of chunks.entries()) {
|
|
43
|
+
sent = await send(session, chatId, part, i === chunks.length - 1 ? keyboard : []);
|
|
44
|
+
}
|
|
45
|
+
const messageId = sent.message_id;
|
|
46
|
+
const tail = chunks[chunks.length - 1];
|
|
47
|
+
if (!keyboard.length)
|
|
48
|
+
return { status: "sent", message_id: messageId };
|
|
49
|
+
const deadline = Date.now() + input.timeoutSeconds * 1000;
|
|
50
|
+
const answer = await waitForAnswer(session, chatId, requestId, options, deadline, input.allowFrom);
|
|
51
|
+
if (!answer) {
|
|
52
|
+
await settle(session, chatId, messageId, tail, "⏳ <i>No response — stale.</i>");
|
|
53
|
+
return { status: "timeout", message_id: messageId };
|
|
54
|
+
}
|
|
55
|
+
await settle(session, chatId, messageId, tail, `✅ <b>${escapeHtml(answer.value)}</b>`);
|
|
56
|
+
return { status: "answered", response: answer.value, kind: answer.kind, message_id: messageId };
|
|
57
|
+
}
|
|
58
|
+
/** What the user sees under their own message as it moves through the queue. */
|
|
59
|
+
const RECEIPT = {
|
|
60
|
+
held: "📥 <i>Held for the agent's next check-in.</i>",
|
|
61
|
+
delivered: "📬 <i>Delivered to the agent.</i>",
|
|
62
|
+
expired: "⌛ <i>Expired — the agent never picked this up. Send it again if it still matters.</i>",
|
|
63
|
+
refused: "⛔ <i>Not accepted — no agent has checked in for this project yet.</i>",
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Telegram gives bots no delivery receipt, so telex sends its own and edits it in place. A project
|
|
67
|
+
* that is not running never posts one at all, which is how the user can tell nobody is listening.
|
|
68
|
+
*/
|
|
69
|
+
export async function receipt(session, chatId, message) {
|
|
70
|
+
const sent = await session.api("sendMessage", {
|
|
71
|
+
chat_id: chatId,
|
|
72
|
+
text: RECEIPT.held,
|
|
73
|
+
parse_mode: "HTML",
|
|
74
|
+
reply_parameters: { message_id: message.message_id, allow_sending_without_reply: true },
|
|
75
|
+
}).catch(() => undefined);
|
|
76
|
+
if (sent)
|
|
77
|
+
message.receipt_id = sent.message_id;
|
|
78
|
+
}
|
|
79
|
+
function updateReceipt(session, chatId, message, text) {
|
|
80
|
+
if (message.receipt_id === undefined)
|
|
81
|
+
return;
|
|
82
|
+
return session.api("editMessageText", {
|
|
83
|
+
chat_id: chatId,
|
|
84
|
+
message_id: message.receipt_id,
|
|
85
|
+
text,
|
|
86
|
+
parse_mode: "HTML",
|
|
87
|
+
}).catch(() => { }); // an unchanged or deleted receipt is not worth failing a heartbeat over
|
|
88
|
+
}
|
|
89
|
+
export const markExpired = (session, chatId, messages) => {
|
|
90
|
+
for (const message of messages)
|
|
91
|
+
void updateReceipt(session, chatId, message, RECEIPT.expired);
|
|
92
|
+
};
|
|
93
|
+
/** Tell the user their message went nowhere, rather than holding it for an agent that may never come. */
|
|
94
|
+
export function refuse(session, chatId, message) {
|
|
95
|
+
return session.api("sendMessage", {
|
|
96
|
+
chat_id: chatId,
|
|
97
|
+
text: RECEIPT.refused,
|
|
98
|
+
parse_mode: "HTML",
|
|
99
|
+
reply_parameters: { message_id: message.message_id, allow_sending_without_reply: true },
|
|
100
|
+
}).catch(() => { });
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* One heartbeat: drop whatever the agent left too long, then hand over the rest. Returns
|
|
104
|
+
* immediately — the agent's own interval is the clock, and its silence is what expires a message.
|
|
105
|
+
*/
|
|
106
|
+
export function heartbeat(session, chatId, now = Date.now()) {
|
|
107
|
+
session.sweepInbox(now);
|
|
108
|
+
return deliver(session, chatId, now);
|
|
109
|
+
}
|
|
110
|
+
/** Hand the queue to the agent and say so in the chat. */
|
|
111
|
+
export function deliver(session, chatId, now = Date.now()) {
|
|
112
|
+
return session.take(chatId).map((message) => {
|
|
113
|
+
void updateReceipt(session, chatId, message, RECEIPT.delivered);
|
|
114
|
+
return {
|
|
115
|
+
text: message.text,
|
|
116
|
+
received_at: new Date(message.received_at).toISOString(),
|
|
117
|
+
waited_seconds: Math.round((now - message.received_at) / 1000),
|
|
118
|
+
};
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
/** An inline keyboard is clickable by anyone who can see it, so authorise the tap, not the send. */
|
|
122
|
+
function authorized(ctx, chatId, allowFrom) {
|
|
123
|
+
if (ctx.chatId !== undefined && String(ctx.chatId) !== String(chatId))
|
|
124
|
+
return false;
|
|
125
|
+
return !allowFrom?.length || (ctx.fromId !== undefined && allowFrom.includes(ctx.fromId));
|
|
126
|
+
}
|
|
127
|
+
async function waitForAnswer(session, chatId, requestId, options, deadline, allowFrom) {
|
|
128
|
+
const tap = await until(deadline, (resolve) => session.onCallback(requestId, (payload, ctx) => {
|
|
129
|
+
if (!authorized(ctx, chatId, allowFrom)) {
|
|
130
|
+
void session.api("answerCallbackQuery", {
|
|
131
|
+
callback_query_id: ctx.callbackId,
|
|
132
|
+
text: "⛔ Not your prompt.",
|
|
133
|
+
}).catch(() => { });
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
resolve({ payload, ctx });
|
|
137
|
+
}));
|
|
138
|
+
if (!tap)
|
|
139
|
+
return null;
|
|
140
|
+
const toast = (text) => session.api("answerCallbackQuery", { callback_query_id: tap.ctx.callbackId, text }).catch(() => { });
|
|
141
|
+
if (tap.payload !== "text") {
|
|
142
|
+
const value = options[Number(tap.payload)];
|
|
143
|
+
await toast(value === undefined ? "" : `✓ ${value.slice(0, 60)}`);
|
|
144
|
+
return value === undefined ? null : { value, kind: "choice" };
|
|
145
|
+
}
|
|
146
|
+
await toast("✍️ Type your answer in the chat.");
|
|
147
|
+
const prompt = await send(session, chatId, "✍️ <i>Reply to this message with your response.</i>", [], {
|
|
148
|
+
force_reply: true,
|
|
149
|
+
});
|
|
150
|
+
const text = await until(deadline, (resolve) => session.onText(chatId, (value, fromId) => {
|
|
151
|
+
if (allowFrom?.length && (fromId === undefined || !allowFrom.includes(fromId)))
|
|
152
|
+
return;
|
|
153
|
+
resolve(value);
|
|
154
|
+
}));
|
|
155
|
+
await session.api("deleteMessage", { chat_id: chatId, message_id: prompt.message_id }).catch(() => { });
|
|
156
|
+
return text === null ? null : { value: text, kind: "text" };
|
|
157
|
+
}
|
|
158
|
+
/** Resolve with the first value the subscriber emits, or null once the deadline passes. */
|
|
159
|
+
function until(deadline, subscribe) {
|
|
160
|
+
return new Promise((resolve) => {
|
|
161
|
+
let done = false;
|
|
162
|
+
const finish = (v) => {
|
|
163
|
+
if (done)
|
|
164
|
+
return;
|
|
165
|
+
done = true;
|
|
166
|
+
clearTimeout(timer);
|
|
167
|
+
unsubscribe();
|
|
168
|
+
resolve(v);
|
|
169
|
+
};
|
|
170
|
+
const timer = setTimeout(() => finish(null), Math.max(0, deadline - Date.now()));
|
|
171
|
+
const unsubscribe = subscribe((v) => finish(v));
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
/** Drop the keyboard and stamp the outcome onto the message that carried it. */
|
|
175
|
+
async function settle(session, chatId, messageId, text, footer) {
|
|
176
|
+
await session.api("editMessageText", {
|
|
177
|
+
chat_id: chatId,
|
|
178
|
+
message_id: messageId,
|
|
179
|
+
text: `${text}\n\n${footer}`,
|
|
180
|
+
parse_mode: "HTML",
|
|
181
|
+
reply_markup: { inline_keyboard: [] },
|
|
182
|
+
}).catch(() => { }); // "message is not modified" and friends are not worth failing the answer over
|
|
183
|
+
}
|
|
184
|
+
/** HTML is Telegram's forgiving parse mode, but agents still emit stray tags — fall back to plain text. */
|
|
185
|
+
async function send(session, chatId, text, keyboard, extraMarkup = {}) {
|
|
186
|
+
const reply_markup = keyboard.length
|
|
187
|
+
? { inline_keyboard: keyboard }
|
|
188
|
+
: Object.keys(extraMarkup).length
|
|
189
|
+
? extraMarkup
|
|
190
|
+
: undefined;
|
|
191
|
+
try {
|
|
192
|
+
return await session.api("sendMessage", { chat_id: chatId, text, parse_mode: "HTML", reply_markup });
|
|
193
|
+
}
|
|
194
|
+
catch (err) {
|
|
195
|
+
if (!(err instanceof TelegramError) || !/parse|entit|tag/i.test(err.description))
|
|
196
|
+
throw err;
|
|
197
|
+
return await session.api("sendMessage", { chat_id: chatId, text, reply_markup });
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=ask.js.map
|
package/dist/ask.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ask.js","sourceRoot":"","sources":["../src/ask.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { parseArgs } from "node:util";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { readConfig, writeConfig, configPath, maskToken } from "./config.js";
|
|
5
|
+
import { addBotInteractive, installConfig } from "./setup.js";
|
|
6
|
+
import { agents, snippet } from "./agents.js";
|
|
7
|
+
const USAGE = `telex — send messages from local AI agents to Telegram
|
|
8
|
+
|
|
9
|
+
telex serve run the MCP server (stdio); what agents launch
|
|
10
|
+
telex add [name] add a bot, guided; or pass --token/--chat-id
|
|
11
|
+
telex list show configured bots
|
|
12
|
+
telex set <name> [options] change a bot
|
|
13
|
+
telex remove <name> delete a bot
|
|
14
|
+
telex config [name] install the MCP registration into this project
|
|
15
|
+
|
|
16
|
+
Options for config:
|
|
17
|
+
--agent <id> skip the prompts: claude, codex, cursor, vscode, zed, ...
|
|
18
|
+
--scope <local|project> for agents with both: gitignored file or committed file
|
|
19
|
+
--print only show the commands and file syntax; write nothing
|
|
20
|
+
-y, --yes don't ask about the current directory
|
|
21
|
+
|
|
22
|
+
Options for add/set:
|
|
23
|
+
--token <token> bot token from @BotFather
|
|
24
|
+
--chat-id <id> chat the bot writes to (negative ids: --chat-id=-1001234567890)
|
|
25
|
+
--allow <id,id> Telegram user ids allowed to answer ("any" to clear)
|
|
26
|
+
--default make this the default bot
|
|
27
|
+
|
|
28
|
+
Config lives at ${configPath()} (override with TELEX_CONFIG).`;
|
|
29
|
+
// Resolves to src/index.ts in a checkout and dist/index.js once built.
|
|
30
|
+
const serverEntry = fileURLToPath(new URL(import.meta.url.endsWith(".ts") ? "index.ts" : "index.js", import.meta.url));
|
|
31
|
+
/** Group chat ids are negative, and parseArgs reads a leading dash as another flag. */
|
|
32
|
+
const { values: flags, positionals } = parseArgsFriendly({
|
|
33
|
+
allowPositionals: true,
|
|
34
|
+
options: {
|
|
35
|
+
token: { type: "string" },
|
|
36
|
+
"chat-id": { type: "string" },
|
|
37
|
+
allow: { type: "string" },
|
|
38
|
+
default: { type: "boolean" },
|
|
39
|
+
json: { type: "boolean" },
|
|
40
|
+
agent: { type: "string" },
|
|
41
|
+
scope: { type: "string" },
|
|
42
|
+
print: { type: "boolean" },
|
|
43
|
+
yes: { type: "boolean", short: "y" },
|
|
44
|
+
help: { type: "boolean", short: "h" },
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
const [command, arg] = positionals;
|
|
48
|
+
function parseArgsFriendly(options) {
|
|
49
|
+
try {
|
|
50
|
+
return parseArgs(options);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
const message = err.message;
|
|
54
|
+
const negative = message.match(/Option '(--[a-z-]+)' argument is ambiguous/i);
|
|
55
|
+
if (negative) {
|
|
56
|
+
console.error(`✗ ${negative[1]} looks like it got a negative value. Write it as ${negative[1]}=-1001234567890.`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
console.error(`✗ ${message.split("\n")[0]}`);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async function run(command, name) {
|
|
64
|
+
switch (command) {
|
|
65
|
+
case "serve":
|
|
66
|
+
await import("./index.js");
|
|
67
|
+
return;
|
|
68
|
+
case "add": {
|
|
69
|
+
const config = readConfig();
|
|
70
|
+
if (name && config.bots[name])
|
|
71
|
+
throw new Error(`bot "${name}" already exists — use "telex set ${name}"`);
|
|
72
|
+
// A token on the command line means the caller already knows everything; don't make them talk to a wizard.
|
|
73
|
+
if (!flags.token) {
|
|
74
|
+
const added = await addBotInteractive(name);
|
|
75
|
+
if (flags.default)
|
|
76
|
+
setDefault(added);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (!flags["chat-id"])
|
|
80
|
+
throw new Error("--token also needs --chat-id");
|
|
81
|
+
if (!name)
|
|
82
|
+
throw new Error("give the bot a name: telex add <name> --token ... --chat-id ...");
|
|
83
|
+
config.bots[name] = { token: flags.token, chatId: numeric(flags["chat-id"]), allowFrom: parseAllow(flags.allow) };
|
|
84
|
+
config.defaultBot = flags.default || !config.defaultBot ? name : config.defaultBot;
|
|
85
|
+
writeConfig(config);
|
|
86
|
+
console.log(`✓ Added "${name}"${config.defaultBot === name ? " (default)" : ""}`);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
case "set": {
|
|
90
|
+
const config = readConfig();
|
|
91
|
+
const bot = required(config.bots, name);
|
|
92
|
+
if (flags.token)
|
|
93
|
+
bot.token = flags.token;
|
|
94
|
+
if (flags["chat-id"])
|
|
95
|
+
bot.chatId = numeric(flags["chat-id"]);
|
|
96
|
+
if (flags.allow !== undefined)
|
|
97
|
+
bot.allowFrom = parseAllow(flags.allow);
|
|
98
|
+
if (flags.default)
|
|
99
|
+
config.defaultBot = name;
|
|
100
|
+
writeConfig(config);
|
|
101
|
+
console.log(`✓ Updated "${name}"`);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
case "remove": {
|
|
105
|
+
const config = readConfig();
|
|
106
|
+
required(config.bots, name);
|
|
107
|
+
delete config.bots[name];
|
|
108
|
+
// Never leave defaultBot pointing at a bot that no longer exists.
|
|
109
|
+
if (config.defaultBot === name)
|
|
110
|
+
config.defaultBot = Object.keys(config.bots)[0];
|
|
111
|
+
writeConfig(config);
|
|
112
|
+
console.log(`✓ Removed "${name}"`);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
case "list": {
|
|
116
|
+
const config = readConfig();
|
|
117
|
+
const names = Object.keys(config.bots);
|
|
118
|
+
if (!names.length)
|
|
119
|
+
return console.log(`No bots configured. Run "telex add".`);
|
|
120
|
+
if (flags.json)
|
|
121
|
+
return console.log(JSON.stringify(redact(config), null, 2));
|
|
122
|
+
for (const n of names) {
|
|
123
|
+
const bot = config.bots[n];
|
|
124
|
+
const allow = bot.allowFrom?.length ? bot.allowFrom.join(", ") : "anyone in chat";
|
|
125
|
+
console.log(`${n === config.defaultBot ? "*" : " "} ${n.padEnd(16)} chat ${String(bot.chatId).padEnd(16)} ${maskToken(bot.token)} allow: ${allow}`);
|
|
126
|
+
}
|
|
127
|
+
console.log(`\n* = default. Config: ${configPath()}`);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
case "config": {
|
|
131
|
+
const config = readConfig();
|
|
132
|
+
if (name)
|
|
133
|
+
required(config.bots, name);
|
|
134
|
+
const entry = { command: "telex", args: ["serve"], ...(name ? { env: { TELEX_BOT: name } } : {}) };
|
|
135
|
+
if (flags.json)
|
|
136
|
+
return console.log(JSON.stringify({ mcpServers: { telex: entry } }, null, 2));
|
|
137
|
+
if (flags.print)
|
|
138
|
+
return printConfigs(entry, name);
|
|
139
|
+
await installConfig(name, { agent: flags.agent, scope: flags.scope, yes: flags.yes });
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
default:
|
|
143
|
+
throw new Error(`unknown command "${command}"\n\n${USAGE}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/** What --print shows: every supported agent, its installer command or its config file. */
|
|
147
|
+
function printConfigs(entry, name) {
|
|
148
|
+
const list = agents();
|
|
149
|
+
console.log(`Agents that install it for you — run in the project root:\n`);
|
|
150
|
+
for (const agent of list.filter((a) => a.cli))
|
|
151
|
+
console.log(` ${agent.label.padEnd(15)}${agent.cli(name).join(" ")}`);
|
|
152
|
+
console.log(`\nAgents you configure by writing a file:\n`);
|
|
153
|
+
for (const agent of list.filter((a) => a.file)) {
|
|
154
|
+
console.log(` ${agent.label.padEnd(15)}${agent.file}${agent.localFile ? ` (or ${agent.localFile}, gitignored)` : ""}`);
|
|
155
|
+
for (const line of snippet(agent, entry).split("\n"))
|
|
156
|
+
console.log(` ${" ".repeat(15)}${line}`);
|
|
157
|
+
console.log();
|
|
158
|
+
}
|
|
159
|
+
console.log(`Codex reads .codex/config.toml only for projects you have trusted.`);
|
|
160
|
+
if (name)
|
|
161
|
+
console.log(`Messages from this project default to "${name}"; the agent can still pass another bot.`);
|
|
162
|
+
else
|
|
163
|
+
console.log(`Pass a bot name to pin this project to one: telex config <name>`);
|
|
164
|
+
console.log(`\nIf "telex" is not on PATH, use: "command": "node", "args": ["${serverEntry}"]`);
|
|
165
|
+
}
|
|
166
|
+
function required(bots, name) {
|
|
167
|
+
if (!name)
|
|
168
|
+
throw new Error("which bot? pass its name");
|
|
169
|
+
const bot = bots[name];
|
|
170
|
+
if (!bot)
|
|
171
|
+
throw new Error(`unknown bot "${name}". Configured: ${Object.keys(bots).join(", ") || "none"}`);
|
|
172
|
+
return bot;
|
|
173
|
+
}
|
|
174
|
+
function setDefault(name) {
|
|
175
|
+
const config = readConfig();
|
|
176
|
+
config.defaultBot = name;
|
|
177
|
+
writeConfig(config);
|
|
178
|
+
}
|
|
179
|
+
const numeric = (v) => (/^-?\d+$/.test(v.trim()) ? Number(v.trim()) : v.trim());
|
|
180
|
+
function parseAllow(value) {
|
|
181
|
+
if (!value || value === "any")
|
|
182
|
+
return undefined;
|
|
183
|
+
return value.split(",").map((v) => {
|
|
184
|
+
const id = Number(v.trim());
|
|
185
|
+
if (!Number.isInteger(id))
|
|
186
|
+
throw new Error(`--allow takes numeric Telegram user ids, got "${v.trim()}"`);
|
|
187
|
+
return id;
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
const redact = (config) => ({
|
|
191
|
+
...config,
|
|
192
|
+
bots: Object.fromEntries(Object.entries(config.bots).map(([n, b]) => [n, { ...b, token: maskToken(b.token) }])),
|
|
193
|
+
});
|
|
194
|
+
try {
|
|
195
|
+
if (flags.help || !command) {
|
|
196
|
+
console.log(USAGE);
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
await run(command, arg);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
catch (err) {
|
|
203
|
+
console.error(`✗ ${err.message}`);
|
|
204
|
+
process.exitCode = 1;
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
export const configPath = () => process.env.TELEX_CONFIG ?? join(process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config"), "telex", "config.json");
|
|
5
|
+
/** Config as it is on disk, or an empty one. For the CLI, which has to cope with "nothing yet". */
|
|
6
|
+
export function readConfig() {
|
|
7
|
+
const path = configPath();
|
|
8
|
+
if (!existsSync(path))
|
|
9
|
+
return { bots: {} };
|
|
10
|
+
try {
|
|
11
|
+
const raw = JSON.parse(readFileSync(path, "utf8"));
|
|
12
|
+
return { defaultBot: raw.defaultBot, bots: raw.bots ?? {} };
|
|
13
|
+
}
|
|
14
|
+
catch (err) {
|
|
15
|
+
throw new Error(`telex: ${path} is not valid JSON: ${err.message}`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function writeConfig(config) {
|
|
19
|
+
const path = configPath();
|
|
20
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
21
|
+
writeFileSync(path, `${JSON.stringify(config, null, 2)}\n`, { mode: 0o600 });
|
|
22
|
+
}
|
|
23
|
+
/** Validated config for the server, which cannot do anything useful without at least one bot. */
|
|
24
|
+
export function loadConfig() {
|
|
25
|
+
const config = readConfig();
|
|
26
|
+
const names = Object.keys(config.bots);
|
|
27
|
+
if (names.length === 0)
|
|
28
|
+
throw new Error(`telex: no bots configured in ${configPath()} — run "telex add"`);
|
|
29
|
+
for (const [name, bot] of Object.entries(config.bots)) {
|
|
30
|
+
if (!bot?.token || bot.chatId === undefined)
|
|
31
|
+
throw new Error(`telex: bot "${name}" needs both token and chatId`);
|
|
32
|
+
}
|
|
33
|
+
if (config.defaultBot && !config.bots[config.defaultBot]) {
|
|
34
|
+
throw new Error(`telex: defaultBot "${config.defaultBot}" is not in bots`);
|
|
35
|
+
}
|
|
36
|
+
return { defaultBot: config.defaultBot ?? names[0], bots: config.bots };
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Which bot a call goes to: the agent's argument wins, then the bot pinned for this
|
|
40
|
+
* project via TELEX_BOT, then the global default.
|
|
41
|
+
*/
|
|
42
|
+
export function pickBot(config, name) {
|
|
43
|
+
const key = name || process.env.TELEX_BOT || config.defaultBot;
|
|
44
|
+
const bot = config.bots[key];
|
|
45
|
+
if (!bot)
|
|
46
|
+
throw new Error(`telex: unknown bot "${key}". Configured: ${Object.keys(config.bots).join(", ")}`);
|
|
47
|
+
return { name: key, bot };
|
|
48
|
+
}
|
|
49
|
+
export const maskToken = (token) => `${token.split(":")[0]}:${"*".repeat(6)}${token.slice(-4)}`;
|
|
50
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|