obsbot-mcp 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +197 -38
  2. package/dist/codec/commands.d.ts +42 -4
  3. package/dist/codec/commands.js +72 -10
  4. package/dist/codec/commands.js.map +1 -1
  5. package/dist/codec/frame.d.ts +1 -0
  6. package/dist/codec/frame.js +1 -1
  7. package/dist/codec/frame.js.map +1 -1
  8. package/dist/codec/preset.d.ts +40 -0
  9. package/dist/codec/preset.js +198 -0
  10. package/dist/codec/preset.js.map +1 -0
  11. package/dist/codec/types.d.ts +4 -0
  12. package/dist/device/helper-factory.d.ts +25 -0
  13. package/dist/device/helper-factory.js +40 -0
  14. package/dist/device/helper-factory.js.map +1 -0
  15. package/dist/device/manager.d.ts +326 -2
  16. package/dist/device/manager.js +720 -24
  17. package/dist/device/manager.js.map +1 -1
  18. package/dist/ipc/client.d.ts +19 -0
  19. package/dist/ipc/client.js +81 -0
  20. package/dist/ipc/client.js.map +1 -0
  21. package/dist/ipc/coordinator.d.ts +29 -0
  22. package/dist/ipc/coordinator.js +94 -0
  23. package/dist/ipc/coordinator.js.map +1 -0
  24. package/dist/ipc/owner.d.ts +21 -0
  25. package/dist/ipc/owner.js +59 -0
  26. package/dist/ipc/owner.js.map +1 -0
  27. package/dist/ipc/protocol.d.ts +21 -0
  28. package/dist/ipc/protocol.js +56 -0
  29. package/dist/ipc/protocol.js.map +1 -0
  30. package/dist/ipc/rendezvous.d.ts +26 -0
  31. package/dist/ipc/rendezvous.js +93 -0
  32. package/dist/ipc/rendezvous.js.map +1 -0
  33. package/dist/mcp/log-sink.d.ts +12 -0
  34. package/dist/mcp/log-sink.js +27 -0
  35. package/dist/mcp/log-sink.js.map +1 -0
  36. package/dist/mcp/ready.d.ts +16 -4
  37. package/dist/mcp/ready.js +11 -8
  38. package/dist/mcp/ready.js.map +1 -1
  39. package/dist/mcp/render.js +1 -1
  40. package/dist/mcp/render.js.map +1 -1
  41. package/dist/mcp/server.js +68 -18
  42. package/dist/mcp/server.js.map +1 -1
  43. package/dist/mcp/tools.d.ts +5 -3
  44. package/dist/mcp/tools.js +787 -186
  45. package/dist/mcp/tools.js.map +1 -1
  46. package/dist/transport/helper-process.d.ts +36 -0
  47. package/dist/transport/helper-process.js +190 -10
  48. package/dist/transport/helper-process.js.map +1 -1
  49. package/dist/transport/linux.d.ts +40 -0
  50. package/dist/transport/linux.js +92 -2
  51. package/dist/transport/linux.js.map +1 -1
  52. package/dist/transport/macos.d.ts +13 -0
  53. package/dist/transport/macos.js +59 -3
  54. package/dist/transport/macos.js.map +1 -1
  55. package/dist/transport/read-serial.d.ts +26 -0
  56. package/dist/transport/read-serial.js +87 -0
  57. package/dist/transport/read-serial.js.map +1 -0
  58. package/dist/transport/transport.d.ts +24 -0
  59. package/dist/transport/windows.d.ts +4 -0
  60. package/dist/transport/windows.js +31 -4
  61. package/dist/transport/windows.js.map +1 -1
  62. package/native/prebuilt/darwin-arm64/obsbot-helper +0 -0
  63. package/native/prebuilt/darwin-x64/obsbot-helper +0 -0
  64. package/native/prebuilt/linux-x64/obsbot-helper +0 -0
  65. package/native/prebuilt/win32-x64/obsbot-helper.exe +0 -0
  66. package/package.json +3 -2
  67. package/dist/device/session.d.ts +0 -22
  68. package/dist/device/session.js +0 -37
  69. package/dist/device/session.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/device/manager.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,MAAM,OAAO,aAAa;IACJ;IAApB,YAAoB,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAErC,eAAe;QACrB,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YACjC,OAAO,IAAI,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzC,CAAC;QACD,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAClC,OAAO,IAAI,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzC,CAAC;QACD,OAAO,IAAI,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,IAAI;QACR,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,eAAe;QACnB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAClC,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACpE,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAC5C,CAAC;QACD,qEAAqE;QACrE,0EAA0E;QAC1E,+DAA+D;QAC/D,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,KAAK,MAAM,MAAM,IAAI,aAAa,EAAE,CAAC;YACnC,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBACnD,IAAI,MAAM,IAAI,CAAC;oBAAE,OAAO,IAAI,CAAC,eAAe,EAAE,CAAC;gBAC/C,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,cAAc,CAAC,CAAC;YAC5C,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,KAAM,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;YACzD,CAAC;QACH,CAAC;QACD,MAAM,IAAI,KAAK,CACb,wCAAwC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAC9D,CAAC;IACJ,CAAC;CACF"}
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/device/manager.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,iFAAiF;AACjF,8EAA8E;AAC9E,gFAAgF;AAChF,4EAA4E;AAC5E,6EAA6E;AAC7E,MAAM,QAAQ,GAAG,MAAM,CAAC;AACxB,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAsB;IACrD,CAAC,QAAQ,EAAE,IAAI,GAAG,CAAS,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;CACnD,CAAC,CAAC;AAEH,iFAAiF;AACjF,0EAA0E;AAC1E,4EAA4E;AAC5E,yEAAyE;AACzE,2EAA2E;AAC3E,oCAAoC;AACpC,MAAM,cAAc,GAAG,SAAS,CAAC;AAEjC,kEAAkE;AAClE,MAAM,OAAO,GAAG,CAAC,CAAU,EAAU,EAAE,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAErF;;;;;;GAMG;AACH,SAAS,cAAc,CAAC,CAAa;IACnC,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;QAAE,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACrE,IAAI,CAAC,CAAC,GAAG,KAAK,SAAS,IAAI,CAAC,CAAC,GAAG,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAC7D,OAAO,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC;AAC3D,CAAC;AAED,8EAA8E;AAC9E,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IACpC,SAAS,CAAW;IAC7B,YAAY,SAAmB;QAC7B,KAAK,CAAC,8CAA8C,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5E,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACnC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;CACF;AAED,+EAA+E;AAC/E,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAClC,SAAS,CAAW;IAC7B,YAAY,MAAc,EAAE,SAAmB;QAC7C,KAAK,CACH,mBAAmB,MAAM,iBAAiB,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAC/F,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;CACF;AAoCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,OAAO,aAAa;IAqEd;IApEF,QAAQ,GAAG,IAAI,GAAG,EAAyB,CAAC;IACpD,4EAA4E;IACpE,UAAU,CAAiB;IACnC;;;OAGG;IACK,OAAO,CAAiB;IAChC;;;;;;;;;OASG;IACK,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,kBAAkB,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/C;;;;;;;;;;;;;;;OAeG;IACH,iFAAiF;IACzE,SAAS,GAAG,KAAK,CAAC;IAE1B;;;;;;;;;;;;;OAaG;IACK,gBAAgB,CAAW;IAEnC;;;;;;;;OAQG;IACK,GAAG,CAAwB;IAEnC,YACU,UAAwC,EAChD,OAAqE,EAAE;QAD/D,eAAU,GAAV,UAAU,CAA8B;QAGhD,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QACtE,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,EAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,CAAC;IAEO,eAAe,CAAC,MAAqB;QAC3C,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YACjC,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;QACpC,CAAC;QACD,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAClC,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;QACpC,CAAC;QACD,OAAO,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAED;;;;;OAKG;IACK,KAAK,CAAC,iBAAiB;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC;QAC/B,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC5B,IAAI,CAAC,MAAM;YAAE,OAAO;QACpB,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;QAAC,MAAM,CAAC;YACP,iEAAiE;QACnE,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6DG;IACK,KAAK,CAAC,aAAa;QACzB,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO,CAAC,8BAA8B;QACrE,IAAI,CAAC;YACH,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM;gBAAE,IAAI,CAAC,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;YACjF,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,6CAA6C;QAC/E,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,0EAA0E;YAC1E,wEAAwE;YACxE,0EAA0E;YAC1E,uEAAuE;YACvE,yEAAyE;YACzE,EAAE;YACF,iEAAiE;YACjE,uEAAuE;YACvE,qEAAqE;YACrE,kEAAkE;YAClE,IAAI,CAAC,GAAG,CACN,wCAAwC,OAAO,CAAC,CAAC,CAAC,KAAK;gBACrD,kDAAkD,CACrD,CAAC;QACJ,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,aAAa;QACzB,qEAAqE;QACrE,0EAA0E;QAC1E,oEAAoE;QACpE,2EAA2E;QAC3E,4EAA4E;QAC5E,IAAI,IAAI,CAAC,UAAU,EAAE,MAAM;YAAE,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QACzD,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACrB,IAAI,CAAC,UAAU,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QAC5C,CAAC;QACD,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,IAAI;QACR,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAC1C,OAAO,MAAM,CAAC,SAAS,EAAE,CAAC;IAC5B,CAAC;IAED;;;;;;;;;;;OAWG;IACK,KAAK,CAAC,IAAI,CAAC,UAAmB;QACpC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAC1C,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC;QACzC,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QAElD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAiD,CAAC;QACvE,IAAI,OAA8B,CAAC;QACnC,yEAAyE;QACzE,wEAAwE;QACxE,2EAA2E;QAC3E,4EAA4E;QAC5E,uDAAuD;QACvD,MAAM,QAAQ,GAAa,EAAE,CAAC;QAE9B,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;YAC3B,IAAI,MAAc,CAAC;YACnB,IAAI,CAAC;gBACH,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACrC,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,+DAA+D;gBAC/D,4DAA4D;gBAC5D,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,kBAAkB,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBACvD,SAAS;YACX,CAAC;YACD,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;gBACf,mEAAmE;gBACnE,qDAAqD;gBACrD,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,6BAA6B,CAAC,CAAC;gBACtD,SAAS;YACX,CAAC;YAED,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;YAC/C,IAAI,MAAc,CAAC;YACnB,IAAI,CAAC;gBACH,MAAM,GAAG,MAAM,SAAS,CAAC,UAAU,EAAE,CAAC;YACxC,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC1C,SAAS;YACX,CAAC;YAED,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;gBAAE,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACtF,OAAO,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YACtF,IAAI,UAAU,IAAI,MAAM,KAAK,UAAU;gBAAE,MAAM;QACjD,CAAC;QAED,IAAI,UAAU,EAAE,CAAC;YACf,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;gBAC7C,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;gBACtB,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;gBAC3B,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;YAClE,CAAC;YACD,MAAM,IAAI,kBAAkB,CAAC,UAAU,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC9D,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACrB,sEAAsE;YACtE,qDAAqD;YACrD,EAAE;YACF,oEAAoE;YACpE,wEAAwE;YACxE,yEAAyE;YACzE,yEAAyE;YACzE,uEAAuE;YACvE,wEAAwE;YACxE,sCAAsC;YACtC,EAAE;YACF,kEAAkE;YAClE,EAAE;YACF,yEAAyE;YACzE,uEAAuE;YACvE,yEAAyE;YACzE,oEAAoE;YACpE,yEAAyE;YACzE,mEAAmE;YACnE,kEAAkE;YAClE,uEAAuE;YACvE,wEAAwE;YACxE,sCAAsC;YACtC,EAAE;YACF,qEAAqE;YACrE,sDAAsD;YACtD,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC/B,wEAAwE;YACxE,wEAAwE;YACxE,uEAAuE;YACvE,wEAAwE;YACxE,wEAAwE;YACxE,6CAA6C;YAC7C,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;YAC3B,qEAAqE;YACrE,2BAA2B;YAC3B,MAAM,IAAI,KAAK,CACb,QAAQ,CAAC,MAAM,KAAK,CAAC;gBACnB,CAAC,CAAC,wBAAwB;gBAC1B,CAAC,CAAC,4BAA4B,QAAQ,CAAC,MAAM,2BAA2B,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAChG,CAAC;QACJ,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YACnB,MAAM,IAAI,oBAAoB,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACpD,CAAC;QACD,mEAAmE;QACnE,uDAAuD;QACvD,IAAI,CAAC,OAAO,CAAC,OAAQ,CAAC,CAAC;QACvB,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAC3B,OAAO,EAAE,SAAS,EAAE,OAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,OAAQ,CAAC,MAAM,EAAE,CAAC;IACpE,CAAC;IAED,0EAA0E;IAClE,OAAO,CAAC,CAAY;QAC1B,uEAAuE;QACvE,2EAA2E;QAC3E,qEAAqE;QACrE,2EAA2E;QAC3E,wEAAwE;QACxE,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;YAAE,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACxE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAE7B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE;YAC1B,MAAM,EAAE,IAAI,CAAC,UAAW;YACxB,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,IAAI,EAAE,CAAC,CAAC,IAAI;SACb,CAAC,CAAC;QACH,qEAAqE;QACrE,wCAAwC;QACxC,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;IAC9B,CAAC;IAED;;;;;;;OAOG;IACH,eAAe,CAAC,MAAe;QAC7B,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,CAAC,GAAG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC9C,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACvC,OAAO,CAAC,CAAC;QACX,CAAC;QACD,IAAI,IAAI,CAAC,kBAAkB,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QACrD,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,UAAU,CAAC,MAAe;QAC9B,MAAM,IAAI,GAAG,KAAK,EAAE,CAAS,EAAE,KAAoB,EAAiB,EAAE;YACpE,IAAI,CAAC;gBACH,MAAM,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAC7B,CAAC;YAAC,MAAM,CAAC;gBACP,sEAAsE;YACxE,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC1B,CAAC,CAAC;QAEF,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACxC,IAAI,KAAK;gBAAE,MAAM,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YACrC,OAAO;QACT,CAAC;QACD,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAC5E,CAAC;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACK,KAAK,CAAC,gBAAgB;QAC5B,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC5C,yEAAyE;YACzE,gEAAgE;YAChE,uEAAuE;YACvE,oEAAoE;YACpE,qEAAqE;YACrE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU;gBAAE,SAAS;YAE/D,sEAAsE;YACtE,0EAA0E;YAC1E,0EAA0E;YAC1E,yEAAyE;YACzE,mEAAmE;YACnE,qEAAqE;YACrE,uEAAuE;YACvE,IAAI,CAAC;gBACH,MAAM,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAC7B,CAAC;YAAC,MAAM,CAAC;gBACP,iEAAiE;YACnE,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,GAAG,CAAC,MAAe;QACvB,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAE9B,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC3C,IAAI,QAAQ;gBAAE,OAAO,QAAQ,CAAC,SAAS,CAAC;YACxC,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC9C,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAE,CAAC,SAAS,CAAC;QACnD,CAAC;QACD,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,oBAAoB,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC5D,CAAC;QACD,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QACxC,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,oBAAoB,CAAC,CAAmB;QAC5C,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC5C,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI;gBAAE,SAAS;YACpC,IAAI,CAAC;gBACH,MAAM,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAC7B,CAAC;YAAC,MAAM,CAAC;gBACP,iEAAiE;YACnE,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC/B,CAAC;QACD,6EAA6E;QAC7E,6EAA6E;QAC7E,0EAA0E;QAC1E,2EAA2E;QAC3E,qBAAqB;QACrB,EAAE;QACF,uEAAuE;QACvE,0EAA0E;QAC1E,wEAAwE;QACxE,qDAAqD;QACrD,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;IAC7B,CAAC;IAED;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,mBAAmB,CAAC,EAAoB;QAC5C,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO,CAAC,8BAA8B;QACrE,8DAA8D;QAC9D,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC;YAAE,OAAO;QACnC,wEAAwE;QACxE,yEAAyE;QACzE,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO;QAE3B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC;QAC3C,IAAI,CAAC;YACH,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAE,CAAC;gBACxC,IAAI,KAAK,GAAG,CAAC;oBAAE,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;gBAC9D,sEAAsE;gBACtE,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC;oBAAE,OAAO;gBACnC,IAAI,CAAC;oBACH,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;oBAClB,kEAAkE;oBAClE,mEAAmE;oBACnE,0CAA0C;oBAC1C,IAAI,CAAC,GAAG,CAAC;wBAAE,IAAI,CAAC,GAAG,CAAC,oDAAoD,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBACjF,OAAO;gBACT,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,oEAAoE;oBACpE,qEAAqE;oBACrE,qCAAqC;oBACrC,IAAI,CAAC,GAAG,CACN,uCAAuC,CAAC,GAAG,CAAC,IAAI,KAAK,YAAY,OAAO,CAAC,CAAC,CAAC,EAAE,CAC9E,CAAC;gBACJ,CAAC;YACH,CAAC;YACD,IAAI,CAAC,GAAG,CACN,6CAA6C,KAAK,aAAa;gBAC7D,uCAAuC,CAC1C,CAAC;QACJ,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;QACzB,CAAC;IACH,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,QAAQ;QACZ,MAAM,KAAK,GAAG,KAAK,EAAE,CAA4B,EAAiB,EAAE;YAClE,IAAI,CAAC,CAAC;gBAAE,OAAO;YACf,IAAI,CAAC;gBACH,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC;YAClB,CAAC;YAAC,MAAM,CAAC;gBACP,iEAAiE;YACnE,CAAC;QACH,CAAC,CAAC;QACF,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;QACzB,MAAM,OAAO,CAAC,GAAG,CAAC;YAChB,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YAC1D,IAAI,CAAC,iBAAiB,EAAE;YACxB,KAAK,CAAC,OAAO,CAAC;SACf,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;IAED,wDAAwD;IACxD,KAAK,CAAC,eAAe;QACnB,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC;IACpB,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,WAAW;QACf,yEAAyE;QACzE,oEAAoE;QACpE,2EAA2E;QAC3E,0EAA0E;QAC1E,sDAAsD;QACtD,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAiB,EAAE,CAAC;QACjC,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU,CAAC;QACtC,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAU,CAAC;QAC3C,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;QACrC,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC5C,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;YAC1F,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACxB,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;gBAAE,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YAC3E,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7B,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAC1C,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC;QACzC,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QAElD,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;YAC3B,mEAAmE;YACnE,mEAAmE;YACnE,kEAAkE;YAClE,oEAAoE;YACpE,gEAAgE;YAChE,kDAAkD;YAClD,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC3B,SAAS,CAAC,kCAAkC;YAC9C,CAAC;YACD,IAAI,CAAC,CAAC,UAAU,KAAK,SAAS,IAAI,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC;gBACrE,SAAS,CAAC,kCAAkC;YAC9C,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;gBACzC,IAAI,MAAM,GAAG,CAAC;oBAAE,SAAS;gBACzB,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;gBAC/C,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,UAAU,EAAE,CAAC;gBAC5C,IAAI,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC;oBAAE,SAAS,CAAC,6CAA6C;gBACpF,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBACxB,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;YACxF,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,OAAO,CAAC,IAAI,CAAC;oBACX,UAAU,EAAE,CAAC,CAAC,UAAU;oBACxB,IAAI,EAAE,CAAC,CAAC,IAAI;oBACZ,MAAM,EAAE,MAAM;oBACd,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;iBACnB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;CACF"}
@@ -0,0 +1,19 @@
1
+ import net from "node:net";
2
+ export declare class OwnerClient {
3
+ private readonly socket;
4
+ private nextId;
5
+ private readonly pending;
6
+ private readonly dec;
7
+ private closedErr?;
8
+ private constructor();
9
+ /** Wrap an already-connected socket (e.g. the one elect() returned). */
10
+ static adopt(socket: net.Socket): OwnerClient;
11
+ static connect(path: string): Promise<OwnerClient>;
12
+ /** Forward a request to the owner; resolve with its result or throw its error. */
13
+ request(body: unknown): Promise<unknown>;
14
+ get closed(): boolean;
15
+ close(): void;
16
+ private send;
17
+ private onData;
18
+ private failAll;
19
+ }
@@ -0,0 +1,81 @@
1
+ import net from "node:net";
2
+ import { encodeFrame, FrameDecoder } from "./protocol.js";
3
+ export class OwnerClient {
4
+ socket;
5
+ nextId = 1;
6
+ pending = new Map();
7
+ dec = new FrameDecoder();
8
+ closedErr;
9
+ constructor(socket) {
10
+ this.socket = socket;
11
+ this.socket.on("data", (chunk) => this.onData(chunk));
12
+ this.socket.on("close", () => this.failAll(new Error("owner connection closed")));
13
+ this.socket.on("error", (e) => this.failAll(e));
14
+ }
15
+ /** Wrap an already-connected socket (e.g. the one elect() returned). */
16
+ static adopt(socket) {
17
+ return new OwnerClient(socket);
18
+ }
19
+ static connect(path) {
20
+ return new Promise((resolve, reject) => {
21
+ const socket = net.connect(path);
22
+ const onError = (e) => reject(e);
23
+ socket.once("error", onError);
24
+ socket.once("connect", () => {
25
+ socket.removeListener("error", onError);
26
+ resolve(new OwnerClient(socket));
27
+ });
28
+ });
29
+ }
30
+ /** Forward a request to the owner; resolve with its result or throw its error. */
31
+ async request(body) {
32
+ const reply = await this.send(body);
33
+ if (reply.ok)
34
+ return reply.result;
35
+ throw new Error(reply.error);
36
+ }
37
+ get closed() {
38
+ return this.closedErr !== undefined;
39
+ }
40
+ close() {
41
+ this.socket.destroy();
42
+ this.failAll(new Error("owner connection closed by client"));
43
+ }
44
+ send(body) {
45
+ if (this.closedErr)
46
+ return Promise.reject(this.closedErr);
47
+ const id = this.nextId++;
48
+ return new Promise((resolve, reject) => {
49
+ this.pending.set(id, { resolve, reject });
50
+ this.socket.write(encodeFrame({ id, body }));
51
+ });
52
+ }
53
+ onData(chunk) {
54
+ let msgs;
55
+ try {
56
+ msgs = this.dec.push(chunk);
57
+ }
58
+ catch (e) {
59
+ this.failAll(e instanceof Error ? e : new Error(String(e)));
60
+ this.socket.destroy();
61
+ return;
62
+ }
63
+ for (const m of msgs) {
64
+ const w = this.pending.get(m.id);
65
+ if (w) {
66
+ this.pending.delete(m.id);
67
+ w.resolve(m.body);
68
+ }
69
+ // Unknown id (late reply after timeout, or a duplicate) → ignore.
70
+ }
71
+ }
72
+ failAll(err) {
73
+ if (this.closedErr)
74
+ return; // already failed; keep the first cause
75
+ this.closedErr = err;
76
+ for (const w of this.pending.values())
77
+ w.reject(err);
78
+ this.pending.clear();
79
+ }
80
+ }
81
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/ipc/client.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,YAAY,EAAc,MAAM,eAAe,CAAC;AAmBtE,MAAM,OAAO,WAAW;IAMe;IAL7B,MAAM,GAAG,CAAC,CAAC;IACF,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IACpC,GAAG,GAAG,IAAI,YAAY,EAAE,CAAC;IAClC,SAAS,CAAS;IAE1B,YAAqC,MAAkB;QAAlB,WAAM,GAAN,MAAM,CAAY;QACrD,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9D,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC;QAClF,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,CAAC;IAED,wEAAwE;IACxE,MAAM,CAAC,KAAK,CAAC,MAAkB;QAC7B,OAAO,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,IAAY;QACzB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACjC,MAAM,OAAO,GAAG,CAAC,CAAU,EAAQ,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAChD,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE;gBAC1B,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBACxC,OAAO,CAAC,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;YACnC,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,kFAAkF;IAClF,KAAK,CAAC,OAAO,CAAC,IAAa;QACzB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,KAAK,CAAC,EAAE;YAAE,OAAO,KAAK,CAAC,MAAM,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,SAAS,KAAK,SAAS,CAAC;IACtC,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACtB,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC,CAAC;IAC/D,CAAC;IAEO,IAAI,CAAC,IAAa;QACxB,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC1D,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACzB,OAAO,IAAI,OAAO,CAAY,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAChD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;YAC1C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,MAAM,CAAC,KAAa;QAC1B,IAAI,IAAkB,CAAC;QACvB,IAAI,CAAC;YACH,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,OAAO,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5D,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACtB,OAAO;QACT,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACjC,IAAI,CAAC,EAAE,CAAC;gBACN,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC1B,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAiB,CAAC,CAAC;YACjC,CAAC;YACD,kEAAkE;QACpE,CAAC;IACH,CAAC;IAEO,OAAO,CAAC,GAAU;QACxB,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO,CAAC,uCAAuC;QACnE,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC;QACrB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE;YAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACrD,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;CACF"}
@@ -0,0 +1,29 @@
1
+ export type RunLocal = (tool: string, args: Record<string, unknown>) => Promise<unknown>;
2
+ /**
3
+ * Wrap a tool runner so calls execute strictly one-at-a-time. This is THE
4
+ * single-camera lock: it must guard both the owner's own MCP calls AND the
5
+ * calls forwarded from clients, because the owner's local path does not pass
6
+ * through OwnerServer's queue. Errors don't break the chain.
7
+ */
8
+ export declare function serialize(fn: RunLocal): RunLocal;
9
+ type RoleName = "none" | "owner" | "client";
10
+ export declare class Coordinator {
11
+ private readonly runLocal;
12
+ private readonly path;
13
+ private role;
14
+ private client?;
15
+ private ownerServer?;
16
+ private electing?;
17
+ /** `runLocal` should already be serialize()-wrapped by the caller. */
18
+ constructor(runLocal: RunLocal, path?: string);
19
+ /** Establish the initial role eagerly at startup. */
20
+ start(): Promise<void>;
21
+ get roleName(): RoleName;
22
+ dispatch(tool: string, args: Record<string, unknown>): Promise<unknown>;
23
+ private runByRole;
24
+ close(): Promise<void>;
25
+ private reset;
26
+ private ensureRole;
27
+ private doElect;
28
+ }
29
+ export {};
@@ -0,0 +1,94 @@
1
+ import { elect, rendezvousPath } from "./rendezvous.js";
2
+ import { OwnerServer } from "./owner.js";
3
+ import { OwnerClient } from "./client.js";
4
+ /**
5
+ * Wrap a tool runner so calls execute strictly one-at-a-time. This is THE
6
+ * single-camera lock: it must guard both the owner's own MCP calls AND the
7
+ * calls forwarded from clients, because the owner's local path does not pass
8
+ * through OwnerServer's queue. Errors don't break the chain.
9
+ */
10
+ export function serialize(fn) {
11
+ let tail = Promise.resolve();
12
+ return (tool, args) => {
13
+ const run = tail.then(() => fn(tool, args));
14
+ tail = run.then(() => undefined, () => undefined);
15
+ return run;
16
+ };
17
+ }
18
+ export class Coordinator {
19
+ runLocal;
20
+ path;
21
+ role = "none";
22
+ client;
23
+ ownerServer;
24
+ electing;
25
+ /** `runLocal` should already be serialize()-wrapped by the caller. */
26
+ constructor(runLocal, path = rendezvousPath()) {
27
+ this.runLocal = runLocal;
28
+ this.path = path;
29
+ }
30
+ /** Establish the initial role eagerly at startup. */
31
+ start() {
32
+ return this.ensureRole();
33
+ }
34
+ get roleName() {
35
+ return this.role;
36
+ }
37
+ async dispatch(tool, args) {
38
+ await this.ensureRole();
39
+ try {
40
+ return await this.runByRole(tool, args);
41
+ }
42
+ catch (e) {
43
+ if (this.role === "client" && this.client?.closed) {
44
+ // The owner went away mid-call → re-elect and retry exactly once.
45
+ this.reset();
46
+ await this.ensureRole();
47
+ return this.runByRole(tool, args);
48
+ }
49
+ throw e; // a genuine owner-side error → surface it unchanged
50
+ }
51
+ }
52
+ runByRole(tool, args) {
53
+ return this.role === "owner"
54
+ ? this.runLocal(tool, args)
55
+ : this.client.request({ tool, args });
56
+ }
57
+ async close() {
58
+ if (this.ownerServer)
59
+ await this.ownerServer.close();
60
+ this.client?.close();
61
+ this.reset();
62
+ }
63
+ reset() {
64
+ this.role = "none";
65
+ this.client = undefined;
66
+ this.ownerServer = undefined;
67
+ }
68
+ ensureRole() {
69
+ if (this.role !== "none")
70
+ return Promise.resolve();
71
+ // Collapse concurrent callers onto one election.
72
+ if (!this.electing) {
73
+ this.electing = this.doElect().finally(() => {
74
+ this.electing = undefined;
75
+ });
76
+ }
77
+ return this.electing;
78
+ }
79
+ async doElect() {
80
+ const r = await elect(this.path);
81
+ if (r.role === "owner") {
82
+ this.ownerServer = new OwnerServer(r.server, (body) => {
83
+ const { tool, args } = body;
84
+ return this.runLocal(tool, args);
85
+ });
86
+ this.role = "owner";
87
+ }
88
+ else {
89
+ this.client = OwnerClient.adopt(r.socket);
90
+ this.role = "client";
91
+ }
92
+ }
93
+ }
94
+ //# sourceMappingURL=coordinator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coordinator.js","sourceRoot":"","sources":["../../src/ipc/coordinator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import net from "node:net";
2
+ export type Handler = (body: unknown) => Promise<unknown>;
3
+ export type ReplyBody = {
4
+ ok: true;
5
+ result: unknown;
6
+ } | {
7
+ ok: false;
8
+ error: string;
9
+ };
10
+ export declare class OwnerServer {
11
+ private readonly server;
12
+ private readonly handle;
13
+ /** Single promise chain → exactly one handler call runs at a time. */
14
+ private queue;
15
+ private readonly sockets;
16
+ constructor(server: net.Server, handle: Handler);
17
+ private accept;
18
+ private enqueue;
19
+ private run;
20
+ close(): Promise<void>;
21
+ }
@@ -0,0 +1,59 @@
1
+ import { encodeFrame, FrameDecoder } from "./protocol.js";
2
+ export class OwnerServer {
3
+ server;
4
+ handle;
5
+ /** Single promise chain → exactly one handler call runs at a time. */
6
+ queue = Promise.resolve();
7
+ sockets = new Set();
8
+ constructor(server, handle) {
9
+ this.server = server;
10
+ this.handle = handle;
11
+ this.server.on("connection", (sock) => this.accept(sock));
12
+ }
13
+ accept(sock) {
14
+ this.sockets.add(sock);
15
+ const dec = new FrameDecoder();
16
+ sock.on("data", (chunk) => {
17
+ let msgs;
18
+ try {
19
+ msgs = dec.push(chunk);
20
+ }
21
+ catch {
22
+ sock.destroy(); // unrecoverable framing error → drop this client
23
+ return;
24
+ }
25
+ for (const msg of msgs)
26
+ this.enqueue(sock, msg);
27
+ });
28
+ const drop = () => {
29
+ this.sockets.delete(sock);
30
+ };
31
+ sock.on("close", drop);
32
+ sock.on("error", drop);
33
+ }
34
+ enqueue(sock, msg) {
35
+ // Chain onto the shared queue so requests run one-at-a-time across all
36
+ // clients. The chain never rejects (errors become error replies), so one
37
+ // failing op can't stall the rest.
38
+ this.queue = this.queue.then(async () => {
39
+ const body = await this.run(msg.body);
40
+ if (!sock.destroyed)
41
+ sock.write(encodeFrame({ id: msg.id, body }));
42
+ });
43
+ }
44
+ async run(reqBody) {
45
+ try {
46
+ return { ok: true, result: await this.handle(reqBody) };
47
+ }
48
+ catch (e) {
49
+ return { ok: false, error: e instanceof Error ? e.message : String(e) };
50
+ }
51
+ }
52
+ async close() {
53
+ for (const s of this.sockets)
54
+ s.destroy();
55
+ this.sockets.clear();
56
+ await new Promise((resolve) => this.server.close(() => resolve()));
57
+ }
58
+ }
59
+ //# sourceMappingURL=owner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"owner.js","sourceRoot":"","sources":["../../src/ipc/owner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /** Upper bound on a single frame. Snapshots (base64 JPEG) are the large case. */
2
+ export declare const MAX_FRAME: number;
3
+ export interface RpcMessage {
4
+ id: number;
5
+ body: unknown;
6
+ }
7
+ /** Serialize a message to a length-prefixed frame. Throws if it exceeds MAX_FRAME. */
8
+ export declare function encodeFrame(msg: unknown): Buffer;
9
+ /**
10
+ * Stateful stream splitter — one per connection. Feed it raw chunks as they
11
+ * arrive; it returns the complete messages now decodable (0 or more), keeping
12
+ * any trailing partial frame buffered for the next push.
13
+ *
14
+ * Throws on a frame whose declared length exceeds MAX_FRAME (a corrupt or
15
+ * hostile peer) — the caller should treat that as a fatal protocol error and
16
+ * drop the connection rather than keep reading.
17
+ */
18
+ export declare class FrameDecoder {
19
+ private buf;
20
+ push(chunk: Buffer): RpcMessage[];
21
+ }
@@ -0,0 +1,56 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Length-prefixed JSON framing for the client↔owner control channel.
3
+ //
4
+ // A named pipe / Unix-domain socket is a byte STREAM: writes coalesce and reads
5
+ // split at arbitrary boundaries, so message edges are not preserved. Each
6
+ // message is framed as [uint32 BE body length][UTF-8 JSON body]. FrameDecoder
7
+ // buffers partial reads and emits one parsed message per complete frame.
8
+ //
9
+ // This is the transport envelope only; `body` is an opaque helper request
10
+ // (client→owner) or helper reply (owner→client). `id` correlates concurrent
11
+ // requests multiplexed over the one connection.
12
+ // ---------------------------------------------------------------------------
13
+ const HEADER = 4; // bytes: uint32 BE body length
14
+ /** Upper bound on a single frame. Snapshots (base64 JPEG) are the large case. */
15
+ export const MAX_FRAME = 16 * 1024 * 1024; // 16 MiB
16
+ /** Serialize a message to a length-prefixed frame. Throws if it exceeds MAX_FRAME. */
17
+ export function encodeFrame(msg) {
18
+ const body = Buffer.from(JSON.stringify(msg), "utf8");
19
+ if (body.length > MAX_FRAME) {
20
+ throw new Error(`ipc frame too large to send: ${body.length} bytes`);
21
+ }
22
+ const header = Buffer.allocUnsafe(HEADER);
23
+ header.writeUInt32BE(body.length, 0);
24
+ return Buffer.concat([header, body]);
25
+ }
26
+ /**
27
+ * Stateful stream splitter — one per connection. Feed it raw chunks as they
28
+ * arrive; it returns the complete messages now decodable (0 or more), keeping
29
+ * any trailing partial frame buffered for the next push.
30
+ *
31
+ * Throws on a frame whose declared length exceeds MAX_FRAME (a corrupt or
32
+ * hostile peer) — the caller should treat that as a fatal protocol error and
33
+ * drop the connection rather than keep reading.
34
+ */
35
+ export class FrameDecoder {
36
+ buf = Buffer.alloc(0);
37
+ push(chunk) {
38
+ this.buf = this.buf.length === 0 ? chunk : Buffer.concat([this.buf, chunk]);
39
+ const out = [];
40
+ for (;;) {
41
+ if (this.buf.length < HEADER)
42
+ break; // not even a full length header yet
43
+ const len = this.buf.readUInt32BE(0);
44
+ if (len > MAX_FRAME) {
45
+ throw new Error(`ipc frame too large to receive: ${len} bytes`);
46
+ }
47
+ if (this.buf.length < HEADER + len)
48
+ break; // body not fully arrived
49
+ const body = this.buf.subarray(HEADER, HEADER + len);
50
+ out.push(JSON.parse(body.toString("utf8")));
51
+ this.buf = this.buf.subarray(HEADER + len);
52
+ }
53
+ return out;
54
+ }
55
+ }
56
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/ipc/protocol.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,qEAAqE;AACrE,EAAE;AACF,gFAAgF;AAChF,0EAA0E;AAC1E,8EAA8E;AAC9E,yEAAyE;AACzE,EAAE;AACF,0EAA0E;AAC1E,4EAA4E;AAC5E,gDAAgD;AAChD,8EAA8E;AAE9E,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,+BAA+B;AACjD,iFAAiF;AACjF,MAAM,CAAC,MAAM,SAAS,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,SAAS;AAOpD,sFAAsF;AACtF,MAAM,UAAU,WAAW,CAAC,GAAY;IACtC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;IACtD,IAAI,IAAI,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,gCAAgC,IAAI,CAAC,MAAM,QAAQ,CAAC,CAAC;IACvE,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACrC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;AACvC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,OAAO,YAAY;IACf,GAAG,GAAW,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEtC,IAAI,CAAC,KAAa;QAChB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;QAC5E,MAAM,GAAG,GAAiB,EAAE,CAAC;QAC7B,SAAS,CAAC;YACR,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,MAAM;gBAAE,MAAM,CAAC,oCAAoC;YACzE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YACrC,IAAI,GAAG,GAAG,SAAS,EAAE,CAAC;gBACpB,MAAM,IAAI,KAAK,CAAC,mCAAmC,GAAG,QAAQ,CAAC,CAAC;YAClE,CAAC;YACD,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,MAAM,GAAG,GAAG;gBAAE,MAAM,CAAC,yBAAyB;YACpE,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,CAAC;YACrD,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAe,CAAC,CAAC;YAC1D,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;CACF"}
@@ -0,0 +1,26 @@
1
+ import net from "node:net";
2
+ /** Well-known rendezvous name → platform endpoint. */
3
+ export declare function rendezvousPath(name?: string): string;
4
+ export type Role = {
5
+ role: "owner";
6
+ server: net.Server;
7
+ } | {
8
+ role: "client";
9
+ socket: net.Socket;
10
+ };
11
+ /**
12
+ * Become the owner, or attach as a client.
13
+ *
14
+ * 1. Try to listen on `path` → win the bind → OWNER.
15
+ * 2. EADDRINUSE → someone's there → connect → CLIENT.
16
+ * 3. Connect refused on POSIX → the endpoint file is STALE (owner crashed
17
+ * without cleaning up); unlink it and retry the listen → OWNER. Windows
18
+ * named pipes are kernel-refcounted and never go stale, so this branch is
19
+ * POSIX-only.
20
+ *
21
+ * The stale-then-retry can itself lose a race to a concurrent starter that
22
+ * binds first; that just yields EADDRINUSE again, so we bounce back to the
23
+ * client path. A small bounded retry keeps a burst of simultaneous starts
24
+ * from spuriously failing.
25
+ */
26
+ export declare function elect(path?: string, attempts?: number): Promise<Role>;
@@ -0,0 +1,93 @@
1
+ import net from "node:net";
2
+ import { unlinkSync } from "node:fs";
3
+ // ---------------------------------------------------------------------------
4
+ // Peer election over a well-known local endpoint.
5
+ //
6
+ // Every obsbot-mcp instance calls elect() on startup. Exactly one wins the
7
+ // bind and becomes the OWNER (it will run the single DeviceManager + native
8
+ // helper and serve everyone else); the rest get EADDRINUSE and attach as
9
+ // CLIENTS that forward their helper ops to the owner. The bind is the lock —
10
+ // there is no check-then-create step to race (see IPC-DESIGN.md).
11
+ //
12
+ // Transport is a named pipe (Windows) / Unix-domain socket (macOS, Linux),
13
+ // NOT shared memory: it gives atomic election, framing, wakeup, and clean
14
+ // crash-detection for free.
15
+ // ---------------------------------------------------------------------------
16
+ /** Well-known rendezvous name → platform endpoint. */
17
+ export function rendezvousPath(name = "obsbot-mcp") {
18
+ return process.platform === "win32"
19
+ ? `\\\\.\\pipe\\${name}`
20
+ : `/tmp/${name}.sock`; // portable across macOS + Linux; abstract sockets are Linux-only
21
+ }
22
+ /**
23
+ * Become the owner, or attach as a client.
24
+ *
25
+ * 1. Try to listen on `path` → win the bind → OWNER.
26
+ * 2. EADDRINUSE → someone's there → connect → CLIENT.
27
+ * 3. Connect refused on POSIX → the endpoint file is STALE (owner crashed
28
+ * without cleaning up); unlink it and retry the listen → OWNER. Windows
29
+ * named pipes are kernel-refcounted and never go stale, so this branch is
30
+ * POSIX-only.
31
+ *
32
+ * The stale-then-retry can itself lose a race to a concurrent starter that
33
+ * binds first; that just yields EADDRINUSE again, so we bounce back to the
34
+ * client path. A small bounded retry keeps a burst of simultaneous starts
35
+ * from spuriously failing.
36
+ */
37
+ export async function elect(path = rendezvousPath(), attempts = 3) {
38
+ let lastErr;
39
+ for (let i = 0; i < attempts; i++) {
40
+ try {
41
+ return { role: "owner", server: await listen(path) };
42
+ }
43
+ catch (e) {
44
+ if (errno(e) !== "EADDRINUSE")
45
+ throw e;
46
+ }
47
+ try {
48
+ return { role: "client", socket: await connect(path) };
49
+ }
50
+ catch (e) {
51
+ lastErr = e;
52
+ const code = errno(e);
53
+ const stale = code === "ECONNREFUSED" || code === "ENOENT";
54
+ if (stale && process.platform !== "win32") {
55
+ try {
56
+ unlinkSync(path);
57
+ }
58
+ catch {
59
+ // already gone, or someone else cleaned it — fine; loop and retry.
60
+ }
61
+ continue; // retry listen
62
+ }
63
+ throw e; // a real connect failure that isn't a stale endpoint
64
+ }
65
+ }
66
+ throw new Error(`elect: could not become owner or client after ${attempts} attempts: ${errno(lastErr) ?? lastErr}`);
67
+ }
68
+ function listen(path) {
69
+ return new Promise((resolve, reject) => {
70
+ const server = net.createServer();
71
+ const onError = (e) => reject(e);
72
+ server.once("error", onError);
73
+ server.listen(path, () => {
74
+ server.removeListener("error", onError);
75
+ resolve(server);
76
+ });
77
+ });
78
+ }
79
+ function connect(path) {
80
+ return new Promise((resolve, reject) => {
81
+ const socket = net.connect(path);
82
+ const onError = (e) => reject(e);
83
+ socket.once("error", onError);
84
+ socket.once("connect", () => {
85
+ socket.removeListener("error", onError);
86
+ resolve(socket);
87
+ });
88
+ });
89
+ }
90
+ function errno(e) {
91
+ return e?.code;
92
+ }
93
+ //# sourceMappingURL=rendezvous.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rendezvous.js","sourceRoot":"","sources":["../../src/ipc/rendezvous.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Build the server's diagnostic log sink.
3
+ *
4
+ * The MCP server's stderr is a pipe to whatever launched it (Claude Code hands
5
+ * it a socket), so `console.error` alone is write-only in practice — the
6
+ * arrival re-bind ladder could fire and nobody would ever know. Setting
7
+ * `OBSBOT_LOG_FILE` appends the same lines somewhere greppable afterwards,
8
+ * which is what watching for a rare event during ordinary use requires.
9
+ *
10
+ * stdout is never an option: it is the JSON-RPC channel.
11
+ */
12
+ export declare function makeLogSink(path: string | undefined, console_: (msg: string) => void): (msg: string) => void;
@@ -0,0 +1,27 @@
1
+ import { appendFileSync } from "node:fs";
2
+ /**
3
+ * Build the server's diagnostic log sink.
4
+ *
5
+ * The MCP server's stderr is a pipe to whatever launched it (Claude Code hands
6
+ * it a socket), so `console.error` alone is write-only in practice — the
7
+ * arrival re-bind ladder could fire and nobody would ever know. Setting
8
+ * `OBSBOT_LOG_FILE` appends the same lines somewhere greppable afterwards,
9
+ * which is what watching for a rare event during ordinary use requires.
10
+ *
11
+ * stdout is never an option: it is the JSON-RPC channel.
12
+ */
13
+ export function makeLogSink(path, console_) {
14
+ if (!path)
15
+ return console_;
16
+ return (msg) => {
17
+ console_(msg);
18
+ try {
19
+ appendFileSync(path, `${new Date().toISOString()} ${msg}\n`);
20
+ }
21
+ catch {
22
+ // A bad path, a full disk, a read-only mount — none of that is worth
23
+ // taking the server down for. The console sink already got the message.
24
+ }
25
+ };
26
+ }
27
+ //# sourceMappingURL=log-sink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-sink.js","sourceRoot":"","sources":["../../src/mcp/log-sink.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEzC;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CACzB,IAAwB,EACxB,QAA+B;IAE/B,IAAI,CAAC,IAAI;QAAE,OAAO,QAAQ,CAAC;IAC3B,OAAO,CAAC,GAAW,EAAQ,EAAE;QAC3B,QAAQ,CAAC,GAAG,CAAC,CAAC;QACd,IAAI,CAAC;YACH,cAAc,CAAC,IAAI,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC;QAC/D,CAAC;QAAC,MAAM,CAAC;YACP,qEAAqE;YACrE,wEAAwE;QAC1E,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}