@mndrk/agx 1.4.29 → 1.4.32

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 (231) hide show
  1. package/README.md +83 -54
  2. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/BUILD_ID +1 -1
  3. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/app-build-manifest.json +97 -76
  4. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/app-path-routes-manifest.json +20 -17
  5. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/build-manifest.json +2 -2
  6. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/prerender-manifest.json +18 -18
  7. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/routes-manifest.json +8 -0
  8. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/_not-found/page.js +7 -2
  9. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/_not-found/page.js.nft.json +1 -1
  10. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  11. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/_not-found.html +1 -1
  12. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/_not-found.rsc +16 -15
  13. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/audit/route_client-reference-manifest.js +1 -1
  14. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/[...nextauth]/route_client-reference-manifest.js +1 -1
  15. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/daemon-secret/route_client-reference-manifest.js +1 -1
  16. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/device/code/route_client-reference-manifest.js +1 -1
  17. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/device/token/route_client-reference-manifest.js +1 -1
  18. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/refresh/route_client-reference-manifest.js +1 -1
  19. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  20. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/domains/[id]/route.js +1 -0
  21. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/domains/[id]/route.js.nft.json +1 -0
  22. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/domains/[id]/route_client-reference-manifest.js +1 -0
  23. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/domains/route.js +1 -0
  24. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/domains/route.js.nft.json +1 -0
  25. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/domains/route_client-reference-manifest.js +1 -0
  26. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/health/route.js +1 -0
  27. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/health/route.js.nft.json +1 -0
  28. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/health/route_client-reference-manifest.js +1 -0
  29. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/learnings/route_client-reference-manifest.js +1 -1
  30. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/logs/stream/route_client-reference-manifest.js +1 -1
  31. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/orchestrator/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
  32. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/orchestrator/tasks/[taskId]/signal/route_client-reference-manifest.js +1 -1
  33. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/orchestrator/tasks/[taskId]/start/route_client-reference-manifest.js +1 -1
  34. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/orchestrator/tasks/[taskId]/status/route_client-reference-manifest.js +1 -1
  35. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/projects/[id]/route.js +1 -1
  36. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/projects/[id]/route_client-reference-manifest.js +1 -1
  37. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/projects/route.js +1 -1
  38. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  39. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/providers/route_client-reference-manifest.js +1 -1
  40. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/queue/complete/route.js +4 -1
  41. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/queue/complete/route_client-reference-manifest.js +1 -1
  42. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/queue/route_client-reference-manifest.js +1 -1
  43. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/stage-prompts/route_client-reference-manifest.js +1 -1
  44. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/comments/[commentId]/route_client-reference-manifest.js +1 -1
  45. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/comments/route_client-reference-manifest.js +1 -1
  46. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/heartbeat/route_client-reference-manifest.js +1 -1
  47. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/history/route_client-reference-manifest.js +1 -1
  48. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/logs/route.js +1 -1
  49. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/logs/route_client-reference-manifest.js +1 -1
  50. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/route_client-reference-manifest.js +1 -1
  51. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/route_client-reference-manifest.js +1 -1
  52. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/stream/route_client-reference-manifest.js +1 -1
  53. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/user-settings/route_client-reference-manifest.js +1 -1
  54. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/workflows/[id]/nodes/route_client-reference-manifest.js +1 -1
  55. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/workflows/[id]/route_client-reference-manifest.js +1 -1
  56. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/workflows/route_client-reference-manifest.js +1 -1
  57. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/callback/route_client-reference-manifest.js +1 -1
  58. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/device/page.js +10 -5
  59. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/device/page.js.nft.json +1 -1
  60. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/device/page_client-reference-manifest.js +1 -1
  61. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/device.html +1 -1
  62. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/device.rsc +20 -19
  63. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/dashboard/page.js +2 -2
  64. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/dashboard/page.js.nft.json +1 -1
  65. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/dashboard/page_client-reference-manifest.js +1 -1
  66. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/dashboard.html +1 -1
  67. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/dashboard.rsc +20 -19
  68. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/index.html +1 -1
  69. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/index.rsc +25 -23
  70. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/login/page.js +7 -2
  71. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/login/page.js.nft.json +1 -1
  72. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/login/page_client-reference-manifest.js +1 -1
  73. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/login.html +1 -1
  74. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/login.rsc +20 -19
  75. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/page.js +7 -2
  76. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/page.js.nft.json +1 -1
  77. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/page_client-reference-manifest.js +1 -1
  78. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/[slug]/page.js +6 -5
  79. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/[slug]/page.js.nft.json +1 -1
  80. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
  81. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/[slug]/tasks/page.js +2 -2
  82. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/[slug]/tasks/page.js.nft.json +1 -1
  83. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/[slug]/tasks/page_client-reference-manifest.js +1 -1
  84. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/[slug]/workflow/page.js +7 -2
  85. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/[slug]/workflow/page.js.nft.json +1 -1
  86. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/[slug]/workflow/page_client-reference-manifest.js +1 -1
  87. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/page.js +2 -2
  88. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/page.js.nft.json +1 -1
  89. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  90. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects.html +1 -1
  91. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects.rsc +20 -19
  92. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/settings/page.js +7 -2
  93. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/settings/page.js.nft.json +1 -1
  94. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  95. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/settings.html +1 -1
  96. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/settings.rsc +20 -19
  97. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app-paths-manifest.json +20 -17
  98. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/chunks/2298.js +1 -1
  99. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/chunks/{8361.js → 3224.js} +3 -3
  100. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/chunks/7143.js +1 -4
  101. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/chunks/9773.js +6 -0
  102. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/middleware-manifest.json +5 -5
  103. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/pages/404.html +1 -1
  104. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/pages/500.html +1 -1
  105. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/server-reference-manifest.js +1 -1
  106. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/server-reference-manifest.json +1 -1
  107. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/8HkVSFiL4He2WYQOlxNL4/_buildManifest.js +1 -0
  108. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/{2456-5577fa071bb78cca.js → 2456-fb622a24e9609222.js} +1 -1
  109. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/_error.js +28 -0
  110. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/audit/route-99c56d5659a15bdb.js +1 -0
  111. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/auth/[...nextauth]/route-99c56d5659a15bdb.js +1 -0
  112. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/auth/daemon-secret/route-99c56d5659a15bdb.js +1 -0
  113. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/auth/device/code/route-99c56d5659a15bdb.js +1 -0
  114. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/auth/device/token/route-99c56d5659a15bdb.js +1 -0
  115. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/auth/refresh/route-99c56d5659a15bdb.js +1 -0
  116. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/auth/status/route-99c56d5659a15bdb.js +1 -0
  117. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/domains/[id]/route-99c56d5659a15bdb.js +1 -0
  118. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/domains/route-99c56d5659a15bdb.js +1 -0
  119. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/health/route-99c56d5659a15bdb.js +1 -0
  120. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/learnings/route-99c56d5659a15bdb.js +1 -0
  121. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/logs/stream/route-99c56d5659a15bdb.js +1 -0
  122. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/orchestrator/tasks/[taskId]/cancel/route-99c56d5659a15bdb.js +1 -0
  123. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/orchestrator/tasks/[taskId]/signal/route-99c56d5659a15bdb.js +1 -0
  124. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/orchestrator/tasks/[taskId]/start/route-99c56d5659a15bdb.js +1 -0
  125. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/orchestrator/tasks/[taskId]/status/route-99c56d5659a15bdb.js +1 -0
  126. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/projects/[id]/route-99c56d5659a15bdb.js +1 -0
  127. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/projects/route-99c56d5659a15bdb.js +1 -0
  128. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/providers/route-99c56d5659a15bdb.js +1 -0
  129. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/queue/complete/route-99c56d5659a15bdb.js +1 -0
  130. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/queue/route-99c56d5659a15bdb.js +1 -0
  131. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/stage-prompts/route-99c56d5659a15bdb.js +1 -0
  132. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/tasks/[id]/comments/[commentId]/route-99c56d5659a15bdb.js +1 -0
  133. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/tasks/[id]/comments/route-99c56d5659a15bdb.js +1 -0
  134. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/tasks/[id]/heartbeat/route-99c56d5659a15bdb.js +1 -0
  135. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/tasks/[id]/history/route-99c56d5659a15bdb.js +1 -0
  136. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/tasks/[id]/logs/route-99c56d5659a15bdb.js +1 -0
  137. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/tasks/[id]/route-99c56d5659a15bdb.js +1 -0
  138. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/tasks/route-99c56d5659a15bdb.js +1 -0
  139. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/tasks/stream/route-99c56d5659a15bdb.js +1 -0
  140. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/user-settings/route-99c56d5659a15bdb.js +1 -0
  141. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/workflows/[id]/nodes/route-99c56d5659a15bdb.js +1 -0
  142. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/workflows/[id]/route-99c56d5659a15bdb.js +1 -0
  143. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/workflows/route-99c56d5659a15bdb.js +1 -0
  144. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/auth/callback/route-99c56d5659a15bdb.js +1 -0
  145. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/auth/device/page-16376ef566a9794d.js +1 -0
  146. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/layout-a88b659f348808e1.js +1 -0
  147. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/projects/[slug]/layout-11d4290500b37271.js +1 -0
  148. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/projects/[slug]/page-98b32955971a9b89.js +1 -0
  149. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/fallback/amp.js +1015 -0
  150. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/fallback/main-app.js +1893 -0
  151. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/fallback/main.js +1616 -0
  152. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/fallback/pages/_app.js +28 -0
  153. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/fallback/pages/_error.js +28 -0
  154. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/fallback/react-refresh.js +62 -0
  155. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/fallback/webpack.js +1368 -0
  156. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/main.js +1616 -0
  157. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/pages/_app.js +28 -0
  158. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/pages/_error.js +28 -0
  159. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/polyfills.js +1 -0
  160. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/react-refresh.js +62 -0
  161. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/webpack.js +1363 -0
  162. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/css/684e3dda28b1eb43.css +1 -0
  163. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/development/_buildManifest.js +1 -0
  164. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/development/_ssgManifest.js +1 -0
  165. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/webpack/4b08482d088962b1.webpack.hot-update.json +1 -0
  166. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/webpack/webpack.4b08482d088962b1.hot-update.js +12 -0
  167. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/worker/index.js +16 -20
  168. package/index.js +9 -8188
  169. package/lib/cli/cloud/command.js +25 -10
  170. package/lib/cli/cloud/executeVerifySingle.js +16 -0
  171. package/lib/cli/cloud/executeVerifySwarm.js +16 -0
  172. package/lib/cli/cloud/iterations.js +6 -2
  173. package/lib/cli/cloud/taskLogger.js +79 -10
  174. package/lib/cli/cloudArtifacts.js +2 -1
  175. package/lib/cli/daemon.js +48 -32
  176. package/lib/cli/interactiveMenu.js +11 -9
  177. package/lib/cli/providers.js +26 -19
  178. package/lib/cli/runCli.js +675 -644
  179. package/lib/commands/daemonBoard.js +9 -9
  180. package/lib/executor.js +4 -11
  181. package/lib/orchestrator/httpClient.js +6 -2
  182. package/lib/proc/ProcessManager.js +197 -0
  183. package/lib/proc/commandExists.js +4 -4
  184. package/lib/proc/killProcessTree.js +157 -0
  185. package/lib/proc/spawnCloudTaskProcess.js +32 -5
  186. package/lib/prompts/cloudTask.js +72 -23
  187. package/lib/storage/paths.js +3 -0
  188. package/lib/storage/runs.js +2 -1
  189. package/lib/verifier.js +10 -9
  190. package/package.json +2 -1
  191. package/templates/stack/postgres/init/001_agx_board_schema.sql +17 -0
  192. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/chunks/6125.js +0 -1
  193. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/M4AQWpnhTFqFD3HFlSHd9/_buildManifest.js +0 -1
  194. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/audit/route-a73121242529c10c.js +0 -1
  195. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/auth/[...nextauth]/route-a73121242529c10c.js +0 -1
  196. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/auth/daemon-secret/route-a73121242529c10c.js +0 -1
  197. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/auth/device/code/route-a73121242529c10c.js +0 -1
  198. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/auth/device/token/route-a73121242529c10c.js +0 -1
  199. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/auth/refresh/route-a73121242529c10c.js +0 -1
  200. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/auth/status/route-a73121242529c10c.js +0 -1
  201. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/learnings/route-a73121242529c10c.js +0 -1
  202. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/logs/stream/route-a73121242529c10c.js +0 -1
  203. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/orchestrator/tasks/[taskId]/cancel/route-a73121242529c10c.js +0 -1
  204. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/orchestrator/tasks/[taskId]/signal/route-a73121242529c10c.js +0 -1
  205. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/orchestrator/tasks/[taskId]/start/route-a73121242529c10c.js +0 -1
  206. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/orchestrator/tasks/[taskId]/status/route-a73121242529c10c.js +0 -1
  207. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/projects/[id]/route-a73121242529c10c.js +0 -1
  208. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/projects/route-a73121242529c10c.js +0 -1
  209. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/providers/route-a73121242529c10c.js +0 -1
  210. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/queue/complete/route-a73121242529c10c.js +0 -1
  211. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/queue/route-a73121242529c10c.js +0 -1
  212. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/stage-prompts/route-a73121242529c10c.js +0 -1
  213. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/tasks/[id]/comments/[commentId]/route-a73121242529c10c.js +0 -1
  214. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/tasks/[id]/comments/route-a73121242529c10c.js +0 -1
  215. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/tasks/[id]/heartbeat/route-a73121242529c10c.js +0 -1
  216. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/tasks/[id]/history/route-a73121242529c10c.js +0 -1
  217. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/tasks/[id]/logs/route-a73121242529c10c.js +0 -1
  218. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/tasks/[id]/route-a73121242529c10c.js +0 -1
  219. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/tasks/route-a73121242529c10c.js +0 -1
  220. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/tasks/stream/route-a73121242529c10c.js +0 -1
  221. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/user-settings/route-a73121242529c10c.js +0 -1
  222. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/workflows/[id]/nodes/route-a73121242529c10c.js +0 -1
  223. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/workflows/[id]/route-a73121242529c10c.js +0 -1
  224. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/api/workflows/route-a73121242529c10c.js +0 -1
  225. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/auth/callback/route-a73121242529c10c.js +0 -1
  226. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/auth/device/page-e2c2560ec12b421d.js +0 -1
  227. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/layout-2d6cff09e6c1e2b2.js +0 -1
  228. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/projects/[slug]/layout-c77e54e6c377c70a.js +0 -1
  229. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/projects/[slug]/page-253ca8286e8f1d68.js +0 -1
  230. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/css/72371329e4c91108.css +0 -1
  231. /package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/{M4AQWpnhTFqFD3HFlSHd9 → 8HkVSFiL4He2WYQOlxNL4}/_ssgManifest.js +0 -0
