@getmegabrain/cli 0.1.0 → 0.1.2

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/dist/constants.js CHANGED
@@ -5,5 +5,5 @@
5
5
  export const APP_BASE_URL = (process.env.MEGABRAIN_APP_URL ?? 'https://getmegabrain.com').replace(/\/+$/, '');
6
6
  /** OpenAI-compatible gateway root; OpenCode's provider appends `/chat/completions`. */
7
7
  export const GATEWAY_BASE_URL = `${APP_BASE_URL}/api/gateway/`;
8
- /** Gateway model id used when the user hasn't picked one. */
9
- export const DEFAULT_MODEL_ID = 'kilo-auto/balanced';
8
+ /** Gateway model id used when the user hasn't picked one (MegaBrain auto-router). */
9
+ export const DEFAULT_MODEL_ID = 'mb-auto/balanced';
package/dist/index.js CHANGED
@@ -3,20 +3,27 @@ import { spawn } from 'node:child_process';
3
3
  import { login } from './device-auth.js';
4
4
  import { readCredentials, writeCredentials, clearCredentials } from './credentials.js';
5
5
  import { writeOpenCodeConfig } from './opencode-config.js';
6
- async function ensureSignedIn() {
7
- if (readCredentials())
8
- return;
6
+ import { fetchGatewayModelIds } from './models.js';
7
+ async function signIn() {
9
8
  console.log('Signing in to MegaBrain…');
10
9
  const { token, userId, userEmail } = await login();
11
10
  writeCredentials({ token, userId, userEmail });
12
- writeOpenCodeConfig(token);
11
+ writeOpenCodeConfig(token, await fetchGatewayModelIds());
12
+ return userEmail;
13
+ }
14
+ async function ensureSignedIn() {
15
+ const credentials = readCredentials();
16
+ if (credentials) {
17
+ // Refresh OpenCode's config on every launch so CLI upgrades (new default
18
+ // model, catalog changes) take effect without an explicit re-login.
19
+ writeOpenCodeConfig(credentials.token, await fetchGatewayModelIds());
20
+ return;
21
+ }
22
+ const userEmail = await signIn();
13
23
  console.log(`\nSigned in as ${userEmail}.\n`);
14
24
  }
15
25
  async function runLogin() {
16
- console.log('Signing in to MegaBrain…');
17
- const { token, userId, userEmail } = await login();
18
- writeCredentials({ token, userId, userEmail });
19
- writeOpenCodeConfig(token);
26
+ const userEmail = await signIn();
20
27
  console.log(`\nSigned in as ${userEmail}. Run \`megabrain\` to start coding.\n`);
21
28
  }
22
29
  function runLogout() {
package/dist/models.js ADDED
@@ -0,0 +1,25 @@
1
+ import { APP_BASE_URL } from './constants.js';
2
+ /**
3
+ * Fetches the MegaBrain Gateway's public model catalog so OpenCode's model
4
+ * picker can list every model the gateway serves (including BYOK-eligible
5
+ * ones — BYOK routing is transparent gateway-side, the ids are the same).
6
+ *
7
+ * Best-effort: returns [] on any failure so login never blocks on this —
8
+ * the caller falls back to registering just the default auto-router model.
9
+ */
10
+ export async function fetchGatewayModelIds() {
11
+ try {
12
+ const res = await fetch(`${APP_BASE_URL}/api/gateway/models`);
13
+ if (!res.ok)
14
+ return [];
15
+ const body = (await res.json());
16
+ if (!Array.isArray(body.data))
17
+ return [];
18
+ return body.data
19
+ .map(model => model.id)
20
+ .filter((id) => typeof id === 'string' && id.length > 0);
21
+ }
22
+ catch {
23
+ return [];
24
+ }
25
+ }
@@ -7,27 +7,73 @@
7
7
  * same thing server-side for BrainClaw sandboxes) — same config shape, same
8
8
  * gateway, adapted to write to the local user's OpenCode config directory
9
9
  * instead of a pinned in-container path.
10
+ *
11
+ * The CLI rewrites this file on every launch (to pick up catalog and default
12
+ * changes), so it must MERGE into the existing config rather than replace it:
13
+ * only the keys the CLI owns (`provider.megabrain`, `model`) are overwritten,
14
+ * everything the user added themselves (lsp, theme, mcp, other providers…)
15
+ * is preserved.
10
16
  */
11
17
  import fs from 'node:fs';
12
18
  import { GATEWAY_BASE_URL, DEFAULT_MODEL_ID } from './constants.js';
13
19
  import { OPENCODE_CONFIG_DIR, OPENCODE_CONFIG_FILE } from './paths.js';
14
20
  const PROVIDER_ID = 'megabrain';
21
+ /** Legacy auto-router default written by CLI ≤0.1.0; migrated to mb-auto/*. */
22
+ const LEGACY_MODEL_PREFIX = `${PROVIDER_ID}/kilo-auto/`;
15
23
  /** OpenCode's `@ai-sdk/openai-compatible` provider appends `/chat/completions` to `baseURL`. */
16
24
  function toOpenCodeBaseUrl(gatewayBaseUrl) {
17
25
  return gatewayBaseUrl.replace(/\/+$/, '') + '/v1';
18
26
  }
19
- export function writeOpenCodeConfig(token, modelId = DEFAULT_MODEL_ID) {
27
+ function readExistingConfig() {
28
+ try {
29
+ const parsed = JSON.parse(fs.readFileSync(OPENCODE_CONFIG_FILE, 'utf8'));
30
+ if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {
31
+ return parsed;
32
+ }
33
+ }
34
+ catch {
35
+ // Missing or unparsable — start from scratch.
36
+ }
37
+ return {};
38
+ }
39
+ /**
40
+ * @param token Gateway token from `megabrain login`.
41
+ * @param modelIds Full catalog to register in OpenCode's model picker; the
42
+ * default auto-router model is always included and stays the default.
43
+ */
44
+ export function writeOpenCodeConfig(token, modelIds = []) {
45
+ const models = {
46
+ [DEFAULT_MODEL_ID]: { name: DEFAULT_MODEL_ID },
47
+ };
48
+ for (const id of modelIds) {
49
+ models[id] = { name: id };
50
+ }
51
+ const existing = readExistingConfig();
52
+ const existingProvider = existing.provider !== null && typeof existing.provider === 'object'
53
+ ? existing.provider
54
+ : {};
55
+ // Keep a user-chosen default model, but migrate the stale kilo-auto default
56
+ // that older CLI versions wrote.
57
+ const existingModel = typeof existing.model === 'string' ? existing.model : undefined;
58
+ const model = existingModel === undefined || existingModel.startsWith(LEGACY_MODEL_PREFIX)
59
+ ? `${PROVIDER_ID}/${DEFAULT_MODEL_ID}`
60
+ : existingModel;
20
61
  const config = {
62
+ ...existing,
21
63
  $schema: 'https://opencode.ai/config.json',
22
64
  provider: {
65
+ ...existingProvider,
23
66
  [PROVIDER_ID]: {
24
67
  npm: '@ai-sdk/openai-compatible',
25
68
  name: 'MegaBrain Gateway',
26
69
  options: { baseURL: toOpenCodeBaseUrl(GATEWAY_BASE_URL), apiKey: token },
27
- models: { [modelId]: { name: modelId } },
70
+ models,
28
71
  },
29
72
  },
30
- model: `${PROVIDER_ID}/${modelId}`,
73
+ model,
74
+ // LSP diagnostics make the agent's edits far more reliable, but OpenCode
75
+ // ships with LSP off. Default it on; a user's explicit choice survives.
76
+ lsp: existing.lsp ?? true,
31
77
  };
32
78
  fs.mkdirSync(OPENCODE_CONFIG_DIR, { recursive: true });
33
79
  fs.writeFileSync(OPENCODE_CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 0o600 });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getmegabrain/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
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",
@@ -10,6 +10,9 @@
10
10
  "files": [
11
11
  "dist"
12
12
  ],
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
13
16
  "engines": {
14
17
  "node": ">=18"
15
18
  },