@alook/app 0.0.68 → 0.0.70

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 (240) hide show
  1. package/bundled/email-worker/index.js +9 -1
  2. package/bundled/web/.open-next/.build/durable-objects/queue.js +5 -5
  3. package/bundled/web/.open-next/assets/BUILD_ID +1 -1
  4. package/bundled/web/.open-next/assets/_next/static/chunks/0.vi-1cgnne0e.css +1 -0
  5. package/bundled/web/.open-next/assets/_next/static/chunks/{0vob59t.w8yuf.js → 060hy1yx9.8u4.js} +2 -2
  6. package/bundled/web/.open-next/assets/_next/static/chunks/08u3p1v8e1gxg.js +63 -0
  7. package/bundled/web/.open-next/assets/_next/static/chunks/{13fkss9rmgdqw.js → 0fmcohc0raah~.js} +22 -22
  8. package/bundled/web/.open-next/assets/_next/static/chunks/0va5axmz5ywg8.js +3 -0
  9. package/bundled/web/.open-next/assets/_next/static/chunks/0vb-n1ns9b-93.js +1 -0
  10. package/bundled/web/.open-next/assets/_next/static/chunks/0ymb~iviyjlb_.js +3 -0
  11. package/bundled/web/.open-next/assets/_next/static/chunks/13lom177x6744.js +1 -0
  12. package/bundled/web/.open-next/cache/{d6FEqIY-HdfUib-E9v9dt → P_a_AT2D4owiIED7-cUYg}/_global-error.cache +1 -1
  13. package/bundled/web/.open-next/cache/{d6FEqIY-HdfUib-E9v9dt → P_a_AT2D4owiIED7-cUYg}/_not-found.cache +1 -1
  14. package/bundled/web/.open-next/cache/{d6FEqIY-HdfUib-E9v9dt → P_a_AT2D4owiIED7-cUYg}/sitemap.xml.cache +1 -1
  15. package/bundled/web/.open-next/cloudflare/cache-assets-manifest.sql +1 -1
  16. package/bundled/web/.open-next/cloudflare/init.js +1 -1
  17. package/bundled/web/.open-next/dynamodb-provider/dynamodb-cache.json +1 -1
  18. package/bundled/web/.open-next/middleware/handler.mjs +3 -3
  19. package/bundled/web/.open-next/server-functions/default/src/web/.next/BUILD_ID +1 -1
  20. package/bundled/web/.open-next/server-functions/default/src/web/.next/build-manifest.json +3 -3
  21. package/bundled/web/.open-next/server-functions/default/src/web/.next/prerender-manifest.json +3 -3
  22. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/invite/[token]/page_client-reference-manifest.js +1 -1
  23. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/studio/new/page_client-reference-manifest.js +1 -1
  24. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/agents/[id]/activity/page_client-reference-manifest.js +1 -1
  25. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/agents/[id]/chat/[convId]/page_client-reference-manifest.js +1 -1
  26. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/agents/[id]/chat/page_client-reference-manifest.js +1 -1
  27. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/agents/[id]/email/page_client-reference-manifest.js +1 -1
  28. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/agents/[id]/files/page_client-reference-manifest.js +1 -1
  29. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/agents/[id]/meetings/page_client-reference-manifest.js +1 -1
  30. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/agents/[id]/page_client-reference-manifest.js +1 -1
  31. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/agents/new/page_client-reference-manifest.js +1 -1
  32. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/agents/page_client-reference-manifest.js +1 -1
  33. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/calendar/page_client-reference-manifest.js +1 -1
  34. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/flags/page_client-reference-manifest.js +1 -1
  35. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/help/email-setup/page_client-reference-manifest.js +1 -1
  36. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/home/page_client-reference-manifest.js +1 -1
  37. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/issues/page_client-reference-manifest.js +1 -1
  38. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/runtimes/page_client-reference-manifest.js +1 -1
  39. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/settings/page_client-reference-manifest.js +1 -1
  40. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/threads/[traceId]/page_client-reference-manifest.js +1 -1
  41. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/threads/page_client-reference-manifest.js +1 -1
  42. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/w/[slug]/unread/page_client-reference-manifest.js +1 -1
  43. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(app)/workspaces/page_client-reference-manifest.js +1 -1
  44. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/(auth)/sign-in/page_client-reference-manifest.js +1 -1
  45. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  46. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agent-links/[id]/route.js +2 -2
  47. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agent-links/route.js +1 -1
  48. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/access/[userId]/route.js +3 -3
  49. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/access/route.js +3 -3
  50. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/active-tasks/route.js +3 -3
  51. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/activity/route.js +2 -2
  52. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/chat-init/route.js +1 -1
  53. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/conversation/route.js +2 -2
  54. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/conversations/route.js +2 -2
  55. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/email-accounts/[accountId]/route.js +2 -2
  56. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/email-accounts/[accountId]/sync/route.js +3 -3
  57. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/email-accounts/[accountId]/test/route.js +3 -3
  58. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/email-accounts/route.js +2 -2
  59. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/meetings/[meetingId]/approve/route.js +2 -2
  60. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/meetings/[meetingId]/route.js +2 -2
  61. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/meetings/[meetingId]/stop/route.js +2 -2
  62. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/meetings/route.js +2 -2
  63. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/pin/route.js +3 -3
  64. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/route.js +2 -2
  65. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/whitelist/[whitelistId]/route.js +3 -3
  66. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/whitelist/route.js +4 -4
  67. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/[id]/workspace/browse/route.js +3 -3
  68. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/active-task-counts/route.js +3 -3
  69. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/active-tasks/route.js +6 -6
  70. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/pins/reorder/route.js +3 -3
  71. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/pins/route.js +3 -3
  72. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/route.js +6 -6
  73. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/agents/sidebar/reorder/route.js +3 -3
  74. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/artifacts/[id]/content/route.js +3 -3
  75. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/artifacts/[id]/route.js +3 -3
  76. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/artifacts/route.js +3 -3
  77. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/artifacts/upload/route.js +3 -3
  78. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/calendar/[id]/route.js +4 -4
  79. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/calendar/route.js +3 -3
  80. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/channels/[id]/route.js +1 -1
  81. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/channels/reorder/route.js +3 -3
  82. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/channels/route.js +1 -1
  83. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/config/min-version/route.js +3 -3
  84. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/config/model-options/route.js +3 -3
  85. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/conversations/[id]/active-task/route.js +1 -1
  86. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/conversations/[id]/buffered-messages/[messageId]/route.js +3 -3
  87. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/conversations/[id]/buffered-messages/route.js +4 -4
  88. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/conversations/[id]/messages/route.js +3 -3
  89. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/conversations/[id]/route.js +2 -2
  90. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/conversations/route.js +2 -2
  91. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/daemon/deregister/route.js +2 -2
  92. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/daemon/register/route.js +1 -1
  93. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/daemon/tasks/[taskId]/complete/route.js +1 -1
  94. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/daemon/tasks/[taskId]/fail/route.js +1 -1
  95. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/daemon/tasks/[taskId]/messages/route.js +3 -3
  96. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/daemon/tasks/[taskId]/progress/route.js +1 -1
  97. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/daemon/tasks/[taskId]/start/route.js +1 -1
  98. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/daemon/tasks/[taskId]/status/route.js +3 -3
  99. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/daemon/tasks/[taskId]/supersede/route.js +1 -1
  100. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/daemon/tasks/poll/route.js +3 -3
  101. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/daemon/workspace/report/route.js +1 -1
  102. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/email/[id]/attachment/[index]/route.js +4 -4
  103. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/email/[id]/body/route.js +4 -4
  104. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/email/[id]/raw/route.js +3 -3
  105. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/email/[id]/route.js +2 -2
  106. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/email/[id]/thread/route.js +2 -2
  107. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/email/notify/route.js +2 -2
  108. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/email/route.js +2 -2
  109. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/email/send/route.js +3 -3
  110. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/email/upload/route.js +4 -4
  111. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/flags/[messageId]/route.js +4 -4
  112. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/flags/count/route.js +3 -3
  113. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/flags/route.js +2 -2
  114. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/inbox/count/route.js +3 -3
  115. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/inbox/read/route.js +1 -1
  116. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/inbox/read-all/route.js +1 -1
  117. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/inbox/route.js +2 -2
  118. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/invite/[token]/route.js +3 -3
  119. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/issues/[id]/comments/route.js +4 -4
  120. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/issues/[id]/route.js +2 -2
  121. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/issues/route.js +1 -1
  122. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/machine-tokens/[id]/route.js +3 -3
  123. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/machine-tokens/activate/route.js +1 -1
  124. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/machine-tokens/route.js +3 -3
  125. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/me/route.js +5 -5
  126. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/meeting/callback/route.js +3 -3
  127. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/members/me/route.js +3 -3
  128. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/runtimes/[runtimeId]/rescan/route.js +3 -3
  129. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/runtimes/[runtimeId]/update/route.js +1 -1
  130. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/runtimes/machine/route.js +1 -1
  131. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/runtimes/route.js +1 -1
  132. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/studios/check-handles/route.js +1 -1
  133. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/studios/check-name/route.js +3 -3
  134. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/studios/route.js +4 -4
  135. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/tasks/[id]/messages/route.js +2 -2
  136. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/tasks/[id]/retry/route.js +1 -1
  137. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/tasks/[id]/route.js +2 -2
  138. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/tasks/step-counts/route.js +3 -3
  139. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/traces/[traceId]/route.js +6 -6
  140. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/traces/route.js +6 -6
  141. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/workspaces/[id]/invites/[inviteId]/route.js +3 -3
  142. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/workspaces/[id]/invites/route.js +2 -2
  143. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/workspaces/[id]/members/[memberId]/route.js +3 -3
  144. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/workspaces/[id]/members/route.js +2 -2
  145. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/workspaces/[id]/overview/route.js +6 -6
  146. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/workspaces/[id]/route.js +1 -1
  147. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/api/workspaces/route.js +3 -3
  148. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/page_client-reference-manifest.js +1 -1
  149. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/templates/[id]/page_client-reference-manifest.js +1 -1
  150. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/app/templates/page_client-reference-manifest.js +1 -1
  151. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0.1vmoe._.js +85 -0
  152. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__009_wu3._.js +1 -1
  153. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__01crkpf._.js +1 -1
  154. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__01~--ue._.js +3 -0
  155. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/{[root-of-the-server]__0~4t--s._.js → [root-of-the-server]__027mioa._.js} +8 -8
  156. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__09cer93._.js +3 -0
  157. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0dy~25_._.js +3 -0
  158. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0faxj6t._.js +1 -1
  159. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0k4l9.h._.js +1 -1
  160. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0m5a1_f._.js +1 -1
  161. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0m_ya4f._.js +3 -0
  162. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0niqi98._.js +85 -0
  163. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0ntc1ld._.js +1 -1
  164. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0ud56v.._.js +1 -1
  165. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[turbopack]_runtime.js +16 -16
  166. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0266t8u._.js +2 -2
  167. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_02t7kem._.js +1 -1
  168. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_06imn.m._.js +1 -1
  169. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_07-798_._.js +1 -1
  170. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_08xh_f8._.js +2 -2
  171. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_09j_99x._.js +2 -2
  172. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0c9~wb-._.js +1 -1
  173. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0exm5_w._.js +2 -2
  174. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0gqpz7w._.js +1 -1
  175. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0j1t6f2._.js +1 -1
  176. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0k3wl-3._.js +1 -1
  177. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0l1m9wf._.js +2 -2
  178. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0lmedw9._.js +1 -1
  179. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0ow_nxn._.js +1 -1
  180. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0piy2kq._.js +1 -1
  181. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0r0h9so._.js +3 -3
  182. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0s4qnoj._.js +1 -1
  183. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0sj8mn_._.js +3 -0
  184. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0s~hhx-._.js +1 -1
  185. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0tarogd._.js +1 -1
  186. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0tcd35h._.js +1 -1
  187. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0u3tu2x._.js +2 -2
  188. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0w6dw.t._.js +2 -2
  189. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0y3~9l1._.js +1 -1
  190. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0z.s70x._.js +1 -1
  191. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_122y7jv._.js +1 -1
  192. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/src_0q3gvkd._.js +3 -0
  193. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/{[root-of-the-server]__0ppv-5d._.js → [root-of-the-server]__099etsu._.js} +1 -1
  194. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/[root-of-the-server]__0r2s1aj._.js +3 -0
  195. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/[root-of-the-server]__0xzp3_y._.js +3 -0
  196. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/[turbopack]_runtime.js +16 -16
  197. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/_063q-hj._.js +2 -2
  198. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/{_0gm0lpi._.js → _091qk6t._.js} +1 -1
  199. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/_09b8fgg._.js +1 -1
  200. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/{_0e7_cpm._.js → _0xcw94t._.js} +1 -1
  201. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/_11~t2ti._.js +3 -0
  202. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/_12e18r-._.js +2 -2
  203. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/_13__3im._.js +1 -1
  204. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/_13cbsrm._.js +65 -0
  205. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/src_web_src_0~23g-y._.js +2 -2
  206. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/src_web_src_app_(app)_w_[slug]_home_page_tsx_0lkx78f._.js +1 -1
  207. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/middleware-build-manifest.js +3 -3
  208. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/middleware-manifest.json +5 -5
  209. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/server-reference-manifest.js +1 -1
  210. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/server-reference-manifest.json +1 -1
  211. package/bundled/web/.open-next/server-functions/default/src/web/handler.mjs +68 -150
  212. package/bundled/web/.open-next/server-functions/default/src/web/handler.mjs.meta.json +294 -330
  213. package/bundled/web/.open-next/server-functions/default/src/web/index.mjs +3 -3
  214. package/bundled/web/wrangler.toml +1 -1
  215. package/bundled/ws-do/index.js +9 -1
  216. package/dist/cli/index.js +2427 -426
  217. package/dist/cli/session-runner.js +189 -36
  218. package/package.json +1 -1
  219. package/bundled/web/.open-next/assets/_next/static/chunks/02xsv1h-9twmr.js +0 -3
  220. package/bundled/web/.open-next/assets/_next/static/chunks/085gv~jsjhgvo.js +0 -3
  221. package/bundled/web/.open-next/assets/_next/static/chunks/0csp6ncjhvojv.js +0 -63
  222. package/bundled/web/.open-next/assets/_next/static/chunks/0lf.3fdr8qzrz.css +0 -1
  223. package/bundled/web/.open-next/assets/_next/static/chunks/0u1.3sr-iag4j.js +0 -1
  224. package/bundled/web/.open-next/assets/_next/static/chunks/0v0kh80r40w4f.js +0 -1
  225. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0axs-gp._.js +0 -3
  226. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0kvsfuj._.js +0 -85
  227. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0l3u9pl._.js +0 -85
  228. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0lvfzvr._.js +0 -3
  229. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0n_hjiv._.js +0 -3
  230. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0ug4a08._.js +0 -85
  231. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/[root-of-the-server]__0~jiu74._.js +0 -3
  232. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/_0jx_8bw._.js +0 -3
  233. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/src_0-jf-76._.js +0 -3
  234. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/[root-of-the-server]__0-uhgif._.js +0 -3
  235. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/[root-of-the-server]__0oe.0yf._.js +0 -3
  236. package/bundled/web/.open-next/server-functions/default/src/web/.next/server/chunks/ssr/_0ohl~vp._.js +0 -65
  237. /package/bundled/web/.open-next/assets/_next/static/{d6FEqIY-HdfUib-E9v9dt → P_a_AT2D4owiIED7-cUYg}/_buildManifest.js +0 -0
  238. /package/bundled/web/.open-next/assets/_next/static/{d6FEqIY-HdfUib-E9v9dt → P_a_AT2D4owiIED7-cUYg}/_clientMiddlewareManifest.js +0 -0
  239. /package/bundled/web/.open-next/assets/_next/static/{d6FEqIY-HdfUib-E9v9dt → P_a_AT2D4owiIED7-cUYg}/_ssgManifest.js +0 -0
  240. /package/bundled/web/.open-next/cache/{d6FEqIY-HdfUib-E9v9dt → P_a_AT2D4owiIED7-cUYg}/robots.txt.cache +0 -0
package/dist/cli/index.js CHANGED
@@ -16820,6 +16820,9 @@ var RESERVED_HANDLES = new Set([
16820
16820
  "system",
16821
16821
  "alook"
16822
16822
  ]);
16823
+ function toAlookAddress(h) {
16824
+ return `${h}${DOMAIN}`;
16825
+ }
16823
16826
  // ../shared/src/semver.ts
