@arbidocs/sdk 0.3.65 → 0.3.67

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/browser.cjs CHANGED
@@ -3568,6 +3568,7 @@ async function authenticatedFetch(options) {
3568
3568
  }
3569
3569
 
3570
3570
  // src/auth.ts
3571
+ var TOKEN_MAX_AGE_MS = 50 * 60 * 1e3;
3571
3572
  function formatWorkspaceChoices(wsList) {
3572
3573
  return wsList.map((ws) => {
3573
3574
  const totalDocs = ws.shared_document_count + ws.private_document_count;
@@ -3598,11 +3599,11 @@ async function createAuthenticatedClient(config, creds, store) {
3598
3599
  });
3599
3600
  store.saveCredentials({
3600
3601
  ...creds,
3602
+ userExtId: loginResult.userExtId ?? creds.userExtId,
3601
3603
  serverSessionKeyBase64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey),
3602
3604
  accessToken: void 0,
3603
- sealedWorkspaceKey: void 0,
3604
- workspaceId: void 0,
3605
- tokenTimestamp: void 0
3605
+ tokenTimestamp: void 0,
3606
+ openedWorkspaces: void 0
3606
3607
  });
3607
3608
  return { arbi, loginResult };
3608
3609
  }
@@ -3612,13 +3613,18 @@ async function performPasswordLogin(config, email, password, store) {
3612
3613
  const loginResult = await arbi.auth.login({ email, password });
3613
3614
  store.saveCredentials({
3614
3615
  email,
3616
+ userExtId: loginResult.userExtId,
3615
3617
  signingPrivateKeyBase64: arbi.crypto.bytesToBase64(loginResult.signingPrivateKey),
3616
3618
  serverSessionKeyBase64: arbi.crypto.bytesToBase64(loginResult.serverSessionKey),
3617
- // Clear any cached workspace tokens new session key invalidates them
3619
+ // `parent_ext_id` is set for persistent agent accounts (the user is
3620
+ // an Assistant owned by another user). Persisting it makes the CLI's
3621
+ // `arbi listen` work — it requires this to confirm a real agent
3622
+ // identity. Regular users get `null`, which we store as `undefined`.
3623
+ parentExtId: loginResult.parentExtId ?? void 0,
3624
+ // New session = no workspaces deposited yet.
3618
3625
  accessToken: void 0,
3619
- sealedWorkspaceKey: void 0,
3620
- workspaceId: void 0,
3621
- tokenTimestamp: void 0
3626
+ tokenTimestamp: void 0,
3627
+ openedWorkspaces: void 0
3622
3628
  });
3623
3629
  return { arbi, loginResult, config };
3624
3630
  }
@@ -3634,16 +3640,6 @@ async function selectWorkspace(arbi, workspaceId, wrappedKey, serverSessionKey,
3634
3640
  arbi.session.setSelectedWorkspace(workspaceId);
3635
3641
  return header;
3636
3642
  }
3637
- async function generateEncryptedWorkspaceKey(arbi, wrappedKey, serverSessionKey, signingPrivateKeyBase64) {
3638
- const signingPrivateKey = client.base64ToBytes(signingPrivateKeyBase64);
3639
- const ed25519PublicKey = signingPrivateKey.slice(32, 64);
3640
- const encryptionKeyPair = client.deriveEncryptionKeypairFromSigning({
3641
- publicKey: ed25519PublicKey,
3642
- secretKey: signingPrivateKey
3643
- });
3644
- const workspaceKey = client.sealedBoxDecrypt(wrappedKey, encryptionKeyPair.secretKey);
3645
- return client.sealKeyForSession(workspaceKey, serverSessionKey);
3646
- }
3647
3643
  async function getRawWorkspaceKey(arbi, workspaceId, signingPrivateKeyBase64) {
3648
3644
  const { data: workspaces, error } = await arbi.fetch.GET("/v1/user/workspaces");
3649
3645
  if (error || !workspaces) {
@@ -3661,38 +3657,79 @@ async function getRawWorkspaceKey(arbi, workspaceId, signingPrivateKeyBase64) {
3661
3657
  });
3662
3658
  return client.sealedBoxDecrypt(ws.wrapped_key, encryptionKeyPair.secretKey);
3663
3659
  }
