copilotkit 0.0.51 → 0.0.52

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.
@@ -1,293 +1,20 @@
1
1
  // src/commands/init.ts
2
2
  import { Flags as Flags3 } from "@oclif/core";
3
- import inquirer4 from "inquirer";
4
- import path7 from "path";
5
- import fs7 from "fs";
6
-
7
- // src/services/auth.service.ts
8
- import Conf2 from "conf";
9
- import cors from "cors";
10
- import express from "express";
11
- import crypto2 from "node:crypto";
12
- import open from "open";
13
- import getPort from "get-port";
14
- import ora from "ora";
15
- import chalk from "chalk";
16
- import inquirer from "inquirer";
17
-
18
- // src/utils/trpc.ts
19
- import { createTRPCClient as trpcClient, httpBatchLink } from "@trpc/client";
20
- import superjson from "superjson";
21
- var COPILOT_CLOUD_BASE_URL = process.env.COPILOT_CLOUD_BASE_URL || "https://cloud.copilotkit.ai";
22
- function createTRPCClient(cliToken) {
23
- return trpcClient({
24
- links: [
25
- httpBatchLink({
26
- url: `${COPILOT_CLOUD_BASE_URL}/api/trpc-cli`,
27
- transformer: superjson,
28
- headers: () => {
29
- return {
30
- "x-trpc-source": "cli",
31
- "x-cli-token": cliToken
32
- };
33
- }
34
- })
35
- ]
36
- });
37
- }
38
-
39
- // src/services/analytics.service.ts
40
- import { Analytics } from "@segment/analytics-node";
41
- import { PostHog } from "posthog-node";
42
- import Conf from "conf";
43
- var AnalyticsService = class {
44
- constructor(authData) {
45
- this.authData = authData;
46
- if (process.env.SEGMENT_DISABLED === "true") {
47
- return;
48
- }
49
- const segmentWriteKey = process.env.SEGMENT_WRITE_KEY || "9Pv6QyExYef2P4hPz4gks6QAvNMi2AOf";
50
- this.globalProperties = {
51
- service: "cli"
52
- };
53
- if (this.authData?.userId) {
54
- this.userId = this.authData.userId;
55
- }
56
- if (this.authData?.email) {
57
- this.email = this.authData.email;
58
- this.globalProperties.email = this.authData.email;
59
- }
60
- if (this.authData?.organizationId) {
61
- this.organizationId = this.authData.organizationId;
62
- }
63
- this.segment = new Analytics({
64
- writeKey: segmentWriteKey,
65
- disable: process.env.SEGMENT_DISABLE === "true"
66
- });
67
- if (process.env.POSTHOG_DISABLED !== "true") {
68
- const posthogKey = process.env.POSTHOG_KEY || "phc_XZdymVYjrph9Mi0xZYGNyCKexxgblXRR1jMENCtdz5Q";
69
- const posthogHost = process.env.POSTHOG_HOST || "https://eu.i.posthog.com";
70
- this.posthog = new PostHog(posthogKey, {
71
- host: posthogHost
72
- });
73
- }
74
- const config = new Conf({ projectName: "CopilotKitCLI" });
75
- if (!config.get("anonymousId")) {
76
- config.set("anonymousId", crypto.randomUUID());
77
- }
78
- }
79
- segment;
80
- posthog;
81
- globalProperties = {};
82
- userId;
83
- email;
84
- organizationId;
85
- config = new Conf({ projectName: "CopilotKitCLI" });
86
- getAnonymousId() {
87
- const anonymousId = this.config.get("anonymousId");
88
- if (!anonymousId) {
89
- const anonymousId2 = crypto.randomUUID();
90
- this.config.set("anonymousId", anonymousId2);
91
- return anonymousId2;
92
- }
93
- return anonymousId;
94
- }
95
- track(event) {
96
- if (!this.segment) {
97
- return Promise.resolve();
98
- }
99
- const payload = {
100
- userId: this.userId ? this.userId : void 0,
101
- email: this.email ? this.email : void 0,
102
- anonymousId: this.getAnonymousId(),
103
- event: event.event,
104
- properties: {
105
- ...this.globalProperties,
106
- ...event.properties,
107
- $groups: this.organizationId ? {
108
- segment_group: this.organizationId
109
- } : void 0,
110
- eventProperties: {
111
- ...event.properties,
112
- ...this.globalProperties
113
- }
114
- }
115
- };
116
- return new Promise((resolve, reject) => {
117
- this.segment.track(payload, (err) => {
118
- if (err) {
119
- resolve();
120
- }
121
- resolve();
122
- });
123
- });
124
- }
125
- /**
126
- * Check if a feature flag is enabled
127
- */
128
- async isFeatureEnabled(flagKey) {
129
- if (!this.posthog) {
130
- return false;
131
- }
132
- try {
133
- const distinctId = this.userId || this.getAnonymousId();
134
- const flag = await this.posthog.isFeatureEnabled(flagKey, distinctId);
135
- return Boolean(flag);
136
- } catch (error) {
137
- console.warn(`Failed to check feature flag ${flagKey}:`, error);
138
- return false;
139
- }
140
- }
141
- /**
142
- * Get feature flag payload
143
- */
144
- async getFeatureFlagPayload(flagKey) {
145
- if (!this.posthog) {
146
- return null;
147
- }
148
- try {
149
- const distinctId = this.userId || this.getAnonymousId();
150
- const payload = await this.posthog.getFeatureFlagPayload(flagKey, distinctId);
151
- return payload;
152
- } catch (error) {
153
- console.warn(`Failed to get feature flag payload ${flagKey}:`, error);
154
- return null;
155
- }
156
- }
157
- /**
158
- * Shutdown analytics services
159
- */
160
- async shutdown() {
161
- if (this.posthog) {
162
- await this.posthog.shutdown();
163
- }
164
- }
165
- };
166
-
167
- // src/services/auth.service.ts
168
- var AuthService = class {
169
- config = new Conf2({ projectName: "CopilotKitCLI" });
170
- COPILOT_CLOUD_BASE_URL = process.env.COPILOT_CLOUD_BASE_URL || "https://cloud.copilotkit.ai";
171
- getToken() {
172
- return this.config.get("cliToken");
173
- }
174
- getCLIToken() {
175
- const cliToken = this.config.get("cliToken");
176
- return cliToken;
177
- }
178
- async logout(cmd) {
179
- this.config.delete("cliToken");
180
- }
181
- async requireLogin(cmd, context) {
182
- let cliToken = this.getCLIToken();
183
- if (!cliToken) {
184
- try {
185
- let shouldLogin = true;
186
- if (context !== "cloud-features") {
187
- const response = await inquirer.prompt([
188
- {
189
- name: "shouldLogin",
190
- type: "confirm",
191
- message: "\u{1FA81} You are not yet authenticated. Authenticate with Copilot Cloud? (press Enter to confirm)",
192
- default: true
193
- }
194
- ]);
195
- shouldLogin = response.shouldLogin;
196
- }
197
- if (shouldLogin) {
198
- if (context === "cloud-features") {
199
- cmd.log(chalk.cyan("\n\u{1F680} Setting up Copilot Cloud authentication...\n"));
200
- }
201
- const loginResult = await this.login({ exitAfterLogin: false });
202
- cliToken = loginResult.cliToken;
203
- return loginResult;
204
- } else {
205
- cmd.error("Authentication required to proceed.");
206
- }
207
- } catch (error) {
208
- if (error instanceof Error && error.name === "ExitPromptError") {
209
- cmd.error(chalk.yellow("\nAuthentication cancelled"));
210
- }
211
- throw error;
212
- }
213
- }
214
- let me;
215
- const trpcClient2 = createTRPCClient(cliToken);
216
- try {
217
- me = await trpcClient2.me.query();
218
- } catch (error) {
219
- cmd.log(chalk.yellow("Your authentication has expired. Re-authenticating..."));
220
- try {
221
- const loginResult = await this.login({ exitAfterLogin: false });
222
- return loginResult;
223
- } catch (loginError) {
224
- cmd.log(chalk.red("Could not authenticate with Copilot Cloud. Please run: npx copilotkit@latest login"));
225
- process.exit(1);
226
- }
227
- }
228
- if (!me.organization || !me.user) {
229
- cmd.error("Authentication required to proceed.");
230
- }
231
- return { cliToken, user: me.user, organization: me.organization };
232
- }
233
- async login({ exitAfterLogin } = { exitAfterLogin: true }) {
234
- const spinner = ora("\u{1FA81} Opening browser for authentication...").start();
235
- let analytics;
236
- analytics = new AnalyticsService();
237
- const app = express();
238
- app.use(cors());
239
- app.use(express.urlencoded({ extended: true }));
240
- app.use(express.json());
241
- const port = await getPort();
242
- const state = crypto2.randomBytes(16).toString("hex");
243
- return new Promise(async (resolve) => {
244
- const server = app.listen(port, () => {
245
- });
246
- await analytics.track({
247
- event: "cli.login.initiated",
248
- properties: {}
249
- });
250
- spinner.text = "\u{1FA81} Waiting for browser authentication to complete...";
251
- app.post("/callback", async (req, res) => {
252
- const { cliToken, user, organization } = req.body;
253
- analytics = new AnalyticsService({ userId: user.id, organizationId: organization.id, email: user.email });
254
- await analytics.track({
255
- event: "cli.login.success",
256
- properties: {
257
- organizationId: organization.id,
258
- userId: user.id,
259
- email: user.email
260
- }
261
- });
262
- if (state !== req.query.state) {
263
- res.status(401).json({ message: "Invalid state" });
264
- spinner.fail("Invalid state");
265
- return;
266
- }
267
- this.config.set("cliToken", cliToken);
268
- res.status(200).json({ message: "Callback called" });
269
- spinner.succeed(`\u{1FA81} Successfully logged in as ${chalk.hex("#7553fc")(user.email)}`);
270
- if (exitAfterLogin) {
271
- process.exit(0);
272
- } else {
273
- server.close();
274
- resolve({ cliToken, user, organization });
275
- }
276
- });
277
- open(`${this.COPILOT_CLOUD_BASE_URL}/cli-auth?callbackUrl=http://localhost:${port}/callback&state=${state}`);
278
- });
279
- }
280
- };
281
3
 
282
4
  // src/commands/base-command.ts
283
5
  import { Command } from "@oclif/core";
284
6
  import Sentry, { consoleIntegration } from "@sentry/node";
285
7
 
286
8
  // src/utils/version.ts
287
- var LIB_VERSION = "0.0.51";
9
+ var LIB_VERSION = "0.0.52";
10
+
11
+ // src/utils/trpc.ts
12
+ import { createTRPCClient as trpcClient, httpBatchLink } from "@trpc/client";
13
+ import superjson from "superjson";
14
+ var COPILOT_CLOUD_BASE_URL = process.env.COPILOT_CLOUD_BASE_URL || "https://cloud.copilotkit.ai";
288
15
 
289
16
  // src/commands/base-command.ts
290
- import chalk2 from "chalk";
17
+ import chalk from "chalk";
291
18
  var BaseCommand = class extends Command {
292
19
  async init() {
293
20
  await this.checkCLIVersion();
@@ -303,12 +30,13 @@ var BaseCommand = class extends Command {
303
30
  });
304
31
  }
