mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-16 13:03:31 +08:00
Fix four root causes in the desktop preview pipeline, surfaced when the model writes the files the user pointed it at: - Output chips guessed paths from prose and could point at a missing file. They are now reconciled against the turn's real changed files: a bare `index.html` resolves to the `todo-app/index.html` actually written, and mentions the turn never changed are dropped. - A standalone single-page index.html got no browser preview (mistaken for a Vite template). It is now only routed to the source view when a package.json/vite.config ships in the same change-set. - Files written outside the session workdir (another folder, or another drive on Windows) failed to preview with 'Path is outside workspace'. The turn's changed-file directories are registered as filesystem access roots; html serves via /local-file and other files via a workdir-relaxed read. - The visual-selection prompt leaked as a raw bubble on Windows because the server-appended '[Image source: ...]' line broke replay dedupe. Replay text is now metadata-normalized before comparison (affects any image message). Adds unit tests for each: htmlPreviewPolicy, assistantOutputTargets reconciliation, replay dedupe + stripGeneratedImageMetadataLines, filesystem access roots, and workspace outside-workdir reads.
83 lines
3.4 KiB
TypeScript
83 lines
3.4 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { isHtmlFilePath, shouldOfferStaticHtmlPreview } from './htmlPreviewPolicy'
|
|
|
|
describe('isHtmlFilePath', () => {
|
|
it('matches html/htm/xhtml regardless of separators and suffixes', () => {
|
|
expect(isHtmlFilePath('index.html')).toBe(true)
|
|
expect(isHtmlFilePath('page.htm')).toBe(true)
|
|
expect(isHtmlFilePath('a/b.xhtml')).toBe(true)
|
|
expect(isHtmlFilePath('C:\\proj\\page.html')).toBe(true)
|
|
expect(isHtmlFilePath('app.html?v=2#top')).toBe(true)
|
|
})
|
|
|
|
it('rejects non-html paths', () => {
|
|
expect(isHtmlFilePath('style.css')).toBe(false)
|
|
expect(isHtmlFilePath('readme.md')).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('shouldOfferStaticHtmlPreview', () => {
|
|
it('is false for non-html files', () => {
|
|
expect(shouldOfferStaticHtmlPreview('app.js')).toBe(false)
|
|
expect(shouldOfferStaticHtmlPreview('styles/site.css')).toBe(false)
|
|
})
|
|
|
|
it('offers static preview for non-index html pages', () => {
|
|
expect(shouldOfferStaticHtmlPreview('todo.html')).toBe(true)
|
|
expect(shouldOfferStaticHtmlPreview('pages/about.html')).toBe(true)
|
|
})
|
|
|
|
it('offers static preview for a hand-authored single-page index.html (no project manifest)', () => {
|
|
// The real-world regression: a "make me a todo page" output written into a
|
|
// subfolder must still get a browser preview — it is NOT a build template.
|
|
expect(shouldOfferStaticHtmlPreview('todo-app/index.html')).toBe(true)
|
|
expect(
|
|
shouldOfferStaticHtmlPreview('todo-app/index.html', {
|
|
siblingFiles: ['todo-app/index.html', 'todo-app/style.css', 'todo-app/app.js'],
|
|
}),
|
|
).toBe(true)
|
|
})
|
|
|
|
it('defaults a bare index.html to static preview when no change-set context is given', () => {
|
|
expect(shouldOfferStaticHtmlPreview('index.html')).toBe(true)
|
|
})
|
|
|
|
it('routes a framework-template index.html (manifest in the same change-set) to source view', () => {
|
|
expect(
|
|
shouldOfferStaticHtmlPreview('index.html', {
|
|
siblingFiles: ['index.html', 'package.json', 'vite.config.ts', 'src/main.tsx'],
|
|
}),
|
|
).toBe(false)
|
|
expect(
|
|
shouldOfferStaticHtmlPreview('my-app/index.html', {
|
|
siblingFiles: ['my-app/package.json', 'my-app/index.html', 'my-app/src/main.tsx'],
|
|
}),
|
|
).toBe(false)
|
|
})
|
|
|
|
it('only treats a manifest as a signal when it sits at or above the index.html dir', () => {
|
|
// A package.json in an unrelated sibling folder must not suppress the preview.
|
|
expect(
|
|
shouldOfferStaticHtmlPreview('site/index.html', {
|
|
siblingFiles: ['api/package.json', 'site/index.html', 'site/app.js'],
|
|
}),
|
|
).toBe(true)
|
|
})
|
|
|
|
it('always offers static preview for build-output and generated exports', () => {
|
|
expect(shouldOfferStaticHtmlPreview('dist/index.html')).toBe(true)
|
|
expect(shouldOfferStaticHtmlPreview('out/index.html')).toBe(true)
|
|
expect(shouldOfferStaticHtmlPreview('build/index.html')).toBe(true)
|
|
expect(shouldOfferStaticHtmlPreview('report_files/index.html')).toBe(true)
|
|
// Even with a manifest present, a built artifact dir stays statically previewable.
|
|
expect(
|
|
shouldOfferStaticHtmlPreview('dist/index.html', { siblingFiles: ['package.json', 'dist/index.html'] }),
|
|
).toBe(true)
|
|
})
|
|
|
|
it('normalizes windows separators and url suffixes', () => {
|
|
expect(shouldOfferStaticHtmlPreview('todo-app\\index.html')).toBe(true)
|
|
expect(shouldOfferStaticHtmlPreview('page.html?v=1#frag')).toBe(true)
|
|
})
|
|
})
|