@agentuity/cli 0.0.109 → 0.0.111

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 (253) hide show
  1. package/dist/build-report.d.ts +201 -0
  2. package/dist/build-report.d.ts.map +1 -0
  3. package/dist/build-report.js +335 -0
  4. package/dist/build-report.js.map +1 -0
  5. package/dist/cli.d.ts.map +1 -1
  6. package/dist/cli.js +19 -4
  7. package/dist/cli.js.map +1 -1
  8. package/dist/cmd/build/entry-generator.d.ts.map +1 -1
  9. package/dist/cmd/build/entry-generator.js +3 -1
  10. package/dist/cmd/build/entry-generator.js.map +1 -1
  11. package/dist/cmd/build/index.d.ts.map +1 -1
  12. package/dist/cmd/build/index.js +44 -1
  13. package/dist/cmd/build/index.js.map +1 -1
  14. package/dist/cmd/build/typecheck.d.ts +7 -1
  15. package/dist/cmd/build/typecheck.d.ts.map +1 -1
  16. package/dist/cmd/build/typecheck.js +11 -1
  17. package/dist/cmd/build/typecheck.js.map +1 -1
  18. package/dist/cmd/build/vite/agent-discovery.d.ts +1 -1
  19. package/dist/cmd/build/vite/agent-discovery.d.ts.map +1 -1
  20. package/dist/cmd/build/vite/agent-discovery.js +3 -3
  21. package/dist/cmd/build/vite/agent-discovery.js.map +1 -1
  22. package/dist/cmd/build/vite/index.d.ts +2 -1
  23. package/dist/cmd/build/vite/index.d.ts.map +1 -1
  24. package/dist/cmd/build/vite/index.js +3 -2
  25. package/dist/cmd/build/vite/index.js.map +1 -1
  26. package/dist/cmd/build/vite/metadata-generator.d.ts.map +1 -1
  27. package/dist/cmd/build/vite/metadata-generator.js +3 -5
  28. package/dist/cmd/build/vite/metadata-generator.js.map +1 -1
  29. package/dist/cmd/build/vite/registry-generator.d.ts +1 -1
  30. package/dist/cmd/build/vite/registry-generator.d.ts.map +1 -1
  31. package/dist/cmd/build/vite/registry-generator.js +126 -41
  32. package/dist/cmd/build/vite/registry-generator.js.map +1 -1
  33. package/dist/cmd/build/vite/route-discovery.d.ts +6 -0
  34. package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -1
  35. package/dist/cmd/build/vite/route-discovery.js +19 -0
  36. package/dist/cmd/build/vite/route-discovery.js.map +1 -1
  37. package/dist/cmd/build/vite/vite-builder.d.ts +3 -0
  38. package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
  39. package/dist/cmd/build/vite/vite-builder.js +10 -2
  40. package/dist/cmd/build/vite/vite-builder.js.map +1 -1
  41. package/dist/cmd/build/vite-bundler.d.ts +3 -0
  42. package/dist/cmd/build/vite-bundler.d.ts.map +1 -1
  43. package/dist/cmd/build/vite-bundler.js +14 -5
  44. package/dist/cmd/build/vite-bundler.js.map +1 -1
  45. package/dist/cmd/cloud/deploy.d.ts.map +1 -1
  46. package/dist/cmd/cloud/deploy.js +149 -10
  47. package/dist/cmd/cloud/deploy.js.map +1 -1
  48. package/dist/cmd/cloud/deployment/show.d.ts.map +1 -1
  49. package/dist/cmd/cloud/deployment/show.js +0 -1
  50. package/dist/cmd/cloud/deployment/show.js.map +1 -1
  51. package/dist/cmd/cloud/sandbox/create.d.ts.map +1 -1
  52. package/dist/cmd/cloud/sandbox/create.js +18 -0
  53. package/dist/cmd/cloud/sandbox/create.js.map +1 -1
  54. package/dist/cmd/cloud/sandbox/delete.d.ts.map +1 -1
  55. package/dist/cmd/cloud/sandbox/delete.js +2 -6
  56. package/dist/cmd/cloud/sandbox/delete.js.map +1 -1
  57. package/dist/cmd/cloud/sandbox/download.d.ts +3 -0
  58. package/dist/cmd/cloud/sandbox/download.d.ts.map +1 -0
  59. package/dist/cmd/cloud/sandbox/download.js +89 -0
  60. package/dist/cmd/cloud/sandbox/download.js.map +1 -0
  61. package/dist/cmd/cloud/sandbox/env.d.ts +3 -0
  62. package/dist/cmd/cloud/sandbox/env.d.ts.map +1 -0
  63. package/dist/cmd/cloud/sandbox/env.js +90 -0
  64. package/dist/cmd/cloud/sandbox/env.js.map +1 -0
  65. package/dist/cmd/cloud/sandbox/get.d.ts.map +1 -1
  66. package/dist/cmd/cloud/sandbox/get.js +5 -0
  67. package/dist/cmd/cloud/sandbox/get.js.map +1 -1
  68. package/dist/cmd/cloud/sandbox/index.d.ts.map +1 -1
  69. package/dist/cmd/cloud/sandbox/index.js +14 -0
  70. package/dist/cmd/cloud/sandbox/index.js.map +1 -1
  71. package/dist/cmd/cloud/sandbox/ls.d.ts +3 -0
  72. package/dist/cmd/cloud/sandbox/ls.d.ts.map +1 -0
  73. package/dist/cmd/cloud/sandbox/ls.js +119 -0
  74. package/dist/cmd/cloud/sandbox/ls.js.map +1 -0
  75. package/dist/cmd/cloud/sandbox/mkdir.d.ts +3 -0
  76. package/dist/cmd/cloud/sandbox/mkdir.d.ts.map +1 -0
  77. package/dist/cmd/cloud/sandbox/mkdir.js +59 -0
  78. package/dist/cmd/cloud/sandbox/mkdir.js.map +1 -0
  79. package/dist/cmd/cloud/sandbox/rm.d.ts +3 -0
  80. package/dist/cmd/cloud/sandbox/rm.d.ts.map +1 -0
  81. package/dist/cmd/cloud/sandbox/rm.js +45 -0
  82. package/dist/cmd/cloud/sandbox/rm.js.map +1 -0
  83. package/dist/cmd/cloud/sandbox/rmdir.d.ts +3 -0
  84. package/dist/cmd/cloud/sandbox/rmdir.d.ts.map +1 -0
  85. package/dist/cmd/cloud/sandbox/rmdir.js +59 -0
  86. package/dist/cmd/cloud/sandbox/rmdir.js.map +1 -0
  87. package/dist/cmd/cloud/sandbox/snapshot/create.d.ts.map +1 -1
  88. package/dist/cmd/cloud/sandbox/snapshot/create.js +0 -2
  89. package/dist/cmd/cloud/sandbox/snapshot/create.js.map +1 -1
  90. package/dist/cmd/cloud/sandbox/snapshot/get.d.ts.map +1 -1
  91. package/dist/cmd/cloud/sandbox/snapshot/get.js +0 -2
  92. package/dist/cmd/cloud/sandbox/snapshot/get.js.map +1 -1
  93. package/dist/cmd/cloud/sandbox/snapshot/list.d.ts.map +1 -1
  94. package/dist/cmd/cloud/sandbox/snapshot/list.js +0 -3
  95. package/dist/cmd/cloud/sandbox/snapshot/list.js.map +1 -1
  96. package/dist/cmd/cloud/sandbox/upload.d.ts +3 -0
  97. package/dist/cmd/cloud/sandbox/upload.d.ts.map +1 -0
  98. package/dist/cmd/cloud/sandbox/upload.js +77 -0
  99. package/dist/cmd/cloud/sandbox/upload.js.map +1 -0
  100. package/dist/cmd/dev/index.d.ts.map +1 -1
  101. package/dist/cmd/dev/index.js +126 -23
  102. package/dist/cmd/dev/index.js.map +1 -1
  103. package/dist/cmd/dev/sync.d.ts.map +1 -1
  104. package/dist/cmd/dev/sync.js +8 -14
  105. package/dist/cmd/dev/sync.js.map +1 -1
  106. package/dist/cmd/git/account/add.d.ts +17 -0
  107. package/dist/cmd/git/account/add.d.ts.map +1 -0
  108. package/dist/cmd/git/account/add.js +244 -0
  109. package/dist/cmd/git/account/add.js.map +1 -0
  110. package/dist/cmd/git/account/index.d.ts +3 -0
  111. package/dist/cmd/git/account/index.d.ts.map +1 -0
  112. package/dist/cmd/git/account/index.js +11 -0
  113. package/dist/cmd/git/account/index.js.map +1 -0
  114. package/dist/cmd/git/account/list.d.ts +2 -0
  115. package/dist/cmd/git/account/list.d.ts.map +1 -0
  116. package/dist/cmd/git/account/list.js +111 -0
  117. package/dist/cmd/git/account/list.js.map +1 -0
  118. package/dist/cmd/git/account/remove.d.ts +2 -0
  119. package/dist/cmd/git/account/remove.d.ts.map +1 -0
  120. package/dist/cmd/git/account/remove.js +171 -0
  121. package/dist/cmd/git/account/remove.js.map +1 -0
  122. package/dist/cmd/git/index.d.ts +3 -0
  123. package/dist/cmd/git/index.d.ts.map +1 -0
  124. package/dist/cmd/git/index.js +19 -0
  125. package/dist/cmd/git/index.js.map +1 -0
  126. package/dist/cmd/git/link.d.ts +32 -0
  127. package/dist/cmd/git/link.d.ts.map +1 -0
  128. package/dist/cmd/git/link.js +357 -0
  129. package/dist/cmd/git/link.js.map +1 -0
  130. package/dist/cmd/git/list.d.ts +2 -0
  131. package/dist/cmd/git/list.d.ts.map +1 -0
  132. package/dist/cmd/git/list.js +137 -0
  133. package/dist/cmd/git/list.js.map +1 -0
  134. package/dist/cmd/git/status.d.ts +2 -0
  135. package/dist/cmd/git/status.d.ts.map +1 -0
  136. package/dist/cmd/git/status.js +119 -0
  137. package/dist/cmd/git/status.js.map +1 -0
  138. package/dist/cmd/git/unlink.d.ts +2 -0
  139. package/dist/cmd/git/unlink.d.ts.map +1 -0
  140. package/dist/cmd/git/unlink.js +98 -0
  141. package/dist/cmd/git/unlink.js.map +1 -0
  142. package/dist/cmd/index.d.ts.map +1 -1
  143. package/dist/cmd/index.js +2 -0
  144. package/dist/cmd/index.js.map +1 -1
  145. package/dist/cmd/integration/api.d.ts +61 -0
  146. package/dist/cmd/integration/api.d.ts.map +1 -0
  147. package/dist/cmd/integration/api.js +176 -0
  148. package/dist/cmd/integration/api.js.map +1 -0
  149. package/dist/cmd/integration/github/connect.d.ts +2 -0
  150. package/dist/cmd/integration/github/connect.d.ts.map +1 -0
  151. package/dist/cmd/integration/github/connect.js +197 -0
  152. package/dist/cmd/integration/github/connect.js.map +1 -0
  153. package/dist/cmd/integration/github/disconnect.d.ts +2 -0
  154. package/dist/cmd/integration/github/disconnect.d.ts.map +1 -0
  155. package/dist/cmd/integration/github/disconnect.js +121 -0
  156. package/dist/cmd/integration/github/disconnect.js.map +1 -0
  157. package/dist/cmd/integration/github/index.d.ts +2 -0
  158. package/dist/cmd/integration/github/index.d.ts.map +1 -0
  159. package/dist/cmd/integration/github/index.js +21 -0
  160. package/dist/cmd/integration/github/index.js.map +1 -0
  161. package/dist/cmd/integration/index.d.ts +2 -0
  162. package/dist/cmd/integration/index.d.ts.map +1 -0
  163. package/dist/cmd/integration/index.js +16 -0
  164. package/dist/cmd/integration/index.js.map +1 -0
  165. package/dist/cmd/project/auth/generate.d.ts +5 -0
  166. package/dist/cmd/project/auth/generate.d.ts.map +1 -0
  167. package/dist/cmd/project/auth/generate.js +102 -0
  168. package/dist/cmd/project/auth/generate.js.map +1 -0
  169. package/dist/cmd/project/auth/index.d.ts +2 -0
  170. package/dist/cmd/project/auth/index.d.ts.map +1 -0
  171. package/dist/cmd/project/auth/index.js +21 -0
  172. package/dist/cmd/project/auth/index.js.map +1 -0
  173. package/dist/cmd/project/auth/init.d.ts +2 -0
  174. package/dist/cmd/project/auth/init.d.ts.map +1 -0
  175. package/dist/cmd/project/auth/init.js +220 -0
  176. package/dist/cmd/project/auth/init.js.map +1 -0
  177. package/dist/cmd/project/auth/shared.d.ts +88 -0
  178. package/dist/cmd/project/auth/shared.d.ts.map +1 -0
  179. package/dist/cmd/project/auth/shared.js +435 -0
  180. package/dist/cmd/project/auth/shared.js.map +1 -0
  181. package/dist/cmd/project/index.d.ts.map +1 -1
  182. package/dist/cmd/project/index.js +9 -1
  183. package/dist/cmd/project/index.js.map +1 -1
  184. package/dist/cmd/project/template-flow.d.ts.map +1 -1
  185. package/dist/cmd/project/template-flow.js +106 -0
  186. package/dist/cmd/project/template-flow.js.map +1 -1
  187. package/dist/config.d.ts +2 -0
  188. package/dist/config.d.ts.map +1 -1
  189. package/dist/config.js +24 -0
  190. package/dist/config.js.map +1 -1
  191. package/dist/errors.d.ts +2 -1
  192. package/dist/errors.d.ts.map +1 -1
  193. package/dist/errors.js +5 -0
  194. package/dist/errors.js.map +1 -1
  195. package/dist/types.d.ts +3 -4
  196. package/dist/types.d.ts.map +1 -1
  197. package/dist/types.js +5 -2
  198. package/dist/types.js.map +1 -1
  199. package/package.json +6 -5
  200. package/src/build-report.ts +457 -0
  201. package/src/cli.ts +20 -4
  202. package/src/cmd/build/entry-generator.ts +3 -1
  203. package/src/cmd/build/index.ts +51 -1
  204. package/src/cmd/build/typecheck.ts +19 -1
  205. package/src/cmd/build/vite/agent-discovery.ts +4 -4
  206. package/src/cmd/build/vite/index.ts +5 -2
  207. package/src/cmd/build/vite/metadata-generator.ts +5 -7
  208. package/src/cmd/build/vite/registry-generator.ts +136 -43
  209. package/src/cmd/build/vite/route-discovery.ts +20 -0
  210. package/src/cmd/build/vite/vite-builder.ts +13 -2
  211. package/src/cmd/build/vite-bundler.ts +17 -4
  212. package/src/cmd/cloud/deploy.ts +183 -12
  213. package/src/cmd/cloud/deployment/show.ts +0 -1
  214. package/src/cmd/cloud/sandbox/create.ts +22 -0
  215. package/src/cmd/cloud/sandbox/delete.ts +2 -6
  216. package/src/cmd/cloud/sandbox/download.ts +96 -0
  217. package/src/cmd/cloud/sandbox/env.ts +104 -0
  218. package/src/cmd/cloud/sandbox/get.ts +5 -0
  219. package/src/cmd/cloud/sandbox/index.ts +14 -0
  220. package/src/cmd/cloud/sandbox/ls.ts +126 -0
  221. package/src/cmd/cloud/sandbox/mkdir.ts +65 -0
  222. package/src/cmd/cloud/sandbox/rm.ts +51 -0
  223. package/src/cmd/cloud/sandbox/rmdir.ts +65 -0
  224. package/src/cmd/cloud/sandbox/snapshot/create.ts +0 -2
  225. package/src/cmd/cloud/sandbox/snapshot/get.ts +0 -2
  226. package/src/cmd/cloud/sandbox/snapshot/list.ts +0 -3
  227. package/src/cmd/cloud/sandbox/upload.ts +83 -0
  228. package/src/cmd/dev/index.ts +147 -33
  229. package/src/cmd/dev/sync.ts +26 -30
  230. package/src/cmd/git/account/add.ts +317 -0
  231. package/src/cmd/git/account/index.ts +12 -0
  232. package/src/cmd/git/account/list.ts +139 -0
  233. package/src/cmd/git/account/remove.ts +212 -0
  234. package/src/cmd/git/index.ts +20 -0
  235. package/src/cmd/git/link.ts +468 -0
  236. package/src/cmd/git/list.ts +161 -0
  237. package/src/cmd/git/status.ts +144 -0
  238. package/src/cmd/git/unlink.ts +117 -0
  239. package/src/cmd/index.ts +2 -0
  240. package/src/cmd/integration/api.ts +379 -0
  241. package/src/cmd/integration/github/connect.ts +242 -0
  242. package/src/cmd/integration/github/disconnect.ts +149 -0
  243. package/src/cmd/integration/github/index.ts +21 -0
  244. package/src/cmd/integration/index.ts +16 -0
  245. package/src/cmd/project/auth/generate.ts +116 -0
  246. package/src/cmd/project/auth/index.ts +21 -0
  247. package/src/cmd/project/auth/init.ts +263 -0
  248. package/src/cmd/project/auth/shared.ts +534 -0
  249. package/src/cmd/project/index.ts +9 -1
  250. package/src/cmd/project/template-flow.ts +125 -0
  251. package/src/config.ts +34 -0
  252. package/src/errors.ts +7 -0
  253. package/src/types.ts +5 -2
