@xgent-ai/skills 0.7.5 → 0.7.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (717) hide show
  1. package/.claude/hooks/xgent-statusline.js +32 -18
  2. package/README.md +61 -35
  3. package/bin/phoenix-diagram.js +14 -0
  4. package/bin/xgent-skills.js +132 -240
  5. package/dist/phoenix-diagram/LICENSE +21 -0
  6. package/dist/phoenix-diagram/NOTICE.md +34 -0
  7. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/005fc765ddc5115da796cca915baa9557abae13ff35e0a47c47affc56f6c414d.txt +272 -0
  8. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/010492e490b92ec85db01daad2a290ea5959f29314a1c4ff25e7a172e223abf9.txt +18 -0
  9. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f.txt +3 -0
  10. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/0218327e7a480793ffdd4eb792379a9709e5c135c7ba267f709d6f6d4d70af0a.txt +201 -0
  11. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/02bb8c3b4e70190e3986c0404ad2fd8d639b4f534252d82379cc1b502b6d1812.txt +191 -0
  12. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/0444c6991eead6822f7b9102e654448d51624431119546492e8b231db42c48bb.txt +25 -0
  13. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/0552c898248eadfc130df0c0e8f6f82776fcb3f1dd5a5af2fa991b5baff9367a.txt +21 -0
  14. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/0ab4d106b6faac07fb6a051815fd1b4d862d730895e2d7d7358c2f13565e7a38.txt +20 -0
  15. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/0b28172679e0009b655da42797c03fd163a3379d5cfa67ba1f1655e974a2a1a9.txt +25 -0
  16. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/0d3f7c086c6b6cf3ea4aac714e9aa3e1fb02e355ce35bd21c56acf8d04390885.txt +21 -0
  17. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/0dd882e53de11566d50f8e8e2d5a651bcf3fabee4987d70f306233cf39094ba7.txt +21 -0
  18. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f.txt +21 -0
  19. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/117829c3ca21efb132d81a44b55363d395ab8eea18526873bc828da4c0e5f038.txt +21 -0
  20. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/123a331b5dbf04c30097fa43b8f858bc85df671fe776de498d01f3d6b7c1f69e.txt +25 -0
  21. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/1a2f5c12ddc934d58956aa5dbdd3255fe55fd957633ab7d0d39e4f0daa73f7df.txt +26 -0
  22. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5.txt +373 -0
  23. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/1f485f0d6125658861351e3d6084ea90fefe78f89450be9915044b7c56d5a75a.txt +15 -0
  24. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b.txt +26 -0
  25. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/20c7855c364d57ea4c97889a5e8d98470a9952dade37bd9248b9a54431670e5e.txt +25 -0
  26. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/20fe7b00e904ed690e3b9fd6073784d3fc428141dbd10b81c01fd143d0797f58.txt +176 -0
  27. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/219920e865eee70b7dcfc948a86b099e7f4fe2de01bcca2ca9a20c0a033f2b59.txt +7 -0
  28. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/23860c2a7b5d96b21569afedf033469bab9fe14a1b24a35068b8641c578ce24d.txt +7 -0
  29. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3.txt +23 -0
  30. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5.txt +220 -0
  31. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/27995d58ad5c1145c1a8cd86244ce844886958a35eb2b78c6b772748669999ac.txt +25 -0
  32. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/28a9529c7d0bb4dc51f4bf5c116a3d16ef247a052f7591466768ddf563fd1cf5.txt +428 -0
  33. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/29e9fe5074bd27e0e5d5d110394fbbcd841baee2651a3c4b4560a632702cede4.txt +26 -0
  34. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/30fefc3a7d6a0041541858293bcbea2dde4caa4c0a5802f996a7f7e8c0085652.txt +23 -0
  35. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/3521672491a3479422d5fe1aca6645dd2984090f85da6e5205abfb18fb7a6897.txt +25 -0
  36. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/35242e7a83f69875e6edeff02291e688c97caafe2f8902e4e19b49d3e78b4cab.txt +176 -0
  37. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/36516aefdc84c5d5a1e7485425913a22dbda69eb1930c5e84d6ae4972b5194b9.txt +23 -0
  38. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/375bdbf54d6584debb4bcc5bce1c9dcfdd581f977c9a8469113dbdf208f4c927.txt +131 -0
  39. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397.txt +25 -0
  40. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/391a5396cec6230bfabd4ef4eb2350eb895bc5efce377a2218f5702ed020d3e3.txt +20 -0
  41. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/39712155836e5c10ef1b07037b606e4ad2d633e72205d162fdd7e2290aa54f15.txt +21 -0
  42. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/3bb1e548250b3acc43febde65a5cdba9f2e0a3288018aa41f009a3c59ffab51a.txt +390 -0
  43. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/3bc70e239e91272782006c638fc0452a714d384224f11f0923036b7be07cf9b5.txt +21 -0
  44. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/3f3d9e0024b1921b067d6f7f88deb4a60cbe7a78e76c64e3f1d7fc3b779b9d04.txt +373 -0
  45. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/3f941b3b89cf7b8370ceb83cc76d2120d471b58735d8ca60238a751a48d7f72f.txt +359 -0
  46. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/3fa4ca83dcc9237839b1bdeb2e6d16bdfb5ec0c5ce42b24694d8bbf0dcbef72c.txt +25 -0
  47. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/42fa16951ce7f24b5a467a40e5b449a1d41e662f97ca779864f053f39e097737.txt +26 -0
  48. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/4455bf75a91154108304cb283e0fea9948c14f13e20d60887cf2552449dea3b1.txt +21 -0
  49. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/451167c55c0fa447cc2d5632714f5e3c567fe4f1e1badefab2c1333852198aca.txt +542 -0
  50. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/45f522cacecb1023856e46df79ca625dfc550c94910078bd8aec6e02880b3d42.txt +25 -0
  51. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/45fd05c4865e7c350b98ad7ac50e1b15462d49af4a91e9b0c9dd933dc9a69742.txt +201 -0
  52. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/4789210f4df8abc03fce1cddd9c2ba517f184840687f2815d741de282c1aa93a.txt +228 -0
  53. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/4cada0bd02ea3692eee6f16400d86c6508bbd3bafb2b65fed0419f36d4f83e8f.txt +25 -0
  54. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/516b24e051bf5630880ebbd55c40a25ce9552ebaf8970a53e8976eb70e522406.txt +201 -0
  55. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/553fffcd9b1cb158bc3e9edc35da85ca5c3b3d7d2e61c883ebcfa8a65814b583.txt +13 -0
  56. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/5757a1f28eff735a8b5e7425478f367812d71e974530f5bedd01219480965f4a.txt +51 -0
  57. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/5b698ca13897be3afdb7174256fa1574f8c6892b8bea1a66dd6469d3fe27885a.txt +19 -0
  58. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/5e05b024f653a5ce199e77cbbbd42fb5553562ec714b819421ed0c3e552a75d7.txt +25 -0
  59. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/60a7062291b01ba068f300612cdbdc20382ac1d4934f07bcdd7167c15299f309.txt +25 -0
  60. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3.txt +25 -0
  61. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a.txt +176 -0
  62. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb.txt +25 -0
  63. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/65f94e99ddaf4f5d1782a6dae23f35d4293a9a01444a13135a6887017d353cee.txt +25 -0
  64. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/6df43f6f4b5d4587f3d8d71e45532c688fd168afa5fe89d571cb32fa09c4ef51.txt +187 -0
  65. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/709e3175b4212f7b13aa93971c9f62ff8c69ec45ad8c6532a7e0c41d7a7d6f8c.txt +25 -0
  66. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/71674605ec4c087fe9eb534e3e4f9e26eb2e4aabcd76a29fd156c6a844d44b3d.txt +21 -0
  67. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/7365cc8878a1d7ce155a58c4ca09c3d7a6be413efa5334a80ea842912b669349.txt +25 -0
  68. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/7abd9b6960dcf7d4d0a48606a5b71bfe37d472db68d70637f3a58a56785f1621.txt +13 -0
  69. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0.txt +25 -0
  70. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/7ca6700600dfa9c9497bf5556365067daa802c871ea78239f129309c7a2048f7.txt +21 -0
  71. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/7cfafc877eccc46c0e346ccbaa5c51bb6b894d2b818e617d970211e232785ad4.txt +15 -0
  72. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c.txt +24 -0
  73. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/7e5886959f67f8c75063a9d55cd3cb08c5a8cbea9a944fa1df2d4ae038f53721.txt +21 -0
  74. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/7fea0ee51a4ca5d5cea7464135fd55e8b09caf3a61da3d451ac8a22af95c033f.txt +20 -0
  75. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/8173d5c29b4f956d532781d2b86e4e30f83e6b7878dce18c919451d6ba707c90.txt +201 -0
  76. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/83c1763356e822adde0a2cae748d938a73fdc263849ccff6b27776dff213bd32.txt +24 -0
  77. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/86dd7f026f916daf7511e39951ad8ea8cf55a8db67ae64060dacf829761c18f3.txt +25 -0
  78. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/8a35369f3ca263b3c62fbb5032947e53b6bfebc6c8a4d1bb982de1c069f6fba5.txt +21 -0
  79. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/8b43ce8accd61e9d370b5ca9e9c4f953279b5c239926c62315b40e24df51b726.txt +25 -0
  80. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/8bb1b50b0e5c9399ae33bd35fab2769010fa6c14e8860c729a52295d84896b7a.txt +201 -0
  81. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/8bce3b45e49ecd1461f223b46de133d8f62cd39f745cfdaf81bee554b908bd42.txt +21 -0
  82. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/8c7516d4b27b1e495be5e38b612298b63de48d05f49cdac94f70f3cd70f8864b.txt +25 -0
  83. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/9046848b63a5c92bff14e4accca80bd987e0623b74adf9226ce5198d312b79d5.txt +30 -0
  84. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5.txt +12 -0
  85. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/9117d922e667125508dde62b02c1f57ed22f5ad21eb536aa2e2d99e1c796e639.txt +25 -0
  86. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/9387c2d197e2370a740ca457dae1662c56de56b811ee4862024343961307f9bf.txt +19 -0
  87. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/946c9835d8034d24404f8cfec5f4654cee5dad17e944afc3d06d742cf2882831.txt +240 -0
  88. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/95bd3988beee069fa2848f648dab43cc6e0b2add2ad6bcb17360caf749802bcc.txt +176 -0
  89. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/9ba9550ad48438d0836ddab3da480b3b69ffa0aac7b7878b5a0039e7ab429411.txt +396 -0
  90. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/9d185ac6703c4b0453974c0d85e9eee43e6941009296bb1f5eb0b54e2329e9f3.txt +202 -0
  91. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba.txt +25 -0
  92. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/9f2ae19ef94ba82887729a4a1617ff25eede56611dd21a4b2c6f797df30fca33.txt +2013 -0
  93. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/9fa38f610a00115dd1f612bdd3559e3b381ea579538b6ff25a5899da250a5fce.txt +21 -0
  94. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/a00511478c83ebb464ef19d840f061c7444adc4636bb561900e75c5808cfc6cc.txt +21 -0
  95. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/a2010f343487d3f7618affe54f789f5487602331c0a8d03f49e9a7c547cf0499.txt +121 -0
  96. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/a5dea80c1f383cb5f80a6bb0da5e55a2beb9f24adb123ce6300af2cbaaa3bf65.txt +19 -0
  97. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2.txt +201 -0
  98. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/a825bd853ab71619a4923d7b4311221427848070ff44d990da39b0b274c1683f.txt +21 -0
  99. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5.txt +201 -0
  100. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf.txt +201 -0
  101. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/ae9baa7beea910273c2f384c2a6b721fb7bd02bda3436074a1072e4ee689f985.txt +25 -0
  102. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/b1181a40b2a7b25cf66fd01481713bc1005df082c53ef73e851e55071b102744.txt +19 -0
  103. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/b38f11f6096706e6de553dabe2a7ed142d59b6fa8c97e290c67496154745cdd5.txt +25 -0
  104. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/b3d734001a94efff3579978d953391aa7115f877657d25eb54037a43875d078a.txt +9 -0
  105. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/b40930bbcf80744c86c46a12bc9da056641d722716c378f5659b9e555ef833e1.txt +201 -0
  106. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/b4eb00df6e2a4d22518fcaa6a2b4646f249b3a3c9814509b22bd2091f1392ff1.txt +27 -0
  107. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/b68ad1a3367b825447089e1f8d6829b97f47a89eb78d2f4ebaef4672f5606186.txt +22 -0
  108. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/b7e650f3fce5c53249d1cdc608b54df156a97edd636cf9d23498d0cfe7aec63e.txt +19 -0
  109. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583.txt +21 -0
  110. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b.txt +201 -0
  111. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383.txt +21 -0
  112. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/c30152c94a6d75e021adbc52b3a52470366a46edb917e17deae3259251af244c.txt +42 -0
  113. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/c394e3bda1f3b9378f30a7cab11242887eeeafc73c7bef36a0fe13e09691e18b.txt +17 -0
  114. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4.txt +201 -0
  115. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/c962ee4d1d05ddc138b202b2540219ebc57893fcf97b364852094a9a94ce1365.txt +7 -0
  116. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5.txt +25 -0
  117. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30.txt +202 -0
  118. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/d1fc1bc0d155df60b2e7705b6b2ae02a05c96f948e1cec6e2fb86360b09f346b.txt +29 -0
  119. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef.txt +25 -0
  120. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/d5fca2653c88ad02d197faead77e22b80c70636b5bec6e02f2805f389a21b86d.txt +10 -0
  121. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/db11fec9946737df39ca3898d9cd8c10ec6f6c3a884a6802b0ad0b81b4e8f23a.txt +1 -0
  122. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/dc91f8200e4b2a1f9261035d4c18c33c246911a6c0f7b543d75347e61b249cff.txt +25 -0
  123. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/ddea4e94a1c35ed9826e54e13a5b50b8f81b21665a00ca07c8861f1859e56b6b.txt +14 -0
  124. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/e271993808fec50ab29350b39539cdec611a9103f827e0aa26d61da70e2d33f8.txt +61 -0
  125. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/e66c269d4819aaab34b49ef5220c4ddab6756f21bb5180761a4eb8561f2b7bbd.txt +438 -0
  126. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/ecc269ef87fd38a1d98e30bfac9ba964a9dbd9315c3770fed98d4d7cb5882055.txt +25 -0
  127. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/efcfee7981ff72431fffb06925cad00a23dce079ed4354f61030ad5abdb78829.txt +22 -0
  128. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/f025ccfb7dfb6bdfedc75ca0f67acc69e6fb4998143d834f7c2f38a29989680f.txt +13 -0
  129. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2.txt +46 -0
  130. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/f51ac2c59a222f7476ce507ca879960e2b64ea64bb2786eefdbeb7b0b538d1b7.txt +25 -0
  131. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/f7715d38a3fa1b4ac97c5729740752505a39cb92ee83ab5b102aeb5eaa7cdea4.txt +25 -0
  132. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/f7db81051789b729fea528a63ec4c938fdcb93d9d61d97dc8cc2e9df6d47f2a1.txt +39 -0
  133. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/f9c4c77baa3828004ee54b8a4f2db2e88ed44a6237a493965bf551fac0fcb62d.txt +17 -0
  134. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85.txt +373 -0
  135. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/fb77f0a9c53e473abe5103c8632ef9f0f2874d4fb3f17cb2d8c661aab9cee9d7.txt +25 -0
  136. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2.txt +25 -0
  137. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/ff92bed461f50338dd703a9ba9aee496a425957873df1d91192776e4bdf5dda7.txt +74 -0
  138. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/rust-std-1.99.1/COPYRIGHT-library.html +29357 -0
  139. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/rust-std-1.99.1/licenses/Apache-2.0.txt +73 -0
  140. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/rust-std-1.99.1/licenses/BSD-2-Clause.txt +9 -0
  141. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/rust-std-1.99.1/licenses/CC-BY-SA-4.0.txt +427 -0
  142. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/rust-std-1.99.1/licenses/GCC-exception-3.1.txt +30 -0
  143. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/rust-std-1.99.1/licenses/GPL-2.0-only.txt +133 -0
  144. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/rust-std-1.99.1/licenses/GPL-3.0-or-later.txt +202 -0
  145. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/rust-std-1.99.1/licenses/ISC.txt +7 -0
  146. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/rust-std-1.99.1/licenses/LLVM-exception.txt +15 -0
  147. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/rust-std-1.99.1/licenses/MIT.txt +9 -0
  148. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/rust-std-1.99.1/licenses/NCSA.txt +29 -0
  149. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/rust-std-1.99.1/licenses/OFL-1.1.txt +43 -0
  150. package/dist/phoenix-diagram/THIRD-PARTY-LICENSES/rust-std-1.99.1/licenses/Unicode-3.0.txt +39 -0
  151. package/dist/phoenix-diagram/THIRD-PARTY-NOTICES.md +210 -0
  152. package/dist/phoenix-diagram/THIRD-PARTY.json +5459 -0
  153. package/dist/phoenix-diagram/VERSION.json +39 -0
  154. package/dist/phoenix-diagram/bundle/ENGINE.json +39 -0
  155. package/dist/phoenix-diagram/bundle/SKILL.md +109 -0
  156. package/dist/phoenix-diagram/bundle/examples/minimal.architecture.json +11 -0
  157. package/dist/phoenix-diagram/bundle/examples/minimal.class.json +23 -0
  158. package/dist/phoenix-diagram/bundle/examples/minimal.dataflow.json +11 -0
  159. package/dist/phoenix-diagram/bundle/examples/minimal.erd.json +25 -0
  160. package/dist/phoenix-diagram/bundle/examples/minimal.lifecycle.json +11 -0
  161. package/dist/phoenix-diagram/bundle/examples/minimal.sequence.json +13 -0
  162. package/dist/phoenix-diagram/bundle/examples/minimal.timeline.json +15 -0
  163. package/dist/phoenix-diagram/bundle/examples/minimal.tree.json +13 -0
  164. package/dist/phoenix-diagram/bundle/examples/minimal.waterfall.json +12 -0
  165. package/dist/phoenix-diagram/bundle/examples/minimal.workflow.json +12 -0
  166. package/dist/phoenix-diagram/bundle/manifest.json +253 -0
  167. package/dist/phoenix-diagram/bundle/references/architecture-compare.md +111 -0
  168. package/dist/phoenix-diagram/bundle/references/authoring-defaults.md +42 -0
  169. package/dist/phoenix-diagram/bundle/references/brand-marks.md +52 -0
  170. package/dist/phoenix-diagram/bundle/references/compatibility.md +22 -0
  171. package/dist/phoenix-diagram/bundle/references/delivery-contract.md +127 -0
  172. package/dist/phoenix-diagram/bundle/references/extending-types.md +14 -0
  173. package/dist/phoenix-diagram/bundle/references/migration.md +57 -0
  174. package/dist/phoenix-diagram/bundle/references/preview.md +45 -0
  175. package/dist/phoenix-diagram/bundle/references/repository-authoring.md +29 -0
  176. package/dist/phoenix-diagram/bundle/references/viewer-runtime.md +27 -0
  177. package/dist/phoenix-diagram/bundle/schemas/README.md +23 -0
  178. package/dist/phoenix-diagram/bundle/schemas/architecture.schema.json +329 -0
  179. package/dist/phoenix-diagram/bundle/schemas/class.schema.json +348 -0
  180. package/dist/phoenix-diagram/bundle/schemas/common.schema.json +358 -0
  181. package/{skills/archify → dist/phoenix-diagram/bundle}/schemas/dataflow.schema.json +36 -8
  182. package/dist/phoenix-diagram/bundle/schemas/erd.schema.json +384 -0
  183. package/dist/phoenix-diagram/bundle/schemas/lifecycle.schema.json +202 -0
  184. package/{skills/archify → dist/phoenix-diagram/bundle}/schemas/sequence.schema.json +41 -10
  185. package/dist/phoenix-diagram/bundle/schemas/timeline.schema.json +170 -0
  186. package/dist/phoenix-diagram/bundle/schemas/tree.schema.json +144 -0
  187. package/dist/phoenix-diagram/bundle/schemas/waterfall.schema.json +150 -0
  188. package/{skills/archify → dist/phoenix-diagram/bundle}/schemas/workflow.schema.json +42 -10
  189. package/dist/phoenix-diagram/bundle/scripts/phoenix-bootstrap.cjs +589 -0
  190. package/dist/phoenix-diagram/bundle/scripts/phoenix-diagram +6 -0
  191. package/dist/phoenix-diagram/bundle/scripts/phoenix-launcher.cjs +10 -0
  192. package/dist/phoenix-ui/THIRD-PARTY.json +164 -158
  193. package/dist/phoenix-ui/VERSION.json +17 -17
  194. package/dist/phoenix-ui/bundle/blobs/00727f7b333a7be8ac7740aa257a3a3f691db8ae545a6afab2b787acab5e88df +46 -0
  195. package/dist/phoenix-ui/bundle/blobs/{547e3c89d5b8feeddd67e43131fd84b95253eb42bf7d730b4e471dba011f6e51 → 00f4a6a630f31eb05fbdd5725e4a294233d24574bd70f4f32f4597d8256a7c1c} +0 -4
  196. package/dist/phoenix-ui/bundle/blobs/{41400e182e2180a567923d58bfa935d2799a54f2a747b2c5813c3884c84f768b → 04057592e18ea9dd3c4edcac14cde3fa5b75239c2552d4459db8e047068f61a8} +6 -7
  197. package/dist/phoenix-ui/bundle/blobs/{34571f7d46632205d518d15cb008457494dfad745c6b483bb11d63ca3a22ac48 → 0cb3bf26e1980b0e530373fb32edbe5864a171492a04e2abe1952ffe78bff231} +6 -7
  198. package/dist/phoenix-ui/bundle/blobs/{852d2943678a76c33b2f7a090d2ca6c152cd120e9ae62775fcc91519b9289011 → 0e684572eb98d24b39cd70fa23e66c163178f5a11756dcf8a98fe2335636b33f} +6 -3
  199. package/dist/phoenix-ui/bundle/blobs/{d17b3a454146e74ef4ecf69d7b72a8fa45c4fe1c695dffb0d36690b653cd2d8f → 10553c45c7bf38e527a57a281c4365152a768b4dd7ef597ff34ae841e9ff7d41} +6 -7
  200. package/dist/phoenix-ui/bundle/blobs/{e49257c0fd32b195cccb16fbfda769c007be6b38f25aceefecd23cfff9366cec → 125bc7030d7f2ba789d7b1d5f474af34f8902b764e7bc351b98f1f6f55779929} +6 -3
  201. package/dist/phoenix-ui/bundle/blobs/{74dbcbbad6c3831e95abb38775dd488c59ae9f1d44a95f5fd4bc0051577488fa → 13cf6c054ed424e2eb639ea12d20a4aa2b1c85eeb00afa8cbd8a30c6c22aadd8} +1 -1
  202. package/dist/phoenix-ui/bundle/blobs/1832ff9624cebd30370eb0e806665c656ac879215f93d33bcc0750baa47459dc +46 -0
  203. package/dist/phoenix-ui/bundle/blobs/{8e7de5ca347036a07f5f1e9cab942d8ff378d029bc101fa6d126406f3298c9db → 1864a10c29e7062cca5e49d1790dc7d9d8ea777bfa2ab6fd941635965cd0084d} +1 -1
  204. package/dist/phoenix-ui/bundle/blobs/{784722b72224a7005a80cdcd6408dd2b25b23fd9619d0f6c8788f7ac681fad4c → 1ecc81de39d28b85b95e797bcc338d4213a50231c3315a741d14571fd22c844f} +6 -7
  205. package/dist/phoenix-ui/bundle/blobs/{b8c614dc7c2eb30ee0f864fec116dbcafb39e5a199dce66d0c1a88b13f76265a → 2079e4146039a8dadf19a39237cbdc0b8b54ea1fa16d320716c2cbf58161c835} +1 -1
  206. package/dist/phoenix-ui/bundle/blobs/{dba6e4a09c5d752e5ddebe7c2c1aefc9c4b2a84e01a3178599579778ed2d09e9 → 2813aa68c0804a7fe061d88201d8a684cac9987b48511e1e2cbfe0a869a67a82} +6 -7
  207. package/dist/phoenix-ui/bundle/blobs/{2889c2817b5079abff254bb6d13f92dbde0fabc38be4acc7d20e613eef5e5829 → 2873e340be947c83c3d03520139b73524fd166a34063d2693d3b711021ea5b87} +6 -7
  208. package/dist/phoenix-ui/bundle/blobs/{64c4aa2d1c24ae5028e987498ac544020d48600a51d9654b2df562681ba480f2 → 298ef41899acefa056eccf2345378078832db6d868d2377f471f896d5c1599f9} +6 -14
  209. package/dist/phoenix-ui/bundle/blobs/{1b7174a6f3f49a8efc8f7fa74ff84cf8960e2646b9bc976e4129a7c8ad608faa → 2b5cef2a14a5b1256ec6de9172a4f57f227948ced1921ef86e899f48524d7fb8} +1 -1
  210. package/dist/phoenix-ui/bundle/blobs/{f148f630f43f3c91cf10feeda5a3c21448ca0683ce82d0fe763c1b43dee584d6 → 2d376cbbf7ec1e262614aac4f1b200e8f60e86e940c7137a2a26788bc857e509} +6 -7
  211. package/dist/phoenix-ui/bundle/blobs/2e5985a6eb339d70cfa25f6d2b420a0ef286caa8467f0226eb841702ec438d0b +46 -0
  212. package/dist/phoenix-ui/bundle/blobs/{7e199833376de5d2b6e088ee2965b448f94da842f28ccbd707e1cc3a295147c8 → 3322d691bf7b578b38723576df6b266993b2afb9e567b0cd1ded898ffe1dc17e} +1 -1
  213. package/dist/phoenix-ui/bundle/blobs/{f82bfc4c6bc9169d4978d5e16fb925f6e152fdd21dc6a2fae719dfdc1645581f → 3625c5c2750f117021232ce81c1e39ac5ef7c21445729327b88cf54dfc937df0} +6 -3
  214. package/dist/phoenix-ui/bundle/blobs/{2ceacad745665f79fd7ad5565646426a36a1b508c0469b931d0f202fad45a80b → 36310febe3e7bd4c9b21407603f2a04afefdc87b7821758bb47098b1b2876765} +6 -3
  215. package/dist/phoenix-ui/bundle/blobs/{24d92a176573768bfffaf8f9c6483e58bceb5bf2a095d1cdf3d3a2c0bcda0707 → 3a9c2daf4ef284ca83b0e7f6fef3a5300e273c32b20769e090463cb8a8b0b06f} +1 -1
  216. package/dist/phoenix-ui/bundle/blobs/{153e377c44b162cf0074698a61716db7f664db78f5635efa926bed484de4f54c → 3ce1a44efe39b93e7a39307c6a5e5f514e938fbae818e358986b4db1b05883ca} +1 -1
  217. package/dist/phoenix-ui/bundle/blobs/{ad8ad0b7acf6c88ef9ce0ee1a640c2200da77821f0d97d605d4f1d4a10e5897a → 403fcde498d75abec7844ee31434201152ac229f7675772164d69563f0572da4} +1 -1
  218. package/dist/phoenix-ui/bundle/blobs/{e8ee6c08e94b80324173d89d6f4cdc5b4829ea6858b3a11fc186588a490cada4 → 45d0e7eff0923c40296e971318756617944c4f1c97f03126cd74c0f8c629f8a4} +3 -1
  219. package/dist/phoenix-ui/bundle/blobs/{e23dabf908842be08751fc4e7f3b586e8c6b1ca0fc30303ec5317c77f83dcf26 → 4c0f396bfa85171f61972d3f3765733318769bb53fe06d2cdcb5d7f64578b5b8} +1 -1
  220. package/dist/phoenix-ui/bundle/blobs/{a5517d32c1539c388c47c00879a0d807ed2989647bfa8c0844ef22328f75f5be → 4f6563876e0e0cc51c38a06767b8800eb3238611e9fdd11e5ff9dd487c742e74} +1 -1
  221. package/dist/phoenix-ui/bundle/blobs/{a9d2203acd45ca33a13d5c68b02b23ed512425ac15f0e8438318ed124b43729d → 4fcada229d0c689c1a493d13184145a81ff40c498e882142ae390bda8e5b2492} +15 -0
  222. package/dist/phoenix-ui/bundle/blobs/5293adc55cf66068b6df20468ad9e91433fd1c48e75d66c86f874aca951a8fb9 +46 -0
  223. package/dist/phoenix-ui/bundle/blobs/{96e2e6bd4fcf9a2c6da65fb029f96d9176308fae2efd9d8653d3b8d838960e07 → 5436f0301ec258f3badcc6842019ee29a9b870d2727dc425fbc9cc0f4f88a284} +3 -1
  224. package/dist/phoenix-ui/bundle/blobs/{d0f4939e86a62b0ca437d51a997ceba7e77d64566b7fa8ca2747487e31ca819d → 54a09a4afdffca3cc135e5007716ea684dc1ed7a78349de859225c55a2fed810} +6 -7
  225. package/dist/phoenix-ui/bundle/blobs/{d5102701d41f7c6195d410a873f742ac72c428b04196e47df5555c5ccaf80504 → 55277fa15eb4bd2f09bf7bb24c4e79df417b06654b1e10f502c7928b192fd7cc} +6 -3
  226. package/dist/phoenix-ui/bundle/blobs/{878064e46af4e4109bab405f965e4149bee40bbe8912ffede10b74cec6cff027 → 567c3f42394f9aee9b048a001016a7ba9d8773d78027f8c995c379886634e719} +6 -3
  227. package/dist/phoenix-ui/bundle/blobs/57c8f33a7401f918566b8a4883871a69ef2223438c51f158c67f69e3250be465 +46 -0
  228. package/dist/phoenix-ui/bundle/blobs/{bc29e115fd337dda2cc7fc70b868dc18e426b08ec186fd270fcfe96bb2efaa5d → 61450dbef64859e3136cd17ae3e997134d5df5721d96985c4e07367f38522129} +6 -3
  229. package/dist/phoenix-ui/bundle/blobs/{e3c1e925be0b2deb0e3765b83ab94b86560292364f275e98bb23a8bdf2c2e049 → 656bbfda3e72b40d53b5832293dc8700ad8a784e804a6246271bf0ea23527822} +1 -1
  230. package/dist/phoenix-ui/bundle/blobs/{ffcaa5c58e779ec74d18bfc3013ad8003f6e7a23f629c1a3b878618961a8b6a3 → 68b454a99ba72c3b9b93ed96c4267847297169f6a5bf321b20e60d637c271068} +6 -3
  231. package/dist/phoenix-ui/bundle/blobs/68e44832c82b873b0aeb2da56def7b1de5f612c019445e5e28238c690124cbbe +46 -0
  232. package/dist/phoenix-ui/bundle/blobs/{45bbd4a8e02ca0012216c5c68e1dcd655ae0046bd50ba4295ef1f58ec4a0957c → 6b8d4c71355429a0b16bf367163fea46103a0a99b4e34f87608a39d85b1b980a} +6 -3
  233. package/dist/phoenix-ui/bundle/blobs/{264815d0080e4862715a4f82542e66241c6563f07259d32aed4a17bbc329b9cc → 6cef874722442de7c60ea96f4221dc54cc4250a270cd05a1e818b58c5b43e232} +6 -7
  234. package/dist/phoenix-ui/bundle/blobs/{2028a857c0476324a4256faf66693e2a869275e53a88d2b182a28b62c2a17893 → 7181f1f4c452c4345695f9100f6deb610f54f4c55f126043433a65b8491fc680} +6 -7
  235. package/dist/phoenix-ui/bundle/blobs/{ccb76aabba47938d518a5d46a09d7e70c4a9222bc391e163763f2a7f12d30437 → 75850a8c9d2a8259f71ef1f86dd5d1325415227c1887e81a3467ae1ee400979f} +1 -1
  236. package/dist/phoenix-ui/bundle/blobs/{4b03cdb5b17d534b5c7e84b079c066f59e8b60b9e454671a453867c4aeb9920d → 77bcc6c2d6ac00a8bfead3b6c6b5fc69f4b60bf086ebbc89271e1b23003168c9} +1 -1
  237. package/dist/phoenix-ui/bundle/blobs/{9520e25a381c82af6f46e175b7c347d1dc513d933dd6cf8c52570c72abb4ca7f → 792552563745d208594cf4ade19110f2c811a0e1a2661ae1ef43a185ccff5a69} +1 -1
  238. package/dist/phoenix-ui/bundle/blobs/{f7c8af35acf71a96056afb6afcff6a3ea42f65561f02652d04e11ad9ece9b8e9 → 7acd9b6f2f61b509c6a518508b8b52c2f0de67cdea4fd3f3d383b3ce8b38cf5e} +6 -7
  239. package/dist/phoenix-ui/bundle/blobs/7bacc1e3da7e8b7127ca3f8f69a2422098b9b2d23fbedefc56dfe76117c1c0e3 +46 -0
  240. package/dist/phoenix-ui/bundle/blobs/{78662176c1d31cec2d640f70df203f93cc1aec604cfc31619f4d2c62ab78861b → 8078b804bea630ed9c4ea07ec2f8ac92aba4128725860a66599eda90390d98f6} +6 -3
  241. package/dist/phoenix-ui/bundle/blobs/{2291169748fe0c4c80634dff3083e7464f82d4358b9b2186759b316e612d466f → 88b150cb804bc141b80a5687a091f61b99627155c465a27adb88546ef615af92} +6 -3
  242. package/dist/phoenix-ui/bundle/blobs/{bde88bf5ac59d744440d9b65f95ceaae01c803b101d48e6afd644a06eeb5de63 → 90f8b07ec12b78e633e306322cda58415aea70d8e0f9ff85bd439361c01dabe1} +6 -3
  243. package/dist/phoenix-ui/bundle/blobs/{486145071d3445e82774f1b39b2bb15986ce52277e798a31ef7e9c27afb42af3 → 95b2944686e8258a655c3b5e6db68593e24e5199354e46aac553918ea2c0f55a} +1 -1
  244. package/dist/phoenix-ui/bundle/blobs/{a1998e37084c11f496d4970f86a85d5a6375bbeaa4797b9f42bbac2d44048d23 → 979639f0e8859d600a8db57e733566d9ad37ff8258c3e05a6f9c0f3008e92373} +1 -1
  245. package/dist/phoenix-ui/bundle/blobs/{3173293607055ea6e1a153ec6f51fb8154782157c8a61abf411da1f41be61728 → 9eaaa00049844060f842fe7fb73cc8edc4be5225cf38a96f33bda3ffc381456c} +6 -7
  246. package/dist/phoenix-ui/bundle/blobs/{69086f7cb235b35ccc230e1f2da41cbb10cea8f0636b6d4514672113a3adc2cb → a420bbda622399399a6b5c7c3614dcaebc6c62faceaf7b3c83c97db53d26b165} +1 -1
  247. package/dist/phoenix-ui/bundle/blobs/a63054b8920905045753facece83f154bf806158c6f46ef380036e7a82d4fde5 +46 -0
  248. package/dist/phoenix-ui/bundle/blobs/{e802e4f7bdc89050a9c0f2ca506e1d493a2316e6e810c0336c57aa073717ef3e → a63788c764b0e4fdcbc029d46093016310edcbcf702d62688e5aaac7ddeee6fd} +3 -1
  249. package/dist/phoenix-ui/bundle/blobs/{827a211ea03d2cb44b4ea1bc81ba1a6dc51a87fa16d6692997c4e4751241c815 → acfc4c26b135d5b27fc0930738486c9d43d379704102fab45564320180942e4b} +4 -2
  250. package/dist/phoenix-ui/bundle/blobs/{8da14f3eabac53c990a66e721387367b46cb676cc4204e8c67d6f88c95a6217f → ad243ca615349127aa422bccc1a6604ad17149735659087ca5bab3c5fae97f4e} +6 -7
  251. package/dist/phoenix-ui/bundle/blobs/b63931066e2b2623d012e1a3c1a0769cc43ed6640460c3899669b45539d6a20d +46 -0
  252. package/dist/phoenix-ui/bundle/blobs/{bb65af58ecc3e0c0093dc9a705a7ab643035e4e592c3adb93583c82d1aef1f51 → bde793ab5ad776f7e6f6d25ce2b838c1b5022054a1dad5502a873423eb0ad917} +6 -7
  253. package/dist/phoenix-ui/bundle/blobs/{8de7c97949b0bc4194b3be7645e4b13e9419767927482d01cf19476f6cbeda14 → c0a70ab2889e5c16e1f09249aefad948ce352c42cfe2b5afb758a4524e1b21b6} +6 -3
  254. package/dist/phoenix-ui/bundle/blobs/{60b2914df394800688c4e20f4eb34e117cd430df9954cf4d48574734507723f4 → c9ee9006ae6c0194a5d39a9f0cb275c52d74a71ea3f6dc2b4c1c7bd89f48a2c0} +1 -1
  255. package/dist/phoenix-ui/bundle/blobs/{6d8315e307eab11d3236935daf7267746cce6da3b51296e6999651ac97bda3a3 → cadc2daefcf238aab981fa56388381d3d5ab9c0686bb9dd8187035c9933dfcee} +6 -3
  256. package/dist/phoenix-ui/bundle/blobs/{d7b744fcc95164d96d9f811a93e2e8a374887146eb762ef775f3d3c7f27abc8d → cbea5728b90f58ff047be6ec4f14eed9d63c7148f5db99b5f147d2f17b472317} +1 -1
  257. package/dist/phoenix-ui/bundle/blobs/d408a4fea71b656aa8a5f6b5c037815a6e4229df336629ebddf4b5c85ed82fac +46 -0
  258. package/dist/phoenix-ui/bundle/blobs/{6ff950a5729ad9ea480ddf8c1b489b1c84189bbf7d6034b3b5a98e7c11a28cec → d9ae0c782d8a77787561536c0d7bc3b61175d59303f3cb8c20796f85140c6984} +1 -1
  259. package/dist/phoenix-ui/bundle/blobs/{1d53e2226465b1047faec7cda2e743e61540ea69e073a3a4057e8d86b277405f → e2932d63eb7f52a82960a19ba79bc800ef4f212164e098f96dee7a4326302f38} +1 -1
  260. package/dist/phoenix-ui/bundle/blobs/{fa576f6655b235bdea535198647305b7a3855e810180cbdf5d4c246c03c7d190 → e381bcfec42ac541d574011460600cf0818aa0e3362e8c6d205b4157890bf821} +6 -7
  261. package/dist/phoenix-ui/bundle/blobs/{8fbce5b4859e6011afa83b1c07c4436589cd7181f9cb997538f4c27f196d0d34 → e415657d8725d9b60ece42cc18581da177c42fc47cb11e501db722a5f524ecf7} +6 -7
  262. package/dist/phoenix-ui/bundle/blobs/{546a8428a2d8628bb3496fadb8c36a6dd65a33464291f214ceb581828f37081b → e46d63e5f8a6ead1d44c8b6302a0c7247af8585b975ab5715518381777622ede} +6 -3
  263. package/dist/phoenix-ui/bundle/blobs/ee63b3f9b354d69443d05ea4a338af56546897335ace7533546e10be56ea2207 +46 -0
  264. package/dist/phoenix-ui/bundle/blobs/{c23617601e9c4d97b775c175a5ce1642c40459b157d0821609fe1d253b83ced8 → ef7d57633252f4604749447608850e299c277f7dd1a32776685df0724b1051c8} +6 -7
  265. package/dist/phoenix-ui/bundle/blobs/{0581c8428246f43c5374393878a29e38f2b1865df87e6f13f2309b8eae54e76f → f0652c6ce41e6949133360178f192ea4ee9f6129a018c7a8b6652870c2330392} +1 -1
  266. package/dist/phoenix-ui/bundle/blobs/{cfac9eaf96481a8874391e5cecc6149abea1f1f19622f77f1ebb9e1876720e91 → f06c9d797ca2ac8c6a49d3dcd2e99d1b4df8bc9637a49c7e80f3161f49d06b1b} +4 -2
  267. package/dist/phoenix-ui/bundle/blobs/{d50780cb0a345051ae3fb12c5f8249a5dac9324d6a1963f04d03aaf769ffc27c → f077545caeb3ecb9f51a3f703a09736ca924869f4b4345c1b1ffbd9bf927a287} +6 -3
  268. package/dist/phoenix-ui/bundle/blobs/f781c5874bcd79ebe1b3b012275b9af7eae6c4867e9a16e29bb3d3ed3dc1940b +46 -0
  269. package/dist/phoenix-ui/bundle/blobs/fa10c0c926997387c89b7c1070e25b1b2b53ee891741e3c450a89ec6c6dcaf7d +46 -0
  270. package/dist/phoenix-ui/bundle/blobs/fb1a36ab7116b0c6709b89720cdded29d80982114c2f87cad614e01e126270dd +46 -0
  271. package/dist/phoenix-ui/bundle/blobs/fbd3214fc12ba70d9c69a995742ba73dc5365823af63afdc93c0c8a8f0c484af +46 -0
  272. package/dist/phoenix-ui/bundle/blobs/{77682e9d63b484f94a699f2c0b393e4540797d311362c384a3d643aec11d6985 → fea19b8381ec10ff8ed1923a336332974bbb552227ed215e7ddaaf0ec0112c1d} +1 -1
  273. package/dist/phoenix-ui/bundle/manifest.json +126 -126
  274. package/docs/phoenix-diagram.md +173 -0
  275. package/docs/phoenix-ui.md +40 -12
  276. package/package.json +14 -10
  277. package/skills/agi-mode/SKILL.md +3 -1
  278. package/skills/agi-mode/assets/sdlc/event.md +4 -5
  279. package/skills/agi-mode/assets/sdlc/object-status.md +1 -1
  280. package/skills/agi-mode/assets/sdlc/protocol.md +4 -2
  281. package/skills/agi-mode/evals/scenarios.md +108 -3
  282. package/skills/agi-mode/playbooks/authoring-a-skill.md +13 -2
  283. package/skills/agi-mode/playbooks/eval.md +19 -3
  284. package/skills/agi-mode/playbooks/hillclimb.md +4 -2
  285. package/skills/agi-mode/playbooks/reflection.md +1 -1
  286. package/skills/agi-mode/playbooks/sdlc.md +10 -6
  287. package/skills/agi-mode/playbooks/what-next.md +6 -2
  288. package/skills/agi-mode/references/eval-protocol.md +13 -4
  289. package/skills/agi-mode/references/interface-design.md +1 -0
  290. package/skills/agi-mode/references/remote-evolution.md +178 -0
  291. package/skills/agi-mode/references/skill-evolution.md +2 -0
  292. package/skills/agi-mode/scripts/evolution/compare.py +569 -0
  293. package/skills/agi-mode/scripts/evolution/evolution.py +2886 -0
  294. package/skills/agi-mode/scripts/evolution/examples/public-smoke.json +128 -0
  295. package/skills/agi-mode/scripts/evolution/examples/quality-calibration.json +128 -0
  296. package/skills/agi-mode/scripts/evolution/examples/quality-rubric.json +133 -0
  297. package/skills/agi-mode/scripts/evolution/protocol.py +1586 -0
  298. package/skills/agi-mode/scripts/evolution/pyproject.toml +16 -0
  299. package/skills/agi-mode/scripts/evolution/quality.py +689 -0
  300. package/skills/agi-mode/scripts/evolution/remote.py +2303 -0
  301. package/skills/agi-mode/scripts/evolution/tests/support.py +201 -0
  302. package/skills/agi-mode/scripts/evolution/tests/test_apply.py +643 -0
  303. package/skills/agi-mode/scripts/evolution/tests/test_bounded_exploration.py +236 -0
  304. package/skills/agi-mode/scripts/evolution/tests/test_bundles.py +414 -0
  305. package/skills/agi-mode/scripts/evolution/tests/test_calibration.py +460 -0
  306. package/skills/agi-mode/scripts/evolution/tests/test_compare.py +377 -0
  307. package/skills/agi-mode/scripts/evolution/tests/test_protocol.py +357 -0
  308. package/skills/agi-mode/scripts/evolution/tests/test_quality.py +647 -0
  309. package/skills/agi-mode/scripts/evolution/tests/test_remote.py +857 -0
  310. package/skills/agi-mode/scripts/evolution/tests/test_search.py +1109 -0
  311. package/skills/agi-mode/scripts/evolution/tests/test_typesafe.py +624 -0
  312. package/skills/agi-mode/scripts/evolution/tests/test_verifier_context.py +132 -0
  313. package/skills/agi-mode/scripts/evolution/typesafe_worker.py +145 -0
  314. package/skills/agi-mode/scripts/evolution/uv.lock +2548 -0
  315. package/skills/apply-code-review/SKILL.md +1 -0
  316. package/skills/apply-code-review/agents/openai.yaml +2 -0
  317. package/skills/apply-doc-review/SKILL.md +1 -0
  318. package/skills/apply-doc-review/agents/openai.yaml +2 -0
  319. package/skills/apply-ui-review/SKILL.md +1 -0
  320. package/skills/apply-ui-review/agents/openai.yaml +2 -0
  321. package/skills/autoresearch/SKILL.md +1 -0
  322. package/skills/clean-artifacts/SKILL.md +52 -0
  323. package/skills/clean-artifacts/agents/openai.yaml +4 -0
  324. package/skills/clean-artifacts/evals/scenarios.md +13 -0
  325. package/skills/clean-artifacts/references/history-cleanup.md +41 -0
  326. package/skills/crd/SKILL.md +100 -65
  327. package/skills/crd/assets/cr-template.md +15 -0
  328. package/skills/crd-respond/SKILL.md +17 -5
  329. package/skills/crd-respond/agents/openai.yaml +2 -2
  330. package/skills/crd-respond/assets/response-template.md +7 -0
  331. package/skills/crd-respond/evals/scenarios.md +7 -0
  332. package/skills/create-verification-skill/SKILL.md +1 -0
  333. package/skills/debugging/SKILL.md +1 -0
  334. package/skills/design-md/SKILL.md +1 -0
  335. package/skills/design-reference/SKILL.md +6 -2
  336. package/skills/design-reference/evals/scenarios.md +4 -0
  337. package/skills/dev-plan/SKILL.md +11 -6
  338. package/skills/dev-plan/references/execution-workflow.md +1 -1
  339. package/skills/dev-plan/references/plan-skeleton.md +234 -69
  340. package/skills/dev-plan/scripts/check_plan.py +1 -1
  341. package/skills/documentation-writer/SKILL.md +19 -14
  342. package/skills/documentation-writer/references/architecture.md +6 -2
  343. package/skills/documentation-writer/references/user-manual.md +2 -2
  344. package/skills/elintp/SKILL.md +12 -6
  345. package/skills/experience-capture/SKILL.md +1 -0
  346. package/skills/gdpr-compliant/SKILL.md +1 -0
  347. package/skills/kpi-dashboard-design/SKILL.md +1 -0
  348. package/skills/landing-page-conversion-audit/SKILL.md +1 -0
  349. package/skills/mcp-release-qa/SKILL.md +2 -1
  350. package/skills/meeting-minutes/SKILL.md +1 -0
  351. package/skills/optimize-agents-md/SKILL.md +128 -0
  352. package/skills/optimize-agents-md/assets/coding-principles.md +118 -0
  353. package/skills/phoenix-diagram/ENGINE.json +39 -0
  354. package/skills/phoenix-diagram/SKILL.md +109 -0
  355. package/skills/phoenix-diagram/examples/legacy.agent-tool-call.workflow.json +94 -0
  356. package/skills/phoenix-diagram/examples/legacy.async-job-roundtrip.sequence.json +61 -0
  357. package/skills/phoenix-diagram/examples/legacy.deployment-release.lifecycle.json +49 -0
  358. package/skills/phoenix-diagram/examples/legacy.product-analytics.dataflow.json +76 -0
  359. package/skills/{archify/test/fixtures/v1-baseline/web-app.architecture.json → phoenix-diagram/examples/legacy.web-app.architecture.json} +16 -11
  360. package/skills/phoenix-diagram/examples/minimal.architecture.json +11 -0
  361. package/skills/phoenix-diagram/examples/minimal.class.json +23 -0
  362. package/skills/phoenix-diagram/examples/minimal.dataflow.json +11 -0
  363. package/skills/phoenix-diagram/examples/minimal.erd.json +25 -0
  364. package/skills/phoenix-diagram/examples/minimal.lifecycle.json +11 -0
  365. package/skills/phoenix-diagram/examples/minimal.sequence.json +13 -0
  366. package/skills/phoenix-diagram/examples/minimal.timeline.json +15 -0
  367. package/skills/phoenix-diagram/examples/minimal.tree.json +13 -0
  368. package/skills/phoenix-diagram/examples/minimal.waterfall.json +12 -0
  369. package/skills/phoenix-diagram/examples/minimal.workflow.json +12 -0
  370. package/skills/phoenix-diagram/references/architecture-compare.md +111 -0
  371. package/skills/phoenix-diagram/references/authoring-defaults.md +42 -0
  372. package/skills/phoenix-diagram/references/brand-marks.md +52 -0
  373. package/skills/phoenix-diagram/references/compatibility.md +22 -0
  374. package/skills/phoenix-diagram/references/delivery-contract.md +127 -0
  375. package/skills/phoenix-diagram/references/extending-types.md +14 -0
  376. package/skills/phoenix-diagram/references/migration.md +57 -0
  377. package/skills/phoenix-diagram/references/preview.md +45 -0
  378. package/skills/phoenix-diagram/references/repository-authoring.md +29 -0
  379. package/skills/phoenix-diagram/references/viewer-runtime.md +27 -0
  380. package/skills/phoenix-diagram/schemas/README.md +23 -0
  381. package/skills/phoenix-diagram/schemas/architecture.schema.json +329 -0
  382. package/skills/phoenix-diagram/schemas/class.schema.json +348 -0
  383. package/skills/phoenix-diagram/schemas/common.schema.json +358 -0
  384. package/skills/{archify/schemas/lifecycle.schema.json → phoenix-diagram/schemas/dataflow.schema.json} +63 -58
  385. package/skills/phoenix-diagram/schemas/erd.schema.json +384 -0
  386. package/skills/phoenix-diagram/schemas/lifecycle.schema.json +202 -0
  387. package/skills/phoenix-diagram/schemas/sequence.schema.json +254 -0
  388. package/skills/phoenix-diagram/schemas/timeline.schema.json +170 -0
  389. package/skills/phoenix-diagram/schemas/tree.schema.json +144 -0
  390. package/skills/phoenix-diagram/schemas/waterfall.schema.json +150 -0
  391. package/skills/phoenix-diagram/schemas/workflow.schema.json +460 -0
  392. package/skills/phoenix-diagram/scripts/phoenix-bootstrap.cjs +589 -0
  393. package/skills/phoenix-diagram/scripts/phoenix-diagram +6 -0
  394. package/skills/phoenix-diagram/scripts/phoenix-launcher.cjs +10 -0
  395. package/skills/phoenix-ui/GENERATED.json +255 -240
  396. package/skills/phoenix-ui/SKILL.md +7 -4
  397. package/skills/phoenix-ui/evals/scenarios.md +8 -1
  398. package/skills/phoenix-ui/reference/craft-floor.md +3 -1
  399. package/skills/phoenix-ui/reference/critique.md +6 -14
  400. package/skills/phoenix-ui/reference/init.md +1 -1
  401. package/skills/phoenix-ui/reference/live.md +1 -1
  402. package/skills/phoenix-ui/reference/operate.md +15 -0
  403. package/skills/phoenix-ui/scripts/ENGINE.json +17 -17
  404. package/skills/phoenix-ui/scripts/phoenix-bootstrap.cjs +0 -4
  405. package/skills/portal-app-exchange/SKILL.md +1 -0
  406. package/skills/portal-dev-setup/SKILL.md +71 -12
  407. package/skills/portal-dev-setup/scripts/onebox.sh +69 -6
  408. package/skills/portal-external-app/SKILL.md +55 -16
  409. package/skills/portal-external-app/references/config-placement.md +108 -2
  410. package/skills/portal-external-app/references/registration-and-onebox.md +56 -2
  411. package/skills/portal-logging/SKILL.md +1 -0
  412. package/skills/portal-micro-app/SKILL.md +2 -1
  413. package/skills/portal-micro-app/references/sdk-reference.md +3 -1
  414. package/skills/prd/SKILL.md +238 -159
  415. package/skills/prd/evals/scenarios.md +13 -0
  416. package/skills/prd/references/prd-skeleton.md +14 -4
  417. package/skills/react/SKILL.md +1 -0
  418. package/skills/resolve-blocked/SKILL.md +46 -19
  419. package/skills/resolve-blocked/agents/openai.yaml +2 -2
  420. package/skills/resolve-blocked/evals/scenarios.md +22 -0
  421. package/skills/resolve-blocked/references/decisions-contract.md +7 -4
  422. package/skills/review-code/SKILL.md +308 -46
  423. package/skills/review-code/agents/openai.yaml +2 -0
  424. package/skills/review-dev-plan/SKILL.md +88 -33
  425. package/skills/review-dev-plan/agents/openai.yaml +2 -0
  426. package/skills/review-dev-plan/references/report-contract.md +53 -19
  427. package/skills/review-dev-plan/references/review-lenses.md +2 -1
  428. package/skills/review-prd/SKILL.md +90 -34
  429. package/skills/review-prd/agents/openai.yaml +2 -0
  430. package/skills/review-prd/references/report-contract.md +54 -18
  431. package/skills/review-prd-dev-gaps/SKILL.md +1 -0
  432. package/skills/review-prd-dev-gaps/agents/openai.yaml +2 -0
  433. package/skills/review-ui/SKILL.md +369 -71
  434. package/skills/review-ui/agents/openai.yaml +2 -0
  435. package/skills/review-ui/evals/scenarios.md +2 -0
  436. package/skills/rust/SKILL.md +76 -84
  437. package/skills/rust/references/api-design.md +97 -0
  438. package/skills/rust/references/{chapter_10.md → async-tokio.md} +42 -18
  439. package/skills/rust/references/behavioral-patterns.md +49 -0
  440. package/skills/rust/references/bevy.md +95 -0
  441. package/skills/rust/references/{chapter_02.md → clippy-and-linting.md} +26 -15
  442. package/skills/rust/references/{chapter_01.md → coding-idioms.md} +58 -7
  443. package/skills/rust/references/crates-and-dependencies.md +66 -0
  444. package/skills/rust/references/{chapter_08.md → documentation.md} +30 -3
  445. package/skills/rust/references/{chapter_04.md → error-handling.md} +32 -6
  446. package/skills/rust/references/{chapter_06.md → generics-and-dispatch.md} +28 -11
  447. package/skills/rust/references/macros.md +45 -0
  448. package/skills/rust/references/{chapter_03.md → performance.md} +25 -2
  449. package/skills/rust/references/{chapter_09.md → pointers-and-ownership.md} +37 -17
  450. package/skills/rust/references/{chapter_05.md → testing.md} +18 -2
  451. package/skills/rust/references/{chapter_07.md → type-state.md} +5 -1
  452. package/skills/rust/references/unsafe-and-ffi.md +56 -0
  453. package/skills/rust-port/SKILL.md +144 -0
  454. package/skills/rust-review/SKILL.md +177 -0
  455. package/skills/security-audit/SKILL.md +1 -0
  456. package/skills/spec-human-decision/SKILL.md +1 -0
  457. package/skills/sql-optimization/SKILL.md +1 -0
  458. package/skills/story-points/SKILL.md +1 -0
  459. package/skills/swarm/SKILL.md +1 -0
  460. package/skills/test-plan/SKILL.md +1 -0
  461. package/skills/ui-loop/SKILL.md +39 -0
  462. package/skills/ui-loop/agents/openai.yaml +3 -0
  463. package/skills/ui-pattern-research/SKILL.md +1 -0
  464. package/skills/use-llm-gateway/SKILL.md +58 -0
  465. package/skills/use-llm-gateway/agents/openai.yaml +4 -0
  466. package/skills/use-llm-gateway/references/api.md +129 -0
  467. package/skills/use-llm-gateway/references/recovery.md +86 -0
  468. package/skills/use-prompt-dsl/SKILL.md +165 -0
  469. package/skills/use-prompt-dsl/references/examples.md +726 -0
  470. package/skills/use-prompt-dsl/references/language.md +938 -0
  471. package/skills/use-rustify-docs/SKILL.md +60 -0
  472. package/skills/use-rustify-docs/agents/openai.yaml +4 -0
  473. package/skills/use-rustify-docs/references/rustify-docs.md +138 -0
  474. package/skills/use-task-gateway/SKILL.md +60 -0
  475. package/skills/use-task-gateway/agents/openai.yaml +3 -0
  476. package/skills/use-task-gateway/references/authentication.md +75 -0
  477. package/skills/use-task-gateway/references/task-api.md +121 -0
  478. package/skills/use-task-gateway/references/workers.md +85 -0
  479. package/skills/use-task-gateway/references/workflow-actions.md +66 -0
  480. package/skills/use-workflow-service/SKILL.md +57 -0
  481. package/skills/use-workflow-service/agents/openai.yaml +3 -0
  482. package/skills/use-workflow-service/references/action-provider.md +84 -0
  483. package/skills/use-workflow-service/references/authentication.md +76 -0
  484. package/skills/use-workflow-service/references/authoring.md +62 -0
  485. package/skills/use-workflow-service/references/mcp.md +47 -0
  486. package/skills/use-workflow-service/references/open-api.md +88 -0
  487. package/skills/use-workflow-service/references/orchestration-choice.md +63 -0
  488. package/skills/working-with-mbx/SKILL.md +1 -0
  489. package/skills/working-with-mise/SKILL.md +1 -0
  490. package/skills/xgent-app-release/SKILL.md +114 -16
  491. package/skills/xgent-app-release/references/build-and-package.md +2 -1
  492. package/skills/xgent-app-release/references/publish-api.md +6 -1
  493. package/skills/xgent-app-release/references/troubleshooting.md +2 -1
  494. package/skills/xgent-app-release/references/verify-preflight.mjs +21 -1
  495. package/skills/xgent-app-release/scripts/preflight.mjs +42 -3
  496. package/skills/xgent-image-push/SKILL.md +1 -0
  497. package/skills/xgent-init/SKILL.md +1 -0
  498. package/docs/claude-context-goal-guard.md +0 -124
  499. package/docs/codex-context-goal-guard.md +0 -109
  500. package/hooks/claude/context-goal-guard.js +0 -139
  501. package/hooks/claude/settings.example.json +0 -26
  502. package/hooks/codex/context-goal-guard.py +0 -189
  503. package/hooks/codex/hooks.example.json +0 -26
  504. package/skills/archify/SKILL.md +0 -137
  505. package/skills/archify/assets/template.html +0 -14937
  506. package/skills/archify/bin/archify.mjs +0 -2139
  507. package/skills/archify/bin/open-artifact.mjs +0 -86
  508. package/skills/archify/bin/preview.mjs +0 -653
  509. package/skills/archify/bin/visual-check.mjs +0 -829
  510. package/skills/archify/brand-marks/README.md +0 -31
  511. package/skills/archify/brand-marks/catalog.json +0 -131
  512. package/skills/archify/delta/architecture-delta.mjs +0 -1232
  513. package/skills/archify/examples/agent-run.lifecycle.json +0 -60
  514. package/skills/archify/examples/brand-aware-delivery.architecture.json +0 -47
  515. package/skills/archify/examples/cache-miss-request.sequence.json +0 -82
  516. package/skills/archify/examples/checkout-platform.base.architecture.json +0 -31
  517. package/skills/archify/examples/checkout-platform.head.architecture.json +0 -31
  518. package/skills/archify/examples/dataflow-product-analytics.html +0 -15048
  519. package/skills/archify/examples/event-stream.dataflow.json +0 -57
  520. package/skills/archify/examples/incident-response.workflow.json +0 -64
  521. package/skills/archify/examples/lifecycle-agent-run.html +0 -14983
  522. package/skills/archify/examples/production-deployment.architecture.json +0 -71
  523. package/skills/archify/examples/release-delivery.workflow.json +0 -62
  524. package/skills/archify/examples/sequence-cache-miss-request.html +0 -15063
  525. package/skills/archify/examples/web-app-rendered.html +0 -15012
  526. package/skills/archify/examples/workflow-agent-tool-call-rendered.html +0 -15054
  527. package/skills/archify/migrations/workflow-v2.mjs +0 -279
  528. package/skills/archify/package-lock.json +0 -149
  529. package/skills/archify/package.json +0 -39
  530. package/skills/archify/recipes/scenarios.mjs +0 -391
  531. package/skills/archify/references/authoring-contract.md +0 -247
  532. package/skills/archify/references/brand-marks.md +0 -65
  533. package/skills/archify/references/delivery-contract.md +0 -138
  534. package/skills/archify/references/viewer-runtime.md +0 -45
  535. package/skills/archify/renderers/architecture/grid.mjs +0 -62
  536. package/skills/archify/renderers/architecture/render-architecture.mjs +0 -1078
  537. package/skills/archify/renderers/dataflow/README.md +0 -104
  538. package/skills/archify/renderers/dataflow/render-dataflow.mjs +0 -483
  539. package/skills/archify/renderers/lifecycle/README.md +0 -115
  540. package/skills/archify/renderers/lifecycle/render-lifecycle.mjs +0 -561
  541. package/skills/archify/renderers/sequence/README.md +0 -114
  542. package/skills/archify/renderers/sequence/render-sequence.mjs +0 -464
  543. package/skills/archify/renderers/shared/brand-marks.mjs +0 -563
  544. package/skills/archify/renderers/shared/cli.mjs +0 -218
  545. package/skills/archify/renderers/shared/desktop-readability.mjs +0 -26
  546. package/skills/archify/renderers/shared/diagnostics.mjs +0 -160
  547. package/skills/archify/renderers/shared/engineering-profiles.mjs +0 -157
  548. package/skills/archify/renderers/shared/generated-brand-marks.mjs +0 -2003
  549. package/skills/archify/renderers/shared/generated-validators.mjs +0 -13
  550. package/skills/archify/renderers/shared/geometry.mjs +0 -1423
  551. package/skills/archify/renderers/shared/i18n.mjs +0 -595
  552. package/skills/archify/renderers/shared/layout-report.mjs +0 -40
  553. package/skills/archify/renderers/shared/legend.mjs +0 -217
  554. package/skills/archify/renderers/shared/output-path.mjs +0 -340
  555. package/skills/archify/renderers/shared/repository-evidence.mjs +0 -239
  556. package/skills/archify/renderers/shared/repository-location.mjs +0 -58
  557. package/skills/archify/renderers/shared/text-fit.mjs +0 -49
  558. package/skills/archify/renderers/shared/utils.mjs +0 -232
  559. package/skills/archify/renderers/shared/validator.mjs +0 -86
  560. package/skills/archify/renderers/workflow/README.md +0 -223
  561. package/skills/archify/renderers/workflow/render-workflow.mjs +0 -35
  562. package/skills/archify/renderers/workflow/workflow-compiler.mjs +0 -4400
  563. package/skills/archify/renderers/workflow/workflow-migration-geometry.mjs +0 -144
  564. package/skills/archify/schemas/README.md +0 -211
  565. package/skills/archify/schemas/architecture.schema.json +0 -178
  566. package/skills/archify/schemas/common.schema.json +0 -115
  567. package/skills/archify/scripts/check-render-output.mjs +0 -916
  568. package/skills/archify/scripts/check-update.mjs +0 -1667
  569. package/skills/archify/scripts/generate-brand-marks.mjs +0 -141
  570. package/skills/archify/scripts/generate-validators.mjs +0 -66
  571. package/skills/archify/scripts/render-examples.mjs +0 -26
  572. package/skills/archify/scripts/update-contract.mjs +0 -182
  573. package/skills/archify/skill-release.json +0 -10
  574. package/skills/archify/test/adaptive-reader-layout.test.mjs +0 -86
  575. package/skills/archify/test/animation.test.mjs +0 -179
  576. package/skills/archify/test/architecture-compare-recovery.test.mjs +0 -157
  577. package/skills/archify/test/architecture-delta-markers.test.mjs +0 -137
  578. package/skills/archify/test/architecture-delta.test.mjs +0 -705
  579. package/skills/archify/test/artifact-receipt-flush.test.mjs +0 -126
  580. package/skills/archify/test/authored-reachability.test.mjs +0 -95
  581. package/skills/archify/test/authoring-safety-contract.test.mjs +0 -54
  582. package/skills/archify/test/automatic-port-spread.test.mjs +0 -376
  583. package/skills/archify/test/base-input-compatibility.test.mjs +0 -42
  584. package/skills/archify/test/brand-marks.test.mjs +0 -678
  585. package/skills/archify/test/chapter-delta-preview.test.mjs +0 -157
  586. package/skills/archify/test/chapter-handoff.test.mjs +0 -97
  587. package/skills/archify/test/chapter-rail.test.mjs +0 -86
  588. package/skills/archify/test/checkout-line-endings.test.mjs +0 -72
  589. package/skills/archify/test/ci-scope.test.mjs +0 -59
  590. package/skills/archify/test/clean-skill-staging.test.mjs +0 -440
  591. package/skills/archify/test/cli-output-types.test.mjs +0 -201
  592. package/skills/archify/test/cli.test.mjs +0 -986
  593. package/skills/archify/test/community-proof-intake.test.mjs +0 -125
  594. package/skills/archify/test/cursor-onboarding.test.mjs +0 -74
  595. package/skills/archify/test/degraded.test.mjs +0 -161
  596. package/skills/archify/test/delivery-contract.test.mjs +0 -52
  597. package/skills/archify/test/desktop-reader-browser.test.mjs +0 -80
  598. package/skills/archify/test/diagram-guide.test.mjs +0 -92
  599. package/skills/archify/test/engineering-profile.test.mjs +0 -209
  600. package/skills/archify/test/export-browser.test.mjs +0 -305
  601. package/skills/archify/test/export-cleanup-browser.test.mjs +0 -294
  602. package/skills/archify/test/finder-browser.test.mjs +0 -274
  603. package/skills/archify/test/finder.test.mjs +0 -104
  604. package/skills/archify/test/fixtures/automatic-routing-node-border-clearance.workflow.json +0 -40
  605. package/skills/archify/test/fixtures/fail-migration-cleanup.mjs +0 -17
  606. package/skills/archify/test/fixtures/issue-126/custom-widths.workflow.json +0 -18
  607. package/skills/archify/test/fixtures/issue-126/explicit-route.workflow.json +0 -28
  608. package/skills/archify/test/fixtures/issue-126/explicit-viewbox.workflow.json +0 -19
  609. package/skills/archify/test/fixtures/issue-126/labels.workflow.json +0 -18
  610. package/skills/archify/test/fixtures/v1-baseline/agent-run.lifecycle.json +0 -64
  611. package/skills/archify/test/fixtures/v1-baseline/agent-tool-call.workflow.json +0 -88
  612. package/skills/archify/test/fixtures/v1-baseline/cache-miss-request.sequence.json +0 -75
  613. package/skills/archify/test/fixtures/v1-baseline/event-stream.dataflow.json +0 -57
  614. package/skills/archify/test/fixtures/v1-baseline/product-analytics.dataflow.json +0 -70
  615. package/skills/archify/test/fixtures/v1-baseline/production-deployment.architecture.json +0 -71
  616. package/skills/archify/test/fixtures/v1-workflow-700x400.workflow.json +0 -22
  617. package/skills/archify/test/fixtures/v1-workflow-explicit-coordinates.workflow.json +0 -47
  618. package/skills/archify/test/focus-browser.test.mjs +0 -226
  619. package/skills/archify/test/gallery.test.mjs +0 -130
  620. package/skills/archify/test/generate-validators.test.mjs +0 -59
  621. package/skills/archify/test/generate-viewer.test.mjs +0 -165
  622. package/skills/archify/test/generated-artifact-xml.test.mjs +0 -88
  623. package/skills/archify/test/geometry.test.mjs +0 -739
  624. package/skills/archify/test/golden.mjs +0 -207
  625. package/skills/archify/test/grid.test.mjs +0 -47
  626. package/skills/archify/test/guide-page.test.mjs +0 -85
  627. package/skills/archify/test/guide.test.mjs +0 -81
  628. package/skills/archify/test/guided-views-browser.test.mjs +0 -460
  629. package/skills/archify/test/guided-views.test.mjs +0 -144
  630. package/skills/archify/test/helpers/desktop-browser.mjs +0 -48
  631. package/skills/archify/test/helpers/offline-fonts.mjs +0 -76
  632. package/skills/archify/test/helpers/viewer-click.mjs +0 -72
  633. package/skills/archify/test/helpers/xml.mjs +0 -37
  634. package/skills/archify/test/i18n.test.mjs +0 -422
  635. package/skills/archify/test/intent-trace-browser.test.mjs +0 -284
  636. package/skills/archify/test/intent-trace.test.mjs +0 -111
  637. package/skills/archify/test/landing.test.mjs +0 -97
  638. package/skills/archify/test/layout-rules.test.mjs +0 -1498
  639. package/skills/archify/test/legend-contract.test.mjs +0 -404
  640. package/skills/archify/test/motion-governor-browser.test.mjs +0 -342
  641. package/skills/archify/test/motion-governor.test.mjs +0 -111
  642. package/skills/archify/test/offline-font-browser.test.mjs +0 -210
  643. package/skills/archify/test/offline-self-containment.test.mjs +0 -80
  644. package/skills/archify/test/open-artifact.test.mjs +0 -118
  645. package/skills/archify/test/ordinary-model-floor.test.mjs +0 -1052
  646. package/skills/archify/test/output-path.test.mjs +0 -587
  647. package/skills/archify/test/presentation.test.mjs +0 -71
  648. package/skills/archify/test/preset-tryon.test.mjs +0 -113
  649. package/skills/archify/test/preview-contract.test.mjs +0 -40
  650. package/skills/archify/test/preview.test.mjs +0 -530
  651. package/skills/archify/test/proof-aperture.test.mjs +0 -78
  652. package/skills/archify/test/reach-share-card.test.mjs +0 -149
  653. package/skills/archify/test/reader-layout-browser.test.mjs +0 -320
  654. package/skills/archify/test/readme-showcase.test.mjs +0 -319
  655. package/skills/archify/test/real-repository-proof.test.mjs +0 -209
  656. package/skills/archify/test/relationship-direct-explorer.test.mjs +0 -115
  657. package/skills/archify/test/relationship-lens.test.mjs +0 -128
  658. package/skills/archify/test/relationship-permalink.test.mjs +0 -130
  659. package/skills/archify/test/relationship-pulse.test.mjs +0 -122
  660. package/skills/archify/test/release-identity.test.mjs +0 -476
  661. package/skills/archify/test/release-package-gates.test.mjs +0 -750
  662. package/skills/archify/test/render-output-checks.test.mjs +0 -588
  663. package/skills/archify/test/renderer-diagnostic-boundary.test.mjs +0 -107
  664. package/skills/archify/test/repair-receipt.test.mjs +0 -181
  665. package/skills/archify/test/repository-evidence-replacement.test.mjs +0 -136
  666. package/skills/archify/test/repository-evidence.test.mjs +0 -605
  667. package/skills/archify/test/repository-language-metadata.test.mjs +0 -67
  668. package/skills/archify/test/route-journey.test.mjs +0 -125
  669. package/skills/archify/test/route-probe-browser.test.mjs +0 -363
  670. package/skills/archify/test/route-probe.test.mjs +0 -114
  671. package/skills/archify/test/route-share-card.test.mjs +0 -163
  672. package/skills/archify/test/semantic-camera.test.mjs +0 -88
  673. package/skills/archify/test/semantic-flow.test.mjs +0 -90
  674. package/skills/archify/test/semantic-legend-gateway.test.mjs +0 -156
  675. package/skills/archify/test/semantic-lens-browser.test.mjs +0 -372
  676. package/skills/archify/test/semantic-lens.test.mjs +0 -103
  677. package/skills/archify/test/semantic-passport.test.mjs +0 -99
  678. package/skills/archify/test/semantic-radar.test.mjs +0 -735
  679. package/skills/archify/test/semantic-zoom.test.mjs +0 -86
  680. package/skills/archify/test/sequence-column-fit.test.mjs +0 -137
  681. package/skills/archify/test/settled-flow.test.mjs +0 -97
  682. package/skills/archify/test/share-card-export.test.mjs +0 -132
  683. package/skills/archify/test/site-language-continuity.test.mjs +0 -569
  684. package/skills/archify/test/site-language-integration.mjs +0 -9
  685. package/skills/archify/test/skill-metadata.test.mjs +0 -84
  686. package/skills/archify/test/stable-update-manifest.test.mjs +0 -167
  687. package/skills/archify/test/start-page.test.mjs +0 -312
  688. package/skills/archify/test/story-beat-navigator.test.mjs +0 -103
  689. package/skills/archify/test/story-carrier.test.mjs +0 -90
  690. package/skills/archify/test/story-director-strip.test.mjs +0 -91
  691. package/skills/archify/test/story-follow-camera.test.mjs +0 -103
  692. package/skills/archify/test/story-horizon.test.mjs +0 -91
  693. package/skills/archify/test/story-moment-link.test.mjs +0 -93
  694. package/skills/archify/test/story-shelf.test.mjs +0 -84
  695. package/skills/archify/test/story-trail.test.mjs +0 -81
  696. package/skills/archify/test/toolbar-polish.test.mjs +0 -57
  697. package/skills/archify/test/update-contract.test.mjs +0 -133
  698. package/skills/archify/test/update-notifier.test.mjs +0 -3317
  699. package/skills/archify/test/v1-compatibility.test.mjs +0 -329
  700. package/skills/archify/test/vertical-edge.test.mjs +0 -68
  701. package/skills/archify/test/viewer-camera-browser.test.mjs +0 -395
  702. package/skills/archify/test/viewer-chrome-layout.test.mjs +0 -1104
  703. package/skills/archify/test/viewer-identifiers-browser.test.mjs +0 -135
  704. package/skills/archify/test/visual-check.test.mjs +0 -400
  705. package/skills/archify/test/webm-artifact.smoke.mjs +0 -1855
  706. package/skills/archify/test/workflow-compiler-hard-contract.test.mjs +0 -2136
  707. package/skills/archify/test/workflow-compiler.test.mjs +0 -1163
  708. package/skills/archify/test/workflow-migration.test.mjs +0 -620
  709. package/skills/archify/test/workflow-semantic-contract.test.mjs +0 -131
  710. /package/{skills/archify/THIRD_PARTY_NOTICES.md → dist/phoenix-diagram/THIRD-PARTY-LICENSES/0b7fb59365dc21c93b0f62526d74ee913aeec9ae532c112bc76afa7edcd56e14.txt} +0 -0
  711. /package/{skills/archify/LICENSE → dist/phoenix-diagram/THIRD-PARTY-LICENSES/b799ab081703e7821ae5096d2c1abdf14bbdc75e8ea1c4045998c36ed6db9706.txt} +0 -0
  712. /package/{skills/archify/assets/JetBrainsMono-OFL.txt → dist/phoenix-diagram/THIRD-PARTY-LICENSES/c1ab7c666206842a02b35b30770dac0d7a10156ed401c9defc3f02a754d89e90.txt} +0 -0
  713. /package/{skills/archify/examples/agent-tool-call.workflow.json → dist/phoenix-diagram/bundle/examples/legacy.agent-tool-call.workflow.json} +0 -0
  714. /package/{skills/archify/examples/async-job-roundtrip.sequence.json → dist/phoenix-diagram/bundle/examples/legacy.async-job-roundtrip.sequence.json} +0 -0
  715. /package/{skills/archify/examples/deployment-release.lifecycle.json → dist/phoenix-diagram/bundle/examples/legacy.deployment-release.lifecycle.json} +0 -0
  716. /package/{skills/archify/examples/product-analytics.dataflow.json → dist/phoenix-diagram/bundle/examples/legacy.product-analytics.dataflow.json} +0 -0
  717. /package/{skills/archify/examples/web-app.architecture.json → dist/phoenix-diagram/bundle/examples/legacy.web-app.architecture.json} +0 -0
