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.
- package/bin/run.js +13 -1
- package/dist/commands/base-command.js +7 -6
- package/dist/commands/base-command.js.map +1 -1
- package/dist/commands/create.d.ts +1 -17
- package/dist/commands/create.js +96 -520
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/dev.js +7 -6
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/init.d.ts +1 -27
- package/dist/commands/init.js +104 -1989
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/login.js +7 -6
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.js +7 -6
- package/dist/commands/logout.js.map +1 -1
- package/dist/utils/version.d.ts +1 -1
- package/dist/utils/version.js +1 -1
- package/dist/utils/version.js.map +1 -1
- package/oclif.manifest.json +3 -3
- package/package.json +1 -1
package/dist/commands/init.js
CHANGED
|
@@ -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.
|
|
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
|
|
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
|
|
307
|
-
|
|
308
|
-
return;
|
|
33
|
+
if (process.env.SENTRY_DISABLED !== "true") {
|
|
34
|
+
Sentry.captureException(err);
|
|
309
35
|
}
|
|
310
|
-
|
|
311
|
-
|
|
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" +
|
|
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
|
|
338
|
-
import
|
|
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
|
|
73
|
+
import ora from "ora";
|
|
346
74
|
var streamPipeline = promisify(pipeline);
|
|
347
75
|
var theme = {
|
|
348
|
-
primary:
|
|
349
|
-
secondary:
|
|
350
|
-
tertiary:
|
|
351
|
-
error:
|
|
352
|
-
command:
|
|
353
|
-
success:
|
|
354
|
-
warning:
|
|
355
|
-
divider:
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
455
|
-
this.
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
this.log(theme.
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
this.log(theme.
|
|
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
|
-
|
|
571
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
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 {
|