diff --git a/docs/.generated/plugin-sdk-api-baseline.sha256 b/docs/.generated/plugin-sdk-api-baseline.sha256 index af1196285c72..b25abf3a2400 100644 --- a/docs/.generated/plugin-sdk-api-baseline.sha256 +++ b/docs/.generated/plugin-sdk-api-baseline.sha256 @@ -1,151 +1,151 @@ -cada1ccdba113c813b6c012d4e119e2a67e23cf7015ebfd62403ed8e74d83cbd module/account-core -4c7a44c538a6856a0861300f05a5df16cb7805fbf1b22c5b772c0a6ad71c45ef module/account-helpers -cbf4e2c3088f8886a7c9ea91325a66e0f0846cea21f0b2891f36399b4811306c module/account-id -8e985f345f21a1c9a2b0e94304aaaad6a326bec1c1ce3b26027d2862804a366e module/account-resolution -e5e67ddf3cab38fcbf9220bc3160715897e2709d9a9ff6ff36f1ecc9453c2367 module/agent-config-primitives -74daa746deb548379d3f0d6eac3c4d082df1034c4360cc03bf51fee0f10a2e4d module/agent-harness -a43840ff36833daef61050fd801e825ec3ba806348b4fbe6c613f20a8807a5e7 module/agent-harness-runtime -5168648cd946abad8a92822889f13ceacc87ed502314a66190d0b1eb8ebe76ea module/agent-media-payload -e82bf122ca0787ec0bcdd12b669cfe24f07da16be1f4090e84c7d645b07ac79f module/agent-runtime -6d12eed0833b9f63b5cea9a763c470487c85c5a722a3a35ec1f5ce07dc8715a9 module/agent-scope-runtime -56b6d5fb6af3d95af1200065aca2e7d4f59e5fa59740505fe6ff433077ef6646 module/allow-from -55cea5390d68839ca7768b4a0cc570b17b65fa0fa3bc4d76130ef0f16cb79ede module/allowlist-config-edit -7ddd81bd5f55de9adf64bf4d92d012f24b37b6da0a72805a3a220d8feff24ca3 module/approval-auth-runtime -a973b03d88f2aa71d3b6c39241527c18d9b1b75f5639bf39cc9b080efbe7b6c6 module/approval-client-runtime -59af6c9bfddc98a0ad2cdc733c6f439f5aa2b14ee14267be81e68715f835bf29 module/approval-delivery-runtime -e26d5faba8bae937a29cb7a8864a1f6ad7e999dd55b47245973ba5fa2dbecae4 module/approval-gateway-runtime -aceab327f18983cfa074384b4510648be2156dfdd30415a2d7a48fd1f38da1c6 module/approval-handler-adapter-runtime -a453261fc6c0d45ad652992bfa3139a1295b6e6296878ee5fde2cf12b995516e module/approval-handler-runtime -dad0906b607cfc044805279c25f656b65579b92b458c8a7c248b7cc8e297d99b module/approval-native-runtime -22db78ca5d8bb308d4ea35fdf0027d6bb6b7ceff8b5737e5bbd651b252d87b5f module/approval-reply-runtime -f5017f6d734f068fd069e5a0611f5728a827bfe05a054389b169e64820b30e72 module/approval-runtime +d3add5597be9e422974496ed388dc0abf5d99941ff60b874d008beab1a1b8a0b module/account-core +1b9d38050a1de968515048d4ada89d5b9d686bd51be0f0c0cb8987a124bb59a7 module/account-helpers +71522995185b956a0cc4927a472cc8d1153e5e998874bfd9a750513175174713 module/account-id +1fe4f05f95e7b29cd81daf65c76fce5db229158c4ffcb8341b390c8ea2e63696 module/account-resolution +87714a883fa2d8c39db921b25992546ab07e23bb5c6bfe739c340d65a989db47 module/agent-config-primitives +a1062730b6e11a0af669590968c839ee5315c2bd2df829fad46a6237569cc0d3 module/agent-harness +2f26ff0e35f6255982f12cdd0facbd0cdb73c9c176fb0e2597b1e40581e55829 module/agent-harness-runtime +b39e78226063156e97da6189b34f1bf92dc07f4bc49a7f67e8dcc521dd878dac module/agent-media-payload +734d51410340183df3a1465d887786ffda6f3f73bcefe905a3ae9c92b85f4e67 module/agent-runtime +68040b4e24969a5d209097b982e1382c7d8bed48d1d1fd5ef5f20754064421e0 module/agent-scope-runtime +8fecb210e22bce4532b6ab649b09465f0bd2c857a44abf40db7d683d6491e6da module/allow-from +74f099da550f5c949541a529d716a7c39a0af7f183d51e433a8b433c98be59f1 module/allowlist-config-edit +8b7e61f1a86d511fd20a28822af13fafcc850d7e68a95d217d42605c13a572e4 module/approval-auth-runtime +e79039b7fae653bbb75c95a20571d0ac3cb508113cf2cb79f5d30ca566fa68ec module/approval-client-runtime +d69e1eaf278e2c913a3317c3fe3f591bfb9b0d331d07fbd3bfab2972e21e18cd module/approval-delivery-runtime +f02f81c3cf3fcaa3bc215b5a1e3ffc3c3c959f4ef8e53423344e3850329f9601 module/approval-gateway-runtime +c5a5a0736d0a999e1b7c8fa967f2d220b03c0c5d8ac30ec43cd0e5bb9b1e2962 module/approval-handler-adapter-runtime +1201987b2a51de1783ee03983f45c14aa5f8c350c427b4aaa6ae6c3287bedc90 module/approval-handler-runtime +796430a3a811d711a6f596984b95fda6a218813128096b3c1eac001944d4aaf7 module/approval-native-runtime +fe40c01e9b168c9b00426eb4febdc557d69d38082e092ca994589acfbb1ae99e module/approval-reply-runtime +06ca5134208844f05a7fb30f334dd4c6d329b9aaecd4baa6f366d4624e9b987f module/approval-runtime 01ca912836b8dec672f705e294f72d346e778557e4c591317d67558ea7669c0b module/archive -ad60ccc4fe9084d47f0477e02d9296bacad32f26d7456e2a84be8d25a53a25c2 module/boolean-param -6e3b8ccee738f8eddde5d813b6e204d6f7c8541fda4cb279a3be3ead27f47e7d module/channel-actions -00d326fdff396dfcc657d1fd16a4015b81d60ae8bf7dad09ac1010b376814de6 module/channel-config-helpers -16dc9d32e8ca3ef78fc63e0fc4b20e6b943633e9572de1a49d24a880b6ffc66c module/channel-config-primitives -c0f910ebfa3dbf283145fb1e3b9c016d03e853ef13e70402b09f3b9d9c2f4ab0 module/channel-config-schema -2dd98659d9600e755f09ef00dd91c36692b8562ed3700461937e94f6cd1e640a module/channel-contract -16d2565753d9b5023549480321c3a8d359b672f4203f1c103523489ce5ff121e module/channel-core -9a5aaf650f9242523bb57bdc2556c323ab64e55aa11e25e2685b73b23ee12534 module/channel-dm-policy -ba41c40956d6b4565605fa38c2d12f4b8471a0f8afe842798716b9032ee4d74a module/channel-entry-contract -982f29a18e07228e3da82cae67d06ff38249592a29c2fd28f01f0d2016ff80d9 module/channel-feedback -1d13edd07a8ae8e21ece6c542cb0cde22e5b6e11d3bb9b2bfaa5ebd2a5239bf8 module/channel-inbound -76bb7f531f3702c801e8fe7479e9e499f601fb361a4303afdcb45fc0da440e4b module/channel-inbound-debounce -df567ce2f4a4ba8a0937f825c46e83763412a724e36b72ce727dc4203c7dd134 module/channel-ingress-runtime -0e6efb79730fae59bb549ad00d9af2848c139b4bb1762e83b66886284e1c1421 module/channel-lifecycle -159d034b431d113f3a6dc41ec0bcadba2d6664051f158330b0e3dd3da8b5d42f module/channel-logging -3aaa573834c68f71490a0b0a8687cd942122cdca03d3b08781cf52220ab71544 module/channel-message -9182ed800c19f6324654dc62f0c78fc11e6a5ef18f4387284066e5b2104da848 module/channel-outbound -930beff13ed42a138f65164013c82f4f4c96422292c5fc634a5edee1dce71367 module/channel-pairing -ee4292b069d4d48cce4fc2dc26df5b5c87eb1fa4769f1f6be9a10c3e1221e1a9 module/channel-plugin-common -94ef57c8f6087fcaa56e59e493c391a04377ed03f23c681edd8d8f6e2d64e0da module/channel-policy -cc0a77137b304b27a313791aa30e43efb4acc254da7590bd47493d81e7104fba module/channel-reply-pipeline -bba5540be7cf9613a163663decdb2affe2af9bbd3ad7914989ab186f9c2abec1 module/channel-runtime-context -f3cee48527f5cddde81912a588e72947d40443322b716871a8d9e5dc0c37c542 module/channel-secret-basic-runtime -0ceb4378709eb2d92a62a275f87fa04e18f77df8f942a9a0acef81019ebc1e24 module/channel-secret-runtime -7c90157a95bc0523fc66b1f78ce140f7ec7dbf809dfa3a480244efc01f972754 module/channel-send-result -fb123c1b557ed2527e335f13c3d6de41ab0c3305151001cf2b1075d1da8034c5 module/channel-setup -aeac9bb8127faf636dde79772a577d9cb003660ef3d1df03ddf606101020c402 module/channel-status -d70ef71f48f9fe5dc01bf13ba3a2ba515322f81dc8f32d08528a113fbc78e30e module/channel-streaming -7f4714752b40f014605e2e7d46006b519972f81b528a286e1a40758493fdef5d module/channel-streaming-config -14f0103adb14627b662fbe9fdd5ed08596ed702a250853e8beb8bb8dd1361588 module/cli-argv -c89ec1b194b76f67a6f4dd108dccf460da6065646cba31374c8aa748f23a39e4 module/collection-runtime -391e6f0c77da2e17a058fc5aea87fd193830b2a14e12fae77c7f63b0226f0bb5 module/command-auth -7dede491d22f7226d955210befca09b32e955c59436c27500f0c7d1971ba07d5 module/command-auth-native -fa2df02bede6ed8843e5c2bd605c6ea5cd20313c305593fbd371dba6f1b931c3 module/command-detection -28a0cae8dee664aef14b1a64c86a46d0fb5637cf9f671790d4fc9ba205e42820 module/command-primitives-runtime -eb4c757fe0086c1dbfa4c3f3caf3dcff0d3cab3924c608237f08f740a6ee5f59 module/command-status -0ef109bca0630cab8578b6d1ad1eb0f92e76dc3995f4a180e34f03212d42f1e0 module/config-contracts -20f3f8042de53e4eee61b64de9102c8c202b9299e6a29235647a4729f70145f2 module/config-mutation -189fa5a240cad0404cd281ad0a14a105a8f3231278d87b71cfbc4f96fb8e48ef module/config-runtime -c1ea9510dfda047609a99d5d2cd1f1560f5d469a36e6b695766213d695c25b0f module/conversation-runtime -c85a82e8f37313cf2111ef6839a48cce6084efef8fd0c199c634fa400032765c module/core -4af19d59c2f18674e7d7f7dc1b358b644dc707e6bd601dc47168bd9e4a669940 module/dedupe-runtime -f70c93d28053ca2e8353e45e6515ce7acef188097c6117d1545965d0699c8004 module/device-bootstrap -68c726280f6585af96c071758ba383e55480b4fc913eae7c26aea1af331dedf3 module/diagnostic-runtime -ea81ef06956c1bc0853fa00afbbc2b5a4019116aaf8a436e1b27d06f7a2c9e88 module/directory-runtime -086bb46f97cb1f4a040b602444daf2c47ac2c24aca150a0d238933956a8100fc module/discord -f65408d85477bb362ebe6ed9148c1bb6b9eb7839733e5e3119f4ff8f1cfd0567 module/error-runtime -b013053a61e7d9be3d0c683c02baf57fa7e4393ec54e0df6a46ab0f2fe2348fd module/extension-shared -ceacad83db01c66e7be6aa21a291597020f13f737b697690eae7d47098e6499a module/gateway-method-runtime -8fa198fde6cb5f651caaa7349bc37992642ea827da6a4c52c94017a0e5dafd6a module/gateway-runtime -6062869202e3d7fdaa1f6801d6c1df7bf7406b8118cc4c7167ed409f5257b05c module/group-access -d117ebba8cc490501725778676a9d75855872b6e5fe2b2f64b1270d4808a2277 module/health -182dc685f2103ff66c1a4839a48f4f40d2eeb0070cd74e449b47aacc4e6f1c22 module/hook-runtime -f6e3c44e7d1090a97aca554a3c247219b8de78b3cb4399cac5efde8a0a6c1156 module/inbound-envelope -1d5ca69fcf2a8476a2309dcd830fc3bbae04b7029fa30eea1081b6590a789f10 module/inbound-event-delivery -36721c58f479fe9ca32737f67850f4607bf8753ef6b193ff129e7a9e5fdbc6bd module/inbound-reply-dispatch -03f7e1190d4101c486908383da099d545e59a6a90f5699b397c976ce6624c029 module/infra-runtime -2e717cccb3db127aed0287d4ea14c41a8e64e46d60c728638153e31e2fb0d296 module/ingress-effect-once -9389d91a090259f06e5ec2aae14c9857e45988d4edc4f91170cb8bc573b966a2 module/interactive-runtime -9dd66baf2def46386ad4706380e57f9068fa9bb3878be2d9ba961ec2f46d3d87 module/json-store -d8ca27a737f235e09f1a9f8cd4b82ac0cde96f10c662347b6ac82e27b70b4a40 module/lazy-runtime -fd00374a91ab5b393152bbbaf90010f9140cf15827bde360d0c6c8724ed34e2e module/logging-core -7670808d8c6227a52b2cddb72121aed9767313dd674f294a1f426dc185c13046 module/matrix -7c2c3ff80fce4cbd02e8976c7418d2da1be190832dd624e59bb30bbc12047755 module/media-local-roots -a5f59c9acbcaa3f82247bf806eb5ba08032373fb853719f0ec9457690f16fc70 module/media-mime -14e6c4c8471207a204710322e88ae2cda12b9e37c726f508f0da45e136262470 module/media-runtime -7a5a1de743fff9d5a86515b501ffd88e7fa49970c9f46a5153816e2ebaef7bb0 module/media-store -c5e3eb1a584f4b8126d9d6c177a840ec9103671e8d1242634ee67db9b5b9e573 module/media-understanding -2288d50521f3323c070a0b74b17e0e647f7ee0e422ccc12989a9ffb8eefacdd4 module/media-understanding-runtime -bebd2931dc51d67c063ff19fa1c278f8dcfe00ab23cfbd480d47329ea8e5088e module/meeting-runtime -ea56ea0455c62f292e1c7b3e56cac6eb3fea00e548f9ab2f4a69e0b41b0a2d96 module/memory-core-host-engine-foundation -00d6f8bc78256558972d431b7983d7b774e0a98d802a1eec533d2cae1e1f1986 module/memory-host-core -87b7a3206346c0d4b294fb3a2395cbaabc3e73ff8b1b9ea925bc3aade3e52687 module/messaging-targets -50e4001a5917b629b51e4d47857db57f01cf4a499f3b6be78ee99568ce7fd46e module/model-session-runtime -44655a08ce111a036c837b8d2e796cf0036941379ab317e5764c6c01e73b39f3 module/models-provider-runtime -55a7e1e57345726b2b54a4c71c66744d5559dd40a164ca552808b689306f53f8 module/native-command-config-runtime -1892da4151de02907448430a4661b8578295bb91638fa6c8d940d858d902876f module/native-command-registry -9470d8e08f7e1d2fe144a81da1b4a331b31a0c74d0c9a5f7cfaa15814e953ea2 module/param-readers -8d8c0c4ebfc6e0c6125df3ae64ec66c10cd797a325de5ea7869fcd84068ab290 module/persistent-dedupe -987648ebe317cc4d6c0505a52d344b12ce9c3a8261a5bd969cee3423c0c53529 module/plugin-config-runtime -f83dbe9460f793f5b57f6df1c208bdf99f272aff7fd9f5cda8e6b25b15bbff20 module/plugin-entry -c0894007b842d68f1dcf0ba6e9a61486d06ef820e78e194939b70a5a4b28e9cb module/plugin-runtime -de508df6d9cfa9d21c4524989dd8bd142fb60cb4ae980193e0907767d76e6022 module/provider-auth -71bebeac51e701cd7c8e63d22754b9bcbd82b024aced303aa055d229781129d7 module/provider-catalog-runtime -56151035047a69e6163d5578023d00f51a2413b777f3784af88e06261c039345 module/proxy-capture -cc3f586640ca1f1988de64ab2b6c9a119024a911a27289fdacfa0901d093c8fe module/question-gateway-runtime -2e09c3181e79e157ed5366b144d116ef8cc06023256ace3fa59b35c43cab513a module/reply-chunking -7994045066b29af1fc6b36ae32068f2a6f277195971af84701cb739cc23d0579 module/reply-dispatch-runtime -ac2b199e95c5c8b1e2a65e62bd41d1b6322e531bca294ef4979a297a12640bce module/reply-history -ad69a4a6970cfac86f9379efb927beac898217946d025c3aea55e6f399da08bb module/reply-payload -1f899eb54013f268d6698ce8e6943289ea0e872747e8e868259106829518db86 module/reply-runtime -b4043b356372f6af64ee3c26e4d6a6d623b817e4d95346358dc0e64a3b61d1e0 module/root-walk -011840eb45317373eefc8505a021c19ef47e7e7f4134c6e411a32ce120ca739f module/routing -ff6cca86f54f94f238205f5b122af36666314e0a380f3ec7f0ccb9ed9208df31 module/run-command -53b0295cec105696a1664c5c7f5576a7b55d197eb95dcd9185486f010bd53750 module/runtime -fcf103d18c1d64ffa9719f1d5a1ca349df3a6125d00c9d54a1b76c195ba8691b module/runtime-config-snapshot -b6b8edc50ecab8386c9acd8f374a207212b5a99c8f518538bbcf0c458dda3881 module/runtime-env -1b223b31f6f78d9eca4a07b92802e59684f24d7a1d040b83856ad165d0dd70fd module/runtime-group-policy -0d8f2c5f3a3325d7d190d2c395835f58ac57f1bea9b6fa516c6942b96d9bf605 module/runtime-store -aa8a411ad37c1d1143b67376bf2d20255b9eedff61d80815f42e4f8ed7bd8e58 module/secret-file -44adc2205f926172fcd3762ca8a96c1485beabcb1bef8b9acfd2233cefea2a6a module/secret-input -57dcb1462d4c4f9a98d934c4ca975b163d704758af9821a64001ff3ac05637c3 module/secret-input-runtime -dc0ee07d392a85c218939000b28c0138f139215da00f5592b34a68ba8e29a25d module/secret-ref-runtime -f97549081955e412d8eb64070c64bb5921bb1324744d824db05767d3adcce403 module/security-runtime -b18d65a8abbed79bcb77e34679b7aeb03f2e9101271f48298b47eb839c33a379 module/session-catalog -046b8f75735b5abeea15dde510f409e429b90f5220ee5c89275861f71fe19f55 module/session-discussion -f112bdabc51ba8659b37d0a6f6a32a2b1d471e5b49b56e108bf750ec55a7ea71 module/session-store-runtime -36affbe151431a6141664b6838e20f2d121ff210d57a3c1b4b41a8818b5c81d8 module/setup -21071e8c2ef020685aba09b5661e37e7415938ff6602053fa831ac9d58673248 module/setup-runtime -df263e722a36ffa168522fa739924bec6b4b122ac3f1e25497a30962bec30607 module/setup-tools -18e384ec43d9eaee52c8e286e127bda2048370e2337964a754d94b236724ca9e module/skill-commands-runtime -ae469f32799380e6b045abaefefee6eb3f00d714ffbf36b6eeef5025dc529472 module/speech-settings -92f8e3fe8b29fa5050f30bcc7a19f1085a590064d9e8b6ac54991e60a691a61e module/ssrf-policy -19c2ac7f81de3203ab91fc88793cf7e0b5bf4eaa2d5d61f4ee9e9f34e3f56be8 module/ssrf-runtime -ff35f9f74d35d37a2eb6126b57f3dc5a4d580b6222fe3a34c9368779ad32eab7 module/state-paths -44cc071d9ba2baa26d6f33ba9407867fb07c33384f49d3e3d5210232022c1b5f module/status-helpers -537047854c21ad20ea0572f8019503cbda3bbafece8194a28c30b0639bde2fde module/string-coerce-runtime -1b5b9a4532db991fce807ba736b550de27aa5f9de2e1f508a8f4f09cae76ea29 module/telegram-account -110944726884fca94f38c9c329b5950629438b9a719f4782c4beeade8bd67746 module/temp-path -0e230313a7a27a915a7aa399c0afd94c4c3e10d485c7b513e757f41bfc362dbe module/text-chunking -2a9971449c5e31c61a715e8ae2d99ac7453690f595c84f4daf85b640bb711689 module/text-runtime -a94c9ff59cc361b04f8731a47d722c4bc88cfabf942221369a8cb67bdcda7249 module/tool-plugin -89846974257b7551d46a514902998d0592fc67b1d8ce036c6514d7b9cd1bc159 module/tool-results -9d6ab352913a573b226e054e1dc8c6d088493aea9954950c65585923b5b6895a module/tool-send -541df9dea799f25e83ea483d481ecebc5b91c016effab593c54d3efe3ee6517b module/web-media -7c43c2cd0f09d72cf5f7cd7df582767e436acb697a81722dde47dbe171c66d2e module/webhook-ingress -af8c5e1c84ec9d365a7aa0d15eb63f0dd9e7b50526023e6212bba020c229f224 module/webhook-request-guards -1cc469eacda2818a116ab7b63847b9ddf86225e8d02e62fac48e618ba41a9852 module/widget-html +d7e53de63b0ac11a266e4abdc18ba6e9401b80309f5c8f5f6a72a00f65dfe3bd module/boolean-param +b234c18152ce7c204483f12b56432eaf628487a58985b45fad5a748efbe7102b module/channel-actions +5b1c747a84962082207d88d629dc8e32a1c71e5579fc50899dc9d0af25347415 module/channel-config-helpers +c2cc71d5070b6071c51248b0648d1ad1a9468d3737df890adc77ec02025e8853 module/channel-config-primitives +45af2c37b55888cd81115aa6837c3cc2ae5a73dd0173e982fff608bed8c3d607 module/channel-config-schema +a38cb34f477cdd6a1a0a664ddcfa8f0f2e1d5f1c30f7fb8bcff0aa3b5fb81a1c module/channel-contract +5167018e99f87bb5d921bdc7709bf05fb433470467f76f698954a366c0a30a8d module/channel-core +b0441683ed12ad0d1e3bd81124f9bfc492bfc8e3307bf1dc85068674e49419a6 module/channel-dm-policy +e3bc795de2eff64754072b7a062cba6b8cf3882b4e12cfc3f3de2cd694fdb18a module/channel-entry-contract +e348cf7e5d26ee4dc7f8de827834f7db5379a08aedc498b5ca899b3fdff497dc module/channel-feedback +90c98588542ed1875f0c26b579930ecb76ea2e8ecfc7815eae64f337d11c19c3 module/channel-inbound +3cd9fdf44a03bd23098a5106ada7b41dd0b4e69039051cbee5fc05965060f8e6 module/channel-inbound-debounce +cc0c189a754c91267948a74096f9617f7f53945f09751243070917961c71ab46 module/channel-ingress-runtime +4ef3dd0ac32f99659e17df55ce4dc1aeda9711ddca0df5508d1907fcb4d43f16 module/channel-lifecycle +0e47457e38d1df0bd572e1408cde2ca6a788b65205f43c585316b5ad3a8f2f16 module/channel-logging +ff897c034772de4c093392fce06671814349cbc1f7d39ded6c90412407998e2f module/channel-message +392c3e8757eb568877e00235a9a6b67044f102f9fd18dc169254071af657b8b4 module/channel-outbound +7441ea71c470e82beffeca577d69beedeb7efcf4439085e35c9813b12e96cdb9 module/channel-pairing +46bbdfff44d2a1e72c8c68d0801fda463361d70a79c50448505f487ff2363f90 module/channel-plugin-common +43a4a56defd68e433dc5a30e25eefccf598513d1bd721b6861574c6fe9783bd5 module/channel-policy +3a342f575458bf45e7c3b9618f7fb196089b7e91fcee16b23bc0b7faedcdb6c4 module/channel-reply-pipeline +482370e60135db9bfaf07f24bab549e5fde09ab265a6061a1f587c5d93929e91 module/channel-runtime-context +e5bab77cf56d4a549b4ba1ba16c15f86394266ecd07b31f96abd5adbfa9bd94b module/channel-secret-basic-runtime +53677d02f5cc8744bd9d335bcb4172a7eda083872f90ffc65c3e474ee149ec0e module/channel-secret-runtime +6c7a1dfd020f3611568c84b8687ce6d06795c953f8f5de71f490fa1d9cc6eead module/channel-send-result +844e8476d0c2967820ff612ca4c11841c149fbfcf541378b9c980013baf30f05 module/channel-setup +528ab5be35a3ad564e74699c6c4aec289a2c424e19f14b7e74fcaf41b0acbe7f module/channel-status +91b43898e843e9497ff1c3aad3d5de5357f0f44e3987d28e5ea70d980b7d418a module/channel-streaming +67df67da5ae72e9eaeb19d41b6bd2432ec4fd8b7b63b2b616fb98f3b4e0ec41d module/channel-streaming-config +1303df5cc58539c6941e2cd159c93259804c925795219f1630f4d740896a77c1 module/cli-argv +ad12670dbfe538f8d0ebf4fb2b68080e93a760278278e6b1ce9bb129d4b2d533 module/collection-runtime +3c625ff1528eb4586f7f287d21afe75905873c0463bc701a9dd7c70d233c1dda module/command-auth +e3bc0ceda7d12196d06bc476e70f980c08a61ba0357fdeaeaf0c6778ac969671 module/command-auth-native +1c725b558e450d7961fc6fe7c0843838860946cb78c1ec82f68305489d534524 module/command-detection +ebaccf95249d1037448f58c543b448ccccff493c4b2086f10093faff87668a61 module/command-primitives-runtime +e85a6cc9ac9972d142cde8ff6e5b8a84b643868b7b1c402b0eede321262f2cd4 module/command-status +3bd594bf7f101450275b8e3593e6420ce25e90093489f2ebe1375ea0f3bb7c23 module/config-contracts +1ac59199900b7ee5ea1d73adcb513d282b62dfe011ce807ddf0df125a30f8008 module/config-mutation +5ec2e13d88466ab2c0c7f25d9cadb6d3a62cb4c7959be11d6e72ad4cf4c5dd6a module/config-runtime +834069efe69c5cda2747b2415baad705767276d5d3ddbe99c2ce83d2b11527eb module/conversation-runtime +dcf04fc00b0d158b118fc9020deb5b032868308cb6f82f49b70ed9d05979fd94 module/core +70f0ceffe7df659416c2114a00cb915b0f2ea45e99862b2dc7f5c21e6fdaa94f module/dedupe-runtime +ebef0e650ab45e44c9335e2b3e15588c968cea6dadd125364a076f9c50ad1e8c module/device-bootstrap +c944f438e9108f3e023149c3d22d152e1c59867151668b9e61bba4da0c09c2cb module/diagnostic-runtime +3519f2584015d6817eefd7803cca7089d66d8569c297367a10aa2114cf6d24d2 module/directory-runtime +10c0932e21a5a8eeca9b515a8f80c420f9d767ddc7cd9926b3ff8f3936ad7f26 module/discord +12f4ff032680218e63370698e2ec8b0c46a5a4dc86ce05462dd1284a06ed2eef module/error-runtime +cdf0108ad6ac4fcd8f1b2f50b0a6f10f28f1dd1a36a60b8345a4f5f0862c8eac module/extension-shared +dd9f6e0fd33cc88b22543c1ee30cc09cf4de4d8f30dff7b7f9cebef885c21543 module/gateway-method-runtime +1f594cdd836aa9bdd0698d1927b164190710e9baf0f66917a45d2f62aa2fc84d module/gateway-runtime +575656e5e0195c8d1813a4e2e3a271e800bb97d44f2dd78c242e3b6714ffa097 module/group-access +e86e937127cf17772834e1c06dc5407d7504b97cac9fe32ef3bf730ad9ea3e58 module/health +54301207a429f30f78aeadb99d6b61591c81b6ea4f467daf3d49efe9106bde81 module/hook-runtime +73c55fa5541efc308d1c99e012f651e45ca84d9049bb8125b6dea687f435862b module/inbound-envelope +4928af5d2509f696b896f53ac790303a0742202dbcdae3e44fe6d1b434a9c1ba module/inbound-event-delivery +8d4232e1b5b24522383888c2f5b14ecae3c615d007b8e73a0cda22b505f42308 module/inbound-reply-dispatch +5069264ca7327b8c5637cf3a854501ec8263148744c3e62af8c0d9f48689b48f module/infra-runtime +ce73721421f1b903dd04ead4df173582e59ea3e9990248102c448b419cc6d272 module/ingress-effect-once +6d0ef8e970d63f711298747344f3c6757fbad6d920b270be06e7611130d846cf module/interactive-runtime +408d257ab5cc4b88a22b7e7595039cb8fc524b261c44141b294fbd0100ba62ee module/json-store +e907fd3a98185f2c261f2aafcaa5a19ee1d7b459d519a498397d629f84c68312 module/lazy-runtime +259373ff0a62fe30ddc4e36260bdba6bf206f98b71a953948bf4dad17c137fff module/logging-core +f1ca4ced4305d0769c2d8cc1291137ac7002fe0e6eaec2c1a71edad2204c8311 module/matrix +3955a8dd748418fa830a9b9a28cd3fdea844212db164b75828aa61ff3848eb5e module/media-local-roots +f74d7295fe716aa140aa0bc9300d6259d71dab826de0808fca6bb02592bf5d6e module/media-mime +2223ff355bea9bf5f903237e1e7dfc2b1c92df27a4141f448b1a20dc0d403a4e module/media-runtime +6a52f93107335f88751704352cc01e62add06f854a5b7d765e2a5ee87c0313b6 module/media-store +bb9f787cd2362268894393f5cf8d16ea582609cb1bb27fbdfc8ea97a76cea214 module/media-understanding +7fc60001aee2f0f95caa7eebe4e8dc74d3a4dcac71f16ce63447d73226f9c683 module/media-understanding-runtime +11aceef9da8abc590d2b5b2cd6a11caaed3c9e54f39cb7e24038bfb01e355b4d module/meeting-runtime +327414d8448f9bbac5d6770f67be92bc7e343415779476611b61acf6e842b0ad module/memory-core-host-engine-foundation +1cad1ac074f2c701e3a48a5b116169292330bd919d5eeedaaf2c36376d449007 module/memory-host-core +1efa0aadc4261d1c6073058cbf3dcc9fa681424819bdd14333e19b249bbc4b18 module/messaging-targets +c374d5020754909d1997b228a2cef74529a11d2deb1f0f65078e9ceb2ed8b7ae module/model-session-runtime +95d7e048fe4e784f149a272a764685081e97fd852c95bbe859519daf36d2d63a module/models-provider-runtime +bba9f68844a60e9bd9b03c694684f62bd7cc11542d6f600bf65b561cadbca8ea module/native-command-config-runtime +62b6329334d16090db4af2a45f4ab5d43842b62db92f458df73af3d9323e681a module/native-command-registry +e1230968f3a3587679a4fa57b67ab36af9bcc81b2bce730c9e724eb66c4418e9 module/param-readers +ca7a56bb1a6169b4cf9befbf5aa21da280a8086fdc49fca4eec520a7a7c98549 module/persistent-dedupe +e3984a76820581c5281412b2449b2bb431110547c2cd833e63d29991e18f7176 module/plugin-config-runtime +7b4fa841f2e5f24a6fb8b7348acb2840d3ed29555d67202cb33d07cb968bdf19 module/plugin-entry +f3df17caa3a3c1904abf7b2ac51cde116135117b545b5fd0f5f3b9eb548075a9 module/plugin-runtime +cff4cdfe96da2a5caa53a5b77addf7f2f9ce94d668be5c9d7e6a11f9b64e7ce0 module/provider-auth +4ddfeb578b91f3bfe82883a97b5378d8baaae4e071dad6b5f9c5a8e331d284ff module/provider-catalog-runtime +8131147d699394bd06503e2ea2f5f1a50b1594a87dded6d118b74a8d0328c8f6 module/proxy-capture +61a976f321591ab6980fff5e780ee8019b57658e94b39370ba6e5923ce28f818 module/question-gateway-runtime +deebc97abbbae14b005ca599d9708fc4ca71964406f6cbb38af7339cf2cdd0df module/reply-chunking +55e675b4c22019fd41d6a6c8cee4f61f8d4e983be517d27519cb8b5fad6b9cf7 module/reply-dispatch-runtime +73f861fa3179d5af1159853c5acab0eec7a6c8f9398dcb75ea770e784fca6727 module/reply-history +0e32d365a83854a04b27522abf9a331a5170ebd345157e11bace539af6a70d88 module/reply-payload +9c510890a98eb0f03c370e58f16c22427720388894e777667c4a874f6ac878ae module/reply-runtime +aa07d85d99fdd2b1e0cbe9975fb6dcae66b8bdce2607c6bd5402ae68bb15118c module/root-walk +3941a8508e73944bf0d920a7334e525c617fc24105ca984fcdc69930ae5cbb7b module/routing +7877a7e58fa32a64107154e5b714c6d165e96989d4aa5f43e0afac085a187af0 module/run-command +9a119658075d586a41dcbd2b4e431c5da1ec2c3d6d21317a18aeeef06359c8ac module/runtime +6df4f6a901ddfafd4f441ef6a2d9a41fca48dd953dc377def2b8ed39db95934f module/runtime-config-snapshot +45bede83ee89886eeda9155f9d4356ce7fa7611c4be744443c1c439173d666ce module/runtime-env +7e871b7319745678bb83fcfc1b54c8751b0ab1af92ff06c01d0659ac92863c11 module/runtime-group-policy +434002543659a8235bf484d88f10d02439b3dbc056bd67c6117bae2da9279048 module/runtime-store +d17862c40825af1ddf0257b44f1e1cbb9c375e8e5ed668fae75d530d1a465cf9 module/secret-file +8e2ac4d3973d8d8ce4478e3440d66ee5c0d9213b0fe9e927c421d14fd31e5e86 module/secret-input +ccd790bc28ce44ca8a2df9a643103555dc650e9778a969c2f6fdeb1f0e1fba1b module/secret-input-runtime +f473090754cb12a5c4a2d39d693315700b25cb053c825c30b3a889a555f10f16 module/secret-ref-runtime +3ac69236c14ac1861aff09f267c523b8f34a63b9bbca085d326c21056604ede0 module/security-runtime +34b3c3904acb961959616b9cefa5b2bc7bc3f543c3e961a94bc6b0d53c148c79 module/session-catalog +c6cf92d099719c629cfddd24243b1deb8febc3122816822e5f4314f9b190e0af module/session-discussion +db9dfcfcdecceae09f163aaad12387e53081a54b6fc7b3ac76427c654662a96c module/session-store-runtime +5af106014a62ef2802236dbc5484d55bfffc2cf7105fd184a4d3b80ac0ab7727 module/setup +b64a0abce77e276b739f8b3979ba60b9b6407955aaedd7803c7d7b9936250574 module/setup-runtime +44d37e0d9131ad2859f41068f2604090c784e65f1bd6ebda8e051b6f2e5e1660 module/setup-tools +fbf92bec93e5cf2afb8be92f9eaefe44dcd8b9c5ba524910d786bca6b48e2530 module/skill-commands-runtime +65438b2c377f9dd3c2a24bfa92e9bca7d568ee6da9d15d8737975bd85a01e188 module/speech-settings +3650198b8d9b0ec76560ebc30bd09fb9f99b22366749cd870918160dd87a2f33 module/ssrf-policy +e6ec1baaa72323bfd0e6e0f2bb1550896d8c95ae4a5d588bd1faeeacd651ed16 module/ssrf-runtime +c1f4358865191005afa6885abf8ed891e0d6fbdc82a04bb7473a5108a0e21516 module/state-paths +80eca61f8d0fc88798a7fb62bc09fee8ffeec7b2329abaaecf3c41c16fa1ba83 module/status-helpers +f097d0096b21c8a052f0f649b7512ecf2aba4744ae6956f001950e053828b309 module/string-coerce-runtime +799a08a3be07df057bb62c01f51b1a35bdfa360ebc3f4c5f9fcccedd19d3aea5 module/telegram-account +aef35bee2502cd6ed8765409b758e452aff8ac9469fd773e6a2a44c9a1bc3f66 module/temp-path +87fa81b9e58d8fc04a4b4202d2d37fca339615f5225687d9db905151439e0f4d module/text-chunking +87f5a0d7948934e403f4e15cb4d2fb54dd97a16a35dffec3cf5ee66ddbd46169 module/text-runtime +b6fa8e1d2c99997aa734a699610c2d06d32fe93d009298d7511c101bd0798a24 module/tool-plugin +dc1a073c59ab61e2789533b777b3f0cb9af689d64a97796b10e8aa82552510db module/tool-results +9a2f1691d747799e833f19ce8b31b844421a660354221d42299ade9cfefcbeda module/tool-send +cda105b721d498df23a554c6b68be150b8fe66b8b9172185c31a0b3b0646b1dc module/web-media +acd86723117251ac58a46347ccae7893c35539d72b97a904372dbafb34f50e22 module/webhook-ingress +3d7a4d6c0e769a78a47d6a67393c72b3a5df9c272058f1f072a28ac9d6b2cfb8 module/webhook-request-guards +de59e86e126b75d13251cba7ebbe27b44d9b5588785d98df5ff4d6722374c81f module/widget-html 9161b36ec0ab062ea41b363c894fcd672a7727f21cb726739f99f9c184fce69d module/zod diff --git a/src/plugin-sdk/api-baseline-declaration-closure.ts b/src/plugin-sdk/api-baseline-declaration-closure.ts new file mode 100644 index 000000000000..83b34b091d93 --- /dev/null +++ b/src/plugin-sdk/api-baseline-declaration-closure.ts @@ -0,0 +1,305 @@ +// Declaration closure rendering keeps compiler-owned dependencies in API baselines. +import { createHash } from "node:crypto"; +import path from "node:path"; +import ts from "typescript"; +import { + normalizePluginSdkApiDeclarationText, + normalizePluginSdkApiSourcePath, +} from "./api-baseline-normalization.js"; + +export type PluginSdkDeclarationClosure = { + hash: string; +}; + +type ClosureExport = { + closure: PluginSdkDeclarationClosure; + surface: T; +}; + +type DeclarationReference = { + mode: ts.ResolutionMode; + specifier: string; +}; + +type EmittedDeclaration = { + declarationFile: ts.SourceFile; + text: string; +}; + +function compareText(left: string, right: string): number { + return left < right ? -1 : left > right ? 1 : 0; +} + +export function formatPluginSdkDiagnostics( + diagnostics: readonly ts.Diagnostic[], + currentDirectory: string, +): string { + return ts.formatDiagnostics(diagnostics, { + getCanonicalFileName: (fileName) => fileName, + getCurrentDirectory: () => currentDirectory, + getNewLine: () => "\n", + }); +} + +export function attachPluginSdkDeclarationClosures( + exports: readonly ClosureExport[], +): T[] { + return exports.map(({ closure, surface }) => { + if (surface.declaration && closure.hash) { + surface.declaration = `// declaration closure: ${closure.hash}\n${surface.declaration}`; + } + return surface; + }); +} + +function collectDeclarationReferences( + sourceFile: ts.SourceFile, + options: ts.CompilerOptions, +): DeclarationReference[] { + const references = new Map(); + const add = (literal: ts.StringLiteralLike) => { + const mode = ts.getModeForUsageLocation(sourceFile, literal, options); + references.set(`${mode ?? "default"}\0${literal.text}`, { + mode, + specifier: literal.text, + }); + }; + const visit = (node: ts.Node) => { + if (ts.isImportDeclaration(node) && ts.isStringLiteralLike(node.moduleSpecifier)) { + add(node.moduleSpecifier); + } else if ( + ts.isExportDeclaration(node) && + node.moduleSpecifier && + ts.isStringLiteralLike(node.moduleSpecifier) + ) { + add(node.moduleSpecifier); + } else if ( + ts.isImportEqualsDeclaration(node) && + ts.isExternalModuleReference(node.moduleReference) && + node.moduleReference.expression && + ts.isStringLiteralLike(node.moduleReference.expression) + ) { + add(node.moduleReference.expression); + } else if ( + ts.isImportTypeNode(node) && + ts.isLiteralTypeNode(node.argument) && + ts.isStringLiteralLike(node.argument.literal) + ) { + add(node.argument.literal); + } + ts.forEachChild(node, visit); + }; + visit(sourceFile); + return [...references.values()].toSorted( + (left, right) => + compareText(left.specifier, right.specifier) || + compareText(String(left.mode), String(right.mode)), + ); +} + +export function createDeclarationClosureRenderer(params: { + printer: ts.Printer; + program: ts.Program; + repoRoot: string; +}): (sourceFile: ts.SourceFile) => PluginSdkDeclarationClosure { + const { printer, program, repoRoot } = params; + const options = program.getCompilerOptions(); + const canonical = (fileName: string) => { + const resolved = path.resolve(fileName); + return ts.sys.useCaseSensitiveFileNames ? resolved : resolved.toLowerCase(); + }; + const sourceFiles = new Map(); + for (const sourceFile of program.getSourceFiles()) { + sourceFiles.set(canonical(sourceFile.fileName), sourceFile); + const realPath = ts.sys.realpath?.(sourceFile.fileName); + if (realPath) { + sourceFiles.set(canonical(realPath), sourceFile); + } + } + const resolutionCache = ts.createModuleResolutionCache(repoRoot, canonical, options); + const moduleHost = ts.createCompilerHost(options, true); + const emitted = new Map(); + const renderedClosures = new Map(); + + const baseDiagnostics = [...program.getOptionsDiagnostics(), ...program.getGlobalDiagnostics()]; + if (baseDiagnostics.length > 0) { + throw new Error( + `Unable to emit Plugin SDK declarations:\n${formatPluginSdkDiagnostics(baseDiagnostics, program.getCurrentDirectory())}`, + ); + } + + const isRepoOwned = (sourceFile: ts.SourceFile) => { + if ( + program.isSourceFileDefaultLibrary(sourceFile) || + program.isSourceFileFromExternalLibrary(sourceFile) + ) { + return false; + } + const relative = path.relative(repoRoot, path.resolve(sourceFile.fileName)); + return ( + relative !== "" && + relative !== ".." && + !relative.startsWith(`..${path.sep}`) && + !path.isAbsolute(relative) && + !relative.split(path.sep).includes("node_modules") + ); + }; + + const getDeclaration = (sourceFile: ts.SourceFile): EmittedDeclaration => { + const key = canonical(sourceFile.fileName); + const cached = emitted.get(key); + if (cached) { + return cached; + } + const diagnostics = [ + ...program.getSyntacticDiagnostics(sourceFile), + ...(sourceFile.isDeclarationFile ? [] : program.getDeclarationDiagnostics(sourceFile)), + ]; + if (diagnostics.length > 0) { + throw new Error( + `Unable to emit ${normalizePluginSdkApiSourcePath(repoRoot, sourceFile.fileName)}:\n${formatPluginSdkDiagnostics(diagnostics, program.getCurrentDirectory())}`, + ); + } + + let declarationFile = sourceFile; + if (!sourceFile.isDeclarationFile) { + let output: { content: string; fileName: string } | undefined; + const result = program.emit( + sourceFile, + (fileName, content, _writeByteOrderMark, _onError, outputSources) => { + if (!/\.d\.[cm]?ts$/u.test(fileName)) { + return; + } + const outputSource = outputSources?.[0]; + if ( + outputSources?.length !== 1 || + !outputSource || + canonical(outputSource.fileName) !== canonical(sourceFile.fileName) + ) { + throw new Error(`Declaration output ${fileName} has no unique source owner`); + } + if (output) { + throw new Error(`Duplicate declaration output for ${sourceFile.fileName}`); + } + output = { content, fileName }; + }, + undefined, + true, + ); + if (result.emitSkipped || result.diagnostics.length > 0) { + const detail = result.diagnostics.length + ? `\n${formatPluginSdkDiagnostics(result.diagnostics, program.getCurrentDirectory())}` + : ""; + throw new Error( + `Unable to emit ${normalizePluginSdkApiSourcePath(repoRoot, sourceFile.fileName)}${detail}`, + ); + } + if (!output) { + throw new Error( + `Missing emitted declaration for ${normalizePluginSdkApiSourcePath(repoRoot, sourceFile.fileName)}`, + ); + } + declarationFile = ts.createSourceFile( + output.fileName, + output.content, + ts.ScriptTarget.Latest, + true, + ts.ScriptKind.TS, + ); + declarationFile.impliedNodeFormat = sourceFile.impliedNodeFormat; + } + + const declaration = { + declarationFile, + text: normalizePluginSdkApiDeclarationText( + repoRoot, + printer.printFile(declarationFile).trim(), + ), + }; + emitted.set(key, declaration); + return declaration; + }; + + const resolveDependency = ( + sourceFile: ts.SourceFile, + reference: DeclarationReference, + ): ts.SourceFile | undefined => { + const resolved = ts.resolveModuleName( + reference.specifier, + sourceFile.fileName, + options, + moduleHost, + resolutionCache, + undefined, + reference.mode, + ).resolvedModule; + if (!resolved) { + if (ts.isExternalModuleNameRelative(reference.specifier)) { + throw new Error( + `Unable to resolve declaration dependency ${reference.specifier} from ${normalizePluginSdkApiSourcePath(repoRoot, sourceFile.fileName)}`, + ); + } + return undefined; + } + if (resolved.isExternalLibraryImport) { + return undefined; + } + const dependency = sourceFiles.get(canonical(resolved.resolvedFileName)); + if (!dependency) { + const relative = path.relative(repoRoot, path.resolve(resolved.resolvedFileName)); + if ( + relative !== ".." && + !relative.startsWith(`..${path.sep}`) && + !path.isAbsolute(relative) + ) { + throw new Error( + `Missing program source for declaration dependency ${resolved.resolvedFileName}`, + ); + } + return undefined; + } + return isRepoOwned(dependency) ? dependency : undefined; + }; + + return (owner) => { + const ownerKey = canonical(owner.fileName); + const cached = renderedClosures.get(ownerKey); + if (cached) { + return cached; + } + if (!isRepoOwned(owner)) { + return { hash: "" }; + } + + const visited = new Set(); + const sections = new Map(); + const visit = (sourceFile: ts.SourceFile) => { + const key = canonical(sourceFile.fileName); + if (visited.has(key)) { + return; + } + visited.add(key); + const declaration = getDeclaration(sourceFile); + sections.set( + normalizePluginSdkApiSourcePath(repoRoot, sourceFile.fileName), + declaration.text, + ); + for (const reference of collectDeclarationReferences(declaration.declarationFile, options)) { + const dependency = resolveDependency(sourceFile, reference); + if (dependency) { + visit(dependency); + } + } + }; + visit(owner); + const renderedSections = [...sections.entries()] + .toSorted(([left], [right]) => compareText(left, right)) + .map(([sourcePath, text]) => ({ sourcePath, text })); + const hash = createHash("sha256") + .update(JSON.stringify(renderedSections), "utf8") + .digest("hex"); + const closure = { hash }; + renderedClosures.set(ownerKey, closure); + return closure; + }; +} diff --git a/src/plugin-sdk/api-baseline-normalization.ts b/src/plugin-sdk/api-baseline-normalization.ts new file mode 100644 index 000000000000..c18006cb3859 --- /dev/null +++ b/src/plugin-sdk/api-baseline-normalization.ts @@ -0,0 +1,48 @@ +// API baseline normalization removes machine-local path differences from compiler output. +import path from "node:path"; + +/** Normalize compiler source paths into stable repo-relative or node_modules-relative paths. */ +export function normalizePluginSdkApiSourcePath(repoRoot: string, filePath: string): string { + const resolvedPath = path.resolve(filePath); + const relative = path.relative(repoRoot, resolvedPath); + const relativePosix = relative.split(path.sep).join(path.posix.sep); + if ( + !relative.startsWith("..") && + !path.isAbsolute(relative) && + !relativePosix.startsWith("node_modules/") + ) { + return relativePosix; + } + + const pathParts = resolvedPath.split(/[\\/]+/); + const nodeModulesIndex = pathParts.lastIndexOf("node_modules"); + if (nodeModulesIndex >= 0 && nodeModulesIndex < pathParts.length - 1) { + return ["node_modules", ...pathParts.slice(nodeModulesIndex + 1)].join(path.posix.sep); + } + + return relativePosix; +} + +function normalizeDeclarationImportSpecifier(repoRoot: string, value: string): string { + if (!path.isAbsolute(value) && !/^[A-Za-z]:[\\/]/.test(value)) { + return value; + } + + const resolvedPath = path.resolve(value); + const relative = path.relative(repoRoot, resolvedPath); + if (relative.startsWith("..") || path.isAbsolute(relative)) { + return value; + } + return relative.split(path.sep).join(path.posix.sep); +} + +/** Strip machine-local absolute paths from declaration text before hashing baseline output. */ +export function normalizePluginSdkApiDeclarationText(repoRoot: string, value: string): string { + return value.replaceAll( + /import\("([^"]+)"((?:\s*,[^)]*)?)\)/g, + (match, specifier: string, suffix: string) => { + const normalized = normalizeDeclarationImportSpecifier(repoRoot, specifier); + return normalized === specifier ? match : `import("${normalized}"${suffix})`; + }, + ); +} diff --git a/src/plugin-sdk/api-baseline.test.ts b/src/plugin-sdk/api-baseline.test.ts index 4cd329f65f45..d53185dc82db 100644 --- a/src/plugin-sdk/api-baseline.test.ts +++ b/src/plugin-sdk/api-baseline.test.ts @@ -1,10 +1,12 @@ /** * Tests the plugin SDK public API baseline. */ +import fs from "node:fs"; import path from "node:path"; import ts from "typescript"; -import { beforeAll, describe, expect, it } from "vitest"; +import { afterEach, beforeAll, describe, expect, it } from "vitest"; import { publicPluginSdkEntrypoints } from "../../scripts/lib/plugin-sdk-entries.mjs"; +import { useAutoCleanupTempDirTracker } from "../../test/helpers/temp-dir.js"; import { computePluginSdkApiBaselineHashFileContent, formatPluginSdkApiTypeAlias, @@ -22,6 +24,7 @@ const TEST_ENTRYPOINTS = [ "channel-policy", "core", "infra-runtime", + "plugin-entry", "provider-auth", "provider-catalog-live-runtime", "provider-oauth-runtime", @@ -32,6 +35,67 @@ const TEST_ENTRYPOINTS = [ "sqlite-runtime-testing", ] as const; +const tempDirs = useAutoCleanupTempDirTracker(afterEach); + +async function renderPrivateDeclarationFixture(params?: { + optionalOption?: boolean; + optionalResult?: boolean; +}) { + const repoRoot = tempDirs.make("openclaw-plugin-sdk-api-"); + const sourceDir = path.join(repoRoot, "src", "plugin-sdk"); + const externalDir = path.join(repoRoot, "node_modules", "fixture-external"); + fs.mkdirSync(sourceDir, { recursive: true }); + fs.mkdirSync(externalDir, { recursive: true }); + fs.writeFileSync( + path.join(repoRoot, "tsconfig.json"), + `${JSON.stringify({ + compilerOptions: { + module: "NodeNext", + moduleResolution: "NodeNext", + target: "ESNext", + }, + })}\n`, + ); + fs.writeFileSync( + path.join(sourceDir, "fixture.ts"), + [ + 'import type { FixtureOptionLeaf } from "./fixture-option.js";', + 'import type { FixtureResultLeaf } from "./fixture-result.js";', + "type FixtureOptions = { nested: FixtureOptionLeaf };", + "type FixtureResult = { nested: FixtureResultLeaf };", + "export declare function createFixture(options: FixtureOptions): FixtureResult;", + ].join("\n"), + ); + fs.writeFileSync( + path.join(sourceDir, "fixture-option.ts"), + [ + 'import type { FixtureResultLeaf } from "./fixture-result.js";', + 'import type { FixtureExternal } from "fixture-external";', + `export type FixtureOptionLeaf = { required${params?.optionalOption ? "?" : ""}: string; result?: FixtureResultLeaf; external?: FixtureExternal };`, + ].join("\n"), + ); + fs.writeFileSync( + path.join(sourceDir, "fixture-result.ts"), + 'export type { FixtureResultLeaf } from "./fixture-result-shape.js";\n', + ); + fs.writeFileSync( + path.join(sourceDir, "fixture-result-shape.ts"), + [ + 'import type { FixtureOptionLeaf } from "./fixture-option.js";', + `export type FixtureResultLeaf = { value${params?.optionalResult ? "?" : ""}: string; option?: FixtureOptionLeaf };`, + ].join("\n"), + ); + fs.writeFileSync( + path.join(externalDir, "package.json"), + `${JSON.stringify({ name: "fixture-external", types: "index.d.ts" })}\n`, + ); + fs.writeFileSync( + path.join(externalDir, "index.d.ts"), + "export type FixtureExternal = { externalOnly: string };\n", + ); + return renderPluginSdkApiBaseline({ repoRoot, entrypoints: ["fixture"] }); +} + function createTupleAliasFixture(tuple: string, warmup: string, prewarm: boolean) { const fileName = "/plugin-sdk-tuple-fixture.ts"; const source = [ @@ -192,6 +256,11 @@ describe("Plugin SDK API baseline", () => { expect(findDeclaration("SqliteTrajectoryRuntimeEventForTest")).toContain( "export type SqliteTrajectoryRuntimeEventForTest =", ); + expect(findDeclaration("definePluginEntry")).toMatch( + /^\/\/ declaration closure: [a-f0-9]{64}/u, + ); + expect(findDeclaration("definePluginEntry")).toContain("DefinePluginEntryOptions"); + expect(findDeclaration("definePluginEntry")).toContain("DefinedPluginEntry"); expect(findDeclaration("ProviderSelection")).toContain( "export type ProviderSelection =", ); @@ -233,4 +302,40 @@ describe("Plugin SDK API baseline", () => { expect(after[0]).not.toBe(before[0]); expect(after.slice(1)).toEqual(before.slice(1)); }); + + it("captures transitive private declaration changes deterministically", async () => { + const baseline = await renderPrivateDeclarationFixture(); + const unchanged = await renderPrivateDeclarationFixture(); + const optionChanged = await renderPrivateDeclarationFixture({ optionalOption: true }); + const resultChanged = await renderPrivateDeclarationFixture({ optionalResult: true }); + const declaration = baseline.baseline.modules[0]?.exports[0]; + + expect(declaration).toEqual( + expect.objectContaining({ + exportName: "createFixture", + kind: "function", + source: { path: "src/plugin-sdk/fixture.ts" }, + }), + ); + expect(declaration?.declaration).toMatch(/^\/\/ declaration closure: [a-f0-9]{64}/u); + expect(declaration?.declaration).toContain("FixtureOptions"); + expect(declaration?.declaration).toContain("FixtureResult"); + expect(declaration?.declaration).not.toContain("required: string;"); + expect(declaration?.declaration).not.toContain("value: string;"); + expect(declaration?.declaration).not.toContain("externalOnly: string;"); + expect(unchanged.json).toBe(baseline.json); + expect(unchanged.jsonl).toBe(baseline.jsonl); + expect(computePluginSdkApiBaselineHashFileContent(unchanged)).toBe( + computePluginSdkApiBaselineHashFileContent(baseline), + ); + + for (const changed of [optionChanged, resultChanged]) { + expect(changed.baseline.modules[0]?.exports[0]?.declaration).not.toBe( + declaration?.declaration, + ); + expect(computePluginSdkApiBaselineHashFileContent(changed)).not.toBe( + computePluginSdkApiBaselineHashFileContent(baseline), + ); + } + }); }); diff --git a/src/plugin-sdk/api-baseline.ts b/src/plugin-sdk/api-baseline.ts index ae58eb305ad3..50f014336857 100644 --- a/src/plugin-sdk/api-baseline.ts +++ b/src/plugin-sdk/api-baseline.ts @@ -10,6 +10,21 @@ import { type PluginSdkDocEntrypoint, } from "../../scripts/lib/plugin-sdk-doc-metadata.ts"; import { publicPluginSdkEntrypoints } from "../../scripts/lib/plugin-sdk-entries.mjs"; +import { + attachPluginSdkDeclarationClosures, + createDeclarationClosureRenderer, + formatPluginSdkDiagnostics, + type PluginSdkDeclarationClosure, +} from "./api-baseline-declaration-closure.js"; +import { + normalizePluginSdkApiDeclarationText, + normalizePluginSdkApiSourcePath as relativePath, +} from "./api-baseline-normalization.js"; + +export { + normalizePluginSdkApiDeclarationText, + normalizePluginSdkApiSourcePath, +} from "./api-baseline-normalization.js"; /** Declaration kind recorded for each public SDK export in the API baseline. */ export type PluginSdkApiExportKind = @@ -102,60 +117,6 @@ function resolveRepoRoot(): string { return path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); } -/** Normalize compiler source paths into stable repo-relative or node_modules-relative paths. */ -export function normalizePluginSdkApiSourcePath(repoRoot: string, filePath: string): string { - const resolvedPath = path.resolve(filePath); - const relative = path.relative(repoRoot, resolvedPath); - const relativePosix = relative.split(path.sep).join(path.posix.sep); - if ( - !relative.startsWith("..") && - !path.isAbsolute(relative) && - !relativePosix.startsWith("node_modules/") - ) { - return relativePosix; - } - - const pathParts = resolvedPath.split(/[\\/]+/); - const nodeModulesIndex = pathParts.lastIndexOf("node_modules"); - if (nodeModulesIndex >= 0 && nodeModulesIndex < pathParts.length - 1) { - return ["node_modules", ...pathParts.slice(nodeModulesIndex + 1)].join(path.posix.sep); - } - - return relativePosix; -} - -function relativePath(repoRoot: string, filePath: string): string { - return normalizePluginSdkApiSourcePath(repoRoot, filePath); -} - -function isAbsoluteImportPath(value: string): boolean { - return path.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value); -} - -function normalizeDeclarationImportSpecifier(repoRoot: string, value: string): string { - if (!isAbsoluteImportPath(value)) { - return value; - } - - const resolvedPath = path.resolve(value); - const relative = path.relative(repoRoot, resolvedPath); - if (relative.startsWith("..") || path.isAbsolute(relative)) { - return value; - } - return relative.split(path.sep).join(path.posix.sep); -} - -/** Strip machine-local absolute paths from declaration text before hashing baseline output. */ -export function normalizePluginSdkApiDeclarationText(repoRoot: string, value: string): string { - return value.replaceAll( - /import\("([^"]+)"((?:\s*,[^)]*)?)\)/g, - (match, specifier: string, suffix: string) => { - const normalized = normalizeDeclarationImportSpecifier(repoRoot, specifier); - return normalized === specifier ? match : `import("${normalized}"${suffix})`; - }, - ); -} - function createCompilerContext(repoRoot: string, entrypoints: readonly string[]) { const configPath = ts.findConfigFile( repoRoot, @@ -168,6 +129,9 @@ function createCompilerContext(repoRoot: string, entrypoints: readonly string[]) throw new Error(ts.flattenDiagnosticMessageText(configFile.error.messageText, "\n")); } const parsedConfig = ts.parseJsonConfigFileContent(configFile.config, ts.sys, repoRoot); + if (parsedConfig.errors.length > 0) { + throw new Error(formatPluginSdkDiagnostics(parsedConfig.errors, repoRoot)); + } const fileNames = entrypoints .map((entrypoint) => path.join(repoRoot, "src", "plugin-sdk", `${entrypoint}.ts`)) .toSorted((left, right) => @@ -176,10 +140,26 @@ function createCompilerContext(repoRoot: string, entrypoints: readonly string[]) relativePath(repoRoot, path.resolve(right)), ), ); - const program = ts.createProgram(fileNames, parsedConfig.options); + const program = ts.createProgram(fileNames, { + ...parsedConfig.options, + declaration: true, + declarationMap: false, + emitDeclarationOnly: true, + noEmit: false, + // Declaration diagnostics are checked explicitly; unrelated untyped external JS stays valid. + noEmitOnError: false, + removeComments: true, + sourceMap: false, + }); + const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed, removeComments: true }); return { checker: program.getTypeChecker(), - printer: ts.createPrinter({ newLine: ts.NewLineKind.LineFeed, removeComments: true }), + declarationClosure: createDeclarationClosureRenderer({ + printer, + program, + repoRoot, + }), + printer, program, }; } @@ -189,12 +169,6 @@ export function listPluginSdkApiBaselineEntrypoints(): string[] { return [...publicPluginSdkEntrypoints]; } -function buildSourceLink(repoRoot: string, filePath: string): PluginSdkApiSourceLink { - return { - path: relativePath(repoRoot, filePath), - }; -} - function inferExportKind( symbol: ts.Symbol, declaration: ts.Declaration | undefined, @@ -571,20 +545,27 @@ function compareDeclarations( function buildExportSurface(params: { checker: ts.TypeChecker; + declarationClosure: (sourceFile: ts.SourceFile) => PluginSdkDeclarationClosure; printer: ts.Printer; repoRoot: string; symbol: ts.Symbol; -}): PluginSdkApiExport { - const { checker, printer, repoRoot, symbol } = params; +}): { closure: PluginSdkDeclarationClosure; surface: PluginSdkApiExport } { + const { checker, declarationClosure, printer, repoRoot, symbol } = params; const { declaration, resolvedSymbol } = resolveSymbolAndDeclaration(checker, repoRoot, symbol); const exportName = symbol.getName(); + const declarationText = declaration + ? printNode(repoRoot, checker, printer, declaration, exportName) + : null; return { - declaration: declaration - ? printNode(repoRoot, checker, printer, declaration, exportName) - : null, - exportName, - kind: inferExportKind(resolvedSymbol, declaration), - source: declaration ? buildSourceLink(repoRoot, declaration.getSourceFile().fileName) : null, + closure: declaration ? declarationClosure(declaration.getSourceFile()) : { hash: "" }, + surface: { + declaration: declarationText, + exportName, + kind: inferExportKind(resolvedSymbol, declaration), + source: declaration + ? { path: relativePath(repoRoot, declaration.getSourceFile().fileName) } + : null, + }, }; } @@ -608,12 +589,13 @@ function sortExports(left: PluginSdkApiExport, right: PluginSdkApiExport): numbe function buildModuleSurface(params: { checker: ts.TypeChecker; + declarationClosure: (sourceFile: ts.SourceFile) => PluginSdkDeclarationClosure; printer: ts.Printer; program: ts.Program; repoRoot: string; entrypoint: string; }): PluginSdkApiModule { - const { checker, printer, program, repoRoot, entrypoint } = params; + const { checker, declarationClosure, printer, program, repoRoot, entrypoint } = params; const metadata = Object.hasOwn(pluginSdkDocMetadata, entrypoint) ? pluginSdkDocMetadata[entrypoint as PluginSdkDocEntrypoint] : undefined; @@ -625,25 +607,27 @@ function buildModuleSurface(params: { const moduleSymbol = checker.getSymbolAtLocation(sourceFile); assert(moduleSymbol, `Unable to resolve module symbol for ${importSpecifier}`); - const exports = checker + const builtExports = checker .getExportsOfModule(moduleSymbol) .filter((symbol) => symbol.getName() !== "__esModule") .map((symbol) => buildExportSurface({ checker, + declarationClosure, printer, repoRoot, symbol, }), ) - .toSorted(sortExports); + .toSorted((left, right) => sortExports(left.surface, right.surface)); + const exports = attachPluginSdkDeclarationClosures(builtExports); return { category: metadata?.category ?? null, entrypoint, exports, importSpecifier, - source: buildSourceLink(repoRoot, moduleSourcePath), + source: { path: relativePath(repoRoot, moduleSourcePath) }, }; } @@ -687,10 +671,14 @@ export async function renderPluginSdkApiBaseline(params?: { const repoRoot = params?.repoRoot ?? resolveRepoRoot(); const entrypoints = params?.entrypoints ?? listPluginSdkApiBaselineEntrypoints(); validateMetadata(); - const { checker, printer, program } = createCompilerContext(repoRoot, entrypoints); + const { checker, declarationClosure, printer, program } = createCompilerContext( + repoRoot, + entrypoints, + ); const modules = entrypoints.map((entrypoint) => buildModuleSurface({ checker, + declarationClosure, printer, program, repoRoot,