@agentuity/cli 0.0.110 → 0.0.112

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 (258) hide show
  1. package/bin/cli.ts +4 -0
  2. package/dist/agents-docs.d.ts +5 -4
  3. package/dist/agents-docs.d.ts.map +1 -1
  4. package/dist/agents-docs.js +28 -8
  5. package/dist/agents-docs.js.map +1 -1
  6. package/dist/cli.d.ts.map +1 -1
  7. package/dist/cli.js +19 -4
  8. package/dist/cli.js.map +1 -1
  9. package/dist/cmd/auth/apikey.d.ts +2 -0
  10. package/dist/cmd/auth/apikey.d.ts.map +1 -0
  11. package/dist/cmd/auth/apikey.js +31 -0
  12. package/dist/cmd/auth/apikey.js.map +1 -0
  13. package/dist/cmd/auth/index.d.ts.map +1 -1
  14. package/dist/cmd/auth/index.js +9 -1
  15. package/dist/cmd/auth/index.js.map +1 -1
  16. package/dist/cmd/build/ast.d.ts.map +1 -1
  17. package/dist/cmd/build/ast.js +103 -2
  18. package/dist/cmd/build/ast.js.map +1 -1
  19. package/dist/cmd/build/entry-generator.d.ts +2 -1
  20. package/dist/cmd/build/entry-generator.d.ts.map +1 -1
  21. package/dist/cmd/build/entry-generator.js +152 -9
  22. package/dist/cmd/build/entry-generator.js.map +1 -1
  23. package/dist/cmd/build/vite/agent-discovery.d.ts +1 -1
  24. package/dist/cmd/build/vite/agent-discovery.d.ts.map +1 -1
  25. package/dist/cmd/build/vite/agent-discovery.js +7 -6
  26. package/dist/cmd/build/vite/agent-discovery.js.map +1 -1
  27. package/dist/cmd/build/vite/index.d.ts.map +1 -1
  28. package/dist/cmd/build/vite/index.js +3 -2
  29. package/dist/cmd/build/vite/index.js.map +1 -1
  30. package/dist/cmd/build/vite/metadata-generator.js +1 -1
  31. package/dist/cmd/build/vite/metadata-generator.js.map +1 -1
  32. package/dist/cmd/build/vite/registry-generator.d.ts +1 -1
  33. package/dist/cmd/build/vite/registry-generator.d.ts.map +1 -1
  34. package/dist/cmd/build/vite/registry-generator.js +115 -23
  35. package/dist/cmd/build/vite/registry-generator.js.map +1 -1
  36. package/dist/cmd/build/vite/route-discovery.d.ts +6 -0
  37. package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -1
  38. package/dist/cmd/build/vite/route-discovery.js +19 -0
  39. package/dist/cmd/build/vite/route-discovery.js.map +1 -1
  40. package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
  41. package/dist/cmd/build/vite/vite-builder.js +3 -2
  42. package/dist/cmd/build/vite/vite-builder.js.map +1 -1
  43. package/dist/cmd/cloud/deploy-fork.d.ts +32 -0
  44. package/dist/cmd/cloud/deploy-fork.d.ts.map +1 -0
  45. package/dist/cmd/cloud/deploy-fork.js +258 -0
  46. package/dist/cmd/cloud/deploy-fork.js.map +1 -0
  47. package/dist/cmd/cloud/deploy.d.ts.map +1 -1
  48. package/dist/cmd/cloud/deploy.js +125 -4
  49. package/dist/cmd/cloud/deploy.js.map +1 -1
  50. package/dist/cmd/cloud/sandbox/create.d.ts.map +1 -1
  51. package/dist/cmd/cloud/sandbox/create.js +18 -0
  52. package/dist/cmd/cloud/sandbox/create.js.map +1 -1
  53. package/dist/cmd/cloud/sandbox/delete.d.ts.map +1 -1
  54. package/dist/cmd/cloud/sandbox/delete.js +2 -6
  55. package/dist/cmd/cloud/sandbox/delete.js.map +1 -1
  56. package/dist/cmd/cloud/sandbox/download.d.ts +3 -0
  57. package/dist/cmd/cloud/sandbox/download.d.ts.map +1 -0
  58. package/dist/cmd/cloud/sandbox/download.js +89 -0
  59. package/dist/cmd/cloud/sandbox/download.js.map +1 -0
  60. package/dist/cmd/cloud/sandbox/env.d.ts +3 -0
  61. package/dist/cmd/cloud/sandbox/env.d.ts.map +1 -0
  62. package/dist/cmd/cloud/sandbox/env.js +90 -0
  63. package/dist/cmd/cloud/sandbox/env.js.map +1 -0
  64. package/dist/cmd/cloud/sandbox/get.d.ts.map +1 -1
  65. package/dist/cmd/cloud/sandbox/get.js +24 -0
  66. package/dist/cmd/cloud/sandbox/get.js.map +1 -1
  67. package/dist/cmd/cloud/sandbox/index.d.ts.map +1 -1
  68. package/dist/cmd/cloud/sandbox/index.js +14 -0
  69. package/dist/cmd/cloud/sandbox/index.js.map +1 -1
  70. package/dist/cmd/cloud/sandbox/ls.d.ts +3 -0
  71. package/dist/cmd/cloud/sandbox/ls.d.ts.map +1 -0
  72. package/dist/cmd/cloud/sandbox/ls.js +119 -0
  73. package/dist/cmd/cloud/sandbox/ls.js.map +1 -0
  74. package/dist/cmd/cloud/sandbox/mkdir.d.ts +3 -0
  75. package/dist/cmd/cloud/sandbox/mkdir.d.ts.map +1 -0
  76. package/dist/cmd/cloud/sandbox/mkdir.js +59 -0
  77. package/dist/cmd/cloud/sandbox/mkdir.js.map +1 -0
  78. package/dist/cmd/cloud/sandbox/rm.d.ts +3 -0
  79. package/dist/cmd/cloud/sandbox/rm.d.ts.map +1 -0
  80. package/dist/cmd/cloud/sandbox/rm.js +45 -0
  81. package/dist/cmd/cloud/sandbox/rm.js.map +1 -0
  82. package/dist/cmd/cloud/sandbox/rmdir.d.ts +3 -0
  83. package/dist/cmd/cloud/sandbox/rmdir.d.ts.map +1 -0
  84. package/dist/cmd/cloud/sandbox/rmdir.js +59 -0
  85. package/dist/cmd/cloud/sandbox/rmdir.js.map +1 -0
  86. package/dist/cmd/cloud/sandbox/snapshot/create.d.ts.map +1 -1
  87. package/dist/cmd/cloud/sandbox/snapshot/create.js +0 -2
  88. package/dist/cmd/cloud/sandbox/snapshot/create.js.map +1 -1
  89. package/dist/cmd/cloud/sandbox/snapshot/get.d.ts.map +1 -1
  90. package/dist/cmd/cloud/sandbox/snapshot/get.js +0 -2
  91. package/dist/cmd/cloud/sandbox/snapshot/get.js.map +1 -1
  92. package/dist/cmd/cloud/sandbox/snapshot/list.d.ts.map +1 -1
  93. package/dist/cmd/cloud/sandbox/snapshot/list.js +0 -3
  94. package/dist/cmd/cloud/sandbox/snapshot/list.js.map +1 -1
  95. package/dist/cmd/cloud/sandbox/upload.d.ts +3 -0
  96. package/dist/cmd/cloud/sandbox/upload.d.ts.map +1 -0
  97. package/dist/cmd/cloud/sandbox/upload.js +77 -0
  98. package/dist/cmd/cloud/sandbox/upload.js.map +1 -0
  99. package/dist/cmd/cloud/ssh.d.ts.map +1 -1
  100. package/dist/cmd/cloud/ssh.js +9 -3
  101. package/dist/cmd/cloud/ssh.js.map +1 -1
  102. package/dist/cmd/dev/index.d.ts.map +1 -1
  103. package/dist/cmd/dev/index.js +34 -19
  104. package/dist/cmd/dev/index.js.map +1 -1
  105. package/dist/cmd/dev/sync.d.ts.map +1 -1
  106. package/dist/cmd/dev/sync.js +8 -14
  107. package/dist/cmd/dev/sync.js.map +1 -1
  108. package/dist/cmd/git/account/add.d.ts +17 -0
  109. package/dist/cmd/git/account/add.d.ts.map +1 -0
  110. package/dist/cmd/git/account/add.js +244 -0
  111. package/dist/cmd/git/account/add.js.map +1 -0
  112. package/dist/cmd/git/account/index.d.ts +3 -0
  113. package/dist/cmd/git/account/index.d.ts.map +1 -0
  114. package/dist/cmd/git/account/index.js +11 -0
  115. package/dist/cmd/git/account/index.js.map +1 -0
  116. package/dist/cmd/git/account/list.d.ts +2 -0
  117. package/dist/cmd/git/account/list.d.ts.map +1 -0
  118. package/dist/cmd/git/account/list.js +111 -0
  119. package/dist/cmd/git/account/list.js.map +1 -0
  120. package/dist/cmd/git/account/remove.d.ts +2 -0
  121. package/dist/cmd/git/account/remove.d.ts.map +1 -0
  122. package/dist/cmd/git/account/remove.js +171 -0
  123. package/dist/cmd/git/account/remove.js.map +1 -0
  124. package/dist/cmd/git/index.d.ts +3 -0
  125. package/dist/cmd/git/index.d.ts.map +1 -0
  126. package/dist/cmd/git/index.js +19 -0
  127. package/dist/cmd/git/index.js.map +1 -0
  128. package/dist/cmd/git/link.d.ts +32 -0
  129. package/dist/cmd/git/link.d.ts.map +1 -0
  130. package/dist/cmd/git/link.js +357 -0
  131. package/dist/cmd/git/link.js.map +1 -0
  132. package/dist/cmd/git/list.d.ts +2 -0
  133. package/dist/cmd/git/list.d.ts.map +1 -0
  134. package/dist/cmd/git/list.js +137 -0
  135. package/dist/cmd/git/list.js.map +1 -0
  136. package/dist/cmd/git/status.d.ts +2 -0
  137. package/dist/cmd/git/status.d.ts.map +1 -0
  138. package/dist/cmd/git/status.js +119 -0
  139. package/dist/cmd/git/status.js.map +1 -0
  140. package/dist/cmd/git/unlink.d.ts +2 -0
  141. package/dist/cmd/git/unlink.d.ts.map +1 -0
  142. package/dist/cmd/git/unlink.js +98 -0
  143. package/dist/cmd/git/unlink.js.map +1 -0
  144. package/dist/cmd/index.d.ts.map +1 -1
  145. package/dist/cmd/index.js +2 -0
  146. package/dist/cmd/index.js.map +1 -1
  147. package/dist/cmd/integration/api.d.ts +61 -0
  148. package/dist/cmd/integration/api.d.ts.map +1 -0
  149. package/dist/cmd/integration/api.js +176 -0
  150. package/dist/cmd/integration/api.js.map +1 -0
  151. package/dist/cmd/integration/github/connect.d.ts +2 -0
  152. package/dist/cmd/integration/github/connect.d.ts.map +1 -0
  153. package/dist/cmd/integration/github/connect.js +197 -0
  154. package/dist/cmd/integration/github/connect.js.map +1 -0
  155. package/dist/cmd/integration/github/disconnect.d.ts +2 -0
  156. package/dist/cmd/integration/github/disconnect.d.ts.map +1 -0
  157. package/dist/cmd/integration/github/disconnect.js +121 -0
  158. package/dist/cmd/integration/github/disconnect.js.map +1 -0
  159. package/dist/cmd/integration/github/index.d.ts +2 -0
  160. package/dist/cmd/integration/github/index.d.ts.map +1 -0
  161. package/dist/cmd/integration/github/index.js +21 -0
  162. package/dist/cmd/integration/github/index.js.map +1 -0
  163. package/dist/cmd/integration/index.d.ts +2 -0
  164. package/dist/cmd/integration/index.d.ts.map +1 -0
  165. package/dist/cmd/integration/index.js +16 -0
  166. package/dist/cmd/integration/index.js.map +1 -0
  167. package/dist/config.d.ts +2 -0
  168. package/dist/config.d.ts.map +1 -1
  169. package/dist/config.js +25 -1
  170. package/dist/config.js.map +1 -1
  171. package/dist/errors.d.ts +2 -1
  172. package/dist/errors.d.ts.map +1 -1
  173. package/dist/errors.js +5 -0
  174. package/dist/errors.js.map +1 -1
  175. package/dist/log-collector.d.ts +30 -0
  176. package/dist/log-collector.d.ts.map +1 -0
  177. package/dist/log-collector.js +74 -0
  178. package/dist/log-collector.js.map +1 -0
  179. package/dist/output.d.ts.map +1 -1
  180. package/dist/output.js +2 -1
  181. package/dist/output.js.map +1 -1
  182. package/dist/steps.d.ts.map +1 -1
  183. package/dist/steps.js +48 -3
  184. package/dist/steps.js.map +1 -1
  185. package/dist/tui/box.d.ts.map +1 -1
  186. package/dist/tui/box.js +1 -6
  187. package/dist/tui/box.js.map +1 -1
  188. package/dist/tui/symbols.d.ts.map +1 -1
  189. package/dist/tui/symbols.js +4 -0
  190. package/dist/tui/symbols.js.map +1 -1
  191. package/dist/tui.d.ts +21 -12
  192. package/dist/tui.d.ts.map +1 -1
  193. package/dist/tui.js +74 -25
  194. package/dist/tui.js.map +1 -1
  195. package/dist/types.d.ts +73 -1
  196. package/dist/types.d.ts.map +1 -1
  197. package/dist/types.js +4 -0
  198. package/dist/types.js.map +1 -1
  199. package/dist/typescript-errors.d.ts.map +1 -1
  200. package/dist/typescript-errors.js +2 -2
  201. package/dist/typescript-errors.js.map +1 -1
  202. package/package.json +6 -6
  203. package/src/agents-docs.ts +42 -8
  204. package/src/cli.ts +20 -4
  205. package/src/cmd/auth/apikey.ts +36 -0
  206. package/src/cmd/auth/index.ts +9 -1
  207. package/src/cmd/build/ast.ts +120 -2
  208. package/src/cmd/build/entry-generator.ts +157 -10
  209. package/src/cmd/build/vite/agent-discovery.ts +8 -5
  210. package/src/cmd/build/vite/index.ts +3 -2
  211. package/src/cmd/build/vite/metadata-generator.ts +1 -1
  212. package/src/cmd/build/vite/registry-generator.ts +125 -24
  213. package/src/cmd/build/vite/route-discovery.ts +20 -0
  214. package/src/cmd/build/vite/vite-builder.ts +3 -2
  215. package/src/cmd/cloud/deploy-fork.ts +296 -0
  216. package/src/cmd/cloud/deploy.ts +148 -4
  217. package/src/cmd/cloud/sandbox/create.ts +22 -0
  218. package/src/cmd/cloud/sandbox/delete.ts +2 -6
  219. package/src/cmd/cloud/sandbox/download.ts +96 -0
  220. package/src/cmd/cloud/sandbox/env.ts +104 -0
  221. package/src/cmd/cloud/sandbox/get.ts +22 -0
  222. package/src/cmd/cloud/sandbox/index.ts +14 -0
  223. package/src/cmd/cloud/sandbox/ls.ts +126 -0
  224. package/src/cmd/cloud/sandbox/mkdir.ts +65 -0
  225. package/src/cmd/cloud/sandbox/rm.ts +51 -0
  226. package/src/cmd/cloud/sandbox/rmdir.ts +65 -0
  227. package/src/cmd/cloud/sandbox/snapshot/create.ts +0 -2
  228. package/src/cmd/cloud/sandbox/snapshot/get.ts +0 -2
  229. package/src/cmd/cloud/sandbox/snapshot/list.ts +0 -3
  230. package/src/cmd/cloud/sandbox/upload.ts +83 -0
  231. package/src/cmd/cloud/ssh.ts +13 -3
  232. package/src/cmd/dev/index.ts +49 -31
  233. package/src/cmd/dev/sync.ts +26 -30
  234. package/src/cmd/git/account/add.ts +317 -0
  235. package/src/cmd/git/account/index.ts +12 -0
  236. package/src/cmd/git/account/list.ts +139 -0
  237. package/src/cmd/git/account/remove.ts +212 -0
  238. package/src/cmd/git/index.ts +20 -0
  239. package/src/cmd/git/link.ts +468 -0
  240. package/src/cmd/git/list.ts +161 -0
  241. package/src/cmd/git/status.ts +144 -0
  242. package/src/cmd/git/unlink.ts +117 -0
  243. package/src/cmd/index.ts +2 -0
  244. package/src/cmd/integration/api.ts +379 -0
  245. package/src/cmd/integration/github/connect.ts +242 -0
  246. package/src/cmd/integration/github/disconnect.ts +149 -0
  247. package/src/cmd/integration/github/index.ts +21 -0
  248. package/src/cmd/integration/index.ts +16 -0
  249. package/src/config.ts +35 -1
  250. package/src/errors.ts +7 -0
  251. package/src/log-collector.ts +77 -0
  252. package/src/output.ts +2 -1
  253. package/src/steps.ts +52 -4
  254. package/src/tui/box.ts +1 -7
  255. package/src/tui/symbols.ts +5 -0
  256. package/src/tui.ts +77 -25
  257. package/src/types.ts +89 -0
  258. package/src/typescript-errors.ts +2 -1
