@amodalai/amodal 0.1.2

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 (511) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE +21 -0
  3. package/README.md +42 -0
  4. package/dist/src/auth/index.d.ts +13 -0
  5. package/dist/src/auth/index.d.ts.map +1 -0
  6. package/dist/src/auth/index.js +10 -0
  7. package/dist/src/auth/index.js.map +1 -0
  8. package/dist/src/auth/oauth2.d.ts +51 -0
  9. package/dist/src/auth/oauth2.d.ts.map +1 -0
  10. package/dist/src/auth/oauth2.js +196 -0
  11. package/dist/src/auth/oauth2.js.map +1 -0
  12. package/dist/src/auth/prompt.d.ts +21 -0
  13. package/dist/src/auth/prompt.d.ts.map +1 -0
  14. package/dist/src/auth/prompt.js +81 -0
  15. package/dist/src/auth/prompt.js.map +1 -0
  16. package/dist/src/auth/test-connection.d.ts +27 -0
  17. package/dist/src/auth/test-connection.d.ts.map +1 -0
  18. package/dist/src/auth/test-connection.js +153 -0
  19. package/dist/src/auth/test-connection.js.map +1 -0
  20. package/dist/src/auth/types.d.ts +32 -0
  21. package/dist/src/auth/types.d.ts.map +1 -0
  22. package/dist/src/auth/types.js +7 -0
  23. package/dist/src/auth/types.js.map +1 -0
  24. package/dist/src/commands/audit.d.ts +18 -0
  25. package/dist/src/commands/audit.d.ts.map +1 -0
  26. package/dist/src/commands/audit.js +86 -0
  27. package/dist/src/commands/audit.js.map +1 -0
  28. package/dist/src/commands/automations.d.ts +28 -0
  29. package/dist/src/commands/automations.d.ts.map +1 -0
  30. package/dist/src/commands/automations.js +179 -0
  31. package/dist/src/commands/automations.js.map +1 -0
  32. package/dist/src/commands/build-manifest-types.d.ts +33 -0
  33. package/dist/src/commands/build-manifest-types.d.ts.map +1 -0
  34. package/dist/src/commands/build-manifest-types.js +30 -0
  35. package/dist/src/commands/build-manifest-types.js.map +1 -0
  36. package/dist/src/commands/build-tools.d.ts +33 -0
  37. package/dist/src/commands/build-tools.d.ts.map +1 -0
  38. package/dist/src/commands/build-tools.js +237 -0
  39. package/dist/src/commands/build-tools.js.map +1 -0
  40. package/dist/src/commands/build.d.ts +23 -0
  41. package/dist/src/commands/build.d.ts.map +1 -0
  42. package/dist/src/commands/build.js +120 -0
  43. package/dist/src/commands/build.js.map +1 -0
  44. package/dist/src/commands/chat.d.ts +26 -0
  45. package/dist/src/commands/chat.d.ts.map +1 -0
  46. package/dist/src/commands/chat.js +123 -0
  47. package/dist/src/commands/chat.js.map +1 -0
  48. package/dist/src/commands/connect.d.ts +18 -0
  49. package/dist/src/commands/connect.d.ts.map +1 -0
  50. package/dist/src/commands/connect.js +198 -0
  51. package/dist/src/commands/connect.js.map +1 -0
  52. package/dist/src/commands/deploy.d.ts +20 -0
  53. package/dist/src/commands/deploy.d.ts.map +1 -0
  54. package/dist/src/commands/deploy.js +137 -0
  55. package/dist/src/commands/deploy.js.map +1 -0
  56. package/dist/src/commands/deployments.d.ts +17 -0
  57. package/dist/src/commands/deployments.d.ts.map +1 -0
  58. package/dist/src/commands/deployments.js +77 -0
  59. package/dist/src/commands/deployments.js.map +1 -0
  60. package/dist/src/commands/dev.d.ts +17 -0
  61. package/dist/src/commands/dev.d.ts.map +1 -0
  62. package/dist/src/commands/dev.js +109 -0
  63. package/dist/src/commands/dev.js.map +1 -0
  64. package/dist/src/commands/diff.d.ts +19 -0
  65. package/dist/src/commands/diff.d.ts.map +1 -0
  66. package/dist/src/commands/diff.js +120 -0
  67. package/dist/src/commands/diff.js.map +1 -0
  68. package/dist/src/commands/docker.d.ts +21 -0
  69. package/dist/src/commands/docker.d.ts.map +1 -0
  70. package/dist/src/commands/docker.js +215 -0
  71. package/dist/src/commands/docker.js.map +1 -0
  72. package/dist/src/commands/eval.d.ts +20 -0
  73. package/dist/src/commands/eval.d.ts.map +1 -0
  74. package/dist/src/commands/eval.js +236 -0
  75. package/dist/src/commands/eval.js.map +1 -0
  76. package/dist/src/commands/experiment.d.ts +21 -0
  77. package/dist/src/commands/experiment.d.ts.map +1 -0
  78. package/dist/src/commands/experiment.js +133 -0
  79. package/dist/src/commands/experiment.js.map +1 -0
  80. package/dist/src/commands/index.d.ts +10 -0
  81. package/dist/src/commands/index.d.ts.map +1 -0
  82. package/dist/src/commands/index.js +75 -0
  83. package/dist/src/commands/index.js.map +1 -0
  84. package/dist/src/commands/init.d.ts +17 -0
  85. package/dist/src/commands/init.d.ts.map +1 -0
  86. package/dist/src/commands/init.js +73 -0
  87. package/dist/src/commands/init.js.map +1 -0
  88. package/dist/src/commands/inspect.d.ts +22 -0
  89. package/dist/src/commands/inspect.d.ts.map +1 -0
  90. package/dist/src/commands/inspect.js +131 -0
  91. package/dist/src/commands/inspect.js.map +1 -0
  92. package/dist/src/commands/install-pkg.d.ts +29 -0
  93. package/dist/src/commands/install-pkg.d.ts.map +1 -0
  94. package/dist/src/commands/install-pkg.js +202 -0
  95. package/dist/src/commands/install-pkg.js.map +1 -0
  96. package/dist/src/commands/link.d.ts +32 -0
  97. package/dist/src/commands/link.d.ts.map +1 -0
  98. package/dist/src/commands/link.js +227 -0
  99. package/dist/src/commands/link.js.map +1 -0
  100. package/dist/src/commands/list.d.ts +19 -0
  101. package/dist/src/commands/list.d.ts.map +1 -0
  102. package/dist/src/commands/list.js +78 -0
  103. package/dist/src/commands/list.js.map +1 -0
  104. package/dist/src/commands/login.d.ts +31 -0
  105. package/dist/src/commands/login.d.ts.map +1 -0
  106. package/dist/src/commands/login.js +205 -0
  107. package/dist/src/commands/login.js.map +1 -0
  108. package/dist/src/commands/promote.d.ts +16 -0
  109. package/dist/src/commands/promote.d.ts.map +1 -0
  110. package/dist/src/commands/promote.js +55 -0
  111. package/dist/src/commands/promote.js.map +1 -0
  112. package/dist/src/commands/publish.d.ts +18 -0
  113. package/dist/src/commands/publish.d.ts.map +1 -0
  114. package/dist/src/commands/publish.js +122 -0
  115. package/dist/src/commands/publish.js.map +1 -0
  116. package/dist/src/commands/rollback.d.ts +17 -0
  117. package/dist/src/commands/rollback.d.ts.map +1 -0
  118. package/dist/src/commands/rollback.js +62 -0
  119. package/dist/src/commands/rollback.js.map +1 -0
  120. package/dist/src/commands/search.d.ts +20 -0
  121. package/dist/src/commands/search.d.ts.map +1 -0
  122. package/dist/src/commands/search.js +133 -0
  123. package/dist/src/commands/search.js.map +1 -0
  124. package/dist/src/commands/secrets.d.ts +20 -0
  125. package/dist/src/commands/secrets.d.ts.map +1 -0
  126. package/dist/src/commands/secrets.js +137 -0
  127. package/dist/src/commands/secrets.js.map +1 -0
  128. package/dist/src/commands/serve.d.ts +23 -0
  129. package/dist/src/commands/serve.d.ts.map +1 -0
  130. package/dist/src/commands/serve.js +144 -0
  131. package/dist/src/commands/serve.js.map +1 -0
  132. package/dist/src/commands/status.d.ts +16 -0
  133. package/dist/src/commands/status.d.ts.map +1 -0
  134. package/dist/src/commands/status.js +83 -0
  135. package/dist/src/commands/status.js.map +1 -0
  136. package/dist/src/commands/sync.d.ts +21 -0
  137. package/dist/src/commands/sync.d.ts.map +1 -0
  138. package/dist/src/commands/sync.js +94 -0
  139. package/dist/src/commands/sync.js.map +1 -0
  140. package/dist/src/commands/test-query.d.ts +19 -0
  141. package/dist/src/commands/test-query.d.ts.map +1 -0
  142. package/dist/src/commands/test-query.js +116 -0
  143. package/dist/src/commands/test-query.js.map +1 -0
  144. package/dist/src/commands/uninstall.d.ts +19 -0
  145. package/dist/src/commands/uninstall.d.ts.map +1 -0
  146. package/dist/src/commands/uninstall.js +84 -0
  147. package/dist/src/commands/uninstall.js.map +1 -0
  148. package/dist/src/commands/update.d.ts +21 -0
  149. package/dist/src/commands/update.d.ts.map +1 -0
  150. package/dist/src/commands/update.js +145 -0
  151. package/dist/src/commands/update.js.map +1 -0
  152. package/dist/src/commands/validate.d.ts +19 -0
  153. package/dist/src/commands/validate.d.ts.map +1 -0
  154. package/dist/src/commands/validate.js +114 -0
  155. package/dist/src/commands/validate.js.map +1 -0
  156. package/dist/src/fixtures/incident-response.d.ts +91 -0
  157. package/dist/src/fixtures/incident-response.d.ts.map +1 -0
  158. package/dist/src/fixtures/incident-response.js +208 -0
  159. package/dist/src/fixtures/incident-response.js.map +1 -0
  160. package/dist/src/main.d.ts +8 -0
  161. package/dist/src/main.d.ts.map +1 -0
  162. package/dist/src/main.js +30 -0
  163. package/dist/src/main.js.map +1 -0
  164. package/dist/src/shared/platform-client.d.ts +92 -0
  165. package/dist/src/shared/platform-client.d.ts.map +1 -0
  166. package/dist/src/shared/platform-client.js +155 -0
  167. package/dist/src/shared/platform-client.js.map +1 -0
  168. package/dist/src/shared/repo-discovery.d.ts +11 -0
  169. package/dist/src/shared/repo-discovery.d.ts.map +1 -0
  170. package/dist/src/shared/repo-discovery.js +33 -0
  171. package/dist/src/shared/repo-discovery.js.map +1 -0
  172. package/dist/src/templates/compose-template.d.ts +10 -0
  173. package/dist/src/templates/compose-template.d.ts.map +1 -0
  174. package/dist/src/templates/compose-template.js +30 -0
  175. package/dist/src/templates/compose-template.js.map +1 -0
  176. package/dist/src/templates/config-template.d.ts +14 -0
  177. package/dist/src/templates/config-template.d.ts.map +1 -0
  178. package/dist/src/templates/config-template.js +35 -0
  179. package/dist/src/templates/config-template.js.map +1 -0
  180. package/dist/src/templates/dockerfile-template.d.ts +10 -0
  181. package/dist/src/templates/dockerfile-template.d.ts.map +1 -0
  182. package/dist/src/templates/dockerfile-template.js +30 -0
  183. package/dist/src/templates/dockerfile-template.js.map +1 -0
  184. package/dist/src/templates/env-template.d.ts +12 -0
  185. package/dist/src/templates/env-template.d.ts.map +1 -0
  186. package/dist/src/templates/env-template.js +24 -0
  187. package/dist/src/templates/env-template.js.map +1 -0
  188. package/dist/src/templates/knowledge-template.d.ts +10 -0
  189. package/dist/src/templates/knowledge-template.d.ts.map +1 -0
  190. package/dist/src/templates/knowledge-template.js +24 -0
  191. package/dist/src/templates/knowledge-template.js.map +1 -0
  192. package/dist/src/templates/skill-template.d.ts +10 -0
  193. package/dist/src/templates/skill-template.d.ts.map +1 -0
  194. package/dist/src/templates/skill-template.js +27 -0
  195. package/dist/src/templates/skill-template.js.map +1 -0
  196. package/dist/src/ui/AskUserPrompt.d.ts +14 -0
  197. package/dist/src/ui/AskUserPrompt.d.ts.map +1 -0
  198. package/dist/src/ui/AskUserPrompt.js +17 -0
  199. package/dist/src/ui/AskUserPrompt.js.map +1 -0
  200. package/dist/src/ui/AssistantMessage.d.ts +14 -0
  201. package/dist/src/ui/AssistantMessage.d.ts.map +1 -0
  202. package/dist/src/ui/AssistantMessage.js +8 -0
  203. package/dist/src/ui/AssistantMessage.js.map +1 -0
  204. package/dist/src/ui/ChatApp.d.ts +15 -0
  205. package/dist/src/ui/ChatApp.d.ts.map +1 -0
  206. package/dist/src/ui/ChatApp.js +144 -0
  207. package/dist/src/ui/ChatApp.js.map +1 -0
  208. package/dist/src/ui/ConfirmationPrompt.d.ts +17 -0
  209. package/dist/src/ui/ConfirmationPrompt.d.ts.map +1 -0
  210. package/dist/src/ui/ConfirmationPrompt.js +21 -0
  211. package/dist/src/ui/ConfirmationPrompt.js.map +1 -0
  212. package/dist/src/ui/DiffRenderer.d.ts +32 -0
  213. package/dist/src/ui/DiffRenderer.d.ts.map +1 -0
  214. package/dist/src/ui/DiffRenderer.js +118 -0
  215. package/dist/src/ui/DiffRenderer.js.map +1 -0
  216. package/dist/src/ui/ExpandableContent.d.ts +15 -0
  217. package/dist/src/ui/ExpandableContent.d.ts.map +1 -0
  218. package/dist/src/ui/ExpandableContent.js +22 -0
  219. package/dist/src/ui/ExpandableContent.js.map +1 -0
  220. package/dist/src/ui/ExploreIndicator.d.ts +13 -0
  221. package/dist/src/ui/ExploreIndicator.d.ts.map +1 -0
  222. package/dist/src/ui/ExploreIndicator.js +14 -0
  223. package/dist/src/ui/ExploreIndicator.js.map +1 -0
  224. package/dist/src/ui/Footer.d.ts +19 -0
  225. package/dist/src/ui/Footer.d.ts.map +1 -0
  226. package/dist/src/ui/Footer.js +57 -0
  227. package/dist/src/ui/Footer.js.map +1 -0
  228. package/dist/src/ui/FullScreenLayout.d.ts +18 -0
  229. package/dist/src/ui/FullScreenLayout.d.ts.map +1 -0
  230. package/dist/src/ui/FullScreenLayout.js +14 -0
  231. package/dist/src/ui/FullScreenLayout.js.map +1 -0
  232. package/dist/src/ui/Header.d.ts +14 -0
  233. package/dist/src/ui/Header.d.ts.map +1 -0
  234. package/dist/src/ui/Header.js +11 -0
  235. package/dist/src/ui/Header.js.map +1 -0
  236. package/dist/src/ui/InputBar.d.ts +17 -0
  237. package/dist/src/ui/InputBar.d.ts.map +1 -0
  238. package/dist/src/ui/InputBar.js +49 -0
  239. package/dist/src/ui/InputBar.js.map +1 -0
  240. package/dist/src/ui/MessageList.d.ts +18 -0
  241. package/dist/src/ui/MessageList.d.ts.map +1 -0
  242. package/dist/src/ui/MessageList.js +9 -0
  243. package/dist/src/ui/MessageList.js.map +1 -0
  244. package/dist/src/ui/NotificationBar.d.ts +14 -0
  245. package/dist/src/ui/NotificationBar.d.ts.map +1 -0
  246. package/dist/src/ui/NotificationBar.js +38 -0
  247. package/dist/src/ui/NotificationBar.js.map +1 -0
  248. package/dist/src/ui/ScrollableMessageList.d.ts +27 -0
  249. package/dist/src/ui/ScrollableMessageList.d.ts.map +1 -0
  250. package/dist/src/ui/ScrollableMessageList.js +16 -0
  251. package/dist/src/ui/ScrollableMessageList.js.map +1 -0
  252. package/dist/src/ui/SessionBrowser.d.ts +20 -0
  253. package/dist/src/ui/SessionBrowser.d.ts.map +1 -0
  254. package/dist/src/ui/SessionBrowser.js +93 -0
  255. package/dist/src/ui/SessionBrowser.js.map +1 -0
  256. package/dist/src/ui/StatusMessage.d.ts +13 -0
  257. package/dist/src/ui/StatusMessage.d.ts.map +1 -0
  258. package/dist/src/ui/StatusMessage.js +17 -0
  259. package/dist/src/ui/StatusMessage.js.map +1 -0
  260. package/dist/src/ui/StreamingView.d.ts +19 -0
  261. package/dist/src/ui/StreamingView.d.ts.map +1 -0
  262. package/dist/src/ui/StreamingView.js +18 -0
  263. package/dist/src/ui/StreamingView.js.map +1 -0
  264. package/dist/src/ui/SubagentDisplay.d.ts +13 -0
  265. package/dist/src/ui/SubagentDisplay.d.ts.map +1 -0
  266. package/dist/src/ui/SubagentDisplay.js +22 -0
  267. package/dist/src/ui/SubagentDisplay.js.map +1 -0
  268. package/dist/src/ui/ThinkingDisplay.d.ts +13 -0
  269. package/dist/src/ui/ThinkingDisplay.d.ts.map +1 -0
  270. package/dist/src/ui/ThinkingDisplay.js +15 -0
  271. package/dist/src/ui/ThinkingDisplay.js.map +1 -0
  272. package/dist/src/ui/ToolCallDisplay.d.ts +16 -0
  273. package/dist/src/ui/ToolCallDisplay.d.ts.map +1 -0
  274. package/dist/src/ui/ToolCallDisplay.js +136 -0
  275. package/dist/src/ui/ToolCallDisplay.js.map +1 -0
  276. package/dist/src/ui/UserMessage.d.ts +12 -0
  277. package/dist/src/ui/UserMessage.d.ts.map +1 -0
  278. package/dist/src/ui/UserMessage.js +5 -0
  279. package/dist/src/ui/UserMessage.js.map +1 -0
  280. package/dist/src/ui/commands/clear.d.ts +7 -0
  281. package/dist/src/ui/commands/clear.d.ts.map +1 -0
  282. package/dist/src/ui/commands/clear.js +13 -0
  283. package/dist/src/ui/commands/clear.js.map +1 -0
  284. package/dist/src/ui/commands/help.d.ts +7 -0
  285. package/dist/src/ui/commands/help.d.ts.map +1 -0
  286. package/dist/src/ui/commands/help.js +26 -0
  287. package/dist/src/ui/commands/help.js.map +1 -0
  288. package/dist/src/ui/commands/index.d.ts +14 -0
  289. package/dist/src/ui/commands/index.d.ts.map +1 -0
  290. package/dist/src/ui/commands/index.js +15 -0
  291. package/dist/src/ui/commands/index.js.map +1 -0
  292. package/dist/src/ui/commands/model.d.ts +7 -0
  293. package/dist/src/ui/commands/model.d.ts.map +1 -0
  294. package/dist/src/ui/commands/model.js +16 -0
  295. package/dist/src/ui/commands/model.js.map +1 -0
  296. package/dist/src/ui/commands/registry.d.ts +30 -0
  297. package/dist/src/ui/commands/registry.d.ts.map +1 -0
  298. package/dist/src/ui/commands/registry.js +45 -0
  299. package/dist/src/ui/commands/registry.js.map +1 -0
  300. package/dist/src/ui/commands/sessions.d.ts +7 -0
  301. package/dist/src/ui/commands/sessions.d.ts.map +1 -0
  302. package/dist/src/ui/commands/sessions.js +13 -0
  303. package/dist/src/ui/commands/sessions.js.map +1 -0
  304. package/dist/src/ui/commands/stats.d.ts +7 -0
  305. package/dist/src/ui/commands/stats.d.ts.map +1 -0
  306. package/dist/src/ui/commands/stats.js +33 -0
  307. package/dist/src/ui/commands/stats.js.map +1 -0
  308. package/dist/src/ui/commands/theme.d.ts +7 -0
  309. package/dist/src/ui/commands/theme.d.ts.map +1 -0
  310. package/dist/src/ui/commands/theme.js +35 -0
  311. package/dist/src/ui/commands/theme.js.map +1 -0
  312. package/dist/src/ui/markdown/CodeBlock.d.ts +14 -0
  313. package/dist/src/ui/markdown/CodeBlock.d.ts.map +1 -0
  314. package/dist/src/ui/markdown/CodeBlock.js +55 -0
  315. package/dist/src/ui/markdown/CodeBlock.js.map +1 -0
  316. package/dist/src/ui/markdown/InlineRenderer.d.ts +12 -0
  317. package/dist/src/ui/markdown/InlineRenderer.d.ts.map +1 -0
  318. package/dist/src/ui/markdown/InlineRenderer.js +70 -0
  319. package/dist/src/ui/markdown/InlineRenderer.js.map +1 -0
  320. package/dist/src/ui/markdown/MarkdownDisplay.d.ts +17 -0
  321. package/dist/src/ui/markdown/MarkdownDisplay.d.ts.map +1 -0
  322. package/dist/src/ui/markdown/MarkdownDisplay.js +142 -0
  323. package/dist/src/ui/markdown/MarkdownDisplay.js.map +1 -0
  324. package/dist/src/ui/markdown/Table.d.ts +14 -0
  325. package/dist/src/ui/markdown/Table.d.ts.map +1 -0
  326. package/dist/src/ui/markdown/Table.js +31 -0
  327. package/dist/src/ui/markdown/Table.js.map +1 -0
  328. package/dist/src/ui/theme.d.ts +39 -0
  329. package/dist/src/ui/theme.d.ts.map +1 -0
  330. package/dist/src/ui/theme.js +39 -0
  331. package/dist/src/ui/theme.js.map +1 -0
  332. package/dist/src/ui/themes/index.d.ts +45 -0
  333. package/dist/src/ui/themes/index.d.ts.map +1 -0
  334. package/dist/src/ui/themes/index.js +73 -0
  335. package/dist/src/ui/themes/index.js.map +1 -0
  336. package/dist/src/ui/themes/light.d.ts +8 -0
  337. package/dist/src/ui/themes/light.d.ts.map +1 -0
  338. package/dist/src/ui/themes/light.js +37 -0
  339. package/dist/src/ui/themes/light.js.map +1 -0
  340. package/dist/src/ui/themes/monochrome.d.ts +8 -0
  341. package/dist/src/ui/themes/monochrome.d.ts.map +1 -0
  342. package/dist/src/ui/themes/monochrome.js +37 -0
  343. package/dist/src/ui/themes/monochrome.js.map +1 -0
  344. package/dist/src/ui/types.d.ts +191 -0
  345. package/dist/src/ui/types.d.ts.map +1 -0
  346. package/dist/src/ui/types.js +7 -0
  347. package/dist/src/ui/types.js.map +1 -0
  348. package/dist/src/ui/useAlternateBuffer.d.ts +11 -0
  349. package/dist/src/ui/useAlternateBuffer.d.ts.map +1 -0
  350. package/dist/src/ui/useAlternateBuffer.js +25 -0
  351. package/dist/src/ui/useAlternateBuffer.js.map +1 -0
  352. package/dist/src/ui/useChat.d.ts +18 -0
  353. package/dist/src/ui/useChat.d.ts.map +1 -0
  354. package/dist/src/ui/useChat.js +599 -0
  355. package/dist/src/ui/useChat.js.map +1 -0
  356. package/dist/src/ui/useElapsedTime.d.ts +11 -0
  357. package/dist/src/ui/useElapsedTime.d.ts.map +1 -0
  358. package/dist/src/ui/useElapsedTime.js +39 -0
  359. package/dist/src/ui/useElapsedTime.js.map +1 -0
  360. package/dist/src/ui/useResponsiveLayout.d.ts +16 -0
  361. package/dist/src/ui/useResponsiveLayout.d.ts.map +1 -0
  362. package/dist/src/ui/useResponsiveLayout.js +24 -0
  363. package/dist/src/ui/useResponsiveLayout.js.map +1 -0
  364. package/dist/src/ui/useScroll.d.ts +20 -0
  365. package/dist/src/ui/useScroll.d.ts.map +1 -0
  366. package/dist/src/ui/useScroll.js +64 -0
  367. package/dist/src/ui/useScroll.js.map +1 -0
  368. package/dist/src/ui/useSessionResume.d.ts +20 -0
  369. package/dist/src/ui/useSessionResume.d.ts.map +1 -0
  370. package/dist/src/ui/useSessionResume.js +77 -0
  371. package/dist/src/ui/useSessionResume.js.map +1 -0
  372. package/dist/tsconfig.tsbuildinfo +1 -0
  373. package/package.json +60 -0
  374. package/src/auth/index.ts +13 -0
  375. package/src/auth/oauth2.test.ts +305 -0
  376. package/src/auth/oauth2.ts +269 -0
  377. package/src/auth/prompt.test.ts +205 -0
  378. package/src/auth/prompt.ts +111 -0
  379. package/src/auth/test-connection.test.ts +224 -0
  380. package/src/auth/test-connection.ts +196 -0
  381. package/src/auth/types.ts +34 -0
  382. package/src/commands/audit.test.ts +92 -0
  383. package/src/commands/audit.ts +113 -0
  384. package/src/commands/automations.test.ts +85 -0
  385. package/src/commands/automations.ts +205 -0
  386. package/src/commands/build-manifest-types.ts +35 -0
  387. package/src/commands/build-tools.ts +281 -0
  388. package/src/commands/build.test.ts +63 -0
  389. package/src/commands/build.ts +135 -0
  390. package/src/commands/chat.ts +147 -0
  391. package/src/commands/command-exports.test.ts +88 -0
  392. package/src/commands/connect.test.ts +343 -0
  393. package/src/commands/connect.ts +237 -0
  394. package/src/commands/deploy.test.ts +124 -0
  395. package/src/commands/deploy.ts +153 -0
  396. package/src/commands/deployments.ts +90 -0
  397. package/src/commands/dev.test.ts +63 -0
  398. package/src/commands/dev.ts +124 -0
  399. package/src/commands/diff.test.ts +183 -0
  400. package/src/commands/diff.ts +143 -0
  401. package/src/commands/docker.ts +232 -0
  402. package/src/commands/eval.test.ts +88 -0
  403. package/src/commands/eval.ts +268 -0
  404. package/src/commands/experiment.test.ts +125 -0
  405. package/src/commands/experiment.ts +153 -0
  406. package/src/commands/index.ts +76 -0
  407. package/src/commands/init.test.ts +109 -0
  408. package/src/commands/init.ts +98 -0
  409. package/src/commands/inspect.test.ts +234 -0
  410. package/src/commands/inspect.ts +157 -0
  411. package/src/commands/install-pkg.test.ts +265 -0
  412. package/src/commands/install-pkg.ts +234 -0
  413. package/src/commands/link.ts +270 -0
  414. package/src/commands/list.test.ts +152 -0
  415. package/src/commands/list.ts +95 -0
  416. package/src/commands/login.test.ts +195 -0
  417. package/src/commands/login.ts +258 -0
  418. package/src/commands/promote.ts +64 -0
  419. package/src/commands/publish.test.ts +203 -0
  420. package/src/commands/publish.ts +142 -0
  421. package/src/commands/rollback.ts +72 -0
  422. package/src/commands/search.test.ts +174 -0
  423. package/src/commands/search.ts +154 -0
  424. package/src/commands/secrets.test.ts +168 -0
  425. package/src/commands/secrets.ts +163 -0
  426. package/src/commands/serve.ts +166 -0
  427. package/src/commands/status.ts +94 -0
  428. package/src/commands/sync.test.ts +130 -0
  429. package/src/commands/sync.ts +119 -0
  430. package/src/commands/test-query.test.ts +42 -0
  431. package/src/commands/test-query.ts +129 -0
  432. package/src/commands/uninstall.test.ts +162 -0
  433. package/src/commands/uninstall.ts +107 -0
  434. package/src/commands/update.test.ts +281 -0
  435. package/src/commands/update.ts +180 -0
  436. package/src/commands/validate.test.ts +260 -0
  437. package/src/commands/validate.ts +139 -0
  438. package/src/e2e-automations.test.ts +305 -0
  439. package/src/e2e-commands.test.ts +587 -0
  440. package/src/e2e-incident-response.test.ts +345 -0
  441. package/src/e2e-plugin-connections.test.ts +415 -0
  442. package/src/e2e-plugins.test.ts +492 -0
  443. package/src/e2e.test.ts +602 -0
  444. package/src/fixtures/incident-response.ts +232 -0
  445. package/src/main.ts +35 -0
  446. package/src/shared/platform-client.test.ts +106 -0
  447. package/src/shared/platform-client.ts +193 -0
  448. package/src/shared/repo-discovery.test.ts +56 -0
  449. package/src/shared/repo-discovery.ts +40 -0
  450. package/src/templates/compose-template.ts +30 -0
  451. package/src/templates/config-template.ts +44 -0
  452. package/src/templates/deployment-templates.test.ts +99 -0
  453. package/src/templates/dockerfile-template.ts +30 -0
  454. package/src/templates/env-template.ts +27 -0
  455. package/src/templates/knowledge-template.ts +24 -0
  456. package/src/templates/skill-template.ts +27 -0
  457. package/src/ui/AskUserPrompt.tsx +58 -0
  458. package/src/ui/AssistantMessage.tsx +51 -0
  459. package/src/ui/ChatApp.tsx +283 -0
  460. package/src/ui/ConfirmationPrompt.tsx +75 -0
  461. package/src/ui/DiffRenderer.test.ts +104 -0
  462. package/src/ui/DiffRenderer.tsx +188 -0
  463. package/src/ui/ExpandableContent.tsx +68 -0
  464. package/src/ui/ExploreIndicator.tsx +44 -0
  465. package/src/ui/Footer.tsx +87 -0
  466. package/src/ui/FullScreenLayout.tsx +45 -0
  467. package/src/ui/Header.tsx +50 -0
  468. package/src/ui/InputBar.tsx +105 -0
  469. package/src/ui/MessageList.tsx +31 -0
  470. package/src/ui/NotificationBar.tsx +64 -0
  471. package/src/ui/ScrollableMessageList.tsx +82 -0
  472. package/src/ui/SessionBrowser.test.ts +49 -0
  473. package/src/ui/SessionBrowser.tsx +179 -0
  474. package/src/ui/StatusMessage.tsx +35 -0
  475. package/src/ui/StreamingView.tsx +87 -0
  476. package/src/ui/SubagentDisplay.tsx +57 -0
  477. package/src/ui/ThinkingDisplay.tsx +45 -0
  478. package/src/ui/ToolCallDisplay.tsx +268 -0
  479. package/src/ui/UserMessage.tsx +22 -0
  480. package/src/ui/chat-e2e.test.ts +581 -0
  481. package/src/ui/commands/clear.ts +15 -0
  482. package/src/ui/commands/help.ts +31 -0
  483. package/src/ui/commands/index.ts +22 -0
  484. package/src/ui/commands/model.ts +19 -0
  485. package/src/ui/commands/registry.test.ts +76 -0
  486. package/src/ui/commands/registry.ts +66 -0
  487. package/src/ui/commands/sessions.ts +16 -0
  488. package/src/ui/commands/stats.ts +35 -0
  489. package/src/ui/commands/theme.ts +41 -0
  490. package/src/ui/markdown/CodeBlock.tsx +118 -0
  491. package/src/ui/markdown/InlineRenderer.tsx +115 -0
  492. package/src/ui/markdown/MarkdownDisplay.tsx +223 -0
  493. package/src/ui/markdown/Table.tsx +75 -0
  494. package/src/ui/theme.ts +39 -0
  495. package/src/ui/themes/index.ts +113 -0
  496. package/src/ui/themes/light.ts +39 -0
  497. package/src/ui/themes/monochrome.ts +39 -0
  498. package/src/ui/types.ts +157 -0
  499. package/src/ui/useAlternateBuffer.ts +27 -0
  500. package/src/ui/useChat.test.ts +492 -0
  501. package/src/ui/useChat.ts +693 -0
  502. package/src/ui/useElapsedTime.test.ts +33 -0
  503. package/src/ui/useElapsedTime.ts +43 -0
  504. package/src/ui/useResponsiveLayout.test.ts +54 -0
  505. package/src/ui/useResponsiveLayout.ts +32 -0
  506. package/src/ui/useScroll.test.ts +99 -0
  507. package/src/ui/useScroll.ts +97 -0
  508. package/src/ui/useSessionResume.test.ts +80 -0
  509. package/src/ui/useSessionResume.ts +102 -0
  510. package/tsconfig.json +17 -0
  511. package/vitest.config.ts +20 -0