@@ -0,0 +1,144 @@
1
+ import { createSubcommand } from '../../types';
2
+ import * as tui from '../../tui';
3
+ import { getCommand } from '../../command-prefix';
4
+ import { ErrorCode } from '../../errors';
5
+ import { getProjectGithubStatus, getGithubIntegrationStatus } from '../integration/api';
6
+ import { z } from 'zod';
7
+
8
+ const StatusResponseSchema = z.object({
9
+ orgId: z.string().describe('Organization ID'),
10
+ connected: z.boolean().describe('Whether GitHub is connected to the org'),
11
+ integrations: z
12
+ .array(
13
+ z.object({
14
+ id: z.string(),
15
+ githubAccountName: z.string(),
16
+ githubAccountType: z.enum(['user', 'org']),
17
+ })
18
+ )
19
+ .describe('Connected GitHub accounts'),
20
+ projectId: z.string().describe('Project ID'),
21
+ linked: z.boolean().describe('Whether the project is linked to a repo'),
22
+ repoFullName: z.string().optional().describe('Full repository name'),
23
+ branch: z.string().optional().describe('Branch'),
24
+ directory: z.string().optional().describe('Directory'),
25
+ autoDeploy: z.boolean().optional().describe('Auto-deploy enabled'),
26
+ previewDeploy: z.boolean().optional().describe('Preview deploys enabled'),
27
+ });
28
+
29
+ export const statusSubcommand = createSubcommand({
30
+ name: 'status',
31
+ description: 'Show GitHub connection status for current project',
32
+ tags: ['read-only'],
33
+ idempotent: true,
34
+ requires: { auth: true, apiClient: true, project: true },
35
+ schema: {
36
+ response: StatusResponseSchema,
37
+ },
38
+ examples: [
39
+ {
40
+ command: getCommand('git status'),
41
+ description: 'Show GitHub status for current project',
42
+ },
43
+ {
44
+ command: getCommand('--json git status'),
45
+ description: 'Get status in JSON format',
46
+ },
47
+ ],
48
+
49
+ async handler(ctx) {
50
+ const { logger, apiClient, project, options } = ctx;
51
+
52
+ try {
53
+ // Get org-level GitHub status
54
+ const orgStatus = await tui.spinner({
55
+ message: 'Checking GitHub connection...',
56
+ clearOnSuccess: true,
57
+ callback: () => getGithubIntegrationStatus(apiClient, project.orgId),
58
+ });
59
+
60
+ // Get project-level link status
61
+ const projectStatus = await tui.spinner({
62
+ message: 'Checking project status...',
63
+ clearOnSuccess: true,
64
+ callback: () => getProjectGithubStatus(apiClient, project.projectId),
65
+ });
66
+
67
+ const result = {
68
+ orgId: project.orgId,
69
+ connected: orgStatus.connected,
70
+ integrations: orgStatus.integrations.map((i) => ({
71
+ id: i.id,
72
+ githubAccountName: i.githubAccountName,
73
+ githubAccountType: i.githubAccountType,
74
+ })),
75
+ projectId: project.projectId,
76
+ linked: projectStatus.linked,
77
+ repoFullName: projectStatus.repoFullName,
78
+ branch: projectStatus.branch,
79
+ directory: projectStatus.directory,
80
+ autoDeploy: projectStatus.autoDeploy,
81
+ previewDeploy: projectStatus.previewDeploy,
82
+ };
83
+
84
+ if (options.json) {
85
+ return result;
86
+ }
87
+
88
+ tui.newline();
89
+ console.log(tui.bold('GitHub Status'));
90
+ tui.newline();
91
+
92
+ // Organization status
93
+ console.log(`${tui.bold('Organization:')} ${project.orgId}`);
94
+ if (orgStatus.connected && orgStatus.integrations.length > 0) {
95
+ console.log(
96
+ ` ${tui.colorSuccess('✓')} ${orgStatus.integrations.length} GitHub account${orgStatus.integrations.length > 1 ? 's' : ''} connected`
97
+ );
98
+ for (const integration of orgStatus.integrations) {
99
+ const typeLabel = integration.githubAccountType === 'org' ? 'org' : 'user';
100
+ console.log(` - ${integration.githubAccountName} ${tui.muted(`(${typeLabel})`)}`);
101
+ }
102
+ } else {
103
+ console.log(` ${tui.colorError('✗')} No GitHub accounts connected`);
104
+ console.log(
105
+ tui.muted(` Run ${tui.bold('agentuity git account add')} to connect one`)
106
+ );
107
+ }
108
+
109
+ tui.newline();
110
+
111
+ // Project status
112
+ console.log(`${tui.bold('Project:')} ${project.projectId}`);
113
+ if (projectStatus.linked) {
114
+ console.log(
115
+ ` ${tui.colorSuccess('✓')} Linked to ${tui.bold(projectStatus.repoFullName ?? '<unknown repository>')}`
116
+ );
117
+ console.log(` Branch: ${projectStatus.branch}`);
118
+ if (projectStatus.directory) {
119
+ console.log(` Directory: ${projectStatus.directory}`);
120
+ }
121
+ console.log(
122
+ ` Auto-deploy: ${projectStatus.autoDeploy ? tui.colorSuccess('enabled') : tui.muted('disabled')}`
123
+ );
124
+ console.log(
125
+ ` Preview deploys: ${projectStatus.previewDeploy ? tui.colorSuccess('enabled') : tui.muted('disabled')}`
126
+ );
127
+ } else {
128
+ console.log(` ${tui.muted('○')} Not linked to a repository`);
129
+ console.log(tui.muted(` Run ${tui.bold('agentuity git link')} to link one`));
130
+ }
131
+
132
+ tui.newline();
133
+
134
+ return result;
135
+ } catch (error) {
136
+ logger.trace(error);
137
+ return logger.fatal(
138
+ 'Failed to get GitHub status: %s',
139
+ error,
140
+ ErrorCode.INTEGRATION_FAILED
141
+ );
142
+ }
143
+ },
144
+ });
@@ -0,0 +1,117 @@
1
+ import { createSubcommand } from '../../types';
2
+ import * as tui from '../../tui';
3
+ import { getCommand } from '../../command-prefix';
4
+ import { ErrorCode } from '../../errors';
5
+ import { getProjectGithubStatus, unlinkProjectFromRepo } from '../integration/api';
6
+ import { z } from 'zod';
7
+
8
+ const UnlinkOptionsSchema = z.object({
9
+ confirm: z.boolean().optional().describe('Skip confirmation prompt'),
10
+ });
11
+
12
+ const UnlinkResponseSchema = z.object({
13
+ unlinked: z.boolean().describe('Whether the project was unlinked'),
14
+ repoFullName: z.string().optional().describe('Repository that was unlinked'),
15
+ });
16
+
17
+ export const unlinkSubcommand = createSubcommand({
18
+ name: 'unlink',
19
+ description: 'Unlink a project from its GitHub repository',
20
+ tags: ['mutating', 'destructive'],
21
+ idempotent: false,
22
+ requires: { auth: true, apiClient: true, project: true },
23
+ schema: {
24
+ options: UnlinkOptionsSchema,
25
+ response: UnlinkResponseSchema,
26
+ },
27
+ examples: [
28
+ {
29
+ command: getCommand('git unlink'),
30
+ description: 'Unlink current project from GitHub',
31
+ },
32
+ {
33
+ command: getCommand('git unlink --confirm'),
34
+ description: 'Unlink without confirmation prompt',
35
+ },
36
+ {
37
+ command: getCommand('--json git unlink --confirm'),
38
+ description: 'Unlink and return JSON result',
39
+ },
40
+ ],
41
+
42
+ async handler(ctx) {
43
+ const { logger, apiClient, project, opts, options } = ctx;
44
+
45
+ try {
46
+ // Check current status
47
+ const status = await tui.spinner({
48
+ message: 'Checking current status...',
49
+ clearOnSuccess: true,
50
+ callback: () => getProjectGithubStatus(apiClient, project.projectId),
51
+ });
52
+
53
+ if (!status.linked) {
54
+ if (!options.json) {
55
+ tui.newline();
56
+ tui.info('This project is not linked to a GitHub repository.');
57
+ }
58
+ return { unlinked: false };
59
+ }
60
+
61
+ if (!opts.confirm) {
62
+ tui.newline();
63
+ console.log(`Currently linked to: ${tui.bold(status.repoFullName ?? 'Unknown')}`);
64
+ console.log(` Branch: ${status.branch ?? 'default'}`);
65
+ if (status.directory) {
66
+ console.log(` Directory: ${status.directory}`);
67
+ }
68
+ console.log(` Auto-deploy: ${status.autoDeploy ? 'enabled' : 'disabled'}`);
69
+ console.log(` Preview deploys: ${status.previewDeploy ? 'enabled' : 'disabled'}`);
70
+ tui.newline();
71
+
72
+ const confirmed = await tui.confirm(
73
+ `Are you sure you want to unlink from ${tui.bold(status.repoFullName ?? 'this repository')}?`
74
+ );
75
+
76
+ if (!confirmed) {
77
+ tui.info('Cancelled');
78
+ return { unlinked: false };
79
+ }
80
+ }
81
+
82
+ await tui.spinner({
83
+ message: 'Unlinking repository...',
84
+ clearOnSuccess: true,
85
+ callback: () => unlinkProjectFromRepo(apiClient, project.projectId),
86
+ });
87
+
88
+ if (!options.json) {
89
+ tui.newline();
90
+ tui.success(`Unlinked from ${tui.bold(status.repoFullName ?? 'repository')}`);
91
+ tui.newline();
92
+ console.log('Automatic deployments have been disabled for this project.');
93
+ }
94
+
95
+ return { unlinked: true, repoFullName: status.repoFullName };
96
+ } catch (error) {
97
+ // Handle user cancellation
98
+ const isCancel =
99
+ error === '' ||
100
+ (error instanceof Error &&
101
+ (error.message === '' || error.message === 'User cancelled'));
102
+
103
+ if (isCancel) {
104
+ tui.newline();
105
+ tui.info('Cancelled');
106
+ return { unlinked: false };
107
+ }
108
+
109
+ logger.trace(error);
110
+ return logger.fatal(
111
+ 'Failed to unlink repository: %s',
112
+ error,
113
+ ErrorCode.INTEGRATION_FAILED
114
+ );
115
+ }
116
+ },
117
+ });
package/src/cmd/index.ts CHANGED
@@ -9,7 +9,9 @@ export async function discoverCommands(): Promise<CommandDefinition[]> {
9
9
  import('./build').then((m) => m.command),
10
10
  import('./cloud').then((m) => m.command),
11
11
  import('./dev').then((m) => m.command),
12
+ import('./git').then((m) => m.gitCommand),
12
13
  import('./help').then((m) => m.command),
14
+ import('./integration').then((m) => m.command),
13
15
  import('./profile').then((m) => m.command),
14
16
  import('./project').then((m) => m.command),
15
17
  import('./repl').then((m) => m.command),
@@ -0,0 +1,379 @@
1
+ import { z } from 'zod';
2
+ import { APIResponseSchema } from '@agentuity/server';
3
+ import type { APIClient } from '../../api';
4
+ import { StructuredError } from '@agentuity/core';
5
+
6
+ const GithubStartDataSchema = z.object({
7
+ shortId: z.string(),
8
+ });
9
+
10
+ const GithubIntegrationSchema = z.object({
11
+ id: z.string(),
12
+ githubAccountName: z.string(),
13
+ githubAccountType: z.enum(['user', 'org']),
14
+ connectedBy: z.string(),
15
+ connectedAt: z.string(),
16
+ });
17
+
18
+ const GithubStatusDataSchema = z.object({
19
+ connected: z.boolean(),
20
+ integrations: z.array(GithubIntegrationSchema).optional(),
21
+ });
22
+
23
+ export interface GithubIntegration {
24
+ id: string;
25
+ githubAccountName: string;
26
+ githubAccountType: 'user' | 'org';
27
+ connectedBy: string;
28
+ connectedAt: string;
29
+ }
30
+
31
+ export interface GithubIntegrationStartResult {
32
+ shortId: string;
33
+ }
34
+
35
+ export interface GithubIntegrationStatusResult {
36
+ connected: boolean;
37
+ integrations: GithubIntegration[];
38
+ }
39
+
40
+ const GithubIntegrationStartError = StructuredError(
41
+ 'GithubIntegrationStartError',
42
+ 'Error starting GitHub integration flow'
43
+ );
44
+
45
+ export async function startGithubIntegration(
46
+ apiClient: APIClient,
47
+ orgId: string
48
+ ): Promise<GithubIntegrationStartResult> {
49
+ const resp = await apiClient.get(
50
+ `/cli/github/start?orgId=${encodeURIComponent(orgId)}`,
51
+ APIResponseSchema(GithubStartDataSchema)
52
+ );
53
+
54
+ if (!resp.success) {
55
+ throw new GithubIntegrationStartError();
56
+ }
57
+
58
+ if (!resp.data) {
59
+ throw new GithubIntegrationStartError();
60
+ }
61
+
62
+ return { shortId: resp.data.shortId };
63
+ }
64
+
65
+ const GithubIntegrationStatusError = StructuredError(
66
+ 'GithubIntegrationStatusError',
67
+ 'Error checking GitHub integration status'
68
+ );
69
+
70
+ export async function getGithubIntegrationStatus(
71
+ apiClient: APIClient,
72
+ orgId: string
73
+ ): Promise<GithubIntegrationStatusResult> {
74
+ const resp = await apiClient.get(
75
+ `/cli/github/status?orgId=${encodeURIComponent(orgId)}`,
76
+ APIResponseSchema(GithubStatusDataSchema)
77
+ );
78
+
79
+ if (!resp.success) {
80
+ throw new GithubIntegrationStatusError();
81
+ }
82
+
83
+ if (!resp.data) {
84
+ throw new GithubIntegrationStatusError();
85
+ }
86
+
87
+ return {
88
+ connected: resp.data.connected,
89
+ integrations: resp.data.integrations ?? [],
90
+ };
91
+ }
92
+
93
+ const GithubDisconnectDataSchema = z.object({
94
+ disconnected: z.boolean(),
95
+ });
96
+
97
+ export interface GithubDisconnectResult {
98
+ disconnected: boolean;
99
+ }
100
+
101
+ const GithubDisconnectError = StructuredError(
102
+ 'GithubDisconnectError',
103
+ 'Error disconnecting GitHub integration'
104
+ );
105
+
106
+ export async function disconnectGithubIntegration(
107
+ apiClient: APIClient,
108
+ orgId: string,
109
+ integrationId: string
110
+ ): Promise<GithubDisconnectResult> {
111
+ const resp = await apiClient.delete(
112
+ `/cli/github/disconnect?orgId=${encodeURIComponent(orgId)}&integrationId=${encodeURIComponent(integrationId)}`,
113
+ APIResponseSchema(GithubDisconnectDataSchema)
114
+ );
115
+
116
+ if (!resp.success) {
117
+ throw new GithubDisconnectError();
118
+ }
119
+
120
+ if (!resp.data) {
121
+ throw new GithubDisconnectError();
122
+ }
123
+
124
+ return { disconnected: resp.data.disconnected };
125
+ }
126
+
127
+ // Existing integrations
128
+
129
+ const GithubExistingIntegrationSchema = z.object({
130
+ id: z.string(),
131
+ integrationId: z.string().nullable(),
132
+ orgId: z.string(),
133
+ orgName: z.string(),
134
+ githubAccountName: z.string(),
135
+ });
136
+
137
+ const GithubExistingDataSchema = z.object({
138
+ integrations: z.array(GithubExistingIntegrationSchema),
139
+ });
140
+
141
+ export interface ExistingGithubIntegration {
142
+ id: string;
143
+ integrationId: string | null;
144
+ orgId: string;
145
+ orgName: string;
146
+ githubAccountName: string;
147
+ }
148
+
149
+ const GithubExistingError = StructuredError(
150
+ 'GithubExistingError',
151
+ 'Error fetching existing GitHub integrations'
152
+ );
153
+
154
+ export async function getExistingGithubIntegrations(
155
+ apiClient: APIClient,
156
+ excludeOrgId?: string
157
+ ): Promise<ExistingGithubIntegration[]> {
158
+ const query = excludeOrgId ? `?excludeOrgId=${encodeURIComponent(excludeOrgId)}` : '';
159
+ const resp = await apiClient.get(
160
+ `/cli/github/existing${query}`,
161
+ APIResponseSchema(GithubExistingDataSchema)
162
+ );
163
+
164
+ if (!resp.success || !resp.data) {
165
+ throw new GithubExistingError();
166
+ }
167
+
168
+ return resp.data.integrations;
169
+ }
170
+
171
+ // Copy integration
172
+
173
+ const GithubCopyDataSchema = z.object({
174
+ copied: z.boolean(),
175
+ });
176
+
177
+ const GithubCopyError = StructuredError('GithubCopyError', 'Error copying GitHub integration');
178
+
179
+ export async function copyGithubIntegration(
180
+ apiClient: APIClient,
181
+ fromOrgId: string,
182
+ toOrgId: string
183
+ ): Promise<boolean> {
184
+ const resp = await apiClient.post(
185
+ '/cli/github/copy',
186
+ { fromOrgId, toOrgId },
187
+ APIResponseSchema(GithubCopyDataSchema)
188
+ );
189
+
190
+ if (!resp.success || !resp.data) {
191
+ throw new GithubCopyError();
192
+ }
193
+
194
+ return resp.data.copied;
195
+ }
196
+
197
+ // Polling
198
+
199
+ const PollForGithubIntegrationError = StructuredError('PollForGithubIntegrationError');
200
+ const PollForGithubIntegrationTimeout = StructuredError(
201
+ 'PollForGithubIntegrationTimeout',
202
+ 'Timed out waiting for GitHub integration. Aborting.'
203
+ );
204
+
205
+ export async function pollForGithubIntegration(
206
+ apiClient: APIClient,
207
+ orgId: string,
208
+ initialCount: number,
209
+ timeoutMs = 600000 // 10 minutes
210
+ ): Promise<GithubIntegrationStatusResult> {
211
+ const started = Date.now();
212
+ let delay = 2000; // Start with 2 seconds
213
+ const maxDelay = 10000; // Cap at 10 seconds
214
+
215
+ while (Date.now() - started < timeoutMs) {
216
+ const resp = await apiClient.get(
217
+ `/cli/github/status?orgId=${encodeURIComponent(orgId)}`,
218
+ APIResponseSchema(GithubStatusDataSchema)
219
+ );
220
+
221
+ if (!resp.success || !resp.data) {
222
+ throw new PollForGithubIntegrationError();
223
+ }
224
+
225
+ const currentCount = resp.data.integrations?.length ?? 0;
226
+ if (currentCount > initialCount) {
227
+ return {
228
+ connected: true,
229
+ integrations: resp.data.integrations ?? [],
230
+ };
231
+ }
232
+
233
+ await Bun.sleep(delay);
234
+ delay = Math.min(delay * 1.5, maxDelay);
235
+ }
236
+
237
+ throw new PollForGithubIntegrationTimeout();
238
+ }
239
+
240
+ // Project linking
241
+
242
+ const GithubRepoSchema = z.object({
243
+ id: z.number(),
244
+ name: z.string(),
245
+ fullName: z.string(),
246
+ private: z.boolean(),
247
+ defaultBranch: z.string(),
248
+ integrationId: z.string(),
249
+ });
250
+
251
+ const GithubReposDataSchema = z.object({
252
+ repos: z.array(GithubRepoSchema),
253
+ });
254
+
255
+ export interface GithubRepo {
256
+ id: number;
257
+ name: string;
258
+ fullName: string;
259
+ private: boolean;
260
+ defaultBranch: string;
261
+ integrationId: string;
262
+ }
263
+
264
+ const GithubReposError = StructuredError('GithubReposError', 'Error fetching GitHub repositories');
265
+
266
+ export async function listGithubRepos(
267
+ apiClient: APIClient,
268
+ orgId: string,
269
+ integrationId?: string
270
+ ): Promise<GithubRepo[]> {
271
+ let url = `/cli/github/repos?orgId=${encodeURIComponent(orgId)}`;
272
+ if (integrationId) {
273
+ url += `&integrationId=${encodeURIComponent(integrationId)}`;
274
+ }
275
+ const resp = await apiClient.get(url, APIResponseSchema(GithubReposDataSchema));
276
+
277
+ if (!resp.success || !resp.data) {
278
+ throw new GithubReposError();
279
+ }
280
+
281
+ return resp.data.repos;
282
+ }
283
+
284
+ const ProjectLinkDataSchema = z.object({
285
+ linked: z.boolean(),
286
+ });
287
+
288
+ export interface LinkProjectOptions {
289
+ projectId: string;
290
+ repoFullName: string;
291
+ branch: string;
292
+ autoDeploy: boolean;
293
+ previewDeploy: boolean;
294
+ directory?: string;
295
+ integrationId?: string;
296
+ }
297
+
298
+ const ProjectLinkError = StructuredError('ProjectLinkError', 'Error linking project to repository');
299
+
300
+ export async function linkProjectToRepo(
301
+ apiClient: APIClient,
302
+ options: LinkProjectOptions
303
+ ): Promise<boolean> {
304
+ const resp = await apiClient.post(
305
+ '/cli/github/link',
306
+ options,
307
+ APIResponseSchema(ProjectLinkDataSchema)
308
+ );
309
+
310
+ if (!resp.success || !resp.data) {
311
+ throw new ProjectLinkError();
312
+ }
313
+
314
+ return resp.data.linked;
315
+ }
316
+
317
+ const ProjectUnlinkDataSchema = z.object({
318
+ unlinked: z.boolean(),
319
+ });
320
+
321
+ const ProjectUnlinkError = StructuredError(
322
+ 'ProjectUnlinkError',
323
+ 'Error unlinking project from repository'
324
+ );
325
+
326
+ export async function unlinkProjectFromRepo(
327
+ apiClient: APIClient,
328
+ projectId: string
329
+ ): Promise<boolean> {
330
+ const resp = await apiClient.delete(
331
+ `/cli/github/unlink?projectId=${encodeURIComponent(projectId)}`,
332
+ APIResponseSchema(ProjectUnlinkDataSchema)
333
+ );
334
+
335
+ if (!resp.success || !resp.data) {
336
+ throw new ProjectUnlinkError();
337
+ }
338
+
339
+ return resp.data.unlinked;
340
+ }
341
+
342
+ const ProjectGithubStatusSchema = z.object({
343
+ linked: z.boolean(),
344
+ repoFullName: z.string().optional(),
345
+ branch: z.string().optional(),
346
+ autoDeploy: z.boolean().optional(),
347
+ previewDeploy: z.boolean().optional(),
348
+ directory: z.string().optional(),
349
+ });
350
+
351
+ export interface ProjectGithubStatus {
352
+ linked: boolean;
353
+ repoFullName?: string;
354
+ branch?: string;
355
+ autoDeploy?: boolean;
356
+ previewDeploy?: boolean;
357
+ directory?: string;
358
+ }
359
+
360
+ const ProjectGithubStatusError = StructuredError(
361
+ 'ProjectGithubStatusError',
362
+ 'Error fetching project GitHub status'
363
+ );
364
+
365
+ export async function getProjectGithubStatus(
366
+ apiClient: APIClient,
367
+ projectId: string
368
+ ): Promise<ProjectGithubStatus> {
369
+ const resp = await apiClient.get(
370
+ `/cli/github/project-status?projectId=${encodeURIComponent(projectId)}`,
371
+ APIResponseSchema(ProjectGithubStatusSchema)
372
+ );
373
+
374
+ if (!resp.success || !resp.data) {
375
+ throw new ProjectGithubStatusError();
376
+ }
377
+
378
+ return resp.data;
379
+ }