docs: make the top-level README product-first

This commit is contained in:
Tianyi Cui
2026-07-23 00:15:44 +08:00
parent 30a1ea7cec
commit ef325b02fa
14 changed files with 172 additions and 635 deletions

View File

@@ -0,0 +1,6 @@
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write
2026-07-22-product-first-root-readme.md: 3d295d39119e9dd70af53cef68948d928a69120a
2026-07-22-product-first-root-readme.zh.md: ebfa0904536fe409873afa5dc88b76d4f7ee9dc7

View File

@@ -0,0 +1,29 @@
# Agent Note: Product-first root README
Status: implemented
English | [中文](2026-07-22-product-first-root-readme.zh.md)
## Problem
The root README is the first page for people evaluating DeepSeek Harness, but SDK-first contributor detail competes with the shortest path from product identity to installation and launch. Exhaustive package inventories, architecture diagrams, demos, and duplicated technical explanations also age faster than the interfaces they describe.
## Decision
The root README presents DeepSeek Harness as an installable coding agent first. It names the SDK foundation, keeps the supported one-line installer, and puts the Web UI, TUI, and headless entry points before architecture and contributor material.
The capability overview stays compact: it identifies the familiar built-in coding capabilities, makes plugin extensibility the distinguishing design, and presents Code Mode and the self-referential Cordis tools as explicit opt-ins. Detailed contracts remain at their owning documentation and are linked instead of copied into the root README.
The English and Chinese READMEs share the product, installation, capability, development, and license structure. Their community sections intentionally follow the primary channel for each language audience: Twitter in English and the WeChat community QR code in Chinese. The QR code is the only retained README media because it is a functional entry point rather than product decoration.
## Alternatives considered
**Keep an SDK-first contributor README.** This makes the repository architecture visible immediately, but it delays the answer to what the product is and how to run it. Contributor orientation remains available through the development and architecture links.
**Adopt a full marketing page with badges, screenshots, an architecture diagram, a package catalog, and tutorials.** This provides more material on the landing page, but duplicates fast-moving facts and creates media maintenance work before the product surface is stable.
**Use the same community channel in both languages.** Exact channel symmetry is simpler, but it is less useful when the two language audiences gather in different places. The technical content remains paired while the community destination is audience-specific.
## Consequences
A new reader reaches a runnable interface quickly and can follow stable links for deeper SDK details. The root README stays small enough to update whenever the installer or CLI surface changes. Rich media, package inventories, and long-form tutorials remain outside this entry point until they have a durable owner and maintenance path.

View File

@@ -0,0 +1,29 @@
# Agent Note: 以产品为先的根 README
Status: implemented
[English](2026-07-22-product-first-root-readme.md) | 中文
## 问题
根 README 是评估 DeepSeek Harness 的读者最先看到的页面,但以 SDK 为先的贡献者信息会挤占从产品定位直达安装与启动的最短路径。详尽的包package清单、架构图、演示以及重复的技术说明也比其描述的接口更快失效。
## 决策
根 README 首先将 DeepSeek Harness 呈现为一款可安装的 coding agent编程智能体。它说明产品基于 SDK保留受支持的单行安装命令并将 Web UI、TUI 和 Headless 入口置于架构与贡献者资料之前。
功能概览保持简洁:它说明常见的内置编程功能,突出插件扩展性这一差异化设计,并明确 Code Mode 和自指 Cordis 工具都需显式启用。详细契约留在各自的权威文档中;根 README 只提供链接,不复制内容。
中英文 README 采用相同的产品、安装、功能、开发和许可证结构。社区章节则有意采用各语言读者的主要渠道:英文版指向 Twitter中文版提供微信社区二维码。二维码是 README 中唯一保留的媒体,因为它是实际入口,而非产品装饰。
## 备选方案
**保留以 SDK 为先的贡献者 README。** 这能让读者立即看到仓库架构,却延后了“产品是什么、如何运行”这两个答案。贡献者仍可通过开发与架构链接获得所需指引。
**采用包含徽章、截图、架构图、包清单和教程的完整营销页面。** 这会让落地页承载更多材料,却会重复易变事实,并在产品接口稳定前增加媒体维护工作。
**两种语言采用同一个社区渠道。** 渠道完全对称更简单,但当两种语言的读者聚集在不同平台时,这种做法实用性更低。技术内容保持配对,社区目的地则按读者群体选择。
## 影响
新读者可以快速进入可运行的界面,并通过稳定链接了解更深入的 SDK 细节。根 README 足够精简,可在安装器或 CLI 接口变化时及时更新。在富媒体、包清单和长篇教程拥有持久的负责方与维护路径之前,它们不进入这个产品入口。

