opencode-telegram-link 1.0.0-rc.4 → 1.0.0-rc.5

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 CHANGED
@@ -2,14 +2,14 @@
2
2
 
3
3
  OpenCode Telegram Notifier is a privacy-first OpenCode plugin and multi-host management gateway for asynchronous notifications, interactive inline buttons, safe remote replies, and proactive remote task dispatching. It is designed for developers who run OpenCode across multiple projects and multiple computers (dev machine, laptop, VPS) while routing every Telegram and Web interaction to the exact originating host, process, and workspace window.
4
4
 
5
- > Version: **v1.0.0-rc.4** (OpenCode Commander Web Dashboard, Proactive Remote Dispatch, Multi-Engine Voice STT, Multi-Host Gateway & Node Agent Architecture).
6
- > Status: Release Candidate 4. Install from a release tarball or source checkout until the first public npm package is published.
5
+ > Version: **v1.0.0-rc.5** (OpenCode Commander Web Dashboard, Proactive Remote Dispatch, Multi-Engine Voice STT, Multi-Host Gateway & Node Agent Architecture).
6
+ > Status: Release Candidate 5. Install from a release tarball or source checkout until the first public npm package is published.
7
7
 
8
8
  [繁體中文總覽 (Traditional Chinese)](docs/README.zh-TW.md)
9
9
 
10
10
  ---
11
11
 
12
- ## Features & Highlights (v1.0.0-rc.4)
12
+ ## Features & Highlights (v1.0.0-rc.5)
13
13
 
14
14
  - 🖥️ **OpenCode Commander (Web GUI Dashboard)**: Built-in modern Glassmorphism Web Console (`http://<gateway-ip>:42617/dashboard`) providing real-time visibility, live metrics, and centralized cluster management.
15
15
  - 🌐 **Cluster Topology & 1-to-1 Window Mapping**: Live cards for all connected computers and OpenCode workspace windows with real-time session indicators and task counters.
