@lunaroute/cli 0.2.5 → 0.2.6

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 CHANGED
@@ -20,7 +20,7 @@ lunaroute setup pi # or: opencode | claude-code | copilot-cli | generic
20
20
 
21
21
  One command from a fresh machine: `setup` asks before touching anything — for `pi` it first offers to install the LunaRoute Pi extension (recommended — models then auto-sync, and you sign in with `/login lunaroute` inside pi), then offers to start pi for you. `opencode` works the same way with its extension (`/connect` to sign in). Decline an extension — or pick a harness whose config needs a key — and `setup` offers to run `lunaroute login` right there (it opens your browser) before writing. The fallback config finishes with an `export LUNAROUTE_API_KEY=…` line — run it in your shell, then start your agent and it routes through LunaRoute.
22
22
 
23
- Already have a key from the dashboard? `lunaroute setup pi --key lr_… --yes` is the whole onboarding: it checks the key against the catalog, installs the Pi extension, and stores the key in `~/.pi/agent/auth.json`, so pi starts signed in with models syncing from `/v1/models`. No models.json edit and no shell export. A stale `providers.lunaroute` block from an older CLI is removed in the same run (backup kept).
23
+ Already have a key from the dashboard? `lunaroute setup pi --key lr_… --yes` is the whole onboarding: it checks the key against the catalog, installs the Pi extension, and stores the key in `~/.pi/agent/auth.json`, so pi starts signed in with models syncing from `/v1/models`. No models.json edit and no shell export. A stale `providers.lunaroute` block from an older CLI is removed in the same run (backup kept). `lunaroute setup opencode --key lr_… --yes` works the same way: it installs the OpenCode extension and stores the key in `~/.local/share/opencode/auth.json`, so opencode starts signed in — no `/connect` needed.
24
24
 
25
25
  Prefer a script? `setup pi --extension` / `--models` pick a flow, `--yes` accepts all prompts, and `--print` previews without writing.
26
26
 
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  import { Command, InvalidArgumentError, Option } from "commander";
5
5
 
6
6
  // package.json
7
- var version = "0.2.5";
7
+ var version = "0.2.6";
8
8
 
9
9
  // src/login.ts
10
10
  import { createServer } from "http";
@@ -591,6 +591,10 @@ function configHome() {
591
591
  function opencodeConfigPath() {
592
592
  return join2(configHome(), "opencode", "opencode.json");
593
593
  }
594
+ function opencodeAuthPath() {
595
+ const dataHome = process.env.XDG_DATA_HOME || join2(homedir2(), ".local", "share");
596
+ return join2(dataHome, "opencode", "auth.json");
597
+ }
594
598
  function openclawConfigPath() {
595
599
  return join2(homedir2(), ".openclaw", "openclaw.json");
596
600
  }
@@ -708,6 +712,25 @@ function providerPlan(ctx) {
708
712
  ]
709
713
  };
710
714
  }
715
+ function buildKeyPlan(key) {
716
+ return {
717
+ fileWrites: [
718
+ {
719
+ kind: "json",
720
+ path: opencodeAuthPath(),
721
+ merge: (existing) => {
722
+ const obj = existing ?? {};
723
+ delete obj["lunaroute/"];
724
+ return { ...obj, lunaroute: { type: "api", key } };
725
+ }
726
+ }
727
+ ],
728
+ exports: [],
729
+ notes: [
730
+ "opencode: key stored in ~/.local/share/opencode/auth.json \u2014 start opencode (or restart it), then /models to pick a lunaroute/* model."
731
+ ]
732
+ };
733
+ }
711
734
 
712
735
  // src/setup/adapters/pi.ts
713
736
  import { readFileSync as readFileSync3 } from "fs";
@@ -811,7 +834,7 @@ function buildStaleProviderCleanupPlan() {
811
834
  };
812
835
  }
813
836
  var KEY_EXPIRES_MS = 10 * 365 * 24 * 60 * 60 * 1e3;
