@alva-ai/toolkit 0.1.4 → 0.2.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/dist/cli.js CHANGED
@@ -11,6 +11,14 @@ var AlvaError = class extends Error {
11
11
  this.status = status;
12
12
  }
13
13
  };
14
+ var CliUsageError = class extends Error {
15
+ command;
16
+ constructor(message, command) {
17
+ super(message);
18
+ this.name = "CliUsageError";
19
+ this.command = command;
20
+ }
21
+ };
14
22
 
15
23
  // src/resources/fs.ts
16
24
  var FsResource = class {
@@ -200,6 +208,23 @@ var DeployResource = class {
200
208
  `/api/v1/deploy/cronjob/${params.id}/resume`
201
209
  );
202
210
  }
211
+ async listRuns(params) {
212
+ this.client._requireAuth();
213
+ return this.client._request(
214
+ "GET",
215
+ `/api/v1/deploy/cronjob/${params.cronjob_id}/runs`,
216
+ {
217
+ query: { first: params.first, cursor: params.cursor }
218
+ }
219
+ );
220
+ }
221
+ async getRunLogs(params) {
222
+ this.client._requireAuth();
223
+ return this.client._request(
224
+ "GET",
225
+ `/api/v1/deploy/cronjob/${params.cronjob_id}/runs/${params.run_id}/logs`
226
+ );
227
+ }
203
228
  };
204
229
 
205
230
  // src/resources/release.ts
@@ -681,16 +706,16 @@ function parseFlag(argv, flag) {
681
706
  return void 0;
682
707
  }
