@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/CHANGELOG.md +12 -0
- package/SKILL.md +13 -1
- package/dist/index.js +334 -175
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
3717
|
+
if (cached && cached.latest !== "0.3.44") {
|
|
3718
3718
|
warn(
|
|
3719
|
-
`Your arbi version is out of date (${"0.3.
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4153
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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((
|
|
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
|
|
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:
|
|
4353
|
-
|
|
4354
|
-
|
|
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
|
-
|
|
4359
|
-
|
|
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
|
-
|
|
4368
|
-
|
|
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
|
-
|
|
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
|
-
|
|
7772
|
-
|
|
7773
|
-
|
|
7774
|
-
|
|
7775
|
-
|
|
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
|
-
|
|
7780
|
-
|
|
7781
|
-
|
|
7782
|
-
|
|
7783
|
-
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
|
|
7787
|
-
|
|
7788
|
-
|
|
7789
|
-
|
|
7790
|
-
|
|
7791
|
-
|
|
7792
|
-
|
|
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
|
-
|
|
7795
|
-
|
|
7796
|
-
{ name: "
|
|
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
|
-
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
|
|
7804
|
-
|
|
7805
|
-
|
|
7806
|
-
|
|
7807
|
-
|
|
7808
|
-
|
|
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
|
-
|
|
7850
|
-
|
|
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
|
|
7855
|
-
|
|
7856
|
-
|
|
7857
|
-
|
|
7858
|
-
|
|
7859
|
-
|
|
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
|
-
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
|
|
7865
|
-
|
|
7866
|
-
|
|
7867
|
-
|
|
7868
|
-
|
|
7869
|
-
|
|
7870
|
-
|
|
7871
|
-
|
|
7872
|
-
|
|
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
|
-
|
|
7879
|
-
|
|
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.
|
|
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);
|