Repository navigation
chore: fork delta since upstream f8d91268 (browse-only) - #30
Closed
DaneSpiritGOD wants to merge 36 commits into
Closed
DaneSpiritGOD wants to merge 36 commits into
DaneSpiritGOD wants to merge 36 commits into
Conversation
Record the vocabulary and the two decisions that make this fork's headless CLI work legible: fork-local development (straight to main, merge upstream in) and shipping the CLI as a single zero-dependency bundle with themes embedded at build time. Also ignore the workspace-local corepack cache, used when the home cache is not writable.
The sync workflow verifies upstream merges in its own workspace and opens a pull request instead of pushing main directly; the human merge is a real push that triggers the publish chain, and the review covers what the snapshot gate cannot.
Add @dane.dai/md-web-cli: an esbuild single-file, zero-dependency Node bundle of the doocs render core (marked + custom renderer + HTML post-processing), with the four theme stylesheets and the ten vendored highlight.js presets imported as text at build time. The render subcommand emits the intermediate form carrying a themed <style> block; CSS inlining and placeholder detection land with the next tickets. Defaults follow the site's default style config (theme default, #0F4C81, 16px/1.75, mac code block, github-dark), explicitly not the MCP server's. Conversion makes zero network requests, proven by a test that hard-blocks net.connect and fetch. A full-coverage fixture (h1-h6, tables, multi-language code blocks, nested lists, blockquotes, images, hr) is included for later tickets. Closes #3
…y color - Add src/config.ts with two normalizers (Designer export, MCP schema JSON) to the internal RenderConfigInput; whitelist-based so junk keys are ignored silently. isCiteStatus/isCountStatus map to citeStatus/countStatus. - Resolve the CSS editor state (cssContentConfig) to the active tab's CSS, mirroring the site's apply-only-active-tab behavior; --css-tab overrides by id or name. Custom CSS is unscoped from #output and merged after theme CSS, before processCSS. - Add headingStyles and bodyColor (default rgb(10,10,10), applied on the output container like the copy flow) to RenderConfigInput and rendering. - CLI: --config, --css-tab, --raw (pre-inlining intermediate output), --body-color and flag overrides; precedence defaults < config < flags. Pending-placeholder failure semantics preserved in both modes.
Introduce the Tier 3 Oracle rebuild entry (ticket 06): - scripts/oracle/rebuild-oracle.mjs: serves the built apps/web/dist on a local static server, drives Playwright Chromium headless, injects the md-web-cli fixture through CodeMirror's native input pipeline (click, select-all, insertText), waits for a stable preview via the app's own readiness signals (fixture markers, no pending diagram/KaTeX, HTML signature stability), triggers the real WeChat copy flow from the header button, reads the processed clipboard HTML back, and writes oracle.html + a structural report atomically (temp + rename) only on full success. - .github/workflows/oracle-rebuild.yml: manual workflow_dispatch that builds the web app, runs the script, and uploads the Oracle HTML and report as the browser-oracle artifact. The browser appears only here, never in the recurring CI path. - playwright added as a root devDependency (the doocs repo has none); browser install is a workflow step, locally documented in packages/md-web-cli/ORACLE.md. - ORACLE.md documents how to run it, what the artifact is, and the cross-reference to the stored research baseline. - tests/oracle-summary.test.ts: jsdom smoke test for the report's structural-summary extraction rules. - eslint.config.mjs: un-ignore scripts/ so the new script is linted.
- scripts/oracle/semantic-diff.mjs: property-level comparison of the browser Oracle vs the CLI's WeChat-ready output with color/numeric tolerance and an explained-differences ledger (class attrs, inline body color, svg attrs, link trailing slash, table margin reset) - scripts/oracle/verify-defaults.mjs: cross-checks site defaultStyleConfig and the rendered output (mac code block, github-dark, 16px/1.75/1x, #0F4C81, #576b95, legend alt, body color rgb(10,10,10)) - scripts/oracle/screenshot-comparison.mjs: headless Chromium screenshots - docs/evidence/md-web-cli-tier1/: committed report, screenshots, manual WeChat check instructions (PENDING HUMAN CHECK) - vitest coverage for extraction, tolerance and classification logic
…ce copy The live oracle artifact is gitignored; the test now falls back to the committed tier-1 evidence copy so the suite passes on a fresh checkout, and color assertions are case-insensitive per parseColor normalization.
…et 08) - commit packages/md-web-cli/golden/snapshot.html, regenerated via pnpm oracle:refresh-snapshot (scripts/oracle/refresh-snapshot.mjs) - add scripts/oracle/verify-snapshot.mjs: standalone, arg-driven gate asserting CLI render exit 0, no pending placeholders, WeChat-ready inline styles (no class/style tags, block elements styled), and semantic property match against the snapshot; --self-test runs the three reverse cases (placeholder injection, style stripping, truncation) and requires each to fail - extract shared tolerance/extraction helpers into scripts/oracle/lib/extract.mjs, reused by semantic-diff.mjs - wrap the gate in vitest (packages/md-web-cli/tests/verify-snapshot.test.ts); 78 tests green - record the snapshot in the Tier 1 evidence README and in the ticket 06 oracle-report.json (goldenSnapshotPath)
…esolution (ticket 09) - add .github/workflows/publish-md-web-cli.yml: push-to-main build + ticket 08 verify-snapshot gate + unit tests, then publish via npm OIDC trusted publishing (id-token: write, no NODE_AUTH_TOKEN, no notification secrets) - version rule: MAJOR.MINOR hand-edited in manifest; PATCH automatic — publish manifest version when (MAJOR,MINOR) differs from registry latest or package unpublished, else registry PATCH + 1, applied with npm version --no-git-tag-version (no write-back commit) - scripts/resolve-publish-version.mjs + vitest coverage for the rule - make package publishable: drop private, add files (dist + README) and license, add README
A font-family list wrapping across lines is reformatting, not a visual change; valuesMatch now normalizes whitespace runs before comparison.
… 10) Weekly cron + manual dispatch that fetches doocs/md, merges new upstream commits into sync/upstream, builds md-web-cli and runs the ticket-08 verify-snapshot gate, then opens or force-updates a PR into main whose body records the verification result and run link. Conflict, build, and verification failures surface as GitHub Actions notifications with no PR. PRs from GITHUB_TOKEN carry no checks; the recorded in-workspace verification is what the human merges on. Merging triggers the ticket-09 publish chain normally.
…lback warning, env-overridable chromium - Boolean flags (--mac-code-block etc.) now consume the next argv token only when it is a boolean literal; a bare flag means true and no longer swallows a following positional input. - mergeCss warns on stderr when every juice attempt fails, so a non-WeChat-ready artifact is never silently written. - Screenshot script's Chromium fallback path is overridable via MD_WEB_CLI_CHROMIUM instead of being machine-locked. - Tier-1 evidence README explicitly records the golden snapshot as the Tier-1-confirmed artifact.
parseColor now handles the color forms a CSS serializer can emit, so the Tier 1 / Tier 2 comparisons no longer treat valid colors as non-colors: - accept 8-digit (#rrggbbaa) and 4-digit (#rgba) hex with an alpha channel - convert rgb() percentage channels to 0-255 instead of reading them raw - round fractional channels and clamp out-of-range channels and alpha - reject malformed or over-long input instead of returning a half parse Boundary tests pin the documented limitations that were left unchanged: valuesMatch ignores units when both sides carry the same number (16px vs 16em), named colors are not parsed, and alpha is compared with tolerance.
Four assertions could not fail, so they proved nothing: - cli.test.ts pointed HTTP_PROXY/HTTPS_PROXY at a dead port, which Node's fetch ignores without --use-env-proxy. offline.test.ts now starts a loopback TCP sink that counts inbound connections and a poisoning preload, then proves a fixture render leaves both at zero — including with every proxy env var pointed at the sink — plus a control that the poison really blocks a foreign dial. - config.test.ts looked for the literal strings `color:red` / `color: red`, but the CSS pipeline re-serializes custom CSS, so neither can ever appear. Replaced with a color-semantic regex. - publish-version and semantic-diff gain boundary cases for hex forms, rgb percentages, clamping, alpha, numeric tolerance, prerelease and build-metadata inputs, and the leftover edge cases are pinned with comments so they stay conscious limitations. Adds output-structure.test.ts: it asserts the CLI-side contract (no <style>, no class attributes, inline styles everywhere) and documents that verify-snapshot's --self-test does not cover that axis. Follow-up tracked in #11.
`expect(html).toMatch(condition ? /./ : /./)` matched any character in either branch, so the line proved nothing. The neighbouring assertion on the style block (`#0d1117`) already covers the github-dark background it was presumably meant to check.
perfectionist/sort-imports expects the type sibling first; eslint --fix was relocating it above the file-level JSDoc, so place it manually below the comment instead. Refs #15
The Oracle rebuild has only ever run locally on macOS. Before anything depends on a headless browser in CI, prove the path works on a Linux runner: install Chromium, build the web app, run the unmodified rebuild-oracle.mjs, and upload the clipboard HTML plus the run log. Refs #16
The browser capture now serves the built app, drives the copy flow, and returns the clipboard HTML as a string, writing only into a caller-supplied temp directory outside the repository. It builds nothing, fails loudly on a missing build, and overrides the browser via MD_WEB_CLI_CHROMIUM. The legacy rebuild script stays as a thin wrapper until the committed Oracle artifacts are retired.
The five style keys a Designer export cannot carry now have one guard: a unit test imports both default configurations and compares values, so a mismatch names the key and both values instead of surfacing as an unexplained diff hunk in the byte comparison.
…ry entry Records why one gate replaced three, why tolerance is forbidden, why the Oracle became a capability, and that the gate landed red on purpose — with the condition that ends the red acceptance.
…actly node scripts/verify.mjs builds both workspaces itself, captures a fresh Oracle into a temp directory, renders the same fixture through the CLI, and compares the outputs with strict string equality. Failures print a class-grouped summary with counts and locations, the complete unified diff, and a hunk total; both outputs and the diff land under a printed temp path, preserved with --keep or --out-dir. Exposed as the root wcli:verify script.
A minimal fixture (heading, paragraph, inline code) runs alongside the full-coverage one by default, labelled as an infrastructure probe: its failure means the harness is broken, its success proves nothing about fidelity. --fixture restricts a run to one fixture.
--config takes an unmodified Designer export, keeps only render-affecting keys, and feeds the same projected file to the CLI and to the browser (seeded into the app's own storage before boot). Article content and pure-UI state are dropped before either side sees them, and the seed is asserted to have taken effect so a silent no-op cannot compare two site-default renders. The five style keys an export cannot carry fall back to each side's own site defaults, guarded by the site-default parity test.
…test The gate now fails on pending placeholders (diagram, formula, unregistered language) and on output that is not WeChat-ready (style block, class attribute, block element without inline style), with the documented structural exemptions. --self-test corrupts a known-good CLI render seven distinct ways and asserts each mutant is rejected, without a browser. Adapts the retired verifier's tests to the comparator rather than dropping them.
CI installs Chromium, caching the browser directory keyed on the Playwright version, and runs the verify gate so the diff is visible on every change without failing the job while the gate is deliberately red. The three existing jobs keep their coverage.
Both workflows stop calling the retired snapshot gate and run the same pnpm wcli:verify as CI, with the same cached Chromium install, and stay blocking: a red gate publishes nothing and holds the sync pull request. The sync PR body renders its verification line from the run's actual outcome instead of a hardcoded success.
One documentation area under packages/md-web-cli/docs: an entry document covering install, usage, and verify invocation, the gate's own reference, the relocated manual WeChat paste procedure, and the known blind spots (including the missing diagram SVG pipeline and the untested real-device paste). The package README points at it instead of duplicating it.
…acle scripts With the verify gate holding the surviving assertions and the Oracle captured at run time, the old machinery has no consumer left: - the six oracle npm scripts, the four obsolete scripts, and the legacy rebuild wrapper (the capability lives in scripts/verify/oracle.mjs) - the shared extraction helper that existed for tolerance and colour matching - the golden snapshot and its refresh path - the two oracle workflows - the committed evidence directory and the standalone Oracle document - the superseded tests; their coverage moved to the comparator's tests Nothing regenerable is committed any more, and no live code, workflow, or doc refers to the retired vocabulary.
…iew changes --out-dir wrote both fixtures into one directory, so the second capture overwrote the first. Artifacts now always land under <root>/<fixture>/. Preview readiness compared element counts and lengths only, so a custom fixture with the same shape as the app's default document could never look ready; the signature now includes a hash of the text.
- share one repository path guard, and refuse an in-repo --out-dir before anything is written (previously projected-config.json/cli.html landed first) - read the Oracle's completion signal from the clipboard instead of sleeping 500ms past the copy button - classify text-only drift as text rather than unclassified - give the self-test a positive control: identical input must compare equal, or every reverse case would pass for the wrong reason - run the browser-gated config-projection test in CI - drop dead exports, dedupe the test subprocess helper, fix ADR/docs wording about seams, CI blocking, and the manual paste step
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fork delta since upstream
f8d91268— browse-onlyBaseline
f8d912682— doocs/mdchore(deps): upgrade project dependencies (#1995), 2026-10-1759d74af4f—main0bbfe56b6deps doocs#1996,67bba7d68mermaid doocs#1997 (2 commits, deliberately out of this diff)Nothing under
apps/**orpackages/core|shared|api|mcp-serveris touched. The fork adds a newworkspace package plus tooling, docs, and workflows; upstream code is only touched at the edges
(
package.jsonscripts, ESLint ignores,.gitignore, CI job tail).What the delta contains
@dane.dai/md-web-cli— headless render CLIpackages/md-web-cli/**, 48 new files, +4272scripts/verify.mjs,scripts/verify/*, +1486.github/workflows/{publish-md-web-cli,sync-upstream}.yml,ci.ymltail, +342docs/adr/000{1,2,3},GLOSSARY.md,docs/agents/*,AGENTS.md, +3651.
@dane.dai/md-web-cli(12)Single-file, zero-runtime-dependency CLI that renders Markdown to WeChat-ready HTML without a browser;
theme and highlight CSS are inlined at build time. Config dialects, flag overrides,
--raw, placeholderfailure semantics, and an OIDC-based npm publish path. Tiers and the golden snapshot were retired in
favour of the verify gate below (ADR-0002).
e6e7e0b2cfeat(md-web-cli): bundle pipeline and minimal render CLI5c6546a33fix(md-web-cli): build bundle before tests so the CLI subprocess test finds dist5270da869feat(md-web-cli): wechat-ready output and placeholder failure semantics5db40a80efeat(md-web-cli): config file dialects, flag overrides,--rawand body color488475f3cfix(md-web-cli): review fixes — boolean flag argv handling, juice fallback warning, env-overridable chromiumfb0863097fix(md-web-cli): order type import before value importa9022310ftest(md-web-cli): replace blind test assertions with observable onescdb293ad2test(md-web-cli): drop an assertion that could never fail968654818test(md-web-cli): assert site-default parity between CLI and app5c9012002test(md-web-cli): golden snapshot + tier 2 verify-snapshot gate7dccaa9f9chore(md-web-cli): retire the tier machinery, golden snapshot, and oracle scriptsa2c3fa69adocs(md-web-cli): consolidate docs and relocate the manual paste check2. Verify gate (16)
One command builds the web app and the CLI, captures both, and compares byte-exactly against a
browser-driven Oracle, plus structural assertions that survive when pixels legitimately move
(ADR-0003). The gate deliberately landed red and is
non-blocking in CI; making it blocking is an explicit decision, not a default.
ca3f7219cfeat(oracle):workflow_dispatchbrowser Oracle rebuild via Playwright66fe68056feat(oracle): semantic diff and tier 1 acceptance evidence3e5ad58fcfix(md-web-cli): semantic-diff tests read the committed oracle evidence copy822c281a1fix(oracle): collapse whitespace when comparing extracted CSS values112b409b7fix(oracle): parse full color syntax in the semantic extractore5cceb1b6feat(verify): make the Oracle a callable capability2b2e5fcbbchore(spike): run the browser Oracle headless on a GitHub runner1347468c6feat(verify): one command that builds, captures, and compares byte-exactly194abcdb4test(verify): add an infrastructure-probe fixture64387a9c5feat(verify): accept a Designer config and project it to render keysef960aa46feat(verify): keep structural assertions and add a reverse-case self-test01ae26641fix(verify): keep per-fixture artifact dirs and detect text-only preview changes59d74af4ffix(verify): close review findings in the gatec8ad1e28cci: run verify as a non-blocking signal with a cached browserc773bda32ci: switch publish and sync workflows to verifyf157415f8docs(adr): record the single verify gate and narrow the Oracle glossary entry3. Publish / sync / CI (4)
49913ec0dfeat(md-web-cli): OIDC publish workflow with registry-aware version resolution2a8ab4093ci(sync): weekly upstream sync workflow with verified sync PRa513bd8f9chore: trigger ci on fork84a7a3bedfix(lint): re-ignore scripts to match upstream lint surface (see Lint divergence: identical commit is green upstream but red in fork CI #15)4. Docs, ADRs, agent setup (4)
782fa764cfeat(agents): add domain documentation and issue tracker guidelines88ab6c145docs: add domain glossary and fork-local ADRsf01a5ac36docs(adr): upstream changes land via a verified sync pull request1ba701502chore: ignore local temp/ scratch directoryUpstream-owned files touched
pnpm-lock.yamlpnpm install.package.jsonwcli:verifyscript;md-web-cliadded totype-check:packages/testfilters;playwrightdevDepeslint.config.mjspackages/md-web-cli/fixtures/ci.ymlpnpm wcli:verify.gitignore.corepack,.playwright-browsers,.wt-ticket-*,.pnpm-store/,temp/AGENTS.md,docs/architecture.mdHow to read this PR
packages/md-web-cli/src/{render,wechat,config}.tsandscripts/verify/{compare,oracle}.mjs.https://github.com/doocs/md/compare/f8d912682...DaneSpiritGOD:md:mainci.ymlruns lint / type-check / test on this PR;pnpm wcli:verifyis the gate itself.Refreshing after the next sync
Retargeting this PR's base instead of opening a new one keeps the history in one place, but existing
inline comments will be marked outdated. Opening a fresh PR per sync keeps comments attributable.
Checklist
f8d912682), not against a moving target