tmex-cli 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/runtime/server.js +666 -106
  3. package/package.json +4 -3
  4. package/resources/fe-dist/assets/DevicePage-fGI-do8S.js +26 -0
  5. package/resources/fe-dist/assets/DevicesPage-kGrzwhGj.js +2 -0
  6. package/resources/fe-dist/assets/FilePage-YWma96aj.js +16 -0
  7. package/resources/fe-dist/assets/SettingsPage-LhUD03Ln.js +32 -0
  8. package/resources/fe-dist/assets/{arc-Wv219fq_.js → arc-DLVa298O.js} +2 -2
  9. package/resources/fe-dist/assets/{architectureDiagram-3BPJPVTR-DkPPo2hY.js → architectureDiagram-3BPJPVTR-EOUpuRby.js} +2 -2
  10. package/resources/fe-dist/assets/{blockDiagram-GPEHLZMM-DPAThozG.js → blockDiagram-GPEHLZMM-BTwwkzZh.js} +2 -2
  11. package/resources/fe-dist/assets/{c4Diagram-AAUBKEIU-DBs_N-_p.js → c4Diagram-AAUBKEIU-xvTqXxl9.js} +2 -2
  12. package/resources/fe-dist/assets/{card-Dl0HC88A.js → card-cbVDy0Xp.js} +2 -2
  13. package/resources/fe-dist/assets/channel-DbG6qNF6.js +2 -0
  14. package/resources/fe-dist/assets/{chunk-2J33WTMH-D3mrUPCp.js → chunk-2J33WTMH-Blr6l1Nk.js} +2 -2
  15. package/resources/fe-dist/assets/{chunk-4BX2VUAB-C0DRv58j.js → chunk-4BX2VUAB-D_Y2TeLg.js} +2 -2
  16. package/resources/fe-dist/assets/{chunk-55IACEB6-DheUp7iQ.js → chunk-55IACEB6-CimNoYDH.js} +2 -2
  17. package/resources/fe-dist/assets/{chunk-727SXJPM-Cvew2yIJ.js → chunk-727SXJPM-JPYDN0Cb.js} +2 -2
  18. package/resources/fe-dist/assets/{chunk-AQP2D5EJ-DUoa4Wdg.js → chunk-AQP2D5EJ-Cb3NZBib.js} +2 -2
  19. package/resources/fe-dist/assets/{chunk-FMBD7UC4-Bt9Oi52P.js → chunk-FMBD7UC4-DyZ7Ot2F.js} +2 -2
  20. package/resources/fe-dist/assets/{chunk-ND2GUHAM-DlWpyDaS.js → chunk-ND2GUHAM-SU6Ea3wF.js} +2 -2
  21. package/resources/fe-dist/assets/{chunk-QZHKN3VN-BZtXwgRW.js → chunk-QZHKN3VN-B6qXX6sU.js} +2 -2
  22. package/resources/fe-dist/assets/classDiagram-4FO5ZUOK-rB1DgxOZ.js +2 -0
  23. package/resources/fe-dist/assets/classDiagram-v2-Q7XG4LA2-rB1DgxOZ.js +2 -0
  24. package/resources/fe-dist/assets/{cose-bilkent-S5V4N54A-yKy6sTY_.js → cose-bilkent-S5V4N54A-BAyMopHS.js} +2 -2
  25. package/resources/fe-dist/assets/{dagre-BM42HDAG-DL4fpno6.js → dagre-BM42HDAG-Ckrx9BXZ.js} +2 -2
  26. package/resources/fe-dist/assets/{diagram-2AECGRRQ-BueYws-9.js → diagram-2AECGRRQ-DTnZtf2k.js} +2 -2
  27. package/resources/fe-dist/assets/{diagram-5GNKFQAL-GQEQSUeb.js → diagram-5GNKFQAL-DBpgZj4a.js} +2 -2
  28. package/resources/fe-dist/assets/{diagram-KO2AKTUF-LE3yI4ed.js → diagram-KO2AKTUF-CfijYCeY.js} +2 -2
  29. package/resources/fe-dist/assets/{diagram-LMA3HP47-BkHjYrU4.js → diagram-LMA3HP47-D7nBmQ-E.js} +2 -2
  30. package/resources/fe-dist/assets/{diagram-OG6HWLK6-DrnHic-P.js → diagram-OG6HWLK6-Bi8sHV0O.js} +2 -2
  31. package/resources/fe-dist/assets/{erDiagram-TEJ5UH35-BCwWv-rO.js → erDiagram-TEJ5UH35-DcoDesO2.js} +2 -2
  32. package/resources/fe-dist/assets/{flowDiagram-I6XJVG4X-DEC2Z_fh.js → flowDiagram-I6XJVG4X-Bbcl9kxS.js} +2 -2
  33. package/resources/fe-dist/assets/{ganttDiagram-6RSMTGT7-H1T5bCsY.js → ganttDiagram-6RSMTGT7-BM8Y7jwp.js} +2 -2
  34. package/resources/fe-dist/assets/{gitGraphDiagram-PVQCEYII-DmZUfKfl.js → gitGraphDiagram-PVQCEYII-x3wpNQcW.js} +2 -2
  35. package/resources/fe-dist/assets/{index-OpBFduyh.js → index-cfY8KuW7.js} +123 -123
  36. package/resources/fe-dist/assets/index-vcS0VPIW.css +1 -0
  37. package/resources/fe-dist/assets/{infoDiagram-5YYISTIA-fDOg9Qr5.js → infoDiagram-5YYISTIA-Bl6cgwVb.js} +2 -2
  38. package/resources/fe-dist/assets/{ishikawaDiagram-YF4QCWOH-QIvSJI3q.js → ishikawaDiagram-YF4QCWOH-BfQ7aZxN.js} +2 -2
  39. package/resources/fe-dist/assets/{journeyDiagram-JHISSGLW-Iz7u4iH8.js → journeyDiagram-JHISSGLW-DSwQzmdL.js} +2 -2
  40. package/resources/fe-dist/assets/{kanban-definition-UN3LZRKU-BYiFSFgn.js → kanban-definition-UN3LZRKU-B1aWDl4E.js} +2 -2
  41. package/resources/fe-dist/assets/{linear-DNHZFKop.js → linear-CfhRC4iX.js} +2 -2
  42. package/resources/fe-dist/assets/markdown-preview-Bf_6UH9R.css +1 -0
  43. package/resources/fe-dist/assets/markdown-preview-CfBRMViB.js +269 -0
  44. package/resources/fe-dist/assets/{mermaid.core-DUipsjFg.js → mermaid.core-M-o4g4TO.js} +6 -6
  45. package/resources/fe-dist/assets/{mindmap-definition-RKZ34NQL-tPbrKC3m.js → mindmap-definition-RKZ34NQL-D976sxOA.js} +2 -2
  46. package/resources/fe-dist/assets/{pieDiagram-4H26LBE5-26o8qBzb.js → pieDiagram-4H26LBE5-PVQ3-EB6.js} +2 -2
  47. package/resources/fe-dist/assets/{quadrantDiagram-W4KKPZXB-BgpGo9Ak.js → quadrantDiagram-W4KKPZXB-BNEFhYNq.js} +2 -2
  48. package/resources/fe-dist/assets/{refresh-cw-DdcimDhs.js → refresh-cw-cfX5JiIH.js} +2 -2
  49. package/resources/fe-dist/assets/{requirementDiagram-4Y6WPE33-BEfrxsDZ.js → requirementDiagram-4Y6WPE33-B7Zd2lpN.js} +2 -2
  50. package/resources/fe-dist/assets/{sankeyDiagram-5OEKKPKP-BuIeHyjh.js → sankeyDiagram-5OEKKPKP-D_Td4j-B.js} +2 -2
  51. package/resources/fe-dist/assets/{sequenceDiagram-3UESZ5HK-CL0sinOn.js → sequenceDiagram-3UESZ5HK-DQSVX5mL.js} +2 -2
  52. package/resources/fe-dist/assets/{stateDiagram-AJRCARHV-BCq5X6hO.js → stateDiagram-AJRCARHV-C0PNCTfs.js} +2 -2
  53. package/resources/fe-dist/assets/stateDiagram-v2-BHNVJYJU-CB5OePKf.js +2 -0
  54. package/resources/fe-dist/assets/{timeline-definition-PNZ67QCA-CnqqA91O.js → timeline-definition-PNZ67QCA-BlMj8Fl1.js} +2 -2
  55. package/resources/fe-dist/assets/{vennDiagram-CIIHVFJN-BqFG3JXB.js → vennDiagram-CIIHVFJN-DuGxwZiq.js} +2 -2
  56. package/resources/fe-dist/assets/{wardley-L42UT6IY-DvfZKNwT.js → wardley-L42UT6IY-4VhWbg10.js} +2 -2
  57. package/resources/fe-dist/assets/{wardleyDiagram-YWT4CUSO-DlABpMGt.js → wardleyDiagram-YWT4CUSO-Bu4k6xIx.js} +2 -2
  58. package/resources/fe-dist/assets/{xychartDiagram-2RQKCTM6-BDiyUuus.js → xychartDiagram-2RQKCTM6-Cv88IDWh.js} +2 -2
  59. package/resources/fe-dist/fonts/GeistMonoNerdFontMono-Bold.woff2 +0 -0
  60. package/resources/fe-dist/fonts/GeistMonoNerdFontMono-Regular.woff2 +0 -0
  61. package/resources/fe-dist/index.html +2 -2
  62. package/resources/fe-dist/tmex-maskable.png +0 -0
  63. package/resources/fe-dist/tmex.png +0 -0
  64. package/resources/fe-dist/assets/DevicePage-5vkaNOjl.js +0 -26
  65. package/resources/fe-dist/assets/DevicesPage-CKnRUGQm.js +0 -2
  66. package/resources/fe-dist/assets/FilePage-Dj0cszD4.css +0 -1
  67. package/resources/fe-dist/assets/FilePage-Uj-tzGW7.js +0 -283
  68. package/resources/fe-dist/assets/SettingsPage-Cfzr_Phh.js +0 -22
  69. package/resources/fe-dist/assets/channel-DyLhDM_y.js +0 -2
  70. package/resources/fe-dist/assets/classDiagram-4FO5ZUOK-DA8DiM06.js +0 -2
  71. package/resources/fe-dist/assets/classDiagram-v2-Q7XG4LA2-DA8DiM06.js +0 -2
  72. package/resources/fe-dist/assets/index-yMgNjHUH.css +0 -1
  73. package/resources/fe-dist/assets/stateDiagram-v2-BHNVJYJU-DH2ctCND.js +0 -2
  74. package/resources/fe-dist/fonts/GeistMono-Bold.woff2 +0 -0
  75. package/resources/fe-dist/fonts/GeistMono-Regular.woff2 +0 -0
