openmates 0.15.0-alpha.22 → 0.15.0-alpha.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-AXNRPVLE.js";
5
5
 
6
6
  // src/client.ts
7
- import { randomUUID as randomUUID5 } from "crypto";
7
+ import { createHash as createHash6, randomUUID as randomUUID5 } from "crypto";
8
8
  import { arch, platform as platform2, release } from "os";
9
9
  import { createInterface as createInterface2 } from "readline/promises";
10
10
  import { stdin as stdin2, stdout } from "process";
@@ -3540,9 +3540,11 @@ function stripTimer(job) {
3540
3540
  }
3541
3541
 
3542
3542
  // src/tasksCli.ts
3543
- import { createHash as createHash5, randomBytes as randomBytes2, randomUUID as randomUUID4 } from "crypto";
3543
+ import { createHash as createHash5, createHmac, hkdfSync, randomBytes as randomBytes2, randomUUID as randomUUID4 } from "crypto";
3544
3544
  var TASK_STATUSES2 = ["backlog", "todo", "in_progress", "blocked", "done"];
3545
3545
  var DEFAULT_STANDALONE_PREFIX = "TASK";
3546
+ var PRIORITY_LEVELS = ["none", "low", "medium", "high", "urgent"];
3547
+ var LABEL_INDEX_INFO = "openmates-task-label-index-v1";
3546
3548
  function normalizeTaskStatus(value) {
3547
3549
  if (value === void 0) return void 0;
3548
3550
  if (TASK_STATUSES2.includes(value)) return value;
@@ -3566,12 +3568,43 @@ function parseDueAt(value) {
3566
3568
  if (Number.isNaN(parsed)) throw new Error(`Invalid --due value '${value}'.`);
3567
3569
  return Math.floor(parsed / 1e3);
3568
3570
  }
3571
+ function normalizeLabels(labels) {
3572
+ const output = [];
3573
+ const seen = /* @__PURE__ */ new Set();
3574
+ for (const label of labels ?? []) {
3575
+ const normalized = label.trim().toLowerCase().replace(/\s+/g, " ");
3576
+ if (!normalized || seen.has(normalized)) continue;
3577
+ seen.add(normalized);
3578
+ output.push(normalized);
3579
+ }
3580
+ return output;
3581
+ }
3582
+ function labelHashes(masterKey, labels) {
3583
+ const indexKey = Buffer.from(hkdfSync("sha256", Buffer.from(masterKey), Buffer.alloc(0), LABEL_INDEX_INFO, 32));
3584
+ return normalizeLabels(labels).map((label) => createHmac("sha256", indexKey).update(label).digest("hex"));
3585
+ }
3586
+ function normalizeTaskPriority(value) {
3587
+ if (value === void 0) return void 0;
3588
+ if (value === null) return 0;
3589
+ if (typeof value === "number") {
3590
+ if (!Number.isInteger(value) || value < 0 || value > 4) throw new Error(`Invalid task priority '${value}'.`);
3591
+ return value;
3592
+ }
3593
+ const normalized = value.trim().toLowerCase();
3594
+ const index = PRIORITY_LEVELS.indexOf(normalized);
3595
+ if (index < 0) throw new Error(`Unknown task priority '${value}'. Expected one of: ${PRIORITY_LEVELS.join(", ")}`);
3596
+ return index;
3597
+ }
3598
+ function taskPriorityLevel(priority) {
3599
+ return PRIORITY_LEVELS[Math.max(0, Math.min(4, Math.trunc(priority ?? 0)))] ?? "none";
3600
+ }
3569
3601
  async function buildCreateUserTaskInput(masterKey, input) {
3570
3602
  const taskKey = randomBytes2(32);
3571
3603
  const encryptedTaskKey = await encryptBytesWithAesGcm(taskKey, masterKey);
3572
3604
  const timestamp = nowSeconds();
3573
3605
  const assignee = parseAssignee(input.assign);
3574
3606
  const linkedProjectIds = input.projectIds ?? [];
3607
+ const labels = normalizeLabels(input.labels ?? input.tags ?? []);
3575
3608
  const status = input.status ?? (assignee.assigneeType === "ai" && !input.dueAt ? "in_progress" : "todo");
3576
3609
  return {
3577
3610
  task_id: randomUUIDCompat(),
@@ -3580,7 +3613,9 @@ async function buildCreateUserTaskInput(masterKey, input) {
3580
3613
  encrypted_task_key: encryptedTaskKey,
3581
3614
  encrypted_title: await encryptWithAesGcmCombined(input.title, taskKey),
3582
3615
  encrypted_description: await encryptWithAesGcmCombined(input.description ?? "", taskKey),
3583
- encrypted_tags: await encryptWithAesGcmCombined("[]", taskKey),
3616
+ encrypted_labels: await encryptWithAesGcmCombined(JSON.stringify(labels), taskKey),
3617
+ encrypted_tags: await encryptWithAesGcmCombined(JSON.stringify(labels), taskKey),
3618
+ label_hashes: labelHashes(masterKey, labels),
3584
3619
  encrypted_linked_project_ids: await encryptWithAesGcmCombined(JSON.stringify(linkedProjectIds), taskKey),
3585
3620
  status,
3586
3621
  assignee_type: assignee.assigneeType,
@@ -3589,7 +3624,7 @@ async function buildCreateUserTaskInput(masterKey, input) {
3589
3624
  linked_project_ids: linkedProjectIds,
3590
3625
  plan_id: input.planId ?? null,
3591
3626
  due_at: input.dueAt ?? null,
3592
- priority: 0,
3627
+ priority: normalizeTaskPriority(input.priority) ?? 0,
3593
3628
  position: timestamp,
3594
3629
  created_at: timestamp,
3595
3630
  updated_at: timestamp
@@ -3612,20 +3647,32 @@ async function buildUpdateUserTaskInput(task, masterKey, input) {
3612
3647
  patch.encrypted_linked_project_ids = await encryptWithAesGcmCombined(JSON.stringify(input.projectIds), taskKey);
3613
3648
  }
3614
3649
  if (input.planId !== void 0) patch.plan_id = input.planId;
3650
+ const priority = normalizeTaskPriority(input.priority);
3651
+ if (priority !== void 0) patch.priority = priority;
3652
+ const replaceLabels = input.labels ?? input.tags;
3653
+ if (replaceLabels !== void 0 || input.addLabels !== void 0 || input.addTags !== void 0 || input.removeLabels !== void 0 || input.removeTags !== void 0) {
3654
+ const remove = new Set(normalizeLabels([...input.removeLabels ?? [], ...input.removeTags ?? []]));
3655
+ const base = replaceLabels !== void 0 ? normalizeLabels(replaceLabels) : task.labels;
3656
+ const labels = normalizeLabels([...base.filter((label) => !remove.has(label)), ...input.addLabels ?? [], ...input.addTags ?? []]);
3657
+ patch.encrypted_labels = await encryptWithAesGcmCombined(JSON.stringify(labels), taskKey);
3658
+ patch.encrypted_tags = await encryptWithAesGcmCombined(JSON.stringify(labels), taskKey);
3659
+ patch.label_hashes = labelHashes(masterKey, labels);
3660
+ }
3615
3661
  return patch;
3616
3662
  }
3617
3663
  async function decryptUserTask(record, masterKey) {
3618
3664
  if (record.source === "workflow_run") return workflowProjectionToTask(record);
3619
3665
  if (typeof record.version !== "number") throw new Error(`Task ${record.task_id} is missing version.`);
3620
3666
  const taskKey = await taskKeyFromRecord(record, masterKey);
3621
- const tags = parseStringArray(await decryptOptional(record.encrypted_tags, taskKey));
3667
+ const labels = parseStringArray(await decryptOptional(record.encrypted_labels || record.encrypted_tags, taskKey));
3622
3668
  const linkedProjectIds = parseStringArray(await decryptOptional(record.encrypted_linked_project_ids, taskKey));
3623
3669
  return {
3624
3670
  taskId: record.task_id,
3625
3671
  shortId: record.short_id || deriveShortId(record),
3626
3672
  title: await decryptOptional(record.encrypted_title, taskKey) || "(untitled task)",
3627
3673
  description: await decryptOptional(record.encrypted_description, taskKey),
3628
- tags,
3674
+ labels,
3675
+ tags: labels,
3629
3676
  latestInstruction: await decryptOptional(record.encrypted_latest_instruction, taskKey),
3630
3677
  status: record.status,
3631
3678
  assigneeType: record.assignee_type,
@@ -3635,6 +3682,7 @@ async function decryptUserTask(record, masterKey) {
3635
3682
  planId: record.plan_id ?? null,
3636
3683
  dueAt: record.due_at ?? null,
3637
3684
  priority: record.priority ?? 0,
3685
+ priorityLevel: taskPriorityLevel(record.priority),
3638
3686
  position: record.position ?? 0,
3639
3687
  queueState: record.queue_state ?? "none",
3640
3688
  blockedReasonCode: record.blocked_reason_code ?? null,
@@ -3651,6 +3699,7 @@ function workflowProjectionToTask(record) {
3651
3699
  shortId: record.short_id || workflowProjectionShortId(record),
3652
3700
  title: record.title || "Workflow run",
3653
3701
  description: record.blocked_message ?? "",
3702
+ labels: [],
3654
3703
  tags: [],
3655
3704
  latestInstruction: "",
3656
3705
  status: record.status,
@@ -3661,6 +3710,7 @@ function workflowProjectionToTask(record) {
3661
3710
  planId: null,
3662
3711
  dueAt: record.due_at ?? null,
3663
3712
  priority: record.priority ?? 0,
3713
+ priorityLevel: taskPriorityLevel(record.priority),
3664
3714
  position: record.position ?? 0,
3665
3715
  queueState: String(record.run_status ?? "workflow"),
3666
3716
  blockedReasonCode: blockedReason,
@@ -3690,9 +3740,9 @@ function findTask(tasks, id) {
3690
3740
  }
3691
3741
  function renderTaskList(tasks) {
3692
3742
  if (tasks.length === 0) return "No tasks found.";
3693
- const lines = ["Tasks", "ID Status Assignee Queue Title"];
3743
+ const lines = ["Tasks", "ID Status Priority Labels Title"];
3694
3744
  for (const task of tasks) {
3695
- lines.push(`${pad(task.shortId, 9)} ${pad(task.status, 12)} ${pad(assigneeLabel(task), 11)} ${pad(task.queueState, 11)} ${task.title}`);
3745
+ lines.push(`${pad(task.shortId, 9)} ${pad(task.status, 12)} ${pad(task.priorityLevel, 9)} ${pad(task.labels.join(","), 19)} ${task.title}`);
3696
3746
  }
3697
3747
  return lines.join("\n");
3698
3748
  }
@@ -3701,11 +3751,13 @@ function renderTaskDetail(task) {
3701
3751
  `Task ${task.shortId}`,
3702
3752
  `Title: ${task.title}`,
3703
3753
  `Status: ${task.status}`,
3754
+ `Priority: ${task.priorityLevel}`,
3704
3755
  `Assignee: ${assigneeLabel(task)}`,
3705
3756
  `Queue: ${task.queueState}`,
3706
3757
  `Task ID: ${task.taskId}`
3707
3758
  ];
3708
3759
  if (task.description) lines.push(`Description: ${task.description}`);
3760
+ if (task.labels.length > 0) lines.push(`Labels: ${task.labels.join(", ")}`);
3709
3761
  if (task.primaryChatId) lines.push(`Chat: ${task.primaryChatId}`);
3710
3762
  if (task.linkedProjectIds.length > 0) lines.push(`Projects: ${task.linkedProjectIds.join(", ")}`);
3711
3763
  if (task.planId) lines.push(`Plan: ${task.planId}`);
@@ -3801,7 +3853,8 @@ function normalizeUnixSeconds(value, fallback) {
3801
3853
  }
3802
3854
  function getClientMessagesVersionForSync(cached) {
3803
3855
  if (cached.messages.length === 0) return 0;
3804
- return typeof cached.details.messages_v === "number" ? cached.details.messages_v : 0;
3856
+ const messagesVersion = typeof cached.details.messages_v === "number" ? cached.details.messages_v : 0;
3857
+ return Math.min(messagesVersion, cached.messages.length);
3805
3858
  }
3806
3859
  var INTEREST_TAG_IDS = [
3807
3860
  "software_development",
@@ -4035,7 +4088,10 @@ function assertTaskPersistPayloadEncrypted(payload) {
4035
4088
  "blocked_reason_code",
4036
4089
  "created_at",
4037
4090
  "key_wrappers",
4091
+ "label_hashes",
4038
4092
  "linked_project_ids",
4093
+ "plan_id",
4094
+ "plan_step_id",
4039
4095
  "position",
4040
4096
  "primary_chat_id",
4041
4097
  "priority",
@@ -4854,7 +4910,7 @@ var OpenMatesClient = class _OpenMatesClient {
4854
4910
  if (!userId) {
4855
4911
  throw new Error("Could not resolve current user id for local connected-account connector.");
4856
4912
  }
4857
- const { createHash: createHash9 } = await import("crypto");
4913
+ const { createHash: createHash10 } = await import("crypto");
4858
4914
  const accountId = randomUUID5();
4859
4915
  const masterKey = this.getMasterKeyBytes();
4860
4916
  const encryptLocalConnectorValue = async (value) => {
@@ -4863,9 +4919,9 @@ var OpenMatesClient = class _OpenMatesClient {
4863
4919
  };
4864
4920
  const payload = {
4865
4921
  id: accountId,
4866
- hashed_user_id: createHash9("sha256").update(userId).digest("hex"),
4922
+ hashed_user_id: createHash10("sha256").update(userId).digest("hex"),
4867
4923
  encrypted_provider_type: await encryptLocalConnectorValue(input.provider_id),
4868
- provider_type_hash: createHash9("sha256").update(input.provider_id).digest("hex"),
4924
+ provider_type_hash: createHash10("sha256").update(input.provider_id).digest("hex"),
4869
4925
  encrypted_account_label: await encryptLocalConnectorValue(input.label),
4870
4926
  encrypted_capabilities: await encryptLocalConnectorValue(input.capabilities),
4871
4927
  encrypted_app_permissions: await encryptLocalConnectorValue({
@@ -5306,14 +5362,26 @@ var OpenMatesClient = class _OpenMatesClient {
5306
5362
  async decryptChatKey(encryptedChatKey, masterKey) {
5307
5363
  return decryptBytesWithAesGcm(encryptedChatKey, masterKey);
5308
5364
  }
5365
+ getMasterWrapperEncryptedChatKey(cache, chatId) {
5366
+ const hashedChatId = createHash6("sha256").update(chatId).digest("hex");
5367
+ const wrapper = (cache?.chatKeyWrappers ?? []).find(
5368
+ (entry) => entry.key_type === "master" && entry.hashed_chat_id === hashedChatId && typeof entry.encrypted_chat_key === "string"
5369
+ );
5370
+ return typeof wrapper?.encrypted_chat_key === "string" ? wrapper.encrypted_chat_key : null;
5371
+ }
5372
+ async resolveChatKey(cache, cached, masterKey) {
5373
+ const chatId = String(cached.details.id ?? "");
5374
+ const wrapperKey = chatId ? this.getMasterWrapperEncryptedChatKey(cache, chatId) : null;
5375
+ const encryptedChatKey = wrapperKey ?? (typeof cached.details.encrypted_chat_key === "string" ? cached.details.encrypted_chat_key : null);
5376
+ return encryptedChatKey ? this.decryptChatKey(encryptedChatKey, masterKey) : null;
5377
+ }
5309
5378
  /**
5310
5379
  * Decrypt a single chat record from the sync cache into a ChatListItem.
5311
5380
  */
5312
- async decryptChatListItem(cached, masterKey) {
5381
+ async decryptChatListItem(cached, masterKey, cache = loadSyncCache()) {
5313
5382
  const d = cached.details;
5314
5383
  const id = String(d.id ?? "");
5315
- const encKey = typeof d.encrypted_chat_key === "string" ? d.encrypted_chat_key : null;
5316
- const chatKeyBytes = encKey ? await this.decryptChatKey(encKey, masterKey) : null;
5384
+ const chatKeyBytes = await this.resolveChatKey(cache, cached, masterKey);
5317
5385
  const title = typeof d.encrypted_title === "string" && chatKeyBytes ? await decryptWithAesGcmCombined(d.encrypted_title, chatKeyBytes) : null;
5318
5386
  const summary = typeof d.encrypted_chat_summary === "string" && chatKeyBytes ? await decryptWithAesGcmCombined(
5319
5387
  d.encrypted_chat_summary,
@@ -5338,7 +5406,7 @@ var OpenMatesClient = class _OpenMatesClient {
5338
5406
  const slice = cache.chats.slice(offset, offset + limit);
5339
5407
  const output = [];
5340
5408
  for (const chat of slice) {
5341
- output.push(await this.decryptChatListItem(chat, masterKey));
5409
+ output.push(await this.decryptChatListItem(chat, masterKey, cache));
5342
5410
  }
5343
5411
  return {
5344
5412
  chats: output,
@@ -5528,7 +5596,7 @@ var OpenMatesClient = class _OpenMatesClient {
5528
5596
  * @param query Full UUID, 8-char short ID, or chat title.
5529
5597
  */
5530
5598
  async getChatMessages(query) {
5531
- const cache = await this.ensureSynced();
5599
+ const cache = await this.ensureSynced(true);
5532
5600
  const masterKey = this.getMasterKeyBytes();
5533
5601
  const normalized = query.trim().toLowerCase();
5534
5602
  let found;
@@ -5547,7 +5615,7 @@ var OpenMatesClient = class _OpenMatesClient {
5547
5615
  }
5548
5616
  if (!found) {
5549
5617
  for (const cached of cache.chats) {
5550
- const item = await this.decryptChatListItem(cached, masterKey);
5618
+ const item = await this.decryptChatListItem(cached, masterKey, cache);
5551
5619
  const title = (item.title ?? "").toLowerCase();
5552
5620
  if (title === normalized) {
5553
5621
  found = cached;
@@ -5570,9 +5638,8 @@ var OpenMatesClient = class _OpenMatesClient {
5570
5638
  `Chat '${query}' not found. Try 'openmates chats search "${query}"' to browse matches.`
5571
5639
  );
5572
5640
  }
5573
- const chatItem = await this.decryptChatListItem(found, masterKey);
5574
- const encKey = typeof found.details.encrypted_chat_key === "string" ? found.details.encrypted_chat_key : null;
5575
- const chatKeyBytes = encKey ? await this.decryptChatKey(encKey, masterKey) : null;
5641
+ const chatItem = await this.decryptChatListItem(found, masterKey, cache);
5642
+ const chatKeyBytes = await this.resolveChatKey(cache, found, masterKey);
5576
5643
  const messages = [];
5577
5644
  for (const raw of found.messages) {
5578
5645
  const m = typeof raw === "string" ? JSON.parse(raw) : raw;
@@ -5591,8 +5658,8 @@ var OpenMatesClient = class _OpenMatesClient {
5591
5658
  );
5592
5659
  let msgEmbedIds = [];
5593
5660
  if (clientMsgId && cache.embeds.length > 0) {
5594
- const { createHash: createHash9 } = await import("crypto");
5595
- const hashed = createHash9("sha256").update(clientMsgId).digest("hex");
5661
+ const { createHash: createHash10 } = await import("crypto");
5662
+ const hashed = createHash10("sha256").update(clientMsgId).digest("hex");
5596
5663
  msgEmbedIds = cache.embeds.filter(
5597
5664
  (e) => e.hashed_message_id === hashed && // Only include parent embeds (no parent_embed_id).
5598
5665
  // Child embeds inherit the parent's key and are loaded
@@ -5639,8 +5706,8 @@ var OpenMatesClient = class _OpenMatesClient {
5639
5706
  );
5640
5707
  }
5641
5708
  const embedId = String(embed.embed_id ?? embed.id ?? "");
5642
- const { createHash: createHash9 } = await import("crypto");
5643
- const hashedEmbedId = createHash9("sha256").update(embedId).digest("hex");
5709
+ const { createHash: createHash10 } = await import("crypto");
5710
+ const hashedEmbedId = createHash10("sha256").update(embedId).digest("hex");
5644
5711
  const embedKeyBytes = await this.resolveEmbedKey(
5645
5712
  cache,
5646
5713
  masterKey,
@@ -5748,7 +5815,7 @@ var OpenMatesClient = class _OpenMatesClient {
5748
5815
  async resolveEmbedKey(cache, masterKey, embed, embedId, hashedEmbedId, visited = /* @__PURE__ */ new Set()) {
5749
5816
  if (visited.has(embedId)) return null;
5750
5817
  visited.add(embedId);
5751
- const { createHash: createHash9 } = await import("crypto");
5818
+ const { createHash: createHash10 } = await import("crypto");
5752
5819
  const masterKeyEntry = cache.embedKeys.find(
5753
5820
  (ek) => ek.hashed_embed_id === hashedEmbedId && String(ek.key_type) === "master"
5754
5821
  );
@@ -5765,7 +5832,7 @@ var OpenMatesClient = class _OpenMatesClient {
5765
5832
  if (chatKeyEntry && typeof chatKeyEntry.encrypted_embed_key === "string") {
5766
5833
  const hashedChatId = String(chatKeyEntry.hashed_chat_id ?? "");
5767
5834
  const owningChat = cache.chats.find((c) => {
5768
- const chatHash = createHash9("sha256").update(String(c.details.id ?? "")).digest("hex");
5835
+ const chatHash = createHash10("sha256").update(String(c.details.id ?? "")).digest("hex");
5769
5836
  return chatHash === hashedChatId;
5770
5837
  });
5771
5838
  if (owningChat) {
@@ -5794,7 +5861,7 @@ var OpenMatesClient = class _OpenMatesClient {
5794
5861
  const parentFullId = String(
5795
5862
  parentEmbed2.embed_id ?? parentEmbed2.id ?? ""
5796
5863
  );
5797
- const parentHashedId = createHash9("sha256").update(parentFullId).digest("hex");
5864
+ const parentHashedId = createHash10("sha256").update(parentFullId).digest("hex");
5798
5865
  const parentKey = await this.resolveEmbedKey(
5799
5866
  cache,
5800
5867
  masterKey,
@@ -5886,9 +5953,7 @@ var OpenMatesClient = class _OpenMatesClient {
5886
5953
  (c) => String(c.details.id ?? "") === chatId || String(c.details.id ?? "").startsWith(chatId)
5887
5954
  );
5888
5955
  if (!found) return [];
5889
- const encKey = typeof found.details.encrypted_chat_key === "string" ? found.details.encrypted_chat_key : null;
5890
- if (!encKey) return [];
5891
- const chatKeyBytes = await this.decryptChatKey(encKey, masterKey);
5956
+ const chatKeyBytes = await this.resolveChatKey(cache, found, masterKey);
5892
5957
  if (!chatKeyBytes) return [];
5893
5958
  const encSuggestions = typeof found.details.encrypted_follow_up_request_suggestions === "string" ? found.details.encrypted_follow_up_request_suggestions : null;
5894
5959
  if (!encSuggestions) return [];
@@ -7783,6 +7848,8 @@ var OpenMatesClient = class _OpenMatesClient {
7783
7848
  if (filters.status) params.set("status", filters.status);
7784
7849
  if (filters.chatId) params.set("chat_id", filters.chatId);
7785
7850
  if (filters.projectId) params.set("project_id", filters.projectId);
7851
+ for (const labelHash of filters.labelHashes ?? []) params.append("label_hash", labelHash);
7852
+ if (filters.priority !== void 0) params.set("priority", String(filters.priority));
7786
7853
  const limit = filters.limit;
7787
7854
  if (Number.isSafeInteger(limit) && limit !== void 0 && limit > 0) params.set("limit", String(limit));
7788
7855
  const query = params.toString();
@@ -8837,7 +8904,7 @@ Required: ${schema.required.join(", ")}`
8837
8904
  const session = this.requireSession();
8838
8905
  const masterKey = base64ToBytes(session.masterKeyExportedB64);
8839
8906
  const cache = await this.ensureSynced();
8840
- const { createHash: createHash9 } = await import("crypto");
8907
+ const { createHash: createHash10 } = await import("crypto");
8841
8908
  const embed = cache.embeds.find(
8842
8909
  (e) => String(e.embed_id ?? "").startsWith(embedIdOrShort) || String(e.id ?? "").startsWith(embedIdOrShort)
8843
8910
  );
@@ -8845,7 +8912,7 @@ Required: ${schema.required.join(", ")}`
8845
8912
  throw new Error(`Embed '${embedIdOrShort}' not found in local cache.`);
8846
8913
  }
8847
8914
  const embedId = String(embed.embed_id ?? embed.id ?? "");
8848
- const hashedEmbedId = createHash9("sha256").update(embedId).digest("hex");
8915
+ const hashedEmbedId = createHash10("sha256").update(embedId).digest("hex");
8849
8916
  const embedKeyBytes = await this.resolveEmbedKey(
8850
8917
  cache,
8851
8918
  masterKey,
@@ -8953,8 +9020,8 @@ Required: ${schema.required.join(", ")}`
8953
9020
  if (!embed) {
8954
9021
  throw new Error(`Embed '${embedId}' not found in local cache. Run 'openmates chats list' to sync first.`);
8955
9022
  }
8956
- const { createHash: createHash9 } = await import("crypto");
8957
- const hashedEmbedId = createHash9("sha256").update(embedId).digest("hex");
9023
+ const { createHash: createHash10 } = await import("crypto");
9024
+ const hashedEmbedId = createHash10("sha256").update(embedId).digest("hex");
8958
9025
  const embedKey = await this.resolveEmbedKey(
8959
9026
  cache,
8960
9027
  masterKey,
@@ -9048,8 +9115,8 @@ Required: ${schema.required.join(", ")}`
9048
9115
  if (!embed) {
9049
9116
  throw new Error(`Embed '${embedId}' not found in local cache. Run 'openmates chats list' to sync first.`);
9050
9117
  }
9051
- const { createHash: createHash9 } = await import("crypto");
9052
- const hashedEmbedId = createHash9("sha256").update(embedId).digest("hex");
9118
+ const { createHash: createHash10 } = await import("crypto");
9119
+ const hashedEmbedId = createHash10("sha256").update(embedId).digest("hex");
9053
9120
  const embedKey = await this.resolveEmbedKey(
9054
9121
  cache,
9055
9122
  masterKey,
@@ -9321,6 +9388,7 @@ Required: ${schema.required.join(", ")}`
9321
9388
  const chats = [];
9322
9389
  const embeds = [];
9323
9390
  const embedKeys = [];
9391
+ const chatKeyWrappers = [];
9324
9392
  let newChatSuggestions = [];
9325
9393
  let totalChatCount = 0;
9326
9394
  let reconciliation = { authoritative: false };
@@ -9348,6 +9416,7 @@ Required: ${schema.required.join(", ")}`
9348
9416
  }
9349
9417
  if (p.embeds) embeds.push(...p.embeds);
9350
9418
  if (p.embed_keys) embedKeys.push(...p.embed_keys);
9419
+ if (p.chat_key_wrappers) chatKeyWrappers.push(...p.chat_key_wrappers);
9351
9420
  } else if (frame.type === "phase_2_last_20_chats_ready") {
9352
9421
  const p = frame.payload;
9353
9422
  totalChatCount = p.total_chat_count ?? 0;
@@ -9361,6 +9430,7 @@ Required: ${schema.required.join(", ")}`
9361
9430
  if (!details || typeof details.id !== "string") continue;
9362
9431
  chats.push({ details, messages: [] });
9363
9432
  }
9433
+ if (p.chat_key_wrappers) chatKeyWrappers.push(...p.chat_key_wrappers);
9364
9434
  } else if (frame.type === "background_message_sync") {
9365
9435
  const p = frame.payload;
9366
9436
  for (const c of p.chats ?? []) {
@@ -9370,6 +9440,7 @@ Required: ${schema.required.join(", ")}`
9370
9440
  }
9371
9441
  if (p.embeds) embeds.push(...p.embeds);
9372
9442
  if (p.embed_keys) embedKeys.push(...p.embed_keys);
9443
+ if (p.chat_key_wrappers) chatKeyWrappers.push(...p.chat_key_wrappers);
9373
9444
  } else if (frame.type === "pending_ai_response") {
9374
9445
  pendingAIResponses.push(frame.payload);
9375
9446
  }
@@ -9435,18 +9506,29 @@ Required: ${schema.required.join(", ")}`
9435
9506
  embedKeys.push(cached);
9436
9507
  }
9437
9508
  }
9509
+ const serverChatKeyWrapperIds = new Set(
9510
+ chatKeyWrappers.map((entry) => String(entry.id ?? ""))
9511
+ );
9512
+ for (const cached of existingCache.chatKeyWrappers ?? []) {
9513
+ const cachedId = String(cached.id ?? "");
9514
+ if (cachedId && !serverChatKeyWrapperIds.has(cachedId)) {
9515
+ chatKeyWrappers.push(cached);
9516
+ }
9517
+ }
9438
9518
  }
9439
9519
  const reconciledChats = reconcileAuthoritativeChats(chats, reconciliation);
9440
9520
  chats.splice(0, chats.length, ...reconciledChats);
9441
9521
  if (reconciliation.deleted_chat_ids?.length) {
9442
- const { createHash: createHash9 } = await import("crypto");
9522
+ const { createHash: createHash10 } = await import("crypto");
9443
9523
  const deletedHashes = new Set(
9444
- reconciliation.deleted_chat_ids.map((id) => createHash9("sha256").update(id).digest("hex"))
9524
+ reconciliation.deleted_chat_ids.map((id) => createHash10("sha256").update(id).digest("hex"))
9445
9525
  );
9446
9526
  const keptEmbeds = embeds.filter((embed) => !deletedHashes.has(String(embed.hashed_chat_id ?? "")));
9447
9527
  const keptKeys = embedKeys.filter((key) => !deletedHashes.has(String(key.hashed_chat_id ?? "")));
9528
+ const keptChatKeyWrappers = chatKeyWrappers.filter((key) => !deletedHashes.has(String(key.hashed_chat_id ?? "")));
9448
9529
  embeds.splice(0, embeds.length, ...keptEmbeds);
9449
9530
  embedKeys.splice(0, embedKeys.length, ...keptKeys);
9531
+ chatKeyWrappers.splice(0, chatKeyWrappers.length, ...keptChatKeyWrappers);
9450
9532
  }
9451
9533
  chats.sort(
9452
9534
  (a, b) => (typeof b.details.last_edited_overall_timestamp === "number" ? b.details.last_edited_overall_timestamp : 0) - (typeof a.details.last_edited_overall_timestamp === "number" ? a.details.last_edited_overall_timestamp : 0)
@@ -9478,6 +9560,7 @@ Required: ${schema.required.join(", ")}`
9478
9560
  chats,
9479
9561
  embeds,
9480
9562
  embedKeys,
9563
+ chatKeyWrappers,
9481
9564
  newChatSuggestions
9482
9565
  };
9483
9566
  saveSyncCache(cache);
@@ -9509,9 +9592,7 @@ Required: ${schema.required.join(", ")}`
9509
9592
  } catch {
9510
9593
  }
9511
9594
  }
9512
- const encryptedChatKey = typeof chat.details.encrypted_chat_key === "string" ? chat.details.encrypted_chat_key : null;
9513
- if (!encryptedChatKey) continue;
9514
- const chatKeyBytes = await this.decryptChatKey(encryptedChatKey, masterKey);
9595
+ const chatKeyBytes = await this.resolveChatKey(loadSyncCache(), chat, masterKey);
9515
9596
  if (!chatKeyBytes) continue;
9516
9597
  const completedAt = normalizeUnixSeconds(
9517
9598
  pending.fired_at,
@@ -13625,7 +13706,7 @@ var GeneratedAppSkills = class {
13625
13706
 
13626
13707
  // src/sdk.ts
13627
13708
  import { decode as toonDecode } from "@toon-format/toon";
13628
- import { createHash as createHash6, randomBytes as randomBytes3, randomUUID as randomUUID6 } from "crypto";
13709
+ import { createHash as createHash7, randomBytes as randomBytes3, randomUUID as randomUUID6 } from "crypto";
13629
13710
  import { chmodSync as chmodSync2, existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
13630
13711
  import { homedir as homedir4 } from "os";
13631
13712
  import { dirname, join as join3 } from "path";
@@ -13763,15 +13844,11 @@ var OpenMates = class {
13763
13844
  }
13764
13845
  async resolveEmbedKeyForShare(embedKeys, embedId) {
13765
13846
  const masterKey = await this.getMasterKey();
13766
- const hashedEmbedId = createHash6("sha256").update(embedId).digest("hex");
13847
+ const hashedEmbedId = createHash7("sha256").update(embedId).digest("hex");
13767
13848
  return this.resolveLoadedEmbedKey(embedKeys, hashedEmbedId, masterKey, masterKey);
13768
13849
  }
13769
- async decryptChatMetadata(chat) {
13770
- if (typeof chat.encrypted_chat_key !== "string") {
13771
- return chat;
13772
- }
13773
- const masterKey = await this.getMasterKey();
13774
- const chatKey = await decryptBytesWithAesGcm(chat.encrypted_chat_key, masterKey);
13850
+ async decryptChatMetadata(chat, chatKeyWrappers) {
13851
+ const chatKey = await this.resolveLoadedChatKey(chat, chatKeyWrappers);
13775
13852
  if (!chatKey) {
13776
13853
  return chat;
13777
13854
  }
@@ -13793,8 +13870,9 @@ var OpenMates = class {
13793
13870
  return payload;
13794
13871
  }
13795
13872
  const chatMetadata = chat;
13796
- const decryptedChat = await this.decryptChatMetadata(chatMetadata);
13797
- const chatKey = typeof chatMetadata.encrypted_chat_key === "string" ? await decryptBytesWithAesGcm(chatMetadata.encrypted_chat_key, await this.getMasterKey()) : null;
13873
+ const chatKeyWrappers = Array.isArray(payload.chat_key_wrappers) ? payload.chat_key_wrappers : Array.isArray(chatMetadata.chat_key_wrappers) ? chatMetadata.chat_key_wrappers : [];
13874
+ const decryptedChat = await this.decryptChatMetadata(chatMetadata, chatKeyWrappers);
13875
+ const chatKey = await this.resolveLoadedChatKey(chatMetadata, chatKeyWrappers);
13798
13876
  if (!chatKey || !Array.isArray(payload.messages)) {
13799
13877
  return { ...payload, chat: decryptedChat };
13800
13878
  }
@@ -13821,6 +13899,15 @@ var OpenMates = class {
13821
13899
  ) : payload.embeds;
13822
13900
  return { ...payload, chat: decryptedChat, messages, embeds };
13823
13901
  }
13902
+ async resolveLoadedChatKey(chat, chatKeyWrappers) {
13903
+ const masterKey = await this.getMasterKey();
13904
+ const hashedChatId = createHash7("sha256").update(chat.id).digest("hex");
13905
+ const wrapper = (chatKeyWrappers ?? []).find(
13906
+ (entry) => entry.key_type === "master" && entry.hashed_chat_id === hashedChatId && typeof entry.encrypted_chat_key === "string"
13907
+ );
13908
+ const encryptedChatKey = typeof wrapper?.encrypted_chat_key === "string" ? wrapper.encrypted_chat_key : typeof chat.encrypted_chat_key === "string" ? chat.encrypted_chat_key : null;
13909
+ return encryptedChatKey ? decryptBytesWithAesGcm(encryptedChatKey, masterKey) : null;
13910
+ }
13824
13911
  async decryptLoadedChatEmbeds(embeds, embedKeys, chatKey) {
13825
13912
  const masterKey = await this.getMasterKey();
13826
13913
  return Promise.all(embeds.map(async (embed) => {
@@ -13828,7 +13915,7 @@ var OpenMates = class {
13828
13915
  if (!embedId) {
13829
13916
  return { ...embed };
13830
13917
  }
13831
- const hashedEmbedId = createHash6("sha256").update(embedId).digest("hex");
13918
+ const hashedEmbedId = createHash7("sha256").update(embedId).digest("hex");
13832
13919
  const embedKey = await this.resolveLoadedEmbedKey(embedKeys, hashedEmbedId, masterKey, chatKey);
13833
13920
  if (!embedKey) {
13834
13921
  return { ...embed };
@@ -13951,7 +14038,12 @@ function loadOrCreateDeviceId(customPath) {
13951
14038
  function withQuery(path, query = {}) {
13952
14039
  const params = new URLSearchParams();
13953
14040
  for (const [key, value] of Object.entries(query)) {
13954
- if (value !== void 0 && value !== null) params.set(key, String(value));
14041
+ if (value === void 0 || value === null) continue;
14042
+ if (Array.isArray(value)) {
14043
+ for (const item of value) params.append(key, String(item));
14044
+ } else {
14045
+ params.set(key, String(value));
14046
+ }
13955
14047
  }
13956
14048
  const serialized = params.toString();
13957
14049
  return serialized ? `${path}?${serialized}` : path;
@@ -14705,10 +14797,13 @@ var OpenMatesTasks = class {
14705
14797
  return this.reorder(id, move, filters);
14706
14798
  }
14707
14799
  async listRaw(filters = {}) {
14800
+ const masterKey = filters.labels || filters.tags ? await this.client.masterKey() : void 0;
14708
14801
  const response = await this.client.get(withQuery("/v1/user-tasks", {
14709
14802
  status: filters.status,
14710
14803
  chat_id: filters.chatId,
14711
- project_id: filters.projectId
14804
+ project_id: filters.projectId,
14805
+ label_hash: masterKey ? labelHashes(masterKey, normalizeLabels(filters.labels ?? filters.tags ?? [])) : void 0,
14806
+ priority: normalizeTaskPriority(filters.priority)
14712
14807
  }));
14713
14808
  return response.tasks ?? [];
14714
14809
  }
@@ -15906,7 +16001,7 @@ var OutputRedactor = class {
15906
16001
  import { readFileSync as readFileSync5, statSync, existsSync as existsSync6 } from "fs";
15907
16002
  import { basename, extname, resolve as resolve2 } from "path";
15908
16003
  import { homedir as homedir5 } from "os";
15909
- import { createHash as createHash7 } from "crypto";
16004
+ import { createHash as createHash8 } from "crypto";
15910
16005
  var MAX_PER_FILE_SIZE = 100 * 1024 * 1024;
15911
16006
  var BLOCKED_EXTENSIONS = /* @__PURE__ */ new Set([
15912
16007
  ".pem",
@@ -16216,7 +16311,7 @@ function processCodeFile(filePath, filename, redactor) {
16216
16311
  line_count: lineCount
16217
16312
  });
16218
16313
  const textPreview = `${filename} (${language}, ${lineCount} lines)`;
16219
- const contentHash = createHash7("sha256").update(content).digest("hex");
16314
+ const contentHash = createHash8("sha256").update(content).digest("hex");
16220
16315
  const embed = {
16221
16316
  embedId,
16222
16317
  embedRef,
@@ -17771,7 +17866,7 @@ function formatTs(ts) {
17771
17866
 
17772
17867
  // src/server.ts
17773
17868
  import { execFileSync as execFileSync2, execSync, spawn as nodeSpawn, spawnSync } from "child_process";
17774
- import { createHash as createHash8, randomBytes as randomBytes4 } from "crypto";
17869
+ import { createHash as createHash9, randomBytes as randomBytes4 } from "crypto";
17775
17870
  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";
17776
17871
  import { createInterface as createInterface3 } from "readline";
17777
17872
  import { createInterface as createPromptInterface } from "readline/promises";
@@ -18436,7 +18531,7 @@ function packagedCaddyTemplatePath(role) {
18436
18531
  }
18437
18532
  function fileHash(path) {
18438
18533
  if (!existsSync7(path)) return null;
18439
- return createHash8("sha256").update(readFileSync6(path)).digest("hex");
18534
+ return createHash9("sha256").update(readFileSync6(path)).digest("hex");
18440
18535
  }
18441
18536
  async function loadSelfHostComposeTemplate(templateRef, role) {
18442
18537
  const templateDir = process.env.OPENMATES_SELFHOST_TEMPLATE_DIR;
@@ -18822,7 +18917,7 @@ function formatSecretPreflight(preflight) {
18822
18917
  return parts.join("; ");
18823
18918
  }
18824
18919
  function hashFile(path) {
18825
- const hash = createHash8("sha256");
18920
+ const hash = createHash9("sha256");
18826
18921
  const fd = openSync(path, "r");
18827
18922
  const buffer = Buffer.allocUnsafe(CHECKSUM_BUFFER_BYTES);
18828
18923
  try {
@@ -43031,7 +43126,7 @@ Only output the final Markdown table. Do NOT include explanations, notes, or any
43031
43126
  text: "@skill:tasks:create Do not ask follow-up questions. Create exactly these three tasks for a public OpenMates demo release checklist. Task 1 title: Review transcript for private data. Description: Confirm the source chat does not contain secrets, personal data, or private account details before publishing. Assign to me. Task 2 title: Verify Tasks and Workflows embeds. Description: Open the public example pages and confirm both parent embeds and child previews render and open fullscreen. Assign to me. Task 3 title: Write public release note. Description: Draft a short release note for developers explaining that the examples come from real CLI-created app-skill chats. Assign to OpenMates."
43032
43127
  },
43033
43128
  message_2: {
43034
- text: '```json\n{"type": "app_skill_use", "embed_id": "7996e3b5-8d25-46bd-b527-8da6f9c65ecf", "app_id": "tasks", "skill_id": "create"}\n```\n\nI\'ve created the three tasks for the OpenMates demo release checklist:\n\n1. **Review transcript for private data** (Assigned to you)\n2. **Verify Tasks and Workflows embeds** (Assigned to you)\n3. **Write public release note** (Assigned to OpenMates)'
43129
+ text: '```json\n{"type": "app_skill_use", "embed_id": "7996e3b5-8d25-46bd-b527-8da6f9c65ecf", "app_id": "tasks", "skill_id": "create"}\n```\n\nIch habe die drei Aufgaben f\xFCr die OpenMates-Demo-Release-Checkliste erstellt:\n\n1. **Transkript auf private Daten pr\xFCfen** (dir zugewiesen)\n2. **Tasks- und Workflows-Embeds pr\xFCfen** (dir zugewiesen)\n3. **\xD6ffentliche Release-Notiz schreiben** (OpenMates zugewiesen)'
43035
43130
  }
43036
43131
  },
43037
43132
  family_stays_kyoto: {
@@ -43415,7 +43510,7 @@ How are you leaning personally on this issue heading into the dinner? Are you ho
43415
43510
  text: "@skill:workflows:create-or-modify Do not ask follow-up questions. Create a simple manual workflow titled Library Book Return Checklist. It should have a manual trigger and three manual steps: gather borrowed books from the shelf, check due dates in the library account, and pack books in a tote bag before leaving home. Keep it concise and suitable for a public demo."
43416
43511
  },
43417
43512
  message_2: {
43418
- text: '```json\n{"type": "app_skill_use", "embed_id": "cda4695f-7f68-42d7-9cfe-d719aa08dc3e", "app_id": "workflows", "skill_id": "create-or-modify"}\n```\n\nI have created the **Library Book Return Checklist** workflow. This manual automation includes the following steps:\n\n1. **Gather books**: Gather borrowed books from the shelf.\n2. **Check due dates**: Check due dates in the library account.\n3. **Pack tote bag**: Pack books in a tote bag before leaving home.\n\nYou can view and manage this checklist in the [Workflows app](/#settings/apps/workflows).'
43513
+ text: '```json\n{"type": "app_skill_use", "embed_id": "cda4695f-7f68-42d7-9cfe-d719aa08dc3e", "app_id": "workflows", "skill_id": "create-or-modify"}\n```\n\nIch habe den Workflow **Bibliotheksb\xFCcher-R\xFCckgabe-Checkliste** erstellt. Diese manuelle Automatisierung enth\xE4lt die folgenden Schritte:\n\n1. **B\xFCcher zusammensuchen**: Ausgeliehene B\xFCcher aus dem Regal nehmen.\n2. **F\xE4lligkeitsdaten pr\xFCfen**: F\xE4lligkeitsdaten im Bibliothekskonto pr\xFCfen.\n3. **Stofftasche packen**: B\xFCcher vor dem Verlassen des Hauses in eine Stofftasche packen.\n\nDu kannst diese Checkliste in der [Workflows-App](/#settings/apps/workflows) ansehen und verwalten.'
43419
43514
  }
43420
43515
  },
43421
43516
  mastodon_account_recent_posts: {
@@ -61220,11 +61315,11 @@ function decodeBase32(input) {
61220
61315
  return Buffer.from(bytes);
61221
61316
  }
61222
61317
  async function generateTotpCode(secret) {
61223
- const { createHmac } = await import("crypto");
61318
+ const { createHmac: createHmac2 } = await import("crypto");
61224
61319
  const counter = Math.floor(Date.now() / 1e3 / 30);
61225
61320
  const counterBuffer = Buffer.alloc(8);
61226
61321
  counterBuffer.writeBigUInt64BE(BigInt(counter));
61227
- const hmac = createHmac("sha1", decodeBase32(secret)).update(counterBuffer).digest();
61322
+ const hmac = createHmac2("sha1", decodeBase32(secret)).update(counterBuffer).digest();
61228
61323
  const offset = hmac[hmac.length - 1] & 15;
61229
61324
  const code = (hmac.readUInt32BE(offset) & 2147483647) % 1e6;
61230
61325
  return String(code).padStart(6, "0");
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  getExtForLang,
4
4
  serializeToYaml
5
- } from "./chunk-47BFVCB4.js";
5
+ } from "./chunk-F4JZMA6W.js";
6
6
  import "./chunk-AXNRPVLE.js";
7
7
  export {
8
8
  getExtForLang,
package/dist/index.d.ts CHANGED
@@ -31,6 +31,9 @@ interface CachedEmbed {
31
31
  interface CachedEmbedKey {
32
32
  [key: string]: unknown;
33
33
  }
34
+ interface CachedChatKeyWrapper {
35
+ [key: string]: unknown;
36
+ }
34
37
  interface CachedNewChatSuggestion {
35
38
  [key: string]: unknown;
36
39
  }
@@ -47,6 +50,8 @@ interface SyncCache {
47
50
  embeds: CachedEmbed[];
48
51
  /** Embed keys for embed decryption */
49
52
  embedKeys: CachedEmbedKey[];
53
+ /** Chat key wrappers for wrapper-first chat decryption */
54
+ chatKeyWrappers?: CachedChatKeyWrapper[];
50
55
  /**
51
56
  * New chat suggestions from the last sync.
52
57
  * Each entry has id, chat_id, encrypted_suggestion, created_at.
@@ -559,7 +564,9 @@ interface UserTaskRecord {
559
564
  encrypted_task_key?: string | null;
560
565
  encrypted_title: string;
561
566
  encrypted_description?: string | null;
567
+ encrypted_labels?: string | null;
562
568
  encrypted_tags?: string | null;
569
+ label_hashes?: string[] | null;
563
570
  encrypted_linked_project_ids?: string | null;
564
571
  encrypted_activity_summary?: string | null;
565
572
  encrypted_latest_instruction?: string | null;
@@ -1283,6 +1290,8 @@ declare class OpenMatesClient {
1283
1290
  * encrypt/decrypt the chat's title, category, messages, etc.
1284
1291
  */
1285
1292
  private decryptChatKey;
1293
+ private getMasterWrapperEncryptedChatKey;
1294
+ private resolveChatKey;
1286
1295
  /**
1287
1296
  * Decrypt a single chat record from the sync cache into a ChatListItem.
1288
1297
  */
@@ -1582,6 +1591,8 @@ declare class OpenMatesClient {
1582
1591
  status?: UserTaskStatus;
1583
1592
  chatId?: string;
1584
1593
  projectId?: string;
1594
+ labelHashes?: string[];
1595
+ priority?: number;
1585
1596
  limit?: number;
1586
1597
  }): Promise<UserTaskRecord[]>;
1587
1598
  createUserTask(input: UserTaskCreateInput): Promise<UserTaskRecord>;
@@ -4800,12 +4811,15 @@ declare class GeneratedAppSkills {
4800
4811
  readonly workflows: WorkflowsAppSkills;
4801
4812
  }
4802
4813
 
4814
+ declare const PRIORITY_LEVELS: readonly ["none", "low", "medium", "high", "urgent"];
4815
+ type TaskPriorityLevel = typeof PRIORITY_LEVELS[number];
4803
4816
  interface DecryptedUserTask {
4804
4817
  taskId: string;
4805
4818
  source?: string;
4806
4819
  shortId: string;
4807
4820
  title: string;
4808
4821
  description: string;
4822
+ labels: string[];
4809
4823
  tags: string[];
4810
4824
  latestInstruction: string;
4811
4825
  status: UserTaskStatus;
@@ -4816,6 +4830,7 @@ interface DecryptedUserTask {
4816
4830
  planId: string | null;
4817
4831
  dueAt: number | null;
4818
4832
  priority: number;
4833
+ priorityLevel: TaskPriorityLevel;
4819
4834
  position: number;
4820
4835
  queueState: string;
4821
4836
  blockedReasonCode: string | null;
@@ -4827,21 +4842,31 @@ interface DecryptedUserTask {
4827
4842
  interface TaskCreateOptions {
4828
4843
  title: string;
4829
4844
  description?: string;
4845
+ labels?: string[];
4846
+ tags?: string[];
4830
4847
  status?: UserTaskStatus;
4831
4848
  assign?: string;
4832
4849
  chatId?: string | null;
4833
4850
  projectIds?: string[];
4834
4851
  planId?: string | null;
4835
4852
  dueAt?: number | null;
4853
+ priority?: TaskPriorityLevel | number | null;
4836
4854
  }
4837
4855
  interface TaskUpdateOptions {
4838
4856
  title?: string;
4839
4857
  description?: string;
4858
+ labels?: string[];
4859
+ tags?: string[];
4860
+ addLabels?: string[];
4861
+ addTags?: string[];
4862
+ removeLabels?: string[];
4863
+ removeTags?: string[];
4840
4864
  status?: UserTaskStatus;
4841
4865
  assign?: string;
4842
4866
  chatId?: string | null;
4843
4867
  projectIds?: string[];
4844
4868
  planId?: string | null;
4869
+ priority?: TaskPriorityLevel | number | null;
4845
4870
  }
4846
4871
 
4847
4872
  interface OpenMatesOptions {
@@ -4938,6 +4963,7 @@ interface EncryptedChatMetadata {
4938
4963
  id: string;
4939
4964
  encrypted_title?: string;
4940
4965
  encrypted_chat_key?: string;
4966
+ chat_key_wrappers?: ChatKeyWrapperRecord[];
4941
4967
  encrypted_chat_summary?: string;
4942
4968
  encrypted_category?: string;
4943
4969
  title?: string;
@@ -4961,6 +4987,9 @@ type TaskListFilters = {
4961
4987
  status?: UserTaskStatus;
4962
4988
  chatId?: string;
4963
4989
  projectId?: string;
4990
+ labels?: string[];
4991
+ tags?: string[];
4992
+ priority?: TaskPriorityLevel | number | null;
4964
4993
  };
4965
4994
  type TaskPlainCreateOptions = TaskCreateOptions;
4966
4995
  type TaskPlainUpdateOptions = TaskUpdateOptions;
@@ -4986,6 +5015,12 @@ interface EmbedKeyRecord {
4986
5015
  encrypted_embed_key?: string;
4987
5016
  [key: string]: unknown;
4988
5017
  }
5018
+ interface ChatKeyWrapperRecord {
5019
+ hashed_chat_id?: string;
5020
+ key_type?: string;
5021
+ encrypted_chat_key?: string;
5022
+ [key: string]: unknown;
5023
+ }
4989
5024
  interface FocusModeSelection {
4990
5025
  appId: string;
4991
5026
  focusModeId: string;
@@ -5043,8 +5078,9 @@ declare class OpenMates {
5043
5078
  masterKey(): Promise<Uint8Array>;
5044
5079
  sdkSession(): Promise<SdkSessionResponse>;
5045
5080
  resolveEmbedKeyForShare(embedKeys: EmbedKeyRecord[], embedId: string): Promise<Uint8Array | null>;
5046
- decryptChatMetadata<T extends EncryptedChatMetadata>(chat: T): Promise<T>;
5081
+ decryptChatMetadata<T extends EncryptedChatMetadata>(chat: T, chatKeyWrappers?: ChatKeyWrapperRecord[]): Promise<T>;
5047
5082
  decryptLoadedChatPayload<T extends Record<string, unknown>>(payload: T): Promise<T>;
5083
+ private resolveLoadedChatKey;
5048
5084
  private decryptLoadedChatEmbeds;
5049
5085
  private resolveLoadedEmbedKey;
5050
5086
  private requestWithMethod;
package/dist/index.js CHANGED
@@ -18,7 +18,7 @@ import {
18
18
  reconcileAuthoritativeChats,
19
19
  renderSupportInfo,
20
20
  serializeToYaml
21
- } from "./chunk-47BFVCB4.js";
21
+ } from "./chunk-F4JZMA6W.js";
22
22
  import "./chunk-AXNRPVLE.js";
23
23
  export {
24
24
  APP_SKILL_METADATA,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openmates",
3
- "version": "0.15.0-alpha.22",
3
+ "version": "0.15.0-alpha.24",
4
4
  "description": "OpenMates CLI and SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",