④段整套同步(六节 + P/S/F/J + 模板)+ open-design 移到技能根

一、④段整套同步(用户选候选 A)
- 新增 `references/stage-proto-doc/assets/产品文档模板.html`(16 KB/247 行,从备份拷、转 LF)。
- ④段 SKILL.md 换成备份 15:28 那版,并按模板口径改齐:
  · 「产品文档框架」从「四块+一附录」改成**六节** —— 页面结构/功能清单/使用场景/操作流程/
    跨页与界面状态/待确认与偏离;与模板同构,⛔ 不从空白页重写结构。
  · 编号从 R/S/F 改成 **P 页面/S 场景/F 功能/J 二级功能**,各自唯一、按展示顺序通排。
  · 保留旧版有价值的要求:每项功能补齐 做什么/入口在哪/输入边界/异常与恢复;重点功能三处标红;
    横向流程图每步写清页面/功能/操作/完成判据。
  · 完成标准「七节」→「六节」,自查清单同步换掉「需求」那批条目,补模板与配图两条。
  · 路径 `designs/<项目>/` → `docs/pm/<项目>/ui/`(2 处)。
  · 补回本机那条「每份产出文档开头都要有一张图」的引用(指向主 skill,段内不复述)。
- 主 skill 同步:四段结构表④行、④段沿革、画图小节(④段画页面结构图 + 用户路径)。

二、open-design 移到技能根(用户选候选 A)
- `git mv product-planning/references/stage-delivery/assets/open-design → open-design/`(4178 文件)。
- `.gitignore` 白名单加 `!/open-design/` —— 否则移出去就不再纳入版本控制。
- 引用改 11 处:路径形态 `assets/open-design/...` → `<技能根>/open-design/...`;
  「随段携带的自带件」改称「同根技能」;「路径怎么找」那条改成自带件(段内相对路径)与
  同根技能(`<技能根>/<技能名>/`)两类分开写。
- open-design 自己的 ATTRIBUTION.md 两处同步(它现在与 oil-ui-pro 同层)。
- 副作用(有益):命名闸门读数由 2063 降到 225 —— 此前它把 open-design 里 919 个第三方 md
  当成规则一起扫了;现在只扫本包 23 个 md。已确认④段的 H1 与 4a/4b/4c 子步仍在检查范围内。

三、验收
- check_naming.py --ws E:/ProgramData/AIProject/contentm_agent = 通过 225 / 失败 0 / 提示 27。
- 活文件里 `assets/open-design` 残留 0;工作区 CRLF 文件 0。
This commit is contained in:
admin committed 2026-10-15 21:17:28 +08:00
1 parent fa0a9026c8
commit 5afeb6b78a
4184 files changed
+326 -70

No files matched your search

