commet 1.9.0 → 1.10.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.
Files changed (2) hide show
  1. package/dist/index.js +766 -199
  2. package/package.json +6 -5
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 import_chalk14 = __toESM(require("chalk"));
28
- var import_commander12 = require("commander");
27
+ var import_chalk16 = __toESM(require("chalk"));
28
+ var import_commander13 = require("commander");
29
29
 
30
30
  // package.json
31
31
  var package_default = {
32
32
  name: "commet",
33
- version: "1.9.0",
33
+ version: "1.10.0",
34
34
  description: "Commet CLI - Manage your billing platform from the command line",
35
35
  bin: {
36
36
  commet: "./bin/commet"
@@ -57,17 +57,18 @@ var package_default = {
57
57
  author: "Commet Team",
58
58
  license: "MIT",
59
59
  dependencies: {
60
- "@inquirer/prompts": "8.0.1",
60
+ "@inquirer/prompts": "8.4.3",
61
61
  ably: "^2.21.0",
62
62
  chalk: "5.6.2",
63
- commander: "14.0.2",
63
+ commander: "14.0.3",
64
+ jiti: "^2.7.0",
64
65
  "jsonc-parser": "3.3.1",
65
66
  open: "11.0.0",
66
- ora: "9.0.0",
67
+ ora: "9.4.0",
67
68
  tar: "^7.5.13"
68
69
  },
69
70
  devDependencies: {
70
- "@types/node": "24.10.1",
71
+ "@types/node": "24.12.4",
71
72
  tsup: "8.5.1",
72
73
  typescript: "5.9.3"
73
74
  },
@@ -218,7 +219,7 @@ var promptTheme = {
218
219
 
219
220
  // src/utils/login-flow.ts
220
221
  function sleep(ms) {
221
- return new Promise((resolve3) => setTimeout(resolve3, ms));
222
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
222
223
  }
223
224
  async function performLogin() {
224
225
  const spinner = (0, import_ora.default)("Initiating login flow...").start();
@@ -492,7 +493,7 @@ async function resolveSkills(opts) {
492
493
  }
493
494
  async function installSkills(projectRoot) {
494
495
  const npx = process.platform === "win32" ? "npx.cmd" : "npx";
495
- return new Promise((resolve3) => {
496
+ return new Promise((resolve4) => {
496
497
  const child = (0, import_node_child_process.spawn)(
497
498
  npx,
498
499
  ["-y", "--loglevel=error", "skills", "add", "commet-labs/commet-skills"],
@@ -503,7 +504,7 @@ async function installSkills(projectRoot) {
503
504
  console.log(import_chalk3.default.dim(" You can install them manually by running:"));
504
505
  console.log(import_chalk3.default.dim(" npx skills add commet-labs/commet-skills"));
505
506
  }
506
- resolve3();
507
+ resolve4();
507
508
  });
508
509
  });
509
510
  }
@@ -916,7 +917,7 @@ var listCommand = new import_commander4.Command("list").description("List featur
916
917
  }
917
918
  const spinner = (0, import_ora4.default)(`Fetching ${type}...`).start();
918
919
  const result = await apiRequest(
919
- `${BASE_URL}/api/cli/types?orgId=${projectConfig.orgId}`
920
+ `${BASE_URL}/api/cli/pull?orgId=${projectConfig.orgId}`
920
921
  );
921
922
  if (result.error || !result.data) {
922
923
  spinner.fail(`Failed to fetch ${type}`);
@@ -1207,255 +1208,820 @@ var logoutCommand = new import_commander7.Command("logout").description("Log out
1207
1208
  });
1208
1209
 
1209
1210
  // src/commands/pull.ts
1210
- var fs6 = __toESM(require("fs"));
1211
- var path6 = __toESM(require("path"));
1212
- var import_chalk10 = __toESM(require("chalk"));
1211
+ var fs5 = __toESM(require("fs"));
1212
+ var path5 = __toESM(require("path"));
1213
+ var import_prompts3 = require("@inquirer/prompts");
1214
+ var import_chalk11 = __toESM(require("chalk"));
1213
1215
  var import_commander8 = require("commander");
1214
1216
  var import_ora5 = __toESM(require("ora"));
1215
1217
 
1216
- // src/utils/environment-validator.ts
1218
+ // src/utils/config-loader.ts
1217
1219
  var fs4 = __toESM(require("fs"));
1218
1220
  var path4 = __toESM(require("path"));
1219
- function validateTypeScriptProject() {
1220
- const cwd = process.cwd();
1221
- const tsconfigPath = path4.join(cwd, "tsconfig.json");
1222
- if (!fs4.existsSync(tsconfigPath)) {
1223
- return false;
1221
+ var import_jiti = require("jiti");
1222
+ var CONFIG_NAMES = [
1223
+ "commet.config.ts",
1224
+ "commet.config.js",
1225
+ "commet.config.mjs"
1226
+ ];
1227
+ function findConfigFile(cwd) {
1228
+ for (const name of CONFIG_NAMES) {
1229
+ const fullPath = path4.resolve(cwd, name);
1230
+ if (fs4.existsSync(fullPath)) {
1231
+ return fullPath;
1232
+ }
1224
1233
  }
1225
- try {
1226
- const content = fs4.readFileSync(tsconfigPath, "utf8");
1227
- JSON.parse(content);
1228
- return true;
1229
- } catch (_error) {
1230
- return false;
1234
+ return null;
1235
+ }
1236
+ async function loadBillingConfig(cwd) {
1237
+ const configPath = findConfigFile(cwd);
1238
+ if (!configPath) {
1239
+ throw new Error(
1240
+ `No commet.config.ts found in ${cwd}. Create one with defineConfig() or run 'commet pull' to generate it.`
1241
+ );
1242
+ }
1243
+ const jiti = (0, import_jiti.createJiti)(configPath, { interopDefault: true });
1244
+ const mod = await jiti.import(configPath);
1245
+ if (!mod || typeof mod !== "object") {
1246
+ throw new Error(`${configPath}: failed to load config module`);
1231
1247
  }
1248
+ const moduleRecord = mod;
1249
+ if (!moduleRecord.default) {
1250
+ throw new Error(
1251
+ `${configPath}: must use \`export default defineConfig({...})\``
1252
+ );
1253
+ }
1254
+ const config = moduleRecord.default;
1255
+ validateConfig(config, configPath);
1256
+ return { config, configPath };
1232
1257
  }
1233
-
1234
- // src/utils/generator.ts
1235
- function generateTypes(seatTypes, features, plans) {
1236
- const seatTypeUnion = seatTypes.length > 0 ? seatTypes.map((s) => `"${s.code}"`).join(" | ") : "string";
1237
- const planCodeUnion = plans.length > 0 ? plans.map((p) => `"${p.code}"`).join(" | ") : "string";
1238
- const featureCodeUnion = features.length > 0 ? features.map((f) => `"${f.code}"`).join(" | ") : "string";
1239
- const seatComments = seatTypes.map(
1240
- (s) => ` * - "${s.code}": ${s.name}${s.description ? ` - ${s.description}` : ""} ${s.isFree ? "(Free)" : ""}`
1241
- ).join("\n");
1242
- const planComments = plans.map(
1243
- (p) => ` * - "${p.code}": ${p.name}${p.description ? ` - ${p.description}` : ""}`
1244
- ).join("\n");
1245
- const featureComments = features.map(
1246
- (f) => ` * - "${f.code}": ${f.name} (${f.type})${f.description ? ` - ${f.description}` : ""}`
1247
- ).join("\n");
1248
- return `// Auto-generated by Commet CLI
1249
- // Do not edit this file manually - run 'commet pull' to update
1250
-
1251
- /**
1252
- * This augments the Commet SDK with your organization's
1253
- * feature codes, seat types, and plan codes for autocomplete.
1254
- *
1255
- * Features available in your organization:
1256
- ${featureComments || " * (none)"}
1257
- *
1258
- * Seat types available in your organization:
1259
- ${seatComments || " * (none)"}
1260
- *
1261
- * Plans available in your organization:
1262
- ${planComments || " * (none)"}
1263
- *
1264
- */
1265
- declare module '@commet/node' {
1266
- interface CommetGeneratedTypes {
1267
- seatType: ${seatTypeUnion};
1268
- planCode: ${planCodeUnion};
1269
- featureCode: ${featureCodeUnion};
1258
+ var VALID_FEATURE_TYPES = /* @__PURE__ */ new Set(["boolean", "usage", "seats"]);
1259
+ var VALID_INTERVALS = /* @__PURE__ */ new Set([
1260
+ "weekly",
1261
+ "monthly",
1262
+ "quarterly",
1263
+ "yearly",
1264
+ "one_time"
1265
+ ]);
1266
+ function validateConfig(config, configPath) {
1267
+ if (!config || typeof config !== "object") {
1268
+ throw new Error(`${configPath}: config must be an object`);
1269
+ }
1270
+ if (!config.features || typeof config.features !== "object") {
1271
+ throw new Error(`${configPath}: config.features must be an object`);
1272
+ }
1273
+ if (!config.plans || typeof config.plans !== "object") {
1274
+ throw new Error(`${configPath}: config.plans must be an object`);
1275
+ }
1276
+ for (const [code, feature] of Object.entries(config.features)) {
1277
+ if (!feature.name || typeof feature.name !== "string") {
1278
+ throw new Error(`Feature "${code}": name is required`);
1279
+ }
1280
+ if (!VALID_FEATURE_TYPES.has(feature.type)) {
1281
+ throw new Error(
1282
+ `Feature "${code}": type must be one of: boolean, usage, seats`
1283
+ );
1284
+ }
1285
+ }
1286
+ for (const [code, plan] of Object.entries(config.plans)) {
1287
+ if (!plan.name || typeof plan.name !== "string") {
1288
+ throw new Error(`Plan "${code}": name is required`);
1289
+ }
1290
+ if (!Array.isArray(plan.prices)) {
1291
+ throw new Error(`Plan "${code}": prices must be an array`);
1292
+ }
1293
+ for (const price of plan.prices) {
1294
+ if (!VALID_INTERVALS.has(price.interval)) {
1295
+ throw new Error(
1296
+ `Plan "${code}": price interval "${price.interval}" is not valid`
1297
+ );
1298
+ }
1299
+ if (typeof price.amount !== "number") {
1300
+ throw new Error(`Plan "${code}": price amount must be a number`);
1301
+ }
1302
+ }
1303
+ if (plan.prices.length > 0) {
1304
+ if (!plan.defaultInterval) {
1305
+ throw new Error(
1306
+ `Plan "${code}": defaultInterval is required when prices are defined`
1307
+ );
1308
+ }
1309
+ const priceIntervals = new Set(plan.prices.map((p) => p.interval));
1310
+ if (!priceIntervals.has(plan.defaultInterval)) {
1311
+ throw new Error(
1312
+ `Plan "${code}": defaultInterval "${plan.defaultInterval}" does not match any price interval (${[...priceIntervals].join(", ")})`
1313
+ );
1314
+ }
1315
+ }
1316
+ if (plan.features) {
1317
+ for (const featureCode of Object.keys(plan.features)) {
1318
+ if (!config.features[featureCode]) {
1319
+ throw new Error(
1320
+ `Plan "${code}": references feature "${featureCode}" which is not defined in config.features`
1321
+ );
1322
+ }
1323
+ }
1324
+ }
1270
1325
  }
1271
1326
  }
1272
1327
 
1273
- export {};
1274
- `;
1328
+ // src/utils/diff.ts
1329
+ var import_chalk10 = __toESM(require("chalk"));
1330
+ function computeDiff(config, remote) {
1331
+ const remoteFeatureMap = new Map(remote.features.map((f) => [f.code, f]));
1332
+ const remotePlanMap = new Map(remote.plans.map((p) => [p.code, p]));
1333
+ const featureChanges = [];
1334
+ for (const [code, localFeature] of Object.entries(config.features)) {
1335
+ const remoteFeature = remoteFeatureMap.get(code);
1336
+ if (!remoteFeature) {
1337
+ featureChanges.push({ code, action: "create" });
1338
+ continue;
1339
+ }
1340
+ const changes = [];
1341
+ if (remoteFeature.name !== localFeature.name) {
1342
+ changes.push(`name: "${remoteFeature.name}" \u2192 "${localFeature.name}"`);
1343
+ }
1344
+ if (remoteFeature.type !== localFeature.type) {
1345
+ changes.push(
1346
+ `type: "${remoteFeature.type}" \u2192 "${localFeature.type}" (BLOCKED)`
1347
+ );
1348
+ }
1349
+ if ("unitName" in localFeature && (remoteFeature.unitName ?? void 0) !== localFeature.unitName) {
1350
+ changes.push(
1351
+ `unitName: "${remoteFeature.unitName ?? ""}" \u2192 "${localFeature.unitName}"`
1352
+ );
1353
+ }
1354
+ featureChanges.push(
1355
+ changes.length > 0 ? { code, action: "update", changes } : { code, action: "unchanged" }
1356
+ );
1357
+ }
1358
+ const unmanagedFeatures = remote.features.filter((f) => !config.features[f.code]).map((f) => f.code);
1359
+ const planChanges = [];
1360
+ for (const [code, localPlan] of Object.entries(config.plans)) {
1361
+ const remotePlan = remotePlanMap.get(code);
1362
+ if (!remotePlan) {
1363
+ planChanges.push({ code, action: "create" });
1364
+ continue;
1365
+ }
1366
+ const changes = [];
1367
+ if (remotePlan.name !== localPlan.name) {
1368
+ changes.push(`name: "${remotePlan.name}" \u2192 "${localPlan.name}"`);
1369
+ }
1370
+ const remoteDefaultInterval = remotePlan.defaultInterval ?? remotePlan.prices.find((p) => p.isDefault)?.billingInterval ?? null;
1371
+ if (localPlan.defaultInterval && remoteDefaultInterval !== localPlan.defaultInterval) {
1372
+ changes.push(
1373
+ `defaultInterval: "${remoteDefaultInterval ?? "none"}" \u2192 "${localPlan.defaultInterval}"`
1374
+ );
1375
+ }
1376
+ const localPriceMap = new Map(localPlan.prices.map((p) => [p.interval, p]));
1377
+ const remotePriceMap = new Map(
1378
+ remotePlan.prices.map((p) => [p.billingInterval, p])
1379
+ );
1380
+ for (const [interval, localPrice] of localPriceMap) {
1381
+ const remotePrice = remotePriceMap.get(interval);
1382
+ if (!remotePrice) {
1383
+ changes.push(
1384
+ `price ${interval}: new ($${(localPrice.amount / 1e4).toFixed(2)})`
1385
+ );
1386
+ } else if (remotePrice.price !== localPrice.amount) {
1387
+ changes.push(
1388
+ `price ${interval}: $${(remotePrice.price / 1e4).toFixed(2)} \u2192 $${(localPrice.amount / 1e4).toFixed(2)}`
1389
+ );
1390
+ }
1391
+ }
1392
+ if (localPlan.features) {
1393
+ const remotePlanFeatureMap = new Map(
1394
+ remotePlan.features.map((f) => [f.featureCode, f])
1395
+ );
1396
+ for (const featureCode of Object.keys(localPlan.features)) {
1397
+ if (!remotePlanFeatureMap.has(featureCode)) {
1398
+ changes.push(`feature ${featureCode}: new`);
1399
+ }
1400
+ }
1401
+ }
1402
+ planChanges.push(
1403
+ changes.length > 0 ? { code, action: "update", changes } : { code, action: "unchanged" }
1404
+ );
1405
+ }
1406
+ const unmanagedPlans = remote.plans.filter((p) => !config.plans[p.code]).map((p) => p.code);
1407
+ const hasChanges = featureChanges.some((c) => c.action !== "unchanged") || planChanges.some((c) => c.action !== "unchanged");
1408
+ return {
1409
+ features: { changes: featureChanges, unmanaged: unmanagedFeatures },
1410
+ plans: { changes: planChanges, unmanaged: unmanagedPlans },
1411
+ hasChanges
1412
+ };
1275
1413
  }
1276
-
1277
- // src/utils/tsconfig-updater.ts
1278
- var fs5 = __toESM(require("fs"));
1279
- var path5 = __toESM(require("path"));
1280
- var import_jsonc_parser = require("jsonc-parser");
1281
- function updateTsConfig(entry) {
1282
- const cwd = process.cwd();
1283
- const tsconfigPath = path5.join(cwd, "tsconfig.json");
1284
- try {
1285
- if (!fs5.existsSync(tsconfigPath)) {
1286
- return {
1287
- success: false,
1288
- error: "tsconfig.json not found"
1289
- };
1414
+ function formatDiff(diff) {
1415
+ const lines = [];
1416
+ lines.push(import_chalk10.default.bold("\nFeatures:"));
1417
+ for (const change of diff.features.changes) {
1418
+ if (change.action === "create") {
1419
+ lines.push(import_chalk10.default.green(` + ${change.code}`));
1420
+ } else if (change.action === "update") {
1421
+ lines.push(import_chalk10.default.yellow(` ~ ${change.code}`));
1422
+ for (const c of change.changes ?? []) {
1423
+ lines.push(import_chalk10.default.dim(` ${c}`));
1424
+ }
1425
+ } else {
1426
+ lines.push(import_chalk10.default.dim(` ${change.code}`));
1290
1427
  }
1291
- const content = fs5.readFileSync(tsconfigPath, "utf8");
1292
- const config = (0, import_jsonc_parser.parse)(content);
1293
- if (config.include && Array.isArray(config.include)) {
1294
- if (config.include.includes(entry)) {
1295
- return { success: true };
1428
+ }
1429
+ if (diff.features.unmanaged.length > 0) {
1430
+ lines.push(
1431
+ import_chalk10.default.dim(
1432
+ ` ? unmanaged: ${diff.features.unmanaged.join(", ")} (not in config, left as-is)`
1433
+ )
1434
+ );
1435
+ }
1436
+ lines.push(import_chalk10.default.bold("\nPlans:"));
1437
+ for (const change of diff.plans.changes) {
1438
+ if (change.action === "create") {
1439
+ lines.push(import_chalk10.default.green(` + ${change.code}`));
1440
+ } else if (change.action === "update") {
1441
+ lines.push(import_chalk10.default.yellow(` ~ ${change.code}`));
1442
+ for (const c of change.changes ?? []) {
1443
+ lines.push(import_chalk10.default.dim(` ${c}`));
1296
1444
  }
1445
+ } else {
1446
+ lines.push(import_chalk10.default.dim(` ${change.code}`));
1297
1447
  }
1298
- const currentInclude = config.include || [];
1299
- const newInclude = [...currentInclude, entry];
1300
- const edits = (0, import_jsonc_parser.modify)(content, ["include"], newInclude, {
1301
- formattingOptions: {
1302
- insertSpaces: true,
1303
- tabSize: 2
1448
+ }
1449
+ if (diff.plans.unmanaged.length > 0) {
1450
+ lines.push(
1451
+ import_chalk10.default.dim(
1452
+ ` ? unmanaged: ${diff.plans.unmanaged.join(", ")} (not in config, left as-is)`
1453
+ )
1454
+ );
1455
+ }
1456
+ return lines.join("\n");
1457
+ }
1458
+
1459
+ // src/utils/generator.ts
1460
+ function generateConfigFile(features, plans) {
1461
+ const lines = [];
1462
+ lines.push('import { defineConfig } from "@commet/node";');
1463
+ lines.push("");
1464
+ lines.push("export default defineConfig({");
1465
+ lines.push(" features: {");
1466
+ for (const f of features) {
1467
+ const parts = [`name: "${f.name}"`, `type: "${f.type}"`];
1468
+ if (f.unitName) parts.push(`unitName: "${f.unitName}"`);
1469
+ if (f.description) parts.push(`description: "${f.description}"`);
1470
+ lines.push(` ${f.code}: { ${parts.join(", ")} },`);
1471
+ }
1472
+ lines.push(" },");
1473
+ lines.push(" plans: {");
1474
+ for (const p of plans) {
1475
+ lines.push(` ${p.code}: {`);
1476
+ lines.push(` name: "${p.name}",`);
1477
+ if (p.description) lines.push(` description: "${p.description}",`);
1478
+ if (p.consumptionModel)
1479
+ lines.push(` consumptionModel: "${p.consumptionModel}",`);
1480
+ if (p.isFree) lines.push(" isFree: true,");
1481
+ if (p.isPublic === false) lines.push(" isPublic: false,");
1482
+ if (p.sortOrder != null && p.sortOrder !== 0)
1483
+ lines.push(` sortOrder: ${p.sortOrder},`);
1484
+ const prices = p.prices ?? [];
1485
+ const defaultInterval = p.defaultInterval ?? prices.find((pr) => pr.isDefault)?.billingInterval ?? prices[0]?.billingInterval;
1486
+ if (defaultInterval)
1487
+ lines.push(` defaultInterval: "${defaultInterval}",`);
1488
+ if (prices.length === 0) {
1489
+ lines.push(" prices: [],");
1490
+ } else {
1491
+ lines.push(" prices: [");
1492
+ for (const price of prices) {
1493
+ const priceParts = [
1494
+ `interval: "${price.billingInterval}"`,
1495
+ `amount: ${price.price}`
1496
+ ];
1497
+ if (price.trialDays) priceParts.push(`trialDays: ${price.trialDays}`);
1498
+ lines.push(` { ${priceParts.join(", ")} },`);
1304
1499
  }
1305
- });
1306
- const updatedContent = (0, import_jsonc_parser.applyEdits)(content, edits);
1307
- fs5.writeFileSync(tsconfigPath, updatedContent, "utf8");
1308
- return { success: true };
1309
- } catch (error) {
1310
- return {
1311
- success: false,
1312
- error: error instanceof Error ? error.message : "Unknown error updating tsconfig.json"
1313
- };
1500
+ lines.push(" ],");
1501
+ }
1502
+ const planFeatures = p.features ?? [];
1503
+ if (planFeatures.length > 0) {
1504
+ lines.push(" features: {");
1505
+ for (const pf of planFeatures) {
1506
+ const featureDef = features.find((f) => f.code === pf.featureCode);
1507
+ const isBoolean = featureDef?.type === "boolean";
1508
+ if (isBoolean) {
1509
+ lines.push(` ${pf.featureCode}: ${pf.enabled ?? true},`);
1510
+ } else {
1511
+ const parts = [];
1512
+ if (pf.includedAmount) parts.push(`included: ${pf.includedAmount}`);
1513
+ if (pf.unlimited) parts.push("unlimited: true");
1514
+ if (pf.overageEnabled && pf.overageUnitPrice) {
1515
+ parts.push(`overage: { unitPrice: ${pf.overageUnitPrice} }`);
1516
+ }
1517
+ if (parts.length > 0) {
1518
+ lines.push(` ${pf.featureCode}: { ${parts.join(", ")} },`);
1519
+ } else {
1520
+ lines.push(` ${pf.featureCode}: {},`);
1521
+ }
1522
+ }
1523
+ }
1524
+ lines.push(" },");
1525
+ }
1526
+ lines.push(" },");
1314
1527
  }
1528
+ lines.push(" },");
1529
+ lines.push("});");
1530
+ lines.push("");
1531
+ return lines.join("\n");
1315
1532
  }
1316
1533
 
1317
1534
  // src/commands/pull.ts
1318
- var pullCommand = new import_commander8.Command("pull").description("Pull type definitions from Commet").action(async () => {
1535
+ var pullCommand = new import_commander8.Command("pull").description("Pull config from Commet and generate commet.config.ts").option("-y, --yes", "Skip confirmation prompt").option("--dry-run", "Show diff without applying changes").option("--json", "Output structured JSON (no colors, no prompts)").action(async (options) => {
1536
+ const jsonMode = options.json;
1319
1537
  if (!authExists()) {
1320
- console.log(import_chalk10.default.red("\u2717 Not authenticated"));
1321
- console.log(import_chalk10.default.dim("Run `commet login` first"));
1322
- return;
1538
+ if (jsonMode) {
1539
+ console.log(JSON.stringify({ error: "Not authenticated" }));
1540
+ } else {
1541
+ console.log(import_chalk11.default.red("\u2717 Not authenticated"));
1542
+ console.log(import_chalk11.default.dim("Run `commet login` first"));
1543
+ }
1544
+ process.exit(1);
1323
1545
  }
1324
- const hasTsConfig = validateTypeScriptProject();
1325
1546
  if (!projectConfigExists()) {
1326
- console.log(import_chalk10.default.red("\u2717 Project not linked"));
1327
- console.log(
1328
- import_chalk10.default.dim("Run `commet link` first to connect to an organization")
1329
- );
1330
- return;
1547
+ if (jsonMode) {
1548
+ console.log(JSON.stringify({ error: "Project not linked" }));
1549
+ } else {
1550
+ console.log(import_chalk11.default.red("\u2717 Project not linked"));
1551
+ console.log(
1552
+ import_chalk11.default.dim("Run `commet link` first to connect to an organization")
1553
+ );
1554
+ }
1555
+ process.exit(1);
1331
1556
  }
1332
1557
  const projectConfig = loadProjectConfig();
1333
1558
  if (!projectConfig) {
1334
- console.log(import_chalk10.default.red("\u2717 Invalid project configuration"));
1335
- return;
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);
1336
1565
  }
1337
- const spinner = (0, import_ora5.default)("Fetching type definitions...").start();
1566
+ const spinner = jsonMode ? null : (0, import_ora5.default)("Fetching config from remote...").start();
1338
1567
  const result = await apiRequest(
1339
- `${BASE_URL}/api/cli/types?orgId=${projectConfig.orgId}`
1568
+ `${BASE_URL}/api/cli/pull?orgId=${projectConfig.orgId}`
1340
1569
  );
1341
1570
  if (result.error || !result.data) {
1342
- spinner.fail("Failed to fetch types");
1343
- console.error(import_chalk10.default.red("Error:"), result.error);
1344
- return;
1571
+ if (jsonMode) {
1572
+ console.log(JSON.stringify({ error: result.error }));
1573
+ } else {
1574
+ spinner?.fail("Failed to fetch config");
1575
+ console.error(import_chalk11.default.red("Error:"), result.error);
1576
+ }
1577
+ process.exit(1);
1345
1578
  }
1346
- const { seatTypes, features, plans } = result.data;
1347
- const typeDefinitions = generateTypes(seatTypes, features, plans);
1348
- const commetDir = path6.resolve(process.cwd(), ".commet");
1349
- const outputPath = path6.join(commetDir, "types.d.ts");
1350
- fs6.mkdirSync(commetDir, { recursive: true });
1351
- fs6.writeFileSync(outputPath, typeDefinitions, "utf8");
1352
- spinner.succeed("Type definitions generated!");
1353
- if (hasTsConfig) {
1354
- const tsconfigResult = updateTsConfig(".commet/types.d.ts");
1355
- if (tsconfigResult.success) {
1356
- console.log(import_chalk10.default.green("\u2713 Updated tsconfig.json"));
1579
+ spinner?.succeed("Remote state fetched");
1580
+ const { features, plans } = result.data;
1581
+ const configContent = generateConfigFile(features, plans);
1582
+ const outputPath = path5.resolve(process.cwd(), "commet.config.ts");
1583
+ const existingConfigPath = findConfigFile(process.cwd());
1584
+ if (!existingConfigPath) {
1585
+ if (options.dryRun) {
1586
+ if (jsonMode) {
1587
+ console.log(
1588
+ JSON.stringify({
1589
+ action: "create",
1590
+ features: features.length,
1591
+ plans: plans.length,
1592
+ applied: false
1593
+ })
1594
+ );
1595
+ } else {
1596
+ console.log(
1597
+ import_chalk11.default.green(
1598
+ `
1599
+ Would create commet.config.ts (${features.length} features, ${plans.length} plans)`
1600
+ )
1601
+ );
1602
+ }
1603
+ return;
1604
+ }
1605
+ fs5.writeFileSync(outputPath, configContent, "utf8");
1606
+ if (jsonMode) {
1607
+ console.log(
1608
+ JSON.stringify({
1609
+ action: "create",
1610
+ features: features.length,
1611
+ plans: plans.length,
1612
+ applied: true
1613
+ })
1614
+ );
1357
1615
  } else {
1358
- console.log(import_chalk10.default.yellow("\u26A0 Could not update tsconfig.json"));
1616
+ console.log(import_chalk11.default.green(`
1617
+ \u2713 Created commet.config.ts`));
1359
1618
  console.log(
1360
- import_chalk10.default.dim(
1361
- 'Add ".commet/types.d.ts" to your tsconfig.json include array'
1362
- )
1619
+ import_chalk11.default.dim(` ${features.length} features, ${plans.length} plans`)
1363
1620
  );
1364
1621
  }
1622
+ return;
1623
+ }
1624
+ const localLoaded = await loadBillingConfig(process.cwd()).catch(
1625
+ (error) => ({
1626
+ parseError: error instanceof Error ? error.message : String(error)
1627
+ })
1628
+ );
1629
+ if ("parseError" in localLoaded) {
1630
+ if (options.dryRun) {
1631
+ if (jsonMode) {
1632
+ console.log(
1633
+ JSON.stringify({
1634
+ action: "overwrite",
1635
+ reason: localLoaded.parseError,
1636
+ applied: false
1637
+ })
1638
+ );
1639
+ } else {
1640
+ console.log(
1641
+ import_chalk11.default.yellow(
1642
+ `
1643
+ \u26A0 Local config is invalid: ${localLoaded.parseError}`
1644
+ )
1645
+ );
1646
+ }
1647
+ return;
1648
+ }
1649
+ if (!options.yes && !jsonMode) {
1650
+ console.log(import_chalk11.default.yellow(`
1651
+ \u26A0 ${localLoaded.parseError}`));
1652
+ const shouldProceed = await (0, import_prompts3.confirm)({
1653
+ message: "Overwrite with remote?",
1654
+ default: true
1655
+ });
1656
+ if (!shouldProceed) {
1657
+ console.log(import_chalk11.default.dim("Pull cancelled"));
1658
+ return;
1659
+ }
1660
+ }
1661
+ fs5.writeFileSync(outputPath, configContent, "utf8");
1662
+ if (jsonMode) {
1663
+ console.log(JSON.stringify({ action: "overwrite", applied: true }));
1664
+ } else {
1665
+ console.log(import_chalk11.default.green("\n\u2713 Overwritten commet.config.ts"));
1666
+ }
1667
+ return;
1668
+ }
1669
+ const localConfig = localLoaded.config;
1670
+ const remoteAsConfig = {
1671
+ features: Object.fromEntries(
1672
+ features.map((f) => [
1673
+ f.code,
1674
+ {
1675
+ name: f.name,
1676
+ type: f.type,
1677
+ ...f.unitName ? { unitName: f.unitName } : {},
1678
+ ...f.description ? { description: f.description } : {}
1679
+ }
1680
+ ])
1681
+ ),
1682
+ plans: Object.fromEntries(
1683
+ plans.map((p) => [
1684
+ p.code,
1685
+ {
1686
+ name: p.name,
1687
+ ...p.description ? { description: p.description } : {},
1688
+ ...p.consumptionModel ? {
1689
+ consumptionModel: p.consumptionModel
1690
+ } : {},
1691
+ ...p.isFree ? { isFree: true } : {},
1692
+ ...p.isPublic === false ? { isPublic: false } : {},
1693
+ ...p.sortOrder ? { sortOrder: p.sortOrder } : {},
1694
+ ...(() => {
1695
+ const planPrices = p.prices ?? [];
1696
+ const defaultPrice = planPrices.find((pr) => pr.isDefault);
1697
+ const defaultInterval = defaultPrice?.billingInterval ?? planPrices[0]?.billingInterval;
1698
+ return defaultInterval ? { defaultInterval } : {};
1699
+ })(),
1700
+ prices: (p.prices ?? []).map((pr) => ({
1701
+ interval: pr.billingInterval,
1702
+ amount: pr.price,
1703
+ ...pr.trialDays ? { trialDays: pr.trialDays } : {}
1704
+ }))
1705
+ }
1706
+ ])
1707
+ )
1708
+ };
1709
+ const localAsRemote = {
1710
+ features: Object.entries(localConfig.features).map(([code, f]) => ({
1711
+ code,
1712
+ name: f.name,
1713
+ type: f.type,
1714
+ description: f.description ?? null,
1715
+ unitName: f.unitName ?? null
1716
+ })),
1717
+ plans: Object.entries(localConfig.plans).map(([code, p]) => ({
1718
+ code,
1719
+ name: p.name,
1720
+ description: p.description ?? null,
1721
+ consumptionModel: p.consumptionModel ?? null,
1722
+ defaultInterval: p.defaultInterval ?? null,
1723
+ isFree: p.isFree,
1724
+ isPublic: p.isPublic,
1725
+ sortOrder: p.sortOrder,
1726
+ prices: p.prices.map((pr) => ({
1727
+ billingInterval: pr.interval,
1728
+ price: pr.amount,
1729
+ trialDays: pr.trialDays ?? null
1730
+ })),
1731
+ features: []
1732
+ }))
1733
+ };
1734
+ const diff = computeDiff(remoteAsConfig, localAsRemote);
1735
+ if (!diff.hasChanges && diff.features.unmanaged.length === 0 && diff.plans.unmanaged.length === 0) {
1736
+ if (jsonMode) {
1737
+ console.log(JSON.stringify({ diff, applied: false, upToDate: true }));
1738
+ } else {
1739
+ console.log(import_chalk11.default.green("\n\u2713 Already up to date"));
1740
+ }
1741
+ return;
1742
+ }
1743
+ if (jsonMode) {
1744
+ if (options.dryRun) {
1745
+ console.log(JSON.stringify({ diff, applied: false }));
1746
+ return;
1747
+ }
1365
1748
  } else {
1366
- console.log(import_chalk10.default.yellow("\u26A0 No tsconfig.json found"));
1749
+ console.log(formatDiff(diff));
1750
+ }
1751
+ if (options.dryRun) {
1752
+ if (!jsonMode) {
1753
+ console.log(import_chalk11.default.dim("\n(dry run \u2014 no changes applied)"));
1754
+ }
1755
+ return;
1756
+ }
1757
+ if (!options.yes && !jsonMode) {
1758
+ const shouldProceed = await (0, import_prompts3.confirm)({
1759
+ message: "Overwrite commet.config.ts with remote state?",
1760
+ default: true
1761
+ });
1762
+ if (!shouldProceed) {
1763
+ console.log(import_chalk11.default.dim("Pull cancelled"));
1764
+ return;
1765
+ }
1766
+ }
1767
+ fs5.writeFileSync(outputPath, configContent, "utf8");
1768
+ if (jsonMode) {
1769
+ console.log(JSON.stringify({ diff, applied: true }));
1770
+ } else {
1771
+ console.log(import_chalk11.default.green("\n\u2713 Updated commet.config.ts"));
1367
1772
  console.log(
1368
- import_chalk10.default.dim(
1369
- 'Add ".commet/types.d.ts" to your tsconfig.json to enable types'
1370
- )
1773
+ import_chalk11.default.dim(` ${features.length} features, ${plans.length} plans`)
1371
1774
  );
1372
1775
  }
1373
- const gitignoreResult = updateGitignore(".commet/");
1374
- if (gitignoreResult.success) {
1375
- console.log(import_chalk10.default.green("\u2713 Updated .gitignore"));
1376
- } else {
1377
- console.log(import_chalk10.default.yellow("\u26A0 No .gitignore found"));
1378
- console.log(import_chalk10.default.dim("Add .commet/ to your .gitignore file"));
1776
+ });
1777
+
1778
+ // src/commands/push.ts
1779
+ var import_prompts4 = require("@inquirer/prompts");
1780
+ var import_chalk12 = __toESM(require("chalk"));
1781
+ var import_commander9 = require("commander");
1782
+ var import_ora6 = __toESM(require("ora"));
1783
+ var pushCommand = new import_commander9.Command("push").description("Push commet.config.ts to your Commet organization").option("-y, --yes", "Skip confirmation prompt").option("--dry-run", "Show diff without applying changes").option("--json", "Output structured JSON (no colors, no prompts)").action(async (options) => {
1784
+ const jsonMode = options.json;
1785
+ if (!authExists()) {
1786
+ if (jsonMode) {
1787
+ console.log(JSON.stringify({ error: "Not authenticated" }));
1788
+ } else {
1789
+ console.log(import_chalk12.default.red("\u2717 Not authenticated"));
1790
+ console.log(import_chalk12.default.dim("Run `commet login` first"));
1791
+ }
1792
+ process.exit(1);
1379
1793
  }
1380
- console.log(import_chalk10.default.green("\nSuccess!"));
1381
- console.log(import_chalk10.default.dim("\nGenerated types:"));
1382
- console.log(
1383
- import_chalk10.default.dim(
1384
- ` Features: ${features.length > 0 ? features.map((f) => f.code).join(", ") : "none"}`
1385
- )
1794
+ if (!projectConfigExists()) {
1795
+ if (jsonMode) {
1796
+ console.log(JSON.stringify({ error: "Project not linked" }));
1797
+ } else {
1798
+ console.log(import_chalk12.default.red("\u2717 Project not linked"));
1799
+ console.log(
1800
+ import_chalk12.default.dim("Run `commet link` first to connect to an organization")
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();
1815
+ const loaded = await loadBillingConfig(process.cwd()).catch(
1816
+ (error) => {
1817
+ const message = error instanceof Error ? error.message : String(error);
1818
+ if (jsonMode) {
1819
+ console.log(JSON.stringify({ error: message }));
1820
+ } else {
1821
+ loadSpinner?.fail("Failed to load config");
1822
+ console.error(import_chalk12.default.red(message));
1823
+ }
1824
+ return null;
1825
+ }
1386
1826
  );
1387
- console.log(
1388
- import_chalk10.default.dim(
1389
- ` Seat types: ${seatTypes.length > 0 ? seatTypes.map((s) => s.code).join(", ") : "none"}`
1390
- )
1827
+ if (!loaded) process.exit(1);
1828
+ const { config, configPath } = loaded;
1829
+ loadSpinner?.succeed(`Loaded ${configPath}`);
1830
+ const fetchSpinner = jsonMode ? null : (0, import_ora6.default)("Fetching remote state...").start();
1831
+ const remoteResult = await apiRequest(
1832
+ `${BASE_URL}/api/cli/pull?orgId=${projectConfig.orgId}`
1391
1833
  );
1392
- console.log(
1393
- import_chalk10.default.dim(
1394
- ` Plans: ${plans.length > 0 ? plans.map((p) => p.code).join(", ") : "none"}`
1395
- )
1834
+ if (remoteResult.error || !remoteResult.data) {
1835
+ if (jsonMode) {
1836
+ console.log(JSON.stringify({ error: remoteResult.error }));
1837
+ } else {
1838
+ fetchSpinner?.fail("Failed to fetch remote state");
1839
+ console.error(import_chalk12.default.red("Error:"), remoteResult.error);
1840
+ }
1841
+ process.exit(1);
1842
+ }
1843
+ fetchSpinner?.succeed("Remote state fetched");
1844
+ const remote = {
1845
+ features: remoteResult.data.features,
1846
+ plans: remoteResult.data.plans
1847
+ };
1848
+ const diff = computeDiff(config, remote);
1849
+ if (jsonMode) {
1850
+ if (options.dryRun) {
1851
+ console.log(JSON.stringify({ diff, applied: false }));
1852
+ return;
1853
+ }
1854
+ } else {
1855
+ console.log(formatDiff(diff));
1856
+ }
1857
+ if (!diff.hasChanges) {
1858
+ if (jsonMode) {
1859
+ console.log(JSON.stringify({ diff, applied: false, upToDate: true }));
1860
+ } else {
1861
+ console.log(import_chalk12.default.green("\n\u2713 Everything is up to date"));
1862
+ }
1863
+ return;
1864
+ }
1865
+ const typeChanges = diff.features.changes.filter(
1866
+ (c) => c.action === "update" && c.changes?.some((ch) => ch.includes("BLOCKED"))
1867
+ );
1868
+ if (typeChanges.length > 0) {
1869
+ const blockedCodes = typeChanges.map((c) => c.code);
1870
+ if (jsonMode) {
1871
+ console.log(
1872
+ JSON.stringify({
1873
+ error: "Feature type changes blocked",
1874
+ blockedCodes,
1875
+ diff
1876
+ })
1877
+ );
1878
+ } else {
1879
+ console.log(
1880
+ import_chalk12.default.red(
1881
+ "\n\u2717 Cannot change feature types. Update them in the dashboard:"
1882
+ )
1883
+ );
1884
+ for (const change of typeChanges) {
1885
+ console.log(import_chalk12.default.red(` - ${change.code}`));
1886
+ }
1887
+ }
1888
+ process.exit(1);
1889
+ }
1890
+ if (options.dryRun) {
1891
+ if (!jsonMode) {
1892
+ console.log(import_chalk12.default.dim("\n(dry run \u2014 no changes applied)"));
1893
+ }
1894
+ return;
1895
+ }
1896
+ if (!options.yes && !jsonMode) {
1897
+ const shouldProceed = await (0, import_prompts4.confirm)({
1898
+ message: "Apply these changes?",
1899
+ default: true
1900
+ });
1901
+ if (!shouldProceed) {
1902
+ console.log(import_chalk12.default.dim("Push cancelled"));
1903
+ return;
1904
+ }
1905
+ }
1906
+ const pushSpinner = jsonMode ? null : (0, import_ora6.default)("Pushing config...").start();
1907
+ const pushResult = await apiRequest(
1908
+ `${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
+ }
1396
1919
  );
1397
- console.log(import_chalk10.default.dim(`
1398
- Output: ${outputPath}`));
1399
- if (seatTypes.length === 0 && plans.length === 0 && features.length === 0) {
1920
+ if (pushResult.error || !pushResult.data) {
1921
+ if (jsonMode) {
1922
+ console.log(JSON.stringify({ error: pushResult.error }));
1923
+ } else {
1924
+ pushSpinner?.fail("Push failed");
1925
+ console.error(import_chalk12.default.red("Error:"), pushResult.error);
1926
+ }
1927
+ process.exit(1);
1928
+ }
1929
+ const pushOutcome = pushResult.data;
1930
+ if (jsonMode) {
1931
+ console.log(JSON.stringify({ diff, applied: true, result: pushOutcome }));
1932
+ return;
1933
+ }
1934
+ const errors = [
1935
+ ...pushOutcome.features.errors,
1936
+ ...pushOutcome.plans.errors
1937
+ ];
1938
+ if (errors.length > 0) {
1939
+ pushSpinner?.warn("Push completed with errors");
1940
+ for (const error of errors) {
1941
+ console.log(import_chalk12.default.red(` \u2717 ${error.code}: ${error.message}`));
1942
+ }
1943
+ } else {
1944
+ pushSpinner?.succeed("Push complete");
1945
+ }
1946
+ if (pushOutcome.features.created.length > 0) {
1947
+ console.log(
1948
+ import_chalk12.default.green(
1949
+ ` Created features: ${pushOutcome.features.created.join(", ")}`
1950
+ )
1951
+ );
1952
+ }
1953
+ if (pushOutcome.features.updated.length > 0) {
1954
+ console.log(
1955
+ import_chalk12.default.yellow(
1956
+ ` Updated features: ${pushOutcome.features.updated.join(", ")}`
1957
+ )
1958
+ );
1959
+ }
1960
+ if (pushOutcome.plans.created.length > 0) {
1400
1961
  console.log(
1401
- import_chalk10.default.yellow(
1402
- "\n\u26A0 No types found. Create features, seat types, and plans in your Commet dashboard."
1962
+ import_chalk12.default.green(` Created plans: ${pushOutcome.plans.created.join(", ")}`)
1963
+ );
1964
+ }
1965
+ if (pushOutcome.plans.updated.length > 0) {
1966
+ console.log(
1967
+ import_chalk12.default.yellow(
1968
+ ` Updated plans: ${pushOutcome.plans.updated.join(", ")}`
1403
1969
  )
1404
1970
  );
1405
1971
  }
1406
1972
  });
1407
1973
 
1408
1974
  // src/commands/switch.ts
1409
- var import_prompts3 = require("@inquirer/prompts");
1410
- var import_chalk11 = __toESM(require("chalk"));
1411
- var import_commander9 = require("commander");
1412
- var import_ora6 = __toESM(require("ora"));
1413
- var switchCommand = new import_commander9.Command("switch").description("Switch to a different organization").action(async () => {
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 () => {
1414
1980
  if (!authExists()) {
1415
- console.log(import_chalk11.default.red("\u2717 Not authenticated"));
1416
- console.log(import_chalk11.default.dim("Run `commet login` first"));
1981
+ console.log(import_chalk13.default.red("\u2717 Not authenticated"));
1982
+ console.log(import_chalk13.default.dim("Run `commet login` first"));
1417
1983
  return;
1418
1984
  }
1419
1985
  if (!projectConfigExists()) {
1420
- console.log(import_chalk11.default.yellow("\u26A0 Project not linked"));
1986
+ console.log(import_chalk13.default.yellow("\u26A0 Project not linked"));
1421
1987
  console.log(
1422
- import_chalk11.default.dim("Run `commet link` first to connect to an organization")
1988
+ import_chalk13.default.dim("Run `commet link` first to connect to an organization")
1423
1989
  );
1424
1990
  return;
1425
1991
  }
1426
- const spinner = (0, import_ora6.default)("Fetching organizations...").start();
1992
+ const spinner = (0, import_ora7.default)("Fetching organizations...").start();
1427
1993
  const result = await apiRequest(
1428
1994
  `${BASE_URL}/api/cli/organizations`
1429
1995
  );
1430
1996
  if (result.error || !result.data) {
1431
1997
  spinner.fail("Failed to fetch organizations");
1432
- console.error(import_chalk11.default.red("Error:"), result.error);
1998
+ console.error(import_chalk13.default.red("Error:"), result.error);
1433
1999
  return;
1434
2000
  }
1435
2001
  const { organizations } = result.data;
1436
2002
  if (organizations.length === 0) {
1437
2003
  spinner.stop();
1438
- console.log(import_chalk11.default.yellow("\u26A0 No organizations found"));
2004
+ console.log(import_chalk13.default.yellow("\u26A0 No organizations found"));
1439
2005
  return;
1440
2006
  }
1441
2007
  spinner.stop();
1442
2008
  let orgId;
1443
2009
  try {
1444
- orgId = await (0, import_prompts3.select)({
2010
+ orgId = await (0, import_prompts5.select)({
1445
2011
  message: "Select organization:",
1446
2012
  choices: organizations.map((org) => ({
1447
- name: `${org.name} ${import_chalk11.default.dim(`(${org.slug}) \xB7 ${org.mode}`)}`,
2013
+ name: `${org.name} ${import_chalk13.default.dim(`(${org.slug}) \xB7 ${org.mode}`)}`,
1448
2014
  value: org.id
1449
2015
  })),
1450
2016
  theme: promptTheme
1451
2017
  });
1452
2018
  } catch (_error) {
1453
- console.log(import_chalk11.default.yellow("\n\u26A0 Switch cancelled"));
2019
+ console.log(import_chalk13.default.yellow("\n\u26A0 Switch cancelled"));
1454
2020
  return;
1455
2021
  }
1456
2022
  const selectedOrg = organizations.find((org) => org.id === orgId);
1457
2023
  if (!selectedOrg) {
1458
- console.log(import_chalk11.default.red("\u2717 Organization not found"));
2024
+ console.log(import_chalk13.default.red("\u2717 Organization not found"));
1459
2025
  return;
1460
2026
  }
1461
2027
  saveProjectConfig({
@@ -1463,55 +2029,55 @@ var switchCommand = new import_commander9.Command("switch").description("Switch
1463
2029
  orgName: selectedOrg.name,
1464
2030
  mode: selectedOrg.mode
1465
2031
  });
1466
- console.log(import_chalk11.default.green("\n\u2713 Switched organization successfully!"));
2032
+ console.log(import_chalk13.default.green("\n\u2713 Switched organization successfully!"));
1467
2033
  console.log(
1468
- import_chalk11.default.dim(`
2034
+ import_chalk13.default.dim(`
1469
2035
  Organization: ${selectedOrg.name} \xB7 ${selectedOrg.mode}`)
1470
2036
  );
1471
2037
  console.log(
1472
- import_chalk11.default.dim(
2038
+ import_chalk13.default.dim(
1473
2039
  "\nRun `commet pull` to update TypeScript types for this organization"
1474
2040
  )
1475
2041
  );
1476
2042
  });
1477
2043
 
1478
2044
  // src/commands/unlink.ts
1479
- var import_chalk12 = __toESM(require("chalk"));
1480
- var import_commander10 = require("commander");
1481
- var unlinkCommand = new import_commander10.Command("unlink").description("Unlink this project from Commet").action(async () => {
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 () => {
1482
2048
  if (!projectConfigExists()) {
1483
2049
  console.log(
1484
- import_chalk12.default.yellow("\u26A0 This project is not linked to any organization")
2050
+ import_chalk14.default.yellow("\u26A0 This project is not linked to any organization")
1485
2051
  );
1486
2052
  return;
1487
2053
  }
1488
2054
  clearProjectConfig();
1489
- console.log(import_chalk12.default.green("\u2713 Project unlinked successfully"));
1490
- console.log(import_chalk12.default.dim("\u2713 Removed .commet/ directory"));
2055
+ console.log(import_chalk14.default.green("\u2713 Project unlinked successfully"));
2056
+ console.log(import_chalk14.default.dim("\u2713 Removed .commet/ directory"));
1491
2057
  console.log(
1492
- import_chalk12.default.dim("\nRun `commet link` to connect to a different organization")
2058
+ import_chalk14.default.dim("\nRun `commet link` to connect to a different organization")
1493
2059
  );
1494
2060
  });
1495
2061
 
1496
2062
  // src/commands/whoami.ts
1497
- var import_chalk13 = __toESM(require("chalk"));
1498
- var import_commander11 = require("commander");
1499
- var whoamiCommand = new import_commander11.Command("whoami").description("Display current authentication and project status").action(async () => {
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 () => {
1500
2066
  if (!authExists()) {
1501
- console.log(import_chalk13.default.yellow("\u26A0 Not logged in"));
1502
- console.log(import_chalk13.default.dim("Run `commet login` to authenticate"));
2067
+ console.log(import_chalk15.default.yellow("\u26A0 Not logged in"));
2068
+ console.log(import_chalk15.default.dim("Run `commet login` to authenticate"));
1503
2069
  return;
1504
2070
  }
1505
- console.log(import_chalk13.default.green("\u2713 Logged in"));
2071
+ console.log(import_chalk15.default.green("\u2713 Logged in"));
1506
2072
  const projectConfig = loadProjectConfig();
1507
2073
  if (projectConfig) {
1508
- console.log(import_chalk13.default.bold("\nProject:"));
1509
- console.log(import_chalk13.default.dim("Organization:"), projectConfig.orgName);
1510
- console.log(import_chalk13.default.dim("Mode:"), projectConfig.mode);
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);
1511
2077
  } else {
1512
- console.log(import_chalk13.default.yellow("\n\u26A0 No project linked"));
2078
+ console.log(import_chalk15.default.yellow("\n\u26A0 No project linked"));
1513
2079
  console.log(
1514
- import_chalk13.default.dim(
2080
+ import_chalk15.default.dim(
1515
2081
  "Run `commet link` to connect this directory to an organization"
1516
2082
  )
1517
2083
  );
@@ -1519,7 +2085,7 @@ var whoamiCommand = new import_commander11.Command("whoami").description("Displa
1519
2085
  });
1520
2086
 
1521
2087
  // src/index.ts
1522
- var program = new import_commander12.Command();
2088
+ var program = new import_commander13.Command();
1523
2089
  program.name("commet").description(
1524
2090
  "Commet CLI - Manage your billing platform from the command line"
1525
2091
  ).version(package_default.version);
@@ -1531,6 +2097,7 @@ program.addCommand(linkCommand);
1531
2097
  program.addCommand(unlinkCommand);
1532
2098
  program.addCommand(switchCommand);
1533
2099
  program.addCommand(infoCommand);
2100
+ program.addCommand(pushCommand);
1534
2101
  program.addCommand(pullCommand);
1535
2102
  program.addCommand(listCommand);
1536
2103
  program.addCommand(listenCommand);
@@ -1543,7 +2110,7 @@ try {
1543
2110
  if (code === "commander.version" || code === "commander.help" || code === "commander.helpDisplayed") {
1544
2111
  process.exit(0);
1545
2112
  }
1546
- console.error(import_chalk14.default.red("Error:"), error.message);
2113
+ console.error(import_chalk16.default.red("Error:"), error.message);
1547
2114
  }
1548
2115
  process.exit(1);
1549
2116
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commet",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "description": "Commet CLI - Manage your billing platform from the command line",
5
5
  "bin": {
6
6
  "commet": "./bin/commet"
@@ -19,17 +19,18 @@
19
19
  "author": "Commet Team",
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
- "@inquirer/prompts": "8.0.1",
22
+ "@inquirer/prompts": "8.4.3",
23
23
  "ably": "^2.21.0",
24
24
  "chalk": "5.6.2",
25
- "commander": "14.0.2",
25
+ "commander": "14.0.3",
26
+ "jiti": "^2.7.0",
26
27
  "jsonc-parser": "3.3.1",
27
28
  "open": "11.0.0",
28
- "ora": "9.0.0",
29
+ "ora": "9.4.0",
29
30
  "tar": "^7.5.13"
30
31
  },
31
32
  "devDependencies": {
32
- "@types/node": "24.10.1",
33
+ "@types/node": "24.12.4",
33
34
  "tsup": "8.5.1",
34
35
  "typescript": "5.9.3"
35
36
  },