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 README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ npm install -g @codra/cli # coming soon
codra run --task summarize-context --jsonl
```

The [`@codra/cli`](packages/codra-npm-cli/) package is a thin Node wrapper that spawns the native `codra` binary built from `codra-cli`. For local development, see [packages/codra-npm-cli/README.md](packages/codra-npm-cli/README.md).
The [`@codra/cli`](packages/codra-npm-cli/) package is a thin Node wrapper that spawns the native `codra` binary built from `codra-cli`. Local `npm run build` packages only the current platform binary; multi-platform npm releases need a release workflow (see [packages/codra-npm-cli/README.md](packages/codra-npm-cli/README.md)).

## Roadmap

Expand Down
48 changes: 41 additions & 7 deletions packages/codra-npm-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@

npm package wrapper for the [Codra](https://github.com/talocode/codra) Rust CLI (`codra-cli` crate). Installs a global `codra` command that forwards to the native binary for your platform.

## Installation (coming soon)
**Status: not published to npm yet.**

This package is **not published to npm yet**. When it is:
## Installation (coming soon)

```bash
npm install -g @codra/cli
codra --help
```

## Local development
Until the package is published, use [local development](#local-development) below.

From the monorepo root (or this package directory):
## Local development

```bash
cd packages/codra-npm-cli
Expand All @@ -23,7 +23,43 @@ node bin/codra.js run --task summarize-context --jsonl
npm test
```

`npm run build` runs `cargo build -p codra-cli --release` and copies the release binary into `bin/native/<platform>-<arch>/`.
`npm run build` runs `cargo build -p codra-cli --release` and copies the release binary into `bin/native/<platform>-<arch>/` for **the current machine only** (for example `linux-arm64` on this host).

## Current limitation

- A local `npm run build` packages **only the current platform/arch** binary.
- `npm pack` / `npm publish` run `prepack`, which rebuilds and copies that same host binary into the tarball.
- End users on other platforms will see a clear error until release-built binaries for their OS/arch are included.
- Real public npm publishing needs release-built binaries for each supported target (see [Multi-platform release plan](#multi-platform-release-plan)).

This package does **not** ship multi-platform binaries today.

## Publishing checklist

When ready to publish (maintainers only):

1. `npm login`
2. `npm run build` — release Rust binary for this host
3. `npm test`
4. `npm run pack:dry` — verify tarball contents (runs `prepack` + dry-run checks)
5. Confirm tarball includes `README.md`, `package.json`, `bin/codra.js`, and `bin/native/<platform>-<arch>/codra` only
6. `npm publish --access public`

Do not publish until multi-platform release binaries are available for your intended audience, unless you are intentionally shipping a single-platform preview.

## Multi-platform release plan

Future release workflow should build and bundle:

| Target | Binary path |
|--------|-------------|
| `linux-x64` | `bin/native/linux-x64/codra` |
| `linux-arm64` | `bin/native/linux-arm64/codra` |
| `darwin-x64` | `bin/native/darwin-x64/codra` |
| `darwin-arm64` | `bin/native/darwin-arm64/codra` |
| `win32-x64` | `bin/native/win32-x64/codra.exe` |

Automation (GitHub Actions or similar) is not implemented yet.

## Supported commands

Expand All @@ -39,8 +75,6 @@ Invalid tasks exit non-zero. With `--jsonl`, failures emit `codra.run.failed`.

## GitHub context (optional)

When running in GitHub Actions or with fixtures:

| Variable | Purpose |
|----------|---------|
| `GITHUB_ACTIONS` | Detect Actions runtime |
Expand Down
77 changes: 59 additions & 18 deletions packages/codra-npm-cli/bin/codra.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,78 @@ const { spawnSync } = require('child_process');
const fs = require('fs');
const path = require('path');

const SUPPORTED_PLATFORMS = new Set([
'linux-arm64',
const PLANNED_PLATFORMS = [
'linux-x64',
'darwin-arm64',
'linux-arm64',
'darwin-x64',
'darwin-arm64',
'win32-x64',
]);
];

function platformArchKey() {
const platform = process.platform;
const arch = process.arch;
return `${platform}-${arch}`;
return `${process.platform}-${process.arch}`;
}

function binaryFileName(platformKey) {
return platformKey && platformKey.startsWith('win32') ? 'codra.exe' : 'codra';
}

function binaryFileName() {
return process.platform === 'win32' ? 'codra.exe' : 'codra';
function nativeBinaryPath(platformKey) {
const name = binaryFileName(platformKey);
return path.join(__dirname, 'native', platformKey, name);
}

function listInstalledBinaryPaths() {
const nativeRoot = path.join(__dirname, 'native');
if (!fs.existsSync(nativeRoot)) {
return [];
}

const installed = [];
for (const entry of fs.readdirSync(nativeRoot, { withFileTypes: true })) {
if (!entry.isDirectory()) continue;
const key = entry.name;
const candidate = nativeBinaryPath(key);
if (fs.existsSync(candidate)) {
installed.push(candidate);
}
}
return installed.sort();
}

function reportMissingBinary(requestedKey) {
const expected = nativeBinaryPath(requestedKey);
const installed = listInstalledBinaryPaths();

process.stderr.write(
`Codra CLI binary is not available for ${requestedKey} in this package.\n` +
`Expected path: ${expected}\n` +
`Planned release targets: ${PLANNED_PLATFORMS.join(', ')}\n`,
);

if (installed.length > 0) {
process.stderr.write('Binaries included in this package:\n');
for (const p of installed) {
process.stderr.write(` - ${p}\n`);
}
} else {
process.stderr.write(
'No native binaries are bundled. Run: npm run build (from packages/codra-npm-cli)\n',
);
}

process.stderr.write(
'Public npm installs require a release-built binary for your platform. ' +
'This tarball currently ships only binaries built on the publishing machine.\n',
);
}

function resolveNativeBinary() {
const key = platformArchKey();
const name = binaryFileName();
const nativePath = path.join(__dirname, 'native', key, name);
const nativePath = nativeBinaryPath(key);

if (!fs.existsSync(nativePath)) {
const supported = [...SUPPORTED_PLATFORMS].sort().join(', ');
process.stderr.write(
`codra: native binary not found for ${key}.\n` +
`Expected: ${nativePath}\n` +
`Supported platform keys (when built): ${supported}\n` +
`Build the package for this machine: npm run build (from packages/codra-npm-cli)\n`,
);
reportMissingBinary(key);
process.exit(1);
}

Expand Down
3 changes: 2 additions & 1 deletion packages/codra-npm-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"scripts": {
"build": "node scripts/build.js",
"test": "node scripts/test.js",
"pack:dry": "npm pack --dry-run"
"prepack": "node scripts/build.js",
"pack:dry": "node scripts/pack-dry-run.js"
},
"publishConfig": {
"access": "public"
Expand Down
58 changes: 58 additions & 0 deletions packages/codra-npm-cli/scripts/pack-dry-run.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
'use strict';

const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');

const packageRoot = path.resolve(__dirname, '..');
const forbidden = [/^node_modules\//, /^target\//, /\.env$/, /^scripts\//];

function main() {
const output = execSync('npm pack --dry-run 2>&1', {
cwd: packageRoot,
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'pipe'],
shell: true,
});

const lines = output.split('\n');
const tarballLines = lines.filter((line) => line.startsWith('npm notice '));
const fileLines = tarballLines
.map((line) => line.replace(/^npm notice /, '').trim())
.filter((line) => /^[\d.]+[kMG]?B\s+/.test(line))
.map((line) => line.replace(/^[\d.]+[kMG]?B\s+/, ''));

const errors = [];

for (const file of fileLines) {
if (forbidden.some((re) => re.test(file))) {
errors.push(`forbidden path in pack: ${file}`);
}
}

const required = ['package.json', 'README.md', 'bin/codra.js'];
for (const file of required) {
if (!fileLines.includes(file)) {
errors.push(`missing required file: ${file}`);
}
}

const nativeBins = fileLines.filter((f) => f.startsWith('bin/native/'));
if (nativeBins.length === 0) {
errors.push('no bin/native/<platform>-<arch>/ binary in pack (run npm run build first)');
Comment on lines +40 to +42
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Include ignored native binaries in npm packs

Because packages/codra-npm-cli/.gitignore excludes bin/native/, the binary that prepack builds is still omitted from the tarball; I verified npm’s packing behavior by creating a dummy bin/native/.../codra and running npm pack --dry-run --ignore-scripts, whose tarball contents listed only README.md, bin/codra.js, and package.json. As a result this new check always reports no bin/native/... after a successful build, and an actual npm publish would ship a wrapper that cannot run unless the ignore/packaging rules are changed.

Useful? React with 👍 / 👎.

}

if (errors.length > 0) {
console.error('[pack-dry-run] failed:');
for (const err of errors) {
console.error(` - ${err}`);
}
process.exit(1);
}

console.log('[pack-dry-run] ok');
console.log(`[pack-dry-run] native binaries: ${nativeBins.join(', ')}`);
process.stdout.write(output);
}

main();
Loading