commet 1.10.0 → 2.0.0
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/index.js +989 -593
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -24,13 +24,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/index.ts
|
|
27
|
-
var
|
|
28
|
-
var
|
|
27
|
+
var import_chalk14 = __toESM(require("chalk"));
|
|
28
|
+
var import_commander10 = require("commander");
|
|
29
29
|
|
|
30
30
|
// package.json
|
|
31
31
|
var package_default = {
|
|
32
32
|
name: "commet",
|
|
33
|
-
version: "
|
|
33
|
+
version: "2.0.0",
|
|
34
34
|
description: "Commet CLI - Manage your billing platform from the command line",
|
|
35
35
|
bin: {
|
|
36
36
|
commet: "./bin/commet"
|
|
@@ -87,16 +87,10 @@ var package_default = {
|
|
|
87
87
|
}
|
|
88
88
|
};
|
|
89
89
|
|
|
90
|
-
// src/commands/
|
|
91
|
-
var
|
|
92
|
-
var fs2 = __toESM(require("fs"));
|
|
93
|
-
var os2 = __toESM(require("os"));
|
|
94
|
-
var path2 = __toESM(require("path"));
|
|
95
|
-
var import_prompts = require("@inquirer/prompts");
|
|
96
|
-
var import_chalk3 = __toESM(require("chalk"));
|
|
90
|
+
// src/commands/api-key.ts
|
|
91
|
+
var import_chalk2 = __toESM(require("chalk"));
|
|
97
92
|
var import_commander = require("commander");
|
|
98
|
-
var
|
|
99
|
-
var import_tar = require("tar");
|
|
93
|
+
var import_ora = __toESM(require("ora"));
|
|
100
94
|
|
|
101
95
|
// src/utils/config.ts
|
|
102
96
|
var fs = __toESM(require("fs"));
|
|
@@ -165,55 +159,353 @@ function clearProjectConfig() {
|
|
|
165
159
|
}
|
|
166
160
|
}
|
|
167
161
|
|
|
162
|
+
// src/utils/telemetry.ts
|
|
163
|
+
var CLI_VERSION = true ? "2.0.0" : "0.0.0";
|
|
164
|
+
var TELEMETRY_URL = "https://commet.co/api/cli/telemetry";
|
|
165
|
+
function detectRuntime() {
|
|
166
|
+
if ("Bun" in globalThis) {
|
|
167
|
+
const bun = globalThis.Bun;
|
|
168
|
+
if (bun && typeof bun.version === "string")
|
|
169
|
+
return { name: "bun", version: bun.version };
|
|
170
|
+
}
|
|
171
|
+
if ("Deno" in globalThis) {
|
|
172
|
+
const deno = globalThis.Deno;
|
|
173
|
+
if (deno?.version?.deno)
|
|
174
|
+
return { name: "deno", version: deno.version.deno };
|
|
175
|
+
}
|
|
176
|
+
return { name: "node", version: process.versions.node };
|
|
177
|
+
}
|
|
178
|
+
var cachedClientInfo = null;
|
|
179
|
+
var cachedUserAgent = null;
|
|
180
|
+
function collectClientInfo() {
|
|
181
|
+
const runtime = detectRuntime();
|
|
182
|
+
return {
|
|
183
|
+
sdk: "commet-cli",
|
|
184
|
+
sdkVersion: CLI_VERSION,
|
|
185
|
+
lang: "node",
|
|
186
|
+
langVersion: process.versions.node,
|
|
187
|
+
platform: process.platform,
|
|
188
|
+
arch: process.arch,
|
|
189
|
+
runtime: runtime.name,
|
|
190
|
+
runtimeVersion: runtime.version
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
function getClientInfoHeader() {
|
|
194
|
+
if (!cachedClientInfo) {
|
|
195
|
+
cachedClientInfo = JSON.stringify(collectClientInfo());
|
|
196
|
+
}
|
|
197
|
+
return cachedClientInfo;
|
|
198
|
+
}
|
|
199
|
+
function getUserAgent() {
|
|
200
|
+
if (!cachedUserAgent) {
|
|
201
|
+
const runtime = detectRuntime();
|
|
202
|
+
cachedUserAgent = `commet-cli/${CLI_VERSION} ${runtime.name}/${runtime.version} ${process.platform}/${process.arch}`;
|
|
203
|
+
}
|
|
204
|
+
return cachedUserAgent;
|
|
205
|
+
}
|
|
206
|
+
function isTelemetryDisabled() {
|
|
207
|
+
return process.env.COMMET_TELEMETRY_DISABLED === "1" || process.env.DO_NOT_TRACK === "1";
|
|
208
|
+
}
|
|
209
|
+
function resolveOrgId() {
|
|
210
|
+
if (process.env.COMMET_API_KEY) return null;
|
|
211
|
+
try {
|
|
212
|
+
const config = loadProjectConfig();
|
|
213
|
+
return config?.orgId ?? null;
|
|
214
|
+
} catch {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
var commandStartTime = null;
|
|
219
|
+
var apiRequestMade = false;
|
|
220
|
+
var commandReported = false;
|
|
221
|
+
function markCommandStart() {
|
|
222
|
+
commandStartTime = Date.now();
|
|
223
|
+
apiRequestMade = false;
|
|
224
|
+
commandReported = false;
|
|
225
|
+
}
|
|
226
|
+
function markApiRequest() {
|
|
227
|
+
apiRequestMade = true;
|
|
228
|
+
}
|
|
229
|
+
function sendTelemetry(payload) {
|
|
230
|
+
const controller = new AbortController();
|
|
231
|
+
const timeout = setTimeout(() => controller.abort(), 750);
|
|
232
|
+
fetch(TELEMETRY_URL, {
|
|
233
|
+
method: "POST",
|
|
234
|
+
headers: {
|
|
235
|
+
"Content-Type": "application/json",
|
|
236
|
+
"User-Agent": getUserAgent()
|
|
237
|
+
},
|
|
238
|
+
body: JSON.stringify(payload),
|
|
239
|
+
signal: controller.signal
|
|
240
|
+
}).catch(() => {
|
|
241
|
+
}).finally(() => clearTimeout(timeout));
|
|
242
|
+
}
|
|
243
|
+
function reportCommand(command, outcome, errorCode) {
|
|
244
|
+
if (commandReported) return;
|
|
245
|
+
if (isTelemetryDisabled()) return;
|
|
246
|
+
if (apiRequestMade && outcome === "success") return;
|
|
247
|
+
commandReported = true;
|
|
248
|
+
const durationMs = commandStartTime ? Date.now() - commandStartTime : null;
|
|
249
|
+
const runtime = detectRuntime();
|
|
250
|
+
const orgId = resolveOrgId();
|
|
251
|
+
sendTelemetry({
|
|
252
|
+
type: "command",
|
|
253
|
+
command,
|
|
254
|
+
outcome,
|
|
255
|
+
...errorCode ? { errorCode } : {},
|
|
256
|
+
...orgId ? { orgId } : {},
|
|
257
|
+
cliVersion: CLI_VERSION,
|
|
258
|
+
runtime: runtime.name,
|
|
259
|
+
runtimeVersion: runtime.version,
|
|
260
|
+
platform: process.platform,
|
|
261
|
+
arch: process.arch,
|
|
262
|
+
...durationMs !== null ? { durationMs } : {},
|
|
263
|
+
authMode: process.env.COMMET_API_KEY ? "api_key" : "login"
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
function reportCrash(error) {
|
|
267
|
+
if (commandReported) return;
|
|
268
|
+
if (isTelemetryDisabled()) return;
|
|
269
|
+
commandReported = true;
|
|
270
|
+
const command = process.argv[2] || "(default)";
|
|
271
|
+
const orgId = resolveOrgId();
|
|
272
|
+
const errorName = error instanceof Error ? error.constructor.name : "UnknownError";
|
|
273
|
+
sendTelemetry({
|
|
274
|
+
type: "crash",
|
|
275
|
+
command,
|
|
276
|
+
errorName,
|
|
277
|
+
...orgId ? { orgId } : {},
|
|
278
|
+
cliVersion: CLI_VERSION,
|
|
279
|
+
platform: process.platform,
|
|
280
|
+
arch: process.arch,
|
|
281
|
+
authMode: process.env.COMMET_API_KEY ? "api_key" : "login"
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
function installCrashHandler() {
|
|
285
|
+
process.on("uncaughtException", (error) => {
|
|
286
|
+
reportCrash(error);
|
|
287
|
+
console.error("Fatal:", error.message);
|
|
288
|
+
setTimeout(() => process.exit(1), 800);
|
|
289
|
+
});
|
|
290
|
+
process.on("unhandledRejection", (reason) => {
|
|
291
|
+
reportCrash(reason);
|
|
292
|
+
console.error(
|
|
293
|
+
"Fatal:",
|
|
294
|
+
reason instanceof Error ? reason.message : String(reason)
|
|
295
|
+
);
|
|
296
|
+
setTimeout(() => process.exit(1), 800);
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
168
300
|
// src/utils/api.ts
|
|
169
301
|
var BASE_URL = "https://commet.co";
|
|
170
302
|
async function apiRequest(endpoint, options = {}) {
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
303
|
+
const apiKey = process.env.COMMET_API_KEY;
|
|
304
|
+
const auth = apiKey ? null : loadAuth();
|
|
305
|
+
if (!apiKey && !auth) {
|
|
306
|
+
return {
|
|
307
|
+
error: {
|
|
308
|
+
code: "auth_required",
|
|
309
|
+
message: "Not authenticated. Run `commet login` first."
|
|
310
|
+
}
|
|
311
|
+
};
|
|
174
312
|
}
|
|
175
313
|
try {
|
|
314
|
+
markApiRequest();
|
|
176
315
|
const response = await fetch(endpoint, {
|
|
177
316
|
...options,
|
|
178
317
|
headers: {
|
|
179
318
|
...options.headers,
|
|
180
|
-
|
|
181
|
-
"
|
|
319
|
+
"Content-Type": "application/json",
|
|
320
|
+
"User-Agent": getUserAgent(),
|
|
321
|
+
"commet-client-info": getClientInfoHeader(),
|
|
322
|
+
...apiKey ? { "x-api-key": apiKey } : { Authorization: `Bearer ${auth.token}` }
|
|
182
323
|
}
|
|
183
324
|
});
|
|
184
325
|
if (!response.ok) {
|
|
185
326
|
const errorData = await response.json().catch(() => ({}));
|
|
186
327
|
return {
|
|
187
|
-
error:
|
|
328
|
+
error: {
|
|
329
|
+
code: errorData.code ?? `http_${response.status}`,
|
|
330
|
+
message: errorData.message ?? errorData.error ?? `Request failed with status ${response.status}`
|
|
331
|
+
}
|
|
188
332
|
};
|
|
189
333
|
}
|
|
190
334
|
const data = await response.json();
|
|
191
335
|
return { data };
|
|
192
336
|
} catch (error) {
|
|
193
337
|
return {
|
|
194
|
-
error:
|
|
338
|
+
error: {
|
|
339
|
+
code: "network_error",
|
|
340
|
+
message: error instanceof Error ? error.message : "Unknown error occurred"
|
|
341
|
+
}
|
|
195
342
|
};
|
|
196
343
|
}
|
|
197
344
|
}
|
|
198
345
|
|
|
346
|
+
// src/utils/output.ts
|
|
347
|
+
var import_chalk = __toESM(require("chalk"));
|
|
348
|
+
function isAgentMode(options) {
|
|
349
|
+
if (options?.output === "agent") return true;
|
|
350
|
+
const idx = process.argv.indexOf("--output");
|
|
351
|
+
return idx !== -1 && process.argv[idx + 1] === "agent";
|
|
352
|
+
}
|
|
353
|
+
function exitWithError(error) {
|
|
354
|
+
const command = process.argv[2] || "(default)";
|
|
355
|
+
reportCommand(command, "error", error.code);
|
|
356
|
+
if (isAgentMode()) {
|
|
357
|
+
console.log(JSON.stringify({ error }));
|
|
358
|
+
} else {
|
|
359
|
+
console.log(import_chalk.default.red(`\u2717 ${error.message}`));
|
|
360
|
+
if (error.action) {
|
|
361
|
+
console.log(import_chalk.default.dim(`Run \`${error.action}\``));
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
process.exit(1);
|
|
365
|
+
}
|
|
366
|
+
function requireAuth() {
|
|
367
|
+
if (process.env.COMMET_API_KEY) return;
|
|
368
|
+
if (!authExists()) {
|
|
369
|
+
exitWithError({
|
|
370
|
+
code: "auth_required",
|
|
371
|
+
message: "Not authenticated",
|
|
372
|
+
action: "commet login"
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
function requireOrgContext() {
|
|
377
|
+
if (process.env.COMMET_API_KEY) {
|
|
378
|
+
return { orgId: "__from_api_key__" };
|
|
379
|
+
}
|
|
380
|
+
requireAuth();
|
|
381
|
+
const projectConfig = loadProjectConfig();
|
|
382
|
+
if (!projectConfig) {
|
|
383
|
+
exitWithError({
|
|
384
|
+
code: "project_not_linked",
|
|
385
|
+
message: "No organization linked",
|
|
386
|
+
action: "commet link"
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
return { orgId: projectConfig.orgId };
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// src/commands/api-key.ts
|
|
393
|
+
var apiKeyCommand = new import_commander.Command("api-key").description(
|
|
394
|
+
"Generate an API key for the linked organization. Use it in CI with COMMET_API_KEY env var."
|
|
395
|
+
).option("--name <name>", "Name for the API key", "CLI").option(
|
|
396
|
+
"--output <format>",
|
|
397
|
+
"Output format: human (default) or agent",
|
|
398
|
+
"human"
|
|
399
|
+
).addHelpText(
|
|
400
|
+
"after",
|
|
401
|
+
`
|
|
402
|
+
Examples:
|
|
403
|
+
$ commet api-key Generate a key for the linked org
|
|
404
|
+
$ commet api-key --name "GitHub CI" Name it for easy identification
|
|
405
|
+
$ commet api-key --output agent JSON output with the key
|
|
406
|
+
|
|
407
|
+
Then use it in CI:
|
|
408
|
+
$ COMMET_API_KEY=sk_... commet push --yes
|
|
409
|
+
`
|
|
410
|
+
).action(async (options) => {
|
|
411
|
+
const agentMode = isAgentMode(options);
|
|
412
|
+
if (process.env.COMMET_API_KEY) {
|
|
413
|
+
exitWithError({
|
|
414
|
+
code: "invalid_context",
|
|
415
|
+
message: "Cannot create API keys while using COMMET_API_KEY",
|
|
416
|
+
action: "commet login"
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
requireAuth();
|
|
420
|
+
const projectConfig = loadProjectConfig();
|
|
421
|
+
if (!projectConfig) {
|
|
422
|
+
exitWithError({
|
|
423
|
+
code: "project_not_linked",
|
|
424
|
+
message: "No organization linked",
|
|
425
|
+
action: "commet link"
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
const spinner = agentMode ? null : (0, import_ora.default)("Generating API key...").start();
|
|
429
|
+
const result = await apiRequest(
|
|
430
|
+
`${BASE_URL}/api/cli/api-keys`,
|
|
431
|
+
{
|
|
432
|
+
method: "POST",
|
|
433
|
+
body: JSON.stringify({
|
|
434
|
+
organizationId: projectConfig.orgId,
|
|
435
|
+
name: options.name
|
|
436
|
+
})
|
|
437
|
+
}
|
|
438
|
+
);
|
|
439
|
+
if (result.error || !result.data) {
|
|
440
|
+
if (agentMode) {
|
|
441
|
+
console.log(JSON.stringify({ error: result.error }));
|
|
442
|
+
} else {
|
|
443
|
+
spinner?.fail("Failed to create API key");
|
|
444
|
+
console.error(import_chalk2.default.red("Error:"), result.error?.message);
|
|
445
|
+
}
|
|
446
|
+
process.exit(1);
|
|
447
|
+
}
|
|
448
|
+
const { apiKey } = result.data;
|
|
449
|
+
const isLive = projectConfig.mode === "live";
|
|
450
|
+
if (agentMode) {
|
|
451
|
+
console.log(
|
|
452
|
+
JSON.stringify({
|
|
453
|
+
success: true,
|
|
454
|
+
apiKey,
|
|
455
|
+
mode: projectConfig.mode,
|
|
456
|
+
...isLive ? {
|
|
457
|
+
warning: "This is a live API key. Rotate it before using in production if generated by an agent."
|
|
458
|
+
} : {}
|
|
459
|
+
})
|
|
460
|
+
);
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
spinner?.succeed("API key created");
|
|
464
|
+
console.log("");
|
|
465
|
+
console.log(` ${import_chalk2.default.bold(apiKey)}`);
|
|
466
|
+
console.log("");
|
|
467
|
+
console.log(import_chalk2.default.yellow(" \u26A0 This key is shown only once \u2014 copy it now."));
|
|
468
|
+
if (isLive) {
|
|
469
|
+
console.log(
|
|
470
|
+
import_chalk2.default.yellow(
|
|
471
|
+
" \u26A0 This is a live key. Rotate it from the dashboard before production use."
|
|
472
|
+
)
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
console.log(
|
|
476
|
+
import_chalk2.default.dim("\n Use in CI: COMMET_API_KEY=<key> commet push --yes")
|
|
477
|
+
);
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
// src/commands/create.ts
|
|
481
|
+
var import_node_child_process = require("child_process");
|
|
482
|
+
var fs2 = __toESM(require("fs"));
|
|
483
|
+
var os2 = __toESM(require("os"));
|
|
484
|
+
var path2 = __toESM(require("path"));
|
|
485
|
+
var import_prompts = require("@inquirer/prompts");
|
|
486
|
+
var import_chalk5 = __toESM(require("chalk"));
|
|
487
|
+
var import_commander2 = require("commander");
|
|
488
|
+
var import_ora3 = __toESM(require("ora"));
|
|
489
|
+
var import_tar = require("tar");
|
|
490
|
+
|
|
199
491
|
// src/utils/login-flow.ts
|
|
200
|
-
var
|
|
492
|
+
var import_chalk4 = __toESM(require("chalk"));
|
|
201
493
|
var import_open = __toESM(require("open"));
|
|
202
|
-
var
|
|
494
|
+
var import_ora2 = __toESM(require("ora"));
|
|
203
495
|
|
|
204
496
|
// src/utils/prompt-theme.ts
|
|
205
|
-
var
|
|
206
|
-
var commetColor =
|
|
497
|
+
var import_chalk3 = __toESM(require("chalk"));
|
|
498
|
+
var commetColor = import_chalk3.default.hex("#e8a07c");
|
|
207
499
|
var promptTheme = {
|
|
208
500
|
prefix: commetColor("\u276F"),
|
|
209
501
|
style: {
|
|
210
502
|
answer: commetColor,
|
|
211
|
-
message:
|
|
212
|
-
error:
|
|
213
|
-
help:
|
|
503
|
+
message: import_chalk3.default.bold,
|
|
504
|
+
error: import_chalk3.default.red,
|
|
505
|
+
help: import_chalk3.default.dim,
|
|
214
506
|
highlight: commetColor.bold,
|
|
215
|
-
description:
|
|
216
|
-
defaultAnswer:
|
|
507
|
+
description: import_chalk3.default.dim,
|
|
508
|
+
defaultAnswer: import_chalk3.default.dim
|
|
217
509
|
}
|
|
218
510
|
};
|
|
219
511
|
|
|
@@ -222,7 +514,7 @@ function sleep(ms) {
|
|
|
222
514
|
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
223
515
|
}
|
|
224
516
|
async function performLogin() {
|
|
225
|
-
const spinner = (0,
|
|
517
|
+
const spinner = (0, import_ora2.default)("Initiating login flow...").start();
|
|
226
518
|
try {
|
|
227
519
|
const deviceResponse = await fetch(`${BASE_URL}/api/auth/device/code`, {
|
|
228
520
|
method: "POST",
|
|
@@ -244,18 +536,18 @@ async function performLogin() {
|
|
|
244
536
|
interval = 5
|
|
245
537
|
} = deviceData;
|
|
246
538
|
spinner.stop();
|
|
247
|
-
console.log(
|
|
539
|
+
console.log(import_chalk4.default.bold("\n\u{1F510} Commet CLI Login\n"));
|
|
248
540
|
console.log("Visit the following URL in your browser:");
|
|
249
541
|
console.log(commetColor.underline(verification_uri_complete));
|
|
250
542
|
console.log("\nOr enter this code manually:");
|
|
251
|
-
console.log(
|
|
252
|
-
console.log(
|
|
543
|
+
console.log(import_chalk4.default.bold.green(` ${user_code}`));
|
|
544
|
+
console.log(import_chalk4.default.dim("\nOpening browser...\n"));
|
|
253
545
|
try {
|
|
254
546
|
await (0, import_open.default)(verification_uri_complete);
|
|
255
547
|
} catch {
|
|
256
|
-
console.log(
|
|
548
|
+
console.log(import_chalk4.default.yellow("\u26A0 Could not open browser automatically."));
|
|
257
549
|
}
|
|
258
|
-
const pollSpinner = (0,
|
|
550
|
+
const pollSpinner = (0, import_ora2.default)("Waiting for authorization...").start();
|
|
259
551
|
let pollingInterval = interval;
|
|
260
552
|
let attempts = 0;
|
|
261
553
|
const maxAttempts = Math.floor(180 / pollingInterval);
|
|
@@ -501,22 +793,22 @@ async function installSkills(projectRoot) {
|
|
|
501
793
|
);
|
|
502
794
|
child.on("close", (code) => {
|
|
503
795
|
if (code !== 0) {
|
|
504
|
-
console.log(
|
|
505
|
-
console.log(
|
|
796
|
+
console.log(import_chalk5.default.dim(" You can install them manually by running:"));
|
|
797
|
+
console.log(import_chalk5.default.dim(" npx skills add commet-labs/commet-skills"));
|
|
506
798
|
}
|
|
507
799
|
resolve4();
|
|
508
800
|
});
|
|
509
801
|
});
|
|
510
802
|
}
|
|
511
|
-
var createCommand = new
|
|
803
|
+
var createCommand = new import_commander2.Command("create").description("Create a new Commet app from a template").argument("[name]", "Project name").option(
|
|
512
804
|
"-t, --template <template>",
|
|
513
805
|
"Template to use (fixed, seats, metered, credits, balance-ai, balance-fixed)"
|
|
514
806
|
).option("--org <slug>", "Organization slug or ID (skips selection)").option("--skills", "Install agent skills").option("--no-skills", "Skip agent skills installation").option("-y, --yes", "Accept defaults for optional prompts").option("--ref <ref>", "Git ref to fetch templates from", "main").option("--list", "List available templates").action(async (argName, opts) => {
|
|
515
807
|
if (opts.list) {
|
|
516
|
-
console.log(
|
|
808
|
+
console.log(import_chalk5.default.bold("\nAvailable templates:\n"));
|
|
517
809
|
for (const t of TEMPLATES) {
|
|
518
810
|
console.log(
|
|
519
|
-
` ${commetColor(t.name.padEnd(14))}${
|
|
811
|
+
` ${commetColor(t.name.padEnd(14))}${import_chalk5.default.dim(t.description)}`
|
|
520
812
|
);
|
|
521
813
|
}
|
|
522
814
|
console.log();
|
|
@@ -525,9 +817,9 @@ var createCommand = new import_commander.Command("create").description("Create a
|
|
|
525
817
|
let projectName = argName;
|
|
526
818
|
if (!projectName) {
|
|
527
819
|
if (!isInteractive()) {
|
|
528
|
-
console.log(
|
|
820
|
+
console.log(import_chalk5.default.red("\u2717 Project name is required"));
|
|
529
821
|
console.log(
|
|
530
|
-
|
|
822
|
+
import_chalk5.default.dim("Pass as positional argument: commet create <name>")
|
|
531
823
|
);
|
|
532
824
|
return;
|
|
533
825
|
}
|
|
@@ -537,21 +829,21 @@ var createCommand = new import_commander.Command("create").description("Create a
|
|
|
537
829
|
theme: promptTheme
|
|
538
830
|
});
|
|
539
831
|
} catch {
|
|
540
|
-
console.log(
|
|
832
|
+
console.log(import_chalk5.default.yellow("\n\u26A0 Cancelled"));
|
|
541
833
|
return;
|
|
542
834
|
}
|
|
543
835
|
}
|
|
544
836
|
const dest = path2.resolve(projectName);
|
|
545
837
|
if (fs2.existsSync(dest)) {
|
|
546
838
|
console.log(
|
|
547
|
-
|
|
839
|
+
import_chalk5.default.red(`\u2717 Directory "${projectName}" already exists`)
|
|
548
840
|
);
|
|
549
841
|
return;
|
|
550
842
|
}
|
|
551
843
|
if (!authExists()) {
|
|
552
844
|
if (!isInteractive()) {
|
|
553
|
-
console.log(
|
|
554
|
-
console.log(
|
|
845
|
+
console.log(import_chalk5.default.red("\u2717 Not authenticated"));
|
|
846
|
+
console.log(import_chalk5.default.dim("Run `commet login` first"));
|
|
555
847
|
return;
|
|
556
848
|
}
|
|
557
849
|
const loggedIn = await performLogin();
|
|
@@ -559,11 +851,11 @@ var createCommand = new import_commander.Command("create").description("Create a
|
|
|
559
851
|
return;
|
|
560
852
|
}
|
|
561
853
|
}
|
|
562
|
-
const orgsSpinner = (0,
|
|
854
|
+
const orgsSpinner = (0, import_ora3.default)("Fetching sandbox organizations...").start();
|
|
563
855
|
const orgsResult = await apiRequest(`${BASE_URL}/api/cli/organizations`);
|
|
564
856
|
if (orgsResult.error || !orgsResult.data) {
|
|
565
857
|
orgsSpinner.fail("Failed to fetch organizations");
|
|
566
|
-
console.log(
|
|
858
|
+
console.log(import_chalk5.default.dim(orgsResult.error));
|
|
567
859
|
return;
|
|
568
860
|
}
|
|
569
861
|
const organizations = orgsResult.data.organizations.filter(
|
|
@@ -571,9 +863,9 @@ var createCommand = new import_commander.Command("create").description("Create a
|
|
|
571
863
|
);
|
|
572
864
|
orgsSpinner.stop();
|
|
573
865
|
if (organizations.length === 0) {
|
|
574
|
-
console.log(
|
|
866
|
+
console.log(import_chalk5.default.yellow("\u26A0 No sandbox organizations found"));
|
|
575
867
|
console.log(
|
|
576
|
-
|
|
868
|
+
import_chalk5.default.dim("Create an organization at https://commet.co first")
|
|
577
869
|
);
|
|
578
870
|
return;
|
|
579
871
|
}
|
|
@@ -583,9 +875,9 @@ var createCommand = new import_commander.Command("create").description("Create a
|
|
|
583
875
|
(org) => org.slug === opts.org || org.id === opts.org
|
|
584
876
|
);
|
|
585
877
|
if (!match) {
|
|
586
|
-
console.log(
|
|
878
|
+
console.log(import_chalk5.default.red(`\u2717 Organization "${opts.org}" not found`));
|
|
587
879
|
console.log(
|
|
588
|
-
|
|
880
|
+
import_chalk5.default.dim(
|
|
589
881
|
`Available: ${organizations.map((o) => o.slug).join(", ")}`
|
|
590
882
|
)
|
|
591
883
|
);
|
|
@@ -596,9 +888,9 @@ var createCommand = new import_commander.Command("create").description("Create a
|
|
|
596
888
|
selectedOrg = organizations[0];
|
|
597
889
|
} else {
|
|
598
890
|
if (!isInteractive()) {
|
|
599
|
-
console.log(
|
|
891
|
+
console.log(import_chalk5.default.red("\u2717 Organization is required"));
|
|
600
892
|
console.log(
|
|
601
|
-
|
|
893
|
+
import_chalk5.default.dim(
|
|
602
894
|
`Pass --org=<slug>. Available: ${organizations.map((o) => o.slug).join(", ")}`
|
|
603
895
|
)
|
|
604
896
|
);
|
|
@@ -608,30 +900,30 @@ var createCommand = new import_commander.Command("create").description("Create a
|
|
|
608
900
|
const orgId = await (0, import_prompts.select)({
|
|
609
901
|
message: "Sandbox organization:",
|
|
610
902
|
choices: organizations.map((org) => ({
|
|
611
|
-
name: `${org.name} ${
|
|
903
|
+
name: `${org.name} ${import_chalk5.default.dim(`(${org.slug})`)}`,
|
|
612
904
|
value: org.id
|
|
613
905
|
})),
|
|
614
906
|
theme: promptTheme
|
|
615
907
|
});
|
|
616
908
|
selectedOrg = organizations.find((org) => org.id === orgId);
|
|
617
909
|
} catch {
|
|
618
|
-
console.log(
|
|
910
|
+
console.log(import_chalk5.default.yellow("\n\u26A0 Cancelled"));
|
|
619
911
|
return;
|
|
620
912
|
}
|
|
621
913
|
}
|
|
622
914
|
let template = TEMPLATES.find((t) => t.name === opts.template);
|
|
623
915
|
if (opts.template && !template) {
|
|
624
|
-
console.log(
|
|
916
|
+
console.log(import_chalk5.default.red(`\u2717 Unknown template "${opts.template}"`));
|
|
625
917
|
console.log(
|
|
626
|
-
|
|
918
|
+
import_chalk5.default.dim("Run `commet create --list` to see available templates")
|
|
627
919
|
);
|
|
628
920
|
return;
|
|
629
921
|
}
|
|
630
922
|
if (!template) {
|
|
631
923
|
if (!isInteractive()) {
|
|
632
|
-
console.log(
|
|
924
|
+
console.log(import_chalk5.default.red("\u2717 Template is required"));
|
|
633
925
|
console.log(
|
|
634
|
-
|
|
926
|
+
import_chalk5.default.dim(
|
|
635
927
|
`Pass --template=<name>. Available: ${TEMPLATES.map((t) => t.name).join(", ")}`
|
|
636
928
|
)
|
|
637
929
|
);
|
|
@@ -641,26 +933,26 @@ var createCommand = new import_commander.Command("create").description("Create a
|
|
|
641
933
|
const selected = await (0, import_prompts.select)({
|
|
642
934
|
message: "Billing model:",
|
|
643
935
|
choices: TEMPLATES.map((t) => ({
|
|
644
|
-
name: `${t.name.padEnd(14)} ${
|
|
936
|
+
name: `${t.name.padEnd(14)} ${import_chalk5.default.dim(t.description)}`,
|
|
645
937
|
value: t.name
|
|
646
938
|
})),
|
|
647
939
|
theme: promptTheme
|
|
648
940
|
});
|
|
649
941
|
template = TEMPLATES.find((t) => t.name === selected);
|
|
650
942
|
} catch {
|
|
651
|
-
console.log(
|
|
943
|
+
console.log(import_chalk5.default.yellow("\n\u26A0 Cancelled"));
|
|
652
944
|
return;
|
|
653
945
|
}
|
|
654
946
|
}
|
|
655
947
|
const shouldInstallSkills = await resolveSkills(opts);
|
|
656
|
-
const downloadSpinner = (0,
|
|
948
|
+
const downloadSpinner = (0, import_ora3.default)("Downloading template...").start();
|
|
657
949
|
try {
|
|
658
950
|
await downloadTemplate(template.dir, dest, opts.ref);
|
|
659
951
|
downloadSpinner.succeed("Template downloaded");
|
|
660
952
|
} catch (error) {
|
|
661
953
|
downloadSpinner.fail("Failed to download template");
|
|
662
954
|
if (error instanceof Error) {
|
|
663
|
-
console.error(
|
|
955
|
+
console.error(import_chalk5.default.red(error.message));
|
|
664
956
|
}
|
|
665
957
|
if (fs2.existsSync(dest)) {
|
|
666
958
|
fs2.rmSync(dest, { recursive: true, force: true });
|
|
@@ -669,7 +961,7 @@ var createCommand = new import_commander.Command("create").description("Create a
|
|
|
669
961
|
}
|
|
670
962
|
updatePackageJson(dest, projectName);
|
|
671
963
|
copyEnvExample(dest);
|
|
672
|
-
const resolveSpinner = (0,
|
|
964
|
+
const resolveSpinner = (0, import_ora3.default)("Resolving package versions...").start();
|
|
673
965
|
try {
|
|
674
966
|
const count = await resolveWorkspaceDeps(dest);
|
|
675
967
|
if (count > 0) {
|
|
@@ -680,14 +972,14 @@ var createCommand = new import_commander.Command("create").description("Create a
|
|
|
680
972
|
} catch (error) {
|
|
681
973
|
resolveSpinner.fail("Failed to resolve package versions");
|
|
682
974
|
if (error instanceof Error) {
|
|
683
|
-
console.error(
|
|
975
|
+
console.error(import_chalk5.default.red(error.message));
|
|
684
976
|
}
|
|
685
977
|
if (fs2.existsSync(dest)) {
|
|
686
978
|
fs2.rmSync(dest, { recursive: true, force: true });
|
|
687
979
|
}
|
|
688
980
|
return;
|
|
689
981
|
}
|
|
690
|
-
const planSpinner = (0,
|
|
982
|
+
const planSpinner = (0, import_ora3.default)("Creating plans...").start();
|
|
691
983
|
const templateResult = await apiRequest(`${BASE_URL}/api/cli/templates`, {
|
|
692
984
|
method: "POST",
|
|
693
985
|
body: JSON.stringify({
|
|
@@ -697,13 +989,13 @@ var createCommand = new import_commander.Command("create").description("Create a
|
|
|
697
989
|
});
|
|
698
990
|
if (templateResult.error || !templateResult.data) {
|
|
699
991
|
planSpinner.fail("Failed to create plans");
|
|
700
|
-
console.log(
|
|
992
|
+
console.log(import_chalk5.default.dim(templateResult.error));
|
|
701
993
|
} else {
|
|
702
994
|
planSpinner.succeed(
|
|
703
995
|
`Created ${templateResult.data.plansCreated} plans and ${templateResult.data.featuresCreated} features`
|
|
704
996
|
);
|
|
705
997
|
}
|
|
706
|
-
const keySpinner = (0,
|
|
998
|
+
const keySpinner = (0, import_ora3.default)("Creating API key...").start();
|
|
707
999
|
const keyResult = await apiRequest(`${BASE_URL}/api/cli/api-keys`, {
|
|
708
1000
|
method: "POST",
|
|
709
1001
|
body: JSON.stringify({
|
|
@@ -713,8 +1005,8 @@ var createCommand = new import_commander.Command("create").description("Create a
|
|
|
713
1005
|
});
|
|
714
1006
|
if (keyResult.error || !keyResult.data) {
|
|
715
1007
|
keySpinner.fail("Failed to create API key");
|
|
716
|
-
console.log(
|
|
717
|
-
console.log(
|
|
1008
|
+
console.log(import_chalk5.default.dim(keyResult.error));
|
|
1009
|
+
console.log(import_chalk5.default.dim("You can create one manually in the dashboard"));
|
|
718
1010
|
} else {
|
|
719
1011
|
writeApiKeyToEnv(dest, keyResult.data.apiKey);
|
|
720
1012
|
keySpinner.succeed("API key created and saved to .env");
|
|
@@ -723,10 +1015,10 @@ var createCommand = new import_commander.Command("create").description("Create a
|
|
|
723
1015
|
if (shouldInstallSkills) {
|
|
724
1016
|
await installSkills(dest);
|
|
725
1017
|
}
|
|
726
|
-
console.log(
|
|
1018
|
+
console.log(import_chalk5.default.green(`
|
|
727
1019
|
\u2713 Created ${projectName}`));
|
|
728
|
-
console.log(
|
|
729
|
-
console.log(
|
|
1020
|
+
console.log(import_chalk5.default.dim(` Template: ${template.name}`));
|
|
1021
|
+
console.log(import_chalk5.default.dim(` Organization: ${selectedOrg.name} \xB7 sandbox`));
|
|
730
1022
|
console.log();
|
|
731
1023
|
console.log(` ${commetColor("cd")} ${projectName}`);
|
|
732
1024
|
console.log(` ${commetColor("npm install")}`);
|
|
@@ -734,43 +1026,11 @@ var createCommand = new import_commander.Command("create").description("Create a
|
|
|
734
1026
|
console.log();
|
|
735
1027
|
});
|
|
736
1028
|
|
|
737
|
-
// src/commands/info.ts
|
|
738
|
-
var import_chalk4 = __toESM(require("chalk"));
|
|
739
|
-
var import_commander2 = require("commander");
|
|
740
|
-
var infoCommand = new import_commander2.Command("info").description("Display information about the current project").action(async () => {
|
|
741
|
-
console.log(import_chalk4.default.bold("\n\u{1F4E6} Project Information\n"));
|
|
742
|
-
if (!authExists()) {
|
|
743
|
-
console.log(import_chalk4.default.yellow("Authentication: Not logged in"));
|
|
744
|
-
console.log(import_chalk4.default.dim("Run `commet login` to authenticate\n"));
|
|
745
|
-
return;
|
|
746
|
-
}
|
|
747
|
-
console.log(import_chalk4.default.green("Authentication: Logged in \u2713"));
|
|
748
|
-
if (!projectConfigExists()) {
|
|
749
|
-
console.log(import_chalk4.default.yellow("\nProject: Not linked"));
|
|
750
|
-
console.log(
|
|
751
|
-
import_chalk4.default.dim("Run `commet link` to connect to an organization\n")
|
|
752
|
-
);
|
|
753
|
-
return;
|
|
754
|
-
}
|
|
755
|
-
const projectConfig = loadProjectConfig();
|
|
756
|
-
if (!projectConfig) {
|
|
757
|
-
console.log(import_chalk4.default.red("\nProject: Invalid configuration"));
|
|
758
|
-
return;
|
|
759
|
-
}
|
|
760
|
-
console.log(import_chalk4.default.green("\nProject: Linked \u2713"));
|
|
761
|
-
console.log(import_chalk4.default.dim(" Organization:"), projectConfig.orgName);
|
|
762
|
-
console.log(import_chalk4.default.dim(" Organization ID:"), projectConfig.orgId);
|
|
763
|
-
console.log(import_chalk4.default.dim(" Mode:"), projectConfig.mode);
|
|
764
|
-
console.log(
|
|
765
|
-
import_chalk4.default.dim("\nRun `commet pull` to generate type definitions\n")
|
|
766
|
-
);
|
|
767
|
-
});
|
|
768
|
-
|
|
769
1029
|
// src/commands/link.ts
|
|
770
1030
|
var import_prompts2 = require("@inquirer/prompts");
|
|
771
|
-
var
|
|
1031
|
+
var import_chalk6 = __toESM(require("chalk"));
|
|
772
1032
|
var import_commander3 = require("commander");
|
|
773
|
-
var
|
|
1033
|
+
var import_ora4 = __toESM(require("ora"));
|
|
774
1034
|
|
|
775
1035
|
// src/utils/gitignore-updater.ts
|
|
776
1036
|
var fs3 = __toESM(require("fs"));
|
|
@@ -806,192 +1066,199 @@ function updateGitignore(entry) {
|
|
|
806
1066
|
}
|
|
807
1067
|
|
|
808
1068
|
// src/commands/link.ts
|
|
809
|
-
var linkCommand = new import_commander3.Command("link").description(
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
1069
|
+
var linkCommand = new import_commander3.Command("link").description(
|
|
1070
|
+
"Link this project to a Commet organization. Re-run to switch orgs."
|
|
1071
|
+
).option(
|
|
1072
|
+
"--org <slug-or-id>",
|
|
1073
|
+
"Organization slug or ID \u2014 skips interactive selection"
|
|
1074
|
+
).option("--clear", "Unlink project from its organization").option(
|
|
1075
|
+
"--output <format>",
|
|
1076
|
+
"Output format: human (default) or agent",
|
|
1077
|
+
"human"
|
|
1078
|
+
).addHelpText(
|
|
1079
|
+
"after",
|
|
1080
|
+
`
|
|
1081
|
+
Examples:
|
|
1082
|
+
$ commet link Interactive \u2014 choose from a list
|
|
1083
|
+
$ commet link --org acme Non-interactive \u2014 match by slug or ID
|
|
1084
|
+
$ commet link --org other Re-run to switch organization
|
|
1085
|
+
$ commet link --clear Unlink project
|
|
1086
|
+
`
|
|
1087
|
+
).action(async (options) => {
|
|
1088
|
+
const agentMode = isAgentMode(options);
|
|
1089
|
+
if (options.clear) {
|
|
1090
|
+
if (!projectConfigExists()) {
|
|
1091
|
+
if (agentMode) {
|
|
1092
|
+
console.log(JSON.stringify({ success: true, message: "Not linked" }));
|
|
1093
|
+
} else {
|
|
1094
|
+
console.log(
|
|
1095
|
+
import_chalk6.default.yellow("\u26A0 This project is not linked to any organization")
|
|
1096
|
+
);
|
|
1097
|
+
}
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1100
|
+
clearProjectConfig();
|
|
1101
|
+
if (agentMode) {
|
|
1102
|
+
console.log(JSON.stringify({ success: true, action: "unlinked" }));
|
|
1103
|
+
} else {
|
|
1104
|
+
console.log(import_chalk6.default.green("\u2713 Project unlinked"));
|
|
1105
|
+
}
|
|
813
1106
|
return;
|
|
814
1107
|
}
|
|
815
|
-
if (
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
);
|
|
821
|
-
console.log(
|
|
822
|
-
import_chalk5.default.dim(
|
|
823
|
-
"\nRun `commet unlink` first if you want to change the organization"
|
|
824
|
-
)
|
|
825
|
-
);
|
|
826
|
-
return;
|
|
1108
|
+
if (!authExists()) {
|
|
1109
|
+
exitWithError({
|
|
1110
|
+
code: "auth_required",
|
|
1111
|
+
message: "Not authenticated",
|
|
1112
|
+
action: "commet login"
|
|
1113
|
+
});
|
|
827
1114
|
}
|
|
828
|
-
const
|
|
1115
|
+
const currentConfig = projectConfigExists() ? loadProjectConfig() : null;
|
|
1116
|
+
const spinner = agentMode ? null : (0, import_ora4.default)("Fetching organizations...").start();
|
|
829
1117
|
const result = await apiRequest(
|
|
830
1118
|
`${BASE_URL}/api/cli/organizations`
|
|
831
1119
|
);
|
|
832
1120
|
if (result.error || !result.data) {
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
1121
|
+
if (agentMode) {
|
|
1122
|
+
console.log(JSON.stringify({ error: result.error }));
|
|
1123
|
+
} else {
|
|
1124
|
+
spinner?.fail("Failed to fetch organizations");
|
|
1125
|
+
console.error(import_chalk6.default.red("Error:"), result.error?.message);
|
|
1126
|
+
}
|
|
1127
|
+
process.exit(1);
|
|
836
1128
|
}
|
|
837
1129
|
const { organizations } = result.data;
|
|
838
1130
|
if (organizations.length === 0) {
|
|
839
|
-
spinner
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
1131
|
+
spinner?.stop();
|
|
1132
|
+
if (agentMode) {
|
|
1133
|
+
console.log(
|
|
1134
|
+
JSON.stringify({
|
|
1135
|
+
error: {
|
|
1136
|
+
code: "no_organizations",
|
|
1137
|
+
message: "No organizations found"
|
|
1138
|
+
}
|
|
1139
|
+
})
|
|
1140
|
+
);
|
|
1141
|
+
} else {
|
|
1142
|
+
console.log(import_chalk6.default.yellow("\u26A0 No organizations found"));
|
|
1143
|
+
console.log(
|
|
1144
|
+
import_chalk6.default.dim("Create an organization at https://commet.co first")
|
|
1145
|
+
);
|
|
1146
|
+
}
|
|
844
1147
|
return;
|
|
845
1148
|
}
|
|
846
|
-
spinner
|
|
847
|
-
let
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
1149
|
+
spinner?.stop();
|
|
1150
|
+
let selectedOrg;
|
|
1151
|
+
if (options.org) {
|
|
1152
|
+
selectedOrg = organizations.find(
|
|
1153
|
+
(org) => org.slug === options.org || org.id === options.org
|
|
1154
|
+
);
|
|
1155
|
+
if (!selectedOrg) {
|
|
1156
|
+
if (agentMode) {
|
|
1157
|
+
console.log(
|
|
1158
|
+
JSON.stringify({
|
|
1159
|
+
error: {
|
|
1160
|
+
code: "org_not_found",
|
|
1161
|
+
message: `Organization "${options.org}" not found`
|
|
1162
|
+
},
|
|
1163
|
+
organizations: organizations.map((o) => ({
|
|
1164
|
+
slug: o.slug,
|
|
1165
|
+
mode: o.mode
|
|
1166
|
+
}))
|
|
1167
|
+
})
|
|
1168
|
+
);
|
|
1169
|
+
} else {
|
|
1170
|
+
console.log(import_chalk6.default.red(`\u2717 Organization "${options.org}" not found`));
|
|
1171
|
+
console.log(import_chalk6.default.dim("\nAvailable organizations:"));
|
|
1172
|
+
for (const org of organizations) {
|
|
1173
|
+
console.log(import_chalk6.default.dim(` ${org.slug} (${org.mode})`));
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
process.exit(1);
|
|
1177
|
+
}
|
|
1178
|
+
} else {
|
|
1179
|
+
let orgId;
|
|
1180
|
+
try {
|
|
1181
|
+
orgId = await (0, import_prompts2.select)({
|
|
1182
|
+
message: currentConfig ? `Switch from ${currentConfig.orgName}? Select new org:` : "Select organization:",
|
|
1183
|
+
choices: organizations.map((org) => {
|
|
1184
|
+
const isCurrent = currentConfig?.orgId === org.id;
|
|
1185
|
+
const label = isCurrent ? `${org.name} ${import_chalk6.default.dim(`(${org.slug}) \xB7 ${org.mode}`)} ${import_chalk6.default.green("\u2190 current")}` : `${org.name} ${import_chalk6.default.dim(`(${org.slug}) \xB7 ${org.mode}`)}`;
|
|
1186
|
+
return { name: label, value: org.id };
|
|
1187
|
+
}),
|
|
1188
|
+
theme: promptTheme
|
|
1189
|
+
});
|
|
1190
|
+
} catch (_error) {
|
|
1191
|
+
console.log(import_chalk6.default.yellow("\n\u26A0 Cancelled"));
|
|
1192
|
+
return;
|
|
1193
|
+
}
|
|
1194
|
+
selectedOrg = organizations.find((org) => org.id === orgId);
|
|
1195
|
+
if (!selectedOrg) {
|
|
1196
|
+
exitWithError({
|
|
1197
|
+
code: "org_not_found",
|
|
1198
|
+
message: "Organization not found"
|
|
1199
|
+
});
|
|
1200
|
+
}
|
|
860
1201
|
}
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
1202
|
+
if (currentConfig?.orgId === selectedOrg.id) {
|
|
1203
|
+
if (agentMode) {
|
|
1204
|
+
console.log(
|
|
1205
|
+
JSON.stringify({
|
|
1206
|
+
success: true,
|
|
1207
|
+
action: "unchanged",
|
|
1208
|
+
organization: {
|
|
1209
|
+
id: selectedOrg.id,
|
|
1210
|
+
name: selectedOrg.name,
|
|
1211
|
+
slug: selectedOrg.slug,
|
|
1212
|
+
mode: selectedOrg.mode
|
|
1213
|
+
}
|
|
1214
|
+
})
|
|
1215
|
+
);
|
|
1216
|
+
} else {
|
|
1217
|
+
console.log(
|
|
1218
|
+
import_chalk6.default.green(
|
|
1219
|
+
`\u2713 Already linked to ${selectedOrg.name} (${selectedOrg.mode})`
|
|
1220
|
+
)
|
|
1221
|
+
);
|
|
1222
|
+
}
|
|
864
1223
|
return;
|
|
865
1224
|
}
|
|
1225
|
+
const action = currentConfig ? "switched" : "linked";
|
|
866
1226
|
saveProjectConfig({
|
|
867
1227
|
orgId: selectedOrg.id,
|
|
868
1228
|
orgName: selectedOrg.name,
|
|
869
1229
|
mode: selectedOrg.mode
|
|
870
1230
|
});
|
|
871
1231
|
const gitignoreResult = updateGitignore(".commet/");
|
|
872
|
-
|
|
873
|
-
console.log(
|
|
874
|
-
import_chalk5.default.dim(`Organization: ${selectedOrg.name} \xB7 ${selectedOrg.mode}`)
|
|
875
|
-
);
|
|
876
|
-
if (gitignoreResult.success) {
|
|
877
|
-
console.log(import_chalk5.default.green("\u2713 Updated .gitignore"));
|
|
878
|
-
} else {
|
|
879
|
-
console.log(import_chalk5.default.yellow("\u26A0 No .gitignore found"));
|
|
880
|
-
console.log(import_chalk5.default.dim("Add .commet/ to your .gitignore file"));
|
|
881
|
-
}
|
|
882
|
-
console.log(import_chalk5.default.dim("\nRun 'commet pull' to generate TypeScript types"));
|
|
883
|
-
});
|
|
884
|
-
|
|
885
|
-
// src/commands/list.ts
|
|
886
|
-
var import_chalk6 = __toESM(require("chalk"));
|
|
887
|
-
var import_commander4 = require("commander");
|
|
888
|
-
var import_ora4 = __toESM(require("ora"));
|
|
889
|
-
var validTypes = ["features", "seats", "plans"];
|
|
890
|
-
var listCommand = new import_commander4.Command("list").description("List features, seat types, or plans").argument("<type>", "Type to list (features, seats, or plans)").action(async (type) => {
|
|
891
|
-
if (!validTypes.includes(type)) {
|
|
1232
|
+
if (agentMode) {
|
|
892
1233
|
console.log(
|
|
893
|
-
|
|
1234
|
+
JSON.stringify({
|
|
1235
|
+
success: true,
|
|
1236
|
+
action,
|
|
1237
|
+
organization: {
|
|
1238
|
+
id: selectedOrg.id,
|
|
1239
|
+
name: selectedOrg.name,
|
|
1240
|
+
slug: selectedOrg.slug,
|
|
1241
|
+
mode: selectedOrg.mode
|
|
1242
|
+
}
|
|
1243
|
+
})
|
|
894
1244
|
);
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
console.log(import_chalk6.default.dim(" commet list seats"));
|
|
898
|
-
console.log(import_chalk6.default.dim(" commet list plans"));
|
|
899
|
-
return;
|
|
900
|
-
}
|
|
901
|
-
if (!authExists()) {
|
|
902
|
-
console.log(import_chalk6.default.red("\u2717 Not authenticated"));
|
|
903
|
-
console.log(import_chalk6.default.dim("Run `commet login` first"));
|
|
904
|
-
return;
|
|
905
|
-
}
|
|
906
|
-
if (!projectConfigExists()) {
|
|
907
|
-
console.log(import_chalk6.default.red("\u2717 Project not linked"));
|
|
1245
|
+
} else {
|
|
1246
|
+
const verb = action === "switched" ? "Switched to" : "Linked to";
|
|
908
1247
|
console.log(
|
|
909
|
-
import_chalk6.default.
|
|
1248
|
+
import_chalk6.default.green(`
|
|
1249
|
+
\u2713 ${verb} ${selectedOrg.name} (${selectedOrg.mode})`)
|
|
910
1250
|
);
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
const projectConfig = loadProjectConfig();
|
|
914
|
-
if (!projectConfig) {
|
|
915
|
-
console.log(import_chalk6.default.red("\u2717 Invalid project configuration"));
|
|
916
|
-
return;
|
|
917
|
-
}
|
|
918
|
-
const spinner = (0, import_ora4.default)(`Fetching ${type}...`).start();
|
|
919
|
-
const result = await apiRequest(
|
|
920
|
-
`${BASE_URL}/api/cli/pull?orgId=${projectConfig.orgId}`
|
|
921
|
-
);
|
|
922
|
-
if (result.error || !result.data) {
|
|
923
|
-
spinner.fail(`Failed to fetch ${type}`);
|
|
924
|
-
console.error(import_chalk6.default.red("Error:"), result.error);
|
|
925
|
-
return;
|
|
926
|
-
}
|
|
927
|
-
spinner.stop();
|
|
928
|
-
if (type === "features") {
|
|
929
|
-
const { features } = result.data;
|
|
930
|
-
if (features.length === 0) {
|
|
931
|
-
console.log(import_chalk6.default.yellow("\u26A0 No features found"));
|
|
932
|
-
console.log(
|
|
933
|
-
import_chalk6.default.dim("Create features in your Commet dashboard first")
|
|
934
|
-
);
|
|
935
|
-
return;
|
|
936
|
-
}
|
|
937
|
-
console.log(import_chalk6.default.bold(`
|
|
938
|
-
\u{1F4CA} Features (${features.length})
|
|
939
|
-
`));
|
|
940
|
-
for (const feature of features) {
|
|
941
|
-
console.log(import_chalk6.default.green(`\u2022 ${feature.code} (${feature.type})`));
|
|
942
|
-
console.log(import_chalk6.default.dim(` ${feature.name}`));
|
|
943
|
-
if (feature.description) {
|
|
944
|
-
console.log(import_chalk6.default.dim(` ${feature.description}`));
|
|
945
|
-
}
|
|
946
|
-
console.log("");
|
|
947
|
-
}
|
|
948
|
-
} else if (type === "seats") {
|
|
949
|
-
const { seatTypes } = result.data;
|
|
950
|
-
if (seatTypes.length === 0) {
|
|
951
|
-
console.log(import_chalk6.default.yellow("\u26A0 No seat types found"));
|
|
952
|
-
console.log(
|
|
953
|
-
import_chalk6.default.dim("Create seat types in your Commet dashboard first")
|
|
954
|
-
);
|
|
955
|
-
return;
|
|
956
|
-
}
|
|
957
|
-
console.log(import_chalk6.default.bold(`
|
|
958
|
-
\u{1F4BA} Seat Types (${seatTypes.length})
|
|
959
|
-
`));
|
|
960
|
-
for (const seatType of seatTypes) {
|
|
961
|
-
console.log(
|
|
962
|
-
import_chalk6.default.green(`\u2022 ${seatType.code}${seatType.isFree ? " (Free)" : ""}`)
|
|
963
|
-
);
|
|
964
|
-
console.log(import_chalk6.default.dim(` ${seatType.name}`));
|
|
965
|
-
if (seatType.description) {
|
|
966
|
-
console.log(import_chalk6.default.dim(` ${seatType.description}`));
|
|
967
|
-
}
|
|
968
|
-
console.log("");
|
|
969
|
-
}
|
|
970
|
-
} else {
|
|
971
|
-
const { plans } = result.data;
|
|
972
|
-
if (plans.length === 0) {
|
|
973
|
-
console.log(import_chalk6.default.yellow("\u26A0 No plans found"));
|
|
974
|
-
console.log(import_chalk6.default.dim("Create plans in your Commet dashboard first"));
|
|
975
|
-
return;
|
|
976
|
-
}
|
|
977
|
-
console.log(import_chalk6.default.bold(`
|
|
978
|
-
\u{1F4CB} Plans (${plans.length})
|
|
979
|
-
`));
|
|
980
|
-
for (const plan of plans) {
|
|
981
|
-
console.log(import_chalk6.default.green(`\u2022 ${plan.code}`));
|
|
982
|
-
console.log(import_chalk6.default.dim(` ${plan.name}`));
|
|
983
|
-
if (plan.description) {
|
|
984
|
-
console.log(import_chalk6.default.dim(` ${plan.description}`));
|
|
985
|
-
}
|
|
986
|
-
console.log("");
|
|
1251
|
+
if (gitignoreResult.success && action === "linked") {
|
|
1252
|
+
console.log(import_chalk6.default.green("\u2713 Updated .gitignore"));
|
|
987
1253
|
}
|
|
1254
|
+
console.log(import_chalk6.default.dim("\nRun `commet pull` to sync your config"));
|
|
988
1255
|
}
|
|
989
1256
|
});
|
|
990
1257
|
|
|
991
1258
|
// src/commands/listen.ts
|
|
992
1259
|
var import_ably = __toESM(require("ably"));
|
|
993
1260
|
var import_chalk7 = __toESM(require("chalk"));
|
|
994
|
-
var
|
|
1261
|
+
var import_commander4 = require("commander");
|
|
995
1262
|
function printEventLine(line) {
|
|
996
1263
|
const time = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false });
|
|
997
1264
|
const eventName = import_chalk7.default.yellow(line.event.padEnd(28));
|
|
@@ -1027,64 +1294,52 @@ function resolveTargetUrl(input2) {
|
|
|
1027
1294
|
}
|
|
1028
1295
|
return parsed.toString();
|
|
1029
1296
|
}
|
|
1030
|
-
var listenCommand = new
|
|
1297
|
+
var listenCommand = new import_commander4.Command("listen").description(
|
|
1298
|
+
"Forward webhook events from Commet to your local server in real time. Opens a persistent connection and replays every event as an HTTP POST to your URL."
|
|
1299
|
+
).argument(
|
|
1031
1300
|
"<url>",
|
|
1032
|
-
"URL
|
|
1033
|
-
).option(
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1301
|
+
"Target URL \u2014 a port (3000), host:port (localhost:3000), or full URL"
|
|
1302
|
+
).option(
|
|
1303
|
+
"--events <types>",
|
|
1304
|
+
"Only forward these event types (comma-separated)"
|
|
1305
|
+
).addHelpText(
|
|
1306
|
+
"after",
|
|
1307
|
+
`
|
|
1308
|
+
Examples:
|
|
1309
|
+
$ commet listen 3000 Forward to http://localhost:3000/
|
|
1310
|
+
$ commet listen localhost:3000/webhooks Forward to a specific path
|
|
1311
|
+
$ commet listen 3000 --events invoice.paid Only forward invoice.paid events
|
|
1312
|
+
`
|
|
1313
|
+
).action(async (url, options) => {
|
|
1314
|
+
const { orgId } = requireOrgContext();
|
|
1044
1315
|
let targetUrl;
|
|
1045
1316
|
try {
|
|
1046
1317
|
targetUrl = resolveTargetUrl(url);
|
|
1047
1318
|
} catch (error) {
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1319
|
+
exitWithError({
|
|
1320
|
+
code: "invalid_url",
|
|
1321
|
+
message: error instanceof Error ? error.message : "Invalid URL"
|
|
1322
|
+
});
|
|
1052
1323
|
}
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
if (result.error) {
|
|
1064
|
-
console.log(import_chalk7.default.dim(result.error));
|
|
1065
|
-
}
|
|
1066
|
-
process.exit(1);
|
|
1067
|
-
}
|
|
1068
|
-
return result.data;
|
|
1069
|
-
}
|
|
1070
|
-
const initialSession = await fetchTokenRequest();
|
|
1071
|
-
const { sessionId, channelName, signingSecret, tokenRequest } = initialSession;
|
|
1072
|
-
async function refreshToken() {
|
|
1073
|
-
const result = await apiRequest(
|
|
1074
|
-
`${BASE_URL}/api/cli/listen/refresh`,
|
|
1075
|
-
{
|
|
1076
|
-
method: "POST",
|
|
1077
|
-
body: JSON.stringify({
|
|
1078
|
-
sessionId,
|
|
1079
|
-
organizationId: projectConfig.orgId
|
|
1080
|
-
})
|
|
1081
|
-
}
|
|
1082
|
-
);
|
|
1083
|
-
if (result.error || !result.data) {
|
|
1084
|
-
throw new Error(result.error ?? "Failed to refresh token");
|
|
1324
|
+
const projectConfig = loadProjectConfig();
|
|
1325
|
+
const organizationId = orgId === "__from_api_key__" ? void 0 : orgId;
|
|
1326
|
+
const orgName = projectConfig?.orgName ?? "API key";
|
|
1327
|
+
const startResult = await apiRequest(
|
|
1328
|
+
`${BASE_URL}/api/cli/listen/start`,
|
|
1329
|
+
{
|
|
1330
|
+
method: "POST",
|
|
1331
|
+
body: JSON.stringify({
|
|
1332
|
+
...organizationId ? { organizationId } : {}
|
|
1333
|
+
})
|
|
1085
1334
|
}
|
|
1086
|
-
|
|
1335
|
+
);
|
|
1336
|
+
if (startResult.error || !startResult.data) {
|
|
1337
|
+
exitWithError({
|
|
1338
|
+
code: "listen_failed",
|
|
1339
|
+
message: "Failed to start listen session"
|
|
1340
|
+
});
|
|
1087
1341
|
}
|
|
1342
|
+
const { sessionId, channelName, signingSecret, tokenRequest } = startResult.data;
|
|
1088
1343
|
let isFirstToken = true;
|
|
1089
1344
|
const ably = new import_ably.default.Realtime({
|
|
1090
1345
|
authCallback: async (_tokenParams, callback) => {
|
|
@@ -1094,8 +1349,20 @@ var listenCommand = new import_commander5.Command("listen").description("Forward
|
|
|
1094
1349
|
callback(null, tokenRequest);
|
|
1095
1350
|
return;
|
|
1096
1351
|
}
|
|
1097
|
-
const
|
|
1098
|
-
|
|
1352
|
+
const refreshResult = await apiRequest(
|
|
1353
|
+
`${BASE_URL}/api/cli/listen/refresh`,
|
|
1354
|
+
{
|
|
1355
|
+
method: "POST",
|
|
1356
|
+
body: JSON.stringify({
|
|
1357
|
+
sessionId,
|
|
1358
|
+
...organizationId ? { organizationId } : {}
|
|
1359
|
+
})
|
|
1360
|
+
}
|
|
1361
|
+
);
|
|
1362
|
+
if (refreshResult.error || !refreshResult.data) {
|
|
1363
|
+
throw new Error("Failed to refresh token");
|
|
1364
|
+
}
|
|
1365
|
+
callback(null, refreshResult.data.tokenRequest);
|
|
1099
1366
|
} catch (error) {
|
|
1100
1367
|
callback(
|
|
1101
1368
|
error instanceof Error ? error.message : "Token refresh failed",
|
|
@@ -1122,9 +1389,7 @@ var listenCommand = new import_commander5.Command("listen").description("Forward
|
|
|
1122
1389
|
});
|
|
1123
1390
|
const channel = ably.channels.get(channelName);
|
|
1124
1391
|
console.log("");
|
|
1125
|
-
console.log(
|
|
1126
|
-
import_chalk7.default.green(` \u2713 Authenticated (org: ${projectConfig.orgName})`)
|
|
1127
|
-
);
|
|
1392
|
+
console.log(import_chalk7.default.green(` \u2713 Authenticated (org: ${orgName})`));
|
|
1128
1393
|
console.log(import_chalk7.default.green(" \u2713 Connected to Commet webhook stream"));
|
|
1129
1394
|
console.log(import_chalk7.default.cyan(` \u27F6 Forwarding to ${targetUrl}`));
|
|
1130
1395
|
console.log(import_chalk7.default.dim(` \u27F6 Signing secret: ${signingSecret}`));
|
|
@@ -1144,7 +1409,11 @@ var listenCommand = new import_commander5.Command("listen").description("Forward
|
|
|
1144
1409
|
body: JSON.stringify(payload)
|
|
1145
1410
|
}).then((response) => {
|
|
1146
1411
|
const ms = Math.round(performance.now() - start);
|
|
1147
|
-
printEventLine({
|
|
1412
|
+
printEventLine({
|
|
1413
|
+
event,
|
|
1414
|
+
statusCode: response.status,
|
|
1415
|
+
ms
|
|
1416
|
+
});
|
|
1148
1417
|
}).catch((error) => {
|
|
1149
1418
|
const ms = Math.round(performance.now() - start);
|
|
1150
1419
|
printEventLine({
|
|
@@ -1164,7 +1433,7 @@ var listenCommand = new import_commander5.Command("listen").description("Forward
|
|
|
1164
1433
|
method: "POST",
|
|
1165
1434
|
body: JSON.stringify({
|
|
1166
1435
|
sessionId,
|
|
1167
|
-
organizationId:
|
|
1436
|
+
...organizationId ? { organizationId } : {}
|
|
1168
1437
|
})
|
|
1169
1438
|
});
|
|
1170
1439
|
process.exit(0);
|
|
@@ -1173,8 +1442,23 @@ var listenCommand = new import_commander5.Command("listen").description("Forward
|
|
|
1173
1442
|
|
|
1174
1443
|
// src/commands/login.ts
|
|
1175
1444
|
var import_chalk8 = __toESM(require("chalk"));
|
|
1176
|
-
var
|
|
1177
|
-
var loginCommand = new
|
|
1445
|
+
var import_commander5 = require("commander");
|
|
1446
|
+
var loginCommand = new import_commander5.Command("login").description(
|
|
1447
|
+
"Authenticate with Commet via browser. Opens a device-code flow \u2014 you confirm in the browser and the CLI stores your token locally at ~/.commet/auth.json."
|
|
1448
|
+
).action(async () => {
|
|
1449
|
+
if (process.env.COMMET_API_KEY) {
|
|
1450
|
+
if (isAgentMode()) {
|
|
1451
|
+
console.log(
|
|
1452
|
+
JSON.stringify({
|
|
1453
|
+
success: true,
|
|
1454
|
+
message: "Using COMMET_API_KEY \u2014 login not needed"
|
|
1455
|
+
})
|
|
1456
|
+
);
|
|
1457
|
+
} else {
|
|
1458
|
+
console.log(import_chalk8.default.green("\u2713 Using COMMET_API_KEY \u2014 login not needed"));
|
|
1459
|
+
}
|
|
1460
|
+
return;
|
|
1461
|
+
}
|
|
1178
1462
|
if (authExists()) {
|
|
1179
1463
|
console.log(import_chalk8.default.yellow("\u26A0 You are already logged in."));
|
|
1180
1464
|
console.log(
|
|
@@ -1197,8 +1481,25 @@ var loginCommand = new import_commander6.Command("login").description("Authentic
|
|
|
1197
1481
|
|
|
1198
1482
|
// src/commands/logout.ts
|
|
1199
1483
|
var import_chalk9 = __toESM(require("chalk"));
|
|
1200
|
-
var
|
|
1201
|
-
var logoutCommand = new
|
|
1484
|
+
var import_commander6 = require("commander");
|
|
1485
|
+
var logoutCommand = new import_commander6.Command("logout").description(
|
|
1486
|
+
"Log out and remove stored credentials from ~/.commet/auth.json."
|
|
1487
|
+
).action(async () => {
|
|
1488
|
+
if (process.env.COMMET_API_KEY) {
|
|
1489
|
+
if (isAgentMode()) {
|
|
1490
|
+
console.log(
|
|
1491
|
+
JSON.stringify({
|
|
1492
|
+
success: true,
|
|
1493
|
+
message: "Using COMMET_API_KEY \u2014 no session to clear"
|
|
1494
|
+
})
|
|
1495
|
+
);
|
|
1496
|
+
} else {
|
|
1497
|
+
console.log(
|
|
1498
|
+
import_chalk9.default.green("\u2713 Using COMMET_API_KEY \u2014 no session to clear")
|
|
1499
|
+
);
|
|
1500
|
+
}
|
|
1501
|
+
return;
|
|
1502
|
+
}
|
|
1202
1503
|
if (!authExists()) {
|
|
1203
1504
|
console.log(import_chalk9.default.yellow("\u26A0 You are not logged in."));
|
|
1204
1505
|
return;
|
|
@@ -1207,13 +1508,76 @@ var logoutCommand = new import_commander7.Command("logout").description("Log out
|
|
|
1207
1508
|
console.log(import_chalk9.default.green("\u2713 Successfully logged out"));
|
|
1208
1509
|
});
|
|
1209
1510
|
|
|
1511
|
+
// src/commands/orgs.ts
|
|
1512
|
+
var import_chalk10 = __toESM(require("chalk"));
|
|
1513
|
+
var import_commander7 = require("commander");
|
|
1514
|
+
var import_ora5 = __toESM(require("ora"));
|
|
1515
|
+
var orgsCommand = new import_commander7.Command("orgs").description(
|
|
1516
|
+
"List all organizations you have access to. Shows name, slug, mode (live/sandbox), and which one is currently linked."
|
|
1517
|
+
).option(
|
|
1518
|
+
"--output <format>",
|
|
1519
|
+
"Output format: human (default) or agent",
|
|
1520
|
+
"human"
|
|
1521
|
+
).addHelpText(
|
|
1522
|
+
"after",
|
|
1523
|
+
`
|
|
1524
|
+
Examples:
|
|
1525
|
+
$ commet orgs Show orgs with current selection marked
|
|
1526
|
+
$ commet orgs --json JSON array for agent/CI use
|
|
1527
|
+
|
|
1528
|
+
The slug shown here is what you pass to 'commet link --org <slug>'.
|
|
1529
|
+
`
|
|
1530
|
+
).action(async (options) => {
|
|
1531
|
+
const agentMode = isAgentMode(options);
|
|
1532
|
+
requireAuth();
|
|
1533
|
+
const spinner = agentMode ? null : (0, import_ora5.default)("Fetching organizations...").start();
|
|
1534
|
+
const result = await apiRequest(
|
|
1535
|
+
`${BASE_URL}/api/cli/organizations`
|
|
1536
|
+
);
|
|
1537
|
+
if (result.error || !result.data) {
|
|
1538
|
+
if (agentMode) {
|
|
1539
|
+
console.log(JSON.stringify({ error: result.error }));
|
|
1540
|
+
} else {
|
|
1541
|
+
spinner?.fail("Failed to fetch organizations");
|
|
1542
|
+
console.error(import_chalk10.default.red("Error:"), result.error?.message);
|
|
1543
|
+
}
|
|
1544
|
+
process.exit(1);
|
|
1545
|
+
}
|
|
1546
|
+
spinner?.stop();
|
|
1547
|
+
const { organizations } = result.data;
|
|
1548
|
+
if (agentMode) {
|
|
1549
|
+
console.log(JSON.stringify(organizations));
|
|
1550
|
+
return;
|
|
1551
|
+
}
|
|
1552
|
+
if (organizations.length === 0) {
|
|
1553
|
+
console.log(import_chalk10.default.yellow("\u26A0 No organizations found"));
|
|
1554
|
+
console.log(
|
|
1555
|
+
import_chalk10.default.dim("Create an organization at https://commet.co first")
|
|
1556
|
+
);
|
|
1557
|
+
return;
|
|
1558
|
+
}
|
|
1559
|
+
const currentProject = loadProjectConfig();
|
|
1560
|
+
console.log(import_chalk10.default.bold(`
|
|
1561
|
+
Organizations (${organizations.length})
|
|
1562
|
+
`));
|
|
1563
|
+
for (const org of organizations) {
|
|
1564
|
+
const isCurrent = currentProject?.orgId === org.id;
|
|
1565
|
+
const marker = isCurrent ? import_chalk10.default.green("\u25CF") : import_chalk10.default.dim("\u25CB");
|
|
1566
|
+
const mode = org.mode === "live" ? import_chalk10.default.green(org.mode) : import_chalk10.default.yellow(org.mode);
|
|
1567
|
+
console.log(
|
|
1568
|
+
` ${marker} ${org.name} ${import_chalk10.default.dim(`(${org.slug})`)} ${mode}`
|
|
1569
|
+
);
|
|
1570
|
+
}
|
|
1571
|
+
console.log("");
|
|
1572
|
+
});
|
|
1573
|
+
|
|
1210
1574
|
// src/commands/pull.ts
|
|
1211
1575
|
var fs5 = __toESM(require("fs"));
|
|
1212
1576
|
var path5 = __toESM(require("path"));
|
|
1213
1577
|
var import_prompts3 = require("@inquirer/prompts");
|
|
1214
|
-
var
|
|
1578
|
+
var import_chalk12 = __toESM(require("chalk"));
|
|
1215
1579
|
var import_commander8 = require("commander");
|
|
1216
|
-
var
|
|
1580
|
+
var import_ora6 = __toESM(require("ora"));
|
|
1217
1581
|
|
|
1218
1582
|
// src/utils/config-loader.ts
|
|
1219
1583
|
var fs4 = __toESM(require("fs"));
|
|
@@ -1326,7 +1690,7 @@ function validateConfig(config, configPath) {
|
|
|
1326
1690
|
}
|
|
1327
1691
|
|
|
1328
1692
|
// src/utils/diff.ts
|
|
1329
|
-
var
|
|
1693
|
+
var import_chalk11 = __toESM(require("chalk"));
|
|
1330
1694
|
function computeDiff(config, remote) {
|
|
1331
1695
|
const remoteFeatureMap = new Map(remote.features.map((f) => [f.code, f]));
|
|
1332
1696
|
const remotePlanMap = new Map(remote.plans.map((p) => [p.code, p]));
|
|
@@ -1413,42 +1777,42 @@ function computeDiff(config, remote) {
|
|
|
1413
1777
|
}
|
|
1414
1778
|
function formatDiff(diff) {
|
|
1415
1779
|
const lines = [];
|
|
1416
|
-
lines.push(
|
|
1780
|
+
lines.push(import_chalk11.default.bold("\nFeatures:"));
|
|
1417
1781
|
for (const change of diff.features.changes) {
|
|
1418
1782
|
if (change.action === "create") {
|
|
1419
|
-
lines.push(
|
|
1783
|
+
lines.push(import_chalk11.default.green(` + ${change.code}`));
|
|
1420
1784
|
} else if (change.action === "update") {
|
|
1421
|
-
lines.push(
|
|
1785
|
+
lines.push(import_chalk11.default.yellow(` ~ ${change.code}`));
|
|
1422
1786
|
for (const c of change.changes ?? []) {
|
|
1423
|
-
lines.push(
|
|
1787
|
+
lines.push(import_chalk11.default.dim(` ${c}`));
|
|
1424
1788
|
}
|
|
1425
1789
|
} else {
|
|
1426
|
-
lines.push(
|
|
1790
|
+
lines.push(import_chalk11.default.dim(` ${change.code}`));
|
|
1427
1791
|
}
|
|
1428
1792
|
}
|
|
1429
1793
|
if (diff.features.unmanaged.length > 0) {
|
|
1430
1794
|
lines.push(
|
|
1431
|
-
|
|
1795
|
+
import_chalk11.default.dim(
|
|
1432
1796
|
` ? unmanaged: ${diff.features.unmanaged.join(", ")} (not in config, left as-is)`
|
|
1433
1797
|
)
|
|
1434
1798
|
);
|
|
1435
1799
|
}
|
|
1436
|
-
lines.push(
|
|
1800
|
+
lines.push(import_chalk11.default.bold("\nPlans:"));
|
|
1437
1801
|
for (const change of diff.plans.changes) {
|
|
1438
1802
|
if (change.action === "create") {
|
|
1439
|
-
lines.push(
|
|
1803
|
+
lines.push(import_chalk11.default.green(` + ${change.code}`));
|
|
1440
1804
|
} else if (change.action === "update") {
|
|
1441
|
-
lines.push(
|
|
1805
|
+
lines.push(import_chalk11.default.yellow(` ~ ${change.code}`));
|
|
1442
1806
|
for (const c of change.changes ?? []) {
|
|
1443
|
-
lines.push(
|
|
1807
|
+
lines.push(import_chalk11.default.dim(` ${c}`));
|
|
1444
1808
|
}
|
|
1445
1809
|
} else {
|
|
1446
|
-
lines.push(
|
|
1810
|
+
lines.push(import_chalk11.default.dim(` ${change.code}`));
|
|
1447
1811
|
}
|
|
1448
1812
|
}
|
|
1449
1813
|
if (diff.plans.unmanaged.length > 0) {
|
|
1450
1814
|
lines.push(
|
|
1451
|
-
|
|
1815
|
+
import_chalk11.default.dim(
|
|
1452
1816
|
` ? unmanaged: ${diff.plans.unmanaged.join(", ")} (not in config, left as-is)`
|
|
1453
1817
|
)
|
|
1454
1818
|
);
|
|
@@ -1532,47 +1896,36 @@ function generateConfigFile(features, plans) {
|
|
|
1532
1896
|
}
|
|
1533
1897
|
|
|
1534
1898
|
// src/commands/pull.ts
|
|
1535
|
-
var pullCommand = new import_commander8.Command("pull").description(
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
}
|
|
1557
|
-
const projectConfig = loadProjectConfig();
|
|
1558
|
-
if (!projectConfig) {
|
|
1559
|
-
if (jsonMode) {
|
|
1560
|
-
console.log(JSON.stringify({ error: "Invalid project configuration" }));
|
|
1561
|
-
} else {
|
|
1562
|
-
console.log(import_chalk11.default.red("\u2717 Invalid project configuration"));
|
|
1563
|
-
}
|
|
1564
|
-
process.exit(1);
|
|
1565
|
-
}
|
|
1566
|
-
const spinner = jsonMode ? null : (0, import_ora5.default)("Fetching config from remote...").start();
|
|
1899
|
+
var pullCommand = new import_commander8.Command("pull").description(
|
|
1900
|
+
"Fetch your billing config from Commet and generate (or update) commet.config.ts with features and plans."
|
|
1901
|
+
).option("-y, --yes", "Skip confirmation prompt").option("--dry-run", "Show what would change without writing any files").option(
|
|
1902
|
+
"--output <format>",
|
|
1903
|
+
"Output format: human (default) or agent",
|
|
1904
|
+
"human"
|
|
1905
|
+
).addHelpText(
|
|
1906
|
+
"after",
|
|
1907
|
+
`
|
|
1908
|
+
Examples:
|
|
1909
|
+
$ commet pull Interactive \u2014 shows diff, asks to confirm
|
|
1910
|
+
$ commet pull --dry-run Preview changes without applying
|
|
1911
|
+
$ commet pull --yes Apply without confirmation
|
|
1912
|
+
$ commet pull --output agent --yes Agent/CI \u2014 structured JSON, no prompts
|
|
1913
|
+
$ COMMET_API_KEY=sk_... commet pull --yes CI pipeline
|
|
1914
|
+
`
|
|
1915
|
+
).action(async (options) => {
|
|
1916
|
+
const agentMode = isAgentMode(options);
|
|
1917
|
+
const { orgId } = requireOrgContext();
|
|
1918
|
+
const spinner = agentMode ? null : (0, import_ora6.default)("Fetching config from remote...").start();
|
|
1919
|
+
const orgQuery = orgId === "__from_api_key__" ? "" : `?orgId=${orgId}`;
|
|
1567
1920
|
const result = await apiRequest(
|
|
1568
|
-
`${BASE_URL}/api/cli/pull
|
|
1921
|
+
`${BASE_URL}/api/cli/pull${orgQuery}`
|
|
1569
1922
|
);
|
|
1570
1923
|
if (result.error || !result.data) {
|
|
1571
|
-
if (
|
|
1924
|
+
if (agentMode) {
|
|
1572
1925
|
console.log(JSON.stringify({ error: result.error }));
|
|
1573
1926
|
} else {
|
|
1574
1927
|
spinner?.fail("Failed to fetch config");
|
|
1575
|
-
console.error(
|
|
1928
|
+
console.error(import_chalk12.default.red("Error:"), result.error?.message);
|
|
1576
1929
|
}
|
|
1577
1930
|
process.exit(1);
|
|
1578
1931
|
}
|
|
@@ -1583,7 +1936,7 @@ var pullCommand = new import_commander8.Command("pull").description("Pull config
|
|
|
1583
1936
|
const existingConfigPath = findConfigFile(process.cwd());
|
|
1584
1937
|
if (!existingConfigPath) {
|
|
1585
1938
|
if (options.dryRun) {
|
|
1586
|
-
if (
|
|
1939
|
+
if (agentMode) {
|
|
1587
1940
|
console.log(
|
|
1588
1941
|
JSON.stringify({
|
|
1589
1942
|
action: "create",
|
|
@@ -1594,7 +1947,7 @@ var pullCommand = new import_commander8.Command("pull").description("Pull config
|
|
|
1594
1947
|
);
|
|
1595
1948
|
} else {
|
|
1596
1949
|
console.log(
|
|
1597
|
-
|
|
1950
|
+
import_chalk12.default.green(
|
|
1598
1951
|
`
|
|
1599
1952
|
Would create commet.config.ts (${features.length} features, ${plans.length} plans)`
|
|
1600
1953
|
)
|
|
@@ -1603,7 +1956,7 @@ Would create commet.config.ts (${features.length} features, ${plans.length} plan
|
|
|
1603
1956
|
return;
|
|
1604
1957
|
}
|
|
1605
1958
|
fs5.writeFileSync(outputPath, configContent, "utf8");
|
|
1606
|
-
if (
|
|
1959
|
+
if (agentMode) {
|
|
1607
1960
|
console.log(
|
|
1608
1961
|
JSON.stringify({
|
|
1609
1962
|
action: "create",
|
|
@@ -1613,10 +1966,9 @@ Would create commet.config.ts (${features.length} features, ${plans.length} plan
|
|
|
1613
1966
|
})
|
|
1614
1967
|
);
|
|
1615
1968
|
} else {
|
|
1616
|
-
console.log(
|
|
1617
|
-
\u2713 Created commet.config.ts`));
|
|
1969
|
+
console.log(import_chalk12.default.green("\n\u2713 Created commet.config.ts"));
|
|
1618
1970
|
console.log(
|
|
1619
|
-
|
|
1971
|
+
import_chalk12.default.dim(` ${features.length} features, ${plans.length} plans`)
|
|
1620
1972
|
);
|
|
1621
1973
|
}
|
|
1622
1974
|
return;
|
|
@@ -1628,7 +1980,7 @@ Would create commet.config.ts (${features.length} features, ${plans.length} plan
|
|
|
1628
1980
|
);
|
|
1629
1981
|
if ("parseError" in localLoaded) {
|
|
1630
1982
|
if (options.dryRun) {
|
|
1631
|
-
if (
|
|
1983
|
+
if (agentMode) {
|
|
1632
1984
|
console.log(
|
|
1633
1985
|
JSON.stringify({
|
|
1634
1986
|
action: "overwrite",
|
|
@@ -1638,7 +1990,7 @@ Would create commet.config.ts (${features.length} features, ${plans.length} plan
|
|
|
1638
1990
|
);
|
|
1639
1991
|
} else {
|
|
1640
1992
|
console.log(
|
|
1641
|
-
|
|
1993
|
+
import_chalk12.default.yellow(
|
|
1642
1994
|
`
|
|
1643
1995
|
\u26A0 Local config is invalid: ${localLoaded.parseError}`
|
|
1644
1996
|
)
|
|
@@ -1646,23 +1998,23 @@ Would create commet.config.ts (${features.length} features, ${plans.length} plan
|
|
|
1646
1998
|
}
|
|
1647
1999
|
return;
|
|
1648
2000
|
}
|
|
1649
|
-
if (!options.yes && !
|
|
1650
|
-
console.log(
|
|
2001
|
+
if (!options.yes && !agentMode) {
|
|
2002
|
+
console.log(import_chalk12.default.yellow(`
|
|
1651
2003
|
\u26A0 ${localLoaded.parseError}`));
|
|
1652
2004
|
const shouldProceed = await (0, import_prompts3.confirm)({
|
|
1653
2005
|
message: "Overwrite with remote?",
|
|
1654
2006
|
default: true
|
|
1655
2007
|
});
|
|
1656
2008
|
if (!shouldProceed) {
|
|
1657
|
-
console.log(
|
|
2009
|
+
console.log(import_chalk12.default.dim("Pull cancelled"));
|
|
1658
2010
|
return;
|
|
1659
2011
|
}
|
|
1660
2012
|
}
|
|
1661
2013
|
fs5.writeFileSync(outputPath, configContent, "utf8");
|
|
1662
|
-
if (
|
|
2014
|
+
if (agentMode) {
|
|
1663
2015
|
console.log(JSON.stringify({ action: "overwrite", applied: true }));
|
|
1664
2016
|
} else {
|
|
1665
|
-
console.log(
|
|
2017
|
+
console.log(import_chalk12.default.green("\n\u2713 Overwritten commet.config.ts"));
|
|
1666
2018
|
}
|
|
1667
2019
|
return;
|
|
1668
2020
|
}
|
|
@@ -1685,9 +2037,7 @@ Would create commet.config.ts (${features.length} features, ${plans.length} plan
|
|
|
1685
2037
|
{
|
|
1686
2038
|
name: p.name,
|
|
1687
2039
|
...p.description ? { description: p.description } : {},
|
|
1688
|
-
...p.consumptionModel ? {
|
|
1689
|
-
consumptionModel: p.consumptionModel
|
|
1690
|
-
} : {},
|
|
2040
|
+
...p.consumptionModel ? { consumptionModel: p.consumptionModel } : {},
|
|
1691
2041
|
...p.isFree ? { isFree: true } : {},
|
|
1692
2042
|
...p.isPublic === false ? { isPublic: false } : {},
|
|
1693
2043
|
...p.sortOrder ? { sortOrder: p.sortOrder } : {},
|
|
@@ -1733,14 +2083,14 @@ Would create commet.config.ts (${features.length} features, ${plans.length} plan
|
|
|
1733
2083
|
};
|
|
1734
2084
|
const diff = computeDiff(remoteAsConfig, localAsRemote);
|
|
1735
2085
|
if (!diff.hasChanges && diff.features.unmanaged.length === 0 && diff.plans.unmanaged.length === 0) {
|
|
1736
|
-
if (
|
|
2086
|
+
if (agentMode) {
|
|
1737
2087
|
console.log(JSON.stringify({ diff, applied: false, upToDate: true }));
|
|
1738
2088
|
} else {
|
|
1739
|
-
console.log(
|
|
2089
|
+
console.log(import_chalk12.default.green("\n\u2713 Already up to date"));
|
|
1740
2090
|
}
|
|
1741
2091
|
return;
|
|
1742
2092
|
}
|
|
1743
|
-
if (
|
|
2093
|
+
if (agentMode) {
|
|
1744
2094
|
if (options.dryRun) {
|
|
1745
2095
|
console.log(JSON.stringify({ diff, applied: false }));
|
|
1746
2096
|
return;
|
|
@@ -1749,77 +2099,69 @@ Would create commet.config.ts (${features.length} features, ${plans.length} plan
|
|
|
1749
2099
|
console.log(formatDiff(diff));
|
|
1750
2100
|
}
|
|
1751
2101
|
if (options.dryRun) {
|
|
1752
|
-
if (!
|
|
1753
|
-
console.log(
|
|
2102
|
+
if (!agentMode) {
|
|
2103
|
+
console.log(import_chalk12.default.dim("\n(dry run \u2014 no changes applied)"));
|
|
1754
2104
|
}
|
|
1755
2105
|
return;
|
|
1756
2106
|
}
|
|
1757
|
-
if (!options.yes && !
|
|
2107
|
+
if (!options.yes && !agentMode) {
|
|
1758
2108
|
const shouldProceed = await (0, import_prompts3.confirm)({
|
|
1759
2109
|
message: "Overwrite commet.config.ts with remote state?",
|
|
1760
2110
|
default: true
|
|
1761
2111
|
});
|
|
1762
2112
|
if (!shouldProceed) {
|
|
1763
|
-
console.log(
|
|
2113
|
+
console.log(import_chalk12.default.dim("Pull cancelled"));
|
|
1764
2114
|
return;
|
|
1765
2115
|
}
|
|
1766
2116
|
}
|
|
1767
2117
|
fs5.writeFileSync(outputPath, configContent, "utf8");
|
|
1768
|
-
if (
|
|
2118
|
+
if (agentMode) {
|
|
1769
2119
|
console.log(JSON.stringify({ diff, applied: true }));
|
|
1770
2120
|
} else {
|
|
1771
|
-
console.log(
|
|
2121
|
+
console.log(import_chalk12.default.green("\n\u2713 Updated commet.config.ts"));
|
|
1772
2122
|
console.log(
|
|
1773
|
-
|
|
2123
|
+
import_chalk12.default.dim(` ${features.length} features, ${plans.length} plans`)
|
|
1774
2124
|
);
|
|
1775
2125
|
}
|
|
1776
2126
|
});
|
|
1777
2127
|
|
|
1778
2128
|
// src/commands/push.ts
|
|
1779
2129
|
var import_prompts4 = require("@inquirer/prompts");
|
|
1780
|
-
var
|
|
2130
|
+
var import_chalk13 = __toESM(require("chalk"));
|
|
1781
2131
|
var import_commander9 = require("commander");
|
|
1782
|
-
var
|
|
1783
|
-
var pushCommand = new import_commander9.Command("push").description(
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
process.exit(1);
|
|
1804
|
-
}
|
|
1805
|
-
const projectConfig = loadProjectConfig();
|
|
1806
|
-
if (!projectConfig) {
|
|
1807
|
-
if (jsonMode) {
|
|
1808
|
-
console.log(JSON.stringify({ error: "Invalid project configuration" }));
|
|
1809
|
-
} else {
|
|
1810
|
-
console.log(import_chalk12.default.red("\u2717 Invalid project configuration"));
|
|
1811
|
-
}
|
|
1812
|
-
process.exit(1);
|
|
1813
|
-
}
|
|
1814
|
-
const loadSpinner = jsonMode ? null : (0, import_ora6.default)("Loading commet.config.ts...").start();
|
|
2132
|
+
var import_ora7 = __toESM(require("ora"));
|
|
2133
|
+
var pushCommand = new import_commander9.Command("push").description(
|
|
2134
|
+
"Push your local commet.config.ts to Commet. Creates or updates features and plans to match your config file."
|
|
2135
|
+
).option("-y, --yes", "Skip confirmation prompt").option("--dry-run", "Show what would change without pushing").option(
|
|
2136
|
+
"--output <format>",
|
|
2137
|
+
"Output format: human (default) or agent",
|
|
2138
|
+
"human"
|
|
2139
|
+
).addHelpText(
|
|
2140
|
+
"after",
|
|
2141
|
+
`
|
|
2142
|
+
Examples:
|
|
2143
|
+
$ commet push Interactive \u2014 shows diff, asks to confirm
|
|
2144
|
+
$ commet push --dry-run Preview what would change on remote
|
|
2145
|
+
$ commet push --yes Push without confirmation
|
|
2146
|
+
$ commet push --output agent --yes Agent/CI \u2014 structured JSON, no prompts
|
|
2147
|
+
$ COMMET_API_KEY=sk_... commet push --yes CI pipeline
|
|
2148
|
+
`
|
|
2149
|
+
).action(async (options) => {
|
|
2150
|
+
const agentMode = isAgentMode(options);
|
|
2151
|
+
const { orgId } = requireOrgContext();
|
|
2152
|
+
const loadSpinner = agentMode ? null : (0, import_ora7.default)("Loading commet.config.ts...").start();
|
|
1815
2153
|
const loaded = await loadBillingConfig(process.cwd()).catch(
|
|
1816
2154
|
(error) => {
|
|
1817
2155
|
const message = error instanceof Error ? error.message : String(error);
|
|
1818
|
-
if (
|
|
1819
|
-
console.log(
|
|
2156
|
+
if (agentMode) {
|
|
2157
|
+
console.log(
|
|
2158
|
+
JSON.stringify({
|
|
2159
|
+
error: { code: "config_invalid", message }
|
|
2160
|
+
})
|
|
2161
|
+
);
|
|
1820
2162
|
} else {
|
|
1821
2163
|
loadSpinner?.fail("Failed to load config");
|
|
1822
|
-
console.error(
|
|
2164
|
+
console.error(import_chalk13.default.red(message));
|
|
1823
2165
|
}
|
|
1824
2166
|
return null;
|
|
1825
2167
|
}
|
|
@@ -1827,16 +2169,17 @@ var pushCommand = new import_commander9.Command("push").description("Push commet
|
|
|
1827
2169
|
if (!loaded) process.exit(1);
|
|
1828
2170
|
const { config, configPath } = loaded;
|
|
1829
2171
|
loadSpinner?.succeed(`Loaded ${configPath}`);
|
|
1830
|
-
const fetchSpinner =
|
|
2172
|
+
const fetchSpinner = agentMode ? null : (0, import_ora7.default)("Fetching remote state...").start();
|
|
2173
|
+
const orgQuery = orgId === "__from_api_key__" ? "" : `?orgId=${orgId}`;
|
|
1831
2174
|
const remoteResult = await apiRequest(
|
|
1832
|
-
`${BASE_URL}/api/cli/pull
|
|
2175
|
+
`${BASE_URL}/api/cli/pull${orgQuery}`
|
|
1833
2176
|
);
|
|
1834
2177
|
if (remoteResult.error || !remoteResult.data) {
|
|
1835
|
-
if (
|
|
2178
|
+
if (agentMode) {
|
|
1836
2179
|
console.log(JSON.stringify({ error: remoteResult.error }));
|
|
1837
2180
|
} else {
|
|
1838
2181
|
fetchSpinner?.fail("Failed to fetch remote state");
|
|
1839
|
-
console.error(
|
|
2182
|
+
console.error(import_chalk13.default.red("Error:"), remoteResult.error?.message);
|
|
1840
2183
|
}
|
|
1841
2184
|
process.exit(1);
|
|
1842
2185
|
}
|
|
@@ -1846,7 +2189,7 @@ var pushCommand = new import_commander9.Command("push").description("Push commet
|
|
|
1846
2189
|
plans: remoteResult.data.plans
|
|
1847
2190
|
};
|
|
1848
2191
|
const diff = computeDiff(config, remote);
|
|
1849
|
-
if (
|
|
2192
|
+
if (agentMode) {
|
|
1850
2193
|
if (options.dryRun) {
|
|
1851
2194
|
console.log(JSON.stringify({ diff, applied: false }));
|
|
1852
2195
|
return;
|
|
@@ -1855,10 +2198,10 @@ var pushCommand = new import_commander9.Command("push").description("Push commet
|
|
|
1855
2198
|
console.log(formatDiff(diff));
|
|
1856
2199
|
}
|
|
1857
2200
|
if (!diff.hasChanges) {
|
|
1858
|
-
if (
|
|
2201
|
+
if (agentMode) {
|
|
1859
2202
|
console.log(JSON.stringify({ diff, applied: false, upToDate: true }));
|
|
1860
2203
|
} else {
|
|
1861
|
-
console.log(
|
|
2204
|
+
console.log(import_chalk13.default.green("\n\u2713 Everything is up to date"));
|
|
1862
2205
|
}
|
|
1863
2206
|
return;
|
|
1864
2207
|
}
|
|
@@ -1867,67 +2210,67 @@ var pushCommand = new import_commander9.Command("push").description("Push commet
|
|
|
1867
2210
|
);
|
|
1868
2211
|
if (typeChanges.length > 0) {
|
|
1869
2212
|
const blockedCodes = typeChanges.map((c) => c.code);
|
|
1870
|
-
if (
|
|
2213
|
+
if (agentMode) {
|
|
1871
2214
|
console.log(
|
|
1872
2215
|
JSON.stringify({
|
|
1873
|
-
error:
|
|
2216
|
+
error: {
|
|
2217
|
+
code: "type_change_blocked",
|
|
2218
|
+
message: "Feature type changes must be done in the dashboard"
|
|
2219
|
+
},
|
|
1874
2220
|
blockedCodes,
|
|
1875
2221
|
diff
|
|
1876
2222
|
})
|
|
1877
2223
|
);
|
|
1878
2224
|
} else {
|
|
1879
2225
|
console.log(
|
|
1880
|
-
|
|
2226
|
+
import_chalk13.default.red(
|
|
1881
2227
|
"\n\u2717 Cannot change feature types. Update them in the dashboard:"
|
|
1882
2228
|
)
|
|
1883
2229
|
);
|
|
1884
2230
|
for (const change of typeChanges) {
|
|
1885
|
-
console.log(
|
|
2231
|
+
console.log(import_chalk13.default.red(` - ${change.code}`));
|
|
1886
2232
|
}
|
|
1887
2233
|
}
|
|
1888
2234
|
process.exit(1);
|
|
1889
2235
|
}
|
|
1890
2236
|
if (options.dryRun) {
|
|
1891
|
-
if (!
|
|
1892
|
-
console.log(
|
|
2237
|
+
if (!agentMode) {
|
|
2238
|
+
console.log(import_chalk13.default.dim("\n(dry run \u2014 no changes applied)"));
|
|
1893
2239
|
}
|
|
1894
2240
|
return;
|
|
1895
2241
|
}
|
|
1896
|
-
if (!options.yes && !
|
|
2242
|
+
if (!options.yes && !agentMode) {
|
|
1897
2243
|
const shouldProceed = await (0, import_prompts4.confirm)({
|
|
1898
2244
|
message: "Apply these changes?",
|
|
1899
2245
|
default: true
|
|
1900
2246
|
});
|
|
1901
2247
|
if (!shouldProceed) {
|
|
1902
|
-
console.log(
|
|
2248
|
+
console.log(import_chalk13.default.dim("Push cancelled"));
|
|
1903
2249
|
return;
|
|
1904
2250
|
}
|
|
1905
2251
|
}
|
|
1906
|
-
const pushSpinner =
|
|
2252
|
+
const pushSpinner = agentMode ? null : (0, import_ora7.default)("Pushing config...").start();
|
|
2253
|
+
const pushBody = {
|
|
2254
|
+
config: { features: config.features, plans: config.plans }
|
|
2255
|
+
};
|
|
2256
|
+
if (orgId !== "__from_api_key__") {
|
|
2257
|
+
pushBody.orgId = orgId;
|
|
2258
|
+
}
|
|
1907
2259
|
const pushResult = await apiRequest(
|
|
1908
2260
|
`${BASE_URL}/api/cli/push`,
|
|
1909
|
-
{
|
|
1910
|
-
method: "POST",
|
|
1911
|
-
body: JSON.stringify({
|
|
1912
|
-
orgId: projectConfig.orgId,
|
|
1913
|
-
config: {
|
|
1914
|
-
features: config.features,
|
|
1915
|
-
plans: config.plans
|
|
1916
|
-
}
|
|
1917
|
-
})
|
|
1918
|
-
}
|
|
2261
|
+
{ method: "POST", body: JSON.stringify(pushBody) }
|
|
1919
2262
|
);
|
|
1920
2263
|
if (pushResult.error || !pushResult.data) {
|
|
1921
|
-
if (
|
|
2264
|
+
if (agentMode) {
|
|
1922
2265
|
console.log(JSON.stringify({ error: pushResult.error }));
|
|
1923
2266
|
} else {
|
|
1924
2267
|
pushSpinner?.fail("Push failed");
|
|
1925
|
-
console.error(
|
|
2268
|
+
console.error(import_chalk13.default.red("Error:"), pushResult.error?.message);
|
|
1926
2269
|
}
|
|
1927
2270
|
process.exit(1);
|
|
1928
2271
|
}
|
|
1929
2272
|
const pushOutcome = pushResult.data;
|
|
1930
|
-
if (
|
|
2273
|
+
if (agentMode) {
|
|
1931
2274
|
console.log(JSON.stringify({ diff, applied: true, result: pushOutcome }));
|
|
1932
2275
|
return;
|
|
1933
2276
|
}
|
|
@@ -1938,170 +2281,88 @@ var pushCommand = new import_commander9.Command("push").description("Push commet
|
|
|
1938
2281
|
if (errors.length > 0) {
|
|
1939
2282
|
pushSpinner?.warn("Push completed with errors");
|
|
1940
2283
|
for (const error of errors) {
|
|
1941
|
-
console.log(
|
|
2284
|
+
console.log(import_chalk13.default.red(` \u2717 ${error.code}: ${error.message}`));
|
|
1942
2285
|
}
|
|
1943
2286
|
} else {
|
|
1944
2287
|
pushSpinner?.succeed("Push complete");
|
|
1945
2288
|
}
|
|
1946
2289
|
if (pushOutcome.features.created.length > 0) {
|
|
1947
2290
|
console.log(
|
|
1948
|
-
|
|
2291
|
+
import_chalk13.default.green(
|
|
1949
2292
|
` Created features: ${pushOutcome.features.created.join(", ")}`
|
|
1950
2293
|
)
|
|
1951
2294
|
);
|
|
1952
2295
|
}
|
|
1953
2296
|
if (pushOutcome.features.updated.length > 0) {
|
|
1954
2297
|
console.log(
|
|
1955
|
-
|
|
2298
|
+
import_chalk13.default.yellow(
|
|
1956
2299
|
` Updated features: ${pushOutcome.features.updated.join(", ")}`
|
|
1957
2300
|
)
|
|
1958
2301
|
);
|
|
1959
2302
|
}
|
|
1960
2303
|
if (pushOutcome.plans.created.length > 0) {
|
|
1961
2304
|
console.log(
|
|
1962
|
-
|
|
2305
|
+
import_chalk13.default.green(` Created plans: ${pushOutcome.plans.created.join(", ")}`)
|
|
1963
2306
|
);
|
|
1964
2307
|
}
|
|
1965
2308
|
if (pushOutcome.plans.updated.length > 0) {
|
|
1966
2309
|
console.log(
|
|
1967
|
-
|
|
2310
|
+
import_chalk13.default.yellow(
|
|
1968
2311
|
` Updated plans: ${pushOutcome.plans.updated.join(", ")}`
|
|
1969
2312
|
)
|
|
1970
2313
|
);
|
|
1971
2314
|
}
|
|
1972
2315
|
});
|
|
1973
2316
|
|
|
1974
|
-
// src/commands/switch.ts
|
|
1975
|
-
var import_prompts5 = require("@inquirer/prompts");
|
|
1976
|
-
var import_chalk13 = __toESM(require("chalk"));
|
|
1977
|
-
var import_commander10 = require("commander");
|
|
1978
|
-
var import_ora7 = __toESM(require("ora"));
|
|
1979
|
-
var switchCommand = new import_commander10.Command("switch").description("Switch to a different organization").action(async () => {
|
|
1980
|
-
if (!authExists()) {
|
|
1981
|
-
console.log(import_chalk13.default.red("\u2717 Not authenticated"));
|
|
1982
|
-
console.log(import_chalk13.default.dim("Run `commet login` first"));
|
|
1983
|
-
return;
|
|
1984
|
-
}
|
|
1985
|
-
if (!projectConfigExists()) {
|
|
1986
|
-
console.log(import_chalk13.default.yellow("\u26A0 Project not linked"));
|
|
1987
|
-
console.log(
|
|
1988
|
-
import_chalk13.default.dim("Run `commet link` first to connect to an organization")
|
|
1989
|
-
);
|
|
1990
|
-
return;
|
|
1991
|
-
}
|
|
1992
|
-
const spinner = (0, import_ora7.default)("Fetching organizations...").start();
|
|
1993
|
-
const result = await apiRequest(
|
|
1994
|
-
`${BASE_URL}/api/cli/organizations`
|
|
1995
|
-
);
|
|
1996
|
-
if (result.error || !result.data) {
|
|
1997
|
-
spinner.fail("Failed to fetch organizations");
|
|
1998
|
-
console.error(import_chalk13.default.red("Error:"), result.error);
|
|
1999
|
-
return;
|
|
2000
|
-
}
|
|
2001
|
-
const { organizations } = result.data;
|
|
2002
|
-
if (organizations.length === 0) {
|
|
2003
|
-
spinner.stop();
|
|
2004
|
-
console.log(import_chalk13.default.yellow("\u26A0 No organizations found"));
|
|
2005
|
-
return;
|
|
2006
|
-
}
|
|
2007
|
-
spinner.stop();
|
|
2008
|
-
let orgId;
|
|
2009
|
-
try {
|
|
2010
|
-
orgId = await (0, import_prompts5.select)({
|
|
2011
|
-
message: "Select organization:",
|
|
2012
|
-
choices: organizations.map((org) => ({
|
|
2013
|
-
name: `${org.name} ${import_chalk13.default.dim(`(${org.slug}) \xB7 ${org.mode}`)}`,
|
|
2014
|
-
value: org.id
|
|
2015
|
-
})),
|
|
2016
|
-
theme: promptTheme
|
|
2017
|
-
});
|
|
2018
|
-
} catch (_error) {
|
|
2019
|
-
console.log(import_chalk13.default.yellow("\n\u26A0 Switch cancelled"));
|
|
2020
|
-
return;
|
|
2021
|
-
}
|
|
2022
|
-
const selectedOrg = organizations.find((org) => org.id === orgId);
|
|
2023
|
-
if (!selectedOrg) {
|
|
2024
|
-
console.log(import_chalk13.default.red("\u2717 Organization not found"));
|
|
2025
|
-
return;
|
|
2026
|
-
}
|
|
2027
|
-
saveProjectConfig({
|
|
2028
|
-
orgId: selectedOrg.id,
|
|
2029
|
-
orgName: selectedOrg.name,
|
|
2030
|
-
mode: selectedOrg.mode
|
|
2031
|
-
});
|
|
2032
|
-
console.log(import_chalk13.default.green("\n\u2713 Switched organization successfully!"));
|
|
2033
|
-
console.log(
|
|
2034
|
-
import_chalk13.default.dim(`
|
|
2035
|
-
Organization: ${selectedOrg.name} \xB7 ${selectedOrg.mode}`)
|
|
2036
|
-
);
|
|
2037
|
-
console.log(
|
|
2038
|
-
import_chalk13.default.dim(
|
|
2039
|
-
"\nRun `commet pull` to update TypeScript types for this organization"
|
|
2040
|
-
)
|
|
2041
|
-
);
|
|
2042
|
-
});
|
|
2043
|
-
|
|
2044
|
-
// src/commands/unlink.ts
|
|
2045
|
-
var import_chalk14 = __toESM(require("chalk"));
|
|
2046
|
-
var import_commander11 = require("commander");
|
|
2047
|
-
var unlinkCommand = new import_commander11.Command("unlink").description("Unlink this project from Commet").action(async () => {
|
|
2048
|
-
if (!projectConfigExists()) {
|
|
2049
|
-
console.log(
|
|
2050
|
-
import_chalk14.default.yellow("\u26A0 This project is not linked to any organization")
|
|
2051
|
-
);
|
|
2052
|
-
return;
|
|
2053
|
-
}
|
|
2054
|
-
clearProjectConfig();
|
|
2055
|
-
console.log(import_chalk14.default.green("\u2713 Project unlinked successfully"));
|
|
2056
|
-
console.log(import_chalk14.default.dim("\u2713 Removed .commet/ directory"));
|
|
2057
|
-
console.log(
|
|
2058
|
-
import_chalk14.default.dim("\nRun `commet link` to connect to a different organization")
|
|
2059
|
-
);
|
|
2060
|
-
});
|
|
2061
|
-
|
|
2062
|
-
// src/commands/whoami.ts
|
|
2063
|
-
var import_chalk15 = __toESM(require("chalk"));
|
|
2064
|
-
var import_commander12 = require("commander");
|
|
2065
|
-
var whoamiCommand = new import_commander12.Command("whoami").description("Display current authentication and project status").action(async () => {
|
|
2066
|
-
if (!authExists()) {
|
|
2067
|
-
console.log(import_chalk15.default.yellow("\u26A0 Not logged in"));
|
|
2068
|
-
console.log(import_chalk15.default.dim("Run `commet login` to authenticate"));
|
|
2069
|
-
return;
|
|
2070
|
-
}
|
|
2071
|
-
console.log(import_chalk15.default.green("\u2713 Logged in"));
|
|
2072
|
-
const projectConfig = loadProjectConfig();
|
|
2073
|
-
if (projectConfig) {
|
|
2074
|
-
console.log(import_chalk15.default.bold("\nProject:"));
|
|
2075
|
-
console.log(import_chalk15.default.dim("Organization:"), projectConfig.orgName);
|
|
2076
|
-
console.log(import_chalk15.default.dim("Mode:"), projectConfig.mode);
|
|
2077
|
-
} else {
|
|
2078
|
-
console.log(import_chalk15.default.yellow("\n\u26A0 No project linked"));
|
|
2079
|
-
console.log(
|
|
2080
|
-
import_chalk15.default.dim(
|
|
2081
|
-
"Run `commet link` to connect this directory to an organization"
|
|
2082
|
-
)
|
|
2083
|
-
);
|
|
2084
|
-
}
|
|
2085
|
-
});
|
|
2086
|
-
|
|
2087
2317
|
// src/index.ts
|
|
2088
|
-
var program = new
|
|
2318
|
+
var program = new import_commander10.Command();
|
|
2089
2319
|
program.name("commet").description(
|
|
2090
|
-
"Commet CLI
|
|
2091
|
-
).version(package_default.version)
|
|
2320
|
+
"Commet CLI \u2014 billing infrastructure as code.\nManage features, plans, and billing config from the command line."
|
|
2321
|
+
).version(package_default.version).addHelpText(
|
|
2322
|
+
"after",
|
|
2323
|
+
`
|
|
2324
|
+
Workflow:
|
|
2325
|
+
$ commet pull Sync remote \u2192 commet.config.ts
|
|
2326
|
+
$ commet push Push local changes \u2192 remote
|
|
2327
|
+
$ commet pull --dry-run See what's configured
|
|
2328
|
+
|
|
2329
|
+
For agents and CI:
|
|
2330
|
+
$ commet JSON capabilities when piped (no args)
|
|
2331
|
+
$ commet pull --output agent --yes Structured output, no prompts
|
|
2332
|
+
$ COMMET_API_KEY=sk_... commet push --yes CI pipeline
|
|
2333
|
+
|
|
2334
|
+
Run commet <command> --help for detailed usage and examples.
|
|
2335
|
+
`
|
|
2336
|
+
);
|
|
2092
2337
|
program.addCommand(createCommand);
|
|
2093
2338
|
program.addCommand(loginCommand);
|
|
2094
2339
|
program.addCommand(logoutCommand);
|
|
2095
|
-
program.addCommand(whoamiCommand);
|
|
2096
2340
|
program.addCommand(linkCommand);
|
|
2097
|
-
program.addCommand(
|
|
2098
|
-
program.addCommand(switchCommand);
|
|
2099
|
-
program.addCommand(infoCommand);
|
|
2341
|
+
program.addCommand(orgsCommand);
|
|
2100
2342
|
program.addCommand(pushCommand);
|
|
2101
2343
|
program.addCommand(pullCommand);
|
|
2102
|
-
program.addCommand(listCommand);
|
|
2103
2344
|
program.addCommand(listenCommand);
|
|
2345
|
+
program.addCommand(apiKeyCommand);
|
|
2346
|
+
program.enablePositionalOptions().passThroughOptions().option(
|
|
2347
|
+
"--output <format>",
|
|
2348
|
+
"Output format: human (default) or agent",
|
|
2349
|
+
"human"
|
|
2350
|
+
);
|
|
2351
|
+
program.action((options) => {
|
|
2352
|
+
if (options.output === "agent") {
|
|
2353
|
+
printAgentInfo();
|
|
2354
|
+
} else {
|
|
2355
|
+
printDefaultScreen();
|
|
2356
|
+
}
|
|
2357
|
+
});
|
|
2358
|
+
program.showSuggestionAfterError();
|
|
2104
2359
|
program.exitOverride();
|
|
2360
|
+
installCrashHandler();
|
|
2361
|
+
markCommandStart();
|
|
2362
|
+
var commandName = process.argv[2] || "(default)";
|
|
2363
|
+
program.hook("postAction", () => {
|
|
2364
|
+
reportCommand(commandName, "success");
|
|
2365
|
+
});
|
|
2105
2366
|
try {
|
|
2106
2367
|
program.parse(process.argv);
|
|
2107
2368
|
} catch (error) {
|
|
@@ -2110,10 +2371,145 @@ try {
|
|
|
2110
2371
|
if (code === "commander.version" || code === "commander.help" || code === "commander.helpDisplayed") {
|
|
2111
2372
|
process.exit(0);
|
|
2112
2373
|
}
|
|
2113
|
-
|
|
2374
|
+
reportCommand(commandName, "error", code);
|
|
2375
|
+
console.error(import_chalk14.default.red("Error:"), error.message);
|
|
2114
2376
|
}
|
|
2115
2377
|
process.exit(1);
|
|
2116
2378
|
}
|
|
2117
|
-
|
|
2118
|
-
|
|
2379
|
+
function printAgentInfo() {
|
|
2380
|
+
const authenticated = authExists() || !!process.env.COMMET_API_KEY;
|
|
2381
|
+
const projectConfig = projectConfigExists() ? loadProjectConfig() : null;
|
|
2382
|
+
const configPath = findConfigFile(process.cwd());
|
|
2383
|
+
const setup = [];
|
|
2384
|
+
if (!authenticated) {
|
|
2385
|
+
setup.push(
|
|
2386
|
+
"Not authenticated. Run 'commet login' (interactive) or set COMMET_API_KEY env var."
|
|
2387
|
+
);
|
|
2388
|
+
}
|
|
2389
|
+
if (authenticated && !projectConfig && !process.env.COMMET_API_KEY) {
|
|
2390
|
+
setup.push(
|
|
2391
|
+
"No project linked. Run 'commet link --org <slug>' or 'commet orgs --json' to find organizations."
|
|
2392
|
+
);
|
|
2393
|
+
}
|
|
2394
|
+
const output = {
|
|
2395
|
+
version: package_default.version,
|
|
2396
|
+
authenticated,
|
|
2397
|
+
...setup.length > 0 ? { setup } : {},
|
|
2398
|
+
project: projectConfig ? {
|
|
2399
|
+
linked: true,
|
|
2400
|
+
orgId: projectConfig.orgId,
|
|
2401
|
+
orgName: projectConfig.orgName,
|
|
2402
|
+
mode: projectConfig.mode
|
|
2403
|
+
} : { linked: false },
|
|
2404
|
+
config: {
|
|
2405
|
+
exists: configPath !== null,
|
|
2406
|
+
path: configPath?.split("/").pop() ?? null
|
|
2407
|
+
},
|
|
2408
|
+
mcp: {
|
|
2409
|
+
url: "https://commet.co/mcp",
|
|
2410
|
+
sandbox: "https://sandbox.commet.co/mcp",
|
|
2411
|
+
hint: "For full billing CRUD (plans, features, customers, subscriptions), connect to the MCP server."
|
|
2412
|
+
},
|
|
2413
|
+
auth: {
|
|
2414
|
+
interactive: "commet login",
|
|
2415
|
+
ci: "Set COMMET_API_KEY environment variable"
|
|
2416
|
+
},
|
|
2417
|
+
commands: {
|
|
2418
|
+
pull: {
|
|
2419
|
+
description: "Pull remote config and generate commet.config.ts",
|
|
2420
|
+
usage: "commet pull --output agent --yes",
|
|
2421
|
+
preview: "commet pull --output agent --dry-run"
|
|
2422
|
+
},
|
|
2423
|
+
push: {
|
|
2424
|
+
description: "Push commet.config.ts to remote",
|
|
2425
|
+
usage: "commet push --output agent --yes",
|
|
2426
|
+
preview: "commet push --output agent --dry-run",
|
|
2427
|
+
ci: "COMMET_API_KEY=sk_... commet push --yes"
|
|
2428
|
+
},
|
|
2429
|
+
orgs: {
|
|
2430
|
+
description: "List available organizations",
|
|
2431
|
+
usage: "commet orgs --output agent"
|
|
2432
|
+
},
|
|
2433
|
+
link: {
|
|
2434
|
+
description: "Link/switch/unlink organization",
|
|
2435
|
+
usage: "commet link --org <slug-or-id>",
|
|
2436
|
+
clear: "commet link --clear"
|
|
2437
|
+
},
|
|
2438
|
+
listen: {
|
|
2439
|
+
description: "Forward webhook events to local server. Long-running streaming process.",
|
|
2440
|
+
usage: "commet listen <url> [--events <types>]"
|
|
2441
|
+
},
|
|
2442
|
+
create: {
|
|
2443
|
+
description: "Scaffold a new Commet app from template",
|
|
2444
|
+
usage: "commet create [name] -t <template> --org <slug> -y"
|
|
2445
|
+
},
|
|
2446
|
+
"api-key": {
|
|
2447
|
+
description: "Generate API key for CI",
|
|
2448
|
+
usage: "commet api-key --output agent"
|
|
2449
|
+
},
|
|
2450
|
+
login: {
|
|
2451
|
+
description: "Authenticate via browser. Requires a human \u2014 opens a device-code flow.",
|
|
2452
|
+
usage: "commet login"
|
|
2453
|
+
},
|
|
2454
|
+
logout: {
|
|
2455
|
+
description: "Log out of Commet",
|
|
2456
|
+
usage: "commet logout"
|
|
2457
|
+
}
|
|
2458
|
+
}
|
|
2459
|
+
};
|
|
2460
|
+
console.log(JSON.stringify(output, null, 2));
|
|
2461
|
+
}
|
|
2462
|
+
function printDefaultScreen() {
|
|
2463
|
+
const version = import_chalk14.default.dim(`v${package_default.version}`);
|
|
2464
|
+
console.log(`
|
|
2465
|
+
${commetColor.bold("Commet")} ${version}`);
|
|
2466
|
+
console.log(import_chalk14.default.dim(" Billing infrastructure as code\n"));
|
|
2467
|
+
const authenticated = authExists();
|
|
2468
|
+
const projectConfig = projectConfigExists() ? loadProjectConfig() : null;
|
|
2469
|
+
const configFile = findConfigFile(process.cwd());
|
|
2470
|
+
if (authenticated) {
|
|
2471
|
+
console.log(import_chalk14.default.green(" \u2713 Authenticated"));
|
|
2472
|
+
} else {
|
|
2473
|
+
console.log(
|
|
2474
|
+
` ${import_chalk14.default.yellow("\u26A0")} Not logged in ${import_chalk14.default.dim("\u2192 commet login")}`
|
|
2475
|
+
);
|
|
2476
|
+
}
|
|
2477
|
+
if (projectConfig) {
|
|
2478
|
+
console.log(
|
|
2479
|
+
import_chalk14.default.green(
|
|
2480
|
+
` \u2713 ${projectConfig.orgName} ${import_chalk14.default.dim(`(${projectConfig.mode})`)}`
|
|
2481
|
+
)
|
|
2482
|
+
);
|
|
2483
|
+
console.log(import_chalk14.default.dim(` ${projectConfig.orgId}`));
|
|
2484
|
+
} else if (authenticated) {
|
|
2485
|
+
console.log(
|
|
2486
|
+
` ${import_chalk14.default.yellow("\u26A0")} No project linked ${import_chalk14.default.dim("\u2192 commet link")}`
|
|
2487
|
+
);
|
|
2488
|
+
}
|
|
2489
|
+
if (configFile) {
|
|
2490
|
+
const fileName = configFile.split("/").pop();
|
|
2491
|
+
console.log(import_chalk14.default.green(` \u2713 ${fileName}`));
|
|
2492
|
+
} else if (projectConfig) {
|
|
2493
|
+
console.log(
|
|
2494
|
+
` ${import_chalk14.default.yellow("\u26A0")} No config file ${import_chalk14.default.dim("\u2192 commet pull")}`
|
|
2495
|
+
);
|
|
2496
|
+
}
|
|
2497
|
+
const cmd = (name) => commetColor(name.padEnd(22));
|
|
2498
|
+
const dim = import_chalk14.default.dim;
|
|
2499
|
+
console.log(dim("\n Config"));
|
|
2500
|
+
console.log(` ${cmd("pull")}${dim("Sync remote \u2192 commet.config.ts")}`);
|
|
2501
|
+
console.log(` ${cmd("push")}${dim("Sync commet.config.ts \u2192 remote")}`);
|
|
2502
|
+
console.log(dim("\n Development"));
|
|
2503
|
+
console.log(` ${cmd("listen <url>")}${dim("Forward webhooks locally")}`);
|
|
2504
|
+
console.log(dim("\n Project"));
|
|
2505
|
+
console.log(` ${cmd("link")}${dim("Link / switch organization")}`);
|
|
2506
|
+
console.log(` ${cmd("orgs")}${dim("List organizations")}`);
|
|
2507
|
+
console.log(dim("\n Setup"));
|
|
2508
|
+
console.log(` ${cmd("create")}${dim("Scaffold a new Commet app")}`);
|
|
2509
|
+
console.log(` ${cmd("api-key")}${dim("Generate API key for CI")}`);
|
|
2510
|
+
console.log(` ${cmd("login")}${dim("Authenticate")}`);
|
|
2511
|
+
console.log(` ${cmd("logout")}${dim("Log out")}`);
|
|
2512
|
+
console.log(
|
|
2513
|
+
dim("\n commet --help for full reference \xB7 COMMET_API_KEY for CI\n")
|
|
2514
|
+
);
|
|
2119
2515
|
}
|