@arbidocs/cli 0.3.10 → 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/CHANGELOG.md +8 -0
- package/dist/index.js +510 -100
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
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
|
|
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(
|
|
64
|
+
console.log(chalk2__default.default.green(msg));
|
|
58
65
|
}
|
|
59
66
|
function error(msg) {
|
|
60
|
-
console.error(
|
|
67
|
+
console.error(chalk2__default.default.red(msg));
|
|
61
68
|
}
|
|
62
69
|
function warn(msg) {
|
|
63
|
-
console.error(
|
|
70
|
+
console.error(chalk2__default.default.yellow(msg));
|
|
64
71
|
}
|
|
65
72
|
function label(key, value) {
|
|
66
|
-
console.log(`${
|
|
73
|
+
console.log(`${chalk2__default.default.bold(key)} ${value}`);
|
|
67
74
|
}
|
|
68
75
|
function dim(msg) {
|
|
69
|
-
console.log(
|
|
76
|
+
console.log(chalk2__default.default.dim(msg));
|
|
70
77
|
}
|
|
71
78
|
function bold(msg) {
|
|
72
|
-
console.log(
|
|
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
|
|
77
|
-
if (["failed", "error", "unavailable", "offline"].includes(lower)) return
|
|
78
|
-
if (["processing", "pending", "degraded", "warning"].includes(lower)) return
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
3585
|
+
if (cached && cached.latest !== "0.3.13") {
|
|
3579
3586
|
warn(
|
|
3580
|
-
`Your arbi version is out of date (${"0.3.
|
|
3587
|
+
`Your arbi version is out of date (${"0.3.13"} \u2192 ${cached.latest}). Run "arbi update".`
|
|
3581
3588
|
);
|
|
3582
3589
|
}
|
|
3583
3590
|
} catch {
|
|
@@ -3595,30 +3602,32 @@ function registerLoginCommand(program2) {
|
|
|
3595
3602
|
clearChatSession();
|
|
3596
3603
|
const { data: workspaces2 } = await arbi.fetch.GET("/v1/user/workspaces");
|
|
3597
3604
|
const wsList = workspaces2 || [];
|
|
3598
|
-
|
|
3599
|
-
if (
|
|
3600
|
-
console.log("No workspaces found.");
|
|
3605
|
+
const memberWorkspaces = wsList.filter((ws2) => ws2.users?.some((u) => u.email === email));
|
|
3606
|
+
if (memberWorkspaces.length === 0) {
|
|
3607
|
+
console.log("No workspaces found. Create one with: arbi workspace create <name>");
|
|
3601
3608
|
return;
|
|
3602
3609
|
}
|
|
3603
3610
|
if (opts.workspace) {
|
|
3604
|
-
const ws2 =
|
|
3611
|
+
const ws2 = memberWorkspaces.find((w) => w.external_id === opts.workspace);
|
|
3605
3612
|
if (!ws2) {
|
|
3606
|
-
error(`Workspace ${opts.workspace} not found.`);
|
|
3613
|
+
error(`Workspace ${opts.workspace} not found or you don't have access.`);
|
|
3607
3614
|
process.exit(1);
|
|
3608
3615
|
}
|
|
3609
3616
|
updateConfig({ selectedWorkspaceId: ws2.external_id });
|
|
3610
3617
|
success(`Workspace: ${ws2.name} (${ref(ws2.external_id)})`);
|
|
3611
3618
|
return;
|
|
3612
3619
|
}
|
|
3613
|
-
if (
|
|
3614
|
-
updateConfig({ selectedWorkspaceId:
|
|
3615
|
-
success(
|
|
3620
|
+
if (memberWorkspaces.length === 1) {
|
|
3621
|
+
updateConfig({ selectedWorkspaceId: memberWorkspaces[0].external_id });
|
|
3622
|
+
success(
|
|
3623
|
+
`Workspace: ${memberWorkspaces[0].name} (${ref(memberWorkspaces[0].external_id)})`
|
|
3624
|
+
);
|
|
3616
3625
|
return;
|
|
3617
3626
|
}
|
|
3618
|
-
const choices = sdk.formatWorkspaceChoices(
|
|
3627
|
+
const choices = sdk.formatWorkspaceChoices(memberWorkspaces);
|
|
3619
3628
|
const selected = await promptSelect("Select workspace", choices);
|
|
3620
3629
|
updateConfig({ selectedWorkspaceId: selected });
|
|
3621
|
-
const ws =
|
|
3630
|
+
const ws = memberWorkspaces.find((w) => w.external_id === selected);
|
|
3622
3631
|
success(`Workspace: ${ws.name} (${ref(selected)})`);
|
|
3623
3632
|
dim('\nTip: Run "arbi config alias" to use A as a shortcut for "arbi ask"');
|
|
3624
3633
|
} catch (err) {
|
|
@@ -3656,7 +3665,11 @@ function registerRegisterCommand(program2) {
|
|
|
3656
3665
|
});
|
|
3657
3666
|
}
|
|
3658
3667
|
async function smartRegister(config, opts) {
|
|
3659
|
-
|
|
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
|
+
}
|
|
3660
3673
|
const arbi = client.createArbiClient({
|
|
3661
3674
|
baseUrl: config.baseUrl,
|
|
3662
3675
|
deploymentDomain: config.deploymentDomain,
|
|
@@ -3722,13 +3735,17 @@ Registered successfully as ${email}`);
|
|
|
3722
3735
|
}
|
|
3723
3736
|
}
|
|
3724
3737
|
async function nonInteractiveRegister(config, opts) {
|
|
3725
|
-
|
|
3738
|
+
let email = opts.email || process.env.ARBI_EMAIL;
|
|
3726
3739
|
const password2 = opts.password || process.env.ARBI_PASSWORD;
|
|
3727
3740
|
const supportApiKey = process.env.SUPPORT_API_KEY;
|
|
3728
3741
|
if (!email) {
|
|
3729
3742
|
error("Email required. Use --email <email> or set ARBI_EMAIL");
|
|
3730
3743
|
process.exit(1);
|
|
3731
3744
|
}
|
|
3745
|
+
if (!email.includes("@")) {
|
|
3746
|
+
email = `${email}@${config.deploymentDomain}`;
|
|
3747
|
+
console.log(`Using email: ${email}`);
|
|
3748
|
+
}
|
|
3732
3749
|
if (!password2) {
|
|
3733
3750
|
error("Password required. Use --password <password> or set ARBI_PASSWORD");
|
|
3734
3751
|
process.exit(1);
|
|
@@ -3771,6 +3788,7 @@ async function nonInteractiveRegister(config, opts) {
|
|
|
3771
3788
|
error(`Registration failed: ${sdk.getErrorMessage(err)}`);
|
|
3772
3789
|
process.exit(1);
|
|
3773
3790
|
}
|
|
3791
|
+
await loginAfterRegister(config, email, password2);
|
|
3774
3792
|
}
|
|
3775
3793
|
async function loginAfterRegister(config, email, password2) {
|
|
3776
3794
|
try {
|
|
@@ -3778,22 +3796,23 @@ async function loginAfterRegister(config, email, password2) {
|
|
|
3778
3796
|
success(`Logged in as ${email}`);
|
|
3779
3797
|
const { data: workspaces2 } = await arbi.fetch.GET("/v1/user/workspaces");
|
|
3780
3798
|
const wsList = workspaces2 || [];
|
|
3781
|
-
|
|
3799
|
+
const memberWorkspaces = wsList.filter((ws2) => ws2.users?.some((u) => u.email === email));
|
|
3800
|
+
if (memberWorkspaces.length === 0) {
|
|
3782
3801
|
console.log("Creating your first workspace...");
|
|
3783
3802
|
const ws2 = await sdk.workspaces.createWorkspace(arbi, "My First Workspace");
|
|
3784
3803
|
updateConfig({ selectedWorkspaceId: ws2.external_id });
|
|
3785
3804
|
success(`Workspace: ${ws2.name} (${ref(ws2.external_id)})`);
|
|
3786
3805
|
return;
|
|
3787
3806
|
}
|
|
3788
|
-
if (
|
|
3789
|
-
updateConfig({ selectedWorkspaceId:
|
|
3790
|
-
success(`Workspace: ${
|
|
3807
|
+
if (memberWorkspaces.length === 1) {
|
|
3808
|
+
updateConfig({ selectedWorkspaceId: memberWorkspaces[0].external_id });
|
|
3809
|
+
success(`Workspace: ${memberWorkspaces[0].name} (${ref(memberWorkspaces[0].external_id)})`);
|
|
3791
3810
|
return;
|
|
3792
3811
|
}
|
|
3793
|
-
const choices = sdk.formatWorkspaceChoices(
|
|
3812
|
+
const choices = sdk.formatWorkspaceChoices(memberWorkspaces);
|
|
3794
3813
|
const selected = await promptSelect("Select workspace", choices);
|
|
3795
3814
|
updateConfig({ selectedWorkspaceId: selected });
|
|
3796
|
-
const ws =
|
|
3815
|
+
const ws = memberWorkspaces.find((w) => w.external_id === selected);
|
|
3797
3816
|
success(`Workspace: ${ws.name} (${ref(selected)})`);
|
|
3798
3817
|
} catch (err) {
|
|
3799
3818
|
error(`Login failed: ${sdk.getErrorMessage(err)}`);
|
|
@@ -3838,9 +3857,9 @@ function timestamp() {
|
|
|
3838
3857
|
return (/* @__PURE__ */ new Date()).toLocaleTimeString("en-GB", { hour12: false });
|
|
3839
3858
|
}
|
|
3840
3859
|
function colorize(level, text) {
|
|
3841
|
-
if (level === "success") return
|
|
3842
|
-
if (level === "error") return
|
|
3843
|
-
if (level === "warning") return
|
|
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);
|
|
3844
3863
|
return text;
|
|
3845
3864
|
}
|
|
3846
3865
|
async function startBackgroundNotifications(baseUrl, accessToken) {
|
|
@@ -3861,18 +3880,18 @@ ${colorize(level, `[${timestamp()}] ${text}`)}
|
|
|
3861
3880
|
onReconnecting: (attempt, maxRetries) => {
|
|
3862
3881
|
process.stderr.write(
|
|
3863
3882
|
`
|
|
3864
|
-
${
|
|
3883
|
+
${chalk2__default.default.yellow(`[${timestamp()}] Reconnecting... (${attempt}/${maxRetries})`)}
|
|
3865
3884
|
`
|
|
3866
3885
|
);
|
|
3867
3886
|
},
|
|
3868
3887
|
onReconnected: () => {
|
|
3869
3888
|
process.stderr.write(`
|
|
3870
|
-
${
|
|
3889
|
+
${chalk2__default.default.green(`[${timestamp()}] Reconnected`)}
|
|
3871
3890
|
`);
|
|
3872
3891
|
},
|
|
3873
3892
|
onReconnectFailed: () => {
|
|
3874
3893
|
process.stderr.write(`
|
|
3875
|
-
${
|
|
3894
|
+
${chalk2__default.default.red(`[${timestamp()}] Reconnection failed`)}
|
|
3876
3895
|
`);
|
|
3877
3896
|
}
|
|
3878
3897
|
});
|
|
@@ -3890,13 +3909,49 @@ process.on("SIGINT", () => {
|
|
|
3890
3909
|
});
|
|
3891
3910
|
|
|
3892
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
|
+
}
|
|
3934
|
+
function formatCliError(err) {
|
|
3935
|
+
const connectionHint = diagnoseConnectionError(err);
|
|
3936
|
+
if (connectionHint) return connectionHint;
|
|
3937
|
+
if (err instanceof sdk.ArbiApiError && err.apiError && typeof err.apiError === "object") {
|
|
3938
|
+
const base = err.message;
|
|
3939
|
+
const apiErr = err.apiError;
|
|
3940
|
+
const detail = apiErr.detail ?? apiErr.message ?? apiErr.error;
|
|
3941
|
+
if (typeof detail === "string" && detail && !base.includes(detail)) {
|
|
3942
|
+
return `${base} \u2014 ${detail}`;
|
|
3943
|
+
}
|
|
3944
|
+
return base;
|
|
3945
|
+
}
|
|
3946
|
+
return sdk.getErrorMessage(err);
|
|
3947
|
+
}
|
|
3893
3948
|
function runAction(fn) {
|
|
3894
3949
|
return async () => {
|
|
3895
3950
|
try {
|
|
3896
3951
|
await fn();
|
|
3897
3952
|
process.exit(0);
|
|
3898
3953
|
} catch (err) {
|
|
3899
|
-
error(`Error: ${
|
|
3954
|
+
error(`Error: ${formatCliError(err)}`);
|
|
3900
3955
|
hintUpdateOnError();
|
|
3901
3956
|
process.exit(1);
|
|
3902
3957
|
}
|
|
@@ -3904,6 +3959,7 @@ function runAction(fn) {
|
|
|
3904
3959
|
}
|
|
3905
3960
|
async function resolveAuth() {
|
|
3906
3961
|
try {
|
|
3962
|
+
resolveConfig();
|
|
3907
3963
|
return await sdk.resolveAuth(store);
|
|
3908
3964
|
} catch (err) {
|
|
3909
3965
|
if (err instanceof sdk.ArbiError) {
|
|
@@ -3915,6 +3971,7 @@ async function resolveAuth() {
|
|
|
3915
3971
|
}
|
|
3916
3972
|
async function resolveWorkspace(workspaceOpt) {
|
|
3917
3973
|
try {
|
|
3974
|
+
resolveConfig();
|
|
3918
3975
|
const ctx = await sdk.resolveWorkspace(store, workspaceOpt);
|
|
3919
3976
|
if (getConfig()?.notifications) {
|
|
3920
3977
|
startBackgroundNotifications(ctx.config.baseUrl, ctx.accessToken).catch(() => {
|
|
@@ -3930,7 +3987,7 @@ async function resolveWorkspace(workspaceOpt) {
|
|
|
3930
3987
|
}
|
|
3931
3988
|
}
|
|
3932
3989
|
function printTable(columns, rows) {
|
|
3933
|
-
console.log(
|
|
3990
|
+
console.log(chalk2__default.default.bold(columns.map((c) => c.header.padEnd(c.width)).join("")));
|
|
3934
3991
|
for (const row of rows) {
|
|
3935
3992
|
console.log(
|
|
3936
3993
|
columns.map((c) => {
|
|
@@ -4028,6 +4085,10 @@ function registerWorkspacesCommand(program2) {
|
|
|
4028
4085
|
process.exit(1);
|
|
4029
4086
|
}
|
|
4030
4087
|
await sdk.workspaces.deleteWorkspaces(arbi, [targetId]);
|
|
4088
|
+
const session = getChatSession();
|
|
4089
|
+
if (session.workspaceId === targetId) {
|
|
4090
|
+
clearChatSession();
|
|
4091
|
+
}
|
|
4031
4092
|
success(`Deleted workspace ${targetId}`);
|
|
4032
4093
|
})()
|
|
4033
4094
|
);
|
|
@@ -4207,6 +4268,23 @@ function registerDocsCommand(program2) {
|
|
|
4207
4268
|
}
|
|
4208
4269
|
const data = await sdk.documents.getDocuments(arbi, docIds);
|
|
4209
4270
|
console.log(JSON.stringify(data, null, 2));
|
|
4271
|
+
const docs = Array.isArray(data) ? data : [data];
|
|
4272
|
+
for (const d of docs) {
|
|
4273
|
+
const raw = d;
|
|
4274
|
+
if (raw.status === "failed") {
|
|
4275
|
+
const reason = raw.error_reason || raw.status_details || raw.error || null;
|
|
4276
|
+
const docId = raw.external_id;
|
|
4277
|
+
if (reason) {
|
|
4278
|
+
console.error(chalk2__default.default.red(`
|
|
4279
|
+
\u26A0 ${docId} processing failed: ${reason}`));
|
|
4280
|
+
} else {
|
|
4281
|
+
console.error(
|
|
4282
|
+
chalk2__default.default.red(`
|
|
4283
|
+
\u26A0 ${docId} processing failed (no error details available)`)
|
|
4284
|
+
);
|
|
4285
|
+
}
|
|
4286
|
+
}
|
|
4287
|
+
}
|
|
4210
4288
|
})()
|
|
4211
4289
|
);
|
|
4212
4290
|
doc.command("delete [ids...]").description("Delete documents (interactive picker if no IDs given)").action(
|
|
@@ -4270,39 +4348,30 @@ function registerDocsCommand(program2) {
|
|
|
4270
4348
|
}
|
|
4271
4349
|
})()
|
|
4272
4350
|
);
|
|
4273
|
-
doc.command("parsed
|
|
4351
|
+
doc.command("parsed <doc-id> [stage]").description("Get parsed document content (stage: marker, subchunk, final; default: final)").action(
|
|
4274
4352
|
(docId, stage) => runAction(async () => {
|
|
4275
|
-
const {
|
|
4276
|
-
if (!docId) {
|
|
4277
|
-
const choices = await fetchDocChoices(arbi, workspaceId);
|
|
4278
|
-
docId = await promptSearch("Select document", choices);
|
|
4279
|
-
}
|
|
4353
|
+
const { accessToken, workspaceKeyHeader, config } = await resolveWorkspace();
|
|
4280
4354
|
const validStages = ["marker", "subchunk", "final"];
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
{ name: "Subchunk", value: "subchunk" },
|
|
4285
|
-
{ name: "Marker (raw)", value: "marker" }
|
|
4286
|
-
]);
|
|
4287
|
-
} else if (!validStages.includes(stage)) {
|
|
4288
|
-
error(`Invalid stage: ${stage}. Must be one of: ${validStages.join(", ")}`);
|
|
4355
|
+
const selectedStage = stage ?? "final";
|
|
4356
|
+
if (!validStages.includes(selectedStage)) {
|
|
4357
|
+
error(`Invalid stage: ${selectedStage}. Must be one of: ${validStages.join(", ")}`);
|
|
4289
4358
|
process.exit(1);
|
|
4290
4359
|
}
|
|
4291
4360
|
const data = await sdk.documents.getParsedContent(
|
|
4292
4361
|
{ baseUrl: config.baseUrl, accessToken, workspaceKeyHeader },
|
|
4293
4362
|
docId,
|
|
4294
|
-
|
|
4363
|
+
selectedStage
|
|
4295
4364
|
);
|
|
4296
4365
|
console.log(JSON.stringify(data, null, 2));
|
|
4297
4366
|
})()
|
|
4298
4367
|
);
|
|
4299
4368
|
}
|
|
4300
4369
|
function registerUploadCommand(program2) {
|
|
4301
|
-
program2.command("upload <
|
|
4302
|
-
(
|
|
4303
|
-
for (const
|
|
4304
|
-
if (!fs__default.default.existsSync(
|
|
4305
|
-
error(`
|
|
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}`);
|
|
4306
4375
|
process.exit(1);
|
|
4307
4376
|
}
|
|
4308
4377
|
}
|
|
@@ -4311,42 +4380,109 @@ function registerUploadCommand(program2) {
|
|
|
4311
4380
|
);
|
|
4312
4381
|
const uploadedDocs = /* @__PURE__ */ new Map();
|
|
4313
4382
|
const auth = { baseUrl: config.baseUrl, accessToken, workspaceKeyHeader };
|
|
4314
|
-
for (const filePath of
|
|
4315
|
-
const
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
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);
|
|
4319
4426
|
}
|
|
4320
|
-
for (const id of result.doc_ext_ids) uploadedDocs.set(id, result.fileName);
|
|
4321
4427
|
}
|
|
4322
|
-
|
|
4428
|
+
const isInteractive = process.stdout.isTTY === true;
|
|
4429
|
+
const shouldWatch = opts.watch === true || paths.length === 1 && isInteractive;
|
|
4430
|
+
if (shouldWatch && uploadedDocs.size > 0) {
|
|
4323
4431
|
const pending = new Set(uploadedDocs.keys());
|
|
4432
|
+
const failed = /* @__PURE__ */ new Map();
|
|
4324
4433
|
console.log(`
|
|
4325
4434
|
Watching ${pending.size} document(s)...`);
|
|
4435
|
+
let onDone;
|
|
4436
|
+
const done = new Promise((r) => {
|
|
4437
|
+
onDone = r;
|
|
4438
|
+
});
|
|
4326
4439
|
const conn = await sdk.connectWebSocket({
|
|
4327
4440
|
baseUrl: config.baseUrl,
|
|
4328
4441
|
accessToken,
|
|
4329
4442
|
onMessage: (msg) => {
|
|
4330
4443
|
if (client.isMessageType(msg, "task_update")) {
|
|
4331
4444
|
if (!pending.has(msg.doc_ext_id)) return;
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
)
|
|
4335
|
-
|
|
4445
|
+
const docName = uploadedDocs.get(msg.doc_ext_id) || msg.file_name;
|
|
4446
|
+
const extra = msg;
|
|
4447
|
+
if (msg.status === "failed") {
|
|
4448
|
+
const reason = extra.error_reason || extra.status_details || extra.detail || "Unknown error";
|
|
4449
|
+
failed.set(msg.doc_ext_id, reason);
|
|
4450
|
+
console.log(` ${docName}: ${status(msg.status)} \u2014 ${reason}`);
|
|
4336
4451
|
pending.delete(msg.doc_ext_id);
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4452
|
+
} else {
|
|
4453
|
+
console.log(` ${docName}: ${status(msg.status)} (${msg.progress}%)`);
|
|
4454
|
+
if (msg.status === "completed") {
|
|
4455
|
+
pending.delete(msg.doc_ext_id);
|
|
4340
4456
|
}
|
|
4341
4457
|
}
|
|
4458
|
+
if (pending.size === 0) {
|
|
4459
|
+
conn.close();
|
|
4460
|
+
}
|
|
4342
4461
|
}
|
|
4343
4462
|
},
|
|
4344
4463
|
onClose: () => {
|
|
4345
|
-
if (
|
|
4464
|
+
if (failed.size > 0) {
|
|
4465
|
+
error(`
|
|
4466
|
+
${failed.size} document(s) failed to process:`);
|
|
4467
|
+
for (const [docId, reason] of failed) {
|
|
4468
|
+
error(` ${uploadedDocs.get(docId) || docId}: ${reason}`);
|
|
4469
|
+
}
|
|
4470
|
+
}
|
|
4471
|
+
if (pending.size > 0) {
|
|
4346
4472
|
warn(`
|
|
4347
4473
|
Connection closed. ${pending.size} document(s) still processing.`);
|
|
4474
|
+
dim('Run "arbi watch" to continue monitoring, or "arbi docs" to check status.');
|
|
4475
|
+
} else if (failed.size === 0 && uploadedDocs.size > 0) {
|
|
4476
|
+
success("\nAll documents processed successfully.");
|
|
4477
|
+
}
|
|
4478
|
+
onDone();
|
|
4348
4479
|
}
|
|
4349
4480
|
});
|
|
4481
|
+
await done;
|
|
4482
|
+
} else if (uploadedDocs.size > 0 && !shouldWatch) {
|
|
4483
|
+
dim(
|
|
4484
|
+
'Tip: Use -W/--watch to monitor processing progress, or run "arbi docs" to check status.'
|
|
4485
|
+
);
|
|
4350
4486
|
}
|
|
4351
4487
|
})()
|
|
4352
4488
|
);
|
|
@@ -4393,9 +4529,14 @@ function registerAskCommand(program2) {
|
|
|
4393
4529
|
const question = words.join(" ");
|
|
4394
4530
|
const { arbi, accessToken, workspaceKeyHeader, workspaceId, config } = await resolveWorkspace(opts.workspace);
|
|
4395
4531
|
const session = getChatSession();
|
|
4532
|
+
const workspaceChanged = session.lastMessageExtId && session.workspaceId && session.workspaceId !== workspaceId;
|
|
4533
|
+
let previousResponseId = null;
|
|
4396
4534
|
if (opts.new) {
|
|
4397
4535
|
clearChatSession();
|
|
4398
|
-
|
|
4536
|
+
} else if (workspaceChanged) {
|
|
4537
|
+
clearChatSession();
|
|
4538
|
+
} else if (session.lastMessageExtId) {
|
|
4539
|
+
previousResponseId = session.lastMessageExtId;
|
|
4399
4540
|
}
|
|
4400
4541
|
const docs = await sdk.documents.listDocuments(arbi);
|
|
4401
4542
|
const docIds = docs.map((d) => d.external_id);
|
|
@@ -4408,11 +4549,11 @@ function registerAskCommand(program2) {
|
|
|
4408
4549
|
workspaceId,
|
|
4409
4550
|
question,
|
|
4410
4551
|
docIds,
|
|
4411
|
-
previousResponseId
|
|
4552
|
+
previousResponseId,
|
|
4412
4553
|
model: opts.config
|
|
4413
4554
|
});
|
|
4414
4555
|
} catch (err) {
|
|
4415
|
-
const isStaleParent =
|
|
4556
|
+
const isStaleParent = previousResponseId && err instanceof Error && (err.message.includes("404") || err.message.includes("Parent message not found"));
|
|
4416
4557
|
if (!isStaleParent) throw err;
|
|
4417
4558
|
clearChatSession();
|
|
4418
4559
|
res = await sdk.assistant.queryAssistant({
|
|
@@ -4430,18 +4571,19 @@ function registerAskCommand(program2) {
|
|
|
4430
4571
|
onToken: (content) => process.stdout.write(content),
|
|
4431
4572
|
onAgentStep: (data) => {
|
|
4432
4573
|
if (opts.verbose) {
|
|
4433
|
-
const
|
|
4434
|
-
console.error(
|
|
4435
|
-
[agent] ${
|
|
4574
|
+
const label2 = sdk.formatAgentStepLabel(data);
|
|
4575
|
+
if (label2) console.error(chalk2__default.default.dim(`
|
|
4576
|
+
[agent] ${label2}`));
|
|
4436
4577
|
}
|
|
4437
4578
|
},
|
|
4438
|
-
onError: (message) => console.error(
|
|
4579
|
+
onError: (message) => console.error(chalk2__default.default.red(`
|
|
4439
4580
|
Error: ${message}`))
|
|
4440
4581
|
});
|
|
4441
4582
|
process.stdout.write("\n");
|
|
4442
4583
|
if (result.assistantMessageExtId) {
|
|
4443
4584
|
const updates = {
|
|
4444
|
-
lastMessageExtId: result.assistantMessageExtId
|
|
4585
|
+
lastMessageExtId: result.assistantMessageExtId,
|
|
4586
|
+
workspaceId
|
|
4445
4587
|
};
|
|
4446
4588
|
const conversationExtId = result.userMessage?.conversation_ext_id ?? result.metadata?.conversation_ext_id;
|
|
4447
4589
|
if (conversationExtId) {
|
|
@@ -4453,30 +4595,73 @@ Error: ${message}`))
|
|
|
4453
4595
|
);
|
|
4454
4596
|
}
|
|
4455
4597
|
function colorize2(level, text) {
|
|
4456
|
-
if (level === "success") return
|
|
4457
|
-
if (level === "error") return
|
|
4458
|
-
if (level === "warning") return
|
|
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);
|
|
4459
4601
|
return text;
|
|
4460
4602
|
}
|
|
4461
4603
|
function registerWatchCommand(program2) {
|
|
4462
|
-
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(
|
|
4463
4605
|
(opts) => runAction(async () => {
|
|
4464
4606
|
const { config, accessToken, workspaceId } = await resolveWorkspace(opts.workspace);
|
|
4465
|
-
|
|
4466
|
-
|
|
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;
|
|
4618
|
+
let onDone;
|
|
4619
|
+
const done = new Promise((r) => {
|
|
4620
|
+
onDone = r;
|
|
4621
|
+
});
|
|
4622
|
+
const conn = await sdk.connectWebSocket({
|
|
4467
4623
|
baseUrl: config.baseUrl,
|
|
4468
4624
|
accessToken,
|
|
4469
4625
|
onMessage: (msg) => {
|
|
4470
|
-
|
|
4471
|
-
|
|
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
|
+
}
|
|
4472
4638
|
},
|
|
4473
4639
|
onClose: (code, reason) => {
|
|
4474
|
-
|
|
4475
|
-
|
|
4640
|
+
if (!jsonMode) {
|
|
4641
|
+
console.log(
|
|
4642
|
+
chalk2__default.default.yellow(`
|
|
4476
4643
|
Connection closed (code ${code}${reason ? ": " + reason : ""})`)
|
|
4477
|
-
|
|
4644
|
+
);
|
|
4645
|
+
}
|
|
4646
|
+
onDone();
|
|
4478
4647
|
}
|
|
4479
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);
|
|
4662
|
+
await done;
|
|
4663
|
+
if (timer) clearTimeout(timer);
|
|
4664
|
+
process.removeListener("SIGINT", sigintHandler);
|
|
4480
4665
|
})()
|
|
4481
4666
|
);
|
|
4482
4667
|
}
|
|
@@ -5303,6 +5488,229 @@ Updated to ${latest}.`);
|
|
|
5303
5488
|
success("Auto-update enabled. ARBI CLI will update automatically on login.");
|
|
5304
5489
|
});
|
|
5305
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
|
+
}
|
|
5306
5714
|
|
|
5307
5715
|
// src/index.ts
|
|
5308
5716
|
console.debug = () => {
|
|
@@ -5313,7 +5721,7 @@ console.info = (...args) => {
|
|
|
5313
5721
|
_origInfo(...args);
|
|
5314
5722
|
};
|
|
5315
5723
|
var program = new commander.Command();
|
|
5316
|
-
program.name("arbi").description("ARBI CLI \u2014 interact with ARBI from the terminal").version("0.3.
|
|
5724
|
+
program.name("arbi").description("ARBI CLI \u2014 interact with ARBI from the terminal").version("0.3.13");
|
|
5317
5725
|
registerConfigCommand(program);
|
|
5318
5726
|
registerLoginCommand(program);
|
|
5319
5727
|
registerRegisterCommand(program);
|
|
@@ -5335,6 +5743,8 @@ registerAgentconfigCommand(program);
|
|
|
5335
5743
|
registerHealthCommand(program);
|
|
5336
5744
|
registerTuiCommand(program);
|
|
5337
5745
|
registerUpdateCommand(program);
|
|
5746
|
+
registerQuickstartCommand(program);
|
|
5747
|
+
registerAgentCreateCommand(program);
|
|
5338
5748
|
program.parse();
|
|
5339
5749
|
//# sourceMappingURL=index.js.map
|
|
5340
5750
|
//# sourceMappingURL=index.js.map
|