traderclaw-cli 1.0.114 → 1.0.116

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.
@@ -1827,12 +1827,13 @@ function configureOpenClawLlmModelPrimaryOnly({ provider, model }, configPath =
1827
1827
  }
1828
1828
 
1829
1829
  /**
1830
- * Spawns `openclaw models auth login --provider openai-codex` with a pseudo-TTY when possible.
1830
+ * Spawns `openclaw models auth login --provider openai-codex --method oauth` with a pseudo-TTY when possible.
1831
+ * `--method oauth` skips the interactive Browser vs Device pairing menu (OpenClaw 2026.4.29+); device flow is `device-code`.
1831
1832
  * The CLI often exits immediately when stdin/stdout are plain pipes (no TTY). On Unix, `script(1)`
1832
1833
  * allocates a PTY so the same flow works as in an interactive terminal.
1833
1834
  */
1834
1835
  export function spawnOpenClawCodexAuthLoginChild() {
1835
- const argv = ["models", "auth", "login", "--provider", "openai-codex"];
1836
+ const argv = ["models", "auth", "login", "--provider", "openai-codex", "--method", "oauth"];
1836
1837
  if (process.platform === "win32") {
1837
1838
  return spawn("openclaw", argv, { stdio: ["pipe", "pipe", "pipe"], shell: false });
1838
1839
  }
@@ -1840,14 +1841,19 @@ export function spawnOpenClawCodexAuthLoginChild() {
1840
1841
  return spawn("unbuffer", ["openclaw", ...argv], { stdio: ["pipe", "pipe", "pipe"], shell: false });
1841
1842
  }
1842
1843
  if (commandExists("script")) {
1843
- const cmdline = "openclaw models auth login --provider openai-codex";
1844
- // --return propagates the inner command's exit code (util-linux 2.38+).
1845
- // Without it, script may exit 0 even if openclaw fails.
1846
- // -f/--flush: when the wizard reads script's stdout via a pipe, default
1847
- // block buffering can delay OAuth URLs until the buffer fills (e.g. 4KiB+),
1848
- // tripping the install wizard's URL detection timeout (OpenClaw 2026.4.x+).
1844
+ // stty cols 32767: set an extremely wide PTY column so OpenClaw/Clack never
1845
+ // wraps the OAuth URL across lines (default PTY width when spawned via pipe is 80).
1846
+ // A wrapped URL causes the wizard's regex to only capture the first segment.
1847
+ // --return propagates openclaw's exit code (util-linux 2.38+).
1848
+ // -f/--flush: force immediate forwarding of each PTY write to the pipe so the
1849
+ // wizard sees the URL as soon as OpenClaw prints it (default is block-buffered).
1850
+ const cmdline =
1851
+ "stty cols 32767 rows 50 2>/dev/null; openclaw models auth login --provider openai-codex --method oauth";
1849
1852
  return spawn("script", ["--return", "-f", "-q", "-c", cmdline, "/dev/null"], {
1850
1853
  stdio: ["pipe", "pipe", "pipe"],
1854
+ // COLUMNS/LINES: belt-and-suspenders env fallback for programs that read env
1855
+ // instead of ioctl(TIOCGWINSZ) to determine terminal dimensions.
1856
+ env: { ...process.env, COLUMNS: "32767", LINES: "50" },
1851
1857
  shell: false,
1852
1858
  });
1853
1859
  }
@@ -1855,7 +1861,7 @@ export function spawnOpenClawCodexAuthLoginChild() {
1855
1861
  }
1856
1862
 
1857
1863
  /**
1858
- * Runs `openclaw models auth login --provider openai-codex` and feeds the pasted redirect URL or code on stdin
1864
+ * Runs `openclaw models auth login --provider openai-codex --method oauth` and feeds the pasted redirect URL or code on stdin
1859
1865
  * when the CLI prompts (with a timed fallback for non-interactive / SSH).
1860
1866
  */
1861
1867
  function runOpenClawCodexOAuthLogin(paste, emitLog) {
@@ -2329,7 +2335,7 @@ export class InstallerStepEngine {
2329
2335
  } catch (err) {
2330
2336
  const tail = `${err?.stderr || ""}\n${err?.stdout || ""}\n${err?.message || ""}`.trim();
2331
2337
  throw new Error(
2332
- `${tail}\n\nIf OAuth cannot complete from the wizard, run in a shell: openclaw models auth login --provider openai-codex — then re-run the wizard with "already logged in" checked.`,
2338
+ `${tail}\n\nIf OAuth cannot complete from the wizard, run in a shell: openclaw models auth login --provider openai-codex --method oauth — then re-run the wizard with "already logged in" checked.`,
2333
2339
  );
2334
2340
  }
2335
2341
  }
@@ -2343,7 +2349,7 @@ export class InstallerStepEngine {
2343
2349
  throw new Error(
2344
2350
  "No OAuth credentials found at " + authFile + ". " +
2345
2351
  "The wizard OAuth flow did not save tokens (the callback may not have reached the OpenClaw CLI). " +
2346
- "Run 'openclaw models auth login --provider openai-codex' in a terminal, " +
2352
+ "Run 'openclaw models auth login --provider openai-codex --method oauth' in a terminal, " +
2347
2353
  "then re-run the wizard with the 'already logged in' option.",
2348
2354
  );
2349
2355
  }
@@ -3043,7 +3043,11 @@ function wizardHtml(defaults) {
3043
3043
  setOauthStep(oauthStepOpen, "error");
3044
3044
  setOauthStep(oauthStepComplete, "error");
3045
3045
  setOauthStep(oauthStepVerify, "error");
3046
- setOauthStatus((data && (data.message || data.error)) || "Could not start OAuth sign-in.", true);
3046
+ let msg = (data && (data.message || data.error)) || "Could not start OAuth sign-in.";
3047
+ if (data && typeof data.detail === "string" && data.detail.trim()) {
3048
+ msg += " " + data.detail.trim().slice(0, 1500);
3049
+ }
3050
+ setOauthStatus(msg, true);
3047
3051
  if (oauthRetryBtn) oauthRetryBtn.classList.remove("hidden");
3048
3052
  updateStartButtonState();
3049
3053
  return;
@@ -3629,6 +3633,27 @@ async function cmdInstall(args) {
3629
3633
  // The \S+ (non-whitespace) tail captures the full query string; see trySendUrl()
3630
3634
  // for why we run this against a stripAnsi+CR-stripped copy of the output.
3631
3635
  const OPENAI_OAUTH_AUTHORIZE_RE = /https:\/\/auth\.openai\.com\/(?:oauth\/authorize|authorize)[^\s"]*/;
3636
+ const OPENAI_OAUTH_AUTHORIZE_RE_LOOSE =
3637
+ /https:\/\/(?:[a-z0-9-]+\.)*openai\.com\/[^\s"]*?(?:oauth\/authorize|\/authorize[^\s"]*)/i;
3638
+
3639
+ /** Best-effort: primary regex, then subdomain/openai authorize URLs, then token-like query heuristics. */
3640
+ function tryExtractOpenAiCodexAuthorizeUrl(cleaned) {
3641
+ let m = cleaned.match(OPENAI_OAUTH_AUTHORIZE_RE);
3642
+ if (m?.[0]) return m[0];
3643
+ m = cleaned.match(OPENAI_OAUTH_AUTHORIZE_RE_LOOSE);
3644
+ if (m?.[0]) return m[0];
3645
+ const candidates = cleaned.match(/https:\/\/[^\s"]+/g) || [];
3646
+ for (const u of candidates) {
3647
+ if (
3648
+ /openai\.com/i.test(u)
3649
+ && /authorize/i.test(u)
3650
+ && /oauth|response_type|client_id|redirect_uri|scope=/i.test(u)
3651
+ ) {
3652
+ return u;
3653
+ }
3654
+ }
3655
+ return null;
3656
+ }
3632
3657
  const oauthSessionTtlMs = 15 * 60 * 1000;
3633
3658
 
3634
3659
  // Long-lived callback proxy on port 1455. Bound at wizard startup so
@@ -3856,6 +3881,10 @@ async function cmdInstall(args) {
3856
3881
  const urlTimeout = setTimeout(() => {
3857
3882
  if (responded) return;
3858
3883
  responded = true;
3884
+ const detail = stripAnsi(combined).slice(-4000);
3885
+ if (process.env.TRADERCLAW_WIZARD_OAUTH_DEBUG === "1") {
3886
+ printWarn(`[TRADERCLAW_WIZARD_OAUTH_DEBUG] OpenClaw output tail before oauth_url_timeout:\n${detail}`);
3887
+ }
3859
3888
  try {
3860
3889
  child.kill("SIGTERM");
3861
3890
  } catch {
@@ -3868,20 +3897,31 @@ async function cmdInstall(args) {
3868
3897
  error: "oauth_url_timeout",
3869
3898
  message:
3870
3899
  "OpenClaw did not provide a ChatGPT sign-in URL in time. Try again.",
3900
+ detail,
3871
3901
  });
3872
3902
  }, 120_000);
3873
3903
 
3874
3904
  const trySendUrl = () => {
3875
3905
  if (responded) return;
3876
- // Strip ANSI escape codes and carriage returns before matching.
3877
- // Newer OpenClaw uses rich terminal output (spinners, colors) and PTY
3878
- // column-wrapping inserts \r\n in the middle of long OAuth URLs, causing
3879
- // the regex to fail on the raw byte stream. Clean first, then match.
3880
- const cleanedForUrl = stripAnsi(combined).replace(/\r/g, "");
3881
- const m = cleanedForUrl.match(OPENAI_OAUTH_AUTHORIZE_RE);
3882
- if (!m || !m[0]) return;
3883
- // Strip any trailing ANSI remnants that slipped through (e.g. \x1b[0m appended by colour reset)
3884
- const authUrl = m[0].replace(/\x1b[^a-zA-Z]*[a-zA-Z]?$/g, "").trim();
3906
+ // Layer 1: strip ANSI codes and carriage returns, then join any URL continuation
3907
+ // lines caused by PTY column-wrapping (e.g. at 80-col default). When the URL is
3908
+ // split across lines the [^\s] tail of the regex stops at the newline and only the
3909
+ // first fragment is captured. Removing newlines that are sandwiched between URL-safe
3910
+ // characters reconnects all fragments before matching.
3911
+ const cleanedForUrl = stripAnsi(combined)
3912
+ .replace(/\r/g, "")
3913
+ .replace(/([A-Za-z0-9%&=+?#:/@._~!$'()*,;-])\n([A-Za-z0-9%&=+?#:/@._~!$'()*,;-])/g, "$1$2");
3914
+ let authUrl = tryExtractOpenAiCodexAuthorizeUrl(cleanedForUrl);
3915
+ // Layer 2: try the raw combined buffer in case stripAnsi dropped a character that
3916
+ // broke the URL detection (raw ANSI seqs don't include space so regex still works).
3917
+ if (!authUrl) {
3918
+ const rawCleaned = combined.replace(/\r/g, "")
3919
+ .replace(/([A-Za-z0-9%&=+?#:/@._~!$'()*,;-])\n([A-Za-z0-9%&=+?#:/@._~!$'()*,;-])/g, "$1$2");
3920
+ authUrl = tryExtractOpenAiCodexAuthorizeUrl(rawCleaned);
3921
+ }
3922
+ if (!authUrl) return;
3923
+ // Strip any trailing ANSI remnants (e.g. \x1b[0m appended by colour reset)
3924
+ authUrl = stripAnsi(authUrl).replace(/\r/g, "").trim();
3885
3925
  if (!authUrl.startsWith("https://")) return;
3886
3926
  clearTimeout(urlTimeout);
3887
3927
  responded = true;
@@ -3944,7 +3984,7 @@ async function cmdInstall(args) {
3944
3984
  pending.status = "failed";
3945
3985
  pending.message =
3946
3986
  "OpenClaw exited OK but no auth tokens were saved. " +
3947
- "Run 'openclaw models auth login --provider openai-codex' in a terminal, " +
3987
+ "Run 'openclaw models auth login --provider openai-codex --method oauth' in a terminal, " +
3948
3988
  "then re-run the wizard with the already-logged-in option.";
3949
3989
  } else {
3950
3990
  pending.status = "failed";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "traderclaw-cli",
3
- "version": "1.0.114",
3
+ "version": "1.0.116",
4
4
  "description": "Global TraderClaw CLI (install --wizard, setup, precheck). Installs solana-traderclaw as a dependency for OpenClaw plugin files.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -17,7 +17,7 @@
17
17
  "node": ">=22"
18
18
  },
19
19
  "dependencies": {
20
- "solana-traderclaw": "^1.0.114"
20
+ "solana-traderclaw": "^1.0.116"
21
21
  },
22
22
  "keywords": [
23
23
  "traderclaw",