46e3899945
- Changes (#72): a file git reports `MM` whose working copy equals HEAD again (a staged change since undone on disk) is no longer listed — JetBrains' GitChangesCollector drops it the same way. Mode-only changes stay listed. statusCounts (the dirty-tree safety checks) is unchanged. - Chat (#73): Claude Code runs no hook before a folder is trusted, so a new pane's session has no row; the chat now says the session has not started, offers Open terminal, and asks before typing a message or /model //effort into the pane (an Enter would pick the trust prompt's "No, exit"). - Terminal: Safari + macOS's own Vietnamese Telex replaces the whole word on each key (insertReplacementText), which xterm.js ignores — only each word's first letter reached the pane. The edit is now sent as DELs + the new tail. - Also: Ctrl+V pastes a screenshot into the terminal as a file path; the folder browser fallback lists files for a file field (`files=1`); the macOS native picker opens in front of the browser; a hidden tab is marked while a chat waits or once a turn ended; chat live line shows running calls, turn time and tokens, and "Done in …".
50 lines
1.7 KiB
TypeScript
50 lines
1.7 KiB
TypeScript
/**
|
|
* @file tabBadge.ts — the browser tab's title mark for Chat panes while the
|
|
* page is hidden: "● Waiting" while a pane's CLI asks the user something (a
|
|
* permission prompt), else "✓ Done" once a turn ended. Shown again, the
|
|
* page drops the "Done" marks; a "Waiting" one lasts until its question is
|
|
* answered. Only the mark this module put in front of the title is ever
|
|
* removed, so a page that sets its own title meanwhile keeps it.
|
|
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
|
*/
|
|
import i18n from "../i18n";
|
|
|
|
export type TabMark = "waiting" | "done";
|
|
|
|
const marks = new Map<string, TabMark>();
|
|
let applied = "";
|
|
|
|
function apply() {
|
|
const title = document.title;
|
|
const base = applied && title.startsWith(applied) ? title.slice(applied.length) : title;
|
|
const all = [...marks.values()];
|
|
const mark =
|
|
document.visibilityState !== "hidden"
|
|
? null
|
|
: all.includes("waiting")
|
|
? "waiting"
|
|
: all.includes("done")
|
|
? "done"
|
|
: null;
|
|
applied = mark ? `${mark === "waiting" ? "●" : "✓"} ${i18n.t(`run:chat.tab.${mark}`)} · ` : "";
|
|
document.title = applied + base;
|
|
}
|
|
|
|
/** Sets (or, with null, drops) the mark of one pane (`key`). */
|
|
export function setTabBadge(key: string, mark: TabMark | null): void {
|
|
// A turn ending in front of the user needs no mark.
|
|
if (mark === "done" && document.visibilityState !== "hidden") mark = null;
|
|
if (mark) marks.set(key, mark);
|
|
else marks.delete(key);
|
|
apply();
|
|
}
|
|
|
|
if (typeof document !== "undefined") {
|
|
document.addEventListener("visibilitychange", () => {
|
|
if (document.visibilityState !== "hidden") {
|
|
for (const [key, mark] of marks) if (mark === "done") marks.delete(key);
|
|
}
|
|
apply();
|
|
});
|
|
}
|