@arbidocs/cli 0.1.4 → 0.3.1

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/dist/index.cjs CHANGED
@@ -3,10 +3,10 @@
3
3
 
4
4
  var commander = require('commander');
5
5
  var core = require('@arbidocs/core');
6
- var sdk = require('@arbidocs/sdk');
7
6
  var prompts = require('@inquirer/prompts');
7
+ var sdk = require('@arbidocs/sdk');
8
8
  var fs = require('fs');
9
- var path2 = require('path');
9
+ var path = require('path');
10
10
  var child_process = require('child_process');
11
11
  var module$1 = require('module');
12
12
 
@@ -14,7 +14,7 @@ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentS
14
14
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
15
15
 
16
16
  var fs__default = /*#__PURE__*/_interopDefault(fs);
17
- var path2__default = /*#__PURE__*/_interopDefault(path2);
17
+ var path__default = /*#__PURE__*/_interopDefault(path);
18
18
 
19
19
  var store = new core.FileConfigStore();
20
20
  function getConfig() {
@@ -37,9 +37,6 @@ function requireConfig() {
37
37
  function getCredentials() {
38
38
  return store.getCredentials();
39
39
  }
40
- function saveCredentials(creds) {
41
- store.saveCredentials(creds);
42
- }
43
40
  function deleteCredentials() {
44
41
  store.deleteCredentials();
45
42
  }
@@ -3385,22 +3382,11 @@ async function promptConfirm(message, defaultValue = true) {
3385
3382
  // src/commands/login.ts
3386
3383
  function registerLoginCommand(program2) {
3387
3384
  program2.command("login").description("Log in to ARBI").option("-e, --email <email>", "Email address (or ARBI_EMAIL env var)").option("-p, --password <password>", "Password (or ARBI_PASSWORD env var)").option("-w, --workspace <id>", "Workspace ID to select after login").action(async (opts) => {
3388
- const config = requireConfig();
3385
+ const config = store.requireConfig();
3389
3386
  const email = opts.email || process.env.ARBI_EMAIL || await promptInput("Email");
3390
3387
  const pw = opts.password || process.env.ARBI_PASSWORD || await promptPassword("Password");
3391
- const arbi = sdk.createArbiClient({
3392
- baseUrl: config.baseUrl,
3393
- deploymentDomain: config.deploymentDomain,
3394
- credentials: "omit"
3395
- });
3396
- await arbi.crypto.initSodium();
3397
3388
  try {
3398
- const result = await arbi.auth.login({ email, password: pw });
3399
- saveCredentials({
3400
- email,
3401
- signingPrivateKeyBase64: arbi.crypto.bytesToBase64(result.signingPrivateKey),
3402
- serverSessionKeyBase64: arbi.crypto.bytesToBase64(result.serverSessionKey)
3403
- });
3389
+ const { arbi } = await core.performPasswordLogin(config, email, pw, store);
3404
3390
  const { data: workspaces2 } = await arbi.fetch.GET("/api/user/workspaces");
3405
3391
  const wsList = workspaces2 || [];
3406
3392
  console.log(`Logged in as ${email}`);
@@ -3423,21 +3409,13 @@ function registerLoginCommand(program2) {
3423
3409
  console.log(`Workspace: ${wsList[0].name} (${wsList[0].external_id})`);
3424
3410
  return;
3425
3411
  }
3426
- const choices = wsList.map((ws2) => {
3427
- const totalDocs = ws2.shared_document_count + ws2.private_document_count;
3428
- return {
3429
- name: `${ws2.name} (${totalDocs} docs)`,
3430
- value: ws2.external_id,
3431
- description: ws2.external_id
3432
- };
3433
- });
3412
+ const choices = core.formatWorkspaceChoices(wsList);
3434
3413
  const selected = await promptSelect("Select workspace", choices);
3435
3414
  updateConfig({ selectedWorkspaceId: selected });
3436
3415
  const ws = wsList.find((w) => w.external_id === selected);
3437
3416
  console.log(`Workspace: ${ws.name} (${selected})`);
3438
3417
  } catch (err) {
3439
- const msg = err instanceof Error ? err.message : String(err);
3440
- console.error(`Login failed: ${msg}`);
3418
+ console.error(`Login failed: ${core.getErrorMessage(err)}`);
3441
3419
  process.exit(1);
3442
3420
  }
3443
3421
  });
@@ -3516,42 +3494,28 @@ async function interactiveRegister(config, opts) {
3516
3494
  console.log(`
3517
3495
  Registered successfully as ${email}`);
3518
3496
  } catch (err) {
3519
- const msg = err instanceof Error ? err.message : String(err);
3520
- console.error(`Registration failed: ${msg}`);
3497
+ console.error(`Registration failed: ${core.getErrorMessage(err)}`);
3521
3498
  process.exit(1);
3522
3499
  }
3523
3500
  const doLogin = await promptConfirm("Log in now?");
3524
3501
  if (doLogin) {
3525
3502
  try {
3526
- const loginResult = await arbi.auth.login({ email, password: password2 });
3527
- saveCredentials({
3528
- email,
3529
- signingPrivateKeyBase64: arbi.crypto.bytesToBase64(loginResult.signingPrivateKey),
3530
- serverSessionKeyBase64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey)
3531
- });
3532
- const { data: workspaces2 } = await arbi.fetch.GET("/api/user/workspaces");
3503
+ const { arbi: loggedInArbi } = await core.performPasswordLogin(config, email, password2, store);
3504
+ const { data: workspaces2 } = await loggedInArbi.fetch.GET("/api/user/workspaces");
3533
3505
  const wsList = workspaces2 || [];
3534
3506
  console.log(`Logged in as ${email}`);
3535
3507
  if (wsList.length === 1) {
3536
3508
  updateConfig({ selectedWorkspaceId: wsList[0].external_id });
3537
3509
  console.log(`Workspace: ${wsList[0].name} (${wsList[0].external_id})`);
3538
3510
  } else if (wsList.length > 1) {
3539
- const choices = wsList.map((ws2) => {
3540
- const totalDocs = ws2.shared_document_count + ws2.private_document_count;
3541
- return {
3542
- name: `${ws2.name} (${totalDocs} docs)`,
3543
- value: ws2.external_id,
3544
- description: ws2.external_id
3545
- };
3546
- });
3511
+ const choices = core.formatWorkspaceChoices(wsList);
3547
3512
  const selected = await promptSelect("Select workspace", choices);
3548
3513
  updateConfig({ selectedWorkspaceId: selected });
3549
3514
  const ws = wsList.find((w) => w.external_id === selected);
3550
3515
  console.log(`Workspace: ${ws.name} (${selected})`);
3551
3516
  }
3552
3517
  } catch (err) {
3553
- const msg = err instanceof Error ? err.message : String(err);
3554
- console.error(`Login failed: ${msg}`);
3518
+ console.error(`Login failed: ${core.getErrorMessage(err)}`);
3555
3519
  console.error("You can log in later with: arbi login");
3556
3520
  }
3557
3521
  }
@@ -3596,8 +3560,7 @@ async function nonInteractiveRegister(config, opts) {
3596
3560
  });
3597
3561
  console.log(`Registered: ${email}`);
3598
3562
  } catch (err) {
3599
- const msg = err instanceof Error ? err.message : String(err);
3600
- console.error(`Registration failed: ${msg}`);
3563
+ console.error(`Registration failed: ${core.getErrorMessage(err)}`);
3601
3564
  process.exit(1);
3602
3565
  }
3603
3566
  }
