Skip to content

Commit 60df708

Browse files
committed
Merge upstream/main into feat/issue-4692-zcode
2 parents 3cc03bf + 2cbb2e4 commit 60df708

768 files changed

Lines changed: 70331 additions & 12543 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/AGENTS.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ Before changing GitHub automation, read the current versions of:
1212
- `.github/workflows/report.atom.yml`
1313
- `.github/scripts/handoff.py`
1414
- `scripts/scopes.ts`
15+
- `specs/current/ci.md` when changing scope rules, confidence tiers, or guards
1516
- `e2e/tests/packaged-smoke-workflow.test.ts`
16-
- `scripts/approve-fork-pr-workflows.ts` and `scripts/approve-fork-pr-workflows.test.ts` when touching fork PR approval behavior
17+
- `scripts/approve-fork-pr-workflows.ts` and `e2e/tests/scripts/approve-fork-pr-workflows.test.ts` when touching fork PR approval behavior
1718

1819
If the change affects cross-workflow behavior, update the topology tests instead of relying only on workflow YAML review.
1920

@@ -163,4 +164,4 @@ GitHub artifact behavior is easy to drift: artifact names must be unique per upl
163164

164165
### Where should tests live?
165166

166-
Cross-workflow topology tests belong in `e2e/tests/` when they observe repository-level behavior. Script-specific behavior can stay next to the script's existing tests. Do not add one-off `*.test.ts` files just because a workflow helper exists; prefer existing topology coverage and helper self-checks when that is enough.
167+
Cross-workflow topology tests belong in `e2e/tests/` when they observe repository-level behavior. Root `scripts/` is test-free (enforced by `pnpm guard`); script behavior-contract coverage lives in `e2e/tests/scripts/`. Do not add one-off `*.test.ts` files just because a workflow helper exists; prefer existing topology coverage and helper self-checks when that is enough.

.github/actions/setup-workspace/action.yml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ inputs:
1414
description: JSON array of labels selected for this job's runs-on value
1515
required: false
1616
default: '[]'
17+
save-pnpm-cache:
18+
description: Save a missing pnpm cache after install; trusted main seed jobs only
19+
required: false
20+
default: 'false'
1721

1822
runs:
1923
using: composite
@@ -62,13 +66,21 @@ runs:
6266
shell: bash
6367
run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
6468

65-
- name: Cache pnpm store
69+
- name: Restore pnpm store
70+
id: pnpm-cache-restore
6671
if: ${{ steps.persistent-pnpm-store.outputs.enabled != 'true' }}
67-
uses: actions/cache@v5.0.5
72+
uses: actions/cache/restore@v5
6873
with:
6974
path: ${{ steps.pnpm-store.outputs.path }}
7075
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
7176

7277
- name: Install dependencies
7378
shell: bash
7479
run: pnpm install --frozen-lockfile
80+
81+
- name: Save pnpm store
82+
if: ${{ inputs.save-pnpm-cache == 'true' && steps.persistent-pnpm-store.outputs.enabled != 'true' && steps.pnpm-cache-restore.outputs.cache-hit != 'true' && github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || github.event_name == 'schedule') }}
83+
uses: actions/cache/save@v5
84+
with:
85+
path: ${{ steps.pnpm-store.outputs.path }}
86+
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}

.github/pull_request_template.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Fixes #
3131

