ksaa 2025.7.20.0__py3-none-any.whl → 2025.7.27.1__py3-none-any.whl

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 (155) hide show
  1. kotonebot/backend/bot.py +60 -12
  2. kotonebot/backend/context/task_action.py +9 -46
  3. kotonebot/backend/dispatch.py +1 -104
  4. kotonebot/backend/flow_controller.py +3 -1
  5. kotonebot/errors.py +37 -2
  6. kotonebot/interop/win/message_box.py +314 -0
  7. kotonebot/interop/win/task_dialog.py +469 -0
  8. kotonebot/kaa/config/produce.py +8 -6
  9. kotonebot/kaa/config/schema.py +2 -0
  10. kotonebot/kaa/errors.py +38 -0
  11. kotonebot/kaa/main/gr.py +22 -5
  12. kotonebot/kaa/metadata.py +18 -0
  13. kotonebot/kaa/resources/__pycache__/__init__.cpython-310.pyc +0 -0
  14. kotonebot/kaa/resources/game.db +0 -0
  15. kotonebot/kaa/resources/game_ver.txt +0 -0
  16. kotonebot/kaa/tasks/R.py +126 -126
  17. kotonebot/kaa/tasks/daily/contest.py +39 -8
  18. kotonebot/kaa/tasks/daily/purchase.py +0 -1
  19. kotonebot/kaa/tasks/end_game.py +4 -3
  20. kotonebot/kaa/tasks/produce/in_purodyuusu.py +30 -29
  21. kotonebot/kaa/tasks/produce/produce.py +2 -1
  22. kotonebot/kaa/tasks/start_game.py +2 -0
  23. kotonebot/ui/user.py +43 -13
  24. {ksaa-2025.7.20.0.dist-info → ksaa-2025.7.27.1.dist-info}/METADATA +2 -1
  25. {ksaa-2025.7.20.0.dist-info → ksaa-2025.7.27.1.dist-info}/RECORD +155 -152
  26. /kotonebot/kaa/sprites/{d56feb26-d560-423f-b5f8-dc06f7a3c8a1.png → 03821ecf-fdd2-4e89-8249-fc7288ac79be.png} +0 -0
  27. /kotonebot/kaa/sprites/{0554264f-0474-44d0-9209-8135d8840c53.png → 04c9d1c8-09b9-402d-b688-796253fdaf0c.png} +0 -0
  28. /kotonebot/kaa/sprites/{94021aa4-fb87-41e7-920a-988a360f8321.png → 05903cc9-9f7a-43ac-88e4-988a68311e05.png} +0 -0
  29. /kotonebot/kaa/sprites/{5aef61f9-d616-42f2-ae8d-5c5a033231d3.png → 093c3fb8-036e-4cf4-917b-d70cabebf571.png} +0 -0
  30. /kotonebot/kaa/sprites/{562f176f-af1e-4352-aeed-62e362177f9f.png → 0f986eac-1e3c-48ed-9850-cae529b30503.png} +0 -0
  31. /kotonebot/kaa/sprites/{e281792b-000b-4048-afb7-e8bb0dbd88b3.png → 116bf963-ad4a-401a-91f7-e3a56a4848b9.png} +0 -0
  32. /kotonebot/kaa/sprites/{9e0492b7-3b66-48a2-b589-91e7fd16106d.png → 14283368-d85d-458a-8f2c-b112bd02256e.png} +0 -0
  33. /kotonebot/kaa/sprites/{401966c8-2095-4eef-b92a-764122de02d9.png → 15ee94ce-1930-4eff-9ce2-0ebe947aaa05.png} +0 -0
  34. /kotonebot/kaa/sprites/{d54fc8f5-e50d-45dd-b123-92414f93488c.png → 1b2a0de3-34cc-42b2-8af3-bfeb8d0d679c.png} +0 -0
  35. /kotonebot/kaa/sprites/{b25627d6-3352-4fe8-93c2-b653efe104d4.png → 1c14e581-b664-488c-9d29-f5228ee6d328.png} +0 -0
  36. /kotonebot/kaa/sprites/{ddae5592-adc3-4c36-bfdd-6c6d91823296.png → 1d457687-ff10-41b0-95e1-6c1b3868b2a0.png} +0 -0
  37. /kotonebot/kaa/sprites/{0002785c-3caa-4c8f-8d47-f29aee04a588.png → 1f5f5454-eb1c-45c3-8467-80c224d528e6.png} +0 -0
  38. /kotonebot/kaa/sprites/{dd699396-5500-43ad-8470-cf7a8ba013ec.png → 252f1cd3-8e09-4b34-b5ba-47b1137a19c1.png} +0 -0
  39. /kotonebot/kaa/sprites/{fda67b44-d46d-4789-89a3-0786c60987ab.png → 2585cb7b-af94-46ac-a31d-f50bd09f40a6.png} +0 -0
  40. /kotonebot/kaa/sprites/{05a23a4a-9b93-4fbd-b4e9-15a7c4a91fdc.png → 28e5138d-bcd4-40d2-9e2f-0c845004b8ae.png} +0 -0
  41. /kotonebot/kaa/sprites/{c5774fb4-be11-4b28-8f58-299ae8872cc1.png → 29fc852e-4c61-416d-80ff-f28c5a64abc1.png} +0 -0
  42. /kotonebot/kaa/sprites/{9449ff36-7adb-42d5-b89d-bf9147d62811.png → 2a539cb4-827f-449b-9780-14a94678948b.png} +0 -0
  43. /kotonebot/kaa/sprites/{bcc433e0-8a4e-455f-b625-4583cea19c1c.png → 2c2ff5ed-3b1a-4dcc-89a9-9457908cb184.png} +0 -0
  44. /kotonebot/kaa/sprites/{fd77088d-652a-472e-9f84-dcc83d40a6bf.png → 2d902d81-5500-4265-9867-c5c4cac573d7.png} +0 -0
  45. /kotonebot/kaa/sprites/{9d80c1ef-0f42-4622-ab9a-bfcc077dace6.png → 31122061-ea7a-419e-8072-8552013a8255.png} +0 -0
  46. /kotonebot/kaa/sprites/{d14633f5-9682-4b59-a4ef-e92a2d26d86b.png → 31745cd7-226e-4e11-b96d-2e202a7097e7.png} +0 -0
  47. /kotonebot/kaa/sprites/{83f9e9a0-54dd-4601-8e54-3091c2892e67.png → 34dcd41c-b800-43b4-b24f-c569bae59db2.png} +0 -0
  48. /kotonebot/kaa/sprites/{d627ba81-9c86-4b53-9ab9-86c8748d8daa.png → 360bcb7f-c710-49d5-9942-2812ed03a447.png} +0 -0
  49. /kotonebot/kaa/sprites/{0aa4472c-b533-46cc-a072-9d165d955424.png → 36e02aa6-f858-4248-b39e-e16686d6baf1.png} +0 -0
  50. /kotonebot/kaa/sprites/{d83f2631-b9d8-4fd6-ab1c-50b0a013f3f0.png → 39882ba6-c9d9-4742-b92d-206781c5f60e.png} +0 -0
  51. /kotonebot/kaa/sprites/{0e29489c-6728-46cd-bd13-2b9d9e74b2da.png → 3ace2c73-cf00-4706-9aac-1a0229b1b3f5.png} +0 -0
  52. /kotonebot/kaa/sprites/{04feeecc-a607-402d-bbc4-a71af87c7fc2.png → 3bd19f01-57f8-4f8b-98b7-b5dd0779f77d.png} +0 -0
  53. /kotonebot/kaa/sprites/{a009c9de-029e-4999-b728-e6877374325a.png → 3cd5382a-a679-4f06-ab83-6328a943148d.png} +0 -0
  54. /kotonebot/kaa/sprites/{f16d6f1e-b9ff-4cff-aed3-dd150caf8f07.png → 3d7d1e3f-29c7-431d-8621-3f31b8880492.png} +0 -0
  55. /kotonebot/kaa/sprites/{681157d7-b37f-442f-b784-86fa9029ecdb.png → 3e558d01-1d7d-4ed3-9200-738252539dc1.png} +0 -0
  56. /kotonebot/kaa/sprites/{8a2938ad-5657-4f66-8447-4bc7fa45b857.png → 3ea31c2c-1421-421c-a7fa-7994c06e4bca.png} +0 -0
  57. /kotonebot/kaa/sprites/{39f88061-a997-4a8a-b09e-4a2425f4a83a.png → 432df4be-4970-4ac0-8465-a698bce6fe65.png} +0 -0
  58. /kotonebot/kaa/sprites/{4622e955-7bb1-450d-a776-01543540fde3.png → 464c3d3a-c772-4f85-94d5-970f46c8d213.png} +0 -0
  59. /kotonebot/kaa/sprites/{1609d037-a3fc-485b-96c6-cf1790434c01.png → 47f4b0a5-5792-4e82-b597-d58ea0b1f494.png} +0 -0
  60. /kotonebot/kaa/sprites/{143db8eb-fdde-4de0-a946-a14123b9262e.png → 4c444aaf-a2d1-44f1-aacc-b737f262a746.png} +0 -0
  61. /kotonebot/kaa/sprites/{9b696383-10dd-4a35-8546-1ccdb8891373.png → 4ced1b5f-bbd2-4230-8555-233d082f4d05.png} +0 -0
  62. /kotonebot/kaa/sprites/{7f4accdd-bd72-45e6-8469-692e27986486.png → 4de619fd-ed06-4210-b1f0-11556deb4dd9.png} +0 -0
  63. /kotonebot/kaa/sprites/{9a9d9398-15df-46ea-a247-04ba01f61603.png → 5033ca17-1327-4554-b939-968b8a78f10a.png} +0 -0
  64. /kotonebot/kaa/sprites/{bc01675d-453c-43f2-9075-f9567c8aa6f9.png → 52ae79ea-f4a4-4c19-9fe8-327f285ace1e.png} +0 -0
  65. /kotonebot/kaa/sprites/{71d6a37d-45df-456f-b673-d1e8b35ee619.png → 566e641a-a364-415c-a17b-2db7862f2714.png} +0 -0
  66. /kotonebot/kaa/sprites/{e89c23b0-ca58-49d1-b439-967a4a4a431d.png → 5a0d6f90-3758-4baa-94fc-a4a412284628.png} +0 -0
  67. /kotonebot/kaa/sprites/{b66e13a1-636c-4478-9d72-7d200ff670a9.png → 5ba7d61f-282d-4ad0-881a-842c26e7f66c.png} +0 -0
  68. /kotonebot/kaa/sprites/{3645c21a-acd8-4ec4-a286-d9031736342c.png → 5f3937f7-a5de-4a11-bcf9-da586596bf47.png} +0 -0
  69. /kotonebot/kaa/sprites/{6cacdb8f-2ea3-4e3c-a124-b957b75ea427.png → 60cfef80-cd08-4205-8088-8d0b22a59b5a.png} +0 -0
  70. /kotonebot/kaa/sprites/{49ccf947-13a5-4839-8f85-d0fe40094e77.png → 61f56d51-8d30-4aed-857a-8eff6fab27c1.png} +0 -0
  71. /kotonebot/kaa/sprites/{dcc214f3-9707-4a2c-aaff-3834e6f12f0b.png → 6468ab50-2d25-4b18-b555-2a56397968b0.png} +0 -0
  72. /kotonebot/kaa/sprites/{04425af8-ba28-407d-ad18-8c3a2483025d.png → 6597b7fd-3c5b-442f-a327-d18b555de544.png} +0 -0
  73. /kotonebot/kaa/sprites/{38c0ed08-5af3-4fca-a37f-27d66fd35a4c.png → 661d0e8d-379d-401d-9f29-147e70123adf.png} +0 -0
  74. /kotonebot/kaa/sprites/{f543861e-c3d5-4bc9-a677-47f9e86918ea.png → 66c7e6df-5c90-4b3a-9b51-78cff1357ed7.png} +0 -0
  75. /kotonebot/kaa/sprites/{0e4b4481-6805-4a1b-a3d8-913681968662.png → 6a033af8-222c-459a-9ab9-a9a69b27822d.png} +0 -0
  76. /kotonebot/kaa/sprites/{9dbc5d76-8c6a-4638-b0c2-eba79542ec58.png → 6c151fbe-7cf9-4629-b47a-da7be835bb4b.png} +0 -0
  77. /kotonebot/kaa/sprites/{6e59d072-06f8-488f-a453-8ba60a05d691.png → 6d225f8d-efc0-42a5-93af-7b81e24377c5.png} +0 -0
  78. /kotonebot/kaa/sprites/{e36ec591-8bf5-4deb-9f28-3977576de931.png → 749bd918-8dfb-4393-bf91-b39e285f1d75.png} +0 -0
  79. /kotonebot/kaa/sprites/{a3384f38-334c-440a-ab06-405bad293bab.png → 75cad2af-b8c5-4f5f-8398-acd90eb4348e.png} +0 -0
  80. /kotonebot/kaa/sprites/{966bcfd4-fefc-4704-907d-45bc6098d3f4.png → 76acc2b6-6649-4b1a-bd52-18ab9a2341d0.png} +0 -0
  81. /kotonebot/kaa/sprites/{2cff833f-10bd-478c-8760-99162c71e9e3.png → 7a8c4af3-2ac1-4295-b844-350ad00f2c50.png} +0 -0
  82. /kotonebot/kaa/sprites/{610ea09a-d623-428f-ac97-1b51dc5e9202.png → 7b552e56-0065-45d8-a0dc-bfe3be62b91f.png} +0 -0
  83. /kotonebot/kaa/sprites/{d6314592-b8a4-4025-9875-b135bf986cf7.png → 7c7cbe5a-37f0-4cf3-8376-4ceeb7a662b0.png} +0 -0
  84. /kotonebot/kaa/sprites/{20733b9b-1df7-42af-ab55-3364e8623602.png → 7dcc9134-9e5f-433b-ae5c-7530484f3f5f.png} +0 -0
  85. /kotonebot/kaa/sprites/{c3562fef-44f7-43d2-a4e6-e7ee21f8bdc5.png → 7dfdefa7-d95f-4348-9e0b-640ed17e138f.png} +0 -0
  86. /kotonebot/kaa/sprites/{a4553bb1-27b9-47c4-8f51-1cff2129df8e.png → 7e4a2554-c05b-458f-b31f-ac6930e8078e.png} +0 -0
  87. /kotonebot/kaa/sprites/{1bb92c94-af17-492e-9d22-393c12b7f346.png → 7e614cff-b492-4c4d-bbfe-0853ff65fcec.png} +0 -0
  88. /kotonebot/kaa/sprites/{87c7532f-2394-403e-a6d8-7a216043ec13.png → 7fcc8f4c-9d06-4747-8c1e-aaba3a61cc0e.png} +0 -0
  89. /kotonebot/kaa/sprites/{e075c8cb-7eef-47cf-b9fe-9e3d1bd98e85.png → 80c6d473-1eb2-4d65-8e8d-8f267ab61cd9.png} +0 -0
  90. /kotonebot/kaa/sprites/{40f04ad0-44c0-4913-89aa-bc466bfd6ace.png → 81fec353-ad18-4223-9ea3-8d128a4a3e77.png} +0 -0
  91. /kotonebot/kaa/sprites/{f0952cb2-dadb-4d9a-933e-cabcbf8850fb.png → 88e4e3c6-3f6b-4192-83c7-4b20a51ad53a.png} +0 -0
  92. /kotonebot/kaa/sprites/{79226566-26e2-4c2f-8f6a-4e4deb9fa9ea.png → 8938249c-94d3-4f20-8013-85d481a54d87.png} +0 -0
  93. /kotonebot/kaa/sprites/{1737a9e0-f8c4-416e-bbad-cb97a658ae9a.png → 8cbbfa8e-17aa-42e7-92f7-319a02c8f7fa.png} +0 -0
  94. /kotonebot/kaa/sprites/{8e0964c4-6e34-43cb-a333-d60bceae7f11.png → 8ed3eab8-779b-4b66-bc24-06b0b1dfac18.png} +0 -0
  95. /kotonebot/kaa/sprites/{3e34e821-ae69-49aa-9d04-bc34b3037cd5.png → 967b207a-79bb-479a-b50e-b2a04cf7ed54.png} +0 -0
  96. /kotonebot/kaa/sprites/{a514ce10-bff1-4aa0-9625-bf560dcb8be5.png → 96b12d02-c634-4e9c-a465-7ee61d5fc0bd.png} +0 -0
  97. /kotonebot/kaa/sprites/{2dab2877-c6c3-45d9-849f-fb2d79b7b74e.png → 9a0c8f11-33f0-4c53-a911-556f3481d952.png} +0 -0
  98. /kotonebot/kaa/sprites/{67f00dd1-86c9-4a49-a37c-87879171a46a.png → 9b439501-e57d-4912-9f57-67c4534060f7.png} +0 -0
  99. /kotonebot/kaa/sprites/{a77c1724-eb8f-4a1a-8997-516deb75ae78.png → 9f2a6935-f462-4726-b56e-8cf23aae3982.png} +0 -0
  100. /kotonebot/kaa/sprites/{b6f5243b-cfb4-42d2-b4eb-2fd1a9d33ab7.png → a148b768-8c8d-4fee-b29f-11d73240a3d0.png} +0 -0
  101. /kotonebot/kaa/sprites/{c577c19e-aa5d-4670-b44c-1c0b3d72451a.png → a1791427-52af-4d1e-8e95-e0533cb66d3c.png} +0 -0
  102. /kotonebot/kaa/sprites/{25f18ff9-dbae-4aed-87b4-c05ca6c4ebf4.png → a2d9b907-f68e-47c7-8aa6-31c07c272d94.png} +0 -0
  103. /kotonebot/kaa/sprites/{10a329df-2515-4551-a130-07e86058abdf.png → a3d5b052-526f-45ef-a2ed-5bba8ca9e4b1.png} +0 -0
  104. /kotonebot/kaa/sprites/{6ac4a3b5-66d2-4429-8cd1-945fbb48280c.png → a66625f6-f80c-48e4-a344-e48036085e2b.png} +0 -0
  105. /kotonebot/kaa/sprites/{1f9f101b-2647-4d14-931e-7a8307495475.png → a6bd2250-81b5-4f54-b6d9-bf9a5a4876d1.png} +0 -0
  106. /kotonebot/kaa/sprites/{a5d3efa4-ec3e-4637-835a-147af973bbf8.png → a7e31af5-a896-47bb-af4b-e71936ac6334.png} +0 -0
  107. /kotonebot/kaa/sprites/{64298c97-baac-48b9-be7d-cb14091aa3cb.png → aab26578-b548-41e5-8996-40ef821ca041.png} +0 -0
  108. /kotonebot/kaa/sprites/{9169bf8e-5907-42e5-b102-47da3bf9a0b1.png → ac0b1f47-ce60-479a-9c5d-d8ced42ec0e0.png} +0 -0
  109. /kotonebot/kaa/sprites/{12151e09-e5f1-4b1d-a211-63cb300cb082.png → acff3d83-f570-4c65-9bb3-db69cd525262.png} +0 -0
  110. /kotonebot/kaa/sprites/{88945ecf-9ac5-46dc-8af6-b21dbfded665.png → ad9cc197-c83d-4d39-b187-7105cde60ef5.png} +0 -0
  111. /kotonebot/kaa/sprites/{f2d8a534-8afd-475c-ac20-738c7efffc90.png → adc38fcc-84d2-4f7c-846d-4fe96dd5d08a.png} +0 -0
  112. /kotonebot/kaa/sprites/{10d9a788-24a2-42e1-9284-78f507986606.png → b5a58c56-3f09-47e5-ab61-57bab752e735.png} +0 -0
  113. /kotonebot/kaa/sprites/{3e613561-8dbd-4094-9889-53f08541a716.png → b92c4308-3778-47aa-8a0b-222d32721beb.png} +0 -0
  114. /kotonebot/kaa/sprites/{cab0b1ff-b40a-42a8-b799-75e309b2dee3.png → bba3cd68-3023-4a7b-9fe9-36ec7adbfc89.png} +0 -0
  115. /kotonebot/kaa/sprites/{f217d7cf-acf5-44eb-9f99-025bbcaea866.png → bd04472b-eeeb-4ad7-b385-8347b7053887.png} +0 -0
  116. /kotonebot/kaa/sprites/{8fb17c7f-778d-4cd5-8d2f-dbf21d264297.png → c157661d-de06-4e34-bc3b-7d79c987e26d.png} +0 -0
  117. /kotonebot/kaa/sprites/{89d3c0a6-266e-486e-998d-ecd0d2536814.png → c2e3d6ac-00b6-4d2a-a30b-52a1190f5f05.png} +0 -0
  118. /kotonebot/kaa/sprites/{df9d09c3-8f15-4caf-bb21-f69644fb4705.png → c370b930-9750-4782-9564-5ce4cd609bdd.png} +0 -0
  119. /kotonebot/kaa/sprites/{12d0271c-1a86-4d2c-b379-b7df847fe20b.png → c84eada8-ff68-4d73-802b-6de88e73ec6d.png} +0 -0
  120. /kotonebot/kaa/sprites/{97a543a8-a859-4a1e-8e33-602f600db389.png → c8f444cc-e809-44c2-86a3-3cbb5bcd0356.png} +0 -0
  121. /kotonebot/kaa/sprites/{41f0e90a-a352-450c-a788-0303d038227a.png → d0881e29-6da6-4823-b65c-eefa9f9f2208.png} +0 -0
  122. /kotonebot/kaa/sprites/{fef40be1-5b75-4023-9977-df46cd211a86.png → d0ad5222-0ee0-412e-819f-3217f9fd854b.png} +0 -0
  123. /kotonebot/kaa/sprites/{e04331fe-d62e-4f77-953d-78515ee5686e.png → d32f8851-4fd2-4484-8ae8-66a375a43f3d.png} +0 -0
  124. /kotonebot/kaa/sprites/{5d3b3a20-89bb-4cf2-9973-25581c32e91c.png → d5a9d7f7-a065-4ff3-ae4c-b027f348ef54.png} +0 -0
  125. /kotonebot/kaa/sprites/{b169172d-8ce2-432a-bed6-1dfc30bcc95c.png → d6235144-ce78-4884-88b4-d1a12b76155f.png} +0 -0
  126. /kotonebot/kaa/sprites/{0a4c6cbe-f42e-4301-9c1a-101fc33421d2.png → d77a936b-c0ae-4dbd-8b44-82288a0957d6.png} +0 -0
  127. /kotonebot/kaa/sprites/{15fe6944-396c-467b-80db-476bbdf65a80.png → d94ce829-a7ab-44aa-bc0c-a4801b650088.png} +0 -0
  128. /kotonebot/kaa/sprites/{92a42da1-d8d2-4233-b6d0-5997a72f3d03.png → dc64e856-2f31-48b1-b17d-32b499f819ce.png} +0 -0
  129. /kotonebot/kaa/sprites/{3fc47270-febf-492e-b8fc-0a9793bc0d56.png → dd5ffd48-2ab0-4795-8193-8a8310101574.png} +0 -0
  130. /kotonebot/kaa/sprites/{6582463d-b4fa-40a1-b771-664c7f71fe9c.png → ddc8f913-e9ae-46dc-a91a-d3ee79e9f32d.png} +0 -0
  131. /kotonebot/kaa/sprites/{1aed664e-ceb3-4a1d-a338-df08dc8ebbd3.png → e049018e-9d2b-4537-add1-e902cf8ac69a.png} +0 -0
  132. /kotonebot/kaa/sprites/{2cea06ca-99f6-4bc5-8dd0-2bba80b07b17.png → e25468f5-929a-4a49-a2e0-4527075353b5.png} +0 -0
  133. /kotonebot/kaa/sprites/{32907971-0e98-4adc-91b8-ac0308c11c3c.png → e54b7482-a348-4252-a373-2ee69b3805b5.png} +0 -0
  134. /kotonebot/kaa/sprites/{f58c3a84-60ea-415b-ac63-4b534dc8cb6c.png → e62afa2c-1c5b-426e-8ff1-ea51f75d0f20.png} +0 -0
  135. /kotonebot/kaa/sprites/{731ed76d-6d6c-48b9-82c3-045cc1ecc419.png → e7a0ea00-2a72-4d74-8664-53726e3e1078.png} +0 -0
  136. /kotonebot/kaa/sprites/{487ae483-2787-4982-93b0-4847665683e9.png → eb67d908-13f8-4cef-9a86-9770e342ab77.png} +0 -0
  137. /kotonebot/kaa/sprites/{3a595ec9-d813-4c09-b8b8-be8f5da88faa.png → ebb662bb-62b4-404c-bb8f-4a7d5feccaa8.png} +0 -0
  138. /kotonebot/kaa/sprites/{c92a2935-cf41-4f56-911a-bc40f122cbf3.png → ee8a6029-63b3-4c13-bdc5-9bd8546d3316.png} +0 -0
  139. /kotonebot/kaa/sprites/{d81b7022-5c81-4533-b949-7e9d75a5b8b4.png → eea2af85-94b2-4c41-8f51-393059dcc43c.png} +0 -0
  140. /kotonebot/kaa/sprites/{f5727018-9a23-40de-840e-610d6e5dfa9d.png → eec4d7d6-3084-4bab-99c1-10e3a9459393.png} +0 -0
  141. /kotonebot/kaa/sprites/{be83e205-8ec5-452f-b42b-b98156516aa8.png → efb31647-3760-4b76-8b5d-ec4b5fb7a975.png} +0 -0
  142. /kotonebot/kaa/sprites/{951ae4be-40f3-4ccc-8578-77aca7f25eef.png → f03739ee-31e1-40ca-9aaf-6c0447d426a4.png} +0 -0
  143. /kotonebot/kaa/sprites/{9dfa46c9-54ec-4dd7-8f2e-e1e66c1206f1.png → f08044bf-8a33-4d6b-8791-94470678efa6.png} +0 -0
  144. /kotonebot/kaa/sprites/{183df82f-acea-4d40-87a8-18fc8ddab6d0.png → f23cb531-18b5-4852-bb11-56dc621e56cc.png} +0 -0
  145. /kotonebot/kaa/sprites/{377857a9-c37f-4a90-afa9-00c4ff7b24ae.png → f7a4208f-0373-4f26-907f-84c3f2b810fc.png} +0 -0
  146. /kotonebot/kaa/sprites/{2bb9dbf7-6cb2-426a-a35c-7228a1320220.png → f88f9f3b-e0e7-498c-ad1c-e92a719164f3.png} +0 -0
  147. /kotonebot/kaa/sprites/{70671b9e-9ebb-4dee-bc5a-dbcb70364adf.png → f93c7a24-157d-43ef-adcc-3873d313c6d7.png} +0 -0
  148. /kotonebot/kaa/sprites/{63cd694d-343e-468d-a53f-360c97f71ee6.png → f957fbb8-ba30-47c0-97b8-ff531d6e3831.png} +0 -0
  149. /kotonebot/kaa/sprites/{dcc2da94-2c9d-4248-bce5-731651e391ae.png → fbbf4921-ece5-4dc0-875d-8f7182596d4f.png} +0 -0
  150. /kotonebot/kaa/sprites/{131fb7e1-6eb9-4722-9943-76ff05c5baee.png → ff361c63-3f3d-48df-a26f-7698bd459219.png} +0 -0
  151. /kotonebot/kaa/sprites/{e4a92c92-0974-40e0-b488-16ea7a4c1a29.png → ff5a0417-229f-41bd-8121-708b08417114.png} +0 -0
  152. {ksaa-2025.7.20.0.dist-info → ksaa-2025.7.27.1.dist-info}/WHEEL +0 -0
  153. {ksaa-2025.7.20.0.dist-info → ksaa-2025.7.27.1.dist-info}/entry_points.txt +0 -0
  154. {ksaa-2025.7.20.0.dist-info → ksaa-2025.7.27.1.dist-info}/licenses/LICENSE +0 -0
  155. {ksaa-2025.7.20.0.dist-info → ksaa-2025.7.27.1.dist-info}/top_level.txt +0 -0
