alpic 0.0.0-staging.4e0b164 → 0.0.0-staging.4e1c632

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 (232) hide show
  1. package/README.md +50 -18
  2. package/dist/__tests__/alpic-command.test.d.ts +1 -0
  3. package/dist/__tests__/alpic-command.test.js +41 -0
  4. package/dist/__tests__/alpic-command.test.js.map +1 -0
  5. package/dist/__tests__/audit.e2e.test.js +235 -18
  6. package/dist/__tests__/audit.e2e.test.js.map +1 -1
  7. package/dist/__tests__/auth.e2e.test.js +10 -5
  8. package/dist/__tests__/auth.e2e.test.js.map +1 -1
  9. package/dist/__tests__/deploy-flags.e2e.test.js +45 -5
  10. package/dist/__tests__/deploy-flags.e2e.test.js.map +1 -1
  11. package/dist/__tests__/deploy.e2e.test.js +14 -10
  12. package/dist/__tests__/deploy.e2e.test.js.map +1 -1
  13. package/dist/__tests__/deployment-inspect.e2e.test.js +11 -6
  14. package/dist/__tests__/deployment-inspect.e2e.test.js.map +1 -1
  15. package/dist/__tests__/deployment-list.e2e.test.js +72 -7
  16. package/dist/__tests__/deployment-list.e2e.test.js.map +1 -1
  17. package/dist/__tests__/deployment-logs.e2e.test.js +35 -13
  18. package/dist/__tests__/deployment-logs.e2e.test.js.map +1 -1
  19. package/dist/__tests__/environment-inspect.e2e.test.d.ts +1 -0
  20. package/dist/__tests__/environment-inspect.e2e.test.js +110 -0
  21. package/dist/__tests__/environment-inspect.e2e.test.js.map +1 -0
  22. package/dist/__tests__/environment-list.e2e.test.d.ts +1 -0
  23. package/dist/__tests__/environment-list.e2e.test.js +89 -0
  24. package/dist/__tests__/environment-list.e2e.test.js.map +1 -0
  25. package/dist/__tests__/environment-variable/environment-variable-add.e2e.test.js +120 -11
  26. package/dist/__tests__/environment-variable/environment-variable-add.e2e.test.js.map +1 -1
  27. package/dist/__tests__/environment-variable/environment-variable-list.e2e.test.js +98 -13
  28. package/dist/__tests__/environment-variable/environment-variable-list.e2e.test.js.map +1 -1
  29. package/dist/__tests__/environment-variable/environment-variable-remove.e2e.test.js +17 -19
  30. package/dist/__tests__/environment-variable/environment-variable-remove.e2e.test.js.map +1 -1
  31. package/dist/__tests__/environment-variable/environment-variable-update.e2e.test.js +25 -30
  32. package/dist/__tests__/environment-variable/environment-variable-update.e2e.test.js.map +1 -1
  33. package/dist/__tests__/git-flags.e2e.test.js +15 -6
  34. package/dist/__tests__/git-flags.e2e.test.js.map +1 -1
  35. package/dist/__tests__/git.e2e.test.js +20 -10
  36. package/dist/__tests__/git.e2e.test.js.map +1 -1
  37. package/dist/__tests__/link.e2e.test.js +211 -17
  38. package/dist/__tests__/link.e2e.test.js.map +1 -1
  39. package/dist/__tests__/logs.e2e.test.js +119 -15
  40. package/dist/__tests__/logs.e2e.test.js.map +1 -1
  41. package/dist/__tests__/{mock-server.d.ts → mock-api.d.ts} +3 -0
  42. package/dist/__tests__/{mock-server.js → mock-api.js} +142 -30
  43. package/dist/__tests__/mock-api.js.map +1 -0
  44. package/dist/__tests__/playground/playground-configure.e2e.test.d.ts +1 -0
  45. package/dist/__tests__/playground/playground-configure.e2e.test.js +135 -0
  46. package/dist/__tests__/playground/playground-configure.e2e.test.js.map +1 -0
  47. package/dist/__tests__/playground/playground-enable-disable.e2e.test.d.ts +1 -0
  48. package/dist/__tests__/playground/playground-enable-disable.e2e.test.js +104 -0
  49. package/dist/__tests__/playground/playground-enable-disable.e2e.test.js.map +1 -0
  50. package/dist/__tests__/playground/playground-example-prompt.e2e.test.d.ts +1 -0
  51. package/dist/__tests__/playground/playground-example-prompt.e2e.test.js +282 -0
  52. package/dist/__tests__/playground/playground-example-prompt.e2e.test.js.map +1 -0
  53. package/dist/__tests__/playground/playground-headers.e2e.test.d.ts +1 -0
  54. package/dist/__tests__/playground/playground-headers.e2e.test.js +324 -0
  55. package/dist/__tests__/playground/playground-headers.e2e.test.js.map +1 -0
  56. package/dist/__tests__/playground/playground-status.e2e.test.d.ts +1 -0
  57. package/dist/__tests__/playground/playground-status.e2e.test.js +88 -0
  58. package/dist/__tests__/playground/playground-status.e2e.test.js.map +1 -0
  59. package/dist/__tests__/project-inspect.e2e.test.d.ts +1 -0
  60. package/dist/__tests__/project-inspect.e2e.test.js +84 -0
  61. package/dist/__tests__/project-inspect.e2e.test.js.map +1 -0
  62. package/dist/__tests__/project-list.e2e.test.d.ts +1 -0
  63. package/dist/__tests__/project-list.e2e.test.js +95 -0
  64. package/dist/__tests__/project-list.e2e.test.js.map +1 -0
  65. package/dist/__tests__/publish.e2e.test.js +76 -6
  66. package/dist/__tests__/publish.e2e.test.js.map +1 -1
  67. package/dist/__tests__/team-inspect.e2e.test.d.ts +1 -0
  68. package/dist/__tests__/team-inspect.e2e.test.js +86 -0
  69. package/dist/__tests__/team-inspect.e2e.test.js.map +1 -0
  70. package/dist/__tests__/team-list.e2e.test.d.ts +1 -0
  71. package/dist/__tests__/team-list.e2e.test.js +58 -0
  72. package/dist/__tests__/team-list.e2e.test.js.map +1 -0
  73. package/dist/__tests__/tunnel.e2e.test.js +19 -5
  74. package/dist/__tests__/tunnel.e2e.test.js.map +1 -1
  75. package/dist/__tests__/utils.d.ts +2 -1
  76. package/dist/__tests__/utils.js +36 -17
  77. package/dist/__tests__/utils.js.map +1 -1
  78. package/dist/commands/audit.d.ts +0 -1
  79. package/dist/commands/audit.js +1 -5
  80. package/dist/commands/audit.js.map +1 -1
  81. package/dist/commands/deploy.d.ts +1 -1
  82. package/dist/commands/deploy.js +16 -8
  83. package/dist/commands/deploy.js.map +1 -1
  84. package/dist/commands/deployment/inspect.js +2 -2
  85. package/dist/commands/deployment/inspect.js.map +1 -1
  86. package/dist/commands/deployment/list.d.ts +2 -1
  87. package/dist/commands/deployment/list.js +5 -8
  88. package/dist/commands/deployment/list.js.map +1 -1
  89. package/dist/commands/deployment/logs.js +4 -1
  90. package/dist/commands/deployment/logs.js.map +1 -1
  91. package/dist/commands/environment/inspect.d.ts +13 -0
  92. package/dist/commands/environment/inspect.js +51 -0
  93. package/dist/commands/environment/inspect.js.map +1 -0
  94. package/dist/commands/environment/list.d.ts +11 -0
  95. package/dist/commands/environment/list.js +56 -0
  96. package/dist/commands/environment/list.js.map +1 -0
  97. package/dist/commands/environment-variable/add.d.ts +0 -1
  98. package/dist/commands/environment-variable/add.js +5 -6
  99. package/dist/commands/environment-variable/add.js.map +1 -1
  100. package/dist/commands/environment-variable/list.js +2 -2
  101. package/dist/commands/environment-variable/list.js.map +1 -1
  102. package/dist/commands/environment-variable/remove.d.ts +0 -1
  103. package/dist/commands/environment-variable/remove.js +2 -6
  104. package/dist/commands/environment-variable/remove.js.map +1 -1
  105. package/dist/commands/environment-variable/update.d.ts +0 -1
  106. package/dist/commands/environment-variable/update.js +2 -6
  107. package/dist/commands/environment-variable/update.js.map +1 -1
  108. package/dist/commands/git/connect.d.ts +0 -1
  109. package/dist/commands/git/connect.js +4 -8
  110. package/dist/commands/git/connect.js.map +1 -1
  111. package/dist/commands/git/disconnect.d.ts +0 -3
  112. package/dist/commands/git/disconnect.js +3 -12
  113. package/dist/commands/git/disconnect.js.map +1 -1
  114. package/dist/commands/link.d.ts +1 -1
  115. package/dist/commands/link.js +10 -9
  116. package/dist/commands/link.js.map +1 -1
  117. package/dist/commands/login.js +2 -2
  118. package/dist/commands/login.js.map +1 -1
  119. package/dist/commands/logs.js +36 -8
  120. package/dist/commands/logs.js.map +1 -1
  121. package/dist/commands/playground/configure.d.ts +12 -0
  122. package/dist/commands/playground/configure.js +39 -0
  123. package/dist/commands/playground/configure.js.map +1 -0
  124. package/dist/commands/playground/disable.d.ts +9 -0
  125. package/dist/commands/playground/disable.js +24 -0
  126. package/dist/commands/playground/disable.js.map +1 -0
  127. package/dist/commands/playground/enable.d.ts +9 -0
  128. package/dist/commands/playground/enable.js +24 -0
  129. package/dist/commands/playground/enable.js.map +1 -0
  130. package/dist/commands/playground/example-prompt/add.d.ts +12 -0
  131. package/dist/commands/playground/example-prompt/add.js +39 -0
  132. package/dist/commands/playground/example-prompt/add.js.map +1 -0
  133. package/dist/commands/playground/example-prompt/list.d.ts +9 -0
  134. package/dist/commands/playground/example-prompt/list.js +24 -0
  135. package/dist/commands/playground/example-prompt/list.js.map +1 -0
  136. package/dist/commands/playground/example-prompt/remove.d.ts +11 -0
  137. package/dist/commands/playground/example-prompt/remove.js +34 -0
  138. package/dist/commands/playground/example-prompt/remove.js.map +1 -0
  139. package/dist/commands/playground/headers/add.d.ts +14 -0
  140. package/dist/commands/playground/headers/add.js +49 -0
  141. package/dist/commands/playground/headers/add.js.map +1 -0
  142. package/dist/commands/playground/headers/list.d.ts +9 -0
  143. package/dist/commands/playground/headers/list.js +24 -0
  144. package/dist/commands/playground/headers/list.js.map +1 -0
  145. package/dist/commands/playground/headers/remove.d.ts +11 -0
  146. package/dist/commands/playground/headers/remove.js +34 -0
  147. package/dist/commands/playground/headers/remove.js.map +1 -0
  148. package/dist/commands/playground/status.d.ts +9 -0
  149. package/dist/commands/playground/status.js +24 -0
  150. package/dist/commands/playground/status.js.map +1 -0
  151. package/dist/commands/project/inspect.d.ts +11 -0
  152. package/dist/commands/project/inspect.js +75 -0
  153. package/dist/commands/project/inspect.js.map +1 -0
  154. package/dist/commands/project/list.d.ts +10 -0
  155. package/dist/commands/project/list.js +50 -0
  156. package/dist/commands/project/list.js.map +1 -0
  157. package/dist/commands/publish.d.ts +2 -2
  158. package/dist/commands/publish.js +4 -11
  159. package/dist/commands/publish.js.map +1 -1
  160. package/dist/commands/team/inspect.d.ts +10 -0
  161. package/dist/commands/team/inspect.js +97 -0
  162. package/dist/commands/team/inspect.js.map +1 -0
  163. package/dist/commands/team/list.d.ts +9 -0
  164. package/dist/commands/team/list.js +40 -0
  165. package/dist/commands/team/list.js.map +1 -0
  166. package/dist/commands/tunnel.d.ts +1 -0
  167. package/dist/commands/tunnel.js +95 -42
  168. package/dist/commands/tunnel.js.map +1 -1
  169. package/dist/env.d.ts +1 -0
  170. package/dist/env.js +1 -0
  171. package/dist/env.js.map +1 -1
  172. package/dist/lib/agent-mode.d.ts +3 -0
  173. package/dist/lib/agent-mode.js +37 -0
  174. package/dist/lib/agent-mode.js.map +1 -0
  175. package/dist/lib/alpic-command.d.ts +8 -1
  176. package/dist/lib/alpic-command.js +24 -5
  177. package/dist/lib/alpic-command.js.map +1 -1
  178. package/dist/lib/archive.js +10 -4
  179. package/dist/lib/archive.js.map +1 -1
  180. package/dist/lib/audit.js +56 -53
  181. package/dist/lib/audit.js.map +1 -1
  182. package/dist/lib/auth/auth.d.ts +3 -1
  183. package/dist/lib/auth/auth.js +18 -9
  184. package/dist/lib/auth/auth.js.map +1 -1
  185. package/dist/lib/auth/oauth/client.d.ts +1 -1
  186. package/dist/lib/auth/oauth/client.js +7 -1
  187. package/dist/lib/auth/oauth/client.js.map +1 -1
  188. package/dist/lib/auth/oauth/server/assets/authorize.html +39 -0
  189. package/dist/lib/auth/oauth/server/index.d.ts +2 -1
  190. package/dist/lib/auth/oauth/server/index.js +31 -8
  191. package/dist/lib/auth/oauth/server/index.js.map +1 -1
  192. package/dist/lib/auth/whoami.js +7 -5
  193. package/dist/lib/auth/whoami.js.map +1 -1
  194. package/dist/lib/base-workflow.d.ts +2 -0
  195. package/dist/lib/base-workflow.js +12 -2
  196. package/dist/lib/base-workflow.js.map +1 -1
  197. package/dist/lib/deployment.d.ts +3 -0
  198. package/dist/lib/deployment.js +14 -10
  199. package/dist/lib/deployment.js.map +1 -1
  200. package/dist/lib/environment-variable.js +36 -33
  201. package/dist/lib/environment-variable.js.map +1 -1
  202. package/dist/lib/git.d.ts +1 -0
  203. package/dist/lib/git.js +24 -5
  204. package/dist/lib/git.js.map +1 -1
  205. package/dist/lib/link.d.ts +2 -0
  206. package/dist/lib/link.js +156 -43
  207. package/dist/lib/link.js.map +1 -1
  208. package/dist/lib/logs.js +8 -4
  209. package/dist/lib/logs.js.map +1 -1
  210. package/dist/lib/playground.d.ts +53 -0
  211. package/dist/lib/playground.js +291 -0
  212. package/dist/lib/playground.js.map +1 -0
  213. package/dist/lib/publish.js +46 -22
  214. package/dist/lib/publish.js.map +1 -1
  215. package/dist/lib/resolve.d.ts +20 -2
  216. package/dist/lib/resolve.js +108 -12
  217. package/dist/lib/resolve.js.map +1 -1
  218. package/dist/lib/telemetry.js +1 -0
  219. package/dist/lib/telemetry.js.map +1 -1
  220. package/dist/lib/upload.js +0 -1
  221. package/dist/lib/upload.js.map +1 -1
  222. package/dist/lib/utils.d.ts +34 -0
  223. package/dist/lib/utils.js +13 -1
  224. package/dist/lib/utils.js.map +1 -1
  225. package/dist/lib/utils.test.js +18 -1
  226. package/dist/lib/utils.test.js.map +1 -1
  227. package/dist/lib/vendor/pipenet.d.ts +1 -0
  228. package/dist/lib/vendor/pipenet.js +15609 -0
  229. package/dist/lib/vendor/pipenet.js.LEGAL.txt +17 -0
  230. package/dist/lib/vendor/pipenet.js.map +7 -0
  231. package/package.json +27 -24
  232. package/dist/__tests__/mock-server.js.map +0 -1