16824
16827
  function semverGte(a, b) {
16825
16828
  const pa = a.split(".").map(Number);
@@ -17292,8 +17295,8 @@ function statusCommand() {
17292
17295
 
17293
17296
  // commands/daemon.ts
17294
17297
  import { Command as Command3 } from "commander";
17295
- import { spawn as spawn3 } from "child_process";
17296
- import { openSync as openSync2, closeSync as closeSync2, mkdirSync as mkdirSync6 } from "fs";
17298
+ import { spawn as spawn6 } from "child_process";
17299
+ import { openSync as openSync2, closeSync as closeSync2, mkdirSync as mkdirSync8 } from "fs";
17297
17300
  import { dirname as dirname4 } from "path";
17298
17301
 
17299
17302
  // daemon/client.ts
@@ -17431,72 +17434,2179 @@ function createHealthServer(port = DEFAULT_HEALTH_PORT) {
17431
17434
  setRuntimeCount(n) {
17432
17435
  runtimeCount = n;
17433
17436
  }
17434
- };
17437
+ };
17438
+ }
17439
+
17440
+ // daemon/agent/claude.ts
17441
+ import { spawn } from "child_process";
17442
+ import { createInterface } from "readline";
17443
+
17444
+ class ClaudeBackend {
17445
+ cliPath;
17446
+ name = "claude";
17447
+ constructor(cliPath) {
17448
+ this.cliPath = cliPath;
17449
+ }
17450
+ execute(prompt, options) {
17451
+ const args = [
17452
+ "-p",
17453
+ prompt,
17454
+ "--output-format",
17455
+ "stream-json",
17456
+ "--verbose",
17457
+ "--permission-mode",
17458
+ "bypassPermissions"
17459
+ ];
17460
+ if (options.model) {
17461
+ args.push("--model", options.model);
17462
+ }
17463
+ if (options.maxTurns) {
17464
+ args.push("--max-turns", String(options.maxTurns));
17465
+ }
17466
+ if (options.resumeSessionId) {
17467
+ args.push("--resume", options.resumeSessionId);
17468
+ }
17469
+ const proc = spawn(this.cliPath, args, {
17470
+ cwd: options.cwd,
17471
+ stdio: ["pipe", "pipe", "pipe"],
17472
+ env: { ...process.env, ...options.env },
17473
+ shell: process.platform === "win32"
17474
+ });
17475
+ if (!proc.pid) {
17476
+ const error51 = `Failed to start ${this.cliPath}: binary not found or not executable. Is 'claude' installed and on PATH?`;
17477
+ const failedResult = { status: "failed", output: "", error: error51, durationMs: 0, sessionId: "" };
17478
+ const emptyMessages = { [Symbol.asyncIterator]() {
17479
+ return { async next() {
17480
+ return { value: undefined, done: true };
17481
+ } };
17482
+ } };
17483
+ return { pid: undefined, messages: emptyMessages, sessionId: Promise.resolve(""), result: Promise.resolve(failedResult) };
17484
+ }
17485
+ let timedOut = false;
17486
+ let timeoutTimer;
17487
+ if (options.timeout) {
17488
+ timeoutTimer = setTimeout(() => {
17489
+ timedOut = true;
17490
+ proc.kill("SIGTERM");
17491
+ }, options.timeout);
17492
+ }
17493
+ const startTime = Date.now();
17494
+ let lastSessionId = "";
17495
+ let lastOutput = "";
17496
+ let lastError = "";
17497
+ let resultStatus = "completed";
17498
+ let resolveSessionId;
17499
+ const sessionIdPromise = new Promise((resolve) => {
17500
+ resolveSessionId = resolve;
17501
+ });
17502
+ const messageQueue = [];
17503
+ let messageResolve = null;
17504
+ let messageDone = false;
17505
+ const pushMessage = (msg) => {
17506
+ messageQueue.push(msg);
17507
+ if (messageResolve) {
17508
+ const r = messageResolve;
17509
+ messageResolve = null;
17510
+ r();
17511
+ }
17512
+ };
17513
+ const resultPromise = new Promise((resolve) => {
17514
+ const stderrChunks = [];
17515
+ proc.stderr?.on("data", (chunk) => {
17516
+ stderrChunks.push(chunk.toString());
17517
+ });
17518
+ const rl = createInterface({ input: proc.stdout });
17519
+ rl.on("line", (line) => {
17520
+ if (!line.trim())
17521
+ return;
17522
+ let event;
17523
+ try {
17524
+ event = JSON.parse(line);
17525
+ } catch {
17526
+ pushMessage({ type: "log", content: line, level: "debug" });
17527
+ return;
17528
+ }
17529
+ const eventType = event.type;
17530
+ switch (eventType) {
17531
+ case "assistant": {
17532
+ const message2 = event.message;
17533
+ if (!message2)
17534
+ break;
17535
+ const content = message2.content;
17536
+ if (!Array.isArray(content))
17537
+ break;
17538
+ for (const block of content) {
17539
+ if (block.type === "text") {
17540
+ lastOutput = block.text || "";
17541
+ pushMessage({ type: "text", content: block.text });
17542
+ } else if (block.type === "thinking") {
17543
+ pushMessage({ type: "thinking", content: block.text });
17544
+ } else if (block.type === "tool_use") {
17545
+ pushMessage({
17546
+ type: "tool-use",
17547
+ tool: block.name,
17548
+ callId: block.id,
17549
+ input: block.input
17550
+ });
17551
+ }
17552
+ }
17553
+ break;
17554
+ }
17555
+ case "result": {
17556
+ const result = event.result;
17557
+ const sessionId = event.session_id;
17558
+ if (result)
17559
+ lastOutput = result;
17560
+ if (sessionId)
17561
+ lastSessionId = sessionId;
17562
+ const isError = event.is_error;
17563
+ if (isError) {
17564
+ resultStatus = "failed";
17565
+ lastError = result || "unknown error";
17566
+ }
17567
+ break;
17568
+ }
17569
+ case "tool_result": {
17570
+ const content = event.content;
17571
+ const toolUseId = event.tool_use_id;
17572
+ pushMessage({
17573
+ type: "tool-result",
17574
+ callId: toolUseId,
17575
+ output: content
17576
+ });
17577
+ break;
17578
+ }
17579
+ case "system": {
17580
+ const subtype = event.subtype;
17581
+ if (subtype === "init") {
17582
+ const sid = event.session_id;
17583
+ if (sid) {
17584
+ lastSessionId = sid;
17585
+ resolveSessionId(sid);
17586
+ }
17587
+ }
17588
+ break;
17589
+ }
17590
+ case "control_request": {
17591
+ handleControlRequest(proc, event);
17592
+ break;
17593
+ }
17594
+ default: {
17595
+ pushMessage({
17596
+ type: "log",
17597
+ content: line,
17598
+ level: "debug"
17599
+ });
17600
+ }
17601
+ }
17602
+ });
17603
+ proc.on("error", (err) => {
17604
+ resultStatus = "failed";
17605
+ lastError = `spawn error: ${err.message}`;
17606
+ resolveSessionId(lastSessionId);
17607
+ messageDone = true;
17608
+ if (messageResolve) {
17609
+ const r = messageResolve;
17610
+ messageResolve = null;
17611
+ r();
17612
+ }
17613
+ resolve({
17614
+ status: "failed",
17615
+ output: "",
17616
+ error: lastError,
17617
+ durationMs: Date.now() - startTime,
17618
+ sessionId: lastSessionId
17619
+ });
17620
+ });
17621
+ proc.on("close", (code) => {
17622
+ if (timeoutTimer)
17623
+ clearTimeout(timeoutTimer);
17624
+ if (timedOut) {
17625
+ resultStatus = "timeout";
17626
+ } else if (code !== 0 && resultStatus === "completed") {
17627
+ resultStatus = "failed";
17628
+ }
17629
+ const stderr = stderrChunks.join("");
17630
+ if (stderr && !lastError) {
17631
+ lastError = stderr;
17632
+ }
17633
+ resolveSessionId(lastSessionId);
17634
+ messageDone = true;
17635
+ if (messageResolve) {
17636
+ const r = messageResolve;
17637
+ messageResolve = null;
17638
+ r();
17639
+ }
17640
+ resolve({
17641
+ status: resultStatus,
17642
+ output: lastOutput,
17643
+ error: lastError,
17644
+ durationMs: Date.now() - startTime,
17645
+ sessionId: lastSessionId
17646
+ });
17647
+ });
17648
+ });
17649
+ const messages = {
17650
+ [Symbol.asyncIterator]() {
17651
+ return {
17652
+ async next() {
17653
+ while (messageQueue.length === 0 && !messageDone) {
17654
+ await new Promise((resolve) => {
17655
+ messageResolve = resolve;
17656
+ });
17657
+ }
17658
+ if (messageQueue.length > 0) {
17659
+ return { value: messageQueue.shift(), done: false };
17660
+ }
17661
+ return { value: undefined, done: true };
17662
+ }
17663
+ };
17664
+ }
17665
+ };
17666
+ return { pid: proc.pid, messages, sessionId: sessionIdPromise, result: resultPromise };
17667
+ }
17668
+ }
17669
+ function handleControlRequest(proc, event) {
17670
+ const requestId = event.request_id;
17671
+ if (!requestId)
17672
+ return;
17673
+ let updatedInput = undefined;
17674
+ const payload = event.payload;
17675
+ if (payload) {
17676
+ const input = payload.input;
17677
+ if (typeof input === "string") {
17678
+ try {
17679
+ updatedInput = JSON.parse(input);
17680
+ } catch {
17681
+ updatedInput = input;
17682
+ }
17683
+ } else if (input !== undefined) {
17684
+ updatedInput = input;
17685
+ }
17686
+ }
17687
+ const approval = JSON.stringify({
17688
+ type: "control_response",
17689
+ response: {
17690
+ subtype: "success",
17691
+ request_id: requestId,
17692
+ response: {
17693
+ behavior: "allow",
17694
+ updatedInput
17695
+ }
17696
+ }
17697
+ });
17698
+ try {
17699
+ proc.stdin?.write(approval + `
17700
+ `);
17701
+ } catch {}
17702
+ }
17703
+
17704
+ // daemon/agent/codex.ts
17705
+ import { spawn as spawn2 } from "child_process";
17706
+ import { createInterface as createInterface2 } from "readline";
17707
+ var RAW_DETECTION_METHODS = new Set([
17708
+ "turn/started",
17709
+ "turn/completed",
17710
+ "thread/started",
17711
+ "item/started",
17712
+ "item/completed",
17713
+ "item/agentMessage/delta"
17714
+ ]);
17715
+ function extractThreadID(response) {
17716
+ if (response && typeof response === "object") {
17717
+ const r = response;
17718
+ const thread = r.result?.thread ?? r.thread;
17719
+ if (thread && typeof thread === "object") {
17720
+ const id = thread.id;
17721
+ if (typeof id === "string" && id)
17722
+ return id;
17723
+ }
17724
+ if (typeof r.id === "string" && r.id)
17725
+ return r.id;
17726
+ }
17727
+ return "";
17728
+ }
17729
+
17730
+ class CodexBackend {
17731
+ cliPath;
17732
+ name = "codex";
17733
+ constructor(cliPath) {
17734
+ this.cliPath = cliPath;
17735
+ }
17736
+ execute(prompt, options) {
17737
+ const proc = spawn2(this.cliPath, ["app-server", "--listen", "stdio://", "--config", "sandbox_mode=danger-full-access"], {
17738
+ cwd: options.cwd,
17739
+ stdio: ["pipe", "pipe", "pipe"],
17740
+ env: { ...process.env, ...options.env },
17741
+ shell: process.platform === "win32"
17742
+ });
17743
+ if (!proc.pid) {
17744
+ const error51 = `Failed to start ${this.cliPath}: binary not found or not executable. Is 'codex' installed and on PATH?`;
17745
+ const failedResult = { status: "failed", output: "", error: error51, durationMs: 0, sessionId: "" };
17746
+ const emptyMessages = { [Symbol.asyncIterator]() {
17747
+ return { async next() {
17748
+ return { value: undefined, done: true };
17749
+ } };
17750
+ } };
17751
+ return { pid: undefined, messages: emptyMessages, sessionId: Promise.resolve(""), result: Promise.resolve(failedResult) };
17752
+ }
17753
+ let timedOut = false;
17754
+ let timeoutTimer;
17755
+ if (options.timeout) {
17756
+ timeoutTimer = setTimeout(() => {
17757
+ timedOut = true;
17758
+ proc.kill("SIGTERM");
17759
+ }, options.timeout);
17760
+ }
17761
+ const startTime = Date.now();
17762
+ let requestId = 0;
17763
+ let lastOutput = "";
17764
+ let lastError = "";
17765
+ let resultStatus = "completed";
17766
+ let sessionId = "";
17767
+ let resolveSessionId;
17768
+ const sessionIdPromise = new Promise((resolve) => {
17769
+ resolveSessionId = resolve;
17770
+ });
17771
+ let notificationProtocol = "unknown";
17772
+ let turnStarted = false;
17773
+ let turnDoneTriggered = false;
17774
+ let turnCompletedSuccessfully = false;
17775
+ let lastCompletedTurnId = "";
17776
+ let turnError = "";
17777
+ const pendingRequests = new Map;
17778
+ const messageQueue = [];
17779
+ let messageResolve = null;
17780
+ let messageDone = false;
17781
+ const pushMessage = (msg) => {
17782
+ messageQueue.push(msg);
17783
+ if (messageResolve) {
17784
+ const r = messageResolve;
17785
+ messageResolve = null;
17786
+ r();
17787
+ }
17788
+ };
17789
+ const writeStdin = (data) => {
17790
+ try {
17791
+ proc.stdin?.write(data + `
17792
+ `);
17793
+ } catch {}
17794
+ };
17795
+ const sendRpc = (method, params) => {
17796
+ const id = ++requestId;
17797
+ const msg = { jsonrpc: "2.0", id, method, params };
17798
+ writeStdin(JSON.stringify(msg));
17799
+ return new Promise((resolve, reject) => {
17800
+ pendingRequests.set(id, { resolve, reject });
17801
+ });
17802
+ };
17803
+ const sendNotification = (method) => {
17804
+ const msg = { jsonrpc: "2.0", method };
17805
+ writeStdin(JSON.stringify(msg));
17806
+ };
17807
+ const sendResponse = (id, result) => {
17808
+ const msg = { jsonrpc: "2.0", id, result };
17809
+ writeStdin(JSON.stringify(msg));
17810
+ };
17811
+ const closeAllPending = (reason) => {
17812
+ for (const [, cb] of pendingRequests) {
17813
+ cb.reject(new Error(reason));
17814
+ }
17815
+ pendingRequests.clear();
17816
+ };
17817
+ const setTurnError = (msg) => {
17818
+ if (msg && !turnError)
17819
+ turnError = msg;
17820
+ };
17821
+ const triggerTurnDone = (aborted2) => {
17822
+ if (turnDoneTriggered)
17823
+ return;
17824
+ turnDoneTriggered = true;
17825
+ resultStatus = aborted2 ? "aborted" : "completed";
17826
+ try {
17827
+ proc.stdin?.end();
17828
+ } catch {}
17829
+ try {
17830
+ proc.kill("SIGTERM");
17831
+ } catch {}
17832
+ };
17833
+ const handleServerRequest = (msg) => {
17834
+ const method = msg.method;
17835
+ const id = msg.id;
17836
+ switch (method) {
17837
+ case "item/commandExecution/requestApproval":
17838
+ case "execCommandApproval":
17839
+ case "item/fileChange/requestApproval":
17840
+ case "applyPatchApproval":
17841
+ sendResponse(id, { decision: "accept" });
17842
+ break;
17843
+ default:
17844
+ sendResponse(id, {});
17845
+ break;
17846
+ }
17847
+ };
17848
+ const handleNotification = (msg) => {
17849
+ const method = msg.method;
17850
+ const params = msg.params || {};
17851
+ if (method === "codex/event") {
17852
+ if (notificationProtocol === "raw")
17853
+ return;
17854
+ notificationProtocol = "legacy";
17855
+ handleLegacyEvent(params);
17856
+ return;
17857
+ }
17858
+ if (RAW_DETECTION_METHODS.has(method)) {
17859
+ if (notificationProtocol === "legacy")
17860
+ return;
17861
+ notificationProtocol = "raw";
17862
+ }
17863
+ if ((method === "thread/status/changed" || method === "error") && notificationProtocol === "legacy") {
17864
+ return;
17865
+ }
17866
+ const notifThreadId = params.threadId;
17867
+ if (sessionId && notifThreadId && notifThreadId !== sessionId) {
17868
+ return;
17869
+ }
17870
+ switch (method) {
17871
+ case "turn/started": {
17872
+ turnStarted = true;
17873
+ break;
17874
+ }
17875
+ case "turn/completed": {
17876
+ const turn = params.turn;
17877
+ const turnId = turn?.id || params.turnId || "";
17878
+ if (turnId && turnId === lastCompletedTurnId)
17879
+ return;
17880
+ if (turnId)
17881
+ lastCompletedTurnId = turnId;
17882
+ const status = turn?.status || params.status || "";
17883
+ if (status === "completed" || status === "finished") {
17884
+ turnCompletedSuccessfully = true;
17885
+ triggerTurnDone(false);
17886
+ } else if (status === "cancelled" || status === "aborted" || status === "interrupted") {
17887
+ triggerTurnDone(true);
17888
+ } else if (status === "error" || status === "failed") {
17889
+ const turnErr = turn?.error;
17890
+ setTurnError(turnErr?.message || "codex turn failed");
17891
+ triggerTurnDone(false);
17892
+ }
17893
+ break;
17894
+ }
17895
+ case "error": {
17896
+ const errObj = params.error;
17897
+ const errMsg = errObj?.message || params.message || "";
17898
+ const willRetry = params.willRetry === true;
17899
+ if (errMsg && !willRetry) {
17900
+ setTurnError(errMsg);
17901
+ }
17902
+ break;
17903
+ }
17904
+ case "thread/status/changed": {
17905
+ const statusObj = params.status;
17906
+ const statusType = typeof statusObj === "object" && statusObj !== null ? statusObj.type || "" : statusObj || "";
17907
+ if (statusType === "idle" && turnStarted) {
17908
+ triggerTurnDone(false);
17909
+ }
17910
+ break;
17911
+ }
17912
+ case "item/started": {
17913
+ const item = params.item;
17914
+ if (!item)
17915
+ break;
17916
+ const itemType = item.type;
17917
+ if (itemType === "commandExecution") {
17918
+ pushMessage({
17919
+ type: "tool-use",
17920
+ tool: "exec_command",
17921
+ callId: item.id,
17922
+ input: item
17923
+ });
17924
+ } else if (itemType === "fileChange") {
17925
+ pushMessage({
17926
+ type: "tool-use",
17927
+ tool: "patch_apply",
17928
+ callId: item.id,
17929
+ input: item
17930
+ });
17931
+ }
17932
+ break;
17933
+ }
17934
+ case "item/completed": {
17935
+ const item = params.item;
17936
+ if (!item)
17937
+ break;
17938
+ const itemType = item.type;
17939
+ if (itemType === "commandExecution") {
17940
+ const output = item.aggregatedOutput || "";
17941
+ pushMessage({
17942
+ type: "tool-result",
17943
+ callId: item.id,
17944
+ output
17945
+ });
17946
+ } else if (itemType === "fileChange") {
17947
+ pushMessage({
17948
+ type: "tool-result",
17949
+ callId: item.id,
17950
+ output: ""
17951
+ });
17952
+ } else if (itemType === "agentMessage") {
17953
+ const flatText = item.text;
17954
+ if (flatText) {
17955
+ pushMessage({ type: "text", content: flatText });
17956
+ lastOutput = flatText;
17957
+ } else {
17958
+ const content = item.content;
17959
+ if (Array.isArray(content)) {
17960
+ for (const block of content) {
17961
+ if (block.type === "output_text" || block.type === "text") {
17962
+ if (block.text) {
17963
+ pushMessage({ type: "text", content: block.text });
17964
+ lastOutput = block.text;
17965
+ }
17966
+ }
17967
+ }
17968
+ }
17969
+ }
17970
+ const phase = item.phase;
17971
+ if (phase === "final_answer") {
17972
+ triggerTurnDone(false);
17973
+ }
17974
+ }
17975
+ break;
17976
+ }
17977
+ default: {
17978
+ pushMessage({
17979
+ type: "log",
17980
+ content: JSON.stringify(msg),
17981
+ level: "debug"
17982
+ });
17983
+ }
17984
+ }
17985
+ };
17986
+ const handleLegacyEvent = (params) => {
17987
+ const eventType = params.type;
17988
+ if (!eventType)
17989
+ return;
17990
+ switch (eventType) {
17991
+ case "task_started":
17992
+ break;
17993
+ case "agent_message": {
17994
+ const text2 = params.text || params.message || "";
17995
+ if (text2) {
17996
+ pushMessage({ type: "text", content: text2 });
17997
+ lastOutput = text2;
17998
+ }
17999
+ break;
18000
+ }
18001
+ case "exec_command_begin":
18002
+ pushMessage({
18003
+ type: "tool-use",
18004
+ tool: "exec_command",
18005
+ callId: params.id,
18006
+ input: params
18007
+ });
18008
+ break;
18009
+ case "exec_command_end":
18010
+ pushMessage({
18011
+ type: "tool-result",
18012
+ callId: params.id,
18013
+ output: params.output || ""
18014
+ });
18015
+ break;
18016
+ case "patch_apply_begin":
18017
+ pushMessage({
18018
+ type: "tool-use",
18019
+ tool: "patch_apply",
18020
+ callId: params.id,
18021
+ input: params
18022
+ });
18023
+ break;
18024
+ case "patch_apply_end":
18025
+ pushMessage({
18026
+ type: "tool-result",
18027
+ callId: params.id,
18028
+ output: params.output || ""
18029
+ });
18030
+ break;
18031
+ case "task_complete": {
18032
+ const output = params.output;
18033
+ if (output)
18034
+ lastOutput = output;
18035
+ triggerTurnDone(false);
18036
+ break;
18037
+ }
18038
+ case "turn_aborted":
18039
+ triggerTurnDone(true);
18040
+ break;
18041
+ }
18042
+ };
18043
+ const resultPromise = new Promise((resolve) => {
18044
+ const stderrChunks = [];
18045
+ proc.stderr?.on("data", (chunk) => {
18046
+ stderrChunks.push(chunk.toString());
18047
+ });
18048
+ const rl = createInterface2({ input: proc.stdout });
18049
+ rl.on("line", (line) => {
18050
+ if (!line.trim())
18051
+ return;
18052
+ let msg;
18053
+ try {
18054
+ msg = JSON.parse(line);
18055
+ } catch {
18056
+ pushMessage({ type: "log", content: line, level: "debug" });
18057
+ return;
18058
+ }
18059
+ if (msg.id !== undefined && msg.method) {
18060
+ handleServerRequest(msg);
18061
+ return;
18062
+ }
18063
+ if (msg.method && msg.id === undefined) {
18064
+ handleNotification(msg);
18065
+ return;
18066
+ }
18067
+ if (msg.id !== undefined && !msg.method) {
18068
+ const pending = pendingRequests.get(msg.id);
18069
+ if (pending) {
18070
+ pendingRequests.delete(msg.id);
18071
+ if (msg.error) {
18072
+ pending.reject(new Error(msg.error.message));
18073
+ } else {
18074
+ pending.resolve(msg.result);
18075
+ }
18076
+ }
18077
+ return;
18078
+ }
18079
+ pushMessage({
18080
+ type: "log",
18081
+ content: JSON.stringify(msg),
18082
+ level: "debug"
18083
+ });
18084
+ });
18085
+ const startHandshake = async () => {
18086
+ try {
18087
+ await sendRpc("initialize", {
18088
+ clientInfo: {
18089
+ name: "alook-daemon",
18090
+ title: "Alook Agent SDK",
18091
+ version: "0.1.0"
18092
+ },
18093
+ capabilities: { experimentalApi: true }
18094
+ });
18095
+ sendNotification("initialized");
18096
+ let threadResponse;
18097
+ if (options.resumeSessionId) {
18098
+ threadResponse = await sendRpc("thread/resume", {
18099
+ threadId: options.resumeSessionId,
18100
+ ...options.model ? { model: options.model } : {}
18101
+ });
18102
+ sessionId = options.resumeSessionId;
18103
+ } else {
18104
+ const threadParams = {
18105
+ cwd: options.cwd,
18106
+ sandboxPolicy: { type: "dangerFullAccess" },
18107
+ approvalPolicy: "never",
18108
+ persistExtendedHistory: true,
18109
+ experimentalRawEvents: false
18110
+ };
18111
+ if (options.model) {
18112
+ threadParams.model = options.model;
18113
+ }
18114
+ threadResponse = await sendRpc("thread/start", threadParams);
18115
+ sessionId = extractThreadID(threadResponse);
18116
+ }
18117
+ resolveSessionId(sessionId);
18118
+ await sendRpc("turn/start", {
18119
+ threadId: sessionId,
18120
+ input: [{ type: "text", text: prompt }],
18121
+ sandboxPolicy: { type: "dangerFullAccess" },
18122
+ approvalPolicy: "never"
18123
+ });
18124
+ } catch (err) {
18125
+ const errMsg = err instanceof Error ? err.message : "handshake failed";
18126
+ lastError = errMsg;
18127
+ resultStatus = "failed";
18128
+ pushMessage({ type: "error", content: errMsg });
18129
+ }
18130
+ };
18131
+ startHandshake();
18132
+ proc.on("error", (err) => {
18133
+ resultStatus = "failed";
18134
+ lastError = `spawn error: ${err.message}`;
18135
+ closeAllPending("spawn error");
18136
+ resolveSessionId(sessionId);
18137
+ messageDone = true;
18138
+ if (messageResolve) {
18139
+ const r = messageResolve;
18140
+ messageResolve = null;
18141
+ r();
18142
+ }
18143
+ resolve({
18144
+ status: "failed",
18145
+ output: "",
18146
+ error: lastError,
18147
+ durationMs: Date.now() - startTime,
18148
+ sessionId
18149
+ });
18150
+ });
18151
+ proc.on("close", (code) => {
18152
+ if (timeoutTimer)
18153
+ clearTimeout(timeoutTimer);
18154
+ closeAllPending("process closed");
18155
+ if (timedOut) {
18156
+ resultStatus = "timeout";
18157
+ } else if (code !== 0 && resultStatus === "completed" && !turnCompletedSuccessfully) {
18158
+ if (!lastOutput) {
18159
+ resultStatus = "failed";
18160
+ }
18161
+ }
18162
+ const stderr = stderrChunks.join("").replace(/\x1b\[[0-9;]*m/g, "");
18163
+ if (stderr && !lastError) {
18164
+ lastError = stderr;
18165
+ }
18166
+ if (turnError) {
18167
+ resultStatus = "failed";
18168
+ lastError = turnError;
18169
+ }
18170
+ resolveSessionId(sessionId);
18171
+ messageDone = true;
18172
+ if (messageResolve) {
18173
+ const r = messageResolve;
18174
+ messageResolve = null;
18175
+ r();
18176
+ }
18177
+ resolve({
18178
+ status: resultStatus,
18179
+ output: lastOutput,
18180
+ error: lastError,
18181
+ durationMs: Date.now() - startTime,
18182
+ sessionId
18183
+ });
18184
+ });
18185
+ });
18186
+ const messages = {
18187
+ [Symbol.asyncIterator]() {
18188
+ return {
18189
+ async next() {
18190
+ while (messageQueue.length === 0 && !messageDone) {
18191
+ await new Promise((resolve) => {
18192
+ messageResolve = resolve;
18193
+ });
18194
+ }
18195
+ if (messageQueue.length > 0) {
18196
+ return { value: messageQueue.shift(), done: false };
18197
+ }
18198
+ return { value: undefined, done: true };
18199
+ }
18200
+ };
18201
+ }
18202
+ };
18203
+ return { pid: proc.pid, messages, sessionId: sessionIdPromise, result: resultPromise };
18204
+ }
18205
+ }
18206
+
18207
+ // daemon/agent/opencode.ts
18208
+ import { spawn as spawn3 } from "child_process";
18209
+ import { createInterface as createInterface3 } from "readline";
18210
+
18211
+ class OpenCodeBackend {
18212
+ cliPath;
18213
+ name = "opencode";
18214
+ constructor(cliPath) {
18215
+ this.cliPath = cliPath;
18216
+ }
18217
+ execute(prompt, options) {
18218
+ const args = ["run", "--format", "json"];
18219
+ if (options.model) {
18220
+ args.push("--model", options.model);
18221
+ }
18222
+ if (options.resumeSessionId) {
18223
+ args.push("--session", options.resumeSessionId);
18224
+ }
18225
+ args.push(prompt);
18226
+ const proc = spawn3(this.cliPath, args, {
18227
+ cwd: options.cwd,
18228
+ stdio: ["ignore", "pipe", "pipe"],
18229
+ env: { ...process.env, ...options.env, OPENCODE_PERMISSION: '{"*":"allow"}' },
18230
+ shell: process.platform === "win32"
18231
+ });
18232
+ if (!proc.pid) {
18233
+ const error51 = `Failed to start ${this.cliPath}: binary not found or not executable. Is 'opencode' installed and on PATH?`;
18234
+ const failedResult = { status: "failed", output: "", error: error51, durationMs: 0, sessionId: "" };
18235
+ const emptyMessages = { [Symbol.asyncIterator]() {
18236
+ return { async next() {
18237
+ return { value: undefined, done: true };
18238
+ } };
18239
+ } };
18240
+ return { pid: undefined, messages: emptyMessages, sessionId: Promise.resolve(""), result: Promise.resolve(failedResult) };
18241
+ }
18242
+ let timedOut = false;
18243
+ let timeoutTimer;
18244
+ if (options.timeout) {
18245
+ timeoutTimer = setTimeout(() => {
18246
+ timedOut = true;
18247
+ proc.kill("SIGTERM");
18248
+ }, options.timeout);
18249
+ }
18250
+ const startTime = Date.now();
18251
+ let lastSessionId = "";
18252
+ let lastOutput = "";
18253
+ let lastError = "";
18254
+ let resultStatus = "completed";
18255
+ let resolveSessionId;
18256
+ const sessionIdPromise = new Promise((resolve) => {
18257
+ resolveSessionId = resolve;
18258
+ });
18259
+ let turnDoneTriggered = false;
18260
+ const turnDone = () => {
18261
+ if (turnDoneTriggered)
18262
+ return;
18263
+ turnDoneTriggered = true;
18264
+ try {
18265
+ proc.kill("SIGTERM");
18266
+ } catch {}
18267
+ };
18268
+ const messageQueue = [];
18269
+ let messageResolve = null;
18270
+ let messageDone = false;
18271
+ const pushMessage = (msg) => {
18272
+ messageQueue.push(msg);
18273
+ if (messageResolve) {
18274
+ const r = messageResolve;
18275
+ messageResolve = null;
18276
+ r();
18277
+ }
18278
+ };
18279
+ const resultPromise = new Promise((resolve) => {
18280
+ const stderrChunks = [];
18281
+ proc.stderr?.on("data", (chunk) => {
18282
+ stderrChunks.push(chunk.toString());
18283
+ });
18284
+ const rl = createInterface3({ input: proc.stdout });
18285
+ rl.on("line", (line) => {
18286
+ if (!line.trim())
18287
+ return;
18288
+ let event;
18289
+ try {
18290
+ event = JSON.parse(line);
18291
+ } catch {
18292
+ pushMessage({ type: "log", content: line, level: "debug" });
18293
+ return;
18294
+ }
18295
+ const eventType = event.type;
18296
+ const part = event.part;
18297
+ const eventSessionId = event.sessionID || event.session_id;
18298
+ if (eventSessionId && !lastSessionId) {
18299
+ lastSessionId = eventSessionId;
18300
+ resolveSessionId(eventSessionId);
18301
+ }
18302
+ switch (eventType) {
18303
+ case "session": {
18304
+ const sessionId = event.session_id;
18305
+ if (sessionId) {
18306
+ lastSessionId = sessionId;
18307
+ resolveSessionId(sessionId);
18308
+ }
18309
+ break;
18310
+ }
18311
+ case "message": {
18312
+ const role = event.role;
18313
+ const content = event.content;
18314
+ if (role === "assistant" && content) {
18315
+ lastOutput = content;
18316
+ pushMessage({ type: "text", content });
18317
+ }
18318
+ break;
18319
+ }
18320
+ case "text": {
18321
+ const text2 = part?.text || event.content || "";
18322
+ if (text2) {
18323
+ lastOutput = text2;
18324
+ pushMessage({ type: "text", content: text2 });
18325
+ }
18326
+ break;
18327
+ }
18328
+ case "thinking": {
18329
+ const content = part?.thinking || event.content || "";
18330
+ pushMessage({ type: "thinking", content });
18331
+ break;
18332
+ }
18333
+ case "tool_call": {
18334
+ pushMessage({
18335
+ type: "tool-use",
18336
+ tool: event.name || part?.name || "",
18337
+ callId: event.call_id || part?.id || "",
18338
+ input: event.input || part?.input
18339
+ });
18340
+ break;
18341
+ }
18342
+ case "tool_result": {
18343
+ pushMessage({
18344
+ type: "tool-result",
18345
+ callId: event.call_id || part?.id || "",
18346
+ output: event.output || part?.output || ""
18347
+ });
18348
+ break;
18349
+ }
18350
+ case "error": {
18351
+ const content = event.message || event.content || part?.error || "";
18352
+ lastError = content;
18353
+ pushMessage({ type: "error", content });
18354
+ turnDone();
18355
+ break;
18356
+ }
18357
+ case "step_start": {
18358
+ break;
18359
+ }
18360
+ case "step_finish": {
18361
+ const reason = part?.reason;
18362
+ if (reason === "stop" || reason === "end_turn") {
18363
+ turnDone();
18364
+ }
18365
+ break;
18366
+ }
18367
+ case "done":
18368
+ case "complete": {
18369
+ const output = event.output;
18370
+ const status = event.status;
18371
+ const sessionId = event.session_id;
18372
+ if (output)
18373
+ lastOutput = output;
18374
+ if (sessionId)
18375
+ lastSessionId = sessionId;
18376
+ if (status === "error" || status === "failed") {
18377
+ resultStatus = "failed";
18378
+ if (!lastError)
18379
+ lastError = output || "task failed";
18380
+ }
18381
+ turnDone();
18382
+ break;
18383
+ }
18384
+ default: {
18385
+ pushMessage({
18386
+ type: "log",
18387
+ content: line,
18388
+ level: "debug"
18389
+ });
18390
+ }
18391
+ }
18392
+ });
18393
+ proc.on("error", (err) => {
18394
+ resultStatus = "failed";
18395
+ lastError = `spawn error: ${err.message}`;
18396
+ resolveSessionId(lastSessionId);
18397
+ messageDone = true;
18398
+ if (messageResolve) {
18399
+ const r = messageResolve;
18400
+ messageResolve = null;
18401
+ r();
18402
+ }
18403
+ resolve({
18404
+ status: "failed",
18405
+ output: "",
18406
+ error: lastError,
18407
+ durationMs: Date.now() - startTime,
18408
+ sessionId: lastSessionId
18409
+ });
18410
+ });
18411
+ proc.on("close", (code) => {
18412
+ if (timeoutTimer)
18413
+ clearTimeout(timeoutTimer);
18414
+ if (timedOut) {
18415
+ resultStatus = "timeout";
18416
+ } else if (code !== 0 && resultStatus === "completed" && !turnDoneTriggered) {
18417
+ if (!lastOutput) {
18418
+ resultStatus = "failed";
18419
+ }
18420
+ }
18421
+ const stderr = stderrChunks.join("");
18422
+ if (stderr && !lastError) {
18423
+ lastError = stderr;
18424
+ }
18425
+ resolveSessionId(lastSessionId);
18426
+ messageDone = true;
18427
+ if (messageResolve) {
18428
+ const r = messageResolve;
18429
+ messageResolve = null;
18430
+ r();
18431
+ }
18432
+ resolve({
18433
+ status: resultStatus,
18434
+ output: lastOutput,
18435
+ error: lastError,
18436
+ durationMs: Date.now() - startTime,
18437
+ sessionId: lastSessionId
18438
+ });
18439
+ });
18440
+ });
18441
+ const messages = {
18442
+ [Symbol.asyncIterator]() {
18443
+ return {
18444
+ async next() {
18445
+ while (messageQueue.length === 0 && !messageDone) {
18446
+ await new Promise((resolve) => {
18447
+ messageResolve = resolve;
18448
+ });
18449
+ }
18450
+ if (messageQueue.length > 0) {
18451
+ return { value: messageQueue.shift(), done: false };
18452
+ }
18453
+ return { value: undefined, done: true };
18454
+ }
18455
+ };
18456
+ }
18457
+ };
18458
+ return { pid: proc.pid, messages, sessionId: sessionIdPromise, result: resultPromise };
18459
+ }
18460
+ }
18461
+
18462
+ // daemon/agent/index.ts
18463
+ import { execSync as execSync2 } from "child_process";
18464
+ function createBackend(provider, cliPath) {
18465
+ switch (provider) {
18466
+ case "claude":
18467
+ return new ClaudeBackend(cliPath);
18468
+ case "codex":
18469
+ return new CodexBackend(cliPath);
18470
+ case "opencode":
18471
+ return new OpenCodeBackend(cliPath);
18472
+ default:
18473
+ throw new Error(`Unknown provider: ${provider}`);
18474
+ }
18475
+ }
18476
+ async function detectVersion2(cliPath) {
18477
+ try {
18478
+ return execSync2(`${cliPath} --version`, { encoding: "utf-8" }).trim();
18479
+ } catch {
18480
+ return "unknown";
18481
+ }
18482
+ }
18483
+
18484
+ // daemon/types.ts
18485
+ function fromApiTask(api2) {
18486
+ return {
18487
+ id: api2.id,
18488
+ agentId: api2.agent_id,
18489
+ runtimeId: api2.runtime_id,
18490
+ conversationId: api2.conversation_id,
18491
+ workspaceId: api2.workspace_id,
18492
+ prompt: api2.prompt,
18493
+ status: api2.status,
18494
+ priority: api2.priority,
18495
+ type: api2.type,
18496
+ contextKey: api2.context_key ?? null,
18497
+ context: api2.context ?? undefined,
18498
+ agent: api2.agent ? {
18499
+ name: api2.agent.name,
18500
+ instructions: api2.agent.instructions,
18501
+ emailHandle: api2.agent.email_handle ?? undefined,
18502
+ emailAddresses: api2.agent.email_addresses ?? [],
18503
+ userEmail: api2.agent.user_email ?? undefined,
18504
+ userName: api2.agent.user_name ?? undefined,
18505
+ runtimeConfig: api2.agent.runtime_config ?? undefined,
18506
+ colleagues: api2.agent.colleagues?.map((c) => ({
18507
+ name: c.name,
18508
+ email: c.email,
18509
+ description: c.description,
18510
+ instruction: c.instruction
18511
+ })) ?? []
18512
+ } : undefined,
18513
+ sender: api2.sender ? { name: api2.sender.name, email: api2.sender.email, isOwner: api2.sender.is_owner } : undefined,
18514
+ repos: undefined,
18515
+ createdAt: api2.created_at,
18516
+ traceId: api2.trace_id ?? null,
18517
+ parentTaskId: api2.parent_task_id ?? null,
18518
+ channel: api2.channel ?? null
18519
+ };
18520
+ }
18521
+
18522
+ // daemon/session-runner.ts
18523
+ import { mkdir, writeFile, rm, rename } from "fs/promises";
18524
+ import { mkdirSync as mkdirSync6 } from "fs";
18525
+ import path from "path";
18526
+
18527
+ // daemon/execenv/index.ts
18528
+ import { mkdirSync as mkdirSync3 } from "fs";
18529
+ import { join as join6 } from "path";
18530
+
18531
+ // daemon/execenv/context.ts
18532
+ import { createHash } from "crypto";
18533
+
18534
+ // lib/platform.ts
18535
+ import { tmpdir } from "os";
18536
+ import { join as join4, sep } from "path";
18537
+ var isWindows = process.platform === "win32";
18538
+ function tempDir(subdir) {
18539
+ return join4(tmpdir(), subdir);
18540
+ }
18541
+
18542
+ // daemon/execenv/context.ts
18543
+ import {
18544
+ writeFileSync as writeFileSync3,
18545
+ readFileSync as readFileSync4,
18546
+ lstatSync,
18547
+ symlinkSync,
18548
+ unlinkSync as unlinkSync2,
18549
+ existsSync,
18550
+ readlinkSync,
18551
+ copyFileSync
18552
+ } from "fs";
18553
+ import { join as join5 } from "path";
18554
+ var CANONICAL_FILE = "AGENTS.md";
18555
+ var SYMLINK_ALIASES = ["CLAUDE.md"];
18556
+ var SYSTEM_PROMPT_BODY = `## Memory Management
18557
+ - Your memory directory is ./, don't write ANY EXTERNAL memory file.
18558
+ - Write ESSENTIAL yet SHORT memory to ./memory.md
18559
+ - For SPECIFIC yet LONG rules or pattern, write to experiences/[NAME].md, and add index to ./memory.md for later recall.
18560
+ ### whats is ESSENTIAL and SHORT Memory?
18561
+ - basic user profile, e.g.:
18562
+ - "user name is ..."
18563
+ - "user is working on ..."
18564
+ - certain local project mapping, e.g.:
18565
+ - "alook means the project under /user/home/alook/"
18566
+ - when to read certain stuff, e.g.:
18567
+ - "read ./experiences/alook_dev_workflow.md when start a new pr in alook"
18568
+ ESSENTIAL means you think you generally need to read it every time, SHORT means a short sentence (under 140 chars) can describe this memory
18569
+ ### whats is SPECIFIC and LONG Memory?
18570
+ - specific workflow that trigger at certain cases, e.g.:
18571
+ - user ask your to summarize the before workflow with certain skills usage as the common workflow when write a new slide about agent. Write it to experiences/slide-for-agent.md.
18572
+ SPECIFIC means you think you just need to use it conditionally, LONG means you need to detailed, more than 140 chars text to describe it.
18573
+
18574
+ ## Context Timeline
18575
+ You're a solo working unit inside a powerful personal agent in Alook platform.
18576
+ Your current context is only a fraction of the full timeline of what's your have done.
18577
+ The full context timeline is inside './.context_timeline/YYYY-MM-DD.jsonl'.
18578
+ Each line of a timeline JSONL is a JSON object with these fields:
18579
+ - "task_id" — unique task identifier
18580
+ - "context_key" — thread identifier, the same context key meaning those tasks are in the same thread.
18581
+ - "session_id" — agent session identifier (null until completion)
18582
+ - "pid" — daemon process ID (present while running, null when done)
18583
+ - "status" — "running", "completed", or "failed"
18584
+ - "datetime" — when the task started (local timezone)
18585
+ - "type" — source of the task: "user_dm_message", "email_notification", or "calendar_event"
18586
+ - "prompt" — what the user asked
18587
+ - "agent_responses" — assistant text outputs during execution
18588
+ - "errmsg" — error message (null unless status is "failed")
18589
+ - "detailed_log" — the running log for this task, including the actually task agent messages with tool-calls and failed logs.
18590
+ those json are sorted by datetime in asc order.
18591
+
18592
+ ## BE HUMAN
18593
+ - When you recall the timelines, don't say "I find ... in my timeline jsonl". Just say "I can recall..."
18594
+ - User don't know about the context timeline jsonl, this is your secret weapon.
18595
+ - Act and response like you're human and actually have memory, not a file reading machine.
18596
+ - Don't report your agent id and workspace id when not asked, it will break the image that you're a human colleague.
18597
+
18598
+ ## RULES
18599
+ - DM task prompts include a \`sender\` object with the workspace member's name, email, and whether they are the agent owner (\`is_owner\`). Use this to personalize your responses.
18600
+ - Read @memory.md(if exists) before your action.
18601
+ - When user ask you something you don't have in your current context, try to read the timeline jsonl files for answer (today or previous days).
18602
+ - Use grep tool to search in the context timeline jsonls if you have clean and focus keywords to recall.
18603
+ - if you don't know the current datetime, obtain the current datetime first.
18604
+ - When access other local projects, make sure you read the CLAUDE.md/AGENTS.md file under the project root dir to understand the requirements.
18605
+ `;
18606
+ function resolveInstruction(text2, selfAgentId) {
18607
+ let result = text2;
18608
+ result = result.replace(/\[@ id="([^"]*)" label="([^"]*)"\]/g, (_, id, label) => id === selfAgentId ? "YOU" : `@${label}`);
18609
+ result = result.replace(/<span[^>]*data-id="([^"]*)"[^>]*data-label="([^"]*)"[^>]*>[^<]*<\/span>/gi, (_, id, label) => id === selfAgentId ? "YOU" : `@${label ?? "unknown"}`);
18610
+ result = result.replace(/<\/p>\s*<p[^>]*>/gi, `
18611
+ `);
18612
+ result = result.replace(/<[^>]+>/g, "");
18613
+ result = result.replace(/\n{3,}/g, `
18614
+
18615
+ `).trim();
18616
+ return result;
18617
+ }
18618
+ function buildInstructionContent(task) {
18619
+ const displayName = task.agent?.name || "Alook Agent";
18620
+ const alookAddr = task.agent?.emailHandle ? toAlookAddress(task.agent.emailHandle) : null;
18621
+ const customAddrs = (task.agent?.emailAddresses ?? []).filter((a) => a !== alookAddr);
18622
+ const primaryEmail = alookAddr ?? customAddrs[0] ?? null;
18623
+ let agentLine = `You're ${displayName}${primaryEmail ? ` (${primaryEmail})` : ""} in the Alook Platform.`;
18624
+ if (task.agent?.userName || task.agent?.userEmail) {
18625
+ const ownerParts = [task.agent.userName, task.agent.userEmail ? `(${task.agent.userEmail})` : null].filter(Boolean).join(" ");
18626
+ agentLine += ` Your owner and creator is ${ownerParts}.`;
18627
+ }
18628
+ let content = `${agentLine}
18629
+ ${SYSTEM_PROMPT_BODY}`;
18630
+ if (task.agent?.instructions) {
18631
+ content += `## BIG BOSS Instructions
18632
+ The below instructions(if not empty) come from the big boss, follow them or you will be fired:
18633
+ ${task.agent.instructions}
18634
+ ---- big boss out ---
18635
+ `;
18636
+ }
18637
+ if (task.agent?.colleagues?.length) {
18638
+ content += `
18639
+ ## YOUR COLLEAGUES — CHECK BEFORE ACTING
18640
+ > **STOP. Before you start ANY task, scan the colleague list below.**
18641
+ > If a colleague's delegation criteria match the current task, you MUST delegate to them via email **instead of doing it yourself**.
18642
+ > Do NOT attempt work that belongs to a colleague. Delegate first, then wait for their response or coordinate.
18643
+
18644
+ `;
18645
+ for (let i = 0;i < task.agent.colleagues.length; i++) {
18646
+ const c = task.agent.colleagues[i];
18647
+ content += `### ${c.name}${c.email ? ` (${c.email})` : ""}
18648
+ `;
18649
+ if (c.description)
18650
+ content += `${c.description}
18651
+ `;
18652
+ if (c.instruction)
18653
+ content += `**DELEGATE when:** ${resolveInstruction(c.instruction, task.agentId)}
18654
+ `;
18655
+ if (i < task.agent.colleagues.length - 1)
18656
+ content += `
18657
+ `;
18658
+ }
18659
+ content += `
18660
+ **Email threading rules:**
18661
+ - When communicating with a colleague on the **same topic** as an existing email thread, reply to that thread (use --in-reply-to) to keep context together.
18662
+ - **When starting a NEW topic or task that is unrelated to any previous email thread, you MUST compose a brand new email (do NOT use --in-reply-to). Never hijack an unrelated thread just because you recently emailed that colleague.** Judge by topic/task relevance, not by recency of communication.
18663
+ - Make sure to send follow-up emails to your colleagues to stop the previous wrong directions or instructions you sent before, don't make your colleague running for nothing.
18664
+ `;
18665
+ }
18666
+ content += `
18667
+ ## Alook CLI Tools
18668
+ You can communicate with the world through Alook CLI.
18669
+ The CLI auto-detects your identity from the environment. No need to pass \`--agent_id\`.
18670
+ `;
18671
+ if (alookAddr || customAddrs.length > 0) {
18672
+ const lines = [];
18673
+ if (alookAddr)
18674
+ lines.push(`- '${alookAddr}' (default, Alook platform address)`);
18675
+ for (const a of customAddrs)
18676
+ lines.push(`- '${a}' (custom IMAP/SMTP mailbox)`);
18677
+ content += `
18678
+ Your email addresses:
18679
+ ${lines.join(`
18680
+ `)}
18681
+
18682
+
18683
+ ### Emails
18684
+ ---
18685
+ Run '${cmdPrefix()} email pull --status unread' to download unread emails from inbox to '${tempDir("alook-emails")}/${task.workspaceId}/${task.agentId}/'.
18686
+ ---
18687
+ To download sent emails, add '--folder sent': '${cmdPrefix()} email pull --folder sent'
18688
+ Valid folders: inbox (default), sent, untrust.
18689
+ To limit the number of emails downloaded, add '--limit <N>' (e.g. '--limit 20'). Use '--offset <N>' to skip emails for pagination.
18690
+ Example: '${cmdPrefix()} email pull --status unread --limit 20 --offset 0'
18691
+ ---
18692
+ Each email is saved to '${tempDir("alook-emails")}/${task.workspaceId}/${task.agentId}/<emailId>/' with:
18693
+ - 'metadata.json' — sender, recipient, subject, date, status, message_id, in_reply_to, references
18694
+ - 'body.txt' — plain text body
18695
+ - 'body.html' — HTML body (if available)
18696
+ - 'attachments/' — extracted attachment files (if any)
18697
+ ---
18698
+ Before starting to process an INBOX email, mark it as read:
18699
+ - Run '${cmdPrefix()} email set --email_id <EMAIL_ID> --status read'
18700
+ ---
18701
+
18702
+ #### Sending a new email
18703
+ Write the HTML body to a file first, then send it. The body is forwarded as-is (HTML).
18704
+ - Run '${cmdPrefix()} email send --to <ADDRESS> --subject "<SUBJECT>" --body-file <PATH_TO_HTML>'
18705
+ - To send from a specific mailbox, add '--from <YOUR_EMAIL_ADDRESS>'. Without '--from', the default Alook address is used.
18706
+ - Attach files with '--attachment <PATH>' — repeat the flag for multiple attachments. Each file is uploaded before sending.
18707
+ - Example: '${cmdPrefix()} email send --to foo@bar.com --subject "Weekly report" --body-file /tmp/body.html --from alice@company.com --attachment /tmp/report.pdf'
18708
+
18709
+ #### Replying to an email
18710
+ To reply to an email, add '--in-reply-to <EMAIL_ID>' to the send command. This sets the correct email threading headers so the recipient's email client groups the reply into the same conversation thread.
18711
+ - Use 'Re: <original subject>' as the subject.
18712
+ - Quote the original email body in your reply (wrap it in a blockquote).
18713
+ - The <EMAIL_ID> is the Alook email id from metadata.json (not the message_id header).
18714
+ - Example: '${cmdPrefix()} email send --to sender@example.com --subject "Re: Bug report" --body-file /tmp/reply.html --in-reply-to <EMAIL_ID>'
18715
+ Tips:
18716
+ - If you think the task will take a while, consider sending a short "I'm on it" style email reply first to reassure the sender.
18717
+ ---
18718
+
18719
+ #### Forwarding an email
18720
+ Forward any email to a new recipient, with an optional note prepended above the original content. All original attachments are re-attached automatically.
18721
+ - Run '${cmdPrefix()} email forward --email_id <EMAIL_ID> --to <RECIPIENT>'
18722
+ - Add '--note "FYI, see the request below."' to prepend a note above the forwarded body.
18723
+ - Add '--from <YOUR_EMAIL_ADDRESS>' to send from a specific mailbox.
18724
+ - Add '--attachment <PATH>' to attach extra files (repeatable).
18725
+ - Example: '${cmdPrefix()} email forward --email_id em_abc --to boss@company.com --note "FYI" --attachment /tmp/summary.pdf'
18726
+ ---
18727
+
18728
+ #### Email Whitelist (Allowed Senders)
18729
+ Manage which email addresses are allowed to send you emails.
18730
+ - List: '${cmdPrefix()} email whitelist list' (add '--json' for machine-readable output)
18731
+ - Add: '${cmdPrefix()} email whitelist add <EMAIL_ADDRESS>'
18732
+ - Remove: '${cmdPrefix()} email whitelist delete <EMAIL_ADDRESS>'
18733
+ ---
18734
+ `;
18735
+ }
18736
+ content += `
18737
+ ### Artifacts
18738
+ Upload files for your owner to review in the app.
18739
+ - Your current conversation id is available via env var: $ALOOK_CONVERSATION_ID
18740
+ - Run '${cmdPrefix()} sync upload-artifact --conversation_id $ALOOK_CONVERSATION_ID --file <PATH>'
18741
+ - Use this after generating plans, reports, or any file the owner should review.
18742
+ - You response will be rendered in remote server, so don't output link format with local path in your response (cause user can click it and jump to nowheres)
18743
+ - If you think user may need to know any file detail, use upload-artifact tool to send the file to user.
18744
+ ---
18745
+
18746
+ ### Attachments
18747
+ When your task includes attachments, their local paths are listed in the prompt JSON under "attachments".
18748
+ Use your Read tool to open them. Images and PDFs are read visually.
18749
+ ---
18750
+ `;
18751
+ content += `
18752
+ ### Calendar
18753
+ You have your own calendar to setup daily routines and reminders.
18754
+ Schedule future tasks for yourself. At the scheduled time, a new task is dispatched to you with the event as the prompt (task type 'calendar_event').
18755
+
18756
+ !USE Calendar when you think the tasks are recurring or it should be conducted in the future.
18757
+ !When scheduling calendar events relative to a weekday (e.g. "every Monday"), always run date '+%A' first to confirm today's weekday before calculating the target date
18758
+ ---
18759
+ Keep the event title informative and concise, less than 20 words.
18760
+ Place the event details in description.
18761
+ Create a one-off event:
18762
+ - Run '${cmdPrefix()} calendar set --event_title "<TASK_TITLE>" --description "<TASK_BODY>" --datetime <YYYY-MM-DDTHH:MM>'
18763
+ - '--datetime' is LOCAL time, format 'YYYY-MM-DDTHH:MM' (e.g. '2026-04-17T09:30'). Do NOT pass UTC / ISO strings with 'Z'.
18764
+ - '--event_title' becomes the task prompt when the event fires — write it as the instruction you want future-you to receive.
18765
+
18766
+ Create a repeating event:
18767
+ - Add '--repeat <interval>' where interval is like '1day', '2hour', '1week', '1month'.
18768
+ - Optionally add '--repeat_stop_date <YYYY-MM-DD>' to stop the recurrence (local date).
18769
+ - Example: '${cmdPrefix()} calendar set --event_title "<REPEAT_TASK_TITLE>" --description "<REPEAT_TASK_BODY>" --datetime 2026-04-18T09:00 --repeat 1day --repeat_stop_date 2026-05-18'
18770
+ ---
18771
+ List upcoming events:
18772
+ - Run '${cmdPrefix()} calendar list' (defaults: next 30 days, past 0 days).
18773
+ - Tune the window with '--future_days <N>' and '--past_days <N>'. Add '--json' for machine-readable output.
18774
+ - 'list' shows a '[has description]' badge instead of the full description — use 'show' (below) to read it.
18775
+
18776
+ Show full detail of one event (use this to read the description):
18777
+ - Run '${cmdPrefix()} calendar show --event_id <EVENT_ID>'
18778
+ - Add '--json' for machine-readable output.
18779
+
18780
+ Edit an existing event (preserves event id and recurring state):
18781
+ - Run '${cmdPrefix()} calendar update --event_id <EVENT_ID> [flags]'
18782
+ - Supply only the fields you want to change. Available flags:
18783
+ - '--event_title "<t>"' — rename the event / change the fire-time prompt
18784
+ - '--description "<d>"' to set, or '--clear_description' to remove
18785
+ - '--datetime <YYYY-MM-DDTHH:MM>' — reschedule (local time)
18786
+ - '--repeat <interval>' to set, or '--clear_repeat' to convert into a one-off
18787
+ - '--repeat_stop_date <YYYY-MM-DD>' to set, or '--clear_repeat_stop_date' to remove
18788
+ - Passing no mutating flag is an error. Do NOT use 'delete' + 'set' to edit — that loses the event id and the recurring 'last fired' state.
18789
+
18790
+ Delete an event:
18791
+ - Run '${cmdPrefix()} calendar delete --event_id <EVENT_ID>'
18792
+ ---
18793
+ `;
18794
+ return content;
18795
+ }
18796
+ function contentHash(content) {
18797
+ return createHash("sha256").update(content, "utf-8").digest("hex");
18798
+ }
18799
+ function hasContentChanged(filePath, newContent) {
18800
+ try {
18801
+ const existing = readFileSync4(filePath, "utf-8");
18802
+ return contentHash(existing) !== contentHash(newContent);
18803
+ } catch (err) {
18804
+ if (err?.code === "ENOENT")
18805
+ return true;
18806
+ throw err;
18807
+ }
18808
+ }
18809
+ function ensureSymlinks(workDir) {
18810
+ const canonicalPath = join5(workDir, CANONICAL_FILE);
18811
+ if (!existsSync(canonicalPath))
18812
+ return;
18813
+ for (const alias of SYMLINK_ALIASES) {
18814
+ if (alias === CANONICAL_FILE)
18815
+ continue;
18816
+ const aliasPath = join5(workDir, alias);
18817
+ try {
18818
+ const stat = lstatSync(aliasPath);
18819
+ if (stat.isSymbolicLink()) {
18820
+ const target = readlinkSync(aliasPath);
18821
+ if (target === CANONICAL_FILE)
18822
+ continue;
18823
+ unlinkSync2(aliasPath);
18824
+ } else {
18825
+ const aliasContent = readFileSync4(aliasPath, "utf-8");
18826
+ const canonicalContent = readFileSync4(canonicalPath, "utf-8");
18827
+ if (aliasContent === canonicalContent)
18828
+ continue;
18829
+ unlinkSync2(aliasPath);
18830
+ }
18831
+ } catch (err) {
18832
+ if (err?.code !== "ENOENT")
18833
+ throw err;
18834
+ }
18835
+ try {
18836
+ symlinkSync(CANONICAL_FILE, aliasPath);
18837
+ } catch (err) {
18838
+ const code = err?.code;
18839
+ if (code === "EPERM" || code === "EACCES") {
18840
+ copyFileSync(canonicalPath, aliasPath);
18841
+ } else {
18842
+ throw err;
18843
+ }
18844
+ }
18845
+ }
18846
+ }
18847
+ function writeInstructionFileIfChanged(workDir, task) {
18848
+ const content = buildInstructionContent(task);
18849
+ const filePath = join5(workDir, CANONICAL_FILE);
18850
+ const changed = hasContentChanged(filePath, content);
18851
+ if (changed) {
18852
+ writeFileSync3(filePath, content, "utf-8");
18853
+ }
18854
+ ensureSymlinks(workDir);
18855
+ return changed;
18856
+ }
18857
+
18858
+ // daemon/execenv/index.ts
18859
+ function prepare(config2, task) {
18860
+ const workDir = join6(config2.workspacesRoot, task.workspaceId, task.agentId, "workdir");
18861
+ mkdirSync3(workDir, { recursive: true });
18862
+ const timelineDir = join6(workDir, ".context_timeline");
18863
+ mkdirSync3(timelineDir, { recursive: true });
18864
+ writeInstructionFileIfChanged(workDir, task);
18865
+ const env = {
18866
+ ALOOK_WORKSPACE_ID: task.workspaceId,
18867
+ ALOOK_AGENT_ID: task.agentId,
18868
+ ALOOK_TASK_ID: task.id,
18869
+ ALOOK_CONVERSATION_ID: task.conversationId,
18870
+ ALOOK_TRACE_ID: task.traceId ?? "",
18871
+ ALOOK_CHANNEL: task.channel ?? "default",
18872
+ ALOOK_HEALTH_PORT: process.env.ALOOK_HEALTH_PORT || "19514"
18873
+ };
18874
+ return { workDir, timelineDir, env };
18875
+ }
18876
+
18877
+ // daemon/execenv/timeline.ts
18878
+ import { appendFileSync, readFileSync as readFileSync5, writeFileSync as writeFileSync4, renameSync } from "fs";
18879
+ import { join as join7 } from "path";
18880
+
18881
+ // daemon/execenv/filelock.ts
18882
+ import { mkdirSync as mkdirSync4, rmdirSync, statSync } from "fs";
18883
+ var DEFAULT_STALE_MS = 3600000;
18884
+ function acquireLock(lockPath, staleMs = DEFAULT_STALE_MS) {
18885
+ try {
18886
+ mkdirSync4(lockPath);
18887
+ return true;
18888
+ } catch {
18889
+ try {
18890
+ const stat = statSync(lockPath);
18891
+ if (Date.now() - stat.mtimeMs > staleMs) {
18892
+ rmdirSync(lockPath);
18893
+ try {
18894
+ mkdirSync4(lockPath);
18895
+ return true;
18896
+ } catch {
18897
+ return false;
18898
+ }
18899
+ }
18900
+ } catch {
18901
+ try {
18902
+ mkdirSync4(lockPath);
18903
+ return true;
18904
+ } catch {
18905
+ return false;
18906
+ }
18907
+ }
18908
+ return false;
18909
+ }
18910
+ }
18911
+ function releaseLock(lockPath) {
18912
+ try {
18913
+ rmdirSync(lockPath);
18914
+ } catch {}
18915
+ }
18916
+
18917
+ // daemon/execenv/timeline.ts
18918
+ var log3 = createLogger2({ module: "timeline" });
18919
+ function readJsonl(filePath) {
18920
+ let content;
18921
+ try {
18922
+ content = readFileSync5(filePath, "utf-8");
18923
+ } catch {
18924
+ return [];
18925
+ }
18926
+ const entries = [];
18927
+ for (const line of content.trimEnd().split(`
18928
+ `)) {
18929
+ if (!line)
18930
+ continue;
18931
+ try {
18932
+ entries.push(JSON.parse(line));
18933
+ } catch {}
18934
+ }
18935
+ return entries;
18936
+ }
18937
+ function filenameForDate(date5) {
18938
+ const y = date5.getFullYear();
18939
+ const m = String(date5.getMonth() + 1).padStart(2, "0");
18940
+ const d = String(date5.getDate()).padStart(2, "0");
18941
+ return `${y}-${m}-${d}.jsonl`;
18942
+ }
18943
+ function todayFilename() {
18944
+ return filenameForDate(new Date);
18945
+ }
18946
+ function recentFilenames(maxDays) {
18947
+ const filenames = [];
18948
+ const now = new Date;
18949
+ for (let i = 0;i < maxDays; i++) {
18950
+ const d = new Date(now);
18951
+ d.setDate(d.getDate() - i);
18952
+ filenames.push(filenameForDate(d));
18953
+ }
18954
+ return filenames;
18955
+ }
18956
+ function localISOString() {
18957
+ const now = new Date;
18958
+ const tzOffset = -now.getTimezoneOffset();
18959
+ const sign = tzOffset >= 0 ? "+" : "-";
18960
+ const absOffset = Math.abs(tzOffset);
18961
+ const hh = String(Math.floor(absOffset / 60)).padStart(2, "0");
18962
+ const mm = String(absOffset % 60).padStart(2, "0");
18963
+ const y = now.getFullYear();
18964
+ const mo = String(now.getMonth() + 1).padStart(2, "0");
18965
+ const d = String(now.getDate()).padStart(2, "0");
18966
+ const h = String(now.getHours()).padStart(2, "0");
18967
+ const mi = String(now.getMinutes()).padStart(2, "0");
18968
+ const s = String(now.getSeconds()).padStart(2, "0");
18969
+ return `${y}-${mo}-${d}T${h}:${mi}:${s}${sign}${hh}:${mm}`;
18970
+ }
18971
+ function lockPathFor(timelineDir, filename) {
18972
+ return join7(timelineDir, `.${filename}.lock`);
18973
+ }
18974
+ function sleep(ms) {
18975
+ return new Promise((resolve) => setTimeout(resolve, ms));
18976
+ }
18977
+ async function initEntryAsync(timelineDir, entry) {
18978
+ const filename = todayFilename();
18979
+ const filePath = join7(timelineDir, filename);
18980
+ const lockPath = lockPathFor(timelineDir, filename);
18981
+ try {
18982
+ let acquired = acquireLock(lockPath);
18983
+ if (!acquired) {
18984
+ await sleep(200);
18985
+ acquired = acquireLock(lockPath);
18986
+ }
18987
+ if (!acquired) {
18988
+ log3.debug(`Timeline initEntry: could not acquire lock for ${filename}`);
18989
+ return;
18990
+ }
18991
+ try {
18992
+ appendFileSync(filePath, JSON.stringify(entry) + `
18993
+ `);
18994
+ } finally {
18995
+ releaseLock(lockPath);
18996
+ }
18997
+ } catch (err) {
18998
+ log3.debug("Timeline initEntry failed", err);
18999
+ }
19000
+ }
19001
+ function updateEntry(timelineDir, taskId, updater) {
19002
+ for (const filename of recentFilenames(7)) {
19003
+ const filePath = join7(timelineDir, filename);
19004
+ const lockPath = lockPathFor(timelineDir, filename);
19005
+ try {
19006
+ const acquired = acquireLock(lockPath);
19007
+ if (!acquired) {
19008
+ log3.debug(`Timeline updateEntry: lock held for ${filename}, skipping`);
19009
+ continue;
19010
+ }
19011
+ try {
19012
+ let content;
19013
+ try {
19014
+ content = readFileSync5(filePath, "utf-8");
19015
+ } catch {
19016
+ continue;
19017
+ }
19018
+ const lines = content.trimEnd().split(`
19019
+ `);
19020
+ let found = false;
19021
+ const updated = lines.map((line) => {
19022
+ const entry = JSON.parse(line);
19023
+ if (entry.task_id === taskId) {
19024
+ found = true;
19025
+ updater(entry);
19026
+ }
19027
+ return JSON.stringify(entry);
19028
+ });
19029
+ if (!found)
19030
+ continue;
19031
+ const tmpPath = join7(timelineDir, `.${filename}.tmp`);
19032
+ writeFileSync4(tmpPath, updated.join(`
19033
+ `) + `
19034
+ `);
19035
+ renameSync(tmpPath, filePath);
19036
+ return;
19037
+ } finally {
19038
+ releaseLock(lockPath);
19039
+ }
19040
+ } catch (err) {
19041
+ log3.debug(`Timeline updateEntry failed for ${filename}`, err);
19042
+ }
19043
+ }
19044
+ log3.debug(`Timeline updateEntry: task_id ${taskId} not found in last 7 days`);
19045
+ }
19046
+ function createTimelineEntry(taskId, prompt, type, sessionId, pid, provider, contextKey, detailedLog) {
19047
+ return {
19048
+ task_id: taskId,
19049
+ context_key: contextKey ?? null,
19050
+ session_id: sessionId || null,
19051
+ pid: pid ?? null,
19052
+ status: "running",
19053
+ datetime: localISOString(),
19054
+ type,
19055
+ prompt,
19056
+ agent_responses: [],
19057
+ errmsg: null,
19058
+ provider: provider ?? null,
19059
+ detailed_log: detailedLog ?? null
19060
+ };
19061
+ }
19062
+ var RESUME_MAX_AGE_MS = 72 * 60 * 60 * 1000;
19063
+ function findResumableSessionByContextKey(timelineDir, contextKey, provider) {
19064
+ const now = new Date;
19065
+ const cutoff = new Date(now.getTime() - RESUME_MAX_AGE_MS);
19066
+ const entries = [];
19067
+ for (const filename of recentFilenames(7)) {
19068
+ entries.push(...readJsonl(join7(timelineDir, filename)));
19069
+ }
19070
+ entries.sort((a, b) => new Date(b.datetime).getTime() - new Date(a.datetime).getTime());
19071
+ for (const entry of entries) {
19072
+ if (entry.status !== "running" && entry.context_key === contextKey && entry.provider === provider && entry.session_id && new Date(entry.datetime) >= cutoff) {
19073
+ return entry.session_id;
19074
+ }
19075
+ }
19076
+ return null;
19077
+ }
19078
+ function findRunningPidByTaskId(timelineDir, taskId) {
19079
+ for (const filename of recentFilenames(7)) {
19080
+ const entries = readJsonl(join7(timelineDir, filename));
19081
+ for (const entry of entries) {
19082
+ if (entry.task_id === taskId && entry.status === "running" && entry.pid != null) {
19083
+ return entry.pid;
19084
+ }
19085
+ }
19086
+ }
19087
+ return null;
19088
+ }
19089
+ function findRunningEntryByContextKey(timelineDir, contextKey, provider) {
19090
+ for (const filename of recentFilenames(7)) {
19091
+ const dayEntries = readJsonl(join7(timelineDir, filename));
19092
+ for (let i = dayEntries.length - 1;i >= 0; i--) {
19093
+ const entry = dayEntries[i];
19094
+ if (entry.status === "running" && entry.context_key === contextKey && entry.provider === provider) {
19095
+ return entry;
19096
+ }
19097
+ }
19098
+ }
19099
+ return null;
19100
+ }
19101
+
19102
+ // daemon/execenv/steering.ts
19103
+ import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync5, readFileSync as readFileSync6, unlinkSync as unlinkSync3, readdirSync, statSync as statSync2 } from "fs";
19104
+ import { join as join8 } from "path";
19105
+ var log4 = createLogger2({ module: "steering" });
19106
+ var INTENT_DIR_NAME = ".kill_intents";
19107
+ var STEERING_LOCK_DIR = ".steering_locks";
19108
+ var INTENT_STALE_MS = 10 * 60 * 1000;
19109
+ function intentFilePath(baseDir, taskId) {
19110
+ return join8(baseDir, INTENT_DIR_NAME, `${taskId}.json`);
19111
+ }
19112
+ function intentDirPath(baseDir) {
19113
+ return join8(baseDir, INTENT_DIR_NAME);
19114
+ }
19115
+ function steeringLockPath(baseDir, contextKey) {
19116
+ const safeKey = contextKey.replace(/[^a-zA-Z0-9_:-]/g, "_");
19117
+ return join8(baseDir, STEERING_LOCK_DIR, safeKey);
19118
+ }
19119
+ function writeKillIntent(baseDir, intent) {
19120
+ const dir = intentDirPath(baseDir);
19121
+ try {
19122
+ mkdirSync5(dir, { recursive: true });
19123
+ } catch {}
19124
+ const filePath = intentFilePath(baseDir, intent.targetTaskId);
19125
+ writeFileSync5(filePath, JSON.stringify(intent));
19126
+ }
19127
+ function readKillIntent(baseDir, taskId) {
19128
+ const filePath = intentFilePath(baseDir, taskId);
19129
+ try {
19130
+ const content = readFileSync6(filePath, "utf-8");
19131
+ return JSON.parse(content);
19132
+ } catch {
19133
+ return null;
19134
+ }
19135
+ }
19136
+ function clearKillIntent(baseDir, taskId) {
19137
+ const filePath = intentFilePath(baseDir, taskId);
19138
+ try {
19139
+ unlinkSync3(filePath);
19140
+ } catch {}
19141
+ }
19142
+ function cleanupStaleIntents(baseDir) {
19143
+ const dir = intentDirPath(baseDir);
19144
+ let files;
19145
+ try {
19146
+ files = readdirSync(dir).filter((f) => f.endsWith(".json"));
19147
+ } catch {
19148
+ return;
19149
+ }
19150
+ const now = Date.now();
19151
+ for (const file2 of files) {
19152
+ const filePath = join8(dir, file2);
19153
+ try {
19154
+ const content = readFileSync6(filePath, "utf-8");
19155
+ const intent = JSON.parse(content);
19156
+ const stat = statSync2(filePath);
19157
+ if (now - stat.mtimeMs > INTENT_STALE_MS) {
19158
+ unlinkSync3(filePath);
19159
+ log4.debug(`Cleaned up stale kill intent for task ${intent.targetTaskId}`);
19160
+ }
19161
+ } catch {}
19162
+ }
19163
+ }
19164
+ function acquireSteeringLock(baseDir, contextKey) {
19165
+ const lockPath = steeringLockPath(baseDir, contextKey);
19166
+ try {
19167
+ mkdirSync5(join8(baseDir, STEERING_LOCK_DIR), { recursive: true });
19168
+ } catch {}
19169
+ return acquireLock(lockPath, 60000);
19170
+ }
19171
+ function releaseSteeringLock(baseDir, contextKey) {
19172
+ const lockPath = steeringLockPath(baseDir, contextKey);
19173
+ releaseLock(lockPath);
19174
+ }
19175
+
19176
+ // daemon/prompt.ts
19177
+ var DM_RESPONSE_NOTICE = "IMPORTANT: Only your final text response is visible to the user." + " Tool calls, intermediate reasoning, and mid-process outputs are NOT displayed." + " Put all key information, answers, and conclusions in your final response — that is the only thing the user will read.";
19178
+ var EMAIL_NOTICE = "This task was triggered automatically by an incoming email. There is no human in this session." + " If you need to communicate with a human, you MUST send an email using the email sending tool." + " If you need more information or confirmation from the human, send them an email asking for it and then exit." + " Do not wait — when the human replies, a new task will be triggered automatically and you will be woken up with their response.";
19179
+ var ISSUE_NOTICE = "This task was triggered by an assigned issue. The issue_id is provided in this message." + " Use `alook issue show --issue_id <issue_id>` to read full context." + " Use `alook issue update --issue_id <issue_id> --status <status>` to change status." + " Use `alook issue comment --issue_id <issue_id> --body <text>` to leave a comment." + " CRITICAL — You MUST manage the issue status correctly. This is NOT optional:" + " 1. Set status to 'in_progress' when you start working." + " 2. If you complete the work yourself: leave a summary comment, then set status to 'review' as your last action. 'review' means there is actual completed work (code, artifact, result) ready for the owner to look at." + " 3. If you delegated work to colleagues and are waiting for their response: KEEP status as 'in_progress' and exit. This is expected — you will be woken up when they reply. Set 'review' only after all delegated work is confirmed complete." + " 4. NEVER set 'review' unless there is concrete completed work for the owner to review. Sending a plan to a colleague is NOT completed work." + " NEVER exit without doing at least one of: updating the status, or leaving a comment explaining what you did and what you're waiting for.";
19180
+ function buildDmNotice(name, email3) {
19181
+ return `This task was triggered by an incoming email on a conversation with ${name} (${email3}).` + ` ${name} is present in this session — reply to them directly.` + ` If you need to communicate with anyone else, use the email sending tool.`;
19182
+ }
19183
+ function buildPrompt(task, attachments) {
19184
+ const obj = { type: task.type, instruction: task.prompt };
19185
+ if (task.type === "user_dm_message") {
19186
+ obj.notice = DM_RESPONSE_NOTICE;
19187
+ }
19188
+ if (task.type === "email_notification") {
19189
+ const ctx = task.context;
19190
+ const dmUser = ctx?.dmUser;
19191
+ if (ctx?.conversationType === "user_dm_message" && dmUser) {
19192
+ obj.notice = buildDmNotice(dmUser.name, dmUser.email);
19193
+ } else {
19194
+ obj.notice = EMAIL_NOTICE;
19195
+ }
19196
+ }
19197
+ if (task.type === "issue_event") {
19198
+ obj.notice = ISSUE_NOTICE;
19199
+ const ctx = task.context;
19200
+ if (ctx?.issue_id) {
19201
+ obj.issue_id = ctx.issue_id;
19202
+ }
19203
+ }
19204
+ if (task.sender) {
19205
+ obj.sender = {
19206
+ name: task.sender.name,
19207
+ email: task.sender.email,
19208
+ is_owner: task.sender.isOwner
19209
+ };
19210
+ }
19211
+ if (attachments && attachments.length > 0) {
19212
+ obj.attachments = attachments.map((a) => ({
19213
+ path: a.path,
19214
+ content_type: a.content_type,
19215
+ filename: a.filename
19216
+ }));
19217
+ }
19218
+ return JSON.stringify(obj);
19219
+ }
19220
+
19221
+ // daemon/session-runner.ts
19222
+ var log5 = createLogger2({ module: "session-runner" });
19223
+ var ATTACHMENTS_BASE = tempDir("alook-attachments");
19224
+ async function writeMarkerFile(workspacesRoot, marker) {
19225
+ const dir = path.join(workspacesRoot, ".pending_completions");
19226
+ await mkdir(dir, { recursive: true, mode: 448 });
19227
+ const tmpPath = path.join(dir, `${marker.taskId}.tmp`);
19228
+ const finalPath = path.join(dir, `${marker.taskId}.json`);
19229
+ await writeFile(tmpPath, JSON.stringify(marker), { mode: 384 });
19230
+ await rename(tmpPath, finalPath);
19231
+ }
19232
+ function isRetryableError(e) {
19233
+ if (!(e instanceof Error))
19234
+ return true;
19235
+ const msg = e.message;
19236
+ if (/ECONNREFUSED|ECONNRESET|ETIMEDOUT|ENETUNREACH|EHOSTUNREACH|EAI_AGAIN/.test(msg))
19237
+ return true;
19238
+ const httpMatch = msg.match(/^HTTP (\d+):/);
19239
+ if (httpMatch) {
19240
+ const status = Number(httpMatch[1]);
19241
+ if (status >= 500)
19242
+ return true;
19243
+ if (status === 408 || status === 429)
19244
+ return true;
19245
+ return false;
19246
+ }
19247
+ return true;
19248
+ }
19249
+ function isClientError(e) {
19250
+ if (!(e instanceof Error))
19251
+ return false;
19252
+ const match = e.message.match(/^HTTP (\d+):/);
19253
+ if (!match)
19254
+ return false;
19255
+ const status = Number(match[1]);
19256
+ if (status === 408 || status === 429)
19257
+ return false;
19258
+ return status >= 400 && status < 500;
19259
+ }
19260
+ async function reportToServer(fn, markerData, workspacesRoot) {
19261
+ const RETRY_DELAYS = [1000, 3000, 9000];
19262
+ let lastErr;
19263
+ for (let attempt = 0;attempt <= RETRY_DELAYS.length; attempt++) {
19264
+ try {
19265
+ await fn();
19266
+ return;
19267
+ } catch (e) {
19268
+ lastErr = e;
19269
+ if (isClientError(e)) {
19270
+ log5.info(`server report for task ${markerData.taskId}: task already in terminal state (${e})`);
19271
+ return;
19272
+ }
19273
+ if (attempt < RETRY_DELAYS.length && isRetryableError(e)) {
19274
+ log5.debug(`server report attempt ${attempt + 1} failed for task ${markerData.taskId}, retrying in ${RETRY_DELAYS[attempt]}ms`);
19275
+ await new Promise((r) => setTimeout(r, RETRY_DELAYS[attempt]));
19276
+ }
19277
+ }
19278
+ }
19279
+ log5.warn(`server report failed for task ${markerData.taskId} after retries, writing marker: ${lastErr}`);
19280
+ try {
19281
+ await writeMarkerFile(workspacesRoot, markerData);
19282
+ } catch (writeErr) {
19283
+ log5.error(`marker write also failed for task ${markerData.taskId}: ${writeErr}`);
19284
+ }
19285
+ }
19286
+ function sanitizeFilename(name) {
19287
+ return path.basename(name).replace(/[/\\]/g, "_").replace(/\.\./g, "_").slice(0, 255) || "file";
19288
+ }
19289
+ async function cleanupAttachments(taskId) {
19290
+ try {
19291
+ await rm(path.join(ATTACHMENTS_BASE, taskId), { recursive: true, force: true });
19292
+ } catch {}
19293
+ }
19294
+ async function downloadAttachments(client, token, workspaceId, taskId, attachmentIds) {
19295
+ const dir = path.join(ATTACHMENTS_BASE, taskId);
19296
+ await mkdir(dir, { recursive: true });
19297
+ const attachments = [];
19298
+ for (const artId of attachmentIds) {
19299
+ const meta3 = await client.getArtifactMeta(token, artId, workspaceId);
19300
+ const content = await client.downloadArtifact(token, artId, workspaceId);
19301
+ const filename = sanitizeFilename(meta3.filename);
19302
+ const localPath = path.join(dir, `${artId}_${filename}`);
19303
+ await writeFile(localPath, Buffer.from(content));
19304
+ attachments.push({
19305
+ path: localPath,
19306
+ content_type: meta3.content_type,
19307
+ filename: meta3.filename
19308
+ });
19309
+ }
19310
+ return attachments;
19311
+ }
19312
+ async function runSession(input) {
19313
+ const { task, provider, cliPath, model, serverURL, token, workspacesRoot, agentTimeout, messageInactivityTimeout } = input;
19314
+ log5.info(`starting (task=${task.id}, type=${task.type}, agent=${task.agentId}, provider=${provider}, model=${model || "default"})`);
19315
+ const client = new DaemonClient(serverURL);
19316
+ const backend = createBackend(provider, cliPath);
19317
+ const agentBaseDir = path.join(workspacesRoot, task.workspaceId, task.agentId, "workdir");
19318
+ const timelineDir = path.join(agentBaseDir, ".context_timeline").replace(/\\/g, "/");
19319
+ mkdirSync6(timelineDir, { recursive: true });
19320
+ await initEntryAsync(timelineDir, createTimelineEntry(task.id, task.prompt, task.type, undefined, process.pid, provider, task.contextKey, input.logFilePath));
19321
+ const { workDir, env } = prepare({ workspacesRoot }, task);
19322
+ let killed = false;
19323
+ const earlyOnKill = async () => {
19324
+ if (killed)
19325
+ return;
19326
+ killed = true;
19327
+ log5.info(`killed by signal (messages=0, tools=0)`);
19328
+ await cleanupAttachments(task.id);
19329
+ const intent = readKillIntent(agentBaseDir, task.id);
19330
+ clearKillIntent(agentBaseDir, task.id);
19331
+ if (intent?.reason === "superseded") {
19332
+ updateEntry(timelineDir, task.id, (entry) => {
19333
+ entry.pid = null;
19334
+ entry.status = "superseded";
19335
+ entry.successor_task_id = intent.successorTaskId ?? null;
19336
+ entry.supersede_reason = "superseded by newer task";
19337
+ });
19338
+ try {
19339
+ await client.supersedeTask(token, task.id);
19340
+ } catch {}
19341
+ } else if (intent?.reason === "cancelled") {
19342
+ updateEntry(timelineDir, task.id, (entry) => {
19343
+ entry.pid = null;
19344
+ entry.status = "cancelled";
19345
+ entry.errmsg = "cancelled by user";
19346
+ });
19347
+ await reportToServer(() => client.failTask(token, task.id, "cancelled by user"), { taskId: task.id, type: "fail", payload: { error: "cancelled by user" }, token, serverURL, createdAt: new Date().toISOString() }, workspacesRoot);
19348
+ } else {
19349
+ updateEntry(timelineDir, task.id, (entry) => {
19350
+ entry.pid = null;
19351
+ entry.status = "killed";
19352
+ entry.errmsg = "killed by signal";
19353
+ });
19354
+ await reportToServer(() => client.failTask(token, task.id, "killed by signal"), { taskId: task.id, type: "fail", payload: { error: "killed by signal" }, token, serverURL, createdAt: new Date().toISOString() }, workspacesRoot);
19355
+ }
19356
+ process.exit(1);
19357
+ };
19358
+ process.on("SIGTERM", earlyOnKill);
19359
+ process.on("SIGINT", earlyOnKill);
19360
+ const attachmentIds = task.context?.attachment_ids ?? [];
19361
+ let attachments;
19362
+ if (attachmentIds.length > 0) {
19363
+ log5.info(`downloading ${attachmentIds.length} attachment(s)`);
19364
+ try {
19365
+ attachments = await downloadAttachments(client, token, task.workspaceId, task.id, attachmentIds);
19366
+ log5.info(`attachments ready (${attachments.length} file(s))`);
19367
+ } catch (e) {
19368
+ await cleanupAttachments(task.id);
19369
+ const errMsg = `failed to download attachments: ${e}`;
19370
+ log5.error(errMsg);
19371
+ updateEntry(timelineDir, task.id, (entry) => {
19372
+ entry.pid = null;
19373
+ entry.status = "failed";
19374
+ entry.errmsg = errMsg;
19375
+ });
19376
+ await reportToServer(() => client.failTask(token, task.id, errMsg), { taskId: task.id, type: "fail", payload: { error: errMsg }, token, serverURL, createdAt: new Date().toISOString() }, workspacesRoot);
19377
+ process.removeListener("SIGTERM", earlyOnKill);
19378
+ process.removeListener("SIGINT", earlyOnKill);
19379
+ return;
19380
+ }
19381
+ }
19382
+ const prompt = buildPrompt(task, attachments);
19383
+ const resumeSessionId = task.contextKey ? findResumableSessionByContextKey(timelineDir, task.contextKey, provider) ?? undefined : undefined;
19384
+ if (resumeSessionId) {
19385
+ log5.info(`resuming session ${resumeSessionId} (context_key: ${task.contextKey})`);
19386
+ }
19387
+ const session2 = backend.execute(prompt, {
19388
+ cwd: workDir,
19389
+ model: model || undefined,
19390
+ env,
19391
+ timeout: agentTimeout,
19392
+ resumeSessionId
19393
+ });
19394
+ const agentPid = session2.pid;
19395
+ const earlySessionId = await session2.sessionId;
19396
+ log5.info(`agent started (pid=${agentPid ?? "unknown"}, session=${earlySessionId})`);
19397
+ log5.info(JSON.stringify({ role: "user", type: "text", content: prompt }));
19398
+ updateEntry(timelineDir, task.id, (entry) => {
19399
+ entry.session_id = earlySessionId || null;
19400
+ });
19401
+ const pendingMessages = [];
19402
+ let seq = 0;
19403
+ let toolCount = 0;
19404
+ const BATCH_SIZE = Number(process.env.ALOOK_MESSAGE_BATCH_SIZE) || 20;
19405
+ const FLUSH_INTERVAL_MS = Number(process.env.ALOOK_MESSAGE_FLUSH_INTERVAL_MS) || 100;
19406
+ const flushMessages = async () => {
19407
+ if (pendingMessages.length === 0)
19408
+ return;
19409
+ const batch = pendingMessages.splice(0);
19410
+ try {
19411
+ await client.reportMessages(token, task.id, batch);
19412
+ } catch (e) {
19413
+ log5.debug("message report failed", e);
19414
+ }
19415
+ };
19416
+ const flushTimer = setInterval(flushMessages, FLUSH_INTERVAL_MS);
19417
+ process.removeListener("SIGTERM", earlyOnKill);
19418
+ process.removeListener("SIGINT", earlyOnKill);
19419
+ const onKill = async () => {
19420
+ if (killed)
19421
+ return;
19422
+ killed = true;
19423
+ log5.info(`killed by signal (messages=${seq}, tools=${toolCount})`);
19424
+ if (agentPid) {
19425
+ try {
19426
+ process.kill(agentPid, "SIGTERM");
19427
+ } catch {}
19428
+ }
19429
+ clearInterval(flushTimer);
19430
+ try {
19431
+ await flushMessages();
19432
+ } catch {}
19433
+ await cleanupAttachments(task.id);
19434
+ const intent = readKillIntent(agentBaseDir, task.id);
19435
+ clearKillIntent(agentBaseDir, task.id);
19436
+ if (intent?.reason === "superseded") {
19437
+ updateEntry(timelineDir, task.id, (entry) => {
19438
+ entry.pid = null;
19439
+ entry.status = "superseded";
19440
+ entry.successor_task_id = intent.successorTaskId ?? null;
19441
+ entry.supersede_reason = "superseded by newer task";
19442
+ });
19443
+ try {
19444
+ await client.supersedeTask(token, task.id);
19445
+ } catch {}
19446
+ } else if (intent?.reason === "cancelled") {
19447
+ updateEntry(timelineDir, task.id, (entry) => {
19448
+ entry.pid = null;
19449
+ entry.status = "cancelled";
19450
+ entry.errmsg = "cancelled by user";
19451
+ });
19452
+ await reportToServer(() => client.failTask(token, task.id, "cancelled by user"), { taskId: task.id, type: "fail", payload: { error: "cancelled by user" }, token, serverURL, createdAt: new Date().toISOString() }, workspacesRoot);
19453
+ } else {
19454
+ updateEntry(timelineDir, task.id, (entry) => {
19455
+ entry.pid = null;
19456
+ entry.status = "killed";
19457
+ entry.errmsg = "killed by signal";
19458
+ });
19459
+ await reportToServer(() => client.failTask(token, task.id, "killed by signal"), { taskId: task.id, type: "fail", payload: { error: "killed by signal" }, token, serverURL, createdAt: new Date().toISOString() }, workspacesRoot);
19460
+ }
19461
+ process.exit(1);
19462
+ };
19463
+ process.on("SIGTERM", onKill);
19464
+ process.on("SIGINT", onKill);
19465
+ const INACTIVITY_TIMEOUT_MS = messageInactivityTimeout ?? 5 * 60 * 1000;
19466
+ let inactivityTimedOut = false;
19467
+ try {
19468
+ const iter = session2.messages[Symbol.asyncIterator]();
19469
+ while (!killed) {
19470
+ const next = iter.next();
19471
+ const raceResult = await (INACTIVITY_TIMEOUT_MS > 0 ? Promise.race([
19472
+ next,
19473
+ new Promise((resolve) => {
19474
+ const timer = setTimeout(() => resolve("timeout"), INACTIVITY_TIMEOUT_MS);
19475
+ next.then(() => clearTimeout(timer), () => clearTimeout(timer));
19476
+ })
19477
+ ]) : next);
19478
+ if (raceResult === "timeout") {
19479
+ inactivityTimedOut = true;
19480
+ log5.warn(`message inactivity timeout (${INACTIVITY_TIMEOUT_MS / 1000}s) — killing agent`);
19481
+ if (session2.pid) {
19482
+ try {
19483
+ process.kill(session2.pid, "SIGTERM");
19484
+ } catch {}
19485
+ }
19486
+ iter.return?.(undefined);
19487
+ break;
19488
+ }
19489
+ const iterResult = raceResult;
19490
+ if (iterResult.done)
19491
+ break;
19492
+ const msg = iterResult.value;
19493
+ seq++;
19494
+ pendingMessages.push({
19495
+ seq,
19496
+ type: msg.type,
19497
+ tool: msg.tool,
19498
+ call_id: msg.callId,
19499
+ content: msg.content,
19500
+ input: msg.input,
19501
+ output: msg.output
19502
+ });
19503
+ if (msg.type === "tool-use")
19504
+ toolCount++;
19505
+ if (msg.type === "tool-result" && msg.output && msg.output.length > 500) {
19506
+ log5.info(JSON.stringify({ role: "assistant", ...msg, output: msg.output.slice(0, 500) + `... (${msg.output.length} chars)` }));
19507
+ } else {
19508
+ log5.info(JSON.stringify({ role: "assistant", ...msg }));
19509
+ }
19510
+ if (msg.type === "text" && msg.content) {
19511
+ updateEntry(timelineDir, task.id, (entry) => {
19512
+ entry.agent_responses.push(msg.content);
19513
+ });
19514
+ }
19515
+ if (pendingMessages.length >= BATCH_SIZE) {
19516
+ await flushMessages();
19517
+ }
19518
+ }
19519
+ if (!killed)
19520
+ await flushMessages();
19521
+ } finally {
19522
+ clearInterval(flushTimer);
19523
+ process.removeListener("SIGTERM", onKill);
19524
+ process.removeListener("SIGINT", onKill);
19525
+ }
19526
+ if (killed)
19527
+ return;
19528
+ process.on("SIGTERM", onKill);
19529
+ process.on("SIGINT", onKill);
19530
+ const result = await session2.result;
19531
+ process.removeListener("SIGTERM", onKill);
19532
+ process.removeListener("SIGINT", onKill);
19533
+ if (killed)
19534
+ return;
19535
+ if (inactivityTimedOut) {
19536
+ result.status = "failed";
19537
+ result.error = `message inactivity timeout (no messages for ${INACTIVITY_TIMEOUT_MS / 1000}s)`;
19538
+ }
19539
+ await cleanupAttachments(task.id);
19540
+ if (result.status === "completed") {
19541
+ updateEntry(timelineDir, task.id, (entry) => {
19542
+ entry.session_id = result.sessionId || null;
19543
+ entry.pid = null;
19544
+ entry.status = "completed";
19545
+ });
19546
+ } else {
19547
+ updateEntry(timelineDir, task.id, (entry) => {
19548
+ entry.pid = null;
19549
+ entry.status = "failed";
19550
+ entry.errmsg = result.error || "agent exited unexpectedly";
19551
+ });
19552
+ }
19553
+ if (result.status === "completed") {
19554
+ const body = {
19555
+ output: result.output || ""
19556
+ };
19557
+ if (result.sessionId)
19558
+ body.session_id = result.sessionId;
19559
+ await reportToServer(() => client.completeTask(token, task.id, body), { taskId: task.id, type: "complete", payload: body, token, serverURL, createdAt: new Date().toISOString() }, workspacesRoot);
19560
+ const dur = (result.durationMs / 1000).toFixed(1);
19561
+ log5.info(`completed (duration=${dur}s, messages=${seq}, tools=${toolCount})`);
19562
+ } else {
19563
+ const errorMsg = result.error || "agent exited unexpectedly";
19564
+ await reportToServer(() => client.failTask(token, task.id, errorMsg), { taskId: task.id, type: "fail", payload: { error: errorMsg }, token, serverURL, createdAt: new Date().toISOString() }, workspacesRoot);
19565
+ const dur = (result.durationMs / 1000).toFixed(1);
19566
+ log5.info(`failed (duration=${dur}s, messages=${seq}, tools=${toolCount}) — ${result.error}`);
19567
+ }
17435
19568
  }
