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
9 changes: 9 additions & 0 deletions .changeset/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
}
2 changes: 1 addition & 1 deletion .github/workflows/auto-close-issues.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Auto Close Issues on PR Merge
on:
pull_request:
types: [closed]
branches: [develop, main]
branches: [main]

jobs:
close-issues:
Expand Down
20 changes: 8 additions & 12 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
name: Publish to npm
name: Publish to npm (manual)

# Emergency fallback: manually trigger npm publish for a specific ref.
# Normal releases are handled by release.yml via changesets/action.
on:
release:
types: [published]
workflow_dispatch:

jobs:
publish:
Expand All @@ -12,20 +13,15 @@ jobs:
id-token: write

steps:
- name: Checkout
uses: actions/checkout@v4
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
registry-url: "https://registry.npmjs.org"

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build
- run: npm ci
- run: npm run build

- name: Publish to npm
run: npm publish --access public
Expand Down
93 changes: 27 additions & 66 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,90 +1,51 @@
name: Release

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

permissions:
contents: write
pull-requests: write

jobs:
# Only run when a release/* PR is merged (not closed without merge)
check:
if: github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/v')
release:
name: Release
runs-on: ubuntu-latest
outputs:
version: ${{ steps.extract.outputs.version }}
steps:
- name: Extract version from branch name
id: extract
run: |
BRANCH="${{ github.event.pull_request.head.ref }}"
VERSION="${BRANCH#release/v}"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "Releasing v${VERSION}"

# ── 1. Build + test gate ─────────────────────────────────────────────────
verify:
needs: check
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20, 22]
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
node-version: "20"
registry-url: "https://registry.npmjs.org"