View File

@@ -1,158 +0,0 @@
---
name: dsh-arch-diagram
description: Regenerate the DeepSeek Harness "System overview" architecture PNGs (English + Chinese) that the top-level README embeds. Reflects the current state of packages/* and docs/architecture.md. Use when the codebase adds/removes/renames services and the README diagram must be refreshed.
---
# dsh-arch-diagram
Produces `assets/arch-en.png` and `assets/arch-zh.png` in this repo — the two hero images embedded at the top of `README.md` and `README.zh.md`.
The pipeline is HTML + Chrome headless, so text quality, layout, and connector geometry are **deterministic** — every rerun produces the same output regardless of model.
Aesthetic is locked to the DeepSeek brand: light blue gradient background, brand-blue Cordis bar, sans-serif everywhere, no serif / no italic / no hand-drawn feel.
---
## When to use
- User asks to "regenerate" or "refresh" the Harness architecture diagram
- User points out `packages/` has changed (new services, renames) and the README diagram is stale
- User just added a new `packages/<family>/` or a new `ctx.*` service and wants the diagram to reflect it
## When NOT to use
- User wants a different diagram (Code Mode, Workflow fanout, agent lifecycle) — those belong in `docs/` and need their own skill
- User wants a different visual aesthetic (dark mode, hand-drawn, editorial-serif) — this skill is locked to DeepSeek brand
---
## Workflow
### 1. Enumerate current services from the repo
The diagram is grounded in two lists that live in the docs:
- **Default Services** — from `packages/core/*` and `docs/architecture.md`'s "Default Services" table. As of last refresh: `ctx.sessions`, `ctx.systemPrompt`, `ctx.tools`, `ctx.agents`, `ctx.agentLoop`.
- **Capability Services** — from the non-core capability packages and `docs/architecture.md`'s "Capability Services" table. As of last refresh: `ctx.llm`, `ctx.bash`, `ctx.sandbox`, `ctx.codeRuntime`, `ctx.fs`, `ctx.skills`, `ctx.web`, `ctx.compact`, `ctx.subagents`, `ctx.workflows`, `ctx.sessionPersistence`, `ctx.sessionQuery`.
**Do this**:
1. Read `docs/architecture.md`
2. Extract the two `ctx.*` tables verbatim
3. Cross-check against `packages/`: services live under `packages/core/*` (defaults) or under `packages/<family>/<package>/` (capabilities). The inner package dir mirrors the npm name without the `@deepseek-ai/dsh-` prefix — e.g. `packages/session-query/session-query/` publishes `@deepseek-ai/dsh-session-query`. Never assume the inner dir carries a `dsh-` prefix.
### 2. Diff against the current HTML templates
Read `harness-arch-en.html` and `harness-arch-zh.html` in this skill directory. Pull out the currently-rendered `ctx.*` names. Report the diff:
```
Default services: no change
Capability services: + ctx.<new>, ctx.<removed>, ↻ ctx.<renamed>
```
### 3. Update the templates
If there are changes, edit both HTML files in place. Each card is one line:
```html
<div class="card"><span class="name">ctx.something</span><span class="desc">short description</span></div>
```
For a **new** service:
- Description is **short** — 24 words (EN), 36 chars (ZH)
- Ground the description in what the package's README or its `ctx.<name>.register()` **actually** does. Do NOT paraphrase from an abstract or invent capabilities the code doesn't have.
- Add the card in **both** languages, in docs order.
For a **removed** service: delete the card in both files.
For a **renamed** service: update the `.name` span in both files.
**Do not touch the layout**. Rows are:
- Top row (`row top`): exactly 5 default-service cards
- Bottom row (`row bottom`): 12 capability-service cards
If the capability count grows past ~13, the row gets visually tight. Stop and ask the user before shrinking fonts or wrapping to two rows.
### 4. Render to PNG
```bash
bash .agents/skills/dsh-arch-diagram/render.sh
```
Default output: `<repo>/assets/arch-en.png` and `<repo>/assets/arch-zh.png` — the paths that `README.md` and `README.zh.md` already reference.
Pass an alternate directory as `$1` to write elsewhere. `CHROME` and `PORT` env vars override the browser path and http.server port.
The script:
- Spins up a temporary `python3 -m http.server` on `127.0.0.1` (needed so Google Fonts CDN loads reliably in Chrome headless)
- Runs Chrome headless twice at `--force-device-scale-factor=2 --window-size=1536,580`
- Writes two 3072×1160 PNGs (~600 KB each)
- Tears down the server
### 5. Verify by eye — mandatory, do not skip
After rendering, **open each PNG and visually check every item** in this list. Do not report the diagram as done without going through it.
- [ ] Top-row card count matches the Default Services list you extracted in §1, every name rendered in full (no truncation on the longest, e.g. `ctx.systemPrompt` / `ctx.agentLoop`)
- [ ] Bottom-row card count matches the Capability Services list you extracted in §1, every name in full (especially the longest, e.g. `ctx.sessionPersistence`)
- [ ] Every card has a description underneath, and the description matches what the code does (not made up)
- [ ] Bar reads `Cordis · microkernel (vendored)` (EN) / `Cordis · 微内核 (vendored)` (ZH)
- [ ] Number of vertical connector lines equals (top-row cards + bottom-row cards) from §1. All straight vertical, all parallel, each reaching the horizontal center of its card
- [ ] `cordis.yml` sidebar visible on the right; dashed arrow points left into the bar
- [ ] `deployment leaf` / `部署清单` and `picks which plugins load` / `决定哪些插件加载` are readable and NOT crossed through by any connector line
- [ ] Chinese descriptions render as CJK glyphs, not `□` tofu boxes (means fonts loaded)
- [ ] No large empty gradient area at the bottom of the image — if there is, tune `--window-size` in `render.sh`
If any check fails: fix the CSS or template, re-run `render.sh`, re-check. Do not report "done" on first render without visually confirming.
---
## Design system (locked — do not modify without explicit user request)
Colors:
- Background: `linear-gradient(135deg, #ffffff 0%, #e8effc 100%)`
- Brand blue (Cordis bar + connectors): `#4a6ef5`
- Ink text: `#1a1a1a`
- Muted text: `#8a8f9c`
- Card border: `#dde3ef`
- Card fill: `#ffffff`
Typography (**sans-serif only** — never serif, never italic):
- English title & body: **Inter** (Google Fonts)
- Chinese title & body: **Noto Sans SC** (Google Fonts) with `PingFang SC` local fallback
- Code labels (`ctx.*`, `cordis.yml`, `vendored`): **JetBrains Mono** (Google Fonts)
Layout:
- `.page` max-width 1560 px, centered
- `.bus-row`, `.row.top`, `.row.bottom` all 96% width, centered
- Top row: `flex: 1` on each card (equal widths)
- Bottom row: `justify-content: space-between` + `flex: 0 0 auto` on each card — cards keep their intrinsic (nowrap) width and adjacent card backgrounds cannot clip a description
- Bus: `#4a6ef5` filled, 60 px tall, 8 px radius
- `cordis.yml` sidebar `position: absolute` at `left: calc(100% + 20px)` of `.bus-row`, width 130 px
- All connectors: CSS `::before` / `::after` pseudo-elements, 2 px wide, 40 px tall, `#4a6ef5`, centered via `left: 50%; transform: translateX(-50%)` — this is what guarantees pixel-perfect vertical parallel lines regardless of card content
Rendering:
- Chrome headless `--force-device-scale-factor=2`
- `--window-size=1820,580` → output is 3640×1160 (aspect ~3.14:1, wider than square-ish so a 12-card capability row fits without truncation)
- Local http.server on `127.0.0.1` so CDN fonts load cleanly
---
## Files in this skill
- `SKILL.md` — this file
- `harness-arch.css` — shared design system (colors, fonts, layout, connectors)
- `harness-arch-en.html` — English template
- `harness-arch-zh.html` — Chinese template
- `render.sh` — Chrome headless renderer
Templates are self-contained. Fonts load from Google Fonts CDN; no local font files.
---
## Rules I keep breaking (and shouldn't)
1. **Verify the output by looking at it.** Don't report "done" and move on — actually inspect each PNG and check every item in §5.
2. **Ground service descriptions in the code, not the docs' abstract, not the marketing copy.** If unsure what a package does, read its `src/` or the `ctx.<name>.register()` block.
3. **Don't touch layout unless asked.** 96% row/bar width, 40 px connector height, and 60 px bar height are all tuned. Card counts grow one at a time; once the bottom row starts to visibly overflow again (adjacent card backgrounds clipping a description, or the `cordis.yml` sidebar falling outside the render viewport), stop and ask before shrinking fonts, widening the viewport further, or wrapping to two rows.
4. **Never introduce a serif font or italic.** Not for titles, not for annotations, not "to make it feel editorial." This diagram is DeepSeek brand: sans-serif, upright, only.

View File

@@ -1,66 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1536, initial-scale=1.0">
<title>DeepSeek Harness · Architecture</title>
<link rel="stylesheet" href="harness-arch.css">
</head>
<body>
<div class="page">
<p class="eyebrow">ARCHITECTURE</p>
<h1>System overview</h1>
<div class="diagram">
<p class="section-label top">DEFAULT SERVICES</p>
<div class="row top">
<div class="card"><span class="name">ctx.sessions</span><span class="desc">event-sourced log</span></div>
<div class="card"><span class="name">ctx.systemPrompt</span><span class="desc">prompt assembly</span></div>
<div class="card"><span class="name">ctx.tools</span><span class="desc">tool registry &amp; pipeline</span></div>
<div class="card"><span class="name">ctx.agents</span><span class="desc">agent handles &amp; events</span></div>
<div class="card"><span class="name">ctx.agentLoop</span><span class="desc">ReAct control loop</span></div>
</div>
<div class="bus-row">
<div class="bus">
<span class="core">Cordis</span>
<span class="dot">·</span>
<span class="core">microkernel</span>
<span class="vendored">(vendored)</span>
</div>
<div class="yml-side">
<div class="yml-arrow">
<svg viewBox="0 0 30 12" width="30" height="12" xmlns="http://www.w3.org/2000/svg">
<line x1="30" y1="6" x2="8" y2="6" stroke="#8a8f9c" stroke-width="1.2" stroke-dasharray="3 3"/>
<polyline points="8,3 2,6 8,9" fill="none" stroke="#8a8f9c" stroke-width="1.2" stroke-linejoin="round" stroke-linecap="round"/>
</svg>
</div>
<div class="yml-box">
<div class="file">cordis.yml</div>
<div class="sub">deployment leaf</div>
</div>
<div class="yml-note">picks which plugins load</div>
</div>
</div>
<div class="row bottom">
<div class="card"><span class="name">ctx.llm</span><span class="desc">LLM provider adapter</span></div>
<div class="card"><span class="name">ctx.bash</span><span class="desc">shell execution</span></div>
<div class="card"><span class="name">ctx.sandbox</span><span class="desc">process confinement</span></div>
<div class="card"><span class="name">ctx.codeRuntime</span><span class="desc">JS worker runtime</span></div>
<div class="card"><span class="name">ctx.fs</span><span class="desc">filesystem + policy</span></div>
<div class="card"><span class="name">ctx.skills</span><span class="desc">reusable skills</span></div>
<div class="card"><span class="name">ctx.web</span><span class="desc">search &amp; fetch</span></div>
<div class="card"><span class="name">ctx.compact</span><span class="desc">context compression</span></div>
<div class="card"><span class="name">ctx.subagents</span><span class="desc">spawn / fork / ACP</span></div>
<div class="card"><span class="name">ctx.workflows</span><span class="desc">dynamic orchestration</span></div>
<div class="card"><span class="name">ctx.sessionPersistence</span><span class="desc">JSONL / SQLite</span></div>
<div class="card"><span class="name">ctx.sessionQuery</span><span class="desc">unified log reads</span></div>
</div>
<p class="section-label bottom">CAPABILITY SERVICES</p>
</div>
</div>
</body>
</html>

View File

@@ -1,66 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1536, initial-scale=1.0">
<title>DeepSeek Harness · 架构</title>
<link rel="stylesheet" href="harness-arch.css">
</head>
<body>
<div class="page">
<p class="eyebrow cn">架 构</p>
<h1 class="cn">系统一览</h1>
<div class="diagram">
<p class="section-label top cn">默 认 服 务</p>
<div class="row top">
<div class="card"><span class="name">ctx.sessions</span><span class="desc cn">事件溯源日志</span></div>
<div class="card"><span class="name">ctx.systemPrompt</span><span class="desc cn">系统提示词组装</span></div>
<div class="card"><span class="name">ctx.tools</span><span class="desc cn">工具注册与执行</span></div>
<div class="card"><span class="name">ctx.agents</span><span class="desc cn">Agent 实例与事件</span></div>
<div class="card"><span class="name">ctx.agentLoop</span><span class="desc cn">ReAct 控制循环</span></div>
</div>
<div class="bus-row">
<div class="bus cn">
<span class="core">Cordis</span>
<span class="dot">·</span>
<span class="core">微内核</span>
<span class="vendored">(vendored)</span>
</div>
<div class="yml-side">
<div class="yml-arrow">
<svg viewBox="0 0 30 12" width="30" height="12" xmlns="http://www.w3.org/2000/svg">
<line x1="30" y1="6" x2="8" y2="6" stroke="#8a8f9c" stroke-width="1.2" stroke-dasharray="3 3"/>
<polyline points="8,3 2,6 8,9" fill="none" stroke="#8a8f9c" stroke-width="1.2" stroke-linejoin="round" stroke-linecap="round"/>
</svg>
</div>
<div class="yml-box">
<div class="file">cordis.yml</div>
<div class="sub cn">部署清单</div>
</div>
<div class="yml-note cn">决定哪些插件加载</div>
</div>
</div>
<div class="row bottom">
<div class="card"><span class="name">ctx.llm</span><span class="desc cn">模型适配层</span></div>
<div class="card"><span class="name">ctx.bash</span><span class="desc cn">命令行执行</span></div>
<div class="card"><span class="name">ctx.sandbox</span><span class="desc cn">进程隔离</span></div>
<div class="card"><span class="name">ctx.codeRuntime</span><span class="desc cn">JS 运行时</span></div>
<div class="card"><span class="name">ctx.fs</span><span class="desc cn">文件读写</span></div>
<div class="card"><span class="name">ctx.skills</span><span class="desc cn">可复用技能</span></div>
<div class="card"><span class="name">ctx.web</span><span class="desc cn">网页搜索抓取</span></div>
<div class="card"><span class="name">ctx.compact</span><span class="desc cn">上下文压缩</span></div>
<div class="card"><span class="name">ctx.subagents</span><span class="desc cn">子智能体</span></div>
<div class="card"><span class="name">ctx.workflows</span><span class="desc cn">动态编排</span></div>
<div class="card"><span class="name">ctx.sessionPersistence</span><span class="desc cn">会话持久化</span></div>
<div class="card"><span class="name">ctx.sessionQuery</span><span class="desc cn">会话日志查询</span></div>
</div>
<p class="section-label bottom cn">能 力 服 务</p>
</div>
</div>
</body>
</html>

View File

@@ -1,220 +0,0 @@
/* DeepSeek brand — bone-white + brand-blue, all sans-serif, no italic, no serif. */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Noto+Sans+SC:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
:root {
--bg-top: #ffffff;
--bg-bot: #e8effc;
--ink: #1a1a1a;
--muted: #8a8f9c;
--card-bd: #dde3ef;
--card-bg: #ffffff;
--brand: #4a6ef5;
--brand-soft: #dbe4fe;
--sans: 'Inter', 'Noto Sans SC', 'PingFang SC', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
--cn: 'Noto Sans SC', 'PingFang SC', 'Inter', -apple-system, sans-serif;
--mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
}
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: var(--sans);
color: var(--ink);
background: linear-gradient(135deg, var(--bg-top) 0%, var(--bg-bot) 100%);
padding: 40px 64px 32px;
-webkit-font-smoothing: antialiased;
font-feature-settings: "kern" 1, "liga" 1, "cv02" 1, "cv11" 1;
}
.page {
max-width: 1560px;
margin: 0 auto;
}
/* ── header ─────────────────────────────────────────── */
.eyebrow {
font-family: var(--sans);
font-size: 12px;
font-weight: 500;
letter-spacing: 0.22em;
color: var(--muted);
text-transform: uppercase;
margin-bottom: 10px;
}
.eyebrow.cn { font-family: var(--cn); letter-spacing: 0.4em; text-transform: none; }
h1 {
font-family: var(--sans);
font-size: 40px;
font-weight: 600;
letter-spacing: -0.02em;
line-height: 1.15;
color: var(--ink);
margin-bottom: 88px;
}
h1.cn { font-family: var(--cn); letter-spacing: 0.02em; font-weight: 600; }
/* ── diagram frame ──────────────────────────────────── */
.diagram { position: relative; }
.section-label {
font-family: var(--sans);
font-size: 11px;
font-weight: 500;
letter-spacing: 0.22em;
color: var(--muted);
text-transform: uppercase;
text-align: center;
margin-bottom: 20px;
}
.section-label.cn { font-family: var(--cn); letter-spacing: 0.4em; text-transform: none; font-size: 12px; }
.section-label.bottom { margin: 20px 0 0; }
/* ── card rows ──────────────────────────────────────── */
.row {
display: flex;
gap: 12px;
justify-content: center;
width: 96%;
margin: 0 auto;
position: relative;
}
.row.top .card { flex: 1; }
.row.bottom {
gap: 0;
justify-content: space-between;
}
/* flex: 0 0 auto so cards keep their intrinsic (nowrap) width and
neighbouring card backgrounds cannot clip a description. */
.row.bottom .card { flex: 0 0 auto; }
.card {
background: var(--card-bg);
border: 1px solid var(--card-bd);
border-radius: 6px;
padding: 14px 10px;
text-align: center;
min-width: 0;
position: relative;
}
.card .name {
font-family: var(--mono);
font-size: 13px;
font-weight: 500;
color: var(--ink);
line-height: 1.2;
white-space: nowrap;
display: block;
}
.card .desc {
font-family: var(--sans);
font-size: 11px;
font-weight: 400;
color: var(--muted);
margin-top: 4px;
line-height: 1.3;
min-height: 28px;
white-space: nowrap;
}
.card .desc.cn { font-family: var(--cn); }
.row.bottom .card { padding: 10px 6px; }
.row.bottom .card .name { font-size: 10px; }
.row.bottom .card .desc { font-size: 9px; min-height: 22px; }
.row.bottom .card .desc.cn { font-size: 10px; }
/* connectors — pure CSS, guaranteed vertical & parallel */
.row.top .card::after,
.row.bottom .card::before {
content: '';
position: absolute;
left: 50%;
transform: translateX(-50%);
width: 2px;
background: var(--brand);
}
.row.top .card::after { top: 100%; height: 40px; }
.row.bottom .card::before { bottom: 100%; height: 40px; }
/* ── bus row (Cordis) ───────────────────────────────── */
.bus-row {
position: relative;
width: 96%;
margin: 40px auto;
}
.bus {
height: 60px;
background: var(--brand);
color: #ffffff;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-family: var(--sans);
font-size: 18px;
font-weight: 500;
letter-spacing: 0.01em;
}
.bus .dot { padding: 0 12px; opacity: 0.75; }
.bus .vendored {
font-family: var(--mono);
font-size: 15px;
font-weight: 400;
opacity: 0.8;
margin-left: 8px;
}
.bus.cn .core { font-family: var(--cn); }
/* ── cordis.yml side box (positioned outside bus width) ─ */
.yml-side {
position: absolute;
left: calc(100% + 20px);
top: 50%;
transform: translateY(-50%);
width: 130px;
display: flex;
flex-direction: column;
align-items: flex-start;
}
.yml-arrow {
position: absolute;
left: -30px;
top: 50%;
transform: translateY(-50%);
width: 30px;
height: 12px;
}
.yml-arrow svg { display: block; }
.yml-box {
width: 100%;
background: var(--card-bg);
border: 1px solid var(--card-bd);
border-radius: 6px;
padding: 12px 10px;
text-align: center;
}
.yml-box .file {
font-family: var(--mono);
font-size: 13px;
font-weight: 500;
color: var(--ink);
}
.yml-box .sub {
font-family: var(--sans);
font-size: 10px;
color: var(--muted);
margin-top: 4px;
line-height: 1.3;
}
.yml-box .sub.cn { font-family: var(--cn); letter-spacing: 0.05em; }
.yml-note {
font-family: var(--sans);
font-size: 10px;
color: var(--muted);
margin-top: 10px;
width: 100%;
text-align: center;
line-height: 1.4;
}
.yml-note.cn { font-family: var(--cn); letter-spacing: 0.05em; }

