@getmegabrain/cli 0.1.2 → 0.1.4

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/LICENSE.md ADDED
@@ -0,0 +1,19 @@
1
+ Copyright 2025-present Kilo Code Inc.
2
+
3
+ Open Core Ventures Source Available License (OCVSAL) version 1.0
4
+
5
+ Using software and associated documentation files (the "Software") in production requires a valid commercial agreement from the copyright holder.
6
+
7
+ You are free to modify the Software, test it, and publish modifications to the Software. You agree that the copyright holder retains all right, title and interest in and to all modifications.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
12
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
13
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
14
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
15
+ SOFTWARE.
16
+
17
+ For all third party components incorporated into this Software, those
18
+ components are licensed under the original license provided by the owner of the
19
+ applicable component.
package/README.md CHANGED
@@ -32,9 +32,14 @@ e.g. `megabrain run "fix the failing test"`.
32
32
  provider pointed at the MegaBrain Gateway — the same config shape BrainClaw
33
33
  writes server-side for its own sandboxes
34
34
  (`services/kiloclaw/controller/src/opencode-config.ts`).
35
- - Every other command execs the real `opencode` binary (installed as a
36
- dependency of this package), so it behaves exactly like OpenCode — this
37
- package only handles auth and gateway wiring.
35
+ - Every other command execs the real `opencode` binary. That binary ships
36
+ bundled inside this package (the `opencode-ai` dependency), and the CLI runs
37
+ it by its absolute path in `node_modules` — it is never expected on your
38
+ `PATH`, and you never install `opencode` yourself. If a restrictive install
39
+ (e.g. `--ignore-scripts`, pnpm, or an allow-scripts policy) skipped
40
+ `opencode-ai`'s postinstall, the CLI fetches the native binary on first
41
+ launch. So it behaves exactly like OpenCode — this package only handles auth
42
+ and gateway wiring.
38
43
 
39
44
  Override the target deployment for local development with
40
45
  `MEGABRAIN_APP_URL` (defaults to `https://getmegabrain.com`).
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ import { login } from './device-auth.js';
4
4
  import { readCredentials, writeCredentials, clearCredentials } from './credentials.js';
5
5
  import { writeOpenCodeConfig } from './opencode-config.js';
6
6
  import { fetchGatewayModelIds } from './models.js';
