@grinev/opencode-telegram-bot 0.1.0-rc.1
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/.env.example +34 -0
- package/LICENSE +21 -0
- package/README.md +72 -0
- package/dist/agent/manager.js +92 -0
- package/dist/agent/types.js +26 -0
- package/dist/app/start-bot-app.js +26 -0
- package/dist/bot/commands/agent.js +16 -0
- package/dist/bot/commands/definitions.js +20 -0
- package/dist/bot/commands/help.js +7 -0
- package/dist/bot/commands/model.js +16 -0
- package/dist/bot/commands/models.js +37 -0
- package/dist/bot/commands/new.js +58 -0
- package/dist/bot/commands/opencode-start.js +87 -0
- package/dist/bot/commands/opencode-stop.js +46 -0
- package/dist/bot/commands/projects.js +104 -0
- package/dist/bot/commands/server-restart.js +23 -0
- package/dist/bot/commands/server-start.js +23 -0
- package/dist/bot/commands/sessions.js +240 -0
- package/dist/bot/commands/start.js +40 -0
- package/dist/bot/commands/status.js +63 -0
- package/dist/bot/commands/stop.js +92 -0
- package/dist/bot/handlers/agent.js +96 -0
- package/dist/bot/handlers/context.js +112 -0
- package/dist/bot/handlers/model.js +115 -0
- package/dist/bot/handlers/permission.js +158 -0
- package/dist/bot/handlers/question.js +294 -0
- package/dist/bot/handlers/variant.js +126 -0
- package/dist/bot/index.js +573 -0
- package/dist/bot/middleware/auth.js +30 -0
- package/dist/bot/utils/keyboard.js +66 -0
- package/dist/cli/args.js +97 -0
- package/dist/cli.js +90 -0
- package/dist/config.js +46 -0
- package/dist/index.js +26 -0
- package/dist/keyboard/manager.js +171 -0
- package/dist/keyboard/types.js +1 -0
- package/dist/model/manager.js +123 -0
- package/dist/model/types.js +26 -0
- package/dist/opencode/client.js +13 -0
- package/dist/opencode/events.js +79 -0
- package/dist/opencode/server.js +104 -0
- package/dist/permission/manager.js +78 -0
- package/dist/permission/types.js +1 -0
- package/dist/pinned/manager.js +610 -0
- package/dist/pinned/types.js +1 -0
- package/dist/pinned-message/service.js +54 -0
- package/dist/process/manager.js +273 -0
- package/dist/process/types.js +1 -0
- package/dist/project/manager.js +28 -0
- package/dist/question/manager.js +143 -0
- package/dist/question/types.js +1 -0
- package/dist/runtime/bootstrap.js +278 -0
- package/dist/runtime/mode.js +74 -0
- package/dist/runtime/paths.js +37 -0
- package/dist/session/manager.js +10 -0
- package/dist/session/state.js +24 -0
- package/dist/settings/manager.js +99 -0
- package/dist/status/formatter.js +44 -0
- package/dist/summary/aggregator.js +427 -0
- package/dist/summary/formatter.js +226 -0
- package/dist/utils/formatting.js +237 -0
- package/dist/utils/logger.js +59 -0
- package/dist/utils/safe-background-task.js +33 -0
- package/dist/variant/manager.js +103 -0
- package/dist/variant/types.js +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import * as fs from "fs/promises";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
const PID_FILE = path.join(process.cwd(), ".opencode-server.pid");
|
|
5
|
+
let serverProcess = null;
|
|
6
|
+
export async function getServerPID() {
|
|
7
|
+
try {
|
|
8
|
+
const content = await fs.readFile(PID_FILE, "utf-8");
|
|
9
|
+
const pid = parseInt(content.trim(), 10);
|
|
10
|
+
if (isNaN(pid)) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
return pid;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export async function saveServerPID(pid) {
|
|
20
|
+
await fs.writeFile(PID_FILE, pid.toString());
|
|
21
|
+
}
|
|
22
|
+
export async function removeServerPID() {
|
|
23
|
+
try {
|
|
24
|
+
await fs.unlink(PID_FILE);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// Ignore if file doesn't exist
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function isServerRunning() {
|
|
31
|
+
return serverProcess !== null && serverProcess.process.pid !== undefined;
|
|
32
|
+
}
|
|
33
|
+
export async function startServer() {
|
|
34
|
+
if (serverProcess !== null) {
|
|
35
|
+
return { success: false, message: "Server is already running" };
|
|
36
|
+
}
|
|
37
|
+
return new Promise((resolve) => {
|
|
38
|
+
const child = spawn("opencode", ["serve"], {
|
|
39
|
+
stdio: "pipe",
|
|
40
|
+
shell: true,
|
|
41
|
+
});
|
|
42
|
+
serverProcess = {
|
|
43
|
+
process: child,
|
|
44
|
+
startTime: new Date(),
|
|
45
|
+
};
|
|
46
|
+
child.stdout?.on("data", (data) => {
|
|
47
|
+
console.log(`[OpenCode Server] ${data.toString().trim()}`);
|
|
48
|
+
});
|
|
49
|
+
child.stderr?.on("data", (data) => {
|
|
50
|
+
console.error(`[OpenCode Server Error] ${data.toString().trim()}`);
|
|
51
|
+
});
|
|
52
|
+
child.on("error", (err) => {
|
|
53
|
+
console.error("Failed to start OpenCode server:", err);
|
|
54
|
+
serverProcess = null;
|
|
55
|
+
resolve({
|
|
56
|
+
success: false,
|
|
57
|
+
message: `Failed to start server: ${err.message}`,
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
child.on("exit", (code, signal) => {
|
|
61
|
+
console.log(`[OpenCode Server] Exited with code ${code}, signal ${signal}`);
|
|
62
|
+
serverProcess = null;
|
|
63
|
+
removeServerPID().catch((err) => console.error("Failed to remove PID file:", err));
|
|
64
|
+
});
|
|
65
|
+
// Wait a bit to check if process started successfully
|
|
66
|
+
setTimeout(() => {
|
|
67
|
+
if (child.pid) {
|
|
68
|
+
saveServerPID(child.pid).catch((err) => console.error("Failed to save PID file:", err));
|
|
69
|
+
resolve({
|
|
70
|
+
success: true,
|
|
71
|
+
message: `Server started successfully (PID: ${child.pid})`,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
serverProcess = null;
|
|
76
|
+
resolve({ success: false, message: "Failed to start server: no PID" });
|
|
77
|
+
}
|
|
78
|
+
}, 2000);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
export async function stopServer() {
|
|
82
|
+
if (!serverProcess) {
|
|
83
|
+
return { success: false, message: "Server is not running" };
|
|
84
|
+
}
|
|
85
|
+
const pid = serverProcess.process.pid;
|
|
86
|
+
const process = serverProcess.process;
|
|
87
|
+
process.kill("SIGTERM");
|
|
88
|
+
serverProcess = null;
|
|
89
|
+
return new Promise((resolve) => {
|
|
90
|
+
// Wait for process to exit
|
|
91
|
+
setTimeout(() => {
|
|
92
|
+
removeServerPID().catch((err) => console.error("Failed to remove PID file:", err));
|
|
93
|
+
resolve({ success: true, message: `Server stopped (was PID ${pid})` });
|
|
94
|
+
}, 1000);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
export async function restartServer() {
|
|
98
|
+
const stopResult = await stopServer();
|
|
99
|
+
if (!stopResult.success && !stopResult.message.includes("not running")) {
|
|
100
|
+
return stopResult;
|
|
101
|
+
}
|
|
102
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
103
|
+
return startServer();
|
|
104
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { logger } from "../utils/logger.js";
|
|
2
|
+
class PermissionManager {
|
|
3
|
+
state = {
|
|
4
|
+
request: null,
|
|
5
|
+
messageId: null,
|
|
6
|
+
isActive: false,
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Start a new permission request
|
|
10
|
+
*/
|
|
11
|
+
startPermission(request) {
|
|
12
|
+
logger.debug(`[PermissionManager] startPermission: id=${request.id}, permission=${request.permission}`);
|
|
13
|
+
if (this.state.isActive) {
|
|
14
|
+
logger.warn("[PermissionManager] Permission already active, replacing");
|
|
15
|
+
this.clear();
|
|
16
|
+
}
|
|
17
|
+
logger.info(`[PermissionManager] New permission request: type=${request.permission}, patterns=${request.patterns.join(", ")}`);
|
|
18
|
+
this.state = {
|
|
19
|
+
request,
|
|
20
|
+
messageId: null,
|
|
21
|
+
isActive: true,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Get current permission request
|
|
26
|
+
*/
|
|
27
|
+
getRequest() {
|
|
28
|
+
return this.state.request;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Get request ID for API reply
|
|
32
|
+
*/
|
|
33
|
+
getRequestID() {
|
|
34
|
+
return this.state.request?.id ?? null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get permission type (bash, edit, etc.)
|
|
38
|
+
*/
|
|
39
|
+
getPermissionType() {
|
|
40
|
+
return this.state.request?.permission ?? null;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get patterns (commands/files)
|
|
44
|
+
*/
|
|
45
|
+
getPatterns() {
|
|
46
|
+
return this.state.request?.patterns ?? [];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Set Telegram message ID for later deletion
|
|
50
|
+
*/
|
|
51
|
+
setMessageId(messageId) {
|
|
52
|
+
this.state.messageId = messageId;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get Telegram message ID
|
|
56
|
+
*/
|
|
57
|
+
getMessageId() {
|
|
58
|
+
return this.state.messageId;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Check if permission request is active
|
|
62
|
+
*/
|
|
63
|
+
isActive() {
|
|
64
|
+
return this.state.isActive;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Clear state after reply
|
|
68
|
+
*/
|
|
69
|
+
clear() {
|
|
70
|
+
logger.debug("[PermissionManager] Clearing permission state");
|
|
71
|
+
this.state = {
|
|
72
|
+
request: null,
|
|
73
|
+
messageId: null,
|
|
74
|
+
isActive: false,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export const permissionManager = new PermissionManager();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|