@@ -0,0 +1,10 @@
# GitHub Dashboard References
These files are examples generated from a public `nexu-io/open-design` dashboard artifact.
- `template.html` — a live-artifact-compatible template using escaped `{{data.path}}` bindings.
- `example-data.json` — compact normalized GitHub dashboard data.
- `artifact-example.json` — minimal daemon create input for a refreshable live artifact.
- `provenance-example.json` — safe provenance notes for public GitHub API sources and transformations.
Use these as implementation references, not mandatory output. The skill may produce a static `index.html` or the live-artifact source set depending on the user's refreshability requirements.
@@ -0,0 +1,15 @@
{
"title": "OpenDesign GitHub Dashboard",
"slug": "open-design-github-dashboard",
"status": "active",
"preview": {
"type": "html",
"entry": "index.html"
},
"document": {
"format": "html_template_v1",
"templatePath": "template.html",
"generatedPreviewPath": "index.html",
"dataPath": "data.json"
}
}
@@ -0,0 +1,138 @@
{
"repository": {
"name": "open-design",
"fullName": "nexu-io/open-design",
"url": "https://github.com/nexu-io/open-design",
"description": "Local-first, open-source alternative to Anthropic's Claude Design. 19 Skills · 71 brand-grade Design Systems · Generate web/desktop/mobile prototypes · slides · images · videos",
"language": "TypeScript",
"license": "Apache-2.0",
"created": "Apr 28, 2026",
"lastUpdated": "May 6, 2026",
"size": "112 MB"
},
"metrics": {
"stars": {
"total": "29,070",
"growth": "2,847"
},
"forks": {
"total": "3,167",
"growth": "218"
},
"contributors": {
"total": "87",
"active": "12"
},
"issues": {
"open": "230",
"total": "450"
},
"pullRequests": {
"open": "5",
"total": "653"
}
},
"charts": {
"starGrowth": [
{ "label": "W1", "height": 45 },
{ "label": "W2", "height": 62 },
{ "label": "W3", "height": 78 },
{ "label": "W4", "height": 100 }
],
"forkTrend": [
{ "height": 35 },
{ "height": 42 },
{ "height": 48 },
{ "height": 55 },
{ "height": 61 },
{ "height": 68 },
{ "height": 74 },
{ "height": 82 },
{ "height": 88 },
{ "height": 95 },
{ "height": 100 }
]
},
"contributors": [
{
"login": "pftom",
"avatar": "https://avatars.githubusercontent.com/u/26423749?v=4",
"contributions": 26
},
{
"login": "lefarcen",
"avatar": "https://avatars.githubusercontent.com/u/20859779?v=4",
"contributions": 18
},
{
"login": "Sid-Qin",
"avatar": "https://avatars.githubusercontent.com/u/201593046?v=4",
"contributions": 17
},
{
"login": "nettee",
"avatar": "https://avatars.githubusercontent.com/u/3953668?v=4",
"contributions": 10
},
{
"login": "alchemistklk",
"avatar": "https://avatars.githubusercontent.com/u/56862773?v=4",
"contributions": 9
}
],
"recentActivity": [
{
"typeText": "PR",
"typeClass": "pr",
"title": "Add Alipay merchant onboarding skill",
"label": "feature",
"labelClass": "feature-pill",
"author": "leilei926524-tech",
"authorAvatar": "https://avatars.githubusercontent.com/u/238133142?v=4",
"updated": "2 hours ago"
},
{
"typeText": "ISSUE",
"typeClass": "issue",
"title": "Add clear success feedback after saving API keys in Settings",
"label": "bug",
"labelClass": "danger-pill",
"author": "shangxinyu1",
"authorAvatar": "https://avatars.githubusercontent.com/u/237175303?v=4",
"updated": "2 hours ago"
},
{
"typeText": "ISSUE",
"typeClass": "issue",
"title": "hermes json-rpc id 2: Invalid params",
"label": "bug",
"labelClass": "danger-pill",
"author": "zlpawn",
"authorAvatar": "https://avatars.githubusercontent.com/u/42241934?v=4",
"updated": "3 hours ago"
},
{
"typeText": "PR",
"typeClass": "pr",
"title": "fix: 修复0.4.0版本聊天窗口宽度溢出问题",
"label": "bug-fix",
"labelClass": "active-pill",
"author": "1119302165",
"authorAvatar": "https://avatars.githubusercontent.com/u/12208097?v=4",
"updated": "4 hours ago"
},
{
"typeText": "ISSUE",
"typeClass": "issue",
"title": "Fix OpenDesign not reading the latest model list from Codex CLI",
"label": "bug",
"labelClass": "danger-pill",
"author": "shangxinyu1",
"authorAvatar": "https://avatars.githubusercontent.com/u/237175303?v=4",
"updated": "5 hours ago"
}
],
"metadata": {
"lastUpdated": "May 6, 2026"
}
}
@@ -0,0 +1,92 @@
{
"sources": [
{
"type": "github_api",
"description": "GitHub REST API v3",
"endpoints": [
"GET /repos/nexu-io/open-design",
"GET /repos/nexu-io/open-design/contributors?per_page=100&page=1",
"GET /search/issues?q=repo:nexu-io/open-design+is:issue",
"GET /search/issues?q=repo:nexu-io/open-design+is:pr"
],
"fetchedAt": "2026-05-06T09:30:00Z"
}
],
"fields": [
{
"path": "repository.fullName",
"source": "GET /repos/nexu-io/open-design",
"field": "full_name"
},
{
"path": "metrics.stars.total",
"source": "GET /repos/nexu-io/open-design",
"field": "stargazers_count"
},
{
"path": "metrics.forks.total",
"source": "GET /repos/nexu-io/open-design",
"field": "forks_count"
},
{
"path": "metrics.contributors.total",
"source": "GET /repos/nexu-io/open-design/contributors?per_page=100&page=N",
"field": "paginated unique contributor count",
"note": "Display value may be capped or labelled as an estimate when only page 1 is available."
},
{
"path": "metrics.issues.total",
"source": "GET /search/issues?q=repo:nexu-io/open-design+is:issue",
"field": "total_count"
},
{
"path": "metrics.pullRequests.total",
"source": "GET /search/issues?q=repo:nexu-io/open-design+is:pr",
"field": "total_count"
},
{
"path": "charts.starGrowth",
"source": "estimated",
"note": "GitHub REST does not expose full historical star deltas; heights are display-normalized from available recent growth signals."
},
{
"path": "charts.forkTrend",
"source": "synthetic",
"note": "Generated as normalized 0-100% chart heights for visual trend preview."
}
],
"transformations": [
{
"step": "Data normalization",
"description": "Converted GitHub API responses to compact dashboard format",
"operations": [
"Formatted large numbers with comma separators",
"Estimated star and fork growth trends and marked them as non-auditable estimates",
"Extracted top 5 contributors by contribution count",
"Selected most recent 5 issues and pull requests",
"Generated normalized chart-height values for star growth and fork trends"
]
},
{
"step": "Privacy filtering",
"description": "Applied safe data practices",
"operations": [
"Preserved only public GitHub profile information",
"Used public avatar URLs",
"Excluded sensitive or internal repository metadata"
]
}
],
"notes": [
"Current repository totals are sourced from public GitHub API endpoints; growth series are explicitly estimated or synthetic as documented in fields[].",
"No authentication tokens or credentials stored",
"Star growth is estimated from available recent growth signals, not directly auditable from GitHub REST alone",
"Fork growth is synthetic for preview purposes",
"Chart heights are normalized percentages for responsive display"
],
"refreshPolicy": {
"recommended": "hourly",
"minInterval": "15 minutes",
"note": "GitHub API has rate limits; recommend caching for production use"
}
}
@@ -0,0 +1,473 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{{data.repository.name}} — GitHub Dashboard</title>
<style>
:root {
--canvas: #f2f2f0;
--surface: #ffffff;
--surface-muted: #fafaf9;
--border: #ececea;
--border-strong: #e2e2df;
--text-primary: #0a0a0a;
--text-secondary: #6b6b6b;
--text-tertiary: #9a9a95;
--active-bg: #e6f4ea;
--active-fg: #1f8a4c;
--pending-bg: #fff6d6;
--pending-fg: #9a7b12;
--feature-bg: #dcebff;
--feature-fg: #2f66c9;
--danger-bg: #fdecec;
--danger-fg: #c0392b;
--green: #34a853;
--amber: #e8a23a;
--red: #d94a3d;
--shadow: 0 1px 2px rgba(10, 10, 10, .04), 0 1px 1px rgba(10, 10, 10, .02);
--radius-card: 16px;
--radius-tile: 12px;
--radius-control: 8px;
font-family: Geist, Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
font-feature-settings: "tnum", "lnum";
}
* { box-sizing: border-box; }
body { margin: 0; background: var(--canvas); color: var(--text-primary); }
.shell { min-height: 100vh; padding: 16px; display: grid; grid-template-columns: 256px 1fr; gap: 16px; }
.sidebar, .main { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-card); box-shadow: var(--shadow); }
.sidebar { padding: 16px; display: flex; flex-direction: column; gap: 22px; }
.brand { height: 48px; display: flex; align-items: center; gap: 10px; font-weight: 600; font-size: 15px; }
.logo { width: 32px; height: 32px; border-radius: 8px; background: linear-gradient(135deg, #2f66c9, #5a8ded); color: white; display: grid; place-items: center; font-size: 18px; font-weight: 600; }
.group-label { display: flex; align-items: center; gap: 8px; color: var(--text-tertiary); font-size: 11px; font-weight: 500; letter-spacing: .02em; text-transform: uppercase; margin-bottom: 8px; margin-top: 4px; }
.dot-ring { width: 14px; height: 14px; border: 1.5px dashed var(--text-tertiary); border-radius: 999px; flex: none; }
.nav { display: grid; gap: 4px; }
.nav-item { min-height: 36px; display: flex; align-items: center; justify-content: space-between; gap: 10px; border-radius: var(--radius-control); padding: 8px 10px; color: var(--text-secondary); font-size: 13px; text-decoration: none; transition: all .15s; }
.nav-item:hover { background: var(--surface-muted); }
.nav-item.active { background: var(--surface-muted); color: var(--text-primary); font-weight: 500; }
.count { border-radius: 999px; padding: 2px 8px; background: var(--surface-muted); color: var(--text-secondary); font-size: 11px; font-weight: 500; }
.main { overflow: hidden; }
.topbar { height: 48px; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; padding: 0 20px; font-size: 14px; }
.topbar-title { display: flex; align-items: center; gap: 10px; }
.topbar-icon { width: 20px; height: 20px; opacity: .7; }
.content { padding: 24px 28px 32px; display: grid; gap: 24px; }
.page-head { display: flex; align-items: end; justify-content: space-between; gap: 16px; }
h1 { margin: 0; font-size: 22px; line-height: 1.25; font-weight: 600; letter-spacing: -.005em; }
.subtitle { margin-top: 6px; color: var(--text-secondary); font-size: 14px; line-height: 1.4; }
.actions { display: flex; gap: 8px; align-items: center; }
button, .button { border: 1px solid var(--border-strong); background: var(--surface); border-radius: var(--radius-control); padding: 8px 14px; color: var(--text-primary); font: inherit; font-size: 12px; cursor: pointer; transition: all .15s; text-decoration: none; display: inline-flex; align-items: center; justify-content: center; }
button:hover, .button:hover { background: var(--surface-muted); }
button.primary, .button.primary { background: var(--text-primary); color: #fff; border-color: var(--text-primary); }
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-card); box-shadow: var(--shadow); padding: 20px; }
.tabs { display: inline-flex; background: var(--surface-muted); border-radius: 12px; padding: 4px; gap: 4px; }
.tab { padding: 6px 12px; border-radius: var(--radius-control); color: var(--text-secondary); font-size: 12px; cursor: pointer; transition: all .15s; border: 1px solid transparent; text-decoration: none; }
.tab.active { background: var(--surface); color: var(--text-primary); border: 1px solid var(--border); box-shadow: var(--shadow); }
.kpis { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 16px; }
.kpi { min-height: 84px; border: 1px solid var(--border); border-radius: var(--radius-tile); background: var(--surface-muted); padding: 14px; display: flex; flex-direction: column; }
.kpi-top { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.glyph { width: 28px; height: 28px; border-radius: 8px; background: var(--surface); border: 1px solid var(--border); display: inline-grid; place-items: center; box-shadow: var(--shadow); font-size: 14px; flex: none; }
.kpi-label { color: var(--text-secondary); font-size: 13px; }
.kpi-num { font-size: 28px; font-weight: 600; line-height: 1.1; margin-top: auto; }
.kpi-trend { font-size: 12px; color: var(--green); margin-top: 4px; font-weight: 500; }
.kpi-trend.down { color: var(--text-tertiary); }
.grid { display: grid; grid-template-columns: 2fr 1fr; gap: 16px; }
.grid-full { display: grid; grid-template-columns: 1fr; gap: 16px; }
.card-title { display: flex; align-items: center; gap: 8px; font-size: 16px; font-weight: 600; margin-bottom: 16px; }
.tick-rule { height: 24px; margin: 8px 0 16px; background: repeating-linear-gradient(90deg, var(--border) 0 1px, transparent 1px 8px); }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
.table-scroll { overflow-x: auto; }
.table-scroll table { min-width: 760px; }
th { text-align: left; padding: 10px 12px; color: var(--text-tertiary); font-size: 11px; font-weight: 500; letter-spacing: .01em; background: var(--surface-muted); text-transform: uppercase; }
td { padding: 14px 12px; border-top: 1px solid var(--border); color: var(--text-secondary); }
td strong { color: var(--text-primary); font-weight: 500; }
.mono { font-family: "Geist Mono", "JetBrains Mono", ui-monospace, monospace; font-size: 12px; }
.pill { display: inline-flex; align-items: center; gap: 6px; border-radius: 999px; padding: 3px 10px; font-size: 11px; font-weight: 500; }
.pill::before { content: ""; width: 6px; height: 6px; border-radius: 999px; background: currentColor; }
.active-pill { background: var(--active-bg); color: var(--active-fg); }
.pending-pill { background: var(--pending-bg); color: var(--pending-fg); }
.feature-pill { background: var(--feature-bg); color: var(--feature-fg); }
.danger-pill { background: var(--danger-bg); color: var(--danger-fg); }
.avatar { width: 28px; height: 28px; border-radius: 999px; border: 1px solid var(--border); background: linear-gradient(135deg, #dcecff, #f8eadb); display: inline-grid; place-items: center; color: var(--text-secondary); font-size: 11px; font-weight: 500; margin-right: 8px; overflow: hidden; flex: none; }
.avatar img { width: 100%; height: 100%; object-fit: cover; }
.contrib { display: grid; gap: 10px; }
.person { display: flex; align-items: center; justify-content: space-between; gap: 10px; border: 1px solid var(--border); border-radius: 12px; padding: 12px; background: var(--surface-muted); }
.person-info { display: flex; align-items: center; gap: 10px; flex: 1; min-width: 0; }
.person-name { font-weight: 500; font-size: 13px; color: var(--text-primary); }
.person-role { font-size: 12px; color: var(--text-secondary); margin-top: 2px; }
.chart-container { position: relative; height: 180px; margin-top: 16px; }
.chart { width: 100%; height: 100%; }
.chart-bars { display: flex; align-items: flex-end; justify-content: space-between; height: 100%; gap: 8px; }
.bar { flex: 1; background: linear-gradient(180deg, var(--green) 0%, #2d8a47 100%); border-radius: 4px 4px 0 0; min-height: 4px; position: relative; transition: all .2s; }
.bar:hover { opacity: .85; }
.bar-label { position: absolute; bottom: -22px; left: 50%; transform: translateX(-50%); font-size: 11px; color: var(--text-tertiary); white-space: nowrap; }
.trend-line { display: flex; align-items: flex-end; height: 100%; gap: 2px; }
.trend-point { flex: 1; background: var(--feature-fg); border-radius: 2px 2px 0 0; min-height: 2px; }
.issue-row { display: flex; align-items: start; gap: 12px; padding: 14px 12px; border-top: 1px solid var(--border); }
.issue-row:first-child { border-top: none; }
.issue-icon { width: 20px; height: 20px; border-radius: 999px; background: var(--active-bg); color: var(--active-fg); display: grid; place-items: center; font-size: 11px; flex: none; margin-top: 2px; }
.issue-icon.pr { background: var(--feature-bg); color: var(--feature-fg); }
.issue-content { flex: 1; min-width: 0; }
.issue-title { font-size: 14px; font-weight: 500; color: var(--text-primary); margin-bottom: 4px; }
.issue-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 12px; color: var(--text-tertiary); margin-top: 6px; }
.issue-meta span { display: flex; align-items: center; gap: 4px; }
.provenance-note { color: var(--text-tertiary); font-size: 12px; line-height: 1.5; padding: 4px 2px; }
@media (max-width: 980px) {
.shell { grid-template-columns: 1fr; }
.kpis { grid-template-columns: repeat(2, 1fr); }
.grid { grid-template-columns: 1fr; }
.sidebar { min-height: auto; }
}
</style>
</head>
<body>
<div class="shell">
<aside class="sidebar" data-od-id="sidebar">
<div class="brand">
<div class="logo">OD</div>
<span>{{data.repository.name}}</span>
</div>
<section>
<div class="group-label"><span class="dot-ring"></span> Repository</div>
<div class="nav">
<a href="#overview" class="nav-item active">Overview</a>
<a href="#activity" class="nav-item">Activity <span class="count">{{data.metrics.pullRequests.open}}</span></a>
<a href="#contributors" class="nav-item">Contributors <span class="count">{{data.metrics.contributors.total}}</span></a>
<a href="#community" class="nav-item">Community</a>
</div>
</section>
<section>
<div class="group-label"><span class="dot-ring"></span> Metrics</div>
<div class="nav">
<a href="#growth-chart" class="nav-item">Stars Growth</a>
<a href="#fork-trend" class="nav-item">Fork Activity</a>
<a href="#activity" class="nav-item">Issue Trends</a>
<a href="#activity" class="nav-item">PR Velocity</a>
</div>
</section>
<section>
<div class="group-label"><span class="dot-ring"></span> Quick Links</div>
<div class="nav">
<a href="{{data.repository.url}}" class="nav-item">GitHub Repository</a>
<a href="{{data.repository.url}}#readme" class="nav-item">Documentation</a>
<a href="{{data.repository.url}}/discussions" class="nav-item">Discussions</a>
</div>
</section>
</aside>
<main class="main">
<div class="topbar" data-od-id="topbar">
<div class="topbar-title">
<svg class="topbar-icon" fill="currentColor" viewBox="0 0 16 16">
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/>
</svg>
<span>{{data.repository.name}} Dashboard</span>
</div>
<div class="actions">
<button>{{data.metadata.lastUpdated}}</button>
<button>⟳ Refresh</button>
</div>
</div>
<div class="content">
<header class="page-head" data-od-id="repo-header" id="overview">
<div>
<h1>{{data.repository.fullName}}</h1>
<div class="subtitle">{{data.repository.description}}</div>
</div>
<div class="actions">
<a class="button" href="{{data.repository.url}}">View on GitHub →</a>
</div>
</header>
<section class="card">
<div class="tabs" role="tablist" aria-label="Dashboard sections">
<a href="#overview" class="tab active" role="tab">Metrics</a>
<a href="#activity" class="tab" role="tab">Activity</a>
<a href="#contributors" class="tab" role="tab">Contributors</a>
<a href="#community" class="tab" role="tab">Community</a>
</div>
<div class="kpis" style="margin-top:16px" data-od-id="kpi-strip">
<div class="kpi">
<div class="kpi-top">
<span class="glyph">⭐</span>
<span class="kpi-label">Stars</span>
</div>
<div class="kpi-num">{{data.metrics.stars.total}}</div>
<div class="kpi-trend">+{{data.metrics.stars.growth}} this week</div>
</div>
<div class="kpi">
<div class="kpi-top">
<span class="glyph">⑂</span>
<span class="kpi-label">Forks</span>
</div>
<div class="kpi-num">{{data.metrics.forks.total}}</div>
<div class="kpi-trend">+{{data.metrics.forks.growth}} this week</div>
</div>
<div class="kpi">
<div class="kpi-top">
<span class="glyph">◎</span>
<span class="kpi-label">Contributors</span>
</div>
<div class="kpi-num">{{data.metrics.contributors.total}}</div>
<div class="kpi-trend">{{data.metrics.contributors.active}} active</div>
</div>
<div class="kpi">
<div class="kpi-top">
<span class="glyph">◌</span>
<span class="kpi-label">Open Issues</span>
</div>
<div class="kpi-num">{{data.metrics.issues.open}}</div>
<div class="kpi-trend down">{{data.metrics.issues.total}} total</div>
</div>
<div class="kpi">
<div class="kpi-top">
<span class="glyph">↑</span>
<span class="kpi-label">Pull Requests</span>
</div>
<div class="kpi-num">{{data.metrics.pullRequests.open}}</div>
<div class="kpi-trend down">{{data.metrics.pullRequests.total}} total</div>
</div>
</div>
</section>
<section class="grid">
<div class="card" data-od-id="growth-chart" id="growth-chart">
<div class="card-title"><span class="dot-ring"></span> Star Growth (Last 30 Days)</div>
<div class="chart-container">
<div class="chart-bars">
<div class="bar" style="height: {{data.charts.starGrowth.0.height}}%;">
<span class="bar-label">{{data.charts.starGrowth.0.label}}</span>
</div>
<div class="bar" style="height: {{data.charts.starGrowth.1.height}}%;">
<span class="bar-label">{{data.charts.starGrowth.1.label}}</span>
</div>
<div class="bar" style="height: {{data.charts.starGrowth.2.height}}%;">
<span class="bar-label">{{data.charts.starGrowth.2.label}}</span>
</div>
<div class="bar" style="height: {{data.charts.starGrowth.3.height}}%;">
<span class="bar-label">{{data.charts.starGrowth.3.label}}</span>
</div>
</div>
</div>
</div>
<aside class="card" data-od-id="contributors" id="contributors">
<div class="card-title"><span class="dot-ring"></span> Top Contributors</div>
<div class="tick-rule"></div>
<div class="contrib">
<div class="person">
<div class="person-info">
<div class="avatar">
<img src="{{data.contributors.0.avatar}}" alt="{{data.contributors.0.login}}" />
</div>
<div>
<div class="person-name">{{data.contributors.0.login}}</div>
<div class="person-role">{{data.contributors.0.contributions}} contributions</div>
</div>
</div>
<span class="pill pending-pill">{{data.contributors.0.contributions}}</span>
</div>
<div class="person">
<div class="person-info">
<div class="avatar">
<img src="{{data.contributors.1.avatar}}" alt="{{data.contributors.1.login}}" />
</div>
<div>
<div class="person-name">{{data.contributors.1.login}}</div>
<div class="person-role">{{data.contributors.1.contributions}} contributions</div>
</div>
</div>
<span class="pill pending-pill">{{data.contributors.1.contributions}}</span>
</div>
<div class="person">
<div class="person-info">
<div class="avatar">
<img src="{{data.contributors.2.avatar}}" alt="{{data.contributors.2.login}}" />
</div>
<div>
<div class="person-name">{{data.contributors.2.login}}</div>
<div class="person-role">{{data.contributors.2.contributions}} contributions</div>
</div>
</div>
<span class="pill pending-pill">{{data.contributors.2.contributions}}</span>
</div>
<div class="person">
<div class="person-info">
<div class="avatar">
<img src="{{data.contributors.3.avatar}}" alt="{{data.contributors.3.login}}" />
</div>
<div>
<div class="person-name">{{data.contributors.3.login}}</div>
<div class="person-role">{{data.contributors.3.contributions}} contributions</div>
</div>
</div>
<span class="pill pending-pill">{{data.contributors.3.contributions}}</span>
</div>
<div class="person">
<div class="person-info">
<div class="avatar">
<img src="{{data.contributors.4.avatar}}" alt="{{data.contributors.4.login}}" />
</div>
<div>
<div class="person-name">{{data.contributors.4.login}}</div>
<div class="person-role">{{data.contributors.4.contributions}} contributions</div>
</div>
</div>
<span class="pill pending-pill">{{data.contributors.4.contributions}}</span>
</div>
</div>
</aside>
</section>
<section class="grid-full">
<div class="card" data-od-id="activity" id="activity">
<div class="card-title"><span class="dot-ring"></span> Recent Activity</div>
<div class="table-scroll">
<table>
<thead>
<tr>
<th style="width: 50px;">Type</th>
<th>Title</th>
<th style="width: 120px;">Status</th>
<th style="width: 140px;">Author</th>
<th style="width: 100px;">Updated</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span class="issue-icon {{data.recentActivity.0.typeClass}}">{{data.recentActivity.0.typeText}}</span>
</td>
<td><strong>{{data.recentActivity.0.title}}</strong></td>
<td>
<span class="pill {{data.recentActivity.0.labelClass}}">{{data.recentActivity.0.label}}</span>
</td>
<td>
<div style="display: flex; align-items: center;">
<span class="avatar" style="margin-right: 8px;">
<img src="{{data.recentActivity.0.authorAvatar}}" alt="{{data.recentActivity.0.author}}" />
</span>
<span>{{data.recentActivity.0.author}}</span>
</div>
</td>
<td class="mono" style="color: var(--text-tertiary);">{{data.recentActivity.0.updated}}</td>
</tr>
<tr>
<td><span class="issue-icon {{data.recentActivity.1.typeClass}}">{{data.recentActivity.1.typeText}}</span></td>
<td><strong>{{data.recentActivity.1.title}}</strong></td>
<td><span class="pill {{data.recentActivity.1.labelClass}}">{{data.recentActivity.1.label}}</span></td>
<td>
<div style="display: flex; align-items: center;">
<span class="avatar" style="margin-right: 8px;"><img src="{{data.recentActivity.1.authorAvatar}}" alt="{{data.recentActivity.1.author}}" /></span>
<span>{{data.recentActivity.1.author}}</span>
</div>
</td>
<td class="mono" style="color: var(--text-tertiary);">{{data.recentActivity.1.updated}}</td>
</tr>
<tr>
<td><span class="issue-icon {{data.recentActivity.2.typeClass}}">{{data.recentActivity.2.typeText}}</span></td>
<td><strong>{{data.recentActivity.2.title}}</strong></td>
<td><span class="pill {{data.recentActivity.2.labelClass}}">{{data.recentActivity.2.label}}</span></td>
<td>
<div style="display: flex; align-items: center;">
<span class="avatar" style="margin-right: 8px;"><img src="{{data.recentActivity.2.authorAvatar}}" alt="{{data.recentActivity.2.author}}" /></span>
<span>{{data.recentActivity.2.author}}</span>
</div>
</td>
<td class="mono" style="color: var(--text-tertiary);">{{data.recentActivity.2.updated}}</td>
</tr>
<tr>
<td><span class="issue-icon {{data.recentActivity.3.typeClass}}">{{data.recentActivity.3.typeText}}</span></td>
<td><strong>{{data.recentActivity.3.title}}</strong></td>
<td><span class="pill {{data.recentActivity.3.labelClass}}">{{data.recentActivity.3.label}}</span></td>
<td>
<div style="display: flex; align-items: center;">
<span class="avatar" style="margin-right: 8px;"><img src="{{data.recentActivity.3.authorAvatar}}" alt="{{data.recentActivity.3.author}}" /></span>
<span>{{data.recentActivity.3.author}}</span>
</div>
</td>
<td class="mono" style="color: var(--text-tertiary);">{{data.recentActivity.3.updated}}</td>
</tr>
<tr>
<td><span class="issue-icon {{data.recentActivity.4.typeClass}}">{{data.recentActivity.4.typeText}}</span></td>
<td><strong>{{data.recentActivity.4.title}}</strong></td>
<td><span class="pill {{data.recentActivity.4.labelClass}}">{{data.recentActivity.4.label}}</span></td>
<td>
<div style="display: flex; align-items: center;">
<span class="avatar" style="margin-right: 8px;"><img src="{{data.recentActivity.4.authorAvatar}}" alt="{{data.recentActivity.4.author}}" /></span>
<span>{{data.recentActivity.4.author}}</span>
</div>
</td>
<td class="mono" style="color: var(--text-tertiary);">{{data.recentActivity.4.updated}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
<section class="grid">
<div class="card" id="fork-trend">
<div class="card-title"><span class="dot-ring"></span> Fork Trend (Last 30 Days)</div>
<div class="chart-container">
<div class="trend-line">
<div class="trend-point" style="height: {{data.charts.forkTrend.0.height}}%;"></div>
<div class="trend-point" style="height: {{data.charts.forkTrend.1.height}}%;"></div>
<div class="trend-point" style="height: {{data.charts.forkTrend.2.height}}%;"></div>
<div class="trend-point" style="height: {{data.charts.forkTrend.3.height}}%;"></div>
<div class="trend-point" style="height: {{data.charts.forkTrend.4.height}}%;"></div>
<div class="trend-point" style="height: {{data.charts.forkTrend.5.height}}%;"></div>
<div class="trend-point" style="height: {{data.charts.forkTrend.6.height}}%;"></div>
<div class="trend-point" style="height: {{data.charts.forkTrend.7.height}}%;"></div>
<div class="trend-point" style="height: {{data.charts.forkTrend.8.height}}%;"></div>
<div class="trend-point" style="height: {{data.charts.forkTrend.9.height}}%;"></div>
<div class="trend-point" style="height: {{data.charts.forkTrend.10.height}}%;"></div>
</div>
</div>
</div>
<div class="card">
<div class="card-title"><span class="dot-ring"></span> Repository Stats</div>
<div class="tick-rule"></div>
<table>
<tbody>
<tr>
<td><strong>Primary Language</strong></td>
<td style="text-align: right;">{{data.repository.language}}</td>
</tr>
<tr>
<td><strong>License</strong></td>
<td style="text-align: right;">{{data.repository.license}}</td>
</tr>
<tr>
<td><strong>Created</strong></td>
<td style="text-align: right;">{{data.repository.created}}</td>
</tr>
<tr>
<td><strong>Last Updated</strong></td>
<td style="text-align: right;">{{data.repository.lastUpdated}}</td>
</tr>
<tr>
<td><strong>Repository Size</strong></td>
<td style="text-align: right;">{{data.repository.size}}</td>
</tr>
</tbody>
</table>
</div>
</section>
<footer class="provenance-note" data-od-id="provenance">
Updated {{data.metadata.lastUpdated}} from public GitHub API fields. Estimated trend data is documented in provenance.json.
</footer>
</div>
</main>
</div>
</body>
</html>