openmates 0.15.0-alpha.21 → 0.15.0-alpha.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-GTFUGLRD.js → chunk-7ONUJGJ2.js} +296 -63
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +119 -10
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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(
|
|
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}`);
|
|
@@ -4035,7 +4087,10 @@ function assertTaskPersistPayloadEncrypted(payload) {
|
|
|
4035
4087
|
"blocked_reason_code",
|
|
4036
4088
|
"created_at",
|
|
4037
4089
|
"key_wrappers",
|
|
4090
|
+
"label_hashes",
|
|
4038
4091
|
"linked_project_ids",
|
|
4092
|
+
"plan_id",
|
|
4093
|
+
"plan_step_id",
|
|
4039
4094
|
"position",
|
|
4040
4095
|
"primary_chat_id",
|
|
4041
4096
|
"priority",
|
|
@@ -4854,7 +4909,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
4854
4909
|
if (!userId) {
|
|
4855
4910
|
throw new Error("Could not resolve current user id for local connected-account connector.");
|
|
4856
4911
|
}
|
|
4857
|
-
const { createHash:
|
|
4912
|
+
const { createHash: createHash10 } = await import("crypto");
|
|
4858
4913
|
const accountId = randomUUID5();
|
|
4859
4914
|
const masterKey = this.getMasterKeyBytes();
|
|
4860
4915
|
const encryptLocalConnectorValue = async (value) => {
|
|
@@ -4863,9 +4918,9 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
4863
4918
|
};
|
|
4864
4919
|
const payload = {
|
|
4865
4920
|
id: accountId,
|
|
4866
|
-
hashed_user_id:
|
|
4921
|
+
hashed_user_id: createHash10("sha256").update(userId).digest("hex"),
|
|
4867
4922
|
encrypted_provider_type: await encryptLocalConnectorValue(input.provider_id),
|
|
4868
|
-
provider_type_hash:
|
|
4923
|
+
provider_type_hash: createHash10("sha256").update(input.provider_id).digest("hex"),
|
|
4869
4924
|
encrypted_account_label: await encryptLocalConnectorValue(input.label),
|
|
4870
4925
|
encrypted_capabilities: await encryptLocalConnectorValue(input.capabilities),
|
|
4871
4926
|
encrypted_app_permissions: await encryptLocalConnectorValue({
|
|
@@ -5306,14 +5361,26 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
5306
5361
|
async decryptChatKey(encryptedChatKey, masterKey) {
|
|
5307
5362
|
return decryptBytesWithAesGcm(encryptedChatKey, masterKey);
|
|
5308
5363
|
}
|
|
5364
|
+
getMasterWrapperEncryptedChatKey(cache, chatId) {
|
|
5365
|
+
const hashedChatId = createHash6("sha256").update(chatId).digest("hex");
|
|
5366
|
+
const wrapper = (cache?.chatKeyWrappers ?? []).find(
|
|
5367
|
+
(entry) => entry.key_type === "master" && entry.hashed_chat_id === hashedChatId && typeof entry.encrypted_chat_key === "string"
|
|
5368
|
+
);
|
|
5369
|
+
return typeof wrapper?.encrypted_chat_key === "string" ? wrapper.encrypted_chat_key : null;
|
|
5370
|
+
}
|
|
5371
|
+
async resolveChatKey(cache, cached, masterKey) {
|
|
5372
|
+
const chatId = String(cached.details.id ?? "");
|
|
5373
|
+
const wrapperKey = chatId ? this.getMasterWrapperEncryptedChatKey(cache, chatId) : null;
|
|
5374
|
+
const encryptedChatKey = wrapperKey ?? (typeof cached.details.encrypted_chat_key === "string" ? cached.details.encrypted_chat_key : null);
|
|
5375
|
+
return encryptedChatKey ? this.decryptChatKey(encryptedChatKey, masterKey) : null;
|
|
5376
|
+
}
|
|
5309
5377
|
/**
|
|
5310
5378
|
* Decrypt a single chat record from the sync cache into a ChatListItem.
|
|
5311
5379
|
*/
|
|
5312
|
-
async decryptChatListItem(cached, masterKey) {
|
|
5380
|
+
async decryptChatListItem(cached, masterKey, cache = loadSyncCache()) {
|
|
5313
5381
|
const d = cached.details;
|
|
5314
5382
|
const id = String(d.id ?? "");
|
|
5315
|
-
const
|
|
5316
|
-
const chatKeyBytes = encKey ? await this.decryptChatKey(encKey, masterKey) : null;
|
|
5383
|
+
const chatKeyBytes = await this.resolveChatKey(cache, cached, masterKey);
|
|
5317
5384
|
const title = typeof d.encrypted_title === "string" && chatKeyBytes ? await decryptWithAesGcmCombined(d.encrypted_title, chatKeyBytes) : null;
|
|
5318
5385
|
const summary = typeof d.encrypted_chat_summary === "string" && chatKeyBytes ? await decryptWithAesGcmCombined(
|
|
5319
5386
|
d.encrypted_chat_summary,
|
|
@@ -5338,7 +5405,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
5338
5405
|
const slice = cache.chats.slice(offset, offset + limit);
|
|
5339
5406
|
const output = [];
|
|
5340
5407
|
for (const chat of slice) {
|
|
5341
|
-
output.push(await this.decryptChatListItem(chat, masterKey));
|
|
5408
|
+
output.push(await this.decryptChatListItem(chat, masterKey, cache));
|
|
5342
5409
|
}
|
|
5343
5410
|
return {
|
|
5344
5411
|
chats: output,
|
|
@@ -5547,7 +5614,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
5547
5614
|
}
|
|
5548
5615
|
if (!found) {
|
|
5549
5616
|
for (const cached of cache.chats) {
|
|
5550
|
-
const item = await this.decryptChatListItem(cached, masterKey);
|
|
5617
|
+
const item = await this.decryptChatListItem(cached, masterKey, cache);
|
|
5551
5618
|
const title = (item.title ?? "").toLowerCase();
|
|
5552
5619
|
if (title === normalized) {
|
|
5553
5620
|
found = cached;
|
|
@@ -5570,9 +5637,8 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
5570
5637
|
`Chat '${query}' not found. Try 'openmates chats search "${query}"' to browse matches.`
|
|
5571
5638
|
);
|
|
5572
5639
|
}
|
|
5573
|
-
const chatItem = await this.decryptChatListItem(found, masterKey);
|
|
5574
|
-
const
|
|
5575
|
-
const chatKeyBytes = encKey ? await this.decryptChatKey(encKey, masterKey) : null;
|
|
5640
|
+
const chatItem = await this.decryptChatListItem(found, masterKey, cache);
|
|
5641
|
+
const chatKeyBytes = await this.resolveChatKey(cache, found, masterKey);
|
|
5576
5642
|
const messages = [];
|
|
5577
5643
|
for (const raw of found.messages) {
|
|
5578
5644
|
const m = typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
@@ -5591,8 +5657,8 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
5591
5657
|
);
|
|
5592
5658
|
let msgEmbedIds = [];
|
|
5593
5659
|
if (clientMsgId && cache.embeds.length > 0) {
|
|
5594
|
-
const { createHash:
|
|
5595
|
-
const hashed =
|
|
5660
|
+
const { createHash: createHash10 } = await import("crypto");
|
|
5661
|
+
const hashed = createHash10("sha256").update(clientMsgId).digest("hex");
|
|
5596
5662
|
msgEmbedIds = cache.embeds.filter(
|
|
5597
5663
|
(e) => e.hashed_message_id === hashed && // Only include parent embeds (no parent_embed_id).
|
|
5598
5664
|
// Child embeds inherit the parent's key and are loaded
|
|
@@ -5639,8 +5705,8 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
5639
5705
|
);
|
|
5640
5706
|
}
|
|
5641
5707
|
const embedId = String(embed.embed_id ?? embed.id ?? "");
|
|
5642
|
-
const { createHash:
|
|
5643
|
-
const hashedEmbedId =
|
|
5708
|
+
const { createHash: createHash10 } = await import("crypto");
|
|
5709
|
+
const hashedEmbedId = createHash10("sha256").update(embedId).digest("hex");
|
|
5644
5710
|
const embedKeyBytes = await this.resolveEmbedKey(
|
|
5645
5711
|
cache,
|
|
5646
5712
|
masterKey,
|
|
@@ -5748,7 +5814,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
5748
5814
|
async resolveEmbedKey(cache, masterKey, embed, embedId, hashedEmbedId, visited = /* @__PURE__ */ new Set()) {
|
|
5749
5815
|
if (visited.has(embedId)) return null;
|
|
5750
5816
|
visited.add(embedId);
|
|
5751
|
-
const { createHash:
|
|
5817
|
+
const { createHash: createHash10 } = await import("crypto");
|
|
5752
5818
|
const masterKeyEntry = cache.embedKeys.find(
|
|
5753
5819
|
(ek) => ek.hashed_embed_id === hashedEmbedId && String(ek.key_type) === "master"
|
|
5754
5820
|
);
|
|
@@ -5765,7 +5831,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
5765
5831
|
if (chatKeyEntry && typeof chatKeyEntry.encrypted_embed_key === "string") {
|
|
5766
5832
|
const hashedChatId = String(chatKeyEntry.hashed_chat_id ?? "");
|
|
5767
5833
|
const owningChat = cache.chats.find((c) => {
|
|
5768
|
-
const chatHash =
|
|
5834
|
+
const chatHash = createHash10("sha256").update(String(c.details.id ?? "")).digest("hex");
|
|
5769
5835
|
return chatHash === hashedChatId;
|
|
5770
5836
|
});
|
|
5771
5837
|
if (owningChat) {
|
|
@@ -5794,7 +5860,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
5794
5860
|
const parentFullId = String(
|
|
5795
5861
|
parentEmbed2.embed_id ?? parentEmbed2.id ?? ""
|
|
5796
5862
|
);
|
|
5797
|
-
const parentHashedId =
|
|
5863
|
+
const parentHashedId = createHash10("sha256").update(parentFullId).digest("hex");
|
|
5798
5864
|
const parentKey = await this.resolveEmbedKey(
|
|
5799
5865
|
cache,
|
|
5800
5866
|
masterKey,
|
|
@@ -5886,9 +5952,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
5886
5952
|
(c) => String(c.details.id ?? "") === chatId || String(c.details.id ?? "").startsWith(chatId)
|
|
5887
5953
|
);
|
|
5888
5954
|
if (!found) return [];
|
|
5889
|
-
const
|
|
5890
|
-
if (!encKey) return [];
|
|
5891
|
-
const chatKeyBytes = await this.decryptChatKey(encKey, masterKey);
|
|
5955
|
+
const chatKeyBytes = await this.resolveChatKey(cache, found, masterKey);
|
|
5892
5956
|
if (!chatKeyBytes) return [];
|
|
5893
5957
|
const encSuggestions = typeof found.details.encrypted_follow_up_request_suggestions === "string" ? found.details.encrypted_follow_up_request_suggestions : null;
|
|
5894
5958
|
if (!encSuggestions) return [];
|
|
@@ -7783,6 +7847,8 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
7783
7847
|
if (filters.status) params.set("status", filters.status);
|
|
7784
7848
|
if (filters.chatId) params.set("chat_id", filters.chatId);
|
|
7785
7849
|
if (filters.projectId) params.set("project_id", filters.projectId);
|
|
7850
|
+
for (const labelHash of filters.labelHashes ?? []) params.append("label_hash", labelHash);
|
|
7851
|
+
if (filters.priority !== void 0) params.set("priority", String(filters.priority));
|
|
7786
7852
|
const limit = filters.limit;
|
|
7787
7853
|
if (Number.isSafeInteger(limit) && limit !== void 0 && limit > 0) params.set("limit", String(limit));
|
|
7788
7854
|
const query = params.toString();
|
|
@@ -8837,7 +8903,7 @@ Required: ${schema.required.join(", ")}`
|
|
|
8837
8903
|
const session = this.requireSession();
|
|
8838
8904
|
const masterKey = base64ToBytes(session.masterKeyExportedB64);
|
|
8839
8905
|
const cache = await this.ensureSynced();
|
|
8840
|
-
const { createHash:
|
|
8906
|
+
const { createHash: createHash10 } = await import("crypto");
|
|
8841
8907
|
const embed = cache.embeds.find(
|
|
8842
8908
|
(e) => String(e.embed_id ?? "").startsWith(embedIdOrShort) || String(e.id ?? "").startsWith(embedIdOrShort)
|
|
8843
8909
|
);
|
|
@@ -8845,7 +8911,7 @@ Required: ${schema.required.join(", ")}`
|
|
|
8845
8911
|
throw new Error(`Embed '${embedIdOrShort}' not found in local cache.`);
|
|
8846
8912
|
}
|
|
8847
8913
|
const embedId = String(embed.embed_id ?? embed.id ?? "");
|
|
8848
|
-
const hashedEmbedId =
|
|
8914
|
+
const hashedEmbedId = createHash10("sha256").update(embedId).digest("hex");
|
|
8849
8915
|
const embedKeyBytes = await this.resolveEmbedKey(
|
|
8850
8916
|
cache,
|
|
8851
8917
|
masterKey,
|
|
@@ -8953,8 +9019,8 @@ Required: ${schema.required.join(", ")}`
|
|
|
8953
9019
|
if (!embed) {
|
|
8954
9020
|
throw new Error(`Embed '${embedId}' not found in local cache. Run 'openmates chats list' to sync first.`);
|
|
8955
9021
|
}
|
|
8956
|
-
const { createHash:
|
|
8957
|
-
const hashedEmbedId =
|
|
9022
|
+
const { createHash: createHash10 } = await import("crypto");
|
|
9023
|
+
const hashedEmbedId = createHash10("sha256").update(embedId).digest("hex");
|
|
8958
9024
|
const embedKey = await this.resolveEmbedKey(
|
|
8959
9025
|
cache,
|
|
8960
9026
|
masterKey,
|
|
@@ -9048,8 +9114,8 @@ Required: ${schema.required.join(", ")}`
|
|
|
9048
9114
|
if (!embed) {
|
|
9049
9115
|
throw new Error(`Embed '${embedId}' not found in local cache. Run 'openmates chats list' to sync first.`);
|
|
9050
9116
|
}
|
|
9051
|
-
const { createHash:
|
|
9052
|
-
const hashedEmbedId =
|
|
9117
|
+
const { createHash: createHash10 } = await import("crypto");
|
|
9118
|
+
const hashedEmbedId = createHash10("sha256").update(embedId).digest("hex");
|
|
9053
9119
|
const embedKey = await this.resolveEmbedKey(
|
|
9054
9120
|
cache,
|
|
9055
9121
|
masterKey,
|
|
@@ -9321,6 +9387,7 @@ Required: ${schema.required.join(", ")}`
|
|
|
9321
9387
|
const chats = [];
|
|
9322
9388
|
const embeds = [];
|
|
9323
9389
|
const embedKeys = [];
|
|
9390
|
+
const chatKeyWrappers = [];
|
|
9324
9391
|
let newChatSuggestions = [];
|
|
9325
9392
|
let totalChatCount = 0;
|
|
9326
9393
|
let reconciliation = { authoritative: false };
|
|
@@ -9348,6 +9415,7 @@ Required: ${schema.required.join(", ")}`
|
|
|
9348
9415
|
}
|
|
9349
9416
|
if (p.embeds) embeds.push(...p.embeds);
|
|
9350
9417
|
if (p.embed_keys) embedKeys.push(...p.embed_keys);
|
|
9418
|
+
if (p.chat_key_wrappers) chatKeyWrappers.push(...p.chat_key_wrappers);
|
|
9351
9419
|
} else if (frame.type === "phase_2_last_20_chats_ready") {
|
|
9352
9420
|
const p = frame.payload;
|
|
9353
9421
|
totalChatCount = p.total_chat_count ?? 0;
|
|
@@ -9361,6 +9429,7 @@ Required: ${schema.required.join(", ")}`
|
|
|
9361
9429
|
if (!details || typeof details.id !== "string") continue;
|
|
9362
9430
|
chats.push({ details, messages: [] });
|
|
9363
9431
|
}
|
|
9432
|
+
if (p.chat_key_wrappers) chatKeyWrappers.push(...p.chat_key_wrappers);
|
|
9364
9433
|
} else if (frame.type === "background_message_sync") {
|
|
9365
9434
|
const p = frame.payload;
|
|
9366
9435
|
for (const c of p.chats ?? []) {
|
|
@@ -9370,6 +9439,7 @@ Required: ${schema.required.join(", ")}`
|
|
|
9370
9439
|
}
|
|
9371
9440
|
if (p.embeds) embeds.push(...p.embeds);
|
|
9372
9441
|
if (p.embed_keys) embedKeys.push(...p.embed_keys);
|
|
9442
|
+
if (p.chat_key_wrappers) chatKeyWrappers.push(...p.chat_key_wrappers);
|
|
9373
9443
|
} else if (frame.type === "pending_ai_response") {
|
|
9374
9444
|
pendingAIResponses.push(frame.payload);
|
|
9375
9445
|
}
|
|
@@ -9435,18 +9505,29 @@ Required: ${schema.required.join(", ")}`
|
|
|
9435
9505
|
embedKeys.push(cached);
|
|
9436
9506
|
}
|
|
9437
9507
|
}
|
|
9508
|
+
const serverChatKeyWrapperIds = new Set(
|
|
9509
|
+
chatKeyWrappers.map((entry) => String(entry.id ?? ""))
|
|
9510
|
+
);
|
|
9511
|
+
for (const cached of existingCache.chatKeyWrappers ?? []) {
|
|
9512
|
+
const cachedId = String(cached.id ?? "");
|
|
9513
|
+
if (cachedId && !serverChatKeyWrapperIds.has(cachedId)) {
|
|
9514
|
+
chatKeyWrappers.push(cached);
|
|
9515
|
+
}
|
|
9516
|
+
}
|
|
9438
9517
|
}
|
|
9439
9518
|
const reconciledChats = reconcileAuthoritativeChats(chats, reconciliation);
|
|
9440
9519
|
chats.splice(0, chats.length, ...reconciledChats);
|
|
9441
9520
|
if (reconciliation.deleted_chat_ids?.length) {
|
|
9442
|
-
const { createHash:
|
|
9521
|
+
const { createHash: createHash10 } = await import("crypto");
|
|
9443
9522
|
const deletedHashes = new Set(
|
|
9444
|
-
reconciliation.deleted_chat_ids.map((id) =>
|
|
9523
|
+
reconciliation.deleted_chat_ids.map((id) => createHash10("sha256").update(id).digest("hex"))
|
|
9445
9524
|
);
|
|
9446
9525
|
const keptEmbeds = embeds.filter((embed) => !deletedHashes.has(String(embed.hashed_chat_id ?? "")));
|
|
9447
9526
|
const keptKeys = embedKeys.filter((key) => !deletedHashes.has(String(key.hashed_chat_id ?? "")));
|
|
9527
|
+
const keptChatKeyWrappers = chatKeyWrappers.filter((key) => !deletedHashes.has(String(key.hashed_chat_id ?? "")));
|
|
9448
9528
|
embeds.splice(0, embeds.length, ...keptEmbeds);
|
|
9449
9529
|
embedKeys.splice(0, embedKeys.length, ...keptKeys);
|
|
9530
|
+
chatKeyWrappers.splice(0, chatKeyWrappers.length, ...keptChatKeyWrappers);
|
|
9450
9531
|
}
|
|
9451
9532
|
chats.sort(
|
|
9452
9533
|
(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 +9559,7 @@ Required: ${schema.required.join(", ")}`
|
|
|
9478
9559
|
chats,
|
|
9479
9560
|
embeds,
|
|
9480
9561
|
embedKeys,
|
|
9562
|
+
chatKeyWrappers,
|
|
9481
9563
|
newChatSuggestions
|
|
9482
9564
|
};
|
|
9483
9565
|
saveSyncCache(cache);
|
|
@@ -9509,9 +9591,7 @@ Required: ${schema.required.join(", ")}`
|
|
|
9509
9591
|
} catch {
|
|
9510
9592
|
}
|
|
9511
9593
|
}
|
|
9512
|
-
const
|
|
9513
|
-
if (!encryptedChatKey) continue;
|
|
9514
|
-
const chatKeyBytes = await this.decryptChatKey(encryptedChatKey, masterKey);
|
|
9594
|
+
const chatKeyBytes = await this.resolveChatKey(loadSyncCache(), chat, masterKey);
|
|
9515
9595
|
if (!chatKeyBytes) continue;
|
|
9516
9596
|
const completedAt = normalizeUnixSeconds(
|
|
9517
9597
|
pending.fired_at,
|
|
@@ -13625,7 +13705,7 @@ var GeneratedAppSkills = class {
|
|
|
13625
13705
|
|
|
13626
13706
|
// src/sdk.ts
|
|
13627
13707
|
import { decode as toonDecode } from "@toon-format/toon";
|
|
13628
|
-
import { createHash as
|
|
13708
|
+
import { createHash as createHash7, randomBytes as randomBytes3, randomUUID as randomUUID6 } from "crypto";
|
|
13629
13709
|
import { chmodSync as chmodSync2, existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
13630
13710
|
import { homedir as homedir4 } from "os";
|
|
13631
13711
|
import { dirname, join as join3 } from "path";
|
|
@@ -13763,15 +13843,11 @@ var OpenMates = class {
|
|
|
13763
13843
|
}
|
|
13764
13844
|
async resolveEmbedKeyForShare(embedKeys, embedId) {
|
|
13765
13845
|
const masterKey = await this.getMasterKey();
|
|
13766
|
-
const hashedEmbedId =
|
|
13846
|
+
const hashedEmbedId = createHash7("sha256").update(embedId).digest("hex");
|
|
13767
13847
|
return this.resolveLoadedEmbedKey(embedKeys, hashedEmbedId, masterKey, masterKey);
|
|
13768
13848
|
}
|
|
13769
|
-
async decryptChatMetadata(chat) {
|
|
13770
|
-
|
|
13771
|
-
return chat;
|
|
13772
|
-
}
|
|
13773
|
-
const masterKey = await this.getMasterKey();
|
|
13774
|
-
const chatKey = await decryptBytesWithAesGcm(chat.encrypted_chat_key, masterKey);
|
|
13849
|
+
async decryptChatMetadata(chat, chatKeyWrappers) {
|
|
13850
|
+
const chatKey = await this.resolveLoadedChatKey(chat, chatKeyWrappers);
|
|
13775
13851
|
if (!chatKey) {
|
|
13776
13852
|
return chat;
|
|
13777
13853
|
}
|
|
@@ -13793,8 +13869,9 @@ var OpenMates = class {
|
|
|
13793
13869
|
return payload;
|
|
13794
13870
|
}
|
|
13795
13871
|
const chatMetadata = chat;
|
|
13796
|
-
const
|
|
13797
|
-
const
|
|
13872
|
+
const chatKeyWrappers = Array.isArray(payload.chat_key_wrappers) ? payload.chat_key_wrappers : Array.isArray(chatMetadata.chat_key_wrappers) ? chatMetadata.chat_key_wrappers : [];
|
|
13873
|
+
const decryptedChat = await this.decryptChatMetadata(chatMetadata, chatKeyWrappers);
|
|
13874
|
+
const chatKey = await this.resolveLoadedChatKey(chatMetadata, chatKeyWrappers);
|
|
13798
13875
|
if (!chatKey || !Array.isArray(payload.messages)) {
|
|
13799
13876
|
return { ...payload, chat: decryptedChat };
|
|
13800
13877
|
}
|
|
@@ -13821,6 +13898,15 @@ var OpenMates = class {
|
|
|
13821
13898
|
) : payload.embeds;
|
|
13822
13899
|
return { ...payload, chat: decryptedChat, messages, embeds };
|
|
13823
13900
|
}
|
|
13901
|
+
async resolveLoadedChatKey(chat, chatKeyWrappers) {
|
|
13902
|
+
const masterKey = await this.getMasterKey();
|
|
13903
|
+
const hashedChatId = createHash7("sha256").update(chat.id).digest("hex");
|
|
13904
|
+
const wrapper = (chatKeyWrappers ?? []).find(
|
|
13905
|
+
(entry) => entry.key_type === "master" && entry.hashed_chat_id === hashedChatId && typeof entry.encrypted_chat_key === "string"
|
|
13906
|
+
);
|
|
13907
|
+
const encryptedChatKey = typeof wrapper?.encrypted_chat_key === "string" ? wrapper.encrypted_chat_key : typeof chat.encrypted_chat_key === "string" ? chat.encrypted_chat_key : null;
|
|
13908
|
+
return encryptedChatKey ? decryptBytesWithAesGcm(encryptedChatKey, masterKey) : null;
|
|
13909
|
+
}
|
|
13824
13910
|
async decryptLoadedChatEmbeds(embeds, embedKeys, chatKey) {
|
|
13825
13911
|
const masterKey = await this.getMasterKey();
|
|
13826
13912
|
return Promise.all(embeds.map(async (embed) => {
|
|
@@ -13828,7 +13914,7 @@ var OpenMates = class {
|
|
|
13828
13914
|
if (!embedId) {
|
|
13829
13915
|
return { ...embed };
|
|
13830
13916
|
}
|
|
13831
|
-
const hashedEmbedId =
|
|
13917
|
+
const hashedEmbedId = createHash7("sha256").update(embedId).digest("hex");
|
|
13832
13918
|
const embedKey = await this.resolveLoadedEmbedKey(embedKeys, hashedEmbedId, masterKey, chatKey);
|
|
13833
13919
|
if (!embedKey) {
|
|
13834
13920
|
return { ...embed };
|
|
@@ -13951,7 +14037,12 @@ function loadOrCreateDeviceId(customPath) {
|
|
|
13951
14037
|
function withQuery(path, query = {}) {
|
|
13952
14038
|
const params = new URLSearchParams();
|
|
13953
14039
|
for (const [key, value] of Object.entries(query)) {
|
|
13954
|
-
if (value
|
|
14040
|
+
if (value === void 0 || value === null) continue;
|
|
14041
|
+
if (Array.isArray(value)) {
|
|
14042
|
+
for (const item of value) params.append(key, String(item));
|
|
14043
|
+
} else {
|
|
14044
|
+
params.set(key, String(value));
|
|
14045
|
+
}
|
|
13955
14046
|
}
|
|
13956
14047
|
const serialized = params.toString();
|
|
13957
14048
|
return serialized ? `${path}?${serialized}` : path;
|
|
@@ -14601,29 +14692,171 @@ var OpenMatesTasks = class {
|
|
|
14601
14692
|
this.client = client;
|
|
14602
14693
|
}
|
|
14603
14694
|
async list(filters = {}) {
|
|
14695
|
+
return (await this.listInternal(filters)).map(toPublicTask);
|
|
14696
|
+
}
|
|
14697
|
+
async listDecrypted(filters = {}) {
|
|
14698
|
+
return this.list(filters);
|
|
14699
|
+
}
|
|
14700
|
+
async show(id, filters = {}) {
|
|
14701
|
+
return toPublicTask(await this.resolve(id, filters));
|
|
14702
|
+
}
|
|
14703
|
+
async create(input) {
|
|
14704
|
+
const masterKey = await this.client.masterKey();
|
|
14705
|
+
const created = await this.createRaw(await buildCreateUserTaskInput(masterKey, input));
|
|
14706
|
+
return toPublicTask(await decryptUserTask(created, masterKey));
|
|
14707
|
+
}
|
|
14708
|
+
async update(id, input, filters = {}) {
|
|
14709
|
+
let task = await this.resolve(id, filters);
|
|
14710
|
+
const masterKey = await this.client.masterKey();
|
|
14711
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
14712
|
+
try {
|
|
14713
|
+
const updated = await this.updateRaw(task.taskId, await buildUpdateUserTaskInput(task, masterKey, input));
|
|
14714
|
+
return toPublicTask(await decryptUserTask(updated, masterKey));
|
|
14715
|
+
} catch (error) {
|
|
14716
|
+
if (attempt > 0 || !isTaskVersionConflict(error)) throw error;
|
|
14717
|
+
await delay(1e3);
|
|
14718
|
+
task = await this.resolve(id, filters);
|
|
14719
|
+
}
|
|
14720
|
+
}
|
|
14721
|
+
throw new OpenMatesConfigError("Task update retry failed unexpectedly");
|
|
14722
|
+
}
|
|
14723
|
+
async edit(id, input, filters = {}) {
|
|
14724
|
+
return this.update(id, input, filters);
|
|
14725
|
+
}
|
|
14726
|
+
async start(id, filters = {}) {
|
|
14727
|
+
let task = await this.resolve(id, filters);
|
|
14728
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
14729
|
+
try {
|
|
14730
|
+
const started = await this.startAIRaw(task.taskId, {
|
|
14731
|
+
version: task.version,
|
|
14732
|
+
primary_chat_id: task.primaryChatId ?? void 0,
|
|
14733
|
+
linked_project_ids: task.linkedProjectIds,
|
|
14734
|
+
plaintext_title: task.title,
|
|
14735
|
+
plaintext_description: task.description,
|
|
14736
|
+
plaintext_latest_instruction: task.latestInstruction
|
|
14737
|
+
});
|
|
14738
|
+
return toPublicTask(await decryptUserTask(started, await this.client.masterKey()));
|
|
14739
|
+
} catch (error) {
|
|
14740
|
+
if (attempt > 0 || !isTaskVersionConflict(error)) throw error;
|
|
14741
|
+
await delay(1e3);
|
|
14742
|
+
task = await this.resolve(id, filters);
|
|
14743
|
+
}
|
|
14744
|
+
}
|
|
14745
|
+
throw new OpenMatesConfigError("Task start retry failed unexpectedly");
|
|
14746
|
+
}
|
|
14747
|
+
async startAI(id, filters = {}) {
|
|
14748
|
+
return this.start(id, filters);
|
|
14749
|
+
}
|
|
14750
|
+
async delete(id, options = {}) {
|
|
14751
|
+
requireConfirmed(options, "Deleting a task");
|
|
14752
|
+
let task = await this.resolve(id, options.filters ?? {});
|
|
14753
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
14754
|
+
try {
|
|
14755
|
+
return await this.client.delete(`/v1/user-tasks/${encodeURIComponent(task.taskId)}?version=${encodeURIComponent(String(task.version))}`);
|
|
14756
|
+
} catch (error) {
|
|
14757
|
+
if (attempt > 0 || !isTaskVersionConflict(error)) throw error;
|
|
14758
|
+
await delay(1e3);
|
|
14759
|
+
task = await this.resolve(id, options.filters ?? {});
|
|
14760
|
+
}
|
|
14761
|
+
}
|
|
14762
|
+
throw new OpenMatesConfigError("Task delete retry failed unexpectedly");
|
|
14763
|
+
}
|
|
14764
|
+
async done(id, filters = {}) {
|
|
14765
|
+
return this.actionById(id, "complete", {}, filters);
|
|
14766
|
+
}
|
|
14767
|
+
async complete(id, filters = {}) {
|
|
14768
|
+
return this.done(id, filters);
|
|
14769
|
+
}
|
|
14770
|
+
async block(id, reason, filters = {}) {
|
|
14771
|
+
return this.actionById(id, "block", { blocked_reason_code: reason }, filters);
|
|
14772
|
+
}
|
|
14773
|
+
async unblock(id, filters = {}) {
|
|
14774
|
+
return this.actionById(id, "unblock", {}, filters);
|
|
14775
|
+
}
|
|
14776
|
+
async skip(id, filters = {}) {
|
|
14777
|
+
return this.actionById(id, "skip", {}, filters);
|
|
14778
|
+
}
|
|
14779
|
+
async reorder(id, move, filters = {}) {
|
|
14780
|
+
let task = await this.resolve(id, filters);
|
|
14781
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
14782
|
+
try {
|
|
14783
|
+
const response = await this.client.request("/v1/user-tasks/reorder", {
|
|
14784
|
+
moves: [{ ...move, task_id: task.taskId, version: task.version }]
|
|
14785
|
+
});
|
|
14786
|
+
return (await decryptUserTasks(response.tasks ?? [], await this.client.masterKey())).map(toPublicTask);
|
|
14787
|
+
} catch (error) {
|
|
14788
|
+
if (attempt > 0 || !isTaskVersionConflict(error)) throw error;
|
|
14789
|
+
await delay(1e3);
|
|
14790
|
+
task = await this.resolve(id, filters);
|
|
14791
|
+
}
|
|
14792
|
+
}
|
|
14793
|
+
throw new OpenMatesConfigError("Task reorder retry failed unexpectedly");
|
|
14794
|
+
}
|
|
14795
|
+
async move(id, move, filters = {}) {
|
|
14796
|
+
return this.reorder(id, move, filters);
|
|
14797
|
+
}
|
|
14798
|
+
async listRaw(filters = {}) {
|
|
14799
|
+
const masterKey = filters.labels || filters.tags ? await this.client.masterKey() : void 0;
|
|
14604
14800
|
const response = await this.client.get(withQuery("/v1/user-tasks", {
|
|
14605
14801
|
status: filters.status,
|
|
14606
14802
|
chat_id: filters.chatId,
|
|
14607
|
-
project_id: filters.projectId
|
|
14803
|
+
project_id: filters.projectId,
|
|
14804
|
+
label_hash: masterKey ? labelHashes(masterKey, normalizeLabels(filters.labels ?? filters.tags ?? [])) : void 0,
|
|
14805
|
+
priority: normalizeTaskPriority(filters.priority)
|
|
14608
14806
|
}));
|
|
14609
14807
|
return response.tasks ?? [];
|
|
14610
14808
|
}
|
|
14611
|
-
async
|
|
14809
|
+
async createRaw(input) {
|
|
14612
14810
|
const response = await this.client.request("/v1/user-tasks", input);
|
|
14613
14811
|
if (!response.task) throw new OpenMatesApiError(500, { detail: "User task response missing task" });
|
|
14614
14812
|
return response.task;
|
|
14615
14813
|
}
|
|
14616
|
-
async
|
|
14814
|
+
async updateRaw(taskId, input) {
|
|
14617
14815
|
const response = await this.client.patch(`/v1/user-tasks/${encodeURIComponent(taskId)}`, input);
|
|
14618
14816
|
if (!response.task) throw new OpenMatesApiError(500, { detail: "User task response missing task" });
|
|
14619
14817
|
return response.task;
|
|
14620
14818
|
}
|
|
14621
|
-
async
|
|
14819
|
+
async startAIRaw(taskId, input) {
|
|
14622
14820
|
const response = await this.client.request(`/v1/user-tasks/${encodeURIComponent(taskId)}/start-ai`, input);
|
|
14623
14821
|
if (!response.task) throw new OpenMatesApiError(500, { detail: "User task response missing task" });
|
|
14624
14822
|
return response.task;
|
|
14625
14823
|
}
|
|
14824
|
+
async listInternal(filters) {
|
|
14825
|
+
return decryptUserTasks(await this.listRaw(filters), await this.client.masterKey());
|
|
14826
|
+
}
|
|
14827
|
+
async resolve(id, filters) {
|
|
14828
|
+
return findTask(await this.listInternal(filters), id);
|
|
14829
|
+
}
|
|
14830
|
+
async actionRaw(taskId, action, input) {
|
|
14831
|
+
const response = await this.client.request(`/v1/user-tasks/${encodeURIComponent(taskId)}/${encodeURIComponent(action)}`, input);
|
|
14832
|
+
if (!response.task) throw new OpenMatesApiError(500, { detail: "User task response missing task" });
|
|
14833
|
+
return response.task;
|
|
14834
|
+
}
|
|
14835
|
+
async actionById(id, action, patch, filters) {
|
|
14836
|
+
let task = await this.resolve(id, filters);
|
|
14837
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
14838
|
+
try {
|
|
14839
|
+
const updated = await this.actionRaw(task.taskId, action, { version: task.version, ...patch });
|
|
14840
|
+
return toPublicTask(await decryptUserTask(updated, await this.client.masterKey()));
|
|
14841
|
+
} catch (error) {
|
|
14842
|
+
if (attempt > 0 || !isTaskVersionConflict(error)) throw error;
|
|
14843
|
+
await delay(1e3);
|
|
14844
|
+
task = await this.resolve(id, filters);
|
|
14845
|
+
}
|
|
14846
|
+
}
|
|
14847
|
+
throw new OpenMatesConfigError("Task action retry failed unexpectedly");
|
|
14848
|
+
}
|
|
14626
14849
|
};
|
|
14850
|
+
function toPublicTask(task) {
|
|
14851
|
+
const { encrypted: _encrypted, ...publicTask } = task;
|
|
14852
|
+
return publicTask;
|
|
14853
|
+
}
|
|
14854
|
+
function isTaskVersionConflict(error) {
|
|
14855
|
+
return error instanceof OpenMatesApiError && error.status === 409 && String(JSON.stringify(error.data)).includes("TASK_VERSION_CONFLICT");
|
|
14856
|
+
}
|
|
14857
|
+
function delay(ms) {
|
|
14858
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
14859
|
+
}
|
|
14627
14860
|
var OpenMatesPlans = class {
|
|
14628
14861
|
client;
|
|
14629
14862
|
constructor(client) {
|
|
@@ -15767,7 +16000,7 @@ var OutputRedactor = class {
|
|
|
15767
16000
|
import { readFileSync as readFileSync5, statSync, existsSync as existsSync6 } from "fs";
|
|
15768
16001
|
import { basename, extname, resolve as resolve2 } from "path";
|
|
15769
16002
|
import { homedir as homedir5 } from "os";
|
|
15770
|
-
import { createHash as
|
|
16003
|
+
import { createHash as createHash8 } from "crypto";
|
|
15771
16004
|
var MAX_PER_FILE_SIZE = 100 * 1024 * 1024;
|
|
15772
16005
|
var BLOCKED_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
15773
16006
|
".pem",
|
|
@@ -16077,7 +16310,7 @@ function processCodeFile(filePath, filename, redactor) {
|
|
|
16077
16310
|
line_count: lineCount
|
|
16078
16311
|
});
|
|
16079
16312
|
const textPreview = `${filename} (${language}, ${lineCount} lines)`;
|
|
16080
|
-
const contentHash =
|
|
16313
|
+
const contentHash = createHash8("sha256").update(content).digest("hex");
|
|
16081
16314
|
const embed = {
|
|
16082
16315
|
embedId,
|
|
16083
16316
|
embedRef,
|
|
@@ -17632,7 +17865,7 @@ function formatTs(ts) {
|
|
|
17632
17865
|
|
|
17633
17866
|
// src/server.ts
|
|
17634
17867
|
import { execFileSync as execFileSync2, execSync, spawn as nodeSpawn, spawnSync } from "child_process";
|
|
17635
|
-
import { createHash as
|
|
17868
|
+
import { createHash as createHash9, randomBytes as randomBytes4 } from "crypto";
|
|
17636
17869
|
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";
|
|
17637
17870
|
import { createInterface as createInterface3 } from "readline";
|
|
17638
17871
|
import { createInterface as createPromptInterface } from "readline/promises";
|
|
@@ -18297,7 +18530,7 @@ function packagedCaddyTemplatePath(role) {
|
|
|
18297
18530
|
}
|
|
18298
18531
|
function fileHash(path) {
|
|
18299
18532
|
if (!existsSync7(path)) return null;
|
|
18300
|
-
return
|
|
18533
|
+
return createHash9("sha256").update(readFileSync6(path)).digest("hex");
|
|
18301
18534
|
}
|
|
18302
18535
|
async function loadSelfHostComposeTemplate(templateRef, role) {
|
|
18303
18536
|
const templateDir = process.env.OPENMATES_SELFHOST_TEMPLATE_DIR;
|
|
@@ -18683,7 +18916,7 @@ function formatSecretPreflight(preflight) {
|
|
|
18683
18916
|
return parts.join("; ");
|
|
18684
18917
|
}
|
|
18685
18918
|
function hashFile(path) {
|
|
18686
|
-
const hash =
|
|
18919
|
+
const hash = createHash9("sha256");
|
|
18687
18920
|
const fd = openSync(path, "r");
|
|
18688
18921
|
const buffer = Buffer.allocUnsafe(CHECKSUM_BUFFER_BYTES);
|
|
18689
18922
|
try {
|
|
@@ -61081,11 +61314,11 @@ function decodeBase32(input) {
|
|
|
61081
61314
|
return Buffer.from(bytes);
|
|
61082
61315
|
}
|
|
61083
61316
|
async function generateTotpCode(secret) {
|
|
61084
|
-
const { createHmac } = await import("crypto");
|
|
61317
|
+
const { createHmac: createHmac2 } = await import("crypto");
|
|
61085
61318
|
const counter = Math.floor(Date.now() / 1e3 / 30);
|
|
61086
61319
|
const counterBuffer = Buffer.alloc(8);
|
|
61087
61320
|
counterBuffer.writeBigUInt64BE(BigInt(counter));
|
|
61088
|
-
const hmac =
|
|
61321
|
+
const hmac = createHmac2("sha1", decodeBase32(secret)).update(counterBuffer).digest();
|
|
61089
61322
|
const offset = hmac[hmac.length - 1] & 15;
|
|
61090
61323
|
const code = (hmac.readUInt32BE(offset) & 2147483647) % 1e6;
|
|
61091
61324
|
return String(code).padStart(6, "0");
|
package/dist/cli.js
CHANGED
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,6 +4811,64 @@ 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];
|
|
4816
|
+
interface DecryptedUserTask {
|
|
4817
|
+
taskId: string;
|
|
4818
|
+
source?: string;
|
|
4819
|
+
shortId: string;
|
|
4820
|
+
title: string;
|
|
4821
|
+
description: string;
|
|
4822
|
+
labels: string[];
|
|
4823
|
+
tags: string[];
|
|
4824
|
+
latestInstruction: string;
|
|
4825
|
+
status: UserTaskStatus;
|
|
4826
|
+
assigneeType: UserTaskAssigneeType;
|
|
4827
|
+
assigneeHash: string | null;
|
|
4828
|
+
primaryChatId: string | null;
|
|
4829
|
+
linkedProjectIds: string[];
|
|
4830
|
+
planId: string | null;
|
|
4831
|
+
dueAt: number | null;
|
|
4832
|
+
priority: number;
|
|
4833
|
+
priorityLevel: TaskPriorityLevel;
|
|
4834
|
+
position: number;
|
|
4835
|
+
queueState: string;
|
|
4836
|
+
blockedReasonCode: string | null;
|
|
4837
|
+
aiExecutionState: string | null;
|
|
4838
|
+
readOnly?: boolean;
|
|
4839
|
+
version: number;
|
|
4840
|
+
encrypted: UserTaskRecord;
|
|
4841
|
+
}
|
|
4842
|
+
interface TaskCreateOptions {
|
|
4843
|
+
title: string;
|
|
4844
|
+
description?: string;
|
|
4845
|
+
labels?: string[];
|
|
4846
|
+
tags?: string[];
|
|
4847
|
+
status?: UserTaskStatus;
|
|
4848
|
+
assign?: string;
|
|
4849
|
+
chatId?: string | null;
|
|
4850
|
+
projectIds?: string[];
|
|
4851
|
+
planId?: string | null;
|
|
4852
|
+
dueAt?: number | null;
|
|
4853
|
+
priority?: TaskPriorityLevel | number | null;
|
|
4854
|
+
}
|
|
4855
|
+
interface TaskUpdateOptions {
|
|
4856
|
+
title?: string;
|
|
4857
|
+
description?: string;
|
|
4858
|
+
labels?: string[];
|
|
4859
|
+
tags?: string[];
|
|
4860
|
+
addLabels?: string[];
|
|
4861
|
+
addTags?: string[];
|
|
4862
|
+
removeLabels?: string[];
|
|
4863
|
+
removeTags?: string[];
|
|
4864
|
+
status?: UserTaskStatus;
|
|
4865
|
+
assign?: string;
|
|
4866
|
+
chatId?: string | null;
|
|
4867
|
+
projectIds?: string[];
|
|
4868
|
+
planId?: string | null;
|
|
4869
|
+
priority?: TaskPriorityLevel | number | null;
|
|
4870
|
+
}
|
|
4871
|
+
|
|
4803
4872
|
interface OpenMatesOptions {
|
|
4804
4873
|
apiKey?: string;
|
|
4805
4874
|
apiUrl?: string;
|
|
@@ -4894,6 +4963,7 @@ interface EncryptedChatMetadata {
|
|
|
4894
4963
|
id: string;
|
|
4895
4964
|
encrypted_title?: string;
|
|
4896
4965
|
encrypted_chat_key?: string;
|
|
4966
|
+
chat_key_wrappers?: ChatKeyWrapperRecord[];
|
|
4897
4967
|
encrypted_chat_summary?: string;
|
|
4898
4968
|
encrypted_category?: string;
|
|
4899
4969
|
title?: string;
|
|
@@ -4913,6 +4983,17 @@ interface DraftRecord extends EncryptedDraftRecord {
|
|
|
4913
4983
|
markdown: string;
|
|
4914
4984
|
preview: string | null;
|
|
4915
4985
|
}
|
|
4986
|
+
type TaskListFilters = {
|
|
4987
|
+
status?: UserTaskStatus;
|
|
4988
|
+
chatId?: string;
|
|
4989
|
+
projectId?: string;
|
|
4990
|
+
labels?: string[];
|
|
4991
|
+
tags?: string[];
|
|
4992
|
+
priority?: TaskPriorityLevel | number | null;
|
|
4993
|
+
};
|
|
4994
|
+
type TaskPlainCreateOptions = TaskCreateOptions;
|
|
4995
|
+
type TaskPlainUpdateOptions = TaskUpdateOptions;
|
|
4996
|
+
type TaskRecord = Omit<DecryptedUserTask, "encrypted">;
|
|
4916
4997
|
interface SdkSessionResponse {
|
|
4917
4998
|
user?: {
|
|
4918
4999
|
id?: string;
|
|
@@ -4934,6 +5015,12 @@ interface EmbedKeyRecord {
|
|
|
4934
5015
|
encrypted_embed_key?: string;
|
|
4935
5016
|
[key: string]: unknown;
|
|
4936
5017
|
}
|
|
5018
|
+
interface ChatKeyWrapperRecord {
|
|
5019
|
+
hashed_chat_id?: string;
|
|
5020
|
+
key_type?: string;
|
|
5021
|
+
encrypted_chat_key?: string;
|
|
5022
|
+
[key: string]: unknown;
|
|
5023
|
+
}
|
|
4937
5024
|
interface FocusModeSelection {
|
|
4938
5025
|
appId: string;
|
|
4939
5026
|
focusModeId: string;
|
|
@@ -4991,8 +5078,9 @@ declare class OpenMates {
|
|
|
4991
5078
|
masterKey(): Promise<Uint8Array>;
|
|
4992
5079
|
sdkSession(): Promise<SdkSessionResponse>;
|
|
4993
5080
|
resolveEmbedKeyForShare(embedKeys: EmbedKeyRecord[], embedId: string): Promise<Uint8Array | null>;
|
|
4994
|
-
decryptChatMetadata<T extends EncryptedChatMetadata>(chat: T): Promise<T>;
|
|
5081
|
+
decryptChatMetadata<T extends EncryptedChatMetadata>(chat: T, chatKeyWrappers?: ChatKeyWrapperRecord[]): Promise<T>;
|
|
4995
5082
|
decryptLoadedChatPayload<T extends Record<string, unknown>>(payload: T): Promise<T>;
|
|
5083
|
+
private resolveLoadedChatKey;
|
|
4996
5084
|
private decryptLoadedChatEmbeds;
|
|
4997
5085
|
private resolveLoadedEmbedKey;
|
|
4998
5086
|
private requestWithMethod;
|
|
@@ -5147,14 +5235,35 @@ declare class OpenMatesProjects {
|
|
|
5147
5235
|
declare class OpenMatesTasks {
|
|
5148
5236
|
private readonly client;
|
|
5149
5237
|
constructor(client: OpenMates);
|
|
5150
|
-
list(filters?:
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
startAI(
|
|
5238
|
+
list(filters?: TaskListFilters): Promise<TaskRecord[]>;
|
|
5239
|
+
listDecrypted(filters?: TaskListFilters): Promise<TaskRecord[]>;
|
|
5240
|
+
show(id: string, filters?: TaskListFilters): Promise<TaskRecord>;
|
|
5241
|
+
create(input: TaskPlainCreateOptions): Promise<TaskRecord>;
|
|
5242
|
+
update(id: string, input: TaskPlainUpdateOptions, filters?: TaskListFilters): Promise<TaskRecord>;
|
|
5243
|
+
edit(id: string, input: TaskPlainUpdateOptions, filters?: TaskListFilters): Promise<TaskRecord>;
|
|
5244
|
+
start(id: string, filters?: TaskListFilters): Promise<TaskRecord>;
|
|
5245
|
+
startAI(id: string, filters?: TaskListFilters): Promise<TaskRecord>;
|
|
5246
|
+
delete(id: string, options?: ConfirmedMutationOptions & {
|
|
5247
|
+
filters?: TaskListFilters;
|
|
5248
|
+
}): Promise<{
|
|
5249
|
+
deleted?: boolean;
|
|
5250
|
+
task_id?: string;
|
|
5251
|
+
}>;
|
|
5252
|
+
done(id: string, filters?: TaskListFilters): Promise<TaskRecord>;
|
|
5253
|
+
complete(id: string, filters?: TaskListFilters): Promise<TaskRecord>;
|
|
5254
|
+
block(id: string, reason: string, filters?: TaskListFilters): Promise<TaskRecord>;
|
|
5255
|
+
unblock(id: string, filters?: TaskListFilters): Promise<TaskRecord>;
|
|
5256
|
+
skip(id: string, filters?: TaskListFilters): Promise<TaskRecord>;
|
|
5257
|
+
reorder(id: string, move: Omit<UserTaskReorderInput["moves"][number], "task_id" | "version">, filters?: TaskListFilters): Promise<TaskRecord[]>;
|
|
5258
|
+
move(id: string, move: Omit<UserTaskReorderInput["moves"][number], "task_id" | "version">, filters?: TaskListFilters): Promise<TaskRecord[]>;
|
|
5259
|
+
private listRaw;
|
|
5260
|
+
private createRaw;
|
|
5261
|
+
private updateRaw;
|
|
5262
|
+
private startAIRaw;
|
|
5263
|
+
private listInternal;
|
|
5264
|
+
private resolve;
|
|
5265
|
+
private actionRaw;
|
|
5266
|
+
private actionById;
|
|
5158
5267
|
}
|
|
5159
5268
|
declare class OpenMatesPlans {
|
|
5160
5269
|
private readonly client;
|
|
@@ -5324,4 +5433,4 @@ type AssistantFeedbackDecision = {
|
|
|
5324
5433
|
};
|
|
5325
5434
|
declare function buildAssistantFeedbackDecision(rating: number): AssistantFeedbackDecision;
|
|
5326
5435
|
|
|
5327
|
-
export { APP_SKILL_METADATA, ASSISTANT_FEEDBACK_REPORT_TITLE, ASSISTANT_FEEDBACK_THANKS, type ApiKeyCreateOptions, type ApiKeyCreateResult, type ApiKeyRecord, type AssistantFeedbackDecision, type AuthMethodsStatus, type AuthoritativeChatReconciliation, type BackupCodesResult, type BankTransferOrderDetails, type BankTransferStatus, type CachedChat, type CachedNewChatSuggestion, type ChatCreateOptions, type ChatListOptions, type ChatListPage, type ChatResponse, type CliSignupResult, type DecryptedDraft, type DecryptedEmbed, type DecryptedMemoryEntry, type DecryptedMessage, type DecryptedNewChatSuggestion, type DocsFile, type DocsFolder, type DocsSearchResult, type DocsTree, type DraftRecord, type EncryptedChatMetadata, type EncryptedDraft, type EncryptedDraftRecord, type FocusModeSelection, type GiftCardBankTransferStatus, INTEREST_TAG_IDS, type InterestTagId, MATE_NAMES, MEMORY_TYPE_REGISTRY, type MemoryFieldDef, type MemoryTypeDef, OpenMates, OpenMatesApiError, OpenMatesClient, type OpenMatesClientOptions, OpenMatesConfigError, type OpenMatesOptions, type OpenMatesSession, type ProjectSourceCapability, type ProjectSourceCreateInput, type ProjectSourceRecord, type ProjectSourceStatus, type ProjectSourceType, SUPPORT_URL, type SyncCache, type TopicPreferencesPayload, type TotpSetupStartResult, type WorkflowCapability, type WorkflowDetail, type WorkflowEdge, type WorkflowGraph, type WorkflowNode, type WorkflowNodeRun, type WorkflowNodeType, type WorkflowRunContentRetention, type WorkflowRunContentStorage, type WorkflowRunDetail, type WorkflowSummary, buildAssistantFeedbackDecision, defaultCloneBranchForVersion, deriveAppUrl, normalizeInterestTagIds, reconcileAuthoritativeChats, renderSupportInfo };
|
|
5436
|
+
export { APP_SKILL_METADATA, ASSISTANT_FEEDBACK_REPORT_TITLE, ASSISTANT_FEEDBACK_THANKS, type ApiKeyCreateOptions, type ApiKeyCreateResult, type ApiKeyRecord, type AssistantFeedbackDecision, type AuthMethodsStatus, type AuthoritativeChatReconciliation, type BackupCodesResult, type BankTransferOrderDetails, type BankTransferStatus, type CachedChat, type CachedNewChatSuggestion, type ChatCreateOptions, type ChatListOptions, type ChatListPage, type ChatResponse, type CliSignupResult, type DecryptedDraft, type DecryptedEmbed, type DecryptedMemoryEntry, type DecryptedMessage, type DecryptedNewChatSuggestion, type DecryptedUserTask, type DocsFile, type DocsFolder, type DocsSearchResult, type DocsTree, type DraftRecord, type EncryptedChatMetadata, type EncryptedDraft, type EncryptedDraftRecord, type FocusModeSelection, type GiftCardBankTransferStatus, INTEREST_TAG_IDS, type InterestTagId, MATE_NAMES, MEMORY_TYPE_REGISTRY, type MemoryFieldDef, type MemoryTypeDef, OpenMates, OpenMatesApiError, OpenMatesClient, type OpenMatesClientOptions, OpenMatesConfigError, type OpenMatesOptions, type OpenMatesSession, type ProjectSourceCapability, type ProjectSourceCreateInput, type ProjectSourceRecord, type ProjectSourceStatus, type ProjectSourceType, SUPPORT_URL, type SyncCache, type TaskListFilters, type TaskPlainCreateOptions, type TaskPlainUpdateOptions, type TaskRecord, type TopicPreferencesPayload, type TotpSetupStartResult, type WorkflowCapability, type WorkflowDetail, type WorkflowEdge, type WorkflowGraph, type WorkflowNode, type WorkflowNodeRun, type WorkflowNodeType, type WorkflowRunContentRetention, type WorkflowRunContentStorage, type WorkflowRunDetail, type WorkflowSummary, buildAssistantFeedbackDecision, defaultCloneBranchForVersion, deriveAppUrl, normalizeInterestTagIds, reconcileAuthoritativeChats, renderSupportInfo };
|
package/dist/index.js
CHANGED