@arbidocs/cli 0.3.13 → 0.3.14

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,82 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.3.14
4
+
5
+ [compare changes](https://github.com/arbicity/ARBI-frontend/compare/v0.3.13...HEAD)
6
+
7
+ ### 🚀 Enhancements
8
+
9
+ - **cli:** Verbose default, configurable watch, default notifications ([22f0faea](https://github.com/arbicity/ARBI-frontend/commit/22f0faea))
10
+ - **cli:** Add response summary line and per-step token usage ([506c723d](https://github.com/arbicity/ARBI-frontend/commit/506c723d))
11
+ - **cli:** Add `arbi task` command for background query submission ([fb492311](https://github.com/arbicity/ARBI-frontend/commit/fb492311))
12
+ - Update schema, SSE token context, and context usage display ([9f908e99](https://github.com/arbicity/ARBI-frontend/commit/9f908e99))
13
+
14
+ ### 🩹 Fixes
15
+
16
+ - Remove stray fi in publish script causing exit code 2 ([7739d8de](https://github.com/arbicity/ARBI-frontend/commit/7739d8de))
17
+ - Changelog generation and enforce conventional commits ([ac5b2e75](https://github.com/arbicity/ARBI-frontend/commit/ac5b2e75))
18
+
19
+ ### 💅 Refactors
20
+
21
+ - **cli:** Move background mode to `arbi ask -b`, simplify task command ([2b9a1a51](https://github.com/arbicity/ARBI-frontend/commit/2b9a1a51))
22
+
3
23
  ## v0.3.13
4
24
 
5
- [compare changes](https://github.com/arbicity/ARBI-frontend/compare/v0.3.11...HEAD)
25
+ [compare changes](https://github.com/arbicity/ARBI-frontend/compare/v0.3.10...v0.3.13)
26
+
27
+ ### 🚀 Enhancements
28
+
29
+ - Tool-specific icons and labels for agent step rendering ([22377ee4](https://github.com/arbicity/ARBI-frontend/commit/22377ee4))
30
+ - Move TOOL_LABELS and LIFECYCLE_LABELS to SDK as single source of truth ([b180663f](https://github.com/arbicity/ARBI-frontend/commit/b180663f))
31
+ - Move templates to agentic mode with get_full_document ([9e625515](https://github.com/arbicity/ARBI-frontend/commit/9e625515))
32
+ - CLI DX improvements: error messages, JWT caching, auto-detect, watch flags, quickstart & agent-create ([eefcc3ef](https://github.com/arbicity/ARBI-frontend/commit/eefcc3ef))
33
+ - Add comprehensive CLI integration tests ([bb5088d2](https://github.com/arbicity/ARBI-frontend/commit/bb5088d2))
34
+ - Simplified template modals v2 ([b2639ea7](https://github.com/arbicity/ARBI-frontend/commit/b2639ea7))
35
+ - Searchable document combobox for Summarise and Translate templates ([880db107](https://github.com/arbicity/ARBI-frontend/commit/880db107))
36
+ - Document page/token counts with size warnings ([49c72ab8](https://github.com/arbicity/ARBI-frontend/commit/49c72ab8))
37
+ - Preserve folder structure on upload ([dc09dbfa](https://github.com/arbicity/ARBI-frontend/commit/dc09dbfa))
38
+ - Folder UI for Documents page ([aaf08dbc](https://github.com/arbicity/ARBI-frontend/commit/aaf08dbc))
39
+ - Uploaded/generated toggle and folder tree in FilterDropdown ([87351c31](https://github.com/arbicity/ARBI-frontend/commit/87351c31))
40
+ - Add text search to Documents page ([bda72622](https://github.com/arbicity/ARBI-frontend/commit/bda72622))
41
+ - Add search field selector and expose folder/content_hash columns ([595d02eb](https://github.com/arbicity/ARBI-frontend/commit/595d02eb))
42
+ - Agentic mode toggle and agent step text handling ([22852e84](https://github.com/arbicity/ARBI-frontend/commit/22852e84))
43
+ - Add Duplicates tri-state filter for documents ([e1682939](https://github.com/arbicity/ARBI-frontend/commit/e1682939))
44
+ - Home page cards: left-align, group by matter ID with collapsible sub-sections ([f3e51750](https://github.com/arbicity/ARBI-frontend/commit/f3e51750))
45
+ - Documents grid improvements, collapsible folder filter, agent step durations ([735f066b](https://github.com/arbicity/ARBI-frontend/commit/735f066b))
46
+ - Developer tab: nested schema fields, footer layout, Apply button ([7daac802](https://github.com/arbicity/ARBI-frontend/commit/7daac802))
47
+ - Redesign templates as horizontal rows with pin button ([8ed4c4e1](https://github.com/arbicity/ARBI-frontend/commit/8ed4c4e1))
48
+ - Make @arbidocs/sdk WebContainer-compatible ([2e5446f3](https://github.com/arbicity/ARBI-frontend/commit/2e5446f3))
49
+ - Optimize HtmlViewer for large documents with lazy loading ([aa3f7733](https://github.com/arbicity/ARBI-frontend/commit/aa3f7733))
50
+
51
+ ### 🩹 Fixes
52
+
53
+ - Fix stale cached token after login/workspace switch ([ef222604](https://github.com/arbicity/ARBI-frontend/commit/ef222604))
54
+ - Fix CI publish: restore PAT_PUBLISH, fail loudly on push errors ([15b8d8e8](https://github.com/arbicity/ARBI-frontend/commit/15b8d8e8))
55
+ - Fix bulk actions toolbar hidden in document modals ([fcf70be3](https://github.com/arbicity/ARBI-frontend/commit/fcf70be3))
56
+ - Resolve document titles in agent step display ([71da1b41](https://github.com/arbicity/ARBI-frontend/commit/71da1b41))
57
+ - Fix document grid in modals by using fixed height ([0e5ed342](https://github.com/arbicity/ARBI-frontend/commit/0e5ed342))
58
+ - Fix citation scroll-to-chunk and show page nav for HTML view ([624a6cfc](https://github.com/arbicity/ARBI-frontend/commit/624a6cfc))
59
+ - Fix citation scroll-to-passage and remove markdown arrow artifacts ([3ce0d32d](https://github.com/arbicity/ARBI-frontend/commit/3ce0d32d))
60
+ - Fix Apply button: stop resetting newConfigId on parentMessageId change ([729f30e9](https://github.com/arbicity/ARBI-frontend/commit/729f30e9))
61
+ - Fix streaming content truncated in non-agentic mode ([7f338f25](https://github.com/arbicity/ARBI-frontend/commit/7f338f25))
62
+ - Prevent agent step preamble from appearing in message body ([0e99e3ed](https://github.com/arbicity/ARBI-frontend/commit/0e99e3ed))
63
+ - Fix model selector resets on messageHistory/parentConfig changes ([c30e4d7c](https://github.com/arbicity/ARBI-frontend/commit/c30e4d7c))
64
+ - Fix workspace switch revert when triggered from home page ([370a46a5](https://github.com/arbicity/ARBI-frontend/commit/370a46a5))
65
+ - Sanitize folder paths for backend API ([70dc0f4a](https://github.com/arbicity/ARBI-frontend/commit/70dc0f4a))
66
+ - Remove selectedThreadId, unify into parentMessageId ([c20f0785](https://github.com/arbicity/ARBI-frontend/commit/c20f0785))
67
+ - Extract metadata from response.completed SSE event ([e8bff08d](https://github.com/arbicity/ARBI-frontend/commit/e8bff08d))
68
+ - Extract conversation documents from last user message instead of leaf ([b3d2718e](https://github.com/arbicity/ARBI-frontend/commit/b3d2718e))
69
+ - CLI integration test failures ([b092962e](https://github.com/arbicity/ARBI-frontend/commit/b092962e))
70
+ - Handle protected branches in publish script ([7746517e](https://github.com/arbicity/ARBI-frontend/commit/7746517e))
6
71
 
7
72
  ### 🏡 Chore
8
73
 
9
- - Bump packages to v0.3.12 for publish ([a13842c0](https://github.com/arbicity/ARBI-frontend/commit/a13842c0))
74
+ - Update schema: add scores to CitationData, chunker tokenizer config ([7fc18309](https://github.com/arbicity/ARBI-frontend/commit/7fc18309))
75
+ - Schema updates ([ab08dc54](https://github.com/arbicity/ARBI-frontend/commit/ab08dc54), [76046067](https://github.com/arbicity/ARBI-frontend/commit/76046067))
76
+ - Remove MemoryLLM from schema ([6806daea](https://github.com/arbicity/ARBI-frontend/commit/6806daea))
77
+ - CI: move integration tests off PR triggers, gate deploy behind them ([ff23f07a](https://github.com/arbicity/ARBI-frontend/commit/ff23f07a))
78
+ - Move PA mode toggle behind experimental feature flag ([2f00bce8](https://github.com/arbicity/ARBI-frontend/commit/2f00bce8))
79
+ - Replace MCP references with TUI in SDK comments ([42683222](https://github.com/arbicity/ARBI-frontend/commit/42683222))
10
80
 
11
81
  ## v0.3.10
12
82
 
package/dist/index.js CHANGED
@@ -125,7 +125,9 @@ function registerConfigCommand(program2) {
125
125
  label("Server URL:", cfg.baseUrl);
126
126
  label("Domain:", cfg.deploymentDomain);
127
127
  label("Auto-update:", cfg.autoUpdate ? "on" : "off");
128
- label("Notifications:", cfg.notifications ? "on" : "off");
128
+ label("Verbose:", cfg.verbose !== false ? "on" : "off");
129
+ label("Watch:", cfg.watch !== false ? "on" : "off");
130
+ label("Notifications:", cfg.notifications !== false ? "on" : "off");
129
131
  if (cfg.selectedWorkspaceId) {
130
132
  label("Workspace:", cfg.selectedWorkspaceId);
131
133
  }
@@ -133,7 +135,7 @@ function registerConfigCommand(program2) {
133
135
  config.command("notifications [on|off]").description("Toggle background WebSocket notifications").action((toggle) => {
134
136
  const cfg = getConfig();
135
137
  if (!toggle) {
136
- label("Notifications:", cfg?.notifications ? "on" : "off");
138
+ label("Notifications:", cfg?.notifications !== false ? "on" : "off");
137
139
  return;
138
140
  }
139
141
  if (toggle !== "on" && toggle !== "off") {
@@ -143,6 +145,32 @@ function registerConfigCommand(program2) {
143
145
  updateConfig({ notifications: toggle === "on" });
144
146
  success(`Notifications: ${toggle}`);
145
147
  });
148
+ config.command("verbose [on|off]").description("Toggle verbose agent steps in ask (default: on)").action((toggle) => {
149
+ const cfg = getConfig();
150
+ if (!toggle) {
151
+ label("Verbose:", cfg?.verbose !== false ? "on" : "off");
152
+ return;
153
+ }
154
+ if (toggle !== "on" && toggle !== "off") {
155
+ error("Usage: arbi config verbose [on|off]");
156
+ process.exit(1);
157
+ }
158
+ updateConfig({ verbose: toggle === "on" });
159
+ success(`Verbose: ${toggle}`);
160
+ });
161
+ config.command("watch [on|off]").description("Toggle upload watch (default: on)").action((toggle) => {
162
+ const cfg = getConfig();
163
+ if (!toggle) {
164
+ label("Watch:", cfg?.watch !== false ? "on" : "off");
165
+ return;
166
+ }
167
+ if (toggle !== "on" && toggle !== "off") {
168
+ error("Usage: arbi config watch [on|off]");
169
+ process.exit(1);
170
+ }
171
+ updateConfig({ watch: toggle === "on" });
172
+ success(`Watch: ${toggle}`);
173
+ });
146
174
  config.command("alias").description('Set up shell alias A for "arbi ask"').action(() => {
147
175
  const rcPath = getShellRcPath();
148
176
  if (isAliasInstalled(rcPath)) {
@@ -3509,7 +3537,7 @@ function getLatestVersion(skipCache = false) {
3509
3537
  }
3510
3538
  }
3511
3539
  function getCurrentVersion() {
3512
- return "0.3.13";
3540
+ return "0.3.14";
3513
3541
  }
3514
3542
  function readChangelog(fromVersion, toVersion) {
3515
3543
  try {
@@ -3562,17 +3590,17 @@ function showChangelog(fromVersion, toVersion) {
3562
3590
  async function checkForUpdates(autoUpdate) {
3563
3591
  try {
3564
3592
  const latest = getLatestVersion();
3565
- if (!latest || latest === "0.3.13") return;
3593
+ if (!latest || latest === "0.3.14") return;
3566
3594
  if (autoUpdate) {
3567
3595
  warn(`
3568
- Your arbi version is out of date (${"0.3.13"} \u2192 ${latest}). Updating...`);
3596
+ Your arbi version is out of date (${"0.3.14"} \u2192 ${latest}). Updating...`);
3569
3597
  child_process.execSync("npm install -g @arbidocs/cli@latest", { stdio: "inherit" });
3570
- showChangelog("0.3.13", latest);
3598
+ showChangelog("0.3.14", latest);
3571
3599
  console.log(`Updated to ${latest}.`);
3572
3600
  } else {
3573
3601
  warn(
3574
3602
  `
3575
- Your arbi version is out of date (${"0.3.13"} \u2192 ${latest}).
3603
+ Your arbi version is out of date (${"0.3.14"} \u2192 ${latest}).
3576
3604
  Run "arbi update" to upgrade, or "arbi update auto" to always stay up to date.`
3577
3605
  );
3578
3606
  }
@@ -3582,9 +3610,9 @@ Run "arbi update" to upgrade, or "arbi update auto" to always stay up to date.`
3582
3610
  function hintUpdateOnError() {
3583
3611
  try {
3584
3612
  const cached = readCache();
3585
- if (cached && cached.latest !== "0.3.13") {
3613
+ if (cached && cached.latest !== "0.3.14") {
3586
3614
  warn(
3587
- `Your arbi version is out of date (${"0.3.13"} \u2192 ${cached.latest}). Run "arbi update".`
3615
+ `Your arbi version is out of date (${"0.3.14"} \u2192 ${cached.latest}). Run "arbi update".`
3588
3616
  );
3589
3617
  }
3590
3618
  } catch {
@@ -3852,6 +3880,54 @@ function registerStatusCommand(program2) {
3852
3880
  }
3853
3881
  });
3854
3882
  }
3883
+ var MAX_TASKS = 50;
3884
+ var MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
3885
+ function getTasksFile() {
3886
+ const configDir = process.env.ARBI_CONFIG_DIR ?? path__default.default.join(os__default.default.homedir(), ".arbi");
3887
+ return path__default.default.join(configDir, "tasks.json");
3888
+ }
3889
+ function ensureDir(filePath) {
3890
+ const dir = path__default.default.dirname(filePath);
3891
+ if (!fs__default.default.existsSync(dir)) {
3892
+ fs__default.default.mkdirSync(dir, { recursive: true, mode: 448 });
3893
+ }
3894
+ }
3895
+ function readTasks() {
3896
+ try {
3897
+ const content = fs__default.default.readFileSync(getTasksFile(), "utf-8");
3898
+ return JSON.parse(content);
3899
+ } catch {
3900
+ return [];
3901
+ }
3902
+ }
3903
+ function writeTasks(tasks) {
3904
+ const filePath = getTasksFile();
3905
+ ensureDir(filePath);
3906
+ fs__default.default.writeFileSync(filePath, JSON.stringify(tasks, null, 2) + "\n", { mode: 384 });
3907
+ }
3908
+ function getTasks() {
3909
+ const now = Date.now();
3910
+ const tasks = readTasks().filter((t) => now - new Date(t.submittedAt).getTime() < MAX_AGE_MS);
3911
+ return tasks;
3912
+ }
3913
+ function addTask(task) {
3914
+ const tasks = [task, ...getTasks().filter((t) => t.id !== task.id)].slice(0, MAX_TASKS);
3915
+ writeTasks(tasks);
3916
+ }
3917
+ function updateTaskStatus(id, status2) {
3918
+ const tasks = readTasks();
3919
+ const task = tasks.find((t) => t.id === id);
3920
+ if (task) {
3921
+ task.status = status2;
3922
+ writeTasks(tasks);
3923
+ }
3924
+ }
3925
+ function getLatestTask() {
3926
+ const tasks = getTasks();
3927
+ return tasks[0] ?? null;
3928
+ }
3929
+
3930
+ // src/notifications.ts
3855
3931
  var activeConnection = null;
3856
3932
  function timestamp() {
3857
3933
  return (/* @__PURE__ */ new Date()).toLocaleTimeString("en-GB", { hour12: false });
@@ -3869,6 +3945,9 @@ async function startBackgroundNotifications(baseUrl, accessToken) {
3869
3945
  baseUrl,
3870
3946
  accessToken,
3871
3947
  onMessage: (msg) => {
3948
+ if (client.isMessageType(msg, "response_complete")) {
3949
+ updateTaskStatus(msg.response_id, msg.status);
3950
+ }
3872
3951
  const { text, level } = sdk.formatWsMessage(msg);
3873
3952
  process.stderr.write(`
3874
3953
  ${colorize(level, `[${timestamp()}] ${text}`)}
@@ -3973,7 +4052,7 @@ async function resolveWorkspace(workspaceOpt) {
3973
4052
  try {
3974
4053
  resolveConfig();
3975
4054
  const ctx = await sdk.resolveWorkspace(store, workspaceOpt);
3976
- if (getConfig()?.notifications) {
4055
+ if (getConfig()?.notifications !== false) {
3977
4056
  startBackgroundNotifications(ctx.config.baseUrl, ctx.accessToken).catch(() => {
3978
4057
  });
3979
4058
  }
@@ -4367,7 +4446,7 @@ function registerDocsCommand(program2) {
4367
4446
  );
4368
4447
  }
4369
4448
  function registerUploadCommand(program2) {
4370
- program2.command("upload <paths...>").description("Upload files, directories, or zip archives to the active workspace").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").option("-W, --watch", "Watch document processing progress after upload").action(
4449
+ program2.command("add <paths...>").alias("upload").description("Add files, directories, or zip archives to the active workspace").option("-w, --workspace <id>", "Workspace ID (defaults to selected workspace)").option("-W, --watch", "Watch document processing progress after upload").option("--no-watch", "Skip watching document processing").action(
4371
4450
  (paths, opts) => runAction(async () => {
4372
4451
  for (const p of paths) {
4373
4452
  if (!fs__default.default.existsSync(p)) {
@@ -4426,7 +4505,8 @@ function registerUploadCommand(program2) {
4426
4505
  }
4427
4506
  }
4428
4507
  const isInteractive = process.stdout.isTTY === true;
4429
- const shouldWatch = opts.watch === true || paths.length === 1 && isInteractive;
4508
+ const watchPref = getConfig()?.watch !== false;
4509
+ const shouldWatch = opts.watch === false ? false : opts.watch === true || watchPref && isInteractive;
4430
4510
  if (shouldWatch && uploadedDocs.size > 0) {
4431
4511
  const pending = new Set(uploadedDocs.keys());
4432
4512
  const failed = /* @__PURE__ */ new Map();
@@ -4524,22 +4604,55 @@ function registerDownloadCommand(program2) {
4524
4604
  );
4525
4605
  }
4526
4606
  function registerAskCommand(program2) {
4527
- 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(
4607
+ 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(
4528
4608
  (words, opts) => runAction(async () => {
4529
4609
  const question = words.join(" ");
4530
4610
  const { arbi, accessToken, workspaceKeyHeader, workspaceId, config } = await resolveWorkspace(opts.workspace);
4531
- const session = getChatSession();
4532
- const workspaceChanged = session.lastMessageExtId && session.workspaceId && session.workspaceId !== workspaceId;
4533
4611
  let previousResponseId = null;
4534
- if (opts.new) {
4535
- clearChatSession();
4536
- } else if (workspaceChanged) {
4612
+ if (opts.continue) {
4613
+ previousResponseId = opts.continue;
4614
+ } else if (opts.new) {
4537
4615
  clearChatSession();
4538
- } else if (session.lastMessageExtId) {
4539
- previousResponseId = session.lastMessageExtId;
4616
+ } else {
4617
+ const session = getChatSession();
4618
+ const workspaceChanged = session.lastMessageExtId && session.workspaceId && session.workspaceId !== workspaceId;
4619
+ if (workspaceChanged) {
4620
+ clearChatSession();
4621
+ } else if (session.lastMessageExtId) {
4622
+ previousResponseId = session.lastMessageExtId;
4623
+ }
4540
4624
  }
4541
4625
  const docs = await sdk.documents.listDocuments(arbi);
4542
4626
  const docIds = docs.map((d) => d.external_id);
4627
+ if (opts.background) {
4628
+ const result2 = await sdk.responses.submitBackgroundQuery({
4629
+ baseUrl: config.baseUrl,
4630
+ accessToken,
4631
+ workspaceKeyHeader,
4632
+ workspaceId,
4633
+ question,
4634
+ docIds,
4635
+ previousResponseId,
4636
+ model: opts.config
4637
+ });
4638
+ addTask({
4639
+ id: result2.id,
4640
+ question: question.slice(0, 200),
4641
+ workspaceId,
4642
+ submittedAt: (/* @__PURE__ */ new Date()).toISOString(),
4643
+ status: "queued",
4644
+ model: result2.model
4645
+ });
4646
+ if (opts.json) {
4647
+ console.log(JSON.stringify({ id: result2.id, status: result2.status }));
4648
+ } else {
4649
+ console.log(`Task queued: ${chalk2__default.default.cyan(result2.id)}`);
4650
+ console.log(
4651
+ chalk2__default.default.dim("Use `arbi task status` or `arbi task result` to check progress.")
4652
+ );
4653
+ }
4654
+ return;
4655
+ }
4543
4656
  let res;
4544
4657
  try {
4545
4658
  res = await sdk.assistant.queryAssistant({
@@ -4567,19 +4680,47 @@ function registerAskCommand(program2) {
4567
4680
  model: opts.config
4568
4681
  });
4569
4682
  }
4683
+ const verbose = opts.quiet === true ? false : getConfig()?.verbose !== false;
4684
+ let elapsedTime = null;
4570
4685
  const result = await sdk.streamSSE(res, {
4571
4686
  onToken: (content) => process.stdout.write(content),
4572
4687
  onAgentStep: (data) => {
4573
- if (opts.verbose) {
4688
+ if (verbose) {
4574
4689
  const label2 = sdk.formatAgentStepLabel(data);
4575
4690
  if (label2) console.error(chalk2__default.default.dim(`
4576
4691
  [agent] ${label2}`));
4577
4692
  }
4578
4693
  },
4694
+ onElapsedTime: (t) => {
4695
+ elapsedTime = t;
4696
+ },
4579
4697
  onError: (message) => console.error(chalk2__default.default.red(`
4580
4698
  Error: ${message}`))
4581
4699
  });
4582
4700
  process.stdout.write("\n");
4701
+ const parts = [];
4702
+ if (result.agentSteps.length > 0) {
4703
+ let stepLabel = `${result.agentSteps.length} step${result.agentSteps.length === 1 ? "" : "s"}`;
4704
+ if (result.toolCallCount > 0) {
4705
+ stepLabel += ` (${result.toolCallCount} tool call${result.toolCallCount === 1 ? "" : "s"})`;
4706
+ }
4707
+ parts.push(stepLabel);
4708
+ }
4709
+ if (result.usage) {
4710
+ parts.push(`${result.usage.total_tokens.toLocaleString()} tokens`);
4711
+ }
4712
+ if (result.context && result.context.context_window > 0) {
4713
+ const used = result.context.all_llm_calls?.last_input_tokens ?? result.context.total_input;
4714
+ parts.push(
4715
+ `${used.toLocaleString()}/${result.context.context_window.toLocaleString()} context`
4716
+ );
4717
+ }
4718
+ if (elapsedTime != null) {
4719
+ parts.push(`${elapsedTime.toFixed(1)}s`);
4720
+ }
4721
+ if (parts.length > 0) {
4722
+ console.error(chalk2__default.default.dim(`[${parts.join(" \xB7 ")}]`));
4723
+ }
4583
4724
  if (result.assistantMessageExtId) {
4584
4725
  const updates = {
4585
4726
  lastMessageExtId: result.assistantMessageExtId,
@@ -5711,6 +5852,103 @@ function registerAgentCreateCommand(program2) {
5711
5852
  }
5712
5853
  );
5713
5854
  }
5855
+ function formatAge(isoDate) {
5856
+ const ms = Date.now() - new Date(isoDate).getTime();
5857
+ if (ms < 6e4) return `${Math.round(ms / 1e3)}s`;
5858
+ if (ms < 36e5) return `${Math.round(ms / 6e4)}m`;
5859
+ if (ms < 864e5) return `${Math.round(ms / 36e5)}h`;
5860
+ return `${Math.round(ms / 864e5)}d`;
5861
+ }
5862
+ function resolveTaskId(taskIdArg) {
5863
+ if (taskIdArg) return taskIdArg;
5864
+ const latest = getLatestTask();
5865
+ if (!latest) {
5866
+ console.error(chalk2__default.default.red('No tasks found. Submit one with: arbi ask -b "your question"'));
5867
+ process.exit(1);
5868
+ }
5869
+ return latest.id;
5870
+ }
5871
+ function statusColor(s) {
5872
+ if (s === "completed") return chalk2__default.default.green(s);
5873
+ if (s === "failed") return chalk2__default.default.red(s);
5874
+ if (s === "queued" || s === "in_progress") return chalk2__default.default.yellow(s);
5875
+ return s;
5876
+ }
5877
+ function registerTaskCommand(program2) {
5878
+ const task = program2.command("task").description("Manage background tasks");
5879
+ task.action(async (_opts, cmd) => {
5880
+ await cmd.commands.find((c) => c.name() === "list").parseAsync([], { from: "user" });
5881
+ });
5882
+ task.command("list").description("List background tasks").action(
5883
+ () => runAction(async () => {
5884
+ const tasks = getTasks();
5885
+ if (tasks.length === 0) {
5886
+ console.log('No tasks. Submit one with: arbi ask -b "your question"');
5887
+ return;
5888
+ }
5889
+ printTable(
5890
+ [
5891
+ { header: "ID", width: 20, value: (r) => r.id },
5892
+ { header: "STATUS", width: 14, value: (r) => statusColor(r.status) },
5893
+ { header: "QUESTION", width: 42, value: (r) => r.question },
5894
+ { header: "AGE", width: 6, value: (r) => formatAge(r.submittedAt) }
5895
+ ],
5896
+ tasks
5897
+ );
5898
+ })()
5899
+ );
5900
+ 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(
5901
+ (taskId, opts) => runAction(async () => {
5902
+ const id = resolveTaskId(taskId);
5903
+ const { accessToken, workspaceKeyHeader, config } = await resolveWorkspace(opts?.workspace);
5904
+ const result = await sdk.responses.getResponse(
5905
+ { baseUrl: config.baseUrl, accessToken, workspaceKeyHeader },
5906
+ id
5907
+ );
5908
+ if (result.status === "completed" || result.status === "failed") {
5909
+ updateTaskStatus(id, result.status);
5910
+ }
5911
+ if (opts?.json) {
5912
+ console.log(JSON.stringify(result, null, 2));
5913
+ } else {
5914
+ console.log(`${chalk2__default.default.bold("ID:")} ${result.id}`);
5915
+ console.log(`${chalk2__default.default.bold("Status:")} ${statusColor(result.status)}`);
5916
+ if (result.model) console.log(`${chalk2__default.default.bold("Model:")} ${result.model}`);
5917
+ if (result.usage) {
5918
+ console.log(`${chalk2__default.default.bold("Tokens:")} ${result.usage.total_tokens.toLocaleString()}`);
5919
+ }
5920
+ }
5921
+ })()
5922
+ );
5923
+ 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(
5924
+ (taskId, opts) => runAction(async () => {
5925
+ const id = resolveTaskId(taskId);
5926
+ const { accessToken, workspaceKeyHeader, config } = await resolveWorkspace(opts?.workspace);
5927
+ const result = await sdk.responses.getResponse(
5928
+ { baseUrl: config.baseUrl, accessToken, workspaceKeyHeader },
5929
+ id
5930
+ );
5931
+ if (result.status === "completed" || result.status === "failed") {
5932
+ updateTaskStatus(id, result.status);
5933
+ }
5934
+ if (opts?.json) {
5935
+ console.log(JSON.stringify(result, null, 2));
5936
+ return;
5937
+ }
5938
+ if (result.status !== "completed") {
5939
+ console.error(
5940
+ chalk2__default.default.yellow(`Task is ${result.status}. Use \`arbi task status\` to check progress.`)
5941
+ );
5942
+ process.exit(1);
5943
+ }
5944
+ const text = sdk.responses.extractResponseText(result);
5945
+ process.stdout.write(text + "\n");
5946
+ if (result.usage) {
5947
+ console.error(chalk2__default.default.dim(`[${result.usage.total_tokens.toLocaleString()} tokens]`));
5948
+ }
5949
+ })()
5950
+ );
5951
+ }
5714
5952
 
5715
5953
  // src/index.ts
5716
5954
  console.debug = () => {
@@ -5721,7 +5959,7 @@ console.info = (...args) => {
5721
5959
  _origInfo(...args);
5722
5960
  };
5723
5961
  var program = new commander.Command();
5724
- program.name("arbi").description("ARBI CLI \u2014 interact with ARBI from the terminal").version("0.3.13");
5962
+ program.name("arbi").description("ARBI CLI \u2014 interact with ARBI from the terminal").version("0.3.14");
5725
5963
  registerConfigCommand(program);
5726
5964
  registerLoginCommand(program);
5727
5965
  registerRegisterCommand(program);
@@ -5745,6 +5983,7 @@ registerTuiCommand(program);
5745
5983
  registerUpdateCommand(program);
5746
5984
  registerQuickstartCommand(program);
5747
5985
  registerAgentCreateCommand(program);
5986
+ registerTaskCommand(program);
5748
5987
  program.parse();
5749
5988
  //# sourceMappingURL=index.js.map
5750
5989
  //# sourceMappingURL=index.js.map