@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.
- package/CHANGELOG.md +21 -0
- package/LICENSE +21 -0
- package/README.md +42 -0
- package/dist/src/auth/index.d.ts +13 -0
- package/dist/src/auth/index.d.ts.map +1 -0
- package/dist/src/auth/index.js +10 -0
- package/dist/src/auth/index.js.map +1 -0
- package/dist/src/auth/oauth2.d.ts +51 -0
- package/dist/src/auth/oauth2.d.ts.map +1 -0
- package/dist/src/auth/oauth2.js +196 -0
- package/dist/src/auth/oauth2.js.map +1 -0
- package/dist/src/auth/prompt.d.ts +21 -0
- package/dist/src/auth/prompt.d.ts.map +1 -0
- package/dist/src/auth/prompt.js +81 -0
- package/dist/src/auth/prompt.js.map +1 -0
- package/dist/src/auth/test-connection.d.ts +27 -0
- package/dist/src/auth/test-connection.d.ts.map +1 -0
- package/dist/src/auth/test-connection.js +153 -0
- package/dist/src/auth/test-connection.js.map +1 -0
- package/dist/src/auth/types.d.ts +32 -0
- package/dist/src/auth/types.d.ts.map +1 -0
- package/dist/src/auth/types.js +7 -0
- package/dist/src/auth/types.js.map +1 -0
- package/dist/src/commands/audit.d.ts +18 -0
- package/dist/src/commands/audit.d.ts.map +1 -0
- package/dist/src/commands/audit.js +86 -0
- package/dist/src/commands/audit.js.map +1 -0
- package/dist/src/commands/automations.d.ts +28 -0
- package/dist/src/commands/automations.d.ts.map +1 -0
- package/dist/src/commands/automations.js +179 -0
- package/dist/src/commands/automations.js.map +1 -0
- package/dist/src/commands/build-manifest-types.d.ts +33 -0
- package/dist/src/commands/build-manifest-types.d.ts.map +1 -0
- package/dist/src/commands/build-manifest-types.js +30 -0
- package/dist/src/commands/build-manifest-types.js.map +1 -0
- package/dist/src/commands/build-tools.d.ts +33 -0
- package/dist/src/commands/build-tools.d.ts.map +1 -0
- package/dist/src/commands/build-tools.js +237 -0
- package/dist/src/commands/build-tools.js.map +1 -0
- package/dist/src/commands/build.d.ts +23 -0
- package/dist/src/commands/build.d.ts.map +1 -0
- package/dist/src/commands/build.js +120 -0
- package/dist/src/commands/build.js.map +1 -0
- package/dist/src/commands/chat.d.ts +26 -0
- package/dist/src/commands/chat.d.ts.map +1 -0
- package/dist/src/commands/chat.js +123 -0
- package/dist/src/commands/chat.js.map +1 -0
- package/dist/src/commands/connect.d.ts +18 -0
- package/dist/src/commands/connect.d.ts.map +1 -0
- package/dist/src/commands/connect.js +198 -0
- package/dist/src/commands/connect.js.map +1 -0
- package/dist/src/commands/deploy.d.ts +20 -0
- package/dist/src/commands/deploy.d.ts.map +1 -0
- package/dist/src/commands/deploy.js +137 -0
- package/dist/src/commands/deploy.js.map +1 -0
- package/dist/src/commands/deployments.d.ts +17 -0
- package/dist/src/commands/deployments.d.ts.map +1 -0
- package/dist/src/commands/deployments.js +77 -0
- package/dist/src/commands/deployments.js.map +1 -0
- package/dist/src/commands/dev.d.ts +17 -0
- package/dist/src/commands/dev.d.ts.map +1 -0
- package/dist/src/commands/dev.js +109 -0
- package/dist/src/commands/dev.js.map +1 -0
- package/dist/src/commands/diff.d.ts +19 -0
- package/dist/src/commands/diff.d.ts.map +1 -0
- package/dist/src/commands/diff.js +120 -0
- package/dist/src/commands/diff.js.map +1 -0
- package/dist/src/commands/docker.d.ts +21 -0
- package/dist/src/commands/docker.d.ts.map +1 -0
- package/dist/src/commands/docker.js +215 -0
- package/dist/src/commands/docker.js.map +1 -0
- package/dist/src/commands/eval.d.ts +20 -0
- package/dist/src/commands/eval.d.ts.map +1 -0
- package/dist/src/commands/eval.js +236 -0
- package/dist/src/commands/eval.js.map +1 -0
- package/dist/src/commands/experiment.d.ts +21 -0
- package/dist/src/commands/experiment.d.ts.map +1 -0
- package/dist/src/commands/experiment.js +133 -0
- package/dist/src/commands/experiment.js.map +1 -0
- package/dist/src/commands/index.d.ts +10 -0
- package/dist/src/commands/index.d.ts.map +1 -0
- package/dist/src/commands/index.js +75 -0
- package/dist/src/commands/index.js.map +1 -0
- package/dist/src/commands/init.d.ts +17 -0
- package/dist/src/commands/init.d.ts.map +1 -0
- package/dist/src/commands/init.js +73 -0
- package/dist/src/commands/init.js.map +1 -0
- package/dist/src/commands/inspect.d.ts +22 -0
- package/dist/src/commands/inspect.d.ts.map +1 -0
- package/dist/src/commands/inspect.js +131 -0
- package/dist/src/commands/inspect.js.map +1 -0
- package/dist/src/commands/install-pkg.d.ts +29 -0
- package/dist/src/commands/install-pkg.d.ts.map +1 -0
- package/dist/src/commands/install-pkg.js +202 -0
- package/dist/src/commands/install-pkg.js.map +1 -0
- package/dist/src/commands/link.d.ts +32 -0
- package/dist/src/commands/link.d.ts.map +1 -0
- package/dist/src/commands/link.js +227 -0
- package/dist/src/commands/link.js.map +1 -0
- package/dist/src/commands/list.d.ts +19 -0
- package/dist/src/commands/list.d.ts.map +1 -0
- package/dist/src/commands/list.js +78 -0
- package/dist/src/commands/list.js.map +1 -0
- package/dist/src/commands/login.d.ts +31 -0
- package/dist/src/commands/login.d.ts.map +1 -0
- package/dist/src/commands/login.js +205 -0
- package/dist/src/commands/login.js.map +1 -0
- package/dist/src/commands/promote.d.ts +16 -0
- package/dist/src/commands/promote.d.ts.map +1 -0
- package/dist/src/commands/promote.js +55 -0
- package/dist/src/commands/promote.js.map +1 -0
- package/dist/src/commands/publish.d.ts +18 -0
- package/dist/src/commands/publish.d.ts.map +1 -0
- package/dist/src/commands/publish.js +122 -0
- package/dist/src/commands/publish.js.map +1 -0
- package/dist/src/commands/rollback.d.ts +17 -0
- package/dist/src/commands/rollback.d.ts.map +1 -0
- package/dist/src/commands/rollback.js +62 -0
- package/dist/src/commands/rollback.js.map +1 -0
- package/dist/src/commands/search.d.ts +20 -0
- package/dist/src/commands/search.d.ts.map +1 -0
- package/dist/src/commands/search.js +133 -0
- package/dist/src/commands/search.js.map +1 -0
- package/dist/src/commands/secrets.d.ts +20 -0
- package/dist/src/commands/secrets.d.ts.map +1 -0
- package/dist/src/commands/secrets.js +137 -0
- package/dist/src/commands/secrets.js.map +1 -0
- package/dist/src/commands/serve.d.ts +23 -0
- package/dist/src/commands/serve.d.ts.map +1 -0
- package/dist/src/commands/serve.js +144 -0
- package/dist/src/commands/serve.js.map +1 -0
- package/dist/src/commands/status.d.ts +16 -0
- package/dist/src/commands/status.d.ts.map +1 -0
- package/dist/src/commands/status.js +83 -0
- package/dist/src/commands/status.js.map +1 -0
- package/dist/src/commands/sync.d.ts +21 -0
- package/dist/src/commands/sync.d.ts.map +1 -0
- package/dist/src/commands/sync.js +94 -0
- package/dist/src/commands/sync.js.map +1 -0
- package/dist/src/commands/test-query.d.ts +19 -0
- package/dist/src/commands/test-query.d.ts.map +1 -0
- package/dist/src/commands/test-query.js +116 -0
- package/dist/src/commands/test-query.js.map +1 -0
- package/dist/src/commands/uninstall.d.ts +19 -0
- package/dist/src/commands/uninstall.d.ts.map +1 -0
- package/dist/src/commands/uninstall.js +84 -0
- package/dist/src/commands/uninstall.js.map +1 -0
- package/dist/src/commands/update.d.ts +21 -0
- package/dist/src/commands/update.d.ts.map +1 -0
- package/dist/src/commands/update.js +145 -0
- package/dist/src/commands/update.js.map +1 -0
- package/dist/src/commands/validate.d.ts +19 -0
- package/dist/src/commands/validate.d.ts.map +1 -0
- package/dist/src/commands/validate.js +114 -0
- package/dist/src/commands/validate.js.map +1 -0
- package/dist/src/fixtures/incident-response.d.ts +91 -0
- package/dist/src/fixtures/incident-response.d.ts.map +1 -0
- package/dist/src/fixtures/incident-response.js +208 -0
- package/dist/src/fixtures/incident-response.js.map +1 -0
- package/dist/src/main.d.ts +8 -0
- package/dist/src/main.d.ts.map +1 -0
- package/dist/src/main.js +30 -0
- package/dist/src/main.js.map +1 -0
- package/dist/src/shared/platform-client.d.ts +92 -0
- package/dist/src/shared/platform-client.d.ts.map +1 -0
- package/dist/src/shared/platform-client.js +155 -0
- package/dist/src/shared/platform-client.js.map +1 -0
- package/dist/src/shared/repo-discovery.d.ts +11 -0
- package/dist/src/shared/repo-discovery.d.ts.map +1 -0
- package/dist/src/shared/repo-discovery.js +33 -0
- package/dist/src/shared/repo-discovery.js.map +1 -0
- package/dist/src/templates/compose-template.d.ts +10 -0
- package/dist/src/templates/compose-template.d.ts.map +1 -0
- package/dist/src/templates/compose-template.js +30 -0
- package/dist/src/templates/compose-template.js.map +1 -0
- package/dist/src/templates/config-template.d.ts +14 -0
- package/dist/src/templates/config-template.d.ts.map +1 -0
- package/dist/src/templates/config-template.js +35 -0
- package/dist/src/templates/config-template.js.map +1 -0
- package/dist/src/templates/dockerfile-template.d.ts +10 -0
- package/dist/src/templates/dockerfile-template.d.ts.map +1 -0
- package/dist/src/templates/dockerfile-template.js +30 -0
- package/dist/src/templates/dockerfile-template.js.map +1 -0
- package/dist/src/templates/env-template.d.ts +12 -0
- package/dist/src/templates/env-template.d.ts.map +1 -0
- package/dist/src/templates/env-template.js +24 -0
- package/dist/src/templates/env-template.js.map +1 -0
- package/dist/src/templates/knowledge-template.d.ts +10 -0
- package/dist/src/templates/knowledge-template.d.ts.map +1 -0
- package/dist/src/templates/knowledge-template.js +24 -0
- package/dist/src/templates/knowledge-template.js.map +1 -0
- package/dist/src/templates/skill-template.d.ts +10 -0
- package/dist/src/templates/skill-template.d.ts.map +1 -0
- package/dist/src/templates/skill-template.js +27 -0
- package/dist/src/templates/skill-template.js.map +1 -0
- package/dist/src/ui/AskUserPrompt.d.ts +14 -0
- package/dist/src/ui/AskUserPrompt.d.ts.map +1 -0
- package/dist/src/ui/AskUserPrompt.js +17 -0
- package/dist/src/ui/AskUserPrompt.js.map +1 -0
- package/dist/src/ui/AssistantMessage.d.ts +14 -0
- package/dist/src/ui/AssistantMessage.d.ts.map +1 -0
- package/dist/src/ui/AssistantMessage.js +8 -0
- package/dist/src/ui/AssistantMessage.js.map +1 -0
- package/dist/src/ui/ChatApp.d.ts +15 -0
- package/dist/src/ui/ChatApp.d.ts.map +1 -0
- package/dist/src/ui/ChatApp.js +144 -0
- package/dist/src/ui/ChatApp.js.map +1 -0
- package/dist/src/ui/ConfirmationPrompt.d.ts +17 -0
- package/dist/src/ui/ConfirmationPrompt.d.ts.map +1 -0
- package/dist/src/ui/ConfirmationPrompt.js +21 -0
- package/dist/src/ui/ConfirmationPrompt.js.map +1 -0
- package/dist/src/ui/DiffRenderer.d.ts +32 -0
- package/dist/src/ui/DiffRenderer.d.ts.map +1 -0
- package/dist/src/ui/DiffRenderer.js +118 -0
- package/dist/src/ui/DiffRenderer.js.map +1 -0
- package/dist/src/ui/ExpandableContent.d.ts +15 -0
- package/dist/src/ui/ExpandableContent.d.ts.map +1 -0
- package/dist/src/ui/ExpandableContent.js +22 -0
- package/dist/src/ui/ExpandableContent.js.map +1 -0
- package/dist/src/ui/ExploreIndicator.d.ts +13 -0
- package/dist/src/ui/ExploreIndicator.d.ts.map +1 -0
- package/dist/src/ui/ExploreIndicator.js +14 -0
- package/dist/src/ui/ExploreIndicator.js.map +1 -0
- package/dist/src/ui/Footer.d.ts +19 -0
- package/dist/src/ui/Footer.d.ts.map +1 -0
- package/dist/src/ui/Footer.js +57 -0
- package/dist/src/ui/Footer.js.map +1 -0
- package/dist/src/ui/FullScreenLayout.d.ts +18 -0
- package/dist/src/ui/FullScreenLayout.d.ts.map +1 -0
- package/dist/src/ui/FullScreenLayout.js +14 -0
- package/dist/src/ui/FullScreenLayout.js.map +1 -0
- package/dist/src/ui/Header.d.ts +14 -0
- package/dist/src/ui/Header.d.ts.map +1 -0
- package/dist/src/ui/Header.js +11 -0
- package/dist/src/ui/Header.js.map +1 -0
- package/dist/src/ui/InputBar.d.ts +17 -0
- package/dist/src/ui/InputBar.d.ts.map +1 -0
- package/dist/src/ui/InputBar.js +49 -0
- package/dist/src/ui/InputBar.js.map +1 -0
- package/dist/src/ui/MessageList.d.ts +18 -0
- package/dist/src/ui/MessageList.d.ts.map +1 -0
- package/dist/src/ui/MessageList.js +9 -0
- package/dist/src/ui/MessageList.js.map +1 -0
- package/dist/src/ui/NotificationBar.d.ts +14 -0
- package/dist/src/ui/NotificationBar.d.ts.map +1 -0
- package/dist/src/ui/NotificationBar.js +38 -0
- package/dist/src/ui/NotificationBar.js.map +1 -0
- package/dist/src/ui/ScrollableMessageList.d.ts +27 -0
- package/dist/src/ui/ScrollableMessageList.d.ts.map +1 -0
- package/dist/src/ui/ScrollableMessageList.js +16 -0
- package/dist/src/ui/ScrollableMessageList.js.map +1 -0
- package/dist/src/ui/SessionBrowser.d.ts +20 -0
- package/dist/src/ui/SessionBrowser.d.ts.map +1 -0
- package/dist/src/ui/SessionBrowser.js +93 -0
- package/dist/src/ui/SessionBrowser.js.map +1 -0
- package/dist/src/ui/StatusMessage.d.ts +13 -0
- package/dist/src/ui/StatusMessage.d.ts.map +1 -0
- package/dist/src/ui/StatusMessage.js +17 -0
- package/dist/src/ui/StatusMessage.js.map +1 -0
- package/dist/src/ui/StreamingView.d.ts +19 -0
- package/dist/src/ui/StreamingView.d.ts.map +1 -0
- package/dist/src/ui/StreamingView.js +18 -0
- package/dist/src/ui/StreamingView.js.map +1 -0
- package/dist/src/ui/SubagentDisplay.d.ts +13 -0
- package/dist/src/ui/SubagentDisplay.d.ts.map +1 -0
- package/dist/src/ui/SubagentDisplay.js +22 -0
- package/dist/src/ui/SubagentDisplay.js.map +1 -0
- package/dist/src/ui/ThinkingDisplay.d.ts +13 -0
- package/dist/src/ui/ThinkingDisplay.d.ts.map +1 -0
- package/dist/src/ui/ThinkingDisplay.js +15 -0
- package/dist/src/ui/ThinkingDisplay.js.map +1 -0
- package/dist/src/ui/ToolCallDisplay.d.ts +16 -0
- package/dist/src/ui/ToolCallDisplay.d.ts.map +1 -0
- package/dist/src/ui/ToolCallDisplay.js +136 -0
- package/dist/src/ui/ToolCallDisplay.js.map +1 -0
- package/dist/src/ui/UserMessage.d.ts +12 -0
- package/dist/src/ui/UserMessage.d.ts.map +1 -0
- package/dist/src/ui/UserMessage.js +5 -0
- package/dist/src/ui/UserMessage.js.map +1 -0
- package/dist/src/ui/commands/clear.d.ts +7 -0
- package/dist/src/ui/commands/clear.d.ts.map +1 -0
- package/dist/src/ui/commands/clear.js +13 -0
- package/dist/src/ui/commands/clear.js.map +1 -0
- package/dist/src/ui/commands/help.d.ts +7 -0
- package/dist/src/ui/commands/help.d.ts.map +1 -0
- package/dist/src/ui/commands/help.js +26 -0
- package/dist/src/ui/commands/help.js.map +1 -0
- package/dist/src/ui/commands/index.d.ts +14 -0
- package/dist/src/ui/commands/index.d.ts.map +1 -0
- package/dist/src/ui/commands/index.js +15 -0
- package/dist/src/ui/commands/index.js.map +1 -0
- package/dist/src/ui/commands/model.d.ts +7 -0
- package/dist/src/ui/commands/model.d.ts.map +1 -0
- package/dist/src/ui/commands/model.js +16 -0
- package/dist/src/ui/commands/model.js.map +1 -0
- package/dist/src/ui/commands/registry.d.ts +30 -0
- package/dist/src/ui/commands/registry.d.ts.map +1 -0
- package/dist/src/ui/commands/registry.js +45 -0
- package/dist/src/ui/commands/registry.js.map +1 -0
- package/dist/src/ui/commands/sessions.d.ts +7 -0
- package/dist/src/ui/commands/sessions.d.ts.map +1 -0
- package/dist/src/ui/commands/sessions.js +13 -0
- package/dist/src/ui/commands/sessions.js.map +1 -0
- package/dist/src/ui/commands/stats.d.ts +7 -0
- package/dist/src/ui/commands/stats.d.ts.map +1 -0
- package/dist/src/ui/commands/stats.js +33 -0
- package/dist/src/ui/commands/stats.js.map +1 -0
- package/dist/src/ui/commands/theme.d.ts +7 -0
- package/dist/src/ui/commands/theme.d.ts.map +1 -0
- package/dist/src/ui/commands/theme.js +35 -0
- package/dist/src/ui/commands/theme.js.map +1 -0
- package/dist/src/ui/markdown/CodeBlock.d.ts +14 -0
- package/dist/src/ui/markdown/CodeBlock.d.ts.map +1 -0
- package/dist/src/ui/markdown/CodeBlock.js +55 -0
- package/dist/src/ui/markdown/CodeBlock.js.map +1 -0
- package/dist/src/ui/markdown/InlineRenderer.d.ts +12 -0
- package/dist/src/ui/markdown/InlineRenderer.d.ts.map +1 -0
- package/dist/src/ui/markdown/InlineRenderer.js +70 -0
- package/dist/src/ui/markdown/InlineRenderer.js.map +1 -0
- package/dist/src/ui/markdown/MarkdownDisplay.d.ts +17 -0
- package/dist/src/ui/markdown/MarkdownDisplay.d.ts.map +1 -0
- package/dist/src/ui/markdown/MarkdownDisplay.js +142 -0
- package/dist/src/ui/markdown/MarkdownDisplay.js.map +1 -0
- package/dist/src/ui/markdown/Table.d.ts +14 -0
- package/dist/src/ui/markdown/Table.d.ts.map +1 -0
- package/dist/src/ui/markdown/Table.js +31 -0
- package/dist/src/ui/markdown/Table.js.map +1 -0
- package/dist/src/ui/theme.d.ts +39 -0
- package/dist/src/ui/theme.d.ts.map +1 -0
- package/dist/src/ui/theme.js +39 -0
- package/dist/src/ui/theme.js.map +1 -0
- package/dist/src/ui/themes/index.d.ts +45 -0
- package/dist/src/ui/themes/index.d.ts.map +1 -0
- package/dist/src/ui/themes/index.js +73 -0
- package/dist/src/ui/themes/index.js.map +1 -0
- package/dist/src/ui/themes/light.d.ts +8 -0
- package/dist/src/ui/themes/light.d.ts.map +1 -0
- package/dist/src/ui/themes/light.js +37 -0
- package/dist/src/ui/themes/light.js.map +1 -0
- package/dist/src/ui/themes/monochrome.d.ts +8 -0
- package/dist/src/ui/themes/monochrome.d.ts.map +1 -0
- package/dist/src/ui/themes/monochrome.js +37 -0
- package/dist/src/ui/themes/monochrome.js.map +1 -0
- package/dist/src/ui/types.d.ts +191 -0
- package/dist/src/ui/types.d.ts.map +1 -0
- package/dist/src/ui/types.js +7 -0
- package/dist/src/ui/types.js.map +1 -0
- package/dist/src/ui/useAlternateBuffer.d.ts +11 -0
- package/dist/src/ui/useAlternateBuffer.d.ts.map +1 -0
- package/dist/src/ui/useAlternateBuffer.js +25 -0
- package/dist/src/ui/useAlternateBuffer.js.map +1 -0
- package/dist/src/ui/useChat.d.ts +18 -0
- package/dist/src/ui/useChat.d.ts.map +1 -0
- package/dist/src/ui/useChat.js +599 -0
- package/dist/src/ui/useChat.js.map +1 -0
- package/dist/src/ui/useElapsedTime.d.ts +11 -0
- package/dist/src/ui/useElapsedTime.d.ts.map +1 -0
- package/dist/src/ui/useElapsedTime.js +39 -0
- package/dist/src/ui/useElapsedTime.js.map +1 -0
- package/dist/src/ui/useResponsiveLayout.d.ts +16 -0
- package/dist/src/ui/useResponsiveLayout.d.ts.map +1 -0
- package/dist/src/ui/useResponsiveLayout.js +24 -0
- package/dist/src/ui/useResponsiveLayout.js.map +1 -0
- package/dist/src/ui/useScroll.d.ts +20 -0
- package/dist/src/ui/useScroll.d.ts.map +1 -0
- package/dist/src/ui/useScroll.js +64 -0
- package/dist/src/ui/useScroll.js.map +1 -0
- package/dist/src/ui/useSessionResume.d.ts +20 -0
- package/dist/src/ui/useSessionResume.d.ts.map +1 -0
- package/dist/src/ui/useSessionResume.js +77 -0
- package/dist/src/ui/useSessionResume.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +60 -0
- package/src/auth/index.ts +13 -0
- package/src/auth/oauth2.test.ts +305 -0
- package/src/auth/oauth2.ts +269 -0
- package/src/auth/prompt.test.ts +205 -0
- package/src/auth/prompt.ts +111 -0
- package/src/auth/test-connection.test.ts +224 -0
- package/src/auth/test-connection.ts +196 -0
- package/src/auth/types.ts +34 -0
- package/src/commands/audit.test.ts +92 -0
- package/src/commands/audit.ts +113 -0
- package/src/commands/automations.test.ts +85 -0
- package/src/commands/automations.ts +205 -0
- package/src/commands/build-manifest-types.ts +35 -0
- package/src/commands/build-tools.ts +281 -0
- package/src/commands/build.test.ts +63 -0
- package/src/commands/build.ts +135 -0
- package/src/commands/chat.ts +147 -0
- package/src/commands/command-exports.test.ts +88 -0
- package/src/commands/connect.test.ts +343 -0
- package/src/commands/connect.ts +237 -0
- package/src/commands/deploy.test.ts +124 -0
- package/src/commands/deploy.ts +153 -0
- package/src/commands/deployments.ts +90 -0
- package/src/commands/dev.test.ts +63 -0
- package/src/commands/dev.ts +124 -0
- package/src/commands/diff.test.ts +183 -0
- package/src/commands/diff.ts +143 -0
- package/src/commands/docker.ts +232 -0
- package/src/commands/eval.test.ts +88 -0
- package/src/commands/eval.ts +268 -0
- package/src/commands/experiment.test.ts +125 -0
- package/src/commands/experiment.ts +153 -0
- package/src/commands/index.ts +76 -0
- package/src/commands/init.test.ts +109 -0
- package/src/commands/init.ts +98 -0
- package/src/commands/inspect.test.ts +234 -0
- package/src/commands/inspect.ts +157 -0
- package/src/commands/install-pkg.test.ts +265 -0
- package/src/commands/install-pkg.ts +234 -0
- package/src/commands/link.ts +270 -0
- package/src/commands/list.test.ts +152 -0
- package/src/commands/list.ts +95 -0
- package/src/commands/login.test.ts +195 -0
- package/src/commands/login.ts +258 -0
- package/src/commands/promote.ts +64 -0
- package/src/commands/publish.test.ts +203 -0
- package/src/commands/publish.ts +142 -0
- package/src/commands/rollback.ts +72 -0
- package/src/commands/search.test.ts +174 -0
- package/src/commands/search.ts +154 -0
- package/src/commands/secrets.test.ts +168 -0
- package/src/commands/secrets.ts +163 -0
- package/src/commands/serve.ts +166 -0
- package/src/commands/status.ts +94 -0
- package/src/commands/sync.test.ts +130 -0
- package/src/commands/sync.ts +119 -0
- package/src/commands/test-query.test.ts +42 -0
- package/src/commands/test-query.ts +129 -0
- package/src/commands/uninstall.test.ts +162 -0
- package/src/commands/uninstall.ts +107 -0
- package/src/commands/update.test.ts +281 -0
- package/src/commands/update.ts +180 -0
- package/src/commands/validate.test.ts +260 -0
- package/src/commands/validate.ts +139 -0
- package/src/e2e-automations.test.ts +305 -0
- package/src/e2e-commands.test.ts +587 -0
- package/src/e2e-incident-response.test.ts +345 -0
- package/src/e2e-plugin-connections.test.ts +415 -0
- package/src/e2e-plugins.test.ts +492 -0
- package/src/e2e.test.ts +602 -0
- package/src/fixtures/incident-response.ts +232 -0
- package/src/main.ts +35 -0
- package/src/shared/platform-client.test.ts +106 -0
- package/src/shared/platform-client.ts +193 -0
- package/src/shared/repo-discovery.test.ts +56 -0
- package/src/shared/repo-discovery.ts +40 -0
- package/src/templates/compose-template.ts +30 -0
- package/src/templates/config-template.ts +44 -0
- package/src/templates/deployment-templates.test.ts +99 -0
- package/src/templates/dockerfile-template.ts +30 -0
- package/src/templates/env-template.ts +27 -0
- package/src/templates/knowledge-template.ts +24 -0
- package/src/templates/skill-template.ts +27 -0
- package/src/ui/AskUserPrompt.tsx +58 -0
- package/src/ui/AssistantMessage.tsx +51 -0
- package/src/ui/ChatApp.tsx +283 -0
- package/src/ui/ConfirmationPrompt.tsx +75 -0
- package/src/ui/DiffRenderer.test.ts +104 -0
- package/src/ui/DiffRenderer.tsx +188 -0
- package/src/ui/ExpandableContent.tsx +68 -0
- package/src/ui/ExploreIndicator.tsx +44 -0
- package/src/ui/Footer.tsx +87 -0
- package/src/ui/FullScreenLayout.tsx +45 -0
- package/src/ui/Header.tsx +50 -0
- package/src/ui/InputBar.tsx +105 -0
- package/src/ui/MessageList.tsx +31 -0
- package/src/ui/NotificationBar.tsx +64 -0
- package/src/ui/ScrollableMessageList.tsx +82 -0
- package/src/ui/SessionBrowser.test.ts +49 -0
- package/src/ui/SessionBrowser.tsx +179 -0
- package/src/ui/StatusMessage.tsx +35 -0
- package/src/ui/StreamingView.tsx +87 -0
- package/src/ui/SubagentDisplay.tsx +57 -0
- package/src/ui/ThinkingDisplay.tsx +45 -0
- package/src/ui/ToolCallDisplay.tsx +268 -0
- package/src/ui/UserMessage.tsx +22 -0
- package/src/ui/chat-e2e.test.ts +581 -0
- package/src/ui/commands/clear.ts +15 -0
- package/src/ui/commands/help.ts +31 -0
- package/src/ui/commands/index.ts +22 -0
- package/src/ui/commands/model.ts +19 -0
- package/src/ui/commands/registry.test.ts +76 -0
- package/src/ui/commands/registry.ts +66 -0
- package/src/ui/commands/sessions.ts +16 -0
- package/src/ui/commands/stats.ts +35 -0
- package/src/ui/commands/theme.ts +41 -0
- package/src/ui/markdown/CodeBlock.tsx +118 -0
- package/src/ui/markdown/InlineRenderer.tsx +115 -0
- package/src/ui/markdown/MarkdownDisplay.tsx +223 -0
- package/src/ui/markdown/Table.tsx +75 -0
- package/src/ui/theme.ts +39 -0
- package/src/ui/themes/index.ts +113 -0
- package/src/ui/themes/light.ts +39 -0
- package/src/ui/themes/monochrome.ts +39 -0
- package/src/ui/types.ts +157 -0
- package/src/ui/useAlternateBuffer.ts +27 -0
- package/src/ui/useChat.test.ts +492 -0
- package/src/ui/useChat.ts +693 -0
- package/src/ui/useElapsedTime.test.ts +33 -0
- package/src/ui/useElapsedTime.ts +43 -0
- package/src/ui/useResponsiveLayout.test.ts +54 -0
- package/src/ui/useResponsiveLayout.ts +32 -0
- package/src/ui/useScroll.test.ts +99 -0
- package/src/ui/useScroll.ts +97 -0
- package/src/ui/useSessionResume.test.ts +80 -0
- package/src/ui/useSessionResume.ts +102 -0
- package/tsconfig.json +17 -0
- package/vitest.config.ts +20 -0
|
@@ -0,0 +1,260 @@
|
|
|
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
|
+
|
|
9
|
+
const mockFindRepoRoot = vi.fn(() => '/test/repo');
|
|
10
|
+
const mockLoadRepo = vi.fn();
|
|
11
|
+
const mockReadLockFile = vi.fn();
|
|
12
|
+
const mockResolveAllPackages = vi.fn();
|
|
13
|
+
|
|
14
|
+
vi.mock('../shared/repo-discovery.js', () => ({
|
|
15
|
+
findRepoRoot: mockFindRepoRoot,
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
vi.mock('@amodalai/core', () => ({
|
|
19
|
+
loadRepo: mockLoadRepo,
|
|
20
|
+
readLockFile: mockReadLockFile,
|
|
21
|
+
resolveAllPackages: mockResolveAllPackages,
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
describe('runValidate', () => {
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
vi.clearAllMocks();
|
|
27
|
+
mockFindRepoRoot.mockReturnValue('/test/repo');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should return 0 when repo is valid', async () => {
|
|
31
|
+
mockLoadRepo.mockResolvedValue({
|
|
32
|
+
connections: new Map([['api', {
|
|
33
|
+
surface: [{method: 'GET', path: '/test'}],
|
|
34
|
+
access: {},
|
|
35
|
+
}]]),
|
|
36
|
+
skills: [{name: 'test', body: 'content'}],
|
|
37
|
+
automations: [{name: 'daily', schedule: '0 8 * * *'}],
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const {runValidate} = await import('./validate.js');
|
|
41
|
+
const result = await runValidate();
|
|
42
|
+
expect(result).toBe(0);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should warn when no connections exist', async () => {
|
|
46
|
+
mockLoadRepo.mockResolvedValue({
|
|
47
|
+
connections: new Map(),
|
|
48
|
+
skills: [],
|
|
49
|
+
automations: [],
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const {runValidate} = await import('./validate.js');
|
|
53
|
+
const result = await runValidate();
|
|
54
|
+
expect(result).toBe(0); // warnings don't cause failure
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should warn when connection has no surface endpoints', async () => {
|
|
58
|
+
mockLoadRepo.mockResolvedValue({
|
|
59
|
+
connections: new Map([['api', {surface: [], access: {}}]]),
|
|
60
|
+
skills: [],
|
|
61
|
+
automations: [],
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const {runValidate} = await import('./validate.js');
|
|
65
|
+
const result = await runValidate();
|
|
66
|
+
expect(result).toBe(0);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should error when skill has empty body', async () => {
|
|
70
|
+
mockLoadRepo.mockResolvedValue({
|
|
71
|
+
connections: new Map(),
|
|
72
|
+
skills: [{name: 'empty-skill', body: ''}],
|
|
73
|
+
automations: [],
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const {runValidate} = await import('./validate.js');
|
|
77
|
+
const result = await runValidate();
|
|
78
|
+
expect(result).toBe(1);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should warn when automation has no schedule', async () => {
|
|
82
|
+
mockLoadRepo.mockResolvedValue({
|
|
83
|
+
connections: new Map(),
|
|
84
|
+
skills: [],
|
|
85
|
+
automations: [{name: 'webhook-only'}],
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const {runValidate} = await import('./validate.js');
|
|
89
|
+
const result = await runValidate();
|
|
90
|
+
expect(result).toBe(0);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should return 1 when repo load fails', async () => {
|
|
94
|
+
mockLoadRepo.mockRejectedValue(new Error('Config parse failed'));
|
|
95
|
+
|
|
96
|
+
const {runValidate} = await import('./validate.js');
|
|
97
|
+
const result = await runValidate();
|
|
98
|
+
expect(result).toBe(1);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should return 1 when repo root not found', async () => {
|
|
102
|
+
mockFindRepoRoot.mockImplementation(() => {
|
|
103
|
+
throw new Error('Not found');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const {runValidate} = await import('./validate.js');
|
|
107
|
+
const result = await runValidate();
|
|
108
|
+
expect(result).toBe(1);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should handle multiple skill errors', async () => {
|
|
112
|
+
mockLoadRepo.mockResolvedValue({
|
|
113
|
+
connections: new Map(),
|
|
114
|
+
skills: [
|
|
115
|
+
{name: 'skill-1', body: ''},
|
|
116
|
+
{name: 'skill-2', body: ''},
|
|
117
|
+
],
|
|
118
|
+
automations: [],
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const {runValidate} = await import('./validate.js');
|
|
122
|
+
const result = await runValidate();
|
|
123
|
+
expect(result).toBe(2);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('should report both errors and warnings', async () => {
|
|
127
|
+
mockLoadRepo.mockResolvedValue({
|
|
128
|
+
connections: new Map(),
|
|
129
|
+
skills: [{name: 'bad', body: ''}],
|
|
130
|
+
automations: [{name: 'no-schedule'}],
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const {runValidate} = await import('./validate.js');
|
|
134
|
+
const result = await runValidate();
|
|
135
|
+
expect(result).toBe(1); // 1 error
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Package-aware validation tests
|
|
139
|
+
it('should run package validation when packages flag set', async () => {
|
|
140
|
+
mockLoadRepo.mockResolvedValue({
|
|
141
|
+
connections: new Map([['api', {surface: [{method: 'GET', path: '/test'}], access: {}}]]),
|
|
142
|
+
skills: [{name: 'test', body: 'content'}],
|
|
143
|
+
automations: [],
|
|
144
|
+
});
|
|
145
|
+
mockReadLockFile.mockResolvedValue({lockVersion: 1, packages: {}});
|
|
146
|
+
mockResolveAllPackages.mockResolvedValue({
|
|
147
|
+
connections: new Map(),
|
|
148
|
+
skills: [],
|
|
149
|
+
automations: [],
|
|
150
|
+
knowledge: [],
|
|
151
|
+
warnings: [],
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
const {runValidate} = await import('./validate.js');
|
|
155
|
+
const result = await runValidate({packages: true});
|
|
156
|
+
expect(result).toBe(0);
|
|
157
|
+
expect(mockResolveAllPackages).toHaveBeenCalled();
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('should report resolution warnings as validation warnings', async () => {
|
|
161
|
+
mockLoadRepo.mockResolvedValue({
|
|
162
|
+
connections: new Map(),
|
|
163
|
+
skills: [],
|
|
164
|
+
automations: [],
|
|
165
|
+
});
|
|
166
|
+
mockReadLockFile.mockResolvedValue({lockVersion: 1, packages: {'connection/salesforce': {version: '1.0.0', npm: '@amodalai/connection-salesforce', integrity: 'sha512-x'}}});
|
|
167
|
+
mockResolveAllPackages.mockResolvedValue({
|
|
168
|
+
connections: new Map(),
|
|
169
|
+
skills: [],
|
|
170
|
+
automations: [],
|
|
171
|
+
knowledge: [],
|
|
172
|
+
warnings: ['Package connection/salesforce is in lock file but not installed (broken symlink?)'],
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const {runValidate} = await import('./validate.js');
|
|
176
|
+
const result = await runValidate({packages: true});
|
|
177
|
+
expect(result).toBe(0); // warnings only
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should error on empty resolved skill', async () => {
|
|
181
|
+
mockLoadRepo.mockResolvedValue({
|
|
182
|
+
connections: new Map(),
|
|
183
|
+
skills: [],
|
|
184
|
+
automations: [],
|
|
185
|
+
});
|
|
186
|
+
mockReadLockFile.mockResolvedValue({lockVersion: 1, packages: {}});
|
|
187
|
+
mockResolveAllPackages.mockResolvedValue({
|
|
188
|
+
connections: new Map(),
|
|
189
|
+
skills: [{name: 'bad-skill', body: ' '}],
|
|
190
|
+
automations: [],
|
|
191
|
+
knowledge: [],
|
|
192
|
+
warnings: [],
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
const {runValidate} = await import('./validate.js');
|
|
196
|
+
const result = await runValidate({packages: true});
|
|
197
|
+
expect(result).toBe(1);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('should skip package validation when no lock file', async () => {
|
|
201
|
+
mockLoadRepo.mockResolvedValue({
|
|
202
|
+
connections: new Map([['api', {surface: [{method: 'GET', path: '/test'}], access: {}}]]),
|
|
203
|
+
skills: [],
|
|
204
|
+
automations: [],
|
|
205
|
+
});
|
|
206
|
+
mockReadLockFile.mockResolvedValue(null);
|
|
207
|
+
|
|
208
|
+
const {runValidate} = await import('./validate.js');
|
|
209
|
+
const result = await runValidate({packages: true});
|
|
210
|
+
expect(result).toBe(0);
|
|
211
|
+
expect(mockResolveAllPackages).not.toHaveBeenCalled();
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('should not run package checks without packages flag', async () => {
|
|
215
|
+
mockLoadRepo.mockResolvedValue({
|
|
216
|
+
connections: new Map([['api', {surface: [{method: 'GET', path: '/test'}], access: {}}]]),
|
|
217
|
+
skills: [],
|
|
218
|
+
automations: [],
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
const {runValidate} = await import('./validate.js');
|
|
222
|
+
const result = await runValidate();
|
|
223
|
+
expect(result).toBe(0);
|
|
224
|
+
expect(mockReadLockFile).not.toHaveBeenCalled();
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it('should handle package resolution failure', async () => {
|
|
228
|
+
mockLoadRepo.mockResolvedValue({
|
|
229
|
+
connections: new Map(),
|
|
230
|
+
skills: [],
|
|
231
|
+
automations: [],
|
|
232
|
+
});
|
|
233
|
+
mockReadLockFile.mockResolvedValue({lockVersion: 1, packages: {}});
|
|
234
|
+
mockResolveAllPackages.mockRejectedValue(new Error('Disk error'));
|
|
235
|
+
|
|
236
|
+
const {runValidate} = await import('./validate.js');
|
|
237
|
+
const result = await runValidate({packages: true});
|
|
238
|
+
expect(result).toBe(1);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('should warn on resolved connection with no endpoints', async () => {
|
|
242
|
+
mockLoadRepo.mockResolvedValue({
|
|
243
|
+
connections: new Map(),
|
|
244
|
+
skills: [],
|
|
245
|
+
automations: [],
|
|
246
|
+
});
|
|
247
|
+
mockReadLockFile.mockResolvedValue({lockVersion: 1, packages: {}});
|
|
248
|
+
mockResolveAllPackages.mockResolvedValue({
|
|
249
|
+
connections: new Map([['empty-conn', {surface: [], spec: {auth: null}}]]),
|
|
250
|
+
skills: [],
|
|
251
|
+
automations: [],
|
|
252
|
+
knowledge: [],
|
|
253
|
+
warnings: [],
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const {runValidate} = await import('./validate.js');
|
|
257
|
+
const result = await runValidate({packages: true});
|
|
258
|
+
expect(result).toBe(0); // warning only
|
|
259
|
+
});
|
|
260
|
+
});
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type {CommandModule} from 'yargs';
|
|
8
|
+
import {loadRepo, readLockFile, resolveAllPackages} from '@amodalai/core';
|
|
9
|
+
import {findRepoRoot} from '../shared/repo-discovery.js';
|
|
10
|
+
|
|
11
|
+
export interface ValidateOptions {
|
|
12
|
+
cwd?: string;
|
|
13
|
+
packages?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface ValidationIssue {
|
|
17
|
+
level: 'error' | 'warning';
|
|
18
|
+
message: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Validates the amodal project configuration by loading the full repo
|
|
23
|
+
* and running cross-reference checks.
|
|
24
|
+
*
|
|
25
|
+
* Returns the number of errors found (0 = valid).
|
|
26
|
+
*/
|
|
27
|
+
export async function runValidate(options: ValidateOptions = {}): Promise<number> {
|
|
28
|
+
const issues: ValidationIssue[] = [];
|
|
29
|
+
|
|
30
|
+
let repoPath: string;
|
|
31
|
+
try {
|
|
32
|
+
repoPath = findRepoRoot(options.cwd);
|
|
33
|
+
} catch (err) {
|
|
34
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
35
|
+
process.stderr.write(`[validate] ${msg}\n`);
|
|
36
|
+
return 1;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
process.stderr.write(`[validate] Loading repo from ${repoPath}\n`);
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const repo = await loadRepo({localPath: repoPath});
|
|
43
|
+
|
|
44
|
+
// Check: at least one connection
|
|
45
|
+
if (repo.connections.size === 0) {
|
|
46
|
+
issues.push({level: 'warning', message: 'No connections defined. The agent cannot access external systems.'});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Check: surface endpoints reference valid access config
|
|
50
|
+
for (const [name, conn] of repo.connections) {
|
|
51
|
+
if (conn.surface.length === 0) {
|
|
52
|
+
issues.push({level: 'warning', message: `Connection "${name}" has no surface endpoints.`});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Check: skills have non-empty bodies
|
|
57
|
+
for (const skill of repo.skills) {
|
|
58
|
+
if (!skill.body.trim()) {
|
|
59
|
+
issues.push({level: 'error', message: `Skill "${skill.name}" has an empty body.`});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Check: automations have schedules
|
|
64
|
+
for (const auto of repo.automations) {
|
|
65
|
+
if (!auto.schedule) {
|
|
66
|
+
issues.push({level: 'warning', message: `Automation "${auto.name}" has no schedule. It will only run via webhook.`});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
} catch (err) {
|
|
71
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
72
|
+
issues.push({level: 'error', message: `Failed to load repo: ${msg}`});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Package-aware validation
|
|
76
|
+
if (options.packages) {
|
|
77
|
+
try {
|
|
78
|
+
const lockFile = await readLockFile(repoPath);
|
|
79
|
+
if (lockFile) {
|
|
80
|
+
const resolved = await resolveAllPackages({repoPath, lockFile});
|
|
81
|
+
|
|
82
|
+
// Report warnings from resolution (missing packages, broken symlinks)
|
|
83
|
+
for (const warning of resolved.warnings) {
|
|
84
|
+
issues.push({level: 'warning', message: warning});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Check for empty resolved connections
|
|
88
|
+
for (const [name, conn] of resolved.connections) {
|
|
89
|
+
if (conn.surface.length === 0) {
|
|
90
|
+
issues.push({level: 'warning', message: `Resolved connection "${name}" has no surface endpoints.`});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Check for empty resolved skills
|
|
95
|
+
for (const skill of resolved.skills) {
|
|
96
|
+
if (!skill.body.trim()) {
|
|
97
|
+
issues.push({level: 'error', message: `Resolved skill "${skill.name}" has an empty body.`});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
process.stderr.write('[validate] No lock file found, skipping package validation.\n');
|
|
102
|
+
}
|
|
103
|
+
} catch (err) {
|
|
104
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
105
|
+
issues.push({level: 'error', message: `Package resolution failed: ${msg}`});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Print results
|
|
110
|
+
const errors = issues.filter((i) => i.level === 'error');
|
|
111
|
+
const warnings = issues.filter((i) => i.level === 'warning');
|
|
112
|
+
|
|
113
|
+
for (const issue of errors) {
|
|
114
|
+
process.stderr.write(` ERROR: ${issue.message}\n`);
|
|
115
|
+
}
|
|
116
|
+
for (const issue of warnings) {
|
|
117
|
+
process.stderr.write(` WARN: ${issue.message}\n`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (errors.length === 0 && warnings.length === 0) {
|
|
121
|
+
process.stderr.write('[validate] All checks passed.\n');
|
|
122
|
+
} else {
|
|
123
|
+
process.stderr.write(`[validate] ${errors.length} error(s), ${warnings.length} warning(s)\n`);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return errors.length;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export const validateCommand: CommandModule = {
|
|
130
|
+
command: 'validate',
|
|
131
|
+
describe: 'Validate the project configuration',
|
|
132
|
+
builder: (yargs) =>
|
|
133
|
+
yargs.option('packages', {type: 'boolean', default: false, describe: 'Include package resolution validation'}),
|
|
134
|
+
handler: async (argv) => {
|
|
135
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
136
|
+
const code = await runValidate({packages: argv['packages'] as boolean});
|
|
137
|
+
process.exit(code);
|
|
138
|
+
},
|
|
139
|
+
};
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* End-to-end test: Automation lifecycle
|
|
9
|
+
*
|
|
10
|
+
* Tests the full automation control flow via the HTTP API:
|
|
11
|
+
* 1. Create repo with cron + webhook automations on disk
|
|
12
|
+
* 2. Boot `createLocalServer` (which integrates ProactiveRunner)
|
|
13
|
+
* 3. List automations — verify both appear, cron is stopped, webhook is running
|
|
14
|
+
* 4. Start a cron automation — verify it becomes running
|
|
15
|
+
* 5. Stop a cron automation — verify it becomes stopped
|
|
16
|
+
* 6. Reject starting a webhook automation (always active)
|
|
17
|
+
* 7. Manually trigger an automation (run)
|
|
18
|
+
* 8. Webhook endpoint accepts events
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import {describe, it, expect, beforeAll, afterAll} from 'vitest';
|
|
22
|
+
import {mkdtempSync, mkdirSync, writeFileSync, rmSync} from 'node:fs';
|
|
23
|
+
import {join} from 'node:path';
|
|
24
|
+
import {tmpdir} from 'node:os';
|
|
25
|
+
import type {AddressInfo} from 'node:net';
|
|
26
|
+
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Fixture data
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
const CONFIG = {
|
|
32
|
+
name: 'automation-test-agent',
|
|
33
|
+
version: '1.0.0',
|
|
34
|
+
description: 'Agent with automations for e2e testing',
|
|
35
|
+
models: {
|
|
36
|
+
main: {provider: 'anthropic', model: 'claude-sonnet-4-20250514'},
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const CRON_AUTOMATION = `# Automation: Daily Scan
|
|
41
|
+
|
|
42
|
+
Schedule: */5 * * * *
|
|
43
|
+
|
|
44
|
+
## Check
|
|
45
|
+
Scan all zones for anomalies and report findings.
|
|
46
|
+
|
|
47
|
+
## Output
|
|
48
|
+
Summary of anomalies found.
|
|
49
|
+
|
|
50
|
+
## Delivery
|
|
51
|
+
stdout
|
|
52
|
+
`;
|
|
53
|
+
|
|
54
|
+
const WEBHOOK_AUTOMATION = `# Automation: Alert Handler
|
|
55
|
+
|
|
56
|
+
## Check
|
|
57
|
+
Run on webhook when an alert fires. Triage the alert and determine severity.
|
|
58
|
+
|
|
59
|
+
## Output
|
|
60
|
+
Triage assessment with severity level.
|
|
61
|
+
|
|
62
|
+
## Delivery
|
|
63
|
+
stdout
|
|
64
|
+
`;
|
|
65
|
+
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// Test suite
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
|
|
70
|
+
describe('E2E: Automation Lifecycle', () => {
|
|
71
|
+
let repoDir: string;
|
|
72
|
+
let server: {app: unknown; start: () => Promise<unknown>; stop: () => Promise<void>} | null = null;
|
|
73
|
+
let baseUrl: string;
|
|
74
|
+
|
|
75
|
+
beforeAll(async () => {
|
|
76
|
+
// 1. Create repo directory with automations
|
|
77
|
+
repoDir = mkdtempSync(join(tmpdir(), 'amodal-e2e-automations-'));
|
|
78
|
+
|
|
79
|
+
// Config
|
|
80
|
+
writeFileSync(join(repoDir, 'amodal.json'), JSON.stringify(CONFIG, null, 2));
|
|
81
|
+
|
|
82
|
+
// Automations
|
|
83
|
+
const autoDir = join(repoDir, 'automations');
|
|
84
|
+
mkdirSync(autoDir, {recursive: true});
|
|
85
|
+
writeFileSync(join(autoDir, 'daily-scan.md'), CRON_AUTOMATION);
|
|
86
|
+
writeFileSync(join(autoDir, 'alert-handler.md'), WEBHOOK_AUTOMATION);
|
|
87
|
+
|
|
88
|
+
// 2. Boot repo server
|
|
89
|
+
const {createLocalServer} = await import('@amodalai/runtime');
|
|
90
|
+
const srv = await createLocalServer({
|
|
91
|
+
repoPath: repoDir,
|
|
92
|
+
port: 0, // random port
|
|
93
|
+
host: '127.0.0.1',
|
|
94
|
+
hotReload: false,
|
|
95
|
+
corsOrigin: '*',
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const httpServer = await srv.start();
|
|
99
|
+
const addr = httpServer.address() as AddressInfo;
|
|
100
|
+
baseUrl = `http://127.0.0.1:${addr.port}`;
|
|
101
|
+
server = srv;
|
|
102
|
+
}, 30000);
|
|
103
|
+
|
|
104
|
+
afterAll(async () => {
|
|
105
|
+
if (server) {
|
|
106
|
+
await server.stop();
|
|
107
|
+
server = null;
|
|
108
|
+
}
|
|
109
|
+
rmSync(repoDir, {recursive: true, force: true});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// =========================================================================
|
|
113
|
+
// Health check — server is up
|
|
114
|
+
// =========================================================================
|
|
115
|
+
|
|
116
|
+
it('should respond to health check', async () => {
|
|
117
|
+
const resp = await fetch(`${baseUrl}/health`);
|
|
118
|
+
expect(resp.status).toBe(200);
|
|
119
|
+
const data = (await resp.json()) as Record<string, unknown>;
|
|
120
|
+
expect(data['status']).toBe('ok');
|
|
121
|
+
expect(data['mode']).toBe('repo');
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// =========================================================================
|
|
125
|
+
// List — both automations appear with correct initial state
|
|
126
|
+
// =========================================================================
|
|
127
|
+
|
|
128
|
+
it('should list automations with correct types and initial state', async () => {
|
|
129
|
+
const resp = await fetch(`${baseUrl}/automations`);
|
|
130
|
+
expect(resp.status).toBe(200);
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
const data = (await resp.json()) as {
|
|
134
|
+
automations: Array<{
|
|
135
|
+
name: string;
|
|
136
|
+
title: string;
|
|
137
|
+
schedule?: string;
|
|
138
|
+
webhookTriggered: boolean;
|
|
139
|
+
running: boolean;
|
|
140
|
+
}>;
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
expect(data.automations).toHaveLength(2);
|
|
144
|
+
|
|
145
|
+
const cronAuto = data.automations.find((a) => a.name === 'daily-scan');
|
|
146
|
+
expect(cronAuto).toBeDefined();
|
|
147
|
+
expect(cronAuto?.title).toBe('Daily Scan');
|
|
148
|
+
expect(cronAuto?.schedule).toBe('*/5 * * * *');
|
|
149
|
+
expect(cronAuto?.webhookTriggered).toBe(false);
|
|
150
|
+
expect(cronAuto?.running).toBe(false); // not started yet
|
|
151
|
+
|
|
152
|
+
const webhookAuto = data.automations.find((a) => a.name === 'alert-handler');
|
|
153
|
+
expect(webhookAuto).toBeDefined();
|
|
154
|
+
expect(webhookAuto?.title).toBe('Alert Handler');
|
|
155
|
+
expect(webhookAuto?.webhookTriggered).toBe(true);
|
|
156
|
+
expect(webhookAuto?.running).toBe(true); // webhooks always active
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// =========================================================================
|
|
160
|
+
// Start — cron automation becomes running
|
|
161
|
+
// =========================================================================
|
|
162
|
+
|
|
163
|
+
it('should start a cron automation', async () => {
|
|
164
|
+
const resp = await fetch(`${baseUrl}/automations/daily-scan/start`, {method: 'POST'});
|
|
165
|
+
expect(resp.status).toBe(200);
|
|
166
|
+
const data = (await resp.json()) as Record<string, unknown>;
|
|
167
|
+
expect(data['status']).toBe('started');
|
|
168
|
+
|
|
169
|
+
// Verify it's now running
|
|
170
|
+
const listResp = await fetch(`${baseUrl}/automations`);
|
|
171
|
+
|
|
172
|
+
const listData = (await listResp.json()) as {
|
|
173
|
+
automations: Array<{name: string; running: boolean}>;
|
|
174
|
+
};
|
|
175
|
+
const cronAuto = listData.automations.find((a) => a.name === 'daily-scan');
|
|
176
|
+
expect(cronAuto?.running).toBe(true);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// =========================================================================
|
|
180
|
+
// Start again — should fail (already running)
|
|
181
|
+
// =========================================================================
|
|
182
|
+
|
|
183
|
+
it('should reject starting an already running automation', async () => {
|
|
184
|
+
const resp = await fetch(`${baseUrl}/automations/daily-scan/start`, {method: 'POST'});
|
|
185
|
+
expect(resp.status).toBe(400);
|
|
186
|
+
const data = (await resp.json()) as Record<string, unknown>;
|
|
187
|
+
expect(data['error']).toContain('already running');
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// =========================================================================
|
|
191
|
+
// Stop — cron automation becomes stopped
|
|
192
|
+
// =========================================================================
|
|
193
|
+
|
|
194
|
+
it('should stop a running cron automation', async () => {
|
|
195
|
+
const resp = await fetch(`${baseUrl}/automations/daily-scan/stop`, {method: 'POST'});
|
|
196
|
+
expect(resp.status).toBe(200);
|
|
197
|
+
const data = (await resp.json()) as Record<string, unknown>;
|
|
198
|
+
expect(data['status']).toBe('stopped');
|
|
199
|
+
|
|
200
|
+
// Verify it's now stopped
|
|
201
|
+
const listResp = await fetch(`${baseUrl}/automations`);
|
|
202
|
+
|
|
203
|
+
const listData = (await listResp.json()) as {
|
|
204
|
+
automations: Array<{name: string; running: boolean}>;
|
|
205
|
+
};
|
|
206
|
+
const cronAuto = listData.automations.find((a) => a.name === 'daily-scan');
|
|
207
|
+
expect(cronAuto?.running).toBe(false);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// =========================================================================
|
|
211
|
+
// Stop again — should fail (not running)
|
|
212
|
+
// =========================================================================
|
|
213
|
+
|
|
214
|
+
it('should reject stopping a non-running automation', async () => {
|
|
215
|
+
const resp = await fetch(`${baseUrl}/automations/daily-scan/stop`, {method: 'POST'});
|
|
216
|
+
expect(resp.status).toBe(400);
|
|
217
|
+
const data = (await resp.json()) as Record<string, unknown>;
|
|
218
|
+
expect(data['error']).toContain('not running');
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// =========================================================================
|
|
222
|
+
// Start webhook automation — should fail (always active)
|
|
223
|
+
// =========================================================================
|
|
224
|
+
|
|
225
|
+
it('should reject starting a webhook-triggered automation', async () => {
|
|
226
|
+
const resp = await fetch(`${baseUrl}/automations/alert-handler/start`, {method: 'POST'});
|
|
227
|
+
expect(resp.status).toBe(400);
|
|
228
|
+
const data = (await resp.json()) as Record<string, unknown>;
|
|
229
|
+
expect(data['error']).toContain('webhook-triggered');
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// =========================================================================
|
|
233
|
+
// Start unknown — should fail
|
|
234
|
+
// =========================================================================
|
|
235
|
+
|
|
236
|
+
it('should reject starting unknown automation', async () => {
|
|
237
|
+
const resp = await fetch(`${baseUrl}/automations/nonexistent/start`, {method: 'POST'});
|
|
238
|
+
expect(resp.status).toBe(400);
|
|
239
|
+
const data = (await resp.json()) as Record<string, unknown>;
|
|
240
|
+
expect(data['error']).toContain('not found');
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// =========================================================================
|
|
244
|
+
// Run — manually trigger an automation (fire and forget)
|
|
245
|
+
// =========================================================================
|
|
246
|
+
|
|
247
|
+
it('should reject triggering unknown automation', async () => {
|
|
248
|
+
const resp = await fetch(`${baseUrl}/automations/nonexistent/run`, {
|
|
249
|
+
method: 'POST',
|
|
250
|
+
headers: {'Content-Type': 'application/json'},
|
|
251
|
+
body: JSON.stringify({}),
|
|
252
|
+
});
|
|
253
|
+
expect(resp.status).toBe(404);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
// =========================================================================
|
|
257
|
+
// Webhook endpoint — accepts events
|
|
258
|
+
// =========================================================================
|
|
259
|
+
|
|
260
|
+
it('should accept webhook events for webhook-triggered automations', async () => {
|
|
261
|
+
const resp = await fetch(`${baseUrl}/webhooks/alert-handler`, {
|
|
262
|
+
method: 'POST',
|
|
263
|
+
headers: {'Content-Type': 'application/json'},
|
|
264
|
+
body: JSON.stringify({alert: 'high-cpu', host: 'web-01'}),
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// May succeed or fail (depends on LLM availability), but route exists
|
|
268
|
+
expect([200, 500]).toContain(resp.status);
|
|
269
|
+
const data = (await resp.json()) as Record<string, unknown>;
|
|
270
|
+
// If 200, it matched and ran
|
|
271
|
+
if (resp.status === 200) {
|
|
272
|
+
expect(data['status']).toBe('accepted');
|
|
273
|
+
}
|
|
274
|
+
// If 500, it matched but execution failed (no LLM configured) — still validates routing
|
|
275
|
+
if (resp.status === 500) {
|
|
276
|
+
expect(data['matched']).toBe(true);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
// =========================================================================
|
|
281
|
+
// Webhook for non-webhook automation — should 404
|
|
282
|
+
// =========================================================================
|
|
283
|
+
|
|
284
|
+
it('should reject webhook for cron-only automation', async () => {
|
|
285
|
+
const resp = await fetch(`${baseUrl}/webhooks/daily-scan`, {
|
|
286
|
+
method: 'POST',
|
|
287
|
+
headers: {'Content-Type': 'application/json'},
|
|
288
|
+
body: JSON.stringify({}),
|
|
289
|
+
});
|
|
290
|
+
expect(resp.status).toBe(404);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
// =========================================================================
|
|
294
|
+
// Webhook for unknown automation — should 404
|
|
295
|
+
// =========================================================================
|
|
296
|
+
|
|
297
|
+
it('should reject webhook for unknown automation', async () => {
|
|
298
|
+
const resp = await fetch(`${baseUrl}/webhooks/nonexistent`, {
|
|
299
|
+
method: 'POST',
|
|
300
|
+
headers: {'Content-Type': 'application/json'},
|
|
301
|
+
body: JSON.stringify({}),
|
|
302
|
+
});
|
|
303
|
+
expect(resp.status).toBe(404);
|
|
304
|
+
});
|
|
305
|
+
});
|