@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.
Files changed (66) hide show
  1. package/.env.example +34 -0
  2. package/LICENSE +21 -0
  3. package/README.md +72 -0
  4. package/dist/agent/manager.js +92 -0
  5. package/dist/agent/types.js +26 -0
  6. package/dist/app/start-bot-app.js +26 -0
  7. package/dist/bot/commands/agent.js +16 -0
  8. package/dist/bot/commands/definitions.js +20 -0
  9. package/dist/bot/commands/help.js +7 -0
  10. package/dist/bot/commands/model.js +16 -0
  11. package/dist/bot/commands/models.js +37 -0
  12. package/dist/bot/commands/new.js +58 -0
  13. package/dist/bot/commands/opencode-start.js +87 -0
  14. package/dist/bot/commands/opencode-stop.js +46 -0
  15. package/dist/bot/commands/projects.js +104 -0
  16. package/dist/bot/commands/server-restart.js +23 -0
  17. package/dist/bot/commands/server-start.js +23 -0
  18. package/dist/bot/commands/sessions.js +240 -0
  19. package/dist/bot/commands/start.js +40 -0
  20. package/dist/bot/commands/status.js +63 -0
  21. package/dist/bot/commands/stop.js +92 -0
  22. package/dist/bot/handlers/agent.js +96 -0
  23. package/dist/bot/handlers/context.js +112 -0
  24. package/dist/bot/handlers/model.js +115 -0
  25. package/dist/bot/handlers/permission.js +158 -0
  26. package/dist/bot/handlers/question.js +294 -0
  27. package/dist/bot/handlers/variant.js +126 -0
  28. package/dist/bot/index.js +573 -0
  29. package/dist/bot/middleware/auth.js +30 -0
  30. package/dist/bot/utils/keyboard.js +66 -0
  31. package/dist/cli/args.js +97 -0
  32. package/dist/cli.js +90 -0
  33. package/dist/config.js +46 -0
  34. package/dist/index.js +26 -0
  35. package/dist/keyboard/manager.js +171 -0
  36. package/dist/keyboard/types.js +1 -0
  37. package/dist/model/manager.js +123 -0
  38. package/dist/model/types.js +26 -0
  39. package/dist/opencode/client.js +13 -0
  40. package/dist/opencode/events.js +79 -0
  41. package/dist/opencode/server.js +104 -0
  42. package/dist/permission/manager.js +78 -0
  43. package/dist/permission/types.js +1 -0
  44. package/dist/pinned/manager.js +610 -0
  45. package/dist/pinned/types.js +1 -0
  46. package/dist/pinned-message/service.js +54 -0
  47. package/dist/process/manager.js +273 -0
  48. package/dist/process/types.js +1 -0
  49. package/dist/project/manager.js +28 -0
  50. package/dist/question/manager.js +143 -0
  51. package/dist/question/types.js +1 -0
  52. package/dist/runtime/bootstrap.js +278 -0
  53. package/dist/runtime/mode.js +74 -0
  54. package/dist/runtime/paths.js +37 -0
  55. package/dist/session/manager.js +10 -0
  56. package/dist/session/state.js +24 -0
  57. package/dist/settings/manager.js +99 -0
  58. package/dist/status/formatter.js +44 -0
  59. package/dist/summary/aggregator.js +427 -0
  60. package/dist/summary/formatter.js +226 -0
  61. package/dist/utils/formatting.js +237 -0
  62. package/dist/utils/logger.js +59 -0
  63. package/dist/utils/safe-background-task.js +33 -0
  64. package/dist/variant/manager.js +103 -0
  65. package/dist/variant/types.js +1 -0
  66. 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 {};