Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 7 additions & 19 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,27 +1,15 @@
// Generated by smith from the workspace's projects. `smith add` and `smith ci generate`
// rewrite this file: put your own steps between the smith:slot markers, which are kept.
{
"name": "opencraw",
"image": "mcr.microsoft.com/devcontainers/typescript-node:24-bookworm",
"image": "mcr.microsoft.com/devcontainers/base:bookworm",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"version": "24"
},
"ghcr.io/devcontainers/features/python:1": {
"version": "3.12"
},
"ghcr.io/devcontainers/features/go:1": {
"version": "1.27",
"golangciLintVersion": "2.14.0"
},
"ghcr.io/devcontainers/features/dotnet:2": {
"version": "10.0"
}
},
"postCreateCommand": "npm install -g npm@12 && npm ci && npx mnci ci setup",
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"nrwl.angular-console",
"firsttris.vscode-jest-runner"
]
}
}
"postCreateCommand": "curl -fsSL https://raw.githubusercontent.com/monosmith-app/monosmith/main/install.sh | sh -s -- \"1.10.0\" && \"$HOME/.local/bin/smith\" ci setup"
}

206 changes: 47 additions & 159 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,183 +1,71 @@
name: CI

# Generated by MoNecromanCI. Deliberately thin: Nx builds, 'nx release'
# versions from conventional commits and pushes ONLY a tag to main, and each
# app is packed into dist/drop/<type>-<name>.zip by its own 'package' target.
# The GitHub Actions equivalent of azure-pipelines.yml — see there for the
# fuller rationale; both stay hand-kept in lockstep, there is no shared template.
# Generated by smith from the workspace's projects. `smith add` and `smith ci generate`
# rewrite this file: put your own steps between the smith:slot markers, which are kept.
name: ci

on:
push:
branches: [main]
pull_request:
branches: [main]

concurrency:
# One run at a time per ref, but `cancel-in-progress` is an **expression** on
# purpose rather than a flat `true`.
#
# A superseded PR run is pure waste, so cancel it. A run on `main` must never
# be cancelled: it publishes packages and pushes release tags, and killing it
# part-way can leave a tag pushed with the publish only half done — a state no
# rerun repairs cleanly, because the version is then already tagged. Those runs
# queue instead, which also stops two `nx release` invocations racing to create
# the same tag when two commits land close together.
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

permissions:
# Lets the release step push the version tag nx release creates back to main,
# and (github-only provider) create the GitHub Release itself.
contents: write
# Lets azure/login exchange this job's OIDC token for a Microsoft Entra ID one,
# which is how a VS Code extension reaches the Marketplace with no stored secret.
# A token minted on a pull request cannot use it: the federated credential is
# pinned to refs/heads/main.
id-token: write
pull-requests: write

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v4
with:
fetch-depth: 0

# Version resolution needs the release tags.
- run: git fetch --all --prune --tags
name: Fetch branches and release tags

- run: git config user.name "github-actions[bot]" && git config user.email "github-actions[bot]@users.noreply.github.com"
name: Set the git identity used for release tags

- uses: actions/setup-node@v7
- uses: actions/setup-node@v4
with:
node-version: 24
# Caches ~/.npm keyed on package-lock.json, so `npm ci` restores from
# the local cache instead of re-downloading every tarball on every run.
# Nothing to invalidate by hand: the action keys on the lockfile, so a
# dependency change misses the cache and a no-op change hits it.
cache: npm

# setup-node installs whatever npm the Node image bundles, and npm's major
# is part of the contract: npm 11 reuses an already-installed tree instead
# of re-resolving, so it applies `overrides` differently from npm 10. See
# NPM_VERSION's remarks for the measurement.
- run: npm install -g npm@12
name: Pin npm to the major mnci verifies against

- run: npm ci
name: Install dependencies
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

# mnci:slot after-install (your own steps go between these two lines; mnci upgrade keeps them)
# mnci:slot-end after-install

# Everything from here to the release is a command of the mnci CLI, a
# devDependency of this workspace, so the version is the lockfile's and a
# developer reproduces CI by running the same line. The guards that used to be
# inline here are tested TypeScript in the CLI's ci-pipeline slice. Node,
# the checkout and 'npm ci' stay above: Node must exist before 'npx' can run.

