@arbidocs/cli 0.3.41 โ†’ 0.3.42

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 CHANGED
@@ -1,12 +1,20 @@
1
1
  # Changelog
2
2
 
3
- ## v0.3.41
3
+ ## v0.3.42
4
4
 
5
5
  [compare changes](https://github.com/arbicity/ARBI-frontend/compare/v0.3.40...HEAD)
6
6
 
7
- ### ๐Ÿก Chore
7
+ ### ๐Ÿš€ Enhancements
8
+
9
+ - **cli:** Workspace improvements โ€” --json, workspace current, delete + copy fixes ([#623](https://github.com/arbicity/ARBI-frontend/pull/623))
10
+
11
+ ## v0.3.40
12
+
13
+ [compare changes](https://github.com/arbicity/ARBI-frontend/compare/v0.3.39...HEAD)
14
+
15
+ ### ๐Ÿš€ Enhancements
8
16
 
9
- - Release v0.3.40 [skip ci] ([5e404545](https://github.com/arbicity/ARBI-frontend/commit/5e404545))
17
+ - **cli:** Add --json to list commands + agent-aware not-logged-in hint ([#629](https://github.com/arbicity/ARBI-frontend/pull/629))
10
18
 
11
19
  ## v0.3.39
12
20
 
package/SKILL.md CHANGED
@@ -32,12 +32,12 @@ Documents, conversations, and tags are scoped per workspace. An active workspace
32
32
  Common moves:
33
33
 
34
34
  - List: `arbi workspaces` (human) ยท `arbi workspaces --json` (script) ยท `arbi workspaces --ids`
35
- - Active workspace ID: `arbi workspace current` (prints the ID, empty string if none)
36
- - Pick/switch: `arbi workspace select <id>` โ€” clears the chat session; uploaded docs in other workspaces are unaffected
37
- - Create: `arbi workspace create "My WS"` โ€” does NOT auto-select, follow with `workspace select`
38
- - Rename / edit: `arbi workspace update '{"name":"New Name"}'`
39
- - Delete: `arbi workspace delete [id]` โ€” deletes immediately (no confirmation prompt); if you delete the active workspace, the selection is cleared
40
- - Share: `arbi workspace add-user <email> -r <role>` where role is `owner|collaborator|guest` (may be plan-limited)
35
+ - Active workspace ID: `arbi workspace current` (prints the ID, empty string if none) ยท `arbi workspace current --json` for full details
36
+ - Pick/switch: `arbi workspace select <id-or-name>` โ€” accepts a workspace ID or a unique (case-insensitive) name; clears the chat session; uploaded docs in other workspaces are unaffected
37
+ - Create: `arbi workspace create "My WS"` โ€” does NOT auto-select. Use `--select` to create + select in one go, `--json` for scripts
38
+ - Rename / edit: `arbi workspace update '{"name":"New Name"}'` (add `--json` for scripts)
39
+ - Delete: `arbi workspace delete [id-or-name]` โ€” prompts for confirmation in interactive shells. In non-TTY shells you **must** pass `-y/--yes` (otherwise the command refuses to delete). If you delete the active workspace, the selection is cleared. `--json` outputs `{id, deleted}`
40
+ - Share: `arbi workspace add-user <email> -r <role>` where role is `owner|collaborator|guest` (plan-limited โ€” free tier has 0 collaborator slots)
41
41
  - List members: `arbi workspace users [--json]`
42
42
  - Remove member: `arbi workspace remove-user <user-id>`
43
43
  - Copy docs between workspaces: `arbi workspace copy <target-ws-id> <doc-id>...` โ€” only copies documents that have finished indexing; partial/failed copies exit non-zero
@@ -45,8 +45,10 @@ Common moves:
45
45
  Scripting notes:
46
46
 
47
47
  - The table output of `arbi workspaces` is NOT reliably parseable (names contain spaces, status cells may contain glyphs). Use `--json` or `--ids`.
48
+ - Switch-by-name in one line: `arbi workspace select "My WS"`. If the name is ambiguous, the CLI lists the matches and exits non-zero โ€” use the ID.
48
49
  - Sessions persist between CLI invocations via the config file (default `~/.arbi/`, override with `ARBI_CONFIG_DIR`).
49
50
  - Per-agent isolation: run agents with their own `ARBI_CONFIG_DIR=<path>` (or `ARBI_ID=<name>`) to avoid stomping each other's active workspace.
51
+ - Agent accounts typically have 0 collaborator slots, so `workspace add-user` errors with "Collaborator limit reached" unless the plan is upgraded.
50
52
 
51
53
  ## Tips
52
54
 
@@ -54,7 +56,7 @@ Scripting notes:
54
56
  - If a command fails with "fetch failed", check connectivity with `arbi health`.
55
57
  - Use `arbi ask -n` to start a fresh conversation (forget prior context).
56
58
  - Use `arbi ask -v` for verbose output showing retrieval steps.
57
- - Use `arbi status --json` and `arbi workspace current` to read CLI state from scripts.
59
+ - Use `arbi status --json` and `arbi workspace current` to read CLI state from scripts. `arbi workspaces --json` lists every workspace with `is_selected` marked.
58
60
 
59
61
  ## For Automations / AI Agents
60
62
 
package/dist/index.js CHANGED
@@ -3641,7 +3641,7 @@ function getLatestVersion(skipCache = false) {
3641
3641
  }
3642
3642
  }
3643
3643
  function getCurrentVersion() {
3644
- return "0.3.41";
3644
+ return "0.3.42";
3645
3645
  }
3646
3646
  function readChangelog(fromVersion, toVersion) {
3647
3647
  try {
@@ -3694,17 +3694,17 @@ function showChangelog(fromVersion, toVersion) {
3694
3694
  async function checkForUpdates(autoUpdate) {
3695
3695
  try {
3696
3696
  const latest = getLatestVersion();
3697
- if (!latest || latest === "0.3.41") return;
3697
+ if (!latest || latest === "0.3.42") return;
3698
3698
  if (autoUpdate) {
3699
3699
  warn(`
3700
- Your arbi version is out of date (${"0.3.41"} \u2192 ${latest}). Updating...`);
3700
+ Your arbi version is out of date (${"0.3.42"} \u2192 ${latest}). Updating...`);
3701
3701
  child_process.execSync("npm install -g @arbidocs/cli@latest", { stdio: "inherit" });
3702
- showChangelog("0.3.41", latest);
3702
+ showChangelog("0.3.42", latest);
3703
3703
  console.log(`Updated to ${latest}.`);
3704
3704
  } else {
3705
3705
  warn(
3706
3706
  `
3707
- Your arbi version is out of date (${"0.3.41"} \u2192 ${latest}).
3707
+ Your arbi version is out of date (${"0.3.42"} \u2192 ${latest}).
3708
3708
  Run "arbi update" to upgrade, or "arbi update auto" to always stay up to date.`
3709
3709
  );
3710
3710
  }
@@ -3714,9 +3714,9 @@ Run "arbi update" to upgrade, or "arbi update auto" to always stay up to date.`
3714
3714
  function hintUpdateOnError() {
3715
3715
  try {
3716
3716
  const cached = readCache();
3717
- if (cached && cached.latest !== "0.3.41") {
3717
+ if (cached && cached.latest !== "0.3.42") {
3718
3718
  warn(
3719
- `Your arbi version is out of date (${"0.3.41"} \u2192 ${cached.latest}). Run "arbi update".`
3719
+ `Your arbi version is out of date (${"0.3.42"} \u2192 ${cached.latest}). Run "arbi update".`
3720
3720
  );
3721
3721
  }
3722
3722
  } catch {
@@ -4417,12 +4417,49 @@ function registerStatusCommand(program2) {
4417
4417
  }
4418
4418
  });
4419
4419
  }
4420
+ function resolveWorkspaceSelector(list, selector) {
4421
+ const byId = list.find((w) => w.external_id === selector);
4422
+ if (byId) return { ok: true, id: byId.external_id, ws: byId };
4423
+ const lower = selector.toLowerCase();
4424
+ const byName = list.filter((w) => (w.name ?? "").toLowerCase() === lower);
4425
+ if (byName.length === 1) return { ok: true, id: byName[0].external_id, ws: byName[0] };
4426
+ if (byName.length > 1) return { ok: false, reason: "ambiguous", matches: byName };
4427
+ return { ok: false, reason: "not-found" };
4428
+ }
4429
+ function printResolveError(list, selector, res) {
4430
+ if (res.ok) return;
4431
+ if (res.reason === "ambiguous") {
4432
+ error(`Workspace name "${selector}" is ambiguous \u2014 multiple matches:`);
4433
+ for (const w of res.matches ?? []) error(` ${w.external_id} ${w.name}`);
4434
+ error("Use the workspace ID instead.");
4435
+ return;
4436
+ }
4437
+ error(`Workspace ${selector} not found.`);
4438
+ error("Available workspaces:");
4439
+ for (const w of list) error(` ${w.external_id} ${w.name}`);
4440
+ }
4420
4441
  function registerWorkspacesCommand(program2) {
4421
- program2.command("workspaces").description("List workspaces").action(
4422
- runAction(async () => {
4442
+ program2.command("workspaces").description("List workspaces").option("--json", "Output as JSON").option("--ids", "Output only workspace IDs (one per line)").action(
4443
+ (opts) => runAction(async () => {
4423
4444
  const { arbi } = await resolveAuth();
4424
4445
  const data = await sdk.workspaces.listWorkspaces(arbi);
4425
4446
  updateCompletionCache(data);
4447
+ if (opts.ids) {
4448
+ for (const w of data) console.log(w.external_id);
4449
+ return;
4450
+ }
4451
+ if (opts.json) {
4452
+ const selectedId = getConfig()?.selectedWorkspaceId ?? null;
4453
+ const out = data.map((w) => ({
4454
+ id: w.external_id,
4455
+ name: w.name,
4456
+ docs: w.shared_document_count + w.private_document_count,
4457
+ role: w.users?.[0]?.role ?? null,
4458
+ is_selected: w.external_id === selectedId
4459
+ }));
4460
+ console.log(JSON.stringify(out, null, 2));
4461
+ return;
4462
+ }
4426
4463
  if (data.length === 0) {
4427
4464
  console.log("No workspaces found.");
4428
4465
  return;
@@ -4444,11 +4481,51 @@ function registerWorkspacesCommand(program2) {
4444
4481
  ],
4445
4482
  data
4446
4483
  );
4447
- })
4484
+ })()
4448
4485
  );
4449
4486
  const workspace = program2.command("workspace").description("Workspace management");
4450
- workspace.command("select [id]").description("Select active workspace (interactive picker if no ID given)").action(
4451
- (id) => runAction(async () => {
4487
+ workspace.command("current").description("Print the currently selected workspace ID (empty string if none)").option("--json", "Output full details as JSON").action(
4488
+ (opts) => runAction(async () => {
4489
+ const selectedId = getConfig()?.selectedWorkspaceId ?? "";
4490
+ if (!opts.json) {
4491
+ console.log(selectedId);
4492
+ return;
4493
+ }
4494
+ if (!selectedId) {
4495
+ console.log(JSON.stringify({ id: null, name: null, docs: 0, role: null }, null, 2));
4496
+ return;
4497
+ }
4498
+ const { arbi } = await resolveAuth();
4499
+ const data = await sdk.workspaces.listWorkspaces(arbi);
4500
+ const ws = data.find((w) => w.external_id === selectedId);
4501
+ if (!ws) {
4502
+ console.log(
4503
+ JSON.stringify(
4504
+ { id: selectedId, name: null, docs: 0, role: null, stale: true },
4505
+ null,
4506
+ 2
4507
+ )
4508
+ );
4509
+ return;
4510
+ }
4511
+ console.log(
4512
+ JSON.stringify(
4513
+ {
4514
+ id: ws.external_id,
4515
+ name: ws.name,
4516
+ docs: ws.shared_document_count + ws.private_document_count,
4517
+ role: ws.users?.[0]?.role ?? null
4518
+ },
4519
+ null,
4520
+ 2
4521
+ )
4522
+ );
4523
+ })()
4524
+ );
4525
+ workspace.command("select [id-or-name]").description(
4526
+ "Select active workspace (accepts ID or unique name; interactive picker if nothing given)"
4527
+ ).action(
4528
+ (idOrName) => runAction(async () => {
4452
4529
  const { arbi } = await resolveAuth();
4453
4530
  const data = await sdk.workspaces.listWorkspaces(arbi);
4454
4531
  updateCompletionCache(data);
@@ -4457,15 +4534,13 @@ function registerWorkspacesCommand(program2) {
4457
4534
  return;
4458
4535
  }
4459
4536
  let selectedId;
4460
- if (id) {
4461
- const ws2 = data.find((w) => w.external_id === id);
4462
- if (!ws2) {
4463
- error(`Workspace ${id} not found.`);
4464
- error("Available workspaces:");
4465
- for (const w of data) error(` ${w.external_id} ${w.name}`);
4537
+ if (idOrName) {
4538
+ const res = resolveWorkspaceSelector(data, idOrName);
4539
+ if (!res.ok) {
4540
+ printResolveError(data, idOrName, res);
4466
4541
  process.exit(1);
4467
4542
  }
4468
- selectedId = id;
4543
+ selectedId = res.id;
4469
4544
  } else {
4470
4545
  const choices = sdk.formatWorkspaceChoices(data);
4471
4546
  selectedId = await promptSelect("Select workspace", choices);
@@ -4476,7 +4551,7 @@ function registerWorkspacesCommand(program2) {
4476
4551
  success(`Selected: ${ws.name} (${ref(selectedId)})`);
4477
4552
  })()
4478
4553
  );
4479
- workspace.command("create <name>").description("Create a new workspace").option("-d, --description <text>", "Workspace description").option("--public", "Make workspace public", false).action(
4554
+ workspace.command("create <name>").description("Create a new workspace").option("-d, --description <text>", "Workspace description").option("--public", "Make workspace public", false).option("--select", "Set the new workspace as the active selection", false).option("--json", "Output the new workspace as JSON").action(
4480
4555
  (name, opts) => runAction(async () => {
4481
4556
  const { arbi, loginResult } = await resolveAuth();
4482
4557
  const userProjects = await sdk.projects.listProjects(arbi);
@@ -4491,37 +4566,114 @@ function registerWorkspacesCommand(program2) {
4491
4566
  opts.description,
4492
4567
  opts.public ?? false
4493
4568
  );
4569
+ if (opts.select) {
4570
+ updateConfig({ selectedWorkspaceId: data.external_id });
4571
+ clearChatSession();
4572
+ }
4573
+ if (opts.json) {
4574
+ console.log(
4575
+ JSON.stringify(
4576
+ {
4577
+ id: data.external_id,
4578
+ name: data.name,
4579
+ selected: opts.select ?? false
4580
+ },
4581
+ null,
4582
+ 2
4583
+ )
4584
+ );
4585
+ return;
4586
+ }
4494
4587
  success(`Created: ${data.name} (${ref(data.external_id)})`);
4588
+ if (opts.select) success(`Selected: ${data.name} (${ref(data.external_id)})`);
4495
4589
  })()
4496
4590
  );
4497
- workspace.command("delete [id]").description("Delete a workspace (defaults to selected workspace)").action(
4498
- (id) => runAction(async () => {
4591
+ workspace.command("delete [id-or-name]").description("Delete a workspace (defaults to selected workspace)").option("-y, --yes", "Skip confirmation prompt (required in non-interactive shells)", false).option("--json", "Output the result as JSON").action(
4592
+ (idOrName, opts) => runAction(async () => {
4499
4593
  const { arbi } = await resolveAuth();
4500
- const targetId = id ?? getConfig()?.selectedWorkspaceId;
4501
- if (!targetId) {
4502
- error("No workspace ID given and no workspace selected. Run: arbi workspace select");
4503
- process.exit(1);
4594
+ const config = getConfig();
4595
+ let targetId;
4596
+ let targetName;
4597
+ if (idOrName) {
4598
+ const data = await sdk.workspaces.listWorkspaces(arbi);
4599
+ const res = resolveWorkspaceSelector(data, idOrName);
4600
+ if (!res.ok) {
4601
+ printResolveError(data, idOrName, res);
4602
+ process.exit(1);
4603
+ }
4604
+ targetId = res.id;
4605
+ targetName = res.ws.name;
4606
+ } else {
4607
+ targetId = config?.selectedWorkspaceId;
4608
+ if (!targetId) {
4609
+ error("No workspace ID given and no workspace selected. Run: arbi workspace select");
4610
+ process.exit(1);
4611
+ }
4612
+ }
4613
+ const isInteractive = process.stdin.isTTY === true && process.stdout.isTTY === true;
4614
+ if (!opts.yes) {
4615
+ if (!isInteractive) {
4616
+ error(
4617
+ `Refusing to delete ${targetId} without confirmation. Re-run with --yes (non-interactive shell).`
4618
+ );
4619
+ process.exit(1);
4620
+ }
4621
+ const label2 = targetName ? `"${targetName}" (${targetId})` : targetId;
4622
+ const confirmed = await promptConfirm(
4623
+ `Delete workspace ${label2}? This removes all documents, conversations, and tags in it.`,
4624
+ false
4625
+ );
4626
+ if (!confirmed) {
4627
+ console.log("Cancelled.");
4628
+ return;
4629
+ }
4504
4630
  }
4505
4631
  await sdk.workspaces.deleteWorkspaces(arbi, [targetId]);
4632
+ if (config?.selectedWorkspaceId === targetId) {
4633
+ updateConfig({ selectedWorkspaceId: void 0 });
4634
+ }
4506
4635
  const session = getChatSession();
4507
4636
  if (session.workspaceId === targetId) {
4508
4637
  clearChatSession();
4509
4638
  }
4639
+ if (opts.json) {
4640
+ console.log(JSON.stringify({ id: targetId, deleted: true }, null, 2));
4641
+ return;
4642
+ }
4510
4643
  success(`Deleted workspace ${targetId}`);
4511
4644
  })()
4512
4645
  );
4513
- workspace.command("update <json>").description("Update workspace properties (pass JSON)").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").action(
4646
+ workspace.command("update <json>").description("Update workspace properties (pass JSON)").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").option("--json", "Output the updated workspace as JSON").action(
4514
4647
  (json, opts) => runAction(async () => {
4515
4648
  const body = parseJsonArg(json, `arbi workspace update '{"name": "New Name"}'`);
4516
4649
  const { arbi } = await resolveWorkspace(opts.workspace);
4517
4650
  const data = await sdk.workspaces.updateWorkspace(arbi, body);
4651
+ if (opts.json) {
4652
+ console.log(JSON.stringify({ id: data.external_id, name: data.name }, null, 2));
4653
+ return;
4654
+ }
4518
4655
  success(`Updated: ${data.name} (${ref(data.external_id)})`);
4519
4656
  })()
4520
4657
  );
4521
- workspace.command("users").description("List users in the active workspace").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").action(
4658
+ workspace.command("users").description("List users in the active workspace").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").option("--json", "Output as JSON").action(
4522
4659
  (opts) => runAction(async () => {
4523
4660
  const { arbi } = await resolveWorkspace(opts.workspace);
4524
4661
  const data = await sdk.workspaces.listWorkspaceUsers(arbi);
4662
+ if (opts.json) {
4663
+ const out = data.map((r) => {
4664
+ const u = r.user ?? {};
4665
+ return {
4666
+ user_id: u.external_id ?? null,
4667
+ email: u.email ?? null,
4668
+ name: [u.given_name, u.family_name].filter(Boolean).join(" ") || null,
4669
+ role: r.role,
4670
+ document_count: r.document_count,
4671
+ conversation_count: r.conversation_count
4672
+ };
4673
+ });
4674
+ console.log(JSON.stringify(out, null, 2));
4675
+ return;
4676
+ }
4525
4677
  if (data.length === 0) {
4526
4678
  console.log("No users found.");
4527
4679
  return;
@@ -4598,7 +4750,18 @@ function registerWorkspacesCommand(program2) {
4598
4750
  signingPrivateKeyBase64
4599
4751
  );
4600
4752
  const data = await sdk.workspaces.copyDocuments(arbi, targetId, docIds, targetKey);
4601
- success(`${data.detail} (${data.documents_copied} document(s) copied)`);
4753
+ const copied = data.documents_copied ?? 0;
4754
+ const requested = docIds.length;
4755
+ if (copied === 0) {
4756
+ error(`Copied 0 of ${requested} document(s). ${data.detail ?? ""}`.trim());
4757
+ error("Hint: documents must be fully indexed before they can be copied.");
4758
+ process.exit(1);
4759
+ }
4760
+ if (copied < requested) {
4761
+ error(`Copied ${copied} of ${requested} document(s). ${data.detail ?? ""}`.trim());
4762
+ return;
4763
+ }
4764
+ success(`Copied ${copied} document(s) to ${targetId}`);
4602
4765
  })()
4603
4766
  );
4604
4767
  }
@@ -8299,7 +8462,7 @@ console.info = (...args) => {
8299
8462
  _origInfo(...args);
8300
8463
  };
8301
8464
  var program = new commander.Command();
8302
- program.name("arbi").description("ARBI CLI \u2014 interact with ARBI from the terminal").version("0.3.41");
8465
+ program.name("arbi").description("ARBI CLI \u2014 interact with ARBI from the terminal").version("0.3.42");
8303
8466
  registerConfigCommand(program);
8304
8467
  registerLoginCommand(program);
8305
8468
  registerRegisterCommand(program);