@wular/coder 0.4.2 → 0.4.3

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 (320) hide show
  1. package/dist/actions-FzDNxMFf.js +20 -0
  2. package/dist/{adapter-BKVzTDnn.js → adapter-7SEiVsmp.js} +1 -1
  3. package/dist/{adapter-B0oYCI0S.js → adapter-BLEfUqoQ.js} +1 -1
  4. package/dist/{adapter-DPInwbJG.js → adapter-H4GlcKQz.js} +1 -1
  5. package/dist/{add-DRsPpQFl.js → add-B50dIJGd.js} +1 -1
  6. package/dist/{add-DkpUwhtO.js → add-D7X3gxap.js} +1 -1
  7. package/dist/{add-C2y-mVzl.js → add-DOEUHIe7.js} +1 -1
  8. package/dist/{add-CLYTF_up.js → add-QExQhTzi.js} +1 -1
  9. package/dist/{add-json-5uPnWPoD.js → add-json-Ck4KIZrT.js} +1 -1
  10. package/dist/{agent-r5mMcehf.js → agent-BPtnEf1q.js} +1 -1
  11. package/dist/{agent-hw3zKw8y.js → agent-BlQ_dNNm.js} +2 -2
  12. package/dist/{alias-_0Rwf2cA.js → alias-BwQBovke.js} +1 -1
  13. package/dist/{app-oE8G1-bi.js → app-y6BYm2eH.js} +1 -1
  14. package/dist/{approvals-DbVrsxec.js → approvals-Cc9cq5T1.js} +2 -2
  15. package/dist/{approve-DeAhFL-m.js → approve-oO9k2fnK.js} +2 -2
  16. package/dist/{apps-eujHiNca.js → apps-CU2YalX8.js} +1 -1
  17. package/dist/{archive-BCUfymIB.js → archive-C5c_HQS1.js} +2 -2
  18. package/dist/{archive-DZ6vpMHb.js → archive-CemlWlVY.js} +2 -2
  19. package/dist/archive-sweep-ehg-fWIt.js +1 -0
  20. package/dist/{args-BOEEdpWk.js → args-DcBCtXhz.js} +1 -1
  21. package/dist/{ask-BU2WVxVM.js → ask-Chu7Twu_.js} +2 -2
  22. package/dist/auth-BOyXPOtu.js +1 -0
  23. package/dist/auth-XbqKSbcD.js +1 -0
  24. package/dist/{chat-bridge-BS9WtP3X.js → chat-bridge-DXgZItGP.js} +1 -1
  25. package/dist/{chat-B_yhNTo0.js → chat-cknlIhVh.js} +1 -1
  26. package/dist/{cli-DWCR7iqa.js → cli-B1ObVrL4.js} +5 -5
  27. package/dist/cli.d.ts +1 -1
  28. package/dist/cli.js +1 -1
  29. package/dist/{client-D9IoAuDD.js → client-31YzOj-i.js} +1 -1
  30. package/dist/{config-12pK4qW7.js → config-DAE_qHYA.js} +1 -1
  31. package/dist/{create-D3f6q0Yq.js → create-CM8B8JxD.js} +1 -1
  32. package/dist/credentials-BXD4Qptk.js +1 -0
  33. package/dist/dash/manifest.json +949 -915
  34. package/dist/dash/public/assets/chunks/{agent-pills-dd0b7643e125bbf1.js → agent-pills-b6a6da91c9559d9f.js} +1 -1
  35. package/dist/dash/public/assets/chunks/{agent-settings-form-45ae6aeaaed2b568.js → agent-settings-form-b615c677046cd6f2.js} +1 -1
  36. package/dist/dash/public/assets/chunks/agents-grid-f2e7b4ff9e11b6e3.js +1 -0
  37. package/dist/dash/public/assets/chunks/{badge-676b01e0c615bf7b.js → badge-215c7b2631dafc69.js} +1 -1
  38. package/dist/dash/public/assets/chunks/{card-e0901d68b79dfa93.js → card-e86dcc81326d2b14.js} +1 -1
  39. package/dist/dash/public/assets/chunks/{combo-952a457d52360d88.js → combo-09e246dc9a517fa8.js} +1 -1
  40. package/dist/dash/public/assets/chunks/composer-417166b029f48c47.js +1 -0
  41. package/dist/dash/public/assets/chunks/composer-645ae8fa97a35280.js +1 -0
  42. package/dist/dash/public/assets/chunks/{confirm-f2fe4ba9905a89c6.js → confirm-5ae484241ad888fd.js} +1 -1
  43. package/dist/dash/public/assets/chunks/{connect-apps-661f3b3a85f1776a.js → connect-apps-4147c45f45fde2b1.js} +1 -1
  44. package/dist/dash/public/assets/chunks/{connect-repositories-5389ec8701a3deac.js → connect-repositories-77591110836bdf03.js} +1 -1
  45. package/dist/dash/public/assets/chunks/credentials-list-e005a0783ec93465.js +2 -0
  46. package/dist/dash/public/assets/chunks/{custom-range-03ba6fb2ade7d282.js → custom-range-463e119af4681c61.js} +1 -1
  47. package/dist/dash/public/assets/chunks/{editor-34cb529d6d8a4b09.js → editor-804b84f4fe6539cd.js} +4 -4
  48. package/dist/dash/public/assets/chunks/{engines-list-2f1acee3ecc8461a.js → engines-list-ceab51f13c690e8c.js} +1 -1
  49. package/dist/dash/public/assets/chunks/{field-901f1f35c18c39c9.js → field-aa0a4b98a976781e.js} +1 -1
  50. package/dist/dash/public/assets/chunks/filter-91144ac2eec6297f.js +1 -0
  51. package/dist/dash/public/assets/chunks/format-105c706345987fb2.js +1 -0
  52. package/dist/dash/public/assets/chunks/heads-a42817b32d2d7f08.js +1 -0
  53. package/dist/dash/public/assets/chunks/{instructions-052fa45a9daf6db6.js → instructions-3a1dcaff2d868aa5.js} +1 -1
  54. package/dist/dash/public/assets/chunks/instructions-6c6f981fffaa31e4.js +1 -0
  55. package/dist/dash/public/assets/chunks/{list-87b359bebd26986a.js → list-7270361464fc3c04.js} +1 -1
  56. package/dist/dash/public/assets/chunks/{mcp-list-b42f0d2ee463b37d.js → mcp-list-2e715d48666b54ad.js} +1 -1
  57. package/dist/dash/public/assets/chunks/{models-list-0669d26fd662aec3.js → models-list-d3c40f94c761a6e5.js} +1 -1
  58. package/dist/dash/public/assets/chunks/paged-3ddb6077bef42752.js +1 -0
  59. package/dist/dash/public/assets/chunks/{platform-actions-c92ca3c6198a9387.js → platform-actions-271ec3b99a64280b.js} +1 -1
  60. package/dist/dash/public/assets/chunks/runners-list-767e49c7d0ec833a.js +1 -0
  61. package/dist/dash/public/assets/chunks/{segmented-358ff2b4992b8384.js → segmented-de4386ccaac7304d.js} +1 -1
  62. package/dist/dash/public/assets/chunks/{select-1013702bdfb1ade4.js → select-a90307706cffa6e0.js} +1 -1
  63. package/dist/dash/public/assets/chunks/{sentinel-c972a33dc69a5135.js → sentinel-b5e032b38604dfd3.js} +1 -1
  64. package/dist/dash/public/assets/chunks/shared-init-7f81ae7bc8c82438.js +2 -0
  65. package/dist/dash/public/assets/chunks/shared-init-933c7f9ee85be766.js +5 -0
  66. package/dist/dash/public/assets/chunks/{tail-7c27aab8ba268bd9.js → tail-4891e727ee526792.js} +1 -1
  67. package/dist/dash/public/assets/chunks/task-actions-ce854925a2dc78fd.js +1 -0
  68. package/dist/dash/public/assets/chunks/task-ddfddeaf07fb684c.js +1 -0
  69. package/dist/dash/public/assets/chunks/task-view-c37dcee08f21a279.js +5 -0
  70. package/dist/dash/public/assets/chunks/tasks-list-baef587999f322d8.js +1 -0
  71. package/dist/dash/public/assets/chunks/{toolbar-f964fa864699f095.js → toolbar-8d98313606ad8a2d.js} +1 -1
  72. package/dist/dash/public/assets/chunks/{versions-list-fc2e0d2a7382e049.js → versions-list-532690efd9f1b0ea.js} +1 -1
  73. package/dist/dash/public/assets/{dash-account-96fc41be318839fa.css → dash-account-edc56e85dbaaabe0.css} +1 -1
  74. package/dist/dash/public/assets/dash-agents-edba57b67e4005d0.css +1 -0
  75. package/dist/dash/public/assets/dash-agents-new-fe22253fbada2fbf.css +1 -0
  76. package/dist/dash/public/assets/dash-agents-param-slug-adf52e9dacb2d825.css +1 -0
  77. package/dist/dash/public/assets/dash-agents-param-slug-edit-a2937a347689ef29.css +1 -0
  78. package/dist/dash/public/assets/dash-agents-param-slug-platforms-265ba13db32a460d.css +1 -0
  79. package/dist/dash/public/assets/dash-agents-param-slug-settings-8afc52eb0372bc4b.css +1 -0
  80. package/dist/dash/public/assets/dash-agents-param-slug-tasks-6193e646be68dbd2.css +1 -0
  81. package/dist/dash/public/assets/dash-agents-param-slug-usage-ceadb3a1c911c402.css +1 -0
  82. package/dist/dash/public/assets/{dash-settings-53b8e6a8f656fa1a.css → dash-settings-cf1997cd7f72e518.css} +1 -1
  83. package/dist/dash/public/assets/dash-settings-param-tab-b44dac8e79a560e6.css +1 -0
  84. package/dist/dash/public/assets/dash-tasks-916c7100a8058aa3.css +1 -0
  85. package/dist/dash/public/assets/dash-tasks-param-id-194a6ffc20e872f2.css +1 -0
  86. package/dist/dash/public/assets/{dash-usage-884943221f76ad93.css → dash-usage-40940b289f85e0b6.css} +1 -1
  87. package/dist/dash/public/assets/pnext-client-13aee92bef5c9e3f.js +1 -0
  88. package/dist/dash/public/assets/pnext-client-1f2686b2044f0df6.js +1 -0
  89. package/dist/dash/public/assets/pnext-client-26130234ebad7067.js +1 -0
  90. package/dist/dash/public/assets/pnext-client-311e35b0076bf406.js +1 -0
  91. package/dist/dash/public/assets/pnext-client-4ade1bf75c9c3d87.js +1 -0
  92. package/dist/dash/public/assets/pnext-client-61cd31b687ede1da.js +1 -0
  93. package/dist/dash/public/assets/{pnext-client-2693db10b197ade1.js → pnext-client-61db65dc4223217a.js} +1 -1
  94. package/dist/dash/public/assets/pnext-client-6ea656e7705e3f2a.js +1 -0
  95. package/dist/dash/public/assets/pnext-client-7fd0f793f0322cb9.js +1 -0
  96. package/dist/dash/public/assets/pnext-client-88159c0840fcfa4a.js +1 -0
  97. package/dist/dash/public/assets/pnext-client-b03f0c47c066b4f3.js +1 -0
  98. package/dist/dash/public/assets/{pnext-client-1afa4148bea69ad2.js → pnext-client-d6478835f543f901.js} +1 -1
  99. package/dist/dash/public/assets/pnext-client-dadb8359021ed590.js +1 -0
  100. package/dist/dash/public/assets/pnext-client-de07532d6aaebf2c.js +1 -0
  101. package/dist/dash/public/assets/pnext-client-f87a31890c8ff224.js +1 -0
  102. package/dist/dash/public/assets/pnext-client-ffe1c123a8e2a350.js +1 -0
  103. package/dist/{default-CwQXCtoB.js → default-BMvUMTFp.js} +1 -1
  104. package/dist/default-B_nKaX0-.js +1 -0
  105. package/dist/{delete-cS01oOIb.js → delete-Bjteibld.js} +2 -2
  106. package/dist/{delete-BD6AnCLg.js → delete-riCIKZwj.js} +2 -2
  107. package/dist/{disable-BMWWeYFQ.js → disable-DQC56YFy.js} +1 -1
  108. package/dist/{discover-Dvr_3_Xr.js → discover-Qanr5TEO.js} +1 -1
  109. package/dist/{discover-Cfx5RPU7.js → discover-lgTYwoQp.js} +2 -2
  110. package/dist/dispatch-BsW_1m7e.js +14 -0
  111. package/dist/{docs-DWegDRiu.js → docs-DFs7lOJp.js} +1 -1
  112. package/dist/{docs-BX65z2Iu.js → docs-DKROso-4.js} +2 -2
  113. package/dist/{enable-Cfzeau2x.js → enable-D2DqZvcU.js} +1 -1
  114. package/dist/{env-CRf6wkM2.js → env-YRY3I60r.js} +1 -1
  115. package/dist/exec-DuUkLMqg.js +11 -0
  116. package/dist/executor-vMppVLB6.js +10 -0
  117. package/dist/flow/builtin/review.js +1 -1
  118. package/dist/flow/index.d.ts +1 -1
  119. package/dist/flow/index.js +1 -1
  120. package/dist/{flow-kAxxVOiR.js → flow-DmERAnR8.js} +1 -1
  121. package/dist/{github-actions-DwUzm4hC.js → github-actions-C_NkHVJq.js} +1 -1
  122. package/dist/http-D01Udu4u.js +1 -0
  123. package/dist/{index-CZjFX5zV.d.ts → index-B1L4zXZH.d.ts} +2 -1
  124. package/dist/{init-C4tDFH4G.js → init-Bd6JHzBc.js} +1 -1
  125. package/dist/integrations-B2CavXR1.js +5 -0
  126. package/dist/integrations-D1Dwy1kt.js +1 -0
  127. package/dist/lib/broker.js +2 -2
  128. package/dist/{list-DuPqU3fk.js → list-4Uo-0v9s.js} +1 -1
  129. package/dist/{list-COAo7eZd.js → list-B0ujEZhd.js} +3 -3
  130. package/dist/{list-5Ljf9TxF.js → list-B5oa1Bhy.js} +2 -2
  131. package/dist/{list-vOvIpbOH.js → list-BjE_l6la.js} +1 -1
  132. package/dist/{list-J8d_zh-o.js → list-Ck9ibCs1.js} +1 -1
  133. package/dist/{list-vpyS-hv8.js → list-DhgK4Zc4.js} +1 -1
  134. package/dist/{list-way5oLO0.js → list-KvL7AUhD.js} +2 -2
  135. package/dist/{list-DzGuMkQy.js → list-byYLBl1U.js} +1 -1
  136. package/dist/{load-BpEsAn51.js → load-SnZd7xG1.js} +1 -1
  137. package/dist/{local-H3uvqEbq.js → local-BRy1EUq2.js} +1 -1
  138. package/dist/log-view-DeJstSkw.js +3 -0
  139. package/dist/{login-BBw95-S3.js → login-C-ahtDKV.js} +1 -1
  140. package/dist/{login-CNmeRAL7.js → login-zpwke8g1.js} +1 -1
  141. package/dist/{logout-j0dTo_Ib.js → logout-CI6Kf-T6.js} +1 -1
  142. package/dist/{maintenance-DkLVtqM7.js → maintenance-BAzr9Jlr.js} +1 -1
  143. package/dist/{match-CXAjDhg7.js → match-DxV1d49D.js} +1 -1
  144. package/dist/{mcp-BgKb2Cdk.js → mcp-CmcL1MCG.js} +1 -1
  145. package/dist/{mcp-CsmBtlW9.js → mcp-mhXwtGQT.js} +1 -1
  146. package/dist/{migrate-N-85_N7J.js → migrate-Czh3TEK5.js} +1 -1
  147. package/dist/{migrate-D4nzYhk8.js → migrate-w7KfzUAR.js} +1 -1
  148. package/dist/{model-B79MFtRV.js → model-JRoTH9QK.js} +1 -1
  149. package/dist/models-C-S7HqSb.js +1 -0
  150. package/dist/{prompt-CEuBMNhk.js → prompt-CMXmt2l9.js} +4 -4
  151. package/dist/{push-DbdnbZYt.js → push-B8BhTyZs.js} +1 -1
  152. package/dist/queue-CirjEskI.js +117 -0
  153. package/dist/refresh-Bmy2r1Ee.js +1 -0
  154. package/dist/{remote-miQNTVRa.js → remote-CxFnEjZl.js} +1 -1
  155. package/dist/{remove-BNzbUhaK.js → remove-C15WLaXT.js} +1 -1
  156. package/dist/{remove-D-QeeZQL.js → remove-CTZYjjSr.js} +1 -1
  157. package/dist/{remove-CLpL12Ya.js → remove-CTl-H0f0.js} +1 -1
  158. package/dist/{remove-CaYH9Cna.js → remove-DX2FVo5b.js} +1 -1
  159. package/dist/rename-D1g4TnHQ.js +1 -0
  160. package/dist/{result-BfTfJayl.js → result-D49VN8PM.js} +3 -3
  161. package/dist/result-DGWyUHYU.js +18 -0
  162. package/dist/{resume-aZ8yWDBh.js → resume-ywzc7z6A.js} +2 -2
  163. package/dist/{review-BEhDcX4b.js → review-ZC0xG8XY.js} +2 -2
  164. package/dist/{rotate-key-BqnKhTK8.js → rotate-key-Bf8_99ck.js} +1 -1
  165. package/dist/{run-BWbabvub.js → run-D7SJ-ieT.js} +2 -2
  166. package/dist/run-DoRQSC_K.js +2 -0
  167. package/dist/{run-BdPjxaZU.js → run-ukCf2Mdy.js} +1 -1
  168. package/dist/runner-D-REfOUe.js +1 -0
  169. package/dist/{runner-sUpWJ_k0.js → runner-wDYhkVsM.js} +1 -1
  170. package/dist/schema-DoNO0dPh.js +1 -0
  171. package/dist/sdk.d.ts +4 -2
  172. package/dist/sdk.js +1 -1
  173. package/dist/serve-BJ_Mbm2m.js +8 -0
  174. package/dist/{serve-C0WC-QrV.js → serve-C1MMhM1F.js} +2 -2
  175. package/dist/{serve-CcObDKKQ.js → serve-DtrOHaoS.js} +2 -2
  176. package/dist/{serve-Ck95047c.js → serve-P9pFkEnE.js} +1 -1
  177. package/dist/{serve-BTeomYxW.js → serve-yjSw0B1a.js} +1 -1
  178. package/dist/{server-BxLFZL80.js → server-DDWTnmbx.js} +1 -1
  179. package/dist/{setup-host-DLd_j2Uw.js → setup-host-L6Rnn5Cz.js} +1 -1
  180. package/dist/{shared-BLkGRKty.js → shared-XsUX_ZZb.js} +1 -1
  181. package/dist/{show-DzoQIs75.js → show-CU-jqJ90.js} +1 -1
  182. package/dist/{show-FC3dJcD-.js → show-DVJmB2u-.js} +1 -1
  183. package/dist/{status-BU3DR1XU.js → status-CBydR7LE.js} +1 -1
  184. package/dist/{steer-P_38hRRD.js → steer-Cm_sHZqs.js} +2 -2
  185. package/dist/{stop-BJGDRPsp.js → stop-DJS7DAPJ.js} +1 -1
  186. package/dist/{stop-BWY6k6v5.js → stop-TrebIIuv.js} +2 -2
  187. package/dist/store-BrNMqJgk.js +42 -0
  188. package/dist/store-j8icrG0v.js +19 -0
  189. package/dist/task-C8lmcNsf.js +1 -0
  190. package/dist/{task-DeglY79z.js → task-CpUI19o2.js} +4 -4
  191. package/dist/task-CvSqiwxo.js +1 -0
  192. package/dist/{test-BrSrhop9.js → test-CDKz4jY_.js} +1 -1
  193. package/dist/{tools-CgswhJzh.js → tools-DBFeoosk.js} +1 -1
  194. package/dist/{types-I5Cwtl_K.d.ts → types-DMGBYB_K.d.ts} +3 -1
  195. package/dist/{unalias-mMHXqok7.js → unalias-BfQFBnuK.js} +1 -1
  196. package/dist/{update-DbOWToPy.js → update-C4FFOie8.js} +1 -1
  197. package/dist/{upgrade-D6oC9HQI.js → upgrade-DLJqMnUQ.js} +2 -2
  198. package/dist/{usage-Cb8Dtv9V.js → usage-CSh-xwQ2.js} +1 -1
  199. package/dist/{usage-DMs-IIJC.js → usage-D8mc4qXK.js} +1 -1
  200. package/dist/{watch-BcMQXGYO.js → watch-CQu-tJKZ.js} +2 -2
  201. package/dist/{watch-eE2XiwsC.js → watch-DmwaEvoi.js} +2 -2
  202. package/dist/{wire-BeT1Axeo.js → wire-DzGLZ3-O.js} +1 -1
  203. package/dist/worker-BLKTMLqa.js +1 -0
  204. package/dist/worker-nHemduM_.js +9 -0
  205. package/dist/{workflow-Cshghoas.js → workflow-IrouAus_.js} +1 -1
  206. package/docs/mcp.md +1 -1
  207. package/migrations/0000_initial.sql +8 -0
  208. package/migrations/meta/0000_snapshot.json +75 -1
  209. package/migrations/meta/_journal.json +1 -1
  210. package/package.json +1 -1
  211. package/plugins/agents/skills/coder/SKILL.md +1 -0
  212. package/plugins/claude/.claude-plugin/plugin.json +1 -1
  213. package/plugins/claude/skills/dispatch/SKILL.md +1 -1
  214. package/plugins/cursor/.cursor-plugin/plugin.json +1 -1
  215. package/plugins/cursor/skills/coder/SKILL.md +1 -0
  216. package/src/client/index.ts +10 -2
  217. package/src/client/types.ts +18 -0
  218. package/src/core/defaults.ts +11 -0
  219. package/src/core/task/log-view.ts +120 -6
  220. package/src/server/dash/app/dash/agents/(list)/agent-menu.tsx +4 -0
  221. package/src/server/dash/app/dash/agents/(list)/agents-grid.tsx +18 -35
  222. package/src/server/dash/app/dash/agents/(list)/loading.tsx +7 -1
  223. package/src/server/dash/app/dash/agents/[slug]/(tabs)/layout.tsx +2 -1
  224. package/src/server/dash/app/dash/layout.tsx +13 -3
  225. package/src/server/dash/app/dash/settings/[tab]/credentials-list.tsx +20 -13
  226. package/src/server/dash/app/dash/settings/[tab]/runners-list.tsx +13 -12
  227. package/src/server/dash/app/dash/tasks/[id]/activity.tsx +49 -4
  228. package/src/server/dash/app/dash/tasks/[id]/task-actions.tsx +43 -6
  229. package/src/server/dash/app/dash/tasks/[id]/task-view.css +52 -31
  230. package/src/server/dash/app/dash/tasks/[id]/task-view.tsx +143 -51
  231. package/src/server/dash/app/dash/tasks/composer.css +4 -0
  232. package/src/server/dash/app/dash/tasks/composer.tsx +6 -5
  233. package/src/server/dash/app/dash/tasks/list/task.ts +29 -1
  234. package/src/server/dash/app/dash/tasks/list/tasks-list.css +20 -7
  235. package/src/server/dash/app/dash/tasks/list/tasks-list.tsx +256 -109
  236. package/src/server/dash/app/dash/tasks/list/tasks-section.tsx +9 -13
  237. package/src/server/dash/app/dash/tasks/page.tsx +3 -35
  238. package/src/server/dash/comps/frame/loading-card.tsx +4 -3
  239. package/src/server/dash/comps/frame/page-head.css +10 -0
  240. package/src/server/dash/comps/frame/page-head.tsx +3 -2
  241. package/src/server/dash/comps/frame/task-toasts.tsx +196 -50
  242. package/src/server/dash/comps/nav/side-toggle.tsx +15 -4
  243. package/src/server/dash/comps/ui/card.css +1 -0
  244. package/src/server/dash/comps/ui/filter.css +64 -0
  245. package/src/server/dash/comps/ui/filter.tsx +336 -0
  246. package/src/server/dash/comps/ui/icons.ts +2 -0
  247. package/src/server/dash/comps/ui/menu.tsx +4 -0
  248. package/src/server/dash/comps/ui/select.tsx +2 -2
  249. package/src/server/dash/comps/ui/toolbar.css +14 -0
  250. package/src/server/dash/utils/client.ts +21 -0
  251. package/src/server/dash/utils/format.ts +12 -4
  252. package/src/server/dash/utils/paged.ts +14 -6
  253. package/dist/actions-Mk3FSlpJ.js +0 -20
  254. package/dist/archive-sweep-Cxbh8yAI.js +0 -1
  255. package/dist/auth-CBWTmAPA.js +0 -1
  256. package/dist/auth-Dmn2U7rr.js +0 -1
  257. package/dist/credentials-l6dsrZLL.js +0 -1
  258. package/dist/dash/public/assets/chunks/agents-grid-b906da80c31fc035.js +0 -1
  259. package/dist/dash/public/assets/chunks/composer-49f9e7c5c4dfda3b.js +0 -1
  260. package/dist/dash/public/assets/chunks/composer-f331d00837143aee.js +0 -1
  261. package/dist/dash/public/assets/chunks/credentials-list-e6177d0943517929.js +0 -2
  262. package/dist/dash/public/assets/chunks/format-eb03fc9d9744d960.js +0 -1
  263. package/dist/dash/public/assets/chunks/heads-1570a3a6db331979.js +0 -1
  264. package/dist/dash/public/assets/chunks/instructions-d0a4b0d95009c262.js +0 -1
  265. package/dist/dash/public/assets/chunks/paged-bc6fa0c2b9d52ed7.js +0 -1
  266. package/dist/dash/public/assets/chunks/runners-list-9fffa50432c470c9.js +0 -1
  267. package/dist/dash/public/assets/chunks/shared-init-20e199043ff5d00f.js +0 -2
  268. package/dist/dash/public/assets/chunks/shared-init-88cce66bb3cfe1e5.js +0 -5
  269. package/dist/dash/public/assets/chunks/task-actions-a9603d520434baab.js +0 -1
  270. package/dist/dash/public/assets/chunks/task-fa8b82e95e771c4a.js +0 -1
  271. package/dist/dash/public/assets/chunks/task-view-f7039cb330bcb0b5.js +0 -3
  272. package/dist/dash/public/assets/chunks/tasks-list-2a905b4a0c3a9042.js +0 -1
  273. package/dist/dash/public/assets/dash-agents-290a7b21c7dc0c92.css +0 -1
  274. package/dist/dash/public/assets/dash-agents-new-a7a07bf4ebda24c2.css +0 -1
  275. package/dist/dash/public/assets/dash-agents-param-slug-69a72fb0bbd14cc2.css +0 -1
  276. package/dist/dash/public/assets/dash-agents-param-slug-edit-397bdfb2f0ca328c.css +0 -1
  277. package/dist/dash/public/assets/dash-agents-param-slug-platforms-a7b3b7247c27f1d2.css +0 -1
  278. package/dist/dash/public/assets/dash-agents-param-slug-settings-8389b7d0555e8ccf.css +0 -1
  279. package/dist/dash/public/assets/dash-agents-param-slug-tasks-5987b8aea5e8f30d.css +0 -1
  280. package/dist/dash/public/assets/dash-agents-param-slug-usage-19abc69e1d4e6b0a.css +0 -1
  281. package/dist/dash/public/assets/dash-settings-param-tab-ac61fdfdd6fd533f.css +0 -1
  282. package/dist/dash/public/assets/dash-tasks-cc0b1d32874b731c.css +0 -1
  283. package/dist/dash/public/assets/dash-tasks-param-id-02b8c7bd99cc1090.css +0 -1
  284. package/dist/dash/public/assets/pnext-client-17ba55bb57a1f4da.js +0 -1
  285. package/dist/dash/public/assets/pnext-client-43f52a07f8067b1b.js +0 -1
  286. package/dist/dash/public/assets/pnext-client-4594b693fe612835.js +0 -1
  287. package/dist/dash/public/assets/pnext-client-73f73e24f8141fb6.js +0 -1
  288. package/dist/dash/public/assets/pnext-client-7574da4651b40eae.js +0 -1
  289. package/dist/dash/public/assets/pnext-client-7b3a2c1092cbbb02.js +0 -1
  290. package/dist/dash/public/assets/pnext-client-816fe5fc96d3f768.js +0 -1
  291. package/dist/dash/public/assets/pnext-client-86cb956b448b0887.js +0 -1
  292. package/dist/dash/public/assets/pnext-client-8b64e3c030164288.js +0 -1
  293. package/dist/dash/public/assets/pnext-client-8f6161084c595a22.js +0 -1
  294. package/dist/dash/public/assets/pnext-client-9203ec11926e5d04.js +0 -1
  295. package/dist/dash/public/assets/pnext-client-a38b446f941d44df.js +0 -1
  296. package/dist/dash/public/assets/pnext-client-bd8d51aaa095e8a4.js +0 -1
  297. package/dist/dash/public/assets/pnext-client-e9821d1f1bdb281d.js +0 -1
  298. package/dist/default-De8FXiWz.js +0 -1
  299. package/dist/dispatch-BKeAch9E.js +0 -14
  300. package/dist/exec-RZFLclKX.js +0 -11
  301. package/dist/executor-BvAA7Cgw.js +0 -10
  302. package/dist/http-Bkg_OQ6r.js +0 -1
  303. package/dist/integrations-BAgdVDhj.js +0 -5
  304. package/dist/integrations-D-L3uQRj.js +0 -1
  305. package/dist/log-view-dg0TlKLA.js +0 -1
  306. package/dist/models-_5LVGC3m.js +0 -1
  307. package/dist/queue-C9fSdE_X.js +0 -116
  308. package/dist/refresh-BDmap1RA.js +0 -1
  309. package/dist/rename-Bhcb4t9F.js +0 -1
  310. package/dist/result-D8DsvJDu.js +0 -15
  311. package/dist/run-Dqe38jX8.js +0 -2
  312. package/dist/runner-BPpiJvHx.js +0 -1
  313. package/dist/schema-CU2iFkp8.js +0 -1
  314. package/dist/serve-DA5I2qXj.js +0 -4
  315. package/dist/store-B3ZHoBJY.js +0 -8
  316. package/dist/store-BLi19UDE.js +0 -42
  317. package/dist/task-C6VAg5WU.js +0 -1
  318. package/dist/task-b2BK481M.js +0 -1
  319. package/dist/worker-CXndxmGF.js +0 -9
  320. package/dist/worker-DrucI22w.js +0 -1