@@ -0,0 +1,2303 @@
1
+ """SSH/Docker execution and its standalone bounded command supervisor."""
2
+
3
+ import argparse
4
+ import base64
5
+ import hashlib
6
+ import io
7
+ import json
8
+ import os
9
+ from pathlib import Path
10
+ import re
11
+ import signal
12
+ import shlex
13
+ import stat
14
+ import subprocess
15
+ import sys
16
+ import tempfile
17
+ import tarfile
18
+ import time
19
+ import uuid
20
+ import urllib.request
21
+
22
+
23
+ TASK_PATH = "/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
24
+
25
+
26
+ class RemoteError(RuntimeError):
27
+ pass
28
+
29
+
30
+ class UnresolvedError(RemoteError):
31
+ pass
32
+
33
+
34
+ def encoded(value):
35
+ return json.dumps(
36
+ value,
37
+ ensure_ascii=False,
38
+ sort_keys=True,
39
+ separators=(",", ":"),
40
+ allow_nan=False,
41
+ ).encode("utf-8")
42
+
43
+
44
+ def digest(content):
45
+ return hashlib.sha256(content).hexdigest()
46
+
47
+
48
+ def read_json(path):
49
+ return json.loads(Path(path).read_text(encoding="utf-8"))
50
+
51
+
52
+ def save_bytes(path, content):
53
+ path = Path(path)
54
+ path.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
55
+ descriptor, temporary = tempfile.mkstemp(prefix=".receipt-", dir=path.parent)
56
+ try:
57
+ with os.fdopen(descriptor, "wb") as stream:
58
+ stream.write(content)
59
+ stream.flush()
60
+ os.fsync(stream.fileno())
61
+ os.replace(temporary, path)
62
+ finally:
63
+ if os.path.exists(temporary):
64
+ os.unlink(temporary)
65
+
66
+
67
+ def save_json(path, value):
68
+ save_bytes(path, encoded(value) + b"\n")
69
+
70
+
71
+ def ssh_request(runtime, source, operation, execution, payload):
72
+ runner_hash = digest(source)
73
+ if runner_hash != execution["runner_hash"]:
74
+ raise UnresolvedError("runner source differs from the frozen execution")
75
+ script = runtime["remote_root"] + "/tools/" + runner_hash + "/remote.py"
76
+ bootstrap = (
77
+ "import hashlib,pathlib,sys; p=pathlib.Path(sys.argv[1]); b=sys.stdin.buffer.read(); "
78
+ "assert hashlib.sha256(b).hexdigest()==sys.argv[2]; "
79
+ "p.parent.mkdir(parents=True,exist_ok=True,mode=0o700); "
80
+ "assert not p.is_symlink(); "
81
+ "assert not p.exists() or p.read_bytes()==b; "
82
+ "p.write_bytes(b) if not p.exists() else None"
83
+ )
84
+ ssh = [
85
+ "ssh",
86
+ "-o",
87
+ "BatchMode=yes",
88
+ "-o",
89
+ "ForwardAgent=no",
90
+ "-o",
91
+ "ClearAllForwardings=yes",
92
+ "-o",
93
+ "ConnectTimeout=10",
94
+ "-o",
95
+ "ConnectionAttempts=1",
96
+ "--",
97
+ runtime["ssh_target"],
98
+ ]
99
+ try:
100
+ deployed = subprocess.run(
101
+ [*ssh, shlex.join(["python3", "-c", bootstrap, script, runner_hash])],
102
+ input=source,
103
+ capture_output=True,
104
+ timeout=30,
105
+ )
106
+ if deployed.returncode:
107
+ raise RemoteError("remote runner could not be staged")
108
+ request = {
109
+ "runtime": runtime,
110
+ "operation": operation,
111
+ "execution": execution,
112
+ "payload": payload,
113
+ }
114
+ timeout = 300
115
+ if operation in {"create", "setup_exec"}:
116
+ timeout = max(1, min(1000, execution["command_deadline"] - time.time()))
117
+ response = subprocess.run(
118
+ [*ssh, shlex.join(["python3", script, "--dispatch"])],
119
+ input=encoded(request),
120
+ capture_output=True,
121
+ timeout=timeout,
122
+ )
123
+ result = json.loads(response.stdout)
124
+ if not isinstance(result, dict):
125
+ raise UnresolvedError("remote response has no execution object")
126
+ if "error" in result:
127
+ error = UnresolvedError if result.get("unresolved") else RemoteError
128
+ raise error(result["error"])
129
+ if response.returncode:
130
+ raise UnresolvedError("remote request did not return a confirmed result")
131
+ return result
132
+ except (OSError, subprocess.TimeoutExpired, json.JSONDecodeError) as error:
133
+ raise UnresolvedError("SSH response could not be confirmed") from error
134
+
135
+
136
+ class RemoteClient:
137
+ def __init__(self, runtime, runner_source=None):
138
+ self.runtime = runtime
139
+ self.runner_source = (
140
+ Path(__file__).read_bytes() if runner_source is None else runner_source
141
+ )
142
+ self.runner_hash = digest(self.runner_source)
143
+
144
+ def _rpc(self, operation, execution, payload=None):
145
+ return ssh_request(
146
+ self.runtime, self.runner_source, operation, execution, payload
147
+ )
148
+
149
+ def submit(self, execution, payload, save):
150
+ if execution["submission_status"] != "not_submitted":
151
+ return self.query(execution, save)
152
+ execution["submission_status"] = "intent_saved"
153
+ save(execution)
154
+ try:
155
+ resource = self._rpc("create", execution, payload)
156
+ execution.update(
157
+ sandbox_id=resource["sandbox_id"],
158
+ engine_id=resource["engine_id"],
159
+ submission_status="resource_created",
160
+ )
161
+ save(execution)
162
+ if payload.get("needs_codex"):
163
+ self.prepare_codex(execution, payload)
164
+ if payload.get("needs_typesafe"):
165
+ self.prepare_typesafe(execution, payload)
166
+ if time.time() >= execution["command_deadline"]:
167
+ raise UnresolvedError(
168
+ "command deadline reached during setup; original command was not launched"
169
+ )
170
+ execution["submission_status"] = "launch_intent_saved"
171
+ save(execution)
172
+ self._rpc("launch", execution)
173
+ execution["submission_status"] = "runner_submitted"
174
+ save(execution)
175
+ return self.query(execution, save)
176
+ except (RemoteError, KeyError) as error:
177
+ execution["submission_status"] = "unresolved"
178
+ save(execution)
179
+ raise UnresolvedError(
180
+ "submission result is unresolved; query the registered execution"
181
+ ) from error
182
+
183
+ def query(self, execution, save):
184
+ from protocol import ProtocolError, validate_execution
185
+
186
+ try:
187
+ for attempt in range(3):
188
+ try:
189
+ result = self._rpc("query", execution)
190
+ break
191
+ except UnresolvedError as error:
192
+ if (
193
+ str(error) != "original command receipt is unavailable"
194
+ or attempt == 2
195
+ or time.time() >= execution["resource_deadline"]
196
+ ):
197
+ raise
198
+ time.sleep(0.25)
199
+ receipt = result["receipt"]
200
+ validate_execution(receipt)
201
+ immutable = [
202
+ "schema_version",
203
+ "remote_task_id",
204
+ "role",
205
+ "idempotency_key",
206
+ "input_hash",
207
+ "command_hash",
208
+ "runner_hash",
209
+ "runner_version",
210
+ "ssh_target",
211
+ "remote_root",
212
+ "sandbox_name",
213
+ "receipt_path",
214
+ "command_deadline",
215
+ "resource_deadline",
216
+ ]
217
+ if any(receipt[key] != execution[key] for key in immutable):
218
+ raise UnresolvedError("remote execution identity has drifted")
219
+ for key in ["sandbox_id", "engine_id"]:
220
+ if execution[key] is not None and receipt[key] != execution[key]:
221
+ raise UnresolvedError("remote resource identity has drifted")
222
+ for key in [
223
+ "sandbox_id",
224
+ "engine_id",
225
+ "phase",
226
+ "process",
227
+ "exit_code",
228
+ "termination_reason",
229
+ "artifact_manifest",
230
+ ]:
231
+ execution[key] = receipt[key]
232
+ save(execution)
233
+ phase = receipt["phase"]
234
+ if (
235
+ phase in {"starting", "running", "capturing"}
236
+ and not result["supervisor_alive"]
237
+ ):
238
+ if result["command_alive"]:
239
+ raise UnresolvedError(
240
+ "original supervisor is unavailable while the command is still running"
241
+ )
242
+ recovered = self._rpc("capture_only", execution)
243
+ if recovered.get("receipt", {}).get("phase") != "captured":
244
+ raise UnresolvedError(
245
+ "capture-only could not preserve the stopped execution"
246
+ )
247
+ return self.query(execution, save)
248
+ if phase == "prepared" and execution["submission_status"] in {
249
+ "launch_intent_saved",
250
+ "runner_submitted",
251
+ "unresolved",
252
+ }:
253
+ raise UnresolvedError("launch window is unresolved")
254
+ if phase == "captured" and receipt["exit_code"] is None:
255
+ raise UnresolvedError("original exit receipt is missing")
256
+ if phase in {"running", "capturing", "captured"}:
257
+ execution["submission_status"] = "runner_submitted"
258
+ save(execution)
259
+ return result
260
+ except (RemoteError, ProtocolError, KeyError) as error:
261
+ execution["submission_status"] = "unresolved"
262
+ save(execution)
263
+ if isinstance(error, UnresolvedError):
264
+ raise
265
+ raise UnresolvedError(
266
+ "registered remote execution could not be queried"
267
+ ) from error
268
+
269
+ def cancel(self, execution, reason, save):
270
+ execution["cancel_reason"] = reason
271
+ save(execution)
272
+ return self._rpc("cancel", execution, {"reason": reason})
273
+
274
+ def export(self, execution, destination, save):
275
+ from protocol import validate_execution
276
+
277
+ validate_execution(execution)
278
+ if execution["phase"] != "captured":
279
+ raise UnresolvedError("execution has no complete capture receipt")
280
+ destination = Path(destination)
281
+ if destination.is_symlink():
282
+ raise UnresolvedError("artifact destination cannot be a symlink")
283
+ destination = destination.resolve()
284
+ destination.mkdir(mode=0o700, parents=True, exist_ok=True)
285
+ execution["export_status"] = "partial"
286
+ save(execution)
287
+ for row in execution["artifact_manifest"]:
288
+ path = destination / row["path"]
289
+ if any(parent.is_symlink() for parent in [path, *path.parents]):
290
+ raise UnresolvedError("artifact path contains a symlink")
291
+ if path.exists():
292
+ content = path.read_bytes()
293
+ else:
294
+ result = self._rpc("read_artifact", execution, {"path": row["path"]})
295
+ try:
296
+ content = base64.b64decode(result["data"], validate=True)
297
+ except (ValueError, KeyError) as error:
298
+ raise UnresolvedError("artifact download is incomplete") from error
299
+ if len(content) != row["size"] or digest(content) != row["sha256"]:
300
+ raise UnresolvedError(
301
+ "artifact bytes do not match the captured manifest"
302
+ )
303
+ if not path.exists():
304
+ save_bytes(path, content)
305
+ execution["export_status"] = "exported"
306
+ save(execution)
307
+ return destination
308
+
309
+ def cleanup(self, execution, save, force_reason=None):
310
+ if execution["export_status"] != "exported" and not force_reason:
311
+ raise UnresolvedError(
312
+ "cleanup requires exported evidence or a recorded force reason"
313
+ )
314
+ execution["cleanup_status"] = "pending"
315
+ save(execution)
316
+ result = self._rpc("cleanup", execution, {"force_reason": force_reason})
317
+ if not result.get("terminated"):
318
+ raise UnresolvedError("registered resource termination is not confirmed")
319
+ execution["cleanup_status"] = "terminated"
320
+ save(execution)
321
+ return result
322
+
323
+ def prepare_codex(self, execution, payload):
324
+ import asyncio
325
+ from pathlib import PurePosixPath
326
+ from types import SimpleNamespace
327
+ from harbor.agents.installed.codex import Codex
328
+
329
+ client = self
330
+
331
+ class DockerSetup:
332
+ default_user = None
333
+
334
+ async def exec(
335
+ self, command, user=None, env=None, cwd=None, timeout_sec=None
336
+ ):
337
+ result = client._rpc(
338
+ "setup_exec",
339
+ execution,
340
+ {
341
+ "command": command,
342
+ "user": user,
343
+ "cwd": cwd,
344
+ "env": {
345
+ "HOME": "/home/evolution",
346
+ "PATH": "/usr/local/bin:/usr/bin:/bin",
347
+ **(env or {}),
348
+ },
349
+ "timeout_sec": timeout_sec,
350
+ },
351
+ )
352
+ return SimpleNamespace(**result)
353
+
354
+ async def upload_file(self, source_path, target_path):
355
+ client._rpc(
356
+ "setup_files",
357
+ execution,
358
+ {target_path: encoded_file(Path(source_path).read_bytes(), 0o600)},
359
+ )
360
+
361
+ class IsolatedCodex(Codex):
362
+ _REMOTE_CODEX_HOME = PurePosixPath("/home/evolution/.codex")
363
+
364
+ async def install(self, environment):
365
+ cached = client._rpc("restore_codex", execution)
366
+ if not cached["restored"]:
367
+ available = await environment.exec(
368
+ command="command -v node && command -v npm", user="root"
369
+ )
370
+ architecture = (
371
+ "arm64"
372
+ if client.runtime["codex_architecture"] == "aarch64"
373
+ else "x64"
374
+ )
375
+ command = (
376
+ "npm install --global --force --prefix /opt/evolution-codex --registry https://registry.npmjs.org @openai/codex@"
377
+ + self._version
378
+ + "-linux-"
379
+ + architecture
380
+ )
381
+ if available.return_code != 0:
382
+ command = shlex.join(
383
+ [
384
+ "python3",
385
+ "-c",
386
+ "import sys; sys.path.insert(0,'/evolution-control'); "
387
+ "from remote import install_codex_archive; "
388
+ "install_codex_archive(sys.argv[1],sys.argv[2],sys.argv[3])",
389
+ "/opt/evolution-codex/lib/node_modules/@openai/codex",
390
+ self._version,
391
+ architecture,
392
+ ]
393
+ )
394
+ installed = await environment.exec(
395
+ command=command,
396
+ user="root",
397
+ timeout_sec=min(
398
+ 900,
399
+ max(1, int(execution["command_deadline"] - time.time())),
400
+ ),
401
+ )
402
+ if installed.return_code != 0:
403
+ raise RemoteError("fixed Codex package installation failed")
404
+ link = (
405
+ "import os,pathlib; root=pathlib.Path('/opt/evolution-codex/lib/node_modules/@openai/codex'); "
406
+ "names={'codex','codex-code-mode-host','codex-exec-server','rg','bwrap'}; "
407
+ "bins=[p for p in root.rglob('*') if p.is_file() and p.name in names and os.access(p,os.X_OK)]; "
408
+ "[(pathlib.Path('/usr/local/bin',p.name).unlink(missing_ok=True),pathlib.Path('/usr/local/bin',p.name).symlink_to(p)) for p in bins]"
409
+ )
410
+ await self.exec_as_root(
411
+ environment, command=shlex.join(["python3", "-c", link])
412
+ )
413
+ if not cached["restored"]:
414
+ client._rpc("cache_codex", execution)
415
+
416
+ async def install():
417
+ with tempfile.TemporaryDirectory(prefix="evolution-setup-") as logs:
418
+ agent = IsolatedCodex(
419
+ logs_dir=Path(logs),
420
+ model_name=self.runtime.get("model"),
421
+ version=self.runtime["codex_version"],
422
+ config=payload["codex_config"],
423
+ )
424
+ environment = DockerSetup()
425
+ await agent.install(environment)
426
+ await agent._upload_effective_config(
427
+ environment,
428
+ agent._build_effective_config(),
429
+ "/home/evolution/.codex/config.toml",
430
+ )
431
+
432
+ asyncio.run(install())
433
+ import toml
434
+
435
+ receipt = self._rpc("finalize_setup", execution)
436
+ if receipt["config_sha256"] != digest(
437
+ toml.dumps(payload["codex_config"]).encode()
438
+ ):
439
+ raise RemoteError(
440
+ "native Codex configuration bytes differ from the declared configuration"
441
+ )
442
+
443
+ def prepare_typesafe(self, execution, payload):
444
+ key = os.environ.get("TYPESAFE_API_KEY")
445
+ if not key:
446
+ raise RemoteError("TypeSafe controller credential is unavailable")
447
+ result = self._rpc("prepare_typesafe", execution, {"key": key})
448
+ if result != {"prepared": True}:
449
+ raise UnresolvedError("TypeSafe credential preparation is unresolved")
450
+
451
+ def destroy_typesafe(self, execution):
452
+ result = self._rpc("destroy_typesafe", execution)
453
+ if result != {"destroyed": True}:
454
+ raise UnresolvedError("TypeSafe credential destruction is unresolved")
455
+
456
+
457
+ def isolation_script(case, *, schema_version=1):
458
+ settings = {"repo": case["repo_path"], "base_commit": case["base_commit"]}
459
+ return (
460
+ "settings="
461
+ + repr(settings)
462
+ + "\n"
463
+ + """
464
+ import json, os, pathlib, socket, subprocess
465
+ checks = {'unprivileged_user': os.getuid() == 10000}
466
+ """
467
+ + ("""import shutil
468
+ npm = shutil.which('npm')
469
+ checks['installed_npm_ready'] = True
470
+ if npm:
471
+ try:
472
+ started = subprocess.run([npm, '--version'], text=True, capture_output=True, timeout=30)
473
+ checks['installed_npm_ready'] = started.returncode == 0 and bool(started.stdout.strip())
474
+ except (OSError, subprocess.TimeoutExpired):
475
+ checks['installed_npm_ready'] = False
476
+ """ if schema_version == 2 else "")
477
+ + """for name, path in [('auth_hidden', '/home/evolution/.codex/auth.json'), ('control_hidden', '/evolution-control/receipt.json')]:
478
+ try:
479
+ pathlib.Path(path).read_bytes()
480
+ checks[name] = False
481
+ except (PermissionError, FileNotFoundError):
482
+ checks[name] = True
483
+ try:
484
+ pathlib.Path('/evolution-control/receipt.json').write_text('forbidden')
485
+ checks['control_write_denied'] = False
486
+ except (PermissionError, FileNotFoundError):
487
+ checks['control_write_denied'] = True
488
+ for name, path in [('no_grader', '/tests/test.sh'), ('no_oracle', '/solution/gold_patch.diff')]:
489
+ try:
490
+ checks[name] = not pathlib.Path(path).exists()
491
+ except PermissionError:
492
+ checks[name] = True
493
+ checks['clean_tool_environment'] = not any(any(word in key.upper() for word in ['TOKEN','SECRET','API_KEY','SSH_AUTH']) for key in os.environ)
494
+ checks['base_matches'] = subprocess.check_output(['git','-C',settings['repo'],'rev-parse','HEAD'],text=True).strip() == settings['base_commit']
495
+ ancestors = set(subprocess.check_output(['git','-C',settings['repo'],'rev-list',settings['base_commit']],text=True).splitlines())
496
+ objects = subprocess.check_output(['git','-C',settings['repo'],'cat-file','--batch-all-objects','--batch-check=%(objectname) %(objecttype)'],text=True).splitlines()
497
+ commits = {line.split()[0] for line in objects if line.endswith(' commit')}
498
+ checks['no_later_git_objects'] = commits <= ancestors
499
+ try:
500
+ connection = socket.create_connection(('github.com', 443), timeout=2)
501
+ connection.close()
502
+ checks['external_network_blocked'] = False
503
+ except OSError:
504
+ checks['external_network_blocked'] = True
505
+ try:
506
+ with socket.socket() as server:
507
+ server.bind(('127.0.0.1', 0))
508
+ server.listen(1)
509
+ connection = socket.create_connection(server.getsockname(), timeout=2)
510
+ connection.close()
511
+ checks['loopback_available'] = True
512
+ except OSError:
513
+ checks['loopback_available'] = False
514
+ marker = pathlib.Path(settings['repo']) / 'src/evolution_capture_probe.js'
515
+ marker.parent.mkdir(parents=True, exist_ok=True)
516
+ marker.write_text('// deterministic capture probe\\n')
517
+ print(json.dumps({'isolation_passed': all(checks.values()), 'checks': checks, 'environment_names': sorted(os.environ)}))
518
+ raise SystemExit(0 if all(checks.values()) else 1)
519
+ """
520
+ )
521
+
522
+
523
+ def native_skill_files(job, bundle):
524
+ from protocol import skill_name
525
+
526
+ baseline = job.bundles[job.spec["baseline_condition"]]
527
+ descriptors = [path for path in job.spec["target"]["surfaces"]["skill"]
528
+ if Path(path).name == "SKILL.md"]
529
+ descriptors.extend(root + "/SKILL.md" for root in job.spec["source"].get("fixed_skill_roots", []))
530
+ files = {}
531
+ for path in descriptors:
532
+ if path not in bundle:
533
+ continue
534
+ root = Path(path).parent.as_posix()
535
+ name = skill_name(baseline[path]["content"])
536
+ for item, row in bundle.items():
537
+ if item.startswith(root + "/"):
538
+ destination = "/home/evolution/.agents/skills/" + name + "/" + item[len(root) + 1:]
539
+ files[destination] = encoded_file(row["content"], row["mode"])
540
+ return files
541
+
542
+
543
+ def smoke_payload(job, case, purpose):
544
+ runtime = job.spec["runtime"]
545
+ repo = case["repo_path"]
546
+ views = job.case_files[case["case_id"]]
547
+ files = {}
548
+ for name, row in views["public_paths"].items():
549
+ files["/evolution-input/task/" + name] = encoded_file(
550
+ row["content"], row["mode"]
551
+ )
552
+ native = purpose == "probe"
553
+ baseline = job.bundles[job.spec["baseline_condition"]]
554
+ same_repository = (case["repo_id"], case["base_commit"]) == (
555
+ job.spec["target"]["repo_id"],
556
+ job.spec["target"]["base_commit"],
557
+ )
558
+ removed = []
559
+ if same_repository:
560
+ for name, row in baseline.items():
561
+ if native and name in job.spec["target"]["surfaces"]["skill"]:
562
+ removed.append(repo + "/" + name)
563
+ else:
564
+ files[repo + "/" + name] = encoded_file(row["content"], row["mode"])
565
+ configuration = codex_configuration(
566
+ runtime.get("model", "gpt-6.1-sol"), runtime.get("effort", "high"),
567
+ schema_version=job.spec["schema_version"],
568
+ )
569
+ if native:
570
+ files.update(native_skill_files(job, baseline))
571
+ if "model" not in runtime:
572
+ files["/home/evolution/.codex/auth.json"] = encoded_file(
573
+ encoded({"OPENAI_API_KEY": "isolation-sentinel-not-a-credential"}),
574
+ 0o600,
575
+ )
576
+ args = codex_arguments(configuration, repo,
577
+ probe=isolation_script(case, schema_version=job.spec["schema_version"]))
578
+ if "model" in runtime:
579
+ startup = codex_arguments(
580
+ configuration,
581
+ repo,
582
+ prompt="Reply exactly RUNTIME_READY. Do not inspect or change files or use tools.",
583
+ )
584
+ args = ["bash", "-c", shlex.join(args) + " && " + shlex.join(startup)]
585
+ outputs = {
586
+ "instruction-receipt.json": "/evolution-control/instruction-receipt.json"
587
+ }
588
+ else:
589
+ for name, row in views["grader_paths"].items():
590
+ files["/" + name] = encoded_file(row["content"], row["mode"])
591
+ if purpose == "oracle":
592
+ for name, row in views["oracle_paths"].items():
593
+ files["/" + name] = encoded_file(row["content"], row["mode"])
594
+ script = (
595
+ "bash /solution/solve.sh && bash /tests/test.sh"
596
+ if purpose == "oracle"
597
+ else "bash /tests/test.sh"
598
+ )
599
+ args = ["bash", "-c", script]
600
+ outputs = {
601
+ "reward.txt": "/logs/verifier/reward.txt",
602
+ "instruction-receipt.json": "/evolution-control/instruction-receipt.json",
603
+ }
604
+ return {
605
+ "image": case["image"],
606
+ "platform": case["platform"],
607
+ "repo_path": repo,
608
+ "base_commit": case["base_commit"],
609
+ "files": files,
610
+ "remove_paths": removed,
611
+ "needs_codex": native,
612
+ "codex_config": configuration if native else None,
613
+ "grading": not native,
614
+ "command": {
615
+ "args": args,
616
+ "cwd": repo,
617
+ "uid": 10000,
618
+ "gid": 10000,
619
+ "env": {
620
+ "HOME": "/home/evolution",
621
+ "CODEX_HOME": "/home/evolution/.codex",
622
+ "PATH": TASK_PATH,
623
+ "GOPATH": "/go",
624
+ "GOCACHE": "/tmp/evolution-go-cache",
625
+ "LANG": "C.UTF-8",
626
+ "USER": "evolution",
627
+ **(
628
+ {
629
+ "HTTP_PROXY": runtime["model_proxy"],
630
+ "HTTPS_PROXY": runtime["model_proxy"],
631
+ }
632
+ if native and "model_proxy" in runtime
633
+ else {}
634
+ ),
635
+ },
636
+ "capture": {
637
+ "repo": repo,
638
+ "baseline_ref_file": "/evolution-control/base-tree.txt",
639
+ "excluded_paths": job.spec["target"]["surfaces"]["agents"],
640
+ "session_dir": "/home/evolution/.codex/sessions" if native else None,
641
+ "runtime_skills": native and "model" in runtime,
642
+ "files": outputs,
643
+ "optional_files": {}
644
+ if native
645
+ else {
646
+ "grade-output.json": "/logs/verifier/output.json",
647
+ "run-script-stdout.txt": "/logs/verifier/run-script-stdout.txt",
648
+ "run-script-stderr.txt": "/logs/verifier/run-script-stderr.txt",
649
+ },
650
+ },
651
+ },
652
+ }
653
+
654
+
655
+ def trial_payload(job, case, bundle):
656
+ payload = smoke_payload(job, case, "probe")
657
+ files = payload["files"]
658
+ for name in list(files):
659
+ if name.startswith("/home/evolution/.agents/skills/"):
660
+ del files[name]
661
+ from protocol import task_contract
662
+
663
+ files.update(native_skill_files(job, bundle))
664
+ for path in job.spec["target"]["surfaces"]["agents"]:
665
+ destination = case["repo_path"] + "/" + path
666
+ files.pop(destination, None)
667
+ if path in bundle:
668
+ files[destination] = encoded_file(
669
+ bundle[path]["content"], bundle[path]["mode"]
670
+ )
671
+ else:
672
+ payload["remove_paths"].append(destination)
673
+ instruction = job.case_files[case["case_id"]]["public_paths"]["instruction.md"][
674
+ "content"
675
+ ].decode("utf-8")
676
+ if job.spec.get("evaluation", {}).get("scoring") == "continuous_100_v1":
677
+ contract = task_contract(case)
678
+ files["/evolution-input/task-contract.md"] = encoded_file(contract, 0o444)
679
+ instruction += "\n\nAdditional frozen observable task requirements:\n" + contract.decode("utf-8")
680
+ payload["command"]["args"] = codex_arguments(
681
+ payload["codex_config"], case["repo_path"], prompt=instruction
682
+ )
683
+ return payload
684
+
685
+
686
+ def grading_payload(job, case, patch):
687
+ payload = smoke_payload(job, case, "empty")
688
+ payload["files"]["/evolution-input/model.patch"] = encoded_file(patch)
689
+ payload["command"]["args"] = [
690
+ "bash",
691
+ "-c",
692
+ "git apply --binary /evolution-input/model.patch && bash /tests/test.sh"
693
+ if patch
694
+ else "bash /tests/test.sh",
695
+ ]
696
+ payload["command"]["capture"]["optional_files"]["checks.json"] = (
697
+ "/logs/verifier/checks.json"
698
+ )
699
+ if job.spec["schema_version"] == 2:
700
+ rubric = json.loads(job.evaluation_files[job.spec["evaluation"]["rubrics"][case["case_id"]]]["content"])
701
+ names = sorted({name for c in rubric["criteria"] for name in c["context_paths"] if name.startswith("repo/")})
702
+ source = """
703
+ import json, pathlib, sys
704
+ root = pathlib.Path.cwd()
705
+ result = {'files': {}, 'omissions': []}
706
+ for name in json.loads(sys.argv[1]):
707
+ path = root / name.removeprefix('repo/')
708
+ try:
709
+ if '..' in path.relative_to(root).parts or any(p.is_symlink() for p in [path, *path.parents] if p != root):
710
+ raise ValueError('unsafe path')
711
+ result['files'][name] = path.read_text(encoding='utf-8')
712
+ except (OSError, ValueError, UnicodeError):
713
+ result['omissions'].append(name)
714
+ pathlib.Path('/logs/verifier/quality-context.json').write_text(json.dumps(result))
715
+ """
716
+ collect = shlex.join(["python3", "-c", source, encoded(names).decode()])
717
+ verify = "bash /tests/test.sh"
718
+ observations = sorted({name for c in rubric["criteria"] for name in c["context_paths"]
719
+ if name.startswith("verifier/")})
720
+ if observations:
721
+ observe_source = """
722
+ import json, pathlib, sys
723
+ root = pathlib.Path('/logs/verifier/public')
724
+ result = {'files': {}, 'omissions': []}
725
+ for name in json.loads(sys.argv[1]):
726
+ path = root / name.removeprefix('verifier/')
727
+ try:
728
+ if '..' in path.relative_to(root).parts or any(p.is_symlink() for p in [path, *path.parents]):
729
+ raise ValueError('unsafe observation path')
730
+ result['files'][name] = path.read_bytes().decode('utf-8')
731
+ except (OSError, ValueError, UnicodeError):
732
+ result['omissions'].append(name)
733
+ pathlib.Path('/logs/verifier/public-context.json').write_text(json.dumps(result))
734
+ """
735
+ observe = shlex.join(["python3", "-c", observe_source, encoded(observations).decode()])
736
+ verify = '{ bash /tests/test.sh; xgent_verifier_status=$?; ' + observe + '; exit "$xgent_verifier_status"; }'
737
+ payload["command"]["capture"]["files"]["public-context.json"] = "/logs/verifier/public-context.json"
738
+ payload["command"]["args"] = ["bash", "-c",
739
+ ("git apply --binary /evolution-input/model.patch && " if patch else "") + collect + " && " + verify]
740
+ payload["command"]["capture"]["files"]["quality-context.json"] = "/logs/verifier/quality-context.json"
741
+ return payload
742
+
743
+
744
+ def regression_payload(job, case, patch, checker):
745
+ payload = grading_payload(job, case, b"")
746
+ payload["files"]["/evolution-input/model.patch"] = encoded_file(patch)
747
+ payload["files"]["/evolution-input/checker.json"] = encoded_file(encoded(checker))
748
+ script = """
749
+ import json, pathlib, subprocess
750
+ checker = json.loads(pathlib.Path('/evolution-input/checker.json').read_text())
751
+ patch = '/evolution-input/model.patch'
752
+ base_tree = subprocess.check_output(['git','write-tree'],text=True).strip()
753
+ def run(argv):
754
+ p = subprocess.run(argv, capture_output=True, text=True, errors='replace')
755
+ return {'exit_code': p.returncode, 'stdout': p.stdout, 'stderr': p.stderr}
756
+ def reset():
757
+ subprocess.run(['git','read-tree','--reset','-u',base_tree],check=True)
758
+ subprocess.run(['git','clean','-fd'],check=True,capture_output=True)
759
+ result = {'status': 'unknown', 'level': None, 'reason': 'replay_setup_failed', 'base_tree': base_tree}
760
+ selection = [arg for path in checker['test_paths'] for arg in ['--include',path]]
761
+ selected = run(['git','apply','--numstat','--allow-empty',*selection,patch])
762
+ test_patch = run(['git','apply','--binary','--allow-empty',*selection,patch])
763
+ if test_patch['exit_code'] == 0 and selected['exit_code'] == 0:
764
+ if not selected['stdout'].strip():
765
+ result.update(status='valid',level=0,reason='no_changed_regression_test')
766
+ else:
767
+ old = run(checker['argv'])
768
+ reset()
769
+ applied = run(['git','apply','--binary',patch])
770
+ if applied['exit_code'] == 0:
771
+ fixed = run(checker['argv'])
772
+ old_text = old['stdout'] + old['stderr']
773
+ environment = ['ModuleNotFoundError:', 'ImportError while importing test module', 'command not found', 'collected 0 items']
774
+ attributed = old['exit_code'] == checker['expected_failure']['exit_code'] and checker['expected_failure']['contains'] in old_text
775
+ if not any(marker in old_text + fixed['stdout'] + fixed['stderr'] for marker in environment):
776
+ result.update(status='valid',level=int(attributed and fixed['exit_code']==0),reason='counterfactual_replay')
777
+ else:
778
+ result['reason'] = 'replay_environment_failure'
779
+ result.update(original=old,fixed=fixed,defect_attributed=attributed)
780
+ pathlib.Path('/logs/verifier/regression-replay.json').write_text(json.dumps(result))
781
+ """
782
+ payload["command"]["args"] = ["python3", "-c", script]
783
+ payload["command"]["capture"]["files"] = {
784
+ "regression-replay.json": "/logs/verifier/regression-replay.json",
785
+ "instruction-receipt.json": "/evolution-control/instruction-receipt.json",
786
+ }
787
+ payload["command"]["capture"]["optional_files"] = {}
788
+ return payload
789
+
790
+
791
+ def generation_payload(job, source, instruction, outputs, *, optimizer=False):
792
+ case = job.spec["cases"][0]
793
+ payload = smoke_payload(job, case, "probe")
794
+ runtime = job.spec["optimizer"] if optimizer else job.spec["runtime"]
795
+ configuration = codex_configuration(runtime["model"], runtime["effort"],
796
+ schema_version=job.spec["schema_version"])
797
+ payload.update(
798
+ repo_path="/work",
799
+ base_commit=None,
800
+ generated_workspace=True,
801
+ codex_config=configuration,
802
+ )
803
+ payload["files"] = {"/work/source.json": encoded_file(encoded(source))}
804
+ payload["remove_paths"] = []
805
+ if optimizer:
806
+ payload["files"]["/evolution-input/method.md"] = encoded_file(
807
+ job.method_files["method.md"]["content"]
808
+ )
809
+ payload["command"].update(
810
+ args=codex_arguments(configuration, "/work", prompt=instruction), cwd="/work"
811
+ )
812
+ payload["command"]["capture"] = {
813
+ "repo": None,
814
+ "excluded_paths": [],
815
+ "session_dir": "/home/evolution/.codex/sessions",
816
+ "runtime_skills": True,
817
+ "files": {
818
+ **{name: "/work/" + name for name in outputs},
819
+ "instruction-receipt.json": "/evolution-control/instruction-receipt.json",
820
+ },
821
+ }
822
+ return payload
823
+
824
+
825
+ def typesafe_payload(job, request, *, long_context=False):
826
+ from typesafe_worker import validate_request
827
+
828
+ validate_request(request)
829
+ if type(long_context) is not bool:
830
+ raise RemoteError("invalid TypeSafe long-context setting")
831
+ payload = generation_payload(job, {}, "", [])
832
+ credential = "/home/evolution/.typesafe/api-key"
833
+ payload.update(needs_codex=False, needs_typesafe=True, codex_config=None)
834
+ payload["files"] = {
835
+ "/work/request.json": encoded_file(encoded(request)),
836
+ "/work/typesafe_worker.py": encoded_file(job.worker_files["typesafe_worker.py"]["content"]),
837
+ }
838
+ payload["command"].update(
839
+ args=["python3", "/work/typesafe_worker.py", "--request", "/work/request.json",
840
+ "--credential", credential, "--output", "/work/auxiliary-response.json",
841
+ "--timeout", str(max(1, job.spec["budget"]["per_trial_timeout_sec"] - 10))],
842
+ typesafe_credential=credential,
843
+ )
844
+ if long_context:
845
+ payload["command"]["args"].append("--long-context")
846
+ payload["command"]["capture"] = {
847
+ "repo": None, "excluded_paths": [], "session_dir": None,
848
+ "files": {"auxiliary-response.json": "/work/auxiliary-response.json",
849
+ "instruction-receipt.json": "/evolution-control/instruction-receipt.json"},
850
+ }
851
+ return payload
852
+
853
+
854
+ def prepare_typesafe_credential(runtime, execution, payload):
855
+ control = host_control(execution)
856
+ packet = read_json(control / "payload.json")
857
+ if execution["role"] != "grader" or not packet.get("needs_typesafe") or packet.get("needs_codex"):
858
+ raise RemoteError("credential preparation requires the registered API worker")
859
+ if packet["command"].get("typesafe_credential") != "/home/evolution/.typesafe/api-key":
860
+ raise RemoteError("API credential path differs")
861
+ if set(payload) != {"key"} or not isinstance(payload["key"], str) or not payload["key"] or any(
862
+ character.isspace() for character in payload["key"]
863
+ ):
864
+ raise RemoteError("API credential is unavailable")
865
+ if (control / "typesafe-credential.json").exists():
866
+ raise UnresolvedError("API credential preparation was already attempted; query the original execution")
867
+ save_json(control / "typesafe-credential.json", {"prepared": False, "destroyed": False})
868
+ # The secret uses its own stdin operation, never create_resource's persisted payload.
869
+ key_path = control / "typesafe.key"
870
+ save_bytes(key_path, payload["key"].encode())
871
+ key_path.chmod(0o600)
872
+ container_exec(runtime, execution, ["python3", "-c",
873
+ "import os,pathlib; p=pathlib.Path('/home/evolution/.typesafe'); "
874
+ "p.mkdir(mode=0o700,exist_ok=True); os.chown(p,10000,10000); os.chmod(p,0o700)"])
875
+ container_files(runtime, execution, {
876
+ "/home/evolution/.typesafe/api-key": encoded_file(key_path.read_bytes(), 0o600),
877
+ "/evolution-control/redaction.json": encoded_file(encoded([payload["key"]]), 0o600),
878
+ })
879
+ container_exec(runtime, execution, ["chown", "10000:10000", "/home/evolution/.typesafe/api-key"])
880
+ key_path.unlink()
881
+ save_json(control / "typesafe-credential.json", {"prepared": True, "destroyed": False})
882
+ return {"prepared": True}
883
+
884
+
885
+ def destroy_typesafe_credential(runtime, execution, resource):
886
+ control = host_control(execution)
887
+ receipt = control / "typesafe-credential.json"
888
+ if not receipt.exists():
889
+ return True
890
+ (control / "typesafe.key").unlink(missing_ok=True)
891
+ if resource is not None:
892
+ container_exec(runtime, execution, ["python3", "-c",
893
+ "import pathlib; pathlib.Path('/home/evolution/.typesafe/api-key').unlink(missing_ok=True); "
894
+ "pathlib.Path('/evolution-control/redaction.json').unlink(missing_ok=True)"])
895
+ save_json(receipt, {"prepared": read_json(receipt)["prepared"], "destroyed": True})
896
+ return True
897
+
898
+
899
+ def host_environment(runtime):
900
+ return {
901
+ "HOME": str(Path.home()),
902
+ "PATH": str(Path(runtime["docker_binary"]).parent)
903
+ + ":/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin",
904
+ "LANG": "C.UTF-8",
905
+ }
906
+
907
+
908
+ def docker(runtime, arguments, *, content=None, timeout=60, check=True):
909
+ result = subprocess.run(
910
+ [runtime["docker_binary"], *arguments],
911
+ input=content,
912
+ capture_output=True,
913
+ env=host_environment(runtime),
914
+ timeout=timeout,
915
+ )
916
+ if check and result.returncode:
917
+ raise RemoteError("remote Docker command failed")
918
+ return result
919
+
920
+
921
+ def engine_identity(runtime):
922
+ result = docker(
923
+ runtime,
924
+ [
925
+ "info",
926
+ "--format",
927
+ '{"id":{{json .ID}},"version":{{json .ServerVersion}},"architecture":{{json .Architecture}}}',
928
+ ],
929
+ )
930
+ value = json.loads(result.stdout)
931
+ if value["version"] != runtime["docker_version"]:
932
+ raise UnresolvedError("Docker version differs from the frozen runtime")
933
+ architecture = {
934
+ "arm64": "aarch64",
935
+ "aarch64": "aarch64",
936
+ "amd64": "x86_64",
937
+ "x86_64": "x86_64",
938
+ }.get(value["architecture"])
939
+ if architecture != runtime["codex_architecture"]:
940
+ raise UnresolvedError("Codex architecture differs from the Docker kernel")
941
+ return value["id"]
942
+
943
+
944
+ def host_control(execution):
945
+ task_id = str(uuid.UUID(execution["remote_task_id"]))
946
+ if (
947
+ task_id != execution["remote_task_id"]
948
+ or execution["sandbox_name"] != "evolve-" + task_id
949
+ ):
950
+ raise UnresolvedError("invalid registered execution identity")
951
+ root = Path(execution["remote_root"]) / "executions" / task_id / "control"
952
+ if str(root / "receipt.json") != execution["receipt_path"]:
953
+ raise UnresolvedError("registered receipt path differs")
954
+ if root.is_symlink():
955
+ raise UnresolvedError("execution control directory cannot be a symlink")
956
+ return root
957
+
958
+
959
+ def owned_resource(runtime, execution):
960
+ identity = engine_identity(runtime)
961
+ if execution["engine_id"] is not None and execution["engine_id"] != identity:
962
+ raise UnresolvedError("registered Docker engine differs")
963
+ result = docker(
964
+ runtime,
965
+ ["inspect", execution["sandbox_id"] or execution["sandbox_name"]],
966
+ check=False,
967
+ )
968
+ if result.returncode:
969
+ # Confirm an absent name with a successful engine query; arbitrary
970
+ # transport and daemon failures must not be interpreted as deletion.
971
+ names = docker(
972
+ runtime,
973
+ [
974
+ "ps",
975
+ "-a",
976
+ "--no-trunc",
977
+ "--filter",
978
+ "name=^/" + execution["sandbox_name"] + "$",
979
+ "--format",
980
+ "{{.ID}}",
981
+ ],
982
+ )
983
+ if names.stdout.strip():
984
+ raise UnresolvedError("resource inspection is unresolved")
985
+ return None
986
+ resource = json.loads(result.stdout)[0]
987
+ labels = resource["Config"].get("Labels") or {}
988
+ if (
989
+ labels.get("xgent.execution") != execution["remote_task_id"]
990
+ or labels.get("xgent.input") != execution["input_hash"]
991
+ ):
992
+ raise UnresolvedError("resource ownership labels differ")
993
+ if (
994
+ execution["sandbox_id"] is not None
995
+ and resource["Id"] != execution["sandbox_id"]
996
+ ):
997
+ raise UnresolvedError("registered container ID differs")
998
+ return resource
999
+
1000
+
1001
+ def container_exec(
1002
+ runtime, execution, args, *, user="root", cwd=None, env=None, timeout=60, check=True
1003
+ ):
1004
+ arguments = ["exec", "--user", str(user)]
1005
+ if cwd:
1006
+ arguments += ["--workdir", cwd]
1007
+ for key, value in (env or {}).items():
1008
+ arguments += ["--env", key + "=" + value]
1009
+ return docker(
1010
+ runtime,
1011
+ [*arguments, execution["sandbox_id"], *args],
1012
+ timeout=timeout,
1013
+ check=check,
1014
+ )
1015
+
1016
+
1017
+ def container_files(runtime, execution, files):
1018
+ archive = io.BytesIO()
1019
+ with tarfile.open(fileobj=archive, mode="w") as stream:
1020
+ for name, row in files.items():
1021
+ path = Path(name)
1022
+ if not path.is_absolute() or ".." in path.parts:
1023
+ raise RemoteError(
1024
+ "container file path is outside the declared namespace"
1025
+ )
1026
+ raw = base64.b64decode(row["data"], validate=True)
1027
+ info = tarfile.TarInfo(name.lstrip("/"))
1028
+ info.size = len(raw)
1029
+ info.mode = row.get("mode", 0o644)
1030
+ stream.addfile(info, io.BytesIO(raw))
1031
+ docker(
1032
+ runtime, ["cp", "-", execution["sandbox_id"] + ":/"], content=archive.getvalue()
1033
+ )
1034
+
1035
+
1036
+ def encoded_file(content, mode=0o644):
1037
+ return {"data": base64.b64encode(content).decode("ascii"), "mode": mode}
1038
+
1039
+
1040
+ def install_codex_archive(destination, version, architecture):
1041
+ label = version + "-linux-" + architecture
1042
+ url = "https://registry.npmjs.org/@openai%2Fcodex/" + label
1043
+ with urllib.request.urlopen(url, timeout=120) as response:
1044
+ metadata = json.load(response)
1045
+ tarball = "https://registry.npmjs.org/@openai/codex/-/codex-" + label + ".tgz"
1046
+ if (
1047
+ metadata.get("name") != "@openai/codex"
1048
+ or metadata.get("version") != label
1049
+ or metadata.get("os") != ["linux"]
1050
+ or metadata.get("cpu") != [architecture]
1051
+ or metadata["dist"]["tarball"] != tarball
1052
+ ):
1053
+ raise RemoteError("fixed Codex package metadata differs")
1054
+ with urllib.request.urlopen(tarball, timeout=120) as response:
1055
+ raw = response.read()
1056
+ integrity = "sha512-" + base64.b64encode(hashlib.sha512(raw).digest()).decode()
1057
+ if metadata["dist"]["integrity"] != integrity:
1058
+ raise RemoteError("fixed Codex package integrity differs")
1059
+ destination = Path(destination)
1060
+ destination.parent.mkdir(parents=True, exist_ok=True)
1061
+ if destination.exists():
1062
+ raise RemoteError("native Codex installation destination already exists")
1063
+ with tempfile.TemporaryDirectory(
1064
+ prefix=".codex-", dir=destination.parent
1065
+ ) as temporary:
1066
+ staged = Path(temporary) / "package"
1067
+ with tarfile.open(fileobj=io.BytesIO(raw), mode="r:gz") as archive:
1068
+ for member in archive:
1069
+ path = Path(member.name)
1070
+ if (
1071
+ path.is_absolute()
1072
+ or ".." in path.parts
1073
+ or not path.parts
1074
+ or path.parts[0] != "package"
1075
+ ):
1076
+ raise RemoteError(
1077
+ "native Codex archive path is outside its package"
1078
+ )
1079
+ if member.isdir():
1080
+ continue
1081
+ if not member.isfile():
1082
+ raise RemoteError("native Codex archive contains a nonregular file")
1083
+ target = staged.joinpath(*path.parts[1:])
1084
+ target.parent.mkdir(parents=True, exist_ok=True)
1085
+ target.write_bytes(archive.extractfile(member).read())
1086
+ target.chmod(member.mode & 0o777)
1087
+ staged.rename(destination)
1088
+
1089
+
1090
+ def instruction_inventory(repo, home, expected):
1091
+ repo, home = Path(repo), Path(home)
1092
+ paths = set()
1093
+ for root, directories, files in os.walk(repo, followlinks=False):
1094
+ directories[:] = [name for name in directories if name != ".git"]
1095
+ paths.update(
1096
+ Path(root) / name
1097
+ for name in files
1098
+ if name in {"AGENTS.md", "AGENTS.override.md", "SKILL.md"}
1099
+ )
1100
+ for root in [repo, *repo.parents]:
1101
+ paths.update(
1102
+ root / name
1103
+ for name in ["AGENTS.md", "AGENTS.override.md"]
1104
+ if (root / name).exists()
1105
+ )
1106
+ paths.update(
1107
+ path for path in (root / ".agents/skills").rglob("*") if path.is_file()
1108
+ )
1109
+ for root in [home / ".agents/skills", home / ".codex/skills", Path("/etc/codex")]:
1110
+ paths.update(path for path in root.rglob("*") if path.is_file())
1111
+ paths.update(
1112
+ home / ".codex" / name
1113
+ for name in ["AGENTS.md", "AGENTS.override.md", "memory.md"]
1114
+ if (home / ".codex" / name).exists()
1115
+ )
1116
+ for path in list(paths):
1117
+ if path.name == "SKILL.md":
1118
+ paths.update(item for item in path.parent.rglob("*") if item.is_file())
1119
+ targets = set()
1120
+ for name in expected:
1121
+ path = Path(name)
1122
+ if path.name == "SKILL.md" and path.is_relative_to(home):
1123
+ match = re.search(
1124
+ rb"(?m)^name:[ \t]*['\"]?([a-z0-9][a-z0-9-]*)", path.read_bytes()
1125
+ )
1126
+ if match:
1127
+ targets.add(match[1])
1128
+ sources, gaps = [], []
1129
+ for path in sorted(paths):
1130
+ if path.is_symlink() or any(
1131
+ parent.is_symlink()
1132
+ for parent in path.parents
1133
+ if parent.is_relative_to(repo) or parent.is_relative_to(home)
1134
+ ):
1135
+ gaps.append("symlink_instruction:" + str(path))
1136
+ continue
1137
+ content = path.read_bytes()
1138
+ hashed = digest(content)
1139
+ if str(path) in expected and hashed == expected[str(path)]["sha256"]:
1140
+ origin = "injected"
1141
+ elif path.is_relative_to(repo):
1142
+ original = subprocess.run(
1143
+ [
1144
+ "git",
1145
+ "-c",
1146
+ "safe.directory=" + str(repo),
1147
+ "-C",
1148
+ str(repo),
1149
+ "show",
1150
+ "HEAD:" + path.relative_to(repo).as_posix(),
1151
+ ],
1152
+ capture_output=True,
1153
+ )
1154
+ origin = (
1155
+ "repository_background"
1156
+ if original.returncode == 0 and original.stdout == content
1157
+ else "unknown"
1158
+ )
1159
+ else:
1160
+ origin = "unknown"
1161
+ if origin == "unknown":
1162
+ gaps.append("undeclared_instruction:" + str(path))
1163
+ if path.name == "SKILL.md" and str(path) not in expected:
1164
+ match = re.search(rb"(?m)^name:[ \t]*['\"]?([a-z0-9][a-z0-9-]*)", content)
1165
+ if match and match[1] in targets:
1166
+ gaps.append("duplicate_target_skill:" + str(path))
1167
+ sources.append({"path": str(path), "sha256": hashed, "origin": origin})
1168
+ return {"sources": sources, "gaps": sorted(set(gaps))}
1169
+
1170
+
1171
+ def credential_values(value):
1172
+ result = []
1173
+ if isinstance(value, dict):
1174
+ for key, item in value.items():
1175
+ if (
1176
+ isinstance(item, str)
1177
+ and len(item) >= 16
1178
+ and any(word in key.upper() for word in ["TOKEN", "API_KEY", "SECRET"])
1179
+ ):
1180
+ result.append(item)
1181
+ else:
1182
+ result.extend(credential_values(item))
1183
+ elif isinstance(value, list):
1184
+ for item in value:
1185
+ result.extend(credential_values(item))
1186
+ return result
1187
+
1188
+
1189
+ def tooling_manifest(directory):
1190
+ directory = Path(directory).resolve(strict=True)
1191
+ result = []
1192
+ for path in sorted(directory.rglob("*")):
1193
+ mode = path.lstat().st_mode
1194
+ entry = {
1195
+ "path": path.relative_to(directory).as_posix(),
1196
+ "mode": stat.S_IMODE(mode),
1197
+ }
1198
+ if path.is_symlink():
1199
+ if not path.resolve().is_relative_to(directory):
1200
+ raise UnresolvedError("cached tooling link escapes its package")
1201
+ entry["link"] = os.readlink(path)
1202
+ elif path.is_file():
1203
+ entry["sha256"] = digest(path.read_bytes())
1204
+ elif path.is_dir():
1205
+ continue
1206
+ else:
1207
+ raise UnresolvedError("cached tooling contains a special file")
1208
+ result.append(entry)
1209
+ if not result:
1210
+ raise UnresolvedError("cached tooling package is empty")
1211
+ return result
1212
+
1213
+
1214
+ def codex_configuration(model="gpt-6.1-sol", effort="high", *, schema_version=1):
1215
+ configuration = {
1216
+ "model": model,
1217
+ "model_reasoning_effort": effort,
1218
+ "approval_policy": "never",
1219
+ "default_permissions": "evolution",
1220
+ "web_search": "disabled",
1221
+ "mcp_servers": {},
1222
+ "notify": [],
1223
+ "features": {
1224
+ "multi_agent": False,
1225
+ "multi_agent_v2": False,
1226
+ "plugins": False,
1227
+ "apps": False,
1228
+ "shell_snapshot": False,
1229
+ "network_proxy": True,
1230
+ },
1231
+ "shell_environment_policy": {
1232
+ "inherit": "none",
1233
+ "ignore_default_excludes": False,
1234
+ "experimental_use_profile": False,
1235
+ "set": {
1236
+ "HOME": "/home/evolution",
1237
+ "PATH": TASK_PATH,
1238
+ "GOPATH": "/go",
1239
+ "GOCACHE": "/tmp/evolution-go-cache",
1240
+ "LANG": "C.UTF-8",
1241
+ },
1242
+ },
1243
+ "permissions": {
1244
+ "evolution": {
1245
+ "filesystem": {
1246
+ ":minimal": "read",
1247
+ ":workspace_roots": "write",
1248
+ "/tmp": "write",
1249
+ "/usr/local": "read",
1250
+ "/opt/evolution-codex": "read",
1251
+ "/go": "write",
1252
+ "/home/evolution/.nvm": "read",
1253
+ "/home/evolution/.agents": "read",
1254
+ "/evolution-input": "read",
1255
+ "/home/evolution/.codex": "deny",
1256
+ "/evolution-control": "deny",
1257
+ "/tests": "deny",
1258
+ "/solution": "deny",
1259
+ },
1260
+ "network": {
1261
+ "enabled": True,
1262
+ "mode": "limited",
1263
+ "allow_local_binding": False,
1264
+ "domains": {"localhost": "allow", "127.0.0.1": "allow"},
1265
+ },
1266
+ }
1267
+ },
1268
+ }
1269
+ if schema_version == 2:
1270
+ filesystem = configuration["permissions"]["evolution"]["filesystem"]
1271
+ # The managed proxy writes public CA bundles beside private Codex state.
1272
+ # A parent deny also hides the injected public CA from child tools.
1273
+ del filesystem["/home/evolution/.codex"]
1274
+ # A directory component keeps rg's filename globs from recursing into
1275
+ # hidden state directories and layering a second mask over their files.
1276
+ filesystem.update({path: "deny" for path in (
1277
+ "/home/evolution/[.]codex/auth*",
1278
+ "/home/evolution/[.]codex/*.json*",
1279
+ "/home/evolution/[.]codex/config*.toml",
1280
+ "/home/evolution/.codex/.env",
1281
+ "/home/evolution/.codex/sessions",
1282
+ "/home/evolution/.codex/archived_sessions",
1283
+ "/home/evolution/.codex/log",
1284
+ "/home/evolution/[.]codex/*.sqlite*",
1285
+ "/home/evolution/[.]codex/.tmp*",
1286
+ )})
1287
+ filesystem["/home/evolution/.codex/proxy/**"] = "read"
1288
+ return configuration
1289
+
1290
+
1291
+ def toml_value(value):
1292
+ if isinstance(value, dict):
1293
+ return (
1294
+ "{"
1295
+ + ",".join(
1296
+ json.dumps(key) + "=" + toml_value(item)
1297
+ for key, item in sorted(value.items())
1298
+ )
1299
+ + "}"
1300
+ )
1301
+ return json.dumps(value, ensure_ascii=False, allow_nan=False)
1302
+
1303
+
1304
+ def codex_arguments(configuration, cwd, *, prompt=None, probe=None):
1305
+ overrides = [
1306
+ part
1307
+ for key, value in sorted(configuration.items())
1308
+ for part in ["-c", key + "=" + toml_value(value)]
1309
+ ]
1310
+ if probe is not None:
1311
+ return [
1312
+ "/usr/local/bin/codex",
1313
+ "sandbox",
1314
+ "-C",
1315
+ cwd,
1316
+ "-P",
1317
+ "evolution",
1318
+ *overrides,
1319
+ "--",
1320
+ "python3",
1321
+ "-c",
1322
+ probe,
1323
+ ]
1324
+ return [
1325
+ "/usr/local/bin/codex",
1326
+ "exec",
1327
+ "--strict-config",
1328
+ "--ignore-user-config",
1329
+ "--ignore-rules",
1330
+ "--skip-git-repo-check",
1331
+ "--json",
1332
+ "-C",
1333
+ cwd,
1334
+ *overrides,
1335
+ "--",
1336
+ prompt,
1337
+ ]
1338
+
1339
+
1340
+ def create_resource(runtime, execution, payload):
1341
+ if (
1342
+ digest(encoded(payload)) != execution["input_hash"]
1343
+ or digest(encoded(payload["command"])) != execution["command_hash"]
1344
+ ):
1345
+ raise RemoteError("submitted inputs differ from their frozen hashes")
1346
+ if payload["command"]["uid"] != 10000 or payload["command"]["gid"] != 10000:
1347
+ raise RemoteError("task command must use the unprivileged task identity")
1348
+ control = host_control(execution)
1349
+ control.mkdir(mode=0o700, parents=True, exist_ok=False)
1350
+ save_json(control / "receipt.json", execution)
1351
+ save_json(control / "runtime.json", runtime)
1352
+ save_json(control / "payload.json", payload)
1353
+ save_bytes(control / "remote.py", Path(__file__).read_bytes())
1354
+ identity = engine_identity(runtime)
1355
+ present = docker(runtime, ["image", "inspect", payload["image"]], check=False)
1356
+ if present.returncode:
1357
+ docker(
1358
+ runtime,
1359
+ ["pull", "--platform", payload["platform"], payload["image"]],
1360
+ timeout=300,
1361
+ )
1362
+ remaining = int(execution["resource_deadline"] - time.time())
1363
+ if remaining <= 0:
1364
+ raise RemoteError("run deadline reached before resource creation")
1365
+ args = [
1366
+ "run",
1367
+ "--detach",
1368
+ "--init",
1369
+ "--name",
1370
+ execution["sandbox_name"],
1371
+ "--platform",
1372
+ payload["platform"],
1373
+ "--label",
1374
+ "xgent.execution=" + execution["remote_task_id"],
1375
+ "--label",
1376
+ "xgent.input=" + execution["input_hash"],
1377
+ "--cpus",
1378
+ "1",
1379
+ "--memory",
1380
+ "4g",
1381
+ "--pids-limit",
1382
+ "512",
1383
+ "--ulimit",
1384
+ "core=0",
1385
+ "--security-opt",
1386
+ "no-new-privileges",
1387
+ "--cap-drop",
1388
+ "NET_RAW",
1389
+ "--cap-add",
1390
+ "NET_ADMIN",
1391
+ "--security-opt",
1392
+ "seccomp=unconfined",
1393
+ "--security-opt",
1394
+ "apparmor=" + runtime.get("apparmor_profile", "unconfined"),
1395
+ "--entrypoint",
1396
+ "/bin/sh",
1397
+ payload["image"],
1398
+ "-c",
1399
+ "sleep " + str(remaining),
1400
+ ]
1401
+ created = docker(runtime, args, timeout=300)
1402
+ execution.update(
1403
+ sandbox_id=created.stdout.decode().strip(),
1404
+ engine_id=identity,
1405
+ submission_status="resource_created",
1406
+ )
1407
+ save_json(control / "receipt.json", execution)
1408
+ resource = owned_resource(runtime, execution)
1409
+ if resource.get("AppArmorProfile") != runtime.get("apparmor_profile", "unconfined"):
1410
+ raise RemoteError(
1411
+ "actual container AppArmor profile differs from the frozen runtime"
1412
+ )
1413
+ if any(item["Type"] == "bind" for item in resource.get("Mounts", [])):
1414
+ raise RemoteError("task container has an undeclared host bind mount")
1415
+ removed = payload.get("remove_paths", [])
1416
+ root = Path(payload["repo_path"])
1417
+ if any(
1418
+ not Path(name).is_relative_to(root)
1419
+ or Path(name) == root
1420
+ or ".." in Path(name).parts
1421
+ or name in payload["files"]
1422
+ for name in removed
1423
+ ):
1424
+ raise RemoteError(
1425
+ "input removal is outside the task repository or conflicts with staged bytes"
1426
+ )
1427
+ if removed:
1428
+ container_exec(
1429
+ runtime,
1430
+ execution,
1431
+ [
1432
+ "python3",
1433
+ "-c",
1434
+ "import json,pathlib,sys; "
1435
+ "[pathlib.Path(name).unlink(missing_ok=True) for name in json.loads(sys.argv[1])]",
1436
+ encoded(removed).decode(),
1437
+ ],
1438
+ )
1439
+ files = dict(payload["files"])
1440
+ files.update(
1441
+ {
1442
+ "/evolution-control/remote.py": encoded_file(Path(__file__).read_bytes()),
1443
+ "/evolution-control/command.json": encoded_file(
1444
+ encoded(payload["command"])
1445
+ ),
1446
+ "/evolution-control/payload.json": encoded_file(encoded(payload)),
1447
+ "/evolution-control/receipt.json": encoded_file(encoded(execution)),
1448
+ }
1449
+ )
1450
+ container_files(runtime, execution, files)
1451
+ setup = (
1452
+ "import os,pathlib; "
1453
+ "p=pathlib.Path('/home/evolution');p.mkdir(parents=True,exist_ok=True);os.chown(p,10000,10000); "
1454
+ "os.chmod('/evolution-control',0o700)"
1455
+ )
1456
+ container_exec(runtime, execution, ["python3", "-c", setup])
1457
+ basic = """
1458
+ import base64, hashlib, json, os, pathlib, subprocess, sys
1459
+ packet = json.loads(pathlib.Path('/evolution-control/payload.json').read_text())
1460
+ repo = pathlib.Path(packet['repo_path'])
1461
+ if packet.get('generated_workspace'):
1462
+ subprocess.run(['git','-C',str(repo),'init','-q'],check=True)
1463
+ subprocess.run(['git','-C',str(repo),'add','-A'],check=True)
1464
+ subprocess.run(['git','-C',str(repo),'-c','user.name=Evaluation','-c','user.email=evaluation@invalid','-c','core.hooksPath=/dev/null','commit','-qm','Input snapshot'],check=True)
1465
+ actual = subprocess.check_output(['git', '-C', str(repo), 'rev-parse', 'HEAD'], text=True).strip()
1466
+ if not packet.get('generated_workspace') and actual != packet['base_commit']:
1467
+ raise ValueError('task image base differs: ' + actual)
1468
+ git = ['git', '-c', 'core.hooksPath=/dev/null', '-c', 'core.fsmonitor=false', '-C', str(repo)]
1469
+ if not packet.get('generated_workspace'):
1470
+ ancestors = set(subprocess.check_output([*git, 'rev-list', packet['base_commit']], text=True).splitlines())
1471
+ objects = subprocess.check_output([*git, 'cat-file', '--batch-all-objects', '--batch-check=%(objectname) %(objecttype)'], text=True).splitlines()
1472
+ commits = {line.split()[0] for line in objects if line.endswith(' commit')}
1473
+ if not commits <= ancestors:
1474
+ raise ValueError('task image contains later Git commits')
1475
+ subprocess.run([*git, 'add', '-A', '--', '.'], check=True)
1476
+ tree = subprocess.check_output([*git, 'write-tree'], text=True).strip()
1477
+ pathlib.Path('/evolution-control/base-tree.txt').write_text(tree)
1478
+ subprocess.run(['chown', '-R', '10000:10000', str(repo)], check=True)
1479
+ if pathlib.Path('/go').is_dir():
1480
+ subprocess.run(['chown', '-R', '10000:10000', '/go'], check=True)
1481
+ if packet.get('grading'):
1482
+ logs = pathlib.Path('/logs/verifier')
1483
+ logs.mkdir(parents=True, exist_ok=True)
1484
+ os.chown(logs, 10000, 10000)
1485
+ files = {}
1486
+ for name in packet.get('remove_paths', []):
1487
+ if pathlib.Path(name).exists() or pathlib.Path(name).is_symlink():
1488
+ raise ValueError('removed instruction is still present')
1489
+ for name, row in packet['files'].items():
1490
+ path = pathlib.Path(name)
1491
+ expected = base64.b64decode(row['data'])
1492
+ if path.is_symlink() or path.read_bytes() != expected:
1493
+ raise ValueError('staged file differs')
1494
+ files[name] = hashlib.sha256(expected).hexdigest()
1495
+ receipt = {'base_commit': actual, 'baseline_tree': tree, 'input_files': files, 'removed_paths': packet.get('remove_paths', []), 'uid': 10000}
1496
+ pathlib.Path('/evolution-control/instruction-receipt.json').write_text(json.dumps(receipt))
1497
+ print(json.dumps(receipt))
1498
+ """
1499
+ prepared = container_exec(
1500
+ runtime,
1501
+ execution,
1502
+ ["python3", "-c", basic],
1503
+ timeout=max(1, min(180, execution["command_deadline"] - time.time())),
1504
+ check=False,
1505
+ )
1506
+ if prepared.returncode:
1507
+ raise RemoteError(
1508
+ "task image or staged input did not match its frozen contract"
1509
+ )
1510
+ receipt = json.loads(prepared.stdout)
1511
+ receipt.update(
1512
+ image_id=resource["Image"],
1513
+ apparmor_profile=resource.get("AppArmorProfile"),
1514
+ mounts=[
1515
+ {
1516
+ "type": item["Type"],
1517
+ "destination": item["Destination"],
1518
+ "read_write": item["RW"],
1519
+ }
1520
+ for item in resource.get("Mounts", [])
1521
+ ],
1522
+ )
1523
+ save_json(control / "instruction-receipt.json", receipt)
1524
+ container_files(
1525
+ runtime,
1526
+ execution,
1527
+ {"/evolution-control/instruction-receipt.json": encoded_file(encoded(receipt))},
1528
+ )
1529
+ return {"sandbox_id": execution["sandbox_id"], "engine_id": identity}
1530
+
1531
+
1532
+ def inner_inspection(runtime, execution):
1533
+ result = container_exec(
1534
+ runtime,
1535
+ execution,
1536
+ ["python3", "/evolution-control/remote.py", "--inspect", "/evolution-control"],
1537
+ check=False,
1538
+ )
1539
+ if result.returncode:
1540
+ raise UnresolvedError("original command receipt is unavailable")
1541
+ return json.loads(result.stdout)
1542
+
1543
+
1544
+ def mirror_capture(runtime, execution, receipt):
1545
+ control = host_control(execution)
1546
+ with tempfile.TemporaryDirectory(prefix="capture-", dir=control) as temporary:
1547
+ target = Path(temporary) / "artifacts"
1548
+ docker(
1549
+ runtime,
1550
+ [
1551
+ "cp",
1552
+ execution["sandbox_id"] + ":/evolution-control/artifacts",
1553
+ str(target),
1554
+ ],
1555
+ )
1556
+ for row in receipt["artifact_manifest"]:
1557
+ name = Path(row["path"])
1558
+ if name.is_absolute() or ".." in name.parts:
1559
+ raise UnresolvedError("artifact manifest escapes capture directory")
1560
+ source = target / name
1561
+ raw = source.read_bytes()
1562
+ if len(raw) != row["size"] or digest(raw) != row["sha256"]:
1563
+ raise UnresolvedError("captured artifact hash differs")
1564
+ copy_artifact(source, control / "artifacts" / name)
1565
+ save_json(control / "receipt.json", receipt)
1566
+ if (control / "typesafe-credential.json").exists():
1567
+ destroy_typesafe_credential(runtime, execution, owned_resource(runtime, execution))
1568
+
1569
+
1570
+ def host_supervise(control):
1571
+ control = Path(control)
1572
+ runtime = read_json(control / "runtime.json")
1573
+ execution = read_json(control / "receipt.json")
1574
+ descriptor = os.open(
1575
+ control / "host-launch.claim", os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600
1576
+ )
1577
+ os.close(descriptor)
1578
+ docker(
1579
+ runtime,
1580
+ [
1581
+ "exec",
1582
+ "--detach",
1583
+ "--user",
1584
+ "root",
1585
+ execution["sandbox_id"],
1586
+ "python3",
1587
+ "/evolution-control/remote.py",
1588
+ "--supervise",
1589
+ "/evolution-control",
1590
+ ],
1591
+ )
1592
+ while time.time() < execution["resource_deadline"]:
1593
+ try:
1594
+ inspected = inner_inspection(runtime, execution)
1595
+ receipt = inspected["receipt"]
1596
+ if receipt["phase"] == "captured":
1597
+ mirror_capture(runtime, execution, receipt)
1598
+ return receipt
1599
+ save_json(control / "receipt.json", receipt)
1600
+ except (RemoteError, OSError, json.JSONDecodeError):
1601
+ pass
1602
+ time.sleep(0.5)
1603
+ raise UnresolvedError(
1604
+ "capture window expired; preserve the registered resource and receipts"
1605
+ )
1606
+
1607
+
1608
+ def dispatch_request(request):
1609
+ runtime, execution, payload = (
1610
+ request["runtime"],
1611
+ request["execution"],
1612
+ request.get("payload"),
1613
+ )
1614
+ if (runtime["ssh_target"], runtime["remote_root"]) != (
1615
+ execution["ssh_target"],
1616
+ execution["remote_root"],
1617
+ ):
1618
+ raise UnresolvedError("SSH execution scope differs")
1619
+ if digest(Path(__file__).read_bytes()) != execution["runner_hash"]:
1620
+ raise UnresolvedError("deployed runner differs from the frozen source")
1621
+ operation = request["operation"]
1622
+ if operation == "create":
1623
+ return create_resource(runtime, execution, payload)
1624
+ control = host_control(execution)
1625
+ original = read_json(control / "receipt.json")
1626
+ for key in ["remote_task_id", "input_hash", "command_hash", "runner_hash"]:
1627
+ if original[key] != execution[key]:
1628
+ raise UnresolvedError("stored execution identity differs")
1629
+ if operation == "read_artifact":
1630
+ matches = [
1631
+ row
1632
+ for row in original["artifact_manifest"]
1633
+ if row["path"] == payload["path"]
1634
+ ]
1635
+ if original["phase"] != "captured" or len(matches) != 1:
1636
+ raise UnresolvedError("artifact is not in the captured manifest")
1637
+ return {
1638
+ "data": base64.b64encode(
1639
+ (control / "artifacts" / matches[0]["path"]).read_bytes()
1640
+ ).decode("ascii")
1641
+ }
1642
+ resource = owned_resource(runtime, original)
1643
+ if operation == "destroy_typesafe":
1644
+ return {"destroyed": destroy_typesafe_credential(runtime, original, resource)}
1645
+ if operation == "prepare_typesafe":
1646
+ if resource is None or original["submission_status"] != "resource_created":
1647
+ raise UnresolvedError("credential preparation requires the original prepared resource")
1648
+ return prepare_typesafe_credential(runtime, original, payload)
1649
+ if operation == "query":
1650
+ if original["phase"] == "captured" and (control / "artifacts").is_dir():
1651
+ destroy_typesafe_credential(runtime, original, resource)
1652
+ return {
1653
+ "receipt": original,
1654
+ "resource_state": "missing"
1655
+ if resource is None
1656
+ else resource["State"]["Status"],
1657
+ "command_alive": False,
1658
+ "supervisor_alive": False,
1659
+ }
1660
+ if resource is None or not resource["State"]["Running"]:
1661
+ raise UnresolvedError(
1662
+ "resource ended before complete evidence was recovered"
1663
+ )
1664
+ inspected = inner_inspection(runtime, original)
1665
+ if inspected["receipt"]["phase"] == "captured":
1666
+ mirror_capture(runtime, original, inspected["receipt"])
1667
+ return {**inspected, "resource_state": resource["State"]["Status"]}
1668
+ if operation == "cleanup":
1669
+ if original["phase"] != "captured" and not payload.get("force_reason"):
1670
+ raise UnresolvedError("cleanup would discard uncaptured evidence")
1671
+ credentials_destroyed = destroy_typesafe_credential(runtime, original, resource)
1672
+ if resource is not None:
1673
+ docker(runtime, ["stop", "--time", "2", resource["Id"]])
1674
+ docker(runtime, ["rm", "--volumes", resource["Id"]])
1675
+ return {"terminated": owned_resource(runtime, original) is None and credentials_destroyed}
1676
+ if resource is None:
1677
+ raise UnresolvedError("registered container is unavailable")
1678
+ if operation == "cancel":
1679
+ container_files(
1680
+ runtime,
1681
+ original,
1682
+ {"/evolution-control/cancel.json": encoded_file(encoded(payload))},
1683
+ )
1684
+ return {"cancel_requested": True}
1685
+ if operation == "capture_only":
1686
+ captured = container_exec(
1687
+ runtime,
1688
+ original,
1689
+ [
1690
+ "python3",
1691
+ "/evolution-control/remote.py",
1692
+ "--capture-only",
1693
+ "/evolution-control",
1694
+ ],
1695
+ check=False,
1696
+ )
1697
+ if captured.returncode:
1698
+ raise UnresolvedError(
1699
+ "original processes could not be confirmed stopped for capture-only"
1700
+ )
1701
+ receipt = json.loads(captured.stdout)
1702
+ mirror_capture(runtime, original, receipt)
1703
+ return {"receipt": receipt}
1704
+ if operation in {"restore_codex", "cache_codex"}:
1705
+ if (control / "host-launch.claim").exists():
1706
+ raise UnresolvedError("tooling cache cannot change after task startup")
1707
+ cache = (
1708
+ Path(runtime["remote_root"])
1709
+ / "tools"
1710
+ / (
1711
+ "codex-"
1712
+ + runtime["codex_version"]
1713
+ + "-"
1714
+ + runtime["codex_architecture"]
1715
+ )
1716
+ )
1717
+ package, index = cache / "package", cache / "manifest.json"
1718
+ if operation == "restore_codex":
1719
+ if not index.exists():
1720
+ return {"restored": False}
1721
+ entries = tooling_manifest(package)
1722
+ if entries != read_json(index):
1723
+ raise UnresolvedError("cached tooling differs from its saved manifest")
1724
+ docker(
1725
+ runtime,
1726
+ ["cp", str(package), original["sandbox_id"] + ":/opt/evolution-codex"],
1727
+ timeout=120,
1728
+ )
1729
+ return {"restored": True, "manifest_sha256": digest(encoded(entries))}
1730
+ version = (
1731
+ container_exec(runtime, original, ["/usr/local/bin/codex", "--version"])
1732
+ .stdout.decode()
1733
+ .strip()
1734
+ )
1735
+ if version != "codex-cli " + runtime["codex_version"]:
1736
+ raise RemoteError("cannot cache a different Codex version")
1737
+ staging = control / "installed-tooling"
1738
+ docker(
1739
+ runtime,
1740
+ ["cp", original["sandbox_id"] + ":/opt/evolution-codex", str(staging)],
1741
+ timeout=120,
1742
+ )
1743
+ entries = tooling_manifest(staging)
1744
+ cache.mkdir(mode=0o700, parents=True, exist_ok=True)
1745
+ if index.exists():
1746
+ if read_json(index) != entries or tooling_manifest(package) != entries:
1747
+ raise UnresolvedError(
1748
+ "installed tooling differs from the existing cache"
1749
+ )
1750
+ else:
1751
+ staging.rename(package)
1752
+ save_json(index, entries)
1753
+ return {"cached": True, "manifest_sha256": digest(encoded(entries))}
1754
+ if operation == "setup_exec":
1755
+ if (control / "host-launch.claim").exists():
1756
+ raise UnresolvedError(
1757
+ "setup cannot execute after the original command has started"
1758
+ )
1759
+ result = container_exec(
1760
+ runtime,
1761
+ original,
1762
+ ["bash", "-c", payload["command"]],
1763
+ user=payload.get("user") or "root",
1764
+ cwd=payload.get("cwd"),
1765
+ env=payload.get("env"),
1766
+ timeout=payload.get("timeout_sec") or 300,
1767
+ check=False,
1768
+ )
1769
+ observation = {
1770
+ "return_code": result.returncode,
1771
+ "stdout": result.stdout.decode(errors="replace"),
1772
+ "stderr": result.stderr.decode(errors="replace"),
1773
+ }
1774
+ with (control / "setup.jsonl").open("ab") as stream:
1775
+ stream.write(encoded(observation) + b"\n")
1776
+ return observation
1777
+ if operation == "setup_files":
1778
+ if (control / "host-launch.claim").exists():
1779
+ raise UnresolvedError("setup cannot alter a started execution")
1780
+ container_files(runtime, original, payload)
1781
+ return {"staged": True}
1782
+ if operation == "finalize_setup":
1783
+ if (control / "host-launch.claim").exists():
1784
+ raise UnresolvedError("setup cannot alter a started execution")
1785
+ packet = read_json(control / "payload.json")
1786
+ authentication = runtime.get("authentication")
1787
+ if authentication is not None:
1788
+ authentication_bytes = Path(authentication["path"]).read_bytes()
1789
+ container_files(
1790
+ runtime,
1791
+ original,
1792
+ {
1793
+ "/home/evolution/.codex/auth.json": encoded_file(
1794
+ authentication_bytes, 0o600
1795
+ ),
1796
+ "/evolution-control/redaction.json": encoded_file(
1797
+ encoded(credential_values(json.loads(authentication_bytes))),
1798
+ 0o600,
1799
+ ),
1800
+ },
1801
+ )
1802
+ setup = (
1803
+ "import base64,hashlib,json,os,pathlib,subprocess,sys; "
1804
+ "sys.path.insert(0,'/evolution-control'); from remote import instruction_inventory; "
1805
+ "packet=json.loads(pathlib.Path('/evolution-control/payload.json').read_text()); "
1806
+ "home=pathlib.Path('/home/evolution'); "
1807
+ "[(os.chown(p,10000,10000)) for p in [home,*home.rglob('*')] if not p.is_symlink()]; "
1808
+ "binary=pathlib.Path('/usr/local/bin/codex').resolve(); "
1809
+ "candidates=[binary]+list(binary.parent.parent.parent.rglob('codex')); "
1810
+ "native=next(p for p in candidates if p.is_file() and p.open('rb').read(4)==b'\\x7fELF'); "
1811
+ "receipt=json.loads(pathlib.Path('/evolution-control/instruction-receipt.json').read_text()); "
1812
+ "inventory=instruction_inventory(pathlib.Path(packet['repo_path']),home,{name:{'sha256':hashlib.sha256(base64.b64decode(row['data'])).hexdigest()} for name,row in packet['files'].items()}); "
1813
+ "receipt.update({'instruction_sources':inventory['sources'],'source_gaps':inventory['gaps']}); "
1814
+ "receipt.update({'codex_version':subprocess.check_output(['/usr/local/bin/codex','--version'],text=True).strip(),"
1815
+ "'binary_sha256':hashlib.sha256(native.read_bytes()).hexdigest(),"
1816
+ "'launcher_sha256':hashlib.sha256(binary.read_bytes()).hexdigest(),"
1817
+ "'config_sha256':hashlib.sha256(pathlib.Path('/home/evolution/.codex/config.toml').read_bytes()).hexdigest()}); "
1818
+ "pathlib.Path('/evolution-control/instruction-receipt.json').write_text(json.dumps(receipt)); "
1819
+ "assert not inventory['gaps'], 'undeclared instruction sources'; "
1820
+ "print(json.dumps(receipt))"
1821
+ )
1822
+ result = container_exec(runtime, original, ["python3", "-c", setup])
1823
+ receipt = json.loads(result.stdout)
1824
+ if receipt["codex_version"] != "codex-cli " + runtime["codex_version"]:
1825
+ raise RemoteError("installed Codex version differs from the frozen runtime")
1826
+ if any(
1827
+ receipt.get(name) != expected
1828
+ for name, expected in packet.get("expected_runtime", {}).items()
1829
+ ):
1830
+ raise RemoteError("actual Codex runtime differs from the calibrated binary")
1831
+ expected_config = packet["codex_config"]
1832
+ receipt["configuration"] = expected_config
1833
+ save_json(control / "instruction-receipt.json", receipt)
1834
+ container_files(
1835
+ runtime,
1836
+ original,
1837
+ {
1838
+ "/evolution-control/instruction-receipt.json": encoded_file(
1839
+ encoded(receipt)
1840
+ )
1841
+ },
1842
+ )
1843
+ return receipt
1844
+ if operation == "launch":
1845
+ if (control / "host-launch.claim").exists():
1846
+ return {"launched": True}
1847
+ with (control / "host-runner.log").open("ab") as output:
1848
+ process = subprocess.Popen(
1849
+ [
1850
+ sys.executable,
1851
+ str(control / "remote.py"),
1852
+ "--host-supervise",
1853
+ str(control),
1854
+ ],
1855
+ stdin=subprocess.DEVNULL,
1856
+ stdout=output,
1857
+ stderr=output,
1858
+ start_new_session=True,
1859
+ env=host_environment(runtime),
1860
+ )
1861
+ save_json(
1862
+ control / "host-supervisor.json",
1863
+ {
1864
+ "pid": process.pid,
1865
+ "pgid": process.pid,
1866
+ "start_identity": process_identity(process.pid),
1867
+ },
1868
+ )
1869
+ return {"launched": True}
1870
+ raise RemoteError("unknown remote operation")
1871
+
1872
+
1873
+ def process_identity(pid):
1874
+ try:
1875
+ proc = Path("/proc") / str(pid)
1876
+ if proc.is_dir():
1877
+ # Emulated /proc/stat start ticks can differ by one tick between
1878
+ # self and external readers. The task directory inode is stable
1879
+ # for that process lifetime and changes when the PID is reused.
1880
+ return (
1881
+ Path("/proc/sys/kernel/random/boot_id").read_text().strip()
1882
+ + ":"
1883
+ + str(proc.stat().st_ino)
1884
+ )
1885
+ result = subprocess.run(
1886
+ ["ps", "-o", "lstart=", "-p", str(pid)], capture_output=True, text=True
1887
+ )
1888
+ return result.stdout.strip() or None
1889
+ except (OSError, ValueError, IndexError):
1890
+ return None
1891
+
1892
+
1893
+ def process_alive(process):
1894
+ if process is None:
1895
+ return False
1896
+ try:
1897
+ os.kill(process["pid"], 0)
1898
+ return process_identity(process["pid"]) == process["start_identity"]
1899
+ except (OSError, KeyError):
1900
+ return False
1901
+
1902
+
1903
+ def inspect_command(control):
1904
+ control = Path(control)
1905
+ receipt = read_json(control / "receipt.json")
1906
+ runner_path = control / "supervisor.json"
1907
+ runner = read_json(runner_path) if runner_path.exists() else None
1908
+ command_alive = process_alive(receipt.get("process"))
1909
+ supervisor_alive = process_alive(runner)
1910
+ latest = read_json(control / "receipt.json")
1911
+ if latest != receipt:
1912
+ receipt = latest
1913
+ command_alive = process_alive(receipt.get("process"))
1914
+ return {
1915
+ "receipt": receipt,
1916
+ "command_alive": command_alive,
1917
+ "supervisor_alive": supervisor_alive,
1918
+ "claimed": (control / "launch.claim").exists(),
1919
+ }
1920
+
1921
+
1922
+ def process_options(command):
1923
+ options = {"cwd": command["cwd"], "env": command["env"], "start_new_session": True}
1924
+ if command["uid"] is not None:
1925
+ options.update(user=command["uid"], group=command["gid"], extra_groups=[])
1926
+ return options
1927
+
1928
+
1929
+ def task_pids(uid):
1930
+ # The production supervisor is root inside its own container. Never scan
1931
+ # or signal the developer's user during deterministic process fixtures.
1932
+ if uid is None or uid < 10000 or os.geteuid() != 0 or not Path("/proc").is_dir():
1933
+ return []
1934
+ result = []
1935
+ for entry in Path("/proc").iterdir():
1936
+ if not entry.name.isdigit():
1937
+ continue
1938
+ try:
1939
+ for line in (entry / "status").read_text().splitlines():
1940
+ if line.startswith("Uid:") and int(line.split()[1]) == uid:
1941
+ result.append(int(entry.name))
1942
+ except (OSError, ValueError):
1943
+ continue
1944
+ return result
1945
+
1946
+
1947
+ def stop_processes(process, uid, child=None, grace=0.5):
1948
+ for sig in [signal.SIGTERM, signal.SIGKILL]:
1949
+ if process is not None:
1950
+ try:
1951
+ os.killpg(process["pgid"], sig)
1952
+ except ProcessLookupError:
1953
+ pass
1954
+ for pid in task_pids(uid):
1955
+ try:
1956
+ os.kill(pid, sig)
1957
+ except ProcessLookupError:
1958
+ pass
1959
+ if sig == signal.SIGTERM:
1960
+ time.sleep(grace)
1961
+ if child is not None:
1962
+ # Reap a terminated leader before signalling remaining group
1963
+ # members; macOS rejects killpg against a zombie-only group.
1964
+ child.poll()
1965
+
1966
+
1967
+ def copy_artifact(source, destination):
1968
+ source = Path(source)
1969
+ path = source
1970
+ while path != path.parent:
1971
+ if path.is_symlink():
1972
+ raise ValueError("artifact source cannot be a symlink")
1973
+ path = path.parent
1974
+ descriptor = os.open(source, os.O_RDONLY | os.O_NONBLOCK | os.O_NOFOLLOW)
1975
+ with os.fdopen(descriptor, "rb") as stream:
1976
+ if not stat.S_ISREG(os.fstat(stream.fileno()).st_mode):
1977
+ raise ValueError("artifact source must be a regular file")
1978
+ save_bytes(destination, stream.read())
1979
+
1980
+
1981
+ def capture_artifacts(control, command):
1982
+ artifacts = control / "artifacts"
1983
+ artifacts.mkdir(mode=0o700, exist_ok=True)
1984
+ gaps = []
1985
+ capture = command["capture"]
1986
+ repository = capture["repo"]
1987
+ if repository is not None:
1988
+ env = {
1989
+ **command["env"],
1990
+ "GIT_CONFIG_NOSYSTEM": "1",
1991
+ "GIT_CONFIG_GLOBAL": "/dev/null",
1992
+ }
1993
+ options = {**process_options(command), "cwd": repository, "env": env}
1994
+ git = [
1995
+ "git",
1996
+ "-c",
1997
+ "core.hooksPath=/dev/null",
1998
+ "-c",
1999
+ "core.fsmonitor=false",
2000
+ "-c",
2001
+ "core.pager=cat",
2002
+ ]
2003
+ added = subprocess.run(
2004
+ [*git, "add", "-A", "--", "."], capture_output=True, timeout=30, **options
2005
+ )
2006
+ baseline = (
2007
+ Path(capture["baseline_ref_file"]).read_text().strip()
2008
+ if capture.get("baseline_ref_file")
2009
+ else "HEAD"
2010
+ )
2011
+ patch = subprocess.run(
2012
+ [
2013
+ *git,
2014
+ "diff",
2015
+ "--cached",
2016
+ "--binary",
2017
+ "--no-ext-diff",
2018
+ "--no-textconv",
2019
+ baseline,
2020
+ "--",
2021
+ ".",
2022
+ *[":(exclude)" + name for name in capture["excluded_paths"]],
2023
+ ],
2024
+ capture_output=True,
2025
+ timeout=30,
2026
+ **options,
2027
+ )
2028
+ if added.returncode or patch.returncode:
2029
+ gaps.append("patch_capture_failed")
2030
+ save_json(
2031
+ artifacts / "patch-capture.json",
2032
+ {
2033
+ "add_exit_code": added.returncode,
2034
+ "diff_exit_code": patch.returncode,
2035
+ "add_stderr": added.stderr.decode(errors="replace"),
2036
+ "diff_stderr": patch.stderr.decode(errors="replace"),
2037
+ },
2038
+ )
2039
+ else:
2040
+ save_bytes(artifacts / "model.patch", patch.stdout)
2041
+ session = capture["session_dir"]
2042
+ runtime_files, runtime_names = {}, []
2043
+ if session is not None:
2044
+ root = Path(session)
2045
+ if root.is_dir() and not root.is_symlink():
2046
+ for source in sorted(root.rglob("*")):
2047
+ if source.is_dir() and not source.is_symlink():
2048
+ continue
2049
+ try:
2050
+ copy_artifact(
2051
+ source, artifacts / "sessions" / source.relative_to(root)
2052
+ )
2053
+ except (OSError, ValueError):
2054
+ gaps.append("session_capture_failed")
2055
+ if capture.get("runtime_skills"):
2056
+ builtins = root.parent / "skills/.system"
2057
+ for entry in sorted(builtins.glob("*/SKILL.md")):
2058
+ runtime_names.append(entry.parent.name)
2059
+ for source in sorted(entry.parent.rglob("*")):
2060
+ if source.is_dir() and not source.is_symlink():
2061
+ continue
2062
+ if "__pycache__" in source.parts or source.suffix == ".pyc":
2063
+ continue
2064
+ name = source.relative_to(builtins).as_posix()
2065
+ try:
2066
+ copy_artifact(source, artifacts / "runtime-skills" / name)
2067
+ runtime_files[name] = stat.S_IMODE(source.stat().st_mode)
2068
+ except (OSError, ValueError):
2069
+ gaps.append("runtime_skill_capture_failed")
2070
+ if not runtime_names:
2071
+ gaps.append("runtime_skills_unavailable")
2072
+ for name, source in capture["files"].items():
2073
+ path = Path(name)
2074
+ if path.is_absolute() or ".." in path.parts:
2075
+ raise ValueError("artifact name must stay relative")
2076
+ try:
2077
+ copy_artifact(source, artifacts / path)
2078
+ except (OSError, ValueError):
2079
+ gaps.append("missing_artifact:" + name)
2080
+ for name, source in capture.get("optional_files", {}).items():
2081
+ path = Path(name)
2082
+ if path.is_absolute() or ".." in path.parts:
2083
+ raise ValueError("optional artifact name must stay relative")
2084
+ if Path(source).exists():
2085
+ copy_artifact(source, artifacts / path)
2086
+ secrets = (
2087
+ read_json(control / "redaction.json")
2088
+ if (control / "redaction.json").exists()
2089
+ else []
2090
+ )
2091
+ auth_path = Path(session).parent / "auth.json" if session is not None else None
2092
+ if auth_path is not None and auth_path.is_file():
2093
+ secrets.extend(credential_values(read_json(auth_path)))
2094
+ redacted = []
2095
+ for path in sorted(artifacts.rglob("*")):
2096
+ if not path.is_file():
2097
+ continue
2098
+ raw = path.read_bytes()
2099
+ changed = raw
2100
+ for secret in set(secrets):
2101
+ changed = changed.replace(secret.encode(), b"[REDACTED]")
2102
+ if changed != raw:
2103
+ if path.name.endswith(".patch"):
2104
+ path.unlink()
2105
+ gaps.append("credential_in_patch")
2106
+ else:
2107
+ save_bytes(path, changed)
2108
+ redacted.append(path.relative_to(artifacts).as_posix())
2109
+ if auth_path is not None and auth_path.exists():
2110
+ auth_path.unlink()
2111
+ (control / "redaction.json").unlink(missing_ok=True)
2112
+ if command.get("typesafe_credential"):
2113
+ credential = Path(command["typesafe_credential"])
2114
+ credential.unlink(missing_ok=True)
2115
+ save_json(artifacts / "credential-receipt.json", {"provider": "typesafe", "destroyed": not credential.exists()})
2116
+ if capture.get("runtime_skills"):
2117
+ save_json(
2118
+ artifacts / "runtime-skills.json",
2119
+ {
2120
+ "skills": runtime_names,
2121
+ "files": [
2122
+ {
2123
+ "path": name,
2124
+ "mode": mode,
2125
+ "sha256": digest(
2126
+ (artifacts / "runtime-skills" / name).read_bytes()
2127
+ ),
2128
+ }
2129
+ for name, mode in sorted(runtime_files.items())
2130
+ ],
2131
+ },
2132
+ )
2133
+ save_json(
2134
+ artifacts / "capture.json",
2135
+ {"gaps": sorted(set(gaps)), "redacted_artifacts": redacted},
2136
+ )
2137
+ manifest = []
2138
+ for path in sorted(artifacts.rglob("*")):
2139
+ if path.is_dir():
2140
+ continue
2141
+ raw = path.read_bytes()
2142
+ manifest.append(
2143
+ {
2144
+ "path": path.relative_to(artifacts).as_posix(),
2145
+ "size": len(raw),
2146
+ "sha256": digest(raw),
2147
+ }
2148
+ )
2149
+ return manifest
2150
+
2151
+
2152
+ def verify_supervisor_inputs(control):
2153
+ receipt = read_json(control / "receipt.json")
2154
+ command = read_json(control / "command.json")
2155
+ if digest(encoded(command)) != receipt["command_hash"]:
2156
+ raise ValueError("frozen command hash mismatch")
2157
+ if digest(Path(__file__).read_bytes()) != receipt["runner_hash"]:
2158
+ raise ValueError("frozen supervisor hash mismatch")
2159
+ return receipt, command
2160
+
2161
+
2162
+ def run_supervisor(control):
2163
+ control = Path(control)
2164
+ receipt, command = verify_supervisor_inputs(control)
2165
+ try:
2166
+ descriptor = os.open(
2167
+ control / "launch.claim", os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600
2168
+ )
2169
+ except FileExistsError:
2170
+ return read_json(control / "receipt.json")
2171
+ os.close(descriptor)
2172
+ save_json(
2173
+ control / "supervisor.json",
2174
+ {
2175
+ "pid": os.getpid(),
2176
+ "pgid": os.getpgrp(),
2177
+ "start_identity": process_identity(os.getpid()),
2178
+ },
2179
+ )
2180
+ receipt["phase"] = "starting"
2181
+ save_json(control / "receipt.json", receipt)
2182
+ artifacts = control / "artifacts"
2183
+ artifacts.mkdir(mode=0o700, exist_ok=True)
2184
+ child = None
2185
+ started = None
2186
+ try:
2187
+ with (
2188
+ (artifacts / "stdout.jsonl").open("wb") as stdout,
2189
+ (artifacts / "stderr.txt").open("wb") as stderr,
2190
+ ):
2191
+ if time.time() >= receipt["command_deadline"]:
2192
+ receipt.update(
2193
+ phase="capturing", termination_reason="not_started_deadline"
2194
+ )
2195
+ save_json(control / "receipt.json", receipt)
2196
+ receipt["artifact_manifest"] = capture_artifacts(control, command)
2197
+ receipt["phase"] = "captured"
2198
+ save_json(control / "receipt.json", receipt)
2199
+ return receipt
2200
+ started = time.monotonic()
2201
+ child = subprocess.Popen(
2202
+ command["args"],
2203
+ stdin=subprocess.DEVNULL,
2204
+ stdout=stdout,
2205
+ stderr=stderr,
2206
+ **process_options(command),
2207
+ )
2208
+ identity = process_identity(child.pid)
2209
+ receipt["process"] = {
2210
+ "pid": child.pid,
2211
+ "pgid": child.pid,
2212
+ "start_identity": identity or "already_exited",
2213
+ }
2214
+ receipt["phase"] = "running"
2215
+ save_json(control / "receipt.json", receipt)
2216
+ reason = "exited"
2217
+ while child.poll() is None:
2218
+ if (control / "cancel.json").exists():
2219
+ reason = "cancelled"
2220
+ break
2221
+ if time.time() >= receipt["command_deadline"]:
2222
+ reason = "timeout"
2223
+ break
2224
+ time.sleep(0.05)
2225
+ stop_processes(receipt["process"], command["uid"], child)
2226
+ receipt["exit_code"] = child.wait(timeout=5)
2227
+ receipt["termination_reason"] = reason
2228
+ except OSError:
2229
+ if child is not None:
2230
+ stop_processes(receipt["process"], command["uid"], child)
2231
+ receipt["exit_code"] = child.wait(timeout=5)
2232
+ receipt["termination_reason"] = "launch_failed"
2233
+ receipt["phase"] = "capturing"
2234
+ save_json(control / "receipt.json", receipt)
2235
+ if started is not None and child is not None and receipt["exit_code"] is not None:
2236
+ save_json(
2237
+ artifacts / "command-metrics.json",
2238
+ {"duration_sec": time.monotonic() - started},
2239
+ )
2240
+ receipt["artifact_manifest"] = capture_artifacts(control, command)
2241
+ receipt["phase"] = "captured"
2242
+ save_json(control / "receipt.json", receipt)
2243
+ return receipt
2244
+
2245
+
2246
+ def capture_only(control):
2247
+ control = Path(control)
2248
+ receipt, command = verify_supervisor_inputs(control)
2249
+ if receipt["phase"] == "captured":
2250
+ return receipt
2251
+ inspection = inspect_command(control)
2252
+ if (
2253
+ inspection["command_alive"]
2254
+ or inspection["supervisor_alive"]
2255
+ or task_pids(command["uid"])
2256
+ ):
2257
+ raise ValueError("cannot capture while original execution may still be running")
2258
+ receipt["phase"] = "capturing"
2259
+ if receipt["exit_code"] is None:
2260
+ receipt["termination_reason"] = "original_exit_unknown"
2261
+ save_json(control / "receipt.json", receipt)
2262
+ receipt["artifact_manifest"] = capture_artifacts(control, command)
2263
+ receipt["phase"] = "captured"
2264
+ save_json(control / "receipt.json", receipt)
2265
+ return receipt
2266
+
2267
+
2268
+ def main():
2269
+ parser = argparse.ArgumentParser(description=__doc__)
2270
+ entry = parser.add_mutually_exclusive_group(required=True)
2271
+ entry.add_argument("--supervise", type=Path)
2272
+ entry.add_argument("--inspect", type=Path)
2273
+ entry.add_argument("--capture-only", type=Path)
2274
+ entry.add_argument("--host-supervise", type=Path)
2275
+ entry.add_argument("--dispatch", action="store_true")
2276
+ args = parser.parse_args()
2277
+ try:
2278
+ if args.dispatch:
2279
+ result = dispatch_request(json.load(sys.stdin))
2280
+ elif args.host_supervise:
2281
+ result = host_supervise(args.host_supervise)
2282
+ elif args.supervise:
2283
+ result = run_supervisor(args.supervise)
2284
+ elif args.capture_only:
2285
+ result = capture_only(args.capture_only)
2286
+ else:
2287
+ result = inspect_command(args.inspect)
2288
+ print(json.dumps(result, ensure_ascii=False))
2289
+ return 0
2290
+ except Exception as error:
2291
+ message = (
2292
+ str(error) if isinstance(error, RemoteError) else "remote operation failed"
2293
+ )
2294
+ print(
2295
+ json.dumps(
2296
+ {"error": message, "unresolved": isinstance(error, UnresolvedError)}
2297
+ )
2298
+ )
2299
+ return 3 if isinstance(error, UnresolvedError) else 4
2300
+
2301
+
2302
+ if __name__ == "__main__":
2303
+ raise SystemExit(main())