@runweave/server-linux-x64 0.1.8 → 0.1.10

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 (357) hide show
  1. package/manifest.json +1494 -161
  2. package/native.tar.gz +0 -0
  3. package/package.json +1 -1
  4. package/payload/.agents/plugins/marketplace.json +20 -0
  5. package/payload/app-server/build-info.json +4 -4
  6. package/payload/app-server/index.cjs +6 -2
  7. package/payload/app-server/index.cjs.map +1 -1
  8. package/payload/backend/activity-sqlite-worker.cjs +2 -0
  9. package/payload/backend/build-info.json +4 -4
  10. package/payload/backend/dev-resources/control.cjs +5 -1
  11. package/payload/backend/index.cjs +466 -295
  12. package/payload/backend/ios-simulators/pool.py +3 -3
  13. package/payload/backend/scheduled-tasks-sqlite-worker.cjs +2 -0
  14. package/payload/frontend/dist/assets/{_baseUniq-vo4uuhMd.js → _baseUniq--CWv8e7O.js} +1 -1
  15. package/payload/frontend/dist/assets/{access-_jCu7Rgu.js → access-BCF23Qto.js} +1 -1
  16. package/payload/frontend/dist/assets/{advanced-CqOhObYj.js → advanced-D8viCLue.js} +1 -1
  17. package/payload/frontend/dist/assets/{appearance-CrrD5gzC.js → appearance-wPVMx-tB.js} +1 -1
  18. package/payload/frontend/dist/assets/{arc-dbfyHSF0.js → arc-BXffHD7A.js} +1 -1
  19. package/payload/frontend/dist/assets/{architectureDiagram-Q4EWVU46-CntSCAsO.js → architectureDiagram-Q4EWVU46-BXHN9QCj.js} +1 -1
  20. package/payload/frontend/dist/assets/{blockDiagram-DXYQGD6D-Chp0D4qy.js → blockDiagram-DXYQGD6D-DoZjab_0.js} +1 -1
  21. package/payload/frontend/dist/assets/{c4Diagram-AHTNJAMY-CF91pOuW.js → c4Diagram-AHTNJAMY-Ds2E62Z8.js} +1 -1
  22. package/payload/frontend/dist/assets/channel-83CTXkVl.js +1 -0
  23. package/payload/frontend/dist/assets/{chunk-4BX2VUAB-B1gxlVu2.js → chunk-4BX2VUAB-Dk1H2-5_.js} +1 -1
  24. package/payload/frontend/dist/assets/{chunk-4TB4RGXK-Cxt3mj9b.js → chunk-4TB4RGXK-Sg0gzSvg.js} +1 -1
  25. package/payload/frontend/dist/assets/{chunk-55IACEB6-BJT6qNik.js → chunk-55IACEB6-Du_EJG4S.js} +1 -1
  26. package/payload/frontend/dist/assets/{chunk-EDXVE4YY-yI59bCa0.js → chunk-EDXVE4YY-BM1Cs5dU.js} +1 -1
  27. package/payload/frontend/dist/assets/{chunk-FMBD7UC4-CDvncKKJ.js → chunk-FMBD7UC4-BM9thfyY.js} +1 -1
  28. package/payload/frontend/dist/assets/{chunk-OYMX7WX6-BblOIU57.js → chunk-OYMX7WX6-C9Bvn4fo.js} +1 -1
  29. package/payload/frontend/dist/assets/{chunk-QZHKN3VN-rODzNdO0.js → chunk-QZHKN3VN-CaakbFhJ.js} +1 -1
  30. package/payload/frontend/dist/assets/{chunk-YZCP3GAM-B6D4wQwk.js → chunk-YZCP3GAM-DkVNrd40.js} +1 -1
  31. package/payload/frontend/dist/assets/classDiagram-6PBFFD2Q-oR8IYJwC.js +1 -0
  32. package/payload/frontend/dist/assets/classDiagram-v2-HSJHXN6E-oR8IYJwC.js +1 -0
  33. package/payload/frontend/dist/assets/clone-BIDF-bd9.js +1 -0
  34. package/payload/frontend/dist/assets/connection-DIdF_3aa.js +12 -0
  35. package/payload/frontend/dist/assets/{connections-DqDmxS-O.js → connections-DBYC8SFl.js} +1 -1
  36. package/payload/frontend/dist/assets/{cose-bilkent-S5V4N54A-BvwVWp29.js → cose-bilkent-S5V4N54A-B4-fwllY.js} +1 -1
  37. package/payload/frontend/dist/assets/{dagre-KV5264BT-h_K1TH11.js → dagre-KV5264BT-Byu4wqLk.js} +1 -1
  38. package/payload/frontend/dist/assets/{desktop-BQ3kGtKG.js → desktop-aESkh0HL.js} +1 -1
  39. package/payload/frontend/dist/assets/{diagram-5BDNPKRD-B8g2SV6L.js → diagram-5BDNPKRD-DJW8DuCX.js} +1 -1
  40. package/payload/frontend/dist/assets/{diagram-G4DWMVQ6-BOEnrqYm.js → diagram-G4DWMVQ6-DTBvds5J.js} +1 -1
  41. package/payload/frontend/dist/assets/{diagram-MMDJMWI5-DlaN_z71.js → diagram-MMDJMWI5-D42e4xzm.js} +1 -1
  42. package/payload/frontend/dist/assets/{diagram-TYMM5635-C_pSKftn.js → diagram-TYMM5635-BjV43-C_.js} +1 -1
  43. package/payload/frontend/dist/assets/{erDiagram-SMLLAGMA-C2dL-h3I.js → erDiagram-SMLLAGMA-DE47Ibp_.js} +1 -1
  44. package/payload/frontend/dist/assets/{flowDiagram-DWJPFMVM-BmXhKWFj.js → flowDiagram-DWJPFMVM-CjGBlzS4.js} +1 -1
  45. package/payload/frontend/dist/assets/{ganttDiagram-T4ZO3ILL-D_Odnssf.js → ganttDiagram-T4ZO3ILL-vfj40KZi.js} +1 -1
  46. package/payload/frontend/dist/assets/{gitGraphDiagram-UUTBAWPF-DcQdcwKZ.js → gitGraphDiagram-UUTBAWPF-DT5xfRNb.js} +1 -1
  47. package/payload/frontend/dist/assets/{graph-C_XsxefA.js → graph-D-AF6yQT.js} +1 -1
  48. package/payload/frontend/dist/assets/{image-D3hgVr8O.js → image-D9gtSsD9.js} +1 -1
  49. package/payload/frontend/dist/assets/{index-CEUsFFQq.js → index-BPVP2P-2.js} +95 -105
  50. package/payload/frontend/dist/assets/{infoDiagram-42DDH7IO-C6TnRyMi.js → infoDiagram-42DDH7IO-C7ew_uLJ.js} +1 -1
  51. package/payload/frontend/dist/assets/{ishikawaDiagram-UXIWVN3A-BL7rfALJ.js → ishikawaDiagram-UXIWVN3A-B6-YebU9.js} +1 -1
  52. package/payload/frontend/dist/assets/{journeyDiagram-VCZTEJTY-C_6407GW.js → journeyDiagram-VCZTEJTY-BOFgJDA5.js} +1 -1
  53. package/payload/frontend/dist/assets/{kanban-definition-6JOO6SKY-CK61Fd0p.js → kanban-definition-6JOO6SKY-jh06wZYz.js} +1 -1
  54. package/payload/frontend/dist/assets/{layout-DVn6JKbl.js → layout-B4p7V5fB.js} +1 -1
  55. package/payload/frontend/dist/assets/{linear-DyWskq8H.js → linear-D2JWfvdc.js} +1 -1
  56. package/payload/frontend/dist/assets/main-CuRgiPQf.js +706 -0
  57. package/payload/frontend/dist/assets/main-D4_uoZQa.css +33 -0
  58. package/payload/frontend/dist/assets/{min-apbLpSJ3.js → min--jD4Arnm.js} +1 -1
  59. package/payload/frontend/dist/assets/{mindmap-definition-QFDTVHPH-MVHZZbma.js → mindmap-definition-QFDTVHPH-DmzjmSuf.js} +1 -1
  60. package/payload/frontend/dist/assets/{monitoring-BApsVez_.js → monitoring-Tvvk6TfB.js} +1 -1
  61. package/payload/frontend/dist/assets/{notifications-CjxSNLU1.js → notifications-CqP2AQrW.js} +1 -1
  62. package/payload/frontend/dist/assets/{pieDiagram-DEJITSTG-Dhbb0AYU.js → pieDiagram-DEJITSTG-B79qIVe5.js} +1 -1
  63. package/payload/frontend/dist/assets/{quadrantDiagram-34T5L4WZ-Yk6LOF0S.js → quadrantDiagram-34T5L4WZ-DIOj1DhE.js} +1 -1
  64. package/payload/frontend/dist/assets/{record-content-BCJ80KS5.js → record-content-CzGGCbNs.js} +1 -1
  65. package/payload/frontend/dist/assets/{requirementDiagram-MS252O5E-BUhS0PEq.js → requirementDiagram-MS252O5E-C-n1j3tN.js} +1 -1
  66. package/payload/frontend/dist/assets/{sankeyDiagram-XADWPNL6-D2sdxz14.js → sankeyDiagram-XADWPNL6-BVKqWE6C.js} +1 -1
  67. package/payload/frontend/dist/assets/{sequenceDiagram-FGHM5R23-CRere4Fy.js → sequenceDiagram-FGHM5R23-B980Icqs.js} +1 -1
  68. package/payload/frontend/dist/assets/{stateDiagram-FHFEXIEX-_pk-OMlm.js → stateDiagram-FHFEXIEX-C-mJHzhL.js} +1 -1
  69. package/payload/frontend/dist/assets/stateDiagram-v2-QKLJ7IA2-B4L4fK9G.js +1 -0
  70. package/payload/frontend/dist/assets/{status-Dk5rRVQF.js → status-Bv4Czr9-.js} +1 -1
  71. package/payload/frontend/dist/assets/suiji-DyzQqRTE.js +1 -0
  72. package/payload/frontend/dist/assets/{svg-X7YkMMvx.js → svg-C6Aj62ig.js} +1 -1
  73. package/payload/frontend/dist/assets/{tabs-BmKbcPVh.js → tabs-BTUOhdAF.js} +1 -1
  74. package/payload/frontend/dist/assets/{timeline-definition-GMOUNBTQ-BPsI2pMC.js → timeline-definition-GMOUNBTQ-Dr9yRuVq.js} +1 -1
  75. package/payload/frontend/dist/assets/{vennDiagram-DHZGUBPP-BNJkZ1Az.js → vennDiagram-DHZGUBPP-B0Xsg1-Z.js} +1 -1
  76. package/payload/frontend/dist/assets/{wardley-RL74JXVD-CVcYeATS.js → wardley-RL74JXVD-BjIKKaA_.js} +1 -1
  77. package/payload/frontend/dist/assets/{wardleyDiagram-NUSXRM2D-BpLJ0alk.js → wardleyDiagram-NUSXRM2D-DMJ7MEA9.js} +1 -1
  78. package/payload/frontend/dist/assets/{xychartDiagram-5P7HB3ND-BdsYYk4M.js → xychartDiagram-5P7HB3ND-2tvgfdab.js} +1 -1
  79. package/payload/frontend/dist/build-info.json +4 -4
  80. package/payload/frontend/dist/companion.html +1 -1
  81. package/payload/frontend/dist/index.html +3 -3
  82. package/payload/packages/agent-bridge/src/install-pi.mjs +81 -0
  83. package/payload/plugins/pi/dist/SKILL.md +22 -0
  84. package/payload/plugins/pi/dist/bridge/app-server-client.cjs +82 -0
  85. package/payload/plugins/pi/dist/bridge/feishu_stop_notify.sh +169 -0
  86. package/payload/plugins/pi/dist/bridge/runweave-hook-bridge.cjs +583 -0
  87. package/payload/plugins/pi/dist/bridge/runweave-hook-completion.cjs +42 -0
  88. package/payload/plugins/pi/dist/bridge/runweave-hook-payload.cjs +578 -0
  89. package/payload/plugins/pi/dist/bridge/runweave-task-supervision.cjs +167 -0
  90. package/payload/plugins/pi/dist/runweave.js +316 -0
  91. package/payload/plugins/toolkit/.codex-plugin/plugin.json +31 -0
  92. package/payload/plugins/toolkit/README.md +185 -0
  93. package/payload/plugins/toolkit/hooks/AGENTS.md +6 -0
  94. package/payload/plugins/toolkit/hooks/app-server-client.cjs +82 -0
  95. package/payload/plugins/toolkit/hooks/feishu_stop_notify.sh +169 -0
  96. package/payload/plugins/toolkit/hooks/runweave-hook-bridge.cjs +583 -0
  97. package/payload/plugins/toolkit/hooks/runweave-hook-completion.cjs +42 -0
  98. package/payload/plugins/toolkit/hooks/runweave-hook-dispatch.cjs +123 -0
  99. package/payload/plugins/toolkit/hooks/runweave-hook-payload.cjs +578 -0
  100. package/payload/plugins/toolkit/hooks/runweave-task-supervision.cjs +167 -0
  101. package/payload/plugins/toolkit/hooks.json +108 -0
  102. package/payload/plugins/toolkit/skills/acceptance/SKILL.md +70 -0
  103. package/payload/plugins/toolkit/skills/acceptance/agents/openai.yaml +4 -0
  104. package/payload/plugins/toolkit/skills/acceptance/references/capture.md +38 -0
  105. package/payload/plugins/toolkit/skills/acceptance/references/delivery.md +54 -0
  106. package/payload/plugins/toolkit/skills/acceptance/references/gallery-contract.md +84 -0
  107. package/payload/plugins/toolkit/skills/acceptance/references/gallery-copy.md +34 -0
  108. package/payload/plugins/toolkit/skills/acceptance/references/video.md +52 -0
  109. package/payload/plugins/toolkit/skills/acceptance/scripts/capture.py +137 -0
  110. package/payload/plugins/toolkit/skills/acceptance/scripts/common.py +63 -0
  111. package/payload/plugins/toolkit/skills/acceptance/scripts/gallery.py +353 -0
  112. package/payload/plugins/toolkit/skills/acceptance/scripts/preview.py +109 -0
  113. package/payload/plugins/toolkit/skills/acceptance/scripts/video.py +283 -0
  114. package/payload/plugins/toolkit/skills/acceptance/templates/reader.css +576 -0
  115. package/payload/plugins/toolkit/skills/acceptance/templates/reader.html +63 -0
  116. package/payload/plugins/toolkit/skills/acceptance/templates/reader.js +326 -0
  117. package/payload/plugins/toolkit/skills/acceptance/templates/viewer.css +55 -0
  118. package/payload/plugins/toolkit/skills/acceptance-gallery/SKILL.md +8 -0
  119. package/payload/plugins/toolkit/skills/acceptance-gallery/agents/openai.yaml +6 -0
  120. package/payload/plugins/toolkit/skills/acceptance-gallery/references/capture-and-copy.md +3 -0
  121. package/payload/plugins/toolkit/skills/acceptance-gallery/references/content-contract.md +3 -0
  122. package/payload/plugins/toolkit/skills/acceptance-gallery/scripts/gallery.py +9 -0
  123. package/payload/plugins/toolkit/skills/acceptance-video/SKILL.md +8 -0
  124. package/payload/plugins/toolkit/skills/acceptance-video/agents/openai.yaml +6 -0
  125. package/payload/plugins/toolkit/skills/acceptance-video/references/input-and-capture.md +3 -0
  126. package/payload/plugins/toolkit/skills/acceptance-video/references/mobile-review.md +3 -0
  127. package/payload/plugins/toolkit/skills/acceptance-video/scripts/capture.py +9 -0
  128. package/payload/plugins/toolkit/skills/acceptance-video/scripts/video.py +9 -0
  129. package/payload/plugins/toolkit/skills/agent-device/SKILL.md +86 -0
  130. package/payload/plugins/toolkit/skills/agent-device/agents/openai.yaml +4 -0
  131. package/payload/plugins/toolkit/skills/agent-device/references/ios-setup.md +36 -0
  132. package/payload/plugins/toolkit/skills/agent-device/scripts/device.py +398 -0
  133. package/payload/plugins/toolkit/skills/agent-device/scripts/resources.py +248 -0
  134. package/payload/plugins/toolkit/skills/architecture-flow-prototyping/SKILL.md +128 -0
  135. package/payload/plugins/toolkit/skills/architecture-flow-prototyping/agents/openai.yaml +4 -0
  136. package/payload/plugins/toolkit/skills/architecture-flow-prototyping/references/architecture-flow-checklist.md +59 -0
  137. package/payload/plugins/toolkit/skills/architecture-flow-prototyping/references/architecture-flow-guide.md +135 -0
  138. package/payload/plugins/toolkit/skills/architecture-flow-prototyping/references/architecture-flow-handoff-template.md +57 -0
  139. package/payload/plugins/toolkit/skills/ask-first/SKILL.md +81 -0
  140. package/payload/plugins/toolkit/skills/brainstorming/SKILL.md +41 -0
  141. package/payload/plugins/toolkit/skills/browse-record/SKILL.md +35 -0
  142. package/payload/plugins/toolkit/skills/browse-record/references/app-usage.md +19 -0
  143. package/payload/plugins/toolkit/skills/browse-record/references/daily-reporting.md +115 -0
  144. package/payload/plugins/toolkit/skills/browse-record/references/zhihu.md +33 -0
  145. package/payload/plugins/toolkit/skills/browse-record/scripts/app_usage.py +110 -0
  146. package/payload/plugins/toolkit/skills/browse-record/scripts/browse_job.py +385 -0
  147. package/payload/plugins/toolkit/skills/browse-record/scripts/zhihu-read.js +126 -0
  148. package/payload/plugins/toolkit/skills/browse-record/scripts/zhihu_http.py +273 -0
  149. package/payload/plugins/toolkit/skills/clear-technical-explanations/LICENSE +21 -0
  150. package/payload/plugins/toolkit/skills/clear-technical-explanations/SKILL.md +103 -0
  151. package/payload/plugins/toolkit/skills/code-grounded-requirements/SKILL.md +54 -0
  152. package/payload/plugins/toolkit/skills/daily-doc-maintenance/SKILL.md +151 -0
  153. package/payload/plugins/toolkit/skills/daily-record/SKILL.md +63 -0
  154. package/payload/plugins/toolkit/skills/daily-record/agents/openai.yaml +4 -0
  155. package/payload/plugins/toolkit/skills/daily-record/references/browser-history.md +6 -0
  156. package/payload/plugins/toolkit/skills/daily-record/references/feishu.md +90 -0
  157. package/payload/plugins/toolkit/skills/daily-record/references/scheduled-reporting.md +144 -0
  158. package/payload/plugins/toolkit/skills/daily-record/references/scheduled-task.template.json +15 -0
  159. package/payload/plugins/toolkit/skills/daily-record/references/suiji-work-records.md +57 -0
  160. package/payload/plugins/toolkit/skills/daily-record/scripts/feishu.py +280 -0
  161. package/payload/plugins/toolkit/skills/daily-record/scripts/job.py +416 -0
  162. package/payload/plugins/toolkit/skills/daily-record/scripts/job_browser.py +77 -0
  163. package/payload/plugins/toolkit/skills/daily-record/scripts/job_facts.py +132 -0
  164. package/payload/plugins/toolkit/skills/daily-record/scripts/job_isolation.py +69 -0
  165. package/payload/plugins/toolkit/skills/daily-record/scripts/job_materials.py +154 -0
  166. package/payload/plugins/toolkit/skills/daily-record/scripts/job_screen.py +77 -0
  167. package/payload/plugins/toolkit/skills/daily-record/scripts/job_state.py +309 -0
  168. package/payload/plugins/toolkit/skills/daily-refactor/SKILL.md +101 -0
  169. package/payload/plugins/toolkit/skills/daily-refactor/scripts/compare-architecture-reports.mjs +168 -0
  170. package/payload/plugins/toolkit/skills/debugging-strategies/SKILL.md +38 -0
  171. package/payload/plugins/toolkit/skills/debugging-strategies/resources/implementation-playbook.md +520 -0
  172. package/payload/plugins/toolkit/skills/diagnostic-log-debugging/SKILL.md +79 -0
  173. package/payload/plugins/toolkit/skills/doc-coauthoring/SKILL.md +64 -0
  174. package/payload/plugins/toolkit/skills/eli5/LICENSE +21 -0
  175. package/payload/plugins/toolkit/skills/eli5/SKILL.md +18 -0
  176. package/payload/plugins/toolkit/skills/experience/SKILL.md +71 -0
  177. package/payload/plugins/toolkit/skills/experience/package.json +13 -0
  178. package/payload/plugins/toolkit/skills/git-advanced-workflows/SKILL.md +457 -0
  179. package/payload/plugins/toolkit/skills/github-pr/SKILL.md +109 -0
  180. package/payload/plugins/toolkit/skills/github-pr/scripts/github-access.mjs +292 -0
  181. package/payload/plugins/toolkit/skills/github-pr/scripts/preflight.mjs +191 -0
  182. package/payload/plugins/toolkit/skills/github-pr/scripts/source-worktree.mjs +354 -0
  183. package/payload/plugins/toolkit/skills/grill-with-docs/SKILL.md +66 -0
  184. package/payload/plugins/toolkit/skills/grill-with-docs/agents/openai.yaml +6 -0
  185. package/payload/plugins/toolkit/skills/grilling/SKILL.md +14 -0
  186. package/payload/plugins/toolkit/skills/handoff/SKILL.md +98 -0
  187. package/payload/plugins/toolkit/skills/karpathy-guidelines/SKILL.md +73 -0
  188. package/payload/plugins/toolkit/skills/playwright-cli/SKILL.md +562 -0
  189. package/payload/plugins/toolkit/skills/playwright-cli/references/element-attributes.md +23 -0
  190. package/payload/plugins/toolkit/skills/playwright-cli/references/playwright-tests.md +39 -0
  191. package/payload/plugins/toolkit/skills/playwright-cli/references/request-mocking.md +87 -0
  192. package/payload/plugins/toolkit/skills/playwright-cli/references/running-code.md +240 -0
  193. package/payload/plugins/toolkit/skills/playwright-cli/references/session-management.md +226 -0
  194. package/payload/plugins/toolkit/skills/playwright-cli/references/spec-driven-testing.md +312 -0
  195. package/payload/plugins/toolkit/skills/playwright-cli/references/storage-state.md +275 -0
  196. package/payload/plugins/toolkit/skills/playwright-cli/references/test-generation.md +138 -0
  197. package/payload/plugins/toolkit/skills/playwright-cli/references/tracing.md +142 -0
  198. package/payload/plugins/toolkit/skills/playwright-cli/references/video-recording.md +157 -0
  199. package/payload/plugins/toolkit/skills/playwright-cli/templates/standalone.config.json +7 -0
  200. package/payload/plugins/toolkit/skills/product-exploration/SKILL.md +64 -0
  201. package/payload/plugins/toolkit/skills/product-exploration/agents/openai.yaml +5 -0
  202. package/payload/plugins/toolkit/skills/prototype-first-development/SKILL.md +134 -0
  203. package/payload/plugins/toolkit/skills/prototype-first-development/references/html-prototype-template/README.md +88 -0
  204. package/payload/plugins/toolkit/skills/prototype-first-development/references/html-prototype-template/app.js +145 -0
  205. package/payload/plugins/toolkit/skills/prototype-first-development/references/html-prototype-template/index.html +229 -0
  206. package/payload/plugins/toolkit/skills/prototype-first-development/references/html-prototype-template/mock-state.json +60 -0
  207. package/payload/plugins/toolkit/skills/prototype-first-development/references/implementation-plan-handoff-template.md +61 -0
  208. package/payload/plugins/toolkit/skills/prototype-first-development/references/prototype-workflow-checklist.md +64 -0
  209. package/payload/plugins/toolkit/skills/publish-runweave-server/SKILL.md +69 -0
  210. package/payload/plugins/toolkit/skills/publish-runweave-server/agents/openai.yaml +4 -0
  211. package/payload/plugins/toolkit/skills/react-best-practices/AGENTS.md +3227 -0
  212. package/payload/plugins/toolkit/skills/react-best-practices/README.md +127 -0
  213. package/payload/plugins/toolkit/skills/react-best-practices/SKILL.md +143 -0
  214. package/payload/plugins/toolkit/skills/react-best-practices/metadata.json +15 -0
  215. package/payload/plugins/toolkit/skills/react-best-practices/rules/advanced/event-handler-refs.md +55 -0
  216. package/payload/plugins/toolkit/skills/react-best-practices/rules/advanced/init-once.md +42 -0
  217. package/payload/plugins/toolkit/skills/react-best-practices/rules/advanced/use-latest.md +39 -0
  218. package/payload/plugins/toolkit/skills/react-best-practices/rules/async/api-routes.md +38 -0
  219. package/payload/plugins/toolkit/skills/react-best-practices/rules/async/defer-await.md +80 -0
  220. package/payload/plugins/toolkit/skills/react-best-practices/rules/async/dependencies.md +52 -0
  221. package/payload/plugins/toolkit/skills/react-best-practices/rules/async/parallel.md +28 -0
  222. package/payload/plugins/toolkit/skills/react-best-practices/rules/async/suspense-boundaries.md +99 -0
  223. package/payload/plugins/toolkit/skills/react-best-practices/rules/bundle/barrel-imports.md +59 -0
  224. package/payload/plugins/toolkit/skills/react-best-practices/rules/bundle/conditional.md +37 -0
  225. package/payload/plugins/toolkit/skills/react-best-practices/rules/bundle/defer-third-party.md +49 -0
  226. package/payload/plugins/toolkit/skills/react-best-practices/rules/bundle/dynamic-imports.md +35 -0
  227. package/payload/plugins/toolkit/skills/react-best-practices/rules/bundle/preload.md +46 -0
  228. package/payload/plugins/toolkit/skills/react-best-practices/rules/client/event-listeners.md +78 -0
  229. package/payload/plugins/toolkit/skills/react-best-practices/rules/client/localstorage-schema.md +77 -0
  230. package/payload/plugins/toolkit/skills/react-best-practices/rules/client/passive-event-listeners.md +48 -0
  231. package/payload/plugins/toolkit/skills/react-best-practices/rules/client/swr-dedup.md +56 -0
  232. package/payload/plugins/toolkit/skills/react-best-practices/rules/js/batch-dom-css.md +110 -0
  233. package/payload/plugins/toolkit/skills/react-best-practices/rules/js/cache-function-results.md +80 -0
  234. package/payload/plugins/toolkit/skills/react-best-practices/rules/js/cache-property-access.md +28 -0
  235. package/payload/plugins/toolkit/skills/react-best-practices/rules/js/cache-storage.md +70 -0
  236. package/payload/plugins/toolkit/skills/react-best-practices/rules/js/combine-iterations.md +32 -0
  237. package/payload/plugins/toolkit/skills/react-best-practices/rules/js/early-exit.md +50 -0
  238. package/payload/plugins/toolkit/skills/react-best-practices/rules/js/flatmap-filter.md +55 -0
  239. package/payload/plugins/toolkit/skills/react-best-practices/rules/js/hoist-regexp.md +45 -0
  240. package/payload/plugins/toolkit/skills/react-best-practices/rules/js/index-maps.md +37 -0
  241. package/payload/plugins/toolkit/skills/react-best-practices/rules/js/length-check-first.md +50 -0
  242. package/payload/plugins/toolkit/skills/react-best-practices/rules/js/min-max-loop.md +82 -0
  243. package/payload/plugins/toolkit/skills/react-best-practices/rules/js/set-map-lookups.md +24 -0
  244. package/payload/plugins/toolkit/skills/react-best-practices/rules/js/tosorted-immutable.md +57 -0
  245. package/payload/plugins/toolkit/skills/react-best-practices/rules/meta/sections.md +46 -0
  246. package/payload/plugins/toolkit/skills/react-best-practices/rules/meta/template.md +28 -0
  247. package/payload/plugins/toolkit/skills/react-best-practices/rules/rendering/activity.md +26 -0
  248. package/payload/plugins/toolkit/skills/react-best-practices/rules/rendering/animate-svg-wrapper.md +38 -0
  249. package/payload/plugins/toolkit/skills/react-best-practices/rules/rendering/conditional-render.md +32 -0
  250. package/payload/plugins/toolkit/skills/react-best-practices/rules/rendering/content-visibility.md +38 -0
  251. package/payload/plugins/toolkit/skills/react-best-practices/rules/rendering/hoist-jsx.md +36 -0
  252. package/payload/plugins/toolkit/skills/react-best-practices/rules/rendering/hydration-no-flicker.md +72 -0
  253. package/payload/plugins/toolkit/skills/react-best-practices/rules/rendering/hydration-suppress-warning.md +26 -0
  254. package/payload/plugins/toolkit/skills/react-best-practices/rules/rendering/resource-hints.md +89 -0
  255. package/payload/plugins/toolkit/skills/react-best-practices/rules/rendering/script-defer-async.md +71 -0
  256. package/payload/plugins/toolkit/skills/react-best-practices/rules/rendering/svg-precision.md +28 -0
  257. package/payload/plugins/toolkit/skills/react-best-practices/rules/rendering/usetransition-loading.md +75 -0
  258. package/payload/plugins/toolkit/skills/react-best-practices/rules/rerender/defer-reads.md +39 -0
  259. package/payload/plugins/toolkit/skills/react-best-practices/rules/rerender/dependencies.md +45 -0
  260. package/payload/plugins/toolkit/skills/react-best-practices/rules/rerender/derived-state-no-effect.md +40 -0
  261. package/payload/plugins/toolkit/skills/react-best-practices/rules/rerender/derived-state.md +29 -0
  262. package/payload/plugins/toolkit/skills/react-best-practices/rules/rerender/functional-setstate.md +77 -0
  263. package/payload/plugins/toolkit/skills/react-best-practices/rules/rerender/lazy-state-init.md +58 -0
  264. package/payload/plugins/toolkit/skills/react-best-practices/rules/rerender/memo-with-default-value.md +36 -0
  265. package/payload/plugins/toolkit/skills/react-best-practices/rules/rerender/memo.md +44 -0
  266. package/payload/plugins/toolkit/skills/react-best-practices/rules/rerender/move-effect-to-event.md +45 -0
  267. package/payload/plugins/toolkit/skills/react-best-practices/rules/rerender/no-inline-components.md +83 -0
  268. package/payload/plugins/toolkit/skills/react-best-practices/rules/rerender/simple-expression-in-memo.md +35 -0
  269. package/payload/plugins/toolkit/skills/react-best-practices/rules/rerender/transitions.md +40 -0
  270. package/payload/plugins/toolkit/skills/react-best-practices/rules/rerender/use-ref-transient-values.md +73 -0
  271. package/payload/plugins/toolkit/skills/react-best-practices/rules/server/after-nonblocking.md +74 -0
  272. package/payload/plugins/toolkit/skills/react-best-practices/rules/server/auth-actions.md +96 -0
  273. package/payload/plugins/toolkit/skills/react-best-practices/rules/server/cache-lru.md +41 -0
  274. package/payload/plugins/toolkit/skills/react-best-practices/rules/server/cache-react.md +76 -0
  275. package/payload/plugins/toolkit/skills/react-best-practices/rules/server/dedup-props.md +65 -0
  276. package/payload/plugins/toolkit/skills/react-best-practices/rules/server/hoist-static-io.md +139 -0
  277. package/payload/plugins/toolkit/skills/react-best-practices/rules/server/parallel-fetching.md +83 -0
  278. package/payload/plugins/toolkit/skills/react-best-practices/rules/server/serialization.md +38 -0
  279. package/payload/plugins/toolkit/skills/recorded-browser-mcp-verification/SKILL.md +8 -0
  280. package/payload/plugins/toolkit/skills/recorded-browser-mcp-verification/agents/openai.yaml +6 -0
  281. package/payload/plugins/toolkit/skills/reproduce-before-fix/SKILL.md +93 -0
  282. package/payload/plugins/toolkit/skills/reproduce-before-fix/agents/openai.yaml +7 -0
  283. package/payload/plugins/toolkit/skills/review-only/SKILL.md +72 -0
  284. package/payload/plugins/toolkit/skills/review-with-runtime-evidence/SKILL.md +134 -0
  285. package/payload/plugins/toolkit/skills/review-with-runtime-evidence/agents/openai.yaml +7 -0
  286. package/payload/plugins/toolkit/skills/review-with-runtime-evidence/references/contracts.md +114 -0
  287. package/payload/plugins/toolkit/skills/review-with-runtime-evidence/scripts/classify-runtime-verdict.mjs +140 -0
  288. package/payload/plugins/toolkit/skills/review-with-runtime-evidence/scripts/run-static-review.mjs +389 -0
  289. package/payload/plugins/toolkit/skills/review-with-runtime-evidence/scripts/static-review-contract.mjs +243 -0
  290. package/payload/plugins/toolkit/skills/run-test-cases/SKILL.md +63 -0
  291. package/payload/plugins/toolkit/skills/runweave-change-validation/SKILL.md +196 -0
  292. package/payload/plugins/toolkit/skills/runweave-change-validation/agents/openai.yaml +7 -0
  293. package/payload/plugins/toolkit/skills/runweave-change-validation/scripts/assert-dev-session-status.mjs +181 -0
  294. package/payload/plugins/toolkit/skills/runweave-dev-session/SKILL.md +126 -0
  295. package/payload/plugins/toolkit/skills/runweave-dev-session/agents/openai.yaml +7 -0
  296. package/payload/plugins/toolkit/skills/runweave-management/SKILL.md +47 -0
  297. package/payload/plugins/toolkit/skills/scheduled-task/SKILL.md +35 -0
  298. package/payload/plugins/toolkit/skills/shadcn/SKILL.md +245 -0
  299. package/payload/plugins/toolkit/skills/shadcn/agents/openai.yml +5 -0
  300. package/payload/plugins/toolkit/skills/shadcn/assets/shadcn-small.png +0 -0
  301. package/payload/plugins/toolkit/skills/shadcn/assets/shadcn.png +0 -0
  302. package/payload/plugins/toolkit/skills/shadcn/cli.md +276 -0
  303. package/payload/plugins/toolkit/skills/shadcn/customization.md +209 -0
  304. package/payload/plugins/toolkit/skills/shadcn/evals/evals.json +47 -0
  305. package/payload/plugins/toolkit/skills/shadcn/mcp.md +94 -0
  306. package/payload/plugins/toolkit/skills/shadcn/rules/base-vs-radix.md +310 -0
  307. package/payload/plugins/toolkit/skills/shadcn/rules/composition.md +197 -0
  308. package/payload/plugins/toolkit/skills/shadcn/rules/forms.md +198 -0
  309. package/payload/plugins/toolkit/skills/shadcn/rules/icons.md +101 -0
  310. package/payload/plugins/toolkit/skills/shadcn/rules/styling.md +163 -0
  311. package/payload/plugins/toolkit/skills/suiji/SKILL.md +54 -0
  312. package/payload/plugins/toolkit/skills/suiji/references/api.md +72 -0
  313. package/payload/plugins/toolkit/skills/suiji/references/source-adapter.md +40 -0
  314. package/payload/plugins/toolkit/skills/suiji/references/work-records.md +36 -0
  315. package/payload/plugins/toolkit/skills/suiji/scripts/source_adapter.py +46 -0
  316. package/payload/plugins/toolkit/skills/suiji/scripts/suiji.py +358 -0
  317. package/payload/plugins/toolkit/skills/suiji/scripts/work_records.py +328 -0
  318. package/payload/plugins/toolkit/skills/suiji/scripts/work_reports.py +75 -0
  319. package/payload/plugins/toolkit/skills/sync-branch-hard-reset/SKILL.md +59 -0
  320. package/payload/plugins/toolkit/skills/update-runweave-backend/SKILL.md +90 -0
  321. package/payload/plugins/toolkit/skills/update-runweave-backend/agents/openai.yaml +4 -0
  322. package/payload/plugins/toolkit/skills/update-runweave-backend/references/npm-update.md +68 -0
  323. package/payload/plugins/toolkit/skills/update-runweave-backend/references/systemd.md +34 -0
  324. package/payload/plugins/toolkit/skills/update-runweave-desktop/SKILL.md +102 -0
  325. package/payload/plugins/toolkit/skills/update-runweave-ios/SKILL.md +16 -0
  326. package/payload/plugins/toolkit/skills/update-runweave-ios/references/ios-wireless-recovery.md +54 -0
  327. package/payload/plugins/toolkit/skills/using-rw/SKILL.md +265 -0
  328. package/payload/plugins/toolkit/skills/write-plan/SKILL.md +72 -0
  329. package/payload/plugins/toolkit/skills/write-test-cases/SKILL.md +100 -0
  330. package/payload/plugins/toolkit/skills/write-test-cases/assets/test-plan-template.yaml +15 -0
  331. package/payload/plugins/toolkit/skills/write-test-cases/references/coverage-checklist.md +75 -0
  332. package/payload/plugins/toolkit/skills/write-test-cases/references/design-techniques.md +91 -0
  333. package/payload/plugins/toolkit/skills/youtube-reading/SKILL.md +35 -0
  334. package/payload/plugins/toolkit/skills/youtube-reading/agents/openai.yaml +4 -0
  335. package/payload/plugins/toolkit/skills/youtube-reading/assets/runtime-lock.json +92 -0
  336. package/payload/plugins/toolkit/skills/youtube-reading/references/content-contract.md +52 -0
  337. package/payload/plugins/toolkit/skills/youtube-reading/references/setup.md +70 -0
  338. package/payload/plugins/toolkit/skills/youtube-reading/requirements.lock +9 -0
  339. package/payload/plugins/toolkit/skills/youtube-reading/scripts/artifacts.py +206 -0
  340. package/payload/plugins/toolkit/skills/youtube-reading/scripts/runtime.py +424 -0
  341. package/payload/plugins/toolkit/skills/youtube-reading/scripts/youtube_reading.py +314 -0
  342. package/payload/plugins/toolkit-release.json +1 -0
  343. package/payload/pty-host/index.cjs +99 -31
  344. package/payload/scripts/toolkit/codex-state.mjs +75 -0
  345. package/payload/scripts/toolkit/release.mjs +210 -0
  346. package/payload/scripts/toolkit/sync-runtime.mjs +108 -0
  347. package/payload/scripts/toolkit/sync.mjs +585 -0
  348. package/payload/server/index.cjs +5 -1
  349. package/payload/frontend/dist/assets/channel-Bf3IeONI.js +0 -1
  350. package/payload/frontend/dist/assets/classDiagram-6PBFFD2Q-CFsG2SvG.js +0 -1
  351. package/payload/frontend/dist/assets/classDiagram-v2-HSJHXN6E-CFsG2SvG.js +0 -1
  352. package/payload/frontend/dist/assets/clone-CeQXm2YN.js +0 -1
  353. package/payload/frontend/dist/assets/connection-XriXysSc.js +0 -12
  354. package/payload/frontend/dist/assets/main-Cg6Oo1xK.css +0 -33
  355. package/payload/frontend/dist/assets/main-H5R-3_w1.js +0 -696
  356. package/payload/frontend/dist/assets/stateDiagram-v2-QKLJ7IA2-CzpdUl_0.js +0 -1
  357. package/payload/frontend/dist/assets/suiji-CO_L5W1X.js +0 -1