@@ -0,0 +1,232 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+
7
+ /**
8
+ * Fixture data for the incident response e2e test.
9
+ *
10
+ * Four content types:
11
+ * 1. Connection: statuspage API (mock)
12
+ * 2. Skill: incident triage methodology
13
+ * 3. Knowledge: oncall runbook
14
+ * 4. Automation: daily health check
15
+ *
16
+ * The mock API returns deterministic data so we can assert on the
17
+ * agent's response content.
18
+ */
19
+
20
+ import http from 'node:http';
21
+
22
+ // ---------------------------------------------------------------------------
23
+ // amodal.json
24
+ // ---------------------------------------------------------------------------
25
+
26
+ export const CONFIG = {
27
+ name: 'incident-response-agent',
28
+ version: '1.0.0',
29
+ description: 'Monitors services and triages incidents',
30
+ models: {
31
+ main: {provider: 'anthropic', model: 'claude-sonnet-4-20250514'},
32
+ },
33
+ };
34
+
35
+ // ---------------------------------------------------------------------------
36
+ // Connection: statuspage
37
+ // ---------------------------------------------------------------------------
38
+
39
+ export const STATUSPAGE_SPEC = {
40
+ source: 'https://statuspage.example.com/api/v1/openapi.json',
41
+ format: 'openapi' as const,
42
+ auth: {
43
+ type: 'bearer',
44
+ header: 'Authorization',
45
+ prefix: 'Bearer',
46
+ token: 'env:STATUSPAGE_TOKEN',
47
+ },
48
+ };
49
+
50
+ export const STATUSPAGE_ACCESS = {
51
+ endpoints: {
52
+ 'GET /components': {returns: ['id', 'name', 'status', 'updated_at']},
53
+ 'GET /incidents': {returns: ['id', 'name', 'status', 'impact', 'created_at']},
54
+ 'GET /incidents/:id': {returns: ['id', 'name', 'status', 'impact', 'body', 'components']},
55
+ 'POST /incidents': {returns: ['id'], confirm: 'review' as const},
56
+ },
57
+ };
58
+
59
+ export const STATUSPAGE_SURFACE = `## Included
60
+
61
+ ### GET /components
62
+ List all monitored components and their current status
63
+
64
+ ### GET /incidents
65
+ List recent incidents
66
+
67
+ ### GET /incidents/:id
68
+ Get incident details
69
+
70
+ ## Excluded
71
+
72
+ ### POST /incidents
73
+ Create a new incident (requires confirmation)
74
+ `;
75
+
76
+ // ---------------------------------------------------------------------------
77
+ // Skill: incident-triage
78
+ // ---------------------------------------------------------------------------
79
+
80
+ export const TRIAGE_SKILL = `---
81
+ name: incident-triage
82
+ description: Methodology for triaging service incidents based on component status
83
+ trigger: When the user asks about service health, incidents, or outages
84
+ ---
85
+
86
+ ## Incident Triage
87
+
88
+ Follow this methodology when assessing service health:
89
+
90
+ 1. **Check component status** — Query GET /components to see current state of all services
91
+ 2. **Identify degraded components** — Any component not in "operational" status needs attention
92
+ 3. **Assess severity** — Use the severity matrix from the oncall runbook
93
+ 4. **Check recent incidents** — Query GET /incidents for correlated issues
94
+ 5. **Recommend action** — Based on severity, recommend the appropriate response from the runbook
95
+
96
+ Always report the exact component names and their statuses. Never fabricate status data.
97
+ `;
98
+
99
+ // ---------------------------------------------------------------------------
100
+ // Knowledge: oncall-runbook
101
+ // ---------------------------------------------------------------------------
102
+
103
+ export const ONCALL_RUNBOOK = `# On-Call Runbook
104
+
105
+ ## Severity Matrix
106
+
107
+ | Level | Criteria | Response Time | Escalation |
108
+ |-------|----------|---------------|------------|
109
+ | SEV1 | Multiple components down | 5 min | Page on-call lead immediately |
110
+ | SEV2 | Single component degraded | 15 min | Notify #incidents channel |
111
+ | SEV3 | Performance degradation | 1 hour | Create ticket |
112
+ | SEV4 | Cosmetic or minor | Next business day | Log for review |
113
+
114
+ ## Key Contacts
115
+
116
+ - **On-call lead**: Alice (alice@example.com)
117
+ - **Platform team**: Bob (bob@example.com)
118
+ - **Database team**: Charlie (charlie@example.com)
119
+
120
+ ## Components
121
+
122
+ - **api-gateway**: Main API entry point. SEV1 if down.
123
+ - **auth-service**: Authentication. SEV1 if down.
124
+ - **database-primary**: Primary Postgres. SEV1 if down.
125
+ - **worker-pool**: Background jobs. SEV2 if degraded.
126
+ - **cdn**: Static assets. SEV3 if degraded.
127
+ `;
128
+
129
+ // ---------------------------------------------------------------------------
130
+ // Automation: health-check
131
+ // ---------------------------------------------------------------------------
132
+
133
+ export const HEALTH_CHECK_AUTOMATION = `# Automation: Daily Health Check
134
+
135
+ Schedule: 0 8 * * *
136
+
137
+ ## Check
138
+ Query the statuspage API for current component status. Report any components not in "operational" state.
139
+
140
+ ## Output
141
+ Summary of component statuses with severity assessment per the oncall runbook.
142
+
143
+ ## Delivery
144
+ Post to #ops-daily channel.
145
+ `;
146
+
147
+ // ---------------------------------------------------------------------------
148
+ // Mock StatusPage API
149
+ // ---------------------------------------------------------------------------
150
+
151
+ /** Deterministic mock data the API returns. */
152
+ export const MOCK_COMPONENTS = [
153
+ {id: 'comp-1', name: 'api-gateway', status: 'operational', updated_at: '2026-03-18T08:00:00Z'},
154
+ {id: 'comp-2', name: 'auth-service', status: 'operational', updated_at: '2026-03-18T08:00:00Z'},
155
+ {id: 'comp-3', name: 'database-primary', status: 'degraded_performance', updated_at: '2026-03-18T09:15:00Z'},
156
+ {id: 'comp-4', name: 'worker-pool', status: 'operational', updated_at: '2026-03-18T08:00:00Z'},
157
+ {id: 'comp-5', name: 'cdn', status: 'operational', updated_at: '2026-03-18T08:00:00Z'},
158
+ ];
159
+
160
+ export const MOCK_INCIDENTS = [
161
+ {
162
+ id: 'inc-42',
163
+ name: 'Database latency spike',
164
+ status: 'investigating',
165
+ impact: 'minor',
166
+ created_at: '2026-03-18T09:10:00Z',
167
+ body: 'We are investigating elevated query latency on the primary database cluster.',
168
+ components: ['database-primary'],
169
+ },
170
+ ];
171
+
172
+ /**
173
+ * Create a mock StatusPage API server that returns deterministic data.
174
+ * Returns a handle with start/stop methods.
175
+ */
176
+ export function createMockStatusPageApi() {
177
+ const requests: Array<{method: string; url: string}> = [];
178
+
179
+ const server = http.createServer((req, res) => {
180
+ const url = req.url ?? '';
181
+ const method = req.method ?? '';
182
+ requests.push({method, url});
183
+
184
+ const json = (data: unknown) => {
185
+ res.writeHead(200, {'Content-Type': 'application/json'});
186
+ res.end(JSON.stringify(data));
187
+ };
188
+
189
+ if (method === 'GET' && url === '/components') {
190
+ json(MOCK_COMPONENTS);
191
+ return;
192
+ }
193
+
194
+ if (method === 'GET' && url === '/incidents') {
195
+ json(MOCK_INCIDENTS);
196
+ return;
197
+ }
198
+
199
+ const incidentMatch = /^\/incidents\/([^/]+)$/.exec(url);
200
+ if (method === 'GET' && incidentMatch) {
201
+ const incident = MOCK_INCIDENTS.find((i) => i.id === incidentMatch[1]);
202
+ if (incident) {
203
+ json(incident);
204
+ } else {
205
+ res.writeHead(404);
206
+ res.end(JSON.stringify({error: 'Not found'}));
207
+ }
208
+ return;
209
+ }
210
+
211
+ res.writeHead(404);
212
+ res.end(JSON.stringify({error: 'Not found'}));
213
+ });
214
+
215
+ let port = 0;
216
+
217
+ return {
218
+ server,
219
+ requests,
220
+ get port() { return port; },
221
+ start: () => new Promise<number>((resolve) => {
222
+ server.listen(0, '127.0.0.1', () => {
223
+ const addr = server.address();
224
+ port = typeof addr === 'object' && addr ? addr.port : 0;
225
+ resolve(port);
226
+ });
227
+ }),
228
+ stop: () => new Promise<void>((resolve, reject) => {
229
+ server.close((err) => (err ? reject(err) : resolve()));
230
+ }),
231
+ };
232
+ }
package/src/main.ts ADDED
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @license
4
+ * Copyright 2025 Amodal Labs, Inc.
5
+ * SPDX-License-Identifier: MIT
6
+ */
7
+
8
+ import {readFileSync} from 'node:fs';
9
+ import yargs from 'yargs';
10
+ import {hideBin} from 'yargs/helpers';
11
+ import {amodalCommands} from './commands/index.js';
12
+
13
+ const raw: unknown = JSON.parse(readFileSync(new URL('../../package.json', import.meta.url), 'utf-8'));
14
+ if (typeof raw !== 'object' || raw === null || !('version' in raw) || typeof raw.version !== 'string') {
15
+ throw new Error('Failed to read version from package.json');
16
+ }
17
+ const pkgVersion = raw.version;
18
+
19
+ const cli = yargs(hideBin(process.argv))
20
+ .scriptName('amodal')
21
+ .usage('$0 <command> [options]');
22
+
23
+ for (const cmd of amodalCommands) {
24
+ cli.command(cmd);
25
+ }
26
+
27
+ cli
28
+ .demandCommand(1, 'Run amodal <command> --help for usage')
29
+ .strict()
30
+ .help()
31
+ .alias('h', 'help')
32
+ .version(process.env['CLI_VERSION'] ?? pkgVersion)
33
+ .alias('v', 'version');
34
+
35
+ void cli.parse();
@@ -0,0 +1,106 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+
7
+ import {describe, it, expect, vi, beforeEach, afterEach} from 'vitest';
8
+ import {PlatformClient} from './platform-client.js';
9
+
10
+ describe('PlatformClient', () => {
11
+ const originalFetch = globalThis.fetch;
12
+
13
+ beforeEach(() => {
14
+ vi.restoreAllMocks();
15
+ });
16
+
17
+ afterEach(() => {
18
+ globalThis.fetch = originalFetch;
19
+ });
20
+
21
+ it('throws if PLATFORM_API_URL not set', () => {
22
+ const origUrl = process.env['PLATFORM_API_URL'];
23
+ const origKey = process.env['PLATFORM_API_KEY'];
24
+ delete process.env['PLATFORM_API_URL'];
25
+ delete process.env['PLATFORM_API_KEY'];
26
+
27
+ try {
28
+ expect(() => new PlatformClient()).toThrow('Platform URL not found');
29
+ } finally {
30
+ if (origUrl) process.env['PLATFORM_API_URL'] = origUrl;
31
+ if (origKey) process.env['PLATFORM_API_KEY'] = origKey;
32
+ }
33
+ });
34
+
35
+ it('throws if PLATFORM_API_KEY not set', () => {
36
+ expect(() => new PlatformClient({url: 'http://localhost:4000'})).toThrow('Platform auth not found');
37
+ });
38
+
39
+ it('creates client with explicit options', () => {
40
+ const client = new PlatformClient({url: 'http://localhost:4000', apiKey: 'test-key'});
41
+ expect(client).toBeDefined();
42
+ });
43
+
44
+ it('uploads snapshot via POST', async () => {
45
+ const mockResponse = {
46
+ id: 'deploy-abc1234',
47
+ environment: 'production',
48
+ isActive: true,
49
+ createdAt: new Date().toISOString(),
50
+ createdBy: 'test',
51
+ source: 'cli',
52
+ snapshotSize: 1024,
53
+ };
54
+
55
+ globalThis.fetch = vi.fn().mockResolvedValue({
56
+ ok: true,
57
+ json: () => Promise.resolve(mockResponse),
58
+ });
59
+
60
+ const client = new PlatformClient({url: 'http://localhost:4000', apiKey: 'key'});
61
+ const result = await client.uploadSnapshot({
62
+ deployId: 'deploy-abc1234',
63
+ createdAt: new Date().toISOString(),
64
+ createdBy: 'test',
65
+ source: 'cli',
66
+ config: {name: 'test', version: '1.0', models: {main: {provider: 'a', model: 'b'}}},
67
+ connections: {},
68
+ skills: [],
69
+ automations: [],
70
+ knowledge: [],
71
+ });
72
+
73
+ expect(result.id).toBe('deploy-abc1234');
74
+
75
+ const fetchCall = (globalThis.fetch as ReturnType<typeof vi.fn>).mock.calls[0] as [string, RequestInit];
76
+ expect(fetchCall[0]).toBe('http://localhost:4000/api/snapshot-deployments');
77
+ expect(fetchCall[1].method).toBe('POST');
78
+ });
79
+
80
+ it('lists deployments via GET', async () => {
81
+ globalThis.fetch = vi.fn().mockResolvedValue({
82
+ ok: true,
83
+ json: () => Promise.resolve([]),
84
+ });
85
+
86
+ const client = new PlatformClient({url: 'http://localhost:4000', apiKey: 'key'});
87
+ const result = await client.listDeployments({environment: 'staging', limit: 5});
88
+
89
+ expect(result).toEqual([]);
90
+
91
+ const fetchCall = (globalThis.fetch as ReturnType<typeof vi.fn>).mock.calls[0] as [string];
92
+ expect(fetchCall[0]).toContain('environment=staging');
93
+ expect(fetchCall[0]).toContain('limit=5');
94
+ });
95
+
96
+ it('throws on non-ok response', async () => {
97
+ globalThis.fetch = vi.fn().mockResolvedValue({
98
+ ok: false,
99
+ status: 401,
100
+ json: () => Promise.resolve({error: 'Unauthorized'}),
101
+ });
102
+
103
+ const client = new PlatformClient({url: 'http://localhost:4000', apiKey: 'bad-key'});
104
+ await expect(client.listDeployments()).rejects.toThrow('failed (401)');
105
+ });
106
+ });
@@ -0,0 +1,193 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+
7
+ import type {DeploySnapshot} from '@amodalai/core';
8
+ import {readProjectLink} from '../commands/link.js';
9
+ import {readRcFile} from '../commands/login.js';
10
+
11
+ /**
12
+ * Metadata returned for a snapshot deployment.
13
+ */
14
+ export interface SnapshotDeploymentMeta {
15
+ id: string;
16
+ environment: string;
17
+ isActive: boolean;
18
+ createdAt: string;
19
+ createdBy: string;
20
+ source: string;
21
+ commitSha?: string;
22
+ branch?: string;
23
+ message?: string;
24
+ snapshotSize: number;
25
+ }
26
+
27
+ /**
28
+ * Resolve platform URL and API key from multiple sources:
29
+ * 1. Explicit options (flags)
30
+ * 2. .amodal/project.json (platformUrl from `amodal link`)
31
+ * 3. ~/.amodalrc (auth token from `amodal login`)
32
+ * 4. Env vars (fallback)
33
+ */
34
+ export async function resolvePlatformConfig(options?: {
35
+ url?: string;
36
+ apiKey?: string;
37
+ }): Promise<{url: string; apiKey: string}> {
38
+ let url = options?.url;
39
+ let apiKey = options?.apiKey;
40
+
41
+ // Try project link for URL
42
+ if (!url) {
43
+ const link = await readProjectLink();
44
+ if (link?.platformUrl) {
45
+ url = link.platformUrl;
46
+ }
47
+ }
48
+
49
+ // Try rc file for auth token
50
+ if (!apiKey) {
51
+ const rc = await readRcFile();
52
+ if (rc.platform?.token) {
53
+ apiKey = rc.platform.token;
54
+ // Also use the URL from rc if still missing
55
+ if (!url && rc.platform.url) {
56
+ url = rc.platform.url;
57
+ }
58
+ }
59
+ }
60
+
61
+ // Env vars as fallback
62
+ if (!url) url = process.env['PLATFORM_API_URL'];
63
+ if (!apiKey) apiKey = process.env['PLATFORM_API_KEY'];
64
+
65
+ if (!url) throw new Error('Platform URL not found. Run `amodal login` + `amodal link`, or set PLATFORM_API_URL.');
66
+ if (!apiKey) throw new Error('Platform auth not found. Run `amodal login`, or set PLATFORM_API_KEY.');
67
+
68
+ return {url: url.replace(/\/$/, ''), apiKey};
69
+ }
70
+
71
+ /**
72
+ * Platform API client for snapshot deployments.
73
+ *
74
+ * Resolves credentials from: explicit options → project link → rc file → env vars.
75
+ * Use `PlatformClient.create()` for async auto-discovery, or `new PlatformClient()` for sync usage.
76
+ */
77
+ export class PlatformClient {
78
+ private readonly baseUrl: string;
79
+ private readonly apiKey: string;
80
+
81
+ constructor(options?: {url?: string; apiKey?: string}) {
82
+ const url = options?.url ?? process.env['PLATFORM_API_URL'];
83
+ const apiKey = options?.apiKey ?? process.env['PLATFORM_API_KEY'];
84
+ if (!url) throw new Error('Platform URL not found. Run `amodal login` + `amodal link`, or set PLATFORM_API_URL.');
85
+ if (!apiKey) throw new Error('Platform auth not found. Run `amodal login`, or set PLATFORM_API_KEY.');
86
+ this.baseUrl = url.replace(/\/$/, '');
87
+ this.apiKey = apiKey;
88
+ }
89
+
90
+ /**
91
+ * Create a PlatformClient with auto-discovery of credentials.
92
+ * Resolves from: explicit options → project link → rc file → env vars.
93
+ */
94
+ static async create(options?: {url?: string; apiKey?: string}): Promise<PlatformClient> {
95
+ const config = await resolvePlatformConfig(options);
96
+ return new PlatformClient(config);
97
+ }
98
+
99
+ private headers(): Record<string, string> {
100
+ return {
101
+ 'Authorization': `Bearer ${this.apiKey}`,
102
+ 'Content-Type': 'application/json',
103
+ };
104
+ }
105
+
106
+ private async request<T>(method: string, path: string, body?: unknown): Promise<T> {
107
+ const url = `${this.baseUrl}${path}`;
108
+ const resp = await fetch(url, {
109
+ method,
110
+ headers: this.headers(),
111
+ ...(body ? {body: JSON.stringify(body)} : {}),
112
+ });
113
+
114
+ if (!resp.ok) {
115
+ let detail = '';
116
+ try {
117
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
118
+ const errBody = await resp.json() as {error?: string};
119
+ detail = errBody.error ? `: ${errBody.error}` : '';
120
+ } catch {
121
+ // ignore parse errors
122
+ }
123
+ throw new Error(`Platform API ${method} ${path} failed (${resp.status})${detail}`);
124
+ }
125
+
126
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
127
+ return resp.json() as Promise<T>;
128
+ }
129
+
130
+ /**
131
+ * Upload a snapshot and deploy it.
132
+ */
133
+ async uploadSnapshot(snapshot: DeploySnapshot, options: {
134
+ environment?: string;
135
+ } = {}): Promise<SnapshotDeploymentMeta> {
136
+ return this.request<SnapshotDeploymentMeta>('POST', '/api/snapshot-deployments', {
137
+ snapshot,
138
+ environment: options.environment ?? 'production',
139
+ });
140
+ }
141
+
142
+ /**
143
+ * List deployments for the authenticated tenant.
144
+ */
145
+ async listDeployments(options: {
146
+ environment?: string;
147
+ limit?: number;
148
+ } = {}): Promise<SnapshotDeploymentMeta[]> {
149
+ const params = new URLSearchParams();
150
+ if (options.environment) params.set('environment', options.environment);
151
+ if (options.limit) params.set('limit', String(options.limit));
152
+ const qs = params.toString();
153
+ return this.request<SnapshotDeploymentMeta[]>('GET', `/api/snapshot-deployments${qs ? `?${qs}` : ''}`);
154
+ }
155
+
156
+ /**
157
+ * Rollback to a previous deployment.
158
+ */
159
+ async rollback(options: {
160
+ deployId?: string;
161
+ environment?: string;
162
+ } = {}): Promise<SnapshotDeploymentMeta> {
163
+ return this.request<SnapshotDeploymentMeta>('POST', '/api/snapshot-deployments/rollback', {
164
+ deployId: options.deployId,
165
+ environment: options.environment ?? 'production',
166
+ });
167
+ }
168
+
169
+ /**
170
+ * Promote a deployment from one environment to another.
171
+ */
172
+ async promote(fromEnv: string, toEnv: string = 'production'): Promise<SnapshotDeploymentMeta> {
173
+ return this.request<SnapshotDeploymentMeta>('POST', '/api/snapshot-deployments/promote', {
174
+ fromEnvironment: fromEnv,
175
+ toEnvironment: toEnv,
176
+ });
177
+ }
178
+
179
+ /**
180
+ * Get status of a specific deployment.
181
+ */
182
+ async getStatus(deployId: string): Promise<SnapshotDeploymentMeta> {
183
+ return this.request<SnapshotDeploymentMeta>('GET', `/api/snapshot-deployments/${deployId}`);
184
+ }
185
+
186
+ /**
187
+ * Get the active snapshot for an environment.
188
+ */
189
+ async getActiveSnapshot(environment: string = 'production'): Promise<DeploySnapshot> {
190
+ const params = new URLSearchParams({environment});
191
+ return this.request<DeploySnapshot>('GET', `/api/snapshot-deployments/active?${params.toString()}`);
192
+ }
193
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+
7
+ import {describe, it, expect, vi, beforeEach} from 'vitest';
8
+ import {findRepoRoot} from './repo-discovery.js';
9
+
10
+ vi.mock('node:fs', () => ({
11
+ existsSync: vi.fn(),
12
+ }));
13
+
14
+ describe('findRepoRoot', () => {
15
+ let existsSync: ReturnType<typeof vi.fn>;
16
+
17
+ beforeEach(async () => {
18
+ const fs = await import('node:fs');
19
+ existsSync = vi.mocked(fs.existsSync);
20
+ existsSync.mockReset();
21
+ });
22
+
23
+ it('should find repo root when config is in current directory', () => {
24
+ existsSync.mockImplementation((path: string) =>
25
+ path === '/projects/myapp/amodal.json',
26
+ );
27
+
28
+ const result = findRepoRoot('/projects/myapp');
29
+ expect(result).toBe('/projects/myapp');
30
+ });
31
+
32
+ it('should find repo root in parent directory', () => {
33
+ existsSync.mockImplementation((path: string) =>
34
+ path === '/projects/myapp/amodal.json',
35
+ );
36
+
37
+ const result = findRepoRoot('/projects/myapp/src/lib');
38
+ expect(result).toBe('/projects/myapp');
39
+ });
40
+
41
+ it('should throw when config is not found', () => {
42
+ existsSync.mockReturnValue(false);
43
+
44
+ expect(() => findRepoRoot('/some/deep/path')).toThrow(
45
+ 'Could not find amodal.json',
46
+ );
47
+ });
48
+
49
+ it('should handle root directory without infinite loop', () => {
50
+ existsSync.mockReturnValue(false);
51
+
52
+ expect(() => findRepoRoot('/')).toThrow(
53
+ 'Could not find amodal.json',
54
+ );
55
+ });
56
+ });
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+
7
+ import {existsSync} from 'node:fs';
8
+ import {join, resolve, dirname} from 'node:path';
9
+
10
+ /**
11
+ * Walks up from `startDir` (or cwd) looking for a directory containing
12
+ * `amodal.json`. Throws if not found.
13
+ */
14
+ export function findRepoRoot(startDir?: string): string {
15
+ let dir = resolve(startDir ?? process.cwd());
16
+
17
+ // Safety limit to prevent infinite loops
18
+ const maxDepth = 100;
19
+ let depth = 0;
20
+
21
+ while (depth < maxDepth) {
22
+ const configPath = join(dir, 'amodal.json');
23
+ if (existsSync(configPath)) {
24
+ return dir;
25
+ }
26
+
27
+ const parent = dirname(dir);
28
+ if (parent === dir) {
29
+ // Reached filesystem root
30
+ break;
31
+ }
32
+ dir = parent;
33
+ depth++;
34
+ }
35
+
36
+ throw new Error(
37
+ 'Could not find amodal.json in any parent directory. ' +
38
+ 'Run `amodal init` to create a new project, or change to a directory containing an amodal.json file.',
39
+ );
40
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Amodal Labs, Inc.
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+
7
+ /**
8
+ * Generate a docker-compose.yml for local/staging deployment.
9
+ */
10
+ export function generateCompose(serviceName: string): string {
11
+ const safeName = serviceName.replace(/[^a-z0-9-]/gi, '-').toLowerCase();
12
+ return `# Docker Compose for amodal runtime
13
+ # Generated by: amodal deploy init
14
+
15
+ services:
16
+ ${safeName}:
17
+ build: .
18
+ ports:
19
+ - "3847:3847"
20
+ env_file:
21
+ - .env.production
22
+ restart: unless-stopped
23
+ healthcheck:
24
+ test: ["CMD", "curl", "-f", "http://localhost:3847/health"]
25
+ interval: 30s
26
+ timeout: 10s
27
+ retries: 3
28
+ start_period: 10s
29
+ `;
30
+ }