mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
refactor: burn SDK export collision debt (#121888)
* refactor: burn SDK export collision debt * chore: regenerate collision debt baselines * fix: update durable delivery core import * fix: remove stale channel metadata type import * fix: preserve config write SDK parameter type * fix: preserve chat metadata SDK return type * chore: refresh plugin SDK API baseline * test: update plugin enable mock import * fix: remove duplicate status helper re-export * fix: preserve strict QA runtime availability errors
This commit is contained in:
committed by
GitHub
parent
1c2ca3f2fc
commit
02e8470bb8
+21
-21
@@ -3,10 +3,10 @@
|
||||
{"contentHash":"0d6827cdd7180482c49dc67aacc2b512e587d3453536081c15d3febaea2f1492","entrypoint":"account-id","importSpecifier":"openclaw/plugin-sdk/account-id"}
|
||||
{"contentHash":"0b4930a77ab3e63bed21a9651a23fb7130f623baf6ce153166cb80a965b0a004","entrypoint":"account-resolution","importSpecifier":"openclaw/plugin-sdk/account-resolution"}
|
||||
{"contentHash":"0349da0a93dadbdcff03ae8064b5066c5f2e1c28ee298bfa9ab3f1f8563300eb","entrypoint":"agent-config-primitives","importSpecifier":"openclaw/plugin-sdk/agent-config-primitives"}
|
||||
{"contentHash":"436e0ea78113e5411324fcf16377a2f269823fcae079d7ff9d1fbd449c5d6c98","entrypoint":"agent-harness","importSpecifier":"openclaw/plugin-sdk/agent-harness"}
|
||||
{"contentHash":"67cf13823fcfe4b8666b8378dc10b057e75f3dcb2b4a234cf2b2d159c3921b08","entrypoint":"agent-harness-runtime","importSpecifier":"openclaw/plugin-sdk/agent-harness-runtime"}
|
||||
{"contentHash":"1f3c0ebd22470430534291f6bd387f153f17f5d0867a3b5419f5442a27f54278","entrypoint":"agent-harness","importSpecifier":"openclaw/plugin-sdk/agent-harness"}
|
||||
{"contentHash":"7f884c6335908c525f2b15b39cd9d1bcefe04b80469c84f1b2767c917ea736b7","entrypoint":"agent-harness-runtime","importSpecifier":"openclaw/plugin-sdk/agent-harness-runtime"}
|
||||
{"contentHash":"4387e74b1261f632a0e140276c0f8cbbbe848a11f7ad287325538ebbee3b09da","entrypoint":"agent-media-payload","importSpecifier":"openclaw/plugin-sdk/agent-media-payload"}
|
||||
{"contentHash":"9d8ba6f6be8f608ea078a10fb915d7122628080637c5dd7ddff91e691446da08","entrypoint":"agent-runtime","importSpecifier":"openclaw/plugin-sdk/agent-runtime"}
|
||||
{"contentHash":"2782e8bae7ec62400f52caf45a6e58f61abb403bc0db28cdbfbc7833cd880ef8","entrypoint":"agent-runtime","importSpecifier":"openclaw/plugin-sdk/agent-runtime"}
|
||||
{"contentHash":"1f0e51c8b1a58fff13ab7d19806d97bf07fca61a5c7edeb3437cd805775a8320","entrypoint":"agent-scope-runtime","importSpecifier":"openclaw/plugin-sdk/agent-scope-runtime"}
|
||||
{"contentHash":"ce460dee97b375e50944f4da2ac95fe4c7a3f7be6b435550f54088b16369ed49","entrypoint":"allow-from","importSpecifier":"openclaw/plugin-sdk/allow-from"}
|
||||
{"contentHash":"c19f8658d0db60b1d3eddfeae9639ca6558592d7d69c6905ab2994b4a572f25b","entrypoint":"allowlist-config-edit","importSpecifier":"openclaw/plugin-sdk/allowlist-config-edit"}
|
||||
@@ -22,23 +22,23 @@
|
||||
{"contentHash":"7f9135d4ea9e3f53ed16bc51c0e44525fdd8907e5824309492a489a35761c25d","entrypoint":"archive","importSpecifier":"openclaw/plugin-sdk/archive"}
|
||||
{"contentHash":"d87a0eb6bae1b95fa645e77b5b9a81eb6cfdad9c469ae365ccd74b26f750166f","entrypoint":"boolean-param","importSpecifier":"openclaw/plugin-sdk/boolean-param"}
|
||||
{"contentHash":"8dbe8fc49378a684c4d52a991da9f27bdb85bb080530fdce1957bfd5c5687724","entrypoint":"channel-actions","importSpecifier":"openclaw/plugin-sdk/channel-actions"}
|
||||
{"contentHash":"09e65193adf3ba78b95019d34cf445746ceb7119069b329585d69d16fd90400b","entrypoint":"channel-config-helpers","importSpecifier":"openclaw/plugin-sdk/channel-config-helpers"}
|
||||
{"contentHash":"5998386ad8e299f9080382e5a982bb96ab9f35d3849ecb6de730df8c63044a77","entrypoint":"channel-config-helpers","importSpecifier":"openclaw/plugin-sdk/channel-config-helpers"}
|
||||
{"contentHash":"222019df4c06aca4e9bbede0fdea4b946f9b024a1524e3837c3c13be6d3d9e6a","entrypoint":"channel-config-primitives","importSpecifier":"openclaw/plugin-sdk/channel-config-primitives"}
|
||||
{"contentHash":"645ec473e40a04e4cc627d05c9156f66d835eb67dab32166f745f66eadc98880","entrypoint":"channel-config-schema","importSpecifier":"openclaw/plugin-sdk/channel-config-schema"}
|
||||
{"contentHash":"75935c1d837265d191436d43bbfe24c6328b35a45a68cad250c157923badf857","entrypoint":"channel-contract","importSpecifier":"openclaw/plugin-sdk/channel-contract"}
|
||||
{"contentHash":"69782257f9972d145234ab79ff78862587ab50b869ee752da958984f1f3da40b","entrypoint":"channel-core","importSpecifier":"openclaw/plugin-sdk/channel-core"}
|
||||
{"contentHash":"7cbe4e1a327ce4623f0c56e7a1debd3ad2d4fc75c148c4366993e90b9951fa5f","entrypoint":"channel-core","importSpecifier":"openclaw/plugin-sdk/channel-core"}
|
||||
{"contentHash":"b2d90f161ca88ef2d5ff35f87f160c772bd784a4ebda91b2ab33bf16b6abd843","entrypoint":"channel-dm-policy","importSpecifier":"openclaw/plugin-sdk/channel-dm-policy"}
|
||||
{"contentHash":"0b9b65943323fa62d16e723a469b4ef883c5e5031c264b293ddff22f80ac635e","entrypoint":"channel-entry-contract","importSpecifier":"openclaw/plugin-sdk/channel-entry-contract"}
|
||||
{"contentHash":"eb5de4fe50596ccc225becd7d40f86900a7467ed409fc1aabd1f7cd4472f0883","entrypoint":"channel-entry-contract","importSpecifier":"openclaw/plugin-sdk/channel-entry-contract"}
|
||||
{"contentHash":"8bc8b784c78a70ee58731aae0be9731c9af01705db00acbafa25de9745a23601","entrypoint":"channel-feedback","importSpecifier":"openclaw/plugin-sdk/channel-feedback"}
|
||||
{"contentHash":"c702f520272a16b626673930d5ad311acddabef85ef6344cb667a46d8d232081","entrypoint":"channel-inbound","importSpecifier":"openclaw/plugin-sdk/channel-inbound"}
|
||||
{"contentHash":"d536677665a306185447d5b83e46ba8a1cd78d11adbc1f4cf4d8171ffdef3116","entrypoint":"channel-inbound","importSpecifier":"openclaw/plugin-sdk/channel-inbound"}
|
||||
{"contentHash":"87ba6e4e9f2f56621f6d52cc262e8b80fada5e338e841439b4d20983e22dfb82","entrypoint":"channel-inbound-debounce","importSpecifier":"openclaw/plugin-sdk/channel-inbound-debounce"}
|
||||
{"contentHash":"7a69b23fdd7b631ed407d9ae4af55df192d93b61488c81626f041d4199760d95","entrypoint":"channel-ingress-runtime","importSpecifier":"openclaw/plugin-sdk/channel-ingress-runtime"}
|
||||
{"contentHash":"85afc43170761c8d7d6d2d91401b0ad033189636050e8cf85d22132e4aba9f1a","entrypoint":"channel-lifecycle","importSpecifier":"openclaw/plugin-sdk/channel-lifecycle"}
|
||||
{"contentHash":"be803c0341214a8e731f98cb7bf98654410ab1e0254d90f9f1ad9f442f70669f","entrypoint":"channel-logging","importSpecifier":"openclaw/plugin-sdk/channel-logging"}
|
||||
{"contentHash":"45c44443a11721749cf248f6297fadbb7de7bd3a1aa9ea556588e1b3e8cc6f6d","entrypoint":"channel-message","importSpecifier":"openclaw/plugin-sdk/channel-message"}
|
||||
{"contentHash":"0a59ef1b77768d9feb363f219d76a1f9d56423ff5b5bdf12e7506b08b410761b","entrypoint":"channel-outbound","importSpecifier":"openclaw/plugin-sdk/channel-outbound"}
|
||||
{"contentHash":"b465f0fe84c2aff407a3903c0d38d2a4afc2d6fae48e2024ccacf1e2df4767cb","entrypoint":"channel-message","importSpecifier":"openclaw/plugin-sdk/channel-message"}
|
||||
{"contentHash":"ef8e8ab4e213b38b5b9e45467f271ecc3cfcb2622add275da7a78782eadd34fe","entrypoint":"channel-outbound","importSpecifier":"openclaw/plugin-sdk/channel-outbound"}
|
||||
{"contentHash":"4e059b59e9c0044627d10a7011f13dcf0ea3546f197731ab0a3af3772e35b8cb","entrypoint":"channel-pairing","importSpecifier":"openclaw/plugin-sdk/channel-pairing"}
|
||||
{"contentHash":"9e0e609d46e3b4a64bccf6d228988dffe9e2099d5cea020a92e0126a01ea2f2c","entrypoint":"channel-plugin-common","importSpecifier":"openclaw/plugin-sdk/channel-plugin-common"}
|
||||
{"contentHash":"252b2da93a59eb13d3cb9f78ca92fdc4bdd577a8fb1912694393c3173781b7ba","entrypoint":"channel-plugin-common","importSpecifier":"openclaw/plugin-sdk/channel-plugin-common"}
|
||||
{"contentHash":"350b4986aec115e3674c9dd3712302e7c185dbefc534b65a98a6a84564e65e05","entrypoint":"channel-policy","importSpecifier":"openclaw/plugin-sdk/channel-policy"}
|
||||
{"contentHash":"369721c067caf33fc86e50c7dd5aec3e8371d2e97e2e3c4305751b79da9e7387","entrypoint":"channel-reply-pipeline","importSpecifier":"openclaw/plugin-sdk/channel-reply-pipeline"}
|
||||
{"contentHash":"5181d3f1c6936e1e13a7d3ab4b904f5ae929a1985480c130915710a9bf8e8a25","entrypoint":"channel-runtime-context","importSpecifier":"openclaw/plugin-sdk/channel-runtime-context"}
|
||||
@@ -60,12 +60,12 @@
|
||||
{"contentHash":"1deb735b023442072fe21294cf4f94af0e44356fd8591ed6a8a9befafc7c3d67","entrypoint":"config-mutation","importSpecifier":"openclaw/plugin-sdk/config-mutation"}
|
||||
{"contentHash":"40df7e972484ae28718fef1095b2b44cb2cc9eadd35464bf28d4ae0d0f0f66b5","entrypoint":"config-runtime","importSpecifier":"openclaw/plugin-sdk/config-runtime"}
|
||||
{"contentHash":"7a5a2f4d3e5e18d211480286d125419ecbf8175bb6f8eeee9a6ee105df03cb3f","entrypoint":"conversation-runtime","importSpecifier":"openclaw/plugin-sdk/conversation-runtime"}
|
||||
{"contentHash":"5986edef7e0fae8b348236d870e6add9e846ef9649347369b20a1fb3e47c7a55","entrypoint":"core","importSpecifier":"openclaw/plugin-sdk/core"}
|
||||
{"contentHash":"db8ccfcf658564acf00cf049861ebbe44a94ceab69f6403e35ca4051c2615e90","entrypoint":"core","importSpecifier":"openclaw/plugin-sdk/core"}
|
||||
{"contentHash":"184f6a3849b361adfc9db756699787e934e274f05eeedcda04cd2b7cb4f9fe5e","entrypoint":"dedupe-runtime","importSpecifier":"openclaw/plugin-sdk/dedupe-runtime"}
|
||||
{"contentHash":"8ba476d7f0411071797cd4362f3a71720d9d008d54107b2cb4eccb4a4eb0db0a","entrypoint":"device-bootstrap","importSpecifier":"openclaw/plugin-sdk/device-bootstrap"}
|
||||
{"contentHash":"cb6fbd1612e60755c7528a5243cec69c9123904297d2e16a9c716485785be532","entrypoint":"diagnostic-runtime","importSpecifier":"openclaw/plugin-sdk/diagnostic-runtime"}
|
||||
{"contentHash":"f7b6949b179827646d4e047ce4f181550ca8d67bd4537441405d36fb79438556","entrypoint":"directory-runtime","importSpecifier":"openclaw/plugin-sdk/directory-runtime"}
|
||||
{"contentHash":"dbf1191e33cdb22bdef411e614c415025a44c40570d18ee43571b338dd12f4a5","entrypoint":"discord","importSpecifier":"openclaw/plugin-sdk/discord"}
|
||||
{"contentHash":"c4794a31e7efdb8c7740f4da6556206f903d3cc8bcc90507310a615c2823abd9","entrypoint":"discord","importSpecifier":"openclaw/plugin-sdk/discord"}
|
||||
{"contentHash":"e0523b4936d7c7ec043265de9e2a8f6289d32dacba0a28c3999ba3a0975dfc21","entrypoint":"error-runtime","importSpecifier":"openclaw/plugin-sdk/error-runtime"}
|
||||
{"contentHash":"5125d71bf8c4aeca728c4b8c73b2984247ba7bcc088a45ee29692ff64e3ebf90","entrypoint":"extension-shared","importSpecifier":"openclaw/plugin-sdk/extension-shared"}
|
||||
{"contentHash":"cbeb81159a1e558846f3cf9eecf3fd5a84858029cfdd9ccf237af428e35e755c","entrypoint":"gateway-method-runtime","importSpecifier":"openclaw/plugin-sdk/gateway-method-runtime"}
|
||||
@@ -75,8 +75,8 @@
|
||||
{"contentHash":"273ebd4fcac3041e3a136410fa396b9704c73eedb66414723996127ed80db8f3","entrypoint":"hook-runtime","importSpecifier":"openclaw/plugin-sdk/hook-runtime"}
|
||||
{"contentHash":"a6537713e63d101897ef9ddfeaae438a50645e2672be5bdced887c4e8a651b96","entrypoint":"inbound-envelope","importSpecifier":"openclaw/plugin-sdk/inbound-envelope"}
|
||||
{"contentHash":"931a52a774750ab895236a8fa7851781ad0279cb5678b1a78e81af9dd25bb3a4","entrypoint":"inbound-event-delivery","importSpecifier":"openclaw/plugin-sdk/inbound-event-delivery"}
|
||||
{"contentHash":"0d576051d319599bd81f41e407354e0bddd129f571df4ad6394b601cf879ef58","entrypoint":"inbound-reply-dispatch","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch"}
|
||||
{"contentHash":"485a44e8099cc31188018a114615be22e4c6f3b4f9ef04df381a95bae480e86b","entrypoint":"infra-runtime","importSpecifier":"openclaw/plugin-sdk/infra-runtime"}
|
||||
{"contentHash":"d092285fcba3c813078c693c6dd0a2b9774cc775c75e4382d6efecf1bf94c04a","entrypoint":"inbound-reply-dispatch","importSpecifier":"openclaw/plugin-sdk/inbound-reply-dispatch"}
|
||||
{"contentHash":"b590647f65a2e148ba7a1bc207f70adbd3a57990b41d3bf6b10f61ee8f27ab87","entrypoint":"infra-runtime","importSpecifier":"openclaw/plugin-sdk/infra-runtime"}
|
||||
{"contentHash":"41a1f24a1b745f833d44e622ae1922c9dc66ee5de56f0e967ec1a3f9e03a2d18","entrypoint":"ingress-effect-once","importSpecifier":"openclaw/plugin-sdk/ingress-effect-once"}
|
||||
{"contentHash":"57f79c6e8db72b2806bc8c016066682de71bf690378ccb4403b8da6dd3d38b28","entrypoint":"interactive-runtime","importSpecifier":"openclaw/plugin-sdk/interactive-runtime"}
|
||||
{"contentHash":"e41d2b9acaec4e89bc69880d645c49c068dbbc19d0a3b247b18b891aa0ce8f39","entrypoint":"json-store","importSpecifier":"openclaw/plugin-sdk/json-store"}
|
||||
@@ -89,7 +89,7 @@
|
||||
{"contentHash":"0df97720dfd7b1a5892bbf3d46bc64297468af9b8cbb8720ce0d80d42ff2e59d","entrypoint":"media-store","importSpecifier":"openclaw/plugin-sdk/media-store"}
|
||||
{"contentHash":"684c061bb0d1112872c9b2d5a00e258d14b4ff8649a26dd0cc67995352d8ca8b","entrypoint":"media-understanding","importSpecifier":"openclaw/plugin-sdk/media-understanding"}
|
||||
{"contentHash":"f48e34067ab9b25a232af71d8ce17f9cbf9165ebce0832deaae3c1d9c9aeaab7","entrypoint":"media-understanding-runtime","importSpecifier":"openclaw/plugin-sdk/media-understanding-runtime"}
|
||||
{"contentHash":"63416bac276f99e275988fd199742a7774fcc1091b7d4cfdd27be31e591c375c","entrypoint":"meeting-runtime","importSpecifier":"openclaw/plugin-sdk/meeting-runtime"}
|
||||
{"contentHash":"c8bdb6f59fb0e5ecef5c5e1a93061eefa25d0c76be2963404d5ff12351f9cf47","entrypoint":"meeting-runtime","importSpecifier":"openclaw/plugin-sdk/meeting-runtime"}
|
||||
{"contentHash":"27509d9bbabc547662a45bf258fa432d1e0c3c3f7c22051858d8a67375486e79","entrypoint":"memory-core-host-engine-foundation","importSpecifier":"openclaw/plugin-sdk/memory-core-host-engine-foundation"}
|
||||
{"contentHash":"ad875662e95df74808357c234ac36825d1ff729165da941180061591525ff47f","entrypoint":"memory-host-core","importSpecifier":"openclaw/plugin-sdk/memory-host-core"}
|
||||
{"contentHash":"0f140018c2c21965b6a8f7a2ac1882babcaf70e733b477bb693e498641629938","entrypoint":"messaging-targets","importSpecifier":"openclaw/plugin-sdk/messaging-targets"}
|
||||
@@ -101,17 +101,17 @@
|
||||
{"contentHash":"3b2106094ccada38a6736f39abbb5814e776638cdb7f1f6d065576e6f8a2d3b6","entrypoint":"persistent-dedupe","importSpecifier":"openclaw/plugin-sdk/persistent-dedupe"}
|
||||
{"contentHash":"e43fcfe8f88cf8d338c3e3496f3bdd6ec14afc1fcf341e171f7758f5c0190d5b","entrypoint":"plugin-command-runtime","importSpecifier":"openclaw/plugin-sdk/plugin-command-runtime"}
|
||||
{"contentHash":"756175b7ff16cd8456b3c85a87466f077476a9236e098c5545ea8ef31fcff0d2","entrypoint":"plugin-config-runtime","importSpecifier":"openclaw/plugin-sdk/plugin-config-runtime"}
|
||||
{"contentHash":"671047f7f29f0ef80021bde1f42f8bc05f900a419b0754ab0a25ec96018d4878","entrypoint":"plugin-entry","importSpecifier":"openclaw/plugin-sdk/plugin-entry"}
|
||||
{"contentHash":"c80882b5e1db8433d02a178b04cac3c60e9ae76e0d767d7374bba5e399ee49eb","entrypoint":"plugin-runtime","importSpecifier":"openclaw/plugin-sdk/plugin-runtime"}
|
||||
{"contentHash":"cc7b14cfab794959ca1c8d1ab375e03324053814b3092f1121aeb1f60dda1f8b","entrypoint":"plugin-entry","importSpecifier":"openclaw/plugin-sdk/plugin-entry"}
|
||||
{"contentHash":"a569e076eb2c4ea8fc8ac9951a861ae5a4c595789b49e1c1d835af20eb41b457","entrypoint":"plugin-runtime","importSpecifier":"openclaw/plugin-sdk/plugin-runtime"}
|
||||
{"contentHash":"d5d21f2a0883eac72d6642d93306c36e2de0f3851286eb3edbe3a2d9d6122dcc","entrypoint":"provider-auth","importSpecifier":"openclaw/plugin-sdk/provider-auth"}
|
||||
{"contentHash":"7d8eef8b52b9c091c4fc9916ed5e925fa97ca9a541a91adcdb59239df9dbf4a4","entrypoint":"provider-catalog-runtime","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime"}
|
||||
{"contentHash":"88cb3ece55129c7efd194de57fd247b90c40d9d6c5f5d82075ddf309b1056ade","entrypoint":"provider-catalog-runtime","importSpecifier":"openclaw/plugin-sdk/provider-catalog-runtime"}
|
||||
{"contentHash":"aee2a235e7218ed4ba36e80e0a6d67ceb3b5de448f25ebc10d6f70552dc35b8a","entrypoint":"proxy-capture","importSpecifier":"openclaw/plugin-sdk/proxy-capture"}
|
||||
{"contentHash":"55bc0be5ce1d700d8b671efccb69ec14a3c942535c2f77d3ed7ca87809dc1ad9","entrypoint":"question-gateway-runtime","importSpecifier":"openclaw/plugin-sdk/question-gateway-runtime"}
|
||||
{"contentHash":"5263836c817c9391fd5a0efdda50552330dd01e4d6bc9cb4ebba58627c48f098","entrypoint":"reply-chunking","importSpecifier":"openclaw/plugin-sdk/reply-chunking"}
|
||||
{"contentHash":"137ac20380a751e39c9e8ea2a7fe69785c1656713af56901d72fe163ab835d2c","entrypoint":"reply-dispatch-runtime","importSpecifier":"openclaw/plugin-sdk/reply-dispatch-runtime"}
|
||||
{"contentHash":"0a7b62b1cfdf15c5d397be2ee951eb991e61712cf331f353faf21b5355863cf1","entrypoint":"reply-history","importSpecifier":"openclaw/plugin-sdk/reply-history"}
|
||||
{"contentHash":"369a0c223cba73be174d9a7ada6dcebff739b15c71c34f767e761b57af667723","entrypoint":"reply-payload","importSpecifier":"openclaw/plugin-sdk/reply-payload"}
|
||||
{"contentHash":"346a32998d94c82981308dccd54ac8bc3dfd3b833e3fd02f15d6ed79ea5cddbd","entrypoint":"reply-runtime","importSpecifier":"openclaw/plugin-sdk/reply-runtime"}
|
||||
{"contentHash":"e4bb392339efecbb53dc8d2a9af5b83a632f527ebdecccfe7c305ce2a46a13d2","entrypoint":"reply-runtime","importSpecifier":"openclaw/plugin-sdk/reply-runtime"}
|
||||
{"contentHash":"91ade8da7db7cd2b9cbafcbf307338fbd0d656ac8a31d10c38cab23a916840b8","entrypoint":"root-walk","importSpecifier":"openclaw/plugin-sdk/root-walk"}
|
||||
{"contentHash":"ad853e4f7e257b2a206f8e3a551b9e50f36a020db1fd36de65c121bcf24a6d5e","entrypoint":"routing","importSpecifier":"openclaw/plugin-sdk/routing"}
|
||||
{"contentHash":"c10788e36c8343600186fe9aadf84eb977e1686cb29e7ee0a581d033b8dfc7e5","entrypoint":"run-command","importSpecifier":"openclaw/plugin-sdk/run-command"}
|
||||
@@ -142,11 +142,11 @@
|
||||
{"contentHash":"09957526abf9619fd2ef095119a7195f2bebf2d8e8b1a5605aee0868152f8b5c","entrypoint":"temp-path","importSpecifier":"openclaw/plugin-sdk/temp-path"}
|
||||
{"contentHash":"4519df78f420290da1fd755f7e4a7de7d09dbc934b3e17fc139aaf64896ffa06","entrypoint":"text-chunking","importSpecifier":"openclaw/plugin-sdk/text-chunking"}
|
||||
{"contentHash":"c5f29e3b48cb9a92111bf565f739875a32fc3e19a009dd0bab3c27bbb71f7583","entrypoint":"text-runtime","importSpecifier":"openclaw/plugin-sdk/text-runtime"}
|
||||
{"contentHash":"31d9c24facf34b7a12b38e474421af901a5246702642dda44369b69096019e5f","entrypoint":"tool-plugin","importSpecifier":"openclaw/plugin-sdk/tool-plugin"}
|
||||
{"contentHash":"f9645fff7dad30a7848d81c12fe0ec73083332361fcd3fccd88ba8d45359f0ee","entrypoint":"tool-plugin","importSpecifier":"openclaw/plugin-sdk/tool-plugin"}
|
||||
{"contentHash":"17e58e27b06e2470908acd719f64ec2add1f117c1882adad79eb5a3b5bd74312","entrypoint":"tool-results","importSpecifier":"openclaw/plugin-sdk/tool-results"}
|
||||
{"contentHash":"aabfb4eacce1bd5190b2f92189332abe7bbe3a5cea3655babe66bf1909206984","entrypoint":"tool-send","importSpecifier":"openclaw/plugin-sdk/tool-send"}
|
||||
{"contentHash":"8d432f42395afae27f4a95c897dfca0bf5df6289c0846d326df424ad5f6b491b","entrypoint":"web-media","importSpecifier":"openclaw/plugin-sdk/web-media"}
|
||||
{"contentHash":"e597e7cd15bb3665cd8e82dc12e1105aaab3911cc0c1e79509da72cd980c96fd","entrypoint":"webhook-ingress","importSpecifier":"openclaw/plugin-sdk/webhook-ingress"}
|
||||
{"contentHash":"dce8b35bf1c8b58681c38dc12ca70537de12703c378cbd8a79a2707e8c4d65f0","entrypoint":"webhook-ingress","importSpecifier":"openclaw/plugin-sdk/webhook-ingress"}
|
||||
{"contentHash":"1fe8314d4dfa3d7b536f39ac5622ff688f6a20fa6ae8b8fa4770d4851e85a400","entrypoint":"webhook-request-guards","importSpecifier":"openclaw/plugin-sdk/webhook-request-guards"}
|
||||
{"contentHash":"6091f4048c4464103dfdf659904c6afa6e29c483b9a05c502ab3333df08f942b","entrypoint":"widget-html","importSpecifier":"openclaw/plugin-sdk/widget-html"}
|
||||
{"contentHash":"eafdc7277066acf893bfef9b635689c1a69d6d5af22ad8cee2b47351d9b53ca6","entrypoint":"zod","importSpecifier":"openclaw/plugin-sdk/zod"}
|
||||
|
||||
@@ -195,7 +195,7 @@ const dispatchReplyHoisted = vi.hoisted(() => ({
|
||||
export const dispatchReplyWithBufferedBlockDispatcher =
|
||||
dispatchReplyHoisted.dispatchReplyWithBufferedBlockDispatcher;
|
||||
vi.mock("../../../src/auto-reply/reply/provider-dispatcher.js", () => ({
|
||||
dispatchReplyWithBufferedBlockDispatcher:
|
||||
dispatchReplyWithBufferedBlockDispatcherCore:
|
||||
dispatchReplyHoisted.dispatchReplyWithBufferedBlockDispatcher,
|
||||
}));
|
||||
vi.mock("openclaw/plugin-sdk/channel-inbound", async (importOriginal) => {
|
||||
|
||||
@@ -27,14 +27,6 @@
|
||||
"src/plugins/uninstall.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "authorizeConfigWrite",
|
||||
"files": [
|
||||
"src/channels/plugins/config-writes.ts",
|
||||
"src/plugin-sdk/channel-config-helpers.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "buildBundleMcpToolsFromCatalog",
|
||||
"files": [
|
||||
@@ -70,22 +62,6 @@
|
||||
"src/plugins/status.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "buildQaTarget",
|
||||
"files": [
|
||||
"src/plugin-sdk/qa-channel-protocol.ts",
|
||||
"src/plugin-sdk/qa-channel.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "bundledPluginFile",
|
||||
"files": [
|
||||
"src/plugin-sdk/test-helpers/bundled-plugin-paths.ts",
|
||||
"src/plugins/contracts/test-helpers/bundled-plugin-roots.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "callGateway",
|
||||
"files": [
|
||||
@@ -100,14 +76,6 @@
|
||||
"src/gateway/call.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "canBypassConfigWritePolicy",
|
||||
"files": [
|
||||
"src/channels/plugins/config-writes.ts",
|
||||
"src/plugin-sdk/channel-config-helpers.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "classifySessionKind",
|
||||
"files": [
|
||||
@@ -137,22 +105,6 @@
|
||||
"src/secrets/runtime.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "closeActiveMemorySearchManager",
|
||||
"files": [
|
||||
"src/plugin-sdk/memory-host-search.ts",
|
||||
"src/plugins/memory-runtime.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "closeActiveMemorySearchManagers",
|
||||
"files": [
|
||||
"src/plugin-sdk/memory-host-search.ts",
|
||||
"src/plugins/memory-runtime.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "containsConfigIncludeDirective",
|
||||
"files": [
|
||||
@@ -160,14 +112,6 @@
|
||||
"src/plugins/install-persistence.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "createFixedWindowRateLimiter",
|
||||
"files": [
|
||||
"src/infra/fixed-window-rate-limit.ts",
|
||||
"src/plugin-sdk/webhook-memory-guards.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "createGatewayStartupTrace",
|
||||
"files": [
|
||||
@@ -189,46 +133,6 @@
|
||||
"src/test-helpers/temp-dir.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "createTestRegistry",
|
||||
"files": [
|
||||
"src/gateway/server/__tests__/test-utils.ts",
|
||||
"src/test-utils/channel-plugins.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "defaultRuntime",
|
||||
"files": [
|
||||
"src/cli/daemon-cli/test-helpers/lifecycle-core-harness.ts",
|
||||
"src/runtime.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "deliverInboundReplyWithMessageSendContext",
|
||||
"files": [
|
||||
"src/channels/turn/durable-delivery.ts",
|
||||
"src/plugin-sdk/channel-outbound.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "dispatchReplyWithBufferedBlockDispatcher",
|
||||
"files": [
|
||||
"src/auto-reply/reply/provider-dispatcher.ts",
|
||||
"src/plugin-sdk/reply-dispatch-runtime.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "dispatchReplyWithDispatcher",
|
||||
"files": [
|
||||
"src/auto-reply/reply/provider-dispatcher.ts",
|
||||
"src/plugin-sdk/reply-dispatch-runtime.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "doctorCommand",
|
||||
"files": [
|
||||
@@ -236,31 +140,6 @@
|
||||
"src/flows/doctor-health.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "drainPendingDeliveries",
|
||||
"files": [
|
||||
"src/infra/outbound/delivery-queue-recovery.ts",
|
||||
"src/plugin-sdk/delivery-queue-runtime.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "enablePluginInConfig",
|
||||
"files": [
|
||||
"src/cli/plugins-cli-test-helpers.ts",
|
||||
"src/plugin-sdk/provider-enable-config.ts",
|
||||
"src/plugins/enable.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "ensureConfiguredAcpBindingReady",
|
||||
"files": [
|
||||
"src/acp/persistent-bindings.lifecycle.ts",
|
||||
"src/plugin-sdk/core.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "extractAssistantVisibleText",
|
||||
"files": [
|
||||
@@ -275,15 +154,6 @@
|
||||
"src/gateway/session-transcript-readers.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fileExists",
|
||||
"files": [
|
||||
"src/infra/state-migrations.fs.ts",
|
||||
"src/media-understanding/fs.ts",
|
||||
"src/plugin-sdk/security-runtime.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "formatConfigPath",
|
||||
"files": [
|
||||
@@ -291,46 +161,6 @@
|
||||
"src/config/logging.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "formatConfigWriteDeniedMessage",
|
||||
"files": [
|
||||
"src/channels/plugins/config-writes.ts",
|
||||
"src/plugin-sdk/channel-config-helpers.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "formatEnvelopeTimestamp",
|
||||
"files": [
|
||||
"src/auto-reply/envelope.ts",
|
||||
"src/plugin-sdk/test-helpers/envelope-timestamp.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "formatSkillsForPrompt",
|
||||
"files": [
|
||||
"src/skills/loading/session.ts",
|
||||
"src/skills/loading/skill-contract.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "generateOAuthState",
|
||||
"files": [
|
||||
"src/plugin-sdk/provider-auth-runtime.ts",
|
||||
"src/plugin-sdk/provider-oauth-runtime.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "getActiveMemorySearchManager",
|
||||
"files": [
|
||||
"src/plugin-sdk/memory-host-search.ts",
|
||||
"src/plugins/memory-runtime.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "getActivePluginChannelRegistryVersion",
|
||||
"files": [
|
||||
@@ -345,14 +175,6 @@
|
||||
"src/plugins/runtime.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "getChatChannelMeta",
|
||||
"files": [
|
||||
"src/channels/chat-meta.ts",
|
||||
"src/plugin-sdk/core.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "getFreePort",
|
||||
"files": [
|
||||
@@ -360,38 +182,6 @@
|
||||
"src/test-utils/ports.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "getReplyFromConfig",
|
||||
"files": [
|
||||
"src/auto-reply/reply/get-reply.ts",
|
||||
"src/gateway/test-helpers.runtime-state.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "getRuntimeAuthForModel",
|
||||
"files": [
|
||||
"src/plugin-sdk/provider-auth-runtime.ts",
|
||||
"src/plugins/runtime/runtime-model-auth.runtime.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "hasOwnProperty",
|
||||
"files": [
|
||||
"src/secrets/runtime-shared.ts",
|
||||
"src/tts/tts-settings.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "inferToolMetaFromArgs",
|
||||
"files": [
|
||||
"src/agents/embedded-agent-utils.ts",
|
||||
"src/plugin-sdk/agent-harness-runtime.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "inspectPluginRegistry",
|
||||
"files": [
|
||||
@@ -462,30 +252,6 @@
|
||||
"src/plugins/install-package.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "isClaudeCliProvider",
|
||||
"files": [
|
||||
"src/agents/cli-runner/helpers.ts",
|
||||
"src/plugin-sdk/anthropic-cli.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "isCommandMessage",
|
||||
"files": [
|
||||
"src/auto-reply/commands-registry.ts",
|
||||
"src/tui/tui-formatters.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "isQaRuntimeAvailable",
|
||||
"files": [
|
||||
"src/plugin-sdk/qa-runner-runtime.ts",
|
||||
"src/plugin-sdk/qa-runtime.ts"
|
||||
],
|
||||
"sdk": true
|
||||
},
|
||||
{
|
||||
"name": "killProcessTree",
|
||||
"files": [
|
||||
|
||||
@@ -59,17 +59,6 @@
|
||||
"wrapped": "src/shared/progress-labels.ts",
|
||||
"wrapper": "src/channels/streaming.ts"
|
||||
},
|
||||
{
|
||||
"name": "drainPendingDeliveries",
|
||||
"wrapped": "src/infra/outbound/delivery-queue-recovery.ts",
|
||||
"wrapper": "src/plugin-sdk/delivery-queue-runtime.ts",
|
||||
"via": "src/infra/outbound/delivery-queue.ts"
|
||||
},
|
||||
{
|
||||
"name": "formatSkillsForPrompt",
|
||||
"wrapped": "src/skills/loading/skill-contract.ts",
|
||||
"wrapper": "src/skills/loading/session.ts"
|
||||
},
|
||||
{
|
||||
"name": "getActivePluginRegistryWorkspaceDirFromState",
|
||||
"wrapped": "src/plugins/runtime-workspace-state.ts",
|
||||
|
||||
@@ -129,7 +129,7 @@ export async function ensureConfiguredAcpBindingSession(params: {
|
||||
}
|
||||
|
||||
/** Resolves a configured binding for a conversation and ensures its ACP session exists. */
|
||||
export async function ensureConfiguredAcpBindingReady(params: {
|
||||
export async function ensureConfiguredAcpBindingReadyCore(params: {
|
||||
cfg: OpenClawConfig;
|
||||
configuredBinding: ResolvedConfiguredAcpBinding | null;
|
||||
}): Promise<{ ok: true } | { ok: false; error: string }> {
|
||||
|
||||
@@ -29,7 +29,7 @@ import type { AcpServerOptions } from "@openclaw/acp-core/types";
|
||||
import type { EventFrame } from "../../packages/gateway-protocol/src/index.js";
|
||||
import type { GatewayClient } from "../gateway/client.js";
|
||||
import {
|
||||
createFixedWindowRateLimiter,
|
||||
createFixedWindowBudget,
|
||||
resolveFixedWindowRateLimitInteger,
|
||||
} from "../infra/fixed-window-rate-limit.js";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
@@ -89,7 +89,7 @@ export class AcpGatewayAgent implements Agent {
|
||||
this.approvalRelays,
|
||||
this.log,
|
||||
);
|
||||
const sessionCreateRateLimiter = createFixedWindowRateLimiter({
|
||||
const sessionCreateRateLimiter = createFixedWindowBudget({
|
||||
maxRequests: resolveFixedWindowRateLimitInteger(
|
||||
opts.sessionCreateRateLimit?.maxRequests,
|
||||
SESSION_CREATE_RATE_LIMIT_DEFAULT_MAX_REQUESTS,
|
||||
|
||||
@@ -53,7 +53,7 @@ const CLI_RUN_QUEUE = new KeyedAsyncQueue();
|
||||
const CLI_IMAGE_SWEEP_TTL_MS = 7 * 24 * 60 * 60 * 1_000;
|
||||
const sweptCliImageRoots = new Set<string>();
|
||||
|
||||
export function isClaudeCliProvider(providerId: string): boolean {
|
||||
export function isClaudeCliBackendId(providerId: string): boolean {
|
||||
return normalizeOptionalLowercaseString(providerId) === "claude-cli";
|
||||
}
|
||||
|
||||
@@ -73,11 +73,11 @@ export function resolveCliRunQueueKey(params: {
|
||||
ownerKey?: string;
|
||||
}): string {
|
||||
const requiresLiveSessionSerialization =
|
||||
isClaudeCliProvider(params.backendId) && params.liveSession === "claude-stdio";
|
||||
isClaudeCliBackendId(params.backendId) && params.liveSession === "claude-stdio";
|
||||
if (params.serialize === false && !requiresLiveSessionSerialization) {
|
||||
return `${params.backendId}:${params.runId}`;
|
||||
}
|
||||
if (isClaudeCliProvider(params.backendId)) {
|
||||
if (isClaudeCliBackendId(params.backendId)) {
|
||||
const ownerKey = params.ownerKey?.trim();
|
||||
if (requiresLiveSessionSerialization && ownerKey) {
|
||||
return `${params.backendId}:owner:${ownerKey}`;
|
||||
|
||||
@@ -128,7 +128,7 @@ import {
|
||||
resolveBundledCliBackendAuthPolicy,
|
||||
type BundledCliBackendAuthPolicy,
|
||||
} from "./cli-backend-auth-policy.js";
|
||||
import { buildCliAgentSystemPrompt, isClaudeCliProvider, normalizeCliModel } from "./helpers.js";
|
||||
import { buildCliAgentSystemPrompt, isClaudeCliBackendId, normalizeCliModel } from "./helpers.js";
|
||||
import { cliBackendLog } from "./log.js";
|
||||
import { buildCliMcpGrantContext, normalizeOptionalMcpContextValue } from "./mcp-grant-context.js";
|
||||
import { CLAUDE_CLI_CONTEXT_MODEL_ALIASES, detectNodeClaudePlacement } from "./prepare-claude.js";
|
||||
@@ -796,7 +796,7 @@ export async function prepareCliRunContext(
|
||||
const promptBuildRestrictsTools =
|
||||
promptBuildToolsAllow !== undefined &&
|
||||
!promptBuildToolsAllow.some((toolName) => normalizeToolName(toolName) === "*");
|
||||
const isClaudeCli = isClaudeCliProvider(params.provider);
|
||||
const isClaudeCli = isClaudeCliBackendId(params.provider);
|
||||
const requestedContextModelId = isClaudeCli ? resolveClaudeCliContextModelId(modelId) : modelId;
|
||||
const normalizedContextModelId = isClaudeCli
|
||||
? resolveClaudeCliContextModelId(normalizedModel)
|
||||
@@ -1390,7 +1390,7 @@ export async function prepareCliRunContext(
|
||||
const hasClaudeCliCandidate =
|
||||
!nodeClaudePlacement &&
|
||||
candidateClaudeCliSessionId !== undefined &&
|
||||
isClaudeCliProvider(params.provider);
|
||||
isClaudeCliBackendId(params.provider);
|
||||
const claudeCliTranscriptMissing =
|
||||
hasClaudeCliCandidate &&
|
||||
!(await prepareDeps.claudeCliSessionTranscriptHasContent({
|
||||
|
||||
@@ -1000,7 +1000,7 @@ export async function loadCompactHooksHarness(): Promise<{
|
||||
}));
|
||||
|
||||
vi.doMock("../../plugins/memory-runtime.js", () => ({
|
||||
getActiveMemorySearchManager: getMemorySearchManagerMock,
|
||||
getActiveMemorySearchManagerCore: getMemorySearchManagerMock,
|
||||
}));
|
||||
|
||||
vi.doMock("../date-time.js", () => ({
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import { createInternalHookEvent, triggerInternalHook } from "../../hooks/internal-hooks.js";
|
||||
import { formatErrorMessage } from "../../infra/errors.js";
|
||||
import { getGlobalHookRunner } from "../../plugins/hook-runner-global.js";
|
||||
import { getActiveMemorySearchManager } from "../../plugins/memory-runtime.js";
|
||||
import { getActiveMemorySearchManagerCore } from "../../plugins/memory-runtime.js";
|
||||
import { emitSessionTranscriptUpdate } from "../../sessions/transcript-events.js";
|
||||
import { resolveSessionAgentId } from "../agent-scope.js";
|
||||
import { resolveMemorySearchConfig } from "../memory-search.js";
|
||||
@@ -47,7 +47,7 @@ async function runPostCompactionSessionMemorySync(params: {
|
||||
if (!resolvedMemory.sync.sessions.postCompactionForce) {
|
||||
return;
|
||||
}
|
||||
const { manager } = await getActiveMemorySearchManager({
|
||||
const { manager } = await getActiveMemorySearchManagerCore({
|
||||
cfg: params.config,
|
||||
agentId,
|
||||
});
|
||||
|
||||
@@ -29,10 +29,9 @@ import {
|
||||
extractMessagingToolSend,
|
||||
sanitizeToolArgs,
|
||||
} from "./embedded-agent-subscribe.tools.js";
|
||||
import { inferToolMetaFromArgs } from "./embedded-agent-utils.js";
|
||||
import { buildAgentHarnessQuestionPromptPayload } from "./harness/user-input-bridge.js";
|
||||
import type { AgentEvent } from "./runtime/index.js";
|
||||
import { isCommandBearingToolCall } from "./tool-display.js";
|
||||
import { inferToolMetaFromArgsCore, isCommandBearingToolCall } from "./tool-display.js";
|
||||
import { resolveFileMutationToolName } from "./tool-mutation-names.js";
|
||||
import { buildToolMutationState } from "./tool-mutation.js";
|
||||
import { normalizeToolName } from "./tool-policy.js";
|
||||
@@ -439,7 +438,7 @@ export function handleToolExecutionStart(
|
||||
const meta = extendExecMeta(
|
||||
toolName,
|
||||
args,
|
||||
inferToolMetaFromArgs(toolName, args, {
|
||||
inferToolMetaFromArgsCore(toolName, args, {
|
||||
detailMode: ctx.params.toolProgressDetail ?? "explain",
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -17,7 +17,6 @@ import {
|
||||
import { sanitizeUserFacingText } from "./embedded-agent-helpers/sanitize-user-facing-text.js";
|
||||
import { renderUserFacingText } from "./embedded-agent-helpers/user-facing-text.js";
|
||||
import type { AgentMessage } from "./runtime/index.js";
|
||||
import { formatToolDetail, resolveToolDisplay } from "./tool-display.js";
|
||||
|
||||
export { stripDowngradedToolCallText } from "../shared/text/assistant-visible-text.js";
|
||||
|
||||
@@ -409,13 +408,3 @@ export function extractThinkingFromTaggedStream(
|
||||
}
|
||||
return text.slice(state.lastTag.end).trim();
|
||||
}
|
||||
|
||||
/** Infer compact display metadata for a tool call from its args. */
|
||||
export function inferToolMetaFromArgs(
|
||||
toolName: string,
|
||||
args: unknown,
|
||||
options?: { detailMode?: "explain" | "raw" },
|
||||
): string | undefined {
|
||||
const display = resolveToolDisplay({ name: toolName, args, detailMode: options?.detailMode });
|
||||
return formatToolDetail(display);
|
||||
}
|
||||
|
||||
@@ -98,6 +98,17 @@ export function formatToolDetail(display: ToolDisplay): string | undefined {
|
||||
return formatToolDetailText(detailRaw);
|
||||
}
|
||||
|
||||
/** Infers compact display metadata for a tool invocation from its arguments. */
|
||||
export function inferToolMetaFromArgsCore(
|
||||
toolName: string,
|
||||
args: unknown,
|
||||
options?: { detailMode?: ToolDetailMode },
|
||||
): string | undefined {
|
||||
return formatToolDetail(
|
||||
resolveToolDisplay({ name: toolName, args, detailMode: options?.detailMode }),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shell-family tools render their command as the whole line instead of
|
||||
* "Label: detail". Backends spell the same tool differently — the Claude CLI
|
||||
|
||||
@@ -3,7 +3,7 @@ import { describe, expect, it } from "vitest";
|
||||
import { withEnv } from "../test-utils/env.js";
|
||||
import {
|
||||
formatAgentEnvelope,
|
||||
formatEnvelopeTimestamp,
|
||||
formatAgentEnvelopeTimestamp,
|
||||
formatInboundEnvelope,
|
||||
resolveEnvelopeFormatOptions,
|
||||
} from "./envelope.js";
|
||||
@@ -28,7 +28,7 @@ describe("formatAgentEnvelope", () => {
|
||||
|
||||
it("formats timestamps in local timezone by default", () => {
|
||||
const ts = Date.UTC(2025, 0, 2, 3, 4);
|
||||
const expectedTimestamp = formatEnvelopeTimestamp(ts, { timezone: "local" });
|
||||
const expectedTimestamp = formatAgentEnvelopeTimestamp(ts, { timezone: "local" });
|
||||
const body = formatAgentEnvelope({
|
||||
channel: "WebChat",
|
||||
timestamp: ts,
|
||||
@@ -70,15 +70,15 @@ describe("formatAgentEnvelope", () => {
|
||||
agents: { defaults: { userTimezone: "Not/A_Timezone" } },
|
||||
});
|
||||
expect(options.timezone).toBe("local");
|
||||
expect(formatEnvelopeTimestamp(ts, options)).toBe(
|
||||
formatEnvelopeTimestamp(ts, { timezone: "local" }),
|
||||
expect(formatAgentEnvelopeTimestamp(ts, options)).toBe(
|
||||
formatAgentEnvelopeTimestamp(ts, { timezone: "local" }),
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps the UTC fallback for an invalid explicit timezone option", () => {
|
||||
const ts = Date.UTC(2025, 0, 2, 3, 4, 5);
|
||||
expect(formatEnvelopeTimestamp(ts, { timezone: "Not/A_Timezone" })).toBe(
|
||||
formatEnvelopeTimestamp(ts, { timezone: "utc" }),
|
||||
expect(formatAgentEnvelopeTimestamp(ts, { timezone: "Not/A_Timezone" })).toBe(
|
||||
formatAgentEnvelopeTimestamp(ts, { timezone: "utc" }),
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ function resolveEnvelopeTimezone(options: NormalizedEnvelopeOptions): ResolvedEn
|
||||
}
|
||||
|
||||
/** Formats an envelope timestamp using local, UTC, user, or explicit IANA timezone rules. */
|
||||
export function formatEnvelopeTimestamp(
|
||||
export function formatAgentEnvelopeTimestamp(
|
||||
ts: number | Date | undefined,
|
||||
options?: EnvelopeFormatOptions,
|
||||
): string | undefined {
|
||||
@@ -202,7 +202,7 @@ export function formatAgentEnvelope(params: AgentEnvelopeParams): string {
|
||||
if (ip) {
|
||||
parts.push(sanitizeEnvelopeHeaderPart(ip));
|
||||
}
|
||||
const ts = formatEnvelopeTimestamp(params.timestamp, resolved);
|
||||
const ts = formatAgentEnvelopeTimestamp(params.timestamp, resolved);
|
||||
if (ts) {
|
||||
parts.push(ts);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import { runCliAgent } from "../../agents/cli-runner.js";
|
||||
import type { RunCliAgentParams } from "../../agents/cli-runner/types.js";
|
||||
import { clearCliSession, getCliSessionBinding } from "../../agents/cli-session.js";
|
||||
import { extractToolResultText } from "../../agents/embedded-agent-subscribe.tools.js";
|
||||
import { inferToolMetaFromArgs } from "../../agents/embedded-agent-utils.js";
|
||||
import type { EmbeddedAgentRunResult } from "../../agents/embedded-agent.js";
|
||||
import {
|
||||
DEFAULT_FAST_MODE_AUTO_ON_SECONDS,
|
||||
@@ -18,6 +17,7 @@ import {
|
||||
resolveAgentRunAbortLifecycleFields,
|
||||
resolveAgentRunErrorLifecycleFields,
|
||||
} from "../../agents/run-termination.js";
|
||||
import { inferToolMetaFromArgsCore } from "../../agents/tool-display.js";
|
||||
import { isCommandBearingToolCall } from "../../agents/tool-display.js";
|
||||
import { normalizeAgentPlanSteps } from "../../channels/streaming.js";
|
||||
import type { SessionEntry } from "../../config/sessions.js";
|
||||
@@ -313,7 +313,7 @@ export function createCliToolSummaryTracker(params: {
|
||||
if (payload.phase === "start") {
|
||||
if (payload.toolCallId && payload.name) {
|
||||
toolByCallId.set(payload.toolCallId, {
|
||||
meta: inferToolMetaFromArgs(payload.name, payload.args, {
|
||||
meta: inferToolMetaFromArgsCore(payload.name, payload.args, {
|
||||
detailMode: params.detailMode ?? "explain",
|
||||
}),
|
||||
commandBearing: isCommandBearingToolCall(payload.name, payload.args),
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
readStringValue,
|
||||
} from "@openclaw/normalization-core/string-coerce";
|
||||
import { inferToolMetaFromArgs } from "../../agents/embedded-agent-utils.js";
|
||||
import { inferToolMetaFromArgsCore } from "../../agents/tool-display.js";
|
||||
import type { GetReplyOptions } from "../types.js";
|
||||
|
||||
/**
|
||||
@@ -93,7 +93,7 @@ export function buildCommandOutputFromToolResultEvent(evt: {
|
||||
const args = readRecordValue(evt.data.args);
|
||||
const title =
|
||||
readStringValue(evt.data.title) ??
|
||||
(args ? inferToolMetaFromArgs(name, args, { detailMode: "explain" }) : undefined);
|
||||
(args ? inferToolMetaFromArgsCore(name, args, { detailMode: "explain" }) : undefined);
|
||||
return {
|
||||
itemId: readStringValue(evt.data.itemId),
|
||||
phase: "end",
|
||||
|
||||
@@ -12,7 +12,7 @@ import type { SessionEntry } from "../../config/sessions/types.js";
|
||||
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import { sliceUtf16Safe, truncateUtf16Safe } from "../../utils.js";
|
||||
import type { EnvelopeFormatOptions } from "../envelope.js";
|
||||
import { formatEnvelopeTimestamp } from "../envelope.js";
|
||||
import { formatAgentEnvelopeTimestamp } from "../envelope.js";
|
||||
import type { TemplateContext } from "../templating.js";
|
||||
import {
|
||||
formatContextJsonBlock,
|
||||
@@ -501,7 +501,7 @@ function formatConversationTimestamp(
|
||||
if (typeof value !== "number" || !Number.isFinite(value)) {
|
||||
return undefined;
|
||||
}
|
||||
return formatEnvelopeTimestamp(value, envelope);
|
||||
return formatAgentEnvelopeTimestamp(value, envelope);
|
||||
}
|
||||
|
||||
function resolveInboundChannel(ctx: TemplateContext): string | undefined {
|
||||
|
||||
@@ -21,7 +21,7 @@ vi.mock("../dispatch.js", () => ({
|
||||
hoisted.plainDispatchMock(...args),
|
||||
}));
|
||||
|
||||
const { dispatchReplyWithBufferedBlockDispatcher, dispatchReplyWithDispatcher } =
|
||||
const { dispatchReplyWithBufferedBlockDispatcherCore, dispatchReplyWithDispatcherCore } =
|
||||
await import("./provider-dispatcher.js");
|
||||
|
||||
const dispatchResult = {
|
||||
@@ -41,7 +41,7 @@ describe("provider dispatcher wrappers", () => {
|
||||
deliver: async () => ({ visibleReplySent: false }),
|
||||
} satisfies ReplyDispatcherWithTypingOptions;
|
||||
|
||||
await dispatchReplyWithBufferedBlockDispatcher({
|
||||
await dispatchReplyWithBufferedBlockDispatcherCore({
|
||||
ctx: { Body: "hello" },
|
||||
cfg: {} as OpenClawConfig,
|
||||
dispatcherOptions,
|
||||
@@ -62,7 +62,7 @@ describe("provider dispatcher wrappers", () => {
|
||||
deliver: async () => ({ visibleReplySent: false }),
|
||||
} satisfies ReplyDispatcherOptions;
|
||||
|
||||
await dispatchReplyWithDispatcher({
|
||||
await dispatchReplyWithDispatcherCore({
|
||||
ctx: { Body: "hello" },
|
||||
cfg: {} as OpenClawConfig,
|
||||
dispatcherOptions,
|
||||
|
||||
@@ -14,7 +14,7 @@ export type {
|
||||
} from "./provider-dispatcher.types.js";
|
||||
|
||||
/** Dispatch a reply using the buffered block dispatcher path. */
|
||||
export const dispatchReplyWithBufferedBlockDispatcher: DispatchReplyWithBufferedBlockDispatcher =
|
||||
export const dispatchReplyWithBufferedBlockDispatcherCore: DispatchReplyWithBufferedBlockDispatcher =
|
||||
async (params) => {
|
||||
return await dispatchInboundMessageWithBufferedDispatcher({
|
||||
ctx: params.ctx,
|
||||
@@ -27,7 +27,7 @@ export const dispatchReplyWithBufferedBlockDispatcher: DispatchReplyWithBuffered
|
||||
};
|
||||
|
||||
/** Dispatch a reply using the standard dispatcher path. */
|
||||
export const dispatchReplyWithDispatcher: DispatchReplyWithDispatcher = async (params) => {
|
||||
export const dispatchReplyWithDispatcherCore: DispatchReplyWithDispatcher = async (params) => {
|
||||
return await dispatchInboundMessageWithDispatcher({
|
||||
ctx: params.ctx,
|
||||
cfg: params.cfg,
|
||||
|
||||
@@ -4,14 +4,20 @@
|
||||
* Provides ordered channel metadata for setup, status, and selection surfaces.
|
||||
*/
|
||||
import { expectDefined } from "@openclaw/normalization-core";
|
||||
import { resolveBundledPluginsDir } from "../plugins/bundled-dir.js";
|
||||
import { buildChatChannelMetaById, type ChatChannelMeta } from "./chat-meta-shared.js";
|
||||
import { CHAT_CHANNEL_ORDER, type ChatChannelId } from "./ids.js";
|
||||
|
||||
let chatChannelMetaCache: Record<ChatChannelId, ChatChannelMeta> | null = null;
|
||||
let chatChannelMetaCache:
|
||||
| { cacheKey: string; metaById: Record<ChatChannelId, ChatChannelMeta> }
|
||||
| undefined;
|
||||
|
||||
function getChatChannelMetaById(): Record<ChatChannelId, ChatChannelMeta> {
|
||||
chatChannelMetaCache ??= buildChatChannelMetaById();
|
||||
return chatChannelMetaCache;
|
||||
const cacheKey = resolveBundledPluginsDir(process.env) ?? "";
|
||||
if (chatChannelMetaCache?.cacheKey !== cacheKey) {
|
||||
chatChannelMetaCache = { cacheKey, metaById: buildChatChannelMetaById() };
|
||||
}
|
||||
return chatChannelMetaCache.metaById;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,7 +18,7 @@ const resolveMocks = vi.hoisted(() => ({
|
||||
}));
|
||||
|
||||
vi.mock("../../acp/persistent-bindings.lifecycle.js", () => ({
|
||||
ensureConfiguredAcpBindingReady: vi.fn(),
|
||||
ensureConfiguredAcpBindingReadyCore: vi.fn(),
|
||||
ensureConfiguredAcpBindingSession: vi.fn(),
|
||||
}));
|
||||
vi.mock("../../gateway/session-reset-service.js", () => ({
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Ensures ACP-backed bound sessions exist, are ready, and can be reset by Gateway.
|
||||
*/
|
||||
import {
|
||||
ensureConfiguredAcpBindingReady,
|
||||
ensureConfiguredAcpBindingReadyCore,
|
||||
ensureConfiguredAcpBindingSession,
|
||||
} from "../../acp/persistent-bindings.lifecycle.js";
|
||||
import { resolveConfiguredAcpBindingSpecBySessionKey } from "../../acp/persistent-bindings.resolve.js";
|
||||
@@ -86,7 +86,7 @@ async function ensureAcpTargetReady(params: {
|
||||
error: "Configured ACP binding unavailable",
|
||||
};
|
||||
}
|
||||
return await ensureConfiguredAcpBindingReady({
|
||||
return await ensureConfiguredAcpBindingReadyCore({
|
||||
cfg: params.cfg,
|
||||
configuredBinding: {
|
||||
spec: configuredBinding,
|
||||
|
||||
@@ -83,7 +83,7 @@ export function canBypassConfigWritePolicy(params: {
|
||||
*/
|
||||
export function formatConfigWriteDeniedMessage(params: {
|
||||
result: Exclude<ConfigWriteAuthorizationResult, { allowed: true }>;
|
||||
fallbackChannelId?: ChannelId | null;
|
||||
fallbackChannelId?: string | null;
|
||||
}): string {
|
||||
return formatConfigWriteDeniedMessageShared(params);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { inferToolMetaFromArgs } from "../agents/embedded-agent-utils.js";
|
||||
import { inferToolMetaFromArgsCore } from "../agents/tool-display.js";
|
||||
import { formatToolAggregate } from "../auto-reply/tool-meta.js";
|
||||
import {
|
||||
buildChannelProgressDraftLine,
|
||||
@@ -187,7 +187,7 @@ describe("backend tool-name casing", () => {
|
||||
},
|
||||
{ commandText: "raw" },
|
||||
);
|
||||
const meta = inferToolMetaFromArgs(name, args, { detailMode: "explain" });
|
||||
const meta = inferToolMetaFromArgsCore(name, args, { detailMode: "explain" });
|
||||
const summaryText = formatToolAggregate(name, meta ? [meta] : undefined, { markdown: true });
|
||||
|
||||
const merged = mergeChannelProgressDraftLine(
|
||||
|
||||
@@ -23,7 +23,7 @@ vi.mock("../message/send.js", async (importOriginal) => {
|
||||
});
|
||||
|
||||
import type { FinalizedMsgContext } from "../../auto-reply/templating.js";
|
||||
import { deliverInboundReplyWithMessageSendContext } from "./durable-delivery.js";
|
||||
import { deliverInboundReplyWithMessageSendContextCore } from "./durable-delivery.js";
|
||||
|
||||
type SendDurableMessageBatchRequest = {
|
||||
cfg?: unknown;
|
||||
@@ -86,7 +86,7 @@ describe("durable inbound reply delivery", () => {
|
||||
});
|
||||
|
||||
it("preserves explicit null thread targets instead of falling back to context thread", async () => {
|
||||
await deliverInboundReplyWithMessageSendContext({
|
||||
await deliverInboundReplyWithMessageSendContextCore({
|
||||
cfg: {},
|
||||
channel: "telegram",
|
||||
agentId: "main",
|
||||
@@ -110,7 +110,7 @@ describe("durable inbound reply delivery", () => {
|
||||
});
|
||||
|
||||
it("does not require unknown-send reconciliation for the default best-effort final path", async () => {
|
||||
await deliverInboundReplyWithMessageSendContext({
|
||||
await deliverInboundReplyWithMessageSendContextCore({
|
||||
cfg: {},
|
||||
channel: "telegram",
|
||||
agentId: "main",
|
||||
@@ -132,7 +132,7 @@ describe("durable inbound reply delivery", () => {
|
||||
});
|
||||
|
||||
it("uses required durability when a caller explicitly requires unknown-send reconciliation", async () => {
|
||||
await deliverInboundReplyWithMessageSendContext({
|
||||
await deliverInboundReplyWithMessageSendContextCore({
|
||||
cfg: {},
|
||||
channel: "telegram",
|
||||
agentId: "main",
|
||||
@@ -172,7 +172,7 @@ describe("durable inbound reply delivery", () => {
|
||||
sentBeforeError: true,
|
||||
});
|
||||
|
||||
const result = await deliverInboundReplyWithMessageSendContext({
|
||||
const result = await deliverInboundReplyWithMessageSendContextCore({
|
||||
cfg: {},
|
||||
channel: "telegram",
|
||||
agentId: "main",
|
||||
|
||||
@@ -145,7 +145,7 @@ function markDurableInboundReplyDeliveryErrorVisible(error: unknown): unknown {
|
||||
}
|
||||
|
||||
/** Delivers final inbound replies through the durable message-send context when supported. */
|
||||
export async function deliverInboundReplyWithMessageSendContext(
|
||||
export async function deliverInboundReplyWithMessageSendContextCore(
|
||||
params: DurableInboundReplyDeliveryParams,
|
||||
): Promise<DurableInboundReplyDeliveryResult> {
|
||||
if (params.info.kind !== "final") {
|
||||
|
||||
@@ -31,7 +31,7 @@ import {
|
||||
toCoreManagedDeliveryInfo,
|
||||
} from "./direct-delivery-custody.js";
|
||||
import {
|
||||
deliverInboundReplyWithMessageSendContext,
|
||||
deliverInboundReplyWithMessageSendContextCore,
|
||||
isDurableInboundReplyDeliveryHandled,
|
||||
throwIfDurableInboundReplyDeliveryFailed,
|
||||
} from "./durable-delivery.js";
|
||||
@@ -546,7 +546,7 @@ async function dispatchChannelTurnWithDeliveryOwner(
|
||||
? await declaredDurable(preparedPayload, info)
|
||||
: declaredDurable;
|
||||
if (durableOptions) {
|
||||
const durable = await deliverInboundReplyWithMessageSendContext({
|
||||
const durable = await deliverInboundReplyWithMessageSendContextCore({
|
||||
cfg: params.cfg,
|
||||
channel: params.channel,
|
||||
accountId: params.accountId,
|
||||
|
||||
@@ -37,7 +37,7 @@ vi.mock("../../auto-reply/reply/provider-dispatcher.js", async (importOriginal)
|
||||
await importOriginal<typeof import("../../auto-reply/reply/provider-dispatcher.js")>();
|
||||
return {
|
||||
...actual,
|
||||
dispatchReplyWithBufferedBlockDispatcher: dispatchReplyWithBufferedBlockDispatcherCore,
|
||||
dispatchReplyWithBufferedBlockDispatcherCore,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ vi.mock("../../auto-reply/reply/provider-dispatcher.js", async (importOriginal)
|
||||
await importOriginal<typeof import("../../auto-reply/reply/provider-dispatcher.js")>();
|
||||
return {
|
||||
...actual,
|
||||
dispatchReplyWithBufferedBlockDispatcher: dispatchReplyWithBufferedBlockDispatcherCore,
|
||||
dispatchReplyWithBufferedBlockDispatcherCore,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ vi.mock("../../auto-reply/reply/provider-dispatcher.js", async (importOriginal)
|
||||
await importOriginal<typeof import("../../auto-reply/reply/provider-dispatcher.js")>();
|
||||
return {
|
||||
...actual,
|
||||
dispatchReplyWithBufferedBlockDispatcher: dispatchReplyWithBufferedBlockDispatcherCore,
|
||||
dispatchReplyWithBufferedBlockDispatcherCore,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { VERSION } from "../../version.js";
|
||||
import {
|
||||
defaultRuntime,
|
||||
lifecycleTestRuntime,
|
||||
resetLifecycleRuntimeLogs,
|
||||
resetLifecycleServiceMocks,
|
||||
service,
|
||||
@@ -30,7 +30,7 @@ const pluginPackagingHintItems = pluginPackagingRecoveryHints.map((text) => ({
|
||||
}));
|
||||
|
||||
function expectLatestRuntimeJson(payload: unknown) {
|
||||
const calls = defaultRuntime.writeJson.mock.calls;
|
||||
const calls = lifecycleTestRuntime.writeJson.mock.calls;
|
||||
expect(calls[calls.length - 1]?.[0]).toEqual(payload);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ vi.mock("../../config/issue-format.js", () => ({
|
||||
}));
|
||||
|
||||
vi.mock("../../runtime.js", () => ({
|
||||
defaultRuntime,
|
||||
defaultRuntime: lifecycleTestRuntime,
|
||||
}));
|
||||
|
||||
function setConfigSnapshot(params: {
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { OpenClawConfig } from "../../config/config.js";
|
||||
import type { GatewayServiceControlArgs } from "../../daemon/service-types.js";
|
||||
import type { GatewayService } from "../../daemon/service.js";
|
||||
import {
|
||||
defaultRuntime,
|
||||
lifecycleTestRuntime,
|
||||
resetLifecycleRuntimeLogs,
|
||||
resetLifecycleServiceMocks,
|
||||
lifecycleRuntimeLogs,
|
||||
@@ -38,7 +38,7 @@ vi.mock("../../config/config.js", () => ({
|
||||
}));
|
||||
|
||||
vi.mock("../../runtime.js", () => ({
|
||||
defaultRuntime,
|
||||
defaultRuntime: lifecycleTestRuntime,
|
||||
}));
|
||||
|
||||
vi.mock("../../infra/restart-intent.js", () => ({
|
||||
|
||||
@@ -20,7 +20,7 @@ type LifecycleServiceHarness = GatewayService & {
|
||||
restart: MockFn<GatewayService["restart"]>;
|
||||
};
|
||||
|
||||
export const defaultRuntime: LifecycleRuntimeHarness = lifecycleRuntimeCapture.defaultRuntime;
|
||||
export const lifecycleTestRuntime: LifecycleRuntimeHarness = lifecycleRuntimeCapture.defaultRuntime;
|
||||
|
||||
export const service: LifecycleServiceHarness = {
|
||||
label: "TestService",
|
||||
|
||||
@@ -102,7 +102,7 @@ export const installPluginFromGitSpec: Mock<InstallPluginFromGitSpecFn> = vi.fn(
|
||||
const parseGitPluginSpec: Mock<ParseGitPluginSpecFn> = vi.fn();
|
||||
const listMarketplacePlugins: Mock<ListMarketplacePluginsFn> = vi.fn();
|
||||
export const resolveMarketplaceInstallShortcut: Mock<ResolveMarketplaceInstallShortcutFn> = vi.fn();
|
||||
export const enablePluginInConfig: UnknownMock = vi.fn();
|
||||
export const enablePluginInConfigMock: UnknownMock = vi.fn();
|
||||
export const recordPluginInstall: UnknownMock = vi.fn();
|
||||
const loadInstalledPluginIndexInstallRecords: AsyncUnknownMock = vi.fn(async () =>
|
||||
clonePluginInstallRecords(mockInstalledPluginIndexInstallRecords),
|
||||
@@ -326,7 +326,7 @@ vi.mock("../plugins/enable.js", () => ({
|
||||
Parameters<(typeof import("../plugins/enable.js"))["enableExplicitlySelectedPluginInConfig"]>,
|
||||
unknown
|
||||
>(
|
||||
enablePluginInConfig,
|
||||
enablePluginInConfigMock,
|
||||
...args,
|
||||
)) as (typeof import("../plugins/enable.js"))["enableExplicitlySelectedPluginInConfig"],
|
||||
enablePluginInConfig: ((
|
||||
@@ -336,7 +336,7 @@ vi.mock("../plugins/enable.js", () => ({
|
||||
Parameters<(typeof import("../plugins/enable.js"))["enablePluginInConfig"]>,
|
||||
unknown
|
||||
>(
|
||||
enablePluginInConfig,
|
||||
enablePluginInConfigMock,
|
||||
...args,
|
||||
)) as (typeof import("../plugins/enable.js"))["enablePluginInConfig"],
|
||||
}));
|
||||
@@ -827,7 +827,7 @@ export function resetPluginsCliTestState() {
|
||||
installPluginFromMarketplace.mockReset();
|
||||
listMarketplacePlugins.mockReset();
|
||||
resolveMarketplaceInstallShortcut.mockReset();
|
||||
enablePluginInConfig.mockReset();
|
||||
enablePluginInConfigMock.mockReset();
|
||||
recordPluginInstall.mockReset();
|
||||
mockInstalledPluginIndexInstallRecords = {};
|
||||
mockInstalledPluginIndexRevision = 0;
|
||||
@@ -909,7 +909,7 @@ export function resetPluginsCliTestState() {
|
||||
ok: false,
|
||||
error: "marketplace install failed",
|
||||
});
|
||||
enablePluginInConfig.mockImplementation(((cfg: OpenClawConfig, pluginId: string) => ({
|
||||
enablePluginInConfigMock.mockImplementation(((cfg: OpenClawConfig, pluginId: string) => ({
|
||||
config: cfg,
|
||||
enabled: true,
|
||||
pluginId,
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
applyExclusiveSlotSelection,
|
||||
buildPluginSnapshotReport,
|
||||
clearPluginRegistryLoadCache,
|
||||
enablePluginInConfig,
|
||||
enablePluginInConfigMock,
|
||||
findBundledPluginSourceMock,
|
||||
installHooksFromNpmSpec,
|
||||
installHooksFromPath,
|
||||
@@ -218,7 +218,7 @@ function primeNpmPluginFallback(pluginId = "demo") {
|
||||
loadConfig.mockReturnValue(cfg);
|
||||
mockClawHubPackageNotFound(pluginId);
|
||||
installPluginFromNpmSpec.mockResolvedValue(createNpmPluginInstallResult(pluginId));
|
||||
enablePluginInConfig.mockReturnValue({ config: enabledCfg });
|
||||
enablePluginInConfigMock.mockReturnValue({ config: enabledCfg });
|
||||
recordPluginInstall.mockReturnValue(enabledCfg);
|
||||
applyExclusiveSlotSelection.mockReturnValue({
|
||||
config: enabledCfg,
|
||||
@@ -233,7 +233,7 @@ function primeSuccessfulPluginPersistence(pluginId = "demo") {
|
||||
const enabledCfg = createEnabledPluginConfig(pluginId);
|
||||
|
||||
loadConfig.mockReturnValue(cfg);
|
||||
enablePluginInConfig.mockReturnValue({ config: enabledCfg });
|
||||
enablePluginInConfigMock.mockReturnValue({ config: enabledCfg });
|
||||
recordPluginInstall.mockReturnValue(enabledCfg);
|
||||
applyExclusiveSlotSelection.mockReturnValue({
|
||||
config: enabledCfg,
|
||||
@@ -1268,7 +1268,7 @@ describe("plugins cli install", () => {
|
||||
marketplaceSource: "local/repo",
|
||||
marketplacePlugin: "alpha",
|
||||
});
|
||||
enablePluginInConfig.mockReturnValue({ config: enabledCfg });
|
||||
enablePluginInConfigMock.mockReturnValue({ config: enabledCfg });
|
||||
buildPluginSnapshotReport.mockReturnValue({
|
||||
plugins: [{ id: "alpha", kind: "provider" }],
|
||||
diagnostics: [],
|
||||
@@ -1748,7 +1748,7 @@ describe("plugins cli install", () => {
|
||||
expect(record.source).toBe("path");
|
||||
expect(String(record.sourcePath)).toContain(pluginId);
|
||||
expect(String(record.installPath)).toContain(pluginId);
|
||||
expect(enablePluginInConfig).not.toHaveBeenCalled();
|
||||
expect(enablePluginInConfigMock).not.toHaveBeenCalled();
|
||||
expect(applyExclusiveSlotSelection).not.toHaveBeenCalled();
|
||||
expect(runtimeLogsContain("requires configuration first")).toBe(true);
|
||||
});
|
||||
@@ -1782,7 +1782,7 @@ describe("plugins cli install", () => {
|
||||
);
|
||||
|
||||
expect(writeConfigFile).not.toHaveBeenCalled();
|
||||
expect(enablePluginInConfig).not.toHaveBeenCalled();
|
||||
expect(enablePluginInConfigMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("enables config-gated bundled installs when provider-backed config is explicit", async () => {
|
||||
@@ -1814,11 +1814,11 @@ describe("plugins cli install", () => {
|
||||
},
|
||||
requiresConfig: true,
|
||||
});
|
||||
enablePluginInConfig.mockReturnValue({ config: enabledCfg });
|
||||
enablePluginInConfigMock.mockReturnValue({ config: enabledCfg });
|
||||
|
||||
await runPluginsCommand(["plugins", "install", pluginId]);
|
||||
|
||||
expect(enablePluginInConfig).toHaveBeenCalledTimes(1);
|
||||
expect(enablePluginInConfigMock).toHaveBeenCalledTimes(1);
|
||||
expect(writeConfigFile).toHaveBeenCalledWith(enabledCfg);
|
||||
expect(runtimeLogsContain("requires configuration first")).toBe(false);
|
||||
});
|
||||
@@ -2357,7 +2357,7 @@ describe("plugins cli install", () => {
|
||||
version: "1.2.3",
|
||||
extensions: ["./dist/index.js"],
|
||||
});
|
||||
enablePluginInConfig.mockReturnValue({ config: enabledCfg });
|
||||
enablePluginInConfigMock.mockReturnValue({ config: enabledCfg });
|
||||
recordPluginInstall.mockReturnValue(enabledCfg);
|
||||
applyExclusiveSlotSelection.mockReturnValue({
|
||||
config: enabledCfg,
|
||||
@@ -2562,7 +2562,7 @@ describe("plugins cli install", () => {
|
||||
extensions: [],
|
||||
};
|
||||
});
|
||||
enablePluginInConfig.mockReturnValue({ config: enabledCfg });
|
||||
enablePluginInConfigMock.mockReturnValue({ config: enabledCfg });
|
||||
recordPluginInstall.mockReturnValue(enabledCfg);
|
||||
applyExclusiveSlotSelection.mockReturnValue({
|
||||
config: enabledCfg,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import {
|
||||
buildPluginRegistrySnapshotReport,
|
||||
enablePluginInConfig,
|
||||
enablePluginInConfigMock,
|
||||
loadConfig,
|
||||
replaceConfigFile,
|
||||
refreshPluginRegistry,
|
||||
@@ -74,7 +74,7 @@ describe("plugins cli policy mutations", () => {
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
loadConfig.mockReturnValue(sourceConfig);
|
||||
enablePluginInConfig.mockReturnValue({
|
||||
enablePluginInConfigMock.mockReturnValue({
|
||||
config: enabledConfig,
|
||||
enabled: true,
|
||||
pluginId: "alpha",
|
||||
@@ -83,7 +83,7 @@ describe("plugins cli policy mutations", () => {
|
||||
|
||||
await runPluginsCommand(["plugins", "enable", "alpha"]);
|
||||
|
||||
expect(enablePluginInConfig).toHaveBeenCalledWith(sourceConfig, "alpha", {
|
||||
expect(enablePluginInConfigMock).toHaveBeenCalledWith(sourceConfig, "alpha", {
|
||||
updateChannelConfig: false,
|
||||
});
|
||||
expect(replaceConfigFile).toHaveBeenCalledWith({
|
||||
@@ -121,7 +121,7 @@ describe("plugins cli policy mutations", () => {
|
||||
])("fails without mutations when $policy blocks enablement", async ({ plugins, reason }) => {
|
||||
const sourceConfig = { plugins } as OpenClawConfig;
|
||||
loadConfig.mockReturnValue(sourceConfig);
|
||||
enablePluginInConfig.mockReturnValue({
|
||||
enablePluginInConfigMock.mockReturnValue({
|
||||
config: sourceConfig,
|
||||
enabled: false,
|
||||
pluginId: "alpha",
|
||||
@@ -153,7 +153,7 @@ describe("plugins cli policy mutations", () => {
|
||||
}
|
||||
}
|
||||
|
||||
expect(enablePluginInConfig).not.toHaveBeenCalled();
|
||||
expect(enablePluginInConfigMock).not.toHaveBeenCalled();
|
||||
expect(writeConfigFile).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -199,7 +199,7 @@ describe("plugins cli policy mutations", () => {
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
loadConfig.mockReturnValue(sourceConfig);
|
||||
enablePluginInConfig.mockReturnValue({
|
||||
enablePluginInConfigMock.mockReturnValue({
|
||||
config: enabledConfig,
|
||||
enabled: true,
|
||||
pluginId,
|
||||
@@ -208,7 +208,7 @@ describe("plugins cli policy mutations", () => {
|
||||
|
||||
await runPluginsCommand(["plugins", "enable", alias]);
|
||||
|
||||
expect(enablePluginInConfig).toHaveBeenCalledWith(sourceConfig, pluginId, {
|
||||
expect(enablePluginInConfigMock).toHaveBeenCalledWith(sourceConfig, pluginId, {
|
||||
updateChannelConfig: false,
|
||||
});
|
||||
expect(replaceConfigFile).toHaveBeenCalledWith({
|
||||
@@ -262,7 +262,7 @@ describe("plugins cli policy mutations", () => {
|
||||
expect(runtimeErrors).toContain(
|
||||
"Plugin not found: missing-plugin. Run `openclaw plugins list` to see installed plugins, or `openclaw plugins search missing-plugin` to look for installable plugins.",
|
||||
);
|
||||
expect(enablePluginInConfig).not.toHaveBeenCalled();
|
||||
expect(enablePluginInConfigMock).not.toHaveBeenCalled();
|
||||
expect(writeConfigFile).not.toHaveBeenCalled();
|
||||
expect(refreshPluginRegistry).not.toHaveBeenCalled();
|
||||
},
|
||||
|
||||
@@ -311,7 +311,7 @@ vi.mock("../infra/runtime-guard.js", () => ({
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/memory-runtime.js", () => ({
|
||||
closeActiveMemorySearchManagers: closeActiveMemorySearchManagersMock,
|
||||
closeActiveMemorySearchManagersCore: closeActiveMemorySearchManagersMock,
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/memory-state.js", () => ({
|
||||
|
||||
+3
-2
@@ -302,8 +302,9 @@ async function closeCliResources(): Promise<void> {
|
||||
async () => {
|
||||
const { hasMemoryRuntime } = await import("../plugins/memory-state.js");
|
||||
if (hasMemoryRuntime()) {
|
||||
const { closeActiveMemorySearchManagers } = await import("../plugins/memory-runtime.js");
|
||||
await closeActiveMemorySearchManagers();
|
||||
const { closeActiveMemorySearchManagersCore } =
|
||||
await import("../plugins/memory-runtime.js");
|
||||
await closeActiveMemorySearchManagersCore();
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
@@ -21,7 +21,7 @@ const resolveApiKeyForProvider = vi.hoisted(() => vi.fn());
|
||||
const hasAnyAuthProfileStoreSource = vi.hoisted(() => vi.fn(() => true));
|
||||
const hasAuthProfileStoreSourceForProvider = vi.hoisted(() => vi.fn(() => true));
|
||||
const isConfiguredAwsSdkAuthProfileForProvider = vi.hoisted(() => vi.fn(() => false));
|
||||
const getActiveMemorySearchManager = vi.hoisted(() => vi.fn());
|
||||
const getActiveMemorySearchManagerCore = vi.hoisted(() => vi.fn());
|
||||
const resolveActiveMemoryBackendConfig = vi.hoisted(() => vi.fn());
|
||||
const auditDreamingArtifacts = vi.hoisted(() => vi.fn());
|
||||
const auditShortTermPromotionArtifacts = vi.hoisted(() => vi.fn());
|
||||
@@ -58,7 +58,7 @@ vi.mock("../agents/auth-profiles.js", () => ({
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/memory-runtime.js", () => ({
|
||||
getActiveMemorySearchManager,
|
||||
getActiveMemorySearchManagerCore,
|
||||
resolveActiveMemoryBackendConfig,
|
||||
}));
|
||||
|
||||
@@ -302,10 +302,10 @@ describe("noteMemorySearchHealth", () => {
|
||||
hasAuthProfileStoreSourceForProvider.mockReturnValue(true);
|
||||
isConfiguredAwsSdkAuthProfileForProvider.mockReset();
|
||||
isConfiguredAwsSdkAuthProfileForProvider.mockReturnValue(false);
|
||||
getActiveMemorySearchManager.mockReset();
|
||||
getActiveMemorySearchManagerCore.mockReset();
|
||||
resolveActiveMemoryBackendConfig.mockReset();
|
||||
resolveActiveMemoryBackendConfig.mockReturnValue({ backend: "builtin" });
|
||||
getActiveMemorySearchManager.mockResolvedValue({
|
||||
getActiveMemorySearchManagerCore.mockResolvedValue({
|
||||
manager: {
|
||||
status: () => ({ workspaceDir: "/tmp/agent-default/workspace", backend: "builtin" }),
|
||||
close: vi.fn(async () => {}),
|
||||
@@ -1094,7 +1094,7 @@ describe("memory recall doctor integration", () => {
|
||||
);
|
||||
resetMemoryRecallMocks();
|
||||
resolveActiveMemoryBackendConfig.mockReturnValue({ backend: "builtin" });
|
||||
getActiveMemorySearchManager.mockResolvedValue({
|
||||
getActiveMemorySearchManagerCore.mockResolvedValue({
|
||||
manager: {
|
||||
status: () => ({ workspaceDir: "/tmp/agent-default/workspace", backend: "builtin" }),
|
||||
close: vi.fn(async () => {}),
|
||||
@@ -1262,12 +1262,12 @@ describe("memory recall doctor integration", () => {
|
||||
});
|
||||
|
||||
it("audits and repairs each agent with isolated managers and paths", async () => {
|
||||
getActiveMemorySearchManager.mockClear();
|
||||
getActiveMemorySearchManagerCore.mockClear();
|
||||
listAgentIds.mockReturnValue(["agent-default", "secondary"]);
|
||||
resolveAgentDir.mockImplementation((_cfg, agentId) => `/tmp/${agentId}`);
|
||||
resolveAgentWorkspaceDir.mockImplementation((_cfg, agentId) => `/tmp/${agentId}/workspace`);
|
||||
const closes = new Map<string, ReturnType<typeof vi.fn>>();
|
||||
getActiveMemorySearchManager.mockImplementation(async ({ agentId }) => {
|
||||
getActiveMemorySearchManagerCore.mockImplementation(async ({ agentId }) => {
|
||||
const close = vi.fn(async () => {});
|
||||
closes.set(agentId, close);
|
||||
return {
|
||||
@@ -1305,7 +1305,7 @@ describe("memory recall doctor integration", () => {
|
||||
|
||||
await maybeRepairMemoryRecallHealth({ cfg, prompter });
|
||||
|
||||
expect(getActiveMemorySearchManager).toHaveBeenCalledTimes(2);
|
||||
expect(getActiveMemorySearchManagerCore).toHaveBeenCalledTimes(2);
|
||||
expect(closes.get("agent-default")).toHaveBeenCalledOnce();
|
||||
expect(closes.get("secondary")).toHaveBeenCalledOnce();
|
||||
expect(repairShortTermPromotionArtifacts).toHaveBeenCalledTimes(1);
|
||||
|
||||
@@ -43,7 +43,7 @@ import {
|
||||
} from "../plugin-sdk/memory-core-bundled-runtime.js";
|
||||
import { normalizePluginsConfig } from "../plugins/config-state.js";
|
||||
import {
|
||||
getActiveMemorySearchManager,
|
||||
getActiveMemorySearchManagerCore,
|
||||
resolveActiveMemoryBackendConfig,
|
||||
} from "../plugins/memory-runtime.js";
|
||||
import { defaultSlotIdForKey } from "../plugins/slots.js";
|
||||
@@ -258,7 +258,7 @@ async function resolveRuntimeMemoryAuditContext(
|
||||
cfg: OpenClawConfig,
|
||||
agentId: string,
|
||||
): Promise<RuntimeMemoryAuditContext | null> {
|
||||
const result = await getActiveMemorySearchManager({
|
||||
const result = await getActiveMemorySearchManagerCore({
|
||||
cfg,
|
||||
agentId,
|
||||
purpose: "status",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { getTailnetHostname } from "../infra/tailscale.js";
|
||||
import type { MemoryProviderStatus } from "../memory-host-sdk/engine-storage.js";
|
||||
import { getActiveMemorySearchManager } from "../plugins/memory-runtime.js";
|
||||
import { getActiveMemorySearchManagerCore } from "../plugins/memory-runtime.js";
|
||||
|
||||
export { getTailnetHostname };
|
||||
|
||||
@@ -21,7 +21,7 @@ export async function getMemorySearchManager(params: {
|
||||
agentId: string;
|
||||
purpose: "status";
|
||||
}): Promise<{ manager: StatusMemoryManager | null }> {
|
||||
const { manager } = await getActiveMemorySearchManager(params);
|
||||
const { manager } = await getActiveMemorySearchManagerCore(params);
|
||||
if (!manager) {
|
||||
return { manager: null };
|
||||
}
|
||||
|
||||
@@ -533,7 +533,7 @@ vi.mock("../channels/config-presence.js", () => ({
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/memory-runtime.js", () => ({
|
||||
getActiveMemorySearchManager: vi.fn(async ({ agentId }: { agentId: string }) => ({
|
||||
getActiveMemorySearchManagerCore: vi.fn(async ({ agentId }: { agentId: string }) => ({
|
||||
manager: {
|
||||
probeVectorAvailability: vi.fn(async () => true),
|
||||
status: () => ({
|
||||
|
||||
@@ -54,7 +54,7 @@ vi.mock("../../agents/memory-search.js", () => ({
|
||||
}));
|
||||
|
||||
vi.mock("../../plugins/memory-runtime.js", () => ({
|
||||
getActiveMemorySearchManager: getMemorySearchManager,
|
||||
getActiveMemorySearchManagerCore: getMemorySearchManager,
|
||||
}));
|
||||
|
||||
vi.mock("./doctor.memory-core-runtime.js", () => ({
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
resolveMemoryDreamingWorkspaces,
|
||||
resolveMemoryRemDreamingConfig,
|
||||
} from "../../memory-host-sdk/dreaming.js";
|
||||
import { getActiveMemorySearchManager } from "../../plugins/memory-runtime.js";
|
||||
import { getActiveMemorySearchManagerCore } from "../../plugins/memory-runtime.js";
|
||||
import { normalizeAgentId } from "../../routing/session-key.js";
|
||||
import { formatError } from "../server-utils.js";
|
||||
import {
|
||||
@@ -707,7 +707,7 @@ export const doctorHandlers: GatewayRequestHandlers = {
|
||||
return;
|
||||
}
|
||||
const { cfg, agentId, requestedAgentId } = resolved;
|
||||
const { manager, error } = await getActiveMemorySearchManager({
|
||||
const { manager, error } = await getActiveMemorySearchManagerCore({
|
||||
cfg,
|
||||
agentId,
|
||||
purpose: "status",
|
||||
|
||||
@@ -8,10 +8,10 @@ import {
|
||||
} from "../../test-utils/openclaw-test-state.js";
|
||||
import type { GatewayRequestContext, RespondFn } from "./types.js";
|
||||
|
||||
const getActiveMemorySearchManager = vi.hoisted(() => vi.fn());
|
||||
const getActiveMemorySearchManagerCore = vi.hoisted(() => vi.fn());
|
||||
const resolveDefaultAgentId = vi.hoisted(() => vi.fn(() => "main"));
|
||||
|
||||
vi.mock("../../plugins/memory-runtime.js", () => ({ getActiveMemorySearchManager }));
|
||||
vi.mock("../../plugins/memory-runtime.js", () => ({ getActiveMemorySearchManagerCore }));
|
||||
vi.mock("../../agents/agent-scope.js", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("../../agents/agent-scope.js")>()),
|
||||
resolveDefaultAgentId,
|
||||
@@ -71,7 +71,7 @@ describe("memory.search gateway method", () => {
|
||||
label: "gateway-memory-search",
|
||||
layout: "state-only",
|
||||
});
|
||||
getActiveMemorySearchManager.mockReset();
|
||||
getActiveMemorySearchManagerCore.mockReset();
|
||||
resolveDefaultAgentId.mockClear();
|
||||
});
|
||||
|
||||
@@ -93,7 +93,7 @@ describe("memory.search gateway method", () => {
|
||||
}),
|
||||
);
|
||||
}
|
||||
expect(getActiveMemorySearchManager).not.toHaveBeenCalled();
|
||||
expect(getActiveMemorySearchManagerCore).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it.each([
|
||||
@@ -102,7 +102,7 @@ describe("memory.search gateway method", () => {
|
||||
])("clamps maxResults=$requested to $expected", async ({ requested, expected }) => {
|
||||
const cfg = createConfig(testState.workspaceDir);
|
||||
const manager = createStubManager();
|
||||
getActiveMemorySearchManager.mockResolvedValue({ manager });
|
||||
getActiveMemorySearchManagerCore.mockResolvedValue({ manager });
|
||||
|
||||
await invokeMemorySearch({ query: "lantern", maxResults: requested, minScore: 0.42 }, cfg);
|
||||
|
||||
@@ -126,7 +126,7 @@ describe("memory.search gateway method", () => {
|
||||
message: "unknown agentId",
|
||||
}),
|
||||
);
|
||||
expect(getActiveMemorySearchManager).not.toHaveBeenCalled();
|
||||
expect(getActiveMemorySearchManagerCore).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("rejects a non-string agentId without acquiring a manager", async () => {
|
||||
@@ -142,7 +142,7 @@ describe("memory.search gateway method", () => {
|
||||
message: "agentId must be a string",
|
||||
}),
|
||||
);
|
||||
expect(getActiveMemorySearchManager).not.toHaveBeenCalled();
|
||||
expect(getActiveMemorySearchManagerCore).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it.each([" ", "---", "ſ"])(
|
||||
@@ -161,7 +161,7 @@ describe("memory.search gateway method", () => {
|
||||
}),
|
||||
);
|
||||
expect(resolveDefaultAgentId).not.toHaveBeenCalled();
|
||||
expect(getActiveMemorySearchManager).not.toHaveBeenCalled();
|
||||
expect(getActiveMemorySearchManagerCore).not.toHaveBeenCalled();
|
||||
},
|
||||
);
|
||||
|
||||
@@ -184,11 +184,11 @@ describe("memory.search gateway method", () => {
|
||||
};
|
||||
const manager = createStubManager();
|
||||
manager.search.mockResolvedValue([result]);
|
||||
getActiveMemorySearchManager.mockResolvedValue({ manager });
|
||||
getActiveMemorySearchManagerCore.mockResolvedValue({ manager });
|
||||
|
||||
const respond = await invokeMemorySearch({ query: "lantern", agentId: requested }, cfg);
|
||||
|
||||
expect(getActiveMemorySearchManager).toHaveBeenCalledWith({
|
||||
expect(getActiveMemorySearchManagerCore).toHaveBeenCalledWith({
|
||||
cfg,
|
||||
agentId: configured,
|
||||
purpose: "cli",
|
||||
@@ -208,7 +208,7 @@ describe("memory.search gateway method", () => {
|
||||
|
||||
it("returns unavailable when no memory manager is configured", async () => {
|
||||
const cfg: OpenClawConfig = {};
|
||||
getActiveMemorySearchManager.mockResolvedValue({
|
||||
getActiveMemorySearchManagerCore.mockResolvedValue({
|
||||
manager: null,
|
||||
error: "memory plugin unavailable",
|
||||
});
|
||||
@@ -235,7 +235,7 @@ describe("memory.search gateway method", () => {
|
||||
dirty: true,
|
||||
custom: { searchMode: "fts-only" },
|
||||
});
|
||||
getActiveMemorySearchManager.mockResolvedValue({ manager });
|
||||
getActiveMemorySearchManagerCore.mockResolvedValue({ manager });
|
||||
|
||||
const respond = await invokeMemorySearch({ query: "hidden codeword" }, cfg);
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import type {
|
||||
MemorySearchResult,
|
||||
} from "../../memory-host-sdk/host/types.js";
|
||||
import { resolveMemorySearchStaleness } from "../../memory-host-sdk/host/types.js";
|
||||
import { getActiveMemorySearchManager } from "../../plugins/memory-runtime.js";
|
||||
import { getActiveMemorySearchManagerCore } from "../../plugins/memory-runtime.js";
|
||||
import { normalizeAgentId } from "../../routing/session-key.js";
|
||||
import type { GatewayRequestHandlers } from "./types.js";
|
||||
|
||||
@@ -108,11 +108,11 @@ export const memorySearchHandlers: GatewayRequestHandlers = {
|
||||
return;
|
||||
}
|
||||
const agentId = requestedAgentId ?? resolveDefaultAgentId(cfg);
|
||||
let acquired: Awaited<ReturnType<typeof getActiveMemorySearchManager>>;
|
||||
let acquired: Awaited<ReturnType<typeof getActiveMemorySearchManagerCore>>;
|
||||
try {
|
||||
// Use the transient CLI lifecycle so request cleanup cannot close a shared manager.
|
||||
// manager.search owns the same lazy/on-search sync behavior as the existing CLI path.
|
||||
acquired = await getActiveMemorySearchManager({
|
||||
acquired = await getActiveMemorySearchManagerCore({
|
||||
cfg,
|
||||
agentId,
|
||||
purpose: "cli",
|
||||
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
} from "../infra/outbound/delivery-queue-storage.js";
|
||||
import {
|
||||
ackDelivery,
|
||||
drainPendingDeliveries,
|
||||
drainPendingDeliveriesCore,
|
||||
failDelivery,
|
||||
failDeliveryAfterPlatformSend,
|
||||
failDeliveryBeforePlatformSend,
|
||||
@@ -188,7 +188,7 @@ async function drainFailedRestartSentinelNotice(params: {
|
||||
if (attemptCount < RESTART_NOTICE_MAX_ATTEMPTS) {
|
||||
await waitForRecoveryDrain();
|
||||
}
|
||||
await drainPendingDeliveries({
|
||||
await drainPendingDeliveriesCore({
|
||||
drainKey: `restart-recovery:${params.queueId}`,
|
||||
logLabel: `${params.summary}: restart notice recovery`,
|
||||
cfg: params.cfg,
|
||||
|
||||
@@ -309,7 +309,7 @@ vi.mock("../infra/outbound/delivery-queue.js", () => ({
|
||||
failDelivery: mocks.failDelivery,
|
||||
failDeliveryAfterPlatformSend: mocks.failDeliveryAfterPlatformSend,
|
||||
failDeliveryBeforePlatformSend: mocks.failDeliveryBeforePlatformSend,
|
||||
drainPendingDeliveries: mocks.drainPendingDeliveries,
|
||||
drainPendingDeliveriesCore: mocks.drainPendingDeliveries,
|
||||
withActiveDeliveryClaim: mocks.withActiveDeliveryClaim,
|
||||
}));
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
} from "../agents/subagents/completion/subagent-completion-delivery.js";
|
||||
import { REPLY_RUN_STILL_SHUTTING_DOWN_TEXT } from "../auto-reply/reply/get-reply-run-queue.js";
|
||||
import { finalizeInboundContext } from "../auto-reply/reply/inbound-context.js";
|
||||
import { dispatchReplyWithBufferedBlockDispatcher } from "../auto-reply/reply/provider-dispatcher.js";
|
||||
import { dispatchReplyWithBufferedBlockDispatcherCore } from "../auto-reply/reply/provider-dispatcher.js";
|
||||
import type { ChatType } from "../channels/chat-type.js";
|
||||
import { getChannelPlugin, normalizeChannelId } from "../channels/plugins/index.js";
|
||||
import { recordInboundSession } from "../channels/session.js";
|
||||
@@ -297,7 +297,7 @@ export async function deliverQueuedSessionDelivery(params: {
|
||||
storePath,
|
||||
ctxPayload,
|
||||
recordInboundSession,
|
||||
dispatchReplyWithBufferedBlockDispatcher,
|
||||
dispatchReplyWithBufferedBlockDispatcher: dispatchReplyWithBufferedBlockDispatcherCore,
|
||||
replyOptions: {
|
||||
sourceReplyDeliveryMode: "message_tool_only",
|
||||
},
|
||||
|
||||
@@ -19,7 +19,7 @@ function waitForFast<T>(
|
||||
type StartSessionDeliveryRuntime =
|
||||
typeof import("../infra/session-delivery-queue-runtime.js").startSessionDeliveryRuntime;
|
||||
type DrainPendingDeliveries =
|
||||
typeof import("../infra/outbound/delivery-queue.js").drainPendingDeliveries;
|
||||
typeof import("../infra/outbound/delivery-queue.js").drainPendingDeliveriesCore;
|
||||
type RecoverPendingDeliveries =
|
||||
typeof import("../infra/outbound/delivery-queue.js").recoverPendingDeliveries;
|
||||
|
||||
@@ -82,7 +82,7 @@ vi.mock("../infra/outbound/deliver.js", () => ({
|
||||
|
||||
vi.mock("../infra/outbound/delivery-queue.js", () => ({
|
||||
recoverPendingDeliveries: hoisted.recoverPendingDeliveries,
|
||||
drainPendingDeliveries: hoisted.drainPendingDeliveries,
|
||||
drainPendingDeliveriesCore: hoisted.drainPendingDeliveries,
|
||||
}));
|
||||
|
||||
vi.mock("../infra/session-delivery-queue-runtime.js", () => ({
|
||||
|
||||
@@ -201,7 +201,7 @@ function startPendingOutboundDeliveryRecovery(params: {
|
||||
if (stopped) {
|
||||
return;
|
||||
}
|
||||
const { drainPendingDeliveries, recoverPendingDeliveries } =
|
||||
const { drainPendingDeliveriesCore, recoverPendingDeliveries } =
|
||||
await import("../infra/outbound/delivery-queue.js");
|
||||
const { deliverOutboundPayloadsInternal } = await import("../infra/outbound/deliver.js");
|
||||
if (stopped) {
|
||||
@@ -218,7 +218,7 @@ function startPendingOutboundDeliveryRecovery(params: {
|
||||
}
|
||||
// Startup migration runs once. Normal retries use fresh config so revoked
|
||||
// accounts cannot inherit the authority captured at gateway startup.
|
||||
await drainPendingDeliveries({
|
||||
await drainPendingDeliveriesCore({
|
||||
drainKey: "gateway:outbound",
|
||||
logLabel: "Outbound delivery retry",
|
||||
cfg: getRuntimeConfig(),
|
||||
|
||||
@@ -56,7 +56,7 @@ import {
|
||||
connectOk,
|
||||
createGatewaySuiteHarness,
|
||||
dispatchInboundMessageMock,
|
||||
getReplyFromConfig,
|
||||
gatewayReplyMock,
|
||||
installGatewayTestHooks,
|
||||
mockGetReplyFromConfigOnce,
|
||||
onceMessage,
|
||||
@@ -4794,7 +4794,7 @@ describe("gateway server chat", () => {
|
||||
|
||||
test("chat.send does not force-disable block streaming", async () => {
|
||||
await withGatewayChatHarness(async ({ ws, createSessionDir }) => {
|
||||
const spy = getReplyFromConfig;
|
||||
const spy = gatewayReplyMock;
|
||||
await connectOk(ws);
|
||||
|
||||
await createSessionDir();
|
||||
@@ -4837,7 +4837,7 @@ describe("gateway server chat", () => {
|
||||
try {
|
||||
await withGatewayChatHarness(
|
||||
async ({ ws, createSessionDir }) => {
|
||||
const spy = getReplyFromConfig;
|
||||
const spy = gatewayReplyMock;
|
||||
await connectOk(ws, makeGatewayWebchatClient());
|
||||
|
||||
await createSessionDir();
|
||||
@@ -4966,7 +4966,7 @@ describe("gateway server chat", () => {
|
||||
test("chat.send forwards Control UI reconnect resume internally", async () => {
|
||||
await withGatewayChatHarness(
|
||||
async ({ ws, createSessionDir }) => {
|
||||
const spy = getReplyFromConfig;
|
||||
const spy = gatewayReplyMock;
|
||||
await connectOk(ws, makeGatewayWebchatClient());
|
||||
|
||||
await createSessionDir();
|
||||
@@ -5005,7 +5005,7 @@ describe("gateway server chat", () => {
|
||||
test("chat.send forwards one-turn queue mode overrides internally", async () => {
|
||||
await withGatewayChatHarness(
|
||||
async ({ ws, createSessionDir }) => {
|
||||
const spy = getReplyFromConfig;
|
||||
const spy = gatewayReplyMock;
|
||||
await connectOk(ws, makeGatewayWebchatClient());
|
||||
|
||||
await createSessionDir();
|
||||
@@ -6386,7 +6386,7 @@ describe("gateway server chat", () => {
|
||||
|
||||
test("smoke: supports abort and idempotent completion", async () => {
|
||||
await withGatewayChatHarness(async ({ ws, createSessionDir }) => {
|
||||
const spy = getReplyFromConfig;
|
||||
const spy = gatewayReplyMock;
|
||||
let aborted = false;
|
||||
await connectOk(ws);
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
dispatchRequest,
|
||||
withGatewayServer,
|
||||
} from "./server-http.test-harness.js";
|
||||
import { createTestRegistry } from "./server/__tests__/test-utils.js";
|
||||
import { createGatewayTestRegistry } from "./server/__tests__/test-utils.js";
|
||||
import { createGatewayPluginRequestHandler } from "./server/plugins-http.js";
|
||||
import { resolveSharedGatewaySessionGeneration } from "./server/ws-shared-generation.js";
|
||||
|
||||
@@ -61,7 +61,7 @@ function createRuntimeScopeRecorderHandler(params: {
|
||||
match?: "exact" | "prefix";
|
||||
}) {
|
||||
return createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({
|
||||
registry: createGatewayTestRegistry({
|
||||
httpRoutes: [
|
||||
{
|
||||
pluginId: params.pluginId,
|
||||
@@ -196,7 +196,7 @@ describe("control ui plugin frame auth route boundaries", () => {
|
||||
test("does not broaden an exact-route grant to child paths", async () => {
|
||||
const childHandler = vi.fn(async () => true);
|
||||
const handlePluginRequest = createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({
|
||||
registry: createGatewayTestRegistry({
|
||||
httpRoutes: [
|
||||
{
|
||||
pluginId: "exact-plugin",
|
||||
@@ -242,7 +242,7 @@ describe("control ui plugin frame auth route boundaries", () => {
|
||||
const outerHandler = vi.fn(async () => true);
|
||||
const adminHandler = vi.fn(async () => true);
|
||||
const handlePluginRequest = createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({
|
||||
registry: createGatewayTestRegistry({
|
||||
httpRoutes: [
|
||||
{
|
||||
pluginId: "same-plugin",
|
||||
@@ -488,7 +488,7 @@ describe("control ui plugin frame auth route boundaries", () => {
|
||||
const outerHandler = vi.fn(async () => true);
|
||||
const nestedHandler = vi.fn(async () => true);
|
||||
const handlePluginRequest = createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({
|
||||
registry: createGatewayTestRegistry({
|
||||
httpRoutes: [
|
||||
{
|
||||
pluginId: "outer-plugin",
|
||||
@@ -588,7 +588,7 @@ describe("control ui plugin frame auth route boundaries", () => {
|
||||
const nestedHandler = vi.fn(async () => true);
|
||||
const outerHandler = vi.fn(async () => true);
|
||||
const handlePluginRequest = createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({
|
||||
registry: createGatewayTestRegistry({
|
||||
httpRoutes: [
|
||||
{
|
||||
pluginId: "outer-plugin",
|
||||
@@ -653,7 +653,7 @@ describe("control ui plugin frame auth route boundaries", () => {
|
||||
const nestedHandler = vi.fn(async () => false);
|
||||
const outerHandler = vi.fn(async () => true);
|
||||
const handlePluginRequest = createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({
|
||||
registry: createGatewayTestRegistry({
|
||||
httpRoutes: [
|
||||
{
|
||||
pluginId: "nested-plugin",
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
withGatewayServer,
|
||||
withGatewayTempConfig,
|
||||
} from "./server-http.test-harness.js";
|
||||
import { createTestRegistry } from "./server/__tests__/test-utils.js";
|
||||
import { createGatewayTestRegistry } from "./server/__tests__/test-utils.js";
|
||||
import { createGatewayPluginRequestHandler } from "./server/plugins-http.js";
|
||||
import { withTempConfig } from "./test-temp-config.js";
|
||||
|
||||
@@ -119,7 +119,7 @@ function createRuntimeScopeRecorderHandler(params: {
|
||||
match?: "exact" | "prefix";
|
||||
}) {
|
||||
return createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({
|
||||
registry: createGatewayTestRegistry({
|
||||
httpRoutes: [
|
||||
{
|
||||
pluginId: params.pluginId,
|
||||
|
||||
@@ -5,7 +5,9 @@ import type { PluginRegistry } from "../../../plugins/registry.js";
|
||||
/**
|
||||
* Shared plugin-registry fixtures for gateway server tests.
|
||||
*/
|
||||
export const createTestRegistry = (overrides: Partial<PluginRegistry> = {}): PluginRegistry => {
|
||||
export const createGatewayTestRegistry = (
|
||||
overrides: Partial<PluginRegistry> = {},
|
||||
): PluginRegistry => {
|
||||
const registry = createEmptyPluginRegistry();
|
||||
for (const key of Object.keys(overrides) as Array<keyof PluginRegistry>) {
|
||||
const value = overrides[key];
|
||||
|
||||
@@ -13,7 +13,7 @@ import { authorizeOperatorScopesForMethod, CLI_DEFAULT_OPERATOR_SCOPES } from ".
|
||||
import { isApprovalRecordVisibleToClient } from "../server-methods/approval-shared.js";
|
||||
import type { GatewayRequestContext } from "../server-methods/types.js";
|
||||
import { makeMockHttpResponse } from "../test-http-response.js";
|
||||
import { createTestRegistry } from "./__tests__/test-utils.js";
|
||||
import { createGatewayTestRegistry } from "./__tests__/test-utils.js";
|
||||
import { createGatewayPluginRequestHandler } from "./plugins-http.js";
|
||||
|
||||
const SECURE_HOOK_PATH = "/secure-hook";
|
||||
@@ -80,11 +80,11 @@ function assertAdminHelperAllowed() {
|
||||
function createPluginRequestHandler(params: {
|
||||
routes: PluginHttpRoute[];
|
||||
log?: SubsystemLogger;
|
||||
getRouteRegistry?: () => ReturnType<typeof createTestRegistry>;
|
||||
getRouteRegistry?: () => ReturnType<typeof createGatewayTestRegistry>;
|
||||
getGatewayRequestContext?: () => GatewayRequestContext;
|
||||
}) {
|
||||
return createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({ httpRoutes: params.routes }),
|
||||
registry: createGatewayTestRegistry({ httpRoutes: params.routes }),
|
||||
...(params.getRouteRegistry ? { getRouteRegistry: params.getRouteRegistry } : {}),
|
||||
log: params.log ?? createMockLogger(),
|
||||
...(params.getGatewayRequestContext
|
||||
@@ -247,7 +247,7 @@ describe("plugin HTTP route runtime scopes", () => {
|
||||
const serverAContext = { label: "server-a" } as unknown as GatewayRequestContext;
|
||||
const serverBContext = { label: "server-b" } as unknown as GatewayRequestContext;
|
||||
const observed: Array<{ route: string; context?: GatewayRequestContext }> = [];
|
||||
const serverARegistry = createTestRegistry({
|
||||
const serverARegistry = createGatewayTestRegistry({
|
||||
httpRoutes: [
|
||||
createRoute({
|
||||
path: SECURE_HOOK_PATH,
|
||||
@@ -260,7 +260,7 @@ describe("plugin HTTP route runtime scopes", () => {
|
||||
}),
|
||||
],
|
||||
});
|
||||
const serverBRegistry = createTestRegistry({
|
||||
const serverBRegistry = createGatewayTestRegistry({
|
||||
httpRoutes: [
|
||||
createRoute({
|
||||
path: SECURE_HOOK_PATH,
|
||||
@@ -418,7 +418,7 @@ describe("plugin HTTP route runtime scopes", () => {
|
||||
const observed: Array<{ route: "exact" | "prefix"; scopes: string[] }> = [];
|
||||
const log = createMockLogger();
|
||||
const handler = createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({
|
||||
registry: createGatewayTestRegistry({
|
||||
httpRoutes: [
|
||||
createRoute({
|
||||
path: "/secure/admin-hook",
|
||||
@@ -487,7 +487,7 @@ describe("plugin HTTP route runtime scopes", () => {
|
||||
async ({ auth, gatewayAuthSatisfied, gatewayRequestOperatorScopes, path, expectedScopes }) => {
|
||||
let observedScopes: string[] | undefined;
|
||||
const handler = createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({
|
||||
registry: createGatewayTestRegistry({
|
||||
httpRoutes: [
|
||||
createRoute({
|
||||
path,
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
} from "../../process/gateway-work-admission.js";
|
||||
import type { GatewayRequestContext } from "../server-methods/types.js";
|
||||
import { makeMockHttpResponse } from "../test-http-response.js";
|
||||
import { createTestRegistry } from "./__tests__/test-utils.js";
|
||||
import { createGatewayTestRegistry } from "./__tests__/test-utils.js";
|
||||
import {
|
||||
createGatewayPluginRequestHandler,
|
||||
createGatewayPluginUpgradeHandler,
|
||||
@@ -99,7 +99,7 @@ function createRequestHandler(
|
||||
getGatewayRequestContext?: () => GatewayRequestContext,
|
||||
) {
|
||||
return createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({ httpRoutes: routes }),
|
||||
registry: createGatewayTestRegistry({ httpRoutes: routes }),
|
||||
log: createLog(),
|
||||
...(getGatewayRequestContext ? { getGatewayRequestContext } : {}),
|
||||
});
|
||||
@@ -107,7 +107,7 @@ function createRequestHandler(
|
||||
|
||||
function createUpgradeHandler(routes: PluginHttpRouteRegistration[]) {
|
||||
return createGatewayPluginUpgradeHandler({
|
||||
registry: createTestRegistry({ httpRoutes: routes }),
|
||||
registry: createGatewayTestRegistry({ httpRoutes: routes }),
|
||||
log: createLog(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { createEmptyPluginRegistry } from "../../plugins/registry.js";
|
||||
import { setActivePluginRegistry } from "../../plugins/runtime.js";
|
||||
import { getPluginRuntimeGatewayRequestScope } from "../../plugins/runtime/gateway-request-scope.js";
|
||||
import { makeMockHttpResponse } from "../test-http-response.js";
|
||||
import { createTestRegistry } from "./__tests__/test-utils.js";
|
||||
import { createGatewayTestRegistry } from "./__tests__/test-utils.js";
|
||||
import {
|
||||
createGatewayPluginUpgradeHandler,
|
||||
createGatewayPluginRequestHandler,
|
||||
@@ -72,7 +72,7 @@ function createSecurePluginRouteHandler(params: {
|
||||
prefixGatewayHandler: () => boolean | Promise<boolean>;
|
||||
}) {
|
||||
return createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({
|
||||
registry: createGatewayTestRegistry({
|
||||
httpRoutes: [
|
||||
createRoute({
|
||||
path: "/plugin/secure/report",
|
||||
@@ -123,7 +123,7 @@ async function invokeRouteAndCollectRuntimeScopes(params: {
|
||||
}) {
|
||||
let observedScopes: string[] | undefined;
|
||||
const handler = createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({
|
||||
registry: createGatewayTestRegistry({
|
||||
httpRoutes: [
|
||||
createRoute({
|
||||
path: params.path,
|
||||
@@ -150,7 +150,7 @@ async function invokeRouteAndCollectRuntimeScopes(params: {
|
||||
async function invokeCanvasGatewayUpgrade(params: { gatewayAuthSatisfied: boolean }) {
|
||||
const routeUpgradeHandler = vi.fn(async () => true);
|
||||
const handler = createGatewayPluginUpgradeHandler({
|
||||
registry: createTestRegistry({
|
||||
registry: createGatewayTestRegistry({
|
||||
httpRoutes: [
|
||||
createRoute({
|
||||
path: CANVAS_WS_PATH,
|
||||
@@ -208,7 +208,7 @@ describe("createGatewayPluginRequestHandler", () => {
|
||||
it("returns false when no routes are registered", async () => {
|
||||
const log = createPluginLog();
|
||||
const handler = createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry(),
|
||||
registry: createGatewayTestRegistry(),
|
||||
log,
|
||||
});
|
||||
const { res } = makeMockHttpResponse();
|
||||
@@ -221,7 +221,7 @@ describe("createGatewayPluginRequestHandler", () => {
|
||||
res.statusCode = 200;
|
||||
});
|
||||
const handler = createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({
|
||||
registry: createGatewayTestRegistry({
|
||||
httpRoutes: [createRoute({ path: "/demo", handler: routeHandler })],
|
||||
}),
|
||||
log: createPluginLog(),
|
||||
@@ -239,7 +239,7 @@ describe("createGatewayPluginRequestHandler", () => {
|
||||
});
|
||||
const prefixHandler = vi.fn(async () => true);
|
||||
const handler = createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({
|
||||
registry: createGatewayTestRegistry({
|
||||
httpRoutes: [
|
||||
createRoute({ path: "/api", match: "prefix", handler: prefixHandler }),
|
||||
createRoute({ path: "/api/demo", match: "exact", handler: exactHandler }),
|
||||
@@ -259,7 +259,7 @@ describe("createGatewayPluginRequestHandler", () => {
|
||||
const first = vi.fn(async () => false);
|
||||
const second = vi.fn(async () => true);
|
||||
const handler = createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({
|
||||
registry: createGatewayTestRegistry({
|
||||
httpRoutes: [
|
||||
createRoute({ path: "/hook", match: "exact", handler: first }),
|
||||
createRoute({ path: "/hook", match: "prefix", handler: second }),
|
||||
@@ -288,7 +288,7 @@ describe("createGatewayPluginRequestHandler", () => {
|
||||
const warn = vi.fn();
|
||||
const log = { warn } as unknown as PluginHandlerLog;
|
||||
const handler = createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({
|
||||
registry: createGatewayTestRegistry({
|
||||
httpRoutes: [createRoute({ path: "/webhooks/sms", auth: "gateway" })],
|
||||
}),
|
||||
log,
|
||||
@@ -337,7 +337,7 @@ describe("createGatewayPluginRequestHandler", () => {
|
||||
res.statusCode = 200;
|
||||
});
|
||||
const handler = createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({
|
||||
registry: createGatewayTestRegistry({
|
||||
httpRoutes: [createRoute({ path: "/api/demo", handler: routeHandler })],
|
||||
}),
|
||||
log: createPluginLog(),
|
||||
@@ -354,7 +354,7 @@ describe("createGatewayPluginRequestHandler", () => {
|
||||
res.statusCode = 200;
|
||||
return true;
|
||||
});
|
||||
const explicitRegistry = createTestRegistry({
|
||||
const explicitRegistry = createGatewayTestRegistry({
|
||||
httpRoutes: [createRoute({ path: "/demo", auth: "plugin", handler: explicitRouteHandler })],
|
||||
});
|
||||
|
||||
@@ -372,7 +372,7 @@ describe("createGatewayPluginRequestHandler", () => {
|
||||
it("logs and responds with 500 when a route throws", async () => {
|
||||
const log = createPluginLog();
|
||||
const handler = createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({
|
||||
registry: createGatewayTestRegistry({
|
||||
httpRoutes: [
|
||||
createRoute({
|
||||
path: "/boom",
|
||||
@@ -397,7 +397,7 @@ describe("createGatewayPluginRequestHandler", () => {
|
||||
it("ends a plugin route response when the route throws after sending headers", async () => {
|
||||
const log = createPluginLog();
|
||||
const handler = createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({
|
||||
registry: createGatewayTestRegistry({
|
||||
httpRoutes: [
|
||||
createRoute({
|
||||
path: "/partial",
|
||||
@@ -477,7 +477,7 @@ describe("createGatewayPluginRequestHandler", () => {
|
||||
async ({ setContentLength }) => {
|
||||
const log = createPluginLog();
|
||||
const handler = createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({
|
||||
registry: createGatewayTestRegistry({
|
||||
httpRoutes: [
|
||||
createRoute({
|
||||
path: "/incomplete",
|
||||
@@ -522,7 +522,7 @@ describe("createGatewayPluginRequestHandler", () => {
|
||||
it("does not end a response the plugin already destroyed before throwing", async () => {
|
||||
const log = createPluginLog();
|
||||
const handler = createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({
|
||||
registry: createGatewayTestRegistry({
|
||||
httpRoutes: [
|
||||
createRoute({
|
||||
path: "/destroyed",
|
||||
@@ -581,7 +581,7 @@ describe("plugin HTTP route auth checks", () => {
|
||||
const decodeOverflowPublicPath = `/googlechat${buildRepeatedEncodedSlash(40)}public`;
|
||||
|
||||
it("detects registered route paths", () => {
|
||||
const registry = createTestRegistry({
|
||||
const registry = createGatewayTestRegistry({
|
||||
httpRoutes: [createRoute({ path: "/demo" })],
|
||||
});
|
||||
expect(isRegisteredPluginHttpRoutePath(registry, "/demo")).toBe(true);
|
||||
@@ -589,7 +589,7 @@ describe("plugin HTTP route auth checks", () => {
|
||||
});
|
||||
|
||||
it("matches canonicalized variants of registered route paths", () => {
|
||||
const registry = createTestRegistry({
|
||||
const registry = createGatewayTestRegistry({
|
||||
httpRoutes: [createRoute({ path: "/api/demo" })],
|
||||
});
|
||||
expect(isRegisteredPluginHttpRoutePath(registry, "/api//demo")).toBe(true);
|
||||
@@ -598,7 +598,7 @@ describe("plugin HTTP route auth checks", () => {
|
||||
});
|
||||
|
||||
it("enforces auth for protected and gateway-auth routes", () => {
|
||||
const registry = createTestRegistry({
|
||||
const registry = createGatewayTestRegistry({
|
||||
httpRoutes: [
|
||||
createRoute({ path: "/googlechat", match: "prefix", auth: "plugin" }),
|
||||
createRoute({ path: "/api/demo", auth: "gateway" }),
|
||||
@@ -613,7 +613,7 @@ describe("plugin HTTP route auth checks", () => {
|
||||
});
|
||||
|
||||
it("enforces auth when any overlapping matched route requires gateway auth", () => {
|
||||
const registry = createTestRegistry({
|
||||
const registry = createGatewayTestRegistry({
|
||||
httpRoutes: [
|
||||
createRoute({ path: "/plugin/secure/report", match: "exact", auth: "plugin" }),
|
||||
createRoute({ path: "/plugin/secure", match: "prefix", auth: "gateway" }),
|
||||
|
||||
@@ -160,9 +160,9 @@ export const agentDiscoveryMock = gatewayTestHoisted.agentDiscoveryMock;
|
||||
export const cronIsolatedRun = gatewayTestHoisted.cronIsolatedRun;
|
||||
export const agentCommand = gatewayTestHoisted.agentCommand;
|
||||
export const dispatchInboundMessageMock = gatewayTestHoisted.dispatchInboundMessage;
|
||||
export const getReplyFromConfig = gatewayTestHoisted.getReplyFromConfig;
|
||||
export const gatewayReplyMock = gatewayTestHoisted.getReplyFromConfig;
|
||||
export const mockGetReplyFromConfigOnce = (impl: GetReplyFromConfigFn) => {
|
||||
getReplyFromConfig.mockImplementationOnce(impl);
|
||||
gatewayReplyMock.mockImplementationOnce(impl);
|
||||
};
|
||||
export const sendWhatsAppMock = gatewayTestHoisted.sendWhatsAppMock;
|
||||
export const testState = gatewayTestHoisted.testState;
|
||||
|
||||
@@ -66,7 +66,7 @@ import {
|
||||
agentCommand,
|
||||
cronIsolatedRun,
|
||||
embeddedRunMock,
|
||||
getReplyFromConfig,
|
||||
gatewayReplyMock,
|
||||
agentDiscoveryMock,
|
||||
sendWhatsAppMock,
|
||||
setTestConfigRoot,
|
||||
@@ -443,8 +443,8 @@ async function resetGatewayTestState(options: { uniqueConfigRoot: boolean }) {
|
||||
cronIsolatedRun.mockResolvedValue({ status: "ok", summary: "ok" });
|
||||
agentCommand.mockReset();
|
||||
agentCommand.mockResolvedValue(undefined);
|
||||
getReplyFromConfig.mockReset();
|
||||
getReplyFromConfig.mockResolvedValue(undefined);
|
||||
gatewayReplyMock.mockReset();
|
||||
gatewayReplyMock.mockResolvedValue(undefined);
|
||||
sendWhatsAppMock.mockReset();
|
||||
sendWhatsAppMock.mockResolvedValue({ messageId: "msg-1", toJid: "jid-1" });
|
||||
embeddedRunMock.activeIds.clear();
|
||||
@@ -540,8 +540,8 @@ async function resetGatewayTestRuntimeOnly() {
|
||||
cronIsolatedRun.mockResolvedValue({ status: "ok", summary: "ok" });
|
||||
agentCommand.mockReset();
|
||||
agentCommand.mockResolvedValue(undefined);
|
||||
getReplyFromConfig.mockReset();
|
||||
getReplyFromConfig.mockResolvedValue(undefined);
|
||||
gatewayReplyMock.mockReset();
|
||||
gatewayReplyMock.mockResolvedValue(undefined);
|
||||
sendWhatsAppMock.mockReset();
|
||||
sendWhatsAppMock.mockResolvedValue({ messageId: "msg-1", toJid: "jid-1" });
|
||||
embeddedRunMock.activeIds.clear();
|
||||
|
||||
@@ -6,7 +6,7 @@ export {
|
||||
cronIsolatedRun,
|
||||
dispatchInboundMessageMock,
|
||||
embeddedRunMock,
|
||||
getReplyFromConfig,
|
||||
gatewayReplyMock,
|
||||
mockGetReplyFromConfigOnce,
|
||||
agentDiscoveryMock,
|
||||
testState,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Covers fixed-window rate limiter boundaries.
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { createFixedWindowRateLimiter } from "./fixed-window-rate-limit.js";
|
||||
import { createFixedWindowBudget } from "./fixed-window-rate-limit.js";
|
||||
|
||||
function expectConsumeResult(
|
||||
result: { allowed: boolean; remaining: number; retryAfterMs: number },
|
||||
@@ -14,7 +14,7 @@ function expectConsumeResult(
|
||||
describe("fixed-window rate limiter", () => {
|
||||
it("blocks after max requests until window reset", () => {
|
||||
let nowMs = 1_000;
|
||||
const limiter = createFixedWindowRateLimiter({
|
||||
const limiter = createFixedWindowBudget({
|
||||
maxRequests: 2,
|
||||
windowMs: 1_000,
|
||||
now: () => nowMs,
|
||||
@@ -30,7 +30,7 @@ describe("fixed-window rate limiter", () => {
|
||||
|
||||
it("clamps maxRequests and windowMs to at least one", () => {
|
||||
let nowMs = 100;
|
||||
const limiter = createFixedWindowRateLimiter({
|
||||
const limiter = createFixedWindowBudget({
|
||||
maxRequests: 0.2,
|
||||
windowMs: 0.4,
|
||||
now: () => nowMs,
|
||||
@@ -45,7 +45,7 @@ describe("fixed-window rate limiter", () => {
|
||||
|
||||
it("falls back to minimums for non-finite required values", () => {
|
||||
let nowMs = 100;
|
||||
const limiter = createFixedWindowRateLimiter({
|
||||
const limiter = createFixedWindowBudget({
|
||||
maxRequests: Number.NaN,
|
||||
windowMs: Number.POSITIVE_INFINITY,
|
||||
now: () => nowMs,
|
||||
@@ -60,7 +60,7 @@ describe("fixed-window rate limiter", () => {
|
||||
|
||||
it("reports the remaining retry window after later blocked attempts", () => {
|
||||
let nowMs = 1_000;
|
||||
const limiter = createFixedWindowRateLimiter({
|
||||
const limiter = createFixedWindowBudget({
|
||||
maxRequests: 1,
|
||||
windowMs: 1_000,
|
||||
now: () => nowMs,
|
||||
@@ -73,7 +73,7 @@ describe("fixed-window rate limiter", () => {
|
||||
});
|
||||
|
||||
it("supports explicit reset", () => {
|
||||
const limiter = createFixedWindowRateLimiter({
|
||||
const limiter = createFixedWindowBudget({
|
||||
maxRequests: 1,
|
||||
windowMs: 10_000,
|
||||
});
|
||||
|
||||
@@ -30,7 +30,7 @@ export function resolveFixedWindowRateLimitInteger(
|
||||
}
|
||||
|
||||
/** Creates a fixed-window counter that reports allowance, remaining quota, and retry delay. */
|
||||
export function createFixedWindowRateLimiter(params: {
|
||||
export function createFixedWindowBudget(params: {
|
||||
/** Maximum successful consume calls allowed per window. */
|
||||
maxRequests: number;
|
||||
/** Fixed window duration in milliseconds. */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { ChannelOutboundAdapter } from "../../channels/plugins/types.public.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { drainPendingDeliveries, type DeliverFn } from "./delivery-queue.js";
|
||||
import { drainPendingDeliveriesCore, type DeliverFn } from "./delivery-queue.js";
|
||||
import { createRecoveryLog } from "./delivery-queue.test-helpers.js";
|
||||
|
||||
export const boundedCronCompletionRetention = {
|
||||
@@ -55,7 +55,7 @@ export async function drainMatrixReconnect(opts: {
|
||||
deliver: DeliverFn;
|
||||
stateDir: string;
|
||||
}): Promise<void> {
|
||||
await drainPendingDeliveries({
|
||||
await drainPendingDeliveriesCore({
|
||||
drainKey: "matrix:reconnect-test",
|
||||
logLabel: "Matrix reconnect drain",
|
||||
cfg: {} as OpenClawConfig,
|
||||
|
||||
@@ -13,7 +13,7 @@ import { createOutboundTestPlugin, createTestRegistry } from "../../test-utils/c
|
||||
import { PlatformMessageNotDispatchedError } from "./deliver-types.js";
|
||||
import { collectEntrySpoolPaths } from "./delivery-queue-media-spool.js";
|
||||
import { loadPendingDeliveries } from "./delivery-queue-storage.js";
|
||||
import { drainPendingDeliveries, type DeliverFn } from "./delivery-queue.js";
|
||||
import { drainPendingDeliveriesCore, type DeliverFn } from "./delivery-queue.js";
|
||||
import {
|
||||
createRecoveryLog,
|
||||
installDeliveryQueueTmpDirHooks,
|
||||
@@ -151,7 +151,7 @@ describe("delivery-queue MEDIA-directive durability (end-to-end)", () => {
|
||||
const recovered: RecoveredSend[] = [];
|
||||
installMatrixAdapter(recoveryPhaseAdapter(recovered, spoolRoot));
|
||||
const deliver = vi.fn<DeliverFn>(async (params) => deliverOutboundPayloads(params));
|
||||
await drainPendingDeliveries({
|
||||
await drainPendingDeliveriesCore({
|
||||
drainKey: "media-directive-test",
|
||||
logLabel: "media-directive drain",
|
||||
cfg,
|
||||
|
||||
@@ -1213,7 +1213,7 @@ async function drainQueuedEntry(opts: {
|
||||
}
|
||||
}
|
||||
|
||||
export async function drainPendingDeliveries(opts: {
|
||||
export async function drainPendingDeliveriesCore(opts: {
|
||||
drainKey: string;
|
||||
logLabel: string;
|
||||
cfg: OpenClawConfig;
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
} from "./delivery-queue-storage.js";
|
||||
import {
|
||||
type DeliverFn,
|
||||
drainPendingDeliveries,
|
||||
drainPendingDeliveriesCore,
|
||||
enqueueDelivery,
|
||||
failDelivery,
|
||||
type RecoveryLogger,
|
||||
@@ -89,7 +89,7 @@ async function drainDirectChatReconnectPending(opts: {
|
||||
stateDir: string;
|
||||
}) {
|
||||
const normalizedAccountId = normalizeReconnectAccountIdForTest(opts.accountId);
|
||||
await drainPendingDeliveries({
|
||||
await drainPendingDeliveriesCore({
|
||||
drainKey: `directchat:${normalizedAccountId}`,
|
||||
logLabel: "DirectChat reconnect drain",
|
||||
cfg: stubCfg,
|
||||
@@ -143,7 +143,7 @@ async function enqueueFailedDirectChatDelivery(params: {
|
||||
return id;
|
||||
}
|
||||
|
||||
describe("drainPendingDeliveries for reconnect", () => {
|
||||
describe("drainPendingDeliveriesCore for reconnect", () => {
|
||||
let tmpDir: string;
|
||||
const fixtures = installDeliveryQueueTmpDirHooks();
|
||||
|
||||
@@ -200,7 +200,7 @@ describe("drainPendingDeliveries for reconnect", () => {
|
||||
{ channel: entry.channel, messageId: `${entry.channel}-delivered` },
|
||||
]);
|
||||
const drain = () =>
|
||||
drainPendingDeliveries({
|
||||
drainPendingDeliveriesCore({
|
||||
drainKey: "gateway:outbound",
|
||||
logLabel: "Outbound delivery retry",
|
||||
cfg: stubCfg,
|
||||
@@ -266,7 +266,7 @@ describe("drainPendingDeliveries for reconnect", () => {
|
||||
});
|
||||
const deliver = vi.fn<DeliverFn>(async () => []);
|
||||
|
||||
await drainPendingDeliveries({
|
||||
await drainPendingDeliveriesCore({
|
||||
drainKey: "gateway:outbound",
|
||||
logLabel: "Outbound delivery retry",
|
||||
cfg,
|
||||
@@ -644,7 +644,7 @@ describe("drainPendingDeliveries for reconnect", () => {
|
||||
const id = await enqueueFailedDirectChatDelivery({ accountId: "acct1", stateDir: tmpDir });
|
||||
let mutated = false;
|
||||
|
||||
await drainPendingDeliveries({
|
||||
await drainPendingDeliveriesCore({
|
||||
drainKey: "directchat:acct1",
|
||||
logLabel: "DirectChat reconnect drain",
|
||||
cfg: stubCfg,
|
||||
|
||||
@@ -15,7 +15,7 @@ export {
|
||||
} from "./delivery-queue-platform-lease.js";
|
||||
export type { QueuedReplyPayloadSendingHook } from "./delivery-queue-storage.js";
|
||||
export {
|
||||
drainPendingDeliveries,
|
||||
drainPendingDeliveriesCore,
|
||||
recoverPendingDeliveries,
|
||||
withActiveDeliveryClaim,
|
||||
} from "./delivery-queue-recovery.js";
|
||||
|
||||
@@ -74,7 +74,7 @@ import {
|
||||
} from "./state-migrations.exec-approvals.js";
|
||||
import {
|
||||
existsDir,
|
||||
fileExists,
|
||||
migrationFileExists,
|
||||
readSessionStoreJson5,
|
||||
safeReadDir,
|
||||
} from "./state-migrations.fs.js";
|
||||
@@ -289,7 +289,7 @@ async function detectManagedWorktreeStateMigration(params: {
|
||||
}): Promise<LegacyStateDetection["worktrees"]> {
|
||||
const rawRoot = path.join(params.stateDir, "worktrees");
|
||||
const stateEnv = { ...params.env, OPENCLAW_STATE_DIR: params.stateDir };
|
||||
const databaseExists = fileExists(resolveOpenClawStateSqlitePath(stateEnv));
|
||||
const databaseExists = migrationFileExists(resolveOpenClawStateSqlitePath(stateEnv));
|
||||
const hasCurrentSchema = params.stateSchemaMigrations.length === 0;
|
||||
const hasLegacy =
|
||||
params.doctorOnlyStateMigrations === true &&
|
||||
@@ -388,10 +388,10 @@ export async function detectLegacyStateMigrations(params: {
|
||||
const { preserveForeignMainAliases } = sessionStoreOwnership;
|
||||
const legacySessionEntries = safeReadDir(sessionsLegacyDir);
|
||||
const hasLegacySessions =
|
||||
fileExists(sessionsLegacyStorePath) ||
|
||||
migrationFileExists(sessionsLegacyStorePath) ||
|
||||
legacySessionEntries.some((e) => e.isFile() && e.name.endsWith(".jsonl"));
|
||||
|
||||
const targetSessionParsed = fileExists(sessionsTargetStorePath)
|
||||
const targetSessionParsed = migrationFileExists(sessionsTargetStorePath)
|
||||
? readSessionStoreJson5(sessionsTargetStorePath)
|
||||
: { store: {}, ok: true };
|
||||
const legacySessionSurfaces = params.legacySessionSurfaces;
|
||||
@@ -423,13 +423,13 @@ export async function detectLegacyStateMigrations(params: {
|
||||
const targetAgentDir = path.join(stateDir, "agents", targetAgentId, "agent");
|
||||
const hasLegacyAgentDir = existsDir(legacyAgentDir);
|
||||
const pluginStateSidecarPath = resolveLegacyPluginStateSidecarPath(stateDir);
|
||||
const hasPluginStateSidecar = fileExists(pluginStateSidecarPath);
|
||||
const hasPluginStateSidecar = migrationFileExists(pluginStateSidecarPath);
|
||||
const hasPendingPluginStateSidecarArchive = hasPendingSqliteSidecarArchive(
|
||||
pluginStateSidecarPath,
|
||||
PLUGIN_STATE_SQLITE_SIDECAR_SUFFIXES,
|
||||
);
|
||||
const pluginInstallIndexPath = resolveLegacyInstalledPluginIndexStorePath({ stateDir });
|
||||
const hasPluginInstallIndex = fileExists(pluginInstallIndexPath);
|
||||
const hasPluginInstallIndex = migrationFileExists(pluginInstallIndexPath);
|
||||
const debugProxyCaptureSidecar = detectLegacyDebugProxyCaptureSidecar(stateDir, env);
|
||||
const stateSchemaMigrations = detectOpenClawStateDatabaseSchemaMigrations({
|
||||
env: { ...env, OPENCLAW_STATE_DIR: stateDir },
|
||||
@@ -451,8 +451,8 @@ export async function detectLegacyStateMigrations(params: {
|
||||
TASK_STATE_SQLITE_SIDECAR_SUFFIXES,
|
||||
);
|
||||
const hasTaskStateSidecars =
|
||||
fileExists(taskRunsSidecarPath) ||
|
||||
fileExists(flowRunsSidecarPath) ||
|
||||
migrationFileExists(taskRunsSidecarPath) ||
|
||||
migrationFileExists(flowRunsSidecarPath) ||
|
||||
hasPendingTaskRunsSidecarArchive ||
|
||||
hasPendingFlowRunsSidecarArchive;
|
||||
const deliveryQueuePaths = {
|
||||
@@ -468,25 +468,28 @@ export async function detectLegacyStateMigrations(params: {
|
||||
triggersPath: resolveLegacyVoiceWakeTriggersPath(stateDir),
|
||||
routingPath: resolveLegacyVoiceWakeRoutingPath(stateDir),
|
||||
};
|
||||
const hasVoiceWake = fileExists(voiceWake.triggersPath) || fileExists(voiceWake.routingPath);
|
||||
const hasVoiceWake =
|
||||
migrationFileExists(voiceWake.triggersPath) || migrationFileExists(voiceWake.routingPath);
|
||||
const updateCheck = {
|
||||
sourcePath: resolveLegacyUpdateCheckPath(stateDir),
|
||||
};
|
||||
const hasUpdateCheck = fileExists(updateCheck.sourcePath);
|
||||
const hasUpdateCheck = migrationFileExists(updateCheck.sourcePath);
|
||||
const configHealth = {
|
||||
sourcePath: resolveLegacyConfigHealthPath(stateDir),
|
||||
};
|
||||
const hasConfigHealth = fileExists(configHealth.sourcePath);
|
||||
const hasConfigHealth = migrationFileExists(configHealth.sourcePath);
|
||||
const pluginBindingApprovals = {
|
||||
sourcePath: resolveLegacyPluginBindingApprovalsPath(env, homedir),
|
||||
};
|
||||
const hasPluginBindingApprovals =
|
||||
path.resolve(path.dirname(pluginBindingApprovals.sourcePath)) === path.resolve(stateDir) &&
|
||||
fileExists(pluginBindingApprovals.sourcePath);
|
||||
migrationFileExists(pluginBindingApprovals.sourcePath);
|
||||
const currentConversationBindings = {
|
||||
sourcePath: resolveLegacyCurrentConversationBindingsPath(stateDir),
|
||||
};
|
||||
const hasCurrentConversationBindings = fileExists(currentConversationBindings.sourcePath);
|
||||
const hasCurrentConversationBindings = migrationFileExists(
|
||||
currentConversationBindings.sourcePath,
|
||||
);
|
||||
const detectDoctorOwnedState = <TDetection>(
|
||||
detect: (options: { stateDir: string; doctorOnlyStateMigrations?: boolean }) => TDetection,
|
||||
): TDetection =>
|
||||
@@ -640,12 +643,12 @@ export async function detectLegacyStateMigrations(params: {
|
||||
`- Managed worktrees: canonicalize ${worktrees.pathRewrites.length} persisted ${worktrees.pathRewrites.length === 1 ? "path" : "paths"} for symlinked state directories`,
|
||||
);
|
||||
}
|
||||
if (fileExists(taskRunsSidecarPath)) {
|
||||
if (migrationFileExists(taskRunsSidecarPath)) {
|
||||
preview.push(`- Task registry sidecar: ${taskRunsSidecarPath} → shared SQLite state`);
|
||||
} else if (hasPendingTaskRunsSidecarArchive) {
|
||||
preview.push(`- Task registry sidecar: finish archive cleanup for ${taskRunsSidecarPath}`);
|
||||
}
|
||||
if (fileExists(flowRunsSidecarPath)) {
|
||||
if (migrationFileExists(flowRunsSidecarPath)) {
|
||||
preview.push(`- Task flow sidecar: ${flowRunsSidecarPath} → shared SQLite state`);
|
||||
} else if (hasPendingFlowRunsSidecarArchive) {
|
||||
preview.push(`- Task flow sidecar: finish archive cleanup for ${flowRunsSidecarPath}`);
|
||||
|
||||
@@ -6,7 +6,7 @@ import { withTempDir } from "../test-helpers/temp-dir.js";
|
||||
import {
|
||||
ensureMigrationDir,
|
||||
existsDir,
|
||||
fileExists,
|
||||
migrationFileExists,
|
||||
readSessionStoreJson5,
|
||||
safeReadDir,
|
||||
} from "./state-migrations.fs.js";
|
||||
@@ -33,9 +33,9 @@ describe("state migration fs helpers", () => {
|
||||
fs.writeFileSync(filePath, "{}", "utf8");
|
||||
fs.mkdirSync(dirPath);
|
||||
|
||||
expect(fileExists(filePath)).toBe(true);
|
||||
expect(fileExists(dirPath)).toBe(false);
|
||||
expect(fileExists(path.join(base, "missing.json"))).toBe(false);
|
||||
expect(migrationFileExists(filePath)).toBe(true);
|
||||
expect(migrationFileExists(dirPath)).toBe(false);
|
||||
expect(migrationFileExists(path.join(base, "missing.json"))).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ export function ensureMigrationDir(dir: string) {
|
||||
}
|
||||
|
||||
/** Returns whether a path exists and resolves to a regular file. */
|
||||
export function fileExists(p: string): boolean {
|
||||
export function migrationFileExists(p: string): boolean {
|
||||
try {
|
||||
return fs.existsSync(p) && fs.statSync(p).isFile();
|
||||
} catch {
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { SessionEntry } from "../config/sessions.js";
|
||||
import { buildAgentMainSessionKey } from "../routing/session-key.js";
|
||||
import {
|
||||
ensureMigrationDir,
|
||||
fileExists,
|
||||
migrationFileExists,
|
||||
readSessionStoreJson5,
|
||||
safeReadDir,
|
||||
type SessionEntryLike,
|
||||
@@ -71,10 +71,10 @@ export async function migrateLegacySessions(
|
||||
|
||||
ensureMigrationDir(detected.sessions.targetDir);
|
||||
|
||||
const legacyParsed = fileExists(detected.sessions.legacyStorePath)
|
||||
const legacyParsed = migrationFileExists(detected.sessions.legacyStorePath)
|
||||
? readSessionStoreJson5(detected.sessions.legacyStorePath)
|
||||
: { store: {}, ok: true };
|
||||
const targetParsed = fileExists(detected.sessions.targetStorePath)
|
||||
const targetParsed = migrationFileExists(detected.sessions.targetStorePath)
|
||||
? readSessionStoreJson5(detected.sessions.targetStorePath)
|
||||
: { store: {}, ok: true };
|
||||
const legacyStore = legacyParsed.store;
|
||||
@@ -192,7 +192,7 @@ export async function migrateLegacySessions(
|
||||
);
|
||||
}
|
||||
|
||||
const targetExists = fileExists(detected.sessions.targetStorePath);
|
||||
const targetExists = migrationFileExists(detected.sessions.targetStorePath);
|
||||
let targetReadable = !targetExists || targetParsed.ok;
|
||||
if (!targetReadable) {
|
||||
if (options.recoverCorruptTargetStore) {
|
||||
@@ -257,7 +257,7 @@ export async function migrateLegacySessions(
|
||||
}
|
||||
const from = path.join(detected.sessions.legacyDir, entry.name);
|
||||
let to = path.join(detected.sessions.targetDir, entry.name);
|
||||
if (fileExists(to)) {
|
||||
if (migrationFileExists(to)) {
|
||||
const parsed = path.parse(entry.name);
|
||||
to = path.join(detected.sessions.targetDir, `${parsed.name}.legacy-${now()}${parsed.ext}`);
|
||||
}
|
||||
@@ -271,7 +271,7 @@ export async function migrateLegacySessions(
|
||||
|
||||
if (legacyParsed.ok && targetReadable) {
|
||||
try {
|
||||
if (fileExists(detected.sessions.legacyStorePath)) {
|
||||
if (migrationFileExists(detected.sessions.legacyStorePath)) {
|
||||
fs.rmSync(detected.sessions.legacyStorePath, { force: true });
|
||||
}
|
||||
} catch {
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
executeSqliteQueryTakeFirstSync,
|
||||
getNodeSqliteKysely,
|
||||
} from "./kysely-sync.js";
|
||||
import { ensureMigrationDir, fileExists } from "./state-migrations.fs.js";
|
||||
import { ensureMigrationDir, migrationFileExists } from "./state-migrations.fs.js";
|
||||
import {
|
||||
PLUGIN_STATE_SQLITE_SIDECAR_SUFFIXES,
|
||||
archiveLegacyImportSource,
|
||||
@@ -45,7 +45,7 @@ export async function migrateLegacyPluginStateSidecar(params: {
|
||||
stateDir: string;
|
||||
}): Promise<{ changes: string[]; warnings: string[] }> {
|
||||
const sourcePath = resolveLegacyPluginStateSidecarPath(params.stateDir);
|
||||
if (!fileExists(sourcePath)) {
|
||||
if (!migrationFileExists(sourcePath)) {
|
||||
const changes: string[] = [];
|
||||
const warnings: string[] = [];
|
||||
if (hasPendingSqliteSidecarArchive(sourcePath, PLUGIN_STATE_SQLITE_SIDECAR_SUFFIXES)) {
|
||||
@@ -171,7 +171,7 @@ export async function migrateLegacyInstalledPluginIndex(params: {
|
||||
stateDir: string;
|
||||
}): Promise<MigrationMessages> {
|
||||
const sourcePath = resolveLegacyInstalledPluginIndexStorePath({ stateDir: params.stateDir });
|
||||
if (!fileExists(sourcePath)) {
|
||||
if (!migrationFileExists(sourcePath)) {
|
||||
return { changes: [], warnings: [] };
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ export function preflightLegacyInstalledPluginIndexMigration(params: {
|
||||
return `State dir migration skipped because persisted plugin install records in ${params.stateDir} are invalid`;
|
||||
}
|
||||
const sourcePath = resolveLegacyInstalledPluginIndexStorePath(params);
|
||||
if (fileExists(sourcePath) && !readLegacyInstalledPluginIndex(sourcePath)) {
|
||||
if (migrationFileExists(sourcePath) && !readLegacyInstalledPluginIndex(sourcePath)) {
|
||||
return `State dir migration skipped because plugin install index ${sourcePath} is invalid`;
|
||||
}
|
||||
return null;
|
||||
@@ -504,7 +504,11 @@ export async function runLegacyMigrationPlans(
|
||||
cleanupKeys.has(resolvePluginStateImportTargetKey(plan.scopeKey, key)) &&
|
||||
!failedTargetKeys.has(resolvePluginStateImportTargetKey(plan.scopeKey, key)),
|
||||
));
|
||||
if (allEntriesCovered && plan.cleanupSource === "rename" && fileExists(plan.sourcePath)) {
|
||||
if (
|
||||
allEntriesCovered &&
|
||||
plan.cleanupSource === "rename" &&
|
||||
migrationFileExists(plan.sourcePath)
|
||||
) {
|
||||
archiveLegacyImportSource({
|
||||
sourcePath: plan.sourcePath,
|
||||
label: plan.label,
|
||||
@@ -512,7 +516,11 @@ export async function runLegacyMigrationPlans(
|
||||
warnings,
|
||||
});
|
||||
}
|
||||
if (allEntriesCovered && plan.cleanupSource === "remove" && fileExists(plan.sourcePath)) {
|
||||
if (
|
||||
allEntriesCovered &&
|
||||
plan.cleanupSource === "remove" &&
|
||||
migrationFileExists(plan.sourcePath)
|
||||
) {
|
||||
try {
|
||||
fs.unlinkSync(plan.sourcePath);
|
||||
changes.push(`Removed ${plan.label} legacy source (${plan.sourcePath})`);
|
||||
@@ -531,7 +539,7 @@ export async function runLegacyMigrationPlans(
|
||||
});
|
||||
continue;
|
||||
}
|
||||
if (fileExists(plan.targetPath)) {
|
||||
if (migrationFileExists(plan.targetPath)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
} from "./kysely-sync.js";
|
||||
import { normalizeConversationRef } from "./outbound/session-binding-normalization.js";
|
||||
import type { SessionBindingRecord } from "./outbound/session-binding.types.js";
|
||||
import { fileExists } from "./state-migrations.fs.js";
|
||||
import { migrationFileExists } from "./state-migrations.fs.js";
|
||||
import { archiveLegacyImportSource } from "./state-migrations.storage.js";
|
||||
import type { LegacyStateDetection, MigrationMessages } from "./state-migrations.types.js";
|
||||
import { normalizeVoiceWakeRoutingConfig } from "./voicewake-routing.js";
|
||||
@@ -64,7 +64,7 @@ export function migrateLegacyJsonState<Value>(params: {
|
||||
}): MigrationMessages {
|
||||
const changes: string[] = [];
|
||||
const warnings: string[] = [];
|
||||
if (!fileExists(params.sourcePath)) {
|
||||
if (!migrationFileExists(params.sourcePath)) {
|
||||
return { changes, warnings };
|
||||
}
|
||||
|
||||
@@ -413,7 +413,7 @@ function retireLegacyConfigHealthSource(params: {
|
||||
warnings: string[];
|
||||
}): void {
|
||||
const archivedPath = `${params.sourcePath}.migrated`;
|
||||
if (!fileExists(archivedPath)) {
|
||||
if (!migrationFileExists(archivedPath)) {
|
||||
archiveLegacyImportSource({
|
||||
sourcePath: params.sourcePath,
|
||||
label: "config health state",
|
||||
@@ -621,7 +621,7 @@ export function migrateLegacyPluginBindingApprovals(params: {
|
||||
detected: LegacyStateDetection["pluginBindingApprovals"];
|
||||
stateDir: string;
|
||||
}): MigrationMessages {
|
||||
// Detection requires the source to belong to this state root; fileExists
|
||||
// Detection requires the source to belong to this state root; migrationFileExists
|
||||
// re-checks for races before the import mutates the same trust scope.
|
||||
if (!params.detected.hasLegacy) {
|
||||
return { changes: [], warnings: [] };
|
||||
|
||||
@@ -35,7 +35,7 @@ import { expandHomePrefix } from "./home-dir.js";
|
||||
import { isWithinDir } from "./path-safety.js";
|
||||
import {
|
||||
existsDir,
|
||||
fileExists,
|
||||
migrationFileExists,
|
||||
parseSessionStoreJson5,
|
||||
readSessionStoreJson5,
|
||||
safeReadDir,
|
||||
@@ -407,14 +407,18 @@ export function resolveStaleLegacySessionFile(params: {
|
||||
? path.resolve(rawSessionFile)
|
||||
: path.resolve(params.legacyDir, rawSessionFile);
|
||||
const relative = path.relative(path.resolve(params.legacyDir), legacySessionFile);
|
||||
if (relative.startsWith("..") || path.isAbsolute(relative) || fileExists(legacySessionFile)) {
|
||||
if (
|
||||
relative.startsWith("..") ||
|
||||
path.isAbsolute(relative) ||
|
||||
migrationFileExists(legacySessionFile)
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
const legacyBackupHasTranscript = safeReadDir(path.dirname(params.legacyDir)).some(
|
||||
(dirent) =>
|
||||
dirent.isDirectory() &&
|
||||
dirent.name.startsWith(`${path.basename(params.legacyDir)}.legacy-`) &&
|
||||
fileExists(
|
||||
migrationFileExists(
|
||||
path.join(path.dirname(params.legacyDir), dirent.name, path.basename(legacySessionFile)),
|
||||
),
|
||||
);
|
||||
@@ -432,7 +436,7 @@ export function resolveStaleLegacySessionFile(params: {
|
||||
return undefined;
|
||||
}
|
||||
const targetSessionFile = path.join(params.targetDir, path.basename(legacySessionFile));
|
||||
if (!fileExists(targetSessionFile) || typeof entry.sessionId !== "string") {
|
||||
if (!migrationFileExists(targetSessionFile) || typeof entry.sessionId !== "string") {
|
||||
return undefined;
|
||||
}
|
||||
const readFirstLine = () => {
|
||||
@@ -678,7 +682,7 @@ export async function migrateOrphanedSessionKeys(params: {
|
||||
// An unknown relationship may have grouped a readable store behind an
|
||||
// inaccessible pathname. Read from a usable alias so the group still gets
|
||||
// the unresolved-identity warning before any rewrite is attempted.
|
||||
const storePath = [...storePaths].find((candidate) => fileExists(candidate));
|
||||
const storePath = [...storePaths].find((candidate) => migrationFileExists(candidate));
|
||||
if (!storePath) {
|
||||
continue;
|
||||
}
|
||||
@@ -854,7 +858,7 @@ export async function migrateLegacyAcpSessionMetadata(params: {
|
||||
}> = [];
|
||||
|
||||
for (const target of targets) {
|
||||
if (!fileExists(target.storePath)) {
|
||||
if (!migrationFileExists(target.storePath)) {
|
||||
continue;
|
||||
}
|
||||
const group = storeGroups.find(({ target: existing }) =>
|
||||
@@ -1048,7 +1052,7 @@ function isManagedLegacySessionStorePathSafe(storePath: string): boolean {
|
||||
if (!agentsDir) {
|
||||
return true;
|
||||
}
|
||||
if (!fileExists(resolvedStorePath)) {
|
||||
if (!migrationFileExists(resolvedStorePath)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
import { runOpenClawStateWriteTransaction } from "../state/openclaw-state-db.js";
|
||||
import { openNodeSqliteDatabase } from "./node-sqlite.js";
|
||||
import { parseRegistryNpmSpec } from "./npm-registry-spec.js";
|
||||
import { fileExists, safeReadDir } from "./state-migrations.fs.js";
|
||||
import { migrationFileExists, safeReadDir } from "./state-migrations.fs.js";
|
||||
import {
|
||||
insertTaskDeliveryRowSql,
|
||||
insertTaskRunRowSql,
|
||||
@@ -121,9 +121,9 @@ export function hasPendingSqliteSidecarArchive(
|
||||
suffixes: readonly string[],
|
||||
): boolean {
|
||||
return (
|
||||
!fileExists(sourcePath) &&
|
||||
fileExists(`${sourcePath}.migrated`) &&
|
||||
suffixes.some((suffix) => suffix !== "" && fileExists(`${sourcePath}${suffix}`))
|
||||
!migrationFileExists(sourcePath) &&
|
||||
migrationFileExists(`${sourcePath}.migrated`) &&
|
||||
suffixes.some((suffix) => suffix !== "" && migrationFileExists(`${sourcePath}${suffix}`))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ function archiveLegacyFileSource(params: {
|
||||
}): LegacyArchiveResolution | null {
|
||||
const archivedPath = `${params.sourcePath}.migrated`;
|
||||
try {
|
||||
if (fileExists(archivedPath)) {
|
||||
if (migrationFileExists(archivedPath)) {
|
||||
// Import has already committed before archival. Identical archive bytes
|
||||
// preserve the same snapshot, so the leftover source can be removed.
|
||||
if (fs.readFileSync(params.sourcePath).equals(fs.readFileSync(archivedPath))) {
|
||||
@@ -190,7 +190,7 @@ function archiveLegacySqliteSidecar(params: {
|
||||
}): void {
|
||||
const existingSources = PLUGIN_STATE_SQLITE_SIDECAR_SUFFIXES.map(
|
||||
(suffix) => `${params.sourcePath}${suffix}`,
|
||||
).filter(fileExists);
|
||||
).filter(migrationFileExists);
|
||||
if (existingSources.length === 0) {
|
||||
return;
|
||||
}
|
||||
@@ -632,7 +632,7 @@ async function migrateLegacyTaskRunsSidecar(params: {
|
||||
stateDir: string;
|
||||
}): Promise<{ changes: string[]; warnings: string[] }> {
|
||||
const sourcePath = resolveLegacyTaskRunsSidecarPath(params.stateDir);
|
||||
if (!fileExists(sourcePath)) {
|
||||
if (!migrationFileExists(sourcePath)) {
|
||||
const changes: string[] = [];
|
||||
const warnings: string[] = [];
|
||||
if (hasPendingSqliteSidecarArchive(sourcePath, TASK_STATE_SQLITE_SIDECAR_SUFFIXES)) {
|
||||
@@ -770,7 +770,7 @@ async function migrateLegacyFlowRunsSidecar(params: {
|
||||
stateDir: string;
|
||||
}): Promise<{ changes: string[]; warnings: string[] }> {
|
||||
const sourcePath = resolveLegacyFlowRunsSidecarPath(params.stateDir);
|
||||
if (!fileExists(sourcePath)) {
|
||||
if (!migrationFileExists(sourcePath)) {
|
||||
const changes: string[] = [];
|
||||
const warnings: string[] = [];
|
||||
if (hasPendingSqliteSidecarArchive(sourcePath, TASK_STATE_SQLITE_SIDECAR_SUFFIXES)) {
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
import { pathExists } from "../infra/fs-safe.js";
|
||||
|
||||
/** Safely checks optional media file paths without throwing on empty input. */
|
||||
export async function fileExists(filePath?: string | null): Promise<boolean> {
|
||||
export async function optionalPathExists(filePath?: string | null): Promise<boolean> {
|
||||
return filePath ? await pathExists(filePath) : false;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import path from "node:path";
|
||||
import type { MediaUnderstandingModelConfig } from "../config/types.tools.js";
|
||||
import { runExec } from "../process/exec.js";
|
||||
import { getOrCreatePromise } from "../shared/lazy-promise.js";
|
||||
import { fileExists } from "./fs.js";
|
||||
import { optionalPathExists } from "./fs.js";
|
||||
|
||||
type LocalAudioCandidate = {
|
||||
id: "parakeet-mlx" | "whisper-cli" | "sherpa-onnx-offline" | "whisper";
|
||||
@@ -283,8 +283,9 @@ export async function inspectLocalAudioSelection(
|
||||
|
||||
const envModel = env.WHISPER_CPP_MODEL?.trim();
|
||||
const defaultWhisperModel = "/opt/homebrew/share/whisper-cpp/for-tests-ggml-tiny.bin";
|
||||
const whisperModel = envModel && (await fileExists(envModel)) ? envModel : defaultWhisperModel;
|
||||
const whisperReady = Boolean(whisperCommand) && (await fileExists(whisperModel));
|
||||
const whisperModel =
|
||||
envModel && (await optionalPathExists(envModel)) ? envModel : defaultWhisperModel;
|
||||
const whisperReady = Boolean(whisperCommand) && (await optionalPathExists(whisperModel));
|
||||
const whisperBackend = whisperCommand
|
||||
? await inspectWhisperBackend({
|
||||
command: whisperCommand,
|
||||
@@ -306,7 +307,7 @@ export async function inspectLocalAudioSelection(
|
||||
const sherpaReady =
|
||||
Boolean(sherpaCommand) &&
|
||||
sherpaFiles.length === 4 &&
|
||||
(await Promise.all(sherpaFiles.map(fileExists))).every(Boolean);
|
||||
(await Promise.all(sherpaFiles.map(optionalPathExists))).every(Boolean);
|
||||
const parakeetReady = Boolean(parakeetCommand) && platform === "darwin" && arch === "arm64";
|
||||
const parakeetArgs = [
|
||||
"{{AttachmentPath}}",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Deprecated compatibility for released @openclaw/matrix packages.
|
||||
// Remove next major after supported Matrix versions no longer import this lazy lifecycle surface.
|
||||
|
||||
export { ensureConfiguredAcpBindingReady } from "../acp/persistent-bindings.lifecycle.js";
|
||||
export { ensureConfiguredAcpBindingReadyCore as ensureConfiguredAcpBindingReady } from "../acp/persistent-bindings.lifecycle.js";
|
||||
export { resolveConfiguredAcpBindingRecord } from "../acp/persistent-bindings.resolve.js";
|
||||
|
||||
@@ -28,7 +28,7 @@ import {
|
||||
type EmbeddedAgentQueueMessageOptions,
|
||||
} from "../agents/embedded-agent-runner/runs.js";
|
||||
import type { SandboxFsBridge } from "../agents/sandbox/fs-bridge.js";
|
||||
import { formatToolDetail, resolveToolDisplay } from "../agents/tool-display.js";
|
||||
import { inferToolMetaFromArgsCore } from "../agents/tool-display.js";
|
||||
import {
|
||||
buildWatchedSessionsPromptLines,
|
||||
prepareWatchedSessionsPrompt,
|
||||
@@ -537,8 +537,7 @@ export function inferToolMetaFromArgs(
|
||||
args: unknown,
|
||||
options?: { detailMode?: ToolProgressDetailMode },
|
||||
): string | undefined {
|
||||
const display = resolveToolDisplay({ name: toolName, args, detailMode: options?.detailMode });
|
||||
return formatToolDetail(display);
|
||||
return inferToolMetaFromArgsCore(toolName, args, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,16 +5,12 @@
|
||||
* export Zod schema builders, while this subpath owns config CRUD adapters,
|
||||
* config-write authorization, and DM access/policy resolution for accounts.
|
||||
*/
|
||||
import { normalizeOptionalLowercaseString } from "../../packages/normalization-core/src/string-coerce.js";
|
||||
import { normalizeStringEntries } from "../../packages/normalization-core/src/string-normalization.js";
|
||||
import {
|
||||
deleteAccountFromConfigSection as deleteAccountFromConfigSectionInSection,
|
||||
setAccountEnabledInConfigSection as setAccountEnabledInConfigSectionInSection,
|
||||
} from "../channels/plugins/config-helpers.js";
|
||||
import {
|
||||
authorizeConfigWriteShared,
|
||||
canBypassConfigWritePolicyShared,
|
||||
formatConfigWriteDeniedMessageShared,
|
||||
resolveChannelConfigWritesShared,
|
||||
type ConfigWriteAuthorizationResultLike,
|
||||
type ConfigWriteScopeLike,
|
||||
@@ -39,8 +35,6 @@ export {
|
||||
type DmAccessRecord,
|
||||
} from "../channels/plugins/dm-access.js";
|
||||
|
||||
const INTERNAL_MESSAGE_CHANNEL = "webchat";
|
||||
|
||||
/** Origin scope used when authorizing channel config writes. */
|
||||
export type ConfigWriteScope = ConfigWriteScopeLike;
|
||||
/** Target account/channel for a config write authorization check. */
|
||||
@@ -80,35 +74,11 @@ export function resolveChannelConfigWrites(params: {
|
||||
return resolveChannelConfigWritesShared(params);
|
||||
}
|
||||
|
||||
/** Authorizes a channel config mutation against origin and target policy. */
|
||||
export function authorizeConfigWrite(params: {
|
||||
cfg: OpenClawConfig;
|
||||
origin?: ConfigWriteScope;
|
||||
target?: ConfigWriteTarget;
|
||||
allowBypass?: boolean;
|
||||
}): ConfigWriteAuthorizationResult {
|
||||
return authorizeConfigWriteShared(params);
|
||||
}
|
||||
|
||||
/** Returns true when trusted internal message scopes can bypass config write policy. */
|
||||
export function canBypassConfigWritePolicy(params: {
|
||||
channel?: string | null;
|
||||
gatewayClientScopes?: string[] | null;
|
||||
}): boolean {
|
||||
return canBypassConfigWritePolicyShared({
|
||||
...params,
|
||||
isInternalMessageChannel: (channel) =>
|
||||
normalizeOptionalLowercaseString(channel) === INTERNAL_MESSAGE_CHANNEL,
|
||||
});
|
||||
}
|
||||
|
||||
/** Formats the denial message shown when config write authorization fails. */
|
||||
export function formatConfigWriteDeniedMessage(params: {
|
||||
result: Exclude<ConfigWriteAuthorizationResult, { allowed: true }>;
|
||||
fallbackChannelId?: string | null;
|
||||
}): string {
|
||||
return formatConfigWriteDeniedMessageShared(params);
|
||||
}
|
||||
export {
|
||||
authorizeConfigWrite,
|
||||
canBypassConfigWritePolicy,
|
||||
formatConfigWriteDeniedMessage,
|
||||
} from "../channels/plugins/config-writes.js";
|
||||
|
||||
type ChannelConfigAccessorParams<Config extends OpenClawConfig = OpenClawConfig> = {
|
||||
cfg: Config;
|
||||
|
||||
@@ -172,10 +172,10 @@ export type {
|
||||
} from "../channels/message/index.js";
|
||||
|
||||
/** Lazily forwards inbound reply delivery through the channel turn durable-delivery module. */
|
||||
export const deliverInboundReplyWithMessageSendContext: ChannelDurableDeliveryModule["deliverInboundReplyWithMessageSendContext"] =
|
||||
export const deliverInboundReplyWithMessageSendContext: ChannelDurableDeliveryModule["deliverInboundReplyWithMessageSendContextCore"] =
|
||||
async (...args) => {
|
||||
const mod = await import("../channels/turn/durable-delivery.js");
|
||||
return await mod.deliverInboundReplyWithMessageSendContext(...args);
|
||||
return await mod.deliverInboundReplyWithMessageSendContextCore(...args);
|
||||
};
|
||||
|
||||
/** Sends a durable message batch without eager-loading channel message runtime internals. */
|
||||
|
||||
+9
-27
@@ -1,7 +1,9 @@
|
||||
import { expectDefined } from "@openclaw/normalization-core";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../../packages/normalization-core/src/string-coerce.js";
|
||||
import type { ResolvedConfiguredAcpBinding } from "../acp/persistent-bindings.types.js";
|
||||
import { buildChatChannelMetaById } from "../channels/chat-meta-shared.js";
|
||||
import {
|
||||
findChatChannelMeta,
|
||||
getChatChannelMeta as getBuiltInChatChannelMeta,
|
||||
} from "../channels/chat-meta.js";
|
||||
import type { ChatChannelId } from "../channels/ids.js";
|
||||
import { emptyChannelConfigSchema } from "../channels/plugins/config-schema.js";
|
||||
import { buildAccountScopedDmSecurityPolicy } from "../channels/plugins/helpers.js";
|
||||
@@ -28,7 +30,6 @@ import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { buildOutboundBaseSessionKey } from "../infra/outbound/base-session-key.js";
|
||||
import type { OutboundDeliveryResult } from "../infra/outbound/deliver.js";
|
||||
import { normalizeOutboundThreadId } from "../infra/outbound/thread-id.js";
|
||||
import { resolveBundledPluginsDir } from "../plugins/bundled-dir.js";
|
||||
import type { PluginRuntime } from "../plugins/runtime/types.js";
|
||||
import type { OpenClawPluginApi } from "../plugins/types.js";
|
||||
import { resolveThreadSessionKeys } from "../routing/session-key.js";
|
||||
@@ -292,7 +293,7 @@ export async function ensureConfiguredAcpBindingReady(params: {
|
||||
configuredBinding: ResolvedConfiguredAcpBinding | null;
|
||||
}): Promise<{ ok: true } | { ok: false; error: string }> {
|
||||
const runtime = await import("../acp/persistent-bindings.lifecycle.js");
|
||||
return runtime.ensureConfiguredAcpBindingReady(params);
|
||||
return runtime.ensureConfiguredAcpBindingReadyCore(params);
|
||||
}
|
||||
|
||||
export {
|
||||
@@ -315,30 +316,11 @@ export type ChannelOutboundSessionRouteParams = Parameters<
|
||||
NonNullable<ChannelMessagingAdapter["resolveOutboundSessionRoute"]>
|
||||
>[0];
|
||||
|
||||
let cachedSdkChatChannelMeta:
|
||||
| {
|
||||
cacheKey: string;
|
||||
metaById: ReturnType<typeof buildChatChannelMetaById>;
|
||||
}
|
||||
| undefined;
|
||||
|
||||
function resolveSdkChatChannelMeta(id: string) {
|
||||
const cacheKey = resolveBundledPluginsDir(process.env) ?? "";
|
||||
if (cachedSdkChatChannelMeta?.cacheKey !== cacheKey) {
|
||||
cachedSdkChatChannelMeta = {
|
||||
cacheKey,
|
||||
metaById: buildChatChannelMetaById(),
|
||||
};
|
||||
}
|
||||
// Optional by design: createChannelPluginBase serves external plugin ids that
|
||||
// are never in the bundled catalog; their meta comes entirely from params.meta.
|
||||
return cachedSdkChatChannelMeta.metaById[id];
|
||||
function getChatChannelMetaForSdk(id: ChatChannelId): ChannelMeta {
|
||||
return getBuiltInChatChannelMeta(id);
|
||||
}
|
||||
|
||||
/** Resolve bundled chat channel metadata while respecting the active bundled-plugin directory. */
|
||||
export function getChatChannelMeta(id: ChatChannelId): ChannelMeta {
|
||||
return expectDefined(resolveSdkChatChannelMeta(id), `chat channel metadata: ${id}`);
|
||||
}
|
||||
export { getChatChannelMetaForSdk as getChatChannelMeta };
|
||||
|
||||
/** Remove one of the known provider prefixes from a free-form target string. */
|
||||
export function stripChannelTargetPrefix(raw: string, ...providers: string[]): string {
|
||||
@@ -858,7 +840,7 @@ export function createChannelPluginBase<TResolvedAccount>(
|
||||
return {
|
||||
id: params.id,
|
||||
meta: {
|
||||
...resolveSdkChatChannelMeta(params.id),
|
||||
...findChatChannelMeta(params.id as ChatChannelId),
|
||||
...params.meta,
|
||||
id: params.id,
|
||||
},
|
||||
|
||||
@@ -17,7 +17,7 @@ const mocks = vi.hoisted(() => ({
|
||||
}));
|
||||
|
||||
vi.mock("../infra/outbound/delivery-queue.js", () => ({
|
||||
drainPendingDeliveries: mocks.coreDrainPendingDeliveries,
|
||||
drainPendingDeliveriesCore: mocks.coreDrainPendingDeliveries,
|
||||
}));
|
||||
|
||||
vi.mock("../infra/outbound/deliver-runtime.js", () => {
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
// Delivery queue runtime helpers persist and replay outbound plugin delivery work.
|
||||
import {
|
||||
drainPendingDeliveries as coreDrainPendingDeliveries,
|
||||
type DeliverFn,
|
||||
} from "../infra/outbound/delivery-queue.js";
|
||||
import { drainPendingDeliveriesCore, type DeliverFn } from "../infra/outbound/delivery-queue.js";
|
||||
import { runWithGatewayIndependentRootWorkAdmission } from "../process/gateway-work-admission.js";
|
||||
import { createLazyRuntimeModule } from "../shared/lazy-runtime.js";
|
||||
|
||||
type DrainPendingDeliveriesOptions = Omit<
|
||||
Parameters<typeof coreDrainPendingDeliveries>[0],
|
||||
Parameters<typeof drainPendingDeliveriesCore>[0],
|
||||
"deliver"
|
||||
> & {
|
||||
/** Optional delivery implementation for tests or plugin-owned send paths. */
|
||||
@@ -28,7 +25,7 @@ export async function drainPendingDeliveries(opts: DrainPendingDeliveriesOptions
|
||||
// Keep lazy resolution and draining in one lease so suspension cannot split the handoff.
|
||||
const deliver =
|
||||
opts.deliver ?? (await loadOutboundDeliverRuntime()).deliverOutboundPayloadsInternal;
|
||||
await coreDrainPendingDeliveries({
|
||||
await drainPendingDeliveriesCore({
|
||||
...opts,
|
||||
deliver,
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { GetReplyOptions } from "../auto-reply/get-reply-options.types.js";
|
||||
import type { DispatchReplyWithBufferedBlockDispatcher } from "../auto-reply/reply/provider-dispatcher.types.js";
|
||||
import type { FinalizedMsgContext } from "../auto-reply/templating.js";
|
||||
import {
|
||||
deliverInboundReplyWithMessageSendContext,
|
||||
deliverInboundReplyWithMessageSendContextCore,
|
||||
isDurableInboundReplyDeliveryHandled,
|
||||
throwIfDurableInboundReplyDeliveryFailed,
|
||||
type DurableInboundReplyDeliveryOptions,
|
||||
@@ -90,7 +90,7 @@ async function recordInboundSessionAndDispatchReply(
|
||||
payload && typeof payload === "object" ? normalizeOutboundReplyPayload(payload) : {},
|
||||
deliver: async (payload, info) => {
|
||||
if (params.durable) {
|
||||
const durable = await deliverInboundReplyWithMessageSendContext({
|
||||
const durable = await deliverInboundReplyWithMessageSendContextCore({
|
||||
cfg: params.cfg,
|
||||
channel: params.channel,
|
||||
accountId: params.accountId,
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* Runtime SDK subpath for active memory search manager operations.
|
||||
*/
|
||||
export {
|
||||
closeActiveMemorySearchManager,
|
||||
closeActiveMemorySearchManagers,
|
||||
getActiveMemorySearchManager,
|
||||
closeActiveMemorySearchManagerCore as closeActiveMemorySearchManager,
|
||||
closeActiveMemorySearchManagersCore as closeActiveMemorySearchManagers,
|
||||
getActiveMemorySearchManagerCore as getActiveMemorySearchManager,
|
||||
resolveActiveMemoryBackendConfig,
|
||||
} from "../plugins/memory-runtime.js";
|
||||
|
||||
@@ -109,10 +109,12 @@ export function buildOAuthCallbackOriginResolver(
|
||||
/**
|
||||
* Generates a high-entropy OAuth state token for local callback validation.
|
||||
*/
|
||||
export function generateOAuthState(): string {
|
||||
function generateHexOAuthState(): string {
|
||||
return crypto.randomBytes(32).toString("hex");
|
||||
}
|
||||
|
||||
export { generateHexOAuthState as generateOAuthState };
|
||||
|
||||
/**
|
||||
* Parses a pasted OAuth redirect URL into callback code/state fields.
|
||||
*/
|
||||
@@ -230,7 +232,7 @@ function isHttpOrigin(value: string): boolean {
|
||||
|
||||
type ResolveApiKeyForProvider = typeof import("../agents/model-auth.js").resolveApiKeyForProvider;
|
||||
type GetRuntimeAuthForModel =
|
||||
typeof import("../plugins/runtime/runtime-model-auth.runtime.js").getRuntimeAuthForModel;
|
||||
typeof import("../plugins/runtime/runtime-model-auth.runtime.js").getRuntimeAuthForModelCore;
|
||||
type RuntimeModelAuthModule = typeof import("../plugins/runtime/runtime-model-auth.runtime.js");
|
||||
const RUNTIME_MODEL_AUTH_CANDIDATES = [
|
||||
"./runtime-model-auth.runtime",
|
||||
@@ -277,7 +279,7 @@ export async function getRuntimeAuthForModel(
|
||||
/** Concrete model auth request forwarded to the runtime auth module. */
|
||||
params: Parameters<GetRuntimeAuthForModel>[0],
|
||||
): Promise<Awaited<ReturnType<GetRuntimeAuthForModel>>> {
|
||||
const { getRuntimeAuthForModel: getRuntimeAuthForModelLocal } =
|
||||
const { getRuntimeAuthForModelCore: getRuntimeAuthForModelLocal } =
|
||||
await loadRuntimeModelAuthModule();
|
||||
return getRuntimeAuthForModelLocal(params);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ export type PluginEnableResult<TConfig extends ProviderEnableConfigCarrier> = {
|
||||
* Enables provider plugins for provider contract setup without applying channel
|
||||
* normalization from the core plugin enable path.
|
||||
*/
|
||||
export function enablePluginInConfig<TConfig extends ProviderEnableConfigCarrier>(
|
||||
function enableProviderPluginInConfig<TConfig extends ProviderEnableConfigCarrier>(
|
||||
/** Provider setup config object to update without channel normalization. */
|
||||
cfg: TConfig,
|
||||
/** Provider plugin id to enable and allowlist. */
|
||||
@@ -68,3 +68,5 @@ export function enablePluginInConfig<TConfig extends ProviderEnableConfigCarrier
|
||||
next = ensurePluginAllowlisted(next, pluginId);
|
||||
return { config: next, enabled: true };
|
||||
}
|
||||
|
||||
export { enableProviderPluginInConfig as enablePluginInConfig };
|
||||
|
||||
@@ -260,12 +260,14 @@ export async function generatePKCE(): Promise<{ verifier: string; challenge: str
|
||||
}
|
||||
|
||||
/** Generates a random base64url OAuth state value for CSRF protection. */
|
||||
export function generateOAuthState(): string {
|
||||
function generateBase64UrlOAuthState(): string {
|
||||
const stateBytes = new Uint8Array(32);
|
||||
crypto.getRandomValues(stateBytes);
|
||||
return base64urlEncode(stateBytes);
|
||||
}
|
||||
|
||||
export { generateBase64UrlOAuthState as generateOAuthState };
|
||||
|
||||
/**
|
||||
* Parses callback URLs, raw query strings, `code#state`, or plain pasted codes.
|
||||
* Empty input returns an empty object so callers can keep prompting.
|
||||
|
||||
@@ -12,7 +12,7 @@ export type QaTargetParts = {
|
||||
};
|
||||
|
||||
/** Encode a canonical QA channel target. */
|
||||
export function buildQaTarget(params: {
|
||||
function buildQaTargetCore(params: {
|
||||
chatType: QaBusConversationKind;
|
||||
conversationId: string;
|
||||
threadId?: string | null;
|
||||
@@ -23,6 +23,8 @@ export function buildQaTarget(params: {
|
||||
return `${params.chatType === "direct" ? "dm" : params.chatType}:${params.conversationId}`;
|
||||
}
|
||||
|
||||
export { buildQaTargetCore as buildQaTarget };
|
||||
|
||||
/** Parse the lowercase, prefix-scoped target grammar shared by QA Channel and QA Lab. */
|
||||
export function parseQaTarget(
|
||||
raw: string,
|
||||
|
||||
@@ -118,6 +118,18 @@ describe("plugin-sdk qa-runtime", () => {
|
||||
expect(module.isQaRuntimeAvailable()).toBe(false);
|
||||
});
|
||||
|
||||
it("rethrows non-absence loader failures that mention the qa-lab runtime path", async () => {
|
||||
loadBundledPluginPublicSurfaceModuleSync.mockImplementation(() => {
|
||||
throw new Error("Failed to evaluate qa-lab/runtime-api.js: invalid runtime export");
|
||||
});
|
||||
|
||||
const module = await import("./qa-runtime.js");
|
||||
|
||||
expect(() => module.isQaRuntimeAvailable()).toThrow(
|
||||
"Failed to evaluate qa-lab/runtime-api.js: invalid runtime export",
|
||||
);
|
||||
});
|
||||
|
||||
it("runs a plugin-owned transport through the private QA suite host", async () => {
|
||||
const runLiveTransportQaSuiteCommand = vi.fn(async () => {});
|
||||
loadBundledPluginPublicSurfaceModuleSync.mockReturnValue({
|
||||
|
||||
@@ -72,8 +72,7 @@ export function loadQaRuntimeModule(): QaRuntimeSurface {
|
||||
});
|
||||
}
|
||||
|
||||
/** Check whether the bundled QA lab runtime surface is present without hiding other load errors. */
|
||||
export function isQaRuntimeAvailable(): boolean {
|
||||
function isQaRuntimeAvailableStrict(): boolean {
|
||||
try {
|
||||
loadQaRuntimeModule();
|
||||
return true;
|
||||
@@ -85,6 +84,8 @@ export function isQaRuntimeAvailable(): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
export { isQaRuntimeAvailableStrict as isQaRuntimeAvailable };
|
||||
|
||||
/** Docker command runner abstraction used by QA Docker helpers and tests. */
|
||||
export type QaDockerRunCommand = (
|
||||
command: string,
|
||||
|
||||
@@ -25,13 +25,13 @@ const loadProviderDispatcherRuntimeModule = createLazyPromise(
|
||||
/** Dispatches a reply with buffered block support after lazy-loading the runtime dispatcher. */
|
||||
export const dispatchReplyWithBufferedBlockDispatcher: DispatchReplyWithBufferedBlockDispatcher =
|
||||
async (params) => {
|
||||
const { dispatchReplyWithBufferedBlockDispatcher: dispatch } =
|
||||
const { dispatchReplyWithBufferedBlockDispatcherCore: dispatch } =
|
||||
await loadProviderDispatcherRuntimeModule();
|
||||
return await dispatch(params);
|
||||
};
|
||||
|
||||
/** Dispatches a reply through the provider dispatcher after lazy-loading runtime code. */
|
||||
export const dispatchReplyWithDispatcher: DispatchReplyWithDispatcher = async (params) => {
|
||||
const { dispatchReplyWithDispatcher: dispatch } = await loadProviderDispatcherRuntimeModule();
|
||||
const { dispatchReplyWithDispatcherCore: dispatch } = await loadProviderDispatcherRuntimeModule();
|
||||
return await dispatch(params);
|
||||
};
|
||||
|
||||
@@ -38,8 +38,8 @@ export {
|
||||
resolveInboundDebounceMs,
|
||||
} from "../auto-reply/inbound-debounce.js";
|
||||
export {
|
||||
dispatchReplyWithBufferedBlockDispatcher,
|
||||
dispatchReplyWithDispatcher,
|
||||
dispatchReplyWithBufferedBlockDispatcherCore as dispatchReplyWithBufferedBlockDispatcher,
|
||||
dispatchReplyWithDispatcherCore as dispatchReplyWithDispatcher,
|
||||
} from "../auto-reply/reply/provider-dispatcher.js";
|
||||
export {
|
||||
createReplyDispatcher,
|
||||
|
||||
@@ -4,12 +4,12 @@ import { dirname, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import ts from "typescript";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { bundledPluginFile, getBundledPluginRoots } from "./test-helpers/bundled-plugin-roots.js";
|
||||
import { contractPluginPath, getBundledPluginRoots } from "./test-helpers/bundled-plugin-roots.js";
|
||||
|
||||
const ROOT_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
|
||||
|
||||
function runtimeApiPluginFile(pluginId: string): string {
|
||||
return bundledPluginFile({ rootDir: ROOT_DIR, pluginId, relativePath: "runtime-api.ts" });
|
||||
return contractPluginPath({ rootDir: ROOT_DIR, pluginId, relativePath: "runtime-api.ts" });
|
||||
}
|
||||
|
||||
const UNGUARDED_RUNTIME_API_PLUGIN_IDS = [
|
||||
@@ -43,7 +43,7 @@ const UNGUARDED_RUNTIME_API_PLUGIN_IDS = [
|
||||
] as const;
|
||||
|
||||
const RUNTIME_API_EXPORT_GUARDS: Record<string, readonly string[]> = {
|
||||
[bundledPluginFile({
|
||||
[contractPluginPath({
|
||||
rootDir: ROOT_DIR,
|
||||
pluginId: "diagnostics-otel",
|
||||
relativePath: "runtime-api.ts",
|
||||
@@ -51,14 +51,15 @@ const RUNTIME_API_EXPORT_GUARDS: Record<string, readonly string[]> = {
|
||||
'export { createDiagnosticsOtelService } from "./src/service.js";',
|
||||
'export type { OpenClawPluginServiceContext } from "./api.js";',
|
||||
],
|
||||
[bundledPluginFile({ rootDir: ROOT_DIR, pluginId: "discord", relativePath: "runtime-api.ts" })]: [
|
||||
'export { discordMessageActions, handleDiscordAction, isDiscordModerationAction, readDiscordChannelCreateParams, readDiscordChannelEditParams, readDiscordChannelMoveParams, readDiscordModerationCommand, readDiscordParentIdParam, requiredGuildPermissionForModerationAction, type DiscordModerationAction, type DiscordModerationCommand } from "./runtime-api.actions.js";',
|
||||
'export { auditDiscordChannelPermissions, collectDiscordAuditChannelIds, fetchDiscordApplicationId, fetchDiscordApplicationSummary, listDiscordDirectoryGroupsLive, listDiscordDirectoryPeersLive, parseApplicationIdFromToken, probeDiscord, resolveDiscordChannelAllowlist, resolveDiscordPrivilegedIntentsFromFlags, resolveDiscordUserAllowlist, setDiscordRuntime, type DiscordApplicationSummary, type DiscordChannelResolution, type DiscordPrivilegedIntentsSummary, type DiscordPrivilegedIntentStatus, type DiscordProbe, type DiscordUserResolution } from "./runtime-api.lookup.js";',
|
||||
'export { DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS, DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS, DISCORD_DEFAULT_LISTENER_TIMEOUT_MS, allowListMatches, clearGateways, clearPresences, createDiscordGatewayPlugin, createDiscordMessageHandler, createDiscordNativeCommand, getGateway, getPresence, isAbortError, isDiscordGroupAllowedByPolicy, monitorDiscordProvider, normalizeDiscordAllowList, normalizeDiscordInboundWorkerTimeoutMs, normalizeDiscordListenerTimeoutMs, normalizeDiscordSlug, presenceCacheSize, registerDiscordListener, registerGateway, resolveDiscordChannelConfig, resolveDiscordChannelConfigWithFallback, resolveDiscordCommandAuthorized, resolveDiscordGatewayIntents, resolveDiscordGuildEntry, resolveDiscordReplyTarget, resolveDiscordShouldRequireMention, resolveGroupDmAllow, runDiscordTaskWithTimeout, sanitizeDiscordThreadName, setPresence, shouldEmitDiscordReactionNotification, unregisterGateway, waitForDiscordGatewayPluginRegistration, type DiscordAllowList, type DiscordChannelConfigResolved, type DiscordGuildEntryResolved, type DiscordMessageEvent, type DiscordMessageHandler, type MonitorDiscordOpts } from "./runtime-api.monitor.js";',
|
||||
'export { DiscordSendError, addRoleDiscord, banMemberDiscord, createChannelDiscord, createScheduledEventDiscord, createThreadDiscord, deleteChannelDiscord, deleteMessageDiscord, editChannelDiscord, editDiscordComponentMessage, editMessageDiscord, fetchChannelInfoDiscord, fetchChannelPermissionsDiscord, fetchMemberGuildPermissionsDiscord, fetchMemberInfoDiscord, fetchMessageDiscord, fetchReactionsDiscord, fetchRoleInfoDiscord, fetchVoiceStatusDiscord, hasAllGuildPermissionsDiscord, hasAnyGuildPermissionDiscord, kickMemberDiscord, listGuildChannelsDiscord, listGuildEmojisDiscord, listPinsDiscord, listScheduledEventsDiscord, listThreadsDiscord, moveChannelDiscord, pinMessageDiscord, reactMessageDiscord, readMessagesDiscord, registerBuiltDiscordComponentMessage, removeChannelPermissionDiscord, removeOwnReactionsDiscord, removeReactionDiscord, removeRoleDiscord, resolveDiscordOutboundSessionRoute, resolveEventCoverImage, searchMessagesDiscord, sendDiscordComponentMessage, sendMessageDiscord, sendPollDiscord, sendStickerDiscord, sendTypingDiscord, sendVoiceMessageDiscord, sendWebhookMessageDiscord, setChannelPermissionDiscord, timeoutMemberDiscord, unpinMessageDiscord, uploadEmojiDiscord, uploadStickerDiscord, type DiscordChannelCreate, type DiscordChannelEdit, type DiscordChannelMove, type DiscordChannelPermissionSet, type DiscordEmojiUpload, type DiscordMessageEdit, type DiscordMessageQuery, type DiscordModerationTarget, type DiscordPermissionsSummary, type DiscordReactionRuntimeContext, type DiscordReactionSummary, type DiscordReactionUser, type DiscordReactOpts, type DiscordRoleChange, type DiscordRuntimeAccountContext, type DiscordSearchQuery, type DiscordSendResult, type DiscordStickerUpload, type DiscordThreadCreate, type DiscordThreadList, type DiscordTimeoutTarget, type ResolveDiscordOutboundSessionRouteParams } from "./runtime-api.send.js";',
|
||||
'export { testing as __testing, testing, autoBindSpawnedDiscordSubagent, createNoopThreadBindingManager, createThreadBindingManager, formatThreadBindingDurationLabel, getThreadBindingManager, listThreadBindingsBySessionKey, listThreadBindingsForAccount, reconcileAcpThreadBindingsOnStartup, resolveDiscordThreadBindingIdleTimeoutMs, resolveDiscordThreadBindingMaxAgeMs, resolveThreadBindingIdleTimeoutMs, resolveThreadBindingInactivityExpiresAt, resolveThreadBindingIntroText, resolveThreadBindingMaxAgeExpiresAt, resolveThreadBindingMaxAgeMs, resolveThreadBindingPersona, resolveThreadBindingPersonaFromRecord, resolveThreadBindingsEnabled, resolveThreadBindingThreadName, setThreadBindingIdleTimeoutBySessionKey, setThreadBindingMaxAgeBySessionKey, unbindThreadBindingsBySessionKey, type AcpThreadBindingReconciliationResult, type ThreadBindingManager, type ThreadBindingRecord, type ThreadBindingTargetKind } from "./runtime-api.threads.js";',
|
||||
],
|
||||
[bundledPluginFile({ rootDir: ROOT_DIR, pluginId: "imessage", relativePath: "runtime-api.ts" })]:
|
||||
[contractPluginPath({ rootDir: ROOT_DIR, pluginId: "discord", relativePath: "runtime-api.ts" })]:
|
||||
[
|
||||
'export { discordMessageActions, handleDiscordAction, isDiscordModerationAction, readDiscordChannelCreateParams, readDiscordChannelEditParams, readDiscordChannelMoveParams, readDiscordModerationCommand, readDiscordParentIdParam, requiredGuildPermissionForModerationAction, type DiscordModerationAction, type DiscordModerationCommand } from "./runtime-api.actions.js";',
|
||||
'export { auditDiscordChannelPermissions, collectDiscordAuditChannelIds, fetchDiscordApplicationId, fetchDiscordApplicationSummary, listDiscordDirectoryGroupsLive, listDiscordDirectoryPeersLive, parseApplicationIdFromToken, probeDiscord, resolveDiscordChannelAllowlist, resolveDiscordPrivilegedIntentsFromFlags, resolveDiscordUserAllowlist, setDiscordRuntime, type DiscordApplicationSummary, type DiscordChannelResolution, type DiscordPrivilegedIntentsSummary, type DiscordPrivilegedIntentStatus, type DiscordProbe, type DiscordUserResolution } from "./runtime-api.lookup.js";',
|
||||
'export { DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS, DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS, DISCORD_DEFAULT_LISTENER_TIMEOUT_MS, allowListMatches, clearGateways, clearPresences, createDiscordGatewayPlugin, createDiscordMessageHandler, createDiscordNativeCommand, getGateway, getPresence, isAbortError, isDiscordGroupAllowedByPolicy, monitorDiscordProvider, normalizeDiscordAllowList, normalizeDiscordInboundWorkerTimeoutMs, normalizeDiscordListenerTimeoutMs, normalizeDiscordSlug, presenceCacheSize, registerDiscordListener, registerGateway, resolveDiscordChannelConfig, resolveDiscordChannelConfigWithFallback, resolveDiscordCommandAuthorized, resolveDiscordGatewayIntents, resolveDiscordGuildEntry, resolveDiscordReplyTarget, resolveDiscordShouldRequireMention, resolveGroupDmAllow, runDiscordTaskWithTimeout, sanitizeDiscordThreadName, setPresence, shouldEmitDiscordReactionNotification, unregisterGateway, waitForDiscordGatewayPluginRegistration, type DiscordAllowList, type DiscordChannelConfigResolved, type DiscordGuildEntryResolved, type DiscordMessageEvent, type DiscordMessageHandler, type MonitorDiscordOpts } from "./runtime-api.monitor.js";',
|
||||
'export { DiscordSendError, addRoleDiscord, banMemberDiscord, createChannelDiscord, createScheduledEventDiscord, createThreadDiscord, deleteChannelDiscord, deleteMessageDiscord, editChannelDiscord, editDiscordComponentMessage, editMessageDiscord, fetchChannelInfoDiscord, fetchChannelPermissionsDiscord, fetchMemberGuildPermissionsDiscord, fetchMemberInfoDiscord, fetchMessageDiscord, fetchReactionsDiscord, fetchRoleInfoDiscord, fetchVoiceStatusDiscord, hasAllGuildPermissionsDiscord, hasAnyGuildPermissionDiscord, kickMemberDiscord, listGuildChannelsDiscord, listGuildEmojisDiscord, listPinsDiscord, listScheduledEventsDiscord, listThreadsDiscord, moveChannelDiscord, pinMessageDiscord, reactMessageDiscord, readMessagesDiscord, registerBuiltDiscordComponentMessage, removeChannelPermissionDiscord, removeOwnReactionsDiscord, removeReactionDiscord, removeRoleDiscord, resolveDiscordOutboundSessionRoute, resolveEventCoverImage, searchMessagesDiscord, sendDiscordComponentMessage, sendMessageDiscord, sendPollDiscord, sendStickerDiscord, sendTypingDiscord, sendVoiceMessageDiscord, sendWebhookMessageDiscord, setChannelPermissionDiscord, timeoutMemberDiscord, unpinMessageDiscord, uploadEmojiDiscord, uploadStickerDiscord, type DiscordChannelCreate, type DiscordChannelEdit, type DiscordChannelMove, type DiscordChannelPermissionSet, type DiscordEmojiUpload, type DiscordMessageEdit, type DiscordMessageQuery, type DiscordModerationTarget, type DiscordPermissionsSummary, type DiscordReactionRuntimeContext, type DiscordReactionSummary, type DiscordReactionUser, type DiscordReactOpts, type DiscordRoleChange, type DiscordRuntimeAccountContext, type DiscordSearchQuery, type DiscordSendResult, type DiscordStickerUpload, type DiscordThreadCreate, type DiscordThreadList, type DiscordTimeoutTarget, type ResolveDiscordOutboundSessionRouteParams } from "./runtime-api.send.js";',
|
||||
'export { testing as __testing, testing, autoBindSpawnedDiscordSubagent, createNoopThreadBindingManager, createThreadBindingManager, formatThreadBindingDurationLabel, getThreadBindingManager, listThreadBindingsBySessionKey, listThreadBindingsForAccount, reconcileAcpThreadBindingsOnStartup, resolveDiscordThreadBindingIdleTimeoutMs, resolveDiscordThreadBindingMaxAgeMs, resolveThreadBindingIdleTimeoutMs, resolveThreadBindingInactivityExpiresAt, resolveThreadBindingIntroText, resolveThreadBindingMaxAgeExpiresAt, resolveThreadBindingMaxAgeMs, resolveThreadBindingPersona, resolveThreadBindingPersonaFromRecord, resolveThreadBindingsEnabled, resolveThreadBindingThreadName, setThreadBindingIdleTimeoutBySessionKey, setThreadBindingMaxAgeBySessionKey, unbindThreadBindingsBySessionKey, type AcpThreadBindingReconciliationResult, type ThreadBindingManager, type ThreadBindingRecord, type ThreadBindingTargetKind } from "./runtime-api.threads.js";',
|
||||
],
|
||||
[contractPluginPath({ rootDir: ROOT_DIR, pluginId: "imessage", relativePath: "runtime-api.ts" })]:
|
||||
[
|
||||
'export { DEFAULT_ACCOUNT_ID, getChatChannelMeta, type ChannelPlugin } from "openclaw/plugin-sdk/core";',
|
||||
'export { buildChannelConfigSchema, IMessageConfigSchema } from "./config-api.js";',
|
||||
@@ -79,7 +80,7 @@ const RUNTIME_API_EXPORT_GUARDS: Record<string, readonly string[]> = {
|
||||
'export { chunkTextForOutbound } from "./src/channel-api.js";',
|
||||
'export type IMessageAccountConfig = Omit< NonNullable<NonNullable<RuntimeApiOpenClawConfig["channels"]>["imessage"]>, "accounts" | "defaultAccount" >;',
|
||||
],
|
||||
[bundledPluginFile({
|
||||
[contractPluginPath({
|
||||
rootDir: ROOT_DIR,
|
||||
pluginId: "googlechat",
|
||||
relativePath: "runtime-api.ts",
|
||||
@@ -107,40 +108,41 @@ const RUNTIME_API_EXPORT_GUARDS: Record<string, readonly string[]> = {
|
||||
'export { createWebhookInFlightLimiter, readJsonWebhookBodyOrReject, type WebhookInFlightLimiter } from "openclaw/plugin-sdk/webhook-request-guards";',
|
||||
'export { setGoogleChatRuntime } from "./src/runtime.js";',
|
||||
],
|
||||
[bundledPluginFile({ rootDir: ROOT_DIR, pluginId: "msteams", relativePath: "runtime-api.ts" })]: [
|
||||
'export { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";',
|
||||
'export type { AllowlistMatch } from "openclaw/plugin-sdk/allow-from";',
|
||||
'export { mergeAllowlist, resolveAllowlistMatchSimple, summarizeMapping } from "openclaw/plugin-sdk/allow-from";',
|
||||
'export type { BaseProbeResult, ChannelDirectoryEntry, ChannelGroupContext, ChannelMessageActionName, ChannelOutboundAdapter } from "openclaw/plugin-sdk/channel-contract";',
|
||||
'export type { ChannelPlugin } from "openclaw/plugin-sdk/channel-core";',
|
||||
'export { logTypingFailure } from "openclaw/plugin-sdk/channel-outbound";',
|
||||
'export { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";',
|
||||
'export { resolveToolsBySender } from "openclaw/plugin-sdk/channel-policy";',
|
||||
'export { createChannelMessageReplyPipeline } from "openclaw/plugin-sdk/channel-outbound";',
|
||||
'export { PAIRING_APPROVED_MESSAGE, buildProbeChannelStatusSummary, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/channel-status";',
|
||||
'export { buildChannelKeyCandidates, normalizeChannelSlug, resolveChannelEntryMatchWithFallback, resolveNestedAllowlistDecision } from "openclaw/plugin-sdk/channel-targets";',
|
||||
'export type { GroupPolicy, GroupToolPolicyConfig, MSTeamsChannelConfig, MSTeamsCloudName, MSTeamsConfig, MSTeamsReplyStyle, MSTeamsTeamConfig, MarkdownTableMode, OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";',
|
||||
'export { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";',
|
||||
'export { resolveDefaultGroupPolicy } from "openclaw/plugin-sdk/runtime-group-policy";',
|
||||
'export { withFileLock } from "openclaw/plugin-sdk/file-lock";',
|
||||
'export { keepHttpServerTaskAlive } from "openclaw/plugin-sdk/channel-outbound";',
|
||||
'export { detectMime, extensionForMime, extractOriginalFilename, getFileExtension, resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/media-runtime";',
|
||||
'export { loadOutboundMediaFromUrl } from "openclaw/plugin-sdk/outbound-media";',
|
||||
'export { buildMediaPayload } from "openclaw/plugin-sdk/reply-payload";',
|
||||
'export type { ReplyPayload } from "openclaw/plugin-sdk/reply-payload";',
|
||||
'export type { PluginRuntime } from "openclaw/plugin-sdk/runtime-store";',
|
||||
'export type { RuntimeEnv } from "openclaw/plugin-sdk/runtime";',
|
||||
'export type { SsrFPolicy } from "openclaw/plugin-sdk/ssrf-runtime";',
|
||||
'export { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";',
|
||||
'export { normalizeStringEntries } from "openclaw/plugin-sdk/string-normalization-runtime";',
|
||||
'export { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking";',
|
||||
'export { DEFAULT_WEBHOOK_MAX_BODY_BYTES } from "openclaw/plugin-sdk/webhook-ingress";',
|
||||
'export { setMSTeamsRuntime } from "./src/runtime.js";',
|
||||
],
|
||||
[bundledPluginFile({ rootDir: ROOT_DIR, pluginId: "irc", relativePath: "runtime-api.ts" })]: [
|
||||
[contractPluginPath({ rootDir: ROOT_DIR, pluginId: "msteams", relativePath: "runtime-api.ts" })]:
|
||||
[
|
||||
'export { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";',
|
||||
'export type { AllowlistMatch } from "openclaw/plugin-sdk/allow-from";',
|
||||
'export { mergeAllowlist, resolveAllowlistMatchSimple, summarizeMapping } from "openclaw/plugin-sdk/allow-from";',
|
||||
'export type { BaseProbeResult, ChannelDirectoryEntry, ChannelGroupContext, ChannelMessageActionName, ChannelOutboundAdapter } from "openclaw/plugin-sdk/channel-contract";',
|
||||
'export type { ChannelPlugin } from "openclaw/plugin-sdk/channel-core";',
|
||||
'export { logTypingFailure } from "openclaw/plugin-sdk/channel-outbound";',
|
||||
'export { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";',
|
||||
'export { resolveToolsBySender } from "openclaw/plugin-sdk/channel-policy";',
|
||||
'export { createChannelMessageReplyPipeline } from "openclaw/plugin-sdk/channel-outbound";',
|
||||
'export { PAIRING_APPROVED_MESSAGE, buildProbeChannelStatusSummary, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/channel-status";',
|
||||
'export { buildChannelKeyCandidates, normalizeChannelSlug, resolveChannelEntryMatchWithFallback, resolveNestedAllowlistDecision } from "openclaw/plugin-sdk/channel-targets";',
|
||||
'export type { GroupPolicy, GroupToolPolicyConfig, MSTeamsChannelConfig, MSTeamsCloudName, MSTeamsConfig, MSTeamsReplyStyle, MSTeamsTeamConfig, MarkdownTableMode, OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";',
|
||||
'export { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";',
|
||||
'export { resolveDefaultGroupPolicy } from "openclaw/plugin-sdk/runtime-group-policy";',
|
||||
'export { withFileLock } from "openclaw/plugin-sdk/file-lock";',
|
||||
'export { keepHttpServerTaskAlive } from "openclaw/plugin-sdk/channel-outbound";',
|
||||
'export { detectMime, extensionForMime, extractOriginalFilename, getFileExtension, resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/media-runtime";',
|
||||
'export { loadOutboundMediaFromUrl } from "openclaw/plugin-sdk/outbound-media";',
|
||||
'export { buildMediaPayload } from "openclaw/plugin-sdk/reply-payload";',
|
||||
'export type { ReplyPayload } from "openclaw/plugin-sdk/reply-payload";',
|
||||
'export type { PluginRuntime } from "openclaw/plugin-sdk/runtime-store";',
|
||||
'export type { RuntimeEnv } from "openclaw/plugin-sdk/runtime";',
|
||||
'export type { SsrFPolicy } from "openclaw/plugin-sdk/ssrf-runtime";',
|
||||
'export { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";',
|
||||
'export { normalizeStringEntries } from "openclaw/plugin-sdk/string-normalization-runtime";',
|
||||
'export { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking";',
|
||||
'export { DEFAULT_WEBHOOK_MAX_BODY_BYTES } from "openclaw/plugin-sdk/webhook-ingress";',
|
||||
'export { setMSTeamsRuntime } from "./src/runtime.js";',
|
||||
],
|
||||
[contractPluginPath({ rootDir: ROOT_DIR, pluginId: "irc", relativePath: "runtime-api.ts" })]: [
|
||||
'export { setIrcRuntime } from "./src/runtime.js";',
|
||||
],
|
||||
[bundledPluginFile({ rootDir: ROOT_DIR, pluginId: "matrix", relativePath: "runtime-api.ts" })]: [
|
||||
[contractPluginPath({ rootDir: ROOT_DIR, pluginId: "matrix", relativePath: "runtime-api.ts" })]: [
|
||||
'export { type MatrixResolvedStringField, type MatrixResolvedStringValues, resolveMatrixAccountStringValues } from "./src/auth-precedence.js";',
|
||||
'export { requiresExplicitMatrixDefaultAccount, resolveMatrixDefaultOrOnlyAccountId } from "./src/account-selection.js";',
|
||||
'export { findMatrixAccountEntry, resolveConfiguredMatrixAccountIds, resolveMatrixChannelConfig } from "./src/account-selection.js";',
|
||||
@@ -159,7 +161,7 @@ const RUNTIME_API_EXPORT_GUARDS: Record<string, readonly string[]> = {
|
||||
'export type { WizardPrompter } from "openclaw/plugin-sdk/setup";',
|
||||
'export function chunkTextForOutbound(text: string, limit: number): string[] { if (text.length === 0) { return [""]; } if (Number.isFinite(limit) && limit > 0 && !Number.isInteger(limit)) { return chunkTextForOutboundSdk(text, limit); } const chunks: string[] = []; let remaining = text; while (remaining.length > limit) { const window = remaining.slice(0, limit); const splitAt = Math.max(window.lastIndexOf("\\n"), window.lastIndexOf(" ")); const breakAt = splitAt > 0 ? splitAt : limit; chunks.push(remaining.slice(0, breakAt).trimEnd()); remaining = remaining.slice(breakAt).trimStart(); } if (remaining.length > 0) { chunks.push(remaining); } return chunks; }',
|
||||
],
|
||||
[bundledPluginFile({
|
||||
[contractPluginPath({
|
||||
rootDir: ROOT_DIR,
|
||||
pluginId: "nextcloud-talk",
|
||||
relativePath: "runtime-api.ts",
|
||||
@@ -179,16 +181,16 @@ const RUNTIME_API_EXPORT_GUARDS: Record<string, readonly string[]> = {
|
||||
'export { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";',
|
||||
'export { setNextcloudTalkRuntime } from "./src/runtime.js";',
|
||||
],
|
||||
[bundledPluginFile({ rootDir: ROOT_DIR, pluginId: "nostr", relativePath: "runtime-api.ts" })]: [
|
||||
[contractPluginPath({ rootDir: ROOT_DIR, pluginId: "nostr", relativePath: "runtime-api.ts" })]: [
|
||||
'export type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";',
|
||||
'export { getPluginRuntimeGatewayRequestScope } from "openclaw/plugin-sdk/plugin-runtime";',
|
||||
'export type { PluginRuntime } from "openclaw/plugin-sdk/runtime-store";',
|
||||
],
|
||||
[bundledPluginFile({ rootDir: ROOT_DIR, pluginId: "signal", relativePath: "runtime-api.ts" })]: [
|
||||
[contractPluginPath({ rootDir: ROOT_DIR, pluginId: "signal", relativePath: "runtime-api.ts" })]: [
|
||||
'export { applyAccountNameToChannelSection, buildBaseAccountStatusSnapshot, buildBaseChannelStatusSummary, buildChannelConfigSchema, type ChannelMessageActionAdapter, type ChannelPlugin, chunkText, collectStatusIssuesFromLastError, createDefaultChannelRuntimeState, DEFAULT_ACCOUNT_ID, deleteAccountFromConfigSection, detectBinary, emptyPluginConfigSchema, formatCliCommand, formatDocsLink, formatPairingApproveHint, getChatChannelMeta, installSignalCli, listEnabledSignalAccounts, listSignalAccountIds, looksLikeSignalTargetId, migrateBaseNameToDefaultAccount, monitorSignalProvider, normalizeAccountId, normalizeE164, normalizeSignalMessagingTarget, type OpenClawConfig, type OpenClawPluginApi, PAIRING_APPROVED_MESSAGE, type PluginRuntime, probeSignal, removeReactionSignal, resolveAllowlistProviderRuntimeGroupPolicy, resolveChannelMediaMaxBytes, resolveDefaultGroupPolicy, resolveDefaultSignalAccountId, type ResolvedSignalAccount, resolveSignalAccount, resolveSignalReactionLevel, sendMessageSignal, sendReactionSignal, setAccountEnabledInConfigSection, type SignalAccountConfig, SignalConfigSchema, signalMessageActions } from "./src/runtime-api.js";',
|
||||
'export { setSignalRuntime } from "./src/runtime.js";',
|
||||
],
|
||||
[bundledPluginFile({ rootDir: ROOT_DIR, pluginId: "slack", relativePath: "runtime-api.ts" })]: [
|
||||
[contractPluginPath({ rootDir: ROOT_DIR, pluginId: "slack", relativePath: "runtime-api.ts" })]: [
|
||||
'export { handleSlackAction, slackActionRuntime, type SlackActionContext } from "./src/action-runtime.js";',
|
||||
'export { listSlackDirectoryGroupsLive, listSlackDirectoryPeersLive } from "./src/directory-live.js";',
|
||||
'export { deleteSlackMessage, editSlackMessage, getSlackMemberInfo, listEnabledSlackAccounts, listSlackAccountIds, listSlackEmojis, listSlackPins, listSlackReactions, monitorSlackProvider, pinSlackMessage, probeSlack, reactSlackMessage, readSlackMessages, removeOwnSlackReactions, removeSlackReaction, resolveDefaultSlackAccountId, resolveSlackAccount, resolveSlackAppToken, resolveSlackBotToken, resolveSlackGroupRequireMention, resolveSlackGroupToolPolicy, sendMessageSlack, sendSlackMessage, unpinSlackMessage } from "./src/index.js";',
|
||||
@@ -197,7 +199,7 @@ const RUNTIME_API_EXPORT_GUARDS: Record<string, readonly string[]> = {
|
||||
'export { registerSlackPluginHttpRoutes } from "./src/http/plugin-routes.js";',
|
||||
'export { setSlackRuntime } from "./src/runtime.js";',
|
||||
],
|
||||
[bundledPluginFile({ rootDir: ROOT_DIR, pluginId: "telegram", relativePath: "runtime-api.ts" })]:
|
||||
[contractPluginPath({ rootDir: ROOT_DIR, pluginId: "telegram", relativePath: "runtime-api.ts" })]:
|
||||
[
|
||||
'export type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry";',
|
||||
'export type { ChannelMessageActionAdapter } from "openclaw/plugin-sdk/channel-contract";',
|
||||
@@ -233,7 +235,7 @@ const RUNTIME_API_EXPORT_GUARDS: Record<string, readonly string[]> = {
|
||||
'export { parseTelegramTopicConversation } from "./src/topic-conversation.js";',
|
||||
'export { resolveTelegramPollVisibility } from "./src/poll-visibility.js";',
|
||||
],
|
||||
[bundledPluginFile({ rootDir: ROOT_DIR, pluginId: "twitch", relativePath: "runtime-api.ts" })]: [
|
||||
[contractPluginPath({ rootDir: ROOT_DIR, pluginId: "twitch", relativePath: "runtime-api.ts" })]: [
|
||||
'export type { ChannelAccountSnapshot, ChannelCapabilities, ChannelGatewayContext, ChannelLogSink, ChannelMessageActionAdapter, ChannelMessageActionContext, ChannelMeta, ChannelOutboundAdapter, ChannelOutboundContext, ChannelResolveKind, ChannelResolveResult, ChannelStatusAdapter } from "openclaw/plugin-sdk/channel-contract";',
|
||||
'export type { ChannelPlugin } from "openclaw/plugin-sdk/channel-core";',
|
||||
'export type { OutboundDeliveryResult } from "openclaw/plugin-sdk/channel-send-result";',
|
||||
@@ -241,7 +243,7 @@ const RUNTIME_API_EXPORT_GUARDS: Record<string, readonly string[]> = {
|
||||
'export type { RuntimeEnv } from "openclaw/plugin-sdk/runtime";',
|
||||
'export type { WizardPrompter } from "openclaw/plugin-sdk/setup";',
|
||||
],
|
||||
[bundledPluginFile({
|
||||
[contractPluginPath({
|
||||
rootDir: ROOT_DIR,
|
||||
pluginId: "voice-call",
|
||||
relativePath: "runtime-api.ts",
|
||||
@@ -255,7 +257,7 @@ const RUNTIME_API_EXPORT_GUARDS: Record<string, readonly string[]> = {
|
||||
'export { TtsAutoSchema, TtsConfigSchema, TtsModeSchema, TtsProviderSchema } from "openclaw/plugin-sdk/tts-runtime";',
|
||||
'export { sleep } from "openclaw/plugin-sdk/runtime-env";',
|
||||
],
|
||||
[bundledPluginFile({ rootDir: ROOT_DIR, pluginId: "whatsapp", relativePath: "runtime-api.ts" })]:
|
||||
[contractPluginPath({ rootDir: ROOT_DIR, pluginId: "whatsapp", relativePath: "runtime-api.ts" })]:
|
||||
[
|
||||
'export { getActiveWebListener, resolveWebAccountId, type ActiveWebListener, type ActiveWebSendOptions } from "./src/active-listener.js";',
|
||||
'export { handleWhatsAppAction, whatsAppActionRuntime } from "./src/action-runtime.js";',
|
||||
@@ -276,7 +278,7 @@ function collectRuntimeApiFiles(): string[] {
|
||||
return [...getBundledPluginRoots().entries()]
|
||||
.filter(([, rootDir]) => existsSync(resolve(rootDir, "runtime-api.ts")))
|
||||
.map(([pluginId]) =>
|
||||
bundledPluginFile({
|
||||
contractPluginPath({
|
||||
rootDir: ROOT_DIR,
|
||||
pluginId,
|
||||
relativePath: "runtime-api.ts",
|
||||
@@ -409,7 +411,7 @@ describe("runtime api guardrails", () => {
|
||||
// cost of importing the full runtime-api barrel. If a future change
|
||||
// re-broadens this file, this test fails so the perf regression is
|
||||
// surfaced explicitly rather than silently re-introduced.
|
||||
const setterFile = bundledPluginFile({
|
||||
const setterFile = contractPluginPath({
|
||||
rootDir: ROOT_DIR,
|
||||
pluginId: "slack",
|
||||
relativePath: "runtime-setter-api.ts",
|
||||
@@ -420,7 +422,7 @@ describe("runtime api guardrails", () => {
|
||||
});
|
||||
|
||||
it("keeps Matrix's narrow runtime-setter entrypoint pinned to a single export", () => {
|
||||
const setterFile = bundledPluginFile({
|
||||
const setterFile = contractPluginPath({
|
||||
rootDir: ROOT_DIR,
|
||||
pluginId: "matrix",
|
||||
relativePath: "runtime-setter-api.ts",
|
||||
@@ -431,7 +433,7 @@ describe("runtime api guardrails", () => {
|
||||
});
|
||||
|
||||
it("keeps Feishu's narrow runtime-setter entrypoint pinned to a single export", () => {
|
||||
const setterFile = bundledPluginFile({
|
||||
const setterFile = contractPluginPath({
|
||||
rootDir: ROOT_DIR,
|
||||
pluginId: "feishu",
|
||||
relativePath: "runtime-setter-api.ts",
|
||||
|
||||
@@ -34,7 +34,7 @@ export function resolveBundledPluginFile(params: {
|
||||
}
|
||||
|
||||
/** Resolves a bundled plugin file as a path relative to a contract test root. */
|
||||
export function bundledPluginFile(params: {
|
||||
export function contractPluginPath(params: {
|
||||
rootDir: string;
|
||||
pluginId: string;
|
||||
relativePath: string;
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
buildPluginDiagnosticsReport,
|
||||
buildPluginSnapshotReport,
|
||||
clearPluginRegistryLoadCache,
|
||||
enablePluginInConfig,
|
||||
enablePluginInConfigMock,
|
||||
loadPluginManifestRegistry,
|
||||
planPluginUninstall,
|
||||
replaceConfigFile,
|
||||
@@ -101,7 +101,7 @@ describe("persistPluginInstall", () => {
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
enablePluginInConfig.mockImplementation((...args: unknown[]) => {
|
||||
enablePluginInConfigMock.mockImplementation((...args: unknown[]) => {
|
||||
const [cfg, pluginId] = args as [OpenClawConfig, string];
|
||||
expect(pluginId).toBe("alpha");
|
||||
expect(cfg.plugins?.allow).toEqual(["memory-core", "alpha"]);
|
||||
@@ -179,7 +179,7 @@ describe("persistPluginInstall", () => {
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
enablePluginInConfig.mockReturnValue({ config: enabledConfig });
|
||||
enablePluginInConfigMock.mockReturnValue({ config: enabledConfig });
|
||||
clearPluginRegistryLoadCache.mockImplementation(() => {
|
||||
throw new Error("cache unavailable");
|
||||
});
|
||||
@@ -217,7 +217,7 @@ describe("persistPluginInstall", () => {
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
enablePluginInConfig.mockReturnValue({ config: enabledConfig });
|
||||
enablePluginInConfigMock.mockReturnValue({ config: enabledConfig });
|
||||
setInstalledPluginIndexInstallRecords({
|
||||
codex: {
|
||||
source: "clawhub",
|
||||
@@ -304,7 +304,7 @@ describe("persistPluginInstall", () => {
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
enablePluginInConfig.mockReturnValue({ config: enabledConfig });
|
||||
enablePluginInConfigMock.mockReturnValue({ config: enabledConfig });
|
||||
setInstalledPluginIndexInstallRecords({
|
||||
codex: {
|
||||
source: "npm",
|
||||
@@ -345,7 +345,7 @@ describe("persistPluginInstall", () => {
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
enablePluginInConfig.mockReturnValue({ config: enabledConfig });
|
||||
enablePluginInConfigMock.mockReturnValue({ config: enabledConfig });
|
||||
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-plugin-persist-"));
|
||||
const previousProjectRoot = path.join(tempRoot, "npm", "projects", "codex-v1");
|
||||
const previousInstallPath = path.join(
|
||||
@@ -447,7 +447,7 @@ describe("persistPluginInstall", () => {
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
enablePluginInConfig.mockReturnValue({ config: enabledConfig });
|
||||
enablePluginInConfigMock.mockReturnValue({ config: enabledConfig });
|
||||
buildPluginSnapshotReport.mockReturnValue({
|
||||
plugins: [
|
||||
{
|
||||
@@ -506,7 +506,7 @@ describe("persistPluginInstall", () => {
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
enablePluginInConfig.mockReturnValue({ config: enabledConfig });
|
||||
enablePluginInConfigMock.mockReturnValue({ config: enabledConfig });
|
||||
buildPluginSnapshotReport.mockReturnValue({
|
||||
plugins: [
|
||||
{
|
||||
@@ -550,7 +550,7 @@ describe("persistPluginInstall", () => {
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
enablePluginInConfig.mockReturnValue({ config: enabledConfig });
|
||||
enablePluginInConfigMock.mockReturnValue({ config: enabledConfig });
|
||||
refreshPluginRegistry.mockRejectedValueOnce(new Error("registry unavailable"));
|
||||
|
||||
const next = await persistPluginInstall({
|
||||
@@ -587,7 +587,7 @@ describe("persistPluginInstall", () => {
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
enablePluginInConfig.mockReturnValue({ config: enabledConfig });
|
||||
enablePluginInConfigMock.mockReturnValue({ config: enabledConfig });
|
||||
|
||||
const next = await persistPluginInstall({
|
||||
snapshot: {
|
||||
@@ -624,7 +624,7 @@ describe("persistPluginInstall", () => {
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
enablePluginInConfig.mockImplementation((...args: unknown[]) => {
|
||||
enablePluginInConfigMock.mockImplementation((...args: unknown[]) => {
|
||||
const [cfg, pluginId] = args as [OpenClawConfig, string];
|
||||
expect(pluginId).toBe("alpha");
|
||||
expect(cfg.plugins?.deny).toEqual(["other"]);
|
||||
@@ -665,7 +665,7 @@ describe("persistPluginInstall", () => {
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
enablePluginInConfig.mockReturnValue({ config: enabledConfig });
|
||||
enablePluginInConfigMock.mockReturnValue({ config: enabledConfig });
|
||||
loadPluginManifestRegistry.mockReturnValue({
|
||||
plugins: [createManifestRecord("legacy-memory")],
|
||||
diagnostics: [],
|
||||
@@ -742,7 +742,7 @@ describe("persistPluginInstall", () => {
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
enablePluginInConfig.mockReturnValue({ config: enabledConfig });
|
||||
enablePluginInConfigMock.mockReturnValue({ config: enabledConfig });
|
||||
loadPluginManifestRegistry.mockReturnValue({
|
||||
plugins: [createManifestRecord("memory-b", { kind: "memory" })],
|
||||
diagnostics: [],
|
||||
@@ -808,7 +808,7 @@ describe("persistPluginInstall", () => {
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
enablePluginInConfig.mockReturnValue({ config: enabledConfig });
|
||||
enablePluginInConfigMock.mockReturnValue({ config: enabledConfig });
|
||||
loadPluginManifestRegistry.mockReturnValue({
|
||||
plugins: [createManifestRecord("plain")],
|
||||
diagnostics: [],
|
||||
@@ -896,7 +896,7 @@ describe("persistPluginInstall", () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(enablePluginInConfig).not.toHaveBeenCalled();
|
||||
expect(enablePluginInConfigMock).not.toHaveBeenCalled();
|
||||
expect(applyExclusiveSlotSelection).not.toHaveBeenCalled();
|
||||
expectRuntimeLogIncludes(
|
||||
'Installed plugin "needs-config" without enabling it because it requires configuration first.',
|
||||
@@ -957,7 +957,7 @@ describe("persistPluginInstall", () => {
|
||||
}),
|
||||
).rejects.toThrow("has invalid configured settings");
|
||||
|
||||
expect(enablePluginInConfig).not.toHaveBeenCalled();
|
||||
expect(enablePluginInConfigMock).not.toHaveBeenCalled();
|
||||
expect(writePersistedInstalledPluginIndexInstallRecordsWithLease).not.toHaveBeenCalled();
|
||||
expect(writeConfigFile).not.toHaveBeenCalled();
|
||||
});
|
||||
@@ -987,7 +987,7 @@ describe("persistPluginInstall", () => {
|
||||
});
|
||||
|
||||
expect(next).toEqual(baseConfig);
|
||||
expect(enablePluginInConfig).not.toHaveBeenCalled();
|
||||
expect(enablePluginInConfigMock).not.toHaveBeenCalled();
|
||||
expect(applyExclusiveSlotSelection).not.toHaveBeenCalled();
|
||||
const persistedRecords = requireMockCallArg(
|
||||
writePersistedInstalledPluginIndexInstallRecordsWithLease,
|
||||
|
||||
@@ -30,9 +30,9 @@ vi.mock("./memory-state.js", async (importOriginal) => {
|
||||
|
||||
import {
|
||||
authorizeActiveMemorySearchHits,
|
||||
closeActiveMemorySearchManager,
|
||||
closeActiveMemorySearchManagers,
|
||||
getActiveMemorySearchManager,
|
||||
closeActiveMemorySearchManagerCore,
|
||||
closeActiveMemorySearchManagersCore,
|
||||
getActiveMemorySearchManagerCore,
|
||||
resolveActiveMemoryBackendConfig,
|
||||
} from "./memory-runtime.js";
|
||||
import { resetStandaloneMemoryRegistrySlot } from "./memory-runtime.test-support.js";
|
||||
@@ -93,7 +93,7 @@ describe("memory runtime handles", () => {
|
||||
mocks.loadPluginRegistryHandle.mockReturnValue(registry);
|
||||
|
||||
await expect(
|
||||
getActiveMemorySearchManager({ cfg: memoryConfig, agentId: "main" }),
|
||||
getActiveMemorySearchManagerCore({ cfg: memoryConfig, agentId: "main" }),
|
||||
).resolves.toEqual({ manager: null, error: "no index" });
|
||||
|
||||
expect(mocks.loadPluginRegistryHandle).toHaveBeenCalledWith({
|
||||
@@ -121,17 +121,17 @@ describe("memory runtime handles", () => {
|
||||
});
|
||||
expect(hasMemoryRuntime()).toBe(false);
|
||||
|
||||
await getActiveMemorySearchManager({ cfg: memoryConfig, agentId: "main" });
|
||||
await getActiveMemorySearchManagerCore({ cfg: memoryConfig, agentId: "main" });
|
||||
expect(hasMemoryRuntime()).toBe(true);
|
||||
|
||||
await closeActiveMemorySearchManagers();
|
||||
await closeActiveMemorySearchManagersCore();
|
||||
expect(hasMemoryRuntime()).toBe(false);
|
||||
|
||||
await getActiveMemorySearchManager({ cfg: memoryConfig, agentId: "main" });
|
||||
await getActiveMemorySearchManagerCore({ cfg: memoryConfig, agentId: "main" });
|
||||
expect(hasMemoryRuntime()).toBe(true);
|
||||
expect(mocks.loadPluginRegistryHandle).toHaveBeenCalledTimes(1);
|
||||
|
||||
await closeActiveMemorySearchManagers();
|
||||
await closeActiveMemorySearchManagersCore();
|
||||
expect(runtime.closeAllMemorySearchManagers).toHaveBeenCalledTimes(2);
|
||||
expect(hasMemoryRuntime()).toBe(false);
|
||||
});
|
||||
@@ -143,14 +143,14 @@ describe("memory runtime handles", () => {
|
||||
.mockReturnValueOnce(main.registry)
|
||||
.mockReturnValueOnce(research.registry);
|
||||
|
||||
await getActiveMemorySearchManager({ cfg: memoryConfig, agentId: "main" });
|
||||
await getActiveMemorySearchManager({ cfg: memoryConfig, agentId: "research" });
|
||||
await getActiveMemorySearchManagerCore({ cfg: memoryConfig, agentId: "main" });
|
||||
await getActiveMemorySearchManagerCore({ cfg: memoryConfig, agentId: "research" });
|
||||
expect(hasMemoryRuntime()).toBe(true);
|
||||
|
||||
await closeActiveMemorySearchManager({ cfg: memoryConfig, agentId: "main" });
|
||||
await closeActiveMemorySearchManagerCore({ cfg: memoryConfig, agentId: "main" });
|
||||
expect(hasMemoryRuntime()).toBe(true);
|
||||
|
||||
await closeActiveMemorySearchManagers();
|
||||
await closeActiveMemorySearchManagersCore();
|
||||
expect(main.runtime.closeAllMemorySearchManagers).toHaveBeenCalledTimes(1);
|
||||
expect(research.runtime.closeAllMemorySearchManagers).toHaveBeenCalledTimes(1);
|
||||
expect(hasMemoryRuntime()).toBe(false);
|
||||
@@ -164,17 +164,17 @@ describe("memory runtime handles", () => {
|
||||
);
|
||||
|
||||
await expect(
|
||||
getActiveMemorySearchManager({ cfg: memoryConfig, agentId: "main" }),
|
||||
getActiveMemorySearchManagerCore({ cfg: memoryConfig, agentId: "main" }),
|
||||
).rejects.toThrow("manager initialization failed");
|
||||
expect(hasMemoryRuntime()).toBe(true);
|
||||
|
||||
runtime.closeAllMemorySearchManagers.mockRejectedValueOnce(
|
||||
new Error("manager teardown failed"),
|
||||
);
|
||||
await expect(closeActiveMemorySearchManagers()).rejects.toThrow("manager teardown failed");
|
||||
await expect(closeActiveMemorySearchManagersCore()).rejects.toThrow("manager teardown failed");
|
||||
expect(hasMemoryRuntime()).toBe(true);
|
||||
|
||||
await closeActiveMemorySearchManagers();
|
||||
await closeActiveMemorySearchManagersCore();
|
||||
expect(hasMemoryRuntime()).toBe(false);
|
||||
});
|
||||
|
||||
@@ -212,7 +212,7 @@ describe("memory runtime handles", () => {
|
||||
},
|
||||
])("does not load a disabled memory selection", async (cfg) => {
|
||||
await expect(
|
||||
getActiveMemorySearchManager({ cfg: cfg as never, agentId: "main" }),
|
||||
getActiveMemorySearchManagerCore({ cfg: cfg as never, agentId: "main" }),
|
||||
).resolves.toEqual({ manager: null, error: "memory plugin unavailable" });
|
||||
expect(mocks.loadPluginRegistryHandle).not.toHaveBeenCalled();
|
||||
});
|
||||
@@ -322,8 +322,8 @@ describe("memory runtime handles", () => {
|
||||
resolveActiveMemoryBackendConfig({ cfg: memoryConfig, agentId: "research" });
|
||||
mocks.loadPluginRegistryHandle.mockClear();
|
||||
|
||||
await closeActiveMemorySearchManager({ cfg: memoryConfig, agentId: "main" });
|
||||
await closeActiveMemorySearchManagers(memoryConfig);
|
||||
await closeActiveMemorySearchManagerCore({ cfg: memoryConfig, agentId: "main" });
|
||||
await closeActiveMemorySearchManagersCore(memoryConfig);
|
||||
|
||||
for (const { runtime } of [main, research]) {
|
||||
expect(runtime.closeMemorySearchManager).toHaveBeenCalledWith({
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user