kotonebot/backend/bot.py CHANGED
@@ -12,6 +12,15 @@ from kotonebot.client import Device
12
12
  from kotonebot.client.host.protocol import Instance
13
13
  from kotonebot.backend.context import init_context, vars
14
14
  from kotonebot.backend.context import task_registry, action_registry, Task, Action
15
+ from kotonebot.errors import StopCurrentTask, UserFriendlyError
16
+ from kotonebot.interop.win.task_dialog import TaskDialog
17
+
18
+
19
+ @dataclass
20
+ class PostTaskContext:
21
+ has_error: bool
22
+ exception: Exception | None
23
+
15
24
 
16
25
  log_stream = io.StringIO()
17
26
  stream_handler = logging.StreamHandler(log_stream)
@@ -19,10 +28,11 @@ stream_handler.setFormatter(logging.Formatter('[%(asctime)s] [%(levelname)s] [%(
19
28
  logging.getLogger('kotonebot').addHandler(stream_handler)
20
29
  logger = logging.getLogger(__name__)
21
30
 
31
+ TaskStatusValue = Literal['pending', 'running', 'finished', 'error', 'cancelled', 'stopped']
22
32
  @dataclass
23
33
  class TaskStatus:
24
34
  task: Task
25
- status: Literal['pending', 'running', 'finished', 'error', 'cancelled']
35
+ status: TaskStatusValue
26
36
 
27
37
  @dataclass
28
38
  class RunStatus:
@@ -73,7 +83,7 @@ class Event(Generic[Params, Return]):
73
83
  class KotoneBotEvents:
74
84
  def __init__(self):
75
85
  self.task_status_changed = Event[
76
- [Task, Literal['pending', 'running', 'finished', 'error', 'cancelled']], None
86
+ [Task, TaskStatusValue], None
77
87
  ]()
78
88
  self.task_error = Event[
79
89
  [Task, Exception], None
@@ -171,42 +181,80 @@ class KotoneBot:
171
181
  self._on_after_init_context()
172
182
  vars.flow.clear_interrupt()
173
183
 
184
+ pre_tasks = [task for task in tasks if task.run_at == 'pre']
185
+ regular_tasks = [task for task in tasks if task.run_at == 'regular']
186
+ post_tasks = [task for task in tasks if task.run_at == 'post']
187
+
174
188
  if by_priority:
175
- tasks = sorted(tasks, key=lambda x: x.priority, reverse=True)
176
- for task in tasks:
189
+ pre_tasks = sorted(pre_tasks, key=lambda x: x.priority, reverse=True)
190
+ regular_tasks = sorted(regular_tasks, key=lambda x: x.priority, reverse=True)
191
+ post_tasks = sorted(post_tasks, key=lambda x: x.priority, reverse=True)
192
+
193
+ all_tasks = pre_tasks + regular_tasks + post_tasks
194
+ for task in all_tasks:
177
195
  self.events.task_status_changed.trigger(task, 'pending')
178
196
 
179
- for task in tasks:
197
+ has_error = False
198
+ exception: Exception | None = None
199
+
200
+ for task in all_tasks:
180
201
  logger.info(f'Task started: {task.name}')
181
202
  self.events.task_status_changed.trigger(task, 'running')
182
203
 
183
204
  if self.debug:
184
- task.func()
205
+ if task.run_at == 'post':
206
+ task.func(PostTaskContext(has_error, exception))
207
+ else:
208
+ task.func()
185
209
  else:
186
210
  try:
187
- task.func()
211
+ if task.run_at == 'post':
212
+ task.func(PostTaskContext(has_error, exception))
213
+ else:
214
+ task.func()
188
215
  self.events.task_status_changed.trigger(task, 'finished')
216
+ except StopCurrentTask:
217
+ logger.info(f'Task skipped/stopped: {task.name}')
218
+ self.events.task_status_changed.trigger(task, 'stopped')
189
219
  # 用户中止
190
220
  except KeyboardInterrupt as e:
191
221
  logger.exception('Keyboard interrupt detected.')
192
- for task1 in tasks[tasks.index(task):]:
222
+ for task1 in all_tasks[all_tasks.index(task):]:
193
223
  self.events.task_status_changed.trigger(task1, 'cancelled')
194
224
  vars.flow.clear_interrupt()
195
225
  break
226
+ # 用户可以自行处理的错误
227
+ except UserFriendlyError as e:
228
+ logger.error(f'Task failed: {task.name}')
229
+ logger.exception(f'Error: ')
230
+ has_error = True
231
+ exception = e
232
+ dialog = TaskDialog(
233
+ title='琴音小助手',
234
+ common_buttons=0,
235
+ main_instruction='任务执行失败',
236
+ content=e.message,
237
+ custom_buttons=e.action_buttons,
238
+ main_icon='error'
239
+ )
240
+ result_custom, _, _ = dialog.show()
241
+ e.invoke(result_custom)
196
242
  # 其他错误
197
243
  except Exception as e:
198
244
  logger.error(f'Task failed: {task.name}')
199
245
  logger.exception(f'Error: ')
246
+ has_error = True
247
+ exception = e
200
248
  report_path = None
201
249
  if self.auto_save_error_report:
202
250
  raise NotImplementedError
203
251
  self.events.task_status_changed.trigger(task, 'error')
204
252
  if not self.resume_on_error:
205
- for task1 in tasks[tasks.index(task)+1:]:
253
+ for task1 in all_tasks[all_tasks.index(task)+1:]:
206
254
  self.events.task_status_changed.trigger(task1, 'cancelled')
207
255
  break
208
- logger.info(f'Task finished: {task.name}')
209
- logger.info('All tasks finished.')
256
+ logger.info(f'Task ended: {task.name}')
257
+ logger.info('All tasks ended.')
210
258
  self.events.finished.trigger()
211
259
 
212
260
  def run_all(self) -> None:
@@ -228,7 +276,7 @@ class KotoneBot:
228
276
  self.events.finished -= _on_finished
229
277
  self.events.task_status_changed -= _on_task_status_changed
230
278
 
231
- def _on_task_status_changed(task: Task, status: Literal['pending', 'running', 'finished', 'error', 'cancelled']):
279
+ def _on_task_status_changed(task: Task, status: TaskStatusValue):
232
280
  def _find(task: Task) -> TaskStatus:
233
281
  for task_status in run_status.tasks:
234
282
  if task_status.task == task:
@@ -1,19 +1,18 @@
1
1
  import logging
2
- from typing import Callable, ParamSpec, TypeVar, overload, Concatenate, Literal
2
+ from typing import Callable, ParamSpec, TypeVar, overload, Literal
3
3
  from dataclasses import dataclass
4
- from typing_extensions import deprecated
5
4
 
6
- import cv2
7
- from cv2.typing import MatLike
8
5
 
9
6
  from .context import ContextStackVars, ScreenshotMode
10
- from ..dispatch import dispatcher as dispatcher_decorator, DispatcherContext
11
7
  from ...errors import TaskNotFoundError
12
8
 
13
9
  P = ParamSpec('P')
14
10
  R = TypeVar('R')
15
11
  logger = logging.getLogger(__name__)
16
12
 
13
+ TaskRunAtType = Literal['pre', 'post', 'manual', 'regular'] | str
14
+
15
+
17
16
  @dataclass
18
17
  class Task:
19
18
  name: str
@@ -24,6 +23,8 @@ class Task:
24
23
  """
25
24
  任务优先级,数字越大优先级越高。
26
25
  """
26
+ run_at: TaskRunAtType = 'regular'
27
+
27
28
 
28
29
  @dataclass
29
30
  class Action:
@@ -51,6 +52,7 @@ def task(
51
52
  pass_through: bool = False,
52
53
  priority: int = 0,
53
54
  screenshot_mode: ScreenshotMode = 'auto',
55
+ run_at: TaskRunAtType = 'regular'
54
56
  ):
55
57
  """
56
58
  `task` 装饰器,用于标记一个函数为任务函数。
@@ -62,6 +64,7 @@ def task(
62
64
  默认情况下, @task 装饰器会包裹任务函数,跟踪其执行情况。
63
65
  如果不想跟踪,则设置此参数为 False。
64
66
  :param priority: 任务优先级,数字越大优先级越高。
67
+ :param run_at: 任务运行时间。
65
68
  """
66
69
  # 设置 ID
67
70
  # 获取 caller 信息
@@ -70,7 +73,7 @@ def task(
70
73
  description = description or func.__doc__ or ''
71
74
  # TODO: task_id 冲突检测
72
75
  task_id = task_id or func.__name__
73
- task = Task(name, task_id, description, _placeholder, priority)
76
+ task = Task(name, task_id, description, _placeholder, priority, run_at)
74
77
  task_registry[name] = task
75
78
  logger.debug(f'Task "{name}" registered.')
76
79
  if pass_through:
@@ -98,7 +101,6 @@ def action(
98
101
  pass_through: bool = False,
99
102
  priority: int = 0,
100
103
  screenshot_mode: ScreenshotMode | None = None,
101
- dispatcher: Literal[False] = False,
102
104
  ) -> Callable[[Callable[P, R]], Callable[P, R]]:
103
105
  """
104
106
  `action` 装饰器,用于标记一个函数为动作函数。
@@ -110,38 +112,6 @@ def action(
110
112
  如果不想跟踪,则设置此参数为 False。
111
113
  :param priority: 动作优先级,数字越大优先级越高。
112
114
  :param screenshot_mode: 截图模式。
113
- :param dispatcher:
114
- 是否为分发器模式。默认为假。
115
- 如果使用分发器,则函数的第一个参数必须为 `ctx: DispatcherContext`。
116
- """
117
- ...
118
-
119
- @overload
120
- @deprecated('使用普通 while 循环代替')
121
- def action(
122
- name: str,
123
- *,
124
- description: str|None = None,
125
- pass_through: bool = False,
126
- priority: int = 0,
127
- screenshot_mode: ScreenshotMode | None = None,
128
- dispatcher: Literal[True, 'fragment'] = True,
129
- ) -> Callable[[Callable[Concatenate[DispatcherContext, P], R]], Callable[P, R]]:
130
- """
131
- `action` 装饰器,用于标记一个函数为动作函数。
132
-
133
- 此重载启用了分发器模式。被装饰函数的第一个参数必须为 `ctx: DispatcherContext`。
134
-
135
- :param name: 动作名称。如果为 None,则使用函数的名称作为名称。
136
- :param description: 动作描述。如果为 None,则使用函数的 docstring 作为描述。
137
- :param pass_through:
138
- 默认情况下, @action 装饰器会包裹动作函数,跟踪其执行情况。
139
- 如果不想跟踪,则设置此参数为 False。
140
- :param priority: 动作优先级,数字越大优先级越高。
141
- :param screenshot_mode: 截图模式,必须为 `'manual' / None`。
142
- :param dispatcher:
143
- 是否为分发器模式。默认为假。
144
- 如果使用分发器,则函数的第一个参数必须为 `ctx: DispatcherContext`。
145
115
  """
146
116
  ...
147
117
 
@@ -176,11 +146,6 @@ def action(*args, **kwargs):
176
146
  pass_through = kwargs.get('pass_through', False)
177
147
  priority = kwargs.get('priority', 0)
178
148
  screenshot_mode = kwargs.get('screenshot_mode', None)
179
- dispatcher = kwargs.get('dispatcher', False)
180
- if dispatcher == True or dispatcher == 'fragment':
181
- if not (screenshot_mode is None or screenshot_mode == 'manual'):
182
- raise ValueError('`screenshot_mode` must be None or "manual" when `dispatcher=True`.')
183
- screenshot_mode = 'manual'
184
149
  def _action_decorator(func: Callable):
185
150
  nonlocal pass_through
186
151
  action = _register(_placeholder, name, description)
@@ -188,8 +153,6 @@ def action(*args, **kwargs):
188
153
  if pass_through:
189
154
  return func
190
155
  else:
191
- if dispatcher:
192
- func = dispatcher_decorator(func, fragment=(dispatcher == 'fragment')) # type: ignore
193
156
  def _wrapper(*args: P.args, **kwargs: P.kwargs):
194
157
  current_callstack.append(action)
195
158
  vars = ContextStackVars.push(screenshot_mode=screenshot_mode)
@@ -1,12 +1,7 @@
1
1
  import time
2
- import uuid
3
2
  import logging
4
- import inspect
5
- from logging import Logger
6
- from types import CodeType
7
3
  from dataclasses import dataclass
8
- from typing import Annotated, Any, Callable, Concatenate, Sequence, TypeVar, ParamSpec, Literal, Protocol, cast
9
- from typing_extensions import deprecated
4
+ from typing import Any, Callable, Literal
10
5
 
11
6
  from dataclasses import dataclass
12
7
 
@@ -16,104 +11,6 @@ from kotonebot.primitives import Rect, is_rect
16
11
  from .core import Image
17
12
 
18
13
  logger = logging.getLogger(__name__)
19
- P = ParamSpec('P')
20
- R = TypeVar('R')
21
- ThenAction = Literal['click', 'log']
22
- DoAction = Literal['click']
23
- # TODO: 需要找个地方统一管理这些属性名
24
- ATTR_DISPATCHER_MARK = '__kb_dispatcher_mark'
25
- ATTR_ORIGINAL_FUNC = '_kb_inner'
26
-
27
-
28
- class DispatchFunc: pass
29
-
30
- wrapper_to_func: dict[Callable, Callable] = {}
31
-
32
- class DispatcherContext:
33
- def __init__(self):
34
- self.finished: bool = False
35
- self._first_run: bool = True
36
-
37
- def finish(self):
38
- """标记已完成 dispatcher 循环。循环将在下次条件检测时退出。"""
39
- self.finished = True
40
-
41
- def expand(self, func: Annotated[Callable[[], Any], DispatchFunc], ignore_finish: bool = True):
42
- """
43
- 调用其他 dispatcher 函数。
44
-
45
- 使用 `expand` 和直接调用的区别是:
46
- * 直接调用会执行 while 循环,直到满足结束条件
47
- * 而使用 `expand` 则只会执行一次。效果类似于将目标函数里的代码直接复制粘贴过来。
48
- """
49
- # 获取原始函数
50
- original_func = func
51
- while not getattr(original_func, ATTR_DISPATCHER_MARK, False):
52
- original_func = getattr(original_func, ATTR_ORIGINAL_FUNC)
53
- original_func = getattr(original_func, ATTR_ORIGINAL_FUNC)
54
-
55
- if not original_func:
56
- raise ValueError(f'{repr(func)} is not a dispatcher function.')
57
- elif not callable(original_func):
58
- raise ValueError(f'{repr(original_func)} is not callable.')
59
- original_func = cast(Callable[[DispatcherContext], Any], original_func)
60
-
61
- old_finished = self.finished
62
- ret = original_func(self)
63
- if ignore_finish:
64
- self.finished = old_finished
65
- return ret
66
-
67
- @property
68
- def beginning(self) -> bool:
69
- """是否为第一次运行"""
70
- return self._first_run
71
-
72
- @property
73
- def finishing(self) -> bool:
74
- """是否即将结束运行"""
75
- return self.finished
76
-
77
- @deprecated('使用 SimpleDispatcher 类或 while 循环替代')
78
- def dispatcher(
79
- func: Callable[Concatenate[DispatcherContext, P], R],
80
- *,
81
- fragment: bool = False
82
- ) -> Annotated[Callable[P, R], DispatchFunc]:
83
- """
84
- 注意:\n
85
- 此装饰器必须在应用 @action/@task 装饰器后再应用,且 `screenshot_mode='manual'` 参数必须设置。
86
- 或者也可以使用 @action/@task 装饰器中的 `dispatcher=True` 参数,
87
- 那么就没有上面两个要求了。
88
-
89
- :param fragment:
90
- 片段模式,默认不启用。
91
- 启用后,被装饰函数将会只执行依次,
92
- 而不会一直循环到 ctx.finish() 被调用。
93
- """
94
- def wrapper(*args: P.args, **kwargs: P.kwargs):
95
- ctx = DispatcherContext()
96
- while not ctx.finished:
97
- from kotonebot import device
98
- device.screenshot()
99
- ret = func(ctx, *args, **kwargs)
100
- ctx._first_run = False
101
- return ret
102
- def fragment_wrapper(*args: P.args, **kwargs: P.kwargs):
103
- ctx = DispatcherContext()
104
- from kotonebot import device
105
- device.screenshot()
106
- return func(ctx, *args, **kwargs)
107
- setattr(wrapper, ATTR_ORIGINAL_FUNC, func)
108
- setattr(fragment_wrapper, ATTR_ORIGINAL_FUNC, func)
109
- setattr(wrapper, ATTR_DISPATCHER_MARK, True)
110
- setattr(fragment_wrapper, ATTR_DISPATCHER_MARK, True)
111
- wrapper_to_func[wrapper] = func
112
- if fragment:
113
- return fragment_wrapper
114
-
115
- else:
116
- return wrapper
117
14
 
118
15
  @dataclass
119
16
  class ClickParams:
@@ -95,7 +95,7 @@ class FlowController:
95
95
  logger.info('Interrupt requested.')
96
96
  self.interrupt_event.set()
97
97
 
98
- def request_pause(self) -> None:
98
+ def request_pause(self, *, wait_resume: bool = False) -> None:
99
99
  """
100
100
  请求暂停任务。
101
101
 
@@ -106,6 +106,8 @@ class FlowController:
106
106
  if not self.paused:
107
107
  logger.info('Pause requested.')
108
108
  self.paused = True
109
+ if wait_resume:
110
+ self.check()
109
111
 
110
112
  def request_resume(self) -> None:
111
113
  """
kotonebot/errors.py CHANGED
@@ -1,9 +1,41 @@
1
+ from typing import Callable
2
+
3
+
1
4
  class KotonebotError(Exception):
2
5
  pass
3
6
 
4
7
  class KotonebotWarning(Warning):
5
8
  pass
6
9
 
10
+ class UserFriendlyError(KotonebotError):
11
+ def __init__(
12
+ self,
13
+ message: str,
14
+ actions: list[tuple[int, str, Callable[[], None]]] = [],
15
+ *args, **kwargs
16
+ ) -> None:
17
+ super().__init__(*args, **kwargs)
18
+ self.message = message
19
+ self.actions = actions or []
20
+
21
+ @property
22
+ def action_buttons(self) -> list[tuple[int, str]]:
23
+ """
24
+ 以 (id: int, btn_text: str) 的形式返回所有按钮定义。
25
+ """
26
+ return [(id, text) for id, text, _ in self.actions]
27
+
28
+ def invoke(self, action_id: int):
29
+ """
30
+ 执行指定 ID 的 action。
31
+ """
32
+ for id, _, func in self.actions:
33
+ if id == action_id:
34
+ func()
35
+ break
36
+ else:
37
+ raise ValueError(f'Action with id {action_id} not found.')
38
+
7
39
  class UnrecoverableError(KotonebotError):
8
40
  pass
9
41
 
@@ -31,7 +63,10 @@ class UnscalableResolutionError(KotonebotError):
31
63
  self.screen_size = screen_size
32
64
  super().__init__(f'Cannot scale to target resolution {target_resolution}. '
33
65
  f'Screen size: {screen_size}')
34
-
66
+
35
67
  class ContextNotInitializedError(KotonebotError):
36
68
  def __init__(self, msg: str = 'Context not initialized'):
37
- super().__init__(msg)
69
+ super().__init__(msg)
70
+
71
+ class StopCurrentTask(KotonebotError):
72
+ pass