@oxagen/cli 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (407) hide show
  1. package/LICENSE +3 -0
  2. package/README.html +379 -0
  3. package/dist/commands/__tests__/cli-parity.test.d.ts +2 -0
  4. package/dist/commands/__tests__/cli-parity.test.d.ts.map +1 -0
  5. package/dist/commands/__tests__/cli-parity.test.js +110 -0
  6. package/dist/commands/__tests__/cli-parity.test.js.map +1 -0
  7. package/dist/commands/agent.approval.resolve.d.ts +3 -0
  8. package/dist/commands/agent.approval.resolve.d.ts.map +1 -0
  9. package/dist/commands/agent.approval.resolve.js +30 -0
  10. package/dist/commands/agent.approval.resolve.js.map +1 -0
  11. package/dist/commands/agent.mcp.list.d.ts +3 -0
  12. package/dist/commands/agent.mcp.list.d.ts.map +1 -0
  13. package/dist/commands/agent.mcp.list.js +23 -0
  14. package/dist/commands/agent.mcp.list.js.map +1 -0
  15. package/dist/commands/agent.mcp.register.d.ts +3 -0
  16. package/dist/commands/agent.mcp.register.d.ts.map +1 -0
  17. package/dist/commands/agent.mcp.register.js +40 -0
  18. package/dist/commands/agent.mcp.register.js.map +1 -0
  19. package/dist/commands/agent.memory.recall.d.ts +3 -0
  20. package/dist/commands/agent.memory.recall.d.ts.map +1 -0
  21. package/dist/commands/agent.memory.recall.js +25 -0
  22. package/dist/commands/agent.memory.recall.js.map +1 -0
  23. package/dist/commands/agent.memory.write.d.ts +3 -0
  24. package/dist/commands/agent.memory.write.d.ts.map +1 -0
  25. package/dist/commands/agent.memory.write.js +25 -0
  26. package/dist/commands/agent.memory.write.js.map +1 -0
  27. package/dist/commands/agent.plan.approve.d.ts +3 -0
  28. package/dist/commands/agent.plan.approve.d.ts.map +1 -0
  29. package/dist/commands/agent.plan.approve.js +34 -0
  30. package/dist/commands/agent.plan.approve.js.map +1 -0
  31. package/dist/commands/agent.skill.list.d.ts +3 -0
  32. package/dist/commands/agent.skill.list.d.ts.map +1 -0
  33. package/dist/commands/agent.skill.list.js +25 -0
  34. package/dist/commands/agent.skill.list.js.map +1 -0
  35. package/dist/commands/agent.task.background.cancel.d.ts +3 -0
  36. package/dist/commands/agent.task.background.cancel.d.ts.map +1 -0
  37. package/dist/commands/agent.task.background.cancel.js +29 -0
  38. package/dist/commands/agent.task.background.cancel.js.map +1 -0
  39. package/dist/commands/agent.task.background.read.d.ts +3 -0
  40. package/dist/commands/agent.task.background.read.d.ts.map +1 -0
  41. package/dist/commands/agent.task.background.read.js +28 -0
  42. package/dist/commands/agent.task.background.read.js.map +1 -0
  43. package/dist/commands/agent.task.background.start.d.ts +3 -0
  44. package/dist/commands/agent.task.background.start.d.ts.map +1 -0
  45. package/dist/commands/agent.task.background.start.js +31 -0
  46. package/dist/commands/agent.task.background.start.js.map +1 -0
  47. package/dist/commands/agent.tool.list.d.ts +3 -0
  48. package/dist/commands/agent.tool.list.d.ts.map +1 -0
  49. package/dist/commands/agent.tool.list.js +25 -0
  50. package/dist/commands/agent.tool.list.js.map +1 -0
  51. package/dist/commands/api-key.create.d.ts +3 -0
  52. package/dist/commands/api-key.create.d.ts.map +1 -0
  53. package/dist/commands/api-key.create.js +30 -0
  54. package/dist/commands/api-key.create.js.map +1 -0
  55. package/dist/commands/api-key.revoke.d.ts +3 -0
  56. package/dist/commands/api-key.revoke.d.ts.map +1 -0
  57. package/dist/commands/api-key.revoke.js +17 -0
  58. package/dist/commands/api-key.revoke.js.map +1 -0
  59. package/dist/commands/archive.create.d.ts +3 -0
  60. package/dist/commands/archive.create.d.ts.map +1 -0
  61. package/dist/commands/archive.create.js +29 -0
  62. package/dist/commands/archive.create.js.map +1 -0
  63. package/dist/commands/asset.upload.d.ts +3 -0
  64. package/dist/commands/asset.upload.d.ts.map +1 -0
  65. package/dist/commands/asset.upload.js +31 -0
  66. package/dist/commands/asset.upload.js.map +1 -0
  67. package/dist/commands/auth.login.d.ts +3 -0
  68. package/dist/commands/auth.login.d.ts.map +1 -0
  69. package/dist/commands/auth.login.js +31 -0
  70. package/dist/commands/auth.login.js.map +1 -0
  71. package/dist/commands/auth.logout.d.ts +3 -0
  72. package/dist/commands/auth.logout.d.ts.map +1 -0
  73. package/dist/commands/auth.logout.js +20 -0
  74. package/dist/commands/auth.logout.js.map +1 -0
  75. package/dist/commands/auth.whoami.d.ts +3 -0
  76. package/dist/commands/auth.whoami.d.ts.map +1 -0
  77. package/dist/commands/auth.whoami.js +20 -0
  78. package/dist/commands/auth.whoami.js.map +1 -0
  79. package/dist/commands/automation.create.d.ts +3 -0
  80. package/dist/commands/automation.create.d.ts.map +1 -0
  81. package/dist/commands/automation.create.js +30 -0
  82. package/dist/commands/automation.create.js.map +1 -0
  83. package/dist/commands/automation.list.d.ts +3 -0
  84. package/dist/commands/automation.list.d.ts.map +1 -0
  85. package/dist/commands/automation.list.js +26 -0
  86. package/dist/commands/automation.list.js.map +1 -0
  87. package/dist/commands/automation.trigger.d.ts +3 -0
  88. package/dist/commands/automation.trigger.d.ts.map +1 -0
  89. package/dist/commands/automation.trigger.js +33 -0
  90. package/dist/commands/automation.trigger.js.map +1 -0
  91. package/dist/commands/billing.credits.purchase.d.ts +3 -0
  92. package/dist/commands/billing.credits.purchase.d.ts.map +1 -0
  93. package/dist/commands/billing.credits.purchase.js +31 -0
  94. package/dist/commands/billing.credits.purchase.js.map +1 -0
  95. package/dist/commands/billing.status.d.ts +3 -0
  96. package/dist/commands/billing.status.d.ts.map +1 -0
  97. package/dist/commands/billing.status.js +30 -0
  98. package/dist/commands/billing.status.js.map +1 -0
  99. package/dist/commands/billing.subscription.read.d.ts +3 -0
  100. package/dist/commands/billing.subscription.read.d.ts.map +1 -0
  101. package/dist/commands/billing.subscription.read.js +26 -0
  102. package/dist/commands/billing.subscription.read.js.map +1 -0
  103. package/dist/commands/billing.subscription.upgrade.start.d.ts +3 -0
  104. package/dist/commands/billing.subscription.upgrade.start.d.ts.map +1 -0
  105. package/dist/commands/billing.subscription.upgrade.start.js +32 -0
  106. package/dist/commands/billing.subscription.upgrade.start.js.map +1 -0
  107. package/dist/commands/brandkit.apply.d.ts +3 -0
  108. package/dist/commands/brandkit.apply.d.ts.map +1 -0
  109. package/dist/commands/brandkit.apply.js +31 -0
  110. package/dist/commands/brandkit.apply.js.map +1 -0
  111. package/dist/commands/chat.send.d.ts +3 -0
  112. package/dist/commands/chat.send.d.ts.map +1 -0
  113. package/dist/commands/chat.send.js +30 -0
  114. package/dist/commands/chat.send.js.map +1 -0
  115. package/dist/commands/conversation.archive.d.ts +3 -0
  116. package/dist/commands/conversation.archive.d.ts.map +1 -0
  117. package/dist/commands/conversation.archive.js +22 -0
  118. package/dist/commands/conversation.archive.js.map +1 -0
  119. package/dist/commands/conversation.chat.d.ts +3 -0
  120. package/dist/commands/conversation.chat.d.ts.map +1 -0
  121. package/dist/commands/conversation.chat.js +28 -0
  122. package/dist/commands/conversation.chat.js.map +1 -0
  123. package/dist/commands/conversation.delete.d.ts +3 -0
  124. package/dist/commands/conversation.delete.d.ts.map +1 -0
  125. package/dist/commands/conversation.delete.js +17 -0
  126. package/dist/commands/conversation.delete.js.map +1 -0
  127. package/dist/commands/conversation.list.d.ts +3 -0
  128. package/dist/commands/conversation.list.d.ts.map +1 -0
  129. package/dist/commands/conversation.list.js +31 -0
  130. package/dist/commands/conversation.list.js.map +1 -0
  131. package/dist/commands/conversation.purge.d.ts +3 -0
  132. package/dist/commands/conversation.purge.d.ts.map +1 -0
  133. package/dist/commands/conversation.purge.js +29 -0
  134. package/dist/commands/conversation.purge.js.map +1 -0
  135. package/dist/commands/conversation.rename.d.ts +3 -0
  136. package/dist/commands/conversation.rename.d.ts.map +1 -0
  137. package/dist/commands/conversation.rename.js +21 -0
  138. package/dist/commands/conversation.rename.js.map +1 -0
  139. package/dist/commands/document.create.d.ts +3 -0
  140. package/dist/commands/document.create.d.ts.map +1 -0
  141. package/dist/commands/document.create.js +29 -0
  142. package/dist/commands/document.create.js.map +1 -0
  143. package/dist/commands/document.list.d.ts +3 -0
  144. package/dist/commands/document.list.d.ts.map +1 -0
  145. package/dist/commands/document.list.js +29 -0
  146. package/dist/commands/document.list.js.map +1 -0
  147. package/dist/commands/document.read.d.ts +3 -0
  148. package/dist/commands/document.read.d.ts.map +1 -0
  149. package/dist/commands/document.read.js +23 -0
  150. package/dist/commands/document.read.js.map +1 -0
  151. package/dist/commands/documents.generate.d.ts +3 -0
  152. package/dist/commands/documents.generate.d.ts.map +1 -0
  153. package/dist/commands/documents.generate.js +34 -0
  154. package/dist/commands/documents.generate.js.map +1 -0
  155. package/dist/commands/documents.pdf.create.d.ts +3 -0
  156. package/dist/commands/documents.pdf.create.d.ts.map +1 -0
  157. package/dist/commands/documents.pdf.create.js +39 -0
  158. package/dist/commands/documents.pdf.create.js.map +1 -0
  159. package/dist/commands/form.create.d.ts +3 -0
  160. package/dist/commands/form.create.d.ts.map +1 -0
  161. package/dist/commands/form.create.js +34 -0
  162. package/dist/commands/form.create.js.map +1 -0
  163. package/dist/commands/form.fill.d.ts +3 -0
  164. package/dist/commands/form.fill.d.ts.map +1 -0
  165. package/dist/commands/form.fill.js +36 -0
  166. package/dist/commands/form.fill.js.map +1 -0
  167. package/dist/commands/form.submit.d.ts +3 -0
  168. package/dist/commands/form.submit.d.ts.map +1 -0
  169. package/dist/commands/form.submit.js +34 -0
  170. package/dist/commands/form.submit.js.map +1 -0
  171. package/dist/commands/image.analyze.d.ts +3 -0
  172. package/dist/commands/image.analyze.d.ts.map +1 -0
  173. package/dist/commands/image.analyze.js +24 -0
  174. package/dist/commands/image.analyze.js.map +1 -0
  175. package/dist/commands/image.create.d.ts +3 -0
  176. package/dist/commands/image.create.d.ts.map +1 -0
  177. package/dist/commands/image.create.js +33 -0
  178. package/dist/commands/image.create.js.map +1 -0
  179. package/dist/commands/image.generate.d.ts +3 -0
  180. package/dist/commands/image.generate.d.ts.map +1 -0
  181. package/dist/commands/image.generate.js +35 -0
  182. package/dist/commands/image.generate.js.map +1 -0
  183. package/dist/commands/image.list.d.ts +3 -0
  184. package/dist/commands/image.list.d.ts.map +1 -0
  185. package/dist/commands/image.list.js +29 -0
  186. package/dist/commands/image.list.js.map +1 -0
  187. package/dist/commands/notifications.list.d.ts +3 -0
  188. package/dist/commands/notifications.list.d.ts.map +1 -0
  189. package/dist/commands/notifications.list.js +32 -0
  190. package/dist/commands/notifications.list.js.map +1 -0
  191. package/dist/commands/notifications.mark.d.ts +3 -0
  192. package/dist/commands/notifications.mark.d.ts.map +1 -0
  193. package/dist/commands/notifications.mark.js +22 -0
  194. package/dist/commands/notifications.mark.js.map +1 -0
  195. package/dist/commands/org.create.d.ts +3 -0
  196. package/dist/commands/org.create.d.ts.map +1 -0
  197. package/dist/commands/org.create.js +22 -0
  198. package/dist/commands/org.create.js.map +1 -0
  199. package/dist/commands/org.list.d.ts +3 -0
  200. package/dist/commands/org.list.d.ts.map +1 -0
  201. package/dist/commands/org.list.js +24 -0
  202. package/dist/commands/org.list.js.map +1 -0
  203. package/dist/commands/org.member.add.d.ts +3 -0
  204. package/dist/commands/org.member.add.d.ts.map +1 -0
  205. package/dist/commands/org.member.add.js +22 -0
  206. package/dist/commands/org.member.add.js.map +1 -0
  207. package/dist/commands/org.member.invite.accept.d.ts +3 -0
  208. package/dist/commands/org.member.invite.accept.d.ts.map +1 -0
  209. package/dist/commands/org.member.invite.accept.js +23 -0
  210. package/dist/commands/org.member.invite.accept.js.map +1 -0
  211. package/dist/commands/org.member.invite.decline.d.ts +3 -0
  212. package/dist/commands/org.member.invite.decline.d.ts.map +1 -0
  213. package/dist/commands/org.member.invite.decline.js +24 -0
  214. package/dist/commands/org.member.invite.decline.js.map +1 -0
  215. package/dist/commands/org.member.remove.d.ts +3 -0
  216. package/dist/commands/org.member.remove.d.ts.map +1 -0
  217. package/dist/commands/org.member.remove.js +21 -0
  218. package/dist/commands/org.member.remove.js.map +1 -0
  219. package/dist/commands/org.member.role.change.d.ts +3 -0
  220. package/dist/commands/org.member.role.change.d.ts.map +1 -0
  221. package/dist/commands/org.member.role.change.js +26 -0
  222. package/dist/commands/org.member.role.change.js.map +1 -0
  223. package/dist/commands/organization.create.d.ts +3 -0
  224. package/dist/commands/organization.create.d.ts.map +1 -0
  225. package/dist/commands/organization.create.js +36 -0
  226. package/dist/commands/organization.create.js.map +1 -0
  227. package/dist/commands/plugin.catalog.browse.d.ts +3 -0
  228. package/dist/commands/plugin.catalog.browse.d.ts.map +1 -0
  229. package/dist/commands/plugin.catalog.browse.js +21 -0
  230. package/dist/commands/plugin.catalog.browse.js.map +1 -0
  231. package/dist/commands/plugin.catalog.get.d.ts +3 -0
  232. package/dist/commands/plugin.catalog.get.d.ts.map +1 -0
  233. package/dist/commands/plugin.catalog.get.js +25 -0
  234. package/dist/commands/plugin.catalog.get.js.map +1 -0
  235. package/dist/commands/plugin.credential.reauth.d.ts +3 -0
  236. package/dist/commands/plugin.credential.reauth.d.ts.map +1 -0
  237. package/dist/commands/plugin.credential.reauth.js +23 -0
  238. package/dist/commands/plugin.credential.reauth.js.map +1 -0
  239. package/dist/commands/plugin.credential.set_secret.d.ts +3 -0
  240. package/dist/commands/plugin.credential.set_secret.d.ts.map +1 -0
  241. package/dist/commands/plugin.credential.set_secret.js +32 -0
  242. package/dist/commands/plugin.credential.set_secret.js.map +1 -0
  243. package/dist/commands/plugin.denylist.add.d.ts +3 -0
  244. package/dist/commands/plugin.denylist.add.d.ts.map +1 -0
  245. package/dist/commands/plugin.denylist.add.js +28 -0
  246. package/dist/commands/plugin.denylist.add.js.map +1 -0
  247. package/dist/commands/plugin.denylist.remove.d.ts +3 -0
  248. package/dist/commands/plugin.denylist.remove.d.ts.map +1 -0
  249. package/dist/commands/plugin.denylist.remove.js +26 -0
  250. package/dist/commands/plugin.denylist.remove.js.map +1 -0
  251. package/dist/commands/plugin.install.d.ts +3 -0
  252. package/dist/commands/plugin.install.d.ts.map +1 -0
  253. package/dist/commands/plugin.install.js +21 -0
  254. package/dist/commands/plugin.install.js.map +1 -0
  255. package/dist/commands/plugin.list.d.ts +3 -0
  256. package/dist/commands/plugin.list.d.ts.map +1 -0
  257. package/dist/commands/plugin.list.js +27 -0
  258. package/dist/commands/plugin.list.js.map +1 -0
  259. package/dist/commands/plugin.org.install.d.ts +3 -0
  260. package/dist/commands/plugin.org.install.d.ts.map +1 -0
  261. package/dist/commands/plugin.org.install.js +24 -0
  262. package/dist/commands/plugin.org.install.js.map +1 -0
  263. package/dist/commands/plugin.org.install_bulk.d.ts +3 -0
  264. package/dist/commands/plugin.org.install_bulk.d.ts.map +1 -0
  265. package/dist/commands/plugin.org.install_bulk.js +35 -0
  266. package/dist/commands/plugin.org.install_bulk.js.map +1 -0
  267. package/dist/commands/plugin.org.list.d.ts +3 -0
  268. package/dist/commands/plugin.org.list.d.ts.map +1 -0
  269. package/dist/commands/plugin.org.list.js +35 -0
  270. package/dist/commands/plugin.org.list.js.map +1 -0
  271. package/dist/commands/plugin.org.set_enabled.d.ts +3 -0
  272. package/dist/commands/plugin.org.set_enabled.d.ts.map +1 -0
  273. package/dist/commands/plugin.org.set_enabled.js +27 -0
  274. package/dist/commands/plugin.org.set_enabled.js.map +1 -0
  275. package/dist/commands/plugin.org.uninstall.d.ts +3 -0
  276. package/dist/commands/plugin.org.uninstall.d.ts.map +1 -0
  277. package/dist/commands/plugin.org.uninstall.js +22 -0
  278. package/dist/commands/plugin.org.uninstall.js.map +1 -0
  279. package/dist/commands/plugin.registry.add.d.ts +3 -0
  280. package/dist/commands/plugin.registry.add.d.ts.map +1 -0
  281. package/dist/commands/plugin.registry.add.js +25 -0
  282. package/dist/commands/plugin.registry.add.js.map +1 -0
  283. package/dist/commands/plugin.registry.list.d.ts +3 -0
  284. package/dist/commands/plugin.registry.list.d.ts.map +1 -0
  285. package/dist/commands/plugin.registry.list.js +18 -0
  286. package/dist/commands/plugin.registry.list.js.map +1 -0
  287. package/dist/commands/plugin.registry.remove.d.ts +3 -0
  288. package/dist/commands/plugin.registry.remove.d.ts.map +1 -0
  289. package/dist/commands/plugin.registry.remove.js +24 -0
  290. package/dist/commands/plugin.registry.remove.js.map +1 -0
  291. package/dist/commands/plugin.registry.sync.d.ts +3 -0
  292. package/dist/commands/plugin.registry.sync.d.ts.map +1 -0
  293. package/dist/commands/plugin.registry.sync.js +26 -0
  294. package/dist/commands/plugin.registry.sync.js.map +1 -0
  295. package/dist/commands/plugin.settings.set_auth_alerts.d.ts +3 -0
  296. package/dist/commands/plugin.settings.set_auth_alerts.d.ts.map +1 -0
  297. package/dist/commands/plugin.settings.set_auth_alerts.js +30 -0
  298. package/dist/commands/plugin.settings.set_auth_alerts.js.map +1 -0
  299. package/dist/commands/plugin.uninstall.d.ts +3 -0
  300. package/dist/commands/plugin.uninstall.d.ts.map +1 -0
  301. package/dist/commands/plugin.uninstall.js +21 -0
  302. package/dist/commands/plugin.uninstall.js.map +1 -0
  303. package/dist/commands/plugin.workspace.set_enabled.d.ts +3 -0
  304. package/dist/commands/plugin.workspace.set_enabled.d.ts.map +1 -0
  305. package/dist/commands/plugin.workspace.set_enabled.js +35 -0
  306. package/dist/commands/plugin.workspace.set_enabled.js.map +1 -0
  307. package/dist/commands/skill.workspace.list.d.ts +3 -0
  308. package/dist/commands/skill.workspace.list.d.ts.map +1 -0
  309. package/dist/commands/skill.workspace.list.js +32 -0
  310. package/dist/commands/skill.workspace.list.js.map +1 -0
  311. package/dist/commands/svg.generate.d.ts +3 -0
  312. package/dist/commands/svg.generate.d.ts.map +1 -0
  313. package/dist/commands/svg.generate.js +29 -0
  314. package/dist/commands/svg.generate.js.map +1 -0
  315. package/dist/commands/system.install.instructions.d.ts +3 -0
  316. package/dist/commands/system.install.instructions.d.ts.map +1 -0
  317. package/dist/commands/system.install.instructions.js +31 -0
  318. package/dist/commands/system.install.instructions.js.map +1 -0
  319. package/dist/commands/user.preferences.get.d.ts +3 -0
  320. package/dist/commands/user.preferences.get.d.ts.map +1 -0
  321. package/dist/commands/user.preferences.get.js +20 -0
  322. package/dist/commands/user.preferences.get.js.map +1 -0
  323. package/dist/commands/user.preferences.read.d.ts +3 -0
  324. package/dist/commands/user.preferences.read.d.ts.map +1 -0
  325. package/dist/commands/user.preferences.read.js +30 -0
  326. package/dist/commands/user.preferences.read.js.map +1 -0
  327. package/dist/commands/user.preferences.update.d.ts +3 -0
  328. package/dist/commands/user.preferences.update.d.ts.map +1 -0
  329. package/dist/commands/user.preferences.update.js +36 -0
  330. package/dist/commands/user.preferences.update.js.map +1 -0
  331. package/dist/commands/user.preferences.write.d.ts +3 -0
  332. package/dist/commands/user.preferences.write.d.ts.map +1 -0
  333. package/dist/commands/user.preferences.write.js +47 -0
  334. package/dist/commands/user.preferences.write.js.map +1 -0
  335. package/dist/commands/video.generate.d.ts +3 -0
  336. package/dist/commands/video.generate.d.ts.map +1 -0
  337. package/dist/commands/video.generate.js +27 -0
  338. package/dist/commands/video.generate.js.map +1 -0
  339. package/dist/commands/workflow.cancel.d.ts +3 -0
  340. package/dist/commands/workflow.cancel.d.ts.map +1 -0
  341. package/dist/commands/workflow.cancel.js +24 -0
  342. package/dist/commands/workflow.cancel.js.map +1 -0
  343. package/dist/commands/workflow.run.d.ts +3 -0
  344. package/dist/commands/workflow.run.d.ts.map +1 -0
  345. package/dist/commands/workflow.run.js +40 -0
  346. package/dist/commands/workflow.run.js.map +1 -0
  347. package/dist/commands/workflow.status.d.ts +3 -0
  348. package/dist/commands/workflow.status.d.ts.map +1 -0
  349. package/dist/commands/workflow.status.js +32 -0
  350. package/dist/commands/workflow.status.js.map +1 -0
  351. package/dist/commands/workspace.create.d.ts +3 -0
  352. package/dist/commands/workspace.create.d.ts.map +1 -0
  353. package/dist/commands/workspace.create.js +23 -0
  354. package/dist/commands/workspace.create.js.map +1 -0
  355. package/dist/commands/workspace.invite.send.d.ts +3 -0
  356. package/dist/commands/workspace.invite.send.d.ts.map +1 -0
  357. package/dist/commands/workspace.invite.send.js +33 -0
  358. package/dist/commands/workspace.invite.send.js.map +1 -0
  359. package/dist/commands/workspace.list.d.ts +3 -0
  360. package/dist/commands/workspace.list.d.ts.map +1 -0
  361. package/dist/commands/workspace.list.js +26 -0
  362. package/dist/commands/workspace.list.js.map +1 -0
  363. package/dist/commands/workspace.member.list.d.ts +3 -0
  364. package/dist/commands/workspace.member.list.d.ts.map +1 -0
  365. package/dist/commands/workspace.member.list.js +25 -0
  366. package/dist/commands/workspace.member.list.js.map +1 -0
  367. package/dist/commands/workspace.model.settings.read.d.ts +3 -0
  368. package/dist/commands/workspace.model.settings.read.d.ts.map +1 -0
  369. package/dist/commands/workspace.model.settings.read.js +21 -0
  370. package/dist/commands/workspace.model.settings.read.js.map +1 -0
  371. package/dist/commands/workspace.model.settings.write.d.ts +3 -0
  372. package/dist/commands/workspace.model.settings.write.d.ts.map +1 -0
  373. package/dist/commands/workspace.model.settings.write.js +25 -0
  374. package/dist/commands/workspace.model.settings.write.js.map +1 -0
  375. package/dist/commands.test.d.ts +2 -0
  376. package/dist/commands.test.d.ts.map +1 -0
  377. package/dist/commands.test.js +1749 -0
  378. package/dist/commands.test.js.map +1 -0
  379. package/dist/components/DevStatus.d.ts +2 -0
  380. package/dist/components/DevStatus.d.ts.map +1 -0
  381. package/dist/components/DevStatus.js +61 -0
  382. package/dist/components/DevStatus.js.map +1 -0
  383. package/dist/components/DevStatus.test.d.ts +2 -0
  384. package/dist/components/DevStatus.test.d.ts.map +1 -0
  385. package/dist/components/DevStatus.test.js +108 -0
  386. package/dist/components/DevStatus.test.js.map +1 -0
  387. package/dist/index.d.ts +3 -0
  388. package/dist/index.d.ts.map +1 -0
  389. package/dist/index.js +278 -0
  390. package/dist/index.js.map +1 -0
  391. package/dist/lib/api-client.d.ts +7 -0
  392. package/dist/lib/api-client.d.ts.map +1 -0
  393. package/dist/lib/api-client.js +40 -0
  394. package/dist/lib/api-client.js.map +1 -0
  395. package/dist/lib/api-client.test.d.ts +2 -0
  396. package/dist/lib/api-client.test.d.ts.map +1 -0
  397. package/dist/lib/api-client.test.js +89 -0
  398. package/dist/lib/api-client.test.js.map +1 -0
  399. package/dist/lib/config.d.ts +12 -0
  400. package/dist/lib/config.d.ts.map +1 -0
  401. package/dist/lib/config.js +32 -0
  402. package/dist/lib/config.js.map +1 -0
  403. package/dist/lib/config.test.d.ts +2 -0
  404. package/dist/lib/config.test.d.ts.map +1 -0
  405. package/dist/lib/config.test.js +103 -0
  406. package/dist/lib/config.test.js.map +1 -0
  407. package/package.json +50 -0