@@ -3638,8 +3601,7 @@ function runAction(fn) {
3638
3601
  try {
3639
3602
  await fn();
3640
3603
  } catch (err) {
3641
- const msg = err instanceof Error ? err.message : String(err);
3642
- console.error(`Error: ${msg}`);
3604
+ console.error(`Error: ${core.getErrorMessage(err)}`);
3643
3605
  process.exit(1);
3644
3606
  }
3645
3607
  };
@@ -3735,14 +3697,7 @@ function registerWorkspacesCommand(program2) {
3735
3697
  }
3736
3698
  selectedId = id;
3737
3699
  } else {
3738
- const choices = data.map((ws2) => {
3739
- const totalDocs = ws2.shared_document_count + ws2.private_document_count;
3740
- return {
3741
- name: `${ws2.name} (${totalDocs} docs)`,
3742
- value: ws2.external_id,
3743
- description: ws2.external_id
3744
- };
3745
- });
3700
+ const choices = core.formatWorkspaceChoices(data);
3746
3701
  selectedId = await promptSelect("Select workspace", choices);
3747
3702
  }
3748
3703
  updateConfig({ selectedWorkspaceId: selectedId });
@@ -3848,11 +3803,23 @@ function registerWorkspacesCommand(program2) {
3848
3803
  })()