package/README.md CHANGED
@@ -4,24 +4,6 @@ Deploy and manage your MCP servers from the command line.
4
4
 
5
5
  Full documentation: **https://docs.alpic.ai/cli/overview**
6
6
 
7
- ## Install
8
-
9
- ```bash
10
- npm install -g alpic
11
- ```
12
-
13
- ## Authenticate
14
-
15
- ```bash
16
- alpic login
17
- ```
18
-
19
- Or set an API key:
20
-
21
- ```bash
22
- export ALPIC_API_KEY=your_api_key_here
23
- ```
24
-
25
7
  ## Commands
26
8
 
27
9
  | Command | Description |
@@ -38,3 +20,53 @@ export ALPIC_API_KEY=your_api_key_here
38
20
  | `telemetry enable\|disable\|status` | Manage usage reporting |
39
21
  | `tunnel` | Expose local server to the internet |
40
22
  | `whoami` | Display current user |
23
+
24
+ ## Development
25
+
26
+ Run `pnpm update:docs` to ensure CLI documentation stays aligned with the current CLI code before finalizing changes.
27
+
28
+ For release validation, the safest way to test the current published versions is:
29
+
30
+ ```bash
31
+ npx alpic@latest <command>
32
+ npx alpic@staging <command>
33
+ ```
34
+
35
+ `alpic@staging` is available for staging builds. For local development of this repository, execute `./bin/dev.js` instead of invoking a published package.
36
+
37
+ ### Testing locally
38
+
39
+ **node-pty**: The root `postinstall` script automatically runs `chmod +x` on node-pty's `spawn-helper` binary (workaround for [microsoft/node-pty#850](https://github.com/microsoft/node-pty/issues/850)). No manual step needed, but if the `tunnel` command fails with a permission error, re-run `pnpm install`.
40
+
41
+ **wellknown controller**: `alpic login` relies on OAuth discovery. The marketplace backend must be running locally and serving `http://localhost:3000/.well-known/oauth-protected-resource`. Without it, the login flow will fail.
42
+
43
+ **Token management**: `alpic login` and `alpic logout` modify your stored credentials on disk. Check your current state with `alpic whoami` before and after tests to avoid accidentally clobbering your credentials.
44
+
45
+ ```bash
46
+ # Point the CLI at the local API
47
+ # Inline these env vars when running commands:
48
+ # ALPIC_API_BASE_URL=http://localhost:3000 ALPIC_COGNITO_CLIENT_ID=2ab4khb8voo489m8qe2lj0u2lp
49
+ alpic whoami
50
+ alpic deploy
51
+ ```
52
+
53
+ ### Testing on staging
54
+
55
+ ```bash
56
+ # Point the CLI at the staging API
57
+ # Inline these env vars when running commands:
58
+ # ALPIC_API_BASE_URL=https://api.staging.alpic.ai ALPIC_COGNITO_CLIENT_ID=2ab4khb8voo489m8qe2lj0u2lp
59
+ alpic login # uses staging credentials — separate from production
60
+ alpic whoami
61
+ alpic deploy
62
+ ```
63
+
64
+ ## Development Guidelines
65
+
66
+ **Tests**: The CLI is heavily tested. Any change should be covered by the existing test suite, or you should add or extend tests so behavior stays protected.
67
+
68
+ **Agent-first**: The CLI must work in non-TTY environments (Claude, Cursor, CI, etc.). Never call `p.spinner()` from `@clack/prompts` directly — use `createSpinner()` from `src/lib/agent-mode.ts`, which auto-detects agent mode via `@vercel/detect-agent` and falls back to plain `console.log`.
69
+
70
+ **Exit handling**: Never call `process.exit()` directly from commands. Use one of the exit helpers provided by the Alpic base command so cleanup, formatting, and agent-mode behavior remain consistent.
71
+
72
+ **`@clack/prompts` is for commands only**: Only command files (`src/commands/**`) and base command classes (`src/lib/alpic-command.ts`, `src/lib/base-workflow.ts`) may import `@clack/prompts` or write to the console. Library utilities in `src/lib/**` must return data — let the calling command handle output.
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,41 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ const mockIsAuthenticated = vi.fn();
3
+ const mockOauthLogin = vi.fn();
4
+ vi.mock("../lib/auth/auth.js", () => ({
5
+ isAuthenticated: () => mockIsAuthenticated(),
6
+ oauthLogin: () => mockOauthLogin(),
7
+ }));
8
+ // Must import after vi.mock so the mock is in place
9
+ const { AlpicCommand } = await import("../lib/alpic-command.js");
10
+ class TestCommand extends AlpicCommand {
11
+ static id = "test";
12
+ async run() {
13
+ await this.ensureAuthenticated({ "non-interactive": false });
14
+ }
15
+ }
16
+ describe("ensureAuthenticated", () => {
17
+ beforeEach(() => {
18
+ vi.clearAllMocks();
19
+ });
20
+ it("does nothing when already authenticated", async () => {
21
+ mockIsAuthenticated.mockResolvedValue(true);
22
+ const command = new TestCommand([], {});
23
+ await command.ensureAuthenticated({ "non-interactive": false });
24
+ expect(mockIsAuthenticated).toHaveBeenCalled();
25
+ expect(mockOauthLogin).not.toHaveBeenCalled();
26
+ });
27
+ it("triggers login flow when not authenticated in interactive mode", async () => {
28
+ mockIsAuthenticated.mockResolvedValue(false);
29
+ mockOauthLogin.mockResolvedValue(undefined);
30
+ const command = new TestCommand([], {});
31
+ await command.ensureAuthenticated({ "non-interactive": false });
32
+ expect(mockOauthLogin).toHaveBeenCalled();
33
+ });
34
+ it("exits with error when not authenticated in non-interactive mode", async () => {
35
+ mockIsAuthenticated.mockResolvedValue(false);
36
+ const command = new TestCommand([], {});
37
+ await expect(command.ensureAuthenticated({ "non-interactive": true })).rejects.toThrow();
38
+ expect(mockOauthLogin).not.toHaveBeenCalled();
39
+ });
40
+ });
41
+ //# sourceMappingURL=alpic-command.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alpic-command.test.js","sourceRoot":"","sources":["../../src/__tests__/alpic-command.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9D,MAAM,mBAAmB,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;AACpC,MAAM,cAAc,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;AAE/B,EAAE,CAAC,IAAI,CAAC,qBAAqB,EAAE,GAAG,EAAE,CAAC,CAAC;IACpC,eAAe,EAAE,GAAG,EAAE,CAAC,mBAAmB,EAAE;IAC5C,UAAU,EAAE,GAAG,EAAE,CAAC,cAAc,EAAE;CACnC,CAAC,CAAC,CAAC;AAEJ,oDAAoD;AACpD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAC;AAEjE,MAAM,WAAY,SAAQ,YAAY;IACpC,MAAM,CAAU,EAAE,GAAG,MAAM,CAAC;IAC5B,KAAK,CAAC,GAAG;QACP,MAAM,IAAI,CAAC,mBAAmB,CAAC,EAAE,iBAAiB,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/D,CAAC;;AAGH,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;QACvD,mBAAmB,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;QAE5C,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,EAAE,EAAE,EAAW,CAAC,CAAC;QACjD,MAAM,OAAO,CAAC,mBAAmB,CAAC,EAAE,iBAAiB,EAAE,KAAK,EAAE,CAAC,CAAC;QAEhE,MAAM,CAAC,mBAAmB,CAAC,CAAC,gBAAgB,EAAE,CAAC;QAC/C,MAAM,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;QAC9E,mBAAmB,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;QAC7C,cAAc,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;QAE5C,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,EAAE,EAAE,EAAW,CAAC,CAAC;QACjD,MAAM,OAAO,CAAC,mBAAmB,CAAC,EAAE,iBAAiB,EAAE,KAAK,EAAE,CAAC,CAAC;QAEhE,MAAM,CAAC,cAAc,CAAC,CAAC,gBAAgB,EAAE,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;QAC/E,mBAAmB,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;QAE7C,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,EAAE,EAAE,EAAW,CAAC,CAAC;QAEjD,MAAM,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QAEzF,MAAM,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAChD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1,19 +1,32 @@
1
1
  import { rmSync } from "node:fs";
