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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ concurrency:
cancel-in-progress: true

env:
BUN_VERSION: 1.3.10
BUN_VERSION: 1.3.14

jobs:
package-smoke:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ concurrency:
cancel-in-progress: false

env:
BUN_VERSION: 1.3.10
BUN_VERSION: 1.3.14

jobs:
preflight:
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ See [RELEASING.md](./RELEASING.md) for the release process and version-bump poli

### Fixed

- Standalone release builds now disable Bun identifier minification to avoid runtime name-collision crashes ([#36](https://github.com/Noumena-Network/code/issues/36)).
- Native `sharp` embedding build for macOS and other non-Linux targets ([#1](https://github.com/Noumena-Network/code/pull/1))
- Tool-call cancellation reason text on parallel tool cancellation ([#13](https://github.com/Noumena-Network/code/pull/13))
- NCode config and credentials are now isolated from Claude Code state on disk ([#11](https://github.com/Noumena-Network/code/pull/11))
Expand Down
11 changes: 10 additions & 1 deletion build/build.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,18 @@ const outFile = path.join(outDir, 'cli.js');
const bundledEntryFile = path.join(outDir, 'src', 'entrypoints', 'cli.js');
const bundledEntryMapFile = `${bundledEntryFile}.map`;
const outMapFile = `${outFile}.map`;
// Identifier mangling (`identifiers: true`) is disabled because Bun's
// bundler renamer can produce runtime identifier collisions in large bundles.
// In issue #36, the standalone CLI contained `function Hg(H4, $) { const A =
// H4(H4); ... }`, where a parameter shadowed the function binding and crashed
// at startup with `H4 is not a function`.
//
// Upstream tracking: oven-sh/bun#28742 documents the same collision class, and
// oven-sh/bun#30272 is the open compiler fix. Re-enable identifier mangling only
// after that fix ships and packageSmoke's manifest guard is updated deliberately.
export const SAFE_STANDALONE_MINIFY = {
whitespace: true,
identifiers: true,
identifiers: false,
};
const vendorSources = [
{
Expand Down
13 changes: 6 additions & 7 deletions build/package.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -195,13 +195,12 @@ export async function buildCompiledPackage(options = {}) {
outfile: binaryPath,
buildMode: parsed.buildMode,
target: targetInfo.compileTarget,
// Bun 1.3.10 miscompiles this CLI when syntax minification is combined
// with whitespace minification. The emitted bundle fuses `return` with
// helper identifiers in the workflow-tool closure (for example
// `return __toCommonJS(...)` becomes `return__toCommonJS(...)`, and
// `return dA(...)` becomes `returndA(...)`), which breaks `--help`
// at runtime. whitespace+identifiers is currently the smallest
// known safe profile for the real single-executable CLI.
// SAFE_STANDALONE_MINIFY intentionally keeps syntax and identifier
// minification disabled. Syntax minification has fused `return` with
// helper identifiers in this CLI, and identifier minification has produced
// runtime name collisions (issue #36, upstream oven-sh/bun#28742).
// Whitespace-only minification is the current safe profile for the real
// single-executable CLI.
minify: SINGLE_EXECUTABLE_MINIFY,
});

Expand Down
20 changes: 16 additions & 4 deletions build/packageSmoke.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ const FORBIDDEN_MANIFEST_KEYS = [
const EXPECTED_IMAGE_PROCESSOR_FALLBACK_WARNING =
'Native image processor not available, falling back to sharp';

// These are smoke-test budgets, not product latency SLOs. They catch broken
// startup paths while allowing GitHub-hosted macOS x64 cold starts enough room
// to avoid millisecond-level flakes after safe whitespace-only packaging.
const VERSION_CHECK_BUDGET_MS = 3_000;
const HELP_CHECK_BUDGET_MS = 4_000;

function parseArgs(argv) {
const args = {
outDir: undefined,
Expand Down Expand Up @@ -143,9 +149,9 @@ async function main() {
`Compiled binary version output did not match expected contract: ${versionResult.stdout}`,
);
}
if (versionResult.elapsedMs > 2_000) {
if (versionResult.elapsedMs > VERSION_CHECK_BUDGET_MS) {
throw new Error(
`Compiled binary --version exceeded fast-path budget: ${versionResult.elapsedMs}ms`,
`Compiled binary --version exceeded fast-path budget (${VERSION_CHECK_BUDGET_MS}ms): ${versionResult.elapsedMs}ms`,
);
}

Expand All @@ -163,9 +169,9 @@ async function main() {
.map(line => line.trimEnd())
.filter(line => line.trim().length > 0);
expectLinesInOrder(helpLines, ['Usage: ncode', 'Options:'], 'compiled binary --help output');
if (helpResult.elapsedMs > 4_000) {
if (helpResult.elapsedMs > HELP_CHECK_BUDGET_MS) {
throw new Error(
`Compiled binary --help exceeded fast-path budget: ${helpResult.elapsedMs}ms`,
`Compiled binary --help exceeded fast-path budget (${HELP_CHECK_BUDGET_MS}ms): ${helpResult.elapsedMs}ms`,
);
}
}
Expand All @@ -190,6 +196,12 @@ async function main() {
);
}

if (manifest.compileOptions?.minify?.identifiers === true) {
throw new Error(
'Standalone package manifest enabled identifier minification, which is unsafe for the mounted CLI runtime (issue #36).',
);
}

if (!result.securityAudit?.ok) {
throw new Error('Compiled package did not report a successful security audit.');
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
"test:teleport": "bun test src/utils/teleport/api.e2e.test.ts src/utils/teleport/environments.test.ts src/utils/teleport/sessionResumeValidation.test.ts src/utils/teleport.test.ts src/utils/cliDisplayCommand.test.ts src/utils/remoteSessionCliOutput.test.ts src/utils/teleportProgressOutput.test.ts src/utils/background/remote/preconditions.test.ts src/utils/background/remote/remoteSession.test.ts src/constants/product.test.ts",
"test:remote": "bun test src/remote/appServer/remoteAppServerBYOKSession.test.ts src/remote/appServer/remoteAppServerSession.test.ts src/remote/appServer/client.test.ts src/commands/teleport/index.test.ts src/commands/remote-env/index.test.ts src/session/remoteSubmitDispatch.test.ts src/session/remoteSubmitPolicy.test.ts src/components/RemoteCallout.test.tsx"
},
"packageManager": "bun@1.3.10",
"packageManager": "bun@1.3.14",
"dependencies": {
"@alcalzone/ansi-tokenize": "0.3.0",
"@anthropic-ai/bedrock-sdk": "0.26.4",
Expand Down
Loading