feat(vscode): show thread git metadata
This commit is contained in:
@@ -225,6 +225,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
cross-tab events, and corruption-tolerant persisted state, while leaving the
|
cross-tab events, and corruption-tolerant persisted state, while leaving the
|
||||||
broader collaboration UI wiring to follow-up work (#2864). Thanks
|
broader collaboration UI wiring to follow-up work (#2864). Thanks
|
||||||
@ljm3790865 for the tab-core implementation and #2753 direction.
|
@ljm3790865 for the tab-core implementation and #2753 direction.
|
||||||
|
- The VS Code Agent View now renders the runtime thread summary's Git `head`
|
||||||
|
and dirty-worktree flag alongside branch metadata, keeping branch switches
|
||||||
|
visible without adding retry/undo/restore mutation endpoints yet (#2580,
|
||||||
|
#2862). Thanks @AiurArtanis and @nasus9527 for the IDE/agent-view requests
|
||||||
|
and @gaord for the runtime metadata direction.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|||||||
@@ -225,6 +225,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
cross-tab events, and corruption-tolerant persisted state, while leaving the
|
cross-tab events, and corruption-tolerant persisted state, while leaving the
|
||||||
broader collaboration UI wiring to follow-up work (#2864). Thanks
|
broader collaboration UI wiring to follow-up work (#2864). Thanks
|
||||||
@ljm3790865 for the tab-core implementation and #2753 direction.
|
@ljm3790865 for the tab-core implementation and #2753 direction.
|
||||||
|
- The VS Code Agent View now renders the runtime thread summary's Git `head`
|
||||||
|
and dirty-worktree flag alongside branch metadata, keeping branch switches
|
||||||
|
visible without adding retry/undo/restore mutation endpoints yet (#2580,
|
||||||
|
#2862). Thanks @AiurArtanis and @nasus9527 for the IDE/agent-view requests
|
||||||
|
and @gaord for the runtime metadata direction.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|||||||
@@ -200,6 +200,8 @@ function readThreadSummaries(value) {
|
|||||||
mode: readString(record.mode) ?? "agent",
|
mode: readString(record.mode) ?? "agent",
|
||||||
workspace: readString(record.workspace),
|
workspace: readString(record.workspace),
|
||||||
branch: readString(record.branch),
|
branch: readString(record.branch),
|
||||||
|
head: readString(record.head),
|
||||||
|
dirty: readBoolean(record.dirty),
|
||||||
archived: record.archived === true,
|
archived: record.archived === true,
|
||||||
updatedAt: readString(record.updated_at) ?? "",
|
updatedAt: readString(record.updated_at) ?? "",
|
||||||
latestTurnStatus: readString(record.latest_turn_status),
|
latestTurnStatus: readString(record.latest_turn_status),
|
||||||
@@ -231,6 +233,9 @@ function readString(value) {
|
|||||||
function readNumber(value) {
|
function readNumber(value) {
|
||||||
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
||||||
}
|
}
|
||||||
|
function readBoolean(value) {
|
||||||
|
return value === true;
|
||||||
|
}
|
||||||
function clampRefreshInterval(value) {
|
function clampRefreshInterval(value) {
|
||||||
if (!Number.isFinite(value)) {
|
if (!Number.isFinite(value)) {
|
||||||
return 15;
|
return 15;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -148,15 +148,31 @@ function renderSnapshot(snapshot) {
|
|||||||
function renderThread(thread) {
|
function renderThread(thread) {
|
||||||
const status = thread.latestTurnStatus ? ` · ${thread.latestTurnStatus}` : "";
|
const status = thread.latestTurnStatus ? ` · ${thread.latestTurnStatus}` : "";
|
||||||
const archived = thread.archived ? " · archived" : "";
|
const archived = thread.archived ? " · archived" : "";
|
||||||
const branch = thread.branch ? ` · branch ${thread.branch}` : "";
|
const git = renderGitMetadata(thread);
|
||||||
const workspace = thread.workspace ? ` · ${thread.workspace}` : "";
|
const workspace = thread.workspace ? ` · ${thread.workspace}` : "";
|
||||||
const updated = thread.updatedAt ? ` · ${formatTimestamp(thread.updatedAt)}` : "";
|
const updated = thread.updatedAt ? ` · ${formatTimestamp(thread.updatedAt)}` : "";
|
||||||
return `<div class="thread">
|
return `<div class="thread">
|
||||||
<div class="thread-title">${escapeHtml(thread.title)}</div>
|
<div class="thread-title">${escapeHtml(thread.title)}</div>
|
||||||
<div class="thread-preview">${escapeHtml(thread.preview || "No recent message.")}</div>
|
<div class="thread-preview">${escapeHtml(thread.preview || "No recent message.")}</div>
|
||||||
<div class="thread-meta">${escapeHtml(`${thread.mode} · ${thread.model}${status}${branch}${archived}${updated}${workspace}`)}</div>
|
<div class="thread-meta">${escapeHtml(`${thread.mode} · ${thread.model}${status}${git}${archived}${updated}${workspace}`)}</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
function renderGitMetadata(thread) {
|
||||||
|
if (!thread.branch && !thread.head && !thread.dirty) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
const parts = [];
|
||||||
|
if (thread.branch) {
|
||||||
|
parts.push(`branch ${thread.branch}`);
|
||||||
|
}
|
||||||
|
if (thread.head) {
|
||||||
|
parts.push(`@ ${thread.head}`);
|
||||||
|
}
|
||||||
|
if (thread.dirty) {
|
||||||
|
parts.push("dirty");
|
||||||
|
}
|
||||||
|
return ` · ${parts.join(" ")}`;
|
||||||
|
}
|
||||||
function labelFor(kind) {
|
function labelFor(kind) {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case "connected":
|
case "connected":
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -18,6 +18,8 @@ export interface ThreadSummary {
|
|||||||
mode: string;
|
mode: string;
|
||||||
workspace?: string;
|
workspace?: string;
|
||||||
branch?: string;
|
branch?: string;
|
||||||
|
head?: string;
|
||||||
|
dirty: boolean;
|
||||||
archived: boolean;
|
archived: boolean;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
latestTurnStatus?: string;
|
latestTurnStatus?: string;
|
||||||
@@ -228,6 +230,8 @@ function readThreadSummaries(value: unknown): ThreadSummary[] {
|
|||||||
mode: readString(record.mode) ?? "agent",
|
mode: readString(record.mode) ?? "agent",
|
||||||
workspace: readString(record.workspace),
|
workspace: readString(record.workspace),
|
||||||
branch: readString(record.branch),
|
branch: readString(record.branch),
|
||||||
|
head: readString(record.head),
|
||||||
|
dirty: readBoolean(record.dirty),
|
||||||
archived: record.archived === true,
|
archived: record.archived === true,
|
||||||
updatedAt: readString(record.updated_at) ?? "",
|
updatedAt: readString(record.updated_at) ?? "",
|
||||||
latestTurnStatus: readString(record.latest_turn_status),
|
latestTurnStatus: readString(record.latest_turn_status),
|
||||||
@@ -265,6 +269,10 @@ function readNumber(value: unknown): number | undefined {
|
|||||||
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function readBoolean(value: unknown): boolean {
|
||||||
|
return value === true;
|
||||||
|
}
|
||||||
|
|
||||||
function clampRefreshInterval(value: number): number {
|
function clampRefreshInterval(value: number): number {
|
||||||
if (!Number.isFinite(value)) {
|
if (!Number.isFinite(value)) {
|
||||||
return 15;
|
return 15;
|
||||||
|
|||||||
@@ -120,16 +120,34 @@ function renderSnapshot(snapshot: SnapshotEntry): string {
|
|||||||
function renderThread(thread: ThreadSummary): string {
|
function renderThread(thread: ThreadSummary): string {
|
||||||
const status = thread.latestTurnStatus ? ` · ${thread.latestTurnStatus}` : "";
|
const status = thread.latestTurnStatus ? ` · ${thread.latestTurnStatus}` : "";
|
||||||
const archived = thread.archived ? " · archived" : "";
|
const archived = thread.archived ? " · archived" : "";
|
||||||
const branch = thread.branch ? ` · branch ${thread.branch}` : "";
|
const git = renderGitMetadata(thread);
|
||||||
const workspace = thread.workspace ? ` · ${thread.workspace}` : "";
|
const workspace = thread.workspace ? ` · ${thread.workspace}` : "";
|
||||||
const updated = thread.updatedAt ? ` · ${formatTimestamp(thread.updatedAt)}` : "";
|
const updated = thread.updatedAt ? ` · ${formatTimestamp(thread.updatedAt)}` : "";
|
||||||
return `<div class="thread">
|
return `<div class="thread">
|
||||||
<div class="thread-title">${escapeHtml(thread.title)}</div>
|
<div class="thread-title">${escapeHtml(thread.title)}</div>
|
||||||
<div class="thread-preview">${escapeHtml(thread.preview || "No recent message.")}</div>
|
<div class="thread-preview">${escapeHtml(thread.preview || "No recent message.")}</div>
|
||||||
<div class="thread-meta">${escapeHtml(`${thread.mode} · ${thread.model}${status}${branch}${archived}${updated}${workspace}`)}</div>
|
<div class="thread-meta">${escapeHtml(`${thread.mode} · ${thread.model}${status}${git}${archived}${updated}${workspace}`)}</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderGitMetadata(thread: ThreadSummary): string {
|
||||||
|
if (!thread.branch && !thread.head && !thread.dirty) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const parts: string[] = [];
|
||||||
|
if (thread.branch) {
|
||||||
|
parts.push(`branch ${thread.branch}`);
|
||||||
|
}
|
||||||
|
if (thread.head) {
|
||||||
|
parts.push(`@ ${thread.head}`);
|
||||||
|
}
|
||||||
|
if (thread.dirty) {
|
||||||
|
parts.push("dirty");
|
||||||
|
}
|
||||||
|
return ` · ${parts.join(" ")}`;
|
||||||
|
}
|
||||||
|
|
||||||
function labelFor(kind: RuntimeState["kind"]): string {
|
function labelFor(kind: RuntimeState["kind"]): string {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case "connected":
|
case "connected":
|
||||||
|
|||||||
Reference in New Issue
Block a user