683
708
  function loadConfig(deps) {
684
- const { argv, env, readFile: readFile2, homedir: homedir2 } = deps;
709
+ const { argv, env, readFile: readFile3, homedir: homedir3 } = deps;
685
710
  const profileName = parseFlag(argv, "--profile") || env.ALVA_PROFILE || "default";
686
711
  const baseUrlFlag = parseFlag(argv, "--base-url");
687
712
  const baseUrlEnv = env.ALVA_ENDPOINT;
688
713
  const apiKeyFlag = parseFlag(argv, "--api-key");
689
714
  const apiKeyEnv = env.ALVA_API_KEY;
690
715
  let fileProfile = {};
691
- const path = configPath({ env, homedir: homedir2 });
716
+ const path = configPath({ env, homedir: homedir3 });
692
717
  try {
693
- const raw = readFile2(path);
718
+ const raw = readFile3(path);
694
719
  let config;
695
720
  try {
696
721
  config = readConfigFile(raw);
@@ -710,11 +735,135 @@ function loadConfig(deps) {
710
735
  };
711
736
  }
712
737
 
713
- // src/cli/index.ts
714
- import * as fs from "fs";
738
+ // src/cli/auth.ts
739
+ import * as crypto from "crypto";
740
+ import * as http from "http";
741
+ import { exec } from "child_process";
715
742
  import * as os from "os";
716
743
  import * as fsPromises from "fs/promises";
717
- var CLI_VERSION = true ? "0.1.4" : "dev";
744
+ function generateState() {
745
+ return crypto.randomBytes(32).toString("hex");
746
+ }
747
+ function parseFlags(argv) {
748
+ const flags = {};
749
+ for (let i = 0; i < argv.length; i++) {
750
+ const arg = argv[i];
751
+ if (arg.startsWith("--")) {
752
+ const eqIdx = arg.indexOf("=");
753
+ if (eqIdx !== -1) {
754
+ flags[arg.slice(2, eqIdx)] = arg.slice(eqIdx + 1);
755
+ } else if (i + 1 < argv.length && !argv[i + 1].startsWith("--")) {
756
+ flags[arg.slice(2)] = argv[i + 1];
757
+ i++;
758
+ }
759
+ }
760
+ }
761
+ return flags;
762
+ }
763
+ function defaultOpenBrowser(url) {
764
+ return new Promise((resolve) => {
765
+ const platform = process.platform;
766
+ let cmd;
767
+ if (platform === "darwin") {
768
+ cmd = `open "${url}"`;
769
+ } else if (platform === "win32") {
770
+ cmd = `start "${url}"`;
771
+ } else {
772
+ cmd = `xdg-open "${url}"`;
773
+ }
774
+ exec(cmd, () => {
775
+ resolve();
776
+ });
777
+ });
778
+ }
779
+ function defaultDeps() {
780
+ return {
781
+ generateState,
782
+ openBrowser: defaultOpenBrowser,
783
+ writeConfigDeps: {
784
+ env: process.env,
785
+ homedir: () => os.homedir(),
786
+ mkdir: (path, options) => fsPromises.mkdir(path, options).then(() => void 0),
787
+ writeFile: (path, data, options) => fsPromises.writeFile(path, data, options).then(() => void 0),
788
+ readFile: (path) => fsPromises.readFile(path, "utf-8")
789
+ },
790
+ createServer: (handler) => http.createServer(handler),
791
+ timeout: 12e4,
792
+ log: (msg) => process.stderr.write(msg)
793
+ };
794
+ }
795
+ async function handleAuthLogin(args, deps) {
796
+ const d = { ...defaultDeps(), ...deps };
797
+ const flags = parseFlags(args.slice(1));
798
+ const profileName = flags.profile || "default";
799
+ const authUrl = flags["auth-url"] || "https://alva.ai";
800
+ const timeout = d.timeout ?? 12e4;
801
+ const state = d.generateState();
802
+ return new Promise((resolve, reject) => {
803
+ const server = d.createServer((req, res) => {
804
+ const reqUrl = new URL(req.url ?? "/", "http://127.0.0.1");
805
+ if (reqUrl.pathname !== "/callback") {
806
+ res.writeHead(404);
807
+ res.end("Not found");
808
+ return;
809
+ }
810
+ const callbackState = reqUrl.searchParams.get("state");
811
+ const apiKey = reqUrl.searchParams.get("api_key");
812
+ if (callbackState !== state) {
813
+ res.writeHead(400);
814
+ res.end(
815
+ "<html><body><h1>Error</h1><p>State mismatch. Please try again.</p></body></html>"
816
+ );
817
+ return;
818
+ }
819
+ if (!apiKey) {
820
+ res.writeHead(400);
821
+ res.end(
822
+ "<html><body><h1>Error</h1><p>Missing API key. Please try again.</p></body></html>"
823
+ );
824
+ return;
825
+ }
826
+ res.writeHead(200, { "Content-Type": "text/html" });
827
+ res.end(
828
+ `<html><body style="display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:rgba(246,246,246,1);font-family:system-ui,sans-serif"><div style="text-align:center;display:flex;flex-direction:column;align-items:center;gap:40px"><h1 style="font-size:45px;font-weight:400;line-height:120%;margin:0">Turn Ideas into Live<br>Investing Playbooks in Minutes</h1><p style="font-size:24px;font-weight:400;margin:0">You're all set for Alva.</p></div></body></html>`
829
+ );
830
+ server.close();
831
+ clearTimeout(timer);
832
+ writeConfig({ apiKey }, d.writeConfigDeps, profileName).then(() => {
833
+ resolve({ status: "logged_in", apiKey, profile: profileName });
834
+ }, reject);
835
+ });
836
+ server.on("error", (err) => {
837
+ clearTimeout(timer);
838
+ reject(err);
839
+ });
840
+ server.listen(0, "127.0.0.1", () => {
841
+ const addr = server.address();
842
+ const callbackUrl = `http://127.0.0.1:${addr.port}/callback`;
843
+ const loginUrl = `${authUrl}/authorize?callback_url=${encodeURIComponent(callbackUrl)}&state=${state}`;
844
+ d.log(
845
+ `Opening browser...
846
+ If it doesn't open, visit:
847
+ ${loginUrl}
848
+
849
+ Waiting for login callback...
850
+ `
851
+ );
852
+ d.openBrowser(loginUrl).catch(() => {
853
+ });
854
+ });
855
+ const timer = setTimeout(() => {
856
+ server.close();
857
+ reject(new Error("Login timed out waiting for callback"));
858
+ }, timeout);
859
+ });
860
+ }
861
+
862
+ // src/cli/index.ts
863
+ import * as fs from "fs";
864
+ import * as os2 from "os";
865
+ import * as fsPromises2 from "fs/promises";
866
+ var CLI_VERSION = true ? "0.2.0" : "dev";
718
867
  function isVersionOlderThan(a, b) {
719
868
  const parse = (v) => {
720
869
  if (!v) return null;
@@ -747,6 +896,7 @@ Commands:
747
896
  comments Playbook comments (create, pin, unpin)
748
897
  remix Save playbook remix lineage
749
898
  trading Trading operations (accounts, portfolio, orders, subscriptions, equity-history, risk-rules, subscribe, unsubscribe, execute, update-risk-rules)
899
+ auth Authentication (login via browser)
750
900
  screenshot Capture a web screenshot as PNG
751
901
 
752
902
  Global options:
@@ -790,6 +940,14 @@ Examples:
790
940
  alva configure --api-key alva_abc123 --base-url http://localhost:8080
791
941
  alva configure --profile staging --api-key alva_stg_key --base-url https://api-llm.stg.alva.ai
792
942
  alva --profile staging whoami`,
943
+ auth: `Usage: alva auth <subcommand>
944
+
945
+ Subcommands:
946
+ login Open browser to authenticate and save credentials
947
+
948
+ Examples:
949
+ alva auth login
950
+ alva auth login --profile staging`,
793
951
  whoami: `Usage: alva whoami [--profile <name>]
794
952
 
795
953
  Verify that your credentials are valid by calling the Alva API. Shows your
@@ -877,11 +1035,13 @@ data SDKs, ALFS, HTTP networking, and the Feed SDK.
877
1035
 
878
1036
  Options:
879
1037
  --code <code> Inline JavaScript code to execute
1038
+ --local-file <path> Path to a local file whose contents are sent as code
880
1039
  --entry-path <path> Path to a script file on ALFS (home-relative)
881
1040
  --working-dir <dir> Working directory for require() (inline code only)
882
1041
  --args <json> JSON object passed to require("env").args
883
1042
 
884
- At least one of --code or --entry-path is required.
1043
+ At least one of --code, --local-file, or --entry-path is required.
1044
+ These three options are mutually exclusive.
885
1045
 
886
1046
  Response fields:
887
1047
  result JSON-encoded return value of the script
@@ -908,7 +1068,8 @@ Examples:
908
1068
  alva run --code "1 + 2 + 3;"
909
1069
  alva run --code "JSON.stringify(require('env').args);" --args '{"symbol":"BTC"}'
910
1070
  alva run --entry-path ~/feeds/my-feed/v1/src/index.js
911
- alva run --entry-path ~/tasks/analyze/src/index.js --args '{"symbol":"NVDA","limit":50}'`,
1071
+ alva run --entry-path ~/tasks/analyze/src/index.js --args '{"symbol":"NVDA","limit":50}'
1072
+ alva run --local-file ./my-script.js --args '{"symbol":"BTC"}'`,
912
1073
  deploy: `Usage: alva deploy <subcommand> [options]
913
1074
 
914
1075
  Manage scheduled cronjobs that run your scripts on a cron schedule.
@@ -957,7 +1118,10 @@ Examples:
957
1118
  alva deploy update --id 42 --cron "0 */2 * * *" --no-push-notify
958
1119
  alva deploy pause --id 42
959
1120
  alva deploy resume --id 42
960
- alva deploy delete --id 42`,
1121
+ alva deploy delete --id 42
1122
+ alva deploy runs --id 42
1123
+ alva deploy runs --id 42 --first 10
1124
+ alva deploy run-logs --id 42 --run-id 123`,
961
1125
  release: `Usage: alva release <subcommand> [options]
962
1126
 
963
1127
  Publish feeds and playbooks to the Alva platform. The typical workflow:
@@ -1187,12 +1351,10 @@ Examples:
1187
1351
  alva trading update-risk-rules --max-single-order-value 10000 --max-single-order-enabled true --max-daily-turnover-value 50000 --max-daily-turnover-enabled true --max-daily-orders-value 100 --max-daily-orders-enabled true`
1188
1352
  };
1189
1353
  async function handleConfigure(args, deps) {
1190
- const flags = parseFlags(args.slice(1));
1354
+ const flags = parseFlags2(args.slice(1));
1191
1355
  const apiKey = flags["api-key"];
1192
1356
  if (!apiKey) {
1193
- throw new Error(
1194
- "--api-key is required. Usage: alva configure --api-key <key> [--base-url <url>] [--profile <name>]"
1195
- );
1357
+ throw new CliUsageError("--api-key is required", "configure");
1196
1358
  }
1197
1359
  if (!apiKey.startsWith("alva_")) {
1198
1360
  process.stderr?.write?.(
@@ -1205,10 +1367,10 @@ async function handleConfigure(args, deps) {
1205
1367
  if (baseUrl) configInput.baseUrl = baseUrl;
1206
1368
  const writeDeps = deps ?? {
1207
1369
  env: process.env,
1208
- homedir: () => os.homedir(),
1209
- mkdir: (path, options) => fsPromises.mkdir(path, options).then(() => void 0),
1210
- writeFile: (path, data, options) => fsPromises.writeFile(path, data, options).then(() => void 0),
1211
- readFile: (path) => fsPromises.readFile(path, "utf-8")
1370
+ homedir: () => os2.homedir(),
1371
+ mkdir: (path, options) => fsPromises2.mkdir(path, options).then(() => void 0),
1372
+ writeFile: (path, data, options) => fsPromises2.writeFile(path, data, options).then(() => void 0),
1373
+ readFile: (path) => fsPromises2.readFile(path, "utf-8")
1212
1374
  };
1213
1375
  const result = await writeConfig(configInput, writeDeps, profileName);
1214
1376
  return {
@@ -1226,7 +1388,7 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
1226
1388
  "execute-latest",
1227
1389
  "dry-run"
1228
1390
  ]);
1229
- function parseFlags(argv) {
1391
+ function parseFlags2(argv) {
1230
1392
  const flags = {};
1231
1393
  for (let i = 0; i < argv.length; i++) {
1232
1394
  const arg = argv[i];
@@ -1254,7 +1416,8 @@ function boolFlag(val) {
1254
1416
  function requireFlag(flags, name, command) {
1255
1417
  const val = flags[name];
1256
1418
  if (val === void 0) {
1257
- throw new Error(`--${name} is required for '${command}'`);
1419
+ const group = command.split(" ")[0];
1420
+ throw new CliUsageError(`--${name} is required for '${command}'`, group);
1258
1421
  }
1259
1422
  return val;
1260
1423
  }
@@ -1262,8 +1425,10 @@ function requireNumericFlag(flags, name, command) {
1262
1425
  const val = requireFlag(flags, name, command);
1263
1426
  const n = Number(val);
1264
1427
  if (Number.isNaN(n)) {
1265
- throw new Error(
1266
- `--${name} must be a number for '${command}', got '${val}'`
1428
+ const group = command.split(" ")[0];
1429
+ throw new CliUsageError(
1430
+ `--${name} must be a number for '${command}', got '${val}'`,
1431
+ group
1267
1432
  );
1268
1433
  }
1269
1434
  return n;
@@ -1307,7 +1472,7 @@ async function dispatch(client, args, meta) {
1307
1472
  return result;
1308
1473
  }
1309
1474
  const subcommand = args[1];
1310
- const flags = parseFlags(
1475
+ const flags = parseFlags2(
1311
1476
  args.slice(
1312
1477
  group === "run" || group === "remix" || group === "screenshot" ? 1 : 2
1313
1478
  )
@@ -1318,11 +1483,13 @@ async function dispatch(client, args, meta) {
1318
1483
  }
1319
1484
  switch (group) {
1320
1485
  case "user":
1321
- if (!subcommand) throw new Error("Missing subcommand for user");
1486
+ if (!subcommand)
1487
+ throw new CliUsageError("Missing subcommand for user", "user");
1322
1488
  if (subcommand === "me") return client.user.me();
1323
- throw new Error(`Unknown subcommand: user ${subcommand}`);
1489
+ throw new CliUsageError(`Unknown subcommand: user ${subcommand}`, "user");
1324
1490
  case "fs": {
1325
- if (!subcommand) throw new Error("Missing subcommand for fs");
1491
+ if (!subcommand)
1492
+ throw new CliUsageError("Missing subcommand for fs", "fs");
1326
1493
  switch (subcommand) {
1327
1494
  case "read":
1328
1495
  return client.fs.read({
@@ -1399,18 +1566,33 @@ async function dispatch(client, args, meta) {
1399
1566
  permission: requireFlag(flags, "permission", "fs revoke")
1400
1567
  });
1401
1568
  default:
1402
- throw new Error(`Unknown subcommand: fs ${subcommand}`);
1569
+ throw new CliUsageError(`Unknown subcommand: fs ${subcommand}`, "fs");
1403
1570
  }
1404
1571
  }
1405
- case "run":
1572
+ case "run": {
1573
+ const sourceFlags = ["code", "local-file", "entry-path"].filter(
1574
+ (f) => flags[f] !== void 0
1575
+ );
1576
+ if (sourceFlags.length > 1) {
1577
+ throw new CliUsageError(
1578
+ `--${sourceFlags.join(" and --")} are mutually exclusive`,
1579
+ "run"
1580
+ );
1581
+ }
1582
+ let code = flags["code"];
1583
+ if (flags["local-file"]) {
1584
+ code = fs.readFileSync(flags["local-file"], "utf-8");
1585
+ }
1406
1586
  return client.run.execute({
1407
- code: flags["code"],
1587
+ code,
1408
1588
  entry_path: flags["entry-path"],
1409
1589
  working_dir: flags["working-dir"],
1410
1590
  args: jsonParse(flags["args"])
1411
1591
  });
1592
+ }
1412
1593
  case "deploy": {
1413
- if (!subcommand) throw new Error("Missing subcommand for deploy");
1594
+ if (!subcommand)
1595
+ throw new CliUsageError("Missing subcommand for deploy", "deploy");
1414
1596
  switch (subcommand) {
1415
1597
  case "create":
1416
1598
  return client.deploy.create({
@@ -1449,12 +1631,27 @@ async function dispatch(client, args, meta) {
1449
1631
  return client.deploy.resume({
1450
1632
  id: requireNumericFlag(flags, "id", "deploy resume")
1451
1633
  });
1634
+ case "runs":
1635
+ return client.deploy.listRuns({
1636
+ cronjob_id: requireNumericFlag(flags, "id", "deploy runs"),
1637
+ first: num(flags["first"]),
1638
+ cursor: num(flags["cursor"])
1639
+ });
1640
+ case "run-logs":
1641
+ return client.deploy.getRunLogs({
1642
+ cronjob_id: requireNumericFlag(flags, "id", "deploy run-logs"),
1643
+ run_id: requireNumericFlag(flags, "run-id", "deploy run-logs")
1644
+ });
1452
1645
  default:
1453
- throw new Error(`Unknown subcommand: deploy ${subcommand}`);
1646
+ throw new CliUsageError(
1647
+ `Unknown subcommand: deploy ${subcommand}`,
1648
+ "deploy"
1649
+ );
1454
1650
  }
1455
1651
  }
1456
1652
  case "release": {
1457
- if (!subcommand) throw new Error("Missing subcommand for release");
1653
+ if (!subcommand)
1654
+ throw new CliUsageError("Missing subcommand for release", "release");
1458
1655
  switch (subcommand) {
1459
1656
  case "feed":
1460
1657
  return client.release.feed({
@@ -1493,11 +1690,15 @@ async function dispatch(client, args, meta) {
1493
1690
  changelog: requireFlag(flags, "changelog", "release playbook")
1494
1691
  });
1495
1692
  default:
1496
- throw new Error(`Unknown subcommand: release ${subcommand}`);
1693
+ throw new CliUsageError(
1694
+ `Unknown subcommand: release ${subcommand}`,
1695
+ "release"
1696
+ );
1497
1697
  }
1498
1698
  }
1499
1699
  case "secrets": {
1500
- if (!subcommand) throw new Error("Missing subcommand for secrets");
1700
+ if (!subcommand)
1701
+ throw new CliUsageError("Missing subcommand for secrets", "secrets");
1501
1702
  switch (subcommand) {
1502
1703
  case "create":
1503
1704
  return client.secrets.create({
@@ -1520,11 +1721,15 @@ async function dispatch(client, args, meta) {
1520
1721
  name: requireFlag(flags, "name", "secrets delete")
1521
1722
  });
1522
1723
  default:
1523
- throw new Error(`Unknown subcommand: secrets ${subcommand}`);
1724
+ throw new CliUsageError(
1725
+ `Unknown subcommand: secrets ${subcommand}`,
1726
+ "secrets"
1727
+ );
1524
1728
  }
1525
1729
  }
1526
1730
  case "sdk": {
1527
- if (!subcommand) throw new Error("Missing subcommand for sdk");
1731
+ if (!subcommand)
1732
+ throw new CliUsageError("Missing subcommand for sdk", "sdk");
1528
1733
  switch (subcommand) {
1529
1734
  case "doc":
1530
1735
  return client.sdk.doc({
@@ -1537,11 +1742,15 @@ async function dispatch(client, args, meta) {
1537
1742
  partition: requireFlag(flags, "partition", "sdk partition-summary")
1538
1743
  });
1539
1744
  default:
1540
- throw new Error(`Unknown subcommand: sdk ${subcommand}`);
1745
+ throw new CliUsageError(
1746
+ `Unknown subcommand: sdk ${subcommand}`,
1747
+ "sdk"
1748
+ );
1541
1749
  }
1542
1750
  }
1543
1751
  case "comments": {
1544
- if (!subcommand) throw new Error("Missing subcommand for comments");
1752
+ if (!subcommand)
1753
+ throw new CliUsageError("Missing subcommand for comments", "comments");
1545
1754
  switch (subcommand) {
1546
1755
  case "create":
1547
1756
  return client.comments.create({
@@ -1563,7 +1772,10 @@ async function dispatch(client, args, meta) {
1563
1772
  )
1564
1773
  });
1565
1774
  default:
1566
- throw new Error(`Unknown subcommand: comments ${subcommand}`);
1775
+ throw new CliUsageError(
1776
+ `Unknown subcommand: comments ${subcommand}`,
1777
+ "comments"
1778
+ );
1567
1779
  }
1568
1780
  }
1569
1781
  case "remix":
@@ -1586,7 +1798,8 @@ async function dispatch(client, args, meta) {
1586
1798
  return { written: outFile, bytes: buf.length };
1587
1799
  }
1588
1800
  case "trading": {
1589
- if (!subcommand) throw new Error("Missing subcommand for trading");
1801
+ if (!subcommand)
1802
+ throw new CliUsageError("Missing subcommand for trading", "trading");
1590
1803
  switch (subcommand) {
1591
1804
  case "accounts":
1592
1805
  return client.trading.accounts();
@@ -1687,13 +1900,21 @@ async function dispatch(client, args, meta) {
1687
1900
  }
1688
1901
  });
1689
1902
  default:
1690
- throw new Error(`Unknown subcommand: trading ${subcommand}`);
1903
+ throw new CliUsageError(
1904
+ `Unknown subcommand: trading ${subcommand}`,
1905
+ "trading"
1906
+ );
1907
+ }
1908
+ }
1909
+ case "auth": {
1910
+ const authSub = args[1];
1911
+ if (!authSub || authSub === "--help" || authSub === "-h" || args[2] === "--help" || args[2] === "-h") {
1912
+ return { _help: true, text: COMMAND_HELP.auth };
1691
1913
  }
1914
+ throw new CliUsageError(`Unknown auth subcommand: '${authSub}'`, "auth");
1692
1915
  }
1693
1916
  default:
1694
- throw new Error(
1695
- `Unknown command: '${group}'. Run 'alva --help' to see available commands.`
1696
- );
1917
+ throw new CliUsageError(`Unknown command: '${group}'`);
1697
1918
  }
1698
1919
  }
1699
1920
  async function main() {
@@ -1713,11 +1934,28 @@ async function main() {
1713
1934
  process.stdout.write(JSON.stringify(result2, null, 2) + "\n");
1714
1935
  return;
1715
1936
  }
1937
+ if (rawArgs[0] === "auth") {
1938
+ const authSub = rawArgs[1];
1939
+ if (!authSub || authSub === "--help" || authSub === "-h" || rawArgs[2] === "--help" || rawArgs[2] === "-h") {
1940
+ process.stdout.write(`${COMMAND_HELP.auth}
1941
+ `);
1942
+ return;
1943
+ }
1944
+ if (authSub === "login") {
1945
+ const result2 = await handleAuthLogin(rawArgs);
1946
+ process.stdout.write(`${JSON.stringify(result2, null, 2)}
1947
+ `);
1948
+ return;
1949
+ }
1950
+ process.stdout.write(`${COMMAND_HELP.auth}
1951
+ `);
1952
+ return;
1953
+ }
1716
1954
  const config = loadConfig({
1717
1955
  argv: rawArgs,
1718
1956
  env: process.env,
1719
1957
  readFile: (path) => fs.readFileSync(path, "utf-8"),
1720
- homedir: () => os.homedir()
1958
+ homedir: () => os2.homedir()
1721
1959
  });
1722
1960
  const client = new AlvaClient({
1723
1961
  apiKey: config.apiKey,
@@ -1759,12 +1997,29 @@ async function main() {
1759
1997
  process.stdout.write(JSON.stringify(result, null, 2) + "\n");
1760
1998
  }
1761
1999
  } catch (err) {
1762
- const error = err instanceof AlvaError ? { code: err.code, message: err.message, status: err.status } : {
1763
- code: "CLI_ERROR",
1764
- message: err instanceof Error ? err.message : String(err)
1765
- };
1766
- process.stderr.write(JSON.stringify({ error }, null, 2) + "\n");
1767
- process.exit(1);
2000
+ if (err instanceof CliUsageError) {
2001
+ const help = err.command ? COMMAND_HELP[err.command] : HELP_TEXT;
2002
+ process.stderr.write(`Error: ${err.message}
2003
+ `);
2004
+ if (help) process.stderr.write(`
2005
+ ${help}
2006
+ `);
2007
+ process.exit(1);
2008
+ } else if (err instanceof AlvaError) {
2009
+ const error = {
2010
+ code: err.code,
2011
+ message: err.message,
2012
+ status: err.status
2013
+ };
2014
+ process.stderr.write(`${JSON.stringify({ error }, null, 2)}
2015
+ `);
2016
+ process.exit(1);
2017
+ } else {
2018
+ const message = err instanceof Error ? err.message : String(err);
2019
+ process.stderr.write(`Error: ${message}
2020
+ `);
2021
+ process.exit(1);
2022
+ }
1768
2023
  }
1769
2024
  }
1770
2025
  var isDirectRun = typeof process !== "undefined" && process.argv[1] && (process.argv[1].endsWith("cli.mjs") || process.argv[1].endsWith("cli.js") || process.argv[1].endsWith("/alva") || process.argv[1].endsWith("\\alva"));