View File

@@ -1,97 +0,0 @@
#!/bin/bash
# render.sh — Chrome headless renderer for the DeepSeek Harness architecture diagram.
#
# Writes arch-en.png and arch-zh.png (3072×1160, ~600 KB each) to the given output
# directory. Default is <repo>/assets/, which is where the README image references
# resolve.
#
# Usage:
# bash render.sh # writes to <repo>/assets/
# bash render.sh /some/other/dir # writes there instead
#
# Env overrides:
# CHROME=/path/to/Chrome # non-standard Chrome location
# PORT=<n> # override the local http.server port
set -e
SKILL_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SKILL_DIR/../../.." && pwd)"
OUT_DIR="${1:-$REPO_ROOT/assets}"
BIND_PORT="${PORT:-0}" # 0 → kernel picks a free port
SERVER_LOG="$(mktemp -t dsh-arch-diagram-server.XXXXXX.log)"
# Locate a Chrome / Chromium binary. Honour $CHROME if set; otherwise probe
# common per-platform paths so `bash render.sh` works on macOS + Linux out
# of the box.
if [ -z "$CHROME" ]; then
for candidate in \
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
"/Applications/Chromium.app/Contents/MacOS/Chromium" \
"$(command -v google-chrome 2>/dev/null || true)" \
"$(command -v google-chrome-stable 2>/dev/null || true)" \
"$(command -v chromium 2>/dev/null || true)" \
"$(command -v chromium-browser 2>/dev/null || true)"; do
if [ -n "$candidate" ] && [ -x "$candidate" ]; then
CHROME="$candidate"; break
fi
done
fi
if [ -z "$CHROME" ] || [ ! -x "$CHROME" ]; then
echo "No Chrome / Chromium binary found." >&2
echo "Tried: macOS default, google-chrome, google-chrome-stable, chromium, chromium-browser." >&2
echo "Set CHROME=/path/to/binary and rerun." >&2
exit 1
fi
mkdir -p "$OUT_DIR"
python3 -u -m http.server "$BIND_PORT" --bind 127.0.0.1 --directory "$SKILL_DIR" \
>"$SERVER_LOG" 2>&1 &
SERVER_PID=$!
cleanup() { kill "$SERVER_PID" 2>/dev/null; rm -f "$SERVER_LOG"; }
trap cleanup EXIT INT TERM
# Discover the actual bound port from Python's own startup line
# ("Serving HTTP on 127.0.0.1 port <N> ..."). Works whether the kernel
# picked it or PORT was set explicitly; no external `lsof` needed.
PORT=""
for _ in $(seq 1 40); do
PORT=$(awk '/Serving HTTP on/ {print $6; exit}' "$SERVER_LOG" 2>/dev/null || true)
[ -n "$PORT" ] && break
# Bail early if the server died (e.g. explicit PORT already in use).
kill -0 "$SERVER_PID" 2>/dev/null || break
sleep 0.05
done
if [ -z "$PORT" ]; then
echo "Failed to detect local server port. Server log:" >&2
cat "$SERVER_LOG" >&2 || true
exit 1
fi
# Chrome/Chromium refuses to run as root without --no-sandbox. Rendering
# a local static HTML doc under a headless browser doesn't need Chrome's
# own sandbox, so passing the flag when EUID is 0 makes the script work
# in Codex/CI container environments that default to root.
CHROME_EXTRA_ARGS=()
if [ "$(id -u)" = "0" ]; then
CHROME_EXTRA_ARGS+=(--no-sandbox)
fi
for lang in en zh; do
out="$OUT_DIR/arch-$lang.png"
"$CHROME" \
"${CHROME_EXTRA_ARGS[@]}" \
--headless=new \
--disable-gpu \
--hide-scrollbars \
--force-device-scale-factor=2 \
--window-size=1820,580 \
--virtual-time-budget=8000 \
--screenshot="$out" \
"http://127.0.0.1:$PORT/harness-arch-$lang.html" \
2>/dev/null
size=$(du -h "$out" | awk '{print $1}')
echo "[$lang] wrote $out ($size)"
done