openmates 0.27.0-alpha.52 → 0.27.0-alpha.53
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-O3V32DYV.js → chunk-PCH6QOC4.js} +665 -275
- package/dist/{cli-CRk4jJXf.d.ts → cli-Cn2HwS-2.d.ts} +4 -0
- 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 +3 -3
|
@@ -755,9 +755,9 @@ async function resumeCodexTask(context) {
|
|
|
755
755
|
child.once("exit", (code) => code === 0 ? resolve20() : reject(new Error(`Codex resume exited with status ${code ?? "interrupted"}.`)));
|
|
756
756
|
});
|
|
757
757
|
}
|
|
758
|
-
function taskOwnerConflict(
|
|
759
|
-
const title = JSON.stringify(
|
|
760
|
-
const location =
|
|
758
|
+
function taskOwnerConflict(owner2) {
|
|
759
|
+
const title = JSON.stringify(owner2.title || "Untitled chat");
|
|
760
|
+
const location = owner2.provider === "openmates" ? `OpenMates chat ID: ${owner2.id}. View: openmates chats show ${owner2.id}` : `Codex chat ID: ${owner2.id}`;
|
|
761
761
|
return `Task is already linked to ${title}. ${location}. Release that link before claiming the task in another chat.`;
|
|
762
762
|
}
|
|
763
763
|
function assertCodexClaimCaller(threadId, currentThread = process.env.CODEX_THREAD_ID) {
|
|
@@ -5438,6 +5438,7 @@ var OpenMatesWsClient = class {
|
|
|
5438
5438
|
const asyncEmbedWaitMs = options?.asyncEmbedWaitMs ?? DEFAULT_ASYNC_EMBED_WAIT_MS;
|
|
5439
5439
|
return new Promise((resolve20, reject) => {
|
|
5440
5440
|
let latestContent = "";
|
|
5441
|
+
let thinkingContent = "";
|
|
5441
5442
|
let messageId = null;
|
|
5442
5443
|
let taskId = null;
|
|
5443
5444
|
let category = null;
|
|
@@ -5779,6 +5780,15 @@ var OpenMatesWsClient = class {
|
|
|
5779
5780
|
}
|
|
5780
5781
|
resetTimeout(timeoutMs);
|
|
5781
5782
|
};
|
|
5783
|
+
const belongsToResponseTurn = (p) => {
|
|
5784
|
+
if (p.chat_id !== chatId) return false;
|
|
5785
|
+
const ids = [p.user_message_id, p.userMessageId].filter((id) => id !== void 0);
|
|
5786
|
+
if (ids.length === 0 || ids.every((id) => id === userMessageId)) return true;
|
|
5787
|
+
if (awaitingSubChatsCompletion && p.is_sub_chat_continuation === true) return true;
|
|
5788
|
+
if (awaitingFocusModeContinuation && p.is_focus_mode_continuation === true) return true;
|
|
5789
|
+
if (p.is_async_skill_continuation === true && p.original_user_message_id === userMessageId && typeof p.async_skill_task_id === "string" && (pendingProjectOperations.has(p.async_skill_task_id) || awaitingUnidentifiedAsyncContinuation)) return true;
|
|
5790
|
+
return Boolean(options?.recoveryTurnId && p.recovery_turn_id === options.recoveryTurnId);
|
|
5791
|
+
};
|
|
5782
5792
|
const onMessage = (rawData) => {
|
|
5783
5793
|
try {
|
|
5784
5794
|
const parsed = JSON.parse(rawData.toString());
|
|
@@ -5901,9 +5911,25 @@ var OpenMatesWsClient = class {
|
|
|
5901
5911
|
else scheduleResolve(latestContent);
|
|
5902
5912
|
return;
|
|
5903
5913
|
}
|
|
5914
|
+
if (type === "thinking_chunk" || type === "thinking_complete") {
|
|
5915
|
+
if (p.chat_id !== chatId || !taskId || p.task_id !== taskId) return;
|
|
5916
|
+
if (type === "thinking_chunk") {
|
|
5917
|
+
if (typeof p.content !== "string" || !p.content) return;
|
|
5918
|
+
thinkingContent += p.content;
|
|
5919
|
+
}
|
|
5920
|
+
onStream?.({
|
|
5921
|
+
kind: "typing",
|
|
5922
|
+
content: latestContent,
|
|
5923
|
+
category,
|
|
5924
|
+
modelName,
|
|
5925
|
+
taskId,
|
|
5926
|
+
thinkingContent,
|
|
5927
|
+
thinkingActive: type === "thinking_chunk"
|
|
5928
|
+
});
|
|
5929
|
+
return;
|
|
5930
|
+
}
|
|
5904
5931
|
if (type === "ai_message_update") {
|
|
5905
|
-
|
|
5906
|
-
if (msgId !== userMessageId && p.chat_id !== chatId) return;
|
|
5932
|
+
if (!belongsToResponseTurn(p)) return;
|
|
5907
5933
|
beginProjectContinuation(p);
|
|
5908
5934
|
if (activeProjectContinuation && (p.is_async_skill_continuation !== true || p.async_skill_task_id !== activeProjectContinuation)) return;
|
|
5909
5935
|
if (p.is_focus_mode_continuation === true) beginFocusModeContinuation();
|
|
@@ -5926,7 +5952,9 @@ var OpenMatesWsClient = class {
|
|
|
5926
5952
|
content: latestContent,
|
|
5927
5953
|
category,
|
|
5928
5954
|
modelName,
|
|
5929
|
-
taskId: taskId ?? void 0
|
|
5955
|
+
taskId: taskId ?? void 0,
|
|
5956
|
+
thinkingContent,
|
|
5957
|
+
thinkingActive: false
|
|
5930
5958
|
});
|
|
5931
5959
|
scheduleResolve(latestContent);
|
|
5932
5960
|
} else {
|
|
@@ -5935,15 +5963,15 @@ var OpenMatesWsClient = class {
|
|
|
5935
5963
|
content: latestContent,
|
|
5936
5964
|
category,
|
|
5937
5965
|
modelName,
|
|
5938
|
-
taskId: taskId ?? void 0
|
|
5966
|
+
taskId: taskId ?? void 0,
|
|
5967
|
+
thinkingContent,
|
|
5968
|
+
thinkingActive: false
|
|
5939
5969
|
});
|
|
5940
5970
|
}
|
|
5941
5971
|
return;
|
|
5942
5972
|
}
|
|
5943
5973
|
if (type === "ai_background_response_completed") {
|
|
5944
|
-
|
|
5945
|
-
if (msgId && msgId !== userMessageId && p.chat_id !== chatId) return;
|
|
5946
|
-
if (!msgId && p.chat_id !== chatId) return;
|
|
5974
|
+
if (!belongsToResponseTurn(p)) return;
|
|
5947
5975
|
beginProjectContinuation(p);
|
|
5948
5976
|
if (activeProjectContinuation && (p.is_async_skill_continuation !== true || p.async_skill_task_id !== activeProjectContinuation)) return;
|
|
5949
5977
|
if (p.is_focus_mode_continuation === true) beginFocusModeContinuation();
|
|
@@ -5958,7 +5986,7 @@ var OpenMatesWsClient = class {
|
|
|
5958
5986
|
awaitingUnidentifiedAsyncContinuation = true;
|
|
5959
5987
|
resetTimeout(Math.max(timeoutMs, 20 * 6e4 + 5e3));
|
|
5960
5988
|
}
|
|
5961
|
-
onStream?.({ kind: "done", content, category, modelName, taskId: taskId ?? void 0 });
|
|
5989
|
+
onStream?.({ kind: "done", content, category, modelName, taskId: taskId ?? void 0, thinkingContent, thinkingActive: false });
|
|
5962
5990
|
scheduleResolve(content);
|
|
5963
5991
|
return;
|
|
5964
5992
|
}
|
|
@@ -5978,14 +6006,17 @@ var OpenMatesWsClient = class {
|
|
|
5978
6006
|
if (typeof message.model_name === "string" && message.model_name) {
|
|
5979
6007
|
modelName = message.model_name;
|
|
5980
6008
|
}
|
|
5981
|
-
onStream?.({ kind: "done", content, category, modelName, taskId: taskId ?? void 0 });
|
|
6009
|
+
onStream?.({ kind: "done", content, category, modelName, taskId: taskId ?? void 0, thinkingContent, thinkingActive: false });
|
|
5982
6010
|
scheduleResolve(content);
|
|
5983
6011
|
return;
|
|
5984
6012
|
}
|
|
5985
6013
|
if (type === "ai_typing_started") {
|
|
5986
|
-
if (p.chat_id !== chatId) return;
|
|
6014
|
+
if (p.chat_id !== chatId || p.user_message_id !== void 0 && p.user_message_id !== userMessageId || p.userMessageId !== void 0 && p.userMessageId !== userMessageId) return;
|
|
5987
6015
|
beginProjectContinuation(p);
|
|
5988
6016
|
capture(p);
|
|
6017
|
+
if (typeof p.task_id !== "string" && typeof p.message_id === "string" && p.message_id) {
|
|
6018
|
+
taskId = p.message_id;
|
|
6019
|
+
}
|
|
5989
6020
|
if (typeof p.title === "string" && p.title.trim()) generatedTitle = p.title.trim();
|
|
5990
6021
|
if (Array.isArray(p.icon_names)) {
|
|
5991
6022
|
generatedIcon = p.icon_names.find((icon) => typeof icon === "string" && icon.trim().length > 0) ?? generatedIcon;
|
|
@@ -5995,7 +6026,9 @@ var OpenMatesWsClient = class {
|
|
|
5995
6026
|
content: "",
|
|
5996
6027
|
category,
|
|
5997
6028
|
modelName,
|
|
5998
|
-
taskId: taskId ?? void 0
|
|
6029
|
+
taskId: taskId ?? void 0,
|
|
6030
|
+
thinkingContent,
|
|
6031
|
+
thinkingActive: false
|
|
5999
6032
|
});
|
|
6000
6033
|
return;
|
|
6001
6034
|
}
|
|
@@ -11493,15 +11526,15 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
11493
11526
|
return `${path2}${separator}team_id=${encodeURIComponent(teamId)}`;
|
|
11494
11527
|
}
|
|
11495
11528
|
async listTeams() {
|
|
11496
|
-
const
|
|
11529
|
+
const owner2 = this.captureTeamAccountOwner();
|
|
11497
11530
|
const response = await this.http.get("/v1/teams", this.getCliRequestHeaders());
|
|
11498
11531
|
if (!response.ok) throw new Error(`Team list failed with HTTP ${response.status}`);
|
|
11499
|
-
if (!
|
|
11532
|
+
if (!owner2.isCurrent()) throw new Error("Account changed while loading Teams.");
|
|
11500
11533
|
const teams = response.data.teams ?? [];
|
|
11501
|
-
await Promise.all(teams.map((team) => this.cacheTeamKeyFromRecord(team,
|
|
11502
|
-
if (!
|
|
11534
|
+
await Promise.all(teams.map((team) => this.cacheTeamKeyFromRecord(team, owner2.isCurrent)));
|
|
11535
|
+
if (!owner2.isCurrent()) throw new Error("Account changed while loading Teams.");
|
|
11503
11536
|
const teamIds = teams.map((team) => team.team_id).filter((teamId) => typeof teamId === "string" && teamId.length > 0);
|
|
11504
|
-
pruneLocalTeamArtifacts(
|
|
11537
|
+
pruneLocalTeamArtifacts(owner2.hashedEmail, teamIds);
|
|
11505
11538
|
if (this.session?.activeTeamId && !teamIds.includes(this.session.activeTeamId)) {
|
|
11506
11539
|
this.setActiveTeamId(null);
|
|
11507
11540
|
}
|
|
@@ -11557,12 +11590,12 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
11557
11590
|
return response.data.team;
|
|
11558
11591
|
}
|
|
11559
11592
|
async getTeam(teamId) {
|
|
11560
|
-
const
|
|
11593
|
+
const owner2 = this.captureTeamAccountOwner();
|
|
11561
11594
|
const response = await this.http.get(`/v1/teams/${encodeURIComponent(teamId)}`, this.getCliRequestHeaders());
|
|
11562
11595
|
if (!response.ok || !response.data.team) throw new Error(`Team get failed with HTTP ${response.status}`);
|
|
11563
|
-
if (!
|
|
11564
|
-
await this.cacheTeamKeyFromRecord(response.data.team,
|
|
11565
|
-
if (!
|
|
11596
|
+
if (!owner2.isCurrent()) throw new Error("Account changed while loading Team.");
|
|
11597
|
+
await this.cacheTeamKeyFromRecord(response.data.team, owner2.isCurrent);
|
|
11598
|
+
if (!owner2.isCurrent()) throw new Error("Account changed while loading Team.");
|
|
11566
11599
|
return response.data.team;
|
|
11567
11600
|
}
|
|
11568
11601
|
/** Team names and descriptions are decrypted only on this device. */
|
|
@@ -13171,7 +13204,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
13171
13204
|
/** Observe lifecycle metadata without claiming or collecting AI responses. */
|
|
13172
13205
|
async observeChatActivity(onChange) {
|
|
13173
13206
|
const session = this.requireSession();
|
|
13174
|
-
const
|
|
13207
|
+
const owner2 = [
|
|
13175
13208
|
session.apiUrl,
|
|
13176
13209
|
session.hashedEmail,
|
|
13177
13210
|
session.sessionId,
|
|
@@ -13180,7 +13213,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
13180
13213
|
];
|
|
13181
13214
|
const ownerCurrent = () => {
|
|
13182
13215
|
const current2 = this.session;
|
|
13183
|
-
return !!current2 && current2.apiUrl ===
|
|
13216
|
+
return !!current2 && current2.apiUrl === owner2[0] && current2.hashedEmail === owner2[1] && current2.sessionId === owner2[2] && current2.createdAt === owner2[3] && current2.masterKeyExportedB64 === owner2[4];
|
|
13184
13217
|
};
|
|
13185
13218
|
const types = ["ai_task_initiated", "ai_typing_started", "ai_typing_ended", "ai_background_response_completed", "ai_task_cancel_requested", "ai_task_error", "pending_ai_response", "team_chat_message_created"];
|
|
13186
13219
|
let stopped = false;
|
|
@@ -14185,7 +14218,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
14185
14218
|
async getChatMessagesWindow(query, options = {}) {
|
|
14186
14219
|
const teamId = this.resolveTeamContext(options);
|
|
14187
14220
|
const session = this.requireSession();
|
|
14188
|
-
const
|
|
14221
|
+
const owner2 = [
|
|
14189
14222
|
session.apiUrl,
|
|
14190
14223
|
session.hashedEmail,
|
|
14191
14224
|
session.sessionId,
|
|
@@ -14196,13 +14229,13 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
14196
14229
|
const selectedTeamId = this.getActiveTeamId();
|
|
14197
14230
|
const current2 = () => {
|
|
14198
14231
|
const active = this.session;
|
|
14199
|
-
if (!active || active.apiUrl !==
|
|
14232
|
+
if (!active || active.apiUrl !== owner2[0] || active.hashedEmail !== owner2[1] || active.sessionId !== owner2[2] || active.createdAt !== owner2[3] || active.masterKeyExportedB64 !== owner2[4] || options.preferCache && this.getActiveTeamId() !== selectedTeamId)
|
|
14200
14233
|
throw new Error("Chat workspace changed");
|
|
14201
14234
|
};
|
|
14202
14235
|
const cache = options.preferCache ? loadSyncCache(teamId) : await this.ensureSynced(false, [], options);
|
|
14203
14236
|
current2();
|
|
14204
14237
|
if (!cache) throw new Error("Chat cache unavailable. Open the chat to refresh it.");
|
|
14205
|
-
const localTeamKey = options.preferCache && teamId ? loadLocalTeamKey(
|
|
14238
|
+
const localTeamKey = options.preferCache && teamId ? loadLocalTeamKey(owner2[1], teamId) : null;
|
|
14206
14239
|
if (options.preferCache && teamId && !localTeamKey) throw new Error("Team key unavailable offline. Reconnect to refresh Team access.");
|
|
14207
14240
|
const wrappingKey = localTeamKey ? base64ToBytes(localTeamKey) : await this.getChatWrappingKey(teamId, masterKey);
|
|
14208
14241
|
current2();
|
|
@@ -18738,7 +18771,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
18738
18771
|
// -------------------------------------------------------------------------
|
|
18739
18772
|
async listUserTasks(filters = {}, options = {}) {
|
|
18740
18773
|
const session = this.requireSession();
|
|
18741
|
-
const
|
|
18774
|
+
const owner2 = [
|
|
18742
18775
|
session.apiUrl,
|
|
18743
18776
|
session.hashedEmail,
|
|
18744
18777
|
session.sessionId,
|
|
@@ -18748,7 +18781,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
18748
18781
|
];
|
|
18749
18782
|
const current2 = () => {
|
|
18750
18783
|
const active = this.session;
|
|
18751
|
-
if (!active || active.apiUrl !==
|
|
18784
|
+
if (!active || active.apiUrl !== owner2[0] || active.hashedEmail !== owner2[1] || active.sessionId !== owner2[2] || active.createdAt !== owner2[3] || active.masterKeyExportedB64 !== owner2[4] || active.activeTeamId !== owner2[5])
|
|
18752
18785
|
throw new Error("Task workspace changed");
|
|
18753
18786
|
};
|
|
18754
18787
|
const params = new URLSearchParams();
|
|
@@ -18984,8 +19017,8 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
18984
19017
|
if (task.externalChat && (current2.external_chat_provider !== input.external_chat_provider || current2.external_chat_lookup_hash !== input.external_chat_lookup_hash)) {
|
|
18985
19018
|
conflict = taskOwnerConflict(task.externalChat);
|
|
18986
19019
|
} else if (task.primaryChatId && task.primaryChatId !== input.primary_chat_id) {
|
|
18987
|
-
const
|
|
18988
|
-
conflict = taskOwnerConflict({ provider: "openmates", id:
|
|
19020
|
+
const owner2 = await this.getChatMetadata(task.primaryChatId, context);
|
|
19021
|
+
conflict = taskOwnerConflict({ provider: "openmates", id: owner2.id, title: owner2.title });
|
|
18989
19022
|
}
|
|
18990
19023
|
}
|
|
18991
19024
|
} catch {
|
|
@@ -21226,9 +21259,9 @@ Required: ${schema.required.join(", ")}`
|
|
|
21226
21259
|
...baseSyncPayload,
|
|
21227
21260
|
...refreshChatIdSet.size > 0 ? { refresh_chat_ids: Array.from(refreshChatIdSet) } : {}
|
|
21228
21261
|
});
|
|
21229
|
-
const
|
|
21262
|
+
const frames3 = await syncFrames;
|
|
21230
21263
|
signal?.throwIfAborted();
|
|
21231
|
-
if (onSyncedCache && !
|
|
21264
|
+
if (onSyncedCache && !frames3.some((frame) => frame.type === "phase_2_last_20_chats_ready")) {
|
|
21232
21265
|
throw new Error("Chat metadata sync ended before history arrived.");
|
|
21233
21266
|
}
|
|
21234
21267
|
if (includeMessageContentRefresh && refreshChatIdSet.size > 0) {
|
|
@@ -21239,9 +21272,9 @@ Required: ${schema.required.join(", ")}`
|
|
|
21239
21272
|
});
|
|
21240
21273
|
const collectedPhase3Frames = await phase3Frames;
|
|
21241
21274
|
signal?.throwIfAborted();
|
|
21242
|
-
|
|
21275
|
+
frames3.push(...collectedPhase3Frames);
|
|
21243
21276
|
}
|
|
21244
|
-
for (const frame of
|
|
21277
|
+
for (const frame of frames3) {
|
|
21245
21278
|
if (frame.type === "phase_1_last_chat_ready") {
|
|
21246
21279
|
const p = frame.payload;
|
|
21247
21280
|
newChatSuggestions = p.new_chat_suggestions ?? [];
|
|
@@ -34662,7 +34695,7 @@ function generateQr(value) {
|
|
|
34662
34695
|
function remotionMeta(c) {
|
|
34663
34696
|
const source = str(c.remotion_source) ?? str(c.source) ?? "";
|
|
34664
34697
|
const fps = firstInt(source, /fps\s*[:=]\s*(\d+)/) ?? 30;
|
|
34665
|
-
const
|
|
34698
|
+
const frames3 = firstInt(source, /durationInFrames\s*[:=]\s*(\d+)/) ?? 150;
|
|
34666
34699
|
const status = str(c.status) ?? "processing";
|
|
34667
34700
|
return {
|
|
34668
34701
|
filename: str(c.filename) ?? str(c.title) ?? "Composition.tsx",
|
|
@@ -34670,7 +34703,7 @@ function remotionMeta(c) {
|
|
|
34670
34703
|
statusText: remotionStatusText(status),
|
|
34671
34704
|
source,
|
|
34672
34705
|
sourceVersion: numberValue(c.current_source_version ?? c.source_version) ?? 1,
|
|
34673
|
-
durationSeconds: Math.max(1, Math.ceil(
|
|
34706
|
+
durationSeconds: Math.max(1, Math.ceil(frames3 / Math.max(1, fps))),
|
|
34674
34707
|
width: firstInt(source, /width\s*[:=]\s*(\d+)/) ?? 1920,
|
|
34675
34708
|
height: firstInt(source, /height\s*[:=]\s*(\d+)/) ?? 1080,
|
|
34676
34709
|
layers: remotionLayers(source),
|
|
@@ -37197,11 +37230,11 @@ async function writeRuntimeIncidentState(installDir, role, state, effectiveUid =
|
|
|
37197
37230
|
const statePath = path.join(stateDir2, `${role}.json`);
|
|
37198
37231
|
const temporaryPath = `${statePath}.${randomUUID12()}.tmp`;
|
|
37199
37232
|
await fs.mkdir(stateDir2, { recursive: true, mode: 448 });
|
|
37200
|
-
const
|
|
37233
|
+
const owner2 = await runtimeIncidentStateOwner(installDir, effectiveUid);
|
|
37201
37234
|
try {
|
|
37202
37235
|
await fs.writeFile(temporaryPath, `${JSON.stringify(state, null, 2)}
|
|
37203
37236
|
`, { flag: "wx", mode: 384 });
|
|
37204
|
-
if (
|
|
37237
|
+
if (owner2 && (owner2.uid !== 0 || owner2.gid !== 0)) await fs.chown(temporaryPath, owner2.uid, owner2.gid);
|
|
37205
37238
|
await fs.rename(temporaryPath, statePath);
|
|
37206
37239
|
await fs.chmod(statePath, 384);
|
|
37207
37240
|
} catch (error) {
|
|
@@ -91485,6 +91518,10 @@ var TuiTerminal = class {
|
|
|
91485
91518
|
paintedWidth = 0;
|
|
91486
91519
|
paintedHeight = 0;
|
|
91487
91520
|
outputBlocked = false;
|
|
91521
|
+
/** Animation ticks must not add work while stdout is awaiting drain. */
|
|
91522
|
+
get isOutputBlocked() {
|
|
91523
|
+
return this.outputBlocked;
|
|
91524
|
+
}
|
|
91488
91525
|
pendingFrame = null;
|
|
91489
91526
|
outputDrained = () => {
|
|
91490
91527
|
this.output.off("drain", this.outputDrained);
|
|
@@ -91526,6 +91563,10 @@ var TuiTerminal = class {
|
|
|
91526
91563
|
const depth = this.output.getColorDepth?.() ?? 8;
|
|
91527
91564
|
return depth >= 24 ? "truecolor" : depth >= 8 ? "ansi256" : depth >= 4 ? "ansi16" : "none";
|
|
91528
91565
|
}
|
|
91566
|
+
/** Explicit terminal preference; GUI OS motion preferences are not available over SSH. */
|
|
91567
|
+
get reducedMotion() {
|
|
91568
|
+
return process.env.OPENMATES_REDUCED_MOTION === "1";
|
|
91569
|
+
}
|
|
91529
91570
|
get ascii() {
|
|
91530
91571
|
return process.env.OPENMATES_ASCII === "1" || process.env.TERM === "dumb";
|
|
91531
91572
|
}
|
|
@@ -92636,10 +92677,62 @@ function filterTasks(tasks, query, status) {
|
|
|
92636
92677
|
const words = query.toLocaleLowerCase().trim().split(/\s+/).filter(Boolean);
|
|
92637
92678
|
return sorted(tasks.filter((task) => {
|
|
92638
92679
|
if (status && task.status !== status) return false;
|
|
92680
|
+
if (!words.length) return true;
|
|
92639
92681
|
const haystack = [task.shortId, task.slug, task.title, task.description, task.labels.join(" "), task.tags.join(" "), task.status, task.assigneeIdentity ?? "", task.assigneeHash ?? "", task.queueState].join(" ").toLocaleLowerCase();
|
|
92640
92682
|
return words.every((word) => haystack.includes(word));
|
|
92641
92683
|
}));
|
|
92642
92684
|
}
|
|
92685
|
+
var titleHeightCache = /* @__PURE__ */ new WeakMap();
|
|
92686
|
+
function taskTitleLines(task, width, selected) {
|
|
92687
|
+
return wrapCells(`${selected ? "\u203A " : " "}${task.title || "Untitled task"}`, Math.max(8, width - 2)).slice(0, 2);
|
|
92688
|
+
}
|
|
92689
|
+
function taskTitleHeight(task, width, selected) {
|
|
92690
|
+
let cache = titleHeightCache.get(task);
|
|
92691
|
+
if (!cache || cache.title !== task.title) {
|
|
92692
|
+
cache = { title: task.title, widths: /* @__PURE__ */ new Map() };
|
|
92693
|
+
titleHeightCache.set(task, cache);
|
|
92694
|
+
}
|
|
92695
|
+
let counts = cache.widths.get(width);
|
|
92696
|
+
if (!counts) {
|
|
92697
|
+
if (cache.widths.size >= 3) {
|
|
92698
|
+
const oldest = cache.widths.keys().next().value;
|
|
92699
|
+
if (oldest !== void 0) cache.widths.delete(oldest);
|
|
92700
|
+
}
|
|
92701
|
+
counts = {};
|
|
92702
|
+
cache.widths.set(width, counts);
|
|
92703
|
+
}
|
|
92704
|
+
const key = selected ? "selected" : "unselected";
|
|
92705
|
+
return counts[key] ?? (counts[key] = taskTitleLines(task, width, selected).length);
|
|
92706
|
+
}
|
|
92707
|
+
function taskCardHeight(task, width, selected) {
|
|
92708
|
+
const titleRows = taskTitleHeight(task, width, selected);
|
|
92709
|
+
return 2 + titleRows + 1 + 1 + Number(task.linkedProjectIds.length > 0) + Number(Boolean(task.dueAt)) + Number(task.priority > 1) + Number(Boolean(task.queueState && task.queueState !== "none"));
|
|
92710
|
+
}
|
|
92711
|
+
function cardPositions(group, width, selectedTaskId, separatorRows) {
|
|
92712
|
+
let height = 0;
|
|
92713
|
+
const cards = group.map((task, index) => {
|
|
92714
|
+
const start = height;
|
|
92715
|
+
const end = start + taskCardHeight(task, width, task.taskId === selectedTaskId);
|
|
92716
|
+
height = end + separatorRows;
|
|
92717
|
+
return { task, index, start, end };
|
|
92718
|
+
});
|
|
92719
|
+
return { cards, height };
|
|
92720
|
+
}
|
|
92721
|
+
function boardWindows(viewport, fullHeight, stackStart, selected) {
|
|
92722
|
+
const requestedStart = Math.floor(viewport.start);
|
|
92723
|
+
const span = Math.min(fullHeight, Math.max(0, Math.ceil(viewport.end) - requestedStart));
|
|
92724
|
+
const start = Math.min(Math.max(0, requestedStart), Math.max(0, fullHeight - span));
|
|
92725
|
+
const end = start + span;
|
|
92726
|
+
const windows = [{ start, end }];
|
|
92727
|
+
if (selected && viewport.followSelection !== false) {
|
|
92728
|
+
const padding = Math.max(1, end - start);
|
|
92729
|
+
windows.push({ start: Math.max(0, stackStart + selected.start - padding), end: stackStart + selected.end + padding });
|
|
92730
|
+
}
|
|
92731
|
+
return windows;
|
|
92732
|
+
}
|
|
92733
|
+
function intersects(start, end, windows) {
|
|
92734
|
+
return windows.some((window) => start < window.end && end > window.start);
|
|
92735
|
+
}
|
|
92643
92736
|
function renderTaskBoard2(tasks, options) {
|
|
92644
92737
|
const width = Math.max(18, options.width);
|
|
92645
92738
|
const visible = filterTasks(tasks, options.query ?? "");
|
|
@@ -92667,14 +92760,40 @@ function renderTaskBoard2(tasks, options) {
|
|
|
92667
92760
|
{ kind: "select", target: "task", column: TASK_STATUSES.indexOf(status), index: 0 }
|
|
92668
92761
|
)), colWidth, gap));
|
|
92669
92762
|
lines.push(shown.map(() => "\u2500".repeat(colWidth)).join(gap));
|
|
92670
|
-
|
|
92671
|
-
task,
|
|
92672
|
-
|
|
92673
|
-
|
|
92674
|
-
|
|
92675
|
-
|
|
92676
|
-
|
|
92677
|
-
|
|
92763
|
+
if (!options.viewport) {
|
|
92764
|
+
const stacks = shown.map(({ tasks: group }) => group.length ? group.flatMap((task, index) => [...taskCard(
|
|
92765
|
+
task,
|
|
92766
|
+
colWidth,
|
|
92767
|
+
task.taskId === options.selectedTaskId,
|
|
92768
|
+
{ kind: "select", target: "task", column: TASK_STATUSES.indexOf(task.status), index, id: task.taskId, activate: true }
|
|
92769
|
+
), ""]) : [padCells("No tasks here.", colWidth)]);
|
|
92770
|
+
for (let row3 = 0; row3 < Math.max(...stacks.map((stack) => stack.length)); row3++) {
|
|
92771
|
+
lines.push(joinColumns(stacks.map((stack) => stack[row3] ?? ""), colWidth, gap));
|
|
92772
|
+
}
|
|
92773
|
+
} else {
|
|
92774
|
+
const stackStart = lines.length;
|
|
92775
|
+
const positions = shown.map(({ tasks: group }) => cardPositions(group, colWidth, options.selectedTaskId, 1));
|
|
92776
|
+
const selectedCard = positions.flatMap(({ cards }) => cards).find(({ task }) => task.taskId === options.selectedTaskId);
|
|
92777
|
+
const totalRows = Math.max(...positions.map(({ cards, height }) => cards.length ? height : 1));
|
|
92778
|
+
const windows = boardWindows(options.viewport, stackStart + totalRows, stackStart, selectedCard);
|
|
92779
|
+
const stacks = positions.map(({ cards }) => {
|
|
92780
|
+
const rows2 = /* @__PURE__ */ new Map();
|
|
92781
|
+
if (!cards.length && intersects(stackStart, stackStart + 1, windows)) rows2.set(0, padCells("No tasks here.", colWidth));
|
|
92782
|
+
for (const card2 of cards) {
|
|
92783
|
+
if (!intersects(stackStart + card2.start, stackStart + card2.end, windows)) continue;
|
|
92784
|
+
const rendered = taskCard(
|
|
92785
|
+
card2.task,
|
|
92786
|
+
colWidth,
|
|
92787
|
+
card2.task.taskId === options.selectedTaskId,
|
|
92788
|
+
{ kind: "select", target: "task", column: TASK_STATUSES.indexOf(card2.task.status), index: card2.index, id: card2.task.taskId, activate: true }
|
|
92789
|
+
);
|
|
92790
|
+
rendered.forEach((line3, offset) => rows2.set(card2.start + offset, line3));
|
|
92791
|
+
}
|
|
92792
|
+
return rows2;
|
|
92793
|
+
});
|
|
92794
|
+
for (let row3 = 0; row3 < totalRows; row3++) {
|
|
92795
|
+
lines.push(intersects(stackStart + row3, stackStart + row3 + 1, windows) ? joinColumns(stacks.map((stack) => stack.get(row3) ?? ""), colWidth, gap) : "");
|
|
92796
|
+
}
|
|
92678
92797
|
}
|
|
92679
92798
|
} else {
|
|
92680
92799
|
const group = columns[focusedIndex]?.tasks ?? [];
|
|
@@ -92684,13 +92803,33 @@ function renderTaskBoard2(tasks, options) {
|
|
|
92684
92803
|
{ kind: "select", target: "task", column: focusedIndex, index: 0 }
|
|
92685
92804
|
), "\u2500".repeat(Math.min(width, 52)));
|
|
92686
92805
|
if (!group.length) lines.push(" No tasks here.");
|
|
92687
|
-
|
|
92688
|
-
|
|
92689
|
-
|
|
92690
|
-
|
|
92691
|
-
|
|
92692
|
-
|
|
92693
|
-
|
|
92806
|
+
if (!options.viewport) {
|
|
92807
|
+
for (const [index, task] of group.entries()) {
|
|
92808
|
+
lines.push(...taskCard(
|
|
92809
|
+
task,
|
|
92810
|
+
Math.min(width, 52),
|
|
92811
|
+
task.taskId === options.selectedTaskId,
|
|
92812
|
+
{ kind: "select", target: "task", column: focusedIndex, index, id: task.taskId, activate: true }
|
|
92813
|
+
));
|
|
92814
|
+
}
|
|
92815
|
+
} else {
|
|
92816
|
+
const stackStart = lines.length;
|
|
92817
|
+
const { cards, height } = cardPositions(group, Math.min(width, 52), options.selectedTaskId, 0);
|
|
92818
|
+
const windows = boardWindows(options.viewport, stackStart + height, stackStart, cards.find(({ task }) => task.taskId === options.selectedTaskId));
|
|
92819
|
+
const rows2 = Array(height).fill("");
|
|
92820
|
+
for (const card2 of cards) {
|
|
92821
|
+
if (!intersects(stackStart + card2.start, stackStart + card2.end, windows)) continue;
|
|
92822
|
+
const rendered = taskCard(
|
|
92823
|
+
card2.task,
|
|
92824
|
+
Math.min(width, 52),
|
|
92825
|
+
card2.task.taskId === options.selectedTaskId,
|
|
92826
|
+
{ kind: "select", target: "task", column: focusedIndex, index: card2.index, id: card2.task.taskId, activate: true }
|
|
92827
|
+
);
|
|
92828
|
+
rendered.forEach((line3, offset) => {
|
|
92829
|
+
rows2[card2.start + offset] = line3;
|
|
92830
|
+
});
|
|
92831
|
+
}
|
|
92832
|
+
lines.push(...rows2);
|
|
92694
92833
|
}
|
|
92695
92834
|
}
|
|
92696
92835
|
return lines;
|
|
@@ -92711,7 +92850,7 @@ function taskCard(task, width, selected, action2) {
|
|
|
92711
92850
|
if (!selected) return top ? `\u256D${edge}\u256E` : `\u2570${edge}\u256F`;
|
|
92712
92851
|
return styledLine([{ text: top ? `\u2554${edge}\u2557` : `\u255A${edge}\u255D`, color: STATUS_COLORS[task.status], background: SELECTED_BACKGROUND, bold: true }]);
|
|
92713
92852
|
};
|
|
92714
|
-
const titleLines =
|
|
92853
|
+
const titleLines = taskTitleLines(task, width, selected);
|
|
92715
92854
|
const metadata = [task.linkedProjectIds.length ? "Project" : "", assignee(task), task.dueAt ? `Due ${new Date(task.dueAt * 1e3).toISOString().slice(0, 10)}` : "", task.priority > 1 ? task.priorityLevel : ""].filter(Boolean);
|
|
92716
92855
|
return [
|
|
92717
92856
|
border(true),
|
|
@@ -94423,7 +94562,7 @@ function settingsChildren(route2, options) {
|
|
|
94423
94562
|
|
|
94424
94563
|
// src/tuiSettings.ts
|
|
94425
94564
|
var currentOwner = (ctx) => typeof ctx.owner === "function" ? ctx.owner() : ctx.owner;
|
|
94426
|
-
var ownerValid = (ctx,
|
|
94565
|
+
var ownerValid = (ctx, owner2) => currentOwner(ctx) === owner2 && ctx.state.owner === owner2 && (ctx.isOwnerCurrent?.() ?? true);
|
|
94427
94566
|
var asObject = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
94428
94567
|
var safeText2 = (value) => terminalText(String(value ?? "")).replace(/\s+/g, " ").trim();
|
|
94429
94568
|
var isSecret = (key) => /(?:secret|token|password|private.?key|encrypted|ciphertext|api_key$|^key$)/i.test(key);
|
|
@@ -94444,10 +94583,10 @@ function settingsWebUrl(ctx) {
|
|
|
94444
94583
|
return "https://openmates.org";
|
|
94445
94584
|
}
|
|
94446
94585
|
}
|
|
94447
|
-
function createTuiSettingsState(
|
|
94586
|
+
function createTuiSettingsState(owner2, options = {}) {
|
|
94448
94587
|
return {
|
|
94449
94588
|
route: "main",
|
|
94450
|
-
owner,
|
|
94589
|
+
owner: owner2,
|
|
94451
94590
|
ownerStale: false,
|
|
94452
94591
|
generation: 0,
|
|
94453
94592
|
authenticated: options.authenticated ?? true,
|
|
@@ -94492,17 +94631,17 @@ function restrictedSession(client2) {
|
|
|
94492
94631
|
}
|
|
94493
94632
|
}
|
|
94494
94633
|
function syncTuiSettingsOwner(ctx) {
|
|
94495
|
-
const
|
|
94496
|
-
if (ctx.isOwnerCurrent?.() === false &&
|
|
94634
|
+
const owner2 = currentOwner(ctx);
|
|
94635
|
+
if (ctx.isOwnerCurrent?.() === false && owner2 === ctx.state.owner) {
|
|
94497
94636
|
if (!ctx.state.ownerStale) {
|
|
94498
|
-
const fresh2 = createTuiSettingsState(
|
|
94637
|
+
const fresh2 = createTuiSettingsState(owner2, { authenticated: ctx.client.hasSession(), restricted: restrictedSession(ctx.client), paymentEnabled: false, webUrl: settingsWebUrl(ctx) });
|
|
94499
94638
|
Object.assign(ctx.state, fresh2, { ownerStale: true, generation: ctx.state.generation + 1 });
|
|
94500
94639
|
ctx.render();
|
|
94501
94640
|
}
|
|
94502
94641
|
return true;
|
|
94503
94642
|
}
|
|
94504
|
-
if (ctx.state.owner ===
|
|
94505
|
-
const fresh = createTuiSettingsState(
|
|
94643
|
+
if (ctx.state.owner === owner2) return false;
|
|
94644
|
+
const fresh = createTuiSettingsState(owner2, {
|
|
94506
94645
|
authenticated: ctx.client.hasSession(),
|
|
94507
94646
|
restricted: restrictedSession(ctx.client),
|
|
94508
94647
|
paymentEnabled: ctx.state.paymentEnabled,
|
|
@@ -94537,14 +94676,14 @@ async function loadPage(ctx, page) {
|
|
|
94537
94676
|
const state = ctx.state;
|
|
94538
94677
|
if (state.busy) return;
|
|
94539
94678
|
if (state.ownerStale) return;
|
|
94540
|
-
const
|
|
94679
|
+
const owner2 = currentOwner(ctx), generation = ++state.generation;
|
|
94541
94680
|
state.busy = true;
|
|
94542
94681
|
state.loading = true;
|
|
94543
94682
|
state.error = null;
|
|
94544
94683
|
ctx.render();
|
|
94545
94684
|
try {
|
|
94546
94685
|
const value = await page.load(ctx.client);
|
|
94547
|
-
if (!ownerValid(ctx,
|
|
94686
|
+
if (!ownerValid(ctx, owner2)) {
|
|
94548
94687
|
ctx.render();
|
|
94549
94688
|
return;
|
|
94550
94689
|
}
|
|
@@ -94565,9 +94704,9 @@ async function loadPage(ctx, page) {
|
|
|
94565
94704
|
state.isAdmin = info.is_admin === true;
|
|
94566
94705
|
}
|
|
94567
94706
|
} catch (error) {
|
|
94568
|
-
if (ownerValid(ctx,
|
|
94707
|
+
if (ownerValid(ctx, owner2) && state.generation === generation) state.error = safeText2(error instanceof Error ? error.message : error);
|
|
94569
94708
|
} finally {
|
|
94570
|
-
if (ownerValid(ctx,
|
|
94709
|
+
if (ownerValid(ctx, owner2) && state.generation === generation) {
|
|
94571
94710
|
state.busy = false;
|
|
94572
94711
|
state.loading = false;
|
|
94573
94712
|
ctx.render();
|
|
@@ -94604,10 +94743,10 @@ async function openTuiSettingsPage(state, route2, ctx) {
|
|
|
94604
94743
|
await loadPage(ctx, page);
|
|
94605
94744
|
}
|
|
94606
94745
|
async function loadProfile(ctx) {
|
|
94607
|
-
const state = ctx.state,
|
|
94746
|
+
const state = ctx.state, owner2 = currentOwner(ctx), generation = state.generation;
|
|
94608
94747
|
try {
|
|
94609
94748
|
const info = asObject(await ctx.client.whoAmI());
|
|
94610
|
-
if (!ownerValid(ctx,
|
|
94749
|
+
if (!ownerValid(ctx, owner2) || state.generation !== generation) return;
|
|
94611
94750
|
state.profile = { username: safeText2(info.username), email: safeText2(info.email), account: safeText2(info.id), team: safeText2(info.active_team_name) };
|
|
94612
94751
|
state.isAdmin = info.is_admin === true;
|
|
94613
94752
|
ctx.render();
|
|
@@ -94615,11 +94754,11 @@ async function loadProfile(ctx) {
|
|
|
94615
94754
|
}
|
|
94616
94755
|
}
|
|
94617
94756
|
async function loadCapabilities(ctx) {
|
|
94618
|
-
const state = ctx.state,
|
|
94757
|
+
const state = ctx.state, owner2 = currentOwner(ctx), generation = state.generation;
|
|
94619
94758
|
if (!state.authenticated || typeof ctx.client.settingsGet !== "function") return;
|
|
94620
94759
|
try {
|
|
94621
94760
|
const status = asObject(await ctx.client.settingsGet("server-status"));
|
|
94622
|
-
if (!ownerValid(ctx,
|
|
94761
|
+
if (!ownerValid(ctx, owner2) || state.generation !== generation) return;
|
|
94623
94762
|
state.paymentEnabled = status.is_self_hosted !== true && status.payment_enabled === true;
|
|
94624
94763
|
state.paymentChecked = true;
|
|
94625
94764
|
ctx.render();
|
|
@@ -94688,7 +94827,7 @@ async function runMutation(ctx, actionId) {
|
|
|
94688
94827
|
ctx.render();
|
|
94689
94828
|
return;
|
|
94690
94829
|
}
|
|
94691
|
-
const
|
|
94830
|
+
const owner2 = currentOwner(ctx), generation = ++state.generation;
|
|
94692
94831
|
state.busy = true;
|
|
94693
94832
|
state.error = null;
|
|
94694
94833
|
state.message = null;
|
|
@@ -94700,7 +94839,7 @@ async function runMutation(ctx, actionId) {
|
|
|
94700
94839
|
ctx.render();
|
|
94701
94840
|
return;
|
|
94702
94841
|
}
|
|
94703
|
-
if (!ownerValid(ctx,
|
|
94842
|
+
if (!ownerValid(ctx, owner2) || state.generation !== generation) return;
|
|
94704
94843
|
const response = asObject(result);
|
|
94705
94844
|
if (response.success === false) throw new Error(safeText2(response.message) || "Operation was not accepted.");
|
|
94706
94845
|
state.message = action2 ? `${action2.label} completed.` : "Saved.";
|
|
@@ -94716,9 +94855,9 @@ async function runMutation(ctx, actionId) {
|
|
|
94716
94855
|
return;
|
|
94717
94856
|
}
|
|
94718
94857
|
} catch (error) {
|
|
94719
|
-
if (ownerValid(ctx,
|
|
94858
|
+
if (ownerValid(ctx, owner2) && state.generation === generation) state.error = safeText2(error instanceof Error ? error.message : error);
|
|
94720
94859
|
} finally {
|
|
94721
|
-
if (ownerValid(ctx,
|
|
94860
|
+
if (ownerValid(ctx, owner2) && state.generation === generation) {
|
|
94722
94861
|
state.busy = false;
|
|
94723
94862
|
ctx.render();
|
|
94724
94863
|
}
|
|
@@ -94788,19 +94927,19 @@ async function handleTuiSettingsCommand(ctx, arg) {
|
|
|
94788
94927
|
if (row3.switchTeam) {
|
|
94789
94928
|
if (ctx.client.getActiveTeamId() === row3.switchTeam) await openTuiSettingsPage(state, "teams/details", ctx);
|
|
94790
94929
|
else {
|
|
94791
|
-
const
|
|
94930
|
+
const owner2 = currentOwner(ctx), generation = ++state.generation;
|
|
94792
94931
|
state.busy = true;
|
|
94793
94932
|
state.error = null;
|
|
94794
94933
|
ctx.render();
|
|
94795
94934
|
try {
|
|
94796
94935
|
const team = await ctx.client.getTeam(row3.switchTeam);
|
|
94797
|
-
if (!ownerValid(ctx,
|
|
94936
|
+
if (!ownerValid(ctx, owner2) || state.generation !== generation) return true;
|
|
94798
94937
|
ctx.client.setActiveTeamId(team.team_id ?? row3.switchTeam);
|
|
94799
94938
|
ctx.render();
|
|
94800
94939
|
} catch (error) {
|
|
94801
|
-
if (ownerValid(ctx,
|
|
94940
|
+
if (ownerValid(ctx, owner2) && state.generation === generation) state.error = safeText2(error instanceof Error ? error.message : error);
|
|
94802
94941
|
} finally {
|
|
94803
|
-
if (ownerValid(ctx,
|
|
94942
|
+
if (ownerValid(ctx, owner2) && state.generation === generation) {
|
|
94804
94943
|
state.busy = false;
|
|
94805
94944
|
ctx.render();
|
|
94806
94945
|
}
|
|
@@ -95102,13 +95241,13 @@ function renderTuiSettings(state, width) {
|
|
|
95102
95241
|
// src/tuiModelSelector.ts
|
|
95103
95242
|
var currentOwner2 = (ctx) => typeof ctx.owner === "function" ? ctx.owner() : ctx.owner;
|
|
95104
95243
|
var currentChatId = (ctx) => typeof ctx.chatId === "function" ? ctx.chatId() : ctx.chatId;
|
|
95105
|
-
var current = (ctx,
|
|
95244
|
+
var current = (ctx, owner2, chatId, generation) => ctx.state.owner === owner2 && ctx.state.chatId === chatId && currentOwner2(ctx) === owner2 && currentChatId(ctx) === chatId && ctx.state.generation === generation && (ctx.isOwnerCurrent?.() ?? true);
|
|
95106
95245
|
var clean = (value) => terminalText(value).replace(/\s+/g, " ").trim();
|
|
95107
95246
|
var modelValue = (model) => model.id;
|
|
95108
95247
|
var rank = { low: 0, medium: 1, high: 2, max: 3 };
|
|
95109
|
-
function createTuiModelSelectorState(
|
|
95248
|
+
function createTuiModelSelectorState(owner2, chatId = null) {
|
|
95110
95249
|
return {
|
|
95111
|
-
owner,
|
|
95250
|
+
owner: owner2,
|
|
95112
95251
|
chatId,
|
|
95113
95252
|
generation: 0,
|
|
95114
95253
|
open: false,
|
|
@@ -95125,9 +95264,9 @@ function createTuiModelSelectorState(owner, chatId = null) {
|
|
|
95125
95264
|
};
|
|
95126
95265
|
}
|
|
95127
95266
|
function syncTuiModelSelectorOwner(ctx) {
|
|
95128
|
-
const
|
|
95129
|
-
if (ctx.state.owner ===
|
|
95130
|
-
Object.assign(ctx.state, createTuiModelSelectorState(
|
|
95267
|
+
const owner2 = currentOwner2(ctx), chatId = currentChatId(ctx);
|
|
95268
|
+
if (ctx.state.owner === owner2 && ctx.state.chatId === chatId && (ctx.isOwnerCurrent?.() ?? true)) return false;
|
|
95269
|
+
Object.assign(ctx.state, createTuiModelSelectorState(owner2, chatId), { generation: ctx.state.generation + 1 });
|
|
95131
95270
|
ctx.render();
|
|
95132
95271
|
return true;
|
|
95133
95272
|
}
|
|
@@ -95165,14 +95304,14 @@ function tuiModelSelectionForSend(state) {
|
|
|
95165
95304
|
}
|
|
95166
95305
|
async function restoreTuiModelSelection(ctx) {
|
|
95167
95306
|
syncTuiModelSelectorOwner(ctx);
|
|
95168
|
-
const state = ctx.state,
|
|
95307
|
+
const state = ctx.state, owner2 = currentOwner2(ctx), chatId = currentChatId(ctx), generation = ++state.generation;
|
|
95169
95308
|
state.ready = false;
|
|
95170
95309
|
state.busy = true;
|
|
95171
95310
|
state.error = null;
|
|
95172
95311
|
ctx.render();
|
|
95173
95312
|
try {
|
|
95174
95313
|
const [catalogResult, selectionResult] = await Promise.allSettled([ctx.loadCatalog(), ctx.restoreSelection()]);
|
|
95175
|
-
if (!current(ctx,
|
|
95314
|
+
if (!current(ctx, owner2, chatId, generation)) return;
|
|
95176
95315
|
if (catalogResult.status === "fulfilled") {
|
|
95177
95316
|
state.models = catalogResult.value.filter((model) => model.id.startsWith(`${model.providerId}/`) && model.name && model.providerName);
|
|
95178
95317
|
state.catalogAuthoritative = catalogResult.value.authoritative !== false;
|
|
@@ -95205,13 +95344,13 @@ async function restoreTuiModelSelection(ctx) {
|
|
|
95205
95344
|
state.selection = "auto";
|
|
95206
95345
|
state.error = "The selected model is unavailable. Reset to Auto.";
|
|
95207
95346
|
await ctx.persistSelection("auto");
|
|
95208
|
-
if (!current(ctx,
|
|
95347
|
+
if (!current(ctx, owner2, chatId, generation)) return;
|
|
95209
95348
|
}
|
|
95210
95349
|
state.ready = true;
|
|
95211
95350
|
} catch (error) {
|
|
95212
|
-
if (current(ctx,
|
|
95351
|
+
if (current(ctx, owner2, chatId, generation)) state.error = clean(error instanceof Error ? error.message : String(error));
|
|
95213
95352
|
} finally {
|
|
95214
|
-
if (current(ctx,
|
|
95353
|
+
if (current(ctx, owner2, chatId, generation)) {
|
|
95215
95354
|
state.busy = false;
|
|
95216
95355
|
ctx.render();
|
|
95217
95356
|
}
|
|
@@ -95322,20 +95461,20 @@ async function handleTuiModelSelectorAction(ctx, action2) {
|
|
|
95322
95461
|
const requested = action2.slice(7);
|
|
95323
95462
|
if (requested !== "auto" && !usableModels(state).some((model) => modelValue(model) === requested)) return true;
|
|
95324
95463
|
const selection = requested === state.selection && requested !== "auto" ? "auto" : requested;
|
|
95325
|
-
const
|
|
95464
|
+
const owner2 = currentOwner2(ctx), chatId = currentChatId(ctx), generation = ++state.generation;
|
|
95326
95465
|
state.busy = true;
|
|
95327
95466
|
state.error = null;
|
|
95328
95467
|
ctx.render();
|
|
95329
95468
|
try {
|
|
95330
95469
|
const persisted = await ctx.persistSelection(selection);
|
|
95331
|
-
if (!current(ctx,
|
|
95470
|
+
if (!current(ctx, owner2, chatId, generation)) return true;
|
|
95332
95471
|
state.selection = persisted;
|
|
95333
95472
|
if (persisted === "auto") state.ready = true;
|
|
95334
95473
|
closeTuiModelSelector(ctx);
|
|
95335
95474
|
} catch (error) {
|
|
95336
|
-
if (current(ctx,
|
|
95475
|
+
if (current(ctx, owner2, chatId, generation)) state.error = clean(error instanceof Error ? error.message : String(error));
|
|
95337
95476
|
} finally {
|
|
95338
|
-
if (current(ctx,
|
|
95477
|
+
if (current(ctx, owner2, chatId, generation)) {
|
|
95339
95478
|
state.busy = false;
|
|
95340
95479
|
ctx.render();
|
|
95341
95480
|
}
|
|
@@ -95484,15 +95623,15 @@ function createTuiModelSelectorShell(args) {
|
|
|
95484
95623
|
}
|
|
95485
95624
|
};
|
|
95486
95625
|
const sync = () => {
|
|
95487
|
-
const
|
|
95488
|
-
if (!
|
|
95626
|
+
const owner2 = ownerId(client2);
|
|
95627
|
+
if (!owner2 || !isTuiAiComposer(state)) {
|
|
95489
95628
|
clearSubscription();
|
|
95490
95629
|
ownerFence = null;
|
|
95491
95630
|
state.modelSelector = null;
|
|
95492
95631
|
return;
|
|
95493
95632
|
}
|
|
95494
95633
|
const chatId = chatIdForView(state);
|
|
95495
|
-
if (state.modelSelector?.owner ===
|
|
95634
|
+
if (state.modelSelector?.owner === owner2 && state.modelSelector.chatId === chatId && ownerFence?.()) {
|
|
95496
95635
|
if (!waitingForChat || state.headerState !== "ready") return;
|
|
95497
95636
|
waitingForChat = false;
|
|
95498
95637
|
const ctx = context();
|
|
@@ -95502,7 +95641,7 @@ function createTuiModelSelectorShell(args) {
|
|
|
95502
95641
|
return;
|
|
95503
95642
|
}
|
|
95504
95643
|
clearSubscription();
|
|
95505
|
-
state.modelSelector = createTuiModelSelectorState(
|
|
95644
|
+
state.modelSelector = createTuiModelSelectorState(owner2, chatId);
|
|
95506
95645
|
ownerFence = captureTuiWorkspaceOwner(client2);
|
|
95507
95646
|
subscribe(chatId);
|
|
95508
95647
|
const picker = state.modelSelector;
|
|
@@ -95577,12 +95716,12 @@ function createTuiModelSelectorShell(args) {
|
|
|
95577
95716
|
}
|
|
95578
95717
|
const ctx = context();
|
|
95579
95718
|
if (!ctx) return { message, blocked: true };
|
|
95580
|
-
const
|
|
95719
|
+
const owner2 = picker.owner, chatId = picker.chatId, generation = picker.generation;
|
|
95581
95720
|
picker.busy = true;
|
|
95582
95721
|
render();
|
|
95583
95722
|
try {
|
|
95584
95723
|
const saved = await ctx.persistSelection(selected.id);
|
|
95585
|
-
if (state.modelSelector !== picker || !ownerFence?.() || picker.owner !==
|
|
95724
|
+
if (state.modelSelector !== picker || !ownerFence?.() || picker.owner !== owner2 || picker.chatId !== chatId || picker.generation !== generation)
|
|
95586
95725
|
return { message, blocked: true };
|
|
95587
95726
|
picker.selection = saved;
|
|
95588
95727
|
picker.ready = true;
|
|
@@ -95968,11 +96107,12 @@ function parseTuiMarkdown(content, width, options = {}) {
|
|
|
95968
96107
|
index = next;
|
|
95969
96108
|
continue;
|
|
95970
96109
|
}
|
|
95971
|
-
for (const line3 of rows2.slice(index, Math.min(next + 1, rows2.length)))
|
|
96110
|
+
for (const line3 of options.semanticOnly ? [] : rows2.slice(index, Math.min(next + 1, rows2.length)))
|
|
95972
96111
|
output.push(...wrapped([{ text: terminalText(line3), color: CODE }], width).map((line4) => ({ type: "line", line: line4 })));
|
|
95973
96112
|
index = next;
|
|
95974
96113
|
continue;
|
|
95975
96114
|
}
|
|
96115
|
+
if (options.semanticOnly) continue;
|
|
95976
96116
|
const heading = /^\s{0,3}#{1,6}\s+(.+?)\s*#*\s*$/.exec(row3);
|
|
95977
96117
|
if (heading && output.length && output.at(-1)?.type === "line" && output.at(-1).line !== "") {
|
|
95978
96118
|
const previous = output.at(-1);
|
|
@@ -96245,7 +96385,8 @@ function renderTuiResultsViewLines(data, options = {}) {
|
|
|
96245
96385
|
|
|
96246
96386
|
// src/tuiChatResults.ts
|
|
96247
96387
|
function messageResultsViews(content) {
|
|
96248
|
-
|
|
96388
|
+
if (!/embeds_(?:results|map)_view/i.test(content)) return [];
|
|
96389
|
+
return parseMessageSegments(content, { preserveCodeFences: true }).flatMap((segment) => segment.type === "text" ? parseTuiMarkdown(segment.value, 160, { semanticOnly: true }).filter((block) => block.type === "results-view") : []);
|
|
96249
96390
|
}
|
|
96250
96391
|
function messageSupplementalEmbedIds(content) {
|
|
96251
96392
|
const ids = /* @__PURE__ */ new Set();
|
|
@@ -97478,7 +97619,8 @@ function renderHeaderDialog(dialog, width, height = 24, state) {
|
|
|
97478
97619
|
|
|
97479
97620
|
// src/tuiInteractiveQuestions.ts
|
|
97480
97621
|
function messageQuestions(content) {
|
|
97481
|
-
|
|
97622
|
+
if (!/interactive_question/i.test(content)) return [];
|
|
97623
|
+
return parseTuiMarkdown(content, 160, { semanticOnly: true }).flatMap((block) => block.type === "question" ? [block.payload] : []);
|
|
97482
97624
|
}
|
|
97483
97625
|
function chatQuestions(state) {
|
|
97484
97626
|
const messages = state.screen === "example" && state.activeExample ? state.activeExample.messages : state.messages;
|
|
@@ -97491,7 +97633,8 @@ function chatQuestions(state) {
|
|
|
97491
97633
|
const latest = questions.filter((item) => item.payload.id === question.payload.id).at(-1);
|
|
97492
97634
|
for (let index = messages.length - 1; index > latest.messageIndex; index--) {
|
|
97493
97635
|
if (messages[index].role !== "user") continue;
|
|
97494
|
-
|
|
97636
|
+
if (!/interactive_response/i.test(messages[index].content)) continue;
|
|
97637
|
+
const response = parseTuiMarkdown(messages[index].content, 160, { semanticOnly: true }).find((block) => block.type === "response" && block.payload.id === question.payload.id);
|
|
97495
97638
|
if (response?.type === "response" && !validateInteractiveQuestionAnswer(question.payload, response.payload)) {
|
|
97496
97639
|
question.response = formatInteractiveQuestionAnswer(question.payload, response.payload).responsePayload;
|
|
97497
97640
|
break;
|
|
@@ -98456,13 +98599,17 @@ function renderWorkspaceFrame(state, rawWidth, rawHeight, body, options = {}) {
|
|
|
98456
98599
|
const marker = content.findIndex((row3) => /^[>›] /.test(lineText(row3).trimStart()));
|
|
98457
98600
|
start = marker >= bodyHeight - 4 ? Math.max(0, marker - bodyHeight + 6) : 0;
|
|
98458
98601
|
} else if (state.followSelection && ["start", "tasks", "projects", "project", "chat", "chats", "example", "examples", "workflow", "workflows", "apps", "app", "app-skill"].includes(state.screen) && state.focus === "content") {
|
|
98459
|
-
const markers = content.map((row3, index) => /(?:^|[
|
|
98602
|
+
const markers = content.map((row3, index) => /(?:^|[│║|])\s*[>›] /.test(lineText(row3)) ? index : -1).filter((index) => index >= 0);
|
|
98460
98603
|
const marker = state.screen === "workflow" ? markers.at(-1) ?? -1 : markers[0] ?? -1;
|
|
98461
98604
|
let selectionEnd = marker;
|
|
98462
98605
|
if (["workflow", "start", "chats", "apps", "projects", "workflows"].includes(state.screen) && marker >= 0) {
|
|
98463
98606
|
const closing2 = content.findIndex((row3, index) => index > marker && lineText(row3).includes("\u2570"));
|
|
98464
98607
|
selectionEnd = Math.min(marker + 10, closing2 < 0 ? marker : closing2);
|
|
98465
98608
|
}
|
|
98609
|
+
if ((state.screen === "tasks" || state.screen === "project" && state.projectTab === "tasks") && marker >= 0) {
|
|
98610
|
+
const closing2 = content.findIndex((row3, index) => index > marker && lineText(row3).includes("\u255A"));
|
|
98611
|
+
selectionEnd = closing2 < 0 ? marker : closing2;
|
|
98612
|
+
}
|
|
98466
98613
|
if (selectionEnd >= start + viewportHeight) start = Math.min(maxStart, selectionEnd - viewportHeight + 1);
|
|
98467
98614
|
if (marker >= 0 && marker < start) start = marker;
|
|
98468
98615
|
}
|
|
@@ -98546,7 +98693,9 @@ function renderWorkspaceFrame(state, rawWidth, rawHeight, body, options = {}) {
|
|
|
98546
98693
|
const sidebarRow = sidebarWidth ? renderSide(side[i], sidebarWidth, gutter, true) : void 0;
|
|
98547
98694
|
const settingsColumn2 = gutter + sidebarWidth + paneWidth + 2;
|
|
98548
98695
|
const settingsRow = settingsWidth ? renderSide(settingsRows[i], settingsWidth, settingsColumn2, false) : void 0;
|
|
98549
|
-
|
|
98696
|
+
const painted = place(rendered, sidebarRow, settingsRow);
|
|
98697
|
+
rows2.push(painted);
|
|
98698
|
+
options.onBodyLine?.(value, i + 2, rendered, painted);
|
|
98550
98699
|
}
|
|
98551
98700
|
if (state.modelSelector?.open && showComposer && aiComposer && !modal && !settingsFullscreen && bodyHeight > 0) {
|
|
98552
98701
|
const popWidth = Math.max(1, Math.min(46, composerWidth));
|
|
@@ -99906,8 +100055,8 @@ function executeTuiAppsSkill(client2, run, confirmation) {
|
|
|
99906
100055
|
async function executeConfirmedTuiAppsSkill(client2, run) {
|
|
99907
100056
|
if (!client2.hasSession()) throw new Error("Sign in to run Apps skills in the terminal.");
|
|
99908
100057
|
if (client2.getActiveTeamId()) throw new Error("Switch to Personal to run Apps skills in the terminal.");
|
|
99909
|
-
const
|
|
99910
|
-
const ownerId2 = string3(
|
|
100058
|
+
const owner2 = record7(await client2.whoAmI());
|
|
100059
|
+
const ownerId2 = string3(owner2.id, string3(owner2.user_id));
|
|
99911
100060
|
if (!ownerId2) throw new Error("Account identity unavailable; skill was not run.");
|
|
99912
100061
|
const rootId = randomUUID19();
|
|
99913
100062
|
const key = randomBytes10(32);
|
|
@@ -100233,6 +100382,106 @@ async function handleSettingsKey(context, chunk, key) {
|
|
|
100233
100382
|
return handleTuiSettingsKey(ctx, chunk, key);
|
|
100234
100383
|
}
|
|
100235
100384
|
|
|
100385
|
+
// src/tuiStreamingRender.ts
|
|
100386
|
+
var COLORS = ["#ff2d55", "#ff6b2b", "#ffd60a", "#30d158", "#32ade6", "#bf5af2"];
|
|
100387
|
+
var glowLines = /* @__PURE__ */ new WeakSet();
|
|
100388
|
+
var ACTION_SKILL = /^(?:add|cancel|clean|create|delete|edit|generate|keep-temporary|modify|remove|run|schedule|send|set|share|speak|transcribe|translate|update|vectorize|write)(?:$|[-_])/;
|
|
100389
|
+
function tuiResponsePhase(segments2) {
|
|
100390
|
+
const skills = [];
|
|
100391
|
+
for (let i = segments2.length - 1; i >= 0; i--) {
|
|
100392
|
+
const segment = segments2[i];
|
|
100393
|
+
if (segment.type === "text") {
|
|
100394
|
+
if (segment.value.trim()) break;
|
|
100395
|
+
continue;
|
|
100396
|
+
}
|
|
100397
|
+
skills.push(typeof segment.meta?.skill_id === "string" ? segment.meta.skill_id : "");
|
|
100398
|
+
}
|
|
100399
|
+
return skills.length ? skills.some((id) => ACTION_SKILL.test(id.toLowerCase())) ? "Working" : "Researching" : "Working";
|
|
100400
|
+
}
|
|
100401
|
+
function clearTuiSendState(state) {
|
|
100402
|
+
state.isBusy = false;
|
|
100403
|
+
state.isAwaitingAi = false;
|
|
100404
|
+
state.streamingMessage = null;
|
|
100405
|
+
state.aiTaskId = null;
|
|
100406
|
+
state.projectFocusPending = null;
|
|
100407
|
+
}
|
|
100408
|
+
var owner = (state) => JSON.stringify([state.signedIn, state.currentUserHash, state.activeTeamId, state.activeChatId, state.routeVersion]);
|
|
100409
|
+
var frames2 = /* @__PURE__ */ new WeakMap();
|
|
100410
|
+
function renderTuiThinking(mate, width, model, phase = "Thinking") {
|
|
100411
|
+
const status = truncateCells(`\u2726 ${phase}\u2026`, width), statusStart = Math.max(0, Math.floor((width - cells(status)) / 2));
|
|
100412
|
+
const name = truncateCells(mate, Math.max(0, statusStart - 1));
|
|
100413
|
+
const spans = [
|
|
100414
|
+
{ text: name, bold: true, color: "#5a85eb" },
|
|
100415
|
+
{ text: " ".repeat(Math.max(0, statusStart - cells(name))) },
|
|
100416
|
+
{ text: status, bold: true, color: "#80caff" }
|
|
100417
|
+
];
|
|
100418
|
+
const rows2 = name ? [{ text: spans.map((span) => span.text).join(""), spans }] : [
|
|
100419
|
+
{ text: truncateCells(mate, width), bold: true, color: "#5a85eb" },
|
|
100420
|
+
{ text: status, bold: true, color: "#80caff" }
|
|
100421
|
+
];
|
|
100422
|
+
if (model) rows2.push({ text: truncateCells(model, width), color: "#808080" });
|
|
100423
|
+
return rows2;
|
|
100424
|
+
}
|
|
100425
|
+
function renderTuiStreamingGlow(width, phase) {
|
|
100426
|
+
const size = Math.max(1, Math.min(72, width)), inset = Math.max(0, Math.floor((width - size) / 2));
|
|
100427
|
+
const spans = [
|
|
100428
|
+
{ text: " ".repeat(inset), color: "#e6e6e6" },
|
|
100429
|
+
...Array.from({ length: size }, (_, index) => ({
|
|
100430
|
+
text: "\u2581",
|
|
100431
|
+
color: COLORS[(Math.floor(index * COLORS.length / size - phase / 2) % COLORS.length + COLORS.length) % COLORS.length]
|
|
100432
|
+
})),
|
|
100433
|
+
{ text: " ".repeat(Math.max(0, width - size - inset)), color: "#e6e6e6" }
|
|
100434
|
+
];
|
|
100435
|
+
const line3 = { text: spans.map((span) => span.text).join(""), spans };
|
|
100436
|
+
glowLines.add(line3);
|
|
100437
|
+
return line3;
|
|
100438
|
+
}
|
|
100439
|
+
function isTuiStreamingGlow(line3) {
|
|
100440
|
+
return typeof line3 !== "string" && glowLines.has(line3);
|
|
100441
|
+
}
|
|
100442
|
+
function clearTuiStreamingFrame(state) {
|
|
100443
|
+
frames2.delete(state);
|
|
100444
|
+
}
|
|
100445
|
+
function rememberTuiStreamingFrame(state, frame, width, height, bodyWidth, painted, options) {
|
|
100446
|
+
const mode = options.colorMode ?? "none";
|
|
100447
|
+
if (!painted || !state.isAwaitingAi || state.screen !== "chat" || mode === "none" || options.reducedMotion || state.modelSelector?.open) return;
|
|
100448
|
+
const at = painted.line.indexOf(painted.rendered);
|
|
100449
|
+
if (at < 0) return;
|
|
100450
|
+
const prefix = painted.line.slice(0, at), suffix = painted.line.slice(at + painted.rendered.length);
|
|
100451
|
+
const variants = Array.from({ length: 12 }, (_, phase) => {
|
|
100452
|
+
const glow = renderTuiStreamingGlow(bodyWidth, phase);
|
|
100453
|
+
return prefix + (typeof glow === "string" ? glow : glow.spans.map((span) => foreground(span.text, span.color ?? "#e6e6e6", mode)).join("")) + suffix;
|
|
100454
|
+
});
|
|
100455
|
+
frames2.set(state, {
|
|
100456
|
+
owner: owner(state),
|
|
100457
|
+
width,
|
|
100458
|
+
height,
|
|
100459
|
+
mode,
|
|
100460
|
+
ascii: options.ascii ?? false,
|
|
100461
|
+
rows: frame.split("\n"),
|
|
100462
|
+
row: painted.row,
|
|
100463
|
+
variants,
|
|
100464
|
+
messages: state.messages,
|
|
100465
|
+
message: state.streamingMessage,
|
|
100466
|
+
content: state.streamingMessage?.content,
|
|
100467
|
+
thinking: state.streamingMessage?.thinkingContent,
|
|
100468
|
+
thinkingActive: state.streamingMessage?.thinkingActive,
|
|
100469
|
+
expanded: state.streamingMessage?.thinkingExpanded,
|
|
100470
|
+
model: state.streamingMessage?.modelName,
|
|
100471
|
+
scroll: state.scrollOffset,
|
|
100472
|
+
input: state.input,
|
|
100473
|
+
focus: state.focus,
|
|
100474
|
+
sidebar: state.sidebarOpen,
|
|
100475
|
+
settings: state.settings
|
|
100476
|
+
});
|
|
100477
|
+
}
|
|
100478
|
+
function renderTuiStreamingAnimationFrame(state, width, height, options = {}) {
|
|
100479
|
+
const saved = frames2.get(state);
|
|
100480
|
+
if (options.reducedMotion || !saved || !state.isAwaitingAi || state.screen !== "chat" || state.textSelection || state.form || state.chrome || state.questionEditor || state.paletteOpen || state.modelSelector?.open || saved.owner !== owner(state) || saved.width !== width || saved.height !== height || saved.mode !== (options.colorMode ?? "none") || saved.ascii !== (options.ascii ?? false) || saved.messages !== state.messages || saved.message !== state.streamingMessage || saved.content !== state.streamingMessage?.content || saved.thinking !== state.streamingMessage?.thinkingContent || saved.thinkingActive !== state.streamingMessage?.thinkingActive || saved.expanded !== state.streamingMessage?.thinkingExpanded || saved.model !== state.streamingMessage?.modelName || saved.scroll !== state.scrollOffset || saved.input !== state.input || saved.focus !== state.focus || saved.sidebar !== state.sidebarOpen || saved.settings !== state.settings) return null;
|
|
100481
|
+
saved.rows[saved.row] = saved.variants[(state.streamingPhase % 12 + 12) % 12];
|
|
100482
|
+
return saved.rows.join("\n");
|
|
100483
|
+
}
|
|
100484
|
+
|
|
100236
100485
|
// src/tuiFullscreenChrome.ts
|
|
100237
100486
|
function captureTuiView(state) {
|
|
100238
100487
|
return {
|
|
@@ -100248,6 +100497,7 @@ function captureTuiView(state) {
|
|
|
100248
100497
|
};
|
|
100249
100498
|
}
|
|
100250
100499
|
function restoreTuiView(state, origin) {
|
|
100500
|
+
clearTuiSendState(state);
|
|
100251
100501
|
Object.assign(state, origin);
|
|
100252
100502
|
state.inputCursor = origin.inputCursor ?? null;
|
|
100253
100503
|
state.navigationIndex = ["chats", "apps", "projects", "workflows", "tasks"].indexOf(state.workspace);
|
|
@@ -100276,6 +100526,7 @@ function closeTuiFullscreen(state) {
|
|
|
100276
100526
|
return true;
|
|
100277
100527
|
}
|
|
100278
100528
|
if (state.screen === "chat" || state.screen === "example") {
|
|
100529
|
+
clearTuiSendState(state);
|
|
100279
100530
|
if (!state.input.startsWith("/")) state.drafts[state.screen === "example" ? `example:${state.activeExample?.chat.id}` : state.activeChatId ?? "new"] = state.input;
|
|
100280
100531
|
const origin = state.chatOrigin;
|
|
100281
100532
|
state.chatOrigin = null;
|
|
@@ -100504,7 +100755,9 @@ function createInitialTuiState() {
|
|
|
100504
100755
|
chatContextAuthoringControls: {},
|
|
100505
100756
|
status: null,
|
|
100506
100757
|
isBusy: false,
|
|
100507
|
-
isAwaitingAi: false
|
|
100758
|
+
isAwaitingAi: false,
|
|
100759
|
+
streamingMessage: null,
|
|
100760
|
+
streamingPhase: 0
|
|
100508
100761
|
};
|
|
100509
100762
|
}
|
|
100510
100763
|
function programmaticQuickstart() {
|
|
@@ -100560,6 +100813,7 @@ function resetEndedTuiSession(state, hasSession) {
|
|
|
100560
100813
|
return true;
|
|
100561
100814
|
}
|
|
100562
100815
|
function renderTuiFrame(state, width, height, options = {}) {
|
|
100816
|
+
clearTuiStreamingFrame(state);
|
|
100563
100817
|
if (state.screen !== "chat") clearChatRenderCache(state);
|
|
100564
100818
|
fenceTuiSettingsView(state);
|
|
100565
100819
|
beginPointerFrame(state, width, height);
|
|
@@ -100569,13 +100823,23 @@ function renderTuiFrame(state, width, height, options = {}) {
|
|
|
100569
100823
|
const teamBanner = state.signedIn && state.activeTeamId ? [{ text: teamIdentityLabel(state), color: "#5a85eb", bold: true }] : [];
|
|
100570
100824
|
const embedHero = state.screen === "embed" ? renderEmbedHero(state, bodyWidth, height) : null;
|
|
100571
100825
|
const stickyRows = state.screen === "embed" ? embedHero.length + 1 : state.screen === "results-view" ? 2 : state.screen === "project" && state.activeProject ? renderProjectIdentity(state.activeProject, { width: bodyWidth }).length + renderProjectTabs(state.projectTab, bodyWidth).length : state.screen === "app" && state.activeApp ? renderTuiAppIdentity(state.activeApp, bodyWidth).length + renderTuiAppTabs(state.appTab, bodyWidth).length : state.screen === "app-skill" && state.activeAppSkill ? renderTuiAppsSkillIdentity(state.activeAppSkill, bodyWidth).length + renderTuiAppsSkillTabs(state.appSkillTab, bodyWidth).length : state.screen === "workflow" && state.activeWorkflow ? renderWorkflowIdentity(state.activeWorkflow, { width: bodyWidth, run: state.workflowTab === "runs" ? state.workflowRuns[state.selectedWorkflowRunIndex] : void 0 }).length + (bodyWidth < 36 ? 7 : 4) : 0;
|
|
100572
|
-
|
|
100826
|
+
let glow;
|
|
100827
|
+
const frame = renderWorkspaceFrame(
|
|
100573
100828
|
state,
|
|
100574
100829
|
width,
|
|
100575
100830
|
height,
|
|
100576
100831
|
[...header2, ...teamBanner, ...renderBody(state, bodyWidth, height, embedHero ?? void 0)],
|
|
100577
|
-
{
|
|
100832
|
+
{
|
|
100833
|
+
...options,
|
|
100834
|
+
stickyRows: stickyRows + header2.length + teamBanner.length,
|
|
100835
|
+
stickyFallbackRows: embedHero ? header2.length + teamBanner.length : void 0,
|
|
100836
|
+
onBodyLine: (value, row3, rendered, line3) => {
|
|
100837
|
+
if (isTuiStreamingGlow(value)) glow = { row: row3, rendered, line: line3 };
|
|
100838
|
+
}
|
|
100839
|
+
}
|
|
100578
100840
|
);
|
|
100841
|
+
rememberTuiStreamingFrame(state, frame, width, height, bodyWidth, glow, options);
|
|
100842
|
+
return frame;
|
|
100579
100843
|
}
|
|
100580
100844
|
function teamIdentityLabel(state) {
|
|
100581
100845
|
const name = terminalText(state.activeTeamName?.trim() || "Team").replace(/\s+/g, " ").slice(0, 80);
|
|
@@ -100687,7 +100951,7 @@ function renderScreenBody(state, width, height, embedHero) {
|
|
|
100687
100951
|
case "projects":
|
|
100688
100952
|
return [...homeHeader(state, width, height), ...renderProjectCarousel(filteredProjects(state.projects, state.filter), width, state.selectedIndex, state.focus === "content")];
|
|
100689
100953
|
case "project":
|
|
100690
|
-
return state.activeProject ? state.projectTab === "tasks" ? [...renderProjectIdentity(state.activeProject, { width }), ...renderProjectPointerTabs("tasks", width), "", ...renderTaskBoard2(state.tasks, { width, selectedTaskId: filterTasks(state.tasks, state.filter)[state.selectedIndex]?.taskId, query: state.filter })] : 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 }) : ["Projects", "Loading project\u2026"];
|
|
100954
|
+
return state.activeProject ? state.projectTab === "tasks" ? [...renderProjectIdentity(state.activeProject, { width }), ...renderProjectPointerTabs("tasks", width), "", ...renderTaskBoard2(state.tasks, { width, selectedTaskId: filterTasks(state.tasks, state.filter)[state.selectedIndex]?.taskId, query: state.filter, viewport: taskViewport(state, height, renderProjectIdentity(state.activeProject, { width }).length + renderProjectPointerTabs("tasks", width).length + 1) })] : 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 }) : ["Projects", "Loading project\u2026"];
|
|
100691
100955
|
case "status":
|
|
100692
100956
|
return renderStatus(state, width);
|
|
100693
100957
|
case "results-view": {
|
|
@@ -100719,9 +100983,9 @@ function renderScreenBody(state, width, height, embedHero) {
|
|
|
100719
100983
|
case "workflow":
|
|
100720
100984
|
return renderWorkflowDetail(state, width);
|
|
100721
100985
|
case "tasks":
|
|
100722
|
-
return [...homeHeader(state, width, height), ...renderTasks(state, width)];
|
|
100986
|
+
return [...homeHeader(state, width, height), ...renderTasks(state, width, height, homeHeader(state, width, height).length)];
|
|
100723
100987
|
case "task":
|
|
100724
|
-
return renderTaskDetail2(state, width);
|
|
100988
|
+
return renderTaskDetail2(state, width, height);
|
|
100725
100989
|
case "start":
|
|
100726
100990
|
default:
|
|
100727
100991
|
return [...renderHomeChatCards(state, width, height), ...state.signedIn && state.activeTeamId ? ["", teamAiReminder()] : []];
|
|
@@ -100761,11 +101025,18 @@ function renderHelp(width) {
|
|
|
100761
101025
|
"Outside TUI: openmates --help, openmates chats --help, openmates apps --help"
|
|
100762
101026
|
].flatMap((line3) => wrap(line3, width));
|
|
100763
101027
|
}
|
|
100764
|
-
function
|
|
100765
|
-
return
|
|
101028
|
+
function taskViewport(state, height, prefixRows = 0) {
|
|
101029
|
+
return {
|
|
101030
|
+
start: Math.max(0, state.scrollOffset - prefixRows - 4),
|
|
101031
|
+
end: state.scrollOffset + height + 4,
|
|
101032
|
+
followSelection: state.followSelection && state.focus === "content"
|
|
101033
|
+
};
|
|
101034
|
+
}
|
|
101035
|
+
function renderTasks(state, width, height, prefixRows = 0) {
|
|
101036
|
+
return renderTaskBoard2(state.tasks, { width, selectedTaskId: filterTasks(state.tasks, state.filter, state.taskStatusFilter || void 0)[state.selectedIndex]?.taskId, query: state.filter, status: state.taskStatusFilter || void 0, viewport: taskViewport(state, height, prefixRows) });
|
|
100766
101037
|
}
|
|
100767
|
-
function renderTaskDetail2(state, width) {
|
|
100768
|
-
if (!state.activeTask) return renderTasks(state, width);
|
|
101038
|
+
function renderTaskDetail2(state, width, height) {
|
|
101039
|
+
if (!state.activeTask) return renderTasks(state, width, height);
|
|
100769
101040
|
return renderTaskDetails(state.activeTask, {
|
|
100770
101041
|
width,
|
|
100771
101042
|
activity: state.taskContext?.activity,
|
|
@@ -100868,8 +101139,7 @@ function renderExampleChat(state, width, height) {
|
|
|
100868
101139
|
}
|
|
100869
101140
|
return lines.flatMap((line3) => typeof line3 === "string" ? wrap(line3, width) : [line3]);
|
|
100870
101141
|
}
|
|
100871
|
-
function renderChat(state, width, height) {
|
|
100872
|
-
const lines = renderChatHeader(state, width, height);
|
|
101142
|
+
function renderChat(state, width, height, fullHistory = false) {
|
|
100873
101143
|
const embeds = new Map(Object.entries(state.chatEmbeds));
|
|
100874
101144
|
const cacheContext = {
|
|
100875
101145
|
owner: JSON.stringify([state.signedIn, state.currentUserHash, state.activeTeamId, state.activeChatId, state.routeVersion]),
|
|
@@ -100896,47 +101166,84 @@ function renderChat(state, width, height) {
|
|
|
100896
101166
|
return firstEmbedId;
|
|
100897
101167
|
};
|
|
100898
101168
|
let contextIndex2 = 0, viewOffset = 0, questionOffset = 0;
|
|
100899
|
-
|
|
101169
|
+
const offsets = state.messages.map((message) => {
|
|
100900
101170
|
const event = message.role === "system" ? parseChatContextContent(message.content) : null;
|
|
100901
|
-
|
|
100902
|
-
|
|
100903
|
-
|
|
101171
|
+
const offset = { event, contextIndex: contextIndex2 + (event ? 1 : 0), viewOffset, questionOffset };
|
|
101172
|
+
if (event) contextIndex2++;
|
|
101173
|
+
else {
|
|
101174
|
+
viewOffset += messageResultsViews(message.content).length;
|
|
101175
|
+
if (message.role === "assistant") questionOffset += messageQuestions(message.content).length;
|
|
101176
|
+
}
|
|
101177
|
+
return offset;
|
|
101178
|
+
});
|
|
101179
|
+
const footer = [];
|
|
101180
|
+
if (state.projectFocusPending) footer.push("Project access starts after the countdown. /project-focus-reject to cancel.");
|
|
101181
|
+
if (state.signedIn && state.activeTeamId) footer.push(teamAiReminder());
|
|
101182
|
+
if (state.followUpSuggestions.length) footer.push("", "Suggestions", ...state.followUpSuggestions.slice(0, 3).map((s, i) => ` ${i + 1}. ${s}`));
|
|
101183
|
+
if (state.status) footer.push("", state.status);
|
|
101184
|
+
const wrappedFooter = footer.flatMap((line3) => typeof line3 === "string" ? wrap(line3, width) : [line3]);
|
|
101185
|
+
const blocks = [];
|
|
101186
|
+
let rowCount = wrappedFooter.length;
|
|
101187
|
+
if (state.isAwaitingAi && !state.streamingMessage?.content.trim()) {
|
|
101188
|
+
const mate = messageLabel("assistant", state.streamingMessage?.title, state.streamingMessage?.category, state.activeChat);
|
|
101189
|
+
const waiting = [...renderTuiThinking(mate, width, state.streamingMessage?.modelName), ...renderTuiReasoning(state.streamingMessage, width), renderTuiStreamingGlow(width, state.streamingPhase), ""];
|
|
101190
|
+
blocks.push(waiting);
|
|
101191
|
+
rowCount += waiting.length;
|
|
101192
|
+
}
|
|
101193
|
+
const budget = Math.max(0, state.scrollOffset) + height + 1;
|
|
101194
|
+
for (let index = state.messages.length - 1; index >= 0; index--) {
|
|
101195
|
+
const message = state.messages[index], offset = offsets[index], rows2 = [];
|
|
101196
|
+
if (offset.event) {
|
|
101197
|
+
const event = offset.event;
|
|
101198
|
+
rows2.push(`${chatContextSummary(event)} \xB7 /context ${offset.contextIndex}`);
|
|
100904
101199
|
if (event.type === "project_authoring_recommendation") {
|
|
100905
101200
|
const job = state.chatContextAuthoringJobs[event.event_id];
|
|
100906
|
-
|
|
101201
|
+
rows2.push(job ? `Authoring: ${job.status} \xB7 ${job.status === "needs_write_approval" ? "/authoring-save" : "/authoring-refresh"} ${offset.contextIndex}` : `[${event.action === "create" ? "Create" : "Update"} ${event.kind === "focus" ? "Focus" : "Workflow"}] /focus-author ${offset.contextIndex}`);
|
|
100907
101202
|
}
|
|
100908
|
-
|
|
100909
|
-
continue;
|
|
101203
|
+
} else {
|
|
101204
|
+
if (message === state.streamingMessage && !message.content.trim()) continue;
|
|
101205
|
+
const questionBlocks = message.role === "assistant";
|
|
101206
|
+
const prepared = cachedChatLayout(
|
|
101207
|
+
state,
|
|
101208
|
+
message,
|
|
101209
|
+
message.content,
|
|
101210
|
+
{ ...cacheContext, variant: questionBlocks ? "questions" : "literal-questions", cacheable: cacheable.has(index) },
|
|
101211
|
+
() => prepareMessageContent(message.content, width, state, questionBlocks)
|
|
101212
|
+
);
|
|
101213
|
+
const label3 = messageLabel(message.role, message.title, message.category, state.activeChat, message.remoteUser);
|
|
101214
|
+
if (state.isAwaitingAi && message === state.streamingMessage) rows2.push(...renderTuiThinking(label3, width, message.modelName, message.thinkingActive ? "Thinking" : tuiResponsePhase(prepared.segments)));
|
|
101215
|
+
else {
|
|
101216
|
+
rows2.push({ text: label3, color: "#5a85eb", bold: true });
|
|
101217
|
+
if (message.role === "assistant" && message.modelName) rows2.push({ text: message.modelName, color: "#808080" });
|
|
101218
|
+
}
|
|
101219
|
+
if (message.role === "assistant") rows2.push(...renderTuiReasoning(message, width));
|
|
101220
|
+
rows2.push(...renderPreparedMessageContent(
|
|
101221
|
+
prepared,
|
|
101222
|
+
width,
|
|
101223
|
+
embeds,
|
|
101224
|
+
state,
|
|
101225
|
+
questionBlocks ? message.embedIds : void 0,
|
|
101226
|
+
offset.viewOffset,
|
|
101227
|
+
offset.questionOffset,
|
|
101228
|
+
defaultEmbedId
|
|
101229
|
+
));
|
|
101230
|
+
if (state.isAwaitingAi && message === state.streamingMessage) rows2.push(renderTuiStreamingGlow(width, state.streamingPhase));
|
|
100910
101231
|
}
|
|
100911
|
-
|
|
100912
|
-
const
|
|
100913
|
-
|
|
100914
|
-
|
|
100915
|
-
|
|
100916
|
-
|
|
100917
|
-
|
|
100918
|
-
|
|
100919
|
-
|
|
100920
|
-
|
|
100921
|
-
|
|
100922
|
-
|
|
100923
|
-
|
|
100924
|
-
|
|
100925
|
-
|
|
100926
|
-
viewOffset,
|
|
100927
|
-
questionOffset,
|
|
100928
|
-
defaultEmbedId
|
|
100929
|
-
));
|
|
100930
|
-
viewOffset += prepared.viewCount;
|
|
100931
|
-
if (questionBlocks) questionOffset += prepared.questionCount;
|
|
100932
|
-
lines.push("");
|
|
100933
|
-
}
|
|
100934
|
-
if (state.projectFocusPending) lines.push("Project access starts after the countdown. /project-focus-reject to cancel.");
|
|
100935
|
-
if (state.isAwaitingAi) lines.push(`${messageLabel("assistant", null, null, state.activeChat)} is typing...`);
|
|
100936
|
-
if (state.signedIn && state.activeTeamId) lines.push(teamAiReminder());
|
|
100937
|
-
if (state.followUpSuggestions.length) lines.push("", "Suggestions", ...state.followUpSuggestions.slice(0, 3).map((s, i) => ` ${i + 1}. ${s}`));
|
|
100938
|
-
if (state.status) lines.push("", state.status);
|
|
100939
|
-
return lines.flatMap((line3) => typeof line3 === "string" ? wrap(line3, width) : [line3]);
|
|
101232
|
+
rows2.push("");
|
|
101233
|
+
const wrapped2 = rows2.flatMap((line3) => typeof line3 === "string" ? wrap(line3, width) : [line3]);
|
|
101234
|
+
blocks.push(wrapped2);
|
|
101235
|
+
rowCount += wrapped2.length;
|
|
101236
|
+
if (!fullHistory && !(state.followSelection && state.focus === "content") && rowCount >= budget) break;
|
|
101237
|
+
}
|
|
101238
|
+
return [...renderChatHeader(state, width, height), ...blocks.reverse().flat(), ...wrappedFooter];
|
|
101239
|
+
}
|
|
101240
|
+
function renderTuiReasoning(message, width) {
|
|
101241
|
+
if (!message?.thinkingContent?.trim()) return [];
|
|
101242
|
+
const summary = pointerLine(
|
|
101243
|
+
`\u2726 Thinking for this response ${message.thinkingExpanded ? "\u25BE" : "\u25B8"} /thinking`,
|
|
101244
|
+
{ kind: "command", command: `/thinking${message.id ? " " + message.id : ""}` }
|
|
101245
|
+
);
|
|
101246
|
+
return [summary, ...message.thinkingExpanded ? wrap(message.thinkingContent, width).map((text7) => ({ text: text7, color: "#a0a0a0" })) : []];
|
|
100940
101247
|
}
|
|
100941
101248
|
function teamAiReminder() {
|
|
100942
101249
|
return "To ask AI, mention @openmates or a configured Mate.";
|
|
@@ -100989,17 +101296,13 @@ function relativeTime(timestamp) {
|
|
|
100989
101296
|
function renderStatus(state, width) {
|
|
100990
101297
|
return ["OpenMates", "", state.status ?? "Working..."].flatMap((line3) => wrap(line3, width));
|
|
100991
101298
|
}
|
|
100992
|
-
function prepareMessageContent(content, width, state, questionBlocks = true
|
|
101299
|
+
function prepareMessageContent(content, width, state, questionBlocks = true) {
|
|
100993
101300
|
const segments2 = parseMessageSegments(content, { preserveCodeFences: true }).map((segment) => segment.type === "embed" ? segment : {
|
|
100994
101301
|
type: "text",
|
|
100995
101302
|
value: segment.value,
|
|
100996
101303
|
blocks: parseTuiMarkdown(segment.value, width, { resolveEmbedAlias: (id) => state ? aliasForEmbed(state, id) : id, questionBlocks })
|
|
100997
101304
|
});
|
|
100998
|
-
return {
|
|
100999
|
-
segments: segments2,
|
|
101000
|
-
viewCount: segments2.reduce((count, segment) => count + (segment.type === "text" ? segment.blocks.filter((block) => block.type === "results-view").length : 0), 0),
|
|
101001
|
-
questionCount: countQuestions && questionBlocks ? messageQuestions(content).length : 0
|
|
101002
|
-
};
|
|
101305
|
+
return { segments: segments2 };
|
|
101003
101306
|
}
|
|
101004
101307
|
function renderMessageContentStyled(content, width, embeds = /* @__PURE__ */ new Map(), state, extraIds = [], viewOffset = 0, questionOffset = 0, questionBlocks = true) {
|
|
101005
101308
|
return renderPreparedMessageContent(
|
|
@@ -101431,6 +101734,7 @@ function rememberDraft(state) {
|
|
|
101431
101734
|
if (state.workspace === "chats" && !state.input.startsWith("/")) state.drafts[chatDraftKey(state)] = state.input;
|
|
101432
101735
|
}
|
|
101433
101736
|
function route(state, workspace, screen) {
|
|
101737
|
+
clearTuiSendState(state);
|
|
101434
101738
|
if (state.settings) closeTuiSettings(state);
|
|
101435
101739
|
if (state.input) rememberDraft(state);
|
|
101436
101740
|
state.workspace = workspace;
|
|
@@ -101902,6 +102206,18 @@ async function handleWorkspaceCommand(context, command) {
|
|
|
101902
102206
|
}
|
|
101903
102207
|
return true;
|
|
101904
102208
|
}
|
|
102209
|
+
case "/thinking": {
|
|
102210
|
+
const messages = [...state.messages, ...state.streamingMessage && !state.messages.includes(state.streamingMessage) ? [state.streamingMessage] : []];
|
|
102211
|
+
const message = arg ? messages.find((message2) => message2.id === arg) : messages.findLast((message2) => message2.role === "assistant" && message2.thinkingContent?.trim());
|
|
102212
|
+
if (state.input.trim() === command) {
|
|
102213
|
+
state.input = "";
|
|
102214
|
+
state.inputCursor = null;
|
|
102215
|
+
}
|
|
102216
|
+
if (message?.thinkingContent?.trim()) message.thinkingExpanded = !message.thinkingExpanded;
|
|
102217
|
+
else state.status = "No visible thinking is available for this response.";
|
|
102218
|
+
render();
|
|
102219
|
+
return true;
|
|
102220
|
+
}
|
|
101905
102221
|
case "/browse":
|
|
101906
102222
|
state.homeShowAll = !state.homeShowAll;
|
|
101907
102223
|
state.selectedIndex = 0;
|
|
@@ -103384,21 +103700,21 @@ function string4(value) {
|
|
|
103384
103700
|
function ownerToken(session, teamId) {
|
|
103385
103701
|
return createHmac4("sha256", Buffer.from(session.masterKeyExportedB64, "base64")).update(JSON.stringify([session.apiUrl, session.hashedEmail, teamId, session.createdAt])).digest("hex");
|
|
103386
103702
|
}
|
|
103387
|
-
function keyFor(
|
|
103388
|
-
return createHmac4("sha256", Buffer.from(
|
|
103703
|
+
function keyFor(owner2, chatId) {
|
|
103704
|
+
return createHmac4("sha256", Buffer.from(owner2, "hex")).update(chatId).digest("hex");
|
|
103389
103705
|
}
|
|
103390
103706
|
function isRecord5(value) {
|
|
103391
103707
|
const v = object4(value);
|
|
103392
103708
|
return typeof v.ciphertext === "string" && v.ciphertext.length > 0 && Number.isSafeInteger(v.version) && v.version >= 0 && typeof v.pending === "boolean";
|
|
103393
103709
|
}
|
|
103394
|
-
function readLocal(
|
|
103710
|
+
function readLocal(owner2, chatId) {
|
|
103395
103711
|
try {
|
|
103396
103712
|
const path2 = join19(resolveStateDir(), FILE);
|
|
103397
103713
|
const raw = readFileSync17(path2, "utf8");
|
|
103398
103714
|
if (Buffer.byteLength(raw) > MAX_FILE_BYTES3) return null;
|
|
103399
103715
|
const envelope = object4(JSON.parse(raw));
|
|
103400
103716
|
if (envelope.version !== 2) return null;
|
|
103401
|
-
const record10 = object4(object4(envelope.owners)[
|
|
103717
|
+
const record10 = object4(object4(envelope.owners)[owner2])[keyFor(owner2, chatId)];
|
|
103402
103718
|
return isRecord5(record10) ? record10 : null;
|
|
103403
103719
|
} catch {
|
|
103404
103720
|
return null;
|
|
@@ -103407,7 +103723,7 @@ function readLocal(owner, chatId) {
|
|
|
103407
103723
|
function sameRecord(left, right) {
|
|
103408
103724
|
return left === right || !!left && !!right && left.ciphertext === right.ciphertext && left.version === right.version && left.pending === right.pending;
|
|
103409
103725
|
}
|
|
103410
|
-
async function writeLocal(
|
|
103726
|
+
async function writeLocal(owner2, chatId, record10, current2, expected) {
|
|
103411
103727
|
if (!current2()) throw new Error("Chat model preference owner changed.");
|
|
103412
103728
|
const dir = resolveStateDir();
|
|
103413
103729
|
mkdirSync16(dir, { recursive: true, mode: 448 });
|
|
@@ -103432,11 +103748,11 @@ async function writeLocal(owner, chatId, record10, current2, expected) {
|
|
|
103432
103748
|
}
|
|
103433
103749
|
} catch {
|
|
103434
103750
|
}
|
|
103435
|
-
const chats = owners[
|
|
103436
|
-
const existing = chats[keyFor(
|
|
103751
|
+
const chats = owners[owner2] ?? {};
|
|
103752
|
+
const existing = chats[keyFor(owner2, chatId)] ?? null;
|
|
103437
103753
|
if (expected !== void 0 && !sameRecord(existing, expected)) return existing;
|
|
103438
|
-
chats[keyFor(
|
|
103439
|
-
owners[
|
|
103754
|
+
chats[keyFor(owner2, chatId)] = record10;
|
|
103755
|
+
owners[owner2] = chats;
|
|
103440
103756
|
if (Object.values(owners).reduce((sum, values) => sum + Object.keys(values).length, 0) > MAX_CHATS)
|
|
103441
103757
|
throw new Error("Chat model preference cache is full.");
|
|
103442
103758
|
const encoded = JSON.stringify({ version: 2, owners });
|
|
@@ -103515,21 +103831,21 @@ function createChatModelPreferences(client2) {
|
|
|
103515
103831
|
if (!client2.hasSession()) throw new Error("Sign in to choose a chat model.");
|
|
103516
103832
|
const session = client2.getSession();
|
|
103517
103833
|
const teamId = client2.resolveTeamContext();
|
|
103518
|
-
const
|
|
103834
|
+
const owner2 = ownerToken(session, teamId);
|
|
103519
103835
|
const persisted = loadSession();
|
|
103520
|
-
if (persisted && ownerToken(persisted, teamId) !==
|
|
103836
|
+
if (persisted && ownerToken(persisted, teamId) !== owner2)
|
|
103521
103837
|
throw new Error("Chat model preference owner changed.");
|
|
103522
103838
|
const current2 = () => {
|
|
103523
103839
|
try {
|
|
103524
|
-
if (!client2.hasSession() || ownerToken(client2.getSession(), client2.resolveTeamContext()) !==
|
|
103840
|
+
if (!client2.hasSession() || ownerToken(client2.getSession(), client2.resolveTeamContext()) !== owner2) return false;
|
|
103525
103841
|
if (!persisted) return true;
|
|
103526
103842
|
const onDisk = loadSession();
|
|
103527
|
-
return !!onDisk && ownerToken(onDisk, teamId) ===
|
|
103843
|
+
return !!onDisk && ownerToken(onDisk, teamId) === owner2;
|
|
103528
103844
|
} catch {
|
|
103529
103845
|
return false;
|
|
103530
103846
|
}
|
|
103531
103847
|
};
|
|
103532
|
-
return { owner, teamId, current: current2, masterKey: Buffer.from(session.masterKeyExportedB64, "base64") };
|
|
103848
|
+
return { owner: owner2, teamId, current: current2, masterKey: Buffer.from(session.masterKeyExportedB64, "base64") };
|
|
103533
103849
|
};
|
|
103534
103850
|
const checked = (current2) => {
|
|
103535
103851
|
if (!current2()) throw new Error("Chat model preference owner changed.");
|
|
@@ -103539,10 +103855,10 @@ function createChatModelPreferences(client2) {
|
|
|
103539
103855
|
if (plaintext === null) throw new Error("Chat model preference could not be decrypted.");
|
|
103540
103856
|
return parseSelection(plaintext);
|
|
103541
103857
|
};
|
|
103542
|
-
const stateKey = (
|
|
103543
|
-
const publish = (
|
|
103858
|
+
const stateKey = (owner2, chatId) => `${owner2}:${chatId}`;
|
|
103859
|
+
const publish = (owner2, chatId, state, current2) => {
|
|
103544
103860
|
checked(current2);
|
|
103545
|
-
const key = stateKey(
|
|
103861
|
+
const key = stateKey(owner2, chatId);
|
|
103546
103862
|
states2.set(key, state);
|
|
103547
103863
|
for (const listener of listeners.get(key) ?? []) {
|
|
103548
103864
|
try {
|
|
@@ -103552,18 +103868,18 @@ function createChatModelPreferences(client2) {
|
|
|
103552
103868
|
}
|
|
103553
103869
|
return state;
|
|
103554
103870
|
};
|
|
103555
|
-
const withChat = (
|
|
103556
|
-
const key = stateKey(
|
|
103871
|
+
const withChat = (owner2, chatId, work) => {
|
|
103872
|
+
const key = stateKey(owner2, chatId);
|
|
103557
103873
|
const task = (serial.get(key) ?? Promise.resolve()).then(work);
|
|
103558
103874
|
serial.set(key, task.catch(() => {
|
|
103559
103875
|
}));
|
|
103560
103876
|
return task;
|
|
103561
103877
|
};
|
|
103562
103878
|
const flush = async (chatId, context = capture()) => {
|
|
103563
|
-
const { owner, teamId, current: current2, masterKey } = context;
|
|
103879
|
+
const { owner: owner2, teamId, current: current2, masterKey } = context;
|
|
103564
103880
|
checked(current2);
|
|
103565
|
-
const local = readLocal(
|
|
103566
|
-
if (!local?.pending) return states2.get(stateKey(
|
|
103881
|
+
const local = readLocal(owner2, chatId);
|
|
103882
|
+
if (!local?.pending) return states2.get(stateKey(owner2, chatId)) ?? { selection: "auto", pending: false, restored: false };
|
|
103567
103883
|
const selection = await decrypt(local, masterKey);
|
|
103568
103884
|
try {
|
|
103569
103885
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
@@ -103573,15 +103889,15 @@ function createChatModelPreferences(client2) {
|
|
|
103573
103889
|
const accepted = await client2.compareAndSetChatModelPreference(chatId, local.ciphertext, expected, teamId);
|
|
103574
103890
|
checked(current2);
|
|
103575
103891
|
if (!accepted) continue;
|
|
103576
|
-
await writeLocal(
|
|
103892
|
+
await writeLocal(owner2, chatId, { ...accepted, pending: false }, current2);
|
|
103577
103893
|
const state = { selection, pending: false, restored: true };
|
|
103578
|
-
return publish(
|
|
103894
|
+
return publish(owner2, chatId, state, current2);
|
|
103579
103895
|
}
|
|
103580
103896
|
throw new Error("Chat model preference conflicted repeatedly.");
|
|
103581
103897
|
} catch {
|
|
103582
103898
|
checked(current2);
|
|
103583
103899
|
const state = { selection, pending: true, restored: true };
|
|
103584
|
-
return publish(
|
|
103900
|
+
return publish(owner2, chatId, state, current2);
|
|
103585
103901
|
}
|
|
103586
103902
|
};
|
|
103587
103903
|
return {
|
|
@@ -103604,32 +103920,32 @@ function createChatModelPreferences(client2) {
|
|
|
103604
103920
|
},
|
|
103605
103921
|
async restore(chatId) {
|
|
103606
103922
|
const context = capture();
|
|
103607
|
-
const { owner, current: current2, masterKey } = context;
|
|
103923
|
+
const { owner: owner2, current: current2, masterKey } = context;
|
|
103608
103924
|
checked(current2);
|
|
103609
|
-
const local = readLocal(
|
|
103925
|
+
const local = readLocal(owner2, chatId);
|
|
103610
103926
|
if (local) {
|
|
103611
103927
|
const selection = await decrypt(local, masterKey);
|
|
103612
103928
|
checked(current2);
|
|
103613
|
-
const initial = publish(
|
|
103614
|
-
void withChat(
|
|
103929
|
+
const initial = publish(owner2, chatId, { selection, pending: local.pending, restored: true }, current2);
|
|
103930
|
+
void withChat(owner2, chatId, async () => {
|
|
103615
103931
|
if (local.pending) return flush(chatId, context);
|
|
103616
103932
|
return refreshRemote(chatId, context, local);
|
|
103617
103933
|
}).catch(() => {
|
|
103618
103934
|
});
|
|
103619
103935
|
return initial;
|
|
103620
103936
|
}
|
|
103621
|
-
return withChat(
|
|
103937
|
+
return withChat(owner2, chatId, () => refreshRemote(chatId, context, null));
|
|
103622
103938
|
},
|
|
103623
103939
|
async select(chatId, selection) {
|
|
103624
103940
|
const context = capture();
|
|
103625
103941
|
return withChat(context.owner, chatId, async () => {
|
|
103626
|
-
const { owner, current: current2, masterKey } = context;
|
|
103942
|
+
const { owner: owner2, current: current2, masterKey } = context;
|
|
103627
103943
|
const serialized = encodeSelection(selection);
|
|
103628
103944
|
const ciphertext = await encryptWithAesGcmCombined(serialized, masterKey);
|
|
103629
103945
|
checked(current2);
|
|
103630
|
-
const previous = readLocal(
|
|
103631
|
-
await writeLocal(
|
|
103632
|
-
publish(
|
|
103946
|
+
const previous = readLocal(owner2, chatId);
|
|
103947
|
+
await writeLocal(owner2, chatId, { ciphertext, version: previous?.version ?? 0, pending: true }, current2);
|
|
103948
|
+
publish(owner2, chatId, { selection, pending: true, restored: true }, current2);
|
|
103633
103949
|
return flush(chatId, context);
|
|
103634
103950
|
});
|
|
103635
103951
|
},
|
|
@@ -103662,7 +103978,7 @@ function createChatModelPreferences(client2) {
|
|
|
103662
103978
|
}
|
|
103663
103979
|
};
|
|
103664
103980
|
async function refreshRemote(chatId, context, local) {
|
|
103665
|
-
const { owner, teamId, current: current2, masterKey } = context;
|
|
103981
|
+
const { owner: owner2, teamId, current: current2, masterKey } = context;
|
|
103666
103982
|
checked(current2);
|
|
103667
103983
|
let remote = null;
|
|
103668
103984
|
let confirmed = false;
|
|
@@ -103673,7 +103989,7 @@ function createChatModelPreferences(client2) {
|
|
|
103673
103989
|
checked(current2);
|
|
103674
103990
|
if (!local) {
|
|
103675
103991
|
const state2 = { selection: "auto", pending: false, restored: false };
|
|
103676
|
-
return publish(
|
|
103992
|
+
return publish(owner2, chatId, state2, current2);
|
|
103677
103993
|
}
|
|
103678
103994
|
}
|
|
103679
103995
|
checked(current2);
|
|
@@ -103681,21 +103997,21 @@ function createChatModelPreferences(client2) {
|
|
|
103681
103997
|
const ciphertext = await encryptWithAesGcmCombined(encodeSelection("auto"), masterKey);
|
|
103682
103998
|
checked(current2);
|
|
103683
103999
|
const autoRecord = { ciphertext, version: 0, pending: false };
|
|
103684
|
-
const stored = await writeLocal(
|
|
104000
|
+
const stored = await writeLocal(owner2, chatId, autoRecord, current2, local);
|
|
103685
104001
|
checked(current2);
|
|
103686
|
-
if (!stored) return publish(
|
|
104002
|
+
if (!stored) return publish(owner2, chatId, { selection: "auto", pending: false, restored: false }, current2);
|
|
103687
104003
|
if (stored !== autoRecord) {
|
|
103688
104004
|
const selection2 = await decrypt(stored, masterKey);
|
|
103689
|
-
return publish(
|
|
104005
|
+
return publish(owner2, chatId, { selection: selection2, pending: stored.pending, restored: true }, current2);
|
|
103690
104006
|
}
|
|
103691
|
-
return publish(
|
|
104007
|
+
return publish(owner2, chatId, { selection: "auto", pending: false, restored: true }, current2);
|
|
103692
104008
|
}
|
|
103693
104009
|
const chosen = remote && (!local || remote.version > local.version) ? remote : local;
|
|
103694
104010
|
const selection = chosen ? await decrypt(chosen, masterKey) : "auto";
|
|
103695
104011
|
checked(current2);
|
|
103696
|
-
if (remote && chosen === remote) await writeLocal(
|
|
104012
|
+
if (remote && chosen === remote) await writeLocal(owner2, chatId, { ...remote, pending: false }, current2);
|
|
103697
104013
|
const state = { selection, pending: false, restored: true };
|
|
103698
|
-
return publish(
|
|
104014
|
+
return publish(owner2, chatId, state, current2);
|
|
103699
104015
|
}
|
|
103700
104016
|
}
|
|
103701
104017
|
|
|
@@ -103713,6 +104029,7 @@ async function runTui(client2, terminal = new TuiTerminal(), startupServices) {
|
|
|
103713
104029
|
hydrateExamples(state);
|
|
103714
104030
|
let resolveResult = null;
|
|
103715
104031
|
let renderTimer = null;
|
|
104032
|
+
let lastFrameOwner = null;
|
|
103716
104033
|
let closed = false;
|
|
103717
104034
|
let stopActivity;
|
|
103718
104035
|
let activityTimer;
|
|
@@ -103745,9 +104062,25 @@ async function runTui(client2, terminal = new TuiTerminal(), startupServices) {
|
|
|
103745
104062
|
void refreshActivity();
|
|
103746
104063
|
}, 3e4);
|
|
103747
104064
|
const activityAnimation = setInterval(() => {
|
|
103748
|
-
if (
|
|
103749
|
-
|
|
104065
|
+
if (closed) return;
|
|
104066
|
+
const sidebarActivity = state.runningChatIds.length > 0;
|
|
104067
|
+
if (sidebarActivity) state.activityFrame = (state.activityFrame + 1) % 4;
|
|
104068
|
+
const streaming = state.screen === "chat" && state.isAwaitingAi && state.streamingMessage && !state.textSelection && !terminal.reducedMotion && !terminal.isOutputBlocked && lastFrameOwner?.();
|
|
104069
|
+
if (streaming) {
|
|
104070
|
+
state.streamingPhase = (state.streamingPhase + 1) % 12;
|
|
104071
|
+
}
|
|
104072
|
+
if (sidebarActivity) {
|
|
103750
104073
|
render();
|
|
104074
|
+
return;
|
|
104075
|
+
}
|
|
104076
|
+
if (streaming && !renderTimer) {
|
|
104077
|
+
const frame = renderTuiStreamingAnimationFrame(
|
|
104078
|
+
state,
|
|
104079
|
+
terminal.width,
|
|
104080
|
+
terminal.height,
|
|
104081
|
+
{ colorMode: terminal.colorMode, ascii: terminal.ascii, reducedMotion: terminal.reducedMotion }
|
|
104082
|
+
);
|
|
104083
|
+
if (frame) terminal.render(frame, tuiComposerCursor(state, terminal.width, terminal.height), state.textSelection);
|
|
103751
104084
|
}
|
|
103752
104085
|
}, 250);
|
|
103753
104086
|
const syncSessionView = () => {
|
|
@@ -103825,7 +104158,8 @@ async function runTui(client2, terminal = new TuiTerminal(), startupServices) {
|
|
|
103825
104158
|
renderTimer = null;
|
|
103826
104159
|
if (closed) return;
|
|
103827
104160
|
syncSessionView();
|
|
103828
|
-
|
|
104161
|
+
lastFrameOwner = client2.hasSession() ? captureTuiWorkspaceOwner(client2) : () => !client2.hasSession();
|
|
104162
|
+
terminal.render(renderTuiFrame(state, terminal.width, terminal.height, { colorMode: terminal.colorMode, ascii: terminal.ascii, reducedMotion: terminal.reducedMotion }), tuiComposerCursor(state, terminal.width, terminal.height), state.textSelection);
|
|
103829
104163
|
}, 16);
|
|
103830
104164
|
};
|
|
103831
104165
|
teamChatRefresh = createTuiTeamChatRefresh(state, client2, render);
|
|
@@ -104094,7 +104428,7 @@ async function handleEnter(params) {
|
|
|
104094
104428
|
}
|
|
104095
104429
|
async function handleCommand(params) {
|
|
104096
104430
|
const { command, state, client: client2, terminal, render, finish, modelShell } = params;
|
|
104097
|
-
client2.clearInteractiveChatViewer();
|
|
104431
|
+
if (command.split(/\s+/, 1)[0] !== "/thinking") client2.clearInteractiveChatViewer();
|
|
104098
104432
|
if (await handleWorkspaceCommand({ state, client: client2, terminal, render, command: (next) => handleCommand({ ...params, command: next }), send: (message, options) => sendTuiMessage({ message, state, client: client2, render, modelShell, questionAnswer: options?.questionAnswer }), modelShell }, command)) return;
|
|
104099
104433
|
const [name, ...parts] = command.split(/\s+/);
|
|
104100
104434
|
const arg = parts.join(" ");
|
|
@@ -104254,17 +104588,66 @@ async function handleCommand(params) {
|
|
|
104254
104588
|
async function sendTuiMessage(params) {
|
|
104255
104589
|
const { state, client: client2, render } = params;
|
|
104256
104590
|
if (state.isBusy) return;
|
|
104591
|
+
const initialMessage = params.message.trim();
|
|
104592
|
+
if (!initialMessage) return;
|
|
104257
104593
|
const preparingOwner = client2.hasSession() ? captureTuiWorkspaceOwner(client2) : () => !client2.hasSession();
|
|
104258
104594
|
const preparingRoute = state.routeVersion;
|
|
104259
|
-
const
|
|
104595
|
+
const previousMessages = state.messages;
|
|
104260
104596
|
const preparingChatId = state.activeChatId;
|
|
104261
|
-
const
|
|
104262
|
-
const
|
|
104263
|
-
|
|
104597
|
+
const previousActiveChat = state.activeChat, previousHeaderState = state.headerState;
|
|
104598
|
+
const previousScreen = state.screen;
|
|
104599
|
+
const sourceExample = previousScreen === "example" ? state.activeExample : null;
|
|
104600
|
+
const history = sourceExample ? buildExampleContinuationHistory(sourceExample) : void 0;
|
|
104601
|
+
const draftKey = sourceExample ? `example:${sourceExample.chat.id}` : preparingChatId ?? "new";
|
|
104602
|
+
const draftBeforeSend = state.drafts[draftKey];
|
|
104603
|
+
if (sourceExample) state.messages = sourceExample.messages.map((m) => ({ role: m.role === "user" ? "user" : "assistant", content: m.content, title: m.senderName }));
|
|
104604
|
+
const messages = state.messages;
|
|
104605
|
+
const userMessage = { id: randomUUID21(), role: "user", content: initialMessage };
|
|
104606
|
+
messages.push(userMessage);
|
|
104607
|
+
state.screen = "chat";
|
|
104608
|
+
state.isBusy = true;
|
|
104609
|
+
state.drafts[draftKey] = "";
|
|
104610
|
+
state.input = "";
|
|
104611
|
+
state.inputCursor = null;
|
|
104612
|
+
state.status = "Preparing message\u2026";
|
|
104613
|
+
render();
|
|
104614
|
+
const ownsPreparation = () => preparingOwner() && state.routeVersion === preparingRoute && state.messages === messages && state.activeChatId === preparingChatId;
|
|
104615
|
+
const restorePreparation = (status) => {
|
|
104616
|
+
if (!ownsPreparation()) return;
|
|
104617
|
+
const index = messages.indexOf(userMessage);
|
|
104618
|
+
if (index >= 0) messages.splice(index, 1);
|
|
104619
|
+
state.messages = previousMessages;
|
|
104620
|
+
state.screen = previousScreen;
|
|
104621
|
+
state.isBusy = false;
|
|
104622
|
+
if (state.input === "" && state.drafts[draftKey] === "") {
|
|
104623
|
+
state.input = initialMessage;
|
|
104624
|
+
state.inputCursor = null;
|
|
104625
|
+
if (draftBeforeSend === void 0) delete state.drafts[draftKey];
|
|
104626
|
+
rememberDraft(state);
|
|
104627
|
+
}
|
|
104628
|
+
if (client2.getActiveTeamId?.()) reconcileTuiTeamSenderLabels(state);
|
|
104629
|
+
state.status = status;
|
|
104630
|
+
render();
|
|
104631
|
+
};
|
|
104632
|
+
let resolved;
|
|
104633
|
+
try {
|
|
104634
|
+
resolved = !params.questionAnswer && params.modelShell ? await params.modelShell.consumeMention(params.message, true) : { message: params.message, blocked: false };
|
|
104635
|
+
} catch (error) {
|
|
104636
|
+
restorePreparation(error instanceof Error ? error.message : String(error));
|
|
104637
|
+
return;
|
|
104638
|
+
}
|
|
104639
|
+
if (!ownsPreparation()) return;
|
|
104640
|
+
if (resolved.blocked) {
|
|
104641
|
+
restorePreparation(null);
|
|
104642
|
+
return;
|
|
104643
|
+
}
|
|
104264
104644
|
const message = resolved.message.trim();
|
|
104265
|
-
if (!message)
|
|
104645
|
+
if (!message) {
|
|
104646
|
+
restorePreparation(null);
|
|
104647
|
+
return;
|
|
104648
|
+
}
|
|
104649
|
+
userMessage.content = message;
|
|
104266
104650
|
client2.clearInteractiveChatViewer();
|
|
104267
|
-
state.isBusy = true;
|
|
104268
104651
|
state.status = "Preparing message\u2026";
|
|
104269
104652
|
render();
|
|
104270
104653
|
if (!ownsPreparation()) return;
|
|
@@ -104272,15 +104655,7 @@ async function sendTuiMessage(params) {
|
|
|
104272
104655
|
try {
|
|
104273
104656
|
prepared = params.questionAnswer ? { message, preparedEmbeds: [], displayNames: [] } : await prepareTuiMessage(client2, message);
|
|
104274
104657
|
} catch (error) {
|
|
104275
|
-
|
|
104276
|
-
state.isBusy = false;
|
|
104277
|
-
if (client2.getActiveTeamId?.()) reconcileTuiTeamSenderLabels(state);
|
|
104278
|
-
state.input = message;
|
|
104279
|
-
state.inputCursor = null;
|
|
104280
|
-
rememberDraft(state);
|
|
104281
|
-
state.status = error instanceof Error ? error.message : String(error);
|
|
104282
|
-
render();
|
|
104283
|
-
}
|
|
104658
|
+
restorePreparation(error instanceof Error ? error.message : String(error));
|
|
104284
104659
|
return;
|
|
104285
104660
|
}
|
|
104286
104661
|
if (!ownsPreparation()) return;
|
|
@@ -104288,34 +104663,16 @@ async function sendTuiMessage(params) {
|
|
|
104288
104663
|
const waitForAi = !client2.hasSession() || shouldWaitForTeamAi(prepared.message, sendTeamId);
|
|
104289
104664
|
const modelSelection = waitForAi && !params.questionAnswer && isTuiAiComposer(state) && client2.hasSession() ? params.modelShell?.selectionForSend() ?? null : "auto";
|
|
104290
104665
|
if (modelSelection === null) {
|
|
104291
|
-
|
|
104292
|
-
state.isBusy = false;
|
|
104293
|
-
state.input = message;
|
|
104294
|
-
state.inputCursor = null;
|
|
104295
|
-
rememberDraft(state);
|
|
104296
|
-
if (sendTeamId) reconcileTuiTeamSenderLabels(state);
|
|
104297
|
-
state.status = "Model selection is loading. Retry or choose Auto before sending.";
|
|
104298
|
-
render();
|
|
104299
|
-
}
|
|
104666
|
+
restorePreparation("Model selection is loading. Retry or choose Auto before sending.");
|
|
104300
104667
|
return;
|
|
104301
104668
|
}
|
|
104302
104669
|
const separator = modelSelection.indexOf("/");
|
|
104303
104670
|
const modelDirective = separator > 0 ? `@ai-model:${modelSelection.slice(separator + 1)}:${modelSelection.slice(0, separator)} ` : "";
|
|
104304
|
-
const previousMessages = state.messages, previousActiveChat = state.activeChat, previousHeaderState = state.headerState;
|
|
104305
|
-
const previousScreen = state.screen;
|
|
104306
|
-
const sourceExample = state.screen === "example" ? state.activeExample : null;
|
|
104307
|
-
const history = sourceExample ? buildExampleContinuationHistory(sourceExample) : void 0;
|
|
104308
|
-
if (sourceExample) state.messages = sourceExample.messages.map((m) => ({ role: m.role === "user" ? "user" : "assistant", content: m.content, title: m.senderName }));
|
|
104309
|
-
const messages = state.messages;
|
|
104310
104671
|
const existingChatId = sourceExample ? null : state.activeChatId;
|
|
104311
104672
|
const chatId = existingChatId ?? randomUUID21();
|
|
104312
104673
|
let ownedMessages = messages, ownedChatId = chatId;
|
|
104313
104674
|
const ownsSend = () => preparingOwner() && state.routeVersion === preparingRoute && state.messages === ownedMessages && state.activeChatId === ownedChatId;
|
|
104314
|
-
const
|
|
104315
|
-
state.drafts[draftKey] = "";
|
|
104316
|
-
state.input = "";
|
|
104317
|
-
state.inputCursor = null;
|
|
104318
|
-
const anonymousHistory = history ?? messages.filter((m) => m.role !== "system").map((m) => ({ message_id: randomUUID21(), role: m.role, content: m.content, sender_name: m.title ?? (m.role === "user" ? "User" : "Assistant"), created_at: Math.floor(Date.now() / 1e3) }));
|
|
104675
|
+
const anonymousHistory = history ?? messages.filter((m) => m !== userMessage && m.role !== "system").map((m) => ({ message_id: randomUUID21(), role: m.role, content: m.content, sender_name: m.title ?? (m.role === "user" ? "User" : "Assistant"), created_at: Math.floor(Date.now() / 1e3) }));
|
|
104319
104676
|
state.activeChatId = chatId;
|
|
104320
104677
|
state.headerState = existingChatId ? "ready" : "loading";
|
|
104321
104678
|
state.headerError = null;
|
|
@@ -104324,8 +104681,8 @@ async function sendTuiMessage(params) {
|
|
|
104324
104681
|
state.screen = "chat";
|
|
104325
104682
|
state.aiTaskId = null;
|
|
104326
104683
|
state.status = prepared.displayNames.length ? `Attached: ${prepared.displayNames.join(", ")}` : null;
|
|
104327
|
-
|
|
104328
|
-
|
|
104684
|
+
userMessage.content = prepared.message;
|
|
104685
|
+
userMessage.embedIds = prepared.preparedEmbeds.map((embed) => embed.embedId);
|
|
104329
104686
|
const privacyCallbacks = {
|
|
104330
104687
|
onPrivacyPrepared: (safe2) => {
|
|
104331
104688
|
if (ownsSend()) {
|
|
@@ -104340,11 +104697,18 @@ async function sendTuiMessage(params) {
|
|
|
104340
104697
|
}
|
|
104341
104698
|
}
|
|
104342
104699
|
};
|
|
104343
|
-
const assistantMessage = waitForAi ? { role: "assistant", content: "", title: "Assistant" } : null;
|
|
104344
|
-
|
|
104700
|
+
const assistantMessage = waitForAi ? { id: randomUUID21(), role: "assistant", content: "", title: "Assistant" } : null;
|
|
104701
|
+
state.streamingMessage = assistantMessage;
|
|
104702
|
+
if (assistantMessage) state.streamingPhase = 0;
|
|
104345
104703
|
state.isAwaitingAi = waitForAi;
|
|
104704
|
+
const showAssistant = (content) => {
|
|
104705
|
+
if (!assistantMessage || !ownsSend() || !content) return;
|
|
104706
|
+
assistantMessage.content = content;
|
|
104707
|
+
if (!messages.includes(assistantMessage)) messages.push(assistantMessage);
|
|
104708
|
+
};
|
|
104346
104709
|
render();
|
|
104347
104710
|
let questionSendError = null;
|
|
104711
|
+
let accepted = false;
|
|
104348
104712
|
try {
|
|
104349
104713
|
if (!client2.hasSession()) {
|
|
104350
104714
|
const result = await client2.sendAnonymousMessage({
|
|
@@ -104352,7 +104716,8 @@ async function sendTuiMessage(params) {
|
|
|
104352
104716
|
...privacyCallbacks,
|
|
104353
104717
|
messageHistory: anonymousHistory
|
|
104354
104718
|
});
|
|
104355
|
-
|
|
104719
|
+
accepted = true;
|
|
104720
|
+
showAssistant(result.assistant);
|
|
104356
104721
|
if (ownsSend()) {
|
|
104357
104722
|
ownedChatId = result.chatId;
|
|
104358
104723
|
state.activeChatId = result.chatId;
|
|
@@ -104385,22 +104750,42 @@ async function sendTuiMessage(params) {
|
|
|
104385
104750
|
onStream: (event) => {
|
|
104386
104751
|
if (!ownsSend()) return;
|
|
104387
104752
|
if (event.taskId) state.aiTaskId = event.taskId;
|
|
104753
|
+
if (assistantMessage && event.thinkingContent !== void 0) assistantMessage.thinkingContent = event.thinkingContent;
|
|
104754
|
+
if (assistantMessage && event.thinkingActive !== void 0) assistantMessage.thinkingActive = event.thinkingActive;
|
|
104755
|
+
if (assistantMessage && event.modelName) assistantMessage.modelName = event.modelName;
|
|
104756
|
+
if (assistantMessage && event.category) {
|
|
104757
|
+
state.activeChat = {
|
|
104758
|
+
id: chatId,
|
|
104759
|
+
shortId: chatId.slice(0, 8),
|
|
104760
|
+
title: state.activeChat?.title ?? null,
|
|
104761
|
+
summary: state.activeChat?.summary ?? null,
|
|
104762
|
+
updatedAt: null,
|
|
104763
|
+
createdAt: state.activeChat?.createdAt ?? Math.floor(Date.now() / 1e3),
|
|
104764
|
+
category: event.category,
|
|
104765
|
+
mateName: null
|
|
104766
|
+
};
|
|
104767
|
+
}
|
|
104388
104768
|
if (assistantMessage && (event.kind === "chunk" || event.kind === "done")) {
|
|
104389
|
-
|
|
104390
|
-
if (event.category) state.activeChat = { id: chatId, shortId: chatId.slice(0, 8), title: state.activeChat?.title ?? null, summary: state.activeChat?.summary ?? null, updatedAt: null, createdAt: state.activeChat?.createdAt ?? Math.floor(Date.now() / 1e3), category: event.category, mateName: null };
|
|
104391
|
-
render();
|
|
104769
|
+
showAssistant(event.content);
|
|
104392
104770
|
}
|
|
104771
|
+
render();
|
|
104393
104772
|
}
|
|
104394
104773
|
});
|
|
104395
|
-
|
|
104774
|
+
accepted = true;
|
|
104775
|
+
showAssistant(result.assistant);
|
|
104396
104776
|
if (ownsSend()) {
|
|
104397
104777
|
ownedChatId = result.chatId;
|
|
104398
104778
|
state.activeChatId = result.chatId;
|
|
104399
104779
|
state.followUpSuggestions = result.followUpSuggestions ?? [];
|
|
104400
104780
|
if (result.userMessageId) userMessage.id = result.userMessageId;
|
|
104401
|
-
if (!existingChatId
|
|
104402
|
-
|
|
104403
|
-
|
|
104781
|
+
if (!existingChatId && params.modelShell) {
|
|
104782
|
+
void Promise.resolve().then(() => ownsSend() ? params.modelShell?.persistCreatedChat(result.chatId, modelSelection) : void 0).catch(() => {
|
|
104783
|
+
});
|
|
104784
|
+
}
|
|
104785
|
+
if (state.screen === "chat" && typeof client2.setInteractiveChatViewer === "function") {
|
|
104786
|
+
void Promise.resolve().then(() => ownsSend() && state.screen === "chat" ? client2.setInteractiveChatViewer(result.chatId) : void 0).catch(() => {
|
|
104787
|
+
});
|
|
104788
|
+
}
|
|
104404
104789
|
if (result.mateName && assistantMessage) assistantMessage.title = result.mateName;
|
|
104405
104790
|
if (typeof client2.getChatMetadata === "function") {
|
|
104406
104791
|
const completedLength = messages.length;
|
|
@@ -104425,13 +104810,14 @@ async function sendTuiMessage(params) {
|
|
|
104425
104810
|
state.headerState = "ready";
|
|
104426
104811
|
}
|
|
104427
104812
|
} catch (error) {
|
|
104813
|
+
if (accepted) return;
|
|
104428
104814
|
if (params.questionAnswer) {
|
|
104429
104815
|
questionSendError = error instanceof Error ? error : new Error(String(error));
|
|
104430
|
-
for (const optimistic of [userMessage, assistantMessage].filter((item) => item !== null)) {
|
|
104431
|
-
const index = messages.indexOf(optimistic);
|
|
104432
|
-
if (index >= 0) messages.splice(index, 1);
|
|
104433
|
-
}
|
|
104434
104816
|
if (ownsSend()) {
|
|
104817
|
+
for (const optimistic of [userMessage, assistantMessage].filter((item) => item !== null)) {
|
|
104818
|
+
const index = messages.indexOf(optimistic);
|
|
104819
|
+
if (index >= 0) messages.splice(index, 1);
|
|
104820
|
+
}
|
|
104435
104821
|
state.messages = previousMessages;
|
|
104436
104822
|
state.activeChatId = existingChatId;
|
|
104437
104823
|
state.activeChat = previousActiveChat;
|
|
@@ -104441,14 +104827,14 @@ async function sendTuiMessage(params) {
|
|
|
104441
104827
|
state.screen = sourceExample ? "example" : "chat";
|
|
104442
104828
|
state.status = null;
|
|
104443
104829
|
}
|
|
104444
|
-
} else if (assistantMessage) {
|
|
104830
|
+
} else if (assistantMessage && ownsSend()) {
|
|
104445
104831
|
assistantMessage.title = "Error";
|
|
104446
|
-
|
|
104447
|
-
|
|
104448
|
-
|
|
104449
|
-
state.headerError = /credit/i.test(assistantMessage.content) ? "Not enough credits" : assistantMessage.content;
|
|
104450
|
-
}
|
|
104832
|
+
showAssistant(error instanceof Error ? error.message : String(error));
|
|
104833
|
+
state.headerState = "error";
|
|
104834
|
+
state.headerError = /credit/i.test(assistantMessage.content) ? "Not enough credits" : assistantMessage.content;
|
|
104451
104835
|
} else if (ownsSend()) {
|
|
104836
|
+
const index = messages.indexOf(userMessage);
|
|
104837
|
+
if (index >= 0) messages.splice(index, 1);
|
|
104452
104838
|
state.messages = previousMessages;
|
|
104453
104839
|
state.activeChatId = existingChatId;
|
|
104454
104840
|
state.activeChat = previousActiveChat;
|
|
@@ -104456,9 +104842,11 @@ async function sendTuiMessage(params) {
|
|
|
104456
104842
|
ownedChatId = existingChatId;
|
|
104457
104843
|
state.headerState = previousHeaderState;
|
|
104458
104844
|
state.screen = previousScreen;
|
|
104459
|
-
state.input
|
|
104460
|
-
|
|
104461
|
-
|
|
104845
|
+
if (state.input === "" && state.drafts[draftKey] === "") {
|
|
104846
|
+
state.input = message;
|
|
104847
|
+
state.inputCursor = null;
|
|
104848
|
+
rememberDraft(state);
|
|
104849
|
+
}
|
|
104462
104850
|
state.status = error instanceof Error ? error.message : String(error);
|
|
104463
104851
|
}
|
|
104464
104852
|
} finally {
|
|
@@ -104466,6 +104854,7 @@ async function sendTuiMessage(params) {
|
|
|
104466
104854
|
state.isBusy = false;
|
|
104467
104855
|
if (sendTeamId) reconcileTuiTeamSenderLabels(state);
|
|
104468
104856
|
state.isAwaitingAi = false;
|
|
104857
|
+
state.streamingMessage = null;
|
|
104469
104858
|
state.projectFocusPending = null;
|
|
104470
104859
|
state.aiTaskId = null;
|
|
104471
104860
|
registerChatEmbedAliases(state);
|
|
@@ -105011,7 +105400,7 @@ async function flushTaskCommands(client2, teamId, root = resolveStateDir(), onNo
|
|
|
105011
105400
|
await taskMutationStore(scope2, root).deliver(command.id, async () => {
|
|
105012
105401
|
if (operation.kind === "create") {
|
|
105013
105402
|
const linked = operation.link_to_chat !== false;
|
|
105014
|
-
const
|
|
105403
|
+
const owner2 = linked ? await readCodexThread(command.thread) : void 0;
|
|
105015
105404
|
const input = await buildCreateUserTaskInput(master, {
|
|
105016
105405
|
taskId: command.task_id,
|
|
105017
105406
|
title: operation.title ?? "",
|
|
@@ -105019,7 +105408,7 @@ async function flushTaskCommands(client2, teamId, root = resolveStateDir(), onNo
|
|
|
105019
105408
|
projectIds: [command.project_id],
|
|
105020
105409
|
status: operation.status,
|
|
105021
105410
|
assign: linked ? "codex" : "user",
|
|
105022
|
-
externalChat:
|
|
105411
|
+
externalChat: owner2 ? { provider: "codex", id: owner2.id, title: owner2.title } : void 0
|
|
105023
105412
|
});
|
|
105024
105413
|
return { kind: "create", taskId: command.task_id, input, creator: linked ? "codex" : void 0 };
|
|
105025
105414
|
}
|
|
@@ -111238,8 +111627,8 @@ async function handleTasks(client2, subcommand, rest, flags, redactor) {
|
|
|
111238
111627
|
}
|
|
111239
111628
|
if (process.env.CODEX_THREAD_ID && (task.externalChat?.provider !== "codex" || task.externalChat.id !== process.env.CODEX_THREAD_ID)) {
|
|
111240
111629
|
if (task.primaryChatId) {
|
|
111241
|
-
const
|
|
111242
|
-
throw new Error(taskOwnerConflict({ provider: "openmates", id:
|
|
111630
|
+
const owner2 = await client2.getChatMetadata(task.primaryChatId, scope2);
|
|
111631
|
+
throw new Error(taskOwnerConflict({ provider: "openmates", id: owner2.id, title: owner2.title }));
|
|
111243
111632
|
}
|
|
111244
111633
|
throw new Error(taskOwnerConflict(task.externalChat));
|
|
111245
111634
|
}
|
|
@@ -111255,8 +111644,8 @@ async function handleTasks(client2, subcommand, rest, flags, redactor) {
|
|
|
111255
111644
|
if (subcommand === "connect") {
|
|
111256
111645
|
if (typeof flags.thread !== "string") throw new Error("Usage: openmates tasks connect <task-id> --thread <codex-thread-uuid>");
|
|
111257
111646
|
if (task.primaryChatId) {
|
|
111258
|
-
const
|
|
111259
|
-
throw new Error(taskOwnerConflict({ provider: "openmates", id:
|
|
111647
|
+
const owner2 = await client2.getChatMetadata(task.primaryChatId, scope2);
|
|
111648
|
+
throw new Error(taskOwnerConflict({ provider: "openmates", id: owner2.id, title: owner2.title }));
|
|
111260
111649
|
}
|
|
111261
111650
|
if (task.externalChat) {
|
|
111262
111651
|
if (task.externalChat.provider === "codex" && task.externalChat.id === flags.thread) {
|
|
@@ -120628,6 +121017,7 @@ async function sendMessageStreaming(client2, params, redactor) {
|
|
|
120628
121017
|
const onStream = (event) => {
|
|
120629
121018
|
if (params.json) return;
|
|
120630
121019
|
if (event.kind === "typing") {
|
|
121020
|
+
if (event.thinkingContent) return;
|
|
120631
121021
|
const mateName = event.category && MATE_NAMES[event.category] ? MATE_NAMES[event.category] : "Mate";
|
|
120632
121022
|
process.stdout.write(`\x1B[2m${mateName} is typing...\x1B[0m`);
|
|
120633
121023
|
typingShown = true;
|