# The language toolchains the workspace needs: Python (ruff, pytest, build,
# twine, and every project installed into one shared environment), Go (the
# modules and a checksum-verified golangci-lint, put on PATH) and Flutter (the
# pinned SDK, put on PATH, and one pub get). Each is skipped cleanly when the
# workspace has no project in that language.
- run: npx mnci ci setup
name: Set up the language toolchains (Python, Go, Flutter)

# Fails ONLY on an advisory that has a published fix, at moderate or above;
# anything upstream has not fixed is printed and passes. pip-audit only
# reports: its output has no "a fix exists" field to draw that line with.
- run: npx mnci ci audit
name: Audit dependencies (fails on an actionable npm advisory)

# .NET, if the workspace has any. actions/setup-dotnet is the
# maintained, cached installer GitHub itself ships, so this uses it
# directly rather than a hand-rolled 'node -e' guard — see
# DOTNET_DETECT_AZURE's remarks for the full reasoning. hashFiles()
# gates it inline, so a JS-only workspace pays nothing.
- uses: actions/setup-dotnet@v6
if: ${{ hashFiles('apps/*/*.csproj', 'packages/*/*.csproj', 'libs/*/*.csproj') != '' }}
node-version: '24'
- uses: actions/setup-python@v5
with:
dotnet-version: 10.0.x

# Fails fast on a stale TypeScript project reference, then the one verify
# step, and deliberately the only one: affected projects on a pull request,
# EVERY project on anything else (a push to main included, so a release is
# always verified in full). Every fallback takes the full path, because a run
# that verifies too little still reports green. Apps that need a C toolchain
# are left to the native job.
- run: npx mnci ci verify
name: Verify (sync check, then affected on a PR, every project on main)

# mnci:phase pack (delete or comment this block to switch it off; mnci upgrade keeps it off)
# Pack every app into dist/drop/<type>-<name>.zip via each app's 'package'
# target; skipped cleanly when the workspace has no apps yet.
- run: npx mnci ci pack
name: Pack all apps (one zip per app -> dist/drop)
if: ${{ github.event_name == 'push' && github.ref_name == 'main' }}

- uses: actions/upload-artifact@v7
if: ${{ github.event_name == 'push' && github.ref_name == 'main' }}
python-version: '3.12'
- name: Install smith
run: curl -fsSL https://raw.githubusercontent.com/monosmith-app/monosmith/main/install.sh | sh -s -- "$SMITH_VERSION"
env:
SMITH_VERSION: 1.10.0
GITHUB_TOKEN: ${{ github.token }}
# smith:slot before-setup
# The lockfile is written by npm 12: npm 11 prunes the nested @emnapi entries of the
# wasm32-wasi bindings, and npm 12's npm ci then refuses it (AGENTS.md).
- name: Pin npm 12
run: npm install -g npm@12
# smith:slot-end before-setup
- name: Setup
run: smith ci setup
- name: Audit
run: smith ci audit
- name: Verify
run: smith ci verify
# smith:slot after-verify
# smith:slot-end after-verify
- name: Release preview
if: github.event_name == 'pull_request'
run: smith release --dry-run --comment
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Pack
if: github.event_name == 'push' && github.ref_name == 'main'
run: smith ci pack
- uses: actions/upload-artifact@v4
if: github.event_name == 'push' && github.ref_name == 'main'
with:
name: drop
path: dist/drop
if-no-files-found: ignore
# mnci:phase-end pack

# mnci:slot before-release (your own steps go between these two lines; mnci upgrade keeps them)
# mnci:slot-end before-release

