pairpod-bot 0.1.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/LICENSE +21 -0
- package/README.md +6 -0
- package/dist/access.d.ts +2 -0
- package/dist/access.js +14 -0
- package/dist/access.js.map +1 -0
- package/dist/agents.d.ts +7 -0
- package/dist/agents.js +10 -0
- package/dist/agents.js.map +1 -0
- package/dist/attach.d.ts +2 -0
- package/dist/attach.js +65 -0
- package/dist/attach.js.map +1 -0
- package/dist/bot.d.ts +1 -0
- package/dist/bot.js +357 -0
- package/dist/bot.js.map +1 -0
- package/dist/config.d.ts +18 -0
- package/dist/config.js +39 -0
- package/dist/config.js.map +1 -0
- package/dist/db.d.ts +2 -0
- package/dist/db.js +87 -0
- package/dist/db.js.map +1 -0
- package/dist/docker.d.ts +15 -0
- package/dist/docker.js +113 -0
- package/dist/docker.js.map +1 -0
- package/dist/env.d.ts +2 -0
- package/dist/env.js +36 -0
- package/dist/env.js.map +1 -0
- package/dist/errors.d.ts +7 -0
- package/dist/errors.js +25 -0
- package/dist/errors.js.map +1 -0
- package/dist/local/sessions.d.ts +5 -0
- package/dist/local/sessions.js +83 -0
- package/dist/local/sessions.js.map +1 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.js +8 -0
- package/dist/main.js.map +1 -0
- package/dist/naming.d.ts +3 -0
- package/dist/naming.js +19 -0
- package/dist/naming.js.map +1 -0
- package/dist/network.d.ts +1 -0
- package/dist/network.js +11 -0
- package/dist/network.js.map +1 -0
- package/dist/notifier.d.ts +4 -0
- package/dist/notifier.js +47 -0
- package/dist/notifier.js.map +1 -0
- package/dist/notify.d.ts +2 -0
- package/dist/notify.js +19 -0
- package/dist/notify.js.map +1 -0
- package/dist/paths.d.ts +9 -0
- package/dist/paths.js +18 -0
- package/dist/paths.js.map +1 -0
- package/dist/routes/attach.d.ts +13 -0
- package/dist/routes/attach.js +49 -0
- package/dist/routes/attach.js.map +1 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.js +51 -0
- package/dist/server.js.map +1 -0
- package/dist/ssh.d.ts +2 -0
- package/dist/ssh.js +84 -0
- package/dist/ssh.js.map +1 -0
- package/dist/store.d.ts +65 -0
- package/dist/store.js +337 -0
- package/dist/store.js.map +1 -0
- package/dist/targets/docker.d.ts +7 -0
- package/dist/targets/docker.js +14 -0
- package/dist/targets/docker.js.map +1 -0
- package/dist/targets/index.d.ts +4 -0
- package/dist/targets/index.js +33 -0
- package/dist/targets/index.js.map +1 -0
- package/dist/targets/ssh.d.ts +25 -0
- package/dist/targets/ssh.js +121 -0
- package/dist/targets/ssh.js.map +1 -0
- package/dist/targets/types.d.ts +15 -0
- package/dist/targets/types.js +2 -0
- package/dist/targets/types.js.map +1 -0
- package/dist/telegram-auth.d.ts +7 -0
- package/dist/telegram-auth.js +41 -0
- package/dist/telegram-auth.js.map +1 -0
- package/dist/vault.d.ts +4 -0
- package/dist/vault.js +57 -0
- package/dist/vault.js.map +1 -0
- package/miniapp/index.html +597 -0
- package/miniapp/ssh.html +251 -0
- package/package.json +44 -0
- package/scripts/fix-pty.cjs +15 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 solidquant
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
package/dist/access.d.ts
ADDED
package/dist/access.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { botConfig } from "./config.js";
|
|
2
|
+
export function hasAllowlist() {
|
|
3
|
+
return botConfig.allowedUserIds.length > 0 || botConfig.allowedUsernames.length > 0;
|
|
4
|
+
}
|
|
5
|
+
export function isAllowed(userId, username) {
|
|
6
|
+
if (!hasAllowlist())
|
|
7
|
+
return true;
|
|
8
|
+
if (userId !== undefined && botConfig.allowedUserIds.includes(userId))
|
|
9
|
+
return true;
|
|
10
|
+
if (username && botConfig.allowedUsernames.includes(username.toLowerCase()))
|
|
11
|
+
return true;
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=access.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access.js","sourceRoot":"","sources":["../src/access.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,UAAU,YAAY;IAC1B,OAAO,SAAS,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC;AACtF,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,MAAe,EAAE,QAAiB;IAC1D,IAAI,CAAC,YAAY,EAAE;QAAE,OAAO,IAAI,CAAC;IACjC,IAAI,MAAM,KAAK,SAAS,IAAI,SAAS,CAAC,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IACnF,IAAI,QAAQ,IAAI,SAAS,CAAC,gBAAgB,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IACzF,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/dist/agents.d.ts
ADDED
package/dist/agents.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,MAAM,GAAgC;IACjD,MAAM,EAAE;QACN,KAAK,EAAE,uBAAuB;QAC9B,UAAU,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC;KAClC;CACF,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,MAAM,CAAC;AACtD,CAAC"}
|
package/dist/attach.d.ts
ADDED
package/dist/attach.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { getDb } from "./db.js";
|
|
2
|
+
import { wireAttach } from "./routes/attach.js";
|
|
3
|
+
import { validateInitData } from "./telegram-auth.js";
|
|
4
|
+
import { isAllowed } from "./access.js";
|
|
5
|
+
import { botConfig } from "./config.js";
|
|
6
|
+
import { getPodRow } from "./store.js";
|
|
7
|
+
import { targetForPod } from "./targets/index.js";
|
|
8
|
+
import { attachLocal } from "./local/sessions.js";
|
|
9
|
+
export async function attachRoutes(app) {
|
|
10
|
+
app.get("/attach", { websocket: true }, async (socket, req) => {
|
|
11
|
+
const q = req.query;
|
|
12
|
+
const auth = validateInitData(q.tgData ?? "", botConfig.token, botConfig.authMaxAgeSec);
|
|
13
|
+
if (!auth.ok) {
|
|
14
|
+
req.log.warn({ reason: auth.reason }, "miniapp attach unauthorized");
|
|
15
|
+
socket.close(4003, "unauthorized");
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (!isAllowed(auth.userId, auth.username)) {
|
|
19
|
+
req.log.warn({ userId: auth.userId, username: auth.username }, "miniapp attach forbidden user");
|
|
20
|
+
socket.close(4003, "forbidden");
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const podId = q.pod;
|
|
24
|
+
const sessionId = q.session;
|
|
25
|
+
if (!podId || !sessionId) {
|
|
26
|
+
socket.close(4004, "missing pod/session");
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const pod = getPodRow(podId);
|
|
30
|
+
if (!pod) {
|
|
31
|
+
socket.close(4004, "pod not found");
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const session = getDb()
|
|
35
|
+
.prepare("SELECT id FROM sessions WHERE pod_id = ? AND id = ?")
|
|
36
|
+
.get(podId, sessionId);
|
|
37
|
+
if (!session) {
|
|
38
|
+
socket.close(4004, "session not found");
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (pod.kind === "local") {
|
|
42
|
+
const cols = q.cols ? parseInt(q.cols, 10) : 80;
|
|
43
|
+
const rows = q.rows ? parseInt(q.rows, 10) : 24;
|
|
44
|
+
attachLocal(socket, sessionId, cols, rows);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const target = targetForPod(pod);
|
|
48
|
+
if (pod.kind === "ssh") {
|
|
49
|
+
try {
|
|
50
|
+
const has = await target.exec(["tmux", "has-session", "-t", sessionId]);
|
|
51
|
+
if (has.exitCode !== 0) {
|
|
52
|
+
socket.close(4004, "session not found");
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
req.log.warn({ err: e.message }, "ssh has-session check failed");
|
|
58
|
+
socket.close(4500, "ssh connect failed");
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
await wireAttach(socket, { cols: q.cols, rows: q.rows }, target, sessionId, (msg, extra) => req.log.info({ extra }, msg));
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=attach.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attach.js","sourceRoot":"","sources":["../src/attach.ts"],"names":[],"mappings":"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"}
|
package/dist/bot.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function startBot(): void;
|
package/dist/bot.js
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
import { Bot, InlineKeyboard } from "grammy";
|
|
2
|
+
import { run } from "@grammyjs/runner";
|
|
3
|
+
import { botConfig } from "./config.js";
|
|
4
|
+
import { isAllowed, hasAllowlist } from "./access.js";
|
|
5
|
+
import { setNotifierBot, recordChat } from "./notifier.js";
|
|
6
|
+
import { listPods, getPod, createPod, createLocalPod, deletePod, createSession, deleteSession, testPod, setPodLabel, setSessionLabel, } from "./store.js";
|
|
7
|
+
// chat id -> a pending rename target; the user's next text message becomes the name.
|
|
8
|
+
const pendingRename = new Map();
|
|
9
|
+
function miniappLink(podId, sessionId) {
|
|
10
|
+
if (!botConfig.miniappUrl)
|
|
11
|
+
return null;
|
|
12
|
+
return `${botConfig.miniappUrl}/?pod=${encodeURIComponent(podId)}&session=${encodeURIComponent(sessionId)}`;
|
|
13
|
+
}
|
|
14
|
+
function sshFormLink(id) {
|
|
15
|
+
if (!botConfig.miniappUrl)
|
|
16
|
+
return null;
|
|
17
|
+
const base = `${botConfig.miniappUrl}/ssh.html`;
|
|
18
|
+
return id ? `${base}?id=${encodeURIComponent(id)}` : base;
|
|
19
|
+
}
|
|
20
|
+
function sshName(p) {
|
|
21
|
+
return p.label || `${p.ssh_user}@${p.ssh_host}`;
|
|
22
|
+
}
|
|
23
|
+
function podLabel(p) {
|
|
24
|
+
if (p.kind === "ssh")
|
|
25
|
+
return `🔌 ${sshName(p)} (${p.sessions.length})`;
|
|
26
|
+
if (p.kind === "local")
|
|
27
|
+
return `💻 ${p.label || p.id} (${p.sessions.length})`;
|
|
28
|
+
return `🐳 ${p.label || p.id} (${p.sessions.length})`;
|
|
29
|
+
}
|
|
30
|
+
function sessName(s) {
|
|
31
|
+
return s.label || s.id;
|
|
32
|
+
}
|
|
33
|
+
function podsView() {
|
|
34
|
+
const pods = listPods().filter((p) => p.status === "running");
|
|
35
|
+
const kb = new InlineKeyboard();
|
|
36
|
+
if (pods.length === 0) {
|
|
37
|
+
kb.text("+ New Pod", "pp:newpod");
|
|
38
|
+
return { text: "No pods yet.", keyboard: kb };
|
|
39
|
+
}
|
|
40
|
+
for (const p of pods) {
|
|
41
|
+
kb.text(podLabel(p), `pp:pod:${p.id}`)
|
|
42
|
+
.text("× delete", `pp:delpod:${p.id}`)
|
|
43
|
+
.row();
|
|
44
|
+
}
|
|
45
|
+
kb.text("+ New Pod", "pp:newpod");
|
|
46
|
+
return { text: "Pods — tap one to manage its sessions.", keyboard: kb };
|
|
47
|
+
}
|
|
48
|
+
function sshView() {
|
|
49
|
+
const pods = listPods().filter((p) => p.kind === "ssh" && p.status === "running");
|
|
50
|
+
const kb = new InlineKeyboard();
|
|
51
|
+
for (const p of pods) {
|
|
52
|
+
kb.text(`🔌 ${sshName(p)}`, `pp:pod:${p.id}`).row();
|
|
53
|
+
const editLink = sshFormLink(p.id);
|
|
54
|
+
if (editLink)
|
|
55
|
+
kb.webApp("✏️ edit", editLink);
|
|
56
|
+
else
|
|
57
|
+
kb.text("✏️ edit (set MINIAPP_URL)", "pp:noapp");
|
|
58
|
+
kb.text("test", `pp:sshtest:${p.id}`).text("× delete", `pp:delpod:${p.id}`).row();
|
|
59
|
+
}
|
|
60
|
+
const link = sshFormLink();
|
|
61
|
+
if (link)
|
|
62
|
+
kb.webApp("➕ Add SSH endpoint", link);
|
|
63
|
+
else
|
|
64
|
+
kb.text("➕ Add SSH (set MINIAPP_URL)", "pp:noapp");
|
|
65
|
+
return {
|
|
66
|
+
text: pods.length === 0 ? "No SSH endpoints yet." : "SSH endpoints:",
|
|
67
|
+
keyboard: kb,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function podView(podId) {
|
|
71
|
+
const pod = getPod(podId);
|
|
72
|
+
const kb = new InlineKeyboard();
|
|
73
|
+
if (!pod) {
|
|
74
|
+
kb.text("‹ Pods", "pp:pods");
|
|
75
|
+
return { text: `Pod ${podId} no longer exists.`, keyboard: kb };
|
|
76
|
+
}
|
|
77
|
+
for (const s of pod.sessions) {
|
|
78
|
+
const link = miniappLink(podId, s.id);
|
|
79
|
+
if (link)
|
|
80
|
+
kb.webApp(`▶ ${sessName(s)}`, link);
|
|
81
|
+
else
|
|
82
|
+
kb.text(`▶ ${sessName(s)} (set MINIAPP_URL)`, "pp:noapp");
|
|
83
|
+
kb.text("✏️", `pp:renamesess:${podId}:${s.id}`)
|
|
84
|
+
.text("× kill", `pp:delsess:${podId}:${s.id}`)
|
|
85
|
+
.row();
|
|
86
|
+
}
|
|
87
|
+
if (pod.kind !== "local") {
|
|
88
|
+
kb.text("⚡ New (skip-perms)", `pp:newsess:${podId}:danger`)
|
|
89
|
+
.text("🔒 New (regular)", `pp:newsess:${podId}:regular`)
|
|
90
|
+
.row();
|
|
91
|
+
}
|
|
92
|
+
kb.text("🖥 New Terminal (shell)", `pp:newsess:${podId}:terminal`).row();
|
|
93
|
+
kb.text("‹ Pods", "pp:pods")
|
|
94
|
+
.text("✏️ rename", `pp:renamepod:${podId}`)
|
|
95
|
+
.text("× delete", `pp:delpod:${podId}`);
|
|
96
|
+
const kindTag = pod.kind === "ssh" ? `🔌 ${sshName(pod)}` : pod.kind === "local" ? "💻 host" : "🐳 docker";
|
|
97
|
+
const header = pod.label ? `Pod "${pod.label}" (${podId}) · ${kindTag}` : `Pod ${podId} · ${kindTag}`;
|
|
98
|
+
const lines = [
|
|
99
|
+
header,
|
|
100
|
+
"",
|
|
101
|
+
pod.sessions.length === 0
|
|
102
|
+
? "No sessions yet. Start one below."
|
|
103
|
+
: "Tap ▶ to open a session terminal.",
|
|
104
|
+
];
|
|
105
|
+
return { text: lines.join("\n"), keyboard: kb };
|
|
106
|
+
}
|
|
107
|
+
function sessionsView() {
|
|
108
|
+
const pods = listPods();
|
|
109
|
+
const kb = new InlineKeyboard();
|
|
110
|
+
let count = 0;
|
|
111
|
+
for (const p of pods) {
|
|
112
|
+
for (const s of p.sessions) {
|
|
113
|
+
const name = `${p.label || p.id} · ${sessName(s)}`;
|
|
114
|
+
const link = miniappLink(p.id, s.id);
|
|
115
|
+
if (link)
|
|
116
|
+
kb.webApp(`▶ ${name}`, link);
|
|
117
|
+
else
|
|
118
|
+
kb.text(`▶ ${name} (set MINIAPP_URL)`, "pp:noapp");
|
|
119
|
+
kb.text("× kill", `pp:delsess:${p.id}:${s.id}`).row();
|
|
120
|
+
count++;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
kb.text("‹ Pods", "pp:pods");
|
|
124
|
+
return {
|
|
125
|
+
text: count === 0 ? "No sessions. Use /pods to create one." : "All sessions:",
|
|
126
|
+
keyboard: kb,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
export function startBot() {
|
|
130
|
+
if (!botConfig.token) {
|
|
131
|
+
console.info("bot disabled (no TELEGRAM_BOT_TOKEN)");
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (!hasAllowlist()) {
|
|
135
|
+
console.warn("No allowlist set (TELEGRAM_ALLOWED_USERNAMES / TELEGRAM_ALLOWED_USER_IDS) — bot allows any user");
|
|
136
|
+
}
|
|
137
|
+
if (!botConfig.miniappUrl) {
|
|
138
|
+
console.warn("MINIAPP_URL not set — terminal mini app buttons disabled");
|
|
139
|
+
}
|
|
140
|
+
const bot = new Bot(botConfig.token);
|
|
141
|
+
setNotifierBot(bot);
|
|
142
|
+
bot.use(async (ctx, next) => {
|
|
143
|
+
if (!isAllowed(ctx.from?.id, ctx.from?.username)) {
|
|
144
|
+
console.warn(`bot rejected user id=${ctx.from?.id} username=@${ctx.from?.username ?? "?"}`);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const chatId = ctx.chat?.id;
|
|
148
|
+
if (chatId !== undefined)
|
|
149
|
+
recordChat(chatId);
|
|
150
|
+
await next();
|
|
151
|
+
});
|
|
152
|
+
// Any button press other than a rename abandons a half-started rename.
|
|
153
|
+
bot.on("callback_query:data", async (ctx, next) => {
|
|
154
|
+
if (!ctx.callbackQuery.data.startsWith("pp:rename") && ctx.chat) {
|
|
155
|
+
pendingRename.delete(ctx.chat.id);
|
|
156
|
+
}
|
|
157
|
+
await next();
|
|
158
|
+
});
|
|
159
|
+
bot.command("start", async (ctx) => {
|
|
160
|
+
await ctx.reply("pairpod terminal bot.\n\n/pods — manage pods & sessions\n/sessions — list all sessions\n/help — reference\n\nTap a session's ▶ button to open a live terminal inside Telegram.");
|
|
161
|
+
});
|
|
162
|
+
bot.command("help", async (ctx) => {
|
|
163
|
+
await ctx.reply([
|
|
164
|
+
"pairpod terminal bot",
|
|
165
|
+
"",
|
|
166
|
+
"/pods — list pods; create/delete; open a pod to manage its sessions",
|
|
167
|
+
"/sessions — list every session with an Open button",
|
|
168
|
+
"/ssh — register/test/delete SSH endpoints (remote hosts as pods)",
|
|
169
|
+
"",
|
|
170
|
+
"New pod backends: 🐳 Docker (a fresh container), 🔌 SSH (a remote host), or 💻 Host (a shell on the bot machine).",
|
|
171
|
+
"",
|
|
172
|
+
"Sessions come in three modes (Docker and SSH):",
|
|
173
|
+
"⚡ skip-perms — claude --dangerously-skip-permissions",
|
|
174
|
+
"🔒 regular — claude (answer permission prompts in the terminal)",
|
|
175
|
+
"🖥 terminal — a plain shell",
|
|
176
|
+
"SSH Claude sessions need claude installed + logged in on the remote, and MINIAPP_URL set.",
|
|
177
|
+
"",
|
|
178
|
+
"▶ opens a byte-identical terminal (xterm) as a Telegram mini app.",
|
|
179
|
+
].join("\n"));
|
|
180
|
+
});
|
|
181
|
+
bot.command("whoami", async (ctx) => {
|
|
182
|
+
await ctx.reply(`id: ${ctx.from?.id}\nusername: @${ctx.from?.username ?? "(none)"}\n\nPin the numeric id via TELEGRAM_ALLOWED_USER_IDS for a stable lock.`);
|
|
183
|
+
});
|
|
184
|
+
bot.command("pods", async (ctx) => {
|
|
185
|
+
const v = podsView();
|
|
186
|
+
await ctx.reply(v.text, { reply_markup: v.keyboard });
|
|
187
|
+
});
|
|
188
|
+
bot.command("sessions", async (ctx) => {
|
|
189
|
+
const v = sessionsView();
|
|
190
|
+
await ctx.reply(v.text, { reply_markup: v.keyboard });
|
|
191
|
+
});
|
|
192
|
+
bot.command("ssh", async (ctx) => {
|
|
193
|
+
const v = sshView();
|
|
194
|
+
await ctx.reply(v.text, { reply_markup: v.keyboard });
|
|
195
|
+
});
|
|
196
|
+
bot.callbackQuery("pp:noapp", async (ctx) => {
|
|
197
|
+
await ctx.answerCallbackQuery({
|
|
198
|
+
text: "Set MINIAPP_URL (https tunnel) to enable the terminal mini app.",
|
|
199
|
+
show_alert: true,
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
bot.callbackQuery("pp:pods", async (ctx) => {
|
|
203
|
+
const v = podsView();
|
|
204
|
+
await ctx.editMessageText(v.text, { reply_markup: v.keyboard });
|
|
205
|
+
await ctx.answerCallbackQuery();
|
|
206
|
+
});
|
|
207
|
+
bot.callbackQuery("pp:sessions", async (ctx) => {
|
|
208
|
+
const v = sessionsView();
|
|
209
|
+
await ctx.editMessageText(v.text, { reply_markup: v.keyboard });
|
|
210
|
+
await ctx.answerCallbackQuery();
|
|
211
|
+
});
|
|
212
|
+
bot.callbackQuery("pp:newpod", async (ctx) => {
|
|
213
|
+
const kb = new InlineKeyboard().text("🐳 Docker", "pp:newdocker").text("💻 Host", "pp:newhost");
|
|
214
|
+
const link = sshFormLink();
|
|
215
|
+
if (link)
|
|
216
|
+
kb.webApp("🔌 SSH", link);
|
|
217
|
+
else
|
|
218
|
+
kb.text("🔌 SSH (set MINIAPP_URL)", "pp:noapp");
|
|
219
|
+
kb.row().text("‹ Pods", "pp:pods");
|
|
220
|
+
await ctx.editMessageText("New pod — choose a backend:", { reply_markup: kb });
|
|
221
|
+
await ctx.answerCallbackQuery();
|
|
222
|
+
});
|
|
223
|
+
bot.callbackQuery("pp:newdocker", async (ctx) => {
|
|
224
|
+
await ctx.answerCallbackQuery({ text: "Creating pod…" });
|
|
225
|
+
try {
|
|
226
|
+
await createPod();
|
|
227
|
+
}
|
|
228
|
+
catch (e) {
|
|
229
|
+
await ctx.reply(`Failed to create pod: ${e.message}`);
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const v = podsView();
|
|
233
|
+
await ctx.editMessageText(v.text, { reply_markup: v.keyboard });
|
|
234
|
+
});
|
|
235
|
+
bot.callbackQuery("pp:newhost", async (ctx) => {
|
|
236
|
+
await ctx.answerCallbackQuery({ text: "Creating host pod…" });
|
|
237
|
+
try {
|
|
238
|
+
createLocalPod();
|
|
239
|
+
}
|
|
240
|
+
catch (e) {
|
|
241
|
+
await ctx.reply(`Failed to create host pod: ${e.message}`);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const v = podsView();
|
|
245
|
+
await ctx.editMessageText(v.text, { reply_markup: v.keyboard });
|
|
246
|
+
});
|
|
247
|
+
bot.callbackQuery(/^pp:sshtest:(.+)$/, async (ctx) => {
|
|
248
|
+
const podId = ctx.match[1];
|
|
249
|
+
try {
|
|
250
|
+
const out = await testPod(podId);
|
|
251
|
+
await ctx.answerCallbackQuery({ text: `OK — ${out}`, show_alert: true });
|
|
252
|
+
}
|
|
253
|
+
catch (e) {
|
|
254
|
+
await ctx.answerCallbackQuery({ text: `Failed: ${e.message}`, show_alert: true });
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
bot.callbackQuery(/^pp:pod:(.+)$/, async (ctx) => {
|
|
258
|
+
const podId = ctx.match[1];
|
|
259
|
+
const v = podView(podId);
|
|
260
|
+
await ctx.editMessageText(v.text, { reply_markup: v.keyboard });
|
|
261
|
+
await ctx.answerCallbackQuery();
|
|
262
|
+
});
|
|
263
|
+
bot.callbackQuery(/^pp:delpod:(.+)$/, async (ctx) => {
|
|
264
|
+
const podId = ctx.match[1];
|
|
265
|
+
await ctx.answerCallbackQuery({ text: "Deleting pod…" });
|
|
266
|
+
try {
|
|
267
|
+
await deletePod(podId);
|
|
268
|
+
}
|
|
269
|
+
catch (e) {
|
|
270
|
+
await ctx.reply(`Failed to delete pod: ${e.message}`);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
const v = podsView();
|
|
274
|
+
await ctx.editMessageText(v.text, { reply_markup: v.keyboard });
|
|
275
|
+
});
|
|
276
|
+
bot.callbackQuery(/^pp:renamepod:(.+)$/, async (ctx) => {
|
|
277
|
+
const podId = ctx.match[1];
|
|
278
|
+
if (ctx.chat)
|
|
279
|
+
pendingRename.set(ctx.chat.id, { podId });
|
|
280
|
+
await ctx.answerCallbackQuery();
|
|
281
|
+
await ctx.reply(`Send a name for ${podId} (your next message). Send "-" to clear it.`, {
|
|
282
|
+
reply_markup: { force_reply: true, input_field_placeholder: "pod name" },
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
bot.callbackQuery(/^pp:renamesess:(.+):(.+)$/, async (ctx) => {
|
|
286
|
+
const podId = ctx.match[1];
|
|
287
|
+
const sessionId = ctx.match[2];
|
|
288
|
+
if (ctx.chat)
|
|
289
|
+
pendingRename.set(ctx.chat.id, { podId, sessionId });
|
|
290
|
+
await ctx.answerCallbackQuery();
|
|
291
|
+
await ctx.reply(`Send a name for session ${sessionId} (your next message). Send "-" to clear it.`, {
|
|
292
|
+
reply_markup: { force_reply: true, input_field_placeholder: "session name" },
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
bot.callbackQuery(/^pp:newsess:(.+):(danger|regular|terminal)$/, async (ctx) => {
|
|
296
|
+
const podId = ctx.match[1];
|
|
297
|
+
const mode = ctx.match[2];
|
|
298
|
+
await ctx.answerCallbackQuery({ text: "Starting session…" });
|
|
299
|
+
try {
|
|
300
|
+
await createSession(podId, mode);
|
|
301
|
+
}
|
|
302
|
+
catch (e) {
|
|
303
|
+
await ctx.reply(`Failed to start session: ${e.message}`);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
const v = podView(podId);
|
|
307
|
+
await ctx.editMessageText(v.text, { reply_markup: v.keyboard });
|
|
308
|
+
});
|
|
309
|
+
bot.callbackQuery(/^pp:delsess:(.+):(.+)$/, async (ctx) => {
|
|
310
|
+
const podId = ctx.match[1];
|
|
311
|
+
const sessionId = ctx.match[2];
|
|
312
|
+
await ctx.answerCallbackQuery({ text: "Killing session…" });
|
|
313
|
+
try {
|
|
314
|
+
await deleteSession(podId, sessionId);
|
|
315
|
+
}
|
|
316
|
+
catch (e) {
|
|
317
|
+
await ctx.reply(`Failed to kill session: ${e.message}`);
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
const v = podView(podId);
|
|
321
|
+
await ctx.editMessageText(v.text, { reply_markup: v.keyboard });
|
|
322
|
+
});
|
|
323
|
+
// Capture the next text message as the name for a pending rename.
|
|
324
|
+
bot.on("message:text", async (ctx) => {
|
|
325
|
+
const pending = pendingRename.get(ctx.chat.id);
|
|
326
|
+
if (!pending)
|
|
327
|
+
return;
|
|
328
|
+
pendingRename.delete(ctx.chat.id);
|
|
329
|
+
const text = ctx.message.text.trim();
|
|
330
|
+
const label = text === "-" ? null : text;
|
|
331
|
+
try {
|
|
332
|
+
if (pending.sessionId)
|
|
333
|
+
setSessionLabel(pending.podId, pending.sessionId, label);
|
|
334
|
+
else
|
|
335
|
+
setPodLabel(pending.podId, label);
|
|
336
|
+
}
|
|
337
|
+
catch (e) {
|
|
338
|
+
await ctx.reply(`Rename failed: ${e.message}`);
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
const v = podView(pending.podId);
|
|
342
|
+
await ctx.reply(v.text, { reply_markup: v.keyboard });
|
|
343
|
+
});
|
|
344
|
+
bot.catch((err) => console.error("bot error", err));
|
|
345
|
+
bot.api
|
|
346
|
+
.setMyCommands([
|
|
347
|
+
{ command: "pods", description: "List pods; create, delete, manage sessions" },
|
|
348
|
+
{ command: "sessions", description: "List all sessions with an open button" },
|
|
349
|
+
{ command: "ssh", description: "List SSH endpoints; add, test, delete" },
|
|
350
|
+
{ command: "whoami", description: "Show your Telegram id and username" },
|
|
351
|
+
{ command: "help", description: "How the terminal bot works" },
|
|
352
|
+
])
|
|
353
|
+
.catch((e) => console.error("setMyCommands failed", e));
|
|
354
|
+
run(bot);
|
|
355
|
+
console.info("bot started");
|
|
356
|
+
}
|
|
357
|
+
//# sourceMappingURL=bot.js.map
|
package/dist/bot.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bot.js","sourceRoot":"","sources":["../src/bot.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const config: {
|
|
2
|
+
workspacesRoot: string;
|
|
3
|
+
dbPath: string;
|
|
4
|
+
dockerSocket: string;
|
|
5
|
+
logLevel: string;
|
|
6
|
+
pairpodNetwork: string;
|
|
7
|
+
telegramAllowedUserIds: number[];
|
|
8
|
+
};
|
|
9
|
+
export declare const botConfig: {
|
|
10
|
+
token: string;
|
|
11
|
+
hookToken: string;
|
|
12
|
+
miniappUrl: string;
|
|
13
|
+
publicUrl: string;
|
|
14
|
+
port: number;
|
|
15
|
+
allowedUserIds: number[];
|
|
16
|
+
allowedUsernames: string[];
|
|
17
|
+
authMaxAgeSec: number;
|
|
18
|
+
};
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import crypto from "node:crypto";
|
|
3
|
+
import { paths } from "./paths.js";
|
|
4
|
+
const EnvSchema = z.object({
|
|
5
|
+
DOCKER_SOCKET: z.string().default("/var/run/docker.sock"),
|
|
6
|
+
LOG_LEVEL: z.string().default("info"),
|
|
7
|
+
PAIRPOD_NETWORK: z.string().default("pairpod-net"),
|
|
8
|
+
TELEGRAM_BOT_TOKEN: z.string().optional(),
|
|
9
|
+
TELEGRAM_ALLOWED_USER_IDS: z.string().optional(),
|
|
10
|
+
});
|
|
11
|
+
const parsed = EnvSchema.parse(process.env);
|
|
12
|
+
export const config = {
|
|
13
|
+
workspacesRoot: paths.workspaces,
|
|
14
|
+
dbPath: paths.db,
|
|
15
|
+
dockerSocket: parsed.DOCKER_SOCKET,
|
|
16
|
+
logLevel: parsed.LOG_LEVEL,
|
|
17
|
+
pairpodNetwork: parsed.PAIRPOD_NETWORK,
|
|
18
|
+
telegramAllowedUserIds: parsed.TELEGRAM_ALLOWED_USER_IDS
|
|
19
|
+
? parsed.TELEGRAM_ALLOWED_USER_IDS.split(",").map((s) => parseInt(s.trim(), 10)).filter((n) => !isNaN(n))
|
|
20
|
+
: [],
|
|
21
|
+
};
|
|
22
|
+
const token = process.env.TELEGRAM_BOT_TOKEN ?? "";
|
|
23
|
+
const miniappUrl = (process.env.MINIAPP_URL ?? "").replace(/\/$/, "");
|
|
24
|
+
export const botConfig = {
|
|
25
|
+
token,
|
|
26
|
+
hookToken: token ? crypto.createHash("sha256").update(token).digest("hex").slice(0, 32) : "",
|
|
27
|
+
miniappUrl,
|
|
28
|
+
// Public origin a remote (SSH) host POSTs permission notifications to. Defaults to the
|
|
29
|
+
// mini-app origin; set PAIRPOD_PUBLIC_URL to decouple it (e.g. a stable named tunnel).
|
|
30
|
+
publicUrl: ((process.env.PAIRPOD_PUBLIC_URL ?? "").replace(/\/$/, "")) || miniappUrl,
|
|
31
|
+
port: Number(process.env.PORT ?? 40002),
|
|
32
|
+
allowedUserIds: config.telegramAllowedUserIds,
|
|
33
|
+
allowedUsernames: (process.env.TELEGRAM_ALLOWED_USERNAMES ?? "")
|
|
34
|
+
.split(",")
|
|
35
|
+
.map((s) => s.trim().replace(/^@/, "").toLowerCase())
|
|
36
|
+
.filter(Boolean),
|
|
37
|
+
authMaxAgeSec: Number(process.env.MINIAPP_AUTH_MAX_AGE_SEC ?? 86400),
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IACzB,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,sBAAsB,CAAC;IACzD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;IACrC,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC;IAClD,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACzC,yBAAyB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACjD,CAAC,CAAC;AAEH,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;AAE5C,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,cAAc,EAAE,KAAK,CAAC,UAAU;IAChC,MAAM,EAAE,KAAK,CAAC,EAAE;IAChB,YAAY,EAAE,MAAM,CAAC,aAAa;IAClC,QAAQ,EAAE,MAAM,CAAC,SAAS;IAC1B,cAAc,EAAE,MAAM,CAAC,eAAe;IACtC,sBAAsB,EAAE,MAAM,CAAC,yBAAyB;QACtD,CAAC,CAAC,MAAM,CAAC,yBAAyB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACzG,CAAC,CAAC,EAAE;CACP,CAAC;AAEF,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,EAAE,CAAC;AACnD,MAAM,UAAU,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAEtE,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,KAAK;IACL,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;IAC5F,UAAU;IACV,uFAAuF;IACvF,uFAAuF;IACvF,SAAS,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,UAAU;IACpF,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,KAAK,CAAC;IACvC,cAAc,EAAE,MAAM,CAAC,sBAAsB;IAC7C,gBAAgB,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAI,EAAE,CAAC;SAC7D,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;SACpD,MAAM,CAAC,OAAO,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,KAAK,CAAC;CACrE,CAAC"}
|
package/dist/db.d.ts
ADDED