305
32
  async catch(err) {
306
- if (process.env.SENTRY_DISABLED === "true") {
307
- super.catch(err);
308
- return;
33
+ if (process.env.SENTRY_DISABLED !== "true") {
34
+ Sentry.captureException(err);
309
35
  }
310
- Sentry.captureException(err);
311
- super.catch(err);
36
+ const message = err?.message ?? "Unknown error";
37
+ this.log("\n" + chalk.red(message) + "\n");
38
+ const exitCode = err?.oclif?.exit ?? 1;
39
+ this.exit(exitCode);
312
40
  }
313
41
  async finally() {
314
42
  if (process.env.SENTRY_DISABLED === "true") {
@@ -327,32 +55,32 @@ var BaseCommand = class extends Command {
327
55
  }
328
56
  }
329
57
  async gracefulError(message) {
330
- this.log("\n" + chalk2.red(message));
58
+ this.log("\n" + chalk.red(message));
331
59
  process.exit(1);
332
60
  }
333
61
  };
334
62
 
335
63
  // src/commands/create.ts
336
64
  import { Flags, Args } from "@oclif/core";
337
- import inquirer2 from "inquirer";
338
- import chalk3 from "chalk";
65
+ import inquirer from "inquirer";
66
+ import chalk2 from "chalk";
339
67
  import fs from "fs-extra";
340
68
  import path from "path";
341
69
  import { promisify } from "util";
342
70
  import { pipeline } from "stream";
343
71
  import { createWriteStream } from "fs";
344
72
  import { extract } from "tar";
345
- import ora2 from "ora";
73
+ import ora from "ora";
346
74
  var streamPipeline = promisify(pipeline);
347
75
  var theme = {
348
- primary: chalk3.magenta,
349
- secondary: chalk3.gray,
350
- tertiary: chalk3.gray,
351
- error: chalk3.red,
352
- command: chalk3.blue,
353
- success: chalk3.green,
354
- warning: chalk3.yellow,
355
- divider: chalk3.gray("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"),
76
+ primary: chalk2.magenta,
77
+ secondary: chalk2.gray,
78
+ tertiary: chalk2.gray,
79
+ error: chalk2.red,
80
+ command: chalk2.blue,
81
+ success: chalk2.green,
82
+ warning: chalk2.yellow,
83
+ divider: chalk2.gray("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"),
356
84
  bottomPadding: ""
357
85
  };
358
86
  var TEMPLATE_REPOS = {
@@ -406,15 +134,7 @@ var KITE = `
406
134
  \u28F7\u28FE\u28FF\u28E4\u28FE\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF
407
135
  `;
408
136
  var Create = class _Create extends BaseCommand {
409
- constructor(argv, config, authService = new AuthService()) {
410
- super(argv, config);
411
- this.authService = authService;
412
- }
413
- trpcClient = null;
414
- analytics = null;
415
- startTime = Date.now();
416
- analyticsQueue = [];
417
- static description = "Create a new CopilotKit project with Next.js and Cloud setup";
137
+ static description = "Create a new CopilotKit project";
418
138
  static examples = [
419
139
  "$ copilotkit create my-app",
420
140
  "$ copilotkit create my-app --framework langgraph-js",
@@ -440,7 +160,7 @@ var Create = class _Create extends BaseCommand {
440
160
  required: false
441
161
  }),
442
162
  project: Flags.string({
443
- description: "project ID (can be found in the Copilot Cloud dashboard)"
163
+ description: "project ID (deprecated, kept for backwards compatibility)"
444
164
  })
445
165
  };
446
166
  static args = {
@@ -449,135 +169,82 @@ var Create = class _Create extends BaseCommand {
449
169
  required: false
450
170
  })
451
171
  };
172
+ constructor(argv, config) {
173
+ super(argv, config);
174
+ }
452
175
  async run() {
453
176
  const { args, flags } = await this.parse(_Create);
454
- try {
455
- this.analytics = new AnalyticsService();
456
- if (!flags["no-banner"]) {
457
- this.log(theme.primary(KITE));
458
- this.log(theme.primary("~ Welcome to CopilotKit! ~\n"));
459
- this.log(theme.divider);
460
- if ((!flags.name || flags.projectName) && !flags.framework) {
461
- this.log("\n" + theme.secondary("Just a few questions to get started!\n"));
462
- }
463
- }
464
- const projectName = flags.name || args.projectName || await this.promptProjectName();
465
- const agentFramework = flags.framework || await this.promptAgentFramework();
466
- this.queueAnalytics("cli.create.started", {
467
- framework_selected: agentFramework,
468
- project_name: projectName,
469
- flags_used: Object.keys(flags).filter((key) => flags[key] !== void 0 && key !== "help")
470
- });
471
- const projectDir = path.resolve(process.cwd(), projectName);
472
- if (fs.existsSync(projectDir)) {
473
- this.log(theme.error(`
474
- Directory "${projectName}" already exists.`));
475
- this.log(theme.secondary("\nYou can:"));
476
- this.log(theme.secondary(" 1. Choose a different project name"));
477
- this.log(theme.secondary(" 2. Remove the existing directory manually if you want to use this name\n"));
478
- this.exit(1);
479
- }
480
- this.log(chalk3.cyan("\n\u{1F511} Now get your API key"));
481
- this.log(chalk3.gray("Setting up your cloud account and retrieving your API key...\n"));
482
- let cloudSetupInfo = null;
483
- try {
484
- cloudSetupInfo = await this.setupCloudApiKey(flags);
485
- if (this.analytics && cloudSetupInfo.cliToken) {
486
- const trpcClient2 = createTRPCClient(cloudSetupInfo.cliToken);
487
- const me = await trpcClient2.me.query();
488
- if (me.user && me.organization) {
489
- this.analytics = new AnalyticsService({
490
- userId: me.user.id,
491
- organizationId: me.organization.id,
492
- email: me.user.email
493
- });
494
- }
495
- }
496
- this.queueAnalytics("cli.create.cloud_setup_completed", {
497
- framework: agentFramework,
498
- project_id: cloudSetupInfo.selectedProjectId,
499
- api_key_retrieved: !!cloudSetupInfo.apiKey
500
- });
501
- } catch (error) {
502
- this.queueAnalytics("cli.create.cloud_setup_failed", {
503
- framework: agentFramework,
504
- error: error.message
505
- });
506
- throw error;
507
- }
508
- const options = {
509
- projectName,
510
- agentFramework,
511
- apiKey: cloudSetupInfo?.apiKey,
512
- projectId: cloudSetupInfo?.selectedProjectId
513
- };
514
- const spinner = ora2({
515
- text: theme.secondary.bold("Creating your project..."),
516
- color: "cyan",
517
- spinner: "dots"
518
- }).start();
519
- try {
520
- await fs.ensureDir(projectDir);
521
- spinner.text = theme.secondary.bold("Downloading template...");
522
- await this.downloadTemplate(projectDir, options.agentFramework);
523
- if (options.apiKey) {
524
- spinner.text = theme.secondary.bold("Configuring API key...");
525
- await this.configureApiKey(projectDir, options.apiKey);
526
- }
527
- spinner.succeed(theme.secondary.bold(`Project "${projectName}" created successfully!`));
528
- this.queueAnalytics("cli.create.project_created", {
529
- framework: agentFramework,
530
- project_name: projectName,
531
- has_api_key: !!options.apiKey,
532
- duration_ms: Date.now() - this.startTime
533
- });
534
- this.log("\n" + theme.divider);
535
- this.log(
536
- "\n" + theme.secondary.bold(
537
- `\u{1FA81}\u{1F91D}${FRAMEWORK_EMOJI[options.agentFramework]} All set!
538
-
539
- Your project is ready with Copilot Cloud configured.`
540
- )
541
- );
542
- this.log("\n" + theme.secondary("Next steps:"));
543
- this.log(theme.secondary(` \u2022 ${theme.command(`cd ${projectName}`)}`));
544
- this.log(theme.secondary(" \u2022 Follow the setup instructions in the README.md"));
545
- this.log("\n" + theme.secondary("Documentation:"));
546
- this.log(theme.secondary(" \u2022 ") + theme.command("https://docs.copilotkit.ai"));
547
- this.log(theme.secondary(" \u2022 ") + theme.command(FRAMEWORK_DOCUMENTATION[options.agentFramework]));
548
- this.log(theme.bottomPadding);
549
- this.queueAnalytics("cli.create.completed", {
550
- framework: agentFramework,
551
- project_name: projectName,
552
- cloud_setup_completed: !!cloudSetupInfo,
553
- api_key_configured: !!options.apiKey,
554
- duration_ms: Date.now() - this.startTime
555
- });
556
- await this.flushAnalytics();
557
- } catch (error) {
558
- spinner.fail(theme.error(`Failed to create project: ${error.message}`));
559
- this.queueAnalytics("cli.create.failed", {
560
- framework: agentFramework,
561
- project_name: projectName,
562
- error: error.message,
563
- step: "project_creation",
564
- duration_ms: Date.now() - this.startTime
565
- });
566
- await this.flushAnalytics();
177
+ if (!flags["no-banner"]) {
178
+ this.log(theme.primary(KITE));
179
+ this.log(theme.primary("~ Welcome to CopilotKit! ~\n"));
180
+ this.log(theme.divider);
181
+ if ((!flags.name || flags.projectName) && !flags.framework) {
182
+ this.log("\n" + theme.secondary("Just a few questions to get started!\n"));
183
+ }
184
+ }
185
+ const projectNameInput = flags.name || args.projectName || await this.promptProjectName();
186
+ const projectName = projectNameInput.trim();
187
+ const usingCurrentDir = projectName === "." || projectName === "./";
188
+ const agentFramework = flags.framework || await this.promptAgentFramework();
189
+ const projectDir = usingCurrentDir ? process.cwd() : path.resolve(process.cwd(), projectName);
190
+ if (usingCurrentDir) {
191
+ const allowedEntries = /* @__PURE__ */ new Set([".git", ".gitignore", ".DS_Store"]);
192
+ const existingEntries = await fs.readdir(projectDir);
193
+ const blockingEntries = existingEntries.filter((entry) => !allowedEntries.has(entry));
194
+ if (blockingEntries.length > 0) {
195
+ this.log(theme.error("\nCurrent directory is not empty."));
196
+ this.log(theme.secondary("\nPlease run create in an empty directory or specify a new project name."));
567
197
  this.exit(1);
568
198
  }
199
+ } else if (await fs.pathExists(projectDir)) {
200
+ this.log(theme.error(`
201
+ Directory "${projectName}" already exists.`));
202
+ this.log(theme.secondary("\nYou can:"));
203
+ this.log(theme.secondary(" 1. Choose a different project name"));
204
+ this.log(theme.secondary(" 2. Remove the existing directory manually if you want to use this name\n"));
205
+ this.exit(1);
206
+ }
207
+ const options = {
208
+ projectName,
209
+ agentFramework
210
+ };
211
+ const spinner = ora({
212
+ text: theme.secondary.bold("Creating your project..."),
213
+ color: "cyan",
214
+ spinner: "dots"
215
+ }).start();
216
+ try {
217
+ await fs.ensureDir(projectDir);
218
+ spinner.text = theme.secondary.bold("Downloading template...");
219
+ await this.downloadTemplate(projectDir, options.agentFramework);
220
+ const displayName = usingCurrentDir ? "current directory" : `"${projectName}"`;
221
+ spinner.succeed(theme.secondary.bold(`Project ${displayName} created successfully!`));
569
222
  } catch (error) {
570
- this.queueAnalytics("cli.create.failed", {
571
- error: error.message,
572
- step: "initialization",
573
- duration_ms: Date.now() - this.startTime
574
- });
575
- await this.flushAnalytics();
576
- this.gracefulError(error.message);
223
+ spinner.fail(theme.error(`Failed to create project: ${error.message}`));
224
+ this.exit(1);
577
225
  }
226
+ this.log("\n" + theme.divider);
227
+ this.log(
228
+ "\n" + theme.secondary.bold(
229
+ `\u{1FA81}\u{1F91D}${FRAMEWORK_EMOJI[options.agentFramework]} All set!
230
+
231
+ Your project is ready to explore CopilotKit locally.`
232
+ )
233
+ );
234
+ this.log("\n" + theme.secondary("Next steps:"));
235
+ if (usingCurrentDir) {
236
+ this.log(theme.secondary(" \u2022 You are already inside your new project directory"));
237
+ } else {
238
+ this.log(theme.secondary(` \u2022 ${theme.command(`cd ${projectName}`)}`));
239
+ }
240
+ this.log(theme.secondary(" \u2022 Follow the setup instructions in the README.md"));
241
+ this.log("\n" + theme.secondary("Documentation:"));
242
+ this.log(theme.secondary(" \u2022 ") + theme.command("https://docs.copilotkit.ai"));
243
+ this.log(theme.secondary(" \u2022 ") + theme.command(FRAMEWORK_DOCUMENTATION[options.agentFramework]));
244
+ this.log(theme.bottomPadding);
578
245
  }
579
246
  async promptProjectName() {
580
- const { projectName } = await inquirer2.prompt([
247
+ const { projectName } = await inquirer.prompt([
581
248
  {
582
249
  type: "input",
583
250
  name: "projectName",
@@ -597,7 +264,7 @@ Your project is ready with Copilot Cloud configured.`
597
264
  return projectName;
598
265
  }
599
266
  async promptAgentFramework() {
600
- const { framework } = await inquirer2.prompt([
267
+ const { framework } = await inquirer.prompt([
601
268
  {
602
269
  type: "list",
603
270
  name: "framework",
@@ -607,11 +274,11 @@ Your project is ready with Copilot Cloud configured.`
607
274
  { name: `${FRAMEWORK_EMOJI["langgraph-js"]} LangGraph (JavaScript)`, value: "langgraph-js" },
608
275
  { name: `${FRAMEWORK_EMOJI.mastra} Mastra`, value: "mastra" },
609
276
  { name: `${FRAMEWORK_EMOJI["pydantic-ai"]} Pydantic AI`, value: "pydantic-ai" },
277
+ { name: `${FRAMEWORK_EMOJI.adk} ADK`, value: "adk" },
610
278
  { name: `${FRAMEWORK_EMOJI.flows} CrewAI Flows`, value: "flows" },
611
279
  { name: `${FRAMEWORK_EMOJI.llamaindex} LlamaIndex`, value: "llamaindex" },
612
280
  { name: `${FRAMEWORK_EMOJI.agno} Agno`, value: "agno" },
613
- { name: `${FRAMEWORK_EMOJI.ag2} AG2`, value: "ag2" },
614
- { name: `${FRAMEWORK_EMOJI.adk} ADK`, value: "adk" }
281
+ { name: `${FRAMEWORK_EMOJI.ag2} AG2`, value: "ag2" }
615
282
  ]
616
283
  }
617
284
  ]);
@@ -637,100 +304,6 @@ Your project is ready with Copilot Cloud configured.`
637
304
  throw new Error(`Failed to download template: ${error.message}`);
638
305
  }
639
306
  }
640
- /**
641
- * Queue an analytics event to be sent later (non-blocking)
642
- */
643
- queueAnalytics(event, properties) {
644
- this.analyticsQueue.push({ event, properties });
645
- }
646
- /**
647
- * Send all queued analytics events in fire-and-forget manner
648
- */
649
- async flushAnalytics() {
650
- if (!this.analytics || this.analyticsQueue.length === 0) {
651
- return;
652
- }
653
- const promises = this.analyticsQueue.map(
654
- ({ event, properties }) => this.analytics.track({ event, properties }).catch(() => {
655
- })
656
- );
657
- Promise.all(promises).catch(() => {
658
- });
659
- if (this.analytics) {
660
- this.analytics.shutdown().catch(() => {
661
- });
662
- }
663
- }
664
- async setupCloudApiKey(flags) {
665
- const { cliToken, organization } = await this.authService.requireLogin(this, "cloud-features");
666
- this.trpcClient = createTRPCClient(cliToken);
667
- const availableProjects = await this.trpcClient.listOrgProjects.query({ orgId: organization.id });
668
- let selectedProjectId;
669
- if (flags.project) {
670
- if (!availableProjects.some((project) => project.id === flags.project)) {
671
- this.log(chalk3.red(`\u{1F4C1} Project with ID ${flags.project} not found`));
672
- process.exit(1);
673
- }
674
- selectedProjectId = flags.project;
675
- this.log(chalk3.green(`\u{1F4C1} Selected project ${selectedProjectId}`));
676
- } else if (availableProjects.length === 1) {
677
- selectedProjectId = availableProjects[0].id;
678
- this.log(chalk3.green(`\u{1F4C1} Auto-selected project ${selectedProjectId}`));
679
- } else {
680
- const { projectId } = await inquirer2.prompt([
681
- {
682
- name: "projectId",
683
- type: "list",
684
- message: "\u{1F4C1} Choose a project:",
685
- choices: availableProjects.map((project) => ({
686
- value: project.id,
687
- name: `${project.name} (ID: ${project.id})`
688
- }))
689
- }
690
- ]);
691
- selectedProjectId = projectId;
692
- }
693
- const spinner = ora2({
694
- text: "Retrieving your API key...",
695
- color: "cyan"
696
- }).start();
697
- try {
698
- const copilotCloudPublicApiKey = await this.trpcClient.getCopilotCloudPublicApiKey.query({
699
- projectId: selectedProjectId
700
- });
701
- if (!copilotCloudPublicApiKey?.key) {
702
- spinner.fail("Failed to retrieve API key");
703
- throw new Error("No API key found for the selected project");
704
- }
705
- spinner.succeed("\u2705 API key retrieved successfully");
706
- return {
707
- cliToken,
708
- organization,
709
- selectedProjectId,
710
- apiKey: copilotCloudPublicApiKey.key
711
- };
712
- } catch (error) {
713
- spinner.fail("Failed to retrieve API key");
714
- throw error;
715
- }
716
- }
717
- async configureApiKey(projectDir, apiKey) {
718
- const envPath = path.join(projectDir, ".env.local");
719
- const envExamplePath = path.join(projectDir, ".env.example");
720
- try {
721
- let envContent = "";
722
- if (await fs.pathExists(envExamplePath)) {
723
- envContent = await fs.readFile(envExamplePath, "utf8");
724
- envContent = envContent.replace(/COPILOT_CLOUD_PUBLIC_API_KEY=.*/g, `COPILOT_CLOUD_PUBLIC_API_KEY=${apiKey}`);
725
- } else {
726
- envContent = `COPILOT_CLOUD_PUBLIC_API_KEY=${apiKey}
727
- `;
728
- }
729
- await fs.writeFile(envPath, envContent);
730
- } catch (error) {
731
- console.warn("Warning: Could not configure API key in .env.local file");
732
- }
733
- }
734
307
  };
735
308
 
736
309
  // src/lib/init/types/questions.ts
@@ -867,784 +440,8 @@ var ConfigFlags = {
867
440
  })
868
441
  };
869
442
 
870
- // src/lib/init/types/templates.ts
871
- var BASE_URL = "https://registry.copilotkit.ai/r";
872
- var templateMapping = {
873
- // Runtimes
874
- RemoteEndpoint: `${BASE_URL}/remote-endpoint.json`,
875
- LangGraphPlatformRuntime: `${BASE_URL}/langgraph-platform-runtime.json`,
876
- // CrewAI
877
- CrewEnterprise: [`${BASE_URL}/coagents-crew-starter.json`],
878
- CrewFlowsEnterprise: [`${BASE_URL}/coagents-starter-crewai-flows.json`],
879
- // LangGraph
880
- LangGraphGeneric: `${BASE_URL}/generic-lg-starter.json`,
881
- LangGraphStarter: [`${BASE_URL}/langgraph-platform-starter.json`, `${BASE_URL}/coagents-starter-ui.json`],
882
- // No Agent
883
- StandardStarter: `${BASE_URL}/standard-starter.json`,
884
- StandardRuntime: `${BASE_URL}/standard-runtime.json`,
885
- // MCP
886
- McpStarter: `${BASE_URL}/mcp-starter.json`,
887
- McpRuntime: `${BASE_URL}/mcp-starter-runtime.json`
888
- };
889
-
890
- // src/lib/init/ide-docs.ts
891
- import path2 from "path";
892
- import { existsSync } from "fs";
893
- import * as fs2 from "fs/promises";
894
- import chalk4 from "chalk";
895
- var COPILOTKIT_DOC_RULE_TEMPLATE = `---
896
- description: CopilotKit Documentation - Complete CopilotKit framework documentation for AI assistance
897
- alwaysApply: false
898
- ---
899
-
900
- # CopilotKit Documentation
901
-
902
- For ANY question about CopilotKit, use the comprehensive documentation available at:
903
- @https://docs.copilotkit.ai/llms-full.txt
904
-
905
- This contains the complete CopilotKit documentation including:
906
- - API references and hooks (useCopilotChat, useCopilotAction, etc.)
907
- - Component library documentation (CopilotKit, CopilotChat, etc.)
908
- - Integration guides and examples
909
- - Best practices and patterns
910
- - Troubleshooting and FAQs
911
-
912
- Always reference this documentation when working with CopilotKit to provide accurate, up-to-date information.
913
- `;
914
- var IDE_DOCS_CONFIGS = {
915
- cursor: {
916
- name: "cursor",
917
- displayName: "Cursor",
918
- rulesDir: ".cursor/rules",
919
- ruleFileName: "00-copilotkit-docs.mdc",
920
- createRuleContent: () => COPILOTKIT_DOC_RULE_TEMPLATE
921
- },
922
- windsurf: {
923
- name: "windsurf",
924
- displayName: "Windsurf",
925
- rulesDir: ".windsurf/rules",
926
- ruleFileName: "00-copilotkit-docs.md",
927
- createRuleContent: () => COPILOTKIT_DOC_RULE_TEMPLATE
928
- }
929
- };
930
- async function ensureDir(dirPath) {
931
- try {
932
- await fs2.mkdir(dirPath, { recursive: true });
933
- } catch (error) {
934
- if (!existsSync(dirPath)) {
935
- throw error;
936
- }
937
- }
938
- }
939
- async function pathExists(filePath) {
940
- try {
941
- await fs2.access(filePath);
942
- return true;
943
- } catch {
944
- return false;
945
- }
946
- }
947
- async function checkIDEInstallation(ide) {
948
- try {
949
- const homeDir = process.env.HOME || process.env.USERPROFILE || "";
950
- let configPath;
951
- switch (ide) {
952
- case "cursor":
953
- configPath = path2.join(homeDir, ".cursor");
954
- break;
955
- case "windsurf":
956
- configPath = path2.join(homeDir, ".codeium", "windsurf");
957
- break;
958
- default:
959
- return false;
960
- }
961
- return existsSync(configPath);
962
- } catch {
963
- return false;
964
- }
965
- }
966
- async function detectInstalledIDEs() {
967
- const allIDEs = ["cursor", "windsurf"];
968
- const installedIDEs = [];
969
- for (const ide of allIDEs) {
970
- if (await checkIDEInstallation(ide)) {
971
- installedIDEs.push(ide);
972
- }
973
- }
974
- return installedIDEs;
975
- }
976
- async function setupIDEDocs(ide, projectDir) {
977
- const config = IDE_DOCS_CONFIGS[ide];
978
- const rulesDir = path2.join(projectDir, config.rulesDir);
979
- const ruleFilePath = path2.join(rulesDir, config.ruleFileName);
980
- await ensureDir(rulesDir);
981
- if (await pathExists(ruleFilePath)) {
982
- console.log(chalk4.yellow(`\u26A0\uFE0F CopilotKit documentation rule already exists for ${config.displayName}`));
983
- return;
984
- }
985
- const ruleContent = config.createRuleContent();
986
- await fs2.writeFile(ruleFilePath, ruleContent, "utf8");
987
- }
988
- function getIDEInstructions(ide) {
989
- const config = IDE_DOCS_CONFIGS[ide];
990
- const instructions = [
991
- chalk4.cyan(`\u{1F4DA} CopilotKit documentation configured for ${config.displayName}!`),
992
- "",
993
- chalk4.bold("What this does:"),
994
- " \u2022 Adds CopilotKit documentation context to your IDE AI assistant",
995
- " \u2022 Provides accurate, up-to-date information about CopilotKit APIs",
996
- " \u2022 Improves code suggestions and help responses",
997
- "",
998
- chalk4.bold("Location:"),
999
- ` \u2022 Rule file: ${chalk4.gray(path2.join(config.rulesDir, config.ruleFileName))}`,
1000
- "",
1001
- chalk4.bold("Usage:"),
1002
- " \u2022 Your IDE AI assistant now has access to CopilotKit documentation",
1003
- " \u2022 Ask questions about CopilotKit APIs, components, and patterns",
1004
- " \u2022 The AI will reference official documentation for accurate answers"
1005
- ];
1006
- if (ide === "cursor") {
1007
- instructions.push(
1008
- "",
1009
- chalk4.bold("Next steps for Cursor:"),
1010
- " \u2022 Restart Cursor if currently open",
1011
- " \u2022 The rule will be automatically available in your AI context",
1012
- " \u2022 Start a new chat to use the documentation context"
1013
- );
1014
- } else if (ide === "windsurf") {
1015
- instructions.push(
1016
- "",
1017
- chalk4.bold("Next steps for Windsurf:"),
1018
- " \u2022 Restart Windsurf if currently open",
1019
- " \u2022 The rule will be automatically available in your AI context",
1020
- " \u2022 Start a new chat to use the documentation context"
1021
- );
1022
- }
1023
- return instructions;
1024
- }
1025
- async function handleIDEDocsSetup(selectedIDE, projectDir, spinner) {
1026
- try {
1027
- spinner.text = chalk4.cyan(`Setting up CopilotKit documentation for ${IDE_DOCS_CONFIGS[selectedIDE].displayName}...`);
1028
- await setupIDEDocs(selectedIDE, projectDir);
1029
- spinner.succeed(chalk4.green(`CopilotKit documentation configured for ${IDE_DOCS_CONFIGS[selectedIDE].displayName}`));
1030
- const instructions = getIDEInstructions(selectedIDE);
1031
- console.log("\n" + instructions.join("\n"));
1032
- } catch (error) {
1033
- spinner.fail(
1034
- chalk4.red(`Failed to setup IDE documentation: ${error instanceof Error ? error.message : "Unknown error"}`)
1035
- );
1036
- throw error;
1037
- }
1038
- }
1039
-
1040
- // src/lib/init/questions.ts
1041
- var linkToDocs = ["Mastra", "AG2", "LlamaIndex", "Agno"];
1042
- var validateUrl = (input) => {
1043
- try {
1044
- const sanitized = sanitizers.url(input);
1045
- const result = UrlSchema.safeParse(sanitized);
1046
- if (result.success) return true;
1047
- return result.error.errors[0]?.message || "Invalid URL format";
1048
- } catch (error) {
1049
- return "Invalid URL format";
1050
- }
1051
- };
1052
- var validateRequired = (input) => {
1053
- return sanitizers.trim(input) ? true : "This field is required";
1054
- };
1055
- function getQuestionsForBranch(branch) {
1056
- const baseQuestions = getBaseQuestions();
1057
- switch (branch) {
1058
- case "A":
1059
- return [...baseQuestions];
1060
- case "B":
1061
- return [...baseQuestions, ...getDeploymentChoiceQuestions()];
1062
- case "C":
1063
- default:
1064
- return [...baseQuestions, ...getCloudDeploymentQuestions()];
1065
- }
1066
- }
1067
- function getBaseQuestions() {
1068
- return [
1069
- {
1070
- type: "select",
1071
- name: "mode",
1072
- message: "\u{1F916} How will you be interacting with AI?",
1073
- choices: Array.from(MODES),
1074
- validate: (input) => {
1075
- try {
1076
- ModeSchema.parse(input);
1077
- return true;
1078
- } catch (error) {
1079
- return "Please select a valid mode";
1080
- }
1081
- }
1082
- },
1083
- // CrewAI specific questions
1084
- {
1085
- type: "select",
1086
- name: "crewType",
1087
- message: "\u{1F465} What kind of CrewAI implementation would you like to use?",
1088
- choices: Array.from(CREW_TYPES),
1089
- when: (answers) => answers.mode === "CrewAI",
1090
- validate: (input) => {
1091
- try {
1092
- CrewTypeSchema.parse(input);
1093
- return true;
1094
- } catch (error) {
1095
- return "Please select a valid crew type";
1096
- }
1097
- }
1098
- },
1099
- {
1100
- type: "input",
1101
- name: "crewName",
1102
- message: "\u{1F465} What would you like to name your crew? (can be anything)",
1103
- when: (answers) => answers.mode === "CrewAI",
1104
- default: "MyCopilotCrew",
1105
- validate: validateRequired,
1106
- sanitize: sanitizers.trim
1107
- },
1108
- {
1109
- type: "input",
1110
- name: "crewUrl",
1111
- message: "\u{1F517} Enter your Crew's Enterprise URL (more info at https://app.crewai.com):",
1112
- when: (answers) => answers.mode === "CrewAI",
1113
- validate: validateUrl,
1114
- sanitize: sanitizers.url
1115
- },
1116
- {
1117
- type: "input",
1118
- name: "crewBearerToken",
1119
- message: "\u{1F511} Enter your Crew's bearer token:",
1120
- when: (answers) => answers.mode === "CrewAI",
1121
- sensitive: true,
1122
- validate: validateRequired,
1123
- sanitize: sanitizers.trim
1124
- },
1125
- // LangGraph specific questions
1126
- {
1127
- type: "yes/no",
1128
- name: "alreadyDeployed",
1129
- message: "\u{1F99C}\u{1F517} Do you have an existing LangGraph agent?",
1130
- when: (answers) => answers.mode === "LangGraph",
1131
- validate: (input) => {
1132
- try {
1133
- YesNoSchema.parse(input);
1134
- return true;
1135
- } catch (error) {
1136
- return "Please select Yes or No";
1137
- }
1138
- }
1139
- },
1140
- {
1141
- type: "yes/no",
1142
- name: "langGraphPlatform",
1143
- message: "\u{1F99C}\u{1F517} Do you already have a LangGraph Agent URL? (remote or localhost)",
1144
- when: (answers) => answers.mode === "LangGraph" && answers.alreadyDeployed === "Yes",
1145
- validate: (input) => {
1146
- try {
1147
- YesNoSchema.parse(input);
1148
- return true;
1149
- } catch (error) {
1150
- return "Please select Yes or No";
1151
- }
1152
- }
1153
- },
1154
- {
1155
- type: "input",
1156
- name: "langGraphPlatformUrl",
1157
- message: "\u{1F99C}\u{1F517} Enter your LangGraph Agent URL (remote or localhost)",
1158
- when: (answers) => answers.mode === "LangGraph" && answers.alreadyDeployed === "Yes" && answers.langGraphPlatform === "Yes",
1159
- validate: validateUrl,
1160
- sanitize: sanitizers.url
1161
- },
1162
- {
1163
- type: "select",
1164
- name: "langGraphAgent",
1165
- message: "\u{1F4E6} Choose a LangGraph starter template:",
1166
- choices: Array.from(LANGGRAPH_AGENTS),
1167
- when: (answers) => answers.mode === "LangGraph" && answers.alreadyDeployed === "No"
1168
- },
1169
- {
1170
- type: "input",
1171
- name: "langSmithApiKey",
1172
- message: "\u{1F99C}\u{1F517} Enter your LangSmith API key (required by LangGraph Platform) :",
1173
- when: (answers) => answers.mode === "LangGraph" && answers.langGraphPlatform === "Yes" && !(answers.langGraphPlatformUrl && isLocalhost(answers.langGraphPlatformUrl)),
1174
- sensitive: true,
1175
- validate: validateRequired,
1176
- sanitize: sanitizers.apiKey
1177
- },
1178
- // LLM Token for self-hosted setups
1179
- {
1180
- type: "input",
1181
- name: "llmToken",
1182
- message: "\u{1F511} Enter your OpenAI API key (optional - leave empty to configure your LLM later):",
1183
- when: (answers) => answers.mode === "LangGraph" && answers.alreadyDeployed === "No" || answers.mode === "Standard" && answers.deploymentChoice === "Self-hosted" || answers.mode === "MCP" && answers.deploymentChoice === "Self-hosted" || answers.mode === "Standard" && answers.useCopilotCloud !== "Yes" || answers.mode === "MCP" && answers.useCopilotCloud !== "Yes",
1184
- sensitive: true,
1185
- sanitize: sanitizers.apiKey
1186
- },
1187
- // IDE Documentation Setup Questions
1188
- {
1189
- type: "yes/no",
1190
- name: "setupIDEDocs",
1191
- message: "\u{1F4DA} Would you like to add CopilotKit documentation to your IDE? (Provides AI assistant with CopilotKit context)",
1192
- when: async () => {
1193
- const installedIDEs = await detectInstalledIDEs();
1194
- return installedIDEs.length > 0;
1195
- },
1196
- validate: (input) => {
1197
- try {
1198
- YesNoSchema.parse(input);
1199
- return true;
1200
- } catch (error) {
1201
- return "Please select Yes or No";
1202
- }
1203
- }
1204
- },
1205
- {
1206
- type: "select",
1207
- name: "selectedIDE",
1208
- message: "\u{1F4BB} Which IDE would you like to configure with CopilotKit documentation?",
1209
- choices: async () => {
1210
- const installedIDEs = await detectInstalledIDEs();
1211
- const choices = installedIDEs.map((ide) => ({
1212
- name: IDE_DOCS_CONFIGS[ide].displayName,
1213
- value: ide
1214
- }));
1215
- choices.push({ name: "Skip", value: "skip" });
1216
- return choices;
1217
- },
1218
- when: (answers) => answers.setupIDEDocs === "Yes"
1219
- }
1220
- ];
1221
- }
1222
- function getDeploymentChoiceQuestions() {
1223
- return [
1224
- {
1225
- type: "select",
1226
- name: "deploymentChoice",
1227
- message: "\u{1F680} Use Copilot Cloud, or self-hosted?",
1228
- choices: Array.from(DEPLOYMENT_CHOICES),
1229
- validate: (input) => {
1230
- try {
1231
- DeploymentChoiceSchema.parse(input);
1232
- return true;
1233
- } catch (error) {
1234
- return "Please select a valid deployment option";
1235
- }
1236
- }
1237
- }
1238
- ];
1239
- }
1240
- function getCloudDeploymentQuestions() {
1241
- return [
1242
- {
1243
- type: "yes/no",
1244
- name: "useCopilotCloud",
1245
- message: "\u{1FA81} Deploy with Copilot Cloud? (recommended for production)",
1246
- when: (answers) => answers.mode === "Standard" || answers.mode === "MCP" || answers.mode === "LangGraph" && answers.alreadyDeployed === "No" || // Include new LangGraph agents
1247
- answers.mode !== "CrewAI" && // Crews only cloud, flows are self-hosted
1248
- answers.alreadyDeployed === "Yes" && answers.langGraphPlatform !== "No" && !linkToDocs.includes(answers.mode || "") && !isLocalhost(answers.langGraphPlatformUrl || ""),
1249
- validate: (input) => {
1250
- try {
1251
- YesNoSchema.parse(input);
1252
- return true;
1253
- } catch (error) {
1254
- return "Please select Yes or No";
1255
- }
1256
- }
1257
- }
1258
- ];
1259
- }
1260
- var questions = getQuestionsForBranch("C");
1261
-
1262
- // src/lib/init/scaffold/shadcn.ts
1263
- import spawn from "cross-spawn";
1264
- async function scaffoldShadCN(flags, userAnswers) {
1265
- try {
1266
- const components = [];
1267
- switch (userAnswers.mode) {
1268
- case "LangGraph":
1269
- components.push(templateMapping.LangGraphGeneric);
1270
- if (userAnswers.langGraphPlatform === "Yes") {
1271
- components.push(templateMapping.LangGraphPlatformRuntime);
1272
- } else {
1273
- components.push(templateMapping.RemoteEndpoint);
1274
- }
1275
- break;
1276
- case "CrewAI":
1277
- if (userAnswers.crewType === "Crews") {
1278
- components.push(...templateMapping.CrewEnterprise);
1279
- } else if (userAnswers.crewType === "Flows") {
1280
- components.push(...templateMapping.CrewFlowsEnterprise);
1281
- } else {
1282
- components.push(templateMapping.RemoteEndpoint);
1283
- }
1284
- break;
1285
- case "MCP":
1286
- components.push(templateMapping.McpStarter);
1287
- if (userAnswers.deploymentChoice === "Self-hosted" || userAnswers.useCopilotCloud === "No") {
1288
- components.push(templateMapping.McpRuntime);
1289
- }
1290
- break;
1291
- case "Standard":
1292
- components.push(templateMapping.StandardStarter);
1293
- if (userAnswers.deploymentChoice === "Self-hosted" || userAnswers.useCopilotCloud === "No") {
1294
- components.push(templateMapping.StandardRuntime);
1295
- }
1296
- break;
1297
- default:
1298
- return;
1299
- }
1300
- await new Promise((resolve) => setTimeout(resolve, 100));
1301
- try {
1302
- const result = spawn.sync("npx", ["shadcn@latest", "add", ...components], {
1303
- stdio: "inherit"
1304
- // This ensures stdin/stdout/stderr are all passed through
1305
- });
1306
- if (result.status !== 0) {
1307
- throw new Error(`The shadcn installation process exited with code ${result.status}`);
1308
- }
1309
- } catch (error) {
1310
- throw error;
1311
- }
1312
- } catch (error) {
1313
- throw error;
1314
- }
1315
- }
1316
-
1317
- // src/lib/init/scaffold/env.ts
1318
- import path3 from "path";
1319
- import fs3 from "fs";
1320
-
1321
- // src/lib/init/scaffold/langgraph-assistants.ts
1322
- async function getLangGraphAgents(url, langSmithApiKey) {
1323
- try {
1324
- const response = await fetch(`${url.trim().replace(/\/$/, "")}/assistants/search`, {
1325
- method: "POST",
1326
- headers: {
1327
- "Content-Type": "application/json",
1328
- "X-Api-Key": langSmithApiKey
1329
- },
1330
- body: JSON.stringify({
1331
- limit: 10,
1332
- offset: 0
1333
- })
1334
- });
1335
- return await response.json();
1336
- } catch (error) {
1337
- throw new Error(`Failed to get LangGraph agents: ${error}`);
1338
- }
1339
- }
1340
-
1341
- // src/lib/init/scaffold/env.ts
1342
- import inquirer3 from "inquirer";
1343
- function needsCloudDeployment(userAnswers) {
1344
- return userAnswers.deploymentChoice === "Copilot Cloud" || // Branch B choice
1345
- userAnswers.useCopilotCloud === "Yes" || // Branch C choice
1346
- userAnswers.mode === "CrewAI" || // CrewAI always needs cloud
1347
- !userAnswers.deploymentChoice && !userAnswers.useCopilotCloud;
1348
- }
1349
- async function scaffoldEnv(flags, userAnswers) {
1350
- try {
1351
- const envFile = path3.join(process.cwd(), ".env");
1352
- if (!fs3.existsSync(envFile)) {
1353
- fs3.writeFileSync(envFile, "", "utf8");
1354
- } else {
1355
- }
1356
- let newEnvValues = "";
1357
- const isCloudDeployment = needsCloudDeployment(userAnswers);
1358
- if (userAnswers.copilotCloudPublicApiKey) {
1359
- newEnvValues += `NEXT_PUBLIC_COPILOT_API_KEY=${userAnswers.copilotCloudPublicApiKey}
1360
- `;
1361
- }
1362
- if (userAnswers.langSmithApiKey) {
1363
- newEnvValues += `LANGSMITH_API_KEY=${userAnswers.langSmithApiKey}
1364
- `;
1365
- }
1366
- if (userAnswers.llmToken) {
1367
- newEnvValues += `OPENAI_API_KEY=${userAnswers.llmToken}
1368
- `;
1369
- }
1370
- if (userAnswers.crewName) {
1371
- newEnvValues += `NEXT_PUBLIC_COPILOTKIT_AGENT_NAME=${userAnswers.crewName}
1372
- `;
1373
- }
1374
- if (userAnswers.langGraphAgent) {
1375
- newEnvValues += `NEXT_PUBLIC_COPILOTKIT_AGENT_NAME=sample_agent
1376
- `;
1377
- newEnvValues += `LANGGRAPH_DEPLOYMENT_URL=http://localhost:8123
1378
- `;
1379
- } else if (userAnswers.langGraphPlatform === "Yes" && !isCloudDeployment) {
1380
- newEnvValues += `LANGGRAPH_DEPLOYMENT_URL=${userAnswers.langGraphPlatformUrl}
1381
- `;
1382
- } else if (userAnswers.langGraphRemoteEndpointURL) {
1383
- newEnvValues += `COPILOTKIT_REMOTE_ENDPOINT=${userAnswers.langGraphRemoteEndpointURL}
1384
- `;
1385
- }
1386
- if (flags.runtimeUrl) {
1387
- newEnvValues += `NEXT_PUBLIC_COPILOTKIT_RUNTIME_URL=${flags.runtimeUrl}
1388
- `;
1389
- } else if (!isCloudDeployment && userAnswers.crewType !== "Crews" && userAnswers.crewType !== "Flows") {
1390
- newEnvValues += `NEXT_PUBLIC_COPILOTKIT_RUNTIME_URL=/api/copilotkit
1391
- `;
1392
- }
1393
- if (userAnswers.langGraphPlatformUrl && (userAnswers.langSmithApiKey || isLocalhost(userAnswers.langGraphPlatformUrl))) {
1394
- const langGraphAgents = await getLangGraphAgents(
1395
- userAnswers.langGraphPlatformUrl,
1396
- userAnswers.langSmithApiKey || ""
1397
- );
1398
- let langGraphAgent = "";
1399
- if (langGraphAgents.length > 1) {
1400
- const { langGraphAgentChoice } = await inquirer3.prompt([
1401
- {
1402
- type: "list",
1403
- name: "langGraphAgentChoice",
1404
- message: "\u{1F99C}\u{1F517} Which agent from your graph would you like to use?",
1405
- choices: langGraphAgents.map((agent) => ({
1406
- name: agent.graph_id,
1407
- value: agent.graph_id
1408
- }))
1409
- }
1410
- ]);
1411
- langGraphAgent = langGraphAgentChoice;
1412
- } else if (langGraphAgents.length === 1) {
1413
- langGraphAgent = langGraphAgents[0].graph_id;
1414
- } else {
1415
- throw new Error("No agents found in your LangGraph endpoint");
1416
- }
1417
- newEnvValues += `NEXT_PUBLIC_COPILOTKIT_AGENT_NAME=${langGraphAgent}
1418
- `;
1419
- }
1420
- if (newEnvValues) {
1421
- fs3.appendFileSync(envFile, newEnvValues);
1422
- }
1423
- } catch (error) {
1424
- throw error;
1425
- }
1426
- }
1427
-
1428
- // src/lib/init/scaffold/github.ts
1429
- import { execSync } from "child_process";
1430
- import * as fs4 from "fs";
1431
- import * as path4 from "path";
1432
- import * as os from "os";
1433
- import chalk5 from "chalk";
1434
- async function cloneGitHubSubdirectory(githubUrl, destinationPath, spinner) {
1435
- try {
1436
- const { owner, repo, branch, subdirectoryPath } = parseGitHubUrl(githubUrl);
1437
- spinner.text = chalk5.cyan(`Cloning from ${owner}/${repo}...`);
1438
- return await sparseCheckout(owner, repo, branch, subdirectoryPath, destinationPath, spinner);
1439
- } catch (error) {
1440
- spinner.text = chalk5.red(`Failed to clone from GitHub: ${error}`);
1441
- return false;
1442
- }
1443
- }
1444
- async function sparseCheckout(owner, repo, branch, subdirectoryPath, destinationPath, spinner) {
1445
- const tempDir = fs4.mkdtempSync(path4.join(os.tmpdir(), "copilotkit-sparse-"));
1446
- try {
1447
- spinner.text = chalk5.cyan("Creating temporary workspace...");
1448
- execSync("git init", { cwd: tempDir, stdio: "pipe" });
1449
- spinner.text = chalk5.cyan("Connecting to repository...");
1450
- execSync(`git remote add origin https://github.com/${owner}/${repo}.git`, { cwd: tempDir, stdio: "pipe" });
1451
- execSync("git config core.sparseCheckout true", { cwd: tempDir, stdio: "pipe" });
1452
- fs4.writeFileSync(path4.join(tempDir, ".git/info/sparse-checkout"), subdirectoryPath);
1453
- spinner.text = chalk5.cyan("Downloading agent files...");
1454
- execSync(`git pull origin ${branch} --depth=1`, { cwd: tempDir, stdio: "pipe" });
1455
- const sourcePath = path4.join(tempDir, subdirectoryPath);
1456
- if (!fs4.existsSync(sourcePath)) {
1457
- throw new Error(`Subdirectory '${subdirectoryPath}' not found in the repository.`);
1458
- }
1459
- fs4.mkdirSync(destinationPath, { recursive: true });
1460
- spinner.text = chalk5.cyan("Installing agent files...");
1461
- await copyDirectoryAsync(sourcePath, destinationPath);
1462
- return true;
1463
- } finally {
1464
- try {
1465
- fs4.rmSync(tempDir, { recursive: true, force: true });
1466
- } catch (error) {
1467
- console.warn(`Failed to clean up temporary directory: ${error}`);
1468
- }
1469
- }
1470
- }
1471
- async function copyDirectoryAsync(source, destination) {
1472
- if (!fs4.existsSync(destination)) {
1473
- fs4.mkdirSync(destination, { recursive: true });
1474
- }
1475
- const entries = fs4.readdirSync(source, { withFileTypes: true });
1476
- for (const entry of entries) {
1477
- const srcPath = path4.join(source, entry.name);
1478
- const destPath = path4.join(destination, entry.name);
1479
- if (entry.isDirectory()) {
1480
- await copyDirectoryAsync(srcPath, destPath);
1481
- } else {
1482
- fs4.copyFileSync(srcPath, destPath);
1483
- }
1484
- if (entries.length > 10) {
1485
- await new Promise((resolve) => setTimeout(resolve, 1));
1486
- }
1487
- }
1488
- }
1489
- function parseGitHubUrl(githubUrl) {
1490
- const url = new URL(githubUrl);
1491
- if (url.hostname !== "github.com") {
1492
- throw new Error("Only GitHub URLs are supported");
1493
- }
1494
- const pathParts = url.pathname.split("/").filter(Boolean);
1495
- if (pathParts.length < 2) {
1496
- throw new Error("Invalid GitHub URL format");
1497
- }
1498
- const owner = pathParts[0];
1499
- const repo = pathParts[1];
1500
- let branch = "main";
1501
- let subdirectoryPath = "";
1502
- if (pathParts.length > 3 && (pathParts[2] === "tree" || pathParts[2] === "blob")) {
1503
- branch = pathParts[3];
1504
- subdirectoryPath = pathParts.slice(4).join("/");
1505
- }
1506
- return { owner, repo, branch, subdirectoryPath };
1507
- }
1508
-
1509
- // src/lib/init/scaffold/packages.ts
1510
- import spawn2 from "cross-spawn";
1511
- import chalk6 from "chalk";
1512
- import ora3 from "ora";
1513
-
1514
- // src/lib/init/scaffold/agent.ts
1515
- import ora4 from "ora";
1516
- import chalk7 from "chalk";
1517
- import path5 from "path";
1518
- import fs5 from "fs";
1519
- async function scaffoldAgent(userAnswers) {
1520
- if (userAnswers.mode === "CrewAI" || userAnswers.mode === "LangGraph" && !userAnswers.langGraphAgent || userAnswers.mode === "Standard" || userAnswers.mode === "MCP") {
1521
- return;
1522
- }
1523
- const spinner = ora4({
1524
- text: chalk7.cyan("Setting up AI agent..."),
1525
- color: "cyan"
1526
- }).start();
1527
- let template = "";
1528
- switch (userAnswers.mode) {
1529
- case "LangGraph":
1530
- if (userAnswers.langGraphAgent === "Python Starter") {
1531
- template = AgentTemplates.LangGraph.Starter.Python;
1532
- } else {
1533
- template = AgentTemplates.LangGraph.Starter.TypeScript;
1534
- }
1535
- break;
1536
- }
1537
- if (!template) {
1538
- spinner.fail(chalk7.red("Failed to determine agent template"));
1539
- throw new Error("Failed to determine agent template");
1540
- }
1541
- const agentDir = path5.join(process.cwd(), "agent");
1542
- try {
1543
- await cloneGitHubSubdirectory(template, agentDir, spinner);
1544
- spinner.text = chalk7.cyan("Creating agent environment variables...");
1545
- let envContent = "";
1546
- if (userAnswers.llmToken) {
1547
- envContent += `OPENAI_API_KEY=${userAnswers.llmToken}
1548
- `;
1549
- }
1550
- if (userAnswers.mode === "LangGraph" && userAnswers.langSmithApiKey) {
1551
- envContent += `LANGSMITH_API_KEY=${userAnswers.langSmithApiKey}
1552
- `;
1553
- }
1554
- if (envContent) {
1555
- const agentEnvFile = path5.join(agentDir, ".env");
1556
- fs5.writeFileSync(agentEnvFile, envContent, "utf8");
1557
- spinner.text = chalk7.cyan("Added API keys to agent .env file");
1558
- }
1559
- if (userAnswers.mode === "LangGraph" && userAnswers.langSmithApiKey) {
1560
- envContent += `LANGSMITH_API_KEY=${userAnswers.langSmithApiKey}
1561
- `;
1562
- }
1563
- if (envContent) {
1564
- const agentEnvFile = path5.join(agentDir, ".env");
1565
- fs5.writeFileSync(agentEnvFile, envContent, "utf8");
1566
- spinner.text = chalk7.cyan("Added API keys to agent .env file");
1567
- }
1568
- if (envContent) {
1569
- const agentEnvFile = path5.join(agentDir, ".env");
1570
- fs5.writeFileSync(agentEnvFile, envContent, "utf8");
1571
- spinner.text = chalk7.cyan("Added API keys to agent .env file");
1572
- }
1573
- } catch (error) {
1574
- spinner.fail(chalk7.red("Failed to clone agent template"));
1575
- throw error;
1576
- }
1577
- spinner.succeed(`${userAnswers.mode} agent cloned successfully`);
1578
- }
1579
- var AgentTemplates = {
1580
- LangGraph: {
1581
- Starter: {
1582
- Python: "https://github.com/CopilotKit/coagents-starter-langgraph/tree/main/agent-py",
1583
- TypeScript: "https://github.com/CopilotKit/coagents-starter-langgraph/tree/main/agent-js"
1584
- }
1585
- },
1586
- CrewAI: {
1587
- Flows: {
1588
- Starter: "https://github.com/CopilotKit/coagents-starter-crewai-flows/tree/main/agent-py"
1589
- }
1590
- }
1591
- };
1592
-
1593
- // src/lib/init/scaffold/crew-inputs.ts
1594
- import * as fs6 from "fs/promises";
1595
- import ora5 from "ora";
1596
- import * as path6 from "path";
1597
- async function addCrewInputs(url, token) {
1598
- try {
1599
- const spinner = ora5("Analyzing crew inputs...").start();
1600
- const inputs = await getCrewInputs(url, token);
1601
- spinner.text = "Adding inputs to app/copilotkit/page.tsx...";
1602
- let filePath = path6.join(process.cwd(), "app", "copilotkit", "page.tsx");
1603
- try {
1604
- await fs6.access(filePath);
1605
- } catch {
1606
- filePath = path6.join(process.cwd(), "src", "app", "copilotkit", "page.tsx");
1607
- }
1608
- try {
1609
- await fs6.access(filePath);
1610
- } catch {
1611
- throw new Error("app/copilotkit/page.tsx and src/app/copilotkit/page.tsx not found");
1612
- }
1613
- let fileContent = await fs6.readFile(filePath, "utf8");
1614
- const inputsString = JSON.stringify(inputs);
1615
- fileContent = fileContent.replace(/\[["']YOUR_INPUTS_HERE["']\]/g, inputsString);
1616
- await fs6.writeFile(filePath, fileContent, "utf8");
1617
- spinner.succeed("Successfully added crew inputs to app/copilotkit/page.tsx");
1618
- } catch (error) {
1619
- console.error("Error updating crew inputs:", error);
1620
- throw error;
1621
- }
1622
- }
1623
- async function getCrewInputs(url, token) {
1624
- const response = await fetch(`${url.trim()}/inputs`, {
1625
- headers: {
1626
- Authorization: `Bearer ${token}`
1627
- }
1628
- });
1629
- if (!response.ok) {
1630
- throw new Error(`Failed to fetch inputs: ${response.statusText}`);
1631
- }
1632
- const data = await response.json();
1633
- return data.inputs;
1634
- }
1635
-
1636
443
  // src/commands/init.ts
1637
- import chalk8 from "chalk";
1638
- import ora6 from "ora";
1639
444
  var CloudInit = class _CloudInit extends BaseCommand {
1640
- constructor(argv, config, authService = new AuthService()) {
1641
- super(argv, config);
1642
- this.authService = authService;
1643
- }
1644
- trpcClient = null;
1645
- analytics = null;
1646
- startTime = Date.now();
1647
- analyticsQueue = [];
1648
445
  static description = "Set up CopilotKit in your Next.js project, or create a new project if none exists";
1649
446
  static examples = ["<%= config.bin %> init", "<%= config.bin %> init --dir ./my-app"];
1650
447
  static flags = {
@@ -1654,696 +451,14 @@ var CloudInit = class _CloudInit extends BaseCommand {
1654
451
  project: Flags3.string({ description: "project ID (can be found in the Copilot Cloud dashboard)" }),
1655
452
  dir: Flags3.string({ description: "directory of the Next.js project", default: "." })
1656
453
  };
454
+ constructor(argv, config) {
455
+ super(argv, config);
456
+ }
1657
457
  async run() {
1658
458
  const { flags } = await this.parse(_CloudInit);
1659
- try {
1660
- this.analytics = new AnalyticsService();
1661
- const nextJsAppExists = this.isNextJsProject(flags);
1662
- if (!nextJsAppExists) {
1663
- this.log(chalk8.gray("Running copilotkit create to set up a new project...\n"));
1664
- const createCommand = new Create(this.argv, this.config, this.authService);
1665
- await createCommand.run();
1666
- return;
1667
- }
1668
- this.log(chalk8.magenta("\n\u{1FA81} Welcome to CopilotKit"));
1669
- if (flags.booth) {
1670
- this.log(chalk8.gray("Thanks for giving CopilotKit a try! Now, let's try to impress you \u{1F4AA}\n"));
1671
- } else {
1672
- this.log(chalk8.gray("Let's power up your Next.js project with AI capabilities\n"));
1673
- }
1674
- const projectValidated = this.validateProjectCompatibility(flags);
1675
- this.queueAnalytics("cli.init.started", {
1676
- nextjs_detected: projectValidated,
1677
- flags_used: Object.keys(flags).filter((key) => flags[key] !== void 0 && key !== "help")
1678
- });
1679
- let userAnswers;
1680
- let cloudSetupInfo = null;
1681
- if (flags.booth) {
1682
- userAnswers = await this.getBoothAnswers();
1683
- } else {
1684
- const result = await this.getUserAnswers(flags);
1685
- userAnswers = result.config;
1686
- cloudSetupInfo = result.cloudSetupInfo;
1687
- }
1688
- this.queueAnalytics("cli.init.mode_selected", {
1689
- mode: userAnswers.mode,
1690
- cloud_setup_completed: !!cloudSetupInfo,
1691
- deployment_choice: userAnswers.deploymentChoice
1692
- });
1693
- if (userAnswers.mode === "Mastra") {
1694
- this.log(chalk8.magenta(`
1695
- \u{1F517} Please go to https://docs.copilotkit.ai/mastra/quickstart to get started.`));
1696
- process.exit(0);
1697
- } else if (userAnswers.mode === "AG2") {
1698
- this.log(chalk8.magenta(`
1699
- \u{1F517} Please go to https://docs.copilotkit.ai/ag2/quickstart to get started.`));
1700
- process.exit(0);
1701
- } else if (userAnswers.mode === "Agno") {
1702
- this.log(chalk8.magenta(`
1703
- \u{1F517} Please go to https://docs.copilotkit.ai/agno/quickstart to get started.`));
1704
- process.exit(0);
1705
- } else if (userAnswers.mode === "LlamaIndex") {
1706
- this.log(chalk8.magenta(`
1707
- \u{1F517} Please go to https://docs.copilotkit.ai/llamaindex/quickstart to get started.`));
1708
- process.exit(0);
1709
- }
1710
- const needsCloudDeployment2 = userAnswers.deploymentChoice === "Copilot Cloud" || // Branch B choice
1711
- userAnswers.useCopilotCloud === "Yes" || // Branch C choice
1712
- userAnswers.mode === "CrewAI" || // CrewAI always needs cloud
1713
- !userAnswers.deploymentChoice && !userAnswers.useCopilotCloud;
1714
- this.queueAnalytics("cli.init.cloud_deployment_selected", {
1715
- deployment_choice: userAnswers.deploymentChoice,
1716
- use_copilot_cloud: userAnswers.useCopilotCloud,
1717
- needs_cloud_deployment: needsCloudDeployment2,
1718
- mode: userAnswers.mode
1719
- });
1720
- if (needsCloudDeployment2) {
1721
- if (cloudSetupInfo) {
1722
- await this.completeCloudDeploymentSetup(flags, userAnswers, cloudSetupInfo);
1723
- } else {
1724
- await this.setupCloud(flags, userAnswers);
1725
- }
1726
- }
1727
- await scaffoldEnv(flags, userAnswers);
1728
- await scaffoldShadCN(flags, userAnswers);
1729
- let agentScaffolded = false;
1730
- if (!flags.booth) {
1731
- await scaffoldAgent(userAnswers);
1732
- agentScaffolded = true;
1733
- }
1734
- if (userAnswers.crewUrl && userAnswers.crewBearerToken)
1735
- await addCrewInputs(userAnswers.crewUrl, userAnswers.crewBearerToken);
1736
- if (userAnswers.setupIDEDocs === "Yes" && userAnswers.selectedIDE !== "skip") {
1737
- const ideDocsSpinner = ora6({
1738
- text: "Setting up CopilotKit IDE documentation...",
1739
- color: "cyan"
1740
- }).start();
1741
- try {
1742
- await handleIDEDocsSetup(userAnswers.selectedIDE, flags.dir, ideDocsSpinner);
1743
- } catch (error) {
1744
- ideDocsSpinner.fail("IDE documentation setup failed, but you can configure it manually later");
1745
- }
1746
- }
1747
- this.queueAnalytics("cli.init.completed", {
1748
- mode: userAnswers.mode,
1749
- cloud_setup_completed: !!cloudSetupInfo,
1750
- cloud_deployment: needsCloudDeployment2,
1751
- deployment_choice: userAnswers.deploymentChoice,
1752
- agent_scaffolded: agentScaffolded,
1753
- api_key_in_env: !!userAnswers.copilotCloudPublicApiKey,
1754
- duration_ms: Date.now() - this.startTime
1755
- });
1756
- await this.flushAnalytics();
1757
- if (flags.booth) {
1758
- this.log("\n-----\n");
1759
- this.log(chalk8.magenta("\u{1F389} Your CopilotKit setup is complete! \u{1F389}\n"));
1760
- this.log(chalk8.bold("\n\u{1F680} Next steps:"));
1761
- this.log(` - Start the Next.js app: ${chalk8.gray("$")} ${chalk8.cyan("npm run dev")}`);
1762
- this.log(` - Navigate to ${chalk8.blue("http://localhost:3000/copilotkit")}`);
1763
- this.log(` - Talk to your agent.`);
1764
- this.log(chalk8.magenta("\nThanks for giving CopilotKit a try! \u{1FA81}\n"));
1765
- } else {
1766
- this.finalSummary(userAnswers, cloudSetupInfo?.selectedProjectId);
1767
- }
1768
- } catch (error) {
1769
- this.queueAnalytics("cli.init.failed", {
1770
- error: error.message,
1771
- step: "unknown",
1772
- duration_ms: Date.now() - this.startTime
1773
- });
1774
- await this.flushAnalytics();
1775
- this.gracefulError(error.message);
1776
- }
1777
- }
1778
- /**
1779
- * Get A/B/C test branch from feature flags
1780
- */
1781
- async getABCTestBranch() {
1782
- const defaultBranch = "C";
1783
- if (!this.analytics) {
1784
- return defaultBranch;
1785
- }
1786
- try {
1787
- const payload = await this.analytics.getFeatureFlagPayload("enterprise-by-default");
1788
- if (payload && typeof payload === "object" && payload.branch) {
1789
- return payload.branch;
1790
- }
1791
- return defaultBranch;
1792
- } catch (error) {
1793
- return defaultBranch;
1794
- }
1795
- }
1796
- /**
1797
- * Queue an analytics event to be sent later (non-blocking)
1798
- */
1799
- queueAnalytics(event, properties) {
1800
- this.analyticsQueue.push({ event, properties });
1801
- }
1802
- /**
1803
- * Send all queued analytics events in fire-and-forget manner
1804
- */
1805
- async flushAnalytics() {
1806
- if (!this.analytics || this.analyticsQueue.length === 0) {
1807
- return;
1808
- }
1809
- const promises = this.analyticsQueue.map(
1810
- ({ event, properties }) => this.analytics.track({ event, properties }).catch(() => {
1811
- })
1812
- );
1813
- Promise.all(promises).catch(() => {
1814
- });
1815
- if (this.analytics) {
1816
- this.analytics.shutdown().catch(() => {
1817
- });
1818
- }
1819
- }
1820
- async getBoothAnswers() {
1821
- const url = await inquirer4.prompt({
1822
- type: "input",
1823
- message: "\u{1F99C}\u{1F517} What is the LangGraph's agent URL?",
1824
- name: "agentURL",
1825
- validate: (value) => {
1826
- if (!value)
1827
- return "You need a URL to continue, it should be present on the screen. If you need help, feel free to ask!";
1828
- if (!value.includes("http") || !value.includes("://")) return "Please provide a valid URL";
1829
- return true;
1830
- }
1831
- });
1832
- return {
1833
- mode: "LangGraph",
1834
- langGraphPlatformUrl: url.agentURL,
1835
- useCopilotCloud: "No",
1836
- alreadyDeployed: "Yes",
1837
- langGraphPlatform: "Yes"
1838
- };
1839
- }
1840
- async getUserAnswers(flags) {
1841
- const initialAnswers = {};
1842
- Object.keys(flags).forEach((flagName) => {
1843
- if (flagName in ConfigFlags && flags[flagName] !== void 0) {
1844
- const camelCaseFlagName = flagName.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
1845
- if (YES_NO.includes(flags[flagName])) {
1846
- initialAnswers[camelCaseFlagName] = flags[flagName];
1847
- } else if (flags[flagName]) {
1848
- initialAnswers[camelCaseFlagName] = flags[flagName];
1849
- }
1850
- }
1851
- });
1852
- const abcBranch = await this.getABCTestBranch();
1853
- this.queueAnalytics("cli.init.abc_branch_selected", {
1854
- branch: abcBranch
1855
- });
1856
- const questionsForBranch = getQuestionsForBranch(abcBranch);
1857
- let cloudSetupInfo = null;
1858
- let earlyApiKey;
1859
- const inquirerQuestions = questionsForBranch.map((q) => {
1860
- if (initialAnswers[q.name] !== void 0) {
1861
- return null;
1862
- }
1863
- const baseQuestion = {
1864
- name: q.name,
1865
- message: q.message,
1866
- when: (answers2) => {
1867
- const combinedAnswers = { ...initialAnswers, ...answers2 };
1868
- return q.when ? q.when(combinedAnswers) : true;
1869
- },
1870
- default: q.default,
1871
- validate: q.validate
1872
- };
1873
- switch (q.type) {
1874
- case "yes/no":
1875
- return {
1876
- ...baseQuestion,
1877
- type: "list",
1878
- choices: ["Yes", "No"]
1879
- };
1880
- case "select":
1881
- return {
1882
- ...baseQuestion,
1883
- type: "list",
1884
- choices: q.choices
1885
- };
1886
- case "input":
1887
- default:
1888
- return {
1889
- ...baseQuestion,
1890
- type: q.sensitive ? "password" : "input",
1891
- mask: q.sensitive ? "*" : void 0,
1892
- filter: q.sanitize ? (input) => q.sanitize(input) : void 0
1893
- };
1894
- }
1895
- }).filter((q) => q !== null);
1896
- const promptAnswers = await inquirer4.prompt(inquirerQuestions);
1897
- const answers = {
1898
- ...initialAnswers,
1899
- ...promptAnswers,
1900
- ...earlyApiKey && { copilotCloudPublicApiKey: earlyApiKey }
1901
- };
1902
- if (abcBranch === "B" && !cloudSetupInfo) {
1903
- this.log(chalk8.cyan("\n\u{1F511} Now you will get an API key"));
1904
- this.log(chalk8.gray("Setting up your cloud account and retrieving your API key...\n"));
1905
- try {
1906
- const tempConfig = { ...answers, signupForCopilotCloud: "Yes" };
1907
- const cloudSignupResult = await this.setupApiKey(flags, tempConfig);
1908
- cloudSetupInfo = cloudSignupResult;
1909
- answers.copilotCloudPublicApiKey = cloudSignupResult.apiKey;
1910
- if (this.analytics && cloudSetupInfo.cliToken) {
1911
- const trpcClient2 = createTRPCClient(cloudSetupInfo.cliToken);
1912
- const me = await trpcClient2.me.query();
1913
- if (me.user && me.organization) {
1914
- this.analytics = new AnalyticsService({
1915
- userId: me.user.id,
1916
- organizationId: me.organization.id,
1917
- email: me.user.email
1918
- });
1919
- }
1920
- }
1921
- this.queueAnalytics("cli.init.branch_b_api_key_setup_completed", {
1922
- branch: abcBranch,
1923
- projectId: cloudSetupInfo.selectedProjectId || "unknown",
1924
- api_key_retrieved: !!cloudSetupInfo.apiKey
1925
- });
1926
- } catch (error) {
1927
- this.queueAnalytics("cli.init.branch_b_api_key_setup_failed", {
1928
- error: error.message,
1929
- branch: abcBranch
1930
- });
1931
- throw error;
1932
- }
1933
- }
1934
- if (abcBranch === "A" && !cloudSetupInfo) {
1935
- this.log(chalk8.cyan("\n\u{1F511} Now get your API key"));
1936
- this.log(chalk8.gray("Setting up your cloud account and retrieving your API key...\n"));
1937
- try {
1938
- const tempConfig = { ...answers, signupForCopilotCloud: "Yes" };
1939
- const cloudSignupResult = await this.setupApiKey(flags, tempConfig);
1940
- cloudSetupInfo = cloudSignupResult;
1941
- answers.copilotCloudPublicApiKey = cloudSignupResult.apiKey;
1942
- if (this.analytics && cloudSetupInfo.cliToken) {
1943
- const trpcClient2 = createTRPCClient(cloudSetupInfo.cliToken);
1944
- const me = await trpcClient2.me.query();
1945
- if (me.user && me.organization) {
1946
- this.analytics = new AnalyticsService({
1947
- userId: me.user.id,
1948
- organizationId: me.organization.id,
1949
- email: me.user.email
1950
- });
1951
- }
1952
- }
1953
- this.queueAnalytics("cli.init.branch_a_cloud_setup_completed", {
1954
- branch: abcBranch,
1955
- projectId: cloudSetupInfo.selectedProjectId || "unknown",
1956
- api_key_retrieved: !!cloudSetupInfo.apiKey
1957
- });
1958
- } catch (error) {
1959
- this.queueAnalytics("cli.init.branch_a_cloud_setup_failed", {
1960
- error: error.message,
1961
- branch: abcBranch
1962
- });
1963
- throw error;
1964
- }
1965
- }
1966
- if (answers.langGraphPlatform === "No") {
1967
- this.log(
1968
- "\nCurrently the CLI only supports scaffolding LangGraph Platform agents. Use our quickstart guide to get started:\n"
1969
- );
1970
- this.log(chalk8.blue("https://docs.copilotkit.ai/coagents/quickstart/langgraph"));
1971
- process.exit(0);
1972
- }
1973
- try {
1974
- const spinner = ora6({ text: "Validating configuration...", color: "green" }).start();
1975
- const validatedConfig = ConfigSchema.parse(answers);
1976
- spinner.succeed(`\u{1F50D} Configuration validated successfully`);
1977
- return { config: validatedConfig, cloudSetupInfo };
1978
- } catch (error) {
1979
- const spinner = ora6({ text: "Validation failed...", color: "red" }).start();
1980
- if (error.errors) {
1981
- const formattedErrors = error.errors.map((err) => `- ${err.path.join(".")}: ${err.message}`).join("\n");
1982
- spinner.fail(chalk8.red("Configuration validation failed:"));
1983
- console.error(chalk8.red(formattedErrors));
1984
- process.exit(1);
1985
- }
1986
- spinner.fail(chalk8.red("Unexpected validation error:"));
1987
- console.error(chalk8.red(error.message || "Unknown error"));
1988
- process.exit(1);
1989
- }
1990
- }
1991
- async setupCloud(flags, userAnswers) {
1992
- const { cliToken, organization } = await this.authService.requireLogin(this, "cloud-features");
1993
- this.trpcClient = createTRPCClient(cliToken);
1994
- const availableProjects = await this.trpcClient.listOrgProjects.query({ orgId: organization.id });
1995
- let selectedProjectId;
1996
- if (flags.project) {
1997
- if (!availableProjects.some((project) => project.id === flags.project)) {
1998
- this.log(chalk8.red(`\u{1F4C1} Project with ID ${flags.project} not found`));
1999
- process.exit(1);
2000
- }
2001
- selectedProjectId = flags.project;
2002
- this.log(chalk8.green(`\u{1F4C1} Selected project ${selectedProjectId}`));
2003
- } else {
2004
- const { projectId } = await inquirer4.prompt([
2005
- {
2006
- name: "projectId",
2007
- type: "list",
2008
- message: "\u{1F4C1} Choose a project:",
2009
- choices: availableProjects.map((project) => ({
2010
- value: project.id,
2011
- name: `${project.name} (ID: ${project.id})${availableProjects.length === 1 ? " (press Enter to confirm)" : ""}`
2012
- }))
2013
- }
2014
- ]);
2015
- selectedProjectId = projectId;
2016
- }
2017
- const copilotCloudPublicApiKey = await this.trpcClient.getCopilotCloudPublicApiKey.query({
2018
- projectId: selectedProjectId
2019
- });
2020
- try {
2021
- const sanitizedConfig = {
2022
- ...userAnswers,
2023
- copilotCloudPublicApiKey: copilotCloudPublicApiKey?.key,
2024
- crewUrl: userAnswers.crewUrl ? sanitizers.url(userAnswers.crewUrl) : void 0,
2025
- langGraphPlatformUrl: userAnswers.langGraphPlatformUrl ? sanitizers.url(userAnswers.langGraphPlatformUrl) : void 0,
2026
- langGraphRemoteEndpointURL: userAnswers.langGraphRemoteEndpointURL ? sanitizers.url(userAnswers.langGraphRemoteEndpointURL) : void 0,
2027
- crewBearerToken: userAnswers.crewBearerToken ? sanitizers.apiKey(userAnswers.crewBearerToken) : void 0,
2028
- langSmithApiKey: userAnswers.langSmithApiKey ? sanitizers.apiKey(userAnswers.langSmithApiKey) : void 0,
2029
- llmToken: userAnswers.llmToken ? sanitizers.apiKey(userAnswers.llmToken) : void 0
2030
- };
2031
- const updatedConfig = ConfigSchema.parse(sanitizedConfig);
2032
- Object.assign(userAnswers, updatedConfig);
2033
- } catch (error) {
2034
- this.log(chalk8.red(`Failed to update configuration with Copilot Cloud API key: ${error.message}`));
2035
- }
2036
- if (userAnswers.crewUrl && userAnswers.crewName && userAnswers.crewBearerToken) {
2037
- const isFlow = userAnswers.crewType === "Flows";
2038
- const crewSpinner = ora6({
2039
- text: chalk8(`\u{1F465} Adding CrewAI ${isFlow ? "Flow" : "Crew"} to Copilot Cloud...`),
2040
- color: "cyan"
2041
- }).start();
2042
- try {
2043
- await this.trpcClient.createRemoteEndpoint.mutate({
2044
- type: isFlow ? "CrewAIFlows" : "CrewAI",
2045
- projectId: selectedProjectId,
2046
- config: {
2047
- type: isFlow ? "CrewAIFlows" : "CrewAI",
2048
- url: userAnswers.crewUrl,
2049
- // Already sanitized
2050
- agentName: userAnswers.crewName,
2051
- agentDescription: `A helpful CrewAI ${isFlow ? "Flow" : "Crew"}`,
2052
- crewApiBearerToken: userAnswers.crewBearerToken
2053
- }
2054
- });
2055
- crewSpinner.succeed(chalk8(`\u{1F465} CrewAI ${isFlow ? "Flow" : "Crew"} added to Copilot Cloud`));
2056
- } catch (error) {
2057
- crewSpinner.fail(chalk8(`\u{1F465} Failed to add CrewAI ${isFlow ? "Flow" : "Crew"} to Copilot Cloud`));
2058
- console.error(error);
2059
- process.exit(1);
2060
- }
2061
- }
2062
- if (userAnswers.mode === "LangGraph" && userAnswers.useCopilotCloud === "Yes" && userAnswers.alreadyDeployed === "Yes") {
2063
- const langGraphSpinner = ora6({
2064
- text: chalk8("\u{1F99C}\u{1F517} Adding LangGraph to Copilot Cloud..."),
2065
- color: "cyan"
2066
- }).start();
2067
- if (userAnswers.langGraphPlatform === "Yes" && userAnswers.langGraphPlatformUrl) {
2068
- try {
2069
- if (!userAnswers.langSmithApiKey) {
2070
- langGraphSpinner.fail(chalk8("\u{1F99C}\u{1F517} LangSmith API key not found. Please provide a valid LangSmith API key."));
2071
- process.exit(1);
2072
- }
2073
- await this.trpcClient.createLGCRemoteEndpoint.mutate({
2074
- type: "LangGraphCloud",
2075
- projectId: selectedProjectId,
2076
- config: {
2077
- deploymentUrl: userAnswers.langGraphPlatformUrl,
2078
- // Already sanitized
2079
- langsmithApiKey: userAnswers.langSmithApiKey,
2080
- agents: []
2081
- }
2082
- });
2083
- langGraphSpinner.succeed(chalk8("\u{1F99C}\u{1F517} LangGraph Cloud remote endpoint created"));
2084
- } catch (error) {
2085
- langGraphSpinner.fail(chalk8("\u{1F99C}\u{1F517} Failed to create LangGraph Cloud remote endpoint. Please try again."));
2086
- process.exit(1);
2087
- }
2088
- } else if (userAnswers.langGraphRemoteEndpointURL) {
2089
- try {
2090
- await this.trpcClient.createRemoteEndpoint.mutate({
2091
- type: "CopilotKit",
2092
- projectId: selectedProjectId,
2093
- config: {
2094
- type: "CopilotKit",
2095
- url: userAnswers.langGraphRemoteEndpointURL
2096
- // Already sanitized
2097
- }
2098
- });
2099
- langGraphSpinner.succeed(chalk8("\u{1F99C}\u{1F517} LangGraph remote endpoint created"));
2100
- } catch (error) {
2101
- langGraphSpinner.fail(chalk8("\u{1F99C}\u{1F517} Failed to create LangGraph remote endpoint. Please try again."));
2102
- process.exit(1);
2103
- }
2104
- }
2105
- }
2106
- }
2107
- async setupApiKey(flags, userAnswers) {
2108
- this.log(chalk8.cyan("\n\u{1F511} Setting up your API key...\n"));
2109
- const { cliToken, organization } = await this.authService.requireLogin(this, "cloud-features");
2110
- this.trpcClient = createTRPCClient(cliToken);
2111
- const availableProjects = await this.trpcClient.listOrgProjects.query({ orgId: organization.id });
2112
- let selectedProjectId;
2113
- if (flags.project) {
2114
- if (!availableProjects.some((project) => project.id === flags.project)) {
2115
- this.log(chalk8.red(`\u{1F4C1} Project with ID ${flags.project} not found`));
2116
- process.exit(1);
2117
- }
2118
- selectedProjectId = flags.project;
2119
- this.log(chalk8.green(`\u{1F4C1} Selected project ${selectedProjectId}`));
2120
- } else if (availableProjects.length === 1) {
2121
- selectedProjectId = availableProjects[0].id;
2122
- this.log(chalk8.green(`\u{1F4C1} Auto-selected project ${selectedProjectId}`));
2123
- } else {
2124
- const { projectId } = await inquirer4.prompt([
2125
- {
2126
- name: "projectId",
2127
- type: "list",
2128
- message: "\u{1F4C1} Choose a project:",
2129
- choices: availableProjects.map((project) => ({
2130
- value: project.id,
2131
- name: `${project.name} (ID: ${project.id})`
2132
- }))
2133
- }
2134
- ]);
2135
- selectedProjectId = projectId;
2136
- }
2137
- let apiKey;
2138
- if (selectedProjectId) {
2139
- const spinner = ora6({
2140
- text: "Retrieving your API key...",
2141
- color: "cyan"
2142
- }).start();
2143
- try {
2144
- const copilotCloudPublicApiKey = await this.trpcClient.getCopilotCloudPublicApiKey.query({
2145
- projectId: selectedProjectId
2146
- });
2147
- apiKey = copilotCloudPublicApiKey?.key;
2148
- spinner.succeed("\u2705 API key retrieved successfully");
2149
- } catch (error) {
2150
- spinner.fail("Failed to retrieve API key, but continuing with setup");
2151
- console.error(error);
2152
- }
2153
- }
2154
- this.log(chalk8.green("\u2705 API key setup complete!\n"));
2155
- return { cliToken, organization, selectedProjectId, apiKey };
2156
- }
2157
- async completeCloudDeploymentSetup(flags, userAnswers, cloudSetupInfo) {
2158
- if (!this.trpcClient) {
2159
- this.trpcClient = createTRPCClient(cloudSetupInfo.cliToken);
2160
- }
2161
- const selectedProjectId = cloudSetupInfo.selectedProjectId;
2162
- if (userAnswers.crewUrl && userAnswers.crewName && userAnswers.crewBearerToken) {
2163
- const isFlow = userAnswers.crewType === "Flows";
2164
- const crewSpinner = ora6({
2165
- text: chalk8(`\u{1F465} Adding CrewAI ${isFlow ? "Flow" : "Crew"} to Copilot Cloud...`),
2166
- color: "cyan"
2167
- }).start();
2168
- try {
2169
- await this.trpcClient.createRemoteEndpoint.mutate({
2170
- type: isFlow ? "CrewAIFlows" : "CrewAI",
2171
- projectId: selectedProjectId,
2172
- config: {
2173
- type: isFlow ? "CrewAIFlows" : "CrewAI",
2174
- url: userAnswers.crewUrl,
2175
- agentName: userAnswers.crewName,
2176
- agentDescription: `A helpful CrewAI ${isFlow ? "Flow" : "Crew"}`,
2177
- crewApiBearerToken: userAnswers.crewBearerToken
2178
- }
2179
- });
2180
- crewSpinner.succeed(chalk8(`\u{1F465} CrewAI ${isFlow ? "Flow" : "Crew"} added to Copilot Cloud`));
2181
- } catch (error) {
2182
- crewSpinner.fail(chalk8(`\u{1F465} Failed to add CrewAI ${isFlow ? "Flow" : "Crew"} to Copilot Cloud`));
2183
- console.error(error);
2184
- process.exit(1);
2185
- }
2186
- }
2187
- if (userAnswers.mode === "LangGraph" && userAnswers.useCopilotCloud === "Yes" && userAnswers.alreadyDeployed === "Yes") {
2188
- const langGraphSpinner = ora6({
2189
- text: chalk8("\u{1F99C}\u{1F517} Adding LangGraph to Copilot Cloud..."),
2190
- color: "cyan"
2191
- }).start();
2192
- if (userAnswers.langGraphPlatform === "Yes" && userAnswers.langGraphPlatformUrl) {
2193
- try {
2194
- if (!userAnswers.langSmithApiKey) {
2195
- langGraphSpinner.fail(chalk8("\u{1F99C}\u{1F517} LangSmith API key not found. Please provide a valid LangSmith API key."));
2196
- process.exit(1);
2197
- }
2198
- await this.trpcClient.createLGCRemoteEndpoint.mutate({
2199
- type: "LangGraphCloud",
2200
- projectId: selectedProjectId,
2201
- config: {
2202
- deploymentUrl: userAnswers.langGraphPlatformUrl,
2203
- langsmithApiKey: userAnswers.langSmithApiKey,
2204
- agents: []
2205
- }
2206
- });
2207
- langGraphSpinner.succeed(chalk8("\u{1F99C}\u{1F517} LangGraph Cloud remote endpoint created"));
2208
- } catch (error) {
2209
- langGraphSpinner.fail(chalk8("\u{1F99C}\u{1F517} Failed to create LangGraph Cloud remote endpoint. Please try again."));
2210
- process.exit(1);
2211
- }
2212
- } else if (userAnswers.langGraphRemoteEndpointURL) {
2213
- try {
2214
- await this.trpcClient.createRemoteEndpoint.mutate({
2215
- type: "CopilotKit",
2216
- projectId: selectedProjectId,
2217
- config: {
2218
- type: "CopilotKit",
2219
- url: userAnswers.langGraphRemoteEndpointURL
2220
- }
2221
- });
2222
- langGraphSpinner.succeed(chalk8("\u{1F99C}\u{1F517} LangGraph remote endpoint created"));
2223
- } catch (error) {
2224
- langGraphSpinner.fail(chalk8("\u{1F99C}\u{1F517} Failed to create LangGraph remote endpoint. Please try again."));
2225
- process.exit(1);
2226
- }
2227
- }
2228
- }
2229
- }
2230
- isNextJsProject(flags) {
2231
- try {
2232
- const projectPath = path7.resolve(process.cwd(), flags.dir);
2233
- if (!fs7.existsSync(projectPath)) {
2234
- return false;
2235
- }
2236
- const packageJsonPath = path7.join(projectPath, "package.json");
2237
- if (!fs7.existsSync(packageJsonPath)) {
2238
- return false;
2239
- }
2240
- const packageJson = JSON.parse(fs7.readFileSync(packageJsonPath, "utf8"));
2241
- return !!(packageJson.dependencies?.next || packageJson.devDependencies?.next);
2242
- } catch {
2243
- return false;
2244
- }
2245
- }
2246
- validateProjectCompatibility(flags) {
2247
- const spinner = ora6("Checking Next.js project compatibility...").start();
2248
- try {
2249
- if (!this.isNextJsProject(flags)) {
2250
- const projectPath2 = path7.resolve(process.cwd(), flags.dir);
2251
- if (!fs7.existsSync(projectPath2)) {
2252
- spinner.fail(`Directory ${flags.dir} does not exist`);
2253
- throw new Error(`Please provide a valid Next.js project directory.`);
2254
- }
2255
- const packageJsonPath = path7.join(projectPath2, "package.json");
2256
- if (!fs7.existsSync(packageJsonPath)) {
2257
- spinner.fail(`No package.json found in ${projectPath2}`);
2258
- throw new Error(`Please provide a valid Next.js project with a package.json file.`);
2259
- }
2260
- spinner.fail(`Not a Next.js project`);
2261
- throw new Error(
2262
- `Directory ${projectPath2} does not appear to be a Next.js project. Make sure it has next in dependencies.`
2263
- );
2264
- }
2265
- const projectPath = path7.resolve(process.cwd(), flags.dir);
2266
- spinner.succeed(`\u{1F53C} Valid Next.js project detected at ${projectPath}`);
2267
- return true;
2268
- } catch (error) {
2269
- if (!spinner.isSpinning) {
2270
- this.log(chalk8.red(error.message));
2271
- } else {
2272
- spinner.fail(chalk8.red(error.message));
2273
- }
2274
- process.exit(1);
2275
- }
2276
- }
2277
- finalSummary(userAnswers, projectId) {
2278
- let agentDevInstructions = "";
2279
- let agentSetupMessage = "";
2280
- if (userAnswers.mode === "CrewAI") {
2281
- if (userAnswers.crewType === "Crews") {
2282
- agentSetupMessage = `Using your Crew from ${chalk8.cyan(userAnswers.crewUrl || "the provided URL")}.`;
2283
- } else if (userAnswers.crewType === "Flows") {
2284
- agentSetupMessage = `We've scaffolded a ${chalk8.cyan("CrewAI Flow")} agent in the ${chalk8.cyan("./agent")} directory.`;
2285
- agentDevInstructions = "poetry lock && poetry install && poetry run demo";
2286
- }
2287
- }
2288
- switch (userAnswers.mode) {
2289
- case "LangGraph":
2290
- switch (userAnswers.langGraphAgent) {
2291
- case "Python Starter":
2292
- agentSetupMessage = `We've scaffolded a ${chalk8.cyan(userAnswers.langGraphAgent || "LangGraph")} agent in the ${chalk8.cyan("./agent")} directory.`;
2293
- agentDevInstructions = "poetry lock && poetry install && poetry run demo";
2294
- break;
2295
- case "TypeScript Starter":
2296
- agentSetupMessage = `We've scaffolded a ${chalk8.cyan(userAnswers.langGraphAgent || "LangGraph")} agent in the ${chalk8.cyan("./agent")} directory.`;
2297
- agentDevInstructions = "npm install && npm run dev";
2298
- break;
2299
- default:
2300
- break;
2301
- }
2302
- break;
2303
- case "CrewAI":
2304
- switch (userAnswers.crewType) {
2305
- case "Crews":
2306
- agentSetupMessage = `Using your Crew from ${chalk8.cyan(userAnswers.crewUrl || "the provided URL")}.`;
2307
- break;
2308
- case "Flows":
2309
- agentSetupMessage = `We've scaffolded a ${chalk8.cyan("CrewAI Flow")} agent in the ${chalk8.cyan("./agent")} directory.`;
2310
- break;
2311
- }
2312
- break;
2313
- default:
2314
- }
2315
- this.log("\n-----\n");
2316
- this.log(chalk8.magenta("\u{1F389} Your CopilotKit setup is complete! \u{1F389}\n"));
2317
- this.log(chalk8.bold(`\u{1F4CB} Recap`));
2318
- this.log(` - CopilotKit has been added to your Next.js app.`);
2319
- if (agentSetupMessage) this.log(` - ${agentSetupMessage}`);
2320
- const isCloudDeployment = userAnswers.deploymentChoice === "Copilot Cloud" || // Branch B choice
2321
- userAnswers.useCopilotCloud === "Yes" || // Branch C choice
2322
- userAnswers.mode === "CrewAI" || // CrewAI always needs cloud
2323
- userAnswers.copilotCloudPublicApiKey;
2324
- const isSelfHosted = userAnswers.deploymentChoice === "Self-hosted";
2325
- if (isCloudDeployment) {
2326
- this.log(` - \u{1F680} Configured for Copilot Cloud deployment.`);
2327
- } else if (isSelfHosted) {
2328
- this.log(` - \u{1F3E0} Configured for self-hosted deployment.`);
2329
- }
2330
- this.log(chalk8.bold("\n\u{1F680} Next steps:"));
2331
- this.log(` - Start your Next.js app: ${chalk8.gray("$")} ${chalk8.cyan("npm run dev")}`);
2332
- if (agentDevInstructions) {
2333
- this.log(` - Start your agent: ${chalk8.gray("$")} ${chalk8.cyan(`cd agent && ${agentDevInstructions}`)}`);
2334
- if (isCloudDeployment) {
2335
- this.log(
2336
- ` - Create local tunnel for your agent: ${chalk8.gray("$")} ${chalk8.cyan(`npx copilotkit@latest dev --port <value>${projectId ? ` --project ${projectId}` : " [--project <value>]"}`)}`
2337
- );
2338
- }
2339
- }
2340
- this.log(` - Navigate to ${chalk8.blue("http://localhost:3000/copilotkit")}`);
2341
- this.log(` - Talk to your agent.`);
2342
- if (userAnswers.setupIDEDocs === "Yes" && userAnswers.selectedIDE !== "skip") {
2343
- this.log(` - Your IDE now has CopilotKit documentation context for better AI assistance.`);
2344
- }
2345
- this.log(` - Read the docs: ${chalk8.blue("https://docs.copilotkit.ai")}`);
2346
- this.log(chalk8.magenta("\nEnjoy building with CopilotKit \u{1FA81}\n"));
459
+ this.log("`copilotkit init` now routes to `copilotkit create`.");
460
+ const createCommand = new Create([], this.config);
461
+ await createCommand.run();
2347
462
  }
2348
463
  };
2349
464
  export {