- run: npm ci
- run: npm run build
- run: node --test test/*.test.mjs

# ── 2. Tag + GitHub Release → triggers publish.yml (npm) ────────────────
github-release:
needs: [check, verify]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Create tag and GitHub Release
# Creates a "Version Packages" PR when changesets are pending,
# or publishes to npm + creates GH Release when Version PR is merged.
- name: Create Version PR or Publish
id: changesets
uses: changesets/action@v1
with:
version: npm run version
publish: npm run release
title: "chore: version packages"
commit: "chore: version packages"
createGithubReleases: true
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ needs.check.outputs.version }}
run: |
git tag "v${VERSION}"
git push origin "v${VERSION}"
gh release create "v${VERSION}" --generate-notes --title "v${VERSION}"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

# ── 3. Publish to ClawHub ──────────────────────────────────────────────
clawhub-publish:
needs: [check, verify]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
- name: Publish skill to ClawHub
- name: Publish to ClawHub
if: steps.changesets.outputs.published == 'true'
env:
CLAWHUB_TOKEN: ${{ secrets.CLAWHUB_TOKEN }}
VERSION: ${{ needs.check.outputs.version }}
run: |
npx clawhub@latest auth login --token "$CLAWHUB_TOKEN" --no-browser
npx clawhub@latest publish "$(pwd)/skills/declaw" --version "$VERSION"

# ── 4. Backmerge main → develop ────────────────────────────────────────
backmerge:
needs: github-release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Merge main into develop
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git checkout develop
git merge main --no-edit
git push origin develop
npx clawhub@latest publish "$(pwd)/skills/declaw"
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: Test

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

jobs:
test:
Expand Down
141 changes: 78 additions & 63 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ OpenClaw plugin for direct P2P communication between agent instances over Yggdra
- Build: `npm run build`
- Run tests: `node --test test/*.test.mjs`
- Dev (watch mode): `npm run dev`
- Release: `bash scripts/release.sh patch|minor|major`
- Add changeset: `npx changeset add`
- Publish skill to ClawHub: `npx clawhub@latest publish skills/declaw`

Always run build before tests — tests import from `dist/`.
Expand Down Expand Up @@ -93,47 +93,33 @@ We use **Git Flow** for version control. Install with `brew install git-flow`.

### Branching Strategy (Git Flow)

- `main` — Production branch, always deployable
- `develop` — Integration branch for features
- `feature/<slug>` — New features (branch from `develop`)
- `fix/<slug>` — Bug fixes (branch from `develop`)
- `hotfix/<version>` — Urgent production fixes (branch from `main`)
- `main` — The only long-lived branch, always deployable
- `feature/<slug>` — New features (branch from `main`)
- `fix/<slug>` — Bug fixes (branch from `main`)

### Git Flow Commands
### Workflow

```bash
# Initialize git flow (first time only)
git flow init
# Start any change
git checkout main && git pull
git checkout -b feature/<slug> # or fix/<slug>

# Start a new feature
git flow feature start <name>
# ... make changes ...
npx changeset add # select patch/minor/major, write a description

# Finish feature — DO NOT use git flow feature finish
# Instead, push and create PR:
git push -u origin feature/<name>
gh pr create --base develop --head feature/<name>

# Start a hotfix
git flow hotfix start <version>

# Finish hotfix (merges to main and develop)
git flow hotfix finish <version>
git push origin main develop --tags

# Start a release
git flow release start <version>

# Finish release
git flow release finish <version>
git push origin main develop --tags
# Push and open PR targeting main
git push -u origin feature/<slug>
gh pr create --base main
```

No `develop` branch. No git-flow. No backmerge.

### Important: All Changes Via PR

**Both `main` and `develop` are branch-protected. No direct push allowed.**
**`main` is branch-protected. No direct push allowed.**

1. Push feature/fix branch to origin
2. Create PR targeting `develop` (features/fixes) or `main` (releases/hotfixes)
2. Create PR targeting `main`
3. CI must pass (`test (20)` + `test (22)`)
4. Squash merge only — one commit per PR
5. **Close the corresponding issue** when merging (use `Fixes #N` or `Closes #N` in the PR description)
Expand Down Expand Up @@ -163,50 +149,66 @@ When creating new issues:

1. All tests must pass: `npm run build && node --test test/*.test.mjs`
2. TypeScript must compile: `npm run build`
3. Feature branches merge to `develop` via PR
4. Hotfix branches merge to both `main` and `develop`
5. Releases: `develop` → `main` via PR
6. Reference the issue number in the PR description (e.g., `#123`)
7. Use closing keywords to auto-close issues on merge (e.g., `Fixes #123`, `Closes #123`)
3. Feature/fix branches merge to `main` via PR
4. Reference the issue number in the PR description (e.g., `#123`)
5. Use closing keywords to auto-close issues on merge (e.g., `Fixes #123`, `Closes #123`)

## Release Process

### Release Pipeline (Local + CI)
### How Releases Work (Changesets)

DeClaw uses [Changesets](https://github.com/changesets/changesets) for automated versioning and publishing. The flow aligns with mastra, langchain, and other major TypeScript projects.

One command kicks off the release via PR — CI handles the rest on merge:
**Step 1 — When opening a PR, add a changeset:**

```bash
bash scripts/release.sh patch # 0.2.2 → 0.2.3
bash scripts/release.sh minor # 0.2.2 → 0.3.0
bash scripts/release.sh major # 0.2.2 → 1.0.0
npx changeset add
# → select: patch / minor / major
# → write one line describing the change
# → commit the generated .changeset/xxx.md alongside your code
```

**Local (`scripts/release.sh`):**
1. **Preflight**: verifies on `main`, clean tree, synced with remote
2. **Build + test**: `npm run build` + `node --test test/*.test.mjs`
3. **Version bump**: syncs all 3 version-bearing files
4. **Changelog check**: warns if `CHANGELOG.md` is missing new version section
5. **Create Release PR**: pushes `release/vX.Y.Z` branch → creates PR targeting `main`
**Step 2 — Merge PR to `main`.**

CI (`release.yml`) detects the new changeset and automatically creates or updates a **"Version Packages" PR** that:
- Bumps `package.json`, `openclaw.plugin.json`, `skills/declaw/SKILL.md`
- Updates `CHANGELOG.md`

**Step 3 — Merge the "Version Packages" PR.**

**CI (`.github/workflows/release.yml`, triggered when `release/v*` PR merges into `main`):**
6. **Build + test gate**: Node 20 + 22 matrix
7. **Tag + GitHub Release**: creates `vX.Y.Z` tag + auto-generated release notes → triggers npm publish
8. **ClawHub publish**: `npx clawhub@latest publish` with `CLAWHUB_TOKEN` secret
9. **Backmerge**: main → develop (via github-actions bot)
CI runs again and automatically:
1. Publishes to npm (`NPM_TOKEN`)
2. Creates GitHub Release + tag
3. Publishes skill to ClawHub (`CLAWHUB_TOKEN`)

No manual version bumping, no release scripts, no backmerge.

### CI Workflows

| Workflow | Trigger | What it does |
|---|---|---|
| `release.yml` | Release PR merged into `main` | Verify → Tag → GH Release ClawHub → Backmerge |
| `publish.yml` | GH Release published | npm publish with `NPM_TOKEN` |
| `test.yml` | Push/PR to main/develop | Build + test (Node 20+22) |
| `release.yml` | Push to `main` | Changesets: create Version PR or publish npm + GH Release + ClawHub |
| `publish.yml` | `workflow_dispatch` only | Emergency manual npm publish |
| `test.yml` | Push/PR to `main` | Build + test (Node 20+22) |
| `auto-close-issues.yml` | PR merged | Close linked issues |
| `bootstrap-health.yml` | Scheduled | Ping all 5 bootstrap nodes |
| `bootstrap-health.yml` | Scheduled (every 6h) | Ping all 5 bootstrap nodes |

### Branch Strategy

`main` is the only long-lived branch. All feature/fix branches target `main` directly:

```bash
git checkout -b feature/<slug> # or fix/<slug>
# ... make changes + npx changeset add ...
git push -u origin feature/<slug>
gh pr create --base main
```

No `develop` branch. No backmerge.

### Branch Protection

Both `main` and `develop` are protected:
`main` is protected:
- **No direct push** — all changes via PR (squash merge only)
- **Required CI**: `test (20)` + `test (22)` must pass
- **No force push** or branch deletion
Expand All @@ -219,12 +221,25 @@ Both `main` and `develop` are protected:
- **Auto-delete branches**: merged PR branches are cleaned up automatically
- **Required secrets**: `NPM_TOKEN` (npm), `CLAWHUB_TOKEN` (ClawHub)

### Pre-release: Update CHANGELOG
### Version-bearing Files

`scripts/sync-version.mjs` (run automatically by `npm run version`) keeps these in sync:

| File | Field |
|---|---|
| `package.json` | `"version"` (canonical source — bumped by Changesets) |
| `package-lock.json` | `"version"` (auto-updated) |
| `openclaw.plugin.json` | `"version"` |
| `skills/declaw/SKILL.md` | `version:` in YAML frontmatter |

### Versioning

Semantic versioning: `vMAJOR.MINOR.PATCH`
- MAJOR: Breaking changes (in 0.x phase, MINOR covers breaking changes)
- MINOR: New features
- PATCH: Bug fixes

Before running the release script, update `CHANGELOG.md`:
- Add a `[X.Y.Z] - YYYY-MM-DD` section
- Categorize entries: `Breaking Changes`, `Added`, `Changed`, `Fixed`
- Reference issues and PRs (e.g., `PR #8`, `Closes #7`)
When adding a changeset, choose accordingly.

### Bootstrap Node Deployment
- Only needed when `bootstrap/server.mjs` or `bootstrap/package.json` changes
Expand All @@ -251,7 +266,7 @@ Before running the release script, update `CHANGELOG.md`:

### Version-bearing Files

These files must always have matching versions (handled by `scripts/release.sh`):
These files must always have matching versions (synced automatically by `scripts/sync-version.mjs` during `npm run version`):
| File | Field |
|---|---|
| `package.json` | `"version"` (canonical source) |
Expand Down
Loading