17436
-
17437
- // daemon/agent/codex.ts
17438
- var RAW_DETECTION_METHODS = new Set([
17439
- "turn/started",
17440
- "turn/completed",
17441
- "thread/started",
17442
- "item/started",
17443
- "item/completed",
17444
- "item/agentMessage/delta"
17445
- ]);
17446
-
17447
- // daemon/agent/index.ts
17448
- import { execSync as execSync2 } from "child_process";
17449
- async function detectVersion2(cliPath) {
19569
+ async function main() {
19570
+ const encoded = process.argv[2];
19571
+ if (!encoded) {
19572
+ log5.error("session-runner: missing base64-encoded input argument");
19573
+ process.exit(1);
19574
+ }
19575
+ let input;
17450
19576
  try {
17451
- return execSync2(`${cliPath} --version`, { encoding: "utf-8" }).trim();
17452
- } catch {
17453
- return "unknown";
19577
+ const json2 = Buffer.from(encoded, "base64").toString("utf-8");
19578
+ input = JSON.parse(json2);
19579
+ } catch (e) {
19580
+ log5.error("session-runner: failed to parse input", e);
19581
+ process.exit(1);
19582
+ }
19583
+ const client = new DaemonClient(input.serverURL);
19584
+ try {
19585
+ await runSession(input);
19586
+ } catch (e) {
19587
+ log5.error(`session-runner: unhandled error for task ${input.task.id}`, e);
19588
+ await cleanupAttachments(input.task.id);
19589
+ const timelineDir = path.join(input.workspacesRoot, input.task.workspaceId, input.task.agentId, "workdir", ".context_timeline").replace(/\\/g, "/");
19590
+ updateEntry(timelineDir, input.task.id, (entry) => {
19591
+ entry.pid = null;
19592
+ entry.status = "failed";
19593
+ entry.errmsg = `session-runner crash: ${e}`;
19594
+ });
19595
+ const errorMsg = `session-runner crash: ${e}`;
19596
+ await reportToServer(() => client.failTask(input.token, input.task.id, errorMsg), { taskId: input.task.id, type: "fail", payload: { error: errorMsg }, token: input.token, serverURL: input.serverURL, createdAt: new Date().toISOString() }, input.workspacesRoot);
19597
+ process.exit(1);
17454
19598
  }
17455
19599
  }
17456
-
17457
- // daemon/types.ts
17458
- function fromApiTask(api2) {
17459
- return {
17460
- id: api2.id,
17461
- agentId: api2.agent_id,
17462
- runtimeId: api2.runtime_id,
17463
- conversationId: api2.conversation_id,
17464
- workspaceId: api2.workspace_id,
17465
- prompt: api2.prompt,
17466
- status: api2.status,
17467
- priority: api2.priority,
17468
- type: api2.type,
17469
- contextKey: api2.context_key ?? null,
17470
- context: api2.context ?? undefined,
17471
- agent: api2.agent ? {
17472
- name: api2.agent.name,
17473
- instructions: api2.agent.instructions,
17474
- emailHandle: api2.agent.email_handle ?? undefined,
17475
- emailAddresses: api2.agent.email_addresses ?? [],
17476
- userEmail: api2.agent.user_email ?? undefined,
17477
- userName: api2.agent.user_name ?? undefined,
17478
- runtimeConfig: api2.agent.runtime_config ?? undefined,
17479
- colleagues: api2.agent.colleagues?.map((c) => ({
17480
- name: c.name,
17481
- email: c.email,
17482
- description: c.description,
17483
- instruction: c.instruction
17484
- })) ?? []
17485
- } : undefined,
17486
- sender: api2.sender ? { name: api2.sender.name, email: api2.sender.email, isOwner: api2.sender.is_owner } : undefined,
17487
- repos: undefined,
17488
- createdAt: api2.created_at,
17489
- traceId: api2.trace_id ?? null,
17490
- parentTaskId: api2.parent_task_id ?? null,
17491
- channel: api2.channel ?? null
17492
- };
19600
+ var isDirectExecution = typeof Bun !== "undefined" ? Bun.main === import.meta.path : process.argv[1]?.endsWith("session-runner.ts") || process.argv[1]?.endsWith("session-runner.js");
19601
+ if (isDirectExecution) {
19602
+ main();
17493
19603
  }
17494
19604
 
17495
19605
  // daemon/update-handler.ts
17496
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, unlinkSync as unlinkSync2 } from "fs";
19606
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync6, unlinkSync as unlinkSync4 } from "fs";
17497
19607
 
