opencode-telegram-bridge 1.0.7 → 1.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/README.md +3 -27
- package/bin/opencode-telegram-bridge.js +1 -1
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +159 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -15
- package/dist/index.js.map +1 -1
- package/dist/run.d.ts +3 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +19 -0
- package/dist/run.js.map +1 -0
- package/docs/configuration.md +6 -3
- package/docs/index.md +1 -2
- package/docs/installation.md +6 -25
- package/docs/systemd.md +26 -14
- package/package.json +1 -1
- package/systemd/opencode-telegram-bridge.env.example +2 -2
- package/systemd/opencode-telegram-bridge.service +2 -2
- package/docs/release.md +0 -112
package/README.md
CHANGED
|
@@ -22,30 +22,6 @@ You still need OpenCode running separately:
|
|
|
22
22
|
opencode serve
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
##
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
npm install
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
2. Create `.env` from the example:
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
cp .env.example .env
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
3. Start OpenCode server in another terminal:
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
opencode serve
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
4. Run the bot:
|
|
45
|
-
|
|
46
|
-
```bash
|
|
47
|
-
npm run dev
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## Releases
|
|
51
|
-
This project uses Changesets. See `docs/release.md`.
|
|
25
|
+
## Documentation
|
|
26
|
+
See the docs for configuration, usage, and systemd setup:
|
|
27
|
+
https://gabriel-trigo.github.io/opencode-telegram-bridge/
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "../dist/
|
|
2
|
+
import "../dist/cli.js"
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import readline from "node:readline/promises";
|
|
6
|
+
import { stdin, stdout } from "node:process";
|
|
7
|
+
import { runBot } from "./run.js";
|
|
8
|
+
const die = (message) => {
|
|
9
|
+
console.error(message);
|
|
10
|
+
process.exit(1);
|
|
11
|
+
};
|
|
12
|
+
const runCommand = (command, args) => {
|
|
13
|
+
const result = spawnSync(command, args, {
|
|
14
|
+
encoding: "utf8",
|
|
15
|
+
stdio: "inherit",
|
|
16
|
+
});
|
|
17
|
+
if (result.status !== 0) {
|
|
18
|
+
throw new Error(`Command failed: ${command} ${args.join(" ")}`);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const resolveExecStart = () => {
|
|
22
|
+
const result = spawnSync("sh", ["-c", "command -v opencode-telegram-bridge"], {
|
|
23
|
+
encoding: "utf8",
|
|
24
|
+
});
|
|
25
|
+
const execStart = result.stdout.trim();
|
|
26
|
+
if (!execStart || result.status !== 0) {
|
|
27
|
+
throw new Error("opencode-telegram-bridge not found in PATH");
|
|
28
|
+
}
|
|
29
|
+
return execStart;
|
|
30
|
+
};
|
|
31
|
+
const readAnswer = async (prompt, options = {}) => {
|
|
32
|
+
const rl = readline.createInterface({ input: stdin, output: stdout });
|
|
33
|
+
const suffix = options.defaultValue ? ` (${options.defaultValue})` : "";
|
|
34
|
+
const answer = (await rl.question(`${prompt}${suffix}: `)).trim();
|
|
35
|
+
rl.close();
|
|
36
|
+
if (!answer && options.defaultValue) {
|
|
37
|
+
return options.defaultValue;
|
|
38
|
+
}
|
|
39
|
+
if (!answer && options.required) {
|
|
40
|
+
throw new Error(`Missing ${prompt}`);
|
|
41
|
+
}
|
|
42
|
+
return answer;
|
|
43
|
+
};
|
|
44
|
+
const confirmAnswer = async (prompt, defaultValue = false) => {
|
|
45
|
+
const rl = readline.createInterface({ input: stdin, output: stdout });
|
|
46
|
+
const suffix = defaultValue ? "(Y/n)" : "(y/N)";
|
|
47
|
+
const answer = (await rl.question(`${prompt} ${suffix}: `)).trim();
|
|
48
|
+
rl.close();
|
|
49
|
+
if (!answer) {
|
|
50
|
+
return defaultValue;
|
|
51
|
+
}
|
|
52
|
+
return answer.toLowerCase().startsWith("y");
|
|
53
|
+
};
|
|
54
|
+
const writeEnvFile = (envPath, values) => {
|
|
55
|
+
const lines = Object.entries(values).map(([key, value]) => `${key}=${value}`);
|
|
56
|
+
fs.mkdirSync(path.dirname(envPath), { recursive: true });
|
|
57
|
+
fs.writeFileSync(envPath, `${lines.join("\n")}\n`, "utf8");
|
|
58
|
+
};
|
|
59
|
+
const writeUnitFile = (unitPath, content) => {
|
|
60
|
+
fs.mkdirSync(path.dirname(unitPath), { recursive: true });
|
|
61
|
+
fs.writeFileSync(unitPath, content, "utf8");
|
|
62
|
+
};
|
|
63
|
+
const buildUnitFile = (envPath, execStart) => `
|
|
64
|
+
[Unit]
|
|
65
|
+
Description=OpenCode Telegram Bridge
|
|
66
|
+
After=network-online.target
|
|
67
|
+
Wants=network-online.target
|
|
68
|
+
|
|
69
|
+
[Service]
|
|
70
|
+
Type=simple
|
|
71
|
+
EnvironmentFile=${envPath}
|
|
72
|
+
ExecStart=${execStart}
|
|
73
|
+
Restart=on-failure
|
|
74
|
+
RestartSec=3
|
|
75
|
+
|
|
76
|
+
[Install]
|
|
77
|
+
WantedBy=default.target
|
|
78
|
+
`;
|
|
79
|
+
const runSetupWizard = async () => {
|
|
80
|
+
if (process.platform !== "linux") {
|
|
81
|
+
die("Setup currently supports Linux systemd only. See the docs for manual setup.");
|
|
82
|
+
}
|
|
83
|
+
const systemctlCheck = spawnSync("systemctl", ["--user", "--version"], {
|
|
84
|
+
encoding: "utf8",
|
|
85
|
+
});
|
|
86
|
+
if (systemctlCheck.status !== 0) {
|
|
87
|
+
die("systemctl --user is not available. Install systemd or use manual setup.");
|
|
88
|
+
}
|
|
89
|
+
const homeDir = os.homedir();
|
|
90
|
+
const envPath = path.join(homeDir, ".config", "opencode-telegram-bridge", "opencode-telegram-bridge.env");
|
|
91
|
+
const unitPath = path.join(homeDir, ".config", "systemd", "user", "opencode-telegram-bridge.service");
|
|
92
|
+
if (fs.existsSync(envPath) || fs.existsSync(unitPath)) {
|
|
93
|
+
const overwrite = await confirmAnswer("Existing config found. Overwrite?", false);
|
|
94
|
+
if (!overwrite) {
|
|
95
|
+
die("Setup cancelled.");
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const botToken = await readAnswer("TELEGRAM_BOT_TOKEN", { required: true });
|
|
99
|
+
const allowedUserId = await readAnswer("TELEGRAM_ALLOWED_USER_ID", {
|
|
100
|
+
required: true,
|
|
101
|
+
});
|
|
102
|
+
if (!Number.isInteger(Number(allowedUserId))) {
|
|
103
|
+
throw new Error("TELEGRAM_ALLOWED_USER_ID must be an integer");
|
|
104
|
+
}
|
|
105
|
+
const serverUrl = await readAnswer("OPENCODE_SERVER_URL", {
|
|
106
|
+
defaultValue: "http://127.0.0.1:4096",
|
|
107
|
+
});
|
|
108
|
+
const serverUsername = await readAnswer("OPENCODE_SERVER_USERNAME", {
|
|
109
|
+
defaultValue: "opencode",
|
|
110
|
+
});
|
|
111
|
+
const serverPassword = await readAnswer("OPENCODE_SERVER_PASSWORD", {});
|
|
112
|
+
const opencodeRestartCommand = await readAnswer("OPENCODE_RESTART_COMMAND", {});
|
|
113
|
+
const opencodeRestartTimeoutMs = opencodeRestartCommand ? "30000" : "";
|
|
114
|
+
const execStart = resolveExecStart();
|
|
115
|
+
writeEnvFile(envPath, {
|
|
116
|
+
TELEGRAM_BOT_TOKEN: botToken,
|
|
117
|
+
TELEGRAM_ALLOWED_USER_ID: allowedUserId,
|
|
118
|
+
OPENCODE_SERVER_URL: serverUrl,
|
|
119
|
+
OPENCODE_SERVER_USERNAME: serverUsername,
|
|
120
|
+
OPENCODE_SERVER_PASSWORD: serverPassword,
|
|
121
|
+
OPENCODE_PROMPT_TIMEOUT_MS: "600000",
|
|
122
|
+
TELEGRAM_HANDLER_TIMEOUT_MS: "630000",
|
|
123
|
+
OPENCODE_RESTART_COMMAND: opencodeRestartCommand,
|
|
124
|
+
OPENCODE_RESTART_TIMEOUT_MS: opencodeRestartTimeoutMs,
|
|
125
|
+
OPENCODE_BRIDGE_RESTART_COMMAND: "systemctl --user restart opencode-telegram-bridge --no-block",
|
|
126
|
+
OPENCODE_BRIDGE_RESTART_TIMEOUT_MS: "30000",
|
|
127
|
+
});
|
|
128
|
+
const unitFile = buildUnitFile(envPath, execStart);
|
|
129
|
+
writeUnitFile(unitPath, unitFile);
|
|
130
|
+
runCommand("systemctl", ["--user", "daemon-reload"]);
|
|
131
|
+
runCommand("systemctl", ["--user", "enable", "--now", "opencode-telegram-bridge"]);
|
|
132
|
+
const enableLinger = await confirmAnswer("Enable linger so the service starts on boot without login?", false);
|
|
133
|
+
if (enableLinger) {
|
|
134
|
+
const user = os.userInfo().username;
|
|
135
|
+
const result = spawnSync("sudo", ["loginctl", "enable-linger", user], {
|
|
136
|
+
encoding: "utf8",
|
|
137
|
+
stdio: "inherit",
|
|
138
|
+
});
|
|
139
|
+
if (result.status !== 0) {
|
|
140
|
+
console.warn("Failed to enable linger. Run: sudo loginctl enable-linger");
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
console.log("Setup complete. Service is running.");
|
|
144
|
+
console.log(`Env file: ${envPath}`);
|
|
145
|
+
console.log(`Unit file: ${unitPath}`);
|
|
146
|
+
};
|
|
147
|
+
const command = process.argv[2];
|
|
148
|
+
if (!command) {
|
|
149
|
+
runBot();
|
|
150
|
+
}
|
|
151
|
+
else if (command === "setup") {
|
|
152
|
+
runSetupWizard().catch((error) => {
|
|
153
|
+
die(error instanceof Error ? error.message : "Setup failed.");
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
die("Unknown command. Use: opencode-telegram-bridge [setup]");
|
|
158
|
+
}
|
|
159
|
+
//# 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/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
export {};
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
CHANGED
|
@@ -1,16 +1,3 @@
|
|
|
1
|
-
import "
|
|
2
|
-
|
|
3
|
-
import { startBot } from "./bot.js";
|
|
4
|
-
import { createOpencodeBridge } from "./opencode.js";
|
|
5
|
-
import { createProjectStore } from "./projects.js";
|
|
6
|
-
import { createChatModelStore, createChatProjectStore, createPersistentSessionStore, } from "./state.js";
|
|
7
|
-
const config = loadConfig();
|
|
8
|
-
const sessionStore = createPersistentSessionStore();
|
|
9
|
-
const opencode = createOpencodeBridge(config.opencode, { sessionStore });
|
|
10
|
-
const projects = createProjectStore();
|
|
11
|
-
const chatProjects = createChatProjectStore();
|
|
12
|
-
const chatModels = createChatModelStore();
|
|
13
|
-
const bot = startBot(config, opencode, projects, chatProjects, chatModels);
|
|
14
|
-
process.once("SIGINT", () => bot.stop("SIGINT"));
|
|
15
|
-
process.once("SIGTERM", () => bot.stop("SIGTERM"));
|
|
1
|
+
import { runBot } from "./run.js";
|
|
2
|
+
runBot();
|
|
16
3
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAEjC,MAAM,EAAE,CAAA"}
|
package/dist/run.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAA;AAYtB,eAAO,MAAM,MAAM,iGAalB,CAAA"}
|
package/dist/run.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
2
|
+
import { loadConfig } from "./config.js";
|
|
3
|
+
import { startBot } from "./bot.js";
|
|
4
|
+
import { createOpencodeBridge } from "./opencode.js";
|
|
5
|
+
import { createProjectStore } from "./projects.js";
|
|
6
|
+
import { createChatModelStore, createChatProjectStore, createPersistentSessionStore, } from "./state.js";
|
|
7
|
+
export const runBot = () => {
|
|
8
|
+
const config = loadConfig();
|
|
9
|
+
const sessionStore = createPersistentSessionStore();
|
|
10
|
+
const opencode = createOpencodeBridge(config.opencode, { sessionStore });
|
|
11
|
+
const projects = createProjectStore();
|
|
12
|
+
const chatProjects = createChatProjectStore();
|
|
13
|
+
const chatModels = createChatModelStore();
|
|
14
|
+
const bot = startBot(config, opencode, projects, chatProjects, chatModels);
|
|
15
|
+
process.once("SIGINT", () => bot.stop("SIGINT"));
|
|
16
|
+
process.once("SIGTERM", () => bot.stop("SIGTERM"));
|
|
17
|
+
return bot;
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=run.js.map
|
package/dist/run.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAA;AAEtB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AACnC,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAClD,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,4BAA4B,GAC7B,MAAM,YAAY,CAAA;AAEnB,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,EAAE;IACzB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;IAC3B,MAAM,YAAY,GAAG,4BAA4B,EAAE,CAAA;IACnD,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,YAAY,EAAE,CAAC,CAAA;IACxE,MAAM,QAAQ,GAAG,kBAAkB,EAAE,CAAA;IACrC,MAAM,YAAY,GAAG,sBAAsB,EAAE,CAAA;IAC7C,MAAM,UAAU,GAAG,oBAAoB,EAAE,CAAA;IACzC,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,CAAC,CAAA;IAE1E,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAA;IAChD,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAA;IAElD,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA"}
|
package/docs/configuration.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Configuration
|
|
2
2
|
|
|
3
|
-
Set these environment variables in
|
|
3
|
+
Set these environment variables in your shell or service environment.
|
|
4
4
|
|
|
5
5
|
## Required
|
|
6
6
|
- `TELEGRAM_BOT_TOKEN` - Telegram bot token.
|
|
@@ -12,10 +12,13 @@ Set these environment variables in `.env` or in your service environment.
|
|
|
12
12
|
- `OPENCODE_SERVER_PASSWORD` - Basic auth password.
|
|
13
13
|
- `OPENCODE_PROMPT_TIMEOUT_MS` - Prompt timeout in milliseconds (default: 600000).
|
|
14
14
|
- `TELEGRAM_HANDLER_TIMEOUT_MS` - Telegraf handler timeout in milliseconds (default: prompt timeout + 30000).
|
|
15
|
-
- `OPENCODE_RESTART_COMMAND` - Command to restart OpenCode when `/reboot` is used (example: `
|
|
15
|
+
- `OPENCODE_RESTART_COMMAND` - Command to restart OpenCode when `/reboot` is used (example: `systemctl --user restart opencode --no-block`).
|
|
16
16
|
- `OPENCODE_RESTART_TIMEOUT_MS` - Restart command timeout in milliseconds (default: 30000).
|
|
17
|
-
- `OPENCODE_BRIDGE_RESTART_COMMAND` - Command to restart the Telegram bridge when `/restart` is used (example: `
|
|
17
|
+
- `OPENCODE_BRIDGE_RESTART_COMMAND` - Command to restart the Telegram bridge when `/restart` is used (example: `systemctl --user restart opencode-telegram-bridge --no-block`).
|
|
18
18
|
- `OPENCODE_BRIDGE_RESTART_TIMEOUT_MS` - Restart command timeout in milliseconds (default: 30000).
|
|
19
19
|
|
|
20
20
|
## Data storage
|
|
21
21
|
- Project aliases and chat selections are stored in `~/.opencode-telegram-bridge/projects.db`.
|
|
22
|
+
|
|
23
|
+
## systemd user service
|
|
24
|
+
The setup wizard writes a user service env file at `~/.config/opencode-telegram-bridge/opencode-telegram-bridge.env`.
|
package/docs/index.md
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
# OpenCode Telegram Bridge
|
|
2
2
|
|
|
3
|
-
Run a Telegram bot that forwards messages to an OpenCode backend and returns responses.
|
|
3
|
+
Run a Telegram bot that forwards messages to an OpenCode backend and returns responses. These docs are for end users and aim to make setup and operation unambiguous.
|
|
4
4
|
|
|
5
5
|
Start here:
|
|
6
6
|
- Installation
|
|
7
7
|
- Configuration
|
|
8
8
|
- Usage
|
|
9
9
|
- Systemd
|
|
10
|
-
- Release
|
package/docs/installation.md
CHANGED
|
@@ -3,40 +3,21 @@
|
|
|
3
3
|
## Prerequisites
|
|
4
4
|
- Node.js 18+
|
|
5
5
|
- OpenCode CLI installed and available on PATH (see https://opencode.ai/docs/cli/)
|
|
6
|
+
- OpenCode server running (`opencode serve`)
|
|
6
7
|
|
|
7
|
-
## Install
|
|
8
|
+
## Install
|
|
8
9
|
```bash
|
|
9
|
-
npm install
|
|
10
|
+
npm install -g opencode-telegram-bridge
|
|
10
11
|
```
|
|
11
12
|
|
|
12
|
-
##
|
|
13
|
+
## Setup (Linux systemd)
|
|
13
14
|
```bash
|
|
14
|
-
opencode
|
|
15
|
+
opencode-telegram-bridge setup
|
|
15
16
|
```
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
Copy the example file and fill in values:
|
|
19
|
-
```bash
|
|
20
|
-
cp .env.example .env
|
|
21
|
-
```
|
|
18
|
+
Setup currently supports Linux systemd only. On other platforms, run the bot manually.
|
|
22
19
|
|
|
23
20
|
## Run the bot
|
|
24
21
|
```bash
|
|
25
|
-
npm run dev
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
For production, build and run:
|
|
29
|
-
```bash
|
|
30
|
-
npm run build
|
|
31
|
-
npm start
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Install via npm
|
|
35
|
-
```bash
|
|
36
|
-
npm install -g opencode-telegram-bridge
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
Run:
|
|
40
|
-
```bash
|
|
41
22
|
opencode-telegram-bridge
|
|
42
23
|
```
|
package/docs/systemd.md
CHANGED
|
@@ -1,30 +1,35 @@
|
|
|
1
|
-
# systemd Service (Linux)
|
|
1
|
+
# systemd Service (Linux user)
|
|
2
2
|
|
|
3
|
-
This project ships a systemd unit template in `systemd/opencode-telegram-bridge.service`.
|
|
3
|
+
This project ships a user systemd unit template in `systemd/opencode-telegram-bridge.service`.
|
|
4
4
|
|
|
5
|
-
##
|
|
6
|
-
|
|
5
|
+
## Recommended: setup wizard
|
|
6
|
+
```bash
|
|
7
|
+
opencode-telegram-bridge setup
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Manual install
|
|
11
|
+
1. Install the package:
|
|
7
12
|
|
|
8
13
|
```bash
|
|
9
|
-
npm install
|
|
10
|
-
npm run build
|
|
14
|
+
npm install -g opencode-telegram-bridge
|
|
11
15
|
```
|
|
12
16
|
|
|
13
17
|
2. Copy the service and env files:
|
|
14
18
|
|
|
15
19
|
```bash
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
mkdir -p ~/.config/systemd/user
|
|
21
|
+
mkdir -p ~/.config/opencode-telegram-bridge
|
|
22
|
+
cp systemd/opencode-telegram-bridge.service ~/.config/systemd/user/opencode-telegram-bridge.service
|
|
23
|
+
cp systemd/opencode-telegram-bridge.env.example ~/.config/opencode-telegram-bridge/opencode-telegram-bridge.env
|
|
19
24
|
```
|
|
20
25
|
|
|
21
26
|
3. Edit the env file:
|
|
22
27
|
|
|
23
28
|
```bash
|
|
24
|
-
|
|
29
|
+
nano ~/.config/opencode-telegram-bridge/opencode-telegram-bridge.env
|
|
25
30
|
```
|
|
26
31
|
|
|
27
|
-
4. Update the service
|
|
32
|
+
4. Update the service path if needed:
|
|
28
33
|
|
|
29
34
|
- `ExecStart=/usr/bin/opencode-telegram-bridge`
|
|
30
35
|
- If you installed via npm in a non-standard location, set `ExecStart` to the output of `command -v opencode-telegram-bridge`.
|
|
@@ -32,11 +37,18 @@ sudo nano /etc/opencode-telegram-bridge.env
|
|
|
32
37
|
5. Enable and start:
|
|
33
38
|
|
|
34
39
|
```bash
|
|
35
|
-
|
|
36
|
-
|
|
40
|
+
systemctl --user daemon-reload
|
|
41
|
+
systemctl --user enable --now opencode-telegram-bridge
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Start on boot (optional)
|
|
45
|
+
User services normally start on login. To run on boot without a login session:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
sudo loginctl enable-linger $(whoami)
|
|
37
49
|
```
|
|
38
50
|
|
|
39
51
|
## Logs
|
|
40
52
|
```bash
|
|
41
|
-
|
|
53
|
+
journalctl --user -u opencode-telegram-bridge -f
|
|
42
54
|
```
|
package/package.json
CHANGED
|
@@ -6,6 +6,6 @@ OPENCODE_SERVER_PASSWORD=
|
|
|
6
6
|
OPENCODE_PROMPT_TIMEOUT_MS=600000
|
|
7
7
|
TELEGRAM_HANDLER_TIMEOUT_MS=630000
|
|
8
8
|
OPENCODE_RESTART_COMMAND=
|
|
9
|
-
OPENCODE_RESTART_TIMEOUT_MS=
|
|
10
|
-
OPENCODE_BRIDGE_RESTART_COMMAND=
|
|
9
|
+
OPENCODE_RESTART_TIMEOUT_MS=
|
|
10
|
+
OPENCODE_BRIDGE_RESTART_COMMAND=systemctl --user restart opencode-telegram-bridge --no-block
|
|
11
11
|
OPENCODE_BRIDGE_RESTART_TIMEOUT_MS=30000
|
|
@@ -5,10 +5,10 @@ Wants=network-online.target
|
|
|
5
5
|
|
|
6
6
|
[Service]
|
|
7
7
|
Type=simple
|
|
8
|
-
EnvironmentFile
|
|
8
|
+
EnvironmentFile=%h/.config/opencode-telegram-bridge/opencode-telegram-bridge.env
|
|
9
9
|
ExecStart=/usr/bin/opencode-telegram-bridge
|
|
10
10
|
Restart=on-failure
|
|
11
11
|
RestartSec=3
|
|
12
12
|
|
|
13
13
|
[Install]
|
|
14
|
-
WantedBy=
|
|
14
|
+
WantedBy=default.target
|
package/docs/release.md
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
# Release
|
|
2
|
-
|
|
3
|
-
This project is published as an npm package.
|
|
4
|
-
|
|
5
|
-
## Mental model
|
|
6
|
-
Every CI run (PRs and pushes) requires a changeset for non-doc changes or it
|
|
7
|
-
fails. A push to `main` creates or updates the release PR. A merged PR leads to
|
|
8
|
-
a push to `main`, so it also updates the release PR. The release PR accumulates
|
|
9
|
-
changesets until it is merged. When the release PR is merged, npm publishes a
|
|
10
|
-
new version and a GitHub release is created using the accumulated changesets.
|
|
11
|
-
|
|
12
|
-
## CI + release flowcharts
|
|
13
|
-
|
|
14
|
-
### Pull request opened
|
|
15
|
-
```
|
|
16
|
-
PR opened/updated
|
|
17
|
-
|
|
|
18
|
-
v
|
|
19
|
-
CI workflow (pull_request)
|
|
20
|
-
|
|
|
21
|
-
+--> npm ci
|
|
22
|
-
+--> changeset check (diff base...head)
|
|
23
|
-
| |
|
|
24
|
-
| +--> relevant change + no changeset -> FAIL
|
|
25
|
-
| +--> docs-only or has changeset -> OK
|
|
26
|
-
+--> typecheck + tests + build
|
|
27
|
-
|
|
|
28
|
-
v
|
|
29
|
-
Status checks gate merge to main
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
### Push to main
|
|
33
|
-
```
|
|
34
|
-
Push to main
|
|
35
|
-
|
|
|
36
|
-
v
|
|
37
|
-
CI workflow (push)
|
|
38
|
-
|
|
|
39
|
-
+--> npm ci
|
|
40
|
-
+--> changeset check (diff before...after)
|
|
41
|
-
| |
|
|
42
|
-
| +--> relevant change + no changeset -> FAIL
|
|
43
|
-
| +--> docs-only or has changeset -> OK
|
|
44
|
-
+--> typecheck + tests + build
|
|
45
|
-
|
|
|
46
|
-
v
|
|
47
|
-
Release workflow (push)
|
|
48
|
-
|
|
|
49
|
-
+--> changesets/action
|
|
50
|
-
|
|
|
51
|
-
+--> changesets present?
|
|
52
|
-
| |
|
|
53
|
-
| +--> yes: create/update release PR (changeset-release/main)
|
|
54
|
-
| | (no publish)
|
|
55
|
-
| |
|
|
56
|
-
| +--> no: run `npm run release` (publish to npm)
|
|
57
|
-
|
|
|
58
|
-
+--> if published: create GitHub release tag (unless it already exists)
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## Manual release (local)
|
|
62
|
-
1. Add a changeset for your change:
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
npx changeset
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
2. Version the release:
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
npm run version
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
3. Publish:
|
|
75
|
-
|
|
76
|
-
```bash
|
|
77
|
-
npm run release
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
The `prepublishOnly` script runs the build to ensure `dist/` is included.
|
|
81
|
-
|
|
82
|
-
## Required setup (GitHub Actions)
|
|
83
|
-
- Configure npm Trusted Publishing for this repo and workflow file (`release.yml`).
|
|
84
|
-
- The workflow requires `id-token: write` permission to publish via OIDC.
|
|
85
|
-
- npm CLI 11.5.1+ is required for trusted publishing.
|
|
86
|
-
|
|
87
|
-
## CI enforcement
|
|
88
|
-
CI fails if a relevant code change lands without a `.changeset/*.md` file.
|
|
89
|
-
Docs-only updates (`docs/`, `README.md`, `.github/`) do not require a changeset.
|
|
90
|
-
|
|
91
|
-
## FAQ
|
|
92
|
-
|
|
93
|
-
### How is the version bump decided?
|
|
94
|
-
You pick it when you run `npx changeset`. The changeset file records whether the
|
|
95
|
-
change is a `patch`, `minor`, or `major`. When you run `npm run version`, all
|
|
96
|
-
pending changesets are read and the highest required bump wins.
|
|
97
|
-
|
|
98
|
-
### How is the changelog generated?
|
|
99
|
-
The changelog is generated from the text in the changeset files, not from
|
|
100
|
-
commits. Each changeset contributes a short release note entry.
|
|
101
|
-
|
|
102
|
-
### Does each merged PR cause a new package version?
|
|
103
|
-
No. Merged PRs with changesets update the release PR. A new version is published
|
|
104
|
-
only when the release PR is merged.
|
|
105
|
-
|
|
106
|
-
### What happens if I push to main without a changeset?
|
|
107
|
-
CI fails. Add a changeset in a follow-up commit and push again. Do not rewrite
|
|
108
|
-
history on main.
|
|
109
|
-
|
|
110
|
-
### Do I need one changeset per commit or per push?
|
|
111
|
-
No. You need one changeset per release-worthy change (often one per PR). A
|
|
112
|
-
single changeset can cover multiple commits.
|