@arbidocs/cli 0.3.11 → 0.3.13

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.js CHANGED
@@ -5,8 +5,8 @@ var commander = require('commander');
5
5
  var fs = require('fs');
6
6
  var os = require('os');
7
7
  var path = require('path');
8
+ var chalk2 = require('chalk');
8
9
  var sdk = require('@arbidocs/sdk');
9
- var chalk = require('chalk');
10
10
  var prompts = require('@inquirer/prompts');
11
11
  var child_process = require('child_process');
12
12
  var client = require('@arbidocs/client');
@@ -18,7 +18,7 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
18
18
  var fs__default = /*#__PURE__*/_interopDefault(fs);
19
19
  var os__default = /*#__PURE__*/_interopDefault(os);
20
20
  var path__default = /*#__PURE__*/_interopDefault(path);
21
- var chalk__default = /*#__PURE__*/_interopDefault(chalk);
21
+ var chalk2__default = /*#__PURE__*/_interopDefault(chalk2);
22
22
 
23
23
  var store = new sdk.FileConfigStore();
24
24
  function getConfig() {
@@ -38,6 +38,13 @@ function requireConfig() {
38
38
  throw err;
39
39
  }
40
40
  }
41
+ function resolveConfig() {
42
+ const { config, source } = store.resolveConfigWithFallbacks();
43
+ if (source !== "config") {
44
+ console.error(chalk2__default.default.dim(`Using server URL from ${source}: ${config.baseUrl}`));
45
+ }
46
+ return config;
47
+ }
41
48
  function getCredentials() {
42
49
  return store.getCredentials();
43
50
  }
@@ -54,32 +61,32 @@ function clearChatSession() {
54
61
  store.clearChatSession();
55
62
  }
56
63
  function success(msg) {
57
- console.log(chalk__default.default.green(msg));
64
+ console.log(chalk2__default.default.green(msg));
58
65
  }
59
66
  function error(msg) {
60
- console.error(chalk__default.default.red(msg));
67
+ console.error(chalk2__default.default.red(msg));
61
68
  }
62
69
  function warn(msg) {
63
- console.error(chalk__default.default.yellow(msg));
70
+ console.error(chalk2__default.default.yellow(msg));
64
71
  }
65
72
  function label(key, value) {
66
- console.log(`${chalk__default.default.bold(key)} ${value}`);
73
+ console.log(`${chalk2__default.default.bold(key)} ${value}`);
67
74
  }
68
75
  function dim(msg) {
69
- console.log(chalk__default.default.dim(msg));
76
+ console.log(chalk2__default.default.dim(msg));
70
77
  }
71
78
  function bold(msg) {
72
- console.log(chalk__default.default.bold(msg));
79
+ console.log(chalk2__default.default.bold(msg));
73
80
  }
74
81
  function status(s) {
75
82
  const lower = s.toLowerCase();
76
- if (["healthy", "completed", "available", "online", "on"].includes(lower)) return chalk__default.default.green(s);
77
- if (["failed", "error", "unavailable", "offline"].includes(lower)) return chalk__default.default.red(s);
78
- if (["processing", "pending", "degraded", "warning"].includes(lower)) return chalk__default.default.yellow(s);
83
+ if (["healthy", "completed", "available", "online", "on"].includes(lower)) return chalk2__default.default.green(s);
84
+ if (["failed", "error", "unavailable", "offline"].includes(lower)) return chalk2__default.default.red(s);
85
+ if (["processing", "pending", "degraded", "warning"].includes(lower)) return chalk2__default.default.yellow(s);
79
86
  return s;
80
87
  }
81
88
  function ref(s) {
82
- return chalk__default.default.cyan(s);
89
+ return chalk2__default.default.cyan(s);
83
90
  }
84
91
 
85
92
  // src/commands/config-cmd.ts
@@ -3502,7 +3509,7 @@ function getLatestVersion(skipCache = false) {
3502
3509
  }
3503
3510
  }
3504
3511
  function getCurrentVersion() {
3505
- return "0.3.11";
3512
+ return "0.3.13";
3506
3513
  }