# mnci:phase release (delete or comment this block to switch it off; mnci upgrade keeps it off)
# Signs in to Microsoft Entra ID as the Marketplace publishing identity (an
# app registration with a federated credential for this repository's main
# branch), so the release step publishes VS Code extensions with
# 'vsce publish --azure-credential' and no token. Runs only when the
# AZURE_CLIENT_ID and AZURE_TENANT_ID repository variables exist and the
# workspace has an extension (every one ships a .vscodeignore). No Azure
# subscription is needed. Setup: README, 'VS Code extensions'.
- uses: azure/login@v3
name: Sign in to Microsoft Entra ID (VS Code Marketplace)
if: ${{ github.event_name == 'push' && github.ref_name == 'main' && vars.AZURE_CLIENT_ID != '' && hashFiles('apps/*/.vscodeignore') != '' }}
with:
client-id: ${{ vars.AZURE_CLIENT_ID }}
tenant-id: ${{ vars.AZURE_TENANT_ID }}
allow-no-subscriptions: true

# The release, in the order that keeps a failure safe: refuse a shallow
# clone, prove the npm token and name the PyPI projects it would create (all
# BEFORE anything is tagged), then version + tag + publish in one 'nx release'
# for npm, Python, C# and VS Code, then attach a releasable Go app's zips and
# push the tags. Which registry, and whether GitHub Releases are on, are read
# from the 'mnci' block of nx.json, not baked into this file. The secrets are
# mapped here, in the one place a command cannot reach.
#
# RELEASE_SPECIFIER (repository variable, Settings -> Secrets and
# variables -> Actions -> Variables) overrides the bump nx would compute
# from conventional commits for THIS run: 'major', 'minor', 'patch', or an
# exact version ('1.2.3'). With more than one releasable package a bare
# keyword is unreliable (nx versions interdependent packages in two passes,
# and the second computes from a version cached before the first), so the
# command fails the run rather than under-bumping silently: prefer an exact
# version, and clear the variable once the override is no longer needed.
- run: npx mnci ci release
name: Release — version, tag, publish and GitHub Release (npm + Python + C# + VS Code)
if: ${{ github.event_name == 'push' && github.ref_name == 'main' }}
- name: Release
if: github.event_name == 'push' && github.ref_name == 'main'
run: smith ci release
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
RELEASE_SPECIFIER: ${{ vars.RELEASE_SPECIFIER }}
# A VS Code extension publishes with Entra ID when the sign-in step
# above ran (VSCE_AUTH=entra), else with the VSCE_PAT token;
# tools/vscode-extension.cjs skips the Marketplace with neither.
VSCE_AUTH: ${{ vars.AZURE_CLIENT_ID != '' && 'entra' || '' }}
VSCE_PAT: ${{ secrets.VSCE_PAT }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# mnci:phase-end release

# mnci:slot after-release (your own steps go between these two lines; mnci upgrade keeps them)
# mnci:slot-end after-release
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
11 changes: 11 additions & 0 deletions .github/workflows/desktop-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ jobs:
with:
node-version: 24
cache: npm
# The npm scripts run smith (MonoSmith); the same installer the generated ci.yml uses.
- name: Install smith
shell: bash
run: |
curl -fsSL https://raw.githubusercontent.com/monosmith-app/monosmith/main/install.sh | sh -s -- "$SMITH_VERSION"
# install.sh adds its folder to PATH in Git Bash form, which cmd and PowerShell cannot use
# (monosmith-app/monosmith#290): add the Windows form too.
if [ "$RUNNER_OS" = Windows ]; then cygpath -w "$HOME/.local/bin" >> "$GITHUB_PATH"; fi
env:
SMITH_VERSION: 1.10.0
GITHUB_TOKEN: ${{ github.token }}
- run: npm ci
- name: Installer
run: npm run studio-desktop:package
Expand Down
19 changes: 15 additions & 4 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Browser end-to-end tests for @opencraw/core, @opencraw/office-reader's
# check that its published bundle runs in a browser, and
# @opencraw/captcha-tesseract's reads of rendered captchas. Kept out of ci.yml on purpose:
# that file is owned and rewritten by `mnci upgrade`, this one is ours.
# that file is generated by `smith ci generate`, this one is ours. Each e2e task installs its browsers
# first (the playwright convention, e2e-browsers) and runs under xvfb-run itself when it opens windows.
name: e2e

on:
Expand All @@ -18,13 +19,23 @@ jobs:
with:
node-version: 24
cache: npm
# The npm scripts run smith (MonoSmith); the same installer the generated ci.yml uses.
- name: Install smith
shell: bash
run: |
curl -fsSL https://raw.githubusercontent.com/monosmith-app/monosmith/main/install.sh | sh -s -- "$SMITH_VERSION"
# install.sh adds its folder to PATH in Git Bash form, which cmd and PowerShell cannot use
# (monosmith-app/monosmith#290): add the Windows form too.
if [ "$RUNNER_OS" = Windows ]; then cygpath -w "$HOME/.local/bin" >> "$GITHUB_PATH"; fi
env:
SMITH_VERSION: 1.10.0
GITHUB_TOKEN: ${{ github.token }}
- run: npm ci
- run: npx playwright install --with-deps chromium
- run: npm run core:e2e
# The recording flows open a headed window: a virtual display stands in for a screen.
- run: xvfb-run -a npm run studio:e2e
- run: npm run studio:e2e
# The desktop app: a real Electron window against the built UI.
- run: xvfb-run -a npm run studio-desktop:e2e
- run: npm run studio-desktop:e2e
- run: npm run office-reader:e2e
- run: npm run captcha-tesseract:e2e
# Every example's recipes load and bind; the examples that run offline run.
Expand Down
11 changes: 11 additions & 0 deletions .github/workflows/vscode-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ jobs:
with:
node-version: 24
cache: npm
# The npm scripts run smith (MonoSmith); the same installer the generated ci.yml uses.
- name: Install smith
shell: bash
run: |
curl -fsSL https://raw.githubusercontent.com/monosmith-app/monosmith/main/install.sh | sh -s -- "$SMITH_VERSION"
# install.sh adds its folder to PATH in Git Bash form, which cmd and PowerShell cannot use
# (monosmith-app/monosmith#290): add the Windows form too.
if [ "$RUNNER_OS" = Windows ]; then cygpath -w "$HOME/.local/bin" >> "$GITHUB_PATH"; fi
env:
SMITH_VERSION: 1.10.0
GITHUB_TOKEN: ${{ github.token }}
- run: npm ci
# The libraries an Electron editor needs on a bare runner.
- run: npx playwright install-deps chromium
Expand Down
11 changes: 11 additions & 0 deletions .github/workflows/vscode-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ jobs:
with:
node-version: 24
cache: npm
# The npm scripts run smith (MonoSmith); the same installer the generated ci.yml uses.
- name: Install smith
shell: bash
run: |
curl -fsSL https://raw.githubusercontent.com/monosmith-app/monosmith/main/install.sh | sh -s -- "$SMITH_VERSION"
# install.sh adds its folder to PATH in Git Bash form, which cmd and PowerShell cannot use
# (monosmith-app/monosmith#290): add the Windows form too.
if [ "$RUNNER_OS" = Windows ]; then cygpath -w "$HOME/.local/bin" >> "$GITHUB_PATH"; fi
env:
SMITH_VERSION: 1.10.0
GITHUB_TOKEN: ${{ github.token }}
- run: npm ci
- name: Package the extension
run: npm run vscode:package
Expand Down
11 changes: 11 additions & 0 deletions .github/workflows/vscode-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,17 @@ jobs:
with:
node-version: 24
cache: npm
# The npm scripts run smith (MonoSmith); the same installer the generated ci.yml uses.
- name: Install smith
shell: bash
run: |
curl -fsSL https://raw.githubusercontent.com/monosmith-app/monosmith/main/install.sh | sh -s -- "$SMITH_VERSION"
# install.sh adds its folder to PATH in Git Bash form, which cmd and PowerShell cannot use
# (monosmith-app/monosmith#290): add the Windows form too.
if [ "$RUNNER_OS" = Windows ]; then cygpath -w "$HOME/.local/bin" >> "$GITHUB_PATH"; fi
env:
SMITH_VERSION: 1.10.0
GITHUB_TOKEN: ${{ github.token }}
- run: npm ci
- name: Package the extension
run: npm run vscode:package
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,7 @@ apps/vscode-extension/*.vsix

# The documentation an agent reads, copied in at build (packages/mcp/scripts/copy-docs.mjs)
/packages/mcp/docs/

# smith
.smith/
.venv/
Loading
Loading