bharatcode-cli 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -0
- package/bin/bharatcode.js +48 -0
- package/install.js +250 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# bharatcode
|
|
2
|
+
|
|
3
|
+
> **OpenCode for India** — a Go-native, MIT-licensed, open-weight-first CLI coding agent. Your code stays in India.
|
|
4
|
+
|
|
5
|
+
This is the npm distribution of [BharatCode](https://github.com/arbazkhan971/bharatcode). Installing it downloads the prebuilt native binary for your platform from GitHub Releases — there is no compilation step.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
Global install (adds `bharatcode` to your PATH):
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install -g bharatcode-cli
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Or run it once without installing:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx bharatcode-cli
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Then:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
bharatcode --help
|
|
25
|
+
bharatcode version
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## How it works
|
|
29
|
+
|
|
30
|
+
On install, a `postinstall` script (`install.js`) detects your operating system and CPU architecture, downloads the matching release archive from `https://github.com/arbazkhan971/bharatcode/releases`, and extracts the `bharatcode` binary. The `bharatcode` command is a thin Node shim that execs that binary, passing through all arguments and exit codes.
|
|
31
|
+
|
|
32
|
+
Supported platforms:
|
|
33
|
+
|
|
34
|
+
| OS | Architectures |
|
|
35
|
+
| ------- | ------------- |
|
|
36
|
+
| macOS | arm64, x64 |
|
|
37
|
+
| Linux | arm64, x64 |
|
|
38
|
+
| Windows | arm64, x64 |
|
|
39
|
+
|
|
40
|
+
## Environment variables
|
|
41
|
+
|
|
42
|
+
- `BHARATCODE_SKIP_DOWNLOAD=1` — skip the binary download during `npm install` (useful for air-gapped CI; you must place the binary in `bin/` yourself).
|
|
43
|
+
|
|
44
|
+
## Troubleshooting
|
|
45
|
+
|
|
46
|
+
If the postinstall download fails (e.g. no network during install), you can re-run it:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
node node_modules/bharatcode/install.js
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Or download the archive for your platform manually from the [Releases page](https://github.com/arbazkhan971/bharatcode/releases) and extract the `bharatcode` binary onto your PATH.
|
|
53
|
+
|
|
54
|
+
## License
|
|
55
|
+
|
|
56
|
+
MIT — see the [main repository](https://github.com/arbazkhan971/bharatcode).
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* Launcher shim for the BharatCode CLI.
|
|
6
|
+
*
|
|
7
|
+
* `npm install -g bharatcode` symlinks this file onto the user's PATH as
|
|
8
|
+
* `bharatcode`. It locates the platform binary that install.js downloaded into
|
|
9
|
+
* ./bharatcode (or ./bharatcode.exe on Windows), spawns it with the same argv
|
|
10
|
+
* and stdio, and exits with the binary's exit code.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const { spawnSync } = require('child_process');
|
|
16
|
+
|
|
17
|
+
// The real executable lives next to this shim, dropped here by install.js.
|
|
18
|
+
const binName = process.platform === 'win32' ? 'bharatcode.exe' : 'bharatcode';
|
|
19
|
+
const binPath = path.join(__dirname, binName);
|
|
20
|
+
|
|
21
|
+
if (!fs.existsSync(binPath)) {
|
|
22
|
+
console.error(
|
|
23
|
+
`[bharatcode] The native binary is missing (expected at ${binPath}).\n` +
|
|
24
|
+
'The postinstall download may have failed. Try reinstalling:\n' +
|
|
25
|
+
' npm install -g bharatcode\n' +
|
|
26
|
+
'or run the installer directly:\n' +
|
|
27
|
+
' node ' + path.join(__dirname, '..', 'install.js') + '\n'
|
|
28
|
+
);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Forward every argument after `node <shim>` and inherit stdio so the TUI,
|
|
33
|
+
// prompts, and pipes all work transparently.
|
|
34
|
+
const result = spawnSync(binPath, process.argv.slice(2), { stdio: 'inherit' });
|
|
35
|
+
|
|
36
|
+
// Propagate signal-based termination as a conventional 128+signal code.
|
|
37
|
+
if (result.signal) {
|
|
38
|
+
const signals = { SIGINT: 2, SIGTERM: 15, SIGHUP: 1, SIGQUIT: 3 };
|
|
39
|
+
process.exit(128 + (signals[result.signal] || 0));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// spawnSync sets .error (e.g. ENOENT/EACCES) if the binary couldn't run.
|
|
43
|
+
if (result.error) {
|
|
44
|
+
console.error(`[bharatcode] Failed to launch binary: ${result.error.message}`);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
process.exit(result.status === null ? 1 : result.status);
|
package/install.js
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* BharatCode npm postinstall script.
|
|
6
|
+
*
|
|
7
|
+
* This runs automatically after `npm install -g bharatcode` (or `npx bharatcode`).
|
|
8
|
+
* It downloads the prebuilt binary matching the user's OS/arch from the
|
|
9
|
+
* corresponding GitHub Release and extracts it into ./bin/ next to the launcher
|
|
10
|
+
* shim (bin/bharatcode.js).
|
|
11
|
+
*
|
|
12
|
+
* Design constraints:
|
|
13
|
+
* - No external dependencies. Only Node built-ins (https, fs, os, path,
|
|
14
|
+
* child_process) plus the system `tar` (unix) / PowerShell (windows) for
|
|
15
|
+
* archive extraction. This keeps the dependency tree at zero, which is the
|
|
16
|
+
* same approach esbuild/Biome-class tools use.
|
|
17
|
+
* - Fail loudly with an actionable message, and tell the user how to install
|
|
18
|
+
* manually if the automated download cannot work (e.g. air-gapped CI).
|
|
19
|
+
*
|
|
20
|
+
* Asset naming (from .goreleaser.yaml):
|
|
21
|
+
* bharatcode_{title Os}_{x86_64|arm64}.{tar.gz|zip}
|
|
22
|
+
* e.g. bharatcode_Darwin_arm64.tar.gz, bharatcode_Windows_x86_64.zip
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
const fs = require('fs');
|
|
26
|
+
const os = require('os');
|
|
27
|
+
const path = require('path');
|
|
28
|
+
const https = require('https');
|
|
29
|
+
const { execFileSync } = require('child_process');
|
|
30
|
+
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Configuration
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
const REPO = 'arbazkhan971/bharatcode';
|
|
36
|
+
const pkg = require('./package.json');
|
|
37
|
+
|
|
38
|
+
// The release tag is derived from the package version. GoReleaser tags releases
|
|
39
|
+
// as `v<version>` (e.g. v0.1.0), so the published npm version MUST match a real
|
|
40
|
+
// GitHub release tag for the download to succeed.
|
|
41
|
+
const VERSION = pkg.version;
|
|
42
|
+
const TAG = 'v' + VERSION;
|
|
43
|
+
|
|
44
|
+
const BIN_DIR = path.join(__dirname, 'bin');
|
|
45
|
+
// On Windows the real executable carries a .exe suffix; elsewhere it is bare.
|
|
46
|
+
const BIN_NAME = process.platform === 'win32' ? 'bharatcode.exe' : 'bharatcode';
|
|
47
|
+
const BIN_PATH = path.join(BIN_DIR, BIN_NAME);
|
|
48
|
+
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
// Platform -> GitHub asset mapping
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
// Maps Node's process.platform to the title-cased GOOS string GoReleaser uses.
|
|
54
|
+
const PLATFORM_TO_OS = {
|
|
55
|
+
darwin: 'Darwin',
|
|
56
|
+
linux: 'Linux',
|
|
57
|
+
win32: 'Windows',
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Maps Node's process.arch to GoReleaser's arch token. GoReleaser rewrites
|
|
61
|
+
// amd64 -> x86_64 and leaves arm64 as-is.
|
|
62
|
+
const ARCH_TO_TOKEN = {
|
|
63
|
+
x64: 'x86_64',
|
|
64
|
+
arm64: 'arm64',
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Build the GitHub asset filename for the current platform.
|
|
69
|
+
* Returns { asset, isZip } or throws if the platform is unsupported.
|
|
70
|
+
*/
|
|
71
|
+
function resolveAsset() {
|
|
72
|
+
const osName = PLATFORM_TO_OS[process.platform];
|
|
73
|
+
const archToken = ARCH_TO_TOKEN[process.arch];
|
|
74
|
+
|
|
75
|
+
if (!osName || !archToken) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
`Unsupported platform: ${process.platform}/${process.arch}.\n` +
|
|
78
|
+
`BharatCode ships prebuilt binaries for: ` +
|
|
79
|
+
`darwin (x64, arm64), linux (x64, arm64), win32 (x64, arm64).\n` +
|
|
80
|
+
`If you need this platform, build from source: ` +
|
|
81
|
+
`https://github.com/${REPO}`
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Windows archives are .zip; everything else is .tar.gz (see .goreleaser.yaml).
|
|
86
|
+
const isZip = process.platform === 'win32';
|
|
87
|
+
const ext = isZip ? 'zip' : 'tar.gz';
|
|
88
|
+
const asset = `bharatcode_${osName}_${archToken}.${ext}`;
|
|
89
|
+
return { asset, isZip };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
// Download (follows redirects — GitHub release assets 302 to a CDN)
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Download a URL to a local file, following up to `maxRedirects` redirects.
|
|
98
|
+
* Resolves when the file is fully written. Rejects on HTTP errors.
|
|
99
|
+
*/
|
|
100
|
+
function download(url, dest, maxRedirects = 10) {
|
|
101
|
+
return new Promise((resolve, reject) => {
|
|
102
|
+
const request = https.get(
|
|
103
|
+
url,
|
|
104
|
+
{
|
|
105
|
+
headers: {
|
|
106
|
+
// Some networks/proxies reject requests without a User-Agent.
|
|
107
|
+
'User-Agent': `bharatcode-npm/${VERSION} (node ${process.version})`,
|
|
108
|
+
Accept: 'application/octet-stream',
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
(res) => {
|
|
112
|
+
const { statusCode, headers } = res;
|
|
113
|
+
|
|
114
|
+
// Follow redirects (GitHub serves assets from a redirected CDN URL).
|
|
115
|
+
if (statusCode >= 300 && statusCode < 400 && headers.location) {
|
|
116
|
+
res.resume(); // discard body so the socket can be reused
|
|
117
|
+
if (maxRedirects <= 0) {
|
|
118
|
+
reject(new Error(`Too many redirects while downloading ${url}`));
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const next = new URL(headers.location, url).toString();
|
|
122
|
+
resolve(download(next, dest, maxRedirects - 1));
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (statusCode !== 200) {
|
|
127
|
+
res.resume();
|
|
128
|
+
reject(
|
|
129
|
+
new Error(
|
|
130
|
+
`Download failed: HTTP ${statusCode} for ${url}\n` +
|
|
131
|
+
`Make sure release ${TAG} exists and publishes that asset:\n` +
|
|
132
|
+
` https://github.com/${REPO}/releases/tag/${TAG}`
|
|
133
|
+
)
|
|
134
|
+
);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const file = fs.createWriteStream(dest);
|
|
139
|
+
res.pipe(file);
|
|
140
|
+
file.on('finish', () => file.close(() => resolve()));
|
|
141
|
+
file.on('error', (err) => {
|
|
142
|
+
fs.rm(dest, { force: true }, () => reject(err));
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
request.on('error', reject);
|
|
148
|
+
// Guard against a hung connection.
|
|
149
|
+
request.setTimeout(120000, () => {
|
|
150
|
+
request.destroy(new Error(`Timed out downloading ${url}`));
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
156
|
+
// Extraction (shells out to system tar / PowerShell — no JS tar dependency)
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Extract the bharatcode binary from `archivePath` into BIN_DIR.
|
|
161
|
+
* Uses `tar` on unix and PowerShell's Expand-Archive on Windows.
|
|
162
|
+
*/
|
|
163
|
+
function extract(archivePath, isZip) {
|
|
164
|
+
if (isZip) {
|
|
165
|
+
// Expand-Archive unpacks the whole zip into BIN_DIR; the binary lands as
|
|
166
|
+
// bharatcode.exe at the archive root (the archive contains no nested dir).
|
|
167
|
+
execFileSync(
|
|
168
|
+
'powershell',
|
|
169
|
+
[
|
|
170
|
+
'-NoProfile',
|
|
171
|
+
'-NonInteractive',
|
|
172
|
+
'-Command',
|
|
173
|
+
// -Force overwrites a stale copy from a previous install.
|
|
174
|
+
`Expand-Archive -LiteralPath '${archivePath}' -DestinationPath '${BIN_DIR}' -Force`,
|
|
175
|
+
],
|
|
176
|
+
{ stdio: 'inherit' }
|
|
177
|
+
);
|
|
178
|
+
} else {
|
|
179
|
+
// GNU/BSD tar both accept -xzf; extract directly into BIN_DIR.
|
|
180
|
+
execFileSync('tar', ['-xzf', archivePath, '-C', BIN_DIR], {
|
|
181
|
+
stdio: 'inherit',
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// ---------------------------------------------------------------------------
|
|
187
|
+
// Main
|
|
188
|
+
// ---------------------------------------------------------------------------
|
|
189
|
+
|
|
190
|
+
async function main() {
|
|
191
|
+
// Allow CI/offline installs to skip the network step entirely.
|
|
192
|
+
if (process.env.BHARATCODE_SKIP_DOWNLOAD === '1') {
|
|
193
|
+
console.log('[bharatcode] BHARATCODE_SKIP_DOWNLOAD=1 set; skipping binary download.');
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const { asset, isZip } = resolveAsset();
|
|
198
|
+
const url = `https://github.com/${REPO}/releases/download/${TAG}/${asset}`;
|
|
199
|
+
|
|
200
|
+
fs.mkdirSync(BIN_DIR, { recursive: true });
|
|
201
|
+
|
|
202
|
+
// If a usable binary is already present (e.g. reinstall), skip the download.
|
|
203
|
+
if (fs.existsSync(BIN_PATH)) {
|
|
204
|
+
console.log(`[bharatcode] Binary already present at ${BIN_PATH}; skipping download.`);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const tmpArchive = path.join(
|
|
209
|
+
os.tmpdir(),
|
|
210
|
+
`bharatcode-${VERSION}-${process.pid}-${asset}`
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
console.log(`[bharatcode] Downloading ${asset} (${TAG}) for ${process.platform}/${process.arch}...`);
|
|
214
|
+
|
|
215
|
+
try {
|
|
216
|
+
await download(url, tmpArchive);
|
|
217
|
+
console.log('[bharatcode] Extracting binary...');
|
|
218
|
+
extract(tmpArchive, isZip);
|
|
219
|
+
|
|
220
|
+
if (!fs.existsSync(BIN_PATH)) {
|
|
221
|
+
throw new Error(
|
|
222
|
+
`Extraction completed but ${BIN_NAME} was not found in ${BIN_DIR}.\n` +
|
|
223
|
+
`The release archive layout may have changed.`
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Ensure the binary is executable on unix (tar usually preserves the bit,
|
|
228
|
+
// but make it explicit so the shim can spawn it).
|
|
229
|
+
if (process.platform !== 'win32') {
|
|
230
|
+
fs.chmodSync(BIN_PATH, 0o755);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
console.log(`[bharatcode] Installed ${BIN_NAME} -> ${BIN_PATH}`);
|
|
234
|
+
} catch (err) {
|
|
235
|
+
console.error('\n[bharatcode] Installation failed.');
|
|
236
|
+
console.error(err.message || err);
|
|
237
|
+
console.error(
|
|
238
|
+
'\nYou can install manually instead:\n' +
|
|
239
|
+
` 1. Download the right archive from https://github.com/${REPO}/releases/tag/${TAG}\n` +
|
|
240
|
+
` 2. Extract the 'bharatcode' binary onto your PATH.\n` +
|
|
241
|
+
'Or build from source with Go: ' +
|
|
242
|
+
`https://github.com/${REPO}\n`
|
|
243
|
+
);
|
|
244
|
+
process.exit(1);
|
|
245
|
+
} finally {
|
|
246
|
+
fs.rm(tmpArchive, { force: true }, () => {});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "bharatcode-cli",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "BharatCode \u2014 an open, sovereign terminal coding agent. OpenCode for India. This npm package downloads the correct prebuilt binary for your platform from GitHub Releases.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"bharatcode",
|
|
7
|
+
"cli",
|
|
8
|
+
"coding-agent",
|
|
9
|
+
"ai",
|
|
10
|
+
"terminal",
|
|
11
|
+
"tui",
|
|
12
|
+
"llm"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://github.com/arbazkhan971/bharatcode#readme",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/arbazkhan971/bharatcode/issues"
|
|
17
|
+
},
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"author": "Arbaz",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/arbazkhan971/bharatcode.git",
|
|
23
|
+
"directory": "npm"
|
|
24
|
+
},
|
|
25
|
+
"bin": {
|
|
26
|
+
"bharatcode": "bin/bharatcode.js"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"postinstall": "node install.js"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"bin/bharatcode.js",
|
|
33
|
+
"install.js",
|
|
34
|
+
"README.md"
|
|
35
|
+
],
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=18"
|
|
38
|
+
},
|
|
39
|
+
"os": [
|
|
40
|
+
"darwin",
|
|
41
|
+
"linux",
|
|
42
|
+
"win32"
|
|
43
|
+
],
|
|
44
|
+
"cpu": [
|
|
45
|
+
"x64",
|
|
46
|
+
"arm64"
|
|
47
|
+
]
|
|
48
|
+
}
|