Mark unread turn summaries in the switcher and Project rows
This commit is contained in:
Vendored
+53
-1
@@ -4,7 +4,7 @@ import { markdown } from "./markdown.js";
|
||||
import { previewURL } from "./preview.js";
|
||||
import { findingCount, reviewCounts, severityCounts, unignoredFindings } from "./reviews.js";
|
||||
import { composerText, endSend, flushDrafts, forgetLostImages, lostImageCount, setComposerImages, setComposerText, startSend } from "./drafts.js";
|
||||
import { currentSession, findTask, focusTab, focusTask, on, onEach, pickReview, pinSnapshot, setFocus, showReview, state, transcriptLoading } from "./state.js";
|
||||
import { currentSession, findTask, focusTab, focusTask, markSummaryRead, on, onEach, pickReview, pinSnapshot, setFocus, showReview, state, transcriptLoading } from "./state.js";
|
||||
import { taskStyle } from "./taskcolor.js";
|
||||
import { fillTodoLinks } from "./todolink.js";
|
||||
export const models = [
|
||||
@@ -149,6 +149,48 @@ export function mountChat(root, src, makeHead) {
|
||||
resizes.observe(transcript);
|
||||
const mutations = new MutationObserver(pin);
|
||||
mutations.observe(transcript, { childList: true, subtree: true, characterData: true });
|
||||
const shown = new Set();
|
||||
const markShown = () => {
|
||||
const taskId = ctx.taskId;
|
||||
if (!taskId || document.visibilityState !== "visible") {
|
||||
return;
|
||||
}
|
||||
for (const el of shown) {
|
||||
markSummaryRead(taskId, Number(el.dataset["seq"]));
|
||||
}
|
||||
};
|
||||
const sightings = new IntersectionObserver((entries) => {
|
||||
for (const e of entries) {
|
||||
if (e.isIntersecting) {
|
||||
shown.add(e.target);
|
||||
}
|
||||
else {
|
||||
shown.delete(e.target);
|
||||
}
|
||||
}
|
||||
markShown();
|
||||
}, { root: transcript });
|
||||
document.addEventListener("visibilitychange", markShown);
|
||||
const jump = () => {
|
||||
const target = state.jump;
|
||||
if (!target || target.taskId !== ctx.taskId) {
|
||||
return;
|
||||
}
|
||||
const end = transcript.querySelector(`.turn-end[data-seq="${target.seq}"]`);
|
||||
if (!end) {
|
||||
return;
|
||||
}
|
||||
state.jump = undefined;
|
||||
const msg = end.previousElementSibling;
|
||||
const box = transcript.getBoundingClientRect();
|
||||
if (msg?.classList.contains("agent")) {
|
||||
transcript.scrollTop += msg.getBoundingClientRect().top - box.top - 8;
|
||||
}
|
||||
else {
|
||||
transcript.scrollTop += end.getBoundingClientRect().bottom - box.bottom + 8;
|
||||
}
|
||||
stuck = transcript.scrollHeight - transcript.scrollTop - transcript.clientHeight < 80;
|
||||
};
|
||||
const newCtx = () => ({
|
||||
tools: new Map(),
|
||||
subagents: new Map(),
|
||||
@@ -434,6 +476,10 @@ export function mountChat(root, src, makeHead) {
|
||||
if (ev.kind === "user.message" && p["mid_turn"] !== true) {
|
||||
ctx.open = true;
|
||||
}
|
||||
if (ev.kind === "turn.ended" && p["summary"] === true && ctx.taskId) {
|
||||
el.dataset["seq"] = String(ev.seq);
|
||||
sightings.observe(el);
|
||||
}
|
||||
put(el);
|
||||
}
|
||||
syncRunning();
|
||||
@@ -446,11 +492,14 @@ export function mountChat(root, src, makeHead) {
|
||||
}
|
||||
fillTodoLinks(transcript, models[0]);
|
||||
pin();
|
||||
jump();
|
||||
};
|
||||
const renderAll = () => {
|
||||
stuck = true;
|
||||
dropStream();
|
||||
pending = [];
|
||||
sightings.disconnect();
|
||||
shown.clear();
|
||||
ctx = newCtx();
|
||||
context = new Map();
|
||||
focusStart = true;
|
||||
@@ -478,6 +527,7 @@ export function mountChat(root, src, makeHead) {
|
||||
onEach([src.streamTopic], (ev) => appendDelta(ev)),
|
||||
onEach([src.readyTopic], () => loading.remove()),
|
||||
onEach(["tasks", "sessions"], () => fillTodoLinks(transcript, models[0])),
|
||||
on("jump", jump),
|
||||
];
|
||||
replace(root, h("div", { class: "transcript-view" }, head, transcript, composer));
|
||||
renderAll();
|
||||
@@ -488,6 +538,8 @@ export function mountChat(root, src, makeHead) {
|
||||
headImpl.dispose?.();
|
||||
resizes.disconnect();
|
||||
mutations.disconnect();
|
||||
sightings.disconnect();
|
||||
document.removeEventListener("visibilitychange", markShown);
|
||||
dropStream();
|
||||
const input = composer.querySelector("textarea");
|
||||
if (input) {
|
||||
|
||||
Reference in New Issue
Block a user