7
+ import { ensureOpencodeBinary } from './opencode.js';
7
8
  async function signIn() {
8
9
  console.log('Signing in to MegaBrain…');
9
10
  const { token, userId, userEmail } = await login();
@@ -40,10 +41,10 @@ function runWhoami() {
40
41
  }
41
42
  function runOpenCode(args) {
42
43
  return new Promise((resolve, reject) => {
43
- const child = spawn('opencode', args, { stdio: 'inherit' });
44
+ const child = spawn(ensureOpencodeBinary(), args, { stdio: 'inherit' });
44
45
  child.on('error', err => {
45
46
  if (err.code === 'ENOENT') {
46
- reject(new Error('Could not find `opencode` on your PATH. Try reinstalling: npm install -g @getmegabrain/cli'));
47
+ reject(new Error('The bundled `opencode` binary is missing. Try reinstalling: npm install -g @getmegabrain/cli'));
47
48
  }
48
49
  else {
49
50
  reject(err);
@@ -74,6 +74,11 @@ export function writeOpenCodeConfig(token, modelIds = []) {
74
74
  // LSP diagnostics make the agent's edits far more reliable, but OpenCode
75
75
  // ships with LSP off. Default it on; a user's explicit choice survives.
76
76
  lsp: existing.lsp ?? true,
77
+ // OpenCode auto-connects a direct OpenRouter provider when it finds
78
+ // OPENROUTER_API_KEY or stored credentials, routing traffic (and billing)
79
+ // around the MegaBrain Gateway. Hide it by default — BYOK goes through
80
+ // the gateway. A user who wants it back can set disabled_providers: [].
81
+ disabled_providers: existing.disabled_providers ?? ['openrouter'],
77
82
  };
78
83
  fs.mkdirSync(OPENCODE_CONFIG_DIR, { recursive: true });
79
84
  fs.writeFileSync(OPENCODE_CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 0o600 });
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Resolves the OpenCode binary that ships *inside* this package.
3
+ *
4
+ * `opencode` is a dependency (`opencode-ai`), not something the user installs
5
+ * or needs to know about. We must NOT invoke it by bare name off `PATH`:
6
+ * npm only links the top-level package's bin (`megabrain`) into the global bin
7
+ * directory on `npm install -g`, so a nested dependency's `opencode` bin never
8
+ * lands on `PATH`. Instead we resolve the bundled binary's absolute path from
9
+ * our own `node_modules` and exec that.
10
+ *
11
+ * `opencode-ai` materializes the platform-specific native binary in its
12
+ * `postinstall` (it copies the right `opencode-<platform>-<arch>` build into
13
+ * `bin/opencode.exe`). If install scripts were skipped (pnpm's default, npm
14
+ * `--ignore-scripts`, or an allow-scripts policy), that file is still the stub
15
+ * shell script shipped in the tarball. Detect that case and run the postinstall
16
+ * ourselves so the binary is fetched on first launch.
17
+ */
18
+ import { spawnSync } from 'node:child_process';
19
+ import { createRequire } from 'node:module';
20
+ import fs from 'node:fs';
21
+ import path from 'node:path';
22
+ const require = createRequire(import.meta.url);
23
+ /** Marker printed by the placeholder bin when opencode-ai's postinstall never ran. */
24
+ const STUB_MARKER = 'postinstall script was not run';
25
+ function opencodePackageDir() {
26
+ return path.dirname(require.resolve('opencode-ai/package.json'));
27
+ }
28
+ /** Absolute path to the bundled OpenCode binary. Pure: no side effects. */
29
+ export function opencodeBinaryPath() {
30
+ return path.join(opencodePackageDir(), 'bin', 'opencode.exe');
31
+ }
32
+ /** True when the binary is missing or is still the un-materialized stub. */
33
+ function needsPostinstall(binPath) {
34
+ let fd;
35
+ try {
36
+ fd = fs.openSync(binPath, 'r');
37
+ }
38
+ catch {
39
+ return true;
40
+ }
41
+ try {
42
+ const buf = Buffer.alloc(256);
43
+ const bytesRead = fs.readSync(fd, buf, 0, buf.length, 0);
44
+ return buf.toString('utf8', 0, bytesRead).includes(STUB_MARKER);
45
+ }
46
+ finally {
47
+ fs.closeSync(fd);
48
+ }
49
+ }
50
+ /**
51
+ * Returns the bundled OpenCode binary path, running opencode-ai's postinstall
52
+ * first if the native binary hasn't been materialized yet.
53
+ */
54
+ export function ensureOpencodeBinary() {
55
+ const binPath = opencodeBinaryPath();
56
+ if (needsPostinstall(binPath)) {
57
+ const postinstall = path.join(opencodePackageDir(), 'postinstall.mjs');
58
+ console.log('Fetching OpenCode binary…');
59
+ spawnSync(process.execPath, [postinstall], {
60
+ cwd: opencodePackageDir(),
61
+ stdio: 'inherit',
62
+ });
63
+ }
64
+ return binPath;
65
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getmegabrain/cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "MegaBrain CLI — sign in once, then code from your terminal via OpenCode wired to the MegaBrain Gateway.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -16,6 +16,16 @@
16
16
  "engines": {
17
17
  "node": ">=18"
18
18
  },
19
+ "dependencies": {
20
+ "opencode-ai": "^1.17.11"
21
+ },
22
+ "devDependencies": {
23
+ "@types/node": "24.12.4",
24
+ "@typescript/native-preview": "7.0.0-dev.20260514.1",
25
+ "tsx": "4.21.0",
26
+ "typescript": "5.9.3",
27
+ "vitest": "4.1.6"
28
+ },
19
29
  "scripts": {
20
30
  "build": "tsc -p tsconfig.build.json",
21
31
  "postbuild": "chmod +x dist/index.js",
@@ -24,15 +34,5 @@
24
34
  "test": "vitest run --passWithNoTests",
25
35
  "test:watch": "vitest",
26
36
  "lint": "pnpm -w exec oxlint --config .oxlintrc.json packages/megabrain-cli/src"
27
- },
28
- "dependencies": {
29
- "opencode-ai": "^1.17.11"
30
- },
31
- "devDependencies": {
32
- "@types/node": "catalog:",
33
- "@typescript/native-preview": "catalog:",
34
- "tsx": "catalog:",
35
- "typescript": "catalog:",
36
- "vitest": "catalog:"
37
37
  }
38
- }
38
+ }