Skip to content

Commit 70c8839

Browse files
committed
Fix adapter installation
1 parent 2c74835 commit 70c8839

7 files changed

Lines changed: 106 additions & 44 deletions

File tree

scripts/lib/io/shell.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ export const shellIo = {
2121
turboBuild: () => $`bun turbo build`,
2222
bunInstall: () => $`bun install`,
2323
publishCliPackage: () => $`bun scripts/release-cli/publish-cli-package.ts`,
24-
verifyCli: (version: string) => $`bun scripts/release-cli/verify.ts ${version}`,
24+
verifyPackages: (packages: string[], version: string) =>
25+
$`bun scripts/release-cli/verify.ts ${version} ${packages.join(',')}`,
2526

2627
// Filesystem
2728
readFile: (path: string) => Bun.file(path).text(),

scripts/release-cli/README.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@ Tag push: agent-facets@X.Y.Z
2727
┌───────────────────────────────────────────────────────────────┐
2828
│ finalize.ts │
2929
│ │
30-
│ 1. publish-cli-package.ts — synthesize agent-facets wrapper │
31-
│ with optionalDependencies → all 12 platform packages │
32-
│ 2. verify.ts — check all 13 packages exist on npm │
33-
│ 3. Create GitHub Release + Slack notification │
30+
│ 1. verify.ts — confirm 12 platform packages on npm │
31+
│ 2. publish-cli-package.ts — synthesize + publish │
32+
│ agent-facets wrapper with optionalDependencies → │
33+
│ all 12 platform packages │
34+
│ 3. verify.ts — confirm wrapper on npm │
35+
│ 4. Create GitHub Release + Slack notification │
3436
└───────────────────────────────────────────────────────────────┘
3537
```
3638

@@ -42,7 +44,7 @@ Tag push: agent-facets@X.Y.Z
4244
| `publish-platform.ts` | `publish-platform` (matrix) | Publish one `@agent-facets/cli-*` package |
4345
| `publish-cli-package.ts` | (called by finalize) | Synthesize and publish the `agent-facets` wrapper |
4446
| `finalize.ts` | `finalize-cli` | Orchestrate: publish wrapper → verify → announce |
45-
| `verify.ts` | (called by finalize) | Verify all 13 packages exist on npm (with retry) |
47+
| `verify.ts` | (called by finalize) | Verify a given list of packages exists on npm (with retry) |
4648
| `seed.ts` | (manual, `bun seed:cli`) | Seed platform package names on npm with v0.0.1 placeholders |
4749
| `targets.ts` | (imported) | Platform target matrix and pure helper functions |
4850

@@ -64,6 +66,8 @@ Users install via `npm install agent-facets`. npm resolves the correct platform
6466
1. Cross-compiling 12 binaries (can't use `npm publish` on source)
6567
2. Publishing 12 platform packages first (each in its own CI job to avoid OOM)
6668
3. Publishing the wrapper package last (it references all 12 via optionalDependencies)
67-
4. Verifying all 13 packages before announcing (npm registry propagation delay)
69+
4. Split verification to handle npm registry propagation delay: pre-publish verifies
70+
the 12 platforms (so the wrapper's `optionalDependencies` will resolve when users
71+
install), and post-publish verifies the wrapper itself before announcing
6872

6973
None of this fits `changeset publish`'s model, so the CLI has its own pipeline.

scripts/release-cli/finalize.test.ts

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from 'bun:test'
22
import * as announce from '../lib/announce'
33
import * as ci from '../lib/ci'
4-
import { SLACK_CHANNELS } from '../lib/constants'
4+
import { CLI_PACKAGE_NAME, SLACK_CHANNELS } from '../lib/constants'
55
import { io } from '../lib/io'
66
import { SAMPLE_CHANGELOG, shellPromise, shellResult, silenceIO } from '../lib/test-helpers'
77
import { finalize } from './finalize'
8+
import { platformPackageNames } from './targets'
89

910
describe('finalize.ts', () => {
1011
beforeEach(() => {
@@ -21,7 +22,7 @@ describe('finalize.ts', () => {
2122
function setupFinalizePath() {
2223
spyOn(io, 'mintGitHubAppToken').mockResolvedValue('fake-gh-token')
2324
spyOn(io, 'publishCliPackage').mockResolvedValue(shellResult())
24-
spyOn(io, 'verifyCli').mockResolvedValue(shellResult())
25+
spyOn(io, 'verifyPackages').mockResolvedValue(shellResult())
2526
spyOn(ci, 'loadWorkspacePackages').mockResolvedValue([
2627
{ name: 'agent-facets', version: '0.4.0', dir: 'packages/cli' },
2728
])
@@ -44,37 +45,47 @@ describe('finalize.ts', () => {
4445
expect(code).toBe(1)
4546
})
4647

47-
test('runs the full verify → publish pipeline', async () => {
48+
test('runs the full verify → publish → verify pipeline', async () => {
4849
process.env.CIRCLE_TAG = 'agent-facets@0.4.0'
4950
setupFinalizePath()
5051

5152
const publishSpy = spyOn(io, 'publishCliPackage').mockResolvedValue(shellResult())
52-
const verifySpy = spyOn(io, 'verifyCli').mockResolvedValue(shellResult())
53+
const verifySpy = spyOn(io, 'verifyPackages').mockResolvedValue(shellResult())
5354

5455
const code = await finalize()
5556

5657
expect(code).toBe(0)
5758
expect(publishSpy).toHaveBeenCalledTimes(1)
58-
expect(verifySpy).toHaveBeenCalledTimes(1)
59+
expect(verifySpy).toHaveBeenCalledTimes(2)
5960
})
6061

61-
test('verifies platform packages before publishing CLI package', async () => {
62+
test('verifies platforms, publishes CLI, then verifies CLI wrapper', async () => {
6263
process.env.CIRCLE_TAG = 'agent-facets@0.4.0'
6364
setupFinalizePath()
6465

65-
const callOrder: string[] = []
66-
spyOn(io, 'verifyCli').mockImplementation(() => {
67-
callOrder.push('verify')
66+
const callOrder: Array<{ phase: string; args?: unknown[] }> = []
67+
spyOn(io, 'verifyPackages').mockImplementation((packages: string[], version: string) => {
68+
callOrder.push({ phase: 'verify', args: [packages, version] })
6869
return shellPromise()
6970
})
7071
spyOn(io, 'publishCliPackage').mockImplementation(() => {
71-
callOrder.push('publish')
72+
callOrder.push({ phase: 'publish' })
7273
return shellPromise()
7374
})
7475

7576
await finalize()
7677

77-
expect(callOrder).toEqual(['verify', 'publish'])
78+
expect(callOrder.map((c) => c.phase)).toEqual(['verify', 'publish', 'verify'])
79+
80+
// First verify call: the 12 platform packages
81+
const firstVerifyArgs = callOrder[0]?.args
82+
expect(firstVerifyArgs?.[0]).toEqual(platformPackageNames())
83+
expect(firstVerifyArgs?.[1]).toBe('0.4.0')
84+
85+
// Second verify call: just the CLI wrapper
86+
const secondVerifyArgs = callOrder[2]?.args
87+
expect(secondVerifyArgs?.[0]).toEqual([CLI_PACKAGE_NAME])
88+
expect(secondVerifyArgs?.[1]).toBe('0.4.0')
7889
})
7990

8091
test('mints GitHub token for release creation', async () => {
@@ -90,15 +101,17 @@ describe('finalize.ts', () => {
90101
expect(process.env.GITHUB_TOKEN).toBe('gh-token')
91102
})
92103

93-
test('passes version to verify', async () => {
104+
test('passes version and correct package list to both verify calls', async () => {
94105
process.env.CIRCLE_TAG = 'agent-facets@0.4.0'
95106
setupFinalizePath()
96107

97-
const verifySpy = spyOn(io, 'verifyCli').mockResolvedValue(shellResult())
108+
const verifySpy = spyOn(io, 'verifyPackages').mockResolvedValue(shellResult())
98109

99110
await finalize()
100111

101-
expect(verifySpy).toHaveBeenCalledWith('0.4.0')
112+
expect(verifySpy).toHaveBeenCalledTimes(2)
113+
expect(verifySpy).toHaveBeenNthCalledWith(1, platformPackageNames(), '0.4.0')
114+
expect(verifySpy).toHaveBeenNthCalledWith(2, [CLI_PACKAGE_NAME], '0.4.0')
102115
})
103116

104117
test('creates GitHub Release after verify', async () => {

scripts/release-cli/finalize.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020

2121
import { announceRelease } from '../lib/announce'
2222
import { loadWorkspacePackages, mintGithubTokens } from '../lib/ci'
23+
import { CLI_PACKAGE_NAME } from '../lib/constants'
2324
import { io } from '../lib/io'
2425
import { parseTag } from '../lib/tags'
26+
import { platformPackageNames } from './targets'
2527

2628
export async function finalize(): Promise<number> {
2729
const tag = process.env.CIRCLE_TAG
@@ -41,15 +43,21 @@ export async function finalize(): Promise<number> {
4143
// Mint GitHub token (for Release creation; npm OIDC is handled by the publish script)
4244
await mintGithubTokens()
4345

44-
// Verify platform packages are visible on npm before publishing the CLI package.
46+
// Verify the 12 platform packages are visible on npm before publishing the CLI wrapper.
4547
// The CLI package's optionalDependencies must be resolvable when users install it.
4648
io.log('Verifying platform packages in registry...')
47-
await io.verifyCli(parsed.version)
49+
await io.verifyPackages(platformPackageNames(), parsed.version)
4850

49-
// Publish CLI package to latest (synthesizes from build output, mints its own OIDC token)
51+
// Publish CLI package to latest (synthesizes from build output, mints its own OIDC token).
52+
// The wrapper is always the LAST package published — users cannot install the new version
53+
// until this completes successfully.
5054
io.log('Publishing CLI package...')
5155
await io.publishCliPackage()
5256

57+
// Verify the CLI wrapper itself propagated to npm before announcing.
58+
io.log('Verifying CLI package in registry...')
59+
await io.verifyPackages([CLI_PACKAGE_NAME], parsed.version)
60+
5361
io.log(`Published ${parsed.name}@${parsed.version} (all platform packages)`)
5462

5563
// Announce

scripts/release-cli/targets.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,14 @@ export interface TargetPackageJson {
3232
cpu: string[]
3333
}
3434

35+
/** The 12 platform binary package names (excludes the CLI wrapper). */
36+
export function platformPackageNames(): string[] {
37+
return allTargets.map(packageName)
38+
}
39+
3540
/** All 13 npm package names: 12 platform binaries + the CLI package. */
3641
export function allPackageNames(): string[] {
37-
return [...allTargets.map(packageName), CLI_PACKAGE_NAME]
42+
return [...platformPackageNames(), CLI_PACKAGE_NAME]
3843
}
3944

4045
// ---------------------------------------------------------------------------

scripts/release-cli/verify.test.ts

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from 'bun:test'
2+
import { CLI_PACKAGE_NAME } from '../lib/constants'
23
import * as npm from '../lib/npm'
3-
import { allPackageNames } from './targets'
4+
import { allPackageNames, platformPackageNames } from './targets'
45
import { verify } from './verify'
56

67
const VERSION = '1.0.0'
78
const ALL_PACKAGES = allPackageNames()
9+
const PLATFORM_PACKAGES = platformPackageNames()
810

911
describe('verify.ts', () => {
1012
beforeEach(() => {
@@ -19,15 +21,15 @@ describe('verify.ts', () => {
1921
test('returns 0 when all packages are found on first attempt', async () => {
2022
spyOn(npm, 'versionExists').mockResolvedValue(true)
2123

22-
const code = await verify(VERSION, 0)
24+
const code = await verify(ALL_PACKAGES, VERSION, 0)
2325

2426
expect(code).toBe(0)
2527
})
2628

27-
test('verifies all 13 packages (12 platform + main)', async () => {
29+
test('verifies all 13 packages (12 platform + main) when given the full list', async () => {
2830
const veSpy = spyOn(npm, 'versionExists').mockResolvedValue(true)
2931

30-
await verify(VERSION, 0)
32+
await verify(ALL_PACKAGES, VERSION, 0)
3133

3234
const checkedPackages = new Set(veSpy.mock.calls.map(([pkg]) => pkg))
3335
for (const pkg of ALL_PACKAGES) {
@@ -36,6 +38,30 @@ describe('verify.ts', () => {
3638
expect(checkedPackages.size).toBe(13)
3739
})
3840

41+
test('verifies only the packages provided in the list (platform-only path)', async () => {
42+
const veSpy = spyOn(npm, 'versionExists').mockResolvedValue(true)
43+
44+
await verify(PLATFORM_PACKAGES, VERSION, 0)
45+
46+
const checkedPackages = new Set(veSpy.mock.calls.map(([pkg]) => pkg))
47+
expect(checkedPackages.size).toBe(12)
48+
for (const pkg of PLATFORM_PACKAGES) {
49+
expect(checkedPackages.has(pkg)).toBe(true)
50+
}
51+
// CLI wrapper must not be checked when only platforms are passed
52+
expect(checkedPackages.has(CLI_PACKAGE_NAME)).toBe(false)
53+
})
54+
55+
test('verifies a single package (CLI wrapper path)', async () => {
56+
const veSpy = spyOn(npm, 'versionExists').mockResolvedValue(true)
57+
58+
await verify([CLI_PACKAGE_NAME], VERSION, 0)
59+
60+
const checkedPackages = new Set(veSpy.mock.calls.map(([pkg]) => pkg))
61+
expect(checkedPackages.size).toBe(1)
62+
expect(checkedPackages.has(CLI_PACKAGE_NAME)).toBe(true)
63+
})
64+
3965
test('retries when some packages are missing, succeeds when they appear', async () => {
4066
const missingPkg = ALL_PACKAGES[0]
4167
let attempt = 0
@@ -48,7 +74,7 @@ describe('verify.ts', () => {
4874
return true
4975
})
5076

51-
const code = await verify(VERSION, 0)
77+
const code = await verify(ALL_PACKAGES, VERSION, 0)
5278

5379
expect(code).toBe(0)
5480
})
@@ -58,7 +84,7 @@ describe('verify.ts', () => {
5884

5985
spyOn(npm, 'versionExists').mockImplementation(async (pkg: string) => !missing.has(pkg))
6086

61-
const code = await verify(VERSION, 0)
87+
const code = await verify(ALL_PACKAGES, VERSION, 0)
6288

6389
expect(code).toBe(1)
6490
})
@@ -72,7 +98,7 @@ describe('verify.ts', () => {
7298
return pkg !== missingPkg
7399
})
74100

75-
await verify(VERSION, 0)
101+
await verify(ALL_PACKAGES, VERSION, 0)
76102

77103
// Non-missing packages should only be checked once
78104
for (const pkg of ALL_PACKAGES) {

scripts/release-cli/verify.ts

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
#!/usr/bin/env bun
22

33
/**
4-
* Verify CLI platform packages exist in the npm registry.
4+
* Verify packages exist in the npm registry.
55
*
6-
* Checks that all 12 platform packages and the CLI package exist
7-
* at the expected version. Retries with exponential backoff to handle
8-
* npm registry propagation delay.
6+
* Checks that the given packages exist at the expected version. Retries with
7+
* exponential backoff to handle npm registry propagation delay.
98
*
10-
* Usage: bun scripts/release-cli/verify.ts <version>
9+
* Usage:
10+
* bun scripts/release-cli/verify.ts <version>
11+
* bun scripts/release-cli/verify.ts <version> <pkg1,pkg2,...>
12+
*
13+
* If no package list is provided, defaults to all 13 CLI packages
14+
* (12 platform binaries + the CLI wrapper) for standalone auditing.
1115
*/
1216

1317
import { versionExists } from '../lib/npm'
@@ -20,12 +24,11 @@ function sleep(ms: number): Promise<void> {
2024
return new Promise((resolve) => setTimeout(resolve, ms))
2125
}
2226

23-
export async function verify(version: string, initialDelayMs = INITIAL_DELAY_MS): Promise<number> {
24-
const packages = allPackageNames()
27+
export async function verify(packages: string[], version: string, initialDelayMs = INITIAL_DELAY_MS): Promise<number> {
2528
let pending = new Set(packages)
2629

27-
console.log(`\n=== Verify CLI Packages ===`)
28-
console.log(`\n Checking ${packages.length} packages at version ${version}...\n`)
30+
console.log(`\n=== Verify Packages ===`)
31+
console.log(`\n Checking ${packages.length} package(s) at version ${version}...\n`)
2932

3033
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
3134
if (attempt > 0) {
@@ -47,7 +50,7 @@ export async function verify(version: string, initialDelayMs = INITIAL_DELAY_MS)
4750
pending = stillPending
4851

4952
if (pending.size === 0) {
50-
console.log(`\n=== All ${packages.length} packages verified ===`)
53+
console.log(`\n=== All ${packages.length} package(s) verified ===`)
5154
return 0
5255
}
5356

@@ -67,9 +70,11 @@ export async function verify(version: string, initialDelayMs = INITIAL_DELAY_MS)
6770
if (import.meta.main) {
6871
const version = process.argv[2]
6972
if (!version) {
70-
console.error('Usage: bun scripts/release-cli/verify.ts <version>')
73+
console.error('Usage: bun scripts/release-cli/verify.ts <version> [pkg1,pkg2,...]')
7174
process.exit(1)
7275
}
73-
const code = await verify(version)
76+
const packagesArg = process.argv[3]
77+
const packages = packagesArg ? packagesArg.split(',').filter(Boolean) : allPackageNames()
78+
const code = await verify(packages, version)
7479
process.exit(code)
7580
}

0 commit comments

Comments
 (0)