ardent-cli 0.0.9 → 0.0.11

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 +565 -56
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,12 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { readFileSync as readFileSync2 } from "fs";
5
- import { Command as Command6 } from "commander";
4
+ import { readFileSync as readFileSync4 } from "fs";
5
+ import { Command as Command7 } from "commander";
6
6
 
7
7
  // src/commands/branch/index.ts
8
8
  import { Command } from "commander";
9
9
 
10
+ // src/lib/api.ts
11
+ import { readFileSync as readFileSync2 } from "fs";
12
+
10
13
  // src/lib/config.ts
11
14
  import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from "fs";
12
15
  import { homedir } from "os";
@@ -104,9 +107,8 @@ async function bootstrapCache() {
104
107
  "Content-Type": "application/json",
105
108
  "Authorization": `Bearer ${token}`
106
109
  };
107
- const [connectorsRes, branchesRes, meRes] = await Promise.all([
110
+ const [connectorsRes, meRes] = await Promise.all([
108
111
  fetch(`${apiUrl}/v1/cli/connectors`, { headers }),
109
- fetch(`${apiUrl}/v1/cli/branches`, { headers }),
110
112
  fetch(`${apiUrl}/v1/cli/me`, { headers })
111
113
  ]);
112
114
  let connectorCount = 0;
@@ -117,20 +119,38 @@ async function bootstrapCache() {
117
119
  setCacheEntry("connectors", connectors);
118
120
  connectorCount = connectors.length;
119
121
  }
120
- if (branchesRes.ok) {
121
- const data = await branchesRes.json();
122
- const branches = data.branches || [];
123
- setCacheEntry("branches", branches);
124
- branchCount = branches.length;
125
- }
126
122
  if (meRes.ok) {
127
123
  const user = await meRes.json();
128
124
  setConfig("user", user);
129
125
  }
126
+ const currentConnectorId = getConfig("currentConnectorId");
127
+ if (currentConnectorId) {
128
+ const branchesRes = await fetch(
129
+ `${apiUrl}/v1/cli/branches?connector_id=${currentConnectorId}`,
130
+ { headers }
131
+ );
132
+ if (branchesRes.ok) {
133
+ const data = await branchesRes.json();
134
+ const branches = data.branches || [];
135
+ setCacheEntry("branches", branches);
136
+ branchCount = branches.length;
137
+ }
138
+ }
130
139
  return { connectors: connectorCount, branches: branchCount };
131
140
  }
132
141
 
133
142
  // src/lib/api.ts
143
+ function getCliVersion() {
144
+ try {
145
+ const packageUrl = new URL("../package.json", import.meta.url);
146
+ const raw = readFileSync2(packageUrl, "utf-8");
147
+ const parsed = JSON.parse(raw);
148
+ return parsed.version ?? "unknown";
149
+ } catch {
150
+ return "unknown";
151
+ }
152
+ }
153
+ var CLI_VERSION = getCliVersion();
134
154
  function parseApiError(status, text) {
135
155
  try {
136
156
  const json = JSON.parse(text);
@@ -139,6 +159,20 @@ function parseApiError(status, text) {
139
159
  }
140
160
  return `API error ${status}: ${text}`;
141
161
  }
162
+ function handleUpgradeRequired(text) {
163
+ try {
164
+ const json = JSON.parse(text);
165
+ if (json.detail) {
166
+ console.error(`
167
+ \u2717 ${json.detail}
168
+ `);
169
+ }
170
+ } catch {
171
+ console.error("\n\u2717 Your CLI is outdated. Please update:\n");
172
+ }
173
+ console.error(" npm install -g ardent-cli@latest\n");
174
+ process.exit(1);
175
+ }
142
176
  var ApiClient = class {
143
177
  getHeaders() {
144
178
  const token = getToken();
@@ -150,20 +184,28 @@ var ApiClient = class {
150
184
  }
151
185
  return {
152
186
  "Content-Type": "application/json",
153
- "Authorization": `Bearer ${token}`
187
+ "Authorization": `Bearer ${token}`,
188
+ "X-CLI-Version": CLI_VERSION
154
189
  };
155
190
  }
191
+ async handleResponse(response) {
192
+ if (response.status === 426) {
193
+ const text = await response.text();
194
+ handleUpgradeRequired(text);
195
+ }
196
+ if (!response.ok) {
197
+ const text = await response.text();
198
+ throw new Error(parseApiError(response.status, text));
199
+ }
200
+ return response.json();
201
+ }
156
202
  async get(path) {
157
203
  const url = `${getApiUrl()}${path}`;
158
204
  const response = await fetch(url, {
159
205
  method: "GET",
160
206
  headers: this.getHeaders()
161
207
  });
162
- if (!response.ok) {
163
- const text = await response.text();
164
- throw new Error(parseApiError(response.status, text));
165
- }
166
- return response.json();
208
+ return this.handleResponse(response);
167
209
  }
168
210
  async post(path, body) {
169
211
  const url = `${getApiUrl()}${path}`;
@@ -172,11 +214,7 @@ var ApiClient = class {
172
214
  headers: this.getHeaders(),
173
215
  body: JSON.stringify(body)
174
216
  });
175
- if (!response.ok) {
176
- const text = await response.text();
177
- throw new Error(parseApiError(response.status, text));
178
- }
179
- return response.json();
217
+ return this.handleResponse(response);
180
218
  }
181
219
  async delete(path, body) {
182
220
  const url = `${getApiUrl()}${path}`;
@@ -185,11 +223,7 @@ var ApiClient = class {
185
223
  headers: this.getHeaders(),
186
224
  body: body ? JSON.stringify(body) : void 0
187
225
  });
188
- if (!response.ok) {
189
- const text = await response.text();
190
- throw new Error(parseApiError(response.status, text));
191
- }
192
- return response.json();
226
+ return this.handleResponse(response);
193
227
  }
194
228
  async patch(path, body) {
195
229
  const url = `${getApiUrl()}${path}`;
@@ -198,11 +232,7 @@ var ApiClient = class {
198
232
  headers: this.getHeaders(),
199
233
  body: JSON.stringify(body)
200
234
  });
201
- if (!response.ok) {
202
- const text = await response.text();
203
- throw new Error(parseApiError(response.status, text));
204
- }
205
- return response.json();
235
+ return this.handleResponse(response);
206
236
  }
207
237
  };
208
238
  var api = new ApiClient();
@@ -224,27 +254,86 @@ function isPermissionError(err) {
224
254
  return false;
225
255
  }
226
256
 
