@arbidocs/sdk 0.3.11 → 0.3.13

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
@@ -1,14 +1,14 @@
1
1
  'use strict';
2
2
 
3
3
  var fs = require('fs');
4
- var path = require('path');
4
+ var path2 = require('path');
5
5
  var os = require('os');
6
6
  var client = require('@arbidocs/client');
7
7
 
8
8
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
9
 
10
10
  var fs__default = /*#__PURE__*/_interopDefault(fs);
11
- var path__default = /*#__PURE__*/_interopDefault(path);
11
+ var path2__default = /*#__PURE__*/_interopDefault(path2);
12
12
  var os__default = /*#__PURE__*/_interopDefault(os);
13
13
 
14
14
  var __defProp = Object.defineProperty;
@@ -44,7 +44,36 @@ function requireOk(result, message) {
44
44
  }
45
45
  }
46
46
  function getErrorMessage(err) {
47
- return err instanceof Error ? err.message : String(err);
47
+ if (!(err instanceof Error)) return String(err);
48
+ const rootCause = getDeepestCause(err);
49
+ if (rootCause !== err) {
50
+ const rootMsg = rootCause.message || String(rootCause);
51
+ if (err.message && !err.message.includes(rootMsg)) {
52
+ return `${err.message}: ${rootMsg}`;
53
+ }
54
+ }
55
+ return err.message;
56
+ }
57
+ function getDeepestCause(err) {
58
+ let current = err;
59
+ const seen = /* @__PURE__ */ new Set();
60
+ while (current.cause instanceof Error && !seen.has(current.cause)) {
61
+ seen.add(current);
62
+ current = current.cause;
63
+ }
64
+ return current;
65
+ }
66
+ function getErrorCode(err) {
67
+ if (!(err instanceof Error)) return void 0;
68
+ let current = err;
69
+ const seen = /* @__PURE__ */ new Set();
70
+ while (current && !seen.has(current)) {
71
+ seen.add(current);
72
+ const code = current.code;
73
+ if (typeof code === "string") return code;
74
+ current = current.cause instanceof Error ? current.cause : void 0;
75
+ }
76
+ return void 0;
48
77
  }
49
78
 
50
79
  // src/fetch.ts