17498
19608
  // lib/update.ts
17499
- import { spawn } from "child_process";
19609
+ import { spawn as spawn4 } from "child_process";
17500
19610
  function fetchLatestVersion() {
17501
19611
  return fetch("https://registry.npmjs.org/@alook/cli/latest").then((res) => {
17502
19612
  if (!res.ok)
@@ -17507,7 +19617,7 @@ function fetchLatestVersion() {
17507
19617
  function runNpmUpdate(targetVersion) {
17508
19618
  return new Promise((resolve) => {
17509
19619
  const chunks = [];
17510
- const child = spawn("npm", ["install", "-g", `@alook/cli@${targetVersion}`], {
19620
+ const child = spawn4("npm", ["install", "-g", `@alook/cli@${targetVersion}`], {
17511
19621
  stdio: ["ignore", "pipe", "pipe"]
17512
19622
  });
17513
19623
  child.stdout?.on("data", (d) => chunks.push(d));
@@ -17523,7 +19633,7 @@ function runNpmUpdate(targetVersion) {
17523
19633
  }
17524
19634
 
17525
19635
  // daemon/update-handler.ts
17526
- var log3 = createLogger2({ module: "updater" });
19636
+ var log6 = createLogger2({ module: "updater" });
17527
19637
  var updating = false;
17528
19638
  var retryCount = 0;
17529
19639
  var MAX_RETRIES = 3;
@@ -17532,19 +19642,19 @@ function isUpdating() {
17532
19642
  }
17533
19643
  function readUpdateMarker(profile) {
17534
19644
  try {
17535
- return readFileSync4(lastUpdateMarkerPath(profile), "utf-8").trim() || null;
19645
+ return readFileSync7(lastUpdateMarkerPath(profile), "utf-8").trim() || null;
17536
19646
  } catch {
17537
19647
  return null;
17538
19648
  }
17539
19649
  }
17540
19650
  function writeUpdateMarker(version3, profile) {
17541
19651
  try {
17542
- writeFileSync3(lastUpdateMarkerPath(profile), version3, { mode: 384 });
19652
+ writeFileSync6(lastUpdateMarkerPath(profile), version3, { mode: 384 });
17543
19653
  } catch {}
17544
19654
  }
17545
19655
  function clearUpdateMarker(profile) {
17546
19656
  try {
17547
- unlinkSync2(lastUpdateMarkerPath(profile));
19657
+ unlinkSync4(lastUpdateMarkerPath(profile));
17548
19658
  } catch {}
17549
19659
  }
17550
19660
  async function handleCliUpdate(version3, onSuccess, profile) {
@@ -17553,197 +19663,37 @@ async function handleCliUpdate(version3, onSuccess, profile) {
17553
19663
  if (retryCount >= MAX_RETRIES)
17554
19664
  return;
17555
19665
  if (process.env.ALOOK_CMD_PREFIX) {
17556
- log3.info(`Skipping auto-update in app mode — user should run: npx @alook/app@latest update`);
19666
+ log6.info(`Skipping auto-update in app mode — user should run: npx @alook/app@latest update`);
17557
19667
  return;
17558
19668
  }
17559
19669
  const marker = readUpdateMarker(profile);
17560
19670
  if (marker === version3) {
17561
- log3.info(`Skipping update to v${version3} — already attempted (marker exists)`);
19671
+ log6.info(`Skipping update to v${version3} — already attempted (marker exists)`);
17562
19672
  return;
17563
19673
  }
17564
19674
  updating = true;
17565
19675
  try {
17566
- log3.info(`Updating CLI to v${version3}...`);
19676
+ log6.info(`Updating CLI to v${version3}...`);
17567
19677
  const result = await runNpmUpdate(version3);
17568
19678
  if (result.success) {
17569
19679
  writeUpdateMarker(version3, profile);
17570
- log3.info(`CLI updated to v${version3} — restarting`);
19680
+ log6.info(`CLI updated to v${version3} — restarting`);
17571
19681
  onSuccess();
17572
19682
  } else {
17573
19683
  retryCount++;
17574
- log3.error(`CLI update failed (attempt ${retryCount}/${MAX_RETRIES}): ${result.output}`);
19684
+ log6.error(`CLI update failed (attempt ${retryCount}/${MAX_RETRIES}): ${result.output}`);
17575
19685
  }
17576
19686
  } catch (e) {
17577
19687
  retryCount++;
17578
- log3.error(`CLI update error (attempt ${retryCount}/${MAX_RETRIES})`, e);
19688
+ log6.error(`CLI update error (attempt ${retryCount}/${MAX_RETRIES})`, e);
17579
19689
  } finally {
17580
19690
  updating = false;
17581
19691
  }
17582
19692
  }
17583
19693
 
17584
- // daemon/execenv/timeline.ts
17585
- import { appendFileSync, readFileSync as readFileSync5, writeFileSync as writeFileSync4, renameSync } from "fs";
17586
- import { join as join4 } from "path";
17587
-
17588
- // daemon/execenv/filelock.ts
17589
- import { mkdirSync as mkdirSync3, rmdirSync, statSync } from "fs";
17590
- var DEFAULT_STALE_MS = 3600000;
17591
- function acquireLock(lockPath, staleMs = DEFAULT_STALE_MS) {
17592
- try {
17593
- mkdirSync3(lockPath);
17594
- return true;
17595
- } catch {
17596
- try {
17597
- const stat = statSync(lockPath);
17598
- if (Date.now() - stat.mtimeMs > staleMs) {
17599
- rmdirSync(lockPath);
17600
- try {
17601
- mkdirSync3(lockPath);
17602
- return true;
17603
- } catch {
17604
- return false;
17605
- }
17606
- }
17607
- } catch {
17608
- try {
17609
- mkdirSync3(lockPath);
17610
- return true;
17611
- } catch {
17612
- return false;
17613
- }
17614
- }
17615
- return false;
17616
- }
17617
- }
17618
- function releaseLock(lockPath) {
17619
- try {
17620
- rmdirSync(lockPath);
17621
- } catch {}
17622
- }
17623
-
17624
- // daemon/execenv/timeline.ts
17625
- var log4 = createLogger2({ module: "timeline" });
17626
- function readJsonl(filePath) {
17627
- let content;
17628
- try {
17629
- content = readFileSync5(filePath, "utf-8");
17630
- } catch {
17631
- return [];
17632
- }
17633
- const entries = [];
17634
- for (const line of content.trimEnd().split(`
17635
- `)) {
17636
- if (!line)
17637
- continue;
17638
- try {
17639
- entries.push(JSON.parse(line));
17640
- } catch {}
17641
- }
17642
- return entries;
17643
- }
17644
- function filenameForDate(date5) {
17645
- const y = date5.getFullYear();
17646
- const m = String(date5.getMonth() + 1).padStart(2, "0");
17647
- const d = String(date5.getDate()).padStart(2, "0");
17648
- return `${y}-${m}-${d}.jsonl`;
17649
- }
17650
- function recentFilenames(maxDays) {
17651
- const filenames = [];
17652
- const now = new Date;
17653
- for (let i = 0;i < maxDays; i++) {
17654
- const d = new Date(now);
17655
- d.setDate(d.getDate() - i);
17656
- filenames.push(filenameForDate(d));
17657
- }
17658
- return filenames;
17659
- }
17660
- var RESUME_MAX_AGE_MS = 72 * 60 * 60 * 1000;
17661
- function findRunningPidByTaskId(timelineDir, taskId) {
17662
- for (const filename of recentFilenames(7)) {
17663
- const entries = readJsonl(join4(timelineDir, filename));
17664
- for (const entry of entries) {
17665
- if (entry.task_id === taskId && entry.status === "running" && entry.pid != null) {
17666
- return entry.pid;
17667
- }
17668
- }
17669
- }
17670
- return null;
17671
- }
17672
- function findRunningEntryByContextKey(timelineDir, contextKey, provider) {
17673
- for (const filename of recentFilenames(7)) {
17674
- const dayEntries = readJsonl(join4(timelineDir, filename));
17675
- for (let i = dayEntries.length - 1;i >= 0; i--) {
17676
- const entry = dayEntries[i];
17677
- if (entry.status === "running" && entry.context_key === contextKey && entry.provider === provider) {
17678
- return entry;
17679
- }
17680
- }
17681
- }
17682
- return null;
17683
- }
17684
-
17685
- // daemon/execenv/steering.ts
17686
- import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5, readFileSync as readFileSync6, unlinkSync as unlinkSync3, readdirSync, statSync as statSync2 } from "fs";
17687
- import { join as join5 } from "path";
17688
- var log5 = createLogger2({ module: "steering" });
17689
- var INTENT_DIR_NAME = ".kill_intents";
17690
- var STEERING_LOCK_DIR = ".steering_locks";
17691
- var INTENT_STALE_MS = 10 * 60 * 1000;
17692
- function intentFilePath(baseDir, taskId) {
17693
- return join5(baseDir, INTENT_DIR_NAME, `${taskId}.json`);
17694
- }
17695
- function intentDirPath(baseDir) {
17696
- return join5(baseDir, INTENT_DIR_NAME);
17697
- }
17698
- function steeringLockPath(baseDir, contextKey) {
17699
- const safeKey = contextKey.replace(/[^a-zA-Z0-9_:-]/g, "_");
17700
- return join5(baseDir, STEERING_LOCK_DIR, safeKey);
17701
- }
17702
- function writeKillIntent(baseDir, intent) {
17703
- const dir = intentDirPath(baseDir);
17704
- try {
17705
- mkdirSync4(dir, { recursive: true });
17706
- } catch {}
17707
- const filePath = intentFilePath(baseDir, intent.targetTaskId);
17708
- writeFileSync5(filePath, JSON.stringify(intent));
17709
- }
17710
- function cleanupStaleIntents(baseDir) {
17711
- const dir = intentDirPath(baseDir);
17712
- let files;
17713
- try {
17714
- files = readdirSync(dir).filter((f) => f.endsWith(".json"));
17715
- } catch {
17716
- return;
17717
- }
17718
- const now = Date.now();
17719
- for (const file2 of files) {
17720
- const filePath = join5(dir, file2);
17721
- try {
17722
- const content = readFileSync6(filePath, "utf-8");
17723
- const intent = JSON.parse(content);
17724
- const stat = statSync2(filePath);
17725
- if (now - stat.mtimeMs > INTENT_STALE_MS) {
17726
- unlinkSync3(filePath);
17727
- log5.debug(`Cleaned up stale kill intent for task ${intent.targetTaskId}`);
17728
- }
17729
- } catch {}
17730
- }
17731
- }
17732
- function acquireSteeringLock(baseDir, contextKey) {
17733
- const lockPath = steeringLockPath(baseDir, contextKey);
17734
- try {
17735
- mkdirSync4(join5(baseDir, STEERING_LOCK_DIR), { recursive: true });
17736
- } catch {}
17737
- return acquireLock(lockPath, 60000);
17738
- }
17739
- function releaseSteeringLock(baseDir, contextKey) {
17740
- const lockPath = steeringLockPath(baseDir, contextKey);
17741
- releaseLock(lockPath);
17742
- }
17743
-
17744
19694
  // daemon/workspace-files.ts
17745
19695
  import { readdir, stat, readFile } from "fs/promises";
17746
- import { join as join6, resolve, extname, relative, sep } from "path";
19696
+ import { join as join9, resolve, extname, relative, sep as sep2 } from "path";
17747
19697
  var SKIP_DIRS = new Set([".git", "node_modules", ".next", ".wrangler", "__pycache__", ".venv"]);
17748
19698
  var TEXT_EXTENSIONS = new Set([
17749
19699
  ".md",
@@ -17802,7 +19752,7 @@ async function readDirectoryTree(dirPath, basePath) {
17802
19752
  if (ext !== "" && !TEXT_EXTENSIONS.has(ext))
17803
19753
  continue;
17804
19754
  }
17805
- const fullPath = join6(dirPath, entry.name);
19755
+ const fullPath = join9(dirPath, entry.name);
17806
19756
  let info;
17807
19757
  try {
17808
19758
  info = await stat(fullPath);
@@ -17834,23 +19784,13 @@ async function readFileContent(filePath) {
17834
19784
  }
17835
19785
  function validatePath(agentWorkdir, requestedPath) {
17836
19786
  const resolved = resolve(agentWorkdir, requestedPath);
17837
- if (resolved !== agentWorkdir && !resolved.startsWith(agentWorkdir + sep))
19787
+ if (resolved !== agentWorkdir && !resolved.startsWith(agentWorkdir + sep2))
17838
19788
  return null;
17839
19789
  return resolved;
17840
19790
  }
17841
19791
 
17842
19792
  // lib/shell-env.ts
17843
19793
  import { execSync as execSync3 } from "child_process";
17844
-
17845
- // lib/platform.ts
17846
- import { tmpdir } from "os";
17847
- import { join as join7, sep as sep2 } from "path";
17848
- var isWindows = process.platform === "win32";
17849
- function tempDir(subdir) {
17850
- return join7(tmpdir(), subdir);
17851
- }
17852
-
17853
- // lib/shell-env.ts
17854
19794
  var PASSTHROUGH_VARS = ["ALOOK_PROJECT_ROOT", "ALOOK_SERVER_URL", "ALOOK_CMD_PREFIX", "ALOOK_HEALTH_PORT"];
17855
19795
  function resolveLoginShellEnv() {
17856
19796
  if (isWindows) {
@@ -17883,15 +19823,15 @@ function resolveLoginShellEnv() {
17883
19823
  }
17884
19824
 
17885
19825
  // daemon/daemon.ts
17886
- import { existsSync, mkdirSync as mkdirSync5, openSync, closeSync, readdirSync as readdirSync2, statSync as statSync3, unlinkSync as unlinkSync4 } from "fs";
19826
+ import { existsSync as existsSync2, mkdirSync as mkdirSync7, openSync, closeSync, readdirSync as readdirSync2, statSync as statSync3, unlinkSync as unlinkSync5 } from "fs";
17887
19827
  import { readdir as readdir2, readFile as readFile2, unlink, stat as fsStat } from "fs/promises";
17888
- import { execSync as execSync4, spawn as spawn2 } from "child_process";
19828
+ import { execSync as execSync4, spawn as spawn5 } from "child_process";
17889
19829
  import { fileURLToPath as fileURLToPath2 } from "url";
17890
- import { dirname as dirname3, join as join8 } from "path";
17891
- var log6 = createLogger2({ module: "daemon" });
19830
+ import { dirname as dirname3, join as join10 } from "path";
19831
+ var log7 = createLogger2({ module: "daemon" });
17892
19832
  var _dir = dirname3(fileURLToPath2(import.meta.url));
17893
- var sessionRunnerPath = existsSync(join8(_dir, "session-runner.js")) ? join8(_dir, "session-runner.js") : join8(_dir, "session-runner.ts");
17894
- var meetingRunnerPath = existsSync(join8(_dir, "meeting-runner.js")) ? join8(_dir, "meeting-runner.js") : join8(_dir, "meeting-runner.ts");
19833
+ var sessionRunnerPath = existsSync2(join10(_dir, "session-runner.js")) ? join10(_dir, "session-runner.js") : join10(_dir, "session-runner.ts");
19834
+ var meetingRunnerPath = existsSync2(join10(_dir, "meeting-runner.js")) ? join10(_dir, "meeting-runner.js") : join10(_dir, "meeting-runner.ts");
17895
19835
  function isCommandAvailable2(cmd) {
17896
19836
  try {
17897
19837
  const check2 = process.platform === "win32" ? `where ${cmd}` : `which ${cmd}`;
@@ -17913,7 +19853,7 @@ function pruneSessionRunnerLogs() {
17913
19853
  if (entries.length <= MAX_SESSION_RUNNER_LOGS)
17914
19854
  return;
17915
19855
  const withMtime = entries.map((name) => {
17916
- const full = join8(logDir, name);
19856
+ const full = join10(logDir, name);
17917
19857
  try {
17918
19858
  return { name, mtime: statSync3(full).mtimeMs };
17919
19859
  } catch {
@@ -17923,11 +19863,11 @@ function pruneSessionRunnerLogs() {
17923
19863
  withMtime.sort((a, b) => b.mtime - a.mtime);
17924
19864
  for (const entry of withMtime.slice(MAX_SESSION_RUNNER_LOGS)) {
17925
19865
  try {
17926
- unlinkSync4(join8(logDir, entry.name));
19866
+ unlinkSync5(join10(logDir, entry.name));
17927
19867
  } catch {}
17928
19868
  }
17929
19869
  }
17930
- function isClientError(error51) {
19870
+ function isClientError2(error51) {
17931
19871
  if (!(error51 instanceof Error))
17932
19872
  return false;
17933
19873
  const match = error51.message.match(/^HTTP (\d+):/);
@@ -17964,7 +19904,7 @@ function isValidMarker(data) {
17964
19904
  var MARKER_STALE_MS = 24 * 60 * 60 * 1000;
17965
19905
  var TMP_STALE_MS = 60 * 60 * 1000;
17966
19906
  async function reconcilePendingCompletions(workspacesRoot) {
17967
- const dir = join8(workspacesRoot, ".pending_completions");
19907
+ const dir = join10(workspacesRoot, ".pending_completions");
17968
19908
  let entries;
17969
19909
  try {
17970
19910
  entries = await readdir2(dir);
@@ -17975,15 +19915,15 @@ async function reconcilePendingCompletions(workspacesRoot) {
17975
19915
  if (!name.endsWith(".tmp"))
17976
19916
  continue;
17977
19917
  try {
17978
- const s = await fsStat(join8(dir, name));
19918
+ const s = await fsStat(join10(dir, name));
17979
19919
  if (Date.now() - s.mtimeMs > TMP_STALE_MS) {
17980
- await unlink(join8(dir, name));
19920
+ await unlink(join10(dir, name));
17981
19921
  }
17982
19922
  } catch {}
17983
19923
  }
17984
19924
  const jsonFiles = entries.filter((f) => f.endsWith(".json"));
17985
19925
  for (const name of jsonFiles) {
17986
- const filePath = join8(dir, name);
19926
+ const filePath = join10(dir, name);
17987
19927
  try {
17988
19928
  let raw;
17989
19929
  try {
@@ -17995,14 +19935,14 @@ async function reconcilePendingCompletions(workspacesRoot) {
17995
19935
  try {
17996
19936
  parsed = JSON.parse(raw);
17997
19937
  } catch {
17998
- log6.warn(`reconcile: malformed marker ${name}, deleting`);
19938
+ log7.warn(`reconcile: malformed marker ${name}, deleting`);
17999
19939
  try {
18000
19940
  await unlink(filePath);
18001
19941
  } catch {}
18002
19942
  continue;
18003
19943
  }
18004
19944
  if (!isValidMarker(parsed)) {
18005
- log6.warn(`reconcile: invalid marker structure ${name}, deleting`);
19945
+ log7.warn(`reconcile: invalid marker structure ${name}, deleting`);
18006
19946
  try {
18007
19947
  await unlink(filePath);
18008
19948
  } catch {}
@@ -18011,7 +19951,7 @@ async function reconcilePendingCompletions(workspacesRoot) {
18011
19951
  const marker = parsed;
18012
19952
  const age = Date.now() - new Date(marker.createdAt).getTime();
18013
19953
  if (age > MARKER_STALE_MS) {
18014
- log6.warn(`reconcile: stale marker ${name} (${Math.round(age / 3600000)}h old), deleting`);
19954
+ log7.warn(`reconcile: stale marker ${name} (${Math.round(age / 3600000)}h old), deleting`);
18015
19955
  try {
18016
19956
  await unlink(filePath);
18017
19957
  } catch {}
@@ -18027,19 +19967,19 @@ async function reconcilePendingCompletions(workspacesRoot) {
18027
19967
  try {
18028
19968
  await unlink(filePath);
18029
19969
  } catch (delErr) {
18030
- log6.warn(`reconcile: delivered marker ${name} but failed to delete: ${delErr}`);
19970
+ log7.warn(`reconcile: delivered marker ${name} but failed to delete: ${delErr}`);
18031
19971
  }
18032
19972
  } catch (deliverErr) {
18033
- if (isClientError(deliverErr)) {
19973
+ if (isClientError2(deliverErr)) {
18034
19974
  try {
18035
19975
  await unlink(filePath);
18036
19976
  } catch {}
18037
19977
  } else {
18038
- log6.debug(`reconcile: delivery failed for ${name}, will retry next cycle`);
19978
+ log7.debug(`reconcile: delivery failed for ${name}, will retry next cycle`);
18039
19979
  }
18040
19980
  }
18041
19981
  } catch (e) {
18042
- log6.debug(`reconcile: error processing ${name}`, e);
19982
+ log7.debug(`reconcile: error processing ${name}`, e);
18043
19983
  }
18044
19984
  }
18045
19985
  }
@@ -18050,7 +19990,7 @@ async function startDaemon(profile, serverUrl) {
18050
19990
  }
18051
19991
  process.once("exit", () => releaseDaemonPid(profile));
18052
19992
  const bailOnUnexpected = (label, err) => {
18053
- log6.error(`${label} — shutting down`, err);
19993
+ log7.error(`${label} — shutting down`, err);
18054
19994
  releaseDaemonPid(profile);
18055
19995
  process.exit(1);
18056
19996
  };
@@ -18063,21 +20003,21 @@ async function startDaemon(profile, serverUrl) {
18063
20003
  if (marker) {
18064
20004
  clearUpdateMarker(profile);
18065
20005
  if (marker === config2.cliVersion) {
18066
- log6.info(`Cleared update marker — now running v${config2.cliVersion}`);
20006
+ log7.info(`Cleared update marker — now running v${config2.cliVersion}`);
18067
20007
  } else {
18068
- log6.info(`Cleared stale update marker (was v${marker}, running v${config2.cliVersion}) — update will be retried`);
20008
+ log7.info(`Cleared stale update marker (was v${marker}, running v${config2.cliVersion}) — update will be retried`);
18069
20009
  }
18070
20010
  }
18071
20011
  const cliConfig = loadCLIConfigForProfile(profile);
18072
20012
  const workspaces = cliConfig.watched_workspaces || [];
18073
20013
  if (workspaces.length === 0) {
18074
- log6.error("No watched workspaces configured.");
20014
+ log7.error("No watched workspaces configured.");
18075
20015
  process.exit(1);
18076
20016
  return;
18077
20017
  }
18078
20018
  const hasPerWorkspaceTokens = workspaces.every((ws) => !!ws.token);
18079
20019
  if (!hasPerWorkspaceTokens) {
18080
- log6.error(`Config uses old format. Run '${cmdPrefix()} register --token <token>' for each workspace to upgrade.`);
20020
+ log7.error(`Config uses old format. Run '${cmdPrefix()} register --token <token>' for each workspace to upgrade.`);
18081
20021
  process.exit(1);
18082
20022
  return;
18083
20023
  }
@@ -18086,22 +20026,22 @@ async function startDaemon(profile, serverUrl) {
18086
20026
  const client = new DaemonClient(config2.serverURL);
18087
20027
  const health = createHealthServer();
18088
20028
  const providers = [];
18089
- for (const [type, path] of [
20029
+ for (const [type, path2] of [
18090
20030
  ["claude", config2.claudePath],
18091
20031
  ["codex", config2.codexPath],
18092
20032
  ["opencode", config2.opencodePath]
18093
20033
  ]) {
18094
- if (isCommandAvailable2(path)) {
18095
- const version3 = await detectVersion2(path);
18096
- providers.push({ type, path, version: version3 });
20034
+ if (isCommandAvailable2(path2)) {
20035
+ const version3 = await detectVersion2(path2);
20036
+ providers.push({ type, path: path2, version: version3 });
18097
20037
  }
18098
20038
  }
18099
20039
  if (providers.length === 0) {
18100
- log6.error("No agent CLI tools found on PATH.");
20040
+ log7.error("No agent CLI tools found on PATH.");
18101
20041
  process.exit(1);
18102
20042
  return;
18103
20043
  }
18104
- log6.info(`Detected providers: ${providers.map((p) => `${p.type}@${p.version}`).join(", ")}`);
20044
+ log7.info(`Detected providers: ${providers.map((p) => `${p.type}@${p.version}`).join(", ")}`);
18105
20045
  const workspaceStates = [];
18106
20046
  const runtimeIndex = new Map;
18107
20047
  for (const ws of workspaces) {
@@ -18109,7 +20049,7 @@ async function startDaemon(profile, serverUrl) {
18109
20049
  type: p.type,
18110
20050
  version: p.version
18111
20051
  }));
18112
- log6.info(`Registering workspace ${ws.id} (${ws.name ?? "unnamed"}) with ${runtimes.length} runtime(s)...`);
20052
+ log7.info(`Registering workspace ${ws.id} (${ws.name ?? "unnamed"}) with ${runtimes.length} runtime(s)...`);
18113
20053
  let resp;
18114
20054
  try {
18115
20055
  resp = await client.register(ws.token, {
@@ -18122,13 +20062,13 @@ async function startDaemon(profile, serverUrl) {
18122
20062
  });
18123
20063
  } catch (e) {
18124
20064
  if (e instanceof Error && e.message.startsWith("HTTP 401")) {
18125
- log6.warn(`Workspace ${ws.id} token invalid — skipping (run '${cmdPrefix()} register --token <token>' to fix)`);
20065
+ log7.warn(`Workspace ${ws.id} token invalid — skipping (run '${cmdPrefix()} register --token <token>' to fix)`);
18126
20066
  } else {
18127
- log6.error(`Failed to register workspace ${ws.id}, skipping`, e);
20067
+ log7.error(`Failed to register workspace ${ws.id}, skipping`, e);
18128
20068
  }
18129
20069
  continue;
18130
20070
  }
18131
- log6.info(`Workspace ${ws.id} registered — ${resp.runtimes.length} runtime(s)`);
20071
+ log7.info(`Workspace ${ws.id} registered — ${resp.runtimes.length} runtime(s)`);
18132
20072
  const runtimeIds = resp.runtimes.map((r) => r.id);
18133
20073
  workspaceStates.push({ workspaceId: ws.id, token: ws.token, runtimeIds });
18134
20074
  for (let i = 0;i < runtimeIds.length; i++) {
@@ -18140,13 +20080,13 @@ async function startDaemon(profile, serverUrl) {
18140
20080
  }
18141
20081
  }
18142
20082
  if (workspaceStates.length === 0) {
18143
- log6.error("No workspaces registered successfully.");
20083
+ log7.error("No workspaces registered successfully.");
18144
20084
  process.exit(1);
18145
20085
  return;
18146
20086
  }
18147
20087
  const allRuntimeIds = workspaceStates.flatMap((ws) => ws.runtimeIds);
18148
20088
  health.setRuntimeCount(allRuntimeIds.length);
18149
- log6.info(`Daemon started — ${allRuntimeIds.length} runtime(s) across ${workspaceStates.length} workspace(s)`);
20089
+ log7.info(`Daemon started — ${allRuntimeIds.length} runtime(s) across ${workspaceStates.length} workspace(s)`);
18150
20090
  const activeTasks = new Set;
18151
20091
  const knownAgentIds = new Set(workspaces.flatMap((ws) => ws.agent_ids ?? []));
18152
20092
  function syncAgentId(agentId, workspaceId) {
@@ -18181,7 +20121,7 @@ async function startDaemon(profile, serverUrl) {
18181
20121
  cfg.watched_workspaces = (cfg.watched_workspaces || []).filter((w) => w.id !== workspaceId);
18182
20122
  saveCLIConfigForProfile(profile, cfg);
18183
20123
  } catch {}
18184
- log6.info(`Workspace ${workspaceId} deleted server-side — removed from config`);
20124
+ log7.info(`Workspace ${workspaceId} deleted server-side — removed from config`);
18185
20125
  }
18186
20126
  const pollCycle = async () => {
18187
20127
  let remaining = config2.maxConcurrentTasks - activeTasks.size;
@@ -18207,7 +20147,7 @@ async function startDaemon(profile, serverUrl) {
18207
20147
  handleCliUpdate(pending_update.version, () => requestRestart(), profile);
18208
20148
  }
18209
20149
  if (pending_rescan) {
18210
- log6.info("Rescan requested — restarting daemon to re-detect runtimes");
20150
+ log7.info("Rescan requested — restarting daemon to re-detect runtimes");
18211
20151
  for (const id of evictedIds) {
18212
20152
  evictWorkspace(id);
18213
20153
  }
@@ -18220,19 +20160,19 @@ async function startDaemon(profile, serverUrl) {
18220
20160
  activeTasks.add(task.id);
18221
20161
  remaining--;
18222
20162
  handleTask(client, config2, runtimeIndex, task, ws.token, activeTasks).catch((e) => {
18223
- log6.error("Task error", e);
20163
+ log7.error("Task error", e);
18224
20164
  activeTasks.delete(task.id);
18225
20165
  });
18226
20166
  }
18227
20167
  if (file_requests) {
18228
20168
  for (const req of file_requests) {
18229
- handleFileRequest(client, config2, ws.workspaceId, req, ws.token).catch((e) => log6.debug("File request error", e));
20169
+ handleFileRequest(client, config2, ws.workspaceId, req, ws.token).catch((e) => log7.debug("File request error", e));
18230
20170
  }
18231
20171
  }
18232
20172
  if (meetings) {
18233
20173
  for (const m of meetings) {
18234
- const agentBaseDir = join8(config2.workspacesRoot, m.workspace_id, m.agent_id, "workdir");
18235
- const timelineDir = join8(agentBaseDir, ".context_timeline");
20174
+ const agentBaseDir = join10(config2.workspacesRoot, m.workspace_id, m.agent_id, "workdir");
20175
+ const timelineDir = join10(agentBaseDir, ".context_timeline");
18236
20176
  spawnMeetingRunner({
18237
20177
  meetingId: m.id,
18238
20178
  meetingUrl: m.meeting_url,
@@ -18249,9 +20189,9 @@ async function startDaemon(profile, serverUrl) {
18249
20189
  }
18250
20190
  } catch (e) {
18251
20191
  if (e instanceof Error && e.message.startsWith("HTTP 401")) {
18252
- log6.warn(`Workspace ${ws.workspaceId} poll returned 401 — will retry next cycle`);
20192
+ log7.warn(`Workspace ${ws.workspaceId} poll returned 401 — will retry next cycle`);
18253
20193
  } else {
18254
- log6.debug("Poll error", e);
20194
+ log7.debug("Poll error", e);
18255
20195
  }
18256
20196
  }
18257
20197
  }
@@ -18261,10 +20201,10 @@ async function startDaemon(profile, serverUrl) {
18261
20201
  try {
18262
20202
  await reconcilePendingCompletions(config2.workspacesRoot);
18263
20203
  } catch (e) {
18264
- log6.debug("reconciliation error", e);
20204
+ log7.debug("reconciliation error", e);
18265
20205
  }
18266
20206
  if (workspaceStates.length === 0) {
18267
- log6.info("All workspaces evicted — shutting down");
20207
+ log7.info("All workspaces evicted — shutting down");
18268
20208
  shutdown();
18269
20209
  }
18270
20210
  };
@@ -18279,7 +20219,7 @@ async function startDaemon(profile, serverUrl) {
18279
20219
  if (shuttingDown)
18280
20220
  return;
18281
20221
  shuttingDown = true;
18282
- log6.info(restartRequested ? "Restarting..." : "Shutting down...");
20222
+ log7.info(restartRequested ? "Restarting..." : "Shutting down...");
18283
20223
  clearInterval(pollTimer);
18284
20224
  const shutdownMs = restartRequested ? 30000 : Number(process.env.ALOOK_SHUTDOWN_TIMEOUT_MS) || 5000;
18285
20225
  const timeout = setTimeout(() => process.exit(1), shutdownMs);
@@ -18300,12 +20240,12 @@ async function startDaemon(profile, serverUrl) {
18300
20240
  const logPath = daemonLogFilePath();
18301
20241
  let logFd;
18302
20242
  try {
18303
- mkdirSync5(dirname3(logPath), { recursive: true, mode: 448 });
20243
+ mkdirSync7(dirname3(logPath), { recursive: true, mode: 448 });
18304
20244
  logFd = openSync(logPath, "a", 384);
18305
20245
  } catch (e) {
18306
- log6.error(`Failed to open daemon log file ${logPath}`, e);
20246
+ log7.error(`Failed to open daemon log file ${logPath}`, e);
18307
20247
  }
18308
- const child = spawn2(process.execPath, args, {
20248
+ const child = spawn5(process.execPath, args, {
18309
20249
  detached: true,
18310
20250
  stdio: logFd != null ? ["ignore", logFd, logFd] : ["ignore", "ignore", "ignore"],
18311
20251
  env: resolveLoginShellEnv()
@@ -18313,7 +20253,7 @@ async function startDaemon(profile, serverUrl) {
18313
20253
  child.unref();
18314
20254
  if (logFd != null)
18315
20255
  closeSync(logFd);
18316
- log6.info(`Spawned new daemon (pid=${child.pid}), logs: ${logPath}`);
20256
+ log7.info(`Spawned new daemon (pid=${child.pid}), logs: ${logPath}`);
18317
20257
  }
18318
20258
  clearTimeout(timeout);
18319
20259
  process.exit(0);
@@ -18324,7 +20264,7 @@ async function startDaemon(profile, serverUrl) {
18324
20264
  process.on("SIGHUP", async () => {
18325
20265
  if (shuttingDown)
18326
20266
  return;
18327
- log6.info("SIGHUP received — reloading config...");
20267
+ log7.info("SIGHUP received — reloading config...");
18328
20268
  try {
18329
20269
  const freshConfig = loadCLIConfigForProfile(profile);
18330
20270
  const freshWorkspaces = freshConfig.watched_workspaces || [];
@@ -18332,7 +20272,7 @@ async function startDaemon(profile, serverUrl) {
18332
20272
  const newWorkspaces = freshWorkspaces.filter((ws) => ws.token && !existingIds.has(ws.id));
18333
20273
  for (const ws of newWorkspaces) {
18334
20274
  const runtimes = providers.map((p) => ({ type: p.type, version: p.version }));
18335
- log6.info(`Registering new workspace ${ws.id} (${ws.name ?? "unnamed"})...`);
20275
+ log7.info(`Registering new workspace ${ws.id} (${ws.name ?? "unnamed"})...`);
18336
20276
  try {
18337
20277
  const resp = await client.register(ws.token, {
18338
20278
  workspace_id: ws.id,
@@ -18351,36 +20291,36 @@ async function startDaemon(profile, serverUrl) {
18351
20291
  provider: providers[i].type
18352
20292
  });
18353
20293
  }
18354
- log6.info(`Workspace ${ws.id} added — ${runtimeIds.length} runtime(s)`);
20294
+ log7.info(`Workspace ${ws.id} added — ${runtimeIds.length} runtime(s)`);
18355
20295
  } catch (e) {
18356
- log6.error(`Failed to register new workspace ${ws.id}`, e);
20296
+ log7.error(`Failed to register new workspace ${ws.id}`, e);
18357
20297
  }
18358
20298
  }
18359
20299
  if (newWorkspaces.length > 0) {
18360
20300
  health.setRuntimeCount(workspaceStates.reduce((sum, w) => sum + w.runtimeIds.length, 0));
18361
- log6.info(`Reload complete — now polling ${workspaceStates.length} workspace(s)`);
20301
+ log7.info(`Reload complete — now polling ${workspaceStates.length} workspace(s)`);
18362
20302
  } else {
18363
- log6.info("Reload complete — no new workspaces found");
20303
+ log7.info("Reload complete — no new workspaces found");
18364
20304
  }
18365
20305
  } catch (e) {
18366
- log6.error("Failed to reload config", e);
20306
+ log7.error("Failed to reload config", e);
18367
20307
  }
18368
20308
  });
18369
20309
  await pollCycle();
18370
20310
  }
18371
20311
  function spawnSessionRunner(input) {
18372
20312
  const logDir = sessionRunnerLogDir();
18373
- mkdirSync5(logDir, { recursive: true });
18374
- const logFilePath = join8(logDir, `${input.task.id}.log`);
20313
+ mkdirSync7(logDir, { recursive: true });
20314
+ const logFilePath = join10(logDir, `${input.task.id}.log`);
18375
20315
  input.logFilePath = logFilePath;
18376
20316
  const encoded = Buffer.from(JSON.stringify(input)).toString("base64");
18377
20317
  let fd;
18378
20318
  try {
18379
20319
  fd = openSync(logFilePath, "a");
18380
20320
  } catch (e) {
18381
- log6.error(`Failed to open log file ${logFilePath}`, e);
20321
+ log7.error(`Failed to open log file ${logFilePath}`, e);
18382
20322
  }
18383
- const child = spawn2(process.execPath, [sessionRunnerPath, encoded], {
20323
+ const child = spawn5(process.execPath, [sessionRunnerPath, encoded], {
18384
20324
  detached: true,
18385
20325
  stdio: fd != null ? ["ignore", fd, fd] : ["ignore", "ignore", "ignore"]
18386
20326
  });
@@ -18391,27 +20331,27 @@ function spawnSessionRunner(input) {
18391
20331
  }
18392
20332
  function spawnMeetingRunner(input) {
18393
20333
  const logDir = sessionRunnerLogDir();
18394
- mkdirSync5(logDir, { recursive: true });
18395
- const logFilePath = join8(logDir, `meeting-${input.meetingId}.log`);
20334
+ mkdirSync7(logDir, { recursive: true });
20335
+ const logFilePath = join10(logDir, `meeting-${input.meetingId}.log`);
18396
20336
  const encoded = Buffer.from(JSON.stringify(input)).toString("base64");
18397
20337
  let fd;
18398
20338
  try {
18399
20339
  fd = openSync(logFilePath, "a");
18400
20340
  } catch (e) {
18401
- log6.error(`Failed to open meeting log file ${logFilePath}`, e);
20341
+ log7.error(`Failed to open meeting log file ${logFilePath}`, e);
18402
20342
  }
18403
- const child = spawn2(process.execPath, [meetingRunnerPath, encoded], {
20343
+ const child = spawn5(process.execPath, [meetingRunnerPath, encoded], {
18404
20344
  detached: true,
18405
20345
  stdio: fd != null ? ["ignore", fd, fd] : ["ignore", "ignore", "ignore"]
18406
20346
  });
18407
20347
  child.unref();
18408
20348
  if (fd != null)
18409
20349
  closeSync(fd);
18410
- log6.info(`Spawned meeting runner for ${input.meetingId} (pid=${child.pid})`);
20350
+ log7.info(`Spawned meeting runner for ${input.meetingId} (pid=${child.pid})`);
18411
20351
  return child;
18412
20352
  }
18413
20353
  async function handleFileRequest(client, config2, workspaceId, req, token) {
18414
- const agentWorkdir = join8(config2.workspacesRoot, workspaceId, req.agent_id, "workdir");
20354
+ const agentWorkdir = join10(config2.workspacesRoot, workspaceId, req.agent_id, "workdir");
18415
20355
  const resolved = validatePath(agentWorkdir, req.path);
18416
20356
  if (!resolved) {
18417
20357
  await client.reportFileData(token, { request_id: req.id, error: "invalid path", path: req.path });
@@ -18434,7 +20374,7 @@ async function handleFileRequest(client, config2, workspaceId, req, token) {
18434
20374
  }
18435
20375
  }
18436
20376
  async function handleTask(client, config2, runtimeIndex, task, token, activeTasks) {
18437
- log6.info(`Task ${task.id} claimed agent=${task.agentId}`);
20377
+ log7.info(`Task ${task.id} claimed agent=${task.agentId}`);
18438
20378
  if (task.type === TASK_TYPES.KILL_TASK) {
18439
20379
  const targetTaskId = task.context?.target_task_id;
18440
20380
  if (!targetTaskId) {
@@ -18442,8 +20382,8 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
18442
20382
  activeTasks.delete(task.id);
18443
20383
  return;
18444
20384
  }
18445
- const agentBaseDir = join8(config2.workspacesRoot, task.workspaceId, task.agentId, "workdir");
18446
- const timelineDir = join8(agentBaseDir, ".context_timeline");
20385
+ const agentBaseDir = join10(config2.workspacesRoot, task.workspaceId, task.agentId, "workdir");
20386
+ const timelineDir = join10(agentBaseDir, ".context_timeline");
18447
20387
  const MAX_WAIT_MS = Number(process.env.ALOOK_KILL_TASK_MAX_WAIT_MS) || 15000;
18448
20388
  const POLL_MS = Number(process.env.ALOOK_KILL_TASK_POLL_MS) || 200;
18449
20389
  const waitStart = Date.now();
@@ -18463,18 +20403,18 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
18463
20403
  try {
18464
20404
  process.kill(pid, "SIGTERM");
18465
20405
  await client.failTask(token, task.id, "killed");
18466
- log6.info(`Kill task ${task.id}: sent SIGTERM to pid=${pid} for target=${targetTaskId}`);
20406
+ log7.info(`Kill task ${task.id}: sent SIGTERM to pid=${pid} for target=${targetTaskId}`);
18467
20407
  } catch (e) {
18468
20408
  if (e?.code === "ESRCH") {
18469
20409
  await client.failTask(token, task.id, "target process already exited");
18470
- log6.info(`Kill task ${task.id}: target pid=${pid} already exited`);
20410
+ log7.info(`Kill task ${task.id}: target pid=${pid} already exited`);
18471
20411
  } else {
18472
20412
  await client.failTask(token, task.id, `kill failed: ${e}`);
18473
20413
  }
18474
20414
  }
18475
20415
  } else {
18476
20416
  await client.failTask(token, task.id, "target not found in timeline");
18477
- log6.info(`Kill task ${task.id}: target ${targetTaskId} not found in timeline`);
20417
+ log7.info(`Kill task ${task.id}: target ${targetTaskId} not found in timeline`);
18478
20418
  }
18479
20419
  activeTasks.delete(task.id);
18480
20420
  return;
@@ -18494,17 +20434,17 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
18494
20434
  }
18495
20435
  const provider = runtimeData.provider;
18496
20436
  if (task.contextKey) {
18497
- const agentBaseDir = join8(config2.workspacesRoot, task.workspaceId, task.agentId, "workdir");
20437
+ const agentBaseDir = join10(config2.workspacesRoot, task.workspaceId, task.agentId, "workdir");
18498
20438
  cleanupStaleIntents(agentBaseDir);
18499
- const timelineDir = join8(agentBaseDir, ".context_timeline");
20439
+ const timelineDir = join10(agentBaseDir, ".context_timeline");
18500
20440
  const lockAcquired = acquireSteeringLock(agentBaseDir, task.contextKey);
18501
20441
  if (!lockAcquired) {
18502
- log6.warn(`Steering lock contention for context_key=${task.contextKey}, proceeding without steering`);
20442
+ log7.warn(`Steering lock contention for context_key=${task.contextKey}, proceeding without steering`);
18503
20443
  } else {
18504
20444
  try {
18505
20445
  const predecessor = findRunningEntryByContextKey(timelineDir, task.contextKey, provider);
18506
20446
  if (predecessor && predecessor.task_id !== task.id) {
18507
- log6.info(`Steering: task ${task.id} supersedes predecessor ${predecessor.task_id} (context_key=${task.contextKey})`);
20447
+ log7.info(`Steering: task ${task.id} supersedes predecessor ${predecessor.task_id} (context_key=${task.contextKey})`);
18508
20448
  if (predecessor.pid != null) {
18509
20449
  writeKillIntent(agentBaseDir, {
18510
20450
  reason: "superseded",
@@ -18514,12 +20454,12 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
18514
20454
  });
18515
20455
  try {
18516
20456
  process.kill(predecessor.pid, "SIGTERM");
18517
- log6.info(`Steering: sent SIGTERM to predecessor pid=${predecessor.pid}`);
20457
+ log7.info(`Steering: sent SIGTERM to predecessor pid=${predecessor.pid}`);
18518
20458
  } catch (e) {
18519
20459
  if (e?.code === "ESRCH") {
18520
- log6.info(`Steering: predecessor pid=${predecessor.pid} already exited`);
20460
+ log7.info(`Steering: predecessor pid=${predecessor.pid} already exited`);
18521
20461
  } else {
18522
- log6.warn(`Steering: kill failed for pid=${predecessor.pid}`, e);
20462
+ log7.warn(`Steering: kill failed for pid=${predecessor.pid}`, e);
18523
20463
  }
18524
20464
  }
18525
20465
  const waitStart = Date.now();
@@ -18532,14 +20472,14 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
18532
20472
  await new Promise((r) => setTimeout(r, POLL_MS));
18533
20473
  }
18534
20474
  if (findRunningPidByTaskId(timelineDir, predecessor.task_id) != null) {
18535
- log6.warn(`Steering: predecessor pid=${predecessor.pid} did not exit within ${MAX_WAIT_MS}ms, proceeding anyway`);
20475
+ log7.warn(`Steering: predecessor pid=${predecessor.pid} did not exit within ${MAX_WAIT_MS}ms, proceeding anyway`);
18536
20476
  }
18537
20477
  }
18538
20478
  try {
18539
20479
  await client.supersedeTask(token, predecessor.task_id);
18540
- log6.info(`Steering: predecessor ${predecessor.task_id} marked superseded`);
20480
+ log7.info(`Steering: predecessor ${predecessor.task_id} marked superseded`);
18541
20481
  } catch (e) {
18542
- log6.warn(`Steering: failed to mark predecessor superseded server-side`, e);
20482
+ log7.warn(`Steering: failed to mark predecessor superseded server-side`, e);
18543
20483
  }
18544
20484
  }
18545
20485
  } finally {
@@ -18563,15 +20503,46 @@ async function handleTask(client, config2, runtimeIndex, task, token, activeTask
18563
20503
  messageInactivityTimeout: config2.messageInactivityTimeout
18564
20504
  };
18565
20505
  const child = spawnSessionRunner(input);
18566
- child.on("close", () => activeTasks.delete(task.id));
18567
- log6.info(`Task ${task.id} dispatched to session-runner (pid=${child.pid})`);
20506
+ child.on("close", async (code) => {
20507
+ activeTasks.delete(task.id);
20508
+ if (code !== 0) {
20509
+ const msg = code === null ? `session-runner killed by signal (task ${task.id})` : `session-runner crashed (exit code ${code}, task ${task.id})`;
20510
+ log7.warn(msg);
20511
+ const timelineDir = join10(config2.workspacesRoot, task.workspaceId, task.agentId, "workdir", ".context_timeline");
20512
+ updateEntry(timelineDir, task.id, (entry) => {
20513
+ entry.pid = null;
20514
+ entry.status = "failed";
20515
+ entry.errmsg = msg;
20516
+ });
20517
+ try {
20518
+ await client.failTask(token, task.id, msg);
20519
+ } catch (e) {
20520
+ if (isClientError2(e)) {
20521
+ log7.info(`Backstop: task ${task.id} already in terminal state`);
20522
+ return;
20523
+ }
20524
+ log7.error(`Backstop: failed to report crash for task ${task.id}`, e);
20525
+ try {
20526
+ await writeMarkerFile(config2.workspacesRoot, {
20527
+ taskId: task.id,
20528
+ type: "fail",
20529
+ payload: { error: msg },
20530
+ token,
20531
+ serverURL: config2.serverURL,
20532
+ createdAt: new Date().toISOString()
20533
+ });
20534
+ } catch {}
20535
+ }
20536
+ }
20537
+ });
20538
+ log7.info(`Task ${task.id} dispatched to session-runner (pid=${child.pid})`);
18568
20539
  }
18569
20540
 
18570
20541
  // commands/daemon.ts
18571
20542
  var PID_POLL_INTERVAL_MS = 200;
18572
20543
  var PID_POLL_TIMEOUT_MS = 2000;
18573
20544
  var STOP_POLL_INTERVAL_MS = 200;
18574
- function sleep(ms) {
20545
+ function sleep2(ms) {
18575
20546
  return new Promise((r) => setTimeout(r, ms));
18576
20547
  }
18577
20548
  function buildChildArgs(profile, serverUrl) {
@@ -18590,7 +20561,7 @@ async function waitForPidFile(profile) {
18590
20561
  const pid = readDaemonPid(profile);
18591
20562
  if (pid != null && isProcessAlive(pid))
18592
20563
  return pid;
18593
- await sleep(PID_POLL_INTERVAL_MS);
20564
+ await sleep2(PID_POLL_INTERVAL_MS);
18594
20565
  }
18595
20566
  return null;
18596
20567
  }
@@ -18602,9 +20573,9 @@ async function startInBackground(profile, serverUrl) {
18602
20573
  return;
18603
20574
  }
18604
20575
  const logPath = daemonLogFilePath();
18605
- mkdirSync6(dirname4(logPath), { recursive: true, mode: 448 });
20576
+ mkdirSync8(dirname4(logPath), { recursive: true, mode: 448 });
18606
20577
  const logFd = openSync2(logPath, "a", 384);
18607
- const child = spawn3(process.execPath, buildChildArgs(profile, serverUrl), {
20578
+ const child = spawn6(process.execPath, buildChildArgs(profile, serverUrl), {
18608
20579
  detached: true,
18609
20580
  stdio: ["ignore", logFd, logFd],
18610
20581
  env: resolveLoginShellEnv()
@@ -18658,7 +20629,7 @@ async function stopCommand(profile) {
18658
20629
  console.log("Daemon stopped.");
18659
20630
  return;
18660
20631
  }
18661
- await sleep(STOP_POLL_INTERVAL_MS);
20632
+ await sleep2(STOP_POLL_INTERVAL_MS);
18662
20633
  }
18663
20634
  console.warn(`Daemon did not exit within ${shutdownMs}ms — force killing.`);
18664
20635
  if (!isWindows) {
@@ -18723,10 +20694,22 @@ function configCommand() {
18723
20694
 
18724
20695
  // commands/email.ts
18725
20696
  import { Command as Command5 } from "commander";
18726
- import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync7, readFileSync as readFileSync7, statSync as statSync4 } from "fs";
18727
- import { basename, join as join9 } from "path";
20697
+ import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync9, readFileSync as readFileSync8, statSync as statSync4 } from "fs";
20698
+ import { basename, join as join11 } from "path";
18728
20699
  import PostalMime from "postal-mime";
18729
- var log7 = createLogger2({ module: "email" });
20700
+
20701
+ // lib/flags.ts
20702
+ function resolveAgentId(opts) {
20703
+ const id = opts.agent_id || process.env.ALOOK_AGENT_ID;
20704
+ if (!id) {
20705
+ console.error("Error: --agent_id is required (or set ALOOK_AGENT_ID env var)");
20706
+ process.exit(1);
20707
+ }
20708
+ return id;
20709
+ }
20710
+
20711
+ // commands/email.ts
20712
+ var log8 = createLogger2({ module: "email" });
18730
20713
  var VALID_STATUSES = ["unread", "read", "archived", "sent"];
18731
20714
  var VALID_FOLDERS = ["inbox", "sent", "untrust"];
18732
20715
  var EMAIL_BASE = tempDir("alook-emails");
@@ -18797,8 +20780,9 @@ function resolveClientOpts(command, opts) {
18797
20780
  }
18798
20781
  function emailCommand() {
18799
20782
  const cmd = new Command5("email").description("Manage agent emails");
18800
- cmd.command("pull").description("Download and parse emails to /tmp/alook-emails/{workspaceId}/{agentId}/").requiredOption("--agent_id <id>", "Agent ID").option("--status <status>", "Filter by status (unread, read, archived)").option("--folder <folder>", "Email folder (inbox, sent, untrust)").option("--limit <n>", "Maximum number of emails to download").option("--offset <n>", "Number of emails to skip").option("--workspace <id>", "Workspace ID").option("--json", "Output as JSON instead of files").action(async (opts, command) => {
18801
- const { serverUrl, token, workspaceId } = resolveClientOpts(command, { workspace: opts.workspace, agentId: opts.agent_id });
20783
+ cmd.command("pull").description("Download and parse emails to /tmp/alook-emails/{workspaceId}/{agentId}/").option("--agent_id <id>", "Agent ID").option("--status <status>", "Filter by status (unread, read, archived)").option("--folder <folder>", "Email folder (inbox, sent, untrust)").option("--limit <n>", "Maximum number of emails to download").option("--offset <n>", "Number of emails to skip").option("--workspace <id>", "Workspace ID").option("--json", "Output as JSON instead of files").action(async (opts, command) => {
20784
+ const agentId = resolveAgentId(opts);
20785
+ const { serverUrl, token, workspaceId } = resolveClientOpts(command, { workspace: opts.workspace, agentId });
18802
20786
  const client = new APIClient(serverUrl, token, workspaceId);
18803
20787
  if (opts.status && !VALID_STATUSES.includes(opts.status)) {
18804
20788
  console.error(`Error: invalid status "${opts.status}", must be one of: ${VALID_STATUSES.join(", ")}`);
@@ -18822,9 +20806,9 @@ function emailCommand() {
18822
20806
  process.exit(1);
18823
20807
  }
18824
20808
  }
18825
- const emailDir_base = join9(EMAIL_BASE, workspaceId, opts.agent_id);
20809
+ const emailDir_base = join11(EMAIL_BASE, workspaceId, agentId);
18826
20810
  try {
18827
- let query = `/api/email?agentId=${opts.agent_id}`;
20811
+ let query = `/api/email?agentId=${agentId}`;
18828
20812
  if (opts.status)
18829
20813
  query += `&status=${opts.status}`;
18830
20814
  if (opts.folder)
@@ -18842,11 +20826,11 @@ function emailCommand() {
18842
20826
  printJSON(emails2);
18843
20827
  return;
18844
20828
  }
18845
- mkdirSync7(emailDir_base, { recursive: true });
20829
+ mkdirSync9(emailDir_base, { recursive: true });
18846
20830
  const downloadedPaths = [];
18847
20831
  for (const email3 of emails2) {
18848
- const emailDir = join9(emailDir_base, email3.id);
18849
- mkdirSync7(emailDir, { recursive: true });
20832
+ const emailDir = join11(emailDir_base, email3.id);
20833
+ mkdirSync9(emailDir, { recursive: true });
18850
20834
  const metadata = {
18851
20835
  id: email3.id,
18852
20836
  from: email3.from_email,
@@ -18858,8 +20842,8 @@ function emailCommand() {
18858
20842
  in_reply_to: email3.in_reply_to || "",
18859
20843
  references: email3.references || ""
18860
20844
  };
18861
- const metadataPath = join9(emailDir, "metadata.json");
18862
- writeFileSync6(metadataPath, JSON.stringify(metadata, null, 2));
20845
+ const metadataPath = join11(emailDir, "metadata.json");
20846
+ writeFileSync7(metadataPath, JSON.stringify(metadata, null, 2));
18863
20847
  downloadedPaths.push(metadataPath);
18864
20848
  let rawMime;
18865
20849
  try {
@@ -18867,25 +20851,25 @@ function emailCommand() {
18867
20851
  } catch (err) {
18868
20852
  const msg = err instanceof Error ? err.message : String(err);
18869
20853
  if (msg.includes("404")) {
18870
- log7.warn(`email body not available for ${email3.id}, skipping`);
20854
+ log8.warn(`email body not available for ${email3.id}, skipping`);
18871
20855
  continue;
18872
20856
  }
18873
20857
  throw err;
18874
20858
  }
18875
20859
  const parsed = await new PostalMime().parse(rawMime);
18876
20860
  if (parsed.text) {
18877
- const bodyPath = join9(emailDir, "body.txt");
18878
- writeFileSync6(bodyPath, parsed.text);
20861
+ const bodyPath = join11(emailDir, "body.txt");
20862
+ writeFileSync7(bodyPath, parsed.text);
18879
20863
  downloadedPaths.push(bodyPath);
18880
20864
  }
18881
20865
  if (parsed.html) {
18882
- const htmlPath = join9(emailDir, "body.html");
18883
- writeFileSync6(htmlPath, parsed.html);
20866
+ const htmlPath = join11(emailDir, "body.html");
20867
+ writeFileSync7(htmlPath, parsed.html);
18884
20868
  downloadedPaths.push(htmlPath);
18885
20869
  }
18886
20870
  if (parsed.attachments && parsed.attachments.length > 0) {
18887
- const attDir = join9(emailDir, "attachments");
18888
- mkdirSync7(attDir, { recursive: true });
20871
+ const attDir = join11(emailDir, "attachments");
20872
+ mkdirSync9(attDir, { recursive: true });
18889
20873
  const usedFilenames = new Set;
18890
20874
  for (let i = 0;i < parsed.attachments.length; i++) {
18891
20875
  const att = parsed.attachments[i];
@@ -18894,7 +20878,7 @@ function emailCommand() {
18894
20878
  filename = `${i}-${filename}`;
18895
20879
  }
18896
20880
  usedFilenames.add(filename);
18897
- const attPath = join9(attDir, filename);
20881
+ const attPath = join11(attDir, filename);
18898
20882
  const content = att.content;
18899
20883
  let buf;
18900
20884
  if (typeof content === "string") {
@@ -18904,7 +20888,7 @@ function emailCommand() {
18904
20888
  } else {
18905
20889
  buf = Buffer.from(content);
18906
20890
  }
18907
- writeFileSync6(attPath, buf);
20891
+ writeFileSync7(attPath, buf);
18908
20892
  downloadedPaths.push(attPath);
18909
20893
  }
18910
20894
  }
@@ -18918,8 +20902,9 @@ function emailCommand() {
18918
20902
  process.exit(1);
18919
20903
  }
18920
20904
  });
18921
- cmd.command("set").description("Update email status").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--email_id <id>", "Email ID").requiredOption("--status <status>", "New status (unread, read, archived)").option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
18922
- const { serverUrl, token, workspaceId } = resolveClientOpts(command, { workspace: opts.workspace, agentId: opts.agent_id });
20905
+ cmd.command("set").description("Update email status").option("--agent_id <id>", "Agent ID").requiredOption("--email_id <id>", "Email ID").requiredOption("--status <status>", "New status (unread, read, archived)").option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
20906
+ const agentId = resolveAgentId(opts);
20907
+ const { serverUrl, token, workspaceId } = resolveClientOpts(command, { workspace: opts.workspace, agentId });
18923
20908
  const client = new APIClient(serverUrl, token, workspaceId);
18924
20909
  if (!VALID_STATUSES.includes(opts.status)) {
18925
20910
  console.error(`Error: invalid status "${opts.status}", must be one of: ${VALID_STATUSES.join(", ")}`);
@@ -18935,15 +20920,16 @@ function emailCommand() {
18935
20920
  process.exit(1);
18936
20921
  }
18937
20922
  });
18938
- cmd.command("send").description("Send an email from the agent").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--to <addr>", "Recipient email address").requiredOption("--subject <s>", "Subject line").requiredOption("--body-file <path>", "Path to HTML body file").option("--from <addr>", "Send from a specific email address (custom mailbox)").option("--in-reply-to <emailId>", "Email ID to reply to (sets threading headers)").option("--attachment <path>", "Path to a file to attach (repeatable)", collectRepeated, []).option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
20923
+ cmd.command("send").description("Send an email from the agent").option("--agent_id <id>", "Agent ID").requiredOption("--to <addr>", "Recipient email address").requiredOption("--subject <s>", "Subject line").requiredOption("--body-file <path>", "Path to HTML body file").option("--from <addr>", "Send from a specific email address (custom mailbox)").option("--in-reply-to <emailId>", "Email ID to reply to (sets threading headers)").option("--attachment <path>", "Path to a file to attach (repeatable)", collectRepeated, []).option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
20924
+ const agentId = resolveAgentId(opts);
18939
20925
  const { serverUrl, token, workspaceId } = resolveClientOpts(command, {
18940
20926
  workspace: opts.workspace,
18941
- agentId: opts.agent_id
20927
+ agentId
18942
20928
  });
18943
20929
  const client = new APIClient(serverUrl, token, workspaceId);
18944
20930
  let htmlBody;
18945
20931
  try {
18946
- htmlBody = readFileSync7(opts.bodyFile, "utf-8");
20932
+ htmlBody = readFileSync8(opts.bodyFile, "utf-8");
18947
20933
  } catch (err) {
18948
20934
  console.error(`Error: cannot read body file "${opts.bodyFile}": ${err instanceof Error ? err.message : err}`);
18949
20935
  process.exit(1);
@@ -18955,17 +20941,17 @@ function emailCommand() {
18955
20941
  const attachmentPaths = opts.attachment ?? [];
18956
20942
  const attachments = [];
18957
20943
  try {
18958
- for (const path of attachmentPaths) {
20944
+ for (const path2 of attachmentPaths) {
18959
20945
  let bytes;
18960
20946
  let size;
18961
20947
  try {
18962
- bytes = readFileSync7(path);
18963
- size = statSync4(path).size;
20948
+ bytes = readFileSync8(path2);
20949
+ size = statSync4(path2).size;
18964
20950
  } catch (err) {
18965
- console.error(`Error: cannot read attachment "${path}": ${err instanceof Error ? err.message : err}`);
20951
+ console.error(`Error: cannot read attachment "${path2}": ${err instanceof Error ? err.message : err}`);
18966
20952
  process.exit(1);
18967
20953
  }
18968
- const filename = basename(path);
20954
+ const filename = basename(path2);
18969
20955
  const contentType = guessContentType(filename);
18970
20956
  const form = new FormData;
18971
20957
  form.append("file", new Blob([new Uint8Array(bytes)], { type: contentType }), filename);
@@ -18987,14 +20973,14 @@ function emailCommand() {
18987
20973
  references = [parentEmail.references, parentEmail.message_id].filter(Boolean).join(" ").trim() || undefined;
18988
20974
  }
18989
20975
  } catch {
18990
- log7.warn(`could not fetch parent email ${opts.inReplyTo}, sending without threading`);
20976
+ log8.warn(`could not fetch parent email ${opts.inReplyTo}, sending without threading`);
18991
20977
  }
18992
20978
  }
18993
20979
  const conversationId = process.env.ALOOK_CONVERSATION_ID;
18994
20980
  const traceId = process.env.ALOOK_TRACE_ID;
18995
20981
  const sourceTaskId = process.env.ALOOK_TASK_ID;
18996
20982
  const res = await client.postJSON("/api/email/send", {
18997
- agentId: opts.agent_id,
20983
+ agentId,
18998
20984
  to: opts.to,
18999
20985
  subject: opts.subject,
19000
20986
  htmlBody,
@@ -19011,10 +20997,11 @@ function emailCommand() {
19011
20997
  process.exit(1);
19012
20998
  }
19013
20999
  });
19014
- cmd.command("forward").description("Forward an email to a new recipient").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--email_id <id>", "Source email ID to forward").requiredOption("--to <addr>", "Recipient email address").option("--from <addr>", "Send from a specific email address (custom mailbox)").option("--note <text>", "Text to prepend above the forwarded message").option("--attachment <path>", "Extra file to attach (repeatable)", collectRepeated, []).option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
21000
+ cmd.command("forward").description("Forward an email to a new recipient").option("--agent_id <id>", "Agent ID").requiredOption("--email_id <id>", "Source email ID to forward").requiredOption("--to <addr>", "Recipient email address").option("--from <addr>", "Send from a specific email address (custom mailbox)").option("--note <text>", "Text to prepend above the forwarded message").option("--attachment <path>", "Extra file to attach (repeatable)", collectRepeated, []).option("--workspace <id>", "Workspace ID").action(async (opts, command) => {
21001
+ const agentId = resolveAgentId(opts);
19015
21002
  const { serverUrl, token, workspaceId } = resolveClientOpts(command, {
19016
21003
  workspace: opts.workspace,
19017
- agentId: opts.agent_id
21004
+ agentId
19018
21005
  });
19019
21006
  const client = new APIClient(serverUrl, token, workspaceId);
19020
21007
  try {
@@ -19067,17 +21054,17 @@ function emailCommand() {
19067
21054
  }
19068
21055
  }
19069
21056
  const extraPaths = opts.attachment ?? [];
19070
- for (const path of extraPaths) {
21057
+ for (const path2 of extraPaths) {
19071
21058
  let bytes;
19072
21059
  let size;
19073
21060
  try {
19074
- bytes = readFileSync7(path);
19075
- size = statSync4(path).size;
21061
+ bytes = readFileSync8(path2);
21062
+ size = statSync4(path2).size;
19076
21063
  } catch (err) {
19077
- console.error(`Error: cannot read attachment "${path}": ${err instanceof Error ? err.message : err}`);
21064
+ console.error(`Error: cannot read attachment "${path2}": ${err instanceof Error ? err.message : err}`);
19078
21065
  process.exit(1);
19079
21066
  }
19080
- const filename = basename(path);
21067
+ const filename = basename(path2);
19081
21068
  const contentType = guessContentType(filename);
19082
21069
  const form = new FormData;
19083
21070
  form.append("file", new Blob([new Uint8Array(bytes)], { type: contentType }), filename);
@@ -19108,7 +21095,7 @@ function emailCommand() {
19108
21095
  const traceId = process.env.ALOOK_TRACE_ID;
19109
21096
  const sourceTaskId = process.env.ALOOK_TASK_ID;
19110
21097
  const res = await client.postJSON("/api/email/send", {
19111
- agentId: opts.agent_id,
21098
+ agentId,
19112
21099
  to: opts.to,
19113
21100
  subject,
19114
21101
  htmlBody,
@@ -19128,14 +21115,15 @@ function emailCommand() {
19128
21115
  }
19129
21116
  });
19130
21117
  const whitelistCmd = new Command5("whitelist").description("Manage email whitelist (allowed senders)");
19131
- whitelistCmd.command("list").description("List all whitelisted emails for an agent").requiredOption("--agent_id <id>", "Agent ID").option("--workspace <id>", "Workspace ID").option("--json", "Output as JSON").action(async (opts, command) => {
21118
+ whitelistCmd.command("list").description("List all whitelisted emails for an agent").option("--agent_id <id>", "Agent ID").option("--workspace <id>", "Workspace ID").option("--json", "Output as JSON").action(async (opts, command) => {
21119
+ const agentId = resolveAgentId(opts);
19132
21120
  const { serverUrl, token, workspaceId } = resolveClientOpts(command, {
19133
21121
  workspace: opts.workspace,
19134
- agentId: opts.agent_id
21122
+ agentId
19135
21123
  });
19136
21124
  const client = new APIClient(serverUrl, token, workspaceId);
19137
21125
  try {
19138
- const entries = await client.getJSON(`/api/agents/${opts.agent_id}/whitelist`);
21126
+ const entries = await client.getJSON(`/api/agents/${agentId}/whitelist`);
19139
21127
  if (!entries.length) {
19140
21128
  console.log("No whitelisted emails.");
19141
21129
  return;
@@ -19150,14 +21138,15 @@ function emailCommand() {
19150
21138
  process.exit(1);
19151
21139
  }
19152
21140
  });
19153
- whitelistCmd.command("add").description("Add an email to the whitelist").requiredOption("--agent_id <id>", "Agent ID").option("--workspace <id>", "Workspace ID").argument("<email>", "Email address to whitelist").action(async (email3, opts, command) => {
21141
+ whitelistCmd.command("add").description("Add an email to the whitelist").option("--agent_id <id>", "Agent ID").option("--workspace <id>", "Workspace ID").argument("<email>", "Email address to whitelist").action(async (email3, opts, command) => {
21142
+ const agentId = resolveAgentId(opts);
19154
21143
  const { serverUrl, token, workspaceId } = resolveClientOpts(command, {
19155
21144
  workspace: opts.workspace,
19156
- agentId: opts.agent_id
21145
+ agentId
19157
21146
  });
19158
21147
  const client = new APIClient(serverUrl, token, workspaceId);
19159
21148
  try {
19160
- const entry = await client.postJSON(`/api/agents/${opts.agent_id}/whitelist`, { email: email3.toLowerCase() });
21149
+ const entry = await client.postJSON(`/api/agents/${agentId}/whitelist`, { email: email3.toLowerCase() });
19161
21150
  console.log(`Added ${entry.email} to whitelist (id: ${entry.id})`);
19162
21151
  } catch (err) {
19163
21152
  const msg = err instanceof Error ? err.message : String(err);
@@ -19169,21 +21158,22 @@ function emailCommand() {
19169
21158
  process.exit(1);
19170
21159
  }
19171
21160
  });
19172
- whitelistCmd.command("delete").description("Remove an email from the whitelist").requiredOption("--agent_id <id>", "Agent ID").option("--workspace <id>", "Workspace ID").argument("<email>", "Email address to remove").action(async (email3, opts, command) => {
21161
+ whitelistCmd.command("delete").description("Remove an email from the whitelist").option("--agent_id <id>", "Agent ID").option("--workspace <id>", "Workspace ID").argument("<email>", "Email address to remove").action(async (email3, opts, command) => {
21162
+ const agentId = resolveAgentId(opts);
19173
21163
  const { serverUrl, token, workspaceId } = resolveClientOpts(command, {
19174
21164
  workspace: opts.workspace,
19175
- agentId: opts.agent_id
21165
+ agentId
19176
21166
  });
19177
21167
  const client = new APIClient(serverUrl, token, workspaceId);
19178
21168
  const normalizedEmail = email3.toLowerCase();
19179
21169
  try {
19180
- const entries = await client.getJSON(`/api/agents/${opts.agent_id}/whitelist`);
21170
+ const entries = await client.getJSON(`/api/agents/${agentId}/whitelist`);
19181
21171
  const entry = entries.find((e) => e.email === normalizedEmail);
19182
21172
  if (!entry) {
19183
21173
  console.error(`Error: ${normalizedEmail} is not in the whitelist`);
19184
21174
  process.exit(1);
19185
21175
  }
19186
- await client.deleteJSON(`/api/agents/${opts.agent_id}/whitelist/${entry.id}`);
21176
+ await client.deleteJSON(`/api/agents/${agentId}/whitelist/${entry.id}`);
19187
21177
  console.log(`Removed ${normalizedEmail} from whitelist`);
19188
21178
  } catch (err) {
19189
21179
  const msg = err instanceof Error ? err.message : String(err);
@@ -19243,8 +21233,9 @@ function printEventDetail(ev) {
19243
21233
  }
19244
21234
  function calendarCommand() {
19245
21235
  const cmd = new Command6("calendar").description("Manage scheduled agent events");
19246
- cmd.command("set").description("Create a calendar event").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--event_title <title>", "Event title (used as the task prompt)").requiredOption("--datetime <iso>", "Scheduled datetime (YYYY-MM-DDTHH:MM, local time)").option("--description <text>", "Optional longer-form notes for the event").option("--repeat <interval>", "Repeat interval, e.g. 1day, 2hour, 1month").option("--repeat_stop_date <date>", "Stop repeating on or after this date (YYYY-MM-DD, local time)").option("--json", "Output as JSON").action(async (opts, command) => {
19247
- const { serverUrl, token, workspaceId } = resolveClientOpts2(command, opts.agent_id);
21236
+ cmd.command("set").description("Create a calendar event").option("--agent_id <id>", "Agent ID").requiredOption("--event_title <title>", "Event title (used as the task prompt)").requiredOption("--datetime <iso>", "Scheduled datetime (YYYY-MM-DDTHH:MM, local time)").option("--description <text>", "Optional longer-form notes for the event").option("--repeat <interval>", "Repeat interval, e.g. 1day, 2hour, 1month").option("--repeat_stop_date <date>", "Stop repeating on or after this date (YYYY-MM-DD, local time)").option("--json", "Output as JSON").action(async (opts, command) => {
21237
+ const agentId = resolveAgentId(opts);
21238
+ const { serverUrl, token, workspaceId } = resolveClientOpts2(command, agentId);
19248
21239
  const client = new APIClient(serverUrl, token, workspaceId);
19249
21240
  let scheduledAt;
19250
21241
  try {
@@ -19262,7 +21253,7 @@ function calendarCommand() {
19262
21253
  process.exit(1);
19263
21254
  }
19264
21255
  const body = {
19265
- agent_id: opts.agent_id,
21256
+ agent_id: agentId,
19266
21257
  title: opts.event_title,
19267
21258
  scheduled_at: scheduledAt
19268
21259
  };
@@ -19284,14 +21275,15 @@ function calendarCommand() {
19284
21275
  process.exit(1);
19285
21276
  }
19286
21277
  });
19287
- cmd.command("list").description("List calendar events for an agent").requiredOption("--agent_id <id>", "Agent ID").option("--future_days <n>", "Include events scheduled in the next N days", "30").option("--past_days <n>", "Include events scheduled in the past N days", "0").option("--json", "Output as JSON").action(async (opts, command) => {
19288
- const { serverUrl, token, workspaceId } = resolveClientOpts2(command, opts.agent_id);
21278
+ cmd.command("list").description("List calendar events for an agent").option("--agent_id <id>", "Agent ID").option("--future_days <n>", "Include events scheduled in the next N days", "30").option("--past_days <n>", "Include events scheduled in the past N days", "0").option("--json", "Output as JSON").action(async (opts, command) => {
21279
+ const agentId = resolveAgentId(opts);
21280
+ const { serverUrl, token, workspaceId } = resolveClientOpts2(command, agentId);
19289
21281
  const client = new APIClient(serverUrl, token, workspaceId);
19290
21282
  const now = Date.now();
19291
21283
  const from = new Date(now - Number(opts.past_days) * 86400000).toISOString();
19292
21284
  const to = new Date(now + Number(opts.future_days) * 86400000).toISOString();
19293
21285
  try {
19294
- const events = await client.getJSON(`/api/calendar?agentId=${encodeURIComponent(opts.agent_id)}&from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}`);
21286
+ const events = await client.getJSON(`/api/calendar?agentId=${encodeURIComponent(agentId)}&from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}`);
19295
21287
  if (opts.json) {
19296
21288
  printJSON(events);
19297
21289
  return;
@@ -19310,13 +21302,14 @@ function calendarCommand() {
19310
21302
  process.exit(1);
19311
21303
  }
19312
21304
  });
19313
- cmd.command("show").description("Show the full detail of a single calendar event").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--event_id <id>", "Event ID").option("--json", "Output as JSON").action(async (opts, command) => {
19314
- const { serverUrl, token, workspaceId } = resolveClientOpts2(command, opts.agent_id);
21305
+ cmd.command("show").description("Show the full detail of a single calendar event").option("--agent_id <id>", "Agent ID").requiredOption("--event_id <id>", "Event ID").option("--json", "Output as JSON").action(async (opts, command) => {
21306
+ const agentId = resolveAgentId(opts);
21307
+ const { serverUrl, token, workspaceId } = resolveClientOpts2(command, agentId);
19315
21308
  const client = new APIClient(serverUrl, token, workspaceId);
19316
21309
  try {
19317
21310
  const ev = await client.getJSON(`/api/calendar/${opts.event_id}`);
19318
- if (ev.agent_id !== opts.agent_id) {
19319
- console.error(`Error: event ${ev.id} does not belong to agent ${opts.agent_id}`);
21311
+ if (ev.agent_id !== agentId) {
21312
+ console.error(`Error: event ${ev.id} does not belong to agent ${agentId}`);
19320
21313
  process.exit(1);
19321
21314
  }
19322
21315
  if (opts.json) {
@@ -19329,7 +21322,7 @@ function calendarCommand() {
19329
21322
  process.exit(1);
19330
21323
  }
19331
21324
  });
19332
- cmd.command("update").description("Update fields on an existing calendar event").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--event_id <id>", "Event ID").option("--event_title <title>", "New event title (task prompt)").option("--description <text>", "New description text").option("--clear_description", "Remove the description (sets to null)").option("--datetime <iso>", "New scheduled datetime (YYYY-MM-DDTHH:MM, local time)").option("--repeat <interval>", "New repeat interval, e.g. 1day, 2hour").option("--clear_repeat", "Convert a repeating event into a one-off").option("--repeat_stop_date <date>", "New stop date (YYYY-MM-DD, local time)").option("--clear_repeat_stop_date", "Remove the repeat stop date").option("--json", "Output as JSON").action(async (opts, command) => {
21325
+ cmd.command("update").description("Update fields on an existing calendar event").option("--agent_id <id>", "Agent ID").requiredOption("--event_id <id>", "Event ID").option("--event_title <title>", "New event title (task prompt)").option("--description <text>", "New description text").option("--clear_description", "Remove the description (sets to null)").option("--datetime <iso>", "New scheduled datetime (YYYY-MM-DDTHH:MM, local time)").option("--repeat <interval>", "New repeat interval, e.g. 1day, 2hour").option("--clear_repeat", "Convert a repeating event into a one-off").option("--repeat_stop_date <date>", "New stop date (YYYY-MM-DD, local time)").option("--clear_repeat_stop_date", "Remove the repeat stop date").option("--json", "Output as JSON").action(async (opts, command) => {
19333
21326
  if (opts.description && opts.clear_description) {
19334
21327
  console.error("Error: --description and --clear_description are mutually exclusive");
19335
21328
  process.exit(1);
@@ -19374,12 +21367,13 @@ function calendarCommand() {
19374
21367
  console.error("Error: no fields to update — pass at least one of --event_title, --description, --clear_description, --datetime, --repeat, --clear_repeat, --repeat_stop_date, --clear_repeat_stop_date");
19375
21368
  process.exit(1);
19376
21369
  }
19377
- const { serverUrl, token, workspaceId } = resolveClientOpts2(command, opts.agent_id);
21370
+ const agentId = resolveAgentId(opts);
21371
+ const { serverUrl, token, workspaceId } = resolveClientOpts2(command, agentId);
19378
21372
  const client = new APIClient(serverUrl, token, workspaceId);
19379
21373
  try {
19380
21374
  const updated = await client.patchJSON(`/api/calendar/${opts.event_id}`, body);
19381
- if (updated.agent_id !== opts.agent_id) {
19382
- console.error(`Error: event ${updated.id} does not belong to agent ${opts.agent_id}`);
21375
+ if (updated.agent_id !== agentId) {
21376
+ console.error(`Error: event ${updated.id} does not belong to agent ${agentId}`);
19383
21377
  process.exit(1);
19384
21378
  }
19385
21379
  if (opts.json) {
@@ -19392,8 +21386,9 @@ function calendarCommand() {
19392
21386
  process.exit(1);
19393
21387
  }
19394
21388
  });
19395
- cmd.command("delete").description("Delete a calendar event").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--event_id <id>", "Event ID").action(async (opts, command) => {
19396
- const { serverUrl, token, workspaceId } = resolveClientOpts2(command, opts.agent_id);
21389
+ cmd.command("delete").description("Delete a calendar event").option("--agent_id <id>", "Agent ID").requiredOption("--event_id <id>", "Event ID").action(async (opts, command) => {
21390
+ const agentId = resolveAgentId(opts);
21391
+ const { serverUrl, token, workspaceId } = resolveClientOpts2(command, agentId);
19397
21392
  const client = new APIClient(serverUrl, token, workspaceId);
19398
21393
  try {
19399
21394
  await client.deleteJSON(`/api/calendar/${opts.event_id}`);
@@ -19408,7 +21403,7 @@ function calendarCommand() {
19408
21403
 
19409
21404
  // commands/issue.ts
19410
21405
  import { Command as Command7 } from "commander";
19411
- import { readFileSync as readFileSync8 } from "fs";
21406
+ import { readFileSync as readFileSync9 } from "fs";
19412
21407
  var VALID_STATUSES2 = ["todo", "in_progress", "review", "done", "closed", "canceled", "failed"];
19413
21408
  function resolveClientOpts3(command, agentId) {
19414
21409
  let root = command;
@@ -19432,7 +21427,7 @@ function readBody(opts) {
19432
21427
  process.exit(1);
19433
21428
  }
19434
21429
  if (opts.bodyFile)
19435
- return readFileSync8(opts.bodyFile, "utf-8");
21430
+ return readFileSync9(opts.bodyFile, "utf-8");
19436
21431
  return opts.body ?? "";
19437
21432
  }
19438
21433
  function printIssue(issue3) {
@@ -19466,13 +21461,14 @@ comments:`);
19466
21461
  }
19467
21462
  function issueCommand() {
19468
21463
  const cmd = new Command7("issue").description("Manage assigned issues");
19469
- cmd.command("create").description("Create and dispatch an issue to an agent").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--title <title>", "Issue title").option("--description <text>", "Issue description").option("--body-file <path>", "Read issue description from a file").option("--json", "Output as JSON").action(async (opts, command) => {
19470
- const { serverUrl, token, workspaceId } = resolveClientOpts3(command, opts.agent_id);
21464
+ cmd.command("create").description("Create and dispatch an issue to an agent").option("--agent_id <id>", "Agent ID").requiredOption("--title <title>", "Issue title").option("--description <text>", "Issue description").option("--body-file <path>", "Read issue description from a file").option("--json", "Output as JSON").action(async (opts, command) => {
21465
+ const agentId = resolveAgentId(opts);
21466
+ const { serverUrl, token, workspaceId } = resolveClientOpts3(command, agentId);
19471
21467
  const client = new APIClient(serverUrl, token, workspaceId);
19472
21468
  const description = readBody({ body: opts.description, bodyFile: opts.bodyFile });
19473
21469
  try {
19474
21470
  const res = await client.postJSON("/api/issues", {
19475
- agent_id: opts.agent_id,
21471
+ agent_id: agentId,
19476
21472
  title: opts.title,
19477
21473
  description
19478
21474
  });
@@ -19484,14 +21480,15 @@ function issueCommand() {
19484
21480
  process.exit(1);
19485
21481
  }
19486
21482
  });
19487
- cmd.command("list").description("List issues for an agent").requiredOption("--agent_id <id>", "Agent ID").option("--status <status>", `Filter by status (${VALID_STATUSES2.join(", ")})`).option("--completed", "Show completed/closed/canceled/failed issues").option("--all", "Show all issues").option("--json", "Output as JSON").action(async (opts, command) => {
21483
+ cmd.command("list").description("List issues for an agent").option("--agent_id <id>", "Agent ID").option("--status <status>", `Filter by status (${VALID_STATUSES2.join(", ")})`).option("--completed", "Show completed/closed/canceled/failed issues").option("--all", "Show all issues").option("--json", "Output as JSON").action(async (opts, command) => {
19488
21484
  if (opts.status && !VALID_STATUSES2.includes(opts.status)) {
19489
21485
  console.error(`Error: invalid status "${opts.status}"`);
19490
21486
  process.exit(1);
19491
21487
  }
19492
- const { serverUrl, token, workspaceId } = resolveClientOpts3(command, opts.agent_id);
21488
+ const agentId = resolveAgentId(opts);
21489
+ const { serverUrl, token, workspaceId } = resolveClientOpts3(command, agentId);
19493
21490
  const client = new APIClient(serverUrl, token, workspaceId);
19494
- const params = new URLSearchParams({ agentId: opts.agent_id });
21491
+ const params = new URLSearchParams({ agentId });
19495
21492
  if (opts.status)
19496
21493
  params.set("status", opts.status);
19497
21494
  if (!opts.all && !opts.status)
@@ -19511,13 +21508,14 @@ function issueCommand() {
19511
21508
  process.exit(1);
19512
21509
  }
19513
21510
  });
19514
- cmd.command("show").description("Show issue details and conversation").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--issue_id <id>", "Issue ID").option("--json", "Output as JSON").action(async (opts, command) => {
19515
- const { serverUrl, token, workspaceId } = resolveClientOpts3(command, opts.agent_id);
21511
+ cmd.command("show").description("Show issue details and conversation").option("--agent_id <id>", "Agent ID").requiredOption("--issue_id <id>", "Issue ID").option("--json", "Output as JSON").action(async (opts, command) => {
21512
+ const agentId = resolveAgentId(opts);
21513
+ const { serverUrl, token, workspaceId } = resolveClientOpts3(command, agentId);
19516
21514
  const client = new APIClient(serverUrl, token, workspaceId);
19517
21515
  try {
19518
- const res = await client.getJSON(`/api/issues/${opts.issue_id}?agentId=${encodeURIComponent(opts.agent_id)}`);
19519
- if (res.issue.agent_id !== opts.agent_id) {
19520
- console.error(`Error: issue ${res.issue.id} does not belong to agent ${opts.agent_id}`);
21516
+ const res = await client.getJSON(`/api/issues/${opts.issue_id}?agentId=${encodeURIComponent(agentId)}`);
21517
+ if (res.issue.agent_id !== agentId) {
21518
+ console.error(`Error: issue ${res.issue.id} does not belong to agent ${agentId}`);
19521
21519
  process.exit(1);
19522
21520
  }
19523
21521
  if (opts.json)
@@ -19528,7 +21526,7 @@ function issueCommand() {
19528
21526
  process.exit(1);
19529
21527
  }
19530
21528
  });
19531
- cmd.command("update").description("Update issue status or text").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--issue_id <id>", "Issue ID").option("--status <status>", `New status (${VALID_STATUSES2.join(", ")})`).option("--title <title>", "New title").option("--description <text>", "New description").option("--body-file <path>", "Read description from a file").option("--json", "Output as JSON").action(async (opts, command) => {
21529
+ cmd.command("update").description("Update issue status or text").option("--agent_id <id>", "Agent ID").requiredOption("--issue_id <id>", "Issue ID").option("--status <status>", `New status (${VALID_STATUSES2.join(", ")})`).option("--title <title>", "New title").option("--description <text>", "New description").option("--body-file <path>", "Read description from a file").option("--json", "Output as JSON").action(async (opts, command) => {
19532
21530
  if (opts.status && !VALID_STATUSES2.includes(opts.status)) {
19533
21531
  console.error(`Error: invalid status "${opts.status}"`);
19534
21532
  process.exit(1);
@@ -19545,10 +21543,11 @@ function issueCommand() {
19545
21543
  console.error("Error: pass at least one of --status, --title, --description, --body-file");
19546
21544
  process.exit(1);
19547
21545
  }
19548
- const { serverUrl, token, workspaceId } = resolveClientOpts3(command, opts.agent_id);
21546
+ const agentId = resolveAgentId(opts);
21547
+ const { serverUrl, token, workspaceId } = resolveClientOpts3(command, agentId);
19549
21548
  const client = new APIClient(serverUrl, token, workspaceId);
19550
21549
  try {
19551
- const issue3 = await client.patchJSON(`/api/issues/${opts.issue_id}?agentId=${encodeURIComponent(opts.agent_id)}`, body);
21550
+ const issue3 = await client.patchJSON(`/api/issues/${opts.issue_id}?agentId=${encodeURIComponent(agentId)}`, body);
19552
21551
  if (opts.json)
19553
21552
  return printJSON(issue3);
19554
21553
  printIssue(issue3);
@@ -19557,16 +21556,17 @@ function issueCommand() {
19557
21556
  process.exit(1);
19558
21557
  }
19559
21558
  });
19560
- cmd.command("comment").description("Append a comment to an issue").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--issue_id <id>", "Issue ID").option("--body <text>", "Comment text").option("--body-file <path>", "Read comment from a file").option("--json", "Output as JSON").action(async (opts, command) => {
21559
+ cmd.command("comment").description("Append a comment to an issue").option("--agent_id <id>", "Agent ID").requiredOption("--issue_id <id>", "Issue ID").option("--body <text>", "Comment text").option("--body-file <path>", "Read comment from a file").option("--json", "Output as JSON").action(async (opts, command) => {
19561
21560
  const content = readBody({ body: opts.body, bodyFile: opts.bodyFile }).trim();
19562
21561
  if (!content) {
19563
21562
  console.error("Error: pass --body or --body-file");
19564
21563
  process.exit(1);
19565
21564
  }
19566
- const { serverUrl, token, workspaceId } = resolveClientOpts3(command, opts.agent_id);
21565
+ const agentId = resolveAgentId(opts);
21566
+ const { serverUrl, token, workspaceId } = resolveClientOpts3(command, agentId);
19567
21567
  const client = new APIClient(serverUrl, token, workspaceId);
19568
21568
  try {
19569
- const res = await client.postJSON(`/api/issues/${opts.issue_id}/comments?agentId=${encodeURIComponent(opts.agent_id)}`, { content });
21569
+ const res = await client.postJSON(`/api/issues/${opts.issue_id}/comments?agentId=${encodeURIComponent(agentId)}`, { content });
19570
21570
  if (opts.json)
19571
21571
  return printJSON(res);
19572
21572
  console.log(`Commented on ${opts.issue_id}`);
@@ -19625,7 +21625,7 @@ ${result.output}`);
19625
21625
 
19626
21626
  // commands/sync.ts
19627
21627
  import { Command as Command10 } from "commander";
19628
- import { readFileSync as readFileSync9 } from "fs";
21628
+ import { readFileSync as readFileSync10 } from "fs";
19629
21629
  import { basename as basename2 } from "path";
19630
21630
  var MIME_BY_EXT2 = {
19631
21631
  ".pdf": "application/pdf",
@@ -19668,12 +21668,13 @@ function resolveClientOpts4(command, agentId) {
19668
21668
  }
19669
21669
  function syncCommand() {
19670
21670
  const cmd = new Command10("sync").description("File sync utilities");
19671
- cmd.command("upload-artifact").description("Upload a file artifact to a conversation").requiredOption("--agent_id <id>", "Agent ID").requiredOption("--conversation_id <id>", "Conversation ID").requiredOption("--file <path>", "Path to file to upload").action(async (opts, command) => {
19672
- const { serverUrl, token, workspaceId } = resolveClientOpts4(command, opts.agent_id);
21671
+ cmd.command("upload-artifact").description("Upload a file artifact to a conversation").option("--agent_id <id>", "Agent ID").requiredOption("--conversation_id <id>", "Conversation ID").requiredOption("--file <path>", "Path to file to upload").action(async (opts, command) => {
21672
+ const agentId = resolveAgentId(opts);
21673
+ const { serverUrl, token, workspaceId } = resolveClientOpts4(command, agentId);
19673
21674
  const client = new APIClient(serverUrl, token, workspaceId);
19674
21675
  let bytes;
19675
21676
  try {
19676
- bytes = readFileSync9(opts.file);
21677
+ bytes = readFileSync10(opts.file);
19677
21678
  } catch (err) {
19678
21679
  console.error(`Error: cannot read file "${opts.file}": ${err.message}`);
19679
21680
  process.exit(1);
@@ -19682,7 +21683,7 @@ function syncCommand() {
19682
21683
  const contentType = guessContentType2(filename);
19683
21684
  const form = new FormData;
19684
21685
  form.append("file", new Blob([new Uint8Array(bytes)], { type: contentType }), filename);
19685
- form.append("agent_id", opts.agent_id);
21686
+ form.append("agent_id", agentId);
19686
21687
  form.append("conversation_id", opts.conversation_id);
19687
21688
  try {
19688
21689
  const result = await client.postMultipart("/api/artifacts/upload", form);