opencode-telegram-link 1.0.0-rc.1 → 1.0.0-rc.3
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 -3
- package/dist/broker/main.js +386 -366
- package/dist/broker/main.js.map +7 -7
- package/dist/broker/server.d.ts.map +1 -1
- package/dist/plugin.js +2 -2
- package/dist/plugin.js.map +2 -2
- package/dist/setup.d.ts +2 -0
- package/dist/setup.d.ts.map +1 -1
- package/dist/uninstall.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
package/dist/broker/main.js
CHANGED
|
@@ -16704,11 +16704,18 @@ class SetupError extends Error {
|
|
|
16704
16704
|
}
|
|
16705
16705
|
|
|
16706
16706
|
class AsyncPromptReader {
|
|
16707
|
+
input;
|
|
16707
16708
|
iterator;
|
|
16708
16709
|
buffer = "";
|
|
16709
16710
|
constructor(input) {
|
|
16711
|
+
this.input = input;
|
|
16710
16712
|
this.iterator = input[Symbol.asyncIterator]();
|
|
16711
16713
|
}
|
|
16714
|
+
close() {
|
|
16715
|
+
if (this.input && "pause" in this.input && typeof this.input.pause === "function") {
|
|
16716
|
+
this.input.pause();
|
|
16717
|
+
}
|
|
16718
|
+
}
|
|
16712
16719
|
async readLine() {
|
|
16713
16720
|
while (true) {
|
|
16714
16721
|
const newlineIndex = this.buffer.indexOf(`
|
|
@@ -16796,360 +16803,361 @@ async function runInteractiveSetup(options = {}) {
|
|
|
16796
16803
|
const stderr = options.stderr ?? process.stderr;
|
|
16797
16804
|
const fetchImpl = options.fetch ?? fetch;
|
|
16798
16805
|
const reader = new AsyncPromptReader(options.stdin ?? process.stdin);
|
|
16799
|
-
|
|
16800
|
-
|
|
16801
|
-
|
|
16802
|
-
|
|
16806
|
+
try {
|
|
16807
|
+
const now = options.now ?? Date.now;
|
|
16808
|
+
const stateDirectory = options.stateDirectory ?? defaultStateDirectory();
|
|
16809
|
+
const cwd = options.cwd ?? process.cwd();
|
|
16810
|
+
stdout.write(`
|
|
16803
16811
|
\u250C OpenCode Telegram Notifier \u2014 Setup Wizard
|
|
16804
16812
|
\u2502
|
|
16805
16813
|
`);
|
|
16806
|
-
|
|
16814
|
+
stdout.write(`\u25C7 Language / \u8A9E\u8A00:
|
|
16807
16815
|
`);
|
|
16808
|
-
|
|
16816
|
+
stdout.write(`\u2502 1) \u7E41\u9AD4\u4E2D\u6587 (zh-TW) [\u9810\u8A2D/Default]
|
|
16809
16817
|
`);
|
|
16810
|
-
|
|
16818
|
+
stdout.write(`\u2502 2) English (en)
|
|
16811
16819
|
`);
|
|
16812
|
-
|
|
16813
|
-
|
|
16814
|
-
|
|
16815
|
-
|
|
16820
|
+
const langChoice = await reader.ask("\u2502 \u8ACB\u9078\u64C7 / Select [1]: ", stdout, "1");
|
|
16821
|
+
const locale = langChoice === "2" || langChoice.toLowerCase() === "en" ? "en" : "zh-TW";
|
|
16822
|
+
const isZh = locale === "zh-TW";
|
|
16823
|
+
stdout.write(`\u2502
|
|
16816
16824
|
`);
|
|
16817
|
-
|
|
16825
|
+
stdout.write(isZh ? `\u25C7 \u8ACB\u9078\u64C7\u6B64\u6A5F\u5668\u7684\u89D2\u8272 (Role):
|
|
16818
16826
|
\u2502 1) \u7368\u7ACB Gateway \u6A21\u5F0F (Gateway Mode) [\u9810\u8A2D/Default] \u2014 \u64C1\u6709\u5C08\u5C6C Telegram Bot\uFF0C\u53EF\u4F9B\u672C\u6A5F\u8207\u5176\u4ED6\u7BC0\u9EDE\u9023\u7DDA
|
|
16819
16827
|
\u2502 2) \u7BC0\u9EDE Agent \u6A21\u5F0F (Node Agent Mode) \u2014 \u9023\u7DDA\u81F3\u73FE\u6709\u7684 Gateway\uFF0C\u5171\u7528 Telegram Bot
|
|
16820
16828
|
` : `\u25C7 Select machine role:
|
|
16821
16829
|
\u2502 1) Standalone Gateway Mode [Default] \u2014 Owns a Telegram Bot, serves local and remote nodes
|
|
16822
16830
|
\u2502 2) Node Agent Mode \u2014 Connects to an existing Gateway, shares Telegram Bot
|
|
16823
16831
|
`);
|
|
16824
|
-
|
|
16825
|
-
|
|
16826
|
-
|
|
16827
|
-
|
|
16832
|
+
const roleChoice = await reader.ask(isZh ? "\u2502 \u8ACB\u9078\u64C7 / Select [1]: " : "\u2502 Select [1]: ", stdout, "1");
|
|
16833
|
+
const isNode = roleChoice === "2" || roleChoice.toLowerCase().includes("node");
|
|
16834
|
+
const defaultHost = hostname3() || "host";
|
|
16835
|
+
stdout.write(`\u2502
|
|
16828
16836
|
`);
|
|
16829
|
-
|
|
16837
|
+
stdout.write(isZh ? `\u25C7 \u4E3B\u6A5F\u8B58\u5225\u6A19\u7C64 (Host Label) [\u9810\u8A2D: ${defaultHost}]:
|
|
16830
16838
|
\u2502 (\u6B64\u6A19\u7C64\u5C07\u986F\u793A\u65BC Telegram \u901A\u77E5\u9802\u90E8\uFF0C\u4FBF\u65BC\u8B58\u5225\u4F86\u6E90\u4E3B\u6A5F)
|
|
16831
16839
|
` : `\u25C7 Host Label [Default: ${defaultHost}]:
|
|
16832
16840
|
\u2502 (Shown in notification header to identify this machine)
|
|
16833
16841
|
`);
|
|
16834
|
-
|
|
16835
|
-
|
|
16836
|
-
|
|
16837
|
-
|
|
16838
|
-
|
|
16839
|
-
|
|
16840
|
-
|
|
16841
|
-
|
|
16842
|
+
const hostLabel = await reader.ask(isZh ? `\u2502 \u6A19\u7C64\u540D\u7A31 [${defaultHost}]: ` : `\u2502 Label [${defaultHost}]: `, stdout, defaultHost);
|
|
16843
|
+
let configData;
|
|
16844
|
+
let isDocker = false;
|
|
16845
|
+
let pairing;
|
|
16846
|
+
let api2;
|
|
16847
|
+
let botInfo;
|
|
16848
|
+
if (isNode) {
|
|
16849
|
+
stdout.write(`\u2502
|
|
16842
16850
|
`);
|
|
16843
|
-
|
|
16851
|
+
stdout.write(isZh ? `\u25C7 \u8ACB\u8F38\u5165 Central Gateway \u7684 WebSocket \u4F4D\u5740:
|
|
16844
16852
|
\u2502 (\u7BC4\u4F8B: ws://192.168.1.100:42617 \u6216 wss://gateway.example.com)
|
|
16845
16853
|
` : `\u25C7 Enter Central Gateway WebSocket URL:
|
|
16846
16854
|
\u2502 (Example: ws://192.168.1.100:42617 or wss://gateway.example.com)
|
|
16847
16855
|
`);
|
|
16848
|
-
|
|
16849
|
-
|
|
16850
|
-
|
|
16856
|
+
const gatewayUrl = await reader.ask("\u2502 Gateway URL: ", stdout);
|
|
16857
|
+
if (!gatewayUrl) {
|
|
16858
|
+
stderr.write(isZh ? `\u2716 Gateway URL \u4E0D\u80FD\u70BA\u7A7A\u3002
|
|
16851
16859
|
` : `\u2716 Gateway URL cannot be empty.
|
|
16852
16860
|
`);
|
|
16853
|
-
|
|
16854
|
-
|
|
16855
|
-
|
|
16861
|
+
return 1;
|
|
16862
|
+
}
|
|
16863
|
+
stdout.write(`\u2502
|
|
16856
16864
|
`);
|
|
16857
|
-
|
|
16865
|
+
stdout.write(isZh ? `\u25C7 \u8ACB\u8F38\u5165 Gateway \u9023\u7DDA\u91D1\u9470 (Secret Token):
|
|
16858
16866
|
\u2502 (\u82E5 Gateway \u7121\u9700\u91D1\u9470\u53EF\u76F4\u63A5\u6309 Enter)
|
|
16859
16867
|
` : `\u25C7 Enter Gateway Secret Token:
|
|
16860
16868
|
\u2502 (Press Enter if no secret required)
|
|
16861
16869
|
`);
|
|
16862
|
-
|
|
16863
|
-
|
|
16864
|
-
|
|
16865
|
-
|
|
16866
|
-
|
|
16867
|
-
|
|
16868
|
-
|
|
16869
|
-
|
|
16870
|
-
|
|
16871
|
-
|
|
16872
|
-
|
|
16873
|
-
|
|
16874
|
-
|
|
16875
|
-
|
|
16876
|
-
|
|
16877
|
-
|
|
16878
|
-
|
|
16879
|
-
|
|
16880
|
-
|
|
16881
|
-
|
|
16882
|
-
|
|
16883
|
-
|
|
16884
|
-
|
|
16885
|
-
|
|
16886
|
-
|
|
16887
|
-
|
|
16888
|
-
|
|
16889
|
-
|
|
16890
|
-
|
|
16891
|
-
|
|
16870
|
+
const gatewaySecret = await reader.ask("\u2502 Secret: ", stdout, "");
|
|
16871
|
+
configData = {
|
|
16872
|
+
mode: "local",
|
|
16873
|
+
role: "node",
|
|
16874
|
+
hostLabel,
|
|
16875
|
+
locale,
|
|
16876
|
+
gateway: {
|
|
16877
|
+
url: gatewayUrl,
|
|
16878
|
+
secret: gatewaySecret || "default-secret"
|
|
16879
|
+
},
|
|
16880
|
+
notifications: {
|
|
16881
|
+
completion: true,
|
|
16882
|
+
error: true,
|
|
16883
|
+
question: true,
|
|
16884
|
+
permission: true,
|
|
16885
|
+
includeChildLifecycle: false,
|
|
16886
|
+
completionDebounceMs: 1500,
|
|
16887
|
+
pluginBufferSize: 100
|
|
16888
|
+
},
|
|
16889
|
+
broker: {
|
|
16890
|
+
host: "127.0.0.1",
|
|
16891
|
+
port: 42617
|
|
16892
|
+
},
|
|
16893
|
+
interaction: {
|
|
16894
|
+
sessionPromptTtlMinutes: 1440,
|
|
16895
|
+
questionTtlMinutes: 30
|
|
16896
|
+
}
|
|
16897
|
+
};
|
|
16898
|
+
} else {
|
|
16899
|
+
stdout.write(`\u2502
|
|
16892
16900
|
`);
|
|
16893
|
-
|
|
16901
|
+
stdout.write(isZh ? `\u25C7 \u90E8\u7F72\u6A21\u5F0F\u9078\u64C7 / Deployment Mode:
|
|
16894
16902
|
\u2502 1) \u672C\u6A5F\u539F\u751F\u6A21\u5F0F (Native Mode) [\u9810\u8A2D/Default] \u2014 Broker \u4F5C\u70BA\u672C\u6A5F\u5E38\u99D0\u7A0B\u5E8F\uFF0COpenCode \u81EA\u52D5\u5728\u80CC\u666F\u62C9\u8D77
|
|
16895
16903
|
\u2502 2) Docker \u5BB9\u5668\u6A21\u5F0F (Docker Container) \u2014 Broker \u9694\u96E2\u65BC Docker \u5BB9\u5668\u4E2D\u57F7\u884C
|
|
16896
16904
|
` : `\u25C7 Deployment Mode:
|
|
16897
16905
|
\u2502 1) Native Mode [Default] \u2014 Broker runs as a local background process, auto-spawned by OpenCode
|
|
16898
16906
|
\u2502 2) Docker Container Mode \u2014 Broker runs isolated inside a Docker container
|
|
16899
16907
|
`);
|
|
16900
|
-
|
|
16901
|
-
|
|
16902
|
-
|
|
16903
|
-
|
|
16904
|
-
|
|
16905
|
-
|
|
16906
|
-
|
|
16907
|
-
|
|
16908
|
+
const modeChoice = await reader.ask(isZh ? "\u2502 \u8ACB\u9078\u64C7 / Select [1]: " : "\u2502 Select [1]: ", stdout, "1");
|
|
16909
|
+
isDocker = modeChoice === "2" || modeChoice.toLowerCase().includes("docker");
|
|
16910
|
+
let botToken = "";
|
|
16911
|
+
let attempts = 0;
|
|
16912
|
+
while (!botInfo) {
|
|
16913
|
+
attempts += 1;
|
|
16914
|
+
if (attempts > 5) {
|
|
16915
|
+
stderr.write(isZh ? `\u2716 \u8D85\u904E\u91CD\u8A66\u6B21\u6578\uFF0C\u8A2D\u5B9A\u7D42\u6B62\u3002
|
|
16908
16916
|
` : `\u2716 Too many attempts. Aborted.
|
|
16909
16917
|
`);
|
|
16910
|
-
|
|
16911
|
-
|
|
16912
|
-
|
|
16918
|
+
return 1;
|
|
16919
|
+
}
|
|
16920
|
+
stdout.write(`\u2502
|
|
16913
16921
|
`);
|
|
16914
|
-
|
|
16915
|
-
|
|
16922
|
+
if (isZh) {
|
|
16923
|
+
stdout.write(`\u25C7 \u8ACB\u8F38\u5165\u5411 @BotFather \u7533\u8ACB\u7684 Telegram Bot Token:
|
|
16916
16924
|
`);
|
|
16917
|
-
|
|
16925
|
+
stdout.write(`\u2502 (\u7BC4\u4F8B: 123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ)
|
|
16918
16926
|
`);
|
|
16919
|
-
|
|
16920
|
-
|
|
16927
|
+
} else {
|
|
16928
|
+
stdout.write(`\u25C7 Enter your Telegram Bot Token from @BotFather:
|
|
16921
16929
|
`);
|
|
16922
|
-
|
|
16930
|
+
stdout.write(`\u2502 (Example: 123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ)
|
|
16923
16931
|
`);
|
|
16924
|
-
|
|
16925
|
-
|
|
16926
|
-
|
|
16927
|
-
|
|
16932
|
+
}
|
|
16933
|
+
botToken = await reader.ask("\u2502 Token: ", stdout);
|
|
16934
|
+
if (!botToken) {
|
|
16935
|
+
stdout.write(isZh ? `\u2502 \u2716 Token \u4E0D\u80FD\u70BA\u7A7A\uFF0C\u8ACB\u91CD\u65B0\u8F38\u5165\u3002
|
|
16928
16936
|
` : `\u2502 \u2716 Token cannot be empty.
|
|
16929
16937
|
`);
|
|
16930
|
-
|
|
16931
|
-
|
|
16932
|
-
|
|
16933
|
-
|
|
16938
|
+
continue;
|
|
16939
|
+
}
|
|
16940
|
+
if (!/^\d+:[A-Za-z0-9_-]{20,}$/.test(botToken)) {
|
|
16941
|
+
stdout.write(isZh ? `\u2502 \u2716 Token \u683C\u5F0F\u4E0D\u7B26\u5408 Telegram \u898F\u7BC4\uFF0C\u8ACB\u91CD\u65B0\u8F38\u5165\u3002
|
|
16934
16942
|
` : `\u2502 \u2716 Invalid token format.
|
|
16935
16943
|
`);
|
|
16936
|
-
|
|
16937
|
-
|
|
16938
|
-
|
|
16944
|
+
continue;
|
|
16945
|
+
}
|
|
16946
|
+
stdout.write(isZh ? `\u2502 \u280B \u6B63\u5728\u5411 Telegram \u9A57\u8B49 Bot Token...
|
|
16939
16947
|
` : `\u2502 \u280B Verifying Bot Token with Telegram...
|
|
16940
16948
|
`);
|
|
16941
|
-
|
|
16942
|
-
|
|
16943
|
-
|
|
16944
|
-
|
|
16945
|
-
|
|
16949
|
+
api2 = new TelegramBotApi({ token: botToken, fetch: fetchImpl });
|
|
16950
|
+
try {
|
|
16951
|
+
botInfo = await api2.getMe();
|
|
16952
|
+
const botName2 = botInfo.username ? `@${botInfo.username}` : `bot ${botInfo.id}`;
|
|
16953
|
+
stdout.write(isZh ? `\u2502 \u2714 \u9023\u7DDA\u6210\u529F\uFF01\u5DF2\u8FA8\u8B58 Bot: ${botName2} (ID: ${botInfo.id})
|
|
16946
16954
|
` : `\u2502 \u2714 Connected! Identified Bot: ${botName2} (ID: ${botInfo.id})
|
|
16947
16955
|
`);
|
|
16948
|
-
|
|
16949
|
-
|
|
16950
|
-
|
|
16956
|
+
} catch (err) {
|
|
16957
|
+
const errMsg = err instanceof Error ? err.message : "connection failed";
|
|
16958
|
+
stdout.write(isZh ? `\u2502 \u2716 Token \u9A57\u8B49\u5931\u6557 (${errMsg})\uFF0C\u8ACB\u78BA\u8A8D\u5F8C\u91CD\u8A66\u3002
|
|
16951
16959
|
` : `\u2502 \u2716 Verification failed (${errMsg}). Please retry.
|
|
16952
16960
|
`);
|
|
16961
|
+
}
|
|
16953
16962
|
}
|
|
16954
|
-
|
|
16955
|
-
|
|
16956
|
-
|
|
16957
|
-
|
|
16958
|
-
stdout.write(`\u2502
|
|
16963
|
+
api2 = new TelegramBotApi({ token: botToken, fetch: fetchImpl });
|
|
16964
|
+
const nonce = createPairingNonce();
|
|
16965
|
+
const botName = botInfo.username ? `@${botInfo.username}` : `Bot (ID: ${botInfo.id})`;
|
|
16966
|
+
stdout.write(`\u2502
|
|
16959
16967
|
`);
|
|
16960
|
-
|
|
16961
|
-
|
|
16968
|
+
if (isZh) {
|
|
16969
|
+
stdout.write(`\u25C7 [\u8EAB\u5206\u9A57\u8B49\u914D\u5C0D]
|
|
16962
16970
|
`);
|
|
16963
|
-
|
|
16971
|
+
stdout.write(`\u2502 \u8ACB\u5728 Telegram \u6253\u958B\u8207 ${botName} \u7684\u79C1\u804A\u8996\u7A97\uFF0C\u4E26\u767C\u9001\u6B64\u9A57\u8B49\u78BC\uFF1A
|
|
16964
16972
|
`);
|
|
16965
|
-
|
|
16973
|
+
stdout.write(`\u2502
|
|
16966
16974
|
\u2502 \uD83D\uDC49 ${nonce}
|
|
16967
16975
|
\u2502
|
|
16968
16976
|
`);
|
|
16969
|
-
|
|
16977
|
+
stdout.write(`\u2502 \u280B \u7B49\u5F85 Telegram \u79C1\u8A0A\u4E2D...
|
|
16970
16978
|
`);
|
|
16971
|
-
|
|
16972
|
-
|
|
16979
|
+
} else {
|
|
16980
|
+
stdout.write(`\u25C7 [Identity Pairing]
|
|
16973
16981
|
`);
|
|
16974
|
-
|
|
16982
|
+
stdout.write(`\u2502 Open a private chat with ${botName} on Telegram and send this code:
|
|
16975
16983
|
`);
|
|
16976
|
-
|
|
16984
|
+
stdout.write(`\u2502
|
|
16977
16985
|
\u2502 \uD83D\uDC49 ${nonce}
|
|
16978
16986
|
\u2502
|
|
16979
16987
|
`);
|
|
16980
|
-
|
|
16988
|
+
stdout.write(`\u2502 \u280B Waiting for Telegram private message...
|
|
16981
16989
|
`);
|
|
16982
|
-
|
|
16983
|
-
|
|
16984
|
-
|
|
16985
|
-
|
|
16986
|
-
|
|
16987
|
-
|
|
16988
|
-
|
|
16989
|
-
|
|
16990
|
-
|
|
16991
|
-
|
|
16992
|
-
|
|
16990
|
+
}
|
|
16991
|
+
const expiresAt = now() + 120000;
|
|
16992
|
+
try {
|
|
16993
|
+
pairing = await waitForPairingMessage(api2, {
|
|
16994
|
+
nonce,
|
|
16995
|
+
expiresAt,
|
|
16996
|
+
now,
|
|
16997
|
+
pollTimeoutSeconds: 5
|
|
16998
|
+
});
|
|
16999
|
+
} catch {
|
|
17000
|
+
stdout.write(isZh ? `\u2502 \u2716 \u914D\u5C0D\u8D85\u6642\u6216\u672A\u6536\u5230\u6709\u6548\u8A0A\u606F\uFF0C\u8A2D\u5B9A\u4E2D\u6B62\u3002
|
|
16993
17001
|
` : `\u2502 \u2716 Pairing timed out or no valid message received. Aborted.
|
|
16994
17002
|
`);
|
|
16995
|
-
|
|
16996
|
-
|
|
16997
|
-
|
|
17003
|
+
return 1;
|
|
17004
|
+
}
|
|
17005
|
+
stdout.write(isZh ? `\u2502 \u2714 \u6536\u5230\u9A57\u8B49\u8A0A\u606F\uFF01\u4F86\u81EA Telegram \u7528\u6236 (ID: ${pairing.userId}, Chat: ${pairing.chatId})
|
|
16998
17006
|
` : `\u2502 \u2714 Received pairing message! Telegram User (ID: ${pairing.userId}, Chat: ${pairing.chatId})
|
|
16999
17007
|
`);
|
|
17000
|
-
|
|
17001
|
-
|
|
17002
|
-
|
|
17008
|
+
const confirmBind = await reader.ask(isZh ? "\u2502 \u662F\u5426\u5C07\u6B64 Telegram \u5E33\u865F\u7D81\u5B9A\u70BA OpenCode \u7BA1\u7406\u54E1\uFF1F [Y/n]: " : "\u2502 Authorize this Telegram user for OpenCode notifications & replies? [Y/n]: ", stdout, "Y");
|
|
17009
|
+
if (confirmBind.toLowerCase() === "n" || confirmBind.toLowerCase() === "no") {
|
|
17010
|
+
stdout.write(isZh ? `\u2502 \u2716 \u5DF2\u53D6\u6D88\u7D81\u5B9A\u3002
|
|
17003
17011
|
` : `\u2502 \u2716 Pairing cancelled.
|
|
17004
17012
|
`);
|
|
17005
|
-
|
|
17006
|
-
|
|
17007
|
-
|
|
17008
|
-
|
|
17009
|
-
|
|
17010
|
-
|
|
17013
|
+
return 1;
|
|
17014
|
+
}
|
|
17015
|
+
const tokenFile = join5(stateDirectory, "telegram-bot-token");
|
|
17016
|
+
await writePrivateTokenFile(stateDirectory, tokenFile, botToken);
|
|
17017
|
+
const identityFile = join5(stateDirectory, "telegram-identity.json");
|
|
17018
|
+
await writeFile3(identityFile, `${JSON.stringify({ userId: pairing.userId, chatId: pairing.chatId, tokenFile, locale }, null, 2)}
|
|
17011
17019
|
`, "utf8");
|
|
17012
|
-
|
|
17020
|
+
stdout.write(isZh ? `\u2502 \u2714 \u5B89\u5168 Token \u6A94\u6848\u5DF2\u5132\u5B58 (${tokenFile})
|
|
17013
17021
|
` : `\u2502 \u2714 Secure token file saved (${tokenFile})
|
|
17014
17022
|
`);
|
|
17015
|
-
|
|
17016
|
-
|
|
17017
|
-
|
|
17018
|
-
|
|
17019
|
-
|
|
17020
|
-
|
|
17021
|
-
|
|
17022
|
-
|
|
17023
|
-
|
|
17024
|
-
|
|
17025
|
-
|
|
17026
|
-
|
|
17027
|
-
|
|
17028
|
-
|
|
17029
|
-
|
|
17030
|
-
|
|
17031
|
-
|
|
17032
|
-
|
|
17033
|
-
|
|
17034
|
-
|
|
17035
|
-
|
|
17036
|
-
|
|
17037
|
-
|
|
17038
|
-
|
|
17039
|
-
|
|
17040
|
-
|
|
17041
|
-
|
|
17042
|
-
|
|
17043
|
-
|
|
17044
|
-
|
|
17023
|
+
configData = {
|
|
17024
|
+
mode: "local",
|
|
17025
|
+
role: "gateway",
|
|
17026
|
+
hostLabel,
|
|
17027
|
+
locale,
|
|
17028
|
+
telegram: {
|
|
17029
|
+
tokenFile,
|
|
17030
|
+
userId: pairing.userId,
|
|
17031
|
+
chatId: pairing.chatId
|
|
17032
|
+
},
|
|
17033
|
+
notifications: {
|
|
17034
|
+
completion: true,
|
|
17035
|
+
error: true,
|
|
17036
|
+
question: true,
|
|
17037
|
+
permission: true,
|
|
17038
|
+
includeChildLifecycle: false,
|
|
17039
|
+
completionDebounceMs: 1500,
|
|
17040
|
+
pluginBufferSize: 100
|
|
17041
|
+
},
|
|
17042
|
+
broker: {
|
|
17043
|
+
host: "127.0.0.1",
|
|
17044
|
+
port: 42617
|
|
17045
|
+
},
|
|
17046
|
+
interaction: {
|
|
17047
|
+
sessionPromptTtlMinutes: 1440,
|
|
17048
|
+
questionTtlMinutes: 30
|
|
17049
|
+
}
|
|
17050
|
+
};
|
|
17051
|
+
}
|
|
17052
|
+
stdout.write(`\u2502
|
|
17045
17053
|
`);
|
|
17046
|
-
|
|
17047
|
-
|
|
17048
|
-
|
|
17049
|
-
|
|
17050
|
-
|
|
17051
|
-
|
|
17052
|
-
|
|
17054
|
+
const discovered = await discoverOpenCodeConfigFiles(cwd);
|
|
17055
|
+
const existingConfigs = discovered.filter((d) => d.exists);
|
|
17056
|
+
const fallback = discovered.find((d) => !d.isWorkspace) ?? discovered[0];
|
|
17057
|
+
const targets = existingConfigs.length > 0 ? existingConfigs : fallback ? [fallback] : [];
|
|
17058
|
+
if (targets.length > 0) {
|
|
17059
|
+
const descList = targets.map((t) => `${t.path} [${t.exists ? isZh ? "\u5DF2\u5B58\u5728" : "existing" : isZh ? "\u5C07\u81EA\u52D5\u5EFA\u7ACB" : "will create"}]`).join(", ");
|
|
17060
|
+
stdout.write(isZh ? `\u25C7 \u5075\u6E2C\u5230 OpenCode \u8A2D\u5B9A\u6A94 (${descList})
|
|
17053
17061
|
` : `\u25C7 Discovered OpenCode config file(s) (${descList})
|
|
17054
17062
|
`);
|
|
17055
|
-
|
|
17056
|
-
|
|
17057
|
-
|
|
17058
|
-
|
|
17059
|
-
|
|
17060
|
-
|
|
17063
|
+
const autoWrite = await reader.ask(isZh ? "\u2502 \u662F\u5426\u81EA\u52D5\u5BEB\u5165\u5916\u639B\u8A2D\u5B9A\uFF1F [Y/n]: " : "\u2502 Automatically update OpenCode config file(s)? [Y/n]: ", stdout, "Y");
|
|
17064
|
+
if (autoWrite.toLowerCase() !== "n" && autoWrite.toLowerCase() !== "no") {
|
|
17065
|
+
for (const target of targets) {
|
|
17066
|
+
try {
|
|
17067
|
+
const { backupPath } = await injectOpenCodeConfig(target.path, configData);
|
|
17068
|
+
stdout.write(isZh ? `\u2502 \u2714 OpenCode \u8A2D\u5B9A\u6A94\u5DF2\u66F4\u65B0: ${target.path}${backupPath ? ` (\u5099\u4EFD\u65BC ${backupPath})` : ""}
|
|
17061
17069
|
` : `\u2502 \u2714 OpenCode config updated: ${target.path}${backupPath ? ` (backup at ${backupPath})` : ""}
|
|
17062
17070
|
`);
|
|
17063
|
-
|
|
17064
|
-
|
|
17065
|
-
|
|
17071
|
+
} catch (err) {
|
|
17072
|
+
const errMsg = err instanceof Error ? err.message : "failed to write config";
|
|
17073
|
+
stdout.write(isZh ? `\u2502 \u2716 \u8A2D\u5B9A\u6A94\u5BEB\u5165\u5931\u6557 (${target.path}): ${errMsg}
|
|
17066
17074
|
` : `\u2502 \u2716 Failed to write config (${target.path}): ${errMsg}
|
|
17067
17075
|
`);
|
|
17076
|
+
}
|
|
17068
17077
|
}
|
|
17069
|
-
}
|
|
17070
|
-
|
|
17071
|
-
stdout.write(isZh ? `\u2502 \u8ACB\u624B\u52D5\u5C07\u4E0B\u5217\u8A2D\u5B9A\u52A0\u5165\u60A8\u7684 opencode.json:
|
|
17078
|
+
} else {
|
|
17079
|
+
stdout.write(isZh ? `\u2502 \u8ACB\u624B\u52D5\u5C07\u4E0B\u5217\u8A2D\u5B9A\u52A0\u5165\u60A8\u7684 opencode.json:
|
|
17072
17080
|
` : `\u2502 Please add the following configuration to your opencode.json:
|
|
17073
17081
|
`);
|
|
17074
|
-
|
|
17082
|
+
stdout.write(`\u2502
|
|
17075
17083
|
${generatePluginConfigSnippet(configData)}
|
|
17076
17084
|
\u2502
|
|
17077
17085
|
`);
|
|
17086
|
+
}
|
|
17078
17087
|
}
|
|
17079
|
-
|
|
17080
|
-
|
|
17081
|
-
|
|
17082
|
-
stdout.write(`\u2502
|
|
17088
|
+
let dockerFailed = false;
|
|
17089
|
+
if (isDocker) {
|
|
17090
|
+
stdout.write(`\u2502
|
|
17083
17091
|
`);
|
|
17084
|
-
|
|
17085
|
-
|
|
17086
|
-
|
|
17092
|
+
const autoStartDocker = await reader.ask(isZh ? "\u25C7 \u662F\u5426\u7ACB\u5373\u5728\u80CC\u666F\u81EA\u52D5\u5EFA\u7F6E\u4E26\u555F\u52D5 Docker Broker \u5BB9\u5668\uFF1F [Y/n]: " : "\u25C7 Build and start Docker Broker container in background now? [Y/n]: ", stdout, "Y");
|
|
17093
|
+
if (autoStartDocker.toLowerCase() !== "n" && autoStartDocker.toLowerCase() !== "no") {
|
|
17094
|
+
stdout.write(isZh ? `\u2502 \u280B \u6B63\u5728\u5EFA\u7F6E\u4E26\u555F\u52D5 Docker \u5BB9\u5668 (docker compose up -d --build)...
|
|
17087
17095
|
` : `\u2502 \u280B Building and starting Docker container (docker compose up -d --build)...
|
|
17088
17096
|
`);
|
|
17089
|
-
|
|
17090
|
-
|
|
17091
|
-
|
|
17092
|
-
|
|
17093
|
-
|
|
17094
|
-
}
|
|
17095
|
-
const result = Bun.spawnSync([
|
|
17096
|
-
dockerCmd,
|
|
17097
|
-
"compose",
|
|
17098
|
-
"-f",
|
|
17099
|
-
composeCtx.composeFile,
|
|
17100
|
-
"--project-directory",
|
|
17101
|
-
composeCtx.projectDir,
|
|
17102
|
-
"up",
|
|
17103
|
-
"-d",
|
|
17104
|
-
"--build"
|
|
17105
|
-
], {
|
|
17106
|
-
cwd: composeCtx.projectDir,
|
|
17107
|
-
env: {
|
|
17108
|
-
...process.env,
|
|
17109
|
-
HOME: process.env.HOME || process.env.USERPROFILE || ""
|
|
17097
|
+
try {
|
|
17098
|
+
const dockerCmd = process.platform === "win32" ? "docker.exe" : "docker";
|
|
17099
|
+
const composeCtx = resolveDockerComposeContext(cwd);
|
|
17100
|
+
if (!composeCtx) {
|
|
17101
|
+
throw new Error("Could not find docker-compose.yml in project or package directory");
|
|
17110
17102
|
}
|
|
17111
|
-
|
|
17112
|
-
|
|
17113
|
-
|
|
17103
|
+
const result = Bun.spawnSync([
|
|
17104
|
+
dockerCmd,
|
|
17105
|
+
"compose",
|
|
17106
|
+
"-f",
|
|
17107
|
+
composeCtx.composeFile,
|
|
17108
|
+
"--project-directory",
|
|
17109
|
+
composeCtx.projectDir,
|
|
17110
|
+
"up",
|
|
17111
|
+
"-d",
|
|
17112
|
+
"--build"
|
|
17113
|
+
], {
|
|
17114
|
+
cwd: composeCtx.projectDir,
|
|
17115
|
+
env: {
|
|
17116
|
+
...process.env,
|
|
17117
|
+
HOME: process.env.HOME || process.env.USERPROFILE || ""
|
|
17118
|
+
}
|
|
17119
|
+
});
|
|
17120
|
+
if (result.exitCode === 0) {
|
|
17121
|
+
stdout.write(isZh ? `\u2502 \u2714 Docker Broker \u5BB9\u5668\u5DF2\u6210\u529F\u5728\u80CC\u666F\u555F\u52D5\uFF01
|
|
17114
17122
|
` : `\u2502 \u2714 Docker Broker container started in background!
|
|
17115
17123
|
`);
|
|
17116
|
-
|
|
17117
|
-
|
|
17118
|
-
|
|
17119
|
-
|
|
17124
|
+
} else {
|
|
17125
|
+
dockerFailed = true;
|
|
17126
|
+
const stderr2 = result.stderr ? new TextDecoder().decode(result.stderr).trim() : "";
|
|
17127
|
+
stdout.write(isZh ? `\u2502 \u2716 Docker \u81EA\u52D5\u555F\u52D5\u672A\u6210\u529F${stderr2 ? ` (${stderr2})` : ""}\uFF08\u8ACB\u78BA\u8A8D Docker Desktop \u662F\u5426\u904B\u884C\u4E2D\uFF09\u3002
|
|
17120
17128
|
` : `\u2502 \u2716 Docker start failed${stderr2 ? ` (${stderr2})` : ""} (please check if Docker is running).
|
|
17121
17129
|
`);
|
|
17122
|
-
|
|
17130
|
+
stdout.write(isZh ? `\u2502 \u60A8\u53EF\u65BC\u7A0D\u5F8C\u624B\u52D5\u57F7\u884C: docker compose -f "${composeCtx.composeFile}" up -d
|
|
17123
17131
|
` : `\u2502 You can manually run later: docker compose -f "${composeCtx.composeFile}" up -d
|
|
17124
17132
|
`);
|
|
17125
|
-
|
|
17126
|
-
|
|
17127
|
-
|
|
17128
|
-
|
|
17129
|
-
|
|
17133
|
+
}
|
|
17134
|
+
} catch (err) {
|
|
17135
|
+
dockerFailed = true;
|
|
17136
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
17137
|
+
stdout.write(isZh ? `\u2502 \u2716 Docker \u555F\u52D5\u5931\u6557: ${msg}\uFF0C\u60A8\u53EF\u65BC\u5B89\u88DD/\u555F\u52D5 Docker \u5F8C\u624B\u52D5\u57F7\u884C docker compose up -d
|
|
17130
17138
|
` : `\u2502 \u2716 Docker startup failed: ${msg}. You can run 'docker compose up -d' after installing/starting Docker.
|
|
17131
17139
|
`);
|
|
17132
|
-
|
|
17133
|
-
|
|
17134
|
-
|
|
17140
|
+
}
|
|
17141
|
+
} else {
|
|
17142
|
+
stdout.write(isZh ? `\u2502 \u60A8\u53EF\u65BC\u7A0D\u5F8C\u624B\u52D5\u555F\u52D5\u5BB9\u5668: docker compose up -d
|
|
17135
17143
|
` : `\u2502 You can manually start the container later: docker compose up -d
|
|
17136
17144
|
`);
|
|
17137
|
-
|
|
17138
|
-
|
|
17139
|
-
|
|
17145
|
+
}
|
|
17146
|
+
} else {
|
|
17147
|
+
stdout.write(`\u2502
|
|
17140
17148
|
`);
|
|
17141
|
-
|
|
17149
|
+
stdout.write(isZh ? `\u2502 \u2714 \u672C\u6A5F\u539F\u751F\u6A21\u5F0F\u5DF2\u8A2D\u5B9A\u5B8C\u6210\uFF01\u7576 OpenCode \u555F\u52D5\u6642\u5C07\u81EA\u52D5\u5728\u80CC\u666F\u63A5\u7BA1 Broker\u3002
|
|
17142
17150
|
` : `\u2502 \u2714 Native mode configured! OpenCode will automatically manage Broker in background.
|
|
17143
17151
|
`);
|
|
17144
|
-
|
|
17145
|
-
|
|
17146
|
-
|
|
17152
|
+
}
|
|
17153
|
+
if (!isNode && pairing && api2) {
|
|
17154
|
+
stdout.write(`\u2502
|
|
17147
17155
|
`);
|
|
17148
|
-
|
|
17149
|
-
|
|
17150
|
-
|
|
17151
|
-
|
|
17152
|
-
|
|
17156
|
+
const sendTest = await reader.ask(isZh ? "\u25C7 \u662F\u5426\u767C\u9001\u6E2C\u8A66\u901A\u77E5\u5230\u60A8\u7684 Telegram\uFF1F [Y/n]: " : "\u25C7 Send a welcome test notification to your Telegram now? [Y/n]: ", stdout, "Y");
|
|
17157
|
+
if (sendTest.toLowerCase() !== "n" && sendTest.toLowerCase() !== "no") {
|
|
17158
|
+
try {
|
|
17159
|
+
const botDisplayName = botInfo?.username ? `@${botInfo.username}` : `Bot (ID: ${botInfo?.id})`;
|
|
17160
|
+
const welcomeText = isZh ? `\uD83C\uDF89 <b>OpenCode Telegram Notifier \u8A2D\u5B9A\u6210\u529F\uFF01</b>
|
|
17153
17161
|
|
|
17154
17162
|
\u5DF2\u6210\u529F\u7D81\u5B9A\u4E3B\u6A5F [${hostLabel}] \u8207 Telegram\u3002
|
|
17155
17163
|
\u7576 OpenCode \u4EFB\u52D9\u5B8C\u6210\u3001\u767C\u751F\u7570\u5E38\u6216\u9700\u8981\u56DE\u8986\u6642\uFF0C\u60A8\u5C07\u5728\u6B64\u6536\u5230\u5373\u6642\u901A\u77E5\u3002
|
|
@@ -17162,38 +17170,41 @@ You will receive notifications here when sessions finish or require input.
|
|
|
17162
17170
|
|
|
17163
17171
|
\u2022 Bot: ${botDisplayName}
|
|
17164
17172
|
\u2022 Authorized User ID: <code>${pairing.userId}</code>`;
|
|
17165
|
-
|
|
17166
|
-
|
|
17167
|
-
|
|
17168
|
-
|
|
17169
|
-
|
|
17170
|
-
|
|
17173
|
+
await api2.sendMessage({
|
|
17174
|
+
chatId: pairing.chatId,
|
|
17175
|
+
text: welcomeText,
|
|
17176
|
+
parseMode: "HTML"
|
|
17177
|
+
});
|
|
17178
|
+
stdout.write(isZh ? `\u2502 \u2714 \u5DF2\u6210\u529F\u767C\u9001\u6E2C\u8A66\u901A\u77E5\u5230\u60A8\u7684 Telegram\uFF01\u8ACB\u6AA2\u67E5\u624B\u6A5F\u8A0A\u606F\u3002
|
|
17171
17179
|
` : `\u2502 \u2714 Test notification sent to your Telegram! Please check your messages.
|
|
17172
17180
|
`);
|
|
17173
|
-
|
|
17174
|
-
|
|
17175
|
-
|
|
17181
|
+
} catch (err) {
|
|
17182
|
+
const errMsg = err instanceof Error ? err.message : "send failed";
|
|
17183
|
+
stdout.write(isZh ? `\u2502 \u2716 \u6E2C\u8A66\u901A\u77E5\u767C\u9001\u5931\u6557: ${errMsg}
|
|
17176
17184
|
` : `\u2502 \u2716 Failed to send test notification: ${errMsg}
|
|
17177
17185
|
`);
|
|
17186
|
+
}
|
|
17178
17187
|
}
|
|
17179
17188
|
}
|
|
17180
|
-
|
|
17181
|
-
stdout.write(`\u2502
|
|
17189
|
+
stdout.write(`\u2502
|
|
17182
17190
|
`);
|
|
17183
|
-
|
|
17184
|
-
|
|
17191
|
+
if (dockerFailed) {
|
|
17192
|
+
stdout.write(isZh ? `\u2514 \u26A0 \u8A2D\u5B9A\u6A94\u5DF2\u5BEB\u5165\uFF0C\u4F46 Docker \u5BB9\u5668\u555F\u52D5\u5931\u6557\u3002\u8ACB\u78BA\u8A8D Docker \u670D\u52D9\u904B\u884C\u5F8C\u624B\u52D5\u555F\u52D5\u5BB9\u5668\u3002
|
|
17185
17193
|
|
|
17186
17194
|
` : `\u2514 \u26A0 Configuration written, but Docker container failed to start. Please ensure Docker is running and start the container manually.
|
|
17187
17195
|
|
|
17188
17196
|
`);
|
|
17189
|
-
|
|
17190
|
-
|
|
17191
|
-
|
|
17197
|
+
return 1;
|
|
17198
|
+
}
|
|
17199
|
+
stdout.write(isZh ? `\u2514 \uD83C\uDF89 \u5B89\u88DD\u8A2D\u5B9A\u5B8C\u6210\uFF01\u60A8\u73FE\u5728\u53EF\u4EE5\u56DE\u5230 OpenCode \u958B\u59CB\u5DE5\u4F5C\u3002
|
|
17192
17200
|
|
|
17193
17201
|
` : `\u2514 \uD83C\uDF89 Setup completed! You can now return to OpenCode and start working.
|
|
17194
17202
|
|
|
17195
17203
|
`);
|
|
17196
|
-
|
|
17204
|
+
return 0;
|
|
17205
|
+
} finally {
|
|
17206
|
+
reader.close();
|
|
17207
|
+
}
|
|
17197
17208
|
}
|
|
17198
17209
|
async function runSetupCli(options = {}) {
|
|
17199
17210
|
const argv = options.argv ?? process.argv.slice(2);
|
|
@@ -17975,7 +17986,7 @@ function rejectionHash(updateId, reason) {
|
|
|
17975
17986
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
17976
17987
|
|
|
17977
17988
|
// src/version.ts
|
|
17978
|
-
var PACKAGE_VERSION = "1.0.0-rc.
|
|
17989
|
+
var PACKAGE_VERSION = "1.0.0-rc.3";
|
|
17979
17990
|
|
|
17980
17991
|
// src/telegram/commands.ts
|
|
17981
17992
|
function isSlashCommand(text) {
|
|
@@ -20100,7 +20111,9 @@ class BrokerServer {
|
|
|
20100
20111
|
clearInterval(this.#livenessTimer);
|
|
20101
20112
|
clearInterval(this.#maintenanceTimer);
|
|
20102
20113
|
failPendingCommands(this.#pendingCommands, "broker stopped");
|
|
20103
|
-
|
|
20114
|
+
try {
|
|
20115
|
+
await this.#telegramRuntimeRef.value?.stop();
|
|
20116
|
+
} catch {}
|
|
20104
20117
|
await this.#server.stop(true);
|
|
20105
20118
|
this.#connections.clear();
|
|
20106
20119
|
await this.#removeDiscovery();
|
|
@@ -20939,7 +20952,9 @@ ${replyText}`,
|
|
|
20939
20952
|
if (this.#deliveryTimer)
|
|
20940
20953
|
clearInterval(this.#deliveryTimer);
|
|
20941
20954
|
this.#deliveryTimer = undefined;
|
|
20942
|
-
|
|
20955
|
+
try {
|
|
20956
|
+
await this.#poller.stop();
|
|
20957
|
+
} catch {}
|
|
20943
20958
|
}
|
|
20944
20959
|
publish(notification) {
|
|
20945
20960
|
if (!this.#registry.resolve(notification.route)) {
|
|
@@ -21690,161 +21705,165 @@ async function runInteractiveUninstall(options = {}) {
|
|
|
21690
21705
|
const stdout = options.stdout ?? process.stdout;
|
|
21691
21706
|
const stderr = options.stderr ?? process.stderr;
|
|
21692
21707
|
const reader = new AsyncPromptReader(options.stdin ?? process.stdin);
|
|
21693
|
-
|
|
21694
|
-
|
|
21695
|
-
|
|
21696
|
-
|
|
21708
|
+
try {
|
|
21709
|
+
const stateDirectory = options.stateDirectory ?? defaultStateDirectory();
|
|
21710
|
+
const cwd = options.cwd ?? process.cwd();
|
|
21711
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
21712
|
+
stdout.write(`
|
|
21697
21713
|
\u250C OpenCode Telegram Notifier \u2014 Uninstaller / \u79FB\u9664\u7CBE\u9748
|
|
21698
21714
|
\u2502
|
|
21699
21715
|
`);
|
|
21700
|
-
|
|
21716
|
+
stdout.write(`\u25C7 Language / \u8A9E\u8A00:
|
|
21701
21717
|
`);
|
|
21702
|
-
|
|
21718
|
+
stdout.write(`\u2502 1) \u7E41\u9AD4\u4E2D\u6587 (zh-TW) [\u9810\u8A2D/Default]
|
|
21703
21719
|
`);
|
|
21704
|
-
|
|
21720
|
+
stdout.write(`\u2502 2) English (en)
|
|
21705
21721
|
`);
|
|
21706
|
-
|
|
21707
|
-
|
|
21708
|
-
|
|
21709
|
-
|
|
21722
|
+
const langChoice = await reader.ask("\u2502 \u8ACB\u9078\u64C7 / Select [1]: ", stdout, "1");
|
|
21723
|
+
const locale = langChoice === "2" || langChoice.toLowerCase() === "en" ? "en" : "zh-TW";
|
|
21724
|
+
const isZh = locale === "zh-TW";
|
|
21725
|
+
stdout.write(`\u2502
|
|
21710
21726
|
`);
|
|
21711
|
-
|
|
21712
|
-
|
|
21713
|
-
|
|
21727
|
+
const confirm = await reader.ask(isZh ? "\u25C7 \u662F\u5426\u78BA\u8A8D\u8981\u89E3\u9664\u5B89\u88DD OpenCode Telegram Notifier\uFF1F [y/N]: " : "\u25C7 Are you sure you want to uninstall OpenCode Telegram Notifier? [y/N]: ", stdout, "N");
|
|
21728
|
+
if (confirm.toLowerCase() !== "y" && confirm.toLowerCase() !== "yes") {
|
|
21729
|
+
stdout.write(isZh ? `\u2502 \u64CD\u4F5C\u5DF2\u53D6\u6D88\u3002
|
|
21714
21730
|
\u2514 \uD83D\uDC4B \u7D50\u675F\u3002
|
|
21715
21731
|
|
|
21716
21732
|
` : `\u2502 Aborted.
|
|
21717
21733
|
\u2514 \uD83D\uDC4B Done.
|
|
21718
21734
|
|
|
21719
21735
|
`);
|
|
21720
|
-
|
|
21721
|
-
|
|
21722
|
-
|
|
21736
|
+
return 0;
|
|
21737
|
+
}
|
|
21738
|
+
stdout.write(`\u2502
|
|
21723
21739
|
`);
|
|
21724
|
-
|
|
21740
|
+
stdout.write(isZh ? `\u25C7 [1/4] \u6B63\u5728\u6AA2\u67E5\u4E26\u505C\u6B62\u57F7\u884C\u4E2D\u7684 Broker (\u672C\u6A5F\u7A0B\u5E8F\u6216 Docker \u5BB9\u5668)...
|
|
21725
21741
|
` : `\u25C7 [1/4] Checking and stopping running Broker (native process or Docker container)...
|
|
21726
21742
|
`);
|
|
21727
|
-
|
|
21728
|
-
|
|
21729
|
-
|
|
21730
|
-
|
|
21731
|
-
|
|
21743
|
+
try {
|
|
21744
|
+
const dockerCmd = process.platform === "win32" ? "docker.exe" : "docker";
|
|
21745
|
+
const dockerDown = Bun.spawnSync([dockerCmd, "compose", "down"], { cwd });
|
|
21746
|
+
if (dockerDown.exitCode === 0) {
|
|
21747
|
+
stdout.write(isZh ? `\u2502 \u2714 Docker Broker \u5BB9\u5668\u5DF2\u505C\u6B62\u4E26\u6E05\u7406\u3002
|
|
21732
21748
|
` : `\u2502 \u2714 Docker Broker container stopped and cleaned up.
|
|
21733
21749
|
`);
|
|
21734
|
-
|
|
21735
|
-
|
|
21736
|
-
|
|
21737
|
-
|
|
21738
|
-
|
|
21739
|
-
|
|
21740
|
-
|
|
21741
|
-
|
|
21750
|
+
}
|
|
21751
|
+
} catch {}
|
|
21752
|
+
try {
|
|
21753
|
+
const identity = await loadOrCreateStateIdentity(stateDirectory);
|
|
21754
|
+
const isRunning = await probeBroker(42617, identity.brokerSecret);
|
|
21755
|
+
if (isRunning) {
|
|
21756
|
+
await runStopCommand({ stateDirectory, port: 42617 }, { stdout, stderr }, fetchImpl);
|
|
21757
|
+
stdout.write(isZh ? `\u2502 \u2714 \u672C\u6A5F Broker \u5DF2\u6210\u529F\u505C\u6B62\u3002
|
|
21742
21758
|
` : `\u2502 \u2714 Local broker stopped.
|
|
21743
21759
|
`);
|
|
21744
|
-
|
|
21745
|
-
|
|
21760
|
+
} else {
|
|
21761
|
+
stdout.write(isZh ? `\u2502 \u2714 \u672C\u6A5F Broker \u672A\u5728\u57F7\u884C\u4E2D\u3002
|
|
21746
21762
|
` : `\u2502 \u2714 Local broker is not running.
|
|
21747
21763
|
`);
|
|
21748
|
-
|
|
21749
|
-
|
|
21750
|
-
|
|
21764
|
+
}
|
|
21765
|
+
} catch {
|
|
21766
|
+
stdout.write(isZh ? `\u2502 \u2714 \u672A\u627E\u5230\u57F7\u884C\u4E2D\u7684\u672C\u6A5F Broker \u6216\u5DF2\u505C\u6B62\u3002
|
|
21751
21767
|
` : `\u2502 \u2714 No active local broker found or already stopped.
|
|
21752
21768
|
`);
|
|
21753
|
-
|
|
21754
|
-
|
|
21769
|
+
}
|
|
21770
|
+
stdout.write(`\u2502
|
|
21755
21771
|
`);
|
|
21756
|
-
|
|
21772
|
+
stdout.write(isZh ? `\u25C7 [2/4] \u6B63\u5728\u641C\u5C0B OpenCode \u8A2D\u5B9A\u6A94...
|
|
21757
21773
|
` : `\u25C7 [2/4] Searching for OpenCode configuration files...
|
|
21758
21774
|
`);
|
|
21759
|
-
|
|
21760
|
-
|
|
21761
|
-
|
|
21762
|
-
|
|
21763
|
-
|
|
21764
|
-
|
|
21765
|
-
|
|
21766
|
-
|
|
21767
|
-
|
|
21775
|
+
const discoveredConfigs = await discoverOpenCodeConfigFiles(cwd);
|
|
21776
|
+
const existingConfigs = discoveredConfigs.filter((c) => c.exists);
|
|
21777
|
+
if (existingConfigs.length > 0) {
|
|
21778
|
+
const cleanConfig = await reader.ask(isZh ? `\u2502 \u627E\u5230 ${existingConfigs.length} \u500B\u8A2D\u5B9A\u6A94\uFF0C\u662F\u5426\u5F9E\u4E2D\u79FB\u9664\u5916\u639B\u8A2D\u5B9A\uFF1F [Y/n]: ` : `\u2502 Found ${existingConfigs.length} config file(s). Remove plugin configuration? [Y/n]: `, stdout, "Y");
|
|
21779
|
+
if (cleanConfig.toLowerCase() !== "n" && cleanConfig.toLowerCase() !== "no") {
|
|
21780
|
+
for (const config2 of existingConfigs) {
|
|
21781
|
+
const { modified, backupPath } = await removeOpenCodeConfig(config2.path);
|
|
21782
|
+
if (modified) {
|
|
21783
|
+
stdout.write(isZh ? `\u2502 \u2714 \u5DF2\u5F9E ${config2.path} \u79FB\u9664\u5916\u639B\u8A2D\u5B9A${backupPath ? ` (\u5099\u4EFD\u65BC ${backupPath})` : ""}
|
|
21768
21784
|
` : `\u2502 \u2714 Removed plugin config from ${config2.path}${backupPath ? ` (backup at ${backupPath})` : ""}
|
|
21769
21785
|
`);
|
|
21770
|
-
|
|
21771
|
-
|
|
21786
|
+
} else {
|
|
21787
|
+
stdout.write(isZh ? `\u2502 - ${config2.path} \u672A\u5305\u542B\u672C\u5916\u639B\u8A2D\u5B9A\u3002
|
|
21772
21788
|
` : `\u2502 - No plugin config in ${config2.path}.
|
|
21773
21789
|
`);
|
|
21790
|
+
}
|
|
21774
21791
|
}
|
|
21775
21792
|
}
|
|
21776
|
-
|
|
21777
|
-
|
|
21778
|
-
|
|
21779
|
-
|
|
21780
|
-
|
|
21781
|
-
|
|
21782
|
-
|
|
21783
|
-
|
|
21784
|
-
|
|
21785
|
-
}
|
|
21786
|
-
}
|
|
21787
|
-
|
|
21788
|
-
stdout.write(isZh ? `\u2502 \u2714 \u672A\u627E\u5230\u4EFB\u4F55 opencode.json \u8A2D\u5B9A\u6A94\u3002
|
|
21793
|
+
const symlinkLocations = [
|
|
21794
|
+
join8(cwd, "node_modules", "opencode-telegram-link"),
|
|
21795
|
+
join8(homedir3(), ".config", "opencode", "node_modules", "opencode-telegram-link"),
|
|
21796
|
+
join8(homedir3(), ".opencode", "node_modules", "opencode-telegram-link")
|
|
21797
|
+
];
|
|
21798
|
+
for (const symlink of symlinkLocations) {
|
|
21799
|
+
try {
|
|
21800
|
+
await rm4(symlink, { recursive: true, force: true });
|
|
21801
|
+
} catch {}
|
|
21802
|
+
}
|
|
21803
|
+
} else {
|
|
21804
|
+
stdout.write(isZh ? `\u2502 \u2714 \u672A\u627E\u5230\u4EFB\u4F55 opencode.json \u8A2D\u5B9A\u6A94\u3002
|
|
21789
21805
|
` : `\u2502 \u2714 No opencode.json configuration files found.
|
|
21790
21806
|
`);
|
|
21791
|
-
|
|
21792
|
-
|
|
21807
|
+
}
|
|
21808
|
+
stdout.write(`\u2502
|
|
21793
21809
|
`);
|
|
21794
|
-
|
|
21795
|
-
|
|
21796
|
-
try {
|
|
21797
|
-
const dbPath = join8(stateDirectory, "state.sqlite");
|
|
21798
|
-
await rm4(dbPath, { force: true });
|
|
21799
|
-
await rm4(`${dbPath}-wal`, { force: true });
|
|
21800
|
-
await rm4(`${dbPath}-shm`, { force: true });
|
|
21801
|
-
await rm4(discoveryRecordPath(stateDirectory), { force: true });
|
|
21802
|
-
await rm4(join8(stateDirectory, "dashboard-settings.json"), { force: true });
|
|
21810
|
+
const cleanState = await reader.ask(isZh ? "\u25C7 [3/4] \u662F\u5426\u6E05\u9664\u904B\u4F5C\u66AB\u5B58\u8CC7\u6599\u5EAB\u8207\u8A0A\u606F\u8DEF\u7531\u72C0\u614B (SQLite)\uFF1F [Y/n]: " : "\u25C7 [3/4] Remove operational database & message routing state (SQLite)? [Y/n]: ", stdout, "Y");
|
|
21811
|
+
if (cleanState.toLowerCase() !== "n" && cleanState.toLowerCase() !== "no") {
|
|
21803
21812
|
try {
|
|
21804
|
-
|
|
21805
|
-
|
|
21806
|
-
|
|
21813
|
+
const dbPath = join8(stateDirectory, "state.sqlite");
|
|
21814
|
+
await rm4(dbPath, { force: true });
|
|
21815
|
+
await rm4(`${dbPath}-wal`, { force: true });
|
|
21816
|
+
await rm4(`${dbPath}-shm`, { force: true });
|
|
21817
|
+
await rm4(discoveryRecordPath(stateDirectory), { force: true });
|
|
21818
|
+
await rm4(join8(stateDirectory, "dashboard-settings.json"), { force: true });
|
|
21819
|
+
try {
|
|
21820
|
+
await rm4(join8(tmpdir(), "opencode_telegram_plugin.log"), { force: true });
|
|
21821
|
+
} catch {}
|
|
21822
|
+
stdout.write(isZh ? `\u2502 \u2714 \u904B\u4F5C\u66AB\u5B58\u8CC7\u6599\u5EAB\u8207\u63A7\u5236\u53F0\u8A2D\u5B9A\u6A94 (dashboard-settings.json) \u5DF2\u6E05\u9664\u3002
|
|
21807
21823
|
` : `\u2502 \u2714 Operational state database & dashboard settings cleared.
|
|
21808
21824
|
`);
|
|
21809
|
-
|
|
21810
|
-
|
|
21825
|
+
} catch {
|
|
21826
|
+
stdout.write(isZh ? `\u2502 - \u66AB\u5B58\u8CC7\u6599\u5EAB\u4E0D\u5B58\u5728\u6216\u5DF2\u6E05\u7406\u3002
|
|
21811
21827
|
` : `\u2502 - State database not found or already clean.
|
|
21812
21828
|
`);
|
|
21829
|
+
}
|
|
21813
21830
|
}
|
|
21814
|
-
|
|
21815
|
-
stdout.write(`\u2502
|
|
21831
|
+
stdout.write(`\u2502
|
|
21816
21832
|
`);
|
|
21817
|
-
|
|
21818
|
-
|
|
21819
|
-
|
|
21820
|
-
|
|
21821
|
-
|
|
21822
|
-
|
|
21833
|
+
const cleanToken = await reader.ask(isZh ? "\u25C7 [4/4] \u662F\u5426\u522A\u9664\u5132\u5B58\u7684 Telegram Bot Token \u6A94\u6848\uFF1F [y/N]: " : "\u25C7 [4/4] Delete saved Telegram Bot Token file? [y/N]: ", stdout, "N");
|
|
21834
|
+
if (cleanToken.toLowerCase() === "y" || cleanToken.toLowerCase() === "yes") {
|
|
21835
|
+
try {
|
|
21836
|
+
const tokenPath = join8(stateDirectory, "telegram-bot-token");
|
|
21837
|
+
await rm4(tokenPath, { force: true });
|
|
21838
|
+
stdout.write(isZh ? `\u2502 \u2714 Token \u6A94\u6848\u5DF2\u5B89\u5168\u522A\u9664\u3002
|
|
21823
21839
|
` : `\u2502 \u2714 Token file securely removed.
|
|
21824
21840
|
`);
|
|
21825
|
-
|
|
21826
|
-
|
|
21841
|
+
} catch {
|
|
21842
|
+
stdout.write(isZh ? `\u2502 - Token \u6A94\u6848\u4E0D\u5B58\u5728\u3002
|
|
21827
21843
|
` : `\u2502 - Token file does not exist.
|
|
21828
21844
|
`);
|
|
21829
|
-
|
|
21830
|
-
|
|
21831
|
-
|
|
21832
|
-
|
|
21833
|
-
|
|
21834
|
-
|
|
21845
|
+
}
|
|
21846
|
+
const cleanAll = await reader.ask(isZh ? `\u2502 \u662F\u5426\u9023\u540C\u91D1\u9470\u76EE\u9304 ${stateDirectory} \u4E00\u4F75\u5B8C\u5168\u522A\u9664\uFF1F [y/N]: ` : `\u2502 Delete entire state directory (${stateDirectory})? [y/N]: `, stdout, "N");
|
|
21847
|
+
if (cleanAll.toLowerCase() === "y" || cleanAll.toLowerCase() === "yes") {
|
|
21848
|
+
try {
|
|
21849
|
+
await rm4(stateDirectory, { recursive: true, force: true });
|
|
21850
|
+
stdout.write(isZh ? `\u2502 \u2714 \u91D1\u9470\u8207\u72C0\u614B\u76EE\u9304\u5DF2\u5B8C\u5168\u79FB\u9664\u3002
|
|
21835
21851
|
` : `\u2502 \u2714 State directory completely removed.
|
|
21836
21852
|
`);
|
|
21837
|
-
|
|
21853
|
+
} catch {}
|
|
21854
|
+
}
|
|
21838
21855
|
}
|
|
21839
|
-
|
|
21840
|
-
stdout.write(`\u2502
|
|
21856
|
+
stdout.write(`\u2502
|
|
21841
21857
|
`);
|
|
21842
|
-
|
|
21858
|
+
stdout.write(isZh ? `\u2514 \uD83C\uDF89 OpenCode Telegram Notifier \u5DF2\u6210\u529F\u79FB\u9664\uFF01
|
|
21843
21859
|
|
|
21844
21860
|
` : `\u2514 \uD83C\uDF89 OpenCode Telegram Notifier successfully uninstalled!
|
|
21845
21861
|
|
|
21846
21862
|
`);
|
|
21847
|
-
|
|
21863
|
+
return 0;
|
|
21864
|
+
} finally {
|
|
21865
|
+
reader.close();
|
|
21866
|
+
}
|
|
21848
21867
|
}
|
|
21849
21868
|
async function runUninstallCli(options = {}) {
|
|
21850
21869
|
const argv = options.argv ?? process.argv.slice(2);
|
|
@@ -21888,9 +21907,10 @@ async function runBroker() {
|
|
|
21888
21907
|
}
|
|
21889
21908
|
if (import.meta.main) {
|
|
21890
21909
|
await runBroker();
|
|
21910
|
+
process.exit(process.exitCode ?? 0);
|
|
21891
21911
|
}
|
|
21892
21912
|
export {
|
|
21893
21913
|
runBroker
|
|
21894
21914
|
};
|
|
21895
21915
|
|
|
21896
|
-
//# debugId=
|
|
21916
|
+
//# debugId=4DA37A84D8B98D2764756E2164756E21
|