@@ -22549,8 +22549,8 @@ function applyRepoEnv(name, env, options, log) {
22549
22549
  loadEnv();
22550
22550
 
22551
22551
  // src/runtime/server.ts
22552
- import { existsSync as existsSync5 } from "fs";
22553
- import { extname as extname2, join as join6, normalize, resolve as resolve4, sep } from "path";
22552
+ import { existsSync as existsSync8 } from "fs";
22553
+ import { extname as extname2, join as join7, normalize, resolve as resolve6, sep } from "path";
22554
22554
 
22555
22555
  // ../../apps/gateway/src/crypto/errors.ts
22556
22556
  function contextLabel(context) {
@@ -22740,11 +22740,22 @@ var I18N_RESOURCES = {
22740
22740
  language_en_US: "English",
22741
22741
  language_zh_CN: "\u7B80\u4F53\u4E2D\u6587",
22742
22742
  language_ja_JP: "\u65E5\u672C\u8A9E",
22743
- theme: "Theme",
22743
+ theme: "Dark Mode",
22744
22744
  themeLight: "Light",
22745
22745
  themeDark: "Dark",
22746
22746
  siteTab: "Site",
22747
22747
  notificationsTab: "Notifications",
22748
+ tabGroup: {
22749
+ general: "General",
22750
+ devicesAndFiles: "Devices & Files",
22751
+ notifications: "Notifications",
22752
+ ai: "AI"
22753
+ },
22754
+ deviceManagement: {
22755
+ title: "Device Management",
22756
+ description: "Add, edit, and connect to your local and SSH devices.",
22757
+ openButton: "Open Device Management"
22758
+ },
22748
22759
  refreshToApply: "Refresh to apply language change",
22749
22760
  saveSettings: "Save Settings",
22750
22761
  settingsSaved: "Settings saved",
@@ -22798,6 +22809,7 @@ var I18N_RESOURCES = {
22798
22809
  search: {
22799
22810
  title: "Search",
22800
22811
  provider: "Search Provider",
22812
+ responsesApiHint: "If your LLM provider uses the OpenAI Responses API protocol, it can use that API's built-in hosted search tool; the third-party search below is an optional supplement.",
22801
22813
  providerNone: "Disabled",
22802
22814
  tavilyApiKey: "Tavily API Key",
22803
22815
  braveApiKey: "Brave API Key",
@@ -22830,6 +22842,35 @@ var I18N_RESOURCES = {
22830
22842
  toggleFailed: "Failed to update directory",
22831
22843
  deleteTitle: "Remove directory?",
22832
22844
  deleteDesc: 'Remove "{{path}}" from the whitelist? Files under it will no longer be accessible.'
22845
+ },
22846
+ version: {
22847
+ title: "Version & Updates",
22848
+ currentVersion: "Current version",
22849
+ installMethod: "Install method",
22850
+ installMethodCli: "Installed via CLI",
22851
+ installMethodNonCli: "Not installed via CLI",
22852
+ deployment: "Deployment",
22853
+ deploymentLaunchd: "launchd (macOS)",
22854
+ deploymentSystemd: "systemd (Linux)",
22855
+ deploymentNone: "None",
22856
+ checkUpdate: "Check for updates",
22857
+ checking: "Checking\u2026",
22858
+ upToDate: "You are on the latest version.",
22859
+ updateAvailable: "Update available: {{version}}",
22860
+ changelog: "Changelog",
22861
+ changelogUnavailable: "No changelog available for this version.",
22862
+ publishedAt: "Published {{date}}",
22863
+ upgrade: "Upgrade now",
22864
+ upgradeDisabledDev: "In-app update is disabled outside the production environment.",
22865
+ upgradeDisabledNonCli: "In-app update is only available for CLI installations.",
22866
+ upgradeWarningTitle: "Confirm upgrade",
22867
+ upgradeWarningBody: "Upgrading restarts the service and will interrupt your current session. It may also affect the survival of tmux processes managed by the service. Continue?",
22868
+ upgradeStarted: "Upgrade started",
22869
+ stateDownloading: "Downloading the new version\u2026",
22870
+ stateExecuting: "Applying the upgrade, the service is restarting\u2026",
22871
+ interruptNotice: "The connection will drop while the service restarts; it will recover shortly.",
22872
+ checkFailed: "Failed to check for updates",
22873
+ terminalHint: "Or upgrade from a terminal: npx tmex-cli@<version> upgrade"
22833
22874
  }
22834
22875
  },
22835
22876
  telegram: {
@@ -22839,6 +22880,7 @@ var I18N_RESOURCES = {
22839
22880
  botToken: "Bot Token",
22840
22881
  botTokenPlaceholder: "123456:AA...",
22841
22882
  addBot: "Add Bot",
22883
+ editBot: "Edit Bot",
22842
22884
  enableBot: "Enable Bot",
22843
22885
  allowAuthRequests: "Allow Authorization Requests",
22844
22886
  pendingChats: "Pending Authorization",
@@ -23015,7 +23057,11 @@ Time: {{time}}`,
23015
23057
  fileTooLarge: "File is too large",
23016
23058
  fileBinary: "Binary files are not supported",
23017
23059
  fileRootDeviceInvalid: "Invalid or unknown device",
23018
- fileRootDuplicate: "This directory is already added for the device"
23060
+ fileRootDuplicate: "This directory is already added for the device",
23061
+ upgradeNotAllowed: "In-app update is not available for this installation.",
23062
+ upgradeInProgress: "An upgrade is already in progress.",
23063
+ upgradeVersionRequired: "Target version is required.",
23064
+ updateCheckFailed: "Failed to query the npm registry."
23019
23065
  },
23020
23066
  notification: {
23021
23067
  clickToJump: "Click to jump to corresponding pane",
@@ -23304,7 +23350,10 @@ Time: {{time}}`,
23304
23350
  },
23305
23351
  validation: {
23306
23352
  deviceNameRequired: "Device name is required",
23307
- hostRequired: "Host is required for SSH devices"
23353
+ hostRequired: "Host is required for SSH devices",
23354
+ portRequired: "A valid port is required for SSH devices",
23355
+ usernameRequired: "Username is required for SSH devices",
23356
+ sshConfigRequired: "SSH config path is required for SSH devices"
23308
23357
  },
23309
23358
  files: {
23310
23359
  title: "Files",
@@ -23519,11 +23568,22 @@ Time: {{time}}`,
23519
23568
  language_en_US: "English",
23520
23569
  language_zh_CN: "\u7B80\u4F53\u4E2D\u6587",
23521
23570
  language_ja_JP: "\u65E5\u672C\u8A9E",
23522
- theme: "\u4E3B\u9898",
23571
+ theme: "\u6DF1\u8272\u6A21\u5F0F",
23523
23572
  themeLight: "\u6D45\u8272",
23524
23573
  themeDark: "\u6DF1\u8272",
23525
23574
  siteTab: "\u7AD9\u70B9",
23526
23575
  notificationsTab: "\u901A\u77E5",
23576
+ tabGroup: {
23577
+ general: "\u901A\u7528\u8BBE\u7F6E",
23578
+ devicesAndFiles: "\u8BBE\u5907\u4E0E\u6587\u4EF6",
23579
+ notifications: "\u901A\u77E5\u8BBE\u7F6E",
23580
+ ai: "AI \u8BBE\u7F6E"
23581
+ },
23582
+ deviceManagement: {
23583
+ title: "\u8BBE\u5907\u7BA1\u7406",
23584
+ description: "\u6DFB\u52A0\u3001\u7F16\u8F91\u5E76\u8FDE\u63A5\u4F60\u7684\u672C\u5730\u4E0E SSH \u8BBE\u5907\u3002",
23585
+ openButton: "\u6253\u5F00\u8BBE\u5907\u7BA1\u7406"
23586
+ },
23527
23587
  refreshToApply: "\u5237\u65B0\u540E\u751F\u6548",
23528
23588
  saveSettings: "\u4FDD\u5B58\u8BBE\u7F6E",
23529
23589
  settingsSaved: "\u7AD9\u70B9\u8BBE\u7F6E\u5DF2\u4FDD\u5B58",
@@ -23577,6 +23637,7 @@ Time: {{time}}`,
23577
23637
  search: {
23578
23638
  title: "\u641C\u7D22",
23579
23639
  provider: "\u641C\u7D22\u63D0\u4F9B\u5546",
23640
+ responsesApiHint: "\u82E5 LLM Provider \u4F7F\u7528 OpenAI Responses API \u534F\u8BAE\uFF0C\u53EF\u76F4\u63A5\u4F7F\u7528\u5176\u5185\u7F6E\u7684 hosted \u641C\u7D22\u5DE5\u5177\uFF1B\u4E0B\u65B9\u7B2C\u4E09\u65B9\u641C\u7D22\u4E3A\u53EF\u9009\u8865\u5145\u3002",
23580
23641
  providerNone: "\u4E0D\u542F\u7528",
23581
23642
  tavilyApiKey: "Tavily API Key",
23582
23643
  braveApiKey: "Brave API Key",
@@ -23609,6 +23670,35 @@ Time: {{time}}`,
23609
23670
  toggleFailed: "\u66F4\u65B0\u76EE\u5F55\u5931\u8D25",
23610
23671
  deleteTitle: "\u79FB\u9664\u76EE\u5F55\uFF1F",
23611
23672
  deleteDesc: "\u5C06\u300C{{path}}\u300D\u79FB\u51FA\u767D\u540D\u5355\uFF1F\u8BE5\u76EE\u5F55\u4E0B\u7684\u6587\u4EF6\u5C06\u4E0D\u518D\u53EF\u8BBF\u95EE\u3002"
23673
+ },
23674
+ version: {
23675
+ title: "\u7248\u672C\u4E0E\u66F4\u65B0",
23676
+ currentVersion: "\u5F53\u524D\u7248\u672C",
23677
+ installMethod: "\u5B89\u88C5\u65B9\u5F0F",
23678
+ installMethodCli: "\u901A\u8FC7 CLI \u5B89\u88C5",
23679
+ installMethodNonCli: "\u975E CLI \u5B89\u88C5",
23680
+ deployment: "\u90E8\u7F72\u65B9\u5F0F",
23681
+ deploymentLaunchd: "launchd\uFF08macOS\uFF09",
23682
+ deploymentSystemd: "systemd\uFF08Linux\uFF09",
23683
+ deploymentNone: "\u65E0",
23684
+ checkUpdate: "\u68C0\u67E5\u66F4\u65B0",
23685
+ checking: "\u68C0\u67E5\u4E2D\u2026",
23686
+ upToDate: "\u5DF2\u662F\u6700\u65B0\u7248\u672C\u3002",
23687
+ updateAvailable: "\u6709\u53EF\u7528\u66F4\u65B0\uFF1A{{version}}",
23688
+ changelog: "\u66F4\u65B0\u65E5\u5FD7",
23689
+ changelogUnavailable: "\u8BE5\u7248\u672C\u6682\u65E0\u66F4\u65B0\u65E5\u5FD7\u3002",
23690
+ publishedAt: "\u53D1\u5E03\u4E8E {{date}}",
23691
+ upgrade: "\u7ACB\u5373\u5347\u7EA7",
23692
+ upgradeDisabledDev: "\u975E production \u73AF\u5883\u5DF2\u7981\u7528\u7A0B\u5E8F\u5185\u66F4\u65B0\u3002",
23693
+ upgradeDisabledNonCli: "\u7A0B\u5E8F\u5185\u66F4\u65B0\u4EC5\u5728\u901A\u8FC7 CLI \u5B89\u88C5\u65F6\u53EF\u7528\u3002",
23694
+ upgradeWarningTitle: "\u786E\u8BA4\u5347\u7EA7",
23695
+ upgradeWarningBody: "\u5347\u7EA7\u4F1A\u91CD\u542F\u670D\u52A1\u5E76\u4E2D\u65AD\u5F53\u524D\u8BBF\u95EE\uFF0C\u8FD8\u53EF\u80FD\u5F71\u54CD\u8BE5\u670D\u52A1\u6258\u7BA1\u7684 tmux \u8FDB\u7A0B\u7684\u5B58\u6D3B\u3002\u662F\u5426\u7EE7\u7EED\uFF1F",
23696
+ upgradeStarted: "\u5347\u7EA7\u5DF2\u5F00\u59CB",
23697
+ stateDownloading: "\u6B63\u5728\u4E0B\u8F7D\u65B0\u7248\u672C\u2026",
23698
+ stateExecuting: "\u6B63\u5728\u6267\u884C\u5347\u7EA7\uFF0C\u670D\u52A1\u5373\u5C06\u91CD\u542F\u2026",
23699
+ interruptNotice: "\u670D\u52A1\u91CD\u542F\u671F\u95F4\u8FDE\u63A5\u4F1A\u65AD\u5F00\uFF0C\u7A0D\u5019\u5373\u53EF\u6062\u590D\u3002",
23700
+ checkFailed: "\u68C0\u67E5\u66F4\u65B0\u5931\u8D25",
23701
+ terminalHint: "\u6216\u901A\u8FC7\u7EC8\u7AEF\u5347\u7EA7\uFF1Anpx tmex-cli@<version> upgrade"
23612
23702
  }
23613
23703
  },
23614
23704
  telegram: {
@@ -23618,6 +23708,7 @@ Time: {{time}}`,
23618
23708
  botToken: "Bot Token",
23619
23709
  botTokenPlaceholder: "123456:AA...",
23620
23710
  addBot: "\u65B0\u589E Bot",
23711
+ editBot: "\u7F16\u8F91 Bot",
23621
23712
  enableBot: "\u542F\u7528 Bot",
23622
23713
  allowAuthRequests: "\u5141\u8BB8\u7533\u8BF7\u6388\u6743",
23623
23714
  pendingChats: "\u5F85\u6388\u6743",
@@ -23794,7 +23885,11 @@ Bot\uFF1A{{botName}}
23794
23885
  fileTooLarge: "\u6587\u4EF6\u8FC7\u5927",
23795
23886
  fileBinary: "\u4E0D\u652F\u6301\u4E8C\u8FDB\u5236\u6587\u4EF6",
23796
23887
  fileRootDeviceInvalid: "\u65E0\u6548\u6216\u672A\u77E5\u7684\u8BBE\u5907",
23797
- fileRootDuplicate: "\u8BE5\u8BBE\u5907\u4E0B\u5DF2\u6DFB\u52A0\u8FC7\u6B64\u76EE\u5F55"
23888
+ fileRootDuplicate: "\u8BE5\u8BBE\u5907\u4E0B\u5DF2\u6DFB\u52A0\u8FC7\u6B64\u76EE\u5F55",
23889
+ upgradeNotAllowed: "\u5F53\u524D\u5B89\u88C5\u65B9\u5F0F\u4E0D\u652F\u6301\u7A0B\u5E8F\u5185\u66F4\u65B0\u3002",
23890
+ upgradeInProgress: "\u5DF2\u6709\u5347\u7EA7\u4EFB\u52A1\u6B63\u5728\u8FDB\u884C\u3002",
23891
+ upgradeVersionRequired: "\u7F3A\u5C11\u76EE\u6807\u7248\u672C\u53F7\u3002",
23892
+ updateCheckFailed: "\u67E5\u8BE2 npm registry \u5931\u8D25\u3002"
23798
23893
  },
23799
23894
  notification: {
23800
23895
  clickToJump: "\u70B9\u51FB\u8DF3\u8F6C\u5230\u5BF9\u5E94 Pane",
@@ -24083,7 +24178,10 @@ Bot\uFF1A{{botName}}
24083
24178
  },
24084
24179
  validation: {
24085
24180
  deviceNameRequired: "\u8BBE\u5907\u540D\u79F0\u4E3A\u5FC5\u586B\u9879",
24086
- hostRequired: "SSH \u8BBE\u5907\u9700\u8981\u586B\u5199\u4E3B\u673A\u5730\u5740"
24181
+ hostRequired: "SSH \u8BBE\u5907\u9700\u8981\u586B\u5199\u4E3B\u673A\u5730\u5740",
24182
+ portRequired: "SSH \u8BBE\u5907\u9700\u8981\u586B\u5199\u6709\u6548\u7AEF\u53E3",
24183
+ usernameRequired: "SSH \u8BBE\u5907\u9700\u8981\u586B\u5199\u7528\u6237\u540D",
24184
+ sshConfigRequired: "SSH \u8BBE\u5907\u9700\u8981\u586B\u5199 ssh config \u8DEF\u5F84"
24087
24185
  },
24088
24186
  files: {
24089
24187
  title: "\u6587\u4EF6",
@@ -24298,11 +24396,22 @@ Bot\uFF1A{{botName}}
24298
24396
  language_en_US: "English",
24299
24397
  language_zh_CN: "\u7B80\u4F53\u4E2D\u6587",
24300
24398
  language_ja_JP: "\u65E5\u672C\u8A9E",
24301
- theme: "\u30C6\u30FC\u30DE",
24399
+ theme: "\u30C0\u30FC\u30AF\u30E2\u30FC\u30C9",
24302
24400
  themeLight: "\u30E9\u30A4\u30C8",
24303
24401
  themeDark: "\u30C0\u30FC\u30AF",
24304
24402
  siteTab: "\u30B5\u30A4\u30C8",
24305
24403
  notificationsTab: "\u901A\u77E5",
24404
+ tabGroup: {
24405
+ general: "\u4E00\u822C\u8A2D\u5B9A",
24406
+ devicesAndFiles: "\u30C7\u30D0\u30A4\u30B9\u3068\u30D5\u30A1\u30A4\u30EB",
24407
+ notifications: "\u901A\u77E5\u8A2D\u5B9A",
24408
+ ai: "AI \u8A2D\u5B9A"
24409
+ },
24410
+ deviceManagement: {
24411
+ title: "\u30C7\u30D0\u30A4\u30B9\u7BA1\u7406",
24412
+ description: "\u30ED\u30FC\u30AB\u30EB\u304A\u3088\u3073 SSH \u30C7\u30D0\u30A4\u30B9\u306E\u8FFD\u52A0\u30FB\u7DE8\u96C6\u30FB\u63A5\u7D9A\u3092\u884C\u3044\u307E\u3059\u3002",
24413
+ openButton: "\u30C7\u30D0\u30A4\u30B9\u7BA1\u7406\u3092\u958B\u304F"
24414
+ },
24306
24415
  refreshToApply: "\u8A00\u8A9E\u5909\u66F4\u3092\u9069\u7528\u3059\u308B\u306B\u306F\u66F4\u65B0\u3057\u3066\u304F\u3060\u3055\u3044",
24307
24416
  saveSettings: "\u8A2D\u5B9A\u3092\u4FDD\u5B58",
24308
24417
  settingsSaved: "\u8A2D\u5B9A\u3092\u4FDD\u5B58\u3057\u307E\u3057\u305F",
@@ -24356,6 +24465,7 @@ Bot\uFF1A{{botName}}
24356
24465
  search: {
24357
24466
  title: "\u691C\u7D22",
24358
24467
  provider: "\u691C\u7D22\u30D7\u30ED\u30D0\u30A4\u30C0\u30FC",
24468
+ responsesApiHint: "LLM \u30D7\u30ED\u30D0\u30A4\u30C0\u30FC\u304C OpenAI Responses API \u30D7\u30ED\u30C8\u30B3\u30EB\u3092\u4F7F\u7528\u3057\u3066\u3044\u308B\u5834\u5408\u3001\u305D\u306E\u5185\u8535 hosted \u691C\u7D22\u30C4\u30FC\u30EB\u3092\u5229\u7528\u3067\u304D\u307E\u3059\u3002\u4E0B\u8A18\u306E\u30B5\u30FC\u30C9\u30D1\u30FC\u30C6\u30A3\u691C\u7D22\u306F\u4EFB\u610F\u306E\u88DC\u5B8C\u3067\u3059\u3002",
24359
24469
  providerNone: "\u7121\u52B9",
24360
24470
  tavilyApiKey: "Tavily API \u30AD\u30FC",
24361
24471
  braveApiKey: "Brave API \u30AD\u30FC",
@@ -24388,6 +24498,35 @@ Bot\uFF1A{{botName}}
24388
24498
  toggleFailed: "\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306E\u66F4\u65B0\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
24389
24499
  deleteTitle: "\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u3092\u524A\u9664\u3057\u307E\u3059\u304B\uFF1F",
24390
24500
  deleteDesc: "\u300C{{path}}\u300D\u3092\u30DB\u30EF\u30A4\u30C8\u30EA\u30B9\u30C8\u304B\u3089\u524A\u9664\u3057\u307E\u3059\u304B\uFF1F\u914D\u4E0B\u306E\u30D5\u30A1\u30A4\u30EB\u306B\u30A2\u30AF\u30BB\u30B9\u3067\u304D\u306A\u304F\u306A\u308A\u307E\u3059\u3002"
24501
+ },
24502
+ version: {
24503
+ title: "\u30D0\u30FC\u30B8\u30E7\u30F3\u3068\u66F4\u65B0",
24504
+ currentVersion: "\u73FE\u5728\u306E\u30D0\u30FC\u30B8\u30E7\u30F3",
24505
+ installMethod: "\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u65B9\u6CD5",
24506
+ installMethodCli: "CLI \u3067\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB",
24507
+ installMethodNonCli: "CLI \u4EE5\u5916\u3067\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB",
24508
+ deployment: "\u30C7\u30D7\u30ED\u30A4\u65B9\u5F0F",
24509
+ deploymentLaunchd: "launchd\uFF08macOS\uFF09",
24510
+ deploymentSystemd: "systemd\uFF08Linux\uFF09",
24511
+ deploymentNone: "\u306A\u3057",
24512
+ checkUpdate: "\u66F4\u65B0\u3092\u78BA\u8A8D",
24513
+ checking: "\u78BA\u8A8D\u4E2D\u2026",
24514
+ upToDate: "\u6700\u65B0\u30D0\u30FC\u30B8\u30E7\u30F3\u3067\u3059\u3002",
24515
+ updateAvailable: "\u66F4\u65B0\u304C\u3042\u308A\u307E\u3059\uFF1A{{version}}",
24516
+ changelog: "\u5909\u66F4\u5C65\u6B74",
24517
+ changelogUnavailable: "\u3053\u306E\u30D0\u30FC\u30B8\u30E7\u30F3\u306E\u5909\u66F4\u5C65\u6B74\u306F\u3042\u308A\u307E\u305B\u3093\u3002",
24518
+ publishedAt: "\u516C\u958B\u65E5 {{date}}",
24519
+ upgrade: "\u4ECA\u3059\u3050\u66F4\u65B0",
24520
+ upgradeDisabledDev: "production \u4EE5\u5916\u306E\u74B0\u5883\u3067\u306F\u30A2\u30D7\u30EA\u5185\u66F4\u65B0\u306F\u7121\u52B9\u3067\u3059\u3002",
24521
+ upgradeDisabledNonCli: "\u30A2\u30D7\u30EA\u5185\u66F4\u65B0\u306F CLI \u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u6642\u306E\u307F\u5229\u7528\u3067\u304D\u307E\u3059\u3002",
24522
+ upgradeWarningTitle: "\u66F4\u65B0\u306E\u78BA\u8A8D",
24523
+ upgradeWarningBody: "\u66F4\u65B0\u3059\u308B\u3068\u30B5\u30FC\u30D3\u30B9\u304C\u518D\u8D77\u52D5\u3057\u3001\u73FE\u5728\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u304C\u4E2D\u65AD\u3055\u308C\u307E\u3059\u3002\u30B5\u30FC\u30D3\u30B9\u304C\u7BA1\u7406\u3059\u308B tmux \u30D7\u30ED\u30BB\u30B9\u306E\u5B58\u7D9A\u306B\u3082\u5F71\u97FF\u3059\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002\u7D9A\u884C\u3057\u307E\u3059\u304B\uFF1F",
24524
+ upgradeStarted: "\u66F4\u65B0\u3092\u958B\u59CB\u3057\u307E\u3057\u305F",
24525
+ stateDownloading: "\u65B0\u3057\u3044\u30D0\u30FC\u30B8\u30E7\u30F3\u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u4E2D\u2026",
24526
+ stateExecuting: "\u66F4\u65B0\u3092\u9069\u7528\u4E2D\u3001\u30B5\u30FC\u30D3\u30B9\u3092\u518D\u8D77\u52D5\u3057\u3066\u3044\u307E\u3059\u2026",
24527
+ interruptNotice: "\u30B5\u30FC\u30D3\u30B9\u518D\u8D77\u52D5\u4E2D\u306F\u63A5\u7D9A\u304C\u5207\u65AD\u3055\u308C\u307E\u3059\u304C\u3001\u307E\u3082\u306A\u304F\u5FA9\u65E7\u3057\u307E\u3059\u3002",
24528
+ checkFailed: "\u66F4\u65B0\u306E\u78BA\u8A8D\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
24529
+ terminalHint: "\u307E\u305F\u306F\u30BF\u30FC\u30DF\u30CA\u30EB\u304B\u3089\u66F4\u65B0\uFF1Anpx tmex-cli@<version> upgrade"
24391
24530
  }
24392
24531
  },
24393
24532
  telegram: {
@@ -24397,6 +24536,7 @@ Bot\uFF1A{{botName}}
24397
24536
  botToken: "Bot Token",
24398
24537
  botTokenPlaceholder: "123456:AA...",
24399
24538
  addBot: "Bot \u3092\u8FFD\u52A0",
24539
+ editBot: "Bot \u3092\u7DE8\u96C6",
24400
24540
  enableBot: "Bot \u3092\u6709\u52B9\u306B\u3059\u308B",
24401
24541
  allowAuthRequests: "\u8A8D\u8A3C\u30EA\u30AF\u30A8\u30B9\u30C8\u3092\u8A31\u53EF",
24402
24542
  pendingChats: "\u627F\u8A8D\u5F85\u3061",
@@ -24573,7 +24713,11 @@ Bot\uFF1A{{botName}}
24573
24713
  fileTooLarge: "\u30D5\u30A1\u30A4\u30EB\u304C\u5927\u304D\u3059\u304E\u307E\u3059",
24574
24714
  fileBinary: "\u30D0\u30A4\u30CA\u30EA\u30D5\u30A1\u30A4\u30EB\u306F\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u305B\u3093",
24575
24715
  fileRootDeviceInvalid: "\u7121\u52B9\u307E\u305F\u306F\u4E0D\u660E\u306A\u30C7\u30D0\u30A4\u30B9",
24576
- fileRootDuplicate: "\u3053\u306E\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306F\u3053\u306E\u30C7\u30D0\u30A4\u30B9\u306B\u65E2\u306B\u8FFD\u52A0\u3055\u308C\u3066\u3044\u307E\u3059"
24716
+ fileRootDuplicate: "\u3053\u306E\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306F\u3053\u306E\u30C7\u30D0\u30A4\u30B9\u306B\u65E2\u306B\u8FFD\u52A0\u3055\u308C\u3066\u3044\u307E\u3059",
24717
+ upgradeNotAllowed: "\u3053\u306E\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3067\u306F\u30A2\u30D7\u30EA\u5185\u66F4\u65B0\u3092\u5229\u7528\u3067\u304D\u307E\u305B\u3093\u3002",
24718
+ upgradeInProgress: "\u3059\u3067\u306B\u66F4\u65B0\u304C\u9032\u884C\u4E2D\u3067\u3059\u3002",
24719
+ upgradeVersionRequired: "\u5BFE\u8C61\u30D0\u30FC\u30B8\u30E7\u30F3\u304C\u5FC5\u8981\u3067\u3059\u3002",
24720
+ updateCheckFailed: "npm registry \u306E\u7167\u4F1A\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002"
24577
24721
  },
24578
24722
  notification: {
24579
24723
  clickToJump: "\u5BFE\u5FDC\u3059\u308B\u30DA\u30A4\u30F3\u306B\u30B8\u30E3\u30F3\u30D7",
@@ -24862,7 +25006,10 @@ Bot\uFF1A{{botName}}
24862
25006
  },
24863
25007
  validation: {
24864
25008
  deviceNameRequired: "\u30C7\u30D0\u30A4\u30B9\u540D\u306F\u5FC5\u9808\u3067\u3059",
24865
- hostRequired: "SSH \u30C7\u30D0\u30A4\u30B9\u306B\u306F\u30DB\u30B9\u30C8\u30A2\u30C9\u30EC\u30B9\u304C\u5FC5\u8981\u3067\u3059"
25009
+ hostRequired: "SSH \u30C7\u30D0\u30A4\u30B9\u306B\u306F\u30DB\u30B9\u30C8\u30A2\u30C9\u30EC\u30B9\u304C\u5FC5\u8981\u3067\u3059",
25010
+ portRequired: "SSH \u30C7\u30D0\u30A4\u30B9\u306B\u306F\u6709\u52B9\u306A\u30DD\u30FC\u30C8\u304C\u5FC5\u8981\u3067\u3059",
25011
+ usernameRequired: "SSH \u30C7\u30D0\u30A4\u30B9\u306B\u306F\u30E6\u30FC\u30B6\u30FC\u540D\u304C\u5FC5\u8981\u3067\u3059",
25012
+ sshConfigRequired: "SSH \u30C7\u30D0\u30A4\u30B9\u306B\u306F ssh config \u306E\u30D1\u30B9\u304C\u5FC5\u8981\u3067\u3059"
24866
25013
  },
24867
25014
  files: {
24868
25015
  title: "\u30D5\u30A1\u30A4\u30EB",
@@ -24920,6 +25067,11 @@ function toBCP47(locale) {
24920
25067
  return locale.replace("_", "-");
24921
25068
  }
24922
25069
  var AVAILABLE_LOCALES = ["en_US", "zh_CN", "ja_JP"];
25070
+ // ../shared/src/version.ts
25071
+ function formatDisplayVersion(baseVersion, isProd) {
25072
+ const base = baseVersion?.trim() || "unknown";
25073
+ return isProd ? base : `${base}_dev`;
25074
+ }
24923
25075
  // ../shared/src/ws-borsh/index.ts
24924
25076
  var exports_ws_borsh = {};
24925
25077
  __export(exports_ws_borsh, {
@@ -27436,6 +27588,7 @@ var config = {
27436
27588
  tmuxAllowPassthrough: getBooleanEnv("TMEX_TMUX_ALLOW_PASSTHROUGH", false),
27437
27589
  tmuxTermProgram: getEnv("TMEX_TMUX_TERM_PROGRAM", "ghostty"),
27438
27590
  tmuxWindowStyle: getEnv("TMEX_TMUX_WINDOW_STYLE", "fg=#d0d0d0,bg=#262626"),
27591
+ tmuxSocket: getEnv("TMEX_TMUX_SOCKET", ""),
27439
27592
  sshReconnectMaxRetriesDefault: Number.parseInt(getEnv("TMEX_SSH_RECONNECT_MAX_RETRIES", "2"), 10),
27440
27593
  sshReconnectDelaySecondsDefault: Number.parseInt(getEnv("TMEX_SSH_RECONNECT_DELAY_SECONDS", "10"), 10),
27441
27594
  languageDefault: getEnv("TMEX_DEFAULT_LANGUAGE", "en_US"),
@@ -97013,6 +97166,19 @@ function shouldIgnoreReaderAbortError(error51) {
97013
97166
  const maybeError = error51;
97014
97167
  return maybeError.name === "AbortError" && maybeError.code === "ERR_STREAM_RELEASE_LOCK" && typeof maybeError.message === "string" && maybeError.message.includes("releaseLock");
97015
97168
  }
97169
+ var TRANSIENT_SPAWN_ERROR_CODES = new Set(["EAGAIN", "EMFILE", "ENFILE", "ENOMEM"]);
97170
+ var TMUX_SPAWN_UNAVAILABLE_EXIT = -2;
97171
+ function isTransientSpawnError(error51) {
97172
+ if (!error51 || typeof error51 !== "object") {
97173
+ return false;
97174
+ }
97175
+ const code2 = error51.code;
97176
+ if (typeof code2 === "string" && TRANSIENT_SPAWN_ERROR_CODES.has(code2)) {
97177
+ return true;
97178
+ }
97179
+ const message = error51.message;
97180
+ return typeof message === "string" && (message.includes("EAGAIN") || message.includes("posix_spawn") || message.includes("resource temporarily unavailable") || message.includes("Too many open files"));
97181
+ }
97016
97182
  function defaultRun(argv) {
97017
97183
  return new Promise((resolve3, reject) => {
97018
97184
  const subprocess = Bun.spawn(argv, {
@@ -97072,6 +97238,7 @@ class LocalExternalTmuxConnection {
97072
97238
  controlStartedAt = 0;
97073
97239
  controlRestartCount = 0;
97074
97240
  controlStderrTail = "";
97241
+ spawnUnavailableNotified = false;
97075
97242
  constructor(options, inputDeps = {}) {
97076
97243
  this.deviceId = options.deviceId;
97077
97244
  this.callbacks = options;
@@ -97123,7 +97290,13 @@ class LocalExternalTmuxConnection {
97123
97290
  this.stopControlClient();
97124
97291
  }
97125
97292
  requestSnapshot() {
97126
- this.requestSnapshotInternal();
97293
+ this.requestSnapshotInternal().catch((error51) => {
97294
+ if (isTransientSpawnError(error51)) {
97295
+ this.handleSpawnUnavailable(error51 instanceof Error ? error51.message : String(error51));
97296
+ return;
97297
+ }
97298
+ this.callbacks.onError(error51 instanceof Error ? error51 : new Error(String(error51)));
97299
+ });
97127
97300
  }
97128
97301
  sendInput(paneId, data) {
97129
97302
  if (!this.connected) {
@@ -97423,6 +97596,7 @@ class LocalExternalTmuxConnection {
97423
97596
  });
97424
97597
  const proc = this.deps.spawnControlClient([
97425
97598
  "tmux",
97599
+ ...config.tmuxSocket ? ["-L", config.tmuxSocket] : [],
97426
97600
  "-C",
97427
97601
  "attach-session",
97428
97602
  "-t",
@@ -97511,6 +97685,16 @@ class LocalExternalTmuxConnection {
97511
97685
  return;
97512
97686
  }
97513
97687
  const probe = await this.runTmuxAllowFailure(["has-session", "-t", this.sessionName]);
97688
+ if (probe.exitCode === TMUX_SPAWN_UNAVAILABLE_EXIT) {
97689
+ this.handleSpawnUnavailable(probe.stderr);
97690
+ this.controlRestartCount = Math.max(0, this.controlRestartCount - 1);
97691
+ if (this.connected && !this.manualDisconnect) {
97692
+ setTimeout(() => {
97693
+ this.reconnectControlClient(exitCode);
97694
+ }, CONTROL_RESTART_DELAY_MS * 4);
97695
+ }
97696
+ return;
97697
+ }
97514
97698
  if (probe.exitCode !== 0) {
97515
97699
  const message = probe.stderr.trim() || probe.stdout.trim() || "tmux session gone";
97516
97700
  console.warn(`[local] tmux session gone on ${this.deviceId}: ${message}`);
@@ -97622,6 +97806,11 @@ class LocalExternalTmuxConnection {
97622
97806
  ].join(SNAPSHOT_FIELD_SEPARATOR)
97623
97807
  ])
97624
97808
  ]);
97809
+ const transientResult = [sessionRes, windowsRes, panesRes].find((res) => res.exitCode === TMUX_SPAWN_UNAVAILABLE_EXIT);
97810
+ if (transientResult) {
97811
+ this.handleSpawnUnavailable(transientResult.stderr);
97812
+ return;
97813
+ }
97625
97814
  if (sessionRes.exitCode !== 0 || windowsRes.exitCode !== 0 || panesRes.exitCode !== 0) {
97626
97815
  const stderrBlob = `${sessionRes.stderr}
97627
97816
  ${windowsRes.stderr}
@@ -97645,6 +97834,7 @@ ${panesRes.stderr}`;
97645
97834
  this.parseSnapshotPanes(panesRes.stdout.split(/\r?\n/));
97646
97835
  this.discardInvalidSnapshot();
97647
97836
  this.controlSubscription?.prunePanes(new Set(this.getExpectedPaneIds()));
97837
+ this.markSpawnRecovered();
97648
97838
  this.emitSnapshot();
97649
97839
  }
97650
97840
  parseSnapshotSession(lines) {
@@ -97830,8 +98020,29 @@ ${panesRes.stderr}`;
97830
98020
  silentTelegram: true
97831
98021
  });
97832
98022
  }
98023
+ handleSpawnUnavailable(message) {
98024
+ if (this.spawnUnavailableNotified) {
98025
+ return;
98026
+ }
98027
+ this.spawnUnavailableNotified = true;
98028
+ const detail = (message || "tmux spawn unavailable (process table exhausted)").trim();
98029
+ console.warn(`[local] tmux spawn unavailable on ${this.deviceId} (process pressure), degrading without shutdown: ${detail}`);
98030
+ this.notifyRuntimeError(detail);
98031
+ }
98032
+ markSpawnRecovered() {
98033
+ this.spawnUnavailableNotified = false;
98034
+ }
97833
98035
  async runTmuxAllowFailure(argv) {
97834
- return this.deps.run(["tmux", ...argv]);
98036
+ const socketArgs = config.tmuxSocket ? ["-L", config.tmuxSocket] : [];
98037
+ try {
98038
+ return await this.deps.run(["tmux", ...socketArgs, ...argv]);
98039
+ } catch (error51) {
98040
+ if (isTransientSpawnError(error51)) {
98041
+ const message = error51 instanceof Error ? error51.message : String(error51);
98042
+ return { exitCode: TMUX_SPAWN_UNAVAILABLE_EXIT, stdout: "", stderr: message };
98043
+ }
98044
+ throw error51;
98045
+ }
97835
98046
  }
97836
98047
  isTmuxServerGoneMessage(message) {
97837
98048
  const normalized = message.toLowerCase();
@@ -103919,6 +104130,344 @@ function json5(data, status = 200) {
103919
104130
  });
103920
104131
  }
103921
104132
 
104133
+ // ../../apps/gateway/src/system/install-info.ts
104134
+ import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
104135
+ import { resolve as resolve3 } from "path";
104136
+ function resolveInstallDir() {
104137
+ const feDist = process.env.TMEX_FE_DIST_DIR;
104138
+ if (feDist) {
104139
+ return resolve3(feDist, "..", "..");
104140
+ }
104141
+ return process.cwd();
104142
+ }
104143
+ function readInstallMeta() {
104144
+ const metaPath = resolve3(resolveInstallDir(), "install-meta.json");
104145
+ try {
104146
+ if (!existsSync4(metaPath))
104147
+ return null;
104148
+ return JSON.parse(readFileSync4(metaPath, "utf8"));
104149
+ } catch {
104150
+ return null;
104151
+ }
104152
+ }
104153
+ function deploymentFromPlatform(platform) {
104154
+ if (platform === "darwin")
104155
+ return "launchd";
104156
+ if (platform === "linux")
104157
+ return "systemd";
104158
+ return "none";
104159
+ }
104160
+ function getInstallInfo() {
104161
+ if (!config.isProd) {
104162
+ return {
104163
+ installedViaCli: false,
104164
+ deployment: "none",
104165
+ installDir: null,
104166
+ serviceName: null,
104167
+ cliVersion: null
104168
+ };
104169
+ }
104170
+ const meta3 = readInstallMeta();
104171
+ if (!meta3) {
104172
+ return {
104173
+ installedViaCli: false,
104174
+ deployment: "none",
104175
+ installDir: resolveInstallDir(),
104176
+ serviceName: null,
104177
+ cliVersion: null
104178
+ };
104179
+ }
104180
+ return {
104181
+ installedViaCli: true,
104182
+ deployment: deploymentFromPlatform(meta3.platform ?? process.platform),
104183
+ installDir: meta3.installDir ?? resolveInstallDir(),
104184
+ serviceName: meta3.serviceName ?? null,
104185
+ cliVersion: meta3.cliVersion ?? null
104186
+ };
104187
+ }
104188
+
104189
+ // ../../apps/gateway/src/system/version.ts
104190
+ import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
104191
+ import { resolve as resolve4 } from "path";
104192
+ var cachedBase;
104193
+ function readRepoPackageVersion() {
104194
+ const dir2 = import.meta.dir;
104195
+ if (!dir2)
104196
+ return null;
104197
+ const path = resolve4(dir2, "../../../../packages/app/package.json");
104198
+ try {
104199
+ if (!existsSync5(path))
104200
+ return null;
104201
+ const pkg = JSON.parse(readFileSync5(path, "utf8"));
104202
+ return pkg.version ?? null;
104203
+ } catch {
104204
+ return null;
104205
+ }
104206
+ }
104207
+ function getBaseVersion() {
104208
+ if (cachedBase !== undefined)
104209
+ return cachedBase;
104210
+ let base = null;
104211
+ if ("0.11.0") {
104212
+ base = "0.11.0";
104213
+ }
104214
+ if (!base && config.isProd) {
104215
+ base = readInstallMeta()?.cliVersion ?? null;
104216
+ }
104217
+ if (!base) {
104218
+ base = readRepoPackageVersion();
104219
+ }
104220
+ cachedBase = base ?? "unknown";
104221
+ return cachedBase;
104222
+ }
104223
+ function getDisplayVersion() {
104224
+ return formatDisplayVersion(getBaseVersion(), config.isProd);
104225
+ }
104226
+ // ../../apps/gateway/src/system/semver.ts
104227
+ function parse5(input) {
104228
+ const match = input.trim().match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/);
104229
+ if (!match)
104230
+ return null;
104231
+ return {
104232
+ major: Number(match[1]),
104233
+ minor: Number(match[2]),
104234
+ patch: Number(match[3]),
104235
+ prerelease: match[4] ?? null
104236
+ };
104237
+ }
104238
+ function compareVersions(a, b3) {
104239
+ const pa = parse5(a);
104240
+ const pb = parse5(b3);
104241
+ if (!pa || !pb)
104242
+ return 0;
104243
+ if (pa.major !== pb.major)
104244
+ return pa.major > pb.major ? 1 : -1;
104245
+ if (pa.minor !== pb.minor)
104246
+ return pa.minor > pb.minor ? 1 : -1;
104247
+ if (pa.patch !== pb.patch)
104248
+ return pa.patch > pb.patch ? 1 : -1;
104249
+ if (pa.prerelease === pb.prerelease)
104250
+ return 0;
104251
+ if (pa.prerelease === null)
104252
+ return 1;
104253
+ if (pb.prerelease === null)
104254
+ return -1;
104255
+ return pa.prerelease > pb.prerelease ? 1 : pa.prerelease < pb.prerelease ? -1 : 0;
104256
+ }
104257
+
104258
+ // ../../apps/gateway/src/system/update-check.ts
104259
+ var REGISTRY_URL = "https://registry.npmjs.org/tmex-cli";
104260
+ var changelogCdnUrl = (version3) => `https://cdn.jsdelivr.net/npm/tmex-cli@${version3}/CHANGELOG.md`;
104261
+ var FETCH_TIMEOUT_MS = 1e4;
104262
+ async function checkForUpdate() {
104263
+ const current = getBaseVersion();
104264
+ const res = await fetch(REGISTRY_URL, {
104265
+ cache: "no-store",
104266
+ headers: { accept: "application/json", "cache-control": "no-cache" },
104267
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
104268
+ });
104269
+ if (!res.ok) {
104270
+ throw new Error(`npm registry HTTP ${res.status}`);
104271
+ }
104272
+ const packument = await res.json();
104273
+ const latest = packument["dist-tags"]?.latest ?? null;
104274
+ const publishedAt = latest ? packument.time?.[latest] ?? null : null;
104275
+ const hasUpdate = latest !== null && current !== "unknown" && compareVersions(latest, current) > 0;
104276
+ const changelog = latest ? await fetchChangelog(latest) : null;
104277
+ return {
104278
+ currentVersion: current,
104279
+ latestVersion: latest,
104280
+ hasUpdate,
104281
+ changelog,
104282
+ publishedAt
104283
+ };
104284
+ }
104285
+ async function fetchChangelog(version3) {
104286
+ try {
104287
+ const res = await fetch(changelogCdnUrl(version3), {
104288
+ cache: "no-store",
104289
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
104290
+ });
104291
+ if (!res.ok)
104292
+ return null;
104293
+ const text3 = await res.text();
104294
+ return text3.trim() ? text3 : null;
104295
+ } catch {
104296
+ return null;
104297
+ }
104298
+ }
104299
+ // ../../apps/gateway/src/system/upgrade.ts
104300
+ import { spawn } from "child_process";
104301
+ import { closeSync, existsSync as existsSync6, openSync } from "fs";
104302
+ import { mkdtemp, rm, writeFile } from "fs/promises";
104303
+ import { tmpdir as tmpdir3 } from "os";
104304
+ import { join as join6 } from "path";
104305
+ class UpgradeController {
104306
+ state = "idle";
104307
+ targetVersion = null;
104308
+ error = null;
104309
+ startedAt = null;
104310
+ status() {
104311
+ return {
104312
+ state: this.state,
104313
+ targetVersion: this.targetVersion,
104314
+ error: this.error,
104315
+ startedAt: this.startedAt
104316
+ };
104317
+ }
104318
+ isBusy() {
104319
+ return this.state !== "idle";
104320
+ }
104321
+ start(version3) {
104322
+ if (this.isBusy())
104323
+ return false;
104324
+ this.state = "downloading";
104325
+ this.targetVersion = version3;
104326
+ this.error = null;
104327
+ this.startedAt = new Date().toISOString();
104328
+ this.run(version3);
104329
+ return true;
104330
+ }
104331
+ async run(version3) {
104332
+ const install = getInstallInfo();
104333
+ const installDir = install.installDir;
104334
+ let stageDir = null;
104335
+ let cacheDir = null;
104336
+ try {
104337
+ if (!installDir) {
104338
+ throw new Error("install directory could not be resolved");
104339
+ }
104340
+ stageDir = await mkdtemp(join6(tmpdir3(), "tmex-upg-"));
104341
+ cacheDir = await mkdtemp(join6(tmpdir3(), "tmex-upg-cache-"));
104342
+ await writeFile(join6(stageDir, "package.json"), `${JSON.stringify({ name: "tmex-upgrade-stage", private: true })}
104343
+ `);
104344
+ await this.runBunAdd(stageDir, cacheDir, version3);
104345
+ const binPath = join6(stageDir, "node_modules", "tmex-cli", "bin", "tmex.js");
104346
+ if (!existsSync6(binPath)) {
104347
+ throw new Error(`downloaded tmex-cli binary not found at ${binPath}`);
104348
+ }
104349
+ this.state = "executing";
104350
+ this.spawnUpgrade(binPath, installDir, version3);
104351
+ } catch (err) {
104352
+ this.error = err instanceof Error ? err.message : String(err);
104353
+ this.state = "idle";
104354
+ this.targetVersion = null;
104355
+ if (stageDir)
104356
+ await rm(stageDir, { recursive: true, force: true }).catch(() => {});
104357
+ if (cacheDir)
104358
+ await rm(cacheDir, { recursive: true, force: true }).catch(() => {});
104359
+ }
104360
+ }
104361
+ runBunAdd(stageDir, cacheDir, version3) {
104362
+ return new Promise((resolve5, reject) => {
104363
+ const child = spawn(process.execPath, ["add", `tmex-cli@${version3}`], {
104364
+ cwd: stageDir,
104365
+ env: { ...process.env, BUN_INSTALL_CACHE_DIR: cacheDir },
104366
+ stdio: "ignore"
104367
+ });
104368
+ child.on("error", reject);
104369
+ child.on("close", (code2) => {
104370
+ if (code2 === 0)
104371
+ resolve5();
104372
+ else
104373
+ reject(new Error(`bun add tmex-cli@${version3} exited with code ${code2 ?? "null"}`));
104374
+ });
104375
+ });
104376
+ }
104377
+ spawnUpgrade(binPath, installDir, version3) {
104378
+ let logFd = null;
104379
+ try {
104380
+ logFd = openSync(join6(installDir, "upgrade.log"), "a");
104381
+ } catch {
104382
+ logFd = null;
104383
+ }
104384
+ const child = spawn(process.execPath, [
104385
+ binPath,
104386
+ "upgrade",
104387
+ "--apply-current-package",
104388
+ "--install-dir",
104389
+ installDir,
104390
+ "--version",
104391
+ version3
104392
+ ], {
104393
+ cwd: installDir,
104394
+ env: process.env,
104395
+ detached: true,
104396
+ stdio: logFd !== null ? ["ignore", logFd, logFd] : "ignore"
104397
+ });
104398
+ child.unref();
104399
+ if (logFd !== null)
104400
+ closeSync(logFd);
104401
+ }
104402
+ }
104403
+ var upgradeController = new UpgradeController;
104404
+
104405
+ // ../../apps/gateway/src/system/index.ts
104406
+ function getSystemInfo() {
104407
+ const install = getInstallInfo();
104408
+ const canSelfUpdate = config.isProd && install.installedViaCli && install.deployment !== "none";
104409
+ return {
104410
+ version: getDisplayVersion(),
104411
+ baseVersion: getBaseVersion(),
104412
+ isProd: config.isProd,
104413
+ installedViaCli: install.installedViaCli,
104414
+ deployment: install.deployment,
104415
+ canSelfUpdate,
104416
+ serviceName: install.serviceName
104417
+ };
104418
+ }
104419
+
104420
+ // ../../apps/gateway/src/api/system.ts
104421
+ function json6(data, status = 200) {
104422
+ return new Response(JSON.stringify(data), {
104423
+ status,
104424
+ headers: { "Content-Type": "application/json" }
104425
+ });
104426
+ }
104427
+ function handleSystemApiRequest(req, path) {
104428
+ if (path === "/api/system/info" && req.method === "GET") {
104429
+ return json6(getSystemInfo());
104430
+ }
104431
+ if (path === "/api/system/update-check" && req.method === "GET") {
104432
+ return handleUpdateCheck();
104433
+ }
104434
+ if (path === "/api/system/upgrade" && req.method === "GET") {
104435
+ return json6(upgradeController.status());
104436
+ }
104437
+ if (path === "/api/system/upgrade" && req.method === "POST") {
104438
+ return handleStartUpgrade(req);
104439
+ }
104440
+ return;
104441
+ }
104442
+ async function handleUpdateCheck() {
104443
+ try {
104444
+ return json6(await checkForUpdate());
104445
+ } catch {
104446
+ return json6({ error: t2("apiError.updateCheckFailed") }, 502);
104447
+ }
104448
+ }
104449
+ async function handleStartUpgrade(req) {
104450
+ const info = getSystemInfo();
104451
+ if (!info.canSelfUpdate) {
104452
+ return json6({ error: t2("apiError.upgradeNotAllowed") }, 403);
104453
+ }
104454
+ let version3 = "";
104455
+ try {
104456
+ const body = await req.json();
104457
+ version3 = (body?.version ?? "").trim();
104458
+ } catch {
104459
+ version3 = "";
104460
+ }
104461
+ if (!version3) {
104462
+ return json6({ error: t2("apiError.upgradeVersionRequired") }, 400);
104463
+ }
104464
+ const started = upgradeController.start(version3);
104465
+ if (!started) {
104466
+ return json6({ ...upgradeController.status(), error: t2("apiError.upgradeInProgress") }, 409);
104467
+ }
104468
+ return json6(upgradeController.status());
104469
+ }
104470
+
103922
104471
  // ../../apps/gateway/src/api/test-connection.ts
103923
104472
  function inferFailurePhase(errorType) {
103924
104473
  if (errorType === "tmux_unavailable") {
@@ -103926,7 +104475,7 @@ function inferFailurePhase(errorType) {
103926
104475
  }
103927
104476
  return "connect";
103928
104477
  }
103929
- function json6(data, status = 200) {
104478
+ function json7(data, status = 200) {
103930
104479
  return new Response(JSON.stringify(data), {
103931
104480
  status,
103932
104481
  headers: {
@@ -103945,7 +104494,7 @@ async function handleDeviceTestConnection(deviceId, inputDeps = {}) {
103945
104494
  };
103946
104495
  const device = deps.getDevice(deviceId);
103947
104496
  if (!device) {
103948
- return json6({ error: deps.translate("apiError.deviceNotFound") }, 404);
104497
+ return json7({ error: deps.translate("apiError.deviceNotFound") }, 404);
103949
104498
  }
103950
104499
  const classifyErrorResponse = (error51) => {
103951
104500
  const rawMessage = error51 instanceof Error ? error51.message : String(error51);
@@ -103958,7 +104507,7 @@ async function handleDeviceTestConnection(deviceId, inputDeps = {}) {
103958
104507
  message: deps.translate(classified.messageKey, classified.messageParams),
103959
104508
  rawMessage
103960
104509
  };
103961
- return json6(payload);
104510
+ return json7(payload);
103962
104511
  };
103963
104512
  let runtime = null;
103964
104513
  try {
@@ -103971,7 +104520,7 @@ async function handleDeviceTestConnection(deviceId, inputDeps = {}) {
103971
104520
  phase: "ready",
103972
104521
  message: deps.translate("common.success")
103973
104522
  };
103974
- return json6(payload);
104523
+ return json7(payload);
103975
104524
  } catch (error51) {
103976
104525
  return classifyErrorResponse(error51);
103977
104526
  } finally {
@@ -105078,35 +105627,35 @@ async function handleListRules(req) {
105078
105627
  if (paneId) {
105079
105628
  rules = rules.filter((rule) => rule.paneId === paneId);
105080
105629
  }
105081
- return json7({ rules: rules.map(toRuleDto) });
105630
+ return json8({ rules: rules.map(toRuleDto) });
105082
105631
  }
105083
105632
  async function handleCreateRule(req, deps) {
105084
105633
  const raw = await readJsonObjectBody3(req);
105085
105634
  if (!raw) {
105086
- return json7({ error: t2("apiError.invalidRequest") }, 400);
105635
+ return json8({ error: t2("apiError.invalidRequest") }, 400);
105087
105636
  }
105088
105637
  const body = raw;
105089
105638
  const name24 = typeof body.name === "string" ? body.name.trim() : "";
105090
105639
  if (!name24) {
105091
- return json7({ error: t2("apiError.watchNameRequired") }, 400);
105640
+ return json8({ error: t2("apiError.watchNameRequired") }, 400);
105092
105641
  }
105093
105642
  const deviceId = typeof body.deviceId === "string" ? body.deviceId.trim() : "";
105094
105643
  if (!deviceId) {
105095
- return json7({ error: t2("apiError.agentDeviceRequired") }, 400);
105644
+ return json8({ error: t2("apiError.agentDeviceRequired") }, 400);
105096
105645
  }
105097
105646
  if (!getDeviceById(deviceId)) {
105098
- return json7({ error: t2("apiError.deviceNotFound") }, 404);
105647
+ return json8({ error: t2("apiError.deviceNotFound") }, 404);
105099
105648
  }
105100
105649
  const paneId = typeof body.paneId === "string" ? body.paneId.trim() : "";
105101
105650
  if (!paneId) {
105102
- return json7({ error: t2("apiError.agentPaneRequired") }, 400);
105651
+ return json8({ error: t2("apiError.agentPaneRequired") }, 400);
105103
105652
  }
105104
105653
  if (!TRIGGER_TYPES.includes(body.triggerType)) {
105105
- return json7({ error: t2("apiError.watchTriggerTypeInvalid") }, 400);
105654
+ return json8({ error: t2("apiError.watchTriggerTypeInvalid") }, 400);
105106
105655
  }
105107
105656
  const parsed = parseRuleFields(raw);
105108
105657
  if (!parsed.ok) {
105109
- return json7({ error: parsed.error }, 400);
105658
+ return json8({ error: parsed.error }, 400);
105110
105659
  }
105111
105660
  const fields = parsed.fields;
105112
105661
  const effective = {
@@ -105119,7 +105668,7 @@ async function handleCreateRule(req, deps) {
105119
105668
  };
105120
105669
  const semanticError = validateRuleSemantics(effective);
105121
105670
  if (semanticError) {
105122
- return json7({ error: semanticError }, 400);
105671
+ return json8({ error: semanticError }, 400);
105123
105672
  }
105124
105673
  const rule = createWatchRule({
105125
105674
  name: name24,
@@ -105142,50 +105691,50 @@ async function handleCreateRule(req, deps) {
105142
105691
  cooldownSeconds: fields.cooldownSeconds
105143
105692
  });
105144
105693
  await deps.service.refreshRule(rule.id);
105145
- return json7({ rule: toRuleDto(rule), state: null }, 201);
105694
+ return json8({ rule: toRuleDto(rule), state: null }, 201);
105146
105695
  }
105147
105696
  async function handleGetRule(id) {
105148
105697
  const rule = getWatchRuleById(id);
105149
105698
  if (!rule) {
105150
- return json7({ error: t2("apiError.watchRuleNotFound") }, 404);
105699
+ return json8({ error: t2("apiError.watchRuleNotFound") }, 404);
105151
105700
  }
105152
105701
  const state = getWatchRuleState(id);
105153
- return json7({ rule: toRuleDto(rule), state: state ? toStateDto(state) : null });
105702
+ return json8({ rule: toRuleDto(rule), state: state ? toStateDto(state) : null });
105154
105703
  }
105155
105704
  async function handleUpdateRule(req, id, deps) {
105156
105705
  const existing = getWatchRuleById(id);
105157
105706
  if (!existing) {
105158
- return json7({ error: t2("apiError.watchRuleNotFound") }, 404);
105707
+ return json8({ error: t2("apiError.watchRuleNotFound") }, 404);
105159
105708
  }
105160
105709
  const raw = await readJsonObjectBody3(req);
105161
105710
  if (!raw) {
105162
- return json7({ error: t2("apiError.invalidRequest") }, 400);
105711
+ return json8({ error: t2("apiError.invalidRequest") }, 400);
105163
105712
  }
105164
105713
  const body = raw;
105165
105714
  const updates = {};
105166
105715
  if (body.name !== undefined) {
105167
105716
  const name24 = typeof body.name === "string" ? body.name.trim() : "";
105168
105717
  if (!name24) {
105169
- return json7({ error: t2("apiError.watchNameRequired") }, 400);
105718
+ return json8({ error: t2("apiError.watchNameRequired") }, 400);
105170
105719
  }
105171
105720
  updates.name = name24;
105172
105721
  }
105173
105722
  if (body.paneId !== undefined) {
105174
105723
  const paneId = typeof body.paneId === "string" ? body.paneId.trim() : "";
105175
105724
  if (!paneId) {
105176
- return json7({ error: t2("apiError.agentPaneRequired") }, 400);
105725
+ return json8({ error: t2("apiError.agentPaneRequired") }, 400);
105177
105726
  }
105178
105727
  updates.paneId = paneId;
105179
105728
  }
105180
105729
  if (body.triggerType !== undefined) {
105181
105730
  if (!TRIGGER_TYPES.includes(body.triggerType)) {
105182
- return json7({ error: t2("apiError.watchTriggerTypeInvalid") }, 400);
105731
+ return json8({ error: t2("apiError.watchTriggerTypeInvalid") }, 400);
105183
105732
  }
105184
105733
  updates.triggerType = body.triggerType;
105185
105734
  }
105186
105735
  const parsed = parseRuleFields(raw);
105187
105736
  if (!parsed.ok) {
105188
- return json7({ error: parsed.error }, 400);
105737
+ return json8({ error: parsed.error }, 400);
105189
105738
  }
105190
105739
  const fields = parsed.fields;
105191
105740
  Object.assign(updates, fields);
@@ -105199,32 +105748,32 @@ async function handleUpdateRule(req, id, deps) {
105199
105748
  };
105200
105749
  const semanticError = validateRuleSemantics(effective);
105201
105750
  if (semanticError) {
105202
- return json7({ error: semanticError }, 400);
105751
+ return json8({ error: semanticError }, 400);
105203
105752
  }
105204
105753
  const rule = updateWatchRule(id, updates);
105205
105754
  if (!rule) {
105206
- return json7({ error: t2("apiError.watchRuleNotFound") }, 404);
105755
+ return json8({ error: t2("apiError.watchRuleNotFound") }, 404);
105207
105756
  }
105208
105757
  await deps.service.refreshRule(id);
105209
105758
  const state = getWatchRuleState(id);
105210
- return json7({ rule: toRuleDto(rule), state: state ? toStateDto(state) : null });
105759
+ return json8({ rule: toRuleDto(rule), state: state ? toStateDto(state) : null });
105211
105760
  }
105212
105761
  async function handleDeleteRule(id, deps) {
105213
105762
  const existing = getWatchRuleById(id);
105214
105763
  if (!existing) {
105215
- return json7({ error: t2("apiError.watchRuleNotFound") }, 404);
105764
+ return json8({ error: t2("apiError.watchRuleNotFound") }, 404);
105216
105765
  }
105217
105766
  deleteWatchRule(id);
105218
105767
  await deps.service.removeRule(id);
105219
- return json7({ success: true });
105768
+ return json8({ success: true });
105220
105769
  }
105221
105770
  async function handleGetRuleState(id, deps) {
105222
105771
  const rule = getWatchRuleById(id);
105223
105772
  if (!rule) {
105224
- return json7({ error: t2("apiError.watchRuleNotFound") }, 404);
105773
+ return json8({ error: t2("apiError.watchRuleNotFound") }, 404);
105225
105774
  }
105226
105775
  const state = getWatchRuleState(id);
105227
- return json7({
105776
+ return json8({
105228
105777
  state: state ? toStateDto(state) : null,
105229
105778
  samples: deps.service.getSamples(id)
105230
105779
  });
@@ -105248,17 +105797,17 @@ function buildAssistPrompt(description, screen) {
105248
105797
  async function handleAssistRegex(req, deps) {
105249
105798
  const raw = await readJsonObjectBody3(req);
105250
105799
  if (!raw) {
105251
- return json7({ error: t2("apiError.invalidRequest") }, 400);
105800
+ return json8({ error: t2("apiError.invalidRequest") }, 400);
105252
105801
  }
105253
105802
  const body = raw;
105254
105803
  const description = typeof body.description === "string" ? body.description.trim() : "";
105255
105804
  if (!description) {
105256
- return json7({ error: t2("apiError.watchAssistDescriptionRequired") }, 400);
105805
+ return json8({ error: t2("apiError.watchAssistDescriptionRequired") }, 400);
105257
105806
  }
105258
105807
  let providerId = null;
105259
105808
  if (body.providerId !== undefined && body.providerId !== null) {
105260
105809
  if (typeof body.providerId !== "string" || !getLlmProviderById(body.providerId)) {
105261
- return json7({ error: t2("apiError.llmProviderNotFound") }, 400);
105810
+ return json8({ error: t2("apiError.llmProviderNotFound") }, 400);
105262
105811
  }
105263
105812
  providerId = body.providerId;
105264
105813
  }
@@ -105268,7 +105817,7 @@ async function handleAssistRegex(req, deps) {
105268
105817
  const paneId = typeof body.paneId === "string" ? body.paneId.trim() : "";
105269
105818
  if (deviceId && paneId) {
105270
105819
  if (!getDeviceById(deviceId)) {
105271
- return json7({ error: t2("apiError.deviceNotFound") }, 404);
105820
+ return json8({ error: t2("apiError.deviceNotFound") }, 404);
105272
105821
  }
105273
105822
  try {
105274
105823
  screen = await deps.captureScreen(deviceId, paneId);
@@ -105289,14 +105838,14 @@ async function handleAssistRegex(req, deps) {
105289
105838
  object3 = result.object;
105290
105839
  } catch (error51) {
105291
105840
  const detail = error51 instanceof Error ? error51.message : String(error51);
105292
- return json7({ error: t2("apiError.watchAssistModelUnavailable", { detail }) }, 502);
105841
+ return json8({ error: t2("apiError.watchAssistModelUnavailable", { detail }) }, 502);
105293
105842
  }
105294
105843
  let regex;
105295
105844
  try {
105296
105845
  regex = compileWatchPattern(object3.pattern, object3.flags);
105297
105846
  } catch (error51) {
105298
105847
  const detail = error51 instanceof Error ? error51.message : String(error51);
105299
- return json7({ error: t2("apiError.watchPatternInvalid", { detail }) }, 502);
105848
+ return json8({ error: t2("apiError.watchPatternInvalid", { detail }) }, 502);
105300
105849
  }
105301
105850
  const preview = [];
105302
105851
  if (screen) {
@@ -105310,7 +105859,7 @@ async function handleAssistRegex(req, deps) {
105310
105859
  match = regex.exec(screen);
105311
105860
  }
105312
105861
  }
105313
- return json7({
105862
+ return json8({
105314
105863
  pattern: object3.pattern,
105315
105864
  flags: object3.flags,
105316
105865
  extractGroup: object3.extractGroup >= 0 ? object3.extractGroup : 0,
@@ -105318,7 +105867,7 @@ async function handleAssistRegex(req, deps) {
105318
105867
  preview
105319
105868
  });
105320
105869
  }
105321
- function json7(data, status = 200) {
105870
+ function json8(data, status = 200) {
105322
105871
  return new Response(JSON.stringify(data), {
105323
105872
  status,
105324
105873
  headers: {
@@ -105508,6 +106057,12 @@ function handleApiRequest(req, _server) {
105508
106057
  return filesResponse;
105509
106058
  }
105510
106059
  }
106060
+ if (path.startsWith("/api/system/")) {
106061
+ const systemResponse = handleSystemApiRequest(req, path);
106062
+ if (systemResponse) {
106063
+ return systemResponse;
106064
+ }
106065
+ }
105511
106066
  if (path === "/api/webhooks" && req.method === "GET") {
105512
106067
  return handleGetWebhooks();
105513
106068
  }
@@ -105521,9 +106076,13 @@ function handleApiRequest(req, _server) {
105521
106076
  return handleGetManifest(req.method);
105522
106077
  }
105523
106078
  if (path === "/healthz" && req.method === "GET") {
105524
- return json8({ status: "ok", restarting: runtimeController.isRestarting() });
106079
+ return json9({
106080
+ status: "ok",
106081
+ restarting: runtimeController.isRestarting(),
106082
+ env: "development"
106083
+ });
105525
106084
  }
105526
- return json8({ error: t2("apiError.notFound") }, 404);
106085
+ return json9({ error: t2("apiError.notFound") }, 404);
105527
106086
  }
105528
106087
  function enrichDeviceWithRuntime(device) {
105529
106088
  const status = getDeviceRuntimeStatus(device.id);
@@ -105537,22 +106096,22 @@ function enrichDeviceWithRuntime(device) {
105537
106096
  }
105538
106097
  async function handleGetDevices() {
105539
106098
  const devices2 = getAllDevices().map(enrichDeviceWithRuntime);
105540
- return json8({ devices: devices2 });
106099
+ return json9({ devices: devices2 });
105541
106100
  }
105542
106101
  async function handleGetDevice(id) {
105543
106102
  const device = getDeviceById(id);
105544
106103
  if (!device) {
105545
- return json8({ error: t2("apiError.deviceNotFound") }, 404);
106104
+ return json9({ error: t2("apiError.deviceNotFound") }, 404);
105546
106105
  }
105547
- return json8({ device: enrichDeviceWithRuntime(device) });
106106
+ return json9({ device: enrichDeviceWithRuntime(device) });
105548
106107
  }
105549
106108
  async function handleCreateDevice(req) {
105550
106109
  const body = await req.json();
105551
106110
  if (!body.name || !body.type || !body.authMode) {
105552
- return json8({ error: t2("apiError.missingFields") }, 400);
106111
+ return json9({ error: t2("apiError.missingFields") }, 400);
105553
106112
  }
105554
106113
  if (body.type === "ssh" && !body.host && !body.sshConfigRef) {
105555
- return json8({ error: t2("apiError.sshRequiresHost") }, 400);
106114
+ return json9({ error: t2("apiError.sshRequiresHost") }, 400);
105556
106115
  }
105557
106116
  const now2 = new Date().toISOString();
105558
106117
  const device = {
@@ -105574,12 +106133,12 @@ async function handleCreateDevice(req) {
105574
106133
  };
105575
106134
  createDevice(device);
105576
106135
  await pushSupervisor.upsert(device.id);
105577
- return json8({ device: getDeviceById(device.id) ?? device }, 201);
106136
+ return json9({ device: getDeviceById(device.id) ?? device }, 201);
105578
106137
  }
105579
106138
  async function handleUpdateDevice(req, id) {
105580
106139
  const existing = getDeviceById(id);
105581
106140
  if (!existing) {
105582
- return json8({ error: t2("apiError.deviceNotFound") }, 404);
106141
+ return json9({ error: t2("apiError.deviceNotFound") }, 404);
105583
106142
  }
105584
106143
  const body = await req.json();
105585
106144
  const updates = {};
@@ -105609,61 +106168,61 @@ async function handleUpdateDevice(req, id) {
105609
106168
  await pushSupervisor.reconnect(id);
105610
106169
  }
105611
106170
  const device = getDeviceById(id);
105612
- return json8({ device });
106171
+ return json9({ device });
105613
106172
  }
105614
106173
  async function handleReorderDevices(req) {
105615
106174
  const body = await req.json();
105616
106175
  if (!Array.isArray(body.deviceIds) || body.deviceIds.some((id) => typeof id !== "string")) {
105617
- return json8({ error: t2("apiError.invalidRequest") }, 400);
106176
+ return json9({ error: t2("apiError.invalidRequest") }, 400);
105618
106177
  }
105619
106178
  reorderDevices(body.deviceIds);
105620
- return json8({ devices: getAllDevices().map(enrichDeviceWithRuntime) });
106179
+ return json9({ devices: getAllDevices().map(enrichDeviceWithRuntime) });
105621
106180
  }
105622
106181
  async function handleDeleteDevice(id) {
105623
106182
  const existing = getDeviceById(id);
105624
106183
  if (!existing) {
105625
- return json8({ error: t2("apiError.deviceNotFound") }, 404);
106184
+ return json9({ error: t2("apiError.deviceNotFound") }, 404);
105626
106185
  }
105627
106186
  deleteDevice(id);
105628
106187
  pushSupervisor.remove(id);
105629
- return json8({ success: true });
106188
+ return json9({ success: true });
105630
106189
  }
105631
106190
  async function handleTestConnection(id) {
105632
106191
  return handleDeviceTestConnection(id);
105633
106192
  }
105634
106193
  async function handleGetSiteSettings() {
105635
- return json8({ settings: getSiteSettings() });
106194
+ return json9({ settings: getSiteSettings() });
105636
106195
  }
105637
106196
  async function handleUpdateSiteSettings(req) {
105638
106197
  try {
105639
106198
  const body = await req.json();
105640
106199
  const updates = normalizeSiteSettingsInput(body);
105641
106200
  const settings = updateSiteSettings(updates);
105642
- return json8({ settings });
106201
+ return json9({ settings });
105643
106202
  } catch (err) {
105644
- return json8({ error: err instanceof Error ? err.message : t2("apiError.invalidRequest") }, 400);
106203
+ return json9({ error: err instanceof Error ? err.message : t2("apiError.invalidRequest") }, 400);
105645
106204
  }
105646
106205
  }
105647
106206
  async function handleRestartGateway() {
105648
106207
  setTimeout(() => {
105649
106208
  runtimeController.requestRestart();
105650
106209
  }, 50);
105651
- return json8({
106210
+ return json9({
105652
106211
  success: true,
105653
106212
  message: t2("settings.restartScheduled")
105654
106213
  });
105655
106214
  }
105656
106215
  async function handleGetTelegramBots() {
105657
106216
  const bots = getTelegramBotsWithStats();
105658
- return json8({ bots });
106217
+ return json9({ bots });
105659
106218
  }
105660
106219
  async function handleCreateTelegramBot(req) {
105661
106220
  const body = await req.json();
105662
106221
  if (!body.name?.trim()) {
105663
- return json8({ error: t2("apiError.botNameRequired") }, 400);
106222
+ return json9({ error: t2("apiError.botNameRequired") }, 400);
105664
106223
  }
105665
106224
  if (!body.token?.trim()) {
105666
- return json8({ error: t2("apiError.botTokenRequired") }, 400);
106225
+ return json9({ error: t2("apiError.botTokenRequired") }, 400);
105667
106226
  }
105668
106227
  const now2 = new Date().toISOString();
105669
106228
  createTelegramBot({
@@ -105677,26 +106236,26 @@ async function handleCreateTelegramBot(req) {
105677
106236
  updatedAt: now2
105678
106237
  });
105679
106238
  await telegramService.refresh();
105680
- return json8({ success: true }, 201);
106239
+ return json9({ success: true }, 201);
105681
106240
  }
105682
106241
  async function handleUpdateTelegramBot(req, botId) {
105683
106242
  const existing = getTelegramBotById(botId);
105684
106243
  if (!existing) {
105685
- return json8({ error: t2("apiError.botNotFound") }, 404);
106244
+ return json9({ error: t2("apiError.botNotFound") }, 404);
105686
106245
  }
105687
106246
  const body = await req.json();
105688
106247
  const updates = {};
105689
106248
  if (body.name !== undefined) {
105690
106249
  const value = body.name.trim();
105691
106250
  if (!value) {
105692
- return json8({ error: t2("apiError.botNameRequired") }, 400);
106251
+ return json9({ error: t2("apiError.botNameRequired") }, 400);
105693
106252
  }
105694
106253
  updates.name = value;
105695
106254
  }
105696
106255
  if (body.token !== undefined) {
105697
106256
  const token = body.token.trim();
105698
106257
  if (!token) {
105699
- return json8({ error: t2("apiError.botTokenRequired") }, 400);
106258
+ return json9({ error: t2("apiError.botTokenRequired") }, 400);
105700
106259
  }
105701
106260
  updates.tokenEnc = await encrypt(token);
105702
106261
  }
@@ -105708,69 +106267,69 @@ async function handleUpdateTelegramBot(req, botId) {
105708
106267
  }
105709
106268
  updateTelegramBot(botId, updates);
105710
106269
  await telegramService.refresh();
105711
- return json8({ success: true });
106270
+ return json9({ success: true });
105712
106271
  }
105713
106272
  async function handleDeleteTelegramBot(botId) {
105714
106273
  const existing = getTelegramBotById(botId);
105715
106274
  if (!existing) {
105716
- return json8({ error: t2("apiError.botNotFound") }, 404);
106275
+ return json9({ error: t2("apiError.botNotFound") }, 404);
105717
106276
  }
105718
106277
  deleteTelegramBot(botId);
105719
106278
  await telegramService.refresh();
105720
- return json8({ success: true });
106279
+ return json9({ success: true });
105721
106280
  }
105722
106281
  async function handleListTelegramChats(botId) {
105723
106282
  const existing = getTelegramBotById(botId);
105724
106283
  if (!existing) {
105725
- return json8({ error: t2("apiError.botNotFound") }, 404);
106284
+ return json9({ error: t2("apiError.botNotFound") }, 404);
105726
106285
  }
105727
106286
  const chats = listTelegramChatsByBot(botId);
105728
- return json8({ chats });
106287
+ return json9({ chats });
105729
106288
  }
105730
106289
  async function handleApproveTelegramChat(botId, chatId) {
105731
106290
  const existing = getTelegramBotById(botId);
105732
106291
  if (!existing) {
105733
- return json8({ error: t2("apiError.botNotFound") }, 404);
106292
+ return json9({ error: t2("apiError.botNotFound") }, 404);
105734
106293
  }
105735
106294
  const chat = approveTelegramChat(botId, chatId);
105736
106295
  if (!chat) {
105737
- return json8({ error: t2("apiError.chatNotFound") }, 404);
106296
+ return json9({ error: t2("apiError.chatNotFound") }, 404);
105738
106297
  }
105739
106298
  const settings = getSiteSettings();
105740
106299
  await telegramService.sendTestMessage(botId, chatId, t2("telegram.approveMessageTemplate", {
105741
106300
  botName: existing.name,
105742
106301
  time: new Date().toLocaleString(toBCP47(settings.language))
105743
106302
  }));
105744
- return json8({ chat });
106303
+ return json9({ chat });
105745
106304
  }
105746
106305
  async function handleDeleteTelegramChat(botId, chatId) {
105747
106306
  const existing = getTelegramBotById(botId);
105748
106307
  if (!existing) {
105749
- return json8({ error: t2("apiError.botNotFound") }, 404);
106308
+ return json9({ error: t2("apiError.botNotFound") }, 404);
105750
106309
  }
105751
106310
  deleteTelegramChat(botId, chatId);
105752
- return json8({ success: true });
106311
+ return json9({ success: true });
105753
106312
  }
105754
106313
  async function handleTestTelegramChat(botId, chatId) {
105755
106314
  const bot = getTelegramBotById(botId);
105756
106315
  if (!bot) {
105757
- return json8({ error: t2("apiError.botNotFound") }, 404);
106316
+ return json9({ error: t2("apiError.botNotFound") }, 404);
105758
106317
  }
105759
106318
  const settings = getSiteSettings();
105760
106319
  await telegramService.sendTestMessage(botId, chatId, t2("telegram.testMessageTemplate", {
105761
106320
  siteName: settings.siteName,
105762
106321
  time: new Date().toLocaleString(toBCP47(settings.language))
105763
106322
  }));
105764
- return json8({ success: true });
106323
+ return json9({ success: true });
105765
106324
  }
105766
106325
  async function handleGetWebhooks() {
105767
106326
  const webhooks = getAllWebhookEndpoints();
105768
- return json8({ webhooks });
106327
+ return json9({ webhooks });
105769
106328
  }
105770
106329
  async function handleCreateWebhook(req) {
105771
106330
  const body = await req.json();
105772
106331
  if (!body.url || !body.secret) {
105773
- return json8({ error: t2("apiError.urlAndSecretRequired") }, 400);
106332
+ return json9({ error: t2("apiError.urlAndSecretRequired") }, 400);
105774
106333
  }
105775
106334
  const now2 = new Date().toISOString();
105776
106335
  const endpoint = {
@@ -105783,11 +106342,11 @@ async function handleCreateWebhook(req) {
105783
106342
  updatedAt: now2
105784
106343
  };
105785
106344
  createWebhookEndpoint(endpoint);
105786
- return json8({ webhook: endpoint }, 201);
106345
+ return json9({ webhook: endpoint }, 201);
105787
106346
  }
105788
106347
  async function handleDeleteWebhook(id) {
105789
106348
  deleteWebhookEndpoint(id);
105790
- return json8({ success: true });
106349
+ return json9({ success: true });
105791
106350
  }
105792
106351
  async function handleGetManifest(method) {
105793
106352
  const settings = getSiteSettings();
@@ -105808,7 +106367,7 @@ async function handleGetManifest(method) {
105808
106367
  purpose: "any"
105809
106368
  },
105810
106369
  {
105811
- src: "/tmex.png",
106370
+ src: "/tmex-maskable.png",
105812
106371
  sizes: "1024x1024",
105813
106372
  type: "image/png",
105814
106373
  purpose: "maskable"
@@ -105826,7 +106385,7 @@ function manifestJson(data, method) {
105826
106385
  }
105827
106386
  });
105828
106387
  }
105829
- function json8(data, status = 200, headers = {}) {
106388
+ function json9(data, status = 200, headers = {}) {
105830
106389
  return new Response(JSON.stringify(data), {
105831
106390
  status,
105832
106391
  headers: {
@@ -105837,8 +106396,8 @@ function json8(data, status = 200, headers = {}) {
105837
106396
  }
105838
106397
 
105839
106398
  // ../../apps/gateway/src/db/migrate.ts
105840
- import { existsSync as existsSync4 } from "fs";
105841
- import { resolve as resolve3 } from "path";
106399
+ import { existsSync as existsSync7 } from "fs";
106400
+ import { resolve as resolve5 } from "path";
105842
106401
 
105843
106402
  // ../../node_modules/.bun/drizzle-orm@0.45.1+d3720f6f296df04b/node_modules/drizzle-orm/migrator.js
105844
106403
  import crypto2 from "crypto";
@@ -105883,10 +106442,10 @@ function resolveMigrationsFolder() {
105883
106442
  const fromEnv = process.env.TMEX_MIGRATIONS_DIR;
105884
106443
  if (fromEnv)
105885
106444
  return fromEnv;
105886
- const byCwd = resolve3(process.cwd(), "drizzle");
105887
- if (existsSync4(byCwd))
106445
+ const byCwd = resolve5(process.cwd(), "drizzle");
106446
+ if (existsSync7(byCwd))
105888
106447
  return byCwd;
105889
- return resolve3(import.meta.dir, "../../drizzle");
106448
+ return resolve5(import.meta.dir, "../../drizzle");
105890
106449
  }
105891
106450
  var migrationsFolder = resolveMigrationsFolder();
105892
106451
  function runMigrations() {
@@ -107688,16 +108247,16 @@ function contentTypeByPath(path) {
107688
108247
  }
107689
108248
  function resolveStaticRoot() {
107690
108249
  if (process.env.TMEX_FE_DIST_DIR) {
107691
- return resolve4(process.env.TMEX_FE_DIST_DIR);
108250
+ return resolve6(process.env.TMEX_FE_DIST_DIR);
107692
108251
  }
107693
- return resolve4(import.meta.dir, "../../resources/fe-dist");
108252
+ return resolve6(import.meta.dir, "../../resources/fe-dist");
107694
108253
  }
107695
108254
  function resolveRequestedFile(staticRoot, pathname) {
107696
- const root = resolve4(staticRoot);
108255
+ const root = resolve6(staticRoot);
107697
108256
  const decoded = decodeURIComponent(pathname);
107698
108257
  const normalized = normalize(decoded).replace(/^\.\.(\/|\\|$)/, "");
107699
108258
  const requested = normalized === "/" ? "/index.html" : normalized;
107700
- const absolutePath = resolve4(root, `.${requested}`);
108259
+ const absolutePath = resolve6(root, `.${requested}`);
107701
108260
  if (absolutePath !== root && !absolutePath.startsWith(`${root}${sep}`)) {
107702
108261
  return null;
107703
108262
  }
@@ -107712,12 +108271,12 @@ async function serveFrontend(req, staticRoot) {
107712
108271
  if (!requestedPath) {
107713
108272
  return new Response(t3("runtime.forbidden"), { status: 403 });
107714
108273
  }
107715
- if (!existsSync5(requestedPath) && extname2(url2.pathname) !== "") {
108274
+ if (!existsSync8(requestedPath) && extname2(url2.pathname) !== "") {
107716
108275
  return new Response(t3("runtime.notFound"), { status: 404 });
107717
108276
  }
107718
- const indexPath = join6(staticRoot, "index.html");
107719
- const targetPath = existsSync5(requestedPath) ? requestedPath : indexPath;
107720
- if (!existsSync5(targetPath)) {
108277
+ const indexPath = join7(staticRoot, "index.html");
108278
+ const targetPath = existsSync8(requestedPath) ? requestedPath : indexPath;
108279
+ if (!existsSync8(targetPath)) {
107721
108280
  return new Response(t3("runtime.frontendMissing"), { status: 500 });
107722
108281
  }
107723
108282
  const headers = new Headers;
@@ -107728,6 +108287,7 @@ async function serveFrontend(req, staticRoot) {
107728
108287
  return new Response(Bun.file(targetPath), { headers });
107729
108288
  }
107730
108289
  async function main() {
108290
+ console.log(`[tmex] version ${getDisplayVersion()}`);
107731
108291
  const host = process.env.TMEX_BIND_HOST || "127.0.0.1";
107732
108292
  const port = Number(process.env.GATEWAY_PORT || "9883");
107733
108293
  const staticRoot = resolveStaticRoot();