@hasna/models 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -2574,34 +2574,56 @@ var source_default = chalk;
2574
2574
 
2575
2575
  // src/cli/index.ts
2576
2576
  import { randomUUID as randomUUID2 } from "crypto";
2577
- import { existsSync, readFileSync as readFileSync2, rmSync, statSync } from "fs";
2578
- import { dirname as dirname4, join as join3 } from "path";
2579
- import { fileURLToPath } from "url";
2577
+ import { existsSync as existsSync2, readFileSync as readFileSync3, rmSync, statSync as statSync2 } from "fs";
2578
+ import { dirname as dirname5, join as join4 } from "path";
2579
+ import { fileURLToPath as fileURLToPath2 } from "url";
2580
2580
 
2581
2581
  // src/version.ts
2582
+ import { existsSync, readFileSync } from "fs";
2583
+ import { dirname, join, parse } from "path";
2584
+ import { fileURLToPath } from "url";
2585
+ var cachedVersion = null;
2582
2586
  function getPackageVersion() {
2583
- return "0.0.2";
2587
+ if (cachedVersion)
2588
+ return cachedVersion;
2589
+ let currentDir = dirname(fileURLToPath(import.meta.url));
2590
+ const root = parse(currentDir).root;
2591
+ while (true) {
2592
+ const packageJsonPath = join(currentDir, "package.json");
2593
+ if (existsSync(packageJsonPath)) {
2594
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
2595
+ if (typeof packageJson.version === "string" && packageJson.version.trim()) {
2596
+ cachedVersion = packageJson.version;
2597
+ return cachedVersion;
2598
+ }
2599
+ throw new Error(`Package metadata at ${packageJsonPath} does not declare a version`);
2600
+ }
2601
+ if (currentDir === root)
2602
+ break;
2603
+ currentDir = dirname(currentDir);
2604
+ }
2605
+ throw new Error("Unable to locate package.json for @hasna/models");
2584
2606
  }
2585
2607
 
2586
2608
  // src/auth.ts