2
- import { afterEach, beforeEach, describe, expect, it } from "vitest";
3
- import { MockApiServer } from "./mock-server.js";
2
+ import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
3
+ import { MockApiServer } from "./mock-api.js";
4
4
  import { buildMockProject, cliSession, createConfigFile, expectSuccessfulApiCall, setupTestDirectory, } from "./utils.js";
5
5
  const TEAM_ID = "mock-team-id";
6
6
  const PROJECT_ID = "mock-project-id";
7
7
  const ENV_ID = "mock-env-id";
8
8
  const STAGING_ENV_ID = "staging-env-id";
9
+ const DEPLOYED_DEPLOYMENT = {
10
+ id: "mock-deployment-id",
11
+ status: "deployed",
12
+ sourceCommitId: "abc1234",
13
+ sourceCommitMessage: "initial deploy",
14
+ completedAt: new Date(),
15
+ };
9
16
  describe("alpic audit (E2E)", () => {
10
17
  let mockServer;
11
18
  let serverUrl;
12
19
  let cwd;
13
20
  let binPath;
14
- beforeEach(async () => {
21
+ beforeAll(async () => {
15
22
  mockServer = new MockApiServer();
16
23
  serverUrl = await mockServer.start();
24
+ });
25
+ afterAll(async () => {
26
+ await mockServer.stop();
27
+ });
28
+ beforeEach(async () => {
29
+ mockServer.reset();
17
30
  const setup = await setupTestDirectory();
18
31
  cwd = setup.cwd;
19
32
  binPath = setup.binPath;
@@ -23,10 +36,10 @@ describe("alpic audit (E2E)", () => {
23
36
  projectName: "my-project",
24
37
  environmentId: ENV_ID,
25
38
  environmentName: "production",
39
+ latestDeployment: DEPLOYED_DEPLOYMENT,
26
40
  }));
27
41
  });
28
- afterEach(async () => {
29
- await mockServer.stop();
42
+ afterEach(() => {
30
43
  if (cwd) {
31
44
  rmSync(cwd, { recursive: true, force: true });
32
45
  }
@@ -43,9 +56,9 @@ describe("alpic audit (E2E)", () => {
43
56
  await cli.expect("Beacon Report");
44
57
  });
45
58
  expect(exitCode).toBe(0);
46
- const createCall = mockServer.getLastCall("POST", "/v1/beacon/analyses");
59
+ const createCall = mockServer.getLastCall("POST", "/v1/beacon/audits");
47
60
  expectSuccessfulApiCall(createCall, (call) => {
48
- expect(call.input).toMatchObject({ targetUrl: "https://example.com/mcp" });
61
+ expect(call.input).toMatchObject({ targetUrl: "https://example.com/mcp", excludeCategories: ["e2e"] });
49
62
  expect(call.input.projectId).toBeUndefined();
50
63
  });
51
64
  });
@@ -90,7 +103,7 @@ describe("alpic audit (E2E)", () => {
90
103
  await cli.expect("Beacon Report");
91
104
  });
92
105
  expect(exitCode).toBe(0);
93
- const createCall = mockServer.getLastCall("POST", "/v1/beacon/analyses");
106
+ const createCall = mockServer.getLastCall("POST", "/v1/beacon/audits");
94
107
  expectSuccessfulApiCall(createCall, (call) => {
95
108
  expect(call.input).toMatchObject({
96
109
  teamId: TEAM_ID,
@@ -124,7 +137,7 @@ describe("alpic audit (E2E)", () => {
124
137
  });
125
138
  expect(exitCode).toBe(0);
126
139
  expect(output).not.toContain("Using project config from .alpic");
127
- const createCall = mockServer.getLastCall("POST", "/v1/beacon/analyses");
140
+ const createCall = mockServer.getLastCall("POST", "/v1/beacon/audits");
128
141
  expectSuccessfulApiCall(createCall, (call) => {
129
142
  expect(call.input).toMatchObject({
130
143
  projectId: PROJECT_ID,
@@ -140,8 +153,7 @@ describe("alpic audit (E2E)", () => {
140
153
  ALPIC_API_KEY: "test-api-key",
141
154
  },
142
155
  }, async (cli) => {
143
- await cli.expect("Choose a team");
144
- await cli.send("");
156
+ await cli.expect("Using team");
145
157
  await cli.expect("Choose a project");
146
158
  await cli.send("");
147
159
  await cli.expect("Beacon Report");
@@ -156,6 +168,7 @@ describe("alpic audit (E2E)", () => {
156
168
  projectName: "my-project",
157
169
  environmentId: ENV_ID,
158
170
  environmentName: "production",
171
+ latestDeployment: DEPLOYED_DEPLOYMENT,
159
172
  }),
160
173
  environments: [
161
174
  {
@@ -165,7 +178,7 @@ describe("alpic audit (E2E)", () => {
165
178
  mcpServerUrl: "https://mcp-production.alpic.ai",
166
179
  createdAt: new Date(),
167
180
  projectId: PROJECT_ID,
168
- latestDeployment: null,
181
+ latestDeployment: DEPLOYED_DEPLOYMENT,
169
182
  },
170
183
  {
171
184
  id: STAGING_ENV_ID,
@@ -189,7 +202,7 @@ describe("alpic audit (E2E)", () => {
189
202
  await cli.expect("Beacon Report");
190
203
  });
191
204
  expect(exitCode).toBe(0);
192
- const createCall = mockServer.getLastCall("POST", "/v1/beacon/analyses");
205
+ const createCall = mockServer.getLastCall("POST", "/v1/beacon/audits");
193
206
  expectSuccessfulApiCall(createCall, (call) => {
194
207
  expect(call.input).toMatchObject({
195
208
  targetUrl: "https://mcp-staging.alpic.ai",
@@ -209,6 +222,180 @@ describe("alpic audit (E2E)", () => {
209
222
  });
210
223
  expect(exitCode).toBe(1);
211
224
  });
225
+ it("hides projects without successful deployments in interactive selection", async () => {
226
+ mockServer.reset();
227
+ mockServer.addProject(buildMockProject({
228
+ projectId: "deployed-project",
229
+ teamId: TEAM_ID,
230
+ projectName: "deployed-project",
231
+ environmentId: "deployed-env",
232
+ environmentName: "production",
233
+ latestDeployment: DEPLOYED_DEPLOYMENT,
234
+ }));
235
+ mockServer.addProject(buildMockProject({
236
+ projectId: "undeployed-project",
237
+ teamId: TEAM_ID,
238
+ projectName: "undeployed-project",
239
+ environmentId: "undeployed-env",
240
+ environmentName: "production",
241
+ }));
242
+ const { exitCode, output } = await cliSession(process.execPath, [binPath, "audit"], {
243
+ cwd,
244
+ env: {
245
+ ALPIC_API_BASE_URL: serverUrl,
246
+ ALPIC_API_KEY: "test-api-key",
247
+ },
248
+ }, async (cli) => {
249
+ await cli.expect("Choose a project");
250
+ await cli.send("");
251
+ await cli.expect("Beacon Report");
252
+ });
253
+ expect(exitCode).toBe(0);
254
+ expect(output).toContain("deployed-project");
255
+ expect(output).not.toContain("undeployed-project");
256
+ });
257
+ it("errors when no projects have successful deployments in interactive mode", async () => {
258
+ mockServer.reset();
259
+ mockServer.addProject(buildMockProject({
260
+ projectId: "failed-project",
261
+ teamId: TEAM_ID,
262
+ projectName: "failed-project",
263
+ environmentId: "failed-env",
264
+ environmentName: "production",
265
+ }));
266
+ const { exitCode } = await cliSession(process.execPath, [binPath, "audit"], {
267
+ cwd,
268
+ env: {
269
+ ALPIC_API_BASE_URL: serverUrl,
270
+ ALPIC_API_KEY: "test-api-key",
271
+ },
272
+ }, async (cli) => {
273
+ await cli.expect("No projects with a successful deployment found");
274
+ });
275
+ expect(exitCode).toBe(1);
276
+ });
277
+ it("only shows deployed environments when selecting interactively", async () => {
278
+ mockServer.reset();
279
+ const multiEnvProject = {
280
+ ...buildMockProject({
281
+ projectId: PROJECT_ID,
282
+ teamId: TEAM_ID,
283
+ projectName: "my-project",
284
+ environmentId: ENV_ID,
285
+ environmentName: "production",
286
+ latestDeployment: DEPLOYED_DEPLOYMENT,
287
+ }),
288
+ environments: [
289
+ {
290
+ id: ENV_ID,
291
+ name: "production",
292
+ sourceBranch: null,
293
+ mcpServerUrl: "https://mcp-production.alpic.ai",
294
+ createdAt: new Date(),
295
+ projectId: PROJECT_ID,
296
+ latestDeployment: DEPLOYED_DEPLOYMENT,
297
+ },
298
+ {
299
+ id: STAGING_ENV_ID,
300
+ name: "staging",
301
+ sourceBranch: "develop",
302
+ mcpServerUrl: "https://mcp-staging.alpic.ai",
303
+ createdAt: new Date(),
304
+ projectId: PROJECT_ID,
305
+ latestDeployment: null,
306
+ },
307
+ ],
308
+ };
309
+ mockServer.addProject(multiEnvProject);
310
+ const { exitCode, output } = await cliSession(process.execPath, [binPath, "audit", "--project-id", PROJECT_ID], {
311
+ cwd,
312
+ env: {
313
+ ALPIC_API_BASE_URL: serverUrl,
314
+ ALPIC_API_KEY: "test-api-key",
315
+ },
316
+ }, async (cli) => {
317
+ await cli.expect('Using environment "production"');
318
+ await cli.expect("Beacon Report");
319
+ });
320
+ expect(exitCode).toBe(0);
321
+ expect(output).not.toContain("staging");
322
+ });
323
+ it("errors in --non-interactive mode when production environment is not deployed but others are", async () => {
324
+ mockServer.reset();
325
+ const multiEnvProject = {
326
+ ...buildMockProject({
327
+ projectId: PROJECT_ID,
328
+ teamId: TEAM_ID,
329
+ projectName: "my-project",
330
+ environmentId: ENV_ID,
331
+ environmentName: "production",
332
+ }),
333
+ environments: [
334
+ {
335
+ id: ENV_ID,
336
+ name: "production",
337
+ sourceBranch: null,
338
+ mcpServerUrl: "https://mcp-production.alpic.ai",
339
+ createdAt: new Date(),
340
+ projectId: PROJECT_ID,
341
+ latestDeployment: null,
342
+ },
343
+ {
344
+ id: STAGING_ENV_ID,
345
+ name: "staging",
346
+ sourceBranch: "develop",
347
+ mcpServerUrl: "https://mcp-staging.alpic.ai",
348
+ createdAt: new Date(),
349
+ projectId: PROJECT_ID,
350
+ latestDeployment: DEPLOYED_DEPLOYMENT,
351
+ },
352
+ {
353
+ id: "feature-env-id",
354
+ name: "feature-x",
355
+ sourceBranch: "feature-x",
356
+ mcpServerUrl: "https://mcp-feature.alpic.ai",
357
+ createdAt: new Date(),
358
+ projectId: PROJECT_ID,
359
+ latestDeployment: DEPLOYED_DEPLOYMENT,
360
+ },
361
+ ],
362
+ };
363
+ mockServer.addProject(multiEnvProject);
364
+ const { exitCode } = await cliSession(process.execPath, [binPath, "audit", "--project-id", PROJECT_ID, "--non-interactive"], {
365
+ cwd,
366
+ env: {
367
+ ALPIC_API_BASE_URL: serverUrl,
368
+ ALPIC_API_KEY: "test-api-key",
369
+ },
370
+ }, async (cli) => {
371
+ await cli.expect("Multiple environments found. Use --environment-id to specify which one to audit.");
372
+ });
373
+ expect(exitCode).toBe(1);
374
+ });
375
+ it("--environment-id bypasses deployment filter and audits an undeployed environment", async () => {
376
+ mockServer.reset();
377
+ mockServer.addProject(buildMockProject({
378
+ projectId: PROJECT_ID,
379
+ teamId: TEAM_ID,
380
+ projectName: "my-project",
381
+ environmentId: ENV_ID,
382
+ environmentName: "production",
383
+ }));
384
+ const { exitCode } = await cliSession(process.execPath, [binPath, "audit", "--project-id", PROJECT_ID, "--environment-id", ENV_ID], {
385
+ cwd,
386
+ env: {
387
+ ALPIC_API_BASE_URL: serverUrl,
388
+ ALPIC_API_KEY: "test-api-key",
389
+ },
390
+ }, async (cli) => {
391
+ await cli.expect("Beacon Report");
392
+ });
393
+ expect(exitCode).toBe(0);
394
+ const createCall = mockServer.getLastCall("POST", "/v1/beacon/audits");
395
+ expectSuccessfulApiCall(createCall, (call) => {
396
+ expect(call.input).toMatchObject({ projectId: PROJECT_ID });
397
+ });
398
+ });
212
399
  it("errors in --non-interactive mode without flags or config", async () => {
213
400
  const { exitCode } = await cliSession(process.execPath, [binPath, "audit", "--non-interactive"], {
214
401
  cwd,
@@ -222,8 +409,8 @@ describe("alpic audit (E2E)", () => {
222
409
  expect(exitCode).toBe(1);
223
410
  });
224
411
  });
225
- describe("analysis lifecycle", () => {
226
- it("polls until analysis completes", async () => {
412
+ describe("audit lifecycle", () => {
413
+ it("polls until audit completes", async () => {
227
414
  const pendingResponse = {
228
415
  id: "mock-analysis-id",
229
416
  targetUrl: "https://example.com/mcp",
@@ -249,6 +436,8 @@ describe("alpic audit (E2E)", () => {
249
436
  requiresAuth: false,
250
437
  hasViewSupport: false,
251
438
  isReadyForPlatform: { chatgpt: true, claudeai: true },
439
+ widgetScreenshotKeys: {},
440
+ widgetScreenshots: {},
252
441
  },
253
442
  };
254
443
  mockServer.setBeaconGetResponses([pendingResponse, pendingResponse, completedResponse]);
@@ -262,10 +451,10 @@ describe("alpic audit (E2E)", () => {
262
451
  await cli.expect("Beacon Report");
263
452
  });
264
453
  expect(exitCode).toBe(0);
265
- const getCalls = mockServer.getCalls("GET", "/v1/beacon/analyses");
454
+ const getCalls = mockServer.getCalls("GET", "/v1/beacon/audits");
266
455
  expect(getCalls.length).toBeGreaterThanOrEqual(3);
267
456
  }, 15_000);
268
- it("handles failed analysis", async () => {
457
+ it("handles failed audit", async () => {
269
458
  mockServer.setBeaconGetResponses([
270
459
  {
271
460
  id: "mock-analysis-id",
@@ -283,7 +472,7 @@ describe("alpic audit (E2E)", () => {
283
472
  ALPIC_API_KEY: "test-api-key",
284
473
  },
285
474
  }, async (cli) => {
286
- await cli.expect("The analysis failed");
475
+ await cli.expect("The audit failed");
287
476
  });
288
477
  expect(exitCode).toBe(1);
289
478
  });
@@ -307,6 +496,8 @@ describe("alpic audit (E2E)", () => {
307
496
  results: [
308
497
  {
309
498
  checkId: "check-pass",
499
+ checkName: "Server Responds",
500
+ description: "Check server connectivity",
310
501
  status: "pass",
311
502
  message: "Server is reachable",
312
503
  severity: "error",
@@ -316,6 +507,8 @@ describe("alpic audit (E2E)", () => {
316
507
  },
317
508
  {
318
509
  checkId: "check-error",
510
+ checkName: "Tool Description",
511
+ description: "Check tool descriptions",
319
512
  status: "fail",
320
513
  message: "Missing tool description",
321
514
  severity: "error",
@@ -326,6 +519,8 @@ describe("alpic audit (E2E)", () => {
326
519
  },
327
520
  {
328
521
  checkId: "check-warning",
522
+ checkName: "Response Time",
523
+ description: "Check response time",
329
524
  status: "fail",
330
525
  message: "Slow response time",
331
526
  severity: "warning",
@@ -337,6 +532,8 @@ describe("alpic audit (E2E)", () => {
337
532
  requiresAuth: false,
338
533
  hasViewSupport: false,
339
534
  isReadyForPlatform: { chatgpt: false, claudeai: true },
535
+ widgetScreenshotKeys: {},
536
+ widgetScreenshots: {},
340
537
  },
341
538
  },
342
539
  ]);
@@ -375,6 +572,8 @@ describe("alpic audit (E2E)", () => {
375
572
  results: [
376
573
  {
377
574
  checkId: "server-responds",
575
+ checkName: "Server Responds",
576
+ description: "Check server connectivity",
378
577
  status: "skip",
379
578
  message: "Server requires authentication",
380
579
  skipReason: "The server returned HTTP 401",
@@ -387,6 +586,8 @@ describe("alpic audit (E2E)", () => {
387
586
  requiresAuth: true,
388
587
  hasViewSupport: false,
389
588
  isReadyForPlatform: { chatgpt: false, claudeai: false },
589
+ widgetScreenshotKeys: {},
590
+ widgetScreenshots: {},
390
591
  },
391
592
  },
392
593
  ]);
@@ -424,6 +625,8 @@ describe("alpic audit (E2E)", () => {
424
625
  results: [
425
626
  {
426
627
  checkId: "connectivity-check",
628
+ checkName: "Server Responds",
629
+ description: "Check server connectivity",
427
630
  status: "pass",
428
631
  message: "Server is reachable",
429
632
  severity: "error",
@@ -433,6 +636,8 @@ describe("alpic audit (E2E)", () => {
433
636
  },
434
637
  {
435
638
  checkId: "tool-description-check",
639
+ checkName: "Tool Description",
640
+ description: "Check tool descriptions",
436
641
  status: "fail",
437
642
  message: "Missing tool description",
438
643
  severity: "error",
@@ -443,6 +648,8 @@ describe("alpic audit (E2E)", () => {
443
648
  },
444
649
  {
445
650
  checkId: "response-time-check",
651
+ checkName: "Response Time",
652
+ description: "Check response time",
446
653
  status: "fail",
447
654
  message: "Slow response time",
448
655
  severity: "warning",
@@ -452,6 +659,8 @@ describe("alpic audit (E2E)", () => {
452
659
  },
453
660
  {
454
661
  checkId: "view-check",
662
+ checkName: "View Support",
663
+ description: "Check if the server has view support",
455
664
  status: "skip",
456
665
  message: "View support check",
457
666
  skipReason: "No view resources found",
@@ -464,6 +673,8 @@ describe("alpic audit (E2E)", () => {
464
673
  requiresAuth: false,
465
674
  hasViewSupport: false,
466
675
  isReadyForPlatform: { chatgpt: false, claudeai: true },
676
+ widgetScreenshotKeys: {},
677
+ widgetScreenshots: {},
467
678
  },
468
679
  },
469
680
  ]);
@@ -499,6 +710,8 @@ describe("alpic audit (E2E)", () => {
499
710
  results: [
500
711
  {
501
712
  checkId: "connectivity-check",
713
+ checkName: "Server Responds",
714
+ description: "Check server connectivity",
502
715
  status: "pass",
503
716
  message: "Server is reachable",
504
717
  severity: "error",
@@ -508,6 +721,8 @@ describe("alpic audit (E2E)", () => {
508
721
  },
509
722
  {
510
723
  checkId: "tool-description-check",
724
+ checkName: "Tool Description",
725
+ description: "Check tool descriptions",
511
726
  status: "pass",
512
727
  message: "Tool descriptions are present",
513
728
  severity: "error",
@@ -519,6 +734,8 @@ describe("alpic audit (E2E)", () => {
519
734
  requiresAuth: false,
520
735
  hasViewSupport: false,
521
736
  isReadyForPlatform: { chatgpt: true, claudeai: true },
737
+ widgetScreenshotKeys: {},
738
+ widgetScreenshots: {},
522
739
  },
523
740
  },
524
741
  ]);