tabby-tmux 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -0
- package/README.zh-CN.md +93 -0
- package/dist/index.js +4226 -0
- package/dist/index.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD,O;;;;;;;;;;;;;;;;;;ACVA;AACiK;AACjB;AAChJ,8BAA8B,sIAA2B,CAAC,+IAAqC;AAC/F;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,OAAO,yGAAyG,UAAU,UAAU,WAAW,KAAK,KAAK,UAAU,WAAW,KAAK,KAAK,UAAU,UAAU,WAAW,KAAK,KAAK,UAAU,WAAW,6CAA6C,iBAAiB,kBAAkB,qBAAqB,+BAA+B,YAAY,oBAAoB,2BAA2B,iBAAiB,qBAAqB,sBAAsB,8BAA8B,SAAS,uBAAuB,sBAAsB,8BAA8B,SAAS,OAAO,KAAK,GAAG,qBAAqB;AACjpB;AACA,iEAAe,uBAAuB,EAAC;;;;;;;;;;;;;;;;;;;;ACxBvC;AACiK;AACjB;AAChJ,8BAA8B,sIAA2B,CAAC,+IAAqC;AAC/F;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,CAAC,OAAO,mHAAmH,mBAAmB,KAAK,KAAK,UAAU,UAAU,UAAU,WAAW,MAAM,WAAW,KAAK,WAAW,MAAM,KAAK,WAAW,gmBAAgmB,8KAA8K,gBAAgB,mBAAmB,gBAAgB,6BAA6B,GAAG,2GAA2G,kCAAkC,GAAG,mCAAmC,oCAAoC,GAAG,qBAAqB;AACx0C;AACA,iEAAe,uBAAuB,EAAC;;;;;;;;;;;;ACrC1B;;AAEb;AACA;AACA;AACA;AACAA,MAAM,CAACC,OAAO,GAAG,UAAUC,sBAAsB,EAAE;EACjD,IAAIC,IAAI,GAAG,EAAE;;EAEb;EACAA,IAAI,CAACC,QAAQ,GAAG,SAASA,QAAQA,CAAA,EAAG;IAClC,OAAO,IAAI,CAACC,GAAG,CAAC,UAAUC,IAAI,EAAE;MAC9B,IAAIC,OAAO,GAAG,EAAE;MAChB,IAAIC,SAAS,GAAG,OAAOF,IAAI,CAAC,CAAC,CAAC,KAAK,WAAW;MAC9C,IAAIA,IAAI,CAAC,CAAC,CAAC,EAAE;QACXC,OAAO,IAAI,aAAa,CAACE,MAAM,CAACH,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;MACjD;MACA,IAAIA,IAAI,CAAC,CAAC,CAAC,EAAE;QACXC,OAAO,IAAI,SAAS,CAACE,MAAM,CAACH,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;MAC5C;MACA,IAAIE,SAAS,EAAE;QACbD,OAAO,IAAI,QAAQ,CAACE,MAAM,CAACH,IAAI,CAAC,CAAC,CAAC,CAACI,MAAM,GAAG,CAAC,GAAG,GAAG,CAACD,MAAM,CAACH,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC;MACjF;MACAC,OAAO,IAAIL,sBAAsB,CAACI,IAAI,CAAC;MACvC,IAAIE,SAAS,EAAE;QACbD,OAAO,IAAI,GAAG;MAChB;MACA,IAAID,IAAI,CAAC,CAAC,CAAC,EAAE;QACXC,OAAO,IAAI,GAAG;MAChB;MACA,IAAID,IAAI,CAAC,CAAC,CAAC,EAAE;QACXC,OAAO,IAAI,GAAG;MAChB;MACA,OAAOA,OAAO;IAChB,CAAC,CAAC,CAACI,IAAI,CAAC,EAAE,CAAC;EACb,CAAC;;EAED;EACAR,IAAI,CAACS,CAAC,GAAG,SAASA,CAACA,CAACC,OAAO,EAAEC,KAAK,EAAEC,MAAM,EAAEC,QAAQ,EAAEC,KAAK,EAAE;IAC3D,IAAI,OAAOJ,OAAO,KAAK,QAAQ,EAAE;MAC/BA,OAAO,GAAG,CAAC,CAAC,IAAI,EAAEA,OAAO,EAAEK,SAAS,CAAC,CAAC;IACxC;IACA,IAAIC,sBAAsB,GAAG,CAAC,CAAC;IAC/B,IAAIJ,MAAM,EAAE;MACV,KAAK,IAAIK,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAG,IAAI,CAACV,MAAM,EAAEU,CAAC,EAAE,EAAE;QACpC,IAAIC,EAAE,GAAG,IAAI,CAACD,CAAC,CAAC,CAAC,CAAC,CAAC;QACnB,IAAIC,EAAE,IAAI,IAAI,EAAE;UACdF,sBAAsB,CAACE,EAAE,CAAC,GAAG,IAAI;QACnC;MACF;IACF;IACA,KAAK,IAAIC,EAAE,GAAG,CAAC,EAAEA,EAAE,GAAGT,OAAO,CAACH,MAAM,EAAEY,EAAE,EAAE,EAAE;MAC1C,IAAIhB,IAAI,GAAG,EAAE,CAACG,MAAM,CAACI,OAAO,CAACS,EAAE,CAAC,CAAC;MACjC,IAAIP,MAAM,IAAII,sBAAsB,CAACb,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QAC7C;MACF;MACA,IAAI,OAAOW,KAAK,KAAK,WAAW,EAAE;QAChC,IAAI,OAAOX,IAAI,CAAC,CAAC,CAAC,KAAK,WAAW,EAAE;UAClCA,IAAI,CAAC,CAAC,CAAC,GAAGW,KAAK;QACjB,CAAC,MAAM;UACLX,IAAI,CAAC,CAAC,CAAC,GAAG,QAAQ,CAACG,MAAM,CAACH,IAAI,CAAC,CAAC,CAAC,CAACI,MAAM,GAAG,CAAC,GAAG,GAAG,CAACD,MAAM,CAACH,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAACG,MAAM,CAACH,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;UACnGA,IAAI,CAAC,CAAC,CAAC,GAAGW,KAAK;QACjB;MACF;MACA,IAAIH,KAAK,EAAE;QACT,IAAI,CAACR,IAAI,CAAC,CAAC,CAAC,EAAE;UACZA,IAAI,CAAC,CAAC,CAAC,GAAGQ,KAAK;QACjB,CAAC,MAAM;UACLR,IAAI,CAAC,CAAC,CAAC,GAAG,SAAS,CAACG,MAAM,CAACH,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAACG,MAAM,CAACH,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;UAC9DA,IAAI,CAAC,CAAC,CAAC,GAAGQ,KAAK;QACjB;MACF;MACA,IAAIE,QAAQ,EAAE;QACZ,IAAI,CAACV,IAAI,CAAC,CAAC,CAAC,EAAE;UACZA,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAACG,MAAM,CAACO,QAAQ,CAAC;QAC/B,CAAC,MAAM;UACLV,IAAI,CAAC,CAAC,CAAC,GAAG,aAAa,CAACG,MAAM,CAACH,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAACG,MAAM,CAACH,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;UACnEA,IAAI,CAAC,CAAC,CAAC,GAAGU,QAAQ;QACpB;MACF;MACAb,IAAI,CAACoB,IAAI,CAACjB,IAAI,CAAC;IACjB;EACF,CAAC;EACD,OAAOH,IAAI;AACb,CAAC,C;;;;;;;;;;;ACpFY;;AAEbH,MAAM,CAACC,OAAO,GAAG,UAAUK,IAAI,EAAE;EAC/B,IAAIC,OAAO,GAAGD,IAAI,CAAC,CAAC,CAAC;EACrB,IAAIkB,UAAU,GAAGlB,IAAI,CAAC,CAAC,CAAC;EACxB,IAAI,CAACkB,UAAU,EAAE;IACf,OAAOjB,OAAO;EAChB;EACA,IAAI,OAAOkB,IAAI,KAAK,UAAU,EAAE;IAC9B,IAAIC,MAAM,GAAGD,IAAI,CAACE,QAAQ,CAACC,kBAAkB,CAACC,IAAI,CAACC,SAAS,CAACN,UAAU,CAAC,CAAC,CAAC,CAAC;IAC3E,IAAIO,IAAI,GAAG,8DAA8D,CAACtB,MAAM,CAACiB,MAAM,CAAC;IACxF,IAAIM,aAAa,GAAG,MAAM,CAACvB,MAAM,CAACsB,IAAI,EAAE,KAAK,CAAC;IAC9C,OAAO,CAACxB,OAAO,CAAC,CAACE,MAAM,CAAC,CAACuB,aAAa,CAAC,CAAC,CAACrB,IAAI,CAAC,IAAI,CAAC;EACrD;EACA,OAAO,CAACJ,OAAO,CAAC,CAACI,IAAI,CAAC,IAAI,CAAC;AAC7B,CAAC,C;;;;;;;;;;;ACdD,qBAAqB,mBAAO,CAAC,2dAAwO;;AAErQ;AACA;AACA;;AAEA;AACA;AACA,UAAU;AACV;AACA;AACA,I;;;;;;;;;;;ACZa;AACb;AACA;AACA;AACA,6CAA6C,QAAQ;AACrD;AACA;AACA;AACA;AACA;AACA,8CAA6C,EAAE,aAAa,EAAC;AAC7D,gCAAgC;AAChC,eAAe,mBAAO,CAAC,oCAAe;AACtC,qBAAqB,mBAAO,CAAC,8BAAY;AACzC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB,mBAAO,CAAC,2EAA2B;AACpD,KAAK;AACL;AACA;AACA,gCAAgC;;;;;;;;;;;;ACjEhC,qBAAqB,mBAAO,CAAC,ieAA2O;;AAExQ;AACA;AACA;;AAEA;AACA;AACA,UAAU;AACV;AACA;AACA,I;;;;;;;;;;;ACZa;AACb;AACA;AACA;AACA,6CAA6C,QAAQ;AACrD;AACA;AACA;AACA;AACA;AACA,8CAA6C,EAAE,aAAa,EAAC;AAC7D,4BAA4B;AAC5B,eAAe,mBAAO,CAAC,oCAAe;AACtC,eAAe,mBAAO,CAAC,kBAAM;AAC7B,yBAAyB,mBAAO,CAAC,sCAAgB;AACjD,kBAAkB,mBAAO,CAAC,oCAAY;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC,YAAY;AAC5C;AACA,uBAAuB;AACvB;AACA;AACA;AACA;AACA,+BAA+B,YAAY;AAC3C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uDAAuD,aAAa;AACpE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B,YAAY;AACzC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,QAAQ,sFAAsF;AAC7H,aAAa;AACb;AACA;AACA;AACA,aAAa;AACb,cAAc,mBAAmB;AACjC;AACA;AACA;AACA,sBAAsB,8EAA8E;AACpG,sBAAsB,4EAA4E;AAClG,sBAAsB,4EAA4E;AAClG,sBAAsB,wEAAwE;AAC9F;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,cAAc,mBAAmB;AACjC;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kEAAkE,oBAAoB,MAAM,YAAY;AACxG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA,mBAAmB,oBAAoB;AACvC,eAAe,oBAAoB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,mBAAO,CAAC,iFAA8B;AAClD,KAAK;AACL;AACA;AACA,4BAA4B;;;;;;;;;;;;AC5Sf;AACb;AACA;AACA;AACA;AACA,eAAe,oCAAoC;AACnD;AACA;AACA,CAAC;AACD;AACA;AACA,CAAC;AACD;AACA,0CAA0C,4BAA4B;AACtE,CAAC;AACD;AACA,CAAC;AACD;AACA;AACA;AACA,6CAA6C,QAAQ;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8CAA6C,EAAE,aAAa,EAAC;AAC7D,+BAA+B;AAC/B,eAAe,mBAAO,CAAC,oCAAe;AACtC,qBAAqB,mBAAO,CAAC,8BAAY;AACzC,qBAAqB,mBAAO,CAAC,8BAAY;AACzC,kBAAkB,mBAAO,CAAC,oCAAY;AACtC,uBAAuB,mBAAO,CAAC,gEAA0B;AACzD,gCAAgC,mBAAO,CAAC,0EAAyB;AACjE,uBAAuB,mBAAO,CAAC,8CAAiB;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,iBAAiB;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uEAAuE;AACvE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8EAA8E,QAAQ,aAAa,eAAe;AAClH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,iBAAiB;AACxD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+DAA+D,gBAAgB;AAC/E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uEAAuE,eAAe;AACtF;AACA;AACA;AACA;AACA,6EAA6E,eAAe;AAC5F;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sEAAsE,aAAa,WAAW,eAAe;AAC7G;AACA;AACA;AACA;AACA;AACA;AACA,yEAAyE,aAAa,WAAW,eAAe;AAChH;AACA;AACA;AACA;AACA;AACA,wEAAwE,aAAa,WAAW,eAAe;AAC/G;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8EAA8E,eAAe;AAC7F;AACA;AACA;AACA,gFAAgF,eAAe;AAC/F;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iDAAiD,SAAS;AAC1D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8CAA8C,cAAc,sBAAsB,oBAAoB;AACtG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iEAAiE,SAAS;AAC1E;AACA,wBAAwB,iCAAiC,kDAAkD,mBAAO,CAAC,8CAAiB;AACpI;AACA;AACA;AACA;AACA,mFAAmF,aAAa,aAAa,SAAS;AACtH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iEAAiE,SAAS;AAC1E;AACA;AACA;AACA,kDAAkD,cAAc,sBAAsB,SAAS;AAC/F;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,iBAAiB;AACxD,4BAA4B,qBAAqB;AACjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8BAA8B;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,oEAAoE,OAAO;AAC3E;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,SAAS;AACT,mEAAmE,OAAO;AAC1E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,QAAQ,8BAA8B,SAAS;AACtF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iDAAiD,QAAQ,cAAc,SAAS;AAChF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yCAAyC,QAAQ,eAAe,iBAAiB,MAAM,SAAS;AAChG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uDAAuD,oBAAoB,IAAI,cAAc;AAC7F;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+DAA+D,aAAa;AAC5E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iEAAiE,YAAY;AAC7E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kDAAkD,QAAQ;AAC1D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qDAAqD,QAAQ,aAAa,SAAS;AACnF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,aAAa;AAC7B;AACA;AACA;AACA;AACA,0DAA0D,KAAK,GAAG,KAAK;AACvE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iEAAiE;AACjE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2EAA2E,MAAM,MAAM,QAAQ,EAAE,eAAe;AAChH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2EAA2E,MAAM,MAAM,QAAQ,EAAE,eAAe;AAChH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,uBAAuB;AAC7B,MAAM,kCAAkC;AACxC,MAAM,kCAAkC;AACxC,MAAM,gCAAgC;AACtC,MAAM,gCAAgC;AACtC,MAAM,yBAAyB;AAC/B,MAAM;AACN;AACA;AACA,gBAAgB,oBAAoB;AACpC,2BAA2B,oBAAoB;AAC/C;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,iCAAiC,4BAA4B,qCAAqC,0BAA0B,2BAA2B,WAAW,sBAAsB,0BAA0B,iCAAiC,4BAA4B,WAAW,4aAA4a,iCAAiC,qCAAqC,2BAA2B,qCAAqC,4DAA4D,6DAA6D,WAAW,iDAAiD,yBAAyB,WAAW,8bAA8b,0BAA0B,iCAAiC,qBAAqB,uBAAuB,0BAA0B,2BAA2B,0BAA0B,mCAAmC,iCAAiC,WAAW,iDAAiD,0BAA0B,iCAAiC,wBAAwB,sBAAsB,0BAA0B,2BAA2B,0BAA0B,mCAAmC,iCAAiC,WAAW,yIAAyI,yDAAyD,WAAW,6DAA6D,0DAA0D,WAAW,2BAA2B,6BAA6B,iCAAiC,0BAA0B,WAAW;AAChhF,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B;;;;;;;;;;;;AC1lClB;AACb;AACA;AACA;AACA,6CAA6C,QAAQ;AACrD;AACA;AACA;AACA;AACA;AACA,8CAA6C,EAAE,aAAa,EAAC;AAC7D,8BAA8B;AAC9B,eAAe,mBAAO,CAAC,oCAAe;AACtC,kBAAkB,mBAAO,CAAC,oCAAY;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA,mBAAmB,oBAAoB;AACvC,uBAAuB,oBAAoB;AAC3C,qBAAqB,qBAAqB;AAC1C,oBAAoB,qBAAqB;AACzC,mBAAmB,qBAAqB;AACxC,qBAAqB,qBAAqB;AAC1C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iDAAiD,WAAW;AAC5D,0EAA0E,gBAAgB;AAC1F;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,6BAA6B,6BAA6B,WAAW,uBAAuB,4BAA4B,kCAAkC,6CAA6C,+BAA+B,iDAAiD,6DAA6D,+BAA+B,+BAA+B,WAAW,wBAAwB,4BAA4B,kCAAkC,uBAAuB,+BAA+B,sBAAsB,2BAA2B,WAAW,uBAAuB,4BAA4B,kCAAkC,uBAAuB,2BAA2B,6BAA6B,4CAA4C,iCAAiC,sCAAsC,0BAA0B,gCAAgC,8BAA8B,kCAAkC,4EAA4E,WAAW,6BAA6B,oDAAoD,0BAA0B,WAAW,8BAA8B,oDAAoD,0BAA0B,sDAAsD,WAAW,uBAAuB,mCAAmC,kCAAkC,sCAAsC,8BAA8B,2BAA2B,6BAA6B,iCAAiC,mDAAmD,gCAAgC,0BAA0B,WAAW,yBAAyB,mCAAmC,kCAAkC,sCAAsC,gCAAgC,iCAAiC,0BAA0B,2BAA2B,iCAAiC,+BAA+B,iCAAiC,8BAA8B,iCAAiC,WAAW,2CAA2C,kCAAkC,0BAA0B,WAAW,+BAA+B,iDAAiD,0BAA0B,WAAW,oBAAoB,0BAA0B,6BAA6B,WAAW,0BAA0B,0BAA0B,WAAW,wBAAwB,4BAA4B,kCAAkC,uBAAuB,+BAA+B,WAAW,oBAAoB,4BAA4B,kCAAkC,sCAAsC,0BAA0B,2BAA2B,2BAA2B,iCAAiC,sCAAsC,0BAA0B,+BAA+B,8BAA8B,WAAW,0BAA0B,mDAAmD,0BAA0B,WAAW;AAC/pG,KAAK;AACL;AACA;AACA,8BAA8B;;;;;;;;;;;;ACnHjB;AACb,8CAA6C,EAAE,aAAa,EAAC;AAC7D,0BAA0B;AAC1B,qBAAqB,mBAAO,CAAC,8BAAY;AACzC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA,0BAA0B;;;;;;;;;;;;ACnBb;AACb,8CAA6C,EAAE,aAAa,EAAC;AAC7D,mBAAmB,GAAG,+BAA+B,GAAG,oCAAoC;AAC5F,eAAe,mBAAO,CAAC,kBAAM;AAC7B,oBAAoB,mBAAO,CAAC,uCAAa;AACzC;AACA,oCAAoC;AACpC,+BAA+B;AAC/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,QAAQ;AACpD,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA,4DAA4D,sBAAsB,MAAM,QAAQ;AAChG,aAAa;AACb,SAAS;AACT;AACA;AACA;AACA;AACA;AACA,yDAAyD;AACzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA,SAAS,UAAU;AACnB;AACA,6CAA6C,SAAS;AACtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B,gBAAgB;AAC5C;AACA,uDAAuD,EAAE;AACzD;AACA,4CAA4C,QAAQ,KAAK,SAAS;AAClE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,uBAAuB,EAAE,+BAA+B;AAC3F;AACA;AACA,wCAAwC,sBAAsB;AAC9D;AACA;AACA;AACA;AACA;AACA,+CAA+C,sBAAsB;AACrE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sDAAsD,sBAAsB;AAC5E;AACA;AACA;AACA,+EAA+E,sBAAsB;AACrG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,KAAK;AACjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oDAAoD,KAAK;AACzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kDAAkD,KAAK;AACvD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gEAAgE,KAAK;AACrE;AACA;AACA;AACA;AACA,iDAAiD,OAAO,IAAI,aAAa,mBAAmB,gBAAgB;AAC5G,4BAA4B,cAAc;AAC1C;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mDAAmD;AACnD;AACA,4BAA4B,uBAAuB;AACnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAkC,yCAAyC;AAC3E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,gBAAgB;AACxC;AACA;AACA,4BAA4B,EAAE;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAmB;;;;;;;;;;;;ACjfN;AACb;AACA;AACA;AACA;AACA,eAAe,oCAAoC;AACnD;AACA;AACA,CAAC;AACD;AACA;AACA,CAAC;AACD;AACA,0CAA0C,4BAA4B;AACtE,CAAC;AACD;AACA,CAAC;AACD;AACA;AACA;AACA,6CAA6C,QAAQ;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8CAA6C,EAAE,aAAa,EAAC;AAC7D,eAAe,mBAAO,CAAC,oCAAe;AACtC,iBAAiB,mBAAO,CAAC,wCAAiB;AAC1C,gBAAgB,mBAAO,CAAC,sCAAgB;AACxC,kCAAkC,mBAAO,CAAC,8BAAY;AACtD,yBAAyB,mBAAO,CAAC,sCAAgB;AACjD,yBAAyB,mBAAO,CAAC,iDAAkB;AACnD,iBAAiB,mBAAO,CAAC,iCAAU;AACnC,mBAAmB,mBAAO,CAAC,qCAAY;AACvC,gCAAgC,mBAAO,CAAC,qFAAoC;AAC5E,mCAAmC,mBAAO,CAAC,2FAAuC;AAClF,kCAAkC,mBAAO,CAAC,yFAAsC;AAChF,6BAA6B,mBAAO,CAAC,+EAAiC;AACtE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,mHAAmH;AACjI,cAAc,0FAA0F;AACxG,cAAc,0GAA0G;AACxH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,kBAAe;;;;;;;;;;;;ACtEF;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB,IAAI;AAC7B;AACA,uDAAuD,gCAAgC;AACvF;AACA,8CAA6C,EAAE,aAAa,EAAC;AAC7D,2BAA2B,GAAG,qBAAqB,GAAG,uBAAuB;AAC7E;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qDAAqD,EAAE;AACvD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yDAAyD,MAAM,IAAI,iCAAiC;AACpG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB;AACvB;AACA;AACA,eAAe;AACf;AACA,oBAAoB,iDAAiD;AACrE;AACA;AACA;AACA,4BAA4B;AAC5B,oDAAoD,KAAK;AACzD,eAAe,UAAU;AACzB;AACA,8BAA8B;AAC9B;AACA;AACA;AACA;AACA,uBAAuB;AACvB;AACA;AACA,eAAe,UAAU;AACzB;AACA,oBAAoB,mDAAmD;AACvE;AACA;AACA;AACA,oEAAoE;AACpE;AACA;AACA;AACA;AACA,mBAAmB;AACnB;AACA;AACA;AACA;AACA;AACA,4BAA4B,2CAA2C;AACvE;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,mCAAmC;AACvD;AACA;AACA;AACA;AACA,iDAAiD,SAAS,gBAAgB,IAAI;AAC9E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA,2BAA2B;;;;;;;;;;;;ACjKd;AACb,8CAA6C,EAAE,aAAa,EAAC;AAC7D,+BAA+B;AAC/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA,+BAA+B;;;;;;;;;;;;ACvBlB;AACb;AACA;AACA;AACA,6CAA6C,QAAQ;AACrD;AACA;AACA;AACA;AACA;AACA,8CAA6C,EAAE,aAAa,EAAC;AAC7D,mBAAmB,GAAG,6BAA6B;AACnD,eAAe,mBAAO,CAAC,oCAAe;AACtC,qBAAqB,mBAAO,CAAC,8BAAY;AACzC,oBAAoB,mBAAO,CAAC,wCAAc;AAC1C,yBAAyB,mBAAO,CAAC,sCAAgB;AACjD,eAAe,mBAAO,CAAC,kBAAM;AAC7B,kBAAkB,mBAAO,CAAC,oCAAY;AACtC,mCAAmC,mBAAO,CAAC,4FAAwC;AACnF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B,kDAAkD;AAC7E,aAAa;AACb,SAAS;AACT;AACA;AACA;AACA;AACA;AACA,8CAA8C;AAC9C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA,wDAAwD,YAAY;AACpE;AACA;AACA;AACA,MAAM,uBAAuB;AAC7B,MAAM,+BAA+B;AACrC,MAAM,kCAAkC;AACxC,MAAM;AACN;AACA;AACA,6BAA6B,oBAAoB;AACjD;AACA;AACA;AACA;AACA;AACA,mBAAmB;;;;;;;;;;;;ACvON;AACb,8CAA6C,EAAE,aAAa,EAAC;AAC7D,6BAA6B,GAAG,sBAAsB,GAAG,uBAAuB;AAChF,eAAe,mBAAO,CAAC,kBAAM;AAC7B,yBAAyB,mBAAO,CAAC,sCAAgB;AACjD,oBAAoB,mBAAO,CAAC,uCAAa;AACzC,kBAAkB,mBAAO,CAAC,mCAAW;AACrC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAoC;AACpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8BAA8B,qBAAqB;AACnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,qBAAqB;AAC5D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0CAA0C,cAAc;AACxD,+DAA+D,OAAO,IAAI,aAAa;AACvF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA,kDAAkD,wBAAwB;AAC1E;AACA;AACA;AACA,kDAAkD,aAAa,IAAI,UAAU;AAC7E,+BAA+B,iCAAiC,0BAA0B;AAC1F;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA,oCAAoC,SAAS;AAC7C;AACA,iBAAiB;AACjB;AACA,+BAA+B,8BAA8B;AAC7D;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,+BAA+B,gCAAgC;AAC/D,SAAS;AACT,iDAAiD,gBAAgB;AACjE;AACA;AACA;AACA;AACA,+BAA+B,0CAA0C,QAAQ;AACjF,SAAS;AACT;AACA,6CAA6C,kBAAkB;AAC/D,mCAAmC,QAAQ,oBAAoB,SAAS;AACxE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,sCAAsC;AACrE,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gDAAgD,yCAAyC;AACzF;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,wDAAwD,UAAU;AAClE,uDAAuD,SAAS;AAChE;AACA,+BAA+B,yCAAyC;AACxE,SAAS;AACT;AACA;AACA,+BAA+B,sBAAsB,UAAU;AAC/D;AACA,SAAS;AACT;AACA;AACA,+BAA+B,qBAAqB;AACpD;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iFAAiF,WAAW,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc;AAC5I;AACA,mCAAmC,iBAAiB;AACpD;AACA,uDAAuD,YAAY;AACnE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB;AACzB,2CAA2C,8BAA8B;AACzE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mFAAmF,SAAS,EAAE,UAAU;AACxG;AACA,mCAAmC,kBAAkB;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,SAAS;AACrD;AACA;AACA;AACA,2CAA2C,8BAA8B;AACzE;AACA;AACA;AACA;AACA,0CAA0C,kBAAkB;AAC5D;AACA;AACA;AACA;AACA;AACA;AACA,6DAA6D,mBAAmB;AAChF;AACA;AACA;AACA,yBAAyB,mBAAmB;AAC5C,kDAAkD,QAAQ,aAAa,SAAS;AAChF,mCAAmC,oCAAoC;AACvE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC,4BAA4B;AAC5D,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAkC,kBAAkB;AACpD;AACA;AACA;AACA,wCAAwC,mBAAmB,6CAA6C,SAAS;AACjH;AACA;AACA;AACA,yBAAyB,wBAAwB;AACjD,mCAAmC,yCAAyC;AAC5E;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B,yCAAyC,iCAAiC;AACrG;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB,QAAQ;AAC/B,4BAA4B,aAAa;AACzC,iCAAiC,kBAAkB;AACnD,iCAAiC,kBAAkB;AACnD,wBAAwB,SAAS;AACjC,wBAAwB,SAAS;AACjC,mCAAmC,oBAAoB;AACvD,mCAAmC,oBAAoB;AACvD,yBAAyB,UAAU;AACnC,2BAA2B,YAAY;AACvC,2BAA2B,YAAY;AACvC,kCAAkC,mBAAmB;AACrD,2BAA2B,YAAY;AACvC,yBAAyB,UAAU;AACnC,kCAAkC,mBAAmB;AACrD,mCAAmC,oBAAoB;AACvD,iCAAiC,kBAAkB;AACnD,8BAA8B,eAAe;AAC7C;AACA,8CAA8C,QAAQ;AACtD;AACA;AACA,4EAA4E,OAAO;AACnF,+EAA+E,OAAO;AACtF,+DAA+D,QAAQ,MAAM,YAAY;AACzF;AACA;AACA,oDAAoD,4BAA4B;AAChF;AACA;AACA,yEAAyE,OAAO;AAChF;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sDAAsD,QAAQ,GAAG,KAAK;AACtE;AACA;AACA,iCAAiC,aAAa,iBAAiB,OAAO,KAAK,qBAAqB;AAChG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iEAAiE,OAAO;AACxE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,EAAE;AACzC,kDAAkD,mBAAmB,EAAE,kBAAkB;AACzF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,EAAE;AACrC,kCAAkC,EAAE;AACpC;AACA;AACA;AACA,0BAA0B,6BAA6B,EAAE,4BAA4B;AACrF;AACA;AACA,sBAAsB,mBAAmB,EAAE,kBAAkB;AAC7D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B,QAAQ,KAAK;AACvC,6BAA6B;AAC7B;AACA;AACA,sBAAsB,mBAAmB,EAAE,kBAAkB;AAC7D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,EAAE;AACrC,8CAA8C,iBAAiB,EAAE,gBAAgB;AACjF;AACA;AACA,wDAAwD,OAAO;AAC/D;AACA;AACA;AACA;AACA,+EAA+E,UAAU;AACzF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0DAA0D,SAAS;AACnE;AACA;AACA,4DAA4D,UAAU,GAAG,0BAA0B;AACnG;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+EAA+E,YAAY,EAAE,aAAa;AAC1G;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,eAAe;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAsB;AACtB,6BAA6B;;;;;;;;;;;;ACh4BhB;AACb;AACA;AACA;AACA,6CAA6C,QAAQ;AACrD;AACA;AACA,8CAA6C,EAAE,aAAa,EAAC;AAC7D,+BAA+B;AAC/B,eAAe,mBAAO,CAAC,oCAAe;AACtC,yBAAyB,mBAAO,CAAC,sCAAgB;AACjD,6BAA6B,mBAAO,CAAC,+EAAiC;AACtE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B;;;;;;;;;;;;AC3BlB;AACb;AACA;AACA;AACA,6CAA6C,QAAQ;AACrD;AACA;AACA;AACA;AACA;AACA,8CAA6C,EAAE,aAAa,EAAC;AAC7D,+BAA+B;AAC/B,eAAe,mBAAO,CAAC,oCAAe;AACtC,qBAAqB,mBAAO,CAAC,8BAAY;AACzC,yBAAyB,mBAAO,CAAC,sCAAgB;AACjD,uBAAuB,mBAAO,CAAC,+DAAyB;AACxD,mCAAmC,mBAAO,CAAC,2FAAuC;AAClF,gCAAgC,mBAAO,CAAC,qFAAoC;AAC5E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB,iBAAiB;AACjB;AACA;AACA;AACA,0BAA0B,2DAA2D;AACrF,0BAA0B,yDAAyD;AACnF,0BAA0B,yDAAyD;AACnF,0BAA0B,qDAAqD;AAC/E;AACA,iBAAiB;AACjB;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6DAA6D,MAAM,MAAM,OAAO;AAChF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA,+BAA+B;;;;;;;;;;;;AC9G/B,6D;;;;;;;;;;;ACAA,2D;;;;;;;;;;;ACAA,4D;;;;;;;;;;;ACAA,kD;;;;;;;;;;;ACAA,wD;;;;;;;;;;;ACAA,4D;;;;;;;;;;;ACAA,4D;;;;;;UCAA;UACA;;UAEA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;UAEA;UACA;;UAEA;UACA;UACA;;;;;WC5BA;WACA;WACA;WACA;WACA;WACA,iCAAiC,WAAW;WAC5C;WACA,E;;;;;WCPA;WACA;WACA;WACA;WACA,yCAAyC,wCAAwC;WACjF;WACA;WACA,E;;;;;WCPA,wF;;;;;WCAA;WACA;WACA;WACA,uDAAuD,iBAAiB;WACxE;WACA,gDAAgD,aAAa;WAC7D,E;;;;;UENA;UACA;UACA;UACA","sources":["webpack://tabby-tmux/webpack/universalModuleDefinition","webpack://tabby-tmux/./src/components/settings.component.scss","webpack://tabby-tmux/./src/components/tmuxPaneTab.component.scss","webpack://tabby-tmux/./node_modules/.pnpm/css-loader@7.1.2_webpack@5.104.1/node_modules/css-loader/dist/runtime/api.js","webpack://tabby-tmux/./node_modules/.pnpm/css-loader@7.1.2_webpack@5.104.1/node_modules/css-loader/dist/runtime/sourceMaps.js","webpack://tabby-tmux/./src/components/settings.component.scss?c1cd","webpack://tabby-tmux/./src/components/settings.component.ts","webpack://tabby-tmux/./src/components/tmuxPaneTab.component.scss?2954","webpack://tabby-tmux/./src/components/tmuxPaneTab.component.ts","webpack://tabby-tmux/./src/components/tmuxSessionTab.component.ts","webpack://tabby-tmux/./src/components/tmuxWindowBar.component.ts","webpack://tabby-tmux/./src/config.ts","webpack://tabby-tmux/./src/gateway.ts","webpack://tabby-tmux/./src/index.ts","webpack://tabby-tmux/./src/layoutParser.ts","webpack://tabby-tmux/./src/logHelper.ts","webpack://tabby-tmux/./src/services/tmux.service.ts","webpack://tabby-tmux/./src/session.ts","webpack://tabby-tmux/./src/settings.ts","webpack://tabby-tmux/./src/tabContextMenu.ts","webpack://tabby-tmux/external umd \"@angular/common\"","webpack://tabby-tmux/external umd \"@angular/core\"","webpack://tabby-tmux/external umd \"@angular/forms\"","webpack://tabby-tmux/external umd \"rxjs\"","webpack://tabby-tmux/external umd \"tabby-core\"","webpack://tabby-tmux/external umd \"tabby-settings\"","webpack://tabby-tmux/external umd \"tabby-terminal\"","webpack://tabby-tmux/webpack/bootstrap","webpack://tabby-tmux/webpack/runtime/compat get default export","webpack://tabby-tmux/webpack/runtime/define property getters","webpack://tabby-tmux/webpack/runtime/hasOwnProperty shorthand","webpack://tabby-tmux/webpack/runtime/make namespace object","webpack://tabby-tmux/webpack/before-startup","webpack://tabby-tmux/webpack/startup","webpack://tabby-tmux/webpack/after-startup"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"@angular/core\"), require(\"@angular/common\"), require(\"@angular/forms\"), require(\"tabby-core\"), require(\"tabby-settings\"), require(\"tabby-terminal\"), require(\"rxjs\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"@angular/core\", \"@angular/common\", \"@angular/forms\", \"tabby-core\", \"tabby-settings\", \"tabby-terminal\", \"rxjs\"], factory);\n\telse {\n\t\tvar a = typeof exports === 'object' ? factory(require(\"@angular/core\"), require(\"@angular/common\"), require(\"@angular/forms\"), require(\"tabby-core\"), require(\"tabby-settings\"), require(\"tabby-terminal\"), require(\"rxjs\")) : factory(root[\"@angular/core\"], root[\"@angular/common\"], root[\"@angular/forms\"], root[\"tabby-core\"], root[\"tabby-settings\"], root[\"tabby-terminal\"], root[\"rxjs\"]);\n\t\tfor(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];\n\t}\n})(this, (__WEBPACK_EXTERNAL_MODULE__angular_core__, __WEBPACK_EXTERNAL_MODULE__angular_common__, __WEBPACK_EXTERNAL_MODULE__angular_forms__, __WEBPACK_EXTERNAL_MODULE_tabby_core__, __WEBPACK_EXTERNAL_MODULE_tabby_settings__, __WEBPACK_EXTERNAL_MODULE_tabby_terminal__, __WEBPACK_EXTERNAL_MODULE_rxjs__) => {\nreturn ","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/.pnpm/css-loader@7.1.2_webpack@5.104.1/node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/.pnpm/css-loader@7.1.2_webpack@5.104.1/node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `.tmux-settings-tab .tmux-table {\n width: 100%;\n display: table;\n border-spacing: 0px 20px;\n}\n.tmux-settings-tab .tmux-table .row {\n width: 100%;\n display: table-row;\n}\n.tmux-settings-tab .tmux-table .row .header {\n padding: 0;\n width: 12em;\n display: table-cell;\n}\n.tmux-settings-tab .tmux-table .row .form-control {\n width: 100%;\n display: table-cell;\n}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/components/settings.component.scss\"],\"names\":[],\"mappings\":\"AACE;EACE,WAAA;EACA,cAAA;EACA,wBAAA;AAAJ;AACI;EACE,WAAA;EACA,kBAAA;AACN;AAAM;EACE,UAAA;EACA,WAAA;EACA,mBAAA;AAER;AAAM;EACE,WAAA;EACA,mBAAA;AAER\",\"sourcesContent\":[\".tmux-settings-tab {\\n .tmux-table {\\n width: 100%;\\n display: table;\\n border-spacing: 0px 20px;\\n .row {\\n width: 100%;\\n display: table-row;\\n .header {\\n padding: 0;\\n width: 12em;\\n display: table-cell;\\n }\\n .form-control {\\n width: 100%;\\n display: table-cell;\\n }\\n }\\n }\\n}\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/.pnpm/css-loader@7.1.2_webpack@5.104.1/node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/.pnpm/css-loader@7.1.2_webpack@5.104.1/node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `@charset \"UTF-8\";\n/*\n * TmuxPaneTab — full CSS control over the terminal content area.\n *\n * BaseTerminalTabComponent applies a \"spaciness\" margin that shrinks the\n * content box, which clips edge characters and makes size calculations\n * harder. tmux owns the cell grid, so we zero out every spacing property\n * so the pane occupies 100 % of its allocated container — pixel-accurate\n * and no rounding surprises.\n *\n * Uniform 4px padding on all sides gives consistent visual breathing room.\n * The scrollbar is hidden to remove the asymmetric right-side gap and\n * simplify size math; scrolling is handled by Tabby's local history buffer.\n * Padding is subtracted in measureClientSize() so tmux grid calculations\n * remain accurate.\n */\n:host > .content {\n margin: 0;\n padding: 4px;\n border: 0;\n box-sizing: border-box;\n}\n\n/* Hide xterm scrollbar — tmux handles scrolling via Control Mode protocol */\n:host ::ng-deep .xterm {\n overflow: hidden !important;\n}\n\n:host ::ng-deep .xterm-viewport {\n overflow-y: hidden !important;\n}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/components/tmuxPaneTab.component.scss\"],\"names\":[],\"mappings\":\"AAAA,gBAAgB;AAAhB;;;;;;;;;;;;;;EAAA;AAeA;EACI,SAAA;EACA,YAAA;EACA,SAAA;EACA,sBAAA;AAEJ;;AACA,4EAAA;AACA;EACI,2BAAA;AAEJ;;AAAA;EACI,6BAAA;AAGJ\",\"sourcesContent\":[\"/*\\n * TmuxPaneTab — full CSS control over the terminal content area.\\n *\\n * BaseTerminalTabComponent applies a \\\"spaciness\\\" margin that shrinks the\\n * content box, which clips edge characters and makes size calculations\\n * harder. tmux owns the cell grid, so we zero out every spacing property\\n * so the pane occupies 100 % of its allocated container — pixel-accurate\\n * and no rounding surprises.\\n *\\n * Uniform 4px padding on all sides gives consistent visual breathing room.\\n * The scrollbar is hidden to remove the asymmetric right-side gap and\\n * simplify size math; scrolling is handled by Tabby's local history buffer.\\n * Padding is subtracted in measureClientSize() so tmux grid calculations\\n * remain accurate.\\n */\\n:host > .content {\\n margin: 0;\\n padding: 4px;\\n border: 0;\\n box-sizing: border-box;\\n}\\n\\n/* Hide xterm scrollbar — tmux handles scrolling via Control Mode protocol */\\n:host ::ng-deep .xterm {\\n overflow: hidden !important;\\n}\\n:host ::ng-deep .xterm-viewport {\\n overflow-y: hidden !important;\\n}\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","\"use strict\";\n\n/*\n MIT License http://www.opensource.org/licenses/mit-license.php\n Author Tobias Koppers @sokra\n*/\nmodule.exports = function (cssWithMappingToString) {\n var list = [];\n\n // return the list of modules as css string\n list.toString = function toString() {\n return this.map(function (item) {\n var content = \"\";\n var needLayer = typeof item[5] !== \"undefined\";\n if (item[4]) {\n content += \"@supports (\".concat(item[4], \") {\");\n }\n if (item[2]) {\n content += \"@media \".concat(item[2], \" {\");\n }\n if (needLayer) {\n content += \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\");\n }\n content += cssWithMappingToString(item);\n if (needLayer) {\n content += \"}\";\n }\n if (item[2]) {\n content += \"}\";\n }\n if (item[4]) {\n content += \"}\";\n }\n return content;\n }).join(\"\");\n };\n\n // import a list of modules into the list\n list.i = function i(modules, media, dedupe, supports, layer) {\n if (typeof modules === \"string\") {\n modules = [[null, modules, undefined]];\n }\n var alreadyImportedModules = {};\n if (dedupe) {\n for (var k = 0; k < this.length; k++) {\n var id = this[k][0];\n if (id != null) {\n alreadyImportedModules[id] = true;\n }\n }\n }\n for (var _k = 0; _k < modules.length; _k++) {\n var item = [].concat(modules[_k]);\n if (dedupe && alreadyImportedModules[item[0]]) {\n continue;\n }\n if (typeof layer !== \"undefined\") {\n if (typeof item[5] === \"undefined\") {\n item[5] = layer;\n } else {\n item[1] = \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\").concat(item[1], \"}\");\n item[5] = layer;\n }\n }\n if (media) {\n if (!item[2]) {\n item[2] = media;\n } else {\n item[1] = \"@media \".concat(item[2], \" {\").concat(item[1], \"}\");\n item[2] = media;\n }\n }\n if (supports) {\n if (!item[4]) {\n item[4] = \"\".concat(supports);\n } else {\n item[1] = \"@supports (\".concat(item[4], \") {\").concat(item[1], \"}\");\n item[4] = supports;\n }\n }\n list.push(item);\n }\n };\n return list;\n};","\"use strict\";\n\nmodule.exports = function (item) {\n var content = item[1];\n var cssMapping = item[3];\n if (!cssMapping) {\n return content;\n }\n if (typeof btoa === \"function\") {\n var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(cssMapping))));\n var data = \"sourceMappingURL=data:application/json;charset=utf-8;base64,\".concat(base64);\n var sourceMapping = \"/*# \".concat(data, \" */\");\n return [content].concat([sourceMapping]).join(\"\\n\");\n }\n return [content].join(\"\\n\");\n};","\n var result = require(\"!!../../node_modules/.pnpm/css-loader@7.1.2_webpack@5.104.1/node_modules/css-loader/dist/cjs.js!../../node_modules/.pnpm/sass-loader@16.0.6_sass@1.97.2_webpack@5.104.1/node_modules/sass-loader/dist/cjs.js!./settings.component.scss\");\n\n if (result && result.__esModule) {\n result = result.default;\n }\n\n if (typeof result === \"string\") {\n module.exports = result;\n } else {\n module.exports = result.toString();\n }\n ","\"use strict\";\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n};\nvar __metadata = (this && this.__metadata) || function (k, v) {\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\n};\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.TmuxSettingsTabComponent = void 0;\nconst core_1 = require(\"@angular/core\");\nconst tabby_core_1 = require(\"tabby-core\");\n// eslint-disable-next-line new-cap\nlet TmuxSettingsTabComponent = class TmuxSettingsTabComponent {\n constructor(config) {\n this.config = config;\n }\n};\nTmuxSettingsTabComponent.ctorParameters = () => [\n { type: tabby_core_1.ConfigService }\n];\nTmuxSettingsTabComponent = __decorate([\n (0, core_1.Component)({\n template: `\n <h3>Tmux</h3>\n <div class=\"tmux-settings-tab\">\n <div class=\"tmux-table\">\n <div class=\"row\">\n <div class=\"header\"><div class=\"title\">Default session name:</div></div>\n <input class=\"form-control\" type=\"text\"\n [(ngModel)]=\"config.store.tmuxPlugin.defaultSessionName\"\n (ngModelChange)=\"config.save()\">\n </div>\n <div class=\"row\">\n <div class=\"header\"><div class=\"title\">Command timeout (ms):</div></div>\n <input class=\"form-control\" type=\"number\"\n [(ngModel)]=\"config.store.tmuxPlugin.commandTimeoutMs\"\n (ngModelChange)=\"config.save()\">\n </div>\n <div class=\"row\">\n <div class=\"header\"><div class=\"title\">Send-keys chunk size:</div></div>\n <input class=\"form-control\" type=\"number\"\n [(ngModel)]=\"config.store.tmuxPlugin.sendKeysChunkSize\"\n (ngModelChange)=\"config.save()\">\n </div>\n <div class=\"row\">\n <div class=\"header\"><div class=\"title\">Resize debounce (ms):</div></div>\n <input class=\"form-control\" type=\"number\"\n [(ngModel)]=\"config.store.tmuxPlugin.resizeDebounceMs\"\n (ngModelChange)=\"config.save()\">\n </div>\n <div class=\"row\">\n <div class=\"header\"><div class=\"title\">Debug logging:</div></div>\n <input type=\"checkbox\"\n [(ngModel)]=\"config.store.tmuxPlugin.debugLogging\"\n (ngModelChange)=\"config.save()\">\n </div>\n </div>\n </div>\n `,\n styles: [require('./settings.component.scss')]\n }),\n __metadata(\"design:paramtypes\", [tabby_core_1.ConfigService])\n], TmuxSettingsTabComponent);\nexports.TmuxSettingsTabComponent = TmuxSettingsTabComponent;\n","\n var result = require(\"!!../../node_modules/.pnpm/css-loader@7.1.2_webpack@5.104.1/node_modules/css-loader/dist/cjs.js!../../node_modules/.pnpm/sass-loader@16.0.6_sass@1.97.2_webpack@5.104.1/node_modules/sass-loader/dist/cjs.js!./tmuxPaneTab.component.scss\");\n\n if (result && result.__esModule) {\n result = result.default;\n }\n\n if (typeof result === \"string\") {\n module.exports = result;\n } else {\n module.exports = result.toString();\n }\n ","\"use strict\";\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n};\nvar __metadata = (this && this.__metadata) || function (k, v) {\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\n};\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.TmuxPaneTabComponent = void 0;\nconst core_1 = require(\"@angular/core\");\nconst rxjs_1 = require(\"rxjs\");\nconst tabby_terminal_1 = require(\"tabby-terminal\");\nconst session_1 = require(\"../session\");\nlet TmuxPaneTabComponent = class TmuxPaneTabComponent extends tabby_terminal_1.BaseTerminalTabComponent {\n constructor(injector) {\n super(injector);\n /**\n * Whether this pane is the active (keyboard-focused) pane in the tmux session.\n * Controls whether hotkey-triggered input (e.g. Ctrl+C, paste) is forwarded.\n *\n * All tmux pane tabs have `hasFocus = true` simultaneously (needed for\n * xterm frontend initialization), but only one pane should process hotkeys.\n * This flag is managed by TmuxSessionTabComponent.focus().\n */\n this._tmuxActive = true;\n /**\n * When true, input is broadcast to all panes in the tmux session\n * (\"Focus all tmux panes\" / synchronize-panes mode).\n * Toggled via the right-click context menu.\n */\n this._tmuxSyncInput = false;\n /** Desired tmux grid size (chars). tmux is authoritative over the cell grid. */\n this._tmuxCols = 0;\n this._tmuxRows = 0;\n /** Whether the xterm frontend has been attached and is ready. */\n this._frontendReady = false;\n }\n ngOnInit() {\n // Profile must be set BEFORE calling super.ngOnInit() because\n // the parent class configures the terminal frontend using profile settings\n this.profile = {\n name: `Tmux Pane %${this.paneId}`,\n type: 'tmux',\n options: {},\n // Required properties for BaseTerminalTabComponent\n behaviorOnSessionEnd: 'close',\n terminalColorScheme: null, // Use default\n };\n this.setTitle(`Pane %${this.paneId}`);\n // Now call parent's ngOnInit to set up the frontend.\n // NOTE: super.ngOnInit() schedules a setImmediate that checks\n // this.hasFocus to decide whether to attach the xterm frontend.\n // BaseTabComponent sets hasFocus=true on focused$.next().\n // We emit focus synchronously right after super.ngOnInit() so that\n // when setImmediate fires, hasFocus is already true.\n super.ngOnInit();\n // Mark this tab as focused so the setImmediate in super.ngOnInit\n // will attach the frontend to the DOM element.\n // This is safe because our overridden focus() doesn't blur siblings.\n this.emitFocused();\n // Initialize our session AFTER emitting focus, so that:\n // 1. frontend.attach() runs via setImmediate (because hasFocus=true)\n // 2. frontend.resize$ fires, which triggers releaseInitialDataBuffer()\n // 3. Then session.start() populates the buffer and it gets released\n //\n // The key insight: setImmediate fires before our async session.start(),\n // so the frontend is attached before history restore begins. This means\n // history output goes directly to the terminal, not into a buffer that\n // gets flushed in a bulk dump.\n this.initializeSession();\n // tmux owns the cell grid. Once the frontend is ready, neutralize\n // xterm's automatic fit-to-container so the pane never overrides the\n // tmux-dictated grid with its own (pixel-rounded) size — that mismatch\n // is what causes off-by-one wrapping / cursor errors. The grid is set\n // explicitly via setTmuxGrid() from the layout sync instead.\n this.frontendReady$.pipe((0, rxjs_1.first)()).subscribe(() => {\n this._frontendReady = true;\n const frontend = this.frontend;\n if (frontend) {\n frontend.enableResizing = false;\n // The frontend's resizeHandler (window resize + ResizeObserver)\n // calls fitAddon.fit() unconditionally and ignores enableResizing.\n // Replace fit() with a no-op so the grid stays exactly what tmux\n // tells us. Keep a reference in case we ever need to restore it.\n if (frontend.fitAddon && typeof frontend.fitAddon.fit === 'function') {\n frontend.fitAddon.fit = () => { };\n }\n }\n // Apply any grid size that arrived before the frontend was ready.\n if (this._tmuxCols > 0 && this._tmuxRows > 0) {\n this.applyTmuxGrid();\n }\n });\n }\n /**\n * Set the authoritative cell grid for this pane, as dictated by the tmux\n * layout string. tmux decides each pane's exact character width/height, so\n * we resize the xterm grid to match instead of letting xterm fit to pixels.\n * This keeps wrapping aligned with tmux and removes the resize feedback loop.\n */\n setTmuxGrid(cols, rows) {\n if (cols <= 0 || rows <= 0)\n return;\n if (cols === this._tmuxCols && rows === this._tmuxRows)\n return;\n this._tmuxCols = cols;\n this._tmuxRows = rows;\n if (this._frontendReady) {\n this.applyTmuxGrid();\n }\n }\n applyTmuxGrid() {\n var _a;\n const xterm = (_a = this.frontend) === null || _a === void 0 ? void 0 : _a.xterm;\n if (!xterm)\n return;\n if (xterm.cols === this._tmuxCols && xterm.rows === this._tmuxRows)\n return;\n try {\n xterm.resize(this._tmuxCols, this._tmuxRows);\n }\n catch (e) {\n this.logger.warn(`Failed to resize pane %${this.paneId} grid`, e);\n }\n // xterm.resize() clears the alternate screen buffer.\n // Re-apply saved alternate content if this pane was on it.\n const session = this.session;\n if ((session === null || session === void 0 ? void 0 : session.pendingAltRestore) && this.controller) {\n this.controller.reapplyAltContent(session);\n }\n }\n async initializeSession() {\n if (!this.controller) {\n throw new Error('Tmux controller not provided to pane tab');\n }\n // Create the pane session\n const paneSession = new session_1.TmuxPaneSession(this.logger, this.controller, this.paneId);\n // Set up the terminal session first so the frontend is wired.\n // This binds session.output$ → this.write() and frontend → session.\n this.setSession(paneSession, true);\n // Start the session (restores history) non-blocking.\n // History is written to the terminal via emitOutput → write().\n paneSession.start();\n }\n /**\n * Guard sendInput so that only the active pane forwards hotkey-triggered\n * input (Ctrl+C, Home, End, etc.) to its tmux session.\n *\n * When _tmuxSyncInput is enabled (\"Focus all tmux panes\"), input is also\n * broadcast to all other panes in the session.\n */\n sendInput(data) {\n if (!this._tmuxActive) {\n return;\n }\n super.sendInput(data);\n // Broadcast to all other panes when sync mode is active\n if (this._tmuxSyncInput && this.controller) {\n const buf = Buffer.isBuffer(data) ? data : Buffer.from(data);\n for (const pid of this.controller.getAllPaneIds()) {\n if (pid !== this.paneId) {\n this.controller.writeToPane(pid, buf);\n }\n }\n }\n }\n /**\n * Guard paste so that only the active pane pastes into its tmux session.\n */\n async paste() {\n if (!this._tmuxActive) {\n return;\n }\n return super.paste();\n }\n /**\n * Always allow closing a tmux pane tab without showing the\n * \"command is still running\" confirmation dialog.\n * The tmux server process is not a user command — lifetime is\n * managed separately by TmuxService/TmuxController.\n */\n async canClose() {\n return true;\n }\n // Override generic title behavior\n getCustomTitle() {\n return `Tmux Pane %${this.paneId}`;\n }\n /**\n * Override the native context menu to provide tmux-specific items only.\n * Keeps: Copy, Paste, Close (pane).\n * Adds: Exit Tmux Mode, Split submenu, Focus all tmux panes.\n */\n async buildContextMenu() {\n const items = [\n {\n label: this.translate.instant('Copy'),\n click: () => { var _a; return (_a = this.frontend) === null || _a === void 0 ? void 0 : _a.copySelection(); },\n },\n {\n label: this.translate.instant('Paste'),\n click: () => this.paste(),\n },\n { type: 'separator' },\n {\n label: this.translate.instant('Split'),\n submenu: [\n { label: this.translate.instant('Right'), click: () => this.splitPane('right') },\n { label: this.translate.instant('Down'), click: () => this.splitPane('down') },\n { label: this.translate.instant('Left'), click: () => this.splitPane('left') },\n { label: this.translate.instant('Up'), click: () => this.splitPane('up') },\n ],\n },\n {\n label: this.translate.instant('Focus all tmux panes'),\n type: 'checkbox',\n checked: this._tmuxSyncInput,\n click: () => this.toggleSyncInput(),\n },\n { type: 'separator' },\n {\n label: this.translate.instant('Close'),\n click: () => this.closePane(),\n },\n ];\n return items;\n }\n async handleRightMouseDown(event) {\n event.preventDefault();\n event.stopPropagation();\n this.platform.popupContextMenu(await this.buildContextMenu(), event);\n }\n async splitPane(direction) {\n if (!this.controller)\n return;\n const flagMap = {\n 'right': '-h',\n 'down': '-v',\n 'left': '-h -b',\n 'up': '-v -b',\n };\n await this.controller.gateway.sendCommand(`split-window ${flagMap[direction]} -t %${this.paneId}`);\n // No explicit refresh needed — the %layout-change notification\n // from tmux will trigger discoverPanesFromLayout() in TmuxController,\n // which discovers the new pane and emits pane-add with pre-loaded\n // history (iTerm2-style).\n }\n async closePane() {\n if (!this.controller)\n return;\n await this.controller.killPane(this.paneId);\n }\n /**\n * Toggle \"Focus all tmux panes\" (synchronize input) across all panes\n * in the current tmux session.\n */\n toggleSyncInput() {\n if (!this.controller)\n return;\n const newValue = !this._tmuxSyncInput;\n for (const pid of this.controller.getAllPaneIds()) {\n const tab = this.findPaneTab(pid);\n if (tab) {\n tab._tmuxSyncInput = newValue;\n }\n }\n }\n findPaneTab(paneId) {\n // Walk the session tab's window pane map to find the tab\n const parent = this.parent;\n if (parent === null || parent === void 0 ? void 0 : parent.windowPaneTabs) {\n for (const paneMap of parent.windowPaneTabs.values()) {\n const tab = paneMap.get(paneId);\n if (tab)\n return tab;\n }\n }\n return null;\n }\n};\nTmuxPaneTabComponent.ctorParameters = () => [\n { type: core_1.Injector }\n];\nTmuxPaneTabComponent.propDecorators = {\n controller: [{ type: core_1.Input }],\n paneId: [{ type: core_1.Input }]\n};\nTmuxPaneTabComponent = __decorate([\n (0, core_1.Component)({\n selector: 'tmux-pane-tab',\n template: tabby_terminal_1.BaseTerminalTabComponent.template,\n animations: tabby_terminal_1.BaseTerminalTabComponent.animations,\n styles: [...tabby_terminal_1.BaseTerminalTabComponent.styles,\n require('./tmuxPaneTab.component.scss')]\n }),\n __metadata(\"design:paramtypes\", [core_1.Injector])\n], TmuxPaneTabComponent);\nexports.TmuxPaneTabComponent = TmuxPaneTabComponent;\n","\"use strict\";\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n var desc = Object.getOwnPropertyDescriptor(m, k);\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\n desc = { enumerable: true, get: function() { return m[k]; } };\n }\n Object.defineProperty(o, k2, desc);\n}) : (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n o[k2] = m[k];\n}));\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n}) : function(o, v) {\n o[\"default\"] = v;\n});\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n};\nvar __importStar = (this && this.__importStar) || function (mod) {\n if (mod && mod.__esModule) return mod;\n var result = {};\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\n __setModuleDefault(result, mod);\n return result;\n};\nvar __metadata = (this && this.__metadata) || function (k, v) {\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\n};\nvar TmuxSessionTabComponent_1;\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.TmuxSessionTabComponent = void 0;\nconst core_1 = require(\"@angular/core\");\nconst tabby_core_1 = require(\"tabby-core\");\nconst tabby_core_2 = require(\"tabby-core\");\nconst session_1 = require(\"../session\");\nconst tmux_service_1 = require(\"../services/tmux.service\");\nconst tmuxPaneTab_component_1 = require(\"./tmuxPaneTab.component\");\nconst layoutParser_1 = require(\"../layoutParser\");\n/**\n * TmuxSessionTabComponent - Manages an entire tmux session within a single Tabby tab.\n *\n * Each tmux window is represented by its pane tabs, which are hidden/shown via\n * removeTab()/addTab() when switching windows. The bottom window bar provides\n * window switching UI.\n *\n * Always created by TmuxService.attachToTerminal() with existingController set.\n */\nlet TmuxSessionTabComponent = TmuxSessionTabComponent_1 = class TmuxSessionTabComponent extends tabby_core_1.SplitTabComponent {\n constructor(injector, tmuxService, configService, tabsService, cdr, hostElement, log) {\n super(injector.get(tabby_core_1.HotkeysService), tabsService, injector.get(tabby_core_2.TabRecoveryService), injector);\n this.tmuxService = tmuxService;\n this.configService = configService;\n this.cdr = cdr;\n this.hostElement = hostElement;\n this.profile = {};\n this.eventSubscription = null;\n // windowId → (paneId → paneTab)\n this.windowPaneTabs = new Map();\n /** Queue for serializing async event processing */\n this.eventQueue = Promise.resolve();\n this.controller = null;\n this.activeWindowId = null;\n this.connected = false;\n this.sessionName = '';\n this._initialized = false;\n this._resizeHandler = null;\n this._resizeTimer = null;\n this._paneAreaObserver = null;\n /** Last dimensions sent to tmux, for dedup */\n this._lastSentCols = 0;\n this._lastSentRows = 0;\n /** Custom tmux pane dividers — kept for interface compatibility but not rendered */\n this._tmuxDividers = [];\n /** mousedown handler attached to .pane-area for border drag detection */\n this._paneAreaMouseDownHandler = null;\n /** mousemove handler for border hover highlight */\n this._paneAreaMouseMoveHandler = null;\n this._tabsService = tabsService;\n this.logger = log.create('tmux-session');\n }\n ngOnInit() {\n this.logger.info('ngOnInit initialized');\n this.controller = this.existingController;\n if (!this.controller) {\n this.logger.error('No controller provided');\n return;\n }\n this.sessionName = this.controller.getSessionName() || this.profile.sessionName || 'default';\n this.setTitle(`Tmux: ${this.sessionName}`);\n // Subscribe to controller events.\n // Events are queued to ensure serial async processing — critical because\n // handleControllerEvent contains async operations (switchToWindow, syncLayout)\n // that must not interleave. Without serialization, concurrent switches from\n // multiple window-add events (during refreshPanes) corrupt activeWindowId.\n this.eventSubscription = this.controller.events.subscribe(event => {\n this.eventQueue = this.eventQueue.then(() => this.handleControllerEvent(event));\n });\n // Bootstrap from current controller snapshot in case early events were missed\n this.bootstrapFromControllerState();\n }\n /**\n * Called after the view is initialized.\n * The parent SplitTabComponent has finished its own ngAfterViewInit\n * (including recoverContainer if any), so #vc is ready.\n */\n async ngAfterViewInit() {\n await super.ngAfterViewInit();\n if (!this.controller)\n return;\n // Wait one more frame to ensure the wrapper's attachTabView\n // has finished inserting us into its ViewContainerRef\n requestAnimationFrame(async () => {\n this._initialized = true;\n await this.controller.refreshPanes();\n this.bootstrapFromControllerState();\n // Wait for all queued events (window-add, pane-add) from refreshPanes\n // to be processed before switching to the first window.\n await this.eventQueue;\n // Prefer the tmux-side active window (from list-windows #{window_active}\n // or %session-window-changed). Fall back to the first window in the map.\n const activeWindowId = this.controller.getActiveWindowId();\n const targetWindowId = (activeWindowId !== null && this.windowPaneTabs.has(activeWindowId))\n ? activeWindowId\n : this.controller.getFirstWindowId();\n if (targetWindowId !== undefined) {\n await this.switchToWindow(targetWindowId);\n }\n // Listen for window resize events (like iTerm2's windowDidResize).\n // Only fires when the browser window changes size, not during\n // internal SplitTab layout operations. Debounced to avoid flooding.\n this._resizeHandler = () => this.scheduleRefreshClientSize();\n window.addEventListener('resize', this._resizeHandler);\n // Observe the .pane-area container directly. This is the single\n // source of truth for the client size: any time the container's\n // pixel size changes (window resize, spanner drag, sidebar toggle,\n // first mount), we recompute and push the whole-window grid to tmux.\n // Per-pane xterm fit is disabled, so this never feeds back.\n const host = this.hostElement.nativeElement;\n const paneArea = host.querySelector('.pane-area');\n if (paneArea && typeof ResizeObserver !== 'undefined') {\n this._paneAreaObserver = new ResizeObserver(() => this.scheduleRefreshClientSize());\n this._paneAreaObserver.observe(paneArea);\n }\n // Attach border hover + drag handlers to the pane-area\n this.attachPaneAreaBorderHandlers();\n // Initial size sync after pane mount\n this.scheduleRefreshClientSize();\n });\n }\n bootstrapFromControllerState() {\n if (!this.controller) {\n return;\n }\n // Prime local maps from controller state so UI can render even if\n // window-add / pane-add events happened before this component subscribed.\n // This is critical: discoverWindowsAndPanes() emits window-add and pane-add\n // during the first call (triggered by session-changed), but the SessionTab\n // component may not exist yet. By the time ngOnInit runs, the controller\n // already knows about all windows and panes — we must create pane tabs\n // here so switchToWindow finds non-empty paneMaps.\n for (const windowState of this.controller.getAllWindowStates()) {\n if (!this.windowPaneTabs.has(windowState.id)) {\n this.windowPaneTabs.set(windowState.id, new Map());\n }\n // Create pane tabs for all panes the controller already knows about\n const paneMap = this.windowPaneTabs.get(windowState.id);\n const ctrlWindowState = this.controller.getWindowState(windowState.id);\n if (ctrlWindowState) {\n for (const paneId of ctrlWindowState.panes) {\n if (!paneMap.has(paneId)) {\n this.logger.info(`Bootstrap: creating pane tab for %${paneId} in window @${windowState.id}`);\n const paneTab = this.createPaneTab(paneId);\n paneTab.controller = this.controller;\n paneTab.paneId = paneId;\n paneMap.set(paneId, paneTab);\n }\n }\n }\n }\n if (this.controller.isAttached) {\n this.connected = true;\n }\n this.cdr.detectChanges();\n }\n async handleControllerEvent(event) {\n var _a, _b;\n this.logger.info('SessionTab event:', event.type, event);\n switch (event.type) {\n case 'initialized':\n case 'session-changed':\n this.connected = true;\n this.sessionName = ((_a = this.controller) === null || _a === void 0 ? void 0 : _a.getSessionName()) || this.profile.sessionName || 'default';\n this.setTitle(`Tmux: ${this.sessionName}`);\n this.cdr.detectChanges();\n break;\n case 'window-add':\n if (event.windowId !== undefined) {\n const isNewWindow = !this.windowPaneTabs.has(event.windowId);\n // Ensure the window has an entry in our map\n if (isNewWindow) {\n this.logger.info(`Adding new window @${event.windowId} to map`);\n this.windowPaneTabs.set(event.windowId, new Map());\n }\n // Switch to a new window if:\n // 1. No active window yet (initial attach), OR\n // 2. This is a genuinely new window created after attach\n // AND we are past the initial bootstrap phase.\n // During batch discovery, we defer switching to ngAfterViewInit.\n //\n // MUST await: switchToWindow is async and rebuilds the SplitContainer\n // tree. Without await, concurrent switches from multiple window-add\n // events (during refreshPanes) interleave and corrupt activeWindowId.\n if (this._initialized && this.activeWindowId === null) {\n this.logger.info(`Switching to first window @${event.windowId}`);\n await this.switchToWindow(event.windowId);\n }\n else if (this._initialized && isNewWindow && this.activeWindowId !== null) {\n // Runtime window creation (after initial attach)\n this.logger.info(`Switching to new runtime window @${event.windowId}`);\n await this.switchToWindow(event.windowId);\n }\n }\n break;\n case 'window-close':\n if (event.windowId !== undefined) {\n await this.handleWindowClose(event.windowId);\n }\n break;\n case 'pane-add':\n if (event.paneId !== undefined && event.windowId !== undefined) {\n this.logger.info(`Handling pane-add event: pane=${event.paneId}, window=${event.windowId}`);\n await this.handlePaneAdd(event.paneId, event.windowId);\n }\n break;\n case 'pane-update':\n if (event.paneId !== undefined && event.windowId !== undefined) {\n // Pane might have moved to a different window\n this.logger.info(`Handling pane-update event: pane=${event.paneId}, window=${event.windowId}`);\n await this.handlePaneUpdate(event.paneId, event.windowId);\n }\n break;\n case 'pane-close':\n if (event.paneId !== undefined && event.windowId !== undefined) {\n this.logger.info(`Handling pane-close event: pane=${event.paneId}, window=${event.windowId}`);\n this.handlePaneClose(event.paneId, event.windowId);\n }\n break;\n case 'layout-change':\n // NOTE: We always call syncLayout for the active window.\n // For non-active windows, we save the layout but don't rebuild\n // the tree (it will be rebuilt when the user switches to it).\n if (event.windowId !== undefined && ((_b = event.data) === null || _b === void 0 ? void 0 : _b.layout)) {\n if (event.windowId === this.activeWindowId) {\n this.logger.info(`Syncing layout for active window @${event.windowId}`);\n await this.syncLayout(event.data.layout);\n }\n else {\n this.logger.info(`Layout changed for inactive window @${event.windowId}, saved for next switch`);\n }\n }\n break;\n case 'exit':\n this.connected = false;\n this.cdr.detectChanges();\n break;\n }\n }\n /**\n * Switch to a different tmux window.\n * Hides current window's panes and shows target window's panes.\n */\n async switchToWindow(windowId) {\n var _a, _b;\n if (windowId === this.activeWindowId)\n return;\n this.logger.info(`Switching to window @${windowId}`);\n // Clear dividers while switching windows\n this._tmuxDividers = [];\n // 1. Detach current active window's pane views (don't use removeTab —\n // SplitTabComponent.removeTab destroys the tab when root.children\n // becomes empty). Instead, clear the root directly.\n if (this.activeWindowId !== null) {\n const paneMap = this.windowPaneTabs.get(this.activeWindowId);\n if (paneMap) {\n this.logger.info(`Detaching ${paneMap.size} pane(s) for window @${this.activeWindowId}`);\n for (const paneTab of paneMap.values()) {\n paneTab.emitVisibility(false);\n this.detachPaneView(paneTab);\n }\n }\n }\n // 2. Update active window\n this.activeWindowId = windowId;\n // 3. Ensure pane tabs exist for this window\n if (!this.windowPaneTabs.has(windowId)) {\n this.windowPaneTabs.set(windowId, new Map());\n }\n const paneMap = this.windowPaneTabs.get(windowId);\n if (paneMap.size === 0) {\n // First time visiting this window. Pane tabs will be created by\n // handlePaneAdd (triggered by discoverPanesFromLayout on\n // %layout-change). We don't call addPanesForWindow — panes are\n // discovered asynchronously (iTerm2-style).\n //\n // HOWEVER: if the controller already knows the layout for this\n // window (from batch discovery during attach), we can proactively\n // discover panes from it instead of waiting for a layout-change\n // event that may never come (tmux doesn't re-send layout-change\n // for windows that haven't changed).\n const windowState = (_a = this.controller) === null || _a === void 0 ? void 0 : _a.getWindowState(windowId);\n if (windowState === null || windowState === void 0 ? void 0 : windowState.layout) {\n this.logger.info(`No pane tabs yet for window @${windowId}, but layout is known — discovering panes proactively`);\n // Extract pane IDs from the known layout and create pane tabs\n const { parseTmuxLayout, flattenLayout } = await Promise.resolve().then(() => __importStar(require('../layoutParser')));\n const layoutTree = parseTmuxLayout(windowState.layout);\n if (layoutTree) {\n for (const pane of flattenLayout(layoutTree)) {\n if (!paneMap.has(pane.paneId)) {\n this.logger.info(`Proactively creating pane tab for %${pane.paneId} in window @${windowId}`);\n const paneTab = this.createPaneTab(pane.paneId);\n paneTab.controller = this.controller;\n paneTab.paneId = pane.paneId;\n paneMap.set(pane.paneId, paneTab);\n }\n }\n }\n }\n else {\n this.logger.info(`No pane tabs yet for window @${windowId}, waiting for pane-add events`);\n }\n }\n else {\n this.logger.info(`Mounting existing ${paneMap.size} pane(s) for window @${windowId}`);\n }\n // 4. Rebuild SplitContainer tree with this window's panes\n this.root = new tabby_core_1.SplitContainer();\n this.root.orientation = 'h';\n const paneTabs = Array.from(paneMap.values());\n if (paneTabs.length > 0) {\n this.logger.info(`Adding ${paneTabs.length} pane tab(s) to SplitTab`);\n for (let i = 0; i < paneTabs.length; i++) {\n const paneTab = paneTabs[i];\n if (i === 0) {\n await this.addTab(paneTab, null, 'r');\n }\n else {\n await this.addTab(paneTab, paneTabs[i - 1], 'r');\n }\n paneTab.emitVisibility(true);\n }\n // 5. Sync layout from tmux\n const windowState = (_b = this.controller) === null || _b === void 0 ? void 0 : _b.getWindowState(windowId);\n if (windowState === null || windowState === void 0 ? void 0 : windowState.layout) {\n this.logger.info('Syncing layout after mounting panes');\n await this.syncLayout(windowState.layout);\n }\n }\n // 6. Detect changes; precise client size refresh happens via the\n // .pane-area ResizeObserver once xterm renders its cell grid.\n this.cdr.detectChanges();\n // 7. Push the correct client size to tmux once panes are mounted.\n // We use requestAnimationFrame to wait for xterm to render its\n // character grid (getCellSize needs real cell dimensions), then\n // force a non-deduplicated refresh-client -C.\n if (paneTabs.length > 0) {\n requestAnimationFrame(() => {\n // Reset dedup so the next call always goes through\n this._lastSentCols = 0;\n this._lastSentRows = 0;\n this.refreshClientSize();\n });\n }\n }\n /**\n * Override focus to manage which pane is the active (hotkey-target) pane.\n *\n * In tmux integration, all panes are visible simultaneously (split layout),\n * so we cannot blur other tabs (that would prevent their xterm frontends\n * from staying initialized). Instead, all pane tabs keep `hasFocus = true`\n * for frontend initialization, and we use `TmuxPaneTabComponent._tmuxActive`\n * to control which pane processes hotkeys.\n */\n focus(tab) {\n ;\n this.focusedTab = tab;\n tab.emitFocused();\n // Mark only the focused pane as active for hotkey routing.\n // Other panes remain visible and initialized but won't process\n // hotkey-triggered input (Ctrl+C, paste, etc.).\n for (const t of this.getAllTabs()) {\n if (t instanceof tmuxPaneTab_component_1.TmuxPaneTabComponent) {\n t._tmuxActive = (t === tab);\n }\n }\n }\n /**\n * Detach a pane tab's view from the ViewContainer without calling\n * removeTab() which would trigger self-destruction when root empties.\n */\n detachPaneView(tab) {\n var _a;\n // Remove from root tree structure\n const parent = this.getParentOf(tab);\n if (parent) {\n const index = parent.children.indexOf(tab);\n if (index !== -1) {\n parent.children.splice(index, 1);\n parent.ratios.splice(index, 1);\n }\n }\n // Remove the embedded view reference so layout() won't position it\n ;\n (_a = this.viewRefs) === null || _a === void 0 ? void 0 : _a.delete(tab);\n tab.removeFromContainer();\n tab.parent = null;\n }\n /**\n * Override removeTab to prevent self-destruction when root.children\n * becomes empty. In TmuxSessionTab, an empty root is normal during\n * window switches and should not destroy the session tab.\n */\n removeTab(tab) {\n var _a;\n const parent = this.getParentOf(tab);\n if (!parent)\n return;\n const index = parent.children.indexOf(tab);\n parent.ratios.splice(index, 1);\n parent.children.splice(index, 1);\n tab.removeFromContainer();\n tab.parent = null;\n (_a = this.viewRefs) === null || _a === void 0 ? void 0 : _a.delete(tab);\n this.layout();\n // Do NOT destroy self when root is empty — this is normal during\n // tmux window switches.\n }\n /**\n }\n\n /**\n * Create a TmuxPaneTabComponent using TabsService (proper Angular DI).\n * This ensures the component has a hostView and ViewContainerRef.\n */\n createPaneTab(paneId) {\n this.logger.info(`Creating TmuxPaneTabComponent for pane %${paneId}`);\n const tab = this._tabsService.create({\n type: tmuxPaneTab_component_1.TmuxPaneTabComponent,\n inputs: {\n controller: this.controller,\n paneId,\n },\n });\n this.logger.info(`TmuxPaneTabComponent created for pane %${paneId}`);\n return tab;\n }\n /**\n * Handle a new pane being added to a window (real-time from tmux).\n *\n * NOTE: We do NOT call addTab here. Instead, we just register the pane in\n * the map and let syncLayout (called from the %layout-change event that\n * tmux sends alongside new-pane creation) build the correct tree.\n * Calling addTab with a fixed direction ('r') would create a wrong tree\n * structure that syncLayout then has to undo — and the async view\n * attachment inside addTab races with syncLayout, leaving panes invisible.\n */\n async handlePaneAdd(paneId, windowId) {\n if (!this.controller)\n return;\n let paneMap = this.windowPaneTabs.get(windowId);\n if (!paneMap) {\n paneMap = new Map();\n this.windowPaneTabs.set(windowId, paneMap);\n }\n if (paneMap.has(paneId)) {\n this.logger.debug(`Pane %${paneId} already tracked for window @${windowId}`);\n return;\n }\n // Create the pane tab and register it — the actual tree mounting\n // happens when syncLayout runs from the %layout-change event.\n const paneTab = this.createPaneTab(paneId);\n paneTab.controller = this.controller;\n paneTab.paneId = paneId;\n paneMap.set(paneId, paneTab);\n this.logger.info(`Registered new pane %${paneId} for window @${windowId}, awaiting layout sync`);\n }\n /**\n * Handle pane-update event (pane might have moved between windows).\n *\n * IMPORTANT: This method MUST NOT trigger switchToWindow or handlePaneAdd.\n * Doing so creates an infinite loop: pane-update → switchToWindow →\n * refreshPanes → pane-update → switchToWindow → ...\n *\n * Only handle panes already tracked in windowPaneTabs. Untracked panes\n * will be picked up by handlePaneAdd (from pane-add events triggered\n * by discoverPanesFromLayout on %layout-change).\n */\n handlePaneUpdate(paneId, windowId) {\n // Find which window currently owns this pane in our map\n let currentWindowId = null;\n for (const [wid, paneMap] of this.windowPaneTabs) {\n if (paneMap.has(paneId)) {\n currentWindowId = wid;\n break;\n }\n }\n if (currentWindowId === null) {\n // Pane not yet tracked — will be added via pane-add or switchToWindow\n return;\n }\n if (currentWindowId === windowId) {\n // Same window — no action needed\n return;\n }\n // Pane moved between windows — move the tab object\n this.logger.info(`Moving pane %${paneId} from window @${currentWindowId} to @${windowId}`);\n const oldPaneMap = this.windowPaneTabs.get(currentWindowId);\n const paneTab = oldPaneMap.get(paneId);\n if (paneTab) {\n oldPaneMap.delete(paneId);\n let newPaneMap = this.windowPaneTabs.get(windowId);\n if (!newPaneMap) {\n newPaneMap = new Map();\n this.windowPaneTabs.set(windowId, newPaneMap);\n }\n newPaneMap.set(paneId, paneTab);\n // If it was in the active window, remove from SplitTab\n if (currentWindowId === this.activeWindowId) {\n paneTab.emitVisibility(false);\n this.detachPaneView(paneTab);\n }\n }\n }\n /**\n * Handle a tmux window being closed.\n */\n async handleWindowClose(windowId) {\n const paneMap = this.windowPaneTabs.get(windowId);\n if (paneMap) {\n // Destroy all pane tabs for this window\n for (const paneTab of paneMap.values()) {\n if (windowId === this.activeWindowId) {\n paneTab.emitVisibility(false);\n this.detachPaneView(paneTab);\n }\n paneTab.destroy();\n }\n this.windowPaneTabs.delete(windowId);\n }\n // If we just closed the active window, switch to another one\n if (windowId === this.activeWindowId) {\n this.activeWindowId = null;\n const remainingWindows = Array.from(this.windowPaneTabs.keys());\n if (remainingWindows.length > 0) {\n await this.switchToWindow(remainingWindows[0]);\n }\n else {\n // No windows left — reset\n this.root = new tabby_core_1.SplitContainer();\n this.root.orientation = 'h';\n this.layout();\n this.cdr.detectChanges();\n }\n }\n }\n /**\n * Synchronize SplitTab layout with tmux's layout string.\n *\n * This is the SINGLE place where the SplitTab tree is built.\n * It creates missing pane tabs, attaches their views, cleans up stale\n * panes, and rebuilds the entire tree from the tmux layout string.\n */\n async syncLayout(layoutStr) {\n var _a;\n const layoutTree = (0, layoutParser_1.parseTmuxLayout)(layoutStr);\n if (!layoutTree) {\n this.logger.warn('Failed to parse layout:', layoutStr);\n return;\n }\n const panes = (0, layoutParser_1.flattenLayout)(layoutTree);\n this.logger.info(`Syncing layout for window @${this.activeWindowId}: ${panes.length} panes`);\n // Ensure pane tabs exist and have attached views for every pane in\n // the layout. New panes (from split-window) are registered by\n // handlePaneAdd but have no view yet — we call addTab to create one.\n if (this.activeWindowId !== null) {\n let paneMap = this.windowPaneTabs.get(this.activeWindowId);\n if (!paneMap) {\n paneMap = new Map();\n this.windowPaneTabs.set(this.activeWindowId, paneMap);\n }\n for (const pane of panes) {\n if (!paneMap.has(pane.paneId)) {\n this.logger.info(`Creating pane tab for %${pane.paneId} during layout sync`);\n const paneTab = this.createPaneTab(pane.paneId);\n paneTab.controller = this.controller;\n paneTab.paneId = pane.paneId;\n paneMap.set(pane.paneId, paneTab);\n }\n }\n // Attach views for panes that don't have one yet.\n // The tree structure will be rebuilt below, so the addTab direction\n // doesn't matter — we just need the view to exist.\n for (const pane of panes) {\n const paneTab = paneMap.get(pane.paneId);\n if (!((_a = this.viewRefs) === null || _a === void 0 ? void 0 : _a.has(paneTab))) {\n this.logger.info(`Attaching view for pane %${pane.paneId}`);\n const existingTabs = this.getAllTabs();\n if (existingTabs.length === 0) {\n await this.addTab(paneTab, null, 'r');\n }\n else {\n await this.addTab(paneTab, existingTabs[existingTabs.length - 1], 'r');\n }\n ;\n paneTab.emitVisibility(true);\n paneTab.emitFocused();\n }\n }\n }\n // Detect and clean up stale pane tabs that are no longer in the layout.\n // When tmux closes a pane, the %layout-change notification omits it.\n // We remove the corresponding tab so the UI stays consistent.\n if (this.activeWindowId !== null) {\n const paneMap = this.windowPaneTabs.get(this.activeWindowId);\n if (paneMap) {\n const layoutPaneIds = new Set(panes.map(p => p.paneId));\n for (const [paneId, paneTab] of paneMap) {\n if (!layoutPaneIds.has(paneId)) {\n this.logger.info(`Pane %${paneId} no longer in layout, cleaning up`);\n paneMap.delete(paneId);\n paneTab.emitVisibility(false);\n this.detachPaneView(paneTab);\n paneTab.destroy();\n }\n }\n }\n }\n // Build the SplitContainer tree from the parsed layout\n const newRoot = this.buildSplitContainerFromLayout(layoutTree);\n if (newRoot instanceof tabby_core_1.SplitContainer) {\n this.root = newRoot;\n this.layout();\n }\n else if (newRoot) {\n // Single pane — wrap in a container\n this.root = new tabby_core_1.SplitContainer();\n this.root.orientation = 'h';\n this.root.children.push(newRoot);\n this.root.ratios.push(1);\n this.layout();\n }\n this.cdr.detectChanges();\n // tmux is authoritative over each pane's character grid: push the exact\n // cell dimensions from the layout string into each xterm. This keeps\n // wrapping aligned with tmux and avoids any pixel-derived resize.\n this.applyLayoutGrids(layoutTree);\n }\n /**\n * Handle a pane being closed (from %pane-close event or manual cleanup).\n */\n handlePaneClose(paneId, windowId) {\n const paneMap = this.windowPaneTabs.get(windowId);\n if (!paneMap)\n return;\n const paneTab = paneMap.get(paneId);\n if (!paneTab)\n return;\n this.logger.info(`Cleaning up closed pane %${paneId} in window @${windowId}`);\n paneMap.delete(paneId);\n if (windowId === this.activeWindowId) {\n ;\n paneTab.emitVisibility(false);\n this.detachPaneView(paneTab);\n this.layout();\n this.cdr.detectChanges();\n }\n ;\n paneTab.destroy();\n }\n /**\n * Build a SplitContainer tree from a tmux layout node.\n */\n buildSplitContainerFromLayout(node) {\n if (node.type === 'pane' && node.paneId !== undefined && this.activeWindowId !== null) {\n const paneMap = this.windowPaneTabs.get(this.activeWindowId);\n return (paneMap === null || paneMap === void 0 ? void 0 : paneMap.get(node.paneId)) || null;\n }\n if (!node.children || node.children.length === 0) {\n return null;\n }\n const container = new tabby_core_1.SplitContainer();\n container.orientation = node.type === 'horizontal' ? 'h' : 'v';\n const totalSize = node.type === 'horizontal'\n ? node.children.reduce((sum, c) => sum + c.width, 0)\n : node.children.reduce((sum, c) => sum + c.height, 0);\n for (const child of node.children) {\n const childComponent = this.buildSplitContainerFromLayout(child);\n if (childComponent) {\n container.children.push(childComponent);\n const ratio = totalSize > 0\n ? (node.type === 'horizontal' ? child.width / totalSize : child.height / totalSize)\n : 1 / node.children.length;\n container.ratios.push(ratio);\n }\n }\n return container.children.length > 0 ? container : null;\n }\n /**\n * Refresh tmux client size based purely on the container (.pane-area) size.\n *\n * This is the SINGLE source of truth for the overall client size and is the\n * key to avoiding the resize feedback loop:\n *\n * - We compute the whole-window character grid from the .pane-area pixel\n * size divided by the xterm cell size. This value depends only on the\n * container, NOT on tmux's per-pane layout.\n * - tmux receives this via `refresh-client -C` and decides how to split\n * the grid among panes (sending %layout-change).\n * - On %layout-change we set each pane's xterm grid explicitly\n * (TmuxPaneTabComponent.setTmuxGrid) — panes never fit-to-pixels and\n * never report a size back up.\n *\n * Because the result is derived from the (stable) container size, a tmux\n * relayout does not change it, so `_lastSentCols/Rows` dedup terminates the\n * loop after a single iteration.\n */\n refreshClientSize() {\n if (!this.controller || !this._initialized)\n return;\n if (this.activeWindowId === null)\n return;\n const measured = this.measureClientSize();\n if (!measured) {\n // Cell size not available yet (no pane frontend mounted/rendered).\n // Retry shortly so the first real size still gets sent once a pane\n // has rendered its character grid — but only if panes are expected.\n const paneMap = this.windowPaneTabs.get(this.activeWindowId);\n if (paneMap && paneMap.size > 0) {\n this.scheduleRefreshClientSize();\n }\n return;\n }\n const { cols, rows } = measured;\n if (cols > 0 && rows > 0 &&\n (cols !== this._lastSentCols || rows !== this._lastSentRows)) {\n this._lastSentCols = cols;\n this._lastSentRows = rows;\n this.logger.info(`Setting tmux client size: ${cols}x${rows}`);\n this.controller.resizePane(0, cols, rows);\n }\n }\n /**\n * Apply the tmux-authoritative character grid to each mounted pane.\n *\n * tmux's layout string gives the exact width/height (in cells) of every\n * pane. We push those directly into the corresponding xterm so display\n * wrapping matches tmux exactly. xterm auto-fit is disabled for tmux panes,\n * so this is the only thing that sizes them.\n */\n applyLayoutGrids(layoutTree) {\n if (this.activeWindowId === null)\n return;\n const paneMap = this.windowPaneTabs.get(this.activeWindowId);\n if (!paneMap)\n return;\n for (const pane of (0, layoutParser_1.flattenLayout)(layoutTree)) {\n const paneTab = paneMap.get(pane.paneId);\n if (paneTab === null || paneTab === void 0 ? void 0 : paneTab.setTmuxGrid) {\n paneTab.setTmuxGrid(pane.width, pane.height);\n }\n }\n }\n /**\n * Measure the whole-window character grid from the .pane-area container.\n *\n * The container width includes per-pane decorations (xterm scrollbar +\n * padding) and UI spanner dividers, none of which belong to the tmux\n * character grid. We subtract them, divide by the real xterm cell size,\n * then add tmux's 1-char dividers between panes so tmux's own grid lines up.\n */\n measureClientSize() {\n var _a, _b;\n const host = this.hostElement.nativeElement;\n const paneArea = (_a = host.querySelector('.pane-area')) !== null && _a !== void 0 ? _a : host;\n const rect = paneArea.getBoundingClientRect();\n if (rect.width < 10 || rect.height < 10)\n return null;\n const cell = this.getCellSize();\n if (!cell)\n return null;\n // Determine pane/split counts for the active window.\n const paneMap = this.activeWindowId !== null\n ? this.windowPaneTabs.get(this.activeWindowId)\n : null;\n const paneCount = (_b = paneMap === null || paneMap === void 0 ? void 0 : paneMap.size) !== null && _b !== void 0 ? _b : 1;\n // UI spanner pixel widths: tabby's split-tab-spanner is 10px each.\n // Our custom tmux dividers are purely visual overlays with no pixel cost.\n // _spanners is still populated by layoutInternal() for tabby's internal\n // bookkeeping, but we no longer render split-tab-spanner elements, so\n // their pixel width should not be subtracted here.\n const spannerPx = 0;\n // Per-pane visual padding defined in tmuxPaneTab.component.scss.\n // Each pane has 4px on all sides (8px total per axis).\n // For N panes in a row: total horizontal padding = N * 8px.\n // For N panes in a column: total vertical padding = N * 8px.\n // Approximate as all panes contributing to both axes (safe overestimate).\n const panePadPerAxis = 8;\n const totalPadPx = paneCount * panePadPerAxis;\n const availableWidth = rect.width - spannerPx - totalPadPx;\n const availableHeight = rect.height - totalPadPx;\n const contentCols = Math.floor(availableWidth / cell.width);\n const contentRows = Math.floor(availableHeight / cell.height);\n // tmux inserts a 1-char divider between adjacent panes; add them back so\n // the size we report covers content + dividers (tmux subtracts them again\n // when splitting). Approximate as a horizontal split (most common case).\n const numDividers = Math.max(0, paneCount - 1);\n const cols = contentCols + numDividers;\n return {\n cols: Math.max(2, cols),\n rows: Math.max(1, contentRows),\n };\n }\n /**\n * Read the xterm character cell size (in CSS pixels) from any mounted pane.\n */\n getCellSize() {\n var _a, _b, _c, _d, _e, _f;\n for (const paneMap of this.windowPaneTabs.values()) {\n for (const paneTab of paneMap.values()) {\n const frontend = paneTab.frontend;\n const dims = (_b = (_a = frontend === null || frontend === void 0 ? void 0 : frontend.xtermCore) === null || _a === void 0 ? void 0 : _a._renderService) === null || _b === void 0 ? void 0 : _b.dimensions;\n if (((_d = (_c = dims === null || dims === void 0 ? void 0 : dims.css) === null || _c === void 0 ? void 0 : _c.cell) === null || _d === void 0 ? void 0 : _d.width) > 0 && ((_f = (_e = dims === null || dims === void 0 ? void 0 : dims.css) === null || _e === void 0 ? void 0 : _e.cell) === null || _f === void 0 ? void 0 : _f.height) > 0) {\n return { width: dims.css.cell.width, height: dims.css.cell.height };\n }\n }\n }\n return null;\n }\n /**\n * Debounced version of refreshClientSize.\n * Multiple sources (window resize, switchToWindow, layout-change) may\n * fire close together — debounce into one refresh-client -C call.\n */\n scheduleRefreshClientSize() {\n var _a, _b;\n if (this._resizeTimer)\n clearTimeout(this._resizeTimer);\n const debounceMs = (_b = (_a = this.configService.store.tmuxPlugin) === null || _a === void 0 ? void 0 : _a.resizeDebounceMs) !== null && _b !== void 0 ? _b : 150;\n this._resizeTimer = setTimeout(() => {\n this._resizeTimer = null;\n this.refreshClientSize();\n }, debounceMs);\n }\n /**\n * Attach mousemove + mousedown handlers to .pane-area so that hovering\n * near a .child's right/bottom border highlights it, and dragging starts\n * a tmux resize-pane operation.\n */\n attachPaneAreaBorderHandlers() {\n const host = this.hostElement.nativeElement;\n const paneArea = host.querySelector('.pane-area');\n if (!paneArea)\n return;\n const HIT = TmuxSessionTabComponent_1.BORDER_HIT;\n // Track which child + edge is currently hovered\n let hoveredChild = null;\n let hoveredEdge = null;\n const clearHover = () => {\n if (hoveredChild) {\n hoveredChild.classList.remove('border-hover-right', 'border-hover-bottom');\n }\n hoveredChild = null;\n hoveredEdge = null;\n paneArea.style.cursor = '';\n };\n const onMove = (e) => {\n const areaRect = paneArea.getBoundingClientRect();\n const mx = e.clientX - areaRect.left;\n const my = e.clientY - areaRect.top;\n // Find a .child whose right or bottom border is within HIT pixels\n clearHover();\n const children = paneArea.querySelectorAll('.child');\n for (const child of Array.from(children)) {\n const el = child;\n const r = el.getBoundingClientRect();\n const right = r.right - areaRect.left;\n const bottom = r.bottom - areaRect.top;\n const left = r.left - areaRect.left;\n const top = r.top - areaRect.top;\n // Right border hit: within HIT of right edge, vertically inside\n if (Math.abs(mx - right) <= HIT && my >= top && my <= bottom) {\n el.classList.add('border-hover-right');\n paneArea.style.cursor = 'col-resize';\n hoveredChild = el;\n hoveredEdge = 'right';\n break;\n }\n // Bottom border hit: within HIT of bottom edge, horizontally inside\n if (Math.abs(my - bottom) <= HIT && mx >= left && mx <= right) {\n el.classList.add('border-hover-bottom');\n paneArea.style.cursor = 'row-resize';\n hoveredChild = el;\n hoveredEdge = 'bottom';\n break;\n }\n }\n };\n const onDown = (e) => {\n if (!hoveredChild || !hoveredEdge || !this.controller)\n return;\n e.preventDefault();\n e.stopPropagation();\n const edge = hoveredEdge;\n const cell = this.getCellSize();\n if (!cell)\n return;\n const startX = e.clientX;\n const startY = e.clientY;\n // Find the pane ID for this .child element\n const resizeTarget = hoveredChild;\n const paneId = this.findPaneIdForElement(resizeTarget);\n if (paneId === null)\n return;\n // Track last sent delta to send incremental resize commands\n let lastSentCols = 0;\n let lastSentRows = 0;\n const onDragMove = (de) => {\n document.body.style.cursor = edge === 'right' ? 'col-resize' : 'row-resize';\n if (edge === 'right') {\n const deltaCols = Math.round((de.clientX - startX) / cell.width);\n if (deltaCols !== lastSentCols) {\n const diff = deltaCols - lastSentCols;\n const flag = diff > 0 ? '-R' : '-L';\n this.controller.gateway.sendCommand(`resize-pane ${flag} -t %${paneId} ${Math.abs(diff)}`);\n lastSentCols = deltaCols;\n }\n }\n else {\n const deltaRows = Math.round((de.clientY - startY) / cell.height);\n if (deltaRows !== lastSentRows) {\n const diff = deltaRows - lastSentRows;\n const flag = diff > 0 ? '-D' : '-U';\n this.controller.gateway.sendCommand(`resize-pane ${flag} -t %${paneId} ${Math.abs(diff)}`);\n lastSentRows = deltaRows;\n }\n }\n };\n const onDragUp = () => {\n document.removeEventListener('mousemove', onDragMove);\n document.removeEventListener('mouseup', onDragUp);\n document.body.style.cursor = '';\n clearHover();\n };\n document.addEventListener('mousemove', onDragMove);\n document.addEventListener('mouseup', onDragUp);\n };\n const onLeave = () => clearHover();\n this._paneAreaMouseMoveHandler = onMove;\n this._paneAreaMouseDownHandler = onDown;\n paneArea.addEventListener('mousemove', onMove);\n paneArea.addEventListener('mousedown', onDown);\n paneArea.addEventListener('mouseleave', onLeave);\n }\n detachPaneAreaBorderHandlers() {\n const host = this.hostElement.nativeElement;\n const paneArea = host.querySelector('.pane-area');\n if (!paneArea)\n return;\n if (this._paneAreaMouseMoveHandler) {\n paneArea.removeEventListener('mousemove', this._paneAreaMouseMoveHandler);\n this._paneAreaMouseMoveHandler = null;\n }\n if (this._paneAreaMouseDownHandler) {\n paneArea.removeEventListener('mousedown', this._paneAreaMouseDownHandler);\n this._paneAreaMouseDownHandler = null;\n }\n }\n /**\n * Map a .child DOM element back to the tmux pane ID it represents.\n */\n findPaneIdForElement(el) {\n var _a, _b, _c;\n if (this.activeWindowId === null)\n return null;\n const paneMap = this.windowPaneTabs.get(this.activeWindowId);\n if (!paneMap)\n return null;\n for (const [paneId, paneTab] of paneMap) {\n const tabEl = (_b = (_a = paneTab.hostElement) === null || _a === void 0 ? void 0 : _a.nativeElement) !== null && _b !== void 0 ? _b : (_c = paneTab.element) === null || _c === void 0 ? void 0 : _c.nativeElement;\n if (tabEl && (tabEl === el || tabEl.contains(el) || el.contains(tabEl))) {\n return paneId;\n }\n }\n return null;\n }\n // ─── (legacy divider stubs removed) ─────────────────────────────────────\n /**\n * Override onSpannerAdjusted to notify tmux of layout change.\n * When the user drags a spanner (split divider), the pane containers\n * resize and xterm.js auto-fits. We need to tell tmux the new client size\n * so it can recalculate its layout accordingly.\n */\n onSpannerAdjusted(spanner) {\n super.onSpannerAdjusted(spanner);\n this.scheduleRefreshClientSize();\n }\n // --- UI Event Handlers ---\n onDisconnect() {\n const ctx = this.tmuxService.findContextForTab(this);\n if (ctx) {\n this.tmuxService.disconnectContext(ctx);\n }\n }\n async onWindowClose(windowId) {\n if (this.controller) {\n await this.controller.killWindow(windowId);\n }\n }\n async onCreateWindow() {\n if (this.controller) {\n const newWindowId = await this.controller.createWindow();\n if (newWindowId !== null) {\n await this.switchToWindow(newWindowId);\n }\n }\n }\n ngOnDestroy() {\n if (this.eventSubscription) {\n this.eventSubscription.unsubscribe();\n }\n if (this._resizeHandler) {\n window.removeEventListener('resize', this._resizeHandler);\n this._resizeHandler = null;\n }\n if (this._paneAreaObserver) {\n this._paneAreaObserver.disconnect();\n this._paneAreaObserver = null;\n }\n if (this._resizeTimer) {\n clearTimeout(this._resizeTimer);\n this._resizeTimer = null;\n }\n this.detachPaneAreaBorderHandlers();\n super.ngOnDestroy();\n }\n async canClose() {\n return true;\n }\n /**\n * Override recovery to delegate to the hidden host tab.\n *\n * When Tabby saves tabs on exit, the original terminal tab (topmostTab)\n * is hidden from app.tabs and would be lost. Instead of persisting the\n * tmux session tab (which cannot be meaningfully restored), we return\n * the host tab's recovery token so Tabby restores the pre-tmux terminal.\n * The tmux session remains alive in the background and can be re-attached.\n */\n async getRecoveryToken(options) {\n const ctx = this.tmuxService.findContextForTab(this);\n if (ctx === null || ctx === void 0 ? void 0 : ctx.topmostTab) {\n return ctx.topmostTab.getRecoveryToken(options);\n }\n return null;\n }\n};\n// ─── Border-based pane separator ────────────────────────────────────────\n/** Pixels from the right/bottom edge of a .child that counts as \"on border\" */\nTmuxSessionTabComponent.BORDER_HIT = 10;\nTmuxSessionTabComponent.ctorParameters = () => [\n { type: core_1.Injector },\n { type: tmux_service_1.TmuxService },\n { type: tabby_core_1.ConfigService },\n { type: tabby_core_1.TabsService },\n { type: core_1.ChangeDetectorRef },\n { type: core_1.ElementRef },\n { type: tabby_core_1.LogService }\n];\nTmuxSessionTabComponent.propDecorators = {\n profile: [{ type: core_1.Input }],\n existingController: [{ type: core_1.Input }]\n};\nTmuxSessionTabComponent = TmuxSessionTabComponent_1 = __decorate([\n (0, core_1.Component)({\n selector: 'tmux-session-tab',\n host: {\n '[class.tmux-session-host]': 'true'\n },\n template: `\n <div class=\"pane-area\" #paneAreaEl>\n <ng-container #vc></ng-container>\n </div>\n <tmux-window-bar\n [controller]=\"controller\"\n [activeWindowId]=\"activeWindowId\"\n (windowSwitch)=\"switchToWindow($event)\"\n (windowClose)=\"onWindowClose($event)\"\n (disconnect)=\"onDisconnect()\"\n (createWindow)=\"onCreateWindow()\"\n ></tmux-window-bar>\n `,\n styles: [\"\\n :host {\\n position: relative;\\n display: flex;\\n flex-direction: column;\\n width: 100%;\\n height: 100%;\\n }\\n .pane-area {\\n flex: 1 1 0;\\n position: relative;\\n min-height: 0;\\n }\\n /* SplitTab.layoutInternal() positions .child with inline left/top/width/height %.\\n border-right + border-bottom render the tmux pane separator line.\\n box-sizing: border-box keeps the border inside the layout box so\\n xterm content is not displaced.\\n The border area also serves as the resize drag handle (see onPaneAreaMouseDown). */\\n ::ng-deep .pane-area > .child {\\n position: absolute;\\n transition: 0.125s all;\\n opacity: .75;\\n box-sizing: border-box;\\n border-right: 1px solid rgba(128,128,128,0.3);\\n border-bottom: 1px solid rgba(128,128,128,0.3);\\n }\\n ::ng-deep .pane-area > .child.focused {\\n opacity: 1;\\n }\\n /*\\n * Transparent hit-target overlays at the right/bottom edges.\\n * xterm renders a scrollbar (~14px wide) that intercepts mouse events,\\n * preventing the pane-area mousemove handler from detecting border\\n * proximity. These ::after pseudo-elements sit above the scrollbar\\n * (z-index: 10) and capture events for resize dragging.\\n */\\n ::ng-deep .pane-area > .child::after {\\n content: '';\\n position: absolute;\\n top: 0;\\n right: 0;\\n width: 10px;\\n height: 100%;\\n z-index: 10;\\n pointer-events: auto;\\n cursor: col-resize;\\n }\\n ::ng-deep .pane-area > .child::before {\\n content: '';\\n position: absolute;\\n bottom: 0;\\n left: 0;\\n width: 100%;\\n height: 10px;\\n z-index: 10;\\n pointer-events: auto;\\n cursor: row-resize;\\n }\\n /* Highlight the border when hovering near the right/bottom edge */\\n ::ng-deep .pane-area > .child.border-hover-right {\\n border-right-color: rgba(128,128,128,0.75);\\n }\\n ::ng-deep .pane-area > .child.border-hover-bottom {\\n border-bottom-color: rgba(128,128,128,0.75);\\n }\\n tmux-window-bar {\\n flex: 0 0 auto;\\n position: relative;\\n z-index: 10;\\n }\\n \"]\n }),\n __metadata(\"design:paramtypes\", [core_1.Injector,\n tmux_service_1.TmuxService,\n tabby_core_1.ConfigService,\n tabby_core_1.TabsService,\n core_1.ChangeDetectorRef,\n core_1.ElementRef,\n tabby_core_1.LogService])\n], TmuxSessionTabComponent);\nexports.TmuxSessionTabComponent = TmuxSessionTabComponent;\n","\"use strict\";\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n};\nvar __metadata = (this && this.__metadata) || function (k, v) {\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\n};\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.TmuxWindowBarComponent = void 0;\nconst core_1 = require(\"@angular/core\");\nconst session_1 = require(\"../session\");\nlet TmuxWindowBarComponent = class TmuxWindowBarComponent {\n constructor(cdr) {\n this.cdr = cdr;\n this.activeWindowId = null;\n this.windowSwitch = new core_1.EventEmitter();\n this.windowClose = new core_1.EventEmitter();\n this.disconnect = new core_1.EventEmitter();\n this.createWindow = new core_1.EventEmitter();\n this.windows = [];\n }\n ngOnInit() {\n this.refreshWindows();\n if (!this.controller) {\n return;\n }\n this.subscription = this.controller.events.subscribe(event => {\n switch (event.type) {\n case 'window-add':\n case 'window-close':\n case 'window-renamed':\n case 'pane-add':\n case 'pane-close':\n case 'initialized':\n this.refreshWindows();\n break;\n }\n });\n }\n ngOnDestroy() {\n var _a;\n (_a = this.subscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();\n }\n refreshWindows() {\n if (!this.controller) {\n this.windows = [];\n this.cdr.detectChanges();\n return;\n }\n const windowStates = this.controller.getAllWindowStates();\n this.windows = windowStates.map(ws => ({\n id: ws.id,\n name: ws.name,\n paneCount: ws.panes.size,\n }));\n this.cdr.detectChanges();\n }\n onCloseWindow(event, win) {\n event.stopPropagation();\n this.windowClose.emit(win.id);\n }\n onContextMenu(event, _win) {\n // Reserved for future context menu (rename, close window, etc.)\n event.preventDefault();\n }\n};\nTmuxWindowBarComponent.ctorParameters = () => [\n { type: core_1.ChangeDetectorRef }\n];\nTmuxWindowBarComponent.propDecorators = {\n controller: [{ type: core_1.Input }],\n activeWindowId: [{ type: core_1.Input }],\n windowSwitch: [{ type: core_1.Output }],\n windowClose: [{ type: core_1.Output }],\n disconnect: [{ type: core_1.Output }],\n createWindow: [{ type: core_1.Output }]\n};\nTmuxWindowBarComponent = __decorate([\n (0, core_1.Component)({\n selector: 'tmux-window-bar',\n template: `\n <div class=\"window-bar\">\n <div class=\"window-tabs\">\n <button\n *ngFor=\"let win of windows\"\n class=\"window-tab\"\n [class.active]=\"win.id === activeWindowId\"\n (click)=\"windowSwitch.emit(win.id)\"\n (contextmenu)=\"onContextMenu($event, win)\"\n [title]=\"win.name\"\n >\n <span class=\"window-name\">{{ win.name }}</span>\n <span class=\"pane-badge\" *ngIf=\"win.paneCount > 1\">{{ win.paneCount }}</span>\n <span class=\"window-close\" title=\"Close Window\" (click)=\"onCloseWindow($event, win)\">\n <i class=\"fas fa-times\"></i>\n </span>\n </button>\n <button class=\"window-tab add-btn\" title=\"New Window\" (click)=\"createWindow.emit()\">\n <i class=\"fas fa-plus\"></i>\n </button>\n </div>\n <div class=\"bar-actions\">\n <button class=\"bar-btn\" title=\"Disconnect\" (click)=\"disconnect.emit()\">\n <i class=\"fas fa-eject\"></i>\n </button>\n </div>\n </div>\n `,\n styles: [\"\\n :host {\\n display: block;\\n flex: 0 0 auto;\\n }\\n .window-bar {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n padding: 2px 8px;\\n background: rgba(30, 30, 30, 0.95);\\n border-top: 1px solid rgba(255, 255, 255, 0.1);\\n min-height: 28px;\\n overflow-x: auto;\\n }\\n .window-tabs {\\n display: flex;\\n align-items: center;\\n gap: 2px;\\n overflow-x: auto;\\n flex: 1;\\n min-width: 0;\\n }\\n .window-tab {\\n display: flex;\\n align-items: center;\\n gap: 4px;\\n height: 22px;\\n padding: 0 8px;\\n border: 1px solid transparent;\\n border-radius: 3px;\\n background: transparent;\\n color: #999;\\n font-size: 0.82em;\\n cursor: pointer;\\n white-space: nowrap;\\n transition: background 0.15s, color 0.15s, border-color 0.15s;\\n }\\n .window-tab:hover {\\n background: rgba(255, 255, 255, 0.08);\\n color: #ccc;\\n }\\n .window-tab.active {\\n background: rgba(255, 255, 255, 0.12);\\n color: #fff;\\n border-color: rgba(255, 255, 255, 0.15);\\n }\\n .pane-badge {\\n display: inline-flex;\\n align-items: center;\\n justify-content: center;\\n min-width: 16px;\\n height: 16px;\\n padding: 0 3px;\\n border-radius: 8px;\\n background: rgba(255, 255, 255, 0.1);\\n font-size: 0.85em;\\n color: #aaa;\\n }\\n .window-close {\\n display: inline-flex;\\n align-items: center;\\n justify-content: center;\\n margin-left: auto;\\n margin-right: -4px;\\n width: 14px;\\n height: 14px;\\n border-radius: 2px;\\n font-size: 0.7em;\\n color: transparent;\\n cursor: pointer;\\n visibility: hidden;\\n }\\n .window-tab:hover .window-close {\\n visibility: visible;\\n color: #888;\\n }\\n .window-close:hover {\\n background: rgba(255, 80, 80, 0.3);\\n color: #f66;\\n }\\n .add-btn {\\n color: #666;\\n padding: 0 6px;\\n }\\n .add-btn:hover {\\n color: #aaa;\\n }\\n .bar-actions {\\n display: flex;\\n align-items: center;\\n gap: 2px;\\n margin-left: 8px;\\n }\\n .bar-btn {\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n width: 24px;\\n height: 24px;\\n border: none;\\n border-radius: 3px;\\n background: transparent;\\n color: #888;\\n font-size: 0.8em;\\n cursor: pointer;\\n }\\n .bar-btn:hover {\\n background: rgba(255, 255, 255, 0.1);\\n color: #ccc;\\n }\\n \"]\n }),\n __metadata(\"design:paramtypes\", [core_1.ChangeDetectorRef])\n], TmuxWindowBarComponent);\nexports.TmuxWindowBarComponent = TmuxWindowBarComponent;\n","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.TmuxConfigProvider = void 0;\nconst tabby_core_1 = require(\"tabby-core\");\n// eslint-disable-next-line new-cap\nclass TmuxConfigProvider extends tabby_core_1.ConfigProvider {\n constructor() {\n super(...arguments);\n this.defaults = {\n tmuxPlugin: {\n defaultSessionName: 'default',\n commandTimeoutMs: 30000,\n sendKeysChunkSize: 200,\n resizeDebounceMs: 150,\n debugLogging: false,\n },\n };\n }\n}\nexports.TmuxConfigProvider = TmuxConfigProvider;\n","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.TmuxGateway = exports.TMUX_COMMAND_WANTS_DATA = exports.TMUX_COMMAND_TOLERATE_ERRORS = void 0;\nconst rxjs_1 = require(\"rxjs\");\nconst logHelper_1 = require(\"./logHelper\");\n// Command flags\nexports.TMUX_COMMAND_TOLERATE_ERRORS = 1 << 0;\nexports.TMUX_COMMAND_WANTS_DATA = 1 << 1;\nconst DEFAULT_COMMAND_TIMEOUT_MS = 30000;\nconst DEFAULT_SEND_KEYS_CHUNK_SIZE = 200;\n/**\n * TmuxGateway - Protocol layer for tmux control mode\n *\n * Handles:\n * - Command queuing with response matching\n * - Protocol parsing (%begin/%end/%error blocks)\n * - Notification dispatch\n * - Key encoding and sending\n */\nclass TmuxGateway {\n constructor(logger, writer, configService) {\n this.logger = logger;\n this.writer = writer;\n this.configService = configService;\n this.commandQueue = [];\n this.currentCommand = null;\n this.currentCommandId = '';\n this.currentResponse = [];\n this.inResponseBlock = false;\n this.nextCommandId = 1;\n this.disconnected = false;\n this.detachSent = false;\n this.acceptNotifications = false;\n this.initialized = false;\n /** Number of fire-and-forget writes whose %begin/%end responses need consuming */\n this.directWritesPending = 0;\n /** Incomplete line buffer for byte-level DCS parsing */\n this.lineBuffer = '';\n this.minimumServerVersion = null;\n this.maximumServerVersion = null;\n this.pauseModeEnabled = false;\n // Events for notifications\n this.output$ = new rxjs_1.Subject();\n this.layoutChange$ = new rxjs_1.Subject();\n this.windowAdd$ = new rxjs_1.Subject();\n this.windowClose$ = new rxjs_1.Subject();\n this.windowRenamed$ = new rxjs_1.Subject();\n this.sessionChanged$ = new rxjs_1.Subject();\n this.sessionsChanged$ = new rxjs_1.Subject();\n this.paneChanged$ = new rxjs_1.Subject();\n this.sessionWindowChanged$ = new rxjs_1.Subject();\n this.paneClose$ = new rxjs_1.Subject();\n this.exit$ = new rxjs_1.Subject();\n this.initialized$ = new rxjs_1.Subject();\n }\n get log() {\n return (0, logHelper_1.createConditionalLogger)(this.logger, this.configService);\n }\n get commandTimeoutMs() {\n var _a, _b, _c;\n return (_c = (_b = (_a = this.configService) === null || _a === void 0 ? void 0 : _a.store.tmuxPlugin) === null || _b === void 0 ? void 0 : _b.commandTimeoutMs) !== null && _c !== void 0 ? _c : DEFAULT_COMMAND_TIMEOUT_MS;\n }\n get sendKeysChunkSize() {\n var _a, _b, _c;\n return (_c = (_b = (_a = this.configService) === null || _a === void 0 ? void 0 : _a.store.tmuxPlugin) === null || _b === void 0 ? void 0 : _b.sendKeysChunkSize) !== null && _c !== void 0 ? _c : DEFAULT_SEND_KEYS_CHUNK_SIZE;\n }\n /**\n * Send a single command and wait for response\n */\n async sendCommand(command, flags = 0) {\n if (this.detachSent || this.disconnected) {\n throw new Error('Gateway disconnected');\n }\n const original = new Promise((resolve, reject) => {\n const cmd = {\n id: this.nextCommandId++,\n command,\n resolve,\n reject,\n flags,\n timestamp: Date.now()\n };\n this.commandQueue.push(cmd);\n this.write(command + '\\r');\n this.log.debug(`Sent command: ${command}`);\n });\n // Race against timeout — if tmux never responds, reject instead of hanging\n let timer;\n const timeout = new Promise((_, reject) => {\n timer = setTimeout(() => {\n // Remove the timed-out command from the queue so it won't\n // consume a later response and cause command-id mismatch.\n reject(new Error(`Command timed out after ${this.commandTimeoutMs}ms: ${command}`));\n }, this.commandTimeoutMs);\n });\n // Clean up timer when original settles\n original.then(() => clearTimeout(timer), () => clearTimeout(timer));\n return Promise.race([original, timeout]);\n }\n /**\n * Send a list of commands atomically (separated by ;)\n */\n async sendCommandList(commands) {\n if (this.detachSent || this.disconnected || commands.length === 0) {\n return [];\n }\n const promises = [];\n const combined = commands.map((c) => {\n const promise = new Promise((resolve, reject) => {\n const cmd = {\n id: this.nextCommandId++,\n command: c.command,\n resolve,\n reject,\n flags: c.flags || 0,\n timestamp: Date.now()\n };\n this.commandQueue.push(cmd);\n });\n promises.push(promise);\n return c.command;\n }).join('; ');\n this.write(combined + '\\r');\n this.log.debug(`Sent command list: ${combined}`);\n return Promise.all(promises);\n }\n /**\n * Send keystrokes to a specific pane.\n *\n * Writes directly to the PTY — bypasses the command queue for zero-latency\n * input. tmux will still send %begin/%end for the send-keys command;\n * parseBegin() tracks these via directWritesPending so they are consumed\n * without trying to dequeue a queued command.\n */\n sendKeys(data, paneId) {\n var _a;\n if (this.disconnected)\n return;\n const hex = data.toString('hex');\n if (hex.length > 0) {\n // Split into chunks to avoid command length limits\n for (let i = 0; i < hex.length; i += this.sendKeysChunkSize) {\n const chunk = hex.substring(i, i + this.sendKeysChunkSize);\n const hexBytes = ((_a = chunk.match(/.{2}/g)) === null || _a === void 0 ? void 0 : _a.join(' ')) || '';\n // Write directly — bypasses command queue for zero-latency input\n this.write(`send-keys -t %${paneId} -H ${hexBytes}\\r`);\n this.directWritesPending++;\n }\n }\n }\n /**\n * Request detach\n */\n detach() {\n if (!this.detachSent) {\n this.write('detach\\r');\n this.detachSent = true;\n }\n }\n /**\n * Feed raw PTY data. Buffers incomplete lines across calls so that TCP\n * fragment boundaries never split a protocol line.\n */\n executeData(data) {\n this.lineBuffer += data.toString('utf-8');\n let newlineIdx;\n while ((newlineIdx = this.lineBuffer.indexOf('\\n')) !== -1) {\n const rawLine = this.lineBuffer.substring(0, newlineIdx);\n this.lineBuffer = this.lineBuffer.substring(newlineIdx + 1);\n const line = rawLine.replace(/\\r$/, '');\n if (line) {\n this.executeLine(line);\n }\n }\n }\n /**\n * Process a single complete line from tmux control mode\n */\n executeLine(line) {\n // Strip DCS artifacts\n line = line.replace(/^\\x1bP\\d+p/, '').replace(/^P\\d+p/, '').replace(/\\x1b\\\\$/, '');\n if (!line)\n return;\n this.log.info(`Received: ${line.substring(0, 100)}${line.length > 100 ? '...' : ''}`);\n // Handle response blocks\n if (this.inResponseBlock) {\n if (line.startsWith(`%end ${this.currentCommandId}`) ||\n line.startsWith(`%end `)) {\n this.stripLastNewline();\n this.finishCurrentCommand(false);\n return;\n }\n else if (line.startsWith(`%error ${this.currentCommandId}`) ||\n line.startsWith(`%error `)) {\n this.stripLastNewline();\n this.finishCurrentCommand(true);\n return;\n }\n else if (line.startsWith('%exit')) {\n // Tmux 1.8 bug workaround\n this.stripLastNewline();\n this.finishCurrentCommand(false);\n // Fall through to handle %exit\n }\n else if (line.startsWith('%output ') || line.startsWith('%extended-output ')) {\n // Dispatch pane output notifications even during response blocks.\n // Otherwise they get accumulated as garbage text in the command\n // response (e.g. capture-pane) and the live output is lost.\n if (this.acceptNotifications) {\n if (line.startsWith('%output ')) {\n this.parseOutput(line);\n }\n else {\n this.parseExtendedOutput(line);\n }\n }\n return;\n }\n else {\n // Accumulate response\n this.currentResponse.push(line);\n return;\n }\n }\n // Handle notifications and commands\n if (line.startsWith('%begin')) {\n this.parseBegin(line);\n }\n else if (line.startsWith('%output ')) {\n if (this.acceptNotifications) {\n this.log.info(`Parsing output line: ${line.substring(0, 50)}...`);\n this.parseOutput(line);\n }\n else {\n this.log.warn(`Ignored output (not accepting notifications): ${line.substring(0, 50)}...`);\n }\n }\n else if (line.startsWith('%extended-output ')) {\n if (this.acceptNotifications) {\n this.parseExtendedOutput(line);\n }\n }\n else if (line.startsWith('%layout-change ')) {\n if (this.acceptNotifications) {\n this.parseLayoutChange(line);\n }\n }\n else if (line.startsWith('%window-add')) {\n if (this.acceptNotifications) {\n this.parseWindowAdd(line);\n }\n }\n else if (line.startsWith('%window-close') || line.startsWith('%unlinked-window-close')) {\n if (this.acceptNotifications) {\n this.parseWindowClose(line);\n }\n }\n else if (line.startsWith('%window-renamed') || line.startsWith('%unlinked-window-renamed')) {\n if (this.acceptNotifications) {\n this.parseWindowRenamed(line);\n }\n }\n else if (line.startsWith('%session-changed')) {\n this.parseSessionChanged(line);\n }\n else if (line.startsWith('%sessions-changed')) {\n if (this.acceptNotifications) {\n this.sessionsChanged$.next();\n }\n }\n else if (line.startsWith('%session-window-changed')) {\n if (this.acceptNotifications) {\n this.parseSessionWindowChanged(line);\n }\n }\n else if (line.startsWith('%window-pane-changed')) {\n if (this.acceptNotifications) {\n this.parsePaneChanged(line);\n }\n }\n else if (line.startsWith('%pane-close') || line.startsWith('%unlinked-pane-close')) {\n if (this.acceptNotifications) {\n this.parsePaneClose(line);\n }\n }\n else if (line.startsWith('%pause') || line.startsWith('%continue')) {\n // Flow control notifications (tmux 3.2+) — acknowledged\n this.log.debug(`Flow control: ${line}`);\n }\n else if (line.startsWith('%no-output')) {\n // Empty response block — no action needed\n }\n else if (line.startsWith('%exit')) {\n this.parseExit(line);\n }\n else if (line.startsWith('%')) {\n // Unknown notification, ignore\n this.log.debug(`Unknown notification: ${line}`);\n }\n }\n // --- Protocol Parsing ---\n parseBegin(line) {\n // %begin timestamp commandId flags\n // Format: %begin 1767853190 875 1\n // tmux Control Mode docs: flags is always 1 for client-originated.\n const parts = line.split(' ');\n if (parts.length < 3) {\n this.logger.warn(`Malformed %begin: ${line}`);\n return;\n }\n const commandId = parts[2];\n this.currentCommandId = commandId;\n this.currentResponse = [];\n this.inResponseBlock = true;\n // If this response is for a fire-and-forget write (sendKeys),\n // consume it without dequeuing a queued command.\n if (this.commandQueue.length === 0 && this.directWritesPending > 0) {\n this.directWritesPending--;\n this.currentCommand = null;\n return;\n }\n if (this.commandQueue.length === 0) {\n // Server-initiated or unexpected response block\n this.currentCommand = null;\n return;\n }\n this.currentCommand = this.commandQueue.shift();\n }\n finishCurrentCommand(isError) {\n this.inResponseBlock = false;\n const response = this.currentResponse.join('\\n');\n if (this.currentCommand) {\n if (isError && !(this.currentCommand.flags & exports.TMUX_COMMAND_TOLERATE_ERRORS)) {\n this.currentCommand.reject(new Error(response));\n }\n else {\n this.currentCommand.resolve(response);\n }\n this.currentCommand = null;\n }\n // Mark as initialized after first successful response\n if (!this.initialized) {\n this.initialized = true;\n this.acceptNotifications = true;\n this.initialized$.next();\n }\n }\n stripLastNewline() {\n if (this.currentResponse.length > 0) {\n const last = this.currentResponse[this.currentResponse.length - 1];\n if (last === '') {\n this.currentResponse.pop();\n }\n }\n }\n parseOutput(line) {\n // %output %<pane> <data>\n const match = line.match(/^%output %(\\d+) (.*)$/);\n if (!match) {\n this.logger.error(`Output regex FAILED for line: <${line}>`);\n return;\n }\n const paneId = parseInt(match[1]);\n const data = this.decodeOutput(match[2]);\n this.log.info(`Parsed output for pane %${paneId}: ${data.length} bytes (match_len=${match[2].length})`);\n this.output$.next({ paneId, data });\n }\n parseExtendedOutput(line) {\n // %extended-output %<pane> <latency> : <data>\n const match = line.match(/^%extended-output %(\\d+) (\\d+) : (.*)$/);\n if (!match)\n return;\n const paneId = parseInt(match[1]);\n const latency = parseInt(match[2]) / 1000; // Convert ms to seconds\n const data = this.decodeOutput(match[3]);\n this.output$.next({ paneId, data, latency });\n }\n parseLayoutChange(line) {\n // %layout-change @<window> <layout> [visible_layout flags]\n const match = line.match(/^%layout-change @(\\d+) (.+)$/);\n if (!match)\n return;\n const windowId = parseInt(match[1]);\n const parts = match[2].split(' ');\n const layout = parts[0];\n const visibleLayout = parts.length > 1 ? parts[1] : undefined;\n const zoomed = parts.length > 2 ? parts[2].includes('Z') : undefined;\n this.layoutChange$.next({ windowId, layout, visibleLayout, zoomed });\n }\n parseWindowAdd(line) {\n // %window-add @<id>\n const match = line.match(/^%window-add @(\\d+)$/);\n if (match) {\n this.windowAdd$.next(parseInt(match[1]));\n }\n }\n parseWindowClose(line) {\n // %window-close @<id> or %unlinked-window-close @<id>\n const match = line.match(/@(\\d+)$/);\n if (match) {\n this.windowClose$.next(parseInt(match[1]));\n }\n }\n parseWindowRenamed(line) {\n // %window-renamed @<id> <name>\n const match = line.match(/^%(?:unlinked-)?window-renamed @(\\d+) (.+)$/);\n if (match) {\n this.windowRenamed$.next({\n windowId: parseInt(match[1]),\n name: this.unescapeTmuxWindowName(match[2])\n });\n }\n }\n parseSessionChanged(line) {\n // %session-changed $<id> <name>\n const match = line.match(/^%session-changed \\$(\\d+) (.+)$/);\n if (match) {\n this.sessionChanged$.next({\n sessionId: parseInt(match[1]),\n sessionName: match[2]\n });\n // Enable notifications after session change\n this.acceptNotifications = true;\n }\n }\n parseSessionWindowChanged(line) {\n // %session-window-changed $session @window\n const match = line.match(/^%session-window-changed \\$\\d+ @(\\d+)/);\n if (match) {\n this.sessionWindowChanged$.next({\n windowId: parseInt(match[1])\n });\n }\n }\n parsePaneChanged(line) {\n // %window-pane-changed @<window> %<pane>\n const match = line.match(/^%window-pane-changed @(\\d+) %(\\d+)$/);\n if (match) {\n this.paneChanged$.next({\n windowId: parseInt(match[1]),\n paneId: parseInt(match[2])\n });\n }\n }\n parsePaneClose(line) {\n // %pane-close @<window> %<pane>\n const match = line.match(/^%(?:unlinked-)?pane-close @(\\d+) %(\\d+)$/);\n if (match) {\n this.paneClose$.next({\n windowId: parseInt(match[1]),\n paneId: parseInt(match[2])\n });\n }\n }\n parseExit(line) {\n // %exit or %exit <reason>\n const reason = line.replace(/^%exit\\s*/, '');\n this.exit$.next(reason);\n this.disconnected = true;\n }\n // --- Utility Methods ---\n write(data) {\n this.writer(data);\n }\n /**\n * Decode tmux octal-escaped output to Buffer\n */\n decodeOutput(str) {\n const bytes = [];\n for (let i = 0; i < str.length; i++) {\n if (str[i] === '\\\\' && i + 3 < str.length) {\n const octal = str.substring(i + 1, i + 4);\n if (/^[0-7]{3}$/.test(octal)) {\n bytes.push(parseInt(octal, 8));\n i += 3;\n continue;\n }\n }\n // Handle UTF-8 properly\n const buf = Buffer.from(str[i], 'utf-8');\n for (const byte of buf) {\n bytes.push(byte);\n }\n }\n return Buffer.from(bytes);\n }\n unescapeTmuxWindowName(name) {\n // Tmux may escape window names\n return name.replace(/\\\\(.)/g, '$1');\n }\n /**\n * Check if server version is at least the given version\n */\n versionAtLeast(version) {\n return this.minimumServerVersion !== null && this.minimumServerVersion >= version;\n }\n}\nexports.TmuxGateway = TmuxGateway;\n","\"use strict\";\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n var desc = Object.getOwnPropertyDescriptor(m, k);\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\n desc = { enumerable: true, get: function() { return m[k]; } };\n }\n Object.defineProperty(o, k2, desc);\n}) : (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n o[k2] = m[k];\n}));\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n}) : function(o, v) {\n o[\"default\"] = v;\n});\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n};\nvar __importStar = (this && this.__importStar) || function (mod) {\n if (mod && mod.__esModule) return mod;\n var result = {};\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\n __setModuleDefault(result, mod);\n return result;\n};\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst core_1 = require(\"@angular/core\");\nconst common_1 = require(\"@angular/common\");\nconst forms_1 = require(\"@angular/forms\");\nconst tabby_core_1 = __importStar(require(\"tabby-core\"));\nconst tabby_settings_1 = require(\"tabby-settings\");\nconst tabContextMenu_1 = require(\"./tabContextMenu\");\nconst config_1 = require(\"./config\");\nconst settings_1 = require(\"./settings\");\nconst tmuxPaneTab_component_1 = require(\"./components/tmuxPaneTab.component\");\nconst tmuxSessionTab_component_1 = require(\"./components/tmuxSessionTab.component\");\nconst tmuxWindowBar_component_1 = require(\"./components/tmuxWindowBar.component\");\nconst settings_component_1 = require(\"./components/settings.component\");\nlet TmuxModule = class TmuxModule {\n};\nTmuxModule = __decorate([\n (0, core_1.NgModule)({\n imports: [\n common_1.CommonModule,\n forms_1.FormsModule,\n tabby_core_1.default,\n ],\n providers: [\n { provide: tabby_core_1.TabContextMenuItemProvider, useClass: tabContextMenu_1.TmuxContextMenuProvider, multi: true },\n { provide: tabby_core_1.ConfigProvider, useClass: config_1.TmuxConfigProvider, multi: true },\n { provide: tabby_settings_1.SettingsTabProvider, useClass: settings_1.TmuxSettingsTabProvider, multi: true },\n ],\n declarations: [\n tmuxPaneTab_component_1.TmuxPaneTabComponent,\n tmuxSessionTab_component_1.TmuxSessionTabComponent,\n tmuxWindowBar_component_1.TmuxWindowBarComponent,\n settings_component_1.TmuxSettingsTabComponent,\n ],\n entryComponents: [\n tmuxPaneTab_component_1.TmuxPaneTabComponent,\n tmuxSessionTab_component_1.TmuxSessionTabComponent,\n settings_component_1.TmuxSettingsTabComponent,\n ],\n })\n], TmuxModule);\nexports.default = TmuxModule;\n","\"use strict\";\n/**\n * TmuxLayoutParser - Parse tmux layout strings to extract pane positions\n *\n * Tmux layout string format:\n * - Checksum,WxH,X,Y<content>\n * - Content can be:\n * - Just a pane ID: \"93x52,0,0,185\"\n * - Vertical split [...]: contains comma-separated panes stacked top-to-bottom\n * - Horizontal split {...}: contains comma-separated panes arranged left-to-right\n *\n * Example: \"41e9,279x71,0,0[279x40,0,0,71,279x30,0,41{147x30,0,41,72,131x30,148,41,73}]\"\n */\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.layoutToSplitFormat = exports.flattenLayout = exports.parseTmuxLayout = void 0;\n/**\n * Parse a tmux layout string into a tree structure\n */\nfunction parseTmuxLayout(layoutStr) {\n if (!layoutStr)\n return null;\n // Remove checksum if present (4 hex chars followed by comma)\n const checksumMatch = layoutStr.match(/^[0-9a-f]{4},/);\n if (checksumMatch) {\n layoutStr = layoutStr.substring(5);\n }\n try {\n return parseNode(layoutStr, 0).node;\n }\n catch (e) {\n console.error('Failed to parse tmux layout:', e);\n return null;\n }\n}\nexports.parseTmuxLayout = parseTmuxLayout;\n/**\n * Parse a single node from the layout string\n */\nfunction parseNode(str, start) {\n // Parse dimension: WxH,X,Y\n const dimMatch = str.substring(start).match(/^(\\d+)x(\\d+),(\\d+),(\\d+)/);\n if (!dimMatch) {\n throw new Error(`Invalid dimension at position ${start}: ${str.substring(start, start + 20)}`);\n }\n const width = parseInt(dimMatch[1]);\n const height = parseInt(dimMatch[2]);\n const x = parseInt(dimMatch[3]);\n const y = parseInt(dimMatch[4]);\n let pos = start + dimMatch[0].length;\n // Check what follows\n if (pos >= str.length) {\n // End of string - this shouldn't happen for a complete layout\n throw new Error('Unexpected end of layout string');\n }\n const nextChar = str[pos];\n if (nextChar === '[') {\n // Vertical split (top-to-bottom) — tmux [...] = panes stacked vertically\n pos++; // skip '['\n const children = [];\n while (str[pos] !== ']') {\n const result = parseNode(str, pos);\n children.push(result.node);\n pos = result.consumed;\n if (str[pos] === ',') {\n pos++; // skip comma between children\n }\n }\n pos++; // skip ']'\n return {\n node: { type: 'vertical', x, y, width, height, children },\n consumed: pos\n };\n }\n else if (nextChar === '{') {\n // Horizontal split (left-to-right) — tmux {...} = panes side by side\n pos++; // skip '{'\n const children = [];\n while (str[pos] !== '}') {\n const result = parseNode(str, pos);\n children.push(result.node);\n pos = result.consumed;\n if (str[pos] === ',') {\n pos++; // skip comma between children\n }\n }\n pos++; // skip '}'\n return {\n node: { type: 'horizontal', x, y, width, height, children },\n consumed: pos\n };\n }\n else if (nextChar === ',' || nextChar === ']' || nextChar === '}' || pos >= str.length) {\n // This is a pane - the next number is the pane ID\n // But wait, we need to check if there's a pane ID\n // The format is WxH,X,Y,PaneID for a simple pane\n if (nextChar === ',') {\n pos++; // skip comma\n const paneIdMatch = str.substring(pos).match(/^(\\d+)/);\n if (paneIdMatch) {\n const paneId = parseInt(paneIdMatch[1]);\n pos += paneIdMatch[0].length;\n return {\n node: { type: 'pane', x, y, width, height, paneId },\n consumed: pos\n };\n }\n }\n // No pane ID found, this might be a container\n return {\n node: { type: 'pane', x, y, width, height },\n consumed: pos\n };\n }\n else {\n throw new Error(`Unexpected character '${nextChar}' at position ${pos}`);\n }\n}\n/**\n * Flatten a layout tree into a list of panes\n */\nfunction flattenLayout(node) {\n const panes = [];\n function traverse(n) {\n if (n.type === 'pane' && n.paneId !== undefined) {\n panes.push({\n paneId: n.paneId,\n x: n.x,\n y: n.y,\n width: n.width,\n height: n.height\n });\n }\n if (n.children) {\n for (const child of n.children) {\n traverse(child);\n }\n }\n }\n traverse(node);\n return panes;\n}\nexports.flattenLayout = flattenLayout;\nfunction layoutToSplitFormat(node) {\n var _a;\n if (node.type === 'pane') {\n return (_a = node.paneId) !== null && _a !== void 0 ? _a : null;\n }\n if (!node.children || node.children.length === 0) {\n return null;\n }\n const orientation = node.type === 'horizontal' ? 'horizontal' : 'vertical';\n // Calculate ratios based on dimensions\n const totalSize = orientation === 'horizontal'\n ? node.children.reduce((sum, c) => sum + c.width, 0)\n : node.children.reduce((sum, c) => sum + c.height, 0);\n const ratios = node.children.map(c => orientation === 'horizontal'\n ? c.width / totalSize\n : c.height / totalSize);\n const children = node.children.map(c => layoutToSplitFormat(c)).filter(c => c !== null);\n return { orientation, ratios, children: children };\n}\nexports.layoutToSplitFormat = layoutToSplitFormat;\n","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.createConditionalLogger = void 0;\n/**\n * Wrap a Logger so that debug/info are gated behind debugLogging config,\n * while warn/error always pass through.\n */\nfunction createConditionalLogger(logger, configService) {\n return {\n debug: (...args) => {\n var _a, _b;\n if ((_b = (_a = configService === null || configService === void 0 ? void 0 : configService.store) === null || _a === void 0 ? void 0 : _a.tmuxPlugin) === null || _b === void 0 ? void 0 : _b.debugLogging)\n logger.debug(...args);\n },\n info: (...args) => {\n var _a, _b;\n if ((_b = (_a = configService === null || configService === void 0 ? void 0 : configService.store) === null || _a === void 0 ? void 0 : _a.tmuxPlugin) === null || _b === void 0 ? void 0 : _b.debugLogging)\n logger.info(...args);\n },\n warn: logger.warn.bind(logger),\n error: logger.error.bind(logger),\n };\n}\nexports.createConditionalLogger = createConditionalLogger;\n","\"use strict\";\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n};\nvar __metadata = (this && this.__metadata) || function (k, v) {\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\n};\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.TmuxService = exports.TmuxOutputInterceptor = void 0;\nconst core_1 = require(\"@angular/core\");\nconst tabby_core_1 = require(\"tabby-core\");\nconst logHelper_1 = require(\"../logHelper\");\nconst tabby_terminal_1 = require(\"tabby-terminal\");\nconst rxjs_1 = require(\"rxjs\");\nconst session_1 = require(\"../session\");\nconst tmuxSessionTab_component_1 = require(\"../components/tmuxSessionTab.component\");\n/**\n * Middleware inserted at position 0 of the original session's middleware chain\n * when entering tmux mode. It captures raw output data for the tmux gateway\n * and BLOCKS it from propagating further, so that other middleware plugins\n * (e.g. trzsz) on the original session do not see tmux control mode data.\n *\n * Without this interceptor, trzsz middleware on the original session would\n * detect trzsz protocol markers embedded in %output lines and trigger\n * chooseSendFiles() a second time (\"double file dialog\" bug).\n */\nclass TmuxOutputInterceptor extends tabby_terminal_1.SessionMiddleware {\n constructor() {\n super(...arguments);\n this._rawOutput = new rxjs_1.Subject();\n /** Raw session output, before any middleware processing */\n this.rawOutput$ = this._rawOutput.asObservable();\n // feedFromTerminal is NOT overridden — terminal→session data flows\n // through normally so the session can still receive input.\n }\n feedFromSession(data) {\n // Capture raw data for the tmux gateway\n this._rawOutput.next(data);\n // Do NOT call super.feedFromSession() — this blocks data from\n // propagating to the rest of the middleware chain (trzsz, etc.)\n }\n}\nexports.TmuxOutputInterceptor = TmuxOutputInterceptor;\nlet TmuxService = class TmuxService {\n constructor(injector, appService, configService, log) {\n this.injector = injector;\n this.appService = appService;\n this.configService = configService;\n this.sessions = new Set();\n this.logger = log.create('tmux-service');\n }\n get log() {\n return (0, logHelper_1.createConditionalLogger)(this.logger, this.configService);\n }\n get isConnected() {\n return this.sessions.size > 0;\n }\n get controller() {\n var _a;\n return ((_a = this.sessions.values().next().value) === null || _a === void 0 ? void 0 : _a.controller) || null;\n }\n /**\n * Find the SessionContext that owns a given sessionTab.\n */\n findContextForTab(tab) {\n for (const ctx of this.sessions) {\n if (ctx.sessionTab === tab)\n return ctx;\n }\n return undefined;\n }\n setupControllerEvents(context) {\n context.subscriptions.push(context.controller.events.subscribe(event => {\n // On initialized, replace the terminal tab with the session tab\n if (event.type === 'initialized' && !context.sessionTab) {\n this.replaceWithSessionTab(context);\n }\n }));\n }\n replaceWithSessionTab(context) {\n if (context.sessionTab)\n return;\n this.log.info('Creating TmuxSessionTab...');\n // Find the topmost parent tab (the actual tab listed in the top tab bar)\n const topmostTab = context.terminalTab.topmostParent || context.terminalTab;\n context.topmostTab = topmostTab;\n // Remember the original index so we can replace in-place\n const tabs = this.appService.tabs;\n const index = tabs.indexOf(topmostTab);\n context.topmostTabIndex = index;\n // IMPORTANT: We must use openNewTabRaw, NOT openNewTab.\n // openNewTab wraps non-SplitTab types in a wrapper SplitTab via wrapAndAddTab().\n // But TmuxSessionTabComponent extends SplitTabComponent, and wrapAndAddTab's\n // SplitTab.addTab(thing) has special logic: when thing instanceof SplitTabComponent,\n // it extracts thing.root and then DESTROYS thing. This kills our component instance\n // before it ever gets rendered, so ngOnInit/ngAfterViewInit never fire.\n //\n // openNewTabRaw adds the tab directly without wrapping, so our component's\n // view is properly attached and lifecycle hooks execute normally.\n const sessionTab = this.appService.openNewTabRaw({\n type: tmuxSessionTab_component_1.TmuxSessionTabComponent,\n inputs: {\n existingController: context.controller,\n profile: { sessionName: context.controller.getSessionName() },\n },\n });\n context.sessionTab = sessionTab;\n // Move the session tab to the same position as the original tab\n if (index !== -1) {\n const sessionIndex = tabs.indexOf(sessionTab);\n if (sessionIndex !== -1) {\n tabs.splice(sessionIndex, 1); // remove from end\n tabs.splice(index, 0, sessionTab) // insert at original position\n ;\n this.appService.tabsChanged.next();\n }\n }\n // Hide the original topmost tab\n if (index !== -1) {\n const origIndex = tabs.indexOf(topmostTab);\n if (origIndex !== -1) {\n tabs.splice(origIndex, 1);\n this.appService.tabsChanged.next();\n }\n }\n // When the session tab is closed (by user or disconnect), clean up\n context.subscriptions.push(sessionTab.destroyed$.subscribe(() => {\n context.sessionTab = undefined;\n }));\n }\n async disconnectContext(context) {\n var _a;\n this.sessions.delete(context);\n context.subscriptions.forEach(s => s.unsubscribe());\n // Detach from tmux control mode so the tmux client process exits\n // cleanly. Without this, the original terminal tab's PTY still has\n // a running `tmux -CC attach` process, causing \"tmux is still running\"\n // confirmation dialogs when the user tries to close the restored tab.\n context.controller.gateway.detach();\n // Remove the output interceptor from the original session's middleware chain\n if (context.outputInterceptor) {\n (_a = context.terminalTab.session) === null || _a === void 0 ? void 0 : _a.middleware.remove(context.outputInterceptor);\n context.outputInterceptor = undefined;\n }\n await context.controller.destroy();\n // Destroy the session tab (removes from tab bar)\n if (context.sessionTab) {\n context.sessionTab.destroy();\n context.sessionTab = undefined;\n }\n // Restore the original topmost tab to the tab bar at its original position\n if (context.topmostTab) {\n const tabs = this.appService.tabs;\n const insertAt = context.topmostTabIndex !== undefined\n ? Math.min(context.topmostTabIndex, tabs.length)\n : tabs.length;\n tabs.splice(insertAt, 0, context.topmostTab);\n this.appService.tabsChanged.next();\n this.appService.selectTab(context.topmostTab);\n }\n this.log.info('Disconnected tmux context');\n }\n /**\n * Disconnect from all sessions\n */\n async disconnect() {\n for (const context of this.sessions) {\n await this.disconnectContext(context);\n }\n }\n /**\n * Attach to tmux from an existing terminal tab.\n * Replaces the terminal tab with a TmuxSessionTab, keeping the terminal tab\n * hidden in context. On disconnect, the terminal tab is restored.\n */\n async attachToTerminal(terminalTab) {\n var _a, _b;\n const session = terminalTab.session;\n if (!session) {\n this.logger.error('Terminal tab has no session');\n return;\n }\n this.log.info('Attaching tmux to existing terminal session');\n const context = {\n controller: null,\n terminalTab,\n subscriptions: []\n };\n // Insert a tmux output interceptor at position 0 of the session's\n // middleware chain. This captures raw output for the gateway and\n // prevents trzsz (or other) middleware on the original session from\n // seeing tmux control mode data (which would cause false positives).\n const interceptor = new TmuxOutputInterceptor();\n session.middleware.unshift(interceptor);\n context.outputInterceptor = interceptor;\n // Create a controller that uses the terminal's session for I/O\n context.controller = new session_1.TmuxController(this.logger, this.injector, (data) => session.write(Buffer.from(data)), () => this.disconnectContext(context), this.configService);\n // Subscribe to the interceptor's raw output to parse tmux control mode.\n // Feed raw buffers directly — the gateway handles line buffering internally\n // via executeData(), which properly handles TCP fragment boundaries.\n context.subscriptions.push(interceptor.rawOutput$.subscribe((data) => {\n context.controller.handleData(data);\n }));\n // Handle terminal tab closure (disconnect on close)\n context.subscriptions.push(terminalTab.destroyed$.subscribe(() => {\n this.log.info('Attached terminal tab closed, disconnecting session');\n this.disconnectContext(context);\n }));\n this.sessions.add(context);\n this.setupControllerEvents(context);\n // Send the tmux -CC command to the terminal\n const sessionName = (_b = (_a = this.configService.store.tmuxPlugin) === null || _a === void 0 ? void 0 : _a.defaultSessionName) !== null && _b !== void 0 ? _b : 'default';\n session.write(Buffer.from(`tmux -CC new -A -s ${sessionName}\\n`));\n }\n};\nTmuxService.ctorParameters = () => [\n { type: core_1.Injector },\n { type: tabby_core_1.AppService },\n { type: tabby_core_1.ConfigService },\n { type: tabby_core_1.LogService }\n];\nTmuxService = __decorate([\n (0, core_1.Injectable)({ providedIn: 'root' }),\n __metadata(\"design:paramtypes\", [core_1.Injector,\n tabby_core_1.AppService,\n tabby_core_1.ConfigService,\n tabby_core_1.LogService])\n], TmuxService);\nexports.TmuxService = TmuxService;\n","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.TmuxControllerSession = exports.TmuxController = exports.TmuxPaneSession = void 0;\nconst rxjs_1 = require(\"rxjs\");\nconst tabby_terminal_1 = require(\"tabby-terminal\");\nconst logHelper_1 = require(\"./logHelper\");\nconst gateway_1 = require(\"./gateway\");\n/**\n * TmuxPaneSession - Represents a single tmux pane as a terminal session\n */\nclass TmuxPaneSession extends tabby_terminal_1.BaseSession {\n constructor(logger, controller, paneId) {\n super(logger);\n this.controller = controller;\n this.paneId = paneId;\n /**\n * Saved alternate screen content + cursor position, persisted after\n * restorePaneHistory so that xterm.resize() (from setTmuxGrid after\n * %layout-change) can re-apply it. xterm.resize() clears the\n * alternate screen buffer, so the content must be written again.\n */\n this.pendingAltRestore = null;\n /**\n * Incomplete screen-title sequence (ESC k ... ESC \\) spanning\n * multiple feedOutput calls. Buffered until the closing ST arrives.\n */\n this._pendingTitleSeq = null;\n this.open = true;\n this.controller.registerPane(this.paneId, this);\n }\n async start() {\n this.open = true;\n // Restore history — for initial attach this is instant (pre-loaded\n // during batch discovery); for runtime panes it falls back to\n // capture-pane.\n await this.controller.restorePaneHistory(this.paneId);\n }\n resize(_columns, _rows) {\n // No-op by design. In tmux integration, tmux is authoritative over the\n // cell grid: each pane's character size comes from the %layout-change\n // string and is applied via TmuxPaneTabComponent.setTmuxGrid().\n //\n // The xterm frontend's automatic fit-to-container resizing is disabled\n // for tmux panes (frontend.enableResizing = false), so this method\n // should normally never be called. Sending refresh-client -C from here\n // would re-introduce the resize feedback loop (pane refit → client\n // size → tmux relayout → pane refit → ...), so we deliberately do\n // nothing. Overall client size is driven only by the container size\n // in TmuxSessionTabComponent.refreshClientSize().\n }\n write(data) {\n this.controller.writeToPane(this.paneId, data);\n }\n // NOTE: feedFromTerminal is NOT overridden — it goes through the\n // middleware chain (BaseSession.feedFromTerminal → middleware →\n // outputToSession$ → write()) so that SessionMiddleware plugins\n // such as trzsz can intercept terminal input.\n kill(_signal) {\n this.destroy();\n }\n async destroy() {\n this.pendingAltRestore = null;\n this._pendingTitleSeq = null;\n await super.destroy();\n this.controller.unregisterPane(this.paneId);\n }\n async gracefullyKillProcess() {\n this.destroy();\n }\n supportsWorkingDirectory() {\n return false;\n }\n async getWorkingDirectory() {\n return null;\n }\n /**\n * Public wrapper for the protected emitOutput().\n * Used by TmuxController to deliver history and buffered output.\n *\n * Filters out screen/tmux \"set window title\" sequences (ESC k ... ESC \\)\n * which xterm.js does not recognize. Without filtering, zsh precmd/preexec\n * hooks that set the terminal title via `print -Pn \"\\ek%s\\e\\\\\"` would leak\n * the title text as visible output (e.g. `echo111` instead of `111`).\n */\n feedOutput(data) {\n data = this.filterScreenTitleSequences(data);\n if (data.length > 0) {\n this.emitOutput(data);\n }\n }\n /**\n * Strip screen/tmux \"set window title\" sequences (ESC k ... ESC \\)\n * from the output stream.\n *\n * In screen/tmux, `ESC k <title> ESC \\` sets the window/tab title.\n * tmux processes these internally but also forwards them verbatim to\n * control-mode clients. xterm.js does NOT handle this sequence — it\n * only recognizes `ESC ] ... BEL/ST` (OSC) — so the title text leaks\n * as visible content (e.g. the command name appears before output).\n *\n * Handles sequences that span multiple feedOutput calls by buffering\n * the incomplete portion until the closing ST (ESC \\) arrives.\n */\n filterScreenTitleSequences(data) {\n // Prepend leftover from previous call\n if (this._pendingTitleSeq) {\n data = Buffer.concat([this._pendingTitleSeq, data]);\n this._pendingTitleSeq = null;\n }\n const ESC = 0x1b;\n const parts = [];\n let pos = 0;\n while (pos < data.length) {\n // Find next ESC k (0x1b 0x6b)\n let startIdx = -1;\n for (let i = pos; i < data.length - 1; i++) {\n if (data[i] === ESC && data[i + 1] === 0x6b) {\n startIdx = i;\n break;\n }\n }\n if (startIdx < 0) {\n // No more title sequences — emit the rest.\n // Buffer a trailing ESC (0x1b) in case the next call\n // starts with 0x6b ('k'), forming a split ESC k pair.\n const tail = data[data.length - 1];\n if (tail === ESC) {\n parts.push(data.subarray(pos, data.length - 1));\n this._pendingTitleSeq = data.subarray(data.length - 1);\n }\n else {\n parts.push(data.subarray(pos));\n }\n break;\n }\n // Emit data before the title sequence\n if (startIdx > pos) {\n parts.push(data.subarray(pos, startIdx));\n }\n // Search for ESC \\ (ST: 0x1b 0x5c) after ESC k\n let stIdx = -1;\n for (let i = startIdx + 2; i < data.length - 1; i++) {\n if (data[i] === ESC && data[i + 1] === 0x5c) {\n stIdx = i;\n break;\n }\n }\n if (stIdx >= 0) {\n // Complete sequence found — skip it entirely\n pos = stIdx + 2;\n }\n else {\n // Incomplete sequence — buffer from ESC k onwards\n this._pendingTitleSeq = data.subarray(startIdx);\n break;\n }\n }\n if (parts.length === 0)\n return Buffer.alloc(0);\n if (parts.length === 1)\n return parts[0];\n return Buffer.concat(parts);\n }\n}\nexports.TmuxPaneSession = TmuxPaneSession;\n/**\n * TmuxController - Manages a tmux control mode session\n *\n * Based on iTerm2's TmuxController architecture.\n */\nclass TmuxController {\n get log() {\n return (0, logHelper_1.createConditionalLogger)(this.logger, this.configService);\n }\n constructor(logger, _injector, // eslint-disable-line @typescript-eslint/no-unused-vars\n writer, closer, configService) {\n this.logger = logger;\n this.closer = closer;\n this.configService = configService;\n this.paneSessions = new Map();\n this.windowStates = new Map();\n this.knownPanes = new Set();\n this.pendingPaneOutput = new Map();\n /** Pre-loaded history from batch discovery (iTerm2-style). */\n this.pendingSnapshots = new Map();\n this.sessionName = '';\n this.sessionId = -1;\n this.attached = false;\n this.activeWindowId = null;\n this.events = new rxjs_1.Subject();\n this.gateway = new gateway_1.TmuxGateway(logger, writer, configService);\n this.setupGatewaySubscriptions();\n }\n setupGatewaySubscriptions() {\n // Handle pane output\n this.gateway.output$.subscribe(({ paneId, data }) => {\n this.log.info(`Session received output for pane %${paneId}: ${data.length} bytes`);\n if (this.paneSessions.has(paneId)) {\n this.paneSessions.get(paneId).feedOutput(data);\n }\n else {\n // Buffer output for panes not yet registered\n if (!this.pendingPaneOutput.has(paneId)) {\n this.pendingPaneOutput.set(paneId, []);\n }\n this.pendingPaneOutput.get(paneId).push(data);\n }\n });\n // Handle session changes - this is our main initialization point\n // Like iTerm2, we immediately batch-discover all windows and panes\n // instead of relying on delayed list-panes or passive %output discovery.\n this.gateway.sessionChanged$.subscribe(({ sessionName, sessionId }) => {\n this.sessionName = sessionName;\n this.sessionId = sessionId;\n this.attached = true;\n this.log.info(`Attached to session: ${sessionName} ($${sessionId})`);\n this.events.next({ type: 'session-changed', data: { sessionName, sessionId } });\n // Immediate batch discovery — no setTimeout delay\n this.discoverWindowsAndPanes();\n });\n // Handle window events\n this.gateway.windowAdd$.subscribe(windowId => {\n if (!this.windowStates.has(windowId)) {\n this.windowStates.set(windowId, {\n id: windowId,\n name: `Window ${windowId}`,\n panes: new Set()\n });\n }\n this.events.next({ type: 'window-add', windowId });\n // For new windows created at runtime (after initial attach),\n // tmux may NOT send %layout-change — only %window-add and %output.\n // We must proactively discover the window's layout and panes.\n // The window-add event has already been emitted above, so the UI\n // has registered the window. discoverWindowsAndPanes will update\n // the windowState with layout and emit pane-add + layout-change.\n this.discoverWindowsAndPanes();\n });\n this.gateway.windowClose$.subscribe(windowId => {\n this.windowStates.delete(windowId);\n this.events.next({ type: 'window-close', windowId });\n });\n this.gateway.windowRenamed$.subscribe(({ windowId, name }) => {\n const state = this.windowStates.get(windowId);\n if (state) {\n state.name = name;\n }\n this.events.next({ type: 'window-renamed', windowId, data: { name } });\n });\n // Handle pane close events (tmux 3.2+)\n this.gateway.paneClose$.subscribe(({ windowId, paneId }) => {\n this.log.info(`Pane %${paneId} closed in window @${windowId}`);\n // Remove from known panes\n this.knownPanes.delete(paneId);\n // Remove from window state\n const windowState = this.windowStates.get(windowId);\n if (windowState) {\n windowState.panes.delete(paneId);\n }\n // Clean up pane session if exists\n const session = this.paneSessions.get(paneId);\n if (session) {\n session.destroy();\n this.paneSessions.delete(paneId);\n }\n this.pendingPaneOutput.delete(paneId);\n this.events.next({ type: 'pane-close', paneId, windowId });\n });\n // Handle layout changes — primary pane discovery trigger (iTerm2-style).\n // Layout strings contain pane IDs. We extract new panes, capture their\n // history/state, then emit pane-add events so the UI can create tabs\n // with pre-loaded data. This replaces the old refreshPanes()-based\n // discovery for runtime pane creation (split-window etc.).\n //\n // IMPORTANT: We do NOT emit 'layout-change' here. discoverPanesFromLayout\n // emits it after pane-add events, ensuring syncLayout() always runs\n // after pane tabs have been created.\n this.gateway.layoutChange$.subscribe(({ windowId, layout, visibleLayout, zoomed }) => {\n const state = this.windowStates.get(windowId);\n if (state) {\n state.layout = layout;\n }\n // Discover new panes from the layout string, then emit layout-change\n this.discoverPanesFromLayout(windowId, layout, visibleLayout, zoomed);\n });\n // Handle exit\n // Handle session-window-changed — the current window changed\n this.gateway.sessionWindowChanged$.subscribe(({ windowId }) => {\n this.log.info(`Active window changed to @${windowId}`);\n this.activeWindowId = windowId;\n this.events.next({ type: 'active-window-changed', windowId });\n });\n this.gateway.exit$.subscribe(reason => {\n this.attached = false;\n this.events.next({ type: 'exit', data: { reason } });\n this.closer();\n });\n // Handle initialization\n this.gateway.initialized$.subscribe(() => {\n this.events.next({ type: 'initialized' });\n this.discoverWindowsAndPanes();\n });\n }\n /**\n * Process a line from the underlying session\n */\n handleLine(line) {\n this.gateway.executeLine(line);\n }\n /**\n * Feed raw PTY data to the gateway for byte-level DCS buffering.\n * Preferred over handleLine for proper handling of TCP fragments.\n */\n handleData(data) {\n this.gateway.executeData(data);\n }\n /**\n * Batch-discover all windows, panes, and history (iTerm2-style).\n *\n * Sequence (mirrors TmuxWindowOpener):\n * 1. list-windows → discover windows with names + layout\n * 2. list-panes → discover pane IDs\n * 3. capture-pane for each new pane → pre-load history\n * 4. emit pane-add events (history already in pendingHistory)\n *\n * By the time the UI creates a TmuxPaneTabComponent for a pane,\n * its history is already captured — no async restore or buffering\n * is needed at the session level.\n */\n async discoverWindowsAndPanes() {\n this.log.info('Batch discovering windows and panes...');\n try {\n // Step 1: Discover all windows with names, layout and active flag\n const winResult = await this.gateway.sendCommand('list-windows -F \"#{window_id} #{window_name} #{window_active} #{window_layout}\"', gateway_1.TMUX_COMMAND_TOLERATE_ERRORS);\n const winLines = winResult.split(/[\\r\\n]+/).map(l => l.trim()).filter(l => l);\n this.log.info(`Found ${winLines.length} window(s) from list-windows`);\n for (const line of winLines) {\n // Format: \"@0 mywindow 1 1234,0x0,0,0{60x24,0,0,1}\"\n const match = line.match(/^@?(\\d+)\\s+(.+?)\\s+([01])\\s+(.+)$/);\n if (match) {\n const windowId = parseInt(match[1]);\n const windowName = match[2];\n const active = match[3] === '1';\n const layout = match[4];\n if (active) {\n this.activeWindowId = windowId;\n }\n if (!this.windowStates.has(windowId)) {\n this.windowStates.set(windowId, {\n id: windowId,\n name: windowName,\n layout,\n panes: new Set()\n });\n this.events.next({ type: 'window-add', windowId });\n }\n else {\n const state = this.windowStates.get(windowId);\n state.name = windowName;\n state.layout = layout;\n }\n }\n }\n // Step 2: Discover all panes and map to windows\n const paneResult = await this.gateway.sendCommand('list-panes -s -F \"#{pane_id} #{window_id}\"', gateway_1.TMUX_COMMAND_TOLERATE_ERRORS);\n const paneLines = paneResult.split(/[\\r\\n]+/).map(l => l.trim()).filter(l => l);\n this.log.info(`Found ${paneLines.length} pane(s) from list-panes`);\n const newPaneIds = [];\n for (const line of paneLines) {\n const match = line.match(/^%?(\\d+)\\s+@?(\\d+)$/);\n if (match) {\n const paneId = parseInt(match[1]);\n const windowId = parseInt(match[2]);\n let windowState = this.windowStates.get(windowId);\n if (!windowState) {\n windowState = {\n id: windowId,\n name: `Window ${windowId}`,\n panes: new Set()\n };\n this.windowStates.set(windowId, windowState);\n this.events.next({ type: 'window-add', windowId });\n }\n windowState.panes.add(paneId);\n if (!this.knownPanes.has(paneId)) {\n this.knownPanes.add(paneId);\n newPaneIds.push({ paneId, windowId });\n }\n }\n }\n // Step 3: Batch-capture history + state for all new panes\n // (mirrors iTerm2 TmuxWindowOpener)\n if (newPaneIds.length > 0) {\n this.log.info(`Capturing history/state for ${newPaneIds.length} new pane(s)...`);\n await this.capturePaneSnapshots(newPaneIds);\n }\n // Step 4: Emit pane-add events — history is now pre-loaded\n for (const { paneId, windowId } of newPaneIds) {\n this.log.info(`Discovered pane %${paneId} in window @${windowId}`);\n this.events.next({ type: 'pane-add', paneId, windowId });\n }\n // Step 5: Emit layout-change for all discovered windows so the UI\n // can build the SplitContainer tree. Without this, syncLayout()\n // never runs and panes remain registered but unmounted.\n for (const windowState of this.windowStates.values()) {\n if (windowState.layout) {\n this.events.next({\n type: 'layout-change',\n windowId: windowState.id,\n data: { layout: windowState.layout },\n });\n }\n }\n }\n catch (e) {\n this.logger.warn('Failed to batch discover windows/panes:', e);\n }\n }\n /**\n * Public alias for discoverWindowsAndPanes.\n * Used by external callers (context menu, session tab ngAfterViewInit)\n * to trigger a full re-scan. For runtime pane creation (split-window),\n * discoverPanesFromLayout() handles it via %layout-change instead.\n */\n async refreshPanes() {\n return this.discoverWindowsAndPanes();\n }\n /**\n * Discover new panes from a %layout-change notification (iTerm2-style).\n *\n * When tmux sends a layout change, the layout string contains all pane\n * IDs for that window. We compare against known panes, capture\n * history/state for any new ones, emit pane-add events, then emit\n * layout-change so syncLayout() runs after pane tabs exist.\n */\n async discoverPanesFromLayout(windowId, layout, visibleLayout, zoomed) {\n // Extract pane IDs from the layout string\n // Pane IDs appear as trailing numbers in layout leaf nodes like \"80x24,0,0,3\"\n // Match pattern: dimension,position,paneId (paneId is the last number after the last comma)\n const paneIdSet = new Set();\n // Match all occurrences of ,\\d+ at the end of leaf node specs\n const leafPattern = /\\d+x\\d+,\\d+,\\d+,(\\d+)/g;\n let m;\n while ((m = leafPattern.exec(layout)) !== null) {\n paneIdSet.add(parseInt(m[1]));\n }\n if (paneIdSet.size === 0)\n return;\n const windowState = this.windowStates.get(windowId);\n const newPaneIds = [];\n for (const paneId of paneIdSet) {\n if (windowState) {\n windowState.panes.add(paneId);\n }\n if (!this.knownPanes.has(paneId)) {\n this.knownPanes.add(paneId);\n newPaneIds.push({ paneId, windowId });\n }\n }\n if (newPaneIds.length > 0) {\n this.log.info(`Discovered ${newPaneIds.length} new pane(s) from layout-change for window @${windowId}`);\n // Capture history + state for new panes (same as discoverWindowsAndPanes Step 3)\n await this.capturePaneSnapshots(newPaneIds);\n // Emit pane-add events — history is now pre-loaded\n for (const { paneId, windowId: wid } of newPaneIds) {\n this.events.next({ type: 'pane-add', paneId, windowId: wid });\n }\n }\n // Emit layout-change AFTER pane-add events, so syncLayout() can\n // create views for newly discovered panes. This ordering is critical:\n // pane-add → handlePaneAdd (creates pane tab) → layout-change →\n // syncLayout (attaches view + builds SplitTree).\n this.events.next({ type: 'layout-change', windowId, data: { layout, visibleLayout, zoomed } });\n }\n /**\n * Capture history + state for an array of panes.\n * Shared by discoverWindowsAndPanes() and discoverPanesFromLayout().\n */\n async capturePaneSnapshots(paneIds) {\n const stateFormat = [\n 'pane_id=#{pane_id}',\n 'alternate_on=#{alternate_on}',\n 'alternate_saved_x=#{alternate_saved_x}',\n 'alternate_saved_y=#{alternate_saved_y}',\n 'cursor_x=#{cursor_x}',\n 'cursor_y=#{cursor_y}',\n 'scroll_region_upper=#{scroll_region_upper}',\n 'scroll_region_lower=#{scroll_region_lower}',\n 'pane_tabs=#{pane_tabs}',\n 'cursor_flag=#{cursor_flag}',\n 'insert_flag=#{insert_flag}',\n 'keypad_cursor_flag=#{keypad_cursor_flag}',\n 'keypad_flag=#{keypad_flag}',\n 'wrap_flag=#{wrap_flag}',\n 'bracket_paste_flag=#{bracket_paste_flag}',\n 'mouse_standard_flag=#{mouse_standard_flag}',\n 'mouse_button_flag=#{mouse_button_flag}',\n 'mouse_any_flag=#{mouse_any_flag}',\n ].join('\\t');\n const captures = paneIds.map(async ({ paneId }) => {\n try {\n const [history, altHistory, stateResult] = await Promise.all([\n this.gateway.sendCommand(`capture-pane -peqJN -S- -t %${paneId}`, gateway_1.TMUX_COMMAND_TOLERATE_ERRORS),\n this.gateway.sendCommand(`capture-pane -peqJN -a -S- -t %${paneId}`, gateway_1.TMUX_COMMAND_TOLERATE_ERRORS),\n this.gateway.sendCommand(`list-panes -t %${paneId} -F \"${stateFormat}\"`, gateway_1.TMUX_COMMAND_TOLERATE_ERRORS),\n ]);\n const state = this.parsePaneState(stateResult, paneId);\n this.pendingSnapshots.set(paneId, { history, altHistory, state });\n }\n catch (e) {\n this.logger.warn(`Failed to capture snapshot for pane %${paneId}:`, e);\n }\n });\n await Promise.all(captures);\n }\n // --- Pane Management ---\n registerPane(paneId, session) {\n this.paneSessions.set(paneId, session);\n this.knownPanes.add(paneId);\n // Flush any buffered output that arrived before registration\n const buffered = this.pendingPaneOutput.get(paneId);\n if (buffered) {\n for (const data of buffered) {\n session.feedOutput(data);\n }\n this.pendingPaneOutput.delete(paneId);\n }\n }\n unregisterPane(paneId) {\n this.paneSessions.delete(paneId);\n this.pendingPaneOutput.delete(paneId);\n this.pendingSnapshots.delete(paneId);\n }\n getPaneSession(paneId) {\n return this.paneSessions.get(paneId);\n }\n hasPaneSession(paneId) {\n return this.paneSessions.has(paneId);\n }\n resizePane(_paneId, columns, rows) {\n // Use refresh-client -C to set client size\n // This affects all panes uniformly in non-variable-size mode\n // Note: paneId is ignored as tmux control mode uses uniform size\n this.gateway.sendCommand(`refresh-client -C ${columns},${rows}`, gateway_1.TMUX_COMMAND_TOLERATE_ERRORS).catch(e => this.logger.warn('Resize failed:', e));\n }\n writeToPane(paneId, data) {\n this.log.info(`Writing ${data.length} bytes to pane %${paneId}: <${data.toString('hex')}>`);\n this.gateway.sendKeys(data, paneId);\n }\n /**\n * Restore pane history.\n *\n * History + state are pre-loaded during discoverWindowsAndPanes()\n * (stored in pendingSnapshots) — this is instant, no capture-pane needed.\n * Both initial attach and runtime panes (split-window etc.) go through\n * discoverWindowsAndPanes() before pane-add events are emitted, so\n * pendingSnapshots is always populated by the time this runs.\n *\n * Restores (like iTerm2 setTmuxHistory:altHistory:state:):\n * 1. Primary screen history\n * 2. Alternate screen history (via CSI ?1047h / escape sequences)\n * 3. Terminal state (cursor, scroll region, modes)\n */\n async restorePaneHistory(paneId) {\n const snapshot = this.pendingSnapshots.get(paneId);\n if (!snapshot) {\n this.logger.warn(`No pre-loaded snapshot for pane %${paneId}, skipping`);\n return;\n }\n this.pendingSnapshots.delete(paneId);\n const session = this.paneSessions.get(paneId);\n if (!session)\n return;\n const state = snapshot.state;\n // Step 1: Write primary screen history to the primary screen.\n // This sets up the scrollback so it's available if the user leaves\n // the program running on the alternate screen.\n if (snapshot.history) {\n const normalized = snapshot.history.replace(/\\n/g, '\\r\\n');\n session.feedOutput(Buffer.from(normalized, 'utf-8'));\n }\n // Step 2: If the pane is on the alternate screen (vim, less, etc.),\n // switch to it and write the alternate content. We stay on alternate.\n if (state.alternateOn) {\n // ?1047h enters alternate screen and clears it\n session.feedOutput(Buffer.from('\\x1b[?1047h', 'utf-8'));\n // Apply terminal state on the alternate screen (scroll region,\n // modes, cursor visibility — NOT the cursor position yet).\n this.applyPaneState(session, state);\n // Write the alternate screen content at the top-left corner.\n // capture-pane with -a gives us exactly what was on the alternate\n // screen, starting from row 0.\n if (snapshot.altHistory && snapshot.altHistory.trim()) {\n session.feedOutput(Buffer.from('\\x1b[H', 'utf-8'));\n const normalized = snapshot.altHistory.replace(/\\n/g, '\\r\\n');\n session.feedOutput(Buffer.from(normalized, 'utf-8'));\n }\n // Re-apply cursor position after content write (content may\n // have moved the cursor via embedded CUP sequences).\n const csi = (s) => `\\x1b[${s}`;\n session.feedOutput(Buffer.from(csi(`${state.cursorY + 1};${state.cursorX + 1}H`), 'utf-8'));\n // Save alternate screen data for re-apply after xterm.resize()\n // (called by setTmuxGrid). xterm.resize() clears the alternate\n // screen buffer, so the content must be written again.\n session.pendingAltRestore = {\n content: snapshot.altHistory || '',\n cursorY: state.cursorY,\n cursorX: state.cursorX,\n modes: this.buildModeSequences(state),\n };\n }\n else {\n // Normal mode — write alternate history if present (rare)\n if (snapshot.altHistory && snapshot.altHistory.trim()) {\n session.feedOutput(Buffer.from('\\x1b[?1047h', 'utf-8'));\n const normalized = snapshot.altHistory.replace(/\\n/g, '\\r\\n');\n session.feedOutput(Buffer.from(normalized, 'utf-8'));\n session.feedOutput(Buffer.from('\\x1b[?1047l', 'utf-8'));\n }\n // Apply terminal state (cursor, scroll region, modes)\n this.applyPaneState(session, state);\n }\n }\n /**\n * Parse pane state from `list-panes -F` response.\n * Mirrors iTerm2 TmuxStateParser.\n */\n parsePaneState(response, expectedPaneId) {\n const state = {\n paneId: expectedPaneId,\n cursorX: 0, cursorY: 0,\n alternateOn: false,\n alternateSavedX: 0, alternateSavedY: 0,\n scrollRegionUpper: 0, scrollRegionLower: 0,\n wrapFlag: true, cursorFlag: true,\n insertFlag: false, bracketPasteFlag: false,\n keypadCursorFlag: false, keypadFlag: false,\n paneTabs: [],\n mouseStandardMode: false,\n mouseButtonMode: false,\n mouseAnyMode: false,\n };\n // `list-panes -t %paneId -F ...` may return multiple lines (one per pane\n // in the window) or a single tab-separated line. We must find the\n // segment whose pane_id matches expectedPaneId — the first match is NOT\n // necessarily the one we asked for.\n const lines = response.split(/[\\r\\n]+/);\n let targetLine = '';\n for (const line of lines) {\n if (!line.includes('pane_id='))\n continue;\n // Check if this line's pane_id matches our expected pane\n const idMatch = line.match(/pane_id=%?(\\d+)/);\n if (idMatch && parseInt(idMatch[1]) === expectedPaneId) {\n targetLine = line;\n break;\n }\n }\n // Fallback: if no exact match found, use the first line with pane_id\n // (happens when list-panes returns only the target pane)\n if (!targetLine) {\n targetLine = lines.find(l => l.includes('pane_id=')) || '';\n }\n if (!targetLine)\n return state;\n for (const part of targetLine.split('\\t')) {\n const eqIdx = part.indexOf('=');\n if (eqIdx < 0)\n continue;\n const key = part.substring(0, eqIdx);\n const value = part.substring(eqIdx + 1);\n const n = parseInt(value);\n switch (key) {\n case 'pane_id':\n state.paneId = n;\n break;\n case 'cursor_x':\n state.cursorX = n;\n break;\n case 'cursor_y':\n state.cursorY = n;\n break;\n case 'alternate_on':\n state.alternateOn = n === 1;\n break;\n case 'alternate_saved_x':\n state.alternateSavedX = n;\n break;\n case 'alternate_saved_y':\n state.alternateSavedY = n;\n break;\n case 'scroll_region_upper':\n state.scrollRegionUpper = n;\n break;\n case 'scroll_region_lower':\n state.scrollRegionLower = n;\n break;\n case 'pane_tabs':\n state.paneTabs = value.split(',').map(Number).filter(x => !isNaN(x));\n break;\n case 'cursor_flag':\n state.cursorFlag = n === 1;\n break;\n case 'insert_flag':\n state.insertFlag = n === 1;\n break;\n case 'keypad_cursor_flag':\n state.keypadCursorFlag = n === 1;\n break;\n case 'keypad_flag':\n state.keypadFlag = n === 1;\n break;\n case 'wrap_flag':\n state.wrapFlag = n === 1;\n break;\n case 'bracket_paste_flag':\n state.bracketPasteFlag = n === 1;\n break;\n case 'mouse_standard_flag':\n state.mouseStandardMode = n === 1;\n break;\n case 'mouse_button_flag':\n state.mouseButtonMode = n === 1;\n break;\n case 'mouse_any_flag':\n state.mouseAnyMode = n === 1;\n break;\n }\n }\n return state;\n }\n /**\n * Apply parsed pane state to the terminal via ANSI escape sequences.\n * Mirrors iTerm2 VT100ScreenMutableState.setTmuxState:.\n */\n applyPaneState(session, state) {\n // Build a sequence of escape codes to restore terminal state.\n const seq = this.buildModeSequences(state);\n session.feedOutput(Buffer.from(seq, 'utf-8'));\n }\n /**\n * Build ANSI escape sequences for terminal mode state (without alternate\n * screen entry). Used by both applyPaneState and pendingAltRestore.\n */\n buildModeSequences(state) {\n const csi = (s) => `\\x1b[${s}`;\n const esc = (s) => `\\x1b${s}`;\n let seq = '';\n // Set scroll region (DECSTBM)\n if (state.scrollRegionUpper > 0 || state.scrollRegionLower > 0) {\n seq += csi(`${state.scrollRegionUpper + 1};${state.scrollRegionLower + 1}r`);\n }\n // Restore cursor position (CUP)\n seq += csi(`${state.cursorY + 1};${state.cursorX + 1}H`);\n // Cursor visibility (DECTCEM)\n seq += state.cursorFlag ? csi('?25h') : csi('?25l');\n // Insert mode (IRM)\n seq += state.insertFlag ? csi('4h') : csi('4l');\n // Application cursor keys (DECCKM)\n seq += state.keypadCursorFlag ? csi('?1h') : csi('?1l');\n // Application keypad mode (DECKPAM / DECKPNM)\n seq += state.keypadFlag ? esc('=') : esc('>');\n // Bracketed paste mode\n seq += state.bracketPasteFlag ? csi('?2004h') : csi('?2004l');\n // Wrap mode (DECAWM)\n seq += state.wrapFlag ? csi('?7h') : csi('?7l');\n // Mouse tracking modes (?1000=normal, ?1002=button, ?1003=any)\n seq += state.mouseStandardMode ? csi('?1000h') : csi('?1000l');\n seq += state.mouseButtonMode ? csi('?1002h') : csi('?1002l');\n seq += state.mouseAnyMode ? csi('?1003h') : csi('?1003l');\n // Tab stops (HTS / TBC)\n // TBC 3 = clear all tab stops, then HTS at each position\n seq += csi('3g');\n for (const col of state.paneTabs) {\n seq += csi(`${col + 1}G`); // CUP to column\n seq += esc('H'); // HTS\n }\n // Reset cursor back to final position (tab stop setup moves it)\n seq += csi(`${state.cursorY + 1};${state.cursorX + 1}H`);\n return seq;\n }\n /**\n * Re-apply alternate screen content after xterm.resize() clears it.\n * Called by TmuxPaneTabComponent.applyTmuxGrid() after resize.\n */\n reapplyAltContent(session) {\n const alt = session.pendingAltRestore;\n if (!alt)\n return;\n // Clear immediately — this is a one-shot re-apply after the initial\n // resize. After this, live tmux output maintains the alternate screen.\n session.pendingAltRestore = null;\n // Enter alternate screen (clears it)\n session.feedOutput(Buffer.from('\\x1b[?1047h', 'utf-8'));\n // Apply modes\n session.feedOutput(Buffer.from(alt.modes, 'utf-8'));\n // Write content at top-left\n if (alt.content && alt.content.trim()) {\n session.feedOutput(Buffer.from('\\x1b[H', 'utf-8'));\n const normalized = alt.content.replace(/\\n/g, '\\r\\n');\n session.feedOutput(Buffer.from(normalized, 'utf-8'));\n }\n // Re-apply cursor position\n const csi = (s) => `\\x1b[${s}`;\n session.feedOutput(Buffer.from(csi(`${alt.cursorY + 1};${alt.cursorX + 1}H`), 'utf-8'));\n }\n async killPane(paneId) {\n await this.gateway.sendCommand(`kill-pane -t %${paneId}`, gateway_1.TMUX_COMMAND_TOLERATE_ERRORS);\n }\n // --- Window Operations ---\n async createWindow() {\n try {\n const result = await this.gateway.sendCommand('new-window -P -F \"#{window_id}\"');\n const match = result.match(/@(\\d+)/);\n return match ? parseInt(match[1]) : null;\n }\n catch (e) {\n this.logger.warn('Failed to create window:', e);\n return null;\n }\n }\n async killWindow(windowId) {\n await this.gateway.sendCommand(`kill-window -t @${windowId}`, gateway_1.TMUX_COMMAND_TOLERATE_ERRORS);\n }\n async renameWindow(windowId, name) {\n await this.gateway.sendCommand(`rename-window -t @${windowId} \"${name.replace(/\"/g, '\\\\\"')}\"`, gateway_1.TMUX_COMMAND_TOLERATE_ERRORS);\n }\n // --- Session Operations ---\n async detach() {\n this.gateway.detach();\n }\n async listSessions() {\n try {\n const result = await this.gateway.sendCommand('list-sessions -F \"#{session_id} #{session_name}\"');\n const sessions = [];\n for (const line of result.split('\\n')) {\n const match = line.match(/^\\$(\\d+) (.+)$/);\n if (match) {\n sessions.push({\n id: parseInt(match[1]),\n name: match[2]\n });\n }\n }\n return sessions;\n }\n catch (e) {\n this.logger.warn('Failed to list sessions:', e);\n return [];\n }\n }\n // --- Lifecycle ---\n async destroy() {\n // Close all pane sessions\n for (const [_paneId, session] of this.paneSessions) {\n await session.destroy();\n }\n this.paneSessions.clear();\n this.attached = false;\n }\n // --- Getters ---\n get isAttached() {\n return this.attached;\n }\n getSessionName() {\n return this.sessionName;\n }\n getSessionId() {\n return this.sessionId;\n }\n getWindowState(windowId) {\n return this.windowStates.get(windowId);\n }\n getAllWindowStates() {\n return Array.from(this.windowStates.values());\n }\n getFirstWindowId() {\n const first = this.windowStates.keys().next();\n return first.done ? undefined : first.value;\n }\n /**\n * Get the tmux-side active window ID, as reported by list-windows\n * #{window_active} or %session-window-changed. Falls back to null.\n */\n getActiveWindowId() {\n return this.activeWindowId;\n }\n /**\n * Get all known pane IDs across all windows.\n * Used by TmuxPaneTabComponent for \"Focus all tmux panes\" (sync input).\n */\n getAllPaneIds() {\n return Array.from(this.knownPanes);\n }\n}\nexports.TmuxController = TmuxController;\nexports.TmuxControllerSession = TmuxController;\n","\"use strict\";\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n};\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.TmuxSettingsTabProvider = void 0;\nconst core_1 = require(\"@angular/core\");\nconst tabby_settings_1 = require(\"tabby-settings\");\nconst settings_component_1 = require(\"./components/settings.component\");\n// eslint-disable-next-line new-cap\nlet TmuxSettingsTabProvider = class TmuxSettingsTabProvider extends tabby_settings_1.SettingsTabProvider {\n constructor() {\n super(...arguments);\n this.id = 'tmux';\n this.icon = 'border-all';\n this.title = 'Tmux';\n }\n getComponentType() {\n return settings_component_1.TmuxSettingsTabComponent;\n }\n};\nTmuxSettingsTabProvider = __decorate([\n (0, core_1.Injectable)()\n], TmuxSettingsTabProvider);\nexports.TmuxSettingsTabProvider = TmuxSettingsTabProvider;\n","\"use strict\";\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n};\nvar __metadata = (this && this.__metadata) || function (k, v) {\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\n};\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.TmuxContextMenuProvider = void 0;\nconst core_1 = require(\"@angular/core\");\nconst tabby_core_1 = require(\"tabby-core\");\nconst tabby_terminal_1 = require(\"tabby-terminal\");\nconst tmux_service_1 = require(\"./services/tmux.service\");\nconst tmuxSessionTab_component_1 = require(\"./components/tmuxSessionTab.component\");\nconst tmuxPaneTab_component_1 = require(\"./components/tmuxPaneTab.component\");\n/**\n * TmuxContextMenuProvider - Adds tmux-related items to tab context menu.\n *\n * - On a terminal tab: \"Enter Tmux Mode\"\n * - On a TmuxSessionTab / TmuxPaneTab: \"Exit Tmux Mode\" + Split + Close pane\n */\nlet TmuxContextMenuProvider = class TmuxContextMenuProvider extends tabby_core_1.TabContextMenuItemProvider {\n constructor(tmuxService) {\n super();\n this.tmuxService = tmuxService;\n this.weight = 5;\n }\n async getItems(tab, _tabHeader) {\n // On a TmuxSessionTab: show exit option\n if (tab instanceof tmuxSessionTab_component_1.TmuxSessionTabComponent) {\n return [\n {\n label: 'Exit Tmux Mode',\n click: async () => {\n await this.tmuxService.disconnect();\n },\n },\n ];\n }\n // On a TmuxPaneTab: show exit, split, and close pane\n if (tab instanceof tmuxPaneTab_component_1.TmuxPaneTabComponent) {\n const items = [\n {\n label: 'Exit Tmux Mode',\n click: async () => {\n await this.tmuxService.disconnect();\n },\n },\n {\n label: 'Split',\n submenu: [\n { label: 'Right', click: () => this.splitPane(tab, 'right') },\n { label: 'Down', click: () => this.splitPane(tab, 'down') },\n { label: 'Left', click: () => this.splitPane(tab, 'left') },\n { label: 'Up', click: () => this.splitPane(tab, 'up') },\n ],\n },\n {\n label: 'Close',\n click: () => this.closePane(tab),\n },\n ];\n return items;\n }\n // On a terminal tab: show enter tmux mode option\n if (tab instanceof tabby_terminal_1.BaseTerminalTabComponent) {\n return [\n {\n label: 'Enter Tmux Mode',\n click: async () => {\n await this.tmuxService.attachToTerminal(tab);\n },\n },\n ];\n }\n return [];\n }\n async splitPane(paneTab, direction) {\n const controller = paneTab.controller;\n if (!controller)\n return;\n const paneId = paneTab.paneId;\n const flagMap = {\n 'right': '-h',\n 'down': '-v',\n 'left': '-h -b',\n 'up': '-v -b',\n };\n const flag = flagMap[direction];\n await controller.gateway.sendCommand(`split-window ${flag} -t %${paneId}`);\n // Discover the new pane and trigger layout update\n await controller.refreshPanes();\n }\n async closePane(paneTab) {\n const controller = paneTab.controller;\n if (!controller)\n return;\n await controller.killPane(paneTab.paneId);\n }\n};\nTmuxContextMenuProvider.ctorParameters = () => [\n { type: tmux_service_1.TmuxService }\n];\nTmuxContextMenuProvider = __decorate([\n (0, core_1.Injectable)(),\n __metadata(\"design:paramtypes\", [tmux_service_1.TmuxService])\n], TmuxContextMenuProvider);\nexports.TmuxContextMenuProvider = TmuxContextMenuProvider;\n","module.exports = __WEBPACK_EXTERNAL_MODULE__angular_common__;","module.exports = __WEBPACK_EXTERNAL_MODULE__angular_core__;","module.exports = __WEBPACK_EXTERNAL_MODULE__angular_forms__;","module.exports = __WEBPACK_EXTERNAL_MODULE_rxjs__;","module.exports = __WEBPACK_EXTERNAL_MODULE_tabby_core__;","module.exports = __WEBPACK_EXTERNAL_MODULE_tabby_settings__;","module.exports = __WEBPACK_EXTERNAL_MODULE_tabby_terminal__;","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Check if module exists (development only)\n\tif (__webpack_modules__[moduleId] === undefined) {\n\t\tvar e = new Error(\"Cannot find module '\" + moduleId + \"'\");\n\t\te.code = 'MODULE_NOT_FOUND';\n\t\tthrow e;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\tid: moduleId,\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","","// startup\n// Load entry module and return exports\n// This entry module is referenced by other modules so it can't be inlined\nvar __webpack_exports__ = __webpack_require__(\"./src/index.ts\");\n",""],"names":["module","exports","cssWithMappingToString","list","toString","map","item","content","needLayer","concat","length","join","i","modules","media","dedupe","supports","layer","undefined","alreadyImportedModules","k","id","_k","push","cssMapping","btoa","base64","unescape","encodeURIComponent","JSON","stringify","data","sourceMapping"],"ignoreList":[],"sourceRoot":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tabby-tmux",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Tmux Control Mode support for Tabby",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"tabby-plugin"
|
|
7
|
+
],
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"typings": "typings/index.d.ts",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/ruanimal/tabby-tmux.git"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/ruanimal/tabby-tmux#readme",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/ruanimal/tabby-tmux/issues"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"typings"
|
|
21
|
+
],
|
|
22
|
+
"author": "ruan.lj <ruan.lj@foxmail.com>",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"@angular/common": "^15",
|
|
29
|
+
"@angular/core": "^15",
|
|
30
|
+
"@angular/forms": "^15",
|
|
31
|
+
"@ng-bootstrap/ng-bootstrap": "^14",
|
|
32
|
+
"rxjs": "^7",
|
|
33
|
+
"tabby-core": "*",
|
|
34
|
+
"tabby-settings": "*",
|
|
35
|
+
"tabby-terminal": "*"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@angular/compiler": "^15.2.10",
|
|
39
|
+
"@angular/compiler-cli": "^15.2.10",
|
|
40
|
+
"@ngtools/webpack": "^15.2.11",
|
|
41
|
+
"@types/node": "^20.3.1",
|
|
42
|
+
"babel-loader": "^10.0.0",
|
|
43
|
+
"css-loader": "^7.1.2",
|
|
44
|
+
"sass": "^1.97.2",
|
|
45
|
+
"sass-loader": "^16.0.6",
|
|
46
|
+
"style-loader": "^4.0.0",
|
|
47
|
+
"svg-inline-loader": "^0.8.2",
|
|
48
|
+
"tabby-core": "1.0.231-nightly.0",
|
|
49
|
+
"tabby-local": "1.0.231-nightly.0",
|
|
50
|
+
"tabby-terminal": "1.0.231-nightly.0",
|
|
51
|
+
"to-string-loader": "^1.2.0",
|
|
52
|
+
"typescript": "^4.9.5",
|
|
53
|
+
"webpack": "^5.86.0",
|
|
54
|
+
"webpack-cli": "^5.0.1"
|
|
55
|
+
},
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "webpack --progress --color",
|
|
58
|
+
"watch": "webpack --progress --color --watch"
|
|
59
|
+
}
|
|
60
|
+
}
|