2587
- import { mkdirSync, readFileSync, writeFileSync } from "fs";
2588
- import { dirname } from "path";
2609
+ import { mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
2610
+ import { dirname as dirname2 } from "path";
2589
2611
  import { spawnSync } from "child_process";
2590
2612
 
2591
2613
  // src/paths.ts
2592
2614
  import { homedir } from "os";
2593
- import { join } from "path";
2615
+ import { join as join2 } from "path";
2594
2616
  function getModelsHome() {
2595
- return process.env["HASNA_MODELS_HOME"] || join(homedir(), ".hasna", "models");
2617
+ return process.env["HASNA_MODELS_HOME"] || join2(homedir(), ".hasna", "models");
2596
2618
  }
2597
2619
  function getDbPath() {
2598
- return process.env["HASNA_MODELS_DB"] || join(getModelsHome(), "models.db");
2620
+ return process.env["HASNA_MODELS_DB"] || join2(getModelsHome(), "models.db");
2599
2621
  }
2600
2622
  function getAuthConfigPath() {
2601
- return join(getModelsHome(), "auth.json");
2623
+ return join2(getModelsHome(), "auth.json");
2602
2624
  }
2603
2625
  function getInstallRoot() {
2604
- return process.env["HASNA_MODELS_INSTALLS"] || join(getModelsHome(), "installs");
2626
+ return process.env["HASNA_MODELS_INSTALLS"] || join2(getModelsHome(), "installs");
2605
2627
  }
2606
2628
 
2607
2629
  // src/auth.ts
@@ -2619,14 +2641,14 @@ var DEFAULT_HF_SECRET_KEYS = [
2619
2641
  var cachedResolution = null;
2620
2642
  function readAuthConfig() {
2621
2643
  try {
2622
- return JSON.parse(readFileSync(getAuthConfigPath(), "utf8"));
2644
+ return JSON.parse(readFileSync2(getAuthConfigPath(), "utf8"));
2623
2645
  } catch {
2624
2646
  return {};
2625
2647
  }
2626
2648
  }
2627
2649
  function writeAuthConfig(config) {
2628
2650
  const path = getAuthConfigPath();
2629
- mkdirSync(dirname(path), { recursive: true });
2651
+ mkdirSync(dirname2(path), { recursive: true });
2630
2652
  writeFileSync(path, `${JSON.stringify(config, null, 2)}
2631
2653
  `);
2632
2654
  }
@@ -2778,8 +2800,8 @@ function safePathSegment(value) {
2778
2800
  }
2779
2801
 
2780
2802
  // src/huggingface.ts
2781
- import { createWriteStream, mkdirSync as mkdirSync2, renameSync, unlinkSync } from "fs";
2782
- import { dirname as dirname2, isAbsolute, join as join2, resolve, sep } from "path";
2803
+ import { createWriteStream, mkdirSync as mkdirSync2, renameSync, statSync, unlinkSync } from "fs";
2804
+ import { dirname as dirname3, isAbsolute, join as join3, resolve, sep } from "path";
2783
2805
  import { pipeline } from "stream/promises";
2784
2806
  import { Readable } from "stream";
2785
2807
  import { randomUUID } from "crypto";
@@ -3015,7 +3037,7 @@ async function createDownloadPlan(input) {
3015
3037
  const unknownSizeFiles = files.filter((file) => file.size == null).map((file) => file.path);
3016
3038
  const totalBytes = unknownSizeFiles.length > 0 ? null : knownBytes;
3017
3039
  const maxBytes = input.maxBytes ?? null;
3018
- const destinationRoot = input.destinationRoot ?? join2(getInstallRoot(), input.ref.provider, input.ref.entityKind, safePathSegment(input.ref.repoId), safePathSegment(input.ref.revision));
3040
+ const destinationRoot = input.destinationRoot ?? join3(getInstallRoot(), input.ref.provider, input.ref.entityKind, safePathSegment(input.ref.repoId), safePathSegment(input.ref.revision));
3019
3041
  return {
3020
3042
  ref: input.ref,
3021
3043
  files,
@@ -3037,7 +3059,7 @@ async function downloadPlannedFiles(plan) {
3037
3059
  for (const file of plan.files) {
3038
3060
  const destination = safeDestinationPath(plan.destinationRoot, file.path);
3039
3061
  const tempDestination = `${destination}.partial-${randomUUID()}`;
3040
- mkdirSync2(dirname2(destination), { recursive: true });
3062
+ mkdirSync2(dirname3(destination), { recursive: true });
3041
3063
  const response = await fetch(file.downloadUrl, { headers: headers(), redirect: "follow" });
3042
3064
  if (!response.ok || !response.body) {
3043
3065
  const text = await response.text().catch(() => "");
@@ -3045,8 +3067,11 @@ async function downloadPlannedFiles(plan) {
3045
3067
  }
3046
3068
  try {
3047
3069
  await pipeline(Readable.fromWeb(response.body), createWriteStream(tempDestination));
3070
+ const bytes = statSync(tempDestination).size;
3071
+ if (file.size != null && bytes !== file.size) {
3072
+ throw new Error(`Downloaded size mismatch for ${file.path}: expected ${file.size} bytes, got ${bytes}`);
3073
+ }
3048
3074
  renameSync(tempDestination, destination);
3049
- const bytes = file.size ?? Bun.file(destination).size;
3050
3075
  downloaded.push({ path: file.path, bytes, destination });
3051
3076
  } catch (error) {
3052
3077
  try {
@@ -3060,14 +3085,14 @@ async function downloadPlannedFiles(plan) {
3060
3085
 
3061
3086
  // src/storage.ts
3062
3087
  import { mkdirSync as mkdirSync3 } from "fs";
3063
- import { dirname as dirname3 } from "path";
3088
+ import { dirname as dirname4 } from "path";
3064
3089
  import { Database } from "bun:sqlite";
3065
3090
  var SCHEMA_VERSION = 1;
3066
3091
 
3067
3092
  class ModelsStore {
3068
3093
  db;
3069
3094
  constructor(path = getDbPath()) {
3070
- mkdirSync3(dirname3(path), { recursive: true });
3095
+ mkdirSync3(dirname4(path), { recursive: true });
3071
3096
  this.db = new Database(path, { create: true });
3072
3097
  this.db.run("PRAGMA busy_timeout = 5000");
3073
3098
  this.db.run("PRAGMA journal_mode = WAL");
@@ -3613,7 +3638,7 @@ program2.command("remove").argument("<id-or-repo>", "install id or repo id").des
3613
3638
  printResult(result, `would remove metadata for ${install.id}${opts.files ? ` and files at ${install.installPath}` : ""}`, opts);
3614
3639
  return;
3615
3640
  }
3616
- if (opts.files && existsSync(install.installPath)) {
3641
+ if (opts.files && existsSync2(install.installPath)) {
3617
3642
  rmSync(install.installPath, { recursive: true, force: true });
3618
3643
  }
3619
3644
  store.deleteInstall(install.id);
@@ -3697,7 +3722,7 @@ program2.command("doctor").description("Check local store, auth, and basic runti
3697
3722
  const auth = redactAuthStatus(getHuggingFaceAuthStatus());
3698
3723
  const checks = [
3699
3724
  { id: "data-dir", status: "ok", detail: dataDir },
3700
- { id: "sqlite", status: existsSync(dbPath) ? "ok" : "warn", detail: dbPath },
3725
+ { id: "sqlite", status: existsSync2(dbPath) ? "ok" : "warn", detail: dbPath },
3701
3726
  { id: "huggingface-auth", status: auth.available ? "ok" : "warn", detail: auth.available ? `token available via ${auth.source}` : "anonymous Hub access only" },
3702
3727
  { id: "catalog", status: "ok", detail: JSON.stringify(store.catalogStats()) }
3703
3728
  ];
@@ -3729,11 +3754,11 @@ program2.command("manual").description("Print the local command manual").option(
3729
3754
  `), opts);
3730
3755
  });
3731
3756
  program2.command("goals").description("Print the implementation goal chain").option("-j, --json", "output JSON").action((opts) => {
3732
- const cliDir = dirname4(fileURLToPath(import.meta.url));
3733
- const path = join3(cliDir, "..", "..", "docs", "GOALS.md");
3734
- const text = existsSync(path) ? readFileSync2(path, "utf8") : "Goal chain not found.";
3757
+ const cliDir = dirname5(fileURLToPath2(import.meta.url));
3758
+ const path = join4(cliDir, "..", "..", "docs", "GOALS.md");
3759
+ const text = existsSync2(path) ? readFileSync3(path, "utf8") : "Goal chain not found.";
3735
3760
  if (isJson(opts)) {
3736
- printJson({ path, bytes: existsSync(path) ? statSync(path).size : 0, text });
3761
+ printJson({ path, bytes: existsSync2(path) ? statSync2(path).size : 0, text });
3737
3762
  } else {
3738
3763
  console.log(text);
3739
3764
  }
package/dist/index.js CHANGED
@@ -424,7 +424,7 @@ function saveHuggingFaceSecretRef(secretKey) {
424
424
  return redactAuthStatus({ provider: "huggingface", available: Boolean(readSecret(secretKey)), source: "secrets", secretKey });
425
425
  }
426
426
  // src/huggingface.ts
427
- import { createWriteStream, mkdirSync as mkdirSync3, renameSync, unlinkSync } from "fs";
427
+ import { createWriteStream, mkdirSync as mkdirSync3, renameSync, statSync, unlinkSync } from "fs";
428
428
  import { dirname as dirname3, isAbsolute, join as join2, resolve, sep } from "path";
429
429
  import { pipeline } from "stream/promises";
430
430
  import { Readable } from "stream";
@@ -691,8 +691,11 @@ async function downloadPlannedFiles(plan) {
691
691
  }
692
692
  try {
693
693
  await pipeline(Readable.fromWeb(response.body), createWriteStream(tempDestination));
694
+ const bytes = statSync(tempDestination).size;
695
+ if (file.size != null && bytes !== file.size) {
696
+ throw new Error(`Downloaded size mismatch for ${file.path}: expected ${file.size} bytes, got ${bytes}`);
697
+ }
694
698
  renameSync(tempDestination, destination);
695
- const bytes = file.size ?? Bun.file(destination).size;
696
699
  downloaded.push({ path: file.path, bytes, destination });
697
700
  } catch (error) {
698
701
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/models",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "CLI-first local model and dataset lifecycle tool for open-source/open-weight catalogs",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",