@@ -0,0 +1,1749 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ // Mock config and api-client before importing commands that use them
3
+ vi.mock("./lib/config.js", () => ({
4
+ getToken: vi.fn(() => "test-token"),
5
+ getApiUrl: vi.fn(() => "http://localhost:4000"),
6
+ readConfig: vi.fn(() => ({ token: "test-token", orgSlug: "my-org", workspaceSlug: "default" })),
7
+ writeConfig: vi.fn(),
8
+ clearConfig: vi.fn(),
9
+ }));
10
+ vi.mock("./lib/api-client.js", () => ({
11
+ apiRequest: vi.fn(),
12
+ requireAuth: vi.fn(),
13
+ ApiError: class ApiError extends Error {
14
+ status;
15
+ constructor(status, message) {
16
+ super(message);
17
+ this.status = status;
18
+ this.name = "ApiError";
19
+ }
20
+ },
21
+ }));
22
+ import { authLoginCommand } from "./commands/auth.login.js";
23
+ import { authLogoutCommand } from "./commands/auth.logout.js";
24
+ import { authWhoamiCommand } from "./commands/auth.whoami.js";
25
+ import { orgListCommand } from "./commands/org.list.js";
26
+ import { orgCreateCommand } from "./commands/org.create.js";
27
+ import { orgMemberAddCommand } from "./commands/org.member.add.js";
28
+ import { orgMemberRemoveCommand } from "./commands/org.member.remove.js";
29
+ import { workspaceListCommand } from "./commands/workspace.list.js";
30
+ import { workspaceCreateCommand } from "./commands/workspace.create.js";
31
+ import { chatSendCommand } from "./commands/chat.send.js";
32
+ import { conversationListCommand } from "./commands/conversation.list.js";
33
+ import { conversationDeleteCommand } from "./commands/conversation.delete.js";
34
+ import { conversationArchiveCommand } from "./commands/conversation.archive.js";
35
+ import { conversationRenameCommand } from "./commands/conversation.rename.js";
36
+ import { apiKeyCreateCommand } from "./commands/api-key.create.js";
37
+ import { apiKeyRevokeCommand } from "./commands/api-key.revoke.js";
38
+ import { notificationsListCommand } from "./commands/notifications.list.js";
39
+ import { notificationsMarkCommand } from "./commands/notifications.mark.js";
40
+ import { pluginListCommand } from "./commands/plugin.list.js";
41
+ import { pluginInstallCommand } from "./commands/plugin.install.js";
42
+ import { pluginUninstallCommand } from "./commands/plugin.uninstall.js";
43
+ import { pluginOrgInstallCommand } from "./commands/plugin.org.install.js";
44
+ import { pluginOrgUninstallCommand } from "./commands/plugin.org.uninstall.js";
45
+ import { pluginCatalogGetCommand } from "./commands/plugin.catalog.get.js";
46
+ import { billingStatusCommand } from "./commands/billing.status.js";
47
+ import { billingCreditsPurchaseCommand } from "./commands/billing.credits.purchase.js";
48
+ import { billingSubscriptionReadCommand } from "./commands/billing.subscription.read.js";
49
+ import { agentMcpListCommand } from "./commands/agent.mcp.list.js";
50
+ import { agentSkillListCommand } from "./commands/agent.skill.list.js";
51
+ import { agentToolListCommand } from "./commands/agent.tool.list.js";
52
+ import { orgMemberRoleChangeCommand } from "./commands/org.member.role.change.js";
53
+ import { agentApprovalResolveCommand } from "./commands/agent.approval.resolve.js";
54
+ import { archiveCreateCommand } from "./commands/archive.create.js";
55
+ import { workflowRunCommand } from "./commands/workflow.run.js";
56
+ import { userPreferencesGetCommand } from "./commands/user.preferences.get.js";
57
+ import { userPreferencesUpdateCommand } from "./commands/user.preferences.update.js";
58
+ import { workspaceMemberListCommand } from "./commands/workspace.member.list.js";
59
+ import { workspaceInviteSendCommand } from "./commands/workspace.invite.send.js";
60
+ import { conversationChatCommand } from "./commands/conversation.chat.js";
61
+ import { imageCreateCommand } from "./commands/image.create.js";
62
+ import { documentCreateCommand } from "./commands/document.create.js";
63
+ import { automationListCommand } from "./commands/automation.list.js";
64
+ import { imageListCommand } from "./commands/image.list.js";
65
+ import { imageAnalyzeCommand } from "./commands/image.analyze.js";
66
+ import { documentListCommand } from "./commands/document.list.js";
67
+ import { documentReadCommand } from "./commands/document.read.js";
68
+ import { formCreateCommand } from "./commands/form.create.js";
69
+ import { formSubmitCommand } from "./commands/form.submit.js";
70
+ import { automationCreateCommand } from "./commands/automation.create.js";
71
+ import { automationTriggerCommand } from "./commands/automation.trigger.js";
72
+ import { skillWorkspaceListCommand } from "./commands/skill.workspace.list.js";
73
+ import { agentMemoryRecallCommand } from "./commands/agent.memory.recall.js";
74
+ import { agentMemoryWriteCommand } from "./commands/agent.memory.write.js";
75
+ import { documentsGenerateCommand } from "./commands/documents.generate.js";
76
+ import { imageGenerateCommand } from "./commands/image.generate.js";
77
+ import { orgMemberInviteAcceptCommand } from "./commands/org.member.invite.accept.js";
78
+ import { pluginCatalogBrowseCommand } from "./commands/plugin.catalog.browse.js";
79
+ import { pluginCredentialReauthCommand } from "./commands/plugin.credential.reauth.js";
80
+ import { pluginRegistryAddCommand } from "./commands/plugin.registry.add.js";
81
+ import { pluginRegistryListCommand } from "./commands/plugin.registry.list.js";
82
+ import { svgGenerateCommand } from "./commands/svg.generate.js";
83
+ import { videoGenerateCommand } from "./commands/video.generate.js";
84
+ import { workspaceModelSettingsReadCommand } from "./commands/workspace.model.settings.read.js";
85
+ import { workspaceModelSettingsWriteCommand } from "./commands/workspace.model.settings.write.js";
86
+ import { agentMcpRegisterCommand } from "./commands/agent.mcp.register.js";
87
+ import { agentPlanApproveCommand } from "./commands/agent.plan.approve.js";
88
+ import { agentTaskBackgroundStartCommand } from "./commands/agent.task.background.start.js";
89
+ import { agentTaskBackgroundReadCommand } from "./commands/agent.task.background.read.js";
90
+ import { agentTaskBackgroundCancelCommand } from "./commands/agent.task.background.cancel.js";
91
+ import { assetUploadCommand } from "./commands/asset.upload.js";
92
+ import { billingSubscriptionUpgradeStartCommand } from "./commands/billing.subscription.upgrade.start.js";
93
+ import { brandkitApplyCommand } from "./commands/brandkit.apply.js";
94
+ import { conversationPurgeCommand } from "./commands/conversation.purge.js";
95
+ import { documentsPdfCreateCommand } from "./commands/documents.pdf.create.js";
96
+ import { formFillCommand } from "./commands/form.fill.js";
97
+ import { orgMemberInviteDeclineCommand } from "./commands/org.member.invite.decline.js";
98
+ import { organizationCreateCommand } from "./commands/organization.create.js";
99
+ import { pluginCredentialSetSecretCommand } from "./commands/plugin.credential.set_secret.js";
100
+ import { pluginDenylistAddCommand } from "./commands/plugin.denylist.add.js";
101
+ import { pluginDenylistRemoveCommand } from "./commands/plugin.denylist.remove.js";
102
+ import { pluginOrgInstallBulkCommand } from "./commands/plugin.org.install_bulk.js";
103
+ import { pluginOrgListCommand } from "./commands/plugin.org.list.js";
104
+ import { pluginOrgSetEnabledCommand } from "./commands/plugin.org.set_enabled.js";
105
+ import { pluginRegistryRemoveCommand } from "./commands/plugin.registry.remove.js";
106
+ import * as apiClient from "./lib/api-client.js";
107
+ import * as config from "./lib/config.js";
108
+ const mockApiRequest = vi.mocked(apiClient.apiRequest);
109
+ const mockRequireAuth = vi.mocked(apiClient.requireAuth);
110
+ const mockWriteConfig = vi.mocked(config.writeConfig);
111
+ const mockClearConfig = vi.mocked(config.clearConfig);
112
+ const mockGetToken = vi.mocked(config.getToken);
113
+ beforeEach(() => {
114
+ vi.clearAllMocks();
115
+ mockRequireAuth.mockImplementation(() => { });
116
+ });
117
+ afterEach(() => {
118
+ vi.restoreAllMocks();
119
+ });
120
+ // ---------------------------------------------------------------------------
121
+ // auth login
122
+ // ---------------------------------------------------------------------------
123
+ describe("auth login", () => {
124
+ it("exits 1 if email or password is missing", async () => {
125
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
126
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => { throw new Error("exit"); });
127
+ await expect(() => authLoginCommand.parseAsync(["node", "cli"])).rejects.toThrow("exit");
128
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("email and password are required"));
129
+ consoleSpy.mockRestore();
130
+ exitSpy.mockRestore();
131
+ });
132
+ it("calls API with credentials and stores token", async () => {
133
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
134
+ mockApiRequest.mockResolvedValueOnce({ token: "new-token", user: { email: "user@example.com" } });
135
+ await authLoginCommand.parseAsync(["node", "cli", "--email", "user@example.com", "--password", "secret"]);
136
+ expect(mockApiRequest).toHaveBeenCalledWith("/auth/sign-in/email", expect.objectContaining({ method: "POST" }));
137
+ expect(mockWriteConfig).toHaveBeenCalledWith(expect.objectContaining({ token: "new-token" }));
138
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Authenticated"));
139
+ consoleSpy.mockRestore();
140
+ });
141
+ it("exits 1 on API error during login", async () => {
142
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
143
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => { throw new Error("exit"); });
144
+ mockApiRequest.mockRejectedValueOnce(new Error("Unauthorized"));
145
+ await expect(() => authLoginCommand.parseAsync(["node", "cli", "--email", "a@b.com", "--password", "pw"])).rejects.toThrow("exit");
146
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Error:"));
147
+ consoleSpy.mockRestore();
148
+ exitSpy.mockRestore();
149
+ });
150
+ it("handles response with session.token shape", async () => {
151
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
152
+ mockApiRequest.mockResolvedValueOnce({ session: { token: "session-tok" } });
153
+ await authLoginCommand.parseAsync(["node", "cli", "-e", "a@b.com", "-p", "pw"]);
154
+ expect(mockWriteConfig).toHaveBeenCalledWith(expect.objectContaining({ token: "session-tok" }));
155
+ consoleSpy.mockRestore();
156
+ });
157
+ });
158
+ // ---------------------------------------------------------------------------
159
+ // auth logout
160
+ // ---------------------------------------------------------------------------
161
+ describe("auth logout", () => {
162
+ it("clears config and reports success", async () => {
163
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
164
+ mockGetToken.mockReturnValue("old-token");
165
+ mockApiRequest.mockResolvedValueOnce({});
166
+ await authLogoutCommand.parseAsync(["node", "cli"]);
167
+ expect(mockClearConfig).toHaveBeenCalled();
168
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Signing out"));
169
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Signed out"));
170
+ consoleSpy.mockRestore();
171
+ });
172
+ it("clears config even if sign-out API fails", async () => {
173
+ mockGetToken.mockReturnValue("tok");
174
+ mockApiRequest.mockRejectedValueOnce(new Error("network error"));
175
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
176
+ await authLogoutCommand.parseAsync(["node", "cli"]);
177
+ expect(mockClearConfig).toHaveBeenCalled();
178
+ consoleSpy.mockRestore();
179
+ });
180
+ it("skips sign-out API call when no token is stored", async () => {
181
+ mockGetToken.mockReturnValue(undefined);
182
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
183
+ await authLogoutCommand.parseAsync(["node", "cli"]);
184
+ expect(mockApiRequest).not.toHaveBeenCalled();
185
+ expect(mockClearConfig).toHaveBeenCalled();
186
+ consoleSpy.mockRestore();
187
+ });
188
+ });
189
+ // ---------------------------------------------------------------------------
190
+ // auth whoami
191
+ // ---------------------------------------------------------------------------
192
+ describe("auth whoami", () => {
193
+ it("displays user, org, and workspace", async () => {
194
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
195
+ mockApiRequest.mockResolvedValueOnce({
196
+ user: { email: "mac@example.com" },
197
+ org: { slug: "my-org" },
198
+ workspace: { slug: "default" },
199
+ });
200
+ await authWhoamiCommand.parseAsync(["node", "cli"]);
201
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("mac@example.com"));
202
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("my-org"));
203
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("default"));
204
+ consoleSpy.mockRestore();
205
+ });
206
+ it("falls back to config values for org/workspace", async () => {
207
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
208
+ mockApiRequest.mockResolvedValueOnce({ user: { email: "mac@example.com" } });
209
+ vi.mocked(config.readConfig).mockReturnValue({ orgSlug: "cfg-org", workspaceSlug: "cfg-ws" });
210
+ await authWhoamiCommand.parseAsync(["node", "cli"]);
211
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("cfg-org"));
212
+ consoleSpy.mockRestore();
213
+ });
214
+ it("exits 1 on API error", async () => {
215
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
216
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => { throw new Error("exit"); });
217
+ mockApiRequest.mockRejectedValueOnce(new Error("Forbidden"));
218
+ await expect(() => authWhoamiCommand.parseAsync(["node", "cli"])).rejects.toThrow("exit");
219
+ consoleSpy.mockRestore();
220
+ exitSpy.mockRestore();
221
+ });
222
+ });
223
+ // ---------------------------------------------------------------------------
224
+ // org list
225
+ // ---------------------------------------------------------------------------
226
+ describe("org list", () => {
227
+ it("prints organization list", async () => {
228
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
229
+ mockApiRequest.mockResolvedValueOnce({
230
+ organizations: [{ slug: "acme", name: "ACME Corp" }],
231
+ });
232
+ await orgListCommand.parseAsync(["node", "cli"]);
233
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Organizations"));
234
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("acme"));
235
+ consoleSpy.mockRestore();
236
+ });
237
+ it("prints empty message when no orgs", async () => {
238
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
239
+ mockApiRequest.mockResolvedValueOnce({ organizations: [] });
240
+ await orgListCommand.parseAsync(["node", "cli"]);
241
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("No organizations"));
242
+ consoleSpy.mockRestore();
243
+ });
244
+ it("handles data array shape from API", async () => {
245
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
246
+ mockApiRequest.mockResolvedValueOnce({ data: [{ id: "id1", slug: "org-1", name: "Org 1" }] });
247
+ await orgListCommand.parseAsync(["node", "cli"]);
248
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("org-1"));
249
+ consoleSpy.mockRestore();
250
+ });
251
+ });
252
+ // ---------------------------------------------------------------------------
253
+ // org create
254
+ // ---------------------------------------------------------------------------
255
+ describe("org create", () => {
256
+ it("creates org and prints slug", async () => {
257
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
258
+ mockApiRequest.mockResolvedValueOnce({ organization: { slug: "new-org", name: "New Org" } });
259
+ await orgCreateCommand.parseAsync(["node", "cli", "New Org"]);
260
+ expect(mockApiRequest).toHaveBeenCalledWith("/organizations", expect.objectContaining({ method: "POST" }));
261
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("new-org"));
262
+ consoleSpy.mockRestore();
263
+ });
264
+ it("exits 1 on API error", async () => {
265
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
266
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => { throw new Error("exit"); });
267
+ mockApiRequest.mockRejectedValueOnce(new Error("Conflict"));
268
+ await expect(() => orgCreateCommand.parseAsync(["node", "cli", "Dup"])).rejects.toThrow("exit");
269
+ consoleSpy.mockRestore();
270
+ exitSpy.mockRestore();
271
+ });
272
+ });
273
+ // ---------------------------------------------------------------------------
274
+ // org member add / remove
275
+ // ---------------------------------------------------------------------------
276
+ describe("org member add", () => {
277
+ it("adds member and confirms", async () => {
278
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
279
+ mockApiRequest.mockResolvedValueOnce({});
280
+ await orgMemberAddCommand.parseAsync(["node", "cli", "new@example.com", "--role", "admin"]);
281
+ expect(mockApiRequest).toHaveBeenCalledWith("/org/members", expect.objectContaining({ method: "POST" }));
282
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("new@example.com"));
283
+ consoleSpy.mockRestore();
284
+ });
285
+ it("defaults role to member when no --role flag given", async () => {
286
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
287
+ mockApiRequest.mockResolvedValueOnce({});
288
+ await orgMemberAddCommand.parseAsync(["node", "cli", "x@example.com", "--role", "member"]);
289
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("member"));
290
+ consoleSpy.mockRestore();
291
+ });
292
+ });
293
+ describe("org member remove", () => {
294
+ it("removes member and confirms", async () => {
295
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
296
+ mockApiRequest.mockResolvedValueOnce({});
297
+ await orgMemberRemoveCommand.parseAsync(["node", "cli", "old@example.com"]);
298
+ expect(mockApiRequest).toHaveBeenCalledWith("/org/members", expect.objectContaining({ method: "DELETE" }));
299
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("old@example.com"));
300
+ consoleSpy.mockRestore();
301
+ });
302
+ });
303
+ // ---------------------------------------------------------------------------
304
+ // workspace list / create
305
+ // ---------------------------------------------------------------------------
306
+ describe("workspace list", () => {
307
+ it("prints workspace list", async () => {
308
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
309
+ mockApiRequest.mockResolvedValueOnce({
310
+ workspaces: [{ slug: "default", name: "Default" }],
311
+ });
312
+ await workspaceListCommand.parseAsync(["node", "cli"]);
313
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Workspaces"));
314
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("default"));
315
+ consoleSpy.mockRestore();
316
+ });
317
+ it("prints empty message when no workspaces", async () => {
318
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
319
+ mockApiRequest.mockResolvedValueOnce({ workspaces: [] });
320
+ await workspaceListCommand.parseAsync(["node", "cli"]);
321
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("No workspaces"));
322
+ consoleSpy.mockRestore();
323
+ });
324
+ it("passes org query param when provided", async () => {
325
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
326
+ mockApiRequest.mockResolvedValueOnce({ workspaces: [] });
327
+ await workspaceListCommand.parseAsync(["node", "cli", "--org", "my-org"]);
328
+ expect(mockApiRequest).toHaveBeenCalledWith(expect.stringContaining("my-org"));
329
+ consoleSpy.mockRestore();
330
+ });
331
+ });
332
+ describe("workspace create", () => {
333
+ it("creates workspace and prints slug", async () => {
334
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
335
+ mockApiRequest.mockResolvedValueOnce({ workspace: { slug: "my-ws", name: "My WS" } });
336
+ await workspaceCreateCommand.parseAsync(["node", "cli", "My WS"]);
337
+ expect(mockApiRequest).toHaveBeenCalledWith("/workspaces", expect.objectContaining({ method: "POST" }));
338
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("my-ws"));
339
+ consoleSpy.mockRestore();
340
+ });
341
+ });
342
+ // ---------------------------------------------------------------------------
343
+ // chat send
344
+ // ---------------------------------------------------------------------------
345
+ describe("chat send", () => {
346
+ it("sends message and prints response", async () => {
347
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
348
+ mockApiRequest.mockResolvedValueOnce({ content: "Hello back!" });
349
+ await chatSendCommand.parseAsync(["node", "cli", "hello"]);
350
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("hello"));
351
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Hello back!"));
352
+ consoleSpy.mockRestore();
353
+ });
354
+ it("passes conversation id when provided", async () => {
355
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
356
+ mockApiRequest.mockResolvedValueOnce({ content: "response" });
357
+ await chatSendCommand.parseAsync(["node", "cli", "hi", "--conversation", "cnv_abc"]);
358
+ const calls = mockApiRequest.mock.calls;
359
+ const init = calls[0]?.[1];
360
+ const callBody = JSON.parse(init?.body);
361
+ expect(callBody.conversationId).toBe("cnv_abc");
362
+ consoleSpy.mockRestore();
363
+ });
364
+ it("exits 1 on API error", async () => {
365
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
366
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => { throw new Error("exit"); });
367
+ mockApiRequest.mockRejectedValueOnce(new Error("timeout"));
368
+ await expect(() => chatSendCommand.parseAsync(["node", "cli", "msg"])).rejects.toThrow("exit");
369
+ consoleSpy.mockRestore();
370
+ exitSpy.mockRestore();
371
+ });
372
+ });
373
+ // ---------------------------------------------------------------------------
374
+ // conversation commands
375
+ // ---------------------------------------------------------------------------
376
+ describe("conversation list", () => {
377
+ it("lists conversations", async () => {
378
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
379
+ mockApiRequest.mockResolvedValueOnce({
380
+ conversations: [{ publicId: "cnv_1", title: "First conversation" }],
381
+ });
382
+ await conversationListCommand.parseAsync(["node", "cli"]);
383
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Conversations"));
384
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("cnv_1"));
385
+ consoleSpy.mockRestore();
386
+ });
387
+ it("shows empty message when no conversations", async () => {
388
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
389
+ mockApiRequest.mockResolvedValueOnce({ conversations: [] });
390
+ await conversationListCommand.parseAsync(["node", "cli"]);
391
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("No conversations"));
392
+ consoleSpy.mockRestore();
393
+ });
394
+ it("passes filter and limit params", async () => {
395
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
396
+ mockApiRequest.mockResolvedValueOnce({ conversations: [] });
397
+ await conversationListCommand.parseAsync(["node", "cli", "--filter", "archived", "--limit", "5"]);
398
+ expect(mockApiRequest).toHaveBeenCalledWith(expect.stringContaining("archived"));
399
+ consoleSpy.mockRestore();
400
+ });
401
+ });
402
+ describe("conversation delete", () => {
403
+ it("deletes conversation and confirms", async () => {
404
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
405
+ mockApiRequest.mockResolvedValueOnce({});
406
+ await conversationDeleteCommand.parseAsync(["node", "cli", "cnv_abc"]);
407
+ expect(mockApiRequest).toHaveBeenCalledWith("/conversations/cnv_abc", expect.objectContaining({ method: "DELETE" }));
408
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("cnv_abc"));
409
+ consoleSpy.mockRestore();
410
+ });
411
+ it("exits 1 on not found", async () => {
412
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
413
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => { throw new Error("exit"); });
414
+ mockApiRequest.mockRejectedValueOnce(new Error("Not found"));
415
+ await expect(() => conversationDeleteCommand.parseAsync(["node", "cli", "bad"])).rejects.toThrow("exit");
416
+ consoleSpy.mockRestore();
417
+ exitSpy.mockRestore();
418
+ });
419
+ });
420
+ describe("conversation archive", () => {
421
+ it("archives conversation", async () => {
422
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
423
+ mockApiRequest.mockResolvedValueOnce({});
424
+ await conversationArchiveCommand.parseAsync(["node", "cli", "cnv_abc"]);
425
+ expect(mockApiRequest).toHaveBeenCalledWith("/conversations/cnv_abc/archive", expect.anything());
426
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("archived"));
427
+ consoleSpy.mockRestore();
428
+ });
429
+ it("unarchives when --unarchive flag is set", async () => {
430
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
431
+ mockApiRequest.mockResolvedValueOnce({});
432
+ await conversationArchiveCommand.parseAsync(["node", "cli", "cnv_abc", "--unarchive"]);
433
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("unarchived"));
434
+ consoleSpy.mockRestore();
435
+ });
436
+ });
437
+ describe("conversation rename", () => {
438
+ it("renames conversation", async () => {
439
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
440
+ mockApiRequest.mockResolvedValueOnce({});
441
+ await conversationRenameCommand.parseAsync(["node", "cli", "cnv_abc", "New Title"]);
442
+ expect(mockApiRequest).toHaveBeenCalledWith("/conversations/cnv_abc/rename", expect.objectContaining({ method: "POST" }));
443
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("New Title"));
444
+ consoleSpy.mockRestore();
445
+ });
446
+ });
447
+ // ---------------------------------------------------------------------------
448
+ // api-key
449
+ // ---------------------------------------------------------------------------
450
+ describe("api-key create", () => {
451
+ it("creates API key and displays secret", async () => {
452
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
453
+ mockApiRequest.mockResolvedValueOnce({ id: "key_123", key: "oxk_abc123secret" });
454
+ const origIsTTY = process.stdout.isTTY;
455
+ process.stdout.isTTY = true; // Simulate interactive TTY to show full secret
456
+ await apiKeyCreateCommand.parseAsync(["node", "cli", "my-key"]);
457
+ process.stdout.isTTY = origIsTTY; // Restore
458
+ expect(mockApiRequest).toHaveBeenCalledWith("/api-keys", expect.objectContaining({ method: "POST" }));
459
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("key_123"));
460
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("oxk_abc123secret"));
461
+ consoleSpy.mockRestore();
462
+ });
463
+ it("exits 1 on API error", async () => {
464
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
465
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => { throw new Error("exit"); });
466
+ mockApiRequest.mockRejectedValueOnce(new Error("Quota exceeded"));
467
+ await expect(() => apiKeyCreateCommand.parseAsync(["node", "cli", "key"])).rejects.toThrow("exit");
468
+ consoleSpy.mockRestore();
469
+ exitSpy.mockRestore();
470
+ });
471
+ });
472
+ describe("api-key revoke", () => {
473
+ it("revokes API key", async () => {
474
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
475
+ mockApiRequest.mockResolvedValueOnce({});
476
+ await apiKeyRevokeCommand.parseAsync(["node", "cli", "key_123"]);
477
+ expect(mockApiRequest).toHaveBeenCalledWith("/api-keys/key_123", expect.objectContaining({ method: "DELETE" }));
478
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("key_123"));
479
+ consoleSpy.mockRestore();
480
+ });
481
+ });
482
+ // ---------------------------------------------------------------------------
483
+ // notifications
484
+ // ---------------------------------------------------------------------------
485
+ describe("notifications list", () => {
486
+ it("lists notifications with unread marker", async () => {
487
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
488
+ mockApiRequest.mockResolvedValueOnce({
489
+ notifications: [
490
+ { publicId: "ntf_1", title: "New member joined", readAt: null },
491
+ { publicId: "ntf_2", title: "Subscription renewed", readAt: "2026-06-01" },
492
+ ],
493
+ });
494
+ await notificationsListCommand.parseAsync(["node", "cli"]);
495
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("ntf_1"));
496
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("ntf_2"));
497
+ consoleSpy.mockRestore();
498
+ });
499
+ it("shows empty message when none", async () => {
500
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
501
+ mockApiRequest.mockResolvedValueOnce({ notifications: [] });
502
+ await notificationsListCommand.parseAsync(["node", "cli"]);
503
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("No notifications"));
504
+ consoleSpy.mockRestore();
505
+ });
506
+ it("passes unread filter", async () => {
507
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
508
+ mockApiRequest.mockResolvedValueOnce({ notifications: [] });
509
+ await notificationsListCommand.parseAsync(["node", "cli", "--unread"]);
510
+ expect(mockApiRequest).toHaveBeenCalledWith(expect.stringContaining("unread"));
511
+ consoleSpy.mockRestore();
512
+ });
513
+ });
514
+ describe("notifications mark", () => {
515
+ it("marks notification as read", async () => {
516
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
517
+ mockApiRequest.mockResolvedValueOnce({});
518
+ await notificationsMarkCommand.parseAsync(["node", "cli", "ntf_1"]);
519
+ expect(mockApiRequest).toHaveBeenCalledWith("/notifications/ntf_1/mark", expect.anything());
520
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("read"));
521
+ consoleSpy.mockRestore();
522
+ });
523
+ it("marks notification as unread with --unread flag", async () => {
524
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
525
+ mockApiRequest.mockResolvedValueOnce({});
526
+ await notificationsMarkCommand.parseAsync(["node", "cli", "ntf_1", "--unread"]);
527
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("unread"));
528
+ consoleSpy.mockRestore();
529
+ });
530
+ });
531
+ // ---------------------------------------------------------------------------
532
+ // plugin
533
+ // ---------------------------------------------------------------------------
534
+ describe("plugin list", () => {
535
+ it("lists installed plugins", async () => {
536
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
537
+ mockApiRequest.mockResolvedValueOnce({
538
+ plugins: [{ pluginId: "github", enabled: true }, { pluginId: "slack", enabled: false }],
539
+ });
540
+ await pluginListCommand.parseAsync(["node", "cli"]);
541
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("github"));
542
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("enabled"));
543
+ consoleSpy.mockRestore();
544
+ });
545
+ it("shows empty message when no plugins", async () => {
546
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
547
+ mockApiRequest.mockResolvedValueOnce({ plugins: [] });
548
+ await pluginListCommand.parseAsync(["node", "cli"]);
549
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("No plugins"));
550
+ consoleSpy.mockRestore();
551
+ });
552
+ });
553
+ describe("plugin install", () => {
554
+ it("installs plugin", async () => {
555
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
556
+ mockApiRequest.mockResolvedValueOnce({});
557
+ await pluginInstallCommand.parseAsync(["node", "cli", "github"]);
558
+ expect(mockApiRequest).toHaveBeenCalledWith("/plugins/install", expect.objectContaining({ method: "POST" }));
559
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("github"));
560
+ consoleSpy.mockRestore();
561
+ });
562
+ it("exits 1 on install failure", async () => {
563
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
564
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => { throw new Error("exit"); });
565
+ mockApiRequest.mockRejectedValueOnce(new Error("Not found in catalog"));
566
+ await expect(() => pluginInstallCommand.parseAsync(["node", "cli", "bad-plugin"])).rejects.toThrow("exit");
567
+ consoleSpy.mockRestore();
568
+ exitSpy.mockRestore();
569
+ });
570
+ });
571
+ describe("plugin uninstall", () => {
572
+ it("uninstalls plugin", async () => {
573
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
574
+ mockApiRequest.mockResolvedValueOnce({});
575
+ await pluginUninstallCommand.parseAsync(["node", "cli", "slack"]);
576
+ expect(mockApiRequest).toHaveBeenCalledWith("/plugins/uninstall", expect.objectContaining({ method: "POST" }));
577
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("slack"));
578
+ consoleSpy.mockRestore();
579
+ });
580
+ });
581
+ // ---------------------------------------------------------------------------
582
+ // billing status
583
+ // ---------------------------------------------------------------------------
584
+ describe("billing status", () => {
585
+ it("shows subscription plan and status", async () => {
586
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
587
+ mockApiRequest.mockResolvedValueOnce({
588
+ subscription: {
589
+ plan: { name: "Scale" },
590
+ status: "active",
591
+ currentPeriodEnd: "2026-07-01",
592
+ },
593
+ creditBalance: { balanceUsd: 42.5 },
594
+ });
595
+ await billingStatusCommand.parseAsync(["node", "cli"]);
596
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Scale"));
597
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("active"));
598
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("42.50"));
599
+ consoleSpy.mockRestore();
600
+ });
601
+ it("shows 'No active subscription' when absent", async () => {
602
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
603
+ mockApiRequest.mockResolvedValueOnce({});
604
+ await billingStatusCommand.parseAsync(["node", "cli"]);
605
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("No active subscription"));
606
+ consoleSpy.mockRestore();
607
+ });
608
+ it("exits 1 on API error", async () => {
609
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
610
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => { throw new Error("exit"); });
611
+ mockApiRequest.mockRejectedValueOnce(new Error("Forbidden"));
612
+ await expect(() => billingStatusCommand.parseAsync(["node", "cli"])).rejects.toThrow("exit");
613
+ consoleSpy.mockRestore();
614
+ exitSpy.mockRestore();
615
+ });
616
+ });
617
+ // ---------------------------------------------------------------------------
618
+ // agent mcp list
619
+ // ---------------------------------------------------------------------------
620
+ describe("agent mcp list", () => {
621
+ it("lists MCP servers successfully", async () => {
622
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
623
+ mockApiRequest.mockResolvedValueOnce({
624
+ servers: [{ id: "mcp1", name: "claude", status: "active" }],
625
+ });
626
+ await agentMcpListCommand.parseAsync(["node", "cli"]);
627
+ expect(mockApiRequest).toHaveBeenCalledWith("/agent/mcp/list?", expect.objectContaining({ method: "GET" }));
628
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("MCP Servers"));
629
+ consoleSpy.mockRestore();
630
+ });
631
+ });
632
+ // ---------------------------------------------------------------------------
633
+ // agent skill list
634
+ // ---------------------------------------------------------------------------
635
+ describe("agent skill list", () => {
636
+ it("lists agent skills successfully", async () => {
637
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
638
+ mockApiRequest.mockResolvedValueOnce({
639
+ skills: [{ id: "skill1", name: "memory", description: "Memory management" }],
640
+ });
641
+ await agentSkillListCommand.parseAsync(["node", "cli"]);
642
+ expect(mockApiRequest).toHaveBeenCalledWith("/agent/skill/list?", expect.objectContaining({ method: "GET" }));
643
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Agent Skills"));
644
+ consoleSpy.mockRestore();
645
+ });
646
+ });
647
+ // ---------------------------------------------------------------------------
648
+ // agent tool list
649
+ // ---------------------------------------------------------------------------
650
+ describe("agent tool list", () => {
651
+ it("lists agent tools successfully", async () => {
652
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
653
+ mockApiRequest.mockResolvedValueOnce({
654
+ tools: [{ id: "tool1", name: "search", description: "Search capability" }],
655
+ });
656
+ await agentToolListCommand.parseAsync(["node", "cli"]);
657
+ expect(mockApiRequest).toHaveBeenCalledWith("/agent/tool/list?", expect.objectContaining({ method: "GET" }));
658
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Agent Tools"));
659
+ consoleSpy.mockRestore();
660
+ });
661
+ });
662
+ // ---------------------------------------------------------------------------
663
+ // billing credits purchase
664
+ // ---------------------------------------------------------------------------
665
+ describe("billing credits purchase", () => {
666
+ it("purchases credits successfully", async () => {
667
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
668
+ mockApiRequest.mockResolvedValueOnce({
669
+ credits: 100,
670
+ totalCost: 10,
671
+ });
672
+ await billingCreditsPurchaseCommand.parseAsync(["node", "cli", "-a", "100"]);
673
+ expect(mockApiRequest).toHaveBeenCalledWith("/billing/credits/purchase", expect.objectContaining({ method: "POST" }));
674
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Purchase initiated"));
675
+ consoleSpy.mockRestore();
676
+ });
677
+ });
678
+ // ---------------------------------------------------------------------------
679
+ // billing subscription read
680
+ // ---------------------------------------------------------------------------
681
+ describe("billing subscription read", () => {
682
+ it("reads subscription details successfully", async () => {
683
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
684
+ mockApiRequest.mockResolvedValueOnce({
685
+ subscription: { id: "sub1", plan: "scale", status: "active" },
686
+ });
687
+ await billingSubscriptionReadCommand.parseAsync(["node", "cli"]);
688
+ expect(mockApiRequest).toHaveBeenCalledWith("/billing/subscription/read?", expect.objectContaining({ method: "GET" }));
689
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Current Subscription"));
690
+ consoleSpy.mockRestore();
691
+ });
692
+ });
693
+ // ---------------------------------------------------------------------------
694
+ // plugin org install
695
+ // ---------------------------------------------------------------------------
696
+ describe("plugin org install", () => {
697
+ it("installs plugin for organization", async () => {
698
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
699
+ mockApiRequest.mockResolvedValueOnce({
700
+ id: "plugin1",
701
+ name: "github",
702
+ status: "installed",
703
+ });
704
+ await pluginOrgInstallCommand.parseAsync(["node", "cli", "-n", "github"]);
705
+ expect(mockApiRequest).toHaveBeenCalledWith("/plugin/org/install", expect.objectContaining({ method: "POST" }));
706
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Plugin installed"));
707
+ consoleSpy.mockRestore();
708
+ });
709
+ });
710
+ // ---------------------------------------------------------------------------
711
+ // plugin org uninstall
712
+ // ---------------------------------------------------------------------------
713
+ describe("plugin org uninstall", () => {
714
+ it("uninstalls plugin from organization", async () => {
715
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
716
+ mockApiRequest.mockResolvedValueOnce({
717
+ id: "plugin1",
718
+ status: "uninstalled",
719
+ });
720
+ await pluginOrgUninstallCommand.parseAsync(["node", "cli", "-p", "plugin1"]);
721
+ expect(mockApiRequest).toHaveBeenCalledWith("/plugin/org/uninstall", expect.objectContaining({ method: "POST" }));
722
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Plugin uninstalled"));
723
+ consoleSpy.mockRestore();
724
+ });
725
+ });
726
+ // ---------------------------------------------------------------------------
727
+ // plugin catalog get
728
+ // ---------------------------------------------------------------------------
729
+ describe("plugin catalog get", () => {
730
+ it("browses plugin catalog", async () => {
731
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
732
+ mockApiRequest.mockResolvedValueOnce({
733
+ plugins: [{ id: "p1", name: "github", description: "GitHub integration", category: "vcs" }],
734
+ });
735
+ await pluginCatalogGetCommand.parseAsync(["node", "cli"]);
736
+ expect(mockApiRequest).toHaveBeenCalledWith("/plugin/catalog/get?", expect.objectContaining({ method: "GET" }));
737
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Available Plugins"));
738
+ consoleSpy.mockRestore();
739
+ });
740
+ });
741
+ // ---------------------------------------------------------------------------
742
+ // org member role change
743
+ // ---------------------------------------------------------------------------
744
+ describe("org member role change", () => {
745
+ it("changes member role successfully", async () => {
746
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
747
+ mockApiRequest.mockResolvedValueOnce({
748
+ userId: "user1",
749
+ role: "admin",
750
+ updated: true,
751
+ });
752
+ await orgMemberRoleChangeCommand.parseAsync(["node", "cli", "-u", "user1", "-r", "admin"]);
753
+ expect(mockApiRequest).toHaveBeenCalledWith("/org/member/role-change", expect.objectContaining({ method: "POST" }));
754
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Role updated"));
755
+ consoleSpy.mockRestore();
756
+ });
757
+ });
758
+ // ---------------------------------------------------------------------------
759
+ // agent approval resolve
760
+ // ---------------------------------------------------------------------------
761
+ describe("agent approval resolve", () => {
762
+ it("resolves approval with approve decision", async () => {
763
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
764
+ mockApiRequest.mockResolvedValueOnce({ id: "apr1", status: "approved" });
765
+ await agentApprovalResolveCommand.parseAsync(["node", "cli", "-a", "apr1", "-d", "approve"]);
766
+ expect(mockApiRequest).toHaveBeenCalledWith("/agent/approval/resolve", expect.objectContaining({ method: "POST" }));
767
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("approved"));
768
+ consoleSpy.mockRestore();
769
+ });
770
+ it("rejects invalid decision", async () => {
771
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => { throw new Error("exit"); });
772
+ await expect(() => agentApprovalResolveCommand.parseAsync(["node", "cli", "-a", "apr1", "-d", "invalid"])).rejects.toThrow();
773
+ exitSpy.mockRestore();
774
+ });
775
+ });
776
+ // ---------------------------------------------------------------------------
777
+ // archive create
778
+ // ---------------------------------------------------------------------------
779
+ describe("archive create", () => {
780
+ it("creates archive from conversation", async () => {
781
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
782
+ mockApiRequest.mockResolvedValueOnce({ id: "arc1", name: "Archive 1", status: "created" });
783
+ await archiveCreateCommand.parseAsync(["node", "cli", "-c", "conv1", "-n", "My Archive"]);
784
+ expect(mockApiRequest).toHaveBeenCalledWith("/archive/create", expect.objectContaining({ method: "POST" }));
785
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Archive created"));
786
+ consoleSpy.mockRestore();
787
+ });
788
+ });
789
+ // ---------------------------------------------------------------------------
790
+ // workflow run
791
+ // ---------------------------------------------------------------------------
792
+ describe("workflow run", () => {
793
+ it("runs workflow with input", async () => {
794
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
795
+ mockApiRequest.mockResolvedValueOnce({ id: "run1", status: "started" });
796
+ await workflowRunCommand.parseAsync(["node", "cli", "-w", "wf1", "--input", '{"key":"value"}']);
797
+ expect(mockApiRequest).toHaveBeenCalledWith("/workflow/run", expect.objectContaining({ method: "POST" }));
798
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("started"));
799
+ consoleSpy.mockRestore();
800
+ });
801
+ });
802
+ // ---------------------------------------------------------------------------
803
+ // user preferences
804
+ // ---------------------------------------------------------------------------
805
+ describe("user preferences get", () => {
806
+ it("fetches user preferences", async () => {
807
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
808
+ mockApiRequest.mockResolvedValueOnce({ theme: "dark", language: "en" });
809
+ await userPreferencesGetCommand.parseAsync(["node", "cli"]);
810
+ expect(mockApiRequest).toHaveBeenCalledWith("/user/preferences/get", expect.any(Object));
811
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("dark"));
812
+ consoleSpy.mockRestore();
813
+ });
814
+ });
815
+ describe("user preferences update", () => {
816
+ it("updates user preferences", async () => {
817
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
818
+ mockApiRequest.mockResolvedValueOnce({ theme: "light" });
819
+ await userPreferencesUpdateCommand.parseAsync(["node", "cli", "-t", "light"]);
820
+ expect(mockApiRequest).toHaveBeenCalledWith("/user/preferences/update", expect.objectContaining({ method: "POST" }));
821
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("light"));
822
+ consoleSpy.mockRestore();
823
+ });
824
+ });
825
+ // ---------------------------------------------------------------------------
826
+ // workspace management
827
+ // ---------------------------------------------------------------------------
828
+ describe("workspace member list", () => {
829
+ it("lists workspace members", async () => {
830
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
831
+ mockApiRequest.mockResolvedValueOnce([{ id: "m1", email: "user@example.com", role: "member", joined_at: "2026-06-08" }]);
832
+ await workspaceMemberListCommand.parseAsync(["node", "cli"]);
833
+ expect(mockApiRequest).toHaveBeenCalled();
834
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("member(s)"));
835
+ consoleSpy.mockRestore();
836
+ });
837
+ });
838
+ describe("workspace invite send", () => {
839
+ it("sends workspace invitation", async () => {
840
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
841
+ mockApiRequest.mockResolvedValueOnce({ id: "inv1", status: "sent" });
842
+ await workspaceInviteSendCommand.parseAsync(["node", "cli", "-e", "user@example.com"]);
843
+ expect(mockApiRequest).toHaveBeenCalledWith("/workspace/invite/send", expect.objectContaining({ method: "POST" }));
844
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Invitation sent"));
845
+ consoleSpy.mockRestore();
846
+ });
847
+ });
848
+ // ---------------------------------------------------------------------------
849
+ // conversation chat
850
+ // ---------------------------------------------------------------------------
851
+ describe("conversation chat", () => {
852
+ it("sends chat message", async () => {
853
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
854
+ mockApiRequest.mockResolvedValueOnce({ id: "msg1", created_at: "2026-06-08T00:00:00Z" });
855
+ await conversationChatCommand.parseAsync(["node", "cli", "-c", "conv1", "-m", "Hello"]);
856
+ expect(mockApiRequest).toHaveBeenCalledWith("/conversation/chat", expect.objectContaining({ method: "POST" }));
857
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Message sent"));
858
+ consoleSpy.mockRestore();
859
+ });
860
+ });
861
+ // ---------------------------------------------------------------------------
862
+ // image management
863
+ // ---------------------------------------------------------------------------
864
+ describe("image create", () => {
865
+ it("creates image from prompt", async () => {
866
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
867
+ mockApiRequest.mockResolvedValueOnce({ id: "img1", url: "https://example.com/img1.jpg" });
868
+ await imageCreateCommand.parseAsync(["node", "cli", "-p", "A blue sky"]);
869
+ expect(mockApiRequest).toHaveBeenCalledWith("/image/create", expect.objectContaining({ method: "POST" }));
870
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Image created"));
871
+ consoleSpy.mockRestore();
872
+ });
873
+ });
874
+ describe("image list", () => {
875
+ it("lists images", async () => {
876
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
877
+ mockApiRequest.mockResolvedValueOnce({ images: [{ id: "img1", url: "https://example.com/img1.jpg", prompt: "Blue sky", created_at: "2026-06-08" }] });
878
+ await imageListCommand.parseAsync(["node", "cli"]);
879
+ expect(mockApiRequest).toHaveBeenCalled();
880
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Images"));
881
+ consoleSpy.mockRestore();
882
+ });
883
+ });
884
+ describe("image analyze", () => {
885
+ it("analyzes image", async () => {
886
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
887
+ mockApiRequest.mockResolvedValueOnce({ analysis: "sky", tags: ["nature", "outdoor"] });
888
+ await imageAnalyzeCommand.parseAsync(["node", "cli", "-i", "img1"]);
889
+ expect(mockApiRequest).toHaveBeenCalledWith("/image/analyze", expect.objectContaining({ method: "POST" }));
890
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Analysis"));
891
+ consoleSpy.mockRestore();
892
+ });
893
+ });
894
+ // ---------------------------------------------------------------------------
895
+ // document management
896
+ // ---------------------------------------------------------------------------
897
+ describe("document create", () => {
898
+ it("creates document", async () => {
899
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
900
+ mockApiRequest.mockResolvedValueOnce({ id: "doc1", title: "My Doc" });
901
+ await documentCreateCommand.parseAsync(["node", "cli", "-t", "My Doc"]);
902
+ expect(mockApiRequest).toHaveBeenCalledWith("/document/create", expect.objectContaining({ method: "POST" }));
903
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Document created"));
904
+ consoleSpy.mockRestore();
905
+ });
906
+ });
907
+ describe("document list", () => {
908
+ it("lists documents", async () => {
909
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
910
+ mockApiRequest.mockResolvedValueOnce({ documents: [{ id: "doc1", title: "Doc 1", created_at: "2026-06-08", updated_at: "2026-06-08", author: "user" }] });
911
+ await documentListCommand.parseAsync(["node", "cli"]);
912
+ expect(mockApiRequest).toHaveBeenCalled();
913
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Documents"));
914
+ consoleSpy.mockRestore();
915
+ });
916
+ });
917
+ describe("document read", () => {
918
+ it("reads document", async () => {
919
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
920
+ mockApiRequest.mockResolvedValueOnce({ title: "Doc 1", content: "Content...", metadata: {}, created_at: "2026-06-08" });
921
+ await documentReadCommand.parseAsync(["node", "cli", "-d", "doc1"]);
922
+ expect(mockApiRequest).toHaveBeenCalled();
923
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Title:"));
924
+ consoleSpy.mockRestore();
925
+ });
926
+ });
927
+ // ---------------------------------------------------------------------------
928
+ // form management
929
+ // ---------------------------------------------------------------------------
930
+ describe("form create", () => {
931
+ it("creates form", async () => {
932
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
933
+ mockApiRequest.mockResolvedValueOnce({ id: "form1", title: "Survey" });
934
+ await formCreateCommand.parseAsync(["node", "cli", "-t", "Survey"]);
935
+ expect(mockApiRequest).toHaveBeenCalledWith("/form/create", expect.objectContaining({ method: "POST" }));
936
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Form created"));
937
+ consoleSpy.mockRestore();
938
+ });
939
+ });
940
+ describe("form submit", () => {
941
+ it("submits form", async () => {
942
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
943
+ mockApiRequest.mockResolvedValueOnce({ id: "sub1", status: "submitted" });
944
+ await formSubmitCommand.parseAsync(["node", "cli", "-f", "form1"]);
945
+ expect(mockApiRequest).toHaveBeenCalledWith("/form/submit", expect.objectContaining({ method: "POST" }));
946
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("submitted"));
947
+ consoleSpy.mockRestore();
948
+ });
949
+ });
950
+ // ---------------------------------------------------------------------------
951
+ // automation management
952
+ // ---------------------------------------------------------------------------
953
+ describe("automation list", () => {
954
+ it("lists automations", async () => {
955
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
956
+ mockApiRequest.mockResolvedValueOnce([{ id: "auto1", name: "Auto 1", status: "active", triggers: ["event1"] }]);
957
+ await automationListCommand.parseAsync(["node", "cli"]);
958
+ expect(mockApiRequest).toHaveBeenCalled();
959
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("automation(s)"));
960
+ consoleSpy.mockRestore();
961
+ });
962
+ });
963
+ describe("automation create", () => {
964
+ it("creates automation", async () => {
965
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
966
+ mockApiRequest.mockResolvedValueOnce({ id: "auto1", name: "My Automation" });
967
+ await automationCreateCommand.parseAsync(["node", "cli", "-n", "My Automation"]);
968
+ expect(mockApiRequest).toHaveBeenCalledWith("/automation/create", expect.objectContaining({ method: "POST" }));
969
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Automation created"));
970
+ consoleSpy.mockRestore();
971
+ });
972
+ });
973
+ describe("automation trigger", () => {
974
+ it("triggers automation", async () => {
975
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
976
+ mockApiRequest.mockResolvedValueOnce({ id: "exec1", status: "running" });
977
+ await automationTriggerCommand.parseAsync(["node", "cli", "-a", "auto1"]);
978
+ expect(mockApiRequest).toHaveBeenCalledWith("/automation/trigger", expect.objectContaining({ method: "POST" }));
979
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("running"));
980
+ consoleSpy.mockRestore();
981
+ });
982
+ });
983
+ // ---------------------------------------------------------------------------
984
+ // skill management
985
+ // ---------------------------------------------------------------------------
986
+ describe("skill workspace list", () => {
987
+ it("lists workspace skills", async () => {
988
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
989
+ mockApiRequest.mockResolvedValueOnce({ skills: [{ id: "skill1", name: "Research", enabled: true, description: "Research skill" }] });
990
+ await skillWorkspaceListCommand.parseAsync(["node", "cli"]);
991
+ expect(mockApiRequest).toHaveBeenCalled();
992
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Workspace skills"));
993
+ consoleSpy.mockRestore();
994
+ });
995
+ });
996
+ // ---------------------------------------------------------------------------
997
+ // agent memory commands
998
+ // ---------------------------------------------------------------------------
999
+ describe("agent memory recall", () => {
1000
+ it("recalls memory observations", async () => {
1001
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1002
+ const mockResult = { observations: [{ id: "obs1", text: "User prefers dark mode", score: 0.9 }] };
1003
+ mockApiRequest.mockResolvedValueOnce(mockResult);
1004
+ await agentMemoryRecallCommand.parseAsync(["node", "cli", "-a", "agent1", "-q", "user preferences"]);
1005
+ expect(mockApiRequest).toHaveBeenCalledWith("/agent/memory/recall", expect.objectContaining({ method: "POST" }));
1006
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("obs1"));
1007
+ consoleSpy.mockRestore();
1008
+ });
1009
+ it("handles recall failure", async () => {
1010
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1011
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1012
+ mockApiRequest.mockRejectedValueOnce(new Error("Network error"));
1013
+ await expect(agentMemoryRecallCommand.parseAsync(["node", "cli", "-a", "agent1", "-q", "query"])).rejects.toThrow();
1014
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to recall"), expect.any(Error));
1015
+ consoleSpy.mockRestore();
1016
+ exitSpy.mockRestore();
1017
+ });
1018
+ });
1019
+ describe("agent memory write", () => {
1020
+ it("writes a memory observation", async () => {
1021
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1022
+ const mockResult = { id: "obs2", status: "stored" };
1023
+ mockApiRequest.mockResolvedValueOnce(mockResult);
1024
+ await agentMemoryWriteCommand.parseAsync(["node", "cli", "-a", "agent1", "-t", "User prefers TypeScript"]);
1025
+ expect(mockApiRequest).toHaveBeenCalledWith("/agent/memory/write", expect.objectContaining({ method: "POST" }));
1026
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("obs2"));
1027
+ consoleSpy.mockRestore();
1028
+ });
1029
+ it("writes a memory observation with tags", async () => {
1030
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1031
+ mockApiRequest.mockResolvedValueOnce({ id: "obs3", status: "stored" });
1032
+ await agentMemoryWriteCommand.parseAsync(["node", "cli", "-a", "agent1", "-t", "Uses dark mode", "--tags", "ui,preferences"]);
1033
+ const callBody = JSON.parse(mockApiRequest.mock.calls[0][1].body);
1034
+ expect(callBody.tags).toEqual(["ui", "preferences"]);
1035
+ consoleSpy.mockRestore();
1036
+ });
1037
+ it("handles write failure", async () => {
1038
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1039
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1040
+ mockApiRequest.mockRejectedValueOnce(new Error("Network error"));
1041
+ await expect(agentMemoryWriteCommand.parseAsync(["node", "cli", "-a", "agent1", "-t", "text"])).rejects.toThrow();
1042
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to write"), expect.any(Error));
1043
+ consoleSpy.mockRestore();
1044
+ exitSpy.mockRestore();
1045
+ });
1046
+ });
1047
+ // ---------------------------------------------------------------------------
1048
+ // documents generate
1049
+ // ---------------------------------------------------------------------------
1050
+ describe("documents generate", () => {
1051
+ it("generates a document from template", async () => {
1052
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1053
+ const mockResult = { id: "doc1", status: "complete", url: "https://example.com/doc.pdf" };
1054
+ mockApiRequest.mockResolvedValueOnce(mockResult);
1055
+ await documentsGenerateCommand.parseAsync(["node", "cli", "-t", "report", "-c", '{"title":"Q1 Report"}']);
1056
+ expect(mockApiRequest).toHaveBeenCalledWith("/documents/generate", expect.objectContaining({ method: "POST" }));
1057
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("doc1"));
1058
+ consoleSpy.mockRestore();
1059
+ });
1060
+ it("fails on invalid JSON context", async () => {
1061
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1062
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1063
+ await expect(documentsGenerateCommand.parseAsync(["node", "cli", "-t", "report", "-c", "not-json"])).rejects.toThrow();
1064
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Invalid JSON"), expect.anything());
1065
+ consoleSpy.mockRestore();
1066
+ exitSpy.mockRestore();
1067
+ });
1068
+ it("handles generate failure", async () => {
1069
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1070
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1071
+ mockApiRequest.mockRejectedValueOnce(new Error("Template not found"));
1072
+ await expect(documentsGenerateCommand.parseAsync(["node", "cli", "-t", "report", "-c", '{}'])).rejects.toThrow();
1073
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to generate"), expect.any(Error));
1074
+ consoleSpy.mockRestore();
1075
+ exitSpy.mockRestore();
1076
+ });
1077
+ });
1078
+ // ---------------------------------------------------------------------------
1079
+ // image generate
1080
+ // ---------------------------------------------------------------------------
1081
+ describe("image generate", () => {
1082
+ it("generates an image and logs JSON result", async () => {
1083
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1084
+ const mockResult = { url: "https://example.com/img.png", id: "img1" };
1085
+ mockApiRequest.mockResolvedValueOnce(mockResult);
1086
+ await imageGenerateCommand.parseAsync(["node", "cli", "-p", "A sunset over the ocean"]);
1087
+ expect(mockApiRequest).toHaveBeenCalledWith("/image/generate", expect.objectContaining({ method: "POST" }));
1088
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("img1"));
1089
+ consoleSpy.mockRestore();
1090
+ });
1091
+ it("handles generate failure", async () => {
1092
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1093
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1094
+ mockApiRequest.mockRejectedValueOnce(new Error("Model not found"));
1095
+ await expect(imageGenerateCommand.parseAsync(["node", "cli", "-p", "a cat"])).rejects.toThrow();
1096
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to generate"), expect.any(Error));
1097
+ consoleSpy.mockRestore();
1098
+ exitSpy.mockRestore();
1099
+ });
1100
+ });
1101
+ // ---------------------------------------------------------------------------
1102
+ // org member invite accept
1103
+ // ---------------------------------------------------------------------------
1104
+ describe("org member invite accept", () => {
1105
+ it("accepts an invitation", async () => {
1106
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1107
+ mockApiRequest.mockResolvedValueOnce({ status: "accepted", orgSlug: "my-org" });
1108
+ await orgMemberInviteAcceptCommand.parseAsync(["node", "cli", "-i", "invite123"]);
1109
+ expect(mockApiRequest).toHaveBeenCalledWith("/org/member/invite/accept", expect.objectContaining({ method: "POST" }));
1110
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("accepted"));
1111
+ consoleSpy.mockRestore();
1112
+ });
1113
+ it("handles accept failure", async () => {
1114
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1115
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1116
+ mockApiRequest.mockRejectedValueOnce(new Error("Invitation expired"));
1117
+ await expect(orgMemberInviteAcceptCommand.parseAsync(["node", "cli", "-i", "inv1"])).rejects.toThrow();
1118
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to accept"), expect.any(Error));
1119
+ consoleSpy.mockRestore();
1120
+ exitSpy.mockRestore();
1121
+ });
1122
+ });
1123
+ // ---------------------------------------------------------------------------
1124
+ // plugin catalog browse
1125
+ // ---------------------------------------------------------------------------
1126
+ describe("plugin catalog browse", () => {
1127
+ it("browses the plugin catalog", async () => {
1128
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1129
+ const mockResult = { plugins: [{ id: "p1", name: "Slack", category: "messaging" }], total: 1 };
1130
+ mockApiRequest.mockResolvedValueOnce(mockResult);
1131
+ await pluginCatalogBrowseCommand.parseAsync(["node", "cli"]);
1132
+ expect(mockApiRequest).toHaveBeenCalledWith("/plugin/catalog/browse", expect.objectContaining({ method: "GET" }));
1133
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Slack"));
1134
+ consoleSpy.mockRestore();
1135
+ });
1136
+ it("handles browse failure", async () => {
1137
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1138
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1139
+ mockApiRequest.mockRejectedValueOnce(new Error("Service unavailable"));
1140
+ await expect(pluginCatalogBrowseCommand.parseAsync(["node", "cli"])).rejects.toThrow();
1141
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to browse"), expect.any(Error));
1142
+ consoleSpy.mockRestore();
1143
+ exitSpy.mockRestore();
1144
+ });
1145
+ });
1146
+ // ---------------------------------------------------------------------------
1147
+ // plugin credential reauth
1148
+ // ---------------------------------------------------------------------------
1149
+ describe("plugin credential reauth", () => {
1150
+ it("re-authenticates plugin credentials", async () => {
1151
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1152
+ mockApiRequest.mockResolvedValueOnce({ status: "reauthenticated", pluginId: "slack" });
1153
+ await pluginCredentialReauthCommand.parseAsync(["node", "cli", "-p", "slack"]);
1154
+ expect(mockApiRequest).toHaveBeenCalledWith("/plugin/credential/reauth", expect.objectContaining({ method: "POST" }));
1155
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("reauthenticated"));
1156
+ consoleSpy.mockRestore();
1157
+ });
1158
+ it("handles reauth failure", async () => {
1159
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1160
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1161
+ mockApiRequest.mockRejectedValueOnce(new Error("OAuth error"));
1162
+ await expect(pluginCredentialReauthCommand.parseAsync(["node", "cli", "-p", "slack"])).rejects.toThrow();
1163
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to re-authenticate"), expect.any(Error));
1164
+ consoleSpy.mockRestore();
1165
+ exitSpy.mockRestore();
1166
+ });
1167
+ });
1168
+ // ---------------------------------------------------------------------------
1169
+ // plugin registry
1170
+ // ---------------------------------------------------------------------------
1171
+ describe("plugin registry list", () => {
1172
+ it("lists plugin registries", async () => {
1173
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1174
+ mockApiRequest.mockResolvedValueOnce({ registries: [{ id: "reg1", name: "Official", url: "https://registry.oxagen.ai" }] });
1175
+ await pluginRegistryListCommand.parseAsync(["node", "cli"]);
1176
+ expect(mockApiRequest).toHaveBeenCalledWith("/plugin/registry/list", expect.objectContaining({ method: "GET" }));
1177
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Official"));
1178
+ consoleSpy.mockRestore();
1179
+ });
1180
+ it("handles list failure", async () => {
1181
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1182
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1183
+ mockApiRequest.mockRejectedValueOnce(new Error("Network error"));
1184
+ await expect(pluginRegistryListCommand.parseAsync(["node", "cli"])).rejects.toThrow();
1185
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to list"), expect.any(Error));
1186
+ consoleSpy.mockRestore();
1187
+ exitSpy.mockRestore();
1188
+ });
1189
+ });
1190
+ describe("plugin registry add", () => {
1191
+ it("adds a plugin registry", async () => {
1192
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1193
+ mockApiRequest.mockResolvedValueOnce({ id: "reg2", name: "Private", url: "https://private.example.com" });
1194
+ await pluginRegistryAddCommand.parseAsync(["node", "cli", "-n", "Private", "-u", "https://private.example.com"]);
1195
+ expect(mockApiRequest).toHaveBeenCalledWith("/plugin/registry/add", expect.objectContaining({ method: "POST" }));
1196
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("reg2"));
1197
+ consoleSpy.mockRestore();
1198
+ });
1199
+ it("handles add failure", async () => {
1200
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1201
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1202
+ mockApiRequest.mockRejectedValueOnce(new Error("Registry already exists"));
1203
+ await expect(pluginRegistryAddCommand.parseAsync(["node", "cli", "-n", "Private", "-u", "https://x.com"])).rejects.toThrow();
1204
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to add"), expect.any(Error));
1205
+ consoleSpy.mockRestore();
1206
+ exitSpy.mockRestore();
1207
+ });
1208
+ });
1209
+ // ---------------------------------------------------------------------------
1210
+ // svg generate
1211
+ // ---------------------------------------------------------------------------
1212
+ describe("svg generate", () => {
1213
+ it("generates SVG and logs it", async () => {
1214
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1215
+ mockApiRequest.mockResolvedValueOnce({ svg: "<svg><rect/></svg>" });
1216
+ await svgGenerateCommand.parseAsync(["node", "cli", "-d", "A red circle"]);
1217
+ expect(mockApiRequest).toHaveBeenCalledWith("/svg/generate", expect.objectContaining({ method: "POST" }));
1218
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("<svg>"));
1219
+ consoleSpy.mockRestore();
1220
+ });
1221
+ it("handles generate failure", async () => {
1222
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1223
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1224
+ mockApiRequest.mockRejectedValueOnce(new Error("Generation failed"));
1225
+ await expect(svgGenerateCommand.parseAsync(["node", "cli", "-d", "circle"])).rejects.toThrow();
1226
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to generate"), expect.any(Error));
1227
+ consoleSpy.mockRestore();
1228
+ exitSpy.mockRestore();
1229
+ });
1230
+ });
1231
+ // ---------------------------------------------------------------------------
1232
+ // video generate
1233
+ // ---------------------------------------------------------------------------
1234
+ describe("video generate", () => {
1235
+ it("generates a video", async () => {
1236
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1237
+ mockApiRequest.mockResolvedValueOnce({ id: "vid1", status: "processing", url: null });
1238
+ await videoGenerateCommand.parseAsync(["node", "cli", "-p", "A flying eagle"]);
1239
+ expect(mockApiRequest).toHaveBeenCalledWith("/video/generate", expect.objectContaining({ method: "POST" }));
1240
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("vid1"));
1241
+ consoleSpy.mockRestore();
1242
+ });
1243
+ it("handles generate failure", async () => {
1244
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1245
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1246
+ mockApiRequest.mockRejectedValueOnce(new Error("Model not available"));
1247
+ await expect(videoGenerateCommand.parseAsync(["node", "cli", "-p", "a cat"])).rejects.toThrow();
1248
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to generate"), expect.any(Error));
1249
+ consoleSpy.mockRestore();
1250
+ exitSpy.mockRestore();
1251
+ });
1252
+ });
1253
+ // ---------------------------------------------------------------------------
1254
+ // workspace model settings
1255
+ // ---------------------------------------------------------------------------
1256
+ describe("workspace model settings read", () => {
1257
+ it("reads workspace model settings", async () => {
1258
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1259
+ mockApiRequest.mockResolvedValueOnce({ defaultModel: "claude-haiku-4-5-20251001", maxTokens: 4096 });
1260
+ await workspaceModelSettingsReadCommand.parseAsync(["node", "cli"]);
1261
+ expect(mockApiRequest).toHaveBeenCalledWith("/workspace/model-settings/read", expect.objectContaining({ method: "POST" }));
1262
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("defaultModel"));
1263
+ consoleSpy.mockRestore();
1264
+ });
1265
+ it("handles read failure", async () => {
1266
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1267
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1268
+ mockApiRequest.mockRejectedValueOnce(new Error("Workspace not found"));
1269
+ await expect(workspaceModelSettingsReadCommand.parseAsync(["node", "cli"])).rejects.toThrow();
1270
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to read"), expect.any(Error));
1271
+ consoleSpy.mockRestore();
1272
+ exitSpy.mockRestore();
1273
+ });
1274
+ });
1275
+ describe("workspace model settings write", () => {
1276
+ it("writes workspace model settings", async () => {
1277
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1278
+ mockApiRequest.mockResolvedValueOnce({ success: true, key: "defaultModel", value: "claude-sonnet-4-6" });
1279
+ await workspaceModelSettingsWriteCommand.parseAsync(["node", "cli", "-k", "defaultModel", "-v", "claude-sonnet-4-6"]);
1280
+ expect(mockApiRequest).toHaveBeenCalledWith("/workspace/model-settings/write", expect.objectContaining({ method: "POST" }));
1281
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("defaultModel"));
1282
+ consoleSpy.mockRestore();
1283
+ });
1284
+ it("handles write failure", async () => {
1285
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1286
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1287
+ mockApiRequest.mockRejectedValueOnce(new Error("Invalid setting key"));
1288
+ await expect(workspaceModelSettingsWriteCommand.parseAsync(["node", "cli", "-k", "badKey", "-v", "value"])).rejects.toThrow();
1289
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to write"), expect.any(Error));
1290
+ consoleSpy.mockRestore();
1291
+ exitSpy.mockRestore();
1292
+ });
1293
+ });
1294
+ // ---------------------------------------------------------------------------
1295
+ // agent mcp register
1296
+ // ---------------------------------------------------------------------------
1297
+ describe("agent mcp register", () => {
1298
+ it("registers an MCP server", async () => {
1299
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1300
+ mockApiRequest.mockResolvedValueOnce({ mcpServerId: "mcp1", healthStatus: "healthy", discoveredTools: ["tool1", "tool2"] });
1301
+ await agentMcpRegisterCommand.parseAsync(["node", "cli", "-n", "My MCP", "-u", "https://mcp.example.com", "-t", "streamable-http"]);
1302
+ expect(mockApiRequest).toHaveBeenCalledWith("/agent/mcp/register", expect.objectContaining({ method: "POST" }));
1303
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("mcp1"));
1304
+ consoleSpy.mockRestore();
1305
+ });
1306
+ it("handles registration failure", async () => {
1307
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1308
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1309
+ mockApiRequest.mockRejectedValueOnce(new Error("Bad URL"));
1310
+ await expect(agentMcpRegisterCommand.parseAsync(["node", "cli", "-n", "M", "-u", "http://x", "-t", "stdio"])).rejects.toThrow();
1311
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Error:"));
1312
+ consoleSpy.mockRestore();
1313
+ exitSpy.mockRestore();
1314
+ });
1315
+ });
1316
+ // ---------------------------------------------------------------------------
1317
+ // agent plan approve
1318
+ // ---------------------------------------------------------------------------
1319
+ describe("agent plan approve", () => {
1320
+ it("approves a plan", async () => {
1321
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1322
+ mockApiRequest.mockResolvedValueOnce({ planId: "plan1", status: "approved" });
1323
+ await agentPlanApproveCommand.parseAsync(["node", "cli", "-p", "plan1", "-d", "approve"]);
1324
+ expect(mockApiRequest).toHaveBeenCalledWith("/agent/plan/approve", expect.objectContaining({ method: "POST" }));
1325
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("approved"));
1326
+ consoleSpy.mockRestore();
1327
+ });
1328
+ it("handles approval failure", async () => {
1329
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1330
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1331
+ mockApiRequest.mockRejectedValueOnce(new Error("Plan not found"));
1332
+ await expect(agentPlanApproveCommand.parseAsync(["node", "cli", "-p", "p1", "-d", "deny"])).rejects.toThrow();
1333
+ consoleSpy.mockRestore();
1334
+ exitSpy.mockRestore();
1335
+ });
1336
+ });
1337
+ // ---------------------------------------------------------------------------
1338
+ // agent task background
1339
+ // ---------------------------------------------------------------------------
1340
+ describe("agent task background start", () => {
1341
+ it("starts a background task", async () => {
1342
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1343
+ mockApiRequest.mockResolvedValueOnce({ taskId: "task1", inngestRunId: "run1" });
1344
+ await agentTaskBackgroundStartCommand.parseAsync(["node", "cli", "-k", "research", "--payload", '{"query":"test"}']);
1345
+ expect(mockApiRequest).toHaveBeenCalledWith("/agent/task/background/start", expect.objectContaining({ method: "POST" }));
1346
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("task1"));
1347
+ consoleSpy.mockRestore();
1348
+ });
1349
+ it("handles start failure", async () => {
1350
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1351
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1352
+ mockApiRequest.mockRejectedValueOnce(new Error("Queue full"));
1353
+ await expect(agentTaskBackgroundStartCommand.parseAsync(["node", "cli", "-k", "kind", "--payload", "{}"])).rejects.toThrow();
1354
+ consoleSpy.mockRestore();
1355
+ exitSpy.mockRestore();
1356
+ });
1357
+ });
1358
+ describe("agent task background read", () => {
1359
+ it("reads task status", async () => {
1360
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1361
+ mockApiRequest.mockResolvedValueOnce({ taskId: "task1", kind: "research", status: "completed", label: "My task", resultPayload: { answer: "42" }, failureReason: null, createdAt: "2026-06-08", startedAt: "2026-06-08", completedAt: "2026-06-08" });
1362
+ await agentTaskBackgroundReadCommand.parseAsync(["node", "cli", "-t", "task1"]);
1363
+ expect(mockApiRequest).toHaveBeenCalled();
1364
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("completed"));
1365
+ consoleSpy.mockRestore();
1366
+ });
1367
+ it("handles read failure", async () => {
1368
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1369
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1370
+ mockApiRequest.mockRejectedValueOnce(new Error("Not found"));
1371
+ await expect(agentTaskBackgroundReadCommand.parseAsync(["node", "cli", "-t", "t1"])).rejects.toThrow();
1372
+ consoleSpy.mockRestore();
1373
+ exitSpy.mockRestore();
1374
+ });
1375
+ });
1376
+ describe("agent task background cancel", () => {
1377
+ it("cancels a background task", async () => {
1378
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1379
+ mockApiRequest.mockResolvedValueOnce({ cancelled: true });
1380
+ await agentTaskBackgroundCancelCommand.parseAsync(["node", "cli", "-t", "task1"]);
1381
+ expect(mockApiRequest).toHaveBeenCalledWith("/agent/task/background/cancel", expect.objectContaining({ method: "POST" }));
1382
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("cancelled"));
1383
+ consoleSpy.mockRestore();
1384
+ });
1385
+ it("reports task could not be cancelled", async () => {
1386
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1387
+ mockApiRequest.mockResolvedValueOnce({ cancelled: false });
1388
+ await agentTaskBackgroundCancelCommand.parseAsync(["node", "cli", "-t", "task1"]);
1389
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("could not be cancelled"));
1390
+ consoleSpy.mockRestore();
1391
+ });
1392
+ it("handles cancel failure", async () => {
1393
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1394
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1395
+ mockApiRequest.mockRejectedValueOnce(new Error("Not found"));
1396
+ await expect(agentTaskBackgroundCancelCommand.parseAsync(["node", "cli", "-t", "t1"])).rejects.toThrow();
1397
+ consoleSpy.mockRestore();
1398
+ exitSpy.mockRestore();
1399
+ });
1400
+ });
1401
+ // ---------------------------------------------------------------------------
1402
+ // asset upload
1403
+ // ---------------------------------------------------------------------------
1404
+ describe("asset upload", () => {
1405
+ it("uploads an asset", async () => {
1406
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1407
+ mockApiRequest.mockResolvedValueOnce({ url: "https://cdn.example.com/img.png", key: "img/abc.png", contentType: "image/png", bytes: 12345 });
1408
+ await assetUploadCommand.parseAsync(["node", "cli", "-s", "https://example.com/img.png", "-k", "image"]);
1409
+ expect(mockApiRequest).toHaveBeenCalledWith("/asset/upload", expect.objectContaining({ method: "POST" }));
1410
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Asset uploaded"));
1411
+ consoleSpy.mockRestore();
1412
+ });
1413
+ it("handles upload failure", async () => {
1414
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1415
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1416
+ mockApiRequest.mockRejectedValueOnce(new Error("Source URL unreachable"));
1417
+ await expect(assetUploadCommand.parseAsync(["node", "cli", "-s", "https://bad.url", "-k", "image"])).rejects.toThrow();
1418
+ consoleSpy.mockRestore();
1419
+ exitSpy.mockRestore();
1420
+ });
1421
+ });
1422
+ // ---------------------------------------------------------------------------
1423
+ // billing subscription upgrade start
1424
+ // ---------------------------------------------------------------------------
1425
+ describe("billing subscription upgrade start", () => {
1426
+ it("starts a checkout session", async () => {
1427
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1428
+ mockApiRequest.mockResolvedValueOnce({ checkoutUrl: "https://checkout.stripe.com/pay/cs_test_123", planSlug: "scale", interval: "month" });
1429
+ await billingSubscriptionUpgradeStartCommand.parseAsync(["node", "cli", "-p", "scale", "-i", "month", "--success-url", "https://app.oxagen.ai/success", "--cancel-url", "https://app.oxagen.ai/cancel"]);
1430
+ expect(mockApiRequest).toHaveBeenCalledWith("/billing/subscription/upgrade/start", expect.objectContaining({ method: "POST" }));
1431
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Checkout session created"));
1432
+ consoleSpy.mockRestore();
1433
+ });
1434
+ it("handles upgrade failure", async () => {
1435
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1436
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1437
+ mockApiRequest.mockRejectedValueOnce(new Error("Stripe error"));
1438
+ await expect(billingSubscriptionUpgradeStartCommand.parseAsync(["node", "cli", "-p", "scale", "-i", "month", "--success-url", "https://a.com/ok", "--cancel-url", "https://a.com/cancel"])).rejects.toThrow();
1439
+ consoleSpy.mockRestore();
1440
+ exitSpy.mockRestore();
1441
+ });
1442
+ });
1443
+ // ---------------------------------------------------------------------------
1444
+ // brandkit apply
1445
+ // ---------------------------------------------------------------------------
1446
+ describe("brandkit apply", () => {
1447
+ it("applies a brand kit", async () => {
1448
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1449
+ mockApiRequest.mockResolvedValueOnce({ stub: true, applied: false, brandKitId: "bk1", targetFileId: "file1" });
1450
+ await brandkitApplyCommand.parseAsync(["node", "cli", "-b", "bk1", "-f", "file1", "-w", "ws1"]);
1451
+ expect(mockApiRequest).toHaveBeenCalledWith("/brandkit/apply", expect.objectContaining({ method: "POST" }));
1452
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("stub"));
1453
+ consoleSpy.mockRestore();
1454
+ });
1455
+ it("handles apply failure", async () => {
1456
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1457
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1458
+ mockApiRequest.mockRejectedValueOnce(new Error("Brand kit not found"));
1459
+ await expect(brandkitApplyCommand.parseAsync(["node", "cli", "-b", "bk1", "-f", "f1", "-w", "ws1"])).rejects.toThrow();
1460
+ consoleSpy.mockRestore();
1461
+ exitSpy.mockRestore();
1462
+ });
1463
+ });
1464
+ // ---------------------------------------------------------------------------
1465
+ // conversation purge
1466
+ // ---------------------------------------------------------------------------
1467
+ describe("conversation purge", () => {
1468
+ it("purges archived conversations with --yes", async () => {
1469
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1470
+ mockApiRequest.mockResolvedValueOnce({ deleted: 5 });
1471
+ await conversationPurgeCommand.parseAsync(["node", "cli", "-w", "ws1", "--yes"]);
1472
+ expect(mockApiRequest).toHaveBeenCalledWith("/conversation/purge", expect.objectContaining({ method: "POST" }));
1473
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Purged 5"));
1474
+ consoleSpy.mockRestore();
1475
+ });
1476
+ it("exits without --yes", async () => {
1477
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1478
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1479
+ await expect(conversationPurgeCommand.parseAsync(["node", "cli", "-w", "ws1"])).rejects.toThrow();
1480
+ expect(consoleSpy).toHaveBeenCalled();
1481
+ consoleSpy.mockRestore();
1482
+ exitSpy.mockRestore();
1483
+ });
1484
+ it("handles purge failure", async () => {
1485
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1486
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1487
+ mockApiRequest.mockRejectedValueOnce(new Error("Workspace not found"));
1488
+ await expect(conversationPurgeCommand.parseAsync(["node", "cli", "-w", "ws1", "--yes"])).rejects.toThrow();
1489
+ consoleSpy.mockRestore();
1490
+ exitSpy.mockRestore();
1491
+ });
1492
+ });
1493
+ // ---------------------------------------------------------------------------
1494
+ // documents pdf create
1495
+ // ---------------------------------------------------------------------------
1496
+ describe("documents pdf create", () => {
1497
+ it("creates a PDF document", async () => {
1498
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1499
+ mockApiRequest.mockResolvedValueOnce({ assetId: "asset1", publicId: "pub1", kind: "pdf", mimeType: "application/pdf", sizeBytes: 50000, url: "https://blob.example.com/doc.pdf", serveUrl: "https://api.example.com/assets/asset1" });
1500
+ await documentsPdfCreateCommand.parseAsync(["node", "cli", "-t", "Q1 Report"]);
1501
+ expect(mockApiRequest).toHaveBeenCalledWith("/documents/pdf/create", expect.objectContaining({ method: "POST" }));
1502
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("PDF created"));
1503
+ consoleSpy.mockRestore();
1504
+ });
1505
+ it("handles pdf create failure", async () => {
1506
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1507
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1508
+ mockApiRequest.mockRejectedValueOnce(new Error("Generation failed"));
1509
+ await expect(documentsPdfCreateCommand.parseAsync(["node", "cli", "-t", "Report"])).rejects.toThrow();
1510
+ consoleSpy.mockRestore();
1511
+ exitSpy.mockRestore();
1512
+ });
1513
+ });
1514
+ // ---------------------------------------------------------------------------
1515
+ // form fill
1516
+ // ---------------------------------------------------------------------------
1517
+ describe("form fill", () => {
1518
+ it("fills form fields", async () => {
1519
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1520
+ const fields = [{ name: "firstName", label: "First Name", type: "text", current: "", changed: false, proposed: "Alice", reason: "Inferred from instruction" }];
1521
+ mockApiRequest.mockResolvedValueOnce({ fields });
1522
+ await formFillCommand.parseAsync(["node", "cli", "-r", "/profile", "-i", "Fill with Alice's info", "--fields", '[{"name":"firstName","label":"First Name","type":"text","current":""}]']);
1523
+ expect(mockApiRequest).toHaveBeenCalledWith("/form/fill", expect.objectContaining({ method: "POST" }));
1524
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Form fill suggestion"));
1525
+ consoleSpy.mockRestore();
1526
+ });
1527
+ it("handles form fill failure", async () => {
1528
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1529
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1530
+ mockApiRequest.mockRejectedValueOnce(new Error("LLM error"));
1531
+ await expect(formFillCommand.parseAsync(["node", "cli", "-r", "/p", "-i", "fill", "--fields", "[]"])).rejects.toThrow();
1532
+ consoleSpy.mockRestore();
1533
+ exitSpy.mockRestore();
1534
+ });
1535
+ });
1536
+ // ---------------------------------------------------------------------------
1537
+ // org member invite decline
1538
+ // ---------------------------------------------------------------------------
1539
+ describe("org member invite decline", () => {
1540
+ it("declines an invitation", async () => {
1541
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1542
+ mockApiRequest.mockResolvedValueOnce({ invitationPublicId: "inv1", status: "declined" });
1543
+ await orgMemberInviteDeclineCommand.parseAsync(["node", "cli", "-i", "inv1"]);
1544
+ expect(mockApiRequest).toHaveBeenCalledWith("/org/member/invite/decline", expect.objectContaining({ method: "POST" }));
1545
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("declined"));
1546
+ consoleSpy.mockRestore();
1547
+ });
1548
+ it("handles decline failure", async () => {
1549
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1550
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1551
+ mockApiRequest.mockRejectedValueOnce(new Error("Invitation not found"));
1552
+ await expect(orgMemberInviteDeclineCommand.parseAsync(["node", "cli", "-i", "inv1"])).rejects.toThrow();
1553
+ consoleSpy.mockRestore();
1554
+ exitSpy.mockRestore();
1555
+ });
1556
+ });
1557
+ // ---------------------------------------------------------------------------
1558
+ // organization create
1559
+ // ---------------------------------------------------------------------------
1560
+ describe("organization create", () => {
1561
+ it("creates an organization", async () => {
1562
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1563
+ mockApiRequest.mockResolvedValueOnce({ publicId: "org1", name: "Acme Corp", slug: "acme-corp", type: "business", createdAt: "2026-06-08" });
1564
+ await organizationCreateCommand.parseAsync(["node", "cli", "-n", "Acme Corp", "-s", "acme-corp"]);
1565
+ expect(mockApiRequest).toHaveBeenCalledWith("/organization/create", expect.objectContaining({ method: "POST" }));
1566
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Organization created"));
1567
+ consoleSpy.mockRestore();
1568
+ });
1569
+ it("handles create failure", async () => {
1570
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1571
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1572
+ mockApiRequest.mockRejectedValueOnce(new Error("Slug already taken"));
1573
+ await expect(organizationCreateCommand.parseAsync(["node", "cli", "-n", "Acme", "-s", "acme"])).rejects.toThrow();
1574
+ consoleSpy.mockRestore();
1575
+ exitSpy.mockRestore();
1576
+ });
1577
+ });
1578
+ // ---------------------------------------------------------------------------
1579
+ // plugin credential set_secret
1580
+ // ---------------------------------------------------------------------------
1581
+ describe("plugin credential set_secret", () => {
1582
+ it("stores a credential", async () => {
1583
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1584
+ mockApiRequest.mockResolvedValueOnce({ ok: true });
1585
+ await pluginCredentialSetSecretCommand.parseAsync(["node", "cli", "-l", "listing1", "-a", "secret", "--secret", "my-secret"]);
1586
+ expect(mockApiRequest).toHaveBeenCalledWith("/plugin/credential/set_secret", expect.objectContaining({ method: "POST" }));
1587
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Credential stored"));
1588
+ consoleSpy.mockRestore();
1589
+ });
1590
+ it("handles credential failure", async () => {
1591
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1592
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1593
+ mockApiRequest.mockRejectedValueOnce(new Error("Listing not found"));
1594
+ await expect(pluginCredentialSetSecretCommand.parseAsync(["node", "cli", "-l", "l1", "-a", "secret"])).rejects.toThrow();
1595
+ consoleSpy.mockRestore();
1596
+ exitSpy.mockRestore();
1597
+ });
1598
+ });
1599
+ // ---------------------------------------------------------------------------
1600
+ // plugin denylist
1601
+ // ---------------------------------------------------------------------------
1602
+ describe("plugin denylist add", () => {
1603
+ it("adds a server to the denylist", async () => {
1604
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1605
+ mockApiRequest.mockResolvedValueOnce({ ok: true });
1606
+ await pluginDenylistAddCommand.parseAsync(["node", "cli", "-s", "bad-server"]);
1607
+ expect(mockApiRequest).toHaveBeenCalledWith("/plugin/denylist/add", expect.objectContaining({ method: "POST" }));
1608
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("bad-server"));
1609
+ consoleSpy.mockRestore();
1610
+ });
1611
+ it("handles denylist add failure", async () => {
1612
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1613
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1614
+ mockApiRequest.mockRejectedValueOnce(new Error("Server not found"));
1615
+ await expect(pluginDenylistAddCommand.parseAsync(["node", "cli", "-s", "srv"])).rejects.toThrow();
1616
+ consoleSpy.mockRestore();
1617
+ exitSpy.mockRestore();
1618
+ });
1619
+ });
1620
+ describe("plugin denylist remove", () => {
1621
+ it("removes a server from the denylist", async () => {
1622
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1623
+ mockApiRequest.mockResolvedValueOnce({ ok: true });
1624
+ await pluginDenylistRemoveCommand.parseAsync(["node", "cli", "-s", "bad-server"]);
1625
+ expect(mockApiRequest).toHaveBeenCalledWith("/plugin/denylist/remove", expect.objectContaining({ method: "POST" }));
1626
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("bad-server"));
1627
+ consoleSpy.mockRestore();
1628
+ });
1629
+ it("handles denylist remove failure", async () => {
1630
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1631
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1632
+ mockApiRequest.mockRejectedValueOnce(new Error("Entry not found"));
1633
+ await expect(pluginDenylistRemoveCommand.parseAsync(["node", "cli", "-s", "srv"])).rejects.toThrow();
1634
+ consoleSpy.mockRestore();
1635
+ exitSpy.mockRestore();
1636
+ });
1637
+ });
1638
+ // ---------------------------------------------------------------------------
1639
+ // plugin org install bulk
1640
+ // ---------------------------------------------------------------------------
1641
+ describe("plugin org install bulk", () => {
1642
+ it("bulk installs plugins", async () => {
1643
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1644
+ mockApiRequest.mockResolvedValueOnce({ installed: [{ catalogServerId: "srv1", orgListingId: "listing1", error: null }] });
1645
+ await pluginOrgInstallBulkCommand.parseAsync(["node", "cli", "--items", '[{"catalogServerId":"srv1"}]']);
1646
+ expect(mockApiRequest).toHaveBeenCalledWith("/plugin/org/install_bulk", expect.objectContaining({ method: "POST" }));
1647
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("1 succeeded"));
1648
+ consoleSpy.mockRestore();
1649
+ });
1650
+ it("reports partial failures", async () => {
1651
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1652
+ mockApiRequest.mockResolvedValueOnce({ installed: [{ catalogServerId: "srv1", orgListingId: null, error: "Not found" }] });
1653
+ await pluginOrgInstallBulkCommand.parseAsync(["node", "cli", "--items", '[{"catalogServerId":"srv1"}]']);
1654
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("0 succeeded, 1 failed"));
1655
+ consoleSpy.mockRestore();
1656
+ });
1657
+ it("handles bulk install failure", async () => {
1658
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1659
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1660
+ mockApiRequest.mockRejectedValueOnce(new Error("Bad request"));
1661
+ await expect(pluginOrgInstallBulkCommand.parseAsync(["node", "cli", "--items", "[]"])).rejects.toThrow();
1662
+ consoleSpy.mockRestore();
1663
+ exitSpy.mockRestore();
1664
+ });
1665
+ });
1666
+ // ---------------------------------------------------------------------------
1667
+ // plugin org list
1668
+ // ---------------------------------------------------------------------------
1669
+ describe("plugin org list", () => {
1670
+ it("lists org plugins", async () => {
1671
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1672
+ mockApiRequest.mockResolvedValueOnce({
1673
+ listings: [{ id: "l1", publicId: "pub1", name: "Slack", pluginType: "mcp_server", enabled: true }],
1674
+ denylist: [],
1675
+ });
1676
+ await pluginOrgListCommand.parseAsync(["node", "cli"]);
1677
+ expect(mockApiRequest).toHaveBeenCalled();
1678
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Slack"));
1679
+ consoleSpy.mockRestore();
1680
+ });
1681
+ it("shows denylist when populated", async () => {
1682
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1683
+ mockApiRequest.mockResolvedValueOnce({
1684
+ listings: [],
1685
+ denylist: [{ id: "d1", serverName: "bad-server", pluginType: "mcp_server", reason: "Security risk" }],
1686
+ });
1687
+ await pluginOrgListCommand.parseAsync(["node", "cli"]);
1688
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Denylist"));
1689
+ consoleSpy.mockRestore();
1690
+ });
1691
+ it("handles list failure", async () => {
1692
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1693
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1694
+ mockApiRequest.mockRejectedValueOnce(new Error("Unauthorized"));
1695
+ await expect(pluginOrgListCommand.parseAsync(["node", "cli"])).rejects.toThrow();
1696
+ consoleSpy.mockRestore();
1697
+ exitSpy.mockRestore();
1698
+ });
1699
+ });
1700
+ // ---------------------------------------------------------------------------
1701
+ // plugin org set_enabled
1702
+ // ---------------------------------------------------------------------------
1703
+ describe("plugin org set_enabled", () => {
1704
+ it("enables a plugin listing", async () => {
1705
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1706
+ mockApiRequest.mockResolvedValueOnce({ ok: true });
1707
+ await pluginOrgSetEnabledCommand.parseAsync(["node", "cli", "-l", "listing1", "--enabled", "true"]);
1708
+ expect(mockApiRequest).toHaveBeenCalledWith("/plugin/org/set_enabled", expect.objectContaining({ method: "POST" }));
1709
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("enabled"));
1710
+ consoleSpy.mockRestore();
1711
+ });
1712
+ it("disables a plugin listing", async () => {
1713
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1714
+ mockApiRequest.mockResolvedValueOnce({ ok: true });
1715
+ await pluginOrgSetEnabledCommand.parseAsync(["node", "cli", "-l", "listing1", "--enabled", "false"]);
1716
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("disabled"));
1717
+ consoleSpy.mockRestore();
1718
+ });
1719
+ it("handles set_enabled failure", async () => {
1720
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1721
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1722
+ mockApiRequest.mockRejectedValueOnce(new Error("Listing not found"));
1723
+ await expect(pluginOrgSetEnabledCommand.parseAsync(["node", "cli", "-l", "l1", "--enabled", "true"])).rejects.toThrow();
1724
+ consoleSpy.mockRestore();
1725
+ exitSpy.mockRestore();
1726
+ });
1727
+ });
1728
+ // ---------------------------------------------------------------------------
1729
+ // plugin registry remove
1730
+ // ---------------------------------------------------------------------------
1731
+ describe("plugin registry remove", () => {
1732
+ it("removes a registry", async () => {
1733
+ const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
1734
+ mockApiRequest.mockResolvedValueOnce({ ok: true });
1735
+ await pluginRegistryRemoveCommand.parseAsync(["node", "cli", "-r", "reg1"]);
1736
+ expect(mockApiRequest).toHaveBeenCalledWith("/plugin/registry/remove", expect.objectContaining({ method: "DELETE" }));
1737
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("reg1 removed"));
1738
+ consoleSpy.mockRestore();
1739
+ });
1740
+ it("handles remove failure", async () => {
1741
+ const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
1742
+ const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
1743
+ mockApiRequest.mockRejectedValueOnce(new Error("Registry is global default"));
1744
+ await expect(pluginRegistryRemoveCommand.parseAsync(["node", "cli", "-r", "r1"])).rejects.toThrow();
1745
+ consoleSpy.mockRestore();
1746
+ exitSpy.mockRestore();
1747
+ });
1748
+ });
1749
+ //# sourceMappingURL=commands.test.js.map