@tostudy-ai/cli 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/tostudy.ts CHANGED
@@ -5,8 +5,10 @@ if (!process.env.LOG_LEVEL) {
5
5
 
6
6
  import { createProgram, CLI_VERSION } from "../src/cli.js";
7
7
  import { checkForUpdates } from "../src/update-checker.js";
8
+ import { maybeAutoUpdate } from "../src/auto-updater.js";
8
9
 
9
10
  const program = createProgram();
10
11
  program.parse();
11
12
 
12
13
  checkForUpdates(CLI_VERSION);
14
+ maybeAutoUpdate(CLI_VERSION);
package/dist/cli.js CHANGED
@@ -2804,7 +2804,7 @@ var CLI_VERSION;
2804
2804
  var init_version = __esm({
2805
2805
  "src/version.ts"() {
2806
2806
  "use strict";
2807
- CLI_VERSION = true ? "0.13.0" : "0.7.1";
2807
+ CLI_VERSION = true ? "0.14.0" : "0.7.1";
2808
2808
  }
2809
2809
  });
2810
2810
 
@@ -2814,22 +2814,24 @@ __export(update_checker_exports, {
2814
2814
  checkForUpdates: () => checkForUpdates,
2815
2815
  checkVersionSync: () => checkVersionSync,
2816
2816
  fetchLatestVersion: () => fetchLatestVersion,
2817
- isNewerVersion: () => isNewerVersion
2817
+ isNewerVersion: () => isNewerVersion,
2818
+ readCache: () => readCache,
2819
+ writeCache: () => writeCache
2818
2820
  });
2819
2821
  import fs7 from "node:fs";
2820
2822
  import path9 from "node:path";
2821
- function readCache() {
2823
+ function readCache(configDir) {
2822
2824
  try {
2823
- const p = path9.join(getConfigDir(), CACHE_FILE);
2825
+ const p = path9.join(configDir ?? getConfigDir(), CACHE_FILE);
2824
2826
  if (!fs7.existsSync(p)) return null;
2825
2827
  return JSON.parse(fs7.readFileSync(p, "utf-8"));
2826
2828
  } catch {
2827
2829
  return null;
2828
2830
  }
2829
2831
  }
2830
- function writeCache(cache) {
2832
+ function writeCache(cache, configDir) {
2831
2833
  try {
2832
- const dir = getConfigDir();
2834
+ const dir = configDir ?? getConfigDir();
2833
2835
  fs7.mkdirSync(dir, { recursive: true });
2834
2836
  fs7.writeFileSync(path9.join(dir, CACHE_FILE), JSON.stringify(cache));
2835
2837
  } catch {
@@ -5468,7 +5470,7 @@ var init_query_promise = __esm({
5468
5470
  function mapResultRow(columns, row, joinsNotNullableMap) {
5469
5471
  const nullifyMap = {};
5470
5472
  const result = columns.reduce(
5471
- (result2, { path: path23, field }, columnIndex) => {
5473
+ (result2, { path: path24, field }, columnIndex) => {
5472
5474
  let decoder;
5473
5475
  if (is(field, Column)) {
5474
5476
  decoder = field;
@@ -5480,8 +5482,8 @@ function mapResultRow(columns, row, joinsNotNullableMap) {
5480
5482
  decoder = field.sql.decoder;
5481
5483
  }
5482
5484
  let node = result2;
5483
- for (const [pathChunkIndex, pathChunk] of path23.entries()) {
5484
- if (pathChunkIndex < path23.length - 1) {
5485
+ for (const [pathChunkIndex, pathChunk] of path24.entries()) {
5486
+ if (pathChunkIndex < path24.length - 1) {
5485
5487
  if (!(pathChunk in node)) {
5486
5488
  node[pathChunk] = {};
5487
5489
  }
@@ -5489,8 +5491,8 @@ function mapResultRow(columns, row, joinsNotNullableMap) {
5489
5491
  } else {
5490
5492
  const rawValue = row[columnIndex];
5491
5493
  const value = node[pathChunk] = rawValue === null ? null : decoder.mapFromDriverValue(rawValue);
5492
- if (joinsNotNullableMap && is(field, Column) && path23.length === 2) {
5493
- const objectName = path23[0];
5494
+ if (joinsNotNullableMap && is(field, Column) && path24.length === 2) {
5495
+ const objectName = path24[0];
5494
5496
  if (!(objectName in nullifyMap)) {
5495
5497
  nullifyMap[objectName] = value === null ? getTableName(field.table) : false;
5496
5498
  } else if (typeof nullifyMap[objectName] === "string" && nullifyMap[objectName] !== getTableName(field.table)) {
@@ -9437,13 +9439,13 @@ function Subscribe(postgres2, options) {
9437
9439
  }
9438
9440
  }
9439
9441
  function handle(a, b2) {
9440
- const path23 = b2.relation.schema + "." + b2.relation.table;
9442
+ const path24 = b2.relation.schema + "." + b2.relation.table;
9441
9443
  call("*", a, b2);
9442
- call("*:" + path23, a, b2);
9443
- b2.relation.keys.length && call("*:" + path23 + "=" + b2.relation.keys.map((x2) => a[x2.name]), a, b2);
9444
+ call("*:" + path24, a, b2);
9445
+ b2.relation.keys.length && call("*:" + path24 + "=" + b2.relation.keys.map((x2) => a[x2.name]), a, b2);
9444
9446
  call(b2.command, a, b2);
9445
- call(b2.command + ":" + path23, a, b2);
9446
- b2.relation.keys.length && call(b2.command + ":" + path23 + "=" + b2.relation.keys.map((x2) => a[x2.name]), a, b2);
9447
+ call(b2.command + ":" + path24, a, b2);
9448
+ b2.relation.keys.length && call(b2.command + ":" + path24 + "=" + b2.relation.keys.map((x2) => a[x2.name]), a, b2);
9447
9449
  }
9448
9450
  function pong() {
9449
9451
  const x2 = Buffer.alloc(34);
@@ -9556,8 +9558,8 @@ function parseEvent(x) {
9556
9558
  const xs = x.match(/^(\*|insert|update|delete)?:?([^.]+?\.?[^=]+)?=?(.+)?/i) || [];
9557
9559
  if (!xs)
9558
9560
  throw new Error("Malformed subscribe pattern: " + x);
9559
- const [, command, path23, key] = xs;
9560
- return (command || "*") + (path23 ? ":" + (path23.indexOf(".") === -1 ? "public." + path23 : path23) : "") + (key ? "=" + key : "");
9561
+ const [, command, path24, key] = xs;
9562
+ return (command || "*") + (path24 ? ":" + (path24.indexOf(".") === -1 ? "public." + path24 : path24) : "") + (key ? "=" + key : "");
9561
9563
  }
9562
9564
  var noop2;
9563
9565
  var init_subscribe = __esm({
@@ -9695,10 +9697,10 @@ function Postgres(a, b2) {
9695
9697
  });
9696
9698
  return query;
9697
9699
  }
9698
- function file2(path23, args = [], options2 = {}) {
9700
+ function file2(path24, args = [], options2 = {}) {
9699
9701
  arguments.length === 2 && !Array.isArray(args) && (options2 = args, args = []);
9700
9702
  const query = new Query([], args, (query2) => {
9701
- fs11.readFile(path23, "utf8", (err, string4) => {
9703
+ fs11.readFile(path24, "utf8", (err, string4) => {
9702
9704
  if (err)
9703
9705
  return query2.reject(err);
9704
9706
  query2.strings = [string4];
@@ -14756,10 +14758,10 @@ function mergeDefs(...defs) {
14756
14758
  function cloneDef(schema) {
14757
14759
  return mergeDefs(schema._zod.def);
14758
14760
  }
14759
- function getElementAtPath(obj, path23) {
14760
- if (!path23)
14761
+ function getElementAtPath(obj, path24) {
14762
+ if (!path24)
14761
14763
  return obj;
14762
- return path23.reduce((acc, key) => acc?.[key], obj);
14764
+ return path24.reduce((acc, key) => acc?.[key], obj);
14763
14765
  }
14764
14766
  function promiseAllObject(promisesObj) {
14765
14767
  const keys = Object.keys(promisesObj);
@@ -15071,11 +15073,11 @@ function aborted(x, startIndex = 0) {
15071
15073
  }
15072
15074
  return false;
15073
15075
  }
15074
- function prefixIssues(path23, issues) {
15076
+ function prefixIssues(path24, issues) {
15075
15077
  return issues.map((iss) => {
15076
15078
  var _a2;
15077
15079
  (_a2 = iss).path ?? (_a2.path = []);
15078
- iss.path.unshift(path23);
15080
+ iss.path.unshift(path24);
15079
15081
  return iss;
15080
15082
  });
15081
15083
  }
@@ -15317,7 +15319,7 @@ function formatError(error49, mapper = (issue2) => issue2.message) {
15317
15319
  }
15318
15320
  function treeifyError(error49, mapper = (issue2) => issue2.message) {
15319
15321
  const result = { errors: [] };
15320
- const processError = (error50, path23 = []) => {
15322
+ const processError = (error50, path24 = []) => {
15321
15323
  var _a2, _b;
15322
15324
  for (const issue2 of error50.issues) {
15323
15325
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -15327,7 +15329,7 @@ function treeifyError(error49, mapper = (issue2) => issue2.message) {
15327
15329
  } else if (issue2.code === "invalid_element") {
15328
15330
  processError({ issues: issue2.issues }, issue2.path);
15329
15331
  } else {
15330
- const fullpath = [...path23, ...issue2.path];
15332
+ const fullpath = [...path24, ...issue2.path];
15331
15333
  if (fullpath.length === 0) {
15332
15334
  result.errors.push(mapper(issue2));
15333
15335
  continue;
@@ -15359,8 +15361,8 @@ function treeifyError(error49, mapper = (issue2) => issue2.message) {
15359
15361
  }
15360
15362
  function toDotPath(_path) {
15361
15363
  const segs = [];
15362
- const path23 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
15363
- for (const seg of path23) {
15364
+ const path24 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
15365
+ for (const seg of path24) {
15364
15366
  if (typeof seg === "number")
15365
15367
  segs.push(`[${seg}]`);
15366
15368
  else if (typeof seg === "symbol")
@@ -28054,13 +28056,13 @@ function resolveRef(ref, ctx) {
28054
28056
  if (!ref.startsWith("#")) {
28055
28057
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
28056
28058
  }
28057
- const path23 = ref.slice(1).split("/").filter(Boolean);
28058
- if (path23.length === 0) {
28059
+ const path24 = ref.slice(1).split("/").filter(Boolean);
28060
+ if (path24.length === 0) {
28059
28061
  return ctx.rootSchema;
28060
28062
  }
28061
28063
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
28062
- if (path23[0] === defsKey) {
28063
- const key = path23[1];
28064
+ if (path24[0] === defsKey) {
28065
+ const key = path24[1];
28064
28066
  if (!key || !ctx.defs[key]) {
28065
28067
  throw new Error(`Reference not found: ${ref}`);
28066
28068
  }
@@ -30323,6 +30325,10 @@ var init_credit_packages = __esm({
30323
30325
  }).notNull(),
30324
30326
  isActive: boolean("is_active").notNull().default(true),
30325
30327
  includesCatalog: boolean("includes_catalog").notNull().default(true),
30328
+ // Subscription tiers 2026-07-07 spec: % off AI-usage debits (0 = none).
30329
+ consumptionDiscountPercent: integer("consumption_discount_percent").notNull().default(0),
30330
+ // Course enrollments redeemable per billing cycle (0 = none; Pro = 1).
30331
+ courseEnrollmentsPerMonth: integer("course_enrollments_per_month").notNull().default(0),
30326
30332
  sortOrder: integer("sort_order").notNull().default(0),
30327
30333
  createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
30328
30334
  updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull()
@@ -30330,7 +30336,12 @@ var init_credit_packages = __esm({
30330
30336
  (table) => ({
30331
30337
  creditsPositive: check("csp_credits_positive", sql`${table.creditsPerMonth} > 0`),
30332
30338
  pricePositive: check("csp_price_positive", sql`${table.priceUsdMonthly} > 0`),
30333
- nameSlugPattern: check("csp_name_slug_pattern", sql`${table.name} ~ '^[a-z][a-z0-9_]{0,49}$'`)
30339
+ nameSlugPattern: check("csp_name_slug_pattern", sql`${table.name} ~ '^[a-z][a-z0-9_]{0,49}$'`),
30340
+ discountRange: check(
30341
+ "csp_discount_range",
30342
+ sql`${table.consumptionDiscountPercent} >= 0 AND ${table.consumptionDiscountPercent} <= 90`
30343
+ ),
30344
+ quotaNonNegative: check("csp_quota_non_negative", sql`${table.courseEnrollmentsPerMonth} >= 0`)
30334
30345
  })
30335
30346
  );
30336
30347
  creditSubscriptions = pgTable(
@@ -43206,6 +43217,38 @@ var init_email_delivery = __esm({
43206
43217
  }
43207
43218
  });
43208
43219
 
43220
+ // ../../packages/database/src/schema/subscription-redemptions.ts
43221
+ var subscriptionCourseRedemptions;
43222
+ var init_subscription_redemptions = __esm({
43223
+ "../../packages/database/src/schema/subscription-redemptions.ts"() {
43224
+ "use strict";
43225
+ init_pg_core();
43226
+ init_users();
43227
+ init_courses3();
43228
+ init_enrollments();
43229
+ init_credit_packages();
43230
+ subscriptionCourseRedemptions = pgTable(
43231
+ "subscription_course_redemptions",
43232
+ {
43233
+ id: uuid("id").defaultRandom().primaryKey(),
43234
+ subscriptionId: uuid("subscription_id").references(() => creditSubscriptions.id, { onDelete: "restrict" }).notNull(),
43235
+ userId: uuid("user_id").references(() => users.id, { onDelete: "cascade" }).notNull(),
43236
+ courseId: uuid("course_id").references(() => courses.id, { onDelete: "restrict" }).notNull(),
43237
+ enrollmentId: uuid("enrollment_id").references(() => enrollments.id, { onDelete: "restrict" }).notNull(),
43238
+ cycleStart: timestamp("cycle_start", { withTimezone: true }).notNull(),
43239
+ createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull()
43240
+ },
43241
+ (table) => ({
43242
+ oncePerCycle: uniqueIndex("scr_subscription_cycle_uq").on(
43243
+ table.subscriptionId,
43244
+ table.cycleStart
43245
+ ),
43246
+ userIdx: index("scr_user_idx").on(table.userId)
43247
+ })
43248
+ );
43249
+ }
43250
+ });
43251
+
43209
43252
  // ../../packages/database/src/schema/index.ts
43210
43253
  var schema_exports = {};
43211
43254
  __export(schema_exports, {
@@ -43628,6 +43671,7 @@ __export(schema_exports, {
43628
43671
  studyModuleSessionsRelations: () => studyModuleSessionsRelations,
43629
43672
  studyPhaseV2Values: () => studyPhaseV2Values,
43630
43673
  studyPhaseValues: () => studyPhaseValues,
43674
+ subscriptionCourseRedemptions: () => subscriptionCourseRedemptions,
43631
43675
  subscriptionPoolStatusEnum: () => subscriptionPoolStatusEnum,
43632
43676
  subscriptionSplitStatusEnum: () => subscriptionSplitStatusEnum,
43633
43677
  supportedCurrencies: () => supportedCurrencies,
@@ -43801,6 +43845,7 @@ var init_schema3 = __esm({
43801
43845
  init_user_profiles();
43802
43846
  init_user_resource_audits();
43803
43847
  init_email_delivery();
43848
+ init_subscription_redemptions();
43804
43849
  }
43805
43850
  });
43806
43851
 
@@ -47937,13 +47982,77 @@ var init_cli = __esm({
47937
47982
  }
47938
47983
  });
47939
47984
 
47985
+ // src/auto-updater.ts
47986
+ var auto_updater_exports = {};
47987
+ __export(auto_updater_exports, {
47988
+ detectManager: () => detectManager,
47989
+ maybeAutoUpdate: () => maybeAutoUpdate
47990
+ });
47991
+ import fs21 from "node:fs";
47992
+ import path23 from "node:path";
47993
+ import { spawn as spawn2 } from "node:child_process";
47994
+ function detectManager(entryRealPath) {
47995
+ const p = entryRealPath.split(path23.sep).join("/");
47996
+ if (p.includes("/pnpm/")) return { cmd: "pnpm", args: ["add", "-g", `${PACKAGE_NAME2}@latest`] };
47997
+ if (p.includes("/.bun/")) return { cmd: "bun", args: ["add", "-g", `${PACKAGE_NAME2}@latest`] };
47998
+ if (p.includes(`/node_modules/${PACKAGE_NAME2}/`))
47999
+ return { cmd: "npm", args: ["i", "-g", `${PACKAGE_NAME2}@latest`] };
48000
+ return null;
48001
+ }
48002
+ function installDir(entryRealPath) {
48003
+ const normalized = entryRealPath.split(path23.sep).join("/");
48004
+ const marker = `/node_modules/${PACKAGE_NAME2}/`;
48005
+ const idx = normalized.indexOf(marker);
48006
+ if (idx === -1) return path23.dirname(entryRealPath);
48007
+ return entryRealPath.slice(0, idx + marker.length - 1);
48008
+ }
48009
+ function maybeAutoUpdate(currentVersion, opts = {}) {
48010
+ try {
48011
+ const env = opts.env ?? process.env;
48012
+ const argv = opts.argv ?? process.argv;
48013
+ const isTTY = opts.isTTY ?? process.stderr.isTTY === true;
48014
+ if (env["TOSTUDY_NO_AUTO_UPDATE"]) return;
48015
+ if (env["CI"] || !isTTY || argv.includes("--json")) return;
48016
+ const configDir = opts.configDir ?? getConfigDir();
48017
+ const cache = readCache(configDir);
48018
+ if (!cache || !isNewerVersion(cache.latest, currentVersion)) return;
48019
+ if (cache.attemptedVersion === cache.latest) return;
48020
+ const entryPath = opts.entryPath ?? argv[1];
48021
+ if (!entryPath) return;
48022
+ const real2 = fs21.realpathSync(entryPath);
48023
+ const mgr = detectManager(real2);
48024
+ if (!mgr) return;
48025
+ fs21.accessSync(installDir(real2), fs21.constants.W_OK);
48026
+ writeCache({ ...cache, attemptedVersion: cache.latest }, configDir);
48027
+ process.stderr.write(
48028
+ `
48029
+ Atualizando ${PACKAGE_NAME2} para ${cache.latest} em segundo plano\u2026
48030
+ `
48031
+ );
48032
+ const spawnFn = opts.spawnFn ?? spawn2;
48033
+ spawnFn(mgr.cmd, mgr.args, { detached: true, stdio: "ignore" }).unref();
48034
+ } catch {
48035
+ }
48036
+ }
48037
+ var PACKAGE_NAME2;
48038
+ var init_auto_updater = __esm({
48039
+ "src/auto-updater.ts"() {
48040
+ "use strict";
48041
+ init_config_dir();
48042
+ init_update_checker();
48043
+ PACKAGE_NAME2 = "@tostudy-ai/cli";
48044
+ }
48045
+ });
48046
+
47940
48047
  // src/cli-entry.ts
47941
48048
  if (!process.env.LOG_LEVEL) {
47942
48049
  process.env.LOG_LEVEL = "fatal";
47943
48050
  }
47944
48051
  var { createProgram: createProgram2, CLI_VERSION: CLI_VERSION2 } = await Promise.resolve().then(() => (init_cli(), cli_exports));
47945
48052
  var { checkForUpdates: checkForUpdates2 } = await Promise.resolve().then(() => (init_update_checker(), update_checker_exports));
48053
+ var { maybeAutoUpdate: maybeAutoUpdate2 } = await Promise.resolve().then(() => (init_auto_updater(), auto_updater_exports));
47946
48054
  var program = createProgram2();
47947
48055
  program.parse();
47948
48056
  checkForUpdates2(CLI_VERSION2);
48057
+ maybeAutoUpdate2(CLI_VERSION2);
47949
48058
  //# sourceMappingURL=cli.js.map