Skip to content

Commit ca38ad6

Browse files
docs: add agent-safe release instructions
1 parent 25b56e7 commit ca38ad6

2 files changed

Lines changed: 88 additions & 10 deletions

File tree

AGENTS.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Arrow Monorepo — Agent Guide
2+
3+
Use this file for repo-wide automation and release tasks. Package-specific docs guidance still lives in `docs/AGENTS.md`.
4+
5+
## Release automation
6+
7+
The release entrypoint is:
8+
9+
```sh
10+
pnpm run release
11+
```
12+
13+
It supports both interactive and non-interactive usage.
14+
15+
### Interactive
16+
17+
- `pnpm run release`
18+
- `pnpm run release:next`
19+
- `pnpm run release:dev`
20+
21+
### Non-interactive
22+
23+
Use these forms for agent automation:
24+
25+
```sh
26+
pnpm run release -- --tag next --bump patch --yes
27+
pnpm run release -- --tag dev --bump patch --yes
28+
pnpm run release -- --tag latest --bump patch --yes
29+
```
30+
31+
Rules:
32+
33+
- `latest` is only allowed from `main`
34+
- `next` and `dev` can be created from non-main branches
35+
- `latest` updates package versions in git, commits, tags, and pushes
36+
- `next` and `dev` create and push only a git tag; the workflow sets publish versions from the tag at release time
37+
38+
Tag formats:
39+
40+
- `vX.Y.Z` -> npm `latest`
41+
- `vX.Y.Z-next.<hash>` -> npm `next`
42+
- `vX.Y.Z-dev.<hash>` -> npm `dev`
43+
44+
## Trusted publishing
45+
46+
Publishing is handled by `.github/workflows/publish.yml`.
47+
48+
- It uses GitHub OIDC trusted publishing
49+
- It installs `npm@latest`
50+
- It does not use an npm token
51+
- It blocks plain `vX.Y.Z` releases unless the tagged commit is on `main`
52+
53+
## Public package set
54+
55+
The automated release flow syncs and publishes:
56+
57+
- `@arrow-js/core`
58+
- `@arrow-js/framework`
59+
- `@arrow-js/highlight`
60+
- `@arrow-js/hydrate`
61+
- `@arrow-js/ssr`
62+
- `@arrow-js/vite-plugin-arrow`
63+
- `@arrow-js/skill`
64+
- `create-arrow-js`

scripts/release.mjs

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,25 +35,29 @@ if (args[0] === 'sync') {
3535

3636
await runInteractiveRelease({
3737
requestedTag: readFlagValue(args, '--tag'),
38+
requestedBump: readFlagValue(args, '--bump'),
3839
dryRun: args.includes('--dry-run'),
40+
skipConfirm: args.includes('--yes'),
3941
})
4042

41-
async function runInteractiveRelease({ requestedTag, dryRun }) {
43+
async function runInteractiveRelease({ requestedTag, requestedBump, dryRun, skipConfirm }) {
4244
if (!isWorkingDirectoryClean()) {
4345
fail('Working directory is not clean. Commit or stash changes first.')
4446
}
4547

4648
const branch = exec('git branch --show-current')
4749
const stableVersion = getStableVersion(readJson(rootPackagePath).version || readPackageVersion('packages/core'))
4850
const releaseTag = await resolveReleaseTag(branch, requestedTag)
49-
const bumpType = await promptChoice(
50-
'Select version bump type:',
51-
[
52-
{ key: '1', value: 'patch', label: `patch (${stableVersion} -> ${bumpVersion(stableVersion, 'patch')})` },
53-
{ key: '2', value: 'minor', label: `minor (${stableVersion} -> ${bumpVersion(stableVersion, 'minor')})` },
54-
{ key: '3', value: 'major', label: `major (${stableVersion} -> ${bumpVersion(stableVersion, 'major')})` },
55-
]
56-
)
51+
const bumpType = requestedBump
52+
? validateBumpType(requestedBump)
53+
: await promptChoice(
54+
'Select version bump type:',
55+
[
56+
{ key: '1', value: 'patch', label: `patch (${stableVersion} -> ${bumpVersion(stableVersion, 'patch')})` },
57+
{ key: '2', value: 'minor', label: `minor (${stableVersion} -> ${bumpVersion(stableVersion, 'minor')})` },
58+
{ key: '3', value: 'major', label: `major (${stableVersion} -> ${bumpVersion(stableVersion, 'major')})` },
59+
]
60+
)
5761
const nextStable = bumpVersion(stableVersion, bumpType)
5862
const commitHash = exec('git rev-parse --short=7 HEAD')
5963
const version = releaseTag === 'latest'
@@ -72,7 +76,9 @@ async function runInteractiveRelease({ requestedTag, dryRun }) {
7276
].join('\n')
7377
)
7478

75-
const confirmed = await promptConfirm(dryRun ? 'Continue with dry run?' : 'Continue with release?')
79+
const confirmed = skipConfirm
80+
? true
81+
: await promptConfirm(dryRun ? 'Continue with dry run?' : 'Continue with release?')
7682
if (!confirmed) {
7783
process.stdout.write('Release cancelled.\n')
7884
process.exit(0)
@@ -150,6 +156,14 @@ function validateReleaseTag(branch, requestedTag) {
150156
}
151157
}
152158

159+
function validateBumpType(value) {
160+
if (!['patch', 'minor', 'major'].includes(value)) {
161+
fail(`Unknown bump type "${value}". Use patch, minor, or major.`)
162+
}
163+
164+
return value
165+
}
166+
153167
function getStableVersion(version) {
154168
return version.split('-')[0]
155169
}

0 commit comments

Comments
 (0)