chore: import upstream snapshot with attribution
CI / typecheck · build · test · bundle-size (push) Failing after 1s
CI / clean-room dependency closure smoke (push) Failing after 1s
CI / server-runtime e2e (docker · pg + valkey) (push) Failing after 2s
Deploy Install Scripts / deploy (push) Failing after 2s
Windows / build (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 12:07:03 +08:00
commit f9447f8e5f
848 changed files with 195208 additions and 0 deletions
+116
View File
@@ -0,0 +1,116 @@
name: CI
on:
pull_request:
push:
branches: [main]
jobs:
build:
name: typecheck · build · test · bundle-size
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Bun (worker runtime + test runner)
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
# The repo intentionally gitignores package-lock.json (.gitignore), so
# `cache: 'npm'` and `npm ci` (both require a committed lockfile) cannot
# be used here — matches windows.yml / npm-publish.yml, which install the
# same way.
- name: Install dependencies
run: npm install --no-audit --no-fund
- name: Typecheck
run: npm run typecheck
# `npm run build` runs scripts/build-hooks.js, which enforces the worker
# bundle-size guardrail (WORKER_SERVICE_MAX_BYTES, see #2584) and the MCP
# server budget. A bundle that grows past threshold fails here → fails CI.
- name: Build (includes bundle-size guardrails)
run: npm run build
# The in-process server-runtime smoke test (tests/server/server-runtime-smoke.test.ts,
# #2550) runs here with no Docker: it boots the server HTTP surface in
# process, loads a mode, creates a key, makes an authed request, and
# checks the viewer responds. This gives every PR real server-runtime
# coverage. The full pg+redis e2e is the docker-gated job below.
- name: Test
run: bun test
clean-room-deps:
name: clean-room dependency closure smoke
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Bun (worker runtime + test runner)
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
# See note in the build job: no committed root lockfile, so npm install.
- name: Install dependencies
run: npm install --no-audit --no-fund
# Run the frozen-lockfile drift check against the COMMITTED tree BEFORE
# `npm run build` regenerates plugin/package.json + plugin/bun.lock (via
# gen-plugin-lockfile.cjs). If a contributor changed plugin deps (through
# scripts/build-hooks.js) but committed a stale plugin/bun.lock, the
# committed pair is out of sync and --frozen-lockfile fails here.
- name: Verify plugin lockfile is in sync (frozen-lockfile drift check)
working-directory: plugin
run: bun install --frozen-lockfile --ignore-scripts
- name: Build
run: npm run build
# Clean-room install + import smoke test (plan-10): installs the packed
# tarball into a throwaway dir and verifies the dependency closure resolves
# and imports outside the dev tree.
- name: Clean-room dependency closure smoke
run: npm run smoke:clean-room
server-runtime-e2e-docker:
name: server-runtime e2e (docker · pg + valkey)
runs-on: ubuntu-latest
timeout-minutes: 30
# Docker is available on ubuntu-latest GitHub runners. This job runs the
# full server-runtime e2e (#2550): real Postgres + Valkey, queue durability,
# restart recovery, and revoked-key denial. It does not gate PRs from the
# `build` job; a failure here surfaces a server-runtime regression before a
# user can file one (plan-07 test matrix).
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
# See note in the build job: no committed lockfile, so npm install.
- name: Install dependencies
run: npm install --no-audit --no-fund
- name: Verify Docker is available
run: docker compose version
- name: Server-runtime Docker e2e
run: npm run e2e:server:docker
+41
View File
@@ -0,0 +1,41 @@
name: Claude Code
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
pull_request_review:
types: [submitted]
jobs:
claude:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
issues: read
id-token: write
actions: read
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 1
- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
additional_permissions: |
actions: read
+123
View File
@@ -0,0 +1,123 @@
name: Close Tracked Issues
# When a "tracking" issue is closed, close every issue listed under its
# "### Issues" section. Tracking issues consolidate several duplicate bug
# reports that share one root cause; closing the tracker resolves them all.
# PRs listed under "### PRs" are intentionally left untouched — those are
# fixes to be merged, not closed.
on:
issues:
types: [closed]
workflow_dispatch:
inputs:
issue_number:
description: 'Tracking issue number to fan-out close from'
required: true
type: number
jobs:
close-tracked:
runs-on: ubuntu-latest
if: |
(github.event_name == 'issues' && contains(github.event.issue.labels.*.name, 'tracking')) ||
github.event_name == 'workflow_dispatch'
permissions:
issues: write
contents: read
steps:
- name: Close issues tracked by this tracker
uses: actions/github-script@v8
with:
script: |
// Resolve the tracking issue (dispatch passes a number; event gives the payload).
let tracker;
if (context.eventName === 'workflow_dispatch') {
const { data } = await github.rest.issues.get({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.inputs.issue_number,
});
tracker = data;
} else {
tracker = context.payload.issue;
}
// The `issues: closed` trigger guarantees a closed tracker. The manual
// workflow_dispatch path bypasses that, and its only valid use is to
// re-run the fan-out on a tracker that is *already* closed (e.g. a prior
// run failed, or issues were added to the list after it closed). Refuse
// to close children while the tracker is still open — otherwise a stray
// dispatch on any issue with an "### Issues" section would bulk-close it.
if (context.eventName === 'workflow_dispatch' && tracker.state !== 'closed') {
console.log(`Tracker #${tracker.number} is open — refusing to fan-out close. `
+ `Close the tracker first, then re-dispatch.`);
return;
}
const body = tracker.body || '';
console.log(`Tracker #${tracker.number}: ${tracker.title}`);
// Isolate the "### Issues" section so we don't pick up PR numbers
// from the "### PRs" block. The section runs until the next heading of
// any level (#{2,} covers H2-H6) or end of body.
const match = body.match(/###\s+Issues\s*\n([\s\S]*?)(?=\n#{2,}\s|\n*$)/i);
if (!match) {
console.log('No "### Issues" section found; nothing to close.');
return;
}
// Collect every #NNNN referenced in that block, de-duplicated.
const numbers = [...new Set(
[...match[1].matchAll(/#(\d+)/g)].map((m) => parseInt(m[1], 10))
)].filter((n) => n !== tracker.number);
if (numbers.length === 0) {
console.log('No issue references found in the Issues section.');
return;
}
console.log(`Tracked issues: ${numbers.map((n) => `#${n}`).join(', ')}`);
for (const issue_number of numbers) {
try {
const { data: target } = await github.rest.issues.get({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number,
});
// Skip pull requests (the REST issues API returns them too).
if (target.pull_request) {
console.log(`#${issue_number} is a PR — skipping.`);
continue;
}
if (target.state === 'closed') {
console.log(`#${issue_number} already closed — skipping.`);
continue;
}
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number,
body: `Resolved via tracking issue #${tracker.number}, which has been closed. `
+ `This report shared a root cause with others consolidated there — `
+ `closing as part of that group. See #${tracker.number} for the details.`,
});
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number,
state: 'closed',
state_reason: 'completed',
});
console.log(`Closed #${issue_number}.`);
} catch (error) {
// One bad reference shouldn't abort the rest of the fan-out.
console.log(`Failed to close #${issue_number}: ${error.message}`);
}
}
@@ -0,0 +1,130 @@
name: Convert Feature Requests to Discussions
on:
issues:
types: [labeled]
workflow_dispatch:
inputs:
issue_number:
description: 'Issue number to convert to discussion'
required: true
type: number
jobs:
convert:
runs-on: ubuntu-latest
if: |
(github.event_name == 'issues' && github.event.label.name == 'feature-request') ||
github.event_name == 'workflow_dispatch'
permissions:
issues: write
discussions: write
contents: read
steps:
- name: Get issue details and create discussion
id: discussion
uses: actions/github-script@v8
with:
script: |
// Get issue details
let issue;
if (context.eventName === 'workflow_dispatch') {
const { data } = await github.rest.issues.get({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.inputs.issue_number
});
issue = data;
} else {
issue = context.payload.issue;
}
console.log(`Processing issue #${issue.number}: ${issue.title}`);
// Format the discussion body with a reference to the original issue
const discussionBody = `> Originally posted as issue #${issue.number} by @${issue.user.login}\n> ${issue.html_url}\n\n${issue.body || 'No description provided.'}`;
const mutation = `
mutation($repositoryId: ID!, $categoryId: ID!, $title: String!, $body: String!) {
createDiscussion(input: {
repositoryId: $repositoryId
categoryId: $categoryId
title: $title
body: $body
}) {
discussion {
url
number
}
}
}
`;
const variables = {
repositoryId: 'R_kgDOPng1Jw',
categoryId: 'DIC_kwDOPng1J84Cw86z',
title: issue.title,
body: discussionBody
};
try {
const result = await github.graphql(mutation, variables);
const discussionUrl = result.createDiscussion.discussion.url;
const discussionNumber = result.createDiscussion.discussion.number;
core.setOutput('url', discussionUrl);
core.setOutput('number', discussionNumber);
core.setOutput('issue_number', issue.number);
console.log(`Created discussion #${discussionNumber}: ${discussionUrl}`);
return { discussionUrl, discussionNumber, issueNumber: issue.number };
} catch (error) {
core.setFailed(`Failed to create discussion: ${error.message}`);
throw error;
}
- name: Comment on issue
uses: actions/github-script@v8
with:
script: |
const issueNumber = ${{ steps.discussion.outputs.issue_number }};
const discussionUrl = '${{ steps.discussion.outputs.url }}';
const comment = `This feature request has been moved to [Discussions](${discussionUrl}) to keep bug reports separate from feature ideas.\n\nPlease continue the conversation there - we'd love to hear your thoughts!`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
body: comment
});
console.log(`Added comment to issue #${issueNumber}`);
- name: Close and lock issue
uses: actions/github-script@v8
with:
script: |
const issueNumber = ${{ steps.discussion.outputs.issue_number }};
// Close the issue
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
state: 'closed'
});
console.log(`Closed issue #${issueNumber}`);
// Lock the issue
await github.rest.issues.lock({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
lock_reason: 'resolved'
});
console.log(`Locked issue #${issueNumber}`);
@@ -0,0 +1,29 @@
name: Deploy Install Scripts
on:
push:
branches: [main]
paths:
- 'openclaw/install.sh'
- 'install/**'
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Copy install scripts to deploy directory
run: |
mkdir -p install/public
cp openclaw/install.sh install/public/openclaw.sh
- name: Deploy to Vercel
uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
vercel-args: '--prod'
working-directory: ./install
+26
View File
@@ -0,0 +1,26 @@
name: Publish to npm
on:
push:
tags:
- 'v*'
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Install Bun (required by smoke:clean-room)
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- run: npm install --ignore-scripts
- run: npm run build
- run: npm run smoke:clean-room
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+34
View File
@@ -0,0 +1,34 @@
name: Summarize new issues
on:
issues:
types: [opened]
jobs:
summary:
runs-on: ubuntu-latest
permissions:
issues: write
models: read
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Run AI inference
id: inference
uses: actions/ai-inference@v2
with:
prompt: |
Summarize the following GitHub issue in one paragraph:
Title: ${{ github.event.issue.title }}
Body: ${{ github.event.issue.body }}
- name: Comment with AI summary
run: |
gh issue comment "$ISSUE_NUMBER" --body "$RESPONSE"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ISSUE_NUMBER: ${{ github.event.issue.number }}
RESPONSE: ${{ steps.inference.outputs.response }}
+38
View File
@@ -0,0 +1,38 @@
name: Windows
on:
pull_request:
paths:
- 'src/**'
- 'plugin/scripts/**'
- 'package.json'
- 'bunfig.toml'
- '.github/workflows/windows.yml'
push:
branches: [main]
jobs:
build:
# Pinned to windows-2022 (VS2022 / v17). The windows-latest image moved to
# windows-2025, which ships Visual Studio 18 — npm's bundled node-gyp@11.5.0
# can't detect it ("unknown version undefined") and native tree-sitter
# rebuilds fail during `npm install`. Revisit when node-gyp gains VS18 support.
runs-on: windows-2022
timeout-minutes: 25
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- name: Install Bun (worker runtime)
run: |
irm bun.sh/install.ps1 | iex
shell: pwsh
- run: npm install --no-audit --no-fund
# Build only — the build-and-sync script also runs marketplace sync + worker
# restart from a hardcoded ~/.claude/plugins path that doesn't exist on CI.
- run: npm run build