copilotkit 0.0.45 → 0.0.47
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/dist/commands/base-command.js +1 -1
- package/dist/commands/base-command.js.map +1 -1
- package/dist/commands/create.d.ts +21 -2
- package/dist/commands/create.js +587 -74
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/dev.js +1 -1
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/init.js +1 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/login.js +1 -1
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.js +1 -1
- package/dist/commands/logout.js.map +1 -1
- package/dist/services/events.d.ts +34 -0
- 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 +9 -3
- package/package.json +1 -1
package/dist/commands/create.js
CHANGED
|
@@ -1,55 +1,379 @@
|
|
|
1
1
|
// src/commands/create.ts
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import
|
|
2
|
+
import { Flags, Args } from "@oclif/core";
|
|
3
|
+
import inquirer2 from "inquirer";
|
|
4
|
+
import chalk3 from "chalk";
|
|
5
5
|
import fs from "fs-extra";
|
|
6
6
|
import path from "path";
|
|
7
7
|
import { promisify } from "util";
|
|
8
8
|
import { pipeline } from "stream";
|
|
9
9
|
import { createWriteStream } from "fs";
|
|
10
10
|
import { extract } from "tar";
|
|
11
|
+
import ora2 from "ora";
|
|
12
|
+
|
|
13
|
+
// src/services/auth.service.ts
|
|
14
|
+
import Conf2 from "conf";
|
|
15
|
+
import cors from "cors";
|
|
16
|
+
import express from "express";
|
|
17
|
+
import crypto2 from "node:crypto";
|
|
18
|
+
import open from "open";
|
|
19
|
+
import getPort from "get-port";
|
|
11
20
|
import ora from "ora";
|
|
21
|
+
import chalk from "chalk";
|
|
22
|
+
import inquirer from "inquirer";
|
|
23
|
+
|
|
24
|
+
// src/utils/trpc.ts
|
|
25
|
+
import { createTRPCClient as trpcClient, httpBatchLink } from "@trpc/client";
|
|
26
|
+
import superjson from "superjson";
|
|
27
|
+
var COPILOT_CLOUD_BASE_URL = process.env.COPILOT_CLOUD_BASE_URL || "https://cloud.copilotkit.ai";
|
|
28
|
+
function createTRPCClient(cliToken) {
|
|
29
|
+
return trpcClient({
|
|
30
|
+
links: [
|
|
31
|
+
httpBatchLink({
|
|
32
|
+
url: `${COPILOT_CLOUD_BASE_URL}/api/trpc-cli`,
|
|
33
|
+
transformer: superjson,
|
|
34
|
+
headers: () => {
|
|
35
|
+
return {
|
|
36
|
+
"x-trpc-source": "cli",
|
|
37
|
+
"x-cli-token": cliToken
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
]
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/services/analytics.service.ts
|
|
46
|
+
import { Analytics } from "@segment/analytics-node";
|
|
47
|
+
import { PostHog } from "posthog-node";
|
|
48
|
+
import Conf from "conf";
|
|
49
|
+
var AnalyticsService = class {
|
|
50
|
+
constructor(authData) {
|
|
51
|
+
this.authData = authData;
|
|
52
|
+
if (process.env.SEGMENT_DISABLED === "true") {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const segmentWriteKey = process.env.SEGMENT_WRITE_KEY || "9Pv6QyExYef2P4hPz4gks6QAvNMi2AOf";
|
|
56
|
+
this.globalProperties = {
|
|
57
|
+
service: "cli"
|
|
58
|
+
};
|
|
59
|
+
if (this.authData?.userId) {
|
|
60
|
+
this.userId = this.authData.userId;
|
|
61
|
+
}
|
|
62
|
+
if (this.authData?.email) {
|
|
63
|
+
this.email = this.authData.email;
|
|
64
|
+
this.globalProperties.email = this.authData.email;
|
|
65
|
+
}
|
|
66
|
+
if (this.authData?.organizationId) {
|
|
67
|
+
this.organizationId = this.authData.organizationId;
|
|
68
|
+
}
|
|
69
|
+
this.segment = new Analytics({
|
|
70
|
+
writeKey: segmentWriteKey,
|
|
71
|
+
disable: process.env.SEGMENT_DISABLE === "true"
|
|
72
|
+
});
|
|
73
|
+
if (process.env.POSTHOG_DISABLED !== "true") {
|
|
74
|
+
const posthogKey = process.env.POSTHOG_KEY || "phc_XZdymVYjrph9Mi0xZYGNyCKexxgblXRR1jMENCtdz5Q";
|
|
75
|
+
const posthogHost = process.env.POSTHOG_HOST || "https://eu.i.posthog.com";
|
|
76
|
+
this.posthog = new PostHog(posthogKey, {
|
|
77
|
+
host: posthogHost
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
const config = new Conf({ projectName: "CopilotKitCLI" });
|
|
81
|
+
if (!config.get("anonymousId")) {
|
|
82
|
+
config.set("anonymousId", crypto.randomUUID());
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
segment;
|
|
86
|
+
posthog;
|
|
87
|
+
globalProperties = {};
|
|
88
|
+
userId;
|
|
89
|
+
email;
|
|
90
|
+
organizationId;
|
|
91
|
+
config = new Conf({ projectName: "CopilotKitCLI" });
|
|
92
|
+
getAnonymousId() {
|
|
93
|
+
const anonymousId = this.config.get("anonymousId");
|
|
94
|
+
if (!anonymousId) {
|
|
95
|
+
const anonymousId2 = crypto.randomUUID();
|
|
96
|
+
this.config.set("anonymousId", anonymousId2);
|
|
97
|
+
return anonymousId2;
|
|
98
|
+
}
|
|
99
|
+
return anonymousId;
|
|
100
|
+
}
|
|
101
|
+
track(event) {
|
|
102
|
+
if (!this.segment) {
|
|
103
|
+
return Promise.resolve();
|
|
104
|
+
}
|
|
105
|
+
const payload = {
|
|
106
|
+
userId: this.userId ? this.userId : void 0,
|
|
107
|
+
email: this.email ? this.email : void 0,
|
|
108
|
+
anonymousId: this.getAnonymousId(),
|
|
109
|
+
event: event.event,
|
|
110
|
+
properties: {
|
|
111
|
+
...this.globalProperties,
|
|
112
|
+
...event.properties,
|
|
113
|
+
$groups: this.organizationId ? {
|
|
114
|
+
segment_group: this.organizationId
|
|
115
|
+
} : void 0,
|
|
116
|
+
eventProperties: {
|
|
117
|
+
...event.properties,
|
|
118
|
+
...this.globalProperties
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
return new Promise((resolve, reject) => {
|
|
123
|
+
this.segment.track(payload, (err) => {
|
|
124
|
+
if (err) {
|
|
125
|
+
resolve();
|
|
126
|
+
}
|
|
127
|
+
resolve();
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Check if a feature flag is enabled
|
|
133
|
+
*/
|
|
134
|
+
async isFeatureEnabled(flagKey) {
|
|
135
|
+
if (!this.posthog) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
const distinctId = this.userId || this.getAnonymousId();
|
|
140
|
+
const flag = await this.posthog.isFeatureEnabled(flagKey, distinctId);
|
|
141
|
+
return Boolean(flag);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
console.warn(`Failed to check feature flag ${flagKey}:`, error);
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Get feature flag payload
|
|
149
|
+
*/
|
|
150
|
+
async getFeatureFlagPayload(flagKey) {
|
|
151
|
+
if (!this.posthog) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
const distinctId = this.userId || this.getAnonymousId();
|
|
156
|
+
const payload = await this.posthog.getFeatureFlagPayload(flagKey, distinctId);
|
|
157
|
+
return payload;
|
|
158
|
+
} catch (error) {
|
|
159
|
+
console.warn(`Failed to get feature flag payload ${flagKey}:`, error);
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Shutdown analytics services
|
|
165
|
+
*/
|
|
166
|
+
async shutdown() {
|
|
167
|
+
if (this.posthog) {
|
|
168
|
+
await this.posthog.shutdown();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// src/services/auth.service.ts
|
|
174
|
+
var AuthService = class {
|
|
175
|
+
config = new Conf2({ projectName: "CopilotKitCLI" });
|
|
176
|
+
COPILOT_CLOUD_BASE_URL = process.env.COPILOT_CLOUD_BASE_URL || "https://cloud.copilotkit.ai";
|
|
177
|
+
getToken() {
|
|
178
|
+
return this.config.get("cliToken");
|
|
179
|
+
}
|
|
180
|
+
getCLIToken() {
|
|
181
|
+
const cliToken = this.config.get("cliToken");
|
|
182
|
+
return cliToken;
|
|
183
|
+
}
|
|
184
|
+
async logout(cmd) {
|
|
185
|
+
this.config.delete("cliToken");
|
|
186
|
+
}
|
|
187
|
+
async requireLogin(cmd, context) {
|
|
188
|
+
let cliToken = this.getCLIToken();
|
|
189
|
+
if (!cliToken) {
|
|
190
|
+
try {
|
|
191
|
+
let shouldLogin = true;
|
|
192
|
+
if (context !== "cloud-features") {
|
|
193
|
+
const response = await inquirer.prompt([
|
|
194
|
+
{
|
|
195
|
+
name: "shouldLogin",
|
|
196
|
+
type: "confirm",
|
|
197
|
+
message: "\u{1FA81} You are not yet authenticated. Authenticate with Copilot Cloud? (press Enter to confirm)",
|
|
198
|
+
default: true
|
|
199
|
+
}
|
|
200
|
+
]);
|
|
201
|
+
shouldLogin = response.shouldLogin;
|
|
202
|
+
}
|
|
203
|
+
if (shouldLogin) {
|
|
204
|
+
if (context === "cloud-features") {
|
|
205
|
+
cmd.log(chalk.cyan("\n\u{1F680} Setting up Copilot Cloud authentication for your selected features...\n"));
|
|
206
|
+
}
|
|
207
|
+
const loginResult = await this.login({ exitAfterLogin: false });
|
|
208
|
+
cliToken = loginResult.cliToken;
|
|
209
|
+
return loginResult;
|
|
210
|
+
} else {
|
|
211
|
+
cmd.error("Authentication required to proceed.");
|
|
212
|
+
}
|
|
213
|
+
} catch (error) {
|
|
214
|
+
if (error instanceof Error && error.name === "ExitPromptError") {
|
|
215
|
+
cmd.error(chalk.yellow("\nAuthentication cancelled"));
|
|
216
|
+
}
|
|
217
|
+
throw error;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
let me;
|
|
221
|
+
const trpcClient2 = createTRPCClient(cliToken);
|
|
222
|
+
try {
|
|
223
|
+
me = await trpcClient2.me.query();
|
|
224
|
+
} catch (error) {
|
|
225
|
+
cmd.log(chalk.red("Could not authenticate with Copilot Cloud. Please run: npx copilotkit@latest login"));
|
|
226
|
+
process.exit(1);
|
|
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
|
+
|
|
282
|
+
// src/commands/base-command.ts
|
|
283
|
+
import { Command } from "@oclif/core";
|
|
284
|
+
import Sentry, { consoleIntegration } from "@sentry/node";
|
|
285
|
+
|
|
286
|
+
// src/utils/version.ts
|
|
287
|
+
var LIB_VERSION = "0.0.47";
|
|
288
|
+
|
|
289
|
+
// src/commands/base-command.ts
|
|
290
|
+
import chalk2 from "chalk";
|
|
291
|
+
var BaseCommand = class extends Command {
|
|
292
|
+
async init() {
|
|
293
|
+
await this.checkCLIVersion();
|
|
294
|
+
if (process.env.SENTRY_DISABLED === "true") {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
Sentry.init({
|
|
298
|
+
dsn: process.env.SENTRY_DSN || "https://1eea15d32e2eacb0456a77db5e39aeeb@o4507288195170304.ingest.us.sentry.io/4508581448581120",
|
|
299
|
+
integrations: [consoleIntegration()],
|
|
300
|
+
// Tracing
|
|
301
|
+
tracesSampleRate: 1
|
|
302
|
+
// Capture 100% of the transactions
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
async catch(err) {
|
|
306
|
+
if (process.env.SENTRY_DISABLED === "true") {
|
|
307
|
+
super.catch(err);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
Sentry.captureException(err);
|
|
311
|
+
super.catch(err);
|
|
312
|
+
}
|
|
313
|
+
async finally() {
|
|
314
|
+
if (process.env.SENTRY_DISABLED === "true") {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
Sentry.close();
|
|
318
|
+
}
|
|
319
|
+
async run() {
|
|
320
|
+
}
|
|
321
|
+
async checkCLIVersion() {
|
|
322
|
+
const response = await fetch(`${COPILOT_CLOUD_BASE_URL}/api/healthz`);
|
|
323
|
+
const data = await response.json();
|
|
324
|
+
const cloudVersion = data.cliVersion;
|
|
325
|
+
if (!cloudVersion || cloudVersion === LIB_VERSION) {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
async gracefulError(message) {
|
|
330
|
+
this.log("\n" + chalk2.red(message));
|
|
331
|
+
process.exit(1);
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
// src/commands/create.ts
|
|
12
336
|
var streamPipeline = promisify(pipeline);
|
|
13
337
|
var theme = {
|
|
14
|
-
primary:
|
|
15
|
-
secondary:
|
|
16
|
-
tertiary:
|
|
17
|
-
error:
|
|
18
|
-
command:
|
|
19
|
-
success:
|
|
20
|
-
warning:
|
|
21
|
-
divider:
|
|
338
|
+
primary: chalk3.magenta,
|
|
339
|
+
secondary: chalk3.gray,
|
|
340
|
+
tertiary: chalk3.gray,
|
|
341
|
+
error: chalk3.red,
|
|
342
|
+
command: chalk3.blue,
|
|
343
|
+
success: chalk3.green,
|
|
344
|
+
warning: chalk3.yellow,
|
|
345
|
+
divider: chalk3.gray("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"),
|
|
22
346
|
bottomPadding: ""
|
|
23
347
|
};
|
|
24
348
|
var TEMPLATE_REPOS = {
|
|
25
349
|
"langgraph-py": "copilotkit/with-langgraph-python",
|
|
26
350
|
"langgraph-js": "copilotkit/with-langgraph-js",
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
351
|
+
mastra: "copilotkit/with-mastra",
|
|
352
|
+
flows: "copilotkit/with-crewai-flows",
|
|
353
|
+
llamaindex: "copilotkit/with-llamaindex",
|
|
354
|
+
agno: "copilotkit/with-agno",
|
|
31
355
|
"pydantic-ai": "copilotkit/with-pydantic-ai",
|
|
32
|
-
|
|
356
|
+
ag2: "ag2ai/ag2-copilotkit-starter"
|
|
33
357
|
};
|
|
34
358
|
var FRAMEWORK_DOCUMENTATION = {
|
|
35
359
|
"langgraph-py": "https://langchain-ai.github.io/langgraph/concepts/why-langgraph",
|
|
36
360
|
"langgraph-js": "https://langchain-ai.github.io/langgraphjs",
|
|
37
|
-
|
|
38
|
-
|
|
361
|
+
flows: "https://docs.crewai.com/guides/flows/first-flow",
|
|
362
|
+
mastra: "https://mastra.ai/en/docs",
|
|
39
363
|
"pydantic-ai": "https://ai.pydantic.dev/ag-ui/",
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
364
|
+
llamaindex: "https://docs.llamaindex.ai/en/stable",
|
|
365
|
+
agno: "https://docs.agno.com/",
|
|
366
|
+
ag2: "https://docs.ag2.ai/latest/docs/user-guide/basic-concepts/overview"
|
|
43
367
|
};
|
|
44
368
|
var FRAMEWORK_EMOJI = {
|
|
45
369
|
"langgraph-js": "\u{1F99C}",
|
|
46
370
|
"langgraph-py": "\u{1F99C}",
|
|
47
|
-
|
|
48
|
-
|
|
371
|
+
flows: "\u{1F465}",
|
|
372
|
+
mastra: "\u{1F311}",
|
|
49
373
|
"pydantic-ai": "\u{1F53C}",
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
374
|
+
llamaindex: "\u{1F999}",
|
|
375
|
+
ag2: "\u{1F916}",
|
|
376
|
+
agno: "\u{1F170}\uFE0F"
|
|
53
377
|
};
|
|
54
378
|
var KITE = `
|
|
55
379
|
\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\u28FF\u28FF\u28FF\u28FF\u28FF
|
|
@@ -68,14 +392,23 @@ var KITE = `
|
|
|
68
392
|
\u287F\u281B\u2800\u2800\u28B4\u28FE\u28F7\u28F6\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28E4\u28FF\u28FE\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF
|
|
69
393
|
\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
|
|
70
394
|
`;
|
|
71
|
-
var Create = class _Create extends
|
|
72
|
-
|
|
395
|
+
var Create = class _Create extends BaseCommand {
|
|
396
|
+
constructor(argv, config, authService = new AuthService()) {
|
|
397
|
+
super(argv, config);
|
|
398
|
+
this.authService = authService;
|
|
399
|
+
}
|
|
400
|
+
trpcClient = null;
|
|
401
|
+
analytics = null;
|
|
402
|
+
startTime = Date.now();
|
|
403
|
+
analyticsQueue = [];
|
|
404
|
+
static description = "Create a new CopilotKit project with Next.js and Cloud setup";
|
|
73
405
|
static examples = [
|
|
74
406
|
"$ copilotkit create my-app",
|
|
75
407
|
"$ copilotkit create my-app --framework langgraph-js",
|
|
76
408
|
"$ copilotkit create -n my-app -f langgraph-js"
|
|
77
409
|
];
|
|
78
410
|
static flags = {
|
|
411
|
+
...BaseCommand.flags,
|
|
79
412
|
framework: Flags.string({
|
|
80
413
|
char: "f",
|
|
81
414
|
description: "Agent framework to use",
|
|
@@ -92,6 +425,9 @@ var Create = class _Create extends Command {
|
|
|
92
425
|
description: "Removes the banner",
|
|
93
426
|
default: false,
|
|
94
427
|
required: false
|
|
428
|
+
}),
|
|
429
|
+
project: Flags.string({
|
|
430
|
+
description: "project ID (can be found in the Copilot Cloud dashboard)"
|
|
95
431
|
})
|
|
96
432
|
};
|
|
97
433
|
static args = {
|
|
@@ -102,58 +438,141 @@ var Create = class _Create extends Command {
|
|
|
102
438
|
};
|
|
103
439
|
async run() {
|
|
104
440
|
const { args, flags } = await this.parse(_Create);
|
|
105
|
-
|
|
106
|
-
this.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
this.log(
|
|
441
|
+
try {
|
|
442
|
+
this.analytics = new AnalyticsService();
|
|
443
|
+
if (!flags["no-banner"]) {
|
|
444
|
+
this.log(theme.primary(KITE));
|
|
445
|
+
this.log(theme.primary("~ Welcome to CopilotKit! ~\n"));
|
|
446
|
+
this.log(theme.divider);
|
|
447
|
+
if ((!flags.name || flags.projectName) && !flags.framework) {
|
|
448
|
+
this.log("\n" + theme.secondary("Just a few questions to get started!\n"));
|
|
449
|
+
}
|
|
111
450
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
451
|
+
const projectName = flags.name || args.projectName || await this.promptProjectName();
|
|
452
|
+
const agentFramework = flags.framework || await this.promptAgentFramework();
|
|
453
|
+
this.queueAnalytics("cli.create.started", {
|
|
454
|
+
framework_selected: agentFramework,
|
|
455
|
+
project_name: projectName,
|
|
456
|
+
flags_used: Object.keys(flags).filter((key) => flags[key] !== void 0 && key !== "help")
|
|
457
|
+
});
|
|
458
|
+
const projectDir = path.resolve(process.cwd(), projectName);
|
|
459
|
+
if (fs.existsSync(projectDir)) {
|
|
460
|
+
this.log(theme.error(`
|
|
122
461
|
Directory "${projectName}" already exists.`));
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
462
|
+
this.log(theme.secondary("\nYou can:"));
|
|
463
|
+
this.log(theme.secondary(" 1. Choose a different project name"));
|
|
464
|
+
this.log(theme.secondary(" 2. Remove the existing directory manually if you want to use this name\n"));
|
|
465
|
+
this.exit(1);
|
|
466
|
+
}
|
|
467
|
+
this.log(chalk3.cyan("\n\u{1F511} Now get your API key"));
|
|
468
|
+
this.log(chalk3.gray("Setting up your cloud account and retrieving your API key...\n"));
|
|
469
|
+
let cloudSetupInfo = null;
|
|
470
|
+
try {
|
|
471
|
+
cloudSetupInfo = await this.setupCloudApiKey(flags);
|
|
472
|
+
if (this.analytics && cloudSetupInfo.cliToken) {
|
|
473
|
+
const trpcClient2 = createTRPCClient(cloudSetupInfo.cliToken);
|
|
474
|
+
const me = await trpcClient2.me.query();
|
|
475
|
+
if (me.user && me.organization) {
|
|
476
|
+
this.analytics = new AnalyticsService({
|
|
477
|
+
userId: me.user.id,
|
|
478
|
+
organizationId: me.organization.id,
|
|
479
|
+
email: me.user.email
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
this.queueAnalytics("cli.create.cloud_setup_completed", {
|
|
484
|
+
framework: agentFramework,
|
|
485
|
+
project_id: cloudSetupInfo.selectedProjectId,
|
|
486
|
+
api_key_retrieved: !!cloudSetupInfo.apiKey
|
|
487
|
+
});
|
|
488
|
+
} catch (error) {
|
|
489
|
+
this.queueAnalytics("cli.create.cloud_setup_failed", {
|
|
490
|
+
framework: agentFramework,
|
|
491
|
+
error: error.message
|
|
492
|
+
});
|
|
493
|
+
throw error;
|
|
494
|
+
}
|
|
495
|
+
const options = {
|
|
496
|
+
projectName,
|
|
497
|
+
agentFramework,
|
|
498
|
+
apiKey: cloudSetupInfo?.apiKey,
|
|
499
|
+
projectId: cloudSetupInfo?.selectedProjectId
|
|
500
|
+
};
|
|
501
|
+
const spinner = ora2({
|
|
502
|
+
text: theme.secondary.bold("Creating your project..."),
|
|
503
|
+
color: "cyan",
|
|
504
|
+
spinner: "dots"
|
|
505
|
+
}).start();
|
|
506
|
+
try {
|
|
507
|
+
await fs.ensureDir(projectDir);
|
|
508
|
+
spinner.text = theme.secondary.bold("Downloading template...");
|
|
509
|
+
await this.downloadTemplate(projectDir, options.agentFramework);
|
|
510
|
+
if (options.apiKey) {
|
|
511
|
+
spinner.text = theme.secondary.bold("Configuring API key...");
|
|
512
|
+
await this.configureApiKey(projectDir, options.apiKey);
|
|
513
|
+
}
|
|
514
|
+
spinner.succeed(theme.secondary.bold(`Project "${projectName}" created successfully!`));
|
|
515
|
+
this.queueAnalytics("cli.create.project_created", {
|
|
516
|
+
framework: agentFramework,
|
|
517
|
+
project_name: projectName,
|
|
518
|
+
has_api_key: !!options.apiKey,
|
|
519
|
+
duration_ms: Date.now() - this.startTime
|
|
520
|
+
});
|
|
521
|
+
this.log("\n" + theme.divider);
|
|
522
|
+
this.log(
|
|
523
|
+
"\n" + theme.secondary.bold(
|
|
524
|
+
`\u{1FA81}\u{1F91D}${FRAMEWORK_EMOJI[options.agentFramework]} All set!
|
|
140
525
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
526
|
+
Your project is ready with Copilot Cloud configured.`
|
|
527
|
+
)
|
|
528
|
+
);
|
|
529
|
+
this.log("\n" + theme.secondary("Next steps:"));
|
|
530
|
+
this.log(theme.secondary(` 1. ${theme.command(`cd ${projectName}`)}`));
|
|
531
|
+
this.log(theme.secondary(" 2. Follow the setup instructions in the README.md"));
|
|
532
|
+
if (options.projectId) {
|
|
533
|
+
this.log(
|
|
534
|
+
theme.secondary(
|
|
535
|
+
` 3. Create local tunnel for development: ${theme.command(`npx copilotkit@latest dev --port <value> --project ${options.projectId}`)}`
|
|
536
|
+
)
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
this.log("\n" + theme.secondary("Documentation:"));
|
|
540
|
+
this.log(theme.secondary(" \u2022 ") + theme.command("https://docs.copilotkit.ai"));
|
|
541
|
+
this.log(theme.secondary(" \u2022 ") + theme.command("https://docs.ag-ui.com"));
|
|
542
|
+
this.log(theme.secondary(" \u2022 ") + theme.command(FRAMEWORK_DOCUMENTATION[options.agentFramework]));
|
|
543
|
+
this.log(theme.bottomPadding);
|
|
544
|
+
this.queueAnalytics("cli.create.completed", {
|
|
545
|
+
framework: agentFramework,
|
|
546
|
+
project_name: projectName,
|
|
547
|
+
cloud_setup_completed: !!cloudSetupInfo,
|
|
548
|
+
api_key_configured: !!options.apiKey,
|
|
549
|
+
duration_ms: Date.now() - this.startTime
|
|
550
|
+
});
|
|
551
|
+
await this.flushAnalytics();
|
|
552
|
+
} catch (error) {
|
|
553
|
+
spinner.fail(theme.error(`Failed to create project: ${error.message}`));
|
|
554
|
+
this.queueAnalytics("cli.create.failed", {
|
|
555
|
+
framework: agentFramework,
|
|
556
|
+
project_name: projectName,
|
|
557
|
+
error: error.message,
|
|
558
|
+
step: "project_creation",
|
|
559
|
+
duration_ms: Date.now() - this.startTime
|
|
560
|
+
});
|
|
561
|
+
await this.flushAnalytics();
|
|
562
|
+
this.exit(1);
|
|
563
|
+
}
|
|
150
564
|
} catch (error) {
|
|
151
|
-
|
|
152
|
-
|
|
565
|
+
this.queueAnalytics("cli.create.failed", {
|
|
566
|
+
error: error.message,
|
|
567
|
+
step: "initialization",
|
|
568
|
+
duration_ms: Date.now() - this.startTime
|
|
569
|
+
});
|
|
570
|
+
await this.flushAnalytics();
|
|
571
|
+
this.gracefulError(error.message);
|
|
153
572
|
}
|
|
154
573
|
}
|
|
155
574
|
async promptProjectName() {
|
|
156
|
-
const { projectName } = await
|
|
575
|
+
const { projectName } = await inquirer2.prompt([
|
|
157
576
|
{
|
|
158
577
|
type: "input",
|
|
159
578
|
name: "projectName",
|
|
@@ -173,7 +592,7 @@ You're ready to start building.`));
|
|
|
173
592
|
return projectName;
|
|
174
593
|
}
|
|
175
594
|
async promptAgentFramework() {
|
|
176
|
-
const { framework } = await
|
|
595
|
+
const { framework } = await inquirer2.prompt([
|
|
177
596
|
{
|
|
178
597
|
type: "list",
|
|
179
598
|
name: "framework",
|
|
@@ -212,6 +631,100 @@ You're ready to start building.`));
|
|
|
212
631
|
throw new Error(`Failed to download template: ${error.message}`);
|
|
213
632
|
}
|
|
214
633
|
}
|
|
634
|
+
/**
|
|
635
|
+
* Queue an analytics event to be sent later (non-blocking)
|
|
636
|
+
*/
|
|
637
|
+
queueAnalytics(event, properties) {
|
|
638
|
+
this.analyticsQueue.push({ event, properties });
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Send all queued analytics events in fire-and-forget manner
|
|
642
|
+
*/
|
|
643
|
+
async flushAnalytics() {
|
|
644
|
+
if (!this.analytics || this.analyticsQueue.length === 0) {
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
const promises = this.analyticsQueue.map(
|
|
648
|
+
({ event, properties }) => this.analytics.track({ event, properties }).catch(() => {
|
|
649
|
+
})
|
|
650
|
+
);
|
|
651
|
+
Promise.all(promises).catch(() => {
|
|
652
|
+
});
|
|
653
|
+
if (this.analytics) {
|
|
654
|
+
this.analytics.shutdown().catch(() => {
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
async setupCloudApiKey(flags) {
|
|
659
|
+
const { cliToken, organization } = await this.authService.requireLogin(this, "cloud-features");
|
|
660
|
+
this.trpcClient = createTRPCClient(cliToken);
|
|
661
|
+
const availableProjects = await this.trpcClient.listOrgProjects.query({ orgId: organization.id });
|
|
662
|
+
let selectedProjectId;
|
|
663
|
+
if (flags.project) {
|
|
664
|
+
if (!availableProjects.some((project) => project.id === flags.project)) {
|
|
665
|
+
this.log(chalk3.red(`\u{1F4C1} Project with ID ${flags.project} not found`));
|
|
666
|
+
process.exit(1);
|
|
667
|
+
}
|
|
668
|
+
selectedProjectId = flags.project;
|
|
669
|
+
this.log(chalk3.green(`\u{1F4C1} Selected project ${selectedProjectId}`));
|
|
670
|
+
} else if (availableProjects.length === 1) {
|
|
671
|
+
selectedProjectId = availableProjects[0].id;
|
|
672
|
+
this.log(chalk3.green(`\u{1F4C1} Auto-selected project ${selectedProjectId}`));
|
|
673
|
+
} else {
|
|
674
|
+
const { projectId } = await inquirer2.prompt([
|
|
675
|
+
{
|
|
676
|
+
name: "projectId",
|
|
677
|
+
type: "list",
|
|
678
|
+
message: "\u{1F4C1} Choose a project:",
|
|
679
|
+
choices: availableProjects.map((project) => ({
|
|
680
|
+
value: project.id,
|
|
681
|
+
name: `${project.name} (ID: ${project.id})`
|
|
682
|
+
}))
|
|
683
|
+
}
|
|
684
|
+
]);
|
|
685
|
+
selectedProjectId = projectId;
|
|
686
|
+
}
|
|
687
|
+
const spinner = ora2({
|
|
688
|
+
text: "Retrieving your API key...",
|
|
689
|
+
color: "cyan"
|
|
690
|
+
}).start();
|
|
691
|
+
try {
|
|
692
|
+
const copilotCloudPublicApiKey = await this.trpcClient.getCopilotCloudPublicApiKey.query({
|
|
693
|
+
projectId: selectedProjectId
|
|
694
|
+
});
|
|
695
|
+
if (!copilotCloudPublicApiKey?.key) {
|
|
696
|
+
spinner.fail("Failed to retrieve API key");
|
|
697
|
+
throw new Error("No API key found for the selected project");
|
|
698
|
+
}
|
|
699
|
+
spinner.succeed("\u2705 API key retrieved successfully");
|
|
700
|
+
return {
|
|
701
|
+
cliToken,
|
|
702
|
+
organization,
|
|
703
|
+
selectedProjectId,
|
|
704
|
+
apiKey: copilotCloudPublicApiKey.key
|
|
705
|
+
};
|
|
706
|
+
} catch (error) {
|
|
707
|
+
spinner.fail("Failed to retrieve API key");
|
|
708
|
+
throw error;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
async configureApiKey(projectDir, apiKey) {
|
|
712
|
+
const envPath = path.join(projectDir, ".env.local");
|
|
713
|
+
const envExamplePath = path.join(projectDir, ".env.example");
|
|
714
|
+
try {
|
|
715
|
+
let envContent = "";
|
|
716
|
+
if (await fs.pathExists(envExamplePath)) {
|
|
717
|
+
envContent = await fs.readFile(envExamplePath, "utf8");
|
|
718
|
+
envContent = envContent.replace(/COPILOT_CLOUD_PUBLIC_API_KEY=.*/g, `COPILOT_CLOUD_PUBLIC_API_KEY=${apiKey}`);
|
|
719
|
+
} else {
|
|
720
|
+
envContent = `COPILOT_CLOUD_PUBLIC_API_KEY=${apiKey}
|
|
721
|
+
`;
|
|
722
|
+
}
|
|
723
|
+
await fs.writeFile(envPath, envContent);
|
|
724
|
+
} catch (error) {
|
|
725
|
+
console.warn("Warning: Could not configure API key in .env.local file");
|
|
726
|
+
}
|
|
727
|
+
}
|
|
215
728
|
};
|
|
216
729
|
export {
|
|
217
730
|
Create as default
|