@@ -0,0 +1,398 @@
1
+ #!/usr/bin/env python3
2
+ """Isolated iOS agent-device sessions; command status is not business acceptance."""
3
+
4
+ import argparse
5
+ import concurrent.futures
6
+ import json
7
+ import importlib.util
8
+ from contextlib import nullcontext
9
+ import os
10
+ from pathlib import Path
11
+ import re
12
+ import subprocess
13
+ import sys
14
+ import tempfile
15
+ import time
16
+ import uuid
17
+
18
+
19
+ VERSION = "0.21.3"
20
+ sys.dont_write_bytecode = True
21
+ import resources
22
+
23
+
24
+ def capture(args, timeout=15):
25
+ result = subprocess.run(args, capture_output=True, text=True, timeout=timeout)
26
+ if result.returncode:
27
+ raise RuntimeError(result.stderr.strip() or result.stdout.strip() or args[0])
28
+ return result.stdout.strip()
29
+
30
+
31
+ def verify_version():
32
+ actual = capture(["agent-device", "--version"])
33
+ if not re.search(rf"(?<![\d.]){re.escape(VERSION)}(?![\d.])", actual):
34
+ raise RuntimeError(f"Expected agent-device {VERSION}; found {actual}")
35
+ return actual
36
+
37
+
38
+ def check_node():
39
+ actual = capture(["node", "--version"])
40
+ parts = tuple(int(part) for part in actual.lstrip("v").split(".")[:2])
41
+ if parts < (22, 12):
42
+ raise RuntimeError(f"Node 22.12+ required; found {actual}")
43
+ return actual
44
+
45
+
46
+ def write_json(path, data):
47
+ path.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n")
48
+ path.chmod(0o600)
49
+
50
+
51
+ def device_json(config, topic):
52
+ with tempfile.TemporaryDirectory(prefix="agent-device-check-") as temporary:
53
+ output = Path(temporary) / "result.json"
54
+ capture([
55
+ "xcrun", "devicectl", "device", "info", topic,
56
+ "--device", config["udid"], "--timeout", "10",
57
+ "--json-output", str(output),
58
+ ])
59
+ return json.loads(output.read_text())["result"]
60
+
61
+
62
+ def check_target(config):
63
+ if config["kind"] == "simulator":
64
+ data = json.loads(capture(["xcrun", "simctl", "list", "devices", "--json"]))
65
+ device = next((d for group in data["devices"].values() for d in group
66
+ if d["udid"] == config["udid"]), None)
67
+ if not device or not device.get("isAvailable") or device["state"] != "Booted":
68
+ raise RuntimeError("Selected simulator is missing, unavailable or not booted")
69
+ return {"name": device["name"], "udid": device["udid"], "state": device["state"]}
70
+ data = device_json(config, "details")
71
+ hardware = data["hardwareProperties"]
72
+ connection = data["connectionProperties"]
73
+ properties = data["deviceProperties"]
74
+ if hardware.get("udid") != config["udid"]:
75
+ raise RuntimeError("Use the exact hardware UDID, not a device name or CoreDevice alias")
76
+ if connection.get("pairingState") != "paired":
77
+ raise RuntimeError("Selected device is not paired")
78
+ if properties.get("developerModeStatus") != "enabled":
79
+ raise RuntimeError("Selected device Developer Mode is not enabled")
80
+ return {"name": properties.get("name"), "udid": hardware["udid"],
81
+ "transport": connection.get("transportType"),
82
+ "developerMode": properties["developerModeStatus"]}
83
+
84
+
85
+ def check_lock(config):
86
+ data = device_json(config, "lockState")
87
+ if data.get("passcodeRequired") or not data.get("unlockedSinceBoot"):
88
+ raise RuntimeError("Unlock the selected iPhone on the device")
89
+ return data
90
+
91
+
92
+ def check_developer_tools():
93
+ output = capture(["/usr/sbin/DevToolsSecurity", "-status"])
94
+ if "enabled" not in output.lower():
95
+ raise RuntimeError(output)
96
+ return output
97
+
98
+
99
+ def check_signing(config):
100
+ if not (config.get("teamId") and config.get("runnerId")):
101
+ raise RuntimeError("UI automation requires --team-id at init; launch does not")
102
+ resources.shared_runner(config["teamId"], config["runnerId"])
103
+ return "Runner signing identifiers configured; provisioning is not verified"
104
+
105
+
106
+ def preflight(root, config, automation=True):
107
+ checks = {
108
+ "xcode": lambda: capture(["xcodebuild", "-version"]),
109
+ "target": lambda: check_target(config),
110
+ }
111
+ if automation:
112
+ checks.update(cli=verify_version, node=check_node)
113
+ if config["kind"] == "device":
114
+ checks.update(lock=lambda: check_lock(config))
115
+ if automation:
116
+ checks.update(developerTools=check_developer_tools, signing=lambda: check_signing(config))
117
+ results = {}
118
+ with concurrent.futures.ThreadPoolExecutor(max_workers=len(checks)) as pool:
119
+ pending = {name: pool.submit(check) for name, check in checks.items()}
120
+ for name, future in pending.items():
121
+ try:
122
+ results[name] = {"ok": True, "detail": future.result()}
123
+ except (OSError, RuntimeError, ValueError, KeyError, subprocess.TimeoutExpired) as error:
124
+ results[name] = {"ok": False, "error": str(error)}
125
+ report = {"preflightOk": all(r["ok"] for r in results.values()),
126
+ "purpose": "automation" if automation else "launch",
127
+ "automationReady": False, "checks": results,
128
+ "unchecked": ["runner provisioning/install quota", "UI Automation authorization",
129
+ "other XCTest users", "app build provenance"]}
130
+ write_json(root / "preflight.json", report)
131
+ print(json.dumps(report, ensure_ascii=False, indent=2))
132
+ return 0 if report["preflightOk"] else 2
133
+
134
+
135
+ def simulator_pool(root, kind):
136
+ if kind != "simulator":
137
+ return None
138
+ anchor = root
139
+ while not anchor.exists() and anchor != anchor.parent:
140
+ anchor = anchor.parent
141
+ repo = None
142
+ # A new/nonexistent task directory must not bypass the current project's policy.
143
+ for directory in (Path.cwd(), anchor):
144
+ result = subprocess.run(["git", "-C", str(directory), "rev-parse", "--show-toplevel"],
145
+ capture_output=True, text=True)
146
+ if result.returncode == 0:
147
+ candidate = Path(result.stdout.strip())
148
+ if (candidate / "packages/app-ios/ios/RunweaveNative.xcodeproj").exists():
149
+ repo = candidate
150
+ break
151
+ if repo is None:
152
+ return None
153
+ path = repo / "scripts/ios-simulators/pool.py"
154
+ if not path.exists():
155
+ raise RuntimeError("This Runweave worktree needs the shared simulator tooling update")
156
+ spec = importlib.util.spec_from_file_location("runweave_simulator_pool", path)
157
+ module = importlib.util.module_from_spec(spec)
158
+ spec.loader.exec_module(module)
159
+ return module
160
+
161
+
162
+ def launch_app(root, config):
163
+ """Native launch only: wireless updates must not depend on XCTest readiness."""
164
+ if config["kind"] != "device":
165
+ raise RuntimeError("launch is for physical devices; simulators use the managed run entry")
166
+ if preflight(root, config, automation=False):
167
+ return 2
168
+ stamp = str(time.time_ns())
169
+ native = root / f"{stamp}-launch-native.json"
170
+ started = time.monotonic()
171
+ print("Launching installed App via CoreDevice; no XCTest or UI verification.", file=sys.stderr, flush=True)
172
+ result = subprocess.run([
173
+ "xcrun", "devicectl", "device", "process", "launch", "--device", config["udid"],
174
+ "--timeout", "30", "--json-output", str(native), config["app"],
175
+ ], capture_output=True, text=True, timeout=40)
176
+ data = json.loads(native.read_text()) if native.exists() else {}
177
+ pid = data.get("result", {}).get("process", {}).get("processIdentifier")
178
+ code = result.returncode or (0 if type(pid) is int and pid > 0 else 2)
179
+ report = {"command": "launch", "app": config["app"], "exit": code,
180
+ "seconds": round(time.monotonic() - started, 3), "processIdentifier": pid,
181
+ "automationReady": False, "uiVerified": False, "nativeResult": str(native)}
182
+ write_json(root / f"{stamp}-launch.json", report)
183
+ if native.exists():
184
+ native.chmod(0o600)
185
+ print(json.dumps(report, ensure_ascii=False, indent=2))
186
+ if code:
187
+ print("Native launch failed; inspect nativeResult. No automatic retry.", file=sys.stderr)
188
+ return code
189
+
190
+
191
+ def runner_diagnostic(root, runner_log, offset, output):
192
+ # Inspect only this invocation, not a failure left by an earlier runner.
193
+ text = ""
194
+ try:
195
+ with runner_log.open("rb") as stream:
196
+ size = runner_log.stat().st_size
197
+ stream.seek(max(offset if size >= offset else 0, size - 256_000))
198
+ text = stream.read().decode("utf-8", errors="replace")
199
+ except OSError:
200
+ pass
201
+ markers = [marker for marker in (
202
+ "exited with code 74", "Exiting due to IDE disconnection",
203
+ "Failed to retrieve test configuration from IDE", "Connection peer refused channel request",
204
+ ) if marker in text]
205
+ if not markers and "xcodebuild exited early" not in output:
206
+ return None
207
+ transport = None
208
+ try:
209
+ transport = json.loads((root / "preflight.json").read_text())["checks"]["target"]["detail"].get("transport")
210
+ except (OSError, ValueError, KeyError, AttributeError):
211
+ pass
212
+ return {"code": "ios_xctest_bootstrap_failed" if markers else "ios_runner_exited_early",
213
+ "transportAtPreflight": transport, "runnerLog": str(runner_log),
214
+ "evidence": markers, "automationReady": False,
215
+ "hint": "App launch and UI automation are separate. For launch-only use launch; "
216
+ "UI acceptance remains blocked. Inspect the runner log before retrying; "
217
+ "increasing a connection timeout cannot revive an exited runner."}
218
+
219
+
220
+ def invoke(root, config, command, private=False, daemon=False, operation=None):
221
+ verify_version()
222
+ env = os.environ.copy()
223
+ env["AGENT_DEVICE_STATE_DIR"] = str(root / "state")
224
+ env["AGENT_DEVICE_NO_UPDATE_NOTIFIER"] = "1"
225
+ # Do not inherit another project's signing overrides.
226
+ for key in ("AGENT_DEVICE_IOS_TEAM_ID", "AGENT_DEVICE_IOS_BUNDLE_ID",
227
+ "AGENT_DEVICE_IOS_PROVISIONING_PROFILE", "AGENT_DEVICE_IOS_SIGNING_IDENTITY"):
228
+ env.pop(key, None)
229
+ if config["kind"] == "device":
230
+ if not daemon and command[0] != "close":
231
+ check_signing(config)
232
+ if config.get("teamId") and config.get("runnerId"):
233
+ env["AGENT_DEVICE_IOS_TEAM_ID"] = config["teamId"]
234
+ env["AGENT_DEVICE_IOS_BUNDLE_ID"] = config["runnerId"]
235
+ args = ["agent-device", *command]
236
+ if not daemon:
237
+ args.extend(["--session", config["session"], "--platform", "ios", "--udid", config["udid"]])
238
+ started = time.monotonic()
239
+ runner_log = root / "state" / "sessions" / config["session"] / "runner.log"
240
+ runner_offset = runner_log.stat().st_size if runner_log.exists() else 0
241
+ print(f"COMMAND_START {command[0]}: waiting for agent-device; UI commands may start XCTest.",
242
+ file=sys.stderr, flush=True)
243
+ if operation:
244
+ operation.owner["automationPending"] = True
245
+ operation.owner["automationStateDir"] = str(root / "state")
246
+ # Persist intent before a daemon may be spawned outside this command's process group.
247
+ pool = simulator_pool(root, config["kind"])
248
+ pool.save_owner(operation.owner)
249
+ result = operation.run(args, env=env, capture_output=True)
250
+ else:
251
+ result = subprocess.run(args, env=env, stdout=subprocess.PIPE,
252
+ stderr=subprocess.STDOUT, text=True)
253
+ output = result.stdout
254
+ code = result.returncode
255
+ # Pinned upstream CLI can return zero without a usable initial snapshot or settle result.
256
+ if code == 0 and "initial interactive snapshot failed" in output:
257
+ code = 2
258
+ if code == 0 and "not settled after" in output:
259
+ code = 3
260
+ try:
261
+ if code == 0 and json.loads(output).get("success") is False:
262
+ code = 2
263
+ except (ValueError, AttributeError):
264
+ pass
265
+ stamp = f"{time.time_ns()}-{uuid.uuid4().hex[:6]}"
266
+ if not private:
267
+ logfile = root / f"{stamp}.log"
268
+ logfile.write_text(output)
269
+ logfile.chmod(0o600)
270
+ metric = {"id": stamp, "command": command[0], "seconds": round(time.monotonic() - started, 3),
271
+ "upstreamExit": result.returncode, "exit": code, "outputSaved": not private}
272
+ if code and not private and config["kind"] == "device":
273
+ diagnostic = runner_diagnostic(root, runner_log, runner_offset, output)
274
+ if diagnostic:
275
+ write_json(root / f"{stamp}.diagnostic.json", diagnostic)
276
+ metric["diagnostic"] = diagnostic["code"]
277
+ print("AUTOMATION_DIAGNOSTIC " + json.dumps(diagnostic), file=sys.stderr)
278
+ with (root / "metrics.jsonl").open("a") as stream:
279
+ stream.write(json.dumps(metric) + "\n")
280
+ (root / "metrics.jsonl").chmod(0o600)
281
+ sys.stdout.write(output)
282
+ print("COMMAND_RESULT " + json.dumps(metric), file=sys.stderr)
283
+ if code != result.returncode:
284
+ print("Observation incomplete. Inspect current state before any retry.", file=sys.stderr)
285
+ return code
286
+
287
+
288
+ def main():
289
+ os.umask(0o077)
290
+ parser = argparse.ArgumentParser(description=__doc__)
291
+ sub = parser.add_subparsers(dest="action", required=True)
292
+ init = sub.add_parser("init", help="Create a new local task; no device mutation")
293
+ init.add_argument("root", type=Path)
294
+ init.add_argument("--kind", choices=("device", "simulator"), required=True)
295
+ init.add_argument("--udid", required=True)
296
+ init.add_argument("--app", required=True)
297
+ init.add_argument("--team-id")
298
+ init.add_argument("--runner-id")
299
+ for action in ("check", "stop", "launch"):
300
+ sub.add_parser(action).add_argument("root", type=Path)
301
+ run = sub.add_parser("run", help="Pass a CLI command after --; open uses the bound App")
302
+ run.add_argument("root", type=Path)
303
+ # REMAINDER keeps upstream flags untouched. A leading --private belongs to this wrapper.
304
+ run.add_argument("command", nargs=argparse.REMAINDER)
305
+ options = parser.parse_args()
306
+ root = options.root.resolve()
307
+ if options.action == "init":
308
+ if options.runner_id and not options.team_id:
309
+ parser.error("--runner-id requires --team-id")
310
+ if options.kind == "device" and options.team_id:
311
+ with resources.guard():
312
+ options.runner_id = resources.shared_runner(options.team_id, options.runner_id)
313
+ if not re.fullmatch(r"[A-Za-z0-9-]+", options.udid):
314
+ parser.error("invalid UDID")
315
+ for value in (options.app, options.runner_id):
316
+ if value and not re.fullmatch(r"[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)+", value):
317
+ parser.error("invalid Bundle ID")
318
+ pool = simulator_pool(root, options.kind)
319
+ if not pool:
320
+ root.mkdir(parents=True, exist_ok=False)
321
+ context = pool.operation(root, options.app, options.udid) if pool else nullcontext()
322
+ with context:
323
+ if (root / "session.json").exists():
324
+ raise RuntimeError("Task already has a session; use a new task directory")
325
+ config = {"kind": options.kind, "udid": options.udid, "app": options.app,
326
+ "teamId": options.team_id, "runnerId": options.runner_id,
327
+ "session": "qa-" + uuid.uuid4().hex[:12], "version": VERSION}
328
+ write_json(root / "session.json", config)
329
+ with resources.guard():
330
+ resources.register(root)
331
+ print(root)
332
+ return 0
333
+ config = json.loads((root / "session.json").read_text())
334
+ if config.get("version") != VERSION:
335
+ raise RuntimeError("Task was created for a different CLI version; create a new task")
336
+ if options.action == "launch":
337
+ if config["kind"] != "device":
338
+ raise RuntimeError("launch is for physical devices")
339
+ with resources.physical_operation(root, config):
340
+ result = launch_app(root, config)
341
+ resources.finished(root, config)
342
+ return result
343
+ if options.action == "run" and config["kind"] == "device":
344
+ check_signing(config)
345
+ pool = simulator_pool(root, config["kind"])
346
+ context = pool.operation(root, config["app"], config["udid"]) if pool else (
347
+ resources.physical_operation(root, config) if config["kind"] == "device" and options.action != "check"
348
+ else nullcontext())
349
+ with context as op:
350
+ if options.action == "check":
351
+ return preflight(root, config)
352
+ if options.action == "stop":
353
+ # Cleanup is allowed even after preflight failed; never stop another state directory.
354
+ close_code = invoke(root, config, ["close"], operation=op)
355
+ stop_code = invoke(root, config, ["daemon", "stop", "--state-dir", str(root / "state"), "--clean"], daemon=True, operation=op)
356
+ if not (stop_code or close_code) and config["kind"] == "device":
357
+ resources.finished(root, config)
358
+ return stop_code or close_code
359
+ command = options.command
360
+ private = bool(command and command[0] == "--private")
361
+ if private:
362
+ command = command[1:]
363
+ if command and command[0] == "--":
364
+ command = command[1:]
365
+ if not command:
366
+ parser.error("run requires an agent-device command after --")
367
+ forbidden = ("--session", "--platform", "--udid", "--device", "--state-dir", "--serial")
368
+ if any(arg == flag or arg.startswith(flag + "=") for arg in command for flag in forbidden):
369
+ parser.error("device/session overrides are fixed by init; create a separate task")
370
+ if command[0] in ("daemon", "devices", "install", "reinstall", "uninstall"):
371
+ parser.error("use stop for cleanup; installation/discovery uses explicit native tooling")
372
+ if command[0] == "open":
373
+ if len(command) > 1 and not command[1].startswith("-"):
374
+ parser.error("open uses the App bound by init; do not pass another App")
375
+ command.insert(1, config["app"])
376
+ if command[0] == "open" and preflight(root, config):
377
+ return 2
378
+ return invoke(root, config, command, private, operation=op)
379
+
380
+
381
+
382
+ if __name__ == "__main__":
383
+ try:
384
+ result = main()
385
+ if result == 0 and len(sys.argv) > 1 and sys.argv[1] == "stop":
386
+ try:
387
+ resources.prune(apply=True)
388
+ except (OSError, RuntimeError, ValueError, subprocess.SubprocessError) as error:
389
+ print(f"Artifact pruning deferred: {error}", file=sys.stderr)
390
+ sys.exit(result)
391
+ except (OSError, RuntimeError, ValueError, KeyError, subprocess.TimeoutExpired) as error:
392
+ code = getattr(error, "code", None)
393
+ if code is not None:
394
+ print(json.dumps({"ok": False, "code": code, "detail": str(error)},
395
+ ensure_ascii=False), file=sys.stderr)
396
+ sys.exit(getattr(error, "exit_code", 2))
397
+ print(f"ERROR: {error}", file=sys.stderr)
398
+ sys.exit(2)
@@ -0,0 +1,248 @@
1
+ #!/usr/bin/env python3
2
+ """Shared signing identity, physical-device ownership and bounded QA artifacts."""
3
+ import argparse
4
+ from contextlib import contextmanager
5
+ import fcntl
6
+ import json
7
+ import os
8
+ from pathlib import Path
9
+ import plistlib
10
+ import re
11
+ import shutil
12
+ import subprocess
13
+ import time
14
+
15
+ BASE = Path.home() / ".runweave" / "agent-device"
16
+ RUNNER_ID = "com.runweave.agentdevice"
17
+ KEEP_TASKS = 20
18
+ MAX_AGE = 14 * 86400
19
+ MAX_BYTES = 1024 ** 3
20
+
21
+
22
+ def read(path):
23
+ return json.loads(path.read_text())
24
+
25
+
26
+ def write(path, value):
27
+ path.parent.mkdir(parents=True, exist_ok=True)
28
+ temporary = path.with_suffix(".tmp")
29
+ temporary.write_text(json.dumps(value, indent=2) + "\n")
30
+ temporary.chmod(0o600)
31
+ temporary.replace(path)
32
+
33
+
34
+ @contextmanager
35
+ def guard():
36
+ BASE.mkdir(parents=True, exist_ok=True)
37
+ with (BASE / "resources.lock").open("a+") as stream:
38
+ try:
39
+ fcntl.flock(stream, fcntl.LOCK_EX | fcntl.LOCK_NB)
40
+ except BlockingIOError:
41
+ raise RuntimeError("device_busy: another managed operation is active")
42
+ try:
43
+ yield
44
+ finally:
45
+ fcntl.flock(stream, fcntl.LOCK_UN)
46
+
47
+
48
+ def shared_runner(team, requested=None):
49
+ if not re.fullmatch(r"[A-Z0-9]{10}", team):
50
+ raise RuntimeError("Expected a ten-character signing Team ID")
51
+ if requested and requested != RUNNER_ID:
52
+ raise RuntimeError(f"Runner identity is shared: use {RUNNER_ID}; task-specific IDs are forbidden")
53
+ path = BASE / "runners" / f"{team}.json"
54
+ if not path.exists():
55
+ write(path, {"teamId": team, "runnerId": RUNNER_ID})
56
+ if read(path) != {"teamId": team, "runnerId": RUNNER_ID}:
57
+ raise RuntimeError("Shared runner registry differs; inspect before changing signing identity")
58
+ return RUNNER_ID
59
+
60
+
61
+ def register(root):
62
+ paths = read(BASE / "tasks.json") if (BASE / "tasks.json").exists() else []
63
+ if str(root) not in paths:
64
+ write(BASE / "tasks.json", [*paths, str(root)])
65
+
66
+
67
+ def device_lock(config):
68
+ udid = config["udid"]
69
+ if not re.fullmatch(r"[A-Fa-f0-9-]+", udid):
70
+ raise RuntimeError("Invalid hardware UDID")
71
+ return Path.home() / ".runweave/native-device/locks" / udid.upper()
72
+
73
+
74
+ @contextmanager
75
+ def physical_operation(root, config):
76
+ with guard():
77
+ path = device_lock(config)
78
+ if path.exists():
79
+ owner = read(path / "owner.json")
80
+ if owner.get("kind") != "agent-device" or owner.get("taskDir") != str(root):
81
+ raise RuntimeError(f"device_busy: {path / 'owner.json'}")
82
+ else:
83
+ active_local()
84
+ path.parent.mkdir(parents=True, exist_ok=True)
85
+ path.mkdir() # Atomic with the existing native XCTest entry's lock.
86
+ write(path / "owner.json", {"kind": "agent-device", "taskDir": str(root),
87
+ "udid": config["udid"], "session": config["session"], "startedAt": time.time()})
88
+ register(root)
89
+ yield
90
+
91
+
92
+ def finished(root, config):
93
+ path = device_lock(config)
94
+ owner = read(path / "owner.json")
95
+ if owner.get("kind") != "agent-device" or owner.get("taskDir") != str(root):
96
+ raise RuntimeError("Device owner changed; refusing release")
97
+ shutil.rmtree(path)
98
+ write(root / "finished.json", {"finishedAt": time.time()})
99
+
100
+
101
+ def active_local():
102
+ output = subprocess.check_output(["ps", "-ww", "-axo", "pid=,comm=,args="], text=True)
103
+ for line in output.splitlines():
104
+ fields = line.strip().split(None, 2)
105
+ if len(fields) != 3 or int(fields[0]) == os.getpid():
106
+ continue
107
+ name = Path(fields[1]).name
108
+ if name in ("xcodebuild", "xctest") or (name == "node" and "agent-device" in fields[2]):
109
+ raise RuntimeError(f"Resources busy: PID {fields[0]} ({name}); stop its owner before pruning")
110
+
111
+
112
+ def size(path):
113
+ return int(subprocess.check_output(["du", "-sk", str(path)], text=True).split()[0]) * 1024
114
+
115
+
116
+ def task_paths(workspace=None):
117
+ paths = set(read(BASE / "tasks.json") if (BASE / "tasks.json").exists() else [])
118
+ if workspace:
119
+ output = subprocess.check_output(["git", "-C", str(workspace), "worktree", "list", "--porcelain"], text=True)
120
+ for line in output.splitlines():
121
+ if line.startswith("worktree "):
122
+ base = Path(line[9:]) / ".runweave/mobile-qa"
123
+ paths.update(str(p.parent) for p in base.glob("*/session.json"))
124
+ return [Path(p) for p in sorted(paths)]
125
+
126
+
127
+ def legacy_builds(workspace, protected, all_history):
128
+ if not workspace:
129
+ return []
130
+ output = subprocess.check_output(["git", "-C", str(workspace), "worktree", "list", "--porcelain"], text=True)
131
+ builds = []
132
+ for line in output.splitlines():
133
+ if not line.startswith("worktree "):
134
+ continue
135
+ base = Path(line[9:]) / ".runweave"
136
+ for root, directories, files in os.walk(base, followlinks=False):
137
+ path = Path(root)
138
+ if any(path == Path(p) or Path(p) in path.parents for p in protected):
139
+ directories[:] = []
140
+ continue
141
+ if "info.plist" in files and (path / "Build").is_dir():
142
+ try:
143
+ data = plistlib.loads((path / "info.plist").read_bytes())
144
+ except (OSError, ValueError, plistlib.InvalidFileException):
145
+ data = {}
146
+ source = str(data.get("WorkspacePath", ""))
147
+ if source.endswith(".xcodeproj") and source.startswith(str(base.parent) + "/"):
148
+ builds.append({"path": str(path), "bytes": size(path), "workspace": source,
149
+ "remove": all_history})
150
+ directories[:] = []
151
+ continue
152
+ if path.name in ("Build", "node_modules", "state", "browser-profile", "user-data"):
153
+ directories[:] = []
154
+ return builds
155
+
156
+
157
+ def inventory(workspace=None, all_history=False):
158
+ protected = set()
159
+ for p in (Path.home() / ".runweave/native-device/locks").glob("*/owner.json"):
160
+ owner = read(p)
161
+ if owner.get("taskDir"):
162
+ protected.add(owner["taskDir"])
163
+ tasks = []
164
+ for path in task_paths(workspace):
165
+ if not path.exists() or path.is_symlink() or not (path / "session.json").is_file():
166
+ continue
167
+ config = read(path / "session.json")
168
+ if config.get("app") not in ("com.runweave.app.native", "com.runweave.suiji"):
169
+ continue
170
+ if path.name in ("", "state") or str(path) in protected:
171
+ continue
172
+ tasks.append({"path": str(path), "bytes": size(path), "modifiedAt": path.stat().st_mtime})
173
+ tasks.sort(key=lambda x: x["modifiedAt"], reverse=True)
174
+ total = 0
175
+ for index, task in enumerate(tasks):
176
+ total += task["bytes"]
177
+ task["remove"] = (all_history or index >= KEEP_TASKS or total > MAX_BYTES
178
+ or time.time() - task["modifiedAt"] > MAX_AGE)
179
+ protected_sessions = {read(Path(p) / "session.json").get("session") for p in protected
180
+ if (Path(p) / "session.json").is_file()}
181
+ logs = []
182
+ for path in (Path.home() / ".agent-device/logs").glob("qa-*"):
183
+ if path.is_symlink() or not path.is_dir() or path.name in protected_sessions:
184
+ continue
185
+ if not re.fullmatch(r"qa-[a-f0-9]{12}", path.name):
186
+ continue
187
+ logs.append({"path": str(path), "bytes": size(path), "modifiedAt": path.stat().st_mtime})
188
+ total = 0
189
+ for index, log in enumerate(sorted(logs, key=lambda x: x["modifiedAt"], reverse=True)):
190
+ total += log["bytes"]
191
+ log["remove"] = (all_history or index >= KEEP_TASKS or total > MAX_BYTES
192
+ or time.time() - log["modifiedAt"] > MAX_AGE)
193
+ caches = []
194
+ base = Path.home() / ".agent-device/apple-runner/derived"
195
+ for path in base.glob("*/*"):
196
+ manifest = path / ".agent-device-runner-cache.json"
197
+ if path.is_symlink() or not manifest.is_file():
198
+ continue
199
+ data = read(manifest)
200
+ bundle = next((v.split("=", 1)[1] for v in data.get("runnerBundleBuildSettings", [])
201
+ if v.startswith("AGENT_DEVICE_IOS_RUNNER_APP_BUNDLE_ID=")), "")
202
+ if not bundle.startswith("com.runweave."):
203
+ continue
204
+ caches.append({"path": str(path), "bytes": size(path), "bundleId": bundle,
205
+ "group": [data.get("deviceKind"), data.get("runnerSigningBuildSettings")],
206
+ "modifiedAt": manifest.stat().st_mtime, "remove": bundle != RUNNER_ID})
207
+ kept = []
208
+ for cache in sorted(caches, key=lambda x: x["modifiedAt"], reverse=True):
209
+ if not cache["remove"]:
210
+ if cache["group"] in kept:
211
+ cache["remove"] = True
212
+ else:
213
+ kept.append(cache["group"])
214
+ return {"tasks": tasks, "caches": caches, "logs": logs,
215
+ "legacyBuilds": legacy_builds(workspace, protected, all_history), "protectedTasks": sorted(protected),
216
+ "limits": {"tasks": KEEP_TASKS, "days": MAX_AGE // 86400, "bytes": MAX_BYTES}}
217
+
218
+
219
+ def prune(workspace=None, apply=False, all_history=False):
220
+ with guard():
221
+ active_local()
222
+ report = inventory(workspace, all_history)
223
+ if apply:
224
+ # Keep a small audit, not a second copy of the deleted build products.
225
+ write(BASE / "last-cleanup.json", report)
226
+ for item in [*report["tasks"], *report["caches"], *report["logs"], *report["legacyBuilds"]]:
227
+ if item["remove"] and Path(item["path"]).exists():
228
+ shutil.rmtree(item["path"])
229
+ write(BASE / "tasks.json", [t["path"] for t in report["tasks"] if not t["remove"]] + report["protectedTasks"])
230
+ return report
231
+
232
+
233
+ def main():
234
+ parser = argparse.ArgumentParser(description=__doc__)
235
+ parser.add_argument("action", choices=("status", "prune"))
236
+ parser.add_argument("--workspace", type=Path)
237
+ parser.add_argument("--apply", action="store_true")
238
+ parser.add_argument("--all-history", action="store_true")
239
+ args = parser.parse_args()
240
+ report = prune(args.workspace, args.apply, args.all_history) if args.action == "prune" else inventory(args.workspace)
241
+ print(json.dumps(report, indent=2))
242
+
243
+
244
+ if __name__ == "__main__":
245
+ try:
246
+ main()
247
+ except (OSError, ValueError, RuntimeError, subprocess.SubprocessError) as error:
248
+ raise SystemExit(str(error))