openmates 0.15.0-alpha.8 → 0.15.0-alpha.9

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.
@@ -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 randomBytes4 = cryptoApi.getRandomValues(new Uint8Array(length));
201
+ const randomBytes5 = cryptoApi.getRandomValues(new Uint8Array(length));
202
202
  for (let index = requiredSets.length; index < length; index += 1) {
203
- result[index] = allChars.charAt(randomBytes4[index] % allChars.length);
203
+ result[index] = allChars.charAt(randomBytes5[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];
@@ -4844,7 +4844,7 @@ var OpenMatesClient = class _OpenMatesClient {
4844
4844
  if (!userId) {
4845
4845
  throw new Error("Could not resolve current user id for local connected-account connector.");
4846
4846
  }
4847
- const { createHash: createHash8 } = await import("crypto");
4847
+ const { createHash: createHash9 } = await import("crypto");
4848
4848
  const accountId = randomUUID5();
4849
4849
  const masterKey = this.getMasterKeyBytes();
4850
4850
  const encryptLocalConnectorValue = async (value) => {
@@ -4853,9 +4853,9 @@ var OpenMatesClient = class _OpenMatesClient {
4853
4853
  };
4854
4854
  const payload = {
4855
4855
  id: accountId,
4856
- hashed_user_id: createHash8("sha256").update(userId).digest("hex"),
4856
+ hashed_user_id: createHash9("sha256").update(userId).digest("hex"),
4857
4857
  encrypted_provider_type: await encryptLocalConnectorValue(input.provider_id),
4858
- provider_type_hash: createHash8("sha256").update(input.provider_id).digest("hex"),
4858
+ provider_type_hash: createHash9("sha256").update(input.provider_id).digest("hex"),
4859
4859
  encrypted_account_label: await encryptLocalConnectorValue(input.label),
4860
4860
  encrypted_capabilities: await encryptLocalConnectorValue(input.capabilities),
4861
4861
  encrypted_app_permissions: await encryptLocalConnectorValue({
@@ -5581,8 +5581,8 @@ var OpenMatesClient = class _OpenMatesClient {
5581
5581
  );
5582
5582
  let msgEmbedIds = [];
5583
5583
  if (clientMsgId && cache.embeds.length > 0) {
5584
- const { createHash: createHash8 } = await import("crypto");
5585
- const hashed = createHash8("sha256").update(clientMsgId).digest("hex");
5584
+ const { createHash: createHash9 } = await import("crypto");
5585
+ const hashed = createHash9("sha256").update(clientMsgId).digest("hex");
5586
5586
  msgEmbedIds = cache.embeds.filter(
5587
5587
  (e) => e.hashed_message_id === hashed && // Only include parent embeds (no parent_embed_id).
5588
5588
  // Child embeds inherit the parent's key and are loaded
@@ -5629,8 +5629,8 @@ var OpenMatesClient = class _OpenMatesClient {
5629
5629
  );
5630
5630
  }
5631
5631
  const embedId = String(embed.embed_id ?? embed.id ?? "");
5632
- const { createHash: createHash8 } = await import("crypto");
5633
- const hashedEmbedId = createHash8("sha256").update(embedId).digest("hex");
5632
+ const { createHash: createHash9 } = await import("crypto");
5633
+ const hashedEmbedId = createHash9("sha256").update(embedId).digest("hex");
5634
5634
  const embedKeyBytes = await this.resolveEmbedKey(
5635
5635
  cache,
5636
5636
  masterKey,
@@ -5738,7 +5738,7 @@ var OpenMatesClient = class _OpenMatesClient {
5738
5738
  async resolveEmbedKey(cache, masterKey, embed, embedId, hashedEmbedId, visited = /* @__PURE__ */ new Set()) {
5739
5739
  if (visited.has(embedId)) return null;
5740
5740
  visited.add(embedId);
5741
- const { createHash: createHash8 } = await import("crypto");
5741
+ const { createHash: createHash9 } = await import("crypto");
5742
5742
  const masterKeyEntry = cache.embedKeys.find(
5743
5743
  (ek) => ek.hashed_embed_id === hashedEmbedId && String(ek.key_type) === "master"
5744
5744
  );
@@ -5755,7 +5755,7 @@ var OpenMatesClient = class _OpenMatesClient {
5755
5755
  if (chatKeyEntry && typeof chatKeyEntry.encrypted_embed_key === "string") {
5756
5756
  const hashedChatId = String(chatKeyEntry.hashed_chat_id ?? "");
5757
5757
  const owningChat = cache.chats.find((c) => {
5758
- const chatHash = createHash8("sha256").update(String(c.details.id ?? "")).digest("hex");
5758
+ const chatHash = createHash9("sha256").update(String(c.details.id ?? "")).digest("hex");
5759
5759
  return chatHash === hashedChatId;
5760
5760
  });
5761
5761
  if (owningChat) {
@@ -5784,7 +5784,7 @@ var OpenMatesClient = class _OpenMatesClient {
5784
5784
  const parentFullId = String(
5785
5785
  parentEmbed2.embed_id ?? parentEmbed2.id ?? ""
5786
5786
  );
5787
- const parentHashedId = createHash8("sha256").update(parentFullId).digest("hex");
5787
+ const parentHashedId = createHash9("sha256").update(parentFullId).digest("hex");
5788
5788
  const parentKey = await this.resolveEmbedKey(
5789
5789
  cache,
5790
5790
  masterKey,
@@ -8796,7 +8796,7 @@ Required: ${schema.required.join(", ")}`
8796
8796
  const session = this.requireSession();
8797
8797
  const masterKey = base64ToBytes(session.masterKeyExportedB64);
8798
8798
  const cache = await this.ensureSynced();
8799
- const { createHash: createHash8 } = await import("crypto");
8799
+ const { createHash: createHash9 } = await import("crypto");
8800
8800
  const embed = cache.embeds.find(
8801
8801
  (e) => String(e.embed_id ?? "").startsWith(embedIdOrShort) || String(e.id ?? "").startsWith(embedIdOrShort)
8802
8802
  );
@@ -8804,7 +8804,7 @@ Required: ${schema.required.join(", ")}`
8804
8804
  throw new Error(`Embed '${embedIdOrShort}' not found in local cache.`);
8805
8805
  }
8806
8806
  const embedId = String(embed.embed_id ?? embed.id ?? "");
8807
- const hashedEmbedId = createHash8("sha256").update(embedId).digest("hex");
8807
+ const hashedEmbedId = createHash9("sha256").update(embedId).digest("hex");
8808
8808
  const embedKeyBytes = await this.resolveEmbedKey(
8809
8809
  cache,
8810
8810
  masterKey,
@@ -8912,8 +8912,8 @@ Required: ${schema.required.join(", ")}`
8912
8912
  if (!embed) {
8913
8913
  throw new Error(`Embed '${embedId}' not found in local cache. Run 'openmates chats list' to sync first.`);
8914
8914
  }
8915
- const { createHash: createHash8 } = await import("crypto");
8916
- const hashedEmbedId = createHash8("sha256").update(embedId).digest("hex");
8915
+ const { createHash: createHash9 } = await import("crypto");
8916
+ const hashedEmbedId = createHash9("sha256").update(embedId).digest("hex");
8917
8917
  const embedKey = await this.resolveEmbedKey(
8918
8918
  cache,
8919
8919
  masterKey,
@@ -9007,8 +9007,8 @@ Required: ${schema.required.join(", ")}`
9007
9007
  if (!embed) {
9008
9008
  throw new Error(`Embed '${embedId}' not found in local cache. Run 'openmates chats list' to sync first.`);
9009
9009
  }
9010
- const { createHash: createHash8 } = await import("crypto");
9011
- const hashedEmbedId = createHash8("sha256").update(embedId).digest("hex");
9010
+ const { createHash: createHash9 } = await import("crypto");
9011
+ const hashedEmbedId = createHash9("sha256").update(embedId).digest("hex");
9012
9012
  const embedKey = await this.resolveEmbedKey(
9013
9013
  cache,
9014
9014
  masterKey,
@@ -9397,9 +9397,9 @@ Required: ${schema.required.join(", ")}`
9397
9397
  const reconciledChats = reconcileAuthoritativeChats(chats, reconciliation);
9398
9398
  chats.splice(0, chats.length, ...reconciledChats);
9399
9399
  if (reconciliation.deleted_chat_ids?.length) {
9400
- const { createHash: createHash8 } = await import("crypto");
9400
+ const { createHash: createHash9 } = await import("crypto");
9401
9401
  const deletedHashes = new Set(
9402
- reconciliation.deleted_chat_ids.map((id) => createHash8("sha256").update(id).digest("hex"))
9402
+ reconciliation.deleted_chat_ids.map((id) => createHash9("sha256").update(id).digest("hex"))
9403
9403
  );
9404
9404
  const keptEmbeds = embeds.filter((embed) => !deletedHashes.has(String(embed.hashed_chat_id ?? "")));
9405
9405
  const keptKeys = embedKeys.filter((key) => !deletedHashes.has(String(key.hashed_chat_id ?? "")));
@@ -9674,15 +9674,6 @@ function printLogo() {
9674
9674
  stdout.write(lines.join("\n") + "\n");
9675
9675
  }
9676
9676
 
9677
- // src/cli.ts
9678
- import { createInterface as createInterface5 } from "readline/promises";
9679
- import { stdin as stdin3, stdout as stdout2 } from "process";
9680
- import { readFileSync as readFileSync9, realpathSync, writeFileSync as writeFileSync6 } from "fs";
9681
- import { fileURLToPath as fileURLToPath2 } from "url";
9682
- import { basename as basename3, dirname as dirname3 } from "path";
9683
- import { randomUUID as randomUUID7 } from "crypto";
9684
- import WebSocket2 from "ws";
9685
-
9686
9677
  // src/generated/appSkills.ts
9687
9678
  var APP_SKILL_METADATA = [
9688
9679
  {
@@ -13590,6 +13581,1374 @@ var GeneratedAppSkills = class {
13590
13581
  workflows;
13591
13582
  };
13592
13583
 
13584
+ // src/sdk.ts
13585
+ import { decode as toonDecode } from "@toon-format/toon";
13586
+ import { createHash as createHash6, randomBytes as randomBytes3, randomUUID as randomUUID6 } from "crypto";
13587
+ import { chmodSync as chmodSync2, existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
13588
+ import { homedir as homedir4 } from "os";
13589
+ import { dirname, join as join3 } from "path";
13590
+ var DEFAULT_API_URL2 = "https://api.openmates.org";
13591
+ var DEFAULT_RECOVERY_POLL_INTERVAL_MS = 500;
13592
+ var DEFAULT_RECOVERY_TIMEOUT_MS = 6e4;
13593
+ var OpenMatesConfigError = class extends Error {
13594
+ constructor(message) {
13595
+ super(message);
13596
+ this.name = "OpenMatesConfigError";
13597
+ }
13598
+ };
13599
+ var OpenMatesApiError = class extends Error {
13600
+ status;
13601
+ data;
13602
+ constructor(status, data) {
13603
+ super(`OpenMates API request failed with HTTP ${status}`);
13604
+ this.name = "OpenMatesApiError";
13605
+ this.status = status;
13606
+ this.data = data;
13607
+ }
13608
+ };
13609
+ var OpenMates = class {
13610
+ apps;
13611
+ account;
13612
+ benchmark;
13613
+ billing;
13614
+ chats;
13615
+ connectedAccounts;
13616
+ docs;
13617
+ drafts;
13618
+ embeds;
13619
+ feedback;
13620
+ inspirations;
13621
+ learningMode;
13622
+ memories;
13623
+ newChatSuggestions;
13624
+ notifications;
13625
+ reminders;
13626
+ projects;
13627
+ settings;
13628
+ plans;
13629
+ tasks;
13630
+ workflows;
13631
+ apiKey;
13632
+ apiUrl;
13633
+ deviceId;
13634
+ sdkSessionPromise;
13635
+ masterKeyPromise;
13636
+ constructor(options = {}) {
13637
+ this.apiKey = options.apiKey ?? process.env.OPENMATES_API_KEY;
13638
+ this.apiUrl = (options.apiUrl ?? DEFAULT_API_URL2).replace(/\/$/, "");
13639
+ this.deviceId = options.deviceId ?? loadOrCreateDeviceId(options.deviceIdPath);
13640
+ this.apps = new GeneratedAppSkills(this.runAppSkill.bind(this));
13641
+ this.account = new OpenMatesAccount(this);
13642
+ this.benchmark = new OpenMatesBenchmark(this);
13643
+ this.billing = new OpenMatesBilling(this);
13644
+ this.chats = new OpenMatesChats(this);
13645
+ this.connectedAccounts = new OpenMatesConnectedAccounts(this);
13646
+ this.docs = new OpenMatesDocs(this);
13647
+ this.drafts = new OpenMatesDrafts(this);
13648
+ this.embeds = new OpenMatesEmbeds(this);
13649
+ this.feedback = new OpenMatesFeedback(this);
13650
+ this.inspirations = new OpenMatesInspirations(this);
13651
+ this.learningMode = new OpenMatesLearningMode(this);
13652
+ this.memories = new OpenMatesMemories(this);
13653
+ this.newChatSuggestions = new OpenMatesNewChatSuggestions(this);
13654
+ this.notifications = new OpenMatesNotifications(this);
13655
+ this.reminders = new OpenMatesReminders(this);
13656
+ this.projects = new OpenMatesProjects(this);
13657
+ this.settings = new OpenMatesSettings(this);
13658
+ this.plans = new OpenMatesPlans(this);
13659
+ this.tasks = new OpenMatesTasks(this);
13660
+ this.workflows = new OpenMatesWorkflows(this);
13661
+ }
13662
+ async runAppSkill(appId, skillId, input) {
13663
+ return this.request(`/v1/apps/${appId}/skills/${skillId}`, input);
13664
+ }
13665
+ async request(path, body, timeoutMs, extraHeaders) {
13666
+ return this.requestWithMethod("POST", path, body, timeoutMs, extraHeaders);
13667
+ }
13668
+ async patch(path, body) {
13669
+ return this.requestWithMethod("PATCH", path, body);
13670
+ }
13671
+ async put(path, body) {
13672
+ return this.requestWithMethod("PUT", path, body);
13673
+ }
13674
+ async delete(path, body) {
13675
+ return this.requestWithMethod("DELETE", path, body);
13676
+ }
13677
+ async get(path) {
13678
+ if (!this.apiKey) {
13679
+ throw new OpenMatesConfigError("OpenMates API key is required");
13680
+ }
13681
+ const response = await fetch(`${this.apiUrl}${path}`, {
13682
+ method: "GET",
13683
+ headers: this.headers(false)
13684
+ });
13685
+ return this.parseResponse(response);
13686
+ }
13687
+ async getPublic(path) {
13688
+ const response = await fetch(`${this.apiUrl}${path}`, {
13689
+ method: "GET",
13690
+ headers: this.publicHeaders()
13691
+ });
13692
+ return this.parseResponse(response);
13693
+ }
13694
+ async getRaw(path) {
13695
+ if (!this.apiKey) {
13696
+ throw new OpenMatesConfigError("OpenMates API key is required");
13697
+ }
13698
+ const response = await fetch(`${this.apiUrl}${path}`, {
13699
+ method: "GET",
13700
+ headers: this.headers(false)
13701
+ });
13702
+ if (!response.ok) {
13703
+ await this.parseResponse(response);
13704
+ }
13705
+ return {
13706
+ contentType: response.headers.get("content-type") ?? "application/octet-stream",
13707
+ filename: extractFilename(response.headers.get("content-disposition")),
13708
+ data: await response.arrayBuffer()
13709
+ };
13710
+ }
13711
+ webOrigin() {
13712
+ return deriveWebOrigin(this.apiUrl);
13713
+ }
13714
+ masterKey() {
13715
+ return this.getMasterKey();
13716
+ }
13717
+ sdkSession() {
13718
+ return this.getSdkSession();
13719
+ }
13720
+ async resolveEmbedKeyForShare(embedKeys, embedId) {
13721
+ const masterKey = await this.getMasterKey();
13722
+ const hashedEmbedId = createHash6("sha256").update(embedId).digest("hex");
13723
+ return this.resolveLoadedEmbedKey(embedKeys, hashedEmbedId, masterKey, masterKey);
13724
+ }
13725
+ async decryptChatMetadata(chat) {
13726
+ if (typeof chat.encrypted_chat_key !== "string") {
13727
+ return chat;
13728
+ }
13729
+ const masterKey = await this.getMasterKey();
13730
+ const chatKey = await decryptBytesWithAesGcm(chat.encrypted_chat_key, masterKey);
13731
+ if (!chatKey) {
13732
+ return chat;
13733
+ }
13734
+ const decrypted = { ...chat };
13735
+ if (typeof chat.encrypted_title === "string") {
13736
+ decrypted.title = await decryptWithAesGcmCombined(chat.encrypted_title, chatKey);
13737
+ }
13738
+ if (typeof chat.encrypted_chat_summary === "string") {
13739
+ decrypted.chat_summary = await decryptWithAesGcmCombined(chat.encrypted_chat_summary, chatKey);
13740
+ }
13741
+ if (typeof chat.encrypted_category === "string") {
13742
+ decrypted.category = await decryptWithAesGcmCombined(chat.encrypted_category, chatKey);
13743
+ }
13744
+ return decrypted;
13745
+ }
13746
+ async decryptLoadedChatPayload(payload) {
13747
+ const chat = payload.chat;
13748
+ if (!chat || typeof chat !== "object") {
13749
+ return payload;
13750
+ }
13751
+ const chatMetadata = chat;
13752
+ const decryptedChat = await this.decryptChatMetadata(chatMetadata);
13753
+ const chatKey = typeof chatMetadata.encrypted_chat_key === "string" ? await decryptBytesWithAesGcm(chatMetadata.encrypted_chat_key, await this.getMasterKey()) : null;
13754
+ if (!chatKey || !Array.isArray(payload.messages)) {
13755
+ return { ...payload, chat: decryptedChat };
13756
+ }
13757
+ const messages = await Promise.all(payload.messages.map(async (rawMessage) => {
13758
+ const message = typeof rawMessage === "string" ? JSON.parse(rawMessage) : { ...rawMessage };
13759
+ if (typeof message.encrypted_content === "string") {
13760
+ message.content = await decryptWithAesGcmCombined(message.encrypted_content, chatKey);
13761
+ }
13762
+ if (typeof message.encrypted_sender_name === "string") {
13763
+ message.senderName = await decryptWithAesGcmCombined(message.encrypted_sender_name, chatKey);
13764
+ }
13765
+ if (typeof message.encrypted_category === "string") {
13766
+ message.category = await decryptWithAesGcmCombined(message.encrypted_category, chatKey);
13767
+ }
13768
+ if (typeof message.encrypted_model_name === "string") {
13769
+ message.modelName = await decryptWithAesGcmCombined(message.encrypted_model_name, chatKey);
13770
+ }
13771
+ return message;
13772
+ }));
13773
+ const embeds = Array.isArray(payload.embeds) ? await this.decryptLoadedChatEmbeds(
13774
+ payload.embeds,
13775
+ Array.isArray(payload.embed_keys) ? payload.embed_keys : [],
13776
+ chatKey
13777
+ ) : payload.embeds;
13778
+ return { ...payload, chat: decryptedChat, messages, embeds };
13779
+ }
13780
+ async decryptLoadedChatEmbeds(embeds, embedKeys, chatKey) {
13781
+ const masterKey = await this.getMasterKey();
13782
+ return Promise.all(embeds.map(async (embed) => {
13783
+ const embedId = String(embed.embed_id ?? embed.id ?? "");
13784
+ if (!embedId) {
13785
+ return { ...embed };
13786
+ }
13787
+ const hashedEmbedId = createHash6("sha256").update(embedId).digest("hex");
13788
+ const embedKey = await this.resolveLoadedEmbedKey(embedKeys, hashedEmbedId, masterKey, chatKey);
13789
+ if (!embedKey) {
13790
+ return { ...embed };
13791
+ }
13792
+ const decrypted = { ...embed };
13793
+ if (typeof embed.encrypted_type === "string") {
13794
+ decrypted.type = await decryptWithAesGcmCombined(embed.encrypted_type, embedKey);
13795
+ }
13796
+ if (typeof embed.encrypted_text_preview === "string") {
13797
+ decrypted.textPreview = await decryptWithAesGcmCombined(embed.encrypted_text_preview, embedKey);
13798
+ }
13799
+ if (typeof embed.encrypted_content === "string") {
13800
+ const content = await decryptWithAesGcmCombined(embed.encrypted_content, embedKey);
13801
+ decrypted.content = parseMaybeJson(content);
13802
+ }
13803
+ return decrypted;
13804
+ }));
13805
+ }
13806
+ async resolveLoadedEmbedKey(embedKeys, hashedEmbedId, masterKey, chatKey) {
13807
+ const matchingKeys = embedKeys.filter((key) => key.hashed_embed_id === hashedEmbedId);
13808
+ const masterKeyEntry = matchingKeys.find((key) => key.key_type === "master");
13809
+ if (typeof masterKeyEntry?.encrypted_embed_key === "string") {
13810
+ const embedKey = await decryptBytesWithAesGcm(masterKeyEntry.encrypted_embed_key, masterKey);
13811
+ if (embedKey) return embedKey;
13812
+ }
13813
+ const chatKeyEntry = matchingKeys.find((key) => key.key_type === "chat");
13814
+ if (typeof chatKeyEntry?.encrypted_embed_key === "string") {
13815
+ return decryptBytesWithAesGcm(chatKeyEntry.encrypted_embed_key, chatKey);
13816
+ }
13817
+ return null;
13818
+ }
13819
+ async requestWithMethod(method, path, body, timeoutMs, extraHeaders) {
13820
+ if (!this.apiKey) {
13821
+ throw new OpenMatesConfigError("OpenMates API key is required");
13822
+ }
13823
+ const response = await fetch(`${this.apiUrl}${path}`, {
13824
+ method,
13825
+ headers: { ...this.headers(body !== void 0), ...extraHeaders },
13826
+ body: body === void 0 ? void 0 : JSON.stringify(body),
13827
+ signal: timeoutMs === void 0 ? void 0 : AbortSignal.timeout(timeoutMs)
13828
+ });
13829
+ return this.parseResponse(response);
13830
+ }
13831
+ getMasterKey() {
13832
+ this.masterKeyPromise ??= this.loadMasterKey();
13833
+ return this.masterKeyPromise;
13834
+ }
13835
+ async loadMasterKey() {
13836
+ if (!this.apiKey) {
13837
+ throw new OpenMatesConfigError("OpenMates API key is required");
13838
+ }
13839
+ const session = await this.getSdkSession();
13840
+ const wrapper = session.key_wrapper;
13841
+ if (!wrapper?.encrypted_key || !wrapper.salt || !wrapper.key_iv) {
13842
+ throw new OpenMatesConfigError("SDK session did not include API-key-wrapped master key material");
13843
+ }
13844
+ const masterKey = await unwrapApiKeyMasterKey({
13845
+ apiKey: this.apiKey,
13846
+ encryptedMasterKeyB64: wrapper.encrypted_key,
13847
+ saltB64: wrapper.salt,
13848
+ keyIvB64: wrapper.key_iv
13849
+ });
13850
+ if (!masterKey) {
13851
+ throw new OpenMatesConfigError("Unable to decrypt SDK session master key with API key");
13852
+ }
13853
+ return masterKey;
13854
+ }
13855
+ getSdkSession() {
13856
+ this.sdkSessionPromise ??= this.request("/v1/sdk/session", {
13857
+ sdk_name: "npm",
13858
+ device_identity: this.deviceId
13859
+ });
13860
+ return this.sdkSessionPromise;
13861
+ }
13862
+ headers(hasBody = true) {
13863
+ const headers = {
13864
+ Accept: "application/json",
13865
+ Authorization: `Bearer ${this.apiKey}`,
13866
+ "X-OpenMates-SDK": "npm",
13867
+ "X-OpenMates-Device-Identity": this.deviceId
13868
+ };
13869
+ if (hasBody) {
13870
+ headers["Content-Type"] = "application/json";
13871
+ }
13872
+ return headers;
13873
+ }
13874
+ publicHeaders() {
13875
+ return {
13876
+ Accept: "application/json",
13877
+ "X-OpenMates-SDK": "npm",
13878
+ "X-OpenMates-Device-Identity": this.deviceId
13879
+ };
13880
+ }
13881
+ async parseResponse(response) {
13882
+ let data = {};
13883
+ try {
13884
+ data = await response.json();
13885
+ } catch {
13886
+ data = {};
13887
+ }
13888
+ if (!response.ok) {
13889
+ throw new OpenMatesApiError(response.status, data);
13890
+ }
13891
+ return data;
13892
+ }
13893
+ };
13894
+ function loadOrCreateDeviceId(customPath) {
13895
+ const path = customPath ?? join3(homedir4(), ".openmates", "sdk-device-id");
13896
+ if (existsSync5(path)) {
13897
+ const stored = readFileSync4(path, "utf8").trim();
13898
+ if (stored) return stored;
13899
+ }
13900
+ const deviceId = randomUUID6();
13901
+ mkdirSync3(dirname(path), { recursive: true, mode: 448 });
13902
+ writeFileSync3(path, `${deviceId}
13903
+ `, { encoding: "utf8", mode: 384 });
13904
+ chmodSync2(path, 384);
13905
+ return deviceId;
13906
+ }
13907
+ function withQuery(path, query = {}) {
13908
+ const params = new URLSearchParams();
13909
+ for (const [key, value] of Object.entries(query)) {
13910
+ if (value !== void 0 && value !== null) params.set(key, String(value));
13911
+ }
13912
+ const serialized = params.toString();
13913
+ return serialized ? `${path}?${serialized}` : path;
13914
+ }
13915
+ function requireConfirmed(options, action) {
13916
+ if (options?.confirmed !== true) {
13917
+ throw new OpenMatesConfigError(`${action} requires confirmed: true`);
13918
+ }
13919
+ }
13920
+ function unsupportedSdkFeature(feature) {
13921
+ throw new OpenMatesConfigError(`${feature} is not available through the API-key SDK yet`);
13922
+ }
13923
+ function extractFilename(contentDisposition) {
13924
+ if (!contentDisposition) return void 0;
13925
+ const encoded = contentDisposition.match(/filename\*=UTF-8''([^;]+)/)?.[1];
13926
+ if (encoded) return decodeURIComponent(encoded);
13927
+ return contentDisposition.match(/filename="?([^";]+)"?/)?.[1];
13928
+ }
13929
+ function normalizeHistory(history) {
13930
+ if (!history) return [];
13931
+ if (Array.isArray(history)) return history;
13932
+ return Array.isArray(history.messages) ? history.messages : [];
13933
+ }
13934
+ function parseMaybeJson(value) {
13935
+ if (value === null) return null;
13936
+ try {
13937
+ return JSON.parse(value);
13938
+ } catch {
13939
+ try {
13940
+ return toonDecode(value, { strict: false });
13941
+ } catch {
13942
+ return value;
13943
+ }
13944
+ }
13945
+ }
13946
+ var OpenMatesChats = class {
13947
+ client;
13948
+ constructor(client) {
13949
+ this.client = client;
13950
+ }
13951
+ async list(options = {}) {
13952
+ const result = await this.client.get(
13953
+ withQuery("/v1/sdk/chats", { limit: options.limit ?? 10, offset: options.offset })
13954
+ );
13955
+ const chats = Array.isArray(result.chats) ? result.chats : [];
13956
+ return Promise.all(chats.map((chat) => this.client.decryptChatMetadata(chat)));
13957
+ }
13958
+ async search(query, options = {}) {
13959
+ const normalized = query.trim().toLowerCase();
13960
+ const chats = await this.list({ limit: 0 });
13961
+ const offset = options.offset ?? 0;
13962
+ const limit = options.limit ?? 10;
13963
+ const matches2 = chats.filter((chat) => {
13964
+ const haystack = [chat.title, chat.chat_summary, chat.category, chat.id].filter((value) => typeof value === "string").join("\n").toLowerCase();
13965
+ return haystack.includes(normalized);
13966
+ });
13967
+ return matches2.slice(offset, limit === 0 ? void 0 : offset + limit);
13968
+ }
13969
+ async load(chatId) {
13970
+ const payload = await this.client.get(`/v1/sdk/chats/${encodeURIComponent(chatId)}`);
13971
+ return this.client.decryptLoadedChatPayload(payload);
13972
+ }
13973
+ async send(message, options = {}) {
13974
+ if (options.saveToAccount === true) {
13975
+ return this.sendSaved(message, options);
13976
+ }
13977
+ const result = await this.client.request("/v1/sdk/chats", {
13978
+ message,
13979
+ history: normalizeHistory(options.history),
13980
+ save_to_account: false,
13981
+ memory_ids: options.memoryIds ?? [],
13982
+ model: options.model,
13983
+ focus_mode: options.focusMode ? { app_id: options.focusMode.appId, focus_mode_id: options.focusMode.focusModeId } : void 0
13984
+ });
13985
+ return result.response ?? result;
13986
+ }
13987
+ async sendSaved(message, options) {
13988
+ const masterKey = await this.client.masterKey();
13989
+ const session = await this.client.sdkSession();
13990
+ if (!session.user?.id) {
13991
+ throw new OpenMatesConfigError("SDK session did not include the authenticated user identity");
13992
+ }
13993
+ const chatId = options.chatId ?? randomUUID6();
13994
+ const turnId = randomUUID6();
13995
+ const messageId = randomUUID6();
13996
+ const createdAt = Math.floor(Date.now() / 1e3);
13997
+ let chatKey;
13998
+ let encryptedChatKey;
13999
+ let expectedMessagesV = 0;
14000
+ let encryptedChatMetadata;
14001
+ if (options.chatId) {
14002
+ const loaded = await this.load(chatId);
14003
+ const chat = loaded.chat;
14004
+ if (!chat?.encrypted_chat_key) {
14005
+ throw new OpenMatesConfigError("Saved chat does not include encrypted chat key material");
14006
+ }
14007
+ const decrypted = await decryptBytesWithAesGcm(chat.encrypted_chat_key, masterKey);
14008
+ if (!decrypted) {
14009
+ throw new OpenMatesConfigError("Unable to decrypt saved chat key material");
14010
+ }
14011
+ chatKey = decrypted;
14012
+ encryptedChatKey = chat.encrypted_chat_key;
14013
+ expectedMessagesV = Number(chat.messages_v ?? 0);
14014
+ } else {
14015
+ chatKey = new Uint8Array(randomBytes3(32));
14016
+ encryptedChatKey = await encryptBytesWithAesGcm(chatKey, masterKey);
14017
+ encryptedChatMetadata = {
14018
+ encrypted_title: await encryptWithAesGcmCombined(options.title ?? message.slice(0, 80), chatKey),
14019
+ encrypted_chat_key: encryptedChatKey,
14020
+ created_at: createdAt,
14021
+ updated_at: createdAt
14022
+ };
14023
+ }
14024
+ const recovery = await deriveChatCompletionRecoveryKeypair(
14025
+ Buffer.from(chatKey).toString("base64url"),
14026
+ chatId,
14027
+ 1
14028
+ );
14029
+ const history = normalizeHistory(options.history);
14030
+ const inferenceRequest = {
14031
+ messages: [...history, { role: "user", content: message }],
14032
+ model: options.model,
14033
+ focus_mode: options.focusMode ? { app_id: options.focusMode.appId, focus_mode_id: options.focusMode.focusModeId } : void 0,
14034
+ memory_ids: options.memoryIds ?? []
14035
+ };
14036
+ const result = await this.client.request("/v1/sdk/chats", {
14037
+ message,
14038
+ history,
14039
+ save_to_account: true,
14040
+ title: options.title,
14041
+ memory_ids: options.memoryIds ?? [],
14042
+ model: options.model,
14043
+ focus_mode: inferenceRequest.focus_mode,
14044
+ protocol_version: 1,
14045
+ chat_id: chatId,
14046
+ turn_id: turnId,
14047
+ message_id: messageId,
14048
+ chat_key_version: 1,
14049
+ encrypted_chat_key: encryptedChatKey,
14050
+ recovery_public_key: recovery.publicKey,
14051
+ expected_messages_v: expectedMessagesV,
14052
+ encrypted_user_message: {
14053
+ client_message_id: messageId,
14054
+ chat_id: chatId,
14055
+ encrypted_content: await encryptWithAesGcmCombined(message, chatKey),
14056
+ encrypted_sender_name: await encryptWithAesGcmCombined("User", chatKey),
14057
+ role: "user",
14058
+ created_at: createdAt,
14059
+ updated_at: createdAt
14060
+ },
14061
+ encrypted_chat_metadata: encryptedChatMetadata,
14062
+ inference_request: inferenceRequest
14063
+ });
14064
+ if (!result.task_id) {
14065
+ throw new OpenMatesConfigError("Saved chat dispatch did not return a stable inference task id");
14066
+ }
14067
+ const claim = await this.pollRecoveryClaim(
14068
+ result.task_id,
14069
+ options.recoveryTimeoutMs ?? DEFAULT_RECOVERY_TIMEOUT_MS,
14070
+ options.recoveryPollIntervalMs ?? DEFAULT_RECOVERY_POLL_INTERVAL_MS
14071
+ );
14072
+ const recovered = await this.openRecoveryClaim(
14073
+ claim,
14074
+ recovery.privateKey,
14075
+ session.user.id,
14076
+ chatId,
14077
+ turnId
14078
+ );
14079
+ const completedAt = Math.floor(Date.now() / 1e3);
14080
+ const encryptedAssistantMessage = {
14081
+ client_message_id: recovered.assistantMessageId,
14082
+ chat_id: chatId,
14083
+ encrypted_content: await encryptWithAesGcmCombined(recovered.content, chatKey),
14084
+ encrypted_sender_name: await encryptWithAesGcmCombined("Assistant", chatKey),
14085
+ role: "assistant",
14086
+ user_message_id: messageId,
14087
+ created_at: completedAt,
14088
+ updated_at: completedAt
14089
+ };
14090
+ if (recovered.category !== null) {
14091
+ encryptedAssistantMessage.encrypted_category = await encryptWithAesGcmCombined(recovered.category, chatKey);
14092
+ }
14093
+ if (recovered.modelName !== null) {
14094
+ encryptedAssistantMessage.encrypted_model_name = await encryptWithAesGcmCombined(recovered.modelName, chatKey);
14095
+ }
14096
+ const terminal = await this.client.request(
14097
+ `/v1/sdk/chats/recovery/${encodeURIComponent(result.task_id)}/persist`,
14098
+ {
14099
+ protocol_version: 1,
14100
+ lease_generation: claim.lease_generation,
14101
+ lease_token: claim.lease_token,
14102
+ expected_messages_v: expectedMessagesV + 1,
14103
+ encrypted_assistant_message: encryptedAssistantMessage
14104
+ }
14105
+ );
14106
+ if (terminal.state !== "TERMINAL") {
14107
+ throw new OpenMatesConfigError("Saved chat recovery did not reach terminal persistence");
14108
+ }
14109
+ return {
14110
+ content: recovered.content,
14111
+ category: recovered.category,
14112
+ model_name: recovered.modelName,
14113
+ chat_id: result.chat_id ?? chatId,
14114
+ task_id: result.task_id,
14115
+ preflight: result.preflight,
14116
+ terminal
14117
+ };
14118
+ }
14119
+ async pollRecoveryClaim(taskId, timeoutMs, pollIntervalMs) {
14120
+ if (!Number.isFinite(timeoutMs) || !Number.isFinite(pollIntervalMs) || timeoutMs <= 0 || pollIntervalMs <= 0) {
14121
+ throw new OpenMatesConfigError("Recovery timeout and poll interval must be finite and positive");
14122
+ }
14123
+ const deadline = Date.now() + timeoutMs;
14124
+ while (Date.now() < deadline) {
14125
+ try {
14126
+ const remainingMs2 = deadline - Date.now();
14127
+ if (remainingMs2 <= 0) break;
14128
+ return await this.client.request(
14129
+ `/v1/sdk/chats/recovery/${encodeURIComponent(taskId)}/claim`,
14130
+ { protocol_version: 1 },
14131
+ remainingMs2
14132
+ );
14133
+ } catch (error) {
14134
+ if (!(error instanceof OpenMatesApiError) || error.status !== 404) throw error;
14135
+ }
14136
+ const remainingMs = deadline - Date.now();
14137
+ if (remainingMs <= 0) break;
14138
+ await new Promise((resolve7) => setTimeout(resolve7, Math.min(pollIntervalMs, remainingMs)));
14139
+ }
14140
+ throw new OpenMatesConfigError("Timed out waiting for saved chat recovery");
14141
+ }
14142
+ async openRecoveryClaim(claim, recoveryPrivateKey, ownerId, chatId, turnId) {
14143
+ const jobId = typeof claim.job_id === "string" ? claim.job_id : null;
14144
+ const assistantMessageId = typeof claim.assistant_message_id === "string" ? claim.assistant_message_id : null;
14145
+ const keyVersion = Number.isSafeInteger(claim.chat_key_version) ? Number(claim.chat_key_version) : null;
14146
+ if (claim.state !== "LEASED" || typeof claim.lease_token !== "string" || !Number.isSafeInteger(claim.lease_generation) || !jobId || !assistantMessageId || keyVersion !== 1 || claim.chat_id !== chatId || claim.turn_id !== turnId || typeof claim.sealed_payload !== "string") {
14147
+ throw new OpenMatesConfigError("Recovery job claim returned invalid lease or identity data");
14148
+ }
14149
+ let envelope;
14150
+ try {
14151
+ envelope = JSON.parse(claim.sealed_payload);
14152
+ } catch {
14153
+ throw new OpenMatesConfigError("Recovery job contained an invalid sealed envelope");
14154
+ }
14155
+ const plaintext = await openChatCompletionRecoveryEnvelope(envelope, {
14156
+ recoveryPrivateKey,
14157
+ ownerId,
14158
+ chatId,
14159
+ turnId,
14160
+ jobId,
14161
+ assistantMessageId,
14162
+ keyVersion
14163
+ });
14164
+ let payload;
14165
+ try {
14166
+ payload = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(plaintext));
14167
+ } catch {
14168
+ throw new OpenMatesConfigError("Recovery job plaintext was not valid UTF-8 JSON");
14169
+ }
14170
+ const fields = ["assistant_message_id", "category", "chat_id", "content", "job_id", "key_version", "model_name", "turn_id"];
14171
+ if (Object.keys(payload).sort().join(",") !== fields.join(",") || payload.assistant_message_id !== assistantMessageId || payload.chat_id !== chatId || payload.turn_id !== turnId || payload.job_id !== jobId || payload.key_version !== keyVersion || typeof payload.content !== "string" || payload.category !== null && typeof payload.category !== "string" || payload.model_name !== null && typeof payload.model_name !== "string") {
14172
+ throw new OpenMatesConfigError("Recovery job plaintext did not match the terminal completion identity");
14173
+ }
14174
+ return {
14175
+ assistantMessageId,
14176
+ content: payload.content,
14177
+ category: payload.category,
14178
+ modelName: payload.model_name
14179
+ };
14180
+ }
14181
+ async export(chatId, options = {}) {
14182
+ const payload = await this.load(chatId);
14183
+ return this.client.request(`/v1/sdk/chats/${encodeURIComponent(chatId)}/export`, {
14184
+ format: options.format ?? "json",
14185
+ payload
14186
+ });
14187
+ }
14188
+ async delete(chatId, options) {
14189
+ requireConfirmed(options, "Deleting a chat");
14190
+ return this.client.delete(`/v1/sdk/chats/${encodeURIComponent(chatId)}`);
14191
+ }
14192
+ async share(chatId, options = {}) {
14193
+ const loaded = await this.load(chatId);
14194
+ const chat = loaded.chat;
14195
+ if (!chat?.encrypted_chat_key) {
14196
+ throw new OpenMatesConfigError("Chat does not include an encrypted chat key");
14197
+ }
14198
+ const chatKey = await decryptBytesWithAesGcm(chat.encrypted_chat_key, await this.client.masterKey());
14199
+ if (!chatKey) {
14200
+ throw new OpenMatesConfigError("Unable to decrypt chat key for share link");
14201
+ }
14202
+ const blob = await generateChatShareBlob(chatId, chatKey, options.expires ?? 0, options.password);
14203
+ return { url: buildChatShareUrl(this.client.webOrigin(), chatId, blob) };
14204
+ }
14205
+ async followUps(chatId) {
14206
+ const payload = await this.load(chatId);
14207
+ const chat = payload.chat;
14208
+ const encrypted = chat?.encrypted_follow_up_request_suggestions;
14209
+ if (typeof encrypted !== "string") return [];
14210
+ const raw = await decryptWithAesGcmCombined(encrypted, await this.client.masterKey());
14211
+ const parsed = raw ? parseMaybeJson(raw) : [];
14212
+ return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string") : [];
14213
+ }
14214
+ async incognito(message) {
14215
+ return this.send(message, { saveToAccount: false });
14216
+ }
14217
+ };
14218
+ var OpenMatesDrafts = class {
14219
+ client;
14220
+ constructor(client) {
14221
+ this.client = client;
14222
+ }
14223
+ async listEncrypted() {
14224
+ const response = await this.client.get("/v1/sdk/drafts");
14225
+ return (response.drafts ?? []).map(normalizeEncryptedDraft);
14226
+ }
14227
+ async list() {
14228
+ return Promise.all((await this.listEncrypted()).map((draft) => this.decrypt(draft)));
14229
+ }
14230
+ async getEncrypted(chatId) {
14231
+ const response = await this.client.get(
14232
+ `/v1/sdk/drafts/${encodeURIComponent(chatId)}`
14233
+ );
14234
+ return response.draft ? normalizeEncryptedDraft(response.draft) : null;
14235
+ }
14236
+ async get(chatId) {
14237
+ const encrypted = await this.getEncrypted(chatId);
14238
+ return encrypted ? this.decrypt(encrypted) : null;
14239
+ }
14240
+ async decrypt(draft) {
14241
+ const masterKey = await this.client.masterKey();
14242
+ const markdown = await decryptWithAesGcmCombined(draft.encryptedDraftMd, masterKey);
14243
+ if (markdown === null) throw new OpenMatesConfigError("Unable to decrypt draft markdown");
14244
+ const preview = draft.encryptedDraftPreview ? await decryptWithAesGcmCombined(draft.encryptedDraftPreview, masterKey) : markdown.slice(0, 160);
14245
+ return { ...draft, markdown, preview };
14246
+ }
14247
+ };
14248
+ function normalizeEncryptedDraft(raw) {
14249
+ return {
14250
+ chatId: String(raw.chat_id ?? ""),
14251
+ encryptedDraftMd: String(raw.encrypted_draft_md ?? ""),
14252
+ encryptedDraftPreview: typeof raw.encrypted_draft_preview === "string" ? raw.encrypted_draft_preview : null,
14253
+ draftV: Number(raw.draft_v ?? 0)
14254
+ };
14255
+ }
14256
+ var OpenMatesAccount = class {
14257
+ client;
14258
+ constructor(client) {
14259
+ this.client = client;
14260
+ }
14261
+ async info() {
14262
+ return this.client.get("/v1/sdk/account");
14263
+ }
14264
+ async setTimezone(timezone) {
14265
+ return this.client.request("/v1/sdk/account/timezone", { timezone });
14266
+ }
14267
+ async listInterests() {
14268
+ const data = await this.client.get("/v1/sdk/account/topic-preferences");
14269
+ const encrypted = data.encrypted_settings;
14270
+ if (typeof encrypted !== "string") return { selectedTagIds: [] };
14271
+ const raw = await decryptWithAesGcmCombined(encrypted, await this.client.masterKey());
14272
+ const parsed = raw ? parseMaybeJson(raw) : {};
14273
+ return {
14274
+ selectedTagIds: typeof parsed === "object" && parsed !== null && Array.isArray(parsed.selected_tag_ids) ? parsed.selected_tag_ids : []
14275
+ };
14276
+ }
14277
+ async setInterests(selectedTagIds) {
14278
+ const encrypted_settings = await encryptWithAesGcmCombined(
14279
+ JSON.stringify({ selected_tag_ids: selectedTagIds }),
14280
+ await this.client.masterKey()
14281
+ );
14282
+ return this.client.request("/v1/sdk/account/topic-preferences", { encrypted_settings });
14283
+ }
14284
+ async clearInterests() {
14285
+ return this.setInterests([]);
14286
+ }
14287
+ async exportManifest() {
14288
+ return this.client.get("/v1/sdk/account/export/manifest");
14289
+ }
14290
+ async exportData() {
14291
+ return this.client.get("/v1/sdk/account/export/data");
14292
+ }
14293
+ async setUsername(username) {
14294
+ return this.client.request("/v1/sdk/account/username", { username });
14295
+ }
14296
+ async storageOverview() {
14297
+ return this.client.get("/v1/sdk/account/storage");
14298
+ }
14299
+ async storageFiles(options = {}) {
14300
+ return this.client.get(withQuery("/v1/sdk/account/storage/files", options.query));
14301
+ }
14302
+ async deleteStorage(options) {
14303
+ requireConfirmed(options, "Deleting stored account files");
14304
+ return this.client.delete("/v1/sdk/account/storage/files", {
14305
+ file_id: options.fileId,
14306
+ category: options.category,
14307
+ all: options.all === true
14308
+ });
14309
+ }
14310
+ };
14311
+ var OpenMatesSettings = class {
14312
+ client;
14313
+ constructor(client) {
14314
+ this.client = client;
14315
+ }
14316
+ async setLanguage(language) {
14317
+ return this.client.request("/v1/sdk/settings/language", { language });
14318
+ }
14319
+ async setDarkMode(enabled) {
14320
+ return this.client.request("/v1/sdk/settings/dark-mode", { enabled });
14321
+ }
14322
+ async setFont(font) {
14323
+ return this.client.request("/v1/sdk/settings/font", { font });
14324
+ }
14325
+ async setModelDefaults(defaults) {
14326
+ return this.client.request("/v1/sdk/settings/ai-model-defaults", defaults);
14327
+ }
14328
+ async setChatAutoDelete(period) {
14329
+ return this.client.request("/v1/sdk/settings/auto-delete/chats", { period });
14330
+ }
14331
+ async shareDebugLogs(options) {
14332
+ requireConfirmed(options, "Sharing debug logs");
14333
+ return unsupportedSdkFeature("Debug-log sharing");
14334
+ }
14335
+ };
14336
+ var OpenMatesMemories = class {
14337
+ client;
14338
+ constructor(client) {
14339
+ this.client = client;
14340
+ }
14341
+ async list(options = {}) {
14342
+ const data = await this.client.get(withQuery("/v1/sdk/memories", options.query));
14343
+ const memories = await Promise.all((data.memories ?? []).map(async (memory) => {
14344
+ const decrypted = { ...memory };
14345
+ if (typeof memory.encrypted_item_json === "string") {
14346
+ const raw = await decryptWithAesGcmCombined(memory.encrypted_item_json, await this.client.masterKey());
14347
+ decrypted.data = raw ? parseMaybeJson(raw) : null;
14348
+ }
14349
+ return decrypted;
14350
+ }));
14351
+ return { memories };
14352
+ }
14353
+ async types(options = {}) {
14354
+ return this.client.get(withQuery("/v1/sdk/memories/types", options.query));
14355
+ }
14356
+ async create(input) {
14357
+ return this.storeMemory(input);
14358
+ }
14359
+ async update(id, input) {
14360
+ return this.storeMemory({ ...input, id });
14361
+ }
14362
+ async delete(id, options) {
14363
+ requireConfirmed(options, "Deleting a memory");
14364
+ return this.client.delete(`/v1/sdk/memories/${encodeURIComponent(id)}`);
14365
+ }
14366
+ async storeMemory(input) {
14367
+ const appId = String(input.appId ?? input.app_id ?? "");
14368
+ const itemType = String(input.itemType ?? input.item_type ?? "");
14369
+ const rawItemValue = input.itemValue ?? input.item_value ?? input.data ?? {};
14370
+ const itemValue = rawItemValue && typeof rawItemValue === "object" && !Array.isArray(rawItemValue) ? rawItemValue : { value: rawItemValue };
14371
+ if (!appId || !itemType) {
14372
+ throw new OpenMatesConfigError("Memory create/update requires appId and itemType");
14373
+ }
14374
+ const now = Math.floor(Date.now() / 1e3);
14375
+ const entry = {
14376
+ id: String(input.id ?? randomUUID6()),
14377
+ app_id: appId,
14378
+ item_key: hashItemKey(appId, itemType),
14379
+ item_type: itemType,
14380
+ encrypted_item_json: await encryptWithAesGcmCombined(
14381
+ JSON.stringify({ ...itemValue, settings_group: appId, _original_item_key: itemType, added_date: now }),
14382
+ await this.client.masterKey()
14383
+ ),
14384
+ encrypted_app_key: "",
14385
+ created_at: Number(input.created_at ?? now),
14386
+ updated_at: now,
14387
+ item_version: Number(input.itemVersion ?? input.item_version ?? 1)
14388
+ };
14389
+ return this.client.request("/v1/sdk/memories", { entry });
14390
+ }
14391
+ };
14392
+ var OpenMatesBilling = class {
14393
+ client;
14394
+ constructor(client) {
14395
+ this.client = client;
14396
+ }
14397
+ async overview() {
14398
+ return this.client.get("/v1/sdk/billing");
14399
+ }
14400
+ async usage(options = {}) {
14401
+ return this.client.get(withQuery("/v1/sdk/billing/usage", options.query));
14402
+ }
14403
+ async usageSummaries() {
14404
+ return this.client.get("/v1/sdk/billing/usage/summaries");
14405
+ }
14406
+ async usageDaily() {
14407
+ return this.client.get("/v1/sdk/billing/usage/daily");
14408
+ }
14409
+ async usageExport(options = {}) {
14410
+ return this.client.getRaw(withQuery("/v1/sdk/billing/usage/export", { months: options.months }));
14411
+ }
14412
+ async createBankTransferOrder(credits) {
14413
+ return this.client.request("/v1/sdk/billing/bank-transfer-orders", { credits_amount: credits, currency: "eur" });
14414
+ }
14415
+ async bankTransferStatus(orderId) {
14416
+ return this.client.get(`/v1/sdk/billing/bank-transfer-orders/${encodeURIComponent(orderId)}`);
14417
+ }
14418
+ async listBankTransferOrders() {
14419
+ return this.client.get("/v1/sdk/billing/bank-transfer-orders");
14420
+ }
14421
+ async listInvoices() {
14422
+ return this.client.get("/v1/sdk/billing/invoices");
14423
+ }
14424
+ async downloadInvoice(invoiceId) {
14425
+ return this.client.getRaw(`/v1/sdk/billing/invoices/${encodeURIComponent(invoiceId)}/download`);
14426
+ }
14427
+ async downloadCreditNote(invoiceId) {
14428
+ return this.client.getRaw(`/v1/sdk/billing/invoices/${encodeURIComponent(invoiceId)}/credit-note/download`);
14429
+ }
14430
+ async requestRefund(invoiceId, options) {
14431
+ requireConfirmed(options, "Requesting an invoice refund");
14432
+ return this.client.request("/v1/sdk/billing/refund", { invoice_id: invoiceId, email_encryption_key: options.emailEncryptionKey });
14433
+ }
14434
+ async redeemGiftCard(code) {
14435
+ return this.client.request("/v1/sdk/billing/gift-cards/redeem", { code });
14436
+ }
14437
+ async listRedeemedGiftCards() {
14438
+ return this.client.get("/v1/sdk/billing/gift-cards/redeemed");
14439
+ }
14440
+ async createGiftCardBankTransferOrder(credits) {
14441
+ return this.client.request("/v1/sdk/billing/gift-cards/bank-transfer-orders", { credits_amount: credits, currency: "eur" });
14442
+ }
14443
+ async giftCardPurchaseStatus(orderId) {
14444
+ return this.client.get(`/v1/sdk/billing/gift-cards/purchases/${encodeURIComponent(orderId)}`);
14445
+ }
14446
+ async listPurchasedGiftCards() {
14447
+ return this.client.get("/v1/sdk/billing/gift-cards/purchased");
14448
+ }
14449
+ async setLowBalanceAutoTopup(input) {
14450
+ return this.client.request("/v1/sdk/billing/auto-topup/low-balance", input);
14451
+ }
14452
+ };
14453
+ var OpenMatesNotifications = class {
14454
+ client;
14455
+ constructor(client) {
14456
+ this.client = client;
14457
+ }
14458
+ async status() {
14459
+ return this.client.get("/v1/sdk/notifications/status");
14460
+ }
14461
+ async list(options = {}) {
14462
+ return this.client.get(withQuery("/v1/sdk/notifications", { limit: options.limit }));
14463
+ }
14464
+ };
14465
+ var OpenMatesReminders = class {
14466
+ client;
14467
+ constructor(client) {
14468
+ this.client = client;
14469
+ }
14470
+ async list() {
14471
+ return this.client.get("/v1/sdk/reminders");
14472
+ }
14473
+ async update(id, input) {
14474
+ return this.client.patch(`/v1/sdk/reminders/${encodeURIComponent(id)}`, input);
14475
+ }
14476
+ async delete(id, options) {
14477
+ requireConfirmed(options, "Deleting a reminder");
14478
+ return this.client.delete(`/v1/sdk/reminders/${encodeURIComponent(id)}`);
14479
+ }
14480
+ };
14481
+ var OpenMatesProjects = class {
14482
+ client;
14483
+ constructor(client) {
14484
+ this.client = client;
14485
+ }
14486
+ async listSources(projectId) {
14487
+ const response = await this.client.get(`/v1/projects/${encodeURIComponent(projectId)}/sources`);
14488
+ return response.sources ?? [];
14489
+ }
14490
+ async createSource(projectId, input) {
14491
+ const response = await this.client.request(`/v1/projects/${encodeURIComponent(projectId)}/sources`, input);
14492
+ if (!response.source) throw new OpenMatesApiError(500, { detail: "Project source response missing source" });
14493
+ return response.source;
14494
+ }
14495
+ };
14496
+ var OpenMatesTasks = class {
14497
+ client;
14498
+ constructor(client) {
14499
+ this.client = client;
14500
+ }
14501
+ async list(filters = {}) {
14502
+ const response = await this.client.get(withQuery("/v1/user-tasks", {
14503
+ status: filters.status,
14504
+ chat_id: filters.chatId,
14505
+ project_id: filters.projectId
14506
+ }));
14507
+ return response.tasks ?? [];
14508
+ }
14509
+ async create(input) {
14510
+ const response = await this.client.request("/v1/user-tasks", input);
14511
+ if (!response.task) throw new OpenMatesApiError(500, { detail: "User task response missing task" });
14512
+ return response.task;
14513
+ }
14514
+ async update(taskId, input) {
14515
+ const response = await this.client.patch(`/v1/user-tasks/${encodeURIComponent(taskId)}`, input);
14516
+ if (!response.task) throw new OpenMatesApiError(500, { detail: "User task response missing task" });
14517
+ return response.task;
14518
+ }
14519
+ async startAI(taskId, input) {
14520
+ const response = await this.client.request(`/v1/user-tasks/${encodeURIComponent(taskId)}/start-ai`, input);
14521
+ if (!response.task) throw new OpenMatesApiError(500, { detail: "User task response missing task" });
14522
+ return response.task;
14523
+ }
14524
+ };
14525
+ var OpenMatesPlans = class {
14526
+ client;
14527
+ constructor(client) {
14528
+ this.client = client;
14529
+ }
14530
+ async list(filters = {}) {
14531
+ const response = await this.client.get(withQuery("/v1/user-plans", {
14532
+ status: filters.status,
14533
+ chat_id: filters.chatId,
14534
+ project_id: filters.projectId,
14535
+ active_only: filters.activeOnly
14536
+ }));
14537
+ return response.plans ?? [];
14538
+ }
14539
+ async create(input) {
14540
+ const response = await this.client.request("/v1/user-plans", input);
14541
+ if (!response.plan) throw new OpenMatesApiError(500, { detail: "User plan response missing plan" });
14542
+ return response.plan;
14543
+ }
14544
+ async update(planId, input) {
14545
+ const response = await this.client.patch(`/v1/user-plans/${encodeURIComponent(planId)}`, input);
14546
+ if (!response.plan) throw new OpenMatesApiError(500, { detail: "User plan response missing plan" });
14547
+ return response.plan;
14548
+ }
14549
+ async activate(planId, input = {}) {
14550
+ const response = await this.client.request(`/v1/user-plans/${encodeURIComponent(planId)}/activate`, input);
14551
+ if (!response.plan) throw new OpenMatesApiError(500, { detail: "User plan response missing plan" });
14552
+ return response.plan.primary_chat_id || typeof input.chat_id !== "string" ? response.plan : { ...response.plan, primary_chat_id: input.chat_id };
14553
+ }
14554
+ async complete(planId, input = {}) {
14555
+ const response = await this.client.request(`/v1/user-plans/${encodeURIComponent(planId)}/complete`, input);
14556
+ if (!response.plan) throw new OpenMatesApiError(500, { detail: "User plan response missing plan" });
14557
+ return response.plan;
14558
+ }
14559
+ async createCriterion(planId, input) {
14560
+ const response = await this.client.request(`/v1/user-plans/${encodeURIComponent(planId)}/criteria`, input);
14561
+ if (!response.criterion) throw new OpenMatesApiError(500, { detail: "User plan criterion response missing criterion" });
14562
+ return response.criterion;
14563
+ }
14564
+ async createVerification(planId, input) {
14565
+ const response = await this.client.request(`/v1/user-plans/${encodeURIComponent(planId)}/verification`, input);
14566
+ if (!response.verification) throw new OpenMatesApiError(500, { detail: "User plan verification response missing verification" });
14567
+ return response.verification;
14568
+ }
14569
+ async addVerificationEvidence(planId, verificationId, input) {
14570
+ const response = await this.client.request(`/v1/user-plans/${encodeURIComponent(planId)}/verification/${encodeURIComponent(verificationId)}/evidence`, input);
14571
+ if (!response.verification) throw new OpenMatesApiError(500, { detail: "User plan verification response missing verification" });
14572
+ return response.verification;
14573
+ }
14574
+ };
14575
+ var OpenMatesWorkflows = class {
14576
+ client;
14577
+ constructor(client) {
14578
+ this.client = client;
14579
+ }
14580
+ async list() {
14581
+ const response = await this.client.get("/v1/workflows");
14582
+ return response.workflows ?? [];
14583
+ }
14584
+ async temporary() {
14585
+ const response = await this.client.get("/v1/workflows/temporary");
14586
+ return response.workflows ?? [];
14587
+ }
14588
+ async capabilities() {
14589
+ const response = await this.client.get("/v1/workflows/capabilities");
14590
+ return response.capabilities ?? [];
14591
+ }
14592
+ async validateYaml(source) {
14593
+ const response = await this.client.request("/v1/workflows/validate", { source });
14594
+ if (!response.validation) throw new OpenMatesApiError(500, { detail: "Workflow validation response missing validation" });
14595
+ return response.validation;
14596
+ }
14597
+ async createFromYaml(source) {
14598
+ const response = await this.client.request("/v1/workflows/yaml", { source });
14599
+ if (!response.workflow) throw new OpenMatesApiError(500, { detail: "Workflow YAML response missing workflow" });
14600
+ if (!response.validation) throw new OpenMatesApiError(500, { detail: "Workflow YAML response missing validation" });
14601
+ return { workflow: response.workflow, validation: response.validation };
14602
+ }
14603
+ async updateFromYaml(workflowId, source) {
14604
+ const response = await this.client.request(`/v1/workflows/${encodeURIComponent(workflowId)}/yaml`, { source });
14605
+ if (!response.workflow) throw new OpenMatesApiError(500, { detail: "Workflow YAML response missing workflow" });
14606
+ if (!response.validation) throw new OpenMatesApiError(500, { detail: "Workflow YAML response missing validation" });
14607
+ return { workflow: response.workflow, validation: response.validation };
14608
+ }
14609
+ async startInput(params) {
14610
+ const response = await this.client.request("/v1/workflows/input", {
14611
+ ...params.text !== void 0 ? { text: params.text } : {},
14612
+ input_type: params.inputType ?? "text",
14613
+ ...params.audioRef !== void 0 ? { audio_ref: params.audioRef } : {},
14614
+ ...params.selectedWorkflowId !== void 0 ? { selected_workflow_id: params.selectedWorkflowId } : {},
14615
+ ...params.selectedProjectId !== void 0 ? { selected_project_id: params.selectedProjectId } : {}
14616
+ });
14617
+ if (!response.session) throw new OpenMatesApiError(500, { detail: "Workflow input response missing session" });
14618
+ return response.session;
14619
+ }
14620
+ async inputSession(sessionId) {
14621
+ const response = await this.client.get(`/v1/workflows/input/${encodeURIComponent(sessionId)}`);
14622
+ if (!response.session) throw new OpenMatesApiError(500, { detail: "Workflow input response missing session" });
14623
+ return response.session;
14624
+ }
14625
+ async inputEvents(sessionId, afterEventId = 0) {
14626
+ const response = await this.client.get(`/v1/workflows/input/${encodeURIComponent(sessionId)}/events?after_event_id=${encodeURIComponent(String(afterEventId))}`);
14627
+ return response.events ?? [];
14628
+ }
14629
+ async followUpInput(sessionId, text) {
14630
+ const response = await this.client.request(`/v1/workflows/input/${encodeURIComponent(sessionId)}/follow-up`, { text });
14631
+ if (!response.session) throw new OpenMatesApiError(500, { detail: "Workflow input response missing session" });
14632
+ return response.session;
14633
+ }
14634
+ async stopInput(sessionId) {
14635
+ const response = await this.client.request(`/v1/workflows/input/${encodeURIComponent(sessionId)}/stop`, {});
14636
+ if (!response.session) throw new OpenMatesApiError(500, { detail: "Workflow input response missing session" });
14637
+ return response.session;
14638
+ }
14639
+ async undoInput(sessionId) {
14640
+ const response = await this.client.request(`/v1/workflows/input/${encodeURIComponent(sessionId)}/undo`, {});
14641
+ if (!response.session) throw new OpenMatesApiError(500, { detail: "Workflow input response missing session" });
14642
+ return response.session;
14643
+ }
14644
+ async get(workflowId) {
14645
+ const response = await this.client.get(`/v1/workflows/${encodeURIComponent(workflowId)}`);
14646
+ if (!response.workflow) throw new OpenMatesApiError(500, { detail: "Workflow response missing workflow" });
14647
+ return response.workflow;
14648
+ }
14649
+ async create(params) {
14650
+ const response = await this.client.request("/v1/workflows", {
14651
+ title: params.title,
14652
+ ...params.description !== void 0 ? { description: params.description } : {},
14653
+ graph: params.graph,
14654
+ enabled: params.enabled ?? false,
14655
+ run_content_retention: params.runContentRetention ?? "last_5",
14656
+ ...params.lifecycle ? { lifecycle: params.lifecycle } : {},
14657
+ ...params.source ? { source: params.source } : {},
14658
+ ...params.sourceChatId !== void 0 ? { source_chat_id: params.sourceChatId } : {},
14659
+ ...params.createdByAssistant !== void 0 ? { created_by_assistant: params.createdByAssistant } : {},
14660
+ ...params.autoDeleteAt !== void 0 ? { auto_delete_at: params.autoDeleteAt } : {}
14661
+ });
14662
+ if (!response.workflow) throw new OpenMatesApiError(500, { detail: "Workflow response missing workflow" });
14663
+ return response.workflow;
14664
+ }
14665
+ async update(workflowId, params) {
14666
+ const payload = {};
14667
+ if (params.title !== void 0) payload.title = params.title;
14668
+ if (params.description !== void 0) payload.description = params.description;
14669
+ if (params.graph !== void 0) payload.graph = params.graph;
14670
+ if (params.enabled !== void 0) payload.enabled = params.enabled;
14671
+ if (params.runContentRetention !== void 0) payload.run_content_retention = params.runContentRetention;
14672
+ const response = await this.client.patch(`/v1/workflows/${encodeURIComponent(workflowId)}`, payload);
14673
+ if (!response.workflow) throw new OpenMatesApiError(500, { detail: "Workflow response missing workflow" });
14674
+ return response.workflow;
14675
+ }
14676
+ async enable(workflowId) {
14677
+ const response = await this.client.request(`/v1/workflows/${encodeURIComponent(workflowId)}/enable`, {});
14678
+ if (!response.workflow) throw new OpenMatesApiError(500, { detail: "Workflow response missing workflow" });
14679
+ return response.workflow;
14680
+ }
14681
+ async disable(workflowId) {
14682
+ const response = await this.client.request(`/v1/workflows/${encodeURIComponent(workflowId)}/disable`, {});
14683
+ if (!response.workflow) throw new OpenMatesApiError(500, { detail: "Workflow response missing workflow" });
14684
+ return response.workflow;
14685
+ }
14686
+ async delete(workflowId, options = {}) {
14687
+ requireConfirmed(options, "Deleting a workflow");
14688
+ return this.client.delete(`/v1/workflows/${encodeURIComponent(workflowId)}`);
14689
+ }
14690
+ async keep(workflowId) {
14691
+ const response = await this.client.request(`/v1/workflows/${encodeURIComponent(workflowId)}/keep`, {});
14692
+ if (!response.workflow) throw new OpenMatesApiError(500, { detail: "Workflow response missing workflow" });
14693
+ return response.workflow;
14694
+ }
14695
+ async run(workflowId, params) {
14696
+ if (!params.idempotencyKey.trim()) throw new OpenMatesConfigError("Workflow run requires a stable idempotencyKey");
14697
+ const response = await this.client.request(`/v1/workflows/${encodeURIComponent(workflowId)}/run`, {
14698
+ mode: params.mode ?? "manual",
14699
+ input: params.input ?? {}
14700
+ }, void 0, { "Idempotency-Key": params.idempotencyKey });
14701
+ if (!response.run) throw new OpenMatesApiError(500, { detail: "Workflow response missing run" });
14702
+ return response.run;
14703
+ }
14704
+ async runs(workflowId) {
14705
+ const response = await this.client.get(`/v1/workflows/${encodeURIComponent(workflowId)}/runs`);
14706
+ return response.runs ?? [];
14707
+ }
14708
+ async runDetail(workflowId, runId) {
14709
+ const response = await this.client.get(`/v1/workflows/${encodeURIComponent(workflowId)}/runs/${encodeURIComponent(runId)}`);
14710
+ if (!response.run) throw new OpenMatesApiError(500, { detail: "Workflow response missing run" });
14711
+ return response.run;
14712
+ }
14713
+ async cancelRun(workflowId, runId) {
14714
+ const result = await this.client.request(
14715
+ `/v1/workflows/${encodeURIComponent(workflowId)}/runs/${encodeURIComponent(runId)}/cancel`,
14716
+ {}
14717
+ );
14718
+ if (result.status !== "cancellation_requested" && result.status !== "cancelled") {
14719
+ throw new OpenMatesApiError(500, { detail: "Workflow response has invalid cancellation status" });
14720
+ }
14721
+ return result;
14722
+ }
14723
+ async respond(workflowId, runId, stepId, input) {
14724
+ const response = await this.client.request(
14725
+ `/v1/workflows/${encodeURIComponent(workflowId)}/runs/${encodeURIComponent(runId)}/respond`,
14726
+ { step_id: stepId, input }
14727
+ );
14728
+ if (!response.run) throw new OpenMatesApiError(500, { detail: "Workflow response missing run" });
14729
+ return response.run;
14730
+ }
14731
+ async upsertTemplateProjection(workflowId, params) {
14732
+ return this.client.put(`/v1/workflows/${encodeURIComponent(workflowId)}/template-projection`, {
14733
+ template_id: params.templateId,
14734
+ source_version: params.sourceVersion,
14735
+ ciphertext: params.ciphertext,
14736
+ ciphertext_checksum: params.ciphertextChecksum,
14737
+ owner_wrapped_key: params.ownerWrappedKey,
14738
+ projection_schema_version: params.projectionSchemaVersion
14739
+ });
14740
+ }
14741
+ async getPublicTemplateProjection(templateId) {
14742
+ return this.client.getPublic(
14743
+ `/v1/workflows/template-projections/${encodeURIComponent(templateId)}`
14744
+ );
14745
+ }
14746
+ async revokeTemplateProjection(workflowId) {
14747
+ return this.client.request(
14748
+ `/v1/workflows/${encodeURIComponent(workflowId)}/template-projection/revoke`,
14749
+ {}
14750
+ );
14751
+ }
14752
+ async unrevokeTemplateProjection(workflowId) {
14753
+ return this.client.request(
14754
+ `/v1/workflows/${encodeURIComponent(workflowId)}/template-projection/unrevoke`,
14755
+ {}
14756
+ );
14757
+ }
14758
+ async completeImportedBinding(workflowId, params) {
14759
+ return this.client.request(
14760
+ `/v1/workflows/${encodeURIComponent(workflowId)}/binding-requirements/complete`,
14761
+ { type: params.type, node_id: params.nodeId }
14762
+ );
14763
+ }
14764
+ async createTemplateShortUrl(params) {
14765
+ return this.client.request("/v1/share/short-url", {
14766
+ token: params.token,
14767
+ encrypted_url: params.encryptedUrl,
14768
+ content_type: "workflow_template",
14769
+ content_id: params.templateId,
14770
+ password_protected: params.passwordProtected ?? false,
14771
+ ...params.ttlSeconds !== void 0 ? { ttl_seconds: params.ttlSeconds } : {}
14772
+ });
14773
+ }
14774
+ async revokeShortUrl(token) {
14775
+ return this.client.delete(`/v1/share/short-url/${encodeURIComponent(token)}`);
14776
+ }
14777
+ async importTemplate(payload) {
14778
+ const response = await this.client.request("/v1/workflows/template-import", payload);
14779
+ if (!response.workflow) throw new OpenMatesApiError(500, { detail: "Workflow template import response missing workflow" });
14780
+ return response.workflow;
14781
+ }
14782
+ };
14783
+ var OpenMatesDocs = class {
14784
+ client;
14785
+ constructor(client) {
14786
+ this.client = client;
14787
+ }
14788
+ async list() {
14789
+ return this.client.get("/v1/sdk/docs");
14790
+ }
14791
+ async search(query) {
14792
+ return this.client.get(withQuery("/v1/sdk/docs/search", { q: query }));
14793
+ }
14794
+ async show(slug) {
14795
+ return this.client.get(`/v1/sdk/docs/${encodeURIComponent(slug)}`);
14796
+ }
14797
+ async download(slug) {
14798
+ return this.client.get(`/v1/sdk/docs/${encodeURIComponent(slug)}/download`);
14799
+ }
14800
+ };
14801
+ var OpenMatesEmbeds = class {
14802
+ preview;
14803
+ client;
14804
+ constructor(client) {
14805
+ this.client = client;
14806
+ this.preview = new OpenMatesEmbedPreview(client);
14807
+ }
14808
+ async show(embedId) {
14809
+ return this.client.get(`/v1/sdk/embeds/${encodeURIComponent(embedId)}`);
14810
+ }
14811
+ async share(embedId, options = {}) {
14812
+ const shown = await this.show(embedId);
14813
+ const keys = Array.isArray(shown.embed_keys) ? shown.embed_keys : [];
14814
+ const embedKey = await this.client.resolveEmbedKeyForShare(keys, embedId);
14815
+ if (!embedKey) throw new OpenMatesConfigError("Unable to resolve embed key for share link");
14816
+ const blob = await generateEmbedShareBlob(embedId, embedKey, options.expires ?? 0, options.password);
14817
+ return { url: buildEmbedShareUrl(this.client.webOrigin(), embedId, blob) };
14818
+ }
14819
+ async versions(embedId) {
14820
+ return this.client.get(`/v1/sdk/embeds/${encodeURIComponent(embedId)}/versions`);
14821
+ }
14822
+ async version(embedId, version) {
14823
+ return this.client.get(`/v1/sdk/embeds/${encodeURIComponent(embedId)}/versions/${version}`);
14824
+ }
14825
+ async restoreVersion(embedId, version, options) {
14826
+ requireConfirmed(options, "Restoring an embed version");
14827
+ return this.client.request(`/v1/sdk/embeds/${encodeURIComponent(embedId)}/versions/${version}/restore`);
14828
+ }
14829
+ };
14830
+ var OpenMatesEmbedPreview = class {
14831
+ client;
14832
+ constructor(client) {
14833
+ this.client = client;
14834
+ }
14835
+ async start(embedId, options) {
14836
+ const response = await this.client.request(
14837
+ `/v1/applications/${encodeURIComponent(embedId)}/preview/start`,
14838
+ {
14839
+ chat_id: options.chatId,
14840
+ ...options.sharedContext ? { shared_context: options.sharedContext } : {},
14841
+ ...options.requestedRuntime ? { requested_runtime: options.requestedRuntime } : {},
14842
+ ...options.sourceMessageId ? { source_message_id: options.sourceMessageId } : {}
14843
+ }
14844
+ );
14845
+ return options.wait === true ? this.waitForRunning(response.session_id, options.timeoutMs ?? 12e4) : response;
14846
+ }
14847
+ async status(sessionId) {
14848
+ return this.client.get(`/v1/applications/preview/${encodeURIComponent(sessionId)}`);
14849
+ }
14850
+ async open(sessionId) {
14851
+ return this.client.request(`/v1/applications/preview/${encodeURIComponent(sessionId)}/open`, {});
14852
+ }
14853
+ async stop(sessionId) {
14854
+ return this.client.request(`/v1/applications/preview/${encodeURIComponent(sessionId)}/stop`, {});
14855
+ }
14856
+ async waitForRunning(sessionId, timeoutMs) {
14857
+ const deadline = Date.now() + timeoutMs;
14858
+ while (Date.now() < deadline) {
14859
+ const status = await this.status(sessionId);
14860
+ if (["running", "failed", "timeout", "cancelled", "stopped"].includes(status.status)) {
14861
+ return status;
14862
+ }
14863
+ await new Promise((resolve7) => setTimeout(resolve7, 1e3));
14864
+ }
14865
+ throw new OpenMatesApiError(408, { detail: "Application preview did not reach running state before timeout" });
14866
+ }
14867
+ };
14868
+ var OpenMatesConnectedAccounts = class {
14869
+ client;
14870
+ constructor(client) {
14871
+ this.client = client;
14872
+ }
14873
+ async import(input) {
14874
+ const payload = await decryptConnectedAccountCliTransferPayload(input.payload, input.passcode);
14875
+ const account = await this.client.get("/v1/sdk/account");
14876
+ const userId = typeof account.id === "string" ? account.id : "";
14877
+ if (!userId) {
14878
+ throw new OpenMatesConfigError("Could not resolve current user id for connected account import");
14879
+ }
14880
+ const row = await buildEncryptedConnectedAccountImportRow({
14881
+ payload,
14882
+ userId,
14883
+ masterKey: await this.client.masterKey()
14884
+ });
14885
+ return this.client.request("/v1/sdk/connected-accounts/import", { row });
14886
+ }
14887
+ };
14888
+ var OpenMatesLearningMode = class {
14889
+ client;
14890
+ constructor(client) {
14891
+ this.client = client;
14892
+ }
14893
+ async status() {
14894
+ return this.client.get("/v1/sdk/learning-mode");
14895
+ }
14896
+ async enable(input) {
14897
+ return this.client.request("/v1/sdk/learning-mode/enable", { age_group: input.ageGroup, passcode: input.passcode });
14898
+ }
14899
+ async disable(passcode) {
14900
+ return this.client.request("/v1/sdk/learning-mode/disable", { passcode });
14901
+ }
14902
+ };
14903
+ var OpenMatesInspirations = class {
14904
+ client;
14905
+ constructor(client) {
14906
+ this.client = client;
14907
+ }
14908
+ async list(options = {}) {
14909
+ return this.client.get(withQuery("/v1/sdk/inspirations", { lang: options.language }));
14910
+ }
14911
+ };
14912
+ var OpenMatesNewChatSuggestions = class {
14913
+ client;
14914
+ constructor(client) {
14915
+ this.client = client;
14916
+ }
14917
+ async list(options = {}) {
14918
+ return this.client.get(withQuery("/v1/sdk/new-chat-suggestions", { limit: options.limit ?? 10 }));
14919
+ }
14920
+ };
14921
+ var OpenMatesFeedback = class {
14922
+ client;
14923
+ constructor(client) {
14924
+ this.client = client;
14925
+ }
14926
+ async assistantResponse(input) {
14927
+ return this.client.request("/v1/sdk/feedback/assistant-response", input);
14928
+ }
14929
+ };
14930
+ var OpenMatesBenchmark = class {
14931
+ client;
14932
+ constructor(client) {
14933
+ this.client = client;
14934
+ }
14935
+ async run(input) {
14936
+ return this.client.request("/v1/sdk/benchmark/run", input);
14937
+ }
14938
+ async estimate(input) {
14939
+ return this.client.request("/v1/sdk/benchmark/estimate", input);
14940
+ }
14941
+ };
14942
+
14943
+ // src/cli.ts
14944
+ import { createInterface as createInterface5 } from "readline/promises";
14945
+ import { stdin as stdin3, stdout as stdout2 } from "process";
14946
+ import { readFileSync as readFileSync10, realpathSync, writeFileSync as writeFileSync7 } from "fs";
14947
+ import { fileURLToPath as fileURLToPath2 } from "url";
14948
+ import { basename as basename3, dirname as dirname4 } from "path";
14949
+ import { randomUUID as randomUUID8 } from "crypto";
14950
+ import WebSocket2 from "ws";
14951
+
13593
14952
  // ../secret-scanner/src/registry.ts
13594
14953
  import { createRequire as createRequire2 } from "module";
13595
14954
 
@@ -14303,10 +15662,10 @@ var OutputRedactor = class {
14303
15662
  };
14304
15663
 
14305
15664
  // src/fileEmbed.ts
14306
- import { readFileSync as readFileSync4, statSync, existsSync as existsSync5 } from "fs";
15665
+ import { readFileSync as readFileSync5, statSync, existsSync as existsSync6 } from "fs";
14307
15666
  import { basename, extname, resolve as resolve2 } from "path";
14308
- import { homedir as homedir4 } from "os";
14309
- import { createHash as createHash6 } from "crypto";
15667
+ import { homedir as homedir5 } from "os";
15668
+ import { createHash as createHash7 } from "crypto";
14310
15669
  var MAX_PER_FILE_SIZE = 100 * 1024 * 1024;
14311
15670
  var BLOCKED_EXTENSIONS = /* @__PURE__ */ new Set([
14312
15671
  ".pem",
@@ -14510,7 +15869,7 @@ function processEnvFileZeroKnowledge(content) {
14510
15869
  }
14511
15870
  function resolvePath(filePath) {
14512
15871
  if (filePath.startsWith("~/")) {
14513
- return resolve2(homedir4(), filePath.slice(2));
15872
+ return resolve2(homedir5(), filePath.slice(2));
14514
15873
  }
14515
15874
  return resolve2(filePath);
14516
15875
  }
@@ -14522,7 +15881,7 @@ function processFiles(filePaths, redactor) {
14522
15881
  const resolvedPath = resolvePath(rawPath);
14523
15882
  const filename = basename(resolvedPath);
14524
15883
  const ext = getExt(filename);
14525
- if (!existsSync5(resolvedPath)) {
15884
+ if (!existsSync6(resolvedPath)) {
14526
15885
  errors.push({ path: rawPath, error: "File not found" });
14527
15886
  continue;
14528
15887
  }
@@ -14588,7 +15947,7 @@ function processFiles(filePaths, redactor) {
14588
15947
  }
14589
15948
  function processCodeFile(filePath, filename, redactor) {
14590
15949
  try {
14591
- let content = readFileSync4(filePath, "utf-8");
15950
+ let content = readFileSync5(filePath, "utf-8");
14592
15951
  let secretsRedacted = false;
14593
15952
  let zeroKnowledge = false;
14594
15953
  if (isEnvFile(filename)) {
@@ -14616,7 +15975,7 @@ function processCodeFile(filePath, filename, redactor) {
14616
15975
  line_count: lineCount
14617
15976
  });
14618
15977
  const textPreview = `${filename} (${language}, ${lineCount} lines)`;
14619
- const contentHash = createHash6("sha256").update(content).digest("hex");
15978
+ const contentHash = createHash7("sha256").update(content).digest("hex");
14620
15979
  const embed = {
14621
15980
  embedId,
14622
15981
  embedRef,
@@ -16171,12 +17530,12 @@ function formatTs(ts) {
16171
17530
 
16172
17531
  // src/server.ts
16173
17532
  import { execFileSync as execFileSync2, execSync, spawn as nodeSpawn, spawnSync } from "child_process";
16174
- import { createHash as createHash7, randomBytes as randomBytes3 } from "crypto";
16175
- import { chmodSync as chmodSync2, closeSync, copyFileSync, cpSync, existsSync as existsSync6, mkdirSync as mkdirSync3, mkdtempSync, openSync, readFileSync as readFileSync5, readSync, readdirSync, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "fs";
17533
+ import { createHash as createHash8, randomBytes as randomBytes4 } from "crypto";
17534
+ 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";
16176
17535
  import { createInterface as createInterface3 } from "readline";
16177
17536
  import { createInterface as createPromptInterface } from "readline/promises";
16178
- import { homedir as homedir5 } from "os";
16179
- import { dirname, join as join3, resolve as resolve3 } from "path";
17537
+ import { homedir as homedir6 } from "os";
17538
+ import { dirname as dirname2, join as join4, resolve as resolve3 } from "path";
16180
17539
 
16181
17540
  // src/branding.ts
16182
17541
  var OPENMATES_WORDMARK = "OPENMATES";
@@ -16446,19 +17805,19 @@ function planContinuousUpdateService(input) {
16446
17805
  }
16447
17806
 
16448
17807
  // src/server.ts
16449
- var SOURCE_COMPOSE_FILE = join3("backend", "core", "docker-compose.yml");
17808
+ var SOURCE_COMPOSE_FILE = join4("backend", "core", "docker-compose.yml");
16450
17809
  var ROLE_IMAGE_COMPOSE_FILES = {
16451
- core: join3("backend", "core", "docker-compose.selfhost.yml"),
16452
- upload: join3("backend", "upload", "docker-compose.yml"),
16453
- preview: join3("backend", "preview", "docker-compose.preview.yml")
17810
+ core: join4("backend", "core", "docker-compose.selfhost.yml"),
17811
+ upload: join4("backend", "upload", "docker-compose.yml"),
17812
+ preview: join4("backend", "preview", "docker-compose.preview.yml")
16454
17813
  };
16455
17814
  var ROLE_TEMPLATE_FILES = {
16456
- core: join3("core", "docker-compose.selfhost.yml"),
16457
- upload: join3("upload", "docker-compose.yml"),
16458
- preview: join3("preview", "docker-compose.preview.yml")
17815
+ core: join4("core", "docker-compose.selfhost.yml"),
17816
+ upload: join4("upload", "docker-compose.yml"),
17817
+ preview: join4("preview", "docker-compose.preview.yml")
16459
17818
  };
16460
- var COMPOSE_OVERRIDE = join3("backend", "core", "docker-compose.override.yml");
16461
- var DEFAULT_INSTALL_PATH = join3(homedir5(), "openmates");
17819
+ var COMPOSE_OVERRIDE = join4("backend", "core", "docker-compose.override.yml");
17820
+ var DEFAULT_INSTALL_PATH = join4(homedir6(), "openmates");
16462
17821
  var REPO_URL = "https://github.com/glowingkitty/OpenMates.git";
16463
17822
  var DEV_BRANCH = "dev";
16464
17823
  var MAIN_BRANCH = "main";
@@ -16472,8 +17831,8 @@ var IMAGE_CHANNEL_TAGS = {
16472
17831
  main: MAIN_BRANCH,
16473
17832
  dev: DEV_BRANCH
16474
17833
  };
16475
- var BACKEND_CONFIG_FILE = join3("backend", "config", "backend_config.yml");
16476
- var IMAGE_RUNTIME_CONFIG_FILE = join3("config", "backend_config.yml");
17834
+ var BACKEND_CONFIG_FILE = join4("backend", "config", "backend_config.yml");
17835
+ var IMAGE_RUNTIME_CONFIG_FILE = join4("config", "backend_config.yml");
16477
17836
  var LOCAL_AI_MODELS_FILE = "local-ai-models.yml";
16478
17837
  var OFF_BY_DEFAULT_FEATURES = /* @__PURE__ */ new Map([
16479
17838
  ["embed:code:application", "Application previews are still unstable"],
@@ -16613,7 +17972,7 @@ function loadConfigForInstallPath(installPath) {
16613
17972
  }
16614
17973
  function getInstallMode(installPath, config = loadConfigForInstallPath(installPath)) {
16615
17974
  if (config?.installMode) return config.installMode;
16616
- if (Object.values(ROLE_IMAGE_COMPOSE_FILES).some((composeFile) => existsSync6(join3(installPath, composeFile)))) return "image";
17975
+ if (Object.values(ROLE_IMAGE_COMPOSE_FILES).some((composeFile) => existsSync7(join4(installPath, composeFile)))) return "image";
16617
17976
  return "source";
16618
17977
  }
16619
17978
  function getServerRole(flags, config) {
@@ -16698,24 +18057,24 @@ function featureKind(featureId) {
16698
18057
  function composeArgs(installPath, withOverrides, installMode = getInstallMode(installPath), role = "core") {
16699
18058
  const composeFile = installMode === "image" ? ROLE_IMAGE_COMPOSE_FILES[role] : SOURCE_COMPOSE_FILE;
16700
18059
  const args = ["compose", "--env-file", ".env", "-f", composeFile];
16701
- if (withOverrides && existsSync6(join3(installPath, COMPOSE_OVERRIDE))) {
18060
+ if (withOverrides && existsSync7(join4(installPath, COMPOSE_OVERRIDE))) {
16702
18061
  args.push("-f", COMPOSE_OVERRIDE);
16703
18062
  }
16704
18063
  return args;
16705
18064
  }
16706
18065
  function ensureGitWorkDirEnv(installPath) {
16707
- const envPath = join3(installPath, ".env");
16708
- if (!existsSync6(envPath)) return;
16709
- const content = readFileSync5(envPath, "utf-8");
18066
+ const envPath = join4(installPath, ".env");
18067
+ if (!existsSync7(envPath)) return;
18068
+ const content = readFileSync6(envPath, "utf-8");
16710
18069
  const lineRegex = /^GIT_WORK_DIR=.*$/m;
16711
18070
  const value = `GIT_WORK_DIR=${installPath}`;
16712
18071
  if (lineRegex.test(content)) {
16713
18072
  const next = content.replace(lineRegex, value);
16714
- if (next !== content) writeFileSync3(envPath, next);
18073
+ if (next !== content) writeFileSync4(envPath, next);
16715
18074
  return;
16716
18075
  }
16717
18076
  const separator2 = content.endsWith("\n") ? "" : "\n";
16718
- writeFileSync3(envPath, `${content}${separator2}${value}
18077
+ writeFileSync4(envPath, `${content}${separator2}${value}
16719
18078
  `);
16720
18079
  }
16721
18080
  function requireDocker() {
@@ -16736,7 +18095,7 @@ function requireGit() {
16736
18095
  }
16737
18096
  function getPackageVersion() {
16738
18097
  try {
16739
- const packageJson = JSON.parse(readFileSync5(new URL("../package.json", import.meta.url), "utf-8"));
18098
+ const packageJson = JSON.parse(readFileSync6(new URL("../package.json", import.meta.url), "utf-8"));
16740
18099
  return packageJson.version ?? "";
16741
18100
  } catch {
16742
18101
  return "";
@@ -16789,10 +18148,10 @@ function resolveTargetImageTag(flags, currentTag, packageVersion) {
16789
18148
  return { tag: getDefaultImageTagForVersion(packageVersion) };
16790
18149
  }
16791
18150
  function randomHex(bytes) {
16792
- return randomBytes3(bytes).toString("hex");
18151
+ return randomBytes4(bytes).toString("hex");
16793
18152
  }
16794
18153
  function generateInviteCode() {
16795
- const digits = Array.from(randomBytes3(12), (byte) => String(byte % 10)).join("");
18154
+ const digits = Array.from(randomBytes4(12), (byte) => String(byte % 10)).join("");
16796
18155
  return `${digits.slice(0, 4)}-${digits.slice(4, 8)}-${digits.slice(8, 12)}`;
16797
18156
  }
16798
18157
  function getEnvVar(content, name) {
@@ -16829,38 +18188,38 @@ async function fetchText(url) {
16829
18188
  return response.text();
16830
18189
  }
16831
18190
  function packagedTemplatePath(role) {
16832
- return join3(dirname(new URL(import.meta.url).pathname), "..", "templates", ROLE_TEMPLATE_FILES[role]);
18191
+ return join4(dirname2(new URL(import.meta.url).pathname), "..", "templates", ROLE_TEMPLATE_FILES[role]);
16833
18192
  }
16834
18193
  function packagedCaddyTemplatePath(role) {
16835
- return join3(dirname(new URL(import.meta.url).pathname), "..", "templates", "caddy", role, "Caddyfile");
18194
+ return join4(dirname2(new URL(import.meta.url).pathname), "..", "templates", "caddy", role, "Caddyfile");
16836
18195
  }
16837
18196
  function fileHash(path) {
16838
- if (!existsSync6(path)) return null;
16839
- return createHash7("sha256").update(readFileSync5(path)).digest("hex");
18197
+ if (!existsSync7(path)) return null;
18198
+ return createHash8("sha256").update(readFileSync6(path)).digest("hex");
16840
18199
  }
16841
18200
  async function loadSelfHostComposeTemplate(templateRef, role) {
16842
18201
  const templateDir = process.env.OPENMATES_SELFHOST_TEMPLATE_DIR;
16843
18202
  if (templateDir) {
16844
- return readFileSync5(join3(resolve3(templateDir), ROLE_TEMPLATE_FILES[role]), "utf-8");
18203
+ return readFileSync6(join4(resolve3(templateDir), ROLE_TEMPLATE_FILES[role]), "utf-8");
16845
18204
  }
16846
18205
  const overrideUrl = process.env.OPENMATES_SELFHOST_COMPOSE_URL;
16847
18206
  if (overrideUrl) {
16848
18207
  return fetchText(overrideUrl);
16849
18208
  }
16850
18209
  const packaged = packagedTemplatePath(role);
16851
- if (existsSync6(packaged)) return readFileSync5(packaged, "utf-8");
18210
+ if (existsSync7(packaged)) return readFileSync6(packaged, "utf-8");
16852
18211
  return fetchText(`https://raw.githubusercontent.com/glowingkitty/OpenMates/${templateRef}/${ROLE_IMAGE_COMPOSE_FILES[role]}`);
16853
18212
  }
16854
18213
  async function writeImageModeRuntimeFiles(installPath, imageTag, role) {
16855
- const roleDir = join3(installPath, "backend", role === "core" ? "core" : role);
16856
- const vaultConfigDir = join3(roleDir, "vault", "config");
16857
- mkdirSync3(vaultConfigDir, { recursive: true });
16858
- mkdirSync3(join3(installPath, "config", "providers"), { recursive: true });
16859
- writeFileSync3(join3(installPath, ROLE_IMAGE_COMPOSE_FILES[role]), await loadSelfHostComposeTemplate(templateRefForImageTag(imageTag, getPackageVersion()), role));
16860
- writeFileSync3(join3(vaultConfigDir, "vault.hcl"), VAULT_CONFIG_TEMPLATE);
18214
+ const roleDir = join4(installPath, "backend", role === "core" ? "core" : role);
18215
+ const vaultConfigDir = join4(roleDir, "vault", "config");
18216
+ mkdirSync4(vaultConfigDir, { recursive: true });
18217
+ mkdirSync4(join4(installPath, "config", "providers"), { recursive: true });
18218
+ writeFileSync4(join4(installPath, ROLE_IMAGE_COMPOSE_FILES[role]), await loadSelfHostComposeTemplate(templateRefForImageTag(imageTag, getPackageVersion()), role));
18219
+ writeFileSync4(join4(vaultConfigDir, "vault.hcl"), VAULT_CONFIG_TEMPLATE);
16861
18220
  ensureImageRuntimeConfig(installPath);
16862
- const envPath = join3(installPath, ".env");
16863
- let envContent = existsSync6(envPath) ? readFileSync5(envPath, "utf-8") : MINIMAL_ENV_TEMPLATE;
18221
+ const envPath = join4(installPath, ".env");
18222
+ let envContent = existsSync7(envPath) ? readFileSync6(envPath, "utf-8") : MINIMAL_ENV_TEMPLATE;
16864
18223
  envContent = setEnvIfEmpty(envContent, "DATABASE_ADMIN_PASSWORD", randomHex(12));
16865
18224
  envContent = setEnvIfEmpty(envContent, "DATABASE_PASSWORD", randomHex(12));
16866
18225
  envContent = setEnvIfEmpty(envContent, "DIRECTUS_TOKEN", randomHex(32));
@@ -16872,13 +18231,13 @@ async function writeImageModeRuntimeFiles(installPath, imageTag, role) {
16872
18231
  envContent = setEnvVar(envContent, "OPENMATES_IMAGE_TAG", imageTag);
16873
18232
  envContent = setEnvVar(envContent, "OPENMATES_IMAGE_REGISTRY", DEFAULT_IMAGE_REGISTRY);
16874
18233
  envContent = setEnvVar(envContent, "GIT_WORK_DIR", installPath);
16875
- writeFileSync3(envPath, envContent.endsWith("\n") ? envContent : `${envContent}
18234
+ writeFileSync4(envPath, envContent.endsWith("\n") ? envContent : `${envContent}
16876
18235
  `);
16877
18236
  }
16878
18237
  function getImageTagFromEnv(installPath, config) {
16879
- const envPath = join3(installPath, ".env");
16880
- if (existsSync6(envPath)) {
16881
- const envTag = getEnvVar(readFileSync5(envPath, "utf-8"), "OPENMATES_IMAGE_TAG");
18238
+ const envPath = join4(installPath, ".env");
18239
+ if (existsSync7(envPath)) {
18240
+ const envTag = getEnvVar(readFileSync6(envPath, "utf-8"), "OPENMATES_IMAGE_TAG");
16882
18241
  if (envTag) return envTag;
16883
18242
  }
16884
18243
  return config?.imageTag ?? "";
@@ -16911,8 +18270,8 @@ async function waitForServerHealth(installPath, role = "core", options = {}) {
16911
18270
  }
16912
18271
  throw new Error(`Updated ${role} server did not pass health checks in time. Tried ${healthUrl}.`);
16913
18272
  }
16914
- const envPath = join3(installPath, ".env");
16915
- const envContent = existsSync6(envPath) ? readFileSync5(envPath, "utf-8") : "";
18273
+ const envPath = join4(installPath, ".env");
18274
+ const envContent = existsSync7(envPath) ? readFileSync6(envPath, "utf-8") : "";
16916
18275
  const urls = deriveSelfHostCliUrls(envContent);
16917
18276
  const apiHealthUrl = `${trailingSlashTrimmed(urls.apiUrl)}/health`;
16918
18277
  const appUrl = trailingSlashTrimmed(urls.appUrl);
@@ -16935,9 +18294,9 @@ function defaultCloneBranchForVersion(version) {
16935
18294
  return /-(alpha|beta|rc)(\.|\d|$)/.test(version) ? DEV_BRANCH : null;
16936
18295
  }
16937
18296
  function hasLlmCredentials(envPath) {
16938
- if (!existsSync6(envPath)) return false;
16939
- if (hasLocalAiModels(dirname(envPath))) return true;
16940
- const content = readFileSync5(envPath, "utf-8");
18297
+ if (!existsSync7(envPath)) return false;
18298
+ if (hasLocalAiModels(dirname2(envPath))) return true;
18299
+ const content = readFileSync6(envPath, "utf-8");
16941
18300
  for (const line of content.split("\n")) {
16942
18301
  const trimmed = line.trim();
16943
18302
  if (trimmed.startsWith("#") || !trimmed) continue;
@@ -16952,8 +18311,8 @@ function hasLlmCredentials(envPath) {
16952
18311
  return false;
16953
18312
  }
16954
18313
  function warnIfMissingLlmCredentials(installPath) {
16955
- const envPath = join3(installPath, ".env");
16956
- if (!existsSync6(envPath)) {
18314
+ const envPath = join4(installPath, ".env");
18315
+ if (!existsSync7(envPath)) {
16957
18316
  console.error(
16958
18317
  "No .env file found. Run 'openmates server install' first, or create .env from .env.example."
16959
18318
  );
@@ -16978,22 +18337,22 @@ function printJson(data) {
16978
18337
  console.log(JSON.stringify(data, null, 2));
16979
18338
  }
16980
18339
  function localModelsOverlayPath(installPath, installMode = getInstallMode(installPath)) {
16981
- if (installMode === "source") return join3(installPath, "backend", "providers", LOCAL_AI_MODELS_FILE);
16982
- return join3(installPath, "config", "providers", LOCAL_AI_MODELS_FILE);
18340
+ if (installMode === "source") return join4(installPath, "backend", "providers", LOCAL_AI_MODELS_FILE);
18341
+ return join4(installPath, "config", "providers", LOCAL_AI_MODELS_FILE);
16983
18342
  }
16984
18343
  function imageBackendConfigPath(installPath) {
16985
- return join3(installPath, IMAGE_RUNTIME_CONFIG_FILE);
18344
+ return join4(installPath, IMAGE_RUNTIME_CONFIG_FILE);
16986
18345
  }
16987
18346
  function ensureImageRuntimeConfig(installPath) {
16988
18347
  const configPath = imageBackendConfigPath(installPath);
16989
- if (existsSync6(configPath)) return;
16990
- mkdirSync3(dirname(configPath), { recursive: true });
16991
- writeFileSync3(configPath, renderFeatureOverrides({ enabled: [], disabled: [] }));
18348
+ if (existsSync7(configPath)) return;
18349
+ mkdirSync4(dirname2(configPath), { recursive: true });
18350
+ writeFileSync4(configPath, renderFeatureOverrides({ enabled: [], disabled: [] }));
16992
18351
  }
16993
18352
  function readLocalModelOverlay(path) {
16994
- if (!existsSync6(path)) return { providers: [] };
18353
+ if (!existsSync7(path)) return { providers: [] };
16995
18354
  try {
16996
- const parsed = JSON.parse(readFileSync5(path, "utf-8"));
18355
+ const parsed = JSON.parse(readFileSync6(path, "utf-8"));
16997
18356
  return { providers: Array.isArray(parsed.providers) ? parsed.providers : [] };
16998
18357
  } catch (error) {
16999
18358
  throw new Error(
@@ -17002,15 +18361,15 @@ function readLocalModelOverlay(path) {
17002
18361
  }
17003
18362
  }
17004
18363
  function writeLocalModelOverlay(path, overlay) {
17005
- mkdirSync3(dirname(path), { recursive: true });
17006
- writeFileSync3(path, `${JSON.stringify(overlay, null, 2)}
18364
+ mkdirSync4(dirname2(path), { recursive: true });
18365
+ writeFileSync4(path, `${JSON.stringify(overlay, null, 2)}
17007
18366
  `);
17008
18367
  }
17009
18368
  function hasLocalAiModels(installPath) {
17010
- const imagePath = join3(installPath, "config", "providers", LOCAL_AI_MODELS_FILE);
17011
- const sourcePath = join3(installPath, "backend", "providers", LOCAL_AI_MODELS_FILE);
18369
+ const imagePath = join4(installPath, "config", "providers", LOCAL_AI_MODELS_FILE);
18370
+ const sourcePath = join4(installPath, "backend", "providers", LOCAL_AI_MODELS_FILE);
17012
18371
  return [imagePath, sourcePath].some((path) => {
17013
- if (!existsSync6(path)) return false;
18372
+ if (!existsSync7(path)) return false;
17014
18373
  try {
17015
18374
  return readLocalModelOverlay(path).providers.some((provider) => provider.models.length > 0);
17016
18375
  } catch {
@@ -17051,30 +18410,30 @@ function nowStamp() {
17051
18410
  return (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
17052
18411
  }
17053
18412
  function backupRoot(installPath) {
17054
- return join3(installPath, "backups");
18413
+ return join4(installPath, "backups");
17055
18414
  }
17056
18415
  function roleBackupDir(installPath, role) {
17057
- return join3(backupRoot(installPath), role);
18416
+ return join4(backupRoot(installPath), role);
17058
18417
  }
17059
18418
  function updateStatusFile(installPath, role) {
17060
- return join3(installPath, ".openmates", `${role}-update-status.json`);
18419
+ return join4(installPath, ".openmates", `${role}-update-status.json`);
17061
18420
  }
17062
18421
  function writeUpdateStatus(installPath, role, status) {
17063
18422
  const filePath = updateStatusFile(installPath, role);
17064
- mkdirSync3(dirname(filePath), { recursive: true, mode: 448 });
17065
- writeFileSync3(filePath, `${JSON.stringify({ role, updated_at: (/* @__PURE__ */ new Date()).toISOString(), ...status }, null, 2)}
18423
+ mkdirSync4(dirname2(filePath), { recursive: true, mode: 448 });
18424
+ writeFileSync4(filePath, `${JSON.stringify({ role, updated_at: (/* @__PURE__ */ new Date()).toISOString(), ...status }, null, 2)}
17066
18425
  `, { mode: 384 });
17067
18426
  }
17068
18427
  function copyIfExists(source, destination) {
17069
- if (!existsSync6(source)) return;
17070
- mkdirSync3(dirname(destination), { recursive: true });
18428
+ if (!existsSync7(source)) return;
18429
+ mkdirSync4(dirname2(destination), { recursive: true });
17071
18430
  cpSync(source, destination, { recursive: true, force: true });
17072
18431
  }
17073
18432
  function readEnvMap(installPath) {
17074
- const envPath = join3(installPath, ".env");
17075
- if (!existsSync6(envPath)) return {};
18433
+ const envPath = join4(installPath, ".env");
18434
+ if (!existsSync7(envPath)) return {};
17076
18435
  const values = {};
17077
- for (const line of readFileSync5(envPath, "utf-8").split("\n")) {
18436
+ for (const line of readFileSync6(envPath, "utf-8").split("\n")) {
17078
18437
  const trimmed = line.trim();
17079
18438
  if (!trimmed || trimmed.startsWith("#")) continue;
17080
18439
  const eqIdx = trimmed.indexOf("=");
@@ -17222,7 +18581,7 @@ function formatSecretPreflight(preflight) {
17222
18581
  return parts.join("; ");
17223
18582
  }
17224
18583
  function hashFile(path) {
17225
- const hash = createHash7("sha256");
18584
+ const hash = createHash8("sha256");
17226
18585
  const fd = openSync(path, "r");
17227
18586
  const buffer = Buffer.allocUnsafe(CHECKSUM_BUFFER_BYTES);
17228
18587
  try {
@@ -17240,7 +18599,7 @@ function writeChecksums(rootDir) {
17240
18599
  const lines = [];
17241
18600
  const walk = (dir) => {
17242
18601
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
17243
- const path = join3(dir, entry.name);
18602
+ const path = join4(dir, entry.name);
17244
18603
  if (entry.isDirectory()) {
17245
18604
  walk(path);
17246
18605
  continue;
@@ -17251,13 +18610,13 @@ function writeChecksums(rootDir) {
17251
18610
  }
17252
18611
  };
17253
18612
  walk(rootDir);
17254
- writeFileSync3(join3(rootDir, "checksums.sha256"), `${lines.sort().join("\n")}
18613
+ writeFileSync4(join4(rootDir, "checksums.sha256"), `${lines.sort().join("\n")}
17255
18614
  `);
17256
18615
  }
17257
18616
  function verifyChecksums(rootDir) {
17258
- const checksumsPath = join3(rootDir, "checksums.sha256");
17259
- if (!existsSync6(checksumsPath)) throw new Error("Backup archive is missing checksums.sha256.");
17260
- for (const line of readFileSync5(checksumsPath, "utf-8").split("\n")) {
18617
+ const checksumsPath = join4(rootDir, "checksums.sha256");
18618
+ if (!existsSync7(checksumsPath)) throw new Error("Backup archive is missing checksums.sha256.");
18619
+ for (const line of readFileSync6(checksumsPath, "utf-8").split("\n")) {
17261
18620
  const trimmed = line.trim();
17262
18621
  if (!trimmed) continue;
17263
18622
  const match = trimmed.match(/^([a-f0-9]{64}) {2}(.+)$/);
@@ -17266,8 +18625,8 @@ function verifyChecksums(rootDir) {
17266
18625
  if (relative3.startsWith("/") || relative3.split(/[\\/]/).includes("..")) {
17267
18626
  throw new Error(`Unsafe checksum path in backup archive: ${relative3}`);
17268
18627
  }
17269
- const filePath = join3(rootDir, relative3);
17270
- if (!existsSync6(filePath)) throw new Error(`Backup archive is missing checksummed file: ${relative3}`);
18628
+ const filePath = join4(rootDir, relative3);
18629
+ if (!existsSync7(filePath)) throw new Error(`Backup archive is missing checksummed file: ${relative3}`);
17271
18630
  const actual = hashFile(filePath);
17272
18631
  if (actual !== match[1]) throw new Error(`Backup checksum mismatch for ${relative3}.`);
17273
18632
  }
@@ -17275,27 +18634,27 @@ function verifyChecksums(rootDir) {
17275
18634
  function createServerBackup(installPath, role, options = {}) {
17276
18635
  const plan = planBackup({ role, includeObservability: options.includeObservability });
17277
18636
  const backupDir = roleBackupDir(installPath, role);
17278
- mkdirSync3(backupDir, { recursive: true, mode: 448 });
17279
- const archivePath = options.output ? resolve3(options.output) : join3(backupDir, options.preUpdate ? `latest-pre-update-${role}.tar.gz` : `openmates-${role}-${nowStamp()}.tar.gz`);
17280
- const tempDir = mkdtempSync(join3(backupDir, ".tmp-"));
18637
+ mkdirSync4(backupDir, { recursive: true, mode: 448 });
18638
+ const archivePath = options.output ? resolve3(options.output) : join4(backupDir, options.preUpdate ? `latest-pre-update-${role}.tar.gz` : `openmates-${role}-${nowStamp()}.tar.gz`);
18639
+ const tempDir = mkdtempSync(join4(backupDir, ".tmp-"));
17281
18640
  const env = readEnvMap(installPath);
17282
18641
  const manifest = {
17283
18642
  role,
17284
18643
  created_at: (/* @__PURE__ */ new Date()).toISOString(),
17285
18644
  cli_version: getPackageVersion(),
17286
- image_tag: getEnvVar(existsSync6(join3(installPath, ".env")) ? readFileSync5(join3(installPath, ".env"), "utf-8") : "", "OPENMATES_IMAGE_TAG"),
18645
+ image_tag: getEnvVar(existsSync7(join4(installPath, ".env")) ? readFileSync6(join4(installPath, ".env"), "utf-8") : "", "OPENMATES_IMAGE_TAG"),
17287
18646
  include_observability: options.includeObservability === true,
17288
18647
  contents: plan.contents
17289
18648
  };
17290
18649
  try {
17291
- writeFileSync3(join3(tempDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
18650
+ writeFileSync4(join4(tempDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
17292
18651
  `);
17293
- copyIfExists(join3(installPath, ".env"), join3(tempDir, "runtime", ".env"));
17294
- copyIfExists(join3(installPath, "config"), join3(tempDir, "runtime", "config"));
18652
+ copyIfExists(join4(installPath, ".env"), join4(tempDir, "runtime", ".env"));
18653
+ copyIfExists(join4(installPath, "config"), join4(tempDir, "runtime", "config"));
17295
18654
  if (role === "core") {
17296
18655
  const databaseUser = env.DATABASE_USERNAME || "directus";
17297
18656
  const databaseName = env.DATABASE_NAME || "directus";
17298
- const dumpFile = openSync(join3(tempDir, "postgres.sql"), "w");
18657
+ const dumpFile = openSync(join4(tempDir, "postgres.sql"), "w");
17299
18658
  try {
17300
18659
  const result = spawnSync(
17301
18660
  "docker",
@@ -17311,15 +18670,15 @@ function createServerBackup(installPath, role, options = {}) {
17311
18670
  }
17312
18671
  }
17313
18672
  for (const item of [
17314
- [join3(installPath, "backend", "core", "uploads"), join3(tempDir, "directus-uploads")],
17315
- [join3(installPath, "backend", "core", "extensions"), join3(tempDir, "directus-extensions")],
17316
- [join3(installPath, "backend", role, "vault"), join3(tempDir, `${role}-vault-config`)]
18673
+ [join4(installPath, "backend", "core", "uploads"), join4(tempDir, "directus-uploads")],
18674
+ [join4(installPath, "backend", "core", "extensions"), join4(tempDir, "directus-extensions")],
18675
+ [join4(installPath, "backend", role, "vault"), join4(tempDir, `${role}-vault-config`)]
17317
18676
  ]) {
17318
18677
  copyIfExists(item[0], item[1]);
17319
18678
  }
17320
18679
  writeChecksums(tempDir);
17321
18680
  execSync(`tar -czf ${shellQuote(archivePath)} -C ${shellQuote(tempDir)} .`, { stdio: "pipe" });
17322
- chmodSync2(archivePath, plan.fileMode);
18681
+ chmodSync3(archivePath, plan.fileMode);
17323
18682
  return archivePath;
17324
18683
  } finally {
17325
18684
  rmSync3(tempDir, { recursive: true, force: true });
@@ -17327,25 +18686,25 @@ function createServerBackup(installPath, role, options = {}) {
17327
18686
  }
17328
18687
  function restoreServerBackup(installPath, role, file) {
17329
18688
  const archivePath = resolve3(file);
17330
- if (!existsSync6(archivePath)) throw new Error(`Backup file not found: ${archivePath}`);
17331
- mkdirSync3(roleBackupDir(installPath, role), { recursive: true, mode: 448 });
17332
- const tempDir = mkdtempSync(join3(roleBackupDir(installPath, role), ".restore-"));
18689
+ if (!existsSync7(archivePath)) throw new Error(`Backup file not found: ${archivePath}`);
18690
+ mkdirSync4(roleBackupDir(installPath, role), { recursive: true, mode: 448 });
18691
+ const tempDir = mkdtempSync(join4(roleBackupDir(installPath, role), ".restore-"));
17333
18692
  const env = readEnvMap(installPath);
17334
18693
  try {
17335
18694
  execSync(`tar -xzf ${shellQuote(archivePath)} -C ${shellQuote(tempDir)}`, { stdio: "pipe" });
17336
18695
  verifyChecksums(tempDir);
17337
- const manifestPath = join3(tempDir, "manifest.json");
17338
- if (!existsSync6(manifestPath)) throw new Error("Backup archive is missing manifest.json.");
17339
- const manifest = JSON.parse(readFileSync5(manifestPath, "utf-8"));
18696
+ const manifestPath = join4(tempDir, "manifest.json");
18697
+ if (!existsSync7(manifestPath)) throw new Error("Backup archive is missing manifest.json.");
18698
+ const manifest = JSON.parse(readFileSync6(manifestPath, "utf-8"));
17340
18699
  if (manifest.role !== role) throw new Error(`Backup role '${manifest.role}' does not match requested role '${role}'.`);
17341
- copyIfExists(join3(tempDir, "runtime", ".env"), join3(installPath, ".env"));
17342
- copyIfExists(join3(tempDir, "runtime", "config"), join3(installPath, "config"));
17343
- const postgresDump = join3(tempDir, "postgres.sql");
17344
- if (role === "core" && existsSync6(postgresDump)) {
18700
+ copyIfExists(join4(tempDir, "runtime", ".env"), join4(installPath, ".env"));
18701
+ copyIfExists(join4(tempDir, "runtime", "config"), join4(installPath, "config"));
18702
+ const postgresDump = join4(tempDir, "postgres.sql");
18703
+ if (role === "core" && existsSync7(postgresDump)) {
17345
18704
  const databaseUser = env.DATABASE_USERNAME || "directus";
17346
18705
  const databaseName = env.DATABASE_NAME || "directus";
17347
18706
  execSync(`docker exec -i cms-database psql -v ON_ERROR_STOP=1 -U ${shellQuote(databaseUser)} ${shellQuote(databaseName)}`, {
17348
- input: readFileSync5(postgresDump),
18707
+ input: readFileSync6(postgresDump),
17349
18708
  stdio: ["pipe", "pipe", "pipe"]
17350
18709
  });
17351
18710
  }
@@ -17600,26 +18959,26 @@ async function serverInstall(flags) {
17600
18959
  const role = getServerRole(flags, null);
17601
18960
  const profile = getCoreProfile(flags, null);
17602
18961
  const runtimePlan = planServerRuntime({ role, profile, withAlerts: flags["with-alerts"] === true });
17603
- if (existsSync6(join3(installPath, SOURCE_COMPOSE_FILE)) || Object.values(ROLE_IMAGE_COMPOSE_FILES).some((composeFile) => existsSync6(join3(installPath, composeFile)))) {
18962
+ if (existsSync7(join4(installPath, SOURCE_COMPOSE_FILE)) || Object.values(ROLE_IMAGE_COMPOSE_FILES).some((composeFile) => existsSync7(join4(installPath, composeFile)))) {
17604
18963
  console.error(`OpenMates already exists at ${installPath}.`);
17605
18964
  console.error("Use 'openmates server update' to update, or choose a different --path.");
17606
18965
  process.exit(1);
17607
18966
  }
17608
18967
  if (!fromSource) {
17609
18968
  requireDocker();
17610
- mkdirSync3(installPath, { recursive: true });
18969
+ mkdirSync4(installPath, { recursive: true });
17611
18970
  if (typeof flags["env-path"] === "string") {
17612
18971
  const envSource = resolve3(flags["env-path"]);
17613
- if (!existsSync6(envSource)) {
18972
+ if (!existsSync7(envSource)) {
17614
18973
  throw new Error(`Env file not found: ${envSource}`);
17615
18974
  }
17616
- copyFileSync(envSource, join3(installPath, ".env"));
18975
+ copyFileSync(envSource, join4(installPath, ".env"));
17617
18976
  console.error(`Copied ${envSource} to ${installPath}/.env`);
17618
18977
  }
17619
18978
  const imageTag = typeof flags["image-tag"] === "string" ? flags["image-tag"] : getDefaultImageTag();
17620
18979
  console.error(`Preparing OpenMates image-mode install at ${installPath}...`);
17621
18980
  await writeImageModeRuntimeFiles(installPath, imageTag, role);
17622
- const cliUrls2 = deriveSelfHostCliUrls(readFileSync5(join3(installPath, ".env"), "utf-8"));
18981
+ const cliUrls2 = deriveSelfHostCliUrls(readFileSync6(join4(installPath, ".env"), "utf-8"));
17623
18982
  try {
17624
18983
  exec("docker network create openmates", installPath);
17625
18984
  } catch {
@@ -17639,7 +18998,7 @@ async function serverInstall(flags) {
17639
18998
  if (flags.json === true) {
17640
18999
  printJson({ command: "install", status: "success", path: installPath, mode: "image", imageTag });
17641
19000
  } else {
17642
- const firstInvite = getEnvVar(readFileSync5(join3(installPath, ".env"), "utf-8"), "SELF_HOST_FIRST_INVITE_CODE");
19001
+ const firstInvite = getEnvVar(readFileSync6(join4(installPath, ".env"), "utf-8"), "SELF_HOST_FIRST_INVITE_CODE");
17643
19002
  console.log(`
17644
19003
  OpenMates installed at ${installPath}`);
17645
19004
  console.log(`Mode: image (${DEFAULT_IMAGE_REGISTRY}, tag ${imageTag})`);
@@ -17676,10 +19035,10 @@ CLI default API: ${cliUrls2.apiUrl}`);
17676
19035
  }
17677
19036
  if (typeof flags["env-path"] === "string") {
17678
19037
  const envSource = resolve3(flags["env-path"]);
17679
- if (!existsSync6(envSource)) {
19038
+ if (!existsSync7(envSource)) {
17680
19039
  throw new Error(`Env file not found: ${envSource}`);
17681
19040
  }
17682
- copyFileSync(envSource, join3(installPath, ".env"));
19041
+ copyFileSync(envSource, join4(installPath, ".env"));
17683
19042
  console.error(`Copied ${envSource} to ${installPath}/.env`);
17684
19043
  }
17685
19044
  console.error("\nRunning setup script...");
@@ -17692,8 +19051,8 @@ CLI default API: ${cliUrls2.apiUrl}`);
17692
19051
  console.error("Setup script failed. Check the output above for details.");
17693
19052
  process.exit(setupCode);
17694
19053
  }
17695
- const envPath = join3(installPath, ".env");
17696
- const cliUrls = deriveSelfHostCliUrls(existsSync6(envPath) ? readFileSync5(envPath, "utf-8") : "");
19054
+ const envPath = join4(installPath, ".env");
19055
+ const cliUrls = deriveSelfHostCliUrls(existsSync7(envPath) ? readFileSync6(envPath, "utf-8") : "");
17697
19056
  saveServerConfig({
17698
19057
  installPath,
17699
19058
  installedAt: Date.now(),
@@ -17725,15 +19084,15 @@ async function installContinuousUpdateService(flags) {
17725
19084
  const channel = typeof flags.channel === "string" ? flags.channel : config?.imageChannel ?? "main";
17726
19085
  const window = typeof flags.window === "string" ? flags.window : "02:00-04:00 UTC";
17727
19086
  const plan = planContinuousUpdateService({ role, channel, window });
17728
- const servicePath = join3("/etc", "systemd", "system", plan.serviceName);
17729
- const timerPath = join3("/etc", "systemd", "system", plan.timerName);
19087
+ const servicePath = join4("/etc", "systemd", "system", plan.serviceName);
19088
+ const timerPath = join4("/etc", "systemd", "system", plan.timerName);
17730
19089
  if (flags["dry-run"] === true || flags.json === true) {
17731
19090
  printJson({ command: "update install-service", status: "planned", role, servicePath, timerPath, unit: plan.unit, timer: plan.timer });
17732
19091
  return;
17733
19092
  }
17734
19093
  try {
17735
- writeFileSync3(servicePath, plan.unit, { mode: 420 });
17736
- writeFileSync3(timerPath, plan.timer, { mode: 420 });
19094
+ writeFileSync4(servicePath, plan.unit, { mode: 420 });
19095
+ writeFileSync4(timerPath, plan.timer, { mode: 420 });
17737
19096
  execSync("systemctl daemon-reload", { stdio: "pipe" });
17738
19097
  execSync(`systemctl enable --now ${shellQuote(plan.timerName)}`, { stdio: "pipe" });
17739
19098
  } catch (error) {
@@ -17750,14 +19109,14 @@ async function serverUpdate(rest, flags) {
17750
19109
  const role2 = getServerRole(flags, config2);
17751
19110
  const filePath = updateStatusFile(installPath2, role2);
17752
19111
  if (flags.json === true) {
17753
- printJson(existsSync6(filePath) ? JSON.parse(readFileSync5(filePath, "utf-8")) : { role: role2, status: "unknown" });
19112
+ printJson(existsSync7(filePath) ? JSON.parse(readFileSync6(filePath, "utf-8")) : { role: role2, status: "unknown" });
17754
19113
  return;
17755
19114
  }
17756
- if (!existsSync6(filePath)) {
19115
+ if (!existsSync7(filePath)) {
17757
19116
  console.log(`No update status recorded for ${role2}.`);
17758
19117
  return;
17759
19118
  }
17760
- console.log(readFileSync5(filePath, "utf-8").trim());
19119
+ console.log(readFileSync6(filePath, "utf-8").trim());
17761
19120
  return;
17762
19121
  }
17763
19122
  if (rest[0] === "install-service") {
@@ -18066,14 +19425,14 @@ async function serverFeatures(rest, flags) {
18066
19425
  const installPath = resolveServerPath(flags);
18067
19426
  const installMode = getInstallMode(installPath);
18068
19427
  if (installMode === "image") ensureImageRuntimeConfig(installPath);
18069
- const configPath = installMode === "image" ? imageBackendConfigPath(installPath) : join3(installPath, BACKEND_CONFIG_FILE);
18070
- if (!existsSync6(configPath)) {
19428
+ const configPath = installMode === "image" ? imageBackendConfigPath(installPath) : join4(installPath, BACKEND_CONFIG_FILE);
19429
+ if (!existsSync7(configPath)) {
18071
19430
  throw new Error(`Backend config not found at ${configPath}. Run 'openmates server install' first or pass --path <dir>.`);
18072
19431
  }
18073
- const content = readFileSync5(configPath, "utf-8");
19432
+ const content = readFileSync6(configPath, "utf-8");
18074
19433
  const overrides = parseFeatureOverrides(content);
18075
19434
  const writeOverrides = (nextOverrides) => {
18076
- writeFileSync3(configPath, updateFeatureOverridesContent(content, nextOverrides));
19435
+ writeFileSync4(configPath, updateFeatureOverridesContent(content, nextOverrides));
18077
19436
  console.log(`Updated ${configPath}`);
18078
19437
  console.log("Restart the server for feature changes to take effect: openmates server restart");
18079
19438
  };
@@ -18306,7 +19665,7 @@ async function serverBackup(rest, flags) {
18306
19665
  const role = getServerRole(flags, config);
18307
19666
  if (action === "list") {
18308
19667
  const dir = roleBackupDir(installPath, role);
18309
- const files = existsSync6(dir) ? readdirSync(dir).filter((item) => item.endsWith(".tar.gz")).sort() : [];
19668
+ const files = existsSync7(dir) ? readdirSync(dir).filter((item) => item.endsWith(".tar.gz")).sort() : [];
18310
19669
  if (flags.json === true) {
18311
19670
  printJson({ role, backupDir: dir, files });
18312
19671
  return;
@@ -18316,7 +19675,7 @@ async function serverBackup(rest, flags) {
18316
19675
  console.log(" none");
18317
19676
  return;
18318
19677
  }
18319
- for (const file of files) console.log(` ${join3(dir, file)}`);
19678
+ for (const file of files) console.log(` ${join4(dir, file)}`);
18320
19679
  return;
18321
19680
  }
18322
19681
  requireDocker();
@@ -18476,7 +19835,7 @@ async function serverCaddy(rest, flags) {
18476
19835
  const role = getServerRole(flags, config);
18477
19836
  const appliedPath = typeof flags.config === "string" ? flags.config : "/etc/caddy/Caddyfile";
18478
19837
  const templatePath = packagedCaddyTemplatePath(role);
18479
- if (!existsSync6(templatePath)) throw new Error(`Packaged Caddy template not found: ${templatePath}`);
19838
+ if (!existsSync7(templatePath)) throw new Error(`Packaged Caddy template not found: ${templatePath}`);
18480
19839
  const plan = planCaddyCommand({ role, action, appliedPath });
18481
19840
  const payload = {
18482
19841
  ...plan,
@@ -18495,7 +19854,7 @@ async function serverCaddy(rest, flags) {
18495
19854
  return;
18496
19855
  }
18497
19856
  if (action === "diff") {
18498
- if (!existsSync6(appliedPath)) throw new Error(`Applied Caddyfile not found: ${appliedPath}`);
19857
+ if (!existsSync7(appliedPath)) throw new Error(`Applied Caddyfile not found: ${appliedPath}`);
18499
19858
  try {
18500
19859
  execSync(`diff -u ${shellQuote(appliedPath)} ${shellQuote(templatePath)}`, { stdio: "inherit" });
18501
19860
  } catch (error) {
@@ -18516,9 +19875,9 @@ WARNING: This will replace ${appliedPath} with the packaged ${role} Caddyfile.`)
18516
19875
  }
18517
19876
  }
18518
19877
  const backupPath = `${appliedPath}.openmates-backup-${nowStamp()}`;
18519
- const hadExistingCaddyfile = existsSync6(appliedPath);
19878
+ const hadExistingCaddyfile = existsSync7(appliedPath);
18520
19879
  try {
18521
- mkdirSync3(dirname(appliedPath), { recursive: true });
19880
+ mkdirSync4(dirname2(appliedPath), { recursive: true });
18522
19881
  if (hadExistingCaddyfile) copyFileSync(appliedPath, backupPath);
18523
19882
  copyFileSync(templatePath, appliedPath);
18524
19883
  execSync("systemctl reload caddy", { stdio: "inherit" });
@@ -53151,10 +54510,10 @@ function buildAssistantFeedbackDecision(rating) {
53151
54510
  }
53152
54511
 
53153
54512
  // src/benchmark.ts
53154
- import { randomUUID as randomUUID6 } from "crypto";
53155
- import { existsSync as existsSync7, mkdtempSync as mkdtempSync2, readFileSync as readFileSync6, readdirSync as readdirSync2, writeFileSync as writeFileSync4 } from "fs";
54513
+ import { randomUUID as randomUUID7 } from "crypto";
54514
+ import { existsSync as existsSync8, mkdtempSync as mkdtempSync2, readFileSync as readFileSync7, readdirSync as readdirSync2, writeFileSync as writeFileSync5 } from "fs";
53156
54515
  import { tmpdir } from "os";
53157
- import { dirname as dirname2, join as join4, resolve as resolve5 } from "path";
54516
+ import { dirname as dirname3, join as join5, resolve as resolve5 } from "path";
53158
54517
  import { fileURLToPath } from "url";
53159
54518
  var DEFAULT_JUDGE_MODEL = "google/gemini-3-flash-preview";
53160
54519
  var DEFAULT_EXTENSIVE_SIZE = 10;
@@ -53451,7 +54810,7 @@ async function handleBenchmark(client, subcommand, rest, flags) {
53451
54810
  const caseIds = parseCaseIds(flags.case);
53452
54811
  const dryRun = flags["dry-run"] === true;
53453
54812
  const output = typeof flags.output === "string" ? flags.output : void 0;
53454
- const runId = typeof flags["run-id"] === "string" ? flags["run-id"] : randomUUID6();
54813
+ const runId = typeof flags["run-id"] === "string" ? flags["run-id"] : randomUUID7();
53455
54814
  const imagePath = typeof flags.image === "string" ? resolve5(flags.image) : defaultImageFixturePath();
53456
54815
  if (!dryRun && flags["confirm-spend-credits"] !== true) {
53457
54816
  throw new Error(
@@ -53747,7 +55106,7 @@ async function buildPromptWithAttachments(client, benchmarkCase, model, imagePat
53747
55106
  ${attachment.messageSuffix}`, embeds: attachment.embeds };
53748
55107
  }
53749
55108
  async function prepareImageAttachment(client, imagePath) {
53750
- if (!existsSync7(imagePath)) throw new Error(`Benchmark image not found: ${imagePath}`);
55109
+ if (!existsSync8(imagePath)) throw new Error(`Benchmark image not found: ${imagePath}`);
53751
55110
  const processed = processFiles([imagePath], null);
53752
55111
  if (processed.blocked.length > 0 || processed.errors.length > 0 || processed.embeds.length === 0) {
53753
55112
  const reason = [...processed.blocked, ...processed.errors].map((entry) => entry.error).join("; ") || "no image embed produced";
@@ -53861,7 +55220,7 @@ function buildLongContextHistory() {
53861
55220
  }
53862
55221
  function appendHistory(history, role, content) {
53863
55222
  history.push({
53864
- message_id: randomUUID6(),
55223
+ message_id: randomUUID7(),
53865
55224
  role,
53866
55225
  sender_name: role === "user" ? "User" : "Assistant",
53867
55226
  content,
@@ -53953,8 +55312,8 @@ function loadProviderPricing() {
53953
55312
  if (!providersDir) return pricing;
53954
55313
  for (const fileName of readdirSync2(providersDir)) {
53955
55314
  if (!fileName.endsWith(".yml")) continue;
53956
- const filePath = join4(providersDir, fileName);
53957
- const text = readFileSync6(filePath, "utf-8");
55315
+ const filePath = join5(providersDir, fileName);
55316
+ const text = readFileSync7(filePath, "utf-8");
53958
55317
  const provider = parseProviderId(text) ?? fileName.replace(/\.yml$/, "");
53959
55318
  for (const modelPricing of parseModelPricing(text, provider)) {
53960
55319
  pricing.set(`${modelPricing.provider}/${modelPricing.modelId}`, modelPricing);
@@ -54006,13 +55365,13 @@ function normalizeModelKey(model) {
54006
55365
  }
54007
55366
  function findProvidersDir() {
54008
55367
  const currentFile = fileURLToPath(import.meta.url);
54009
- let current = dirname2(currentFile);
55368
+ let current = dirname3(currentFile);
54010
55369
  for (let index = 0; index < 8; index += 1) {
54011
- const candidate = join4(current, "backend", "providers");
54012
- if (existsSync7(candidate)) return candidate;
54013
- const parentCandidate = join4(current, "..", "..", "backend", "providers");
54014
- if (existsSync7(parentCandidate)) return resolve5(parentCandidate);
54015
- const next = dirname2(current);
55370
+ const candidate = join5(current, "backend", "providers");
55371
+ if (existsSync8(candidate)) return candidate;
55372
+ const parentCandidate = join5(current, "..", "..", "backend", "providers");
55373
+ if (existsSync8(parentCandidate)) return resolve5(parentCandidate);
55374
+ const next = dirname3(current);
54016
55375
  if (next === current) break;
54017
55376
  current = next;
54018
55377
  }
@@ -54133,18 +55492,18 @@ function round2(value) {
54133
55492
  return Math.round(value * 100) / 100;
54134
55493
  }
54135
55494
  function defaultImageFixturePath() {
54136
- const fixtureDir = join4(dirname2(fileURLToPath(import.meta.url)), "..", "fixtures");
54137
- const fixturePath = join4(fixtureDir, "brandenburger-tor.png");
54138
- if (existsSync7(fixturePath)) return fixturePath;
54139
- const tempDir = mkdtempSync2(join4(tmpdir(), "openmates-benchmark-"));
54140
- const tempPath = join4(tempDir, "brandenburger-tor.svg");
54141
- writeFileSync4(tempPath, FIXTURE_IMAGE_SVG, "utf-8");
55495
+ const fixtureDir = join5(dirname3(fileURLToPath(import.meta.url)), "..", "fixtures");
55496
+ const fixturePath = join5(fixtureDir, "brandenburger-tor.png");
55497
+ if (existsSync8(fixturePath)) return fixturePath;
55498
+ const tempDir = mkdtempSync2(join5(tmpdir(), "openmates-benchmark-"));
55499
+ const tempPath = join5(tempDir, "brandenburger-tor.svg");
55500
+ writeFileSync5(tempPath, FIXTURE_IMAGE_SVG, "utf-8");
54142
55501
  return tempPath;
54143
55502
  }
54144
55503
  function writeBenchmarkResult(result, flags, output) {
54145
55504
  const json = `${JSON.stringify(result, null, 2)}
54146
55505
  `;
54147
- if (output) writeFileSync4(output, json, "utf-8");
55506
+ if (output) writeFileSync5(output, json, "utf-8");
54148
55507
  if (flags.json === true || output) {
54149
55508
  process.stdout.write(json);
54150
55509
  return;
@@ -55503,10 +56862,10 @@ function clamp(value, min, max) {
55503
56862
  }
55504
56863
 
55505
56864
  // src/remoteAccess.ts
55506
- import { homedir as homedir6 } from "os";
55507
- import { chmodSync as chmodSync3, existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync7, statSync as statSync2, writeFileSync as writeFileSync5 } from "fs";
56865
+ import { homedir as homedir7 } from "os";
56866
+ import { chmodSync as chmodSync4, existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync8, statSync as statSync2, writeFileSync as writeFileSync6 } from "fs";
55508
56867
  import { spawn as spawn2 } from "child_process";
55509
- import { join as join5, resolve as resolve6, relative as relative2 } from "path";
56868
+ import { join as join6, resolve as resolve6, relative as relative2 } from "path";
55510
56869
 
55511
56870
  // src/projectFileRisk.ts
55512
56871
  var SECRET_OR_ENVIRONMENT_PATTERNS = [
@@ -55612,15 +56971,15 @@ var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
55612
56971
  ".mp4",
55613
56972
  ".mov"
55614
56973
  ]);
55615
- function resolveRemoteCachePath(sourceId, homeDirectory = homedir6()) {
56974
+ function resolveRemoteCachePath(sourceId, homeDirectory = homedir7()) {
55616
56975
  assertSafeSourceId(sourceId);
55617
- return join5(homeDirectory, ".openmates", "remote-cache", sourceId);
56976
+ return join6(homeDirectory, ".openmates", "remote-cache", sourceId);
55618
56977
  }
55619
56978
  function startRemoteAccessSource(input) {
55620
56979
  assertSafeSourceId(input.sourceId);
55621
- const homeDirectory = input.homeDirectory ?? homedir6();
56980
+ const homeDirectory = input.homeDirectory ?? homedir7();
55622
56981
  const rootPath = resolve6(input.rootPath);
55623
- if (!existsSync8(rootPath) || !statSync2(rootPath).isDirectory()) {
56982
+ if (!existsSync9(rootPath) || !statSync2(rootPath).isDirectory()) {
55624
56983
  throw new Error(`Remote source path does not exist or is not a directory: ${rootPath}`);
55625
56984
  }
55626
56985
  const now = Math.floor(Date.now() / 1e3);
@@ -55637,14 +56996,14 @@ function startRemoteAccessSource(input) {
55637
56996
  };
55638
56997
  const sources = listRemoteAccessSources(homeDirectory).filter((entry) => entry.sourceId !== input.sourceId);
55639
56998
  saveRemoteAccessSources([...sources, source], homeDirectory);
55640
- mkdirSync4(source.cachePath, { recursive: true, mode: 448 });
56999
+ mkdirSync5(source.cachePath, { recursive: true, mode: 448 });
55641
57000
  return source;
55642
57001
  }
55643
- function listRemoteAccessSources(homeDirectory = homedir6()) {
57002
+ function listRemoteAccessSources(homeDirectory = homedir7()) {
55644
57003
  const filePath = remoteAccessStorePath(homeDirectory);
55645
- if (!existsSync8(filePath)) return [];
57004
+ if (!existsSync9(filePath)) return [];
55646
57005
  try {
55647
- const parsed = JSON.parse(readFileSync7(filePath, "utf-8"));
57006
+ const parsed = JSON.parse(readFileSync8(filePath, "utf-8"));
55648
57007
  if (!Array.isArray(parsed.sources)) {
55649
57008
  throw new Error("Remote source store is missing the sources array");
55650
57009
  }
@@ -55793,16 +57152,16 @@ function parseRgMatch(line) {
55793
57152
  }
55794
57153
  }
55795
57154
  function remoteAccessStorePath(homeDirectory) {
55796
- return join5(homeDirectory, ".openmates", "remote-sources.json");
57155
+ return join6(homeDirectory, ".openmates", "remote-sources.json");
55797
57156
  }
55798
57157
  function saveRemoteAccessSources(sources, homeDirectory) {
55799
57158
  const filePath = remoteAccessStorePath(homeDirectory);
55800
- const stateDir = join5(homeDirectory, ".openmates");
55801
- mkdirSync4(stateDir, { recursive: true, mode: 448 });
55802
- chmodSync3(stateDir, 448);
55803
- writeFileSync5(filePath, `${JSON.stringify({ sources }, null, 2)}
57159
+ const stateDir = join6(homeDirectory, ".openmates");
57160
+ mkdirSync5(stateDir, { recursive: true, mode: 448 });
57161
+ chmodSync4(stateDir, 448);
57162
+ writeFileSync6(filePath, `${JSON.stringify({ sources }, null, 2)}
55804
57163
  `, { mode: 384 });
55805
- chmodSync3(filePath, 384);
57164
+ chmodSync4(filePath, 384);
55806
57165
  }
55807
57166
  function assertRemoteAccessSourceRecord(value, index) {
55808
57167
  if (typeof value !== "object" || value === null) {
@@ -55821,13 +57180,13 @@ function assertRemoteAccessSourceRecord(value, index) {
55821
57180
 
55822
57181
  // src/selfUpdate.ts
55823
57182
  import { spawnSync as spawnSync2 } from "child_process";
55824
- import { readFileSync as readFileSync8 } from "fs";
57183
+ import { readFileSync as readFileSync9 } from "fs";
55825
57184
  var PACKAGE_NAME = "openmates";
55826
57185
  var DEFAULT_TARGET = "latest";
55827
57186
  var SAFE_TARGET_RE = /^[a-zA-Z0-9._@+~:-]+$/;
55828
57187
  function getCliPackageVersion() {
55829
57188
  try {
55830
- const packageJson = JSON.parse(readFileSync8(new URL("../package.json", import.meta.url), "utf-8"));
57189
+ const packageJson = JSON.parse(readFileSync9(new URL("../package.json", import.meta.url), "utf-8"));
55831
57190
  return packageJson.version ?? "unknown";
55832
57191
  } catch {
55833
57192
  return "unknown";
@@ -56449,7 +57808,7 @@ async function handleRemoteAccess(client, subcommand, rest, flags) {
56449
57808
  if (!rootPath) {
56450
57809
  throw new Error("Missing source path. Usage: openmates remote-access start --path <folder>");
56451
57810
  }
56452
- const sourceId = typeof flags["source-id"] === "string" ? flags["source-id"] : randomUUID7();
57811
+ const sourceId = typeof flags["source-id"] === "string" ? flags["source-id"] : randomUUID8();
56453
57812
  const projectId = typeof flags.project === "string" ? flags.project : void 0;
56454
57813
  validateRemoteSourceRegistrationFlags(projectId, flags);
56455
57814
  const sourceType = parseRemoteAccessSourceType(flags.type);
@@ -56606,6 +57965,7 @@ async function handleChats(client, subcommand, rest, flags, redactor) {
56606
57965
  printChatsHelp();
56607
57966
  return;
56608
57967
  }
57968
+ const apiKey = resolveApiKey(flags) ?? void 0;
56609
57969
  if (rest[0] === "tasks") {
56610
57970
  await handleTasks(client, rest[1], rest.slice(2), { ...flags, chat: subcommand });
56611
57971
  return;
@@ -56613,7 +57973,7 @@ async function handleChats(client, subcommand, rest, flags, redactor) {
56613
57973
  if (subcommand === "list") {
56614
57974
  const limit = typeof flags.limit === "string" ? parseInt(flags.limit, 10) : 10;
56615
57975
  const page = typeof flags.page === "string" ? parseInt(flags.page, 10) : 1;
56616
- const result = client.hasSession() ? await client.listChats(limit, page) : listExampleChats(limit, page);
57976
+ const result = apiKey ? await listApiKeyChats(client, apiKey, limit, page) : client.hasSession() ? await client.listChats(limit, page) : listExampleChats(limit, page);
56617
57977
  if (flags.json === true) {
56618
57978
  printJson2(result);
56619
57979
  } else {
@@ -56627,7 +57987,7 @@ async function handleChats(client, subcommand, rest, flags, redactor) {
56627
57987
  throw new Error(
56628
57988
  "Missing search query. Usage: openmates chats search <query>"
56629
57989
  );
56630
- const result = client.hasSession() ? await client.searchChats(query) : searchExampleChats(query);
57990
+ const result = apiKey ? await searchApiKeyChats(client, apiKey, query) : client.hasSession() ? await client.searchChats(query) : searchExampleChats(query);
56631
57991
  if (flags.json === true) {
56632
57992
  printJson2(result);
56633
57993
  } else {
@@ -56647,7 +58007,7 @@ async function handleChats(client, subcommand, rest, flags, redactor) {
56647
58007
  throw new Error(
56648
58008
  "Missing message text. Usage: openmates chats new <message>"
56649
58009
  );
56650
- const result = await sendMessageStreaming(
58010
+ const result = apiKey ? await sendApiKeyChatNew(client, apiKey, message, flags) : await sendMessageStreaming(
56651
58011
  client,
56652
58012
  {
56653
58013
  message,
@@ -56887,7 +58247,14 @@ Run 'openmates chats show ` + chatId + "' to check if suggestions have been save
56887
58247
  let deleted = 0;
56888
58248
  for (const r of resolved) {
56889
58249
  try {
56890
- await client.deleteChat(r.input);
58250
+ if (apiKey) {
58251
+ await new OpenMates({ apiKey, apiUrl: client.apiUrl }).chats.delete(
58252
+ r.input,
58253
+ { confirmed: true }
58254
+ );
58255
+ } else {
58256
+ await client.deleteChat(r.input);
58257
+ }
56891
58258
  const label = r.title ? `"${r.title}"` : r.input;
56892
58259
  process.stdout.write(` \x1B[32m\u2713\x1B[0m Deleted ${label}
56893
58260
  `);
@@ -57035,16 +58402,16 @@ ${deleted}/${resolved.length} chat(s) deleted.`);
57035
58402
  }
57036
58403
  }
57037
58404
  const { mkdir, writeFile } = await import("fs/promises");
57038
- const { join: join6 } = await import("path");
58405
+ const { join: join7 } = await import("path");
57039
58406
  if (useZip) {
57040
- const tmpDir = join6(outputDir, `.${filenameBase}_tmp`);
58407
+ const tmpDir = join7(outputDir, `.${filenameBase}_tmp`);
57041
58408
  await mkdir(tmpDir, { recursive: true });
57042
- await writeFile(join6(tmpDir, `${filenameBase}.yml`), yamlContent);
57043
- await writeFile(join6(tmpDir, `${filenameBase}.md`), mdContent);
58409
+ await writeFile(join7(tmpDir, `${filenameBase}.yml`), yamlContent);
58410
+ await writeFile(join7(tmpDir, `${filenameBase}.md`), mdContent);
57044
58411
  if (codeEmbeds.length > 0) {
57045
58412
  for (const ce of codeEmbeds) {
57046
58413
  const fpath = ce.filePath ?? ce.filename ?? `${ce.embedId.slice(0, 8)}.${getExtForLang(ce.language)}`;
57047
- const fullPath = join6(tmpDir, "code", fpath);
58414
+ const fullPath = join7(tmpDir, "code", fpath);
57048
58415
  await mkdir(fullPath.substring(0, fullPath.lastIndexOf("/")), {
57049
58416
  recursive: true
57050
58417
  });
@@ -57052,13 +58419,13 @@ ${deleted}/${resolved.length} chat(s) deleted.`);
57052
58419
  }
57053
58420
  }
57054
58421
  if (transcriptEmbeds.length > 0) {
57055
- const tDir = join6(tmpDir, "transcripts");
58422
+ const tDir = join7(tmpDir, "transcripts");
57056
58423
  await mkdir(tDir, { recursive: true });
57057
58424
  for (const te of transcriptEmbeds) {
57058
- await writeFile(join6(tDir, te.filename), te.content);
58425
+ await writeFile(join7(tDir, te.filename), te.content);
57059
58426
  }
57060
58427
  }
57061
- const zipPath = join6(outputDir, `${filenameBase}.zip`);
58428
+ const zipPath = join7(outputDir, `${filenameBase}.zip`);
57062
58429
  const { execSync: execSync2 } = await import("child_process");
57063
58430
  try {
57064
58431
  execSync2(`cd "${tmpDir}" && zip -r "${zipPath}" .`, { stdio: "pipe" });
@@ -57073,17 +58440,17 @@ ${deleted}/${resolved.length} chat(s) deleted.`);
57073
58440
  );
57074
58441
  }
57075
58442
  } else {
57076
- const chatDir = join6(outputDir, filenameBase);
58443
+ const chatDir = join7(outputDir, filenameBase);
57077
58444
  await mkdir(chatDir, { recursive: true });
57078
58445
  const written = [];
57079
- await writeFile(join6(chatDir, `${filenameBase}.yml`), yamlContent);
58446
+ await writeFile(join7(chatDir, `${filenameBase}.yml`), yamlContent);
57080
58447
  written.push(`${filenameBase}.yml`);
57081
- await writeFile(join6(chatDir, `${filenameBase}.md`), mdContent);
58448
+ await writeFile(join7(chatDir, `${filenameBase}.md`), mdContent);
57082
58449
  written.push(`${filenameBase}.md`);
57083
58450
  if (codeEmbeds.length > 0) {
57084
58451
  for (const ce of codeEmbeds) {
57085
58452
  const fpath = ce.filePath ?? ce.filename ?? `${ce.embedId.slice(0, 8)}.${getExtForLang(ce.language)}`;
57086
- const fullPath = join6(chatDir, "code", fpath);
58453
+ const fullPath = join7(chatDir, "code", fpath);
57087
58454
  await mkdir(fullPath.substring(0, fullPath.lastIndexOf("/")), {
57088
58455
  recursive: true
57089
58456
  });
@@ -57092,10 +58459,10 @@ ${deleted}/${resolved.length} chat(s) deleted.`);
57092
58459
  }
57093
58460
  }
57094
58461
  if (transcriptEmbeds.length > 0) {
57095
- const tDir = join6(chatDir, "transcripts");
58462
+ const tDir = join7(chatDir, "transcripts");
57096
58463
  await mkdir(tDir, { recursive: true });
57097
58464
  for (const te of transcriptEmbeds) {
57098
- await writeFile(join6(tDir, te.filename), te.content);
58465
+ await writeFile(join7(tDir, te.filename), te.content);
57099
58466
  written.push(`transcripts/${te.filename}`);
57100
58467
  }
57101
58468
  }
@@ -57131,7 +58498,7 @@ ${deleted}/${resolved.length} chat(s) deleted.`);
57131
58498
  printJson2({
57132
58499
  chat_id: chat.id,
57133
58500
  title: chat.title,
57134
- output_dir: useZip ? join6(outputDir, `${filenameBase}.zip`) : join6(outputDir, filenameBase),
58501
+ output_dir: useZip ? join7(outputDir, `${filenameBase}.zip`) : join7(outputDir, filenameBase),
57135
58502
  files,
57136
58503
  code_embeds: codeEmbeds.length,
57137
58504
  transcript_embeds: transcriptEmbeds.length
@@ -57256,6 +58623,109 @@ ${deleted}/${resolved.length} chat(s) deleted.`);
57256
58623
  printChatsHelp();
57257
58624
  process.exit(1);
57258
58625
  }
58626
+ async function listApiKeyChats(client, apiKey, limit, page) {
58627
+ const safeLimit = Number.isFinite(limit) && limit > 0 ? limit : 10;
58628
+ const safePage = Number.isFinite(page) && page > 0 ? page : 1;
58629
+ const sdk = new OpenMates({ apiKey, apiUrl: client.apiUrl });
58630
+ const chats = await sdk.chats.list({ limit: safeLimit, offset: (safePage - 1) * safeLimit });
58631
+ return sdkChatsToChatListPage(chats, safeLimit, safePage);
58632
+ }
58633
+ async function searchApiKeyChats(client, apiKey, query) {
58634
+ const sdk = new OpenMates({ apiKey, apiUrl: client.apiUrl });
58635
+ const chats = await sdk.chats.search(query, { limit: 0 });
58636
+ return sdkChatsToChatListPage(chats, chats.length || 1, 1).chats;
58637
+ }
58638
+ function sdkChatsToChatListPage(chats, limit, page) {
58639
+ return {
58640
+ chats: chats.map((chat) => {
58641
+ const category = typeof chat.category === "string" ? chat.category : null;
58642
+ return {
58643
+ id: chat.id,
58644
+ shortId: chat.id.slice(0, 8),
58645
+ title: typeof chat.title === "string" ? chat.title : null,
58646
+ summary: typeof chat.chat_summary === "string" ? chat.chat_summary : null,
58647
+ updatedAt: normalizeSdkTimestamp(chat.updated_at),
58648
+ category,
58649
+ mateName: category ? MATE_NAMES[category] ?? null : null
58650
+ };
58651
+ }),
58652
+ total: chats.length,
58653
+ page,
58654
+ limit,
58655
+ hasMore: chats.length >= limit
58656
+ };
58657
+ }
58658
+ function normalizeSdkTimestamp(value) {
58659
+ if (typeof value === "number" && Number.isFinite(value)) return value;
58660
+ if (typeof value === "string" && value.trim()) {
58661
+ const parsed = Date.parse(value);
58662
+ return Number.isFinite(parsed) ? Math.floor(parsed / 1e3) : null;
58663
+ }
58664
+ return null;
58665
+ }
58666
+ async function sendApiKeyChatNew(client, apiKey, message, flags) {
58667
+ const sdk = new OpenMates({ apiKey, apiUrl: client.apiUrl });
58668
+ const response = await sdk.chats.send(message, {
58669
+ saveToAccount: false
58670
+ });
58671
+ const result = normalizeApiKeyChatResponse(response);
58672
+ if (flags.json !== true) {
58673
+ const category = typeof result.category === "string" ? result.category : null;
58674
+ const modelName = typeof result.modelName === "string" ? result.modelName : null;
58675
+ const mateBlock = ansiMateBlock(category, category ? MATE_NAMES[category] ?? null : null);
58676
+ const modelSuffix = modelName ? ` \x1B[2m${modelName}\x1B[0m` : "";
58677
+ process.stdout.write(`${SEP}
58678
+ `);
58679
+ process.stdout.write(`${mateBlock}${modelSuffix}
58680
+ `);
58681
+ process.stdout.write(`${SEP}
58682
+ `);
58683
+ process.stdout.write(`${String(result.assistant ?? "")}
58684
+ `);
58685
+ const chatId = typeof result.chatId === "string" ? result.chatId : null;
58686
+ if (chatId) {
58687
+ const shortId = chatId.slice(0, 8);
58688
+ process.stdout.write(`${SEP}
58689
+ `);
58690
+ process.stdout.write(
58691
+ `\x1B[2mContinue: openmates chats send --chat ${shortId} "your message"\x1B[0m
58692
+ \x1B[2mHistory: openmates chats show ${shortId}\x1B[0m
58693
+ `
58694
+ );
58695
+ }
58696
+ }
58697
+ return result;
58698
+ }
58699
+ function normalizeApiKeyChatResponse(response) {
58700
+ const chatId = typeof response.chat_id === "string" ? response.chat_id : null;
58701
+ const category = typeof response.category === "string" ? response.category : null;
58702
+ const modelName = typeof response.model_name === "string" ? response.model_name : null;
58703
+ return {
58704
+ status: "completed",
58705
+ chatId,
58706
+ chat_id: chatId,
58707
+ messageId: null,
58708
+ message_id: null,
58709
+ assistant: typeof response.content === "string" ? response.content : "",
58710
+ category,
58711
+ modelName,
58712
+ model_name: modelName,
58713
+ mateName: category ? MATE_NAMES[category] ?? null : null,
58714
+ followUpSuggestions: [],
58715
+ follow_up_suggestions: [],
58716
+ taskEvents: [],
58717
+ task_events: [],
58718
+ pendingTaskUpdateJobs: [],
58719
+ pending_task_update_jobs: [],
58720
+ subChatEvents: [],
58721
+ sub_chat_events: [],
58722
+ appSettingsMemoryRequests: [],
58723
+ app_settings_memory_requests: [],
58724
+ acceptedTaskProposals: [],
58725
+ accepted_task_proposals: [],
58726
+ raw: response
58727
+ };
58728
+ }
57259
58729
  function resolveExampleChatForOpen(target) {
57260
58730
  const numericTarget = parseInt(target, 10);
57261
58731
  if (!Number.isNaN(numericTarget) && String(numericTarget) === target.trim()) {
@@ -57302,7 +58772,7 @@ async function handleWorkflows(client, subcommand, rest, flags) {
57302
58772
  if (subcommand === "validate") {
57303
58773
  const file = typeof flags.file === "string" ? flags.file : "";
57304
58774
  if (!file) throw new Error("Missing --file. Example: openmates workflows validate --file workflow.yml");
57305
- const validation = await client.validateWorkflowYaml(readFileSync9(file, "utf8"));
58775
+ const validation = await client.validateWorkflowYaml(readFileSync10(file, "utf8"));
57306
58776
  if (flags.json === true) {
57307
58777
  printJson2(validation);
57308
58778
  } else {
@@ -57318,7 +58788,7 @@ async function handleWorkflows(client, subcommand, rest, flags) {
57318
58788
  if (subcommand === "create") {
57319
58789
  const yamlFile = typeof flags.file === "string" ? flags.file : "";
57320
58790
  if (yamlFile) {
57321
- const result = await client.createWorkflowYaml(readFileSync9(yamlFile, "utf8"));
58791
+ const result = await client.createWorkflowYaml(readFileSync10(yamlFile, "utf8"));
57322
58792
  if (flags.json === true) {
57323
58793
  printJson2(result);
57324
58794
  } else {
@@ -57351,7 +58821,7 @@ async function handleWorkflows(client, subcommand, rest, flags) {
57351
58821
  const workflowId = rest[0];
57352
58822
  const yamlFile = typeof flags.file === "string" ? flags.file : "";
57353
58823
  if (!workflowId || !yamlFile) throw new Error("Missing workflow ID or --file. Example: openmates workflows update <id> --file workflow.yml");
57354
- const result = await client.updateWorkflowYaml(workflowId, readFileSync9(yamlFile, "utf8"));
58824
+ const result = await client.updateWorkflowYaml(workflowId, readFileSync10(yamlFile, "utf8"));
57355
58825
  if (flags.json === true) {
57356
58826
  printJson2(result);
57357
58827
  } else {
@@ -58470,7 +59940,7 @@ async function handleEmbeds(client, subcommand, rest, flags) {
58470
59940
  throw new Error("Embed version content was not available after local reconstruction.");
58471
59941
  }
58472
59942
  if (typeof flags.output === "string") {
58473
- writeFileSync6(flags.output, result.content, "utf-8");
59943
+ writeFileSync7(flags.output, result.content, "utf-8");
58474
59944
  if (flags.json === true) {
58475
59945
  printJson2({ ...result, output: flags.output });
58476
59946
  } else {
@@ -58912,11 +60382,11 @@ function parseYamlScalar(value) {
58912
60382
  }
58913
60383
  async function saveDownloadedDocument(document, output) {
58914
60384
  const { mkdir, writeFile } = await import("fs/promises");
58915
- const { join: join6, basename: basename4, dirname: dirname4 } = await import("path");
60385
+ const { join: join7, basename: basename4, dirname: dirname5 } = await import("path");
58916
60386
  const target = typeof output === "string" ? output : ".";
58917
60387
  const filename = basename4(document.filename || "document.pdf");
58918
- const filePath = target.endsWith(".pdf") ? target : join6(target, filename);
58919
- await mkdir(dirname4(filePath), { recursive: true });
60388
+ const filePath = target.endsWith(".pdf") ? target : join7(target, filename);
60389
+ await mkdir(dirname5(filePath), { recursive: true });
58920
60390
  await writeFile(filePath, document.data);
58921
60391
  return filePath;
58922
60392
  }
@@ -59073,7 +60543,7 @@ async function promptPlainText(question) {
59073
60543
  }
59074
60544
  async function writeSecretFile(filePath, content, force = false) {
59075
60545
  const { mkdir, writeFile, stat: stat2 } = await import("fs/promises");
59076
- const { dirname: dirname4 } = await import("path");
60546
+ const { dirname: dirname5 } = await import("path");
59077
60547
  try {
59078
60548
  await stat2(filePath);
59079
60549
  if (!force) throw new Error(`${filePath} already exists. Use --force to overwrite.`);
@@ -59083,13 +60553,13 @@ async function writeSecretFile(filePath, content, force = false) {
59083
60553
  }
59084
60554
  if (error instanceof Error && !("code" in error)) throw error;
59085
60555
  }
59086
- await mkdir(dirname4(filePath), { recursive: true });
60556
+ await mkdir(dirname5(filePath), { recursive: true });
59087
60557
  await writeFile(filePath, content, { mode: 384 });
59088
60558
  return filePath;
59089
60559
  }
59090
60560
  async function generateProvisioningPassword() {
59091
- const { randomBytes: randomBytes4 } = await import("crypto");
59092
- return `OM-${randomBytes4(18).toString("base64url")}-aA2#`;
60561
+ const { randomBytes: randomBytes5 } = await import("crypto");
60562
+ return `OM-${randomBytes5(18).toString("base64url")}-aA2#`;
59093
60563
  }
59094
60564
  function decodeBase32(input) {
59095
60565
  const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
@@ -62574,7 +64044,7 @@ async function handleDocs(client, subcommand, rest, flags) {
62574
64044
  }
62575
64045
  if (subcommand === "download") {
62576
64046
  const { writeFile, mkdir } = await import("fs/promises");
62577
- const { join: join6, dirname: dirname4 } = await import("path");
64047
+ const { join: join7, dirname: dirname5 } = await import("path");
62578
64048
  if (flags.all === true) {
62579
64049
  const outputDir = typeof flags.output === "string" ? flags.output : "./openmates-docs";
62580
64050
  const tree = await client.listDocs();
@@ -62583,8 +64053,8 @@ async function handleDocs(client, subcommand, rest, flags) {
62583
64053
  let count = 0;
62584
64054
  for (const slug2 of slugs) {
62585
64055
  const content2 = await client.getDoc(slug2);
62586
- const filePath = join6(outputDir, `${slug2}.md`);
62587
- await mkdir(dirname4(filePath), { recursive: true });
64056
+ const filePath = join7(outputDir, `${slug2}.md`);
64057
+ await mkdir(dirname5(filePath), { recursive: true });
62588
64058
  await writeFile(filePath, content2, "utf-8");
62589
64059
  count++;
62590
64060
  process.stderr.write(`\r Downloaded ${count}/${slugs.length}`);
@@ -62657,7 +64127,7 @@ function isCliEntrypoint() {
62657
64127
  try {
62658
64128
  const invokedPath = realpathSync(entrypoint);
62659
64129
  const modulePath = realpathSync(fileURLToPath2(import.meta.url));
62660
- return invokedPath === modulePath || basename3(invokedPath) === "cli.js" && dirname3(invokedPath) === dirname3(modulePath);
64130
+ return invokedPath === modulePath || basename3(invokedPath) === "cli.js" && dirname4(invokedPath) === dirname4(modulePath);
62661
64131
  } catch {
62662
64132
  return false;
62663
64133
  }
@@ -62671,21 +64141,6 @@ if (isCliEntrypoint()) {
62671
64141
  }
62672
64142
 
62673
64143
  export {
62674
- deriveChatCompletionRecoveryKeypair,
62675
- openChatCompletionRecoveryEnvelope,
62676
- unwrapApiKeyMasterKey,
62677
- decryptWithAesGcmCombined,
62678
- decryptBytesWithAesGcm,
62679
- encryptBytesWithAesGcm,
62680
- encryptWithAesGcmCombined,
62681
- hashItemKey,
62682
- generateChatShareBlob,
62683
- generateEmbedShareBlob,
62684
- deriveWebOrigin,
62685
- buildChatShareUrl,
62686
- buildEmbedShareUrl,
62687
- decryptConnectedAccountCliTransferPayload,
62688
- buildEncryptedConnectedAccountImportRow,
62689
64144
  INTEREST_TAG_IDS,
62690
64145
  normalizeInterestTagIds,
62691
64146
  MEMORY_TYPE_REGISTRY,
@@ -62694,7 +64149,9 @@ export {
62694
64149
  deriveAppUrl,
62695
64150
  OpenMatesClient,
62696
64151
  APP_SKILL_METADATA,
62697
- GeneratedAppSkills,
64152
+ OpenMatesConfigError,
64153
+ OpenMatesApiError,
64154
+ OpenMates,
62698
64155
  SUPPORT_URL,
62699
64156
  renderSupportInfo,
62700
64157
  defaultCloneBranchForVersion,