opencode-telegram-link 1.0.0-rc.2 → 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.
@@ -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
- const now = options.now ?? Date.now;
16800
- const stateDirectory = options.stateDirectory ?? defaultStateDirectory();
16801
- const cwd = options.cwd ?? process.cwd();
16802
- stdout.write(`
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
- stdout.write(`\u25C7 Language / \u8A9E\u8A00:
16814
+ stdout.write(`\u25C7 Language / \u8A9E\u8A00:
16807
16815
  `);
16808
- stdout.write(`\u2502 1) \u7E41\u9AD4\u4E2D\u6587 (zh-TW) [\u9810\u8A2D/Default]
16816
+ stdout.write(`\u2502 1) \u7E41\u9AD4\u4E2D\u6587 (zh-TW) [\u9810\u8A2D/Default]
16809
16817
  `);
16810
- stdout.write(`\u2502 2) English (en)
16818
+ stdout.write(`\u2502 2) English (en)
16811
16819
  `);
16812
- const langChoice = await reader.ask("\u2502 \u8ACB\u9078\u64C7 / Select [1]: ", stdout, "1");
16813
- const locale = langChoice === "2" || langChoice.toLowerCase() === "en" ? "en" : "zh-TW";
16814
- const isZh = locale === "zh-TW";
16815
- stdout.write(`\u2502
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
- stdout.write(isZh ? `\u25C7 \u8ACB\u9078\u64C7\u6B64\u6A5F\u5668\u7684\u89D2\u8272 (Role):
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
- const roleChoice = await reader.ask(isZh ? "\u2502 \u8ACB\u9078\u64C7 / Select [1]: " : "\u2502 Select [1]: ", stdout, "1");
16825
- const isNode = roleChoice === "2" || roleChoice.toLowerCase().includes("node");
16826
- const defaultHost = hostname3() || "host";
16827
- stdout.write(`\u2502
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
- stdout.write(isZh ? `\u25C7 \u4E3B\u6A5F\u8B58\u5225\u6A19\u7C64 (Host Label) [\u9810\u8A2D: ${defaultHost}]:
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
- const hostLabel = await reader.ask(isZh ? `\u2502 \u6A19\u7C64\u540D\u7A31 [${defaultHost}]: ` : `\u2502 Label [${defaultHost}]: `, stdout, defaultHost);
16835
- let configData;
16836
- let isDocker = false;
16837
- let pairing;
16838
- let api2;
16839
- let botInfo;
16840
- if (isNode) {
16841
- stdout.write(`\u2502
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
- stdout.write(isZh ? `\u25C7 \u8ACB\u8F38\u5165 Central Gateway \u7684 WebSocket \u4F4D\u5740:
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
- const gatewayUrl = await reader.ask("\u2502 Gateway URL: ", stdout);
16849
- if (!gatewayUrl) {
16850
- stderr.write(isZh ? `\u2716 Gateway URL \u4E0D\u80FD\u70BA\u7A7A\u3002
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
- return 1;
16854
- }
16855
- stdout.write(`\u2502
16861
+ return 1;
16862
+ }
16863
+ stdout.write(`\u2502
16856
16864
  `);
16857
- stdout.write(isZh ? `\u25C7 \u8ACB\u8F38\u5165 Gateway \u9023\u7DDA\u91D1\u9470 (Secret Token):
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
- const gatewaySecret = await reader.ask("\u2502 Secret: ", stdout, "");
16863
- configData = {
16864
- mode: "local",
16865
- role: "node",
16866
- hostLabel,
16867
- locale,
16868
- gateway: {
16869
- url: gatewayUrl,
16870
- secret: gatewaySecret || "default-secret"
16871
- },
16872
- notifications: {
16873
- completion: true,
16874
- error: true,
16875
- question: true,
16876
- permission: true,
16877
- includeChildLifecycle: false,
16878
- completionDebounceMs: 1500,
16879
- pluginBufferSize: 100
16880
- },
16881
- broker: {
16882
- host: "127.0.0.1",
16883
- port: 42617
16884
- },
16885
- interaction: {
16886
- sessionPromptTtlMinutes: 1440,
16887
- questionTtlMinutes: 30
16888
- }
16889
- };
16890
- } else {
16891
- stdout.write(`\u2502
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
- stdout.write(isZh ? `\u25C7 \u90E8\u7F72\u6A21\u5F0F\u9078\u64C7 / Deployment Mode:
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
- const modeChoice = await reader.ask(isZh ? "\u2502 \u8ACB\u9078\u64C7 / Select [1]: " : "\u2502 Select [1]: ", stdout, "1");
16901
- isDocker = modeChoice === "2" || modeChoice.toLowerCase().includes("docker");
16902
- let botToken = "";
16903
- let attempts = 0;
16904
- while (!botInfo) {
16905
- attempts += 1;
16906
- if (attempts > 5) {
16907
- stderr.write(isZh ? `\u2716 \u8D85\u904E\u91CD\u8A66\u6B21\u6578\uFF0C\u8A2D\u5B9A\u7D42\u6B62\u3002
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
- return 1;
16911
- }
16912
- stdout.write(`\u2502
16918
+ return 1;
16919
+ }
16920
+ stdout.write(`\u2502
16913
16921
  `);
16914
- if (isZh) {
16915
- stdout.write(`\u25C7 \u8ACB\u8F38\u5165\u5411 @BotFather \u7533\u8ACB\u7684 Telegram Bot Token:
16922
+ if (isZh) {
16923
+ stdout.write(`\u25C7 \u8ACB\u8F38\u5165\u5411 @BotFather \u7533\u8ACB\u7684 Telegram Bot Token:
16916
16924
  `);
16917
- stdout.write(`\u2502 (\u7BC4\u4F8B: 123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ)
16925
+ stdout.write(`\u2502 (\u7BC4\u4F8B: 123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ)
16918
16926
  `);
16919
- } else {
16920
- stdout.write(`\u25C7 Enter your Telegram Bot Token from @BotFather:
16927
+ } else {
16928
+ stdout.write(`\u25C7 Enter your Telegram Bot Token from @BotFather:
16921
16929
  `);
16922
- stdout.write(`\u2502 (Example: 123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ)
16930
+ stdout.write(`\u2502 (Example: 123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ)
16923
16931
  `);
16924
- }
16925
- botToken = await reader.ask("\u2502 Token: ", stdout);
16926
- if (!botToken) {
16927
- stdout.write(isZh ? `\u2502 \u2716 Token \u4E0D\u80FD\u70BA\u7A7A\uFF0C\u8ACB\u91CD\u65B0\u8F38\u5165\u3002
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
- continue;
16931
- }
16932
- if (!/^\d+:[A-Za-z0-9_-]{20,}$/.test(botToken)) {
16933
- stdout.write(isZh ? `\u2502 \u2716 Token \u683C\u5F0F\u4E0D\u7B26\u5408 Telegram \u898F\u7BC4\uFF0C\u8ACB\u91CD\u65B0\u8F38\u5165\u3002
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
- continue;
16937
- }
16938
- stdout.write(isZh ? `\u2502 \u280B \u6B63\u5728\u5411 Telegram \u9A57\u8B49 Bot Token...
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
- api2 = new TelegramBotApi({ token: botToken, fetch: fetchImpl });
16942
- try {
16943
- botInfo = await api2.getMe();
16944
- const botName2 = botInfo.username ? `@${botInfo.username}` : `bot ${botInfo.id}`;
16945
- stdout.write(isZh ? `\u2502 \u2714 \u9023\u7DDA\u6210\u529F\uFF01\u5DF2\u8FA8\u8B58 Bot: ${botName2} (ID: ${botInfo.id})
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
- } catch (err) {
16949
- const errMsg = err instanceof Error ? err.message : "connection failed";
16950
- stdout.write(isZh ? `\u2502 \u2716 Token \u9A57\u8B49\u5931\u6557 (${errMsg})\uFF0C\u8ACB\u78BA\u8A8D\u5F8C\u91CD\u8A66\u3002
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
- api2 = new TelegramBotApi({ token: botToken, fetch: fetchImpl });
16956
- const nonce = createPairingNonce();
16957
- const botName = botInfo.username ? `@${botInfo.username}` : `Bot (ID: ${botInfo.id})`;
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
- if (isZh) {
16961
- stdout.write(`\u25C7 [\u8EAB\u5206\u9A57\u8B49\u914D\u5C0D]
16968
+ if (isZh) {
16969
+ stdout.write(`\u25C7 [\u8EAB\u5206\u9A57\u8B49\u914D\u5C0D]
16962
16970
  `);
16963
- stdout.write(`\u2502 \u8ACB\u5728 Telegram \u6253\u958B\u8207 ${botName} \u7684\u79C1\u804A\u8996\u7A97\uFF0C\u4E26\u767C\u9001\u6B64\u9A57\u8B49\u78BC\uFF1A
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
- stdout.write(`\u2502
16973
+ stdout.write(`\u2502
16966
16974
  \u2502 \uD83D\uDC49 ${nonce}
16967
16975
  \u2502
16968
16976
  `);
16969
- stdout.write(`\u2502 \u280B \u7B49\u5F85 Telegram \u79C1\u8A0A\u4E2D...
16977
+ stdout.write(`\u2502 \u280B \u7B49\u5F85 Telegram \u79C1\u8A0A\u4E2D...
16970
16978
  `);
16971
- } else {
16972
- stdout.write(`\u25C7 [Identity Pairing]
16979
+ } else {
16980
+ stdout.write(`\u25C7 [Identity Pairing]
16973
16981
  `);
16974
- stdout.write(`\u2502 Open a private chat with ${botName} on Telegram and send this code:
16982
+ stdout.write(`\u2502 Open a private chat with ${botName} on Telegram and send this code:
16975
16983
  `);
16976
- stdout.write(`\u2502
16984
+ stdout.write(`\u2502
16977
16985
  \u2502 \uD83D\uDC49 ${nonce}
16978
16986
  \u2502
16979
16987
  `);
16980
- stdout.write(`\u2502 \u280B Waiting for Telegram private message...
16988
+ stdout.write(`\u2502 \u280B Waiting for Telegram private message...
16981
16989
  `);
16982
- }
16983
- const expiresAt = now() + 120000;
16984
- try {
16985
- pairing = await waitForPairingMessage(api2, {
16986
- nonce,
16987
- expiresAt,
16988
- now,
16989
- pollTimeoutSeconds: 5
16990
- });
16991
- } catch {
16992
- stdout.write(isZh ? `\u2502 \u2716 \u914D\u5C0D\u8D85\u6642\u6216\u672A\u6536\u5230\u6709\u6548\u8A0A\u606F\uFF0C\u8A2D\u5B9A\u4E2D\u6B62\u3002
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
- return 1;
16996
- }
16997
- stdout.write(isZh ? `\u2502 \u2714 \u6536\u5230\u9A57\u8B49\u8A0A\u606F\uFF01\u4F86\u81EA Telegram \u7528\u6236 (ID: ${pairing.userId}, Chat: ${pairing.chatId})
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
- 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");
17001
- if (confirmBind.toLowerCase() === "n" || confirmBind.toLowerCase() === "no") {
17002
- stdout.write(isZh ? `\u2502 \u2716 \u5DF2\u53D6\u6D88\u7D81\u5B9A\u3002
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
- return 1;
17006
- }
17007
- const tokenFile = join5(stateDirectory, "telegram-bot-token");
17008
- await writePrivateTokenFile(stateDirectory, tokenFile, botToken);
17009
- const identityFile = join5(stateDirectory, "telegram-identity.json");
17010
- await writeFile3(identityFile, `${JSON.stringify({ userId: pairing.userId, chatId: pairing.chatId, tokenFile, locale }, null, 2)}
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
- stdout.write(isZh ? `\u2502 \u2714 \u5B89\u5168 Token \u6A94\u6848\u5DF2\u5132\u5B58 (${tokenFile})
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
- configData = {
17016
- mode: "local",
17017
- role: "gateway",
17018
- hostLabel,
17019
- locale,
17020
- telegram: {
17021
- tokenFile,
17022
- userId: pairing.userId,
17023
- chatId: pairing.chatId
17024
- },
17025
- notifications: {
17026
- completion: true,
17027
- error: true,
17028
- question: true,
17029
- permission: true,
17030
- includeChildLifecycle: false,
17031
- completionDebounceMs: 1500,
17032
- pluginBufferSize: 100
17033
- },
17034
- broker: {
17035
- host: "127.0.0.1",
17036
- port: 42617
17037
- },
17038
- interaction: {
17039
- sessionPromptTtlMinutes: 1440,
17040
- questionTtlMinutes: 30
17041
- }
17042
- };
17043
- }
17044
- stdout.write(`\u2502
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
- const discovered = await discoverOpenCodeConfigFiles(cwd);
17047
- const existingConfigs = discovered.filter((d) => d.exists);
17048
- const fallback = discovered.find((d) => !d.isWorkspace) ?? discovered[0];
17049
- const targets = existingConfigs.length > 0 ? existingConfigs : fallback ? [fallback] : [];
17050
- if (targets.length > 0) {
17051
- const descList = targets.map((t) => `${t.path} [${t.exists ? isZh ? "\u5DF2\u5B58\u5728" : "existing" : isZh ? "\u5C07\u81EA\u52D5\u5EFA\u7ACB" : "will create"}]`).join(", ");
17052
- stdout.write(isZh ? `\u25C7 \u5075\u6E2C\u5230 OpenCode \u8A2D\u5B9A\u6A94 (${descList})
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
- 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");
17056
- if (autoWrite.toLowerCase() !== "n" && autoWrite.toLowerCase() !== "no") {
17057
- for (const target of targets) {
17058
- try {
17059
- const { backupPath } = await injectOpenCodeConfig(target.path, configData);
17060
- stdout.write(isZh ? `\u2502 \u2714 OpenCode \u8A2D\u5B9A\u6A94\u5DF2\u66F4\u65B0: ${target.path}${backupPath ? ` (\u5099\u4EFD\u65BC ${backupPath})` : ""}
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
- } catch (err) {
17064
- const errMsg = err instanceof Error ? err.message : "failed to write config";
17065
- stdout.write(isZh ? `\u2502 \u2716 \u8A2D\u5B9A\u6A94\u5BEB\u5165\u5931\u6557 (${target.path}): ${errMsg}
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
- } else {
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
- stdout.write(`\u2502
17082
+ stdout.write(`\u2502
17075
17083
  ${generatePluginConfigSnippet(configData)}
17076
17084
  \u2502
17077
17085
  `);
17086
+ }
17078
17087
  }
17079
- }
17080
- let dockerFailed = false;
17081
- if (isDocker) {
17082
- stdout.write(`\u2502
17088
+ let dockerFailed = false;
17089
+ if (isDocker) {
17090
+ stdout.write(`\u2502
17083
17091
  `);
17084
- 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");
17085
- if (autoStartDocker.toLowerCase() !== "n" && autoStartDocker.toLowerCase() !== "no") {
17086
- stdout.write(isZh ? `\u2502 \u280B \u6B63\u5728\u5EFA\u7F6E\u4E26\u555F\u52D5 Docker \u5BB9\u5668 (docker compose up -d --build)...
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
- try {
17090
- const dockerCmd = process.platform === "win32" ? "docker.exe" : "docker";
17091
- const composeCtx = resolveDockerComposeContext(cwd);
17092
- if (!composeCtx) {
17093
- throw new Error("Could not find docker-compose.yml in project or package directory");
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
- if (result.exitCode === 0) {
17113
- stdout.write(isZh ? `\u2502 \u2714 Docker Broker \u5BB9\u5668\u5DF2\u6210\u529F\u5728\u80CC\u666F\u555F\u52D5\uFF01
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
- } else {
17117
- dockerFailed = true;
17118
- const stderr2 = result.stderr ? new TextDecoder().decode(result.stderr).trim() : "";
17119
- 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
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
- stdout.write(isZh ? `\u2502 \u60A8\u53EF\u65BC\u7A0D\u5F8C\u624B\u52D5\u57F7\u884C: docker compose -f "${composeCtx.composeFile}" up -d
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
- } catch (err) {
17127
- dockerFailed = true;
17128
- const msg = err instanceof Error ? err.message : String(err);
17129
- 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
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
- } else {
17134
- stdout.write(isZh ? `\u2502 \u60A8\u53EF\u65BC\u7A0D\u5F8C\u624B\u52D5\u555F\u52D5\u5BB9\u5668: docker compose up -d
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
- } else {
17139
- stdout.write(`\u2502
17145
+ }
17146
+ } else {
17147
+ stdout.write(`\u2502
17140
17148
  `);
17141
- 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
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
- if (!isNode && pairing && api2) {
17146
- stdout.write(`\u2502
17152
+ }
17153
+ if (!isNode && pairing && api2) {
17154
+ stdout.write(`\u2502
17147
17155
  `);
17148
- 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");
17149
- if (sendTest.toLowerCase() !== "n" && sendTest.toLowerCase() !== "no") {
17150
- try {
17151
- const botDisplayName = botInfo?.username ? `@${botInfo.username}` : `Bot (ID: ${botInfo?.id})`;
17152
- const welcomeText = isZh ? `\uD83C\uDF89 <b>OpenCode Telegram Notifier \u8A2D\u5B9A\u6210\u529F\uFF01</b>
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
- await api2.sendMessage({
17166
- chatId: pairing.chatId,
17167
- text: welcomeText,
17168
- parseMode: "HTML"
17169
- });
17170
- 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
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
- } catch (err) {
17174
- const errMsg = err instanceof Error ? err.message : "send failed";
17175
- stdout.write(isZh ? `\u2502 \u2716 \u6E2C\u8A66\u901A\u77E5\u767C\u9001\u5931\u6557: ${errMsg}
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
- if (dockerFailed) {
17184
- 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
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
- return 1;
17190
- }
17191
- 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
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
- return 0;
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.2";
17989
+ var PACKAGE_VERSION = "1.0.0-rc.3";
17979
17990
 
17980
17991
  // src/telegram/commands.ts
17981
17992
  function isSlashCommand(text) {
@@ -21694,161 +21705,165 @@ async function runInteractiveUninstall(options = {}) {
21694
21705
  const stdout = options.stdout ?? process.stdout;
21695
21706
  const stderr = options.stderr ?? process.stderr;
21696
21707
  const reader = new AsyncPromptReader(options.stdin ?? process.stdin);
21697
- const stateDirectory = options.stateDirectory ?? defaultStateDirectory();
21698
- const cwd = options.cwd ?? process.cwd();
21699
- const fetchImpl = options.fetch ?? fetch;
21700
- stdout.write(`
21708
+ try {
21709
+ const stateDirectory = options.stateDirectory ?? defaultStateDirectory();
21710
+ const cwd = options.cwd ?? process.cwd();
21711
+ const fetchImpl = options.fetch ?? fetch;
21712
+ stdout.write(`
21701
21713
  \u250C OpenCode Telegram Notifier \u2014 Uninstaller / \u79FB\u9664\u7CBE\u9748
21702
21714
  \u2502
21703
21715
  `);
21704
- stdout.write(`\u25C7 Language / \u8A9E\u8A00:
21716
+ stdout.write(`\u25C7 Language / \u8A9E\u8A00:
21705
21717
  `);
21706
- stdout.write(`\u2502 1) \u7E41\u9AD4\u4E2D\u6587 (zh-TW) [\u9810\u8A2D/Default]
21718
+ stdout.write(`\u2502 1) \u7E41\u9AD4\u4E2D\u6587 (zh-TW) [\u9810\u8A2D/Default]
21707
21719
  `);
21708
- stdout.write(`\u2502 2) English (en)
21720
+ stdout.write(`\u2502 2) English (en)
21709
21721
  `);
21710
- const langChoice = await reader.ask("\u2502 \u8ACB\u9078\u64C7 / Select [1]: ", stdout, "1");
21711
- const locale = langChoice === "2" || langChoice.toLowerCase() === "en" ? "en" : "zh-TW";
21712
- const isZh = locale === "zh-TW";
21713
- stdout.write(`\u2502
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
21714
21726
  `);
21715
- 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");
21716
- if (confirm.toLowerCase() !== "y" && confirm.toLowerCase() !== "yes") {
21717
- stdout.write(isZh ? `\u2502 \u64CD\u4F5C\u5DF2\u53D6\u6D88\u3002
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
21718
21730
  \u2514 \uD83D\uDC4B \u7D50\u675F\u3002
21719
21731
 
21720
21732
  ` : `\u2502 Aborted.
21721
21733
  \u2514 \uD83D\uDC4B Done.
21722
21734
 
21723
21735
  `);
21724
- return 0;
21725
- }
21726
- stdout.write(`\u2502
21736
+ return 0;
21737
+ }
21738
+ stdout.write(`\u2502
21727
21739
  `);
21728
- 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)...
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)...
21729
21741
  ` : `\u25C7 [1/4] Checking and stopping running Broker (native process or Docker container)...
21730
21742
  `);
21731
- try {
21732
- const dockerCmd = process.platform === "win32" ? "docker.exe" : "docker";
21733
- const dockerDown = Bun.spawnSync([dockerCmd, "compose", "down"], { cwd });
21734
- if (dockerDown.exitCode === 0) {
21735
- stdout.write(isZh ? `\u2502 \u2714 Docker Broker \u5BB9\u5668\u5DF2\u505C\u6B62\u4E26\u6E05\u7406\u3002
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
21736
21748
  ` : `\u2502 \u2714 Docker Broker container stopped and cleaned up.
21737
21749
  `);
21738
- }
21739
- } catch {}
21740
- try {
21741
- const identity = await loadOrCreateStateIdentity(stateDirectory);
21742
- const isRunning = await probeBroker(42617, identity.brokerSecret);
21743
- if (isRunning) {
21744
- await runStopCommand({ stateDirectory, port: 42617 }, { stdout, stderr }, fetchImpl);
21745
- stdout.write(isZh ? `\u2502 \u2714 \u672C\u6A5F Broker \u5DF2\u6210\u529F\u505C\u6B62\u3002
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
21746
21758
  ` : `\u2502 \u2714 Local broker stopped.
21747
21759
  `);
21748
- } else {
21749
- stdout.write(isZh ? `\u2502 \u2714 \u672C\u6A5F Broker \u672A\u5728\u57F7\u884C\u4E2D\u3002
21760
+ } else {
21761
+ stdout.write(isZh ? `\u2502 \u2714 \u672C\u6A5F Broker \u672A\u5728\u57F7\u884C\u4E2D\u3002
21750
21762
  ` : `\u2502 \u2714 Local broker is not running.
21751
21763
  `);
21752
- }
21753
- } catch {
21754
- stdout.write(isZh ? `\u2502 \u2714 \u672A\u627E\u5230\u57F7\u884C\u4E2D\u7684\u672C\u6A5F Broker \u6216\u5DF2\u505C\u6B62\u3002
21764
+ }
21765
+ } catch {
21766
+ stdout.write(isZh ? `\u2502 \u2714 \u672A\u627E\u5230\u57F7\u884C\u4E2D\u7684\u672C\u6A5F Broker \u6216\u5DF2\u505C\u6B62\u3002
21755
21767
  ` : `\u2502 \u2714 No active local broker found or already stopped.
21756
21768
  `);
21757
- }
21758
- stdout.write(`\u2502
21769
+ }
21770
+ stdout.write(`\u2502
21759
21771
  `);
21760
- stdout.write(isZh ? `\u25C7 [2/4] \u6B63\u5728\u641C\u5C0B OpenCode \u8A2D\u5B9A\u6A94...
21772
+ stdout.write(isZh ? `\u25C7 [2/4] \u6B63\u5728\u641C\u5C0B OpenCode \u8A2D\u5B9A\u6A94...
21761
21773
  ` : `\u25C7 [2/4] Searching for OpenCode configuration files...
21762
21774
  `);
21763
- const discoveredConfigs = await discoverOpenCodeConfigFiles(cwd);
21764
- const existingConfigs = discoveredConfigs.filter((c) => c.exists);
21765
- if (existingConfigs.length > 0) {
21766
- 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");
21767
- if (cleanConfig.toLowerCase() !== "n" && cleanConfig.toLowerCase() !== "no") {
21768
- for (const config2 of existingConfigs) {
21769
- const { modified, backupPath } = await removeOpenCodeConfig(config2.path);
21770
- if (modified) {
21771
- stdout.write(isZh ? `\u2502 \u2714 \u5DF2\u5F9E ${config2.path} \u79FB\u9664\u5916\u639B\u8A2D\u5B9A${backupPath ? ` (\u5099\u4EFD\u65BC ${backupPath})` : ""}
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})` : ""}
21772
21784
  ` : `\u2502 \u2714 Removed plugin config from ${config2.path}${backupPath ? ` (backup at ${backupPath})` : ""}
21773
21785
  `);
21774
- } else {
21775
- stdout.write(isZh ? `\u2502 - ${config2.path} \u672A\u5305\u542B\u672C\u5916\u639B\u8A2D\u5B9A\u3002
21786
+ } else {
21787
+ stdout.write(isZh ? `\u2502 - ${config2.path} \u672A\u5305\u542B\u672C\u5916\u639B\u8A2D\u5B9A\u3002
21776
21788
  ` : `\u2502 - No plugin config in ${config2.path}.
21777
21789
  `);
21790
+ }
21778
21791
  }
21779
21792
  }
21780
- }
21781
- const symlinkLocations = [
21782
- join8(cwd, "node_modules", "opencode-telegram-link"),
21783
- join8(homedir3(), ".config", "opencode", "node_modules", "opencode-telegram-link"),
21784
- join8(homedir3(), ".opencode", "node_modules", "opencode-telegram-link")
21785
- ];
21786
- for (const symlink of symlinkLocations) {
21787
- try {
21788
- await rm4(symlink, { recursive: true, force: true });
21789
- } catch {}
21790
- }
21791
- } else {
21792
- 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
21793
21805
  ` : `\u2502 \u2714 No opencode.json configuration files found.
21794
21806
  `);
21795
- }
21796
- stdout.write(`\u2502
21807
+ }
21808
+ stdout.write(`\u2502
21797
21809
  `);
21798
- 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");
21799
- if (cleanState.toLowerCase() !== "n" && cleanState.toLowerCase() !== "no") {
21800
- try {
21801
- const dbPath = join8(stateDirectory, "state.sqlite");
21802
- await rm4(dbPath, { force: true });
21803
- await rm4(`${dbPath}-wal`, { force: true });
21804
- await rm4(`${dbPath}-shm`, { force: true });
21805
- await rm4(discoveryRecordPath(stateDirectory), { force: true });
21806
- 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") {
21807
21812
  try {
21808
- await rm4(join8(tmpdir(), "opencode_telegram_plugin.log"), { force: true });
21809
- } catch {}
21810
- 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
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
21811
21823
  ` : `\u2502 \u2714 Operational state database & dashboard settings cleared.
21812
21824
  `);
21813
- } catch {
21814
- stdout.write(isZh ? `\u2502 - \u66AB\u5B58\u8CC7\u6599\u5EAB\u4E0D\u5B58\u5728\u6216\u5DF2\u6E05\u7406\u3002
21825
+ } catch {
21826
+ stdout.write(isZh ? `\u2502 - \u66AB\u5B58\u8CC7\u6599\u5EAB\u4E0D\u5B58\u5728\u6216\u5DF2\u6E05\u7406\u3002
21815
21827
  ` : `\u2502 - State database not found or already clean.
21816
21828
  `);
21829
+ }
21817
21830
  }
21818
- }
21819
- stdout.write(`\u2502
21831
+ stdout.write(`\u2502
21820
21832
  `);
21821
- 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");
21822
- if (cleanToken.toLowerCase() === "y" || cleanToken.toLowerCase() === "yes") {
21823
- try {
21824
- const tokenPath = join8(stateDirectory, "telegram-bot-token");
21825
- await rm4(tokenPath, { force: true });
21826
- stdout.write(isZh ? `\u2502 \u2714 Token \u6A94\u6848\u5DF2\u5B89\u5168\u522A\u9664\u3002
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
21827
21839
  ` : `\u2502 \u2714 Token file securely removed.
21828
21840
  `);
21829
- } catch {
21830
- stdout.write(isZh ? `\u2502 - Token \u6A94\u6848\u4E0D\u5B58\u5728\u3002
21841
+ } catch {
21842
+ stdout.write(isZh ? `\u2502 - Token \u6A94\u6848\u4E0D\u5B58\u5728\u3002
21831
21843
  ` : `\u2502 - Token file does not exist.
21832
21844
  `);
21833
- }
21834
- 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");
21835
- if (cleanAll.toLowerCase() === "y" || cleanAll.toLowerCase() === "yes") {
21836
- try {
21837
- await rm4(stateDirectory, { recursive: true, force: true });
21838
- stdout.write(isZh ? `\u2502 \u2714 \u91D1\u9470\u8207\u72C0\u614B\u76EE\u9304\u5DF2\u5B8C\u5168\u79FB\u9664\u3002
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
21839
21851
  ` : `\u2502 \u2714 State directory completely removed.
21840
21852
  `);
21841
- } catch {}
21853
+ } catch {}
21854
+ }
21842
21855
  }
21843
- }
21844
- stdout.write(`\u2502
21856
+ stdout.write(`\u2502
21845
21857
  `);
21846
- stdout.write(isZh ? `\u2514 \uD83C\uDF89 OpenCode Telegram Notifier \u5DF2\u6210\u529F\u79FB\u9664\uFF01
21858
+ stdout.write(isZh ? `\u2514 \uD83C\uDF89 OpenCode Telegram Notifier \u5DF2\u6210\u529F\u79FB\u9664\uFF01
21847
21859
 
21848
21860
  ` : `\u2514 \uD83C\uDF89 OpenCode Telegram Notifier successfully uninstalled!
21849
21861
 
21850
21862
  `);
21851
- return 0;
21863
+ return 0;
21864
+ } finally {
21865
+ reader.close();
21866
+ }
21852
21867
  }
21853
21868
  async function runUninstallCli(options = {}) {
21854
21869
  const argv = options.argv ?? process.argv.slice(2);
@@ -21892,9 +21907,10 @@ async function runBroker() {
21892
21907
  }
21893
21908
  if (import.meta.main) {
21894
21909
  await runBroker();
21910
+ process.exit(process.exitCode ?? 0);
21895
21911
  }
21896
21912
  export {
21897
21913
  runBroker
21898
21914
  };
21899
21915
 
21900
- //# debugId=02CC163E478BF57D64756E2164756E21
21916
+ //# debugId=4DA37A84D8B98D2764756E2164756E21