257
+ // src/lib/telemetry.ts
258
+ import { randomUUID } from "crypto";
259
+ function getAnonymousId() {
260
+ let anonymousId = getConfig("anonymousId");
261
+ if (!anonymousId) {
262
+ anonymousId = randomUUID();
263
+ setConfig("anonymousId", anonymousId);
264
+ }
265
+ return anonymousId;
266
+ }
267
+ function trackEvent(event, properties = {}) {
268
+ const distinctId = getConfig("userId") ?? getAnonymousId();
269
+ fetch(`${getApiUrl()}/v1/posthog/event`, {
270
+ method: "POST",
271
+ headers: { "Content-Type": "application/json" },
272
+ body: JSON.stringify({
273
+ events: [{
274
+ event,
275
+ properties: {
276
+ ...properties,
277
+ distinct_id: distinctId,
278
+ source: "cli"
279
+ }
280
+ }]
281
+ })
282
+ }).catch(() => {
283
+ });
284
+ }
285
+ function identifyUser(userId, personProperties = {}) {
286
+ const anonymousId = getAnonymousId();
287
+ setConfig("userId", userId);
288
+ fetch(`${getApiUrl()}/v1/posthog/event`, {
289
+ method: "POST",
290
+ headers: { "Content-Type": "application/json" },
291
+ body: JSON.stringify({
292
+ events: [{
293
+ event: "$identify",
294
+ properties: {
295
+ distinct_id: userId,
296
+ $anon_distinct_id: anonymousId,
297
+ source: "cli",
298
+ $set: personProperties
299
+ }
300
+ }]
301
+ })
302
+ }).catch(() => {
303
+ });
304
+ }
305
+
227
306
  // src/commands/branch/create.ts
