@actionway/cli 0.18.3 → 0.18.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.
Files changed (2) hide show
  1. package/dist/index.js +59 -11
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -12434,7 +12434,7 @@ var REFRESH_SKEW_S = 30;
12434
12434
  var TOKEN_TIMEOUT_MS = 2e4;
12435
12435
  var DISCOVERY_TIMEOUT_MS = 1e4;
12436
12436
  var SESSION_TIMEOUT_MS = 2e4;
12437
- var DEFAULT_LOGIN_TIMEOUT_MS = 12e4;
12437
+ var DEFAULT_LOGIN_TIMEOUT_MS = 12e5;
12438
12438
  function stripSlash(url) {
12439
12439
  return url.replace(/\/+$/, "");
12440
12440
  }
@@ -12521,7 +12521,15 @@ async function fetchCliOAuthConfig(gateway, fetchImpl = fetch) {
12521
12521
  signal: AbortSignal.timeout(DISCOVERY_TIMEOUT_MS)
12522
12522
  });
12523
12523
  if (!response.ok) {
12524
- throw new Error(`Actionway login configuration is unavailable (${response.status})`);
12524
+ let detail = "";
12525
+ try {
12526
+ const body2 = await response.json();
12527
+ const code = typeof body2?.error?.code === "string" ? body2.error.code : "";
12528
+ const message = typeof body2?.error?.message === "string" ? body2.error.message : "";
12529
+ detail = [code, message].filter(Boolean).join(": ");
12530
+ } catch {
12531
+ }
12532
+ throw new Error(`Actionway login configuration is unavailable (${response.status}${detail ? `; ${detail}` : ""})`);
12525
12533
  }
12526
12534
  const body = await response.json();