@@ -1 +1 @@
1
- {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/broker/commands.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,KAAK,YAAY,EAEjB,KAAK,kBAAkB,EAExB,MAAM,UAAU,CAAC;AAElB,KAAK,cAAc,GAAG;IACpB,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC1C,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC3C,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC3C,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5D,CAAC;AAEF,wBAAsB,YAAY,CAAC,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAqC9F;AA2DD,wBAAsB,cAAc,CAClC,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,cAAc,EACvB,mBAAmB,GAAE,OAAO,KAAa,GACxC,OAAO,CAAC,MAAM,CAAC,CAejB"}
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/broker/commands.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,KAAK,YAAY,EAEjB,KAAK,kBAAkB,EAExB,MAAM,UAAU,CAAC;AAElB,KAAK,cAAc,GAAG;IACpB,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC1C,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC3C,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC3C,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5D,CAAC;AAEF,wBAAsB,YAAY,CAAC,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAsC9F;AA2DD,wBAAsB,cAAc,CAClC,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,cAAc,EACvB,mBAAmB,GAAE,OAAO,KAAa,GACxC,OAAO,CAAC,MAAM,CAAC,CAejB"}
@@ -14518,9 +14518,9 @@ var DiagnosticSchema = exports_external.object({
14518
14518
 
14519
14519
  // src/setup.ts
14520
14520
  import { randomBytes as randomBytes2, randomUUID as randomUUID3 } from "crypto";
14521
- import { existsSync, readFileSync } from "fs";
14522
- import { chmod as chmod3, lstat as lstat5, mkdir as mkdir3, open as open2, readFile as readFile5, rename as rename4, rm as rm2, writeFile as writeFile3 } from "fs/promises";
14523
- import { hostname as hostname3, platform as platform4 } from "os";
14521
+ import { existsSync as existsSync2, readFileSync } from "fs";
14522
+ import { chmod as chmod3, lstat as lstat5, mkdir as mkdir3, open as open2, readFile as readFile5, rename as rename4, rm as rm2, writeFile as writeFile4 } from "fs/promises";
14523
+ import { hostname as hostname3, platform as platform5 } from "os";
14524
14524
  import { dirname as dirname2, join as join5, resolve as resolve2 } from "path";
14525
14525
 
14526
14526
  // src/config.ts
@@ -15888,6 +15888,93 @@ async function removeOpenCodeConfig(targetPath) {
15888
15888
  return { modified: false };
15889
15889
  }
15890
15890
  }
15891
+ // src/service.ts
15892
+ import { existsSync } from "fs";
15893
+ import { writeFile as writeFile2 } from "fs/promises";
15894
+ import { homedir as homedir3, platform as platform4 } from "os";
15895
+ function isSystemdAvailable() {
15896
+ if (platform4() !== "linux")
15897
+ return false;
15898
+ try {
15899
+ const result = Bun.spawnSync(["systemctl", "--version"]);
15900
+ return result.exitCode === 0;
15901
+ } catch {
15902
+ return false;
15903
+ }
15904
+ }
15905
+ function generateSystemdService(options = {}) {
15906
+ const user = options.user || process.env.USER || "root";
15907
+ const home = options.home || process.env.HOME || homedir3();
15908
+ const envPath = options.envPath || process.env.PATH || "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
15909
+ const execPath = options.execPath || process.execPath;
15910
+ const binScript = options.binScript || process.argv[1] || "opencode-telegram-link";
15911
+ return `[Unit]
15912
+ Description=OpenCode Telegram Gateway & Commander
15913
+ After=network.target
15914
+
15915
+ [Service]
15916
+ Type=simple
15917
+ User=${user}
15918
+ WorkingDirectory=${home}
15919
+ Environment=HOME=${home}
15920
+ Environment="PATH=${envPath}"
15921
+ Environment="OPENCODE_TELEGRAM_BROKER_BIND_HOST=0.0.0.0"
15922
+ ExecStart=${execPath} ${binScript} start --bind-host 0.0.0.0
15923
+ Restart=always
15924
+ RestartSec=5
15925
+
15926
+ [Install]
15927
+ WantedBy=multi-user.target
15928
+ `;
15929
+ }
15930
+ async function installSystemdService(options = {}) {
15931
+ try {
15932
+ const serviceContent = generateSystemdService(options);
15933
+ const tmpServicePath = `/tmp/opencode-gateway.${process.pid}.service`;
15934
+ await writeFile2(tmpServicePath, serviceContent, "utf8");
15935
+ const isRoot = typeof process.getuid === "function" && process.getuid() === 0;
15936
+ const cpCmd = isRoot ? ["cp", tmpServicePath, "/etc/systemd/system/opencode-gateway.service"] : ["sudo", "cp", tmpServicePath, "/etc/systemd/system/opencode-gateway.service"];
15937
+ const cpResult = Bun.spawnSync(cpCmd);
15938
+ if (cpResult.exitCode !== 0) {
15939
+ const err = cpResult.stderr ? new TextDecoder().decode(cpResult.stderr) : "Failed to copy service file";
15940
+ return { success: false, error: err };
15941
+ }
15942
+ const reloadCmd = isRoot ? ["systemctl", "daemon-reload"] : ["sudo", "systemctl", "daemon-reload"];
15943
+ Bun.spawnSync(reloadCmd);
15944
+ const enableCmd = isRoot ? ["systemctl", "enable", "--now", "opencode-gateway"] : ["sudo", "systemctl", "enable", "--now", "opencode-gateway"];
15945
+ const enableResult = Bun.spawnSync(enableCmd);
15946
+ if (enableResult.exitCode !== 0) {
15947
+ const err = enableResult.stderr ? new TextDecoder().decode(enableResult.stderr) : "Failed to enable service";
15948
+ return { success: false, error: err };
15949
+ }
15950
+ return { success: true };
15951
+ } catch (err) {
15952
+ return { success: false, error: err instanceof Error ? err.message : String(err) };
15953
+ }
15954
+ }
15955
+ async function uninstallSystemdService() {
15956
+ const serviceFile = "/etc/systemd/system/opencode-gateway.service";
15957
+ if (!existsSync(serviceFile)) {
15958
+ return { success: true, removed: false };
15959
+ }
15960
+ try {
15961
+ const isRoot = typeof process.getuid === "function" && process.getuid() === 0;
15962
+ const disableCmd = isRoot ? ["systemctl", "disable", "--now", "opencode-gateway"] : ["sudo", "systemctl", "disable", "--now", "opencode-gateway"];
15963
+ Bun.spawnSync(disableCmd);
15964
+ const rmCmd = isRoot ? ["rm", "-f", serviceFile] : ["sudo", "rm", "-f", serviceFile];
15965
+ Bun.spawnSync(rmCmd);
15966
+ const reloadCmd = isRoot ? ["systemctl", "daemon-reload"] : ["sudo", "systemctl", "daemon-reload"];
15967
+ Bun.spawnSync(reloadCmd);
15968
+ return { success: true, removed: true };
15969
+ } catch (err) {
15970
+ return {
15971
+ success: false,
15972
+ removed: false,
15973
+ error: err instanceof Error ? err.message : String(err)
15974
+ };
15975
+ }
15976
+ }
15977
+
15891
15978
  // src/state/database.ts
15892
15979
  import { Database } from "bun:sqlite";
15893
15980
  import { chmod as chmod2, copyFile as copyFile2, lstat as lstat4, rename as rename2 } from "fs/promises";
@@ -16385,7 +16472,7 @@ var SCHEMA_VERSION_2 = `
16385
16472
  `;
16386
16473
  // src/state/discovery.ts
16387
16474
  import { randomUUID as randomUUID2 } from "crypto";
16388
- import { readFile as readFile4, rename as rename3, rm, writeFile as writeFile2 } from "fs/promises";
16475
+ import { readFile as readFile4, rename as rename3, rm, writeFile as writeFile3 } from "fs/promises";
16389
16476
  import { join as join4 } from "path";
16390
16477
  var DiscoveryRecordSchema = exports_external.object({
16391
16478
  port: exports_external.number().int().min(1).max(65535),
@@ -16407,7 +16494,7 @@ async function writeDiscoveryRecord(stateDirectory, port) {
16407
16494
  };
16408
16495
  const destination = discoveryRecordPath(stateDirectory);
16409
16496
  const temporary = `${destination}.${record2.nonce}.tmp`;
16410
- await writeFile2(temporary, `${JSON.stringify(record2)}
16497
+ await writeFile3(temporary, `${JSON.stringify(record2)}
16411
16498
  `, { encoding: "utf8", mode: 384 });
16412
16499
  await rename3(temporary, destination);
16413
16500
  return record2;
@@ -16654,7 +16741,7 @@ class TelegramApiError extends Error {
16654
16741
 
16655
16742
  // src/setup.ts
16656
16743
  function resolveDockerComposeContext(cwd = process.cwd(), explicitComposePath) {
16657
- if (explicitComposePath && existsSync(explicitComposePath)) {
16744
+ if (explicitComposePath && existsSync2(explicitComposePath)) {
16658
16745
  return {
16659
16746
  composeFile: explicitComposePath,
16660
16747
  projectDir: dirname2(explicitComposePath)
@@ -16667,7 +16754,7 @@ function resolveDockerComposeContext(cwd = process.cwd(), explicitComposePath) {
16667
16754
  ];
16668
16755
  for (const file2 of packageCandidates) {
16669
16756
  try {
16670
- if (existsSync(file2)) {
16757
+ if (existsSync2(file2)) {
16671
16758
  return {
16672
16759
  composeFile: file2,
16673
16760
  projectDir: dirname2(file2)
@@ -16677,7 +16764,7 @@ function resolveDockerComposeContext(cwd = process.cwd(), explicitComposePath) {
16677
16764
  }
16678
16765
  const cwdCompose = join5(cwd, "docker-compose.yml");
16679
16766
  try {
16680
- if (existsSync(cwdCompose)) {
16767
+ if (existsSync2(cwdCompose)) {
16681
16768
  const content = readFileSync(cwdCompose, "utf8");
16682
16769
  if (content.includes("opencode-telegram-broker") || content.includes("broker.Dockerfile")) {
16683
16770
  return {
@@ -17011,7 +17098,7 @@ async function runInteractiveSetup(options = {}) {
17011
17098
  const tokenFile = join5(stateDirectory, "telegram-bot-token");
17012
17099
  await writePrivateTokenFile(stateDirectory, tokenFile, botToken);
17013
17100
  const identityFile = join5(stateDirectory, "telegram-identity.json");
17014
- await writeFile3(identityFile, `${JSON.stringify({ userId: pairing.userId, chatId: pairing.chatId, tokenFile, locale }, null, 2)}
17101
+ await writeFile4(identityFile, `${JSON.stringify({ userId: pairing.userId, chatId: pairing.chatId, tokenFile, locale }, null, 2)}
17015
17102
  `, "utf8");
17016
17103
  stdout.write(isZh ? `\u2502 \u2714 \u5B89\u5168 Token \u6A94\u6848\u5DF2\u5132\u5B58 (${tokenFile})
17017
17104
  ` : `\u2502 \u2714 Secure token file saved (${tokenFile})
@@ -17142,9 +17229,32 @@ ${generatePluginConfigSnippet(configData)}
17142
17229
  } else {
17143
17230
  stdout.write(`\u2502
17144
17231
  `);
17145
- 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
17232
+ if (!isNode && isSystemdAvailable()) {
17233
+ const autoSystemd = await reader.ask(isZh ? "\u25C7 \u662F\u5426\u5C07 Gateway \u8A3B\u518A\u70BA Systemd \u7CFB\u7D71\u958B\u6A5F\u81EA\u52D5\u555F\u52D5\u670D\u52D9\uFF1F [Y/n]: " : "\u25C7 Register Gateway as a systemd background service (auto-start on boot)? [Y/n]: ", stdout, "Y");
17234
+ if (autoSystemd.toLowerCase() !== "n" && autoSystemd.toLowerCase() !== "no") {
17235
+ stdout.write(isZh ? `\u2502 \u280B \u6B63\u5728\u8A3B\u518A\u4E26\u555F\u7528 Systemd \u670D\u52D9 (opencode-gateway.service)...
17236
+ ` : `\u2502 \u280B Registering and enabling systemd service (opencode-gateway.service)...
17237
+ `);
17238
+ const serviceResult = await installSystemdService();
17239
+ if (serviceResult.success) {
17240
+ stdout.write(isZh ? `\u2502 \u2714 Systemd \u670D\u52D9\u5DF2\u6210\u529F\u5EFA\u7ACB\u4E26\u555F\u52D5\uFF01\u91CD\u958B\u6A5F\u6642\u5C07\u81EA\u52D5\u5728\u80CC\u666F\u57F7\u884C\u3002
17241
+ ` : `\u2502 \u2714 Systemd service created and enabled! Will auto-start on boot.
17242
+ `);
17243
+ } else {
17244
+ stdout.write(isZh ? `\u2502 \u2716 Systemd \u670D\u52D9\u8A3B\u518A\u5931\u6557: ${serviceResult.error}\uFF08\u60A8\u53EF\u65BC\u7A0D\u5F8C\u624B\u52D5\u555F\u52D5: npx opencode-telegram-link start\uFF09
17245
+ ` : `\u2502 \u2716 Failed to register systemd service: ${serviceResult.error}
17246
+ `);
17247
+ }
17248
+ } else {
17249
+ 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
17250
+ ` : `\u2502 \u2714 Native mode configured! OpenCode will automatically manage Broker in background.
17251
+ `);
17252
+ }
17253
+ } else {
17254
+ 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
17146
17255
  ` : `\u2502 \u2714 Native mode configured! OpenCode will automatically manage Broker in background.
17147
17256
  `);
17257
+ }
17148
17258
  }
17149
17259
  if (!isNode && pairing && api2) {
17150
17260
  stdout.write(`\u2502
@@ -17329,7 +17439,7 @@ async function assertPrivateFile(path) {
17329
17439
  await assertPrivateMode(path, stats.mode, 384);
17330
17440
  }
17331
17441
  async function assertPrivateMode(path, mode, expectedMode) {
17332
- if (platform4() === "win32")
17442
+ if (platform5() === "win32")
17333
17443
  return;
17334
17444
  if ((mode & 63) !== 0) {
17335
17445
  throw new SetupError("SETUP_PERMISSIONS_UNSAFE", "setup state must not allow group or other access");
@@ -17337,7 +17447,7 @@ async function assertPrivateMode(path, mode, expectedMode) {
17337
17447
  await chmodPrivate(path, expectedMode);
17338
17448
  }
17339
17449
  async function chmodPrivate(path, mode) {
17340
- if (platform4() !== "win32")
17450
+ if (platform5() !== "win32")
17341
17451
  await chmod3(path, mode);
17342
17452
  }
17343
17453
  function parseSetupArgs(argv) {
@@ -17438,7 +17548,7 @@ function publicBot(bot) {
17438
17548
 
17439
17549
  // src/uninstall.ts
17440
17550
  import { rm as rm4 } from "fs/promises";
17441
- import { homedir as homedir3, tmpdir } from "os";
17551
+ import { homedir as homedir4, tmpdir } from "os";
17442
17552
  import { join as join8 } from "path";
17443
17553
 
17444
17554
  // src/broker/registry.ts
@@ -17747,7 +17857,7 @@ function sameSessionRoute(left, right) {
17747
17857
  }
17748
17858
  // src/broker/server.ts
17749
17859
  import { createHash as createHash5, randomUUID as randomUUID6, timingSafeEqual } from "crypto";
17750
- import { readFile as readFile6, writeFile as writeFile4 } from "fs/promises";
17860
+ import { readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
17751
17861
  import { join as join6 } from "path";
17752
17862
 
17753
17863
  // src/i18n/catalogs.ts
@@ -17982,7 +18092,7 @@ function rejectionHash(updateId, reason) {
17982
18092
  import { randomUUID as randomUUID4 } from "crypto";
17983
18093
 
17984
18094
  // src/version.ts
17985
- var PACKAGE_VERSION = "1.0.0-rc.4";
18095
+ var PACKAGE_VERSION = "1.0.0-rc.5";
17986
18096
 
17987
18097
  // src/telegram/commands.ts
17988
18098
  function isSlashCommand(text) {
@@ -20049,7 +20159,7 @@ async function loadDashboardSettings(stateDirectory) {
20049
20159
  }
20050
20160
  async function saveDashboardSettings(stateDirectory, settings) {
20051
20161
  const filePath = join6(stateDirectory, "dashboard-settings.json");
20052
- await writeFile4(filePath, JSON.stringify(settings, null, 2), "utf-8");
20162
+ await writeFile5(filePath, JSON.stringify(settings, null, 2), "utf-8");
20053
20163
  }
20054
20164
  async function readJsonBody(request) {
20055
20165
  const text = await request.text();
@@ -21455,10 +21565,11 @@ async function runBrokerCli(options = {}) {
21455
21565
  stdout: options.stdout ?? process.stdout,
21456
21566
  stderr: options.stderr ?? process.stderr
21457
21567
  };
21458
- const command = argv[0];
21459
- const flags = parseFlags(argv.slice(1));
21568
+ const normalizedArgv = argv[0] === "broker" ? argv.slice(1) : argv;
21569
+ const command = normalizedArgv[0];
21570
+ const flags = parseFlags(normalizedArgv.slice(1));
21460
21571
  const brokerOptions = brokerOptionsFrom(flags, env);
21461
- if (!command || command === "start") {
21572
+ if (!command || command === "start" || command === "run") {
21462
21573
  return await runStartCommand(brokerOptions, streams, options.onStarted);
21463
21574
  }
21464
21575
  try {
@@ -21750,6 +21861,14 @@ async function runInteractiveUninstall(options = {}) {
21750
21861
  }
21751
21862
  } catch {}
21752
21863
  }
21864
+ try {
21865
+ const systemdResult = await uninstallSystemdService();
21866
+ if (systemdResult.removed) {
21867
+ stdout.write(isZh ? `\u2502 \u2714 Systemd \u670D\u52D9 (opencode-gateway.service) \u5DF2\u505C\u7528\u4E26\u79FB\u9664\u3002
21868
+ ` : `\u2502 \u2714 Systemd service (opencode-gateway.service) stopped and removed.
21869
+ `);
21870
+ }
21871
+ } catch {}
21753
21872
  try {
21754
21873
  const identity = await loadOrCreateStateIdentity(stateDirectory);
21755
21874
  const isRunning = await probeBroker(42617, identity.brokerSecret);
@@ -21793,8 +21912,8 @@ async function runInteractiveUninstall(options = {}) {
21793
21912
  }
21794
21913
  const symlinkLocations = [
21795
21914
  join8(cwd, "node_modules", "opencode-telegram-link"),
21796
- join8(homedir3(), ".config", "opencode", "node_modules", "opencode-telegram-link"),
21797
- join8(homedir3(), ".opencode", "node_modules", "opencode-telegram-link")
21915
+ join8(homedir4(), ".config", "opencode", "node_modules", "opencode-telegram-link"),
21916
+ join8(homedir4(), ".opencode", "node_modules", "opencode-telegram-link")
21798
21917
  ];
21799
21918
  for (const symlink of symlinkLocations) {
21800
21919
  try {
@@ -21914,4 +22033,4 @@ export {
21914
22033
  runBroker
21915
22034
  };
21916
22035
 
21917
- //# debugId=81AE8738AC7A8E1264756E2164756E21
22036
+ //# debugId=6769A77FD917233264756E2164756E21