814
- function buildKeyPlan(key) {
837
+ function buildKeyPlan2(key) {
815
838
  return {
816
839
  fileWrites: [
817
840
  {
@@ -1008,7 +1031,7 @@ async function runSetup(harness, opts, deps = {
1008
1031
  return 1;
1009
1032
  }
1010
1033
  if (opts.key && (opts.extension || opts.models)) {
1011
- console.error("--key runs the full pi flow; drop --extension/--models.");
1034
+ console.error("--key runs the full pi or opencode flow; drop --extension/--models.");
1012
1035
  return 1;
1013
1036
  }
1014
1037
  const adapter = ADAPTERS[harness];
@@ -1089,7 +1112,7 @@ async function runSetup(harness, opts, deps = {
1089
1112
  };
1090
1113
  let plan;
1091
1114
  try {
1092
- plan = harness === "pi" && opts.key ? buildKeyPlan("<your-api-key>") : adapter(ctx);
1115
+ plan = harness === "pi" && opts.key ? buildKeyPlan2("<your-api-key>") : adapter(ctx);
1093
1116
  } catch (err) {
1094
1117
  console.error(err instanceof Error ? err.message : err);
1095
1118
  return 1;
@@ -1166,7 +1189,7 @@ async function runPiSetup(opts, stored, routingUrl, deps) {
1166
1189
  console.log("\nSkipped. Inside pi, run /login lunaroute to sign in.");
1167
1190
  return 0;
1168
1191
  }
1169
- const plan = combinePlans(buildKeyPlan(creds2.routing_key), stalePiProviderExists() ? buildStaleProviderCleanupPlan() : null);
1192
+ const plan = combinePlans(buildKeyPlan2(creds2.routing_key), stalePiProviderExists() ? buildStaleProviderCleanupPlan() : null);
1170
1193
  const wcode = await applyAndReport(plan, creds2.routing_key, true);
1171
1194
  if (wcode !== 0) return wcode;
1172
1195
  console.log("\nDone. Start pi \u2014 it is signed in. Pick a model with /model.");
@@ -1291,11 +1314,48 @@ async function runHermesConfigSets(spawn, routingUrl, key) {
1291
1314
  async function runOpencodeSetup(stored, settings, routingUrl, opts, deps) {
1292
1315
  try {
1293
1316
  if (opts.print) {
1317
+ const plan = combinePlans(
1318
+ buildPlan(
1319
+ { routingUrl, orgId: settings.org_id, models: [], keyEnvVar: "LUNAROUTE_API_KEY" },
1320
+ { extension: true }
1321
+ ),
1322
+ opts.key ? buildKeyPlan("<your-api-key>") : null
1323
+ );
1324
+ return applyAndReport(plan, stored?.routing_key ?? "", false);
1325
+ }
1326
+ if (opts.key) {
1327
+ const creds2 = await requireCreds(opts, deps, stored);
1328
+ if (!creds2) return 1;
1329
+ const install = await deps.confirm("Install the LunaRoute OpenCode extension?", {
1330
+ yes: opts.yes
1331
+ });
1332
+ if (!install) {
1333
+ return applyOpencodeProvider(
1334
+ creds2,
1335
+ routingUrl,
1336
+ await deps.confirm("Merge LunaRoute provider into opencode.json (backup kept, other providers preserved)?", {
1337
+ yes: opts.yes
1338
+ })
1339
+ );
1340
+ }
1294
1341
  const plan = buildPlan(
1295
1342
  { routingUrl, orgId: settings.org_id, models: [], keyEnvVar: "LUNAROUTE_API_KEY" },
1296
1343
  { extension: true }
1297
1344
  );
1298
- return applyAndReport(plan, stored?.routing_key ?? "", false);
1345
+ const code = await applyAndReport(plan, creds2.routing_key, true);
1346
+ if (code !== 0) return code;
1347
+ const store = await deps.confirm(
1348
+ "Store the key in ~/.local/share/opencode/auth.json (replaces any existing LunaRoute login; other credentials preserved)?",
1349
+ { yes: opts.yes }
1350
+ );
1351
+ if (!store) {
1352
+ console.log("\nSkipped. Inside opencode, run /connect to sign in.");
1353
+ return 0;
1354
+ }
1355
+ const wcode = await applyAndReport(buildKeyPlan(creds2.routing_key), creds2.routing_key, true);
1356
+ if (wcode !== 0) return wcode;
1357
+ console.log("\nDone. Start opencode \u2014 it is signed in. Pick a model with /models.");
1358
+ return 0;
1299
1359
  }
1300
1360
  if (await deps.confirm(
1301
1361
  "Install the LunaRoute OpenCode extension (recommended \u2014 /connect login, models auto-sync)?",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunaroute/cli",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "LunaRoute CLI — configure coding harnesses and manage your LunaRoute account.",
5
5
  "repository": {
6
6
  "type": "git",