@arbidocs/cli 0.3.89 → 0.3.90
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 +18 -0
- package/dist/index.js +394 -362
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -3694,7 +3694,7 @@ function getLatestVersion(skipCache = false) {
|
|
|
3694
3694
|
}
|
|
3695
3695
|
}
|
|
3696
3696
|
function getCurrentVersion() {
|
|
3697
|
-
return "0.3.
|
|
3697
|
+
return "0.3.90";
|
|
3698
3698
|
}
|
|
3699
3699
|
function readChangelog(fromVersion, toVersion) {
|
|
3700
3700
|
try {
|
|
@@ -3747,17 +3747,17 @@ function showChangelog(fromVersion, toVersion) {
|
|
|
3747
3747
|
async function checkForUpdates(autoUpdate) {
|
|
3748
3748
|
try {
|
|
3749
3749
|
const latest = getLatestVersion();
|
|
3750
|
-
if (!latest || latest === "0.3.
|
|
3750
|
+
if (!latest || latest === "0.3.90") return;
|
|
3751
3751
|
if (autoUpdate) {
|
|
3752
3752
|
warn(`
|
|
3753
|
-
Your arbi version is out of date (${"0.3.
|
|
3753
|
+
Your arbi version is out of date (${"0.3.90"} \u2192 ${latest}). Updating...`);
|
|
3754
3754
|
child_process.execSync("npm install -g @arbidocs/cli@latest", { stdio: "inherit" });
|
|
3755
|
-
showChangelog("0.3.
|
|
3755
|
+
showChangelog("0.3.90", latest);
|
|
3756
3756
|
console.log(`Updated to ${latest}.`);
|
|
3757
3757
|
} else {
|
|
3758
3758
|
warn(
|
|
3759
3759
|
`
|
|
3760
|
-
Your arbi version is out of date (${"0.3.
|
|
3760
|
+
Your arbi version is out of date (${"0.3.90"} \u2192 ${latest}).
|
|
3761
3761
|
Run "arbi update" to upgrade, or "arbi update auto" to always stay up to date.`
|
|
3762
3762
|
);
|
|
3763
3763
|
}
|
|
@@ -3789,10 +3789,10 @@ function markNagShown(latest) {
|
|
|
3789
3789
|
function hintUpdateOnError() {
|
|
3790
3790
|
try {
|
|
3791
3791
|
const cached = readCache();
|
|
3792
|
-
if (!cached || cached.latest === "0.3.
|
|
3792
|
+
if (!cached || cached.latest === "0.3.90") return;
|
|
3793
3793
|
if (!shouldShowNag(cached.latest)) return;
|
|
3794
3794
|
warn(
|
|
3795
|
-
`Your arbi version is out of date (${"0.3.
|
|
3795
|
+
`Your arbi version is out of date (${"0.3.90"} \u2192 ${cached.latest}). Run "arbi update".`
|
|
3796
3796
|
);
|
|
3797
3797
|
markNagShown(cached.latest);
|
|
3798
3798
|
} catch {
|
|
@@ -4803,6 +4803,283 @@ function registerStatusCommand(program2) {
|
|
|
4803
4803
|
});
|
|
4804
4804
|
}
|
|
4805
4805
|
init_prompts();
|
|
4806
|
+
async function resolveRecipient(arbi, ref2) {
|
|
4807
|
+
const isEmail = ref2.includes("@");
|
|
4808
|
+
const matchKey = isEmail ? "email" : "external_id";
|
|
4809
|
+
const contacts = await sdk.contacts.listContacts(arbi);
|
|
4810
|
+
const contactMatch = contacts.find((c) => {
|
|
4811
|
+
if (isEmail) return c.email === ref2;
|
|
4812
|
+
const u = c.user;
|
|
4813
|
+
return u?.external_id === ref2 || c.external_id === ref2;
|
|
4814
|
+
});
|
|
4815
|
+
if (contactMatch) {
|
|
4816
|
+
const u = contactMatch.user;
|
|
4817
|
+
const extId = u?.external_id ?? contactMatch.external_id;
|
|
4818
|
+
const pubKey = u?.encryption_public_key ?? "";
|
|
4819
|
+
if (pubKey) return { extId, pubKey };
|
|
4820
|
+
}
|
|
4821
|
+
try {
|
|
4822
|
+
const agents = await sdk.agents.listAgents(arbi);
|
|
4823
|
+
const agentMatch = agents.find((a) => a[matchKey] === ref2);
|
|
4824
|
+
if (agentMatch) {
|
|
4825
|
+
return { extId: agentMatch.external_id, pubKey: agentMatch.encryption_public_key };
|
|
4826
|
+
}
|
|
4827
|
+
} catch {
|
|
4828
|
+
}
|
|
4829
|
+
try {
|
|
4830
|
+
const wsUsers = await sdk.workspaces.listWorkspaceUsers(arbi);
|
|
4831
|
+
const wsMatch = wsUsers.find((wu) => wu[matchKey] === ref2);
|
|
4832
|
+
if (wsMatch) {
|
|
4833
|
+
const u = wsMatch;
|
|
4834
|
+
return {
|
|
4835
|
+
extId: u.external_id,
|
|
4836
|
+
pubKey: u.encryption_public_key
|
|
4837
|
+
};
|
|
4838
|
+
}
|
|
4839
|
+
} catch {
|
|
4840
|
+
}
|
|
4841
|
+
return null;
|
|
4842
|
+
}
|
|
4843
|
+
function rowMatchesFilters(row, opts) {
|
|
4844
|
+
if (opts.unread && row.read) return false;
|
|
4845
|
+
const sender = row.sender;
|
|
4846
|
+
const recipient = row.recipient;
|
|
4847
|
+
if (opts.from) {
|
|
4848
|
+
const needle = opts.from.toLowerCase();
|
|
4849
|
+
const senderMatch = sender?.email?.toLowerCase() === needle || sender?.external_id === opts.from;
|
|
4850
|
+
const recipientMatch = recipient?.email?.toLowerCase() === needle || recipient?.external_id === opts.from;
|
|
4851
|
+
if (!senderMatch && !recipientMatch) return false;
|
|
4852
|
+
}
|
|
4853
|
+
if (opts.thread) {
|
|
4854
|
+
const needle = opts.thread.toLowerCase();
|
|
4855
|
+
const peer = sender?.external_id === opts.myExtId ? recipient : sender;
|
|
4856
|
+
const peerMatch = peer?.email?.toLowerCase() === needle || peer?.external_id === opts.thread;
|
|
4857
|
+
if (!peerMatch) return false;
|
|
4858
|
+
}
|
|
4859
|
+
if (opts.since) {
|
|
4860
|
+
const cutoff = Date.parse(opts.since);
|
|
4861
|
+
if (Number.isFinite(cutoff)) {
|
|
4862
|
+
const createdAt = typeof row.created_at === "string" ? Date.parse(row.created_at) : NaN;
|
|
4863
|
+
if (!Number.isFinite(createdAt) || createdAt < cutoff) return false;
|
|
4864
|
+
}
|
|
4865
|
+
}
|
|
4866
|
+
return true;
|
|
4867
|
+
}
|
|
4868
|
+
function registerDmCommand(program2) {
|
|
4869
|
+
const dm = program2.command("dm").description("Direct messages (E2E encrypted)");
|
|
4870
|
+
dm.command("list").description("List direct messages (decrypted, newest first)").option("--unread", "Only show unread messages").option("--from <email-or-extid>", "Filter by sender OR recipient (email or usr- id)").option(
|
|
4871
|
+
"--thread <email-or-extid>",
|
|
4872
|
+
"Show the full conversation with one peer (both directions)"
|
|
4873
|
+
).option("--since <iso>", "Only messages newer than this ISO timestamp").option("-l, --limit <n>", "Cap to N most-recent messages", (v) => parseInt(v, 10)).option("--json", "Output as JSON (recommended for scripting / agents)").action(
|
|
4874
|
+
(opts) => runAction(async () => {
|
|
4875
|
+
const { arbi, crypto: crypto2 } = await resolveDmCrypto();
|
|
4876
|
+
const all = await sdk.dm.listDecryptedDMs(arbi, crypto2);
|
|
4877
|
+
const myExtId = arbi.session.getState().userExtId ?? void 0;
|
|
4878
|
+
const dms = all.filter((r) => r.type === "user_message");
|
|
4879
|
+
const filterOpts = {
|
|
4880
|
+
unread: Boolean(opts.unread),
|
|
4881
|
+
from: typeof opts.from === "string" ? opts.from : void 0,
|
|
4882
|
+
thread: typeof opts.thread === "string" ? opts.thread : void 0,
|
|
4883
|
+
since: typeof opts.since === "string" ? opts.since : void 0,
|
|
4884
|
+
myExtId
|
|
4885
|
+
};
|
|
4886
|
+
const filtered = dms.filter((r) => rowMatchesFilters(r, filterOpts));
|
|
4887
|
+
const limited = typeof opts.limit === "number" && opts.limit > 0 ? filtered.slice(0, opts.limit) : filtered;
|
|
4888
|
+
if (opts.json) {
|
|
4889
|
+
printJson(limited.map((r) => ({ ...r, encrypted_in_transit: true })));
|
|
4890
|
+
return;
|
|
4891
|
+
}
|
|
4892
|
+
if (limited.length === 0) {
|
|
4893
|
+
process.stderr.write("No messages found.\n");
|
|
4894
|
+
return;
|
|
4895
|
+
}
|
|
4896
|
+
const peer = (r) => {
|
|
4897
|
+
const s = r.sender;
|
|
4898
|
+
const recip = r.recipient;
|
|
4899
|
+
return s?.external_id === myExtId ? recip : s;
|
|
4900
|
+
};
|
|
4901
|
+
printTable(
|
|
4902
|
+
[
|
|
4903
|
+
{ header: "ID", width: 16, value: (r) => r.external_id },
|
|
4904
|
+
{
|
|
4905
|
+
header: "DIR",
|
|
4906
|
+
width: 4,
|
|
4907
|
+
value: (r) => r.sender?.external_id === myExtId ? "\u2192" : "\u2190"
|
|
4908
|
+
},
|
|
4909
|
+
{
|
|
4910
|
+
header: "PEER",
|
|
4911
|
+
width: 26,
|
|
4912
|
+
value: (r) => {
|
|
4913
|
+
const p = peer(r);
|
|
4914
|
+
return sdk.formatUserName(p) || p?.email || "";
|
|
4915
|
+
}
|
|
4916
|
+
},
|
|
4917
|
+
{ header: "READ", width: 6, value: (r) => r.read ? "yes" : "no" },
|
|
4918
|
+
{
|
|
4919
|
+
header: "CONTENT",
|
|
4920
|
+
width: 50,
|
|
4921
|
+
value: (r) => truncate(r.content ?? "", 49)
|
|
4922
|
+
}
|
|
4923
|
+
],
|
|
4924
|
+
limited
|
|
4925
|
+
);
|
|
4926
|
+
})()
|
|
4927
|
+
);
|
|
4928
|
+
dm.command("send [recipient] [content...]").description("Send an E2E encrypted DM (interactive if no args)").action(
|
|
4929
|
+
(recipient, contentParts) => runAction(async () => {
|
|
4930
|
+
const { arbi, crypto: crypto2 } = await resolveDmCrypto();
|
|
4931
|
+
if (!recipient) {
|
|
4932
|
+
requireInteractive(
|
|
4933
|
+
'Pass recipient + message as arguments: arbi dm send <email-or-id> "<message>"'
|
|
4934
|
+
);
|
|
4935
|
+
const contacts = await sdk.contacts.listContacts(arbi);
|
|
4936
|
+
if (contacts.length === 0) {
|
|
4937
|
+
error("No contacts found. Add contacts first: arbi contacts add <email>");
|
|
4938
|
+
process.exit(1);
|
|
4939
|
+
}
|
|
4940
|
+
recipient = await promptSelect(
|
|
4941
|
+
"Send to",
|
|
4942
|
+
contacts.map((c) => {
|
|
4943
|
+
const u = c.user;
|
|
4944
|
+
const name = sdk.formatUserName(u);
|
|
4945
|
+
return {
|
|
4946
|
+
name: name ? `${name} (${c.email})` : c.email,
|
|
4947
|
+
value: u?.external_id ?? c.external_id,
|
|
4948
|
+
description: c.email
|
|
4949
|
+
};
|
|
4950
|
+
})
|
|
4951
|
+
);
|
|
4952
|
+
}
|
|
4953
|
+
let content = contentParts?.length ? contentParts.join(" ") : void 0;
|
|
4954
|
+
if (!content) {
|
|
4955
|
+
requireInteractive(
|
|
4956
|
+
'Pass the message as a positional argument: arbi dm send <email> "your message"'
|
|
4957
|
+
);
|
|
4958
|
+
content = await promptInput("Message");
|
|
4959
|
+
}
|
|
4960
|
+
const resolved = await resolveRecipient(arbi, recipient);
|
|
4961
|
+
if (!resolved) {
|
|
4962
|
+
error(
|
|
4963
|
+
`No contact, agent, or workspace member found for: ${recipient}
|
|
4964
|
+
Try: arbi contacts add ${recipient.includes("@") ? recipient : "<their-email>"}`
|
|
4965
|
+
);
|
|
4966
|
+
process.exit(3);
|
|
4967
|
+
}
|
|
4968
|
+
const recipientExtId = resolved.extId;
|
|
4969
|
+
const recipientPubKey = resolved.pubKey;
|
|
4970
|
+
if (!recipientPubKey) {
|
|
4971
|
+
error(
|
|
4972
|
+
"Cannot send encrypted DM \u2014 recipient public key not found.\nAdd them as a contact first: arbi contacts add <email>"
|
|
4973
|
+
);
|
|
4974
|
+
process.exit(3);
|
|
4975
|
+
}
|
|
4976
|
+
const data = await sdk.dm.sendEncryptedDM(
|
|
4977
|
+
arbi,
|
|
4978
|
+
[
|
|
4979
|
+
{
|
|
4980
|
+
recipient_ext_id: recipientExtId,
|
|
4981
|
+
content,
|
|
4982
|
+
recipient_encryption_public_key: recipientPubKey
|
|
4983
|
+
}
|
|
4984
|
+
],
|
|
4985
|
+
crypto2
|
|
4986
|
+
);
|
|
4987
|
+
for (const n of data) {
|
|
4988
|
+
success(`Sent (encrypted): ${n.external_id} \u2192 ${n.recipient.email}`);
|
|
4989
|
+
}
|
|
4990
|
+
})()
|
|
4991
|
+
);
|
|
4992
|
+
dm.command("read [ids...]").description("Mark messages as read (interactive picker if no IDs given)").option("--all", "Mark every unread message as read (no picker)").action(
|
|
4993
|
+
(ids, opts) => runAction(async () => {
|
|
4994
|
+
const { arbi, crypto: crypto2 } = await resolveDmCrypto();
|
|
4995
|
+
let msgIds = ids && ids.length > 0 ? ids : void 0;
|
|
4996
|
+
if (!msgIds && opts?.all) {
|
|
4997
|
+
const data2 = await sdk.dm.listDecryptedDMs(arbi, crypto2);
|
|
4998
|
+
msgIds = data2.filter((m) => !m.read).map((m) => m.external_id);
|
|
4999
|
+
}
|
|
5000
|
+
if (!msgIds) {
|
|
5001
|
+
const data2 = await sdk.dm.listDecryptedDMs(arbi, crypto2);
|
|
5002
|
+
const unread = data2.filter((m) => !m.read);
|
|
5003
|
+
if (unread.length === 0) {
|
|
5004
|
+
process.stderr.write("No unread messages.\n");
|
|
5005
|
+
return;
|
|
5006
|
+
}
|
|
5007
|
+
requireInteractive("Pass IDs directly or use --all to mark every unread message read.");
|
|
5008
|
+
msgIds = await promptCheckbox(
|
|
5009
|
+
"Select messages to mark as read",
|
|
5010
|
+
unread.map((m) => {
|
|
5011
|
+
const s = m.sender;
|
|
5012
|
+
const from = sdk.formatUserName(s) || s?.email || "";
|
|
5013
|
+
return {
|
|
5014
|
+
name: `${from}: ${(m.content ?? "").slice(0, 50)}`,
|
|
5015
|
+
value: m.external_id
|
|
5016
|
+
};
|
|
5017
|
+
})
|
|
5018
|
+
);
|
|
5019
|
+
if (msgIds.length === 0) return;
|
|
5020
|
+
}
|
|
5021
|
+
if (msgIds.length === 0) {
|
|
5022
|
+
process.stderr.write("No unread messages.\n");
|
|
5023
|
+
return;
|
|
5024
|
+
}
|
|
5025
|
+
const data = await sdk.dm.markRead(arbi, msgIds);
|
|
5026
|
+
success(`Marked ${data.length} message(s) as read.`);
|
|
5027
|
+
})()
|
|
5028
|
+
);
|
|
5029
|
+
dm.command("delete [ids...]").description("Delete messages (interactive picker if no IDs given)").option("--all", "Delete every message in your DM history (no picker, no prompt)").option("--dry-run", "Preview which messages would be deleted (no SDK call)").action(
|
|
5030
|
+
(ids, opts) => runAction(async () => {
|
|
5031
|
+
const { arbi, crypto: crypto2 } = await resolveDmCrypto();
|
|
5032
|
+
let msgIds = ids && ids.length > 0 ? ids : void 0;
|
|
5033
|
+
if (!msgIds && opts?.all) {
|
|
5034
|
+
const data = await sdk.dm.listDecryptedDMs(arbi, crypto2);
|
|
5035
|
+
msgIds = data.map((m) => m.external_id);
|
|
5036
|
+
}
|
|
5037
|
+
if (!msgIds) {
|
|
5038
|
+
const data = await sdk.dm.listDecryptedDMs(arbi, crypto2);
|
|
5039
|
+
if (data.length === 0) {
|
|
5040
|
+
process.stderr.write("No messages found.\n");
|
|
5041
|
+
return;
|
|
5042
|
+
}
|
|
5043
|
+
requireInteractive("Pass IDs directly or use --all to delete the whole inbox.");
|
|
5044
|
+
msgIds = await promptCheckbox(
|
|
5045
|
+
"Select messages to delete",
|
|
5046
|
+
data.map((m) => {
|
|
5047
|
+
const s = m.sender;
|
|
5048
|
+
const from = sdk.formatUserName(s) || s?.email || "";
|
|
5049
|
+
return {
|
|
5050
|
+
name: `${from}: ${(m.content ?? "").slice(0, 50)}`,
|
|
5051
|
+
value: m.external_id
|
|
5052
|
+
};
|
|
5053
|
+
})
|
|
5054
|
+
);
|
|
5055
|
+
if (msgIds.length === 0) return;
|
|
5056
|
+
}
|
|
5057
|
+
if (msgIds.length === 0) {
|
|
5058
|
+
process.stderr.write("No messages to delete.\n");
|
|
5059
|
+
return;
|
|
5060
|
+
}
|
|
5061
|
+
if (opts?.dryRun) {
|
|
5062
|
+
dryRun(`delete ${msgIds.length} message(s)`, msgIds);
|
|
5063
|
+
return;
|
|
5064
|
+
}
|
|
5065
|
+
await sdk.dm.deleteDMs(arbi, msgIds);
|
|
5066
|
+
success(`Deleted ${msgIds.length} message(s).`);
|
|
5067
|
+
})()
|
|
5068
|
+
);
|
|
5069
|
+
dm.arguments("[maybeSubcommand]").action(async (maybe) => {
|
|
5070
|
+
if (maybe) {
|
|
5071
|
+
suggestSubcommandAndExit(
|
|
5072
|
+
"dm",
|
|
5073
|
+
maybe,
|
|
5074
|
+
dm.commands.map((c) => c.name())
|
|
5075
|
+
);
|
|
5076
|
+
}
|
|
5077
|
+
await dm.commands.find((c) => c.name() === "list").parseAsync([], { from: "user" });
|
|
5078
|
+
});
|
|
5079
|
+
}
|
|
5080
|
+
|
|
5081
|
+
// src/commands/workspaces.ts
|
|
5082
|
+
init_prompts();
|
|
4806
5083
|
function resolveWorkspaceSelector(list, selector) {
|
|
4807
5084
|
const byId = list.find((w) => w.external_id === selector);
|
|
4808
5085
|
if (byId) return { ok: true, id: byId.external_id, ws: byId };
|
|
@@ -5144,6 +5421,36 @@ function registerWorkspacesCommand(program2) {
|
|
|
5144
5421
|
for (const u of data) success(`Added: ${u.user.email} as ${u.role}`);
|
|
5145
5422
|
})()
|
|
5146
5423
|
);
|
|
5424
|
+
workspace.command("request-access <owner>").description("Ask another user to grant you access to one of their workspaces").option("--note <note>", "Optional message to the workspace owner").option(
|
|
5425
|
+
"-w, --workspace <id>",
|
|
5426
|
+
"Target a specific workspace id (advanced \u2014 usually omitted; the owner picks)"
|
|
5427
|
+
).action(
|
|
5428
|
+
(owner, opts) => runAction(async () => {
|
|
5429
|
+
const { arbi, crypto: crypto2, loginResult } = await resolveDmCrypto();
|
|
5430
|
+
const resolved = await resolveRecipient(arbi, owner);
|
|
5431
|
+
if (!resolved || !resolved.pubKey) {
|
|
5432
|
+
error(
|
|
5433
|
+
`No contact, agent, or workspace member found for: ${owner}
|
|
5434
|
+
Try: arbi contacts add ${owner.includes("@") ? owner : "<their-email>"}`
|
|
5435
|
+
);
|
|
5436
|
+
process.exit(3);
|
|
5437
|
+
}
|
|
5438
|
+
await sdk.dm.requestWorkspaceAccess(
|
|
5439
|
+
arbi,
|
|
5440
|
+
{
|
|
5441
|
+
recipientExtId: resolved.extId,
|
|
5442
|
+
recipientEncryptionPublicKey: resolved.pubKey,
|
|
5443
|
+
sessionPubkeyB64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey),
|
|
5444
|
+
note: opts.note,
|
|
5445
|
+
workspaceExtId: opts.workspace
|
|
5446
|
+
},
|
|
5447
|
+
crypto2
|
|
5448
|
+
);
|
|
5449
|
+
success(
|
|
5450
|
+
`Requested workspace access from ${owner}` + (opts.workspace ? ` (workspace ${opts.workspace})` : "") + ". They\u2019ll be notified and can grant temporary or permanent access."
|
|
5451
|
+
);
|
|
5452
|
+
})()
|
|
5453
|
+
);
|
|
5147
5454
|
workspace.command("remove-user <users...>").description("Remove users from the active workspace (accepts usr-ids or emails)").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").option("--dry-run", "Preview which users would be removed (no SDK call)").action(
|
|
5148
5455
|
(users, opts) => runAction(async () => {
|
|
5149
5456
|
const { arbi } = await resolveWorkspace(opts.workspace);
|
|
@@ -7748,394 +8055,119 @@ Timeout (${timeoutSec}s), closing.`));
|
|
|
7748
8055
|
await done;
|
|
7749
8056
|
if (timer) clearTimeout(timer);
|
|
7750
8057
|
process.removeListener("SIGINT", sigintHandler);
|
|
7751
|
-
if (timedOut && maxCount && messageCount < maxCount) {
|
|
7752
|
-
if (jsonMode) {
|
|
7753
|
-
console.log(
|
|
7754
|
-
JSON.stringify({
|
|
7755
|
-
type: "timeout",
|
|
7756
|
-
received: messageCount,
|
|
7757
|
-
expected: maxCount,
|
|
7758
|
-
timeout_seconds: timeoutSec
|
|
7759
|
-
})
|
|
7760
|
-
);
|
|
7761
|
-
} else {
|
|
7762
|
-
console.error(
|
|
7763
|
-
chalk2__default.default.yellow(`Timed out before reaching ${maxCount} messages (got ${messageCount}).`)
|
|
7764
|
-
);
|
|
7765
|
-
}
|
|
7766
|
-
process.exit(124);
|
|
7767
|
-
}
|
|
7768
|
-
})()
|
|
7769
|
-
);
|
|
7770
|
-
}
|
|
7771
|
-
init_prompts();
|
|
7772
|
-
function redactPictures(rows) {
|
|
7773
|
-
return rows.map((row) => {
|
|
7774
|
-
const user = row.user;
|
|
7775
|
-
if (!user || typeof user.picture !== "string" || user.picture.length === 0) return row;
|
|
7776
|
-
return {
|
|
7777
|
-
...row,
|
|
7778
|
-
user: {
|
|
7779
|
-
...user,
|
|
7780
|
-
has_picture: true,
|
|
7781
|
-
picture: null
|
|
7782
|
-
}
|
|
7783
|
-
};
|
|
7784
|
-
});
|
|
7785
|
-
}
|
|
7786
|
-
function registerContactsCommand(program2) {
|
|
7787
|
-
const contacts = program2.command("contacts").description("Contacts: list, add, remove");
|
|
7788
|
-
contacts.command("list").description("List all contacts").option("--json", "Output as JSON").option("--include-pictures", "Keep base64 profile-picture bytes in --json output").action(
|
|
7789
|
-
(opts) => runAction(async () => {
|
|
7790
|
-
const { arbi } = await resolveAuth();
|
|
7791
|
-
const data = await sdk.contacts.listContacts(arbi);
|
|
7792
|
-
if (opts.json) {
|
|
7793
|
-
printJson(opts.includePictures ? data : redactPictures(data));
|
|
7794
|
-
return;
|
|
7795
|
-
}
|
|
7796
|
-
if (data.length === 0) {
|
|
7797
|
-
process.stderr.write("No contacts found.\n");
|
|
7798
|
-
return;
|
|
7799
|
-
}
|
|
7800
|
-
printTable(
|
|
7801
|
-
[
|
|
7802
|
-
{ header: "ID", width: 16, value: (r) => r.external_id },
|
|
7803
|
-
{
|
|
7804
|
-
header: "NAME",
|
|
7805
|
-
width: 20,
|
|
7806
|
-
value: (r) => sdk.formatUserName(r.user)
|
|
7807
|
-
},
|
|
7808
|
-
{ header: "EMAIL", width: 30, value: (r) => r.email },
|
|
7809
|
-
{ header: "STATUS", width: 18, value: (r) => r.status }
|
|
7810
|
-
],
|
|
7811
|
-
data
|
|
7812
|
-
);
|
|
7813
|
-
})()
|
|
7814
|
-
);
|
|
7815
|
-
contacts.command("add [emails...]").description("Add contacts by email (prompt if no emails given)").action(
|
|
7816
|
-
(emails) => runAction(async () => {
|
|
7817
|
-
const { arbi } = await resolveAuth();
|
|
7818
|
-
if (!emails || emails.length === 0) {
|
|
7819
|
-
requireInteractive("Pass email(s) as positional args: arbi contacts add foo@x.y bar@x.y");
|
|
7820
|
-
const input2 = await promptInput("Email address(es), comma-separated");
|
|
7821
|
-
emails = input2.split(",").map((e) => e.trim()).filter(Boolean);
|
|
7822
|
-
if (emails.length === 0) return;
|
|
7823
|
-
}
|
|
7824
|
-
const data = await sdk.contacts.addContacts(arbi, emails);
|
|
7825
|
-
for (const c of data) {
|
|
7826
|
-
success(`Added: ${c.email} (${c.external_id}) \u2014 ${c.status}`);
|
|
7827
|
-
}
|
|
7828
|
-
})()
|
|
7829
|
-
);
|
|
7830
|
-
contacts.command("remove [ids...]").description("Remove contacts (interactive picker if no IDs given)").option("--dry-run", "Preview which contacts would be removed (no SDK call)").action(
|
|
7831
|
-
(ids, opts) => runAction(async () => {
|
|
7832
|
-
const { arbi } = await resolveAuth();
|
|
7833
|
-
let contactIds = ids && ids.length > 0 ? ids : void 0;
|
|
7834
|
-
if (!contactIds) {
|
|
7835
|
-
const data = await sdk.contacts.listContacts(arbi);
|
|
7836
|
-
if (data.length === 0) {
|
|
7837
|
-
process.stderr.write("No contacts found.\n");
|
|
7838
|
-
return;
|
|
7839
|
-
}
|
|
7840
|
-
requireInteractive("Pass contact IDs directly: arbi contacts remove cnt-\u2026");
|
|
7841
|
-
contactIds = await promptCheckbox(
|
|
7842
|
-
"Select contacts to remove",
|
|
7843
|
-
data.map((c) => {
|
|
7844
|
-
const name = sdk.formatUserName(c.user);
|
|
7845
|
-
return {
|
|
7846
|
-
name: name ? `${name} (${c.email})` : c.email,
|
|
7847
|
-
value: c.external_id
|
|
7848
|
-
};
|
|
7849
|
-
})
|
|
7850
|
-
);
|
|
7851
|
-
if (contactIds.length === 0) return;
|
|
7852
|
-
}
|
|
7853
|
-
if (opts?.dryRun) {
|
|
7854
|
-
dryRun(`remove ${contactIds.length} contact(s)`, contactIds);
|
|
7855
|
-
return;
|
|
7856
|
-
}
|
|
7857
|
-
await sdk.contacts.removeContacts(arbi, contactIds);
|
|
7858
|
-
success(`Removed ${contactIds.length} contact(s).`);
|
|
7859
|
-
})()
|
|
7860
|
-
);
|
|
7861
|
-
contacts.allowUnknownOption(true).allowExcessArguments(true).action(async () => {
|
|
7862
|
-
const tail = contacts.args ?? [];
|
|
7863
|
-
await contacts.commands.find((c) => c.name() === "list").parseAsync(tail, { from: "user" });
|
|
7864
|
-
});
|
|
7865
|
-
}
|
|
7866
|
-
init_prompts();
|
|
7867
|
-
async function resolveRecipient(arbi, ref2) {
|
|
7868
|
-
const isEmail = ref2.includes("@");
|
|
7869
|
-
const matchKey = isEmail ? "email" : "external_id";
|
|
7870
|
-
const contacts = await sdk.contacts.listContacts(arbi);
|
|
7871
|
-
const contactMatch = contacts.find((c) => {
|
|
7872
|
-
if (isEmail) return c.email === ref2;
|
|
7873
|
-
const u = c.user;
|
|
7874
|
-
return u?.external_id === ref2 || c.external_id === ref2;
|
|
7875
|
-
});
|
|
7876
|
-
if (contactMatch) {
|
|
7877
|
-
const u = contactMatch.user;
|
|
7878
|
-
const extId = u?.external_id ?? contactMatch.external_id;
|
|
7879
|
-
const pubKey = u?.encryption_public_key ?? "";
|
|
7880
|
-
if (pubKey) return { extId, pubKey };
|
|
7881
|
-
}
|
|
7882
|
-
try {
|
|
7883
|
-
const agents = await sdk.agents.listAgents(arbi);
|
|
7884
|
-
const agentMatch = agents.find((a) => a[matchKey] === ref2);
|
|
7885
|
-
if (agentMatch) {
|
|
7886
|
-
return { extId: agentMatch.external_id, pubKey: agentMatch.encryption_public_key };
|
|
7887
|
-
}
|
|
7888
|
-
} catch {
|
|
7889
|
-
}
|
|
7890
|
-
try {
|
|
7891
|
-
const wsUsers = await sdk.workspaces.listWorkspaceUsers(arbi);
|
|
7892
|
-
const wsMatch = wsUsers.find((wu) => wu[matchKey] === ref2);
|
|
7893
|
-
if (wsMatch) {
|
|
7894
|
-
const u = wsMatch;
|
|
7895
|
-
return {
|
|
7896
|
-
extId: u.external_id,
|
|
7897
|
-
pubKey: u.encryption_public_key
|
|
7898
|
-
};
|
|
7899
|
-
}
|
|
7900
|
-
} catch {
|
|
7901
|
-
}
|
|
7902
|
-
return null;
|
|
7903
|
-
}
|
|
7904
|
-
function rowMatchesFilters(row, opts) {
|
|
7905
|
-
if (opts.unread && row.read) return false;
|
|
7906
|
-
const sender = row.sender;
|
|
7907
|
-
const recipient = row.recipient;
|
|
7908
|
-
if (opts.from) {
|
|
7909
|
-
const needle = opts.from.toLowerCase();
|
|
7910
|
-
const senderMatch = sender?.email?.toLowerCase() === needle || sender?.external_id === opts.from;
|
|
7911
|
-
const recipientMatch = recipient?.email?.toLowerCase() === needle || recipient?.external_id === opts.from;
|
|
7912
|
-
if (!senderMatch && !recipientMatch) return false;
|
|
7913
|
-
}
|
|
7914
|
-
if (opts.thread) {
|
|
7915
|
-
const needle = opts.thread.toLowerCase();
|
|
7916
|
-
const peer = sender?.external_id === opts.myExtId ? recipient : sender;
|
|
7917
|
-
const peerMatch = peer?.email?.toLowerCase() === needle || peer?.external_id === opts.thread;
|
|
7918
|
-
if (!peerMatch) return false;
|
|
7919
|
-
}
|
|
7920
|
-
if (opts.since) {
|
|
7921
|
-
const cutoff = Date.parse(opts.since);
|
|
7922
|
-
if (Number.isFinite(cutoff)) {
|
|
7923
|
-
const createdAt = typeof row.created_at === "string" ? Date.parse(row.created_at) : NaN;
|
|
7924
|
-
if (!Number.isFinite(createdAt) || createdAt < cutoff) return false;
|
|
7925
|
-
}
|
|
7926
|
-
}
|
|
7927
|
-
return true;
|
|
8058
|
+
if (timedOut && maxCount && messageCount < maxCount) {
|
|
8059
|
+
if (jsonMode) {
|
|
8060
|
+
console.log(
|
|
8061
|
+
JSON.stringify({
|
|
8062
|
+
type: "timeout",
|
|
8063
|
+
received: messageCount,
|
|
8064
|
+
expected: maxCount,
|
|
8065
|
+
timeout_seconds: timeoutSec
|
|
8066
|
+
})
|
|
8067
|
+
);
|
|
8068
|
+
} else {
|
|
8069
|
+
console.error(
|
|
8070
|
+
chalk2__default.default.yellow(`Timed out before reaching ${maxCount} messages (got ${messageCount}).`)
|
|
8071
|
+
);
|
|
8072
|
+
}
|
|
8073
|
+
process.exit(124);
|
|
8074
|
+
}
|
|
8075
|
+
})()
|
|
8076
|
+
);
|
|
7928
8077
|
}
|
|
7929
|
-
|
|
7930
|
-
|
|
7931
|
-
|
|
7932
|
-
|
|
7933
|
-
|
|
7934
|
-
|
|
8078
|
+
init_prompts();
|
|
8079
|
+
function redactPictures(rows) {
|
|
8080
|
+
return rows.map((row) => {
|
|
8081
|
+
const user = row.user;
|
|
8082
|
+
if (!user || typeof user.picture !== "string" || user.picture.length === 0) return row;
|
|
8083
|
+
return {
|
|
8084
|
+
...row,
|
|
8085
|
+
user: {
|
|
8086
|
+
...user,
|
|
8087
|
+
has_picture: true,
|
|
8088
|
+
picture: null
|
|
8089
|
+
}
|
|
8090
|
+
};
|
|
8091
|
+
});
|
|
8092
|
+
}
|
|
8093
|
+
function registerContactsCommand(program2) {
|
|
8094
|
+
const contacts = program2.command("contacts").description("Contacts: list, add, remove");
|
|
8095
|
+
contacts.command("list").description("List all contacts").option("--json", "Output as JSON").option("--include-pictures", "Keep base64 profile-picture bytes in --json output").action(
|
|
7935
8096
|
(opts) => runAction(async () => {
|
|
7936
|
-
const { arbi
|
|
7937
|
-
const
|
|
7938
|
-
const myExtId = arbi.session.getState().userExtId ?? void 0;
|
|
7939
|
-
const dms = all.filter((r) => r.type === "user_message");
|
|
7940
|
-
const filterOpts = {
|
|
7941
|
-
unread: Boolean(opts.unread),
|
|
7942
|
-
from: typeof opts.from === "string" ? opts.from : void 0,
|
|
7943
|
-
thread: typeof opts.thread === "string" ? opts.thread : void 0,
|
|
7944
|
-
since: typeof opts.since === "string" ? opts.since : void 0,
|
|
7945
|
-
myExtId
|
|
7946
|
-
};
|
|
7947
|
-
const filtered = dms.filter((r) => rowMatchesFilters(r, filterOpts));
|
|
7948
|
-
const limited = typeof opts.limit === "number" && opts.limit > 0 ? filtered.slice(0, opts.limit) : filtered;
|
|
8097
|
+
const { arbi } = await resolveAuth();
|
|
8098
|
+
const data = await sdk.contacts.listContacts(arbi);
|
|
7949
8099
|
if (opts.json) {
|
|
7950
|
-
printJson(
|
|
8100
|
+
printJson(opts.includePictures ? data : redactPictures(data));
|
|
7951
8101
|
return;
|
|
7952
8102
|
}
|
|
7953
|
-
if (
|
|
7954
|
-
process.stderr.write("No
|
|
8103
|
+
if (data.length === 0) {
|
|
8104
|
+
process.stderr.write("No contacts found.\n");
|
|
7955
8105
|
return;
|
|
7956
8106
|
}
|
|
7957
|
-
const peer = (r) => {
|
|
7958
|
-
const s = r.sender;
|
|
7959
|
-
const recip = r.recipient;
|
|
7960
|
-
return s?.external_id === myExtId ? recip : s;
|
|
7961
|
-
};
|
|
7962
8107
|
printTable(
|
|
7963
8108
|
[
|
|
7964
8109
|
{ header: "ID", width: 16, value: (r) => r.external_id },
|
|
7965
8110
|
{
|
|
7966
|
-
header: "
|
|
7967
|
-
width:
|
|
7968
|
-
value: (r) => r.
|
|
7969
|
-
},
|
|
7970
|
-
{
|
|
7971
|
-
header: "PEER",
|
|
7972
|
-
width: 26,
|
|
7973
|
-
value: (r) => {
|
|
7974
|
-
const p = peer(r);
|
|
7975
|
-
return sdk.formatUserName(p) || p?.email || "";
|
|
7976
|
-
}
|
|
8111
|
+
header: "NAME",
|
|
8112
|
+
width: 20,
|
|
8113
|
+
value: (r) => sdk.formatUserName(r.user)
|
|
7977
8114
|
},
|
|
7978
|
-
{ header: "
|
|
7979
|
-
{
|
|
7980
|
-
header: "CONTENT",
|
|
7981
|
-
width: 50,
|
|
7982
|
-
value: (r) => truncate(r.content ?? "", 49)
|
|
7983
|
-
}
|
|
7984
|
-
],
|
|
7985
|
-
limited
|
|
7986
|
-
);
|
|
7987
|
-
})()
|
|
7988
|
-
);
|
|
7989
|
-
dm.command("send [recipient] [content...]").description("Send an E2E encrypted DM (interactive if no args)").action(
|
|
7990
|
-
(recipient, contentParts) => runAction(async () => {
|
|
7991
|
-
const { arbi, crypto: crypto2 } = await resolveDmCrypto();
|
|
7992
|
-
if (!recipient) {
|
|
7993
|
-
requireInteractive(
|
|
7994
|
-
'Pass recipient + message as arguments: arbi dm send <email-or-id> "<message>"'
|
|
7995
|
-
);
|
|
7996
|
-
const contacts = await sdk.contacts.listContacts(arbi);
|
|
7997
|
-
if (contacts.length === 0) {
|
|
7998
|
-
error("No contacts found. Add contacts first: arbi contacts add <email>");
|
|
7999
|
-
process.exit(1);
|
|
8000
|
-
}
|
|
8001
|
-
recipient = await promptSelect(
|
|
8002
|
-
"Send to",
|
|
8003
|
-
contacts.map((c) => {
|
|
8004
|
-
const u = c.user;
|
|
8005
|
-
const name = sdk.formatUserName(u);
|
|
8006
|
-
return {
|
|
8007
|
-
name: name ? `${name} (${c.email})` : c.email,
|
|
8008
|
-
value: u?.external_id ?? c.external_id,
|
|
8009
|
-
description: c.email
|
|
8010
|
-
};
|
|
8011
|
-
})
|
|
8012
|
-
);
|
|
8013
|
-
}
|
|
8014
|
-
let content = contentParts?.length ? contentParts.join(" ") : void 0;
|
|
8015
|
-
if (!content) {
|
|
8016
|
-
requireInteractive(
|
|
8017
|
-
'Pass the message as a positional argument: arbi dm send <email> "your message"'
|
|
8018
|
-
);
|
|
8019
|
-
content = await promptInput("Message");
|
|
8020
|
-
}
|
|
8021
|
-
const resolved = await resolveRecipient(arbi, recipient);
|
|
8022
|
-
if (!resolved) {
|
|
8023
|
-
error(
|
|
8024
|
-
`No contact, agent, or workspace member found for: ${recipient}
|
|
8025
|
-
Try: arbi contacts add ${recipient.includes("@") ? recipient : "<their-email>"}`
|
|
8026
|
-
);
|
|
8027
|
-
process.exit(3);
|
|
8028
|
-
}
|
|
8029
|
-
const recipientExtId = resolved.extId;
|
|
8030
|
-
const recipientPubKey = resolved.pubKey;
|
|
8031
|
-
if (!recipientPubKey) {
|
|
8032
|
-
error(
|
|
8033
|
-
"Cannot send encrypted DM \u2014 recipient public key not found.\nAdd them as a contact first: arbi contacts add <email>"
|
|
8034
|
-
);
|
|
8035
|
-
process.exit(3);
|
|
8036
|
-
}
|
|
8037
|
-
const data = await sdk.dm.sendEncryptedDM(
|
|
8038
|
-
arbi,
|
|
8039
|
-
[
|
|
8040
|
-
{
|
|
8041
|
-
recipient_ext_id: recipientExtId,
|
|
8042
|
-
content,
|
|
8043
|
-
recipient_encryption_public_key: recipientPubKey
|
|
8044
|
-
}
|
|
8115
|
+
{ header: "EMAIL", width: 30, value: (r) => r.email },
|
|
8116
|
+
{ header: "STATUS", width: 18, value: (r) => r.status }
|
|
8045
8117
|
],
|
|
8046
|
-
|
|
8118
|
+
data
|
|
8047
8119
|
);
|
|
8048
|
-
for (const n of data) {
|
|
8049
|
-
success(`Sent (encrypted): ${n.external_id} \u2192 ${n.recipient.email}`);
|
|
8050
|
-
}
|
|
8051
8120
|
})()
|
|
8052
8121
|
);
|
|
8053
|
-
|
|
8054
|
-
(
|
|
8055
|
-
const { arbi
|
|
8056
|
-
|
|
8057
|
-
|
|
8058
|
-
const
|
|
8059
|
-
|
|
8060
|
-
|
|
8061
|
-
if (!msgIds) {
|
|
8062
|
-
const data2 = await sdk.dm.listDecryptedDMs(arbi, crypto2);
|
|
8063
|
-
const unread = data2.filter((m) => !m.read);
|
|
8064
|
-
if (unread.length === 0) {
|
|
8065
|
-
process.stderr.write("No unread messages.\n");
|
|
8066
|
-
return;
|
|
8067
|
-
}
|
|
8068
|
-
requireInteractive("Pass IDs directly or use --all to mark every unread message read.");
|
|
8069
|
-
msgIds = await promptCheckbox(
|
|
8070
|
-
"Select messages to mark as read",
|
|
8071
|
-
unread.map((m) => {
|
|
8072
|
-
const s = m.sender;
|
|
8073
|
-
const from = sdk.formatUserName(s) || s?.email || "";
|
|
8074
|
-
return {
|
|
8075
|
-
name: `${from}: ${(m.content ?? "").slice(0, 50)}`,
|
|
8076
|
-
value: m.external_id
|
|
8077
|
-
};
|
|
8078
|
-
})
|
|
8079
|
-
);
|
|
8080
|
-
if (msgIds.length === 0) return;
|
|
8122
|
+
contacts.command("add [emails...]").description("Add contacts by email (prompt if no emails given)").action(
|
|
8123
|
+
(emails) => runAction(async () => {
|
|
8124
|
+
const { arbi } = await resolveAuth();
|
|
8125
|
+
if (!emails || emails.length === 0) {
|
|
8126
|
+
requireInteractive("Pass email(s) as positional args: arbi contacts add foo@x.y bar@x.y");
|
|
8127
|
+
const input2 = await promptInput("Email address(es), comma-separated");
|
|
8128
|
+
emails = input2.split(",").map((e) => e.trim()).filter(Boolean);
|
|
8129
|
+
if (emails.length === 0) return;
|
|
8081
8130
|
}
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
|
|
8131
|
+
const data = await sdk.contacts.addContacts(arbi, emails);
|
|
8132
|
+
for (const c of data) {
|
|
8133
|
+
success(`Added: ${c.email} (${c.external_id}) \u2014 ${c.status}`);
|
|
8085
8134
|
}
|
|
8086
|
-
const data = await sdk.dm.markRead(arbi, msgIds);
|
|
8087
|
-
success(`Marked ${data.length} message(s) as read.`);
|
|
8088
8135
|
})()
|
|
8089
8136
|
);
|
|
8090
|
-
|
|
8137
|
+
contacts.command("remove [ids...]").description("Remove contacts (interactive picker if no IDs given)").option("--dry-run", "Preview which contacts would be removed (no SDK call)").action(
|
|
8091
8138
|
(ids, opts) => runAction(async () => {
|
|
8092
|
-
const { arbi
|
|
8093
|
-
let
|
|
8094
|
-
if (!
|
|
8095
|
-
const data = await sdk.
|
|
8096
|
-
msgIds = data.map((m) => m.external_id);
|
|
8097
|
-
}
|
|
8098
|
-
if (!msgIds) {
|
|
8099
|
-
const data = await sdk.dm.listDecryptedDMs(arbi, crypto2);
|
|
8139
|
+
const { arbi } = await resolveAuth();
|
|
8140
|
+
let contactIds = ids && ids.length > 0 ? ids : void 0;
|
|
8141
|
+
if (!contactIds) {
|
|
8142
|
+
const data = await sdk.contacts.listContacts(arbi);
|
|
8100
8143
|
if (data.length === 0) {
|
|
8101
|
-
process.stderr.write("No
|
|
8144
|
+
process.stderr.write("No contacts found.\n");
|
|
8102
8145
|
return;
|
|
8103
8146
|
}
|
|
8104
|
-
requireInteractive("Pass IDs directly
|
|
8105
|
-
|
|
8106
|
-
"Select
|
|
8107
|
-
data.map((
|
|
8108
|
-
const
|
|
8109
|
-
const from = sdk.formatUserName(s) || s?.email || "";
|
|
8147
|
+
requireInteractive("Pass contact IDs directly: arbi contacts remove cnt-\u2026");
|
|
8148
|
+
contactIds = await promptCheckbox(
|
|
8149
|
+
"Select contacts to remove",
|
|
8150
|
+
data.map((c) => {
|
|
8151
|
+
const name = sdk.formatUserName(c.user);
|
|
8110
8152
|
return {
|
|
8111
|
-
name: `${
|
|
8112
|
-
value:
|
|
8153
|
+
name: name ? `${name} (${c.email})` : c.email,
|
|
8154
|
+
value: c.external_id
|
|
8113
8155
|
};
|
|
8114
8156
|
})
|
|
8115
8157
|
);
|
|
8116
|
-
if (
|
|
8117
|
-
}
|
|
8118
|
-
if (msgIds.length === 0) {
|
|
8119
|
-
process.stderr.write("No messages to delete.\n");
|
|
8120
|
-
return;
|
|
8158
|
+
if (contactIds.length === 0) return;
|
|
8121
8159
|
}
|
|
8122
8160
|
if (opts?.dryRun) {
|
|
8123
|
-
dryRun(`
|
|
8161
|
+
dryRun(`remove ${contactIds.length} contact(s)`, contactIds);
|
|
8124
8162
|
return;
|
|
8125
8163
|
}
|
|
8126
|
-
await sdk.
|
|
8127
|
-
success(`
|
|
8164
|
+
await sdk.contacts.removeContacts(arbi, contactIds);
|
|
8165
|
+
success(`Removed ${contactIds.length} contact(s).`);
|
|
8128
8166
|
})()
|
|
8129
8167
|
);
|
|
8130
|
-
|
|
8131
|
-
|
|
8132
|
-
|
|
8133
|
-
"dm",
|
|
8134
|
-
maybe,
|
|
8135
|
-
dm.commands.map((c) => c.name())
|
|
8136
|
-
);
|
|
8137
|
-
}
|
|
8138
|
-
await dm.commands.find((c) => c.name() === "list").parseAsync([], { from: "user" });
|
|
8168
|
+
contacts.allowUnknownOption(true).allowExcessArguments(true).action(async () => {
|
|
8169
|
+
const tail = contacts.args ?? [];
|
|
8170
|
+
await contacts.commands.find((c) => c.name() === "list").parseAsync(tail, { from: "user" });
|
|
8139
8171
|
});
|
|
8140
8172
|
}
|
|
8141
8173
|
init_prompts();
|
|
@@ -10273,7 +10305,7 @@ console.info = (...args) => {
|
|
|
10273
10305
|
_origInfo(...args);
|
|
10274
10306
|
};
|
|
10275
10307
|
var program = new commander.Command();
|
|
10276
|
-
program.name("arbi").description("ARBI CLI \u2014 interact with ARBI from the terminal").version("0.3.
|
|
10308
|
+
program.name("arbi").description("ARBI CLI \u2014 interact with ARBI from the terminal").version("0.3.90").showHelpAfterError(true).showSuggestionAfterError(true);
|
|
10277
10309
|
registerConfigCommand(program);
|
|
10278
10310
|
registerLoginCommand(program);
|
|
10279
10311
|
registerRegisterCommand(program);
|