obsbot-mcp 0.3.0 → 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.
- package/README.md +197 -38
- package/dist/codec/commands.d.ts +42 -4
- package/dist/codec/commands.js +72 -10
- package/dist/codec/commands.js.map +1 -1
- package/dist/codec/frame.d.ts +1 -0
- package/dist/codec/frame.js +1 -1
- package/dist/codec/frame.js.map +1 -1
- package/dist/codec/preset.d.ts +40 -0
- package/dist/codec/preset.js +198 -0
- package/dist/codec/preset.js.map +1 -0
- package/dist/codec/types.d.ts +4 -0
- package/dist/device/helper-factory.d.ts +25 -0
- package/dist/device/helper-factory.js +40 -0
- package/dist/device/helper-factory.js.map +1 -0
- package/dist/device/manager.d.ts +326 -2
- package/dist/device/manager.js +720 -24
- package/dist/device/manager.js.map +1 -1
- package/dist/ipc/client.d.ts +19 -0
- package/dist/ipc/client.js +81 -0
- package/dist/ipc/client.js.map +1 -0
- package/dist/ipc/coordinator.d.ts +29 -0
- package/dist/ipc/coordinator.js +94 -0
- package/dist/ipc/coordinator.js.map +1 -0
- package/dist/ipc/owner.d.ts +21 -0
- package/dist/ipc/owner.js +59 -0
- package/dist/ipc/owner.js.map +1 -0
- package/dist/ipc/protocol.d.ts +21 -0
- package/dist/ipc/protocol.js +56 -0
- package/dist/ipc/protocol.js.map +1 -0
- package/dist/ipc/rendezvous.d.ts +26 -0
- package/dist/ipc/rendezvous.js +93 -0
- package/dist/ipc/rendezvous.js.map +1 -0
- package/dist/mcp/log-sink.d.ts +12 -0
- package/dist/mcp/log-sink.js +27 -0
- package/dist/mcp/log-sink.js.map +1 -0
- package/dist/mcp/ready.d.ts +16 -4
- package/dist/mcp/ready.js +11 -8
- package/dist/mcp/ready.js.map +1 -1
- package/dist/mcp/render.js +1 -1
- package/dist/mcp/render.js.map +1 -1
- package/dist/mcp/server.js +68 -18
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts +5 -3
- package/dist/mcp/tools.js +787 -186
- package/dist/mcp/tools.js.map +1 -1
- package/dist/transport/helper-process.d.ts +36 -0
- package/dist/transport/helper-process.js +190 -10
- package/dist/transport/helper-process.js.map +1 -1
- package/dist/transport/linux.d.ts +40 -0
- package/dist/transport/linux.js +92 -2
- package/dist/transport/linux.js.map +1 -1
- package/dist/transport/macos.d.ts +13 -0
- package/dist/transport/macos.js +59 -3
- package/dist/transport/macos.js.map +1 -1
- package/dist/transport/read-serial.d.ts +26 -0
- package/dist/transport/read-serial.js +87 -0
- package/dist/transport/read-serial.js.map +1 -0
- package/dist/transport/transport.d.ts +24 -0
- package/dist/transport/windows.d.ts +4 -0
- package/dist/transport/windows.js +31 -4
- package/dist/transport/windows.js.map +1 -1
- package/native/prebuilt/darwin-arm64/obsbot-helper +0 -0
- package/native/prebuilt/darwin-x64/obsbot-helper +0 -0
- package/native/prebuilt/linux-x64/obsbot-helper +0 -0
- package/native/prebuilt/win32-x64/obsbot-helper.exe +0 -0
- package/package.json +3 -2
- package/dist/device/session.d.ts +0 -22
- package/dist/device/session.js +0 -37
- 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":"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"}
|
|
@@ -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"}
|