@@ -101,10 +130,10 @@ var FileConfigStore = class {
101
130
  credentialsFile;
102
131
  sessionFile;
103
132
  constructor(configDir) {
104
- this.configDir = configDir ?? process.env.ARBI_CONFIG_DIR ?? path__default.default.join(os__default.default.homedir(), ".arbi");
105
- this.configFile = path__default.default.join(this.configDir, "config.json");
106
- this.credentialsFile = path__default.default.join(this.configDir, "credentials.json");
107
- this.sessionFile = path__default.default.join(this.configDir, "session.json");
133
+ this.configDir = configDir ?? process.env.ARBI_CONFIG_DIR ?? path2__default.default.join(os__default.default.homedir(), ".arbi");
134
+ this.configFile = path2__default.default.join(this.configDir, "config.json");
135
+ this.credentialsFile = path2__default.default.join(this.configDir, "credentials.json");
136
+ this.sessionFile = path2__default.default.join(this.configDir, "session.json");
108
137
  }
109
138
  ensureConfigDir() {
110
139
  if (!fs__default.default.existsSync(this.configDir)) {
@@ -175,6 +204,77 @@ var FileConfigStore = class {
175
204
  clearChatSession() {
176
205
  this.saveChatSession({ ...DEFAULT_SESSION });
177
206
  }
207
+ /**
208
+ * Try to resolve config from multiple sources, in priority order:
209
+ *
210
+ * 1. Existing `~/.arbi/config.json` (highest priority)
211
+ * 2. `ARBI_SERVER_URL` environment variable
212
+ * 3. `.env` file in `searchDir` → read `VITE_DEPLOYMENT_DOMAIN`
213
+ * 4. `public/config.json` in `searchDir` → read `deployment.domain`
214
+ * 5. Default to `https://localhost`
215
+ *
216
+ * Returns `{ config, source }` where source describes where the config came from.
217
+ * Saves auto-detected config to disk so subsequent calls use the fast path.
218
+ */
219
+ resolveConfigWithFallbacks(searchDir) {
220
+ const existing = this.getConfig();
221
+ if (existing?.baseUrl) {
222
+ return { config: existing, source: "config" };
223
+ }
224
+ const envUrl = process.env.ARBI_SERVER_URL;
225
+ if (envUrl) {
226
+ const domain = new URL(envUrl).hostname;
227
+ const config2 = { baseUrl: envUrl.replace(/\/$/, ""), deploymentDomain: domain };
228
+ this.saveConfig(config2);
229
+ return { config: config2, source: "ARBI_SERVER_URL env var" };
230
+ }
231
+ const dir = searchDir || process.cwd();
232
+ const dotenvConfig = this.readDotEnvDomain(path2__default.default.join(dir, ".env"));
233
+ if (dotenvConfig) {
234
+ this.saveConfig(dotenvConfig);
235
+ return { config: dotenvConfig, source: ".env file" };
236
+ }
237
+ const publicConfig = this.readPublicConfigDomain(path2__default.default.join(dir, "public", "config.json"));
238
+ if (publicConfig) {
239
+ this.saveConfig(publicConfig);
240
+ return { config: publicConfig, source: "public/config.json" };
241
+ }
242
+ const config = { baseUrl: "https://localhost", deploymentDomain: "localhost" };
243
+ this.saveConfig(config);
244
+ return { config, source: "default (https://localhost)" };
245
+ }
246
+ /**
247
+ * Read VITE_DEPLOYMENT_DOMAIN from a .env file.
248
+ */
249
+ readDotEnvDomain(filePath) {
250
+ try {
251
+ const content = fs__default.default.readFileSync(filePath, "utf-8");
252
+ const match = content.match(/^VITE_DEPLOYMENT_DOMAIN\s*=\s*(.+)$/m);
253
+ if (match) {
254
+ const domain = match[1].trim().replace(/^["']|["']$/g, "");
255
+ if (domain) {
256
+ return { baseUrl: `https://${domain}`, deploymentDomain: domain };
257
+ }
258
+ }
259
+ } catch {
260
+ }
261
+ return null;
262
+ }
263
+ /**
264
+ * Read deployment.domain from a public/config.json file.
265
+ */
266
+ readPublicConfigDomain(filePath) {
267
+ try {
268
+ const content = fs__default.default.readFileSync(filePath, "utf-8");
269
+ const json = JSON.parse(content);
270
+ const domain = json?.deployment?.domain;
271
+ if (domain) {
272
+ return { baseUrl: `https://${domain}`, deploymentDomain: domain };
273
+ }
274
+ } catch {
275
+ }
276
+ return null;
277
+ }
178
278
  };
179
279
  function formatWorkspaceChoices(wsList) {
180
280
  return wsList.map((ws) => {
@@ -200,7 +300,11 @@ async function createAuthenticatedClient(config, creds, store) {
200
300
  });
201
301
  store.saveCredentials({
202
302
  ...creds,
203
- serverSessionKeyBase64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey)
303
+ serverSessionKeyBase64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey),
304
+ accessToken: void 0,
305
+ workspaceKeyHeader: void 0,
306
+ workspaceId: void 0,
307
+ tokenTimestamp: void 0
204
308
  });
205
309
  return { arbi, loginResult };
206
310
  }
@@ -215,7 +319,12 @@ async function performPasswordLogin(config, email, password, store) {
215
319
  store.saveCredentials({
216
320
  email,
217
321
  signingPrivateKeyBase64: arbi.crypto.bytesToBase64(loginResult.signingPrivateKey),
218
- serverSessionKeyBase64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey)
322
+ serverSessionKeyBase64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey),
323
+ // Clear any cached workspace tokens — new session key invalidates them
324
+ accessToken: void 0,
325
+ workspaceKeyHeader: void 0,
326
+ workspaceId: void 0,
327
+ tokenTimestamp: void 0
219
328
  });
220
329
  return { arbi, loginResult, config };
221
330
  }
@@ -278,6 +387,10 @@ async function resolveAuth(store) {
278
387
  const { arbi, loginResult } = await createAuthenticatedClient(config, creds, store);
279
388
  return { arbi, loginResult, config };
280
389
  }
390
+ var TOKEN_MAX_AGE_MS = 50 * 60 * 1e3;
391
+ function isCachedTokenValid(creds, workspaceId) {
392
+ return !!(creds.accessToken && creds.workspaceKeyHeader && creds.workspaceId === workspaceId && creds.tokenTimestamp && Date.now() - new Date(creds.tokenTimestamp).getTime() < TOKEN_MAX_AGE_MS);
393
+ }
281
394
  async function resolveWorkspace(store, workspaceOpt) {
282
395
  const config = store.requireConfig();
283
396
  const creds = store.requireCredentials();
@@ -285,6 +398,32 @@ async function resolveWorkspace(store, workspaceOpt) {
285
398
  if (!workspaceId) {
286
399
  throw new ArbiError("No workspace selected. Run: arbi workspace select <id>");
287
400
  }
401
+ if (isCachedTokenValid(creds, workspaceId)) {
402
+ const arbi2 = client.createArbiClient({
403
+ baseUrl: config.baseUrl,
404
+ deploymentDomain: config.deploymentDomain,
405
+ credentials: "omit"
406
+ });
407
+ await arbi2.crypto.initSodium();
408
+ arbi2.session.setSelectedWorkspace(workspaceId);
409
+ arbi2.session.setAccessToken(creds.accessToken);
410
+ arbi2.session.setCachedWorkspaceHeader(workspaceId, creds.workspaceKeyHeader);
411
+ const signingPrivateKey = client.base64ToBytes(creds.signingPrivateKeyBase64);
412
+ const serverSessionKey = client.base64ToBytes(creds.serverSessionKeyBase64);
413
+ const loginResult2 = {
414
+ accessToken: creds.accessToken,
415
+ signingPrivateKey,
416
+ serverSessionKey
417
+ };
418
+ return {
419
+ arbi: arbi2,
420
+ loginResult: loginResult2,
421
+ config,
422
+ workspaceId,
423
+ accessToken: creds.accessToken,
424
+ workspaceKeyHeader: creds.workspaceKeyHeader
425
+ };
426
+ }
288
427
  const { arbi, loginResult } = await createAuthenticatedClient(config, creds, store);
289
428
  await selectWorkspaceById(
290
429
  arbi,
@@ -297,10 +436,57 @@ async function resolveWorkspace(store, workspaceOpt) {
297
436
  if (!accessToken || !workspaceKeyHeader) {
298
437
  throw new ArbiError("Authentication error \u2014 missing token or workspace key");
299
438
  }
439
+ store.saveCredentials({
440
+ ...store.requireCredentials(),
441
+ accessToken,
442
+ workspaceKeyHeader,
443
+ workspaceId,
444
+ tokenTimestamp: (/* @__PURE__ */ new Date()).toISOString()
445
+ });
300
446
  return { arbi, loginResult, config, workspaceId, accessToken, workspaceKeyHeader };
301
447
  }
302
448
 
303
449
  // src/sse.ts
450
+ var TOOL_LABELS = {
451
+ search_documents: "Searching documents",
452
+ get_document_passages: "Reading document",
453
+ get_table_of_contents: "Getting table of contents",
454
+ view_document_pages: "Viewing document pages",
455
+ get_full_document: "Reading full document",
456
+ web_search: "Searching the web",
457
+ read_url: "Reading web pages",
458
+ ask_user: "Asking user",
459
+ compaction: "Compacting conversation",
460
+ personal_agent: "Running agent",
461
+ create_artifact: "Creating artifact",
462
+ create_plan: "Creating plan",
463
+ save_skill: "Saving skill",
464
+ run_code: "Running code"
465
+ };
466
+ var LIFECYCLE_LABELS = {
467
+ evaluation: "Evaluating results",
468
+ answering: "Writing answer",
469
+ reviewing: "Reviewing answer",
470
+ planning: "Planning",
471
+ tool_progress: "Working"
472
+ };
473
+ function formatAgentStepLabel(step) {
474
+ if (step.focus) return step.focus;
475
+ const detail = step.detail;
476
+ if (step.step === "tool_progress" && detail && detail.length > 0) {
477
+ const toolName = detail[0].tool;
478
+ const label = toolName && TOOL_LABELS[toolName] || LIFECYCLE_LABELS.tool_progress;
479
+ const message = detail[0].message;
480
+ return message ? `${label}: ${message}` : label;
481
+ }
482
+ if (step.step) {
483
+ return LIFECYCLE_LABELS[step.step] || step.step;
484
+ }
485
+ if (detail && detail.length > 0 && detail[0].tool) {
486
+ return TOOL_LABELS[detail[0].tool] || detail[0].tool;
487
+ }
488
+ return "";
489
+ }
304
490
  function parseSSEEvents(chunk, buffer) {
305
491
  const combined = buffer + chunk;
306
492
  const events = [];
@@ -388,8 +574,8 @@ async function streamSSE(response, callbacks = {}) {
388
574
  // ARBI-specific events (dot-prefixed from server)
389
575
  "arbi.agent_step": (raw) => {
390
576
  const data = JSON.parse(raw);
391
- const focus = data.focus || data.step || "";
392
- if (focus) agentSteps.push(focus);
577
+ const label = formatAgentStepLabel(data);
578
+ if (label) agentSteps.push(label);
393
579
  callbacks.onAgentStep?.(data);
394
580
  if (data.t != null) callbacks.onElapsedTime?.(data.t);
395
581
  },
@@ -667,16 +853,34 @@ function formatUserName(user) {
667
853
  // src/operations/documents.ts
668
854
  var documents_exports = {};
669
855
  __export(documents_exports, {
856
+ SUPPORTED_EXTENSIONS: () => SUPPORTED_EXTENSIONS,
670
857
  deleteDocuments: () => deleteDocuments,
671
858
  downloadDocument: () => downloadDocument,
672
859
  getDocuments: () => getDocuments,
673
860
  getParsedContent: () => getParsedContent,
674
861
  listDocuments: () => listDocuments,
862
+ sanitizeFolderPath: () => sanitizeFolderPath,
675
863
  updateDocuments: () => updateDocuments,
676
864
  uploadFile: () => uploadFile,
677
- uploadLocalFile: () => uploadLocalFile,
865
+ uploadFiles: () => uploadFiles,
678
866
  uploadUrl: () => uploadUrl
679
867
  });
868
+ var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
869
+ ".pdf",
870
+ ".txt",
871
+ ".md",
872
+ ".html",
873
+ ".doc",
874
+ ".docx",
875
+ ".rtf",
876
+ ".ppt",
877
+ ".pptx",
878
+ ".xls",
879
+ ".xlsx"
880
+ ]);
881
+ function sanitizeFolderPath(folderPath) {
882
+ return folderPath.replace(/[^a-zA-Z0-9_\-/]/g, "_").replace(/_{2,}/g, "_");
883
+ }
680
884
  async function listDocuments(arbi) {
681
885
  return requireData(await arbi.fetch.GET("/v1/document/list"), "Failed to fetch documents");
682
886
  }
@@ -715,22 +919,31 @@ async function getParsedContent(auth, docId, stage) {
715
919
  });
716
920
  return res.json();
717
921
  }
718
- async function uploadFile(auth, workspaceId, fileData, fileName) {
922
+ async function uploadFile(auth, workspaceId, fileData, fileName, options) {
719
923
  const formData = new FormData();
720
924
  formData.append("files", fileData, fileName);
925
+ const params = new URLSearchParams({ workspace_ext_id: workspaceId });
926
+ if (options?.folder) params.set("folder", sanitizeFolderPath(options.folder));
721
927
  const res = await authenticatedFetch({
722
928
  ...auth,
723
- path: `/v1/document/upload?workspace_ext_id=${workspaceId}`,
929
+ path: `/v1/document/upload?${params.toString()}`,
724
930
  method: "POST",
725
931
  body: formData
726
932
  });
727
933
  return res.json();
728
934
  }
729
- async function uploadLocalFile(auth, workspaceId, filePath) {
730
- const fileBuffer = fs__default.default.readFileSync(filePath);
731
- const fileName = path__default.default.basename(filePath);
732
- const result = await uploadFile(auth, workspaceId, new Blob([fileBuffer]), fileName);
733
- return { ...result, fileName };
935
+ async function uploadFiles(auth, workspaceId, files, options) {
936
+ const formData = new FormData();
937
+ for (const f of files) formData.append("files", f.data, f.name);
938
+ const params = new URLSearchParams({ workspace_ext_id: workspaceId });
939
+ if (options?.folder) params.set("folder", sanitizeFolderPath(options.folder));
940
+ const res = await authenticatedFetch({
941
+ ...auth,
942
+ path: `/v1/document/upload?${params.toString()}`,
943
+ method: "POST",
944
+ body: formData
945
+ });
946
+ return res.json();
734
947
  }
735
948
  async function downloadDocument(auth, docId) {
736
949
  return authenticatedFetch({
@@ -930,6 +1143,8 @@ async function retrieve(options) {
930
1143
  input: query,
931
1144
  workspace_ext_id: workspaceId,
932
1145
  stream: false,
1146
+ background: false,
1147
+ store: true,
933
1148
  tools,
934
1149
  ...model ? { model } : {}
935
1150
  };
@@ -945,6 +1160,8 @@ async function queryAssistant(options) {
945
1160
  input: question,
946
1161
  workspace_ext_id: workspaceId,
947
1162
  stream: true,
1163
+ background: false,
1164
+ store: true,
948
1165
  tools: {
949
1166
  retrieval_chunk: buildRetrievalChunkTool(docIds),
950
1167
  retrieval_full_context: buildRetrievalFullContextTool([])
@@ -1404,11 +1621,12 @@ var Arbi = class {
1404
1621
  workspaceId ?? this.requireWorkspace(),
1405
1622
  shared
1406
1623
  ),
1407
- uploadFile: (fileData, fileName, workspaceId) => uploadFile(
1624
+ uploadFile: (fileData, fileName, options) => uploadFile(
1408
1625
  this.getAuthHeaders(),
1409
- workspaceId ?? this.requireWorkspace(),
1626
+ options?.workspaceId ?? this.requireWorkspace(),
1410
1627
  fileData,
1411
- fileName
1628
+ fileName,
1629
+ options?.folder ? { folder: options.folder } : void 0
1412
1630
  ),
1413
1631
  download: (docId) => downloadDocument(this.getAuthHeaders(), docId),
1414
1632
  getParsedContent: (docId, stage) => getParsedContent(this.getAuthHeaders(), docId, stage)
@@ -1550,10 +1768,129 @@ var Arbi = class {
1550
1768
  }
1551
1769
  };
1552
1770
 
1771
+ // src/operations/documents-node.ts
1772
+ var documents_node_exports = {};
1773
+ __export(documents_node_exports, {
1774
+ uploadDirectory: () => uploadDirectory,
1775
+ uploadLocalFile: () => uploadLocalFile,
1776
+ uploadZip: () => uploadZip
1777
+ });
1778
+ function collectFiles(dirPath, baseDir) {
1779
+ const root = baseDir ?? dirPath;
1780
+ const results = [];
1781
+ for (const entry of fs__default.default.readdirSync(dirPath, { withFileTypes: true })) {
1782
+ const fullPath = path2__default.default.join(dirPath, entry.name);
1783
+ if (entry.isDirectory()) {
1784
+ results.push(...collectFiles(fullPath, root));
1785
+ } else if (entry.isFile()) {
1786
+ const ext = path2__default.default.extname(entry.name).toLowerCase();
1787
+ if (SUPPORTED_EXTENSIONS.has(ext)) {
1788
+ results.push({ absolutePath: fullPath, relativePath: path2__default.default.relative(root, fullPath) });
1789
+ }
1790
+ }
1791
+ }
1792
+ return results;
1793
+ }
1794
+ async function uploadLocalFile(auth, workspaceId, filePath, options) {
1795
+ const fileBuffer = fs__default.default.readFileSync(filePath);
1796
+ const fileName = path2__default.default.basename(filePath);
1797
+ const result = await uploadFile(auth, workspaceId, new Blob([fileBuffer]), fileName, options);
1798
+ return { ...result, fileName };
1799
+ }
1800
+ async function uploadDirectory(auth, workspaceId, dirPath) {
1801
+ const resolvedDir = path2__default.default.resolve(dirPath);
1802
+ const dirName = path2__default.default.basename(resolvedDir);
1803
+ const entries = collectFiles(resolvedDir);
1804
+ if (entries.length === 0) {
1805
+ return { doc_ext_ids: [], duplicates: [], folders: /* @__PURE__ */ new Map() };
1806
+ }
1807
+ const groups = /* @__PURE__ */ new Map();
1808
+ for (const entry of entries) {
1809
+ const relDir = path2__default.default.dirname(entry.relativePath);
1810
+ const folder = relDir === "." ? dirName : `${dirName}/${relDir}`;
1811
+ if (!groups.has(folder)) groups.set(folder, []);
1812
+ groups.get(folder).push({ absolutePath: entry.absolutePath, name: path2__default.default.basename(entry.relativePath) });
1813
+ }
1814
+ const allDocIds = [];
1815
+ const allDuplicates = [];
1816
+ const folders = /* @__PURE__ */ new Map();
1817
+ for (const [folder, files] of groups) {
1818
+ const blobs = files.map((f) => ({
1819
+ data: new Blob([fs__default.default.readFileSync(f.absolutePath)]),
1820
+ name: f.name
1821
+ }));
1822
+ const result = await uploadFiles(auth, workspaceId, blobs, { folder });
1823
+ const dups = result.duplicates ?? [];
1824
+ allDocIds.push(...result.doc_ext_ids);
1825
+ allDuplicates.push(...dups);
1826
+ folders.set(folder, {
1827
+ fileCount: files.length,
1828
+ doc_ext_ids: result.doc_ext_ids,
1829
+ duplicates: dups
1830
+ });
1831
+ }
1832
+ return { doc_ext_ids: allDocIds, duplicates: allDuplicates, folders };
1833
+ }
1834
+ async function uploadZip(auth, workspaceId, zipPath) {
1835
+ const JSZip = (await import('jszip')).default;
1836
+ const zipBuffer = fs__default.default.readFileSync(zipPath);
1837
+ const zip = await JSZip.loadAsync(zipBuffer);
1838
+ const zipBaseName = path2__default.default.basename(zipPath).replace(/\.zip$/i, "");
1839
+ const entries = [];
1840
+ zip.forEach((relativePath, zipEntry) => {
1841
+ if (zipEntry.dir) return;
1842
+ const ext = path2__default.default.extname(relativePath).toLowerCase();
1843
+ if (SUPPORTED_EXTENSIONS.has(ext)) {
1844
+ entries.push({ zipEntryPath: relativePath, zipEntry });
1845
+ }
1846
+ });
1847
+ if (entries.length === 0) {
1848
+ return { doc_ext_ids: [], duplicates: [], folders: /* @__PURE__ */ new Map() };
1849
+ }
1850
+ const firstParts = new Set(entries.map((e) => e.zipEntryPath.split("/")[0]));
1851
+ const hasSingleRoot = firstParts.size === 1 && entries.every((e) => e.zipEntryPath.includes("/"));
1852
+ const groups = /* @__PURE__ */ new Map();
1853
+ for (const entry of entries) {
1854
+ const data = await entry.zipEntry.async("uint8array");
1855
+ const fileName = path2__default.default.basename(entry.zipEntryPath);
1856
+ const relDir = path2__default.default.dirname(entry.zipEntryPath);
1857
+ let folder;
1858
+ if (hasSingleRoot) {
1859
+ folder = relDir === "." ? zipBaseName : relDir;
1860
+ } else {
1861
+ folder = relDir === "." ? zipBaseName : `${zipBaseName}/${relDir}`;
1862
+ }
1863
+ folder = sanitizeFolderPath(folder);
1864
+ if (!groups.has(folder)) groups.set(folder, []);
1865
+ groups.get(folder).push({ name: fileName, data });
1866
+ }
1867
+ const allDocIds = [];
1868
+ const allDuplicates = [];
1869
+ const folders = /* @__PURE__ */ new Map();
1870
+ for (const [folder, files] of groups) {
1871
+ const blobs = files.map((f) => ({
1872
+ data: new Blob([f.data]),
1873
+ name: f.name
1874
+ }));
1875
+ const result = await uploadFiles(auth, workspaceId, blobs, { folder });
1876
+ const dups = result.duplicates ?? [];
1877
+ allDocIds.push(...result.doc_ext_ids);
1878
+ allDuplicates.push(...dups);
1879
+ folders.set(folder, {
1880
+ fileCount: files.length,
1881
+ doc_ext_ids: result.doc_ext_ids,
1882
+ duplicates: dups
1883
+ });
1884
+ }
1885
+ return { doc_ext_ids: allDocIds, duplicates: allDuplicates, folders };
1886
+ }
1887
+
1553
1888
  exports.Arbi = Arbi;
1554
1889
  exports.ArbiApiError = ArbiApiError;
1555
1890
  exports.ArbiError = ArbiError;
1556
1891
  exports.FileConfigStore = FileConfigStore;
1892
+ exports.LIFECYCLE_LABELS = LIFECYCLE_LABELS;
1893
+ exports.TOOL_LABELS = TOOL_LABELS;
1557
1894
  exports.agentconfig = agentconfig_exports;
1558
1895
  exports.assistant = assistant_exports;
1559
1896
  exports.authenticatedFetch = authenticatedFetch;
@@ -1570,12 +1907,15 @@ exports.createDocumentWaiter = createDocumentWaiter;
1570
1907
  exports.dm = dm_exports;
1571
1908
  exports.doctags = doctags_exports;
1572
1909
  exports.documents = documents_exports;
1910
+ exports.documentsNode = documents_node_exports;
1573
1911
  exports.files = files_exports;
1912
+ exports.formatAgentStepLabel = formatAgentStepLabel;
1574
1913
  exports.formatFileSize = formatFileSize;
1575
1914
  exports.formatUserName = formatUserName;
1576
1915
  exports.formatWorkspaceChoices = formatWorkspaceChoices;
1577
1916
  exports.formatWsMessage = formatWsMessage;
1578
1917
  exports.generateEncryptedWorkspaceKey = generateEncryptedWorkspaceKey;
1918
+ exports.getErrorCode = getErrorCode;
1579
1919
  exports.getErrorMessage = getErrorMessage;
1580
1920
  exports.health = health_exports;
1581
1921
  exports.parseSSEEvents = parseSSEEvents;