@actionway/cli 0.18.3 → 0.18.5

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
@@ -33,6 +33,7 @@ actionway init
33
33
  - **命令面 = 明码写出的注册表**(无 profile flag、无运行期分叉):
34
34
  - `tools search / inspect / call` 是长尾 capability 的规范发现与执行面;
35
35
  - 高频 typed command 继续提供参数与文件 UX,但投影到同一个 Tool Call;
36
+ - `account invitation` 获取或首次创建当前账户的永久邀请码、链接和服务端本地化分享文案;
36
37
  - `account usage / wallet / transactions` 只读 Actionway Business 数据;
37
38
  - 本壳另有 `init` / `doctor` / `update` / `login` / `logout` / `whoami`,cli-core
38
39
  继续提供 wait/poll 与已冻结的共享 typed commands。
@@ -63,6 +64,7 @@ pnpm cli logout # 删除本机凭据;重复执行也是成功的幂
63
64
  pnpm cli update --check # 查新版(24h 缓存)
64
65
  pnpm cli -- tools search "generate a product image"
65
66
  pnpm cli -- tools inspect media.image.generate
67
+ pnpm cli -- account invitation --locale zh-cn
66
68
  pnpm cli -- account usage
67
69
  pnpm cli -- account usage --from 2026-08-01 --to 2026-09-01 --service generate-image
68
70
  pnpm cli -- account transactions --from 2026-08-01 --kind top_up
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: actionway
3
- description: Use the local Actionway CLI to discover, inspect, price, and call Actionway capabilities; continue asynchronous jobs or confirmed calls; read Actionway account usage, wallet, and transactions; authenticate; or update the CLI. Trigger when a local Agent can complete a task through `actionway`, when a `job_ref` or `call_ref` must be continued, or when the user asks about Actionway tools or account data.
3
+ description: Use the local Actionway CLI to discover, inspect, price, and call Actionway capabilities; continue asynchronous jobs or confirmed calls; get the signed-in user's Actionway invitation, account usage, wallet, and transactions; authenticate; or update the CLI. Trigger when a local Agent can complete a task through `actionway`, when a `job_ref` or `call_ref` must be continued, or when the user asks about Actionway tools or account data.
4
4
  metadata:
5
5
  version: "0.0.0-dev"
6
6
  ---
@@ -23,7 +23,8 @@ Use the installed `actionway` CLI and its server-backed Capability Registry as t
23
23
  - If Search returns `clarification_required`, ask its bounded question. If it returns candidates, choose only a supported `tool_ref` and run `actionway tools inspect <tool_ref>` before the generic call. Inspect is the authority for the current input Schema, variants, effects, guidance, and Actionway USD price.
24
24
  - `actionway search` is the Web Search business capability. Capability discovery is always `actionway tools search`.
25
25
  - Use a high-frequency typed command only when `actionway --help` exposes an exact fit. Read `actionway <command> --help` and, when available, `--print-schema`; typed commands are parameter/file conveniences over the same Tool Call, confirmation, billing, and Job path.
26
- - For account questions, use only the requested read command: `actionway account usage`, `actionway account wallet`, or `actionway account transactions`.
26
+ - When the signed-in user asks to generate, show, copy, or share their invitation, run `actionway account invitation --locale <zh-cn|zh-tw|en|ja>` using the conversation language. Return the server-provided `code`, `url`, and `message`; do not invent reward amounts or rewrite promotion terms. The first request creates one permanent code and later requests return that same code.
27
+ - For other account questions, use only the requested read command: `actionway account usage`, `actionway account wallet`, or `actionway account transactions`.
27
28
 
28
29
  ## Inspect and call
29
30
 
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 } : {},
@@ -12967,6 +13015,10 @@ function failAccount(error) {
12967
13015
  }
12968
13016
  fail({ code: "E_BACKEND", message: error instanceof Error ? error.message : String(error) });
12969
13017
  }
13018
+ function invitationEndpoint(locale = "en") {
13019
+ const parameters = new URLSearchParams({ locale });
13020
+ return `v1/account/invitation?${parameters.toString()}`;
13021
+ }
12970
13022
  function accountEndpoint(path, options) {
12971
13023
  const parameters = new URLSearchParams();
12972
13024
  for (const [name, value] of [
@@ -12992,7 +13044,8 @@ async function read(endpoint, getTransport3) {
12992
13044
  }
12993
13045
  }
12994
13046
  function registerAccountCommands(program2, getTransport3) {
12995
- const account = program2.command("account").description("Read your Actionway USD wallet, service usage, and wallet transactions.");
13047
+ const account = program2.command("account").description("Access your Actionway invitation, USD wallet, service usage, and wallet transactions.");
13048
+ account.command("invitation").description("Get or create your permanent invitation code, link, and localized share message.").option("--locale <locale>", "Share-message locale: zh-cn, zh-tw, en, or ja.", "en").action((options) => read(invitationEndpoint(options.locale), getTransport3));
12996
13049
  account.command("usage").description("Query held, charged, released, and free capability calls.").option("--limit <count>", "Maximum records in this page (1-100).").option("--cursor <cursor>", "Opaque nextCursor returned by the previous page.").option("--from <date>", "Inclusive ISO date or timestamp (UTC for date-only values).").option("--to <date>", "Exclusive ISO date or timestamp (UTC for date-only values).").option("--status <status>", "held, settled, or expired.").option("--service <service-id>", "Exact public serviceId.").option("--pricing-kind <kind>", "priced or free.").action((options) => read(accountEndpoint("usage", options), getTransport3));
12997
13050
  account.command("wallet").description("Show the current available and held Actionway USD wallet balance.").action(() => read("v1/account/wallet", getTransport3));
12998
13051
  account.command("transactions").description("Query wallet top-ups, charges, promotions, refunds, and other fund movements.").option("--limit <count>", "Maximum records in this page (1-50).").option("--cursor <cursor>", "Opaque nextCursor returned by the previous page.").option("--from <date>", "Inclusive ISO date or timestamp (UTC for date-only values).").option("--to <date>", "Exclusive ISO date or timestamp (UTC for date-only values).").option("--status <status>", "pending, succeeded, or failed.").option("--kind <kind>", "top_up, charge, refund, dispute, or promotion kind.").action((options) => read(accountEndpoint("transactions", options), getTransport3));
@@ -13415,7 +13468,7 @@ function failFromError3(err) {
13415
13468
  function registerInitCommand(program2) {
13416
13469
  program2.command("init").description(
13417
13470
  "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) => {
13471
+ ).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
13472
  try {
13420
13473
  const skill = materializeSkill();
13421
13474
  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.5",
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"