3232
- [ ] **UI** — new page / dialog / panel / menu item / setting / empty state in `apps/web` or `apps/desktop` (including Electron menu bar)
3333
- [ ] **Keyboard shortcut** — new or changed
34-
- [ ] **CLI / env var** — new `od` subcommand or flag, new `tools-dev` / `tools-pack` / `tools-pr` flag, or new `OD_*` env var
34+
- [ ] **CLI / env var** — new `od` subcommand or flag, new `tools-dev` / `tools-pack` flag, or new `OD_*` env var
3535
- [ ] **API / contract** — new `/api/*` endpoint, new SSE event, or changed shape in `packages/contracts`
3636
- [ ] **Extension point** — new entry under `skills/`, `design-systems/`, `design-templates/`, or `craft/`, or change to the skills protocol
3737
- [ ] **i18n keys** — added new translation keys (see `TRANSLATIONS.md` for the locale workflow)
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
name: cache-maintenance
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths:
7+
- pnpm-lock.yaml
8+
- .github/actions/setup-workspace/action.yml
9+
- .github/workflows/cache-maintenance.yml
10+
pull_request_target:
11+
types: [closed]
12+
workflow_dispatch:
13+
14+
permissions:
15+
actions: write
16+
contents: read
17+
18+
jobs:
19+
seed-pnpm-windows:
20+
if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main')
21+
runs-on: windows-latest
22+
timeout-minutes: 15
23+
steps:
24+
- name: Checkout main
25+
uses: actions/checkout@v6.0.2
26+
27+
- name: Seed Windows pnpm cache
28+
uses: ./.github/actions/setup-workspace
29+
with:
30+
save-pnpm-cache: 'true'
31+
32+
clean-closed-pr-buildkit:
33+
if: github.event_name == 'pull_request_target' && github.repository == 'nexu-io/open-design'
34+
runs-on: ubuntu-24.04
35+
timeout-minutes: 5
36+
steps:
37+
- name: Delete closed PR BuildKit caches
38+
env:
39+
CACHE_REF: refs/pull/${{ github.event.pull_request.number }}/merge
40+
GH_TOKEN: ${{ github.token }}
41+
run: |
42+
set -euo pipefail
43+
44+
cache_rows="$(
45+
gh cache list \
46+
--repo "$GITHUB_REPOSITORY" \
47+
--ref "$CACHE_REF" \
48+
--limit 10000 \
49+
--json id,key,sizeInBytes \
50+
--jq '.[] | select((.key | startswith("buildkit-blob-")) or (.key | startswith("index-buildkit-"))) | [.id, .key, .sizeInBytes] | @tsv'
51+
)"
52+
53+
if [ -z "$cache_rows" ]; then
54+
echo "No closed-PR BuildKit caches found for $CACHE_REF"
55+
exit 0
56+
fi
57+
58+
count=0
59+
bytes=0
60+
while IFS=$'\t' read -r cache_id cache_key cache_size; do
61+
[ -n "$cache_id" ] || continue
62+
echo "Deleting cache id=$cache_id key=$cache_key bytes=$cache_size ref=$CACHE_REF"
63+
gh cache delete "$cache_id" --repo "$GITHUB_REPOSITORY"
64+
count=$((count + 1))
65+
bytes=$((bytes + cache_size))
66+
done <<< "$cache_rows"
67+
68+
echo "Deleted $count closed-PR BuildKit caches ($bytes bytes) for $CACHE_REF"

.github/workflows/ci.yml

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ jobs:
6363
run_playwright_critical: ${{ steps.detect.outputs.run_playwright_critical }}
6464
run_playwright_visual: ${{ steps.detect.outputs.run_playwright_visual }}
6565
run_preflight: ${{ steps.detect.outputs.run_preflight }}
66+
run_preflight_typecheck: ${{ steps.detect.outputs.run_preflight_typecheck }}
6667
run_ui_p0: ${{ steps.detect.outputs.run_ui_p0 }}
6768
run_web_workspace_tests: ${{ steps.detect.outputs.run_web_workspace_tests }}
6869
run_windows_tools_pack_payload_tests: ${{ steps.detect.outputs.run_windows_tools_pack_payload_tests }}
@@ -136,21 +137,31 @@ jobs:
136137
timeout-minutes: 10
137138
env:
138139
ACTIONLINT_VERSION: 1.7.12
140+
SHELLCHECK_VERSION: 0.11.0
139141

140142
steps:
141143
- name: Checkout
142144
uses: actions/checkout@v6.0.2
143145

