@arbidocs/cli 0.3.11 → 0.3.14
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 +73 -4
- package/dist/index.js +649 -70
- 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
|
|
@@ -118,7 +125,9 @@ function registerConfigCommand(program2) {
|
|
|
118
125
|
label("Server URL:", cfg.baseUrl);
|
|
119
126
|
label("Domain:", cfg.deploymentDomain);
|
|
120
127
|
label("Auto-update:", cfg.autoUpdate ? "on" : "off");
|
|
121
|
-
label("
|
|
128
|
+
label("Verbose:", cfg.verbose !== false ? "on" : "off");
|
|
129
|
+
label("Watch:", cfg.watch !== false ? "on" : "off");
|
|
130
|
+
label("Notifications:", cfg.notifications !== false ? "on" : "off");
|
|
122
131
|
if (cfg.selectedWorkspaceId) {
|
|
123
132
|
label("Workspace:", cfg.selectedWorkspaceId);
|
|
124
133
|
}
|
|
@@ -126,7 +135,7 @@ function registerConfigCommand(program2) {
|
|
|
126
135
|
config.command("notifications [on|off]").description("Toggle background WebSocket notifications").action((toggle) => {
|
|
127
136
|
const cfg = getConfig();
|
|
128
137
|
if (!toggle) {
|
|
129
|
-
label("Notifications:", cfg?.notifications ? "on" : "off");
|
|
138
|
+
label("Notifications:", cfg?.notifications !== false ? "on" : "off");
|
|
130
139
|
return;
|
|
131
140
|
}
|
|
132
141
|
if (toggle !== "on" && toggle !== "off") {
|
|
@@ -136,6 +145,32 @@ function registerConfigCommand(program2) {
|
|
|
136
145
|
updateConfig({ notifications: toggle === "on" });
|
|
137
146
|
success(`Notifications: ${toggle}`);
|
|
138
147
|
});
|
|
148
|
+
config.command("verbose [on|off]").description("Toggle verbose agent steps in ask (default: on)").action((toggle) => {
|
|
149
|
+
const cfg = getConfig();
|
|
150
|
+
if (!toggle) {
|
|
151
|
+
label("Verbose:", cfg?.verbose !== false ? "on" : "off");
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (toggle !== "on" && toggle !== "off") {
|
|
155
|
+
error("Usage: arbi config verbose [on|off]");
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
updateConfig({ verbose: toggle === "on" });
|
|
159
|
+
success(`Verbose: ${toggle}`);
|
|
160
|
+
});
|
|
161
|
+
config.command("watch [on|off]").description("Toggle upload watch (default: on)").action((toggle) => {
|
|
162
|
+
const cfg = getConfig();
|
|
163
|
+
if (!toggle) {
|
|
164
|
+
label("Watch:", cfg?.watch !== false ? "on" : "off");
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (toggle !== "on" && toggle !== "off") {
|
|
168
|
+
error("Usage: arbi config watch [on|off]");
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
updateConfig({ watch: toggle === "on" });
|
|
172
|
+
success(`Watch: ${toggle}`);
|
|
173
|
+
});
|
|
139
174
|
config.command("alias").description('Set up shell alias A for "arbi ask"').action(() => {
|
|
140
175
|
const rcPath = getShellRcPath();
|
|
141
176
|
if (isAliasInstalled(rcPath)) {
|
|
@@ -3502,7 +3537,7 @@ function getLatestVersion(skipCache = false) {
|
|
|
3502
3537
|
}
|
|
3503
3538
|
}
|
|
3504
3539
|
function getCurrentVersion() {
|
|
3505
|
-
return "0.3.
|
|
3540
|
+
return "0.3.14";
|
|
3506
3541
|
}
|
|
3507
3542
|
function readChangelog(fromVersion, toVersion) {
|
|
3508
3543
|
try {
|
|
@@ -3555,17 +3590,17 @@ function showChangelog(fromVersion, toVersion) {
|
|
|
3555
3590
|
async function checkForUpdates(autoUpdate) {
|
|
3556
3591
|
try {
|
|
3557
3592
|
const latest = getLatestVersion();
|
|
3558
|
-
if (!latest || latest === "0.3.
|
|
3593
|
+
if (!latest || latest === "0.3.14") return;
|
|
3559
3594
|
if (autoUpdate) {
|
|
3560
3595
|
warn(`
|
|
3561
|
-
Your arbi version is out of date (${"0.3.
|
|
3596
|
+
Your arbi version is out of date (${"0.3.14"} \u2192 ${latest}). Updating...`);
|
|
3562
3597
|
child_process.execSync("npm install -g @arbidocs/cli@latest", { stdio: "inherit" });
|
|
3563
|
-
showChangelog("0.3.
|
|
3598
|
+
showChangelog("0.3.14", latest);
|
|
3564
3599
|
console.log(`Updated to ${latest}.`);
|
|
3565
3600
|
} else {
|
|
3566
3601
|
warn(
|
|
3567
3602
|
`
|
|
3568
|
-
Your arbi version is out of date (${"0.3.
|
|
3603
|
+
Your arbi version is out of date (${"0.3.14"} \u2192 ${latest}).
|
|
3569
3604
|
Run "arbi update" to upgrade, or "arbi update auto" to always stay up to date.`
|
|
3570
3605
|
);
|
|
3571
3606
|
}
|
|
@@ -3575,9 +3610,9 @@ Run "arbi update" to upgrade, or "arbi update auto" to always stay up to date.`
|
|
|
3575
3610
|
function hintUpdateOnError() {
|
|
3576
3611
|
try {
|
|
3577
3612
|
const cached = readCache();
|
|
3578
|
-
if (cached && cached.latest !== "0.3.
|
|
3613
|
+
if (cached && cached.latest !== "0.3.14") {
|
|
3579
3614
|
warn(
|
|
3580
|
-
`Your arbi version is out of date (${"0.3.
|
|
3615
|
+
`Your arbi version is out of date (${"0.3.14"} \u2192 ${cached.latest}). Run "arbi update".`
|
|
3581
3616
|
);
|
|
3582
3617
|
}
|
|
3583
3618
|
} catch {
|
|
@@ -3658,7 +3693,11 @@ function registerRegisterCommand(program2) {
|
|
|
3658
3693
|
});
|
|
3659
3694
|
}
|
|
3660
3695
|
async function smartRegister(config, opts) {
|
|
3661
|
-
|
|
3696
|
+
let email = opts.email || process.env.ARBI_EMAIL || await promptInput("Email");
|
|
3697
|
+
if ((opts.email || process.env.ARBI_EMAIL) && !email.includes("@")) {
|
|
3698
|
+
email = `${email}@${config.deploymentDomain}`;
|
|
3699
|
+
console.log(`Using email: ${email}`);
|
|
3700
|
+
}
|
|
3662
3701
|
const arbi = client.createArbiClient({
|
|
3663
3702
|
baseUrl: config.baseUrl,
|
|
3664
3703
|
deploymentDomain: config.deploymentDomain,
|
|
@@ -3724,13 +3763,17 @@ Registered successfully as ${email}`);
|
|
|
3724
3763
|
}
|
|
3725
3764
|
}
|
|
3726
3765
|
async function nonInteractiveRegister(config, opts) {
|
|
3727
|
-
|
|
3766
|
+
let email = opts.email || process.env.ARBI_EMAIL;
|
|
3728
3767
|
const password2 = opts.password || process.env.ARBI_PASSWORD;
|
|
3729
3768
|
const supportApiKey = process.env.SUPPORT_API_KEY;
|
|
3730
3769
|
if (!email) {
|
|
3731
3770
|
error("Email required. Use --email <email> or set ARBI_EMAIL");
|
|
3732
3771
|
process.exit(1);
|
|
3733
3772
|
}
|
|
3773
|
+
if (!email.includes("@")) {
|
|
3774
|
+
email = `${email}@${config.deploymentDomain}`;
|
|
3775
|
+
console.log(`Using email: ${email}`);
|
|
3776
|
+
}
|
|
3734
3777
|
if (!password2) {
|
|
3735
3778
|
error("Password required. Use --password <password> or set ARBI_PASSWORD");
|
|
3736
3779
|
process.exit(1);
|
|
@@ -3837,14 +3880,62 @@ function registerStatusCommand(program2) {
|
|
|
3837
3880
|
}
|
|
3838
3881
|
});
|
|
3839
3882
|
}
|
|
3883
|
+
var MAX_TASKS = 50;
|
|
3884
|
+
var MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
3885
|
+
function getTasksFile() {
|
|
3886
|
+
const configDir = process.env.ARBI_CONFIG_DIR ?? path__default.default.join(os__default.default.homedir(), ".arbi");
|
|
3887
|
+
return path__default.default.join(configDir, "tasks.json");
|
|
3888
|
+
}
|
|
3889
|
+
function ensureDir(filePath) {
|
|
3890
|
+
const dir = path__default.default.dirname(filePath);
|
|
3891
|
+
if (!fs__default.default.existsSync(dir)) {
|
|
3892
|
+
fs__default.default.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
3893
|
+
}
|
|
3894
|
+
}
|
|
3895
|
+
function readTasks() {
|
|
3896
|
+
try {
|
|
3897
|
+
const content = fs__default.default.readFileSync(getTasksFile(), "utf-8");
|
|
3898
|
+
return JSON.parse(content);
|
|
3899
|
+
} catch {
|
|
3900
|
+
return [];
|
|
3901
|
+
}
|
|
3902
|
+
}
|
|
3903
|
+
function writeTasks(tasks) {
|
|
3904
|
+
const filePath = getTasksFile();
|
|
3905
|
+
ensureDir(filePath);
|
|
3906
|
+
fs__default.default.writeFileSync(filePath, JSON.stringify(tasks, null, 2) + "\n", { mode: 384 });
|
|
3907
|
+
}
|
|
3908
|
+
function getTasks() {
|
|
3909
|
+
const now = Date.now();
|
|
3910
|
+
const tasks = readTasks().filter((t) => now - new Date(t.submittedAt).getTime() < MAX_AGE_MS);
|
|
3911
|
+
return tasks;
|
|
3912
|
+
}
|
|
3913
|
+
function addTask(task) {
|
|
3914
|
+
const tasks = [task, ...getTasks().filter((t) => t.id !== task.id)].slice(0, MAX_TASKS);
|
|
3915
|
+
writeTasks(tasks);
|
|
3916
|
+
}
|
|
3917
|
+
function updateTaskStatus(id, status2) {
|
|
3918
|
+
const tasks = readTasks();
|
|
3919
|
+
const task = tasks.find((t) => t.id === id);
|
|
3920
|
+
if (task) {
|
|
3921
|
+
task.status = status2;
|
|
3922
|
+
writeTasks(tasks);
|
|
3923
|
+
}
|
|
3924
|
+
}
|
|
3925
|
+
function getLatestTask() {
|
|
3926
|
+
const tasks = getTasks();
|
|
3927
|
+
return tasks[0] ?? null;
|
|
3928
|
+
}
|
|
3929
|
+
|
|
3930
|
+
// src/notifications.ts
|
|
3840
3931
|
var activeConnection = null;
|
|
3841
3932
|
function timestamp() {
|
|
3842
3933
|
return (/* @__PURE__ */ new Date()).toLocaleTimeString("en-GB", { hour12: false });
|
|
3843
3934
|
}
|
|
3844
3935
|
function colorize(level, text) {
|
|
3845
|
-
if (level === "success") return
|
|
3846
|
-
if (level === "error") return
|
|
3847
|
-
if (level === "warning") return
|
|
3936
|
+
if (level === "success") return chalk2__default.default.green(text);
|
|
3937
|
+
if (level === "error") return chalk2__default.default.red(text);
|
|
3938
|
+
if (level === "warning") return chalk2__default.default.yellow(text);
|
|
3848
3939
|
return text;
|
|
3849
3940
|
}
|
|
3850
3941
|
async function startBackgroundNotifications(baseUrl, accessToken) {
|
|
@@ -3854,6 +3945,9 @@ async function startBackgroundNotifications(baseUrl, accessToken) {
|
|
|
3854
3945
|
baseUrl,
|
|
3855
3946
|
accessToken,
|
|
3856
3947
|
onMessage: (msg) => {
|
|
3948
|
+
if (client.isMessageType(msg, "response_complete")) {
|
|
3949
|
+
updateTaskStatus(msg.response_id, msg.status);
|
|
3950
|
+
}
|
|
3857
3951
|
const { text, level } = sdk.formatWsMessage(msg);
|
|
3858
3952
|
process.stderr.write(`
|
|
3859
3953
|
${colorize(level, `[${timestamp()}] ${text}`)}
|
|
@@ -3865,18 +3959,18 @@ ${colorize(level, `[${timestamp()}] ${text}`)}
|
|
|
3865
3959
|
onReconnecting: (attempt, maxRetries) => {
|
|
3866
3960
|
process.stderr.write(
|
|
3867
3961
|
`
|
|
3868
|
-
${
|
|
3962
|
+
${chalk2__default.default.yellow(`[${timestamp()}] Reconnecting... (${attempt}/${maxRetries})`)}
|
|
3869
3963
|
`
|
|
3870
3964
|
);
|
|
3871
3965
|
},
|
|
3872
3966
|
onReconnected: () => {
|
|
3873
3967
|
process.stderr.write(`
|
|
3874
|
-
${
|
|
3968
|
+
${chalk2__default.default.green(`[${timestamp()}] Reconnected`)}
|
|
3875
3969
|
`);
|
|
3876
3970
|
},
|
|
3877
3971
|
onReconnectFailed: () => {
|
|
3878
3972
|
process.stderr.write(`
|
|
3879
|
-
${
|
|
3973
|
+
${chalk2__default.default.red(`[${timestamp()}] Reconnection failed`)}
|
|
3880
3974
|
`);
|
|
3881
3975
|
}
|
|
3882
3976
|
});
|
|
@@ -3894,7 +3988,31 @@ process.on("SIGINT", () => {
|
|
|
3894
3988
|
});
|
|
3895
3989
|
|
|
3896
3990
|
// src/helpers.ts
|
|
3991
|
+
var CONNECTION_ERROR_HINTS = {
|
|
3992
|
+
ECONNREFUSED: "Connection refused. Is the backend running?",
|
|
3993
|
+
ECONNRESET: "Connection reset by server. The backend may have restarted.",
|
|
3994
|
+
ENOTFOUND: "DNS resolution failed. Check the server URL.",
|
|
3995
|
+
ETIMEDOUT: "Connection timed out. Check network connectivity.",
|
|
3996
|
+
UNABLE_TO_VERIFY_LEAF_SIGNATURE: "TLS certificate cannot be verified. The cert may be expired or self-signed.",
|
|
3997
|
+
CERT_HAS_EXPIRED: "TLS certificate has expired. Renew with manage-deployment.",
|
|
3998
|
+
ERR_TLS_CERT_ALTNAME_INVALID: "TLS certificate hostname mismatch. Check the server URL.",
|
|
3999
|
+
DEPTH_ZERO_SELF_SIGNED_CERT: "Self-signed TLS certificate. The cert may need to be renewed.",
|
|
4000
|
+
SELF_SIGNED_CERT_IN_CHAIN: "Self-signed certificate in chain. The cert may need to be renewed."
|
|
4001
|
+
};
|
|
4002
|
+
function diagnoseConnectionError(err) {
|
|
4003
|
+
const code = sdk.getErrorCode(err);
|
|
4004
|
+
if (code && code in CONNECTION_ERROR_HINTS) {
|
|
4005
|
+
return CONNECTION_ERROR_HINTS[code];
|
|
4006
|
+
}
|
|
4007
|
+
const msg = err instanceof Error ? err.message : "";
|
|
4008
|
+
if (msg === "fetch failed" || msg.includes("fetch failed")) {
|
|
4009
|
+
return "Network error connecting to the server. Run `arbi health` to diagnose.";
|
|
4010
|
+
}
|
|
4011
|
+
return void 0;
|
|
4012
|
+
}
|
|
3897
4013
|
function formatCliError(err) {
|
|
4014
|
+
const connectionHint = diagnoseConnectionError(err);
|
|
4015
|
+
if (connectionHint) return connectionHint;
|
|
3898
4016
|
if (err instanceof sdk.ArbiApiError && err.apiError && typeof err.apiError === "object") {
|
|
3899
4017
|
const base = err.message;
|
|
3900
4018
|
const apiErr = err.apiError;
|
|
@@ -3920,6 +4038,7 @@ function runAction(fn) {
|
|
|
3920
4038
|
}
|
|
3921
4039
|
async function resolveAuth() {
|
|
3922
4040
|
try {
|
|
4041
|
+
resolveConfig();
|
|
3923
4042
|
return await sdk.resolveAuth(store);
|
|
3924
4043
|
} catch (err) {
|
|
3925
4044
|
if (err instanceof sdk.ArbiError) {
|
|
@@ -3931,8 +4050,9 @@ async function resolveAuth() {
|
|
|
3931
4050
|
}
|
|
3932
4051
|
async function resolveWorkspace(workspaceOpt) {
|
|
3933
4052
|
try {
|
|
4053
|
+
resolveConfig();
|
|
3934
4054
|
const ctx = await sdk.resolveWorkspace(store, workspaceOpt);
|
|
3935
|
-
if (getConfig()?.notifications) {
|
|
4055
|
+
if (getConfig()?.notifications !== false) {
|
|
3936
4056
|
startBackgroundNotifications(ctx.config.baseUrl, ctx.accessToken).catch(() => {
|
|
3937
4057
|
});
|
|
3938
4058
|
}
|
|
@@ -3946,7 +4066,7 @@ async function resolveWorkspace(workspaceOpt) {
|
|
|
3946
4066
|
}
|
|
3947
4067
|
}
|
|
3948
4068
|
function printTable(columns, rows) {
|
|
3949
|
-
console.log(
|
|
4069
|
+
console.log(chalk2__default.default.bold(columns.map((c) => c.header.padEnd(c.width)).join("")));
|
|
3950
4070
|
for (const row of rows) {
|
|
3951
4071
|
console.log(
|
|
3952
4072
|
columns.map((c) => {
|
|
@@ -4234,11 +4354,11 @@ function registerDocsCommand(program2) {
|
|
|
4234
4354
|
const reason = raw.error_reason || raw.status_details || raw.error || null;
|
|
4235
4355
|
const docId = raw.external_id;
|
|
4236
4356
|
if (reason) {
|
|
4237
|
-
console.error(
|
|
4357
|
+
console.error(chalk2__default.default.red(`
|
|
4238
4358
|
\u26A0 ${docId} processing failed: ${reason}`));
|
|
4239
4359
|
} else {
|
|
4240
4360
|
console.error(
|
|
4241
|
-
|
|
4361
|
+
chalk2__default.default.red(`
|
|
4242
4362
|
\u26A0 ${docId} processing failed (no error details available)`)
|
|
4243
4363
|
);
|
|
4244
4364
|
}
|
|
@@ -4326,11 +4446,11 @@ function registerDocsCommand(program2) {
|
|
|
4326
4446
|
);
|
|
4327
4447
|
}
|
|
4328
4448
|
function registerUploadCommand(program2) {
|
|
4329
|
-
program2.command("
|
|
4330
|
-
(
|
|
4331
|
-
for (const
|
|
4332
|
-
if (!fs__default.default.existsSync(
|
|
4333
|
-
error(`
|
|
4449
|
+
program2.command("add <paths...>").alias("upload").description("Add 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").option("--no-watch", "Skip watching document processing").action(
|
|
4450
|
+
(paths, opts) => runAction(async () => {
|
|
4451
|
+
for (const p of paths) {
|
|
4452
|
+
if (!fs__default.default.existsSync(p)) {
|
|
4453
|
+
error(`Path not found: ${p}`);
|
|
4334
4454
|
process.exit(1);
|
|
4335
4455
|
}
|
|
4336
4456
|
}
|
|
@@ -4339,16 +4459,54 @@ function registerUploadCommand(program2) {
|
|
|
4339
4459
|
);
|
|
4340
4460
|
const uploadedDocs = /* @__PURE__ */ new Map();
|
|
4341
4461
|
const auth = { baseUrl: config.baseUrl, accessToken, workspaceKeyHeader };
|
|
4342
|
-
for (const filePath of
|
|
4343
|
-
const
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4462
|
+
for (const filePath of paths) {
|
|
4463
|
+
const stat = fs__default.default.statSync(filePath);
|
|
4464
|
+
if (stat.isDirectory()) {
|
|
4465
|
+
const result = await sdk.documentsNode.uploadDirectory(auth, workspaceId, filePath);
|
|
4466
|
+
if (result.doc_ext_ids.length === 0) {
|
|
4467
|
+
warn(`No supported files found in directory: ${filePath}`);
|
|
4468
|
+
continue;
|
|
4469
|
+
}
|
|
4470
|
+
for (const [folder, info] of result.folders) {
|
|
4471
|
+
success(
|
|
4472
|
+
` ${folder}: ${info.fileCount} file(s) \u2192 ${info.doc_ext_ids.length} uploaded`
|
|
4473
|
+
);
|
|
4474
|
+
if (info.duplicates.length > 0) {
|
|
4475
|
+
warn(` Duplicates: ${info.duplicates.join(", ")}`);
|
|
4476
|
+
}
|
|
4477
|
+
}
|
|
4478
|
+
success(
|
|
4479
|
+
`Uploaded directory: ${filePath} (${result.doc_ext_ids.length} document(s) total)`
|
|
4480
|
+
);
|
|
4481
|
+
for (const id of result.doc_ext_ids) uploadedDocs.set(id, filePath);
|
|
4482
|
+
} else if (filePath.toLowerCase().endsWith(".zip")) {
|
|
4483
|
+
const result = await sdk.documentsNode.uploadZip(auth, workspaceId, filePath);
|
|
4484
|
+
if (result.doc_ext_ids.length === 0) {
|
|
4485
|
+
warn(`No supported files found in zip: ${filePath}`);
|
|
4486
|
+
continue;
|
|
4487
|
+
}
|
|
4488
|
+
for (const [folder, info] of result.folders) {
|
|
4489
|
+
success(
|
|
4490
|
+
` ${folder}: ${info.fileCount} file(s) \u2192 ${info.doc_ext_ids.length} uploaded`
|
|
4491
|
+
);
|
|
4492
|
+
if (info.duplicates.length > 0) {
|
|
4493
|
+
warn(` Duplicates: ${info.duplicates.join(", ")}`);
|
|
4494
|
+
}
|
|
4495
|
+
}
|
|
4496
|
+
success(`Uploaded zip: ${filePath} (${result.doc_ext_ids.length} document(s) total)`);
|
|
4497
|
+
for (const id of result.doc_ext_ids) uploadedDocs.set(id, filePath);
|
|
4498
|
+
} else {
|
|
4499
|
+
const result = await sdk.documentsNode.uploadLocalFile(auth, workspaceId, filePath);
|
|
4500
|
+
success(`Uploaded: ${result.fileName} (${result.doc_ext_ids.join(", ")})`);
|
|
4501
|
+
if (result.duplicates && result.duplicates.length > 0) {
|
|
4502
|
+
warn(` Duplicates: ${result.duplicates.join(", ")}`);
|
|
4503
|
+
}
|
|
4504
|
+
for (const id of result.doc_ext_ids) uploadedDocs.set(id, result.fileName);
|
|
4347
4505
|
}
|
|
4348
|
-
for (const id of result.doc_ext_ids) uploadedDocs.set(id, result.fileName);
|
|
4349
4506
|
}
|
|
4350
4507
|
const isInteractive = process.stdout.isTTY === true;
|
|
4351
|
-
const
|
|
4508
|
+
const watchPref = getConfig()?.watch !== false;
|
|
4509
|
+
const shouldWatch = opts.watch === false ? false : opts.watch === true || watchPref && isInteractive;
|
|
4352
4510
|
if (shouldWatch && uploadedDocs.size > 0) {
|
|
4353
4511
|
const pending = new Set(uploadedDocs.keys());
|
|
4354
4512
|
const failed = /* @__PURE__ */ new Map();
|
|
@@ -4446,22 +4604,55 @@ function registerDownloadCommand(program2) {
|
|
|
4446
4604
|
);
|
|
4447
4605
|
}
|
|
4448
4606
|
function registerAskCommand(program2) {
|
|
4449
|
-
program2.command("ask <question...>").description("Ask the RAG assistant a question (no quotes needed)").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").option("-c, --config <id>", "Config ext_id to use (e.g. cfg-xxx)").option("-n, --new", "Start a new conversation (ignore previous context)").option("-
|
|
4607
|
+
program2.command("ask <question...>").description("Ask the RAG assistant a question (no quotes needed)").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").option("-c, --continue <msg-id>", "Continue from a specific message ID").option("--config <id>", "Config ext_id to use (e.g. cfg-xxx)").option("-n, --new", "Start a new conversation (ignore previous context)").option("-b, --background", "Submit as background task (fire and forget)").option("-q, --quiet", "Suppress agent steps and tool calls").option("--json", "Output in JSON format (background mode only)").action(
|
|
4450
4608
|
(words, opts) => runAction(async () => {
|
|
4451
4609
|
const question = words.join(" ");
|
|
4452
4610
|
const { arbi, accessToken, workspaceKeyHeader, workspaceId, config } = await resolveWorkspace(opts.workspace);
|
|
4453
|
-
const session = getChatSession();
|
|
4454
|
-
const workspaceChanged = session.lastMessageExtId && session.workspaceId && session.workspaceId !== workspaceId;
|
|
4455
4611
|
let previousResponseId = null;
|
|
4456
|
-
if (opts.
|
|
4612
|
+
if (opts.continue) {
|
|
4613
|
+
previousResponseId = opts.continue;
|
|
4614
|
+
} else if (opts.new) {
|
|
4457
4615
|
clearChatSession();
|
|
4458
|
-
} else
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4616
|
+
} else {
|
|
4617
|
+
const session = getChatSession();
|
|
4618
|
+
const workspaceChanged = session.lastMessageExtId && session.workspaceId && session.workspaceId !== workspaceId;
|
|
4619
|
+
if (workspaceChanged) {
|
|
4620
|
+
clearChatSession();
|
|
4621
|
+
} else if (session.lastMessageExtId) {
|
|
4622
|
+
previousResponseId = session.lastMessageExtId;
|
|
4623
|
+
}
|
|
4462
4624
|
}
|
|
4463
4625
|
const docs = await sdk.documents.listDocuments(arbi);
|
|
4464
4626
|
const docIds = docs.map((d) => d.external_id);
|
|
4627
|
+
if (opts.background) {
|
|
4628
|
+
const result2 = await sdk.responses.submitBackgroundQuery({
|
|
4629
|
+
baseUrl: config.baseUrl,
|
|
4630
|
+
accessToken,
|
|
4631
|
+
workspaceKeyHeader,
|
|
4632
|
+
workspaceId,
|
|
4633
|
+
question,
|
|
4634
|
+
docIds,
|
|
4635
|
+
previousResponseId,
|
|
4636
|
+
model: opts.config
|
|
4637
|
+
});
|
|
4638
|
+
addTask({
|
|
4639
|
+
id: result2.id,
|
|
4640
|
+
question: question.slice(0, 200),
|
|
4641
|
+
workspaceId,
|
|
4642
|
+
submittedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4643
|
+
status: "queued",
|
|
4644
|
+
model: result2.model
|
|
4645
|
+
});
|
|
4646
|
+
if (opts.json) {
|
|
4647
|
+
console.log(JSON.stringify({ id: result2.id, status: result2.status }));
|
|
4648
|
+
} else {
|
|
4649
|
+
console.log(`Task queued: ${chalk2__default.default.cyan(result2.id)}`);
|
|
4650
|
+
console.log(
|
|
4651
|
+
chalk2__default.default.dim("Use `arbi task status` or `arbi task result` to check progress.")
|
|
4652
|
+
);
|
|
4653
|
+
}
|
|
4654
|
+
return;
|
|
4655
|
+
}
|
|
4465
4656
|
let res;
|
|
4466
4657
|
try {
|
|
4467
4658
|
res = await sdk.assistant.queryAssistant({
|
|
@@ -4489,19 +4680,47 @@ function registerAskCommand(program2) {
|
|
|
4489
4680
|
model: opts.config
|
|
4490
4681
|
});
|
|
4491
4682
|
}
|
|
4683
|
+
const verbose = opts.quiet === true ? false : getConfig()?.verbose !== false;
|
|
4684
|
+
let elapsedTime = null;
|
|
4492
4685
|
const result = await sdk.streamSSE(res, {
|
|
4493
4686
|
onToken: (content) => process.stdout.write(content),
|
|
4494
4687
|
onAgentStep: (data) => {
|
|
4495
|
-
if (
|
|
4496
|
-
const
|
|
4497
|
-
console.error(
|
|
4498
|
-
[agent] ${
|
|
4688
|
+
if (verbose) {
|
|
4689
|
+
const label2 = sdk.formatAgentStepLabel(data);
|
|
4690
|
+
if (label2) console.error(chalk2__default.default.dim(`
|
|
4691
|
+
[agent] ${label2}`));
|
|
4499
4692
|
}
|
|
4500
4693
|
},
|
|
4501
|
-
|
|
4694
|
+
onElapsedTime: (t) => {
|
|
4695
|
+
elapsedTime = t;
|
|
4696
|
+
},
|
|
4697
|
+
onError: (message) => console.error(chalk2__default.default.red(`
|
|
4502
4698
|
Error: ${message}`))
|
|
4503
4699
|
});
|
|
4504
4700
|
process.stdout.write("\n");
|
|
4701
|
+
const parts = [];
|
|
4702
|
+
if (result.agentSteps.length > 0) {
|
|
4703
|
+
let stepLabel = `${result.agentSteps.length} step${result.agentSteps.length === 1 ? "" : "s"}`;
|
|
4704
|
+
if (result.toolCallCount > 0) {
|
|
4705
|
+
stepLabel += ` (${result.toolCallCount} tool call${result.toolCallCount === 1 ? "" : "s"})`;
|
|
4706
|
+
}
|
|
4707
|
+
parts.push(stepLabel);
|
|
4708
|
+
}
|
|
4709
|
+
if (result.usage) {
|
|
4710
|
+
parts.push(`${result.usage.total_tokens.toLocaleString()} tokens`);
|
|
4711
|
+
}
|
|
4712
|
+
if (result.context && result.context.context_window > 0) {
|
|
4713
|
+
const used = result.context.all_llm_calls?.last_input_tokens ?? result.context.total_input;
|
|
4714
|
+
parts.push(
|
|
4715
|
+
`${used.toLocaleString()}/${result.context.context_window.toLocaleString()} context`
|
|
4716
|
+
);
|
|
4717
|
+
}
|
|
4718
|
+
if (elapsedTime != null) {
|
|
4719
|
+
parts.push(`${elapsedTime.toFixed(1)}s`);
|
|
4720
|
+
}
|
|
4721
|
+
if (parts.length > 0) {
|
|
4722
|
+
console.error(chalk2__default.default.dim(`[${parts.join(" \xB7 ")}]`));
|
|
4723
|
+
}
|
|
4505
4724
|
if (result.assistantMessageExtId) {
|
|
4506
4725
|
const updates = {
|
|
4507
4726
|
lastMessageExtId: result.assistantMessageExtId,
|
|
@@ -4517,36 +4736,73 @@ Error: ${message}`))
|
|
|
4517
4736
|
);
|
|
4518
4737
|
}
|
|
4519
4738
|
function colorize2(level, text) {
|
|
4520
|
-
if (level === "success") return
|
|
4521
|
-
if (level === "error") return
|
|
4522
|
-
if (level === "warning") return
|
|
4739
|
+
if (level === "success") return chalk2__default.default.green(text);
|
|
4740
|
+
if (level === "error") return chalk2__default.default.red(text);
|
|
4741
|
+
if (level === "warning") return chalk2__default.default.yellow(text);
|
|
4523
4742
|
return text;
|
|
4524
4743
|
}
|
|
4525
4744
|
function registerWatchCommand(program2) {
|
|
4526
|
-
program2.command("watch").description("Watch workspace activity in real time").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").action(
|
|
4745
|
+
program2.command("watch").description("Watch workspace activity in real time").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").option("-t, --timeout <seconds>", "Auto-close after N seconds").option("-n, --count <n>", "Stop after N messages").option("--json", "Output NDJSON (one JSON object per line)").action(
|
|
4527
4746
|
(opts) => runAction(async () => {
|
|
4528
4747
|
const { config, accessToken, workspaceId } = await resolveWorkspace(opts.workspace);
|
|
4529
|
-
|
|
4748
|
+
const timeoutSec = opts.timeout ? parseInt(opts.timeout, 10) : void 0;
|
|
4749
|
+
const maxCount = opts.count ? parseInt(opts.count, 10) : void 0;
|
|
4750
|
+
const jsonMode = opts.json ?? false;
|
|
4751
|
+
if (!jsonMode) {
|
|
4752
|
+
const parts = [`Watching workspace ${workspaceId}...`];
|
|
4753
|
+
if (timeoutSec) parts.push(`(timeout: ${timeoutSec}s)`);
|
|
4754
|
+
if (maxCount) parts.push(`(max: ${maxCount} messages)`);
|
|
4755
|
+
parts.push("(Ctrl+C to stop)");
|
|
4756
|
+
console.log(parts.join(" "));
|
|
4757
|
+
}
|
|
4758
|
+
let messageCount = 0;
|
|
4530
4759
|
let onDone;
|
|
4531
4760
|
const done = new Promise((r) => {
|
|
4532
4761
|
onDone = r;
|
|
4533
4762
|
});
|
|
4534
|
-
await sdk.connectWebSocket({
|
|
4763
|
+
const conn = await sdk.connectWebSocket({
|
|
4535
4764
|
baseUrl: config.baseUrl,
|
|
4536
4765
|
accessToken,
|
|
4537
4766
|
onMessage: (msg) => {
|
|
4538
|
-
|
|
4539
|
-
|
|
4767
|
+
messageCount++;
|
|
4768
|
+
if (jsonMode) {
|
|
4769
|
+
console.log(JSON.stringify(msg));
|
|
4770
|
+
} else {
|
|
4771
|
+
const { text, level } = sdk.formatWsMessage(msg);
|
|
4772
|
+
console.log(colorize2(level, text));
|
|
4773
|
+
}
|
|
4774
|
+
if (maxCount && messageCount >= maxCount) {
|
|
4775
|
+
if (!jsonMode) console.log(chalk2__default.default.dim(`
|
|
4776
|
+
Reached ${maxCount} messages, closing.`));
|
|
4777
|
+
conn.close();
|
|
4778
|
+
}
|
|
4540
4779
|
},
|
|
4541
4780
|
onClose: (code, reason) => {
|
|
4542
|
-
|
|
4543
|
-
|
|
4781
|
+
if (!jsonMode) {
|
|
4782
|
+
console.log(
|
|
4783
|
+
chalk2__default.default.yellow(`
|
|
4544
4784
|
Connection closed (code ${code}${reason ? ": " + reason : ""})`)
|
|
4545
|
-
|
|
4785
|
+
);
|
|
4786
|
+
}
|
|
4546
4787
|
onDone();
|
|
4547
4788
|
}
|
|
4548
4789
|
});
|
|
4790
|
+
let timer;
|
|
4791
|
+
if (timeoutSec) {
|
|
4792
|
+
timer = setTimeout(() => {
|
|
4793
|
+
if (!jsonMode) console.log(chalk2__default.default.dim(`
|
|
4794
|
+
Timeout (${timeoutSec}s), closing.`));
|
|
4795
|
+
conn.close();
|
|
4796
|
+
}, timeoutSec * 1e3);
|
|
4797
|
+
}
|
|
4798
|
+
const sigintHandler = () => {
|
|
4799
|
+
if (timer) clearTimeout(timer);
|
|
4800
|
+
conn.close();
|
|
4801
|
+
};
|
|
4802
|
+
process.on("SIGINT", sigintHandler);
|
|
4549
4803
|
await done;
|
|
4804
|
+
if (timer) clearTimeout(timer);
|
|
4805
|
+
process.removeListener("SIGINT", sigintHandler);
|
|
4550
4806
|
})()
|
|
4551
4807
|
);
|
|
4552
4808
|
}
|
|
@@ -5373,6 +5629,326 @@ Updated to ${latest}.`);
|
|
|
5373
5629
|
success("Auto-update enabled. ARBI CLI will update automatically on login.");
|
|
5374
5630
|
});
|
|
5375
5631
|
}
|
|
5632
|
+
function registerQuickstartCommand(program2) {
|
|
5633
|
+
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) => {
|
|
5634
|
+
console.log("\nWelcome to ARBI CLI setup!\n");
|
|
5635
|
+
const { config, source } = store.resolveConfigWithFallbacks();
|
|
5636
|
+
if (url) {
|
|
5637
|
+
const domain = new URL(url).hostname;
|
|
5638
|
+
config.baseUrl = url.replace(/\/$/, "");
|
|
5639
|
+
config.deploymentDomain = domain;
|
|
5640
|
+
store.saveConfig(config);
|
|
5641
|
+
}
|
|
5642
|
+
const useDetected = await promptConfirm(`Use server ${config.baseUrl}?`, true);
|
|
5643
|
+
if (!useDetected) {
|
|
5644
|
+
const customUrl = await promptInput("Server URL");
|
|
5645
|
+
try {
|
|
5646
|
+
const domain = new URL(customUrl).hostname;
|
|
5647
|
+
config.baseUrl = customUrl.replace(/\/$/, "");
|
|
5648
|
+
config.deploymentDomain = domain;
|
|
5649
|
+
store.saveConfig(config);
|
|
5650
|
+
} catch {
|
|
5651
|
+
error("Invalid URL");
|
|
5652
|
+
process.exit(1);
|
|
5653
|
+
}
|
|
5654
|
+
} else if (source !== "config") {
|
|
5655
|
+
store.saveConfig(config);
|
|
5656
|
+
}
|
|
5657
|
+
dim(`Server: ${config.baseUrl}`);
|
|
5658
|
+
const action = await promptSelect("Do you have an account?", [
|
|
5659
|
+
{ name: "Yes, log me in", value: "login" },
|
|
5660
|
+
{ name: "No, register a new account", value: "register" }
|
|
5661
|
+
]);
|
|
5662
|
+
const arbiClient = client.createArbiClient({
|
|
5663
|
+
baseUrl: config.baseUrl,
|
|
5664
|
+
deploymentDomain: config.deploymentDomain,
|
|
5665
|
+
credentials: "omit"
|
|
5666
|
+
});
|
|
5667
|
+
await arbiClient.crypto.initSodium();
|
|
5668
|
+
let email;
|
|
5669
|
+
let password2;
|
|
5670
|
+
if (action === "register") {
|
|
5671
|
+
email = await promptInput("Email");
|
|
5672
|
+
password2 = await promptPassword("Password");
|
|
5673
|
+
const confirmPw = await promptPassword("Confirm password");
|
|
5674
|
+
if (password2 !== confirmPw) {
|
|
5675
|
+
error("Passwords do not match.");
|
|
5676
|
+
process.exit(1);
|
|
5677
|
+
}
|
|
5678
|
+
const codeMethod = await promptSelect("Verification method", [
|
|
5679
|
+
{ name: "I have an invitation code", value: "code" },
|
|
5680
|
+
{ name: "Send me a verification email", value: "email" }
|
|
5681
|
+
]);
|
|
5682
|
+
let verificationCode;
|
|
5683
|
+
if (codeMethod === "code") {
|
|
5684
|
+
verificationCode = await promptInput("Invitation code");
|
|
5685
|
+
} else {
|
|
5686
|
+
console.log("Sending verification email...");
|
|
5687
|
+
const verifyResponse = await arbiClient.fetch.POST("/v1/user/verify-email", {
|
|
5688
|
+
body: { email }
|
|
5689
|
+
});
|
|
5690
|
+
if (verifyResponse.error) {
|
|
5691
|
+
error(`Failed to send verification email: ${JSON.stringify(verifyResponse.error)}`);
|
|
5692
|
+
process.exit(1);
|
|
5693
|
+
}
|
|
5694
|
+
success("Verification email sent. Check your inbox.");
|
|
5695
|
+
verificationCode = await promptInput("Verification code");
|
|
5696
|
+
}
|
|
5697
|
+
try {
|
|
5698
|
+
const firstName = await promptInput("First name", false) || "User";
|
|
5699
|
+
const lastName = await promptInput("Last name", false) || "";
|
|
5700
|
+
await arbiClient.auth.register({
|
|
5701
|
+
email,
|
|
5702
|
+
password: password2,
|
|
5703
|
+
verificationCode,
|
|
5704
|
+
firstName,
|
|
5705
|
+
lastName
|
|
5706
|
+
});
|
|
5707
|
+
success(`Registered as ${email}`);
|
|
5708
|
+
} catch (err) {
|
|
5709
|
+
error(`Registration failed: ${sdk.getErrorMessage(err)}`);
|
|
5710
|
+
process.exit(1);
|
|
5711
|
+
}
|
|
5712
|
+
} else {
|
|
5713
|
+
email = await promptInput("Email");
|
|
5714
|
+
password2 = await promptPassword("Password");
|
|
5715
|
+
}
|
|
5716
|
+
try {
|
|
5717
|
+
const { arbi } = await sdk.performPasswordLogin(config, email, password2, store);
|
|
5718
|
+
success(`Logged in as ${email}`);
|
|
5719
|
+
const { data: workspaces2 } = await arbi.fetch.GET("/v1/user/workspaces");
|
|
5720
|
+
const wsList = workspaces2 || [];
|
|
5721
|
+
const memberWorkspaces = wsList.filter((ws) => ws.users?.some((u) => u.email === email));
|
|
5722
|
+
let workspaceId;
|
|
5723
|
+
let workspaceName;
|
|
5724
|
+
if (memberWorkspaces.length === 0) {
|
|
5725
|
+
console.log("Creating your first workspace...");
|
|
5726
|
+
const ws = await sdk.workspaces.createWorkspace(arbi, "My Workspace");
|
|
5727
|
+
workspaceId = ws.external_id;
|
|
5728
|
+
workspaceName = ws.name;
|
|
5729
|
+
} else {
|
|
5730
|
+
const choices = [
|
|
5731
|
+
...sdk.formatWorkspaceChoices(memberWorkspaces),
|
|
5732
|
+
{ name: "+ Create new workspace", value: "__new__", description: "" }
|
|
5733
|
+
];
|
|
5734
|
+
const selected = await promptSelect("Select workspace", choices);
|
|
5735
|
+
if (selected === "__new__") {
|
|
5736
|
+
const name = await promptInput("Workspace name", false) || "My Workspace";
|
|
5737
|
+
const ws = await sdk.workspaces.createWorkspace(arbi, name);
|
|
5738
|
+
workspaceId = ws.external_id;
|
|
5739
|
+
workspaceName = ws.name;
|
|
5740
|
+
} else {
|
|
5741
|
+
workspaceId = selected;
|
|
5742
|
+
workspaceName = memberWorkspaces.find((w) => w.external_id === selected)?.name || "";
|
|
5743
|
+
}
|
|
5744
|
+
}
|
|
5745
|
+
updateConfig({ selectedWorkspaceId: workspaceId });
|
|
5746
|
+
console.log("");
|
|
5747
|
+
success("Setup complete!");
|
|
5748
|
+
console.log("");
|
|
5749
|
+
console.log(` Server: ${ref(config.baseUrl)}`);
|
|
5750
|
+
console.log(` Account: ${ref(email)}`);
|
|
5751
|
+
console.log(` Workspace: ${workspaceName} (${ref(workspaceId)})`);
|
|
5752
|
+
console.log("");
|
|
5753
|
+
dim('Try: arbi ask "hello"');
|
|
5754
|
+
} catch (err) {
|
|
5755
|
+
error(`Login failed: ${sdk.getErrorMessage(err)}`);
|
|
5756
|
+
process.exit(1);
|
|
5757
|
+
}
|
|
5758
|
+
});
|
|
5759
|
+
}
|
|
5760
|
+
var CENTRAL_API_URL2 = "https://central.arbi.work";
|
|
5761
|
+
var DEFAULT_PASSWORD = "agent-dev-1234";
|
|
5762
|
+
async function getVerificationCode2(email, apiKey) {
|
|
5763
|
+
const params = new URLSearchParams({ email });
|
|
5764
|
+
const res = await fetch(`${CENTRAL_API_URL2}/license-management/verify-ci?${params.toString()}`, {
|
|
5765
|
+
method: "GET",
|
|
5766
|
+
headers: { "x-api-key": apiKey }
|
|
5767
|
+
});
|
|
5768
|
+
if (!res.ok) {
|
|
5769
|
+
const body = await res.text().catch(() => "");
|
|
5770
|
+
throw new Error(`Failed to get verification code: ${res.status} ${body}`);
|
|
5771
|
+
}
|
|
5772
|
+
const data = await res.json();
|
|
5773
|
+
const words = data?.verification_words ?? data?.verification_code ?? null;
|
|
5774
|
+
if (!words) throw new Error("No verification code in response");
|
|
5775
|
+
return Array.isArray(words) ? words.join(" ") : String(words);
|
|
5776
|
+
}
|
|
5777
|
+
function registerAgentCreateCommand(program2) {
|
|
5778
|
+
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(
|
|
5779
|
+
async (url, opts) => {
|
|
5780
|
+
const { config, source } = store.resolveConfigWithFallbacks();
|
|
5781
|
+
if (url) {
|
|
5782
|
+
const domain = new URL(url).hostname;
|
|
5783
|
+
config.baseUrl = url.replace(/\/$/, "");
|
|
5784
|
+
config.deploymentDomain = domain;
|
|
5785
|
+
store.saveConfig(config);
|
|
5786
|
+
dim(`Server: ${config.baseUrl}`);
|
|
5787
|
+
} else {
|
|
5788
|
+
dim(`Server: ${config.baseUrl} (from ${source})`);
|
|
5789
|
+
}
|
|
5790
|
+
const supportApiKey = process.env.SUPPORT_API_KEY;
|
|
5791
|
+
if (!supportApiKey) {
|
|
5792
|
+
error(
|
|
5793
|
+
"SUPPORT_API_KEY is required.\nSet it with: export SUPPORT_API_KEY=<key>\nOr source from .env: source .env && arbi agent-create"
|
|
5794
|
+
);
|
|
5795
|
+
process.exit(1);
|
|
5796
|
+
}
|
|
5797
|
+
const timestamp2 = Date.now();
|
|
5798
|
+
let email = opts.email || `agent-${timestamp2}@${config.deploymentDomain}`;
|
|
5799
|
+
if (!email.includes("@")) {
|
|
5800
|
+
email = `${email}@${config.deploymentDomain}`;
|
|
5801
|
+
}
|
|
5802
|
+
dim(`Email: ${email}`);
|
|
5803
|
+
const arbiClient = client.createArbiClient({
|
|
5804
|
+
baseUrl: config.baseUrl,
|
|
5805
|
+
deploymentDomain: config.deploymentDomain,
|
|
5806
|
+
credentials: "omit"
|
|
5807
|
+
});
|
|
5808
|
+
await arbiClient.crypto.initSodium();
|
|
5809
|
+
const verifyResponse = await arbiClient.fetch.POST("/v1/user/verify-email", {
|
|
5810
|
+
body: { email }
|
|
5811
|
+
});
|
|
5812
|
+
if (verifyResponse.error) {
|
|
5813
|
+
error(`verify-email failed: ${JSON.stringify(verifyResponse.error)}`);
|
|
5814
|
+
process.exit(1);
|
|
5815
|
+
}
|
|
5816
|
+
let verificationCode;
|
|
5817
|
+
try {
|
|
5818
|
+
verificationCode = await getVerificationCode2(email, supportApiKey);
|
|
5819
|
+
} catch (err) {
|
|
5820
|
+
error(`Failed to get verification code: ${sdk.getErrorMessage(err)}`);
|
|
5821
|
+
process.exit(1);
|
|
5822
|
+
}
|
|
5823
|
+
try {
|
|
5824
|
+
await arbiClient.auth.register({
|
|
5825
|
+
email,
|
|
5826
|
+
password: opts.password,
|
|
5827
|
+
verificationCode,
|
|
5828
|
+
firstName: "Agent",
|
|
5829
|
+
lastName: `${timestamp2}`
|
|
5830
|
+
});
|
|
5831
|
+
} catch (err) {
|
|
5832
|
+
error(`Registration failed: ${sdk.getErrorMessage(err)}`);
|
|
5833
|
+
process.exit(1);
|
|
5834
|
+
}
|
|
5835
|
+
try {
|
|
5836
|
+
const { arbi } = await sdk.performPasswordLogin(config, email, opts.password, store);
|
|
5837
|
+
const ws = await sdk.workspaces.createWorkspace(arbi, opts.workspaceName);
|
|
5838
|
+
updateConfig({ selectedWorkspaceId: ws.external_id });
|
|
5839
|
+
console.log("");
|
|
5840
|
+
success("Agent account created!");
|
|
5841
|
+
console.log("");
|
|
5842
|
+
console.log(` Email: ${ref(email)}`);
|
|
5843
|
+
console.log(` Password: ${ref(opts.password)}`);
|
|
5844
|
+
console.log(` Workspace: ${ws.name} (${ref(ws.external_id)})`);
|
|
5845
|
+
console.log(` Server: ${ref(config.baseUrl)}`);
|
|
5846
|
+
console.log("");
|
|
5847
|
+
dim('Ready to use: arbi ask "hello"');
|
|
5848
|
+
} catch (err) {
|
|
5849
|
+
error(`Post-registration setup failed: ${sdk.getErrorMessage(err)}`);
|
|
5850
|
+
process.exit(1);
|
|
5851
|
+
}
|
|
5852
|
+
}
|
|
5853
|
+
);
|
|
5854
|
+
}
|
|
5855
|
+
function formatAge(isoDate) {
|
|
5856
|
+
const ms = Date.now() - new Date(isoDate).getTime();
|
|
5857
|
+
if (ms < 6e4) return `${Math.round(ms / 1e3)}s`;
|
|
5858
|
+
if (ms < 36e5) return `${Math.round(ms / 6e4)}m`;
|
|
5859
|
+
if (ms < 864e5) return `${Math.round(ms / 36e5)}h`;
|
|
5860
|
+
return `${Math.round(ms / 864e5)}d`;
|
|
5861
|
+
}
|
|
5862
|
+
function resolveTaskId(taskIdArg) {
|
|
5863
|
+
if (taskIdArg) return taskIdArg;
|
|
5864
|
+
const latest = getLatestTask();
|
|
5865
|
+
if (!latest) {
|
|
5866
|
+
console.error(chalk2__default.default.red('No tasks found. Submit one with: arbi ask -b "your question"'));
|
|
5867
|
+
process.exit(1);
|
|
5868
|
+
}
|
|
5869
|
+
return latest.id;
|
|
5870
|
+
}
|
|
5871
|
+
function statusColor(s) {
|
|
5872
|
+
if (s === "completed") return chalk2__default.default.green(s);
|
|
5873
|
+
if (s === "failed") return chalk2__default.default.red(s);
|
|
5874
|
+
if (s === "queued" || s === "in_progress") return chalk2__default.default.yellow(s);
|
|
5875
|
+
return s;
|
|
5876
|
+
}
|
|
5877
|
+
function registerTaskCommand(program2) {
|
|
5878
|
+
const task = program2.command("task").description("Manage background tasks");
|
|
5879
|
+
task.action(async (_opts, cmd) => {
|
|
5880
|
+
await cmd.commands.find((c) => c.name() === "list").parseAsync([], { from: "user" });
|
|
5881
|
+
});
|
|
5882
|
+
task.command("list").description("List background tasks").action(
|
|
5883
|
+
() => runAction(async () => {
|
|
5884
|
+
const tasks = getTasks();
|
|
5885
|
+
if (tasks.length === 0) {
|
|
5886
|
+
console.log('No tasks. Submit one with: arbi ask -b "your question"');
|
|
5887
|
+
return;
|
|
5888
|
+
}
|
|
5889
|
+
printTable(
|
|
5890
|
+
[
|
|
5891
|
+
{ header: "ID", width: 20, value: (r) => r.id },
|
|
5892
|
+
{ header: "STATUS", width: 14, value: (r) => statusColor(r.status) },
|
|
5893
|
+
{ header: "QUESTION", width: 42, value: (r) => r.question },
|
|
5894
|
+
{ header: "AGE", width: 6, value: (r) => formatAge(r.submittedAt) }
|
|
5895
|
+
],
|
|
5896
|
+
tasks
|
|
5897
|
+
);
|
|
5898
|
+
})()
|
|
5899
|
+
);
|
|
5900
|
+
task.command("status [task-id]").description("Check current task status (defaults to most recent)").option("-w, --workspace <id>", "Workspace ID").option("--json", "Output in JSON format").action(
|
|
5901
|
+
(taskId, opts) => runAction(async () => {
|
|
5902
|
+
const id = resolveTaskId(taskId);
|
|
5903
|
+
const { accessToken, workspaceKeyHeader, config } = await resolveWorkspace(opts?.workspace);
|
|
5904
|
+
const result = await sdk.responses.getResponse(
|
|
5905
|
+
{ baseUrl: config.baseUrl, accessToken, workspaceKeyHeader },
|
|
5906
|
+
id
|
|
5907
|
+
);
|
|
5908
|
+
if (result.status === "completed" || result.status === "failed") {
|
|
5909
|
+
updateTaskStatus(id, result.status);
|
|
5910
|
+
}
|
|
5911
|
+
if (opts?.json) {
|
|
5912
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5913
|
+
} else {
|
|
5914
|
+
console.log(`${chalk2__default.default.bold("ID:")} ${result.id}`);
|
|
5915
|
+
console.log(`${chalk2__default.default.bold("Status:")} ${statusColor(result.status)}`);
|
|
5916
|
+
if (result.model) console.log(`${chalk2__default.default.bold("Model:")} ${result.model}`);
|
|
5917
|
+
if (result.usage) {
|
|
5918
|
+
console.log(`${chalk2__default.default.bold("Tokens:")} ${result.usage.total_tokens.toLocaleString()}`);
|
|
5919
|
+
}
|
|
5920
|
+
}
|
|
5921
|
+
})()
|
|
5922
|
+
);
|
|
5923
|
+
task.command("result [task-id]").description("Fetch and print the completed task result").option("-w, --workspace <id>", "Workspace ID").option("--json", "Output in JSON format").action(
|
|
5924
|
+
(taskId, opts) => runAction(async () => {
|
|
5925
|
+
const id = resolveTaskId(taskId);
|
|
5926
|
+
const { accessToken, workspaceKeyHeader, config } = await resolveWorkspace(opts?.workspace);
|
|
5927
|
+
const result = await sdk.responses.getResponse(
|
|
5928
|
+
{ baseUrl: config.baseUrl, accessToken, workspaceKeyHeader },
|
|
5929
|
+
id
|
|
5930
|
+
);
|
|
5931
|
+
if (result.status === "completed" || result.status === "failed") {
|
|
5932
|
+
updateTaskStatus(id, result.status);
|
|
5933
|
+
}
|
|
5934
|
+
if (opts?.json) {
|
|
5935
|
+
console.log(JSON.stringify(result, null, 2));
|
|
5936
|
+
return;
|
|
5937
|
+
}
|
|
5938
|
+
if (result.status !== "completed") {
|
|
5939
|
+
console.error(
|
|
5940
|
+
chalk2__default.default.yellow(`Task is ${result.status}. Use \`arbi task status\` to check progress.`)
|
|
5941
|
+
);
|
|
5942
|
+
process.exit(1);
|
|
5943
|
+
}
|
|
5944
|
+
const text = sdk.responses.extractResponseText(result);
|
|
5945
|
+
process.stdout.write(text + "\n");
|
|
5946
|
+
if (result.usage) {
|
|
5947
|
+
console.error(chalk2__default.default.dim(`[${result.usage.total_tokens.toLocaleString()} tokens]`));
|
|
5948
|
+
}
|
|
5949
|
+
})()
|
|
5950
|
+
);
|
|
5951
|
+
}
|
|
5376
5952
|
|
|
5377
5953
|
// src/index.ts
|
|
5378
5954
|
console.debug = () => {
|
|
@@ -5383,7 +5959,7 @@ console.info = (...args) => {
|
|
|
5383
5959
|
_origInfo(...args);
|
|
5384
5960
|
};
|
|
5385
5961
|
var program = new commander.Command();
|
|
5386
|
-
program.name("arbi").description("ARBI CLI \u2014 interact with ARBI from the terminal").version("0.3.
|
|
5962
|
+
program.name("arbi").description("ARBI CLI \u2014 interact with ARBI from the terminal").version("0.3.14");
|
|
5387
5963
|
registerConfigCommand(program);
|
|
5388
5964
|
registerLoginCommand(program);
|
|
5389
5965
|
registerRegisterCommand(program);
|
|
@@ -5405,6 +5981,9 @@ registerAgentconfigCommand(program);
|
|
|
5405
5981
|
registerHealthCommand(program);
|
|
5406
5982
|
registerTuiCommand(program);
|
|
5407
5983
|
registerUpdateCommand(program);
|
|
5984
|
+
registerQuickstartCommand(program);
|
|
5985
|
+
registerAgentCreateCommand(program);
|
|
5986
|
+
registerTaskCommand(program);
|
|
5408
5987
|
program.parse();
|
|
5409
5988
|
//# sourceMappingURL=index.js.map
|
|
5410
5989
|
//# sourceMappingURL=index.js.map
|