228
307
  async function createAction(name, options) {
229
308
  try {
230
309
  const startTime = performance.now();
231
- const job = await api.post("/v1/cli/jobs/create", {
232
- name
233
- });
310
+ const connectorId = getConfig("currentConnectorId");
311
+ if (!connectorId) {
312
+ console.error("\u2717 No connector selected. Run 'ardent connector switch' first.");
313
+ process.exit(1);
314
+ }
234
315
  await api.post("/v1/branch/create", {
235
- job_id: job.job_id,
236
- service_type: options.service
316
+ connector_id: connectorId,
317
+ service_type: options.service,
318
+ name
237
319
  });
238
- const apiBranches = await api.get(`/v1/branches/${job.job_id}`);
239
- const apiBranch = apiBranches.find((branch2) => branch2.service_type === options.service);
320
+ const response = await api.get(`/v1/cli/branches?connector_id=${connectorId}`);
321
+ const apiBranches = response.branches || [];
322
+ let apiBranch;
323
+ for (const branch2 of apiBranches) {
324
+ if (branch2.name === name) {
325
+ apiBranch = branch2;
326
+ break;
327
+ }
328
+ }
240
329
  if (!apiBranch) {
241
330
  console.error("\u2717 Branch created but could not fetch details");
242
331
  process.exit(1);
243
332
  }
244
333
  const branch = {
245
334
  id: apiBranch.id,
246
- job_id: job.job_id,
247
- name,
335
+ connector_id: apiBranch.connector_id,
336
+ name: apiBranch.name,
248
337
  service_type: apiBranch.service_type,
249
338
  branch_url: apiBranch.branch_url || "",
250
339
  status: apiBranch.status,
@@ -256,6 +345,7 @@ async function createAction(name, options) {
256
345
  setCacheEntry("branches", cachedBranches);
257
346
  setCurrentBranch(name);
258
347
  const elapsed = ((performance.now() - startTime) / 1e3).toFixed(1);
348
+ trackEvent("CLI: branch create succeeded", { service_type: options.service, duration_seconds: parseFloat(elapsed) });
259
349
  console.log(`\u2713 Branch '${name}' created and checked out in ${elapsed}s`);
260
350
  if (branch.branch_url) {
261
351
  console.log(`
@@ -263,9 +353,11 @@ ${branch.branch_url}`);
263
353
  }
264
354
  } catch (err) {
265
355
  if (isNetworkError(err)) {
356
+ trackEvent("CLI: branch create failed", { reason: "offline" });
266
357
  console.error("\u2717 Cannot create branch while offline");
267
358
  process.exit(1);
268
359
  }
360
+ trackEvent("CLI: branch create failed", { reason: "api_error" });
269
361
  console.error("\u2717 Failed:", err instanceof Error ? err.message : err);
270
362
  process.exit(1);
271
363
  }
@@ -277,7 +369,12 @@ async function listAction() {
277
369
  let fromCache = false;
278
370
  let cacheTime = "";
279
371
  try {
280
- const result = await api.get("/v1/cli/branches");
372
+ const currentConnectorId = getConfig("currentConnectorId");
373
+ if (!currentConnectorId) {
374
+ console.error("\u2717 No connector selected. Run 'ardent connector switch' first.");
375
+ process.exit(1);
376
+ }
377
+ const result = await api.get(`/v1/cli/branches?connector_id=${currentConnectorId}`);
281
378
  if (!result.branches) {
282
379
  throw new Error("API returned invalid response: missing branches array");
283
380
  }
@@ -290,11 +387,14 @@ async function listAction() {
290
387
  branches = cached.data;
291
388
  fromCache = true;
292
389
  cacheTime = formatCacheTime(cached.updated_at);
390
+ trackEvent("CLI: branch list served from cache");
293
391
  } else {
392
+ trackEvent("CLI: branch list failed", { reason: "offline_no_cache" });
294
393
  console.error("\u2717 Offline and no cached data available");
295
394
  process.exit(1);
296
395
  }
297
396
  } else {
397
+ trackEvent("CLI: branch list failed", { reason: "api_error" });
298
398
  console.error("\u2717 Failed:", err instanceof Error ? err.message : err);
299
399
  process.exit(1);
300
400
  }
@@ -303,6 +403,7 @@ async function listAction() {
303
403
  console.log(`\u26A0 Offline - showing cached data from ${cacheTime}
304
404
  `);
305
405
  }
406
+ trackEvent("CLI: branch list succeeded", { branch_count: branches.length, from_cache: fromCache });
306
407
  if (branches.length === 0) {
307
408
  console.log("No branches found");
308
409
  console.log(" Create one with: ardent branch create <name>");
@@ -357,6 +458,7 @@ function infoAction(name) {
357
458
  console.log(`
358
459
  URL: ${branch.branch_url}`);
359
460
  }
461
+ trackEvent("CLI: branch info");
360
462
  }
361
463
 
362
464
  // src/commands/branch/delete.ts
@@ -369,18 +471,21 @@ async function deleteAction(name) {
369
471
  process.exit(1);
370
472
  }
371
473
  try {
372
- await api.delete(`/v1/cli/jobs/${branch.job_id}`);
474
+ await api.delete(`/v1/cli/branches/${branch.id}`);
373
475
  const updatedBranches = cached.data.filter((cachedBranch) => cachedBranch.id !== branch.id);
374
476
  setCacheEntry("branches", updatedBranches);
375
477
  if (getCurrentBranch() === name) {
376
478
  clearCurrentBranch();
377
479
  }
480
+ trackEvent("CLI: branch delete succeeded");
378
481
  console.log("\u2713 Branch deleted");
379
482
  } catch (err) {
380
483
  if (isNetworkError(err)) {
484
+ trackEvent("CLI: branch delete failed", { reason: "offline" });
381
485
  console.error("\u2717 Cannot delete branch while offline");
382
486
  process.exit(1);
383
487
  }
488
+ trackEvent("CLI: branch delete failed", { reason: "api_error" });
384
489
  console.error("\u2717 Failed:", err instanceof Error ? err.message : err);
385
490
  process.exit(1);
386
491
  }
@@ -427,6 +532,7 @@ async function switchAction(name) {
427
532
  console.log(`
428
533
  ${branch.branch_url}`);
429
534
  }
535
+ trackEvent("CLI: branch switch");
430
536
  }
431
537
 
432
538
  // src/commands/branch/diff.ts
@@ -476,7 +582,7 @@ async function diffAction(options) {
476
582
  return;
477
583
  }
478
584
  try {
479
- const stateRaw = await api.get(`/v1/branches/${branch.job_id}/state`);
585
+ const stateRaw = await api.get(`/v1/branches/${branch.id}/state`);
480
586
  if (!stateRaw || Object.keys(stateRaw).length === 0) {
481
587
  console.log("No changes captured");
482
588
  return;
@@ -632,8 +738,14 @@ async function diffAction(options) {
632
738
  if ((!ddl || ddl.length === 0) && (!diff || diff.length === 0)) {
633
739
  console.log("No changes");
634
740
  }
741
+ trackEvent("CLI: branch diff succeeded", {
742
+ sql_mode: Boolean(options.sql),
743
+ ddl_count: ddl?.length ?? 0,
744
+ data_change_count: diff?.length ?? 0
745
+ });
635
746
  }
636
747
  } catch (err) {
748
+ trackEvent("CLI: branch diff failed", { reason: "api_error" });
637
749
  console.error("\u2717 Failed:", err instanceof Error ? err.message : err);
638
750
  process.exit(1);
639
751
  }
@@ -800,12 +912,20 @@ async function createAction2(type, url, options) {
800
912
  }
801
913
  try {
802
914
  const connectorName = options.name || (isByoc ? "my-neon-connection" : "my-postgresql-connection");
915
+ const currentProjectId = getConfig("currentProjectId");
916
+ if (!currentProjectId) {
917
+ console.error("\u2717 No current project set. Switch to a project first:");
918
+ console.error(" ardent project list");
919
+ console.error(" ardent project switch <name>");
920
+ process.exit(1);
921
+ }
803
922
  let createPayload;
804
923
  if (isByoc) {
805
924
  console.log("Creating connector (BYOC Neon)...");
806
925
  createPayload = {
807
926
  name: connectorName,
808
927
  service_name: "postgresql",
928
+ project_id: currentProjectId,
809
929
  byoc: options.byoc,
810
930
  neon_api_key: options.apiKey,
811
931
  neon_project_id: options.projectId,
@@ -822,6 +942,7 @@ async function createAction2(type, url, options) {
822
942
  createPayload = {
823
943
  name: connectorName,
824
944
  service_name: "postgresql",
945
+ project_id: currentProjectId,
825
946
  connection_details: {
826
947
  host: parsed.host,
827
948
  port: parsed.port,
@@ -865,11 +986,15 @@ async function createAction2(type, url, options) {
865
986
  const cachedConnectors = cached?.data || [];
866
987
  cachedConnectors.push(newConnector);
867
988
  setCacheEntry("connectors", cachedConnectors);
989
+ setConfig("currentConnectorId", connectorId);
990
+ setConfig("currentConnectorName", connectorName);
991
+ trackEvent("CLI: connector create succeeded", { db_type: type, byoc: isByoc });
868
992
  console.log("\u2713 Connector created and ready");
869
993
  console.log(` ID: ${connectorId}`);
870
994
  showNextStep();
871
995
  } catch (err) {
872
996
  if (isPermissionError(err)) {
997
+ trackEvent("CLI: connector create failed", { reason: "permission_denied" });
873
998
  console.error("\u2717 You don't have permission to create connectors.");
874
999
  console.error("");
875
1000
  console.error(" Ask your organization admin to either:");
@@ -877,6 +1002,7 @@ async function createAction2(type, url, options) {
877
1002
  console.error(" \u2022 Upgrade your role to Admin");
878
1003
  process.exit(1);
879
1004
  }
1005
+ trackEvent("CLI: connector create failed", { reason: "api_error" });
880
1006
  console.error("\u2717 Failed:", err instanceof Error ? err.message : err);
881
1007
  process.exit(1);
882
1008
  }
@@ -888,7 +1014,9 @@ async function listAction2() {
888
1014
  let fromCache = false;
889
1015
  let cacheTime = "";
890
1016
  try {
891
- const result = await api.get("/v1/cli/connectors");
1017
+ const currentProjectId = getConfig("currentProjectId");
1018
+ const projectFilter = currentProjectId ? `?project_id=${currentProjectId}` : "";
1019
+ const result = await api.get(`/v1/cli/connectors${projectFilter}`);
892
1020
  if (!result.connectors) {
893
1021
  throw new Error("API returned invalid response: missing connectors array");
894
1022
  }
@@ -902,14 +1030,17 @@ async function listAction2() {
902
1030
  fromCache = true;
903
1031
  cacheTime = formatCacheTime(cached.updated_at);
904
1032
  } else {
1033
+ trackEvent("CLI: connector list failed", { reason: "offline_no_cache" });
905
1034
  console.error("\u2717 Offline and no cached data available");
906
1035
  process.exit(1);
907
1036
  }
908
1037
  } else {
1038
+ trackEvent("CLI: connector list failed", { reason: "api_error" });
909
1039
  console.error("\u2717 Failed:", err instanceof Error ? err.message : err);
910
1040
  process.exit(1);
911
1041
  }
912
1042
  }
1043
+ trackEvent("CLI: connector list succeeded", { connector_count: connectors.length, from_cache: fromCache });
913
1044
  if (fromCache) {
914
1045
  console.log(`\u26A0 Offline - showing cached data from ${cacheTime}
915
1046
  `);
@@ -919,11 +1050,21 @@ async function listAction2() {
919
1050
  console.log(" Create one with: ardent connector create postgresql <url>");
920
1051
  return;
921
1052
  }
1053
+ const currentConnectorId = getConfig("currentConnectorId");
1054
+ const green3 = "\x1B[32m";
1055
+ const dim3 = "\x1B[2m";
1056
+ const reset3 = "\x1B[0m";
922
1057
  console.log("Connectors:\n");
923
1058
  for (const connector of connectors) {
1059
+ const isCurrent = connector.id === currentConnectorId;
924
1060
  const icon = connector.status === "healthy" ? "\u25CF" : "\u25CB";
925
- console.log(` ${icon} ${connector.service_name}`);
926
- console.log(` Name: ${connector.name}`);
1061
+ if (isCurrent) {
1062
+ console.log(`${green3}* ${icon} ${connector.name}${reset3}`);
1063
+ console.log(`${green3} ${connector.service_name}${reset3}`);
1064
+ } else {
1065
+ console.log(` ${icon} ${connector.name}`);
1066
+ console.log(`${dim3} ${connector.service_name}${reset3}`);
1067
+ }
927
1068
  console.log();
928
1069
  }
929
1070
  }
@@ -960,13 +1101,16 @@ async function deleteAction2(name) {
960
1101
  const updatedConnectors = currentCache.data.filter((c) => c.id !== connector.id);
961
1102
  setCacheEntry("connectors", updatedConnectors);
962
1103
  }
1104
+ trackEvent("CLI: connector delete succeeded");
963
1105
  console.log("\u2713 Connector deleted");
964
1106
  } catch (err) {
965
1107
  if (isNetworkError(err)) {
1108
+ trackEvent("CLI: connector delete failed", { reason: "offline" });
966
1109
  console.error("\u2717 Cannot delete connector while offline");
967
1110
  process.exit(1);
968
1111
  }
969
1112
  if (isPermissionError(err)) {
1113
+ trackEvent("CLI: connector delete failed", { reason: "permission_denied" });
970
1114
  console.error("\u2717 You don't have permission to delete connectors.");
971
1115
  console.error("");
972
1116
  console.error(" Ask your organization admin to either:");
@@ -974,15 +1118,70 @@ async function deleteAction2(name) {
974
1118
  console.error(" \u2022 Upgrade your role to Admin");
975
1119
  process.exit(1);
976
1120
  }
1121
+ trackEvent("CLI: connector delete failed", { reason: "api_error" });
977
1122
  console.error("\u2717 Failed:", err instanceof Error ? err.message : err);
978
1123
  process.exit(1);
979
1124
  }
980
1125
  }
981
1126
 
1127
+ // src/commands/connector/switch.ts
1128
+ async function switchAction2(name) {
1129
+ const cached = getCacheEntry("connectors");
1130
+ let connector = cached?.data.find(
1131
+ (cachedConnector) => cachedConnector.name === name
1132
+ );
1133
+ if (!connector) {
1134
+ try {
1135
+ const result = await api.get("/v1/cli/connectors");
1136
+ if (!result.connectors) {
1137
+ throw new Error("API returned invalid response: missing connectors array");
1138
+ }
1139
+ setCacheEntry("connectors", result.connectors);
1140
+ connector = result.connectors.find(
1141
+ (remoteConnector) => remoteConnector.name === name
1142
+ );
1143
+ } catch (err) {
1144
+ if (isNetworkError(err)) {
1145
+ if (!connector) {
1146
+ console.error(`\u2717 Connector "${name}" not found in cache`);
1147
+ console.log(" Run 'ardent connector list' when online to refresh");
1148
+ process.exit(1);
1149
+ }
1150
+ } else {
1151
+ console.error("\u2717 Failed:", err instanceof Error ? err.message : err);
1152
+ process.exit(1);
1153
+ }
1154
+ }
1155
+ }
1156
+ if (!connector) {
1157
+ console.error(`\u2717 Connector "${name}" not found`);
1158
+ console.log(" Run: ardent connector list");
1159
+ process.exit(1);
1160
+ }
1161
+ const previousName = getConfig("currentConnectorName");
1162
+ setConfig("currentConnectorId", connector.id);
1163
+ setConfig("currentConnectorName", connector.name);
1164
+ clearCurrentBranch();
1165
+ if (previousName && previousName !== name) {
1166
+ console.log(`Switched from '${previousName}' to '${name}'`);
1167
+ } else {
1168
+ console.log(`Switched to connector '${name}'`);
1169
+ }
1170
+ try {
1171
+ const branchResult = await api.get(
1172
+ `/v1/cli/branches?connector_id=${connector.id}`
1173
+ );
1174
+ setCacheEntry("branches", branchResult.branches || []);
1175
+ } catch {
1176
+ }
1177
+ trackEvent("CLI: connector switch");
1178
+ }
1179
+
982
1180
  // src/commands/connector/index.ts
983
1181
  var connectorCommand = new Command2("connector").description("Manage database connectors");
984
1182
  connectorCommand.command("create <type> [url]").description("Create a new connector").option("-n, --name <name>", "Connector name").option("--byoc <provider>", "Bring your own Neon project (e.g. neon)").option("--api-key <key>", "Neon API key (required with --byoc)").option("--project-id <id>", "Neon project ID (required with --byoc)").action(createAction2);
985
1183
  connectorCommand.command("list").description("List your connectors").action(listAction2);
1184
+ connectorCommand.command("switch <name>").description("Switch to a different connector").action(switchAction2);
986
1185
  connectorCommand.command("delete <name>").description("Delete a connector by name").action(deleteAction2);
987
1186
 
988
1187
  // src/commands/invite/index.ts
@@ -1001,15 +1200,18 @@ async function sendAction(email, role) {
1001
1200
  email,
1002
1201
  role: role.toLowerCase()
1003
1202
  });
1203
+ trackEvent("CLI: invite send succeeded", { role: result.role });
1004
1204
  console.log(`\u2713 Invite sent to ${result.email}`);
1005
1205
  console.log(` Role: ${result.role}`);
1006
1206
  console.log(` Org: ${result.org_name}`);
1007
1207
  } catch (err) {
1008
1208
  if (isNetworkError(err)) {
1209
+ trackEvent("CLI: invite send failed", { reason: "offline" });
1009
1210
  console.error("\u2717 Cannot send invite while offline");
1010
1211
  process.exit(1);
1011
1212
  }
1012
1213
  if (isPermissionError(err)) {
1214
+ trackEvent("CLI: invite send failed", { reason: "permission_denied" });
1013
1215
  console.error("\u2717 You don't have permission to invite users.");
1014
1216
  console.error("");
1015
1217
  console.error(" Ask your organization admin to either:");
@@ -1017,6 +1219,7 @@ async function sendAction(email, role) {
1017
1219
  console.error(" \u2022 Upgrade your role to Admin");
1018
1220
  process.exit(1);
1019
1221
  }
1222
+ trackEvent("CLI: invite send failed", { reason: "api_error" });
1020
1223
  console.error("\u2717 Failed:", err instanceof Error ? err.message : err);
1021
1224
  process.exit(1);
1022
1225
  }
@@ -1030,6 +1233,7 @@ async function listAction3() {
1030
1233
  throw new Error("API returned invalid response: missing invites array");
1031
1234
  }
1032
1235
  const invites = result.invites;
1236
+ trackEvent("CLI: invite list succeeded", { invite_count: invites.length });
1033
1237
  if (invites.length === 0) {
1034
1238
  console.log("No pending invites");
1035
1239
  return;
@@ -1043,9 +1247,11 @@ async function listAction3() {
1043
1247
  }
1044
1248
  } catch (err) {
1045
1249
  if (isNetworkError(err)) {
1250
+ trackEvent("CLI: invite list failed", { reason: "offline" });
1046
1251
  console.error("\u2717 Cannot list invites while offline");
1047
1252
  process.exit(1);
1048
1253
  }
1254
+ trackEvent("CLI: invite list failed", { reason: "api_error" });
1049
1255
  console.error("\u2717 Failed:", err instanceof Error ? err.message : err);
1050
1256
  process.exit(1);
1051
1257
  }
@@ -1055,12 +1261,15 @@ async function listAction3() {
1055
1261
  async function deleteAction3(email) {
1056
1262
  try {
1057
1263
  await api.delete("/v1/cli/invites", { email });
1264
+ trackEvent("CLI: invite delete succeeded");
1058
1265
  console.log(`\u2713 Invite for ${email} deleted`);
1059
1266
  } catch (err) {
1060
1267
  if (isNetworkError(err)) {
1268
+ trackEvent("CLI: invite delete failed", { reason: "offline" });
1061
1269
  console.error("\u2717 Cannot delete invite while offline");
1062
1270
  process.exit(1);
1063
1271
  }
1272
+ trackEvent("CLI: invite delete failed", { reason: "api_error" });
1064
1273
  console.error("\u2717 Failed:", err instanceof Error ? err.message : err);
1065
1274
  process.exit(1);
1066
1275
  }
@@ -1084,6 +1293,7 @@ import { Command as Command4 } from "commander";
1084
1293
  async function membersAction() {
1085
1294
  try {
1086
1295
  const result = await api.get("/v1/cli/members");
1296
+ trackEvent("CLI: org members succeeded", { member_count: result.members?.length ?? 0 });
1087
1297
  if (!result.members || result.members.length === 0) {
1088
1298
  console.log("No members found");
1089
1299
  return;
@@ -1097,9 +1307,11 @@ async function membersAction() {
1097
1307
  }
1098
1308
  } catch (err) {
1099
1309
  if (isNetworkError(err)) {
1310
+ trackEvent("CLI: org members failed", { reason: "offline" });
1100
1311
  console.error("\u2717 Cannot list members while offline");
1101
1312
  process.exit(1);
1102
1313
  }
1314
+ trackEvent("CLI: org members failed", { reason: "api_error" });
1103
1315
  console.error("\u2717 Failed:", err instanceof Error ? err.message : err);
1104
1316
  process.exit(1);
1105
1317
  }
@@ -1115,18 +1327,22 @@ async function setRoleAction(email, role) {
1115
1327
  }
1116
1328
  try {
1117
1329
  const result = await api.patch("/v1/cli/members/role", { email, role });
1330
+ trackEvent("CLI: org set-role succeeded", { role: result.new_role });
1118
1331
  console.log(`\u2713 Updated ${result.email} to ${result.new_role}`);
1119
1332
  } catch (err) {
1120
1333
  if (isNetworkError(err)) {
1334
+ trackEvent("CLI: org set-role failed", { reason: "offline" });
1121
1335
  console.error("\u2717 Cannot update role while offline");
1122
1336
  process.exit(1);
1123
1337
  }
1124
1338
  if (isPermissionError(err)) {
1339
+ trackEvent("CLI: org set-role failed", { reason: "permission_denied" });
1125
1340
  console.error("\u2717 You don't have permission to update member roles.");
1126
1341
  console.error("");
1127
1342
  console.error(" Only org admins and owners can change roles.");
1128
1343
  process.exit(1);
1129
1344
  }
1345
+ trackEvent("CLI: org set-role failed", { reason: "api_error" });
1130
1346
  console.error("\u2717 Failed:", err instanceof Error ? err.message : err);
1131
1347
  process.exit(1);
1132
1348
  }
@@ -1136,18 +1352,22 @@ async function setRoleAction(email, role) {
1136
1352
  async function removeAction(email) {
1137
1353
  try {
1138
1354
  await api.delete("/v1/cli/members", { email });
1355
+ trackEvent("CLI: org remove member succeeded");
1139
1356
  console.log(`\u2713 Removed ${email} from organization`);
1140
1357
  } catch (err) {
1141
1358
  if (isNetworkError(err)) {
1359
+ trackEvent("CLI: org remove member failed", { reason: "offline" });
1142
1360
  console.error("\u2717 Cannot remove member while offline");
1143
1361
  process.exit(1);
1144
1362
  }
1145
1363
  if (isPermissionError(err)) {
1364
+ trackEvent("CLI: org remove member failed", { reason: "permission_denied" });
1146
1365
  console.error("\u2717 You don't have permission to remove members.");
1147
1366
  console.error("");
1148
1367
  console.error(" Only org admins and owners can remove members.");
1149
1368
  process.exit(1);
1150
1369
  }
1370
+ trackEvent("CLI: org remove member failed", { reason: "api_error" });
1151
1371
  console.error("\u2717 Failed:", err instanceof Error ? err.message : err);
1152
1372
  process.exit(1);
1153
1373
  }
@@ -1159,16 +1379,203 @@ orgCommand.command("members").description("List organization members").action(me
1159
1379
  orgCommand.command("set-role <email> <role>").description("Update a member's role (owner/admin/member/viewer)").action(setRoleAction);
1160
1380
  orgCommand.command("remove <email>").description("Remove a member from the organization").action(removeAction);
1161
1381
 
1162
- // src/commands/auth/index.ts
1382
+ // src/commands/project/index.ts
1163
1383
  import { Command as Command5 } from "commander";
1164
1384
 
1385
+ // src/commands/project/create.ts
1386
+ async function createAction3(name) {
1387
+ const user = getConfig("user");
1388
+ if (!user?.org_id) {
1389
+ console.error("\u2717 No organization found. Run: ardent login");
1390
+ process.exit(1);
1391
+ }
1392
+ try {
1393
+ const project = await api.post("/v1/projects", {
1394
+ name,
1395
+ org_id: user.org_id
1396
+ });
1397
+ const cached = getCacheEntry("projects");
1398
+ const cachedProjects = cached?.data || [];
1399
+ cachedProjects.push(project);
1400
+ setCacheEntry("projects", cachedProjects);
1401
+ setConfig("currentProjectId", project.id);
1402
+ setConfig("currentProjectName", project.name);
1403
+ trackEvent("CLI: project create succeeded");
1404
+ console.log(`\u2713 Project '${name}' created`);
1405
+ console.log(` ID: ${project.id}`);
1406
+ } catch (err) {
1407
+ if (isNetworkError(err)) {
1408
+ trackEvent("CLI: project create failed", { reason: "offline" });
1409
+ console.error("\u2717 Cannot create project while offline");
1410
+ process.exit(1);
1411
+ }
1412
+ if (isPermissionError(err)) {
1413
+ trackEvent("CLI: project create failed", { reason: "permission_denied" });
1414
+ console.error("\u2717 You don't have permission to create projects.");
1415
+ process.exit(1);
1416
+ }
1417
+ trackEvent("CLI: project create failed", { reason: "api_error" });
1418
+ console.error("\u2717 Failed:", err instanceof Error ? err.message : err);
1419
+ process.exit(1);
1420
+ }
1421
+ }
1422
+
1423
+ // src/commands/project/list.ts
1424
+ async function listAction4() {
1425
+ let projects = [];
1426
+ let fromCache = false;
1427
+ let cacheTime = "";
1428
+ try {
1429
+ const user = getConfig("user");
1430
+ if (!user?.org_id) {
1431
+ console.error("\u2717 No organization found. Run: ardent login");
1432
+ process.exit(1);
1433
+ }
1434
+ const result = await api.get(
1435
+ `/v1/projects?org_id=${user.org_id}`
1436
+ );
1437
+ if (!result.projects) {
1438
+ throw new Error("API returned invalid response: missing projects array");
1439
+ }
1440
+ projects = result.projects;
1441
+ setCacheEntry("projects", projects);
1442
+ } catch (err) {
1443
+ if (isNetworkError(err)) {
1444
+ const cached = getCacheEntry("projects");
1445
+ if (cached) {
1446
+ projects = cached.data;
1447
+ fromCache = true;
1448
+ cacheTime = formatCacheTime(cached.updated_at);
1449
+ } else {
1450
+ trackEvent("CLI: project list failed", { reason: "offline_no_cache" });
1451
+ console.error("\u2717 Offline and no cached data available");
1452
+ process.exit(1);
1453
+ }
1454
+ } else {
1455
+ trackEvent("CLI: project list failed", { reason: "api_error" });
1456
+ console.error("\u2717 Failed:", err instanceof Error ? err.message : err);
1457
+ process.exit(1);
1458
+ }
1459
+ }
1460
+ trackEvent("CLI: project list succeeded", {
1461
+ project_count: projects.length,
1462
+ from_cache: fromCache
1463
+ });
1464
+ if (fromCache) {
1465
+ console.log(`\u26A0 Offline - showing cached data from ${cacheTime}
1466
+ `);
1467
+ }
1468
+ if (projects.length === 0) {
1469
+ console.log("No projects found");
1470
+ return;
1471
+ }
1472
+ const currentProjectId = getConfig("currentProjectId");
1473
+ const green3 = "\x1B[32m";
1474
+ const dim3 = "\x1B[2m";
1475
+ const reset3 = "\x1B[0m";
1476
+ console.log("Projects:\n");
1477
+ for (const project of projects) {
1478
+ const isCurrent = project.id === currentProjectId;
1479
+ if (isCurrent) {
1480
+ console.log(`${green3}* ${project.name}${reset3}`);
1481
+ console.log(`${green3} ${project.id}${reset3}`);
1482
+ } else {
1483
+ console.log(` ${project.name}`);
1484
+ console.log(`${dim3} ${project.id}${reset3}`);
1485
+ }
1486
+ console.log();
1487
+ }
1488
+ }
1489
+
1490
+ // src/commands/project/switch.ts
1491
+ async function switchAction3(name) {
1492
+ let projects = [];
1493
+ const cached = getCacheEntry("projects");
1494
+ let project = cached?.data.find(
1495
+ (cachedProject) => cachedProject.name === name
1496
+ );
1497
+ if (!project) {
1498
+ try {
1499
+ const user = getConfig("user");
1500
+ if (!user?.org_id) {
1501
+ console.error("\u2717 No organization found. Run: ardent login");
1502
+ process.exit(1);
1503
+ }
1504
+ const result = await api.get(
1505
+ `/v1/projects?org_id=${user.org_id}`
1506
+ );
1507
+ if (!result.projects) {
1508
+ throw new Error(
1509
+ "API returned invalid response: missing projects array"
1510
+ );
1511
+ }
1512
+ projects = result.projects;
1513
+ setCacheEntry("projects", projects);
1514
+ project = projects.find(
1515
+ (remoteProject) => remoteProject.name === name
1516
+ );
1517
+ } catch (err) {
1518
+ if (isNetworkError(err)) {
1519
+ if (!project) {
1520
+ console.error(`\u2717 Project "${name}" not found in cache`);
1521
+ console.log(" Run 'ardent project list' when online to refresh");
1522
+ process.exit(1);
1523
+ }
1524
+ } else {
1525
+ console.error("\u2717 Failed:", err instanceof Error ? err.message : err);
1526
+ process.exit(1);
1527
+ }
1528
+ }
1529
+ }
1530
+ if (!project) {
1531
+ console.error(`\u2717 Project "${name}" not found`);
1532
+ console.log(" Run: ardent project list");
1533
+ process.exit(1);
1534
+ }
1535
+ const previousId = getConfig("currentProjectId");
1536
+ const previousName = getConfig("currentProjectName");
1537
+ setConfig("currentProjectId", project.id);
1538
+ setConfig("currentProjectName", project.name);
1539
+ setConfig("currentConnectorId", void 0);
1540
+ setConfig("currentConnectorName", void 0);
1541
+ clearCurrentBranch();
1542
+ if (previousName && previousName !== name) {
1543
+ console.log(`Switched from '${previousName}' to '${name}'`);
1544
+ } else {
1545
+ console.log(`Switched to project '${name}'`);
1546
+ }
1547
+ trackEvent("CLI: project switch");
1548
+ }
1549
+
1550
+ // src/commands/project/index.ts
1551
+ var projectCommand = new Command5("project").description(
1552
+ "Manage projects"
1553
+ );
1554
+ projectCommand.command("create <name>").description("Create a new project").action(createAction3);
1555
+ projectCommand.command("list").description("List your projects").action(listAction4);
1556
+ projectCommand.command("switch <name>").description("Switch to a different project").action(switchAction3);
1557
+
1558
+ // src/commands/auth/index.ts
1559
+ import { Command as Command6 } from "commander";
1560
+
1165
1561
  // src/commands/auth/login.ts
1166
1562
  async function loginAction(options) {
1167
1563
  if (options.token) {
1168
1564
  setConfig("token", options.token);
1169
1565
  console.log("\u2713 Logged in successfully");
1566
+ trackEvent("CLI: login succeeded", { method: "token" });
1170
1567
  try {
1171
1568
  await bootstrapCache();
1569
+ const user = getConfig("user");
1570
+ if (user) {
1571
+ const tokenPersonProperties = {};
1572
+ if (user.email) tokenPersonProperties.email = user.email;
1573
+ if (user.full_name) tokenPersonProperties.$name = user.full_name;
1574
+ if (user.org_name) tokenPersonProperties.org_name = user.org_name;
1575
+ if (user.user_id) {
1576
+ identifyUser(user.user_id, tokenPersonProperties);
1577
+ }
1578
+ }
1172
1579
  } catch {
1173
1580
  }
1174
1581
  showNextStep();
@@ -1182,6 +1589,7 @@ async function loginAction(options) {
1182
1589
  });
1183
1590
  if (!initResponse.ok) {
1184
1591
  const error = await initResponse.text();
1592
+ trackEvent("CLI: login failed", { method: "browser", reason: "init_failed" });
1185
1593
  console.error("\u2717 Failed to initialize auth:", error);
1186
1594
  process.exit(1);
1187
1595
  }
@@ -1198,6 +1606,7 @@ async function loginAction(options) {
1198
1606
  `${getApiUrl()}/v1/cli/auth/poll?session=${session_id}`
1199
1607
  );
1200
1608
  if (!pollResponse.ok) {
1609
+ trackEvent("CLI: login failed", { method: "browser", reason: "poll_failed" });
1201
1610
  console.error("\u2717 Poll failed");
1202
1611
  process.exit(1);
1203
1612
  }
@@ -1205,26 +1614,39 @@ async function loginAction(options) {
1205
1614
  if (result.status === "completed") {
1206
1615
  setConfig("token", result.token);
1207
1616
  console.log("\n\u2713 Logged in successfully");
1617
+ trackEvent("CLI: login succeeded", { method: "browser" });
1208
1618
  try {
1209
1619
  await bootstrapCache();
1210
1620
  } catch {
1211
1621
  }
1622
+ const user = getConfig("user");
1623
+ const personProperties = {};
1624
+ if (user?.email) personProperties.email = user.email;
1625
+ if (user?.full_name) personProperties.$name = user.full_name;
1626
+ if (user?.org_name) personProperties.org_name = user.org_name;
1627
+ if (result.user_id) {
1628
+ identifyUser(result.user_id, personProperties);
1629
+ }
1212
1630
  showNextStep();
1213
1631
  return;
1214
1632
  }
1215
1633
  if (result.status === "expired") {
1634
+ trackEvent("CLI: login failed", { method: "browser", reason: "expired" });
1216
1635
  console.error("\n\u2717 Session expired. Please try again.");
1217
1636
  process.exit(1);
1218
1637
  }
1219
1638
  if (result.status === "error") {
1639
+ trackEvent("CLI: login failed", { method: "browser", reason: "error" });
1220
1640
  console.error("\n\u2717 Error:", result.message);
1221
1641
  process.exit(1);
1222
1642
  }
1223
1643
  process.stdout.write(".");
1224
1644
  }
1645
+ trackEvent("CLI: login failed", { method: "browser", reason: "timeout" });
1225
1646
  console.error("\n\u2717 Timed out. Please try again.");
1226
1647
  process.exit(1);
1227
1648
  } catch (error) {
1649
+ trackEvent("CLI: login failed", { method: "browser", reason: "network_error" });
1228
1650
  console.error("\u2717 Login failed:", error instanceof Error ? error.message : error);
1229
1651
  process.exit(1);
1230
1652
  }
@@ -1232,6 +1654,7 @@ async function loginAction(options) {
1232
1654
 
1233
1655
  // src/commands/auth/logout.ts
1234
1656
  function logoutAction() {
1657
+ trackEvent("CLI: logout");
1235
1658
  clearConfig();
1236
1659
  console.log("\u2713 Logged out");
1237
1660
  }
@@ -1240,6 +1663,7 @@ function logoutAction() {
1240
1663
  function statusAction() {
1241
1664
  const token = getConfig("token");
1242
1665
  if (!token) {
1666
+ trackEvent("CLI: auth status", { authenticated: false });
1243
1667
  console.log("\u2717 Not authenticated");
1244
1668
  console.log(" Run: ardent login");
1245
1669
  return;
@@ -1259,12 +1683,88 @@ function statusAction() {
1259
1683
  console.log(` Token: ${token.slice(0, 8)}...${token.slice(-4)}`);
1260
1684
  console.log(" Run: ardent login to refresh profile info");
1261
1685
  }
1686
+ trackEvent("CLI: auth status", { authenticated: true });
1262
1687
  }
1263
1688
 
1264
1689
  // src/commands/auth/index.ts
1265
- var loginCommand = new Command5("login").description("Login to Ardent").option("-t, --token <token>", "API token (skip browser login)").action(loginAction);
1266
- var logoutCommand = new Command5("logout").description("Logout from Ardent").action(logoutAction);
1267
- var statusCommand = new Command5("status").description("Show status").action(statusAction);
1690
+ var loginCommand = new Command6("login").description("Login to Ardent").option("-t, --token <token>", "API token (skip browser login)").action(loginAction);
1691
+ var logoutCommand = new Command6("logout").description("Logout from Ardent").action(logoutAction);
1692
+ var statusCommand = new Command6("status").description("Show status").action(statusAction);
1693
+
1694
+ // src/lib/update-check.ts
1695
+ import { existsSync as existsSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
1696
+ import { join as join2 } from "path";
1697
+ import { homedir as homedir2 } from "os";
1698
+ var UPDATE_CHECK_FILE = join2(homedir2(), ".ardent", "update-check.json");
1699
+ var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
1700
+ var PACKAGE_NAME = "ardent-cli";
1701
+ function loadCache() {
1702
+ try {
1703
+ if (existsSync2(UPDATE_CHECK_FILE)) {
1704
+ return JSON.parse(readFileSync3(UPDATE_CHECK_FILE, "utf-8"));
1705
+ }
1706
+ } catch {
1707
+ }
1708
+ return null;
1709
+ }
1710
+ function saveCache(latestVersion) {
1711
+ try {
1712
+ const data = {
1713
+ latest_version: latestVersion,
1714
+ checked_at: (/* @__PURE__ */ new Date()).toISOString()
1715
+ };
1716
+ writeFileSync2(UPDATE_CHECK_FILE, JSON.stringify(data));
1717
+ } catch {
1718
+ }
1719
+ }
1720
+ function isNewerVersion(current, latest) {
1721
+ const currentParts = current.split(".").map(Number);
1722
+ const latestParts = latest.split(".").map(Number);
1723
+ for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) {
1724
+ const currentPart = currentParts[i] || 0;
1725
+ const latestPart = latestParts[i] || 0;
1726
+ if (latestPart > currentPart) return true;
1727
+ if (latestPart < currentPart) return false;
1728
+ }
1729
+ return false;
1730
+ }
1731
+ async function checkForUpdate(currentVersion) {
1732
+ try {
1733
+ const cache = loadCache();
1734
+ if (cache) {
1735
+ const elapsed = Date.now() - new Date(cache.checked_at).getTime();
1736
+ if (elapsed < CHECK_INTERVAL_MS) {
1737
+ if (isNewerVersion(currentVersion, cache.latest_version)) {
1738
+ printUpdateNotice(currentVersion, cache.latest_version);
1739
+ }
1740
+ return;
1741
+ }
1742
+ }
1743
+ const controller = new AbortController();
1744
+ const timeout = setTimeout(() => controller.abort(), 3e3);
1745
+ const response = await fetch(
1746
+ `https://registry.npmjs.org/${PACKAGE_NAME}/latest`,
1747
+ { signal: controller.signal }
1748
+ );
1749
+ clearTimeout(timeout);
1750
+ if (!response.ok) return;
1751
+ const data = await response.json();
1752
+ const latestVersion = data.version;
1753
+ saveCache(latestVersion);
1754
+ if (isNewerVersion(currentVersion, latestVersion)) {
1755
+ printUpdateNotice(currentVersion, latestVersion);
1756
+ }
1757
+ } catch {
1758
+ }
1759
+ }
1760
+ function printUpdateNotice(current, latest) {
1761
+ const yellow2 = "\x1B[33m";
1762
+ const green3 = "\x1B[32m";
1763
+ const reset3 = "\x1B[0m";
1764
+ console.error(
1765
+ `${yellow2}Update available: ${current} \u2192 ${latest}${reset3} \u2014 run ${green3}npm install -g ardent-cli@latest${reset3}`
1766
+ );
1767
+ }
1268
1768
 
1269
1769
  // src/index.ts
1270
1770
  var HELP_TEXT = `
@@ -1276,9 +1776,15 @@ AUTHENTICATION
1276
1776
  logout Clear stored credentials
1277
1777
  status Check authentication status
1278
1778
 
1779
+ PROJECTS
1780
+ project create Create a new project
1781
+ project list List your projects (* = current)
1782
+ project switch Switch to a different project
1783
+
1279
1784
  CONNECTORS
1280
1785
  connector create Connect a database (postgresql, snowflake, etc.)
1281
- connector list List your connectors
1786
+ connector list List your connectors (* = current)
1787
+ connector switch Switch to a different connector
1282
1788
  connector delete Delete a connector
1283
1789
 
1284
1790
  BRANCHES
@@ -1308,24 +1814,25 @@ EXAMPLES
1308
1814
  ardent branch switch my-feature
1309
1815
  ardent org members
1310
1816
  `;
1311
- var CLI_VERSION = getCliVersion();
1312
- var program = new Command6();
1313
- function getCliVersion() {
1817
+ var CLI_VERSION2 = getCliVersion2();
1818
+ var program = new Command7();
1819
+ function getCliVersion2() {
1314
1820
  try {
1315
1821
  const packageUrl = new URL("../package.json", import.meta.url);
1316
- const raw = readFileSync2(packageUrl, "utf-8");
1822
+ const raw = readFileSync4(packageUrl, "utf-8");
1317
1823
  const parsed = JSON.parse(raw);
1318
1824
  return parsed.version ?? "unknown";
1319
1825
  } catch {
1320
1826
  return "unknown";
1321
1827
  }
1322
1828
  }
1323
- program.name("ardent").description("CLI for Ardent database branching").version(CLI_VERSION).configureHelp({
1829
+ program.name("ardent").description("CLI for Ardent database branching").version(CLI_VERSION2).configureHelp({
1324
1830
  formatHelp: () => BANNER + HELP_TEXT
1325
1831
  });
1326
1832
  program.addCommand(loginCommand);
1327
1833
  program.addCommand(logoutCommand);
1328
1834
  program.addCommand(statusCommand);
1835
+ program.addCommand(projectCommand);
1329
1836
  program.addCommand(connectorCommand);
1330
1837
  program.addCommand(branchCommand);
1331
1838
  program.addCommand(inviteCommand);
@@ -1352,4 +1859,6 @@ if (args.length === 0) {
1352
1859
  }
1353
1860
  program.help();
1354
1861
  }
1862
+ getAnonymousId();
1863
+ checkForUpdate(CLI_VERSION2);
1355
1864
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ardent-cli",
3
- "version": "0.0.9",
3
+ "version": "0.0.11",
4
4
  "description": "Git for Data infrastructure",
5
5
  "type": "module",
6
6
  "bin": {