tmex-cli 0.16.2 → 0.16.4
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 +6 -18
- package/dist/runtime/server.js +826 -243
- package/package.json +1 -1
- package/resources/fe-dist/assets/DevicePage-DxFUn3eM.js +24 -0
- package/resources/fe-dist/assets/{DevicesPage-B_jvUZtl.js → DevicesPage-CJF229QB.js} +1 -1
- package/resources/fe-dist/assets/{FilePage-DTSmWM1D.js → FilePage-CkEaJiW3.js} +1 -1
- package/resources/fe-dist/assets/{SettingsPage-LTHV37Rj.js → SettingsPage-BjsRYOBG.js} +4 -4
- package/resources/fe-dist/assets/{agent-tab-vPjPGa5f.js → agent-tab-6MAsxcE4.js} +1 -1
- package/resources/fe-dist/assets/{api-D_FToAy0.js → api-B3b18azE.js} +1 -1
- package/resources/fe-dist/assets/{arc-BSCyoyGW.js → arc-BAINpc3Q.js} +1 -1
- package/resources/fe-dist/assets/{architectureDiagram-3BPJPVTR-CBO0dAe2.js → architectureDiagram-3BPJPVTR-CWFap8y8.js} +1 -1
- package/resources/fe-dist/assets/{blockDiagram-GPEHLZMM-0ONANm30.js → blockDiagram-GPEHLZMM-BnR3WVDx.js} +1 -1
- package/resources/fe-dist/assets/{c4Diagram-AAUBKEIU-DpvhCnF8.js → c4Diagram-AAUBKEIU-BT4ZOccY.js} +1 -1
- package/resources/fe-dist/assets/{card-CD9i-fLq.js → card-TMGETMIE.js} +1 -1
- package/resources/fe-dist/assets/channel-C_D-Pin5.js +1 -0
- package/resources/fe-dist/assets/{chunk-2J33WTMH-MmS9_ur_.js → chunk-2J33WTMH-B4Tvbi6K.js} +1 -1
- package/resources/fe-dist/assets/{chunk-4BX2VUAB-CLd4Yxwh.js → chunk-4BX2VUAB-e7mC2fAZ.js} +1 -1
- package/resources/fe-dist/assets/{chunk-55IACEB6-DgCH4WwT.js → chunk-55IACEB6-CIYZgFr_.js} +1 -1
- package/resources/fe-dist/assets/{chunk-727SXJPM-B9DM5PB4.js → chunk-727SXJPM-Cp8xQ_Up.js} +1 -1
- package/resources/fe-dist/assets/{chunk-AQP2D5EJ-DQwC9D9W.js → chunk-AQP2D5EJ-C-NtHCtH.js} +1 -1
- package/resources/fe-dist/assets/{chunk-FMBD7UC4-BnvyNYGh.js → chunk-FMBD7UC4-DmjdaPSW.js} +1 -1
- package/resources/fe-dist/assets/{chunk-ND2GUHAM-BzcZgEWG.js → chunk-ND2GUHAM-Zg5krkW_.js} +1 -1
- package/resources/fe-dist/assets/{chunk-QZHKN3VN-C9BaHIUI.js → chunk-QZHKN3VN-BIuK8Di1.js} +1 -1
- package/resources/fe-dist/assets/classDiagram-4FO5ZUOK-BKAkOexI.js +1 -0
- package/resources/fe-dist/assets/classDiagram-v2-Q7XG4LA2-BKAkOexI.js +1 -0
- package/resources/fe-dist/assets/{copy-DzIk8AxV.js → copy-BfbLkQQH.js} +1 -1
- package/resources/fe-dist/assets/{cose-bilkent-S5V4N54A-NkTc0ObP.js → cose-bilkent-S5V4N54A-DjsBN2Gw.js} +1 -1
- package/resources/fe-dist/assets/{dagre-BM42HDAG-BdFDBfE_.js → dagre-BM42HDAG-EHYEOgd4.js} +1 -1
- package/resources/fe-dist/assets/{diagram-2AECGRRQ-Ba4Y0igR.js → diagram-2AECGRRQ-DP2qaS44.js} +1 -1
- package/resources/fe-dist/assets/{diagram-5GNKFQAL-B4_Or8Vp.js → diagram-5GNKFQAL-CXjsd6rW.js} +1 -1
- package/resources/fe-dist/assets/{diagram-KO2AKTUF-DbmmHTYj.js → diagram-KO2AKTUF-C3imvzg0.js} +1 -1
- package/resources/fe-dist/assets/{diagram-LMA3HP47-CRrd6lc4.js → diagram-LMA3HP47-BWfVIlqx.js} +1 -1
- package/resources/fe-dist/assets/{diagram-OG6HWLK6-BOEazFIu.js → diagram-OG6HWLK6-DjPzNtRm.js} +1 -1
- package/resources/fe-dist/assets/{erDiagram-TEJ5UH35-Dk-UowK8.js → erDiagram-TEJ5UH35-B0NYaEtR.js} +1 -1
- package/resources/fe-dist/assets/{files-tab-D2vddvsj.js → files-tab-BFIlXST7.js} +1 -1
- package/resources/fe-dist/assets/{flowDiagram-I6XJVG4X-BhbGYx-g.js → flowDiagram-I6XJVG4X-CdStxlad.js} +1 -1
- package/resources/fe-dist/assets/{ganttDiagram-6RSMTGT7-iezClDTv.js → ganttDiagram-6RSMTGT7-DdEyq_eg.js} +1 -1
- package/resources/fe-dist/assets/{gitGraphDiagram-PVQCEYII-Ncqf3CQw.js → gitGraphDiagram-PVQCEYII-DVt7acpU.js} +1 -1
- package/resources/fe-dist/assets/{index-UoApkLSY.js → index-C1akMMWP.js} +63 -63
- package/resources/fe-dist/assets/{index-DOfY8kwB.js → index-c9jmHxDX.js} +1 -1
- package/resources/fe-dist/assets/{infoDiagram-5YYISTIA-CUg3PkAb.js → infoDiagram-5YYISTIA-BfBQlpuG.js} +1 -1
- package/resources/fe-dist/assets/{ishikawaDiagram-YF4QCWOH-DU0ekJw5.js → ishikawaDiagram-YF4QCWOH-DUn8fG3F.js} +1 -1
- package/resources/fe-dist/assets/{journeyDiagram-JHISSGLW-Ji7WtMH7.js → journeyDiagram-JHISSGLW-D1YteFVs.js} +1 -1
- package/resources/fe-dist/assets/{kanban-definition-UN3LZRKU-B8zVyM8Q.js → kanban-definition-UN3LZRKU-Do0o8nlT.js} +1 -1
- package/resources/fe-dist/assets/{linear-tNPPicfI.js → linear-Bmap7qQK.js} +1 -1
- package/resources/fe-dist/assets/{markdown-preview-CzbcKxcJ.js → markdown-preview-ByBN48Ac.js} +3 -3
- package/resources/fe-dist/assets/{mermaid.core-BoNU6G1d.js → mermaid.core-CloKtMOb.js} +5 -5
- package/resources/fe-dist/assets/{mindmap-definition-RKZ34NQL-D_v1LaNP.js → mindmap-definition-RKZ34NQL-BFPgS54r.js} +1 -1
- package/resources/fe-dist/assets/{pieDiagram-4H26LBE5-B1CHCpFf.js → pieDiagram-4H26LBE5-DwY4DDxv.js} +1 -1
- package/resources/fe-dist/assets/{quadrantDiagram-W4KKPZXB-DvA3zgR7.js → quadrantDiagram-W4KKPZXB-3jSLHV3z.js} +1 -1
- package/resources/fe-dist/assets/{requirementDiagram-4Y6WPE33-BCna6ZG5.js → requirementDiagram-4Y6WPE33-DHrqJmHL.js} +1 -1
- package/resources/fe-dist/assets/{sankeyDiagram-5OEKKPKP-KEllFLAf.js → sankeyDiagram-5OEKKPKP-CIaPmx-2.js} +1 -1
- package/resources/fe-dist/assets/{send-BgCF67Uc.js → send-CAJeq7VS.js} +1 -1
- package/resources/fe-dist/assets/{sequenceDiagram-3UESZ5HK-DRsq_jg_.js → sequenceDiagram-3UESZ5HK-DhRU1sO_.js} +1 -1
- package/resources/fe-dist/assets/{stateDiagram-AJRCARHV-DhATBo8D.js → stateDiagram-AJRCARHV-DZWC0te0.js} +1 -1
- package/resources/fe-dist/assets/stateDiagram-v2-BHNVJYJU-BJcIn84l.js +1 -0
- package/resources/fe-dist/assets/{terminal-settings-panel-DsMMZFBi.js → terminal-settings-panel-BiDSWGtf.js} +2 -2
- package/resources/fe-dist/assets/{timeline-definition-PNZ67QCA-Det7AzPd.js → timeline-definition-PNZ67QCA-Y0cAlUby.js} +1 -1
- package/resources/fe-dist/assets/{transfer-toast-CHcCj3qf.js → transfer-toast-yJBQc29j.js} +1 -1
- package/resources/fe-dist/assets/{triangle-alert-BjHP6Ipw.js → triangle-alert-Bs89Dzy0.js} +1 -1
- package/resources/fe-dist/assets/{vennDiagram-CIIHVFJN-BF4R466L.js → vennDiagram-CIIHVFJN-BVWElA6Q.js} +1 -1
- package/resources/fe-dist/assets/{wardley-L42UT6IY-DLHZ_6-V.js → wardley-L42UT6IY-BBf8FmIs.js} +1 -1
- package/resources/fe-dist/assets/{wardleyDiagram-YWT4CUSO-CekN3Ye6.js → wardleyDiagram-YWT4CUSO-Cyk4va1x.js} +1 -1
- package/resources/fe-dist/assets/{xychartDiagram-2RQKCTM6-CJD3yg0M.js → xychartDiagram-2RQKCTM6-DmEvYdFT.js} +1 -1
- package/resources/fe-dist/assets/{zap-Dx7JTXJN.js → zap-B28XlJER.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",
|
|
@@ -28304,6 +28376,7 @@ var config = {
|
|
|
28304
28376
|
bellThrottleSecondsDefault: Number.parseInt(getEnv("TMEX_BELL_THROTTLE_SECONDS", "6"), 10),
|
|
28305
28377
|
notificationThrottleSecondsDefault: Number.parseInt(getEnv("TMEX_NOTIFICATION_THROTTLE_SECONDS", "3"), 10),
|
|
28306
28378
|
tmuxAllowPassthrough: getBooleanEnv("TMEX_TMUX_ALLOW_PASSTHROUGH", false),
|
|
28379
|
+
themeNotify2031Enabled: getBooleanEnv("TMEX_THEME_NOTIFY_2031", true),
|
|
28307
28380
|
tmuxTermProgram: getEnv("TMEX_TMUX_TERM_PROGRAM", "ghostty"),
|
|
28308
28381
|
tmuxWindowStyle: getEnv("TMEX_TMUX_WINDOW_STYLE", "fg=#d0d0d0,bg=#262626"),
|
|
28309
28382
|
tmuxSocket: getEnv("TMEX_TMUX_SOCKET", ""),
|
|
@@ -33329,8 +33402,12 @@ var siteSettings = sqliteTable("site_settings", {
|
|
|
33329
33402
|
sshReconnectMaxRetries: integer("ssh_reconnect_max_retries").notNull(),
|
|
33330
33403
|
sshReconnectDelaySeconds: integer("ssh_reconnect_delay_seconds").notNull(),
|
|
33331
33404
|
language: text("language").notNull().default("en_US"),
|
|
33405
|
+
theme: text("theme").notNull().default("dark"),
|
|
33332
33406
|
updatedAt: text("updated_at").notNull()
|
|
33333
|
-
}, (table) => [
|
|
33407
|
+
}, (table) => [
|
|
33408
|
+
check("site_settings_singleton_check", sql`${table.id} = 1`),
|
|
33409
|
+
check("site_settings_theme_check", sql`${table.theme} in ('dark', 'light')`)
|
|
33410
|
+
]);
|
|
33334
33411
|
var terminalShortcutSettings = sqliteTable("terminal_shortcut_settings", {
|
|
33335
33412
|
id: integer("id").primaryKey(),
|
|
33336
33413
|
items: text("items", { mode: "json" }).$type().notNull().default(DEFAULT_TERMINAL_SHORTCUTS),
|
|
@@ -33624,6 +33701,7 @@ function toSiteSettings(row) {
|
|
|
33624
33701
|
sshReconnectMaxRetries: row.sshReconnectMaxRetries,
|
|
33625
33702
|
sshReconnectDelaySeconds: row.sshReconnectDelaySeconds,
|
|
33626
33703
|
language: normalizeLocale(row.language),
|
|
33704
|
+
theme: row.theme,
|
|
33627
33705
|
updatedAt: row.updatedAt
|
|
33628
33706
|
};
|
|
33629
33707
|
}
|
|
@@ -33917,6 +33995,7 @@ function updateSiteSettings(updates) {
|
|
|
33917
33995
|
sshReconnectMaxRetries: updates.sshReconnectMaxRetries ?? current.sshReconnectMaxRetries,
|
|
33918
33996
|
sshReconnectDelaySeconds: updates.sshReconnectDelaySeconds ?? current.sshReconnectDelaySeconds,
|
|
33919
33997
|
language: updates.language ? normalizeLocale(updates.language) : current.language,
|
|
33998
|
+
theme: updates.theme ?? current.theme,
|
|
33920
33999
|
updatedAt: new Date().toISOString()
|
|
33921
34000
|
};
|
|
33922
34001
|
const orm = getDb();
|
|
@@ -33928,7 +34007,8 @@ function updateSiteSettings(updates) {
|
|
|
33928
34007
|
enableBrowserNotificationToast: next.enableBrowserNotificationToast,
|
|
33929
34008
|
enableNotificationPush: next.enableNotificationPush,
|
|
33930
34009
|
enableBellPush: next.enableBellPush,
|
|
33931
|
-
enableBellSound: next.enableBellSound
|
|
34010
|
+
enableBellSound: next.enableBellSound,
|
|
34011
|
+
theme: next.theme
|
|
33932
34012
|
}).where(eq(siteSettings.id, 1)).run();
|
|
33933
34013
|
siteSettingsCache = { value: next, expiresAt: Date.now() + SITE_SETTINGS_TTL_MS };
|
|
33934
34014
|
if (instance.language !== next.language) {
|
|
@@ -98354,7 +98434,9 @@ var MAX_OSC_KIND_BYTES = 16;
|
|
|
98354
98434
|
var MAX_OSC_PAYLOAD_BYTES = 8 * 1024;
|
|
98355
98435
|
var MAX_DCS_PASSTHROUGH_BYTES = 64 * 1024;
|
|
98356
98436
|
var MAX_KITTY_PENDING_IDS = 16;
|
|
98437
|
+
var MAX_CSI_BYTES = 64;
|
|
98357
98438
|
var TMUX_PASSTHROUGH_PREFIX = "tmux;";
|
|
98439
|
+
var THEME_UPDATES_MODE = "2031";
|
|
98358
98440
|
function createPaneStreamParser(options) {
|
|
98359
98441
|
let phase = "normal";
|
|
98360
98442
|
let oscKind = "";
|
|
@@ -98364,6 +98446,8 @@ function createPaneStreamParser(options) {
|
|
|
98364
98446
|
let warnedDcsOverflow = false;
|
|
98365
98447
|
let dcsPrefix = "";
|
|
98366
98448
|
let dcsBytes = [];
|
|
98449
|
+
let csiBytes = [];
|
|
98450
|
+
let inTmuxPassthrough = false;
|
|
98367
98451
|
const kittyPending = new Map;
|
|
98368
98452
|
function resetOscState() {
|
|
98369
98453
|
oscKind = "";
|
|
@@ -98513,8 +98597,19 @@ function createPaneStreamParser(options) {
|
|
|
98513
98597
|
dcsBytes = [];
|
|
98514
98598
|
dcsPrefix = "";
|
|
98515
98599
|
phase = "normal";
|
|
98516
|
-
|
|
98517
|
-
|
|
98600
|
+
inTmuxPassthrough = true;
|
|
98601
|
+
try {
|
|
98602
|
+
for (const byte of content) {
|
|
98603
|
+
processByte(byte);
|
|
98604
|
+
}
|
|
98605
|
+
} finally {
|
|
98606
|
+
inTmuxPassthrough = false;
|
|
98607
|
+
}
|
|
98608
|
+
const phaseAfterFlush = phase;
|
|
98609
|
+
if (phaseAfterFlush === "csi") {
|
|
98610
|
+
output.push(27, 91, ...csiBytes);
|
|
98611
|
+
csiBytes = [];
|
|
98612
|
+
phase = "normal";
|
|
98518
98613
|
}
|
|
98519
98614
|
}
|
|
98520
98615
|
function appendDcsByte(byte) {
|
|
@@ -98559,10 +98654,38 @@ function createPaneStreamParser(options) {
|
|
|
98559
98654
|
phase = "dcs-detect";
|
|
98560
98655
|
return;
|
|
98561
98656
|
}
|
|
98657
|
+
if (byte === 91) {
|
|
98658
|
+
csiBytes = [];
|
|
98659
|
+
phase = "csi";
|
|
98660
|
+
return;
|
|
98661
|
+
}
|
|
98562
98662
|
output.push(27, byte);
|
|
98563
98663
|
phase = "normal";
|
|
98564
98664
|
return;
|
|
98565
98665
|
}
|
|
98666
|
+
if (phase === "csi") {
|
|
98667
|
+
if (byte >= 64 && byte <= 126) {
|
|
98668
|
+
output.push(27, 91, ...csiBytes, byte);
|
|
98669
|
+
if ((byte === 104 || byte === 108) && csiBytes[0] === 63 && !inTmuxPassthrough) {
|
|
98670
|
+
const params = decoder2.decode(new Uint8Array(csiBytes.slice(1))).split(";");
|
|
98671
|
+
if (params.includes(THEME_UPDATES_MODE)) {
|
|
98672
|
+
options.onThemeSubscription?.(byte === 104);
|
|
98673
|
+
}
|
|
98674
|
+
}
|
|
98675
|
+
csiBytes = [];
|
|
98676
|
+
phase = "normal";
|
|
98677
|
+
return;
|
|
98678
|
+
}
|
|
98679
|
+
if (byte >= 32 && byte <= 63 && csiBytes.length < MAX_CSI_BYTES) {
|
|
98680
|
+
csiBytes.push(byte);
|
|
98681
|
+
return;
|
|
98682
|
+
}
|
|
98683
|
+
output.push(27, 91, ...csiBytes);
|
|
98684
|
+
csiBytes = [];
|
|
98685
|
+
phase = "normal";
|
|
98686
|
+
processByte(byte);
|
|
98687
|
+
return;
|
|
98688
|
+
}
|
|
98566
98689
|
if (phase === "dcs-detect") {
|
|
98567
98690
|
const expected = TMUX_PASSTHROUGH_PREFIX.charCodeAt(dcsPrefix.length);
|
|
98568
98691
|
if (byte === expected) {
|
|
@@ -98755,7 +98878,8 @@ function createControlModeSubscription(callbacks) {
|
|
|
98755
98878
|
onBell: () => callbacks.onBell(paneId),
|
|
98756
98879
|
onNotification: (notification) => callbacks.onNotification(paneId, notification),
|
|
98757
98880
|
onPromptMarker: (marker24) => callbacks.onPromptMarker?.(paneId, marker24),
|
|
98758
|
-
onClipboardWrite: (text3) => callbacks.onClipboardWrite?.(paneId, text3)
|
|
98881
|
+
onClipboardWrite: (text3) => callbacks.onClipboardWrite?.(paneId, text3),
|
|
98882
|
+
onThemeSubscription: (subscribed) => callbacks.onThemeSubscription?.(paneId, subscribed)
|
|
98759
98883
|
});
|
|
98760
98884
|
paneParsers.set(paneId, parser2);
|
|
98761
98885
|
return parser2;
|
|
@@ -99096,6 +99220,44 @@ function isTargetMissingMessage(message) {
|
|
|
99096
99220
|
return normalized.includes("can't find window") || normalized.includes("can't find pane") || normalized.includes("no such window") || normalized.includes("no such pane");
|
|
99097
99221
|
}
|
|
99098
99222
|
|
|
99223
|
+
// ../../apps/gateway/src/tmux-client/theme-subscriptions.ts
|
|
99224
|
+
function createThemeSubscriptionTracker() {
|
|
99225
|
+
const subscribed = new Set;
|
|
99226
|
+
return {
|
|
99227
|
+
note(paneId, isSubscribed) {
|
|
99228
|
+
if (isSubscribed) {
|
|
99229
|
+
subscribed.add(paneId);
|
|
99230
|
+
} else {
|
|
99231
|
+
subscribed.delete(paneId);
|
|
99232
|
+
}
|
|
99233
|
+
},
|
|
99234
|
+
clear(paneId) {
|
|
99235
|
+
subscribed.delete(paneId);
|
|
99236
|
+
},
|
|
99237
|
+
prune(validPaneIds) {
|
|
99238
|
+
for (const paneId of subscribed) {
|
|
99239
|
+
if (!validPaneIds.has(paneId)) {
|
|
99240
|
+
subscribed.delete(paneId);
|
|
99241
|
+
}
|
|
99242
|
+
}
|
|
99243
|
+
},
|
|
99244
|
+
restore(paneIds) {
|
|
99245
|
+
for (const paneId of paneIds) {
|
|
99246
|
+
subscribed.add(paneId);
|
|
99247
|
+
}
|
|
99248
|
+
},
|
|
99249
|
+
has(paneId) {
|
|
99250
|
+
return subscribed.has(paneId);
|
|
99251
|
+
},
|
|
99252
|
+
list() {
|
|
99253
|
+
return [...subscribed];
|
|
99254
|
+
},
|
|
99255
|
+
reset() {
|
|
99256
|
+
subscribed.clear();
|
|
99257
|
+
}
|
|
99258
|
+
};
|
|
99259
|
+
}
|
|
99260
|
+
|
|
99099
99261
|
// ../../apps/gateway/src/tmux-client/tmux-version.ts
|
|
99100
99262
|
var MIN_CONTROL_MODE_VERSION = { major: 3, minor: 0 };
|
|
99101
99263
|
function parseTmuxVersion(versionOutput) {
|
|
@@ -99233,6 +99395,8 @@ class LocalExternalTmuxConnection {
|
|
|
99233
99395
|
heartbeatTimer = null;
|
|
99234
99396
|
heartbeatPending = false;
|
|
99235
99397
|
heartbeatTimeoutTimer = null;
|
|
99398
|
+
themeSubscriptions = createThemeSubscriptionTracker();
|
|
99399
|
+
themeSubscriptionsRestored = false;
|
|
99236
99400
|
constructor(options, inputDeps = {}) {
|
|
99237
99401
|
this.deviceId = options.deviceId;
|
|
99238
99402
|
this.callbacks = options;
|
|
@@ -99345,7 +99509,13 @@ class LocalExternalTmuxConnection {
|
|
|
99345
99509
|
if (!this.connected) {
|
|
99346
99510
|
return;
|
|
99347
99511
|
}
|
|
99348
|
-
const argv = [
|
|
99512
|
+
const argv = [
|
|
99513
|
+
"new-window",
|
|
99514
|
+
"-t",
|
|
99515
|
+
this.sessionName,
|
|
99516
|
+
"-c",
|
|
99517
|
+
cwd ?? this.resolveDefaultWorkingDir()
|
|
99518
|
+
];
|
|
99349
99519
|
if (name24) {
|
|
99350
99520
|
argv.push("-n", name24);
|
|
99351
99521
|
}
|
|
@@ -99481,17 +99651,69 @@ class LocalExternalTmuxConnection {
|
|
|
99481
99651
|
]);
|
|
99482
99652
|
}
|
|
99483
99653
|
}
|
|
99484
|
-
setWindowStyle(style) {
|
|
99654
|
+
async setWindowStyle(style) {
|
|
99485
99655
|
if (!this.connected) {
|
|
99486
99656
|
return;
|
|
99487
99657
|
}
|
|
99488
99658
|
if (!resolveTmuxWindowStyle(config.tmuxWindowStyle)) {
|
|
99489
99659
|
return;
|
|
99490
99660
|
}
|
|
99491
|
-
this.configureWindowStyle(style).catch((error51) => {
|
|
99661
|
+
await this.configureWindowStyle(style).catch((error51) => {
|
|
99492
99662
|
this.callbacks.onError(error51);
|
|
99493
99663
|
});
|
|
99494
99664
|
}
|
|
99665
|
+
signalThemeChange(paneId, theme) {
|
|
99666
|
+
if (!this.connected || !config.themeNotify2031Enabled) {
|
|
99667
|
+
return;
|
|
99668
|
+
}
|
|
99669
|
+
if (!this.themeSubscriptions.has(paneId)) {
|
|
99670
|
+
return;
|
|
99671
|
+
}
|
|
99672
|
+
this.sendInput(paneId, `\x1B[?997;${theme === "dark" ? "1" : "2"}n`);
|
|
99673
|
+
}
|
|
99674
|
+
noteThemeSubscription(paneId, subscribed) {
|
|
99675
|
+
this.themeSubscriptions.note(paneId, subscribed);
|
|
99676
|
+
this.runTmuxAllowFailure([
|
|
99677
|
+
"set-option",
|
|
99678
|
+
"-p",
|
|
99679
|
+
"-t",
|
|
99680
|
+
paneId,
|
|
99681
|
+
"@tmex_2031",
|
|
99682
|
+
subscribed ? "on" : "off"
|
|
99683
|
+
]).catch(() => {});
|
|
99684
|
+
}
|
|
99685
|
+
clearThemeSubscription(paneId) {
|
|
99686
|
+
if (!this.themeSubscriptions.has(paneId)) {
|
|
99687
|
+
return;
|
|
99688
|
+
}
|
|
99689
|
+
this.themeSubscriptions.clear(paneId);
|
|
99690
|
+
this.runTmuxAllowFailure(["set-option", "-p", "-t", paneId, "@tmex_2031", "off"]).catch(() => {});
|
|
99691
|
+
}
|
|
99692
|
+
restoreThemeSubscriptionsOnce() {
|
|
99693
|
+
if (this.themeSubscriptionsRestored) {
|
|
99694
|
+
return;
|
|
99695
|
+
}
|
|
99696
|
+
this.themeSubscriptionsRestored = true;
|
|
99697
|
+
this.runTmuxAllowFailure([
|
|
99698
|
+
"list-panes",
|
|
99699
|
+
"-a",
|
|
99700
|
+
"-F",
|
|
99701
|
+
"#{pane_id}|#{@tmex_2031}"
|
|
99702
|
+
]).then((result) => {
|
|
99703
|
+
if (!result || result.exitCode !== 0) {
|
|
99704
|
+
return;
|
|
99705
|
+
}
|
|
99706
|
+
const restored = [];
|
|
99707
|
+
for (const line of result.stdout.split(`
|
|
99708
|
+
`)) {
|
|
99709
|
+
const [paneId, flag] = line.trim().split("|");
|
|
99710
|
+
if (paneId && flag === "on") {
|
|
99711
|
+
restored.push(paneId);
|
|
99712
|
+
}
|
|
99713
|
+
}
|
|
99714
|
+
this.themeSubscriptions.restore(restored);
|
|
99715
|
+
}).catch(() => {});
|
|
99716
|
+
}
|
|
99495
99717
|
async capturePaneText(paneId, opts) {
|
|
99496
99718
|
if (!this.connected) {
|
|
99497
99719
|
throw new Error(`tmux connection not available: ${this.deviceId}`);
|
|
@@ -99518,7 +99740,14 @@ class LocalExternalTmuxConnection {
|
|
|
99518
99740
|
if (exists3.exitCode === 0) {
|
|
99519
99741
|
return;
|
|
99520
99742
|
}
|
|
99521
|
-
await this.runTmux([
|
|
99743
|
+
await this.runTmux([
|
|
99744
|
+
"new-session",
|
|
99745
|
+
"-d",
|
|
99746
|
+
"-c",
|
|
99747
|
+
this.resolveDefaultWorkingDir(),
|
|
99748
|
+
"-s",
|
|
99749
|
+
this.sessionName
|
|
99750
|
+
]);
|
|
99522
99751
|
}
|
|
99523
99752
|
async configureSessionOptions() {
|
|
99524
99753
|
await this.runTmuxAllowFailure([
|
|
@@ -99529,7 +99758,14 @@ class LocalExternalTmuxConnection {
|
|
|
99529
99758
|
"allow-passthrough",
|
|
99530
99759
|
config.tmuxAllowPassthrough ? "on" : "off"
|
|
99531
99760
|
]);
|
|
99532
|
-
await this.runTmuxAllowFailure([
|
|
99761
|
+
await this.runTmuxAllowFailure([
|
|
99762
|
+
"set-option",
|
|
99763
|
+
"-t",
|
|
99764
|
+
this.sessionName,
|
|
99765
|
+
"-g",
|
|
99766
|
+
"extended-keys",
|
|
99767
|
+
"on"
|
|
99768
|
+
]);
|
|
99533
99769
|
await this.runTmuxAllowFailure([
|
|
99534
99770
|
"set-option",
|
|
99535
99771
|
"-t",
|
|
@@ -99538,7 +99774,14 @@ class LocalExternalTmuxConnection {
|
|
|
99538
99774
|
"extended-keys-format",
|
|
99539
99775
|
"csi-u"
|
|
99540
99776
|
]);
|
|
99541
|
-
await this.runTmuxAllowFailure([
|
|
99777
|
+
await this.runTmuxAllowFailure([
|
|
99778
|
+
"set-option",
|
|
99779
|
+
"-t",
|
|
99780
|
+
this.sessionName,
|
|
99781
|
+
"-g",
|
|
99782
|
+
"focus-events",
|
|
99783
|
+
"off"
|
|
99784
|
+
]);
|
|
99542
99785
|
await this.runTmuxAllowFailure([
|
|
99543
99786
|
"set-option",
|
|
99544
99787
|
"-t",
|
|
@@ -99697,11 +99940,17 @@ class LocalExternalTmuxConnection {
|
|
|
99697
99940
|
this.emitNotification(paneId, notification);
|
|
99698
99941
|
},
|
|
99699
99942
|
onPromptMarker: (paneId, marker24) => {
|
|
99943
|
+
if (marker24.kind === "A") {
|
|
99944
|
+
this.clearThemeSubscription(paneId);
|
|
99945
|
+
}
|
|
99700
99946
|
this.callbacks.onPromptMarker?.(paneId, marker24);
|
|
99701
99947
|
},
|
|
99702
99948
|
onClipboardWrite: (paneId, text3) => {
|
|
99703
99949
|
this.callbacks.onClipboardWrite?.(paneId, text3);
|
|
99704
99950
|
},
|
|
99951
|
+
onThemeSubscription: (paneId, subscribed) => {
|
|
99952
|
+
this.noteThemeSubscription(paneId, subscribed);
|
|
99953
|
+
},
|
|
99705
99954
|
onStructureChanged: () => {
|
|
99706
99955
|
this.requestSnapshot();
|
|
99707
99956
|
},
|
|
@@ -99899,7 +100148,14 @@ class LocalExternalTmuxConnection {
|
|
|
99899
100148
|
async closeWindowInternal(windowId) {
|
|
99900
100149
|
const count2 = Number.parseInt((await this.runTmux(["display-message", "-p", "-t", this.sessionName, "#{session_windows}"])).stdout.trim() || "0", 10);
|
|
99901
100150
|
if (count2 <= 1) {
|
|
99902
|
-
await this.runTmux([
|
|
100151
|
+
await this.runTmux([
|
|
100152
|
+
"new-window",
|
|
100153
|
+
"-d",
|
|
100154
|
+
"-t",
|
|
100155
|
+
this.sessionName,
|
|
100156
|
+
"-c",
|
|
100157
|
+
this.resolveDefaultWorkingDir()
|
|
100158
|
+
]);
|
|
99903
100159
|
}
|
|
99904
100160
|
await this.runAndRefresh(["kill-window", "-t", windowId], true);
|
|
99905
100161
|
}
|
|
@@ -100008,7 +100264,14 @@ class LocalExternalTmuxConnection {
|
|
|
100008
100264
|
"-F",
|
|
100009
100265
|
WINDOW_SNAPSHOT_FORMAT
|
|
100010
100266
|
]),
|
|
100011
|
-
this.runTmuxAllowFailure([
|
|
100267
|
+
this.runTmuxAllowFailure([
|
|
100268
|
+
"list-panes",
|
|
100269
|
+
"-s",
|
|
100270
|
+
"-t",
|
|
100271
|
+
this.sessionName,
|
|
100272
|
+
"-F",
|
|
100273
|
+
PANE_SNAPSHOT_FORMAT
|
|
100274
|
+
])
|
|
100012
100275
|
]);
|
|
100013
100276
|
const transientResult = [sessionRes, windowsRes, panesRes].find((res) => res.exitCode === TMUX_SPAWN_UNAVAILABLE_EXIT);
|
|
100014
100277
|
if (transientResult) {
|
|
@@ -100037,7 +100300,10 @@ ${panesRes.stderr}`;
|
|
|
100037
100300
|
this.parseSnapshotWindows(windowsRes.stdout.split(/\r?\n/));
|
|
100038
100301
|
this.parseSnapshotPanes(panesRes.stdout.split(/\r?\n/));
|
|
100039
100302
|
this.discardInvalidSnapshot();
|
|
100040
|
-
|
|
100303
|
+
const expectedPaneIds = new Set(this.getExpectedPaneIds());
|
|
100304
|
+
this.controlSubscription?.prunePanes(expectedPaneIds);
|
|
100305
|
+
this.themeSubscriptions.prune(expectedPaneIds);
|
|
100306
|
+
this.restoreThemeSubscriptionsOnce();
|
|
100041
100307
|
this.markSpawnRecovered();
|
|
100042
100308
|
this.emitSnapshot();
|
|
100043
100309
|
}
|
|
@@ -100294,6 +100560,45 @@ function joinShellArgs(argv) {
|
|
|
100294
100560
|
return argv.map((arg) => quoteShellArg(arg)).join(" ");
|
|
100295
100561
|
}
|
|
100296
100562
|
|
|
100563
|
+
// ../../apps/gateway/src/tmux-client/ssh-bootstrap.ts
|
|
100564
|
+
function buildSshBootstrapScript() {
|
|
100565
|
+
return [
|
|
100566
|
+
". /etc/profile 2>/dev/null || true",
|
|
100567
|
+
'[ -f "$HOME/.profile" ] && . "$HOME/.profile" 2>/dev/null || true',
|
|
100568
|
+
'[ -f "$HOME/.bash_profile" ] && . "$HOME/.bash_profile" 2>/dev/null || true',
|
|
100569
|
+
'TMUX_BIN="$(command -v tmux 2>/dev/null || true)"',
|
|
100570
|
+
'if [ -z "$TMUX_BIN" ]; then',
|
|
100571
|
+
" for p in /usr/local/bin/tmux /opt/homebrew/bin/tmux /usr/bin/tmux /bin/tmux; do",
|
|
100572
|
+
' [ -x "$p" ] && TMUX_BIN="$p" && break',
|
|
100573
|
+
" done",
|
|
100574
|
+
"fi",
|
|
100575
|
+
'HOME_DIR="${HOME:-$(pwd)}"',
|
|
100576
|
+
'if [ -z "$TMUX_BIN" ]; then',
|
|
100577
|
+
" printf 'TMEX_BOOT_FAIL\\ttmux_not_found\\n'",
|
|
100578
|
+
"else",
|
|
100579
|
+
` printf 'TMEX_BOOT_OK\\t%s\\t%s\\t%s\\n' "$TMUX_BIN" "$("$TMUX_BIN" -V 2>/dev/null)" "$HOME_DIR"`,
|
|
100580
|
+
"fi"
|
|
100581
|
+
].join(`
|
|
100582
|
+
`);
|
|
100583
|
+
}
|
|
100584
|
+
function parseSshBootstrapOutput(output) {
|
|
100585
|
+
const lines = output.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
100586
|
+
for (const line of lines) {
|
|
100587
|
+
if (line.startsWith("TMEX_BOOT_OK\t")) {
|
|
100588
|
+
const [, tmuxBin = "", tmuxVersion = "", homeDir = ""] = line.split("\t");
|
|
100589
|
+
if (!tmuxBin || !homeDir) {
|
|
100590
|
+
return { ok: false, reason: "invalid_bootstrap_payload" };
|
|
100591
|
+
}
|
|
100592
|
+
return { ok: true, tmuxBin, tmuxVersion, homeDir };
|
|
100593
|
+
}
|
|
100594
|
+
if (line.startsWith("TMEX_BOOT_FAIL\t")) {
|
|
100595
|
+
const [, reason = "tmux_bootstrap_failed"] = line.split("\t");
|
|
100596
|
+
return { ok: false, reason };
|
|
100597
|
+
}
|
|
100598
|
+
}
|
|
100599
|
+
return { ok: false, reason: "missing_bootstrap_marker" };
|
|
100600
|
+
}
|
|
100601
|
+
|
|
100297
100602
|
// ../../apps/gateway/src/tmux-client/ssh-connect-config.ts
|
|
100298
100603
|
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
100299
100604
|
import { join as join3 } from "path";
|
|
@@ -100586,45 +100891,6 @@ async function resolveSshConnectConfig(device, decrypt2, inputDeps = {}) {
|
|
|
100586
100891
|
return authConfig;
|
|
100587
100892
|
}
|
|
100588
100893
|
|
|
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
100894
|
// ../../apps/gateway/src/tmux-client/ssh-external-connection.ts
|
|
100629
100895
|
function hasRenderableTerminalContent2(value) {
|
|
100630
100896
|
return value.trim().length > 0;
|
|
@@ -100664,6 +100930,8 @@ class SshExternalTmuxConnection {
|
|
|
100664
100930
|
heartbeatTimer = null;
|
|
100665
100931
|
heartbeatPending = false;
|
|
100666
100932
|
heartbeatTimeoutTimer = null;
|
|
100933
|
+
themeSubscriptions = createThemeSubscriptionTracker();
|
|
100934
|
+
themeSubscriptionsRestored = false;
|
|
100667
100935
|
sshClient = null;
|
|
100668
100936
|
commandStream = null;
|
|
100669
100937
|
commandStdoutBuffer = "";
|
|
@@ -100725,6 +100993,58 @@ class SshExternalTmuxConnection {
|
|
|
100725
100993
|
});
|
|
100726
100994
|
}
|
|
100727
100995
|
}
|
|
100996
|
+
signalThemeChange(paneId, theme) {
|
|
100997
|
+
if (!this.connected || !config.themeNotify2031Enabled) {
|
|
100998
|
+
return;
|
|
100999
|
+
}
|
|
101000
|
+
if (!this.themeSubscriptions.has(paneId)) {
|
|
101001
|
+
return;
|
|
101002
|
+
}
|
|
101003
|
+
this.sendInput(paneId, `\x1B[?997;${theme === "dark" ? "1" : "2"}n`);
|
|
101004
|
+
}
|
|
101005
|
+
noteThemeSubscription(paneId, subscribed) {
|
|
101006
|
+
this.themeSubscriptions.note(paneId, subscribed);
|
|
101007
|
+
this.runTmuxAllowFailure([
|
|
101008
|
+
"set-option",
|
|
101009
|
+
"-p",
|
|
101010
|
+
"-t",
|
|
101011
|
+
paneId,
|
|
101012
|
+
"@tmex_2031",
|
|
101013
|
+
subscribed ? "on" : "off"
|
|
101014
|
+
]).catch(() => {});
|
|
101015
|
+
}
|
|
101016
|
+
clearThemeSubscription(paneId) {
|
|
101017
|
+
if (!this.themeSubscriptions.has(paneId)) {
|
|
101018
|
+
return;
|
|
101019
|
+
}
|
|
101020
|
+
this.themeSubscriptions.clear(paneId);
|
|
101021
|
+
this.runTmuxAllowFailure(["set-option", "-p", "-t", paneId, "@tmex_2031", "off"]).catch(() => {});
|
|
101022
|
+
}
|
|
101023
|
+
restoreThemeSubscriptionsOnce() {
|
|
101024
|
+
if (this.themeSubscriptionsRestored) {
|
|
101025
|
+
return;
|
|
101026
|
+
}
|
|
101027
|
+
this.themeSubscriptionsRestored = true;
|
|
101028
|
+
this.runTmuxAllowFailure([
|
|
101029
|
+
"list-panes",
|
|
101030
|
+
"-a",
|
|
101031
|
+
"-F",
|
|
101032
|
+
"#{pane_id}|#{@tmex_2031}"
|
|
101033
|
+
]).then((result) => {
|
|
101034
|
+
if (!result || result.exitCode !== 0) {
|
|
101035
|
+
return;
|
|
101036
|
+
}
|
|
101037
|
+
const restored = [];
|
|
101038
|
+
for (const line of result.stdout.split(`
|
|
101039
|
+
`)) {
|
|
101040
|
+
const [paneId, flag] = line.trim().split("|");
|
|
101041
|
+
if (paneId && flag === "on") {
|
|
101042
|
+
restored.push(paneId);
|
|
101043
|
+
}
|
|
101044
|
+
}
|
|
101045
|
+
this.themeSubscriptions.restore(restored);
|
|
101046
|
+
}).catch(() => {});
|
|
101047
|
+
}
|
|
100728
101048
|
resizePane(paneId, cols, rows) {
|
|
100729
101049
|
if (!this.connected) {
|
|
100730
101050
|
return;
|
|
@@ -100761,7 +101081,13 @@ class SshExternalTmuxConnection {
|
|
|
100761
101081
|
if (!this.connected) {
|
|
100762
101082
|
return;
|
|
100763
101083
|
}
|
|
100764
|
-
const argv = [
|
|
101084
|
+
const argv = [
|
|
101085
|
+
"new-window",
|
|
101086
|
+
"-t",
|
|
101087
|
+
this.sessionName,
|
|
101088
|
+
"-c",
|
|
101089
|
+
cwd ?? this.resolveDefaultWorkingDir()
|
|
101090
|
+
];
|
|
100765
101091
|
if (name24) {
|
|
100766
101092
|
argv.push("-n", name24);
|
|
100767
101093
|
}
|
|
@@ -100897,14 +101223,14 @@ class SshExternalTmuxConnection {
|
|
|
100897
101223
|
]);
|
|
100898
101224
|
}
|
|
100899
101225
|
}
|
|
100900
|
-
setWindowStyle(style) {
|
|
101226
|
+
async setWindowStyle(style) {
|
|
100901
101227
|
if (!this.connected) {
|
|
100902
101228
|
return;
|
|
100903
101229
|
}
|
|
100904
101230
|
if (!resolveTmuxWindowStyle(config.tmuxWindowStyle)) {
|
|
100905
101231
|
return;
|
|
100906
101232
|
}
|
|
100907
|
-
this.configureWindowStyle(style).catch((error51) => {
|
|
101233
|
+
await this.configureWindowStyle(style).catch((error51) => {
|
|
100908
101234
|
this.callbacks.onError(error51);
|
|
100909
101235
|
});
|
|
100910
101236
|
}
|
|
@@ -101040,7 +101366,14 @@ class SshExternalTmuxConnection {
|
|
|
101040
101366
|
if (exists3.exitCode === 0) {
|
|
101041
101367
|
return;
|
|
101042
101368
|
}
|
|
101043
|
-
await this.runTmux([
|
|
101369
|
+
await this.runTmux([
|
|
101370
|
+
"new-session",
|
|
101371
|
+
"-d",
|
|
101372
|
+
"-c",
|
|
101373
|
+
this.resolveDefaultWorkingDir(),
|
|
101374
|
+
"-s",
|
|
101375
|
+
this.sessionName
|
|
101376
|
+
]);
|
|
101044
101377
|
}
|
|
101045
101378
|
async configureSessionOptions() {
|
|
101046
101379
|
await this.runTmuxAllowFailure([
|
|
@@ -101051,7 +101384,14 @@ class SshExternalTmuxConnection {
|
|
|
101051
101384
|
"allow-passthrough",
|
|
101052
101385
|
config.tmuxAllowPassthrough ? "on" : "off"
|
|
101053
101386
|
]);
|
|
101054
|
-
await this.runTmuxAllowFailure([
|
|
101387
|
+
await this.runTmuxAllowFailure([
|
|
101388
|
+
"set-option",
|
|
101389
|
+
"-t",
|
|
101390
|
+
this.sessionName,
|
|
101391
|
+
"-g",
|
|
101392
|
+
"extended-keys",
|
|
101393
|
+
"on"
|
|
101394
|
+
]);
|
|
101055
101395
|
await this.runTmuxAllowFailure([
|
|
101056
101396
|
"set-option",
|
|
101057
101397
|
"-t",
|
|
@@ -101060,7 +101400,14 @@ class SshExternalTmuxConnection {
|
|
|
101060
101400
|
"extended-keys-format",
|
|
101061
101401
|
"csi-u"
|
|
101062
101402
|
]);
|
|
101063
|
-
await this.runTmuxAllowFailure([
|
|
101403
|
+
await this.runTmuxAllowFailure([
|
|
101404
|
+
"set-option",
|
|
101405
|
+
"-t",
|
|
101406
|
+
this.sessionName,
|
|
101407
|
+
"-g",
|
|
101408
|
+
"focus-events",
|
|
101409
|
+
"off"
|
|
101410
|
+
]);
|
|
101064
101411
|
await this.runTmuxAllowFailure([
|
|
101065
101412
|
"set-option",
|
|
101066
101413
|
"-t",
|
|
@@ -101108,6 +101455,7 @@ class SshExternalTmuxConnection {
|
|
|
101108
101455
|
if (!windowStyle) {
|
|
101109
101456
|
return;
|
|
101110
101457
|
}
|
|
101458
|
+
const startedAt = config.isDev ? Date.now() : 0;
|
|
101111
101459
|
await this.runTmuxAllowFailure([
|
|
101112
101460
|
"set-hook",
|
|
101113
101461
|
"-t",
|
|
@@ -101123,22 +101471,26 @@ class SshExternalTmuxConnection {
|
|
|
101123
101471
|
"#{window_id}"
|
|
101124
101472
|
]);
|
|
101125
101473
|
if (windows.exitCode !== 0) {
|
|
101474
|
+
if (config.isDev) {
|
|
101475
|
+
console.debug(`[ssh] configureWindowStyle deviceId=${this.deviceId} elapsed=${Date.now() - startedAt}ms (list-windows failed)`);
|
|
101476
|
+
}
|
|
101126
101477
|
return;
|
|
101127
101478
|
}
|
|
101479
|
+
const windowIds = [];
|
|
101128
101480
|
for (const line of windows.stdout.split(`
|
|
101129
101481
|
`)) {
|
|
101130
101482
|
const windowId = line.trim();
|
|
101131
101483
|
if (!windowId) {
|
|
101132
101484
|
continue;
|
|
101133
101485
|
}
|
|
101134
|
-
|
|
101135
|
-
|
|
101136
|
-
|
|
101137
|
-
|
|
101138
|
-
|
|
101139
|
-
|
|
101140
|
-
|
|
101141
|
-
]);
|
|
101486
|
+
windowIds.push(windowId);
|
|
101487
|
+
}
|
|
101488
|
+
if (windowIds.length > 0) {
|
|
101489
|
+
const setOptions = windowIds.map((id) => `${quoteShellArg(this.tmuxBin)} set-option -w -t ${quoteShellArg(id)} window-style ${quoteShellArg(windowStyle)}`).join(" && ");
|
|
101490
|
+
await this.runShellAllowFailure(setOptions);
|
|
101491
|
+
}
|
|
101492
|
+
if (config.isDev) {
|
|
101493
|
+
console.debug(`[ssh] configureWindowStyle deviceId=${this.deviceId} windows=${windowIds.length} elapsed=${Date.now() - startedAt}ms`);
|
|
101142
101494
|
}
|
|
101143
101495
|
}
|
|
101144
101496
|
async ensureGhosttyTerminfo() {
|
|
@@ -101215,11 +101567,17 @@ class SshExternalTmuxConnection {
|
|
|
101215
101567
|
this.emitNotification(paneId, notification);
|
|
101216
101568
|
},
|
|
101217
101569
|
onPromptMarker: (paneId, marker24) => {
|
|
101570
|
+
if (marker24.kind === "A") {
|
|
101571
|
+
this.clearThemeSubscription(paneId);
|
|
101572
|
+
}
|
|
101218
101573
|
this.callbacks.onPromptMarker?.(paneId, marker24);
|
|
101219
101574
|
},
|
|
101220
101575
|
onClipboardWrite: (paneId, text3) => {
|
|
101221
101576
|
this.callbacks.onClipboardWrite?.(paneId, text3);
|
|
101222
101577
|
},
|
|
101578
|
+
onThemeSubscription: (paneId, subscribed) => {
|
|
101579
|
+
this.noteThemeSubscription(paneId, subscribed);
|
|
101580
|
+
},
|
|
101223
101581
|
onStructureChanged: () => {
|
|
101224
101582
|
this.requestSnapshot();
|
|
101225
101583
|
},
|
|
@@ -101380,7 +101738,14 @@ class SshExternalTmuxConnection {
|
|
|
101380
101738
|
async closeWindowInternal(windowId) {
|
|
101381
101739
|
const count2 = Number.parseInt((await this.runTmux(["display-message", "-p", "-t", this.sessionName, "#{session_windows}"])).stdout.trim() || "0", 10);
|
|
101382
101740
|
if (count2 <= 1) {
|
|
101383
|
-
await this.runTmux([
|
|
101741
|
+
await this.runTmux([
|
|
101742
|
+
"new-window",
|
|
101743
|
+
"-d",
|
|
101744
|
+
"-t",
|
|
101745
|
+
this.sessionName,
|
|
101746
|
+
"-c",
|
|
101747
|
+
this.resolveDefaultWorkingDir()
|
|
101748
|
+
]);
|
|
101384
101749
|
}
|
|
101385
101750
|
await this.runAndRefresh(["kill-window", "-t", windowId], true);
|
|
101386
101751
|
}
|
|
@@ -101489,7 +101854,14 @@ class SshExternalTmuxConnection {
|
|
|
101489
101854
|
"-F",
|
|
101490
101855
|
WINDOW_SNAPSHOT_FORMAT
|
|
101491
101856
|
]),
|
|
101492
|
-
this.runTmuxAllowFailure([
|
|
101857
|
+
this.runTmuxAllowFailure([
|
|
101858
|
+
"list-panes",
|
|
101859
|
+
"-s",
|
|
101860
|
+
"-t",
|
|
101861
|
+
this.sessionName,
|
|
101862
|
+
"-F",
|
|
101863
|
+
PANE_SNAPSHOT_FORMAT
|
|
101864
|
+
])
|
|
101493
101865
|
]);
|
|
101494
101866
|
if (sessionRes.exitCode !== 0 || windowsRes.exitCode !== 0 || panesRes.exitCode !== 0) {
|
|
101495
101867
|
const stderrBlob = `${sessionRes.stderr}
|
|
@@ -101513,7 +101885,10 @@ ${panesRes.stderr}`;
|
|
|
101513
101885
|
this.parseSnapshotWindows(windowsRes.stdout.split(/\r?\n/));
|
|
101514
101886
|
this.parseSnapshotPanes(panesRes.stdout.split(/\r?\n/));
|
|
101515
101887
|
this.discardInvalidSnapshot();
|
|
101516
|
-
|
|
101888
|
+
const expectedPaneIds = new Set(this.getExpectedPaneIds());
|
|
101889
|
+
this.controlSubscription?.prunePanes(expectedPaneIds);
|
|
101890
|
+
this.themeSubscriptions.prune(expectedPaneIds);
|
|
101891
|
+
this.restoreThemeSubscriptionsOnce();
|
|
101517
101892
|
this.emitSnapshot();
|
|
101518
101893
|
}
|
|
101519
101894
|
parseSnapshotSession(lines) {
|
|
@@ -102013,7 +102388,10 @@ class DeviceSessionRuntime {
|
|
|
102013
102388
|
this.connection.renameWindow(windowId, name24);
|
|
102014
102389
|
}
|
|
102015
102390
|
setWindowStyle(style) {
|
|
102016
|
-
this.connection.setWindowStyle(style);
|
|
102391
|
+
return this.connection.setWindowStyle(style);
|
|
102392
|
+
}
|
|
102393
|
+
signalThemeChange(paneId, theme) {
|
|
102394
|
+
this.connection.signalThemeChange(paneId, theme);
|
|
102017
102395
|
}
|
|
102018
102396
|
async capturePaneText(paneId, opts) {
|
|
102019
102397
|
return this.connection.capturePaneText(paneId, opts);
|
|
@@ -107545,8 +107923,8 @@ function getBaseVersion() {
|
|
|
107545
107923
|
if (cachedBase !== undefined)
|
|
107546
107924
|
return cachedBase;
|
|
107547
107925
|
let base = null;
|
|
107548
|
-
if ("0.16.
|
|
107549
|
-
base = "0.16.
|
|
107926
|
+
if ("0.16.4") {
|
|
107927
|
+
base = "0.16.4";
|
|
107550
107928
|
}
|
|
107551
107929
|
if (!base && config.isProd) {
|
|
107552
107930
|
base = readInstallMeta()?.cliVersion ?? null;
|
|
@@ -107921,6 +108299,62 @@ async function handleDeviceTestConnection(deviceId, inputDeps = {}) {
|
|
|
107921
108299
|
}
|
|
107922
108300
|
}
|
|
107923
108301
|
|
|
108302
|
+
// ../../apps/gateway/src/tmux/theme-broadcaster.ts
|
|
108303
|
+
var tmuxBroadcaster = null;
|
|
108304
|
+
var s2cBroadcaster = null;
|
|
108305
|
+
function registerThemeBroadcaster(tmux, s2c = null) {
|
|
108306
|
+
tmuxBroadcaster = tmux;
|
|
108307
|
+
s2cBroadcaster = s2c;
|
|
108308
|
+
}
|
|
108309
|
+
function broadcastThemeChange(theme) {
|
|
108310
|
+
tmuxBroadcaster?.(theme);
|
|
108311
|
+
}
|
|
108312
|
+
function broadcastSiteThemeUpdateS2C(theme) {
|
|
108313
|
+
s2cBroadcaster?.(theme);
|
|
108314
|
+
}
|
|
108315
|
+
|
|
108316
|
+
// ../../apps/gateway/src/api/theme.ts
|
|
108317
|
+
var VALID_THEMES = ["dark", "light"];
|
|
108318
|
+
function handleThemeApiRequest(req, path) {
|
|
108319
|
+
if (path === "/api/settings/theme" && req.method === "GET") {
|
|
108320
|
+
return handleGetTheme();
|
|
108321
|
+
}
|
|
108322
|
+
if (path === "/api/settings/theme" && req.method === "POST") {
|
|
108323
|
+
return handleUpdateTheme(req);
|
|
108324
|
+
}
|
|
108325
|
+
return null;
|
|
108326
|
+
}
|
|
108327
|
+
function handleGetTheme() {
|
|
108328
|
+
const settings = getSiteSettings();
|
|
108329
|
+
return json8({ theme: settings.theme, serverTimestamp: Date.now() });
|
|
108330
|
+
}
|
|
108331
|
+
async function handleUpdateTheme(req) {
|
|
108332
|
+
let body;
|
|
108333
|
+
try {
|
|
108334
|
+
body = await req.json();
|
|
108335
|
+
} catch {
|
|
108336
|
+
return json8({ error: "invalid request body" }, 400);
|
|
108337
|
+
}
|
|
108338
|
+
if (typeof body !== "object" || body === null || Array.isArray(body)) {
|
|
108339
|
+
return json8({ error: "invalid request body" }, 400);
|
|
108340
|
+
}
|
|
108341
|
+
const { theme } = body;
|
|
108342
|
+
if (typeof theme !== "string" || !VALID_THEMES.includes(theme)) {
|
|
108343
|
+
return json8({ error: "theme must be one of: dark, light" }, 400);
|
|
108344
|
+
}
|
|
108345
|
+
const serverTimestamp = Date.now();
|
|
108346
|
+
updateSiteSettings({ theme });
|
|
108347
|
+
broadcastThemeChange(theme);
|
|
108348
|
+
broadcastSiteThemeUpdateS2C(theme);
|
|
108349
|
+
return json8({ theme, serverTimestamp });
|
|
108350
|
+
}
|
|
108351
|
+
function json8(data, status = 200) {
|
|
108352
|
+
return new Response(JSON.stringify(data), {
|
|
108353
|
+
status,
|
|
108354
|
+
headers: { "Content-Type": "application/json" }
|
|
108355
|
+
});
|
|
108356
|
+
}
|
|
108357
|
+
|
|
107924
108358
|
// ../../apps/gateway/src/db/watch.ts
|
|
107925
108359
|
function createWatchRule(input) {
|
|
107926
108360
|
const orm = getDb();
|
|
@@ -109019,35 +109453,35 @@ async function handleListRules(req) {
|
|
|
109019
109453
|
if (paneId) {
|
|
109020
109454
|
rules = rules.filter((rule) => rule.paneId === paneId);
|
|
109021
109455
|
}
|
|
109022
|
-
return
|
|
109456
|
+
return json9({ rules: rules.map(toRuleDto) });
|
|
109023
109457
|
}
|
|
109024
109458
|
async function handleCreateRule(req, deps) {
|
|
109025
109459
|
const raw = await readJsonObjectBody3(req);
|
|
109026
109460
|
if (!raw) {
|
|
109027
|
-
return
|
|
109461
|
+
return json9({ error: t2("apiError.invalidRequest") }, 400);
|
|
109028
109462
|
}
|
|
109029
109463
|
const body = raw;
|
|
109030
109464
|
const name24 = typeof body.name === "string" ? body.name.trim() : "";
|
|
109031
109465
|
if (!name24) {
|
|
109032
|
-
return
|
|
109466
|
+
return json9({ error: t2("apiError.watchNameRequired") }, 400);
|
|
109033
109467
|
}
|
|
109034
109468
|
const deviceId = typeof body.deviceId === "string" ? body.deviceId.trim() : "";
|
|
109035
109469
|
if (!deviceId) {
|
|
109036
|
-
return
|
|
109470
|
+
return json9({ error: t2("apiError.agentDeviceRequired") }, 400);
|
|
109037
109471
|
}
|
|
109038
109472
|
if (!getDeviceById(deviceId)) {
|
|
109039
|
-
return
|
|
109473
|
+
return json9({ error: t2("apiError.deviceNotFound") }, 404);
|
|
109040
109474
|
}
|
|
109041
109475
|
const paneId = typeof body.paneId === "string" ? body.paneId.trim() : "";
|
|
109042
109476
|
if (!paneId) {
|
|
109043
|
-
return
|
|
109477
|
+
return json9({ error: t2("apiError.agentPaneRequired") }, 400);
|
|
109044
109478
|
}
|
|
109045
109479
|
if (!TRIGGER_TYPES.includes(body.triggerType)) {
|
|
109046
|
-
return
|
|
109480
|
+
return json9({ error: t2("apiError.watchTriggerTypeInvalid") }, 400);
|
|
109047
109481
|
}
|
|
109048
109482
|
const parsed = parseRuleFields(raw);
|
|
109049
109483
|
if (!parsed.ok) {
|
|
109050
|
-
return
|
|
109484
|
+
return json9({ error: parsed.error }, 400);
|
|
109051
109485
|
}
|
|
109052
109486
|
const fields = parsed.fields;
|
|
109053
109487
|
const effective = {
|
|
@@ -109060,7 +109494,7 @@ async function handleCreateRule(req, deps) {
|
|
|
109060
109494
|
};
|
|
109061
109495
|
const semanticError = validateRuleSemantics(effective);
|
|
109062
109496
|
if (semanticError) {
|
|
109063
|
-
return
|
|
109497
|
+
return json9({ error: semanticError }, 400);
|
|
109064
109498
|
}
|
|
109065
109499
|
const rule = createWatchRule({
|
|
109066
109500
|
name: name24,
|
|
@@ -109083,50 +109517,50 @@ async function handleCreateRule(req, deps) {
|
|
|
109083
109517
|
cooldownSeconds: fields.cooldownSeconds
|
|
109084
109518
|
});
|
|
109085
109519
|
await deps.service.refreshRule(rule.id);
|
|
109086
|
-
return
|
|
109520
|
+
return json9({ rule: toRuleDto(rule), state: null }, 201);
|
|
109087
109521
|
}
|
|
109088
109522
|
async function handleGetRule(id) {
|
|
109089
109523
|
const rule = getWatchRuleById(id);
|
|
109090
109524
|
if (!rule) {
|
|
109091
|
-
return
|
|
109525
|
+
return json9({ error: t2("apiError.watchRuleNotFound") }, 404);
|
|
109092
109526
|
}
|
|
109093
109527
|
const state = getWatchRuleState(id);
|
|
109094
|
-
return
|
|
109528
|
+
return json9({ rule: toRuleDto(rule), state: state ? toStateDto(state) : null });
|
|
109095
109529
|
}
|
|
109096
109530
|
async function handleUpdateRule(req, id, deps) {
|
|
109097
109531
|
const existing = getWatchRuleById(id);
|
|
109098
109532
|
if (!existing) {
|
|
109099
|
-
return
|
|
109533
|
+
return json9({ error: t2("apiError.watchRuleNotFound") }, 404);
|
|
109100
109534
|
}
|
|
109101
109535
|
const raw = await readJsonObjectBody3(req);
|
|
109102
109536
|
if (!raw) {
|
|
109103
|
-
return
|
|
109537
|
+
return json9({ error: t2("apiError.invalidRequest") }, 400);
|
|
109104
109538
|
}
|
|
109105
109539
|
const body = raw;
|
|
109106
109540
|
const updates = {};
|
|
109107
109541
|
if (body.name !== undefined) {
|
|
109108
109542
|
const name24 = typeof body.name === "string" ? body.name.trim() : "";
|
|
109109
109543
|
if (!name24) {
|
|
109110
|
-
return
|
|
109544
|
+
return json9({ error: t2("apiError.watchNameRequired") }, 400);
|
|
109111
109545
|
}
|
|
109112
109546
|
updates.name = name24;
|
|
109113
109547
|
}
|
|
109114
109548
|
if (body.paneId !== undefined) {
|
|
109115
109549
|
const paneId = typeof body.paneId === "string" ? body.paneId.trim() : "";
|
|
109116
109550
|
if (!paneId) {
|
|
109117
|
-
return
|
|
109551
|
+
return json9({ error: t2("apiError.agentPaneRequired") }, 400);
|
|
109118
109552
|
}
|
|
109119
109553
|
updates.paneId = paneId;
|
|
109120
109554
|
}
|
|
109121
109555
|
if (body.triggerType !== undefined) {
|
|
109122
109556
|
if (!TRIGGER_TYPES.includes(body.triggerType)) {
|
|
109123
|
-
return
|
|
109557
|
+
return json9({ error: t2("apiError.watchTriggerTypeInvalid") }, 400);
|
|
109124
109558
|
}
|
|
109125
109559
|
updates.triggerType = body.triggerType;
|
|
109126
109560
|
}
|
|
109127
109561
|
const parsed = parseRuleFields(raw);
|
|
109128
109562
|
if (!parsed.ok) {
|
|
109129
|
-
return
|
|
109563
|
+
return json9({ error: parsed.error }, 400);
|
|
109130
109564
|
}
|
|
109131
109565
|
const fields = parsed.fields;
|
|
109132
109566
|
Object.assign(updates, fields);
|
|
@@ -109140,32 +109574,32 @@ async function handleUpdateRule(req, id, deps) {
|
|
|
109140
109574
|
};
|
|
109141
109575
|
const semanticError = validateRuleSemantics(effective);
|
|
109142
109576
|
if (semanticError) {
|
|
109143
|
-
return
|
|
109577
|
+
return json9({ error: semanticError }, 400);
|
|
109144
109578
|
}
|
|
109145
109579
|
const rule = updateWatchRule(id, updates);
|
|
109146
109580
|
if (!rule) {
|
|
109147
|
-
return
|
|
109581
|
+
return json9({ error: t2("apiError.watchRuleNotFound") }, 404);
|
|
109148
109582
|
}
|
|
109149
109583
|
await deps.service.refreshRule(id);
|
|
109150
109584
|
const state = getWatchRuleState(id);
|
|
109151
|
-
return
|
|
109585
|
+
return json9({ rule: toRuleDto(rule), state: state ? toStateDto(state) : null });
|
|
109152
109586
|
}
|
|
109153
109587
|
async function handleDeleteRule(id, deps) {
|
|
109154
109588
|
const existing = getWatchRuleById(id);
|
|
109155
109589
|
if (!existing) {
|
|
109156
|
-
return
|
|
109590
|
+
return json9({ error: t2("apiError.watchRuleNotFound") }, 404);
|
|
109157
109591
|
}
|
|
109158
109592
|
deleteWatchRule(id);
|
|
109159
109593
|
await deps.service.removeRule(id);
|
|
109160
|
-
return
|
|
109594
|
+
return json9({ success: true });
|
|
109161
109595
|
}
|
|
109162
109596
|
async function handleGetRuleState(id, deps) {
|
|
109163
109597
|
const rule = getWatchRuleById(id);
|
|
109164
109598
|
if (!rule) {
|
|
109165
|
-
return
|
|
109599
|
+
return json9({ error: t2("apiError.watchRuleNotFound") }, 404);
|
|
109166
109600
|
}
|
|
109167
109601
|
const state = getWatchRuleState(id);
|
|
109168
|
-
return
|
|
109602
|
+
return json9({
|
|
109169
109603
|
state: state ? toStateDto(state) : null,
|
|
109170
109604
|
samples: deps.service.getSamples(id)
|
|
109171
109605
|
});
|
|
@@ -109189,17 +109623,17 @@ function buildAssistPrompt(description, screen) {
|
|
|
109189
109623
|
async function handleAssistRegex(req, deps) {
|
|
109190
109624
|
const raw = await readJsonObjectBody3(req);
|
|
109191
109625
|
if (!raw) {
|
|
109192
|
-
return
|
|
109626
|
+
return json9({ error: t2("apiError.invalidRequest") }, 400);
|
|
109193
109627
|
}
|
|
109194
109628
|
const body = raw;
|
|
109195
109629
|
const description = typeof body.description === "string" ? body.description.trim() : "";
|
|
109196
109630
|
if (!description) {
|
|
109197
|
-
return
|
|
109631
|
+
return json9({ error: t2("apiError.watchAssistDescriptionRequired") }, 400);
|
|
109198
109632
|
}
|
|
109199
109633
|
let providerId = null;
|
|
109200
109634
|
if (body.providerId !== undefined && body.providerId !== null) {
|
|
109201
109635
|
if (typeof body.providerId !== "string" || !getLlmProviderById(body.providerId)) {
|
|
109202
|
-
return
|
|
109636
|
+
return json9({ error: t2("apiError.llmProviderNotFound") }, 400);
|
|
109203
109637
|
}
|
|
109204
109638
|
providerId = body.providerId;
|
|
109205
109639
|
}
|
|
@@ -109209,7 +109643,7 @@ async function handleAssistRegex(req, deps) {
|
|
|
109209
109643
|
const paneId = typeof body.paneId === "string" ? body.paneId.trim() : "";
|
|
109210
109644
|
if (deviceId && paneId) {
|
|
109211
109645
|
if (!getDeviceById(deviceId)) {
|
|
109212
|
-
return
|
|
109646
|
+
return json9({ error: t2("apiError.deviceNotFound") }, 404);
|
|
109213
109647
|
}
|
|
109214
109648
|
try {
|
|
109215
109649
|
screen = await deps.captureScreen(deviceId, paneId);
|
|
@@ -109230,14 +109664,14 @@ async function handleAssistRegex(req, deps) {
|
|
|
109230
109664
|
object3 = result.object;
|
|
109231
109665
|
} catch (error51) {
|
|
109232
109666
|
const detail = error51 instanceof Error ? error51.message : String(error51);
|
|
109233
|
-
return
|
|
109667
|
+
return json9({ error: t2("apiError.watchAssistModelUnavailable", { detail }) }, 502);
|
|
109234
109668
|
}
|
|
109235
109669
|
let regex;
|
|
109236
109670
|
try {
|
|
109237
109671
|
regex = compileWatchPattern(object3.pattern, object3.flags);
|
|
109238
109672
|
} catch (error51) {
|
|
109239
109673
|
const detail = error51 instanceof Error ? error51.message : String(error51);
|
|
109240
|
-
return
|
|
109674
|
+
return json9({ error: t2("apiError.watchPatternInvalid", { detail }) }, 502);
|
|
109241
109675
|
}
|
|
109242
109676
|
const preview = [];
|
|
109243
109677
|
if (screen) {
|
|
@@ -109251,7 +109685,7 @@ async function handleAssistRegex(req, deps) {
|
|
|
109251
109685
|
match = regex.exec(screen);
|
|
109252
109686
|
}
|
|
109253
109687
|
}
|
|
109254
|
-
return
|
|
109688
|
+
return json9({
|
|
109255
109689
|
pattern: object3.pattern,
|
|
109256
109690
|
flags: object3.flags,
|
|
109257
109691
|
extractGroup: object3.extractGroup >= 0 ? object3.extractGroup : 0,
|
|
@@ -109259,7 +109693,7 @@ async function handleAssistRegex(req, deps) {
|
|
|
109259
109693
|
preview
|
|
109260
109694
|
});
|
|
109261
109695
|
}
|
|
109262
|
-
function
|
|
109696
|
+
function json9(data, status = 200) {
|
|
109263
109697
|
return new Response(JSON.stringify(data), {
|
|
109264
109698
|
status,
|
|
109265
109699
|
headers: {
|
|
@@ -109404,6 +109838,12 @@ function handleApiRequest(req, _server) {
|
|
|
109404
109838
|
if (path === "/api/settings/terminal-shortcuts" && req.method === "PATCH") {
|
|
109405
109839
|
return handleUpdateTerminalShortcuts(req);
|
|
109406
109840
|
}
|
|
109841
|
+
if (path === "/api/settings/theme" && (req.method === "GET" || req.method === "POST")) {
|
|
109842
|
+
const themeResponse = handleThemeApiRequest(req, path);
|
|
109843
|
+
if (themeResponse) {
|
|
109844
|
+
return themeResponse;
|
|
109845
|
+
}
|
|
109846
|
+
}
|
|
109407
109847
|
if (path === "/api/settings/restart" && req.method === "POST") {
|
|
109408
109848
|
return handleRestartGateway();
|
|
109409
109849
|
}
|
|
@@ -109507,13 +109947,13 @@ function handleApiRequest(req, _server) {
|
|
|
109507
109947
|
return handleGetManifest(req.method);
|
|
109508
109948
|
}
|
|
109509
109949
|
if (path === "/healthz" && req.method === "GET") {
|
|
109510
|
-
return
|
|
109950
|
+
return json10({
|
|
109511
109951
|
status: "ok",
|
|
109512
109952
|
restarting: runtimeController.isRestarting(),
|
|
109513
109953
|
env: "development"
|
|
109514
109954
|
});
|
|
109515
109955
|
}
|
|
109516
|
-
return
|
|
109956
|
+
return json10({ error: t2("apiError.notFound") }, 404);
|
|
109517
109957
|
}
|
|
109518
109958
|
function enrichDeviceWithRuntime(device) {
|
|
109519
109959
|
const status = getDeviceRuntimeStatus(device.id);
|
|
@@ -109527,22 +109967,22 @@ function enrichDeviceWithRuntime(device) {
|
|
|
109527
109967
|
}
|
|
109528
109968
|
async function handleGetDevices() {
|
|
109529
109969
|
const devices2 = getAllDevices().map(enrichDeviceWithRuntime);
|
|
109530
|
-
return
|
|
109970
|
+
return json10({ devices: devices2 });
|
|
109531
109971
|
}
|
|
109532
109972
|
async function handleGetDevice(id) {
|
|
109533
109973
|
const device = getDeviceById(id);
|
|
109534
109974
|
if (!device) {
|
|
109535
|
-
return
|
|
109975
|
+
return json10({ error: t2("apiError.deviceNotFound") }, 404);
|
|
109536
109976
|
}
|
|
109537
|
-
return
|
|
109977
|
+
return json10({ device: enrichDeviceWithRuntime(device) });
|
|
109538
109978
|
}
|
|
109539
109979
|
async function handleCreateDevice(req) {
|
|
109540
109980
|
const body = await req.json();
|
|
109541
109981
|
if (!body.name || !body.type || !body.authMode) {
|
|
109542
|
-
return
|
|
109982
|
+
return json10({ error: t2("apiError.missingFields") }, 400);
|
|
109543
109983
|
}
|
|
109544
109984
|
if (body.type === "ssh" && !body.host && !body.sshConfigRef) {
|
|
109545
|
-
return
|
|
109985
|
+
return json10({ error: t2("apiError.sshRequiresHost") }, 400);
|
|
109546
109986
|
}
|
|
109547
109987
|
const now2 = new Date().toISOString();
|
|
109548
109988
|
const device = {
|
|
@@ -109565,12 +110005,12 @@ async function handleCreateDevice(req) {
|
|
|
109565
110005
|
};
|
|
109566
110006
|
createDevice(device);
|
|
109567
110007
|
await pushSupervisor.upsert(device.id);
|
|
109568
|
-
return
|
|
110008
|
+
return json10({ device: getDeviceById(device.id) ?? device }, 201);
|
|
109569
110009
|
}
|
|
109570
110010
|
async function handleUpdateDevice(req, id) {
|
|
109571
110011
|
const existing = getDeviceById(id);
|
|
109572
110012
|
if (!existing) {
|
|
109573
|
-
return
|
|
110013
|
+
return json10({ error: t2("apiError.deviceNotFound") }, 404);
|
|
109574
110014
|
}
|
|
109575
110015
|
const body = await req.json();
|
|
109576
110016
|
const updates = {};
|
|
@@ -109604,74 +110044,74 @@ async function handleUpdateDevice(req, id) {
|
|
|
109604
110044
|
pushSupervisor.updateDefaultWorkingDir(id, updates.defaultWorkingDir);
|
|
109605
110045
|
}
|
|
109606
110046
|
const device = getDeviceById(id);
|
|
109607
|
-
return
|
|
110047
|
+
return json10({ device });
|
|
109608
110048
|
}
|
|
109609
110049
|
async function handleReorderDevices(req) {
|
|
109610
110050
|
const body = await req.json();
|
|
109611
110051
|
if (!Array.isArray(body.deviceIds) || body.deviceIds.some((id) => typeof id !== "string")) {
|
|
109612
|
-
return
|
|
110052
|
+
return json10({ error: t2("apiError.invalidRequest") }, 400);
|
|
109613
110053
|
}
|
|
109614
110054
|
reorderDevices(body.deviceIds);
|
|
109615
|
-
return
|
|
110055
|
+
return json10({ devices: getAllDevices().map(enrichDeviceWithRuntime) });
|
|
109616
110056
|
}
|
|
109617
110057
|
async function handleDeleteDevice(id) {
|
|
109618
110058
|
const existing = getDeviceById(id);
|
|
109619
110059
|
if (!existing) {
|
|
109620
|
-
return
|
|
110060
|
+
return json10({ error: t2("apiError.deviceNotFound") }, 404);
|
|
109621
110061
|
}
|
|
109622
110062
|
deleteDevice(id);
|
|
109623
110063
|
pushSupervisor.remove(id);
|
|
109624
|
-
return
|
|
110064
|
+
return json10({ success: true });
|
|
109625
110065
|
}
|
|
109626
110066
|
async function handleTestConnection(id) {
|
|
109627
110067
|
return handleDeviceTestConnection(id);
|
|
109628
110068
|
}
|
|
109629
110069
|
async function handleGetSiteSettings() {
|
|
109630
|
-
return
|
|
110070
|
+
return json10({ settings: getSiteSettings() });
|
|
109631
110071
|
}
|
|
109632
110072
|
async function handleUpdateSiteSettings(req) {
|
|
109633
110073
|
try {
|
|
109634
110074
|
const body = await req.json();
|
|
109635
110075
|
const updates = normalizeSiteSettingsInput(body);
|
|
109636
110076
|
const settings = updateSiteSettings(updates);
|
|
109637
|
-
return
|
|
110077
|
+
return json10({ settings });
|
|
109638
110078
|
} catch (err) {
|
|
109639
|
-
return
|
|
110079
|
+
return json10({ error: err instanceof Error ? err.message : t2("apiError.invalidRequest") }, 400);
|
|
109640
110080
|
}
|
|
109641
110081
|
}
|
|
109642
110082
|
async function handleGetTerminalShortcuts() {
|
|
109643
|
-
return
|
|
110083
|
+
return json10({ settings: getTerminalShortcutSettings() });
|
|
109644
110084
|
}
|
|
109645
110085
|
async function handleUpdateTerminalShortcuts(req) {
|
|
109646
110086
|
try {
|
|
109647
110087
|
const body = await req.json();
|
|
109648
110088
|
const updates = normalizeTerminalShortcutsInput(body);
|
|
109649
110089
|
const settings = updateTerminalShortcutSettings(updates);
|
|
109650
|
-
return
|
|
110090
|
+
return json10({ settings });
|
|
109651
110091
|
} catch (err) {
|
|
109652
|
-
return
|
|
110092
|
+
return json10({ error: err instanceof Error ? err.message : t2("apiError.invalidRequest") }, 400);
|
|
109653
110093
|
}
|
|
109654
110094
|
}
|
|
109655
110095
|
async function handleRestartGateway() {
|
|
109656
110096
|
setTimeout(() => {
|
|
109657
110097
|
runtimeController.requestRestart();
|
|
109658
110098
|
}, 50);
|
|
109659
|
-
return
|
|
110099
|
+
return json10({
|
|
109660
110100
|
success: true,
|
|
109661
110101
|
message: t2("settings.restartScheduled")
|
|
109662
110102
|
});
|
|
109663
110103
|
}
|
|
109664
110104
|
async function handleGetTelegramBots() {
|
|
109665
110105
|
const bots = getTelegramBotsWithStats();
|
|
109666
|
-
return
|
|
110106
|
+
return json10({ bots });
|
|
109667
110107
|
}
|
|
109668
110108
|
async function handleCreateTelegramBot(req) {
|
|
109669
110109
|
const body = await req.json();
|
|
109670
110110
|
if (!body.name?.trim()) {
|
|
109671
|
-
return
|
|
110111
|
+
return json10({ error: t2("apiError.botNameRequired") }, 400);
|
|
109672
110112
|
}
|
|
109673
110113
|
if (!body.token?.trim()) {
|
|
109674
|
-
return
|
|
110114
|
+
return json10({ error: t2("apiError.botTokenRequired") }, 400);
|
|
109675
110115
|
}
|
|
109676
110116
|
const now2 = new Date().toISOString();
|
|
109677
110117
|
createTelegramBot({
|
|
@@ -109685,26 +110125,26 @@ async function handleCreateTelegramBot(req) {
|
|
|
109685
110125
|
updatedAt: now2
|
|
109686
110126
|
});
|
|
109687
110127
|
await telegramService.refresh();
|
|
109688
|
-
return
|
|
110128
|
+
return json10({ success: true }, 201);
|
|
109689
110129
|
}
|
|
109690
110130
|
async function handleUpdateTelegramBot(req, botId) {
|
|
109691
110131
|
const existing = getTelegramBotById(botId);
|
|
109692
110132
|
if (!existing) {
|
|
109693
|
-
return
|
|
110133
|
+
return json10({ error: t2("apiError.botNotFound") }, 404);
|
|
109694
110134
|
}
|
|
109695
110135
|
const body = await req.json();
|
|
109696
110136
|
const updates = {};
|
|
109697
110137
|
if (body.name !== undefined) {
|
|
109698
110138
|
const value = body.name.trim();
|
|
109699
110139
|
if (!value) {
|
|
109700
|
-
return
|
|
110140
|
+
return json10({ error: t2("apiError.botNameRequired") }, 400);
|
|
109701
110141
|
}
|
|
109702
110142
|
updates.name = value;
|
|
109703
110143
|
}
|
|
109704
110144
|
if (body.token !== undefined) {
|
|
109705
110145
|
const token = body.token.trim();
|
|
109706
110146
|
if (!token) {
|
|
109707
|
-
return
|
|
110147
|
+
return json10({ error: t2("apiError.botTokenRequired") }, 400);
|
|
109708
110148
|
}
|
|
109709
110149
|
updates.tokenEnc = await encrypt(token);
|
|
109710
110150
|
}
|
|
@@ -109716,69 +110156,69 @@ async function handleUpdateTelegramBot(req, botId) {
|
|
|
109716
110156
|
}
|
|
109717
110157
|
updateTelegramBot(botId, updates);
|
|
109718
110158
|
await telegramService.refresh();
|
|
109719
|
-
return
|
|
110159
|
+
return json10({ success: true });
|
|
109720
110160
|
}
|
|
109721
110161
|
async function handleDeleteTelegramBot(botId) {
|
|
109722
110162
|
const existing = getTelegramBotById(botId);
|
|
109723
110163
|
if (!existing) {
|
|
109724
|
-
return
|
|
110164
|
+
return json10({ error: t2("apiError.botNotFound") }, 404);
|
|
109725
110165
|
}
|
|
109726
110166
|
deleteTelegramBot(botId);
|
|
109727
110167
|
await telegramService.refresh();
|
|
109728
|
-
return
|
|
110168
|
+
return json10({ success: true });
|
|
109729
110169
|
}
|
|
109730
110170
|
async function handleListTelegramChats(botId) {
|
|
109731
110171
|
const existing = getTelegramBotById(botId);
|
|
109732
110172
|
if (!existing) {
|
|
109733
|
-
return
|
|
110173
|
+
return json10({ error: t2("apiError.botNotFound") }, 404);
|
|
109734
110174
|
}
|
|
109735
110175
|
const chats = listTelegramChatsByBot(botId);
|
|
109736
|
-
return
|
|
110176
|
+
return json10({ chats });
|
|
109737
110177
|
}
|
|
109738
110178
|
async function handleApproveTelegramChat(botId, chatId) {
|
|
109739
110179
|
const existing = getTelegramBotById(botId);
|
|
109740
110180
|
if (!existing) {
|
|
109741
|
-
return
|
|
110181
|
+
return json10({ error: t2("apiError.botNotFound") }, 404);
|
|
109742
110182
|
}
|
|
109743
110183
|
const chat = approveTelegramChat(botId, chatId);
|
|
109744
110184
|
if (!chat) {
|
|
109745
|
-
return
|
|
110185
|
+
return json10({ error: t2("apiError.chatNotFound") }, 404);
|
|
109746
110186
|
}
|
|
109747
110187
|
const settings = getSiteSettings();
|
|
109748
110188
|
await telegramService.sendTestMessage(botId, chatId, t2("telegram.approveMessageTemplate", {
|
|
109749
110189
|
botName: existing.name,
|
|
109750
110190
|
time: new Date().toLocaleString(toBCP47(settings.language))
|
|
109751
110191
|
}));
|
|
109752
|
-
return
|
|
110192
|
+
return json10({ chat });
|
|
109753
110193
|
}
|
|
109754
110194
|
async function handleDeleteTelegramChat(botId, chatId) {
|
|
109755
110195
|
const existing = getTelegramBotById(botId);
|
|
109756
110196
|
if (!existing) {
|
|
109757
|
-
return
|
|
110197
|
+
return json10({ error: t2("apiError.botNotFound") }, 404);
|
|
109758
110198
|
}
|
|
109759
110199
|
deleteTelegramChat(botId, chatId);
|
|
109760
|
-
return
|
|
110200
|
+
return json10({ success: true });
|
|
109761
110201
|
}
|
|
109762
110202
|
async function handleTestTelegramChat(botId, chatId) {
|
|
109763
110203
|
const bot = getTelegramBotById(botId);
|
|
109764
110204
|
if (!bot) {
|
|
109765
|
-
return
|
|
110205
|
+
return json10({ error: t2("apiError.botNotFound") }, 404);
|
|
109766
110206
|
}
|
|
109767
110207
|
const settings = getSiteSettings();
|
|
109768
110208
|
await telegramService.sendTestMessage(botId, chatId, t2("telegram.testMessageTemplate", {
|
|
109769
110209
|
siteName: settings.siteName,
|
|
109770
110210
|
time: new Date().toLocaleString(toBCP47(settings.language))
|
|
109771
110211
|
}));
|
|
109772
|
-
return
|
|
110212
|
+
return json10({ success: true });
|
|
109773
110213
|
}
|
|
109774
110214
|
async function handleGetWeixinAccounts() {
|
|
109775
110215
|
const accounts = getWeixinAccountsWithStats();
|
|
109776
|
-
return
|
|
110216
|
+
return json10({ accounts });
|
|
109777
110217
|
}
|
|
109778
110218
|
async function handleCreateWeixinAccount(req) {
|
|
109779
110219
|
const body = await req.json();
|
|
109780
110220
|
if (!body.name?.trim()) {
|
|
109781
|
-
return
|
|
110221
|
+
return json10({ error: t2("weixin.accountNameRequired") }, 400);
|
|
109782
110222
|
}
|
|
109783
110223
|
const now2 = new Date().toISOString();
|
|
109784
110224
|
const id = v4_default();
|
|
@@ -109795,19 +110235,19 @@ async function handleCreateWeixinAccount(req) {
|
|
|
109795
110235
|
createdAt: now2,
|
|
109796
110236
|
updatedAt: now2
|
|
109797
110237
|
});
|
|
109798
|
-
return
|
|
110238
|
+
return json10({ success: true, accountId: id }, 201);
|
|
109799
110239
|
}
|
|
109800
110240
|
async function handleUpdateWeixinAccount(req, accountId) {
|
|
109801
110241
|
const existing = getWeixinAccountById(accountId);
|
|
109802
110242
|
if (!existing) {
|
|
109803
|
-
return
|
|
110243
|
+
return json10({ error: t2("weixin.accountNotFound") }, 404);
|
|
109804
110244
|
}
|
|
109805
110245
|
const body = await req.json();
|
|
109806
110246
|
const updates = {};
|
|
109807
110247
|
if (body.name !== undefined) {
|
|
109808
110248
|
const value = body.name.trim();
|
|
109809
110249
|
if (!value) {
|
|
109810
|
-
return
|
|
110250
|
+
return json10({ error: t2("weixin.accountNameRequired") }, 400);
|
|
109811
110251
|
}
|
|
109812
110252
|
updates.name = value;
|
|
109813
110253
|
}
|
|
@@ -109819,52 +110259,52 @@ async function handleUpdateWeixinAccount(req, accountId) {
|
|
|
109819
110259
|
}
|
|
109820
110260
|
updateWeixinAccount(accountId, updates);
|
|
109821
110261
|
await weixinService.refresh();
|
|
109822
|
-
return
|
|
110262
|
+
return json10({ success: true });
|
|
109823
110263
|
}
|
|
109824
110264
|
async function handleDeleteWeixinAccount(accountId) {
|
|
109825
110265
|
const existing = getWeixinAccountById(accountId);
|
|
109826
110266
|
if (!existing) {
|
|
109827
|
-
return
|
|
110267
|
+
return json10({ error: t2("weixin.accountNotFound") }, 404);
|
|
109828
110268
|
}
|
|
109829
110269
|
deleteWeixinAccount(accountId);
|
|
109830
110270
|
await weixinService.refresh();
|
|
109831
|
-
return
|
|
110271
|
+
return json10({ success: true });
|
|
109832
110272
|
}
|
|
109833
110273
|
async function handleStartWeixinLogin(accountId) {
|
|
109834
110274
|
const existing = getWeixinAccountById(accountId);
|
|
109835
110275
|
if (!existing) {
|
|
109836
|
-
return
|
|
110276
|
+
return json10({ error: t2("weixin.accountNotFound") }, 404);
|
|
109837
110277
|
}
|
|
109838
110278
|
try {
|
|
109839
110279
|
const result = await weixinService.startLogin(accountId);
|
|
109840
|
-
return
|
|
110280
|
+
return json10(result);
|
|
109841
110281
|
} catch (err) {
|
|
109842
|
-
return
|
|
110282
|
+
return json10({ error: err instanceof Error ? err.message : t2("weixin.loginFailed") }, 502);
|
|
109843
110283
|
}
|
|
109844
110284
|
}
|
|
109845
110285
|
async function handleGetWeixinLoginStatus(accountId) {
|
|
109846
110286
|
const existing = getWeixinAccountById(accountId);
|
|
109847
110287
|
if (!existing) {
|
|
109848
|
-
return
|
|
110288
|
+
return json10({ error: t2("weixin.accountNotFound") }, 404);
|
|
109849
110289
|
}
|
|
109850
|
-
return
|
|
110290
|
+
return json10(weixinService.getLoginStatus(accountId));
|
|
109851
110291
|
}
|
|
109852
110292
|
async function handleListWeixinUsers(accountId) {
|
|
109853
110293
|
const existing = getWeixinAccountById(accountId);
|
|
109854
110294
|
if (!existing) {
|
|
109855
|
-
return
|
|
110295
|
+
return json10({ error: t2("weixin.accountNotFound") }, 404);
|
|
109856
110296
|
}
|
|
109857
110297
|
const users = listWeixinUsersByAccount(accountId);
|
|
109858
|
-
return
|
|
110298
|
+
return json10({ users });
|
|
109859
110299
|
}
|
|
109860
110300
|
async function handleApproveWeixinUser(accountId, userId) {
|
|
109861
110301
|
const existing = getWeixinAccountById(accountId);
|
|
109862
110302
|
if (!existing) {
|
|
109863
|
-
return
|
|
110303
|
+
return json10({ error: t2("weixin.accountNotFound") }, 404);
|
|
109864
110304
|
}
|
|
109865
110305
|
const user = approveWeixinUser(accountId, userId);
|
|
109866
110306
|
if (!user) {
|
|
109867
|
-
return
|
|
110307
|
+
return json10({ error: t2("weixin.userNotFound") }, 404);
|
|
109868
110308
|
}
|
|
109869
110309
|
const settings = getSiteSettings();
|
|
109870
110310
|
try {
|
|
@@ -109875,12 +110315,12 @@ async function handleApproveWeixinUser(accountId, userId) {
|
|
|
109875
110315
|
} catch (err) {
|
|
109876
110316
|
console.error("[weixin] approve ack failed:", err);
|
|
109877
110317
|
}
|
|
109878
|
-
return
|
|
110318
|
+
return json10({ user });
|
|
109879
110319
|
}
|
|
109880
110320
|
async function handleTestWeixinUser(accountId, userId) {
|
|
109881
110321
|
const existing = getWeixinAccountById(accountId);
|
|
109882
110322
|
if (!existing) {
|
|
109883
|
-
return
|
|
110323
|
+
return json10({ error: t2("weixin.accountNotFound") }, 404);
|
|
109884
110324
|
}
|
|
109885
110325
|
const settings = getSiteSettings();
|
|
109886
110326
|
try {
|
|
@@ -109889,14 +110329,14 @@ async function handleTestWeixinUser(accountId, userId) {
|
|
|
109889
110329
|
time: new Date().toLocaleString(toBCP47(settings.language))
|
|
109890
110330
|
}));
|
|
109891
110331
|
} catch (err) {
|
|
109892
|
-
return
|
|
110332
|
+
return json10({ error: err instanceof Error ? err.message : t2("weixin.testMessageFailed") }, 400);
|
|
109893
110333
|
}
|
|
109894
|
-
return
|
|
110334
|
+
return json10({ success: true });
|
|
109895
110335
|
}
|
|
109896
110336
|
async function handleTestWeixinAccount(accountId) {
|
|
109897
110337
|
const existing = getWeixinAccountById(accountId);
|
|
109898
110338
|
if (!existing) {
|
|
109899
|
-
return
|
|
110339
|
+
return json10({ error: t2("weixin.accountNotFound") }, 404);
|
|
109900
110340
|
}
|
|
109901
110341
|
const settings = getSiteSettings();
|
|
109902
110342
|
try {
|
|
@@ -109905,26 +110345,26 @@ async function handleTestWeixinAccount(accountId) {
|
|
|
109905
110345
|
time: new Date().toLocaleString(toBCP47(settings.language))
|
|
109906
110346
|
}));
|
|
109907
110347
|
} catch (err) {
|
|
109908
|
-
return
|
|
110348
|
+
return json10({ error: err instanceof Error ? err.message : t2("weixin.testMessageFailed") }, 400);
|
|
109909
110349
|
}
|
|
109910
|
-
return
|
|
110350
|
+
return json10({ success: true });
|
|
109911
110351
|
}
|
|
109912
110352
|
async function handleDeleteWeixinUser(accountId, userId) {
|
|
109913
110353
|
const existing = getWeixinAccountById(accountId);
|
|
109914
110354
|
if (!existing) {
|
|
109915
|
-
return
|
|
110355
|
+
return json10({ error: t2("weixin.accountNotFound") }, 404);
|
|
109916
110356
|
}
|
|
109917
110357
|
deleteWeixinUser(accountId, userId);
|
|
109918
|
-
return
|
|
110358
|
+
return json10({ success: true });
|
|
109919
110359
|
}
|
|
109920
110360
|
async function handleGetWebhooks() {
|
|
109921
110361
|
const webhooks = getAllWebhookEndpoints();
|
|
109922
|
-
return
|
|
110362
|
+
return json10({ webhooks });
|
|
109923
110363
|
}
|
|
109924
110364
|
async function handleCreateWebhook(req) {
|
|
109925
110365
|
const body = await req.json();
|
|
109926
110366
|
if (!body.url || !body.secret) {
|
|
109927
|
-
return
|
|
110367
|
+
return json10({ error: t2("apiError.urlAndSecretRequired") }, 400);
|
|
109928
110368
|
}
|
|
109929
110369
|
const now2 = new Date().toISOString();
|
|
109930
110370
|
const endpoint = {
|
|
@@ -109937,11 +110377,11 @@ async function handleCreateWebhook(req) {
|
|
|
109937
110377
|
updatedAt: now2
|
|
109938
110378
|
};
|
|
109939
110379
|
createWebhookEndpoint(endpoint);
|
|
109940
|
-
return
|
|
110380
|
+
return json10({ webhook: endpoint }, 201);
|
|
109941
110381
|
}
|
|
109942
110382
|
async function handleDeleteWebhook(id) {
|
|
109943
110383
|
deleteWebhookEndpoint(id);
|
|
109944
|
-
return
|
|
110384
|
+
return json10({ success: true });
|
|
109945
110385
|
}
|
|
109946
110386
|
async function handleGetManifest(method) {
|
|
109947
110387
|
const settings = getSiteSettings();
|
|
@@ -109980,7 +110420,7 @@ function manifestJson(data, method) {
|
|
|
109980
110420
|
}
|
|
109981
110421
|
});
|
|
109982
110422
|
}
|
|
109983
|
-
function
|
|
110423
|
+
function json10(data, status = 200, headers = {}) {
|
|
109984
110424
|
return new Response(JSON.stringify(data), {
|
|
109985
110425
|
status,
|
|
109986
110426
|
headers: {
|
|
@@ -110693,12 +111133,27 @@ var defaultDeps5 = {
|
|
|
110693
111133
|
await tmuxRuntimeRegistry.release(deviceId, runtime);
|
|
110694
111134
|
}
|
|
110695
111135
|
};
|
|
111136
|
+
function parseWindowLayoutSize(layout) {
|
|
111137
|
+
if (!layout)
|
|
111138
|
+
return null;
|
|
111139
|
+
const match = /^[0-9a-fA-F]{4},(\d+)x(\d+)/.exec(layout);
|
|
111140
|
+
if (!match)
|
|
111141
|
+
return null;
|
|
111142
|
+
return { cols: Number(match[1]), rows: Number(match[2]) };
|
|
111143
|
+
}
|
|
110696
111144
|
|
|
110697
111145
|
class WebSocketServer {
|
|
110698
111146
|
connections = new Map;
|
|
110699
111147
|
pendingConnectionEntries = new Map;
|
|
111148
|
+
connectedClients = new Set;
|
|
110700
111149
|
windowCustomNames = new Map;
|
|
110701
111150
|
paneCustomNames = new Map;
|
|
111151
|
+
currentTheme = null;
|
|
111152
|
+
themeSignalLast = new Map;
|
|
111153
|
+
lastThemeTimestamp = 0n;
|
|
111154
|
+
pendingTmuxTheme = null;
|
|
111155
|
+
themeApplyInFlight = false;
|
|
111156
|
+
lastBroadcastTheme = new Map;
|
|
110702
111157
|
deps;
|
|
110703
111158
|
constructor(options = {}) {
|
|
110704
111159
|
this.deps = {
|
|
@@ -110730,6 +111185,8 @@ class WebSocketServer {
|
|
|
110730
111185
|
this.clearReconnectTimer(entry);
|
|
110731
111186
|
entry.detachRuntime?.();
|
|
110732
111187
|
entry.detachRuntime = null;
|
|
111188
|
+
this.themeSignalLast.delete(deviceId);
|
|
111189
|
+
this.lastBroadcastTheme.delete(deviceId);
|
|
110733
111190
|
this.deps.releaseRuntime(deviceId, entry.runtime);
|
|
110734
111191
|
}
|
|
110735
111192
|
attachRuntime(deviceId, runtime) {
|
|
@@ -110814,6 +111271,7 @@ class WebSocketServer {
|
|
|
110814
111271
|
handleOpen(ws) {
|
|
110815
111272
|
console.log("[ws] client connected");
|
|
110816
111273
|
sessionStateStore.create(ws);
|
|
111274
|
+
this.connectedClients.add(ws);
|
|
110817
111275
|
}
|
|
110818
111276
|
handleMessage(ws, message) {
|
|
110819
111277
|
if (typeof message === "string") {
|
|
@@ -110852,6 +111310,7 @@ class WebSocketServer {
|
|
|
110852
111310
|
}
|
|
110853
111311
|
handleClose(ws) {
|
|
110854
111312
|
console.log("[ws] client disconnected");
|
|
111313
|
+
this.connectedClients.delete(ws);
|
|
110855
111314
|
switchBarrier.cleanupClient(ws);
|
|
110856
111315
|
sessionStateStore.cleanup(ws);
|
|
110857
111316
|
agentWsHub.removeClient(ws);
|
|
@@ -111038,6 +111497,11 @@ class WebSocketServer {
|
|
|
111038
111497
|
agentWsHub.unsubscribe(ws, decoded.sessionId);
|
|
111039
111498
|
return;
|
|
111040
111499
|
}
|
|
111500
|
+
case exports_ws_borsh.KIND_SITE_THEME_UPDATE: {
|
|
111501
|
+
const decoded = exports_ws_borsh.decodePayload(exports_ws_borsh.schema.SiteThemeUpdateC2SSchema, payload);
|
|
111502
|
+
this.handleSiteThemeUpdate(ws, decoded);
|
|
111503
|
+
return;
|
|
111504
|
+
}
|
|
111041
111505
|
default:
|
|
111042
111506
|
this.sendError(ws, refSeq, exports_ws_borsh.ERROR_UNKNOWN_KIND, `Unknown kind: ${kind}`, false);
|
|
111043
111507
|
}
|
|
@@ -111258,13 +111722,18 @@ class WebSocketServer {
|
|
|
111258
111722
|
const entry = this.connections.get(deviceId);
|
|
111259
111723
|
if (!entry)
|
|
111260
111724
|
return;
|
|
111261
|
-
const
|
|
111262
|
-
if (
|
|
111263
|
-
const
|
|
111264
|
-
if (
|
|
111265
|
-
entry.runtime.resizeWindow(window2.id, cols, rows);
|
|
111725
|
+
const window2 = entry.lastSnapshot?.session?.windows?.find((w) => w.panes?.some((p) => p.id === paneId));
|
|
111726
|
+
if (window2?.panes && window2.panes.length > 1) {
|
|
111727
|
+
const currentSize = parseWindowLayoutSize(window2.layout);
|
|
111728
|
+
if (currentSize && currentSize.cols === cols && currentSize.rows === rows) {
|
|
111266
111729
|
return;
|
|
111267
111730
|
}
|
|
111731
|
+
entry.runtime.resizeWindow(window2.id, cols, rows);
|
|
111732
|
+
return;
|
|
111733
|
+
}
|
|
111734
|
+
const pane = window2?.panes.find((p) => p.id === paneId);
|
|
111735
|
+
if (pane && pane.width === cols && pane.height === rows) {
|
|
111736
|
+
return;
|
|
111268
111737
|
}
|
|
111269
111738
|
entry.runtime.resizePane(paneId, cols, rows);
|
|
111270
111739
|
}
|
|
@@ -111355,7 +111824,111 @@ class WebSocketServer {
|
|
|
111355
111824
|
const entry = this.connections.get(deviceId);
|
|
111356
111825
|
if (!entry)
|
|
111357
111826
|
return;
|
|
111358
|
-
|
|
111827
|
+
(async () => {
|
|
111828
|
+
try {
|
|
111829
|
+
await entry.runtime.setWindowStyle(style);
|
|
111830
|
+
} catch (err) {
|
|
111831
|
+
console.error("[ws] setWindowStyle failed:", err);
|
|
111832
|
+
}
|
|
111833
|
+
if (this.currentTheme !== null) {
|
|
111834
|
+
const theme = this.currentTheme;
|
|
111835
|
+
if (this.lastBroadcastTheme.get(deviceId) !== theme) {
|
|
111836
|
+
this.lastBroadcastTheme.set(deviceId, theme);
|
|
111837
|
+
this.broadcastThemeChange(theme);
|
|
111838
|
+
}
|
|
111839
|
+
}
|
|
111840
|
+
})();
|
|
111841
|
+
}
|
|
111842
|
+
handleSiteThemeUpdate(ws, decoded) {
|
|
111843
|
+
if (decoded.theme !== exports_ws_borsh.SITE_THEME_DARK && decoded.theme !== exports_ws_borsh.SITE_THEME_LIGHT) {
|
|
111844
|
+
this.sendError(ws, null, exports_ws_borsh.ERROR_PAYLOAD_DECODE_FAILED, `invalid theme value: ${decoded.theme}`, false);
|
|
111845
|
+
return;
|
|
111846
|
+
}
|
|
111847
|
+
const themeName = decoded.theme === exports_ws_borsh.SITE_THEME_LIGHT ? "light" : "dark";
|
|
111848
|
+
updateSiteSettings({ theme: themeName });
|
|
111849
|
+
this.scheduleTmuxThemeApply(themeName);
|
|
111850
|
+
this.broadcastSiteThemeUpdateS2C(themeName);
|
|
111851
|
+
}
|
|
111852
|
+
scheduleTmuxThemeApply(theme) {
|
|
111853
|
+
this.pendingTmuxTheme = theme;
|
|
111854
|
+
if (this.themeApplyInFlight) {
|
|
111855
|
+
return;
|
|
111856
|
+
}
|
|
111857
|
+
this.themeApplyInFlight = true;
|
|
111858
|
+
(async () => {
|
|
111859
|
+
try {
|
|
111860
|
+
while (this.pendingTmuxTheme !== null) {
|
|
111861
|
+
const next = this.pendingTmuxTheme;
|
|
111862
|
+
this.pendingTmuxTheme = null;
|
|
111863
|
+
await this.handleSiteThemeChange(next);
|
|
111864
|
+
this.broadcastThemeChange(next);
|
|
111865
|
+
}
|
|
111866
|
+
} finally {
|
|
111867
|
+
this.themeApplyInFlight = false;
|
|
111868
|
+
}
|
|
111869
|
+
})();
|
|
111870
|
+
}
|
|
111871
|
+
broadcastSiteThemeUpdateS2C(theme) {
|
|
111872
|
+
const now2 = BigInt(Date.now());
|
|
111873
|
+
if (now2 <= this.lastThemeTimestamp) {
|
|
111874
|
+
this.lastThemeTimestamp += 1n;
|
|
111875
|
+
} else {
|
|
111876
|
+
this.lastThemeTimestamp = now2;
|
|
111877
|
+
}
|
|
111878
|
+
const effectiveTimestamp = this.lastThemeTimestamp;
|
|
111879
|
+
const themeCode = theme === "light" ? exports_ws_borsh.SITE_THEME_LIGHT : exports_ws_borsh.SITE_THEME_DARK;
|
|
111880
|
+
const payloadBytes = exports_ws_borsh.encodePayload(exports_ws_borsh.schema.SiteThemeUpdateS2CSchema, {
|
|
111881
|
+
theme: themeCode,
|
|
111882
|
+
serverTimestamp: effectiveTimestamp
|
|
111883
|
+
});
|
|
111884
|
+
for (const client of this.connectedClients) {
|
|
111885
|
+
this.sendEnvelope(client, exports_ws_borsh.KIND_SITE_THEME_UPDATE, payloadBytes);
|
|
111886
|
+
}
|
|
111887
|
+
}
|
|
111888
|
+
async handleSiteThemeChange(theme) {
|
|
111889
|
+
if (theme !== "dark" && theme !== "light") {
|
|
111890
|
+
return;
|
|
111891
|
+
}
|
|
111892
|
+
this.currentTheme = theme;
|
|
111893
|
+
const style = getTmuxWindowStyle(theme);
|
|
111894
|
+
const results = await Promise.allSettled([...this.connections.values()].map((entry) => entry.runtime.setWindowStyle(style)));
|
|
111895
|
+
for (const result of results) {
|
|
111896
|
+
if (result.status === "rejected") {
|
|
111897
|
+
console.error("[ws] setWindowStyle on theme change failed:", result.reason);
|
|
111898
|
+
}
|
|
111899
|
+
}
|
|
111900
|
+
}
|
|
111901
|
+
applyThemeToDevice(deviceId) {
|
|
111902
|
+
if (this.currentTheme === null) {
|
|
111903
|
+
return;
|
|
111904
|
+
}
|
|
111905
|
+
const entry = this.connections.get(deviceId);
|
|
111906
|
+
if (!entry) {
|
|
111907
|
+
return;
|
|
111908
|
+
}
|
|
111909
|
+
const style = getTmuxWindowStyle(this.currentTheme);
|
|
111910
|
+
entry.runtime.setWindowStyle(style).catch((err) => {
|
|
111911
|
+
console.error(`[ws] setWindowStyle on device ${deviceId} failed:`, err);
|
|
111912
|
+
});
|
|
111913
|
+
}
|
|
111914
|
+
broadcastThemeChange(theme) {
|
|
111915
|
+
const now2 = Date.now();
|
|
111916
|
+
for (const [deviceId, entry] of this.connections) {
|
|
111917
|
+
const last = this.themeSignalLast.get(deviceId);
|
|
111918
|
+
if (last && last.theme === theme && now2 - last.at < 1000) {
|
|
111919
|
+
continue;
|
|
111920
|
+
}
|
|
111921
|
+
this.themeSignalLast.set(deviceId, { theme, at: now2 });
|
|
111922
|
+
this.lastBroadcastTheme.set(deviceId, theme);
|
|
111923
|
+
const panes = entry.lastSnapshot?.session?.windows?.flatMap((w) => w.panes) ?? [];
|
|
111924
|
+
for (const pane of panes) {
|
|
111925
|
+
try {
|
|
111926
|
+
entry.runtime.signalThemeChange(pane.id, theme);
|
|
111927
|
+
} catch (err) {
|
|
111928
|
+
console.error(`[ws] signalThemeChange failed for ${deviceId}/${pane.id}:`, err);
|
|
111929
|
+
}
|
|
111930
|
+
}
|
|
111931
|
+
}
|
|
111359
111932
|
}
|
|
111360
111933
|
handleReorderWindows(deviceId, windowIds) {
|
|
111361
111934
|
setWindowOrder(deviceId, windowIds);
|
|
@@ -111499,6 +112072,9 @@ class WebSocketServer {
|
|
|
111499
112072
|
runtime = await this.deps.acquireRuntime(deviceId);
|
|
111500
112073
|
detachRuntime = this.attachRuntime(deviceId, runtime);
|
|
111501
112074
|
await runtime.connect();
|
|
112075
|
+
if (this.currentTheme !== null) {
|
|
112076
|
+
await runtime.setWindowStyle(getTmuxWindowStyle(this.currentTheme));
|
|
112077
|
+
}
|
|
111502
112078
|
return {
|
|
111503
112079
|
runtime,
|
|
111504
112080
|
detachRuntime,
|
|
@@ -111801,10 +112377,16 @@ async function createGatewayRuntime(options = {}) {
|
|
|
111801
112377
|
primeLocalShellPath();
|
|
111802
112378
|
sweepOrphanTransferTemps();
|
|
111803
112379
|
const wsServer = new WebSocketServer;
|
|
112380
|
+
wsServer.currentTheme = getSiteSettings().theme;
|
|
111804
112381
|
connectionAlertNotifier.setBroadcaster((deviceId, payload) => {
|
|
111805
112382
|
wsServer.broadcastDeviceError(deviceId, payload);
|
|
111806
112383
|
});
|
|
111807
112384
|
registerSnapshotLookup((deviceId) => wsServer.getLastSnapshot(deviceId));
|
|
112385
|
+
registerThemeBroadcaster((theme) => {
|
|
112386
|
+
wsServer.scheduleTmuxThemeApply(theme);
|
|
112387
|
+
}, (theme) => {
|
|
112388
|
+
wsServer.broadcastSiteThemeUpdateS2C(theme);
|
|
112389
|
+
});
|
|
111808
112390
|
await telegramService.refresh();
|
|
111809
112391
|
await weixinService.refresh();
|
|
111810
112392
|
await pushSupervisor.start();
|
|
@@ -111852,6 +112434,7 @@ async function createGatewayRuntime(options = {}) {
|
|
|
111852
112434
|
},
|
|
111853
112435
|
async stop() {
|
|
111854
112436
|
connectionAlertNotifier.setBroadcaster(null);
|
|
112437
|
+
registerThemeBroadcaster(null);
|
|
111855
112438
|
wsServer.closeAll();
|
|
111856
112439
|
await watchService.stop();
|
|
111857
112440
|
await agentSupervisor.stop();
|