@thyn-ai/sqai 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,12 +17,21 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
21
31
  var index_exports = {};
22
32
  __export(index_exports, {
23
33
  ContractIndex: () => ContractIndex,
34
+ LoginError: () => LoginError,
24
35
  ResultStore: () => ResultStore,
25
36
  RuntimeProvisioner: () => RuntimeProvisioner,
26
37
  SQAI: () => SQAI,
@@ -31,15 +42,19 @@ __export(index_exports, {
31
42
  currentPlatformKey: () => currentPlatformKey,
32
43
  invocationHash: () => invocationHash,
33
44
  isReadOnlyEligible: () => isReadOnlyEligible,
45
+ login: () => login,
46
+ logout: () => logout,
34
47
  lookupCapability: () => lookupCapability,
48
+ readCachedApiKey: () => readCachedApiKey,
35
49
  runtimeCacheDir: () => runtimeCacheDir,
50
+ sqaiHome: () => sqaiHome,
36
51
  validateComputation: () => validateComputation
37
52
  });
38
53
  module.exports = __toCommonJS(index_exports);
39
54
 
40
55
  // src/sqai.ts
41
- var import_node_crypto6 = require("crypto");
42
- var import_node_os2 = require("os");
56
+ var import_node_crypto7 = require("crypto");
57
+ var import_node_os3 = require("os");
43
58
  var import_algenta_sdk3 = require("algenta-sdk");
44
59
 
45
60
  // src/contract-data.json
@@ -354,22 +369,180 @@ var ResultStore = class {
354
369
  };
355
370
 
356
371
  // src/runtime/provision.ts
357
- var import_node_os = require("os");
358
- var import_node_path2 = require("path");
359
- var import_node_fs2 = require("fs");
360
- var import_node_crypto5 = require("crypto");
372
+ var import_node_os2 = require("os");
373
+ var import_node_path3 = require("path");
374
+ var import_node_fs3 = require("fs");
375
+ var import_node_crypto6 = require("crypto");
361
376
  var import_node_stream = require("stream");
362
377
  var import_promises = require("stream/promises");
363
378
  var import_algenta_sdk2 = require("algenta-sdk");
364
379
 
365
- // src/runtime/bundle.ts
366
- var import_node_child_process = require("child_process");
367
- var import_node_crypto4 = require("crypto");
380
+ // src/runtime/auth.ts
381
+ var import_node_crypto3 = require("crypto");
368
382
  var import_node_fs = require("fs");
383
+ var import_node_os = require("os");
369
384
  var import_node_path = require("path");
385
+ var CLIENT_ID = "sqai-cli";
386
+ var SCOPE = "sqai";
387
+ var PRODUCT = "sqai";
388
+ var DEFAULT_PLAN = "sqai_developer";
389
+ var DEFAULT_ACCOUNTS_URL = "https://accounts.thyn.ai";
390
+ var DEFAULT_API_URL = "https://api.sqai.com";
391
+ var LoginError = class extends Error {
392
+ };
393
+ function sqaiHome() {
394
+ return process.env.SQAI_HOME ?? (0, import_node_path.join)((0, import_node_os.homedir)(), ".sqai");
395
+ }
396
+ var p = (name) => (0, import_node_path.join)(sqaiHome(), name);
397
+ var apiKeyPath = () => p("api_key");
398
+ var tokenPath = () => p("token");
399
+ var deviceIdPath = () => p("device_id");
400
+ var accountsUrl = () => (process.env.SQAI_ACCOUNTS_URL ?? DEFAULT_ACCOUNTS_URL).replace(/\/$/, "");
401
+ var apiUrl = () => (process.env.SQAI_API_URL ?? DEFAULT_API_URL).replace(/\/$/, "");
402
+ function readSecret(path) {
403
+ try {
404
+ const v = (0, import_node_fs.readFileSync)(path, "utf8").trim();
405
+ return v || void 0;
406
+ } catch {
407
+ return void 0;
408
+ }
409
+ }
410
+ async function readCachedApiKey() {
411
+ return process.env.SQAI_API_KEY ?? process.env.ALGENTA_API_KEY ?? readSecret(apiKeyPath());
412
+ }
413
+ function cache(path, value) {
414
+ (0, import_node_fs.mkdirSync)(sqaiHome(), { recursive: true });
415
+ (0, import_node_fs.writeFileSync)(path, value.trim() + "\n", "utf8");
416
+ try {
417
+ (0, import_node_fs.chmodSync)(path, 384);
418
+ } catch {
419
+ }
420
+ }
421
+ function deviceId() {
422
+ const existing = readSecret(deviceIdPath());
423
+ if (existing) return existing;
424
+ const value = (0, import_node_crypto3.createHash)("sha256").update(`${(0, import_node_os.hostname)()}:${Date.now()}:${Math.random()}`).digest("hex");
425
+ cache(deviceIdPath(), value);
426
+ return value;
427
+ }
428
+ async function request(method, url, opts = {}) {
429
+ const headers = { Accept: "application/json", "User-Agent": "sqai-cli" };
430
+ if (opts.body !== void 0) headers["Content-Type"] = "application/json";
431
+ if (opts.bearer) headers["Authorization"] = `Bearer ${opts.bearer}`;
432
+ let res;
433
+ try {
434
+ res = await fetch(url, {
435
+ method,
436
+ headers,
437
+ body: opts.body !== void 0 ? JSON.stringify(opts.body) : void 0
438
+ });
439
+ } catch (e) {
440
+ throw new LoginError(`${method} ${url}: ${e instanceof Error ? e.message : String(e)}`);
441
+ }
442
+ let json = {};
443
+ try {
444
+ json = await res.json();
445
+ } catch {
446
+ json = {};
447
+ }
448
+ return { status: res.status, json };
449
+ }
450
+ async function deviceAuthorize(accounts, openBrowser, maxWaitMs = 3e5) {
451
+ const { json: start } = await request("POST", `${accounts}/oauth/device/code`, {
452
+ body: { client_id: CLIENT_ID, scope: SCOPE }
453
+ });
454
+ const deviceCode = start.device_code;
455
+ const userCode = start.user_code;
456
+ const verify = start.verification_uri_complete || start.verification_uri;
457
+ const interval = Number(start.interval ?? 5);
458
+ if (!deviceCode || !userCode || !verify) throw new LoginError("accounts device-code response missing fields");
459
+ process.stdout.write(`
460
+ Open ${verify}
461
+ and enter code: ${userCode}
462
+
463
+ `);
464
+ if (openBrowser) await tryOpenBrowser(verify);
465
+ const deadline = Date.now() + maxWaitMs;
466
+ while (Date.now() < deadline) {
467
+ await new Promise((r) => setTimeout(r, interval * 1e3));
468
+ const { status, json: tok } = await request("POST", `${accounts}/oauth/device/token`, {
469
+ body: {
470
+ client_id: CLIENT_ID,
471
+ device_code: deviceCode,
472
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code"
473
+ }
474
+ });
475
+ const access = tok.access_token;
476
+ if (access) return access;
477
+ const error = tok.error;
478
+ if (error === "authorization_pending" || error === "slow_down" || status === 400 || status === 428) continue;
479
+ throw new LoginError(`device authorization failed: ${error ?? `HTTP ${status}`}`);
480
+ }
481
+ throw new LoginError("timed out waiting for device authorization");
482
+ }
483
+ async function tryOpenBrowser(url) {
484
+ try {
485
+ const { spawn: spawn2 } = await import("child_process");
486
+ const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
487
+ spawn2(cmd, [url], { stdio: "ignore", detached: true, shell: process.platform === "win32" }).unref();
488
+ } catch {
489
+ }
490
+ }
491
+ async function createApiKey(api, accessToken, plan) {
492
+ const { status, json } = await request("POST", `${api}/v1/products/${PRODUCT}/onboard`, {
493
+ bearer: accessToken,
494
+ body: { name: CLIENT_ID, product: PRODUCT, plan }
495
+ });
496
+ const key = json.raw_key || json.key || json.api_key;
497
+ if (status >= 400 || !key) {
498
+ const detail = json.error && typeof json.error === "object" ? json.error.message : void 0;
499
+ throw new LoginError(`could not create API key (HTTP ${status})${detail ? `: ${detail}` : ""}`);
500
+ }
501
+ return key;
502
+ }
503
+ async function login(opts = {}) {
504
+ const plan = opts.plan ?? DEFAULT_PLAN;
505
+ const accounts = accountsUrl();
506
+ const api = apiUrl();
507
+ let token = opts.accessToken ?? process.env.SQAI_TOKEN;
508
+ if (token) {
509
+ process.stdout.write("using supplied token (headless)\n");
510
+ } else {
511
+ process.stdout.write(`authenticating via ${accounts} \u2026
512
+ `);
513
+ token = await deviceAuthorize(accounts, opts.openBrowser ?? true);
514
+ }
515
+ cache(tokenPath(), token);
516
+ process.stdout.write("creating your free SQAI Developer API key \u2026\n");
517
+ const apiKey = await createApiKey(api, token, plan);
518
+ cache(apiKeyPath(), apiKey);
519
+ deviceId();
520
+ process.stdout.write(
521
+ "\n \u2713 sqai login complete \u2014 the local runtime will provision a device-bound offline license on first use.\n SQAI runs fully on your machine; no data leaves it.\n\n"
522
+ );
523
+ return {
524
+ device_id: deviceId(),
525
+ plan,
526
+ api_key_prefix: apiKey.includes("_") ? `${apiKey.split("_", 1)[0]}_\u2026` : `${apiKey.slice(0, 6)}\u2026`
527
+ };
528
+ }
529
+ function logout() {
530
+ for (const path of [tokenPath(), apiKeyPath()]) {
531
+ try {
532
+ (0, import_node_fs.rmSync)(path);
533
+ } catch {
534
+ }
535
+ }
536
+ }
537
+
538
+ // src/runtime/bundle.ts
539
+ var import_node_child_process = require("child_process");
540
+ var import_node_crypto5 = require("crypto");
541
+ var import_node_fs2 = require("fs");
542
+ var import_node_path2 = require("path");
370
543
 
371
544
  // src/runtime/trust.ts
372
- var import_node_crypto3 = require("crypto");
545
+ var import_node_crypto4 = require("crypto");
373
546
  var RELEASE_1_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
374
547
  MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA7m4G1dEMi5FppLa5hu9N
375
548
  4pUyoGELPaN5X7bO+9Qktgbv21+c8I4sQCufKouZEVNMNluKNrWcQ5dSwOuVxxS9
@@ -468,11 +641,11 @@ function keyValidNow(key, nowMs) {
468
641
  }
469
642
  function signatureVerifies(manifestBytes, signature, publicKeyPem) {
470
643
  try {
471
- const key = (0, import_node_crypto3.createPublicKey)(publicKeyPem);
644
+ const key = (0, import_node_crypto4.createPublicKey)(publicKeyPem);
472
645
  if (key.asymmetricKeyType !== "rsa") {
473
646
  return false;
474
647
  }
475
- return (0, import_node_crypto3.verify)("sha256", manifestBytes, key, signature);
648
+ return (0, import_node_crypto4.verify)("sha256", manifestBytes, key, signature);
476
649
  } catch {
477
650
  return false;
478
651
  }
@@ -652,7 +825,7 @@ async function hashTarMember(tarball, member, cap) {
652
825
  const child = (0, import_node_child_process.spawn)("tar", ["-xOf", tarball, "--", member], {
653
826
  stdio: ["ignore", "pipe", "pipe"]
654
827
  });
655
- const digest = (0, import_node_crypto4.createHash)("sha256");
828
+ const digest = (0, import_node_crypto5.createHash)("sha256");
656
829
  let total = 0;
657
830
  let overflow = false;
658
831
  child.stdout.on("data", (chunk) => {
@@ -686,7 +859,7 @@ async function hashTarMember(tarball, member, cap) {
686
859
  });
687
860
  }
688
861
  async function extractTarball(tarball, destinationDir) {
689
- await import_node_fs.promises.mkdir(destinationDir, { recursive: true });
862
+ await import_node_fs2.promises.mkdir(destinationDir, { recursive: true });
690
863
  await new Promise((resolve, reject) => {
691
864
  const child = (0, import_node_child_process.spawn)("tar", ["-xf", tarball, "-C", destinationDir], {
692
865
  stdio: ["ignore", "ignore", "pipe"]
@@ -712,8 +885,8 @@ async function extractTarball(tarball, destinationDir) {
712
885
  }
713
886
  function sha256File(path) {
714
887
  return new Promise((resolve, reject) => {
715
- const digest = (0, import_node_crypto4.createHash)("sha256");
716
- const stream = (0, import_node_fs.createReadStream)(path);
888
+ const digest = (0, import_node_crypto5.createHash)("sha256");
889
+ const stream = (0, import_node_fs2.createReadStream)(path);
717
890
  stream.on("data", (chunk) => digest.update(chunk));
718
891
  stream.on("error", reject);
719
892
  stream.on("end", () => resolve(digest.digest("hex")));
@@ -722,7 +895,7 @@ function sha256File(path) {
722
895
  function digestsEqual(actualHex, expectedHex) {
723
896
  const actual = Buffer.from(actualHex.toLowerCase(), "utf-8");
724
897
  const expected = Buffer.from(expectedHex.toLowerCase(), "utf-8");
725
- return actual.length === expected.length && (0, import_node_crypto4.timingSafeEqual)(actual, expected);
898
+ return actual.length === expected.length && (0, import_node_crypto5.timingSafeEqual)(actual, expected);
726
899
  }
727
900
  function parseVerifiedManifest(manifestBytes) {
728
901
  let manifest;
@@ -872,7 +1045,7 @@ async function verifyBundleTarball(tarball, expectations) {
872
1045
  return manifest;
873
1046
  }
874
1047
  async function listFilesRecursively(root, relative = "") {
875
- const entries = await import_node_fs.promises.readdir((0, import_node_path.join)(root, relative), { withFileTypes: true });
1048
+ const entries = await import_node_fs2.promises.readdir((0, import_node_path2.join)(root, relative), { withFileTypes: true });
876
1049
  const files = [];
877
1050
  for (const entry of entries) {
878
1051
  const relPath = relative === "" ? entry.name : `${relative}/${entry.name}`;
@@ -896,21 +1069,21 @@ async function listFilesRecursively(root, relative = "") {
896
1069
  return files;
897
1070
  }
898
1071
  async function verifyInstalledBundleDir(installDir, expectations) {
899
- const manifestPath = (0, import_node_path.join)(installDir, MANIFEST_NAME);
900
- const signaturePath = (0, import_node_path.join)(installDir, MANIFEST_SIG_NAME);
1072
+ const manifestPath = (0, import_node_path2.join)(installDir, MANIFEST_NAME);
1073
+ const signaturePath = (0, import_node_path2.join)(installDir, MANIFEST_SIG_NAME);
901
1074
  let manifestBytes;
902
1075
  let signature;
903
1076
  try {
904
- const manifestStat = await import_node_fs.promises.lstat(manifestPath);
905
- const signatureStat = await import_node_fs.promises.lstat(signaturePath);
1077
+ const manifestStat = await import_node_fs2.promises.lstat(manifestPath);
1078
+ const signatureStat = await import_node_fs2.promises.lstat(signaturePath);
906
1079
  if (!manifestStat.isFile() || !signatureStat.isFile() || manifestStat.size > MAX_MANIFEST_BYTES || signatureStat.size > MAX_SIG_BYTES) {
907
1080
  throw new BundleVerificationError(
908
1081
  "member_unreadable",
909
1082
  "installed bundle manifest/signature is not a capped regular file"
910
1083
  );
911
1084
  }
912
- manifestBytes = await import_node_fs.promises.readFile(manifestPath);
913
- signature = await import_node_fs.promises.readFile(signaturePath);
1085
+ manifestBytes = await import_node_fs2.promises.readFile(manifestPath);
1086
+ signature = await import_node_fs2.promises.readFile(signaturePath);
914
1087
  } catch (error) {
915
1088
  if (error instanceof BundleVerificationError) {
916
1089
  throw error;
@@ -937,8 +1110,8 @@ async function verifyInstalledBundleDir(installDir, expectations) {
937
1110
  `installed file not listed in signed manifest: '${relPath}'`
938
1111
  );
939
1112
  }
940
- const absolute = (0, import_node_path.join)(installDir, relPath);
941
- const stat = await import_node_fs.promises.lstat(absolute);
1113
+ const absolute = (0, import_node_path2.join)(installDir, relPath);
1114
+ const stat = await import_node_fs2.promises.lstat(absolute);
942
1115
  if (stat.nlink > 1) {
943
1116
  throw new BundleVerificationError(
944
1117
  "unsafe_member",
@@ -994,28 +1167,28 @@ var LOCK_FRESH_MS = 10 * 60 * 1e3;
994
1167
  var LOCK_WAIT_TIMEOUT_MS = 90 * 1e3;
995
1168
  var LOCK_POLL_INTERVAL_MS = 1e3;
996
1169
  function currentPlatformKey() {
997
- const os = (0, import_node_os.platform)();
998
- const arch = (0, import_node_os.arch)();
1170
+ const os = (0, import_node_os2.platform)();
1171
+ const arch = (0, import_node_os2.arch)();
999
1172
  const osName = os === "darwin" ? "darwin" : os === "linux" ? "linux" : os;
1000
1173
  return `${osName}-${arch}`;
1001
1174
  }
1002
1175
  function cacheDirFor(brand) {
1003
- const os = (0, import_node_os.platform)();
1176
+ const os = (0, import_node_os2.platform)();
1004
1177
  if (os === "darwin") {
1005
- return (0, import_node_path2.join)((0, import_node_os.homedir)(), "Library", "Caches", brand, "runtime");
1178
+ return (0, import_node_path3.join)((0, import_node_os2.homedir)(), "Library", "Caches", brand, "runtime");
1006
1179
  }
1007
1180
  if (os === "win32") {
1008
- const localAppData = process.env.LOCALAPPDATA ?? (0, import_node_path2.join)((0, import_node_os.homedir)(), "AppData", "Local");
1009
- return (0, import_node_path2.join)(localAppData, brand, "runtime");
1181
+ const localAppData = process.env.LOCALAPPDATA ?? (0, import_node_path3.join)((0, import_node_os2.homedir)(), "AppData", "Local");
1182
+ return (0, import_node_path3.join)(localAppData, brand, "runtime");
1010
1183
  }
1011
- const xdgCache = process.env.XDG_CACHE_HOME ?? (0, import_node_path2.join)((0, import_node_os.homedir)(), ".cache");
1012
- return (0, import_node_path2.join)(xdgCache, brand.toLowerCase(), "runtime");
1184
+ const xdgCache = process.env.XDG_CACHE_HOME ?? (0, import_node_path3.join)((0, import_node_os2.homedir)(), ".cache");
1185
+ return (0, import_node_path3.join)(xdgCache, brand.toLowerCase(), "runtime");
1013
1186
  }
1014
1187
  function runtimeCacheDir() {
1015
1188
  const current = cacheDirFor("SQAI");
1016
- if (!(0, import_node_fs2.existsSync)(current)) {
1189
+ if (!(0, import_node_fs3.existsSync)(current)) {
1017
1190
  const legacy = cacheDirFor("Algenta");
1018
- if (legacy !== current && (0, import_node_fs2.existsSync)(legacy)) {
1191
+ if (legacy !== current && (0, import_node_fs3.existsSync)(legacy)) {
1019
1192
  return legacy;
1020
1193
  }
1021
1194
  }
@@ -1034,12 +1207,12 @@ async function defaultDownloadBundle(url, destination) {
1034
1207
  }
1035
1208
  await (0, import_promises.pipeline)(
1036
1209
  import_node_stream.Readable.fromWeb(response.body),
1037
- (0, import_node_fs2.createWriteStream)(destination)
1210
+ (0, import_node_fs3.createWriteStream)(destination)
1038
1211
  );
1039
1212
  }
1040
1213
  async function removeQuietly(path) {
1041
1214
  try {
1042
- await import_node_fs2.promises.rm(path, { recursive: true, force: true });
1215
+ await import_node_fs3.promises.rm(path, { recursive: true, force: true });
1043
1216
  } catch {
1044
1217
  }
1045
1218
  }
@@ -1164,7 +1337,7 @@ var RuntimeProvisioner = class _RuntimeProvisioner {
1164
1337
  localCacheKey(modules, platformKey) {
1165
1338
  const canonical = modules.join(",");
1166
1339
  const version = this.options.contract.runtime_bundle.version;
1167
- return (0, import_node_crypto5.createHash)("sha256").update(`${canonical}|${platformKey}|${version}`).digest("hex").slice(0, 20);
1340
+ return (0, import_node_crypto6.createHash)("sha256").update(`${canonical}|${platformKey}|${version}`).digest("hex").slice(0, 20);
1168
1341
  }
1169
1342
  /**
1170
1343
  * Deterministic per-filter daemon endpoint so a filtered runtime never collides
@@ -1173,7 +1346,7 @@ var RuntimeProvisioner = class _RuntimeProvisioner {
1173
1346
  filterEndpoint(cacheKey) {
1174
1347
  const seed = parseInt(cacheKey.slice(0, 6), 16) || 0;
1175
1348
  const port = 50100 + seed % 800;
1176
- return { sock: (0, import_node_path2.join)(this.cacheDir(), `${cacheKey}.sock`), tcp: `127.0.0.1:${port}` };
1349
+ return { sock: (0, import_node_path3.join)(this.cacheDir(), `${cacheKey}.sock`), tcp: `127.0.0.1:${port}` };
1177
1350
  }
1178
1351
  static DAEMON_ENDPOINT_ENV = [
1179
1352
  "ALGENTA_DAEMON_SOCK",
@@ -1190,7 +1363,7 @@ var RuntimeProvisioner = class _RuntimeProvisioner {
1190
1363
  process.env.ALGENTA_DAEMON_SOCK = endpoint.sock;
1191
1364
  process.env.ALGENTA_DAEMON_TCP = endpoint.tcp;
1192
1365
  process.env.ALGENTA_MOJO_SOCK = `${endpoint.sock}.worker`;
1193
- process.env.ALGENTA_RUNTIME_DIR = (0, import_node_path2.join)(installDir, ".runtime");
1366
+ process.env.ALGENTA_RUNTIME_DIR = (0, import_node_path3.join)(installDir, ".runtime");
1194
1367
  return saved;
1195
1368
  }
1196
1369
  restoreEnv(saved) {
@@ -1305,9 +1478,9 @@ var RuntimeProvisioner = class _RuntimeProvisioner {
1305
1478
  }
1306
1479
  /** Verify an existing install if present; returns null when absent/invalid. */
1307
1480
  async verifiedInstallOrNull(platformKey, version, removeOnFailure, installKey = version) {
1308
- const installDir = (0, import_node_path2.join)(this.cacheDir(), installKey);
1481
+ const installDir = (0, import_node_path3.join)(this.cacheDir(), installKey);
1309
1482
  try {
1310
- await import_node_fs2.promises.access((0, import_node_path2.join)(installDir, MANIFEST_NAME));
1483
+ await import_node_fs3.promises.access((0, import_node_path3.join)(installDir, MANIFEST_NAME));
1311
1484
  } catch {
1312
1485
  return null;
1313
1486
  }
@@ -1327,7 +1500,7 @@ var RuntimeProvisioner = class _RuntimeProvisioner {
1327
1500
  async acquireLock(lockPath) {
1328
1501
  const payload = JSON.stringify({ pid: process.pid, created_at: (/* @__PURE__ */ new Date()).toISOString() });
1329
1502
  try {
1330
- const handle = await import_node_fs2.promises.open(lockPath, "wx");
1503
+ const handle = await import_node_fs3.promises.open(lockPath, "wx");
1331
1504
  try {
1332
1505
  await handle.writeFile(payload, "utf-8");
1333
1506
  } finally {
@@ -1341,7 +1514,7 @@ var RuntimeProvisioner = class _RuntimeProvisioner {
1341
1514
  async lockIsStale(lockPath) {
1342
1515
  const freshMs = this.options.lockFreshMs ?? LOCK_FRESH_MS;
1343
1516
  try {
1344
- const raw = await import_node_fs2.promises.readFile(lockPath, "utf-8");
1517
+ const raw = await import_node_fs3.promises.readFile(lockPath, "utf-8");
1345
1518
  const parsed = JSON.parse(raw);
1346
1519
  const createdAt = typeof parsed.created_at === "string" ? Date.parse(parsed.created_at) : NaN;
1347
1520
  if (!Number.isFinite(createdAt)) {
@@ -1359,12 +1532,12 @@ var RuntimeProvisioner = class _RuntimeProvisioner {
1359
1532
  /** Serialize installers on `<cacheDir>/<installKey>.lock`; returns the verified install. */
1360
1533
  async ensureInstalled(platformKey, version, platformBundle, installKey = version) {
1361
1534
  const cacheDir = this.cacheDir();
1362
- await import_node_fs2.promises.mkdir(cacheDir, { recursive: true });
1535
+ await import_node_fs3.promises.mkdir(cacheDir, { recursive: true });
1363
1536
  const existing = await this.verifiedInstallOrNull(platformKey, version, true, installKey);
1364
1537
  if (existing) {
1365
1538
  return existing;
1366
1539
  }
1367
- const lockPath = (0, import_node_path2.join)(cacheDir, `${installKey}.lock`);
1540
+ const lockPath = (0, import_node_path3.join)(cacheDir, `${installKey}.lock`);
1368
1541
  const waitTimeoutMs = this.options.lockWaitTimeoutMs ?? LOCK_WAIT_TIMEOUT_MS;
1369
1542
  const pollIntervalMs = this.options.lockPollIntervalMs ?? LOCK_POLL_INTERVAL_MS;
1370
1543
  const deadline = Date.now() + waitTimeoutMs;
@@ -1409,10 +1582,10 @@ var RuntimeProvisioner = class _RuntimeProvisioner {
1409
1582
  /** Holder-of-the-lock path: download → verify → extract → atomic rename. */
1410
1583
  async downloadVerifyExtract(platformKey, version, platformBundle, installKey = version) {
1411
1584
  const cacheDir = this.cacheDir();
1412
- const token = (0, import_node_crypto5.randomBytes)(6).toString("hex");
1413
- const tarballPath = (0, import_node_path2.join)(cacheDir, `tmp-${token}.tgz`);
1414
- const extractDir = (0, import_node_path2.join)(cacheDir, `tmp-${token}`);
1415
- const installDir = (0, import_node_path2.join)(cacheDir, installKey);
1585
+ const token = (0, import_node_crypto6.randomBytes)(6).toString("hex");
1586
+ const tarballPath = (0, import_node_path3.join)(cacheDir, `tmp-${token}.tgz`);
1587
+ const extractDir = (0, import_node_path3.join)(cacheDir, `tmp-${token}`);
1588
+ const installDir = (0, import_node_path3.join)(cacheDir, installKey);
1416
1589
  const url = resolveBundleUrl(platformBundle.url, version, platformKey);
1417
1590
  try {
1418
1591
  const download = this.options.downloadBundle ?? defaultDownloadBundle;
@@ -1457,7 +1630,7 @@ var RuntimeProvisioner = class _RuntimeProvisioner {
1457
1630
  throw this.wrapVerificationError(error, platformKey, version);
1458
1631
  }
1459
1632
  try {
1460
- await import_node_fs2.promises.rename(extractDir, installDir);
1633
+ await import_node_fs3.promises.rename(extractDir, installDir);
1461
1634
  } catch (error) {
1462
1635
  const raced = await this.verifiedInstallOrNull(platformKey, version, false, installKey);
1463
1636
  if (raced) {
@@ -1487,10 +1660,16 @@ var RuntimeProvisioner = class _RuntimeProvisioner {
1487
1660
  throw this.wrapVerificationError(error, platformKey, version);
1488
1661
  }
1489
1662
  const daemonCommand = [
1490
- (0, import_node_path2.join)(installed.installDir, ...entryRelative.split("/")),
1663
+ (0, import_node_path3.join)(installed.installDir, ...entryRelative.split("/")),
1491
1664
  "start",
1492
1665
  "--foreground"
1493
1666
  ];
1667
+ if (!process.env.ALGENTA_API_KEY && !process.env.DE_API_KEY) {
1668
+ const key = await readCachedApiKey();
1669
+ if (key) {
1670
+ process.env.ALGENTA_API_KEY = key;
1671
+ }
1672
+ }
1494
1673
  const managed = this.newRuntime(
1495
1674
  endpoint ? { autoStart: true, daemonCommand, tcpAddress: endpoint.tcp } : { autoStart: true, daemonCommand }
1496
1675
  );
@@ -1524,8 +1703,8 @@ var RuntimeProvisioner = class _RuntimeProvisioner {
1524
1703
  }
1525
1704
  }
1526
1705
  try {
1527
- await import_node_fs2.promises.writeFile(
1528
- (0, import_node_path2.join)(this.cacheDir(), "state.json"),
1706
+ await import_node_fs3.promises.writeFile(
1707
+ (0, import_node_path3.join)(this.cacheDir(), "state.json"),
1529
1708
  JSON.stringify(
1530
1709
  { pid: null, version, started_at: (/* @__PURE__ */ new Date()).toISOString() },
1531
1710
  null,
@@ -1894,7 +2073,7 @@ var SQAI = class {
1894
2073
  async compute(spec) {
1895
2074
  const resolvedBindings = await this.resolveBindings(spec.bindings ?? []);
1896
2075
  const validated = validateComputation(spec, this.contractIndex, this.policy, resolvedBindings);
1897
- const requestId = `sqai_${(0, import_node_crypto6.randomBytes)(8).toString("hex")}`;
2076
+ const requestId = `sqai_${(0, import_node_crypto7.randomBytes)(8).toString("hex")}`;
1898
2077
  const target = await this.dispatchTarget();
1899
2078
  const outcome = await dispatchComputation(
1900
2079
  target,
@@ -1937,7 +2116,7 @@ var SQAI = class {
1937
2116
  runtime_bundle_version: bundle.version || "unmanaged",
1938
2117
  runtime_bundle_sha256: platformBundle?.sha256 ?? "unmanaged",
1939
2118
  platform: currentPlatformKey(),
1940
- architecture: (0, import_node_os2.arch)(),
2119
+ architecture: (0, import_node_os3.arch)(),
1941
2120
  kernel_build: outcome.engine_used,
1942
2121
  precision_mode: "float64",
1943
2122
  thread_count: 1,
@@ -2091,6 +2270,7 @@ function mapSource(registration) {
2091
2270
  // Annotate the CommonJS export names for ESM import in node:
2092
2271
  0 && (module.exports = {
2093
2272
  ContractIndex,
2273
+ LoginError,
2094
2274
  ResultStore,
2095
2275
  RuntimeProvisioner,
2096
2276
  SQAI,
@@ -2101,8 +2281,12 @@ function mapSource(registration) {
2101
2281
  currentPlatformKey,
2102
2282
  invocationHash,
2103
2283
  isReadOnlyEligible,
2284
+ login,
2285
+ logout,
2104
2286
  lookupCapability,
2287
+ readCachedApiKey,
2105
2288
  runtimeCacheDir,
2289
+ sqaiHome,
2106
2290
  validateComputation
2107
2291
  });
2108
2292
  //# sourceMappingURL=index.cjs.map