package/lib/cli/runCli.js CHANGED
@@ -21,7 +21,7 @@
21
21
  // → spawns: agx <provider> --continue <task>
22
22
  // ============================================================
23
23
 
24
- const { spawn, spawnSync, execSync } = require('child_process');
24
+ const execa = require('execa');
25
25
  const pMap = require('p-map');
26
26
  const pRetry = require("p-retry");
27
27
  const pRetryFn = pRetry.default || pRetry;
@@ -37,6 +37,8 @@ const { loadCloudConfigFile, saveCloudConfigFile, clearCloudConfig } = require('
37
37
  const { truncateForComment, cleanAgentOutputForComment, extractFileRefsFromText } = require('../ui/text');
38
38
  const { commandExists } = require('../proc/commandExists');
39
39
  const { spawnCloudTaskProcess } = require('../proc/spawnCloudTaskProcess');
40
+ const { scheduleTermination } = require('../proc/killProcessTree');
41
+ const { getProcessManager } = require('../proc/ProcessManager');
40
42
  const { createCloudClient } = require('../cloud/client');
41
43
  const { buildContinueCloudTaskPrompt, buildNewAutonomousCloudTaskPrompt } = require('../prompts/cloudTask');
42
44
  const {
@@ -132,9 +134,11 @@ const {
132
134
  createDaemonArtifactsRecorder,
133
135
  buildLocalRunIndexEntry,
134
136
  saveAugmentedPrompt,
137
+ extractSection,
135
138
  buildFullDaemonPromptContext,
136
139
  resolveTaskTicketType,
137
140
  parseList,
141
+ localArtifactKey,
138
142
  } = cloudArtifacts;
139
143
 
140
144
  // Config paths
@@ -244,6 +248,7 @@ const cloudRunner = createCloudRunner({
244
248
  fetch: globalThis.fetch,
245
249
 
246
250
  // config + transport
251
+ loadConfig,
247
252
  loadCloudConfigFile,
248
253
  postTaskLog,
249
254
  postTaskComment,
@@ -252,6 +257,8 @@ const cloudRunner = createCloudRunner({
252
257
  sanitizeCliArgs,
253
258
  commandExists,
254
259
  spawnCloudTaskProcess,
260
+ scheduleTermination,
261
+ getProcessManager,
255
262
  pMap,
256
263
  pRetryFn,
257
264
 
@@ -691,66 +698,66 @@ async function checkOnboarding() {
691
698
  console.log(`${c.green}✓${c.reset} Running task inline`);
692
699
  console.log(`${c.dim}Task: ${taskId}${c.reset}`);
693
700
 
694
- const decisionPayload = await runCloudDaemonTask(effectiveTask);
695
- // Inline run: always print the explanation so failures are actionable.
696
- if (decisionPayload?.decision && decisionPayload.decision !== 'done') {
697
- const detail = String(decisionPayload.summary || decisionPayload.explanation || '').trim();
698
- if (detail) {
699
- console.error(`${c.red}✗${c.reset} ${decisionPayload.decision}: ${detail}`);
700
- } else {
701
- console.error(`${c.red}✗${c.reset} ${decisionPayload.decision}`);
702
- }
703
- }
704
- const decision = String(decisionPayload?.decision || 'failed').toLowerCase();
705
- return decision === 'done' ? 0 : 1;
706
- }
707
-
708
- function normalizeDaemonDecision(decision, fallbackSummary = '', extra = {}) {
709
- const allowed = new Set(['done', 'blocked', 'not_done', 'failed']);
710
- const extractedDecision = typeof decision?.decision === 'string' ? decision.decision.trim() : '';
711
- const normalizedDecision = allowed.has(extractedDecision) ? extractedDecision : 'failed';
712
-
713
- const extraErr = typeof extra?.error === 'string' && extra.error.trim() ? extra.error.trim() : '';
714
- const explanation = typeof decision?.explanation === 'string' && decision.explanation.trim()
715
- ? decision.explanation.trim()
716
- : (extraErr || fallbackSummary || `Daemon decision: ${normalizedDecision}`);
717
- const finalResult = typeof decision?.final_result === 'string' && decision.final_result.trim()
718
- ? decision.final_result.trim()
719
- : explanation;
720
- const summary = typeof decision?.summary === 'string' && decision.summary.trim()
721
- ? decision.summary.trim()
722
- : (extraErr || '');
723
-
724
- return {
725
- decision: normalizedDecision,
726
- explanation,
727
- final_result: finalResult,
728
- summary,
729
- };
730
- }
731
-
732
- async function runCloudDaemonTask(task) {
733
- const { buildCloudTaskTerminalPatch } = require('../cloud/status');
734
-
735
- const taskId = String(task?.id || '').trim();
736
- if (!taskId) {
737
- throw new Error('Queue returned task without id');
738
- }
739
-
740
- const provider = String(task?.provider || task?.engine || 'claude').toLowerCase();
741
- const model = typeof task?.model === 'string' && task.model.trim() ? task.model.trim() : null;
742
- const logger = createTaskLogger(taskId);
743
- const localArtifacts = isLocalArtifactsEnabled();
744
- const storage = localArtifacts ? require('../storage') : null;
745
- const stageLocal = mapCloudStageToLocalStage(task?.stage);
746
- let projectSlug = null;
747
- let taskSlug = null;
748
- const orchestrator = getOrchestrator();
749
- const cancellationWatcher = createCancellationWatcher({ orchestrator, taskId });
750
-
751
- let lockHandle = null;
752
- let lastRun = null;
753
- let runIndexEntry = null;
701
+ const decisionPayload = await runCloudDaemonTask(effectiveTask);
702
+ // Inline run: always print the explanation so failures are actionable.
703
+ if (decisionPayload?.decision && decisionPayload.decision !== 'done') {
704
+ const detail = String(decisionPayload.summary || decisionPayload.explanation || '').trim();
705
+ if (detail) {
706
+ console.error(`${c.red}✗${c.reset} ${decisionPayload.decision}: ${detail}`);
707
+ } else {
708
+ console.error(`${c.red}✗${c.reset} ${decisionPayload.decision}`);
709
+ }
710
+ }
711
+ const decision = String(decisionPayload?.decision || 'failed').toLowerCase();
712
+ return decision === 'done' ? 0 : 1;
713
+ }
714
+
715
+ function normalizeDaemonDecision(decision, fallbackSummary = '', extra = {}) {
716
+ const allowed = new Set(['done', 'blocked', 'not_done', 'failed']);
717
+ const extractedDecision = typeof decision?.decision === 'string' ? decision.decision.trim() : '';
718
+ const normalizedDecision = allowed.has(extractedDecision) ? extractedDecision : 'failed';
719
+
720
+ const extraErr = typeof extra?.error === 'string' && extra.error.trim() ? extra.error.trim() : '';
721
+ const explanation = typeof decision?.explanation === 'string' && decision.explanation.trim()
722
+ ? decision.explanation.trim()
723
+ : (extraErr || fallbackSummary || `Daemon decision: ${normalizedDecision}`);
724
+ const finalResult = typeof decision?.final_result === 'string' && decision.final_result.trim()
725
+ ? decision.final_result.trim()
726
+ : explanation;
727
+ const summary = typeof decision?.summary === 'string' && decision.summary.trim()
728
+ ? decision.summary.trim()
729
+ : (extraErr || '');
730
+
731
+ return {
732
+ decision: normalizedDecision,
733
+ explanation,
734
+ final_result: finalResult,
735
+ summary,
736
+ };
737
+ }
738
+
739
+ async function runCloudDaemonTask(task) {
740
+ const { buildCloudTaskTerminalPatch } = require('../cloud/status');
741
+
742
+ const taskId = String(task?.id || '').trim();
743
+ if (!taskId) {
744
+ throw new Error('Queue returned task without id');
745
+ }
746
+
747
+ const provider = String(task?.provider || task?.engine || 'claude').toLowerCase();
748
+ const model = typeof task?.model === 'string' && task.model.trim() ? task.model.trim() : null;
749
+ const logger = createTaskLogger(taskId);
750
+ const localArtifacts = isLocalArtifactsEnabled();
751
+ const storage = localArtifacts ? require('../storage') : null;
752
+ const stageLocal = mapCloudStageToLocalStage(task?.stage);
753
+ let projectSlug = null;
754
+ let taskSlug = null;
755
+ const orchestrator = getOrchestrator();
756
+ const cancellationWatcher = createCancellationWatcher({ orchestrator, taskId });
757
+
758
+ let lockHandle = null;
759
+ let lastRun = null;
760
+ let runIndexEntry = null;
754
761
 
755
762
  logger.log('system', `[daemon] picked task ${taskId} (${task?.stage || 'unknown'})\n`);
756
763
  console.log(`${c.dim}[daemon] picked ${taskId} (${task?.stage || 'unknown'}) via ${provider}${model ? `/${model}` : ''}${c.reset}`);
@@ -836,19 +843,19 @@ async function checkOnboarding() {
836
843
 
837
844
  // Execute+verify loop runs per-iteration local runs under the mapped cloud stage.
838
845
  let loopResult;
839
- if (task?.swarm) {
840
- loopResult = await runSwarmExecuteVerifyLoop({
841
- taskId,
842
- task,
843
- logger,
844
- storage,
845
- projectSlug,
846
- taskSlug,
847
- stageLocal,
848
- initialPromptContext: fullPromptContext,
849
- cancellationWatcher,
850
- });
851
- } else {
846
+ if (task?.swarm) {
847
+ loopResult = await runSwarmExecuteVerifyLoop({
848
+ taskId,
849
+ task,
850
+ logger,
851
+ storage,
852
+ projectSlug,
853
+ taskSlug,
854
+ stageLocal,
855
+ initialPromptContext: fullPromptContext,
856
+ cancellationWatcher,
857
+ });
858
+ } else {
852
859
  loopResult = await runSingleAgentExecuteVerifyLoop({
853
860
  taskId,
854
861
  task,
@@ -866,20 +873,20 @@ async function checkOnboarding() {
866
873
 
867
874
  lastRun = loopResult?.lastRun || null;
868
875
  runIndexEntry = loopResult?.runIndexEntry || null;
869
- decisionPayload = normalizeDaemonDecision(
870
- loopResult?.decision,
871
- loopResult?.code === 0 ? 'Execution completed.' : 'Execution failed.',
872
- { error: task?.error || '' }
873
- );
876
+ decisionPayload = normalizeDaemonDecision(
877
+ loopResult?.decision,
878
+ loopResult?.code === 0 ? 'Execution completed.' : 'Execution failed.',
879
+ { error: task?.error || '' }
880
+ );
874
881
  } else {
875
882
  // Fallback: cloud-only execution path (legacy).
876
883
  if (task?.swarm) {
877
- runResult = await runSwarmLoop({ taskId, task, artifacts: null, cancellationWatcher });
878
- decisionPayload = normalizeDaemonDecision(
879
- runResult?.decision,
880
- runResult?.code === 0 ? 'Swarm execution completed.' : 'Swarm execution failed.',
881
- { error: task?.error || '' }
882
- );
884
+ runResult = await runSwarmLoop({ taskId, task, artifacts: null, cancellationWatcher });
885
+ decisionPayload = normalizeDaemonDecision(
886
+ runResult?.decision,
887
+ runResult?.code === 0 ? 'Swarm execution completed.' : 'Swarm execution failed.',
888
+ { error: task?.error || '' }
889
+ );
883
890
  } else {
884
891
  runResult = await runSingleAgentLoop({
885
892
  taskId,
@@ -890,36 +897,36 @@ async function checkOnboarding() {
890
897
  artifacts: null,
891
898
  cancellationWatcher,
892
899
  });
893
- decisionPayload = normalizeDaemonDecision(
894
- runResult?.decision,
895
- runResult?.code === 0 ? 'Single-agent execution completed.' : 'Single-agent execution failed.',
896
- { error: task?.error || '' }
897
- );
900
+ decisionPayload = normalizeDaemonDecision(
901
+ runResult?.decision,
902
+ runResult?.code === 0 ? 'Single-agent execution completed.' : 'Single-agent execution failed.',
903
+ { error: task?.error || '' }
904
+ );
898
905
  }
899
906
  }
900
- } catch (err) {
901
- const message = err?.message || 'Daemon execution failed.';
902
- // This error is in the daemon process (not the spawned agx subprocess), so also write it
903
- // to the run container when local artifacts are enabled.
904
- if (localArtifacts && lastRun?.paths?.root) {
905
- const runContainerPath = path.dirname(lastRun.paths.root);
906
- const detail = err?.stack || message;
907
- await appendRunContainerLog(runContainerPath, 'daemon/daemon_error.log', `[${new Date().toISOString()}] ${detail}`);
908
- }
909
- decisionPayload = {
910
- decision: 'failed',
911
- explanation: message,
912
- final_result: message,
913
- summary: message,
914
- };
915
- logger.log('error', `[daemon] execution failed: ${message}\n`);
916
- } finally {
917
- await logger.flushAll();
918
- try { cancellationWatcher?.destroy?.(); } catch { }
919
- if (localArtifacts) {
920
- try {
921
- // Runs are finalized per-iteration inside the execute/verify loop.
922
- } catch (e) {
907
+ } catch (err) {
908
+ const message = err?.message || 'Daemon execution failed.';
909
+ // This error is in the daemon process (not the spawned agx subprocess), so also write it
910
+ // to the run container when local artifacts are enabled.
911
+ if (localArtifacts && lastRun?.paths?.root) {
912
+ const runContainerPath = path.dirname(lastRun.paths.root);
913
+ const detail = err?.stack || message;
914
+ await appendRunContainerLog(runContainerPath, 'daemon/daemon_error.log', `[${new Date().toISOString()}] ${detail}`);
915
+ }
916
+ decisionPayload = {
917
+ decision: 'failed',
918
+ explanation: message,
919
+ final_result: message,
920
+ summary: message,
921
+ };
922
+ logger.log('error', `[daemon] execution failed: ${message}\n`);
923
+ } finally {
924
+ await logger.flushAll();
925
+ try { cancellationWatcher?.destroy?.(); } catch { }
926
+ if (localArtifacts) {
927
+ try {
928
+ // Runs are finalized per-iteration inside the execute/verify loop.
929
+ } catch (e) {
923
930
  // Never break cloud completion because local artifacts failed.
924
931
  logger?.log('error', `[daemon] local artifact finalize failed: ${e?.message || e}\n`);
925
932
  } finally {
@@ -930,40 +937,40 @@ async function checkOnboarding() {
930
937
  }
931
938
  }
932
939
 
933
- const completionResult = await cloudRequest('POST', '/api/queue/complete', {
934
- taskId,
935
- log: decisionPayload.summary || decisionPayload.explanation,
936
- decision: decisionPayload.decision,
937
- final_result: decisionPayload.final_result,
940
+ const completionResult = await cloudRequest('POST', '/api/queue/complete', {
941
+ taskId,
942
+ log: decisionPayload.summary || decisionPayload.explanation,
943
+ decision: decisionPayload.decision,
944
+ final_result: decisionPayload.final_result,
938
945
  explanation: decisionPayload.explanation,
939
946
  ...(localArtifacts && lastRun?.paths?.root ? {
940
947
  artifact_path: lastRun.paths.root,
941
948
  artifact_host: os.hostname(),
942
949
  artifact_key: localArtifactKey(lastRun.paths.root),
943
950
  } : {}),
944
- ...(runIndexEntry ? { run_entry: runIndexEntry } : {}),
945
- });
946
-
947
- // Best-effort: ensure cloud task status is terminal when stage/decision indicates completion.
948
- // Some board runtimes advance `stage` to "done" but leave `status` as "in_progress".
949
- try {
950
- let newStage = completionResult?.newStage || completionResult?.task?.stage || null;
951
- if (!newStage) {
952
- try {
953
- const { task: refreshed } = await cloudRequest('GET', `/api/tasks/${taskId}`);
954
- newStage = refreshed?.stage || null;
955
- } catch { }
956
- }
957
- const patch = buildCloudTaskTerminalPatch({ decision: decisionPayload?.decision, newStage });
958
- if (patch) {
959
- await cloudRequest('PATCH', `/api/tasks/${taskId}`, patch);
960
- }
961
- } catch { }
962
-
963
- // Post a structured outcome comment (separate from queue completion log).
964
- await postTaskComment(taskId, [
965
- `## ${task?.stage || 'stage'} completed`,
966
- '',
951
+ ...(runIndexEntry ? { run_entry: runIndexEntry } : {}),
952
+ });
953
+
954
+ // Best-effort: ensure cloud task status is terminal when stage/decision indicates completion.
955
+ // Some board runtimes advance `stage` to "done" but leave `status` as "in_progress".
956
+ try {
957
+ let newStage = completionResult?.newStage || completionResult?.task?.stage || null;
958
+ if (!newStage) {
959
+ try {
960
+ const { task: refreshed } = await cloudRequest('GET', `/api/tasks/${taskId}`);
961
+ newStage = refreshed?.stage || null;
962
+ } catch { }
963
+ }
964
+ const patch = buildCloudTaskTerminalPatch({ decision: decisionPayload?.decision, newStage });
965
+ if (patch) {
966
+ await cloudRequest('PATCH', `/api/tasks/${taskId}`, patch);
967
+ }
968
+ } catch { }
969
+
970
+ // Post a structured outcome comment (separate from queue completion log).
971
+ await postTaskComment(taskId, [
972
+ `## ${task?.stage || 'stage'} completed`,
973
+ '',
967
974
  `Decision: ${decisionPayload.decision}`,
968
975
  '',
969
976
  decisionPayload.summary || decisionPayload.explanation || '',
@@ -996,15 +1003,22 @@ async function checkOnboarding() {
996
1003
  const inFlight = new Map();
997
1004
  let stopping = false;
998
1005
 
1006
+ const pm = getProcessManager();
1007
+
999
1008
  const requestStop = () => {
1000
1009
  if (stopping) return;
1001
1010
  stopping = true;
1002
1011
  console.log(`\n${c.dim}[daemon] stopping... waiting for ${inFlight.size} active task(s)${c.reset}`);
1012
+ pm.killAll();
1003
1013
  };
1004
1014
 
1005
1015
  process.on('SIGINT', requestStop);
1006
1016
  process.on('SIGTERM', requestStop);
1007
1017
 
1018
+ // Periodic orphan heartbeat sweep
1019
+ const orphanSweep = setInterval(() => pm.sweepOrphanedHeartbeats(), 60_000);
1020
+ orphanSweep.unref();
1021
+
1008
1022
  console.log(`${c.green}✓${c.reset} Daemon loop started (workers=${maxWorkers}, poll=${pollMs}ms)`);
1009
1023
 
1010
1024
  while (!stopping) {
@@ -1557,14 +1571,14 @@ async function checkOnboarding() {
1557
1571
 
1558
1572
  console.log(`${c.bold}Tasks${c.reset} (${tasks.length})\n`);
1559
1573
  let idx = 1;
1560
- for (const task of tasks) {
1561
- const statusIcon = {
1562
- queued: c.yellow + '○' + c.reset,
1563
- in_progress: c.blue + '●' + c.reset,
1564
- blocked: c.yellow + '!' + c.reset,
1565
- completed: c.green + '✓' + c.reset,
1566
- failed: c.red + '✗' + c.reset,
1567
- }[task.status] || '?';
1574
+ for (const task of tasks) {
1575
+ const statusIcon = {
1576
+ queued: c.yellow + '○' + c.reset,
1577
+ in_progress: c.blue + '●' + c.reset,
1578
+ blocked: c.yellow + '!' + c.reset,
1579
+ completed: c.green + '✓' + c.reset,
1580
+ failed: c.red + '✗' + c.reset,
1581
+ }[task.status] || '?';
1568
1582
 
1569
1583
  console.log(` ${c.dim}${idx}.${c.reset} ${statusIcon} ${task.slug || 'task'}`);
1570
1584
  const displayProvider = task.swarm
@@ -1632,35 +1646,35 @@ async function checkOnboarding() {
1632
1646
  process.exit(0);
1633
1647
  }
1634
1648
 
1635
- const message = log || 'Stage completed via agx CLI';
1636
- const { task, newStage } = await cloudRequest('POST', '/api/queue/complete', {
1637
- taskId: resolvedTaskId,
1638
- log: message,
1639
- decision: 'done',
1640
- explanation: message,
1641
- final_result: message,
1642
- });
1643
- let stageAfter = newStage || task?.stage || null;
1644
- if (!stageAfter) {
1645
- try {
1646
- const { task: refreshed } = await cloudRequest('GET', `/api/tasks/${resolvedTaskId}`);
1647
- stageAfter = refreshed?.stage || null;
1648
- } catch { }
1649
- }
1650
-
1651
- // If this completion transitioned the task into a terminal stage, align `status` too.
1652
- try {
1653
- const patch = buildCloudTaskTerminalPatch({ newStage: stageAfter });
1654
- if (patch) {
1655
- await cloudRequest('PATCH', `/api/tasks/${resolvedTaskId}`, patch);
1656
- }
1657
- } catch { }
1658
-
1659
- console.log(`${c.green}✓${c.reset} Stage completed`);
1660
- console.log(` New stage: ${stageAfter || 'unknown'}`);
1661
- if (String(stageAfter || '').toLowerCase() === 'done') {
1662
- console.log(` ${c.green}Task is now complete!${c.reset}`);
1663
- }
1649
+ const message = log || 'Stage completed via agx CLI';
1650
+ const { task, newStage } = await cloudRequest('POST', '/api/queue/complete', {
1651
+ taskId: resolvedTaskId,
1652
+ log: message,
1653
+ decision: 'done',
1654
+ explanation: message,
1655
+ final_result: message,
1656
+ });
1657
+ let stageAfter = newStage || task?.stage || null;
1658
+ if (!stageAfter) {
1659
+ try {
1660
+ const { task: refreshed } = await cloudRequest('GET', `/api/tasks/${resolvedTaskId}`);
1661
+ stageAfter = refreshed?.stage || null;
1662
+ } catch { }
1663
+ }
1664
+
1665
+ // If this completion transitioned the task into a terminal stage, align `status` too.
1666
+ try {
1667
+ const patch = buildCloudTaskTerminalPatch({ newStage: stageAfter });
1668
+ if (patch) {
1669
+ await cloudRequest('PATCH', `/api/tasks/${resolvedTaskId}`, patch);
1670
+ }
1671
+ } catch { }
1672
+
1673
+ console.log(`${c.green}✓${c.reset} Stage completed`);
1674
+ console.log(` New stage: ${stageAfter || 'unknown'}`);
1675
+ if (String(stageAfter || '').toLowerCase() === 'done') {
1676
+ console.log(` ${c.green}Task is now complete!${c.reset}`);
1677
+ }
1664
1678
  } catch (err) {
1665
1679
  console.log(`${c.red}✗${c.reset} Failed: ${err.message}`);
1666
1680
  process.exit(1);
@@ -2160,9 +2174,12 @@ async function checkOnboarding() {
2160
2174
 
2161
2175
  // agx container ls (Docker-style namespace - list running daemons)
2162
2176
  if (cmd === 'container' && args[1] === 'ls') {
2163
- const { execSync } = require('child_process');
2164
2177
  try {
2165
- const result = execSync('pgrep -fl "agx.*daemon" 2>/dev/null || echo ""', { encoding: 'utf8' });
2178
+ const result = execa.commandSync('pgrep -fl "agx.*daemon" 2>/dev/null || echo \"\"', {
2179
+ shell: true,
2180
+ encoding: 'utf8',
2181
+ reject: false,
2182
+ }).stdout || '';
2166
2183
  if (result.trim()) {
2167
2184
  console.log(`${c.bold}Running Containers${c.reset}\n`);
2168
2185
  console.log(result.trim());
@@ -2216,13 +2233,18 @@ async function checkOnboarding() {
2216
2233
 
2217
2234
  // agx container stop (Docker-style namespace - stop daemon)
2218
2235
  if (cmd === 'container' && args[1] === 'stop') {
2219
- const { execSync } = require('child_process');
2220
2236
  try {
2221
- const result = execSync('pgrep -fl "agx.*daemon" 2>/dev/null || echo ""', { encoding: 'utf8' });
2237
+ const result = execa.commandSync('pgrep -fl "agx.*daemon" 2>/dev/null || echo \"\"', {
2238
+ shell: true,
2239
+ encoding: 'utf8',
2240
+ reject: false,
2241
+ }).stdout || '';
2222
2242
  if (result.trim()) {
2223
- const pids = result.trim().split('\n').map(line => line.split(' ')[0]);
2243
+ const pids = result.trim().split('\n').map(line => line.trim().split(/\s+/)[0]).filter(Boolean);
2224
2244
  for (const pid of pids) {
2225
- execSync(`kill ${pid}`, { encoding: 'utf8' });
2245
+ const n = Number.parseInt(pid, 10);
2246
+ if (!Number.isFinite(n) || n <= 0) continue;
2247
+ try { process.kill(n, 'SIGTERM'); } catch { }
2226
2248
  }
2227
2249
  console.log(`${c.green}✓${c.reset} Container(s) stopped`);
2228
2250
  } else {
@@ -2307,7 +2329,7 @@ async function checkOnboarding() {
2307
2329
  // Helper to get current crontab
2308
2330
  const getCrontab = () => {
2309
2331
  try {
2310
- return execSync('crontab -l 2>/dev/null', { encoding: 'utf8' });
2332
+ return execa.commandSync('crontab -l 2>/dev/null', { shell: true, encoding: 'utf8', reject: false }).stdout || '';
2311
2333
  } catch {
2312
2334
  return '';
2313
2335
  }
@@ -2318,9 +2340,9 @@ async function checkOnboarding() {
2318
2340
  const tmp = path.join(os.tmpdir(), `agx-crontab-${Date.now()}`);
2319
2341
  fs.writeFileSync(tmp, content);
2320
2342
  try {
2321
- execSync(`crontab ${tmp}`, { timeout: 5000 });
2343
+ execa.commandSync(`crontab ${tmp}`, { shell: true, timeout: 5000, reject: false });
2322
2344
  } finally {
2323
- try { fs.unlinkSync(tmp); } catch {}
2345
+ try { fs.unlinkSync(tmp); } catch { }
2324
2346
  }
2325
2347
  };
2326
2348
 
@@ -2374,11 +2396,13 @@ async function checkOnboarding() {
2374
2396
  // Default: update now
2375
2397
  console.log(`${c.cyan}→${c.reset} Checking for updates...`);
2376
2398
  try {
2377
- const result = spawnSync('npm', ['update', '-g', '@mndrk/agx'], {
2399
+ const child = execa('npm', ['update', '-g', '@mndrk/agx'], {
2378
2400
  stdio: 'inherit',
2379
- shell: true
2401
+ shell: false,
2402
+ reject: false,
2380
2403
  });
2381
- if (result.status === 0) {
2404
+ const result = await child;
2405
+ if (result.exitCode === 0) {
2382
2406
  console.log(`${c.green}✓${c.reset} Update complete`);
2383
2407
  } else {
2384
2408
  console.log(`${c.red}✗${c.reset} Update failed`);
@@ -2456,35 +2480,35 @@ async function runCli(argv = process.argv) {
2456
2480
  const originalArgv = process.argv;
2457
2481
  if (Array.isArray(argv)) process.argv = argv;
2458
2482
  try {
2459
- if (await checkOnboarding()) return;
2483
+ if (await checkOnboarding()) return;
2460
2484
 
2461
- const args = process.argv.slice(2);
2462
- let provider = args[0];
2463
- const config = loadConfig();
2485
+ const args = process.argv.slice(2);
2486
+ let provider = args[0];
2487
+ const config = loadConfig();
2464
2488
 
2465
- // Normalize provider aliases
2466
- const PROVIDER_ALIASES = {
2467
- 'g': 'gemini',
2468
- 'gem': 'gemini',
2469
- 'gemini': 'gemini',
2470
- 'c': 'claude',
2471
- 'cl': 'claude',
2472
- 'claude': 'claude',
2473
- 'x': 'codex',
2474
- 'codex': 'codex',
2475
- 'o': 'ollama',
2476
- 'ol': 'ollama',
2477
- 'ollama': 'ollama'
2478
- };
2489
+ // Normalize provider aliases
2490
+ const PROVIDER_ALIASES = {
2491
+ 'g': 'gemini',
2492
+ 'gem': 'gemini',
2493
+ 'gemini': 'gemini',
2494
+ 'c': 'claude',
2495
+ 'cl': 'claude',
2496
+ 'claude': 'claude',
2497
+ 'x': 'codex',
2498
+ 'codex': 'codex',
2499
+ 'o': 'ollama',
2500
+ 'ol': 'ollama',
2501
+ 'ollama': 'ollama'
2502
+ };
2479
2503
 
2480
- const VALID_PROVIDERS = ['gemini', 'claude', 'ollama', 'codex'];
2504
+ const VALID_PROVIDERS = ['gemini', 'claude', 'ollama', 'codex'];
2481
2505
 
2482
- // Handle help
2483
- if (args.includes('--help') || args.includes('-h')) {
2484
- const defaultNote = config?.defaultProvider
2485
- ? ` Default: ${config.defaultProvider}`
2486
- : '';
2487
- console.log(`agx - Autonomous AI Agent CLI
2506
+ // Handle help
2507
+ if (args.includes('--help') || args.includes('-h')) {
2508
+ const defaultNote = config?.defaultProvider
2509
+ ? ` Default: ${config.defaultProvider}`
2510
+ : '';
2511
+ console.log(`agx - Autonomous AI Agent CLI
2488
2512
 
2489
2513
  USAGE:
2490
2514
  agx -a -p "build something" Autonomous: works until done
@@ -2548,386 +2572,338 @@ EXAMPLES:
2548
2572
  agx codex -p "refactor this" # One-shot question
2549
2573
  agx task ls # Check cloud tasks
2550
2574
  agx container logs # See what's happening`);
2551
- process.exit(0);
2552
- }
2553
-
2554
- // Detect if first arg is a provider or an option
2555
- const isProviderArg = provider && PROVIDER_ALIASES[provider.toLowerCase()];
2556
-
2557
- // If no provider specified, use default from config
2558
- if (!provider || (!isProviderArg && provider.startsWith('-'))) {
2559
- if (config?.defaultProvider) {
2560
- // Shift: treat current args as options, use default provider
2561
- if (provider && provider.startsWith('-')) {
2562
- // First arg is an option, not a provider
2563
- provider = config.defaultProvider;
2564
- } else if (!provider) {
2565
- provider = config.defaultProvider;
2566
- }
2567
- } else {
2568
- console.log(`${c.yellow}No provider specified and no default configured.${c.reset}`);
2569
- console.log(`\nRun ${c.cyan}agx init${c.reset} to set up, or specify a provider:\n`);
2570
- console.log(` ${c.dim}agx claude --prompt "hello"${c.reset}`);
2571
- console.log(` ${c.dim}agx codex --prompt "hello"${c.reset}`);
2572
- console.log(` ${c.dim}agx gemini --prompt "hello"${c.reset}`);
2573
- console.log(` ${c.dim}agx ollama --prompt "hello"${c.reset}\n`);
2574
- process.exit(1);
2575
+ process.exit(0);
2575
2576
  }
2576
- }
2577
2577
 
2578
- // Resolve provider
2579
- const resolvedProvider = PROVIDER_ALIASES[provider.toLowerCase()];
2580
- if (!resolvedProvider) {
2581
- console.error(`${c.red}Error:${c.reset} Unknown provider "${provider}"`);
2582
- console.error(`Valid providers: ${VALID_PROVIDERS.join(', ')}`);
2583
- process.exit(1);
2584
- }
2585
- provider = resolvedProvider;
2586
-
2587
- // Determine remaining args - if first arg wasn't a provider, include it
2588
- const remainingArgs = isProviderArg ? args.slice(1) : args;
2589
- const translatedArgs = [];
2590
- const rawArgs = [];
2591
- let env = { ...process.env };
2592
-
2593
- // Split raw arguments at --
2594
- const dashIndex = remainingArgs.indexOf('--');
2595
- let processedArgs = remainingArgs;
2596
- if (dashIndex !== -1) {
2597
- processedArgs = remainingArgs.slice(0, dashIndex);
2598
- rawArgs.push(...remainingArgs.slice(dashIndex + 1));
2599
- }
2600
-
2601
- // Parsed options (explicit structure for predictability)
2602
- const options = {
2603
- prompt: null,
2604
- model: null,
2605
- yolo: false,
2606
- print: false,
2607
- interactive: false,
2608
- sandbox: false,
2609
- debug: false,
2610
- mcp: null,
2611
- cloud: null, // null = auto-detect, true = force on, false = force off
2612
- cloudTaskId: null,
2613
- autonomous: false,
2614
- daemon: false
2615
- };
2578
+ // Detect if first arg is a provider or an option
2579
+ const isProviderArg = provider && PROVIDER_ALIASES[provider.toLowerCase()];
2616
2580
 
2617
- // Collect positional args (legacy support, but --prompt is preferred)
2618
- const positionalArgs = [];
2619
-
2620
- for (let i = 0; i < processedArgs.length; i++) {
2621
- const arg = processedArgs[i];
2622
- const nextArg = processedArgs[i + 1];
2623
-
2624
- switch (arg) {
2625
- case '--prompt':
2626
- case '-p':
2627
- if (nextArg && !nextArg.startsWith('-')) {
2628
- options.prompt = nextArg;
2629
- i++;
2630
- }
2631
- break;
2632
- case '--model':
2633
- case '-m':
2634
- if (nextArg && !nextArg.startsWith('-')) {
2635
- options.model = nextArg;
2636
- i++;
2637
- }
2638
- break;
2639
- case '--yolo':
2640
- case '-y':
2641
- options.yolo = true;
2642
- break;
2643
- case '--print':
2644
- options.print = true;
2645
- break;
2646
- case '--interactive':
2647
- case '-i':
2648
- options.interactive = true;
2649
- break;
2650
- case '--sandbox':
2651
- case '-s':
2652
- options.sandbox = true;
2653
- break;
2654
- case '--debug':
2655
- case '-d':
2656
- options.debug = true;
2657
- break;
2658
- case '--mcp':
2659
- if (nextArg && !nextArg.startsWith('-')) {
2660
- options.mcp = nextArg;
2661
- i++;
2662
- }
2663
- break;
2664
- case '--autonomous':
2665
- case '--auto':
2666
- case '-a':
2667
- options.autonomous = true;
2668
- options.yolo = true; // Autonomous = unattended, skip prompts
2669
- break;
2670
- case '--cloud-task':
2671
- if (nextArg && !nextArg.startsWith('-')) {
2672
- options.cloudTaskId = nextArg;
2673
- i++;
2674
- }
2675
- break;
2676
- case '--daemon':
2677
- options.daemon = true;
2678
- break;
2679
- default:
2680
- if (arg.startsWith('-')) {
2681
- // Unknown flag - pass through
2682
- translatedArgs.push(arg);
2683
- } else {
2684
- // Positional argument (legacy prompt support)
2685
- positionalArgs.push(arg);
2581
+ // If no provider specified, use default from config
2582
+ if (!provider || (!isProviderArg && provider.startsWith('-'))) {
2583
+ if (config?.defaultProvider) {
2584
+ // Shift: treat current args as options, use default provider
2585
+ if (provider && provider.startsWith('-')) {
2586
+ // First arg is an option, not a provider
2587
+ provider = config.defaultProvider;
2588
+ } else if (!provider) {
2589
+ provider = config.defaultProvider;
2686
2590
  }
2591
+ } else {
2592
+ console.log(`${c.yellow}No provider specified and no default configured.${c.reset}`);
2593
+ console.log(`\nRun ${c.cyan}agx init${c.reset} to set up, or specify a provider:\n`);
2594
+ console.log(` ${c.dim}agx claude --prompt "hello"${c.reset}`);
2595
+ console.log(` ${c.dim}agx codex --prompt "hello"${c.reset}`);
2596
+ console.log(` ${c.dim}agx gemini --prompt "hello"${c.reset}`);
2597
+ console.log(` ${c.dim}agx ollama --prompt "hello"${c.reset}\n`);
2598
+ process.exit(1);
2599
+ }
2687
2600
  }
2688
- }
2689
-
2690
- // Determine final prompt: explicit --prompt takes precedence
2691
- const finalPrompt = options.prompt || positionalArgs.join(' ');
2692
2601
 
2693
- // Apply default model from config when --model is not specified
2694
- if (!options.model) {
2695
- const configuredModel = config?.models?.[provider] || (provider === 'ollama' ? config?.ollama?.model : null);
2696
- if (configuredModel) options.model = configuredModel;
2697
- }
2698
-
2699
- // Build command based on provider
2700
- let command = '';
2701
-
2702
- // Apply common options to translatedArgs
2703
- if (options.model) {
2704
- translatedArgs.push('--model', options.model);
2705
- }
2706
- if (options.debug) {
2707
- translatedArgs.push('--debug');
2708
- }
2602
+ // Resolve provider
2603
+ const resolvedProvider = PROVIDER_ALIASES[provider.toLowerCase()];
2604
+ if (!resolvedProvider) {
2605
+ console.error(`${c.red}Error:${c.reset} Unknown provider "${provider}"`);
2606
+ console.error(`Valid providers: ${VALID_PROVIDERS.join(', ')}`);
2607
+ process.exit(1);
2608
+ }
2609
+ provider = resolvedProvider;
2610
+
2611
+ // Determine remaining args - if first arg wasn't a provider, include it
2612
+ const remainingArgs = isProviderArg ? args.slice(1) : args;
2613
+ const translatedArgs = [];
2614
+ const rawArgs = [];
2615
+ let env = { ...process.env };
2616
+
2617
+ // Split raw arguments at --
2618
+ const dashIndex = remainingArgs.indexOf('--');
2619
+ let processedArgs = remainingArgs;
2620
+ if (dashIndex !== -1) {
2621
+ processedArgs = remainingArgs.slice(0, dashIndex);
2622
+ rawArgs.push(...remainingArgs.slice(dashIndex + 1));
2623
+ }
2624
+
2625
+ // Parsed options (explicit structure for predictability)
2626
+ const options = {
2627
+ prompt: null,
2628
+ model: null,
2629
+ yolo: false,
2630
+ print: false,
2631
+ interactive: false,
2632
+ sandbox: false,
2633
+ debug: false,
2634
+ mcp: null,
2635
+ cloud: null, // null = auto-detect, true = force on, false = force off
2636
+ cloudTaskId: null,
2637
+ autonomous: false,
2638
+ daemon: false
2639
+ };
2709
2640
 
2710
- if (provider === 'gemini') {
2711
- command = 'gemini';
2641
+ // Collect positional args (legacy support, but --prompt is preferred)
2642
+ const positionalArgs = [];
2712
2643
 
2713
- // Gemini-specific translations
2714
- if (options.yolo) translatedArgs.push('--yolo');
2715
- if (options.sandbox) translatedArgs.push('--sandbox');
2644
+ for (let i = 0; i < processedArgs.length; i++) {
2645
+ const arg = processedArgs[i];
2646
+ const nextArg = processedArgs[i + 1];
2716
2647
 
2717
- // Gemini prompt handling
2718
- if (finalPrompt) {
2719
- if (options.print) {
2720
- translatedArgs.push('--prompt', finalPrompt);
2721
- } else if (options.interactive) {
2722
- translatedArgs.push('--prompt-interactive', finalPrompt);
2723
- } else {
2724
- translatedArgs.push(finalPrompt);
2725
- }
2726
- }
2727
- } else if (provider === 'codex') {
2728
- command = 'codex';
2729
-
2730
- // Use non-interactive mode whenever this is a scripted invocation.
2731
- const shouldUseExec = options.cloudTaskId
2732
- || options.autonomous
2733
- || options.daemon
2734
- || options.print
2735
- || (finalPrompt && !options.interactive);
2736
- if (shouldUseExec) {
2737
- translatedArgs.unshift('exec');
2738
- }
2739
-
2740
- // Codex approval/sandbox modes:
2741
- // - Officially documented: --auto-edit, --full-auto
2742
- // - Some Codex builds also accept: --dangerously-bypass-approvals-and-sandbox
2743
- // We only attempt the dangerous bypass for unattended runs, and we add a runtime
2744
- // retry below if the installed Codex CLI rejects the flag.
2745
- // If we're using `codex exec`, choose exactly one execution policy:
2746
- // - default unattended: --full-auto (sandboxed, workspace-write)
2747
- // - explicit yolo: --dangerously-bypass-approvals-and-sandbox (unsandboxed)
2748
- //
2749
- // Codex CLI rejects using both at once.
2750
- if (shouldUseExec) {
2751
- if (options.yolo) {
2752
- translatedArgs.push('--dangerously-bypass-approvals-and-sandbox');
2753
- } else {
2754
- translatedArgs.push('--full-auto');
2648
+ switch (arg) {
2649
+ case '--prompt':
2650
+ case '-p':
2651
+ if (nextArg && !nextArg.startsWith('-')) {
2652
+ options.prompt = nextArg;
2653
+ i++;
2654
+ }
2655
+ break;
2656
+ case '--model':
2657
+ case '-m':
2658
+ if (nextArg && !nextArg.startsWith('-')) {
2659
+ options.model = nextArg;
2660
+ i++;
2661
+ }
2662
+ break;
2663
+ case '--yolo':
2664
+ case '-y':
2665
+ options.yolo = true;
2666
+ break;
2667
+ case '--print':
2668
+ options.print = true;
2669
+ break;
2670
+ case '--interactive':
2671
+ case '-i':
2672
+ options.interactive = true;
2673
+ break;
2674
+ case '--sandbox':
2675
+ case '-s':
2676
+ options.sandbox = true;
2677
+ break;
2678
+ case '--debug':
2679
+ case '-d':
2680
+ options.debug = true;
2681
+ break;
2682
+ case '--mcp':
2683
+ if (nextArg && !nextArg.startsWith('-')) {
2684
+ options.mcp = nextArg;
2685
+ i++;
2686
+ }
2687
+ break;
2688
+ case '--autonomous':
2689
+ case '--auto':
2690
+ case '-a':
2691
+ options.autonomous = true;
2692
+ options.yolo = true; // Autonomous = unattended, skip prompts
2693
+ break;
2694
+ case '--cloud-task':
2695
+ if (nextArg && !nextArg.startsWith('-')) {
2696
+ options.cloudTaskId = nextArg;
2697
+ i++;
2698
+ }
2699
+ break;
2700
+ case '--daemon':
2701
+ options.daemon = true;
2702
+ break;
2703
+ default:
2704
+ if (arg.startsWith('-')) {
2705
+ // Unknown flag - pass through
2706
+ translatedArgs.push(arg);
2707
+ } else {
2708
+ // Positional argument (legacy prompt support)
2709
+ positionalArgs.push(arg);
2710
+ }
2755
2711
  }
2756
2712
  }
2757
2713
 
2758
- if (finalPrompt) {
2759
- translatedArgs.push(finalPrompt);
2714
+ // Determine final prompt: explicit --prompt takes precedence
2715
+ const finalPrompt = options.prompt || positionalArgs.join(' ');
2716
+
2717
+ // Apply default model from config when --model is not specified
2718
+ if (!options.model) {
2719
+ const configuredModel = config?.models?.[provider] || (provider === 'ollama' ? config?.ollama?.model : null);
2720
+ if (configuredModel) options.model = configuredModel;
2760
2721
  }
2761
- } else if (provider === 'ollama') {
2762
- // Ollama now routes through Claude CLI with Ollama base URL
2763
- command = 'claude';
2764
- translatedArgs.length = 0; // Clear any accumulated args
2765
2722
 
2766
- // Environment variables for Ollama-via-Claude
2767
- env.ANTHROPIC_AUTH_TOKEN = 'ollama';
2768
- env.ANTHROPIC_BASE_URL = 'http://localhost:11434';
2769
- env.ANTHROPIC_API_KEY = '';
2723
+ // Build command based on provider
2724
+ let command = '';
2770
2725
 
2771
- // Claude flags for Ollama compatibility
2772
- translatedArgs.push('--dangerously-skip-permissions');
2726
+ // Apply common options to translatedArgs
2727
+ if (options.model) {
2728
+ translatedArgs.push('--model', options.model);
2729
+ }
2730
+ if (options.debug) {
2731
+ translatedArgs.push('--debug');
2732
+ }
2773
2733
 
2774
- // Get model from options or config
2775
- const ollamaModel = options.model || config?.models?.ollama || config?.ollama?.model || 'llama3.2:3b';
2776
- translatedArgs.push('--model', ollamaModel);
2734
+ if (provider === 'gemini') {
2735
+ command = 'gemini';
2777
2736
 
2778
- if (finalPrompt) {
2779
- translatedArgs.push('-p', finalPrompt);
2780
- }
2781
- } else {
2782
- // Claude
2783
- command = 'claude';
2737
+ // Gemini-specific translations
2738
+ if (options.yolo) translatedArgs.push('--yolo');
2739
+ if (options.sandbox) translatedArgs.push('--sandbox');
2784
2740
 
2785
- // Claude-specific translations
2786
- if (options.yolo) translatedArgs.push('--dangerously-skip-permissions');
2787
- // Default to --print when prompt is provided and --interactive not specified
2788
- if (options.print || (finalPrompt && !options.interactive)) {
2789
- translatedArgs.push('--print');
2790
- }
2791
- if (options.mcp) translatedArgs.push('--mcp-config', options.mcp);
2741
+ // Gemini prompt handling
2742
+ if (finalPrompt) {
2743
+ if (options.print) {
2744
+ translatedArgs.push('--prompt', finalPrompt);
2745
+ } else if (options.interactive) {
2746
+ translatedArgs.push('--prompt-interactive', finalPrompt);
2747
+ } else {
2748
+ translatedArgs.push(finalPrompt);
2749
+ }
2750
+ }
2751
+ } else if (provider === 'codex') {
2752
+ command = 'codex';
2753
+
2754
+ // Use non-interactive mode whenever this is a scripted invocation.
2755
+ const shouldUseExec = options.cloudTaskId
2756
+ || options.autonomous
2757
+ || options.daemon
2758
+ || options.print
2759
+ || (finalPrompt && !options.interactive);
2760
+ if (shouldUseExec) {
2761
+ translatedArgs.unshift('exec');
2762
+ }
2763
+
2764
+ // Codex approval/sandbox modes:
2765
+ // - Officially documented: --auto-edit, --full-auto
2766
+ // - Some Codex builds also accept: --dangerously-bypass-approvals-and-sandbox
2767
+ // We only attempt the dangerous bypass for unattended runs, and we add a runtime
2768
+ // retry below if the installed Codex CLI rejects the flag.
2769
+ // If we're using `codex exec`, choose exactly one execution policy:
2770
+ // - default unattended: --full-auto (sandboxed, workspace-write)
2771
+ // - explicit yolo: --dangerously-bypass-approvals-and-sandbox (unsandboxed)
2772
+ //
2773
+ // Codex CLI rejects using both at once.
2774
+ if (shouldUseExec) {
2775
+ if (options.yolo) {
2776
+ translatedArgs.push('--dangerously-bypass-approvals-and-sandbox');
2777
+ } else {
2778
+ translatedArgs.push('--full-auto');
2779
+ }
2780
+ }
2792
2781
 
2793
- // Claude prompt (positional at end)
2794
- if (finalPrompt) {
2795
- translatedArgs.push(finalPrompt);
2796
- }
2797
- }
2782
+ if (finalPrompt) {
2783
+ translatedArgs.push(finalPrompt);
2784
+ }
2785
+ } else if (provider === 'ollama') {
2786
+ // Ollama now routes through Claude CLI with Ollama base URL
2787
+ command = 'claude';
2788
+ translatedArgs.length = 0; // Clear any accumulated args
2798
2789
 
2799
- // Append raw args at the end
2800
- translatedArgs.push(...rawArgs);
2790
+ // Environment variables for Ollama-via-Claude
2791
+ env.ANTHROPIC_AUTH_TOKEN = 'ollama';
2792
+ env.ANTHROPIC_BASE_URL = 'http://localhost:11434';
2793
+ env.ANTHROPIC_API_KEY = '';
2801
2794
 
2802
- // ==================== CLOUD INTEGRATION ====================
2795
+ // Claude flags for Ollama compatibility
2796
+ translatedArgs.push('--dangerously-skip-permissions');
2803
2797
 
2804
- // Cloud context logic:
2805
- // - agx -p "..." one-shot, no task
2806
- // - agx -a -p "..." → create new task in cloud
2807
- // - agx --cloud-task <id> → continue cloud task (used by daemon)
2798
+ // Get model from options or config
2799
+ const ollamaModel = options.model || config?.models?.ollama || config?.ollama?.model || 'llama3.2:3b';
2800
+ translatedArgs.push('--model', ollamaModel);
2808
2801
 
2809
- const cloudClient = createCloudClient({ configDir: CONFIG_DIR });
2810
- const loadCloudConfig = cloudClient.loadConfig;
2811
- const saveCloudConfig = cloudClient.saveConfig;
2812
- const cloudRequest = cloudClient.request;
2802
+ if (finalPrompt) {
2803
+ translatedArgs.push('-p', finalPrompt);
2804
+ }
2805
+ } else {
2806
+ // Claude
2807
+ command = 'claude';
2813
2808
 
2814
- // Best-effort: if local CLI settings are newer than DB settings, up-sync to cloud.
2815
- // Non-fatal on failure (offline DB, schema missing, etc.).
2816
- try {
2817
- const meta = config?.settingsMeta || {};
2818
- const cliChangedAt = typeof meta.changedAt === 'string' ? meta.changedAt : '';
2819
- const cliChangedTs = cliChangedAt ? Date.parse(cliChangedAt) : NaN;
2820
- const cliProvider = config?.defaultProvider || '';
2821
- const cliModel = cliProvider
2822
- ? (config?.models?.[cliProvider] || (cliProvider === 'ollama' ? config?.ollama?.model : null))
2823
- : null;
2824
-
2825
- if (Number.isFinite(cliChangedTs) && cliProvider && cliModel) {
2826
- let dbChangedTs = NaN;
2827
- try {
2828
- const db = await cloudRequest('GET', '/api/user-settings');
2829
- const dbChangedAt = typeof db?.settings?.changed_at === 'string' ? db.settings.changed_at : '';
2830
- dbChangedTs = dbChangedAt ? Date.parse(dbChangedAt) : NaN;
2831
- } catch { }
2809
+ // Claude-specific translations
2810
+ if (options.yolo) translatedArgs.push('--dangerously-skip-permissions');
2811
+ // Default to --print when prompt is provided and --interactive not specified
2812
+ if (options.print || (finalPrompt && !options.interactive)) {
2813
+ translatedArgs.push('--print');
2814
+ }
2815
+ if (options.mcp) translatedArgs.push('--mcp-config', options.mcp);
2832
2816
 
2833
- if (!Number.isFinite(dbChangedTs) || cliChangedTs > dbChangedTs) {
2834
- await cloudRequest('PUT', '/api/user-settings', {
2835
- default_provider: cliProvider,
2836
- default_model: cliModel,
2837
- models: config?.models || { [cliProvider]: cliModel },
2838
- provenance: 'cli',
2839
- changed_at: cliChangedAt,
2840
- });
2817
+ // Claude prompt (positional at end)
2818
+ if (finalPrompt) {
2819
+ translatedArgs.push(finalPrompt);
2841
2820
  }
2842
2821
  }
2843
- } catch { }
2844
2822
 
2845
- // --cloud-task: load existing task from cloud (used by daemon)
2846
- if (options.cloudTaskId) {
2847
- try {
2848
- const { task } = await cloudRequest('GET', `/api/tasks/${options.cloudTaskId}`);
2823
+ // Append raw args at the end
2824
+ translatedArgs.push(...rawArgs);
2849
2825
 
2850
- // Fetch task comments
2851
- let taskComments = [];
2852
- try {
2853
- const commentsResponse = await cloudRequest('GET', `/api/tasks/${options.cloudTaskId}/comments`);
2854
- taskComments = commentsResponse?.comments || [];
2855
- } catch (err) {
2856
- console.error(`${c.yellow}Warning: Could not fetch task comments:${c.reset} ${err.message}`);
2857
- }
2858
-
2859
- // Build augmented prompt with task context
2860
- const plan = extractSection(task.content, 'Plan');
2861
- const todo = extractSection(task.content, 'Todo') || extractSection(task.content, 'TODO');
2862
- const checkpoints = extractSection(task.content, 'Checkpoints');
2863
- const learnings = extractSection(task.content, 'Learnings');
2864
-
2865
- const stageKey = task?.stage || 'unknown';
2866
- const stagePrompt = resolveStageObjective(task, stageKey, '');
2867
- const stageRequirement = buildStageRequirementPrompt({ stage: stageKey, stagePrompt });
2868
-
2869
- const augmentedPrompt = buildContinueCloudTaskPrompt({
2870
- task,
2871
- taskComments,
2872
- finalPrompt,
2873
- stagePrompt,
2874
- stageRequirement,
2875
- extracted: { plan, todo, checkpoints, learnings },
2876
- });
2826
+ // ==================== CLOUD INTEGRATION ====================
2877
2827
 
2878
- const promptIndex = translatedArgs.indexOf(finalPrompt);
2879
- if (promptIndex !== -1) {
2880
- translatedArgs[promptIndex] = augmentedPrompt;
2881
- } else {
2882
- translatedArgs.push(augmentedPrompt);
2883
- }
2884
- saveAugmentedPrompt(augmentedPrompt, options.debug);
2828
+ // Cloud context logic:
2829
+ // - agx -p "..." → one-shot, no task
2830
+ // - agx -a -p "..." → create new task in cloud
2831
+ // - agx --cloud-task <id> → continue cloud task (used by daemon)
2885
2832
 
2886
- console.log(`${c.dim}[cloud] Loaded task: ${task.title || task.id}${c.reset}\n`);
2887
- } catch (err) {
2888
- console.error(`${c.red}Failed to load cloud task:${c.reset} ${err.message}`);
2889
- process.exit(1);
2890
- }
2891
- }
2892
-
2893
- // Auto-create task in cloud if --autonomous specified
2894
- if (options.autonomous && finalPrompt && !options.cloudTaskId) {
2895
- console.log(`${c.dim}[cloud] Creating task...${c.reset}`);
2833
+ const cloudClient = createCloudClient({ configDir: CONFIG_DIR });
2834
+ const loadCloudConfig = cloudClient.loadConfig;
2835
+ const saveCloudConfig = cloudClient.saveConfig;
2836
+ const cloudRequest = cloudClient.request;
2896
2837
 
2838
+ // Best-effort: if local CLI settings are newer than DB settings, up-sync to cloud.
2839
+ // Non-fatal on failure (offline DB, schema missing, etc.).
2897
2840
  try {
2898
- const cloudConfig = loadCloudConfig();
2899
- if (cloudConfig?.apiUrl) {
2900
- const frontmatter = ['status: queued', 'stage: ideation'];
2901
- frontmatter.push(`engine: ${provider}`);
2902
-
2903
- const content = `---\n${frontmatter.join('\n')}\n---\n\n# ${finalPrompt}\n`;
2841
+ const meta = config?.settingsMeta || {};
2842
+ const cliChangedAt = typeof meta.changedAt === 'string' ? meta.changedAt : '';
2843
+ const cliChangedTs = cliChangedAt ? Date.parse(cliChangedAt) : NaN;
2844
+ const cliProvider = config?.defaultProvider || '';
2845
+ const cliModel = cliProvider
2846
+ ? (config?.models?.[cliProvider] || (cliProvider === 'ollama' ? config?.ollama?.model : null))
2847
+ : null;
2848
+
2849
+ if (Number.isFinite(cliChangedTs) && cliProvider && cliModel) {
2850
+ let dbChangedTs = NaN;
2851
+ try {
2852
+ const db = await cloudRequest('GET', '/api/user-settings');
2853
+ const dbChangedAt = typeof db?.settings?.changed_at === 'string' ? db.settings.changed_at : '';
2854
+ dbChangedTs = dbChangedAt ? Date.parse(dbChangedAt) : NaN;
2855
+ } catch { }
2904
2856
 
2905
- const { task } = await cloudRequest('POST', '/api/tasks', { content });
2857
+ if (!Number.isFinite(dbChangedTs) || cliChangedTs > dbChangedTs) {
2858
+ await cloudRequest('PUT', '/api/user-settings', {
2859
+ default_provider: cliProvider,
2860
+ default_model: cliModel,
2861
+ models: config?.models || { [cliProvider]: cliModel },
2862
+ provenance: 'cli',
2863
+ changed_at: cliChangedAt,
2864
+ });
2865
+ }
2866
+ }
2867
+ } catch { }
2906
2868
 
2907
- console.log(`${c.green}✓${c.reset} Task created in cloud: ${task.id}`);
2908
- options.cloudTaskId = task.id;
2869
+ // --cloud-task: load existing task from cloud (used by daemon)
2870
+ if (options.cloudTaskId) {
2871
+ try {
2872
+ const { task } = await cloudRequest('GET', `/api/tasks/${options.cloudTaskId}`);
2909
2873
 
2910
- // Fetch task comments (should be empty for new tasks, but good practice)
2874
+ // Fetch task comments
2911
2875
  let taskComments = [];
2912
2876
  try {
2913
- const commentsResponse = await cloudRequest('GET', `/api/tasks/${task.id}/comments`);
2877
+ const commentsResponse = await cloudRequest('GET', `/api/tasks/${options.cloudTaskId}/comments`);
2914
2878
  taskComments = commentsResponse?.comments || [];
2915
2879
  } catch (err) {
2916
2880
  console.error(`${c.yellow}Warning: Could not fetch task comments:${c.reset} ${err.message}`);
2917
2881
  }
2918
2882
 
2919
- // Update prompt with task context
2920
- const stageKey = task?.stage || 'unknown';
2921
- const stagePrompt = resolveStageObjective(task, stageKey, '');
2922
- const stageRequirement = buildStageRequirementPrompt({ stage: stageKey, stagePrompt });
2923
-
2924
- const augmentedPrompt = buildNewAutonomousCloudTaskPrompt({
2925
- task,
2926
- taskComments,
2927
- finalPrompt,
2928
- stagePrompt,
2929
- stageRequirement,
2930
- });
2883
+ // Build augmented prompt with task context
2884
+ const plan = cloudArtifacts.extractSection(task.content, 'Plan');
2885
+ const todo = cloudArtifacts.extractSection(task.content, 'Todo') || cloudArtifacts.extractSection(task.content, 'TODO');
2886
+ const checkpoints = cloudArtifacts.extractSection(task.content, 'Checkpoints');
2887
+ const learnings = cloudArtifacts.extractSection(task.content, 'Learnings');
2888
+
2889
+ const stageKey = task?.stage || 'unknown';
2890
+ const stagePrompt = resolveStageObjective(task, stageKey, '');
2891
+ const stageRequirement = buildStageRequirementPrompt({ stage: stageKey, stagePrompt });
2892
+ const runContext = {
2893
+ run_root: process.env.AGX_RUN_ROOT || '',
2894
+ plan_dir: process.env.AGX_RUN_PLAN_DIR || '',
2895
+ artifacts_dir: process.env.AGX_RUN_ARTIFACTS_DIR || '',
2896
+ };
2897
+
2898
+ const augmentedPrompt = buildContinueCloudTaskPrompt({
2899
+ task,
2900
+ taskComments,
2901
+ finalPrompt,
2902
+ stagePrompt,
2903
+ stageRequirement,
2904
+ extracted: { plan, todo, checkpoints, learnings },
2905
+ runContext,
2906
+ });
2931
2907
 
2932
2908
  const promptIndex = translatedArgs.indexOf(finalPrompt);
2933
2909
  if (promptIndex !== -1) {
@@ -2937,115 +2913,170 @@ EXAMPLES:
2937
2913
  }
2938
2914
  saveAugmentedPrompt(augmentedPrompt, options.debug);
2939
2915
 
2940
- // Start daemon for autonomous mode
2941
- if (options.autonomous) {
2942
- startDaemon();
2943
- console.log(`${c.green}✓${c.reset} Autonomous mode: daemon running\n`);
2944
- }
2945
- } else {
2946
- console.log(`${c.yellow}Cloud API URL not configured. Set AGX_CLOUD_URL (default http://localhost:41741).${c.reset}`);
2947
- console.log(`${c.dim}Task not created. Running in one-shot mode.${c.reset}`);
2916
+ console.log(`${c.dim}[cloud] Loaded task: ${task.title || task.id}${c.reset}\n`);
2917
+ } catch (err) {
2918
+ console.error(`${c.red}Failed to load cloud task:${c.reset} ${err.message}`);
2919
+ process.exit(1);
2948
2920
  }
2949
- } catch (err) {
2950
- console.error(`${c.yellow}Warning: Could not create cloud task:${c.reset} ${err.message}`);
2951
- console.log(`${c.dim}Running in one-shot mode.${c.reset}`);
2952
2921
  }
2953
- }
2954
2922
 
2955
- // Normal mode - just pass through to provider
2956
- const useOllamaPipe = provider === 'ollama' && options.ollamaPrompt && command === 'ollama';
2957
- const shouldRetryCodexBypassFlag = command === 'codex'
2958
- && translatedArgs.includes('--dangerously-bypass-approvals-and-sandbox');
2923
+ // Auto-create task in cloud if --autonomous specified
2924
+ if (options.autonomous && finalPrompt && !options.cloudTaskId) {
2925
+ console.log(`${c.dim}[cloud] Creating task...${c.reset}`);
2959
2926
 
2960
- const spawnProvider = (cmd, args, spawnOpts) => {
2961
- const childProc = spawn(cmd, args, spawnOpts);
2962
- // Send prompt to Ollama via stdin
2963
- if (useOllamaPipe && childProc.stdin) {
2964
- childProc.stdin.write(options.ollamaPrompt);
2965
- childProc.stdin.end();
2966
- }
2927
+ try {
2928
+ const cloudConfig = loadCloudConfig();
2929
+ if (cloudConfig?.apiUrl) {
2930
+ const frontmatter = ['status: queued', 'stage: ideation'];
2931
+ frontmatter.push(`engine: ${provider}`);
2967
2932
 
2968
- childProc.on('exit', (code) => {
2969
- process.exit(code || 0);
2970
- });
2933
+ const content = `---\n${frontmatter.join('\n')}\n---\n\n# ${finalPrompt}\n`;
2934
+
2935
+ const { task } = await cloudRequest('POST', '/api/tasks', { content });
2936
+
2937
+ console.log(`${c.green}✓${c.reset} Task created in cloud: ${task.id}`);
2938
+ options.cloudTaskId = task.id;
2939
+
2940
+ // Fetch task comments (should be empty for new tasks, but good practice)
2941
+ let taskComments = [];
2942
+ try {
2943
+ const commentsResponse = await cloudRequest('GET', `/api/tasks/${task.id}/comments`);
2944
+ taskComments = commentsResponse?.comments || [];
2945
+ } catch (err) {
2946
+ console.error(`${c.yellow}Warning: Could not fetch task comments:${c.reset} ${err.message}`);
2947
+ }
2948
+
2949
+ // Update prompt with task context
2950
+ const stageKey = task?.stage || 'unknown';
2951
+ const stagePrompt = resolveStageObjective(task, stageKey, '');
2952
+ const stageRequirement = buildStageRequirementPrompt({ stage: stageKey, stagePrompt });
2953
+
2954
+ const augmentedPrompt = buildNewAutonomousCloudTaskPrompt({
2955
+ task,
2956
+ taskComments,
2957
+ finalPrompt,
2958
+ stagePrompt,
2959
+ stageRequirement,
2960
+ });
2961
+
2962
+ const promptIndex = translatedArgs.indexOf(finalPrompt);
2963
+ if (promptIndex !== -1) {
2964
+ translatedArgs[promptIndex] = augmentedPrompt;
2965
+ } else {
2966
+ translatedArgs.push(augmentedPrompt);
2967
+ }
2968
+ saveAugmentedPrompt(augmentedPrompt, options.debug);
2971
2969
 
2972
- childProc.on('error', (err) => {
2973
- if (err.code === 'ENOENT') {
2974
- console.error(`${c.red}Error:${c.reset} "${cmd}" command not found.`);
2975
- console.error(`\n${c.dim}Install it first:${c.reset}`);
2976
- if (cmd === 'claude') {
2977
- console.error(` npm install -g @anthropic-ai/claude-code`);
2978
- } else if (cmd === 'gemini') {
2979
- console.error(` npm install -g @google/gemini-cli`);
2980
- } else if (cmd === 'ollama') {
2981
- console.error(` brew install ollama # macOS`);
2982
- console.error(` curl -fsSL https://ollama.ai/install.sh | sh # Linux`);
2983
- } else if (cmd === 'codex') {
2984
- console.error(` npm install -g @openai/codex`);
2970
+ // Start daemon for autonomous mode
2971
+ if (options.autonomous) {
2972
+ startDaemon();
2973
+ console.log(`${c.green}✓${c.reset} Autonomous mode: daemon running\n`);
2974
+ }
2975
+ } else {
2976
+ console.log(`${c.yellow}Cloud API URL not configured. Set AGX_CLOUD_URL (default http://localhost:41741).${c.reset}`);
2977
+ console.log(`${c.dim}Task not created. Running in one-shot mode.${c.reset}`);
2985
2978
  }
2986
- } else {
2987
- console.error(`${c.red}Failed to start ${cmd}:${c.reset}`, err.message);
2979
+ } catch (err) {
2980
+ console.error(`${c.yellow}Warning: Could not create cloud task:${c.reset} ${err.message}`);
2981
+ console.log(`${c.dim}Running in one-shot mode.${c.reset}`);
2988
2982
  }
2989
- process.exit(1);
2990
- });
2983
+ }
2991
2984
 
2992
- return childProc;
2993
- };
2985
+ // Normal mode - just pass through to provider
2986
+ const useOllamaPipe = provider === 'ollama' && options.ollamaPrompt && command === 'ollama';
2987
+ const shouldRetryCodexBypassFlag = command === 'codex'
2988
+ && translatedArgs.includes('--dangerously-bypass-approvals-and-sandbox');
2994
2989
 
2995
- if (!shouldRetryCodexBypassFlag) {
2996
- spawnProvider(command, translatedArgs, {
2997
- env,
2998
- stdio: useOllamaPipe ? ['pipe', 'inherit', 'inherit'] : 'inherit',
2999
- shell: false
3000
- });
3001
- } else {
3002
- // Best-effort compatibility: if the local Codex CLI doesn't recognize
3003
- // --dangerously-bypass-approvals-and-sandbox, retry without it.
3004
- const firstArgs = translatedArgs.slice();
3005
- const retryArgs = translatedArgs.filter((a) => a !== '--dangerously-bypass-approvals-and-sandbox');
3006
-
3007
- let stderrBuf = '';
3008
- const maxBuf = 16 * 1024;
3009
-
3010
- const child = spawn(command, firstArgs, {
3011
- env,
3012
- stdio: ['inherit', 'pipe', 'pipe'],
3013
- shell: false
3014
- });
2990
+ const spawnProvider = (cmd, args, spawnOpts) => {
2991
+ const childProc = execa(cmd, args, { reject: false, ...spawnOpts });
2992
+ // Send prompt to Ollama via stdin
2993
+ if (useOllamaPipe && childProc.stdin) {
2994
+ childProc.stdin.write(options.ollamaPrompt);
2995
+ childProc.stdin.end();
2996
+ }
3015
2997
 
3016
- if (child.stdout) {
3017
- child.stdout.on('data', (d) => process.stdout.write(d));
3018
- }
3019
- if (child.stderr) {
3020
- child.stderr.on('data', (d) => {
3021
- process.stderr.write(d);
3022
- if (stderrBuf.length < maxBuf) {
3023
- stderrBuf += d.toString('utf8').slice(0, maxBuf - stderrBuf.length);
2998
+ childProc.on('exit', (code) => {
2999
+ process.exit(code || 0);
3000
+ });
3001
+
3002
+ childProc.on('error', (err) => {
3003
+ if (err.code === 'ENOENT') {
3004
+ console.error(`${c.red}Error:${c.reset} "${cmd}" command not found.`);
3005
+ console.error(`\n${c.dim}Install it first:${c.reset}`);
3006
+ if (cmd === 'claude') {
3007
+ console.error(` npm install -g @anthropic-ai/claude-code`);
3008
+ } else if (cmd === 'gemini') {
3009
+ console.error(` npm install -g @google/gemini-cli`);
3010
+ } else if (cmd === 'ollama') {
3011
+ console.error(` brew install ollama # macOS`);
3012
+ console.error(` curl -fsSL https://ollama.ai/install.sh | sh # Linux`);
3013
+ } else if (cmd === 'codex') {
3014
+ console.error(` npm install -g @openai/codex`);
3015
+ }
3016
+ } else {
3017
+ console.error(`${c.red}Failed to start ${cmd}:${c.reset}`, err.message);
3024
3018
  }
3019
+ process.exit(1);
3025
3020
  });
3026
- }
3027
3021
 
3028
- child.on('close', (code) => {
3029
- const failed = (code || 0) !== 0;
3030
- const looksLikeUnknownFlag = /unknown option|unknown flag|unrecognized option|unexpected argument|invalid option/i.test(stderrBuf)
3031
- && /dangerously-bypass-approvals-and-sandbox/i.test(stderrBuf);
3032
- if (failed && looksLikeUnknownFlag) {
3033
- console.error(`${c.yellow}[agx] Codex CLI rejected --dangerously-bypass-approvals-and-sandbox; retrying without it.${c.reset}`);
3034
- spawnProvider(command, retryArgs, {
3035
- env,
3036
- stdio: 'inherit',
3037
- shell: false
3022
+ return childProc;
3023
+ };
3024
+
3025
+ if (!shouldRetryCodexBypassFlag) {
3026
+ spawnProvider(command, translatedArgs, {
3027
+ env,
3028
+ stdio: useOllamaPipe ? ['pipe', 'inherit', 'inherit'] : 'inherit',
3029
+ shell: false
3030
+ });
3031
+ } else {
3032
+ // Best-effort compatibility: if the local Codex CLI doesn't recognize
3033
+ // --dangerously-bypass-approvals-and-sandbox, retry without it.
3034
+ const firstArgs = translatedArgs.slice();
3035
+ const retryArgs = translatedArgs.filter((a) => a !== '--dangerously-bypass-approvals-and-sandbox');
3036
+
3037
+ let stderrBuf = '';
3038
+ const maxBuf = 16 * 1024;
3039
+
3040
+ const child = execa(command, firstArgs, {
3041
+ env,
3042
+ stdio: ['inherit', 'pipe', 'pipe'],
3043
+ shell: false,
3044
+ reject: false,
3045
+ });
3046
+
3047
+ if (child.stdout) {
3048
+ child.stdout.on('data', (d) => process.stdout.write(d));
3049
+ }
3050
+ if (child.stderr) {
3051
+ child.stderr.on('data', (d) => {
3052
+ process.stderr.write(d);
3053
+ if (stderrBuf.length < maxBuf) {
3054
+ stderrBuf += d.toString('utf8').slice(0, maxBuf - stderrBuf.length);
3055
+ }
3038
3056
  });
3039
- return;
3040
3057
  }
3041
- process.exit(code || 0);
3042
- });
3043
3058
 
3044
- child.on('error', (err) => {
3045
- console.error(`${c.red}Failed to start ${command}:${c.reset}`, err.message);
3046
- process.exit(1);
3047
- });
3048
- }
3059
+ child.on('close', (code) => {
3060
+ const failed = (code || 0) !== 0;
3061
+ const looksLikeUnknownFlag = /unknown option|unknown flag|unrecognized option|unexpected argument|invalid option/i.test(stderrBuf)
3062
+ && /dangerously-bypass-approvals-and-sandbox/i.test(stderrBuf);
3063
+ if (failed && looksLikeUnknownFlag) {
3064
+ console.error(`${c.yellow}[agx] Codex CLI rejected --dangerously-bypass-approvals-and-sandbox; retrying without it.${c.reset}`);
3065
+ spawnProvider(command, retryArgs, {
3066
+ env,
3067
+ stdio: 'inherit',
3068
+ shell: false
3069
+ });
3070
+ return;
3071
+ }
3072
+ process.exit(code || 0);
3073
+ });
3074
+
3075
+ child.on('error', (err) => {
3076
+ console.error(`${c.red}Failed to start ${command}:${c.reset}`, err.message);
3077
+ process.exit(1);
3078
+ });
3079
+ }
3049
3080
 
3050
3081
  } finally {
3051
3082
  process.argv = originalArgv;