lua-cli 3.17.1 → 3.17.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/index.js CHANGED
@@ -22224,6 +22224,23 @@ async function gitUserConfigured(cwd) {
22224
22224
  };
22225
22225
  }
22226
22226
  __name(gitUserConfigured, "gitUserConfigured");
22227
+ async function getRemoteOriginUrl(cwd) {
22228
+ try {
22229
+ const { stdout, code } = await runGit([
22230
+ "config",
22231
+ "--get",
22232
+ "remote.origin.url"
22233
+ ], {
22234
+ cwd
22235
+ });
22236
+ if (code !== 0) return null;
22237
+ const trimmed = stdout.trim();
22238
+ return trimmed.length > 0 ? trimmed : null;
22239
+ } catch {
22240
+ return null;
22241
+ }
22242
+ }
22243
+ __name(getRemoteOriginUrl, "getRemoteOriginUrl");
22227
22244
  async function getCommitSha(cwd) {
22228
22245
  try {
22229
22246
  const { stdout, code } = await runGit([
@@ -22305,39 +22322,17 @@ async function clearAuth(provider) {
22305
22322
  __name(clearAuth, "clearAuth");
22306
22323
 
22307
22324
  // src/utils/git-providers/github-provider.ts
22308
- import { createServer } from "http";
22309
- import { randomBytes as randomBytes2 } from "crypto";
22310
22325
  import { request } from "undici";
22311
- import open from "open";
22312
22326
 
22313
22327
  // src/config/git-providers.constants.ts
22314
22328
  var GITHUB_CLIENT_ID = "Ov23lipe1jgBlCsoi9OO";
22315
22329
  var GITHUB_OAUTH_BASE_URL = "https://github.com";
22316
22330
  var GITHUB_API_BASE_URL = "https://api.github.com";
22317
22331
  var GITHUB_OAUTH_SCOPE = "repo";
22318
- var LOOPBACK_PORT_MIN = 49152;
22319
- var LOOPBACK_PORT_MAX = 65535;
22320
- var LOOPBACK_PORT_ATTEMPTS = 3;
22321
- var LOOPBACK_TIMEOUT_MS = 5 * 60 * 1e3;
22322
22332
  var DEVICE_FLOW_DEFAULT_INTERVAL_MS = 5e3;
22323
22333
  var DEVICE_FLOW_SLOW_DOWN_INCREMENT_MS = 5e3;
22324
22334
  var PUSH_TIMEOUT_MS = 2 * 60 * 1e3;
22325
22335
 
22326
- // src/utils/pkce.ts
22327
- import { createHash as createHash2, randomBytes } from "crypto";
22328
- function generateCodeVerifier() {
22329
- return base64url(randomBytes(64));
22330
- }
22331
- __name(generateCodeVerifier, "generateCodeVerifier");
22332
- function computeCodeChallenge(verifier) {
22333
- return base64url(createHash2("sha256").update(verifier).digest());
22334
- }
22335
- __name(computeCodeChallenge, "computeCodeChallenge");
22336
- function base64url(buf) {
22337
- return buf.toString("base64").replace(/=+$/, "").replace(/\+/g, "-").replace(/\//g, "_");
22338
- }
22339
- __name(base64url, "base64url");
22340
-
22341
22336
  // src/interfaces/git-providers.ts
22342
22337
  var GitPushError = class extends Error {
22343
22338
  static {
@@ -22362,18 +22357,26 @@ function scrubToken(s, token) {
22362
22357
  __name(scrubToken, "scrubToken");
22363
22358
 
22364
22359
  // src/utils/git-providers/github-provider.ts
22365
- var SUCCESS_HTML = `<!doctype html><meta charset="utf-8"><title>Lua CLI</title>
22366
- <body style="font-family: system-ui; padding: 4rem; text-align: center;">
22367
- <h1>&#x2713; Connected</h1>
22368
- <p>You can close this tab and return to the terminal.</p>
22369
- </body>`;
22370
22360
  var GitHubProvider = class {
22371
22361
  static {
22372
22362
  __name(this, "GitHubProvider");
22373
22363
  }
22374
22364
  name = "github";
22375
- async login(opts) {
22376
- const token = opts.device ? await this.deviceFlow() : await this.loopbackFlow();
22365
+ /**
22366
+ * GitHub is authenticated via the OAuth **device flow** only.
22367
+ *
22368
+ * The browser/loopback authorization-code flow is intentionally NOT used:
22369
+ * GitHub requires a `client_secret` to exchange the code (PKCE does not
22370
+ * replace it — the secretless exchange returns `incorrect_client_credentials`),
22371
+ * and a CLI published to npm cannot safely embed a secret. The device flow
22372
+ * needs no secret, which is why it is the only viable flow for a public
22373
+ * client (the same reason GitHub's own `gh` CLI defaults to it).
22374
+ *
22375
+ * `opts.device` is accepted for backwards compatibility but is now a no-op:
22376
+ * the device flow is always used.
22377
+ */
22378
+ async login(_opts) {
22379
+ const token = await this.deviceFlow();
22377
22380
  const username = await this.fetchUsername(token);
22378
22381
  await saveAuth(this.name, {
22379
22382
  token,
@@ -22416,126 +22419,6 @@ var GitHubProvider = class {
22416
22419
  const status = matchPushStatus(scrubbed);
22417
22420
  throw new GitPushError(status === 401 ? "GitHub authentication failed (token revoked or insufficient scope)." : status === 403 ? "GitHub rejected the push (403 \u2014 possible SSO enforcement or missing scope)." : "git push failed.", status, scrubbed);
22418
22421
  }
22419
- async loopbackFlow() {
22420
- const verifier = generateCodeVerifier();
22421
- const challenge = computeCodeChallenge(verifier);
22422
- const state = randomBytes2(16).toString("hex");
22423
- const { code, redirectUri } = await this.captureLoopbackCode({
22424
- state,
22425
- challenge
22426
- });
22427
- return this.exchangeCodeForToken({
22428
- code,
22429
- verifier,
22430
- redirectUri
22431
- });
22432
- }
22433
- async captureLoopbackCode(args2) {
22434
- let lastErr;
22435
- for (let i = 0; i < LOOPBACK_PORT_ATTEMPTS; i++) {
22436
- const port = randomPort();
22437
- try {
22438
- return await this.runLoopbackServer(port, args2.state, args2.challenge);
22439
- } catch (err) {
22440
- lastErr = err;
22441
- if (!isPortInUse(err)) throw err;
22442
- }
22443
- }
22444
- throw new Error(`Could not bind a loopback port after ${LOOPBACK_PORT_ATTEMPTS} attempts. Try \`lua git auth github --device\` instead.${lastErr ? ` (${lastErr instanceof Error ? lastErr.message : String(lastErr)})` : ""}`);
22445
- }
22446
- runLoopbackServer(port, state, challenge) {
22447
- return new Promise((resolveOuter, rejectOuter) => {
22448
- let settled = false;
22449
- const settle = /* @__PURE__ */ __name((fn) => {
22450
- if (settled) return;
22451
- settled = true;
22452
- fn();
22453
- }, "settle");
22454
- const server = createServer((req, res) => {
22455
- const url = new URL(req.url ?? "/", `http://127.0.0.1:${port}`);
22456
- if (url.pathname !== "/callback") {
22457
- res.writeHead(404).end();
22458
- return;
22459
- }
22460
- const code = url.searchParams.get("code");
22461
- const gotState = url.searchParams.get("state");
22462
- if (!code || gotState !== state) {
22463
- res.writeHead(400, {
22464
- "content-type": "text/plain"
22465
- }).end("State mismatch.");
22466
- server.close();
22467
- settle(() => {
22468
- clearTimeout(timeout);
22469
- rejectOuter(new Error("OAuth callback state mismatch (possible CSRF). Re-run the command."));
22470
- });
22471
- return;
22472
- }
22473
- res.writeHead(200, {
22474
- "content-type": "text/html"
22475
- }).end(SUCCESS_HTML);
22476
- server.close();
22477
- settle(() => {
22478
- clearTimeout(timeout);
22479
- resolveOuter({
22480
- code,
22481
- redirectUri
22482
- });
22483
- });
22484
- });
22485
- const timeout = setTimeout(() => {
22486
- server.close();
22487
- settle(() => rejectOuter(new Error("OAuth flow timed out (5 min). Re-run `lua git auth github`.")));
22488
- }, LOOPBACK_TIMEOUT_MS);
22489
- timeout.unref();
22490
- server.on("error", (err) => {
22491
- server.close();
22492
- settle(() => {
22493
- clearTimeout(timeout);
22494
- rejectOuter(err);
22495
- });
22496
- });
22497
- let redirectUri = "";
22498
- server.listen(port, "127.0.0.1", () => {
22499
- const actualPort = server.address().port;
22500
- redirectUri = `http://127.0.0.1:${actualPort}/callback`;
22501
- const authUrl = new URL(`${GITHUB_OAUTH_BASE_URL}/login/oauth/authorize`);
22502
- authUrl.searchParams.set("client_id", GITHUB_CLIENT_ID);
22503
- authUrl.searchParams.set("redirect_uri", redirectUri);
22504
- authUrl.searchParams.set("scope", GITHUB_OAUTH_SCOPE);
22505
- authUrl.searchParams.set("code_challenge", challenge);
22506
- authUrl.searchParams.set("code_challenge_method", "S256");
22507
- authUrl.searchParams.set("state", state);
22508
- open(authUrl.toString()).catch(() => {
22509
- server.close();
22510
- settle(() => {
22511
- clearTimeout(timeout);
22512
- rejectOuter(new Error("Couldn't open a browser \u2014 try `lua git auth github --device` for the device flow."));
22513
- });
22514
- });
22515
- });
22516
- });
22517
- }
22518
- async exchangeCodeForToken(args2) {
22519
- const res = await request(`${GITHUB_OAUTH_BASE_URL}/login/oauth/access_token`, {
22520
- method: "POST",
22521
- headers: {
22522
- accept: "application/json",
22523
- "content-type": "application/json"
22524
- },
22525
- body: JSON.stringify({
22526
- client_id: GITHUB_CLIENT_ID,
22527
- code: args2.code,
22528
- code_verifier: args2.verifier,
22529
- redirect_uri: args2.redirectUri,
22530
- grant_type: "authorization_code"
22531
- })
22532
- });
22533
- const body = await res.body.json();
22534
- if (!body.access_token) {
22535
- throw new Error(`GitHub rejected the token exchange: ${body.error ?? "unknown error"}`);
22536
- }
22537
- return body.access_token;
22538
- }
22539
22422
  async fetchUsername(token) {
22540
22423
  const res = await request(`${GITHUB_API_BASE_URL}/user`, {
22541
22424
  method: "GET",
@@ -22598,15 +22481,6 @@ var GitHubProvider = class {
22598
22481
  throw new Error("Device flow timed out. Re-run `lua git auth github --device`.");
22599
22482
  }
22600
22483
  };
22601
- function randomPort() {
22602
- const span = LOOPBACK_PORT_MAX - LOOPBACK_PORT_MIN + 1;
22603
- return LOOPBACK_PORT_MIN + Math.floor(Math.random() * span);
22604
- }
22605
- __name(randomPort, "randomPort");
22606
- function isPortInUse(err) {
22607
- return !!err && typeof err === "object" && "code" in err && err.code === "EADDRINUSE";
22608
- }
22609
- __name(isPortInUse, "isPortInUse");
22610
22484
  function sleep(ms) {
22611
22485
  return new Promise((r) => setTimeout(r, ms));
22612
22486
  }
@@ -22665,7 +22539,7 @@ async function tryGitAutoPush(ctx) {
22665
22539
  warnOnce("missing-github-token", "git.autoPush is enabled but no GitHub auth \u2014 run `lua git auth github`.");
22666
22540
  return;
22667
22541
  }
22668
- const remote = await readRemoteOriginUrl(ctx.cwd);
22542
+ const remote = await getRemoteOriginUrl(ctx.cwd);
22669
22543
  if (!remote) {
22670
22544
  warnOnce("missing-github-remote", "git.autoPush is enabled but no `remote.origin.url` is set. Skipping push.");
22671
22545
  return;
@@ -22715,19 +22589,6 @@ async function tryGitAutoPush(ctx) {
22715
22589
  }
22716
22590
  }
22717
22591
  __name(tryGitAutoPush, "tryGitAutoPush");
22718
- async function readRemoteOriginUrl(cwd) {
22719
- const res = await runGit([
22720
- "config",
22721
- "--get",
22722
- "remote.origin.url"
22723
- ], {
22724
- cwd
22725
- });
22726
- if (res.code !== 0) return null;
22727
- const trimmed = res.stdout.trim();
22728
- return trimmed.length > 0 ? trimmed : null;
22729
- }
22730
- __name(readRemoteOriginUrl, "readRemoteOriginUrl");
22731
22592
  async function readCurrentBranch(cwd) {
22732
22593
  const res = await runGit([
22733
22594
  "rev-parse",
@@ -28204,7 +28065,7 @@ __name(viewResourceInteractive, "viewResourceInteractive");
28204
28065
  init_cli();
28205
28066
  init_command_utils();
28206
28067
  init_analytics();
28207
- import open2 from "open";
28068
+ import open from "open";
28208
28069
  async function adminCommand() {
28209
28070
  return withErrorHandling(async () => {
28210
28071
  writeProgress("Opening Lua Admin Dashboard...");
@@ -28212,7 +28073,7 @@ async function adminCommand() {
28212
28073
  showProgress: false
28213
28074
  });
28214
28075
  const adminUrl = `https://admin.heylua.ai/validate-token/${apiKey}?redirect=/admin/usage?&agentId=${agentId}&orgId=${orgId}`;
28215
- await open2(adminUrl);
28076
+ await open(adminUrl);
28216
28077
  writeSuccess("Lua Admin Dashboard opened in your browser");
28217
28078
  console.log(`
28218
28079
  Dashboard URL: https://admin.heylua.ai`);
@@ -28228,7 +28089,7 @@ __name(adminCommand, "adminCommand");
28228
28089
  init_cli();
28229
28090
  init_command_utils();
28230
28091
  init_analytics();
28231
- import open3 from "open";
28092
+ import open2 from "open";
28232
28093
  async function evalsCommand() {
28233
28094
  return withErrorHandling(async () => {
28234
28095
  writeProgress("Opening Lua Evaluations Dashboard...");
@@ -28236,7 +28097,7 @@ async function evalsCommand() {
28236
28097
  showProgress: false
28237
28098
  });
28238
28099
  const evalsUrl = `https://evals.heylua.ai?apiKey=${apiKey}&agentID=${agentId}`;
28239
- await open3(evalsUrl);
28100
+ await open2(evalsUrl);
28240
28101
  writeSuccess("Lua Evaluations Dashboard opened in your browser");
28241
28102
  console.log(`
28242
28103
  Dashboard URL: https://evals.heylua.ai`);
@@ -28250,12 +28111,12 @@ __name(evalsCommand, "evalsCommand");
28250
28111
  // src/commands/docs.ts
28251
28112
  init_cli();
28252
28113
  init_analytics();
28253
- import open4 from "open";
28114
+ import open3 from "open";
28254
28115
  async function docsCommand() {
28255
28116
  return withErrorHandling(async () => {
28256
28117
  writeProgress("Opening Lua Documentation...");
28257
28118
  const docsUrl = "https://docs.heylua.ai";
28258
- await open4(docsUrl);
28119
+ await open3(docsUrl);
28259
28120
  writeSuccess("Lua Documentation opened in your browser");
28260
28121
  console.log(`
28261
28122
  Documentation: ${docsUrl}
@@ -28269,7 +28130,7 @@ __name(docsCommand, "docsCommand");
28269
28130
  init_cli();
28270
28131
  init_command_utils();
28271
28132
  import inquirer12 from "inquirer";
28272
- import open5 from "open";
28133
+ import open4 from "open";
28273
28134
 
28274
28135
  // src/api/channels.api.service.ts
28275
28136
  init_http_client();
@@ -28838,7 +28699,7 @@ async function openAdminDashboard(apiKey, config) {
28838
28699
  throw new Error("No orgId found in lua.skill.yaml. Please ensure your configuration is valid.");
28839
28700
  }
28840
28701
  const adminUrl = `https://admin.heylua.ai/validate-token/${apiKey}?redirect=/admin/usage?&agentId=${agentId}&orgId=${orgId}`;
28841
- await open5(adminUrl);
28702
+ await open4(adminUrl);
28842
28703
  writeSuccess("\u2705 Lua Admin Dashboard opened in your browser");
28843
28704
  console.log(`
28844
28705
  Dashboard URL: https://admin.heylua.ai`);
@@ -37622,7 +37483,7 @@ init_cli();
37622
37483
  init_constants();
37623
37484
  import http from "http";
37624
37485
  import { URL as URL2 } from "url";
37625
- import open6 from "open";
37486
+ import open5 from "open";
37626
37487
  init_command_utils();
37627
37488
  init_developer_api_service();
37628
37489
 
@@ -38645,7 +38506,7 @@ Integration: ${selectedIntegration.name}`);
38645
38506
  `);
38646
38507
  const callbackPromise = startCallbackServer(3e5);
38647
38508
  try {
38648
- await open6(authUrl);
38509
+ await open5(authUrl);
38649
38510
  writeInfo("\u{1F310} Browser opened - please complete the authorization");
38650
38511
  } catch (error) {
38651
38512
  writeInfo("\u{1F4A1} Could not open browser automatically. Please open the URL above manually.");
@@ -39076,7 +38937,7 @@ Available scopes for ${selectedIntegration.name}:`);
39076
38937
  `);
39077
38938
  const callbackPromise = startCallbackServer(3e5);
39078
38939
  try {
39079
- await open6(authUrl);
38940
+ await open5(authUrl);
39080
38941
  writeInfo("\u{1F310} Browser opened - please complete the authorization");
39081
38942
  } catch (error) {
39082
38943
  writeInfo("\u{1F4A1} Could not open browser automatically. Please open the URL above manually.");
@@ -41289,7 +41150,7 @@ __name(pumpRemoteAudioToSpeaker, "pumpRemoteAudioToSpeaker");
41289
41150
  // src/commands/voice-browser.ts
41290
41151
  init_cli();
41291
41152
  import http2 from "http";
41292
- import open7 from "open";
41153
+ import open6 from "open";
41293
41154
  var SAFETY_TIMEOUT_MS = 60 * 60 * 1e3;
41294
41155
  async function runBrowserMode(joinUrl) {
41295
41156
  const { wsUrl, token } = parseJoinUrl(joinUrl);
@@ -41321,7 +41182,7 @@ async function runBrowserMode(joinUrl) {
41321
41182
  const localUrl = `http://localhost:${port}/`;
41322
41183
  writeSuccess(`Voice room ready (opening browser)`);
41323
41184
  console.log(` ${localUrl}`);
41324
- await open7(localUrl);
41185
+ await open6(localUrl);
41325
41186
  await new Promise((resolve6) => {
41326
41187
  const safety = setTimeout(() => {
41327
41188
  try {
@@ -42374,7 +42235,7 @@ function failConnect(status, banner, errorMessage) {
42374
42235
  throw new Error(errorMessage);
42375
42236
  }
42376
42237
  __name(failConnect, "failConnect");
42377
- async function gitConnectCommand() {
42238
+ async function gitConnectCommand(opts = {}) {
42378
42239
  return withErrorHandling(async () => {
42379
42240
  const config = readYamlConfig();
42380
42241
  if (!config) {
@@ -42413,15 +42274,35 @@ async function gitConnectCommand() {
42413
42274
  user_configured: false
42414
42275
  }, '\u2717 Git user.name is not configured.\n Fix: git config --global user.name "Your Name"', "git user.name is not configured");
42415
42276
  }
42277
+ const passedStatus = {
42278
+ git_available: true,
42279
+ in_repo: true,
42280
+ user_configured: true
42281
+ };
42282
+ if (opts.autoPush) {
42283
+ const token = await getToken2("github");
42284
+ if (!token) {
42285
+ failConnect(passedStatus, "\u2717 --auto-push needs a linked GitHub account.\n Fix: run `lua git auth github` to link your GitHub account, then re-run `lua git connect --auto-push`.", "no GitHub account linked");
42286
+ }
42287
+ const remote = await getRemoteOriginUrl();
42288
+ if (!remote) {
42289
+ failConnect(passedStatus, "\u2717 --auto-push needs a GitHub remote, but `remote.origin.url` is not set.\n Fix: git remote add origin https://github.com/<owner>/<repo>.git", "no origin remote configured");
42290
+ }
42291
+ if (!isGitHubUrl(remote)) {
42292
+ failConnect(passedStatus, `\u2717 --auto-push only supports GitHub HTTPS remotes, but origin is ${remote}.
42293
+ Fix: git remote set-url origin https://github.com/<owner>/<repo>.git`, "origin is not a GitHub HTTPS remote");
42294
+ }
42295
+ }
42416
42296
  config.git = {
42297
+ ...config.git,
42417
42298
  enabled: true
42418
42299
  };
42300
+ if (opts.autoPush) config.git.autoPush = true;
42419
42301
  writeYamlConfig(config);
42420
- writeSuccess("\u2713 Git integration enabled. Future `lua push`, `lua version *`, and `lua pull` runs will auto-commit.");
42302
+ writeSuccess(opts.autoPush ? "\u2713 Git integration enabled with auto-push. Future `lua push`, `lua version *`, and `lua pull` runs will auto-commit and push to GitHub." : "\u2713 Git integration enabled. Future `lua push`, `lua version *`, and `lua pull` runs will auto-commit.");
42421
42303
  trackEvent("cli_git_connect_completed", {
42422
- git_available: true,
42423
- in_repo: true,
42424
- user_configured: true,
42304
+ ...passedStatus,
42305
+ auto_push: Boolean(opts.autoPush),
42425
42306
  succeeded: true
42426
42307
  });
42427
42308
  }, "git connect");
@@ -42535,7 +42416,7 @@ function gitAuthGithubCommand(opts) {
42535
42416
  writeSuccess(`Logged in to GitHub as @${result.username}.`);
42536
42417
  trackEvent("cli_git_auth_succeeded", {
42537
42418
  provider: "github",
42538
- flow: opts.device ? "device" : "loopback"
42419
+ flow: "device"
42539
42420
  });
42540
42421
  }, "git-auth-github");
42541
42422
  }
@@ -43319,11 +43200,13 @@ Examples:
43319
43200
  $ lua version delete v3 --force Skip confirmation
43320
43201
  `).action((version, opts) => versionDeleteCommand(version, opts));
43321
43202
  const gitGroup = program2.command("git").description("Manage opt-in git auto-commits for this project");
43322
- gitGroup.command("connect").description("Enable git auto-commits (runs sanity checks, writes git.enabled: true)").action(() => gitConnectCommand());
43203
+ gitGroup.command("connect").description("Enable git auto-commits (runs sanity checks, writes git.enabled: true)").option("--auto-push", "Also enable post-commit auto-push (requires `lua git auth github` + a GitHub HTTPS origin remote)").action((opts) => gitConnectCommand({
43204
+ autoPush: opts.autoPush
43205
+ }));
43323
43206
  gitGroup.command("disconnect").description("Disable git auto-commits (existing commits/tags untouched)").action(() => gitDisconnectCommand());
43324
43207
  gitGroup.command("status").description("Show git integration config + last lua-issued commit/tag").action(() => gitStatusCommand());
43325
43208
  const gitAuthGroup = gitGroup.command("auth").description("Manage git remote provider authentication");
43326
- gitAuthGroup.command("github").description("Link a GitHub account").option("--device", "Use the device flow (paste a code into github.com/login/device)").option("--force", "Overwrite an existing link without prompting").action((opts) => gitAuthGithubCommand(opts));
43209
+ gitAuthGroup.command("github").description("Link a GitHub account (OAuth device flow)").option("--device", "(deprecated; device flow is always used \u2014 flag kept for compatibility)").option("--force", "Overwrite an existing link without prompting").action((opts) => gitAuthGithubCommand(opts));
43327
43210
  gitAuthGroup.command("status").description("Show the current git auth status").action(() => gitAuthStatusCommand());
43328
43211
  gitAuthGroup.command("disconnect [provider]").description("Disconnect a git provider (default: github)").action((provider) => gitAuthDisconnectCommand(provider));
43329
43212
  program2.command("pull").description("\u{1F4E5} Pull the agent's source code locally").option("--version <version>", "Pull source linked to a specific agent version (requires versioning)").option("--force", "Skip confirmation prompt").addHelpText("after", `