tmex-cli 0.16.2 → 0.16.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -21
- package/dist/runtime/server.js +583 -227
- package/package.json +1 -1
- package/resources/fe-dist/assets/DevicePage-DtByPprm.js +24 -0
- package/resources/fe-dist/assets/{DevicesPage-B_jvUZtl.js → DevicesPage-WMW0FcaU.js} +1 -1
- package/resources/fe-dist/assets/{FilePage-DTSmWM1D.js → FilePage-C3yjgRDh.js} +1 -1
- package/resources/fe-dist/assets/{SettingsPage-LTHV37Rj.js → SettingsPage-CKZEPwEq.js} +4 -4
- package/resources/fe-dist/assets/{agent-tab-vPjPGa5f.js → agent-tab-B77EotmX.js} +1 -1
- package/resources/fe-dist/assets/{api-D_FToAy0.js → api-DZDjPn8l.js} +1 -1
- package/resources/fe-dist/assets/{arc-BSCyoyGW.js → arc-DNrUdLWP.js} +1 -1
- package/resources/fe-dist/assets/{architectureDiagram-3BPJPVTR-CBO0dAe2.js → architectureDiagram-3BPJPVTR-B5DYf-5o.js} +1 -1
- package/resources/fe-dist/assets/{blockDiagram-GPEHLZMM-0ONANm30.js → blockDiagram-GPEHLZMM-DSgjcUbw.js} +1 -1
- package/resources/fe-dist/assets/{c4Diagram-AAUBKEIU-DpvhCnF8.js → c4Diagram-AAUBKEIU-DKjqulHT.js} +1 -1
- package/resources/fe-dist/assets/{card-CD9i-fLq.js → card-DWQzPt-3.js} +1 -1
- package/resources/fe-dist/assets/channel-CpZANba-.js +1 -0
- package/resources/fe-dist/assets/{chunk-2J33WTMH-MmS9_ur_.js → chunk-2J33WTMH-DHQ_-AlN.js} +1 -1
- package/resources/fe-dist/assets/{chunk-4BX2VUAB-CLd4Yxwh.js → chunk-4BX2VUAB-C7sszhBq.js} +1 -1
- package/resources/fe-dist/assets/{chunk-55IACEB6-DgCH4WwT.js → chunk-55IACEB6-BkPT2okv.js} +1 -1
- package/resources/fe-dist/assets/{chunk-727SXJPM-B9DM5PB4.js → chunk-727SXJPM-BsD5c54G.js} +1 -1
- package/resources/fe-dist/assets/{chunk-AQP2D5EJ-DQwC9D9W.js → chunk-AQP2D5EJ-Dx3mc4xO.js} +1 -1
- package/resources/fe-dist/assets/{chunk-FMBD7UC4-BnvyNYGh.js → chunk-FMBD7UC4-CyZO-UAp.js} +1 -1
- package/resources/fe-dist/assets/{chunk-ND2GUHAM-BzcZgEWG.js → chunk-ND2GUHAM-DNxRBeA7.js} +1 -1
- package/resources/fe-dist/assets/{chunk-QZHKN3VN-C9BaHIUI.js → chunk-QZHKN3VN-DsPa138W.js} +1 -1
- package/resources/fe-dist/assets/classDiagram-4FO5ZUOK-BW09ep_0.js +1 -0
- package/resources/fe-dist/assets/classDiagram-v2-Q7XG4LA2-BW09ep_0.js +1 -0
- package/resources/fe-dist/assets/{copy-DzIk8AxV.js → copy-DwXKDgGT.js} +1 -1
- package/resources/fe-dist/assets/{cose-bilkent-S5V4N54A-NkTc0ObP.js → cose-bilkent-S5V4N54A-C1d180_v.js} +1 -1
- package/resources/fe-dist/assets/{dagre-BM42HDAG-BdFDBfE_.js → dagre-BM42HDAG-Bv8hvnH7.js} +1 -1
- package/resources/fe-dist/assets/{diagram-2AECGRRQ-Ba4Y0igR.js → diagram-2AECGRRQ-DfbJBHI6.js} +1 -1
- package/resources/fe-dist/assets/{diagram-5GNKFQAL-B4_Or8Vp.js → diagram-5GNKFQAL-COnOrAiu.js} +1 -1
- package/resources/fe-dist/assets/{diagram-KO2AKTUF-DbmmHTYj.js → diagram-KO2AKTUF-BOtU5EdV.js} +1 -1
- package/resources/fe-dist/assets/{diagram-LMA3HP47-CRrd6lc4.js → diagram-LMA3HP47-B-WcT-Mc.js} +1 -1
- package/resources/fe-dist/assets/{diagram-OG6HWLK6-BOEazFIu.js → diagram-OG6HWLK6-BptGbu0F.js} +1 -1
- package/resources/fe-dist/assets/{erDiagram-TEJ5UH35-Dk-UowK8.js → erDiagram-TEJ5UH35-H06uoCHU.js} +1 -1
- package/resources/fe-dist/assets/{files-tab-D2vddvsj.js → files-tab-C841Mmn_.js} +1 -1
- package/resources/fe-dist/assets/{flowDiagram-I6XJVG4X-BhbGYx-g.js → flowDiagram-I6XJVG4X-QOk_IVWN.js} +1 -1
- package/resources/fe-dist/assets/{ganttDiagram-6RSMTGT7-iezClDTv.js → ganttDiagram-6RSMTGT7-Q7s2jHyi.js} +1 -1
- package/resources/fe-dist/assets/{gitGraphDiagram-PVQCEYII-Ncqf3CQw.js → gitGraphDiagram-PVQCEYII-Q7tAtx1u.js} +1 -1
- package/resources/fe-dist/assets/{index-DOfY8kwB.js → index-C2v9tHtI.js} +1 -1
- package/resources/fe-dist/assets/{index-UoApkLSY.js → index-Dc3Fwpho.js} +63 -63
- package/resources/fe-dist/assets/{infoDiagram-5YYISTIA-CUg3PkAb.js → infoDiagram-5YYISTIA-B9n7MrtF.js} +1 -1
- package/resources/fe-dist/assets/{ishikawaDiagram-YF4QCWOH-DU0ekJw5.js → ishikawaDiagram-YF4QCWOH-oZeau8IS.js} +1 -1
- package/resources/fe-dist/assets/{journeyDiagram-JHISSGLW-Ji7WtMH7.js → journeyDiagram-JHISSGLW-ClXjUmc1.js} +1 -1
- package/resources/fe-dist/assets/{kanban-definition-UN3LZRKU-B8zVyM8Q.js → kanban-definition-UN3LZRKU-Cwn4VzH2.js} +1 -1
- package/resources/fe-dist/assets/{linear-tNPPicfI.js → linear-BNOQBDiB.js} +1 -1
- package/resources/fe-dist/assets/{markdown-preview-CzbcKxcJ.js → markdown-preview-BsYVAcJ1.js} +3 -3
- package/resources/fe-dist/assets/{mermaid.core-BoNU6G1d.js → mermaid.core-C3nmuA6R.js} +5 -5
- package/resources/fe-dist/assets/{mindmap-definition-RKZ34NQL-D_v1LaNP.js → mindmap-definition-RKZ34NQL-BKstxajf.js} +1 -1
- package/resources/fe-dist/assets/{pieDiagram-4H26LBE5-B1CHCpFf.js → pieDiagram-4H26LBE5-D_2bHoC9.js} +1 -1
- package/resources/fe-dist/assets/{quadrantDiagram-W4KKPZXB-DvA3zgR7.js → quadrantDiagram-W4KKPZXB-D6K_QmUy.js} +1 -1
- package/resources/fe-dist/assets/{requirementDiagram-4Y6WPE33-BCna6ZG5.js → requirementDiagram-4Y6WPE33-B1SWUDkA.js} +1 -1
- package/resources/fe-dist/assets/{sankeyDiagram-5OEKKPKP-KEllFLAf.js → sankeyDiagram-5OEKKPKP-DPmalO0b.js} +1 -1
- package/resources/fe-dist/assets/{send-BgCF67Uc.js → send-J45szXFM.js} +1 -1
- package/resources/fe-dist/assets/{sequenceDiagram-3UESZ5HK-DRsq_jg_.js → sequenceDiagram-3UESZ5HK-C08DcZug.js} +1 -1
- package/resources/fe-dist/assets/{stateDiagram-AJRCARHV-DhATBo8D.js → stateDiagram-AJRCARHV-K9bVAVhg.js} +1 -1
- package/resources/fe-dist/assets/stateDiagram-v2-BHNVJYJU-DTGkSC6X.js +1 -0
- package/resources/fe-dist/assets/{terminal-settings-panel-DsMMZFBi.js → terminal-settings-panel-tZuaqdqz.js} +2 -2
- package/resources/fe-dist/assets/{timeline-definition-PNZ67QCA-Det7AzPd.js → timeline-definition-PNZ67QCA-DG0FtOvK.js} +1 -1
- package/resources/fe-dist/assets/{transfer-toast-CHcCj3qf.js → transfer-toast-D72q4082.js} +1 -1
- package/resources/fe-dist/assets/{triangle-alert-BjHP6Ipw.js → triangle-alert-CagsqsWp.js} +1 -1
- package/resources/fe-dist/assets/{vennDiagram-CIIHVFJN-BF4R466L.js → vennDiagram-CIIHVFJN-CKBEKUkA.js} +1 -1
- package/resources/fe-dist/assets/{wardley-L42UT6IY-DLHZ_6-V.js → wardley-L42UT6IY-DTlpnptg.js} +1 -1
- package/resources/fe-dist/assets/{wardleyDiagram-YWT4CUSO-CekN3Ye6.js → wardleyDiagram-YWT4CUSO-CnwEikRb.js} +1 -1
- package/resources/fe-dist/assets/{xychartDiagram-2RQKCTM6-CJD3yg0M.js → xychartDiagram-2RQKCTM6-uaYRX4Ue.js} +1 -1
- package/resources/fe-dist/assets/{zap-Dx7JTXJN.js → zap-DcJ8Gp1I.js} +1 -1
- package/resources/fe-dist/index.html +1 -1
- package/resources/gateway-drizzle/0014_lucky_killraven.sql +1 -0
- package/resources/gateway-drizzle/meta/_journal.json +7 -0
- package/resources/fe-dist/assets/DevicePage-CgDkuNLp.js +0 -24
- package/resources/fe-dist/assets/channel-DBhb6_En.js +0 -1
- package/resources/fe-dist/assets/classDiagram-4FO5ZUOK-9V2iXOG7.js +0 -1
- package/resources/fe-dist/assets/classDiagram-v2-Q7XG4LA2-9V2iXOG7.js +0 -1
- package/resources/fe-dist/assets/stateDiagram-v2-BHNVJYJU-Dn_gMFVD.js +0 -1
package/dist/runtime/server.js
CHANGED
|
@@ -25668,6 +25668,8 @@ __export(exports_ws_borsh, {
|
|
|
25668
25668
|
WATCH_EVENT_TRIGGERED: () => WATCH_EVENT_TRIGGERED,
|
|
25669
25669
|
WATCH_EVENT_RULE_ERROR: () => WATCH_EVENT_RULE_ERROR,
|
|
25670
25670
|
WATCH_EVENT_MODEL_UNAVAILABLE: () => WATCH_EVENT_MODEL_UNAVAILABLE,
|
|
25671
|
+
SITE_THEME_LIGHT: () => SITE_THEME_LIGHT,
|
|
25672
|
+
SITE_THEME_DARK: () => SITE_THEME_DARK,
|
|
25671
25673
|
MAX_CHUNK_STREAMS: () => MAX_CHUNK_STREAMS,
|
|
25672
25674
|
MAX_CHUNKS_PER_MESSAGE: () => MAX_CHUNKS_PER_MESSAGE,
|
|
25673
25675
|
MAGIC: () => MAGIC,
|
|
@@ -25700,6 +25702,7 @@ __export(exports_ws_borsh, {
|
|
|
25700
25702
|
KIND_SWITCH_ACK: () => KIND_SWITCH_ACK,
|
|
25701
25703
|
KIND_STATE_SNAPSHOT_DIFF: () => KIND_STATE_SNAPSHOT_DIFF,
|
|
25702
25704
|
KIND_STATE_SNAPSHOT: () => KIND_STATE_SNAPSHOT,
|
|
25705
|
+
KIND_SITE_THEME_UPDATE: () => KIND_SITE_THEME_UPDATE,
|
|
25703
25706
|
KIND_PONG: () => KIND_PONG,
|
|
25704
25707
|
KIND_PING: () => KIND_PING,
|
|
25705
25708
|
KIND_LIVE_RESUME: () => KIND_LIVE_RESUME,
|
|
@@ -25800,6 +25803,7 @@ var KIND_AGENT_SUBSCRIBE = 1537;
|
|
|
25800
25803
|
var KIND_AGENT_UNSUBSCRIBE = 1538;
|
|
25801
25804
|
var KIND_AGENT_EVENT = 1539;
|
|
25802
25805
|
var KIND_WATCH_EVENT = 1793;
|
|
25806
|
+
var KIND_SITE_THEME_UPDATE = 2049;
|
|
25803
25807
|
var VALID_KINDS = new Set([
|
|
25804
25808
|
KIND_HELLO_C2S,
|
|
25805
25809
|
KIND_HELLO_S2C,
|
|
@@ -25845,7 +25849,8 @@ var VALID_KINDS = new Set([
|
|
|
25845
25849
|
KIND_AGENT_SUBSCRIBE,
|
|
25846
25850
|
KIND_AGENT_UNSUBSCRIBE,
|
|
25847
25851
|
KIND_AGENT_EVENT,
|
|
25848
|
-
KIND_WATCH_EVENT
|
|
25852
|
+
KIND_WATCH_EVENT,
|
|
25853
|
+
KIND_SITE_THEME_UPDATE
|
|
25849
25854
|
]);
|
|
25850
25855
|
function isValidKind(kind) {
|
|
25851
25856
|
return VALID_KINDS.has(kind);
|
|
@@ -25896,68 +25901,11 @@ function kindToString(kind) {
|
|
|
25896
25901
|
[KIND_AGENT_SUBSCRIBE]: "AGENT_SUBSCRIBE",
|
|
25897
25902
|
[KIND_AGENT_UNSUBSCRIBE]: "AGENT_UNSUBSCRIBE",
|
|
25898
25903
|
[KIND_AGENT_EVENT]: "AGENT_EVENT",
|
|
25899
|
-
[KIND_WATCH_EVENT]: "WATCH_EVENT"
|
|
25904
|
+
[KIND_WATCH_EVENT]: "WATCH_EVENT",
|
|
25905
|
+
[KIND_SITE_THEME_UPDATE]: "SITE_THEME_UPDATE"
|
|
25900
25906
|
};
|
|
25901
25907
|
return kindMap[kind] ?? `UNKNOWN(0x${kind.toString(16).padStart(4, "0")})`;
|
|
25902
25908
|
}
|
|
25903
|
-
// ../shared/src/ws-borsh/agent.ts
|
|
25904
|
-
var AGENT_EVENT_SYNC = 1;
|
|
25905
|
-
var AGENT_EVENT_STATUS = 2;
|
|
25906
|
-
var AGENT_EVENT_TEXT_DELTA = 3;
|
|
25907
|
-
var AGENT_EVENT_REASONING_DELTA = 4;
|
|
25908
|
-
var AGENT_EVENT_TOOL_CALL = 5;
|
|
25909
|
-
var AGENT_EVENT_TOOL_RESULT = 6;
|
|
25910
|
-
var AGENT_EVENT_CONFIRMATION_REQUEST = 7;
|
|
25911
|
-
var AGENT_EVENT_CONFIRMATION_RESOLVED = 8;
|
|
25912
|
-
var AGENT_EVENT_MESSAGE_PERSISTED = 9;
|
|
25913
|
-
var AGENT_EVENT_ERROR = 10;
|
|
25914
|
-
var AGENT_EVENT_TURN_FINISHED = 11;
|
|
25915
|
-
var AGENT_EVENT_CREDENTIAL_WARNING = 12;
|
|
25916
|
-
var AGENT_EVENT_QUEUE_UPDATED = 13;
|
|
25917
|
-
var WATCH_EVENT_TRIGGERED = 1;
|
|
25918
|
-
var WATCH_EVENT_MODEL_UNAVAILABLE = 2;
|
|
25919
|
-
var WATCH_EVENT_RULE_ERROR = 3;
|
|
25920
|
-
// ../shared/src/ws-borsh/errors.ts
|
|
25921
|
-
var ERROR_UNSUPPORTED_PROTOCOL = 1001;
|
|
25922
|
-
var ERROR_INVALID_FRAME = 1002;
|
|
25923
|
-
var ERROR_UNKNOWN_KIND = 1003;
|
|
25924
|
-
var ERROR_PAYLOAD_DECODE_FAILED = 1004;
|
|
25925
|
-
var ERROR_FRAME_TOO_LARGE = 1005;
|
|
25926
|
-
var ERROR_DEVICE_NOT_FOUND = 1101;
|
|
25927
|
-
var ERROR_DEVICE_CONNECT_FAILED = 1102;
|
|
25928
|
-
var ERROR_TMUX_TARGET_NOT_FOUND = 1201;
|
|
25929
|
-
var ERROR_TMUX_NOT_READY = 1202;
|
|
25930
|
-
var ERROR_SELECT_CONFLICT = 1301;
|
|
25931
|
-
var ERROR_SELECT_TOKEN_MISMATCH = 1302;
|
|
25932
|
-
var ERROR_INTERNAL_ERROR = 1401;
|
|
25933
|
-
var ERROR_MESSAGES = {
|
|
25934
|
-
[ERROR_UNSUPPORTED_PROTOCOL]: "Unsupported protocol version",
|
|
25935
|
-
[ERROR_INVALID_FRAME]: "Invalid frame format",
|
|
25936
|
-
[ERROR_UNKNOWN_KIND]: "Unknown message kind",
|
|
25937
|
-
[ERROR_PAYLOAD_DECODE_FAILED]: "Failed to decode payload",
|
|
25938
|
-
[ERROR_FRAME_TOO_LARGE]: "Frame exceeds maximum size",
|
|
25939
|
-
[ERROR_DEVICE_NOT_FOUND]: "Device not found",
|
|
25940
|
-
[ERROR_DEVICE_CONNECT_FAILED]: "Failed to connect device",
|
|
25941
|
-
[ERROR_TMUX_TARGET_NOT_FOUND]: "Tmux target not found",
|
|
25942
|
-
[ERROR_TMUX_NOT_READY]: "Tmux not ready",
|
|
25943
|
-
[ERROR_SELECT_CONFLICT]: "Select conflict",
|
|
25944
|
-
[ERROR_SELECT_TOKEN_MISMATCH]: "Select token mismatch",
|
|
25945
|
-
[ERROR_INTERNAL_ERROR]: "Internal server error"
|
|
25946
|
-
};
|
|
25947
|
-
function getErrorMessage(code) {
|
|
25948
|
-
return ERROR_MESSAGES[code] ?? `Unknown error code: ${code}`;
|
|
25949
|
-
}
|
|
25950
|
-
|
|
25951
|
-
class WsBorshError extends Error {
|
|
25952
|
-
code;
|
|
25953
|
-
retryable;
|
|
25954
|
-
constructor(code, retryable = false, message) {
|
|
25955
|
-
super(message ?? getErrorMessage(code));
|
|
25956
|
-
this.code = code;
|
|
25957
|
-
this.retryable = retryable;
|
|
25958
|
-
this.name = "WsBorshError";
|
|
25959
|
-
}
|
|
25960
|
-
}
|
|
25961
25909
|
// ../shared/src/ws-borsh/schema.ts
|
|
25962
25910
|
var exports_schema = {};
|
|
25963
25911
|
__export(exports_schema, {
|
|
@@ -25995,7 +25943,11 @@ __export(exports_schema, {
|
|
|
25995
25943
|
SwitchAckSchema: () => SwitchAckSchema,
|
|
25996
25944
|
StateSnapshotSchema: () => StateSnapshotSchema,
|
|
25997
25945
|
StateSnapshotDiffSchema: () => StateSnapshotDiffSchema,
|
|
25946
|
+
SiteThemeUpdateS2CSchema: () => SiteThemeUpdateS2CSchema,
|
|
25947
|
+
SiteThemeUpdateC2SSchema: () => SiteThemeUpdateC2SSchema,
|
|
25998
25948
|
SessionWireSchema: () => SessionWireSchema,
|
|
25949
|
+
SITE_THEME_LIGHT: () => SITE_THEME_LIGHT,
|
|
25950
|
+
SITE_THEME_DARK: () => SITE_THEME_DARK,
|
|
25999
25951
|
PingPongSchema: () => PingPongSchema,
|
|
26000
25952
|
PaneWireSchema: () => PaneWireSchema,
|
|
26001
25953
|
PaneCloseEventSchema: () => PaneCloseEventSchema,
|
|
@@ -26341,6 +26293,73 @@ var NotificationEventSchema = import_zorsh.b.struct({
|
|
|
26341
26293
|
paneTitle: OptionStringSchema,
|
|
26342
26294
|
paneCurrentCommand: OptionStringSchema
|
|
26343
26295
|
});
|
|
26296
|
+
var SITE_THEME_DARK = 0;
|
|
26297
|
+
var SITE_THEME_LIGHT = 1;
|
|
26298
|
+
var SiteThemeUpdateC2SSchema = import_zorsh.b.struct({
|
|
26299
|
+
theme: import_zorsh.b.u8()
|
|
26300
|
+
});
|
|
26301
|
+
var SiteThemeUpdateS2CSchema = import_zorsh.b.struct({
|
|
26302
|
+
theme: import_zorsh.b.u8(),
|
|
26303
|
+
serverTimestamp: import_zorsh.b.u64()
|
|
26304
|
+
});
|
|
26305
|
+
// ../shared/src/ws-borsh/agent.ts
|
|
26306
|
+
var AGENT_EVENT_SYNC = 1;
|
|
26307
|
+
var AGENT_EVENT_STATUS = 2;
|
|
26308
|
+
var AGENT_EVENT_TEXT_DELTA = 3;
|
|
26309
|
+
var AGENT_EVENT_REASONING_DELTA = 4;
|
|
26310
|
+
var AGENT_EVENT_TOOL_CALL = 5;
|
|
26311
|
+
var AGENT_EVENT_TOOL_RESULT = 6;
|
|
26312
|
+
var AGENT_EVENT_CONFIRMATION_REQUEST = 7;
|
|
26313
|
+
var AGENT_EVENT_CONFIRMATION_RESOLVED = 8;
|
|
26314
|
+
var AGENT_EVENT_MESSAGE_PERSISTED = 9;
|
|
26315
|
+
var AGENT_EVENT_ERROR = 10;
|
|
26316
|
+
var AGENT_EVENT_TURN_FINISHED = 11;
|
|
26317
|
+
var AGENT_EVENT_CREDENTIAL_WARNING = 12;
|
|
26318
|
+
var AGENT_EVENT_QUEUE_UPDATED = 13;
|
|
26319
|
+
var WATCH_EVENT_TRIGGERED = 1;
|
|
26320
|
+
var WATCH_EVENT_MODEL_UNAVAILABLE = 2;
|
|
26321
|
+
var WATCH_EVENT_RULE_ERROR = 3;
|
|
26322
|
+
// ../shared/src/ws-borsh/errors.ts
|
|
26323
|
+
var ERROR_UNSUPPORTED_PROTOCOL = 1001;
|
|
26324
|
+
var ERROR_INVALID_FRAME = 1002;
|
|
26325
|
+
var ERROR_UNKNOWN_KIND = 1003;
|
|
26326
|
+
var ERROR_PAYLOAD_DECODE_FAILED = 1004;
|
|
26327
|
+
var ERROR_FRAME_TOO_LARGE = 1005;
|
|
26328
|
+
var ERROR_DEVICE_NOT_FOUND = 1101;
|
|
26329
|
+
var ERROR_DEVICE_CONNECT_FAILED = 1102;
|
|
26330
|
+
var ERROR_TMUX_TARGET_NOT_FOUND = 1201;
|
|
26331
|
+
var ERROR_TMUX_NOT_READY = 1202;
|
|
26332
|
+
var ERROR_SELECT_CONFLICT = 1301;
|
|
26333
|
+
var ERROR_SELECT_TOKEN_MISMATCH = 1302;
|
|
26334
|
+
var ERROR_INTERNAL_ERROR = 1401;
|
|
26335
|
+
var ERROR_MESSAGES = {
|
|
26336
|
+
[ERROR_UNSUPPORTED_PROTOCOL]: "Unsupported protocol version",
|
|
26337
|
+
[ERROR_INVALID_FRAME]: "Invalid frame format",
|
|
26338
|
+
[ERROR_UNKNOWN_KIND]: "Unknown message kind",
|
|
26339
|
+
[ERROR_PAYLOAD_DECODE_FAILED]: "Failed to decode payload",
|
|
26340
|
+
[ERROR_FRAME_TOO_LARGE]: "Frame exceeds maximum size",
|
|
26341
|
+
[ERROR_DEVICE_NOT_FOUND]: "Device not found",
|
|
26342
|
+
[ERROR_DEVICE_CONNECT_FAILED]: "Failed to connect device",
|
|
26343
|
+
[ERROR_TMUX_TARGET_NOT_FOUND]: "Tmux target not found",
|
|
26344
|
+
[ERROR_TMUX_NOT_READY]: "Tmux not ready",
|
|
26345
|
+
[ERROR_SELECT_CONFLICT]: "Select conflict",
|
|
26346
|
+
[ERROR_SELECT_TOKEN_MISMATCH]: "Select token mismatch",
|
|
26347
|
+
[ERROR_INTERNAL_ERROR]: "Internal server error"
|
|
26348
|
+
};
|
|
26349
|
+
function getErrorMessage(code) {
|
|
26350
|
+
return ERROR_MESSAGES[code] ?? `Unknown error code: ${code}`;
|
|
26351
|
+
}
|
|
26352
|
+
|
|
26353
|
+
class WsBorshError extends Error {
|
|
26354
|
+
code;
|
|
26355
|
+
retryable;
|
|
26356
|
+
constructor(code, retryable = false, message) {
|
|
26357
|
+
super(message ?? getErrorMessage(code));
|
|
26358
|
+
this.code = code;
|
|
26359
|
+
this.retryable = retryable;
|
|
26360
|
+
this.name = "WsBorshError";
|
|
26361
|
+
}
|
|
26362
|
+
}
|
|
26344
26363
|
// ../shared/src/ws-borsh/codec.ts
|
|
26345
26364
|
var MAGIC = new Uint8Array([84, 88]);
|
|
26346
26365
|
var CURRENT_VERSION = 1;
|
|
@@ -26860,6 +26879,59 @@ function decodePaneWire(wire) {
|
|
|
26860
26879
|
top: wire.top ?? undefined
|
|
26861
26880
|
};
|
|
26862
26881
|
}
|
|
26882
|
+
// ../shared/src/appearance.ts
|
|
26883
|
+
var TERMINAL_THEME_LIGHT = {
|
|
26884
|
+
background: "#e1e1e1",
|
|
26885
|
+
foreground: "#616161",
|
|
26886
|
+
cursor: "#616161",
|
|
26887
|
+
selectionBackground: "rgba(97, 97, 97, 0.25)",
|
|
26888
|
+
black: "#171717",
|
|
26889
|
+
red: "#bf2172",
|
|
26890
|
+
green: "#009799",
|
|
26891
|
+
yellow: "#9a7200",
|
|
26892
|
+
blue: "#007299",
|
|
26893
|
+
magenta: "#9b1d72",
|
|
26894
|
+
cyan: "#007173",
|
|
26895
|
+
white: "#d9d9d9",
|
|
26896
|
+
brightBlack: "#4e4e4e",
|
|
26897
|
+
brightRed: "#e12672",
|
|
26898
|
+
brightGreen: "#00bddf",
|
|
26899
|
+
brightYellow: "#ffdd00",
|
|
26900
|
+
brightBlue: "#7299bc",
|
|
26901
|
+
brightMagenta: "#e17899",
|
|
26902
|
+
brightCyan: "#6fbcbd",
|
|
26903
|
+
brightWhite: "#f1f1f1"
|
|
26904
|
+
};
|
|
26905
|
+
var TERMINAL_THEME_DARK = {
|
|
26906
|
+
background: "#262626",
|
|
26907
|
+
foreground: "#d0d0d0",
|
|
26908
|
+
cursor: "#c5c5c5",
|
|
26909
|
+
selectionBackground: "rgba(197, 197, 197, 0.25)",
|
|
26910
|
+
black: "#000000",
|
|
26911
|
+
red: "#ba3c3c",
|
|
26912
|
+
green: "#5d876d",
|
|
26913
|
+
yellow: "#d5a54e",
|
|
26914
|
+
blue: "#887c8d",
|
|
26915
|
+
magenta: "#cd6d6d",
|
|
26916
|
+
cyan: "#618484",
|
|
26917
|
+
white: "#cfcdc3",
|
|
26918
|
+
brightBlack: "#000000",
|
|
26919
|
+
brightRed: "#ea7171",
|
|
26920
|
+
brightGreen: "#7aab7a",
|
|
26921
|
+
brightYellow: "#d1d194",
|
|
26922
|
+
brightBlue: "#afa3b5",
|
|
26923
|
+
brightMagenta: "#e29f9f",
|
|
26924
|
+
brightCyan: "#a0aea3",
|
|
26925
|
+
brightWhite: "#d0d0d0"
|
|
26926
|
+
};
|
|
26927
|
+
function getTerminalTheme(name) {
|
|
26928
|
+
return name === "light" ? TERMINAL_THEME_LIGHT : TERMINAL_THEME_DARK;
|
|
26929
|
+
}
|
|
26930
|
+
function getTmuxWindowStyle(theme) {
|
|
26931
|
+
const colors = getTerminalTheme(theme);
|
|
26932
|
+
return `fg=${colors.foreground},bg=${colors.background}`;
|
|
26933
|
+
}
|
|
26934
|
+
|
|
26863
26935
|
// ../shared/src/index.ts
|
|
26864
26936
|
var TERMINAL_SHORTCUT_ACTIONS = [
|
|
26865
26937
|
"paste",
|
|
@@ -33329,8 +33401,12 @@ var siteSettings = sqliteTable("site_settings", {
|
|
|
33329
33401
|
sshReconnectMaxRetries: integer("ssh_reconnect_max_retries").notNull(),
|
|
33330
33402
|
sshReconnectDelaySeconds: integer("ssh_reconnect_delay_seconds").notNull(),
|
|
33331
33403
|
language: text("language").notNull().default("en_US"),
|
|
33404
|
+
theme: text("theme").notNull().default("dark"),
|
|
33332
33405
|
updatedAt: text("updated_at").notNull()
|
|
33333
|
-
}, (table) => [
|
|
33406
|
+
}, (table) => [
|
|
33407
|
+
check("site_settings_singleton_check", sql`${table.id} = 1`),
|
|
33408
|
+
check("site_settings_theme_check", sql`${table.theme} in ('dark', 'light')`)
|
|
33409
|
+
]);
|
|
33334
33410
|
var terminalShortcutSettings = sqliteTable("terminal_shortcut_settings", {
|
|
33335
33411
|
id: integer("id").primaryKey(),
|
|
33336
33412
|
items: text("items", { mode: "json" }).$type().notNull().default(DEFAULT_TERMINAL_SHORTCUTS),
|
|
@@ -33624,6 +33700,7 @@ function toSiteSettings(row) {
|
|
|
33624
33700
|
sshReconnectMaxRetries: row.sshReconnectMaxRetries,
|
|
33625
33701
|
sshReconnectDelaySeconds: row.sshReconnectDelaySeconds,
|
|
33626
33702
|
language: normalizeLocale(row.language),
|
|
33703
|
+
theme: row.theme,
|
|
33627
33704
|
updatedAt: row.updatedAt
|
|
33628
33705
|
};
|
|
33629
33706
|
}
|
|
@@ -33917,6 +33994,7 @@ function updateSiteSettings(updates) {
|
|
|
33917
33994
|
sshReconnectMaxRetries: updates.sshReconnectMaxRetries ?? current.sshReconnectMaxRetries,
|
|
33918
33995
|
sshReconnectDelaySeconds: updates.sshReconnectDelaySeconds ?? current.sshReconnectDelaySeconds,
|
|
33919
33996
|
language: updates.language ? normalizeLocale(updates.language) : current.language,
|
|
33997
|
+
theme: updates.theme ?? current.theme,
|
|
33920
33998
|
updatedAt: new Date().toISOString()
|
|
33921
33999
|
};
|
|
33922
34000
|
const orm = getDb();
|
|
@@ -33928,7 +34006,8 @@ function updateSiteSettings(updates) {
|
|
|
33928
34006
|
enableBrowserNotificationToast: next.enableBrowserNotificationToast,
|
|
33929
34007
|
enableNotificationPush: next.enableNotificationPush,
|
|
33930
34008
|
enableBellPush: next.enableBellPush,
|
|
33931
|
-
enableBellSound: next.enableBellSound
|
|
34009
|
+
enableBellSound: next.enableBellSound,
|
|
34010
|
+
theme: next.theme
|
|
33932
34011
|
}).where(eq(siteSettings.id, 1)).run();
|
|
33933
34012
|
siteSettingsCache = { value: next, expiresAt: Date.now() + SITE_SETTINGS_TTL_MS };
|
|
33934
34013
|
if (instance.language !== next.language) {
|
|
@@ -99345,7 +99424,13 @@ class LocalExternalTmuxConnection {
|
|
|
99345
99424
|
if (!this.connected) {
|
|
99346
99425
|
return;
|
|
99347
99426
|
}
|
|
99348
|
-
const argv = [
|
|
99427
|
+
const argv = [
|
|
99428
|
+
"new-window",
|
|
99429
|
+
"-t",
|
|
99430
|
+
this.sessionName,
|
|
99431
|
+
"-c",
|
|
99432
|
+
cwd ?? this.resolveDefaultWorkingDir()
|
|
99433
|
+
];
|
|
99349
99434
|
if (name24) {
|
|
99350
99435
|
argv.push("-n", name24);
|
|
99351
99436
|
}
|
|
@@ -99492,6 +99577,11 @@ class LocalExternalTmuxConnection {
|
|
|
99492
99577
|
this.callbacks.onError(error51);
|
|
99493
99578
|
});
|
|
99494
99579
|
}
|
|
99580
|
+
signalThemeChange(_paneId, _theme) {
|
|
99581
|
+
if (!this.connected) {
|
|
99582
|
+
return;
|
|
99583
|
+
}
|
|
99584
|
+
}
|
|
99495
99585
|
async capturePaneText(paneId, opts) {
|
|
99496
99586
|
if (!this.connected) {
|
|
99497
99587
|
throw new Error(`tmux connection not available: ${this.deviceId}`);
|
|
@@ -99518,7 +99608,14 @@ class LocalExternalTmuxConnection {
|
|
|
99518
99608
|
if (exists3.exitCode === 0) {
|
|
99519
99609
|
return;
|
|
99520
99610
|
}
|
|
99521
|
-
await this.runTmux([
|
|
99611
|
+
await this.runTmux([
|
|
99612
|
+
"new-session",
|
|
99613
|
+
"-d",
|
|
99614
|
+
"-c",
|
|
99615
|
+
this.resolveDefaultWorkingDir(),
|
|
99616
|
+
"-s",
|
|
99617
|
+
this.sessionName
|
|
99618
|
+
]);
|
|
99522
99619
|
}
|
|
99523
99620
|
async configureSessionOptions() {
|
|
99524
99621
|
await this.runTmuxAllowFailure([
|
|
@@ -99529,7 +99626,14 @@ class LocalExternalTmuxConnection {
|
|
|
99529
99626
|
"allow-passthrough",
|
|
99530
99627
|
config.tmuxAllowPassthrough ? "on" : "off"
|
|
99531
99628
|
]);
|
|
99532
|
-
await this.runTmuxAllowFailure([
|
|
99629
|
+
await this.runTmuxAllowFailure([
|
|
99630
|
+
"set-option",
|
|
99631
|
+
"-t",
|
|
99632
|
+
this.sessionName,
|
|
99633
|
+
"-g",
|
|
99634
|
+
"extended-keys",
|
|
99635
|
+
"on"
|
|
99636
|
+
]);
|
|
99533
99637
|
await this.runTmuxAllowFailure([
|
|
99534
99638
|
"set-option",
|
|
99535
99639
|
"-t",
|
|
@@ -99538,7 +99642,14 @@ class LocalExternalTmuxConnection {
|
|
|
99538
99642
|
"extended-keys-format",
|
|
99539
99643
|
"csi-u"
|
|
99540
99644
|
]);
|
|
99541
|
-
await this.runTmuxAllowFailure([
|
|
99645
|
+
await this.runTmuxAllowFailure([
|
|
99646
|
+
"set-option",
|
|
99647
|
+
"-t",
|
|
99648
|
+
this.sessionName,
|
|
99649
|
+
"-g",
|
|
99650
|
+
"focus-events",
|
|
99651
|
+
"off"
|
|
99652
|
+
]);
|
|
99542
99653
|
await this.runTmuxAllowFailure([
|
|
99543
99654
|
"set-option",
|
|
99544
99655
|
"-t",
|
|
@@ -99899,7 +100010,14 @@ class LocalExternalTmuxConnection {
|
|
|
99899
100010
|
async closeWindowInternal(windowId) {
|
|
99900
100011
|
const count2 = Number.parseInt((await this.runTmux(["display-message", "-p", "-t", this.sessionName, "#{session_windows}"])).stdout.trim() || "0", 10);
|
|
99901
100012
|
if (count2 <= 1) {
|
|
99902
|
-
await this.runTmux([
|
|
100013
|
+
await this.runTmux([
|
|
100014
|
+
"new-window",
|
|
100015
|
+
"-d",
|
|
100016
|
+
"-t",
|
|
100017
|
+
this.sessionName,
|
|
100018
|
+
"-c",
|
|
100019
|
+
this.resolveDefaultWorkingDir()
|
|
100020
|
+
]);
|
|
99903
100021
|
}
|
|
99904
100022
|
await this.runAndRefresh(["kill-window", "-t", windowId], true);
|
|
99905
100023
|
}
|
|
@@ -100008,7 +100126,14 @@ class LocalExternalTmuxConnection {
|
|
|
100008
100126
|
"-F",
|
|
100009
100127
|
WINDOW_SNAPSHOT_FORMAT
|
|
100010
100128
|
]),
|
|
100011
|
-
this.runTmuxAllowFailure([
|
|
100129
|
+
this.runTmuxAllowFailure([
|
|
100130
|
+
"list-panes",
|
|
100131
|
+
"-s",
|
|
100132
|
+
"-t",
|
|
100133
|
+
this.sessionName,
|
|
100134
|
+
"-F",
|
|
100135
|
+
PANE_SNAPSHOT_FORMAT
|
|
100136
|
+
])
|
|
100012
100137
|
]);
|
|
100013
100138
|
const transientResult = [sessionRes, windowsRes, panesRes].find((res) => res.exitCode === TMUX_SPAWN_UNAVAILABLE_EXIT);
|
|
100014
100139
|
if (transientResult) {
|
|
@@ -100294,6 +100419,45 @@ function joinShellArgs(argv) {
|
|
|
100294
100419
|
return argv.map((arg) => quoteShellArg(arg)).join(" ");
|
|
100295
100420
|
}
|
|
100296
100421
|
|
|
100422
|
+
// ../../apps/gateway/src/tmux-client/ssh-bootstrap.ts
|
|
100423
|
+
function buildSshBootstrapScript() {
|
|
100424
|
+
return [
|
|
100425
|
+
". /etc/profile 2>/dev/null || true",
|
|
100426
|
+
'[ -f "$HOME/.profile" ] && . "$HOME/.profile" 2>/dev/null || true',
|
|
100427
|
+
'[ -f "$HOME/.bash_profile" ] && . "$HOME/.bash_profile" 2>/dev/null || true',
|
|
100428
|
+
'TMUX_BIN="$(command -v tmux 2>/dev/null || true)"',
|
|
100429
|
+
'if [ -z "$TMUX_BIN" ]; then',
|
|
100430
|
+
" for p in /usr/local/bin/tmux /opt/homebrew/bin/tmux /usr/bin/tmux /bin/tmux; do",
|
|
100431
|
+
' [ -x "$p" ] && TMUX_BIN="$p" && break',
|
|
100432
|
+
" done",
|
|
100433
|
+
"fi",
|
|
100434
|
+
'HOME_DIR="${HOME:-$(pwd)}"',
|
|
100435
|
+
'if [ -z "$TMUX_BIN" ]; then',
|
|
100436
|
+
" printf 'TMEX_BOOT_FAIL\\ttmux_not_found\\n'",
|
|
100437
|
+
"else",
|
|
100438
|
+
` printf 'TMEX_BOOT_OK\\t%s\\t%s\\t%s\\n' "$TMUX_BIN" "$("$TMUX_BIN" -V 2>/dev/null)" "$HOME_DIR"`,
|
|
100439
|
+
"fi"
|
|
100440
|
+
].join(`
|
|
100441
|
+
`);
|
|
100442
|
+
}
|
|
100443
|
+
function parseSshBootstrapOutput(output) {
|
|
100444
|
+
const lines = output.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
100445
|
+
for (const line of lines) {
|
|
100446
|
+
if (line.startsWith("TMEX_BOOT_OK\t")) {
|
|
100447
|
+
const [, tmuxBin = "", tmuxVersion = "", homeDir = ""] = line.split("\t");
|
|
100448
|
+
if (!tmuxBin || !homeDir) {
|
|
100449
|
+
return { ok: false, reason: "invalid_bootstrap_payload" };
|
|
100450
|
+
}
|
|
100451
|
+
return { ok: true, tmuxBin, tmuxVersion, homeDir };
|
|
100452
|
+
}
|
|
100453
|
+
if (line.startsWith("TMEX_BOOT_FAIL\t")) {
|
|
100454
|
+
const [, reason = "tmux_bootstrap_failed"] = line.split("\t");
|
|
100455
|
+
return { ok: false, reason };
|
|
100456
|
+
}
|
|
100457
|
+
}
|
|
100458
|
+
return { ok: false, reason: "missing_bootstrap_marker" };
|
|
100459
|
+
}
|
|
100460
|
+
|
|
100297
100461
|
// ../../apps/gateway/src/tmux-client/ssh-connect-config.ts
|
|
100298
100462
|
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
100299
100463
|
import { join as join3 } from "path";
|
|
@@ -100586,45 +100750,6 @@ async function resolveSshConnectConfig(device, decrypt2, inputDeps = {}) {
|
|
|
100586
100750
|
return authConfig;
|
|
100587
100751
|
}
|
|
100588
100752
|
|
|
100589
|
-
// ../../apps/gateway/src/tmux-client/ssh-bootstrap.ts
|
|
100590
|
-
function buildSshBootstrapScript() {
|
|
100591
|
-
return [
|
|
100592
|
-
". /etc/profile 2>/dev/null || true",
|
|
100593
|
-
'[ -f "$HOME/.profile" ] && . "$HOME/.profile" 2>/dev/null || true',
|
|
100594
|
-
'[ -f "$HOME/.bash_profile" ] && . "$HOME/.bash_profile" 2>/dev/null || true',
|
|
100595
|
-
'TMUX_BIN="$(command -v tmux 2>/dev/null || true)"',
|
|
100596
|
-
'if [ -z "$TMUX_BIN" ]; then',
|
|
100597
|
-
" for p in /usr/local/bin/tmux /opt/homebrew/bin/tmux /usr/bin/tmux /bin/tmux; do",
|
|
100598
|
-
' [ -x "$p" ] && TMUX_BIN="$p" && break',
|
|
100599
|
-
" done",
|
|
100600
|
-
"fi",
|
|
100601
|
-
'HOME_DIR="${HOME:-$(pwd)}"',
|
|
100602
|
-
'if [ -z "$TMUX_BIN" ]; then',
|
|
100603
|
-
" printf 'TMEX_BOOT_FAIL\\ttmux_not_found\\n'",
|
|
100604
|
-
"else",
|
|
100605
|
-
` printf 'TMEX_BOOT_OK\\t%s\\t%s\\t%s\\n' "$TMUX_BIN" "$("$TMUX_BIN" -V 2>/dev/null)" "$HOME_DIR"`,
|
|
100606
|
-
"fi"
|
|
100607
|
-
].join(`
|
|
100608
|
-
`);
|
|
100609
|
-
}
|
|
100610
|
-
function parseSshBootstrapOutput(output) {
|
|
100611
|
-
const lines = output.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
100612
|
-
for (const line of lines) {
|
|
100613
|
-
if (line.startsWith("TMEX_BOOT_OK\t")) {
|
|
100614
|
-
const [, tmuxBin = "", tmuxVersion = "", homeDir = ""] = line.split("\t");
|
|
100615
|
-
if (!tmuxBin || !homeDir) {
|
|
100616
|
-
return { ok: false, reason: "invalid_bootstrap_payload" };
|
|
100617
|
-
}
|
|
100618
|
-
return { ok: true, tmuxBin, tmuxVersion, homeDir };
|
|
100619
|
-
}
|
|
100620
|
-
if (line.startsWith("TMEX_BOOT_FAIL\t")) {
|
|
100621
|
-
const [, reason = "tmux_bootstrap_failed"] = line.split("\t");
|
|
100622
|
-
return { ok: false, reason };
|
|
100623
|
-
}
|
|
100624
|
-
}
|
|
100625
|
-
return { ok: false, reason: "missing_bootstrap_marker" };
|
|
100626
|
-
}
|
|
100627
|
-
|
|
100628
100753
|
// ../../apps/gateway/src/tmux-client/ssh-external-connection.ts
|
|
100629
100754
|
function hasRenderableTerminalContent2(value) {
|
|
100630
100755
|
return value.trim().length > 0;
|
|
@@ -100725,6 +100850,11 @@ class SshExternalTmuxConnection {
|
|
|
100725
100850
|
});
|
|
100726
100851
|
}
|
|
100727
100852
|
}
|
|
100853
|
+
signalThemeChange(_paneId, _theme) {
|
|
100854
|
+
if (!this.connected) {
|
|
100855
|
+
return;
|
|
100856
|
+
}
|
|
100857
|
+
}
|
|
100728
100858
|
resizePane(paneId, cols, rows) {
|
|
100729
100859
|
if (!this.connected) {
|
|
100730
100860
|
return;
|
|
@@ -100761,7 +100891,13 @@ class SshExternalTmuxConnection {
|
|
|
100761
100891
|
if (!this.connected) {
|
|
100762
100892
|
return;
|
|
100763
100893
|
}
|
|
100764
|
-
const argv = [
|
|
100894
|
+
const argv = [
|
|
100895
|
+
"new-window",
|
|
100896
|
+
"-t",
|
|
100897
|
+
this.sessionName,
|
|
100898
|
+
"-c",
|
|
100899
|
+
cwd ?? this.resolveDefaultWorkingDir()
|
|
100900
|
+
];
|
|
100765
100901
|
if (name24) {
|
|
100766
100902
|
argv.push("-n", name24);
|
|
100767
100903
|
}
|
|
@@ -101040,7 +101176,14 @@ class SshExternalTmuxConnection {
|
|
|
101040
101176
|
if (exists3.exitCode === 0) {
|
|
101041
101177
|
return;
|
|
101042
101178
|
}
|
|
101043
|
-
await this.runTmux([
|
|
101179
|
+
await this.runTmux([
|
|
101180
|
+
"new-session",
|
|
101181
|
+
"-d",
|
|
101182
|
+
"-c",
|
|
101183
|
+
this.resolveDefaultWorkingDir(),
|
|
101184
|
+
"-s",
|
|
101185
|
+
this.sessionName
|
|
101186
|
+
]);
|
|
101044
101187
|
}
|
|
101045
101188
|
async configureSessionOptions() {
|
|
101046
101189
|
await this.runTmuxAllowFailure([
|
|
@@ -101051,7 +101194,14 @@ class SshExternalTmuxConnection {
|
|
|
101051
101194
|
"allow-passthrough",
|
|
101052
101195
|
config.tmuxAllowPassthrough ? "on" : "off"
|
|
101053
101196
|
]);
|
|
101054
|
-
await this.runTmuxAllowFailure([
|
|
101197
|
+
await this.runTmuxAllowFailure([
|
|
101198
|
+
"set-option",
|
|
101199
|
+
"-t",
|
|
101200
|
+
this.sessionName,
|
|
101201
|
+
"-g",
|
|
101202
|
+
"extended-keys",
|
|
101203
|
+
"on"
|
|
101204
|
+
]);
|
|
101055
101205
|
await this.runTmuxAllowFailure([
|
|
101056
101206
|
"set-option",
|
|
101057
101207
|
"-t",
|
|
@@ -101060,7 +101210,14 @@ class SshExternalTmuxConnection {
|
|
|
101060
101210
|
"extended-keys-format",
|
|
101061
101211
|
"csi-u"
|
|
101062
101212
|
]);
|
|
101063
|
-
await this.runTmuxAllowFailure([
|
|
101213
|
+
await this.runTmuxAllowFailure([
|
|
101214
|
+
"set-option",
|
|
101215
|
+
"-t",
|
|
101216
|
+
this.sessionName,
|
|
101217
|
+
"-g",
|
|
101218
|
+
"focus-events",
|
|
101219
|
+
"off"
|
|
101220
|
+
]);
|
|
101064
101221
|
await this.runTmuxAllowFailure([
|
|
101065
101222
|
"set-option",
|
|
101066
101223
|
"-t",
|
|
@@ -101108,6 +101265,7 @@ class SshExternalTmuxConnection {
|
|
|
101108
101265
|
if (!windowStyle) {
|
|
101109
101266
|
return;
|
|
101110
101267
|
}
|
|
101268
|
+
const startedAt = config.isDev ? Date.now() : 0;
|
|
101111
101269
|
await this.runTmuxAllowFailure([
|
|
101112
101270
|
"set-hook",
|
|
101113
101271
|
"-t",
|
|
@@ -101123,22 +101281,26 @@ class SshExternalTmuxConnection {
|
|
|
101123
101281
|
"#{window_id}"
|
|
101124
101282
|
]);
|
|
101125
101283
|
if (windows.exitCode !== 0) {
|
|
101284
|
+
if (config.isDev) {
|
|
101285
|
+
console.debug(`[ssh] configureWindowStyle deviceId=${this.deviceId} elapsed=${Date.now() - startedAt}ms (list-windows failed)`);
|
|
101286
|
+
}
|
|
101126
101287
|
return;
|
|
101127
101288
|
}
|
|
101289
|
+
const windowIds = [];
|
|
101128
101290
|
for (const line of windows.stdout.split(`
|
|
101129
101291
|
`)) {
|
|
101130
101292
|
const windowId = line.trim();
|
|
101131
101293
|
if (!windowId) {
|
|
101132
101294
|
continue;
|
|
101133
101295
|
}
|
|
101134
|
-
|
|
101135
|
-
|
|
101136
|
-
|
|
101137
|
-
|
|
101138
|
-
|
|
101139
|
-
|
|
101140
|
-
|
|
101141
|
-
]);
|
|
101296
|
+
windowIds.push(windowId);
|
|
101297
|
+
}
|
|
101298
|
+
if (windowIds.length > 0) {
|
|
101299
|
+
const setOptions = windowIds.map((id) => `${quoteShellArg(this.tmuxBin)} set-option -w -t ${quoteShellArg(id)} window-style ${quoteShellArg(windowStyle)}`).join(" && ");
|
|
101300
|
+
await this.runShellAllowFailure(setOptions);
|
|
101301
|
+
}
|
|
101302
|
+
if (config.isDev) {
|
|
101303
|
+
console.debug(`[ssh] configureWindowStyle deviceId=${this.deviceId} windows=${windowIds.length} elapsed=${Date.now() - startedAt}ms`);
|
|
101142
101304
|
}
|
|
101143
101305
|
}
|
|
101144
101306
|
async ensureGhosttyTerminfo() {
|
|
@@ -101380,7 +101542,14 @@ class SshExternalTmuxConnection {
|
|
|
101380
101542
|
async closeWindowInternal(windowId) {
|
|
101381
101543
|
const count2 = Number.parseInt((await this.runTmux(["display-message", "-p", "-t", this.sessionName, "#{session_windows}"])).stdout.trim() || "0", 10);
|
|
101382
101544
|
if (count2 <= 1) {
|
|
101383
|
-
await this.runTmux([
|
|
101545
|
+
await this.runTmux([
|
|
101546
|
+
"new-window",
|
|
101547
|
+
"-d",
|
|
101548
|
+
"-t",
|
|
101549
|
+
this.sessionName,
|
|
101550
|
+
"-c",
|
|
101551
|
+
this.resolveDefaultWorkingDir()
|
|
101552
|
+
]);
|
|
101384
101553
|
}
|
|
101385
101554
|
await this.runAndRefresh(["kill-window", "-t", windowId], true);
|
|
101386
101555
|
}
|
|
@@ -101489,7 +101658,14 @@ class SshExternalTmuxConnection {
|
|
|
101489
101658
|
"-F",
|
|
101490
101659
|
WINDOW_SNAPSHOT_FORMAT
|
|
101491
101660
|
]),
|
|
101492
|
-
this.runTmuxAllowFailure([
|
|
101661
|
+
this.runTmuxAllowFailure([
|
|
101662
|
+
"list-panes",
|
|
101663
|
+
"-s",
|
|
101664
|
+
"-t",
|
|
101665
|
+
this.sessionName,
|
|
101666
|
+
"-F",
|
|
101667
|
+
PANE_SNAPSHOT_FORMAT
|
|
101668
|
+
])
|
|
101493
101669
|
]);
|
|
101494
101670
|
if (sessionRes.exitCode !== 0 || windowsRes.exitCode !== 0 || panesRes.exitCode !== 0) {
|
|
101495
101671
|
const stderrBlob = `${sessionRes.stderr}
|
|
@@ -102015,6 +102191,9 @@ class DeviceSessionRuntime {
|
|
|
102015
102191
|
setWindowStyle(style) {
|
|
102016
102192
|
this.connection.setWindowStyle(style);
|
|
102017
102193
|
}
|
|
102194
|
+
signalThemeChange(paneId, theme) {
|
|
102195
|
+
this.connection.signalThemeChange(paneId, theme);
|
|
102196
|
+
}
|
|
102018
102197
|
async capturePaneText(paneId, opts) {
|
|
102019
102198
|
return this.connection.capturePaneText(paneId, opts);
|
|
102020
102199
|
}
|
|
@@ -107545,8 +107724,8 @@ function getBaseVersion() {
|
|
|
107545
107724
|
if (cachedBase !== undefined)
|
|
107546
107725
|
return cachedBase;
|
|
107547
107726
|
let base = null;
|
|
107548
|
-
if ("0.16.
|
|
107549
|
-
base = "0.16.
|
|
107727
|
+
if ("0.16.3") {
|
|
107728
|
+
base = "0.16.3";
|
|
107550
107729
|
}
|
|
107551
107730
|
if (!base && config.isProd) {
|
|
107552
107731
|
base = readInstallMeta()?.cliVersion ?? null;
|
|
@@ -107921,6 +108100,62 @@ async function handleDeviceTestConnection(deviceId, inputDeps = {}) {
|
|
|
107921
108100
|
}
|
|
107922
108101
|
}
|
|
107923
108102
|
|
|
108103
|
+
// ../../apps/gateway/src/tmux/theme-broadcaster.ts
|
|
108104
|
+
var tmuxBroadcaster = null;
|
|
108105
|
+
var s2cBroadcaster = null;
|
|
108106
|
+
function registerThemeBroadcaster(tmux, s2c = null) {
|
|
108107
|
+
tmuxBroadcaster = tmux;
|
|
108108
|
+
s2cBroadcaster = s2c;
|
|
108109
|
+
}
|
|
108110
|
+
function broadcastThemeChange(theme) {
|
|
108111
|
+
tmuxBroadcaster?.(theme);
|
|
108112
|
+
}
|
|
108113
|
+
function broadcastSiteThemeUpdateS2C(theme) {
|
|
108114
|
+
s2cBroadcaster?.(theme);
|
|
108115
|
+
}
|
|
108116
|
+
|
|
108117
|
+
// ../../apps/gateway/src/api/theme.ts
|
|
108118
|
+
var VALID_THEMES = ["dark", "light"];
|
|
108119
|
+
function handleThemeApiRequest(req, path) {
|
|
108120
|
+
if (path === "/api/settings/theme" && req.method === "GET") {
|
|
108121
|
+
return handleGetTheme();
|
|
108122
|
+
}
|
|
108123
|
+
if (path === "/api/settings/theme" && req.method === "POST") {
|
|
108124
|
+
return handleUpdateTheme(req);
|
|
108125
|
+
}
|
|
108126
|
+
return null;
|
|
108127
|
+
}
|
|
108128
|
+
function handleGetTheme() {
|
|
108129
|
+
const settings = getSiteSettings();
|
|
108130
|
+
return json8({ theme: settings.theme, serverTimestamp: Date.now() });
|
|
108131
|
+
}
|
|
108132
|
+
async function handleUpdateTheme(req) {
|
|
108133
|
+
let body;
|
|
108134
|
+
try {
|
|
108135
|
+
body = await req.json();
|
|
108136
|
+
} catch {
|
|
108137
|
+
return json8({ error: "invalid request body" }, 400);
|
|
108138
|
+
}
|
|
108139
|
+
if (typeof body !== "object" || body === null || Array.isArray(body)) {
|
|
108140
|
+
return json8({ error: "invalid request body" }, 400);
|
|
108141
|
+
}
|
|
108142
|
+
const { theme } = body;
|
|
108143
|
+
if (typeof theme !== "string" || !VALID_THEMES.includes(theme)) {
|
|
108144
|
+
return json8({ error: "theme must be one of: dark, light" }, 400);
|
|
108145
|
+
}
|
|
108146
|
+
const serverTimestamp = Date.now();
|
|
108147
|
+
updateSiteSettings({ theme });
|
|
108148
|
+
broadcastThemeChange(theme);
|
|
108149
|
+
broadcastSiteThemeUpdateS2C(theme);
|
|
108150
|
+
return json8({ theme, serverTimestamp });
|
|
108151
|
+
}
|
|
108152
|
+
function json8(data, status = 200) {
|
|
108153
|
+
return new Response(JSON.stringify(data), {
|
|
108154
|
+
status,
|
|
108155
|
+
headers: { "Content-Type": "application/json" }
|
|
108156
|
+
});
|
|
108157
|
+
}
|
|
108158
|
+
|
|
107924
108159
|
// ../../apps/gateway/src/db/watch.ts
|
|
107925
108160
|
function createWatchRule(input) {
|
|
107926
108161
|
const orm = getDb();
|
|
@@ -109019,35 +109254,35 @@ async function handleListRules(req) {
|
|
|
109019
109254
|
if (paneId) {
|
|
109020
109255
|
rules = rules.filter((rule) => rule.paneId === paneId);
|
|
109021
109256
|
}
|
|
109022
|
-
return
|
|
109257
|
+
return json9({ rules: rules.map(toRuleDto) });
|
|
109023
109258
|
}
|
|
109024
109259
|
async function handleCreateRule(req, deps) {
|
|
109025
109260
|
const raw = await readJsonObjectBody3(req);
|
|
109026
109261
|
if (!raw) {
|
|
109027
|
-
return
|
|
109262
|
+
return json9({ error: t2("apiError.invalidRequest") }, 400);
|
|
109028
109263
|
}
|
|
109029
109264
|
const body = raw;
|
|
109030
109265
|
const name24 = typeof body.name === "string" ? body.name.trim() : "";
|
|
109031
109266
|
if (!name24) {
|
|
109032
|
-
return
|
|
109267
|
+
return json9({ error: t2("apiError.watchNameRequired") }, 400);
|
|
109033
109268
|
}
|
|
109034
109269
|
const deviceId = typeof body.deviceId === "string" ? body.deviceId.trim() : "";
|
|
109035
109270
|
if (!deviceId) {
|
|
109036
|
-
return
|
|
109271
|
+
return json9({ error: t2("apiError.agentDeviceRequired") }, 400);
|
|
109037
109272
|
}
|
|
109038
109273
|
if (!getDeviceById(deviceId)) {
|
|
109039
|
-
return
|
|
109274
|
+
return json9({ error: t2("apiError.deviceNotFound") }, 404);
|
|
109040
109275
|
}
|
|
109041
109276
|
const paneId = typeof body.paneId === "string" ? body.paneId.trim() : "";
|
|
109042
109277
|
if (!paneId) {
|
|
109043
|
-
return
|
|
109278
|
+
return json9({ error: t2("apiError.agentPaneRequired") }, 400);
|
|
109044
109279
|
}
|
|
109045
109280
|
if (!TRIGGER_TYPES.includes(body.triggerType)) {
|
|
109046
|
-
return
|
|
109281
|
+
return json9({ error: t2("apiError.watchTriggerTypeInvalid") }, 400);
|
|
109047
109282
|
}
|
|
109048
109283
|
const parsed = parseRuleFields(raw);
|
|
109049
109284
|
if (!parsed.ok) {
|
|
109050
|
-
return
|
|
109285
|
+
return json9({ error: parsed.error }, 400);
|
|
109051
109286
|
}
|
|
109052
109287
|
const fields = parsed.fields;
|
|
109053
109288
|
const effective = {
|
|
@@ -109060,7 +109295,7 @@ async function handleCreateRule(req, deps) {
|
|
|
109060
109295
|
};
|
|
109061
109296
|
const semanticError = validateRuleSemantics(effective);
|
|
109062
109297
|
if (semanticError) {
|
|
109063
|
-
return
|
|
109298
|
+
return json9({ error: semanticError }, 400);
|
|
109064
109299
|
}
|
|
109065
109300
|
const rule = createWatchRule({
|
|
109066
109301
|
name: name24,
|
|
@@ -109083,50 +109318,50 @@ async function handleCreateRule(req, deps) {
|
|
|
109083
109318
|
cooldownSeconds: fields.cooldownSeconds
|
|
109084
109319
|
});
|
|
109085
109320
|
await deps.service.refreshRule(rule.id);
|
|
109086
|
-
return
|
|
109321
|
+
return json9({ rule: toRuleDto(rule), state: null }, 201);
|
|
109087
109322
|
}
|
|
109088
109323
|
async function handleGetRule(id) {
|
|
109089
109324
|
const rule = getWatchRuleById(id);
|
|
109090
109325
|
if (!rule) {
|
|
109091
|
-
return
|
|
109326
|
+
return json9({ error: t2("apiError.watchRuleNotFound") }, 404);
|
|
109092
109327
|
}
|
|
109093
109328
|
const state = getWatchRuleState(id);
|
|
109094
|
-
return
|
|
109329
|
+
return json9({ rule: toRuleDto(rule), state: state ? toStateDto(state) : null });
|
|
109095
109330
|
}
|
|
109096
109331
|
async function handleUpdateRule(req, id, deps) {
|
|
109097
109332
|
const existing = getWatchRuleById(id);
|
|
109098
109333
|
if (!existing) {
|
|
109099
|
-
return
|
|
109334
|
+
return json9({ error: t2("apiError.watchRuleNotFound") }, 404);
|
|
109100
109335
|
}
|
|
109101
109336
|
const raw = await readJsonObjectBody3(req);
|
|
109102
109337
|
if (!raw) {
|
|
109103
|
-
return
|
|
109338
|
+
return json9({ error: t2("apiError.invalidRequest") }, 400);
|
|
109104
109339
|
}
|
|
109105
109340
|
const body = raw;
|
|
109106
109341
|
const updates = {};
|
|
109107
109342
|
if (body.name !== undefined) {
|
|
109108
109343
|
const name24 = typeof body.name === "string" ? body.name.trim() : "";
|
|
109109
109344
|
if (!name24) {
|
|
109110
|
-
return
|
|
109345
|
+
return json9({ error: t2("apiError.watchNameRequired") }, 400);
|
|
109111
109346
|
}
|
|
109112
109347
|
updates.name = name24;
|
|
109113
109348
|
}
|
|
109114
109349
|
if (body.paneId !== undefined) {
|
|
109115
109350
|
const paneId = typeof body.paneId === "string" ? body.paneId.trim() : "";
|
|
109116
109351
|
if (!paneId) {
|
|
109117
|
-
return
|
|
109352
|
+
return json9({ error: t2("apiError.agentPaneRequired") }, 400);
|
|
109118
109353
|
}
|
|
109119
109354
|
updates.paneId = paneId;
|
|
109120
109355
|
}
|
|
109121
109356
|
if (body.triggerType !== undefined) {
|
|
109122
109357
|
if (!TRIGGER_TYPES.includes(body.triggerType)) {
|
|
109123
|
-
return
|
|
109358
|
+
return json9({ error: t2("apiError.watchTriggerTypeInvalid") }, 400);
|
|
109124
109359
|
}
|
|
109125
109360
|
updates.triggerType = body.triggerType;
|
|
109126
109361
|
}
|
|
109127
109362
|
const parsed = parseRuleFields(raw);
|
|
109128
109363
|
if (!parsed.ok) {
|
|
109129
|
-
return
|
|
109364
|
+
return json9({ error: parsed.error }, 400);
|
|
109130
109365
|
}
|
|
109131
109366
|
const fields = parsed.fields;
|
|
109132
109367
|
Object.assign(updates, fields);
|
|
@@ -109140,32 +109375,32 @@ async function handleUpdateRule(req, id, deps) {
|
|
|
109140
109375
|
};
|
|
109141
109376
|
const semanticError = validateRuleSemantics(effective);
|
|
109142
109377
|
if (semanticError) {
|
|
109143
|
-
return
|
|
109378
|
+
return json9({ error: semanticError }, 400);
|
|
109144
109379
|
}
|
|
109145
109380
|
const rule = updateWatchRule(id, updates);
|
|
109146
109381
|
if (!rule) {
|
|
109147
|
-
return
|
|
109382
|
+
return json9({ error: t2("apiError.watchRuleNotFound") }, 404);
|
|
109148
109383
|
}
|
|
109149
109384
|
await deps.service.refreshRule(id);
|
|
109150
109385
|
const state = getWatchRuleState(id);
|
|
109151
|
-
return
|
|
109386
|
+
return json9({ rule: toRuleDto(rule), state: state ? toStateDto(state) : null });
|
|
109152
109387
|
}
|
|
109153
109388
|
async function handleDeleteRule(id, deps) {
|
|
109154
109389
|
const existing = getWatchRuleById(id);
|
|
109155
109390
|
if (!existing) {
|
|
109156
|
-
return
|
|
109391
|
+
return json9({ error: t2("apiError.watchRuleNotFound") }, 404);
|
|
109157
109392
|
}
|
|
109158
109393
|
deleteWatchRule(id);
|
|
109159
109394
|
await deps.service.removeRule(id);
|
|
109160
|
-
return
|
|
109395
|
+
return json9({ success: true });
|
|
109161
109396
|
}
|
|
109162
109397
|
async function handleGetRuleState(id, deps) {
|
|
109163
109398
|
const rule = getWatchRuleById(id);
|
|
109164
109399
|
if (!rule) {
|
|
109165
|
-
return
|
|
109400
|
+
return json9({ error: t2("apiError.watchRuleNotFound") }, 404);
|
|
109166
109401
|
}
|
|
109167
109402
|
const state = getWatchRuleState(id);
|
|
109168
|
-
return
|
|
109403
|
+
return json9({
|
|
109169
109404
|
state: state ? toStateDto(state) : null,
|
|
109170
109405
|
samples: deps.service.getSamples(id)
|
|
109171
109406
|
});
|
|
@@ -109189,17 +109424,17 @@ function buildAssistPrompt(description, screen) {
|
|
|
109189
109424
|
async function handleAssistRegex(req, deps) {
|
|
109190
109425
|
const raw = await readJsonObjectBody3(req);
|
|
109191
109426
|
if (!raw) {
|
|
109192
|
-
return
|
|
109427
|
+
return json9({ error: t2("apiError.invalidRequest") }, 400);
|
|
109193
109428
|
}
|
|
109194
109429
|
const body = raw;
|
|
109195
109430
|
const description = typeof body.description === "string" ? body.description.trim() : "";
|
|
109196
109431
|
if (!description) {
|
|
109197
|
-
return
|
|
109432
|
+
return json9({ error: t2("apiError.watchAssistDescriptionRequired") }, 400);
|
|
109198
109433
|
}
|
|
109199
109434
|
let providerId = null;
|
|
109200
109435
|
if (body.providerId !== undefined && body.providerId !== null) {
|
|
109201
109436
|
if (typeof body.providerId !== "string" || !getLlmProviderById(body.providerId)) {
|
|
109202
|
-
return
|
|
109437
|
+
return json9({ error: t2("apiError.llmProviderNotFound") }, 400);
|
|
109203
109438
|
}
|
|
109204
109439
|
providerId = body.providerId;
|
|
109205
109440
|
}
|
|
@@ -109209,7 +109444,7 @@ async function handleAssistRegex(req, deps) {
|
|
|
109209
109444
|
const paneId = typeof body.paneId === "string" ? body.paneId.trim() : "";
|
|
109210
109445
|
if (deviceId && paneId) {
|
|
109211
109446
|
if (!getDeviceById(deviceId)) {
|
|
109212
|
-
return
|
|
109447
|
+
return json9({ error: t2("apiError.deviceNotFound") }, 404);
|
|
109213
109448
|
}
|
|
109214
109449
|
try {
|
|
109215
109450
|
screen = await deps.captureScreen(deviceId, paneId);
|
|
@@ -109230,14 +109465,14 @@ async function handleAssistRegex(req, deps) {
|
|
|
109230
109465
|
object3 = result.object;
|
|
109231
109466
|
} catch (error51) {
|
|
109232
109467
|
const detail = error51 instanceof Error ? error51.message : String(error51);
|
|
109233
|
-
return
|
|
109468
|
+
return json9({ error: t2("apiError.watchAssistModelUnavailable", { detail }) }, 502);
|
|
109234
109469
|
}
|
|
109235
109470
|
let regex;
|
|
109236
109471
|
try {
|
|
109237
109472
|
regex = compileWatchPattern(object3.pattern, object3.flags);
|
|
109238
109473
|
} catch (error51) {
|
|
109239
109474
|
const detail = error51 instanceof Error ? error51.message : String(error51);
|
|
109240
|
-
return
|
|
109475
|
+
return json9({ error: t2("apiError.watchPatternInvalid", { detail }) }, 502);
|
|
109241
109476
|
}
|
|
109242
109477
|
const preview = [];
|
|
109243
109478
|
if (screen) {
|
|
@@ -109251,7 +109486,7 @@ async function handleAssistRegex(req, deps) {
|
|
|
109251
109486
|
match = regex.exec(screen);
|
|
109252
109487
|
}
|
|
109253
109488
|
}
|
|
109254
|
-
return
|
|
109489
|
+
return json9({
|
|
109255
109490
|
pattern: object3.pattern,
|
|
109256
109491
|
flags: object3.flags,
|
|
109257
109492
|
extractGroup: object3.extractGroup >= 0 ? object3.extractGroup : 0,
|
|
@@ -109259,7 +109494,7 @@ async function handleAssistRegex(req, deps) {
|
|
|
109259
109494
|
preview
|
|
109260
109495
|
});
|
|
109261
109496
|
}
|
|
109262
|
-
function
|
|
109497
|
+
function json9(data, status = 200) {
|
|
109263
109498
|
return new Response(JSON.stringify(data), {
|
|
109264
109499
|
status,
|
|
109265
109500
|
headers: {
|
|
@@ -109404,6 +109639,12 @@ function handleApiRequest(req, _server) {
|
|
|
109404
109639
|
if (path === "/api/settings/terminal-shortcuts" && req.method === "PATCH") {
|
|
109405
109640
|
return handleUpdateTerminalShortcuts(req);
|
|
109406
109641
|
}
|
|
109642
|
+
if (path === "/api/settings/theme" && (req.method === "GET" || req.method === "POST")) {
|
|
109643
|
+
const themeResponse = handleThemeApiRequest(req, path);
|
|
109644
|
+
if (themeResponse) {
|
|
109645
|
+
return themeResponse;
|
|
109646
|
+
}
|
|
109647
|
+
}
|
|
109407
109648
|
if (path === "/api/settings/restart" && req.method === "POST") {
|
|
109408
109649
|
return handleRestartGateway();
|
|
109409
109650
|
}
|
|
@@ -109507,13 +109748,13 @@ function handleApiRequest(req, _server) {
|
|
|
109507
109748
|
return handleGetManifest(req.method);
|
|
109508
109749
|
}
|
|
109509
109750
|
if (path === "/healthz" && req.method === "GET") {
|
|
109510
|
-
return
|
|
109751
|
+
return json10({
|
|
109511
109752
|
status: "ok",
|
|
109512
109753
|
restarting: runtimeController.isRestarting(),
|
|
109513
109754
|
env: "development"
|
|
109514
109755
|
});
|
|
109515
109756
|
}
|
|
109516
|
-
return
|
|
109757
|
+
return json10({ error: t2("apiError.notFound") }, 404);
|
|
109517
109758
|
}
|
|
109518
109759
|
function enrichDeviceWithRuntime(device) {
|
|
109519
109760
|
const status = getDeviceRuntimeStatus(device.id);
|
|
@@ -109527,22 +109768,22 @@ function enrichDeviceWithRuntime(device) {
|
|
|
109527
109768
|
}
|
|
109528
109769
|
async function handleGetDevices() {
|
|
109529
109770
|
const devices2 = getAllDevices().map(enrichDeviceWithRuntime);
|
|
109530
|
-
return
|
|
109771
|
+
return json10({ devices: devices2 });
|
|
109531
109772
|
}
|
|
109532
109773
|
async function handleGetDevice(id) {
|
|
109533
109774
|
const device = getDeviceById(id);
|
|
109534
109775
|
if (!device) {
|
|
109535
|
-
return
|
|
109776
|
+
return json10({ error: t2("apiError.deviceNotFound") }, 404);
|
|
109536
109777
|
}
|
|
109537
|
-
return
|
|
109778
|
+
return json10({ device: enrichDeviceWithRuntime(device) });
|
|
109538
109779
|
}
|
|
109539
109780
|
async function handleCreateDevice(req) {
|
|
109540
109781
|
const body = await req.json();
|
|
109541
109782
|
if (!body.name || !body.type || !body.authMode) {
|
|
109542
|
-
return
|
|
109783
|
+
return json10({ error: t2("apiError.missingFields") }, 400);
|
|
109543
109784
|
}
|
|
109544
109785
|
if (body.type === "ssh" && !body.host && !body.sshConfigRef) {
|
|
109545
|
-
return
|
|
109786
|
+
return json10({ error: t2("apiError.sshRequiresHost") }, 400);
|
|
109546
109787
|
}
|
|
109547
109788
|
const now2 = new Date().toISOString();
|
|
109548
109789
|
const device = {
|
|
@@ -109565,12 +109806,12 @@ async function handleCreateDevice(req) {
|
|
|
109565
109806
|
};
|
|
109566
109807
|
createDevice(device);
|
|
109567
109808
|
await pushSupervisor.upsert(device.id);
|
|
109568
|
-
return
|
|
109809
|
+
return json10({ device: getDeviceById(device.id) ?? device }, 201);
|
|
109569
109810
|
}
|
|
109570
109811
|
async function handleUpdateDevice(req, id) {
|
|
109571
109812
|
const existing = getDeviceById(id);
|
|
109572
109813
|
if (!existing) {
|
|
109573
|
-
return
|
|
109814
|
+
return json10({ error: t2("apiError.deviceNotFound") }, 404);
|
|
109574
109815
|
}
|
|
109575
109816
|
const body = await req.json();
|
|
109576
109817
|
const updates = {};
|
|
@@ -109604,74 +109845,74 @@ async function handleUpdateDevice(req, id) {
|
|
|
109604
109845
|
pushSupervisor.updateDefaultWorkingDir(id, updates.defaultWorkingDir);
|
|
109605
109846
|
}
|
|
109606
109847
|
const device = getDeviceById(id);
|
|
109607
|
-
return
|
|
109848
|
+
return json10({ device });
|
|
109608
109849
|
}
|
|
109609
109850
|
async function handleReorderDevices(req) {
|
|
109610
109851
|
const body = await req.json();
|
|
109611
109852
|
if (!Array.isArray(body.deviceIds) || body.deviceIds.some((id) => typeof id !== "string")) {
|
|
109612
|
-
return
|
|
109853
|
+
return json10({ error: t2("apiError.invalidRequest") }, 400);
|
|
109613
109854
|
}
|
|
109614
109855
|
reorderDevices(body.deviceIds);
|
|
109615
|
-
return
|
|
109856
|
+
return json10({ devices: getAllDevices().map(enrichDeviceWithRuntime) });
|
|
109616
109857
|
}
|
|
109617
109858
|
async function handleDeleteDevice(id) {
|
|
109618
109859
|
const existing = getDeviceById(id);
|
|
109619
109860
|
if (!existing) {
|
|
109620
|
-
return
|
|
109861
|
+
return json10({ error: t2("apiError.deviceNotFound") }, 404);
|
|
109621
109862
|
}
|
|
109622
109863
|
deleteDevice(id);
|
|
109623
109864
|
pushSupervisor.remove(id);
|
|
109624
|
-
return
|
|
109865
|
+
return json10({ success: true });
|
|
109625
109866
|
}
|
|
109626
109867
|
async function handleTestConnection(id) {
|
|
109627
109868
|
return handleDeviceTestConnection(id);
|
|
109628
109869
|
}
|
|
109629
109870
|
async function handleGetSiteSettings() {
|
|
109630
|
-
return
|
|
109871
|
+
return json10({ settings: getSiteSettings() });
|
|
109631
109872
|
}
|
|
109632
109873
|
async function handleUpdateSiteSettings(req) {
|
|
109633
109874
|
try {
|
|
109634
109875
|
const body = await req.json();
|
|
109635
109876
|
const updates = normalizeSiteSettingsInput(body);
|
|
109636
109877
|
const settings = updateSiteSettings(updates);
|
|
109637
|
-
return
|
|
109878
|
+
return json10({ settings });
|
|
109638
109879
|
} catch (err) {
|
|
109639
|
-
return
|
|
109880
|
+
return json10({ error: err instanceof Error ? err.message : t2("apiError.invalidRequest") }, 400);
|
|
109640
109881
|
}
|
|
109641
109882
|
}
|
|
109642
109883
|
async function handleGetTerminalShortcuts() {
|
|
109643
|
-
return
|
|
109884
|
+
return json10({ settings: getTerminalShortcutSettings() });
|
|
109644
109885
|
}
|
|
109645
109886
|
async function handleUpdateTerminalShortcuts(req) {
|
|
109646
109887
|
try {
|
|
109647
109888
|
const body = await req.json();
|
|
109648
109889
|
const updates = normalizeTerminalShortcutsInput(body);
|
|
109649
109890
|
const settings = updateTerminalShortcutSettings(updates);
|
|
109650
|
-
return
|
|
109891
|
+
return json10({ settings });
|
|
109651
109892
|
} catch (err) {
|
|
109652
|
-
return
|
|
109893
|
+
return json10({ error: err instanceof Error ? err.message : t2("apiError.invalidRequest") }, 400);
|
|
109653
109894
|
}
|
|
109654
109895
|
}
|
|
109655
109896
|
async function handleRestartGateway() {
|
|
109656
109897
|
setTimeout(() => {
|
|
109657
109898
|
runtimeController.requestRestart();
|
|
109658
109899
|
}, 50);
|
|
109659
|
-
return
|
|
109900
|
+
return json10({
|
|
109660
109901
|
success: true,
|
|
109661
109902
|
message: t2("settings.restartScheduled")
|
|
109662
109903
|
});
|
|
109663
109904
|
}
|
|
109664
109905
|
async function handleGetTelegramBots() {
|
|
109665
109906
|
const bots = getTelegramBotsWithStats();
|
|
109666
|
-
return
|
|
109907
|
+
return json10({ bots });
|
|
109667
109908
|
}
|
|
109668
109909
|
async function handleCreateTelegramBot(req) {
|
|
109669
109910
|
const body = await req.json();
|
|
109670
109911
|
if (!body.name?.trim()) {
|
|
109671
|
-
return
|
|
109912
|
+
return json10({ error: t2("apiError.botNameRequired") }, 400);
|
|
109672
109913
|
}
|
|
109673
109914
|
if (!body.token?.trim()) {
|
|
109674
|
-
return
|
|
109915
|
+
return json10({ error: t2("apiError.botTokenRequired") }, 400);
|
|
109675
109916
|
}
|
|
109676
109917
|
const now2 = new Date().toISOString();
|
|
109677
109918
|
createTelegramBot({
|
|
@@ -109685,26 +109926,26 @@ async function handleCreateTelegramBot(req) {
|
|
|
109685
109926
|
updatedAt: now2
|
|
109686
109927
|
});
|
|
109687
109928
|
await telegramService.refresh();
|
|
109688
|
-
return
|
|
109929
|
+
return json10({ success: true }, 201);
|
|
109689
109930
|
}
|
|
109690
109931
|
async function handleUpdateTelegramBot(req, botId) {
|
|
109691
109932
|
const existing = getTelegramBotById(botId);
|
|
109692
109933
|
if (!existing) {
|
|
109693
|
-
return
|
|
109934
|
+
return json10({ error: t2("apiError.botNotFound") }, 404);
|
|
109694
109935
|
}
|
|
109695
109936
|
const body = await req.json();
|
|
109696
109937
|
const updates = {};
|
|
109697
109938
|
if (body.name !== undefined) {
|
|
109698
109939
|
const value = body.name.trim();
|
|
109699
109940
|
if (!value) {
|
|
109700
|
-
return
|
|
109941
|
+
return json10({ error: t2("apiError.botNameRequired") }, 400);
|
|
109701
109942
|
}
|
|
109702
109943
|
updates.name = value;
|
|
109703
109944
|
}
|
|
109704
109945
|
if (body.token !== undefined) {
|
|
109705
109946
|
const token = body.token.trim();
|
|
109706
109947
|
if (!token) {
|
|
109707
|
-
return
|
|
109948
|
+
return json10({ error: t2("apiError.botTokenRequired") }, 400);
|
|
109708
109949
|
}
|
|
109709
109950
|
updates.tokenEnc = await encrypt(token);
|
|
109710
109951
|
}
|
|
@@ -109716,69 +109957,69 @@ async function handleUpdateTelegramBot(req, botId) {
|
|
|
109716
109957
|
}
|
|
109717
109958
|
updateTelegramBot(botId, updates);
|
|
109718
109959
|
await telegramService.refresh();
|
|
109719
|
-
return
|
|
109960
|
+
return json10({ success: true });
|
|
109720
109961
|
}
|
|
109721
109962
|
async function handleDeleteTelegramBot(botId) {
|
|
109722
109963
|
const existing = getTelegramBotById(botId);
|
|
109723
109964
|
if (!existing) {
|
|
109724
|
-
return
|
|
109965
|
+
return json10({ error: t2("apiError.botNotFound") }, 404);
|
|
109725
109966
|
}
|
|
109726
109967
|
deleteTelegramBot(botId);
|
|
109727
109968
|
await telegramService.refresh();
|
|
109728
|
-
return
|
|
109969
|
+
return json10({ success: true });
|
|
109729
109970
|
}
|
|
109730
109971
|
async function handleListTelegramChats(botId) {
|
|
109731
109972
|
const existing = getTelegramBotById(botId);
|
|
109732
109973
|
if (!existing) {
|
|
109733
|
-
return
|
|
109974
|
+
return json10({ error: t2("apiError.botNotFound") }, 404);
|
|
109734
109975
|
}
|
|
109735
109976
|
const chats = listTelegramChatsByBot(botId);
|
|
109736
|
-
return
|
|
109977
|
+
return json10({ chats });
|
|
109737
109978
|
}
|
|
109738
109979
|
async function handleApproveTelegramChat(botId, chatId) {
|
|
109739
109980
|
const existing = getTelegramBotById(botId);
|
|
109740
109981
|
if (!existing) {
|
|
109741
|
-
return
|
|
109982
|
+
return json10({ error: t2("apiError.botNotFound") }, 404);
|
|
109742
109983
|
}
|
|
109743
109984
|
const chat = approveTelegramChat(botId, chatId);
|
|
109744
109985
|
if (!chat) {
|
|
109745
|
-
return
|
|
109986
|
+
return json10({ error: t2("apiError.chatNotFound") }, 404);
|
|
109746
109987
|
}
|
|
109747
109988
|
const settings = getSiteSettings();
|
|
109748
109989
|
await telegramService.sendTestMessage(botId, chatId, t2("telegram.approveMessageTemplate", {
|
|
109749
109990
|
botName: existing.name,
|
|
109750
109991
|
time: new Date().toLocaleString(toBCP47(settings.language))
|
|
109751
109992
|
}));
|
|
109752
|
-
return
|
|
109993
|
+
return json10({ chat });
|
|
109753
109994
|
}
|
|
109754
109995
|
async function handleDeleteTelegramChat(botId, chatId) {
|
|
109755
109996
|
const existing = getTelegramBotById(botId);
|
|
109756
109997
|
if (!existing) {
|
|
109757
|
-
return
|
|
109998
|
+
return json10({ error: t2("apiError.botNotFound") }, 404);
|
|
109758
109999
|
}
|
|
109759
110000
|
deleteTelegramChat(botId, chatId);
|
|
109760
|
-
return
|
|
110001
|
+
return json10({ success: true });
|
|
109761
110002
|
}
|
|
109762
110003
|
async function handleTestTelegramChat(botId, chatId) {
|
|
109763
110004
|
const bot = getTelegramBotById(botId);
|
|
109764
110005
|
if (!bot) {
|
|
109765
|
-
return
|
|
110006
|
+
return json10({ error: t2("apiError.botNotFound") }, 404);
|
|
109766
110007
|
}
|
|
109767
110008
|
const settings = getSiteSettings();
|
|
109768
110009
|
await telegramService.sendTestMessage(botId, chatId, t2("telegram.testMessageTemplate", {
|
|
109769
110010
|
siteName: settings.siteName,
|
|
109770
110011
|
time: new Date().toLocaleString(toBCP47(settings.language))
|
|
109771
110012
|
}));
|
|
109772
|
-
return
|
|
110013
|
+
return json10({ success: true });
|
|
109773
110014
|
}
|
|
109774
110015
|
async function handleGetWeixinAccounts() {
|
|
109775
110016
|
const accounts = getWeixinAccountsWithStats();
|
|
109776
|
-
return
|
|
110017
|
+
return json10({ accounts });
|
|
109777
110018
|
}
|
|
109778
110019
|
async function handleCreateWeixinAccount(req) {
|
|
109779
110020
|
const body = await req.json();
|
|
109780
110021
|
if (!body.name?.trim()) {
|
|
109781
|
-
return
|
|
110022
|
+
return json10({ error: t2("weixin.accountNameRequired") }, 400);
|
|
109782
110023
|
}
|
|
109783
110024
|
const now2 = new Date().toISOString();
|
|
109784
110025
|
const id = v4_default();
|
|
@@ -109795,19 +110036,19 @@ async function handleCreateWeixinAccount(req) {
|
|
|
109795
110036
|
createdAt: now2,
|
|
109796
110037
|
updatedAt: now2
|
|
109797
110038
|
});
|
|
109798
|
-
return
|
|
110039
|
+
return json10({ success: true, accountId: id }, 201);
|
|
109799
110040
|
}
|
|
109800
110041
|
async function handleUpdateWeixinAccount(req, accountId) {
|
|
109801
110042
|
const existing = getWeixinAccountById(accountId);
|
|
109802
110043
|
if (!existing) {
|
|
109803
|
-
return
|
|
110044
|
+
return json10({ error: t2("weixin.accountNotFound") }, 404);
|
|
109804
110045
|
}
|
|
109805
110046
|
const body = await req.json();
|
|
109806
110047
|
const updates = {};
|
|
109807
110048
|
if (body.name !== undefined) {
|
|
109808
110049
|
const value = body.name.trim();
|
|
109809
110050
|
if (!value) {
|
|
109810
|
-
return
|
|
110051
|
+
return json10({ error: t2("weixin.accountNameRequired") }, 400);
|
|
109811
110052
|
}
|
|
109812
110053
|
updates.name = value;
|
|
109813
110054
|
}
|
|
@@ -109819,52 +110060,52 @@ async function handleUpdateWeixinAccount(req, accountId) {
|
|
|
109819
110060
|
}
|
|
109820
110061
|
updateWeixinAccount(accountId, updates);
|
|
109821
110062
|
await weixinService.refresh();
|
|
109822
|
-
return
|
|
110063
|
+
return json10({ success: true });
|
|
109823
110064
|
}
|
|
109824
110065
|
async function handleDeleteWeixinAccount(accountId) {
|
|
109825
110066
|
const existing = getWeixinAccountById(accountId);
|
|
109826
110067
|
if (!existing) {
|
|
109827
|
-
return
|
|
110068
|
+
return json10({ error: t2("weixin.accountNotFound") }, 404);
|
|
109828
110069
|
}
|
|
109829
110070
|
deleteWeixinAccount(accountId);
|
|
109830
110071
|
await weixinService.refresh();
|
|
109831
|
-
return
|
|
110072
|
+
return json10({ success: true });
|
|
109832
110073
|
}
|
|
109833
110074
|
async function handleStartWeixinLogin(accountId) {
|
|
109834
110075
|
const existing = getWeixinAccountById(accountId);
|
|
109835
110076
|
if (!existing) {
|
|
109836
|
-
return
|
|
110077
|
+
return json10({ error: t2("weixin.accountNotFound") }, 404);
|
|
109837
110078
|
}
|
|
109838
110079
|
try {
|
|
109839
110080
|
const result = await weixinService.startLogin(accountId);
|
|
109840
|
-
return
|
|
110081
|
+
return json10(result);
|
|
109841
110082
|
} catch (err) {
|
|
109842
|
-
return
|
|
110083
|
+
return json10({ error: err instanceof Error ? err.message : t2("weixin.loginFailed") }, 502);
|
|
109843
110084
|
}
|
|
109844
110085
|
}
|
|
109845
110086
|
async function handleGetWeixinLoginStatus(accountId) {
|
|
109846
110087
|
const existing = getWeixinAccountById(accountId);
|
|
109847
110088
|
if (!existing) {
|
|
109848
|
-
return
|
|
110089
|
+
return json10({ error: t2("weixin.accountNotFound") }, 404);
|
|
109849
110090
|
}
|
|
109850
|
-
return
|
|
110091
|
+
return json10(weixinService.getLoginStatus(accountId));
|
|
109851
110092
|
}
|
|
109852
110093
|
async function handleListWeixinUsers(accountId) {
|
|
109853
110094
|
const existing = getWeixinAccountById(accountId);
|
|
109854
110095
|
if (!existing) {
|
|
109855
|
-
return
|
|
110096
|
+
return json10({ error: t2("weixin.accountNotFound") }, 404);
|
|
109856
110097
|
}
|
|
109857
110098
|
const users = listWeixinUsersByAccount(accountId);
|
|
109858
|
-
return
|
|
110099
|
+
return json10({ users });
|
|
109859
110100
|
}
|
|
109860
110101
|
async function handleApproveWeixinUser(accountId, userId) {
|
|
109861
110102
|
const existing = getWeixinAccountById(accountId);
|
|
109862
110103
|
if (!existing) {
|
|
109863
|
-
return
|
|
110104
|
+
return json10({ error: t2("weixin.accountNotFound") }, 404);
|
|
109864
110105
|
}
|
|
109865
110106
|
const user = approveWeixinUser(accountId, userId);
|
|
109866
110107
|
if (!user) {
|
|
109867
|
-
return
|
|
110108
|
+
return json10({ error: t2("weixin.userNotFound") }, 404);
|
|
109868
110109
|
}
|
|
109869
110110
|
const settings = getSiteSettings();
|
|
109870
110111
|
try {
|
|
@@ -109875,12 +110116,12 @@ async function handleApproveWeixinUser(accountId, userId) {
|
|
|
109875
110116
|
} catch (err) {
|
|
109876
110117
|
console.error("[weixin] approve ack failed:", err);
|
|
109877
110118
|
}
|
|
109878
|
-
return
|
|
110119
|
+
return json10({ user });
|
|
109879
110120
|
}
|
|
109880
110121
|
async function handleTestWeixinUser(accountId, userId) {
|
|
109881
110122
|
const existing = getWeixinAccountById(accountId);
|
|
109882
110123
|
if (!existing) {
|
|
109883
|
-
return
|
|
110124
|
+
return json10({ error: t2("weixin.accountNotFound") }, 404);
|
|
109884
110125
|
}
|
|
109885
110126
|
const settings = getSiteSettings();
|
|
109886
110127
|
try {
|
|
@@ -109889,14 +110130,14 @@ async function handleTestWeixinUser(accountId, userId) {
|
|
|
109889
110130
|
time: new Date().toLocaleString(toBCP47(settings.language))
|
|
109890
110131
|
}));
|
|
109891
110132
|
} catch (err) {
|
|
109892
|
-
return
|
|
110133
|
+
return json10({ error: err instanceof Error ? err.message : t2("weixin.testMessageFailed") }, 400);
|
|
109893
110134
|
}
|
|
109894
|
-
return
|
|
110135
|
+
return json10({ success: true });
|
|
109895
110136
|
}
|
|
109896
110137
|
async function handleTestWeixinAccount(accountId) {
|
|
109897
110138
|
const existing = getWeixinAccountById(accountId);
|
|
109898
110139
|
if (!existing) {
|
|
109899
|
-
return
|
|
110140
|
+
return json10({ error: t2("weixin.accountNotFound") }, 404);
|
|
109900
110141
|
}
|
|
109901
110142
|
const settings = getSiteSettings();
|
|
109902
110143
|
try {
|
|
@@ -109905,26 +110146,26 @@ async function handleTestWeixinAccount(accountId) {
|
|
|
109905
110146
|
time: new Date().toLocaleString(toBCP47(settings.language))
|
|
109906
110147
|
}));
|
|
109907
110148
|
} catch (err) {
|
|
109908
|
-
return
|
|
110149
|
+
return json10({ error: err instanceof Error ? err.message : t2("weixin.testMessageFailed") }, 400);
|
|
109909
110150
|
}
|
|
109910
|
-
return
|
|
110151
|
+
return json10({ success: true });
|
|
109911
110152
|
}
|
|
109912
110153
|
async function handleDeleteWeixinUser(accountId, userId) {
|
|
109913
110154
|
const existing = getWeixinAccountById(accountId);
|
|
109914
110155
|
if (!existing) {
|
|
109915
|
-
return
|
|
110156
|
+
return json10({ error: t2("weixin.accountNotFound") }, 404);
|
|
109916
110157
|
}
|
|
109917
110158
|
deleteWeixinUser(accountId, userId);
|
|
109918
|
-
return
|
|
110159
|
+
return json10({ success: true });
|
|
109919
110160
|
}
|
|
109920
110161
|
async function handleGetWebhooks() {
|
|
109921
110162
|
const webhooks = getAllWebhookEndpoints();
|
|
109922
|
-
return
|
|
110163
|
+
return json10({ webhooks });
|
|
109923
110164
|
}
|
|
109924
110165
|
async function handleCreateWebhook(req) {
|
|
109925
110166
|
const body = await req.json();
|
|
109926
110167
|
if (!body.url || !body.secret) {
|
|
109927
|
-
return
|
|
110168
|
+
return json10({ error: t2("apiError.urlAndSecretRequired") }, 400);
|
|
109928
110169
|
}
|
|
109929
110170
|
const now2 = new Date().toISOString();
|
|
109930
110171
|
const endpoint = {
|
|
@@ -109937,11 +110178,11 @@ async function handleCreateWebhook(req) {
|
|
|
109937
110178
|
updatedAt: now2
|
|
109938
110179
|
};
|
|
109939
110180
|
createWebhookEndpoint(endpoint);
|
|
109940
|
-
return
|
|
110181
|
+
return json10({ webhook: endpoint }, 201);
|
|
109941
110182
|
}
|
|
109942
110183
|
async function handleDeleteWebhook(id) {
|
|
109943
110184
|
deleteWebhookEndpoint(id);
|
|
109944
|
-
return
|
|
110185
|
+
return json10({ success: true });
|
|
109945
110186
|
}
|
|
109946
110187
|
async function handleGetManifest(method) {
|
|
109947
110188
|
const settings = getSiteSettings();
|
|
@@ -109980,7 +110221,7 @@ function manifestJson(data, method) {
|
|
|
109980
110221
|
}
|
|
109981
110222
|
});
|
|
109982
110223
|
}
|
|
109983
|
-
function
|
|
110224
|
+
function json10(data, status = 200, headers = {}) {
|
|
109984
110225
|
return new Response(JSON.stringify(data), {
|
|
109985
110226
|
status,
|
|
109986
110227
|
headers: {
|
|
@@ -110697,8 +110938,14 @@ var defaultDeps5 = {
|
|
|
110697
110938
|
class WebSocketServer {
|
|
110698
110939
|
connections = new Map;
|
|
110699
110940
|
pendingConnectionEntries = new Map;
|
|
110941
|
+
connectedClients = new Set;
|
|
110700
110942
|
windowCustomNames = new Map;
|
|
110701
110943
|
paneCustomNames = new Map;
|
|
110944
|
+
currentTheme = null;
|
|
110945
|
+
themeSignalLast = new Map;
|
|
110946
|
+
lastThemeTimestamp = 0n;
|
|
110947
|
+
lastBroadcastTheme = new Map;
|
|
110948
|
+
lastBroadcastSize = new Map;
|
|
110702
110949
|
deps;
|
|
110703
110950
|
constructor(options = {}) {
|
|
110704
110951
|
this.deps = {
|
|
@@ -110730,6 +110977,9 @@ class WebSocketServer {
|
|
|
110730
110977
|
this.clearReconnectTimer(entry);
|
|
110731
110978
|
entry.detachRuntime?.();
|
|
110732
110979
|
entry.detachRuntime = null;
|
|
110980
|
+
this.themeSignalLast.delete(deviceId);
|
|
110981
|
+
this.lastBroadcastTheme.delete(deviceId);
|
|
110982
|
+
this.lastBroadcastSize.delete(deviceId);
|
|
110733
110983
|
this.deps.releaseRuntime(deviceId, entry.runtime);
|
|
110734
110984
|
}
|
|
110735
110985
|
attachRuntime(deviceId, runtime) {
|
|
@@ -110814,6 +111064,7 @@ class WebSocketServer {
|
|
|
110814
111064
|
handleOpen(ws) {
|
|
110815
111065
|
console.log("[ws] client connected");
|
|
110816
111066
|
sessionStateStore.create(ws);
|
|
111067
|
+
this.connectedClients.add(ws);
|
|
110817
111068
|
}
|
|
110818
111069
|
handleMessage(ws, message) {
|
|
110819
111070
|
if (typeof message === "string") {
|
|
@@ -110852,6 +111103,7 @@ class WebSocketServer {
|
|
|
110852
111103
|
}
|
|
110853
111104
|
handleClose(ws) {
|
|
110854
111105
|
console.log("[ws] client disconnected");
|
|
111106
|
+
this.connectedClients.delete(ws);
|
|
110855
111107
|
switchBarrier.cleanupClient(ws);
|
|
110856
111108
|
sessionStateStore.cleanup(ws);
|
|
110857
111109
|
agentWsHub.removeClient(ws);
|
|
@@ -111038,6 +111290,11 @@ class WebSocketServer {
|
|
|
111038
111290
|
agentWsHub.unsubscribe(ws, decoded.sessionId);
|
|
111039
111291
|
return;
|
|
111040
111292
|
}
|
|
111293
|
+
case exports_ws_borsh.KIND_SITE_THEME_UPDATE: {
|
|
111294
|
+
const decoded = exports_ws_borsh.decodePayload(exports_ws_borsh.schema.SiteThemeUpdateC2SSchema, payload);
|
|
111295
|
+
this.handleSiteThemeUpdate(ws, decoded);
|
|
111296
|
+
return;
|
|
111297
|
+
}
|
|
111041
111298
|
default:
|
|
111042
111299
|
this.sendError(ws, refSeq, exports_ws_borsh.ERROR_UNKNOWN_KIND, `Unknown kind: ${kind}`, false);
|
|
111043
111300
|
}
|
|
@@ -111258,6 +111515,11 @@ class WebSocketServer {
|
|
|
111258
111515
|
const entry = this.connections.get(deviceId);
|
|
111259
111516
|
if (!entry)
|
|
111260
111517
|
return;
|
|
111518
|
+
const last = this.lastBroadcastSize.get(deviceId);
|
|
111519
|
+
if (last && last.cols === cols && last.rows === rows) {
|
|
111520
|
+
return;
|
|
111521
|
+
}
|
|
111522
|
+
this.lastBroadcastSize.set(deviceId, { cols, rows });
|
|
111261
111523
|
const snapshot = entry.lastSnapshot;
|
|
111262
111524
|
if (snapshot?.session?.windows) {
|
|
111263
111525
|
const window2 = snapshot.session.windows.find((w) => w.panes && w.panes.some((p) => p.id === paneId));
|
|
@@ -111356,6 +111618,89 @@ class WebSocketServer {
|
|
|
111356
111618
|
if (!entry)
|
|
111357
111619
|
return;
|
|
111358
111620
|
entry.runtime.setWindowStyle(style);
|
|
111621
|
+
if (this.currentTheme !== null) {
|
|
111622
|
+
const theme = this.currentTheme;
|
|
111623
|
+
if (this.lastBroadcastTheme.get(deviceId) !== theme) {
|
|
111624
|
+
this.lastBroadcastTheme.set(deviceId, theme);
|
|
111625
|
+
this.broadcastThemeChange(theme);
|
|
111626
|
+
}
|
|
111627
|
+
}
|
|
111628
|
+
}
|
|
111629
|
+
handleSiteThemeUpdate(ws, decoded) {
|
|
111630
|
+
if (decoded.theme !== exports_ws_borsh.SITE_THEME_DARK && decoded.theme !== exports_ws_borsh.SITE_THEME_LIGHT) {
|
|
111631
|
+
this.sendError(ws, null, exports_ws_borsh.ERROR_PAYLOAD_DECODE_FAILED, `invalid theme value: ${decoded.theme}`, false);
|
|
111632
|
+
return;
|
|
111633
|
+
}
|
|
111634
|
+
const themeName = decoded.theme === exports_ws_borsh.SITE_THEME_LIGHT ? "light" : "dark";
|
|
111635
|
+
updateSiteSettings({ theme: themeName });
|
|
111636
|
+
this.handleSiteThemeChange(themeName);
|
|
111637
|
+
this.broadcastThemeChange(themeName);
|
|
111638
|
+
this.broadcastSiteThemeUpdateS2C(themeName);
|
|
111639
|
+
}
|
|
111640
|
+
broadcastSiteThemeUpdateS2C(theme) {
|
|
111641
|
+
const now2 = BigInt(Date.now());
|
|
111642
|
+
if (now2 <= this.lastThemeTimestamp) {
|
|
111643
|
+
this.lastThemeTimestamp += 1n;
|
|
111644
|
+
} else {
|
|
111645
|
+
this.lastThemeTimestamp = now2;
|
|
111646
|
+
}
|
|
111647
|
+
const effectiveTimestamp = this.lastThemeTimestamp;
|
|
111648
|
+
const themeCode = theme === "light" ? exports_ws_borsh.SITE_THEME_LIGHT : exports_ws_borsh.SITE_THEME_DARK;
|
|
111649
|
+
const payloadBytes = exports_ws_borsh.encodePayload(exports_ws_borsh.schema.SiteThemeUpdateS2CSchema, {
|
|
111650
|
+
theme: themeCode,
|
|
111651
|
+
serverTimestamp: effectiveTimestamp
|
|
111652
|
+
});
|
|
111653
|
+
for (const client of this.connectedClients) {
|
|
111654
|
+
this.sendEnvelope(client, exports_ws_borsh.KIND_SITE_THEME_UPDATE, payloadBytes);
|
|
111655
|
+
}
|
|
111656
|
+
}
|
|
111657
|
+
handleSiteThemeChange(theme) {
|
|
111658
|
+
if (theme !== "dark" && theme !== "light") {
|
|
111659
|
+
return;
|
|
111660
|
+
}
|
|
111661
|
+
this.currentTheme = theme;
|
|
111662
|
+
const style = getTmuxWindowStyle(theme);
|
|
111663
|
+
for (const [, entry] of this.connections) {
|
|
111664
|
+
try {
|
|
111665
|
+
entry.runtime.setWindowStyle(style);
|
|
111666
|
+
} catch (err) {
|
|
111667
|
+
console.error("[ws] setWindowStyle on theme change failed:", err);
|
|
111668
|
+
}
|
|
111669
|
+
}
|
|
111670
|
+
}
|
|
111671
|
+
applyThemeToDevice(deviceId) {
|
|
111672
|
+
if (this.currentTheme === null) {
|
|
111673
|
+
return;
|
|
111674
|
+
}
|
|
111675
|
+
const entry = this.connections.get(deviceId);
|
|
111676
|
+
if (!entry) {
|
|
111677
|
+
return;
|
|
111678
|
+
}
|
|
111679
|
+
const style = getTmuxWindowStyle(this.currentTheme);
|
|
111680
|
+
try {
|
|
111681
|
+
entry.runtime.setWindowStyle(style);
|
|
111682
|
+
} catch (err) {
|
|
111683
|
+
console.error(`[ws] setWindowStyle on device ${deviceId} failed:`, err);
|
|
111684
|
+
}
|
|
111685
|
+
}
|
|
111686
|
+
broadcastThemeChange(theme) {
|
|
111687
|
+
const now2 = Date.now();
|
|
111688
|
+
for (const [deviceId, entry] of this.connections) {
|
|
111689
|
+
const last = this.themeSignalLast.get(deviceId);
|
|
111690
|
+
if (last && last.theme === theme && now2 - last.at < 1000) {
|
|
111691
|
+
continue;
|
|
111692
|
+
}
|
|
111693
|
+
this.themeSignalLast.set(deviceId, { theme, at: now2 });
|
|
111694
|
+
this.lastBroadcastTheme.set(deviceId, theme);
|
|
111695
|
+
const panes = entry.lastSnapshot?.session?.windows?.flatMap((w) => w.panes) ?? [];
|
|
111696
|
+
for (const pane of panes) {
|
|
111697
|
+
try {
|
|
111698
|
+
entry.runtime.signalThemeChange(pane.id, theme);
|
|
111699
|
+
} catch (err) {
|
|
111700
|
+
console.error(`[ws] signalThemeChange failed for ${deviceId}/${pane.id}:`, err);
|
|
111701
|
+
}
|
|
111702
|
+
}
|
|
111703
|
+
}
|
|
111359
111704
|
}
|
|
111360
111705
|
handleReorderWindows(deviceId, windowIds) {
|
|
111361
111706
|
setWindowOrder(deviceId, windowIds);
|
|
@@ -111499,6 +111844,9 @@ class WebSocketServer {
|
|
|
111499
111844
|
runtime = await this.deps.acquireRuntime(deviceId);
|
|
111500
111845
|
detachRuntime = this.attachRuntime(deviceId, runtime);
|
|
111501
111846
|
await runtime.connect();
|
|
111847
|
+
if (this.currentTheme !== null) {
|
|
111848
|
+
runtime.setWindowStyle(getTmuxWindowStyle(this.currentTheme));
|
|
111849
|
+
}
|
|
111502
111850
|
return {
|
|
111503
111851
|
runtime,
|
|
111504
111852
|
detachRuntime,
|
|
@@ -111801,10 +112149,17 @@ async function createGatewayRuntime(options = {}) {
|
|
|
111801
112149
|
primeLocalShellPath();
|
|
111802
112150
|
sweepOrphanTransferTemps();
|
|
111803
112151
|
const wsServer = new WebSocketServer;
|
|
112152
|
+
wsServer.currentTheme = getSiteSettings().theme;
|
|
111804
112153
|
connectionAlertNotifier.setBroadcaster((deviceId, payload) => {
|
|
111805
112154
|
wsServer.broadcastDeviceError(deviceId, payload);
|
|
111806
112155
|
});
|
|
111807
112156
|
registerSnapshotLookup((deviceId) => wsServer.getLastSnapshot(deviceId));
|
|
112157
|
+
registerThemeBroadcaster((theme) => {
|
|
112158
|
+
wsServer.handleSiteThemeChange(theme);
|
|
112159
|
+
wsServer.broadcastThemeChange(theme);
|
|
112160
|
+
}, (theme) => {
|
|
112161
|
+
wsServer.broadcastSiteThemeUpdateS2C(theme);
|
|
112162
|
+
});
|
|
111808
112163
|
await telegramService.refresh();
|
|
111809
112164
|
await weixinService.refresh();
|
|
111810
112165
|
await pushSupervisor.start();
|
|
@@ -111852,6 +112207,7 @@ async function createGatewayRuntime(options = {}) {
|
|
|
111852
112207
|
},
|
|
111853
112208
|
async stop() {
|
|
111854
112209
|
connectionAlertNotifier.setBroadcaster(null);
|
|
112210
|
+
registerThemeBroadcaster(null);
|
|
111855
112211
|
wsServer.closeAll();
|
|
111856
112212
|
await watchService.stop();
|
|
111857
112213
|
await agentSupervisor.stop();
|