chore: exclude local resource artifacts from main sync

This commit is contained in:
2026-05-15 10:16:45 +09:00
parent 442879313f
commit d38d022872
504 changed files with 17074 additions and 3642 deletions

View File

@@ -2,12 +2,16 @@ import type { ChatMessagePart } from './types';
const LINK_CARD_LINE_PATTERN = /^\s*\[\[link-card:(.+?)\]\]\s*$/i;
const PROMPT_LINE_PATTERN = /^\s*\[\[prompt:(.+?)\]\]\s*$/i;
const STANDALONE_MARKDOWN_LINK_LINE_PATTERN = /^\s*(?:[-*+]\s+|\d+\.\s+)?\[([^\]]+)\]\(([^)]+)\)\s*$/;
const STANDALONE_URL_LINE_PATTERN = /^\s*(?:[-*+]\s+|\d+\.\s+)?((?:https?:\/\/|\/)[^\s<>)\]]+)\s*$/i;
const PROMPT_BLOCK_START_PATTERN = /^\s*\[\[prompt:\s*$/i;
const PROMPT_BLOCK_END_PATTERN = /^\s*\]\]\s*$/;
const PROMPT_CODE_BLOCK_START_PATTERN = /^\s*```(?:json|prompt)(?:\s+prompt)?\s*$/i;
const CODE_BLOCK_END_PATTERN = /^\s*```\s*$/;
const RESOURCE_PATH_PREFIXES = ['/api/chat/resources/', '/public/.codex_chat/', '/.codex_chat/'] as const;
const CHAT_API_RESOURCE_MARKER = '/api/chat/resources/';
const CHAT_DOT_CODEX_MARKER = '/.codex_chat/';
const CHAT_PUBLIC_DOT_CODEX_MARKER = '/public/.codex_chat/';
const RESOURCE_MANAGER_PREVIEW_MARKER = '/api/resource-manager/preview/';
const RESOURCE_MANAGER_ROOT_MARKER = 'resource/';
type PromptPart = Extract<ChatMessagePart, { type: 'prompt' }>;
type PromptOption = PromptPart['options'][number];
type PromptPreview = NonNullable<PromptOption['preview']>;
@@ -17,6 +21,65 @@ function normalizeText(value: unknown) {
return String(value ?? '').trim();
}
function normalizeResourceManagerPathSegment(segment: string) {
const normalized = normalizeText(segment);
if (!normalized) {
return '';
}
try {
return encodeURIComponent(decodeURIComponent(normalized));
} catch {
return encodeURIComponent(normalized);
}
}
function buildResourceManagerPreviewUrl(value: string) {
const normalized = normalizeText(value).replace(/\\/g, '/');
const matchedResourcePath = normalized.match(/(?:^|\/)(resource\/.+)$/i)?.[1];
const resourcePath = normalizeText(matchedResourcePath).replace(/^\/+/, '');
if (!resourcePath) {
return '';
}
const relativePath = resourcePath.slice(RESOURCE_MANAGER_ROOT_MARKER.length).replace(/^\/+/, '');
if (!relativePath) {
return '';
}
const encodedPath = relativePath
.split('/')
.filter(Boolean)
.map((segment) => normalizeResourceManagerPathSegment(segment))
.join('/');
return encodedPath ? `${RESOURCE_MANAGER_PREVIEW_MARKER}${encodedPath}` : '';
}
function extractKnownPreviewPath(value: string) {
const normalized = normalizeText(value);
if (!normalized) {
return '';
}
try {
const parsed = new URL(normalized);
const pathname = `${parsed.pathname || ''}${parsed.search || ''}${parsed.hash || ''}`;
if (pathname.startsWith(CHAT_API_RESOURCE_MARKER) || pathname.startsWith(RESOURCE_MANAGER_PREVIEW_MARKER)) {
return pathname;
}
return normalized;
} catch {
return '';
}
}
function normalizeUrl(value: string) {
const normalized = normalizeText(value);
@@ -24,6 +87,12 @@ function normalizeUrl(value: string) {
return '';
}
const knownPreviewPath = extractKnownPreviewPath(normalized);
if (knownPreviewPath) {
return knownPreviewPath;
}
const malformedResourceMatch = normalized.match(/^https?:\/(api\/chat\/resources\/.+)$/i);
if (malformedResourceMatch?.[1]) {
return `/${malformedResourceMatch[1]}`;
@@ -48,6 +117,14 @@ function normalizeUrl(value: string) {
return `${CHAT_API_RESOURCE_MARKER}${normalized.slice(dotCodexIndex + 1)}`;
}
if (normalized === 'resource' || normalized === '/resource' || normalized.startsWith('resource/') || normalized.includes('/resource/')) {
const resourceManagerPreviewUrl = buildResourceManagerPreviewUrl(normalized);
if (resourceManagerPreviewUrl) {
return resourceManagerPreviewUrl;
}
}
if (/^(?:https?:\/\/|\/)/i.test(normalized)) {
return normalized;
}
@@ -193,59 +270,10 @@ function resolveLinkCardUrlAndActionLabel(rawUrl: string, rawActionLabel?: strin
};
}
function hasKnownFileExtension(url: string) {
const pathname = url.split('?')[0] ?? '';
return /\.[a-z0-9]{1,8}$/i.test(pathname);
}
function isInternalResourceUrl(url: string) {
return RESOURCE_PATH_PREFIXES.some((prefix) => url.startsWith(prefix));
}
function isStructuredLinkCardCandidate(url: string) {
const normalized = normalizeUrl(url);
if (!normalized) {
return false;
}
if (isInternalResourceUrl(normalized)) {
return false;
}
return /^https?:\/\//i.test(normalized) && !hasKnownFileExtension(normalized);
}
function buildFallbackLinkTitle(url: string) {
try {
const parsed = new URL(url, typeof window !== 'undefined' ? window.location.origin : 'https://local.invalid');
const lastSegment = parsed.pathname.split('/').filter(Boolean).at(-1)?.trim();
return lastSegment || parsed.hostname || normalizeText(url);
} catch {
return normalizeText(url);
}
}
function normalizeStandaloneTitle(value: string) {
return value
.replace(/^\s*(?:[-*+]\s+|\d+\.\s+)?/, '')
.replace(/[`'"]+/g, '')
.replace(/\s+/g, ' ')
.trim();
}
function resolveStandaloneLinkTitle(keptLines: string[], url: string) {
for (let index = keptLines.length - 1; index >= 0; index -= 1) {
const candidate = normalizeStandaloneTitle(keptLines[index] ?? '');
if (candidate) {
return candidate;
}
}
return buildFallbackLinkTitle(url);
}
function buildLinkCardPart(rawBody: string): ChatMessagePart | null {
const segments = rawBody
.split('|')
@@ -330,6 +358,17 @@ function buildPromptPart(rawBody: string): ChatMessagePart | null {
};
}
function buildPromptPartFromBlock(rawBody: string) {
const trimmed = rawBody.trim();
if (!trimmed) {
return null;
}
const promptWrapperMatched = trimmed.match(/^\[\[prompt:\s*([\s\S]*?)\s*\]\]$/i);
return buildPromptPart(promptWrapperMatched?.[1] ?? trimmed);
}
export function extractChatMessageParts(text: string) {
const lines = String(text ?? '').split('\n');
const keptLines: string[] = [];
@@ -382,7 +421,8 @@ export function extractChatMessageParts(text: string) {
return true;
};
for (const line of lines) {
for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
const line = lines[lineIndex] ?? '';
const promptMatched = line.match(PROMPT_LINE_PATTERN);
if (promptMatched) {
@@ -392,29 +432,65 @@ export function extractChatMessageParts(text: string) {
continue;
}
if (PROMPT_BLOCK_START_PATTERN.test(line)) {
const wrappedLines = [line];
const promptBodyLines: string[] = [];
let cursor = lineIndex + 1;
let foundBlockEnd = false;
for (; cursor < lines.length; cursor += 1) {
const nextLine = lines[cursor] ?? '';
wrappedLines.push(nextLine);
if (PROMPT_BLOCK_END_PATTERN.test(nextLine)) {
foundBlockEnd = true;
break;
}
promptBodyLines.push(nextLine);
}
if (foundBlockEnd && pushPart(buildPromptPartFromBlock(promptBodyLines.join('\n')))) {
lineIndex = cursor;
continue;
}
keptLines.push(...wrappedLines);
lineIndex = foundBlockEnd ? cursor : lines.length;
continue;
}
if (PROMPT_CODE_BLOCK_START_PATTERN.test(line)) {
const fencedLines = [line];
const jsonBodyLines: string[] = [];
let cursor = lineIndex + 1;
let foundFenceEnd = false;
for (; cursor < lines.length; cursor += 1) {
const nextLine = lines[cursor] ?? '';
fencedLines.push(nextLine);
if (CODE_BLOCK_END_PATTERN.test(nextLine)) {
foundFenceEnd = true;
break;
}
jsonBodyLines.push(nextLine);
}
if (foundFenceEnd && pushPart(buildPromptPartFromBlock(jsonBodyLines.join('\n')))) {
lineIndex = cursor;
continue;
}
keptLines.push(...fencedLines);
lineIndex = foundFenceEnd ? cursor : lines.length;
continue;
}
const matched = line.match(LINK_CARD_LINE_PATTERN);
if (!matched) {
const markdownLinkMatch = line.match(STANDALONE_MARKDOWN_LINK_LINE_PATTERN);
if (markdownLinkMatch) {
const [, rawTitle, rawUrl] = markdownLinkMatch;
if (isStructuredLinkCardCandidate(rawUrl ?? '')) {
if (pushPart(buildLinkCardPart(`${rawTitle}|${rawUrl}`))) {
continue;
}
}
}
const standaloneUrlMatch = line.match(STANDALONE_URL_LINE_PATTERN);
if (standaloneUrlMatch) {
const rawUrl = standaloneUrlMatch[1] ?? '';
if (isStructuredLinkCardCandidate(rawUrl)) {
if (pushPart(buildLinkCardPart(`${resolveStandaloneLinkTitle(keptLines, rawUrl)}|${rawUrl}`))) {
continue;
}
}
}
keptLines.push(line);
continue;
}