144-
- name: Install actionlint
146+
- name: Install actionlint and ShellCheck
145147
run: |
146148
case "$(uname -m)" in
147-
x86_64) actionlint_arch=amd64 ;;
148-
aarch64|arm64) actionlint_arch=arm64 ;;
149+
x86_64)
150+
actionlint_arch=amd64
151+
shellcheck_arch=x86_64
152+
;;
153+
aarch64|arm64)
154+
actionlint_arch=arm64
155+
shellcheck_arch=aarch64
156+
;;
149157
*) echo "Unsupported actionlint architecture: $(uname -m)" >&2; exit 1 ;;
150158
esac
151159
curl -fsSL "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_${actionlint_arch}.tar.gz" \
152160
| tar -xz actionlint
161+
curl -fsSL "https://github.com/koalaman/shellcheck/releases/download/v${SHELLCHECK_VERSION}/shellcheck-v${SHELLCHECK_VERSION}.linux.${shellcheck_arch}.tar.gz" \
162+
| tar -xz --strip-components=1 "shellcheck-v${SHELLCHECK_VERSION}/shellcheck"
153163
sudo install -m 0755 actionlint /usr/local/bin/actionlint
164+
sudo install -m 0755 shellcheck /usr/local/bin/shellcheck
154165
155166
- name: Check workflow files
156167
run: actionlint -color
@@ -245,12 +256,14 @@ jobs:
245256
# If postinstall grows a targeted app type-generation phase covering these
246257
# three exports without broad app builds, this CI prebuild can be removed.
247258
- name: Prebuild workspace type declarations
259+
if: ${{ needs.scopes.outputs.run_preflight_typecheck == 'true' }}
248260
run: |
249261
pnpm --filter @open-design/daemon build
250262
pnpm --filter @open-design/desktop build
251263
pnpm --filter @open-design/web build:sidecar
252264
253265
- name: Typecheck workspaces
266+
if: ${{ needs.scopes.outputs.run_preflight_typecheck == 'true' }}
254267
run: |
255268
pnpm -r --filter '!open-design' --filter '!@open-design/landing-page' --workspace-concurrency="${OPEN_DESIGN_WORKSPACE_CONCURRENCY:-1}" --if-present run typecheck
256269
pnpm exec tsc -p scripts/tsconfig.json --noEmit
@@ -291,7 +304,13 @@ jobs:
291304
pnpm --filter @open-design/tools-dev test
292305
fi
293306
if [ "${{ needs.scopes.outputs.tools_pack_tests_required }}" = "true" ]; then
307+
pnpm --filter @open-design/desktop build
308+
pnpm --filter @open-design/desktop test
309+
pnpm --filter @open-design/packaged test
294310
pnpm --filter @open-design/tools-pack test
311+
if [ "${{ needs.scopes.outputs.run_e2e_vitest }}" != "true" ]; then
312+
pnpm --filter @open-design/e2e test tests/packaged-launcher-update-loop.test.ts
313+
fi
295314
fi
296315
297316
- name: Probe watcher environment
@@ -723,8 +742,11 @@ jobs:
723742
marker="<!-- merge-queue-needs-validation -->"
724743
{
725744
printf '%s\n' "$marker"
745+
# Markdown code spans are intentional literal text.
746+
# shellcheck disable=SC2016
726747
printf 'Ejected from the merge queue: this PR still carries the `needs-validation` label.\n\n'
727748
printf 'The merge queue gate ([run %s](%s/%s/actions/runs/%s)) blocked the queued group because of the label. That failure runs on the queue'"'"'s transient ref, so it never appears in this PR'"'"'s own checks — they stay green, and this notice is the only visible trace on the PR.\n\n' "$RUN_ID" "$GITHUB_SERVER_URL" "$REPO" "$RUN_ID"
749+
# shellcheck disable=SC2016
728750
printf 'To land this PR: complete the QA pass the label is tracking, remove the `needs-validation` label, then add the PR back to the merge queue.\n'
729751
} > "$handoff_dir/body.md"
730752
jq -n \

