Fix OA workspace cover thumbnails and add space chat new session.

Resolve mindspace-cover images from workspace directories when generating feed thumbnails, refresh stale SVGs missing embedded photos, and disable thumbnail API caching so fixes take effect immediately. Also add a new session control to the space chat panel, including on mobile.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
John
2026-06-16 17:57:00 -07:00
parent 6d99d762da
commit ab0718938e
8 changed files with 133 additions and 8 deletions
+51 -4
View File
@@ -451,6 +451,30 @@ export function isModernFeedThumbnail(svg) {
return /width="540" height="720"/.test(svg) && /filter id="grain"/.test(svg);
}
export function thumbnailHasEmbeddedPhoto(svg) {
return /href="data:image\//.test(String(svg ?? ''));
}
export function resolveWorkspaceHtmlContentBaseDir(workspacePublishDir, workspaceHtmlRelativePath) {
if (!workspacePublishDir || !workspaceHtmlRelativePath) return undefined;
const dir = path.posix.dirname(String(workspaceHtmlRelativePath).replace(/^\/+/, ''));
return dir === '.' ? workspacePublishDir : path.join(workspacePublishDir, dir);
}
async function shouldRegenerateThumbnailForCover(storageRoot, html, meta, existing) {
if (!existing || !isModernFeedThumbnail(existing) || meta.force) return Boolean(meta.force);
const signals = extractCoverSignals(html, meta);
if (!signals.image) return false;
if (thumbnailHasEmbeddedPhoto(existing)) return false;
const coverDataUri = await resolveCoverDataUri({
storageRoot,
contentStorageKey: meta.contentStorageKey,
contentBaseDir: meta.contentBaseDir,
imageUrl: signals.image,
});
return Boolean(coverDataUri);
}
export async function generateHtmlThumbnail(storageRoot, storageKey, html, meta = {}) {
const signals = extractCoverSignals(html, meta);
const coverDataUri = await resolveCoverDataUri({
@@ -467,7 +491,13 @@ export async function generateHtmlThumbnail(storageRoot, storageKey, html, meta
export async function ensureHtmlThumbnail(storageRoot, storageKey, html, meta = {}) {
const existing = await readThumbnailIfExists(storageRoot, storageKey);
if (existing && isModernFeedThumbnail(existing) && !meta.force) {
return existing;
const needsCoverRefresh = await shouldRegenerateThumbnailForCover(
storageRoot,
html,
meta,
existing,
);
if (!needsCoverRefresh) return existing;
}
return generateHtmlThumbnail(storageRoot, storageKey, html, meta);
}
@@ -480,17 +510,34 @@ export async function ensurePageThumbnail({
workspacePublishDir = null,
workspaceHtmlRelativePath = null,
}) {
const contentBaseDir =
meta.contentBaseDir ??
resolveWorkspaceHtmlContentBaseDir(workspacePublishDir, workspaceHtmlRelativePath);
const enrichedMeta = contentBaseDir ? { ...meta, contentBaseDir } : meta;
if (workspacePublishDir && workspaceHtmlRelativePath) {
const sidecar = await readThumbnailIfExists(
workspacePublishDir,
workspaceThumbnailRelativePath(workspaceHtmlRelativePath),
);
if (sidecar && isModernFeedThumbnail(sidecar)) {
await writeThumbnail(storageRoot, pageThumbnailStorageKey, sidecar);
return sidecar;
if (thumbnailHasEmbeddedPhoto(sidecar)) {
await writeThumbnail(storageRoot, pageThumbnailStorageKey, sidecar);
return sidecar;
}
const needsCoverRefresh = await shouldRegenerateThumbnailForCover(
workspacePublishDir,
html,
enrichedMeta,
sidecar,
);
if (!needsCoverRefresh) {
await writeThumbnail(storageRoot, pageThumbnailStorageKey, sidecar);
return sidecar;
}
}
}
return ensureHtmlThumbnail(storageRoot, pageThumbnailStorageKey, html, meta);
return ensureHtmlThumbnail(storageRoot, pageThumbnailStorageKey, html, enrichedMeta);
}
export async function readThumbnailIfExists(storageRoot, storageKey) {