@arbidocs/cli 0.3.18 → 0.3.20
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 +75 -0
- package/SKILL.md +30 -0
- package/dist/index.js +768 -87
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
package/dist/index.js
CHANGED
|
@@ -10,6 +10,7 @@ var sdk = require('@arbidocs/sdk');
|
|
|
10
10
|
var prompts = require('@inquirer/prompts');
|
|
11
11
|
var child_process = require('child_process');
|
|
12
12
|
var client = require('@arbidocs/client');
|
|
13
|
+
var url = require('url');
|
|
13
14
|
var module$1 = require('module');
|
|
14
15
|
|
|
15
16
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
@@ -3250,7 +3251,7 @@ var waitForOthersClosedDelete = (databases, name, openDatabases, cb) => {
|
|
|
3250
3251
|
};
|
|
3251
3252
|
var deleteDatabase = (databases, connectionQueues, name, request, cb) => {
|
|
3252
3253
|
const deleteDBTask = () => {
|
|
3253
|
-
return new Promise((
|
|
3254
|
+
return new Promise((resolve3) => {
|
|
3254
3255
|
const db = databases.get(name);
|
|
3255
3256
|
const oldVersion = db !== void 0 ? db.version : 0;
|
|
3256
3257
|
const onComplete = (err) => {
|
|
@@ -3261,7 +3262,7 @@ var deleteDatabase = (databases, connectionQueues, name, request, cb) => {
|
|
|
3261
3262
|
cb(null, oldVersion);
|
|
3262
3263
|
}
|
|
3263
3264
|
} finally {
|
|
3264
|
-
|
|
3265
|
+
resolve3();
|
|
3265
3266
|
}
|
|
3266
3267
|
};
|
|
3267
3268
|
try {
|
|
@@ -3409,7 +3410,7 @@ var runVersionchangeTransaction = (connection, version, request, cb) => {
|
|
|
3409
3410
|
};
|
|
3410
3411
|
var openDatabase = (databases, connectionQueues, name, version, request, cb) => {
|
|
3411
3412
|
const openDBTask = () => {
|
|
3412
|
-
return new Promise((
|
|
3413
|
+
return new Promise((resolve3) => {
|
|
3413
3414
|
const onComplete = (err) => {
|
|
3414
3415
|
try {
|
|
3415
3416
|
if (err) {
|
|
@@ -3418,7 +3419,7 @@ var openDatabase = (databases, connectionQueues, name, version, request, cb) =>
|
|
|
3418
3419
|
cb(null, connection);
|
|
3419
3420
|
}
|
|
3420
3421
|
} finally {
|
|
3421
|
-
|
|
3422
|
+
resolve3();
|
|
3422
3423
|
}
|
|
3423
3424
|
};
|
|
3424
3425
|
let db = databases.get(name);
|
|
@@ -3636,7 +3637,7 @@ function getLatestVersion(skipCache = false) {
|
|
|
3636
3637
|
}
|
|
3637
3638
|
}
|
|
3638
3639
|
function getCurrentVersion() {
|
|
3639
|
-
return "0.3.
|
|
3640
|
+
return "0.3.20";
|
|
3640
3641
|
}
|
|
3641
3642
|
function readChangelog(fromVersion, toVersion) {
|
|
3642
3643
|
try {
|
|
@@ -3689,17 +3690,17 @@ function showChangelog(fromVersion, toVersion) {
|
|
|
3689
3690
|
async function checkForUpdates(autoUpdate) {
|
|
3690
3691
|
try {
|
|
3691
3692
|
const latest = getLatestVersion();
|
|
3692
|
-
if (!latest || latest === "0.3.
|
|
3693
|
+
if (!latest || latest === "0.3.20") return;
|
|
3693
3694
|
if (autoUpdate) {
|
|
3694
3695
|
warn(`
|
|
3695
|
-
Your arbi version is out of date (${"0.3.
|
|
3696
|
+
Your arbi version is out of date (${"0.3.20"} \u2192 ${latest}). Updating...`);
|
|
3696
3697
|
child_process.execSync("npm install -g @arbidocs/cli@latest", { stdio: "inherit" });
|
|
3697
|
-
showChangelog("0.3.
|
|
3698
|
+
showChangelog("0.3.20", latest);
|
|
3698
3699
|
console.log(`Updated to ${latest}.`);
|
|
3699
3700
|
} else {
|
|
3700
3701
|
warn(
|
|
3701
3702
|
`
|
|
3702
|
-
Your arbi version is out of date (${"0.3.
|
|
3703
|
+
Your arbi version is out of date (${"0.3.20"} \u2192 ${latest}).
|
|
3703
3704
|
Run "arbi update" to upgrade, or "arbi update auto" to always stay up to date.`
|
|
3704
3705
|
);
|
|
3705
3706
|
}
|
|
@@ -3709,9 +3710,9 @@ Run "arbi update" to upgrade, or "arbi update auto" to always stay up to date.`
|
|
|
3709
3710
|
function hintUpdateOnError() {
|
|
3710
3711
|
try {
|
|
3711
3712
|
const cached = readCache();
|
|
3712
|
-
if (cached && cached.latest !== "0.3.
|
|
3713
|
+
if (cached && cached.latest !== "0.3.20") {
|
|
3713
3714
|
warn(
|
|
3714
|
-
`Your arbi version is out of date (${"0.3.
|
|
3715
|
+
`Your arbi version is out of date (${"0.3.20"} \u2192 ${cached.latest}). Run "arbi update".`
|
|
3715
3716
|
);
|
|
3716
3717
|
}
|
|
3717
3718
|
} catch {
|
|
@@ -3902,12 +3903,23 @@ async function resolveWorkspace(workspaceOpt) {
|
|
|
3902
3903
|
throw err;
|
|
3903
3904
|
}
|
|
3904
3905
|
}
|
|
3906
|
+
async function resolveDmCrypto() {
|
|
3907
|
+
const authCtx = await resolveAuth();
|
|
3908
|
+
const { arbi, loginResult } = authCtx;
|
|
3909
|
+
const userExtId = arbi.session.getState().userExtId;
|
|
3910
|
+
if (!userExtId) {
|
|
3911
|
+
error("No user ID in session \u2014 cannot set up DM encryption.");
|
|
3912
|
+
process.exit(1);
|
|
3913
|
+
}
|
|
3914
|
+
const crypto = sdk.dm.createDmCryptoContext(arbi, loginResult.signingPrivateKey, userExtId);
|
|
3915
|
+
return { ...authCtx, crypto };
|
|
3916
|
+
}
|
|
3905
3917
|
function printTable(columns, rows) {
|
|
3906
3918
|
console.log(chalk2__default.default.bold(columns.map((c) => c.header.padEnd(c.width)).join("")));
|
|
3907
3919
|
for (const row of rows) {
|
|
3908
3920
|
console.log(
|
|
3909
3921
|
columns.map((c) => {
|
|
3910
|
-
const val = c.value(row);
|
|
3922
|
+
const val = c.value(row) ?? "";
|
|
3911
3923
|
return val.slice(0, c.width - 2).padEnd(c.width);
|
|
3912
3924
|
}).join("")
|
|
3913
3925
|
);
|
|
@@ -3921,10 +3933,324 @@ function parseJsonArg(input2, example) {
|
|
|
3921
3933
|
process.exit(1);
|
|
3922
3934
|
}
|
|
3923
3935
|
}
|
|
3936
|
+
var AGENT_BACKENDS = ["claude", "openclaw"];
|
|
3937
|
+
var AGENT_MIN_VERSIONS = {
|
|
3938
|
+
claude: {
|
|
3939
|
+
binary: "claude",
|
|
3940
|
+
minVersion: "2.0.0",
|
|
3941
|
+
installUrl: "https://docs.anthropic.com/en/docs/claude-code"
|
|
3942
|
+
},
|
|
3943
|
+
openclaw: {
|
|
3944
|
+
binary: "openclaw",
|
|
3945
|
+
minVersion: "2026.2.0",
|
|
3946
|
+
installUrl: "https://docs.openclaw.ai/install"
|
|
3947
|
+
}
|
|
3948
|
+
};
|
|
3949
|
+
function checkAgentDependency(backend) {
|
|
3950
|
+
const { binary, minVersion, installUrl } = AGENT_MIN_VERSIONS[backend];
|
|
3951
|
+
let version;
|
|
3952
|
+
try {
|
|
3953
|
+
version = child_process.execFileSync(binary, ["--version"], { encoding: "utf-8", timeout: 5e3 }).trim();
|
|
3954
|
+
} catch {
|
|
3955
|
+
error(
|
|
3956
|
+
`"${binary}" is not installed or not in PATH.
|
|
3957
|
+
The "${backend}" agent backend requires ${binary} >= ${minVersion}.
|
|
3958
|
+
Install: ${installUrl}`
|
|
3959
|
+
);
|
|
3960
|
+
process.exit(1);
|
|
3961
|
+
}
|
|
3962
|
+
const versionMatch = version.match(/(\d+\.\d+[\d.]*)/);
|
|
3963
|
+
if (!versionMatch) {
|
|
3964
|
+
dim(`Could not parse ${binary} version from: ${version}`);
|
|
3965
|
+
return;
|
|
3966
|
+
}
|
|
3967
|
+
const current = versionMatch[1];
|
|
3968
|
+
if (compareVersions(current, minVersion) < 0) {
|
|
3969
|
+
error(
|
|
3970
|
+
`"${binary}" version ${current} is too old (need >= ${minVersion}).
|
|
3971
|
+
Update: ${installUrl}`
|
|
3972
|
+
);
|
|
3973
|
+
process.exit(1);
|
|
3974
|
+
}
|
|
3975
|
+
dim(`${binary} ${current} \u2713`);
|
|
3976
|
+
}
|
|
3977
|
+
function compareVersions(a, b) {
|
|
3978
|
+
const pa = a.split(".").map(Number);
|
|
3979
|
+
const pb = b.split(".").map(Number);
|
|
3980
|
+
const len = Math.max(pa.length, pb.length);
|
|
3981
|
+
for (let i = 0; i < len; i++) {
|
|
3982
|
+
const diff = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
3983
|
+
if (diff !== 0) return diff;
|
|
3984
|
+
}
|
|
3985
|
+
return 0;
|
|
3986
|
+
}
|
|
3987
|
+
function loadSkillContent() {
|
|
3988
|
+
const cliRoot = path.resolve(path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href)))), "..");
|
|
3989
|
+
try {
|
|
3990
|
+
return fs2.readFileSync(path.join(cliRoot, "SKILL.md"), "utf-8");
|
|
3991
|
+
} catch {
|
|
3992
|
+
return void 0;
|
|
3993
|
+
}
|
|
3994
|
+
}
|
|
3995
|
+
function createAgent(backend, sessionId) {
|
|
3996
|
+
switch (backend) {
|
|
3997
|
+
case "claude":
|
|
3998
|
+
return new sdk.ClaudeOrchestrator({ sessionId, skillPrompt: loadSkillContent() });
|
|
3999
|
+
case "openclaw":
|
|
4000
|
+
return new sdk.OpenClawOrchestrator({ sessionId });
|
|
4001
|
+
default:
|
|
4002
|
+
throw new Error(`Unknown agent backend: ${backend}`);
|
|
4003
|
+
}
|
|
4004
|
+
}
|
|
4005
|
+
function installSkill(backend) {
|
|
4006
|
+
const cliRoot = path.resolve(path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href)))), "..");
|
|
4007
|
+
const skillPath = path.join(cliRoot, "SKILL.md");
|
|
4008
|
+
let skillContent;
|
|
4009
|
+
try {
|
|
4010
|
+
skillContent = fs2.readFileSync(skillPath, "utf-8");
|
|
4011
|
+
} catch {
|
|
4012
|
+
return;
|
|
4013
|
+
}
|
|
4014
|
+
switch (backend) {
|
|
4015
|
+
case "claude": {
|
|
4016
|
+
const commandsDir = path.join(os.homedir(), ".claude", "commands", "arbi");
|
|
4017
|
+
const targetPath = path.join(commandsDir, "SKILL.md");
|
|
4018
|
+
try {
|
|
4019
|
+
fs2.mkdirSync(commandsDir, { recursive: true });
|
|
4020
|
+
if (fs2.existsSync(targetPath)) {
|
|
4021
|
+
const existing = fs2.readFileSync(targetPath, "utf-8");
|
|
4022
|
+
if (existing === skillContent) return;
|
|
4023
|
+
}
|
|
4024
|
+
fs2.writeFileSync(targetPath, skillContent, "utf-8");
|
|
4025
|
+
dim(`Installed ARBI skill \u2192 ${targetPath}`);
|
|
4026
|
+
} catch {
|
|
4027
|
+
}
|
|
4028
|
+
break;
|
|
4029
|
+
}
|
|
4030
|
+
case "openclaw": {
|
|
4031
|
+
const ocAgentName = "arbi";
|
|
4032
|
+
const ocWorkspace = path.join(os.homedir(), ".arbi", "openclaw-workspace");
|
|
4033
|
+
const bootstrapPath = path.join(ocWorkspace, "BOOTSTRAP.md");
|
|
4034
|
+
try {
|
|
4035
|
+
const list = child_process.execFileSync("openclaw", ["agents", "list", "--json"], {
|
|
4036
|
+
encoding: "utf-8"
|
|
4037
|
+
});
|
|
4038
|
+
const agents = JSON.parse(list);
|
|
4039
|
+
const exists = Array.isArray(agents) ? agents.some((a) => a.id === ocAgentName) : false;
|
|
4040
|
+
if (!exists) {
|
|
4041
|
+
fs2.mkdirSync(ocWorkspace, { recursive: true });
|
|
4042
|
+
child_process.execFileSync(
|
|
4043
|
+
"openclaw",
|
|
4044
|
+
["agents", "add", ocAgentName, "--workspace", ocWorkspace, "--non-interactive"],
|
|
4045
|
+
{ encoding: "utf-8" }
|
|
4046
|
+
);
|
|
4047
|
+
dim(`Created OpenClaw agent "${ocAgentName}" \u2192 ${ocWorkspace}`);
|
|
4048
|
+
}
|
|
4049
|
+
} catch {
|
|
4050
|
+
fs2.mkdirSync(ocWorkspace, { recursive: true });
|
|
4051
|
+
try {
|
|
4052
|
+
child_process.execFileSync(
|
|
4053
|
+
"openclaw",
|
|
4054
|
+
["agents", "add", ocAgentName, "--workspace", ocWorkspace, "--non-interactive"],
|
|
4055
|
+
{ encoding: "utf-8" }
|
|
4056
|
+
);
|
|
4057
|
+
dim(`Created OpenClaw agent "${ocAgentName}" \u2192 ${ocWorkspace}`);
|
|
4058
|
+
} catch {
|
|
4059
|
+
}
|
|
4060
|
+
}
|
|
4061
|
+
try {
|
|
4062
|
+
fs2.mkdirSync(ocWorkspace, { recursive: true });
|
|
4063
|
+
if (fs2.existsSync(bootstrapPath)) {
|
|
4064
|
+
const existing = fs2.readFileSync(bootstrapPath, "utf-8");
|
|
4065
|
+
if (existing === skillContent) break;
|
|
4066
|
+
}
|
|
4067
|
+
fs2.writeFileSync(bootstrapPath, skillContent, "utf-8");
|
|
4068
|
+
dim(`Installed ARBI skill \u2192 ${bootstrapPath}`);
|
|
4069
|
+
} catch {
|
|
4070
|
+
}
|
|
4071
|
+
break;
|
|
4072
|
+
}
|
|
4073
|
+
}
|
|
4074
|
+
}
|
|
4075
|
+
async function setupAgent(agentName, config) {
|
|
4076
|
+
const backend = agentName ?? config.orchestrator;
|
|
4077
|
+
if (!backend) return void 0;
|
|
4078
|
+
if (!AGENT_BACKENDS.includes(backend)) {
|
|
4079
|
+
error(`Unknown agent backend: "${backend}". Choose from: ${AGENT_BACKENDS.join(", ")}`);
|
|
4080
|
+
process.exit(1);
|
|
4081
|
+
}
|
|
4082
|
+
checkAgentDependency(backend);
|
|
4083
|
+
installSkill(backend);
|
|
4084
|
+
if (agentName && agentName !== config.orchestrator) {
|
|
4085
|
+
updateConfig({ orchestrator: backend });
|
|
4086
|
+
dim(`Default agent backend set to "${backend}"`);
|
|
4087
|
+
}
|
|
4088
|
+
return backend;
|
|
4089
|
+
}
|
|
4090
|
+
async function startListening(agentName, config) {
|
|
4091
|
+
const backend = agentName ?? config.orchestrator;
|
|
4092
|
+
if (!backend) {
|
|
4093
|
+
error(
|
|
4094
|
+
`No agent backend configured. Use --agent to specify one:
|
|
4095
|
+
arbi connect --agent ${AGENT_BACKENDS[0]} --listen`
|
|
4096
|
+
);
|
|
4097
|
+
process.exit(1);
|
|
4098
|
+
}
|
|
4099
|
+
const creds = store.getCredentials();
|
|
4100
|
+
if (!creds?.parentExtId) {
|
|
4101
|
+
error(
|
|
4102
|
+
"DM listener requires a persistent agent identity (parentExtId).\n This session was not claimed as a delegated agent."
|
|
4103
|
+
);
|
|
4104
|
+
process.exit(1);
|
|
4105
|
+
}
|
|
4106
|
+
dim("Starting DM listener...");
|
|
4107
|
+
const { arbi, crypto } = await resolveDmCrypto();
|
|
4108
|
+
const sessionId = arbi.session.getState().userExtId ?? "default";
|
|
4109
|
+
const orchestrator = createAgent(backend, sessionId);
|
|
4110
|
+
const fullConfig = resolveConfig();
|
|
4111
|
+
const accessToken = arbi.session.getState().accessToken;
|
|
4112
|
+
if (!accessToken) {
|
|
4113
|
+
error("No access token \u2014 authentication may have failed.");
|
|
4114
|
+
process.exit(1);
|
|
4115
|
+
}
|
|
4116
|
+
const listener = await sdk.startDmListener({
|
|
4117
|
+
arbi,
|
|
4118
|
+
accessToken,
|
|
4119
|
+
baseUrl: fullConfig.baseUrl,
|
|
4120
|
+
crypto,
|
|
4121
|
+
orchestrator,
|
|
4122
|
+
parentExtId: creds.parentExtId,
|
|
4123
|
+
onLog: (msg) => dim(msg),
|
|
4124
|
+
onError: (msg, err) => error(`${msg}${err ? `: ${err}` : ""}`)
|
|
4125
|
+
});
|
|
4126
|
+
success(`Listening for DMs as ${chalk2__default.default.cyan(creds.email)} via ${chalk2__default.default.cyan(backend)}`);
|
|
4127
|
+
dim("Press Ctrl+C to stop.");
|
|
4128
|
+
const shutdown = () => {
|
|
4129
|
+
dim("\nShutting down listener...");
|
|
4130
|
+
listener.close();
|
|
4131
|
+
orchestrator.close?.();
|
|
4132
|
+
process.exit(0);
|
|
4133
|
+
};
|
|
4134
|
+
process.on("SIGINT", shutdown);
|
|
4135
|
+
process.on("SIGTERM", shutdown);
|
|
4136
|
+
await new Promise(() => {
|
|
4137
|
+
});
|
|
4138
|
+
}
|
|
4139
|
+
function registerConnectCommand(program2) {
|
|
4140
|
+
program2.command("connect").description("Claim a session and/or connect to an agent backend").option("--code <claim-code>", "Claim code from parent (required on first run)").option("--agent <name>", `Agent backend (${AGENT_BACKENDS.join(", ")})`).option("--listen", "Start DM listener (agent receives prompts via encrypted DMs)").action((opts) => {
|
|
4141
|
+
const run = async () => {
|
|
4142
|
+
const config = resolveConfig();
|
|
4143
|
+
const creds = store.getCredentials();
|
|
4144
|
+
const hasIdentity = creds?.signingPrivateKeyBase64;
|
|
4145
|
+
if (!hasIdentity) {
|
|
4146
|
+
const claimCode = opts.code?.trim() ?? "";
|
|
4147
|
+
if (!claimCode) {
|
|
4148
|
+
const authorizeUrl = `${config.baseUrl}#/action/authorize-agent`;
|
|
4149
|
+
error(
|
|
4150
|
+
`No saved identity. Provide a claim code:
|
|
4151
|
+
arbi connect --code purple-mountain-river
|
|
4152
|
+
|
|
4153
|
+
Get a claim code from the ARBI web UI:
|
|
4154
|
+
${chalk2__default.default.underline(authorizeUrl)}`
|
|
4155
|
+
);
|
|
4156
|
+
process.exit(1);
|
|
4157
|
+
}
|
|
4158
|
+
dim("Claiming session...");
|
|
4159
|
+
const arbi = client.createArbiClient({
|
|
4160
|
+
baseUrl: config.baseUrl,
|
|
4161
|
+
deploymentDomain: config.deploymentDomain,
|
|
4162
|
+
credentials: "omit"
|
|
4163
|
+
});
|
|
4164
|
+
await arbi.crypto.initSodium();
|
|
4165
|
+
const keypair = arbi.crypto.generateRandomSigningKeypair();
|
|
4166
|
+
const signingPubKeyBase64 = client.bytesToBase64(keypair.publicKey);
|
|
4167
|
+
const signingPrivateKeyBase64 = client.bytesToBase64(keypair.secretKey);
|
|
4168
|
+
const claimResponse = await sdk.sessions.claimSession(arbi, claimCode, signingPubKeyBase64);
|
|
4169
|
+
const parentExtId = claimResponse.user.parent_ext_id ?? void 0;
|
|
4170
|
+
const agentEmail = claimResponse.user.email ?? claimResponse.user.external_id;
|
|
4171
|
+
store.saveCredentials({
|
|
4172
|
+
email: agentEmail,
|
|
4173
|
+
signingPrivateKeyBase64,
|
|
4174
|
+
serverSessionKeyBase64: claimResponse.session_key,
|
|
4175
|
+
accessToken: claimResponse.access_token,
|
|
4176
|
+
parentExtId
|
|
4177
|
+
});
|
|
4178
|
+
const workspaces3 = claimResponse.workspaces ?? [];
|
|
4179
|
+
if (workspaces3.length > 0) {
|
|
4180
|
+
const firstWs = workspaces3[0];
|
|
4181
|
+
const wsId = firstWs.external_id;
|
|
4182
|
+
if (wsId) {
|
|
4183
|
+
updateConfig({ selectedWorkspaceId: wsId });
|
|
4184
|
+
}
|
|
4185
|
+
}
|
|
4186
|
+
success("Session claimed!");
|
|
4187
|
+
console.log(` Identity: ${chalk2__default.default.cyan(agentEmail)}`);
|
|
4188
|
+
if (parentExtId) {
|
|
4189
|
+
console.log(` Parent: ${chalk2__default.default.cyan(parentExtId)}`);
|
|
4190
|
+
console.log(` Type: Persistent agent`);
|
|
4191
|
+
} else {
|
|
4192
|
+
console.log(` Type: Ephemeral session`);
|
|
4193
|
+
}
|
|
4194
|
+
console.log("");
|
|
4195
|
+
if (parentExtId) {
|
|
4196
|
+
try {
|
|
4197
|
+
arbi.session.setAccessToken(claimResponse.access_token);
|
|
4198
|
+
arbi.session.setUser(agentEmail, claimResponse.user.external_id);
|
|
4199
|
+
const contacts = await sdk.contacts.listContacts(arbi);
|
|
4200
|
+
const parentContact = contacts.find((c) => {
|
|
4201
|
+
const u = c.user;
|
|
4202
|
+
return u?.external_id === parentExtId;
|
|
4203
|
+
});
|
|
4204
|
+
const parentPubKey = parentContact?.user?.encryption_public_key;
|
|
4205
|
+
if (parentPubKey) {
|
|
4206
|
+
const userExtId = claimResponse.user.external_id ?? agentEmail;
|
|
4207
|
+
const crypto = sdk.dm.createDmCryptoContext(
|
|
4208
|
+
arbi,
|
|
4209
|
+
client.base64ToBytes(signingPrivateKeyBase64),
|
|
4210
|
+
userExtId
|
|
4211
|
+
);
|
|
4212
|
+
await sdk.dm.sendEncryptedDM(
|
|
4213
|
+
arbi,
|
|
4214
|
+
[
|
|
4215
|
+
{
|
|
4216
|
+
recipient_ext_id: parentExtId,
|
|
4217
|
+
content: `\u{1F511} Agent recovery key for ${agentEmail}
|
|
4218
|
+
signing_key: ${signingPrivateKeyBase64}
|
|
4219
|
+
|
|
4220
|
+
Save this key \u2014 it is the only way to recover this agent session.`,
|
|
4221
|
+
recipient_encryption_public_key: parentPubKey
|
|
4222
|
+
}
|
|
4223
|
+
],
|
|
4224
|
+
crypto
|
|
4225
|
+
);
|
|
4226
|
+
dim("Recovery key sent to parent via encrypted DM.");
|
|
4227
|
+
} else {
|
|
4228
|
+
dim("Could not find parent encryption key \u2014 recovery key not sent.");
|
|
4229
|
+
dim(`Backup manually: ${signingPrivateKeyBase64}`);
|
|
4230
|
+
}
|
|
4231
|
+
} catch {
|
|
4232
|
+
dim("Failed to send recovery key DM \u2014 save it manually:");
|
|
4233
|
+
dim(` ${signingPrivateKeyBase64}`);
|
|
4234
|
+
}
|
|
4235
|
+
}
|
|
4236
|
+
}
|
|
4237
|
+
await setupAgent(opts.agent, config);
|
|
4238
|
+
if (opts.listen) {
|
|
4239
|
+
await startListening(opts.agent, config);
|
|
4240
|
+
} else {
|
|
4241
|
+
success("Connected. Use `arbi --help` to explore.");
|
|
4242
|
+
}
|
|
4243
|
+
};
|
|
4244
|
+
run().catch((err) => {
|
|
4245
|
+
error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
4246
|
+
process.exit(1);
|
|
4247
|
+
});
|
|
4248
|
+
});
|
|
4249
|
+
}
|
|
3924
4250
|
|
|
3925
4251
|
// src/commands/login.ts
|
|
3926
4252
|
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").option("--sso", "Log in with Auth0 SSO (device flow)").action(
|
|
4253
|
+
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").option("--sso", "Log in with Auth0 SSO (device flow)").option("--agent <name>", "Agent backend to configure (claude, openclaw)").option("--listen", "Start DM listener after login").action(
|
|
3928
4254
|
(opts) => runAction(async () => {
|
|
3929
4255
|
const config = store.requireConfig();
|
|
3930
4256
|
const email = opts.email || process.env.ARBI_EMAIL || await promptInput("Email");
|
|
@@ -3955,35 +4281,37 @@ Open this URL in your browser:
|
|
|
3955
4281
|
const wsList = workspaces3 || [];
|
|
3956
4282
|
updateCompletionCache(wsList);
|
|
3957
4283
|
const memberWorkspaces = wsList.filter(
|
|
3958
|
-
(
|
|
4284
|
+
(ws) => ws.users?.some((u) => u.user.email === email)
|
|
3959
4285
|
);
|
|
3960
4286
|
if (memberWorkspaces.length === 0) {
|
|
3961
4287
|
console.log("No workspaces found. Create one with: arbi workspace create <name>");
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
const ws2 = memberWorkspaces.find((w) => w.external_id === opts.workspace);
|
|
3966
|
-
if (!ws2) {
|
|
4288
|
+
} else if (opts.workspace) {
|
|
4289
|
+
const ws = memberWorkspaces.find((w) => w.external_id === opts.workspace);
|
|
4290
|
+
if (!ws) {
|
|
3967
4291
|
error(`Workspace ${opts.workspace} not found or you don't have access.`);
|
|
3968
4292
|
process.exit(1);
|
|
3969
4293
|
}
|
|
3970
|
-
updateConfig({ selectedWorkspaceId:
|
|
3971
|
-
success(`Workspace: ${
|
|
3972
|
-
|
|
3973
|
-
}
|
|
3974
|
-
if (memberWorkspaces.length === 1) {
|
|
4294
|
+
updateConfig({ selectedWorkspaceId: ws.external_id });
|
|
4295
|
+
success(`Workspace: ${ws.name} (${ref(ws.external_id)})`);
|
|
4296
|
+
} else if (memberWorkspaces.length === 1) {
|
|
3975
4297
|
updateConfig({ selectedWorkspaceId: memberWorkspaces[0].external_id });
|
|
3976
4298
|
success(
|
|
3977
4299
|
`Workspace: ${memberWorkspaces[0].name} (${ref(memberWorkspaces[0].external_id)})`
|
|
3978
4300
|
);
|
|
3979
|
-
|
|
4301
|
+
} else {
|
|
4302
|
+
const choices = sdk.formatWorkspaceChoices(memberWorkspaces);
|
|
4303
|
+
const selected = await promptSelect("Select workspace", choices);
|
|
4304
|
+
updateConfig({ selectedWorkspaceId: selected });
|
|
4305
|
+
const ws = memberWorkspaces.find((w) => w.external_id === selected);
|
|
4306
|
+
success(`Workspace: ${ws.name} (${ref(selected)})`);
|
|
4307
|
+
dim('\nTip: Run "arbi config alias" to use A as a shortcut for "arbi ask"');
|
|
4308
|
+
}
|
|
4309
|
+
if (opts.agent || opts.listen) {
|
|
4310
|
+
await setupAgent(opts.agent, config);
|
|
4311
|
+
if (opts.listen) {
|
|
4312
|
+
await startListening(opts.agent, config);
|
|
4313
|
+
}
|
|
3980
4314
|
}
|
|
3981
|
-
const choices = sdk.formatWorkspaceChoices(memberWorkspaces);
|
|
3982
|
-
const selected = await promptSelect("Select workspace", choices);
|
|
3983
|
-
updateConfig({ selectedWorkspaceId: selected });
|
|
3984
|
-
const ws = memberWorkspaces.find((w) => w.external_id === selected);
|
|
3985
|
-
success(`Workspace: ${ws.name} (${ref(selected)})`);
|
|
3986
|
-
dim('\nTip: Run "arbi config alias" to use A as a shortcut for "arbi ask"');
|
|
3987
4315
|
} catch (err) {
|
|
3988
4316
|
error(`Login failed: ${formatCliError(err)}`);
|
|
3989
4317
|
process.exit(1);
|
|
@@ -4149,15 +4477,16 @@ async function nonInteractiveRegister(config, opts) {
|
|
|
4149
4477
|
}
|
|
4150
4478
|
async function loginAfterRegister(config, email, password2) {
|
|
4151
4479
|
try {
|
|
4152
|
-
const { arbi } = await sdk.performPasswordLogin(config, email, password2, store);
|
|
4480
|
+
const { arbi, loginResult } = await sdk.performPasswordLogin(config, email, password2, store);
|
|
4153
4481
|
success(`Logged in as ${email}`);
|
|
4154
4482
|
const { data: workspaces3 } = await arbi.fetch.GET("/v1/user/workspaces");
|
|
4155
4483
|
const wsList = workspaces3 || [];
|
|
4156
4484
|
updateCompletionCache(wsList);
|
|
4157
|
-
const memberWorkspaces = wsList.filter((ws2) => ws2.users?.some((u) => u.email === email));
|
|
4485
|
+
const memberWorkspaces = wsList.filter((ws2) => ws2.users?.some((u) => u.user.email === email));
|
|
4158
4486
|
if (memberWorkspaces.length === 0) {
|
|
4159
4487
|
console.log("Creating your first workspace...");
|
|
4160
|
-
const
|
|
4488
|
+
const encryptedKey = await sdk.generateNewWorkspaceKey(arbi, loginResult.serverSessionKey);
|
|
4489
|
+
const ws2 = await sdk.workspaces.createWorkspace(arbi, "My First Workspace", encryptedKey);
|
|
4161
4490
|
updateConfig({ selectedWorkspaceId: ws2.external_id });
|
|
4162
4491
|
success(`Workspace: ${ws2.name} (${ref(ws2.external_id)})`);
|
|
4163
4492
|
return;
|
|
@@ -4271,10 +4600,12 @@ function registerWorkspacesCommand(program2) {
|
|
|
4271
4600
|
);
|
|
4272
4601
|
workspace.command("create <name>").description("Create a new workspace").option("-d, --description <text>", "Workspace description").option("--public", "Make workspace public", false).action(
|
|
4273
4602
|
(name, opts) => runAction(async () => {
|
|
4274
|
-
const { arbi } = await resolveAuth();
|
|
4603
|
+
const { arbi, loginResult } = await resolveAuth();
|
|
4604
|
+
const encryptedKey = await sdk.generateNewWorkspaceKey(arbi, loginResult.serverSessionKey);
|
|
4275
4605
|
const data = await sdk.workspaces.createWorkspace(
|
|
4276
4606
|
arbi,
|
|
4277
4607
|
name,
|
|
4608
|
+
encryptedKey,
|
|
4278
4609
|
opts.description,
|
|
4279
4610
|
opts.public ?? false
|
|
4280
4611
|
);
|
|
@@ -4513,7 +4844,10 @@ function registerDocsCommand(program2) {
|
|
|
4513
4844
|
const parsed = parseJsonArg(json, `arbi doc update '[{"external_id": "doc-123", "shared": true}]'`);
|
|
4514
4845
|
const docs = Array.isArray(parsed) ? parsed : parsed.documents;
|
|
4515
4846
|
const { arbi } = await resolveWorkspace();
|
|
4516
|
-
const data = await sdk.documents.updateDocuments(
|
|
4847
|
+
const data = await sdk.documents.updateDocuments(
|
|
4848
|
+
arbi,
|
|
4849
|
+
docs
|
|
4850
|
+
);
|
|
4517
4851
|
success(`Updated ${data.length} document(s).`);
|
|
4518
4852
|
} else {
|
|
4519
4853
|
const { arbi, workspaceId } = await resolveWorkspace();
|
|
@@ -4556,7 +4890,7 @@ function registerDocsCommand(program2) {
|
|
|
4556
4890
|
);
|
|
4557
4891
|
doc.command("parsed <doc-id> [stage]").description("Get parsed document content (stage: marker, subchunk, final; default: final)").action(
|
|
4558
4892
|
(docId, stage) => runAction(async () => {
|
|
4559
|
-
const { accessToken,
|
|
4893
|
+
const { accessToken, config } = await resolveWorkspace();
|
|
4560
4894
|
const validStages = ["marker", "subchunk", "final"];
|
|
4561
4895
|
const selectedStage = stage ?? "final";
|
|
4562
4896
|
if (!validStages.includes(selectedStage)) {
|
|
@@ -4564,7 +4898,7 @@ function registerDocsCommand(program2) {
|
|
|
4564
4898
|
process.exit(1);
|
|
4565
4899
|
}
|
|
4566
4900
|
const data = await sdk.documents.getParsedContent(
|
|
4567
|
-
{ baseUrl: config.baseUrl, accessToken
|
|
4901
|
+
{ baseUrl: config.baseUrl, accessToken },
|
|
4568
4902
|
docId,
|
|
4569
4903
|
selectedStage
|
|
4570
4904
|
);
|
|
@@ -4581,11 +4915,9 @@ function registerUploadCommand(program2) {
|
|
|
4581
4915
|
process.exit(1);
|
|
4582
4916
|
}
|
|
4583
4917
|
}
|
|
4584
|
-
const { config, accessToken,
|
|
4585
|
-
opts.workspace
|
|
4586
|
-
);
|
|
4918
|
+
const { config, accessToken, workspaceId } = await resolveWorkspace(opts.workspace);
|
|
4587
4919
|
const uploadedDocs = /* @__PURE__ */ new Map();
|
|
4588
|
-
const auth = { baseUrl: config.baseUrl, accessToken
|
|
4920
|
+
const auth = { baseUrl: config.baseUrl, accessToken };
|
|
4589
4921
|
for (const filePath of paths) {
|
|
4590
4922
|
const stat = fs2__default.default.statSync(filePath);
|
|
4591
4923
|
if (stat.isDirectory()) {
|
|
@@ -4697,7 +5029,7 @@ Connection closed. ${pending.size} document(s) still processing.`);
|
|
|
4697
5029
|
function registerDownloadCommand(program2) {
|
|
4698
5030
|
program2.command("download [doc-id]").description("Download a document (interactive picker if no ID given)").option("-o, --output <path>", "Output file path").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").action(
|
|
4699
5031
|
(docId, opts) => runAction(async () => {
|
|
4700
|
-
const { arbi, config, accessToken,
|
|
5032
|
+
const { arbi, config, accessToken, workspaceId } = await resolveWorkspace(opts.workspace);
|
|
4701
5033
|
if (!docId) {
|
|
4702
5034
|
const data = await sdk.documents.listDocuments(arbi);
|
|
4703
5035
|
if (data.length === 0) {
|
|
@@ -4712,7 +5044,7 @@ function registerDownloadCommand(program2) {
|
|
|
4712
5044
|
docId = await promptSearch("Select document to download", choices);
|
|
4713
5045
|
}
|
|
4714
5046
|
const res = await sdk.documents.downloadDocument(
|
|
4715
|
-
{ baseUrl: config.baseUrl, accessToken
|
|
5047
|
+
{ baseUrl: config.baseUrl, accessToken },
|
|
4716
5048
|
docId
|
|
4717
5049
|
);
|
|
4718
5050
|
let filename = `${docId}`;
|
|
@@ -4734,7 +5066,7 @@ function registerAskCommand(program2) {
|
|
|
4734
5066
|
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(
|
|
4735
5067
|
(words, opts) => runAction(async () => {
|
|
4736
5068
|
const question = words.join(" ");
|
|
4737
|
-
const { arbi, accessToken,
|
|
5069
|
+
const { arbi, accessToken, workspaceId, config } = await resolveWorkspace(opts.workspace);
|
|
4738
5070
|
let previousResponseId = null;
|
|
4739
5071
|
if (opts.continue) {
|
|
4740
5072
|
previousResponseId = opts.continue;
|
|
@@ -4755,7 +5087,6 @@ function registerAskCommand(program2) {
|
|
|
4755
5087
|
const result2 = await sdk.responses.submitBackgroundQuery({
|
|
4756
5088
|
baseUrl: config.baseUrl,
|
|
4757
5089
|
accessToken,
|
|
4758
|
-
workspaceKeyHeader,
|
|
4759
5090
|
workspaceId,
|
|
4760
5091
|
question,
|
|
4761
5092
|
docIds,
|
|
@@ -4785,7 +5116,6 @@ function registerAskCommand(program2) {
|
|
|
4785
5116
|
res = await sdk.assistant.queryAssistant({
|
|
4786
5117
|
baseUrl: config.baseUrl,
|
|
4787
5118
|
accessToken,
|
|
4788
|
-
workspaceKeyHeader,
|
|
4789
5119
|
workspaceId,
|
|
4790
5120
|
question,
|
|
4791
5121
|
docIds,
|
|
@@ -4799,7 +5129,6 @@ function registerAskCommand(program2) {
|
|
|
4799
5129
|
res = await sdk.assistant.queryAssistant({
|
|
4800
5130
|
baseUrl: config.baseUrl,
|
|
4801
5131
|
accessToken,
|
|
4802
|
-
workspaceKeyHeader,
|
|
4803
5132
|
workspaceId,
|
|
4804
5133
|
question,
|
|
4805
5134
|
docIds,
|
|
@@ -5190,11 +5519,11 @@ function registerContactsCommand(program2) {
|
|
|
5190
5519
|
});
|
|
5191
5520
|
}
|
|
5192
5521
|
function registerDmCommand(program2) {
|
|
5193
|
-
const dm = program2.command("dm").description("Direct messages");
|
|
5194
|
-
dm.command("list").description("List all DMs and notifications").action(
|
|
5522
|
+
const dm = program2.command("dm").description("Direct messages (E2E encrypted)");
|
|
5523
|
+
dm.command("list").description("List all DMs and notifications (decrypted)").action(
|
|
5195
5524
|
runAction(async () => {
|
|
5196
|
-
const { arbi } = await
|
|
5197
|
-
const data = await sdk.dm.
|
|
5525
|
+
const { arbi, crypto } = await resolveDmCrypto();
|
|
5526
|
+
const data = await sdk.dm.listDecryptedDMs(arbi, crypto);
|
|
5198
5527
|
if (data.length === 0) {
|
|
5199
5528
|
console.log("No messages found.");
|
|
5200
5529
|
return;
|
|
@@ -5218,18 +5547,18 @@ function registerDmCommand(program2) {
|
|
|
5218
5547
|
);
|
|
5219
5548
|
})
|
|
5220
5549
|
);
|
|
5221
|
-
dm.command("send [recipient] [content]").description("Send
|
|
5222
|
-
(recipient,
|
|
5223
|
-
const { arbi } = await
|
|
5550
|
+
dm.command("send [recipient] [content...]").description("Send an E2E encrypted DM (interactive if no args)").action(
|
|
5551
|
+
(recipient, contentParts) => runAction(async () => {
|
|
5552
|
+
const { arbi, crypto } = await resolveDmCrypto();
|
|
5224
5553
|
if (!recipient) {
|
|
5225
|
-
const
|
|
5226
|
-
if (
|
|
5554
|
+
const contacts2 = await sdk.contacts.listContacts(arbi);
|
|
5555
|
+
if (contacts2.length === 0) {
|
|
5227
5556
|
error("No contacts found. Add contacts first: arbi contacts add <email>");
|
|
5228
5557
|
process.exit(1);
|
|
5229
5558
|
}
|
|
5230
5559
|
recipient = await promptSelect(
|
|
5231
5560
|
"Send to",
|
|
5232
|
-
|
|
5561
|
+
contacts2.map((c) => {
|
|
5233
5562
|
const u = c.user;
|
|
5234
5563
|
const name = sdk.formatUserName(u);
|
|
5235
5564
|
return {
|
|
@@ -5240,21 +5569,93 @@ function registerDmCommand(program2) {
|
|
|
5240
5569
|
})
|
|
5241
5570
|
);
|
|
5242
5571
|
}
|
|
5572
|
+
let content = contentParts?.length ? contentParts.join(" ") : void 0;
|
|
5243
5573
|
if (!content) {
|
|
5244
5574
|
content = await promptInput("Message");
|
|
5245
5575
|
}
|
|
5576
|
+
const contacts = await sdk.contacts.listContacts(arbi);
|
|
5246
5577
|
let recipientExtId = recipient;
|
|
5578
|
+
let recipientPubKey;
|
|
5247
5579
|
if (recipient.includes("@")) {
|
|
5248
|
-
const contacts = await sdk.contacts.listContacts(arbi);
|
|
5249
5580
|
const match = contacts.find((c) => c.email === recipient);
|
|
5250
|
-
if (
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5581
|
+
if (match) {
|
|
5582
|
+
const u = match.user;
|
|
5583
|
+
recipientExtId = u?.external_id ?? match.external_id;
|
|
5584
|
+
recipientPubKey = u?.encryption_public_key;
|
|
5585
|
+
} else {
|
|
5586
|
+
try {
|
|
5587
|
+
const agentsList = await sdk.agents.listAgents(arbi);
|
|
5588
|
+
const agentMatch = agentsList.find((a) => a.email === recipient);
|
|
5589
|
+
if (agentMatch) {
|
|
5590
|
+
recipientExtId = agentMatch.external_id;
|
|
5591
|
+
recipientPubKey = agentMatch.encryption_public_key;
|
|
5592
|
+
}
|
|
5593
|
+
} catch {
|
|
5594
|
+
}
|
|
5595
|
+
if (!recipientPubKey) {
|
|
5596
|
+
try {
|
|
5597
|
+
const wsUsers = await sdk.workspaces.listWorkspaceUsers(arbi);
|
|
5598
|
+
const wsMatch = wsUsers.find(
|
|
5599
|
+
(wu) => wu.email === recipient
|
|
5600
|
+
);
|
|
5601
|
+
if (wsMatch) {
|
|
5602
|
+
const u = wsMatch;
|
|
5603
|
+
recipientExtId = u.external_id;
|
|
5604
|
+
recipientPubKey = u.encryption_public_key;
|
|
5605
|
+
}
|
|
5606
|
+
} catch {
|
|
5607
|
+
}
|
|
5608
|
+
}
|
|
5609
|
+
if (!recipientExtId || recipientExtId === recipient) {
|
|
5610
|
+
error(`No contact, agent, or workspace member found with email: ${recipient}`);
|
|
5611
|
+
process.exit(1);
|
|
5612
|
+
}
|
|
5254
5613
|
}
|
|
5255
|
-
|
|
5614
|
+
} else {
|
|
5615
|
+
const match = contacts.find((c) => {
|
|
5616
|
+
const u = c.user;
|
|
5617
|
+
return u?.external_id === recipient || c.external_id === recipient;
|
|
5618
|
+
});
|
|
5619
|
+
recipientPubKey = match?.user?.encryption_public_key;
|
|
5620
|
+
if (!recipientPubKey) {
|
|
5621
|
+
try {
|
|
5622
|
+
const agentsList = await sdk.agents.listAgents(arbi);
|
|
5623
|
+
const agentMatch = agentsList.find((a) => a.external_id === recipientExtId);
|
|
5624
|
+
if (agentMatch) {
|
|
5625
|
+
recipientPubKey = agentMatch.encryption_public_key;
|
|
5626
|
+
}
|
|
5627
|
+
} catch {
|
|
5628
|
+
}
|
|
5629
|
+
}
|
|
5630
|
+
if (!recipientPubKey) {
|
|
5631
|
+
try {
|
|
5632
|
+
const wsUsers = await sdk.workspaces.listWorkspaceUsers(arbi);
|
|
5633
|
+
const wsMatch = wsUsers.find(
|
|
5634
|
+
(wu) => wu.external_id === recipientExtId
|
|
5635
|
+
);
|
|
5636
|
+
if (wsMatch) {
|
|
5637
|
+
recipientPubKey = wsMatch.encryption_public_key;
|
|
5638
|
+
}
|
|
5639
|
+
} catch {
|
|
5640
|
+
}
|
|
5641
|
+
}
|
|
5642
|
+
}
|
|
5643
|
+
if (!recipientPubKey) {
|
|
5644
|
+
error("Cannot send encrypted DM \u2014 recipient public key not found.");
|
|
5645
|
+
error("The recipient is not in your contacts or workspace.");
|
|
5646
|
+
process.exit(1);
|
|
5256
5647
|
}
|
|
5257
|
-
const data = await sdk.dm.
|
|
5648
|
+
const data = await sdk.dm.sendEncryptedDM(
|
|
5649
|
+
arbi,
|
|
5650
|
+
[
|
|
5651
|
+
{
|
|
5652
|
+
recipient_ext_id: recipientExtId,
|
|
5653
|
+
content,
|
|
5654
|
+
recipient_encryption_public_key: recipientPubKey
|
|
5655
|
+
}
|
|
5656
|
+
],
|
|
5657
|
+
crypto
|
|
5658
|
+
);
|
|
5258
5659
|
for (const n of data) {
|
|
5259
5660
|
success(`Sent: ${n.external_id} \u2192 ${n.recipient.email}`);
|
|
5260
5661
|
}
|
|
@@ -5262,10 +5663,10 @@ function registerDmCommand(program2) {
|
|
|
5262
5663
|
);
|
|
5263
5664
|
dm.command("read [ids...]").description("Mark messages as read (interactive picker if no IDs given)").action(
|
|
5264
5665
|
(ids) => runAction(async () => {
|
|
5265
|
-
const { arbi } = await
|
|
5666
|
+
const { arbi, crypto } = await resolveDmCrypto();
|
|
5266
5667
|
let msgIds = ids && ids.length > 0 ? ids : void 0;
|
|
5267
5668
|
if (!msgIds) {
|
|
5268
|
-
const data2 = await sdk.dm.
|
|
5669
|
+
const data2 = await sdk.dm.listDecryptedDMs(arbi, crypto);
|
|
5269
5670
|
const unread = data2.filter((m) => !m.read);
|
|
5270
5671
|
if (unread.length === 0) {
|
|
5271
5672
|
console.log("No unread messages.");
|
|
@@ -5290,10 +5691,10 @@ function registerDmCommand(program2) {
|
|
|
5290
5691
|
);
|
|
5291
5692
|
dm.command("delete [ids...]").description("Delete messages (interactive picker if no IDs given)").action(
|
|
5292
5693
|
(ids) => runAction(async () => {
|
|
5293
|
-
const { arbi } = await
|
|
5694
|
+
const { arbi, crypto } = await resolveDmCrypto();
|
|
5294
5695
|
let msgIds = ids && ids.length > 0 ? ids : void 0;
|
|
5295
5696
|
if (!msgIds) {
|
|
5296
|
-
const data = await sdk.dm.
|
|
5697
|
+
const data = await sdk.dm.listDecryptedDMs(arbi, crypto);
|
|
5297
5698
|
if (data.length === 0) {
|
|
5298
5699
|
console.log("No messages found.");
|
|
5299
5700
|
return;
|
|
@@ -5385,7 +5786,10 @@ function registerTagsCommand(program2) {
|
|
|
5385
5786
|
const shared = interactive ? opts.shared || await promptConfirm("Shared?", false) : opts.shared ?? false;
|
|
5386
5787
|
const data = await sdk.tags.createTag(arbi, {
|
|
5387
5788
|
name,
|
|
5388
|
-
tagType: {
|
|
5789
|
+
tagType: {
|
|
5790
|
+
type: tagType,
|
|
5791
|
+
options: []
|
|
5792
|
+
},
|
|
5389
5793
|
instruction,
|
|
5390
5794
|
shared
|
|
5391
5795
|
});
|
|
@@ -6028,16 +6432,19 @@ function registerQuickstartCommand(program2) {
|
|
|
6028
6432
|
password2 = await promptPassword("Password");
|
|
6029
6433
|
}
|
|
6030
6434
|
try {
|
|
6031
|
-
const { arbi } = await sdk.performPasswordLogin(config, email, password2, store);
|
|
6435
|
+
const { arbi, loginResult } = await sdk.performPasswordLogin(config, email, password2, store);
|
|
6032
6436
|
success(`Logged in as ${email}`);
|
|
6033
6437
|
const { data: workspaces3 } = await arbi.fetch.GET("/v1/user/workspaces");
|
|
6034
6438
|
const wsList = workspaces3 || [];
|
|
6035
|
-
const memberWorkspaces = wsList.filter(
|
|
6439
|
+
const memberWorkspaces = wsList.filter(
|
|
6440
|
+
(ws) => ws.users?.some((u) => u.user.email === email)
|
|
6441
|
+
);
|
|
6036
6442
|
let workspaceId;
|
|
6037
6443
|
let workspaceName;
|
|
6038
6444
|
if (memberWorkspaces.length === 0) {
|
|
6039
6445
|
console.log("Creating your first workspace...");
|
|
6040
|
-
const
|
|
6446
|
+
const encryptedKey = await sdk.generateNewWorkspaceKey(arbi, loginResult.serverSessionKey);
|
|
6447
|
+
const ws = await sdk.workspaces.createWorkspace(arbi, "My Workspace", encryptedKey);
|
|
6041
6448
|
workspaceId = ws.external_id;
|
|
6042
6449
|
workspaceName = ws.name;
|
|
6043
6450
|
} else {
|
|
@@ -6048,7 +6455,8 @@ function registerQuickstartCommand(program2) {
|
|
|
6048
6455
|
const selected = await promptSelect("Select workspace", choices);
|
|
6049
6456
|
if (selected === "__new__") {
|
|
6050
6457
|
const name = await promptInput("Workspace name", false) || "My Workspace";
|
|
6051
|
-
const
|
|
6458
|
+
const encKey = await sdk.generateNewWorkspaceKey(arbi, loginResult.serverSessionKey);
|
|
6459
|
+
const ws = await sdk.workspaces.createWorkspace(arbi, name, encKey);
|
|
6052
6460
|
workspaceId = ws.external_id;
|
|
6053
6461
|
workspaceName = ws.name;
|
|
6054
6462
|
} else {
|
|
@@ -6147,8 +6555,14 @@ function registerAgentCreateCommand(program2) {
|
|
|
6147
6555
|
process.exit(1);
|
|
6148
6556
|
}
|
|
6149
6557
|
try {
|
|
6150
|
-
const { arbi } = await sdk.performPasswordLogin(
|
|
6151
|
-
|
|
6558
|
+
const { arbi, loginResult } = await sdk.performPasswordLogin(
|
|
6559
|
+
config,
|
|
6560
|
+
email,
|
|
6561
|
+
opts.password,
|
|
6562
|
+
store
|
|
6563
|
+
);
|
|
6564
|
+
const encryptedKey = await sdk.generateNewWorkspaceKey(arbi, loginResult.serverSessionKey);
|
|
6565
|
+
const ws = await sdk.workspaces.createWorkspace(arbi, opts.workspaceName, encryptedKey);
|
|
6152
6566
|
updateConfig({ selectedWorkspaceId: ws.external_id });
|
|
6153
6567
|
console.log("");
|
|
6154
6568
|
success("Agent account created!");
|
|
@@ -6166,6 +6580,60 @@ function registerAgentCreateCommand(program2) {
|
|
|
6166
6580
|
}
|
|
6167
6581
|
);
|
|
6168
6582
|
}
|
|
6583
|
+
function registerAgentCommand(program2) {
|
|
6584
|
+
const agent = program2.command("agent").description("Manage persistent agents");
|
|
6585
|
+
agent.command("list").description("List your persistent agents").action(
|
|
6586
|
+
runAction(async () => {
|
|
6587
|
+
const { arbi } = await resolveAuth();
|
|
6588
|
+
const data = await sdk.agents.listAgents(arbi);
|
|
6589
|
+
if (data.length === 0) {
|
|
6590
|
+
console.log("No agents found.");
|
|
6591
|
+
return;
|
|
6592
|
+
}
|
|
6593
|
+
printTable(
|
|
6594
|
+
[
|
|
6595
|
+
{ header: "ID", width: 20, value: (r) => r.external_id },
|
|
6596
|
+
{
|
|
6597
|
+
header: "NAME",
|
|
6598
|
+
width: 24,
|
|
6599
|
+
value: (r) => sdk.formatUserName(r) || r.email || ""
|
|
6600
|
+
},
|
|
6601
|
+
{ header: "EMAIL", width: 40, value: (r) => r.email || "" }
|
|
6602
|
+
],
|
|
6603
|
+
data
|
|
6604
|
+
);
|
|
6605
|
+
})
|
|
6606
|
+
);
|
|
6607
|
+
agent.command("delete [agent-id]").description("Delete a persistent agent (picker if no ID)").action(
|
|
6608
|
+
(agentId) => runAction(async () => {
|
|
6609
|
+
const { arbi } = await resolveAuth();
|
|
6610
|
+
if (!agentId) {
|
|
6611
|
+
const data = await sdk.agents.listAgents(arbi);
|
|
6612
|
+
if (data.length === 0) {
|
|
6613
|
+
console.log("No agents to delete.");
|
|
6614
|
+
return;
|
|
6615
|
+
}
|
|
6616
|
+
agentId = await promptSelect(
|
|
6617
|
+
"Select agent to delete",
|
|
6618
|
+
data.map((a) => ({
|
|
6619
|
+
name: `${sdk.formatUserName(a) || a.email} (${a.external_id})`,
|
|
6620
|
+
value: a.external_id
|
|
6621
|
+
}))
|
|
6622
|
+
);
|
|
6623
|
+
}
|
|
6624
|
+
const confirmed = await promptConfirm(`Delete agent ${agentId}?`, false);
|
|
6625
|
+
if (!confirmed) {
|
|
6626
|
+
console.log("Cancelled.");
|
|
6627
|
+
return;
|
|
6628
|
+
}
|
|
6629
|
+
await sdk.agents.deleteAgents(arbi, [agentId]);
|
|
6630
|
+
success(`Agent ${agentId} deleted.`);
|
|
6631
|
+
})()
|
|
6632
|
+
);
|
|
6633
|
+
agent.action(async () => {
|
|
6634
|
+
await agent.commands.find((c) => c.name() === "list").parseAsync([], { from: "user" });
|
|
6635
|
+
});
|
|
6636
|
+
}
|
|
6169
6637
|
function formatAge(isoDate) {
|
|
6170
6638
|
const ms = Date.now() - new Date(isoDate).getTime();
|
|
6171
6639
|
if (ms < 6e4) return `${Math.round(ms / 1e3)}s`;
|
|
@@ -6214,11 +6682,8 @@ function registerTaskCommand(program2) {
|
|
|
6214
6682
|
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(
|
|
6215
6683
|
(taskId, opts) => runAction(async () => {
|
|
6216
6684
|
const id = resolveTaskId(taskId);
|
|
6217
|
-
const { accessToken,
|
|
6218
|
-
const result = await sdk.responses.getResponse(
|
|
6219
|
-
{ baseUrl: config.baseUrl, accessToken, workspaceKeyHeader },
|
|
6220
|
-
id
|
|
6221
|
-
);
|
|
6685
|
+
const { accessToken, config } = await resolveWorkspace(opts?.workspace);
|
|
6686
|
+
const result = await sdk.responses.getResponse({ baseUrl: config.baseUrl, accessToken }, id);
|
|
6222
6687
|
if (result.status === "completed" || result.status === "failed") {
|
|
6223
6688
|
updateTaskStatus(id, result.status);
|
|
6224
6689
|
}
|
|
@@ -6237,11 +6702,8 @@ function registerTaskCommand(program2) {
|
|
|
6237
6702
|
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(
|
|
6238
6703
|
(taskId, opts) => runAction(async () => {
|
|
6239
6704
|
const id = resolveTaskId(taskId);
|
|
6240
|
-
const { accessToken,
|
|
6241
|
-
const result = await sdk.responses.getResponse(
|
|
6242
|
-
{ baseUrl: config.baseUrl, accessToken, workspaceKeyHeader },
|
|
6243
|
-
id
|
|
6244
|
-
);
|
|
6705
|
+
const { accessToken, config } = await resolveWorkspace(opts?.workspace);
|
|
6706
|
+
const result = await sdk.responses.getResponse({ baseUrl: config.baseUrl, accessToken }, id);
|
|
6245
6707
|
if (result.status === "completed" || result.status === "failed") {
|
|
6246
6708
|
updateTaskStatus(id, result.status);
|
|
6247
6709
|
}
|
|
@@ -6342,6 +6804,220 @@ function registerCompletionCommand(program2) {
|
|
|
6342
6804
|
})
|
|
6343
6805
|
);
|
|
6344
6806
|
}
|
|
6807
|
+
function resolvePath(p) {
|
|
6808
|
+
const raw = p ?? ".";
|
|
6809
|
+
const expanded = raw.startsWith("~") ? raw.replace("~", os.homedir()) : raw;
|
|
6810
|
+
return path.resolve(expanded);
|
|
6811
|
+
}
|
|
6812
|
+
function formatSize(bytes) {
|
|
6813
|
+
if (bytes < 1024) return `${bytes}B`;
|
|
6814
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}K`;
|
|
6815
|
+
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)}M`;
|
|
6816
|
+
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)}G`;
|
|
6817
|
+
}
|
|
6818
|
+
function registerLocalCommand(program2) {
|
|
6819
|
+
const local = program2.command("local").description("Local filesystem operations");
|
|
6820
|
+
local.command("ls [path]").description("List files in a directory").option("-l, --long", "Show file sizes and types").action((path5, opts) => {
|
|
6821
|
+
const dir = resolvePath(path5);
|
|
6822
|
+
let entries;
|
|
6823
|
+
try {
|
|
6824
|
+
entries = fs2.readdirSync(dir);
|
|
6825
|
+
} catch {
|
|
6826
|
+
console.error(`Cannot read directory: ${dir}`);
|
|
6827
|
+
process.exit(1);
|
|
6828
|
+
}
|
|
6829
|
+
for (const entry of entries.filter((e) => !e.startsWith(".")).sort()) {
|
|
6830
|
+
if (opts?.long) {
|
|
6831
|
+
try {
|
|
6832
|
+
const stat = fs2.statSync(path.join(dir, entry));
|
|
6833
|
+
const type = stat.isDirectory() ? "dir" : "file";
|
|
6834
|
+
const size = stat.isFile() ? formatSize(stat.size) : "-";
|
|
6835
|
+
console.log(`${type.padEnd(5)} ${size.padStart(10)} ${entry}`);
|
|
6836
|
+
} catch {
|
|
6837
|
+
console.log(`? ${"-".padStart(10)} ${entry}`);
|
|
6838
|
+
}
|
|
6839
|
+
} else {
|
|
6840
|
+
console.log(entry);
|
|
6841
|
+
}
|
|
6842
|
+
}
|
|
6843
|
+
});
|
|
6844
|
+
local.command("find <pattern>").description('Find files matching a glob (e.g. "**/*.pdf")').option("-d, --dir <path>", "Directory to search in", ".").action((pattern, opts) => {
|
|
6845
|
+
const dir = resolvePath(opts.dir);
|
|
6846
|
+
const results = fs2.globSync(pattern, { cwd: dir });
|
|
6847
|
+
if (results.length === 0) {
|
|
6848
|
+
console.log(`No files matching "${pattern}" in ${dir}`);
|
|
6849
|
+
return;
|
|
6850
|
+
}
|
|
6851
|
+
for (const file of results) {
|
|
6852
|
+
console.log(file);
|
|
6853
|
+
}
|
|
6854
|
+
});
|
|
6855
|
+
local.command("cat <file>").description("Print file contents").option("--head <lines>", "Only show first N lines").action((file, opts) => {
|
|
6856
|
+
const filePath = resolvePath(file);
|
|
6857
|
+
let content;
|
|
6858
|
+
try {
|
|
6859
|
+
content = fs2.readFileSync(filePath, "utf-8");
|
|
6860
|
+
} catch {
|
|
6861
|
+
console.error(`Cannot read file: ${filePath}`);
|
|
6862
|
+
process.exit(1);
|
|
6863
|
+
}
|
|
6864
|
+
if (opts.head) {
|
|
6865
|
+
const n = parseInt(opts.head, 10);
|
|
6866
|
+
console.log(content.split("\n").slice(0, n).join("\n"));
|
|
6867
|
+
} else {
|
|
6868
|
+
console.log(content);
|
|
6869
|
+
}
|
|
6870
|
+
});
|
|
6871
|
+
local.command("tree [path]").description("Show directory tree").option("-d, --depth <n>", "Maximum depth", "3").action((path5, opts) => {
|
|
6872
|
+
const dir = resolvePath(path5);
|
|
6873
|
+
const maxDepth = parseInt(opts?.depth ?? "3", 10);
|
|
6874
|
+
console.log(path.basename(dir) + "/");
|
|
6875
|
+
printTree(dir, "", maxDepth, 0);
|
|
6876
|
+
});
|
|
6877
|
+
}
|
|
6878
|
+
function printTree(dir, prefix, maxDepth, depth) {
|
|
6879
|
+
if (depth >= maxDepth) return;
|
|
6880
|
+
let entries;
|
|
6881
|
+
try {
|
|
6882
|
+
entries = fs2.readdirSync(dir).filter((e) => !e.startsWith(".")).sort();
|
|
6883
|
+
} catch {
|
|
6884
|
+
return;
|
|
6885
|
+
}
|
|
6886
|
+
for (let i = 0; i < entries.length; i++) {
|
|
6887
|
+
const entry = entries[i];
|
|
6888
|
+
const isLast = i === entries.length - 1;
|
|
6889
|
+
const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
6890
|
+
const full = path.join(dir, entry);
|
|
6891
|
+
let isDir = false;
|
|
6892
|
+
try {
|
|
6893
|
+
isDir = fs2.statSync(full).isDirectory();
|
|
6894
|
+
} catch {
|
|
6895
|
+
continue;
|
|
6896
|
+
}
|
|
6897
|
+
console.log(`${prefix}${connector}${entry}${isDir ? "/" : ""}`);
|
|
6898
|
+
if (isDir) {
|
|
6899
|
+
const nextPrefix = prefix + (isLast ? " " : "\u2502 ");
|
|
6900
|
+
printTree(full, nextPrefix, maxDepth, depth + 1);
|
|
6901
|
+
}
|
|
6902
|
+
}
|
|
6903
|
+
}
|
|
6904
|
+
async function authorizeShared(opts) {
|
|
6905
|
+
const { arbi, loginResult } = await resolveAuth();
|
|
6906
|
+
let name = opts.name;
|
|
6907
|
+
if (!name) {
|
|
6908
|
+
name = await promptInput(opts.persist ? "Agent name" : "Session name");
|
|
6909
|
+
}
|
|
6910
|
+
if (!name?.trim()) {
|
|
6911
|
+
error("Name is required");
|
|
6912
|
+
process.exit(1);
|
|
6913
|
+
}
|
|
6914
|
+
const { data: allWorkspaces, error: wsErr } = await arbi.fetch.GET("/v1/user/workspaces");
|
|
6915
|
+
if (wsErr || !allWorkspaces || allWorkspaces.length === 0) {
|
|
6916
|
+
error("No workspaces found");
|
|
6917
|
+
process.exit(1);
|
|
6918
|
+
}
|
|
6919
|
+
let workspaceIds = opts.workspace;
|
|
6920
|
+
if (!workspaceIds || workspaceIds.length === 0) {
|
|
6921
|
+
workspaceIds = await promptCheckbox(
|
|
6922
|
+
"Select workspaces to grant access",
|
|
6923
|
+
allWorkspaces.map((ws) => ({
|
|
6924
|
+
name: `${ws.name} (${ws.external_id})`,
|
|
6925
|
+
value: ws.external_id
|
|
6926
|
+
}))
|
|
6927
|
+
);
|
|
6928
|
+
}
|
|
6929
|
+
if (workspaceIds.length === 0) {
|
|
6930
|
+
error("At least one workspace is required");
|
|
6931
|
+
process.exit(1);
|
|
6932
|
+
}
|
|
6933
|
+
const creds = store.requireCredentials();
|
|
6934
|
+
const workspaceKeysMap = {};
|
|
6935
|
+
for (const wsId of workspaceIds) {
|
|
6936
|
+
const ws = allWorkspaces.find((w) => w.external_id === wsId);
|
|
6937
|
+
if (!ws?.wrapped_key) {
|
|
6938
|
+
error(`Workspace ${wsId} not found or has no encryption key`);
|
|
6939
|
+
process.exit(1);
|
|
6940
|
+
}
|
|
6941
|
+
const encryptedKey = await sdk.generateEncryptedWorkspaceKey(
|
|
6942
|
+
arbi,
|
|
6943
|
+
ws.wrapped_key,
|
|
6944
|
+
loginResult.serverSessionKey,
|
|
6945
|
+
creds.signingPrivateKeyBase64
|
|
6946
|
+
);
|
|
6947
|
+
workspaceKeysMap[wsId] = encryptedKey;
|
|
6948
|
+
}
|
|
6949
|
+
const ttl = parseInt(opts.ttl || "3600", 10);
|
|
6950
|
+
const response = await sdk.sessions.authorizeSession(arbi, workspaceKeysMap, {
|
|
6951
|
+
activeWorkspace: workspaceIds[0],
|
|
6952
|
+
ttl,
|
|
6953
|
+
persistIdentity: opts.persist,
|
|
6954
|
+
name: name.trim()
|
|
6955
|
+
});
|
|
6956
|
+
return { response, ttl };
|
|
6957
|
+
}
|
|
6958
|
+
function registerAuthorizeCommand(program2) {
|
|
6959
|
+
const authorize = program2.command("authorize").description("Create a claim code for a session or agent");
|
|
6960
|
+
authorize.command("agent").description("Create a persistent agent identity with a claim code").option("--name <name>", "Agent name").option("-w, --workspace <ids...>", "Workspace IDs to grant access to (interactive if omitted)").action(
|
|
6961
|
+
(opts) => runAction(async () => {
|
|
6962
|
+
const { response } = await authorizeShared({ persist: true, ...opts });
|
|
6963
|
+
console.log("");
|
|
6964
|
+
success("Agent authorized!");
|
|
6965
|
+
console.log("");
|
|
6966
|
+
console.log(` Claim code: ${chalk2__default.default.cyan(chalk2__default.default.bold(response.claim_code))}`);
|
|
6967
|
+
console.log("");
|
|
6968
|
+
dim("On the agent machine: arbi connect --code <claim-code> --agent claude");
|
|
6969
|
+
})()
|
|
6970
|
+
);
|
|
6971
|
+
authorize.command("session").description("Create an ephemeral session with a claim code").option("--name <name>", "Session name").option("--ttl <seconds>", "Session TTL in seconds (default: 3600)", "3600").option("-w, --workspace <ids...>", "Workspace IDs to grant access to (interactive if omitted)").action(
|
|
6972
|
+
(opts) => runAction(async () => {
|
|
6973
|
+
const { response, ttl } = await authorizeShared({ persist: false, ...opts });
|
|
6974
|
+
console.log("");
|
|
6975
|
+
success("Session authorized!");
|
|
6976
|
+
console.log("");
|
|
6977
|
+
console.log(` Claim code: ${chalk2__default.default.cyan(chalk2__default.default.bold(response.claim_code))}`);
|
|
6978
|
+
console.log(` Expires in: ${ttl}s`);
|
|
6979
|
+
console.log("");
|
|
6980
|
+
dim("Claim with: arbi connect --code <claim-code>");
|
|
6981
|
+
})()
|
|
6982
|
+
);
|
|
6983
|
+
authorize.action(() => {
|
|
6984
|
+
authorize.help();
|
|
6985
|
+
});
|
|
6986
|
+
}
|
|
6987
|
+
function registerSessionCommand(program2) {
|
|
6988
|
+
const session = program2.command("session").description("List and manage sessions");
|
|
6989
|
+
session.command("list").description("List active sessions").action(
|
|
6990
|
+
runAction(async () => {
|
|
6991
|
+
const { arbi } = await resolveAuth();
|
|
6992
|
+
const data = await sdk.sessions.listSessions(arbi);
|
|
6993
|
+
if (data.length === 0) {
|
|
6994
|
+
console.log("No active sessions.");
|
|
6995
|
+
return;
|
|
6996
|
+
}
|
|
6997
|
+
printTable(
|
|
6998
|
+
[
|
|
6999
|
+
{
|
|
7000
|
+
header: "ID",
|
|
7001
|
+
width: 18,
|
|
7002
|
+
value: (r) => r.external_id || r.session_id
|
|
7003
|
+
},
|
|
7004
|
+
{ header: "NAME", width: 20, value: (r) => r.name || "" },
|
|
7005
|
+
{ header: "STATUS", width: 12, value: (r) => r.status },
|
|
7006
|
+
{ header: "TTL", width: 10, value: (r) => `${r.ttl}s` },
|
|
7007
|
+
{
|
|
7008
|
+
header: "WORKSPACES",
|
|
7009
|
+
width: 12,
|
|
7010
|
+
value: (r) => String(r.workspaces?.length ?? 0)
|
|
7011
|
+
}
|
|
7012
|
+
],
|
|
7013
|
+
data
|
|
7014
|
+
);
|
|
7015
|
+
})
|
|
7016
|
+
);
|
|
7017
|
+
session.action(async () => {
|
|
7018
|
+
await session.commands.find((c) => c.name() === "list").parseAsync([], { from: "user" });
|
|
7019
|
+
});
|
|
7020
|
+
}
|
|
6345
7021
|
|
|
6346
7022
|
// src/index.ts
|
|
6347
7023
|
console.debug = () => {
|
|
@@ -6352,7 +7028,7 @@ console.info = (...args) => {
|
|
|
6352
7028
|
_origInfo(...args);
|
|
6353
7029
|
};
|
|
6354
7030
|
var program = new commander.Command();
|
|
6355
|
-
program.name("arbi").description("ARBI CLI \u2014 interact with ARBI from the terminal").version("0.3.
|
|
7031
|
+
program.name("arbi").description("ARBI CLI \u2014 interact with ARBI from the terminal").version("0.3.20");
|
|
6356
7032
|
registerConfigCommand(program);
|
|
6357
7033
|
registerLoginCommand(program);
|
|
6358
7034
|
registerRegisterCommand(program);
|
|
@@ -6378,8 +7054,13 @@ registerTuiCommand(program);
|
|
|
6378
7054
|
registerUpdateCommand(program);
|
|
6379
7055
|
registerQuickstartCommand(program);
|
|
6380
7056
|
registerAgentCreateCommand(program);
|
|
7057
|
+
registerAgentCommand(program);
|
|
6381
7058
|
registerTaskCommand(program);
|
|
6382
7059
|
registerCompletionCommand(program);
|
|
7060
|
+
registerConnectCommand(program);
|
|
7061
|
+
registerAuthorizeCommand(program);
|
|
7062
|
+
registerSessionCommand(program);
|
|
7063
|
+
registerLocalCommand(program);
|
|
6383
7064
|
var completionIdx = process.argv.indexOf("--get-completions");
|
|
6384
7065
|
if (completionIdx !== -1) {
|
|
6385
7066
|
const line = process.argv[completionIdx + 1] ?? "";
|