@@ -9,8 +9,7 @@ import type { AgentCardRow, IntegrationInfo, Paged } from '@coder/client/types';
9
9
  import { Empty } from '@/comps/ui/card';
10
10
  import { initial } from '@/utils/format';
11
11
  import { AgentPills, BrandIcon, Platform } from '@/app/dash/agents/agent/agent-pills';
12
- import { Menu, MenuRadio } from '@/comps/ui/menu';
13
- import { Icon } from '@/comps/ui/icon';
12
+ import { Filter } from '@/comps/ui/filter';
14
13
  import { NewAgentMenu } from './agent-menu';
15
14
  import { Search, Toolbar, queryOf, useFilters } from '@/comps/ui/toolbar';
16
15
  import { Tail } from '@/comps/ui/tail';
@@ -93,39 +92,23 @@ export function AgentsGrid({
93
92
  <>
94
93
  <Toolbar head={head} action={<NewAgentMenu />}>
95
94
  <Search value={values.q} label="Search agents" onInput={value => set('q', value, 250)} />
96
- <Menu
97
- class="filter-more"
98
- label="More filters"
99
- summaryClass={`field-btn${values.platform || values.type ? ' on' : ''}`}
100
- summary="Filter"
101
- >
102
- <p class="pop-label">Platform</p>
103
- <div role="group" aria-label="Platform">
104
- <MenuRadio on={!values.platform} onPick={() => set('platform', '')}>
105
- All platforms
106
- </MenuRadio>
107
- {catalog.map(entry => (
108
- <MenuRadio
109
- key={entry.id}
110
- on={values.platform === entry.id}
111
- onPick={() => set('platform', entry.id)}
112
- >
113
- <span class="pf">
114
- <BrandIcon brand={entry.brand} />
115
- {entry.name}
116
- </span>
117
- </MenuRadio>
118
- ))}
119
- </div>
120
- <p class="pop-label">Source</p>
121
- <div role="group" aria-label="Source">
122
- {KINDS.map(([value, label]) => (
123
- <MenuRadio key={value} on={values.type === value} onPick={() => set('type', value)}>
124
- {label}
125
- </MenuRadio>
126
- ))}
127
- </div>
128
- </Menu>
95
+ <Filter
96
+ name="agents"
97
+ facets={[
98
+ {
99
+ key: 'platform',
100
+ label: 'Platform',
101
+ options: catalog.map((entry): [string, string] => [entry.id, entry.name]),
102
+ icon: value => {
103
+ const entry = catalog.find(item => item.id === value);
104
+ return entry ? <BrandIcon brand={entry.brand} /> : undefined;
105
+ },
106
+ },
107
+ { key: 'type', label: 'Source', options: KINDS },
108
+ ]}
109
+ values={values}
110
+ onChange={set}
111
+ />
129
112
  </Toolbar>
130
113
  {children}
131
114
  {list.rows.length ? (
@@ -1,4 +1,5 @@
1
1
  import { HEADS } from '@/comps/frame/heads';
2
+ import { iAgent } from '@/comps/ui/icons';
2
3
  import { Page } from '@/comps/frame/page-head';
3
4
  import { LoadingToolbar } from '@/comps/frame/loading-card';
4
5
  import { Loading } from '@/comps/ui/card';
@@ -7,7 +8,12 @@ import { Loading } from '@/comps/ui/card';
7
8
  export default function AgentsLoading() {
8
9
  return (
9
10
  <Page>
10
- <LoadingToolbar head={HEADS.agents} search="Search agents" more action="New agent" />
11
+ <LoadingToolbar
12
+ head={HEADS.agents}
13
+ search="Search agents"
14
+ more
15
+ action={{ label: 'New agent', icon: iAgent }}
16
+ />
11
17
  <Loading label="Loading agents" />
12
18
  </Page>
13
19
  );
@@ -1,7 +1,7 @@
1
1
  import type { ComponentChildren } from 'preact';
2
2
  import { dynamic } from '@wular/pnext/dynamic';
3
3
 
4
- import { iGit, iPencil } from '@/comps/ui/icons';
4
+ import { iGit, iPencil, iPlus } from '@/comps/ui/icons';
5
5
  import { Link } from '@wular/pnext/link';
6
6
  import { load } from '@/api/load';
7
7
  import type { AgentRow, TasksPage } from '@coder/client/types';
@@ -56,6 +56,7 @@ function LoadingAgentHead({ back }: { back: ComponentChildren }) {
56
56
  back={back}
57
57
  actions={
58
58
  <button type="button" class="btn" disabled>
59
+ <Icon d={iPlus} />
59
60
  New task
60
61
  </button>
61
62
  }
@@ -213,6 +213,15 @@ async function ActiveCount({ count }: { count: Promise<TasksPage> }) {
213
213
  ) : null;
214
214
  }
215
215
 
216
+ // Without a saved choice, mid-width screens start with the sidebar collapsed, before first paint.
217
+ const SIDE_AUTO = `(() => {
218
+ const app = document.currentScript.parentElement;
219
+ const mid = matchMedia('(min-width: 761px) and (max-width: 1279px)');
220
+ const sync = () => /(?:^|; )side=/.test(document.cookie) || app.classList.toggle('side-min', mid.matches);
221
+ sync();
222
+ mid.addEventListener('change', sync);
223
+ })()`;
224
+
216
225
  // `serve` opens /dash#token=…: the fragment never reaches the server, so the form posts it while the page loads, busy from first paint.
217
226
  const TOKEN_FROM_HASH = `(() => {
218
227
  const token = /(?:^|&)token=([^&]+)/.exec(location.hash.slice(1))?.[1];
@@ -296,10 +305,11 @@ export default function DashLayout({
296
305
  const { pathname, host } = new URL(request.url);
297
306
  const me = load(request).me();
298
307
  const active = load(request).tasks.list({ cursor: '', limit: 1, summary: true, counts: true });
299
- const collapsed = /(?:^|; )side=min(?:;|$)/.test(request.headers.get('cookie') ?? '');
308
+ const side = /(?:^|; )side=(min|max)(?:;|$)/.exec(request.headers.get('cookie') ?? '')?.[1];
300
309
 
301
310
  return (
302
- <div class={collapsed ? 'app side-min' : 'app'}>
311
+ <div class={side === 'min' ? 'app side-min' : 'app'}>
312
+ {side ? null : <script dangerouslySetInnerHTML={{ __html: SIDE_AUTO }} />}
303
313
  <header class="top">
304
314
  <div class="top-l">
305
315
  <Drawer />
@@ -332,7 +342,7 @@ export default function DashLayout({
332
342
  )}
333
343
  </nav>
334
344
  <div class="side-foot">
335
- <SideToggle collapsed={collapsed} />
345
+ <SideToggle collapsed={side === 'min'} />
336
346
  <WithMe me={me}>{who => <ServerMenu me={who} host={host} />}</WithMe>
337
347
  </div>
338
348
  </aside>
@@ -4,7 +4,7 @@ import './credentials-list.css';
4
4
 
5
5
  import { useEffect, useRef, useState } from 'preact/hooks';
6
6
 
7
- import { client } from '@/utils/client';
7
+ import { client, poll } from '@/utils/client';
8
8
  import { iCheck, iCopy, iDots } from '@/comps/ui/icons';
9
9
  import { useRouter } from '@wular/pnext/navigation/client';
10
10
  import type { CredentialRow, EngineStatus, Me } from '@coder/client/types';
@@ -336,23 +336,30 @@ export function EngineLogins({ status: initial }: { status: EngineStatus }) {
336
336
  const [status, setStatus] = useState(initial);
337
337
  const [busy, setBusy] = useState('');
338
338
  const [error, setError] = useState('');
339
- const waiting = useRef<ReturnType<typeof setInterval>>();
339
+ const waiting = useRef<() => void>();
340
340
 
341
341
  // A sign-in finishes in the browser the engine opened; the status says when.
342
342
  const watch = (engine: string) => {
343
- clearInterval(waiting.current);
343
+ waiting.current?.();
344
344
  const until = Date.now() + 5 * 60_000;
345
- waiting.current = setInterval(() => {
346
- void client.engines.status().then(next => {
347
- setStatus(next);
348
- if (next[engine as 'claude' | 'codex']?.signedIn || Date.now() > until) {
349
- clearInterval(waiting.current);
350
- setBusy('');
351
- }
352
- });
345
+ // A status read from a sign-in already stopped never stops the next one.
346
+ let current = true;
347
+ const stopPoll = poll(async () => {
348
+ const next = await client.engines.status();
349
+ if (!current) return;
350
+ setStatus(next);
351
+ if (next[engine as 'claude' | 'codex']?.signedIn || Date.now() > until) {
352
+ stop();
353
+ setBusy('');
354
+ }
353
355
  }, 2000);
356
+ const stop = () => {
357
+ current = false;
358
+ stopPoll();
359
+ };
360
+ waiting.current = stop;
354
361
  };
355
- useEffect(() => () => clearInterval(waiting.current), []);
362
+ useEffect(() => () => waiting.current?.(), []);
356
363
  const act = (engine: string, action: 'login' | 'logout') => {
357
364
  setBusy(`${engine}:${action}`);
358
365
  setError('');
@@ -413,7 +420,7 @@ export function EngineLogins({ status: initial }: { status: EngineStatus }) {
413
420
  type="button"
414
421
  class="btn ghost sm"
415
422
  onClick={() => {
416
- clearInterval(waiting.current);
423
+ waiting.current?.();
417
424
  setBusy('');
418
425
  }}
419
426
  >
@@ -4,7 +4,7 @@ import './runners-list.css';
4
4
 
5
5
  import { useEffect, useRef, useState } from 'preact/hooks';
6
6
 
7
- import { client } from '@/utils/client';
7
+ import { client, poll } from '@/utils/client';
8
8
  import {
9
9
  iCheck,
10
10
  iCopy,
@@ -246,15 +246,19 @@ function AddRunner({
246
246
  useEffect(() => {
247
247
  if (!pairing) return;
248
248
  const until = Math.min(pairing.expiresAt, Date.now() + 15 * 60_000);
249
- const timer = setInterval(() => {
249
+ // A list read from a pairing already gone never ends the next one.
250
+ let current = true;
251
+ const stop = poll(async () => {
250
252
  if (Date.now() > until) return cancel();
251
- void client.runners.list().then(rows => {
252
- if (!rows.items.some(row => !known.includes(row.id))) return;
253
- onAdded(rows);
254
- cancel();
255
- });
253
+ const rows = await client.runners.list();
254
+ if (!current || !rows.items.some(row => !known.includes(row.id))) return;
255
+ onAdded(rows);
256
+ cancel();
256
257
  }, 2000);
257
- return () => clearInterval(timer);
258
+ return () => {
259
+ current = false;
260
+ stop();
261
+ };
258
262
  }, [pairing]);
259
263
 
260
264
  const cancel = () => {
@@ -411,10 +415,7 @@ export function RunnersList({ first, me }: { first: Runners; me: Me }) {
411
415
  const items = sortedRunners(rows.items);
412
416
 
413
417
  // Online dots stay fresh while the tab is open.
414
- useEffect(() => {
415
- const timer = setInterval(() => void client.runners.list().then(setRows, () => {}), 30_000);
416
- return () => clearInterval(timer);
417
- }, []);
418
+ useEffect(() => poll(() => client.runners.list().then(setRows), 30_000), []);
418
419
 
419
420
  const change = async (act: () => Promise<unknown>) => {
420
421
  setError('');
@@ -40,7 +40,7 @@ const ICONS: Record<TaskDisplayRow['kind'], string> = {
40
40
 
41
41
  /** Rows long enough to fold to one line. */
42
42
  const foldable = (row: TaskDisplayRow) =>
43
- Boolean(row.detail) || row.title.length > 120 || row.title.includes('\n');
43
+ Boolean(row.detail || row.result?.detail) || row.title.length > 120 || row.title.includes('\n');
44
44
 
45
45
  const atEnd = () => innerHeight + scrollY >= document.documentElement.scrollHeight - 48;
46
46
 
@@ -65,15 +65,43 @@ function useWindowVirtualizer(count: number, list: { current: HTMLElement | null
65
65
  return virtual;
66
66
  }
67
67
 
68
+ /** A call's or approval's outcome on the right: a spinner and the time so far, then ✓ or ✗ and how long it took. */
69
+ function CallState({ row, running }: { row: TaskDisplayRow; running: boolean }) {
70
+ const [, tick] = useReducer((n: number) => n + 1, 0);
71
+ useEffect(() => {
72
+ if (!running) return;
73
+ const timer = setInterval(() => tick(0), 1000);
74
+ return () => clearInterval(timer);
75
+ }, [running]);
76
+ const result = row.result;
77
+ const took = running ? Math.max(0, Date.now() - row.at) : result?.durationMs;
78
+ const text = [
79
+ row.state,
80
+ result && !result.ok && result.exitCode !== undefined ? `exit ${result.exitCode}` : '',
81
+ took ? formatDuration(took) : '',
82
+ ]
83
+ .filter(Boolean)
84
+ .join(' · ');
85
+
86
+ return (
87
+ <span class={`act-state${result && !result.ok ? ' bad' : ''}`}>
88
+ {running ? <i class="spin" /> : result ? <Icon d={result.ok ? iCheck : iX} /> : null}
89
+ {text}
90
+ </span>
91
+ );
92
+ }
93
+
68
94
  function Row({
69
95
  row,
70
96
  tz,
71
97
  open,
98
+ running,
72
99
  onToggle,
73
100
  }: {
74
101
  row: TaskDisplayRow;
75
102
  tz: string;
76
103
  open: boolean;
104
+ running: boolean;
77
105
  onToggle: () => void;
78
106
  }) {
79
107
  const title = useRef<HTMLSpanElement>(null);
@@ -83,6 +111,7 @@ function Row({
83
111
  }, [row.title]);
84
112
  const fold = open || clipped || foldable(row);
85
113
  const failed = row.tone === 'error';
114
+ const timed = row.kind === 'tool' || row.state !== undefined;
86
115
  const extra =
87
116
  row.kind === 'tool-result'
88
117
  ? [
@@ -100,7 +129,7 @@ function Row({
100
129
  return (
101
130
  <Tag
102
131
  type={fold ? 'button' : undefined}
103
- class={`act ${row.kind}${row.tone ? ` ${row.tone}` : ''}${row.separated ? ' sep' : ''}${open ? ' open' : ''}`}
132
+ class={`act ${row.kind}${row.tone ? ` ${row.tone}` : ''}${row.separated ? ' sep' : ''}${timed ? ' timed' : ''}${open ? ' open' : ''}`}
104
133
  aria-expanded={fold ? open : undefined}
105
134
  onClick={fold ? onToggle : undefined}
106
135
  >
@@ -108,11 +137,20 @@ function Row({
108
137
  <Icon d={row.kind === 'tool-result' && failed ? iX : ICONS[row.kind]} />
109
138
  <span class="act-text">
110
139
  <span class="act-title" ref={title}>
111
- {row.title}
140
+ {row.kind === 'tool' && row.tool && row.title.startsWith(`${row.tool} `) ? (
141
+ <>
142
+ <span class="act-tool">{row.tool}</span>
143
+ {row.title.slice(row.tool.length)}
144
+ </>
145
+ ) : (
146
+ row.title
147
+ )}
112
148
  </span>
113
149
  {extra ? <span class="act-detail">{extra}</span> : null}
114
- {row.detail ? <span class="act-detail">{row.detail}</span> : null}
150
+ {row.detail && (open || !row.state) ? <span class="act-detail">{row.detail}</span> : null}
151
+ {open && row.result?.detail ? <span class="act-detail">{row.result.detail}</span> : null}
115
152
  </span>
153
+ {timed ? <CallState row={row} running={running} /> : null}
116
154
  {fold ? <Icon d={iDown} class="act-chev" /> : null}
117
155
  </Tag>
118
156
  );
@@ -132,6 +170,8 @@ export function Activity({
132
170
  const [open, setOpen] = useState<Set<number>>(new Set());
133
171
  const [follow, setFollow] = useState(live);
134
172
  const virtual = useWindowVirtualizer(rows.length, list);
173
+ // Calls the agent has moved on from without a result are not still running.
174
+ const settled = rows.findLastIndex(row => row.kind === 'assistant' || row.kind === 'reasoning');
135
175
 
136
176
  useEffect(() => {
137
177
  const onScroll = () => setFollow(atEnd());
@@ -173,6 +213,11 @@ export function Activity({
173
213
  row={row}
174
214
  tz={tz}
175
215
  open={open.has(row.seq)}
216
+ running={
217
+ live &&
218
+ !row.result &&
219
+ (row.state !== undefined || (row.kind === 'tool' && item.index > settled))
220
+ }
176
221
  onToggle={() =>
177
222
  setOpen(value => {
178
223
  const next = new Set(value);
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { useState } from 'preact/hooks';
3
+ import { useEffect, useState } from 'preact/hooks';
4
4
 
5
5
  import { client } from '@/utils/client';
6
6
  import { useRouter } from '@wular/pnext/navigation/client';
@@ -12,6 +12,7 @@ import { ConfirmDialog } from '@/comps/ui/confirm';
12
12
  import { Menu, MenuItem } from '@/comps/ui/menu';
13
13
  import { Icon } from '@/comps/ui/icon';
14
14
  import { iDots } from '@/comps/ui/icons';
15
+ import { showToast, toastError } from '@/comps/frame/task-toasts';
15
16
 
16
17
  export function approvalParts(approval: unknown): {
17
18
  id?: string;
@@ -114,6 +115,14 @@ export function TaskActions({ task, live }: { task: TaskRow; live: boolean }) {
114
115
  )}
115
116
  <Menu summary={<Icon d={iDots} />} summaryClass="icon-btn" label="More actions">
116
117
  {live && !archived ? <MenuItem title="Archive" onClick={archive} /> : null}
118
+ <MenuItem
119
+ title="Copy task id"
120
+ onClick={() =>
121
+ void navigator.clipboard
122
+ .writeText(task.task.id)
123
+ .then(() => showToast('Copied', task.task.id))
124
+ }
125
+ />
117
126
  <MenuItem title="Delete" danger onClick={() => setDeleting('ask')} />
118
127
  </Menu>
119
128
  <ConfirmDialog
@@ -131,9 +140,26 @@ export function TaskActions({ task, live }: { task: TaskRow; live: boolean }) {
131
140
 
132
141
  export function Approval({ task }: { task: TaskRow }) {
133
142
  const action = useAction(task.task.id);
143
+ const [busy, setBusy] = useState<'accept' | 'decline'>();
144
+ // A sent decision hides its card at once; the events stream catches up after.
145
+ const [decided, setDecided] = useState<string>();
134
146
  const { id, action: tool, reason } = approvalParts(task.approval);
135
- const decide = (decision: 'accept' | 'decline') =>
136
- void action.run('approve', { approvalId: id, decision });
147
+
148
+ const decide = async (decision: 'accept' | 'decline') => {
149
+ setBusy(decision);
150
+ const ok = await action.run('approve', { approvalId: id, decision });
151
+ setBusy(undefined);
152
+ if (!ok) return;
153
+ setDecided(id);
154
+ showToast(decision === 'accept' ? 'Allowed' : 'Denied', 'The task continues.');
155
+ };
156
+
157
+ useEffect(() => {
158
+ if (action.error) toastError('Not sent', action.error);
159
+ }, [action.error]);
160
+
161
+ if (id && decided === id) return null;
162
+
137
163
  return (
138
164
  <Card
139
165
  tone="accent"
@@ -141,11 +167,22 @@ export function Approval({ task }: { task: TaskRow }) {
141
167
  actions={
142
168
  task.task.flow === 'default' ? (
143
169
  <>
144
- <Flash {...action} />
145
- <button type="button" class="btn outline sm" onClick={() => decide('decline')}>
170
+ <button
171
+ type="button"
172
+ class="btn outline sm"
173
+ disabled={Boolean(busy)}
174
+ aria-busy={busy === 'decline'}
175
+ onClick={() => void decide('decline')}
176
+ >
146
177
  Deny
147
178
  </button>
148
- <button type="button" class="btn sm" onClick={() => decide('accept')}>
179
+ <button
180
+ type="button"
181
+ class="btn sm"
182
+ disabled={Boolean(busy)}
183
+ aria-busy={busy === 'accept'}
184
+ onClick={() => void decide('accept')}
185
+ >
149
186
  Allow
150
187
  </button>
151
188
  </>
@@ -1,60 +1,52 @@
1
- /* task head: the id line under the title */
2
- .head .lead:has(.task-id) {
1
+ /* task head: the facts line under the title */
2
+ .head .lead:has(.fact) {
3
3
  display: flex;
4
4
  align-items: center;
5
- gap: 12px;
6
- }
7
- .head.stuck .lead:has(.task-id) {
8
- display: none;
9
- }
10
- .task-id {
5
+ gap: 16px;
11
6
  font-size: 12px;
12
- overflow: hidden;
13
- text-overflow: ellipsis;
14
7
  }
15
- .head .copy {
16
- display: inline-grid;
17
- place-items: center;
18
- flex: none;
19
- margin-left: -8px;
20
- padding: 2px;
21
- border: 0;
22
- background: none;
8
+ .fact {
9
+ display: inline-flex;
10
+ align-items: center;
11
+ gap: 5px;
12
+ white-space: nowrap;
13
+ }
14
+ .fact .ic {
15
+ width: 12px;
16
+ height: 12px;
23
17
  color: var(--dim);
24
- cursor: pointer;
25
18
  }
26
- .head .copy:hover {
27
- color: var(--fg);
19
+ .fact-dim {
20
+ color: var(--dim);
28
21
  }
29
- .head .copy .ic {
30
- width: 13px;
31
- height: 13px;
22
+ .head.stuck .lead:has(.fact) {
23
+ display: none;
32
24
  }
33
25
  /* phones: the actions sit on the back link's row, the title gets the full width under it */
34
26
  @media (max-width: 760px) {
35
- .head:has(.task-id) .back {
27
+ .head:has(.fact) .back {
36
28
  height: 34px;
37
29
  }
38
- .head:has(.task-id) .title-row > h1 {
30
+ .head:has(.fact) .title-row > h1 {
39
31
  flex-basis: 100%;
40
32
  }
41
- .head:has(.task-id) .actions {
33
+ .head:has(.fact) .actions {
42
34
  position: absolute;
43
35
  top: 0;
44
36
  right: 16px;
45
37
  width: auto;
46
38
  flex-wrap: nowrap;
47
39
  }
48
- .head.stuck:has(.task-id) .actions {
40
+ .head.stuck:has(.fact) .actions {
49
41
  position: static;
50
42
  }
51
- .head.stuck:has(.task-id) .actions > .menu {
43
+ .head.stuck:has(.fact) .actions > .menu {
52
44
  display: inline;
53
45
  }
54
- .head.stuck:has(.task-id) .title-row > h1 {
46
+ .head.stuck:has(.fact) .title-row > h1 {
55
47
  flex-basis: auto;
56
48
  }
57
- .head.stuck:has(.task-id) .meta {
49
+ .head.stuck:has(.fact) .meta {
58
50
  display: none;
59
51
  }
60
52
  }
@@ -196,6 +188,9 @@ button.act:hover {
196
188
  flex: 1 1 0;
197
189
  color: var(--dim);
198
190
  }
191
+ .act-tool {
192
+ color: var(--fg);
193
+ }
199
194
  .act.open .act-text {
200
195
  display: grid;
201
196
  gap: 2px;
@@ -228,6 +223,32 @@ button.act:hover {
228
223
  .act.error :is(.act-title, .ic) {
229
224
  color: var(--bad);
230
225
  }
226
+ .act.timed {
227
+ grid-template-columns: 76px 16px minmax(0, 1fr) auto 14px;
228
+ }
229
+ .act-state {
230
+ color: var(--dim);
231
+ font-size: 11px;
232
+ font-variant-numeric: tabular-nums;
233
+ white-space: nowrap;
234
+ }
235
+ .act-state.bad,
236
+ .act-state.bad .ic {
237
+ color: var(--bad);
238
+ }
239
+ .act-state :is(.ic, .spin) {
240
+ display: inline-block;
241
+ width: 11px;
242
+ height: 11px;
243
+ margin: 0 6px 0 0;
244
+ vertical-align: -1px;
245
+ }
246
+ .act-state .spin {
247
+ border: 1.5px solid currentColor;
248
+ border-top-color: transparent;
249
+ border-radius: 50%;
250
+ animation: spin 0.8s linear infinite;
251
+ }
231
252
  .act-empty {
232
253
  padding: 24px 0;
233
254
  text-align: center;