diff --git a/.agents/skills/protowiki-components/references/chrome-primitives.md b/.agents/skills/protowiki-components/references/chrome-primitives.md index 4b5f10b..1ee7d4a 100644 --- a/.agents/skills/protowiki-components/references/chrome-primitives.md +++ b/.agents/skills/protowiki-components/references/chrome-primitives.md @@ -12,7 +12,7 @@ chrome-without-the-wrapper (e.g., a custom layout that doesn't use | Skin | Chrome feel | Notes | | --- | --- | --- | -| `desktop` | **Vector 2022–style** | Wordmark/tagline (**`wordmarkSrc`**, **`taglineSrc`**, **`#logo` override**), **`SearchBar`** + **Search** button, username link (**`username`** + **`#username`**), user-tool cluster ( **`navTools`** preset vs **`#nav`** override ). **Main-menu glyph is icon-only** (mock). Global skin stays **desktop** until the viewport is **≤640px**; **below 1120px**, inline search collapses to a search icon; **below 768px**, watchlist hides (`nav-button-desktop` parity). | +| `desktop` | **Vector 2022–style** | Wordmark/tagline (**`wordmarkSrc`**, **`taglineSrc`**, **`#logo` override**), **`SearchBar`** + **Search** button, username link (**`username`** + **`#username`**), user-tool cluster ( **`navTools`** preset vs **`#nav`** override ). **Main-menu glyph is icon-only mock by default** — override via **`#menu`**. Global skin stays **desktop** until the viewport is **≤640px**; **below 1120px**, inline search collapses to a search icon; **below 768px**, watchlist hides (`nav-button-desktop` parity). | | `mobile` | **Minerva-style** | Grey elevated bar: menu, Wikipedia wordmark (**`mobileWordmarkSrc`** / **`wordmarkSrc`**, **`#logo`**), search icon + notifications — **`navTools` is ignored**. | **`ChromeFooter`** matches the skin: @@ -52,6 +52,7 @@ Desktop **inline search** is always **``** inside the header (not a | Slot | Default | Use for | | --- | --- | --- | | `#logo` | EN Wikipedia wordmark (+ tagline on desktop) via `` | Replace with another project's wordmark / lockup | +| `#menu` | Mock burger icon (**desktop**: non-interactive glyph; **mobile**: quiet button) | Replace with an interactive main-menu trigger + popover (**`ChromeWrapper`** forwards **`#menu`**) | | `#username` | Anchor from **`username`** (hidden when empty after trim) | Replace with custom markup before tool icons (**desktop**) | | `#nav` | Vector-style tool icons on **desktop** only | Replace the default user-tool cluster (**`navTools` ignored**) | diff --git a/.agents/skills/protowiki-components/references/dashboard.md b/.agents/skills/protowiki-components/references/dashboard.md index 469a3f9..d49c300 100644 --- a/.agents/skills/protowiki-components/references/dashboard.md +++ b/.agents/skills/protowiki-components/references/dashboard.md @@ -14,7 +14,7 @@ Reference prototypes: Do not confuse: - **`SpecialPageWrapper` `help`** — desktop title-row **Help** link (Codex docs URL) -- **`dashpage/HelpModule.vue`** — prototype-local **"Get help with editing"** sidebar/mobile card (wraps **`DashboardModule`**) +- **`template-homepage/HelpModule.vue`** — prototype-local **"Get help with editing"** sidebar/mobile card (wraps **`DashboardModule`**) ## `Dashboard` @@ -35,7 +35,7 @@ With **`data-skin="desktop"`**, the two-column grid (`primary` ~66% + `sidebar` Utility classes from the component stylesheet: - **`dashboard-slot`** — min-height baseline on module roots -- **`dashboard-slot--desktop-primary`**, **`dashboard-slot--mobile-primary`**, etc. — prototype hooks for per-slot sizing (see **`template-dashboard`** / **`dashpage`**) +- **`dashboard-slot--desktop-primary`**, **`dashboard-slot--mobile-primary`**, etc. — prototype hooks for per-slot sizing (see **`template-dashboard`** / **`template-homepage`**) ### Props diff --git a/.agents/skills/protowiki-getting-started/SKILL.md b/.agents/skills/protowiki-getting-started/SKILL.md index bdac5a7..ff9256b 100644 --- a/.agents/skills/protowiki-getting-started/SKILL.md +++ b/.agents/skills/protowiki-getting-started/SKILL.md @@ -51,7 +51,7 @@ protowiki/ │ │ ├── index.vue ← home / gallery (auto-lists prototypes) │ │ ├── template-chrome/index.vue │ │ ├── template-dashboard/index.vue -│ │ └── dashpage/index.vue +│ │ └── template-homepage/index.vue │ ├── components/ ← shipped components (wrappers, primitives, article, dashboard) │ ├── composables/ ← useSkin / useTheme (read-only hooks) │ ├── lib/ ← theming logic, helpers diff --git a/.agents/skills/wiki-apis/assets/fetch_schemas.sh b/.agents/skills/wiki-apis/assets/fetch_schemas.sh index e37ddcb..6bd6b42 100755 --- a/.agents/skills/wiki-apis/assets/fetch_schemas.sh +++ b/.agents/skills/wiki-apis/assets/fetch_schemas.sh @@ -21,7 +21,7 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -UA='ProtoWiki-snapshot/0.1 (https://github.com/wikimedia-research/protowiki; protowiki@wikimedia.org)' +UA='ProtoWiki-snapshot/0.1 (https://github.com/wikimedia/protowiki; protowiki@wikimedia.org)' pretty_json() { python3 -c 'import sys, json; json.dump(json.load(sys.stdin), sys.stdout, indent=2, sort_keys=True)' diff --git a/package-lock.json b/package-lock.json index 2ed7fda..982ded4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@wikimedia/codex": "^2.5.1", "@wikimedia/codex-design-tokens": "^2.5.1", "@wikimedia/codex-icons": "^2.5.1", + "fakewiki": "^0.0.13", "vue": "^3.5.13", "vue-router": "^4.5.0" }, @@ -1906,6 +1907,7 @@ "resolved": "https://registry.npmjs.org/@wikimedia/codex-icons/-/codex-icons-2.5.1.tgz", "integrity": "sha512-ZbAXQD0dLuqj8uoMrpswusPymAZ07Pt0Y5wp1mNS3YyHuc1aAvsOGWdsV88YYoJN1l2jvYUE98/KoAKn7Cw5YA==", "license": "MIT", + "peer": true, "engines": { "node": ">=20.20.2", "npm": ">=10.8.2" @@ -2580,6 +2582,16 @@ "dev": true, "license": "MIT" }, + "node_modules/fakewiki": { + "version": "0.0.13", + "resolved": "https://registry.npmjs.org/fakewiki/-/fakewiki-0.0.13.tgz", + "integrity": "sha512-bPIK55+eHRfA5tn7fGHBg/bpTSTP6r4S/HWEskcD5h2XZT3NFB+lxVVgNByvZCOSWI34cv3X8DFCFMzE6R8r+A==", + "license": "GPL-2.0-only", + "peerDependencies": { + "@wikimedia/codex-icons": "^2.0.0", + "vue": "^3.5.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", diff --git a/package.json b/package.json index 5fa316b..d16dd22 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@wikimedia/codex": "^2.5.1", "@wikimedia/codex-design-tokens": "^2.5.1", "@wikimedia/codex-icons": "^2.5.1", + "fakewiki": "^0.0.13", "vue": "^3.5.13", "vue-router": "^4.5.0" }, diff --git a/scripts/probe-dashpage-recent-changes-signals.ts b/scripts/probe-dashpage-recent-changes-signals.ts new file mode 100644 index 0000000..66a7488 --- /dev/null +++ b/scripts/probe-dashpage-recent-changes-signals.ts @@ -0,0 +1,62 @@ +#!/usr/bin/env npx tsx +/** + * Probe language-agnostic articlequality score deltas for recent edits. + * Run: npx tsx scripts/probe-dashpage-recent-changes-signals.ts + */ + +import { createDashpageRecentChangesWiki } from '../src/lib/fetchDashpageRecentChanges' +import { fetchArticleQualityScore } from '../src/lib/fetchArticleQualityScore' +import { DASHPAGE_RC_API_USER_AGENT } from '../src/lib/dashpageRecentChangesConstants' + +async function sleep(ms: number): Promise { + await new Promise((resolve) => setTimeout(resolve, ms)) +} + +async function main(): Promise { + const wiki = createDashpageRecentChangesWiki() + const deltas: number[] = [] + + console.log('Fetching recent changes (needs review)…') + const rc = await wiki.getRecentChanges({ limit: 12, onlyNeedsReview: true }) + + for (const rev of rc.revisions) { + if (!rev.id || !rev.pageName || rev.pageName.includes(':')) continue + + const parentId = await wiki.getParentRevisionId(rev.pageName, rev.id) + if (parentId == null || parentId <= 0) continue + + const before = await fetchArticleQualityScore(parentId, 'en', DASHPAGE_RC_API_USER_AGENT) + await sleep(300) + const after = await fetchArticleQualityScore(rev.id, 'en', DASHPAGE_RC_API_USER_AGENT) + await sleep(300) + + if (before && after) { + const delta = after.score - before.score + deltas.push(delta) + console.log( + `rev ${rev.id} (${rev.pageName}): before=${before.score.toFixed(4)} after=${after.score.toFixed(4)} delta=${delta.toFixed(4)}`, + ) + } + } + + if (!deltas.length) { + console.log('No deltas collected — keeping default threshold 0.03') + return + } + + const absDeltas = deltas.map(Math.abs).sort((a, b) => a - b) + const median = absDeltas[Math.floor(absDeltas.length / 2)] ?? 0 + const p75 = absDeltas[Math.floor(absDeltas.length * 0.75)] ?? median + const suggested = Math.max(0.02, Math.min(0.05, Math.round(p75 * 100) / 100)) + + console.log('\nSummary:') + console.log(` samples: ${deltas.length}`) + console.log(` |delta| median: ${median.toFixed(4)}`) + console.log(` |delta| p75: ${p75.toFixed(4)}`) + console.log(` suggested display threshold (sprinthackular uses ${1e-6}): any delta > 0`) +} + +main().catch((error) => { + console.error(error) + process.exit(1) +}) diff --git a/scripts/snapshot-wiki-skins.sh b/scripts/snapshot-wiki-skins.sh index 4caef0f..37a3f65 100755 --- a/scripts/snapshot-wiki-skins.sh +++ b/scripts/snapshot-wiki-skins.sh @@ -7,7 +7,7 @@ ROOT="$(cd "$(dirname "$0")/.." && pwd)" OUT_DIR="${1:-$ROOT/src/styles/wiki-content}" mkdir -p "$OUT_DIR" -UA='ProtoWiki-snapshot/0.1 (https://github.com/wikimedia-research/protowiki)' +UA='ProtoWiki-snapshot/0.1 (https://github.com/wikimedia/protowiki)' VECTOR_MODULES='site.styles|skins.vector.styles|ext.cite.styles|mediawiki.skinning.content.parsoid|mediawiki.hlist|mediawiki.ui.button|mediawiki.skinning.interface' MINERVA_MODULES='site.styles|skins.minerva.base.styles|skins.minerva.styles|ext.cite.styles|mediawiki.skinning.content.parsoid|mediawiki.hlist|mediawiki.skinning.interface' diff --git a/src/components/ArticleLive.vue b/src/components/ArticleLive.vue index 02ffd2d..0562c2d 100644 --- a/src/components/ArticleLive.vue +++ b/src/components/ArticleLive.vue @@ -5,6 +5,7 @@ import { CdxMessage, CdxProgressBar } from '@wikimedia/codex' import ArticleRenderer from '@/components/ArticleRenderer.vue' import ArticleWrapper from '@/components/ArticleWrapper.vue' import type { Skin, Theme } from '@/lib/theming' +import { wipeLocalStorage } from '@/lib/wipeLocalStorage' /** Cache of successfully fetched live article HTML (key: host + title). */ type CachedArticleBody = { html: string; liveTitle: string } @@ -29,6 +30,7 @@ function loadFromStorage(key: string): CachedArticleBody | null { if (!raw) return null return JSON.parse(raw) as CachedArticleBody } catch { + wipeLocalStorage() return null } } @@ -131,8 +133,7 @@ async function fetchArticle(title: string) { }) const headers: Record = { Accept: 'text/html; charset=utf-8', - 'Api-User-Agent': - 'ProtoWiki/0.1 (https://github.com/wikimedia-research/protowiki) prototype', + 'Api-User-Agent': 'ProtoWiki/0.1 (https://github.com/wikimedia/protowiki) prototype', } const response = await fetch(url, { headers }) if (!response.ok) { diff --git a/src/components/ChromeHeader.vue b/src/components/ChromeHeader.vue index c87617f..48fe46f 100644 --- a/src/components/ChromeHeader.vue +++ b/src/components/ChromeHeader.vue @@ -96,10 +96,12 @@ function navHas(tool: ChromeNavTool): boolean {