@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,328 @@
1
+ """Work-fact commands. Authentication and frozen-write transport stay in suiji.py."""
2
+ import datetime as dt
3
+ import hashlib
4
+ import json
5
+ import os
6
+ from pathlib import Path
7
+ import re
8
+ import tempfile
9
+ import uuid
10
+
11
+ STATUSES = {"progress", "discussed", "documented", "attempted", "agent-reported", "verified"}
12
+ FIELDS = {"workDate", "title", "statement", "status", "project"}
13
+
14
+
15
+ def validate(payload, fail, enforce_limits=True):
16
+ def require(ok, message):
17
+ if not ok:
18
+ raise fail(message)
19
+ def exact(value, keys, optional=()):
20
+ require(isinstance(value, dict) and not set(value) - set(keys) - set(optional) and set(keys) <= set(value), "INVALID_WORK_FIELDS")
21
+ def text(value, maximum, blank=False):
22
+ require(isinstance(value, str) and len(value) <= maximum and (blank or bool(value.strip())), "INVALID_WORK_TEXT")
23
+ require(all(not (ord(c) < 32 and c not in "\t\r\n") and not 127 <= ord(c) <= 159 and not 0xD800 <= ord(c) <= 0xDFFF for c in value), "INVALID_WORK_UNICODE")
24
+ def identity(value):
25
+ text(value, 240)
26
+ require(not value.startswith(("/", "~")) and not re.match(r"^[A-Za-z]:[\\/]", value) and not any(c in value for c in "\r\n\t"), "INVALID_STABLE_KEY")
27
+ def scope(value):
28
+ require(isinstance(value, str) and bool(re.fullmatch(r"[A-Za-z0-9_.:-]{1,120}", value)), "INVALID_SOURCE_SCOPE")
29
+ def timestamp(value):
30
+ require(isinstance(value, str) and bool(re.fullmatch(r"\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(?:\.\d+)?(?:Z|[+-]\d\d:\d\d)", value)), "INVALID_SOURCE_TIME")
31
+ return dt.datetime.fromisoformat(value.replace("Z", "+00:00"))
32
+ exact(payload, {"schemaVersion", "sourceNamespace", "sourceCollectedAt", "days"}, {"basedOnFeedRevision", "materialResults"})
33
+ require(payload["schemaVersion"] == 1, "INVALID_WORK_SCHEMA")
34
+ scope(payload["sourceNamespace"])
35
+ if "basedOnFeedRevision" in payload:
36
+ require(bool(re.fullmatch(r"0|[1-9][0-9]{0,18}", payload["basedOnFeedRevision"])), "INVALID_FEED_REVISION")
37
+ require(isinstance(payload["days"], list) and 1 <= len(payload["days"]) <= 100, "INVALID_WORK_DAYS")
38
+ results = payload.get("materialResults", [])
39
+ require(isinstance(results, list) and (not enforce_limits or len(results) <= 100), "INVALID_MATERIAL_RESULTS")
40
+ seen = set()
41
+ for item in results:
42
+ exact(item, {"recordId", "recordVersion", "sourceHash", "outcome", "eventKeys"})
43
+ uuid.UUID(item["recordId"])
44
+ require(item["recordId"] not in seen and type(item["recordVersion"]) is int and item["recordVersion"] > 0, "INVALID_MATERIAL_VERSION")
45
+ seen.add(item["recordId"])
46
+ require(bool(re.fullmatch(r"[a-f0-9]{64}", item["sourceHash"])), "INVALID_MATERIAL_HASH")
47
+ require(item["outcome"] in {"included", "merged", "no-new-fact"} and isinstance(item["eventKeys"], list) and len(item["eventKeys"]) <= 100, "INVALID_MATERIAL_OUTCOME")
48
+ require(bool(item["eventKeys"]) == (item["outcome"] != "no-new-fact"), "MATERIAL_EVENT_KEYS_REQUIRED")
49
+ for key in item["eventKeys"]:
50
+ identity(key)
51
+ dates, keys, times, count = set(), set(), [], 0
52
+ for day in payload["days"]:
53
+ exact(day, {"date", "requestedScopes", "receipts", "facts"})
54
+ date = dt.date.fromisoformat(day["date"])
55
+ require(date.isoformat() == day["date"] and day["date"] not in dates, "INVALID_WORK_DATE")
56
+ dates.add(day["date"])
57
+ requested = day["requestedScopes"]
58
+ require(isinstance(requested, list) and 1 <= len(requested) <= 100 and len(set(requested)) == len(requested), "INVALID_REQUESTED_SCOPES")
59
+ for s in requested:
60
+ scope(s)
61
+ receipts = {}
62
+ require(isinstance(day["receipts"], list), "INVALID_RECEIPTS")
63
+ for receipt in day["receipts"]:
64
+ exact(receipt, {"sourceScope", "status", "collectedAt", "from", "to"})
65
+ s = receipt["sourceScope"]
66
+ require(s in requested and s not in receipts and receipt["status"] in {"complete", "partial", "unavailable"}, "INVALID_RECEIPT_SCOPE")
67
+ start = dt.datetime.combine(date, dt.time(), dt.timezone(dt.timedelta(hours=8)))
68
+ require(timestamp(receipt["from"]) == start and timestamp(receipt["to"]) == start + dt.timedelta(days=1), "INVALID_RECEIPT_WINDOW")
69
+ times.append(timestamp(receipt["collectedAt"]))
70
+ receipts[s] = receipt
71
+ require(set(receipts) == set(requested), "MISSING_SOURCE_RECEIPT")
72
+ require(isinstance(day["facts"], list), "INVALID_FACTS")
73
+ for fact in day["facts"]:
74
+ exact(fact, {"externalKey", "eventKey", "title", "statement", "status", "project", "sourceRefs"})
75
+ for k in ("externalKey", "eventKey"):
76
+ identity(fact[k])
77
+ require(fact["externalKey"] not in keys, "DUPLICATE_EXTERNAL_KEY")
78
+ keys.add(fact["externalKey"])
79
+ require(isinstance(fact["title"], str), "INVALID_WORK_TITLE")
80
+ fact["title"] = fact["title"].strip()
81
+ text(fact["title"], 80)
82
+ require(not any(c in fact["title"] for c in "\n\r\t"), "INVALID_TITLE")
83
+ text(fact["statement"], 4000)
84
+ require(fact["status"] in STATUSES, "INVALID_WORK_STATUS")
85
+ if fact["project"] is not None:
86
+ require(isinstance(fact["project"], str), "INVALID_PROJECT")
87
+ fact["project"] = fact["project"].strip() or None
88
+ if fact["project"] is not None:
89
+ text(fact["project"], 80)
90
+ require(not any(c in fact["project"] for c in "\n\r\t"), "INVALID_PROJECT")
91
+ require(isinstance(fact["sourceRefs"], list) and 1 <= len(fact["sourceRefs"]) <= 100, "SOURCE_REQUIRED")
92
+ if all(ref["channel"] == "screen-timeline" for ref in fact["sourceRefs"]):
93
+ require(fact["status"] in {"documented", "discussed"}, "SCREEN_ONLY_IS_OBSERVATION")
94
+ for ref in fact["sourceRefs"]:
95
+ exact(ref, {"channel", "sourceScope", "nativeId"}, {"revision", "hash"})
96
+ require(ref["channel"] in {"local-agent", "feishu-message", "feishu-document", "browser-visit", "screen-timeline", "suiji-material"} and ref["sourceScope"] in receipts and receipts[ref["sourceScope"]]["status"] != "unavailable", "SOURCE_NOT_READ")
97
+ for field in ("nativeId", "revision"):
98
+ if field in ref:
99
+ identity(ref[field])
100
+ require(not any(c in ref[field] for c in "/\\") and "://" not in ref[field], "NATIVE_ID_REQUIRED")
101
+ require("hash" not in ref or bool(re.fullmatch(r"[a-fA-F0-9]{64}", ref["hash"])), "INVALID_SOURCE_HASH")
102
+ count += 1
103
+ require(timestamp(payload["sourceCollectedAt"]) == max(times), "SOURCE_TIME_MUST_MATCH_RECEIPTS")
104
+ require(not enforce_limits or (count <= 100 and len(json.dumps(payload, ensure_ascii=False, separators=(",", ":")).encode()) <= 200 * 1024), "WORK_PACKAGE_LIMIT: split whole days; prepare the next only after receipt confirmation")
105
+ return payload
106
+
107
+
108
+ def list_all(client, filters, fail):
109
+ items, days, cursor, revision = [], {}, None, None
110
+ while True:
111
+ page = client.call("list_work_facts", {**filters, **({"cursor": cursor} if cursor else {})})
112
+ if revision is not None and page["feedRevision"] != revision:
113
+ raise fail("WORK_FEED_CHANGED; discard this incomplete read and restart")
114
+ revision = page["feedRevision"]
115
+ items.extend(page["items"])
116
+ days.update({day["date"]: day for day in page["days"]})
117
+ next_cursor = page.get("nextCursor")
118
+ if not next_cursor:
119
+ return {"items": items, "days": sorted(days.values(), key=lambda d: d["date"], reverse=True), "nextCursor": None, "feedRevision": revision}
120
+ if next_cursor == cursor:
121
+ raise fail("INVALID_PAGINATION; incomplete read")
122
+ cursor = next_cursor
123
+
124
+
125
+ def identity_key(namespace, external):
126
+ return json.dumps([namespace, external], ensure_ascii=False, separators=(",", ":"))
127
+
128
+
129
+ def index_path(args):
130
+ return Path(args.config).with_suffix(".work-identities.json")
131
+
132
+
133
+ def atomic_private(path, data):
134
+ fd, temporary = tempfile.mkstemp(prefix=".work-index-", dir=path.parent)
135
+ try:
136
+ with os.fdopen(fd, "wb") as stream:
137
+ stream.write(data)
138
+ stream.flush()
139
+ os.fsync(stream.fileno())
140
+ os.replace(temporary, path)
141
+ finally:
142
+ if os.path.exists(temporary):
143
+ os.unlink(temporary)
144
+
145
+
146
+ def prepare(client, args, fail, private_read, exclusive_write):
147
+ payload = validate(json.loads(private_read(args.input)), fail, enforce_limits=False)
148
+ original = payload
149
+ material_dates = {}
150
+ for item in payload.get("materialResults", []):
151
+ record = client.call("get_record", {"recordId": item["recordId"]})["record"]
152
+ if not record.get("material") or record["material"]["sourceHash"] != item["sourceHash"] or record["version"] != item["recordVersion"]:
153
+ raise fail("MATERIAL_VERSION_CHANGED")
154
+ material_dates[item["recordId"]] = record["material"]["materialDate"]
155
+ def select_materials(value):
156
+ if "materialResults" in value:
157
+ dates = {d["date"] for d in value["days"]}
158
+ value["materialResults"] = [r for r in original["materialResults"] if material_dates[r["recordId"]] in dates]
159
+ return value
160
+ kept = []
161
+ for day in original["days"]:
162
+ trial = select_materials({**original, "days": kept + [day]})
163
+ trial["sourceCollectedAt"] = max((r["collectedAt"] for d in trial["days"] for r in d["receipts"]), key=lambda v: dt.datetime.fromisoformat(v.replace("Z", "+00:00")))
164
+ if len(trial.get("materialResults", [])) > 100 or sum(len(d["facts"]) for d in trial["days"]) > 100 or len(json.dumps(trial, ensure_ascii=False, separators=(",", ":")).encode()) > 200 * 1024:
165
+ if not kept:
166
+ raise fail("SINGLE_DAY_PACKAGE_LIMIT; refuse to truncate a day")
167
+ break
168
+ kept.append(day)
169
+ payload = {**original, "days": kept, "sourceCollectedAt": max((r["collectedAt"] for d in kept for r in d["receipts"]), key=lambda v: dt.datetime.fromisoformat(v.replace("Z", "+00:00")))}
170
+ payload = select_materials(payload)
171
+ remaining = original["days"][len(kept):]
172
+ validate(payload, fail)
173
+ page = list_all(client, {}, fail)
174
+ if payload.get("basedOnFeedRevision") not in (None, page["feedRevision"]):
175
+ raise fail("WORK_FEED_CHANGED; review the current facts before preparing again")
176
+ payload["basedOnFeedRevision"] = page["feedRevision"]
177
+ identity = {"endpoint": client.base, "serverId": client.config["serverId"], "ownerId": client.config["ownerId"]}
178
+ path = index_path(args)
179
+ index = json.loads(private_read(path)) if path.exists() else {"identity": identity, "keys": {}}
180
+ if index["identity"] != identity:
181
+ raise fail("INDEX_IDENTITY_MISMATCH")
182
+ previews = []
183
+ by_id = {f["id"]: f for f in page["items"]}
184
+ for day in payload["days"]:
185
+ for f in day["facts"]:
186
+ key = identity_key(payload["sourceNamespace"], f["externalKey"])
187
+ old = index["keys"].get(key)
188
+ if old is None and index.get("schemaVersion", 1) == 1:
189
+ old = index["keys"].get(payload["sourceNamespace"] + ":" + f["externalKey"])
190
+ if old and old["eventKey"] != f["eventKey"]:
191
+ raise fail("STABLE_EVENT_IDENTITY_CHANGED")
192
+ index["keys"][key] = {**(old or {}), "eventKey": f["eventKey"], "sourceNamespace": payload["sourceNamespace"], "externalKey": f["externalKey"]}
193
+ current = by_id.get((old or {}).get("id"))
194
+ previews.append({"date": day["date"], "externalKey": f["externalKey"], "title": f["title"], "status": f["status"], "manualFields": current["manualFields"] if current else [], "current": current})
195
+ atomic_private(path, json.dumps(index, ensure_ascii=False).encode())
196
+ out = Path(args.out)
197
+ out.mkdir(mode=0o700, parents=True, exist_ok=False)
198
+ frozen = {"identity": identity, "payload": payload, "indexPath": str(path.resolve())}
199
+ if remaining:
200
+ remainder = {k: v for k, v in original.items() if k != "basedOnFeedRevision"}
201
+ remainder["days"] = remaining
202
+ select_materials(remainder)
203
+ remainder["sourceCollectedAt"] = max((r["collectedAt"] for d in remaining for r in d["receipts"]), key=lambda v: dt.datetime.fromisoformat(v.replace("Z", "+00:00")))
204
+ exclusive_write(out / "remaining.json", json.dumps(remainder, ensure_ascii=False).encode())
205
+ exclusive_write(out / "prepared.json", json.dumps(frozen, ensure_ascii=False).encode())
206
+ exclusive_write(out / "preview.json", json.dumps({"feedRevision": page["feedRevision"], "facts": previews, "days": [{"date": d["date"], "count": len(d["facts"]), "receipts": d["receipts"]} for d in payload["days"]]}, ensure_ascii=False, indent=2).encode())
207
+ return {"prepared": str(out / "prepared.json"), "preview": str(out / "preview.json"), "facts": len(previews), "feedRevision": page["feedRevision"], "writes": 0, "remainingDays": len(remaining), "next": "Only after confirming this receipt, prepare remaining.json" if remaining else None}
208
+
209
+
210
+ def verify_result(client, intent, result, fail):
211
+ operation, args = intent["operation"], intent["arguments"]
212
+ if operation == "import_work_facts":
213
+ inputs = {f["externalKey"]: {**f, "workDate": d["date"]} for d in args["input"]["days"] for f in d["facts"]}
214
+ facts = result.get("facts", [])
215
+ if not result.get("importId") or len(facts) != len(inputs) or len({r["externalKey"] for r in facts}) != len(inputs):
216
+ raise fail("INVALID_IMPORT_RECEIPT; original request retained")
217
+ if sum(result.get(k, -1) for k in ("created", "updated", "unchanged")) != len(inputs):
218
+ raise fail("INVALID_IMPORT_COUNTS; original request retained")
219
+ for row in facts:
220
+ expected = inputs.get(row["externalKey"])
221
+ actual = row["fact"]
222
+ if not expected or actual["id"] != row["id"] or actual["eventKey"] != expected["eventKey"] or actual["version"] != row["version"]:
223
+ raise fail("INVALID_IMPORT_FACT_RECEIPT")
224
+ if any(actual[field] != expected[field] for field in FIELDS - set(actual["manualFields"])):
225
+ raise fail("IMPORT_EFFECTIVE_FIELDS_MISMATCH")
226
+ current = client.call("get_work_fact", {"factId": row["id"]})["fact"]
227
+ if current != actual:
228
+ if current.get("id") != actual["id"] or current.get("eventKey") != actual["eventKey"] or current.get("version", 0) <= actual["version"]:
229
+ raise fail("IMPORT_READBACK_MISMATCH; original request retained")
230
+ result.setdefault("changedSinceReceipt", []).append(row["id"])
231
+ for item in args["input"].get("materialResults", []):
232
+ receipt = client.call("get_material_result", {"recordId": item["recordId"], "recordVersion": item["recordVersion"]})
233
+ if receipt.get("sourceHash") != item["sourceHash"] or not receipt.get("processedAt"):
234
+ raise fail("MATERIAL_READBACK_MISMATCH; original request retained")
235
+ elif operation == "reclassify_work_facts":
236
+ facts = result.get("facts", [])
237
+ expected = {i["id"]: i for i in args["input"]["items"]}
238
+ if {f["id"] for f in facts} != set(expected) or any(f["project"] != expected[f["id"]].get("project", args["input"].get("project")) or f["version"] != expected[f["id"]]["expectedVersion"] + 1 for f in facts):
239
+ raise fail("INVALID_RECLASSIFICATION_RECEIPT")
240
+ for fact in facts:
241
+ if client.call("get_work_fact", {"factId": fact["id"]})["fact"] != fact:
242
+ raise fail("RECLASSIFICATION_READBACK_CHANGED")
243
+ return result
244
+
245
+
246
+ def reclassification(value, fail):
247
+ if not isinstance(value, dict) or set(value) not in ({"items", "project"}, {"items"}):
248
+ raise fail("INVALID_RECLASSIFICATION_FIELDS")
249
+ if not isinstance(value["items"], list) or not 1 <= len(value["items"]) <= 100:
250
+ raise fail("INVALID_RECLASSIFICATION_COUNT")
251
+ def project(value):
252
+ if value is None:
253
+ return None
254
+ if not isinstance(value, str):
255
+ raise fail("INVALID_PROJECT")
256
+ result = value.strip() or None
257
+ if result is not None and (len(result) > 80 or any(ord(c) < 32 or 127 <= ord(c) <= 159 or 0xD800 <= ord(c) <= 0xDFFF for c in result)):
258
+ raise fail("INVALID_PROJECT")
259
+ return result
260
+ seen = set()
261
+ for item in value["items"]:
262
+ fields = {"id", "expectedVersion"} | ({"project"} if "project" not in value else set())
263
+ if not isinstance(item, dict) or set(item) != fields:
264
+ raise fail("INVALID_RECLASSIFICATION_ITEM")
265
+ if not isinstance(item["id"], str):
266
+ raise fail("INVALID_FACT_ID")
267
+ uuid.UUID(item["id"])
268
+ if item["id"] in seen or type(item["expectedVersion"]) is not int or item["expectedVersion"] < 1:
269
+ raise fail("INVALID_RECLASSIFICATION_VERSION_OR_DUPLICATE")
270
+ seen.add(item["id"])
271
+ if "project" in item:
272
+ item["project"] = project(item["project"])
273
+ if "project" in value:
274
+ value["project"] = project(value["project"])
275
+ return value
276
+
277
+
278
+ def recovery_intent(args, config, fail, private_read):
279
+ """Opt-in automation is restricted to an already frozen work import."""
280
+ job = json.loads(private_read(args.job_config))
281
+ intent = json.loads(private_read(args.request))
282
+ if job.get("suiji", {}).get("autoPublish") is not True:
283
+ raise fail("AUTO_PUBLISH_DISABLED")
284
+ if Path(job["suiji"]["configPath"]).resolve() != Path(args.config).resolve():
285
+ raise fail("JOB_CONNECTION_MISMATCH")
286
+ if intent.get("operation") != "import_work_facts":
287
+ raise fail("WORK_IMPORT_ONLY")
288
+ expected = {k: config[k] for k in ("serverId", "ownerId")}
289
+ # endpoint normalization is done by the shared client before any write.
290
+ if any(intent.get("identity", {}).get(k) != v for k, v in expected.items()):
291
+ raise fail("REQUEST_IDENTITY_MISMATCH")
292
+ payload = intent["arguments"]["input"]
293
+ if payload.get("sourceNamespace") != job.get("sourceNamespace"):
294
+ raise fail("JOB_SOURCE_MISMATCH")
295
+ validate(payload, fail)
296
+ local = job["sources"]["localAgent"]["providers"]
297
+ allowed = {"agent:" + job["producerId"] + ":" + p for p in local}
298
+ if job["sources"]["feishu"]["enabled"]:
299
+ allowed.add("feishu:" + job["sources"]["feishu"]["accountScope"] + ":messages")
300
+ browser = job["sources"].get("browser", {})
301
+ screen = job["sources"].get("screen", {})
302
+ materials = job["sources"].get("materials", {})
303
+ for day in payload["days"]:
304
+ expected = set(allowed)
305
+ if browser.get("enabled") and day["date"] >= browser["effectiveFrom"]:
306
+ expected.add("browser:" + job["producerId"] + ":observed")
307
+ if screen.get("enabled") and day["date"] >= screen["effectiveFrom"]:
308
+ expected.add("screen:" + job["producerId"] + ":" + screen["expectedDeviceID"] + ":observed")
309
+ if materials.get("enabled") and day["date"] >= materials["effectiveFrom"]:
310
+ expected.add("materials:" + materials["accountScope"])
311
+ if set(day["requestedScopes"]) != expected:
312
+ raise fail("JOB_SCOPE_MISMATCH")
313
+ return intent
314
+
315
+
316
+ def reconcile(client, request, intent, fail, run_intent):
317
+ import time
318
+ for attempt in range(3):
319
+ try:
320
+ return run_intent(client, request, intent)
321
+ except fail as error:
322
+ # Explicit feed conflicts are terminal rejections, never unknown writes.
323
+ if not any(str(error).startswith(code) for code in
324
+ ("NETWORK_RESULT_UNKNOWN", "DEPENDENCY_UNAVAILABLE", "HTTP_502", "HTTP_503", "HTTP_504")):
325
+ raise
326
+ if attempt == 2:
327
+ raise
328
+ time.sleep(attempt + 1)
@@ -0,0 +1,75 @@
1
+ """Prepare a seven-calendar-day report from the authoritative Suiji work feed."""
2
+ import datetime as dt
3
+ import json
4
+ from pathlib import Path
5
+ import time
6
+
7
+ import work_records
8
+
9
+ SHANGHAI = dt.timezone(dt.timedelta(hours=8))
10
+
11
+
12
+ def period(anchor=None, now=None):
13
+ today = (now or dt.datetime.now(SHANGHAI)).astimezone(SHANGHAI).date()
14
+ friday = dt.date.fromisoformat(anchor) if anchor else today - dt.timedelta(days=(today.weekday() - 4) % 7)
15
+ if friday.weekday() != 4 or friday > today:
16
+ raise ValueError("ANCHOR_MUST_BE_A_PAST_OR_CURRENT_FRIDAY")
17
+ return {"from": (friday - dt.timedelta(days=7)).isoformat(), "to": (friday - dt.timedelta(days=1)).isoformat()}
18
+
19
+
20
+ def identity(client):
21
+ return {"endpoint": client.base, **{k: client.config[k] for k in ("serverId", "ownerId")}}
22
+
23
+
24
+ def prepare(client, args, fail, write):
25
+ window = period(args.anchor)
26
+ deadline = time.monotonic() + int(args.wait_seconds)
27
+ while True:
28
+ feed = work_records.list_all(client, {**window, "view": "logs"}, fail)
29
+ incomplete = [d for d in feed["days"] if d["coverage"] != "complete"]
30
+ if not incomplete or time.monotonic() >= deadline:
31
+ break
32
+ time.sleep(min(30, max(0, deadline - time.monotonic())))
33
+ sources = client.call("list_work_sources", window)
34
+ existing = client.call("find_work_report", window)["report"]
35
+ if existing and existing["manuallyEdited"]:
36
+ raise fail("REPORT_MANUALLY_EDITED; preserve the existing report")
37
+ payload = {**window, "basedOnFeedRevision": feed["feedRevision"],
38
+ "sourceFacts": [{"id": f["id"], "version": f["version"]} for f in feed["items"]]}
39
+ if existing:
40
+ payload["expectedVersion"] = existing["version"]
41
+ value = {"identity": identity(client), "payload": payload, "facts": feed["items"],
42
+ "days": feed["days"], "sources": sources, "existingReport": existing,
43
+ "incompleteDates": [d["date"] for d in incomplete]}
44
+ root = Path(args.out)
45
+ root.mkdir(mode=0o700, parents=True, exist_ok=False)
46
+ target = root / "prepared.json"
47
+ write(target, json.dumps(value, ensure_ascii=False).encode())
48
+ return {"prepared": str(target), **window, "factCount": len(feed["items"]),
49
+ "complete": not incomplete, "incompleteDates": value["incompleteDates"],
50
+ "instructions": "Read every fact, merge repeated matters across days and sources. Preserve outcome evidence and unresolved work. Save title/body JSON, then report-publish. Missing sources are not zero work."}
51
+
52
+
53
+ def publish(client, args, fail, read, write, run):
54
+ prepared = json.loads(read(args.input))
55
+ if prepared["identity"] != identity(client):
56
+ raise fail("PREPARED_IDENTITY_MISMATCH")
57
+ result = json.loads(read(args.file))
58
+ if set(result) != {"title", "body"} or not all(isinstance(result[k], str) and result[k].strip() for k in result):
59
+ raise fail("REPORT_TITLE_AND_BODY_REQUIRED")
60
+ import uuid
61
+ intent = {"identity": prepared["identity"], "operation": "publish_work_report",
62
+ "arguments": {"idempotencyKey": str(uuid.uuid4()), "input": {**prepared["payload"], **result}},
63
+ "receiptPath": str(Path(args.request).with_suffix(".receipt.json"))}
64
+ write(args.request, json.dumps(intent, ensure_ascii=False).encode())
65
+ return run(client, args.request, intent)
66
+
67
+
68
+ def verify(client, intent, result, fail):
69
+ value = result.get("report", {})
70
+ expected = intent["arguments"]["input"]
71
+ if not value.get("id") or any(value.get(k) != expected[k] for k in ("from", "to", "title", "body", "sourceFacts")):
72
+ raise fail("INVALID_REPORT_RESPONSE; original request retained")
73
+ actual = client.call("get_work_report", {"reportId": value["id"]})["report"]
74
+ if actual != value:
75
+ raise fail("REPORT_READBACK_CHANGED; original request retained")
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: sync-branch-hard-reset
3
+ description: 当用户给出一个 Git 分支名,并要求先 fetch、切换到该分支、如有本地代码先 stash、再用 reset --hard 将该分支更新到 origin/main 最新代码,最后还原之前 stash 的本地改动时使用。
4
+ ---
5
+
6
+ # 同步分支到 origin/main 最新
7
+
8
+ 仅当用户明确给出目标分支名,并希望把该本地分支强制同步到远程主分支 `origin/main` 的最新代码时使用。这个流程会执行 `git reset --hard`,必须严格按顺序操作。
9
+
10
+ ## 输入
11
+
12
+ - `branch_name`:用户给出的分支名。
13
+ - 如果用户给的是 `origin/<branch>`,本地分支名按 `<branch>` 处理,但 reset 基准仍然是 `origin/main`。
14
+ - 默认远端是 `origin`。用户明确指定其他 remote 时,才使用其他 remote。
15
+
16
+ ## 固定流程
17
+
18
+ 1. 检查当前状态:
19
+ - `git status --short`
20
+ - `git branch --show-current`
21
+ 2. 如果 `git status --short` 有输出,先 stash 本地改动:
22
+ - `git stash push -u -m "before hard reset <branch_name> $(date +%Y%m%d-%H%M%S)"`
23
+ - 记录 `git stash list -1` 的输出,并记住最新 stash ref,例如 `stash@{0}`。
24
+ - 如果 stash 失败,停止,不要继续 fetch、switch 或 reset。
25
+ 3. 更新远端引用:
26
+ - `git fetch --prune origin`
27
+ 4. 确认远程主分支存在:
28
+ - `git rev-parse --verify --quiet origin/main`
29
+ - 如果不存在,停止,并说明 `origin/main` 不存在;不要执行 `reset --hard`。
30
+ 5. 切换到目标分支:
31
+ - 如果本地分支已存在:`git switch <branch_name>`
32
+ - 如果本地分支不存在:`git switch -c <branch_name> --no-track origin/main`
33
+ 6. 强制同步到 `origin/main` 最新:
34
+ - `git reset --hard origin/main`
35
+ 7. 如果第 2 步创建过 stash,还原本地改动:
36
+ - `git stash pop <stash_ref>`
37
+ - 如果还原时出现冲突,停止并报告冲突文件;不要继续做其他修复,除非用户明确要求。
38
+ 8. 验证结果:
39
+ - `git status --short`
40
+ - `git branch -vv`
41
+ - `git log -1 --oneline`
42
+
43
+ ## 边界
44
+
45
+ - 不要在 stash 成功前执行 `reset --hard`。
46
+ - 如果本流程创建了 stash,reset 完成后必须尝试 `git stash pop` 还原;不要把用户的本地改动长期留在 stash 里不处理。
47
+ - 不要把 reset 目标改成 `origin/<branch_name>`,除非用户明确要求同步到同名远端分支。
48
+ - 不要 push。
49
+ - 不要删除分支。
50
+ - 不要处理和目标分支同步无关的改动。
51
+
52
+ ## 回复
53
+
54
+ 完成后简短说明:
55
+
56
+ - 当前分支。
57
+ - 已 reset 到 `origin/main` 的哪个最新 commit。
58
+ - 是否创建并还原了 stash;如果还原冲突,给出冲突文件和 stash 状态。
59
+ - `git status --short` 是否为空。
@@ -0,0 +1,90 @@
1
+ ---
2
+ name: update-runweave-backend
3
+ description: 通过 npm 更新 Linux 机器上的 Runweave CLI、Backend、Web 与 App Server,检查服务、登录、任务保活和开机自启;旧源码部署先迁移到 npm。用于“升级远程机器到最新版”“更新服务器 CLI 和服务”及无桌面后台;发布 npm 新版本使用 publish-runweave-server,不用于 macOS、桌面端、手机端或 Dev Session。
4
+ ---
5
+
6
+ # 更新 Runweave Linux 后台
7
+
8
+ 纯服务端统一使用 npm 发行包,不在服务器 git pull、编译或运行源码安装器升级。
9
+ 旧源码部署先执行一次迁移,随后进入相同的 npm 升级流程;本地 Mac 桌面端仍保留源码更新,
10
+ 由其专属流程处理。CI 从源码构建发行包,不属于目标机器的源码升级。
11
+
12
+ ## 范围与入口
13
+
14
+ 读取目标仓库的 `AGENTS.md`、`docs/deployment/npm-server-operations.md`、
15
+ `docs/cli/server-cli.md`、`docs/cli/configuration.md` 和 `docs/cli/service-management.md`。
16
+ 服务器本身不需要源码仓库;按本技能及已安装 CLI 的帮助操作。
17
+ 涉及配置版本变化时另读仓库的 `docs/deployment/configuration-upgrades.md`;
18
+ 没有仓库时按本技能的预检边界及发行包提供的版本声明、迁移入口操作,不猜测命令。
19
+ 旧源码部署另读 `docs/deployment/backend-standalone.md` 的一次性迁移流程。
20
+
21
+ 每次整套更新都建立下表。状态只能是待更新、已更新、已一致、不适用或受阻,并记录依据;缺少安装不能直接记为“不适用”。
22
+
23
+ 程序更新状态与运行/自启状态分列。用户主动停用只说明应保留 disabled/inactive,不证明程序版本已一致;若其程序属于本次更新范围,离线更新并保留停用状态,未核对版本前不能标“已一致”。
24
+
25
+ | 组件 | 默认处理 |
26
+ | ------------------------ | ----------------------------------------------------------------------------------- |
27
+ | Backend 与 Web 静态资源 | 必查、一起更新;包含 Activity、Evolution、定时任务 workers 和原生依赖 |
28
+ | App Server | 必查、更新安装与运行进程;缺少时补齐所需配置和托管,无法补齐则报告受阻 |
29
+ | 全局 `rw` | 必查,更新服务用户实际使用的入口及被服务/Hook 固定引用的入口 |
30
+ | Research MCP、隧道 | 已部署或目标明确需要时纳入,分别检查程序、配置、运行与自启 |
31
+ | 飞书 Bridge | `hub`/`standalone` 单独核对并默认保持现状,明确要求时才更新;`node` 随 Backend 更新 |
32
+ | 快照分享、其他配套服务 | 对照实际 unit、容器、配置与进程补入,不限于固定名称 |
33
+ | 随记、推送网关等独立产品 | 属于用户指定目标时纳入;同机存在也先说明归属,不因“整套后台”跨机器批量更新 |
34
+
35
+ 定时任务调度、Activity、Evolution 是 Backend 能力,不为它们另造 daemon。代理与隧道通常验证原配置和运行即可;不顺便升级操作系统、第三方 Agent CLI 或重新申请凭据。保留用户明确停用的服务,不借更新重新启用。
36
+
37
+ ## 1. 识别目标与恢复条件
38
+
39
+ - 确认 Linux 主机、服务运行用户、实例、配置根、Backend profile、安装来源及目标 npm 版本。SSH 用户不等于服务用户;profile 不会把本地文件操作变成远程操作。
40
+ - 记录已安装、active、running 版本及 sourceRevision,核对 registry 的目标精确版本和平台包。旧源码部署只记录当前基线及恢复材料,保留仓库和本地修改,不执行源码升级。
41
+ - 查 systemd 的已安装 unit 和运行 unit,也查用户级 unit、容器及手动进程;不能只看当前活跃服务或按名字含 `runweave` 筛选。记录真实 unit、owner、ExecStart、数据路径、运行版本、启用状态和依赖。检查输出前过滤 unit/进程参数中的凭据,不打印完整环境文件或进程环境。
42
+ - 保留原 HOME、CODEX_HOME、配置、Agent 登录态、Backend 身份、tmux socket、数据库和 Activity 正文密钥。备份配置、unit/drop-in、旧发布指针与可回退产物;运行中数据库使用其一致性备份方法,不把普通文件复制当成完整备份。
43
+ - 检查目标 Node、架构、libc、ABI、磁盘、依赖工具和权限;Server 使用匹配目标环境的 Node 22 平台包。容器或没有 systemd 的环境沿用已有 supervisor;报告不能执行 systemd 分支,不用 `nohup` 冒充开机自启。
44
+ - 维护通道必须能在 Backend/Bridge/MCP 停止后继续使用,例如独立 SSH。若当前 Agent 只能通过待更新服务控制主机,先建立可恢复的独立通道,再切换;不让更新切断唯一控制路径。
45
+
46
+ 先向用户简述目标、组件清单、目标版本、预计中断与恢复方式。已有整套更新授权时继续执行,不重复索要许可;目标机器或实例确实无法确定时才询问。
47
+
48
+ ## 2. 升级或迁移
49
+
50
+ 已由 `rw server` 管理的实例按 [NPM 机器升级](references/npm-update.md) 固定 CLI/Server 两个目标版本,
51
+ 在原 prefix 升级 CLI,再用 `rw server update --version` 升级服务。
52
+ 版本已一致且运行正常时不重新安装或重启。不重复 init、service install 或手动切换 current。
53
+
54
+ 旧源码或独立 Backend 包部署按仓库的 `docs/deployment/backend-standalone.md` 完成一次性迁移。
55
+ 先准备公开 npm 产物、备份和恢复条件,再停止原 owner;不对运行中的实例直接强行接管。
56
+ 缺少兼容的平台发行包时报告具体缺口,交给发布流程解决,不退回服务器源码构建。
57
+
58
+ 配置调整使用 `runweave-management`,保留 CAS 与敏感值私有输入。核对旧进程实际采用的
59
+ `terminal.tmux.shutdownPolicy=preserve` 与 Backend unit 的 `KillMode=process`;
60
+ 只修改配置不能保护仍采用 cleanup 的旧进程,需先排空任务或采用已验证的迁移方式。
61
+
62
+ ## 3. 服务托管与配套能力
63
+
64
+ 按 [systemd 检查](references/systemd.md) 核对唯一 owner、身份、持久自启与恢复条件。
65
+ 新装/迁移使用 `rw server service install --dry-run` 审查生成配置,再注册;正常更新复用现有托管。
66
+ 已有容器或 supervisor 时保留其持久启动机制,进程使用已发布 npm 产物,不叠加第二套 owner。
67
+
68
+ 独立 Hub/MCP/隧道按实际归属核对兼容性、配置、运行与自启。未包含在 Server npm 包的独立程序,
69
+ 不假定随包更新,也不调用旧源码安装器补齐;若本次明确要求更新,使用它自己的受支持发行入口,
70
+ 缺少发行产物则报告受阻,不把单独产品的失败掩盖为整套完成。保留用户主动停用的服务。
71
+
72
+ 每次切换后检查实际进程与健康。异常时停止后续切换,依据实际状态修复;
73
+ 回退前检查数据/schema 与配置兼容性,不自动回滚数据库、覆盖新增数据或启动遗留 unit 抢占实例。
74
+
75
+ ## 4. 验证更新与开机恢复
76
+
77
+ 逐项取得证据,不能只看安装返回值或 `systemctl is-active`:
78
+
79
+ - **版本**:实际进程的 entry、release/build ID、sourceRevision 或产物摘要对应目标基线;`command -v rw`、`rw version --json` 对应服务用户和 unit 使用的 CLI。
80
+ - **服务**:检查目标 unit 的 MainPID、退出结果、重启次数和本轮日志;App Server owner 与 systemd MainPID 一致,Backend 能连接它。保留原身份、配置路径与数据路径。
81
+ - **业务**:通过真实 profile 检查 `rw health`、`rw status`、项目/终端只读查询及已启用能力。状态快照不能覆盖独立服务时另行检查。浏览器交互验收使用 `playwright-cli`;没有执行就明确未验收,不能用 HTTP 200 代替 Web 可用。消息投递或向已有 Agent 输入不是默认验收动作。
82
+ - **会话**:对比升级前后 tmux server、pane、任务 PID 和输出,确认所声明的 Backend 重启保活;定时任务同时检查排空/恢复状态,不重放业务任务来制造成功。
83
+ - **自启配置**:逐项核对持久 enable 状态及启动依赖;用户级服务还须检查 linger。保留显式停用意图。静态 unit 须证明有持久启动依赖,`enabled-runtime` 不算跨重启生效。
84
+ - **整机重启**:只有用户已授权重启该机器时才执行。先保存检查清单、boot ID、基线和重连方式;重连后核对 boot ID 已改变,在手动启动任何服务之前检查全部服务和业务。补启动成功只能算修复,不能算该次自动恢复通过。
85
+
86
+ 没有实际整机重启时报告“自启配置已检查,整机重启未验证”,不因此阻止交付已完成的更新。整机重启会终止 tmux/Agent 进程;服务自启不承诺原业务任务自动续跑,也不要配置开机自动拉取代码或再次更新来代替启动已安装版本。
87
+
88
+ ## 交付
89
+
90
+ 报告目标机器/实例、目标 npm 版本与 sourceRevision、每个组件的旧新版本、安装与运行结果、自启配置和业务验证。将“运行验证通过”“自启配置通过”“整机重启验证通过”分开,说明未覆盖项及失败后的实际状态。任一必需组件受阻时不能宣布整套完成;无需为本技能运行安装或更新其他 skill。
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "升级 Runweave npm 后台"
3
+ short_description: "升级机器的 CLI 与 Server npm 包,验证服务、登录和任务保活"
4
+ default_prompt: "使用 $update-runweave-backend 通过 npm 升级目标 Linux 机器的 CLI 和 Server;旧源码部署先迁移,检查服务、登录、终端保活及开机自启。"
@@ -0,0 +1,68 @@
1
+ # NPM 部署的机器升级
2
+
3
+ 适用于已由 `rw server` 管理的 Linux Stable。通用合同见目标仓库的 `docs/cli/server-cli.md`;
4
+ 已知机器的路径约定见 `docs/deployment/npm-server-operations.md`。使用远端已安装 CLI 时先核对帮助,
5
+ 不要求目标机器安装源码仓库。旧源码部署先按仓库 `docs/deployment/backend-standalone.md` 一次性迁移;不再提供源码日常升级。
6
+
7
+ ## 固定目标与恢复材料
8
+
9
+ - 通过独立 SSH 在目标机器确认服务用户、HOME、Node、实例、配置根、npm prefix 和实际 rw wrapper。
10
+ 查询 `server status --json`、`server doctor --json`、CLI 包内 package.json 与 systemd 状态。
11
+ CLI 的源码版本与 npm 版本可能不同,不能只看 `rw version` 判断 npm 包版本。
12
+ - 用户说“升级后台到最新版”时,默认核对独立 CLI 和 Server 两个 npm 包。
13
+ 用户只要求其中一个时保持范围;版本已一致且运行正常时不重新安装或重启。
14
+ - 将目标 channel 解析成两个精确版本并记录。优先使用发布流程交接的已验证版本;
15
+ 默认 latest,不能因为 next 编号较大就自动选 next。确认对应平台包、Node ABI 与管理协议兼容。
16
+ - 保存配置、unit/drop-in、安装记录、发布指针、现有 npm 包版本及可恢复产物,数据库使用一致性备份。
17
+ 对比基线包括项目/终端 ID、tmux socket/pane/任务 PID。保留密钥和 Agent 登录态,不输出凭据。
18
+ - 向用户简述旧新版本、机器和短暂连接中断,已有升级授权时继续。服务原本停用则保持停用。
19
+ 普通 tmux Agent 可保活,但正在调用 HTTP/WS 的操作仍可能受影响。
20
+
21
+ ## 升级顺序
22
+
23
+ 切换前先核对目标发行版的配置要求。配置结构版本、域版本与编辑 revision 不是 npm 版本;
24
+ “最新配置”指目标程序要求的结构。候选迁移应在副本上预演并校验,备份后在受控切换阶段提交,
25
+ 业务只读取迁移后的目标结构。CLI 与旧 Server 共用配置时,不得在 CLI 更新后提前迁移共享域。
26
+ 核对所有实际配置消费者,缺少必需输入、迁移链或共同可用的切换方案时,在停服前报告受阻。
27
+
28
+ `rw config migrate --source-manifest` 仅导入旧文件。新版 CLI/Server 提供版本迁移;
29
+ 先读取 `rw server status --json`,只有 `cliCapabilities.updateDryRun === true` 才执行
30
+ `rw server update --version <目标版本> --dry-run`。旧 CLI 可能接受但忽略这个参数,
31
+ 不能用实际调用来试探是否支持预演;缺少能力字段时先升级到已验证支持它的 CLI。
32
+ 预演通过后用同一精确版本执行更新;提交时仍由 CLI 校验 CAS,不提前用 `config upgrade`
33
+ 修改运行实例。旧工具缺少入口且目标需要迁移时报告受阻,不手改版本号或现场写迁移脚本。
34
+ 数据兼容拒绝须交给发行流程处理,不跳过检查。
35
+
36
+ 1. CLI 若需要更新,在原 npm prefix、原服务 HOME 与 Node PATH 下安装核验过的精确版本。
37
+ 采用该机器已验证的 sudo/用户方式;不能用 SSH 登录用户的裸 `npm install -g` 改装到另一个 prefix。
38
+ 不覆盖实例 wrapper。读取实际包版本和 wrapper 指向,执行 CLI 帮助及 `server status` 确认管理能力可用。
39
+ 2. 只有 CLI 管理能力确认可用后,执行同一实例入口的
40
+ `rw server update --version <精确Server版本>`。由该命令执行下载/原生与兼容预检、维护租约、
41
+ 停止、安装、切换、原运行模式重启与健康检查。无需重复 init、service install 或手动改 current。
42
+ 3. 若出现 `SERVER_TASKS_ACTIVE`,列明受影响执行并等待后重查;不默认 force。
43
+ 数据不兼容、原生预检失败或安装归属不明时先解决,不停止旧服务冒险继续。
44
+ `--force` 不能解除数据与原生兼容限制。
45
+ 4. 安装或更新返回不确定时重新读取实际状态、包版本、发布指针和 update receipt,
46
+ 不凭旧日志重放整套操作。CLI 成功、Server 失败要分别报告,不称整套升级成功。
47
+
48
+ CLI 与 Server 的升级不是跨包/跨数据库原子事务。配置和 active 指针均未变化时,新版 CLI
49
+ 会尝试恢复原服务;已经提交配置或激活新版后不自动回滚,按回执判断实际状态。
50
+ CLI 切换后若管理能力失效,确认恢复条件后可在原 prefix 重装保存的旧 CLI;
51
+ Server 恢复使用兼容版本的 `server update --version`。不能自动恢复旧数据库覆盖升级后的写入,
52
+ 也不因 npm 更新失败重新启动遗留源码 unit 与新服务争抢实例。
53
+ 若配置已经迁移,旧程序启动前必须有匹配的配置恢复方案;核对备份身份、结构版本与
54
+ 升级后的配置修改,不能直接重装旧 CLI 并假定它能读新版配置。配置备份恢复不代表数据库可回退。
55
+
56
+ ## 真实验证与交付
57
+
58
+ - CLI npm 版本、Server installed/active/running 版本对应目标,Backend/App Server PID 与 supervisor 一致。
59
+ - 配置源/目标结构版本、执行的迁移步骤与恢复位置有据可查;发生配置变化时核对 saved/applied revision,未观测到消费者应用不能声称已生效。
60
+ - 对本应运行的服务检查健康、重启次数、日志和持久自启;本来停用的服务检查已安装版本并保留停用状态。
61
+ - 通过合法现有 profile 或私有凭据输入完成认证业务请求,核对项目/终端及 tmux 保活。
62
+ 验证登录时创建的临时 session 应注销,不泄露 token 或重置用户密码。
63
+ - 若用户报告某个入口登录失败,在那个入口复测前保持问题未解决;CLI 鉴权和健康 200 不等于用户 UI 成功。
64
+ - 独立 Hub/MCP/隧道按原范围单独核对,不因 Server 包更新顺带重启其他产品。
65
+ - 不默认整机重启。分别报告程序版本、运行验证、自启配置与真实重启验收,以及未完成项和恢复位置。
66
+
67
+ 交付应让用户看懂“哪台机器的 CLI 从什么版本到什么版本,Server 从什么版本到什么版本,
68
+ 服务与登录是否可用,现有任务是否保留”。仅需要升级机器时,不创建新的 npm 发行版。