3660
+ async function openWorkspaceEntry(arbi, ws, serverSessionKey, signingPrivateKeyBase64) {
3661
+ if (ws.wrapped_key) {
3662
+ const sealedKey = await selectWorkspace(
3663
+ arbi,
3664
+ ws.external_id,
3665
+ ws.wrapped_key,
3666
+ serverSessionKey,
3667
+ signingPrivateKeyBase64
3668
+ );
3669
+ const { error: error2 } = await arbi.fetch.POST("/v1/workspace/{workspace_ext_id}/open", {
3670
+ params: { path: { workspace_ext_id: ws.external_id } },
3671
+ body: { workspace_key: sealedKey }
3672
+ });
3673
+ if (error2) {
3674
+ throw new ArbiError(`Workspace open failed for ${ws.external_id}: ${JSON.stringify(error2)}`);
3675
+ }
3676
+ return sealedKey;
3677
+ }
3678
+ arbi.session.setSelectedWorkspace(ws.external_id);
3679
+ const { error } = await arbi.fetch.POST("/v1/workspace/{workspace_ext_id}/open", {
3680
+ params: { path: { workspace_ext_id: ws.external_id } },
3681
+ body: {}
3682
+ });
3683
+ if (error) {
3684
+ throw new ArbiError(`Workspace open failed for ${ws.external_id}: ${JSON.stringify(error)}`);
3685
+ }
3686
+ return null;
3687
+ }
3664
3688
  async function selectWorkspaceById(arbi, workspaceId, serverSessionKey, signingPrivateKeyBase64) {
3665
3689
  const { data: workspaces, error } = await arbi.fetch.GET("/v1/user/workspaces");
3666
3690
  if (error || !workspaces) {
3667
3691
  throw new ArbiError("Failed to fetch workspaces");
3668
3692
  }
3669
3693
  const ws = workspaces.find((w2) => w2.external_id === workspaceId);
3670
- if (!ws || !ws.wrapped_key) {
3671
- throw new ArbiError(`Workspace ${workspaceId} not found or has no encryption key`);
3694
+ if (!ws) {
3695
+ throw new ArbiError(`Workspace ${workspaceId} not found`);
3672
3696
  }
3673
- const sealedKey = await selectWorkspace(
3674
- arbi,
3675
- ws.external_id,
3676
- ws.wrapped_key,
3677
- serverSessionKey,
3678
- signingPrivateKeyBase64
3679
- );
3680
- await arbi.fetch.POST("/v1/workspace/{workspace_ext_id}/open", {
3681
- params: { path: { workspace_ext_id: ws.external_id } },
3682
- body: { workspace_key: sealedKey }
3683
- });
3684
- return { external_id: ws.external_id, name: ws.name, wrapped_key: ws.wrapped_key };
3697
+ const sealedKey = await openWorkspaceEntry(arbi, ws, serverSessionKey, signingPrivateKeyBase64);
3698
+ return {
3699
+ external_id: ws.external_id,
3700
+ name: ws.name,
3701
+ wrapped_key: ws.wrapped_key ?? null,
3702
+ sealed_key: sealedKey
3703
+ };
3704
+ }
3705
+ function isSessionAlive(creds) {
3706
+ return !!(creds.accessToken && creds.tokenTimestamp && Date.now() - new Date(creds.tokenTimestamp).getTime() < TOKEN_MAX_AGE_MS);
3707
+ }
3708
+ async function buildAuthFromCache(config, creds, store) {
3709
+ const arbi = client.createArbiClient(buildClientOptions(config, store, creds.email));
3710
+ await arbi.crypto.initSodium();
3711
+ arbi.session.setUser(creds.email, creds.userExtId);
3712
+ arbi.session.setAccessToken(creds.accessToken);
3713
+ const signingPrivateKey = client.base64ToBytes(creds.signingPrivateKeyBase64);
3714
+ const serverSessionKey = client.base64ToBytes(creds.serverSessionKeyBase64);
3715
+ const loginResult = {
3716
+ accessToken: creds.accessToken,
3717
+ userExtId: creds.userExtId,
3718
+ signingPrivateKey,
3719
+ serverSessionKey
3720
+ };
3721
+ return { arbi, loginResult };
3685
3722
  }
3686
3723
  async function resolveAuth(store) {
3687
3724
  const config = store.requireConfig();
3688
3725
  const creds = store.requireCredentials();
3726
+ if (isSessionAlive(creds)) {
3727
+ const { arbi: arbi2, loginResult: loginResult2 } = await buildAuthFromCache(config, creds, store);
3728
+ return { arbi: arbi2, loginResult: loginResult2, config };
3729
+ }
3689
3730
  const { arbi, loginResult } = await createAuthenticatedClient(config, creds, store);
3690
3731
  return { arbi, loginResult, config };
3691
3732
  }
3692
- var TOKEN_MAX_AGE_MS = 50 * 60 * 1e3;
3693
- function isCachedTokenValid(creds, workspaceId) {
3694
- return !!(creds.accessToken && creds.sealedWorkspaceKey && creds.workspaceId === workspaceId && creds.tokenTimestamp && Date.now() - new Date(creds.tokenTimestamp).getTime() < TOKEN_MAX_AGE_MS);
3695
- }
3696
3733
  async function resolveWorkspace(store, workspaceOpt) {
3697
3734
  const config = store.requireConfig();
3698
3735
  const creds = store.requireCredentials();
@@ -3700,53 +3737,52 @@ async function resolveWorkspace(store, workspaceOpt) {
3700
3737
  if (!workspaceId) {
3701
3738
  throw new ArbiError("No workspace selected. Run: arbi workspace select <id>");
3702
3739
  }
3703
- if (isCachedTokenValid(creds, workspaceId)) {
3704
- const arbi2 = client.createArbiClient(buildClientOptions(config, store, creds.email));
3705
- await arbi2.crypto.initSodium();
3706
- arbi2.session.setUser(creds.email);
3740
+ if (isSessionAlive(creds)) {
3741
+ const { arbi: arbi2, loginResult: loginResult2 } = await buildAuthFromCache(config, creds, store);
3707
3742
  arbi2.session.setSelectedWorkspace(workspaceId);
3708
- arbi2.session.setAccessToken(creds.accessToken);
3709
- const signingPrivateKey = client.base64ToBytes(creds.signingPrivateKeyBase64);
3710
- const serverSessionKey = client.base64ToBytes(creds.serverSessionKeyBase64);
3711
- const loginResult2 = {
3712
- accessToken: creds.accessToken,
3713
- signingPrivateKey,
3714
- serverSessionKey
3715
- };
3743
+ await selectWorkspaceById(
3744
+ arbi2,
3745
+ workspaceId,
3746
+ loginResult2.serverSessionKey,
3747
+ creds.signingPrivateKeyBase64
3748
+ );
3749
+ const nextOpened = Array.from(/* @__PURE__ */ new Set([...creds.openedWorkspaces ?? [], workspaceId]));
3750
+ store.saveCredentials({
3751
+ ...store.requireCredentials(),
3752
+ openedWorkspaces: nextOpened
3753
+ });
3716
3754
  return {
3717
3755
  arbi: arbi2,
3718
3756
  loginResult: loginResult2,
3719
3757
  config,
3720
3758
  workspaceId,
3721
- accessToken: creds.accessToken,
3722
- sealedWorkspaceKey: creds.sealedWorkspaceKey
3759
+ accessToken: creds.accessToken
3723
3760
  };
3724
3761
  }
3725
3762
  const { arbi, loginResult } = await createAuthenticatedClient(config, creds, store);
3726
- const wsInfo = await selectWorkspaceById(
3763
+ await selectWorkspaceById(
3727
3764
  arbi,
3728
3765
  workspaceId,
3729
3766
  loginResult.serverSessionKey,
3730
3767
  creds.signingPrivateKeyBase64
3731
3768
  );
3732
3769
  const accessToken = arbi.session.getState().accessToken;
3733
- const sealedWorkspaceKey = await generateEncryptedWorkspaceKey(
3734
- arbi,
3735
- wsInfo.wrapped_key,
3736
- loginResult.serverSessionKey,
3737
- creds.signingPrivateKeyBase64
3738
- );
3739
3770
  if (!accessToken) {
3740
3771
  throw new ArbiError("Authentication error \u2014 missing token");
3741
3772
  }
3742
3773
  store.saveCredentials({
3743
3774
  ...store.requireCredentials(),
3744
3775
  accessToken,
3745
- sealedWorkspaceKey,
3746
- workspaceId,
3747
- tokenTimestamp: (/* @__PURE__ */ new Date()).toISOString()
3776
+ tokenTimestamp: (/* @__PURE__ */ new Date()).toISOString(),
3777
+ openedWorkspaces: [workspaceId]
3748
3778
  });
3749
- return { arbi, loginResult, config, workspaceId, accessToken, sealedWorkspaceKey };
3779
+ return {
3780
+ arbi,
3781
+ loginResult,
3782
+ config,
3783
+ workspaceId,
3784
+ accessToken
3785
+ };
3750
3786
  }
3751
3787
 
3752
3788
  // src/sse.ts
@@ -4310,6 +4346,7 @@ async function uploadFile(auth, fileData, fileName, options) {
4310
4346
  const params = new URLSearchParams();
4311
4347
  if (options?.folder) params.set("folder", sanitizeFolderPath(options.folder));
4312
4348
  if (options?.configExtId) params.set("config_ext_id", options.configExtId);
4349
+ if (options?.wpType) params.set("wp_type", options.wpType);
4313
4350
  const qs = params.toString();
4314
4351
  const res = await authenticatedFetch({
4315
4352
  ...auth,
@@ -4325,6 +4362,7 @@ async function uploadFiles(auth, files, options) {
4325
4362
  const params = new URLSearchParams();
4326
4363
  if (options?.folder) params.set("folder", sanitizeFolderPath(options.folder));
4327
4364
  if (options?.configExtId) params.set("config_ext_id", options.configExtId);
4365
+ if (options?.wpType) params.set("wp_type", options.wpType);
4328
4366
  const qs = params.toString();
4329
4367
  const res = await authenticatedFetch({
4330
4368
  ...auth,
@@ -4650,6 +4688,10 @@ __export(assistant_exports, {
4650
4688
  buildRetrievalChunkTool: () => buildRetrievalChunkTool,
4651
4689
  buildRetrievalFullContextTool: () => buildRetrievalFullContextTool,
4652
4690
  buildRetrievalTocTool: () => buildRetrievalTocTool,
4691
+ filterSkills: () => filterSkills,
4692
+ listSkills: () => listSkills,
4693
+ parseSlashCommand: () => parseSlashCommand,
4694
+ parseSlashTokenInProgress: () => parseSlashTokenInProgress,
4653
4695
  queryAssistant: () => queryAssistant,
4654
4696
  respondToAgent: () => respondToAgent,
4655
4697
  retrieve: () => retrieve
@@ -4745,6 +4787,40 @@ async function respondToAgent(arbi, assistantMessageExtId, answer) {
4745
4787
  "Failed to respond to agent"
4746
4788
  );
4747
4789
  }
4790
+ async function listSkills(arbi, options) {
4791
+ const result = requireData(
4792
+ await arbi.fetch.GET("/v1/assistant/skills", {
4793
+ params: { query: { include_hidden: options?.includeHidden ?? false } }
4794
+ }),
4795
+ "Failed to list skills"
4796
+ );
4797
+ return result.skills;
4798
+ }
4799
+ function parseSlashCommand(input) {
4800
+ const m2 = /^\s*\/([a-zA-Z0-9_-]+)(?:\s+([\s\S]*))?$/.exec(input);
4801
+ if (!m2) return null;
4802
+ return { slug: m2[1].toLowerCase(), args: m2[2] ?? "" };
4803
+ }
4804
+ function parseSlashTokenInProgress(buffer) {
4805
+ const m2 = /^\s*\/([a-zA-Z0-9_-]*)$/.exec(buffer);
4806
+ return m2 ? m2[1].toLowerCase() : null;
4807
+ }
4808
+ function filterSkills(items, query, pinned = []) {
4809
+ const q2 = query.toLowerCase();
4810
+ const pinnedSet = new Set(pinned);
4811
+ const key = (s2) => (s2.slug ?? s2.name).toLowerCase();
4812
+ const matched = q2 ? items.filter((s2) => key(s2).includes(q2)) : items.slice();
4813
+ matched.sort((a2, b2) => {
4814
+ const aPinned = pinnedSet.has(key(a2)) ? 0 : 1;
4815
+ const bPinned = pinnedSet.has(key(b2)) ? 0 : 1;
4816
+ if (aPinned !== bPinned) return aPinned - bPinned;
4817
+ const aPrefix = key(a2).startsWith(q2) ? 0 : 1;
4818
+ const bPrefix = key(b2).startsWith(q2) ? 0 : 1;
4819
+ if (aPrefix !== bPrefix) return aPrefix - bPrefix;
4820
+ return key(a2).localeCompare(key(b2));
4821
+ });
4822
+ return matched;
4823
+ }
4748
4824
 
4749
4825
  // src/operations/tags.ts
4750
4826
  var tags_exports = {};