.github/workflows/cut-patch-release.yml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,12 @@ jobs:
100100
# (e.g. version=0.15.1 gates open-design-v0.15.0, not the latest 0.14.0).
101101
vmajor=${V%%.*}; vrest=${V#*.}; vminor=${vrest%%.*}
102102
MINOR_BASE="${vmajor}.${vminor}.0"
103-
echo "version=$V" >> "$GITHUB_OUTPUT"
104-
echo "branch=release/v$V" >> "$GITHUB_OUTPUT"
105-
echo "minor_base=$MINOR_BASE" >> "$GITHUB_OUTPUT"
106-
echo "minor_tag=open-design-v$MINOR_BASE" >> "$GITHUB_OUTPUT"
103+
{
104+
echo "version=$V"
105+
echo "branch=release/v$V"
106+
echo "minor_base=$MINOR_BASE"
107+
echo "minor_tag=open-design-v$MINOR_BASE"
108+
} >> "$GITHUB_OUTPUT"
107109
echo "Cutting patch v$V (branch release/v$V); gating on stable v$MINOR_BASE"
108110
109111
# Guard: the minor this patch sits on (the Tuesday cut) must already be a

.github/workflows/landing-page-ci.yml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,9 @@ jobs:
8181
- name: Setup workspace
8282
uses: ./.github/actions/setup-workspace
8383

84-
- name: Cache generated previews
84+
- name: Restore generated previews
8585
id: previews-cache
86-
uses: actions/cache@v5.0.5
86+
uses: actions/cache/restore@v5
8787
with:
8888
path: apps/landing-page/public/previews
8989
key: landing-page-previews-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml', 'package.json', 'apps/landing-page/package.json', 'apps/landing-page/scripts/generate-previews.ts', 'apps/landing-page/scripts/fallback-preview-card.ts', 'skills/**', 'design-templates/**', 'templates/live-artifacts/**', 'plugins/_official/**') }}
@@ -125,6 +125,13 @@ jobs:
125125
OD_LANDING_NOINDEX: '1'
126126
run: pnpm --filter @open-design/landing-page build:static
127127

128+
- name: Save generated previews
129+
if: ${{ steps.previews-cache.outputs.cache-hit != 'true' && github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }}
130+
uses: actions/cache/save@v5
131+
with:
132+
path: apps/landing-page/public/previews
133+
key: landing-page-previews-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml', 'package.json', 'apps/landing-page/package.json', 'apps/landing-page/scripts/generate-previews.ts', 'apps/landing-page/scripts/fallback-preview-card.ts', 'skills/**', 'design-templates/**', 'templates/live-artifacts/**', 'plugins/_official/**') }}
134+
128135
- name: Lint changed blog SEO
129136
# The build above sets OD_LANDING_NOINDEX=1, so every rendered page in
130137
# `out/` carries `noindex`. Pass the same flag through so the SEO linter

.github/workflows/release-beta-s.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,8 @@ jobs:
754754
-BuildJsonPath "C:\.tmp\runner\od-beta\win_x64\build\build.json" `
755755
-IndexPath "C:\.tmp\runner\od-beta\win_x64\build\index.json" `
756756
-ReportRoot "C:\.tmp\runner\od-beta\win_x64\release-report\win_x64" `
757-
-OutputsPath "C:\.tmp\runner\od-beta\win_x64\build\outputs.json"
757+
-OutputsPath "C:\.tmp\runner\od-beta\win_x64\build\outputs.json" `
758+
-RequireVelaCli
758759
759760
- name: Write win_x64 release report
760761
if: ${{ always() }}
@@ -979,6 +980,10 @@ jobs:
979980
RELEASE_LATEST_CAS_REQUIRED: "true"
980981
RELEASE_ASSET_SUFFIX: auto
981982
RELEASE_CHANNEL: betas
983+
RELEASE_LAUNCHER_VERSION_MIN_BETAS: ${{ vars.RELEASE_LAUNCHER_VERSION_MIN_BETAS }}
984+
RELEASE_LAUNCHER_VERSION_MIN_STABLE: ${{ vars.RELEASE_LAUNCHER_VERSION_MIN_STABLE }}
985+
RELEASE_LAUNCHER_VERSION_MIN_URL_BETAS: ${{ vars.RELEASE_LAUNCHER_VERSION_MIN_URL_BETAS }}
986+
RELEASE_LAUNCHER_VERSION_MIN_URL_STABLE: ${{ vars.RELEASE_LAUNCHER_VERSION_MIN_URL_STABLE }}
982987
RELEASE_MANIFEST_DIR: ${{ runner.temp }}/release-platform-manifests
983988
RELEASE_METADATA_DIR: ${{ runner.temp }}/release-metadata
984989
RELEASE_NOTE_MANIFEST_PATH: ${{ runner.temp }}/release-metadata/release-note-publication.json

0 commit comments

Comments
 (0)