@arbidocs/cli 0.3.15 → 0.3.17
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 +43 -0
- package/dist/index.js +665 -387
- package/dist/index.js.map +1 -1
- package/package.json +8 -5
- package/scripts/postinstall.js +56 -0
- package/scripts/preuninstall.js +35 -0
package/dist/index.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var commander = require('commander');
|
|
5
|
-
var
|
|
6
|
-
var os = require('os');
|
|
5
|
+
var fs2 = require('fs');
|
|
7
6
|
var path = require('path');
|
|
7
|
+
var os = require('os');
|
|
8
8
|
var chalk2 = require('chalk');
|
|
9
9
|
var sdk = require('@arbidocs/sdk');
|
|
10
10
|
var prompts = require('@inquirer/prompts');
|
|
@@ -15,11 +15,104 @@ var module$1 = require('module');
|
|
|
15
15
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
16
16
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
17
17
|
|
|
18
|
-
var
|
|
19
|
-
var os__default = /*#__PURE__*/_interopDefault(os);
|
|
18
|
+
var fs2__default = /*#__PURE__*/_interopDefault(fs2);
|
|
20
19
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
20
|
+
var os__default = /*#__PURE__*/_interopDefault(os);
|
|
21
21
|
var chalk2__default = /*#__PURE__*/_interopDefault(chalk2);
|
|
22
22
|
|
|
23
|
+
function getCacheFile() {
|
|
24
|
+
const configDir = process.env.ARBI_CONFIG_DIR ?? path__default.default.join(os__default.default.homedir(), ".arbi");
|
|
25
|
+
return path__default.default.join(configDir, "completions.json");
|
|
26
|
+
}
|
|
27
|
+
function ensureDir(filePath) {
|
|
28
|
+
const dir = path__default.default.dirname(filePath);
|
|
29
|
+
if (!fs2__default.default.existsSync(dir)) {
|
|
30
|
+
fs2__default.default.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function getCachedWorkspaceIds() {
|
|
34
|
+
try {
|
|
35
|
+
const content = fs2__default.default.readFileSync(getCacheFile(), "utf-8");
|
|
36
|
+
const cache = JSON.parse(content);
|
|
37
|
+
return cache.workspaces.map((w) => w.id);
|
|
38
|
+
} catch {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function updateCompletionCache(workspaces3) {
|
|
43
|
+
const cache = {
|
|
44
|
+
workspaces: workspaces3.filter((w) => w.external_id).map((w) => ({ id: w.external_id, name: w.name ?? "" })),
|
|
45
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
46
|
+
};
|
|
47
|
+
const filePath = getCacheFile();
|
|
48
|
+
ensureDir(filePath);
|
|
49
|
+
fs2__default.default.writeFileSync(filePath, JSON.stringify(cache, null, 2) + "\n", { mode: 384 });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/completion.ts
|
|
53
|
+
var WORKSPACE_ID_OPTIONS = /* @__PURE__ */ new Set(["-w", "--workspace"]);
|
|
54
|
+
function getOptionFlags(cmd) {
|
|
55
|
+
const flags = [];
|
|
56
|
+
for (const opt of cmd.options) {
|
|
57
|
+
if (opt.short) flags.push(opt.short);
|
|
58
|
+
if (opt.long) flags.push(opt.long);
|
|
59
|
+
}
|
|
60
|
+
return flags;
|
|
61
|
+
}
|
|
62
|
+
function findOption(cmd, flag) {
|
|
63
|
+
return cmd.options.find((o) => o.short === flag || o.long === flag);
|
|
64
|
+
}
|
|
65
|
+
function getCompletions(program2, line) {
|
|
66
|
+
const parts = line.trim().split(/\s+/);
|
|
67
|
+
if (parts.length > 0) {
|
|
68
|
+
const first = parts[0];
|
|
69
|
+
if (first === program2.name() || first.endsWith("/" + program2.name())) {
|
|
70
|
+
parts.shift();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const endsWithSpace = line.endsWith(" ");
|
|
74
|
+
let current = program2;
|
|
75
|
+
let consumed = 0;
|
|
76
|
+
for (let i = 0; i < parts.length; i++) {
|
|
77
|
+
const word = parts[i];
|
|
78
|
+
const sub = current.commands.find(
|
|
79
|
+
(c) => c.name() === word || c.aliases().includes(word)
|
|
80
|
+
);
|
|
81
|
+
if (sub) {
|
|
82
|
+
current = sub;
|
|
83
|
+
consumed = i + 1;
|
|
84
|
+
} else {
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const remaining = parts.slice(consumed);
|
|
89
|
+
const lastWord = remaining.length > 0 ? remaining[remaining.length - 1] : "";
|
|
90
|
+
const prevWord = endsWithSpace ? remaining[remaining.length - 1] : remaining[remaining.length - 2];
|
|
91
|
+
if (prevWord && WORKSPACE_ID_OPTIONS.has(prevWord)) {
|
|
92
|
+
return getCachedWorkspaceIds();
|
|
93
|
+
}
|
|
94
|
+
const subcommands = current.commands.map((c) => c.name());
|
|
95
|
+
const options = getOptionFlags(current);
|
|
96
|
+
const allCandidates = [...subcommands, ...options];
|
|
97
|
+
if (remaining.length === 0 || endsWithSpace && remaining.length >= 0) {
|
|
98
|
+
if (endsWithSpace) {
|
|
99
|
+
const used = /* @__PURE__ */ new Set();
|
|
100
|
+
for (const part of remaining) {
|
|
101
|
+
if (part.startsWith("-")) {
|
|
102
|
+
used.add(part);
|
|
103
|
+
const opt = findOption(current, part);
|
|
104
|
+
if (opt) {
|
|
105
|
+
if (opt.short) used.add(opt.short);
|
|
106
|
+
if (opt.long) used.add(opt.long);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return allCandidates.filter((c) => !used.has(c));
|
|
111
|
+
}
|
|
112
|
+
return allCandidates;
|
|
113
|
+
}
|
|
114
|
+
return allCandidates.filter((c) => c.startsWith(lastWord));
|
|
115
|
+
}
|
|
23
116
|
var store = new sdk.FileConfigStore();
|
|
24
117
|
function getConfig() {
|
|
25
118
|
return store.getConfig();
|
|
@@ -51,6 +144,12 @@ function getCredentials() {
|
|
|
51
144
|
function deleteCredentials() {
|
|
52
145
|
store.deleteCredentials();
|
|
53
146
|
}
|
|
147
|
+
function saveLastMetadata(metadata) {
|
|
148
|
+
store.saveLastMetadata?.(metadata);
|
|
149
|
+
}
|
|
150
|
+
function loadLastMetadata() {
|
|
151
|
+
return store.loadLastMetadata?.() ?? null;
|
|
152
|
+
}
|
|
54
153
|
function getChatSession() {
|
|
55
154
|
return store.getChatSession();
|
|
56
155
|
}
|
|
@@ -98,8 +197,8 @@ function getShellRcPath() {
|
|
|
98
197
|
return path.join(os.homedir(), ".bashrc");
|
|
99
198
|
}
|
|
100
199
|
function isAliasInstalled(rcPath) {
|
|
101
|
-
if (!
|
|
102
|
-
const content =
|
|
200
|
+
if (!fs2.existsSync(rcPath)) return false;
|
|
201
|
+
const content = fs2.readFileSync(rcPath, "utf-8");
|
|
103
202
|
return content.includes(ALIAS_LINE) || content.includes(ALIAS_MARKER);
|
|
104
203
|
}
|
|
105
204
|
function registerConfigCommand(program2) {
|
|
@@ -178,7 +277,7 @@ function registerConfigCommand(program2) {
|
|
|
178
277
|
dim("Usage: A what is the meaning of life");
|
|
179
278
|
return;
|
|
180
279
|
}
|
|
181
|
-
|
|
280
|
+
fs2.appendFileSync(rcPath, `
|
|
182
281
|
${ALIAS_MARKER}
|
|
183
282
|
${ALIAS_LINE}
|
|
184
283
|
`);
|
|
@@ -3504,7 +3603,7 @@ var CACHE_FILE = path__default.default.join(os__default.default.homedir(), ".arb
|
|
|
3504
3603
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
3505
3604
|
function readCache() {
|
|
3506
3605
|
try {
|
|
3507
|
-
const data = JSON.parse(
|
|
3606
|
+
const data = JSON.parse(fs2__default.default.readFileSync(CACHE_FILE, "utf8"));
|
|
3508
3607
|
if (data.latest && data.checkedAt && Date.now() - data.checkedAt < CACHE_TTL_MS) {
|
|
3509
3608
|
return data;
|
|
3510
3609
|
}
|
|
@@ -3515,8 +3614,8 @@ function readCache() {
|
|
|
3515
3614
|
function writeCache(latest) {
|
|
3516
3615
|
try {
|
|
3517
3616
|
const dir = path__default.default.dirname(CACHE_FILE);
|
|
3518
|
-
if (!
|
|
3519
|
-
|
|
3617
|
+
if (!fs2__default.default.existsSync(dir)) fs2__default.default.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
3618
|
+
fs2__default.default.writeFileSync(CACHE_FILE, JSON.stringify({ latest, checkedAt: Date.now() }) + "\n");
|
|
3520
3619
|
} catch {
|
|
3521
3620
|
}
|
|
3522
3621
|
}
|
|
@@ -3537,13 +3636,13 @@ function getLatestVersion(skipCache = false) {
|
|
|
3537
3636
|
}
|
|
3538
3637
|
}
|
|
3539
3638
|
function getCurrentVersion() {
|
|
3540
|
-
return "0.3.
|
|
3639
|
+
return "0.3.17";
|
|
3541
3640
|
}
|
|
3542
3641
|
function readChangelog(fromVersion, toVersion) {
|
|
3543
3642
|
try {
|
|
3544
3643
|
const globalRoot = child_process.execSync("npm root -g", { encoding: "utf8", timeout: 5e3 }).trim();
|
|
3545
3644
|
const changelogPath = path__default.default.join(globalRoot, "@arbidocs", "cli", "CHANGELOG.md");
|
|
3546
|
-
const text =
|
|
3645
|
+
const text = fs2__default.default.readFileSync(changelogPath, "utf8");
|
|
3547
3646
|
return extractSections(text, fromVersion, toVersion);
|
|
3548
3647
|
} catch {
|
|
3549
3648
|
return null;
|
|
@@ -3590,17 +3689,17 @@ function showChangelog(fromVersion, toVersion) {
|
|
|
3590
3689
|
async function checkForUpdates(autoUpdate) {
|
|
3591
3690
|
try {
|
|
3592
3691
|
const latest = getLatestVersion();
|
|
3593
|
-
if (!latest || latest === "0.3.
|
|
3692
|
+
if (!latest || latest === "0.3.17") return;
|
|
3594
3693
|
if (autoUpdate) {
|
|
3595
3694
|
warn(`
|
|
3596
|
-
Your arbi version is out of date (${"0.3.
|
|
3695
|
+
Your arbi version is out of date (${"0.3.17"} \u2192 ${latest}). Updating...`);
|
|
3597
3696
|
child_process.execSync("npm install -g @arbidocs/cli@latest", { stdio: "inherit" });
|
|
3598
|
-
showChangelog("0.3.
|
|
3697
|
+
showChangelog("0.3.17", latest);
|
|
3599
3698
|
console.log(`Updated to ${latest}.`);
|
|
3600
3699
|
} else {
|
|
3601
3700
|
warn(
|
|
3602
3701
|
`
|
|
3603
|
-
Your arbi version is out of date (${"0.3.
|
|
3702
|
+
Your arbi version is out of date (${"0.3.17"} \u2192 ${latest}).
|
|
3604
3703
|
Run "arbi update" to upgrade, or "arbi update auto" to always stay up to date.`
|
|
3605
3704
|
);
|
|
3606
3705
|
}
|
|
@@ -3610,150 +3709,359 @@ Run "arbi update" to upgrade, or "arbi update auto" to always stay up to date.`
|
|
|
3610
3709
|
function hintUpdateOnError() {
|
|
3611
3710
|
try {
|
|
3612
3711
|
const cached = readCache();
|
|
3613
|
-
if (cached && cached.latest !== "0.3.
|
|
3712
|
+
if (cached && cached.latest !== "0.3.17") {
|
|
3614
3713
|
warn(
|
|
3615
|
-
`Your arbi version is out of date (${"0.3.
|
|
3714
|
+
`Your arbi version is out of date (${"0.3.17"} \u2192 ${cached.latest}). Run "arbi update".`
|
|
3616
3715
|
);
|
|
3617
3716
|
}
|
|
3618
3717
|
} catch {
|
|
3619
3718
|
}
|
|
3620
3719
|
}
|
|
3720
|
+
var MAX_TASKS = 50;
|
|
3721
|
+
var MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
3722
|
+
function getTasksFile() {
|
|
3723
|
+
const configDir = process.env.ARBI_CONFIG_DIR ?? path__default.default.join(os__default.default.homedir(), ".arbi");
|
|
3724
|
+
return path__default.default.join(configDir, "tasks.json");
|
|
3725
|
+
}
|
|
3726
|
+
function ensureDir2(filePath) {
|
|
3727
|
+
const dir = path__default.default.dirname(filePath);
|
|
3728
|
+
if (!fs2__default.default.existsSync(dir)) {
|
|
3729
|
+
fs2__default.default.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
3730
|
+
}
|
|
3731
|
+
}
|
|
3732
|
+
function readTasks() {
|
|
3733
|
+
try {
|
|
3734
|
+
const content = fs2__default.default.readFileSync(getTasksFile(), "utf-8");
|
|
3735
|
+
return JSON.parse(content);
|
|
3736
|
+
} catch {
|
|
3737
|
+
return [];
|
|
3738
|
+
}
|
|
3739
|
+
}
|
|
3740
|
+
function writeTasks(tasks) {
|
|
3741
|
+
const filePath = getTasksFile();
|
|
3742
|
+
ensureDir2(filePath);
|
|
3743
|
+
fs2__default.default.writeFileSync(filePath, JSON.stringify(tasks, null, 2) + "\n", { mode: 384 });
|
|
3744
|
+
}
|
|
3745
|
+
function getTasks() {
|
|
3746
|
+
const now = Date.now();
|
|
3747
|
+
const tasks = readTasks().filter((t) => now - new Date(t.submittedAt).getTime() < MAX_AGE_MS);
|
|
3748
|
+
return tasks;
|
|
3749
|
+
}
|
|
3750
|
+
function addTask(task) {
|
|
3751
|
+
const tasks = [task, ...getTasks().filter((t) => t.id !== task.id)].slice(0, MAX_TASKS);
|
|
3752
|
+
writeTasks(tasks);
|
|
3753
|
+
}
|
|
3754
|
+
function updateTaskStatus(id, status2) {
|
|
3755
|
+
const tasks = readTasks();
|
|
3756
|
+
const task = tasks.find((t) => t.id === id);
|
|
3757
|
+
if (task) {
|
|
3758
|
+
task.status = status2;
|
|
3759
|
+
writeTasks(tasks);
|
|
3760
|
+
}
|
|
3761
|
+
}
|
|
3762
|
+
function getLatestTask() {
|
|
3763
|
+
const tasks = getTasks();
|
|
3764
|
+
return tasks[0] ?? null;
|
|
3765
|
+
}
|
|
3621
3766
|
|
|
3622
|
-
// src/
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
if (
|
|
3641
|
-
|
|
3642
|
-
process.exit(1);
|
|
3767
|
+
// src/notifications.ts
|
|
3768
|
+
var activeConnection = null;
|
|
3769
|
+
function timestamp() {
|
|
3770
|
+
return (/* @__PURE__ */ new Date()).toLocaleTimeString("en-GB", { hour12: false });
|
|
3771
|
+
}
|
|
3772
|
+
function colorize(level, text) {
|
|
3773
|
+
if (level === "success") return chalk2__default.default.green(text);
|
|
3774
|
+
if (level === "error") return chalk2__default.default.red(text);
|
|
3775
|
+
if (level === "warning") return chalk2__default.default.yellow(text);
|
|
3776
|
+
return text;
|
|
3777
|
+
}
|
|
3778
|
+
async function startBackgroundNotifications(baseUrl, accessToken) {
|
|
3779
|
+
if (activeConnection) return;
|
|
3780
|
+
try {
|
|
3781
|
+
activeConnection = await sdk.connectWithReconnect({
|
|
3782
|
+
baseUrl,
|
|
3783
|
+
accessToken,
|
|
3784
|
+
onMessage: (msg) => {
|
|
3785
|
+
if (client.isMessageType(msg, "response_complete")) {
|
|
3786
|
+
updateTaskStatus(msg.response_id, msg.status);
|
|
3643
3787
|
}
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3788
|
+
const { text, level } = sdk.formatWsMessage(msg);
|
|
3789
|
+
process.stderr.write(`
|
|
3790
|
+
${colorize(level, `[${timestamp()}] ${text}`)}
|
|
3791
|
+
`);
|
|
3792
|
+
},
|
|
3793
|
+
onClose: () => {
|
|
3794
|
+
activeConnection = null;
|
|
3795
|
+
},
|
|
3796
|
+
onReconnecting: (attempt, maxRetries) => {
|
|
3797
|
+
process.stderr.write(
|
|
3798
|
+
`
|
|
3799
|
+
${chalk2__default.default.yellow(`[${timestamp()}] Reconnecting... (${attempt}/${maxRetries})`)}
|
|
3800
|
+
`
|
|
3652
3801
|
);
|
|
3653
|
-
|
|
3802
|
+
},
|
|
3803
|
+
onReconnected: () => {
|
|
3804
|
+
process.stderr.write(`
|
|
3805
|
+
${chalk2__default.default.green(`[${timestamp()}] Reconnected`)}
|
|
3806
|
+
`);
|
|
3807
|
+
},
|
|
3808
|
+
onReconnectFailed: () => {
|
|
3809
|
+
process.stderr.write(`
|
|
3810
|
+
${chalk2__default.default.red(`[${timestamp()}] Reconnection failed`)}
|
|
3811
|
+
`);
|
|
3654
3812
|
}
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
updateConfig({ selectedWorkspaceId: selected });
|
|
3658
|
-
const ws = memberWorkspaces.find((w) => w.external_id === selected);
|
|
3659
|
-
success(`Workspace: ${ws.name} (${ref(selected)})`);
|
|
3660
|
-
dim('\nTip: Run "arbi config alias" to use A as a shortcut for "arbi ask"');
|
|
3661
|
-
} catch (err) {
|
|
3662
|
-
error(`Login failed: ${sdk.getErrorMessage(err)}`);
|
|
3663
|
-
process.exit(1);
|
|
3664
|
-
} finally {
|
|
3665
|
-
await checkForUpdates(getConfig()?.autoUpdate);
|
|
3666
|
-
}
|
|
3667
|
-
});
|
|
3668
|
-
}
|
|
3669
|
-
var CENTRAL_API_URL = "https://central.arbi.work";
|
|
3670
|
-
async function getVerificationCode(email, apiKey) {
|
|
3671
|
-
const params = new URLSearchParams({ email });
|
|
3672
|
-
const res = await fetch(`${CENTRAL_API_URL}/license-management/verify-ci?${params.toString()}`, {
|
|
3673
|
-
method: "GET",
|
|
3674
|
-
headers: { "x-api-key": apiKey }
|
|
3675
|
-
});
|
|
3676
|
-
if (!res.ok) {
|
|
3677
|
-
const body = await res.text().catch(() => "");
|
|
3678
|
-
throw new Error(`Failed to get verification code: ${res.status} ${body}`);
|
|
3813
|
+
});
|
|
3814
|
+
} catch {
|
|
3679
3815
|
}
|
|
3680
|
-
const data = await res.json();
|
|
3681
|
-
const words = data?.verification_words ?? data?.verification_code ?? null;
|
|
3682
|
-
if (!words) throw new Error("No verification code in response");
|
|
3683
|
-
return Array.isArray(words) ? words.join(" ") : String(words);
|
|
3684
3816
|
}
|
|
3685
|
-
function
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
if (opts.nonInteractive) {
|
|
3689
|
-
await nonInteractiveRegister(config, opts);
|
|
3690
|
-
} else {
|
|
3691
|
-
await smartRegister(config, opts);
|
|
3692
|
-
}
|
|
3693
|
-
});
|
|
3817
|
+
function stopBackgroundNotifications() {
|
|
3818
|
+
activeConnection?.close();
|
|
3819
|
+
activeConnection = null;
|
|
3694
3820
|
}
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3821
|
+
process.on("exit", stopBackgroundNotifications);
|
|
3822
|
+
process.on("SIGINT", () => {
|
|
3823
|
+
stopBackgroundNotifications();
|
|
3824
|
+
process.exit(0);
|
|
3825
|
+
});
|
|
3826
|
+
|
|
3827
|
+
// src/helpers.ts
|
|
3828
|
+
var CONNECTION_ERROR_HINTS = {
|
|
3829
|
+
ECONNREFUSED: "Connection refused. Is the backend running?",
|
|
3830
|
+
ECONNRESET: "Connection reset by server. The backend may have restarted.",
|
|
3831
|
+
ENOTFOUND: "DNS resolution failed. Check the server URL.",
|
|
3832
|
+
ETIMEDOUT: "Connection timed out. Check network connectivity.",
|
|
3833
|
+
UNABLE_TO_VERIFY_LEAF_SIGNATURE: "TLS certificate cannot be verified. The cert may be expired or self-signed.",
|
|
3834
|
+
CERT_HAS_EXPIRED: "TLS certificate has expired. Renew with manage-deployment.",
|
|
3835
|
+
ERR_TLS_CERT_ALTNAME_INVALID: "TLS certificate hostname mismatch. Check the server URL.",
|
|
3836
|
+
DEPTH_ZERO_SELF_SIGNED_CERT: "Self-signed TLS certificate. The cert may need to be renewed.",
|
|
3837
|
+
SELF_SIGNED_CERT_IN_CHAIN: "Self-signed certificate in chain. The cert may need to be renewed."
|
|
3838
|
+
};
|
|
3839
|
+
function diagnoseConnectionError(err) {
|
|
3840
|
+
const code = sdk.getErrorCode(err);
|
|
3841
|
+
if (code && code in CONNECTION_ERROR_HINTS) {
|
|
3842
|
+
return CONNECTION_ERROR_HINTS[code];
|
|
3700
3843
|
}
|
|
3701
|
-
const
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
const
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
verificationCode = await promptInput("Invitation code");
|
|
3717
|
-
} else {
|
|
3718
|
-
console.log("Sending verification email...");
|
|
3719
|
-
const verifyResponse = await arbi.fetch.POST("/v1/user/verify-email", {
|
|
3720
|
-
body: { email }
|
|
3721
|
-
});
|
|
3722
|
-
if (verifyResponse.error) {
|
|
3723
|
-
error(`Failed to send verification email: ${JSON.stringify(verifyResponse.error)}`);
|
|
3724
|
-
process.exit(1);
|
|
3725
|
-
}
|
|
3726
|
-
success("Verification email sent. Check your inbox.");
|
|
3727
|
-
verificationCode = await promptInput("Verification code");
|
|
3844
|
+
const msg = err instanceof Error ? err.message : "";
|
|
3845
|
+
if (msg === "fetch failed" || msg.includes("fetch failed")) {
|
|
3846
|
+
return "Network error connecting to the server. Run `arbi health` to diagnose.";
|
|
3847
|
+
}
|
|
3848
|
+
return void 0;
|
|
3849
|
+
}
|
|
3850
|
+
function formatCliError(err) {
|
|
3851
|
+
const connectionHint = diagnoseConnectionError(err);
|
|
3852
|
+
if (connectionHint) return connectionHint;
|
|
3853
|
+
if (err instanceof sdk.ArbiApiError && err.apiError && typeof err.apiError === "object") {
|
|
3854
|
+
const base = err.message;
|
|
3855
|
+
const apiErr = err.apiError;
|
|
3856
|
+
const detail = apiErr.detail ?? apiErr.message ?? apiErr.error;
|
|
3857
|
+
if (typeof detail === "string" && detail && !base.includes(detail)) {
|
|
3858
|
+
return `${base} \u2014 ${detail}`;
|
|
3728
3859
|
}
|
|
3860
|
+
return base;
|
|
3729
3861
|
}
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
error(
|
|
3862
|
+
return sdk.getErrorMessage(err);
|
|
3863
|
+
}
|
|
3864
|
+
function runAction(fn) {
|
|
3865
|
+
return async () => {
|
|
3866
|
+
try {
|
|
3867
|
+
await fn();
|
|
3868
|
+
process.exit(0);
|
|
3869
|
+
} catch (err) {
|
|
3870
|
+
error(`Error: ${formatCliError(err)}`);
|
|
3871
|
+
hintUpdateOnError();
|
|
3739
3872
|
process.exit(1);
|
|
3740
3873
|
}
|
|
3741
|
-
}
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
const lastName = opts.lastName || (hasAllCoreFlags ? "" : await promptInput("Last name", false) || "");
|
|
3874
|
+
};
|
|
3875
|
+
}
|
|
3876
|
+
async function resolveAuth() {
|
|
3745
3877
|
try {
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3878
|
+
resolveConfig();
|
|
3879
|
+
return await sdk.resolveAuth(store);
|
|
3880
|
+
} catch (err) {
|
|
3881
|
+
if (err instanceof sdk.ArbiError) {
|
|
3882
|
+
error(err.message);
|
|
3883
|
+
process.exit(1);
|
|
3884
|
+
}
|
|
3885
|
+
throw err;
|
|
3886
|
+
}
|
|
3887
|
+
}
|
|
3888
|
+
async function resolveWorkspace(workspaceOpt) {
|
|
3889
|
+
try {
|
|
3890
|
+
resolveConfig();
|
|
3891
|
+
const ctx = await sdk.resolveWorkspace(store, workspaceOpt);
|
|
3892
|
+
if (getConfig()?.notifications !== false) {
|
|
3893
|
+
startBackgroundNotifications(ctx.config.baseUrl, ctx.accessToken).catch(() => {
|
|
3894
|
+
});
|
|
3895
|
+
}
|
|
3896
|
+
return ctx;
|
|
3897
|
+
} catch (err) {
|
|
3898
|
+
if (err instanceof sdk.ArbiError) {
|
|
3899
|
+
error(err.message);
|
|
3900
|
+
process.exit(1);
|
|
3901
|
+
}
|
|
3902
|
+
throw err;
|
|
3903
|
+
}
|
|
3904
|
+
}
|
|
3905
|
+
function printTable(columns, rows) {
|
|
3906
|
+
console.log(chalk2__default.default.bold(columns.map((c) => c.header.padEnd(c.width)).join("")));
|
|
3907
|
+
for (const row of rows) {
|
|
3908
|
+
console.log(
|
|
3909
|
+
columns.map((c) => {
|
|
3910
|
+
const val = c.value(row);
|
|
3911
|
+
return val.slice(0, c.width - 2).padEnd(c.width);
|
|
3912
|
+
}).join("")
|
|
3913
|
+
);
|
|
3914
|
+
}
|
|
3915
|
+
}
|
|
3916
|
+
function parseJsonArg(input2, example) {
|
|
3917
|
+
try {
|
|
3918
|
+
return JSON.parse(input2);
|
|
3919
|
+
} catch {
|
|
3920
|
+
error(`Invalid JSON. Example: ${example}`);
|
|
3921
|
+
process.exit(1);
|
|
3922
|
+
}
|
|
3923
|
+
}
|
|
3924
|
+
|
|
3925
|
+
// src/commands/login.ts
|
|
3926
|
+
function registerLoginCommand(program2) {
|
|
3927
|
+
program2.command("login").description("Log in to ARBI").option("-e, --email <email>", "Email address (or ARBI_EMAIL env var)").option("-p, --password <password>", "Password (or ARBI_PASSWORD env var)").option("-w, --workspace <id>", "Workspace ID to select after login").action(
|
|
3928
|
+
(opts) => runAction(async () => {
|
|
3929
|
+
const config = store.requireConfig();
|
|
3930
|
+
const email = opts.email || process.env.ARBI_EMAIL || await promptInput("Email");
|
|
3931
|
+
const pw = opts.password || process.env.ARBI_PASSWORD || await promptPassword("Password");
|
|
3932
|
+
try {
|
|
3933
|
+
const { arbi } = await sdk.performPasswordLogin(config, email, pw, store);
|
|
3934
|
+
clearChatSession();
|
|
3935
|
+
const { data: workspaces3 } = await arbi.fetch.GET("/v1/user/workspaces");
|
|
3936
|
+
const wsList = workspaces3 || [];
|
|
3937
|
+
updateCompletionCache(wsList);
|
|
3938
|
+
const memberWorkspaces = wsList.filter((ws2) => ws2.users?.some((u) => u.email === email));
|
|
3939
|
+
if (memberWorkspaces.length === 0) {
|
|
3940
|
+
console.log("No workspaces found. Create one with: arbi workspace create <name>");
|
|
3941
|
+
return;
|
|
3942
|
+
}
|
|
3943
|
+
if (opts.workspace) {
|
|
3944
|
+
const ws2 = memberWorkspaces.find((w) => w.external_id === opts.workspace);
|
|
3945
|
+
if (!ws2) {
|
|
3946
|
+
error(`Workspace ${opts.workspace} not found or you don't have access.`);
|
|
3947
|
+
process.exit(1);
|
|
3948
|
+
}
|
|
3949
|
+
updateConfig({ selectedWorkspaceId: ws2.external_id });
|
|
3950
|
+
success(`Workspace: ${ws2.name} (${ref(ws2.external_id)})`);
|
|
3951
|
+
return;
|
|
3952
|
+
}
|
|
3953
|
+
if (memberWorkspaces.length === 1) {
|
|
3954
|
+
updateConfig({ selectedWorkspaceId: memberWorkspaces[0].external_id });
|
|
3955
|
+
success(
|
|
3956
|
+
`Workspace: ${memberWorkspaces[0].name} (${ref(memberWorkspaces[0].external_id)})`
|
|
3957
|
+
);
|
|
3958
|
+
return;
|
|
3959
|
+
}
|
|
3960
|
+
const choices = sdk.formatWorkspaceChoices(memberWorkspaces);
|
|
3961
|
+
const selected = await promptSelect("Select workspace", choices);
|
|
3962
|
+
updateConfig({ selectedWorkspaceId: selected });
|
|
3963
|
+
const ws = memberWorkspaces.find((w) => w.external_id === selected);
|
|
3964
|
+
success(`Workspace: ${ws.name} (${ref(selected)})`);
|
|
3965
|
+
dim('\nTip: Run "arbi config alias" to use A as a shortcut for "arbi ask"');
|
|
3966
|
+
} catch (err) {
|
|
3967
|
+
error(`Login failed: ${formatCliError(err)}`);
|
|
3968
|
+
process.exit(1);
|
|
3969
|
+
} finally {
|
|
3970
|
+
await checkForUpdates(getConfig()?.autoUpdate);
|
|
3971
|
+
}
|
|
3972
|
+
})()
|
|
3973
|
+
);
|
|
3974
|
+
}
|
|
3975
|
+
var CENTRAL_API_URL = "https://central.arbi.work";
|
|
3976
|
+
async function getVerificationCode(email, apiKey) {
|
|
3977
|
+
const params = new URLSearchParams({ email });
|
|
3978
|
+
const res = await fetch(`${CENTRAL_API_URL}/license-management/verify-ci?${params.toString()}`, {
|
|
3979
|
+
method: "GET",
|
|
3980
|
+
headers: { "x-api-key": apiKey }
|
|
3981
|
+
});
|
|
3982
|
+
if (!res.ok) {
|
|
3983
|
+
const body = await res.text().catch(() => "");
|
|
3984
|
+
throw new Error(`Failed to get verification code: ${res.status} ${body}`);
|
|
3985
|
+
}
|
|
3986
|
+
const data = await res.json();
|
|
3987
|
+
const words = data?.verification_words ?? data?.verification_code ?? null;
|
|
3988
|
+
if (!words) throw new Error("No verification code in response");
|
|
3989
|
+
return Array.isArray(words) ? words.join(" ") : String(words);
|
|
3990
|
+
}
|
|
3991
|
+
function registerRegisterCommand(program2) {
|
|
3992
|
+
program2.command("register").description("Register a new ARBI account").option("--non-interactive", "CI/automation mode (requires SUPPORT_API_KEY env var)").option("-e, --email <email>", "Email address (or ARBI_EMAIL env var)").option("-p, --password <password>", "Password (or ARBI_PASSWORD env var)").option("-c, --verification-code <code>", "Verification code (skip prompt)").option("--first-name <name>", "First name").option("--last-name <name>", "Last name").action(
|
|
3993
|
+
(opts) => runAction(async () => {
|
|
3994
|
+
const config = requireConfig();
|
|
3995
|
+
if (opts.nonInteractive) {
|
|
3996
|
+
await nonInteractiveRegister(config, opts);
|
|
3997
|
+
} else {
|
|
3998
|
+
await smartRegister(config, opts);
|
|
3999
|
+
}
|
|
4000
|
+
})()
|
|
4001
|
+
);
|
|
4002
|
+
}
|
|
4003
|
+
async function smartRegister(config, opts) {
|
|
4004
|
+
let email = opts.email || process.env.ARBI_EMAIL || await promptInput("Email");
|
|
4005
|
+
if ((opts.email || process.env.ARBI_EMAIL) && !email.includes("@")) {
|
|
4006
|
+
email = `${email}@${config.deploymentDomain}`;
|
|
4007
|
+
console.log(`Using email: ${email}`);
|
|
4008
|
+
}
|
|
4009
|
+
const arbi = client.createArbiClient({
|
|
4010
|
+
baseUrl: config.baseUrl,
|
|
4011
|
+
deploymentDomain: config.deploymentDomain,
|
|
4012
|
+
credentials: "omit"
|
|
4013
|
+
});
|
|
4014
|
+
await arbi.crypto.initSodium();
|
|
4015
|
+
let verificationCode;
|
|
4016
|
+
if (opts.verificationCode) {
|
|
4017
|
+
verificationCode = opts.verificationCode;
|
|
4018
|
+
} else {
|
|
4019
|
+
const codeMethod = await promptSelect("Verification method", [
|
|
4020
|
+
{ name: "I have an invitation code", value: "code" },
|
|
4021
|
+
{ name: "Send me a verification email", value: "email" }
|
|
4022
|
+
]);
|
|
4023
|
+
if (codeMethod === "code") {
|
|
4024
|
+
verificationCode = await promptInput("Invitation code");
|
|
4025
|
+
} else {
|
|
4026
|
+
console.log("Sending verification email...");
|
|
4027
|
+
const verifyResponse = await arbi.fetch.POST("/v1/user/verify-email", {
|
|
4028
|
+
body: { email }
|
|
4029
|
+
});
|
|
4030
|
+
if (verifyResponse.error) {
|
|
4031
|
+
error(`Failed to send verification email: ${JSON.stringify(verifyResponse.error)}`);
|
|
4032
|
+
process.exit(1);
|
|
4033
|
+
}
|
|
4034
|
+
success("Verification email sent. Check your inbox.");
|
|
4035
|
+
verificationCode = await promptInput("Verification code");
|
|
4036
|
+
}
|
|
4037
|
+
}
|
|
4038
|
+
let pw;
|
|
4039
|
+
const flagOrEnvPassword = opts.password || process.env.ARBI_PASSWORD;
|
|
4040
|
+
if (flagOrEnvPassword) {
|
|
4041
|
+
pw = flagOrEnvPassword;
|
|
4042
|
+
} else {
|
|
4043
|
+
pw = await promptPassword("Password");
|
|
4044
|
+
const confirmPw = await promptPassword("Confirm password");
|
|
4045
|
+
if (pw !== confirmPw) {
|
|
4046
|
+
error("Passwords do not match.");
|
|
4047
|
+
process.exit(1);
|
|
4048
|
+
}
|
|
4049
|
+
}
|
|
4050
|
+
const hasAllCoreFlags = !!(opts.email || process.env.ARBI_EMAIL) && !!(opts.password || process.env.ARBI_PASSWORD) && !!opts.verificationCode;
|
|
4051
|
+
const firstName = opts.firstName || (hasAllCoreFlags ? "User" : await promptInput("First name", false) || "User");
|
|
4052
|
+
const lastName = opts.lastName || (hasAllCoreFlags ? "" : await promptInput("Last name", false) || "");
|
|
4053
|
+
try {
|
|
4054
|
+
await arbi.auth.register({
|
|
4055
|
+
email,
|
|
4056
|
+
password: pw,
|
|
4057
|
+
verificationCode,
|
|
4058
|
+
firstName,
|
|
3751
4059
|
lastName
|
|
3752
4060
|
});
|
|
3753
4061
|
success(`
|
|
3754
4062
|
Registered successfully as ${email}`);
|
|
3755
4063
|
} catch (err) {
|
|
3756
|
-
error(`Registration failed: ${
|
|
4064
|
+
error(`Registration failed: ${formatCliError(err)}`);
|
|
3757
4065
|
process.exit(1);
|
|
3758
4066
|
}
|
|
3759
4067
|
const allFlagsProvided = !!(opts.email || process.env.ARBI_EMAIL) && !!(opts.password || process.env.ARBI_PASSWORD) && !!opts.verificationCode;
|
|
@@ -3813,7 +4121,7 @@ async function nonInteractiveRegister(config, opts) {
|
|
|
3813
4121
|
});
|
|
3814
4122
|
success(`Registered: ${email}`);
|
|
3815
4123
|
} catch (err) {
|
|
3816
|
-
error(`Registration failed: ${
|
|
4124
|
+
error(`Registration failed: ${formatCliError(err)}`);
|
|
3817
4125
|
process.exit(1);
|
|
3818
4126
|
}
|
|
3819
4127
|
await loginAfterRegister(config, email, password2);
|
|
@@ -3822,8 +4130,9 @@ async function loginAfterRegister(config, email, password2) {
|
|
|
3822
4130
|
try {
|
|
3823
4131
|
const { arbi } = await sdk.performPasswordLogin(config, email, password2, store);
|
|
3824
4132
|
success(`Logged in as ${email}`);
|
|
3825
|
-
const { data:
|
|
3826
|
-
const wsList =
|
|
4133
|
+
const { data: workspaces3 } = await arbi.fetch.GET("/v1/user/workspaces");
|
|
4134
|
+
const wsList = workspaces3 || [];
|
|
4135
|
+
updateCompletionCache(wsList);
|
|
3827
4136
|
const memberWorkspaces = wsList.filter((ws2) => ws2.users?.some((u) => u.email === email));
|
|
3828
4137
|
if (memberWorkspaces.length === 0) {
|
|
3829
4138
|
console.log("Creating your first workspace...");
|
|
@@ -3843,7 +4152,7 @@ async function loginAfterRegister(config, email, password2) {
|
|
|
3843
4152
|
const ws = memberWorkspaces.find((w) => w.external_id === selected);
|
|
3844
4153
|
success(`Workspace: ${ws.name} (${ref(selected)})`);
|
|
3845
4154
|
} catch (err) {
|
|
3846
|
-
error(`Login failed: ${
|
|
4155
|
+
error(`Login failed: ${formatCliError(err)}`);
|
|
3847
4156
|
error("You can log in later with: arbi login");
|
|
3848
4157
|
}
|
|
3849
4158
|
}
|
|
@@ -3880,217 +4189,12 @@ function registerStatusCommand(program2) {
|
|
|
3880
4189
|
}
|
|
3881
4190
|
});
|
|
3882
4191
|
}
|
|
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
|
|
3931
|
-
var activeConnection = null;
|
|
3932
|
-
function timestamp() {
|
|
3933
|
-
return (/* @__PURE__ */ new Date()).toLocaleTimeString("en-GB", { hour12: false });
|
|
3934
|
-
}
|
|
3935
|
-
function colorize(level, text) {
|
|
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);
|
|
3939
|
-
return text;
|
|
3940
|
-
}
|
|
3941
|
-
async function startBackgroundNotifications(baseUrl, accessToken) {
|
|
3942
|
-
if (activeConnection) return;
|
|
3943
|
-
try {
|
|
3944
|
-
activeConnection = await sdk.connectWithReconnect({
|
|
3945
|
-
baseUrl,
|
|
3946
|
-
accessToken,
|
|
3947
|
-
onMessage: (msg) => {
|
|
3948
|
-
if (client.isMessageType(msg, "response_complete")) {
|
|
3949
|
-
updateTaskStatus(msg.response_id, msg.status);
|
|
3950
|
-
}
|
|
3951
|
-
const { text, level } = sdk.formatWsMessage(msg);
|
|
3952
|
-
process.stderr.write(`
|
|
3953
|
-
${colorize(level, `[${timestamp()}] ${text}`)}
|
|
3954
|
-
`);
|
|
3955
|
-
},
|
|
3956
|
-
onClose: () => {
|
|
3957
|
-
activeConnection = null;
|
|
3958
|
-
},
|
|
3959
|
-
onReconnecting: (attempt, maxRetries) => {
|
|
3960
|
-
process.stderr.write(
|
|
3961
|
-
`
|
|
3962
|
-
${chalk2__default.default.yellow(`[${timestamp()}] Reconnecting... (${attempt}/${maxRetries})`)}
|
|
3963
|
-
`
|
|
3964
|
-
);
|
|
3965
|
-
},
|
|
3966
|
-
onReconnected: () => {
|
|
3967
|
-
process.stderr.write(`
|
|
3968
|
-
${chalk2__default.default.green(`[${timestamp()}] Reconnected`)}
|
|
3969
|
-
`);
|
|
3970
|
-
},
|
|
3971
|
-
onReconnectFailed: () => {
|
|
3972
|
-
process.stderr.write(`
|
|
3973
|
-
${chalk2__default.default.red(`[${timestamp()}] Reconnection failed`)}
|
|
3974
|
-
`);
|
|
3975
|
-
}
|
|
3976
|
-
});
|
|
3977
|
-
} catch {
|
|
3978
|
-
}
|
|
3979
|
-
}
|
|
3980
|
-
function stopBackgroundNotifications() {
|
|
3981
|
-
activeConnection?.close();
|
|
3982
|
-
activeConnection = null;
|
|
3983
|
-
}
|
|
3984
|
-
process.on("exit", stopBackgroundNotifications);
|
|
3985
|
-
process.on("SIGINT", () => {
|
|
3986
|
-
stopBackgroundNotifications();
|
|
3987
|
-
process.exit(0);
|
|
3988
|
-
});
|
|
3989
|
-
|
|
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
|
-
}
|
|
4013
|
-
function formatCliError(err) {
|
|
4014
|
-
const connectionHint = diagnoseConnectionError(err);
|
|
4015
|
-
if (connectionHint) return connectionHint;
|
|
4016
|
-
if (err instanceof sdk.ArbiApiError && err.apiError && typeof err.apiError === "object") {
|
|
4017
|
-
const base = err.message;
|
|
4018
|
-
const apiErr = err.apiError;
|
|
4019
|
-
const detail = apiErr.detail ?? apiErr.message ?? apiErr.error;
|
|
4020
|
-
if (typeof detail === "string" && detail && !base.includes(detail)) {
|
|
4021
|
-
return `${base} \u2014 ${detail}`;
|
|
4022
|
-
}
|
|
4023
|
-
return base;
|
|
4024
|
-
}
|
|
4025
|
-
return sdk.getErrorMessage(err);
|
|
4026
|
-
}
|
|
4027
|
-
function runAction(fn) {
|
|
4028
|
-
return async () => {
|
|
4029
|
-
try {
|
|
4030
|
-
await fn();
|
|
4031
|
-
process.exit(0);
|
|
4032
|
-
} catch (err) {
|
|
4033
|
-
error(`Error: ${formatCliError(err)}`);
|
|
4034
|
-
hintUpdateOnError();
|
|
4035
|
-
process.exit(1);
|
|
4036
|
-
}
|
|
4037
|
-
};
|
|
4038
|
-
}
|
|
4039
|
-
async function resolveAuth() {
|
|
4040
|
-
try {
|
|
4041
|
-
resolveConfig();
|
|
4042
|
-
return await sdk.resolveAuth(store);
|
|
4043
|
-
} catch (err) {
|
|
4044
|
-
if (err instanceof sdk.ArbiError) {
|
|
4045
|
-
error(err.message);
|
|
4046
|
-
process.exit(1);
|
|
4047
|
-
}
|
|
4048
|
-
throw err;
|
|
4049
|
-
}
|
|
4050
|
-
}
|
|
4051
|
-
async function resolveWorkspace(workspaceOpt) {
|
|
4052
|
-
try {
|
|
4053
|
-
resolveConfig();
|
|
4054
|
-
const ctx = await sdk.resolveWorkspace(store, workspaceOpt);
|
|
4055
|
-
if (getConfig()?.notifications !== false) {
|
|
4056
|
-
startBackgroundNotifications(ctx.config.baseUrl, ctx.accessToken).catch(() => {
|
|
4057
|
-
});
|
|
4058
|
-
}
|
|
4059
|
-
return ctx;
|
|
4060
|
-
} catch (err) {
|
|
4061
|
-
if (err instanceof sdk.ArbiError) {
|
|
4062
|
-
error(err.message);
|
|
4063
|
-
process.exit(1);
|
|
4064
|
-
}
|
|
4065
|
-
throw err;
|
|
4066
|
-
}
|
|
4067
|
-
}
|
|
4068
|
-
function printTable(columns, rows) {
|
|
4069
|
-
console.log(chalk2__default.default.bold(columns.map((c) => c.header.padEnd(c.width)).join("")));
|
|
4070
|
-
for (const row of rows) {
|
|
4071
|
-
console.log(
|
|
4072
|
-
columns.map((c) => {
|
|
4073
|
-
const val = c.value(row);
|
|
4074
|
-
return val.slice(0, c.width - 2).padEnd(c.width);
|
|
4075
|
-
}).join("")
|
|
4076
|
-
);
|
|
4077
|
-
}
|
|
4078
|
-
}
|
|
4079
|
-
function parseJsonArg(input2, example) {
|
|
4080
|
-
try {
|
|
4081
|
-
return JSON.parse(input2);
|
|
4082
|
-
} catch {
|
|
4083
|
-
error(`Invalid JSON. Example: ${example}`);
|
|
4084
|
-
process.exit(1);
|
|
4085
|
-
}
|
|
4086
|
-
}
|
|
4087
|
-
|
|
4088
|
-
// src/commands/workspaces.ts
|
|
4089
4192
|
function registerWorkspacesCommand(program2) {
|
|
4090
4193
|
program2.command("workspaces").description("List workspaces").action(
|
|
4091
4194
|
runAction(async () => {
|
|
4092
4195
|
const { arbi } = await resolveAuth();
|
|
4093
4196
|
const data = await sdk.workspaces.listWorkspaces(arbi);
|
|
4197
|
+
updateCompletionCache(data);
|
|
4094
4198
|
if (data.length === 0) {
|
|
4095
4199
|
console.log("No workspaces found.");
|
|
4096
4200
|
return;
|
|
@@ -4119,6 +4223,7 @@ function registerWorkspacesCommand(program2) {
|
|
|
4119
4223
|
(id) => runAction(async () => {
|
|
4120
4224
|
const { arbi } = await resolveAuth();
|
|
4121
4225
|
const data = await sdk.workspaces.listWorkspaces(arbi);
|
|
4226
|
+
updateCompletionCache(data);
|
|
4122
4227
|
if (data.length === 0) {
|
|
4123
4228
|
console.log("No workspaces found.");
|
|
4124
4229
|
return;
|
|
@@ -4171,17 +4276,17 @@ function registerWorkspacesCommand(program2) {
|
|
|
4171
4276
|
success(`Deleted workspace ${targetId}`);
|
|
4172
4277
|
})()
|
|
4173
4278
|
);
|
|
4174
|
-
workspace.command("update <
|
|
4175
|
-
(
|
|
4176
|
-
const body = parseJsonArg(json, `arbi workspace update
|
|
4177
|
-
const { arbi } = await resolveWorkspace(
|
|
4279
|
+
workspace.command("update <json>").description("Update workspace properties (pass JSON)").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").action(
|
|
4280
|
+
(json, opts) => runAction(async () => {
|
|
4281
|
+
const body = parseJsonArg(json, `arbi workspace update '{"name": "New Name"}'`);
|
|
4282
|
+
const { arbi } = await resolveWorkspace(opts.workspace);
|
|
4178
4283
|
const data = await sdk.workspaces.updateWorkspace(arbi, body);
|
|
4179
4284
|
success(`Updated: ${data.name} (${ref(data.external_id)})`);
|
|
4180
4285
|
})()
|
|
4181
4286
|
);
|
|
4182
4287
|
workspace.command("users").description("List users in the active workspace").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").action(
|
|
4183
4288
|
(opts) => runAction(async () => {
|
|
4184
|
-
const { arbi
|
|
4289
|
+
const { arbi } = await resolveWorkspace(opts.workspace);
|
|
4185
4290
|
const data = await sdk.workspaces.listWorkspaceUsers(arbi);
|
|
4186
4291
|
if (data.length === 0) {
|
|
4187
4292
|
console.log("No users found.");
|
|
@@ -4217,7 +4322,7 @@ function registerWorkspacesCommand(program2) {
|
|
|
4217
4322
|
);
|
|
4218
4323
|
workspace.command("add-user <emails...>").description("Add users to the active workspace").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").option("-r, --role <role>", "Role: owner, collaborator, guest", "collaborator").action(
|
|
4219
4324
|
(emails, opts) => runAction(async () => {
|
|
4220
|
-
const { arbi
|
|
4325
|
+
const { arbi } = await resolveWorkspace(opts.workspace);
|
|
4221
4326
|
const role = opts.role ?? "collaborator";
|
|
4222
4327
|
const data = await sdk.workspaces.addWorkspaceUsers(arbi, emails, role);
|
|
4223
4328
|
for (const u of data) success(`Added: ${u.user.email} as ${u.role}`);
|
|
@@ -4225,14 +4330,14 @@ function registerWorkspacesCommand(program2) {
|
|
|
4225
4330
|
);
|
|
4226
4331
|
workspace.command("remove-user <user-ids...>").description("Remove users from the active workspace").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").action(
|
|
4227
4332
|
(userIds, opts) => runAction(async () => {
|
|
4228
|
-
const { arbi
|
|
4333
|
+
const { arbi } = await resolveWorkspace(opts.workspace);
|
|
4229
4334
|
await sdk.workspaces.removeWorkspaceUsers(arbi, userIds);
|
|
4230
4335
|
success(`Removed ${userIds.length} user(s).`);
|
|
4231
4336
|
})()
|
|
4232
4337
|
);
|
|
4233
4338
|
workspace.command("set-role <role> <user-ids...>").description("Update user roles (owner, collaborator, guest)").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").action(
|
|
4234
4339
|
(role, userIds, opts) => runAction(async () => {
|
|
4235
|
-
const { arbi
|
|
4340
|
+
const { arbi } = await resolveWorkspace(opts.workspace);
|
|
4236
4341
|
const data = await sdk.workspaces.setUserRole(
|
|
4237
4342
|
arbi,
|
|
4238
4343
|
userIds,
|
|
@@ -4243,14 +4348,15 @@ function registerWorkspacesCommand(program2) {
|
|
|
4243
4348
|
);
|
|
4244
4349
|
workspace.command("copy <target-workspace-id> <doc-ids...>").description("Copy documents to another workspace").option("-w, --workspace <id>", "Source workspace ID (defaults to selected workspace)").action(
|
|
4245
4350
|
(targetId, docIds, opts) => runAction(async () => {
|
|
4246
|
-
const { arbi
|
|
4247
|
-
const
|
|
4248
|
-
const wsList = await sdk.workspaces.listWorkspaces(arbi);
|
|
4351
|
+
const { arbi: userArbi } = await resolveAuth();
|
|
4352
|
+
const wsList = await sdk.workspaces.listWorkspaces(userArbi);
|
|
4249
4353
|
const targetWs = wsList.find((w) => w.external_id === targetId);
|
|
4250
4354
|
if (!targetWs || !targetWs.wrapped_key) {
|
|
4251
4355
|
error(`Target workspace ${targetId} not found or has no encryption key`);
|
|
4252
4356
|
process.exit(1);
|
|
4253
4357
|
}
|
|
4358
|
+
const { arbi, loginResult } = await resolveWorkspace(opts.workspace);
|
|
4359
|
+
const signingPrivateKeyBase64 = arbi.crypto.bytesToBase64(loginResult.signingPrivateKey);
|
|
4254
4360
|
const targetKey = await sdk.generateEncryptedWorkspaceKey(
|
|
4255
4361
|
arbi,
|
|
4256
4362
|
targetWs.wrapped_key,
|
|
@@ -4449,7 +4555,7 @@ function registerUploadCommand(program2) {
|
|
|
4449
4555
|
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
4556
|
(paths, opts) => runAction(async () => {
|
|
4451
4557
|
for (const p of paths) {
|
|
4452
|
-
if (!
|
|
4558
|
+
if (!fs2__default.default.existsSync(p)) {
|
|
4453
4559
|
error(`Path not found: ${p}`);
|
|
4454
4560
|
process.exit(1);
|
|
4455
4561
|
}
|
|
@@ -4460,7 +4566,7 @@ function registerUploadCommand(program2) {
|
|
|
4460
4566
|
const uploadedDocs = /* @__PURE__ */ new Map();
|
|
4461
4567
|
const auth = { baseUrl: config.baseUrl, accessToken, workspaceKeyHeader };
|
|
4462
4568
|
for (const filePath of paths) {
|
|
4463
|
-
const stat =
|
|
4569
|
+
const stat = fs2__default.default.statSync(filePath);
|
|
4464
4570
|
if (stat.isDirectory()) {
|
|
4465
4571
|
const result = await sdk.documentsNode.uploadDirectory(auth, workspaceId, filePath);
|
|
4466
4572
|
if (result.doc_ext_ids.length === 0) {
|
|
@@ -4596,7 +4702,7 @@ function registerDownloadCommand(program2) {
|
|
|
4596
4702
|
}
|
|
4597
4703
|
const outputPath = opts.output || path__default.default.join(process.cwd(), filename);
|
|
4598
4704
|
const buffer = Buffer.from(await res.arrayBuffer());
|
|
4599
|
-
|
|
4705
|
+
fs2__default.default.writeFileSync(outputPath, buffer);
|
|
4600
4706
|
success(
|
|
4601
4707
|
`Downloaded: ${path__default.default.basename(outputPath)} (${(buffer.length / (1024 * 1024)).toFixed(1)} MB)`
|
|
4602
4708
|
);
|
|
@@ -4682,13 +4788,22 @@ function registerAskCommand(program2) {
|
|
|
4682
4788
|
}
|
|
4683
4789
|
const verbose = opts.quiet === true ? false : getConfig()?.verbose !== false;
|
|
4684
4790
|
let elapsedTime = null;
|
|
4791
|
+
let firstToken = true;
|
|
4685
4792
|
const result = await sdk.streamSSE(res, {
|
|
4686
|
-
onToken: (content) =>
|
|
4793
|
+
onToken: (content) => {
|
|
4794
|
+
if (firstToken) {
|
|
4795
|
+
process.stderr.write(chalk2__default.default.dim("[ARBI] "));
|
|
4796
|
+
firstToken = false;
|
|
4797
|
+
}
|
|
4798
|
+
process.stdout.write(content);
|
|
4799
|
+
},
|
|
4687
4800
|
onAgentStep: (data) => {
|
|
4688
4801
|
if (verbose) {
|
|
4689
4802
|
const label2 = sdk.formatAgentStepLabel(data);
|
|
4690
|
-
if (label2)
|
|
4691
|
-
|
|
4803
|
+
if (label2 && data.step !== "answering") {
|
|
4804
|
+
console.error(chalk2__default.default.dim(`
|
|
4805
|
+
[ARBI] ${label2}`));
|
|
4806
|
+
}
|
|
4692
4807
|
}
|
|
4693
4808
|
},
|
|
4694
4809
|
onElapsedTime: (t) => {
|
|
@@ -4698,29 +4813,23 @@ function registerAskCommand(program2) {
|
|
|
4698
4813
|
Error: ${message}`))
|
|
4699
4814
|
});
|
|
4700
4815
|
process.stdout.write("\n");
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4816
|
+
if (result.metadata) {
|
|
4817
|
+
saveLastMetadata(result.metadata);
|
|
4818
|
+
}
|
|
4819
|
+
const refs = sdk.countCitations(result.metadata);
|
|
4820
|
+
const summary = opts.quiet !== true ? sdk.formatStreamSummary(result, elapsedTime) : "";
|
|
4821
|
+
if (summary) {
|
|
4822
|
+
const refSuffix = refs > 0 ? ` \xB7 ${refs} ref${refs === 1 ? "" : "s"}` : "";
|
|
4823
|
+
const text = `[${summary}${refSuffix}]`;
|
|
4824
|
+
const cols = process.stderr.columns || 80;
|
|
4825
|
+
const pad = Math.max(0, cols - text.length);
|
|
4826
|
+
console.error(chalk2__default.default.dim(" ".repeat(pad) + text));
|
|
4827
|
+
}
|
|
4828
|
+
if (refs > 0 && opts.quiet !== true) {
|
|
4829
|
+
console.error(
|
|
4830
|
+
chalk2__default.default.dim(`[${refs} citation${refs === 1 ? "" : "s"} \u2014 arbi cite to browse]`)
|
|
4716
4831
|
);
|
|
4717
4832
|
}
|
|
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
|
-
}
|
|
4724
4833
|
if (result.assistantMessageExtId) {
|
|
4725
4834
|
const updates = {
|
|
4726
4835
|
lastMessageExtId: result.assistantMessageExtId,
|
|
@@ -4735,6 +4844,87 @@ Error: ${message}`))
|
|
|
4735
4844
|
})()
|
|
4736
4845
|
);
|
|
4737
4846
|
}
|
|
4847
|
+
var MAX_PASSAGE_LINES = 40;
|
|
4848
|
+
function registerCiteCommand(program2) {
|
|
4849
|
+
program2.command("cite [number]").description("Browse citations from the last response").option("-a, --all", "Show all citations with full passages").action(
|
|
4850
|
+
(number, opts) => runAction(async () => {
|
|
4851
|
+
const raw = loadLastMetadata();
|
|
4852
|
+
if (!raw) {
|
|
4853
|
+
console.error(chalk2__default.default.dim("No citation data available. Run `arbi ask` first."));
|
|
4854
|
+
return;
|
|
4855
|
+
}
|
|
4856
|
+
const metadata = raw;
|
|
4857
|
+
const count = sdk.countCitations(metadata);
|
|
4858
|
+
if (count === 0) {
|
|
4859
|
+
console.log(chalk2__default.default.dim("The last response contained no citations."));
|
|
4860
|
+
return;
|
|
4861
|
+
}
|
|
4862
|
+
const resolved = sdk.resolveCitations(metadata);
|
|
4863
|
+
if (opts.all) {
|
|
4864
|
+
for (const r of resolved) {
|
|
4865
|
+
printCitationDetail(r.citationNum, resolved);
|
|
4866
|
+
console.log();
|
|
4867
|
+
}
|
|
4868
|
+
return;
|
|
4869
|
+
}
|
|
4870
|
+
if (number) {
|
|
4871
|
+
printCitationDetail(number, resolved);
|
|
4872
|
+
return;
|
|
4873
|
+
}
|
|
4874
|
+
const summaries = sdk.summarizeCitations(resolved);
|
|
4875
|
+
console.log(chalk2__default.default.bold(`Citations (${summaries.length}):
|
|
4876
|
+
`));
|
|
4877
|
+
for (const s of summaries) {
|
|
4878
|
+
const page = s.pageNumber != null ? `, p${s.pageNumber}` : "";
|
|
4879
|
+
const chunks = s.chunkCount > 1 ? ` (${s.chunkCount} passages)` : "";
|
|
4880
|
+
console.log(
|
|
4881
|
+
` ${chalk2__default.default.cyan(`[${s.citationNum}]`)} ${chalk2__default.default.bold(s.docTitle)}${page}${chunks}`
|
|
4882
|
+
);
|
|
4883
|
+
const truncated = s.statement.length > 120 ? s.statement.slice(0, 120).replace(/\n/g, " ").trim() + "..." : s.statement.replace(/\n/g, " ").trim();
|
|
4884
|
+
console.log(` ${chalk2__default.default.dim(truncated)}`);
|
|
4885
|
+
}
|
|
4886
|
+
console.log(chalk2__default.default.dim(`
|
|
4887
|
+
Use \`arbi cite <N>\` to view full passage.`));
|
|
4888
|
+
})()
|
|
4889
|
+
);
|
|
4890
|
+
}
|
|
4891
|
+
function printCitationDetail(num, resolved) {
|
|
4892
|
+
const citation = resolved.find((r) => r.citationNum === num);
|
|
4893
|
+
if (!citation) {
|
|
4894
|
+
console.error(chalk2__default.default.red(`Citation [${num}] not found.`));
|
|
4895
|
+
return;
|
|
4896
|
+
}
|
|
4897
|
+
const firstChunk = citation.chunks[0];
|
|
4898
|
+
const docTitle = firstChunk?.metadata?.doc_title ?? "Unknown document";
|
|
4899
|
+
const page = firstChunk?.metadata?.page_number;
|
|
4900
|
+
console.log(chalk2__default.default.bold.cyan(`[Citation ${citation.citationNum}]`) + " " + chalk2__default.default.bold(docTitle));
|
|
4901
|
+
if (page != null) {
|
|
4902
|
+
console.log(chalk2__default.default.dim(`Page ${page}`));
|
|
4903
|
+
}
|
|
4904
|
+
console.log();
|
|
4905
|
+
console.log(chalk2__default.default.bold("Statement:"));
|
|
4906
|
+
console.log(` ${citation.citationData.statement}`);
|
|
4907
|
+
console.log();
|
|
4908
|
+
for (let i = 0; i < citation.chunks.length; i++) {
|
|
4909
|
+
const chunk = citation.chunks[i];
|
|
4910
|
+
if (citation.chunks.length > 1) {
|
|
4911
|
+
console.log(chalk2__default.default.bold(`Passage ${i + 1}/${citation.chunks.length}:`));
|
|
4912
|
+
} else {
|
|
4913
|
+
console.log(chalk2__default.default.bold("Passage:"));
|
|
4914
|
+
}
|
|
4915
|
+
const lines = chunk.content.split("\n");
|
|
4916
|
+
if (lines.length > MAX_PASSAGE_LINES) {
|
|
4917
|
+
console.log(lines.slice(0, MAX_PASSAGE_LINES).join("\n"));
|
|
4918
|
+
console.log(chalk2__default.default.dim(` ... (${lines.length - MAX_PASSAGE_LINES} more lines)`));
|
|
4919
|
+
} else {
|
|
4920
|
+
console.log(chunk.content);
|
|
4921
|
+
}
|
|
4922
|
+
if (i < citation.chunks.length - 1) console.log();
|
|
4923
|
+
}
|
|
4924
|
+
if (citation.chunks.length === 0) {
|
|
4925
|
+
console.log(chalk2__default.default.dim(" (no passage data available)"));
|
|
4926
|
+
}
|
|
4927
|
+
}
|
|
4738
4928
|
function chunkScore(chunk) {
|
|
4739
4929
|
return chunk.metadata.rerank_score ?? chunk.metadata.score ?? 0;
|
|
4740
4930
|
}
|
|
@@ -5819,8 +6009,8 @@ function registerQuickstartCommand(program2) {
|
|
|
5819
6009
|
try {
|
|
5820
6010
|
const { arbi } = await sdk.performPasswordLogin(config, email, password2, store);
|
|
5821
6011
|
success(`Logged in as ${email}`);
|
|
5822
|
-
const { data:
|
|
5823
|
-
const wsList =
|
|
6012
|
+
const { data: workspaces3 } = await arbi.fetch.GET("/v1/user/workspaces");
|
|
6013
|
+
const wsList = workspaces3 || [];
|
|
5824
6014
|
const memberWorkspaces = wsList.filter((ws) => ws.users?.some((u) => u.email === email));
|
|
5825
6015
|
let workspaceId;
|
|
5826
6016
|
let workspaceName;
|
|
@@ -6052,6 +6242,85 @@ function registerTaskCommand(program2) {
|
|
|
6052
6242
|
})()
|
|
6053
6243
|
);
|
|
6054
6244
|
}
|
|
6245
|
+
var MARKER_START = "# arbi-cli completion start";
|
|
6246
|
+
var MARKER_END = "# arbi-cli completion end";
|
|
6247
|
+
var BASH_COMPLETION = `
|
|
6248
|
+
${MARKER_START}
|
|
6249
|
+
_arbi_completions() {
|
|
6250
|
+
local cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
6251
|
+
local candidates
|
|
6252
|
+
candidates=$(arbi --get-completions "\${COMP_LINE}" 2>/dev/null)
|
|
6253
|
+
COMPREPLY=($(compgen -W "$candidates" -- "$cur"))
|
|
6254
|
+
}
|
|
6255
|
+
complete -o default -F _arbi_completions arbi
|
|
6256
|
+
${MARKER_END}`;
|
|
6257
|
+
var ZSH_COMPLETION = `
|
|
6258
|
+
${MARKER_START}
|
|
6259
|
+
_arbi_completions() {
|
|
6260
|
+
local candidates
|
|
6261
|
+
candidates=(\${(f)"$(arbi --get-completions "\${words[*]}" 2>/dev/null)"})
|
|
6262
|
+
compadd -a candidates
|
|
6263
|
+
}
|
|
6264
|
+
compdef _arbi_completions arbi
|
|
6265
|
+
${MARKER_END}`;
|
|
6266
|
+
function getShellRcPath2() {
|
|
6267
|
+
const shell = process.env.SHELL || "";
|
|
6268
|
+
if (shell.includes("zsh")) return path.join(os.homedir(), ".zshrc");
|
|
6269
|
+
return path.join(os.homedir(), ".bashrc");
|
|
6270
|
+
}
|
|
6271
|
+
function isZsh() {
|
|
6272
|
+
return (process.env.SHELL || "").includes("zsh");
|
|
6273
|
+
}
|
|
6274
|
+
function isCompletionInstalled(rcPath) {
|
|
6275
|
+
if (!fs2.existsSync(rcPath)) return false;
|
|
6276
|
+
const content = fs2.readFileSync(rcPath, "utf-8");
|
|
6277
|
+
return content.includes(MARKER_START);
|
|
6278
|
+
}
|
|
6279
|
+
function removeCompletionBlock(content) {
|
|
6280
|
+
const startIdx = content.indexOf(MARKER_START);
|
|
6281
|
+
const endIdx = content.indexOf(MARKER_END);
|
|
6282
|
+
if (startIdx === -1 || endIdx === -1) return content;
|
|
6283
|
+
const before = content.substring(0, startIdx).replace(/\n+$/, "");
|
|
6284
|
+
const after = content.substring(endIdx + MARKER_END.length);
|
|
6285
|
+
return before + after;
|
|
6286
|
+
}
|
|
6287
|
+
function registerCompletionCommand(program2) {
|
|
6288
|
+
const completion = program2.command("completion").description("Manage shell tab completion");
|
|
6289
|
+
completion.command("install").description("Install shell tab completion (bash/zsh)").action(() => {
|
|
6290
|
+
const rcPath = getShellRcPath2();
|
|
6291
|
+
if (isCompletionInstalled(rcPath)) {
|
|
6292
|
+
success(`Completion already installed in ${rcPath}`);
|
|
6293
|
+
dim("If it's not working, run: source " + rcPath);
|
|
6294
|
+
return;
|
|
6295
|
+
}
|
|
6296
|
+
const snippet = isZsh() ? ZSH_COMPLETION : BASH_COMPLETION;
|
|
6297
|
+
fs2.appendFileSync(rcPath, snippet + "\n");
|
|
6298
|
+
success(`Installed tab completion in ${rcPath}`);
|
|
6299
|
+
dim("");
|
|
6300
|
+
dim(`Run: source ${rcPath}`);
|
|
6301
|
+
dim("Then try: arbi <TAB>");
|
|
6302
|
+
});
|
|
6303
|
+
completion.command("uninstall").description("Remove shell tab completion").action(() => {
|
|
6304
|
+
const rcPath = getShellRcPath2();
|
|
6305
|
+
if (!isCompletionInstalled(rcPath)) {
|
|
6306
|
+
dim("Completion is not installed.");
|
|
6307
|
+
return;
|
|
6308
|
+
}
|
|
6309
|
+
const content = fs2.readFileSync(rcPath, "utf-8");
|
|
6310
|
+
const cleaned = removeCompletionBlock(content);
|
|
6311
|
+
fs2.writeFileSync(rcPath, cleaned);
|
|
6312
|
+
success(`Removed tab completion from ${rcPath}`);
|
|
6313
|
+
dim(`Run: source ${rcPath}`);
|
|
6314
|
+
});
|
|
6315
|
+
completion.command("refresh").description("Refresh cached workspace IDs for tab completion").action(
|
|
6316
|
+
runAction(async () => {
|
|
6317
|
+
const { arbi } = await resolveAuth();
|
|
6318
|
+
const data = await sdk.workspaces.listWorkspaces(arbi);
|
|
6319
|
+
updateCompletionCache(data);
|
|
6320
|
+
success(`Cached ${data.length} workspace(s) for tab completion.`);
|
|
6321
|
+
})
|
|
6322
|
+
);
|
|
6323
|
+
}
|
|
6055
6324
|
|
|
6056
6325
|
// src/index.ts
|
|
6057
6326
|
console.debug = () => {
|
|
@@ -6062,7 +6331,7 @@ console.info = (...args) => {
|
|
|
6062
6331
|
_origInfo(...args);
|
|
6063
6332
|
};
|
|
6064
6333
|
var program = new commander.Command();
|
|
6065
|
-
program.name("arbi").description("ARBI CLI \u2014 interact with ARBI from the terminal").version("0.3.
|
|
6334
|
+
program.name("arbi").description("ARBI CLI \u2014 interact with ARBI from the terminal").version("0.3.17");
|
|
6066
6335
|
registerConfigCommand(program);
|
|
6067
6336
|
registerLoginCommand(program);
|
|
6068
6337
|
registerRegisterCommand(program);
|
|
@@ -6073,6 +6342,7 @@ registerDocsCommand(program);
|
|
|
6073
6342
|
registerUploadCommand(program);
|
|
6074
6343
|
registerDownloadCommand(program);
|
|
6075
6344
|
registerAskCommand(program);
|
|
6345
|
+
registerCiteCommand(program);
|
|
6076
6346
|
registerFindCommand(program);
|
|
6077
6347
|
registerWatchCommand(program);
|
|
6078
6348
|
registerContactsCommand(program);
|
|
@@ -6088,6 +6358,14 @@ registerUpdateCommand(program);
|
|
|
6088
6358
|
registerQuickstartCommand(program);
|
|
6089
6359
|
registerAgentCreateCommand(program);
|
|
6090
6360
|
registerTaskCommand(program);
|
|
6361
|
+
registerCompletionCommand(program);
|
|
6362
|
+
var completionIdx = process.argv.indexOf("--get-completions");
|
|
6363
|
+
if (completionIdx !== -1) {
|
|
6364
|
+
const line = process.argv[completionIdx + 1] ?? "";
|
|
6365
|
+
const candidates = getCompletions(program, line);
|
|
6366
|
+
if (candidates.length > 0) process.stdout.write(candidates.join("\n") + "\n");
|
|
6367
|
+
process.exit(0);
|
|
6368
|
+
}
|
|
6091
6369
|
program.parse();
|
|
6092
6370
|
//# sourceMappingURL=index.js.map
|
|
6093
6371
|
//# sourceMappingURL=index.js.map
|