3849
3804
  );
3850
3805
  }
3851
- function formatSize(bytes) {
3852
- if (!bytes) return "-";
3853
- if (bytes < 1024) return `${bytes} B`;
3854
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
3855
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
3806
+ function statusSymbol(status) {
3807
+ switch (status) {
3808
+ case "completed":
3809
+ return "\u2713";
3810
+ //
3811
+ case "failed":
3812
+ return "\u2717";
3813
+ // ✗
3814
+ case "skipped":
3815
+ return "\u2013";
3816
+ // –
3817
+ case "queued":
3818
+ return "\u25CB";
3819
+ // ○
3820
+ default:
3821
+ return "\u25CF";
3822
+ }
3856
3823
  }
3857
3824
  async function fetchDocChoices(arbi, workspaceId) {
3858
3825
  const data = await core.documents.listDocuments(arbi, workspaceId);
@@ -3878,9 +3845,31 @@ function registerDocsCommand(program2) {
3878
3845
  printTable(
3879
3846
  [
3880
3847
  { header: "ID", width: 24, value: (r) => r.external_id },
3881
- { header: "NAME", width: 36, value: (r) => r.file_name ?? "Unnamed" },
3882
- { header: "STATUS", width: 14, value: (r) => r.status ?? "" },
3883
- { header: "SIZE", width: 10, value: (r) => formatSize(r.file_size) }
3848
+ { header: "S", width: 2, value: (r) => statusSymbol(r.status) },
3849
+ {
3850
+ header: "TITLE",
3851
+ width: 34,
3852
+ value: (r) => {
3853
+ const meta = r.doc_metadata;
3854
+ return meta?.title ?? r.file_name ?? "Unnamed";
3855
+ }
3856
+ },
3857
+ {
3858
+ header: "DATE",
3859
+ width: 12,
3860
+ value: (r) => {
3861
+ const meta = r.doc_metadata;
3862
+ return meta?.doc_date ?? "-";
3863
+ }
3864
+ },
3865
+ {
3866
+ header: "SUMMARY",
3867
+ width: 50,
3868
+ value: (r) => {
3869
+ const meta = r.doc_metadata;
3870
+ return meta?.doc_subject ?? "-";
3871
+ }
3872
+ }
3884
3873
  ],
3885
3874
  data
3886
3875
  );
@@ -3981,9 +3970,7 @@ function registerDocsCommand(program2) {
3981
3970
  process.exit(1);
3982
3971
  }
3983
3972
  const data = await core.documents.getParsedContent(
3984
- config.baseUrl,
3985
- accessToken,
3986
- workspaceKeyHeader,
3973
+ { baseUrl: config.baseUrl, accessToken, workspaceKeyHeader },
3987
3974
  docId,
3988
3975
  stage
3989
3976
  );
@@ -4004,22 +3991,14 @@ function registerUploadCommand(program2) {
4004
3991
  opts.workspace
4005
3992
  );
4006
3993
  const uploadedDocs = /* @__PURE__ */ new Map();
3994
+ const auth = { baseUrl: config.baseUrl, accessToken, workspaceKeyHeader };
4007
3995
  for (const filePath of files) {
4008
- const fileBuffer = fs__default.default.readFileSync(filePath);
4009
- const fileName = path2__default.default.basename(filePath);
4010
- const result = await core.documents.uploadFile(
4011
- config.baseUrl,
4012
- accessToken,
4013
- workspaceKeyHeader,
4014
- workspaceId,
4015
- new Blob([fileBuffer]),
4016
- fileName
4017
- );
4018
- console.log(`Uploaded: ${fileName} (${result.doc_ext_ids.join(", ")})`);
3996
+ const result = await core.documents.uploadLocalFile(auth, workspaceId, filePath);
3997
+ console.log(`Uploaded: ${result.fileName} (${result.doc_ext_ids.join(", ")})`);
4019
3998
  if (result.duplicates && result.duplicates.length > 0) {
4020
3999
  console.log(` Duplicates: ${result.duplicates.join(", ")}`);
4021
4000
  }
4022
- for (const id of result.doc_ext_ids) uploadedDocs.set(id, fileName);
4001
+ for (const id of result.doc_ext_ids) uploadedDocs.set(id, result.fileName);
4023
4002
  }
4024
4003
  if (opts.watch && uploadedDocs.size > 0) {
4025
4004
  const pending = new Set(uploadedDocs.keys());
@@ -4071,9 +4050,7 @@ function registerDownloadCommand(program2) {
4071
4050
  docId = await promptSearch("Select document to download", choices);
4072
4051
  }
4073
4052
  const res = await core.documents.downloadDocument(
4074
- config.baseUrl,
4075
- accessToken,
4076
- workspaceKeyHeader,
4053
+ { baseUrl: config.baseUrl, accessToken, workspaceKeyHeader },
4077
4054
  docId
4078
4055
  );
4079
4056
  let filename = `${docId}`;
@@ -4082,18 +4059,19 @@ function registerDownloadCommand(program2) {
4082
4059
  const match = disposition.match(/filename[*]?=(?:UTF-8''|"?)([^";]+)/i);
4083
4060
  if (match) filename = decodeURIComponent(match[1].replace(/"/g, ""));
4084
4061
  }
4085
- const outputPath = opts.output || path2__default.default.join(process.cwd(), filename);
4062
+ const outputPath = opts.output || path__default.default.join(process.cwd(), filename);
4086
4063
  const buffer = Buffer.from(await res.arrayBuffer());
4087
4064
  fs__default.default.writeFileSync(outputPath, buffer);
4088
4065
  console.log(
4089
- `Downloaded: ${path2__default.default.basename(outputPath)} (${(buffer.length / (1024 * 1024)).toFixed(1)} MB)`
4066
+ `Downloaded: ${path__default.default.basename(outputPath)} (${(buffer.length / (1024 * 1024)).toFixed(1)} MB)`
4090
4067
  );
4091
4068
  })()
4092
4069
  );
4093
4070
  }
4094
4071
  function registerAskCommand(program2) {
4095
- program2.command("ask <question>").description("Ask the RAG assistant a question").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").option("-c, --config <id>", "Config ext_id to use (e.g. cfg-xxx)").option("-n, --new", "Start a new conversation (ignore previous context)").option("-v, --verbose", "Show agent steps and tool calls").action(
4096
- (question, opts) => runAction(async () => {
4072
+ program2.command("ask <question...>").description("Ask the RAG assistant a question (no quotes needed)").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").option("-c, --config <id>", "Config ext_id to use (e.g. cfg-xxx)").option("-n, --new", "Start a new conversation (ignore previous context)").option("-v, --verbose", "Show agent steps and tool calls").action(
4073
+ (words, opts) => runAction(async () => {
4074
+ const question = words.join(" ");
4097
4075
  const { arbi, accessToken, workspaceKeyHeader, workspaceId, config } = await resolveWorkspace(opts.workspace);
4098
4076
  const session = getChatSession();
4099
4077
  if (opts.new) {
@@ -4112,7 +4090,7 @@ function registerAskCommand(program2) {
4112
4090
  parentMessageExtId: session.lastMessageExtId,
4113
4091
  configExtId: opts.config
4114
4092
  });
4115
- const { assistantMessageExtId } = await core.streamSSE(res, {
4093
+ const result = await core.streamSSE(res, {
4116
4094
  onToken: (content) => process.stdout.write(content),
4117
4095
  onAgentStep: (data) => {
4118
4096
  if (opts.verbose) {
@@ -4125,8 +4103,15 @@ function registerAskCommand(program2) {
4125
4103
  Error: ${message}`)
4126
4104
  });
4127
4105
  process.stdout.write("\n");
4128
- if (assistantMessageExtId) {
4129
- updateChatSession({ lastMessageExtId: assistantMessageExtId });
4106
+ if (result.assistantMessageExtId) {
4107
+ const updates = {
4108
+ lastMessageExtId: result.assistantMessageExtId
4109
+ };
4110
+ const conversationExtId = result.userMessage?.conversation_ext_id ?? result.metadata?.conversation_ext_id;
4111
+ if (conversationExtId) {
4112
+ updates.conversationExtId = conversationExtId;
4113
+ }
4114
+ updateChatSession(updates);
4130
4115
  }
4131
4116
  })()
4132
4117
  );
@@ -4181,10 +4166,7 @@ function registerContactsCommand(program2) {
4181
4166
  {
4182
4167
  header: "NAME",
4183
4168
  width: 20,
4184
- value: (r) => {
4185
- const u = r.user;
4186
- return u ? [u.given_name, u.family_name].filter(Boolean).join(" ") : "";
4187
- }
4169
+ value: (r) => core.formatUserName(r.user)
4188
4170
  },
4189
4171
  { header: "EMAIL", width: 30, value: (r) => r.email },
4190
4172
  { header: "STATUS", width: 18, value: (r) => r.status }
@@ -4220,8 +4202,7 @@ function registerContactsCommand(program2) {
4220
4202
  contactIds = await promptCheckbox(
4221
4203
  "Select contacts to remove",
4222
4204
  data.map((c) => {
4223
- const u = c.user;
4224
- const name = u ? [u.given_name, u.family_name].filter(Boolean).join(" ") : "";
4205
+ const name = core.formatUserName(c.user);
4225
4206
  return {
4226
4207
  name: name ? `${name} (${c.email})` : c.email,
4227
4208
  value: c.external_id
@@ -4257,9 +4238,7 @@ function registerDmCommand(program2) {
4257
4238
  width: 22,
4258
4239
  value: (r) => {
4259
4240
  const s = r.sender;
4260
- if (!s) return "";
4261
- const name = [s.given_name, s.family_name].filter(Boolean).join(" ");
4262
- return name || s.email || "";
4241
+ return core.formatUserName(s) || s?.email || "";
4263
4242
  }
4264
4243
  },
4265
4244
  { header: "READ", width: 6, value: (r) => r.read ? "yes" : "no" },
@@ -4282,7 +4261,7 @@ function registerDmCommand(program2) {
4282
4261
  "Send to",
4283
4262
  contacts.map((c) => {
4284
4263
  const u = c.user;
4285
- const name = u ? [u.given_name, u.family_name].filter(Boolean).join(" ") : "";
4264
+ const name = core.formatUserName(u);
4286
4265
  return {
4287
4266
  name: name ? `${name} (${c.email})` : c.email,
4288
4267
  value: u?.external_id ?? c.external_id,
@@ -4326,7 +4305,7 @@ function registerDmCommand(program2) {
4326
4305
  "Select messages to mark as read",
4327
4306
  unread.map((m) => {
4328
4307
  const s = m.sender;
4329
- const from = s ? [s.given_name, s.family_name].filter(Boolean).join(" ") || s.email || "" : "";
4308
+ const from = core.formatUserName(s) || s?.email || "";
4330
4309
  return {
4331
4310
  name: `${from}: ${(m.content ?? "").slice(0, 50)}`,
4332
4311
  value: m.external_id
@@ -4353,7 +4332,7 @@ function registerDmCommand(program2) {
4353
4332
  "Select messages to delete",
4354
4333
  data.map((m) => {
4355
4334
  const s = m.sender;
4356
- const from = s ? [s.given_name, s.family_name].filter(Boolean).join(" ") || s.email || "" : "";
4335
+ const from = core.formatUserName(s) || s?.email || "";
4357
4336
  return {
4358
4337
  name: `${from}: ${(m.content ?? "").slice(0, 50)}`,
4359
4338
  value: m.external_id