* ci: build and check packages in parallel The Vue SDK's declarations used the tsc resolver, which took 21 of the 32 seconds a local package build takes; tsdown's default oxc resolver writes byte-identical output in 4 seconds. Packages now build level by level, each level's packages together, with their output printed whole. Package checks run npm and Bun packing side by side and ATTW on every core instead of two. * ci: skip the merge queue's suites for a tree its PR already passed The merge queue reran every check even when master had not moved, so the queued commit had exactly the tree the pull request's CI had just passed. A passing PR run now records that tree as a commit status on the PR head, and the queue's classification compares its own tree with it: a match runs only the always-on checks, anything else the full suites. Fork PRs cannot write the status and keep the full run. * ci: accept a verified tree only from its pull request's passing CI run Any writer can post a commit status, and another pull request's CI could post one on this head, so a status alone could skip the queue's suites. The record now links the run that wrote it, and the queue accepts it only when GitHub shows Actions created it and the run is this repository's CI workflow on pull_request, passed, and ran on this exact head. Recording no longer fails the gate when the status cannot be written. Parallel packs and builds now all settle before a failure is reported, so none writes into a directory that is being removed or rebuilt. * refactor(ci): group the verified-tree lookup and recorder in one folder
7.1 KiB
Repo tooling, CI, and releases
Private tooling lives under tools/<role>/<domain>/{src,tests}; Steiger enforces the layout and kebab-case domain names. Every tool is a workspace named @open-pencil/<domain>-tools, listed literally in the root workspaces (the manifest schema rejects globs on purpose), so it can declare dependencies and run through bun --filter. bun run check:tools type-checks every tool through tools/tsconfig.json; bun run test:tools runs every tool with a test script. A tool imports its own files through its package.json imports alias (#ci/*, #release/*), other tools through their package name, and the docs site config through the shared #docs-config/* path.
| Role | Contract | Domains |
|---|---|---|
checks/ |
Read the tree and exit non-zero; never write inside the repository except an own baseline behind an explicit --write |
architecture, lint, i18n, secret-scan, type-shapes, docs, test-homes, package-quality |
generate/ |
Write generated files or artifacts, idempotently | brand, tauri-menu, authoring-reference, visual-oracles |
release/ |
Build, verify, and publish packages and native artifacts | package-artifacts, release-packages |
ci/ |
Consumed by workflows: path classification and gate policy, container images, the review-guidance bot | policy, images, pr-review-guidance |
dev/ |
Test running and benchmarks for humans | unit-tests, navigation-benchmark, dev-server |
- Nothing under
generate/orrelease/runs frombun run checkexcept through a check entrypoint;generate/authoring-referencekeeps itscheck.tsbesidegenerate.tsuntil it splits. - Resolve the workspace with
resolveWorkspaceRootfrom@open-pencil/package-artifacts-tools, not parent-directory traversal. Keep sibling imports relative. checks/test-homesownsengine-baseline.txtandcheck:test-homes;dev/unit-testsowns the shard map and runner (tests/AGENTS.md).- No
scripts/entrypoints: rootpackage.jsonscripts call tool files directly.
CI
.github/workflows/ci.ymlandheavy-tests.ymldefine validation gates. PR CI always classifies changed paths throughtools/ci/policy/src/policy.ts: root docs, package READMEs, everyAGENTS.md,packages/docsMarkdown and assets, and skill Markdown are docs-only; runtime prompt Markdown, executable examples, configuration, and unknown paths require code validation.- Docs-only changes run documentation integrity and the docs build; everything else runs the full suites. The aggregate
CI resultgate requires successful classification and every applicable job; failures, cancellations, and unexpected skips cannot pass. Do not restore workflow-level path filtering on required CI. commitlint.config.tsenforces commit structure in the Commit messages job; the separate PR title workflow validates titles. Preserve theRelease vX.Y.Zexception and product casing when changing rules; the known AI co-author check does not rewrite base history. Gate policy lives intools/ci/policy/src/policy.ts.tools/ci/policyruns right after Bun is set up, before any install, so it imports only Node built-ins;oxlint.jsonswitchesopen-pencil/prefer-es-toolkitoff there. Other CI tools install their workspace first, aspr-review-guidance.ymldoes through.github/actions/setup-bun.- Required checks must also run on
merge_group, the merge queue's event; read base and head frommerge_group.base_sha/head_shathere (ci.yml,pr-title.yml). - A passing pull request run records the tree it tested as the
CI verified treestatus on the PR head; a merge queue commit with that exact tree is classifiedverifiedand runs only the always-on checks. Any other tree, including a group with other PRs ahead, gets the full run (tools/ci/policy/src/verified-tree/). - App and docs production workflows run on
v*tags orworkflow_dispatch, not ordinarymasterpushes.build.ymlchecks the tooling out under.pipeline/and runstools/release/release-packagesfrom there.
Releases
- Update versions in the root and publishable package manifests plus
desktop/tauri.conf.jsonanddesktop/Cargo.toml; moveUnreleasedinto## x.y.z — YYYY-MM-DD; commitRelease vX.Y.Z; tag and pushvX.Y.Z. .github/workflows/build.ymlis the source of truth:v*tags (or dispatches for an immutable stable tag) build shared frontend/package outputs once, build signed desktop artifacts in parallel, verify and attest one complete same-run artifact set, publish npm packages, and replace the draft release assets using the exact changelog section. Policy, provenance, and recovery:tools/release/release-packages/README.md.- Public workspace packages are discovered by the package-artifacts catalog. Bun source exports require the complete
srcdirectory in package contents; Node exports usedist. Release preparation must preserve resolution maps. Prepared publish directories receive the rootLICENSEwhen a package has none of its own, and every package needs aREADME.mdbecause npm renders it. Publishing uses prepared npm tarballs verified through the shared Node/Bun consumer checks; never publish package directories manually.test:packagesfirst runs the packaging guards intools/checks/package-quality/src/smoke/guards.ts: fixture manifests packed with the realnpm packthat must trip the tarball inspector and the Node/Bun consumer checks before those checks vouch for real packages. - Ensure Tauri and Apple signing/notarization secrets are configured. Verify the draft title, body, and artifacts, then publish. Release titles are exactly the tag (
vX.Y.Z) without a product-name prefix. - Homebrew's
openpencilcask is managed upstream: BrewTestBot proposes bumps and Homebrew merges them. Check the upstream cask PR after publication; do not push to the archived custom tap or add bump automation. Users install the app withbrew install --cask openpenciland the CLI through npm or Bun.
Brand assets
Canonical artwork lives in assets/brand/ (main mark and optical micro master; see its README). tools/generate/brand/ derives web, docs, and native icons with RealFaviconGenerator and Tauri; generated assets are ignored, not committed. Vite and VitePress configs prepare their own targets, and Tauri dev/build hooks prepare native icons.