openmates 0.27.0-alpha.52 → 0.27.0-alpha.54
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-W2VJSU3Q.js} +783 -277
- package/dist/{cli-CRk4jJXf.d.ts → cli-jvpep36C.d.ts} +7 -1
- 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();
|
|
@@ -15955,6 +15988,18 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
15955
15988
|
remoteCommandReviewInteractive: Boolean(params.onRemoteCommandReview)
|
|
15956
15989
|
});
|
|
15957
15990
|
}
|
|
15991
|
+
const queuedAdmission = !params.incognito && shouldWaitForAi ? ws.waitForMessage("message_queued", (payload) => {
|
|
15992
|
+
const event = payload;
|
|
15993
|
+
return event.chat_id === chatId && event.user_message_id === messageId;
|
|
15994
|
+
}, params.responseTimeoutMs ?? 9e4) : null;
|
|
15995
|
+
if (queuedAdmission) void queuedAdmission.catch(() => {
|
|
15996
|
+
});
|
|
15997
|
+
const pausedHandoff = !params.incognito && shouldWaitForAi ? ws.waitForMessage("queued_handoff_paused", (payload) => {
|
|
15998
|
+
const event = payload;
|
|
15999
|
+
return event.chat_id === chatId && (event.message_id === messageId || event.message_id === void 0);
|
|
16000
|
+
}, params.responseTimeoutMs ?? 9e4) : null;
|
|
16001
|
+
if (pausedHandoff) void pausedHandoff.catch(() => {
|
|
16002
|
+
});
|
|
15958
16003
|
const confirmed = ws.waitForMessage(
|
|
15959
16004
|
"chat_message_confirmed",
|
|
15960
16005
|
(payload) => {
|
|
@@ -16248,11 +16293,56 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
16248
16293
|
}
|
|
16249
16294
|
await this.replayCurrentTurnRecoveryOutputPages(ws, ownerId2, pages, cache, teamId, chatId);
|
|
16250
16295
|
};
|
|
16251
|
-
const
|
|
16296
|
+
const responsePromise = precollectedResponse ?? ws.collectAiResponse(messageId, chatId, {
|
|
16252
16297
|
...streamOpts,
|
|
16253
16298
|
timeoutMs: params.responseTimeoutMs,
|
|
16254
16299
|
recoveryTurnId: savedTurnId
|
|
16255
|
-
})
|
|
16300
|
+
});
|
|
16301
|
+
const outcome = await Promise.race([
|
|
16302
|
+
responsePromise.then((response) => ({ kind: "response", response })),
|
|
16303
|
+
...queuedAdmission ? [queuedAdmission.then(
|
|
16304
|
+
(frame) => ({ kind: "queued", frame }),
|
|
16305
|
+
() => new Promise(() => {
|
|
16306
|
+
})
|
|
16307
|
+
)] : [],
|
|
16308
|
+
...pausedHandoff ? [pausedHandoff.then(
|
|
16309
|
+
(frame) => ({ kind: "paused", frame }),
|
|
16310
|
+
() => new Promise(() => {
|
|
16311
|
+
})
|
|
16312
|
+
)] : []
|
|
16313
|
+
]);
|
|
16314
|
+
if (outcome.kind === "paused") {
|
|
16315
|
+
void responsePromise.catch(() => {
|
|
16316
|
+
});
|
|
16317
|
+
throw new Error("Message saved, but AI handoff is paused. No assistant run started; check the chat before retrying.");
|
|
16318
|
+
}
|
|
16319
|
+
if (outcome.kind === "queued") {
|
|
16320
|
+
void responsePromise.catch(() => {
|
|
16321
|
+
});
|
|
16322
|
+
const frame = outcome.frame.payload;
|
|
16323
|
+
return {
|
|
16324
|
+
status: "queued",
|
|
16325
|
+
chatId,
|
|
16326
|
+
messageId: null,
|
|
16327
|
+
userMessageId: messageId,
|
|
16328
|
+
queueMode: frame.queue_mode === "steer" ? "steer" : "follow_up",
|
|
16329
|
+
queueRevision: typeof frame.queue_revision === "number" ? frame.queue_revision : 1,
|
|
16330
|
+
assistant: "",
|
|
16331
|
+
category: null,
|
|
16332
|
+
modelName: null,
|
|
16333
|
+
mateName: null,
|
|
16334
|
+
followUpSuggestions: [],
|
|
16335
|
+
taskProposals: [],
|
|
16336
|
+
taskUpdateProposals: [],
|
|
16337
|
+
taskEvents: [],
|
|
16338
|
+
pendingTaskUpdateJobs: [],
|
|
16339
|
+
subChatEvents: [],
|
|
16340
|
+
appSettingsMemoryRequests: [],
|
|
16341
|
+
tokenUsage: null,
|
|
16342
|
+
promptBudget: null
|
|
16343
|
+
};
|
|
16344
|
+
}
|
|
16345
|
+
const resp = outcome.response;
|
|
16256
16346
|
assistantMessageId = resp.messageId;
|
|
16257
16347
|
assistant = resp.content;
|
|
16258
16348
|
category = resp.category;
|
|
@@ -18738,7 +18828,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
18738
18828
|
// -------------------------------------------------------------------------
|
|
18739
18829
|
async listUserTasks(filters = {}, options = {}) {
|
|
18740
18830
|
const session = this.requireSession();
|
|
18741
|
-
const
|
|
18831
|
+
const owner2 = [
|
|
18742
18832
|
session.apiUrl,
|
|
18743
18833
|
session.hashedEmail,
|
|
18744
18834
|
session.sessionId,
|
|
@@ -18748,7 +18838,7 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
18748
18838
|
];
|
|
18749
18839
|
const current2 = () => {
|
|
18750
18840
|
const active = this.session;
|
|
18751
|
-
if (!active || active.apiUrl !==
|
|
18841
|
+
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
18842
|
throw new Error("Task workspace changed");
|
|
18753
18843
|
};
|
|
18754
18844
|
const params = new URLSearchParams();
|
|
@@ -18984,8 +19074,8 @@ var OpenMatesClient = class _OpenMatesClient {
|
|
|
18984
19074
|
if (task.externalChat && (current2.external_chat_provider !== input.external_chat_provider || current2.external_chat_lookup_hash !== input.external_chat_lookup_hash)) {
|
|
18985
19075
|
conflict = taskOwnerConflict(task.externalChat);
|
|
18986
19076
|
} else if (task.primaryChatId && task.primaryChatId !== input.primary_chat_id) {
|
|
18987
|
-
const
|
|
18988
|
-
conflict = taskOwnerConflict({ provider: "openmates", id:
|
|
19077
|
+
const owner2 = await this.getChatMetadata(task.primaryChatId, context);
|
|
19078
|
+
conflict = taskOwnerConflict({ provider: "openmates", id: owner2.id, title: owner2.title });
|
|
18989
19079
|
}
|
|
18990
19080
|
}
|
|
18991
19081
|
} catch {
|
|
@@ -21226,9 +21316,9 @@ Required: ${schema.required.join(", ")}`
|
|
|
21226
21316
|
...baseSyncPayload,
|
|
21227
21317
|
...refreshChatIdSet.size > 0 ? { refresh_chat_ids: Array.from(refreshChatIdSet) } : {}
|
|
21228
21318
|
});
|
|
21229
|
-
const
|
|
21319
|
+
const frames3 = await syncFrames;
|
|
21230
21320
|
signal?.throwIfAborted();
|
|
21231
|
-
if (onSyncedCache && !
|
|
21321
|
+
if (onSyncedCache && !frames3.some((frame) => frame.type === "phase_2_last_20_chats_ready")) {
|
|
21232
21322
|
throw new Error("Chat metadata sync ended before history arrived.");
|
|
21233
21323
|
}
|
|
21234
21324
|
if (includeMessageContentRefresh && refreshChatIdSet.size > 0) {
|
|
@@ -21239,9 +21329,9 @@ Required: ${schema.required.join(", ")}`
|
|
|
21239
21329
|
});
|
|
21240
21330
|
const collectedPhase3Frames = await phase3Frames;
|
|
21241
21331
|
signal?.throwIfAborted();
|
|
21242
|
-
|
|
21332
|
+
frames3.push(...collectedPhase3Frames);
|
|
21243
21333
|
}
|
|
21244
|
-
for (const frame of
|
|
21334
|
+
for (const frame of frames3) {
|
|
21245
21335
|
if (frame.type === "phase_1_last_chat_ready") {
|
|
21246
21336
|
const p = frame.payload;
|
|
21247
21337
|
newChatSuggestions = p.new_chat_suggestions ?? [];
|
|
@@ -34662,7 +34752,7 @@ function generateQr(value) {
|
|
|
34662
34752
|
function remotionMeta(c) {
|
|
34663
34753
|
const source = str(c.remotion_source) ?? str(c.source) ?? "";
|
|
34664
34754
|
const fps = firstInt(source, /fps\s*[:=]\s*(\d+)/) ?? 30;
|
|
34665
|
-
const
|
|
34755
|
+
const frames3 = firstInt(source, /durationInFrames\s*[:=]\s*(\d+)/) ?? 150;
|
|
34666
34756
|
const status = str(c.status) ?? "processing";
|
|
34667
34757
|
return {
|
|
34668
34758
|
filename: str(c.filename) ?? str(c.title) ?? "Composition.tsx",
|
|
@@ -34670,7 +34760,7 @@ function remotionMeta(c) {
|
|
|
34670
34760
|
statusText: remotionStatusText(status),
|
|
34671
34761
|
source,
|
|
34672
34762
|
sourceVersion: numberValue(c.current_source_version ?? c.source_version) ?? 1,
|
|
34673
|
-
durationSeconds: Math.max(1, Math.ceil(
|
|
34763
|
+
durationSeconds: Math.max(1, Math.ceil(frames3 / Math.max(1, fps))),
|
|
34674
34764
|
width: firstInt(source, /width\s*[:=]\s*(\d+)/) ?? 1920,
|
|
34675
34765
|
height: firstInt(source, /height\s*[:=]\s*(\d+)/) ?? 1080,
|
|
34676
34766
|
layers: remotionLayers(source),
|
|
@@ -37197,11 +37287,11 @@ async function writeRuntimeIncidentState(installDir, role, state, effectiveUid =
|
|
|
37197
37287
|
const statePath = path.join(stateDir2, `${role}.json`);
|
|
37198
37288
|
const temporaryPath = `${statePath}.${randomUUID12()}.tmp`;
|
|
37199
37289
|
await fs.mkdir(stateDir2, { recursive: true, mode: 448 });
|
|
37200
|
-
const
|
|
37290
|
+
const owner2 = await runtimeIncidentStateOwner(installDir, effectiveUid);
|
|
37201
37291
|
try {
|
|
37202
37292
|
await fs.writeFile(temporaryPath, `${JSON.stringify(state, null, 2)}
|
|
37203
37293
|
`, { flag: "wx", mode: 384 });
|
|
37204
|
-
if (
|
|
37294
|
+
if (owner2 && (owner2.uid !== 0 || owner2.gid !== 0)) await fs.chown(temporaryPath, owner2.uid, owner2.gid);
|
|
37205
37295
|
await fs.rename(temporaryPath, statePath);
|
|
37206
37296
|
await fs.chmod(statePath, 384);
|
|
37207
37297
|
} catch (error) {
|
|
@@ -65591,6 +65681,9 @@ Only output the final Markdown table. Do NOT include explanations, notes, or any
|
|
|
65591
65681
|
generated_by: {
|
|
65592
65682
|
text: "generated by {model}"
|
|
65593
65683
|
},
|
|
65684
|
+
using_model: {
|
|
65685
|
+
text: "Using {model}"
|
|
65686
|
+
},
|
|
65594
65687
|
assistant_speech: {
|
|
65595
65688
|
confirmation: {
|
|
65596
65689
|
text: "Confirmation"
|
|
@@ -65798,6 +65891,26 @@ Only output the final Markdown table. Do NOT include explanations, notes, or any
|
|
|
65798
65891
|
text: "Stop queue"
|
|
65799
65892
|
}
|
|
65800
65893
|
},
|
|
65894
|
+
response_activity: {
|
|
65895
|
+
using: {
|
|
65896
|
+
text: "Using {apps}"
|
|
65897
|
+
},
|
|
65898
|
+
thinking_using: {
|
|
65899
|
+
text: "Thinking & using {apps}"
|
|
65900
|
+
},
|
|
65901
|
+
response_thinking: {
|
|
65902
|
+
text: "Thinking for this response"
|
|
65903
|
+
},
|
|
65904
|
+
researching: {
|
|
65905
|
+
text: "Researching\u2026"
|
|
65906
|
+
},
|
|
65907
|
+
working: {
|
|
65908
|
+
text: "Working\u2026"
|
|
65909
|
+
},
|
|
65910
|
+
writing: {
|
|
65911
|
+
text: "Writing\u2026"
|
|
65912
|
+
}
|
|
65913
|
+
},
|
|
65801
65914
|
new_chat_suggestions: {
|
|
65802
65915
|
quantum_computing: {
|
|
65803
65916
|
text: "Teach me about quantum computing in simple terms"
|
|
@@ -66525,6 +66638,38 @@ Only output the final Markdown table. Do NOT include explanations, notes, or any
|
|
|
66525
66638
|
text: "Could not start the explanation chat. Please try again."
|
|
66526
66639
|
}
|
|
66527
66640
|
},
|
|
66641
|
+
queued_followup: {
|
|
66642
|
+
queued: {
|
|
66643
|
+
text: "Queued"
|
|
66644
|
+
},
|
|
66645
|
+
steering: {
|
|
66646
|
+
text: "Steering current response"
|
|
66647
|
+
},
|
|
66648
|
+
updating: {
|
|
66649
|
+
text: "Updating\u2026"
|
|
66650
|
+
},
|
|
66651
|
+
steer_instead: {
|
|
66652
|
+
text: "Steer instead"
|
|
66653
|
+
},
|
|
66654
|
+
editing: {
|
|
66655
|
+
text: "Editing queued message"
|
|
66656
|
+
},
|
|
66657
|
+
cancel_edit: {
|
|
66658
|
+
text: "Cancel edit"
|
|
66659
|
+
},
|
|
66660
|
+
conflict: {
|
|
66661
|
+
text: "This queued message changed on another device. Reopen it to edit the latest version."
|
|
66662
|
+
},
|
|
66663
|
+
unavailable: {
|
|
66664
|
+
text: "Couldn\u2019t update the queued message. Try again."
|
|
66665
|
+
},
|
|
66666
|
+
steer_deferred: {
|
|
66667
|
+
text: "Couldn\u2019t steer this response. Your message remains queued."
|
|
66668
|
+
},
|
|
66669
|
+
paused: {
|
|
66670
|
+
text: "Saved, but the assistant could not continue with this message."
|
|
66671
|
+
}
|
|
66672
|
+
},
|
|
66528
66673
|
hidden_chats: {
|
|
66529
66674
|
unlock: {
|
|
66530
66675
|
text: "Unlock hidden chats"
|
|
@@ -91485,6 +91630,10 @@ var TuiTerminal = class {
|
|
|
91485
91630
|
paintedWidth = 0;
|
|
91486
91631
|
paintedHeight = 0;
|
|
91487
91632
|
outputBlocked = false;
|
|
91633
|
+
/** Animation ticks must not add work while stdout is awaiting drain. */
|
|
91634
|
+
get isOutputBlocked() {
|
|
91635
|
+
return this.outputBlocked;
|
|
91636
|
+
}
|
|
91488
91637
|
pendingFrame = null;
|
|
91489
91638
|
outputDrained = () => {
|
|
91490
91639
|
this.output.off("drain", this.outputDrained);
|
|
@@ -91526,6 +91675,10 @@ var TuiTerminal = class {
|
|
|
91526
91675
|
const depth = this.output.getColorDepth?.() ?? 8;
|
|
91527
91676
|
return depth >= 24 ? "truecolor" : depth >= 8 ? "ansi256" : depth >= 4 ? "ansi16" : "none";
|
|
91528
91677
|
}
|
|
91678
|
+
/** Explicit terminal preference; GUI OS motion preferences are not available over SSH. */
|
|
91679
|
+
get reducedMotion() {
|
|
91680
|
+
return process.env.OPENMATES_REDUCED_MOTION === "1";
|
|
91681
|
+
}
|
|
91529
91682
|
get ascii() {
|
|
91530
91683
|
return process.env.OPENMATES_ASCII === "1" || process.env.TERM === "dumb";
|
|
91531
91684
|
}
|
|
@@ -92636,10 +92789,62 @@ function filterTasks(tasks, query, status) {
|
|
|
92636
92789
|
const words = query.toLocaleLowerCase().trim().split(/\s+/).filter(Boolean);
|
|
92637
92790
|
return sorted(tasks.filter((task) => {
|
|
92638
92791
|
if (status && task.status !== status) return false;
|
|
92792
|
+
if (!words.length) return true;
|
|
92639
92793
|
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
92794
|
return words.every((word) => haystack.includes(word));
|
|
92641
92795
|
}));
|
|
92642
92796
|
}
|
|
92797
|
+
var titleHeightCache = /* @__PURE__ */ new WeakMap();
|
|
92798
|
+
function taskTitleLines(task, width, selected) {
|
|
92799
|
+
return wrapCells(`${selected ? "\u203A " : " "}${task.title || "Untitled task"}`, Math.max(8, width - 2)).slice(0, 2);
|
|
92800
|
+
}
|
|
92801
|
+
function taskTitleHeight(task, width, selected) {
|
|
92802
|
+
let cache = titleHeightCache.get(task);
|
|
92803
|
+
if (!cache || cache.title !== task.title) {
|
|
92804
|
+
cache = { title: task.title, widths: /* @__PURE__ */ new Map() };
|
|
92805
|
+
titleHeightCache.set(task, cache);
|
|
92806
|
+
}
|
|
92807
|
+
let counts = cache.widths.get(width);
|
|
92808
|
+
if (!counts) {
|
|
92809
|
+
if (cache.widths.size >= 3) {
|
|
92810
|
+
const oldest = cache.widths.keys().next().value;
|
|
92811
|
+
if (oldest !== void 0) cache.widths.delete(oldest);
|
|
92812
|
+
}
|
|
92813
|
+
counts = {};
|
|
92814
|
+
cache.widths.set(width, counts);
|
|
92815
|
+
}
|
|
92816
|
+
const key = selected ? "selected" : "unselected";
|
|
92817
|
+
return counts[key] ?? (counts[key] = taskTitleLines(task, width, selected).length);
|
|
92818
|
+
}
|
|
92819
|
+
function taskCardHeight(task, width, selected) {
|
|
92820
|
+
const titleRows = taskTitleHeight(task, width, selected);
|
|
92821
|
+
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"));
|
|
92822
|
+
}
|
|
92823
|
+
function cardPositions(group, width, selectedTaskId, separatorRows) {
|
|
92824
|
+
let height = 0;
|
|
92825
|
+
const cards = group.map((task, index) => {
|
|
92826
|
+
const start = height;
|
|
92827
|
+
const end = start + taskCardHeight(task, width, task.taskId === selectedTaskId);
|
|
92828
|
+
height = end + separatorRows;
|
|
92829
|
+
return { task, index, start, end };
|
|
92830
|
+
});
|
|
92831
|
+
return { cards, height };
|
|
92832
|
+
}
|
|
92833
|
+
function boardWindows(viewport, fullHeight, stackStart, selected) {
|
|
92834
|
+
const requestedStart = Math.floor(viewport.start);
|
|
92835
|
+
const span = Math.min(fullHeight, Math.max(0, Math.ceil(viewport.end) - requestedStart));
|
|
92836
|
+
const start = Math.min(Math.max(0, requestedStart), Math.max(0, fullHeight - span));
|
|
92837
|
+
const end = start + span;
|
|
92838
|
+
const windows = [{ start, end }];
|
|
92839
|
+
if (selected && viewport.followSelection !== false) {
|
|
92840
|
+
const padding = Math.max(1, end - start);
|
|
92841
|
+
windows.push({ start: Math.max(0, stackStart + selected.start - padding), end: stackStart + selected.end + padding });
|
|
92842
|
+
}
|
|
92843
|
+
return windows;
|
|
92844
|
+
}
|
|
92845
|
+
function intersects(start, end, windows) {
|
|
92846
|
+
return windows.some((window) => start < window.end && end > window.start);
|
|
92847
|
+
}
|
|
92643
92848
|
function renderTaskBoard2(tasks, options) {
|
|
92644
92849
|
const width = Math.max(18, options.width);
|
|
92645
92850
|
const visible = filterTasks(tasks, options.query ?? "");
|
|
@@ -92667,14 +92872,40 @@ function renderTaskBoard2(tasks, options) {
|
|
|
92667
92872
|
{ kind: "select", target: "task", column: TASK_STATUSES.indexOf(status), index: 0 }
|
|
92668
92873
|
)), colWidth, gap));
|
|
92669
92874
|
lines.push(shown.map(() => "\u2500".repeat(colWidth)).join(gap));
|
|
92670
|
-
|
|
92671
|
-
task,
|
|
92672
|
-
|
|
92673
|
-
|
|
92674
|
-
|
|
92675
|
-
|
|
92676
|
-
|
|
92677
|
-
|
|
92875
|
+
if (!options.viewport) {
|
|
92876
|
+
const stacks = shown.map(({ tasks: group }) => group.length ? group.flatMap((task, index) => [...taskCard(
|
|
92877
|
+
task,
|
|
92878
|
+
colWidth,
|
|
92879
|
+
task.taskId === options.selectedTaskId,
|
|
92880
|
+
{ kind: "select", target: "task", column: TASK_STATUSES.indexOf(task.status), index, id: task.taskId, activate: true }
|
|
92881
|
+
), ""]) : [padCells("No tasks here.", colWidth)]);
|
|
92882
|
+
for (let row3 = 0; row3 < Math.max(...stacks.map((stack) => stack.length)); row3++) {
|
|
92883
|
+
lines.push(joinColumns(stacks.map((stack) => stack[row3] ?? ""), colWidth, gap));
|
|
92884
|
+
}
|
|
92885
|
+
} else {
|
|
92886
|
+
const stackStart = lines.length;
|
|
92887
|
+
const positions = shown.map(({ tasks: group }) => cardPositions(group, colWidth, options.selectedTaskId, 1));
|
|
92888
|
+
const selectedCard = positions.flatMap(({ cards }) => cards).find(({ task }) => task.taskId === options.selectedTaskId);
|
|
92889
|
+
const totalRows = Math.max(...positions.map(({ cards, height }) => cards.length ? height : 1));
|
|
92890
|
+
const windows = boardWindows(options.viewport, stackStart + totalRows, stackStart, selectedCard);
|
|
92891
|
+
const stacks = positions.map(({ cards }) => {
|
|
92892
|
+
const rows2 = /* @__PURE__ */ new Map();
|
|
92893
|
+
if (!cards.length && intersects(stackStart, stackStart + 1, windows)) rows2.set(0, padCells("No tasks here.", colWidth));
|
|
92894
|
+
for (const card2 of cards) {
|
|
92895
|
+
if (!intersects(stackStart + card2.start, stackStart + card2.end, windows)) continue;
|
|
92896
|
+
const rendered = taskCard(
|
|
92897
|
+
card2.task,
|
|
92898
|
+
colWidth,
|
|
92899
|
+
card2.task.taskId === options.selectedTaskId,
|
|
92900
|
+
{ kind: "select", target: "task", column: TASK_STATUSES.indexOf(card2.task.status), index: card2.index, id: card2.task.taskId, activate: true }
|
|
92901
|
+
);
|
|
92902
|
+
rendered.forEach((line3, offset) => rows2.set(card2.start + offset, line3));
|
|
92903
|
+
}
|
|
92904
|
+
return rows2;
|
|
92905
|
+
});
|
|
92906
|
+
for (let row3 = 0; row3 < totalRows; row3++) {
|
|
92907
|
+
lines.push(intersects(stackStart + row3, stackStart + row3 + 1, windows) ? joinColumns(stacks.map((stack) => stack.get(row3) ?? ""), colWidth, gap) : "");
|
|
92908
|
+
}
|
|
92678
92909
|
}
|
|
92679
92910
|
} else {
|
|
92680
92911
|
const group = columns[focusedIndex]?.tasks ?? [];
|
|
@@ -92684,13 +92915,33 @@ function renderTaskBoard2(tasks, options) {
|
|
|
92684
92915
|
{ kind: "select", target: "task", column: focusedIndex, index: 0 }
|
|
92685
92916
|
), "\u2500".repeat(Math.min(width, 52)));
|
|
92686
92917
|
if (!group.length) lines.push(" No tasks here.");
|
|
92687
|
-
|
|
92688
|
-
|
|
92689
|
-
|
|
92690
|
-
|
|
92691
|
-
|
|
92692
|
-
|
|
92693
|
-
|
|
92918
|
+
if (!options.viewport) {
|
|
92919
|
+
for (const [index, task] of group.entries()) {
|
|
92920
|
+
lines.push(...taskCard(
|
|
92921
|
+
task,
|
|
92922
|
+
Math.min(width, 52),
|
|
92923
|
+
task.taskId === options.selectedTaskId,
|
|
92924
|
+
{ kind: "select", target: "task", column: focusedIndex, index, id: task.taskId, activate: true }
|
|
92925
|
+
));
|
|
92926
|
+
}
|
|
92927
|
+
} else {
|
|
92928
|
+
const stackStart = lines.length;
|
|
92929
|
+
const { cards, height } = cardPositions(group, Math.min(width, 52), options.selectedTaskId, 0);
|
|
92930
|
+
const windows = boardWindows(options.viewport, stackStart + height, stackStart, cards.find(({ task }) => task.taskId === options.selectedTaskId));
|
|
92931
|
+
const rows2 = Array(height).fill("");
|
|
92932
|
+
for (const card2 of cards) {
|
|
92933
|
+
if (!intersects(stackStart + card2.start, stackStart + card2.end, windows)) continue;
|
|
92934
|
+
const rendered = taskCard(
|
|
92935
|
+
card2.task,
|
|
92936
|
+
Math.min(width, 52),
|
|
92937
|
+
card2.task.taskId === options.selectedTaskId,
|
|
92938
|
+
{ kind: "select", target: "task", column: focusedIndex, index: card2.index, id: card2.task.taskId, activate: true }
|
|
92939
|
+
);
|
|
92940
|
+
rendered.forEach((line3, offset) => {
|
|
92941
|
+
rows2[card2.start + offset] = line3;
|
|
92942
|
+
});
|
|
92943
|
+
}
|
|
92944
|
+
lines.push(...rows2);
|
|
92694
92945
|
}
|
|
92695
92946
|
}
|
|
92696
92947
|
return lines;
|
|
@@ -92711,7 +92962,7 @@ function taskCard(task, width, selected, action2) {
|
|
|
92711
92962
|
if (!selected) return top ? `\u256D${edge}\u256E` : `\u2570${edge}\u256F`;
|
|
92712
92963
|
return styledLine([{ text: top ? `\u2554${edge}\u2557` : `\u255A${edge}\u255D`, color: STATUS_COLORS[task.status], background: SELECTED_BACKGROUND, bold: true }]);
|
|
92713
92964
|
};
|
|
92714
|
-
const titleLines =
|
|
92965
|
+
const titleLines = taskTitleLines(task, width, selected);
|
|
92715
92966
|
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
92967
|
return [
|
|
92717
92968
|
border(true),
|
|
@@ -94423,7 +94674,7 @@ function settingsChildren(route2, options) {
|
|
|
94423
94674
|
|
|
94424
94675
|
// src/tuiSettings.ts
|
|
94425
94676
|
var currentOwner = (ctx) => typeof ctx.owner === "function" ? ctx.owner() : ctx.owner;
|
|
94426
|
-
var ownerValid = (ctx,
|
|
94677
|
+
var ownerValid = (ctx, owner2) => currentOwner(ctx) === owner2 && ctx.state.owner === owner2 && (ctx.isOwnerCurrent?.() ?? true);
|
|
94427
94678
|
var asObject = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
94428
94679
|
var safeText2 = (value) => terminalText(String(value ?? "")).replace(/\s+/g, " ").trim();
|
|
94429
94680
|
var isSecret = (key) => /(?:secret|token|password|private.?key|encrypted|ciphertext|api_key$|^key$)/i.test(key);
|
|
@@ -94444,10 +94695,10 @@ function settingsWebUrl(ctx) {
|
|
|
94444
94695
|
return "https://openmates.org";
|
|
94445
94696
|
}
|
|
94446
94697
|
}
|
|
94447
|
-
function createTuiSettingsState(
|
|
94698
|
+
function createTuiSettingsState(owner2, options = {}) {
|
|
94448
94699
|
return {
|
|
94449
94700
|
route: "main",
|
|
94450
|
-
owner,
|
|
94701
|
+
owner: owner2,
|
|
94451
94702
|
ownerStale: false,
|
|
94452
94703
|
generation: 0,
|
|
94453
94704
|
authenticated: options.authenticated ?? true,
|
|
@@ -94492,17 +94743,17 @@ function restrictedSession(client2) {
|
|
|
94492
94743
|
}
|
|
94493
94744
|
}
|
|
94494
94745
|
function syncTuiSettingsOwner(ctx) {
|
|
94495
|
-
const
|
|
94496
|
-
if (ctx.isOwnerCurrent?.() === false &&
|
|
94746
|
+
const owner2 = currentOwner(ctx);
|
|
94747
|
+
if (ctx.isOwnerCurrent?.() === false && owner2 === ctx.state.owner) {
|
|
94497
94748
|
if (!ctx.state.ownerStale) {
|
|
94498
|
-
const fresh2 = createTuiSettingsState(
|
|
94749
|
+
const fresh2 = createTuiSettingsState(owner2, { authenticated: ctx.client.hasSession(), restricted: restrictedSession(ctx.client), paymentEnabled: false, webUrl: settingsWebUrl(ctx) });
|
|
94499
94750
|
Object.assign(ctx.state, fresh2, { ownerStale: true, generation: ctx.state.generation + 1 });
|
|
94500
94751
|
ctx.render();
|
|
94501
94752
|
}
|
|
94502
94753
|
return true;
|
|
94503
94754
|
}
|
|
94504
|
-
if (ctx.state.owner ===
|
|
94505
|
-
const fresh = createTuiSettingsState(
|
|
94755
|
+
if (ctx.state.owner === owner2) return false;
|
|
94756
|
+
const fresh = createTuiSettingsState(owner2, {
|
|
94506
94757
|
authenticated: ctx.client.hasSession(),
|
|
94507
94758
|
restricted: restrictedSession(ctx.client),
|
|
94508
94759
|
paymentEnabled: ctx.state.paymentEnabled,
|
|
@@ -94537,14 +94788,14 @@ async function loadPage(ctx, page) {
|
|
|
94537
94788
|
const state = ctx.state;
|
|
94538
94789
|
if (state.busy) return;
|
|
94539
94790
|
if (state.ownerStale) return;
|
|
94540
|
-
const
|
|
94791
|
+
const owner2 = currentOwner(ctx), generation = ++state.generation;
|
|
94541
94792
|
state.busy = true;
|
|
94542
94793
|
state.loading = true;
|
|
94543
94794
|
state.error = null;
|
|
94544
94795
|
ctx.render();
|
|
94545
94796
|
try {
|
|
94546
94797
|
const value = await page.load(ctx.client);
|
|
94547
|
-
if (!ownerValid(ctx,
|
|
94798
|
+
if (!ownerValid(ctx, owner2)) {
|
|
94548
94799
|
ctx.render();
|
|
94549
94800
|
return;
|
|
94550
94801
|
}
|
|
@@ -94565,9 +94816,9 @@ async function loadPage(ctx, page) {
|
|
|
94565
94816
|
state.isAdmin = info.is_admin === true;
|
|
94566
94817
|
}
|
|
94567
94818
|
} catch (error) {
|
|
94568
|
-
if (ownerValid(ctx,
|
|
94819
|
+
if (ownerValid(ctx, owner2) && state.generation === generation) state.error = safeText2(error instanceof Error ? error.message : error);
|
|
94569
94820
|
} finally {
|
|
94570
|
-
if (ownerValid(ctx,
|
|
94821
|
+
if (ownerValid(ctx, owner2) && state.generation === generation) {
|
|
94571
94822
|
state.busy = false;
|
|
94572
94823
|
state.loading = false;
|
|
94573
94824
|
ctx.render();
|
|
@@ -94604,10 +94855,10 @@ async function openTuiSettingsPage(state, route2, ctx) {
|
|
|
94604
94855
|
await loadPage(ctx, page);
|
|
94605
94856
|
}
|
|
94606
94857
|
async function loadProfile(ctx) {
|
|
94607
|
-
const state = ctx.state,
|
|
94858
|
+
const state = ctx.state, owner2 = currentOwner(ctx), generation = state.generation;
|
|
94608
94859
|
try {
|
|
94609
94860
|
const info = asObject(await ctx.client.whoAmI());
|
|
94610
|
-
if (!ownerValid(ctx,
|
|
94861
|
+
if (!ownerValid(ctx, owner2) || state.generation !== generation) return;
|
|
94611
94862
|
state.profile = { username: safeText2(info.username), email: safeText2(info.email), account: safeText2(info.id), team: safeText2(info.active_team_name) };
|
|
94612
94863
|
state.isAdmin = info.is_admin === true;
|
|
94613
94864
|
ctx.render();
|
|
@@ -94615,11 +94866,11 @@ async function loadProfile(ctx) {
|
|
|
94615
94866
|
}
|
|
94616
94867
|
}
|
|
94617
94868
|
async function loadCapabilities(ctx) {
|
|
94618
|
-
const state = ctx.state,
|
|
94869
|
+
const state = ctx.state, owner2 = currentOwner(ctx), generation = state.generation;
|
|
94619
94870
|
if (!state.authenticated || typeof ctx.client.settingsGet !== "function") return;
|
|
94620
94871
|
try {
|
|
94621
94872
|
const status = asObject(await ctx.client.settingsGet("server-status"));
|
|
94622
|
-
if (!ownerValid(ctx,
|
|
94873
|
+
if (!ownerValid(ctx, owner2) || state.generation !== generation) return;
|
|
94623
94874
|
state.paymentEnabled = status.is_self_hosted !== true && status.payment_enabled === true;
|
|
94624
94875
|
state.paymentChecked = true;
|
|
94625
94876
|
ctx.render();
|
|
@@ -94688,7 +94939,7 @@ async function runMutation(ctx, actionId) {
|
|
|
94688
94939
|
ctx.render();
|
|
94689
94940
|
return;
|
|
94690
94941
|
}
|
|
94691
|
-
const
|
|
94942
|
+
const owner2 = currentOwner(ctx), generation = ++state.generation;
|
|
94692
94943
|
state.busy = true;
|
|
94693
94944
|
state.error = null;
|
|
94694
94945
|
state.message = null;
|
|
@@ -94700,7 +94951,7 @@ async function runMutation(ctx, actionId) {
|
|
|
94700
94951
|
ctx.render();
|
|
94701
94952
|
return;
|
|
94702
94953
|
}
|
|
94703
|
-
if (!ownerValid(ctx,
|
|
94954
|
+
if (!ownerValid(ctx, owner2) || state.generation !== generation) return;
|
|
94704
94955
|
const response = asObject(result);
|
|
94705
94956
|
if (response.success === false) throw new Error(safeText2(response.message) || "Operation was not accepted.");
|
|
94706
94957
|
state.message = action2 ? `${action2.label} completed.` : "Saved.";
|
|
@@ -94716,9 +94967,9 @@ async function runMutation(ctx, actionId) {
|
|
|
94716
94967
|
return;
|
|
94717
94968
|
}
|
|
94718
94969
|
} catch (error) {
|
|
94719
|
-
if (ownerValid(ctx,
|
|
94970
|
+
if (ownerValid(ctx, owner2) && state.generation === generation) state.error = safeText2(error instanceof Error ? error.message : error);
|
|
94720
94971
|
} finally {
|
|
94721
|
-
if (ownerValid(ctx,
|
|
94972
|
+
if (ownerValid(ctx, owner2) && state.generation === generation) {
|
|
94722
94973
|
state.busy = false;
|
|
94723
94974
|
ctx.render();
|
|
94724
94975
|
}
|
|
@@ -94788,19 +95039,19 @@ async function handleTuiSettingsCommand(ctx, arg) {
|
|
|
94788
95039
|
if (row3.switchTeam) {
|
|
94789
95040
|
if (ctx.client.getActiveTeamId() === row3.switchTeam) await openTuiSettingsPage(state, "teams/details", ctx);
|
|
94790
95041
|
else {
|
|
94791
|
-
const
|
|
95042
|
+
const owner2 = currentOwner(ctx), generation = ++state.generation;
|
|
94792
95043
|
state.busy = true;
|
|
94793
95044
|
state.error = null;
|
|
94794
95045
|
ctx.render();
|
|
94795
95046
|
try {
|
|
94796
95047
|
const team = await ctx.client.getTeam(row3.switchTeam);
|
|
94797
|
-
if (!ownerValid(ctx,
|
|
95048
|
+
if (!ownerValid(ctx, owner2) || state.generation !== generation) return true;
|
|
94798
95049
|
ctx.client.setActiveTeamId(team.team_id ?? row3.switchTeam);
|
|
94799
95050
|
ctx.render();
|
|
94800
95051
|
} catch (error) {
|
|
94801
|
-
if (ownerValid(ctx,
|
|
95052
|
+
if (ownerValid(ctx, owner2) && state.generation === generation) state.error = safeText2(error instanceof Error ? error.message : error);
|
|
94802
95053
|
} finally {
|
|
94803
|
-
if (ownerValid(ctx,
|
|
95054
|
+
if (ownerValid(ctx, owner2) && state.generation === generation) {
|
|
94804
95055
|
state.busy = false;
|
|
94805
95056
|
ctx.render();
|
|
94806
95057
|
}
|
|
@@ -95102,13 +95353,13 @@ function renderTuiSettings(state, width) {
|
|
|
95102
95353
|
// src/tuiModelSelector.ts
|
|
95103
95354
|
var currentOwner2 = (ctx) => typeof ctx.owner === "function" ? ctx.owner() : ctx.owner;
|
|
95104
95355
|
var currentChatId = (ctx) => typeof ctx.chatId === "function" ? ctx.chatId() : ctx.chatId;
|
|
95105
|
-
var current = (ctx,
|
|
95356
|
+
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
95357
|
var clean = (value) => terminalText(value).replace(/\s+/g, " ").trim();
|
|
95107
95358
|
var modelValue = (model) => model.id;
|
|
95108
95359
|
var rank = { low: 0, medium: 1, high: 2, max: 3 };
|
|
95109
|
-
function createTuiModelSelectorState(
|
|
95360
|
+
function createTuiModelSelectorState(owner2, chatId = null) {
|
|
95110
95361
|
return {
|
|
95111
|
-
owner,
|
|
95362
|
+
owner: owner2,
|
|
95112
95363
|
chatId,
|
|
95113
95364
|
generation: 0,
|
|
95114
95365
|
open: false,
|
|
@@ -95125,9 +95376,9 @@ function createTuiModelSelectorState(owner, chatId = null) {
|
|
|
95125
95376
|
};
|
|
95126
95377
|
}
|
|
95127
95378
|
function syncTuiModelSelectorOwner(ctx) {
|
|
95128
|
-
const
|
|
95129
|
-
if (ctx.state.owner ===
|
|
95130
|
-
Object.assign(ctx.state, createTuiModelSelectorState(
|
|
95379
|
+
const owner2 = currentOwner2(ctx), chatId = currentChatId(ctx);
|
|
95380
|
+
if (ctx.state.owner === owner2 && ctx.state.chatId === chatId && (ctx.isOwnerCurrent?.() ?? true)) return false;
|
|
95381
|
+
Object.assign(ctx.state, createTuiModelSelectorState(owner2, chatId), { generation: ctx.state.generation + 1 });
|
|
95131
95382
|
ctx.render();
|
|
95132
95383
|
return true;
|
|
95133
95384
|
}
|
|
@@ -95165,14 +95416,14 @@ function tuiModelSelectionForSend(state) {
|
|
|
95165
95416
|
}
|
|
95166
95417
|
async function restoreTuiModelSelection(ctx) {
|
|
95167
95418
|
syncTuiModelSelectorOwner(ctx);
|
|
95168
|
-
const state = ctx.state,
|
|
95419
|
+
const state = ctx.state, owner2 = currentOwner2(ctx), chatId = currentChatId(ctx), generation = ++state.generation;
|
|
95169
95420
|
state.ready = false;
|
|
95170
95421
|
state.busy = true;
|
|
95171
95422
|
state.error = null;
|
|
95172
95423
|
ctx.render();
|
|
95173
95424
|
try {
|
|
95174
95425
|
const [catalogResult, selectionResult] = await Promise.allSettled([ctx.loadCatalog(), ctx.restoreSelection()]);
|
|
95175
|
-
if (!current(ctx,
|
|
95426
|
+
if (!current(ctx, owner2, chatId, generation)) return;
|
|
95176
95427
|
if (catalogResult.status === "fulfilled") {
|
|
95177
95428
|
state.models = catalogResult.value.filter((model) => model.id.startsWith(`${model.providerId}/`) && model.name && model.providerName);
|
|
95178
95429
|
state.catalogAuthoritative = catalogResult.value.authoritative !== false;
|
|
@@ -95205,13 +95456,13 @@ async function restoreTuiModelSelection(ctx) {
|
|
|
95205
95456
|
state.selection = "auto";
|
|
95206
95457
|
state.error = "The selected model is unavailable. Reset to Auto.";
|
|
95207
95458
|
await ctx.persistSelection("auto");
|
|
95208
|
-
if (!current(ctx,
|
|
95459
|
+
if (!current(ctx, owner2, chatId, generation)) return;
|
|
95209
95460
|
}
|
|
95210
95461
|
state.ready = true;
|
|
95211
95462
|
} catch (error) {
|
|
95212
|
-
if (current(ctx,
|
|
95463
|
+
if (current(ctx, owner2, chatId, generation)) state.error = clean(error instanceof Error ? error.message : String(error));
|
|
95213
95464
|
} finally {
|
|
95214
|
-
if (current(ctx,
|
|
95465
|
+
if (current(ctx, owner2, chatId, generation)) {
|
|
95215
95466
|
state.busy = false;
|
|
95216
95467
|
ctx.render();
|
|
95217
95468
|
}
|
|
@@ -95322,20 +95573,20 @@ async function handleTuiModelSelectorAction(ctx, action2) {
|
|
|
95322
95573
|
const requested = action2.slice(7);
|
|
95323
95574
|
if (requested !== "auto" && !usableModels(state).some((model) => modelValue(model) === requested)) return true;
|
|
95324
95575
|
const selection = requested === state.selection && requested !== "auto" ? "auto" : requested;
|
|
95325
|
-
const
|
|
95576
|
+
const owner2 = currentOwner2(ctx), chatId = currentChatId(ctx), generation = ++state.generation;
|
|
95326
95577
|
state.busy = true;
|
|
95327
95578
|
state.error = null;
|
|
95328
95579
|
ctx.render();
|
|
95329
95580
|
try {
|
|
95330
95581
|
const persisted = await ctx.persistSelection(selection);
|
|
95331
|
-
if (!current(ctx,
|
|
95582
|
+
if (!current(ctx, owner2, chatId, generation)) return true;
|
|
95332
95583
|
state.selection = persisted;
|
|
95333
95584
|
if (persisted === "auto") state.ready = true;
|
|
95334
95585
|
closeTuiModelSelector(ctx);
|
|
95335
95586
|
} catch (error) {
|
|
95336
|
-
if (current(ctx,
|
|
95587
|
+
if (current(ctx, owner2, chatId, generation)) state.error = clean(error instanceof Error ? error.message : String(error));
|
|
95337
95588
|
} finally {
|
|
95338
|
-
if (current(ctx,
|
|
95589
|
+
if (current(ctx, owner2, chatId, generation)) {
|
|
95339
95590
|
state.busy = false;
|
|
95340
95591
|
ctx.render();
|
|
95341
95592
|
}
|
|
@@ -95484,15 +95735,15 @@ function createTuiModelSelectorShell(args) {
|
|
|
95484
95735
|
}
|
|
95485
95736
|
};
|
|
95486
95737
|
const sync = () => {
|
|
95487
|
-
const
|
|
95488
|
-
if (!
|
|
95738
|
+
const owner2 = ownerId(client2);
|
|
95739
|
+
if (!owner2 || !isTuiAiComposer(state)) {
|
|
95489
95740
|
clearSubscription();
|
|
95490
95741
|
ownerFence = null;
|
|
95491
95742
|
state.modelSelector = null;
|
|
95492
95743
|
return;
|
|
95493
95744
|
}
|
|
95494
95745
|
const chatId = chatIdForView(state);
|
|
95495
|
-
if (state.modelSelector?.owner ===
|
|
95746
|
+
if (state.modelSelector?.owner === owner2 && state.modelSelector.chatId === chatId && ownerFence?.()) {
|
|
95496
95747
|
if (!waitingForChat || state.headerState !== "ready") return;
|
|
95497
95748
|
waitingForChat = false;
|
|
95498
95749
|
const ctx = context();
|
|
@@ -95502,7 +95753,7 @@ function createTuiModelSelectorShell(args) {
|
|
|
95502
95753
|
return;
|
|
95503
95754
|
}
|
|
95504
95755
|
clearSubscription();
|
|
95505
|
-
state.modelSelector = createTuiModelSelectorState(
|
|
95756
|
+
state.modelSelector = createTuiModelSelectorState(owner2, chatId);
|
|
95506
95757
|
ownerFence = captureTuiWorkspaceOwner(client2);
|
|
95507
95758
|
subscribe(chatId);
|
|
95508
95759
|
const picker = state.modelSelector;
|
|
@@ -95577,12 +95828,12 @@ function createTuiModelSelectorShell(args) {
|
|
|
95577
95828
|
}
|
|
95578
95829
|
const ctx = context();
|
|
95579
95830
|
if (!ctx) return { message, blocked: true };
|
|
95580
|
-
const
|
|
95831
|
+
const owner2 = picker.owner, chatId = picker.chatId, generation = picker.generation;
|
|
95581
95832
|
picker.busy = true;
|
|
95582
95833
|
render();
|
|
95583
95834
|
try {
|
|
95584
95835
|
const saved = await ctx.persistSelection(selected.id);
|
|
95585
|
-
if (state.modelSelector !== picker || !ownerFence?.() || picker.owner !==
|
|
95836
|
+
if (state.modelSelector !== picker || !ownerFence?.() || picker.owner !== owner2 || picker.chatId !== chatId || picker.generation !== generation)
|
|
95586
95837
|
return { message, blocked: true };
|
|
95587
95838
|
picker.selection = saved;
|
|
95588
95839
|
picker.ready = true;
|
|
@@ -95968,11 +96219,12 @@ function parseTuiMarkdown(content, width, options = {}) {
|
|
|
95968
96219
|
index = next;
|
|
95969
96220
|
continue;
|
|
95970
96221
|
}
|
|
95971
|
-
for (const line3 of rows2.slice(index, Math.min(next + 1, rows2.length)))
|
|
96222
|
+
for (const line3 of options.semanticOnly ? [] : rows2.slice(index, Math.min(next + 1, rows2.length)))
|
|
95972
96223
|
output.push(...wrapped([{ text: terminalText(line3), color: CODE }], width).map((line4) => ({ type: "line", line: line4 })));
|
|
95973
96224
|
index = next;
|
|
95974
96225
|
continue;
|
|
95975
96226
|
}
|
|
96227
|
+
if (options.semanticOnly) continue;
|
|
95976
96228
|
const heading = /^\s{0,3}#{1,6}\s+(.+?)\s*#*\s*$/.exec(row3);
|
|
95977
96229
|
if (heading && output.length && output.at(-1)?.type === "line" && output.at(-1).line !== "") {
|
|
95978
96230
|
const previous = output.at(-1);
|
|
@@ -96245,7 +96497,8 @@ function renderTuiResultsViewLines(data, options = {}) {
|
|
|
96245
96497
|
|
|
96246
96498
|
// src/tuiChatResults.ts
|
|
96247
96499
|
function messageResultsViews(content) {
|
|
96248
|
-
|
|
96500
|
+
if (!/embeds_(?:results|map)_view/i.test(content)) return [];
|
|
96501
|
+
return parseMessageSegments(content, { preserveCodeFences: true }).flatMap((segment) => segment.type === "text" ? parseTuiMarkdown(segment.value, 160, { semanticOnly: true }).filter((block) => block.type === "results-view") : []);
|
|
96249
96502
|
}
|
|
96250
96503
|
function messageSupplementalEmbedIds(content) {
|
|
96251
96504
|
const ids = /* @__PURE__ */ new Set();
|
|
@@ -97478,7 +97731,8 @@ function renderHeaderDialog(dialog, width, height = 24, state) {
|
|
|
97478
97731
|
|
|
97479
97732
|
// src/tuiInteractiveQuestions.ts
|
|
97480
97733
|
function messageQuestions(content) {
|
|
97481
|
-
|
|
97734
|
+
if (!/interactive_question/i.test(content)) return [];
|
|
97735
|
+
return parseTuiMarkdown(content, 160, { semanticOnly: true }).flatMap((block) => block.type === "question" ? [block.payload] : []);
|
|
97482
97736
|
}
|
|
97483
97737
|
function chatQuestions(state) {
|
|
97484
97738
|
const messages = state.screen === "example" && state.activeExample ? state.activeExample.messages : state.messages;
|
|
@@ -97491,7 +97745,8 @@ function chatQuestions(state) {
|
|
|
97491
97745
|
const latest = questions.filter((item) => item.payload.id === question.payload.id).at(-1);
|
|
97492
97746
|
for (let index = messages.length - 1; index > latest.messageIndex; index--) {
|
|
97493
97747
|
if (messages[index].role !== "user") continue;
|
|
97494
|
-
|
|
97748
|
+
if (!/interactive_response/i.test(messages[index].content)) continue;
|
|
97749
|
+
const response = parseTuiMarkdown(messages[index].content, 160, { semanticOnly: true }).find((block) => block.type === "response" && block.payload.id === question.payload.id);
|
|
97495
97750
|
if (response?.type === "response" && !validateInteractiveQuestionAnswer(question.payload, response.payload)) {
|
|
97496
97751
|
question.response = formatInteractiveQuestionAnswer(question.payload, response.payload).responsePayload;
|
|
97497
97752
|
break;
|
|
@@ -98456,13 +98711,17 @@ function renderWorkspaceFrame(state, rawWidth, rawHeight, body, options = {}) {
|
|
|
98456
98711
|
const marker = content.findIndex((row3) => /^[>›] /.test(lineText(row3).trimStart()));
|
|
98457
98712
|
start = marker >= bodyHeight - 4 ? Math.max(0, marker - bodyHeight + 6) : 0;
|
|
98458
98713
|
} 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) => /(?:^|[
|
|
98714
|
+
const markers = content.map((row3, index) => /(?:^|[│║|])\s*[>›] /.test(lineText(row3)) ? index : -1).filter((index) => index >= 0);
|
|
98460
98715
|
const marker = state.screen === "workflow" ? markers.at(-1) ?? -1 : markers[0] ?? -1;
|
|
98461
98716
|
let selectionEnd = marker;
|
|
98462
98717
|
if (["workflow", "start", "chats", "apps", "projects", "workflows"].includes(state.screen) && marker >= 0) {
|
|
98463
98718
|
const closing2 = content.findIndex((row3, index) => index > marker && lineText(row3).includes("\u2570"));
|
|
98464
98719
|
selectionEnd = Math.min(marker + 10, closing2 < 0 ? marker : closing2);
|
|
98465
98720
|
}
|
|
98721
|
+
if ((state.screen === "tasks" || state.screen === "project" && state.projectTab === "tasks") && marker >= 0) {
|
|
98722
|
+
const closing2 = content.findIndex((row3, index) => index > marker && lineText(row3).includes("\u255A"));
|
|
98723
|
+
selectionEnd = closing2 < 0 ? marker : closing2;
|
|
98724
|
+
}
|
|
98466
98725
|
if (selectionEnd >= start + viewportHeight) start = Math.min(maxStart, selectionEnd - viewportHeight + 1);
|
|
98467
98726
|
if (marker >= 0 && marker < start) start = marker;
|
|
98468
98727
|
}
|
|
@@ -98546,7 +98805,9 @@ function renderWorkspaceFrame(state, rawWidth, rawHeight, body, options = {}) {
|
|
|
98546
98805
|
const sidebarRow = sidebarWidth ? renderSide(side[i], sidebarWidth, gutter, true) : void 0;
|
|
98547
98806
|
const settingsColumn2 = gutter + sidebarWidth + paneWidth + 2;
|
|
98548
98807
|
const settingsRow = settingsWidth ? renderSide(settingsRows[i], settingsWidth, settingsColumn2, false) : void 0;
|
|
98549
|
-
|
|
98808
|
+
const painted = place(rendered, sidebarRow, settingsRow);
|
|
98809
|
+
rows2.push(painted);
|
|
98810
|
+
options.onBodyLine?.(value, i + 2, rendered, painted);
|
|
98550
98811
|
}
|
|
98551
98812
|
if (state.modelSelector?.open && showComposer && aiComposer && !modal && !settingsFullscreen && bodyHeight > 0) {
|
|
98552
98813
|
const popWidth = Math.max(1, Math.min(46, composerWidth));
|
|
@@ -99906,8 +100167,8 @@ function executeTuiAppsSkill(client2, run, confirmation) {
|
|
|
99906
100167
|
async function executeConfirmedTuiAppsSkill(client2, run) {
|
|
99907
100168
|
if (!client2.hasSession()) throw new Error("Sign in to run Apps skills in the terminal.");
|
|
99908
100169
|
if (client2.getActiveTeamId()) throw new Error("Switch to Personal to run Apps skills in the terminal.");
|
|
99909
|
-
const
|
|
99910
|
-
const ownerId2 = string3(
|
|
100170
|
+
const owner2 = record7(await client2.whoAmI());
|
|
100171
|
+
const ownerId2 = string3(owner2.id, string3(owner2.user_id));
|
|
99911
100172
|
if (!ownerId2) throw new Error("Account identity unavailable; skill was not run.");
|
|
99912
100173
|
const rootId = randomUUID19();
|
|
99913
100174
|
const key = randomBytes10(32);
|
|
@@ -100233,6 +100494,106 @@ async function handleSettingsKey(context, chunk, key) {
|
|
|
100233
100494
|
return handleTuiSettingsKey(ctx, chunk, key);
|
|
100234
100495
|
}
|
|
100235
100496
|
|
|
100497
|
+
// src/tuiStreamingRender.ts
|
|
100498
|
+
var COLORS = ["#ff2d55", "#ff6b2b", "#ffd60a", "#30d158", "#32ade6", "#bf5af2"];
|
|
100499
|
+
var glowLines = /* @__PURE__ */ new WeakSet();
|
|
100500
|
+
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)(?:$|[-_])/;
|
|
100501
|
+
function tuiResponsePhase(segments2) {
|
|
100502
|
+
const skills = [];
|
|
100503
|
+
for (let i = segments2.length - 1; i >= 0; i--) {
|
|
100504
|
+
const segment = segments2[i];
|
|
100505
|
+
if (segment.type === "text") {
|
|
100506
|
+
if (segment.value.trim()) break;
|
|
100507
|
+
continue;
|
|
100508
|
+
}
|
|
100509
|
+
skills.push(typeof segment.meta?.skill_id === "string" ? segment.meta.skill_id : "");
|
|
100510
|
+
}
|
|
100511
|
+
return skills.length ? skills.some((id) => ACTION_SKILL.test(id.toLowerCase())) ? "Working" : "Researching" : "Working";
|
|
100512
|
+
}
|
|
100513
|
+
function clearTuiSendState(state) {
|
|
100514
|
+
state.isBusy = false;
|
|
100515
|
+
state.isAwaitingAi = false;
|
|
100516
|
+
state.streamingMessage = null;
|
|
100517
|
+
state.aiTaskId = null;
|
|
100518
|
+
state.projectFocusPending = null;
|
|
100519
|
+
}
|
|
100520
|
+
var owner = (state) => JSON.stringify([state.signedIn, state.currentUserHash, state.activeTeamId, state.activeChatId, state.routeVersion]);
|
|
100521
|
+
var frames2 = /* @__PURE__ */ new WeakMap();
|
|
100522
|
+
function renderTuiThinking(mate, width, model, phase = "Thinking") {
|
|
100523
|
+
const status = truncateCells(`\u2726 ${phase}\u2026`, width), statusStart = Math.max(0, Math.floor((width - cells(status)) / 2));
|
|
100524
|
+
const name = truncateCells(mate, Math.max(0, statusStart - 1));
|
|
100525
|
+
const spans = [
|
|
100526
|
+
{ text: name, bold: true, color: "#5a85eb" },
|
|
100527
|
+
{ text: " ".repeat(Math.max(0, statusStart - cells(name))) },
|
|
100528
|
+
{ text: status, bold: true, color: "#80caff" }
|
|
100529
|
+
];
|
|
100530
|
+
const rows2 = name ? [{ text: spans.map((span) => span.text).join(""), spans }] : [
|
|
100531
|
+
{ text: truncateCells(mate, width), bold: true, color: "#5a85eb" },
|
|
100532
|
+
{ text: status, bold: true, color: "#80caff" }
|
|
100533
|
+
];
|
|
100534
|
+
if (model) rows2.push({ text: truncateCells(model, width), color: "#808080" });
|
|
100535
|
+
return rows2;
|
|
100536
|
+
}
|
|
100537
|
+
function renderTuiStreamingGlow(width, phase) {
|
|
100538
|
+
const size = Math.max(1, Math.min(72, width)), inset = Math.max(0, Math.floor((width - size) / 2));
|
|
100539
|
+
const spans = [
|
|
100540
|
+
{ text: " ".repeat(inset), color: "#e6e6e6" },
|
|
100541
|
+
...Array.from({ length: size }, (_, index) => ({
|
|
100542
|
+
text: "\u2581",
|
|
100543
|
+
color: COLORS[(Math.floor(index * COLORS.length / size - phase / 2) % COLORS.length + COLORS.length) % COLORS.length]
|
|
100544
|
+
})),
|
|
100545
|
+
{ text: " ".repeat(Math.max(0, width - size - inset)), color: "#e6e6e6" }
|
|
100546
|
+
];
|
|
100547
|
+
const line3 = { text: spans.map((span) => span.text).join(""), spans };
|
|
100548
|
+
glowLines.add(line3);
|
|
100549
|
+
return line3;
|
|
100550
|
+
}
|
|
100551
|
+
function isTuiStreamingGlow(line3) {
|
|
100552
|
+
return typeof line3 !== "string" && glowLines.has(line3);
|
|
100553
|
+
}
|
|
100554
|
+
function clearTuiStreamingFrame(state) {
|
|
100555
|
+
frames2.delete(state);
|
|
100556
|
+
}
|
|
100557
|
+
function rememberTuiStreamingFrame(state, frame, width, height, bodyWidth, painted, options) {
|
|
100558
|
+
const mode = options.colorMode ?? "none";
|
|
100559
|
+
if (!painted || !state.isAwaitingAi || state.screen !== "chat" || mode === "none" || options.reducedMotion || state.modelSelector?.open) return;
|
|
100560
|
+
const at = painted.line.indexOf(painted.rendered);
|
|
100561
|
+
if (at < 0) return;
|
|
100562
|
+
const prefix = painted.line.slice(0, at), suffix = painted.line.slice(at + painted.rendered.length);
|
|
100563
|
+
const variants = Array.from({ length: 12 }, (_, phase) => {
|
|
100564
|
+
const glow = renderTuiStreamingGlow(bodyWidth, phase);
|
|
100565
|
+
return prefix + (typeof glow === "string" ? glow : glow.spans.map((span) => foreground(span.text, span.color ?? "#e6e6e6", mode)).join("")) + suffix;
|
|
100566
|
+
});
|
|
100567
|
+
frames2.set(state, {
|
|
100568
|
+
owner: owner(state),
|
|
100569
|
+
width,
|
|
100570
|
+
height,
|
|
100571
|
+
mode,
|
|
100572
|
+
ascii: options.ascii ?? false,
|
|
100573
|
+
rows: frame.split("\n"),
|
|
100574
|
+
row: painted.row,
|
|
100575
|
+
variants,
|
|
100576
|
+
messages: state.messages,
|
|
100577
|
+
message: state.streamingMessage,
|
|
100578
|
+
content: state.streamingMessage?.content,
|
|
100579
|
+
thinking: state.streamingMessage?.thinkingContent,
|
|
100580
|
+
thinkingActive: state.streamingMessage?.thinkingActive,
|
|
100581
|
+
expanded: state.streamingMessage?.thinkingExpanded,
|
|
100582
|
+
model: state.streamingMessage?.modelName,
|
|
100583
|
+
scroll: state.scrollOffset,
|
|
100584
|
+
input: state.input,
|
|
100585
|
+
focus: state.focus,
|
|
100586
|
+
sidebar: state.sidebarOpen,
|
|
100587
|
+
settings: state.settings
|
|
100588
|
+
});
|
|
100589
|
+
}
|
|
100590
|
+
function renderTuiStreamingAnimationFrame(state, width, height, options = {}) {
|
|
100591
|
+
const saved = frames2.get(state);
|
|
100592
|
+
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;
|
|
100593
|
+
saved.rows[saved.row] = saved.variants[(state.streamingPhase % 12 + 12) % 12];
|
|
100594
|
+
return saved.rows.join("\n");
|
|
100595
|
+
}
|
|
100596
|
+
|
|
100236
100597
|
// src/tuiFullscreenChrome.ts
|
|
100237
100598
|
function captureTuiView(state) {
|
|
100238
100599
|
return {
|
|
@@ -100248,6 +100609,7 @@ function captureTuiView(state) {
|
|
|
100248
100609
|
};
|
|
100249
100610
|
}
|
|
100250
100611
|
function restoreTuiView(state, origin) {
|
|
100612
|
+
clearTuiSendState(state);
|
|
100251
100613
|
Object.assign(state, origin);
|
|
100252
100614
|
state.inputCursor = origin.inputCursor ?? null;
|
|
100253
100615
|
state.navigationIndex = ["chats", "apps", "projects", "workflows", "tasks"].indexOf(state.workspace);
|
|
@@ -100276,6 +100638,7 @@ function closeTuiFullscreen(state) {
|
|
|
100276
100638
|
return true;
|
|
100277
100639
|
}
|
|
100278
100640
|
if (state.screen === "chat" || state.screen === "example") {
|
|
100641
|
+
clearTuiSendState(state);
|
|
100279
100642
|
if (!state.input.startsWith("/")) state.drafts[state.screen === "example" ? `example:${state.activeExample?.chat.id}` : state.activeChatId ?? "new"] = state.input;
|
|
100280
100643
|
const origin = state.chatOrigin;
|
|
100281
100644
|
state.chatOrigin = null;
|
|
@@ -100504,7 +100867,9 @@ function createInitialTuiState() {
|
|
|
100504
100867
|
chatContextAuthoringControls: {},
|
|
100505
100868
|
status: null,
|
|
100506
100869
|
isBusy: false,
|
|
100507
|
-
isAwaitingAi: false
|
|
100870
|
+
isAwaitingAi: false,
|
|
100871
|
+
streamingMessage: null,
|
|
100872
|
+
streamingPhase: 0
|
|
100508
100873
|
};
|
|
100509
100874
|
}
|
|
100510
100875
|
function programmaticQuickstart() {
|
|
@@ -100560,6 +100925,7 @@ function resetEndedTuiSession(state, hasSession) {
|
|
|
100560
100925
|
return true;
|
|
100561
100926
|
}
|
|
100562
100927
|
function renderTuiFrame(state, width, height, options = {}) {
|
|
100928
|
+
clearTuiStreamingFrame(state);
|
|
100563
100929
|
if (state.screen !== "chat") clearChatRenderCache(state);
|
|
100564
100930
|
fenceTuiSettingsView(state);
|
|
100565
100931
|
beginPointerFrame(state, width, height);
|
|
@@ -100569,13 +100935,23 @@ function renderTuiFrame(state, width, height, options = {}) {
|
|
|
100569
100935
|
const teamBanner = state.signedIn && state.activeTeamId ? [{ text: teamIdentityLabel(state), color: "#5a85eb", bold: true }] : [];
|
|
100570
100936
|
const embedHero = state.screen === "embed" ? renderEmbedHero(state, bodyWidth, height) : null;
|
|
100571
100937
|
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
|
-
|
|
100938
|
+
let glow;
|
|
100939
|
+
const frame = renderWorkspaceFrame(
|
|
100573
100940
|
state,
|
|
100574
100941
|
width,
|
|
100575
100942
|
height,
|
|
100576
100943
|
[...header2, ...teamBanner, ...renderBody(state, bodyWidth, height, embedHero ?? void 0)],
|
|
100577
|
-
{
|
|
100944
|
+
{
|
|
100945
|
+
...options,
|
|
100946
|
+
stickyRows: stickyRows + header2.length + teamBanner.length,
|
|
100947
|
+
stickyFallbackRows: embedHero ? header2.length + teamBanner.length : void 0,
|
|
100948
|
+
onBodyLine: (value, row3, rendered, line3) => {
|
|
100949
|
+
if (isTuiStreamingGlow(value)) glow = { row: row3, rendered, line: line3 };
|
|
100950
|
+
}
|
|
100951
|
+
}
|
|
100578
100952
|
);
|
|
100953
|
+
rememberTuiStreamingFrame(state, frame, width, height, bodyWidth, glow, options);
|
|
100954
|
+
return frame;
|
|
100579
100955
|
}
|
|
100580
100956
|
function teamIdentityLabel(state) {
|
|
100581
100957
|
const name = terminalText(state.activeTeamName?.trim() || "Team").replace(/\s+/g, " ").slice(0, 80);
|
|
@@ -100687,7 +101063,7 @@ function renderScreenBody(state, width, height, embedHero) {
|
|
|
100687
101063
|
case "projects":
|
|
100688
101064
|
return [...homeHeader(state, width, height), ...renderProjectCarousel(filteredProjects(state.projects, state.filter), width, state.selectedIndex, state.focus === "content")];
|
|
100689
101065
|
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"];
|
|
101066
|
+
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
101067
|
case "status":
|
|
100692
101068
|
return renderStatus(state, width);
|
|
100693
101069
|
case "results-view": {
|
|
@@ -100719,9 +101095,9 @@ function renderScreenBody(state, width, height, embedHero) {
|
|
|
100719
101095
|
case "workflow":
|
|
100720
101096
|
return renderWorkflowDetail(state, width);
|
|
100721
101097
|
case "tasks":
|
|
100722
|
-
return [...homeHeader(state, width, height), ...renderTasks(state, width)];
|
|
101098
|
+
return [...homeHeader(state, width, height), ...renderTasks(state, width, height, homeHeader(state, width, height).length)];
|
|
100723
101099
|
case "task":
|
|
100724
|
-
return renderTaskDetail2(state, width);
|
|
101100
|
+
return renderTaskDetail2(state, width, height);
|
|
100725
101101
|
case "start":
|
|
100726
101102
|
default:
|
|
100727
101103
|
return [...renderHomeChatCards(state, width, height), ...state.signedIn && state.activeTeamId ? ["", teamAiReminder()] : []];
|
|
@@ -100761,11 +101137,18 @@ function renderHelp(width) {
|
|
|
100761
101137
|
"Outside TUI: openmates --help, openmates chats --help, openmates apps --help"
|
|
100762
101138
|
].flatMap((line3) => wrap(line3, width));
|
|
100763
101139
|
}
|
|
100764
|
-
function
|
|
100765
|
-
return
|
|
101140
|
+
function taskViewport(state, height, prefixRows = 0) {
|
|
101141
|
+
return {
|
|
101142
|
+
start: Math.max(0, state.scrollOffset - prefixRows - 4),
|
|
101143
|
+
end: state.scrollOffset + height + 4,
|
|
101144
|
+
followSelection: state.followSelection && state.focus === "content"
|
|
101145
|
+
};
|
|
100766
101146
|
}
|
|
100767
|
-
function
|
|
100768
|
-
|
|
101147
|
+
function renderTasks(state, width, height, prefixRows = 0) {
|
|
101148
|
+
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) });
|
|
101149
|
+
}
|
|
101150
|
+
function renderTaskDetail2(state, width, height) {
|
|
101151
|
+
if (!state.activeTask) return renderTasks(state, width, height);
|
|
100769
101152
|
return renderTaskDetails(state.activeTask, {
|
|
100770
101153
|
width,
|
|
100771
101154
|
activity: state.taskContext?.activity,
|
|
@@ -100868,8 +101251,7 @@ function renderExampleChat(state, width, height) {
|
|
|
100868
101251
|
}
|
|
100869
101252
|
return lines.flatMap((line3) => typeof line3 === "string" ? wrap(line3, width) : [line3]);
|
|
100870
101253
|
}
|
|
100871
|
-
function renderChat(state, width, height) {
|
|
100872
|
-
const lines = renderChatHeader(state, width, height);
|
|
101254
|
+
function renderChat(state, width, height, fullHistory = false) {
|
|
100873
101255
|
const embeds = new Map(Object.entries(state.chatEmbeds));
|
|
100874
101256
|
const cacheContext = {
|
|
100875
101257
|
owner: JSON.stringify([state.signedIn, state.currentUserHash, state.activeTeamId, state.activeChatId, state.routeVersion]),
|
|
@@ -100896,47 +101278,84 @@ function renderChat(state, width, height) {
|
|
|
100896
101278
|
return firstEmbedId;
|
|
100897
101279
|
};
|
|
100898
101280
|
let contextIndex2 = 0, viewOffset = 0, questionOffset = 0;
|
|
100899
|
-
|
|
101281
|
+
const offsets = state.messages.map((message) => {
|
|
100900
101282
|
const event = message.role === "system" ? parseChatContextContent(message.content) : null;
|
|
100901
|
-
|
|
100902
|
-
|
|
100903
|
-
|
|
101283
|
+
const offset = { event, contextIndex: contextIndex2 + (event ? 1 : 0), viewOffset, questionOffset };
|
|
101284
|
+
if (event) contextIndex2++;
|
|
101285
|
+
else {
|
|
101286
|
+
viewOffset += messageResultsViews(message.content).length;
|
|
101287
|
+
if (message.role === "assistant") questionOffset += messageQuestions(message.content).length;
|
|
101288
|
+
}
|
|
101289
|
+
return offset;
|
|
101290
|
+
});
|
|
101291
|
+
const footer = [];
|
|
101292
|
+
if (state.projectFocusPending) footer.push("Project access starts after the countdown. /project-focus-reject to cancel.");
|
|
101293
|
+
if (state.signedIn && state.activeTeamId) footer.push(teamAiReminder());
|
|
101294
|
+
if (state.followUpSuggestions.length) footer.push("", "Suggestions", ...state.followUpSuggestions.slice(0, 3).map((s, i) => ` ${i + 1}. ${s}`));
|
|
101295
|
+
if (state.status) footer.push("", state.status);
|
|
101296
|
+
const wrappedFooter = footer.flatMap((line3) => typeof line3 === "string" ? wrap(line3, width) : [line3]);
|
|
101297
|
+
const blocks = [];
|
|
101298
|
+
let rowCount = wrappedFooter.length;
|
|
101299
|
+
if (state.isAwaitingAi && !state.streamingMessage?.content.trim()) {
|
|
101300
|
+
const mate = messageLabel("assistant", state.streamingMessage?.title, state.streamingMessage?.category, state.activeChat);
|
|
101301
|
+
const waiting = [...renderTuiThinking(mate, width, state.streamingMessage?.modelName), ...renderTuiReasoning(state.streamingMessage, width), renderTuiStreamingGlow(width, state.streamingPhase), ""];
|
|
101302
|
+
blocks.push(waiting);
|
|
101303
|
+
rowCount += waiting.length;
|
|
101304
|
+
}
|
|
101305
|
+
const budget = Math.max(0, state.scrollOffset) + height + 1;
|
|
101306
|
+
for (let index = state.messages.length - 1; index >= 0; index--) {
|
|
101307
|
+
const message = state.messages[index], offset = offsets[index], rows2 = [];
|
|
101308
|
+
if (offset.event) {
|
|
101309
|
+
const event = offset.event;
|
|
101310
|
+
rows2.push(`${chatContextSummary(event)} \xB7 /context ${offset.contextIndex}`);
|
|
100904
101311
|
if (event.type === "project_authoring_recommendation") {
|
|
100905
101312
|
const job = state.chatContextAuthoringJobs[event.event_id];
|
|
100906
|
-
|
|
101313
|
+
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
101314
|
}
|
|
100908
|
-
|
|
100909
|
-
continue;
|
|
101315
|
+
} else {
|
|
101316
|
+
if (message === state.streamingMessage && !message.content.trim()) continue;
|
|
101317
|
+
const questionBlocks = message.role === "assistant";
|
|
101318
|
+
const prepared = cachedChatLayout(
|
|
101319
|
+
state,
|
|
101320
|
+
message,
|
|
101321
|
+
message.content,
|
|
101322
|
+
{ ...cacheContext, variant: questionBlocks ? "questions" : "literal-questions", cacheable: cacheable.has(index) },
|
|
101323
|
+
() => prepareMessageContent(message.content, width, state, questionBlocks)
|
|
101324
|
+
);
|
|
101325
|
+
const label3 = messageLabel(message.role, message.title, message.category, state.activeChat, message.remoteUser);
|
|
101326
|
+
if (state.isAwaitingAi && message === state.streamingMessage) rows2.push(...renderTuiThinking(label3, width, message.modelName, message.thinkingActive ? "Thinking" : tuiResponsePhase(prepared.segments)));
|
|
101327
|
+
else {
|
|
101328
|
+
rows2.push({ text: label3, color: "#5a85eb", bold: true });
|
|
101329
|
+
if (message.role === "assistant" && message.modelName) rows2.push({ text: message.modelName, color: "#808080" });
|
|
101330
|
+
}
|
|
101331
|
+
if (message.role === "assistant") rows2.push(...renderTuiReasoning(message, width));
|
|
101332
|
+
rows2.push(...renderPreparedMessageContent(
|
|
101333
|
+
prepared,
|
|
101334
|
+
width,
|
|
101335
|
+
embeds,
|
|
101336
|
+
state,
|
|
101337
|
+
questionBlocks ? message.embedIds : void 0,
|
|
101338
|
+
offset.viewOffset,
|
|
101339
|
+
offset.questionOffset,
|
|
101340
|
+
defaultEmbedId
|
|
101341
|
+
));
|
|
101342
|
+
if (state.isAwaitingAi && message === state.streamingMessage) rows2.push(renderTuiStreamingGlow(width, state.streamingPhase));
|
|
100910
101343
|
}
|
|
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]);
|
|
101344
|
+
rows2.push("");
|
|
101345
|
+
const wrapped2 = rows2.flatMap((line3) => typeof line3 === "string" ? wrap(line3, width) : [line3]);
|
|
101346
|
+
blocks.push(wrapped2);
|
|
101347
|
+
rowCount += wrapped2.length;
|
|
101348
|
+
if (!fullHistory && !(state.followSelection && state.focus === "content") && rowCount >= budget) break;
|
|
101349
|
+
}
|
|
101350
|
+
return [...renderChatHeader(state, width, height), ...blocks.reverse().flat(), ...wrappedFooter];
|
|
101351
|
+
}
|
|
101352
|
+
function renderTuiReasoning(message, width) {
|
|
101353
|
+
if (!message?.thinkingContent?.trim()) return [];
|
|
101354
|
+
const summary = pointerLine(
|
|
101355
|
+
`\u2726 Thinking for this response ${message.thinkingExpanded ? "\u25BE" : "\u25B8"} /thinking`,
|
|
101356
|
+
{ kind: "command", command: `/thinking${message.id ? " " + message.id : ""}` }
|
|
101357
|
+
);
|
|
101358
|
+
return [summary, ...message.thinkingExpanded ? wrap(message.thinkingContent, width).map((text7) => ({ text: text7, color: "#a0a0a0" })) : []];
|
|
100940
101359
|
}
|
|
100941
101360
|
function teamAiReminder() {
|
|
100942
101361
|
return "To ask AI, mention @openmates or a configured Mate.";
|
|
@@ -100989,17 +101408,13 @@ function relativeTime(timestamp) {
|
|
|
100989
101408
|
function renderStatus(state, width) {
|
|
100990
101409
|
return ["OpenMates", "", state.status ?? "Working..."].flatMap((line3) => wrap(line3, width));
|
|
100991
101410
|
}
|
|
100992
|
-
function prepareMessageContent(content, width, state, questionBlocks = true
|
|
101411
|
+
function prepareMessageContent(content, width, state, questionBlocks = true) {
|
|
100993
101412
|
const segments2 = parseMessageSegments(content, { preserveCodeFences: true }).map((segment) => segment.type === "embed" ? segment : {
|
|
100994
101413
|
type: "text",
|
|
100995
101414
|
value: segment.value,
|
|
100996
101415
|
blocks: parseTuiMarkdown(segment.value, width, { resolveEmbedAlias: (id) => state ? aliasForEmbed(state, id) : id, questionBlocks })
|
|
100997
101416
|
});
|
|
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
|
-
};
|
|
101417
|
+
return { segments: segments2 };
|
|
101003
101418
|
}
|
|
101004
101419
|
function renderMessageContentStyled(content, width, embeds = /* @__PURE__ */ new Map(), state, extraIds = [], viewOffset = 0, questionOffset = 0, questionBlocks = true) {
|
|
101005
101420
|
return renderPreparedMessageContent(
|
|
@@ -101431,6 +101846,7 @@ function rememberDraft(state) {
|
|
|
101431
101846
|
if (state.workspace === "chats" && !state.input.startsWith("/")) state.drafts[chatDraftKey(state)] = state.input;
|
|
101432
101847
|
}
|
|
101433
101848
|
function route(state, workspace, screen) {
|
|
101849
|
+
clearTuiSendState(state);
|
|
101434
101850
|
if (state.settings) closeTuiSettings(state);
|
|
101435
101851
|
if (state.input) rememberDraft(state);
|
|
101436
101852
|
state.workspace = workspace;
|
|
@@ -101902,6 +102318,18 @@ async function handleWorkspaceCommand(context, command) {
|
|
|
101902
102318
|
}
|
|
101903
102319
|
return true;
|
|
101904
102320
|
}
|
|
102321
|
+
case "/thinking": {
|
|
102322
|
+
const messages = [...state.messages, ...state.streamingMessage && !state.messages.includes(state.streamingMessage) ? [state.streamingMessage] : []];
|
|
102323
|
+
const message = arg ? messages.find((message2) => message2.id === arg) : messages.findLast((message2) => message2.role === "assistant" && message2.thinkingContent?.trim());
|
|
102324
|
+
if (state.input.trim() === command) {
|
|
102325
|
+
state.input = "";
|
|
102326
|
+
state.inputCursor = null;
|
|
102327
|
+
}
|
|
102328
|
+
if (message?.thinkingContent?.trim()) message.thinkingExpanded = !message.thinkingExpanded;
|
|
102329
|
+
else state.status = "No visible thinking is available for this response.";
|
|
102330
|
+
render();
|
|
102331
|
+
return true;
|
|
102332
|
+
}
|
|
101905
102333
|
case "/browse":
|
|
101906
102334
|
state.homeShowAll = !state.homeShowAll;
|
|
101907
102335
|
state.selectedIndex = 0;
|
|
@@ -103384,21 +103812,21 @@ function string4(value) {
|
|
|
103384
103812
|
function ownerToken(session, teamId) {
|
|
103385
103813
|
return createHmac4("sha256", Buffer.from(session.masterKeyExportedB64, "base64")).update(JSON.stringify([session.apiUrl, session.hashedEmail, teamId, session.createdAt])).digest("hex");
|
|
103386
103814
|
}
|
|
103387
|
-
function keyFor(
|
|
103388
|
-
return createHmac4("sha256", Buffer.from(
|
|
103815
|
+
function keyFor(owner2, chatId) {
|
|
103816
|
+
return createHmac4("sha256", Buffer.from(owner2, "hex")).update(chatId).digest("hex");
|
|
103389
103817
|
}
|
|
103390
103818
|
function isRecord5(value) {
|
|
103391
103819
|
const v = object4(value);
|
|
103392
103820
|
return typeof v.ciphertext === "string" && v.ciphertext.length > 0 && Number.isSafeInteger(v.version) && v.version >= 0 && typeof v.pending === "boolean";
|
|
103393
103821
|
}
|
|
103394
|
-
function readLocal(
|
|
103822
|
+
function readLocal(owner2, chatId) {
|
|
103395
103823
|
try {
|
|
103396
103824
|
const path2 = join19(resolveStateDir(), FILE);
|
|
103397
103825
|
const raw = readFileSync17(path2, "utf8");
|
|
103398
103826
|
if (Buffer.byteLength(raw) > MAX_FILE_BYTES3) return null;
|
|
103399
103827
|
const envelope = object4(JSON.parse(raw));
|
|
103400
103828
|
if (envelope.version !== 2) return null;
|
|
103401
|
-
const record10 = object4(object4(envelope.owners)[
|
|
103829
|
+
const record10 = object4(object4(envelope.owners)[owner2])[keyFor(owner2, chatId)];
|
|
103402
103830
|
return isRecord5(record10) ? record10 : null;
|
|
103403
103831
|
} catch {
|
|
103404
103832
|
return null;
|
|
@@ -103407,7 +103835,7 @@ function readLocal(owner, chatId) {
|
|
|
103407
103835
|
function sameRecord(left, right) {
|
|
103408
103836
|
return left === right || !!left && !!right && left.ciphertext === right.ciphertext && left.version === right.version && left.pending === right.pending;
|
|
103409
103837
|
}
|
|
103410
|
-
async function writeLocal(
|
|
103838
|
+
async function writeLocal(owner2, chatId, record10, current2, expected) {
|
|
103411
103839
|
if (!current2()) throw new Error("Chat model preference owner changed.");
|
|
103412
103840
|
const dir = resolveStateDir();
|
|
103413
103841
|
mkdirSync16(dir, { recursive: true, mode: 448 });
|
|
@@ -103432,11 +103860,11 @@ async function writeLocal(owner, chatId, record10, current2, expected) {
|
|
|
103432
103860
|
}
|
|
103433
103861
|
} catch {
|
|
103434
103862
|
}
|
|
103435
|
-
const chats = owners[
|
|
103436
|
-
const existing = chats[keyFor(
|
|
103863
|
+
const chats = owners[owner2] ?? {};
|
|
103864
|
+
const existing = chats[keyFor(owner2, chatId)] ?? null;
|
|
103437
103865
|
if (expected !== void 0 && !sameRecord(existing, expected)) return existing;
|
|
103438
|
-
chats[keyFor(
|
|
103439
|
-
owners[
|
|
103866
|
+
chats[keyFor(owner2, chatId)] = record10;
|
|
103867
|
+
owners[owner2] = chats;
|
|
103440
103868
|
if (Object.values(owners).reduce((sum, values) => sum + Object.keys(values).length, 0) > MAX_CHATS)
|
|
103441
103869
|
throw new Error("Chat model preference cache is full.");
|
|
103442
103870
|
const encoded = JSON.stringify({ version: 2, owners });
|
|
@@ -103515,21 +103943,21 @@ function createChatModelPreferences(client2) {
|
|
|
103515
103943
|
if (!client2.hasSession()) throw new Error("Sign in to choose a chat model.");
|
|
103516
103944
|
const session = client2.getSession();
|
|
103517
103945
|
const teamId = client2.resolveTeamContext();
|
|
103518
|
-
const
|
|
103946
|
+
const owner2 = ownerToken(session, teamId);
|
|
103519
103947
|
const persisted = loadSession();
|
|
103520
|
-
if (persisted && ownerToken(persisted, teamId) !==
|
|
103948
|
+
if (persisted && ownerToken(persisted, teamId) !== owner2)
|
|
103521
103949
|
throw new Error("Chat model preference owner changed.");
|
|
103522
103950
|
const current2 = () => {
|
|
103523
103951
|
try {
|
|
103524
|
-
if (!client2.hasSession() || ownerToken(client2.getSession(), client2.resolveTeamContext()) !==
|
|
103952
|
+
if (!client2.hasSession() || ownerToken(client2.getSession(), client2.resolveTeamContext()) !== owner2) return false;
|
|
103525
103953
|
if (!persisted) return true;
|
|
103526
103954
|
const onDisk = loadSession();
|
|
103527
|
-
return !!onDisk && ownerToken(onDisk, teamId) ===
|
|
103955
|
+
return !!onDisk && ownerToken(onDisk, teamId) === owner2;
|
|
103528
103956
|
} catch {
|
|
103529
103957
|
return false;
|
|
103530
103958
|
}
|
|
103531
103959
|
};
|
|
103532
|
-
return { owner, teamId, current: current2, masterKey: Buffer.from(session.masterKeyExportedB64, "base64") };
|
|
103960
|
+
return { owner: owner2, teamId, current: current2, masterKey: Buffer.from(session.masterKeyExportedB64, "base64") };
|
|
103533
103961
|
};
|
|
103534
103962
|
const checked = (current2) => {
|
|
103535
103963
|
if (!current2()) throw new Error("Chat model preference owner changed.");
|
|
@@ -103539,10 +103967,10 @@ function createChatModelPreferences(client2) {
|
|
|
103539
103967
|
if (plaintext === null) throw new Error("Chat model preference could not be decrypted.");
|
|
103540
103968
|
return parseSelection(plaintext);
|
|
103541
103969
|
};
|
|
103542
|
-
const stateKey = (
|
|
103543
|
-
const publish = (
|
|
103970
|
+
const stateKey = (owner2, chatId) => `${owner2}:${chatId}`;
|
|
103971
|
+
const publish = (owner2, chatId, state, current2) => {
|
|
103544
103972
|
checked(current2);
|
|
103545
|
-
const key = stateKey(
|
|
103973
|
+
const key = stateKey(owner2, chatId);
|
|
103546
103974
|
states2.set(key, state);
|
|
103547
103975
|
for (const listener of listeners.get(key) ?? []) {
|
|
103548
103976
|
try {
|
|
@@ -103552,18 +103980,18 @@ function createChatModelPreferences(client2) {
|
|
|
103552
103980
|
}
|
|
103553
103981
|
return state;
|
|
103554
103982
|
};
|
|
103555
|
-
const withChat = (
|
|
103556
|
-
const key = stateKey(
|
|
103983
|
+
const withChat = (owner2, chatId, work) => {
|
|
103984
|
+
const key = stateKey(owner2, chatId);
|
|
103557
103985
|
const task = (serial.get(key) ?? Promise.resolve()).then(work);
|
|
103558
103986
|
serial.set(key, task.catch(() => {
|
|
103559
103987
|
}));
|
|
103560
103988
|
return task;
|
|
103561
103989
|
};
|
|
103562
103990
|
const flush = async (chatId, context = capture()) => {
|
|
103563
|
-
const { owner, teamId, current: current2, masterKey } = context;
|
|
103991
|
+
const { owner: owner2, teamId, current: current2, masterKey } = context;
|
|
103564
103992
|
checked(current2);
|
|
103565
|
-
const local = readLocal(
|
|
103566
|
-
if (!local?.pending) return states2.get(stateKey(
|
|
103993
|
+
const local = readLocal(owner2, chatId);
|
|
103994
|
+
if (!local?.pending) return states2.get(stateKey(owner2, chatId)) ?? { selection: "auto", pending: false, restored: false };
|
|
103567
103995
|
const selection = await decrypt(local, masterKey);
|
|
103568
103996
|
try {
|
|
103569
103997
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
@@ -103573,15 +104001,15 @@ function createChatModelPreferences(client2) {
|
|
|
103573
104001
|
const accepted = await client2.compareAndSetChatModelPreference(chatId, local.ciphertext, expected, teamId);
|
|
103574
104002
|
checked(current2);
|
|
103575
104003
|
if (!accepted) continue;
|
|
103576
|
-
await writeLocal(
|
|
104004
|
+
await writeLocal(owner2, chatId, { ...accepted, pending: false }, current2);
|
|
103577
104005
|
const state = { selection, pending: false, restored: true };
|
|
103578
|
-
return publish(
|
|
104006
|
+
return publish(owner2, chatId, state, current2);
|
|
103579
104007
|
}
|
|
103580
104008
|
throw new Error("Chat model preference conflicted repeatedly.");
|
|
103581
104009
|
} catch {
|
|
103582
104010
|
checked(current2);
|
|
103583
104011
|
const state = { selection, pending: true, restored: true };
|
|
103584
|
-
return publish(
|
|
104012
|
+
return publish(owner2, chatId, state, current2);
|
|
103585
104013
|
}
|
|
103586
104014
|
};
|
|
103587
104015
|
return {
|
|
@@ -103604,32 +104032,32 @@ function createChatModelPreferences(client2) {
|
|
|
103604
104032
|
},
|
|
103605
104033
|
async restore(chatId) {
|
|
103606
104034
|
const context = capture();
|
|
103607
|
-
const { owner, current: current2, masterKey } = context;
|
|
104035
|
+
const { owner: owner2, current: current2, masterKey } = context;
|
|
103608
104036
|
checked(current2);
|
|
103609
|
-
const local = readLocal(
|
|
104037
|
+
const local = readLocal(owner2, chatId);
|
|
103610
104038
|
if (local) {
|
|
103611
104039
|
const selection = await decrypt(local, masterKey);
|
|
103612
104040
|
checked(current2);
|
|
103613
|
-
const initial = publish(
|
|
103614
|
-
void withChat(
|
|
104041
|
+
const initial = publish(owner2, chatId, { selection, pending: local.pending, restored: true }, current2);
|
|
104042
|
+
void withChat(owner2, chatId, async () => {
|
|
103615
104043
|
if (local.pending) return flush(chatId, context);
|
|
103616
104044
|
return refreshRemote(chatId, context, local);
|
|
103617
104045
|
}).catch(() => {
|
|
103618
104046
|
});
|
|
103619
104047
|
return initial;
|
|
103620
104048
|
}
|
|
103621
|
-
return withChat(
|
|
104049
|
+
return withChat(owner2, chatId, () => refreshRemote(chatId, context, null));
|
|
103622
104050
|
},
|
|
103623
104051
|
async select(chatId, selection) {
|
|
103624
104052
|
const context = capture();
|
|
103625
104053
|
return withChat(context.owner, chatId, async () => {
|
|
103626
|
-
const { owner, current: current2, masterKey } = context;
|
|
104054
|
+
const { owner: owner2, current: current2, masterKey } = context;
|
|
103627
104055
|
const serialized = encodeSelection(selection);
|
|
103628
104056
|
const ciphertext = await encryptWithAesGcmCombined(serialized, masterKey);
|
|
103629
104057
|
checked(current2);
|
|
103630
|
-
const previous = readLocal(
|
|
103631
|
-
await writeLocal(
|
|
103632
|
-
publish(
|
|
104058
|
+
const previous = readLocal(owner2, chatId);
|
|
104059
|
+
await writeLocal(owner2, chatId, { ciphertext, version: previous?.version ?? 0, pending: true }, current2);
|
|
104060
|
+
publish(owner2, chatId, { selection, pending: true, restored: true }, current2);
|
|
103633
104061
|
return flush(chatId, context);
|
|
103634
104062
|
});
|
|
103635
104063
|
},
|
|
@@ -103662,7 +104090,7 @@ function createChatModelPreferences(client2) {
|
|
|
103662
104090
|
}
|
|
103663
104091
|
};
|
|
103664
104092
|
async function refreshRemote(chatId, context, local) {
|
|
103665
|
-
const { owner, teamId, current: current2, masterKey } = context;
|
|
104093
|
+
const { owner: owner2, teamId, current: current2, masterKey } = context;
|
|
103666
104094
|
checked(current2);
|
|
103667
104095
|
let remote = null;
|
|
103668
104096
|
let confirmed = false;
|
|
@@ -103673,7 +104101,7 @@ function createChatModelPreferences(client2) {
|
|
|
103673
104101
|
checked(current2);
|
|
103674
104102
|
if (!local) {
|
|
103675
104103
|
const state2 = { selection: "auto", pending: false, restored: false };
|
|
103676
|
-
return publish(
|
|
104104
|
+
return publish(owner2, chatId, state2, current2);
|
|
103677
104105
|
}
|
|
103678
104106
|
}
|
|
103679
104107
|
checked(current2);
|
|
@@ -103681,21 +104109,21 @@ function createChatModelPreferences(client2) {
|
|
|
103681
104109
|
const ciphertext = await encryptWithAesGcmCombined(encodeSelection("auto"), masterKey);
|
|
103682
104110
|
checked(current2);
|
|
103683
104111
|
const autoRecord = { ciphertext, version: 0, pending: false };
|
|
103684
|
-
const stored = await writeLocal(
|
|
104112
|
+
const stored = await writeLocal(owner2, chatId, autoRecord, current2, local);
|
|
103685
104113
|
checked(current2);
|
|
103686
|
-
if (!stored) return publish(
|
|
104114
|
+
if (!stored) return publish(owner2, chatId, { selection: "auto", pending: false, restored: false }, current2);
|
|
103687
104115
|
if (stored !== autoRecord) {
|
|
103688
104116
|
const selection2 = await decrypt(stored, masterKey);
|
|
103689
|
-
return publish(
|
|
104117
|
+
return publish(owner2, chatId, { selection: selection2, pending: stored.pending, restored: true }, current2);
|
|
103690
104118
|
}
|
|
103691
|
-
return publish(
|
|
104119
|
+
return publish(owner2, chatId, { selection: "auto", pending: false, restored: true }, current2);
|
|
103692
104120
|
}
|
|
103693
104121
|
const chosen = remote && (!local || remote.version > local.version) ? remote : local;
|
|
103694
104122
|
const selection = chosen ? await decrypt(chosen, masterKey) : "auto";
|
|
103695
104123
|
checked(current2);
|
|
103696
|
-
if (remote && chosen === remote) await writeLocal(
|
|
104124
|
+
if (remote && chosen === remote) await writeLocal(owner2, chatId, { ...remote, pending: false }, current2);
|
|
103697
104125
|
const state = { selection, pending: false, restored: true };
|
|
103698
|
-
return publish(
|
|
104126
|
+
return publish(owner2, chatId, state, current2);
|
|
103699
104127
|
}
|
|
103700
104128
|
}
|
|
103701
104129
|
|
|
@@ -103713,6 +104141,7 @@ async function runTui(client2, terminal = new TuiTerminal(), startupServices) {
|
|
|
103713
104141
|
hydrateExamples(state);
|
|
103714
104142
|
let resolveResult = null;
|
|
103715
104143
|
let renderTimer = null;
|
|
104144
|
+
let lastFrameOwner = null;
|
|
103716
104145
|
let closed = false;
|
|
103717
104146
|
let stopActivity;
|
|
103718
104147
|
let activityTimer;
|
|
@@ -103745,9 +104174,25 @@ async function runTui(client2, terminal = new TuiTerminal(), startupServices) {
|
|
|
103745
104174
|
void refreshActivity();
|
|
103746
104175
|
}, 3e4);
|
|
103747
104176
|
const activityAnimation = setInterval(() => {
|
|
103748
|
-
if (
|
|
103749
|
-
|
|
104177
|
+
if (closed) return;
|
|
104178
|
+
const sidebarActivity = state.runningChatIds.length > 0;
|
|
104179
|
+
if (sidebarActivity) state.activityFrame = (state.activityFrame + 1) % 4;
|
|
104180
|
+
const streaming = state.screen === "chat" && state.isAwaitingAi && state.streamingMessage && !state.textSelection && !terminal.reducedMotion && !terminal.isOutputBlocked && lastFrameOwner?.();
|
|
104181
|
+
if (streaming) {
|
|
104182
|
+
state.streamingPhase = (state.streamingPhase + 1) % 12;
|
|
104183
|
+
}
|
|
104184
|
+
if (sidebarActivity) {
|
|
103750
104185
|
render();
|
|
104186
|
+
return;
|
|
104187
|
+
}
|
|
104188
|
+
if (streaming && !renderTimer) {
|
|
104189
|
+
const frame = renderTuiStreamingAnimationFrame(
|
|
104190
|
+
state,
|
|
104191
|
+
terminal.width,
|
|
104192
|
+
terminal.height,
|
|
104193
|
+
{ colorMode: terminal.colorMode, ascii: terminal.ascii, reducedMotion: terminal.reducedMotion }
|
|
104194
|
+
);
|
|
104195
|
+
if (frame) terminal.render(frame, tuiComposerCursor(state, terminal.width, terminal.height), state.textSelection);
|
|
103751
104196
|
}
|
|
103752
104197
|
}, 250);
|
|
103753
104198
|
const syncSessionView = () => {
|
|
@@ -103825,7 +104270,8 @@ async function runTui(client2, terminal = new TuiTerminal(), startupServices) {
|
|
|
103825
104270
|
renderTimer = null;
|
|
103826
104271
|
if (closed) return;
|
|
103827
104272
|
syncSessionView();
|
|
103828
|
-
|
|
104273
|
+
lastFrameOwner = client2.hasSession() ? captureTuiWorkspaceOwner(client2) : () => !client2.hasSession();
|
|
104274
|
+
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
104275
|
}, 16);
|
|
103830
104276
|
};
|
|
103831
104277
|
teamChatRefresh = createTuiTeamChatRefresh(state, client2, render);
|
|
@@ -104094,7 +104540,7 @@ async function handleEnter(params) {
|
|
|
104094
104540
|
}
|
|
104095
104541
|
async function handleCommand(params) {
|
|
104096
104542
|
const { command, state, client: client2, terminal, render, finish, modelShell } = params;
|
|
104097
|
-
client2.clearInteractiveChatViewer();
|
|
104543
|
+
if (command.split(/\s+/, 1)[0] !== "/thinking") client2.clearInteractiveChatViewer();
|
|
104098
104544
|
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
104545
|
const [name, ...parts] = command.split(/\s+/);
|
|
104100
104546
|
const arg = parts.join(" ");
|
|
@@ -104254,17 +104700,66 @@ async function handleCommand(params) {
|
|
|
104254
104700
|
async function sendTuiMessage(params) {
|
|
104255
104701
|
const { state, client: client2, render } = params;
|
|
104256
104702
|
if (state.isBusy) return;
|
|
104703
|
+
const initialMessage = params.message.trim();
|
|
104704
|
+
if (!initialMessage) return;
|
|
104257
104705
|
const preparingOwner = client2.hasSession() ? captureTuiWorkspaceOwner(client2) : () => !client2.hasSession();
|
|
104258
104706
|
const preparingRoute = state.routeVersion;
|
|
104259
|
-
const
|
|
104707
|
+
const previousMessages = state.messages;
|
|
104260
104708
|
const preparingChatId = state.activeChatId;
|
|
104261
|
-
const
|
|
104262
|
-
const
|
|
104263
|
-
|
|
104709
|
+
const previousActiveChat = state.activeChat, previousHeaderState = state.headerState;
|
|
104710
|
+
const previousScreen = state.screen;
|
|
104711
|
+
const sourceExample = previousScreen === "example" ? state.activeExample : null;
|
|
104712
|
+
const history = sourceExample ? buildExampleContinuationHistory(sourceExample) : void 0;
|
|
104713
|
+
const draftKey = sourceExample ? `example:${sourceExample.chat.id}` : preparingChatId ?? "new";
|
|
104714
|
+
const draftBeforeSend = state.drafts[draftKey];
|
|
104715
|
+
if (sourceExample) state.messages = sourceExample.messages.map((m) => ({ role: m.role === "user" ? "user" : "assistant", content: m.content, title: m.senderName }));
|
|
104716
|
+
const messages = state.messages;
|
|
104717
|
+
const userMessage = { id: randomUUID21(), role: "user", content: initialMessage };
|
|
104718
|
+
messages.push(userMessage);
|
|
104719
|
+
state.screen = "chat";
|
|
104720
|
+
state.isBusy = true;
|
|
104721
|
+
state.drafts[draftKey] = "";
|
|
104722
|
+
state.input = "";
|
|
104723
|
+
state.inputCursor = null;
|
|
104724
|
+
state.status = "Preparing message\u2026";
|
|
104725
|
+
render();
|
|
104726
|
+
const ownsPreparation = () => preparingOwner() && state.routeVersion === preparingRoute && state.messages === messages && state.activeChatId === preparingChatId;
|
|
104727
|
+
const restorePreparation = (status) => {
|
|
104728
|
+
if (!ownsPreparation()) return;
|
|
104729
|
+
const index = messages.indexOf(userMessage);
|
|
104730
|
+
if (index >= 0) messages.splice(index, 1);
|
|
104731
|
+
state.messages = previousMessages;
|
|
104732
|
+
state.screen = previousScreen;
|
|
104733
|
+
state.isBusy = false;
|
|
104734
|
+
if (state.input === "" && state.drafts[draftKey] === "") {
|
|
104735
|
+
state.input = initialMessage;
|
|
104736
|
+
state.inputCursor = null;
|
|
104737
|
+
if (draftBeforeSend === void 0) delete state.drafts[draftKey];
|
|
104738
|
+
rememberDraft(state);
|
|
104739
|
+
}
|
|
104740
|
+
if (client2.getActiveTeamId?.()) reconcileTuiTeamSenderLabels(state);
|
|
104741
|
+
state.status = status;
|
|
104742
|
+
render();
|
|
104743
|
+
};
|
|
104744
|
+
let resolved;
|
|
104745
|
+
try {
|
|
104746
|
+
resolved = !params.questionAnswer && params.modelShell ? await params.modelShell.consumeMention(params.message, true) : { message: params.message, blocked: false };
|
|
104747
|
+
} catch (error) {
|
|
104748
|
+
restorePreparation(error instanceof Error ? error.message : String(error));
|
|
104749
|
+
return;
|
|
104750
|
+
}
|
|
104751
|
+
if (!ownsPreparation()) return;
|
|
104752
|
+
if (resolved.blocked) {
|
|
104753
|
+
restorePreparation(null);
|
|
104754
|
+
return;
|
|
104755
|
+
}
|
|
104264
104756
|
const message = resolved.message.trim();
|
|
104265
|
-
if (!message)
|
|
104757
|
+
if (!message) {
|
|
104758
|
+
restorePreparation(null);
|
|
104759
|
+
return;
|
|
104760
|
+
}
|
|
104761
|
+
userMessage.content = message;
|
|
104266
104762
|
client2.clearInteractiveChatViewer();
|
|
104267
|
-
state.isBusy = true;
|
|
104268
104763
|
state.status = "Preparing message\u2026";
|
|
104269
104764
|
render();
|
|
104270
104765
|
if (!ownsPreparation()) return;
|
|
@@ -104272,15 +104767,7 @@ async function sendTuiMessage(params) {
|
|
|
104272
104767
|
try {
|
|
104273
104768
|
prepared = params.questionAnswer ? { message, preparedEmbeds: [], displayNames: [] } : await prepareTuiMessage(client2, message);
|
|
104274
104769
|
} 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
|
-
}
|
|
104770
|
+
restorePreparation(error instanceof Error ? error.message : String(error));
|
|
104284
104771
|
return;
|
|
104285
104772
|
}
|
|
104286
104773
|
if (!ownsPreparation()) return;
|
|
@@ -104288,34 +104775,16 @@ async function sendTuiMessage(params) {
|
|
|
104288
104775
|
const waitForAi = !client2.hasSession() || shouldWaitForTeamAi(prepared.message, sendTeamId);
|
|
104289
104776
|
const modelSelection = waitForAi && !params.questionAnswer && isTuiAiComposer(state) && client2.hasSession() ? params.modelShell?.selectionForSend() ?? null : "auto";
|
|
104290
104777
|
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
|
-
}
|
|
104778
|
+
restorePreparation("Model selection is loading. Retry or choose Auto before sending.");
|
|
104300
104779
|
return;
|
|
104301
104780
|
}
|
|
104302
104781
|
const separator = modelSelection.indexOf("/");
|
|
104303
104782
|
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
104783
|
const existingChatId = sourceExample ? null : state.activeChatId;
|
|
104311
104784
|
const chatId = existingChatId ?? randomUUID21();
|
|
104312
104785
|
let ownedMessages = messages, ownedChatId = chatId;
|
|
104313
104786
|
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) }));
|
|
104787
|
+
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
104788
|
state.activeChatId = chatId;
|
|
104320
104789
|
state.headerState = existingChatId ? "ready" : "loading";
|
|
104321
104790
|
state.headerError = null;
|
|
@@ -104324,8 +104793,8 @@ async function sendTuiMessage(params) {
|
|
|
104324
104793
|
state.screen = "chat";
|
|
104325
104794
|
state.aiTaskId = null;
|
|
104326
104795
|
state.status = prepared.displayNames.length ? `Attached: ${prepared.displayNames.join(", ")}` : null;
|
|
104327
|
-
|
|
104328
|
-
|
|
104796
|
+
userMessage.content = prepared.message;
|
|
104797
|
+
userMessage.embedIds = prepared.preparedEmbeds.map((embed) => embed.embedId);
|
|
104329
104798
|
const privacyCallbacks = {
|
|
104330
104799
|
onPrivacyPrepared: (safe2) => {
|
|
104331
104800
|
if (ownsSend()) {
|
|
@@ -104340,11 +104809,18 @@ async function sendTuiMessage(params) {
|
|
|
104340
104809
|
}
|
|
104341
104810
|
}
|
|
104342
104811
|
};
|
|
104343
|
-
const assistantMessage = waitForAi ? { role: "assistant", content: "", title: "Assistant" } : null;
|
|
104344
|
-
|
|
104812
|
+
const assistantMessage = waitForAi ? { id: randomUUID21(), role: "assistant", content: "", title: "Assistant" } : null;
|
|
104813
|
+
state.streamingMessage = assistantMessage;
|
|
104814
|
+
if (assistantMessage) state.streamingPhase = 0;
|
|
104345
104815
|
state.isAwaitingAi = waitForAi;
|
|
104816
|
+
const showAssistant = (content) => {
|
|
104817
|
+
if (!assistantMessage || !ownsSend() || !content) return;
|
|
104818
|
+
assistantMessage.content = content;
|
|
104819
|
+
if (!messages.includes(assistantMessage)) messages.push(assistantMessage);
|
|
104820
|
+
};
|
|
104346
104821
|
render();
|
|
104347
104822
|
let questionSendError = null;
|
|
104823
|
+
let accepted = false;
|
|
104348
104824
|
try {
|
|
104349
104825
|
if (!client2.hasSession()) {
|
|
104350
104826
|
const result = await client2.sendAnonymousMessage({
|
|
@@ -104352,7 +104828,8 @@ async function sendTuiMessage(params) {
|
|
|
104352
104828
|
...privacyCallbacks,
|
|
104353
104829
|
messageHistory: anonymousHistory
|
|
104354
104830
|
});
|
|
104355
|
-
|
|
104831
|
+
accepted = true;
|
|
104832
|
+
showAssistant(result.assistant);
|
|
104356
104833
|
if (ownsSend()) {
|
|
104357
104834
|
ownedChatId = result.chatId;
|
|
104358
104835
|
state.activeChatId = result.chatId;
|
|
@@ -104385,22 +104862,42 @@ async function sendTuiMessage(params) {
|
|
|
104385
104862
|
onStream: (event) => {
|
|
104386
104863
|
if (!ownsSend()) return;
|
|
104387
104864
|
if (event.taskId) state.aiTaskId = event.taskId;
|
|
104865
|
+
if (assistantMessage && event.thinkingContent !== void 0) assistantMessage.thinkingContent = event.thinkingContent;
|
|
104866
|
+
if (assistantMessage && event.thinkingActive !== void 0) assistantMessage.thinkingActive = event.thinkingActive;
|
|
104867
|
+
if (assistantMessage && event.modelName) assistantMessage.modelName = event.modelName;
|
|
104868
|
+
if (assistantMessage && event.category) {
|
|
104869
|
+
state.activeChat = {
|
|
104870
|
+
id: chatId,
|
|
104871
|
+
shortId: chatId.slice(0, 8),
|
|
104872
|
+
title: state.activeChat?.title ?? null,
|
|
104873
|
+
summary: state.activeChat?.summary ?? null,
|
|
104874
|
+
updatedAt: null,
|
|
104875
|
+
createdAt: state.activeChat?.createdAt ?? Math.floor(Date.now() / 1e3),
|
|
104876
|
+
category: event.category,
|
|
104877
|
+
mateName: null
|
|
104878
|
+
};
|
|
104879
|
+
}
|
|
104388
104880
|
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();
|
|
104881
|
+
showAssistant(event.content);
|
|
104392
104882
|
}
|
|
104883
|
+
render();
|
|
104393
104884
|
}
|
|
104394
104885
|
});
|
|
104395
|
-
|
|
104886
|
+
accepted = true;
|
|
104887
|
+
showAssistant(result.assistant);
|
|
104396
104888
|
if (ownsSend()) {
|
|
104397
104889
|
ownedChatId = result.chatId;
|
|
104398
104890
|
state.activeChatId = result.chatId;
|
|
104399
104891
|
state.followUpSuggestions = result.followUpSuggestions ?? [];
|
|
104400
104892
|
if (result.userMessageId) userMessage.id = result.userMessageId;
|
|
104401
|
-
if (!existingChatId
|
|
104402
|
-
|
|
104403
|
-
|
|
104893
|
+
if (!existingChatId && params.modelShell) {
|
|
104894
|
+
void Promise.resolve().then(() => ownsSend() ? params.modelShell?.persistCreatedChat(result.chatId, modelSelection) : void 0).catch(() => {
|
|
104895
|
+
});
|
|
104896
|
+
}
|
|
104897
|
+
if (state.screen === "chat" && typeof client2.setInteractiveChatViewer === "function") {
|
|
104898
|
+
void Promise.resolve().then(() => ownsSend() && state.screen === "chat" ? client2.setInteractiveChatViewer(result.chatId) : void 0).catch(() => {
|
|
104899
|
+
});
|
|
104900
|
+
}
|
|
104404
104901
|
if (result.mateName && assistantMessage) assistantMessage.title = result.mateName;
|
|
104405
104902
|
if (typeof client2.getChatMetadata === "function") {
|
|
104406
104903
|
const completedLength = messages.length;
|
|
@@ -104425,13 +104922,14 @@ async function sendTuiMessage(params) {
|
|
|
104425
104922
|
state.headerState = "ready";
|
|
104426
104923
|
}
|
|
104427
104924
|
} catch (error) {
|
|
104925
|
+
if (accepted) return;
|
|
104428
104926
|
if (params.questionAnswer) {
|
|
104429
104927
|
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
104928
|
if (ownsSend()) {
|
|
104929
|
+
for (const optimistic of [userMessage, assistantMessage].filter((item) => item !== null)) {
|
|
104930
|
+
const index = messages.indexOf(optimistic);
|
|
104931
|
+
if (index >= 0) messages.splice(index, 1);
|
|
104932
|
+
}
|
|
104435
104933
|
state.messages = previousMessages;
|
|
104436
104934
|
state.activeChatId = existingChatId;
|
|
104437
104935
|
state.activeChat = previousActiveChat;
|
|
@@ -104441,14 +104939,14 @@ async function sendTuiMessage(params) {
|
|
|
104441
104939
|
state.screen = sourceExample ? "example" : "chat";
|
|
104442
104940
|
state.status = null;
|
|
104443
104941
|
}
|
|
104444
|
-
} else if (assistantMessage) {
|
|
104942
|
+
} else if (assistantMessage && ownsSend()) {
|
|
104445
104943
|
assistantMessage.title = "Error";
|
|
104446
|
-
|
|
104447
|
-
|
|
104448
|
-
|
|
104449
|
-
state.headerError = /credit/i.test(assistantMessage.content) ? "Not enough credits" : assistantMessage.content;
|
|
104450
|
-
}
|
|
104944
|
+
showAssistant(error instanceof Error ? error.message : String(error));
|
|
104945
|
+
state.headerState = "error";
|
|
104946
|
+
state.headerError = /credit/i.test(assistantMessage.content) ? "Not enough credits" : assistantMessage.content;
|
|
104451
104947
|
} else if (ownsSend()) {
|
|
104948
|
+
const index = messages.indexOf(userMessage);
|
|
104949
|
+
if (index >= 0) messages.splice(index, 1);
|
|
104452
104950
|
state.messages = previousMessages;
|
|
104453
104951
|
state.activeChatId = existingChatId;
|
|
104454
104952
|
state.activeChat = previousActiveChat;
|
|
@@ -104456,9 +104954,11 @@ async function sendTuiMessage(params) {
|
|
|
104456
104954
|
ownedChatId = existingChatId;
|
|
104457
104955
|
state.headerState = previousHeaderState;
|
|
104458
104956
|
state.screen = previousScreen;
|
|
104459
|
-
state.input
|
|
104460
|
-
|
|
104461
|
-
|
|
104957
|
+
if (state.input === "" && state.drafts[draftKey] === "") {
|
|
104958
|
+
state.input = message;
|
|
104959
|
+
state.inputCursor = null;
|
|
104960
|
+
rememberDraft(state);
|
|
104961
|
+
}
|
|
104462
104962
|
state.status = error instanceof Error ? error.message : String(error);
|
|
104463
104963
|
}
|
|
104464
104964
|
} finally {
|
|
@@ -104466,6 +104966,7 @@ async function sendTuiMessage(params) {
|
|
|
104466
104966
|
state.isBusy = false;
|
|
104467
104967
|
if (sendTeamId) reconcileTuiTeamSenderLabels(state);
|
|
104468
104968
|
state.isAwaitingAi = false;
|
|
104969
|
+
state.streamingMessage = null;
|
|
104469
104970
|
state.projectFocusPending = null;
|
|
104470
104971
|
state.aiTaskId = null;
|
|
104471
104972
|
registerChatEmbedAliases(state);
|
|
@@ -105011,7 +105512,7 @@ async function flushTaskCommands(client2, teamId, root = resolveStateDir(), onNo
|
|
|
105011
105512
|
await taskMutationStore(scope2, root).deliver(command.id, async () => {
|
|
105012
105513
|
if (operation.kind === "create") {
|
|
105013
105514
|
const linked = operation.link_to_chat !== false;
|
|
105014
|
-
const
|
|
105515
|
+
const owner2 = linked ? await readCodexThread(command.thread) : void 0;
|
|
105015
105516
|
const input = await buildCreateUserTaskInput(master, {
|
|
105016
105517
|
taskId: command.task_id,
|
|
105017
105518
|
title: operation.title ?? "",
|
|
@@ -105019,7 +105520,7 @@ async function flushTaskCommands(client2, teamId, root = resolveStateDir(), onNo
|
|
|
105019
105520
|
projectIds: [command.project_id],
|
|
105020
105521
|
status: operation.status,
|
|
105021
105522
|
assign: linked ? "codex" : "user",
|
|
105022
|
-
externalChat:
|
|
105523
|
+
externalChat: owner2 ? { provider: "codex", id: owner2.id, title: owner2.title } : void 0
|
|
105023
105524
|
});
|
|
105024
105525
|
return { kind: "create", taskId: command.task_id, input, creator: linked ? "codex" : void 0 };
|
|
105025
105526
|
}
|
|
@@ -111238,8 +111739,8 @@ async function handleTasks(client2, subcommand, rest, flags, redactor) {
|
|
|
111238
111739
|
}
|
|
111239
111740
|
if (process.env.CODEX_THREAD_ID && (task.externalChat?.provider !== "codex" || task.externalChat.id !== process.env.CODEX_THREAD_ID)) {
|
|
111240
111741
|
if (task.primaryChatId) {
|
|
111241
|
-
const
|
|
111242
|
-
throw new Error(taskOwnerConflict({ provider: "openmates", id:
|
|
111742
|
+
const owner2 = await client2.getChatMetadata(task.primaryChatId, scope2);
|
|
111743
|
+
throw new Error(taskOwnerConflict({ provider: "openmates", id: owner2.id, title: owner2.title }));
|
|
111243
111744
|
}
|
|
111244
111745
|
throw new Error(taskOwnerConflict(task.externalChat));
|
|
111245
111746
|
}
|
|
@@ -111255,8 +111756,8 @@ async function handleTasks(client2, subcommand, rest, flags, redactor) {
|
|
|
111255
111756
|
if (subcommand === "connect") {
|
|
111256
111757
|
if (typeof flags.thread !== "string") throw new Error("Usage: openmates tasks connect <task-id> --thread <codex-thread-uuid>");
|
|
111257
111758
|
if (task.primaryChatId) {
|
|
111258
|
-
const
|
|
111259
|
-
throw new Error(taskOwnerConflict({ provider: "openmates", id:
|
|
111759
|
+
const owner2 = await client2.getChatMetadata(task.primaryChatId, scope2);
|
|
111760
|
+
throw new Error(taskOwnerConflict({ provider: "openmates", id: owner2.id, title: owner2.title }));
|
|
111260
111761
|
}
|
|
111261
111762
|
if (task.externalChat) {
|
|
111262
111763
|
if (task.externalChat.provider === "codex" && task.externalChat.id === flags.thread) {
|
|
@@ -120628,6 +121129,7 @@ async function sendMessageStreaming(client2, params, redactor) {
|
|
|
120628
121129
|
const onStream = (event) => {
|
|
120629
121130
|
if (params.json) return;
|
|
120630
121131
|
if (event.kind === "typing") {
|
|
121132
|
+
if (event.thinkingContent) return;
|
|
120631
121133
|
const mateName = event.category && MATE_NAMES[event.category] ? MATE_NAMES[event.category] : "Mate";
|
|
120632
121134
|
process.stdout.write(`\x1B[2m${mateName} is typing...\x1B[0m`);
|
|
120633
121135
|
typingShown = true;
|
|
@@ -121058,6 +121560,10 @@ ${renderRemoteCommandReview(review)}
|
|
|
121058
121560
|
const acceptedTaskProposals = params.acceptTaskProposals === true && result.status === "completed" ? await acceptChatTaskProposals(client2, result.chatId, result.taskProposals, `${finalMessage}
|
|
121059
121561
|
|
|
121060
121562
|
${result.assistant}`) : [];
|
|
121563
|
+
if (result.status === "queued") {
|
|
121564
|
+
if (!params.json) process.stderr.write("Message queued for this chat. It will run after the active response finishes.\n");
|
|
121565
|
+
return { ...result, acceptedTaskProposals: [] };
|
|
121566
|
+
}
|
|
121061
121567
|
if (result.status === "waiting_for_user") {
|
|
121062
121568
|
const question = parseInteractiveQuestionBlock(result.assistant);
|
|
121063
121569
|
if (params.json && question) {
|