openmates 0.15.0-alpha.28 → 0.15.0-alpha.29

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.
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-AXNRPVLE.js";
5
5
 
6
6
  // src/client.ts
7
- import { createHash as createHash6, randomUUID as randomUUID5 } from "crypto";
7
+ import { createHash as createHash7, randomBytes as randomBytes3, randomUUID as randomUUID5 } from "crypto";
8
8
  import { arch, platform as platform2, release } from "os";
9
9
  import { createInterface as createInterface2 } from "readline/promises";
10
10
  import { stdin as stdin2, stdout } from "process";
@@ -198,9 +198,9 @@ function generateSecureRecoveryKey(length = 24) {
198
198
  const chars = requiredSets[index];
199
199
  result[index] = chars.charAt(randomByte % chars.length);
200
200
  }
201
- const randomBytes5 = cryptoApi.getRandomValues(new Uint8Array(length));
201
+ const randomBytes6 = cryptoApi.getRandomValues(new Uint8Array(length));
202
202
  for (let index = requiredSets.length; index < length; index += 1) {
203
- result[index] = allChars.charAt(randomBytes5[index] % allChars.length);
203
+ result[index] = allChars.charAt(randomBytes6[index] % allChars.length);
204
204
  }
205
205
  for (let index = result.length - 1; index > 0; index -= 1) {
206
206
  const randomByte = cryptoApi.getRandomValues(new Uint8Array(1))[0];
@@ -699,6 +699,7 @@ import {
699
699
  rmSync,
700
700
  writeFileSync
701
701
  } from "fs";
702
+ import { createHash as createHash3 } from "crypto";
702
703
  import { homedir as homedir2 } from "os";
703
704
  import { join } from "path";
704
705
 
@@ -975,6 +976,7 @@ function saveSession(session) {
975
976
  createdAt: session.createdAt,
976
977
  authorizerDeviceName: session.authorizerDeviceName,
977
978
  autoLogoutMinutes: session.autoLogoutMinutes,
979
+ activeTeamId: session.activeTeamId ?? null,
978
980
  masterKeyStorage: result.type
979
981
  };
980
982
  if (result.type === "encrypted") {
@@ -1082,26 +1084,32 @@ function buildSession(onDisk, masterKey, emailEncryptionKey) {
1082
1084
  userEmailSalt: onDisk.userEmailSalt,
1083
1085
  createdAt: onDisk.createdAt,
1084
1086
  authorizerDeviceName: onDisk.authorizerDeviceName,
1085
- autoLogoutMinutes: onDisk.autoLogoutMinutes
1087
+ autoLogoutMinutes: onDisk.autoLogoutMinutes,
1088
+ activeTeamId: onDisk.activeTeamId ?? null
1086
1089
  };
1087
1090
  }
1088
1091
  var SYNC_CACHE_FILE = "sync_cache.json";
1089
- function saveSyncCache(cache) {
1090
- const filePath = join(ensureStateDir(), SYNC_CACHE_FILE);
1092
+ function syncCacheFile(teamId) {
1093
+ if (!teamId) return SYNC_CACHE_FILE;
1094
+ const digest = createHash3("sha256").update(teamId).digest("hex").slice(0, 32);
1095
+ return `sync_cache.team.${digest}.json`;
1096
+ }
1097
+ function saveSyncCache(cache, teamId) {
1098
+ const filePath = join(ensureStateDir(), syncCacheFile(teamId));
1091
1099
  writeJsonFile(filePath, cache);
1092
1100
  }
1093
- function loadSyncCache() {
1094
- const filePath = join(ensureStateDir(), SYNC_CACHE_FILE);
1101
+ function loadSyncCache(teamId) {
1102
+ const filePath = join(ensureStateDir(), syncCacheFile(teamId));
1095
1103
  return readJsonFile(filePath);
1096
1104
  }
1097
- function clearSyncCache() {
1098
- const filePath = join(ensureStateDir(), SYNC_CACHE_FILE);
1105
+ function clearSyncCache(teamId) {
1106
+ const filePath = join(ensureStateDir(), syncCacheFile(teamId));
1099
1107
  if (existsSync2(filePath)) {
1100
1108
  rmSync(filePath);
1101
1109
  }
1102
1110
  }
1103
- function isSyncCacheFresh(maxAgeMs = 3e5) {
1104
- const cache = loadSyncCache();
1111
+ function isSyncCacheFresh(maxAgeMs = 3e5, teamId) {
1112
+ const cache = loadSyncCache(teamId);
1105
1113
  if (!cache) return false;
1106
1114
  return Date.now() - cache.syncedAt < maxAgeMs;
1107
1115
  }
@@ -2297,7 +2305,7 @@ function escapeRegExp(s) {
2297
2305
  }
2298
2306
 
2299
2307
  // src/embedCreator.ts
2300
- import { randomUUID, createHash as createHash3, randomBytes, webcrypto as webcrypto3 } from "crypto";
2308
+ import { randomUUID, createHash as createHash4, randomBytes, webcrypto as webcrypto3 } from "crypto";
2301
2309
  import { encode as toonEncode } from "@toon-format/toon";
2302
2310
  var cryptoApi3 = webcrypto3;
2303
2311
  var AES_GCM_IV_LENGTH3 = 12;
@@ -2351,7 +2359,7 @@ function generateEmbedKey() {
2351
2359
  return new Uint8Array(randomBytes(32));
2352
2360
  }
2353
2361
  function computeSHA256(content) {
2354
- return createHash3("sha256").update(content).digest("hex");
2362
+ return createHash4("sha256").update(content).digest("hex");
2355
2363
  }
2356
2364
  function toonEncodeContent(data) {
2357
2365
  try {
@@ -2546,7 +2554,7 @@ function buildEmbedShareUrl(origin, embedId, blob) {
2546
2554
  }
2547
2555
 
2548
2556
  // src/connectedAccountImport.ts
2549
- import { createHash as createHash4, randomUUID as randomUUID2, webcrypto as webcrypto5 } from "crypto";
2557
+ import { createHash as createHash5, randomUUID as randomUUID2, webcrypto as webcrypto5 } from "crypto";
2550
2558
  var TRANSFER_PREFIX = "OMCA1.";
2551
2559
  var SUPPORTED_KDF_ITERATIONS = 1e5;
2552
2560
  async function decryptConnectedAccountCliTransferPayload(encryptedPayload, passcode) {
@@ -2691,7 +2699,7 @@ function defaultProviderLabel(providerId) {
2691
2699
  return providerId === "google_calendar" ? "Google Calendar" : "Connected account";
2692
2700
  }
2693
2701
  function sha256Hex2(value) {
2694
- return createHash4("sha256").update(value).digest("hex");
2702
+ return createHash5("sha256").update(value).digest("hex");
2695
2703
  }
2696
2704
  function base64UrlToBytes2(value) {
2697
2705
  return base64ToBytes(value.replace(/-/g, "+").replace(/_/g, "/"));
@@ -3540,7 +3548,7 @@ function stripTimer(job) {
3540
3548
  }
3541
3549
 
3542
3550
  // src/tasksCli.ts
3543
- import { createHash as createHash5, createHmac, hkdfSync, randomBytes as randomBytes2, randomUUID as randomUUID4 } from "crypto";
3551
+ import { createHash as createHash6, createHmac, hkdfSync, randomBytes as randomBytes2, randomUUID as randomUUID4 } from "crypto";
3544
3552
  var TASK_STATUSES2 = ["backlog", "todo", "in_progress", "blocked", "done"];
3545
3553
  var DEFAULT_STANDALONE_PREFIX = "TASK";
3546
3554
  var PRIORITY_LEVELS = ["none", "low", "medium", "high", "urgent"];
@@ -3722,7 +3730,7 @@ function workflowProjectionToTask(record) {
3722
3730
  }
3723
3731
  function workflowProjectionShortId(record) {
3724
3732
  const stableId = record.workflow_run_id || record.task_id;
3725
- return `WF-${createHash5("sha256").update(stableId).digest("hex").slice(0, 6).toUpperCase()}`;
3733
+ return `WF-${createHash6("sha256").update(stableId).digest("hex").slice(0, 6).toUpperCase()}`;
3726
3734
  }
3727
3735
  async function decryptUserTasks(records, masterKey) {
3728
3736
  const output = [];
@@ -3828,7 +3836,7 @@ function parseStringArray(value) {
3828
3836
  function deriveShortId(record) {
3829
3837
  const prefix = record.short_id_prefix || DEFAULT_STANDALONE_PREFIX;
3830
3838
  const source = record.task_id || `${record.created_at ?? ""}-${record.position ?? ""}`;
3831
- const digest = createHash5("sha256").update(source).digest("hex").slice(0, 4).toUpperCase();
3839
+ const digest = createHash6("sha256").update(source).digest("hex").slice(0, 4).toUpperCase();
3832
3840
  return `${prefix}-${parseInt(digest, 16) % 1e4}`;
3833
3841
  }
3834
3842
  function nowSeconds() {
@@ -3968,7 +3976,8 @@ function buildTurnTokenRefsRequestPayload(params) {
3968
3976
  return {
3969
3977
  chat_id: params.chatId,
3970
3978
  message_id: params.messageId,
3971
- refs: params.refs.map((ref) => ({ ...ref }))
3979
+ refs: params.refs.map((ref) => ({ ...ref })),
3980
+ ...params.teamId ? { team_id: params.teamId } : {}
3972
3981
  };
3973
3982
  }
3974
3983
  function categoryFromMemoryKey(key) {
@@ -4752,6 +4761,189 @@ var OpenMatesClient = class _OpenMatesClient {
4752
4761
  hasSession() {
4753
4762
  return this.session !== null;
4754
4763
  }
4764
+ getActiveTeamId() {
4765
+ return this.session?.activeTeamId ?? null;
4766
+ }
4767
+ setActiveTeamId(teamId) {
4768
+ const session = this.requireSession();
4769
+ this.session = { ...session, activeTeamId: teamId };
4770
+ saveSession(this.session);
4771
+ }
4772
+ resolveTeamContext(options = {}) {
4773
+ if (options.personal) return null;
4774
+ if (options.teamId !== void 0) return options.teamId;
4775
+ return this.getActiveTeamId();
4776
+ }
4777
+ appendTeamQuery(path, options = {}) {
4778
+ const teamId = this.resolveTeamContext(options);
4779
+ if (!teamId) return path;
4780
+ const separator2 = path.includes("?") ? "&" : "?";
4781
+ return `${path}${separator2}team_id=${encodeURIComponent(teamId)}`;
4782
+ }
4783
+ async listTeams() {
4784
+ this.requireSession();
4785
+ const response = await this.http.get("/v1/teams", this.getCliRequestHeaders());
4786
+ if (!response.ok) throw new Error(`Team list failed with HTTP ${response.status}`);
4787
+ return response.data.teams ?? [];
4788
+ }
4789
+ async createTeam(input) {
4790
+ this.requireSession();
4791
+ const now = Math.floor(Date.now() / 1e3);
4792
+ const teamKeyBytes = randomBytes3(32);
4793
+ const payload = {
4794
+ team_id: input.teamId ?? randomUUID5(),
4795
+ slug: input.slug ?? void 0,
4796
+ encrypted_name: input.encryptedName ?? await encryptWithAesGcmCombined(input.name ?? "Untitled team", teamKeyBytes),
4797
+ encrypted_description: input.encryptedDescription ?? (input.description ? await encryptWithAesGcmCombined(input.description, teamKeyBytes) : void 0),
4798
+ encrypted_team_key: input.encryptedTeamKey ?? await encryptBytesWithAesGcm(teamKeyBytes, this.getMasterKeyBytes()),
4799
+ encrypted_zero_balance: input.encryptedZeroBalance ?? await encryptWithAesGcmCombined("0", teamKeyBytes),
4800
+ created_at: input.createdAt ?? now,
4801
+ updated_at: input.createdAt ?? now
4802
+ };
4803
+ const response = await this.http.post("/v1/teams", payload, this.getCliRequestHeaders());
4804
+ if (!response.ok || !response.data.team) throw new Error(`Team create failed with HTTP ${response.status}`);
4805
+ return response.data.team;
4806
+ }
4807
+ async getTeam(teamId) {
4808
+ this.requireSession();
4809
+ const response = await this.http.get(`/v1/teams/${encodeURIComponent(teamId)}`, this.getCliRequestHeaders());
4810
+ if (!response.ok || !response.data.team) throw new Error(`Team get failed with HTTP ${response.status}`);
4811
+ return response.data.team;
4812
+ }
4813
+ async updateTeam(teamId, input) {
4814
+ this.requireSession();
4815
+ const response = await this.http.patch(`/v1/teams/${encodeURIComponent(teamId)}`, {
4816
+ updated_at: input.updated_at ?? Math.floor(Date.now() / 1e3),
4817
+ ...input
4818
+ }, this.getCliRequestHeaders());
4819
+ if (!response.ok || !response.data.team) throw new Error(`Team update failed with HTTP ${response.status}`);
4820
+ return response.data.team;
4821
+ }
4822
+ async deleteTeam(teamId) {
4823
+ this.requireSession();
4824
+ const response = await this.http.delete(`/v1/teams/${encodeURIComponent(teamId)}`, void 0, this.getCliRequestHeaders());
4825
+ if (!response.ok) throw new Error(`Team delete failed with HTTP ${response.status}`);
4826
+ return { success: response.data.success === true };
4827
+ }
4828
+ async createTeamInvite(teamId, input) {
4829
+ this.requireSession();
4830
+ const response = await this.http.post(`/v1/teams/${encodeURIComponent(teamId)}/invites`, {
4831
+ invite_id: input.invite_id ?? randomUUID5(),
4832
+ created_at: input.created_at ?? Math.floor(Date.now() / 1e3),
4833
+ ...input
4834
+ }, this.getCliRequestHeaders());
4835
+ if (!response.ok || !response.data.invite) throw new Error(`Team invite create failed with HTTP ${response.status}`);
4836
+ return response.data.invite;
4837
+ }
4838
+ async acceptTeamInvite(inviteId) {
4839
+ this.requireSession();
4840
+ const response = await this.http.post(`/v1/teams/invites/${encodeURIComponent(inviteId)}/accept`, { accepted_at: Math.floor(Date.now() / 1e3) }, this.getCliRequestHeaders());
4841
+ if (!response.ok || !response.data.access_request) throw new Error(`Team invite accept failed with HTTP ${response.status}`);
4842
+ return { access_request: response.data.access_request, status_label: response.data.status_label };
4843
+ }
4844
+ async declineTeamInvite(inviteId) {
4845
+ this.requireSession();
4846
+ const response = await this.http.post(`/v1/teams/invites/${encodeURIComponent(inviteId)}/decline`, { declined_at: Math.floor(Date.now() / 1e3) }, this.getCliRequestHeaders());
4847
+ if (!response.ok) throw new Error(`Team invite decline failed with HTTP ${response.status}`);
4848
+ return { success: response.data.success === true };
4849
+ }
4850
+ async listTeamAccessRequests(teamId, status) {
4851
+ this.requireSession();
4852
+ const query = status && status !== "all" ? `?status=${encodeURIComponent(status)}` : status === "all" ? "?status=" : "";
4853
+ const response = await this.http.get(`/v1/teams/${encodeURIComponent(teamId)}/access-requests${query}`, this.getCliRequestHeaders());
4854
+ if (!response.ok) throw new Error(`Team access requests failed with HTTP ${response.status}`);
4855
+ return response.data.access_requests ?? [];
4856
+ }
4857
+ async approveTeamAccessRequest(teamId, accessRequestId, encryptedTeamKey) {
4858
+ this.requireSession();
4859
+ const response = await this.http.post(`/v1/teams/${encodeURIComponent(teamId)}/access-requests/${encodeURIComponent(accessRequestId)}/approve`, { encrypted_team_key: encryptedTeamKey, approved_at: Math.floor(Date.now() / 1e3) }, this.getCliRequestHeaders());
4860
+ if (!response.ok || !response.data.membership) throw new Error(`Team access approval failed with HTTP ${response.status}`);
4861
+ return response.data.membership;
4862
+ }
4863
+ async rejectTeamAccessRequest(teamId, accessRequestId) {
4864
+ this.requireSession();
4865
+ const response = await this.http.post(`/v1/teams/${encodeURIComponent(teamId)}/access-requests/${encodeURIComponent(accessRequestId)}/reject`, { rejected_at: Math.floor(Date.now() / 1e3) }, this.getCliRequestHeaders());
4866
+ if (!response.ok) throw new Error(`Team access rejection failed with HTTP ${response.status}`);
4867
+ return { success: response.data.success === true };
4868
+ }
4869
+ async exportTeamData(teamId, input = {}) {
4870
+ this.requireSession();
4871
+ const response = await this.http.post(`/v1/teams/${encodeURIComponent(teamId)}/export`, {
4872
+ export_id: input.export_id,
4873
+ created_at: input.created_at ?? Math.floor(Date.now() / 1e3)
4874
+ }, this.getCliRequestHeaders());
4875
+ if (!response.ok) throw new Error(`Team export failed with HTTP ${response.status}`);
4876
+ return response.data;
4877
+ }
4878
+ async getTeamExport(teamId, exportId) {
4879
+ this.requireSession();
4880
+ const response = await this.http.get(`/v1/teams/${encodeURIComponent(teamId)}/export/${encodeURIComponent(exportId)}`, this.getCliRequestHeaders());
4881
+ if (!response.ok) throw new Error(`Team export download failed with HTTP ${response.status}`);
4882
+ return response.data;
4883
+ }
4884
+ async importTeamData(destinationTeamId, artifact) {
4885
+ this.requireSession();
4886
+ const response = await this.http.post("/v1/teams/import", {
4887
+ destination_team_id: destinationTeamId,
4888
+ artifact,
4889
+ imported_at: Math.floor(Date.now() / 1e3)
4890
+ }, this.getCliRequestHeaders());
4891
+ if (!response.ok) throw new Error(`Team import failed with HTTP ${response.status}`);
4892
+ return response.data;
4893
+ }
4894
+ async updateTeamMemberRole(teamId, memberUserId, role) {
4895
+ this.requireSession();
4896
+ const response = await this.http.patch(`/v1/teams/${encodeURIComponent(teamId)}/members/${encodeURIComponent(memberUserId)}`, { role, updated_at: Math.floor(Date.now() / 1e3) }, this.getCliRequestHeaders());
4897
+ if (!response.ok || !response.data.membership) throw new Error(`Team member update failed with HTTP ${response.status}`);
4898
+ return response.data.membership;
4899
+ }
4900
+ async removeTeamMember(teamId, memberUserId) {
4901
+ this.requireSession();
4902
+ const response = await this.http.post(`/v1/teams/${encodeURIComponent(teamId)}/members/${encodeURIComponent(memberUserId)}/remove`, { removed_at: Math.floor(Date.now() / 1e3) }, this.getCliRequestHeaders());
4903
+ if (!response.ok) throw new Error(`Team member remove failed with HTTP ${response.status}`);
4904
+ return { success: response.data.success === true };
4905
+ }
4906
+ async getTeamBilling(teamId) {
4907
+ this.requireSession();
4908
+ const response = await this.http.get(`/v1/teams/${encodeURIComponent(teamId)}/billing`, this.getCliRequestHeaders());
4909
+ if (!response.ok || !response.data.billing) throw new Error(`Team billing failed with HTTP ${response.status}`);
4910
+ return response.data.billing;
4911
+ }
4912
+ async addTeamCredits(teamId, input) {
4913
+ this.requireSession();
4914
+ const response = await this.http.post(`/v1/teams/${encodeURIComponent(teamId)}/billing/credits`, {
4915
+ event_id: input.event_id ?? randomUUID5(),
4916
+ encrypted_balance: input.encrypted_balance ?? String(input.encryptedBalance ?? "0"),
4917
+ occurred_at: input.occurred_at ?? Math.floor(Date.now() / 1e3),
4918
+ ...input
4919
+ }, this.getCliRequestHeaders());
4920
+ if (!response.ok || !response.data.billing) throw new Error(`Team credit add failed with HTTP ${response.status}`);
4921
+ return response.data.billing;
4922
+ }
4923
+ async listTeamUsage(teamId, memberUserId) {
4924
+ this.requireSession();
4925
+ const query = memberUserId ? `?member_user_id=${encodeURIComponent(memberUserId)}` : "";
4926
+ const response = await this.http.get(`/v1/teams/${encodeURIComponent(teamId)}/billing/usage${query}`, this.getCliRequestHeaders());
4927
+ if (!response.ok) throw new Error(`Team usage failed with HTTP ${response.status}`);
4928
+ return response.data.usage ?? [];
4929
+ }
4930
+ async moveWorkspaceToTeam(workspaceType, objectId, teamId) {
4931
+ this.requireSession();
4932
+ const routeByType = {
4933
+ chat: `/v1/chats/${encodeURIComponent(objectId)}/move`,
4934
+ project: `/v1/projects/${encodeURIComponent(objectId)}/move`,
4935
+ task: `/v1/user-tasks/${encodeURIComponent(objectId)}/move`,
4936
+ plan: `/v1/user-plans/${encodeURIComponent(objectId)}/move`,
4937
+ workflow: `/v1/workflows/${encodeURIComponent(objectId)}/move`
4938
+ };
4939
+ const response = await this.http.post(
4940
+ routeByType[workspaceType],
4941
+ { team_id: teamId, confirmed: true, moved_at: Math.floor(Date.now() / 1e3) },
4942
+ this.getCliRequestHeaders()
4943
+ );
4944
+ if (!response.ok) throw new Error(`${workspaceType} move failed with HTTP ${response.status}`);
4945
+ return response.data;
4946
+ }
4755
4947
  async getAnonymousFreeUsageStatus() {
4756
4948
  const response = await this.http.get("/v1/anonymous/free-usage/status");
4757
4949
  if (response.status === 404) {
@@ -4910,7 +5102,7 @@ var OpenMatesClient = class _OpenMatesClient {
4910
5102
  if (!userId) {
4911
5103
  throw new Error("Could not resolve current user id for local connected-account connector.");
4912
5104
  }
4913
- const { createHash: createHash10 } = await import("crypto");
5105
+ const { createHash: createHash11 } = await import("crypto");
4914
5106
  const accountId = randomUUID5();
4915
5107
  const masterKey = this.getMasterKeyBytes();
4916
5108
  const encryptLocalConnectorValue = async (value) => {
@@ -4919,9 +5111,9 @@ var OpenMatesClient = class _OpenMatesClient {
4919
5111
  };
4920
5112
  const payload = {
4921
5113
  id: accountId,
4922
- hashed_user_id: createHash10("sha256").update(userId).digest("hex"),
5114
+ hashed_user_id: createHash11("sha256").update(userId).digest("hex"),
4923
5115
  encrypted_provider_type: await encryptLocalConnectorValue(input.provider_id),
4924
- provider_type_hash: createHash10("sha256").update(input.provider_id).digest("hex"),
5116
+ provider_type_hash: createHash11("sha256").update(input.provider_id).digest("hex"),
4925
5117
  encrypted_account_label: await encryptLocalConnectorValue(input.label),
4926
5118
  encrypted_capabilities: await encryptLocalConnectorValue(input.capabilities),
4927
5119
  encrypted_app_permissions: await encryptLocalConnectorValue({
@@ -5363,7 +5555,7 @@ var OpenMatesClient = class _OpenMatesClient {
5363
5555
  return decryptBytesWithAesGcm(encryptedChatKey, masterKey);
5364
5556
  }
5365
5557
  getMasterWrapperEncryptedChatKey(cache, chatId) {
5366
- const hashedChatId = createHash6("sha256").update(chatId).digest("hex");
5558
+ const hashedChatId = createHash7("sha256").update(chatId).digest("hex");
5367
5559
  const wrapper = (cache?.chatKeyWrappers ?? []).find(
5368
5560
  (entry) => entry.key_type === "master" && entry.hashed_chat_id === hashedChatId && typeof entry.encrypted_chat_key === "string"
5369
5561
  );
@@ -5398,8 +5590,8 @@ var OpenMatesClient = class _OpenMatesClient {
5398
5590
  mateName: category ? MATE_NAMES[category] ?? null : null
5399
5591
  };
5400
5592
  }
5401
- async listChats(limit = 10, page = 1) {
5402
- const cache = await this.ensureSynced();
5593
+ async listChats(limit = 10, page = 1, options = {}) {
5594
+ const cache = await this.ensureSynced(false, [], options);
5403
5595
  const masterKey = this.getMasterKeyBytes();
5404
5596
  const total = cache.chats.length;
5405
5597
  const offset = (page - 1) * limit;
@@ -5567,8 +5759,8 @@ var OpenMatesClient = class _OpenMatesClient {
5567
5759
  preview
5568
5760
  };
5569
5761
  }
5570
- async searchChats(query) {
5571
- const cache = await this.ensureSynced();
5762
+ async searchChats(query, options = {}) {
5763
+ const cache = await this.ensureSynced(false, [], options);
5572
5764
  const masterKey = this.getMasterKeyBytes();
5573
5765
  const normalized = query.trim().toLowerCase();
5574
5766
  const results = [];
@@ -5595,8 +5787,8 @@ var OpenMatesClient = class _OpenMatesClient {
5595
5787
  *
5596
5788
  * @param query Full UUID, 8-char short ID, or chat title.
5597
5789
  */
5598
- async getChatMessages(query) {
5599
- const cache = await this.ensureSynced(true);
5790
+ async getChatMessages(query, options = {}) {
5791
+ const cache = await this.ensureSynced(true, [], options);
5600
5792
  const masterKey = this.getMasterKeyBytes();
5601
5793
  const normalized = query.trim().toLowerCase();
5602
5794
  let found;
@@ -5658,8 +5850,8 @@ var OpenMatesClient = class _OpenMatesClient {
5658
5850
  );
5659
5851
  let msgEmbedIds = [];
5660
5852
  if (clientMsgId && cache.embeds.length > 0) {
5661
- const { createHash: createHash10 } = await import("crypto");
5662
- const hashed = createHash10("sha256").update(clientMsgId).digest("hex");
5853
+ const { createHash: createHash11 } = await import("crypto");
5854
+ const hashed = createHash11("sha256").update(clientMsgId).digest("hex");
5663
5855
  msgEmbedIds = cache.embeds.filter(
5664
5856
  (e) => e.hashed_message_id === hashed && // Only include parent embeds (no parent_embed_id).
5665
5857
  // Child embeds inherit the parent's key and are loaded
@@ -5706,8 +5898,8 @@ var OpenMatesClient = class _OpenMatesClient {
5706
5898
  );
5707
5899
  }
5708
5900
  const embedId = String(embed.embed_id ?? embed.id ?? "");
5709
- const { createHash: createHash10 } = await import("crypto");
5710
- const hashedEmbedId = createHash10("sha256").update(embedId).digest("hex");
5901
+ const { createHash: createHash11 } = await import("crypto");
5902
+ const hashedEmbedId = createHash11("sha256").update(embedId).digest("hex");
5711
5903
  const embedKeyBytes = await this.resolveEmbedKey(
5712
5904
  cache,
5713
5905
  masterKey,
@@ -5815,7 +6007,7 @@ var OpenMatesClient = class _OpenMatesClient {
5815
6007
  async resolveEmbedKey(cache, masterKey, embed, embedId, hashedEmbedId, visited = /* @__PURE__ */ new Set()) {
5816
6008
  if (visited.has(embedId)) return null;
5817
6009
  visited.add(embedId);
5818
- const { createHash: createHash10 } = await import("crypto");
6010
+ const { createHash: createHash11 } = await import("crypto");
5819
6011
  const masterKeyEntry = cache.embedKeys.find(
5820
6012
  (ek) => ek.hashed_embed_id === hashedEmbedId && String(ek.key_type) === "master"
5821
6013
  );
@@ -5832,7 +6024,7 @@ var OpenMatesClient = class _OpenMatesClient {
5832
6024
  if (chatKeyEntry && typeof chatKeyEntry.encrypted_embed_key === "string") {
5833
6025
  const hashedChatId = String(chatKeyEntry.hashed_chat_id ?? "");
5834
6026
  const owningChat = cache.chats.find((c) => {
5835
- const chatHash = createHash10("sha256").update(String(c.details.id ?? "")).digest("hex");
6027
+ const chatHash = createHash11("sha256").update(String(c.details.id ?? "")).digest("hex");
5836
6028
  return chatHash === hashedChatId;
5837
6029
  });
5838
6030
  if (owningChat) {
@@ -5861,7 +6053,7 @@ var OpenMatesClient = class _OpenMatesClient {
5861
6053
  const parentFullId = String(
5862
6054
  parentEmbed2.embed_id ?? parentEmbed2.id ?? ""
5863
6055
  );
5864
- const parentHashedId = createHash10("sha256").update(parentFullId).digest("hex");
6056
+ const parentHashedId = createHash11("sha256").update(parentFullId).digest("hex");
5865
6057
  const parentKey = await this.resolveEmbedKey(
5866
6058
  cache,
5867
6059
  masterKey,
@@ -5879,8 +6071,9 @@ var OpenMatesClient = class _OpenMatesClient {
5879
6071
  * Resolve a short chat ID (first 8 chars) or partial title to a full UUID.
5880
6072
  * Accepts full UUIDs unchanged. Returns undefined if no match found.
5881
6073
  */
5882
- async resolveFullChatId(idOrShort) {
5883
- const staleCache = loadSyncCache();
6074
+ async resolveFullChatId(idOrShort, options = {}) {
6075
+ const teamId = this.resolveTeamContext(options);
6076
+ const staleCache = loadSyncCache(teamId);
5884
6077
  const lower = idOrShort.toLowerCase();
5885
6078
  if (staleCache) {
5886
6079
  for (const chat of staleCache.chats) {
@@ -5891,7 +6084,9 @@ var OpenMatesClient = class _OpenMatesClient {
5891
6084
  }
5892
6085
  const freshCache = await this.ensureSynced(
5893
6086
  /* forceRefresh */
5894
- true
6087
+ true,
6088
+ [],
6089
+ { teamId }
5895
6090
  );
5896
6091
  for (const chat of freshCache.chats) {
5897
6092
  const fullId = String(chat.details.id ?? "");
@@ -5911,8 +6106,8 @@ var OpenMatesClient = class _OpenMatesClient {
5911
6106
  *
5912
6107
  * @param limit Maximum number of suggestions to return (default: 10)
5913
6108
  */
5914
- async listNewChatSuggestions(limit = 10) {
5915
- const cache = await this.ensureSynced();
6109
+ async listNewChatSuggestions(limit = 10, options = {}) {
6110
+ const cache = await this.ensureSynced(false, [], options);
5916
6111
  const masterKey = this.getMasterKeyBytes();
5917
6112
  const rawSuggestions = cache.newChatSuggestions ?? [];
5918
6113
  const results = [];
@@ -5942,12 +6137,13 @@ var OpenMatesClient = class _OpenMatesClient {
5942
6137
  *
5943
6138
  * Mirrors: chat_actions_store.ts / FollowUpSuggestions.svelte (web app)
5944
6139
  */
5945
- async getChatFollowUpSuggestions(chatId) {
5946
- const cachedMatch = loadSyncCache()?.chats.find(
6140
+ async getChatFollowUpSuggestions(chatId, options = {}) {
6141
+ const teamId = this.resolveTeamContext(options);
6142
+ const cachedMatch = loadSyncCache(teamId)?.chats.find(
5947
6143
  (c) => String(c.details.id ?? "") === chatId || String(c.details.id ?? "").startsWith(chatId)
5948
6144
  );
5949
6145
  const refreshChatId = String(cachedMatch?.details.id ?? chatId);
5950
- const cache = await this.ensureSynced(true, [refreshChatId]);
6146
+ const cache = await this.ensureSynced(true, [refreshChatId], { teamId });
5951
6147
  const masterKey = this.getMasterKeyBytes();
5952
6148
  const found = cache.chats.find(
5953
6149
  (c) => String(c.details.id ?? "") === chatId || String(c.details.id ?? "").startsWith(chatId)
@@ -5972,11 +6168,12 @@ var OpenMatesClient = class _OpenMatesClient {
5972
6168
  return [];
5973
6169
  }
5974
6170
  async sendMessage(params) {
6171
+ const teamId = this.resolveTeamContext({ teamId: params.teamId, personal: params.personal });
5975
6172
  let chatId;
5976
6173
  if (!params.chatId) {
5977
6174
  chatId = randomUUID5();
5978
6175
  } else if (params.chatId.length < 36) {
5979
- const resolved = await this.resolveFullChatId(params.chatId);
6176
+ const resolved = await this.resolveFullChatId(params.chatId, { teamId });
5980
6177
  if (!resolved) {
5981
6178
  throw new Error(
5982
6179
  `Chat not found for '${params.chatId}'. Use a full UUID or the first 8 characters of an existing chat ID.`
@@ -5990,7 +6187,7 @@ var OpenMatesClient = class _OpenMatesClient {
5990
6187
  let memoryMetadataKeys = [];
5991
6188
  if (!params.incognito) {
5992
6189
  try {
5993
- availableMemories = await this.listMemories();
6190
+ availableMemories = await this.listMemories({ teamId });
5994
6191
  memoryMetadataKeys = [
5995
6192
  ...new Set(
5996
6193
  availableMemories.filter((memory) => memory.app_id && memory.item_type).map((memory) => `${memory.app_id}-${memory.item_type}`)
@@ -6014,14 +6211,15 @@ var OpenMatesClient = class _OpenMatesClient {
6014
6211
  const messageId = randomUUID5();
6015
6212
  const createdAt = Math.floor(Date.now() / 1e3);
6016
6213
  const isNewChat = !params.chatId;
6017
- ws.send("set_active_chat", { chat_id: chatId });
6214
+ ws.send("set_active_chat", { chat_id: chatId, ...teamId ? { team_id: teamId } : {} });
6018
6215
  const connectedAccountDirectory = buildConnectedAccountDirectoryPayload(
6019
6216
  params.connectedAccountDirectory
6020
6217
  );
6021
6218
  const connectedAccountTokenRefs = params.connectedAccountTokenRefInputs?.length ? await this.createTurnTokenRefs({
6022
6219
  chatId,
6023
6220
  messageId,
6024
- refs: params.connectedAccountTokenRefInputs
6221
+ refs: params.connectedAccountTokenRefInputs,
6222
+ teamId
6025
6223
  }) : [];
6026
6224
  assertNoConnectedAccountSecretLeak(connectedAccountTokenRefs);
6027
6225
  const piiMappings = params.piiMappings ?? [];
@@ -6043,7 +6241,7 @@ var OpenMatesClient = class _OpenMatesClient {
6043
6241
  masterKey
6044
6242
  );
6045
6243
  } else {
6046
- const cache = loadSyncCache() ?? await this.ensureSynced();
6244
+ const cache = loadSyncCache(teamId) ?? await this.ensureSynced(false, [], { teamId });
6047
6245
  const chat = cache.chats.find(
6048
6246
  (c) => String(c.details.id ?? "") === chatId || String(c.details.id ?? "").startsWith(chatId)
6049
6247
  );
@@ -6063,6 +6261,7 @@ var OpenMatesClient = class _OpenMatesClient {
6063
6261
  const clientCapabilities = explicitTasksAppSkill ? [] : ["task_update_jobs"];
6064
6262
  const messagePayload = {
6065
6263
  chat_id: chatId,
6264
+ ...teamId ? { team_id: teamId } : {},
6066
6265
  client_capabilities: clientCapabilities,
6067
6266
  is_incognito: Boolean(params.incognito),
6068
6267
  message: {
@@ -6188,6 +6387,7 @@ var OpenMatesClient = class _OpenMatesClient {
6188
6387
  const preflightPayload = {
6189
6388
  protocol_version: protocolVersion,
6190
6389
  chat_id: chatId,
6390
+ ...teamId ? { team_id: teamId } : {},
6191
6391
  turn_id: turnId,
6192
6392
  message_id: messageId,
6193
6393
  chat_key_version: chatKeyVersion,
@@ -6624,7 +6824,7 @@ var OpenMatesClient = class _OpenMatesClient {
6624
6824
  } catch (error) {
6625
6825
  if (error instanceof WebSocketProtocolError) {
6626
6826
  if (error.code === "version_conflict") {
6627
- const latestCache = await this.ensureSynced(true, [chatId]);
6827
+ const latestCache = await this.ensureSynced(true, [chatId], { teamId });
6628
6828
  const latestChat = latestCache.chats.find(
6629
6829
  (chat) => String(chat.details.id ?? "") === chatId
6630
6830
  );
@@ -6657,6 +6857,7 @@ var OpenMatesClient = class _OpenMatesClient {
6657
6857
  await this.persistPostProcessingMetadata({
6658
6858
  ws,
6659
6859
  chatId,
6860
+ teamId,
6660
6861
  chatKeyBytes,
6661
6862
  followUpSuggestions: resp.followUpSuggestions,
6662
6863
  newChatSuggestions: resp.newChatSuggestions,
@@ -6673,7 +6874,7 @@ var OpenMatesClient = class _OpenMatesClient {
6673
6874
  });
6674
6875
  pendingTaskUpdateJobs = pendingTaskUpdateJobs.filter((job) => !persistedTaskJobIds.has(job.job_id));
6675
6876
  await persistTaskEventSystemMessages(taskEvents);
6676
- clearSyncCache();
6877
+ clearSyncCache(teamId);
6677
6878
  }
6678
6879
  } finally {
6679
6880
  ws.close();
@@ -7099,6 +7300,7 @@ var OpenMatesClient = class _OpenMatesClient {
7099
7300
  if (!encryptedFollowUps && encryptedNewChatSuggestions.length === 0) return;
7100
7301
  await params.ws.sendAsync("update_post_processing_metadata", {
7101
7302
  chat_id: params.chatId,
7303
+ ...params.teamId ? { team_id: params.teamId } : {},
7102
7304
  encrypted_follow_up_suggestions: encryptedFollowUps,
7103
7305
  encrypted_new_chat_suggestions: encryptedNewChatSuggestions,
7104
7306
  encrypted_chat_key: params.encryptedChatKey ?? ""
@@ -7118,10 +7320,11 @@ var OpenMatesClient = class _OpenMatesClient {
7118
7320
  * Mirrors the web app's sendDeleteChatImpl in chatSyncServiceSenders.ts.
7119
7321
  * Sends a delete_chat WebSocket message and waits for the server ack.
7120
7322
  */
7121
- async deleteChat(chatIdInput) {
7323
+ async deleteChat(chatIdInput, options = {}) {
7324
+ const teamId = this.resolveTeamContext(options);
7122
7325
  let chatId;
7123
7326
  if (chatIdInput.length < 36) {
7124
- const resolved = await this.resolveFullChatId(chatIdInput);
7327
+ const resolved = await this.resolveFullChatId(chatIdInput, { teamId });
7125
7328
  if (!resolved) {
7126
7329
  throw new Error(
7127
7330
  `Chat not found for '${chatIdInput}'. Use a full UUID or the first 8 characters of an existing chat ID.`
@@ -7133,7 +7336,7 @@ var OpenMatesClient = class _OpenMatesClient {
7133
7336
  }
7134
7337
  const { ws } = await this.openWsClient();
7135
7338
  try {
7136
- ws.send("delete_chat", { chatId });
7339
+ ws.send("delete_chat", { chatId, chat_id: chatId, ...teamId ? { team_id: teamId } : {} });
7137
7340
  await ws.waitForMessage(
7138
7341
  "chat_deleted",
7139
7342
  (payload) => {
@@ -7145,6 +7348,7 @@ var OpenMatesClient = class _OpenMatesClient {
7145
7348
  } finally {
7146
7349
  ws.close();
7147
7350
  }
7351
+ clearSyncCache(teamId);
7148
7352
  }
7149
7353
  // -------------------------------------------------------------------------
7150
7354
  // Apps
@@ -7429,10 +7633,10 @@ var OpenMatesClient = class _OpenMatesClient {
7429
7633
  // -------------------------------------------------------------------------
7430
7634
  // Workflows
7431
7635
  // -------------------------------------------------------------------------
7432
- async listWorkflows() {
7636
+ async listWorkflows(options = {}) {
7433
7637
  this.requireSession();
7434
7638
  const response = await this.http.get(
7435
- "/v1/workflows",
7639
+ this.appendTeamQuery("/v1/workflows", options),
7436
7640
  this.getCliRequestHeaders()
7437
7641
  );
7438
7642
  if (!response.ok) {
@@ -7497,10 +7701,10 @@ var OpenMatesClient = class _OpenMatesClient {
7497
7701
  }
7498
7702
  return { workflow: createLike.data.workflow, validation: createLike.data.validation };
7499
7703
  }
7500
- async getWorkflow(workflowId) {
7704
+ async getWorkflow(workflowId, options = {}) {
7501
7705
  this.requireSession();
7502
7706
  const response = await this.http.get(
7503
- `/v1/workflows/${encodeURIComponent(workflowId)}`,
7707
+ this.appendTeamQuery(`/v1/workflows/${encodeURIComponent(workflowId)}`, options),
7504
7708
  this.getCliRequestHeaders()
7505
7709
  );
7506
7710
  if (!response.ok || !response.data.workflow) {
@@ -7875,6 +8079,8 @@ var OpenMatesClient = class _OpenMatesClient {
7875
8079
  if (filters.priority !== void 0) params.set("priority", String(filters.priority));
7876
8080
  const limit = filters.limit;
7877
8081
  if (Number.isSafeInteger(limit) && limit !== void 0 && limit > 0) params.set("limit", String(limit));
8082
+ const teamId = this.resolveTeamContext({ teamId: filters.teamId, personal: filters.personal });
8083
+ if (teamId) params.set("team_id", teamId);
7878
8084
  const query = params.toString();
7879
8085
  const response = await this.http.get(
7880
8086
  `/v1/user-tasks${query ? `?${query}` : ""}`,
@@ -7995,6 +8201,8 @@ var OpenMatesClient = class _OpenMatesClient {
7995
8201
  if (filters.chatId) params.set("chat_id", filters.chatId);
7996
8202
  if (filters.projectId) params.set("project_id", filters.projectId);
7997
8203
  if (filters.activeOnly !== void 0) params.set("active_only", String(filters.activeOnly));
8204
+ const teamId = this.resolveTeamContext({ teamId: filters.teamId, personal: filters.personal });
8205
+ if (teamId) params.set("team_id", teamId);
7998
8206
  const query = params.toString();
7999
8207
  const response = await this.http.get(
8000
8208
  `/v1/user-plans${query ? `?${query}` : ""}`,
@@ -8643,9 +8851,18 @@ var OpenMatesClient = class _OpenMatesClient {
8643
8851
  * List all memories for the current user, decrypted.
8644
8852
  * Fetches from the GDPR export endpoint and decrypts each entry with the master key.
8645
8853
  */
8646
- async listMemories() {
8854
+ async sdkGetMemories(teamId) {
8855
+ const response = await this.http.get(
8856
+ `/v1/sdk/memories?team_id=${encodeURIComponent(teamId)}`,
8857
+ this.getCliRequestHeaders()
8858
+ );
8859
+ if (!response.ok) throw new Error(`Team memory list failed with HTTP ${response.status}`);
8860
+ return response.data.memories ?? [];
8861
+ }
8862
+ async listMemories(options = {}) {
8647
8863
  const masterKey = this.getMasterKeyBytes();
8648
- const data = await this.settingsGet(
8864
+ const teamId = this.resolveTeamContext(options);
8865
+ const data = teamId ? { data: { app_settings_memories: await this.sdkGetMemories(teamId) } } : await this.settingsGet(
8649
8866
  "/v1/settings/export-account-data?include_usage=false&include_invoices=false"
8650
8867
  );
8651
8868
  const rawEntries = data.data?.app_settings_memories ?? [];
@@ -8711,17 +8928,20 @@ var OpenMatesClient = class _OpenMatesClient {
8711
8928
  itemType: params.itemType,
8712
8929
  itemValue: params.itemValue,
8713
8930
  entryId: params.entryId,
8714
- itemVersion: params.currentVersion + 1
8931
+ itemVersion: params.currentVersion + 1,
8932
+ teamId: params.teamId,
8933
+ personal: params.personal
8715
8934
  });
8716
8935
  }
8717
8936
  /**
8718
8937
  * Delete a memory entry. Sends `delete_app_settings_memories_entry` over
8719
8938
  * WebSocket. The server deletes from Directus and broadcasts to all devices.
8720
8939
  */
8721
- async deleteMemory(entryId) {
8940
+ async deleteMemory(entryId, options = {}) {
8722
8941
  const { ws } = await this.openWsClient();
8723
8942
  try {
8724
- ws.send("delete_app_settings_memories_entry", { entry_id: entryId });
8943
+ const teamId = this.resolveTeamContext(options);
8944
+ ws.send("delete_app_settings_memories_entry", { entry_id: entryId, ...teamId ? { team_id: teamId } : {} });
8725
8945
  await ws.waitForMessage(
8726
8946
  "app_settings_memories_entry_deleted",
8727
8947
  (payload) => {
@@ -8774,6 +8994,7 @@ Required: ${schema.required.join(", ")}`
8774
8994
  }
8775
8995
  const entryId = params.entryId ?? randomUUID5();
8776
8996
  const now = Math.floor(Date.now() / 1e3);
8997
+ const teamId = this.resolveTeamContext({ teamId: params.teamId, personal: params.personal });
8777
8998
  const hashedKey = hashItemKey(params.appId, params.itemType);
8778
8999
  const plaintextPayload = {
8779
9000
  ...params.itemValue,
@@ -8788,6 +9009,7 @@ Required: ${schema.required.join(", ")}`
8788
9009
  const { ws } = await this.openWsClient();
8789
9010
  try {
8790
9011
  ws.send("store_app_settings_memories_entry", {
9012
+ ...teamId ? { team_id: teamId } : {},
8791
9013
  entry: {
8792
9014
  id: entryId,
8793
9015
  app_id: params.appId,
@@ -8797,7 +9019,8 @@ Required: ${schema.required.join(", ")}`
8797
9019
  encrypted_app_key: "",
8798
9020
  created_at: now,
8799
9021
  updated_at: now,
8800
- item_version: params.itemVersion
9022
+ item_version: params.itemVersion,
9023
+ ...teamId ? { team_id: teamId } : {}
8801
9024
  }
8802
9025
  });
8803
9026
  await ws.waitForMessage(
@@ -8927,7 +9150,7 @@ Required: ${schema.required.join(", ")}`
8927
9150
  const session = this.requireSession();
8928
9151
  const masterKey = base64ToBytes(session.masterKeyExportedB64);
8929
9152
  const cache = await this.ensureSynced();
8930
- const { createHash: createHash10 } = await import("crypto");
9153
+ const { createHash: createHash11 } = await import("crypto");
8931
9154
  const embed = cache.embeds.find(
8932
9155
  (e) => String(e.embed_id ?? "").startsWith(embedIdOrShort) || String(e.id ?? "").startsWith(embedIdOrShort)
8933
9156
  );
@@ -8935,7 +9158,7 @@ Required: ${schema.required.join(", ")}`
8935
9158
  throw new Error(`Embed '${embedIdOrShort}' not found in local cache.`);
8936
9159
  }
8937
9160
  const embedId = String(embed.embed_id ?? embed.id ?? "");
8938
- const hashedEmbedId = createHash10("sha256").update(embedId).digest("hex");
9161
+ const hashedEmbedId = createHash11("sha256").update(embedId).digest("hex");
8939
9162
  const embedKeyBytes = await this.resolveEmbedKey(
8940
9163
  cache,
8941
9164
  masterKey,
@@ -9043,8 +9266,8 @@ Required: ${schema.required.join(", ")}`
9043
9266
  if (!embed) {
9044
9267
  throw new Error(`Embed '${embedId}' not found in local cache. Run 'openmates chats list' to sync first.`);
9045
9268
  }
9046
- const { createHash: createHash10 } = await import("crypto");
9047
- const hashedEmbedId = createHash10("sha256").update(embedId).digest("hex");
9269
+ const { createHash: createHash11 } = await import("crypto");
9270
+ const hashedEmbedId = createHash11("sha256").update(embedId).digest("hex");
9048
9271
  const embedKey = await this.resolveEmbedKey(
9049
9272
  cache,
9050
9273
  masterKey,
@@ -9138,8 +9361,8 @@ Required: ${schema.required.join(", ")}`
9138
9361
  if (!embed) {
9139
9362
  throw new Error(`Embed '${embedId}' not found in local cache. Run 'openmates chats list' to sync first.`);
9140
9363
  }
9141
- const { createHash: createHash10 } = await import("crypto");
9142
- const hashedEmbedId = createHash10("sha256").update(embedId).digest("hex");
9364
+ const { createHash: createHash11 } = await import("crypto");
9365
+ const hashedEmbedId = createHash11("sha256").update(embedId).digest("hex");
9143
9366
  const embedKey = await this.resolveEmbedKey(
9144
9367
  cache,
9145
9368
  masterKey,
@@ -9378,13 +9601,14 @@ Required: ${schema.required.join(", ")}`
9378
9601
  * The sync cache stores encrypted data — decryption is always on-demand.
9379
9602
  * SECURITY: decrypted user content is NEVER written to disk.
9380
9603
  */
9381
- async ensureSynced(forceRefresh = false, refreshChatIds = []) {
9604
+ async ensureSynced(forceRefresh = false, refreshChatIds = [], options = {}) {
9605
+ const teamId = this.resolveTeamContext(options);
9382
9606
  const refreshChatIdSet = new Set(refreshChatIds.filter(Boolean));
9383
- if (!forceRefresh && refreshChatIdSet.size === 0 && isSyncCacheFresh()) {
9384
- const cache2 = loadSyncCache();
9607
+ if (!forceRefresh && refreshChatIdSet.size === 0 && isSyncCacheFresh(3e5, teamId)) {
9608
+ const cache2 = loadSyncCache(teamId);
9385
9609
  if (cache2) return cache2;
9386
9610
  }
9387
- const existingCache = loadSyncCache();
9611
+ const existingCache = loadSyncCache(teamId);
9388
9612
  const clientChatVersions = {};
9389
9613
  const clientChatIds = [];
9390
9614
  const clientEmbedIds = [];
@@ -9420,6 +9644,7 @@ Required: ${schema.required.join(", ")}`
9420
9644
  try {
9421
9645
  ws.send("phased_sync_request", {
9422
9646
  phase: "all",
9647
+ ...teamId ? { team_id: teamId } : {},
9423
9648
  client_chat_versions: clientChatVersions,
9424
9649
  client_chat_ids: clientChatIds,
9425
9650
  client_embed_ids: clientEmbedIds
@@ -9542,9 +9767,9 @@ Required: ${schema.required.join(", ")}`
9542
9767
  const reconciledChats = reconcileAuthoritativeChats(chats, reconciliation);
9543
9768
  chats.splice(0, chats.length, ...reconciledChats);
9544
9769
  if (reconciliation.deleted_chat_ids?.length) {
9545
- const { createHash: createHash10 } = await import("crypto");
9770
+ const { createHash: createHash11 } = await import("crypto");
9546
9771
  const deletedHashes = new Set(
9547
- reconciliation.deleted_chat_ids.map((id) => createHash10("sha256").update(id).digest("hex"))
9772
+ reconciliation.deleted_chat_ids.map((id) => createHash11("sha256").update(id).digest("hex"))
9548
9773
  );
9549
9774
  const keptEmbeds = embeds.filter((embed) => !deletedHashes.has(String(embed.hashed_chat_id ?? "")));
9550
9775
  const keptKeys = embedKeys.filter((key) => !deletedHashes.has(String(key.hashed_chat_id ?? "")));
@@ -9558,7 +9783,7 @@ Required: ${schema.required.join(", ")}`
9558
9783
  );
9559
9784
  let persistedTaskJobIds = /* @__PURE__ */ new Set();
9560
9785
  try {
9561
- await this.persistPendingAIResponsesFromSync(ws, chats, pendingAIResponses);
9786
+ await this.persistPendingAIResponsesFromSync(ws, chats, pendingAIResponses, teamId);
9562
9787
  persistedTaskJobIds = await this.persistPendingTaskUpdateJobs({
9563
9788
  ws,
9564
9789
  jobs: pendingTaskUpdateJobs,
@@ -9573,8 +9798,8 @@ Required: ${schema.required.join(", ")}`
9573
9798
  ws.close();
9574
9799
  }
9575
9800
  if (persistedTaskJobIds.size > 0) {
9576
- clearSyncCache();
9577
- return this.ensureSynced(true, refreshChatIds);
9801
+ clearSyncCache(teamId);
9802
+ return this.ensureSynced(true, refreshChatIds, { teamId });
9578
9803
  }
9579
9804
  const cache = {
9580
9805
  syncedAt: Date.now(),
@@ -9586,10 +9811,10 @@ Required: ${schema.required.join(", ")}`
9586
9811
  chatKeyWrappers,
9587
9812
  newChatSuggestions
9588
9813
  };
9589
- saveSyncCache(cache);
9814
+ saveSyncCache(cache, teamId);
9590
9815
  return cache;
9591
9816
  }
9592
- async persistPendingAIResponsesFromSync(ws, chats, pendingResponses) {
9817
+ async persistPendingAIResponsesFromSync(ws, chats, pendingResponses, teamId) {
9593
9818
  if (pendingResponses.length === 0) return;
9594
9819
  const masterKey = this.getMasterKeyBytes();
9595
9820
  for (const pending of pendingResponses) {
@@ -9615,7 +9840,7 @@ Required: ${schema.required.join(", ")}`
9615
9840
  } catch {
9616
9841
  }
9617
9842
  }
9618
- const chatKeyBytes = await this.resolveChatKey(loadSyncCache(), chat, masterKey);
9843
+ const chatKeyBytes = await this.resolveChatKey(loadSyncCache(teamId), chat, masterKey);
9619
9844
  if (!chatKeyBytes) continue;
9620
9845
  const completedAt = normalizeUnixSeconds(
9621
9846
  pending.fired_at,
@@ -10000,6 +10225,70 @@ var APP_SKILL_METADATA = [
10000
10225
  "properties": {}
10001
10226
  }
10002
10227
  },
10228
+ {
10229
+ "app_id": "design",
10230
+ "skill_id": "search_icons",
10231
+ "app_namespace_ts": "design",
10232
+ "skill_method_ts": "searchIcons",
10233
+ "app_namespace_py": "design",
10234
+ "skill_method_py": "search_icons",
10235
+ "description_key": "app_skills.design.search_icons.description",
10236
+ "description": "Search for free SVG icons for UI, product, interface, or graphic design. Use this when the user asks to find icons by name, concept, object, or action. Do not use it for brand-logo search or generated icon creation.",
10237
+ "schema": {
10238
+ "type": "object",
10239
+ "properties": {
10240
+ "requests": {
10241
+ "type": "array",
10242
+ "description": "Array of icon search requests backed by Iconify.",
10243
+ "items": {
10244
+ "type": "object",
10245
+ "properties": {
10246
+ "query": {
10247
+ "type": "string",
10248
+ "description": 'Search query, e.g. "home", "calendar", or "settings".'
10249
+ },
10250
+ "count": {
10251
+ "type": "integer",
10252
+ "minimum": 1,
10253
+ "maximum": 50,
10254
+ "default": 24,
10255
+ "description": "Maximum number of icon results to return."
10256
+ },
10257
+ "license_policy": {
10258
+ "type": "string",
10259
+ "enum": [
10260
+ "permissive",
10261
+ "all"
10262
+ ],
10263
+ "default": "permissive",
10264
+ "description": "Filter to permissive/no-attribution licenses by default."
10265
+ },
10266
+ "include_prefixes": {
10267
+ "type": "array",
10268
+ "items": {
10269
+ "type": "string"
10270
+ },
10271
+ "description": "Optional Iconify collection prefixes to include."
10272
+ },
10273
+ "exclude_prefixes": {
10274
+ "type": "array",
10275
+ "items": {
10276
+ "type": "string"
10277
+ },
10278
+ "description": "Optional Iconify collection prefixes to exclude."
10279
+ }
10280
+ },
10281
+ "required": [
10282
+ "query"
10283
+ ]
10284
+ }
10285
+ }
10286
+ },
10287
+ "required": [
10288
+ "requests"
10289
+ ]
10290
+ }
10291
+ },
10003
10292
  {
10004
10293
  "app_id": "electronics",
10005
10294
  "skill_id": "search_components",
@@ -13180,6 +13469,20 @@ var CodeAppSkills = class {
13180
13469
  return this.runSkill("code", "search_repos", input);
13181
13470
  }
13182
13471
  };
13472
+ var DesignAppSkills = class {
13473
+ runSkill;
13474
+ constructor(runSkill) {
13475
+ this.runSkill = runSkill;
13476
+ }
13477
+ /**
13478
+ * Search for free SVG icons for UI, product, interface, or graphic design. Use this when the user asks to find icons by name, concept, object, or action. Do not use it for brand-logo search or generated icon creation.
13479
+ * Description key: app_skills.design.search_icons.description
13480
+ * Skill: design/search_icons
13481
+ */
13482
+ async searchIcons(input) {
13483
+ return this.runSkill("design", "search_icons", input);
13484
+ }
13485
+ };
13183
13486
  var ElectronicsAppSkills = class {
13184
13487
  runSkill;
13185
13488
  constructor(runSkill) {
@@ -13673,6 +13976,7 @@ var GeneratedAppSkills = class {
13673
13976
  this.ai = new AiAppSkills(runSkill);
13674
13977
  this.books = new BooksAppSkills(runSkill);
13675
13978
  this.code = new CodeAppSkills(runSkill);
13979
+ this.design = new DesignAppSkills(runSkill);
13676
13980
  this.electronics = new ElectronicsAppSkills(runSkill);
13677
13981
  this.events = new EventsAppSkills(runSkill);
13678
13982
  this.fitness = new FitnessAppSkills(runSkill);
@@ -13701,6 +14005,7 @@ var GeneratedAppSkills = class {
13701
14005
  ai;
13702
14006
  books;
13703
14007
  code;
14008
+ design;
13704
14009
  electronics;
13705
14010
  events;
13706
14011
  fitness;
@@ -13729,7 +14034,7 @@ var GeneratedAppSkills = class {
13729
14034
 
13730
14035
  // src/sdk.ts
13731
14036
  import { decode as toonDecode } from "@toon-format/toon";
13732
- import { createHash as createHash7, randomBytes as randomBytes3, randomUUID as randomUUID6 } from "crypto";
14037
+ import { createHash as createHash8, randomBytes as randomBytes4, randomUUID as randomUUID6 } from "crypto";
13733
14038
  import { chmodSync as chmodSync2, existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
13734
14039
  import { homedir as homedir4 } from "os";
13735
14040
  import { dirname, join as join3 } from "path";
@@ -13867,7 +14172,7 @@ var OpenMates = class {
13867
14172
  }
13868
14173
  async resolveEmbedKeyForShare(embedKeys, embedId) {
13869
14174
  const masterKey = await this.getMasterKey();
13870
- const hashedEmbedId = createHash7("sha256").update(embedId).digest("hex");
14175
+ const hashedEmbedId = createHash8("sha256").update(embedId).digest("hex");
13871
14176
  return this.resolveLoadedEmbedKey(embedKeys, hashedEmbedId, masterKey, masterKey);
13872
14177
  }
13873
14178
  async decryptChatMetadata(chat, chatKeyWrappers) {
@@ -13924,7 +14229,7 @@ var OpenMates = class {
13924
14229
  }
13925
14230
  async resolveLoadedChatKey(chat, chatKeyWrappers) {
13926
14231
  const masterKey = await this.getMasterKey();
13927
- const hashedChatId = createHash7("sha256").update(chat.id).digest("hex");
14232
+ const hashedChatId = createHash8("sha256").update(chat.id).digest("hex");
13928
14233
  const wrapper = (chatKeyWrappers ?? []).find(
13929
14234
  (entry) => entry.key_type === "master" && entry.hashed_chat_id === hashedChatId && typeof entry.encrypted_chat_key === "string"
13930
14235
  );
@@ -13938,7 +14243,7 @@ var OpenMates = class {
13938
14243
  if (!embedId) {
13939
14244
  return { ...embed };
13940
14245
  }
13941
- const hashedEmbedId = createHash7("sha256").update(embedId).digest("hex");
14246
+ const hashedEmbedId = createHash8("sha256").update(embedId).digest("hex");
13942
14247
  const embedKey = await this.resolveLoadedEmbedKey(embedKeys, hashedEmbedId, masterKey, chatKey);
13943
14248
  if (!embedKey) {
13944
14249
  return { ...embed };
@@ -14171,7 +14476,7 @@ var OpenMatesChats = class {
14171
14476
  encryptedChatKey = chat.encrypted_chat_key;
14172
14477
  expectedMessagesV = Number(chat.messages_v ?? 0);
14173
14478
  } else {
14174
- chatKey = new Uint8Array(randomBytes3(32));
14479
+ chatKey = new Uint8Array(randomBytes4(32));
14175
14480
  encryptedChatKey = await encryptBytesWithAesGcm(chatKey, masterKey);
14176
14481
  encryptedChatMetadata = {
14177
14482
  encrypted_title: await encryptWithAesGcmCombined(options.title ?? message.slice(0, 80), chatKey),
@@ -16024,7 +16329,7 @@ var OutputRedactor = class {
16024
16329
  import { readFileSync as readFileSync5, statSync, existsSync as existsSync6 } from "fs";
16025
16330
  import { basename, extname, resolve as resolve2 } from "path";
16026
16331
  import { homedir as homedir5 } from "os";
16027
- import { createHash as createHash8 } from "crypto";
16332
+ import { createHash as createHash9 } from "crypto";
16028
16333
  var MAX_PER_FILE_SIZE = 100 * 1024 * 1024;
16029
16334
  var BLOCKED_EXTENSIONS = /* @__PURE__ */ new Set([
16030
16335
  ".pem",
@@ -16334,7 +16639,7 @@ function processCodeFile(filePath, filename, redactor) {
16334
16639
  line_count: lineCount
16335
16640
  });
16336
16641
  const textPreview = `${filename} (${language}, ${lineCount} lines)`;
16337
- const contentHash = createHash8("sha256").update(content).digest("hex");
16642
+ const contentHash = createHash9("sha256").update(content).digest("hex");
16338
16643
  const embed = {
16339
16644
  embedId,
16340
16645
  embedRef,
@@ -17889,7 +18194,7 @@ function formatTs(ts) {
17889
18194
 
17890
18195
  // src/server.ts
17891
18196
  import { execFileSync as execFileSync2, execSync, spawn as nodeSpawn, spawnSync } from "child_process";
17892
- import { createHash as createHash9, randomBytes as randomBytes4 } from "crypto";
18197
+ import { createHash as createHash10, randomBytes as randomBytes5 } from "crypto";
17893
18198
  import { chmodSync as chmodSync3, closeSync, copyFileSync, cpSync, existsSync as existsSync7, mkdirSync as mkdirSync4, mkdtempSync, openSync, readFileSync as readFileSync6, readSync, readdirSync, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "fs";
17894
18199
  import { createInterface as createInterface3 } from "readline";
17895
18200
  import { createInterface as createPromptInterface } from "readline/promises";
@@ -18507,10 +18812,10 @@ function resolveTargetImageTag(flags, currentTag, packageVersion) {
18507
18812
  return { tag: getDefaultImageTagForVersion(packageVersion) };
18508
18813
  }
18509
18814
  function randomHex(bytes) {
18510
- return randomBytes4(bytes).toString("hex");
18815
+ return randomBytes5(bytes).toString("hex");
18511
18816
  }
18512
18817
  function generateInviteCode() {
18513
- const digits = Array.from(randomBytes4(12), (byte) => String(byte % 10)).join("");
18818
+ const digits = Array.from(randomBytes5(12), (byte) => String(byte % 10)).join("");
18514
18819
  return `${digits.slice(0, 4)}-${digits.slice(4, 8)}-${digits.slice(8, 12)}`;
18515
18820
  }
18516
18821
  function getEnvVar(content, name) {
@@ -18554,7 +18859,7 @@ function packagedCaddyTemplatePath(role) {
18554
18859
  }
18555
18860
  function fileHash(path) {
18556
18861
  if (!existsSync7(path)) return null;
18557
- return createHash9("sha256").update(readFileSync6(path)).digest("hex");
18862
+ return createHash10("sha256").update(readFileSync6(path)).digest("hex");
18558
18863
  }
18559
18864
  async function loadSelfHostComposeTemplate(templateRef, role) {
18560
18865
  const templateDir = process.env.OPENMATES_SELFHOST_TEMPLATE_DIR;
@@ -18940,7 +19245,7 @@ function formatSecretPreflight(preflight) {
18940
19245
  return parts.join("; ");
18941
19246
  }
18942
19247
  function hashFile(path) {
18943
- const hash = createHash9("sha256");
19248
+ const hash = createHash10("sha256");
18944
19249
  const fd = openSync(path, "r");
18945
19250
  const buffer = Buffer.allocUnsafe(CHECKSUM_BUFFER_BYTES);
18946
19251
  try {
@@ -45934,7 +46239,7 @@ As of mid-2026, the severe supply shocks from the 2024\u20132025 avian flu have
45934
46239
  text: "Web, search, and content retrieval (only when you use a web or search skill)"
45935
46240
  },
45936
46241
  description: {
45937
- text: "These providers are only used when you invoke a web, videos, news, or web-read skill. They see the content of what you search for or the URLs you ask to read, but no user identifier \u2014 they do not know which OpenMates user made each request."
46242
+ text: "These providers are only used when you invoke a web, videos, news, web-read, or design icon search skill. They see the content of what you search for, the URLs you ask to read, or the public icon identifiers you ask to preview, but no user identifier \u2014 they do not know which OpenMates user made each request."
45938
46243
  },
45939
46244
  brave: {
45940
46245
  heading: {
@@ -45952,6 +46257,14 @@ As of mid-2026, the severe supply shocks from the 2024\u20132025 avian flu have
45952
46257
  text: "Firecrawl powers the web read skill, scraping and extracting content from web pages you ask about. Firecrawl sees the URL you requested and the full content of the scraped page."
45953
46258
  }
45954
46259
  },
46260
+ iconify: {
46261
+ heading: {
46262
+ text: "Iconify (public SVG icon search)"
46263
+ },
46264
+ description: {
46265
+ text: "Iconify powers the design.search_icons skill. Iconify sees icon search queries and the icon collection/name needed to fetch SVG previews, but no OpenMates user identifier. OpenMates fetches Iconify data server-side and clients do not call Iconify directly."
46266
+ }
46267
+ },
45955
46268
  webshare: {
45956
46269
  heading: {
45957
46270
  text: "Webshare (rotating proxy)"
@@ -58078,6 +58391,10 @@ async function main() {
58078
58391
  printTasksHelp();
58079
58392
  return;
58080
58393
  }
58394
+ if (command === "teams") {
58395
+ printTeamsHelp();
58396
+ return;
58397
+ }
58081
58398
  if (command === "connected-accounts") {
58082
58399
  printConnectedAccountsHelp();
58083
58400
  return;
@@ -58200,6 +58517,10 @@ async function main() {
58200
58517
  await handleTasks(client, subcommand, rest, parsed.flags);
58201
58518
  return;
58202
58519
  }
58520
+ if (command === "teams") {
58521
+ await handleTeams(client, subcommand, rest, parsed.flags);
58522
+ return;
58523
+ }
58203
58524
  if (command === "drafts") {
58204
58525
  await handleDrafts(client, subcommand, rest, parsed.flags);
58205
58526
  return;
@@ -58469,11 +58790,12 @@ function taskScopeFromFlags(flags, masterKey) {
58469
58790
  projectId: typeof flags.project === "string" ? flags.project : void 0,
58470
58791
  planId: typeof flags.plan === "string" ? flags.plan : void 0,
58471
58792
  labelHashes: labelHashes(masterKey, labelFlags(flags)),
58472
- priority: typeof flags.priority === "string" ? normalizeTaskPriority(flags.priority) : void 0
58793
+ priority: typeof flags.priority === "string" ? normalizeTaskPriority(flags.priority) : void 0,
58794
+ ...teamContextFromFlags(flags)
58473
58795
  };
58474
58796
  }
58475
58797
  async function loadTasks(client, masterKey, scope) {
58476
- const records = await client.listUserTasks({ status: scope.status, chatId: scope.chatId, projectId: scope.projectId, labelHashes: scope.labelHashes, priority: scope.priority });
58798
+ const records = await client.listUserTasks({ status: scope.status, chatId: scope.chatId, projectId: scope.projectId, labelHashes: scope.labelHashes, priority: scope.priority, teamId: scope.teamId, personal: scope.personal });
58477
58799
  const tasks = await decryptUserTasks(records, masterKey);
58478
58800
  return scope.planId ? tasks.filter((task) => task.planId === scope.planId) : tasks;
58479
58801
  }
@@ -58488,6 +58810,252 @@ function printTaskOutput(task, flags) {
58488
58810
  if (flags.json === true) printJson2({ task: taskToJson(task) });
58489
58811
  else console.log(renderTaskDetail(task));
58490
58812
  }
58813
+ async function handleTeams(client, subcommand, rest, flags) {
58814
+ if (!subcommand || subcommand === "help" || flags.help === true) {
58815
+ printTeamsHelp();
58816
+ return;
58817
+ }
58818
+ if (subcommand === "list") {
58819
+ const teams = await client.listTeams();
58820
+ printTeamsOutput(teams, client.getActiveTeamId(), flags);
58821
+ return;
58822
+ }
58823
+ if (subcommand === "switch") {
58824
+ const teamId = requireTeamId(rest, flags);
58825
+ client.setActiveTeamId(teamId);
58826
+ if (flags.json === true) printJson2({ active_team_id: teamId, context: "team" });
58827
+ else console.log(`Active team: ${teamId}`);
58828
+ return;
58829
+ }
58830
+ if (subcommand === "personal") {
58831
+ client.setActiveTeamId(null);
58832
+ if (flags.json === true) printJson2({ active_team_id: null, context: "personal" });
58833
+ else console.log("Active context: personal");
58834
+ return;
58835
+ }
58836
+ if (subcommand === "show") {
58837
+ const teamId = requireTeamId(rest, flags);
58838
+ const team = await client.getTeam(teamId);
58839
+ if (flags.json === true) printJson2({ team, active_team_id: client.getActiveTeamId() });
58840
+ else printTeamRecord(team, client.getActiveTeamId());
58841
+ return;
58842
+ }
58843
+ if (subcommand === "create") {
58844
+ const name = requiredStringFlag(flags.name, "--name <name>");
58845
+ const team = await client.createTeam({
58846
+ name,
58847
+ description: typeof flags.description === "string" ? flags.description : void 0,
58848
+ slug: typeof flags.slug === "string" ? flags.slug : void 0
58849
+ });
58850
+ if (flags.switch === true || flags.activate === true) {
58851
+ const teamId = team.team_id ?? team.id;
58852
+ if (typeof teamId === "string") client.setActiveTeamId(teamId);
58853
+ }
58854
+ if (flags.json === true) printJson2({ team, active_team_id: client.getActiveTeamId() });
58855
+ else printTeamRecord(team, client.getActiveTeamId());
58856
+ return;
58857
+ }
58858
+ if (subcommand === "update") {
58859
+ const teamId = requireTeamId(rest, flags);
58860
+ const patch = {};
58861
+ if (typeof flags.name === "string") patch.encrypted_name = flags.name;
58862
+ if (typeof flags.description === "string") patch.encrypted_description = flags.description;
58863
+ if (typeof flags.slug === "string") patch.slug = flags.slug;
58864
+ if (Object.keys(patch).length === 0) throw new Error("Nothing to update. Provide --name, --description, or --slug.");
58865
+ const team = await client.updateTeam(teamId, patch);
58866
+ if (flags.json === true) printJson2({ team });
58867
+ else printTeamRecord(team, client.getActiveTeamId());
58868
+ return;
58869
+ }
58870
+ if (subcommand === "delete") {
58871
+ const teamId = requireTeamId(rest, flags);
58872
+ if (flags.yes !== true && flags.confirm !== true) throw new Error("Deleting a team requires --yes.");
58873
+ const result = await client.deleteTeam(teamId);
58874
+ if (client.getActiveTeamId() === teamId) client.setActiveTeamId(null);
58875
+ if (flags.json === true) printJson2(result);
58876
+ else console.log(`Team deleted: ${teamId}`);
58877
+ return;
58878
+ }
58879
+ if (subcommand === "invite") {
58880
+ const teamId = requireTeamId(rest, flags);
58881
+ const input = {};
58882
+ if (typeof flags.email === "string") input.recipient_email = flags.email;
58883
+ if (typeof flags.user === "string") input.invitee_user_id = flags.user;
58884
+ if (typeof flags["encrypted-recipient-hint"] === "string") input.encrypted_recipient_hint = flags["encrypted-recipient-hint"];
58885
+ if (typeof flags["expires-at"] === "string") input.expires_at = Number.parseInt(flags["expires-at"], 10);
58886
+ input.role = parseTeamInviteRole(flags.role);
58887
+ const invite = await client.createTeamInvite(teamId, input);
58888
+ if (flags.json === true) printJson2({ invite });
58889
+ else printJson2(invite);
58890
+ return;
58891
+ }
58892
+ if (subcommand === "accept-invite") {
58893
+ const inviteId = requiredStringFlag(flags.invite ?? rest[0], "<invite-id>");
58894
+ const result = await client.acceptTeamInvite(inviteId);
58895
+ if (flags.json === true) printJson2(result);
58896
+ else printJson2(result);
58897
+ return;
58898
+ }
58899
+ if (subcommand === "decline-invite") {
58900
+ const inviteId = requiredStringFlag(flags.invite ?? rest[0], "<invite-id>");
58901
+ const result = await client.declineTeamInvite(inviteId);
58902
+ if (flags.json === true) printJson2(result);
58903
+ else console.log("Team invite declined.");
58904
+ return;
58905
+ }
58906
+ if (subcommand === "access-requests") {
58907
+ const teamId = requireTeamId(rest, flags);
58908
+ const status = typeof flags.status === "string" ? flags.status : void 0;
58909
+ const accessRequests = await client.listTeamAccessRequests(teamId, status);
58910
+ if (flags.json === true) printJson2({ access_requests: accessRequests });
58911
+ else printJson2(accessRequests);
58912
+ return;
58913
+ }
58914
+ if (subcommand === "approve-access") {
58915
+ const teamId = requireTeamId(rest, flags);
58916
+ const accessRequestId = requiredStringFlag(flags.request ?? flags["access-request"] ?? rest[1], "<access-request-id>");
58917
+ const encryptedTeamKey = requiredStringFlag(flags["encrypted-team-key"], "--encrypted-team-key <value>");
58918
+ const membership = await client.approveTeamAccessRequest(teamId, accessRequestId, encryptedTeamKey);
58919
+ if (flags.json === true) printJson2({ membership });
58920
+ else printJson2(membership);
58921
+ return;
58922
+ }
58923
+ if (subcommand === "reject-access") {
58924
+ const teamId = requireTeamId(rest, flags);
58925
+ const accessRequestId = requiredStringFlag(flags.request ?? flags["access-request"] ?? rest[1], "<access-request-id>");
58926
+ const result = await client.rejectTeamAccessRequest(teamId, accessRequestId);
58927
+ if (flags.json === true) printJson2(result);
58928
+ else console.log(`Team access request rejected: ${accessRequestId}`);
58929
+ return;
58930
+ }
58931
+ if (subcommand === "role") {
58932
+ const teamId = requireTeamId(rest, flags);
58933
+ const memberUserId = requiredStringFlag(flags.user ?? rest[1], "--user <user-id>");
58934
+ const role = parseTeamAssignableRole(flags.role);
58935
+ const membership = await client.updateTeamMemberRole(teamId, memberUserId, role);
58936
+ if (flags.json === true) printJson2({ membership });
58937
+ else printJson2(membership);
58938
+ return;
58939
+ }
58940
+ if (subcommand === "remove-member") {
58941
+ const teamId = requireTeamId(rest, flags);
58942
+ const memberUserId = requiredStringFlag(flags.user ?? rest[1], "--user <user-id>");
58943
+ const result = await client.removeTeamMember(teamId, memberUserId);
58944
+ if (flags.json === true) printJson2(result);
58945
+ else console.log(`Team member removed: ${memberUserId}`);
58946
+ return;
58947
+ }
58948
+ if (subcommand === "billing") {
58949
+ const teamId = requireTeamId(rest, flags);
58950
+ const billing = await client.getTeamBilling(teamId);
58951
+ if (flags.json === true) printJson2({ billing });
58952
+ else printJson2(billing);
58953
+ return;
58954
+ }
58955
+ if (subcommand === "add-credits") {
58956
+ const teamId = requireTeamId(rest, flags);
58957
+ const credits = requiredNumberFlag(flags.credits, "--credits <amount>");
58958
+ const billing = await client.addTeamCredits(teamId, { credits });
58959
+ if (flags.json === true) printJson2({ billing });
58960
+ else printJson2(billing);
58961
+ return;
58962
+ }
58963
+ if (subcommand === "usage") {
58964
+ const teamId = requireTeamId(rest, flags);
58965
+ const usage = await client.listTeamUsage(teamId, typeof flags.user === "string" ? flags.user : void 0);
58966
+ if (flags.json === true) printJson2({ usage });
58967
+ else printJson2(usage);
58968
+ return;
58969
+ }
58970
+ if (subcommand === "move") {
58971
+ const teamId = requireTeamId(rest, flags);
58972
+ const workspaceType = parseWorkspaceMoveType(flags.type ?? rest[1]);
58973
+ const objectId = requiredStringFlag(flags.id ?? rest[2], "--id <resource-id>");
58974
+ if (flags.yes !== true && flags.confirm !== true) throw new Error("Moving a workspace resource requires --yes.");
58975
+ const result = await client.moveWorkspaceToTeam(workspaceType, objectId, teamId);
58976
+ if (flags.json === true) printJson2(result);
58977
+ else console.log(`${workspaceType} moved to team ${teamId}: ${objectId}`);
58978
+ return;
58979
+ }
58980
+ if (subcommand === "export") {
58981
+ const teamId = requireTeamId(rest, flags);
58982
+ const output = requiredStringFlag(flags.output, "--output <path>");
58983
+ const result = await client.exportTeamData(teamId);
58984
+ const artifact = result.artifact && typeof result.artifact === "object" ? result.artifact : result;
58985
+ writeFileSync7(output, `${JSON.stringify(artifact, null, 2)}
58986
+ `, { encoding: "utf-8", mode: 384 });
58987
+ if (flags.json === true) printJson2({ ...result, output });
58988
+ else console.log(`Team export written: ${output}`);
58989
+ return;
58990
+ }
58991
+ if (subcommand === "import") {
58992
+ const file = requiredStringFlag(flags.file ?? rest[0], "--file <path>");
58993
+ const artifact = JSON.parse(readFileSync10(file, "utf-8"));
58994
+ let teamId = typeof flags.team === "string" ? flags.team : typeof flags["destination-team"] === "string" ? flags["destination-team"] : void 0;
58995
+ if (!teamId && typeof flags["new-team-name"] === "string") {
58996
+ const team = await client.createTeam({ name: flags["new-team-name"] });
58997
+ teamId = typeof team.team_id === "string" ? team.team_id : typeof team.id === "string" ? team.id : void 0;
58998
+ }
58999
+ if (!teamId) throw new Error("Team import requires --team <team-id> or --new-team-name <name>.");
59000
+ const result = await client.importTeamData(teamId, artifact);
59001
+ if (flags.json === true) printJson2(result);
59002
+ else printJson2(result);
59003
+ return;
59004
+ }
59005
+ throw new Error(`Unknown teams command '${subcommand}'. Run 'openmates teams --help'.`);
59006
+ }
59007
+ function requireTeamId(rest, flags) {
59008
+ return requiredStringFlag(flags.team ?? flags["team-id"] ?? rest[0], "--team <team-id>");
59009
+ }
59010
+ function requiredStringFlag(value, label) {
59011
+ if (typeof value !== "string" || value.trim().length === 0) throw new Error(`Missing ${label}.`);
59012
+ return value.trim();
59013
+ }
59014
+ function requiredNumberFlag(value, label) {
59015
+ const raw = requiredStringFlag(value, label);
59016
+ const parsed = Number(raw);
59017
+ if (!Number.isFinite(parsed) || parsed <= 0) throw new Error(`Invalid ${label}: ${raw}`);
59018
+ return parsed;
59019
+ }
59020
+ function parseTeamInviteRole(value) {
59021
+ if (value === void 0 || value === false) return "member";
59022
+ return parseTeamAssignableRole(value);
59023
+ }
59024
+ function parseTeamAssignableRole(value) {
59025
+ const role = requiredStringFlag(value, "--role <admin|member|viewer>");
59026
+ if (role === "admin" || role === "member" || role === "viewer") return role;
59027
+ throw new Error("Team role must be admin, member, or viewer.");
59028
+ }
59029
+ function parseWorkspaceMoveType(value) {
59030
+ const type = requiredStringFlag(value, "--type <chat|project|task|plan|workflow>");
59031
+ if (type === "chat" || type === "project" || type === "task" || type === "plan" || type === "workflow") return type;
59032
+ throw new Error("Workspace type must be chat, project, task, plan, or workflow.");
59033
+ }
59034
+ function teamContextFromFlags(flags) {
59035
+ if (flags.personal === true) return { personal: true };
59036
+ if (typeof flags.team === "string") return { teamId: flags.team };
59037
+ if (typeof flags["team-id"] === "string") return { teamId: flags["team-id"] };
59038
+ return {};
59039
+ }
59040
+ function printTeamsOutput(teams, activeTeamId, flags) {
59041
+ if (flags.json === true) {
59042
+ printJson2({ teams, active_team_id: activeTeamId });
59043
+ return;
59044
+ }
59045
+ if (teams.length === 0) {
59046
+ console.log("No teams.");
59047
+ return;
59048
+ }
59049
+ for (const team of teams) printTeamRecord(team, activeTeamId);
59050
+ }
59051
+ function printTeamRecord(team, activeTeamId) {
59052
+ const teamId = typeof team.team_id === "string" ? team.team_id : typeof team.id === "string" ? team.id : "unknown";
59053
+ const activeMarker = activeTeamId === teamId ? " *" : "";
59054
+ console.log(`${teamId}${activeMarker}`);
59055
+ if (typeof team.slug === "string") kv("slug", team.slug);
59056
+ if (typeof team.role === "string") kv("role", team.role);
59057
+ if (typeof team.status === "string") kv("status", team.status);
59058
+ }
58491
59059
  function taskToJson(task) {
58492
59060
  return {
58493
59061
  task_id: task.taskId,
@@ -58693,6 +59261,7 @@ async function handleChats(client, subcommand, rest, flags, redactor) {
58693
59261
  return;
58694
59262
  }
58695
59263
  const apiKey = resolveApiKey(flags) ?? void 0;
59264
+ const teamContext = teamContextFromFlags(flags);
58696
59265
  if (rest[0] === "tasks") {
58697
59266
  await handleTasks(client, rest[1], rest.slice(2), { ...flags, chat: subcommand });
58698
59267
  return;
@@ -58700,7 +59269,7 @@ async function handleChats(client, subcommand, rest, flags, redactor) {
58700
59269
  if (subcommand === "list") {
58701
59270
  const limit = typeof flags.limit === "string" ? parseInt(flags.limit, 10) : 10;
58702
59271
  const page = typeof flags.page === "string" ? parseInt(flags.page, 10) : 1;
58703
- const result = apiKey ? await listApiKeyChats(client, apiKey, limit, page) : client.hasSession() ? await client.listChats(limit, page) : listExampleChats(limit, page);
59272
+ const result = apiKey ? await listApiKeyChats(client, apiKey, limit, page) : client.hasSession() ? await client.listChats(limit, page, teamContext) : listExampleChats(limit, page);
58704
59273
  if (flags.json === true) {
58705
59274
  printJson2(result);
58706
59275
  } else {
@@ -58714,7 +59283,7 @@ async function handleChats(client, subcommand, rest, flags, redactor) {
58714
59283
  throw new Error(
58715
59284
  "Missing search query. Usage: openmates chats search <query>"
58716
59285
  );
58717
- const result = apiKey ? await searchApiKeyChats(client, apiKey, query) : client.hasSession() ? await client.searchChats(query) : searchExampleChats(query);
59286
+ const result = apiKey ? await searchApiKeyChats(client, apiKey, query) : client.hasSession() ? await client.searchChats(query, teamContext) : searchExampleChats(query);
58718
59287
  if (flags.json === true) {
58719
59288
  printJson2(result);
58720
59289
  } else {
@@ -58746,6 +59315,7 @@ async function handleChats(client, subcommand, rest, flags, redactor) {
58746
59315
  acceptTaskProposals: flags["accept-task-proposals"] === true,
58747
59316
  piiDetection: flags["no-pii-detection"] !== true,
58748
59317
  responseTimeoutMs: parseResponseTimeoutMs(flags),
59318
+ ...teamContext,
58749
59319
  anonymousLearningMode: client.hasSession() ? void 0 : parseAnonymousLearningModeFlags(flags)
58750
59320
  },
58751
59321
  redactor
@@ -58771,14 +59341,14 @@ async function handleChats(client, subcommand, rest, flags, redactor) {
58771
59341
  );
58772
59342
  process.exit(1);
58773
59343
  }
58774
- const fullId = await client.resolveFullChatId(chatId).catch(() => void 0);
59344
+ const fullId = await client.resolveFullChatId(chatId, teamContext).catch(() => void 0);
58775
59345
  if (!fullId) {
58776
59346
  console.error(
58777
59347
  `Chat '${chatId}' not found. Run 'openmates chats list' to see available chats.`
58778
59348
  );
58779
59349
  process.exit(1);
58780
59350
  }
58781
- const suggestions = await client.getChatFollowUpSuggestions(fullId);
59351
+ const suggestions = await client.getChatFollowUpSuggestions(fullId, teamContext);
58782
59352
  if (suggestions.length === 0) {
58783
59353
  console.error(
58784
59354
  `No follow-up suggestions stored for chat '${chatId}'.
@@ -58822,7 +59392,8 @@ Run 'openmates chats show ` + chatId + "' to check if suggestions have been save
58822
59392
  autoApproveMemories: flags["auto-approve-memories"] === true,
58823
59393
  acceptTaskProposals: flags["accept-task-proposals"] === true,
58824
59394
  piiDetection: flags["no-pii-detection"] !== true,
58825
- responseTimeoutMs: parseResponseTimeoutMs(flags)
59395
+ responseTimeoutMs: parseResponseTimeoutMs(flags),
59396
+ ...teamContext
58826
59397
  },
58827
59398
  redactor
58828
59399
  );
@@ -58852,7 +59423,8 @@ Run 'openmates chats show ` + chatId + "' to check if suggestions have been save
58852
59423
  autoApproveMemories: flags["auto-approve-memories"] === true,
58853
59424
  acceptTaskProposals: flags["accept-task-proposals"] === true,
58854
59425
  piiDetection: flags["no-pii-detection"] !== true,
58855
- responseTimeoutMs: parseResponseTimeoutMs(flags)
59426
+ responseTimeoutMs: parseResponseTimeoutMs(flags),
59427
+ ...teamContext
58856
59428
  },
58857
59429
  redactor
58858
59430
  );
@@ -58918,14 +59490,14 @@ Run 'openmates chats show ` + chatId + "' to check if suggestions have been save
58918
59490
  }
58919
59491
  return;
58920
59492
  }
58921
- const { chat, messages } = await client.getChatMessages(resolvedId);
59493
+ const { chat, messages } = await client.getChatMessages(resolvedId, teamContext);
58922
59494
  if (flags.json === true) {
58923
- const followUpSuggestions = await client.getChatFollowUpSuggestions(chat.id).catch(() => []);
59495
+ const followUpSuggestions = await client.getChatFollowUpSuggestions(chat.id, teamContext).catch(() => []);
58924
59496
  printJson2({ chat, messages, follow_up_suggestions: followUpSuggestions });
58925
59497
  } else if (flags.raw === true) {
58926
59498
  await printChatConversationRaw(chat, messages);
58927
59499
  } else {
58928
- const followUpSuggestions = await client.getChatFollowUpSuggestions(chat.id).catch(() => []);
59500
+ const followUpSuggestions = await client.getChatFollowUpSuggestions(chat.id, teamContext).catch(() => []);
58929
59501
  await printChatConversation(client, chat, messages, followUpSuggestions);
58930
59502
  }
58931
59503
  return;
@@ -58940,7 +59512,7 @@ Run 'openmates chats show ` + chatId + "' to check if suggestions have been save
58940
59512
  const resolved = [];
58941
59513
  for (const id of chatIds) {
58942
59514
  try {
58943
- const { chat } = await client.getChatMessages(id);
59515
+ const { chat } = await client.getChatMessages(id, teamContext);
58944
59516
  resolved.push({ input: id, title: chat.title ?? null });
58945
59517
  } catch {
58946
59518
  resolved.push({ input: id, title: null });
@@ -58980,7 +59552,7 @@ Run 'openmates chats show ` + chatId + "' to check if suggestions have been save
58980
59552
  { confirmed: true }
58981
59553
  );
58982
59554
  } else {
58983
- await client.deleteChat(r.input);
59555
+ await client.deleteChat(r.input, teamContext);
58984
59556
  }
58985
59557
  const label = r.title ? `"${r.title}"` : r.input;
58986
59558
  process.stdout.write(` \x1B[32m\u2713\x1B[0m Deleted ${label}
@@ -59006,7 +59578,7 @@ ${deleted}/${resolved.length} chat(s) deleted.`);
59006
59578
  process.exit(1);
59007
59579
  }
59008
59580
  const resolvedId = chatId.toLowerCase() === "last" ? "__last__" : chatId;
59009
- const { chat, messages } = await client.getChatMessages(resolvedId);
59581
+ const { chat, messages } = await client.getChatMessages(resolvedId, teamContext);
59010
59582
  const outputDir = typeof flags.output === "string" ? flags.output : process.cwd();
59011
59583
  const useZip = flags.zip === true;
59012
59584
  const timestampMs = chat.updatedAt && chat.updatedAt < 1e12 ? chat.updatedAt * 1e3 : chat.updatedAt ?? Date.now();
@@ -59316,7 +59888,7 @@ ${deleted}/${resolved.length} chat(s) deleted.`);
59316
59888
  );
59317
59889
  process.exit(1);
59318
59890
  }
59319
- const result = await client.listChats(n, 1);
59891
+ const result = await client.listChats(n, 1, teamContext);
59320
59892
  if (result.total === 0) {
59321
59893
  console.error(
59322
59894
  "No chats found. Run 'openmates chats list' to sync."
@@ -59537,7 +60109,7 @@ async function handleWorkflows(client, subcommand, rest, flags) {
59537
60109
  return;
59538
60110
  }
59539
60111
  if (subcommand === "list") {
59540
- const workflows = await client.listWorkflows();
60112
+ const workflows = await client.listWorkflows(teamContextFromFlags(flags));
59541
60113
  if (flags.json === true) {
59542
60114
  printJson2(workflows);
59543
60115
  } else {
@@ -59681,7 +60253,7 @@ async function handleWorkflows(client, subcommand, rest, flags) {
59681
60253
  if (subcommand === "show") {
59682
60254
  const workflowId = rest[0];
59683
60255
  if (!workflowId) throw new Error("Missing workflow ID. Example: openmates workflows show <id>");
59684
- const workflow = await client.getWorkflow(workflowId);
60256
+ const workflow = await client.getWorkflow(workflowId, teamContextFromFlags(flags));
59685
60257
  if (flags.json === true) {
59686
60258
  printJson2(workflow);
59687
60259
  } else {
@@ -61334,8 +61906,8 @@ async function writeSecretFile(filePath, content, force = false) {
61334
61906
  return filePath;
61335
61907
  }
61336
61908
  async function generateProvisioningPassword() {
61337
- const { randomBytes: randomBytes5 } = await import("crypto");
61338
- return `OM-${randomBytes5(18).toString("base64url")}-aA2#`;
61909
+ const { randomBytes: randomBytes6 } = await import("crypto");
61910
+ return `OM-${randomBytes6(18).toString("base64url")}-aA2#`;
61339
61911
  }
61340
61912
  function decodeBase32(input) {
61341
61913
  const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
@@ -62153,7 +62725,7 @@ async function handleMemories(client, rest, flags) {
62153
62725
  if (action === "list") {
62154
62726
  const appId = typeof flags["app-id"] === "string" ? flags["app-id"] : null;
62155
62727
  const itemType = typeof flags["item-type"] === "string" ? flags["item-type"] : null;
62156
- let result = await client.listMemories();
62728
+ let result = await client.listMemories(teamContextFromFlags(flags));
62157
62729
  if (appId) result = result.filter((m) => m.app_id === appId);
62158
62730
  if (itemType) result = result.filter((m) => m.item_type === itemType);
62159
62731
  if (flags.json === true) {
@@ -62200,7 +62772,7 @@ Example: --data '{"name":"Python","proficiency":"advanced"}'`
62200
62772
  process.exit(1);
62201
62773
  }
62202
62774
  const itemValue = JSON.parse(dataRaw);
62203
- const result = await client.createMemory({ appId, itemType, itemValue });
62775
+ const result = await client.createMemory({ appId, itemType, itemValue, ...teamContextFromFlags(flags) });
62204
62776
  if (flags.json === true) {
62205
62777
  printJson2(result);
62206
62778
  } else {
@@ -62232,7 +62804,8 @@ Example: --data '{"name":"Python","proficiency":"advanced"}'`
62232
62804
  appId,
62233
62805
  itemType,
62234
62806
  itemValue,
62235
- currentVersion
62807
+ currentVersion,
62808
+ ...teamContextFromFlags(flags)
62236
62809
  });
62237
62810
  if (flags.json === true) {
62238
62811
  printJson2(result);
@@ -62251,7 +62824,7 @@ Example: --data '{"name":"Python","proficiency":"advanced"}'`
62251
62824
  );
62252
62825
  process.exit(1);
62253
62826
  }
62254
- const result = await client.deleteMemory(entryId);
62827
+ const result = await client.deleteMemory(entryId, teamContextFromFlags(flags));
62255
62828
  if (flags.json === true) {
62256
62829
  printJson2(result);
62257
62830
  } else {
@@ -62760,6 +63333,8 @@ async function sendMessageStreaming(client, params, redactor) {
62760
63333
  const result = await client.sendMessage({
62761
63334
  message: finalMessage,
62762
63335
  chatId: params.chatId,
63336
+ teamId: params.teamId,
63337
+ personal: params.personal,
62763
63338
  incognito: params.incognito,
62764
63339
  onStream,
62765
63340
  onSubChatEvent,
@@ -64272,6 +64847,7 @@ Commands:
64272
64847
  openmates whoami [--json] Show account info
64273
64848
  openmates chats [--help] Chat commands (list, search, show, ...)
64274
64849
  openmates tasks [--help] Task commands (list, create, board, ...)
64850
+ openmates teams [--help] Team lifecycle, membership, billing, and move commands
64275
64851
  openmates drafts [--help] Encrypted draft lifecycle commands
64276
64852
  openmates apps [--help] App skill commands (list, run, ...)
64277
64853
  openmates workflows [--help] Server-side workflow commands
@@ -64584,6 +65160,35 @@ Notes:
64584
65160
  Labels organize tasks privately. --tag, --tags, --add-tag, and --remove-tag are accepted aliases.
64585
65161
  Normal output decrypts task title, description, and labels locally; use --json for machine-readable plaintext fields.`);
64586
65162
  }
65163
+ function printTeamsHelp() {
65164
+ console.log(`Teams commands:
65165
+ openmates teams list [--json]
65166
+ openmates teams switch <team-id> [--json]
65167
+ openmates teams personal [--json]
65168
+ openmates teams show <team-id> [--json]
65169
+ openmates teams create --name <name> [--description <description>] [--slug <slug>] [--switch] [--json]
65170
+ openmates teams update <team-id> [--name <encrypted-name>] [--description <encrypted-description>] [--slug <slug>] [--json]
65171
+ openmates teams delete <team-id> --yes [--json]
65172
+ openmates teams invite <team-id> (--email <email>|--user <user-id>) [--role admin|member|viewer] [--json]
65173
+ openmates teams accept-invite <invite-id> [--json]
65174
+ openmates teams decline-invite <invite-id> [--json]
65175
+ openmates teams access-requests <team-id> [--status pending_access_approval|all] [--json]
65176
+ openmates teams approve-access <team-id> <access-request-id> --encrypted-team-key <value> [--json]
65177
+ openmates teams reject-access <team-id> <access-request-id> [--json]
65178
+ openmates teams role <team-id> --user <user-id> --role admin|member|viewer [--json]
65179
+ openmates teams remove-member <team-id> --user <user-id> [--json]
65180
+ openmates teams billing <team-id> [--json]
65181
+ openmates teams add-credits <team-id> --credits <amount> [--json]
65182
+ openmates teams usage <team-id> [--user <user-id>] [--json]
65183
+ openmates teams move <team-id> --type chat|project|task|plan|workflow --id <resource-id> --yes [--json]
65184
+ openmates teams export <team-id> --output <path> [--json]
65185
+ openmates teams import --file <path> (--team <team-id>|--new-team-name <name>) [--json]
65186
+
65187
+ Context:
65188
+ openmates teams switch <team-id> persists the active team for team-aware commands.
65189
+ openmates teams personal clears the active team and returns commands to personal context.
65190
+ Team V1 only supports team-wide workspace visibility.`);
65191
+ }
64587
65192
  function printDraftsHelp() {
64588
65193
  console.log(`Draft commands:
64589
65194
  openmates drafts create <text> [--chat <uuid>] [--preview <text>] [--json]