openmates 0.27.0-alpha.29 → 0.27.0-alpha.30
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-EPROIPGH.js → chunk-FRFIWC3S.js} +1065 -415
- package/dist/{cli-CpMY_IwJ.d.ts → cli-8Cout9Au.d.ts} +27 -2
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/fixtures/privacy-runtime/linux-arm64/libggml-base.so +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml-base.so.0 +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml-base.so.0.15.1 +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml-cpu.so +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml-cpu.so.0 +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml-cpu.so.0.15.1 +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml.so +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml.so.0 +0 -0
- package/fixtures/privacy-runtime/linux-arm64/libggml.so.0.15.1 +0 -0
- package/fixtures/privacy-runtime/linux-arm64/manifest.json +9 -9
- package/package.json +1 -1
|
@@ -10054,6 +10054,24 @@ function getClientMessagesVersionForSync(cached) {
|
|
|
10054
10054
|
const messagesVersion = typeof cached.details.messages_v === "number" ? cached.details.messages_v : 0;
|
|
10055
10055
|
return Math.min(messagesVersion, cached.messages.length);
|
|
10056
10056
|
}
|
|
10057
|
+
function mergeConcurrentChatMessages(cache, latest) {
|
|
10058
|
+
const byId = new Map(latest?.chats.map((chat) => [String(chat.details.id), chat]));
|
|
10059
|
+
const chatHashes = new Set(cache.chats.map((chat) => computeSHA256(String(chat.details.id))));
|
|
10060
|
+
const embedIds = new Set(cache.embeds.map((embed) => String(embed.embed_id ?? embed.id)));
|
|
10061
|
+
const addedEmbeds = (latest?.embeds ?? []).filter((embed) => !embedIds.has(String(embed.embed_id ?? embed.id)) && (!embed.hashed_chat_id || chatHashes.has(String(embed.hashed_chat_id))));
|
|
10062
|
+
const keyIds = new Set(cache.embedKeys.map((key) => String(key.id ?? key.encrypted_embed_key)));
|
|
10063
|
+
const embedHashes = new Set([...cache.embeds, ...addedEmbeds].map((embed) => computeSHA256(String(embed.embed_id ?? embed.id))));
|
|
10064
|
+
return {
|
|
10065
|
+
...cache,
|
|
10066
|
+
...latest && "tuiContinueCiphertext" in latest ? { tuiContinueCiphertext: latest.tuiContinueCiphertext } : {},
|
|
10067
|
+
embeds: [...cache.embeds, ...addedEmbeds],
|
|
10068
|
+
embedKeys: [...cache.embedKeys, ...(latest?.embedKeys ?? []).filter((key) => !keyIds.has(String(key.id ?? key.encrypted_embed_key)) && embedHashes.has(String(key.hashed_embed_id)))],
|
|
10069
|
+
chats: cache.chats.map((chat) => {
|
|
10070
|
+
const newer = byId.get(String(chat.details.id));
|
|
10071
|
+
return newer && newer.details.messages_v === chat.details.messages_v && newer.details.encrypted_chat_key === chat.details.encrypted_chat_key && newer.messages.length > chat.messages.length ? { ...chat, messages: newer.messages } : chat;
|
|
10072
|
+
})
|
|
10073
|
+
};
|
|
10074
|
+
}
|
|
10057
10075
|
function findCliMessageBoundaryIndex(messages, messageId) {
|
|
10058
10076
|
const index = messages.findIndex((message) => message.id === messageId || message.id.startsWith(messageId));
|
|
10059
10077
|
if (index < 0) {
|
|
@@ -11894,7 +11912,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
11894
11912
|
if (!userId) {
|
|
11895
11913
|
throw new Error("Could not resolve current user id for local connected-account connector.");
|
|
11896
11914
|
}
|
|
11897
|
-
const { createHash:
|
|
11915
|
+
const { createHash: createHash31 } = await import("crypto");
|
|
11898
11916
|
const accountId = randomUUID9();
|
|
11899
11917
|
const masterKey = this.getMasterKeyBytes();
|
|
11900
11918
|
const encryptLocalConnectorValue = async (value) => {
|
|
@@ -11903,9 +11921,9 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
11903
11921
|
};
|
|
11904
11922
|
const payload = {
|
|
11905
11923
|
id: accountId,
|
|
11906
|
-
hashed_user_id:
|
|
11924
|
+
hashed_user_id: createHash31("sha256").update(userId).digest("hex"),
|
|
11907
11925
|
encrypted_provider_type: await encryptLocalConnectorValue(input.provider_id),
|
|
11908
|
-
provider_type_hash:
|
|
11926
|
+
provider_type_hash: createHash31("sha256").update(input.provider_id).digest("hex"),
|
|
11909
11927
|
encrypted_account_label: await encryptLocalConnectorValue(input.label),
|
|
11910
11928
|
encrypted_capabilities: await encryptLocalConnectorValue(input.capabilities),
|
|
11911
11929
|
encrypted_app_permissions: await encryptLocalConnectorValue({
|
|
@@ -12783,7 +12801,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
12783
12801
|
const cache = await this.ensureSynced(options.forceRefresh === true, [], options, false, options.onSyncedChats ? async (synced) => {
|
|
12784
12802
|
const syncedPage = await this.decryptChatListPage(synced, limit, page, options, teamId, masterKey);
|
|
12785
12803
|
options.signal?.throwIfAborted();
|
|
12786
|
-
saveSyncCache({ ...synced, syncedAt: 0 }, teamId);
|
|
12804
|
+
saveSyncCache(mergeConcurrentChatMessages({ ...synced, syncedAt: 0 }, loadSyncCache(teamId)), teamId);
|
|
12787
12805
|
options.onSyncedChats?.(syncedPage);
|
|
12788
12806
|
} : void 0, options.signal);
|
|
12789
12807
|
return this.decryptChatListPage(cache, limit, page, options, teamId, masterKey);
|
|
@@ -13148,6 +13166,15 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
13148
13166
|
}
|
|
13149
13167
|
return drafts;
|
|
13150
13168
|
}
|
|
13169
|
+
async getCachedDraft(chatId, options = {}) {
|
|
13170
|
+
const teamId = this.resolveTeamContext(options);
|
|
13171
|
+
const masterKey = Buffer.from(this.getMasterKeyBytes());
|
|
13172
|
+
if (teamId && !loadLocalTeamKey(this.requireSession().hashedEmail, teamId)) return null;
|
|
13173
|
+
const chat = loadSyncCache(teamId)?.chats.find((entry) => String(entry.details.id ?? "") === chatId);
|
|
13174
|
+
const draft = chat ? await this.decryptCachedDraft(chat) : null;
|
|
13175
|
+
if (!this.hasSession() || teamId !== this.resolveTeamContext(options) || !masterKey.equals(Buffer.from(this.getMasterKeyBytes()))) throw new Error("Chat workspace changed");
|
|
13176
|
+
return draft;
|
|
13177
|
+
}
|
|
13151
13178
|
async getDraft(chatId, forceRefresh = false) {
|
|
13152
13179
|
if (forceRefresh) {
|
|
13153
13180
|
let response;
|
|
@@ -13479,24 +13506,71 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
13479
13506
|
/** Get decrypted messages for a chat resolved by UUID, prefix or title. */
|
|
13480
13507
|
async getChatMessages(query, options = {}) {
|
|
13481
13508
|
const teamId = this.resolveTeamContext(options);
|
|
13482
|
-
|
|
13483
|
-
const
|
|
13484
|
-
|
|
13485
|
-
|
|
13509
|
+
const masterKey = Buffer.from(this.getMasterKeyBytes());
|
|
13510
|
+
const localCache = options.preferCache ? loadSyncCache(teamId) : null;
|
|
13511
|
+
let cache = localCache ?? (options.preferCache ? {
|
|
13512
|
+
syncedAt: 0,
|
|
13513
|
+
totalChatCount: 0,
|
|
13514
|
+
loadedChatCount: 0,
|
|
13515
|
+
chats: [],
|
|
13516
|
+
embeds: [],
|
|
13517
|
+
embedKeys: []
|
|
13518
|
+
} : await this.ensureSynced(true, [], options));
|
|
13519
|
+
const current = () => {
|
|
13520
|
+
if (!this.hasSession() || teamId !== this.resolveTeamContext(options) || !masterKey.equals(Buffer.from(this.getMasterKeyBytes()))) throw new Error("Chat workspace changed");
|
|
13521
|
+
};
|
|
13522
|
+
const localTeamKey = options.preferCache && teamId ? loadLocalTeamKey(this.requireSession().hashedEmail, teamId) : null;
|
|
13523
|
+
if (options.preferCache && teamId && !localTeamKey) throw new Error("Team key unavailable offline. Reconnect to refresh Team access.");
|
|
13524
|
+
const wrappingKey = localTeamKey ? base64ToBytes(localTeamKey) : await this.getChatWrappingKey(teamId, masterKey);
|
|
13525
|
+
let found;
|
|
13526
|
+
let fetchedMetadata = false;
|
|
13527
|
+
try {
|
|
13528
|
+
found = await this.resolveCachedChatForQuery(query, cache, wrappingKey, teamId);
|
|
13529
|
+
} catch (error) {
|
|
13530
|
+
if (!options.preferCache || !(error instanceof Error) || !/^Chat '.*' not found\./.test(error.message)) throw error;
|
|
13531
|
+
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(query)) throw error;
|
|
13532
|
+
const response = await this.http.post(
|
|
13533
|
+
this.appendTeamQuery("/v1/chats/metadata/batch", options),
|
|
13534
|
+
{ chat_ids: [query] },
|
|
13535
|
+
this.getCliRequestHeaders()
|
|
13536
|
+
);
|
|
13537
|
+
current();
|
|
13538
|
+
if (!response.ok) throw new Error(`Chat metadata failed with HTTP ${response.status}`);
|
|
13539
|
+
const details = response.data.chats.find((chat) => String(chat.id ?? "") === query);
|
|
13540
|
+
if (!details) throw error;
|
|
13541
|
+
found = { details, messages: [] };
|
|
13542
|
+
fetchedMetadata = true;
|
|
13543
|
+
cache = { ...cache, chats: [...cache.chats, found], chatKeyWrappers: [
|
|
13544
|
+
...cache.chatKeyWrappers ?? [],
|
|
13545
|
+
...Array.isArray(details.chat_key_wrappers) ? details.chat_key_wrappers : []
|
|
13546
|
+
] };
|
|
13547
|
+
}
|
|
13486
13548
|
const foundChatId = String(found.details.id ?? "");
|
|
13487
|
-
if (foundChatId && getClientMessagesVersionForSync(found) === 0) {
|
|
13549
|
+
if (!options.preferCache && foundChatId && getClientMessagesVersionForSync(found) === 0) {
|
|
13488
13550
|
cache = await this.ensureSynced(true, [foundChatId], options, true);
|
|
13489
13551
|
found = cache.chats.find((c) => String(c.details.id ?? "") === foundChatId) ?? found;
|
|
13490
13552
|
}
|
|
13491
13553
|
const chatItem = await this.decryptChatListItem(found, wrappingKey, cache, teamId);
|
|
13492
13554
|
const chatKeyBytes = await this.resolveChatKey(cache, found, wrappingKey, teamId);
|
|
13555
|
+
if (!chatKeyBytes && (found.details.encrypted_chat_key || found.messages.length || Number(found.details.messages_v) > 0)) throw new Error("Chat key unavailable. Use /refresh to retry.");
|
|
13556
|
+
const persistMessages = (messages2) => {
|
|
13557
|
+
current();
|
|
13558
|
+
options.signal?.throwIfAborted();
|
|
13559
|
+
const latest = loadSyncCache(teamId) ?? cache;
|
|
13560
|
+
const row = latest.chats.find((chat) => String(chat.details.id) === foundChatId);
|
|
13561
|
+
if (row && (row.details.messages_v !== found.details.messages_v || row.details.encrypted_chat_key !== found.details.encrypted_chat_key)) return;
|
|
13562
|
+
if (!row && localCache?.chats.some((chat) => String(chat.details.id) === foundChatId)) return;
|
|
13563
|
+
const merged = { ...latest, chats: row ? latest.chats.map((chat) => chat === row ? { ...row, messages: messages2 } : chat) : [...latest.chats, { ...found, messages: messages2 }] };
|
|
13564
|
+
saveSyncCache(mergeConcurrentChatMessages(merged, latest), teamId);
|
|
13565
|
+
};
|
|
13493
13566
|
let rawMessages = found.messages;
|
|
13567
|
+
let historyIncomplete = rawMessages.length > 0 && Number(found.details.messages_v) > rawMessages.length;
|
|
13494
13568
|
const hasServerMessages = typeof found.details.messages_v === "number" && found.details.messages_v > 0;
|
|
13495
|
-
if (rawMessages.length === 0 && hasServerMessages && foundChatId) {
|
|
13569
|
+
if (rawMessages.length === 0 && (hasServerMessages || fetchedMetadata) && foundChatId) {
|
|
13496
13570
|
const pages = [];
|
|
13497
13571
|
let cursor = null;
|
|
13498
13572
|
let hasMoreBefore = true;
|
|
13499
|
-
for (let page = 0; page < CLI_MESSAGE_HISTORY_MAX_PAGES && hasMoreBefore; page += 1) {
|
|
13573
|
+
for (let page = 0; page < Math.max(1, Math.min(CLI_MESSAGE_HISTORY_MAX_PAGES, options.maxHistoryPages ?? CLI_MESSAGE_HISTORY_MAX_PAGES)) && hasMoreBefore; page += 1) {
|
|
13500
13574
|
const queryParams = new URLSearchParams({
|
|
13501
13575
|
direction: cursor ? "before" : "latest",
|
|
13502
13576
|
limit: String(CLI_MESSAGE_HISTORY_PAGE_LIMIT),
|
|
@@ -13506,21 +13580,58 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
13506
13580
|
queryParams.set("before_timestamp", String(cursor.created_at));
|
|
13507
13581
|
queryParams.set("before_message_id", cursor.message_id);
|
|
13508
13582
|
}
|
|
13509
|
-
|
|
13510
|
-
|
|
13511
|
-
|
|
13512
|
-
|
|
13583
|
+
options.signal?.throwIfAborted();
|
|
13584
|
+
let response;
|
|
13585
|
+
try {
|
|
13586
|
+
response = await this.http.get(
|
|
13587
|
+
this.appendTeamQuery(`/v1/chats/${encodeURIComponent(foundChatId)}/messages/window?${queryParams.toString()}`, { teamId }),
|
|
13588
|
+
this.getCliRequestHeaders()
|
|
13589
|
+
);
|
|
13590
|
+
} catch (error) {
|
|
13591
|
+
if (!options.preferCache || !pages.length) throw error;
|
|
13592
|
+
historyIncomplete = true;
|
|
13593
|
+
break;
|
|
13594
|
+
}
|
|
13595
|
+
current();
|
|
13596
|
+
options.signal?.throwIfAborted();
|
|
13513
13597
|
if (!response.ok) throw new Error(`Chat messages failed with HTTP ${response.status}`);
|
|
13514
13598
|
const pageMessages = Array.isArray(response.data.messages) ? normalizeSyncedMessages(response.data.messages) : [];
|
|
13515
13599
|
if (pageMessages.length === 0) break;
|
|
13600
|
+
if (page === 0 && options.onMessages) {
|
|
13601
|
+
const latest = await this.decryptRawChatMessages(pageMessages, chatItem, chatKeyBytes, cache.embeds);
|
|
13602
|
+
current();
|
|
13603
|
+
if (options.preferCache) persistMessages(pageMessages);
|
|
13604
|
+
options.onMessages({ chat: chatItem, messages: latest });
|
|
13605
|
+
}
|
|
13516
13606
|
pages.unshift(pageMessages);
|
|
13517
13607
|
cursor = response.data.start_cursor ?? null;
|
|
13518
13608
|
hasMoreBefore = response.data.has_more_before === true && cursor !== null;
|
|
13519
13609
|
}
|
|
13520
13610
|
rawMessages = pages.flat();
|
|
13611
|
+
historyIncomplete ||= hasMoreBefore;
|
|
13521
13612
|
}
|
|
13522
13613
|
const messages = await this.decryptRawChatMessages(rawMessages, chatItem, chatKeyBytes, cache.embeds);
|
|
13523
|
-
|
|
13614
|
+
current();
|
|
13615
|
+
if (options.preferCache && rawMessages !== found.messages) persistMessages(rawMessages);
|
|
13616
|
+
return { chat: chatItem, messages, ...historyIncomplete ? { historyIncomplete: true } : {} };
|
|
13617
|
+
}
|
|
13618
|
+
/** Warm the latest recent windows in the background; only ciphertext reaches disk. */
|
|
13619
|
+
async cacheRecentChatMessages(options = {}) {
|
|
13620
|
+
const teamId = this.resolveTeamContext(options), masterKey = Buffer.from(this.getMasterKeyBytes());
|
|
13621
|
+
const recent2 = (loadSyncCache(teamId)?.chats ?? []).sort((a, b) => Number(b.details.last_edited_overall_timestamp ?? 0) - Number(a.details.last_edited_overall_timestamp ?? 0)).slice(0, 20).filter((chat) => Number(chat.details.messages_v) > 0 && chat.messages.length === 0);
|
|
13622
|
+
let next = 0;
|
|
13623
|
+
await Promise.all(Array.from({ length: Math.min(3, recent2.length) }, async () => {
|
|
13624
|
+
while (next < recent2.length) {
|
|
13625
|
+
options.signal?.throwIfAborted();
|
|
13626
|
+
if (!this.hasSession() || teamId !== this.resolveTeamContext(options) || !masterKey.equals(Buffer.from(this.getMasterKeyBytes()))) throw new Error("Chat workspace changed");
|
|
13627
|
+
const chat = recent2[next++];
|
|
13628
|
+
try {
|
|
13629
|
+
await this.getChatMessages(String(chat.details.id), { ...options, preferCache: true, maxHistoryPages: 1 });
|
|
13630
|
+
} catch {
|
|
13631
|
+
options.signal?.throwIfAborted();
|
|
13632
|
+
}
|
|
13633
|
+
}
|
|
13634
|
+
}));
|
|
13524
13635
|
}
|
|
13525
13636
|
async generateExistingAssistantSpeech(query, selection, options = {}) {
|
|
13526
13637
|
const { chat, messages } = await this.getChatMessages(query, options);
|
|
@@ -13793,23 +13904,81 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
13793
13904
|
*
|
|
13794
13905
|
* hashed_embed_id in the key table = SHA-256(embed.embed_id).
|
|
13795
13906
|
*/
|
|
13796
|
-
async getEmbed(embedIdOrShort) {
|
|
13797
|
-
const
|
|
13798
|
-
const
|
|
13799
|
-
|
|
13907
|
+
async getEmbed(embedIdOrShort, options = {}) {
|
|
13908
|
+
const teamId = this.resolveTeamContext(options), masterKey = Buffer.from(this.getMasterKeyBytes());
|
|
13909
|
+
const current = () => {
|
|
13910
|
+
if (!this.hasSession() || teamId !== this.resolveTeamContext(options) || !masterKey.equals(Buffer.from(this.getMasterKeyBytes()))) throw new Error("Embed workspace changed");
|
|
13911
|
+
};
|
|
13912
|
+
let cache = options.preferCache ? loadSyncCache(teamId) : await this.ensureSynced(false, [], options);
|
|
13913
|
+
cache ??= { syncedAt: 0, totalChatCount: 0, loadedChatCount: 0, chats: [], embeds: [], embedKeys: [] };
|
|
13914
|
+
const localTeamKey = options.preferCache && teamId ? loadLocalTeamKey(this.requireSession().hashedEmail, teamId) : null;
|
|
13915
|
+
if (options.preferCache && teamId && !localTeamKey) throw new Error("Team key unavailable offline.");
|
|
13916
|
+
const wrappingKey = localTeamKey ? base64ToBytes(localTeamKey) : await this.getChatWrappingKey(teamId, masterKey);
|
|
13917
|
+
let embed = cache.embeds.find(
|
|
13800
13918
|
(e) => String(e.embed_id ?? "").startsWith(embedIdOrShort) || String(e.id ?? "").startsWith(embedIdOrShort)
|
|
13801
13919
|
);
|
|
13920
|
+
let fetched = false;
|
|
13921
|
+
const fetchedIds = /* @__PURE__ */ new Set(), fetchedKeyIds = /* @__PURE__ */ new Set();
|
|
13922
|
+
const wrapperId = (key) => `${key.hashed_embed_id}:${key.key_type}:${key.hashed_chat_id ?? ""}`;
|
|
13923
|
+
const targetId = embed ? String(embed.embed_id ?? embed.id) : embedIdOrShort;
|
|
13924
|
+
const cachedKey = options.preferCache && embed ? await this.resolveEmbedKey(cache, wrappingKey, embed, targetId, computeSHA256(targetId)) : null;
|
|
13925
|
+
if ((!embed || !cachedKey) && options.preferCache && /^[0-9a-f-]{36}$/i.test(targetId)) {
|
|
13926
|
+
if (teamId && !options.chatId) throw new Error("Open the original Team chat to load this embed.");
|
|
13927
|
+
const { ws } = await this.openWsClient({ taskUpdateJobs: false });
|
|
13928
|
+
try {
|
|
13929
|
+
let wanted = targetId;
|
|
13930
|
+
const visited = /* @__PURE__ */ new Set();
|
|
13931
|
+
while (wanted && !visited.has(wanted) && visited.size < 8) {
|
|
13932
|
+
visited.add(wanted);
|
|
13933
|
+
const pending = ws.waitForMessage("send_embed_data", (payload) => {
|
|
13934
|
+
const row2 = payload, nested = row2.payload ?? row2;
|
|
13935
|
+
return nested.embed_id === wanted;
|
|
13936
|
+
}, 1e4);
|
|
13937
|
+
await ws.sendAsync("request_embed", { embed_id: wanted, ...teamId ? { team_id: teamId, chat_id: options.chatId } : {} });
|
|
13938
|
+
const envelope = (await pending).payload, row = envelope.payload ?? envelope;
|
|
13939
|
+
current();
|
|
13940
|
+
if (row.already_encrypted !== true || typeof row.content !== "string") throw new Error("Saved embed ciphertext is unavailable. Open its original chat and /refresh.");
|
|
13941
|
+
const encrypted = {
|
|
13942
|
+
embed_id: wanted,
|
|
13943
|
+
encrypted_type: row.type,
|
|
13944
|
+
encrypted_content: row.content,
|
|
13945
|
+
encrypted_text_preview: row.encrypted_text_preview,
|
|
13946
|
+
created_at: row.createdAt,
|
|
13947
|
+
updated_at: row.updatedAt,
|
|
13948
|
+
hashed_chat_id: typeof row.chat_id === "string" ? /^[0-9a-f]{64}$/i.test(row.chat_id) ? row.chat_id : computeSHA256(row.chat_id) : void 0,
|
|
13949
|
+
parent_embed_id: row.parent_embed_id,
|
|
13950
|
+
status: row.status
|
|
13951
|
+
};
|
|
13952
|
+
const wrappers = Array.isArray(row.embed_keys) ? row.embed_keys : [];
|
|
13953
|
+
fetchedIds.add(wanted);
|
|
13954
|
+
for (const wrapper of wrappers) fetchedKeyIds.add(wrapperId(wrapper));
|
|
13955
|
+
cache = {
|
|
13956
|
+
...cache,
|
|
13957
|
+
embeds: [...cache.embeds.filter((e) => String(e.embed_id ?? e.id) !== wanted), encrypted],
|
|
13958
|
+
embedKeys: [...cache.embedKeys.filter((key) => !wrappers.some((wrapper) => wrapperId(wrapper) === wrapperId(key))), ...wrappers]
|
|
13959
|
+
};
|
|
13960
|
+
fetched = true;
|
|
13961
|
+
const parent = typeof row.parent_embed_id === "string" ? row.parent_embed_id : "";
|
|
13962
|
+
const parentEmbed2 = cache.embeds.find((e) => String(e.embed_id ?? e.id) === parent);
|
|
13963
|
+
const parentKey = parentEmbed2 ? await this.resolveEmbedKey(cache, wrappingKey, parentEmbed2, parent, computeSHA256(parent)) : null;
|
|
13964
|
+
wanted = parent && !parentKey ? parent : "";
|
|
13965
|
+
}
|
|
13966
|
+
embed = cache.embeds.find((e) => String(e.embed_id ?? e.id) === targetId);
|
|
13967
|
+
} finally {
|
|
13968
|
+
ws.close();
|
|
13969
|
+
}
|
|
13970
|
+
}
|
|
13802
13971
|
if (!embed) {
|
|
13803
13972
|
throw new Error(
|
|
13804
13973
|
`Embed '${embedIdOrShort}' not found in local cache. Run 'openmates chats list' to sync first.`
|
|
13805
13974
|
);
|
|
13806
13975
|
}
|
|
13807
13976
|
const embedId = String(embed.embed_id ?? embed.id ?? "");
|
|
13808
|
-
const { createHash:
|
|
13809
|
-
const hashedEmbedId =
|
|
13977
|
+
const { createHash: createHash31 } = await import("crypto");
|
|
13978
|
+
const hashedEmbedId = createHash31("sha256").update(embedId).digest("hex");
|
|
13810
13979
|
const embedKeyBytes = await this.resolveEmbedKey(
|
|
13811
13980
|
cache,
|
|
13812
|
-
|
|
13981
|
+
wrappingKey,
|
|
13813
13982
|
embed,
|
|
13814
13983
|
embedId,
|
|
13815
13984
|
hashedEmbedId
|
|
@@ -13824,7 +13993,19 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
13824
13993
|
let content = null;
|
|
13825
13994
|
const rawContent = await decryptField2("encrypted_content");
|
|
13826
13995
|
if (rawContent) content = parseEmbedContentObject(rawContent);
|
|
13827
|
-
|
|
13996
|
+
if (options.preferCache && (!embedKeyBytes || rawContent === null)) throw new Error("Saved embed key or content is unavailable. Use /refresh to retry.");
|
|
13997
|
+
if (!options.preferCache) content = await this.refreshRemotionVideoCreateContent(embedId, content);
|
|
13998
|
+
if (options.preferCache) {
|
|
13999
|
+
current();
|
|
14000
|
+
if (fetched) {
|
|
14001
|
+
const latest = loadSyncCache(teamId) ?? cache;
|
|
14002
|
+
saveSyncCache({
|
|
14003
|
+
...latest,
|
|
14004
|
+
embeds: [...latest.embeds.filter((e) => !fetchedIds.has(String(e.embed_id ?? e.id))), ...cache.embeds.filter((e) => fetchedIds.has(String(e.embed_id ?? e.id)))],
|
|
14005
|
+
embedKeys: [...latest.embedKeys.filter((key) => !fetchedKeyIds.has(wrapperId(key))), ...cache.embedKeys.filter((key) => fetchedKeyIds.has(wrapperId(key)))]
|
|
14006
|
+
}, teamId);
|
|
14007
|
+
}
|
|
14008
|
+
}
|
|
13828
14009
|
const strVal = (v) => typeof v === "string" && v.trim() ? v.trim() : null;
|
|
13829
14010
|
const resolvedType = type ?? strVal(content?.type) ?? null;
|
|
13830
14011
|
const resolvedAppId = typeof embed.app_id === "string" ? embed.app_id : strVal(content?.app_id) ?? null;
|
|
@@ -13908,7 +14089,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
13908
14089
|
async resolveEmbedKey(cache, masterKey, embed, embedId, hashedEmbedId, visited = /* @__PURE__ */ new Set()) {
|
|
13909
14090
|
if (visited.has(embedId)) return null;
|
|
13910
14091
|
visited.add(embedId);
|
|
13911
|
-
const { createHash:
|
|
14092
|
+
const { createHash: createHash31 } = await import("crypto");
|
|
13912
14093
|
const masterKeyEntry = cache.embedKeys.find(
|
|
13913
14094
|
(ek) => ek.hashed_embed_id === hashedEmbedId && String(ek.key_type) === "master"
|
|
13914
14095
|
);
|
|
@@ -13925,23 +14106,14 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
13925
14106
|
if (chatKeyEntry && typeof chatKeyEntry.encrypted_embed_key === "string") {
|
|
13926
14107
|
const hashedChatId = String(chatKeyEntry.hashed_chat_id ?? "");
|
|
13927
14108
|
const owningChat = cache.chats.find((c) => {
|
|
13928
|
-
const chatHash =
|
|
14109
|
+
const chatHash = createHash31("sha256").update(String(c.details.id ?? "")).digest("hex");
|
|
13929
14110
|
return chatHash === hashedChatId;
|
|
13930
14111
|
});
|
|
13931
14112
|
if (owningChat) {
|
|
13932
|
-
const
|
|
13933
|
-
if (
|
|
13934
|
-
const
|
|
13935
|
-
|
|
13936
|
-
masterKey
|
|
13937
|
-
);
|
|
13938
|
-
if (chatKeyBytes) {
|
|
13939
|
-
const key = await decryptBytesWithAesGcm(
|
|
13940
|
-
chatKeyEntry.encrypted_embed_key,
|
|
13941
|
-
chatKeyBytes
|
|
13942
|
-
);
|
|
13943
|
-
if (key) return key;
|
|
13944
|
-
}
|
|
14113
|
+
const chatKeyBytes = await this.resolveChatKey(cache, owningChat, masterKey, this.resolveTeamContext());
|
|
14114
|
+
if (chatKeyBytes) {
|
|
14115
|
+
const key = await decryptBytesWithAesGcm(chatKeyEntry.encrypted_embed_key, chatKeyBytes);
|
|
14116
|
+
if (key) return key;
|
|
13945
14117
|
}
|
|
13946
14118
|
}
|
|
13947
14119
|
}
|
|
@@ -13954,7 +14126,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
13954
14126
|
const parentFullId = String(
|
|
13955
14127
|
parentEmbed2.embed_id ?? parentEmbed2.id ?? ""
|
|
13956
14128
|
);
|
|
13957
|
-
const parentHashedId =
|
|
14129
|
+
const parentHashedId = createHash31("sha256").update(parentFullId).digest("hex");
|
|
13958
14130
|
const parentKey = await this.resolveEmbedKey(
|
|
13959
14131
|
cache,
|
|
13960
14132
|
masterKey,
|
|
@@ -19324,6 +19496,35 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
19324
19496
|
);
|
|
19325
19497
|
return legacy.data?.app_settings_memories ?? [];
|
|
19326
19498
|
}
|
|
19499
|
+
async getCachedContinueItems() {
|
|
19500
|
+
const teamId = this.resolveTeamContext(), masterKey = Buffer.from(this.getMasterKeyBytes());
|
|
19501
|
+
const teamKey = teamId ? loadLocalTeamKey(this.requireSession().hashedEmail, teamId) : null;
|
|
19502
|
+
if (teamId && !teamKey) return null;
|
|
19503
|
+
const cache = loadSyncCache(teamId);
|
|
19504
|
+
if (!cache?.tuiContinueCiphertext) return null;
|
|
19505
|
+
const plain = await decryptWithAesGcmCombined(cache.tuiContinueCiphertext, teamKey ? base64ToBytes(teamKey) : masterKey);
|
|
19506
|
+
if (!this.hasSession() || this.resolveTeamContext() !== teamId || !masterKey.equals(Buffer.from(this.getMasterKeyBytes()))) throw new Error("Home workspace changed");
|
|
19507
|
+
if (!plain) return null;
|
|
19508
|
+
const data = JSON.parse(plain);
|
|
19509
|
+
return Array.isArray(data.memories) && Array.isArray(data.reminders) ? data : null;
|
|
19510
|
+
}
|
|
19511
|
+
async getContinueItems() {
|
|
19512
|
+
const teamId = this.resolveTeamContext(), masterKey = Buffer.from(this.getMasterKeyBytes());
|
|
19513
|
+
const [memories, response] = await Promise.all([teamId ? Promise.resolve([]) : this.listMemories({ personal: true }), this.settingsGet("/v1/settings/reminders?include_recent_fired=true&upcoming_hours=24&recent_hours=12")]);
|
|
19514
|
+
const reminderData = response;
|
|
19515
|
+
const teamChats = new Set(loadSyncCache(teamId)?.chats.map((chat) => String(chat.details.id)) ?? []);
|
|
19516
|
+
const reminders = reminderData.success && Array.isArray(reminderData.reminders) ? reminderData.reminders : [];
|
|
19517
|
+
const data = {
|
|
19518
|
+
memories: memories.filter((memory) => typeof memory.data.embed_id === "string"),
|
|
19519
|
+
reminders: teamId ? reminders.filter((reminder) => teamChats.has(String(reminder.target_chat_id))) : reminders
|
|
19520
|
+
};
|
|
19521
|
+
const wrappingKey = await this.getChatWrappingKey(teamId, masterKey);
|
|
19522
|
+
const tuiContinueCiphertext = await encryptWithAesGcmCombined(JSON.stringify(data), wrappingKey);
|
|
19523
|
+
if (!this.hasSession() || this.resolveTeamContext() !== teamId || !masterKey.equals(Buffer.from(this.getMasterKeyBytes()))) throw new Error("Home workspace changed");
|
|
19524
|
+
const cache = loadSyncCache(teamId) ?? { syncedAt: 0, totalChatCount: 0, loadedChatCount: 0, chats: [], embeds: [], embedKeys: [] };
|
|
19525
|
+
saveSyncCache({ ...cache, tuiContinueCiphertext }, teamId);
|
|
19526
|
+
return data;
|
|
19527
|
+
}
|
|
19327
19528
|
async listMemories(options = {}) {
|
|
19328
19529
|
const masterKey = this.getMasterKeyBytes();
|
|
19329
19530
|
const teamId = this.resolveTeamContext(options);
|
|
@@ -19674,7 +19875,7 @@ Required: ${schema.required.join(", ")}`
|
|
|
19674
19875
|
const session = this.requireSession();
|
|
19675
19876
|
const masterKey = base64ToBytes(session.masterKeyExportedB64);
|
|
19676
19877
|
const cache = await this.ensureSynced();
|
|
19677
|
-
const { createHash:
|
|
19878
|
+
const { createHash: createHash31 } = await import("crypto");
|
|
19678
19879
|
const embed = cache.embeds.find(
|
|
19679
19880
|
(e) => String(e.embed_id ?? "").startsWith(embedIdOrShort) || String(e.id ?? "").startsWith(embedIdOrShort)
|
|
19680
19881
|
);
|
|
@@ -19682,7 +19883,7 @@ Required: ${schema.required.join(", ")}`
|
|
|
19682
19883
|
throw new Error(`Embed '${embedIdOrShort}' not found in local cache.`);
|
|
19683
19884
|
}
|
|
19684
19885
|
const embedId = String(embed.embed_id ?? embed.id ?? "");
|
|
19685
|
-
const hashedEmbedId =
|
|
19886
|
+
const hashedEmbedId = createHash31("sha256").update(embedId).digest("hex");
|
|
19686
19887
|
const embedKeyBytes = await this.resolveEmbedKey(
|
|
19687
19888
|
cache,
|
|
19688
19889
|
masterKey,
|
|
@@ -19849,8 +20050,8 @@ Required: ${schema.required.join(", ")}`
|
|
|
19849
20050
|
if (!embed) {
|
|
19850
20051
|
throw new Error(`Embed '${embedId}' not found in local cache. Run 'openmates chats list' to sync first.`);
|
|
19851
20052
|
}
|
|
19852
|
-
const { createHash:
|
|
19853
|
-
const hashedEmbedId =
|
|
20053
|
+
const { createHash: createHash31 } = await import("crypto");
|
|
20054
|
+
const hashedEmbedId = createHash31("sha256").update(embedId).digest("hex");
|
|
19854
20055
|
const embedKey = await this.resolveEmbedKey(
|
|
19855
20056
|
cache,
|
|
19856
20057
|
masterKey,
|
|
@@ -19981,8 +20182,8 @@ Required: ${schema.required.join(", ")}`
|
|
|
19981
20182
|
if (!embed) {
|
|
19982
20183
|
throw new Error(`Embed '${embedId}' not found in local cache. Run 'openmates chats list' to sync first.`);
|
|
19983
20184
|
}
|
|
19984
|
-
const { createHash:
|
|
19985
|
-
const hashedEmbedId =
|
|
20185
|
+
const { createHash: createHash31 } = await import("crypto");
|
|
20186
|
+
const hashedEmbedId = createHash31("sha256").update(embedId).digest("hex");
|
|
19986
20187
|
const embedKey = await this.resolveEmbedKey(
|
|
19987
20188
|
cache,
|
|
19988
20189
|
masterKey,
|
|
@@ -20308,6 +20509,7 @@ Required: ${schema.required.join(", ")}`
|
|
|
20308
20509
|
async ensureSynced(forceRefresh = false, refreshChatIds = [], options = {}, includeMessageContentRefresh = false, onSyncedCache, signal) {
|
|
20309
20510
|
signal?.throwIfAborted();
|
|
20310
20511
|
const teamId = this.resolveTeamContext(options);
|
|
20512
|
+
const syncMasterKey = Buffer.from(this.getMasterKeyBytes());
|
|
20311
20513
|
const refreshChatIdSet = new Set(refreshChatIds.filter(Boolean));
|
|
20312
20514
|
if (!forceRefresh && refreshChatIdSet.size === 0 && isSyncCacheFresh(3e5, teamId)) {
|
|
20313
20515
|
const cache2 = loadSyncCache(teamId);
|
|
@@ -20509,9 +20711,9 @@ Required: ${schema.required.join(", ")}`
|
|
|
20509
20711
|
chats.splice(0, chats.length, ...reconciledChats);
|
|
20510
20712
|
if (totalChatCount === 0) totalChatCount = chats.length;
|
|
20511
20713
|
if (reconciliation.deleted_chat_ids?.length) {
|
|
20512
|
-
const { createHash:
|
|
20714
|
+
const { createHash: createHash31 } = await import("crypto");
|
|
20513
20715
|
const deletedHashes = new Set(
|
|
20514
|
-
reconciliation.deleted_chat_ids.map((id) =>
|
|
20716
|
+
reconciliation.deleted_chat_ids.map((id) => createHash31("sha256").update(id).digest("hex"))
|
|
20515
20717
|
);
|
|
20516
20718
|
const keptEmbeds = embeds.filter((embed) => !deletedHashes.has(String(embed.hashed_chat_id ?? "")));
|
|
20517
20719
|
const keptKeys = embedKeys.filter((key) => !deletedHashes.has(String(key.hashed_chat_id ?? "")));
|
|
@@ -20600,8 +20802,10 @@ Required: ${schema.required.join(", ")}`
|
|
|
20600
20802
|
chatKeyWrappers,
|
|
20601
20803
|
newChatSuggestions
|
|
20602
20804
|
};
|
|
20603
|
-
|
|
20604
|
-
|
|
20805
|
+
if (!this.hasSession() || teamId !== this.resolveTeamContext(options) || !syncMasterKey.equals(Buffer.from(this.getMasterKeyBytes()))) throw new Error("Chat workspace changed");
|
|
20806
|
+
const mergedCache = mergeConcurrentChatMessages(cache, loadSyncCache(teamId));
|
|
20807
|
+
saveSyncCache(mergedCache, teamId);
|
|
20808
|
+
return mergedCache;
|
|
20605
20809
|
}
|
|
20606
20810
|
/**
|
|
20607
20811
|
* Claim and finish reconnect workflow deliveries using only normal client
|
|
@@ -31860,7 +32064,7 @@ async function flushPendingTaskActivities(client2, teamId, stateDir2 = resolveSt
|
|
|
31860
32064
|
import { existsSync as existsSync24, readFileSync as readFileSync22, realpathSync as realpathSync12, readdirSync as readdirSync13, statSync as statSync11, writeFileSync as writeFileSync15 } from "fs";
|
|
31861
32065
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
31862
32066
|
import { basename as basename9, dirname as dirname17, join as join28 } from "path";
|
|
31863
|
-
import { createHash as
|
|
32067
|
+
import { createHash as createHash30, randomBytes as randomBytes13, randomUUID as randomUUID23 } from "crypto";
|
|
31864
32068
|
import { arch as arch2, platform as platform2 } from "os";
|
|
31865
32069
|
import { parse as parseYaml, parseDocument as parseYamlDocument, stringify as stringifyYaml } from "yaml";
|
|
31866
32070
|
|
|
@@ -32972,6 +33176,120 @@ function prepareUrlEmbeds(message) {
|
|
|
32972
33176
|
|
|
32973
33177
|
// src/embedRenderers.ts
|
|
32974
33178
|
import qrcode2 from "qrcode-terminal";
|
|
33179
|
+
|
|
33180
|
+
// src/tuiText.ts
|
|
33181
|
+
var segments = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
33182
|
+
function stripAnsi(value) {
|
|
33183
|
+
return value.replace(/\x1b(?:\[[0-?]*[ -/]*[@-~]|\][^\x07\x1b]*(?:\x07|\x1b\\))/g, "");
|
|
33184
|
+
}
|
|
33185
|
+
function terminalText(value) {
|
|
33186
|
+
return stripAnsi(value).replace(/[\x00-\x08\x0b-\x1f\x7f-\x9f]/g, "").replace(/\t/g, " ");
|
|
33187
|
+
}
|
|
33188
|
+
function graphemeWidth(value) {
|
|
33189
|
+
if (/^[\p{Mark}\p{Cf}]+$/u.test(value)) return 0;
|
|
33190
|
+
const cp = value.codePointAt(0) ?? 0;
|
|
33191
|
+
if (/\p{Extended_Pictographic}|\p{Regional_Indicator}|\u20e3/u.test(value)) return 2;
|
|
33192
|
+
return cp >= 4352 && (cp <= 4447 || cp === 9001 || cp === 9002 || cp >= 11904 && cp <= 42191 && cp !== 12351 || cp >= 44032 && cp <= 55203 || cp >= 63744 && cp <= 64255 || cp >= 65040 && cp <= 65049 || cp >= 65072 && cp <= 65135 || cp >= 65281 && cp <= 65376 || cp >= 65504 && cp <= 65510 || cp >= 131072 && cp <= 262141) ? 2 : 1;
|
|
33193
|
+
}
|
|
33194
|
+
function cells(value) {
|
|
33195
|
+
return [...segments.segment(stripAnsi(value))].reduce((n, item) => n + graphemeWidth(item.segment), 0);
|
|
33196
|
+
}
|
|
33197
|
+
function truncateCells(value, width, ellipsis = "\u2026") {
|
|
33198
|
+
const clean = terminalText(value).replace(/\n/g, " ");
|
|
33199
|
+
if (cells(clean) <= width) return clean;
|
|
33200
|
+
const available = Math.max(0, width - cells(ellipsis));
|
|
33201
|
+
let result = "", used = 0;
|
|
33202
|
+
for (const { segment } of segments.segment(clean)) {
|
|
33203
|
+
const size = graphemeWidth(segment);
|
|
33204
|
+
if (used + size > available) break;
|
|
33205
|
+
result += segment;
|
|
33206
|
+
used += size;
|
|
33207
|
+
}
|
|
33208
|
+
return width > 0 ? result + (cells(ellipsis) <= width ? ellipsis : "") : "";
|
|
33209
|
+
}
|
|
33210
|
+
function padCells(value, width) {
|
|
33211
|
+
const trimmed = truncateCells(value, width);
|
|
33212
|
+
return trimmed + " ".repeat(Math.max(0, width - cells(trimmed)));
|
|
33213
|
+
}
|
|
33214
|
+
function sliceCells(value, start, width) {
|
|
33215
|
+
start = Math.max(0, Math.floor(start));
|
|
33216
|
+
width = Math.max(0, Math.floor(width));
|
|
33217
|
+
const end = start + width;
|
|
33218
|
+
let position = 0, result = "";
|
|
33219
|
+
for (const { segment } of segments.segment(terminalText(value).replace(/\n/g, " "))) {
|
|
33220
|
+
const size = graphemeWidth(segment), next = position + size;
|
|
33221
|
+
if (next > start && position < end) {
|
|
33222
|
+
result += position >= start && next <= end ? segment : " ".repeat(Math.min(end, next) - Math.max(start, position));
|
|
33223
|
+
}
|
|
33224
|
+
position = next;
|
|
33225
|
+
if (position >= end) break;
|
|
33226
|
+
}
|
|
33227
|
+
return result + " ".repeat(Math.max(0, width - cells(result)));
|
|
33228
|
+
}
|
|
33229
|
+
function wrapCells(value, width) {
|
|
33230
|
+
width = Math.max(1, width);
|
|
33231
|
+
const result = [];
|
|
33232
|
+
for (const line of terminalText(value).split("\n")) {
|
|
33233
|
+
let text7 = "", used = 0;
|
|
33234
|
+
for (const { segment } of segments.segment(line)) {
|
|
33235
|
+
const size = graphemeWidth(segment);
|
|
33236
|
+
if (size > width) {
|
|
33237
|
+
if (text7) result.push(text7);
|
|
33238
|
+
result.push("?");
|
|
33239
|
+
text7 = "";
|
|
33240
|
+
used = 0;
|
|
33241
|
+
continue;
|
|
33242
|
+
}
|
|
33243
|
+
if (used + size > width) {
|
|
33244
|
+
result.push(text7);
|
|
33245
|
+
text7 = "";
|
|
33246
|
+
used = 0;
|
|
33247
|
+
}
|
|
33248
|
+
text7 += segment;
|
|
33249
|
+
used += size;
|
|
33250
|
+
}
|
|
33251
|
+
result.push(text7);
|
|
33252
|
+
}
|
|
33253
|
+
return result;
|
|
33254
|
+
}
|
|
33255
|
+
function eraseGrapheme(value) {
|
|
33256
|
+
const items = [...segments.segment(value)];
|
|
33257
|
+
return items.length ? value.slice(0, items[items.length - 1].index) : "";
|
|
33258
|
+
}
|
|
33259
|
+
function moveGraphemeCursor(value, cursor, direction) {
|
|
33260
|
+
const boundaries = [...segments.segment(value)].map((item) => item.index);
|
|
33261
|
+
boundaries.push(value.length);
|
|
33262
|
+
return direction < 0 ? boundaries.filter((index) => index < cursor).at(-1) ?? 0 : boundaries.find((index) => index > cursor) ?? value.length;
|
|
33263
|
+
}
|
|
33264
|
+
var lineText = (line) => typeof line === "string" ? line : line.text;
|
|
33265
|
+
var rgb = (hex) => [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16));
|
|
33266
|
+
function colorSequence(color, mode, background) {
|
|
33267
|
+
if (mode === "none") return "";
|
|
33268
|
+
if (mode === "truecolor") return `\x1B[${background ? 48 : 38};2;${color.join(";")}m`;
|
|
33269
|
+
if (mode === "ansi256") {
|
|
33270
|
+
const level = (v) => Math.round(v / 255 * 5);
|
|
33271
|
+
return `\x1B[${background ? 48 : 38};5;${16 + 36 * level(color[0]) + 6 * level(color[1]) + level(color[2])}m`;
|
|
33272
|
+
}
|
|
33273
|
+
const [r, g, b] = color;
|
|
33274
|
+
const index = (r > 100 ? 1 : 0) + (g > 100 ? 2 : 0) + (b > 100 ? 4 : 0);
|
|
33275
|
+
return `\x1B[${(background ? 40 : 30) + index}m`;
|
|
33276
|
+
}
|
|
33277
|
+
function foreground(value, color, mode, bold = false) {
|
|
33278
|
+
return mode === "none" ? value : `${bold ? "\x1B[1m" : ""}${colorSequence(rgb(color), mode, false)}${value}\x1B[0m`;
|
|
33279
|
+
}
|
|
33280
|
+
function backgroundLine(value, width, color, mode, bold = false) {
|
|
33281
|
+
const line = padCells(value, width);
|
|
33282
|
+
if (mode === "none") return line;
|
|
33283
|
+
const white = mode === "ansi16" ? "\x1B[97m" : colorSequence([255, 255, 255], mode, false);
|
|
33284
|
+
return `${bold ? "\x1B[1m" : ""}${white}${colorSequence(rgb(color), mode, true)}${line}\x1B[0m`;
|
|
33285
|
+
}
|
|
33286
|
+
|
|
33287
|
+
// src/embedRenderers.ts
|
|
33288
|
+
var stdoutWriter = (chunk) => {
|
|
33289
|
+
process.stdout.write(chunk);
|
|
33290
|
+
};
|
|
33291
|
+
var writeEmbedLine = (write, text7 = "") => write(`${text7}
|
|
33292
|
+
`);
|
|
32975
33293
|
var str = (v) => typeof v === "string" && v.length > 0 ? v : null;
|
|
32976
33294
|
var DIRECT_TYPES = /* @__PURE__ */ new Set([
|
|
32977
33295
|
"code",
|
|
@@ -33087,7 +33405,7 @@ function formatFare(value) {
|
|
|
33087
33405
|
function trunc(s, max) {
|
|
33088
33406
|
return s.length > max ? s.slice(0, max) + "\u2026" : s;
|
|
33089
33407
|
}
|
|
33090
|
-
function
|
|
33408
|
+
function stripAnsi2(value) {
|
|
33091
33409
|
return value.replace(new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g"), "");
|
|
33092
33410
|
}
|
|
33093
33411
|
function extractTextLines(value) {
|
|
@@ -33125,7 +33443,7 @@ function formatEmbedPreviewLines(embed, maxContentLines = 8) {
|
|
|
33125
33443
|
const skill = embed.skillId ?? str(c.skill_id) ?? "";
|
|
33126
33444
|
const label3 = skill ? `${app}/${skill}` : app || DIRECT_TYPE_LABELS[resolvedType] || resolvedType;
|
|
33127
33445
|
const title = str(c.title) ?? str(c.name) ?? str(c.query) ?? embed.textPreview ?? "";
|
|
33128
|
-
const status =
|
|
33446
|
+
const status = stripAnsi2(statusIcon(str(c.status)) || statusIcon("finished"));
|
|
33129
33447
|
const lines = [`\u250C\u2500 ${status} ${label3}${title ? ` \xB7 ${trunc(title, 56)}` : ""}`];
|
|
33130
33448
|
const fileNames = extractFileNames(c);
|
|
33131
33449
|
if (fileNames.length > 0) {
|
|
@@ -33268,50 +33586,50 @@ async function renderEmbedPreview(embed, client2) {
|
|
|
33268
33586
|
process.stdout.write(`\x1B[2m\u2514\u2500 openmates embeds show ${shortId}\x1B[0m
|
|
33269
33587
|
`);
|
|
33270
33588
|
}
|
|
33271
|
-
async function renderEmbedFullscreen(embed, client2) {
|
|
33589
|
+
async function renderEmbedFullscreen(embed, client2, write = stdoutWriter, createShareLinks = true) {
|
|
33272
33590
|
const c = embed.content ?? {};
|
|
33273
33591
|
const resolvedType = embed.type ?? str(c.type) ?? "";
|
|
33274
33592
|
if (DIRECT_TYPES.has(resolvedType)) {
|
|
33275
33593
|
const typeLabel = DIRECT_TYPE_LABELS[resolvedType] ?? resolvedType;
|
|
33276
|
-
|
|
33594
|
+
write(
|
|
33277
33595
|
`\x1B[1m${typeLabel}\x1B[0m \x1B[2m${embed.embedId.slice(0, 8)}\x1B[0m
|
|
33278
33596
|
`
|
|
33279
33597
|
);
|
|
33280
33598
|
if (embed.createdAt)
|
|
33281
|
-
|
|
33599
|
+
write(
|
|
33282
33600
|
`\x1B[2mCreated:\x1B[0m ${formatTs(embed.createdAt)}
|
|
33283
33601
|
`
|
|
33284
33602
|
);
|
|
33285
|
-
|
|
33286
|
-
renderDirectTypeFullscreen(embed, c);
|
|
33603
|
+
write("\n");
|
|
33604
|
+
renderDirectTypeFullscreen(embed, c, write);
|
|
33287
33605
|
return;
|
|
33288
33606
|
}
|
|
33289
33607
|
const app = embed.appId ?? str(embed.content?.app_id) ?? "";
|
|
33290
33608
|
const skill = embed.skillId ?? str(embed.content?.skill_id) ?? "";
|
|
33291
33609
|
const label3 = skill ? `${app}/${skill}` : app || "embed";
|
|
33292
33610
|
const status = str(c.status);
|
|
33293
|
-
|
|
33294
|
-
if (status)
|
|
33295
|
-
|
|
33611
|
+
write(`\x1B[1m${label3}\x1B[0m`);
|
|
33612
|
+
if (status) write(` ${statusLabel(status)}`);
|
|
33613
|
+
write(` \x1B[2m${embed.embedId.slice(0, 8)}\x1B[0m
|
|
33296
33614
|
`);
|
|
33297
33615
|
const query = str(c.query) ?? str(c.search_query) ?? str(c.question);
|
|
33298
33616
|
const provider = str(c.provider);
|
|
33299
|
-
if (query)
|
|
33617
|
+
if (query) write(`\x1B[2mQuery:\x1B[0m ${query}
|
|
33300
33618
|
`);
|
|
33301
|
-
if (provider)
|
|
33619
|
+
if (provider) write(`\x1B[2mProvider:\x1B[0m ${provider}
|
|
33302
33620
|
`);
|
|
33303
33621
|
if (embed.createdAt)
|
|
33304
|
-
|
|
33622
|
+
write(
|
|
33305
33623
|
`\x1B[2mCreated:\x1B[0m ${formatTs(embed.createdAt)}
|
|
33306
33624
|
`
|
|
33307
33625
|
);
|
|
33308
33626
|
const error = str(c.error) ?? str(c.error_message);
|
|
33309
33627
|
if (error) {
|
|
33310
|
-
|
|
33628
|
+
write(`
|
|
33311
33629
|
\x1B[31mError:\x1B[0m ${error}
|
|
33312
33630
|
`);
|
|
33313
33631
|
}
|
|
33314
|
-
|
|
33632
|
+
write("\n");
|
|
33315
33633
|
const key = `${app}/${skill}`;
|
|
33316
33634
|
switch (key) {
|
|
33317
33635
|
case "web/search":
|
|
@@ -33319,91 +33637,98 @@ async function renderEmbedFullscreen(embed, client2) {
|
|
|
33319
33637
|
case "shopping/search_products":
|
|
33320
33638
|
case "images/search":
|
|
33321
33639
|
case "mail/search":
|
|
33322
|
-
await renderSearchFullscreen(c, client2);
|
|
33640
|
+
await renderSearchFullscreen(c, client2, write);
|
|
33323
33641
|
break;
|
|
33324
33642
|
case "events/search":
|
|
33325
|
-
await renderEventsSearchFullscreen(c, client2);
|
|
33643
|
+
await renderEventsSearchFullscreen(c, client2, write);
|
|
33326
33644
|
break;
|
|
33327
33645
|
case "videos/search":
|
|
33328
|
-
await renderVideosSearchFullscreen(c, client2);
|
|
33646
|
+
await renderVideosSearchFullscreen(c, client2, write);
|
|
33329
33647
|
break;
|
|
33330
33648
|
case "maps/search":
|
|
33331
|
-
renderMapsSearchFullscreen(c);
|
|
33649
|
+
renderMapsSearchFullscreen(c, write);
|
|
33332
33650
|
break;
|
|
33333
33651
|
case "travel/search_connections":
|
|
33334
|
-
await renderTravelConnectionsFullscreen(c, client2);
|
|
33652
|
+
await renderTravelConnectionsFullscreen(c, client2, write);
|
|
33335
33653
|
break;
|
|
33336
33654
|
case "travel/search_stays":
|
|
33337
|
-
await renderTravelStaysFullscreen(c, client2);
|
|
33655
|
+
await renderTravelStaysFullscreen(c, client2, write);
|
|
33338
33656
|
break;
|
|
33339
33657
|
case "travel/price_calendar":
|
|
33340
|
-
renderTravelPriceCalendarFullscreen(c);
|
|
33658
|
+
renderTravelPriceCalendarFullscreen(c, write);
|
|
33341
33659
|
break;
|
|
33342
33660
|
case "travel/get_flight":
|
|
33343
|
-
renderTravelFlightFullscreen(c);
|
|
33661
|
+
renderTravelFlightFullscreen(c, write);
|
|
33344
33662
|
break;
|
|
33345
33663
|
case "code/get_docs":
|
|
33346
|
-
renderCodeDocsFullscreen(c);
|
|
33664
|
+
renderCodeDocsFullscreen(c, write);
|
|
33347
33665
|
break;
|
|
33348
33666
|
case "web/read":
|
|
33349
|
-
renderWebReadFullscreen(c);
|
|
33667
|
+
renderWebReadFullscreen(c, write);
|
|
33350
33668
|
break;
|
|
33351
33669
|
case "math/calculate":
|
|
33352
|
-
renderMathCalculateFullscreen(c);
|
|
33670
|
+
renderMathCalculateFullscreen(c, write);
|
|
33353
33671
|
break;
|
|
33354
33672
|
case "reminder/set-reminder":
|
|
33355
33673
|
case "reminder/list-reminders":
|
|
33356
33674
|
case "reminder/cancel-reminder":
|
|
33357
|
-
renderReminderFullscreen(c);
|
|
33675
|
+
renderReminderFullscreen(c, write);
|
|
33358
33676
|
break;
|
|
33359
33677
|
case "images/generate":
|
|
33360
33678
|
case "images/generate_draft":
|
|
33361
|
-
renderImageGenerateFullscreen(c);
|
|
33679
|
+
renderImageGenerateFullscreen(c, write);
|
|
33362
33680
|
break;
|
|
33363
33681
|
case "videos/get_transcript":
|
|
33364
|
-
renderVideoTranscriptFullscreen(c);
|
|
33682
|
+
renderVideoTranscriptFullscreen(c, write);
|
|
33365
33683
|
break;
|
|
33366
33684
|
case "videos/create":
|
|
33367
|
-
await renderRemotionCreateFullscreen(embed, c, client2);
|
|
33685
|
+
await renderRemotionCreateFullscreen(embed, c, client2, write, createShareLinks);
|
|
33368
33686
|
break;
|
|
33369
33687
|
case "health/search_appointments":
|
|
33370
|
-
await renderHealthSearchFullscreen(c, client2);
|
|
33688
|
+
await renderHealthSearchFullscreen(c, client2, write);
|
|
33371
33689
|
break;
|
|
33372
33690
|
case "audio/transcribe":
|
|
33373
|
-
renderAudioTranscribeFullscreen(c);
|
|
33691
|
+
renderAudioTranscribeFullscreen(c, write);
|
|
33374
33692
|
break;
|
|
33375
33693
|
default:
|
|
33376
|
-
renderDirectTypeFullscreen(embed, c);
|
|
33694
|
+
renderDirectTypeFullscreen(embed, c, write);
|
|
33377
33695
|
break;
|
|
33378
33696
|
}
|
|
33379
33697
|
}
|
|
33698
|
+
async function formatEmbedFullscreenLines(embed, client2) {
|
|
33699
|
+
let output = "";
|
|
33700
|
+
await renderEmbedFullscreen(embed, client2, (chunk) => {
|
|
33701
|
+
output += chunk;
|
|
33702
|
+
}, false);
|
|
33703
|
+
return terminalText(output).trimEnd().split("\n");
|
|
33704
|
+
}
|
|
33380
33705
|
async function renderSearchPreview(c, ln, _client) {
|
|
33381
33706
|
const count = resolveResultCount(c);
|
|
33382
33707
|
if (count !== null) ln(`\x1B[2m+ ${count} results\x1B[0m`);
|
|
33383
33708
|
else if (str(c.status) === "finished") ln("\x1B[2mNo results\x1B[0m");
|
|
33384
33709
|
}
|
|
33385
|
-
async function renderSearchFullscreen(c, client2) {
|
|
33710
|
+
async function renderSearchFullscreen(c, client2, write) {
|
|
33386
33711
|
const results = await resolveChildResults(c, client2);
|
|
33387
33712
|
if (results.length === 0) {
|
|
33388
|
-
|
|
33713
|
+
writeEmbedLine(write, "No results found.");
|
|
33389
33714
|
return;
|
|
33390
33715
|
}
|
|
33391
|
-
|
|
33716
|
+
writeEmbedLine(write, `${results.length} results:
|
|
33392
33717
|
`);
|
|
33393
33718
|
for (const r of results) {
|
|
33394
33719
|
const title = str(r.title) ?? str(r.name) ?? "";
|
|
33395
33720
|
const url = str(r.url) ?? str(r.link) ?? "";
|
|
33396
33721
|
const desc = str(r.description) ?? str(r.snippet) ?? str(r.summary) ?? "";
|
|
33397
33722
|
const age = str(r.page_age);
|
|
33398
|
-
if (title)
|
|
33723
|
+
if (title) write(` \x1B[1m${title}\x1B[0m
|
|
33399
33724
|
`);
|
|
33400
|
-
if (url)
|
|
33725
|
+
if (url) write(` \x1B[2m${url}\x1B[0m
|
|
33401
33726
|
`);
|
|
33402
|
-
if (age)
|
|
33727
|
+
if (age) write(` \x1B[2m${age}\x1B[0m
|
|
33403
33728
|
`);
|
|
33404
|
-
if (desc)
|
|
33729
|
+
if (desc) write(` ${desc}
|
|
33405
33730
|
`);
|
|
33406
|
-
|
|
33731
|
+
write(` \x1B[2m${"\u2500".repeat(40)}\x1B[0m
|
|
33407
33732
|
`);
|
|
33408
33733
|
}
|
|
33409
33734
|
}
|
|
@@ -33412,13 +33737,13 @@ async function renderEventsSearchPreview(c, ln, _client) {
|
|
|
33412
33737
|
if (count !== null) ln(`\x1B[2m+ ${count} events\x1B[0m`);
|
|
33413
33738
|
else if (str(c.status) === "finished") ln("\x1B[2mNo events found\x1B[0m");
|
|
33414
33739
|
}
|
|
33415
|
-
async function renderEventsSearchFullscreen(c, client2) {
|
|
33740
|
+
async function renderEventsSearchFullscreen(c, client2, write) {
|
|
33416
33741
|
const results = await resolveChildResults(c, client2);
|
|
33417
33742
|
if (results.length === 0) {
|
|
33418
|
-
|
|
33743
|
+
writeEmbedLine(write, "No events found.");
|
|
33419
33744
|
return;
|
|
33420
33745
|
}
|
|
33421
|
-
|
|
33746
|
+
writeEmbedLine(write, `${results.length} events:
|
|
33422
33747
|
`);
|
|
33423
33748
|
for (const r of results) {
|
|
33424
33749
|
const name = str(r.name) ?? str(r.title) ?? "";
|
|
@@ -33427,19 +33752,19 @@ async function renderEventsSearchFullscreen(c, client2) {
|
|
|
33427
33752
|
const url = str(r.url) ?? str(r.link) ?? "";
|
|
33428
33753
|
const desc = str(r.description) ?? str(r.summary) ?? "";
|
|
33429
33754
|
const going = typeof r.going_count === "number" ? r.going_count : null;
|
|
33430
|
-
if (name)
|
|
33755
|
+
if (name) write(` \x1B[1m${name}\x1B[0m
|
|
33431
33756
|
`);
|
|
33432
|
-
if (date)
|
|
33433
|
-
if (venue)
|
|
33434
|
-
if (date || venue)
|
|
33757
|
+
if (date) write(` \x1B[2m${date}\x1B[0m`);
|
|
33758
|
+
if (venue) write(` \x1B[2m@ ${venue}\x1B[0m`);
|
|
33759
|
+
if (date || venue) write("\n");
|
|
33435
33760
|
if (going !== null)
|
|
33436
|
-
|
|
33761
|
+
write(` \x1B[2m${going} going\x1B[0m
|
|
33437
33762
|
`);
|
|
33438
|
-
if (desc)
|
|
33763
|
+
if (desc) write(` ${desc}
|
|
33439
33764
|
`);
|
|
33440
|
-
if (url)
|
|
33765
|
+
if (url) write(` \x1B[2m${url}\x1B[0m
|
|
33441
33766
|
`);
|
|
33442
|
-
|
|
33767
|
+
write(` \x1B[2m${"\u2500".repeat(40)}\x1B[0m
|
|
33443
33768
|
`);
|
|
33444
33769
|
}
|
|
33445
33770
|
}
|
|
@@ -33448,30 +33773,30 @@ async function renderVideosSearchPreview(c, ln, _client) {
|
|
|
33448
33773
|
if (count !== null) ln(`\x1B[2m+ ${count} videos\x1B[0m`);
|
|
33449
33774
|
else if (str(c.status) === "finished") ln("\x1B[2mNo videos found\x1B[0m");
|
|
33450
33775
|
}
|
|
33451
|
-
async function renderVideosSearchFullscreen(c, client2) {
|
|
33776
|
+
async function renderVideosSearchFullscreen(c, client2, write) {
|
|
33452
33777
|
const results = await resolveChildResults(c, client2);
|
|
33453
33778
|
if (results.length === 0) {
|
|
33454
|
-
|
|
33779
|
+
writeEmbedLine(write, "No videos found.");
|
|
33455
33780
|
return;
|
|
33456
33781
|
}
|
|
33457
|
-
|
|
33782
|
+
writeEmbedLine(write, `${results.length} videos:
|
|
33458
33783
|
`);
|
|
33459
33784
|
for (const r of results) {
|
|
33460
33785
|
const title = str(r.title) ?? "";
|
|
33461
33786
|
const channel = str(r.channel) ?? str(r.author) ?? "";
|
|
33462
33787
|
const duration = str(r.duration) ?? "";
|
|
33463
33788
|
const url = str(r.url) ?? str(r.link) ?? "";
|
|
33464
|
-
if (title)
|
|
33789
|
+
if (title) write(` \x1B[1m${title}\x1B[0m
|
|
33465
33790
|
`);
|
|
33466
33791
|
if (channel || duration) {
|
|
33467
|
-
|
|
33792
|
+
write(
|
|
33468
33793
|
` \x1B[2m${channel}${duration ? ` ${duration}` : ""}\x1B[0m
|
|
33469
33794
|
`
|
|
33470
33795
|
);
|
|
33471
33796
|
}
|
|
33472
|
-
if (url)
|
|
33797
|
+
if (url) write(` \x1B[2m${url}\x1B[0m
|
|
33473
33798
|
`);
|
|
33474
|
-
|
|
33799
|
+
writeEmbedLine(write);
|
|
33475
33800
|
}
|
|
33476
33801
|
}
|
|
33477
33802
|
async function renderRemotionCreatePreview(embed, c, ln, client2) {
|
|
@@ -33488,38 +33813,38 @@ async function renderRemotionCreatePreview(embed, c, ln, client2) {
|
|
|
33488
33813
|
await renderRemotionShareLink(embed.embedId, client2, ln);
|
|
33489
33814
|
}
|
|
33490
33815
|
}
|
|
33491
|
-
async function renderRemotionCreateFullscreen(embed, c, client2) {
|
|
33816
|
+
async function renderRemotionCreateFullscreen(embed, c, client2, write, createShareLinks) {
|
|
33492
33817
|
const meta = remotionMeta(c);
|
|
33493
|
-
|
|
33818
|
+
write(`\x1B[1m${meta.filename}\x1B[0m
|
|
33494
33819
|
`);
|
|
33495
|
-
|
|
33820
|
+
write(`${meta.statusText} \x1B[2mv${meta.sourceVersion} \xB7 ${meta.durationSeconds}s \xB7 ${meta.width}x${meta.height}\x1B[0m
|
|
33496
33821
|
|
|
33497
33822
|
`);
|
|
33498
33823
|
if (meta.layers.length > 0) {
|
|
33499
|
-
|
|
33824
|
+
write("Timeline:\n");
|
|
33500
33825
|
for (const layer of meta.layers) {
|
|
33501
|
-
|
|
33826
|
+
write(` - ${layer}
|
|
33502
33827
|
`);
|
|
33503
33828
|
}
|
|
33504
|
-
|
|
33829
|
+
write("\n");
|
|
33505
33830
|
}
|
|
33506
33831
|
if (meta.source) {
|
|
33507
|
-
|
|
33508
|
-
|
|
33509
|
-
|
|
33832
|
+
write("Source:\n");
|
|
33833
|
+
write("```tsx\n");
|
|
33834
|
+
write(`${meta.source.trim()}
|
|
33510
33835
|
`);
|
|
33511
|
-
|
|
33836
|
+
write("```\n\n");
|
|
33512
33837
|
}
|
|
33513
33838
|
if (meta.error) {
|
|
33514
|
-
|
|
33839
|
+
write(`\x1B[31mError:\x1B[0m ${meta.error}
|
|
33515
33840
|
|
|
33516
33841
|
`);
|
|
33517
33842
|
}
|
|
33518
|
-
if (meta.status === "finished") {
|
|
33519
|
-
await renderRemotionShareLink(embed.embedId, client2, (line) =>
|
|
33843
|
+
if (createShareLinks && meta.status === "finished") {
|
|
33844
|
+
await renderRemotionShareLink(embed.embedId, client2, (line) => write(`${line}
|
|
33520
33845
|
`));
|
|
33521
|
-
} else {
|
|
33522
|
-
|
|
33846
|
+
} else if (meta.status !== "finished") {
|
|
33847
|
+
write("Run again after rendering finishes to get the rendered video link and QR code.\n");
|
|
33523
33848
|
}
|
|
33524
33849
|
}
|
|
33525
33850
|
async function renderRemotionShareLink(embedId, client2, ln) {
|
|
@@ -33603,26 +33928,26 @@ function renderMapsSearchPreview(c, ln) {
|
|
|
33603
33928
|
ln("\x1B[2mNo places found\x1B[0m");
|
|
33604
33929
|
}
|
|
33605
33930
|
}
|
|
33606
|
-
function renderMapsSearchFullscreen(c) {
|
|
33931
|
+
function renderMapsSearchFullscreen(c, write) {
|
|
33607
33932
|
const results = c.results;
|
|
33608
33933
|
if (!Array.isArray(results) || results.length === 0) {
|
|
33609
|
-
|
|
33934
|
+
writeEmbedLine(write, "No places found.");
|
|
33610
33935
|
return;
|
|
33611
33936
|
}
|
|
33612
|
-
|
|
33937
|
+
writeEmbedLine(write, `${results.length} places:
|
|
33613
33938
|
`);
|
|
33614
33939
|
for (const r of results) {
|
|
33615
33940
|
const name = str(r.displayName) ?? str(r.name) ?? "";
|
|
33616
33941
|
const address = str(r.formattedAddress) ?? str(r.address) ?? "";
|
|
33617
33942
|
const rating = typeof r.rating === "number" ? `\u2605 ${r.rating}` : "";
|
|
33618
33943
|
if (name)
|
|
33619
|
-
|
|
33944
|
+
write(
|
|
33620
33945
|
` \x1B[1m${name}\x1B[0m${rating ? ` ${rating}` : ""}
|
|
33621
33946
|
`
|
|
33622
33947
|
);
|
|
33623
|
-
if (address)
|
|
33948
|
+
if (address) write(` \x1B[2m${address}\x1B[0m
|
|
33624
33949
|
`);
|
|
33625
|
-
|
|
33950
|
+
writeEmbedLine(write);
|
|
33626
33951
|
}
|
|
33627
33952
|
}
|
|
33628
33953
|
async function renderTravelConnectionsPreview(c, ln, _client) {
|
|
@@ -33649,13 +33974,13 @@ async function renderTravelConnectionsPreview(c, ln, _client) {
|
|
|
33649
33974
|
}
|
|
33650
33975
|
}
|
|
33651
33976
|
}
|
|
33652
|
-
async function renderTravelConnectionsFullscreen(c, client2) {
|
|
33977
|
+
async function renderTravelConnectionsFullscreen(c, client2, write) {
|
|
33653
33978
|
const results = await resolveChildResults(c, client2);
|
|
33654
33979
|
if (results.length === 0) {
|
|
33655
|
-
|
|
33980
|
+
writeEmbedLine(write, "No connections found.");
|
|
33656
33981
|
return;
|
|
33657
33982
|
}
|
|
33658
|
-
|
|
33983
|
+
writeEmbedLine(write, `${results.length} connections:
|
|
33659
33984
|
`);
|
|
33660
33985
|
for (const r of results) {
|
|
33661
33986
|
const origin = str(r.origin) ?? "";
|
|
@@ -33667,33 +33992,33 @@ async function renderTravelConnectionsFullscreen(c, client2) {
|
|
|
33667
33992
|
const stops = typeof r.stops === "number" ? r.stops === 0 ? "Direct" : `${r.stops} stops` : "";
|
|
33668
33993
|
const carriers = Array.isArray(r.carriers) ? r.carriers.join(", ") : str(r.carrier) ?? "";
|
|
33669
33994
|
if (origin && dest)
|
|
33670
|
-
|
|
33995
|
+
write(` \x1B[1m${origin} \u2192 ${dest}\x1B[0m
|
|
33671
33996
|
`);
|
|
33672
33997
|
if (dep && arr)
|
|
33673
|
-
|
|
33998
|
+
write(
|
|
33674
33999
|
` ${dep} \u2013 ${arr}${duration ? ` (${duration})` : ""}
|
|
33675
34000
|
`
|
|
33676
34001
|
);
|
|
33677
34002
|
if (price || stops || carriers) {
|
|
33678
|
-
|
|
34003
|
+
write(
|
|
33679
34004
|
` \x1B[2m${[price, stops, carriers].filter(Boolean).join(" \xB7 ")}\x1B[0m
|
|
33680
34005
|
`
|
|
33681
34006
|
);
|
|
33682
34007
|
}
|
|
33683
|
-
|
|
34008
|
+
writeEmbedLine(write);
|
|
33684
34009
|
}
|
|
33685
34010
|
}
|
|
33686
34011
|
async function renderTravelStaysPreview(c, ln, _client) {
|
|
33687
34012
|
const count = resolveResultCount(c);
|
|
33688
34013
|
if (count !== null) ln(`\x1B[2m${count} stays\x1B[0m`);
|
|
33689
34014
|
}
|
|
33690
|
-
async function renderTravelStaysFullscreen(c, client2) {
|
|
34015
|
+
async function renderTravelStaysFullscreen(c, client2, write) {
|
|
33691
34016
|
const results = await resolveChildResults(c, client2);
|
|
33692
34017
|
if (results.length === 0) {
|
|
33693
|
-
|
|
34018
|
+
writeEmbedLine(write, "No stays found.");
|
|
33694
34019
|
return;
|
|
33695
34020
|
}
|
|
33696
|
-
|
|
34021
|
+
writeEmbedLine(write, `${results.length} stays:
|
|
33697
34022
|
`);
|
|
33698
34023
|
for (const r of results) {
|
|
33699
34024
|
const name = str(r.name) ?? str(r.hotel_name) ?? "";
|
|
@@ -33701,15 +34026,15 @@ async function renderTravelStaysFullscreen(c, client2) {
|
|
|
33701
34026
|
const rating = typeof r.rating === "number" ? `\u2605 ${r.rating}` : "";
|
|
33702
34027
|
const address = str(r.address) ?? "";
|
|
33703
34028
|
if (name)
|
|
33704
|
-
|
|
34029
|
+
write(
|
|
33705
34030
|
` \x1B[1m${name}\x1B[0m${rating ? ` ${rating}` : ""}
|
|
33706
34031
|
`
|
|
33707
34032
|
);
|
|
33708
|
-
if (price)
|
|
34033
|
+
if (price) write(` ${price}
|
|
33709
34034
|
`);
|
|
33710
|
-
if (address)
|
|
34035
|
+
if (address) write(` \x1B[2m${address}\x1B[0m
|
|
33711
34036
|
`);
|
|
33712
|
-
|
|
34037
|
+
writeEmbedLine(write);
|
|
33713
34038
|
}
|
|
33714
34039
|
}
|
|
33715
34040
|
function renderTravelPriceCalendarPreview(c, ln) {
|
|
@@ -33722,24 +34047,24 @@ function renderTravelPriceCalendarPreview(c, ln) {
|
|
|
33722
34047
|
ln(`\x1B[2mFrom ${currency} ${cheapest}\x1B[0m`);
|
|
33723
34048
|
}
|
|
33724
34049
|
}
|
|
33725
|
-
function renderTravelPriceCalendarFullscreen(c) {
|
|
34050
|
+
function renderTravelPriceCalendarFullscreen(c, write) {
|
|
33726
34051
|
const prices = c.prices;
|
|
33727
34052
|
if (!Array.isArray(prices) || prices.length === 0) {
|
|
33728
|
-
|
|
34053
|
+
writeEmbedLine(write, "No price data available.");
|
|
33729
34054
|
return;
|
|
33730
34055
|
}
|
|
33731
34056
|
const currency = str(c.currency) ?? "EUR";
|
|
33732
|
-
|
|
34057
|
+
writeEmbedLine(write, `Price calendar (${prices.length} dates):
|
|
33733
34058
|
`);
|
|
33734
34059
|
for (const p of prices.slice(0, 14)) {
|
|
33735
34060
|
const date = str(p.date) ?? "";
|
|
33736
34061
|
const price = p.price ?? p.amount;
|
|
33737
34062
|
if (date && price !== void 0) {
|
|
33738
|
-
|
|
34063
|
+
write(` ${date} ${currency} ${price}
|
|
33739
34064
|
`);
|
|
33740
34065
|
}
|
|
33741
34066
|
}
|
|
33742
|
-
if (prices.length > 14)
|
|
34067
|
+
if (prices.length > 14) writeEmbedLine(write, ` ... and ${prices.length - 14} more`);
|
|
33743
34068
|
}
|
|
33744
34069
|
function renderTravelFlightPreview(c, ln) {
|
|
33745
34070
|
const flightNumber = str(c.flight_number) ?? str(c.callsign) ?? "";
|
|
@@ -33752,7 +34077,7 @@ function renderTravelFlightPreview(c, ln) {
|
|
|
33752
34077
|
const status = str(c.flight_status);
|
|
33753
34078
|
if (status) ln(`\x1B[2mStatus: ${status}\x1B[0m`);
|
|
33754
34079
|
}
|
|
33755
|
-
function renderTravelFlightFullscreen(c) {
|
|
34080
|
+
function renderTravelFlightFullscreen(c, write) {
|
|
33756
34081
|
const fields = [
|
|
33757
34082
|
["Flight", c.flight_number ?? c.callsign],
|
|
33758
34083
|
["Airline", c.airline],
|
|
@@ -33769,7 +34094,7 @@ function renderTravelFlightFullscreen(c) {
|
|
|
33769
34094
|
];
|
|
33770
34095
|
for (const [label3, value] of fields) {
|
|
33771
34096
|
if (value !== null && value !== void 0) {
|
|
33772
|
-
|
|
34097
|
+
write(` \x1B[2m${label3.padEnd(14)}\x1B[0m ${value}
|
|
33773
34098
|
`);
|
|
33774
34099
|
}
|
|
33775
34100
|
}
|
|
@@ -33782,14 +34107,14 @@ function renderCodeDocsPreview(c, ln) {
|
|
|
33782
34107
|
if (libId) ln(`\x1B[2mLibrary: ${String(libId)}\x1B[0m`);
|
|
33783
34108
|
if (wordCount) ln(`\x1B[2m${String(wordCount)} words\x1B[0m`);
|
|
33784
34109
|
}
|
|
33785
|
-
function renderCodeDocsFullscreen(c) {
|
|
34110
|
+
function renderCodeDocsFullscreen(c, write) {
|
|
33786
34111
|
const results = c.results;
|
|
33787
34112
|
const first = Array.isArray(results) ? results[0] : null;
|
|
33788
34113
|
const docs = str(first?.documentation) ?? str(c.documentation) ?? "";
|
|
33789
34114
|
if (docs) {
|
|
33790
|
-
|
|
34115
|
+
writeEmbedLine(write, docs);
|
|
33791
34116
|
} else {
|
|
33792
|
-
|
|
34117
|
+
writeEmbedLine(write, "No documentation content.");
|
|
33793
34118
|
}
|
|
33794
34119
|
}
|
|
33795
34120
|
function renderWebReadPreview(c, ln) {
|
|
@@ -33798,17 +34123,17 @@ function renderWebReadPreview(c, ln) {
|
|
|
33798
34123
|
if (url) ln(`\x1B[2m${trunc(url, 60)}\x1B[0m`);
|
|
33799
34124
|
if (resultCount) ln(`\x1B[2m${resultCount} results\x1B[0m`);
|
|
33800
34125
|
}
|
|
33801
|
-
function renderWebReadFullscreen(c) {
|
|
34126
|
+
function renderWebReadFullscreen(c, write) {
|
|
33802
34127
|
const url = str(c.url);
|
|
33803
|
-
if (url)
|
|
34128
|
+
if (url) write(`\x1B[2mURL:\x1B[0m ${url}
|
|
33804
34129
|
|
|
33805
34130
|
`);
|
|
33806
34131
|
const results = c.results;
|
|
33807
34132
|
if (Array.isArray(results)) {
|
|
33808
34133
|
for (const r of results) {
|
|
33809
34134
|
const content = str(r.content) ?? str(r.text) ?? "";
|
|
33810
|
-
if (content)
|
|
33811
|
-
|
|
34135
|
+
if (content) writeEmbedLine(write, content);
|
|
34136
|
+
writeEmbedLine(write);
|
|
33812
34137
|
}
|
|
33813
34138
|
}
|
|
33814
34139
|
}
|
|
@@ -33824,26 +34149,26 @@ function renderMathCalculatePreview(c, ln) {
|
|
|
33824
34149
|
else if (result) ln(trunc(result, 80));
|
|
33825
34150
|
}
|
|
33826
34151
|
}
|
|
33827
|
-
function renderMathCalculateFullscreen(c) {
|
|
34152
|
+
function renderMathCalculateFullscreen(c, write) {
|
|
33828
34153
|
const results = c.results;
|
|
33829
34154
|
const title = str(c.title);
|
|
33830
|
-
if (title)
|
|
34155
|
+
if (title) write(` \x1B[2mTitle:\x1B[0m ${title}
|
|
33831
34156
|
`);
|
|
33832
34157
|
if (!Array.isArray(results) || results.length === 0) {
|
|
33833
|
-
|
|
34158
|
+
writeEmbedLine(write, "No calculation results.");
|
|
33834
34159
|
return;
|
|
33835
34160
|
}
|
|
33836
34161
|
for (const r of results) {
|
|
33837
34162
|
const resultTitle = str(r.title);
|
|
33838
34163
|
const expr = str(r.expression) ?? str(r.input) ?? "";
|
|
33839
34164
|
const result = str(r.result) ?? str(r.output) ?? "";
|
|
33840
|
-
if (resultTitle && resultTitle !== title)
|
|
34165
|
+
if (resultTitle && resultTitle !== title) write(` \x1B[2mTitle:\x1B[0m ${resultTitle}
|
|
33841
34166
|
`);
|
|
33842
|
-
if (expr)
|
|
34167
|
+
if (expr) write(` \x1B[2mExpression:\x1B[0m ${expr}
|
|
33843
34168
|
`);
|
|
33844
|
-
if (result)
|
|
34169
|
+
if (result) write(` \x1B[1mResult:\x1B[0m ${result}
|
|
33845
34170
|
`);
|
|
33846
|
-
|
|
34171
|
+
writeEmbedLine(write);
|
|
33847
34172
|
}
|
|
33848
34173
|
}
|
|
33849
34174
|
function renderReminderPreview(c, ln) {
|
|
@@ -33853,7 +34178,7 @@ function renderReminderPreview(c, ln) {
|
|
|
33853
34178
|
if (time) ln(`\x1B[2m\u{1F551} ${time}\x1B[0m`);
|
|
33854
34179
|
if (c.is_repeating === true) ln("\x1B[2mRepeating\x1B[0m");
|
|
33855
34180
|
}
|
|
33856
|
-
function renderReminderFullscreen(c) {
|
|
34181
|
+
function renderReminderFullscreen(c, write) {
|
|
33857
34182
|
const fields = [
|
|
33858
34183
|
["Message", c.prompt ?? c.message ?? c.reminder_text],
|
|
33859
34184
|
["Time", c.trigger_at_formatted ?? c.trigger_at],
|
|
@@ -33869,7 +34194,7 @@ function renderReminderFullscreen(c) {
|
|
|
33869
34194
|
];
|
|
33870
34195
|
for (const [label3, value] of fields) {
|
|
33871
34196
|
if (value !== null && value !== void 0) {
|
|
33872
|
-
|
|
34197
|
+
write(` \x1B[2m${label3.padEnd(14)}\x1B[0m ${value}
|
|
33873
34198
|
`);
|
|
33874
34199
|
}
|
|
33875
34200
|
}
|
|
@@ -33881,7 +34206,7 @@ function renderImageGeneratePreview(c, ln) {
|
|
|
33881
34206
|
if (prompt) ln(trunc(prompt, 60));
|
|
33882
34207
|
ln("\x1B[2m[image]\x1B[0m");
|
|
33883
34208
|
}
|
|
33884
|
-
function renderImageGenerateFullscreen(c) {
|
|
34209
|
+
function renderImageGenerateFullscreen(c, write) {
|
|
33885
34210
|
const fields = [
|
|
33886
34211
|
["Model", c.model],
|
|
33887
34212
|
["Prompt", c.prompt],
|
|
@@ -33890,11 +34215,11 @@ function renderImageGenerateFullscreen(c) {
|
|
|
33890
34215
|
];
|
|
33891
34216
|
for (const [label3, value] of fields) {
|
|
33892
34217
|
if (value !== null && value !== void 0) {
|
|
33893
|
-
|
|
34218
|
+
write(` \x1B[2m${label3.padEnd(14)}\x1B[0m ${value}
|
|
33894
34219
|
`);
|
|
33895
34220
|
}
|
|
33896
34221
|
}
|
|
33897
|
-
|
|
34222
|
+
writeEmbedLine(write, "\n [Images are encrypted \u2014 view in web app]");
|
|
33898
34223
|
}
|
|
33899
34224
|
function renderVideoTranscriptPreview(c, ln) {
|
|
33900
34225
|
const title = str(c.title) ?? str(c.video_title) ?? "";
|
|
@@ -33902,17 +34227,17 @@ function renderVideoTranscriptPreview(c, ln) {
|
|
|
33902
34227
|
if (title) ln(trunc(title, 60));
|
|
33903
34228
|
if (channel) ln(`\x1B[2m${channel}\x1B[0m`);
|
|
33904
34229
|
}
|
|
33905
|
-
function renderVideoTranscriptFullscreen(c) {
|
|
34230
|
+
function renderVideoTranscriptFullscreen(c, write) {
|
|
33906
34231
|
const title = str(c.title) ?? str(c.video_title);
|
|
33907
34232
|
const url = str(c.url) ?? str(c.video_url);
|
|
33908
|
-
if (title)
|
|
34233
|
+
if (title) write(`\x1B[1m${title}\x1B[0m
|
|
33909
34234
|
`);
|
|
33910
|
-
if (url)
|
|
34235
|
+
if (url) write(`\x1B[2m${url}\x1B[0m
|
|
33911
34236
|
`);
|
|
33912
|
-
|
|
34237
|
+
writeEmbedLine(write);
|
|
33913
34238
|
const transcript = str(c.transcript) ?? str(c.text) ?? "";
|
|
33914
|
-
if (transcript)
|
|
33915
|
-
else
|
|
34239
|
+
if (transcript) writeEmbedLine(write, transcript);
|
|
34240
|
+
else writeEmbedLine(write, "No transcript available.");
|
|
33916
34241
|
}
|
|
33917
34242
|
async function renderHealthSearchPreview(c, ln, _client) {
|
|
33918
34243
|
const count = resolveResultCount(c);
|
|
@@ -33920,26 +34245,26 @@ async function renderHealthSearchPreview(c, ln, _client) {
|
|
|
33920
34245
|
else if (str(c.status) === "finished")
|
|
33921
34246
|
ln("\x1B[2mNo appointments found\x1B[0m");
|
|
33922
34247
|
}
|
|
33923
|
-
async function renderHealthSearchFullscreen(c, client2) {
|
|
34248
|
+
async function renderHealthSearchFullscreen(c, client2, write) {
|
|
33924
34249
|
const results = await resolveChildResults(c, client2);
|
|
33925
34250
|
if (results.length === 0) {
|
|
33926
|
-
|
|
34251
|
+
writeEmbedLine(write, "No appointments found.");
|
|
33927
34252
|
return;
|
|
33928
34253
|
}
|
|
33929
|
-
|
|
34254
|
+
writeEmbedLine(write, `${results.length} appointments:
|
|
33930
34255
|
`);
|
|
33931
34256
|
for (const r of results) {
|
|
33932
34257
|
const slotDt = str(r.slot_datetime) ?? str(r.next_slot) ?? str(r.date) ?? "";
|
|
33933
34258
|
const name = str(r.name) ?? str(r.doctor_name) ?? str(r.title) ?? "";
|
|
33934
34259
|
const speciality = str(r.speciality) ?? "";
|
|
33935
34260
|
const address = str(r.address) ?? "";
|
|
33936
|
-
if (slotDt)
|
|
34261
|
+
if (slotDt) write(` \x1B[1m${slotDt}\x1B[0m
|
|
33937
34262
|
`);
|
|
33938
|
-
if (name)
|
|
34263
|
+
if (name) write(` ${name}${speciality ? ` \xB7 ${speciality}` : ""}
|
|
33939
34264
|
`);
|
|
33940
|
-
if (address)
|
|
34265
|
+
if (address) write(` \x1B[2m${address}\x1B[0m
|
|
33941
34266
|
`);
|
|
33942
|
-
|
|
34267
|
+
writeEmbedLine(write);
|
|
33943
34268
|
}
|
|
33944
34269
|
}
|
|
33945
34270
|
function renderAudioTranscribePreview(c, ln) {
|
|
@@ -33950,10 +34275,10 @@ function renderAudioTranscribePreview(c, ln) {
|
|
|
33950
34275
|
const text7 = str(c.text) ?? str(c.transcript) ?? "";
|
|
33951
34276
|
if (text7) ln(trunc(text7, 60));
|
|
33952
34277
|
}
|
|
33953
|
-
function renderAudioTranscribeFullscreen(c) {
|
|
34278
|
+
function renderAudioTranscribeFullscreen(c, write) {
|
|
33954
34279
|
const text7 = str(c.text) ?? str(c.transcript) ?? "";
|
|
33955
|
-
if (text7)
|
|
33956
|
-
else
|
|
34280
|
+
if (text7) writeEmbedLine(write, text7);
|
|
34281
|
+
else writeEmbedLine(write, "No transcript available.");
|
|
33957
34282
|
}
|
|
33958
34283
|
function renderByDirectType(embed, c, ln) {
|
|
33959
34284
|
const type = embed.type ?? str(c.type) ?? "";
|
|
@@ -34148,7 +34473,7 @@ function renderByDirectType(embed, c, ln) {
|
|
|
34148
34473
|
}
|
|
34149
34474
|
}
|
|
34150
34475
|
}
|
|
34151
|
-
function renderDirectTypeFullscreen(embed, c) {
|
|
34476
|
+
function renderDirectTypeFullscreen(embed, c, write) {
|
|
34152
34477
|
const type = embed.type ?? str(c.type) ?? "";
|
|
34153
34478
|
switch (type) {
|
|
34154
34479
|
case "code":
|
|
@@ -34156,12 +34481,12 @@ function renderDirectTypeFullscreen(embed, c) {
|
|
|
34156
34481
|
const lang = str(c.language);
|
|
34157
34482
|
const filename = str(c.filename);
|
|
34158
34483
|
const code = str(c.code) ?? str(c.content) ?? "";
|
|
34159
|
-
if (filename)
|
|
34484
|
+
if (filename) write(`\x1B[2mFile:\x1B[0m ${filename}
|
|
34160
34485
|
`);
|
|
34161
|
-
if (lang)
|
|
34486
|
+
if (lang) write(`\x1B[2mLanguage:\x1B[0m ${lang}
|
|
34162
34487
|
`);
|
|
34163
|
-
|
|
34164
|
-
if (code)
|
|
34488
|
+
writeEmbedLine(write);
|
|
34489
|
+
if (code) writeEmbedLine(write, code);
|
|
34165
34490
|
break;
|
|
34166
34491
|
}
|
|
34167
34492
|
case "code-application":
|
|
@@ -34169,11 +34494,11 @@ function renderDirectTypeFullscreen(embed, c) {
|
|
|
34169
34494
|
const name = str(c.name) ?? str(c.title);
|
|
34170
34495
|
const framework = str(c.framework);
|
|
34171
34496
|
const runtime = str(c.runtime);
|
|
34172
|
-
if (name)
|
|
34497
|
+
if (name) write(`\x1B[1m${name}\x1B[0m
|
|
34173
34498
|
`);
|
|
34174
|
-
if (framework)
|
|
34499
|
+
if (framework) write(`\x1B[2mFramework:\x1B[0m ${framework}
|
|
34175
34500
|
`);
|
|
34176
|
-
if (runtime)
|
|
34501
|
+
if (runtime) write(`\x1B[2mRuntime:\x1B[0m ${runtime}
|
|
34177
34502
|
`);
|
|
34178
34503
|
break;
|
|
34179
34504
|
}
|
|
@@ -34181,24 +34506,24 @@ function renderDirectTypeFullscreen(embed, c) {
|
|
|
34181
34506
|
case "doc": {
|
|
34182
34507
|
const title = str(c.title);
|
|
34183
34508
|
const html = str(c.html) ?? "";
|
|
34184
|
-
if (title)
|
|
34509
|
+
if (title) write(`\x1B[1m${title}\x1B[0m
|
|
34185
34510
|
|
|
34186
34511
|
`);
|
|
34187
34512
|
if (html) {
|
|
34188
34513
|
const text7 = html.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
34189
|
-
|
|
34514
|
+
writeEmbedLine(write, text7);
|
|
34190
34515
|
}
|
|
34191
34516
|
break;
|
|
34192
34517
|
}
|
|
34193
34518
|
case "document": {
|
|
34194
34519
|
const title = str(c.title);
|
|
34195
34520
|
const html = str(c.html) ?? "";
|
|
34196
|
-
if (title)
|
|
34521
|
+
if (title) write(`\x1B[1m${title}\x1B[0m
|
|
34197
34522
|
|
|
34198
34523
|
`);
|
|
34199
34524
|
if (html) {
|
|
34200
34525
|
const text7 = html.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
34201
|
-
|
|
34526
|
+
writeEmbedLine(write, text7);
|
|
34202
34527
|
}
|
|
34203
34528
|
break;
|
|
34204
34529
|
}
|
|
@@ -34206,23 +34531,23 @@ function renderDirectTypeFullscreen(embed, c) {
|
|
|
34206
34531
|
case "sheet": {
|
|
34207
34532
|
const title = str(c.title);
|
|
34208
34533
|
const table = str(c.table) ?? str(c.content) ?? "";
|
|
34209
|
-
if (title)
|
|
34534
|
+
if (title) write(`\x1B[1m${title}\x1B[0m
|
|
34210
34535
|
|
|
34211
34536
|
`);
|
|
34212
|
-
if (table)
|
|
34537
|
+
if (table) writeEmbedLine(write, table);
|
|
34213
34538
|
break;
|
|
34214
34539
|
}
|
|
34215
34540
|
case "pdf": {
|
|
34216
34541
|
const filename = str(c.filename);
|
|
34217
|
-
if (filename)
|
|
34542
|
+
if (filename) write(`\x1B[2mFile:\x1B[0m ${filename}
|
|
34218
34543
|
`);
|
|
34219
34544
|
const results = c.results;
|
|
34220
34545
|
if (Array.isArray(results)) {
|
|
34221
34546
|
for (const r of results) {
|
|
34222
34547
|
const content = str(r.content) ?? str(r.text) ?? "";
|
|
34223
34548
|
if (content) {
|
|
34224
|
-
|
|
34225
|
-
|
|
34549
|
+
writeEmbedLine(write);
|
|
34550
|
+
writeEmbedLine(write, content);
|
|
34226
34551
|
}
|
|
34227
34552
|
}
|
|
34228
34553
|
}
|
|
@@ -34233,15 +34558,15 @@ function renderDirectTypeFullscreen(embed, c) {
|
|
|
34233
34558
|
const url = str(c.url);
|
|
34234
34559
|
const desc = str(c.description) ?? str(c.snippet) ?? "";
|
|
34235
34560
|
const age = str(c.page_age);
|
|
34236
|
-
if (title)
|
|
34561
|
+
if (title) write(`\x1B[1m${title}\x1B[0m
|
|
34237
34562
|
`);
|
|
34238
|
-
if (url)
|
|
34563
|
+
if (url) write(`\x1B[2m${url}\x1B[0m
|
|
34239
34564
|
`);
|
|
34240
|
-
if (age)
|
|
34565
|
+
if (age) write(`\x1B[2mAge: ${age}\x1B[0m
|
|
34241
34566
|
`);
|
|
34242
34567
|
if (desc) {
|
|
34243
|
-
|
|
34244
|
-
|
|
34568
|
+
writeEmbedLine(write);
|
|
34569
|
+
writeEmbedLine(write, desc);
|
|
34245
34570
|
}
|
|
34246
34571
|
break;
|
|
34247
34572
|
}
|
|
@@ -34251,18 +34576,18 @@ function renderDirectTypeFullscreen(embed, c) {
|
|
|
34251
34576
|
const channel = str(c.channel) ?? str(c.author) ?? "";
|
|
34252
34577
|
const duration = str(c.duration) ?? "";
|
|
34253
34578
|
const desc = str(c.description) ?? str(c.snippet) ?? "";
|
|
34254
|
-
if (title)
|
|
34579
|
+
if (title) write(`\x1B[1m${title}\x1B[0m
|
|
34255
34580
|
`);
|
|
34256
|
-
if (url)
|
|
34581
|
+
if (url) write(`\x1B[2m${url}\x1B[0m
|
|
34257
34582
|
`);
|
|
34258
34583
|
if (channel)
|
|
34259
|
-
|
|
34584
|
+
write(
|
|
34260
34585
|
`\x1B[2mChannel:\x1B[0m ${channel}${duration ? ` \x1B[2m(${duration})\x1B[0m` : ""}
|
|
34261
34586
|
`
|
|
34262
34587
|
);
|
|
34263
34588
|
if (desc) {
|
|
34264
|
-
|
|
34265
|
-
|
|
34589
|
+
writeEmbedLine(write);
|
|
34590
|
+
writeEmbedLine(write, desc);
|
|
34266
34591
|
}
|
|
34267
34592
|
break;
|
|
34268
34593
|
}
|
|
@@ -34270,13 +34595,13 @@ function renderDirectTypeFullscreen(embed, c) {
|
|
|
34270
34595
|
const subject = str(c.subject);
|
|
34271
34596
|
const receiver = str(c.receiver);
|
|
34272
34597
|
const content = str(c.content) ?? "";
|
|
34273
|
-
if (subject)
|
|
34598
|
+
if (subject) write(`\x1B[1m${subject}\x1B[0m
|
|
34274
34599
|
`);
|
|
34275
|
-
if (receiver)
|
|
34600
|
+
if (receiver) write(`\x1B[2mTo: ${receiver}\x1B[0m
|
|
34276
34601
|
`);
|
|
34277
34602
|
if (content) {
|
|
34278
|
-
|
|
34279
|
-
|
|
34603
|
+
writeEmbedLine(write);
|
|
34604
|
+
writeEmbedLine(write, content);
|
|
34280
34605
|
}
|
|
34281
34606
|
break;
|
|
34282
34607
|
}
|
|
@@ -34284,30 +34609,52 @@ function renderDirectTypeFullscreen(embed, c) {
|
|
|
34284
34609
|
case "mindmaps-mindmap": {
|
|
34285
34610
|
const document = mindMapDocumentFromContent(c);
|
|
34286
34611
|
const title = str(c.title) ?? str(document?.title) ?? "Mind Map";
|
|
34287
|
-
|
|
34612
|
+
write(`\x1B[1m${title}\x1B[0m
|
|
34288
34613
|
`);
|
|
34289
34614
|
if (!document) {
|
|
34290
|
-
|
|
34615
|
+
writeEmbedLine(write, "Invalid mind map JSON");
|
|
34291
34616
|
break;
|
|
34292
34617
|
}
|
|
34293
|
-
|
|
34618
|
+
writeEmbedLine(write, `${document.nodes.length} nodes \xB7 ${document.edges?.length ?? 0} edges
|
|
34294
34619
|
`);
|
|
34295
|
-
|
|
34296
|
-
|
|
34297
|
-
|
|
34298
|
-
|
|
34620
|
+
writeEmbedLine(write, mindMapOutline(document));
|
|
34621
|
+
writeEmbedLine(write, "\n```openmates_mindmap");
|
|
34622
|
+
writeEmbedLine(write, JSON.stringify(document, null, 2));
|
|
34623
|
+
writeEmbedLine(write, "```");
|
|
34624
|
+
break;
|
|
34625
|
+
}
|
|
34626
|
+
case "events-event": {
|
|
34627
|
+
const venue = isRecord2(c.venue) ? c.venue : {};
|
|
34628
|
+
const organizer = isRecord2(c.organizer) ? c.organizer : {};
|
|
34629
|
+
const fee = isRecord2(c.fee) ? c.fee : {};
|
|
34630
|
+
const field = (label3, value) => {
|
|
34631
|
+
if (value !== null && value !== void 0 && String(value).trim()) {
|
|
34632
|
+
writeEmbedLine(write, label3);
|
|
34633
|
+
writeEmbedLine(write, String(value));
|
|
34634
|
+
writeEmbedLine(write);
|
|
34635
|
+
}
|
|
34636
|
+
};
|
|
34637
|
+
writeEmbedLine(write, str(c.title) ?? str(c.name) ?? "Event");
|
|
34638
|
+
writeEmbedLine(write);
|
|
34639
|
+
field("When", [c.date_start ?? c.start_time ?? c.date, c.date_end, c.timezone].filter(Boolean).join(" \xB7 "));
|
|
34640
|
+
field("Location", c.event_type === "online" ? "Online event" : [venue.name ?? c.venue_name, venue.address ?? c.venue_address, venue.city ?? c.venue_city, venue.country ?? c.venue_country, str(c.location)].filter(Boolean).join(", "));
|
|
34641
|
+
field("Organizer", organizer.name ?? c.organizer_name);
|
|
34642
|
+
field("Description", c.description);
|
|
34643
|
+
field("Admission", c.is_paid === false ? "Free" : [fee.amount ?? c.fee_amount, fee.currency ?? c.fee_currency].filter((v) => v !== void 0 && v !== null).join(" "));
|
|
34644
|
+
field("Attendees", c.rsvp_count);
|
|
34645
|
+
field("Event page", c.url);
|
|
34299
34646
|
break;
|
|
34300
34647
|
}
|
|
34301
34648
|
default: {
|
|
34302
34649
|
for (const [k, v] of Object.entries(c)) {
|
|
34303
34650
|
if (v === null || v === void 0 || k.startsWith("_")) continue;
|
|
34304
34651
|
if (typeof v === "object") {
|
|
34305
|
-
|
|
34652
|
+
write(
|
|
34306
34653
|
` \x1B[2m${k.padEnd(20)}\x1B[0m ${JSON.stringify(v)}
|
|
34307
34654
|
`
|
|
34308
34655
|
);
|
|
34309
34656
|
} else {
|
|
34310
|
-
|
|
34657
|
+
write(
|
|
34311
34658
|
` \x1B[2m${k.padEnd(20)}\x1B[0m ${String(v)}
|
|
34312
34659
|
`
|
|
34313
34660
|
);
|
|
@@ -87100,113 +87447,6 @@ function formValue(form, name) {
|
|
|
87100
87447
|
return form.fields.find((field) => field.name === name)?.value ?? "";
|
|
87101
87448
|
}
|
|
87102
87449
|
|
|
87103
|
-
// src/tuiText.ts
|
|
87104
|
-
var segments = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
87105
|
-
function stripAnsi2(value) {
|
|
87106
|
-
return value.replace(/\x1b(?:\[[0-?]*[ -/]*[@-~]|\][^\x07\x1b]*(?:\x07|\x1b\\))/g, "");
|
|
87107
|
-
}
|
|
87108
|
-
function terminalText(value) {
|
|
87109
|
-
return stripAnsi2(value).replace(/[\x00-\x08\x0b-\x1f\x7f-\x9f]/g, "").replace(/\t/g, " ");
|
|
87110
|
-
}
|
|
87111
|
-
function graphemeWidth(value) {
|
|
87112
|
-
if (/^[\p{Mark}\p{Cf}]+$/u.test(value)) return 0;
|
|
87113
|
-
const cp = value.codePointAt(0) ?? 0;
|
|
87114
|
-
if (/\p{Extended_Pictographic}|\p{Regional_Indicator}|\u20e3/u.test(value)) return 2;
|
|
87115
|
-
return cp >= 4352 && (cp <= 4447 || cp === 9001 || cp === 9002 || cp >= 11904 && cp <= 42191 && cp !== 12351 || cp >= 44032 && cp <= 55203 || cp >= 63744 && cp <= 64255 || cp >= 65040 && cp <= 65049 || cp >= 65072 && cp <= 65135 || cp >= 65281 && cp <= 65376 || cp >= 65504 && cp <= 65510 || cp >= 131072 && cp <= 262141) ? 2 : 1;
|
|
87116
|
-
}
|
|
87117
|
-
function cells(value) {
|
|
87118
|
-
return [...segments.segment(stripAnsi2(value))].reduce((n, item) => n + graphemeWidth(item.segment), 0);
|
|
87119
|
-
}
|
|
87120
|
-
function truncateCells(value, width, ellipsis = "\u2026") {
|
|
87121
|
-
const clean = terminalText(value).replace(/\n/g, " ");
|
|
87122
|
-
if (cells(clean) <= width) return clean;
|
|
87123
|
-
const available = Math.max(0, width - cells(ellipsis));
|
|
87124
|
-
let result = "", used = 0;
|
|
87125
|
-
for (const { segment } of segments.segment(clean)) {
|
|
87126
|
-
const size = graphemeWidth(segment);
|
|
87127
|
-
if (used + size > available) break;
|
|
87128
|
-
result += segment;
|
|
87129
|
-
used += size;
|
|
87130
|
-
}
|
|
87131
|
-
return width > 0 ? result + (cells(ellipsis) <= width ? ellipsis : "") : "";
|
|
87132
|
-
}
|
|
87133
|
-
function padCells(value, width) {
|
|
87134
|
-
const trimmed = truncateCells(value, width);
|
|
87135
|
-
return trimmed + " ".repeat(Math.max(0, width - cells(trimmed)));
|
|
87136
|
-
}
|
|
87137
|
-
function sliceCells(value, start, width) {
|
|
87138
|
-
start = Math.max(0, Math.floor(start));
|
|
87139
|
-
width = Math.max(0, Math.floor(width));
|
|
87140
|
-
const end = start + width;
|
|
87141
|
-
let position = 0, result = "";
|
|
87142
|
-
for (const { segment } of segments.segment(terminalText(value).replace(/\n/g, " "))) {
|
|
87143
|
-
const size = graphemeWidth(segment), next = position + size;
|
|
87144
|
-
if (next > start && position < end) {
|
|
87145
|
-
result += position >= start && next <= end ? segment : " ".repeat(Math.min(end, next) - Math.max(start, position));
|
|
87146
|
-
}
|
|
87147
|
-
position = next;
|
|
87148
|
-
if (position >= end) break;
|
|
87149
|
-
}
|
|
87150
|
-
return result + " ".repeat(Math.max(0, width - cells(result)));
|
|
87151
|
-
}
|
|
87152
|
-
function wrapCells(value, width) {
|
|
87153
|
-
width = Math.max(1, width);
|
|
87154
|
-
const result = [];
|
|
87155
|
-
for (const line of terminalText(value).split("\n")) {
|
|
87156
|
-
let text7 = "", used = 0;
|
|
87157
|
-
for (const { segment } of segments.segment(line)) {
|
|
87158
|
-
const size = graphemeWidth(segment);
|
|
87159
|
-
if (size > width) {
|
|
87160
|
-
if (text7) result.push(text7);
|
|
87161
|
-
result.push("?");
|
|
87162
|
-
text7 = "";
|
|
87163
|
-
used = 0;
|
|
87164
|
-
continue;
|
|
87165
|
-
}
|
|
87166
|
-
if (used + size > width) {
|
|
87167
|
-
result.push(text7);
|
|
87168
|
-
text7 = "";
|
|
87169
|
-
used = 0;
|
|
87170
|
-
}
|
|
87171
|
-
text7 += segment;
|
|
87172
|
-
used += size;
|
|
87173
|
-
}
|
|
87174
|
-
result.push(text7);
|
|
87175
|
-
}
|
|
87176
|
-
return result;
|
|
87177
|
-
}
|
|
87178
|
-
function eraseGrapheme(value) {
|
|
87179
|
-
const items = [...segments.segment(value)];
|
|
87180
|
-
return items.length ? value.slice(0, items[items.length - 1].index) : "";
|
|
87181
|
-
}
|
|
87182
|
-
function moveGraphemeCursor(value, cursor, direction) {
|
|
87183
|
-
const boundaries = [...segments.segment(value)].map((item) => item.index);
|
|
87184
|
-
boundaries.push(value.length);
|
|
87185
|
-
return direction < 0 ? boundaries.filter((index) => index < cursor).at(-1) ?? 0 : boundaries.find((index) => index > cursor) ?? value.length;
|
|
87186
|
-
}
|
|
87187
|
-
var lineText = (line) => typeof line === "string" ? line : line.text;
|
|
87188
|
-
var rgb = (hex) => [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16));
|
|
87189
|
-
function colorSequence(color, mode, background) {
|
|
87190
|
-
if (mode === "none") return "";
|
|
87191
|
-
if (mode === "truecolor") return `\x1B[${background ? 48 : 38};2;${color.join(";")}m`;
|
|
87192
|
-
if (mode === "ansi256") {
|
|
87193
|
-
const level = (v) => Math.round(v / 255 * 5);
|
|
87194
|
-
return `\x1B[${background ? 48 : 38};5;${16 + 36 * level(color[0]) + 6 * level(color[1]) + level(color[2])}m`;
|
|
87195
|
-
}
|
|
87196
|
-
const [r, g, b] = color;
|
|
87197
|
-
const index = (r > 100 ? 1 : 0) + (g > 100 ? 2 : 0) + (b > 100 ? 4 : 0);
|
|
87198
|
-
return `\x1B[${(background ? 40 : 30) + index}m`;
|
|
87199
|
-
}
|
|
87200
|
-
function foreground(value, color, mode, bold = false) {
|
|
87201
|
-
return mode === "none" ? value : `${bold ? "\x1B[1m" : ""}${colorSequence(rgb(color), mode, false)}${value}\x1B[0m`;
|
|
87202
|
-
}
|
|
87203
|
-
function backgroundLine(value, width, color, mode, bold = false) {
|
|
87204
|
-
const line = padCells(value, width);
|
|
87205
|
-
if (mode === "none") return line;
|
|
87206
|
-
const white = mode === "ansi16" ? "\x1B[97m" : colorSequence([255, 255, 255], mode, false);
|
|
87207
|
-
return `${bold ? "\x1B[1m" : ""}${white}${colorSequence(rgb(color), mode, true)}${line}\x1B[0m`;
|
|
87208
|
-
}
|
|
87209
|
-
|
|
87210
87450
|
// src/tuiProjectsWorkspace.ts
|
|
87211
87451
|
function contextFor(client2, project) {
|
|
87212
87452
|
const teamId = project ? project.teamId : client2.getActiveTeamId();
|
|
@@ -88431,7 +88671,7 @@ async function refreshTuiChatSidebar(state, client2, render, includeProjects = f
|
|
|
88431
88671
|
render();
|
|
88432
88672
|
}
|
|
88433
88673
|
} catch {
|
|
88434
|
-
if (current()) {
|
|
88674
|
+
if (current() && !state.status) {
|
|
88435
88675
|
state.status = "Running chat status unavailable.";
|
|
88436
88676
|
render();
|
|
88437
88677
|
}
|
|
@@ -88724,6 +88964,9 @@ function centeredCarouselText(text7, width) {
|
|
|
88724
88964
|
return " ".repeat(Math.max(0, Math.floor((width - cells(value)) / 2))) + value;
|
|
88725
88965
|
}
|
|
88726
88966
|
|
|
88967
|
+
// src/tuiHome.ts
|
|
88968
|
+
import { createHash as createHash21 } from "crypto";
|
|
88969
|
+
|
|
88727
88970
|
// ../workspaceInspirationDefaults.ts
|
|
88728
88971
|
function getWorkspaceInspirations(surface) {
|
|
88729
88972
|
const now = Math.floor(Date.now() / 1e3);
|
|
@@ -88924,7 +89167,235 @@ function getWorkspaceInspirations(surface) {
|
|
|
88924
89167
|
];
|
|
88925
89168
|
}
|
|
88926
89169
|
|
|
89170
|
+
// ../ui/src/services/continueCarouselService.ts
|
|
89171
|
+
var HOUR_MS = 60 * 60 * 1e3;
|
|
89172
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
89173
|
+
var UPCOMING_WINDOW_MS = 24 * HOUR_MS;
|
|
89174
|
+
var RECENT_WINDOW_MS = 12 * HOUR_MS;
|
|
89175
|
+
function asString(value) {
|
|
89176
|
+
return typeof value === "string" ? value.trim() : "";
|
|
89177
|
+
}
|
|
89178
|
+
function parseTime(value) {
|
|
89179
|
+
const raw = asString(value);
|
|
89180
|
+
if (!raw) return null;
|
|
89181
|
+
const parsed = new Date(raw).getTime();
|
|
89182
|
+
return Number.isNaN(parsed) ? null : parsed;
|
|
89183
|
+
}
|
|
89184
|
+
function parseDateOnlyEnd(value) {
|
|
89185
|
+
const raw = asString(value);
|
|
89186
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(raw)) return null;
|
|
89187
|
+
const parsed = (/* @__PURE__ */ new Date(`${raw}T23:59:59.999`)).getTime();
|
|
89188
|
+
return Number.isNaN(parsed) ? null : parsed;
|
|
89189
|
+
}
|
|
89190
|
+
function formatRelativeLabel(prefix, timestamp, nowMs) {
|
|
89191
|
+
const diffMs = timestamp - nowMs;
|
|
89192
|
+
const absMinutes = Math.max(1, Math.round(Math.abs(diffMs) / 6e4));
|
|
89193
|
+
if (absMinutes < 60) {
|
|
89194
|
+
return diffMs >= 0 ? `${prefix} in ${absMinutes}m` : `${prefix} ${absMinutes}m ago`;
|
|
89195
|
+
}
|
|
89196
|
+
const hours = Math.max(1, Math.round(absMinutes / 60));
|
|
89197
|
+
if (hours < 24) {
|
|
89198
|
+
return diffMs >= 0 ? `${prefix} in ${hours}h` : `${prefix} ${hours}h ago`;
|
|
89199
|
+
}
|
|
89200
|
+
const days = Math.max(1, Math.round(hours / 24));
|
|
89201
|
+
return diffMs >= 0 ? `${prefix} in ${days}d` : `${prefix} ${days}d ago`;
|
|
89202
|
+
}
|
|
89203
|
+
function formatDateOnlyLabel(prefix, timestamp, nowMs) {
|
|
89204
|
+
const targetDate = new Date(timestamp);
|
|
89205
|
+
const currentDate = new Date(nowMs);
|
|
89206
|
+
targetDate.setHours(0, 0, 0, 0);
|
|
89207
|
+
currentDate.setHours(0, 0, 0, 0);
|
|
89208
|
+
const dayDifference = Math.round((targetDate.getTime() - currentDate.getTime()) / DAY_MS);
|
|
89209
|
+
if (dayDifference === 0) return `${prefix} today`;
|
|
89210
|
+
if (dayDifference === 1) return `${prefix} tomorrow`;
|
|
89211
|
+
if (dayDifference === -1) return `${prefix} yesterday`;
|
|
89212
|
+
return dayDifference > 0 ? `${prefix} in ${dayDifference}d` : `${prefix} ${Math.abs(dayDifference)}d ago`;
|
|
89213
|
+
}
|
|
89214
|
+
function buildReminderPriority(reminder, nowMs = Date.now()) {
|
|
89215
|
+
const triggerMs = reminder.trigger_at * 1e3;
|
|
89216
|
+
if (!Number.isFinite(triggerMs) || triggerMs <= 0) return null;
|
|
89217
|
+
if (triggerMs <= nowMs) {
|
|
89218
|
+
if (nowMs - triggerMs > RECENT_WINDOW_MS && reminder.status !== "pending") return null;
|
|
89219
|
+
return {
|
|
89220
|
+
reason: "reminder_due",
|
|
89221
|
+
label: formatRelativeLabel("Reminder", triggerMs, nowMs),
|
|
89222
|
+
timestamp: triggerMs
|
|
89223
|
+
};
|
|
89224
|
+
}
|
|
89225
|
+
if (triggerMs - nowMs > UPCOMING_WINDOW_MS) return null;
|
|
89226
|
+
return {
|
|
89227
|
+
reason: "reminder_soon",
|
|
89228
|
+
label: formatRelativeLabel("Reminder", triggerMs, nowMs),
|
|
89229
|
+
timestamp: triggerMs
|
|
89230
|
+
};
|
|
89231
|
+
}
|
|
89232
|
+
function getSavedItemTimeWindow(itemValue) {
|
|
89233
|
+
const exactStartMs = parseTime(itemValue.date_start) ?? parseTime(itemValue.departure) ?? parseTime(itemValue.start_time) ?? parseTime(itemValue.starts_at) ?? parseTime(itemValue.datetime) ?? parseTime(itemValue.appointment_time);
|
|
89234
|
+
const dateOnlyStartMs = exactStartMs === null ? parseDateOnlyEnd(itemValue.date) : null;
|
|
89235
|
+
const startMs = exactStartMs ?? dateOnlyStartMs ?? parseTime(itemValue.available_from);
|
|
89236
|
+
const endMs = parseTime(itemValue.date_end) ?? parseTime(itemValue.arrival) ?? parseTime(itemValue.end_time) ?? parseTime(itemValue.ends_at) ?? parseTime(itemValue.checkout) ?? parseTime(itemValue.available_until);
|
|
89237
|
+
return { startMs, endMs, startIsDateOnly: dateOnlyStartMs !== null };
|
|
89238
|
+
}
|
|
89239
|
+
function getSavedItemPriority(itemValue, nowMs, itemLabel) {
|
|
89240
|
+
const { startMs, endMs, startIsDateOnly } = getSavedItemTimeWindow(itemValue);
|
|
89241
|
+
if (endMs && endMs >= nowMs && (!startMs || startMs <= nowMs)) {
|
|
89242
|
+
return {
|
|
89243
|
+
reason: "ongoing_saved_item",
|
|
89244
|
+
label: `${itemLabel} ongoing`,
|
|
89245
|
+
timestamp: endMs
|
|
89246
|
+
};
|
|
89247
|
+
}
|
|
89248
|
+
if (!startMs) return null;
|
|
89249
|
+
const startedRecently = startMs <= nowMs && nowMs - startMs <= RECENT_WINDOW_MS;
|
|
89250
|
+
const startsSoon = startMs > nowMs && startMs - nowMs <= UPCOMING_WINDOW_MS;
|
|
89251
|
+
if (!startedRecently && !startsSoon) return null;
|
|
89252
|
+
return {
|
|
89253
|
+
reason: "upcoming_saved_item",
|
|
89254
|
+
label: startIsDateOnly ? formatDateOnlyLabel(itemLabel, startMs, nowMs) : formatRelativeLabel(itemLabel, startMs, nowMs),
|
|
89255
|
+
timestamp: startMs
|
|
89256
|
+
};
|
|
89257
|
+
}
|
|
89258
|
+
function getSavedItemPresentation(appId, groupName, itemValue) {
|
|
89259
|
+
if (appId === "travel" || groupName.includes("connection")) {
|
|
89260
|
+
return {
|
|
89261
|
+
icon: "plane",
|
|
89262
|
+
category: "travel",
|
|
89263
|
+
itemLabel: "Trip",
|
|
89264
|
+
summary: [asString(itemValue.origin), asString(itemValue.destination), asString(itemValue.notes)].filter(Boolean).join(" \xB7 ") || null
|
|
89265
|
+
};
|
|
89266
|
+
}
|
|
89267
|
+
if (appId === "events" || groupName.includes("event")) {
|
|
89268
|
+
return {
|
|
89269
|
+
icon: "calendar-days",
|
|
89270
|
+
category: "events",
|
|
89271
|
+
itemLabel: "Event",
|
|
89272
|
+
summary: [asString(itemValue.location), asString(itemValue.provider)].filter(Boolean).join(" \xB7 ") || null
|
|
89273
|
+
};
|
|
89274
|
+
}
|
|
89275
|
+
if (appId === "health") {
|
|
89276
|
+
return {
|
|
89277
|
+
icon: "stethoscope",
|
|
89278
|
+
category: "health",
|
|
89279
|
+
itemLabel: "Appointment",
|
|
89280
|
+
summary: asString(itemValue.notes) || null
|
|
89281
|
+
};
|
|
89282
|
+
}
|
|
89283
|
+
if (appId === "home") {
|
|
89284
|
+
return {
|
|
89285
|
+
icon: "house",
|
|
89286
|
+
category: "home",
|
|
89287
|
+
itemLabel: "Listing",
|
|
89288
|
+
summary: [asString(itemValue.location), asString(itemValue.notes)].filter(Boolean).join(" \xB7 ") || null
|
|
89289
|
+
};
|
|
89290
|
+
}
|
|
89291
|
+
return {
|
|
89292
|
+
icon: "bookmark",
|
|
89293
|
+
category: null,
|
|
89294
|
+
itemLabel: "Saved item",
|
|
89295
|
+
summary: asString(itemValue.notes) || null
|
|
89296
|
+
};
|
|
89297
|
+
}
|
|
89298
|
+
function getReminderByTargetChatId(reminders, nowMs = Date.now()) {
|
|
89299
|
+
const byChat = /* @__PURE__ */ new Map();
|
|
89300
|
+
for (const reminder of reminders) {
|
|
89301
|
+
const chatId = asString(reminder.target_chat_id);
|
|
89302
|
+
if (!chatId) continue;
|
|
89303
|
+
const priority = buildReminderPriority(reminder, nowMs);
|
|
89304
|
+
if (!priority) continue;
|
|
89305
|
+
const existing = byChat.get(chatId);
|
|
89306
|
+
if (!existing || compareContinuePriority(priority, existing.priority, nowMs) < 0) {
|
|
89307
|
+
byChat.set(chatId, { reminder, priority });
|
|
89308
|
+
}
|
|
89309
|
+
}
|
|
89310
|
+
return byChat;
|
|
89311
|
+
}
|
|
89312
|
+
function getReminderByTargetEmbedId(reminders, nowMs = Date.now()) {
|
|
89313
|
+
const byEmbed = /* @__PURE__ */ new Map();
|
|
89314
|
+
for (const reminder of reminders) {
|
|
89315
|
+
const embedId = asString(reminder.target_embed_id);
|
|
89316
|
+
if (!embedId) continue;
|
|
89317
|
+
const priority = buildReminderPriority(reminder, nowMs);
|
|
89318
|
+
if (!priority) continue;
|
|
89319
|
+
const existing = byEmbed.get(embedId);
|
|
89320
|
+
if (!existing || compareContinuePriority(priority, existing.priority, nowMs) < 0) {
|
|
89321
|
+
byEmbed.set(embedId, { reminder, priority });
|
|
89322
|
+
}
|
|
89323
|
+
}
|
|
89324
|
+
return byEmbed;
|
|
89325
|
+
}
|
|
89326
|
+
function getSavedEmbedContinueCandidates(state, remindersByEmbedId = /* @__PURE__ */ new Map(), nowMs = Date.now()) {
|
|
89327
|
+
const candidates = [];
|
|
89328
|
+
for (const [appId, groups] of Array.from(state.entriesByApp.entries())) {
|
|
89329
|
+
for (const [groupName, entries] of Object.entries(groups)) {
|
|
89330
|
+
for (const entry of entries) {
|
|
89331
|
+
const itemValue = entry.item_value || {};
|
|
89332
|
+
const embedId = asString(itemValue.embed_id);
|
|
89333
|
+
if (!embedId) continue;
|
|
89334
|
+
const presentation = getSavedItemPresentation(appId, groupName, itemValue);
|
|
89335
|
+
const reminderMatch = remindersByEmbedId.get(embedId);
|
|
89336
|
+
const { startMs, endMs } = getSavedItemTimeWindow(itemValue);
|
|
89337
|
+
const priority = startMs || endMs ? getSavedItemPriority(itemValue, nowMs, presentation.itemLabel) : reminderMatch?.priority;
|
|
89338
|
+
if (!priority) continue;
|
|
89339
|
+
candidates.push({
|
|
89340
|
+
kind: "embed",
|
|
89341
|
+
embedId,
|
|
89342
|
+
appId,
|
|
89343
|
+
title: asString(itemValue.title) || asString(itemValue.name) || presentation.itemLabel,
|
|
89344
|
+
summary: presentation.summary,
|
|
89345
|
+
icon: presentation.icon,
|
|
89346
|
+
category: presentation.category,
|
|
89347
|
+
itemValue,
|
|
89348
|
+
priority
|
|
89349
|
+
});
|
|
89350
|
+
}
|
|
89351
|
+
}
|
|
89352
|
+
}
|
|
89353
|
+
return sortContinuePriorityItems(candidates, nowMs);
|
|
89354
|
+
}
|
|
89355
|
+
function priorityRank(priority) {
|
|
89356
|
+
switch (priority.reason) {
|
|
89357
|
+
case "reminder_due":
|
|
89358
|
+
return 0;
|
|
89359
|
+
case "reminder_soon":
|
|
89360
|
+
return 1;
|
|
89361
|
+
case "ongoing_saved_item":
|
|
89362
|
+
return 2;
|
|
89363
|
+
case "upcoming_saved_item":
|
|
89364
|
+
return 3;
|
|
89365
|
+
}
|
|
89366
|
+
}
|
|
89367
|
+
function compareContinuePriority(a, b, nowMs = Date.now()) {
|
|
89368
|
+
const rankDiff = priorityRank(a) - priorityRank(b);
|
|
89369
|
+
if (rankDiff !== 0) return rankDiff;
|
|
89370
|
+
if (a.reason === "reminder_due") {
|
|
89371
|
+
return Math.abs(nowMs - a.timestamp) - Math.abs(nowMs - b.timestamp);
|
|
89372
|
+
}
|
|
89373
|
+
return Math.abs(a.timestamp - nowMs) - Math.abs(b.timestamp - nowMs);
|
|
89374
|
+
}
|
|
89375
|
+
function sortContinuePriorityItems(items, nowMs = Date.now()) {
|
|
89376
|
+
return [...items].sort((a, b) => compareContinuePriority(a.priority, b.priority, nowMs));
|
|
89377
|
+
}
|
|
89378
|
+
|
|
88927
89379
|
// src/tuiHome.ts
|
|
89380
|
+
function homeContinueItems(state, now = Date.now()) {
|
|
89381
|
+
const chats = homeChatItems(state);
|
|
89382
|
+
if (!state.signedIn || !state.continueData) return chats.map((chat) => ({ kind: "chat", chat }));
|
|
89383
|
+
const entriesByApp = /* @__PURE__ */ new Map();
|
|
89384
|
+
for (const memory of state.continueData.memories) {
|
|
89385
|
+
const groups = entriesByApp.get(memory.app_id) ?? {};
|
|
89386
|
+
const group = memory.item_type;
|
|
89387
|
+
(groups[group] ??= []).push({ id: memory.id, item_key: memory.item_key_hash, item_value: memory.data, settings_group: group });
|
|
89388
|
+
entriesByApp.set(memory.app_id, groups);
|
|
89389
|
+
}
|
|
89390
|
+
const reminders = state.continueData.reminders;
|
|
89391
|
+
const reminderChats = getReminderByTargetChatId(reminders, now);
|
|
89392
|
+
const priorityChats = chats.filter((chat) => reminderChats.has(chat.id) && !chat.parentId && !chat.isSubChat && chat.id !== state.activeChatId).map((chat) => ({ kind: "chat", chat, priority: reminderChats.get(chat.id).priority }));
|
|
89393
|
+
const embeds = getSavedEmbedContinueCandidates({ entriesByApp }, getReminderByTargetEmbedId(reminders, now), now).filter((item) => `${item.title} ${item.summary ?? ""} ${item.priority.label}`.toLowerCase().includes(state.filter.toLowerCase()));
|
|
89394
|
+
const priority = sortContinuePriorityItems([...priorityChats, ...embeds], now).slice(0, 10);
|
|
89395
|
+
const promoted = new Set(priority.filter((item) => item.kind === "chat").map((item) => item.chat.id));
|
|
89396
|
+
return [...priority, ...chats.filter((chat) => !promoted.has(chat.id)).map((chat) => ({ kind: "chat", chat }))];
|
|
89397
|
+
}
|
|
89398
|
+
var homeItemId = (item) => item?.kind === "embed" ? `embed:${item.embedId}` : item ? `chat:${item.chat.id}` : void 0;
|
|
88928
89399
|
var BLUE = { start: "#4867cd", end: "#5a85eb" };
|
|
88929
89400
|
var prompts = {
|
|
88930
89401
|
chats: "What do you need help with?",
|
|
@@ -88949,12 +89420,12 @@ function currentInspiration(state) {
|
|
|
88949
89420
|
}
|
|
88950
89421
|
function updateHomeChats(state, chats) {
|
|
88951
89422
|
const preserveSelection = isWorkspaceHome(state) && state.workspace === "chats";
|
|
88952
|
-
const selectedId = preserveSelection ?
|
|
89423
|
+
const selectedId = preserveSelection ? homeItemId(homeContinueItems(state)[state.selectedIndex]) : void 0;
|
|
88953
89424
|
updateTuiChatSidebar(state, () => {
|
|
88954
89425
|
state.recentChats = chats;
|
|
88955
89426
|
});
|
|
88956
89427
|
if (preserveSelection) {
|
|
88957
|
-
const items =
|
|
89428
|
+
const items = homeContinueItems(state), index = items.findIndex((item) => homeItemId(item) === selectedId);
|
|
88958
89429
|
state.selectedIndex = index >= 0 ? index : Math.max(0, Math.min(state.selectedIndex, items.length - 1));
|
|
88959
89430
|
}
|
|
88960
89431
|
}
|
|
@@ -88963,7 +89434,26 @@ async function loadHomeData(state, client2, render) {
|
|
|
88963
89434
|
const controller = new AbortController();
|
|
88964
89435
|
state.homeAbortController = controller;
|
|
88965
89436
|
const request = ++state.homeLoadVersion, signedIn = state.signedIn;
|
|
88966
|
-
const
|
|
89437
|
+
const teamId = typeof client2.getActiveTeamId === "function" ? client2.getActiveTeamId() : null;
|
|
89438
|
+
const masterKey = signedIn && typeof client2.getMasterKeyBytes === "function" ? Buffer.from(client2.getMasterKeyBytes()) : null;
|
|
89439
|
+
const contextKey = `${teamId ?? "personal"}:${masterKey ? createHash21("sha256").update(masterKey).digest("hex") : signedIn}`;
|
|
89440
|
+
if (state.homeContextKey && state.homeContextKey !== contextKey) {
|
|
89441
|
+
state.continueData = null;
|
|
89442
|
+
state.recentChats = [];
|
|
89443
|
+
state.activityChats = [];
|
|
89444
|
+
state.sidebarLinkedChats = [];
|
|
89445
|
+
state.chatSidebarProjects = [];
|
|
89446
|
+
}
|
|
89447
|
+
state.homeContextKey = contextKey;
|
|
89448
|
+
const current = () => {
|
|
89449
|
+
if (controller.signal.aborted || request !== state.homeLoadVersion || state.signedIn !== signedIn) return false;
|
|
89450
|
+
if (typeof client2.getActiveTeamId === "function" && client2.getActiveTeamId() !== teamId) return false;
|
|
89451
|
+
try {
|
|
89452
|
+
return !masterKey || (typeof client2.hasSession !== "function" || client2.hasSession()) && masterKey.equals(Buffer.from(client2.getMasterKeyBytes()));
|
|
89453
|
+
} catch {
|
|
89454
|
+
return false;
|
|
89455
|
+
}
|
|
89456
|
+
};
|
|
88967
89457
|
state.homeLoading = true;
|
|
88968
89458
|
state.homeError = null;
|
|
88969
89459
|
state.homeChatsLoading = signedIn && homeChatItems(state).length === 0;
|
|
@@ -88978,7 +89468,58 @@ async function loadHomeData(state, client2, render) {
|
|
|
88978
89468
|
state.homeChatsLoading = homeChatItems(state).length === 0;
|
|
88979
89469
|
render();
|
|
88980
89470
|
}
|
|
89471
|
+
const updateContinue = (data) => {
|
|
89472
|
+
const selected = homeItemId(homeContinueItems(state)[state.selectedIndex]);
|
|
89473
|
+
state.continueData = data;
|
|
89474
|
+
if (state.homeSelectionMoved || state.selectedIndex > 0) {
|
|
89475
|
+
const index = homeContinueItems(state).findIndex((item) => homeItemId(item) === selected);
|
|
89476
|
+
state.selectedIndex = index < 0 ? 0 : index;
|
|
89477
|
+
} else state.selectedIndex = 0;
|
|
89478
|
+
render();
|
|
89479
|
+
};
|
|
89480
|
+
if (signedIn && typeof client2.getCachedContinueItems === "function") {
|
|
89481
|
+
try {
|
|
89482
|
+
const cached = await client2.getCachedContinueItems();
|
|
89483
|
+
if (!current()) return;
|
|
89484
|
+
if (cached) updateContinue(cached);
|
|
89485
|
+
} catch {
|
|
89486
|
+
if (!current()) return;
|
|
89487
|
+
}
|
|
89488
|
+
}
|
|
88981
89489
|
const work = [];
|
|
89490
|
+
let continueRefresh;
|
|
89491
|
+
const refreshContinue = () => {
|
|
89492
|
+
if (!continueRefresh && signedIn && typeof client2.getContinueItems === "function") {
|
|
89493
|
+
continueRefresh = client2.getContinueItems().then((data) => {
|
|
89494
|
+
if (!current()) return;
|
|
89495
|
+
updateContinue(data);
|
|
89496
|
+
if (typeof client2.getEmbed !== "function") return;
|
|
89497
|
+
const saved = homeContinueItems(state).filter((item) => item.kind === "embed").slice(0, 10);
|
|
89498
|
+
let next = 0;
|
|
89499
|
+
void Promise.all(Array.from({ length: Math.min(3, saved.length) }, async () => {
|
|
89500
|
+
while (current() && next < saved.length) {
|
|
89501
|
+
const item = saved[next++];
|
|
89502
|
+
try {
|
|
89503
|
+
await client2.getEmbed(item.embedId, { preferCache: true });
|
|
89504
|
+
} catch {
|
|
89505
|
+
if (!current()) return;
|
|
89506
|
+
}
|
|
89507
|
+
}
|
|
89508
|
+
}));
|
|
89509
|
+
}).catch(() => {
|
|
89510
|
+
});
|
|
89511
|
+
}
|
|
89512
|
+
return continueRefresh ?? Promise.resolve();
|
|
89513
|
+
};
|
|
89514
|
+
if (!teamId) work.push(refreshContinue());
|
|
89515
|
+
let warming;
|
|
89516
|
+
const warmRecent = () => {
|
|
89517
|
+
if (!current() || warming || typeof client2.cacheRecentChatMessages !== "function") return;
|
|
89518
|
+
warming = client2.cacheRecentChatMessages({ signal: controller.signal }).catch(() => {
|
|
89519
|
+
}).finally(() => {
|
|
89520
|
+
warming = void 0;
|
|
89521
|
+
});
|
|
89522
|
+
};
|
|
88982
89523
|
if (typeof client2.getDailyInspirations === "function") work.push(client2.getDailyInspirations().then((list) => {
|
|
88983
89524
|
if (current()) {
|
|
88984
89525
|
state.inspirations = list;
|
|
@@ -89003,10 +89544,15 @@ async function loadHomeData(state, client2, render) {
|
|
|
89003
89544
|
updateHomeChats(state, page.chats);
|
|
89004
89545
|
state.homeChatsLoading = false;
|
|
89005
89546
|
render();
|
|
89547
|
+
warmRecent();
|
|
89548
|
+
if (teamId) void refreshContinue();
|
|
89006
89549
|
}
|
|
89007
|
-
} }).then((page) => {
|
|
89550
|
+
} }).then(async (page) => {
|
|
89008
89551
|
if (current()) {
|
|
89009
89552
|
updateHomeChats(state, page.chats);
|
|
89553
|
+
warmRecent();
|
|
89554
|
+
if (teamId) await refreshContinue();
|
|
89555
|
+
if (!current()) return;
|
|
89010
89556
|
if (page.pendingRecoveryOutputs) state.status = "Some saved AI outputs are pending recovery. Use /refresh to retry.";
|
|
89011
89557
|
render();
|
|
89012
89558
|
}
|
|
@@ -89031,6 +89577,19 @@ async function loadHomeData(state, client2, render) {
|
|
|
89031
89577
|
render();
|
|
89032
89578
|
}
|
|
89033
89579
|
}
|
|
89580
|
+
function startHomeSync(state, client2, render, closed) {
|
|
89581
|
+
let refreshing = false;
|
|
89582
|
+
const timer = setInterval(() => {
|
|
89583
|
+
if (closed() || state.startup || !state.signedIn || state.homeLoading || refreshing) return;
|
|
89584
|
+
refreshing = true;
|
|
89585
|
+
void loadHomeData(state, client2, render).catch(() => {
|
|
89586
|
+
}).finally(() => {
|
|
89587
|
+
refreshing = false;
|
|
89588
|
+
});
|
|
89589
|
+
}, 6e4);
|
|
89590
|
+
timer.unref?.();
|
|
89591
|
+
return () => clearInterval(timer);
|
|
89592
|
+
}
|
|
89034
89593
|
var centered2 = centeredCarouselText;
|
|
89035
89594
|
function homeHeader(state, width, height) {
|
|
89036
89595
|
const inspiration = currentInspiration(state), rows2 = Math.max(4, Math.min(8, Math.floor(height / 5))), result = [];
|
|
@@ -89048,25 +89607,34 @@ function homeHeader(state, width, height) {
|
|
|
89048
89607
|
return result;
|
|
89049
89608
|
}
|
|
89050
89609
|
function renderHomeChatCards(state, width, height) {
|
|
89051
|
-
const
|
|
89610
|
+
const items = homeContinueItems(state), result = homeHeader(state, width, height);
|
|
89052
89611
|
const activeCount = runningTuiChatGroups(state).length;
|
|
89053
89612
|
if (activeCount) result.push(centered2(`${activeCount} ${activeCount === 1 ? "chat" : "chats"} active\u2026 /active`, width), "");
|
|
89054
|
-
if (!
|
|
89613
|
+
if (!items.length) {
|
|
89055
89614
|
result.push(centered2(state.homeChatsLoading ? "Loading your recent chats\u2026" : state.homeError || "Start a chat below. Your recent chats will appear here.", width), "");
|
|
89056
89615
|
return result;
|
|
89057
89616
|
}
|
|
89058
89617
|
result.push(centered2(state.signedIn ? "Continue where you left off" : "Explore example chats", width), "");
|
|
89059
|
-
const selected = Math.max(0, Math.min(
|
|
89060
|
-
result.push(...renderCardCarousel(
|
|
89061
|
-
|
|
89062
|
-
|
|
89063
|
-
|
|
89064
|
-
|
|
89065
|
-
|
|
89618
|
+
const selected = Math.max(0, Math.min(items.length - 1, state.selectedIndex));
|
|
89619
|
+
result.push(...renderCardCarousel(items.map((item) => {
|
|
89620
|
+
if (item.kind === "embed") return {
|
|
89621
|
+
title: item.title,
|
|
89622
|
+
description: item.summary || "Open saved item",
|
|
89623
|
+
footer: `${item.priority.label} \xB7 Saved`,
|
|
89624
|
+
background: (item.category && CATEGORY_GRADIENTS[item.category] || BLUE).start
|
|
89625
|
+
};
|
|
89626
|
+
const chat = item.chat;
|
|
89627
|
+
return {
|
|
89628
|
+
title: chat.title || chat.draftPreview || "Untitled chat",
|
|
89629
|
+
description: chat.hasDraft ? "Draft" : chat.summary || "Continue this conversation",
|
|
89630
|
+
footer: item.priority?.label || chat.category?.replaceAll("_", " ") || "Chat",
|
|
89631
|
+
background: (chat.category && CATEGORY_GRADIENTS[chat.category] || BLUE).start
|
|
89632
|
+
};
|
|
89633
|
+
}), width, selected, state.focus === "content"));
|
|
89066
89634
|
result.push(
|
|
89067
89635
|
"",
|
|
89068
|
-
centered2(`${selected > 0 ? "\u2039" : " "} Chat ${selected + 1} of ${
|
|
89069
|
-
centered2("\u2190/\u2192 choose
|
|
89636
|
+
centered2(`${selected > 0 ? "\u2039" : " "} ${items.some((item) => item.kind === "embed") ? "Item" : "Chat"} ${selected + 1} of ${items.length} ${selected < items.length - 1 ? "\u203A" : " "}`, width),
|
|
89637
|
+
centered2("\u2190/\u2192 choose \xB7 Enter open \xB7 Tab write", width),
|
|
89070
89638
|
"",
|
|
89071
89639
|
centered2("/search Search chats \xB7 Ctrl+N New chat", width)
|
|
89072
89640
|
);
|
|
@@ -89810,6 +90378,12 @@ function createInitialTuiState() {
|
|
|
89810
90378
|
homeError: null,
|
|
89811
90379
|
homeLoadVersion: 0,
|
|
89812
90380
|
homeShowAll: false,
|
|
90381
|
+
homeSelectionMoved: false,
|
|
90382
|
+
homeContextKey: null,
|
|
90383
|
+
continueData: null,
|
|
90384
|
+
detailEmbed: null,
|
|
90385
|
+
embedOrigin: null,
|
|
90386
|
+
embedChoices: [],
|
|
89813
90387
|
apps: [],
|
|
89814
90388
|
activeApp: null,
|
|
89815
90389
|
activeAppSkill: null,
|
|
@@ -90049,8 +90623,12 @@ function renderScreenBody(state, width, height) {
|
|
|
90049
90623
|
return state.activeProject ? state.projectTab === "tasks" ? [...blueHero(renderProjectIdentity(state.activeProject, { width }), renderProjectIdentity(state.activeProject, { width }).length), ...renderProjectTabs("tasks", width), "", ...renderTaskBoard2(state.tasks, { width, selectedTaskId: filterTasks(state.tasks, state.filter)[state.selectedIndex]?.taskId, query: state.filter })] : blueHero(renderProjectDetail(state.activeProject, { width, tab: state.projectTab, files: state.projectFiles, selectedFileId: filteredProjectFiles(state.projectFiles, state.filter)[state.selectedIndex]?.id, query: state.filter, folderId: state.projectFolderId ?? void 0, sourceId: state.projectSourceId ?? void 0, path: state.projectPath }), renderProjectIdentity(state.activeProject, { width }).length) : ["Projects", "Loading project\u2026"];
|
|
90050
90624
|
case "status":
|
|
90051
90625
|
return renderStatus(state, width);
|
|
90052
|
-
case "embed":
|
|
90053
|
-
|
|
90626
|
+
case "embed": {
|
|
90627
|
+
const app = state.detailEmbed?.appId ?? "", gradient = APP_GRADIENTS[app] ?? PRIMARY_GRADIENT;
|
|
90628
|
+
const title = state.detailTitle || "Embed";
|
|
90629
|
+
const header2 = [title, state.detailEmbed ? `${state.detailEmbed.type?.replaceAll("-", " ") ?? "Saved item"} \xB7 ${state.detailEmbed.embedId.slice(0, 8)}` : "Saved embeds"];
|
|
90630
|
+
return [...coloredHero(header2, header2.length, gradient), "", ...(state.embedChoices.length ? state.embedChoices.map((id, index) => `${index === state.selectedIndex ? ">" : " "} Embed ${index + 1} \xB7 ${id.slice(0, 8)} \xB7 Enter open`) : state.detailLines).flatMap((line) => wrap(line, width)), "", "\u2191/\u2193 scroll \xB7 PgUp/PgDn page \xB7 Esc back"];
|
|
90631
|
+
}
|
|
90054
90632
|
case "workflows":
|
|
90055
90633
|
return [...homeHeader(state, width, height), ...homeCards(state.workflows.filter((w) => w.title.toLowerCase().includes(state.filter.toLowerCase())).flatMap((w, i) => [...renderWorkflowPreviewCard(w, { width: Math.min(width, 88), selected: state.focus === "content" && i === state.selectedIndex }), ""]), width, []), "Show my workflows \xB7 /search Search"];
|
|
90056
90634
|
case "workflow":
|
|
@@ -90230,7 +90808,7 @@ function renderChat(state, width) {
|
|
|
90230
90808
|
}
|
|
90231
90809
|
function renderChatHeader(state, width) {
|
|
90232
90810
|
const chat = state.screen === "example" ? state.activeExample?.chat : state.activeChat;
|
|
90233
|
-
const title = state.headerState === "loading" && !chat?.title ? "Creating new chat\u2026" : state.headerState === "error" ? state.headerError || "Could not send message" : chat?.title || (state.messages.length ? "Chat" : "New chat");
|
|
90811
|
+
const title = state.headerState === "loading" && !chat?.title ? state.status === "Loading chat\u2026" ? "Loading chat\u2026" : "Creating new chat\u2026" : state.headerState === "error" ? state.headerError || "Could not send message" : chat?.title || (state.messages.length ? "Chat" : "New chat");
|
|
90234
90812
|
const category = chat?.category?.replaceAll("_", " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
|
|
90235
90813
|
const summary = chat?.summary || (state.messages.length ? "" : "What would you like to work on?");
|
|
90236
90814
|
const badges = state.screen === "example" ? "Example chat" : state.input && !state.messages.length ? "Draft" : "";
|
|
@@ -90521,6 +91099,7 @@ function route(state, workspace, screen) {
|
|
|
90521
91099
|
state.selectedIndex = 0;
|
|
90522
91100
|
state.sidebarIndex = 0;
|
|
90523
91101
|
state.homeShowAll = false;
|
|
91102
|
+
state.homeSelectionMoved = false;
|
|
90524
91103
|
state.status = null;
|
|
90525
91104
|
state.form = null;
|
|
90526
91105
|
state.workflowEdit = null;
|
|
@@ -90553,23 +91132,45 @@ async function recent(context) {
|
|
|
90553
91132
|
async function openSavedChat(context, id) {
|
|
90554
91133
|
const { state, client: client2, render } = context;
|
|
90555
91134
|
const request = route(state, "chats", "chat");
|
|
90556
|
-
state.
|
|
90557
|
-
|
|
90558
|
-
const result = await client2.getChatMessages(id);
|
|
90559
|
-
if (state.routeVersion !== request) return;
|
|
90560
|
-
state.activeChatId = result.chat.id;
|
|
90561
|
-
state.activeChat = result.chat;
|
|
91135
|
+
state.activeChatId = id;
|
|
91136
|
+
state.activeChat = [...state.recentChats, ...state.sidebarLinkedChats, ...state.activityChats].find((chat) => chat.id === id) ?? null;
|
|
90562
91137
|
state.activeExample = null;
|
|
90563
|
-
state.
|
|
90564
|
-
state.
|
|
90565
|
-
state.
|
|
90566
|
-
state.headerState = "ready";
|
|
90567
|
-
state.headerError = null;
|
|
90568
|
-
const remoteDraft = state.drafts[id] === void 0 && typeof client2.getDraft === "function" ? await client2.getDraft(result.chat.id) : null;
|
|
90569
|
-
if (state.routeVersion !== request) return;
|
|
90570
|
-
state.input = state.drafts[result.chat.id] ?? remoteDraft?.markdown ?? "";
|
|
90571
|
-
state.status = null;
|
|
91138
|
+
state.messages = [];
|
|
91139
|
+
state.headerState = state.activeChat ? "ready" : "loading";
|
|
91140
|
+
state.status = "Loading chat\u2026";
|
|
90572
91141
|
render();
|
|
91142
|
+
let published = false;
|
|
91143
|
+
const publish = (result2, pending = false) => {
|
|
91144
|
+
if (state.routeVersion !== request) return;
|
|
91145
|
+
state.activeChatId = result2.chat.id;
|
|
91146
|
+
state.activeChat = result2.chat;
|
|
91147
|
+
state.activeExample = null;
|
|
91148
|
+
state.selectedProjectId = null;
|
|
91149
|
+
state.messages = result2.messages.map((m) => ({ id: m.id, role: m.role === "user" ? "user" : m.role === "system" ? "system" : "assistant", content: m.content, title: m.senderName, embedIds: m.embedIds }));
|
|
91150
|
+
state.projectFocusPending = null;
|
|
91151
|
+
state.headerState = "ready";
|
|
91152
|
+
state.headerError = null;
|
|
91153
|
+
if (!published) state.input = state.drafts[result2.chat.id] ?? "";
|
|
91154
|
+
state.status = pending ? "Loading older messages\u2026" : result2.historyIncomplete ? "Showing cached recent messages. Older history is unavailable offline." : null;
|
|
91155
|
+
render();
|
|
91156
|
+
if (!published && state.drafts[result2.chat.id] === void 0) {
|
|
91157
|
+
const inputAtOpen = state.input;
|
|
91158
|
+
const draft = typeof client2.getCachedDraft === "function" ? client2.getCachedDraft(result2.chat.id) : typeof client2.getDraft === "function" ? client2.getDraft(result2.chat.id) : Promise.resolve(null);
|
|
91159
|
+
void draft.then((remoteDraft) => {
|
|
91160
|
+
if (state.routeVersion !== request || state.input !== inputAtOpen || state.drafts[result2.chat.id] !== void 0) return;
|
|
91161
|
+
state.input = remoteDraft?.markdown ?? "";
|
|
91162
|
+
render();
|
|
91163
|
+
}).catch(() => {
|
|
91164
|
+
if (state.routeVersion === request && !state.status) {
|
|
91165
|
+
state.status = "Saved draft unavailable.";
|
|
91166
|
+
render();
|
|
91167
|
+
}
|
|
91168
|
+
});
|
|
91169
|
+
}
|
|
91170
|
+
published = true;
|
|
91171
|
+
};
|
|
91172
|
+
const result = await client2.getChatMessages(id, { preferCache: true, onMessages: (latest) => publish(latest, true) });
|
|
91173
|
+
publish(result);
|
|
90573
91174
|
}
|
|
90574
91175
|
async function openProject(context, id) {
|
|
90575
91176
|
const { state, client: client2, render } = context;
|
|
@@ -90978,7 +91579,8 @@ async function handleWorkspaceCommand(context, command) {
|
|
|
90978
91579
|
case "/chat-create-project": {
|
|
90979
91580
|
if (state.chatProjectBusy) return true;
|
|
90980
91581
|
if (!state.signedIn) throw new Error("Sign in to organize chats.");
|
|
90981
|
-
const
|
|
91582
|
+
const homeItem = homeContinueItems(state)[state.selectedIndex];
|
|
91583
|
+
const selected = state.focus === "sidebar" ? tuiChatSidebarRows(state)[state.sidebarIndex]?.chatId : ["start", "chats"].includes(state.screen) ? homeItem?.kind === "chat" ? homeItem.chat.id : void 0 : state.activeChatId;
|
|
90982
91584
|
const ids = arg ? arg.split(/\s+/).filter(Boolean) : selected ? [selected] : [];
|
|
90983
91585
|
if (!ids.length) throw new Error("Choose a saved chat first.");
|
|
90984
91586
|
await refreshTuiChatSidebar(state, client2, render, true);
|
|
@@ -91114,29 +91716,47 @@ async function handleWorkspaceCommand(context, command) {
|
|
|
91114
91716
|
return true;
|
|
91115
91717
|
}
|
|
91116
91718
|
case "/embed": {
|
|
91719
|
+
if (state.screen !== "embed") state.embedOrigin = { screen: state.screen, workspace: state.workspace, focus: state.focus, selectedIndex: state.selectedIndex, scrollOffset: state.scrollOffset, filter: state.filter, input: state.input };
|
|
91117
91720
|
const request = route(state, state.workspace, "embed");
|
|
91118
91721
|
state.detailTitle = "Embeds";
|
|
91722
|
+
state.detailEmbed = null;
|
|
91723
|
+
state.focus = "content";
|
|
91724
|
+
state.detailLines = ["Loading saved embed\u2026"];
|
|
91725
|
+
render();
|
|
91119
91726
|
if (!arg) {
|
|
91120
91727
|
const ids = [...new Set(state.messages.flatMap((message) => message.embedIds ?? []))];
|
|
91728
|
+
state.embedChoices = ids;
|
|
91121
91729
|
state.detailLines = ids.length ? ids.map((id) => `/embed ${id}`) : ["No saved embeds in this chat yet."];
|
|
91122
91730
|
} else {
|
|
91123
|
-
|
|
91124
|
-
|
|
91125
|
-
|
|
91126
|
-
|
|
91127
|
-
|
|
91128
|
-
|
|
91129
|
-
|
|
91130
|
-
|
|
91131
|
-
|
|
91132
|
-
|
|
91133
|
-
|
|
91134
|
-
|
|
91135
|
-
|
|
91136
|
-
|
|
91137
|
-
|
|
91138
|
-
|
|
91139
|
-
|
|
91731
|
+
try {
|
|
91732
|
+
const example = state.activeExample?.embeds?.find((embed2) => embed2.embed_id === arg);
|
|
91733
|
+
const content = example ? parseEmbedContentObject(example.content) : null;
|
|
91734
|
+
const embed = example && content ? {
|
|
91735
|
+
id: arg,
|
|
91736
|
+
embedId: arg,
|
|
91737
|
+
type: example.type,
|
|
91738
|
+
content,
|
|
91739
|
+
textPreview: null,
|
|
91740
|
+
appId: typeof content.app_id === "string" ? content.app_id : null,
|
|
91741
|
+
skillId: typeof content.skill_id === "string" ? content.skill_id : null,
|
|
91742
|
+
createdAt: null
|
|
91743
|
+
} : await client2.getEmbed(arg, { preferCache: true, chatId: state.activeChatId ?? void 0 });
|
|
91744
|
+
if (request !== state.routeVersion) return true;
|
|
91745
|
+
state.detailTitle = embed.textPreview || (embed.appId ? `${embed.appId}${embed.skillId ? `/${embed.skillId}` : ""}` : embed.type?.replaceAll("_", " ")) || "Embed";
|
|
91746
|
+
state.detailEmbed = embed;
|
|
91747
|
+
state.embedChoices = [];
|
|
91748
|
+
const cachedClient = Object.create(client2);
|
|
91749
|
+
cachedClient.getEmbed = (id, options) => client2.getEmbed(id, { ...options, preferCache: true, chatId: state.activeChatId ?? void 0 });
|
|
91750
|
+
const lines = await formatEmbedFullscreenLines(embed, cachedClient);
|
|
91751
|
+
if (request !== state.routeVersion) return true;
|
|
91752
|
+
state.detailLines = lines;
|
|
91753
|
+
} catch (error) {
|
|
91754
|
+
if (request !== state.routeVersion) return true;
|
|
91755
|
+
state.detailTitle = "Saved embed unavailable";
|
|
91756
|
+
state.detailLines = [error instanceof Error ? error.message : String(error), "", "Reconnect and use /refresh to retry."];
|
|
91757
|
+
state.detailEmbed = null;
|
|
91758
|
+
state.status = null;
|
|
91759
|
+
}
|
|
91140
91760
|
}
|
|
91141
91761
|
render();
|
|
91142
91762
|
return true;
|
|
@@ -91343,6 +91963,11 @@ async function handleWorkspaceKey(context, chunk, key) {
|
|
|
91343
91963
|
render();
|
|
91344
91964
|
return true;
|
|
91345
91965
|
}
|
|
91966
|
+
if (state.screen === "embed" && state.embedChoices.length && state.focus === "content" && ["up", "down"].includes(key.name ?? "")) {
|
|
91967
|
+
state.selectedIndex = Math.max(0, Math.min(state.embedChoices.length - 1, state.selectedIndex + (key.name === "up" ? -1 : 1)));
|
|
91968
|
+
render();
|
|
91969
|
+
return true;
|
|
91970
|
+
}
|
|
91346
91971
|
if (key.ctrl && key.name === "b") {
|
|
91347
91972
|
await handleWorkspaceCommand(context, "/sidebar");
|
|
91348
91973
|
return true;
|
|
@@ -91430,8 +92055,24 @@ async function handleWorkspaceKey(context, chunk, key) {
|
|
|
91430
92055
|
state.focus = "content";
|
|
91431
92056
|
state.scrollOffset = 0;
|
|
91432
92057
|
} else if (state.screen === "embed") {
|
|
91433
|
-
|
|
91434
|
-
state.
|
|
92058
|
+
const origin = state.embedOrigin;
|
|
92059
|
+
state.embedOrigin = null;
|
|
92060
|
+
state.detailEmbed = null;
|
|
92061
|
+
state.embedChoices = [];
|
|
92062
|
+
if (origin) {
|
|
92063
|
+
state.screen = origin.screen;
|
|
92064
|
+
state.workspace = origin.workspace;
|
|
92065
|
+
state.focus = origin.focus;
|
|
92066
|
+
state.selectedIndex = origin.selectedIndex;
|
|
92067
|
+
state.scrollOffset = origin.scrollOffset;
|
|
92068
|
+
state.filter = origin.filter;
|
|
92069
|
+
state.input = origin.input;
|
|
92070
|
+
state.inputCursor = null;
|
|
92071
|
+
} else {
|
|
92072
|
+
state.screen = state.workspace === "projects" ? "project" : "chats";
|
|
92073
|
+
state.focus = "content";
|
|
92074
|
+
}
|
|
92075
|
+
++state.routeVersion;
|
|
91435
92076
|
} else {
|
|
91436
92077
|
state.input = "";
|
|
91437
92078
|
state.focus = state.workspace === "chats" ? "composer" : "content";
|
|
@@ -91459,7 +92100,8 @@ async function handleWorkspaceKey(context, chunk, key) {
|
|
|
91459
92100
|
return true;
|
|
91460
92101
|
}
|
|
91461
92102
|
if (carouselHome && state.focus === "content" && (key.name === "left" || key.name === "right")) {
|
|
91462
|
-
const count = chatHome ?
|
|
92103
|
+
const count = chatHome ? homeContinueItems(state).length : homeTuiApps(state.apps, state.filter, state.homeShowAll).length;
|
|
92104
|
+
state.homeSelectionMoved = true;
|
|
91463
92105
|
state.selectedIndex = Math.max(0, Math.min(Math.max(0, count - 1), state.selectedIndex + (key.name === "left" ? -1 : 1)));
|
|
91464
92106
|
state.followSelection = true;
|
|
91465
92107
|
render();
|
|
@@ -91676,7 +92318,7 @@ async function handleWorkspaceKey(context, chunk, key) {
|
|
|
91676
92318
|
return true;
|
|
91677
92319
|
}
|
|
91678
92320
|
if (state.focus === "content" && (key.name === "up" || key.name === "down") && ["start", "tasks", "projects", "project", "chats"].includes(state.screen)) {
|
|
91679
|
-
const count = state.screen === "tasks" || state.screen === "project" && state.projectTab === "tasks" ? filterTasks(state.tasks, state.filter, state.taskStatusFilter || void 0).length : state.screen === "projects" ? filteredProjects(state.projects, state.filter).length : state.screen === "project" ? filteredProjectFiles(state.projectFiles, state.filter).length :
|
|
92321
|
+
const count = state.screen === "tasks" || state.screen === "project" && state.projectTab === "tasks" ? filterTasks(state.tasks, state.filter, state.taskStatusFilter || void 0).length : state.screen === "projects" ? filteredProjects(state.projects, state.filter).length : state.screen === "project" ? filteredProjectFiles(state.projectFiles, state.filter).length : homeContinueItems(state).length;
|
|
91680
92322
|
state.selectedIndex = Math.max(0, Math.min(count - 1, state.selectedIndex + (key.name === "up" ? -1 : 1)));
|
|
91681
92323
|
render();
|
|
91682
92324
|
return true;
|
|
@@ -91693,13 +92335,19 @@ async function handleWorkspaceKey(context, chunk, key) {
|
|
|
91693
92335
|
return true;
|
|
91694
92336
|
}
|
|
91695
92337
|
if (state.screen === "chats" || state.screen === "start") {
|
|
91696
|
-
const
|
|
91697
|
-
if (
|
|
92338
|
+
const item = homeContinueItems(state)[state.selectedIndex];
|
|
92339
|
+
if (item?.kind === "embed") await context.command(`/embed ${item.embedId}`);
|
|
92340
|
+
else if (item) {
|
|
92341
|
+
const chat = item.chat;
|
|
91698
92342
|
if (chat.source === "example") await context.command(`/example ${chat.slug || chat.id}`);
|
|
91699
92343
|
else await openSavedChat(context, chat.id);
|
|
91700
92344
|
}
|
|
91701
92345
|
return true;
|
|
91702
92346
|
}
|
|
92347
|
+
if (state.screen === "embed" && state.embedChoices.length) {
|
|
92348
|
+
await context.command(`/embed ${state.embedChoices[state.selectedIndex]}`);
|
|
92349
|
+
return true;
|
|
92350
|
+
}
|
|
91703
92351
|
}
|
|
91704
92352
|
if (state.focus === "composer") {
|
|
91705
92353
|
if (key.name === "return" && state.workspace !== "chats") {
|
|
@@ -91928,10 +92576,12 @@ async function runTui(client2, terminal = new TuiTerminal(), startupServices) {
|
|
|
91928
92576
|
terminal.render(renderTuiFrame(state, terminal.width, terminal.height, { colorMode: terminal.colorMode, ascii: terminal.ascii }));
|
|
91929
92577
|
}, 16);
|
|
91930
92578
|
};
|
|
92579
|
+
const stopHomeSync = startHomeSync(state, client2, render, () => closed);
|
|
91931
92580
|
const finish = (result2) => {
|
|
91932
92581
|
closed = true;
|
|
91933
92582
|
state.homeAbortController?.abort();
|
|
91934
92583
|
Object.values(state.chatContextAuthoringControls).forEach((control) => control.stop());
|
|
92584
|
+
stopHomeSync();
|
|
91935
92585
|
stopActivity?.();
|
|
91936
92586
|
clearTimeout(activityTimer);
|
|
91937
92587
|
clearInterval(activityPoll);
|
|
@@ -92818,7 +93468,7 @@ function clamp(value, min, max) {
|
|
|
92818
93468
|
}
|
|
92819
93469
|
|
|
92820
93470
|
// src/codexTaskBridge.ts
|
|
92821
|
-
import { createHash as
|
|
93471
|
+
import { createHash as createHash22 } from "crypto";
|
|
92822
93472
|
import { spawn as spawn3 } from "child_process";
|
|
92823
93473
|
import { existsSync as existsSync13, readFileSync as readFileSync15, readdirSync as readdirSync7 } from "fs";
|
|
92824
93474
|
import { isAbsolute as isAbsolute4, join as join18, resolve as resolve11 } from "path";
|
|
@@ -92861,7 +93511,7 @@ async function flushCodexChatDeletions(client2, teamId, stateRoot, notice) {
|
|
|
92861
93511
|
const session = client2.getSession();
|
|
92862
93512
|
const scope2 = [session.apiUrl, session.hashedEmail, teamId || "personal"];
|
|
92863
93513
|
const account = JSON.stringify(scope2);
|
|
92864
|
-
const directory = join18(stateRoot, "codex-chat-deletions",
|
|
93514
|
+
const directory = join18(stateRoot, "codex-chat-deletions", createHash22("sha256").update(account).digest("hex"));
|
|
92865
93515
|
if (!existsSync13(directory)) return;
|
|
92866
93516
|
const release2 = await lockfile4.lock(directory, { retries: 0, stale: 24e4 });
|
|
92867
93517
|
try {
|
|
@@ -92895,14 +93545,14 @@ async function flushCodexChatDeletions(client2, teamId, stateRoot, notice) {
|
|
|
92895
93545
|
}
|
|
92896
93546
|
|
|
92897
93547
|
// src/taskCommandDelivery.ts
|
|
92898
|
-
import { createHash as
|
|
93548
|
+
import { createHash as createHash23 } from "crypto";
|
|
92899
93549
|
import { existsSync as existsSync14, readFileSync as readFileSync16, readdirSync as readdirSync8 } from "fs";
|
|
92900
93550
|
import { join as join19 } from "path";
|
|
92901
93551
|
import lockfile5 from "proper-lockfile";
|
|
92902
93552
|
async function flushTaskCommands(client2, teamId, root = resolveStateDir(), onNotice) {
|
|
92903
93553
|
const session = client2.getSession();
|
|
92904
93554
|
const scope2 = [session.apiUrl, session.hashedEmail, teamId || "personal"];
|
|
92905
|
-
const directory = join19(root, "task-command-delivery",
|
|
93555
|
+
const directory = join19(root, "task-command-delivery", createHash23("sha256").update(JSON.stringify(scope2)).digest("hex"));
|
|
92906
93556
|
if (!existsSync14(directory)) return;
|
|
92907
93557
|
const release2 = await lockfile5.lock(directory, { retries: 0, stale: 24e4 });
|
|
92908
93558
|
try {
|
|
@@ -93012,7 +93662,7 @@ import {
|
|
|
93012
93662
|
writeFileSync as writeFileSync13
|
|
93013
93663
|
} from "fs";
|
|
93014
93664
|
import { spawn as spawn7 } from "child_process";
|
|
93015
|
-
import { createHash as
|
|
93665
|
+
import { createHash as createHash29 } from "crypto";
|
|
93016
93666
|
import { extname as extname4, join as join26, resolve as resolve17, relative as relative11 } from "path";
|
|
93017
93667
|
|
|
93018
93668
|
// src/projectSourceRootPolicy.ts
|
|
@@ -93047,7 +93697,7 @@ function isEqualOrInside(parent, candidate) {
|
|
|
93047
93697
|
}
|
|
93048
93698
|
|
|
93049
93699
|
// src/projectPathPolicy.ts
|
|
93050
|
-
import { createHash as
|
|
93700
|
+
import { createHash as createHash24, randomBytes as randomBytes11 } from "crypto";
|
|
93051
93701
|
import {
|
|
93052
93702
|
chmodSync as chmodSync8,
|
|
93053
93703
|
closeSync as closeSync5,
|
|
@@ -93328,7 +93978,7 @@ function isInside2(root, candidate) {
|
|
|
93328
93978
|
return relation === "" || !relation.startsWith("..") && !isAbsolute5(relation);
|
|
93329
93979
|
}
|
|
93330
93980
|
function sha2562(value) {
|
|
93331
|
-
return
|
|
93981
|
+
return createHash24("sha256").update(value).digest("hex");
|
|
93332
93982
|
}
|
|
93333
93983
|
function stableJson2(value) {
|
|
93334
93984
|
return JSON.stringify(value, (_key, item) => {
|
|
@@ -93338,7 +93988,7 @@ function stableJson2(value) {
|
|
|
93338
93988
|
}
|
|
93339
93989
|
|
|
93340
93990
|
// src/remoteFileWrites.ts
|
|
93341
|
-
import { createHash as
|
|
93991
|
+
import { createHash as createHash25, randomBytes as randomBytes12 } from "crypto";
|
|
93342
93992
|
import {
|
|
93343
93993
|
chmodSync as chmodSync9,
|
|
93344
93994
|
closeSync as closeSync7,
|
|
@@ -93603,7 +94253,7 @@ var MAX_FILE_BYTES2 = 200 * 1024;
|
|
|
93603
94253
|
var LOCK_ROOT = join22(tmpdir5(), `openmates-remote-file-locks-${typeof process.getuid === "function" ? process.getuid() : "user"}`);
|
|
93604
94254
|
var DEFAULT_JOURNAL_ROOT = join22(tmpdir5(), `openmates-remote-file-journal-${typeof process.getuid === "function" ? process.getuid() : "user"}`);
|
|
93605
94255
|
function sha256ProjectFile(content) {
|
|
93606
|
-
return
|
|
94256
|
+
return createHash25("sha256").update(content).digest("hex");
|
|
93607
94257
|
}
|
|
93608
94258
|
async function executeRemoteFileMutation(options) {
|
|
93609
94259
|
const mutation = validateMutation(options.mutation);
|
|
@@ -94291,13 +94941,13 @@ import { existsSync as existsSync21, realpathSync as realpathSync10, statSync as
|
|
|
94291
94941
|
import { basename as basename8, dirname as dirname15, relative as relative10, resolve as resolve16 } from "path";
|
|
94292
94942
|
|
|
94293
94943
|
// src/remoteCommandRuntime.ts
|
|
94294
|
-
import { createHash as
|
|
94944
|
+
import { createHash as createHash27, randomUUID as randomUUID21 } from "crypto";
|
|
94295
94945
|
import { spawn as spawn6, spawnSync as spawnSync5 } from "child_process";
|
|
94296
94946
|
import { existsSync as existsSync19, lstatSync as lstatSync9, readdirSync as readdirSync11, realpathSync as realpathSync7, statSync as statSync6 } from "fs";
|
|
94297
94947
|
import { isAbsolute as isAbsolute8, join as join23, relative as relative7, resolve as resolve15, sep } from "path";
|
|
94298
94948
|
|
|
94299
94949
|
// src/remoteCommandAppArmor.ts
|
|
94300
|
-
import { createHash as
|
|
94950
|
+
import { createHash as createHash26 } from "crypto";
|
|
94301
94951
|
import { spawn as spawn5 } from "child_process";
|
|
94302
94952
|
import { lstatSync as lstatSync8, readFileSync as readFileSync18, realpathSync as realpathSync6, statSync as statSync5 } from "fs";
|
|
94303
94953
|
import { isAbsolute as isAbsolute7, relative as relative6 } from "path";
|
|
@@ -94514,7 +95164,7 @@ function hasControl2(value) {
|
|
|
94514
95164
|
});
|
|
94515
95165
|
}
|
|
94516
95166
|
function sha2563(value) {
|
|
94517
|
-
return
|
|
95167
|
+
return createHash26("sha256").update(value).digest("hex");
|
|
94518
95168
|
}
|
|
94519
95169
|
|
|
94520
95170
|
// src/remoteCommandRuntime.ts
|
|
@@ -95355,7 +96005,7 @@ function stableJson4(value) {
|
|
|
95355
96005
|
return JSON.stringify(value);
|
|
95356
96006
|
}
|
|
95357
96007
|
function sha2564(value) {
|
|
95358
|
-
return
|
|
96008
|
+
return createHash27("sha256").update(value).digest("hex");
|
|
95359
96009
|
}
|
|
95360
96010
|
function deepFreeze(value) {
|
|
95361
96011
|
if (value && typeof value === "object") {
|
|
@@ -95633,7 +96283,7 @@ function capabilityError(message) {
|
|
|
95633
96283
|
}
|
|
95634
96284
|
|
|
95635
96285
|
// src/remoteCommandResourceGrants.ts
|
|
95636
|
-
import { createHash as
|
|
96286
|
+
import { createHash as createHash28 } from "crypto";
|
|
95637
96287
|
import { chmodSync as chmodSync11, existsSync as existsSync20, lstatSync as lstatSync10, mkdirSync as mkdirSync18, readFileSync as readFileSync19, realpathSync as realpathSync9, renameSync as renameSync9, statSync as statSync8, writeFileSync as writeFileSync12 } from "fs";
|
|
95638
96288
|
import { isAbsolute as isAbsolute10, join as join25, relative as relative9 } from "path";
|
|
95639
96289
|
var STORE_FILE = "remote-command-resource-grants.json";
|
|
@@ -95728,7 +96378,7 @@ function resolveRemoteCommandResourceGrants(context) {
|
|
|
95728
96378
|
return { writable_targets, network_profiles, credential_profiles };
|
|
95729
96379
|
}
|
|
95730
96380
|
function definitionDigest(kind, definition) {
|
|
95731
|
-
return
|
|
96381
|
+
return createHash28("sha256").update(JSON.stringify(["openmates-command-resource-v1", kind, definition])).digest("hex");
|
|
95732
96382
|
}
|
|
95733
96383
|
function upsert(grant) {
|
|
95734
96384
|
validateIdentity(grant.project_id, grant.source_id, grant.profile_id);
|
|
@@ -96898,7 +97548,7 @@ function readRemoteAccessTextFile(options) {
|
|
|
96898
97548
|
truncated,
|
|
96899
97549
|
sizeBytes: stats.size,
|
|
96900
97550
|
lineCount: countTextLines(content),
|
|
96901
|
-
expected_base: truncated ? null :
|
|
97551
|
+
expected_base: truncated ? null : createHash29("sha256").update(bytes2.subarray(0, bytesRead)).digest("hex")
|
|
96902
97552
|
};
|
|
96903
97553
|
} catch (error) {
|
|
96904
97554
|
const code = error.code;
|
|
@@ -96948,7 +97598,7 @@ function readRemoteAccessImageChunk(options) {
|
|
|
96948
97598
|
mime_type: mimeType,
|
|
96949
97599
|
size_bytes: stats.size,
|
|
96950
97600
|
offset: options.offset,
|
|
96951
|
-
content_hash:
|
|
97601
|
+
content_hash: createHash29("sha256").update(bytes2).digest("hex")
|
|
96952
97602
|
};
|
|
96953
97603
|
} catch (error) {
|
|
96954
97604
|
if (error.code === "ELOOP") throw new Error("Remote source path is a symbolic link");
|
|
@@ -96996,8 +97646,8 @@ function readRemoteAccessFileChunk(options) {
|
|
|
96996
97646
|
content_base64: bytes2.toString("base64"),
|
|
96997
97647
|
size_bytes: stats.size,
|
|
96998
97648
|
offset: options.offset,
|
|
96999
|
-
file_identity:
|
|
97000
|
-
chunk_hash:
|
|
97649
|
+
file_identity: createHash29("sha256").update(`${stats.dev}:${stats.ino}:${stats.size}:${stats.mtimeMs}:${stats.ctimeMs}`).digest("hex"),
|
|
97650
|
+
chunk_hash: createHash29("sha256").update(bytes2).digest("hex")
|
|
97001
97651
|
};
|
|
97002
97652
|
} catch (error) {
|
|
97003
97653
|
if (error.code === "ELOOP") throw new Error("Remote source path is a symbolic link");
|
|
@@ -100197,7 +100847,7 @@ async function handlePlans(client2, subcommand, rest, flags, redactor) {
|
|
|
100197
100847
|
if (action === "diff") throw new Error("Revision diffs are reviewed in the authenticated web review page; use submit-for-review to print its URL.");
|
|
100198
100848
|
if (action !== "submit-for-review") throw new Error("Usage: openmates plans revisions list|submit-for-review|status|diff <plan-id>");
|
|
100199
100849
|
const snapshot2 = JSON.stringify(planToJson(plan));
|
|
100200
|
-
const revision = await client2.submitPlanRevision(plan.planId, { fingerprint:
|
|
100850
|
+
const revision = await client2.submitPlanRevision(plan.planId, { fingerprint: createHash30("sha256").update(snapshot2).digest("hex"), encrypted_snapshot: await encryptPlanAssumptionSources(plan, masterKey, snapshot2), created_at: nowSeconds2() });
|
|
100201
100851
|
const reviewUrl = `${deriveAppUrl(client2.apiUrl)}/plans/${plan.planId}/review?revision=${revision.revision_id}`;
|
|
100202
100852
|
if (flags.json === true) printJson2({ revision, review_url: reviewUrl });
|
|
100203
100853
|
else console.log(`Plan revision submitted for web review: ${reviewUrl}`);
|
|
@@ -101117,7 +101767,7 @@ async function handleProjects(client2, subcommand, rest, flags, redactor) {
|
|
|
101117
101767
|
encrypted_settings: await encryptWithAesGcmCombined(JSON.stringify({ default_focus: defaultFocus }), projectKey),
|
|
101118
101768
|
key_wrappers: wrapping.teamId ? [{
|
|
101119
101769
|
key_type: "team",
|
|
101120
|
-
hashed_team_id:
|
|
101770
|
+
hashed_team_id: createHash30("sha256").update(wrapping.teamId).digest("hex"),
|
|
101121
101771
|
team_key_epoch: 1,
|
|
101122
101772
|
encrypted_project_key: await encryptBytesWithAesGcm(projectKey, wrapping.key),
|
|
101123
101773
|
wrapper_version: 1,
|
|
@@ -102499,7 +103149,7 @@ async function createEncryptedRemoteAccessProject(client2, name, rootPath, write
|
|
|
102499
103149
|
encrypted_settings: await encryptWithAesGcmCombined(JSON.stringify({ default_focus: defaultFocus }), projectKey),
|
|
102500
103150
|
key_wrappers: wrapping.teamId ? [{
|
|
102501
103151
|
key_type: "team",
|
|
102502
|
-
hashed_team_id:
|
|
103152
|
+
hashed_team_id: createHash30("sha256").update(wrapping.teamId).digest("hex"),
|
|
102503
103153
|
team_key_epoch: 1,
|
|
102504
103154
|
encrypted_project_key: await encryptBytesWithAesGcm(projectKey, wrapping.key),
|
|
102505
103155
|
wrapper_version: 1,
|
|
@@ -103890,7 +104540,7 @@ function normalizeApiKeyLoadedChat(payload) {
|
|
|
103890
104540
|
const messages = rawMessages.map((message) => {
|
|
103891
104541
|
const messageId = String(message.client_message_id ?? message.message_id ?? message.id ?? "");
|
|
103892
104542
|
const directEmbedIds = Array.isArray(message.embedIds) ? message.embedIds : Array.isArray(message.embed_ids) ? message.embed_ids : [];
|
|
103893
|
-
const hashedMessageId = messageId ?
|
|
104543
|
+
const hashedMessageId = messageId ? createHash30("sha256").update(messageId).digest("hex") : null;
|
|
103894
104544
|
const matchedEmbedIds = hashedMessageId ? rawEmbeds.filter((embed) => embed.hashed_message_id === hashedMessageId && !embed.parent_embed_id).map((embed) => String(embed.embed_id ?? embed.id ?? "")).filter(Boolean) : [];
|
|
103895
104545
|
return {
|
|
103896
104546
|
id: messageId,
|