@@ -680,7 +680,34 @@ export const command = createCommand({
680
680
  );
681
681
  }
682
682
 
683
- // Step 2: Generate entry file with workbench config
683
+ // Step 2: Discover agents and routes for registry generation
684
+ const srcDir = join(rootDir, 'src');
685
+ const { discoverAgents } = await import('../build/vite/agent-discovery');
686
+ const { discoverRoutes } = await import('../build/vite/route-discovery');
687
+ const { generateAgentRegistry, generateRouteRegistry } = await import(
688
+ '../build/vite/registry-generator'
689
+ );
690
+
691
+ const agentMetadata = await discoverAgents(
692
+ srcDir,
693
+ project?.projectId ?? '',
694
+ deploymentId,
695
+ logger
696
+ );
697
+ const { routes, routeInfoList } = await discoverRoutes(
698
+ srcDir,
699
+ project?.projectId ?? '',
700
+ deploymentId,
701
+ logger
702
+ );
703
+
704
+ // Generate agent and route registries for type augmentation
705
+ // (TypeScript needs these files to exist for proper type inference)
706
+ generateAgentRegistry(srcDir, agentMetadata);
707
+ generateRouteRegistry(srcDir, routeInfoList);
708
+ logger.debug('Agent and route registries generated for dev mode');
709
+
710
+ // Step 3: Generate entry file with workbench and analytics config
684
711
  // Note: vitePort is NOT passed here - the app reads process.env.VITE_PORT at runtime