3507
3514
  function readChangelog(fromVersion, toVersion) {
3508
3515
  try {
@@ -3555,17 +3562,17 @@ function showChangelog(fromVersion, toVersion) {
3555
3562
  async function checkForUpdates(autoUpdate) {
3556
3563
  try {
3557
3564
  const latest = getLatestVersion();
3558
- if (!latest || latest === "0.3.11") return;
3565
+ if (!latest || latest === "0.3.13") return;
3559
3566
  if (autoUpdate) {
3560
3567
  warn(`
3561
- Your arbi version is out of date (${"0.3.11"} \u2192 ${latest}). Updating...`);
3568
+ Your arbi version is out of date (${"0.3.13"} \u2192 ${latest}). Updating...`);
3562
3569
  child_process.execSync("npm install -g @arbidocs/cli@latest", { stdio: "inherit" });
3563
- showChangelog("0.3.11", latest);
3570
+ showChangelog("0.3.13", latest);
3564
3571
  console.log(`Updated to ${latest}.`);
3565
3572
  } else {
3566
3573
  warn(
3567
3574
  `
3568
- Your arbi version is out of date (${"0.3.11"} \u2192 ${latest}).
3575
+ Your arbi version is out of date (${"0.3.13"} \u2192 ${latest}).
3569
3576
  Run "arbi update" to upgrade, or "arbi update auto" to always stay up to date.`
3570
3577
  );
3571
3578
  }
@@ -3575,9 +3582,9 @@ Run "arbi update" to upgrade, or "arbi update auto" to always stay up to date.`
3575
3582
  function hintUpdateOnError() {
3576
3583
  try {
3577
3584
  const cached = readCache();
3578
- if (cached && cached.latest !== "0.3.11") {
3585
+ if (cached && cached.latest !== "0.3.13") {
3579
3586
  warn(
3580
- `Your arbi version is out of date (${"0.3.11"} \u2192 ${cached.latest}). Run "arbi update".`
3587
+ `Your arbi version is out of date (${"0.3.13"} \u2192 ${cached.latest}). Run "arbi update".`
3581
3588
  );
3582
3589
  }
3583
3590
  } catch {
@@ -3658,7 +3665,11 @@ function registerRegisterCommand(program2) {
3658
3665
  });
3659
3666
  }
3660
3667
  async function smartRegister(config, opts) {
3661
- const email = opts.email || process.env.ARBI_EMAIL || await promptInput("Email");
3668
+ let email = opts.email || process.env.ARBI_EMAIL || await promptInput("Email");
3669
+ if ((opts.email || process.env.ARBI_EMAIL) && !email.includes("@")) {
3670
+ email = `${email}@${config.deploymentDomain}`;
3671
+ console.log(`Using email: ${email}`);
3672
+ }
3662
3673
  const arbi = client.createArbiClient({
3663
3674
  baseUrl: config.baseUrl,
3664
3675
  deploymentDomain: config.deploymentDomain,
@@ -3724,13 +3735,17 @@ Registered successfully as ${email}`);
3724
3735
  }
3725
3736
  }
3726
3737
  async function nonInteractiveRegister(config, opts) {
3727
- const email = opts.email || process.env.ARBI_EMAIL;
3738
+ let email = opts.email || process.env.ARBI_EMAIL;
3728
3739
  const password2 = opts.password || process.env.ARBI_PASSWORD;
3729
3740
  const supportApiKey = process.env.SUPPORT_API_KEY;
3730
3741
  if (!email) {
3731
3742
  error("Email required. Use --email <email> or set ARBI_EMAIL");
3732
3743
  process.exit(1);
3733
3744
  }
3745
+ if (!email.includes("@")) {
3746
+ email = `${email}@${config.deploymentDomain}`;
3747
+ console.log(`Using email: ${email}`);
3748
+ }
3734
3749
  if (!password2) {
3735
3750
  error("Password required. Use --password <password> or set ARBI_PASSWORD");
3736
3751
  process.exit(1);
@@ -3842,9 +3857,9 @@ function timestamp() {
3842
3857
  return (/* @__PURE__ */ new Date()).toLocaleTimeString("en-GB", { hour12: false });
3843
3858
  }
3844
3859
  function colorize(level, text) {
3845
- if (level === "success") return chalk__default.default.green(text);
3846
- if (level === "error") return chalk__default.default.red(text);
3847
- if (level === "warning") return chalk__default.default.yellow(text);
3860
+ if (level === "success") return chalk2__default.default.green(text);
3861
+ if (level === "error") return chalk2__default.default.red(text);
3862
+ if (level === "warning") return chalk2__default.default.yellow(text);
3848
3863
  return text;
3849
3864
  }
3850
3865
  async function startBackgroundNotifications(baseUrl, accessToken) {
@@ -3865,18 +3880,18 @@ ${colorize(level, `[${timestamp()}] ${text}`)}
3865
3880
  onReconnecting: (attempt, maxRetries) => {
3866
3881
  process.stderr.write(
3867
3882
  `
3868
- ${chalk__default.default.yellow(`[${timestamp()}] Reconnecting... (${attempt}/${maxRetries})`)}
3883
+ ${chalk2__default.default.yellow(`[${timestamp()}] Reconnecting... (${attempt}/${maxRetries})`)}
3869
3884
  `
3870
3885
  );
3871
3886
  },
3872
3887
  onReconnected: () => {
3873
3888
  process.stderr.write(`
3874
- ${chalk__default.default.green(`[${timestamp()}] Reconnected`)}
3889
+ ${chalk2__default.default.green(`[${timestamp()}] Reconnected`)}
3875
3890
  `);
3876
3891
  },
3877
3892
  onReconnectFailed: () => {
3878
3893
  process.stderr.write(`
3879
- ${chalk__default.default.red(`[${timestamp()}] Reconnection failed`)}
3894
+ ${chalk2__default.default.red(`[${timestamp()}] Reconnection failed`)}
3880
3895
  `);
3881
3896
  }
3882
3897
  });
@@ -3894,7 +3909,31 @@ process.on("SIGINT", () => {
3894
3909
  });
3895
3910
 
3896
3911
  // src/helpers.ts
3912
+ var CONNECTION_ERROR_HINTS = {
3913
+ ECONNREFUSED: "Connection refused. Is the backend running?",
3914
+ ECONNRESET: "Connection reset by server. The backend may have restarted.",
3915
+ ENOTFOUND: "DNS resolution failed. Check the server URL.",
3916
+ ETIMEDOUT: "Connection timed out. Check network connectivity.",
3917
+ UNABLE_TO_VERIFY_LEAF_SIGNATURE: "TLS certificate cannot be verified. The cert may be expired or self-signed.",
3918
+ CERT_HAS_EXPIRED: "TLS certificate has expired. Renew with manage-deployment.",
3919
+ ERR_TLS_CERT_ALTNAME_INVALID: "TLS certificate hostname mismatch. Check the server URL.",
3920
+ DEPTH_ZERO_SELF_SIGNED_CERT: "Self-signed TLS certificate. The cert may need to be renewed.",
3921
+ SELF_SIGNED_CERT_IN_CHAIN: "Self-signed certificate in chain. The cert may need to be renewed."
3922
+ };
3923
+ function diagnoseConnectionError(err) {
3924
+ const code = sdk.getErrorCode(err);
3925
+ if (code && code in CONNECTION_ERROR_HINTS) {
3926
+ return CONNECTION_ERROR_HINTS[code];
3927
+ }
3928
+ const msg = err instanceof Error ? err.message : "";
3929
+ if (msg === "fetch failed" || msg.includes("fetch failed")) {
3930
+ return "Network error connecting to the server. Run `arbi health` to diagnose.";
3931
+ }
3932
+ return void 0;
3933
+ }
3897
3934
  function formatCliError(err) {
3935
+ const connectionHint = diagnoseConnectionError(err);
3936
+ if (connectionHint) return connectionHint;
3898
3937
  if (err instanceof sdk.ArbiApiError && err.apiError && typeof err.apiError === "object") {
3899
3938
  const base = err.message;
3900
3939
  const apiErr = err.apiError;
@@ -3920,6 +3959,7 @@ function runAction(fn) {
3920
3959
  }
3921
3960
  async function resolveAuth() {
3922
3961
  try {
3962
+ resolveConfig();
3923
3963
  return await sdk.resolveAuth(store);
3924
3964
  } catch (err) {
3925
3965
  if (err instanceof sdk.ArbiError) {
@@ -3931,6 +3971,7 @@ async function resolveAuth() {
3931
3971
  }
3932
3972
  async function resolveWorkspace(workspaceOpt) {
3933
3973
  try {
3974
+ resolveConfig();
3934
3975
  const ctx = await sdk.resolveWorkspace(store, workspaceOpt);
3935
3976
  if (getConfig()?.notifications) {
3936
3977
  startBackgroundNotifications(ctx.config.baseUrl, ctx.accessToken).catch(() => {
@@ -3946,7 +3987,7 @@ async function resolveWorkspace(workspaceOpt) {
3946
3987
  }
3947
3988
  }
3948
3989
  function printTable(columns, rows) {
3949
- console.log(chalk__default.default.bold(columns.map((c) => c.header.padEnd(c.width)).join("")));
3990
+ console.log(chalk2__default.default.bold(columns.map((c) => c.header.padEnd(c.width)).join("")));
3950
3991
  for (const row of rows) {
3951
3992
  console.log(
3952
3993
  columns.map((c) => {
@@ -4234,11 +4275,11 @@ function registerDocsCommand(program2) {
4234
4275
  const reason = raw.error_reason || raw.status_details || raw.error || null;
4235
4276
  const docId = raw.external_id;
4236
4277
  if (reason) {
4237
- console.error(chalk__default.default.red(`
4278
+ console.error(chalk2__default.default.red(`
4238
4279
  \u26A0 ${docId} processing failed: ${reason}`));
4239
4280
  } else {
4240
4281
  console.error(
4241
- chalk__default.default.red(`
4282
+ chalk2__default.default.red(`
4242
4283
  \u26A0 ${docId} processing failed (no error details available)`)
4243
4284
  );
4244
4285
  }
@@ -4326,11 +4367,11 @@ function registerDocsCommand(program2) {
4326
4367
  );
4327
4368
  }
4328
4369
  function registerUploadCommand(program2) {
4329
- program2.command("upload <files...>").description("Upload documents to the active workspace").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").option("-W, --watch", "Watch document processing progress after upload").action(
4330
- (files, opts) => runAction(async () => {
4331
- for (const f of files) {
4332
- if (!fs__default.default.existsSync(f)) {
4333
- error(`File not found: ${f}`);
4370
+ program2.command("upload <paths...>").description("Upload files, directories, or zip archives to the active workspace").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").option("-W, --watch", "Watch document processing progress after upload").action(
4371
+ (paths, opts) => runAction(async () => {
4372
+ for (const p of paths) {
4373
+ if (!fs__default.default.existsSync(p)) {
4374
+ error(`Path not found: ${p}`);
4334
4375
  process.exit(1);
4335
4376
  }
4336
4377
  }
@@ -4339,16 +4380,53 @@ function registerUploadCommand(program2) {
4339
4380
  );
4340
4381
  const uploadedDocs = /* @__PURE__ */ new Map();
4341
4382
  const auth = { baseUrl: config.baseUrl, accessToken, workspaceKeyHeader };
4342
- for (const filePath of files) {
4343
- const result = await sdk.documents.uploadLocalFile(auth, workspaceId, filePath);
4344
- success(`Uploaded: ${result.fileName} (${result.doc_ext_ids.join(", ")})`);
4345
- if (result.duplicates && result.duplicates.length > 0) {
4346
- warn(` Duplicates: ${result.duplicates.join(", ")}`);
4383
+ for (const filePath of paths) {
4384
+ const stat = fs__default.default.statSync(filePath);
4385
+ if (stat.isDirectory()) {
4386
+ const result = await sdk.documentsNode.uploadDirectory(auth, workspaceId, filePath);
4387
+ if (result.doc_ext_ids.length === 0) {
4388
+ warn(`No supported files found in directory: ${filePath}`);
4389
+ continue;
4390
+ }
4391
+ for (const [folder, info] of result.folders) {
4392
+ success(
4393
+ ` ${folder}: ${info.fileCount} file(s) \u2192 ${info.doc_ext_ids.length} uploaded`
4394
+ );
4395
+ if (info.duplicates.length > 0) {
4396
+ warn(` Duplicates: ${info.duplicates.join(", ")}`);
4397
+ }
4398
+ }
4399
+ success(
4400
+ `Uploaded directory: ${filePath} (${result.doc_ext_ids.length} document(s) total)`
4401
+ );
4402
+ for (const id of result.doc_ext_ids) uploadedDocs.set(id, filePath);
4403
+ } else if (filePath.toLowerCase().endsWith(".zip")) {
4404
+ const result = await sdk.documentsNode.uploadZip(auth, workspaceId, filePath);
4405
+ if (result.doc_ext_ids.length === 0) {
4406
+ warn(`No supported files found in zip: ${filePath}`);
4407
+ continue;
4408
+ }
4409
+ for (const [folder, info] of result.folders) {
4410
+ success(
4411
+ ` ${folder}: ${info.fileCount} file(s) \u2192 ${info.doc_ext_ids.length} uploaded`
4412
+ );
4413
+ if (info.duplicates.length > 0) {
4414
+ warn(` Duplicates: ${info.duplicates.join(", ")}`);
4415
+ }
4416
+ }
4417
+ success(`Uploaded zip: ${filePath} (${result.doc_ext_ids.length} document(s) total)`);
4418
+ for (const id of result.doc_ext_ids) uploadedDocs.set(id, filePath);
4419
+ } else {
4420
+ const result = await sdk.documentsNode.uploadLocalFile(auth, workspaceId, filePath);
4421
+ success(`Uploaded: ${result.fileName} (${result.doc_ext_ids.join(", ")})`);
4422
+ if (result.duplicates && result.duplicates.length > 0) {
4423
+ warn(` Duplicates: ${result.duplicates.join(", ")}`);
4424
+ }
4425
+ for (const id of result.doc_ext_ids) uploadedDocs.set(id, result.fileName);
4347
4426
  }
4348
- for (const id of result.doc_ext_ids) uploadedDocs.set(id, result.fileName);
4349
4427
  }
4350
4428
  const isInteractive = process.stdout.isTTY === true;
4351
- const shouldWatch = opts.watch === true || files.length === 1 && isInteractive;
4429
+ const shouldWatch = opts.watch === true || paths.length === 1 && isInteractive;
4352
4430
  if (shouldWatch && uploadedDocs.size > 0) {
4353
4431
  const pending = new Set(uploadedDocs.keys());
4354
4432
  const failed = /* @__PURE__ */ new Map();
@@ -4493,12 +4571,12 @@ function registerAskCommand(program2) {
4493
4571
  onToken: (content) => process.stdout.write(content),
4494
4572
  onAgentStep: (data) => {
4495
4573
  if (opts.verbose) {
4496
- const focus = data.focus || data.step || "";
4497
- console.error(chalk__default.default.dim(`
4498
- [agent] ${focus}`));
4574
+ const label2 = sdk.formatAgentStepLabel(data);
4575
+ if (label2) console.error(chalk2__default.default.dim(`
4576
+ [agent] ${label2}`));
4499
4577
  }
4500
4578
  },
4501
- onError: (message) => console.error(chalk__default.default.red(`
4579
+ onError: (message) => console.error(chalk2__default.default.red(`
4502
4580
  Error: ${message}`))
4503
4581
  });
4504
4582
  process.stdout.write("\n");
@@ -4517,36 +4595,73 @@ Error: ${message}`))
4517
4595
  );
4518
4596
  }
4519
4597
  function colorize2(level, text) {
4520
- if (level === "success") return chalk__default.default.green(text);
4521
- if (level === "error") return chalk__default.default.red(text);
4522
- if (level === "warning") return chalk__default.default.yellow(text);
4598
+ if (level === "success") return chalk2__default.default.green(text);
4599
+ if (level === "error") return chalk2__default.default.red(text);
4600
+ if (level === "warning") return chalk2__default.default.yellow(text);
4523
4601
  return text;
4524
4602
  }
4525
4603
  function registerWatchCommand(program2) {
4526
- program2.command("watch").description("Watch workspace activity in real time").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").action(
4604
+ program2.command("watch").description("Watch workspace activity in real time").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").option("-t, --timeout <seconds>", "Auto-close after N seconds").option("-n, --count <n>", "Stop after N messages").option("--json", "Output NDJSON (one JSON object per line)").action(
4527
4605
  (opts) => runAction(async () => {
4528
4606
  const { config, accessToken, workspaceId } = await resolveWorkspace(opts.workspace);
4529
- console.log(`Watching workspace ${workspaceId}... (Ctrl+C to stop)`);
4607
+ const timeoutSec = opts.timeout ? parseInt(opts.timeout, 10) : void 0;
4608
+ const maxCount = opts.count ? parseInt(opts.count, 10) : void 0;
4609
+ const jsonMode = opts.json ?? false;
4610
+ if (!jsonMode) {
4611
+ const parts = [`Watching workspace ${workspaceId}...`];
4612
+ if (timeoutSec) parts.push(`(timeout: ${timeoutSec}s)`);
4613
+ if (maxCount) parts.push(`(max: ${maxCount} messages)`);
4614
+ parts.push("(Ctrl+C to stop)");
4615
+ console.log(parts.join(" "));
4616
+ }
4617
+ let messageCount = 0;
4530
4618
  let onDone;
4531
4619
  const done = new Promise((r) => {
4532
4620
  onDone = r;
4533
4621
  });
4534
- await sdk.connectWebSocket({
4622
+ const conn = await sdk.connectWebSocket({
4535
4623
  baseUrl: config.baseUrl,
4536
4624
  accessToken,
4537
4625
  onMessage: (msg) => {
4538
- const { text, level } = sdk.formatWsMessage(msg);
4539
- console.log(colorize2(level, text));
4626
+ messageCount++;
4627
+ if (jsonMode) {
4628
+ console.log(JSON.stringify(msg));
4629
+ } else {
4630
+ const { text, level } = sdk.formatWsMessage(msg);
4631
+ console.log(colorize2(level, text));
4632
+ }
4633
+ if (maxCount && messageCount >= maxCount) {
4634
+ if (!jsonMode) console.log(chalk2__default.default.dim(`
4635
+ Reached ${maxCount} messages, closing.`));
4636
+ conn.close();
4637
+ }
4540
4638
  },
4541
4639
  onClose: (code, reason) => {
4542
- console.log(
4543
- chalk__default.default.yellow(`
4640
+ if (!jsonMode) {
4641
+ console.log(
4642
+ chalk2__default.default.yellow(`
4544
4643
  Connection closed (code ${code}${reason ? ": " + reason : ""})`)
4545
- );
4644
+ );
4645
+ }
4546
4646
  onDone();
4547
4647
  }
4548
4648
  });
4649
+ let timer;
4650
+ if (timeoutSec) {
4651
+ timer = setTimeout(() => {
4652
+ if (!jsonMode) console.log(chalk2__default.default.dim(`
4653
+ Timeout (${timeoutSec}s), closing.`));
4654
+ conn.close();
4655
+ }, timeoutSec * 1e3);
4656
+ }
4657
+ const sigintHandler = () => {
4658
+ if (timer) clearTimeout(timer);
4659
+ conn.close();
4660
+ };
4661
+ process.on("SIGINT", sigintHandler);
4549
4662
  await done;
4663
+ if (timer) clearTimeout(timer);
4664
+ process.removeListener("SIGINT", sigintHandler);
4550
4665
  })()
4551
4666
  );
4552
4667
  }
@@ -5373,6 +5488,229 @@ Updated to ${latest}.`);
5373
5488
  success("Auto-update enabled. ARBI CLI will update automatically on login.");
5374
5489
  });
5375
5490
  }
5491
+ function registerQuickstartCommand(program2) {
5492
+ program2.command("quickstart").description("Interactive setup wizard \u2014 configure, register/login, and select a workspace").argument("[url]", "Server URL (auto-detected if omitted)").action(async (url) => {
5493
+ console.log("\nWelcome to ARBI CLI setup!\n");
5494
+ const { config, source } = store.resolveConfigWithFallbacks();
5495
+ if (url) {
5496
+ const domain = new URL(url).hostname;
5497
+ config.baseUrl = url.replace(/\/$/, "");
5498
+ config.deploymentDomain = domain;
5499
+ store.saveConfig(config);
5500
+ }
5501
+ const useDetected = await promptConfirm(`Use server ${config.baseUrl}?`, true);
5502
+ if (!useDetected) {
5503
+ const customUrl = await promptInput("Server URL");
5504
+ try {
5505
+ const domain = new URL(customUrl).hostname;
5506
+ config.baseUrl = customUrl.replace(/\/$/, "");
5507
+ config.deploymentDomain = domain;
5508
+ store.saveConfig(config);
5509
+ } catch {
5510
+ error("Invalid URL");
5511
+ process.exit(1);
5512
+ }
5513
+ } else if (source !== "config") {
5514
+ store.saveConfig(config);
5515
+ }
5516
+ dim(`Server: ${config.baseUrl}`);
5517
+ const action = await promptSelect("Do you have an account?", [
5518
+ { name: "Yes, log me in", value: "login" },
5519
+ { name: "No, register a new account", value: "register" }
5520
+ ]);
5521
+ const arbiClient = client.createArbiClient({
5522
+ baseUrl: config.baseUrl,
5523
+ deploymentDomain: config.deploymentDomain,
5524
+ credentials: "omit"
5525
+ });
5526
+ await arbiClient.crypto.initSodium();
5527
+ let email;
5528
+ let password2;
5529
+ if (action === "register") {
5530
+ email = await promptInput("Email");
5531
+ password2 = await promptPassword("Password");
5532
+ const confirmPw = await promptPassword("Confirm password");
5533
+ if (password2 !== confirmPw) {
5534
+ error("Passwords do not match.");
5535
+ process.exit(1);
5536
+ }
5537
+ const codeMethod = await promptSelect("Verification method", [
5538
+ { name: "I have an invitation code", value: "code" },
5539
+ { name: "Send me a verification email", value: "email" }
5540
+ ]);
5541
+ let verificationCode;
5542
+ if (codeMethod === "code") {
5543
+ verificationCode = await promptInput("Invitation code");
5544
+ } else {
5545
+ console.log("Sending verification email...");
5546
+ const verifyResponse = await arbiClient.fetch.POST("/v1/user/verify-email", {
5547
+ body: { email }
5548
+ });
5549
+ if (verifyResponse.error) {
5550
+ error(`Failed to send verification email: ${JSON.stringify(verifyResponse.error)}`);
5551
+ process.exit(1);
5552
+ }
5553
+ success("Verification email sent. Check your inbox.");
5554
+ verificationCode = await promptInput("Verification code");
5555
+ }
5556
+ try {
5557
+ const firstName = await promptInput("First name", false) || "User";
5558
+ const lastName = await promptInput("Last name", false) || "";
5559
+ await arbiClient.auth.register({
5560
+ email,
5561
+ password: password2,
5562
+ verificationCode,
5563
+ firstName,
5564
+ lastName
5565
+ });
5566
+ success(`Registered as ${email}`);
5567
+ } catch (err) {
5568
+ error(`Registration failed: ${sdk.getErrorMessage(err)}`);
5569
+ process.exit(1);
5570
+ }
5571
+ } else {
5572
+ email = await promptInput("Email");
5573
+ password2 = await promptPassword("Password");
5574
+ }
5575
+ try {
5576
+ const { arbi } = await sdk.performPasswordLogin(config, email, password2, store);
5577
+ success(`Logged in as ${email}`);
5578
+ const { data: workspaces2 } = await arbi.fetch.GET("/v1/user/workspaces");
5579
+ const wsList = workspaces2 || [];
5580
+ const memberWorkspaces = wsList.filter((ws) => ws.users?.some((u) => u.email === email));
5581
+ let workspaceId;
5582
+ let workspaceName;
5583
+ if (memberWorkspaces.length === 0) {
5584
+ console.log("Creating your first workspace...");
5585
+ const ws = await sdk.workspaces.createWorkspace(arbi, "My Workspace");
5586
+ workspaceId = ws.external_id;
5587
+ workspaceName = ws.name;
5588
+ } else {
5589
+ const choices = [
5590
+ ...sdk.formatWorkspaceChoices(memberWorkspaces),
5591
+ { name: "+ Create new workspace", value: "__new__", description: "" }
5592
+ ];
5593
+ const selected = await promptSelect("Select workspace", choices);
5594
+ if (selected === "__new__") {
5595
+ const name = await promptInput("Workspace name", false) || "My Workspace";
5596
+ const ws = await sdk.workspaces.createWorkspace(arbi, name);
5597
+ workspaceId = ws.external_id;
5598
+ workspaceName = ws.name;
5599
+ } else {
5600
+ workspaceId = selected;
5601
+ workspaceName = memberWorkspaces.find((w) => w.external_id === selected)?.name || "";
5602
+ }
5603
+ }
5604
+ updateConfig({ selectedWorkspaceId: workspaceId });
5605
+ console.log("");
5606
+ success("Setup complete!");
5607
+ console.log("");
5608
+ console.log(` Server: ${ref(config.baseUrl)}`);
5609
+ console.log(` Account: ${ref(email)}`);
5610
+ console.log(` Workspace: ${workspaceName} (${ref(workspaceId)})`);
5611
+ console.log("");
5612
+ dim('Try: arbi ask "hello"');
5613
+ } catch (err) {
5614
+ error(`Login failed: ${sdk.getErrorMessage(err)}`);
5615
+ process.exit(1);
5616
+ }
5617
+ });
5618
+ }
5619
+ var CENTRAL_API_URL2 = "https://central.arbi.work";
5620
+ var DEFAULT_PASSWORD = "agent-dev-1234";
5621
+ async function getVerificationCode2(email, apiKey) {
5622
+ const params = new URLSearchParams({ email });
5623
+ const res = await fetch(`${CENTRAL_API_URL2}/license-management/verify-ci?${params.toString()}`, {
5624
+ method: "GET",
5625
+ headers: { "x-api-key": apiKey }
5626
+ });
5627
+ if (!res.ok) {
5628
+ const body = await res.text().catch(() => "");
5629
+ throw new Error(`Failed to get verification code: ${res.status} ${body}`);
5630
+ }
5631
+ const data = await res.json();
5632
+ const words = data?.verification_words ?? data?.verification_code ?? null;
5633
+ if (!words) throw new Error("No verification code in response");
5634
+ return Array.isArray(words) ? words.join(" ") : String(words);
5635
+ }
5636
+ function registerAgentCreateCommand(program2) {
5637
+ program2.command("agent-create").description("Create a bot/test account (requires SUPPORT_API_KEY)").argument("[url]", "Server URL (auto-detected if omitted)").option("-p, --password <password>", "Account password", DEFAULT_PASSWORD).option("--workspace-name <name>", "Workspace name", "Agent Workspace").option("--email <email>", "Custom email (default: agent-{timestamp}@{domain})").action(
5638
+ async (url, opts) => {
5639
+ const { config, source } = store.resolveConfigWithFallbacks();
5640
+ if (url) {
5641
+ const domain = new URL(url).hostname;
5642
+ config.baseUrl = url.replace(/\/$/, "");
5643
+ config.deploymentDomain = domain;
5644
+ store.saveConfig(config);
5645
+ dim(`Server: ${config.baseUrl}`);
5646
+ } else {
5647
+ dim(`Server: ${config.baseUrl} (from ${source})`);
5648
+ }
5649
+ const supportApiKey = process.env.SUPPORT_API_KEY;
5650
+ if (!supportApiKey) {
5651
+ error(
5652
+ "SUPPORT_API_KEY is required.\nSet it with: export SUPPORT_API_KEY=<key>\nOr source from .env: source .env && arbi agent-create"
5653
+ );
5654
+ process.exit(1);
5655
+ }
5656
+ const timestamp2 = Date.now();
5657
+ let email = opts.email || `agent-${timestamp2}@${config.deploymentDomain}`;
5658
+ if (!email.includes("@")) {
5659
+ email = `${email}@${config.deploymentDomain}`;
5660
+ }
5661
+ dim(`Email: ${email}`);
5662
+ const arbiClient = client.createArbiClient({
5663
+ baseUrl: config.baseUrl,
5664
+ deploymentDomain: config.deploymentDomain,
5665
+ credentials: "omit"
5666
+ });
5667
+ await arbiClient.crypto.initSodium();
5668
+ const verifyResponse = await arbiClient.fetch.POST("/v1/user/verify-email", {
5669
+ body: { email }
5670
+ });
5671
+ if (verifyResponse.error) {
5672
+ error(`verify-email failed: ${JSON.stringify(verifyResponse.error)}`);
5673
+ process.exit(1);
5674
+ }
5675
+ let verificationCode;
5676
+ try {
5677
+ verificationCode = await getVerificationCode2(email, supportApiKey);
5678
+ } catch (err) {
5679
+ error(`Failed to get verification code: ${sdk.getErrorMessage(err)}`);
5680
+ process.exit(1);
5681
+ }
5682
+ try {
5683
+ await arbiClient.auth.register({
5684
+ email,
5685
+ password: opts.password,
5686
+ verificationCode,
5687
+ firstName: "Agent",
5688
+ lastName: `${timestamp2}`
5689
+ });
5690
+ } catch (err) {
5691
+ error(`Registration failed: ${sdk.getErrorMessage(err)}`);
5692
+ process.exit(1);
5693
+ }
5694
+ try {
5695
+ const { arbi } = await sdk.performPasswordLogin(config, email, opts.password, store);
5696
+ const ws = await sdk.workspaces.createWorkspace(arbi, opts.workspaceName);
5697
+ updateConfig({ selectedWorkspaceId: ws.external_id });
5698
+ console.log("");
5699
+ success("Agent account created!");
5700
+ console.log("");
5701
+ console.log(` Email: ${ref(email)}`);
5702
+ console.log(` Password: ${ref(opts.password)}`);
5703
+ console.log(` Workspace: ${ws.name} (${ref(ws.external_id)})`);
5704
+ console.log(` Server: ${ref(config.baseUrl)}`);
5705
+ console.log("");
5706
+ dim('Ready to use: arbi ask "hello"');
5707
+ } catch (err) {
5708
+ error(`Post-registration setup failed: ${sdk.getErrorMessage(err)}`);
5709
+ process.exit(1);
5710
+ }
5711
+ }
5712
+ );
5713
+ }
5376
5714
 
5377
5715
  // src/index.ts
5378
5716
  console.debug = () => {
@@ -5383,7 +5721,7 @@ console.info = (...args) => {
5383
5721
  _origInfo(...args);
5384
5722
  };
5385
5723
  var program = new commander.Command();
5386
- program.name("arbi").description("ARBI CLI \u2014 interact with ARBI from the terminal").version("0.3.11");
5724
+ program.name("arbi").description("ARBI CLI \u2014 interact with ARBI from the terminal").version("0.3.13");
5387
5725
  registerConfigCommand(program);
5388
5726
  registerLoginCommand(program);
5389
5727
  registerRegisterCommand(program);
@@ -5405,6 +5743,8 @@ registerAgentconfigCommand(program);
5405
5743
  registerHealthCommand(program);
5406
5744
  registerTuiCommand(program);
5407
5745
  registerUpdateCommand(program);
5746
+ registerQuickstartCommand(program);
5747
+ registerAgentCreateCommand(program);
5408
5748
  program.parse();
5409
5749
  //# sourceMappingURL=index.js.map
5410
5750
  //# sourceMappingURL=index.js.map