Skip to content

Commit 64d57d0

Browse files
authored
Merge pull request #495 from code-yeongyu/fix/issue-446-publish-gate
fix(release): validate staged bundle dependencies
2 parents 119f663 + d108cc4 commit 64d57d0

5 files changed

Lines changed: 58 additions & 5 deletions

File tree

packages/coding-agent/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
### Fixed
1414

15+
- Allow consumer-resolved native optional dependencies to remain outside the universal tarball's vendored bundle, enabling the cross-platform Claude Agent SDK sidecar fix to publish successfully ([#446](https://github.com/code-yeongyu/senpi/issues/446)).
16+
1517
### Removed
1618

1719
## [2026.7.29-2] - 2026-07-29

packages/coding-agent/changes.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Local fork changes
22

3+
## 2026-07-30 — Publish gate honors consumer-resolved platform optionals (#446)
4+
5+
- Changed: `assertSenpiPackedWorkspaceFiles()` now validates the staged `bundleDependencies` contract when it is available, while retaining the legacy all-runtime fallback for callers without a staged manifest.
6+
- Why: issue #446 intentionally promotes complete native optional-dependency families into the published root manifest so npm can select the consumer platform. The publish-only workflow still treated those non-bundled optionals as missing vendored files and stopped before npm publication.
7+
- What changed: `publish.mjs` passes the staged bundle list into the pack assertion, and focused RED→GREEN coverage proves a bundled portable Claude SDK may omit the consumer-resolved `darwin-arm64` package from the universal tarball.
8+
- Why the extension system could not handle this: the failure occurs in npm tarball validation before package publication or runtime extension loading.
9+
- Merge-conflict risk: low. Expected conflict zones are the publish pack assertion, `publish.mjs`, and the focused packaging test.
10+
311
## 2026-07-29 — Consumer-resolved Claude Agent SDK sidecars (#446)
412

513
- Changed: publish-manifest staging now promotes a bundled package's complete platform-specific optional dependency family into the root `@code-yeongyu/senpi` manifest while continuing to exclude the publish runner's materialized native package from `bundleDependencies`.

scripts/prepare-senpi-bundled-workspaces.mjs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,11 @@ export function assertSenpiPackedWorkspaceFiles(packed, options = {}) {
134134
const prebuildFiles = new Set(nativeTargets.map(nativePrebuildFile));
135135
const filePaths = new Set((packed.files ?? []).map((file) => file.path));
136136

137-
// Every runtime dependency of the publish manifest must be vendored in the tarball.
138-
// npm only packs node_modules entries reachable from bundleDependencies, so a dep
139-
// missing here means it would be fetched from the registry at install time — the
140-
// exact failure mode (nondeterministic ERR_MODULE_NOT_FOUND) the full bundle removes.
137+
// Every dependency selected by the staged bundle manifest must be vendored in the
138+
// tarball. Platform-specific optional dependencies intentionally stay outside this
139+
// list so npm can resolve the matching native package on the consumer machine.
141140
const missingRuntimeDependencies = [];
142-
for (const dependencyName of options.runtimeDependencies ?? []) {
141+
for (const dependencyName of options.bundledDependencies ?? options.runtimeDependencies ?? []) {
143142
const packageJsonPath = `node_modules/${dependencyName}/package.json`;
144143
if (!filePaths.has(`package/${packageJsonPath}`) && !filePaths.has(packageJsonPath)) {
145144
missingRuntimeDependencies.push(dependencyName);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import assert from "node:assert/strict";
2+
import { it } from "node:test";
3+
import {
4+
assertSenpiPackedWorkspaceFiles,
5+
nativePrebuildFile,
6+
nativePrebuildTarget,
7+
} from "./prepare-senpi-bundled-workspaces.mjs";
8+
9+
it("accepts consumer-resolved platform optionals outside the packed bundle", () => {
10+
// Given: the portable SDK is bundled, while npm must install the target-native
11+
// optional package on the consumer machine.
12+
const hostPrebuild = nativePrebuildFile(nativePrebuildTarget());
13+
const packed = {
14+
files: [
15+
{ path: "package/dist/cli.js" },
16+
{ path: "package/node_modules/@earendil-works/pi-agent-core/package.json" },
17+
{ path: "package/node_modules/@earendil-works/pi-agent-core/dist/index.js" },
18+
{ path: "package/node_modules/@earendil-works/pi-ai/package.json" },
19+
{ path: "package/node_modules/@earendil-works/pi-ai/dist/index.js" },
20+
{ path: "package/node_modules/@earendil-works/pi-pty/package.json" },
21+
{ path: "package/node_modules/@earendil-works/pi-pty/dist/index.js" },
22+
{ path: "package/node_modules/@earendil-works/pi-pty/native/index.js" },
23+
{ path: `package/node_modules/@earendil-works/pi-pty/${hostPrebuild}` },
24+
{ path: "package/node_modules/@earendil-works/pi-tui/package.json" },
25+
{ path: "package/node_modules/@earendil-works/pi-tui/dist/index.js" },
26+
{ path: "package/node_modules/@code-yeongyu/senpi-codemode/package.json" },
27+
{ path: "package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts" },
28+
{ path: "package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/prelude.py" },
29+
{ path: "package/node_modules/@anthropic-ai/claude-agent-sdk/package.json" },
30+
],
31+
};
32+
33+
// When / Then
34+
assert.doesNotThrow(() =>
35+
assertSenpiPackedWorkspaceFiles(packed, {
36+
runtimeDependencies: [
37+
"@anthropic-ai/claude-agent-sdk",
38+
"@anthropic-ai/claude-agent-sdk-darwin-arm64",
39+
],
40+
bundledDependencies: ["@anthropic-ai/claude-agent-sdk"],
41+
}),
42+
);
43+
});

scripts/publish.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ function validatePack(directory) {
105105
...Object.keys(packageJson.dependencies ?? {}),
106106
...Object.keys(packageJson.optionalDependencies ?? {}),
107107
],
108+
bundledDependencies: packageJson.bundleDependencies ?? packageJson.bundledDependencies,
108109
});
109110
}
110111
if (sourceOnlyPackages.has(packageJson.name)) {

0 commit comments

Comments
 (0)