685
712
  const { generateEntryFile } = await import('../build/entry-generator');
686
713
  await generateEntryFile({
@@ -690,9 +717,10 @@ export const command = createCommand({
690
717
  logger,
691
718
  mode: 'dev',
692
719
  workbench: workbenchConfigData.enabled ? workbenchConfigData : undefined,
720
+ analytics: agentuityConfig?.analytics,
693
721
  });
694
722
 
695
- // Step 3: Bundle the app with LLM patches (dev mode = no minification)
723
+ // Step 4: Bundle the app with LLM patches (dev mode = no minification)
696
724
  // This produces .agentuity/app.js with AI Gateway routing patches applied
697
725
  const { installExternalsAndBuild } = await import(
698
726
  '../build/vite/server-bundler'
@@ -704,14 +732,11 @@ export const command = createCommand({
704
732
  });
705
733
 
706
734
  // Generate metadata file (needed for eval ID lookup at runtime)
707
- const { discoverAgents } = await import('../build/vite/agent-discovery');
708
- const { discoverRoutes } = await import('../build/vite/route-discovery');
735
+ // Reuse agentMetadata and routes from Step 2
709
736
  const { generateMetadata, writeMetadataFile } = await import(
710
737
  '../build/vite/metadata-generator'
711
738
  );
712
739
 
713
- const srcDir = join(rootDir, 'src');
714
-
715
740
  const promises: Promise<void>[] = [];
716
741
 
717
742
  // Generate/update prompt files (non-blocking)
@@ -722,25 +747,13 @@ export const command = createCommand({
722
747
  logger.warn('Failed to generate prompt files: %s', err.message)
723
748
  )
724
749
  );
725
- const agents = await discoverAgents(
726
- srcDir,
727
- project?.projectId ?? '',
728
- deploymentId,
729
- logger
730
- );
731
- const { routes } = await discoverRoutes(
732
- srcDir,
733
- project?.projectId ?? '',
734
- deploymentId,
735
- logger
736
- );
737
750
 
738
751
  const metadata = await generateMetadata({
739
752
  rootDir,
740
753
  projectId: project?.projectId ?? '',
741
754
  orgId: project?.orgId ?? '',
742
755
  deploymentId,
743
- agents,
756
+ agents: agentMetadata,
744
757
  routes,
745
758
  dev: true,
746
759
  logger,
@@ -771,19 +784,24 @@ export const command = createCommand({
771
784
  console.log('');
772
785
  fileWatcher.resume();
773
786
  // wait for a file change or shutdown to trigger a recompile
774
- while (true) {
775
- if (shutdownRequested) {
776
- return;
777
- }
778
- if (shouldRestart) {
779
- break;
780
- }
787
+ while (!shutdownRequested && !shouldRestart) {
781
788
  await tui.spinner({
782
789
  message: 'Waiting for changes...',
783
790
  clearOnSuccess: true,
784
- callback: () => Bun.sleep(1000),
791
+ callback: async () => {
792
+ // Check more frequently so CTRL+C is responsive
793
+ for (let i = 0; i < 10; i++) {
794
+ if (shutdownRequested || shouldRestart) {
795
+ return;
796
+ }
797
+ await Bun.sleep(100);
798
+ }
799
+ },
785
800
  });
786
801
  }
802
+ if (shutdownRequested) {
803
+ return;
804
+ }
787
805
  }
788
806
  } catch (error) {
789
807
  tui.error(`Failed to build dev bundle: ${error}`);
@@ -805,10 +823,6 @@ export const command = createCommand({
805
823
  }
806
824
 
807
825
  try {
808
- // Set environment variables for LLM provider patches BEFORE starting server
809
- // These must be set so the bundled patches can route LLM calls through AI Gateway
810
- const serviceUrls = getServiceUrls(project?.region);
811
-
812
826
  // Load SDK key from project .env files for AI Gateway routing
813
827
  // This must be set so the bundled AI SDK patches can inject the API key
814
828
  if (!process.env.AGENTUITY_SDK_KEY) {
@@ -836,6 +850,9 @@ export const command = createCommand({
836
850
  process.env.AGENTUITY_PORT = process.env.PORT;
837
851
 
838
852
  if (project) {
853
+ // Set environment variables for LLM provider patches
854
+ // These must be set so the bundled patches can route LLM calls through AI Gateway
855
+ const serviceUrls = getServiceUrls(project.region);
839
856
  process.env.AGENTUITY_TRANSPORT_URL = serviceUrls.catalyst;
840
857
  process.env.AGENTUITY_CATALYST_URL = serviceUrls.catalyst;
841
858
  process.env.AGENTUITY_VECTOR_URL = serviceUrls.vector;
@@ -844,6 +861,7 @@ export const command = createCommand({
844
861
  process.env.AGENTUITY_STREAM_URL = serviceUrls.stream;
845
862
  process.env.AGENTUITY_CLOUD_ORG_ID = project.orgId;
846
863
  process.env.AGENTUITY_CLOUD_PROJECT_ID = project.projectId;
864
+ process.env.AGENTUITY_CLOUD_DEPLOYMENT_ID = deploymentId;
847
865
  }
848
866
 
849
867
  // Set Vite port for asset proxying in bundled app
@@ -15,7 +15,7 @@ interface AgentSyncPayload {
15
15
  interface EvalSyncPayload {
16
16
  id: string;
17
17
  name: string;
18
- evalId: string;
18
+ identifier: string;
19
19
  description?: string;
20
20
  version: string;
21
21
  filename: string;
@@ -100,7 +100,7 @@ function getEvalsToSync(
100
100
 
101
101
  evalsToCreate.push({
102
102
  ...evalItem,
103
- evalId: evalItem.evalId,
103
+ identifier: evalItem.identifier,
104
104
  projectId,
105
105
  agentIdentifier: agent.agentId,
106
106
  });
@@ -133,18 +133,28 @@ class DevmodeSyncService implements IDevmodeSyncService {
133
133
  projectId: string,
134
134
  deploymentId: string
135
135
  ): Promise<void> {
136
+ this.logger.debug(
137
+ '[CLI SYNC] sync() called with projectId=%s, deploymentId=%s',
138
+ projectId,
139
+ deploymentId
140
+ );
141
+ this.logger.debug(
142
+ '[CLI SYNC] currentMetadata has %d agents',
143
+ currentMetadata.agents?.length ?? 0
144
+ );
145
+
136
146
  // Build previous agent IDs set
137
147
  const previousAgentIds = new Set<string>();
138
148
  if (previousMetadata) {
139
149
  this.logger.debug(
140
- 'Previous metadata found with %d agent(s)',
150
+ '[CLI SYNC] Previous metadata found with %d agent(s)',
141
151
  previousMetadata.agents?.length ?? 0
142
152
  );
143
153
  for (const agent of previousMetadata.agents || []) {
144
154
  previousAgentIds.add(agent.id);
145
155
  }
146
156
  } else {
147
- this.logger.debug('No previous metadata, all agents will be treated as new');
157
+ this.logger.debug('[CLI SYNC] No previous metadata, all agents will be treated as new');
148
158
  }
149
159
 
150
160
  // Build previous eval IDs set
@@ -178,9 +188,10 @@ class DevmodeSyncService implements IDevmodeSyncService {
178
188
  );
179
189
  for (const evalItem of agent.evals) {
180
190
  this.logger.debug(
181
- '[CLI EVAL SYNC] - %s (evalId: %s)',
191
+ '[CLI EVAL SYNC] - %s (id: %s, identifier: %s)',
182
192
  evalItem.name,
183
- evalItem.evalId
193
+ evalItem.id,
194
+ evalItem.identifier
184
195
  );
185
196
  }
186
197
  }
@@ -208,13 +219,11 @@ class DevmodeSyncService implements IDevmodeSyncService {
208
219
  agentsToDelete.length
209
220
  );
210
221
  }
211
- if (evalsToCreate.length > 0 || evalsToDelete.length > 0) {
212
- this.logger.debug(
213
- 'Bulk syncing %d eval(s) to create, %d eval(s) to delete',
214
- evalsToCreate.length,
215
- evalsToDelete.length
216
- );
217
- }
222
+ this.logger.debug(
223
+ '[CLI EVAL SYNC] Evals to sync: %d to create, %d to delete',
224
+ evalsToCreate.length,
225
+ evalsToDelete.length
226
+ );
218
227
 
219
228
  // Sync both in parallel
220
229
  try {
@@ -273,14 +282,7 @@ class DevmodeSyncService implements IDevmodeSyncService {
273
282
  evalsToDelete: string[],
274
283
  deploymentId: string
275
284
  ): Promise<void> {
276
- this.logger.debug(
277
- '[CLI EVAL SYNC] syncEvals called: %d to create, %d to delete',
278
- evals.length,
279
- evalsToDelete.length
280
- );
281
-
282
285
  if (evals.length === 0 && evalsToDelete.length === 0) {
283
- this.logger.debug('[CLI EVAL SYNC] No evals to sync, skipping');
284
286
  return;
285
287
  }
286
288
 
@@ -290,15 +292,10 @@ class DevmodeSyncService implements IDevmodeSyncService {
290
292
  delete: evalsToDelete,
291
293
  };
292
294
 
293
- this.logger.debug('[CLI EVAL SYNC] Sending payload to POST /cli/devmode/eval:');
294
- for (const evalItem of evals) {
295
- this.logger.debug(
296
- '[CLI EVAL SYNC] - %s (id: %s, evalId: %s)',
297
- evalItem.name,
298
- evalItem.id,
299
- evalItem.evalId
300
- );
301
- }
295
+ this.logger.debug(
296
+ '[CLI EVAL SYNC] Sending payload to POST /cli/devmode/eval: %s',
297
+ JSON.stringify(payload, null, 2)
298
+ );
302
299
 
303
300
  try {
304
301
  await this.apiClient.post(
@@ -306,7 +303,6 @@ class DevmodeSyncService implements IDevmodeSyncService {
306
303
  payload,
307
304
  z.object({ success: z.boolean() })
308
305
  );
309
- this.logger.debug('[CLI EVAL SYNC] Sync successful');
310
306
  } catch (error) {
311
307
  this.logger.error('[CLI EVAL SYNC] Sync failed: %s', error);
312
308
  throw error;
@@ -0,0 +1,317 @@
1
+ import { createSubcommand } from '../../../types';
2
+ import type { Config } from '../../../types';
3
+ import * as tui from '../../../tui';
4
+ import { getCommand } from '../../../command-prefix';
5
+ import { getAPIBaseURL } from '../../../api';
6
+ import type { APIClient } from '../../../api';
7
+ import { ErrorCode } from '../../../errors';
8
+ import { listOrganizations } from '@agentuity/server';
9
+ import enquirer from 'enquirer';
10
+ import type { Logger } from '@agentuity/core';
11
+ import { z } from 'zod';
12
+ import {
13
+ startGithubIntegration,
14
+ pollForGithubIntegration,
15
+ getGithubIntegrationStatus,
16
+ getExistingGithubIntegrations,
17
+ copyGithubIntegration,
18
+ } from '../../integration/api';
19
+
20
+ export interface RunGitAccountConnectOptions {
21
+ apiClient: APIClient;
22
+ orgId: string;
23
+ orgName?: string;
24
+ logger: Logger;
25
+ config?: Config | null;
26
+ }
27
+
28
+ export interface RunGitAccountConnectResult {
29
+ connected: boolean;
30
+ cancelled?: boolean;
31
+ }
32
+
33
+ export async function runGitAccountConnect(
34
+ options: RunGitAccountConnectOptions
35
+ ): Promise<RunGitAccountConnectResult> {
36
+ const { apiClient, orgId, orgName, logger, config } = options;
37
+ const orgDisplay = orgName ?? orgId;
38
+
39
+ try {
40
+ const currentStatus = await getGithubIntegrationStatus(apiClient, orgId);
41
+ const initialCount = currentStatus.integrations?.length ?? 0;
42
+
43
+ const existingIntegrations = await tui.spinner({
44
+ message: 'Checking for existing GitHub connections...',
45
+ clearOnSuccess: true,
46
+ callback: () => getExistingGithubIntegrations(apiClient, orgId),
47
+ });
48
+
49
+ const alreadyConnectedNames = new Set(
50
+ currentStatus.integrations?.map((i) => i.githubAccountName) ?? []
51
+ );
52
+ const availableIntegrations = existingIntegrations.filter(
53
+ (i) => !alreadyConnectedNames.has(i.githubAccountName)
54
+ );
55
+
56
+ if (availableIntegrations.length > 0) {
57
+ tui.newline();
58
+
59
+ const integrationChoices = availableIntegrations.map((i) => ({
60
+ name: i.id,
61
+ message: `${i.githubAccountName} ${tui.muted(`(from ${i.orgName})`)}`,
62
+ }));
63
+
64
+ console.log(tui.muted('Press enter with none selected to add a new account'));
65
+ tui.newline();
66
+
67
+ const selectResponse = await enquirer.prompt<{ integrationIds: string[] }>({
68
+ type: 'multiselect',
69
+ name: 'integrationIds',
70
+ message: 'Select GitHub accounts to add',
71
+ choices: integrationChoices,
72
+ });
73
+
74
+ if (selectResponse.integrationIds.length > 0) {
75
+ const selectedIntegrations = availableIntegrations.filter((i) =>
76
+ selectResponse.integrationIds.includes(i.id)
77
+ );
78
+
79
+ const accountNames = selectedIntegrations.map((i) => i.githubAccountName).join(', ');
80
+
81
+ const confirmResponse = await enquirer.prompt<{ confirm: boolean }>({
82
+ type: 'confirm',
83
+ name: 'confirm',
84
+ message: `Add ${tui.bold(accountNames)} to ${tui.bold(orgDisplay)}?`,
85
+ initial: true,
86
+ });
87
+
88
+ if (confirmResponse.confirm) {
89
+ await tui.spinner({
90
+ message: `Adding ${selectedIntegrations.length} GitHub account${selectedIntegrations.length > 1 ? 's' : ''}...`,
91
+ clearOnSuccess: true,
92
+ callback: async () => {
93
+ for (const integration of selectedIntegrations) {
94
+ await copyGithubIntegration(apiClient, integration.orgId, orgId);
95
+ }
96
+ },
97
+ });
98
+
99
+ tui.newline();
100
+ tui.success(
101
+ `Added GitHub account${selectedIntegrations.length > 1 ? 's' : ''} to ${tui.bold(orgDisplay)}`
102
+ );
103
+ return { connected: true };
104
+ }
105
+ }
106
+ }
107
+
108
+ const startResult = await tui.spinner({
109
+ message: 'Getting GitHub authorization URL...',
110
+ clearOnSuccess: true,
111
+ callback: () => startGithubIntegration(apiClient, orgId),
112
+ });
113
+
114
+ if (!startResult) {
115
+ tui.error('Failed to start GitHub authorization');
116
+ return { connected: false };
117
+ }
118
+
119
+ const { shortId } = startResult;
120
+ const apiBaseUrl = getAPIBaseURL(config);
121
+ const url = `${apiBaseUrl}/github/connect/${shortId}`;
122
+
123
+ const copied = await tui.copyToClipboard(url);
124
+
125
+ tui.newline();
126
+ if (copied) {
127
+ console.log('GitHub authorization URL copied to clipboard! Open it in your browser:');
128
+ } else {
129
+ console.log('Open this URL in your browser to authorize GitHub access:');
130
+ }
131
+ tui.newline();
132
+ console.log(` ${tui.link(url)}`);
133
+ tui.newline();
134
+ console.log(tui.muted('Press Enter to open in your browser, or Ctrl+C to cancel'));
135
+ tui.newline();
136
+
137
+ const result = await tui.spinner({
138
+ type: 'countdown',
139
+ message: 'Waiting for GitHub authorization',
140
+ timeoutMs: 600000,
141
+ clearOnSuccess: true,
142
+ onEnterPress: () => {
143
+ const platform = process.platform;
144
+ if (platform === 'win32') {
145
+ Bun.spawn(['cmd', '/c', 'start', '', url], {
146
+ stdout: 'ignore',
147
+ stderr: 'ignore',
148
+ });
149
+ } else {
150
+ const command = platform === 'darwin' ? 'open' : 'xdg-open';
151
+ Bun.spawn([command, url], { stdout: 'ignore', stderr: 'ignore' });
152
+ }
153
+ },
154
+ callback: async () => {
155
+ return await pollForGithubIntegration(apiClient, orgId, initialCount);
156
+ },
157
+ });
158
+
159
+ tui.newline();
160
+ if (result.connected) {
161
+ tui.success(`GitHub account added to ${tui.bold(orgDisplay)}`);
162
+ return { connected: true };
163
+ }
164
+
165
+ return { connected: false };
166
+ } catch (error) {
167
+ const isCancel =
168
+ error === '' ||
169
+ (error instanceof Error && (error.message === '' || error.message === 'User cancelled'));
170
+
171
+ if (isCancel) {
172
+ tui.newline();
173
+ tui.info('Cancelled');
174
+ return { connected: false, cancelled: true };
175
+ }
176
+
177
+ logger.trace(error);
178
+ throw error;
179
+ }
180
+ }
181
+
182
+ const AddOptionsSchema = z.object({
183
+ org: z.string().optional().describe('Organization ID to add the account to'),
184
+ });
185
+
186
+ const AddResponseSchema = z.object({
187
+ connected: z.boolean().describe('Whether the account was connected'),
188
+ orgId: z.string().optional().describe('Organization ID'),
189
+ });
190
+
191
+ export const addSubcommand = createSubcommand({
192
+ name: 'add',
193
+ description: 'Add a GitHub account to your organization',
194
+ tags: ['mutating', 'creates-resource', 'slow', 'api-intensive'],
195
+ idempotent: false,
196
+ requires: { auth: true, apiClient: true },
197
+ schema: {
198
+ options: AddOptionsSchema,
199
+ response: AddResponseSchema,
200
+ },
201
+ examples: [
202
+ {
203
+ command: getCommand('git account add'),
204
+ description: 'Add a GitHub account to your organization',
205
+ },
206
+ {
207
+ command: getCommand('git account add --org org_abc123'),
208
+ description: 'Add to a specific organization',
209
+ },
210
+ ],
211
+
212
+ async handler(ctx) {
213
+ const { logger, apiClient, config, opts } = ctx;
214
+
215
+ try {
216
+ const orgs = await tui.spinner({
217
+ message: 'Fetching organizations...',
218
+ clearOnSuccess: true,
219
+ callback: () => listOrganizations(apiClient),
220
+ });
221
+
222
+ if (orgs.length === 0) {
223
+ tui.fatal('No organizations found for your account');
224
+ }
225
+
226
+ let orgId = opts.org;
227
+ let selectedOrg: (typeof orgs)[0] | undefined;
228
+
229
+ if (orgId) {
230
+ selectedOrg = orgs.find((o) => o.id === orgId);
231
+ if (!selectedOrg) {
232
+ tui.fatal(`Organization ${orgId} not found`);
233
+ }
234
+ } else {
235
+ const orgStatuses = await tui.spinner({
236
+ message: 'Checking GitHub integration status...',
237
+ clearOnSuccess: true,
238
+ callback: async () => {
239
+ const statuses = await Promise.all(
240
+ orgs.map(async (org) => {
241
+ const status = await getGithubIntegrationStatus(apiClient, org.id);
242
+ return {
243
+ ...org,
244
+ connected: status.connected,
245
+ integrations: status.integrations,
246
+ };
247
+ })
248
+ );
249
+ return statuses;
250
+ },
251
+ });
252
+
253
+ const sortedOrgs = [...orgStatuses].sort((a, b) => a.name.localeCompare(b.name));
254
+
255
+ if (orgs.length === 1) {
256
+ orgId = orgs[0].id;
257
+ selectedOrg = orgs[0];
258
+ } else {
259
+ const choices = sortedOrgs.map((org) => {
260
+ const count = org.integrations.length;
261
+ const suffix =
262
+ count > 0
263
+ ? tui.muted(` (${count} GitHub account${count > 1 ? 's' : ''})`)
264
+ : '';
265
+ return {
266
+ name: org.name,
267
+ message: `${org.name}${suffix}`,
268
+ value: org.id,
269
+ };
270
+ });
271
+
272
+ const response = await enquirer.prompt<{ orgName: string }>({
273
+ type: 'select',
274
+ name: 'orgName',
275
+ message: 'Select an organization',
276
+ choices,
277
+ result(name: string) {
278
+ // @ts-expect-error - this.map exists at runtime
279
+ return this.map(name)[name];
280
+ },
281
+ });
282
+
283
+ orgId = response.orgName;
284
+ selectedOrg = sortedOrgs.find((o) => o.id === orgId);
285
+ }
286
+ }
287
+
288
+ const result = await runGitAccountConnect({
289
+ apiClient,
290
+ orgId: orgId!,
291
+ orgName: selectedOrg?.name,
292
+ logger,
293
+ config,
294
+ });
295
+
296
+ return { connected: result.connected, orgId };
297
+ } catch (error) {
298
+ const isCancel =
299
+ error === '' ||
300
+ (error instanceof Error &&
301
+ (error.message === '' || error.message === 'User cancelled'));
302
+
303
+ if (isCancel) {
304
+ tui.newline();
305
+ tui.info('Cancelled');
306
+ return { connected: false };
307
+ }
308
+
309
+ logger.trace(error);
310
+ return logger.fatal(
311
+ 'Failed to add GitHub account: %s',
312
+ error,
313
+ ErrorCode.INTEGRATION_FAILED
314
+ );
315
+ }
316
+ },
317
+ });
@@ -0,0 +1,12 @@
1
+ import { createCommand } from '../../../types';
2
+ import { addSubcommand } from './add';
3
+ import { removeSubcommand } from './remove';
4
+ import { listSubcommand } from './list';
5
+
6
+ export const accountCommand = createCommand({
7
+ name: 'account',
8
+ description: 'Manage GitHub accounts connected to your organization',
9
+ subcommands: [addSubcommand, removeSubcommand, listSubcommand],
10
+ });
11
+
12
+ export default accountCommand;