@dolusoft/claude-collab 1.10.3 → 1.10.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -50
- package/dist/cli.js +1 -124
- package/dist/cli.js.map +1 -1
- package/dist/mcp-main.js +1 -124
- package/dist/mcp-main.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/infrastructure/p2p/p2p-protocol.ts","../src/infrastructure/discovery/multicast-discovery.ts","../src/infrastructure/terminal-injector/windows-injector.ts","../src/infrastructure/terminal-injector/index.ts","../src/infrastructure/terminal-injector/injection-queue.ts","../src/infrastructure/p2p/p2p-node.ts","../src/presentation/mcp/tools/ask.tool.ts","../src/presentation/mcp/tools/reply.tool.ts","../src/presentation/mcp/tools/peers.tool.ts","../src/presentation/mcp/tools/history.tool.ts","../src/infrastructure/firewall/firewall.ts","../src/presentation/mcp/tools/firewall-open.tool.ts","../src/presentation/mcp/tools/firewall-close.tool.ts","../src/presentation/mcp/tools/peer-find.tool.ts","../src/presentation/mcp/server.ts","../src/cli.ts"],"names":["EventEmitter","uuidv4","z"],"mappings":";;;;;;;;;;;;;;;AA+CO,SAAS,UAAU,GAAA,EAAqB;AAC7C,EAAA,OAAO,IAAA,CAAK,UAAU,GAAG,CAAA;AAC3B;AAEO,SAAS,MAAM,IAAA,EAAsB;AAC1C,EAAA,OAAO,IAAA,CAAK,MAAM,IAAI,CAAA;AACxB;AC1CO,IAAM,cAAA,GAAiB,eAAA;AACvB,IAAM,cAAA,GAAiB,KAAA;AAC9B,IAAM,qBAAA,GAAwB,GAAA;AAC9B,IAAM,eAAA,GAAkB,GAAA;AAsBjB,IAAM,kBAAA,GAAN,cAAiC,YAAA,CAAa;AAAA,EAC3C,MAAA,GAA8B,IAAA;AAAA,EAC9B,cAAA,GAAwC,IAAA;AAAA,EACxC,YAAA,GAAsC,IAAA;AAAA,EAE7B,KAAA,uBAAY,GAAA,EAAmD;AAAA,EACxE,MAAA,GAAS,EAAA;AAAA,EACT,QAAA,GAAW,CAAA;AAAA,EAEnB,KAAA,CAAM,MAAc,MAAA,EAAsB;AACxC,IAAA,IAAA,CAAK,MAAA,GAAS,IAAA;AACd,IAAA,IAAA,CAAK,QAAA,GAAW,MAAA;AAEhB,IAAA,MAAM,MAAA,GAAS,MAAM,YAAA,CAAa,EAAE,MAAM,MAAA,EAAQ,SAAA,EAAW,MAAM,CAAA;AACnE,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAEd,IAAA,MAAA,CAAO,EAAA,CAAG,OAAA,EAAS,CAAC,GAAA,KAAQ;AAC1B,MAAA,OAAA,CAAQ,KAAA,CAAM,2BAAA,EAA6B,GAAA,CAAI,OAAO,CAAA;AAAA,IACxD,CAAC,CAAA;AAED,IAAA,MAAA,CAAO,EAAA,CAAG,SAAA,EAAW,CAAC,GAAA,EAAK,KAAA,KAAU;AACnC,MAAA,IAAI;AACF,QAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,UAAU,CAAA;AACrC,QAAA,IAAA,CAAK,aAAA,CAAc,GAAA,EAAK,KAAA,CAAM,OAAO,CAAA;AAAA,MACvC,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF,CAAC,CAAA;AAED,IAAA,MAAA,CAAO,IAAA,CAAK,gBAAgB,MAAM;AAChC,MAAA,IAAI;AACF,QAAA,MAAA,CAAO,cAAc,cAAc,CAAA;AACnC,QAAA,MAAA,CAAO,gBAAgB,CAAC,CAAA;AACxB,QAAA,MAAA,CAAO,qBAAqB,KAAK,CAAA;AAAA,MACnC,SAAS,GAAA,EAAK;AACZ,QAAA,OAAA,CAAQ,KAAA,CAAM,iCAAiC,GAAG,CAAA;AAAA,MACpD;AAEA,MAAA,IAAA,CAAK,QAAA,EAAS;AACd,MAAA,IAAA,CAAK,iBAAiB,WAAA,CAAY,MAAM,IAAA,CAAK,QAAA,IAAY,qBAAqB,CAAA;AAC9E,MAAA,IAAA,CAAK,eAAe,WAAA,CAAY,MAAM,IAAA,CAAK,aAAA,IAAiB,GAAK,CAAA;AAAA,IACnE,CAAC,CAAA;AAAA,EACH;AAAA,EAEA,IAAA,GAAa;AACX,IAAA,IAAI,KAAK,cAAA,EAAgB;AAAE,MAAA,aAAA,CAAc,KAAK,cAAc,CAAA;AAAG,MAAA,IAAA,CAAK,cAAA,GAAiB,IAAA;AAAA,IAAM;AAC3F,IAAA,IAAI,KAAK,YAAA,EAAc;AAAE,MAAA,aAAA,CAAc,KAAK,YAAY,CAAA;AAAG,MAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AAAA,IAAM;AACrF,IAAA,IAAI,KAAK,MAAA,EAAQ;AACf,MAAA,IAAA,CAAK,YAAY,EAAE,IAAA,EAAM,SAAS,IAAA,EAAM,IAAA,CAAK,QAAQ,CAAA;AACrD,MAAA,IAAI;AACF,QAAA,IAAA,CAAK,MAAA,CAAO,eAAe,cAAc,CAAA;AACzC,QAAA,IAAA,CAAK,OAAO,KAAA,EAAM;AAAA,MACpB,CAAA,CAAA,MAAQ;AAAA,MAAe;AACvB,MAAA,IAAA,CAAK,MAAA,GAAS,IAAA;AAAA,IAChB;AACA,IAAA,IAAA,CAAK,MAAM,KAAA,EAAM;AAAA,EACnB;AAAA,EAEA,cAAA,GAAyB;AACvB,IAAA,MAAM,UAAA,GAAa,GAAG,iBAAA,EAAkB;AACxC,IAAA,KAAA,MAAW,KAAA,IAAS,MAAA,CAAO,MAAA,CAAO,UAAU,CAAA,EAAG;AAC7C,MAAA,IAAI,CAAC,KAAA,EAAO;AACZ,MAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,QAAA,IAAI,KAAK,MAAA,KAAW,MAAA,IAAU,CAAC,IAAA,CAAK,QAAA,SAAiB,IAAA,CAAK,OAAA;AAAA,MAC5D;AAAA,IACF;AACA,IAAA,OAAO,WAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMQ,QAAA,GAAiB;AACvB,IAAA,IAAA,CAAK,WAAA,CAAY,EAAE,IAAA,EAAM,UAAA,EAAY,IAAA,EAAM,KAAK,MAAA,EAAQ,MAAA,EAAQ,IAAA,CAAK,QAAA,EAAU,CAAA;AAAA,EACjF;AAAA,EAEQ,YAAY,GAAA,EAAyB;AAC3C,IAAA,IAAI,CAAC,KAAK,MAAA,EAAQ;AAClB,IAAA,MAAM,MAAM,MAAA,CAAO,IAAA,CAAK,IAAA,CAAK,SAAA,CAAU,GAAG,CAAC,CAAA;AAC3C,IAAA,IAAA,CAAK,OAAO,IAAA,CAAK,GAAA,EAAK,cAAA,EAAgB,cAAA,EAAgB,CAAC,GAAA,KAAQ;AAC7D,MAAA,IAAI,GAAA,EAAK,OAAA,CAAQ,KAAA,CAAM,yBAAA,EAA2B,IAAI,OAAO,CAAA;AAAA,IAC/D,CAAC,CAAA;AAAA,EACH;AAAA,EAEQ,YAAY,IAAA,EAAoB;AACtC,IAAA,IAAI,CAAC,KAAK,MAAA,EAAQ;AAClB,IAAA,MAAM,MAAM,MAAA,CAAO,IAAA,CAAK,IAAA,CAAK,SAAA,CAAU,EAAE,IAAA,EAAM,UAAA,EAAY,IAAA,EAAM,IAAA,CAAK,QAAQ,MAAA,EAAQ,IAAA,CAAK,UAAU,OAAA,EAAS,IAAA,EAAM,CAAC,CAAA;AACrH,IAAA,IAAA,CAAK,OAAO,IAAA,CAAK,GAAA,EAAK,cAAA,EAAgB,IAAA,EAAM,CAAC,GAAA,KAAQ;AACnD,MAAA,IAAI,KAAK,OAAA,CAAQ,KAAA,CAAM,gCAAgC,IAAI,CAAA,OAAA,CAAA,EAAW,IAAI,OAAO,CAAA;AAAA,IACnF,CAAC,CAAA;AAAA,EACH;AAAA,EAEQ,aAAA,CAAc,KAAmB,MAAA,EAAsB;AAC7D,IAAA,IAAI,GAAA,CAAI,SAAS,UAAA,EAAY;AAC3B,MAAA,IAAI,GAAA,CAAI,IAAA,KAAS,IAAA,CAAK,MAAA,EAAQ;AAE9B,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,IAAI,IAAI,CAAA;AACxC,MAAA,IAAI,CAAC,QAAA,EAAU;AACb,QAAA,MAAM,IAAA,GAAO,EAAE,IAAA,EAAM,GAAA,CAAI,IAAA,EAAM,EAAA,EAAI,MAAA,EAAQ,MAAA,EAAQ,GAAA,CAAI,MAAA,EAAQ,QAAA,EAAU,IAAA,CAAK,KAAI,EAAE;AACpF,QAAA,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,GAAA,CAAI,IAAA,EAAM,IAAI,CAAA;AAC7B,QAAA,OAAA,CAAQ,KAAA,CAAM,gCAAgC,GAAA,CAAI,IAAI,MAAM,MAAM,CAAA,CAAA,EAAI,GAAA,CAAI,MAAM,CAAA,CAAE,CAAA;AAAA,MACpF,CAAA,MAAO;AACL,QAAA,QAAA,CAAS,QAAA,GAAW,KAAK,GAAA,EAAI;AAC7B,QAAA,QAAA,CAAS,EAAA,GAAK,MAAA;AACd,QAAA,QAAA,CAAS,SAAS,GAAA,CAAI,MAAA;AAAA,MACxB;AAKA,MAAA,IAAI,CAAC,IAAI,OAAA,EAAS;AAChB,QAAA,IAAA,CAAK,YAAY,MAAM,CAAA;AAAA,MACzB;AAIA,MAAA,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,EAAE,IAAA,EAAM,GAAA,CAAI,IAAA,EAAM,EAAA,EAAI,MAAA,EAAQ,MAAA,EAAQ,GAAA,CAAI,MAAA,EAAQ,CAAA;AAAA,IAC5E,CAAA,MAAA,IAAW,GAAA,CAAI,IAAA,KAAS,OAAA,EAAS;AAC/B,MAAA,IAAI,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,GAAA,CAAI,IAAI,CAAA,EAAG;AAC5B,QAAA,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,GAAA,CAAI,IAAI,CAAA;AAC1B,QAAA,IAAA,CAAK,IAAA,CAAK,WAAA,EAAa,GAAA,CAAI,IAAI,CAAA;AAC/B,QAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,uBAAA,EAA0B,GAAA,CAAI,IAAI,CAAA,CAAE,CAAA;AAAA,MACpD;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,aAAA,GAAsB;AAC5B,IAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,IAAA,KAAA,MAAW,CAAC,IAAA,EAAM,IAAI,CAAA,IAAK,KAAK,KAAA,EAAO;AACrC,MAAA,IAAI,GAAA,GAAM,IAAA,CAAK,QAAA,GAAW,eAAA,EAAiB;AACzC,QAAA,IAAA,CAAK,KAAA,CAAM,OAAO,IAAI,CAAA;AACtB,QAAA,IAAA,CAAK,IAAA,CAAK,aAAa,IAAI,CAAA;AAC3B,QAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,4BAAA,EAA+B,IAAI,CAAA,CAAE,CAAA;AAAA,MACrD;AAAA,IACF;AAAA,EACF;AACF,CAAA;AChKA,IAAM,YAAA,GAAe;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AA4GrB,SAAS,WAAA,CAAY,WAAmB,IAAA,EAAsB;AAC5D,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,MAAA,EAAO,EAAG,CAAA,UAAA,EAAa,IAAA,CAAK,GAAA,EAAK,CAAA,IAAA,CAAM,CAAA,CAAE,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA;AAChF,EAAA,OAAO;AAAA,QAAA,EACC,OAAO,CAAA;AAAA;AAAA,aAAA,EAEF,SAAS;AAAA,iBAAA,EACL,YAAY,CAAA;AAAA,EAC7B,IAAI;AAAA,CAAA;AAEN;AAEA,SAAS,IAAI,MAAA,EAA+B;AAC1C,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,IAAA,MAAM,UAAU,MAAA,CAAO,IAAA,CAAK,QAAQ,SAAS,CAAA,CAAE,SAAS,QAAQ,CAAA;AAChE,IAAA,QAAA;AAAA,MACE,YAAA;AAAA,MACA,CAAC,YAAA,EAAc,cAAA,EAAgB,QAAA,EAAU,mBAAmB,OAAO,CAAA;AAAA,MACnE,EAAE,aAAa,IAAA,EAAK;AAAA,MACpB,MAAM;AACJ,QAAA,MAAM,OAAA,GAAU,MAAA,CAAO,KAAA,CAAM,mBAAmB,IAAI,CAAC,CAAA;AACrD,QAAA,IAAI,SAAS,IAAI;AAAE,UAAA,UAAA,CAAW,OAAO,CAAA;AAAA,QAAG,CAAA,CAAA,MAAQ;AAAA,QAAW;AAC3D,QAAA,OAAA,EAAQ;AAAA,MACV;AAAA,KACF;AAAA,EACF,CAAC,CAAA;AACH;AAEA,eAAsB,cAAc,IAAA,EAA6B;AAC/D,EAAA,MAAM,YAAY,OAAA,CAAQ,IAAA;AAC1B,EAAA,MAAM,UAAU,MAAA,CAAO,IAAA,CAAK,MAAM,SAAS,CAAA,CAAE,SAAS,QAAQ,CAAA;AAE9D,EAAA,MAAM,MAAA,GAAS,YAAY,SAAA,EAAW;AAAA,iDAAA,EACW,OAAO,CAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,CAazD,CAAA;AAEC,EAAA,MAAM,IAAI,MAAM,CAAA;AAClB;AAEA,eAAsB,kBAAA,GAAoC;AACxD,EAAA,MAAM,YAAY,OAAA,CAAQ,IAAA;AAE1B,EAAA,MAAM,MAAA,GAAS,YAAY,SAAA,EAAW;AAAA;AAAA,CAEvC,CAAA;AAEC,EAAA,MAAM,IAAI,MAAM,CAAA;AAClB;;;ACtKA,SAAS,2BAA2B,QAAA,EAAsC;AAExE,EAAA,MAAM,UAAU,QAAA,CAAS,OAAA,CAAQ,QAAQ,MAAA,EAAQ,GAAG,EAAE,IAAA,EAAK;AAC3D,EAAA,OAAO,CAAA,gBAAA,EAAmB,QAAA,CAAS,UAAU,CAAA,GAAA,EAAM,SAAS,IAAA,CAAK,WAAW,CAAA,EAAA,EAAK,QAAA,CAAS,KAAK,QAAQ,CAAA,GAAA,EAAM,OAAO,CAAA,8BAAA,EAAiC,SAAS,UAAU,CAAA,kCAAA,CAAA;AAC1K;AAMA,eAAsB,yBAAyB,QAAA,EAA6C;AAC1F,EAAA,IAAI,OAAA,CAAQ,aAAa,OAAA,EAAS;AAElC,EAAA,MAAM,IAAA,GAAO,2BAA2B,QAAQ,CAAA;AAChD,EAAA,MAAM,cAAc,IAAI,CAAA;AAC1B;AAMA,eAAsB,iBAAA,GAAmC;AACvD,EAAA,IAAI,OAAA,CAAQ,aAAa,OAAA,EAAS;AAClC,EAAA,MAAM,kBAAA,EAAmB;AAC3B;;;AC1BA,IAAM,gBAAA,GAAmB,IAAI,EAAA,GAAK,GAAA;AAElC,IAAM,cAAA,GAAN,cAA6BA,YAAAA,CAAa;AAAA,EAChC,QAA8B,EAAC;AAAA,EAC/B,UAAA,GAAa,KAAA;AAAA;AAAA;AAAA;AAAA,EAKrB,QAAQ,QAAA,EAAoC;AAC1C,IAAA,IAAA,CAAK,KAAA,CAAM,KAAK,QAAQ,CAAA;AACxB,IAAA,IAAI,CAAC,IAAA,CAAK,UAAA,EAAY,KAAK,KAAK,WAAA,EAAY;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAA,GAAsB;AACpB,IAAA,IAAA,CAAK,KAAK,SAAS,CAAA;AAAA,EACrB;AAAA,EAEA,MAAc,WAAA,GAA6B;AACzC,IAAA,IAAI,IAAA,CAAK,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG;AAC3B,MAAA,IAAA,CAAK,UAAA,GAAa,KAAA;AAClB,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAClB,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,KAAA,CAAM,KAAA,EAAM;AAGlC,IAAA,MAAM,yBAAyB,QAAQ,CAAA;AAGvC,IAAA,MAAM,IAAI,OAAA,CAAc,CAAC,OAAA,KAAY;AACnC,MAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,OAAA,EAAS,gBAAgB,CAAA;AAClD,MAAA,IAAA,CAAK,IAAA,CAAK,WAAW,MAAM;AACzB,QAAA,YAAA,CAAa,KAAK,CAAA;AAClB,QAAA,OAAA,EAAQ;AAAA,MACV,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAGD,IAAA,MAAM,iBAAA,EAAkB;AAGxB,IAAA,KAAK,KAAK,WAAA,EAAY;AAAA,EACxB;AACF,CAAA;AAEO,IAAM,cAAA,GAAiB,IAAI,cAAA,EAAe;;;ACP1C,IAAM,UAAN,MAAuC;AAAA,EA2B5C,WAAA,CACmB,SAAA,GAA8B,CAAC,GAAA,EAAO,KAAK,CAAA,EAC5D;AADiB,IAAA,IAAA,CAAA,SAAA,GAAA,SAAA;AAAA,EAChB;AAAA,EA5BK,MAAA,GAAiC,IAAA;AAAA,EACjC,MAAA,GAAS,EAAA;AAAA,EACT,OAAA,GAAU,KAAA;AAAA;AAAA,EAGD,eAAA,uBAAsB,GAAA,EAAuB;AAAA;AAAA,EAE7C,QAAA,uBAAe,GAAA,EAAuB;AAAA;AAAA,EAEtC,eAAA,uBAAsB,GAAA,EAAY;AAAA,EAElC,iBAAA,uBAAwB,GAAA,EAA8B;AAAA,EACtD,eAAA,uBAAsB,GAAA,EAA4B;AAAA,EAClD,aAAA,uBAAoB,GAAA,EAAkE;AAAA,EACtF,gBAAA,uBAAuB,GAAA,EAAoB;AAAA,EAC3C,eAAA,uBAAsB,GAAA,EAA2B;AAAA;AAAA,EAGjD,aAAA,uBAAoB,GAAA,EAAiD;AAAA;AAAA,EAErE,sBAAA,uBAA6B,GAAA,EAAmD;AAAA,EAEzF,SAAA,GAAuC,IAAA;AAAA,EAEvC,SAAA,GAAY,CAAA;AAAA;AAAA;AAAA;AAAA,EAUpB,IAAI,WAAA,GAAuB;AAAE,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,EAAS;AAAA,EAClD,IAAI,IAAA,GAAe;AAAE,IAAA,OAAO,IAAA,CAAK,SAAA;AAAA,EAAW;AAAA,EAE5C,IAAI,aAAA,GAAoC;AACtC,IAAA,OAAO,KAAK,MAAA,IAAU,MAAA;AAAA,EACxB;AAAA,EAEA,MAAM,IAAA,CAAK,IAAA,EAAc,WAAA,EAA0C;AACjE,IAAA,IAAA,CAAK,MAAA,GAAS,IAAA;AACd,IAAA,MAAM,KAAK,WAAA,EAAY;AACvB,IAAA,IAAA,CAAK,cAAA,EAAe;AACpB,IAAA,OAAO;AAAA,MACL,UAAUC,EAAA,EAAO;AAAA,MACjB,MAAA,EAAQ,IAAA;AAAA,MACR,QAAA,EAAU,IAAA;AAAA,MACV,WAAA;AAAA,MACA,MAAA,EAAQ,QAAA;AAAA,MACR,MAAM,IAAA,CAAK;AAAA,KACb;AAAA,EACF;AAAA,EAEA,MAAM,GAAA,CAAI,MAAA,EAAgB,OAAA,EAAiB,MAAA,EAAwC;AACjF,IAAA,MAAM,EAAA,GAAK,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,MAAM,CAAA;AAC1C,IAAA,IAAI,CAAC,EAAA,IAAM,EAAA,CAAG,UAAA,KAAe,UAAU,IAAA,EAAM;AAC3C,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,MAAA,EAAS,MAAM,CAAA,oDAAA,CAAsD,CAAA;AAAA,IACvF;AAEA,IAAA,MAAM,aAAaA,EAAA,EAAO;AAC1B,IAAA,IAAA,CAAK,aAAA,CAAc,GAAA,CAAI,UAAA,EAAY,EAAE,MAAA,EAAQ,OAAA,EAAS,OAAA,EAAA,iBAAS,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY,EAAG,CAAA;AAEzF,IAAA,MAAM,aAAa,IAAA,CAAK,eAAA;AAAA,MACtB,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,KAAS,SAAA,IAAa,EAAE,UAAA,KAAe,UAAA;AAAA,MAChD;AAAA,KACF;AAEA,IAAA,IAAA,CAAK,QAAA,CAAS,EAAA,EAAI,EAAE,IAAA,EAAM,KAAA,EAAO,IAAA,EAAM,IAAA,CAAK,MAAA,EAAQ,UAAA,EAAY,OAAA,EAAS,MAAA,EAAQ,CAAA;AACjF,IAAA,MAAM,UAAA;AACN,IAAA,OAAO,UAAA;AAAA,EACT;AAAA,EAEA,aAAA,CAAc,YAAoB,SAAA,EAAsD;AAEtF,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,UAAU,CAAA;AAClD,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,OAAO,QAAQ,OAAA,CAAQ,IAAA,CAAK,YAAA,CAAa,UAAA,EAAY,MAAM,CAAC,CAAA;AAAA,IAC9D;AAEA,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,MAAA,MAAM,OAAA,GAAU,WAAW,MAAM;AAC/B,QAAA,IAAA,CAAK,aAAA,CAAc,OAAO,UAAU,CAAA;AACpC,QAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,MACd,GAAG,SAAS,CAAA;AAEZ,MAAA,IAAA,CAAK,aAAA,CAAc,GAAA,CAAI,UAAA,EAAY,CAAC,MAAA,KAAW;AAC7C,QAAA,YAAA,CAAa,OAAO,CAAA;AACpB,QAAA,OAAA,CAAQ,MAAM,CAAA;AAAA,MAChB,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,YAAY,UAAA,EAAuD;AACvE,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,UAAU,CAAA;AAClD,IAAA,OAAO,MAAA,GAAS,IAAA,CAAK,YAAA,CAAa,UAAA,EAAY,MAAM,CAAA,GAAI,IAAA;AAAA,EAC1D;AAAA,EAEQ,YAAA,CAAa,YAAoB,MAAA,EAA2C;AAClF,IAAA,OAAO;AAAA,MACL,UAAA;AAAA,MACA,IAAA,EAAM,EAAE,WAAA,EAAa,CAAA,EAAG,OAAO,QAAQ,CAAA,OAAA,CAAA,EAAW,QAAA,EAAU,MAAA,CAAO,QAAA,EAAS;AAAA,MAC5E,SAAS,MAAA,CAAO,OAAA;AAAA,MAChB,QAAQ,MAAA,CAAO,MAAA;AAAA,MACf,YAAY,MAAA,CAAO;AAAA,KACrB;AAAA,EACF;AAAA,EAEA,MAAM,KAAA,CAAM,UAAA,EAAoB,OAAA,EAAiB,MAAA,EAAsC;AACrF,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,iBAAA,CAAkB,GAAA,CAAI,UAAU,CAAA;AACtD,IAAA,IAAI,CAAC,QAAA,EAAU,MAAM,IAAI,KAAA,CAAM,CAAA,SAAA,EAAY,UAAU,CAAA,UAAA,CAAY,CAAA;AAEjE,IAAA,QAAA,CAAS,QAAA,GAAW,IAAA;AACpB,IAAA,QAAA,CAAS,aAAA,GAAgB,OAAA;AACzB,IAAA,QAAA,CAAS,YAAA,GAAe,MAAA;AAExB,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,gBAAA,CAAiB,GAAA,CAAI,UAAU,CAAA;AACvD,IAAA,IAAI,UAAA,EAAY;AACd,MAAA,MAAM,SAAA,GAAmD;AAAA,QACvD,IAAA,EAAM,QAAA;AAAA,QACN,MAAM,IAAA,CAAK,MAAA;AAAA,QACX,UAAA;AAAA,QACA,OAAA;AAAA,QACA,MAAA;AAAA,QACA,UAAA,EAAA,iBAAY,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,OACrC;AACA,MAAA,MAAM,EAAA,GAAK,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,UAAU,CAAA;AAC9C,MAAA,IAAI,EAAA,IAAM,EAAA,CAAG,UAAA,KAAe,SAAA,CAAU,IAAA,EAAM;AAC1C,QAAA,IAAA,CAAK,QAAA,CAAS,IAAI,SAAS,CAAA;AAAA,MAC7B,CAAA,MAAO;AAEL,QAAA,IAAA,CAAK,sBAAA,CAAuB,GAAA,CAAI,UAAA,EAAY,SAAS,CAAA;AACrD,QAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,OAAA,EAAU,UAAU,CAAA,qDAAA,CAAuD,CAAA;AAAA,MAC3F;AAAA,IACF;AAEA,IAAA,cAAA,CAAe,aAAA,EAAc;AAAA,EAC/B;AAAA,EAEA,MAAM,QAAA,GAAiC;AACrC,IAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,IAAA,MAAM,YAAY,CAAC,GAAG,IAAA,CAAK,iBAAA,CAAkB,QAAQ,CAAA,CAClD,MAAA,CAAO,CAAC,MAAM,CAAC,CAAA,CAAE,QAAQ,CAAA,CACzB,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,MACX,YAAY,CAAA,CAAE,UAAA;AAAA,MACd,IAAA,EAAM,EAAE,WAAA,EAAa,CAAA,EAAG,EAAE,QAAQ,CAAA,OAAA,CAAA,EAAW,QAAA,EAAU,CAAA,CAAE,QAAA,EAAS;AAAA,MAClE,SAAS,CAAA,CAAE,OAAA;AAAA,MACX,QAAQ,CAAA,CAAE,MAAA;AAAA,MACV,MAAA,EAAQ,SAAA;AAAA,MACR,SAAA,EAAW,CAAA,CAAE,SAAA,CAAU,WAAA,EAAY;AAAA,MACnC,KAAA,EAAO,GAAA,GAAM,CAAA,CAAE,SAAA,CAAU,OAAA;AAAQ,KACnC,CAAE,CAAA;AACJ,IAAA,OAAO,EAAE,SAAA,EAAW,UAAA,EAAY,UAAU,MAAA,EAAQ,YAAA,EAAc,UAAU,MAAA,EAAO;AAAA,EACnF;AAAA,EAEA,OAAA,GAAoB;AAClB,IAAA,OAAO;AAAA,MACL,UAAU,IAAA,CAAK,MAAA;AAAA,MACf,MAAM,IAAA,CAAK,SAAA;AAAA,MACX,gBAAgB,CAAC,GAAG,IAAA,CAAK,eAAA,CAAgB,MAAM;AAAA,KACjD;AAAA,EACF;AAAA,EAEA,UAAA,GAA6B;AAC3B,IAAA,MAAM,UAA0B,EAAC;AAEjC,IAAA,KAAA,MAAW,CAAC,UAAA,EAAY,IAAI,CAAA,IAAK,KAAK,aAAA,EAAe;AACnD,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,UAAU,CAAA;AAClD,MAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,QACX,SAAA,EAAW,MAAA;AAAA,QACX,UAAA;AAAA,QACA,MAAM,IAAA,CAAK,MAAA;AAAA,QACX,UAAU,IAAA,CAAK,OAAA;AAAA,QACf,SAAS,IAAA,CAAK,OAAA;AAAA,QACd,GAAI,MAAA,GAAS,EAAE,MAAA,EAAQ,MAAA,CAAO,SAAS,UAAA,EAAY,MAAA,CAAO,UAAA,EAAW,GAAI;AAAC,OAC3E,CAAA;AAAA,IACH;AAEA,IAAA,KAAA,MAAW,GAAG,QAAQ,CAAA,IAAK,KAAK,iBAAA,EAAmB;AACjD,MAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,QACX,SAAA,EAAW,UAAA;AAAA,QACX,YAAY,QAAA,CAAS,UAAA;AAAA,QACrB,MAAM,QAAA,CAAS,QAAA;AAAA,QACf,UAAU,QAAA,CAAS,OAAA;AAAA,QACnB,OAAA,EAAS,QAAA,CAAS,SAAA,CAAU,WAAA,EAAY;AAAA,QACxC,GAAI,QAAA,CAAS,QAAA,IAAY,QAAA,CAAS,aAAA,GAC9B,EAAE,MAAA,EAAQ,QAAA,CAAS,aAAA,EAAe,UAAA,EAAA,qBAAgB,IAAA,EAAK,EAAE,WAAA,EAAY,KACrE;AAAC,OACN,CAAA;AAAA,IACH;AAEA,IAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,EAAE,OAAA,CAAQ,aAAA,CAAc,CAAA,CAAE,OAAO,CAAC,CAAA;AAAA,EAClE;AAAA,EAEA,MAAM,UAAA,GAA4B;AAChC,IAAA,IAAA,CAAK,WAAW,IAAA,EAAK;AACrB,IAAA,IAAA,CAAK,SAAA,GAAY,IAAA;AACjB,IAAA,KAAA,MAAW,MAAM,IAAA,CAAK,eAAA,CAAgB,MAAA,EAAO,KAAM,KAAA,EAAM;AACzD,IAAA,IAAA,CAAK,gBAAgB,KAAA,EAAM;AAC3B,IAAA,IAAA,CAAK,SAAS,KAAA,EAAM;AACpB,IAAA,IAAA,CAAK,QAAQ,KAAA,EAAM;AACnB,IAAA,IAAA,CAAK,MAAA,GAAS,IAAA;AACd,IAAA,IAAA,CAAK,OAAA,GAAU,KAAA;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAMQ,WAAA,GAA6B;AACnC,IAAA,MAAM,CAAC,GAAA,EAAK,GAAG,CAAA,GAAI,IAAA,CAAK,SAAA;AACxB,IAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,QAAO,IAAK,GAAA,GAAM,GAAA,GAAM,CAAA,CAAE,CAAA,GAAI,GAAA;AAEjE,IAAA,MAAM,OAAA,GAAU,CAAC,YAAA,KAAwC;AACvD,MAAA,IAAI,iBAAiB,CAAA,EAAG;AACtB,QAAA,OAAO,OAAA,CAAQ,OAAO,IAAI,KAAA,CAAM,+BAA+B,GAAG,CAAA,CAAA,EAAI,GAAG,CAAA,CAAE,CAAC,CAAA;AAAA,MAC9E;AAEA,MAAA,MAAM,OAAO,IAAA,EAAK;AAClB,MAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,QAAA,MAAM,GAAA,GAAM,IAAI,eAAA,CAAgB,EAAE,MAAM,CAAA;AAExC,QAAA,GAAA,CAAI,IAAA,CAAK,aAAa,MAAM;AAC1B,UAAA,IAAA,CAAK,MAAA,GAAS,GAAA;AACd,UAAA,IAAA,CAAK,SAAA,GAAY,IAAA;AACjB,UAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AACf,UAAA,OAAA,CAAQ,MAAM,CAAA,wBAAA,EAA2B,IAAI,CAAA,KAAA,EAAQ,IAAA,CAAK,MAAM,CAAA,CAAA,CAAG,CAAA;AACnE,UAAA,IAAA,CAAK,qBAAqB,GAAG,CAAA;AAC7B,UAAA,OAAA,EAAQ;AAAA,QACV,CAAC,CAAA;AAED,QAAA,GAAA,CAAI,IAAA,CAAK,OAAA,EAAS,CAAC,GAAA,KAA+B;AAChD,UAAA,GAAA,CAAI,KAAA,EAAM;AACV,UAAA,IAAI,GAAA,CAAI,SAAS,YAAA,EAAc;AAE7B,YAAA,OAAA,CAAQ,YAAA,GAAe,CAAC,CAAA,CAAE,IAAA,CAAK,SAAS,MAAM,CAAA;AAAA,UAChD,CAAA,MAAO;AACL,YAAA,MAAA,CAAO,GAAG,CAAA;AAAA,UACZ;AAAA,QACF,CAAC,CAAA;AAAA,MACH,CAAC,CAAA;AAAA,IACH,CAAA;AAEA,IAAA,OAAO,QAAQ,EAAE,CAAA;AAAA,EACnB;AAAA,EAEQ,qBAAqB,GAAA,EAA4B;AACvD,IAAA,GAAA,CAAI,EAAA,CAAG,YAAA,EAAc,CAAC,EAAA,KAAO;AAC3B,MAAA,EAAA,CAAG,EAAA,CAAG,SAAA,EAAW,CAAC,IAAA,KAAS;AACzB,QAAA,IAAI;AACF,UAAA,IAAA,CAAK,cAAc,EAAA,EAAI,KAAA,CAAM,IAAA,CAAK,QAAA,EAAU,CAAC,CAAA;AAAA,QAC/C,CAAA,CAAA,MAAQ;AAAA,QAAyB;AAAA,MACnC,CAAC,CAAA;AAED,MAAA,EAAA,CAAG,EAAA,CAAG,SAAS,MAAM;AACnB,QAAA,MAAM,IAAA,GAAO,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,EAAE,CAAA;AACjC,QAAA,IAAI,IAAA,EAAM;AACR,UAAA,IAAA,CAAK,QAAA,CAAS,OAAO,EAAE,CAAA;AACvB,UAAA,IAAI,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,IAAI,MAAM,EAAA,EAAI;AACzC,YAAA,IAAA,CAAK,eAAA,CAAgB,OAAO,IAAI,CAAA;AAChC,YAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,mCAAA,EAAsC,IAAI,CAAA,CAAE,CAAA;AAAA,UAC5D;AAAA,QACF;AAAA,MACF,CAAC,CAAA;AAED,MAAA,EAAA,CAAG,EAAA,CAAG,OAAA,EAAS,CAAC,GAAA,KAAQ;AACtB,QAAA,OAAA,CAAQ,KAAA,CAAM,yBAAA,EAA2B,GAAA,CAAI,OAAO,CAAA;AAAA,MACtD,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAED,IAAA,GAAA,CAAI,EAAA,CAAG,OAAA,EAAS,CAAC,GAAA,KAAQ;AACvB,MAAA,OAAA,CAAQ,KAAA,CAAM,qBAAA,EAAuB,GAAA,CAAI,OAAO,CAAA;AAAA,IAClD,CAAC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAMQ,cAAA,GAAuB;AAC7B,IAAA,MAAM,SAAA,GAAY,IAAI,kBAAA,EAAmB;AACzC,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AAEjB,IAAA,SAAA,CAAU,EAAA,CAAG,YAAA,EAAc,CAAC,IAAA,KAAyB;AACnD,MAAA,IAAI,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA,EAAG;AACzC,MAAA,IAAI,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA,EAAG;AACzC,MAAA,IAAA,CAAK,cAAc,IAAA,CAAK,IAAA,EAAM,IAAA,CAAK,EAAA,EAAI,KAAK,MAAM,CAAA;AAAA,IACpD,CAAC,CAAA;AAED,IAAA,SAAA,CAAU,KAAA,CAAM,IAAA,CAAK,MAAA,EAAQ,IAAA,CAAK,SAAS,CAAA;AAAA,EAC7C;AAAA,EAEQ,aAAA,CAAc,QAAA,EAAkB,IAAA,EAAc,IAAA,EAAoB;AACxE,IAAA,IAAA,CAAK,eAAA,CAAgB,IAAI,QAAQ,CAAA;AACjC,IAAA,MAAM,KAAK,IAAI,SAAA,CAAU,QAAQ,IAAI,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE,CAAA;AAE/C,IAAA,EAAA,CAAG,EAAA,CAAG,QAAQ,MAAM;AAClB,MAAA,IAAA,CAAK,QAAA,CAAS,IAAI,EAAE,IAAA,EAAM,SAAS,IAAA,EAAM,IAAA,CAAK,QAAQ,CAAA;AAAA,IACxD,CAAC,CAAA;AAED,IAAA,EAAA,CAAG,EAAA,CAAG,SAAA,EAAW,CAAC,IAAA,KAAS;AACzB,MAAA,IAAI;AACF,QAAA,IAAA,CAAK,cAAc,EAAA,EAAI,KAAA,CAAM,IAAA,CAAK,QAAA,EAAU,CAAC,CAAA;AAAA,MAC/C,CAAA,CAAA,MAAQ;AAAA,MAAyB;AAAA,IACnC,CAAC,CAAA;AAED,IAAA,EAAA,CAAG,EAAA,CAAG,SAAS,MAAM;AACnB,MAAA,IAAA,CAAK,eAAA,CAAgB,OAAO,QAAQ,CAAA;AACpC,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,EAAE,CAAA;AACjC,MAAA,IAAI,IAAA,EAAM;AACR,QAAA,IAAA,CAAK,QAAA,CAAS,OAAO,EAAE,CAAA;AACvB,QAAA,IAAI,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,IAAI,MAAM,EAAA,EAAI;AACzC,UAAA,IAAA,CAAK,eAAA,CAAgB,OAAO,IAAI,CAAA;AAChC,UAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,8BAAA,EAAiC,IAAI,CAAA,CAAE,CAAA;AAAA,QACvD;AAAA,MACF;AAAA,IACF,CAAC,CAAA;AAED,IAAA,EAAA,CAAG,EAAA,CAAG,OAAA,EAAS,CAAC,GAAA,KAAQ;AACtB,MAAA,OAAA,CAAQ,MAAM,CAAA,kBAAA,EAAqB,QAAQ,CAAA,UAAA,EAAa,GAAA,CAAI,OAAO,CAAA,CAAE,CAAA;AACrE,MAAA,IAAA,CAAK,eAAA,CAAgB,OAAO,QAAQ,CAAA;AAAA,IACtC,CAAC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAMQ,aAAA,CAAc,IAAe,GAAA,EAAmB;AAEtD,IAAA,KAAA,MAAW,OAAA,IAAW,IAAA,CAAK,eAAA,EAAiB,OAAA,CAAQ,GAAG,CAAA;AAEvD,IAAA,QAAQ,IAAI,IAAA;AAAM,MAChB,KAAK,OAAA,EAAS;AACZ,QAAA,IAAI,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,GAAA,CAAI,IAAI,CAAA,EAAG;AACtC,UAAA,EAAA,CAAG,SAAA,EAAU;AACb,UAAA;AAAA,QACF;AACA,QAAA,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,GAAA,CAAI,IAAA,EAAM,EAAE,CAAA;AACrC,QAAA,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,EAAA,EAAI,GAAA,CAAI,IAAI,CAAA;AAC9B,QAAA,IAAA,CAAK,eAAA,CAAgB,MAAA,CAAO,GAAA,CAAI,IAAI,CAAA;AACpC,QAAA,IAAA,CAAK,QAAA,CAAS,IAAI,EAAE,IAAA,EAAM,aAAa,IAAA,EAAM,IAAA,CAAK,QAAQ,CAAA;AAC1D,QAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,6BAAA,EAAgC,GAAA,CAAI,IAAI,CAAA,CAAE,CAAA;AACxD,QAAA,IAAA,CAAK,oBAAA,CAAqB,GAAA,CAAI,IAAA,EAAM,EAAE,CAAA;AACtC,QAAA;AAAA,MACF;AAAA,MAEA,KAAK,WAAA,EAAa;AAChB,QAAA,IAAI,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,GAAA,CAAI,IAAI,CAAA,EAAG;AACtC,UAAA,EAAA,CAAG,SAAA,EAAU;AACb,UAAA;AAAA,QACF;AACA,QAAA,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,GAAA,CAAI,IAAA,EAAM,EAAE,CAAA;AACrC,QAAA,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,EAAA,EAAI,GAAA,CAAI,IAAI,CAAA;AAC9B,QAAA,IAAA,CAAK,eAAA,CAAgB,MAAA,CAAO,GAAA,CAAI,IAAI,CAAA;AACpC,QAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,yBAAA,EAA4B,GAAA,CAAI,IAAI,CAAA,CAAE,CAAA;AACpD,QAAA,IAAA,CAAK,oBAAA,CAAqB,GAAA,CAAI,IAAA,EAAM,EAAE,CAAA;AACtC,QAAA;AAAA,MACF;AAAA,MAEA,KAAK,KAAA;AACH,QAAA,IAAA,CAAK,iBAAA,CAAkB,IAAI,GAAG,CAAA;AAC9B,QAAA;AAAA,MAEF,KAAK,QAAA;AACH,QAAA,IAAI,CAAC,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,GAAA,CAAI,UAAU,CAAA,EAAG;AAC7C,UAAA,MAAM,MAAA,GAAyB;AAAA,YAC7B,SAAS,GAAA,CAAI,OAAA;AAAA,YACb,QAAQ,GAAA,CAAI,MAAA;AAAA,YACZ,YAAY,GAAA,CAAI,UAAA;AAAA,YAChB,UAAU,GAAA,CAAI;AAAA,WAChB;AACA,UAAA,IAAA,CAAK,eAAA,CAAgB,GAAA,CAAI,GAAA,CAAI,UAAA,EAAY,MAAM,CAAA;AAG/C,UAAA,MAAM,MAAA,GAAS,IAAA,CAAK,aAAA,CAAc,GAAA,CAAI,IAAI,UAAU,CAAA;AACpD,UAAA,IAAI,MAAA,EAAQ;AACV,YAAA,IAAA,CAAK,aAAA,CAAc,MAAA,CAAO,GAAA,CAAI,UAAU,CAAA;AACxC,YAAA,MAAA,CAAO,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,UAAA,EAAY,MAAM,CAAC,CAAA;AAAA,UAClD;AAAA,QACF;AACA,QAAA;AAAA;AAGJ,EACF;AAAA,EAEQ,iBAAA,CAAkB,IAAe,GAAA,EAAmB;AAC1D,IAAA,IAAA,CAAK,gBAAA,CAAiB,GAAA,CAAI,GAAA,CAAI,UAAA,EAAY,IAAI,IAAI,CAAA;AAClD,IAAA,IAAA,CAAK,iBAAA,CAAkB,GAAA,CAAI,GAAA,CAAI,UAAA,EAAY;AAAA,MACzC,YAAY,GAAA,CAAI,UAAA;AAAA,MAChB,UAAU,GAAA,CAAI,IAAA;AAAA,MACd,SAAS,GAAA,CAAI,OAAA;AAAA,MACb,QAAQ,GAAA,CAAI,MAAA;AAAA,MACZ,SAAA,sBAAe,IAAA,EAAK;AAAA,MACpB,QAAA,EAAU;AAAA,KACX,CAAA;AAGD,IAAA,IAAA,CAAK,QAAA,CAAS,IAAI,EAAE,IAAA,EAAM,WAAW,UAAA,EAAY,GAAA,CAAI,YAAY,CAAA;AAGjE,IAAA,cAAA,CAAe,OAAA,CAAQ;AAAA,MACrB,YAAY,GAAA,CAAI,UAAA;AAAA,MAChB,IAAA,EAAM,EAAE,WAAA,EAAa,CAAA,EAAG,IAAI,IAAI,CAAA,OAAA,CAAA,EAAW,QAAA,EAAU,GAAA,CAAI,IAAA,EAAK;AAAA,MAC9D,SAAS,GAAA,CAAI,OAAA;AAAA,MACb,QAAQ,GAAA,CAAI,MAAA;AAAA,MACZ,MAAA,EAAQ,SAAA;AAAA,MACR,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,MAClC,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AAAA,EAEQ,oBAAA,CAAqB,UAAkB,EAAA,EAAqB;AAClE,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,sBAAA,CAAuB,GAAA,CAAI,QAAQ,CAAA;AACxD,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,IAAA,CAAK,sBAAA,CAAuB,OAAO,QAAQ,CAAA;AAC3C,MAAA,IAAA,CAAK,QAAA,CAAS,IAAI,OAAO,CAAA;AACzB,MAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,kCAAA,EAAqC,QAAQ,CAAA,iBAAA,CAAmB,CAAA;AAAA,IAChF;AAAA,EACF;AAAA,EAEQ,QAAA,CAAS,IAAe,GAAA,EAAmB;AACjD,IAAA,IAAI,EAAA,CAAG,UAAA,KAAe,SAAA,CAAU,IAAA,EAAM;AACpC,MAAA,EAAA,CAAG,IAAA,CAAK,SAAA,CAAU,GAAG,CAAC,CAAA;AAAA,IACxB;AAAA,EACF;AAAA,EAEQ,eAAA,CACN,QACA,SAAA,EACY;AACZ,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,MAAM,OAAA,GAAU,WAAW,MAAM;AAC/B,QAAA,IAAA,CAAK,eAAA,CAAgB,OAAO,OAAO,CAAA;AACnC,QAAA,MAAA,CAAO,IAAI,KAAA,CAAM,mBAAmB,CAAC,CAAA;AAAA,MACvC,GAAG,SAAS,CAAA;AAEZ,MAAA,MAAM,OAAA,GAAU,CAAC,GAAA,KAAsB;AACrC,QAAA,IAAI,MAAA,CAAO,GAAG,CAAA,EAAG;AACf,UAAA,YAAA,CAAa,OAAO,CAAA;AACpB,UAAA,IAAA,CAAK,eAAA,CAAgB,OAAO,OAAO,CAAA;AACnC,UAAA,OAAA,CAAQ,GAAQ,CAAA;AAAA,QAClB;AAAA,MACF,CAAA;AAEA,MAAA,IAAA,CAAK,eAAA,CAAgB,IAAI,OAAO,CAAA;AAAA,IAClC,CAAC,CAAA;AAAA,EACH;AACF,CAAA;ACjfA,IAAM,eAAA,GAAkB,CAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,gGAAA,CAAA;AAuBxB,IAAM,SAAA,GAAY;AAAA,EAChB,IAAA,EAAM,CAAA,CACH,MAAA,EAAO,CACP,SAAS,iGAAiG,CAAA;AAAA,EAC7G,QAAA,EAAU,CAAA,CACP,MAAA,EAAO,CACP,QAAA;AAAA,IACC;AAAA;AAEN,CAAA;AAEO,SAAS,eAAA,CAAgB,QAAmB,MAAA,EAA6B;AAC9E,EAAA,MAAA,CAAO,IAAA,CAAK,KAAA,EAAO,eAAA,EAAiB,SAAA,EAAW,OAAO,IAAA,KAAS;AAC7D,IAAA,MAAM,aAAa,IAAA,CAAK,IAAA;AACxB,IAAA,MAAM,WAAW,IAAA,CAAK,QAAA;AAEtB,IAAA,IAAI;AACF,MAAA,IAAI,CAAC,OAAO,aAAA,EAAe;AACzB,QAAA,OAAO;AAAA,UACL,SAAS,CAAC;AAAA,YACR,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM;AAAA,WACP,CAAA;AAAA,UACD,OAAA,EAAS;AAAA,SACX;AAAA,MACF;AAEA,MAAA,MAAM,aAAa,MAAM,MAAA,CAAO,GAAA,CAAI,UAAA,EAAY,UAAU,UAAU,CAAA;AAGpE,MAAA,MAAM,SAAS,MAAM,MAAA,CAAO,cAAc,UAAA,EAAY,CAAA,GAAI,KAAK,GAAI,CAAA;AAEnE,MAAA,IAAI,WAAW,IAAA,EAAM;AACnB,QAAA,OAAO;AAAA,UACL,SAAS,CAAC;AAAA,YACR,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM,CAAA,EAAA,EAAK,MAAA,CAAO,IAAA,CAAK,WAAW,CAAA;;AAAA,EAAmB,OAAO,OAAO,CAAA;AAAA,WACpE;AAAA,SACH;AAAA,MACF;AAEA,MAAA,OAAO;AAAA,QACL,SAAS,CAAC;AAAA,UACR,IAAA,EAAM,MAAA;AAAA,UACN,IAAA,EAAM;AAAA,YACJ,qBAAqB,UAAU,CAAA,yCAAA,CAAA;AAAA,YAC/B,kBAAkB,UAAU,CAAA,EAAA,CAAA;AAAA,YAC5B,CAAA,CAAA;AAAA,YACA,CAAA,yCAAA,CAAA;AAAA,YACA,CAAA,mDAAA,CAAA;AAAA,YACA,CAAA,6CAAA;AAAA,WACF,CAAE,KAAK,IAAI;AAAA,SACZ;AAAA,OACH;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,YAAA,GAAe,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,eAAA;AAC9D,MAAA,MAAM,aAAA,GAAgB,YAAA,CAAa,QAAA,CAAS,eAAe,CAAA;AAC3D,MAAA,OAAO;AAAA,QACL,SAAS,CAAC;AAAA,UACR,IAAA,EAAM,MAAA;AAAA,UACN,MAAM,aAAA,GACF,CAAA,MAAA,EAAS,UAAU,CAAA,gEAAA,CAAA,GACnB,4BAA4B,YAAY,CAAA;AAAA,SAC7C,CAAA;AAAA,QACD,OAAA,EAAS;AAAA,OACX;AAAA,IACF;AAAA,EACF,CAAC,CAAA;AACH;AC1FA,IAAM,iBAAA,GAAoB,CAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,uFAAA,CAAA;AAuB1B,IAAM,WAAA,GAAc;AAAA,EAClB,UAAA,EAAYC,CAAAA,CACT,MAAA,EAAO,CACP,QAAA;AAAA,IACC;AAAA,GACF;AAAA,EACF,MAAA,EAAQA,CAAAA,CACL,MAAA,EAAO,CACP,QAAA;AAAA,IACC;AAAA;AAEN,CAAA;AAEO,SAAS,iBAAA,CAAkB,QAAmB,MAAA,EAA6B;AAChF,EAAA,MAAA,CAAO,IAAA,CAAK,OAAA,EAAS,iBAAA,EAAmB,WAAA,EAAa,OAAO,IAAA,KAAS;AACnE,IAAA,MAAM,aAAa,IAAA,CAAK,UAAA;AACxB,IAAA,MAAM,SAAS,IAAA,CAAK,MAAA;AAEpB,IAAA,IAAI;AACF,MAAA,IAAI,CAAC,OAAO,aAAA,EAAe;AACzB,QAAA,OAAO;AAAA,UACL,SAAS,CAAC;AAAA,YACR,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM;AAAA,WACP,CAAA;AAAA,UACD,OAAA,EAAS;AAAA,SACX;AAAA,MACF;AAEA,MAAA,MAAM,MAAA,CAAO,KAAA,CAAM,UAAA,EAAY,MAAA,EAAQ,UAAU,CAAA;AAEjD,MAAA,cAAA,CAAe,aAAA,EAAc;AAE7B,MAAA,OAAO;AAAA,QACL,SAAS,CAAC;AAAA,UACR,IAAA,EAAM,MAAA;AAAA,UACN,IAAA,EAAM,CAAA,sFAAA;AAAA,SACP;AAAA,OACH;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,YAAA,GAAe,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,eAAA;AAC9D,MAAA,MAAM,UAAA,GAAa,YAAA,CAAa,QAAA,CAAS,WAAW,CAAA;AACpD,MAAA,OAAO;AAAA,QACL,SAAS,CAAC;AAAA,UACR,IAAA,EAAM,MAAA;AAAA,UACN,MAAM,UAAA,GACF,CAAA,WAAA,EAAc,UAAU,CAAA,oFAAA,CAAA,GACxB,yBAAyB,YAAY,CAAA;AAAA,SAC1C,CAAA;AAAA,QACD,OAAA,EAAS;AAAA,OACX;AAAA,IACF;AAAA,EACF,CAAC,CAAA;AACH;;;AC9EA,IAAM,iBAAA,GAAoB,CAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA,mEAAA,CAAA;AAkBnB,SAAS,iBAAA,CAAkB,QAAmB,MAAA,EAA6B;AAChF,EAAA,MAAA,CAAO,IAAA,CAAK,OAAA,EAAS,iBAAA,EAAmB,IAAI,YAAY;AACtD,IAAA,MAAM,IAAA,GAAO,OAAO,OAAA,EAAQ;AAC5B,IAAA,MAAM,MAAA,GAAS,KAAK,QAAA,IAAY,eAAA;AAChC,IAAA,MAAM,MAAA,GAAS,KAAK,IAAA,IAAQ,GAAA;AAC5B,IAAA,MAAM,YAAY,IAAA,CAAK,cAAA;AAEvB,IAAA,IAAI,CAAC,OAAO,WAAA,EAAa;AACvB,MAAA,OAAO;AAAA,QACL,SAAS,CAAC;AAAA,UACR,IAAA,EAAM,MAAA;AAAA,UACN,IAAA,EAAM;AAAA,YACJ,uCAAuC,MAAM,CAAA,gBAAA,CAAA;AAAA,YAC7C,CAAA,iDAAA;AAAA,WACF,CAAE,KAAK,IAAI;AAAA,SACZ,CAAA;AAAA,QACD,OAAA,EAAS;AAAA,OACX;AAAA,IACF;AAEA,IAAA,IAAI,SAAA,CAAU,WAAW,CAAA,EAAG;AAC1B,MAAA,OAAO;AAAA,QACL,SAAS,CAAC;AAAA,UACR,IAAA,EAAM,MAAA;AAAA,UACN,IAAA,EAAM;AAAA,YACJ,CAAA,SAAA,EAAY,MAAM,CAAA,qBAAA,EAAwB,MAAM,CAAA,EAAA,CAAA;AAAA,YAChD,CAAA,uBAAA,CAAA;AAAA,YACA,CAAA,CAAA;AAAA,YACA,CAAA,qFAAA,CAAA;AAAA,YACA,CAAA,iEAAA;AAAA,WACF,CAAE,KAAK,IAAI;AAAA,SACZ;AAAA,OACH;AAAA,IACF;AAEA,IAAA,MAAM,IAAA,GAAO,SAAA,CAAU,GAAA,CAAI,CAAC,IAAA,KAAS,YAAO,IAAI,CAAA,CAAE,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA;AAC7D,IAAA,OAAO;AAAA,MACL,SAAS,CAAC;AAAA,QACR,IAAA,EAAM,MAAA;AAAA,QACN,MAAM,CAAA,SAAA,EAAY,MAAM,WAAW,MAAM,CAAA,oBAAA,EAAuB,UAAU,MAAM,CAAA;AAAA,EAAO,IAAI,CAAA;AAAA,OAC5F;AAAA,KACH;AAAA,EACF,CAAC,CAAA;AACH;;;AC7DA,IAAM,mBAAA,GAAsB,CAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA,oEAAA,CAAA;AAcrB,SAAS,mBAAA,CAAoB,QAAmB,MAAA,EAA6B;AAClF,EAAA,MAAA,CAAO,IAAA,CAAK,SAAA,EAAW,mBAAA,EAAqB,IAAI,YAAY;AAC1D,IAAA,MAAM,OAAA,GAAU,OAAO,UAAA,EAAW;AAElC,IAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AACxB,MAAA,OAAO;AAAA,QACL,SAAS,CAAC,EAAE,MAAM,MAAA,EAAQ,IAAA,EAAM,4CAA4C;AAAA,OAC9E;AAAA,IACF;AAEA,IAAA,MAAM,aAAa,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA,KAAM,CAAC,EAAE,MAAM,CAAA;AAElD,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM;AAC/B,MAAA,MAAM,OAAO,IAAI,IAAA,CAAK,CAAA,CAAE,OAAO,EAAE,kBAAA,EAAmB;AAEpD,MAAA,IAAI,CAAA,CAAE,cAAc,MAAA,EAAQ;AAC1B,QAAA,MAAM,UAAA,GAAa,EAAE,MAAA,GACjB,CAAA,SAAA,EAAO,EAAE,IAAI,CAAA,EAAA,EAAK,CAAA,CAAE,MAAM,CAAA,CAAA,GAC1B,CAAA,wBAAA,CAAA;AACJ,QAAA,OAAO,IAAI,IAAI,CAAA,SAAA,EAAO,EAAE,IAAI,CAAA,EAAA,EAAK,EAAE,QAAQ;AAAA,EAAK,UAAU,CAAA,CAAA;AAAA,MAC5D,CAAA,MAAO;AACL,QAAA,MAAM,aAAa,CAAA,CAAE,MAAA,GACjB,CAAA,cAAA,EAAY,CAAA,CAAE,MAAM,CAAA,CAAA,GACpB,CAAA,qEAAA,CAAA;AACJ,QAAA,OAAO,IAAI,IAAI,CAAA,SAAA,EAAO,EAAE,IAAI,CAAA,EAAA,EAAK,EAAE,QAAQ;AAAA,EAAK,UAAU,CAAA,CAAA;AAAA,MAC5D;AAAA,IACF,CAAC,CAAA;AAED,IAAA,MAAM,OAAA,GAAU,UAAA,CAAW,MAAA,GAAS,CAAA,GAChC;;AAAA,OAAA,EAAS,UAAA,CAAW,MAAM,CAAA,0CAAA,CAAA,GAC1B,EAAA;AAEJ,IAAA,OAAO;AAAA,MACL,OAAA,EAAS,CAAC,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,KAAA,CAAM,IAAA,CAAK,MAAM,CAAA,GAAI,OAAA,EAAS;AAAA,KAChE;AAAA,EACF,CAAC,CAAA;AACH;AC1CA,SAAS,iBAAiB,QAAA,EAAmC;AAC3D,EAAA,MAAM,OAAA,GAAU,QAAA,CAAS,GAAA,CAAI,CAAC,CAAA,KAAM,IAAI,CAAC,CAAA,CAAA,CAAG,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA;AACtD,EAAA,MAAM,SAAA,GAAY,mDAAmD,OAAO,CAAA,mBAAA,CAAA;AAE5E,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,IAAA,MAAM,KAAK,KAAA,CAAM,YAAA,EAAc,CAAC,YAAA,EAAc,UAAA,EAAY,SAAS,CAAC,CAAA;AAEpE,IAAA,EAAA,CAAG,EAAA,CAAG,OAAA,EAAS,CAAC,IAAA,KAAS;AACvB,MAAA,IAAI,IAAA,KAAS,GAAG,OAAA,EAAQ;AAAA,kBACZ,IAAI,KAAA,CAAM,CAAA,uDAAA,EAA0D,IAAI,IAAI,CAAC,CAAA;AAAA,IAC3F,CAAC,CAAA;AAED,IAAA,EAAA,CAAG,EAAA,CAAG,OAAA,EAAS,CAAC,GAAA,KAAQ;AACtB,MAAA,MAAA,CAAO,IAAI,KAAA,CAAM,CAAA,6BAAA,EAAgC,GAAA,CAAI,OAAO,EAAE,CAAC,CAAA;AAAA,IACjE,CAAC,CAAA;AAAA,EACH,CAAC,CAAA;AACH;AAEA,eAAe,SAAS,QAAA,EAAmC;AACzD,EAAA,MAAM,iBAAiB,QAAQ,CAAA;AACjC;AAEA,eAAsB,gBAAgB,IAAA,EAA6B;AAEjE,EAAA,MAAM,QAAA,CAAS;AAAA,IACb,aAAA;AAAA,IAAe,UAAA;AAAA,IAAY,KAAA;AAAA,IAAO,MAAA;AAAA,IAClC,sBAAsB,IAAI,CAAA,CAAA;AAAA,IAC1B,cAAA;AAAA,IACA,QAAA;AAAA,IACA,aAAa,IAAI,CAAA,CAAA;AAAA,IACjB;AAAA,GACD,CAAA;AAGD,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,CAAS;AAAA,MACb,aAAA;AAAA,MAAe,UAAA;AAAA,MAAY,KAAA;AAAA,MAAO,MAAA;AAAA,MAClC,8BAAA;AAAA,MACA,cAAA;AAAA,MACA,QAAA;AAAA,MACA,iBAAA;AAAA,MACA;AAAA,KACD,CAAA;AAAA,EACH,CAAA,CAAA,MAAQ;AAAA,EAA0D;AACpE;AAEA,eAAsB,mBAAmB,IAAA,EAA6B;AACpE,EAAA,MAAM,QAAA,CAAS;AAAA,IACb,aAAA;AAAA,IAAe,UAAA;AAAA,IAAY,QAAA;AAAA,IAAU,MAAA;AAAA,IACrC,sBAAsB,IAAI,CAAA;AAAA,GAC3B,CAAA;AAGD,EAAA,IAAI;AACF,IAAA,MAAM,SAAS,CAAC,aAAA,EAAe,YAAY,QAAA,EAAU,MAAA,EAAQ,8BAA8B,CAAC,CAAA;AAAA,EAC9F,CAAA,CAAA,MAAQ;AAAA,EAAsB;AAChC;;;AC9DA,IAAM,yBAAA,GAA4B,CAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA,6DAAA,CAAA;AAoB3B,SAAS,wBAAA,CAAyB,QAAmB,MAAA,EAA6B;AACvF,EAAA,MAAA,CAAO,IAAA;AAAA,IACL,eAAA;AAAA,IACA,yBAAA;AAAA,IACA;AAAA,MACE,IAAA,EAAMA,CAAAA,CACH,MAAA,EAAO,CACP,GAAA,CAAI,IAAI,CAAA,CACR,GAAA,CAAI,KAAK,CAAA,CACT,QAAA,EAAS,CACT,QAAA;AAAA,QACC;AAAA;AACF,KACJ;AAAA,IACA,OAAO,EAAE,IAAA,EAAK,KAAM;AAClB,MAAA,MAAM,UAAA,GAAa,IAAA,IAAQ,MAAA,CAAO,OAAA,EAAQ,CAAE,IAAA;AAC5C,MAAA,IAAI,CAAC,UAAA,EAAY;AACf,QAAA,OAAO;AAAA,UACL,SAAS,CAAC,EAAE,MAAM,MAAA,EAAQ,IAAA,EAAM,2EAAsE,CAAA;AAAA,UACtG,OAAA,EAAS;AAAA,SACX;AAAA,MACF;AAEA,MAAA,IAAI;AACF,QAAA,MAAM,gBAAgB,UAAU,CAAA;AAChC,QAAA,OAAO;AAAA,UACL,SAAS,CAAC;AAAA,YACR,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM;AAAA,cACJ,CAAA,8BAAA,EAAiC,UAAU,CAAA,gBAAA,EAAmB,UAAU,CAAA,EAAA,CAAA;AAAA,cACxE,CAAA,gDAAA,CAAA;AAAA,cACA,CAAA,0DAAA;AAAA,aACF,CAAE,KAAK,IAAI;AAAA,WACZ;AAAA,SACH;AAAA,MACF,SAAS,GAAA,EAAK;AACZ,QAAA,MAAM,MAAM,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG,CAAA;AAC3D,QAAA,OAAO;AAAA,UACL,SAAS,CAAC;AAAA,YACR,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM;AAAA,cACJ,4BAA4B,GAAG,CAAA,CAAA;AAAA,cAC/B,CAAA,CAAA;AAAA,cACA,CAAA,0EAAA;AAAA,aACF,CAAE,KAAK,IAAI;AAAA,WACZ,CAAA;AAAA,UACD,OAAA,EAAS;AAAA,SACX;AAAA,MACF;AAAA,IACF;AAAA,GACF;AACF;ACvEA,IAAM,0BAAA,GAA6B,CAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA,+EAAA,CAAA;AAiB5B,SAAS,yBAAA,CAA0B,QAAmB,MAAA,EAA6B;AACxF,EAAA,MAAA,CAAO,IAAA;AAAA,IACL,gBAAA;AAAA,IACA,0BAAA;AAAA,IACA;AAAA,MACE,IAAA,EAAMA,CAAAA,CACH,MAAA,EAAO,CACP,GAAA,CAAI,IAAI,CAAA,CACR,GAAA,CAAI,KAAK,CAAA,CACT,QAAA,EAAS,CACT,QAAA;AAAA,QACC;AAAA;AACF,KACJ;AAAA,IACA,OAAO,EAAE,IAAA,EAAK,KAAM;AAClB,MAAA,MAAM,UAAA,GAAa,IAAA,IAAQ,MAAA,CAAO,OAAA,EAAQ,CAAE,IAAA;AAC5C,MAAA,IAAI,CAAC,UAAA,EAAY;AACf,QAAA,OAAO;AAAA,UACL,SAAS,CAAC,EAAE,MAAM,MAAA,EAAQ,IAAA,EAAM,2EAAsE,CAAA;AAAA,UACtG,OAAA,EAAS;AAAA,SACX;AAAA,MACF;AAEA,MAAA,IAAI;AACF,QAAA,MAAM,mBAAmB,UAAU,CAAA;AACnC,QAAA,OAAO;AAAA,UACL,SAAS,CAAC;AAAA,YACR,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM,CAAA,+BAAA,EAAkC,UAAU,CAAA,gBAAA,EAAmB,UAAU,CAAA,EAAA;AAAA,WAChF;AAAA,SACH;AAAA,MACF,SAAS,GAAA,EAAK;AACZ,QAAA,MAAM,MAAM,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG,CAAA;AAC3D,QAAA,OAAO;AAAA,UACL,SAAS,CAAC;AAAA,YACR,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM;AAAA,cACJ,mCAAmC,GAAG,CAAA,CAAA;AAAA,cACtC,CAAA,CAAA;AAAA,cACA,CAAA,yGAAA;AAAA,aACF,CAAE,KAAK,IAAI;AAAA,WACZ,CAAA;AAAA,UACD,OAAA,EAAS;AAAA,SACX;AAAA,MACF;AAAA,IACF;AAAA,GACF;AACF;AC9DA,IAAM,qBAAA,GAAwB,CAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA,iFAAA,CAAA;AAsBvB,SAAS,oBAAA,CAAqB,QAAmB,MAAA,EAA6B;AACnF,EAAA,MAAA,CAAO,IAAA;AAAA,IACL,WAAA;AAAA,IACA,qBAAA;AAAA,IACA;AAAA,MACE,YAAA,EAAcA,CAAAA,CACX,MAAA,EAAO,CACP,GAAA,CAAI,EAAE,CAAA,CACN,GAAA,CAAI,GAAG,CAAA,CACP,QAAA,EAAS,CACT,SAAS,qDAAqD;AAAA,KACnE;AAAA,IACA,OAAO,EAAE,YAAA,GAAe,EAAA,EAAG,KAAM;AAC/B,MAAA,MAAM,IAAA,GAAO,MAAA,CAAO,OAAA,EAAQ,CAAE,IAAA;AAC9B,MAAA,IAAI,CAAC,IAAA,EAAM;AACT,QAAA,OAAO;AAAA,UACL,SAAS,CAAC,EAAE,MAAM,MAAA,EAAQ,IAAA,EAAM,uDAAuD,CAAA;AAAA,UACvF,OAAA,EAAS;AAAA,SACX;AAAA,MACF;AAGA,MAAA,IAAI;AACF,QAAA,MAAM,gBAAgB,IAAI,CAAA;AAAA,MAC5B,SAAS,GAAA,EAAK;AACZ,QAAA,MAAM,MAAM,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG,CAAA;AAC3D,QAAA,OAAO;AAAA,UACL,OAAA,EAAS,CAAC,EAAE,IAAA,EAAM,QAAQ,IAAA,EAAM,CAAA,yBAAA,EAA4B,GAAG,CAAA,CAAA,EAAI,CAAA;AAAA,UACnE,OAAA,EAAS;AAAA,SACX;AAAA,MACF;AAEA,MAAA,MAAM,eAAe,IAAI,GAAA,CAAI,MAAA,CAAO,OAAA,GAAU,cAAc,CAAA;AAG5D,MAAA,MAAM,IAAI,QAAc,CAAC,OAAA,KAAY,WAAW,OAAA,EAAS,YAAA,GAAe,GAAI,CAAC,CAAA;AAG7E,MAAA,IAAI;AACF,QAAA,MAAM,mBAAmB,IAAI,CAAA;AAAA,MAC/B,CAAA,CAAA,MAAQ;AAAA,MAAuE;AAG/E,MAAA,MAAM,QAAA,GAAW,MAAA,CAAO,OAAA,EAAQ,CAAE,cAAA;AAClC,MAAA,MAAM,QAAA,GAAW,SAAS,MAAA,CAAO,CAAC,MAAM,CAAC,YAAA,CAAa,GAAA,CAAI,CAAC,CAAC,CAAA;AAE5D,MAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AACzB,QAAA,OAAO;AAAA,UACL,SAAS,CAAC;AAAA,YACR,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM;AAAA,cACJ,wBAAwB,YAAY,CAAA,EAAA,CAAA;AAAA,cACpC,CAAA,CAAA;AAAA,cACA,CAAA,kEAAA,CAAA;AAAA,cACA,CAAA,0CAAA;AAAA,aACF,CAAE,KAAK,IAAI;AAAA,WACZ;AAAA,SACH;AAAA,MACF;AAEA,MAAA,MAAM,KAAA,GAAQ;AAAA,QACZ,CAAA,kCAAA,EAAqC,SAAS,MAAM,CAAA,EAAA,CAAA;AAAA,QACpD,GAAG,QAAA,CAAS,GAAA,CAAI,CAAC,MAAM,CAAA,SAAA,EAAO,CAAC,CAAA,EAAG,QAAA,CAAS,QAAA,CAAS,CAAC,CAAA,GAAI,QAAA,GAAW,EAAE,CAAA,CAAE,CAAA;AAAA,QACxE,CAAA,CAAA;AAAA,QACA,CAAA,8DAAA,CAAA;AAAA,QACA,CAAA,kFAAA;AAAA,OACF;AAEA,MAAA,OAAO;AAAA,QACL,OAAA,EAAS,CAAC,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAM,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA,EAAG;AAAA,OACpD;AAAA,IACF;AAAA,GACF;AACF;;;ACtFO,SAAS,gBAAgB,OAAA,EAAsC;AACpE,EAAA,MAAM,EAAE,QAAO,GAAI,OAAA;AAEnB,EAAA,MAAM,MAAA,GAAS,IAAI,SAAA,CAAU;AAAA,IAC3B,IAAA,EAAM,eAAA;AAAA,IACN,OAAA,EAAS;AAAA,GACV,CAAA;AAED,EAAA,eAAA,CAAgB,QAAQ,MAAM,CAAA;AAC9B,EAAA,iBAAA,CAAkB,QAAQ,MAAM,CAAA;AAChC,EAAA,iBAAA,CAAkB,QAAQ,MAAM,CAAA;AAChC,EAAA,mBAAA,CAAoB,QAAQ,MAAM,CAAA;AAClC,EAAA,wBAAA,CAAyB,QAAQ,MAAM,CAAA;AACvC,EAAA,yBAAA,CAA0B,QAAQ,MAAM,CAAA;AACxC,EAAA,oBAAA,CAAqB,QAAQ,MAAM,CAAA;AAEnC,EAAA,OAAO,MAAA;AACT;AAEA,eAAsB,eAAe,OAAA,EAA0C;AAC7E,EAAA,MAAM,MAAA,GAAS,gBAAgB,OAAO,CAAA;AACtC,EAAA,MAAM,SAAA,GAAY,IAAI,oBAAA,EAAqB;AAC3C,EAAA,MAAM,MAAA,CAAO,QAAQ,SAAS,CAAA;AAChC;;;AC1BA,IAAM,OAAA,GAAU,IAAI,OAAA,EAAQ;AAE5B,OAAA,CACG,IAAA,CAAK,eAAe,CAAA,CACpB,WAAA,CAAY,yDAAyD,CAAA,CACrE,OAAA,CAAQ,OAAO,CAAA,CACf,eAAe,eAAA,EAAiB,yCAAyC,CAAA,CACzE,MAAA,CAAO,OAAO,OAAA,KAA8B;AAC3C,EAAA,MAAM,IAAA,GAAO,IAAI,OAAA,EAAQ;AAEzB,EAAA,MAAM,QAAA,GAAW,cAAA,CAAe,EAAE,MAAA,EAAQ,MAAM,CAAA;AAEhD,EAAA,IAAA,CAAK,IAAA,CAAK,QAAQ,IAAA,EAAM,OAAA,CAAQ,IAAI,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AACnD,IAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,kCAAA,EAAqC,GAAA,CAAI,OAAO,CAAA,CAAE,CAAA;AAAA,EAClE,CAAC,CAAA;AAED,EAAA,MAAM,QAAA;AACR,CAAC,CAAA;AAEH,OAAA,CAAQ,KAAA,EAAM","file":"cli.js","sourcesContent":["/**\r\n * P2P Wire Protocol\r\n * Messages exchanged directly between peers (no hub).\r\n * @module infrastructure/p2p/p2p-protocol\r\n */\r\n\r\nimport type { MessageFormat } from '../../domain/value-objects/message-content.vo.js';\r\n\r\n// Sent when a peer connects (client → server, or outbound → inbound)\r\nexport interface HelloMsg {\r\n type: 'HELLO';\r\n name: string;\r\n}\r\n\r\n// Acknowledge the HELLO\r\nexport interface HelloAckMsg {\r\n type: 'HELLO_ACK';\r\n name: string;\r\n}\r\n\r\n// Ask a question directly to the connected peer\r\nexport interface AskMsg {\r\n type: 'ASK';\r\n from: string;\r\n questionId: string;\r\n content: string;\r\n format: MessageFormat;\r\n}\r\n\r\n// Confirm question was received\r\nexport interface AskAckMsg {\r\n type: 'ASK_ACK';\r\n questionId: string;\r\n}\r\n\r\n// Push answer back to the asker\r\nexport interface AnswerMsg {\r\n type: 'ANSWER';\r\n from: string;\r\n questionId: string;\r\n content: string;\r\n format: MessageFormat;\r\n answeredAt: string;\r\n}\r\n\r\nexport type P2PMsg = HelloMsg | HelloAckMsg | AskMsg | AskAckMsg | AnswerMsg;\r\n\r\nexport function serialize(msg: P2PMsg): string {\r\n return JSON.stringify(msg);\r\n}\r\n\r\nexport function parse(data: string): P2PMsg {\r\n return JSON.parse(data) as P2PMsg;\r\n}\r\n","/**\r\n * MulticastDiscovery\r\n * Discovers peers on the local network using UDP multicast.\r\n * Nodes announce themselves periodically; peers discover each other automatically.\r\n * @module infrastructure/discovery/multicast-discovery\r\n */\r\n\r\nimport dgram from 'dgram';\r\nimport os from 'os';\r\nimport { EventEmitter } from 'events';\r\n\r\nexport const MULTICAST_ADDR = '239.255.42.42';\r\nexport const MULTICAST_PORT = 11776;\r\nconst HEARTBEAT_INTERVAL_MS = 5_000;\r\nconst PEER_TIMEOUT_MS = 20_000; // ~4x heartbeat\r\n\r\ninterface AnnounceMsg {\r\n type: 'ANNOUNCE';\r\n name: string;\r\n wsPort: number;\r\n unicast?: true; // present only on direct unicast replies — prevents reply loops\r\n}\r\n\r\ninterface LeaveMsg {\r\n type: 'LEAVE';\r\n name: string;\r\n}\r\n\r\ntype DiscoveryMsg = AnnounceMsg | LeaveMsg;\r\n\r\nexport interface DiscoveredPeer {\r\n name: string;\r\n ip: string;\r\n wsPort: number;\r\n}\r\n\r\nexport class MulticastDiscovery extends EventEmitter {\r\n private socket: dgram.Socket | null = null;\r\n private heartbeatTimer: NodeJS.Timeout | null = null;\r\n private timeoutTimer: NodeJS.Timeout | null = null;\r\n\r\n private readonly peers = new Map<string, DiscoveredPeer & { lastSeen: number }>();\r\n private myName = '';\r\n private myWsPort = 0;\r\n\r\n start(name: string, wsPort: number): void {\r\n this.myName = name;\r\n this.myWsPort = wsPort;\r\n\r\n const socket = dgram.createSocket({ type: 'udp4', reuseAddr: true });\r\n this.socket = socket;\r\n\r\n socket.on('error', (err) => {\r\n console.error('[multicast] socket error:', err.message);\r\n });\r\n\r\n socket.on('message', (buf, rinfo) => {\r\n try {\r\n const msg = JSON.parse(buf.toString()) as DiscoveryMsg;\r\n this.handleMessage(msg, rinfo.address);\r\n } catch {\r\n // ignore malformed messages\r\n }\r\n });\r\n\r\n socket.bind(MULTICAST_PORT, () => {\r\n try {\r\n socket.addMembership(MULTICAST_ADDR);\r\n socket.setMulticastTTL(1); // LAN only — don't cross routers\r\n socket.setMulticastLoopback(false); // don't receive own messages\r\n } catch (err) {\r\n console.error('[multicast] membership error:', err);\r\n }\r\n\r\n this.announce();\r\n this.heartbeatTimer = setInterval(() => this.announce(), HEARTBEAT_INTERVAL_MS);\r\n this.timeoutTimer = setInterval(() => this.checkTimeouts(), 5_000);\r\n });\r\n }\r\n\r\n stop(): void {\r\n if (this.heartbeatTimer) { clearInterval(this.heartbeatTimer); this.heartbeatTimer = null; }\r\n if (this.timeoutTimer) { clearInterval(this.timeoutTimer); this.timeoutTimer = null; }\r\n if (this.socket) {\r\n this.sendMessage({ type: 'LEAVE', name: this.myName });\r\n try {\r\n this.socket.dropMembership(MULTICAST_ADDR);\r\n this.socket.close();\r\n } catch { /* ignore */ }\r\n this.socket = null;\r\n }\r\n this.peers.clear();\r\n }\r\n\r\n resolveLocalIp(): string {\r\n const interfaces = os.networkInterfaces();\r\n for (const iface of Object.values(interfaces)) {\r\n if (!iface) continue;\r\n for (const addr of iface) {\r\n if (addr.family === 'IPv4' && !addr.internal) return addr.address;\r\n }\r\n }\r\n return '127.0.0.1';\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private\r\n // ---------------------------------------------------------------------------\r\n\r\n private announce(): void {\r\n this.sendMessage({ type: 'ANNOUNCE', name: this.myName, wsPort: this.myWsPort });\r\n }\r\n\r\n private sendMessage(msg: DiscoveryMsg): void {\r\n if (!this.socket) return;\r\n const buf = Buffer.from(JSON.stringify(msg));\r\n this.socket.send(buf, MULTICAST_PORT, MULTICAST_ADDR, (err) => {\r\n if (err) console.error('[multicast] send error:', err.message);\r\n });\r\n }\r\n\r\n private sendUnicast(toIp: string): void {\r\n if (!this.socket) return;\r\n const buf = Buffer.from(JSON.stringify({ type: 'ANNOUNCE', name: this.myName, wsPort: this.myWsPort, unicast: true }));\r\n this.socket.send(buf, MULTICAST_PORT, toIp, (err) => {\r\n if (err) console.error(`[multicast] unicast reply to ${toIp} error:`, err.message);\r\n });\r\n }\r\n\r\n private handleMessage(msg: DiscoveryMsg, fromIp: string): void {\r\n if (msg.type === 'ANNOUNCE') {\r\n if (msg.name === this.myName) return;\r\n\r\n const existing = this.peers.get(msg.name);\r\n if (!existing) {\r\n const peer = { name: msg.name, ip: fromIp, wsPort: msg.wsPort, lastSeen: Date.now() };\r\n this.peers.set(msg.name, peer);\r\n console.error(`[multicast] discovered peer: ${msg.name} @ ${fromIp}:${msg.wsPort}`);\r\n } else {\r\n existing.lastSeen = Date.now();\r\n existing.ip = fromIp;\r\n existing.wsPort = msg.wsPort;\r\n }\r\n\r\n // Send unicast reply on every multicast ANNOUNCE (not on unicast replies)\r\n // so the sender can discover us even when multicast is one-way.\r\n // Loop-safe: unicast replies carry unicast:true so we don't reply back.\r\n if (!msg.unicast) {\r\n this.sendUnicast(fromIp);\r\n }\r\n\r\n // Emit on every ANNOUNCE so p2p-node retries failed connection attempts.\r\n // Guards in p2p-node (peerConnections.has / connectingPeers.has) prevent duplicates.\r\n this.emit('peer-found', { name: msg.name, ip: fromIp, wsPort: msg.wsPort });\r\n } else if (msg.type === 'LEAVE') {\r\n if (this.peers.has(msg.name)) {\r\n this.peers.delete(msg.name);\r\n this.emit('peer-lost', msg.name);\r\n console.error(`[multicast] peer left: ${msg.name}`);\r\n }\r\n }\r\n }\r\n\r\n private checkTimeouts(): void {\r\n const now = Date.now();\r\n for (const [name, peer] of this.peers) {\r\n if (now - peer.lastSeen > PEER_TIMEOUT_MS) {\r\n this.peers.delete(name);\r\n this.emit('peer-lost', name);\r\n console.error(`[multicast] peer timed out: ${name}`);\r\n }\r\n }\r\n }\r\n}\r\n","/**\r\n * Windows Terminal Injector\r\n * AttachConsole(ppid) → CreateFile(\"CONIN$\") → WriteConsoleInput\r\n * All keystrokes (text, Ctrl+U, Enter, Ctrl+Y) go through WriteConsoleInput.\r\n * No WScript.Shell / SendKeys / SetForegroundWindow — no focus dependency.\r\n * @module infrastructure/terminal-injector/windows-injector\r\n */\r\n\r\nimport { execFile } from 'child_process';\r\nimport { unlinkSync } from 'fs';\r\nimport { tmpdir } from 'os';\r\nimport { join } from 'path';\r\n\r\nconst CS_CONINJECT = `\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Runtime.InteropServices;\r\n\r\npublic class ConInject {\r\n [DllImport(\"kernel32.dll\")] public static extern bool FreeConsole();\r\n [DllImport(\"kernel32.dll\")] public static extern bool AttachConsole(uint pid);\r\n [DllImport(\"kernel32.dll\", CharSet=CharSet.Unicode, SetLastError=true)]\r\n public static extern IntPtr CreateFile(\r\n string lpFileName, uint dwDesiredAccess, uint dwShareMode,\r\n IntPtr lpSecurityAttributes, uint dwCreationDisposition,\r\n uint dwFlagsAndAttributes, IntPtr hTemplateFile);\r\n [DllImport(\"kernel32.dll\")] public static extern bool WriteConsoleInput(\r\n IntPtr hIn, INPUT_RECORD[] buf, uint len, out uint written);\r\n [DllImport(\"kernel32.dll\")] public static extern bool CloseHandle(IntPtr h);\r\n\r\n [StructLayout(LayoutKind.Explicit, Size=20)]\r\n public struct INPUT_RECORD {\r\n [FieldOffset(0)] public ushort EventType;\r\n [FieldOffset(4)] public int bKeyDown;\r\n [FieldOffset(8)] public ushort wRepeatCount;\r\n [FieldOffset(10)] public ushort wVirtualKeyCode;\r\n [FieldOffset(12)] public ushort wVirtualScanCode;\r\n [FieldOffset(14)] public ushort UnicodeChar;\r\n [FieldOffset(16)] public uint dwControlKeyState;\r\n }\r\n\r\n const uint LEFT_CTRL = 0x0008;\r\n\r\n static IntPtr OpenConin(uint pid) {\r\n FreeConsole();\r\n if (!AttachConsole(pid)) return new IntPtr(-1);\r\n return CreateFile(\"CONIN$\", 0xC0000000, 3, IntPtr.Zero, 3, 0, IntPtr.Zero);\r\n }\r\n\r\n // Inject plain text characters into console input buffer\r\n public static int InjectText(uint pid, string text) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new List<INPUT_RECORD>();\r\n foreach (char c in text) {\r\n records.Add(new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, UnicodeChar=(ushort)c });\r\n records.Add(new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, UnicodeChar=(ushort)c });\r\n }\r\n\r\n var arr = records.ToArray();\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, arr, (uint)arr.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n\r\n // Inject Enter (VK_RETURN = 0x0D)\r\n public static int InjectEnter(uint pid) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new INPUT_RECORD[] {\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0x0D, UnicodeChar=0x0D },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0x0D, UnicodeChar=0x0D }\r\n };\r\n\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, records, (uint)records.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n\r\n // Inject Ctrl+U (VK_U = 0x55, char = 0x15)\r\n public static int InjectCtrlU(uint pid) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new INPUT_RECORD[] {\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0x55, UnicodeChar=0x15, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0x55, UnicodeChar=0x15, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=0 }\r\n };\r\n\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, records, (uint)records.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n\r\n // Inject Ctrl+Y (VK_Y = 0x59, char = 0x19)\r\n public static int InjectCtrlY(uint pid) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new INPUT_RECORD[] {\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0x59, UnicodeChar=0x19, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0x59, UnicodeChar=0x19, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=0 }\r\n };\r\n\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, records, (uint)records.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n}\r\n`;\r\n\r\nfunction buildScript(claudePid: number, body: string): string {\r\n const logFile = join(tmpdir(), `cc-inject-${Date.now()}.log`).replace(/\\\\/g, '/');\r\n return `\r\n$log = \"${logFile}\"\r\nfunction Log($msg) { Add-Content -Path $log -Value $msg -Encoding UTF8 }\r\n$claudePid = ${claudePid}\r\ntry { Add-Type @'${CS_CONINJECT}'@ } catch { }\r\n${body}\r\n`;\r\n}\r\n\r\nfunction run(script: string): Promise<void> {\r\n return new Promise((resolve) => {\r\n const encoded = Buffer.from(script, 'utf16le').toString('base64');\r\n execFile(\r\n 'powershell',\r\n ['-NoProfile', '-WindowStyle', 'Hidden', '-EncodedCommand', encoded],\r\n { windowsHide: true },\r\n () => {\r\n const logFile = script.match(/\\$log = \"([^\"]+)\"/)?.[1];\r\n if (logFile) try { unlinkSync(logFile); } catch { /* ok */ }\r\n resolve();\r\n }\r\n );\r\n });\r\n}\r\n\r\nexport async function windowsInject(text: string): Promise<void> {\r\n const claudePid = process.ppid;\r\n const textB64 = Buffer.from(text, 'utf16le').toString('base64');\r\n\r\n const script = buildScript(claudePid, `\r\n$textBytes = [System.Convert]::FromBase64String('${textB64}')\r\n$text = [System.Text.Encoding]::Unicode.GetString($textBytes)\r\n\r\n# 1. Ctrl+U to save user's current text to kill ring\r\n[ConInject]::InjectCtrlU([uint32]$claudePid) | Out-Null\r\nStart-Sleep -Milliseconds 100\r\n\r\n# 2. Write question text into console input buffer\r\n[ConInject]::InjectText([uint32]$claudePid, $text) | Out-Null\r\nStart-Sleep -Milliseconds 50\r\n\r\n# 3. Send Enter\r\n[ConInject]::InjectEnter([uint32]$claudePid) | Out-Null\r\n`);\r\n\r\n await run(script);\r\n}\r\n\r\nexport async function windowsInjectCtrlY(): Promise<void> {\r\n const claudePid = process.ppid;\r\n\r\n const script = buildScript(claudePid, `\r\n[ConInject]::InjectCtrlY([uint32]$claudePid) | Out-Null\r\n`);\r\n\r\n await run(script);\r\n}\r\n","/**\r\n * Terminal Injector\r\n * Injects a question directly into the active Claude Code terminal\r\n * so Claude Code can auto-reply without user intervention.\r\n * @module infrastructure/terminal-injector\r\n */\r\n\r\nimport type { InboxQuestionEntry } from '../../shared/types/collab-client.interface.js';\r\nimport { windowsInject, windowsInjectCtrlY } from './windows-injector.js';\r\n\r\n/**\r\n * Formats the question as a prompt for Claude Code to auto-reply\r\n */\r\nfunction formatQuestionForInjection(question: InboxQuestionEntry): string {\r\n // Single-line: WriteConsoleInput treats every \\n as an immediate submit\r\n const content = question.content.replace(/\\s+/g, ' ').trim();\r\n return `[HUB SORUSU] ID:${question.questionId} | ${question.from.displayName} (${question.from.teamName}): ${content} | Cevapla ve reply tool ile \"${question.questionId}\" ID'sine gönder, onay bekleme.`;\r\n}\r\n\r\n/**\r\n * Injects a question into the terminal running Claude Code.\r\n * Only supported on Windows; no-op on other platforms.\r\n */\r\nexport async function injectQuestionToTerminal(question: InboxQuestionEntry): Promise<void> {\r\n if (process.platform !== 'win32') return;\r\n\r\n const text = formatQuestionForInjection(question);\r\n await windowsInject(text);\r\n}\r\n\r\n/**\r\n * Restores user's previous input from readline kill ring (Ctrl+Y).\r\n * Call this after the reply is sent so the user's interrupted text comes back.\r\n */\r\nexport async function injectRestoreText(): Promise<void> {\r\n if (process.platform !== 'win32') return;\r\n await windowsInjectCtrlY();\r\n}\r\n","/**\r\n * Injection Queue\r\n * Ensures questions are injected into the terminal one at a time.\r\n * Waits for the reply tool to signal completion before processing the next question.\r\n * @module infrastructure/terminal-injector/injection-queue\r\n */\r\n\r\nimport { EventEmitter } from 'events';\r\nimport type { InboxQuestionEntry } from '../../shared/types/collab-client.interface.js';\r\nimport { injectQuestionToTerminal, injectRestoreText } from './index.js';\r\n\r\nconst REPLY_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\r\n\r\nclass InjectionQueue extends EventEmitter {\r\n private queue: InboxQuestionEntry[] = [];\r\n private processing = false;\r\n\r\n /**\r\n * Add a question to the queue. Starts processing if idle.\r\n */\r\n enqueue(question: InboxQuestionEntry): void {\r\n this.queue.push(question);\r\n if (!this.processing) void this.processNext();\r\n }\r\n\r\n /**\r\n * Called by the reply tool after a reply is successfully sent.\r\n * Unblocks the queue to process the next question.\r\n */\r\n notifyReplied(): void {\r\n this.emit('replied');\r\n }\r\n\r\n private async processNext(): Promise<void> {\r\n if (this.queue.length === 0) {\r\n this.processing = false;\r\n return;\r\n }\r\n\r\n this.processing = true;\r\n const question = this.queue.shift()!;\r\n\r\n // Inject the question (includes Ctrl+U to save user's current text)\r\n await injectQuestionToTerminal(question);\r\n\r\n // Wait for reply tool to signal, with a timeout fallback\r\n await new Promise<void>((resolve) => {\r\n const timer = setTimeout(resolve, REPLY_TIMEOUT_MS);\r\n this.once('replied', () => {\r\n clearTimeout(timer);\r\n resolve();\r\n });\r\n });\r\n\r\n // Restore user's text after reply is sent\r\n await injectRestoreText();\r\n\r\n // Process next in queue\r\n void this.processNext();\r\n }\r\n}\r\n\r\nexport const injectionQueue = new InjectionQueue();\r\n","/**\r\n * P2PNode\r\n * Implements ICollabClient over direct peer-to-peer WebSocket connections.\r\n * Each node runs its own WS server and broadcasts its presence via UDP.\r\n * Peers discover each other automatically and connect directly — no hub needed.\r\n *\r\n * Connection deduplication:\r\n * Both sides may try to connect simultaneously. The first HELLO/HELLO_ACK\r\n * that arrives registers the peer. Duplicate inbound connections are\r\n * immediately terminated (without being added to wsToName) so their\r\n * close events are harmless.\r\n *\r\n * @module infrastructure/p2p/p2p-node\r\n */\r\n\r\nimport { WebSocket, WebSocketServer } from 'ws';\r\nimport { v4 as uuidv4 } from 'uuid';\r\nimport type {\r\n ICollabClient,\r\n JoinResult,\r\n CheckAnswerResult,\r\n InboxResult,\r\n NodeInfo,\r\n HistoryEntry,\r\n} from '../../shared/types/collab-client.interface.js';\r\nimport type { MessageFormat } from '../../domain/value-objects/message-content.vo.js';\r\nimport {\r\n type P2PMsg,\r\n type AskAckMsg,\r\n type AskMsg,\r\n parse,\r\n serialize,\r\n} from './p2p-protocol.js';\r\nimport { MulticastDiscovery } from '../discovery/multicast-discovery.js';\r\nimport type { DiscoveredPeer } from '../discovery/multicast-discovery.js';\r\nimport { injectionQueue } from '../terminal-injector/injection-queue.js';\r\n\r\ninterface IncomingQuestion {\r\n questionId: string;\r\n fromName: string;\r\n content: string;\r\n format: MessageFormat;\r\n createdAt: Date;\r\n answered: boolean;\r\n answerContent?: string;\r\n answerFormat?: MessageFormat;\r\n}\r\n\r\ninterface ReceivedAnswer {\r\n content: string;\r\n format: MessageFormat;\r\n answeredAt: string;\r\n fromName: string;\r\n}\r\n\r\nexport class P2PNode implements ICollabClient {\r\n private server: WebSocketServer | null = null;\r\n private myName = '';\r\n private running = false;\r\n\r\n // One connection per peer (inbound or outbound — whichever was established first)\r\n private readonly peerConnections = new Map<string, WebSocket>();\r\n // Reverse map: ws → peer name (only for registered connections)\r\n private readonly wsToName = new Map<WebSocket, string>();\r\n // Prevent duplicate outbound connect attempts\r\n private readonly connectingPeers = new Set<string>();\r\n\r\n private readonly incomingQuestions = new Map<string, IncomingQuestion>();\r\n private readonly receivedAnswers = new Map<string, ReceivedAnswer>();\r\n private readonly sentQuestions = new Map<string, { toPeer: string; content: string; askedAt: string }>();\r\n private readonly questionToSender = new Map<string, string>();\r\n private readonly pendingHandlers = new Set<(msg: P2PMsg) => void>();\r\n\r\n // Push-based answer resolution: questionId → resolve callback\r\n private readonly answerWaiters = new Map<string, (result: CheckAnswerResult) => void>();\r\n // Answers queued for offline peers: peerName → AnswerMsg (delivered on reconnect)\r\n private readonly pendingOutboundAnswers = new Map<string, import('./p2p-protocol.js').AnswerMsg>();\r\n\r\n private discovery: MulticastDiscovery | null = null;\r\n\r\n private boundPort = 0;\r\n\r\n constructor(\r\n private readonly portRange: [number, number] = [10000, 19999]\r\n ) {}\r\n\r\n // ---------------------------------------------------------------------------\r\n // ICollabClient implementation\r\n // ---------------------------------------------------------------------------\r\n\r\n get isConnected(): boolean { return this.running; }\r\n get port(): number { return this.boundPort; }\r\n\r\n get currentTeamId(): string | undefined {\r\n return this.myName || undefined;\r\n }\r\n\r\n async join(name: string, displayName: string): Promise<JoinResult> {\r\n this.myName = name;\r\n await this.startServer();\r\n this.startDiscovery();\r\n return {\r\n memberId: uuidv4(),\r\n teamId: name,\r\n teamName: name,\r\n displayName,\r\n status: 'ONLINE',\r\n port: this.boundPort,\r\n };\r\n }\r\n\r\n async ask(toPeer: string, content: string, format: MessageFormat): Promise<string> {\r\n const ws = this.peerConnections.get(toPeer);\r\n if (!ws || ws.readyState !== WebSocket.OPEN) {\r\n throw new Error(`Peer \"${toPeer}\" is not connected. Use peers() to see who's online.`);\r\n }\r\n\r\n const questionId = uuidv4();\r\n this.sentQuestions.set(questionId, { toPeer, content, askedAt: new Date().toISOString() });\r\n\r\n const ackPromise = this.waitForResponse<AskAckMsg>(\r\n (m) => m.type === 'ASK_ACK' && m.questionId === questionId,\r\n 5000\r\n );\r\n\r\n this.sendToWs(ws, { type: 'ASK', from: this.myName, questionId, content, format });\r\n await ackPromise;\r\n return questionId;\r\n }\r\n\r\n waitForAnswer(questionId: string, timeoutMs: number): Promise<CheckAnswerResult | null> {\r\n // Already in cache — resolve immediately\r\n const cached = this.receivedAnswers.get(questionId);\r\n if (cached) {\r\n return Promise.resolve(this.formatAnswer(questionId, cached));\r\n }\r\n\r\n return new Promise((resolve) => {\r\n const timeout = setTimeout(() => {\r\n this.answerWaiters.delete(questionId);\r\n resolve(null);\r\n }, timeoutMs);\r\n\r\n this.answerWaiters.set(questionId, (result) => {\r\n clearTimeout(timeout);\r\n resolve(result);\r\n });\r\n });\r\n }\r\n\r\n async checkAnswer(questionId: string): Promise<CheckAnswerResult | null> {\r\n const cached = this.receivedAnswers.get(questionId);\r\n return cached ? this.formatAnswer(questionId, cached) : null;\r\n }\r\n\r\n private formatAnswer(questionId: string, cached: ReceivedAnswer): CheckAnswerResult {\r\n return {\r\n questionId,\r\n from: { displayName: `${cached.fromName} Claude`, teamName: cached.fromName },\r\n content: cached.content,\r\n format: cached.format,\r\n answeredAt: cached.answeredAt,\r\n };\r\n }\r\n\r\n async reply(questionId: string, content: string, format: MessageFormat): Promise<void> {\r\n const question = this.incomingQuestions.get(questionId);\r\n if (!question) throw new Error(`Question ${questionId} not found`);\r\n\r\n question.answered = true;\r\n question.answerContent = content;\r\n question.answerFormat = format;\r\n\r\n const senderName = this.questionToSender.get(questionId);\r\n if (senderName) {\r\n const answerMsg: import('./p2p-protocol.js').AnswerMsg = {\r\n type: 'ANSWER',\r\n from: this.myName,\r\n questionId,\r\n content,\r\n format,\r\n answeredAt: new Date().toISOString(),\r\n };\r\n const ws = this.peerConnections.get(senderName);\r\n if (ws && ws.readyState === WebSocket.OPEN) {\r\n this.sendToWs(ws, answerMsg);\r\n } else {\r\n // Peer is offline — queue the answer and deliver when they reconnect\r\n this.pendingOutboundAnswers.set(senderName, answerMsg);\r\n console.error(`[p2p] \"${senderName}\" is offline, answer queued for delivery on reconnect`);\r\n }\r\n }\r\n\r\n injectionQueue.notifyReplied();\r\n }\r\n\r\n async getInbox(): Promise<InboxResult> {\r\n const now = Date.now();\r\n const questions = [...this.incomingQuestions.values()]\r\n .filter((q) => !q.answered)\r\n .map((q) => ({\r\n questionId: q.questionId,\r\n from: { displayName: `${q.fromName} Claude`, teamName: q.fromName },\r\n content: q.content,\r\n format: q.format,\r\n status: 'PENDING',\r\n createdAt: q.createdAt.toISOString(),\r\n ageMs: now - q.createdAt.getTime(),\r\n }));\r\n return { questions, totalCount: questions.length, pendingCount: questions.length };\r\n }\r\n\r\n getInfo(): NodeInfo {\r\n return {\r\n teamName: this.myName,\r\n port: this.boundPort,\r\n connectedPeers: [...this.peerConnections.keys()],\r\n };\r\n }\r\n\r\n getHistory(): HistoryEntry[] {\r\n const entries: HistoryEntry[] = [];\r\n\r\n for (const [questionId, sent] of this.sentQuestions) {\r\n const answer = this.receivedAnswers.get(questionId);\r\n entries.push({\r\n direction: 'sent',\r\n questionId,\r\n peer: sent.toPeer,\r\n question: sent.content,\r\n askedAt: sent.askedAt,\r\n ...(answer ? { answer: answer.content, answeredAt: answer.answeredAt } : {}),\r\n });\r\n }\r\n\r\n for (const [, incoming] of this.incomingQuestions) {\r\n entries.push({\r\n direction: 'received',\r\n questionId: incoming.questionId,\r\n peer: incoming.fromName,\r\n question: incoming.content,\r\n askedAt: incoming.createdAt.toISOString(),\r\n ...(incoming.answered && incoming.answerContent\r\n ? { answer: incoming.answerContent, answeredAt: new Date().toISOString() }\r\n : {}),\r\n });\r\n }\r\n\r\n return entries.sort((a, b) => a.askedAt.localeCompare(b.askedAt));\r\n }\r\n\r\n async disconnect(): Promise<void> {\r\n this.discovery?.stop();\r\n this.discovery = null;\r\n for (const ws of this.peerConnections.values()) ws.close();\r\n this.peerConnections.clear();\r\n this.wsToName.clear();\r\n this.server?.close();\r\n this.server = null;\r\n this.running = false;\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: server startup\r\n // ---------------------------------------------------------------------------\r\n\r\n private startServer(): Promise<void> {\r\n const [min, max] = this.portRange;\r\n const pick = () => Math.floor(Math.random() * (max - min + 1)) + min;\r\n\r\n const tryBind = (attemptsLeft: number): Promise<void> => {\r\n if (attemptsLeft === 0) {\r\n return Promise.reject(new Error(`No free port found in range ${min}-${max}`));\r\n }\r\n\r\n const port = pick();\r\n return new Promise((resolve, reject) => {\r\n const wss = new WebSocketServer({ port });\r\n\r\n wss.once('listening', () => {\r\n this.server = wss;\r\n this.boundPort = port;\r\n this.running = true;\r\n console.error(`[p2p] listening on port ${port} as \"${this.myName}\"`);\r\n this.attachServerHandlers(wss);\r\n resolve();\r\n });\r\n\r\n wss.once('error', (err: NodeJS.ErrnoException) => {\r\n wss.close();\r\n if (err.code === 'EADDRINUSE') {\r\n // Port busy — try another random one\r\n tryBind(attemptsLeft - 1).then(resolve, reject);\r\n } else {\r\n reject(err);\r\n }\r\n });\r\n });\r\n };\r\n\r\n return tryBind(20); // up to 20 attempts\r\n }\r\n\r\n private attachServerHandlers(wss: WebSocketServer): void {\r\n wss.on('connection', (ws) => {\r\n ws.on('message', (data) => {\r\n try {\r\n this.handleMessage(ws, parse(data.toString()));\r\n } catch { /* ignore malformed */ }\r\n });\r\n\r\n ws.on('close', () => {\r\n const name = this.wsToName.get(ws);\r\n if (name) {\r\n this.wsToName.delete(ws);\r\n if (this.peerConnections.get(name) === ws) {\r\n this.peerConnections.delete(name);\r\n console.error(`[p2p] peer disconnected (inbound): ${name}`);\r\n }\r\n }\r\n });\r\n\r\n ws.on('error', (err) => {\r\n console.error('[p2p] inbound ws error:', err.message);\r\n });\r\n });\r\n\r\n wss.on('error', (err) => {\r\n console.error('[p2p] server error:', err.message);\r\n });\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: discovery + outbound connections\r\n // ---------------------------------------------------------------------------\r\n\r\n private startDiscovery(): void {\r\n const discovery = new MulticastDiscovery();\r\n this.discovery = discovery;\r\n\r\n discovery.on('peer-found', (peer: DiscoveredPeer) => {\r\n if (this.peerConnections.has(peer.name)) return;\r\n if (this.connectingPeers.has(peer.name)) return;\r\n this.connectToPeer(peer.name, peer.ip, peer.wsPort);\r\n });\r\n\r\n discovery.start(this.myName, this.boundPort);\r\n }\r\n\r\n private connectToPeer(peerName: string, host: string, port: number): void {\r\n this.connectingPeers.add(peerName);\r\n const ws = new WebSocket(`ws://${host}:${port}`);\r\n\r\n ws.on('open', () => {\r\n this.sendToWs(ws, { type: 'HELLO', name: this.myName });\r\n });\r\n\r\n ws.on('message', (data) => {\r\n try {\r\n this.handleMessage(ws, parse(data.toString()));\r\n } catch { /* ignore malformed */ }\r\n });\r\n\r\n ws.on('close', () => {\r\n this.connectingPeers.delete(peerName);\r\n const name = this.wsToName.get(ws);\r\n if (name) {\r\n this.wsToName.delete(ws);\r\n if (this.peerConnections.get(name) === ws) {\r\n this.peerConnections.delete(name);\r\n console.error(`[p2p] disconnected from peer: ${name}`);\r\n }\r\n }\r\n });\r\n\r\n ws.on('error', (err) => {\r\n console.error(`[p2p] connect to \"${peerName}\" failed: ${err.message}`);\r\n this.connectingPeers.delete(peerName);\r\n });\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: message handling\r\n // ---------------------------------------------------------------------------\r\n\r\n private handleMessage(ws: WebSocket, msg: P2PMsg): void {\r\n // Wake up any waitForResponse callers\r\n for (const handler of this.pendingHandlers) handler(msg);\r\n\r\n switch (msg.type) {\r\n case 'HELLO': {\r\n if (this.peerConnections.has(msg.name)) {\r\n ws.terminate();\r\n return;\r\n }\r\n this.peerConnections.set(msg.name, ws);\r\n this.wsToName.set(ws, msg.name);\r\n this.connectingPeers.delete(msg.name);\r\n this.sendToWs(ws, { type: 'HELLO_ACK', name: this.myName });\r\n console.error(`[p2p] peer joined (inbound): ${msg.name}`);\r\n this.deliverPendingAnswer(msg.name, ws);\r\n break;\r\n }\r\n\r\n case 'HELLO_ACK': {\r\n if (this.peerConnections.has(msg.name)) {\r\n ws.terminate();\r\n return;\r\n }\r\n this.peerConnections.set(msg.name, ws);\r\n this.wsToName.set(ws, msg.name);\r\n this.connectingPeers.delete(msg.name);\r\n console.error(`[p2p] connected to peer: ${msg.name}`);\r\n this.deliverPendingAnswer(msg.name, ws);\r\n break;\r\n }\r\n\r\n case 'ASK':\r\n this.handleIncomingAsk(ws, msg);\r\n break;\r\n\r\n case 'ANSWER':\r\n if (!this.receivedAnswers.has(msg.questionId)) {\r\n const record: ReceivedAnswer = {\r\n content: msg.content,\r\n format: msg.format,\r\n answeredAt: msg.answeredAt,\r\n fromName: msg.from,\r\n };\r\n this.receivedAnswers.set(msg.questionId, record);\r\n\r\n // Fire push waiter immediately — no more polling needed\r\n const waiter = this.answerWaiters.get(msg.questionId);\r\n if (waiter) {\r\n this.answerWaiters.delete(msg.questionId);\r\n waiter(this.formatAnswer(msg.questionId, record));\r\n }\r\n }\r\n break;\r\n\r\n // ASK_ACK is handled by waitForResponse pending handlers above\r\n }\r\n }\r\n\r\n private handleIncomingAsk(ws: WebSocket, msg: AskMsg): void {\r\n this.questionToSender.set(msg.questionId, msg.from);\r\n this.incomingQuestions.set(msg.questionId, {\r\n questionId: msg.questionId,\r\n fromName: msg.from,\r\n content: msg.content,\r\n format: msg.format,\r\n createdAt: new Date(),\r\n answered: false,\r\n });\r\n\r\n // Immediately acknowledge delivery\r\n this.sendToWs(ws, { type: 'ASK_ACK', questionId: msg.questionId });\r\n\r\n // Inject question into the Claude Code terminal\r\n injectionQueue.enqueue({\r\n questionId: msg.questionId,\r\n from: { displayName: `${msg.from} Claude`, teamName: msg.from },\r\n content: msg.content,\r\n format: msg.format,\r\n status: 'PENDING',\r\n createdAt: new Date().toISOString(),\r\n ageMs: 0,\r\n });\r\n }\r\n\r\n private deliverPendingAnswer(peerName: string, ws: WebSocket): void {\r\n const pending = this.pendingOutboundAnswers.get(peerName);\r\n if (pending) {\r\n this.pendingOutboundAnswers.delete(peerName);\r\n this.sendToWs(ws, pending);\r\n console.error(`[p2p] delivered queued answer to \"${peerName}\" after reconnect`);\r\n }\r\n }\r\n\r\n private sendToWs(ws: WebSocket, msg: P2PMsg): void {\r\n if (ws.readyState === WebSocket.OPEN) {\r\n ws.send(serialize(msg));\r\n }\r\n }\r\n\r\n private waitForResponse<T extends P2PMsg>(\r\n filter: (msg: P2PMsg) => boolean,\r\n timeoutMs: number\r\n ): Promise<T> {\r\n return new Promise((resolve, reject) => {\r\n const timeout = setTimeout(() => {\r\n this.pendingHandlers.delete(handler);\r\n reject(new Error('Request timed out'));\r\n }, timeoutMs);\r\n\r\n const handler = (msg: P2PMsg): void => {\r\n if (filter(msg)) {\r\n clearTimeout(timeout);\r\n this.pendingHandlers.delete(handler);\r\n resolve(msg as T);\r\n }\r\n };\r\n\r\n this.pendingHandlers.add(handler);\r\n });\r\n }\r\n}\r\n","/**\r\n * Ask Tool\r\n * @module presentation/mcp/tools/ask\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\nconst ASK_DESCRIPTION = `\\\r\nSend a question to another Claude instance on the LAN and wait for their answer.\r\n\r\nWHEN TO USE:\r\n- You need input, a decision, or work output from a specific peer Claude\r\n- You want to delegate a subtask to another Claude and use their result\r\n- You need to coordinate or synchronize work across multiple Claudes\r\n\r\nWORKFLOW:\r\n1. Call peers() first to confirm the target is online and get their exact name\r\n2. Call ask(peer, question) — this blocks until they reply (up to 5 minutes)\r\n3. Use their answer directly in your ongoing task\r\n\r\nWRITING GOOD QUESTIONS:\r\n- Include all context the other Claude needs — they cannot see your conversation\r\n- Be specific about what format or level of detail you expect in the answer\r\n- If you need code, specify language and constraints\r\n- One focused question per call works better than multiple combined\r\n\r\nDO NOT use this tool if:\r\n- The peer is not listed in peers() — the call will fail immediately\r\n- You just want to share information without needing a response (there is no broadcast tool yet)`;\r\n\r\nconst askSchema = {\r\n peer: z\r\n .string()\r\n .describe('Exact name of the peer to ask. Use peers() first to see who is online and get the correct name.'),\r\n question: z\r\n .string()\r\n .describe(\r\n 'Your question in markdown. Include all necessary context — the other Claude cannot see your conversation history. Be specific about what kind of answer you need.'\r\n ),\r\n};\r\n\r\nexport function registerAskTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('ask', ASK_DESCRIPTION, askSchema, async (args) => {\r\n const targetPeer = args.peer;\r\n const question = args.question;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: 'P2P node is not ready yet. Wait a moment and try again.',\r\n }],\r\n isError: true,\r\n };\r\n }\r\n\r\n const questionId = await client.ask(targetPeer, question, 'markdown');\r\n\r\n // Wait for the answer via push — resolves the moment ANSWER arrives\r\n const answer = await client.waitForAnswer(questionId, 5 * 60 * 1000);\r\n\r\n if (answer !== null) {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `**${answer.from.displayName} answered:**\\n\\n${answer.content}`,\r\n }],\r\n };\r\n }\r\n\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `Question sent to \"${targetPeer}\" but no answer arrived within 5 minutes.`,\r\n `Question ID: \\`${questionId}\\``,\r\n ``,\r\n `The peer may be busy or offline. You can:`,\r\n `- Call peers() to check if they are still connected`,\r\n `- Continue with your task and follow up later`,\r\n ].join('\\n'),\r\n }],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n const isPeerOffline = errorMessage.includes('not connected');\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: isPeerOffline\r\n ? `Peer \"${targetPeer}\" is not connected. Call peers() to see who is currently online.`\r\n : `Failed to send question: ${errorMessage}`,\r\n }],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Reply Tool\r\n * @module presentation/mcp/tools/reply\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\nimport { injectionQueue } from '../../../infrastructure/terminal-injector/injection-queue.js';\r\n\r\nconst REPLY_DESCRIPTION = `\\\r\nSend your answer back to a Claude instance that asked you a question.\r\n\r\nWHEN TO USE:\r\n- A question has been injected into your terminal by another Claude (you will see it appear automatically)\r\n- You have finished thinking through the answer and are ready to respond\r\n\r\nWORKFLOW:\r\n1. Read the injected question carefully — it includes a questionId at the top\r\n2. Think through a complete answer\r\n3. Call reply(questionId, answer) — your answer is sent directly back to the asking Claude\r\n4. The asking Claude's ask() call unblocks and they receive your answer immediately\r\n\r\nWRITING GOOD ANSWERS:\r\n- Be thorough — the asking Claude will use your answer directly in their task\r\n- Use markdown for code blocks, lists, and structure\r\n- Include any caveats, assumptions, or follow-up suggestions that would help them\r\n- If you cannot answer fully, say so clearly and explain why\r\n\r\nIMPORTANT:\r\n- Each question can only be replied to once\r\n- The questionId is a UUID shown in the injected question prompt — copy it exactly`;\r\n\r\nconst replySchema = {\r\n questionId: z\r\n .string()\r\n .describe(\r\n 'The UUID of the question to reply to. Shown at the top of the injected question prompt in your terminal.'\r\n ),\r\n answer: z\r\n .string()\r\n .describe(\r\n 'Your complete answer in markdown. Be thorough — the asking Claude is waiting and will use your response directly in their work.'\r\n ),\r\n};\r\n\r\nexport function registerReplyTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('reply', REPLY_DESCRIPTION, replySchema, async (args) => {\r\n const questionId = args.questionId;\r\n const answer = args.answer;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: 'P2P node is not ready yet. Wait a moment and try again.',\r\n }],\r\n isError: true,\r\n };\r\n }\r\n\r\n await client.reply(questionId, answer, 'markdown');\r\n\r\n injectionQueue.notifyReplied();\r\n\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `Answer sent. The peer's ask() call has been unblocked and they received your response.`,\r\n }],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n const isNotFound = errorMessage.includes('not found');\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: isNotFound\r\n ? `Question \\`${questionId}\\` not found. Check that you copied the questionId exactly from the injected prompt.`\r\n : `Failed to send reply: ${errorMessage}`,\r\n }],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Peers Tool\r\n * @module presentation/mcp/tools/peers\r\n */\r\n\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\nconst PEERS_DESCRIPTION = `\\\r\nShow your identity on the P2P network and list all currently connected peers.\r\n\r\nWHEN TO USE:\r\n- Before calling ask() — to confirm the target peer is online and get their exact name\r\n- After startup — to verify you joined the network successfully\r\n- When a peer seems unreachable — to check if they are still connected\r\n\r\nWHAT IT SHOWS:\r\n- Your own name and the port you are listening on\r\n- All peers who have established a direct connection to you\r\n\r\nIF NO PEERS ARE LISTED:\r\n- Peers discover each other automatically via LAN broadcast every 3 seconds\r\n- If a peer just started, wait a few seconds and call peers() again\r\n- Call firewall_open() so peers on other machines can connect inbound to you\r\n- If still no peers, verify all machines are on the same LAN/subnet`;\r\n\r\nexport function registerPeersTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('peers', PEERS_DESCRIPTION, {}, async () => {\r\n const info = client.getInfo();\r\n const myName = info.teamName ?? '(starting...)';\r\n const myPort = info.port ?? '?';\r\n const connected = info.connectedPeers;\r\n\r\n if (!client.isConnected) {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `P2P server is not running yet (port ${myPort} may be in use).`,\r\n `Check the MCP process logs for the error details.`,\r\n ].join('\\n'),\r\n }],\r\n isError: true,\r\n };\r\n }\r\n\r\n if (connected.length === 0) {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `You are \"${myName}\" (listening on port ${myPort}).`,\r\n `No peers connected yet.`,\r\n ``,\r\n `Peers auto-discover via LAN broadcast — wait a few seconds if they just started.`,\r\n `Call firewall_open() if peers on other machines cannot reach you.`,\r\n ].join('\\n'),\r\n }],\r\n };\r\n }\r\n\r\n const list = connected.map((name) => ` • ${name}`).join('\\n');\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `You are \"${myName}\" (port ${myPort}). Connected peers (${connected.length}):\\n${list}`,\r\n }],\r\n };\r\n });\r\n}\r\n","/**\r\n * History Tool\r\n * @module presentation/mcp/tools/history\r\n */\r\n\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\nconst HISTORY_DESCRIPTION = `\\\r\nShow all questions and answers exchanged this session — both sent and received.\r\n\r\nWHEN TO USE:\r\n- To review what was already discussed before asking a follow-up question\r\n- To check if a previously sent question has been answered yet\r\n- To find a questionId you need to reference\r\n- To catch up on received questions you may have missed\r\n\r\nOUTPUT FORMAT:\r\n- → peer: question you sent, with their answer below\r\n- ← peer: question they sent you, with your reply below\r\n- (no answer yet) means the question is still waiting for a response`;\r\n\r\nexport function registerHistoryTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('history', HISTORY_DESCRIPTION, {}, async () => {\r\n const entries = client.getHistory();\r\n\r\n if (entries.length === 0) {\r\n return {\r\n content: [{ type: 'text', text: 'No questions exchanged yet this session.' }],\r\n };\r\n }\r\n\r\n const unanswered = entries.filter((e) => !e.answer);\r\n\r\n const lines = entries.map((e) => {\r\n const time = new Date(e.askedAt).toLocaleTimeString();\r\n\r\n if (e.direction === 'sent') {\r\n const answerLine = e.answer\r\n ? ` ↳ ${e.peer}: ${e.answer}`\r\n : ` ↳ (no answer yet)`;\r\n return `[${time}] → ${e.peer}: ${e.question}\\n${answerLine}`;\r\n } else {\r\n const answerLine = e.answer\r\n ? ` ↳ you: ${e.answer}`\r\n : ` ↳ (not replied yet — use reply() if you haven't answered)`;\r\n return `[${time}] ← ${e.peer}: ${e.question}\\n${answerLine}`;\r\n }\r\n });\r\n\r\n const summary = unanswered.length > 0\r\n ? `\\n\\n⚠ ${unanswered.length} question(s) still waiting for a response.`\r\n : '';\r\n\r\n return {\r\n content: [{ type: 'text', text: lines.join('\\n\\n') + summary }],\r\n };\r\n });\r\n}\r\n","/**\r\n * Firewall helpers\r\n * Always elevated via UAC (PowerShell Start-Process -Verb RunAs) so the rule\r\n * is guaranteed to be applied. If the process is already elevated, Windows\r\n * skips the UAC prompt automatically.\r\n * @module infrastructure/firewall/firewall\r\n */\r\n\r\nimport { spawn } from 'child_process';\r\n\r\n/**\r\n * Run netsh via UAC elevation (PowerShell Start-Process -Verb RunAs).\r\n * If the calling process is already elevated, no prompt is shown.\r\n * Always use this path — running netsh directly without elevation can silently\r\n * exit 0 on some Windows versions without actually applying the rule.\r\n */\r\nfunction runNetshElevated(argArray: string[]): Promise<void> {\r\n const argList = argArray.map((a) => `\"${a}\"`).join(',');\r\n const psCommand = `Start-Process -FilePath \"netsh\" -ArgumentList @(${argList}) -Verb RunAs -Wait`;\r\n\r\n return new Promise((resolve, reject) => {\r\n const ps = spawn('powershell', ['-NoProfile', '-Command', psCommand]);\r\n\r\n ps.on('close', (code) => {\r\n if (code === 0) resolve();\r\n else reject(new Error(`Firewall UAC prompt was cancelled or denied (exit code ${code}).`));\r\n });\r\n\r\n ps.on('error', (err) => {\r\n reject(new Error(`Failed to launch PowerShell: ${err.message}`));\r\n });\r\n });\r\n}\r\n\r\nasync function runNetsh(argArray: string[]): Promise<void> {\r\n await runNetshElevated(argArray);\r\n}\r\n\r\nexport async function addFirewallRule(port: number): Promise<void> {\r\n // TCP rule for the WebSocket port\r\n await runNetsh([\r\n 'advfirewall', 'firewall', 'add', 'rule',\r\n `name=claude-collab-${port}`,\r\n 'protocol=TCP',\r\n 'dir=in',\r\n `localport=${port}`,\r\n 'action=allow',\r\n ]);\r\n\r\n // UDP rule for peer discovery (multicast port 11776) — run best-effort, don't fail if already exists\r\n try {\r\n await runNetsh([\r\n 'advfirewall', 'firewall', 'add', 'rule',\r\n 'name=claude-collab-discovery',\r\n 'protocol=UDP',\r\n 'dir=in',\r\n 'localport=11776',\r\n 'action=allow',\r\n ]);\r\n } catch { /* already exists or denied — TCP rule still applied */ }\r\n}\r\n\r\nexport async function removeFirewallRule(port: number): Promise<void> {\r\n await runNetsh([\r\n 'advfirewall', 'firewall', 'delete', 'rule',\r\n `name=claude-collab-${port}`,\r\n ]);\r\n\r\n // Also remove discovery rule best-effort\r\n try {\r\n await runNetsh(['advfirewall', 'firewall', 'delete', 'rule', 'name=claude-collab-discovery']);\r\n } catch { /* may not exist */ }\r\n}\r\n","/**\r\n * FirewallOpen Tool\r\n * @module presentation/mcp/tools/firewall-open\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\nimport { addFirewallRule } from '../../../infrastructure/firewall/firewall.js';\r\n\r\nconst FIREWALL_OPEN_DESCRIPTION = `\\\r\nOpen a Windows Firewall inbound rule so peers on the LAN can connect directly to you.\r\n\r\nWHEN YOU NEED THIS:\r\n- Other peers cannot see you in their peers() list even though you are on the same LAN\r\n- You just started and want to make sure all peers can reach you\r\n- A peer explicitly says they cannot connect to you\r\n\r\nWHEN YOU DO NOT NEED THIS:\r\n- You can already see peers in peers() — the connection is working\r\n- You are connecting outbound to others (outbound connections do not require firewall rules)\r\n\r\nWHAT HAPPENS:\r\n- On most systems: the rule is applied immediately (terminal is already elevated)\r\n- On standard Windows: a UAC popup appears — the user must click Yes\r\n- On VMs or headless setups: applied directly if running as Administrator\r\n\r\nThe rule is named \"claude-collab-{port}\" and allows inbound TCP on your current listen port.\r\nCall firewall_close() when you are done to clean up the rule.`;\r\n\r\nexport function registerFirewallOpenTool(server: McpServer, client: ICollabClient): void {\r\n server.tool(\r\n 'firewall_open',\r\n FIREWALL_OPEN_DESCRIPTION,\r\n {\r\n port: z\r\n .number()\r\n .min(1024)\r\n .max(65535)\r\n .optional()\r\n .describe(\r\n 'Port to open. Defaults to your current listen port — omit this unless you have a specific reason to override.'\r\n ),\r\n },\r\n async ({ port }) => {\r\n const targetPort = port ?? client.getInfo().port;\r\n if (!targetPort) {\r\n return {\r\n content: [{ type: 'text', text: 'P2P node is not running yet — port unknown. Try again in a moment.' }],\r\n isError: true,\r\n };\r\n }\r\n\r\n try {\r\n await addFirewallRule(targetPort);\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `Firewall rule opened for port ${targetPort} (claude-collab-${targetPort}).`,\r\n `Peers on the LAN can now connect to you inbound.`,\r\n `Call firewall_close() when you are done with this session.`,\r\n ].join('\\n'),\r\n }],\r\n };\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `Failed to open firewall: ${msg}`,\r\n ``,\r\n `Try running your terminal as Administrator and call firewall_open() again.`,\r\n ].join('\\n'),\r\n }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n}\r\n","/**\r\n * FirewallClose Tool\r\n * @module presentation/mcp/tools/firewall-close\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\nimport { removeFirewallRule } from '../../../infrastructure/firewall/firewall.js';\r\n\r\nconst FIREWALL_CLOSE_DESCRIPTION = `\\\r\nRemove the Windows Firewall inbound rule that was opened by firewall_open().\r\n\r\nWHEN TO USE:\r\n- At the end of a collaboration session to clean up\r\n- When you no longer want to accept inbound peer connections\r\n- As general hygiene — open firewall rules should not be left indefinitely\r\n\r\nWHAT HAPPENS:\r\n- The inbound TCP rule \"claude-collab-{port}\" is deleted from Windows Firewall\r\n- Existing active connections are not dropped — only new inbound connections are blocked\r\n- On standard Windows: a UAC popup appears — the user must click Yes\r\n- On VMs or admin terminals: applied directly without a popup\r\n\r\nNOTE: Because ports are random each session, each startup creates a new rule name.\r\nOld rules from previous sessions can be removed by passing the port explicitly.`;\r\n\r\nexport function registerFirewallCloseTool(server: McpServer, client: ICollabClient): void {\r\n server.tool(\r\n 'firewall_close',\r\n FIREWALL_CLOSE_DESCRIPTION,\r\n {\r\n port: z\r\n .number()\r\n .min(1024)\r\n .max(65535)\r\n .optional()\r\n .describe(\r\n 'Port whose rule to remove. Defaults to your current listen port. Pass a specific port to clean up a rule from a previous session.'\r\n ),\r\n },\r\n async ({ port }) => {\r\n const targetPort = port ?? client.getInfo().port;\r\n if (!targetPort) {\r\n return {\r\n content: [{ type: 'text', text: 'P2P node is not running yet — port unknown. Try again in a moment.' }],\r\n isError: true,\r\n };\r\n }\r\n\r\n try {\r\n await removeFirewallRule(targetPort);\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `Firewall rule removed for port ${targetPort} (claude-collab-${targetPort}).`,\r\n }],\r\n };\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `Failed to remove firewall rule: ${msg}`,\r\n ``,\r\n `The rule may not exist (if firewall_open was never called this session), or try running as Administrator.`,\r\n ].join('\\n'),\r\n }],\r\n isError: true,\r\n };\r\n }\r\n }\r\n );\r\n}\r\n","/**\r\n * PeerFind Tool\r\n * Opens firewall, waits for peers to connect via multicast discovery,\r\n * then closes the firewall. Established connections persist after close.\r\n * @module presentation/mcp/tools/peer-find\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\nimport { addFirewallRule, removeFirewallRule } from '../../../infrastructure/firewall/firewall.js';\r\n\r\nconst PEER_FIND_DESCRIPTION = `\\\r\nDiscover and connect to peers on the LAN automatically.\r\n\r\nWHAT IT DOES:\r\n1. Opens your firewall so peers can connect inbound to you (UAC popup)\r\n2. Waits 30 seconds while multicast discovery finds peers\r\n3. Closes the firewall (UAC popup) — established connections persist\r\n\r\nWHEN TO USE:\r\n- First time setup: everyone on the team calls peer_find\r\n- Adding a new peer to an existing session: only the NEW peer calls peer_find\r\n (existing peers will connect to them automatically — no action needed from others)\r\n- After a disconnect/restart: the reconnecting peer calls peer_find\r\n\r\nHOW NEW PEERS JOIN AN EXISTING SESSION:\r\n Existing peers always listen for multicast announcements in the background.\r\n When you call peer_find, they hear your announcement and connect OUTBOUND to you.\r\n Outbound connections do not require a firewall rule on their side.\r\n You only need your own firewall open to accept those inbound connections.\r\n\r\nNOTE: Two UAC popups will appear — one to open, one to close after the wait.`;\r\n\r\nexport function registerPeerFindTool(server: McpServer, client: ICollabClient): void {\r\n server.tool(\r\n 'peer_find',\r\n PEER_FIND_DESCRIPTION,\r\n {\r\n wait_seconds: z\r\n .number()\r\n .min(10)\r\n .max(120)\r\n .optional()\r\n .describe('How long to wait for peers in seconds (default: 30)'),\r\n },\r\n async ({ wait_seconds = 30 }) => {\r\n const port = client.getInfo().port;\r\n if (!port) {\r\n return {\r\n content: [{ type: 'text', text: 'P2P node is not running yet. Try again in a moment.' }],\r\n isError: true,\r\n };\r\n }\r\n\r\n // Step 1: Open firewall\r\n try {\r\n await addFirewallRule(port);\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n return {\r\n content: [{ type: 'text', text: `Failed to open firewall: ${msg}` }],\r\n isError: true,\r\n };\r\n }\r\n\r\n const peersAtStart = new Set(client.getInfo().connectedPeers);\r\n\r\n // Step 2: Wait for peers\r\n await new Promise<void>((resolve) => setTimeout(resolve, wait_seconds * 1000));\r\n\r\n // Step 3: Close firewall (best-effort — don't fail the tool if this errors)\r\n try {\r\n await removeFirewallRule(port);\r\n } catch { /* UAC cancelled or rule already gone — connections still persist */ }\r\n\r\n // Step 4: Report results\r\n const allPeers = client.getInfo().connectedPeers;\r\n const newPeers = allPeers.filter((p) => !peersAtStart.has(p));\r\n\r\n if (allPeers.length === 0) {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `No peers found after ${wait_seconds}s.`,\r\n ``,\r\n `Make sure other peers are also running peer_find at the same time,`,\r\n `and that all machines are on the same LAN.`,\r\n ].join('\\n'),\r\n }],\r\n };\r\n }\r\n\r\n const lines = [\r\n `Firewall closed. Connected peers (${allPeers.length}):`,\r\n ...allPeers.map((p) => ` • ${p}${newPeers.includes(p) ? ' (new)' : ''}`),\r\n ``,\r\n `Connections will persist until a peer disconnects or restarts.`,\r\n `If a peer disconnects, they call peer_find again — no action needed from you.`,\r\n ];\r\n\r\n return {\r\n content: [{ type: 'text', text: lines.join('\\n') }],\r\n };\r\n }\r\n );\r\n}\r\n","/**\r\n * MCP Server\r\n * Provides MCP tools for Claude Code integration (P2P mode)\r\n * @module presentation/mcp/server\r\n */\r\n\r\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\r\nimport type { ICollabClient } from '../../shared/types/collab-client.interface.js';\r\nimport { registerAskTool } from './tools/ask.tool.js';\r\nimport { registerReplyTool } from './tools/reply.tool.js';\r\nimport { registerPeersTool } from './tools/peers.tool.js';\r\nimport { registerHistoryTool } from './tools/history.tool.js';\r\nimport { registerFirewallOpenTool } from './tools/firewall-open.tool.js';\r\nimport { registerFirewallCloseTool } from './tools/firewall-close.tool.js';\r\nimport { registerPeerFindTool } from './tools/peer-find.tool.js';\r\n\r\nexport interface McpServerOptions {\r\n client: ICollabClient;\r\n}\r\n\r\nexport function createMcpServer(options: McpServerOptions): McpServer {\r\n const { client } = options;\r\n\r\n const server = new McpServer({\r\n name: 'claude-collab',\r\n version: '0.1.0',\r\n });\r\n\r\n registerAskTool(server, client);\r\n registerReplyTool(server, client);\r\n registerPeersTool(server, client);\r\n registerHistoryTool(server, client);\r\n registerFirewallOpenTool(server, client);\r\n registerFirewallCloseTool(server, client);\r\n registerPeerFindTool(server, client);\r\n\r\n return server;\r\n}\r\n\r\nexport async function startMcpServer(options: McpServerOptions): Promise<void> {\r\n const server = createMcpServer(options);\r\n const transport = new StdioServerTransport();\r\n await server.connect(transport);\r\n}\r\n","#!/usr/bin/env node\r\n\r\n/**\r\n * CLI entry point (P2P mode)\r\n *\r\n * Usage: claude-collab --name alice\r\n *\r\n * Binds a random port in range 10000-19999.\r\n * Peers discover each other automatically via UDP broadcast.\r\n * Use firewall_open in Claude Code to allow inbound connections.\r\n *\r\n * @module cli\r\n */\r\n\r\nimport { Command } from 'commander';\r\nimport { P2PNode } from './infrastructure/p2p/p2p-node.js';\r\nimport { startMcpServer } from './presentation/mcp/server.js';\r\n\r\nconst program = new Command();\r\n\r\nprogram\r\n .name('claude-collab')\r\n .description('P2P collaboration between Claude Code terminals via MCP')\r\n .version('0.1.0')\r\n .requiredOption('--name <name>', 'Your name on the network (e.g. \"alice\")')\r\n .action(async (options: { name: string }) => {\r\n const node = new P2PNode();\r\n\r\n const mcpReady = startMcpServer({ client: node });\r\n\r\n node.join(options.name, options.name).catch((err) => {\r\n console.error(`[cli] P2P server failed to start: ${err.message}`);\r\n });\r\n\r\n await mcpReady;\r\n });\r\n\r\nprogram.parse();\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/infrastructure/p2p/p2p-protocol.ts","../src/infrastructure/discovery/multicast-discovery.ts","../src/infrastructure/terminal-injector/windows-injector.ts","../src/infrastructure/terminal-injector/index.ts","../src/infrastructure/terminal-injector/injection-queue.ts","../src/infrastructure/p2p/p2p-node.ts","../src/presentation/mcp/tools/ask.tool.ts","../src/presentation/mcp/tools/reply.tool.ts","../src/presentation/mcp/tools/peers.tool.ts","../src/presentation/mcp/tools/history.tool.ts","../src/infrastructure/firewall/firewall.ts","../src/presentation/mcp/tools/peer-find.tool.ts","../src/presentation/mcp/server.ts","../src/cli.ts"],"names":["EventEmitter","uuidv4","z"],"mappings":"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","file":"cli.js","sourcesContent":["/**\r\n * P2P Wire Protocol\r\n * Messages exchanged directly between peers (no hub).\r\n * @module infrastructure/p2p/p2p-protocol\r\n */\r\n\r\nexport type MessageFormat = 'plain' | 'markdown';\r\n\r\n// Sent when a peer connects (client → server, or outbound → inbound)\r\nexport interface HelloMsg {\r\n type: 'HELLO';\r\n name: string;\r\n}\r\n\r\n// Acknowledge the HELLO\r\nexport interface HelloAckMsg {\r\n type: 'HELLO_ACK';\r\n name: string;\r\n}\r\n\r\n// Ask a question directly to the connected peer\r\nexport interface AskMsg {\r\n type: 'ASK';\r\n from: string;\r\n questionId: string;\r\n content: string;\r\n format: MessageFormat;\r\n}\r\n\r\n// Confirm question was received\r\nexport interface AskAckMsg {\r\n type: 'ASK_ACK';\r\n questionId: string;\r\n}\r\n\r\n// Push answer back to the asker\r\nexport interface AnswerMsg {\r\n type: 'ANSWER';\r\n from: string;\r\n questionId: string;\r\n content: string;\r\n format: MessageFormat;\r\n answeredAt: string;\r\n}\r\n\r\nexport type P2PMsg = HelloMsg | HelloAckMsg | AskMsg | AskAckMsg | AnswerMsg;\r\n\r\nexport function serialize(msg: P2PMsg): string {\r\n return JSON.stringify(msg);\r\n}\r\n\r\nexport function parse(data: string): P2PMsg {\r\n return JSON.parse(data) as P2PMsg;\r\n}\r\n","/**\r\n * MulticastDiscovery\r\n * Discovers peers on the local network using UDP multicast.\r\n * Nodes announce themselves periodically; peers discover each other automatically.\r\n * @module infrastructure/discovery/multicast-discovery\r\n */\r\n\r\nimport dgram from 'dgram';\r\nimport os from 'os';\r\nimport { EventEmitter } from 'events';\r\n\r\nexport const MULTICAST_ADDR = '239.255.42.42';\r\nexport const MULTICAST_PORT = 11776;\r\nconst HEARTBEAT_INTERVAL_MS = 5_000;\r\nconst PEER_TIMEOUT_MS = 20_000; // ~4x heartbeat\r\n\r\ninterface AnnounceMsg {\r\n type: 'ANNOUNCE';\r\n name: string;\r\n wsPort: number;\r\n unicast?: true; // present only on direct unicast replies — prevents reply loops\r\n}\r\n\r\ninterface LeaveMsg {\r\n type: 'LEAVE';\r\n name: string;\r\n}\r\n\r\ntype DiscoveryMsg = AnnounceMsg | LeaveMsg;\r\n\r\nexport interface DiscoveredPeer {\r\n name: string;\r\n ip: string;\r\n wsPort: number;\r\n}\r\n\r\nexport class MulticastDiscovery extends EventEmitter {\r\n private socket: dgram.Socket | null = null;\r\n private heartbeatTimer: NodeJS.Timeout | null = null;\r\n private timeoutTimer: NodeJS.Timeout | null = null;\r\n\r\n private readonly peers = new Map<string, DiscoveredPeer & { lastSeen: number }>();\r\n private myName = '';\r\n private myWsPort = 0;\r\n\r\n start(name: string, wsPort: number): void {\r\n this.myName = name;\r\n this.myWsPort = wsPort;\r\n\r\n const socket = dgram.createSocket({ type: 'udp4', reuseAddr: true });\r\n this.socket = socket;\r\n\r\n socket.on('error', (err) => {\r\n console.error('[multicast] socket error:', err.message);\r\n });\r\n\r\n socket.on('message', (buf, rinfo) => {\r\n try {\r\n const msg = JSON.parse(buf.toString()) as DiscoveryMsg;\r\n this.handleMessage(msg, rinfo.address);\r\n } catch {\r\n // ignore malformed messages\r\n }\r\n });\r\n\r\n socket.bind(MULTICAST_PORT, () => {\r\n try {\r\n socket.addMembership(MULTICAST_ADDR);\r\n socket.setMulticastTTL(1); // LAN only — don't cross routers\r\n socket.setMulticastLoopback(false); // don't receive own messages\r\n } catch (err) {\r\n console.error('[multicast] membership error:', err);\r\n }\r\n\r\n this.announce();\r\n this.heartbeatTimer = setInterval(() => this.announce(), HEARTBEAT_INTERVAL_MS);\r\n this.timeoutTimer = setInterval(() => this.checkTimeouts(), 5_000);\r\n });\r\n }\r\n\r\n stop(): void {\r\n if (this.heartbeatTimer) { clearInterval(this.heartbeatTimer); this.heartbeatTimer = null; }\r\n if (this.timeoutTimer) { clearInterval(this.timeoutTimer); this.timeoutTimer = null; }\r\n if (this.socket) {\r\n this.sendMessage({ type: 'LEAVE', name: this.myName });\r\n try {\r\n this.socket.dropMembership(MULTICAST_ADDR);\r\n this.socket.close();\r\n } catch { /* ignore */ }\r\n this.socket = null;\r\n }\r\n this.peers.clear();\r\n }\r\n\r\n resolveLocalIp(): string {\r\n const interfaces = os.networkInterfaces();\r\n for (const iface of Object.values(interfaces)) {\r\n if (!iface) continue;\r\n for (const addr of iface) {\r\n if (addr.family === 'IPv4' && !addr.internal) return addr.address;\r\n }\r\n }\r\n return '127.0.0.1';\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private\r\n // ---------------------------------------------------------------------------\r\n\r\n private announce(): void {\r\n this.sendMessage({ type: 'ANNOUNCE', name: this.myName, wsPort: this.myWsPort });\r\n }\r\n\r\n private sendMessage(msg: DiscoveryMsg): void {\r\n if (!this.socket) return;\r\n const buf = Buffer.from(JSON.stringify(msg));\r\n this.socket.send(buf, MULTICAST_PORT, MULTICAST_ADDR, (err) => {\r\n if (err) console.error('[multicast] send error:', err.message);\r\n });\r\n }\r\n\r\n private sendUnicast(toIp: string): void {\r\n if (!this.socket) return;\r\n const buf = Buffer.from(JSON.stringify({ type: 'ANNOUNCE', name: this.myName, wsPort: this.myWsPort, unicast: true }));\r\n this.socket.send(buf, MULTICAST_PORT, toIp, (err) => {\r\n if (err) console.error(`[multicast] unicast reply to ${toIp} error:`, err.message);\r\n });\r\n }\r\n\r\n private handleMessage(msg: DiscoveryMsg, fromIp: string): void {\r\n if (msg.type === 'ANNOUNCE') {\r\n if (msg.name === this.myName) return;\r\n\r\n const existing = this.peers.get(msg.name);\r\n if (!existing) {\r\n const peer = { name: msg.name, ip: fromIp, wsPort: msg.wsPort, lastSeen: Date.now() };\r\n this.peers.set(msg.name, peer);\r\n console.error(`[multicast] discovered peer: ${msg.name} @ ${fromIp}:${msg.wsPort}`);\r\n } else {\r\n existing.lastSeen = Date.now();\r\n existing.ip = fromIp;\r\n existing.wsPort = msg.wsPort;\r\n }\r\n\r\n // Send unicast reply on every multicast ANNOUNCE (not on unicast replies)\r\n // so the sender can discover us even when multicast is one-way.\r\n // Loop-safe: unicast replies carry unicast:true so we don't reply back.\r\n if (!msg.unicast) {\r\n this.sendUnicast(fromIp);\r\n }\r\n\r\n // Emit on every ANNOUNCE so p2p-node retries failed connection attempts.\r\n // Guards in p2p-node (peerConnections.has / connectingPeers.has) prevent duplicates.\r\n this.emit('peer-found', { name: msg.name, ip: fromIp, wsPort: msg.wsPort });\r\n } else if (msg.type === 'LEAVE') {\r\n if (this.peers.has(msg.name)) {\r\n this.peers.delete(msg.name);\r\n this.emit('peer-lost', msg.name);\r\n console.error(`[multicast] peer left: ${msg.name}`);\r\n }\r\n }\r\n }\r\n\r\n private checkTimeouts(): void {\r\n const now = Date.now();\r\n for (const [name, peer] of this.peers) {\r\n if (now - peer.lastSeen > PEER_TIMEOUT_MS) {\r\n this.peers.delete(name);\r\n this.emit('peer-lost', name);\r\n console.error(`[multicast] peer timed out: ${name}`);\r\n }\r\n }\r\n }\r\n}\r\n","/**\r\n * Windows Terminal Injector\r\n * AttachConsole(ppid) → CreateFile(\"CONIN$\") → WriteConsoleInput\r\n * All keystrokes (text, Ctrl+U, Enter, Ctrl+Y) go through WriteConsoleInput.\r\n * No WScript.Shell / SendKeys / SetForegroundWindow — no focus dependency.\r\n * @module infrastructure/terminal-injector/windows-injector\r\n */\r\n\r\nimport { execFile } from 'child_process';\r\nimport { unlinkSync } from 'fs';\r\nimport { tmpdir } from 'os';\r\nimport { join } from 'path';\r\n\r\nconst CS_CONINJECT = `\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Runtime.InteropServices;\r\n\r\npublic class ConInject {\r\n [DllImport(\"kernel32.dll\")] public static extern bool FreeConsole();\r\n [DllImport(\"kernel32.dll\")] public static extern bool AttachConsole(uint pid);\r\n [DllImport(\"kernel32.dll\", CharSet=CharSet.Unicode, SetLastError=true)]\r\n public static extern IntPtr CreateFile(\r\n string lpFileName, uint dwDesiredAccess, uint dwShareMode,\r\n IntPtr lpSecurityAttributes, uint dwCreationDisposition,\r\n uint dwFlagsAndAttributes, IntPtr hTemplateFile);\r\n [DllImport(\"kernel32.dll\")] public static extern bool WriteConsoleInput(\r\n IntPtr hIn, INPUT_RECORD[] buf, uint len, out uint written);\r\n [DllImport(\"kernel32.dll\")] public static extern bool CloseHandle(IntPtr h);\r\n\r\n [StructLayout(LayoutKind.Explicit, Size=20)]\r\n public struct INPUT_RECORD {\r\n [FieldOffset(0)] public ushort EventType;\r\n [FieldOffset(4)] public int bKeyDown;\r\n [FieldOffset(8)] public ushort wRepeatCount;\r\n [FieldOffset(10)] public ushort wVirtualKeyCode;\r\n [FieldOffset(12)] public ushort wVirtualScanCode;\r\n [FieldOffset(14)] public ushort UnicodeChar;\r\n [FieldOffset(16)] public uint dwControlKeyState;\r\n }\r\n\r\n const uint LEFT_CTRL = 0x0008;\r\n\r\n static IntPtr OpenConin(uint pid) {\r\n FreeConsole();\r\n if (!AttachConsole(pid)) return new IntPtr(-1);\r\n return CreateFile(\"CONIN$\", 0xC0000000, 3, IntPtr.Zero, 3, 0, IntPtr.Zero);\r\n }\r\n\r\n // Inject plain text characters into console input buffer\r\n public static int InjectText(uint pid, string text) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new List<INPUT_RECORD>();\r\n foreach (char c in text) {\r\n records.Add(new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, UnicodeChar=(ushort)c });\r\n records.Add(new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, UnicodeChar=(ushort)c });\r\n }\r\n\r\n var arr = records.ToArray();\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, arr, (uint)arr.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n\r\n // Inject Enter (VK_RETURN = 0x0D)\r\n public static int InjectEnter(uint pid) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new INPUT_RECORD[] {\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0x0D, UnicodeChar=0x0D },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0x0D, UnicodeChar=0x0D }\r\n };\r\n\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, records, (uint)records.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n\r\n // Inject Ctrl+U (VK_U = 0x55, char = 0x15)\r\n public static int InjectCtrlU(uint pid) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new INPUT_RECORD[] {\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0x55, UnicodeChar=0x15, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0x55, UnicodeChar=0x15, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=0 }\r\n };\r\n\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, records, (uint)records.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n\r\n // Inject Ctrl+Y (VK_Y = 0x59, char = 0x19)\r\n public static int InjectCtrlY(uint pid) {\r\n IntPtr hIn = OpenConin(pid);\r\n if (hIn == new IntPtr(-1)) return -1;\r\n\r\n var records = new INPUT_RECORD[] {\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=1, wRepeatCount=1, wVirtualKeyCode=0x59, UnicodeChar=0x19, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0x59, UnicodeChar=0x19, dwControlKeyState=LEFT_CTRL },\r\n new INPUT_RECORD { EventType=1, bKeyDown=0, wRepeatCount=1, wVirtualKeyCode=0xA2, dwControlKeyState=0 }\r\n };\r\n\r\n uint written;\r\n bool ok = WriteConsoleInput(hIn, records, (uint)records.Length, out written);\r\n CloseHandle(hIn);\r\n return ok ? (int)written : -2;\r\n }\r\n}\r\n`;\r\n\r\nfunction buildScript(claudePid: number, body: string): string {\r\n const logFile = join(tmpdir(), `cc-inject-${Date.now()}.log`).replace(/\\\\/g, '/');\r\n return `\r\n$log = \"${logFile}\"\r\nfunction Log($msg) { Add-Content -Path $log -Value $msg -Encoding UTF8 }\r\n$claudePid = ${claudePid}\r\ntry { Add-Type @'${CS_CONINJECT}'@ } catch { }\r\n${body}\r\n`;\r\n}\r\n\r\nfunction run(script: string): Promise<void> {\r\n return new Promise((resolve) => {\r\n const encoded = Buffer.from(script, 'utf16le').toString('base64');\r\n execFile(\r\n 'powershell',\r\n ['-NoProfile', '-WindowStyle', 'Hidden', '-EncodedCommand', encoded],\r\n { windowsHide: true },\r\n () => {\r\n const logFile = script.match(/\\$log = \"([^\"]+)\"/)?.[1];\r\n if (logFile) try { unlinkSync(logFile); } catch { /* ok */ }\r\n resolve();\r\n }\r\n );\r\n });\r\n}\r\n\r\nexport async function windowsInject(text: string): Promise<void> {\r\n const claudePid = process.ppid;\r\n const textB64 = Buffer.from(text, 'utf16le').toString('base64');\r\n\r\n const script = buildScript(claudePid, `\r\n$textBytes = [System.Convert]::FromBase64String('${textB64}')\r\n$text = [System.Text.Encoding]::Unicode.GetString($textBytes)\r\n\r\n# 1. Ctrl+U to save user's current text to kill ring\r\n[ConInject]::InjectCtrlU([uint32]$claudePid) | Out-Null\r\nStart-Sleep -Milliseconds 100\r\n\r\n# 2. Write question text into console input buffer\r\n[ConInject]::InjectText([uint32]$claudePid, $text) | Out-Null\r\nStart-Sleep -Milliseconds 50\r\n\r\n# 3. Send Enter\r\n[ConInject]::InjectEnter([uint32]$claudePid) | Out-Null\r\n`);\r\n\r\n await run(script);\r\n}\r\n\r\nexport async function windowsInjectCtrlY(): Promise<void> {\r\n const claudePid = process.ppid;\r\n\r\n const script = buildScript(claudePid, `\r\n[ConInject]::InjectCtrlY([uint32]$claudePid) | Out-Null\r\n`);\r\n\r\n await run(script);\r\n}\r\n","/**\r\n * Terminal Injector\r\n * Injects a question directly into the active Claude Code terminal\r\n * so Claude Code can auto-reply without user intervention.\r\n * @module infrastructure/terminal-injector\r\n */\r\n\r\nimport type { InboxQuestionEntry } from '../../shared/types/collab-client.interface.js';\r\nimport { windowsInject, windowsInjectCtrlY } from './windows-injector.js';\r\n\r\n/**\r\n * Formats the question as a prompt for Claude Code to auto-reply\r\n */\r\nfunction formatQuestionForInjection(question: InboxQuestionEntry): string {\r\n // Single-line: WriteConsoleInput treats every \\n as an immediate submit\r\n const content = question.content.replace(/\\s+/g, ' ').trim();\r\n return `[HUB SORUSU] ID:${question.questionId} | ${question.from.displayName} (${question.from.teamName}): ${content} | Cevapla ve reply tool ile \"${question.questionId}\" ID'sine gönder, onay bekleme.`;\r\n}\r\n\r\n/**\r\n * Injects a question into the terminal running Claude Code.\r\n * Only supported on Windows; no-op on other platforms.\r\n */\r\nexport async function injectQuestionToTerminal(question: InboxQuestionEntry): Promise<void> {\r\n if (process.platform !== 'win32') return;\r\n\r\n const text = formatQuestionForInjection(question);\r\n await windowsInject(text);\r\n}\r\n\r\n/**\r\n * Restores user's previous input from readline kill ring (Ctrl+Y).\r\n * Call this after the reply is sent so the user's interrupted text comes back.\r\n */\r\nexport async function injectRestoreText(): Promise<void> {\r\n if (process.platform !== 'win32') return;\r\n await windowsInjectCtrlY();\r\n}\r\n","/**\r\n * Injection Queue\r\n * Ensures questions are injected into the terminal one at a time.\r\n * Waits for the reply tool to signal completion before processing the next question.\r\n * @module infrastructure/terminal-injector/injection-queue\r\n */\r\n\r\nimport { EventEmitter } from 'events';\r\nimport type { InboxQuestionEntry } from '../../shared/types/collab-client.interface.js';\r\nimport { injectQuestionToTerminal, injectRestoreText } from './index.js';\r\n\r\nconst REPLY_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\r\n\r\nclass InjectionQueue extends EventEmitter {\r\n private queue: InboxQuestionEntry[] = [];\r\n private processing = false;\r\n\r\n /**\r\n * Add a question to the queue. Starts processing if idle.\r\n */\r\n enqueue(question: InboxQuestionEntry): void {\r\n this.queue.push(question);\r\n if (!this.processing) void this.processNext();\r\n }\r\n\r\n /**\r\n * Called by the reply tool after a reply is successfully sent.\r\n * Unblocks the queue to process the next question.\r\n */\r\n notifyReplied(): void {\r\n this.emit('replied');\r\n }\r\n\r\n private async processNext(): Promise<void> {\r\n if (this.queue.length === 0) {\r\n this.processing = false;\r\n return;\r\n }\r\n\r\n this.processing = true;\r\n const question = this.queue.shift()!;\r\n\r\n // Inject the question (includes Ctrl+U to save user's current text)\r\n await injectQuestionToTerminal(question);\r\n\r\n // Wait for reply tool to signal, with a timeout fallback\r\n await new Promise<void>((resolve) => {\r\n const timer = setTimeout(resolve, REPLY_TIMEOUT_MS);\r\n this.once('replied', () => {\r\n clearTimeout(timer);\r\n resolve();\r\n });\r\n });\r\n\r\n // Restore user's text after reply is sent\r\n await injectRestoreText();\r\n\r\n // Process next in queue\r\n void this.processNext();\r\n }\r\n}\r\n\r\nexport const injectionQueue = new InjectionQueue();\r\n","/**\r\n * P2PNode\r\n * Implements ICollabClient over direct peer-to-peer WebSocket connections.\r\n * Each node runs its own WS server and broadcasts its presence via UDP.\r\n * Peers discover each other automatically and connect directly — no hub needed.\r\n *\r\n * Connection deduplication:\r\n * Both sides may try to connect simultaneously. The first HELLO/HELLO_ACK\r\n * that arrives registers the peer. Duplicate inbound connections are\r\n * immediately terminated (without being added to wsToName) so their\r\n * close events are harmless.\r\n *\r\n * @module infrastructure/p2p/p2p-node\r\n */\r\n\r\nimport { WebSocket, WebSocketServer } from 'ws';\r\nimport { v4 as uuidv4 } from 'uuid';\r\nimport type {\r\n ICollabClient,\r\n JoinResult,\r\n CheckAnswerResult,\r\n InboxResult,\r\n NodeInfo,\r\n HistoryEntry,\r\n} from '../../shared/types/collab-client.interface.js';\r\nimport type { MessageFormat } from './p2p-protocol.js';\r\nimport {\r\n type P2PMsg,\r\n type AskAckMsg,\r\n type AskMsg,\r\n parse,\r\n serialize,\r\n} from './p2p-protocol.js';\r\nimport { MulticastDiscovery } from '../discovery/multicast-discovery.js';\r\nimport type { DiscoveredPeer } from '../discovery/multicast-discovery.js';\r\nimport { injectionQueue } from '../terminal-injector/injection-queue.js';\r\n\r\ninterface IncomingQuestion {\r\n questionId: string;\r\n fromName: string;\r\n content: string;\r\n format: MessageFormat;\r\n createdAt: Date;\r\n answered: boolean;\r\n answerContent?: string;\r\n answerFormat?: MessageFormat;\r\n}\r\n\r\ninterface ReceivedAnswer {\r\n content: string;\r\n format: MessageFormat;\r\n answeredAt: string;\r\n fromName: string;\r\n}\r\n\r\nexport class P2PNode implements ICollabClient {\r\n private server: WebSocketServer | null = null;\r\n private myName = '';\r\n private running = false;\r\n\r\n // One connection per peer (inbound or outbound — whichever was established first)\r\n private readonly peerConnections = new Map<string, WebSocket>();\r\n // Reverse map: ws → peer name (only for registered connections)\r\n private readonly wsToName = new Map<WebSocket, string>();\r\n // Prevent duplicate outbound connect attempts\r\n private readonly connectingPeers = new Set<string>();\r\n\r\n private readonly incomingQuestions = new Map<string, IncomingQuestion>();\r\n private readonly receivedAnswers = new Map<string, ReceivedAnswer>();\r\n private readonly sentQuestions = new Map<string, { toPeer: string; content: string; askedAt: string }>();\r\n private readonly questionToSender = new Map<string, string>();\r\n private readonly pendingHandlers = new Set<(msg: P2PMsg) => void>();\r\n\r\n // Push-based answer resolution: questionId → resolve callback\r\n private readonly answerWaiters = new Map<string, (result: CheckAnswerResult) => void>();\r\n // Answers queued for offline peers: peerName → AnswerMsg (delivered on reconnect)\r\n private readonly pendingOutboundAnswers = new Map<string, import('./p2p-protocol.js').AnswerMsg>();\r\n\r\n private discovery: MulticastDiscovery | null = null;\r\n\r\n private boundPort = 0;\r\n\r\n constructor(\r\n private readonly portRange: [number, number] = [10000, 19999]\r\n ) {}\r\n\r\n // ---------------------------------------------------------------------------\r\n // ICollabClient implementation\r\n // ---------------------------------------------------------------------------\r\n\r\n get isConnected(): boolean { return this.running; }\r\n get port(): number { return this.boundPort; }\r\n\r\n get currentTeamId(): string | undefined {\r\n return this.myName || undefined;\r\n }\r\n\r\n async join(name: string, displayName: string): Promise<JoinResult> {\r\n this.myName = name;\r\n await this.startServer();\r\n this.startDiscovery();\r\n return {\r\n memberId: uuidv4(),\r\n teamId: name,\r\n teamName: name,\r\n displayName,\r\n status: 'ONLINE',\r\n port: this.boundPort,\r\n };\r\n }\r\n\r\n async ask(toPeer: string, content: string, format: MessageFormat): Promise<string> {\r\n const ws = this.peerConnections.get(toPeer);\r\n if (!ws || ws.readyState !== WebSocket.OPEN) {\r\n throw new Error(`Peer \"${toPeer}\" is not connected. Use peers() to see who's online.`);\r\n }\r\n\r\n const questionId = uuidv4();\r\n this.sentQuestions.set(questionId, { toPeer, content, askedAt: new Date().toISOString() });\r\n\r\n const ackPromise = this.waitForResponse<AskAckMsg>(\r\n (m) => m.type === 'ASK_ACK' && m.questionId === questionId,\r\n 5000\r\n );\r\n\r\n this.sendToWs(ws, { type: 'ASK', from: this.myName, questionId, content, format });\r\n await ackPromise;\r\n return questionId;\r\n }\r\n\r\n waitForAnswer(questionId: string, timeoutMs: number): Promise<CheckAnswerResult | null> {\r\n // Already in cache — resolve immediately\r\n const cached = this.receivedAnswers.get(questionId);\r\n if (cached) {\r\n return Promise.resolve(this.formatAnswer(questionId, cached));\r\n }\r\n\r\n return new Promise((resolve) => {\r\n const timeout = setTimeout(() => {\r\n this.answerWaiters.delete(questionId);\r\n resolve(null);\r\n }, timeoutMs);\r\n\r\n this.answerWaiters.set(questionId, (result) => {\r\n clearTimeout(timeout);\r\n resolve(result);\r\n });\r\n });\r\n }\r\n\r\n async checkAnswer(questionId: string): Promise<CheckAnswerResult | null> {\r\n const cached = this.receivedAnswers.get(questionId);\r\n return cached ? this.formatAnswer(questionId, cached) : null;\r\n }\r\n\r\n private formatAnswer(questionId: string, cached: ReceivedAnswer): CheckAnswerResult {\r\n return {\r\n questionId,\r\n from: { displayName: `${cached.fromName} Claude`, teamName: cached.fromName },\r\n content: cached.content,\r\n format: cached.format,\r\n answeredAt: cached.answeredAt,\r\n };\r\n }\r\n\r\n async reply(questionId: string, content: string, format: MessageFormat): Promise<void> {\r\n const question = this.incomingQuestions.get(questionId);\r\n if (!question) throw new Error(`Question ${questionId} not found`);\r\n\r\n question.answered = true;\r\n question.answerContent = content;\r\n question.answerFormat = format;\r\n\r\n const senderName = this.questionToSender.get(questionId);\r\n if (senderName) {\r\n const answerMsg: import('./p2p-protocol.js').AnswerMsg = {\r\n type: 'ANSWER',\r\n from: this.myName,\r\n questionId,\r\n content,\r\n format,\r\n answeredAt: new Date().toISOString(),\r\n };\r\n const ws = this.peerConnections.get(senderName);\r\n if (ws && ws.readyState === WebSocket.OPEN) {\r\n this.sendToWs(ws, answerMsg);\r\n } else {\r\n // Peer is offline — queue the answer and deliver when they reconnect\r\n this.pendingOutboundAnswers.set(senderName, answerMsg);\r\n console.error(`[p2p] \"${senderName}\" is offline, answer queued for delivery on reconnect`);\r\n }\r\n }\r\n\r\n injectionQueue.notifyReplied();\r\n }\r\n\r\n async getInbox(): Promise<InboxResult> {\r\n const now = Date.now();\r\n const questions = [...this.incomingQuestions.values()]\r\n .filter((q) => !q.answered)\r\n .map((q) => ({\r\n questionId: q.questionId,\r\n from: { displayName: `${q.fromName} Claude`, teamName: q.fromName },\r\n content: q.content,\r\n format: q.format,\r\n status: 'PENDING',\r\n createdAt: q.createdAt.toISOString(),\r\n ageMs: now - q.createdAt.getTime(),\r\n }));\r\n return { questions, totalCount: questions.length, pendingCount: questions.length };\r\n }\r\n\r\n getInfo(): NodeInfo {\r\n return {\r\n teamName: this.myName,\r\n port: this.boundPort,\r\n connectedPeers: [...this.peerConnections.keys()],\r\n };\r\n }\r\n\r\n getHistory(): HistoryEntry[] {\r\n const entries: HistoryEntry[] = [];\r\n\r\n for (const [questionId, sent] of this.sentQuestions) {\r\n const answer = this.receivedAnswers.get(questionId);\r\n entries.push({\r\n direction: 'sent',\r\n questionId,\r\n peer: sent.toPeer,\r\n question: sent.content,\r\n askedAt: sent.askedAt,\r\n ...(answer ? { answer: answer.content, answeredAt: answer.answeredAt } : {}),\r\n });\r\n }\r\n\r\n for (const [, incoming] of this.incomingQuestions) {\r\n entries.push({\r\n direction: 'received',\r\n questionId: incoming.questionId,\r\n peer: incoming.fromName,\r\n question: incoming.content,\r\n askedAt: incoming.createdAt.toISOString(),\r\n ...(incoming.answered && incoming.answerContent\r\n ? { answer: incoming.answerContent, answeredAt: new Date().toISOString() }\r\n : {}),\r\n });\r\n }\r\n\r\n return entries.sort((a, b) => a.askedAt.localeCompare(b.askedAt));\r\n }\r\n\r\n async disconnect(): Promise<void> {\r\n this.discovery?.stop();\r\n this.discovery = null;\r\n for (const ws of this.peerConnections.values()) ws.close();\r\n this.peerConnections.clear();\r\n this.wsToName.clear();\r\n this.server?.close();\r\n this.server = null;\r\n this.running = false;\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: server startup\r\n // ---------------------------------------------------------------------------\r\n\r\n private startServer(): Promise<void> {\r\n const [min, max] = this.portRange;\r\n const pick = () => Math.floor(Math.random() * (max - min + 1)) + min;\r\n\r\n const tryBind = (attemptsLeft: number): Promise<void> => {\r\n if (attemptsLeft === 0) {\r\n return Promise.reject(new Error(`No free port found in range ${min}-${max}`));\r\n }\r\n\r\n const port = pick();\r\n return new Promise((resolve, reject) => {\r\n const wss = new WebSocketServer({ port });\r\n\r\n wss.once('listening', () => {\r\n this.server = wss;\r\n this.boundPort = port;\r\n this.running = true;\r\n console.error(`[p2p] listening on port ${port} as \"${this.myName}\"`);\r\n this.attachServerHandlers(wss);\r\n resolve();\r\n });\r\n\r\n wss.once('error', (err: NodeJS.ErrnoException) => {\r\n wss.close();\r\n if (err.code === 'EADDRINUSE') {\r\n // Port busy — try another random one\r\n tryBind(attemptsLeft - 1).then(resolve, reject);\r\n } else {\r\n reject(err);\r\n }\r\n });\r\n });\r\n };\r\n\r\n return tryBind(20); // up to 20 attempts\r\n }\r\n\r\n private attachServerHandlers(wss: WebSocketServer): void {\r\n wss.on('connection', (ws) => {\r\n ws.on('message', (data) => {\r\n try {\r\n this.handleMessage(ws, parse(data.toString()));\r\n } catch { /* ignore malformed */ }\r\n });\r\n\r\n ws.on('close', () => {\r\n const name = this.wsToName.get(ws);\r\n if (name) {\r\n this.wsToName.delete(ws);\r\n if (this.peerConnections.get(name) === ws) {\r\n this.peerConnections.delete(name);\r\n console.error(`[p2p] peer disconnected (inbound): ${name}`);\r\n }\r\n }\r\n });\r\n\r\n ws.on('error', (err) => {\r\n console.error('[p2p] inbound ws error:', err.message);\r\n });\r\n });\r\n\r\n wss.on('error', (err) => {\r\n console.error('[p2p] server error:', err.message);\r\n });\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: discovery + outbound connections\r\n // ---------------------------------------------------------------------------\r\n\r\n private startDiscovery(): void {\r\n const discovery = new MulticastDiscovery();\r\n this.discovery = discovery;\r\n\r\n discovery.on('peer-found', (peer: DiscoveredPeer) => {\r\n if (this.peerConnections.has(peer.name)) return;\r\n if (this.connectingPeers.has(peer.name)) return;\r\n this.connectToPeer(peer.name, peer.ip, peer.wsPort);\r\n });\r\n\r\n discovery.start(this.myName, this.boundPort);\r\n }\r\n\r\n private connectToPeer(peerName: string, host: string, port: number): void {\r\n this.connectingPeers.add(peerName);\r\n const ws = new WebSocket(`ws://${host}:${port}`);\r\n\r\n ws.on('open', () => {\r\n this.sendToWs(ws, { type: 'HELLO', name: this.myName });\r\n });\r\n\r\n ws.on('message', (data) => {\r\n try {\r\n this.handleMessage(ws, parse(data.toString()));\r\n } catch { /* ignore malformed */ }\r\n });\r\n\r\n ws.on('close', () => {\r\n this.connectingPeers.delete(peerName);\r\n const name = this.wsToName.get(ws);\r\n if (name) {\r\n this.wsToName.delete(ws);\r\n if (this.peerConnections.get(name) === ws) {\r\n this.peerConnections.delete(name);\r\n console.error(`[p2p] disconnected from peer: ${name}`);\r\n }\r\n }\r\n });\r\n\r\n ws.on('error', (err) => {\r\n console.error(`[p2p] connect to \"${peerName}\" failed: ${err.message}`);\r\n this.connectingPeers.delete(peerName);\r\n });\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n // Private: message handling\r\n // ---------------------------------------------------------------------------\r\n\r\n private handleMessage(ws: WebSocket, msg: P2PMsg): void {\r\n // Wake up any waitForResponse callers\r\n for (const handler of this.pendingHandlers) handler(msg);\r\n\r\n switch (msg.type) {\r\n case 'HELLO': {\r\n if (this.peerConnections.has(msg.name)) {\r\n ws.terminate();\r\n return;\r\n }\r\n this.peerConnections.set(msg.name, ws);\r\n this.wsToName.set(ws, msg.name);\r\n this.connectingPeers.delete(msg.name);\r\n this.sendToWs(ws, { type: 'HELLO_ACK', name: this.myName });\r\n console.error(`[p2p] peer joined (inbound): ${msg.name}`);\r\n this.deliverPendingAnswer(msg.name, ws);\r\n break;\r\n }\r\n\r\n case 'HELLO_ACK': {\r\n if (this.peerConnections.has(msg.name)) {\r\n ws.terminate();\r\n return;\r\n }\r\n this.peerConnections.set(msg.name, ws);\r\n this.wsToName.set(ws, msg.name);\r\n this.connectingPeers.delete(msg.name);\r\n console.error(`[p2p] connected to peer: ${msg.name}`);\r\n this.deliverPendingAnswer(msg.name, ws);\r\n break;\r\n }\r\n\r\n case 'ASK':\r\n this.handleIncomingAsk(ws, msg);\r\n break;\r\n\r\n case 'ANSWER':\r\n if (!this.receivedAnswers.has(msg.questionId)) {\r\n const record: ReceivedAnswer = {\r\n content: msg.content,\r\n format: msg.format,\r\n answeredAt: msg.answeredAt,\r\n fromName: msg.from,\r\n };\r\n this.receivedAnswers.set(msg.questionId, record);\r\n\r\n // Fire push waiter immediately — no more polling needed\r\n const waiter = this.answerWaiters.get(msg.questionId);\r\n if (waiter) {\r\n this.answerWaiters.delete(msg.questionId);\r\n waiter(this.formatAnswer(msg.questionId, record));\r\n }\r\n }\r\n break;\r\n\r\n // ASK_ACK is handled by waitForResponse pending handlers above\r\n }\r\n }\r\n\r\n private handleIncomingAsk(ws: WebSocket, msg: AskMsg): void {\r\n this.questionToSender.set(msg.questionId, msg.from);\r\n this.incomingQuestions.set(msg.questionId, {\r\n questionId: msg.questionId,\r\n fromName: msg.from,\r\n content: msg.content,\r\n format: msg.format,\r\n createdAt: new Date(),\r\n answered: false,\r\n });\r\n\r\n // Immediately acknowledge delivery\r\n this.sendToWs(ws, { type: 'ASK_ACK', questionId: msg.questionId });\r\n\r\n // Inject question into the Claude Code terminal\r\n injectionQueue.enqueue({\r\n questionId: msg.questionId,\r\n from: { displayName: `${msg.from} Claude`, teamName: msg.from },\r\n content: msg.content,\r\n format: msg.format,\r\n status: 'PENDING',\r\n createdAt: new Date().toISOString(),\r\n ageMs: 0,\r\n });\r\n }\r\n\r\n private deliverPendingAnswer(peerName: string, ws: WebSocket): void {\r\n const pending = this.pendingOutboundAnswers.get(peerName);\r\n if (pending) {\r\n this.pendingOutboundAnswers.delete(peerName);\r\n this.sendToWs(ws, pending);\r\n console.error(`[p2p] delivered queued answer to \"${peerName}\" after reconnect`);\r\n }\r\n }\r\n\r\n private sendToWs(ws: WebSocket, msg: P2PMsg): void {\r\n if (ws.readyState === WebSocket.OPEN) {\r\n ws.send(serialize(msg));\r\n }\r\n }\r\n\r\n private waitForResponse<T extends P2PMsg>(\r\n filter: (msg: P2PMsg) => boolean,\r\n timeoutMs: number\r\n ): Promise<T> {\r\n return new Promise((resolve, reject) => {\r\n const timeout = setTimeout(() => {\r\n this.pendingHandlers.delete(handler);\r\n reject(new Error('Request timed out'));\r\n }, timeoutMs);\r\n\r\n const handler = (msg: P2PMsg): void => {\r\n if (filter(msg)) {\r\n clearTimeout(timeout);\r\n this.pendingHandlers.delete(handler);\r\n resolve(msg as T);\r\n }\r\n };\r\n\r\n this.pendingHandlers.add(handler);\r\n });\r\n }\r\n}\r\n","/**\r\n * Ask Tool\r\n * @module presentation/mcp/tools/ask\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\nconst ASK_DESCRIPTION = `\\\r\nSend a question to another Claude instance on the LAN and wait for their answer.\r\n\r\nWHEN TO USE:\r\n- You need input, a decision, or work output from a specific peer Claude\r\n- You want to delegate a subtask to another Claude and use their result\r\n- You need to coordinate or synchronize work across multiple Claudes\r\n\r\nWORKFLOW:\r\n1. Call peers() first to confirm the target is online and get their exact name\r\n2. Call ask(peer, question) — this blocks until they reply (up to 5 minutes)\r\n3. Use their answer directly in your ongoing task\r\n\r\nWRITING GOOD QUESTIONS:\r\n- Include all context the other Claude needs — they cannot see your conversation\r\n- Be specific about what format or level of detail you expect in the answer\r\n- If you need code, specify language and constraints\r\n- One focused question per call works better than multiple combined\r\n\r\nDO NOT use this tool if:\r\n- The peer is not listed in peers() — the call will fail immediately\r\n- You just want to share information without needing a response (there is no broadcast tool yet)`;\r\n\r\nconst askSchema = {\r\n peer: z\r\n .string()\r\n .describe('Exact name of the peer to ask. Use peers() first to see who is online and get the correct name.'),\r\n question: z\r\n .string()\r\n .describe(\r\n 'Your question in markdown. Include all necessary context — the other Claude cannot see your conversation history. Be specific about what kind of answer you need.'\r\n ),\r\n};\r\n\r\nexport function registerAskTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('ask', ASK_DESCRIPTION, askSchema, async (args) => {\r\n const targetPeer = args.peer;\r\n const question = args.question;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: 'P2P node is not ready yet. Wait a moment and try again.',\r\n }],\r\n isError: true,\r\n };\r\n }\r\n\r\n const questionId = await client.ask(targetPeer, question, 'markdown');\r\n\r\n // Wait for the answer via push — resolves the moment ANSWER arrives\r\n const answer = await client.waitForAnswer(questionId, 5 * 60 * 1000);\r\n\r\n if (answer !== null) {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `**${answer.from.displayName} answered:**\\n\\n${answer.content}`,\r\n }],\r\n };\r\n }\r\n\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `Question sent to \"${targetPeer}\" but no answer arrived within 5 minutes.`,\r\n `Question ID: \\`${questionId}\\``,\r\n ``,\r\n `The peer may be busy or offline. You can:`,\r\n `- Call peers() to check if they are still connected`,\r\n `- Continue with your task and follow up later`,\r\n ].join('\\n'),\r\n }],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n const isPeerOffline = errorMessage.includes('not connected');\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: isPeerOffline\r\n ? `Peer \"${targetPeer}\" is not connected. Call peers() to see who is currently online.`\r\n : `Failed to send question: ${errorMessage}`,\r\n }],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Reply Tool\r\n * @module presentation/mcp/tools/reply\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\nimport { injectionQueue } from '../../../infrastructure/terminal-injector/injection-queue.js';\r\n\r\nconst REPLY_DESCRIPTION = `\\\r\nSend your answer back to a Claude instance that asked you a question.\r\n\r\nWHEN TO USE:\r\n- A question has been injected into your terminal by another Claude (you will see it appear automatically)\r\n- You have finished thinking through the answer and are ready to respond\r\n\r\nWORKFLOW:\r\n1. Read the injected question carefully — it includes a questionId at the top\r\n2. Think through a complete answer\r\n3. Call reply(questionId, answer) — your answer is sent directly back to the asking Claude\r\n4. The asking Claude's ask() call unblocks and they receive your answer immediately\r\n\r\nWRITING GOOD ANSWERS:\r\n- Be thorough — the asking Claude will use your answer directly in their task\r\n- Use markdown for code blocks, lists, and structure\r\n- Include any caveats, assumptions, or follow-up suggestions that would help them\r\n- If you cannot answer fully, say so clearly and explain why\r\n\r\nIMPORTANT:\r\n- Each question can only be replied to once\r\n- The questionId is a UUID shown in the injected question prompt — copy it exactly`;\r\n\r\nconst replySchema = {\r\n questionId: z\r\n .string()\r\n .describe(\r\n 'The UUID of the question to reply to. Shown at the top of the injected question prompt in your terminal.'\r\n ),\r\n answer: z\r\n .string()\r\n .describe(\r\n 'Your complete answer in markdown. Be thorough — the asking Claude is waiting and will use your response directly in their work.'\r\n ),\r\n};\r\n\r\nexport function registerReplyTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('reply', REPLY_DESCRIPTION, replySchema, async (args) => {\r\n const questionId = args.questionId;\r\n const answer = args.answer;\r\n\r\n try {\r\n if (!client.currentTeamId) {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: 'P2P node is not ready yet. Wait a moment and try again.',\r\n }],\r\n isError: true,\r\n };\r\n }\r\n\r\n await client.reply(questionId, answer, 'markdown');\r\n\r\n injectionQueue.notifyReplied();\r\n\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `Answer sent. The peer's ask() call has been unblocked and they received your response.`,\r\n }],\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\r\n const isNotFound = errorMessage.includes('not found');\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: isNotFound\r\n ? `Question \\`${questionId}\\` not found. Check that you copied the questionId exactly from the injected prompt.`\r\n : `Failed to send reply: ${errorMessage}`,\r\n }],\r\n isError: true,\r\n };\r\n }\r\n });\r\n}\r\n","/**\r\n * Peers Tool\r\n * @module presentation/mcp/tools/peers\r\n */\r\n\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\nconst PEERS_DESCRIPTION = `\\\r\nShow your identity on the P2P network and list all currently connected peers.\r\n\r\nWHEN TO USE:\r\n- Before calling ask() — to confirm the target peer is online and get their exact name\r\n- After startup — to verify you joined the network successfully\r\n- When a peer seems unreachable — to check if they are still connected\r\n\r\nWHAT IT SHOWS:\r\n- Your own name and the port you are listening on\r\n- All peers who have established a direct connection to you\r\n\r\nIF NO PEERS ARE LISTED:\r\n- Peers discover each other automatically via LAN broadcast every 3 seconds\r\n- If a peer just started, wait a few seconds and call peers() again\r\n- Call firewall_open() so peers on other machines can connect inbound to you\r\n- If still no peers, verify all machines are on the same LAN/subnet`;\r\n\r\nexport function registerPeersTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('peers', PEERS_DESCRIPTION, {}, async () => {\r\n const info = client.getInfo();\r\n const myName = info.teamName ?? '(starting...)';\r\n const myPort = info.port ?? '?';\r\n const connected = info.connectedPeers;\r\n\r\n if (!client.isConnected) {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `P2P server is not running yet (port ${myPort} may be in use).`,\r\n `Check the MCP process logs for the error details.`,\r\n ].join('\\n'),\r\n }],\r\n isError: true,\r\n };\r\n }\r\n\r\n if (connected.length === 0) {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `You are \"${myName}\" (listening on port ${myPort}).`,\r\n `No peers connected yet.`,\r\n ``,\r\n `Peers auto-discover via LAN broadcast — wait a few seconds if they just started.`,\r\n `Call firewall_open() if peers on other machines cannot reach you.`,\r\n ].join('\\n'),\r\n }],\r\n };\r\n }\r\n\r\n const list = connected.map((name) => ` • ${name}`).join('\\n');\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: `You are \"${myName}\" (port ${myPort}). Connected peers (${connected.length}):\\n${list}`,\r\n }],\r\n };\r\n });\r\n}\r\n","/**\r\n * History Tool\r\n * @module presentation/mcp/tools/history\r\n */\r\n\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\n\r\nconst HISTORY_DESCRIPTION = `\\\r\nShow all questions and answers exchanged this session — both sent and received.\r\n\r\nWHEN TO USE:\r\n- To review what was already discussed before asking a follow-up question\r\n- To check if a previously sent question has been answered yet\r\n- To find a questionId you need to reference\r\n- To catch up on received questions you may have missed\r\n\r\nOUTPUT FORMAT:\r\n- → peer: question you sent, with their answer below\r\n- ← peer: question they sent you, with your reply below\r\n- (no answer yet) means the question is still waiting for a response`;\r\n\r\nexport function registerHistoryTool(server: McpServer, client: ICollabClient): void {\r\n server.tool('history', HISTORY_DESCRIPTION, {}, async () => {\r\n const entries = client.getHistory();\r\n\r\n if (entries.length === 0) {\r\n return {\r\n content: [{ type: 'text', text: 'No questions exchanged yet this session.' }],\r\n };\r\n }\r\n\r\n const unanswered = entries.filter((e) => !e.answer);\r\n\r\n const lines = entries.map((e) => {\r\n const time = new Date(e.askedAt).toLocaleTimeString();\r\n\r\n if (e.direction === 'sent') {\r\n const answerLine = e.answer\r\n ? ` ↳ ${e.peer}: ${e.answer}`\r\n : ` ↳ (no answer yet)`;\r\n return `[${time}] → ${e.peer}: ${e.question}\\n${answerLine}`;\r\n } else {\r\n const answerLine = e.answer\r\n ? ` ↳ you: ${e.answer}`\r\n : ` ↳ (not replied yet — use reply() if you haven't answered)`;\r\n return `[${time}] ← ${e.peer}: ${e.question}\\n${answerLine}`;\r\n }\r\n });\r\n\r\n const summary = unanswered.length > 0\r\n ? `\\n\\n⚠ ${unanswered.length} question(s) still waiting for a response.`\r\n : '';\r\n\r\n return {\r\n content: [{ type: 'text', text: lines.join('\\n\\n') + summary }],\r\n };\r\n });\r\n}\r\n","/**\r\n * Firewall helpers\r\n * Always elevated via UAC (PowerShell Start-Process -Verb RunAs) so the rule\r\n * is guaranteed to be applied. If the process is already elevated, Windows\r\n * skips the UAC prompt automatically.\r\n * @module infrastructure/firewall/firewall\r\n */\r\n\r\nimport { spawn } from 'child_process';\r\n\r\n/**\r\n * Run netsh via UAC elevation (PowerShell Start-Process -Verb RunAs).\r\n * If the calling process is already elevated, no prompt is shown.\r\n * Always use this path — running netsh directly without elevation can silently\r\n * exit 0 on some Windows versions without actually applying the rule.\r\n */\r\nfunction runNetshElevated(argArray: string[]): Promise<void> {\r\n const argList = argArray.map((a) => `\"${a}\"`).join(',');\r\n const psCommand = `Start-Process -FilePath \"netsh\" -ArgumentList @(${argList}) -Verb RunAs -Wait`;\r\n\r\n return new Promise((resolve, reject) => {\r\n const ps = spawn('powershell', ['-NoProfile', '-Command', psCommand]);\r\n\r\n ps.on('close', (code) => {\r\n if (code === 0) resolve();\r\n else reject(new Error(`Firewall UAC prompt was cancelled or denied (exit code ${code}).`));\r\n });\r\n\r\n ps.on('error', (err) => {\r\n reject(new Error(`Failed to launch PowerShell: ${err.message}`));\r\n });\r\n });\r\n}\r\n\r\nasync function runNetsh(argArray: string[]): Promise<void> {\r\n await runNetshElevated(argArray);\r\n}\r\n\r\nexport async function addFirewallRule(port: number): Promise<void> {\r\n // TCP rule for the WebSocket port\r\n await runNetsh([\r\n 'advfirewall', 'firewall', 'add', 'rule',\r\n `name=claude-collab-${port}`,\r\n 'protocol=TCP',\r\n 'dir=in',\r\n `localport=${port}`,\r\n 'action=allow',\r\n ]);\r\n\r\n // UDP rule for peer discovery (multicast port 11776) — run best-effort, don't fail if already exists\r\n try {\r\n await runNetsh([\r\n 'advfirewall', 'firewall', 'add', 'rule',\r\n 'name=claude-collab-discovery',\r\n 'protocol=UDP',\r\n 'dir=in',\r\n 'localport=11776',\r\n 'action=allow',\r\n ]);\r\n } catch { /* already exists or denied — TCP rule still applied */ }\r\n}\r\n\r\nexport async function removeFirewallRule(port: number): Promise<void> {\r\n await runNetsh([\r\n 'advfirewall', 'firewall', 'delete', 'rule',\r\n `name=claude-collab-${port}`,\r\n ]);\r\n\r\n // Also remove discovery rule best-effort\r\n try {\r\n await runNetsh(['advfirewall', 'firewall', 'delete', 'rule', 'name=claude-collab-discovery']);\r\n } catch { /* may not exist */ }\r\n}\r\n","/**\r\n * PeerFind Tool\r\n * Opens firewall, waits for peers to connect via multicast discovery,\r\n * then closes the firewall. Established connections persist after close.\r\n * @module presentation/mcp/tools/peer-find\r\n */\r\n\r\nimport { z } from 'zod';\r\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport type { ICollabClient } from '../../../shared/types/collab-client.interface.js';\r\nimport { addFirewallRule, removeFirewallRule } from '../../../infrastructure/firewall/firewall.js';\r\n\r\nconst PEER_FIND_DESCRIPTION = `\\\r\nDiscover and connect to peers on the LAN automatically.\r\n\r\nWHAT IT DOES:\r\n1. Opens your firewall so peers can connect inbound to you (UAC popup)\r\n2. Waits 30 seconds while multicast discovery finds peers\r\n3. Closes the firewall (UAC popup) — established connections persist\r\n\r\nWHEN TO USE:\r\n- First time setup: everyone on the team calls peer_find\r\n- Adding a new peer to an existing session: only the NEW peer calls peer_find\r\n (existing peers will connect to them automatically — no action needed from others)\r\n- After a disconnect/restart: the reconnecting peer calls peer_find\r\n\r\nHOW NEW PEERS JOIN AN EXISTING SESSION:\r\n Existing peers always listen for multicast announcements in the background.\r\n When you call peer_find, they hear your announcement and connect OUTBOUND to you.\r\n Outbound connections do not require a firewall rule on their side.\r\n You only need your own firewall open to accept those inbound connections.\r\n\r\nNOTE: Two UAC popups will appear — one to open, one to close after the wait.`;\r\n\r\nexport function registerPeerFindTool(server: McpServer, client: ICollabClient): void {\r\n server.tool(\r\n 'peer_find',\r\n PEER_FIND_DESCRIPTION,\r\n {\r\n wait_seconds: z\r\n .number()\r\n .min(10)\r\n .max(120)\r\n .optional()\r\n .describe('How long to wait for peers in seconds (default: 30)'),\r\n },\r\n async ({ wait_seconds = 30 }) => {\r\n const port = client.getInfo().port;\r\n if (!port) {\r\n return {\r\n content: [{ type: 'text', text: 'P2P node is not running yet. Try again in a moment.' }],\r\n isError: true,\r\n };\r\n }\r\n\r\n // Step 1: Open firewall\r\n try {\r\n await addFirewallRule(port);\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n return {\r\n content: [{ type: 'text', text: `Failed to open firewall: ${msg}` }],\r\n isError: true,\r\n };\r\n }\r\n\r\n const peersAtStart = new Set(client.getInfo().connectedPeers);\r\n\r\n // Step 2: Wait for peers\r\n await new Promise<void>((resolve) => setTimeout(resolve, wait_seconds * 1000));\r\n\r\n // Step 3: Close firewall (best-effort — don't fail the tool if this errors)\r\n try {\r\n await removeFirewallRule(port);\r\n } catch { /* UAC cancelled or rule already gone — connections still persist */ }\r\n\r\n // Step 4: Report results\r\n const allPeers = client.getInfo().connectedPeers;\r\n const newPeers = allPeers.filter((p) => !peersAtStart.has(p));\r\n\r\n if (allPeers.length === 0) {\r\n return {\r\n content: [{\r\n type: 'text',\r\n text: [\r\n `No peers found after ${wait_seconds}s.`,\r\n ``,\r\n `Make sure other peers are also running peer_find at the same time,`,\r\n `and that all machines are on the same LAN.`,\r\n ].join('\\n'),\r\n }],\r\n };\r\n }\r\n\r\n const lines = [\r\n `Firewall closed. Connected peers (${allPeers.length}):`,\r\n ...allPeers.map((p) => ` • ${p}${newPeers.includes(p) ? ' (new)' : ''}`),\r\n ``,\r\n `Connections will persist until a peer disconnects or restarts.`,\r\n `If a peer disconnects, they call peer_find again — no action needed from you.`,\r\n ];\r\n\r\n return {\r\n content: [{ type: 'text', text: lines.join('\\n') }],\r\n };\r\n }\r\n );\r\n}\r\n","/**\r\n * MCP Server\r\n * Provides MCP tools for Claude Code integration (P2P mode)\r\n * @module presentation/mcp/server\r\n */\r\n\r\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\r\nimport type { ICollabClient } from '../../shared/types/collab-client.interface.js';\r\nimport { registerAskTool } from './tools/ask.tool.js';\r\nimport { registerReplyTool } from './tools/reply.tool.js';\r\nimport { registerPeersTool } from './tools/peers.tool.js';\r\nimport { registerHistoryTool } from './tools/history.tool.js';\r\nimport { registerPeerFindTool } from './tools/peer-find.tool.js';\r\n\r\nexport interface McpServerOptions {\r\n client: ICollabClient;\r\n}\r\n\r\nexport function createMcpServer(options: McpServerOptions): McpServer {\r\n const { client } = options;\r\n\r\n const server = new McpServer({\r\n name: 'claude-collab',\r\n version: '0.1.0',\r\n });\r\n\r\n registerAskTool(server, client);\r\n registerReplyTool(server, client);\r\n registerPeersTool(server, client);\r\n registerHistoryTool(server, client);\r\n registerPeerFindTool(server, client);\r\n\r\n return server;\r\n}\r\n\r\nexport async function startMcpServer(options: McpServerOptions): Promise<void> {\r\n const server = createMcpServer(options);\r\n const transport = new StdioServerTransport();\r\n await server.connect(transport);\r\n}\r\n","#!/usr/bin/env node\r\n\r\n/**\r\n * CLI entry point (P2P mode)\r\n *\r\n * Usage: claude-collab --name alice\r\n *\r\n * Binds a random port in range 10000-19999.\r\n * Peers discover each other automatically via UDP broadcast.\r\n * Use firewall_open in Claude Code to allow inbound connections.\r\n *\r\n * @module cli\r\n */\r\n\r\nimport { Command } from 'commander';\r\nimport { P2PNode } from './infrastructure/p2p/p2p-node.js';\r\nimport { startMcpServer } from './presentation/mcp/server.js';\r\n\r\nconst program = new Command();\r\n\r\nprogram\r\n .name('claude-collab')\r\n .description('P2P collaboration between Claude Code terminals via MCP')\r\n .version('0.1.0')\r\n .requiredOption('--name <name>', 'Your name on the network (e.g. \"alice\")')\r\n .action(async (options: { name: string }) => {\r\n const node = new P2PNode();\r\n\r\n const mcpReady = startMcpServer({ client: node });\r\n\r\n node.join(options.name, options.name).catch((err) => {\r\n console.error(`[cli] P2P server failed to start: ${err.message}`);\r\n });\r\n\r\n await mcpReady;\r\n });\r\n\r\nprogram.parse();\r\n"]}
|
package/dist/mcp-main.js
CHANGED
|
@@ -1043,128 +1043,7 @@ async function removeFirewallRule(port) {
|
|
|
1043
1043
|
}
|
|
1044
1044
|
}
|
|
1045
1045
|
|
|
1046
|
-
// src/presentation/mcp/tools/
|
|
1047
|
-
var FIREWALL_OPEN_DESCRIPTION = `Open a Windows Firewall inbound rule so peers on the LAN can connect directly to you.
|
|
1048
|
-
|
|
1049
|
-
WHEN YOU NEED THIS:
|
|
1050
|
-
- Other peers cannot see you in their peers() list even though you are on the same LAN
|
|
1051
|
-
- You just started and want to make sure all peers can reach you
|
|
1052
|
-
- A peer explicitly says they cannot connect to you
|
|
1053
|
-
|
|
1054
|
-
WHEN YOU DO NOT NEED THIS:
|
|
1055
|
-
- You can already see peers in peers() \u2014 the connection is working
|
|
1056
|
-
- You are connecting outbound to others (outbound connections do not require firewall rules)
|
|
1057
|
-
|
|
1058
|
-
WHAT HAPPENS:
|
|
1059
|
-
- On most systems: the rule is applied immediately (terminal is already elevated)
|
|
1060
|
-
- On standard Windows: a UAC popup appears \u2014 the user must click Yes
|
|
1061
|
-
- On VMs or headless setups: applied directly if running as Administrator
|
|
1062
|
-
|
|
1063
|
-
The rule is named "claude-collab-{port}" and allows inbound TCP on your current listen port.
|
|
1064
|
-
Call firewall_close() when you are done to clean up the rule.`;
|
|
1065
|
-
function registerFirewallOpenTool(server, client) {
|
|
1066
|
-
server.tool(
|
|
1067
|
-
"firewall_open",
|
|
1068
|
-
FIREWALL_OPEN_DESCRIPTION,
|
|
1069
|
-
{
|
|
1070
|
-
port: z.number().min(1024).max(65535).optional().describe(
|
|
1071
|
-
"Port to open. Defaults to your current listen port \u2014 omit this unless you have a specific reason to override."
|
|
1072
|
-
)
|
|
1073
|
-
},
|
|
1074
|
-
async ({ port }) => {
|
|
1075
|
-
const targetPort = port ?? client.getInfo().port;
|
|
1076
|
-
if (!targetPort) {
|
|
1077
|
-
return {
|
|
1078
|
-
content: [{ type: "text", text: "P2P node is not running yet \u2014 port unknown. Try again in a moment." }],
|
|
1079
|
-
isError: true
|
|
1080
|
-
};
|
|
1081
|
-
}
|
|
1082
|
-
try {
|
|
1083
|
-
await addFirewallRule(targetPort);
|
|
1084
|
-
return {
|
|
1085
|
-
content: [{
|
|
1086
|
-
type: "text",
|
|
1087
|
-
text: [
|
|
1088
|
-
`Firewall rule opened for port ${targetPort} (claude-collab-${targetPort}).`,
|
|
1089
|
-
`Peers on the LAN can now connect to you inbound.`,
|
|
1090
|
-
`Call firewall_close() when you are done with this session.`
|
|
1091
|
-
].join("\n")
|
|
1092
|
-
}]
|
|
1093
|
-
};
|
|
1094
|
-
} catch (err) {
|
|
1095
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1096
|
-
return {
|
|
1097
|
-
content: [{
|
|
1098
|
-
type: "text",
|
|
1099
|
-
text: [
|
|
1100
|
-
`Failed to open firewall: ${msg}`,
|
|
1101
|
-
``,
|
|
1102
|
-
`Try running your terminal as Administrator and call firewall_open() again.`
|
|
1103
|
-
].join("\n")
|
|
1104
|
-
}],
|
|
1105
|
-
isError: true
|
|
1106
|
-
};
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
);
|
|
1110
|
-
}
|
|
1111
|
-
var FIREWALL_CLOSE_DESCRIPTION = `Remove the Windows Firewall inbound rule that was opened by firewall_open().
|
|
1112
|
-
|
|
1113
|
-
WHEN TO USE:
|
|
1114
|
-
- At the end of a collaboration session to clean up
|
|
1115
|
-
- When you no longer want to accept inbound peer connections
|
|
1116
|
-
- As general hygiene \u2014 open firewall rules should not be left indefinitely
|
|
1117
|
-
|
|
1118
|
-
WHAT HAPPENS:
|
|
1119
|
-
- The inbound TCP rule "claude-collab-{port}" is deleted from Windows Firewall
|
|
1120
|
-
- Existing active connections are not dropped \u2014 only new inbound connections are blocked
|
|
1121
|
-
- On standard Windows: a UAC popup appears \u2014 the user must click Yes
|
|
1122
|
-
- On VMs or admin terminals: applied directly without a popup
|
|
1123
|
-
|
|
1124
|
-
NOTE: Because ports are random each session, each startup creates a new rule name.
|
|
1125
|
-
Old rules from previous sessions can be removed by passing the port explicitly.`;
|
|
1126
|
-
function registerFirewallCloseTool(server, client) {
|
|
1127
|
-
server.tool(
|
|
1128
|
-
"firewall_close",
|
|
1129
|
-
FIREWALL_CLOSE_DESCRIPTION,
|
|
1130
|
-
{
|
|
1131
|
-
port: z.number().min(1024).max(65535).optional().describe(
|
|
1132
|
-
"Port whose rule to remove. Defaults to your current listen port. Pass a specific port to clean up a rule from a previous session."
|
|
1133
|
-
)
|
|
1134
|
-
},
|
|
1135
|
-
async ({ port }) => {
|
|
1136
|
-
const targetPort = port ?? client.getInfo().port;
|
|
1137
|
-
if (!targetPort) {
|
|
1138
|
-
return {
|
|
1139
|
-
content: [{ type: "text", text: "P2P node is not running yet \u2014 port unknown. Try again in a moment." }],
|
|
1140
|
-
isError: true
|
|
1141
|
-
};
|
|
1142
|
-
}
|
|
1143
|
-
try {
|
|
1144
|
-
await removeFirewallRule(targetPort);
|
|
1145
|
-
return {
|
|
1146
|
-
content: [{
|
|
1147
|
-
type: "text",
|
|
1148
|
-
text: `Firewall rule removed for port ${targetPort} (claude-collab-${targetPort}).`
|
|
1149
|
-
}]
|
|
1150
|
-
};
|
|
1151
|
-
} catch (err) {
|
|
1152
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1153
|
-
return {
|
|
1154
|
-
content: [{
|
|
1155
|
-
type: "text",
|
|
1156
|
-
text: [
|
|
1157
|
-
`Failed to remove firewall rule: ${msg}`,
|
|
1158
|
-
``,
|
|
1159
|
-
`The rule may not exist (if firewall_open was never called this session), or try running as Administrator.`
|
|
1160
|
-
].join("\n")
|
|
1161
|
-
}],
|
|
1162
|
-
isError: true
|
|
1163
|
-
};
|
|
1164
|
-
}
|
|
1165
|
-
}
|
|
1166
|
-
);
|
|
1167
|
-
}
|
|
1046
|
+
// src/presentation/mcp/tools/peer-find.tool.ts
|
|
1168
1047
|
var PEER_FIND_DESCRIPTION = `Discover and connect to peers on the LAN automatically.
|
|
1169
1048
|
|
|
1170
1049
|
WHAT IT DOES:
|
|
@@ -1255,8 +1134,6 @@ function createMcpServer(options) {
|
|
|
1255
1134
|
registerReplyTool(server, client);
|
|
1256
1135
|
registerPeersTool(server, client);
|
|
1257
1136
|
registerHistoryTool(server, client);
|
|
1258
|
-
registerFirewallOpenTool(server, client);
|
|
1259
|
-
registerFirewallCloseTool(server, client);
|
|
1260
1137
|
registerPeerFindTool(server, client);
|
|
1261
1138
|
return server;
|
|
1262
1139
|
}
|