diff --git a/.agents/skills/do-wdr-release/SKILL.md b/.agents/skills/do-wdr-release/SKILL.md index 3ccf547..221fecf 100644 --- a/.agents/skills/do-wdr-release/SKILL.md +++ b/.agents/skills/do-wdr-release/SKILL.md @@ -86,6 +86,7 @@ git push origin main --tags ### 4. Wait for CI/CD The tag push triggers `.github/workflows/release.yml` which: + - Runs Python and Rust test suites - Builds binaries for Linux, macOS, and Windows - Generates build attestations diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 4fa442a..dc08121 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -55,11 +55,6 @@ name = "compaction_bench" harness = false path = "benches/compaction_bench.rs" -[[bench]] -name = "quality_bench" -harness = false -path = "benches/quality_bench.rs" - [[bin]] name = "do-wdr" path = "src/main.rs" diff --git a/cli/benches/quality_bench.rs b/cli/benches/quality_bench.rs deleted file mode 100644 index d518577..0000000 --- a/cli/benches/quality_bench.rs +++ /dev/null @@ -1,54 +0,0 @@ -use criterion::{Criterion, black_box, criterion_group, criterion_main}; -use do_wdr_lib::quality::score_content; -use std::time::Duration; - -fn bench_quality(c: &mut Criterion) { - let markdown = r#" ---- -relevance_score: 0.95 -intent_category: Technical -token_estimate: 1500 -last_updated: 2026-05-20 ---- - -[ANCHOR: SUMMARY] -This is a high-quality document with all the required markers and some content. -It avoids noise but mentions cookies once for testing purposes. - -[ANCHOR: TECHNICAL_DETAILS] -The implementation uses Rust for performance and reliability. -We ensure that the quality scoring is accurate and efficient. -Deduplication is key to high-quality synthesis. - -[ANCHOR: COMPARISON] -Compared to other solutions, this one is more 2026-compliant. - -[ANCHOR: CITATIONS] -[1] https://example.com/docs -[2] https://rust-lang.org - -# Some more content to reach the length threshold -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. -Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. -Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. -Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. -"#.repeat(10); - - let links = vec![ - "https://example.com".to_string(), - "https://rust-lang.org".to_string(), - ]; - - let mut group = c.benchmark_group("quality"); - group.measurement_time(Duration::from_secs(5)); - - group.bench_function("score_content", |b| { - b.iter(|| { - score_content(black_box(&markdown), black_box(&links), black_box(0.7)); - }); - }); - group.finish(); -} - -criterion_group!(benches, bench_quality); -criterion_main!(benches); diff --git a/cli/src/quality.rs b/cli/src/quality.rs index 579e900..d7f450e 100644 --- a/cli/src/quality.rs +++ b/cli/src/quality.rs @@ -8,31 +8,25 @@ pub struct QualityScore { pub acceptable: bool, } -use regex::Regex; -use std::collections::HashSet; -use std::sync::OnceLock; - -static NOISY_REGEX: OnceLock = OnceLock::new(); - pub fn score_content(markdown: &str, links: &[String], threshold: f32) -> QualityScore { let trimmed = markdown.trim(); let len = trimmed.len(); let too_short = len < 500; let missing_links = links.is_empty(); - - let mut num_lines = 0; - let mut unique_lines = HashSet::new(); - for line in trimmed.lines() { - num_lines += 1; - unique_lines.insert(line.trim()); - } - let unique_count = unique_lines.len(); - let duplicate_heavy = num_lines > 0 && unique_count < std::cmp::max(5, num_lines / 3); - - let noisy_re = NOISY_REGEX - .get_or_init(|| Regex::new("(?i)cookie|subscribe|javascript|log in|sign up").unwrap()); - let noisy_count = noisy_re.find_iter(trimmed).count(); + let lines: Vec<&str> = trimmed.lines().collect(); + let unique_lines = lines + .iter() + .copied() + .collect::>() + .len(); + let duplicate_heavy = !lines.is_empty() && unique_lines < std::cmp::max(5, lines.len() / 3); + let lower = trimmed.to_lowercase(); + let noisy_count = lower.matches("cookie").count() + + lower.matches("subscribe").count() + + lower.matches("javascript").count() + + lower.matches("log in").count() + + lower.matches("sign up").count(); let noisy = noisy_count > 6; let has_frontmatter = trimmed.starts_with("---") diff --git a/web/app/components/MainContent.tsx b/web/app/components/MainContent.tsx index e197504..e8babd7 100644 --- a/web/app/components/MainContent.tsx +++ b/web/app/components/MainContent.tsx @@ -1,8 +1,10 @@ "use client"; -import Link from "next/link"; +import { MainHeader } from "@/app/components/MainHeader"; +import { SearchSection } from "@/app/components/SearchSection"; +import { MetadataBar } from "@/app/components/MetadataBar"; import ResultCard from "@/app/components/ResultCard"; -import { ProviderResult } from "@/lib/results"; +import type { ProviderResult } from "@/lib/results"; interface MainContentProps { mobileMenuOpen: boolean; @@ -36,191 +38,87 @@ interface MainContentProps { isUrl: boolean; } -export default function MainContent({ - mobileMenuOpen, - setMobileMenuOpen, - query, - setQuery, - handleSubmit, - loading, - inputRef, - error, - result, - setResult, - setError, - providerStatus, - setProviderStatus, - sourceProvider, - setSourceProvider, - resolveTime, - setResolveTime, - qualityScore, - setQualityScore, - parsedResults, - setParsedResults, - viewRaw, - setViewRaw, - helpfulIds, - toggleHelpful, - handleCopyResult, - handleCardCopy, - copied, - isUrl, -}: MainContentProps) { - const charCount = result.length; +export const MainContent = (props: MainContentProps) => { + const { + setMobileMenuOpen, + query, + setQuery, + handleSubmit, + loading, + inputRef, + error, + result, + setResult, + setError, + providerStatus, + setProviderStatus, + sourceProvider, + setSourceProvider, + resolveTime, + setResolveTime, + qualityScore, + setQualityScore, + parsedResults, + setParsedResults, + viewRaw, + setViewRaw, + helpfulIds, + toggleHelpful, + handleCopyResult, + handleCardCopy, + copied, + isUrl, + } = props; + + const handleClear = () => { + setQuery(""); + setResult(""); + setError(""); + setProviderStatus(null); + setResolveTime(null); + setSourceProvider(null); + setQualityScore(null); + setParsedResults([]); + setViewRaw(false); + inputRef.current?.focus(); + }; return (
- {/* Header */} -
-
- {/* Hamburger menu - mobile only */} - - do-web-doc-resolver -
- - Help - -
+ - {/* Input */} -
-
- -
- setQuery(e.target.value)} - onKeyDown={(e) => e.key === "Enter" && handleSubmit()} - placeholder="URL or search query..." - aria-invalid={!!error} - aria-errormessage={error ? "search-error" : undefined} - className="w-full bg-transparent text-[20px] sm:text-[24px] text-foreground placeholder:text-text-dim tracking-tight pr-10" - /> - {query && ( - - )} -
- {query.trim() && ( -
- - -
- )} -
- {query.trim() && ( -
- {isUrl ? "Resolving as URL" : "Searching"} -
- )} - {providerStatus && ( -
- {providerStatus} -
- )} -
+ - {/* Error */} {error && ( )} - {/* Output */}
{result ? ( <> - {/* Metadata bar */} -
-
- - Source: {sourceProvider} - - {resolveTime && {resolveTime}ms} - {charCount.toLocaleString()} chars - {qualityScore !== null && ( - - Quality: = 70 ? "text-accent" : qualityScore >= 40 ? "text-[#ffaa00]" : "text-error"}>{qualityScore} - - )} -
-
- - - -
-
+ {viewRaw || parsedResults.length === 0 ? (