@arbidocs/cli 0.3.42 → 0.3.44

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
@@ -3641,7 +3641,7 @@ function getLatestVersion(skipCache = false) {
3641
3641
  }
3642
3642
  }
3643
3643
  function getCurrentVersion() {
3644
- return "0.3.42";
3644
+ return "0.3.44";
3645
3645
  }
3646
3646
  function readChangelog(fromVersion, toVersion) {
3647
3647
  try {
@@ -3694,17 +3694,17 @@ function showChangelog(fromVersion, toVersion) {
3694
3694
  async function checkForUpdates(autoUpdate) {
3695
3695
  try {
3696
3696
  const latest = getLatestVersion();
3697
- if (!latest || latest === "0.3.42") return;
3697
+ if (!latest || latest === "0.3.44") return;
3698
3698
  if (autoUpdate) {
3699
3699
  warn(`
3700
- Your arbi version is out of date (${"0.3.42"} \u2192 ${latest}). Updating...`);
3700
+ Your arbi version is out of date (${"0.3.44"} \u2192 ${latest}). Updating...`);
3701
3701
  child_process.execSync("npm install -g @arbidocs/cli@latest", { stdio: "inherit" });
3702
- showChangelog("0.3.42", latest);
3702
+ showChangelog("0.3.44", latest);
3703
3703
  console.log(`Updated to ${latest}.`);
3704
3704
  } else {
3705
3705
  warn(
3706
3706
  `
3707
- Your arbi version is out of date (${"0.3.42"} \u2192 ${latest}).
3707
+ Your arbi version is out of date (${"0.3.44"} \u2192 ${latest}).
3708
3708
  Run "arbi update" to upgrade, or "arbi update auto" to always stay up to date.`
3709
3709
  );
3710
3710
  }
@@ -3714,9 +3714,9 @@ Run "arbi update" to upgrade, or "arbi update auto" to always stay up to date.`
3714
3714
  function hintUpdateOnError() {
3715
3715
  try {
3716
3716
  const cached = readCache();
3717
- if (cached && cached.latest !== "0.3.42") {
3717
+ if (cached && cached.latest !== "0.3.44") {
3718
3718
  warn(
3719
- `Your arbi version is out of date (${"0.3.42"} \u2192 ${cached.latest}). Run "arbi update".`
3719
+ `Your arbi version is out of date (${"0.3.44"} \u2192 ${cached.latest}). Run "arbi update".`
3720
3720
  );
3721
3721
  }
3722
3722
  } catch {
@@ -4101,14 +4101,29 @@ function registerListenCommand(program2) {
4101
4101
 
4102
4102
  // src/commands/login.ts
4103
4103
  function registerLoginCommand(program2) {
4104
- program2.command("login").description("Log in to ARBI").option("-e, --email <email>", "Email address (or ARBI_EMAIL env var)").option("-p, --password <password>", "Password (or ARBI_PASSWORD env var)").option("-k, --signing-key <key>", "Signing key (base64) for agent recovery login").option("-w, --workspace <id>", "Workspace ID to select after login").option("--sso", "Log in with Auth0 SSO (device flow)").option("--agent <name>", "Agent backend to configure (claude, openclaw)").option("--listen", "Start DM listener after login").action(
4104
+ program2.command("login").description("Log in to ARBI").option("-e, --email <email>", "Email address (or ARBI_EMAIL env var)").option("-p, --password <password>", "Password (or ARBI_PASSWORD env var)").option("-k, --signing-key <key>", "Signing key (base64) for agent recovery login").option("-w, --workspace <id>", "Workspace ID to select after login").option("--sso", "Log in with Auth0 SSO (device flow)").option("--agent <name>", "Agent backend to configure (claude, openclaw)").option("--listen", "Start DM listener after login").option("--json", "Emit a single JSON object on success (scripting)").action(
4105
4105
  (opts) => runAction(async () => {
4106
4106
  const config = store.requireConfig();
4107
- const email = opts.email || process.env.ARBI_EMAIL || await promptInput("Email");
4107
+ const isTty = process.stdin.isTTY;
4108
+ const emailFromFlagOrEnv = opts.email || process.env.ARBI_EMAIL;
4109
+ if (!isTty && !emailFromFlagOrEnv) {
4110
+ const msg = "Email is required when stdin is not a TTY. Use --email <email> or set ARBI_EMAIL.";
4111
+ if (opts.json) console.log(JSON.stringify({ ok: false, error: msg }));
4112
+ else error(msg);
4113
+ process.exit(1);
4114
+ }
4115
+ const passwordFromFlagOrEnv = opts.password || process.env.ARBI_PASSWORD;
4116
+ if (!isTty && !passwordFromFlagOrEnv && !opts.signingKey) {
4117
+ const msg = "Password is required when stdin is not a TTY. Use --password <password> or set ARBI_PASSWORD.";
4118
+ if (opts.json) console.log(JSON.stringify({ ok: false, error: msg }));
4119
+ else error(msg);
4120
+ process.exit(1);
4121
+ }
4122
+ const email = emailFromFlagOrEnv || await promptInput("Email");
4108
4123
  try {
4109
4124
  let ssoPolling = false;
4110
4125
  const { arbi } = opts.signingKey ? await sdk.performSigningKeyLogin(config, email, opts.signingKey, store) : opts.sso ? await (async () => {
4111
- const pw = opts.password || process.env.ARBI_PASSWORD || await promptPassword("Password");
4126
+ const pw = passwordFromFlagOrEnv || await promptPassword("Password");
4112
4127
  const result = await sdk.performSsoDeviceFlowLogin(config, email, pw, store, {
4113
4128
  onUserCode: (userCode, verificationUri) => {
4114
4129
  console.log(`
@@ -4127,9 +4142,10 @@ Open this URL in your browser:
4127
4142
  if (ssoPolling) console.log("\n");
4128
4143
  return result;
4129
4144
  })() : await (async () => {
4130
- const pw = opts.password || process.env.ARBI_PASSWORD || await promptPassword("Password");
4145
+ const pw = passwordFromFlagOrEnv || await promptPassword("Password");
4131
4146
  return sdk.performPasswordLogin(config, email, pw, store);
4132
4147
  })();
4148
+ if (!opts.json) success(`Logged in as ${email}`);
4133
4149
  clearChatSession();
4134
4150
  const { data: workspaces3 } = await arbi.fetch.GET("/v1/user/workspaces");
4135
4151
  const wsList = workspaces3 || [];
@@ -4137,26 +4153,39 @@ Open this URL in your browser:
4137
4153
  const memberWorkspaces = wsList.filter(
4138
4154
  (ws) => ws.users?.some((u) => u.user.email === email)
4139
4155
  );
4156
+ let selectedWorkspace;
4140
4157
  if (memberWorkspaces.length === 0) {
4141
- console.log("No workspaces found. Create one with: arbi workspace create <name>");
4158
+ if (!opts.json) {
4159
+ console.log("No workspaces found. Create one with: arbi workspace create <name>");
4160
+ }
4142
4161
  } else if (opts.workspace) {
4143
4162
  const ws = memberWorkspaces.find((w) => w.external_id === opts.workspace);
4144
4163
  if (!ws) {
4145
- error(`Workspace ${opts.workspace} not found or you don't have access.`);
4164
+ const msg = `Workspace ${opts.workspace} not found or you don't have access.`;
4165
+ if (opts.json) console.log(JSON.stringify({ ok: false, error: msg }));
4166
+ else error(msg);
4146
4167
  process.exit(1);
4147
4168
  }
4148
4169
  updateConfig({ selectedWorkspaceId: ws.external_id });
4149
- success(`Workspace: ${ws.name} (${ref(ws.external_id)})`);
4170
+ selectedWorkspace = { external_id: ws.external_id, name: ws.name };
4171
+ if (!opts.json) success(`Workspace: ${ws.name} (${ref(ws.external_id)})`);
4150
4172
  } else if (memberWorkspaces.length === 1) {
4151
4173
  updateConfig({ selectedWorkspaceId: memberWorkspaces[0].external_id });
4152
- success(
4153
- `Workspace: ${memberWorkspaces[0].name} (${ref(memberWorkspaces[0].external_id)})`
4154
- );
4174
+ selectedWorkspace = {
4175
+ external_id: memberWorkspaces[0].external_id,
4176
+ name: memberWorkspaces[0].name
4177
+ };
4178
+ if (!opts.json)
4179
+ success(
4180
+ `Workspace: ${memberWorkspaces[0].name} (${ref(memberWorkspaces[0].external_id)})`
4181
+ );
4182
+ } else if (opts.json) {
4155
4183
  } else {
4156
4184
  const choices = sdk.formatWorkspaceChoices(memberWorkspaces);
4157
4185
  const selected = await promptSelect("Select workspace", choices);
4158
4186
  updateConfig({ selectedWorkspaceId: selected });
4159
4187
  const ws = memberWorkspaces.find((w) => w.external_id === selected);
4188
+ selectedWorkspace = { external_id: selected, name: ws.name };
4160
4189
  success(`Workspace: ${ws.name} (${ref(selected)})`);
4161
4190
  dim('\nTip: Run "arbi config alias" to use A as a shortcut for "arbi ask"');
4162
4191
  }
@@ -4166,8 +4195,21 @@ Open this URL in your browser:
4166
4195
  await startListening(opts.agent, config);
4167
4196
  }
4168
4197
  }
4198
+ if (opts.json) {
4199
+ console.log(
4200
+ JSON.stringify({
4201
+ ok: true,
4202
+ email,
4203
+ server: config.baseUrl,
4204
+ workspace: selectedWorkspace ?? null,
4205
+ workspaces_available: memberWorkspaces.length
4206
+ })
4207
+ );
4208
+ }
4169
4209
  } catch (err) {
4170
- error(`Login failed: ${formatCliError(err)}`);
4210
+ const msg = formatCliError(err);
4211
+ if (opts.json) console.log(JSON.stringify({ ok: false, error: msg }));
4212
+ else error(`Login failed: ${msg}`);
4171
4213
  process.exit(1);
4172
4214
  } finally {
4173
4215
  await checkForUpdates(getConfig()?.autoUpdate);
@@ -4176,7 +4218,19 @@ Open this URL in your browser:
4176
4218
  );
4177
4219
  }
4178
4220
  var CENTRAL_API_URL = "https://central.arbi.work";
4179
- async function getVerificationCode(email, apiKey) {
4221
+ var RegisterHintError = class extends Error {
4222
+ constructor(message, kind) {
4223
+ super(message);
4224
+ this.kind = kind;
4225
+ this.name = "RegisterHintError";
4226
+ }
4227
+ kind;
4228
+ };
4229
+ function looksLikeAgentEmail(email) {
4230
+ const local = email.split("@")[0] ?? "";
4231
+ return local.toLowerCase().startsWith("agent-");
4232
+ }
4233
+ async function getVerificationCode(email, apiKey, deploymentDomain) {
4180
4234
  const params = new URLSearchParams({ email });
4181
4235
  const res = await fetch(`${CENTRAL_API_URL}/license-management/verify-ci?${params.toString()}`, {
4182
4236
  method: "GET",
@@ -4184,6 +4238,24 @@ async function getVerificationCode(email, apiKey) {
4184
4238
  });
4185
4239
  if (!res.ok) {
4186
4240
  const body = await res.text().catch(() => "");
4241
+ if (res.status === 403 && /agent-\*/i.test(body)) {
4242
+ throw new RegisterHintError(
4243
+ `This SUPPORT_API_KEY is a deployment key that can only register agent-*@${deploymentDomain} emails. Prefix your email with "agent-" (e.g. agent-<id>@${deploymentDomain}) or use a superuser key.`,
4244
+ "agent-email-required"
4245
+ );
4246
+ }
4247
+ if (res.status === 403 && /Invalid API Key/i.test(body)) {
4248
+ throw new RegisterHintError(
4249
+ "SUPPORT_API_KEY was rejected by central. Check the key value.",
4250
+ "bad-api-key"
4251
+ );
4252
+ }
4253
+ if (res.status === 404 && /No verification record/i.test(body)) {
4254
+ throw new RegisterHintError(
4255
+ `No pending verification for ${email}. The email may already be registered \u2014 try: arbi login --email ${email}`,
4256
+ "already-registered"
4257
+ );
4258
+ }
4187
4259
  throw new Error(`Failed to get verification code: ${res.status} ${body}`);
4188
4260
  }
4189
4261
  const data = await res.json();
@@ -4192,7 +4264,7 @@ async function getVerificationCode(email, apiKey) {
4192
4264
  return Array.isArray(words) ? words.join(" ") : String(words);
4193
4265
  }
4194
4266
  function registerRegisterCommand(program2) {
4195
- program2.command("register").description("Register a new ARBI account").option("--non-interactive", "CI/automation mode (requires SUPPORT_API_KEY env var)").option("-e, --email <email>", "Email address (or ARBI_EMAIL env var)").option("-p, --password <password>", "Password (or ARBI_PASSWORD env var)").option("-c, --verification-code <code>", "Verification code (skip prompt)").option("--first-name <name>", "First name").option("--last-name <name>", "Last name").action(
4267
+ program2.command("register").description("Register a new ARBI account").option("--non-interactive", "CI/automation mode (requires SUPPORT_API_KEY env var)").option("-e, --email <email>", "Email address (or ARBI_EMAIL env var)").option("-p, --password <password>", "Password (or ARBI_PASSWORD env var)").option("-c, --verification-code <code>", "Verification code (skip prompt)").option("--first-name <name>", "First name").option("--last-name <name>", "Last name").option("-y, --yes", 'Skip the post-register "Log in now?" confirmation').option("--json", "Emit a single JSON object on success (scripting)").action(
4196
4268
  (opts) => runAction(async () => {
4197
4269
  const config = requireConfig();
4198
4270
  if (opts.nonInteractive) {
@@ -4207,7 +4279,7 @@ async function smartRegister(config, opts) {
4207
4279
  let email = opts.email || process.env.ARBI_EMAIL || await promptInput("Email");
4208
4280
  if ((opts.email || process.env.ARBI_EMAIL) && !email.includes("@")) {
4209
4281
  email = `${email}@${config.deploymentDomain}`;
4210
- console.log(`Using email: ${email}`);
4282
+ if (!opts.json) console.log(`Using email: ${email}`);
4211
4283
  }
4212
4284
  const arbi = client.createArbiClient({
4213
4285
  baseUrl: config.baseUrl,
@@ -4261,16 +4333,22 @@ async function smartRegister(config, opts) {
4261
4333
  firstName,
4262
4334
  lastName
4263
4335
  });
4264
- success(`
4336
+ if (!opts.json) success(`
4265
4337
  Registered successfully as ${email}`);
4266
4338
  } catch (err) {
4267
- error(`Registration failed: ${formatCliError(err)}`);
4339
+ if (opts.json) {
4340
+ console.log(JSON.stringify({ ok: false, stage: "register", error: formatCliError(err) }));
4341
+ } else {
4342
+ error(`Registration failed: ${formatCliError(err)}`);
4343
+ }
4268
4344
  process.exit(1);
4269
4345
  }
4270
4346
  const allFlagsProvided = !!(opts.email || process.env.ARBI_EMAIL) && !!(opts.password || process.env.ARBI_PASSWORD) && !!opts.verificationCode;
4271
- const doLogin = allFlagsProvided || await promptConfirm("Log in now?");
4347
+ const doLogin = allFlagsProvided || opts.yes || await promptConfirm("Log in now?");
4272
4348
  if (doLogin) {
4273
- await loginAfterRegister(config, email, pw);
4349
+ await loginAfterRegister(config, email, pw, { json: opts.json });
4350
+ } else if (opts.json) {
4351
+ console.log(JSON.stringify({ ok: true, email, server: config.baseUrl, logged_in: false }));
4274
4352
  }
4275
4353
  }
4276
4354
  async function nonInteractiveRegister(config, opts) {
@@ -4283,12 +4361,18 @@ async function nonInteractiveRegister(config, opts) {
4283
4361
  }
4284
4362
  if (!email.includes("@")) {
4285
4363
  email = `${email}@${config.deploymentDomain}`;
4286
- console.log(`Using email: ${email}`);
4364
+ if (!opts.json) console.log(`Using email: ${email}`);
4287
4365
  }
4288
4366
  if (!password2) {
4289
4367
  error("Password required. Use --password <password> or set ARBI_PASSWORD");
4290
4368
  process.exit(1);
4291
4369
  }
4370
+ if (supportApiKey && !opts.verificationCode && !looksLikeAgentEmail(email)) {
4371
+ const hint = `Email "${email}" does not start with "agent-". SUPPORT_API_KEY deployment keys only accept agent-*@${config.deploymentDomain} emails. If your key is a superuser key this may still succeed \u2014 proceeding...`;
4372
+ if (!opts.json) {
4373
+ console.error(`Warning: ${hint}`);
4374
+ }
4375
+ }
4292
4376
  const arbi = client.createArbiClient({
4293
4377
  baseUrl: config.baseUrl,
4294
4378
  deploymentDomain: config.deploymentDomain,
@@ -4309,10 +4393,37 @@ async function nonInteractiveRegister(config, opts) {
4309
4393
  body: { email }
4310
4394
  });
4311
4395
  if (verifyResponse.error) {
4312
- error(`verify-email failed: ${JSON.stringify(verifyResponse.error)}`);
4396
+ if (opts.json) {
4397
+ console.log(
4398
+ JSON.stringify({
4399
+ ok: false,
4400
+ stage: "verify-email",
4401
+ error: JSON.stringify(verifyResponse.error)
4402
+ })
4403
+ );
4404
+ } else {
4405
+ error(`verify-email failed: ${JSON.stringify(verifyResponse.error)}`);
4406
+ }
4407
+ process.exit(1);
4408
+ }
4409
+ try {
4410
+ verificationCode = await getVerificationCode(email, supportApiKey, config.deploymentDomain);
4411
+ } catch (err) {
4412
+ const msg = err instanceof Error ? err.message : String(err);
4413
+ if (opts.json) {
4414
+ console.log(
4415
+ JSON.stringify({
4416
+ ok: false,
4417
+ stage: "verify-ci",
4418
+ error: msg,
4419
+ kind: err instanceof RegisterHintError ? err.kind : void 0
4420
+ })
4421
+ );
4422
+ } else {
4423
+ error(`Error: ${msg}`);
4424
+ }
4313
4425
  process.exit(1);
4314
4426
  }
4315
- verificationCode = await getVerificationCode(email, supportApiKey);
4316
4427
  }
4317
4428
  try {
4318
4429
  await arbi.auth.register({
@@ -4322,60 +4433,93 @@ async function nonInteractiveRegister(config, opts) {
4322
4433
  firstName: opts.firstName ?? "Test",
4323
4434
  lastName: opts.lastName ?? "User"
4324
4435
  });
4325
- success(`Registered: ${email}`);
4436
+ if (!opts.json) success(`Registered: ${email}`);
4326
4437
  } catch (err) {
4327
- error(`Registration failed: ${formatCliError(err)}`);
4438
+ if (opts.json) {
4439
+ console.log(JSON.stringify({ ok: false, stage: "register", error: formatCliError(err) }));
4440
+ } else {
4441
+ error(`Registration failed: ${formatCliError(err)}`);
4442
+ }
4328
4443
  process.exit(1);
4329
4444
  }
4330
- await loginAfterRegister(config, email, password2);
4445
+ await loginAfterRegister(config, email, password2, { json: opts.json });
4331
4446
  }
4332
- async function loginAfterRegister(config, email, password2) {
4447
+ async function loginAfterRegister(config, email, password2, { json = false } = {}) {
4333
4448
  try {
4334
4449
  const { arbi, loginResult } = await sdk.performPasswordLogin(config, email, password2, store);
4335
- success(`Logged in as ${email}`);
4450
+ if (!json) success(`Logged in as ${email}`);
4336
4451
  const { data: workspaces3 } = await arbi.fetch.GET("/v1/user/workspaces");
4337
4452
  const wsList = workspaces3 || [];
4338
4453
  updateCompletionCache(wsList);
4339
- const memberWorkspaces = wsList.filter((ws2) => ws2.users?.some((u) => u.user.email === email));
4454
+ const memberWorkspaces = wsList.filter((ws) => ws.users?.some((u) => u.user.email === email));
4455
+ let selectedWorkspace;
4340
4456
  if (memberWorkspaces.length === 0) {
4341
- console.log("Creating your first workspace...");
4457
+ if (!json) console.log("Creating your first workspace...");
4342
4458
  const userProjects = await sdk.projects.listProjects(arbi);
4343
4459
  const defaultProjectExtId = userProjects[0]?.external_id;
4344
4460
  if (!defaultProjectExtId) throw new Error("No projects found for user");
4345
4461
  const encryptedKey = await sdk.generateNewWorkspaceKey(arbi, loginResult.serverSessionKey);
4346
- const ws2 = await sdk.workspaces.createWorkspace(
4462
+ const ws = await sdk.workspaces.createWorkspace(
4347
4463
  arbi,
4348
4464
  "My First Workspace",
4349
4465
  encryptedKey,
4350
4466
  defaultProjectExtId
4351
4467
  );
4352
- updateConfig({ selectedWorkspaceId: ws2.external_id });
4353
- success(`Workspace: ${ws2.name} (${ref(ws2.external_id)})`);
4354
- return;
4355
- }
4356
- if (memberWorkspaces.length === 1) {
4468
+ updateConfig({ selectedWorkspaceId: ws.external_id });
4469
+ selectedWorkspace = { external_id: ws.external_id, name: ws.name };
4470
+ if (!json) success(`Workspace: ${ws.name} (${ref(ws.external_id)})`);
4471
+ } else if (memberWorkspaces.length === 1) {
4357
4472
  updateConfig({ selectedWorkspaceId: memberWorkspaces[0].external_id });
4358
- success(`Workspace: ${memberWorkspaces[0].name} (${ref(memberWorkspaces[0].external_id)})`);
4359
- return;
4473
+ selectedWorkspace = {
4474
+ external_id: memberWorkspaces[0].external_id,
4475
+ name: memberWorkspaces[0].name
4476
+ };
4477
+ if (!json)
4478
+ success(`Workspace: ${memberWorkspaces[0].name} (${ref(memberWorkspaces[0].external_id)})`);
4479
+ } else if (json) {
4480
+ } else {
4481
+ const choices = sdk.formatWorkspaceChoices(memberWorkspaces);
4482
+ const selected = await promptSelect("Select workspace", choices);
4483
+ updateConfig({ selectedWorkspaceId: selected });
4484
+ const ws = memberWorkspaces.find((w) => w.external_id === selected);
4485
+ selectedWorkspace = { external_id: selected, name: ws.name };
4486
+ success(`Workspace: ${ws.name} (${ref(selected)})`);
4487
+ }
4488
+ if (json) {
4489
+ console.log(
4490
+ JSON.stringify({
4491
+ ok: true,
4492
+ email,
4493
+ server: config.baseUrl,
4494
+ logged_in: true,
4495
+ workspace: selectedWorkspace ?? null,
4496
+ workspaces_available: memberWorkspaces.length
4497
+ })
4498
+ );
4360
4499
  }
4361
- const choices = sdk.formatWorkspaceChoices(memberWorkspaces);
4362
- const selected = await promptSelect("Select workspace", choices);
4363
- updateConfig({ selectedWorkspaceId: selected });
4364
- const ws = memberWorkspaces.find((w) => w.external_id === selected);
4365
- success(`Workspace: ${ws.name} (${ref(selected)})`);
4366
4500
  } catch (err) {
4367
- error(`Login failed: ${formatCliError(err)}`);
4368
- error("You can log in later with: arbi login");
4501
+ if (json) {
4502
+ console.log(
4503
+ JSON.stringify({ ok: false, stage: "post-register-login", error: formatCliError(err) })
4504
+ );
4505
+ } else {
4506
+ error(`Login failed: ${formatCliError(err)}`);
4507
+ error("You can log in later with: arbi login");
4508
+ }
4369
4509
  }
4370
4510
  }
4371
4511
 
4372
4512
  // src/commands/logout.ts
4373
4513
  function registerLogoutCommand(program2) {
4374
- program2.command("logout").description("Log out of ARBI").action(() => {
4514
+ program2.command("logout").description("Log out of ARBI").option("--json", "Emit a single JSON object on success (scripting)").action((opts) => {
4375
4515
  deleteCredentials();
4376
4516
  clearChatSession();
4377
4517
  updateConfig({ selectedWorkspaceId: void 0 });
4378
- success("Logged out.");
4518
+ if (opts.json) {
4519
+ console.log(JSON.stringify({ ok: true }));
4520
+ } else {
4521
+ success("Logged out.");
4522
+ }
4379
4523
  });
4380
4524
  }
4381
4525
 
@@ -7766,145 +7910,160 @@ Updated to ${latest}.`);
7766
7910
  success("Auto-update enabled. ARBI CLI will update automatically on login.");
7767
7911
  });
7768
7912
  }
7913
+ function isExitPromptError(err) {
7914
+ return err instanceof Error && err.name === "ExitPromptError";
7915
+ }
7769
7916
  function registerQuickstartCommand(program2) {
7770
7917
  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) => {
7771
- console.log("\nWelcome to ARBI CLI setup!\n");
7772
- const { config, source } = store.resolveConfigWithFallbacks();
7773
- if (url) {
7774
- const domain = new URL(url).hostname;
7775
- config.baseUrl = url.replace(/\/$/, "");
7918
+ try {
7919
+ await runQuickstart(url);
7920
+ } catch (err) {
7921
+ if (isExitPromptError(err)) {
7922
+ console.log("\nSetup cancelled.");
7923
+ process.exit(130);
7924
+ }
7925
+ error(`Quickstart failed: ${sdk.getErrorMessage(err)}`);
7926
+ process.exit(1);
7927
+ }
7928
+ });
7929
+ }
7930
+ async function runQuickstart(url) {
7931
+ console.log("\nWelcome to ARBI CLI setup!\n");
7932
+ const { config, source } = store.resolveConfigWithFallbacks();
7933
+ if (url) {
7934
+ const domain = new URL(url).hostname;
7935
+ config.baseUrl = url.replace(/\/$/, "");
7936
+ config.deploymentDomain = domain;
7937
+ store.saveConfig(config);
7938
+ }
7939
+ const useDetected = await promptConfirm(`Use server ${config.baseUrl}?`, true);
7940
+ if (!useDetected) {
7941
+ const customUrl = await promptInput("Server URL");
7942
+ try {
7943
+ const domain = new URL(customUrl).hostname;
7944
+ config.baseUrl = customUrl.replace(/\/$/, "");
7776
7945
  config.deploymentDomain = domain;
7777
7946
  store.saveConfig(config);
7947
+ } catch {
7948
+ error("Invalid URL");
7949
+ process.exit(1);
7778
7950
  }
7779
- const useDetected = await promptConfirm(`Use server ${config.baseUrl}?`, true);
7780
- if (!useDetected) {
7781
- const customUrl = await promptInput("Server URL");
7782
- try {
7783
- const domain = new URL(customUrl).hostname;
7784
- config.baseUrl = customUrl.replace(/\/$/, "");
7785
- config.deploymentDomain = domain;
7786
- store.saveConfig(config);
7787
- } catch {
7788
- error("Invalid URL");
7789
- process.exit(1);
7790
- }
7791
- } else if (source !== "config") {
7792
- store.saveConfig(config);
7951
+ } else if (source !== "config") {
7952
+ store.saveConfig(config);
7953
+ }
7954
+ dim(`Server: ${config.baseUrl}`);
7955
+ const action = await promptSelect("Do you have an account?", [
7956
+ { name: "Yes, log me in", value: "login" },
7957
+ { name: "No, register a new account", value: "register" }
7958
+ ]);
7959
+ const arbiClient = client.createArbiClient({
7960
+ baseUrl: config.baseUrl,
7961
+ deploymentDomain: config.deploymentDomain,
7962
+ credentials: "omit"
7963
+ });
7964
+ await arbiClient.crypto.initSodium();
7965
+ let email;
7966
+ let password2;
7967
+ if (action === "register") {
7968
+ email = await promptInput("Email");
7969
+ password2 = await promptPassword("Password");
7970
+ const confirmPw = await promptPassword("Confirm password");
7971
+ if (password2 !== confirmPw) {
7972
+ error("Passwords do not match.");
7973
+ process.exit(1);
7793
7974
  }
7794
- dim(`Server: ${config.baseUrl}`);
7795
- const action = await promptSelect("Do you have an account?", [
7796
- { name: "Yes, log me in", value: "login" },
7797
- { name: "No, register a new account", value: "register" }
7975
+ const codeMethod = await promptSelect("Verification method", [
7976
+ { name: "I have an invitation code", value: "code" },
7977
+ { name: "Send me a verification email", value: "email" }
7798
7978
  ]);
7799
- const arbiClient = client.createArbiClient({
7800
- baseUrl: config.baseUrl,
7801
- deploymentDomain: config.deploymentDomain,
7802
- credentials: "omit"
7803
- });
7804
- await arbiClient.crypto.initSodium();
7805
- let email;
7806
- let password2;
7807
- if (action === "register") {
7808
- email = await promptInput("Email");
7809
- password2 = await promptPassword("Password");
7810
- const confirmPw = await promptPassword("Confirm password");
7811
- if (password2 !== confirmPw) {
7812
- error("Passwords do not match.");
7813
- process.exit(1);
7814
- }
7815
- const codeMethod = await promptSelect("Verification method", [
7816
- { name: "I have an invitation code", value: "code" },
7817
- { name: "Send me a verification email", value: "email" }
7818
- ]);
7819
- let verificationCode;
7820
- if (codeMethod === "code") {
7821
- verificationCode = await promptInput("Invitation code");
7822
- } else {
7823
- console.log("Sending verification email...");
7824
- const verifyResponse = await arbiClient.fetch.POST("/v1/user/verify-email", {
7825
- body: { email }
7826
- });
7827
- if (verifyResponse.error) {
7828
- error(`Failed to send verification email: ${JSON.stringify(verifyResponse.error)}`);
7829
- process.exit(1);
7830
- }
7831
- success("Verification email sent. Check your inbox.");
7832
- verificationCode = await promptInput("Verification code");
7833
- }
7834
- try {
7835
- const firstName = await promptInput("First name", false) || "User";
7836
- const lastName = await promptInput("Last name", false) || "";
7837
- await arbiClient.auth.register({
7838
- email,
7839
- password: password2,
7840
- verificationCode,
7841
- firstName,
7842
- lastName
7843
- });
7844
- success(`Registered as ${email}`);
7845
- } catch (err) {
7846
- error(`Registration failed: ${sdk.getErrorMessage(err)}`);
7979
+ let verificationCode;
7980
+ if (codeMethod === "code") {
7981
+ verificationCode = await promptInput("Invitation code");
7982
+ } else {
7983
+ console.log("Sending verification email...");
7984
+ const verifyResponse = await arbiClient.fetch.POST("/v1/user/verify-email", {
7985
+ body: { email }
7986
+ });
7987
+ if (verifyResponse.error) {
7988
+ error(`Failed to send verification email: ${JSON.stringify(verifyResponse.error)}`);
7847
7989
  process.exit(1);
7848
7990
  }
7849
- } else {
7850
- email = await promptInput("Email");
7851
- password2 = await promptPassword("Password");
7991
+ success("Verification email sent. Check your inbox.");
7992
+ verificationCode = await promptInput("Verification code");
7852
7993
  }
7853
7994
  try {
7854
- const { arbi, loginResult } = await sdk.performPasswordLogin(config, email, password2, store);
7855
- success(`Logged in as ${email}`);
7856
- const { data: workspaces3 } = await arbi.fetch.GET("/v1/user/workspaces");
7857
- const wsList = workspaces3 || [];
7858
- const memberWorkspaces = wsList.filter(
7859
- (ws) => ws.users?.some((u) => u.user.email === email)
7995
+ const firstName = await promptInput("First name", false) || "User";
7996
+ const lastName = await promptInput("Last name", false) || "";
7997
+ await arbiClient.auth.register({
7998
+ email,
7999
+ password: password2,
8000
+ verificationCode,
8001
+ firstName,
8002
+ lastName
8003
+ });
8004
+ success(`Registered as ${email}`);
8005
+ } catch (err) {
8006
+ if (isExitPromptError(err)) throw err;
8007
+ error(`Registration failed: ${sdk.getErrorMessage(err)}`);
8008
+ process.exit(1);
8009
+ }
8010
+ } else {
8011
+ email = await promptInput("Email");
8012
+ password2 = await promptPassword("Password");
8013
+ }
8014
+ try {
8015
+ const { arbi, loginResult } = await sdk.performPasswordLogin(config, email, password2, store);
8016
+ success(`Logged in as ${email}`);
8017
+ const { data: workspaces3 } = await arbi.fetch.GET("/v1/user/workspaces");
8018
+ const wsList = workspaces3 || [];
8019
+ const memberWorkspaces = wsList.filter((ws) => ws.users?.some((u) => u.user.email === email));
8020
+ const userProjects = await sdk.projects.listProjects(arbi);
8021
+ const defaultProjectExtId = userProjects[0]?.external_id;
8022
+ if (!defaultProjectExtId) throw new Error("No projects found for user");
8023
+ let workspaceId;
8024
+ let workspaceName;
8025
+ if (memberWorkspaces.length === 0) {
8026
+ console.log("Creating your first workspace...");
8027
+ const encryptedKey = await sdk.generateNewWorkspaceKey(arbi, loginResult.serverSessionKey);
8028
+ const ws = await sdk.workspaces.createWorkspace(
8029
+ arbi,
8030
+ "My Workspace",
8031
+ encryptedKey,
8032
+ defaultProjectExtId
7860
8033
  );
7861
- const userProjects = await sdk.projects.listProjects(arbi);
7862
- const defaultProjectExtId = userProjects[0]?.external_id;
7863
- if (!defaultProjectExtId) throw new Error("No projects found for user");
7864
- let workspaceId;
7865
- let workspaceName;
7866
- if (memberWorkspaces.length === 0) {
7867
- console.log("Creating your first workspace...");
7868
- const encryptedKey = await sdk.generateNewWorkspaceKey(arbi, loginResult.serverSessionKey);
7869
- const ws = await sdk.workspaces.createWorkspace(
7870
- arbi,
7871
- "My Workspace",
7872
- encryptedKey,
7873
- defaultProjectExtId
7874
- );
8034
+ workspaceId = ws.external_id;
8035
+ workspaceName = ws.name;
8036
+ } else {
8037
+ const choices = [
8038
+ ...sdk.formatWorkspaceChoices(memberWorkspaces),
8039
+ { name: "+ Create new workspace", value: "__new__", description: "" }
8040
+ ];
8041
+ const selected = await promptSelect("Select workspace", choices);
8042
+ if (selected === "__new__") {
8043
+ const name = await promptInput("Workspace name", false) || "My Workspace";
8044
+ const encKey = await sdk.generateNewWorkspaceKey(arbi, loginResult.serverSessionKey);
8045
+ const ws = await sdk.workspaces.createWorkspace(arbi, name, encKey, defaultProjectExtId);
7875
8046
  workspaceId = ws.external_id;
7876
8047
  workspaceName = ws.name;
7877
8048
  } else {
7878
- const choices = [
7879
- ...sdk.formatWorkspaceChoices(memberWorkspaces),
7880
- { name: "+ Create new workspace", value: "__new__", description: "" }
7881
- ];
7882
- const selected = await promptSelect("Select workspace", choices);
7883
- if (selected === "__new__") {
7884
- const name = await promptInput("Workspace name", false) || "My Workspace";
7885
- const encKey = await sdk.generateNewWorkspaceKey(arbi, loginResult.serverSessionKey);
7886
- const ws = await sdk.workspaces.createWorkspace(arbi, name, encKey, defaultProjectExtId);
7887
- workspaceId = ws.external_id;
7888
- workspaceName = ws.name;
7889
- } else {
7890
- workspaceId = selected;
7891
- workspaceName = memberWorkspaces.find((w) => w.external_id === selected)?.name || "";
7892
- }
8049
+ workspaceId = selected;
8050
+ workspaceName = memberWorkspaces.find((w) => w.external_id === selected)?.name || "";
7893
8051
  }
7894
- updateConfig({ selectedWorkspaceId: workspaceId });
7895
- console.log("");
7896
- success("Setup complete!");
7897
- console.log("");
7898
- console.log(` Server: ${ref(config.baseUrl)}`);
7899
- console.log(` Account: ${ref(email)}`);
7900
- console.log(` Workspace: ${workspaceName} (${ref(workspaceId)})`);
7901
- console.log("");
7902
- dim('Try: arbi ask "hello"');
7903
- } catch (err) {
7904
- error(`Login failed: ${sdk.getErrorMessage(err)}`);
7905
- process.exit(1);
7906
8052
  }
7907
- });
8053
+ updateConfig({ selectedWorkspaceId: workspaceId });
8054
+ console.log("");
8055
+ success("Setup complete!");
8056
+ console.log("");
8057
+ console.log(` Server: ${ref(config.baseUrl)}`);
8058
+ console.log(` Account: ${ref(email)}`);
8059
+ console.log(` Workspace: ${workspaceName} (${ref(workspaceId)})`);
8060
+ console.log("");
8061
+ dim('Try: arbi ask "hello"');
8062
+ } catch (err) {
8063
+ if (isExitPromptError(err)) throw err;
8064
+ error(`Login failed: ${sdk.getErrorMessage(err)}`);
8065
+ process.exit(1);
8066
+ }
7908
8067
  }
7909
8068
  var CENTRAL_API_URL2 = "https://central.arbi.work";
7910
8069
  var DEFAULT_PASSWORD = "agent-dev-1234";
@@ -8462,7 +8621,7 @@ console.info = (...args) => {
8462
8621
  _origInfo(...args);
8463
8622
  };
8464
8623
  var program = new commander.Command();
8465
- program.name("arbi").description("ARBI CLI \u2014 interact with ARBI from the terminal").version("0.3.42");
8624
+ program.name("arbi").description("ARBI CLI \u2014 interact with ARBI from the terminal").version("0.3.44");
8466
8625
  registerConfigCommand(program);
8467
8626
  registerLoginCommand(program);
8468
8627
  registerRegisterCommand(program);