12527
12535
  if (typeof body !== "object" || body === null || !("issuer" in body) || typeof body.issuer !== "string" || !("client_id" in body) || typeof body.client_id !== "string" || !body.issuer.trim() || !body.client_id.trim()) {
@@ -12694,14 +12702,21 @@ async function waitForCode(state, timeoutMs) {
12694
12702
  const port = server.address().port;
12695
12703
  const timer = setTimeout(() => {
12696
12704
  rejectCode(
12697
- new CliError("E_BACKEND", `login timed out after ${Math.round(timeoutMs / 1e3)} seconds`, "run `actionway login` again")
12705
+ new CliError(
12706
+ "E_BACKEND",
12707
+ `login timed out after ${Math.round(timeoutMs / 1e3)} seconds`,
12708
+ "run `actionway login` again and ask the user to finish the browser sign-in promptly; pass --timeout-seconds <n> to allow more time"
12709
+ )
12698
12710
  );
12699
12711
  server.close();
12700
12712
  }, timeoutMs);
12701
12713
  return {
12702
12714
  redirectUri: `http://127.0.0.1:${port}/callback`,
12703
12715
  code: code.finally(() => clearTimeout(timer)),
12704
- close: () => new Promise((resolve3) => server.listening ? server.close(() => resolve3()) : resolve3())
12716
+ close: () => {
12717
+ clearTimeout(timer);
12718
+ return new Promise((resolve3) => server.listening ? server.close(() => resolve3()) : resolve3());
12719
+ }
12705
12720
  };
12706
12721
  }
12707
12722
  async function readJsonObject(response) {
@@ -12720,8 +12735,14 @@ async function tokenRequest(issuer, body, fetchImpl) {
12720
12735
  });
12721
12736
  const value = await readJsonObject(response);
12722
12737
  if (!response.ok || typeof value.access_token !== "string") {
12723
- const message = typeof value.error_description === "string" ? value.error_description : "token request failed";
12724
- throw new CliError("E_BACKEND", message);
12738
+ const code = typeof value.error === "string" ? value.error : "";
12739
+ const description = typeof value.error_description === "string" ? value.error_description : "";
12740
+ const message = [code, description].filter(Boolean).join(": ") || "token request failed";
12741
+ throw new CliError(
12742
+ "E_BACKEND",
12743
+ message,
12744
+ code === "invalid_client" ? "the client_id/issuer pair does not belong to one Actionway environment: clear ACTIONWAY_OAUTH_CLIENT_ID and ACTIONWAY_OAUTH_ISSUER (or drop --client-id/--issuer) and run `actionway login` again to rediscover both; if no overrides are set, the stored credentials are stale \u2014 run `actionway logout` then `actionway login`" : void 0
12745
+ );
12725
12746
  }
12726
12747
  return {
12727
12748
  accessToken: value.access_token,
@@ -12796,19 +12817,44 @@ async function login(options = {}) {
12796
12817
  const onNotice = options.onNotice ?? ((message) => process.stderr.write(`${message}
12797
12818
  `));
12798
12819
  const gateway = resolveGatewayUrl(options.gateway, env);
12820
+ const gatewaySource = options.gateway?.trim() ? "flag" : (env.ACTIONWAY_GATEWAY_URL ?? "").trim() ? "env" : "default";
12799
12821
  let clientId = options.clientId?.trim() || (env.ACTIONWAY_OAUTH_CLIENT_ID ?? "").trim();
12800
12822
  let issuer = options.issuer?.trim() || (env.ACTIONWAY_OAUTH_ISSUER ?? "").trim();
12823
+ const clientIdSource = options.clientId?.trim() ? "flag" : (env.ACTIONWAY_OAUTH_CLIENT_ID ?? "").trim() ? "env" : "discovery";
12824
+ const issuerSource = options.issuer?.trim() ? "flag" : (env.ACTIONWAY_OAUTH_ISSUER ?? "").trim() ? "env" : "discovery";
12825
+ const authContext = () => ({
12826
+ gateway_url: gateway,
12827
+ gateway_source: gatewaySource,
12828
+ ...issuer ? { issuer } : {},
12829
+ issuer_source: issuerSource,
12830
+ ...clientId ? { client_id: clientId } : {},
12831
+ client_id_source: clientIdSource
12832
+ });
12833
+ const withAuthContext = (error) => {
12834
+ if (error instanceof CliError) {
12835
+ throw new CliError(error.code, error.message, error.hint, { ...error.extra ?? {}, auth_context: authContext() });
12836
+ }
12837
+ throw error;
12838
+ };
12839
+ if (!!clientId !== !!issuer) {
12840
+ throw new CliError(
12841
+ "E_SCHEMA",
12842
+ "client_id and issuer overrides must be provided together",
12843
+ "pass both --client-id and --issuer (or set both ACTIONWAY_OAUTH_CLIENT_ID and ACTIONWAY_OAUTH_ISSUER), or neither to use discovery",
12844
+ { auth_context: authContext() }
12845
+ );
12846
+ }
12801
12847
  if (!clientId || !issuer) {
12802
12848
  let discovered;
12803
12849
  try {
12804
12850
  discovered = await fetchCliOAuthConfig(gateway, fetchImpl);
12805
12851
  } catch (error) {
12806
12852
  const message = error instanceof Error ? error.message : String(error);
12807
- throw new CliError(
12853
+ return withAuthContext(new CliError(
12808
12854
  "E_BACKEND",
12809
12855
  `login failed: ${message}`,
12810
- "retry later or pass --client-id and --issuer explicitly"
12811
- );
12856
+ "check auth_context.gateway_url is the intended Actionway environment (unset ACTIONWAY_GATEWAY_URL or fix --gateway if not) and run `actionway login` again; if the gateway is correct, the environment is misconfigured \u2014 report this error to the user instead of retrying (passing both --client-id and --issuer explicitly remains available as a temporary override)"
12857
+ ));
12812
12858
  }
12813
12859
  clientId ||= discovered.clientId;
12814
12860
  issuer ||= discovered.issuer;
@@ -12865,6 +12911,8 @@ ${authorizeUrl}`);
12865
12911
  };
12866
12912
  saveCredentials(credentials, env);
12867
12913
  return { credentials, account };
12914
+ } catch (error) {
12915
+ return withAuthContext(error);
12868
12916
  } finally {
12869
12917
  await callback.close();
12870
12918
  }
@@ -12917,7 +12965,7 @@ function failFromError2(err, fallbackHint) {
12917
12965
  });
12918
12966
  }
12919
12967
  function registerAuthCommands(program2) {
12920
- program2.command("login").description("Authenticate with Actionway in the browser (Clerk OAuth with PKCE).").option("--gateway <url>", "Actionway public origin").option("--client-id <id>", "Actionway OAuth client id (default: discovered from the public origin)").option("--issuer <url>", "Actionway OAuth issuer (default: discovered from the public origin)").option("--timeout-seconds <n>", "how long to wait for browser authentication").option("--no-browser", "print the authorize URL instead of opening a browser").action(async (opts) => {
12968
+ program2.command("login").description("Authenticate with Actionway in the browser (Clerk OAuth with PKCE).").option("--gateway <url>", "Actionway public origin").option("--client-id <id>", "Actionway OAuth client id (must be paired with --issuer; default: both discovered from the public origin)").option("--issuer <url>", "Actionway OAuth issuer (must be paired with --client-id; default: both discovered from the public origin)").option("--timeout-seconds <n>", "how long to wait for browser authentication").option("--no-browser", "print the authorize URL instead of opening a browser").action(async (opts) => {
12921
12969
  try {
12922
12970
  const { credentials, account } = await login({
12923
12971
  ...opts.gateway ? { gateway: opts.gateway } : {},
@@ -13415,7 +13463,7 @@ function failFromError3(err) {
13415
13463
  function registerInitCommand(program2) {
13416
13464
  program2.command("init").description(
13417
13465
  "Complete browser authentication and stage the Actionway Skill for your agent to install. The CLI never writes into an agent's own configuration directory."
13418
- ).option("--gateway <url>", "Actionway public origin").option("--client-id <id>", "Actionway OAuth client id").option("--issuer <url>", "Actionway OAuth issuer").option("--timeout-seconds <n>", "how long to wait for browser authentication").option("--install-session-id <uuid>", "onboarding install session id").option("--no-browser", "print the authorize URL instead of opening a browser").addOption(new Option("--skill-only").hideHelp()).action(async (opts) => {
13466
+ ).option("--gateway <url>", "Actionway public origin").option("--client-id <id>", "Actionway OAuth client id (must be paired with --issuer)").option("--issuer <url>", "Actionway OAuth issuer (must be paired with --client-id)").option("--timeout-seconds <n>", "how long to wait for browser authentication").option("--install-session-id <uuid>", "onboarding install session id").option("--no-browser", "print the authorize URL instead of opening a browser").addOption(new Option("--skill-only").hideHelp()).action(async (opts) => {
13419
13467
  try {
13420
13468
  const skill = materializeSkill();
13421
13469
  if (opts.skillOnly) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actionway/cli",
3
- "version": "0.18.3",
3
+ "version": "0.18.4",
4
4
  "description": "actionway CLI 的本地端壳:Clerk OAuth 鉴权 + cli-core 共享命令面 + init / update / skill 物化 / 版本三链路(终端用户本地 Codex / Claude Code 使用)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -19,8 +19,8 @@
19
19
  "tsx": "^4.20.0",
20
20
  "typescript": "7.0.2",
21
21
  "vitest": "^3.2.7",
22
- "@actionway/contracts": "0.1.0",
23
- "@actionway/cli-core": "0.1.0"
22
+ "@actionway/cli-core": "0.1.0",
23
+ "@actionway/contracts": "0.1.0"
24
24
  },
25
25
  "engines": {
26
26
  "node": ">=20"