* chore: prefer es-toolkit helpers and lint the mechanical cases AGENTS.md now names the es-toolkit helpers to reach for instead of hand-written equivalents, and the exceptions: a single clear native call or a measured hot path. The new open-pencil/prefer-es-toolkit rule rejects filter(Boolean) and Set round trips on arrays, the two cases that need no type information, and the existing 45 sites use compact and uniq. tools/ci/policy runs before dependencies are installed, so the rule is off there. * refactor: deduplicate diagnostic categories with uniq * fix: keep es-toolkit out of serialized Playwright callbacks The codemod rewrote a filter(Boolean) inside a page.evaluate callback, which Playwright runs in the page where the compact import does not exist. The spec filters there again, and the rule now skips callbacks passed to evaluate, $eval, $$eval, evaluateHandle, addInitScript and waitForFunction, and filter calls on iterators from values, keys, entries and matchAll, which compact cannot take. * test: write the prefer-es-toolkit cases like the other rule tests Short standalone snippets, as in the base64 and JSON rule tests, instead of a declaration prefix on every case and inline object types.
6.8 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). - 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.