codex-multi-auth 2.8.6 → 2.9.0

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 (48) hide show
  1. package/.codex-plugin/plugin.json +1 -1
  2. package/README.md +1 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +34 -0
  5. package/dist/lib/account-policy.d.ts +3 -1
  6. package/dist/lib/account-policy.d.ts.map +1 -1
  7. package/dist/lib/account-policy.js +14 -1
  8. package/dist/lib/codex-manager/login-flow.js +7 -0
  9. package/dist/lib/codex-manager/login-menu-actions.d.ts.map +1 -1
  10. package/dist/lib/codex-manager/login-menu-actions.js +7 -1
  11. package/dist/lib/policy/runtime-policy.d.ts +7 -0
  12. package/dist/lib/policy/runtime-policy.d.ts.map +1 -1
  13. package/dist/lib/policy/runtime-policy.js +1 -0
  14. package/dist/lib/request/fetch-helpers.d.ts +7 -0
  15. package/dist/lib/request/fetch-helpers.d.ts.map +1 -1
  16. package/dist/lib/request/fetch-helpers.js +1 -1
  17. package/dist/lib/request/rate-limit-decision.d.ts +27 -0
  18. package/dist/lib/request/rate-limit-decision.d.ts.map +1 -1
  19. package/dist/lib/request/rate-limit-decision.js +117 -2
  20. package/dist/lib/request/response-handler.d.ts +3 -1
  21. package/dist/lib/request/response-handler.d.ts.map +1 -1
  22. package/dist/lib/request/response-handler.js +26 -5
  23. package/dist/lib/request/stream-failover-runtime.d.ts +8 -1
  24. package/dist/lib/request/stream-failover-runtime.d.ts.map +1 -1
  25. package/dist/lib/request/stream-failover-runtime.js +9 -1
  26. package/dist/lib/request/stream-failover.d.ts.map +1 -1
  27. package/dist/lib/request/stream-failover.js +41 -0
  28. package/dist/lib/runtime/account-check.d.ts.map +1 -1
  29. package/dist/lib/runtime/account-check.js +8 -1
  30. package/dist/lib/runtime/account-status.d.ts +39 -10
  31. package/dist/lib/runtime/account-status.d.ts.map +1 -1
  32. package/dist/lib/runtime/account-status.js +47 -42
  33. package/dist/lib/runtime-rotation-proxy.d.ts.map +1 -1
  34. package/dist/lib/runtime-rotation-proxy.js +73 -8
  35. package/dist/lib/storage.d.ts +19 -0
  36. package/dist/lib/storage.d.ts.map +1 -1
  37. package/dist/lib/storage.js +32 -0
  38. package/dist/lib/usage/index.d.ts +2 -0
  39. package/dist/lib/usage/index.d.ts.map +1 -1
  40. package/dist/lib/usage/index.js +2 -0
  41. package/dist/lib/usage/stream-usage-deferral.d.ts +39 -0
  42. package/dist/lib/usage/stream-usage-deferral.d.ts.map +1 -0
  43. package/dist/lib/usage/stream-usage-deferral.js +54 -0
  44. package/dist/lib/usage/usage-extraction.d.ts +42 -0
  45. package/dist/lib/usage/usage-extraction.d.ts.map +1 -0
  46. package/dist/lib/usage/usage-extraction.js +178 -0
  47. package/package.json +1 -1
  48. package/scripts/codex.js +300 -82
package/scripts/codex.js CHANGED
@@ -421,6 +421,14 @@ function extractForcedAccountFlag(args) {
421
421
  let sawFlag = false;
422
422
  for (let index = 0; index < args.length; index += 1) {
423
423
  const arg = args[index];
424
+ // `--` ends option parsing: everything after it is Codex's root
425
+ // `[PROMPT]` text. A `--account` spelled in there is the user's prompt,
426
+ // not a launcher flag — stripping it would both mangle the prompt and
427
+ // silently pin the run to an account nobody selected.
428
+ if (arg === "--") {
429
+ strippedArgs.push(...args.slice(index));
430
+ break;
431
+ }
424
432
  if (arg === "--account") {
425
433
  sawFlag = true;
426
434
  const next = args[index + 1];
@@ -1365,6 +1373,9 @@ function replaceRequestedModel(args, nextModel) {
1365
1373
  const nextArgs = [...args];
1366
1374
  for (let i = 0; i < nextArgs.length; i += 1) {
1367
1375
  const arg = nextArgs[i];
1376
+ // Past `--` the tokens are the user's prompt. Rewriting one in place
1377
+ // would edit the prompt text itself before re-forwarding it.
1378
+ if (arg === "--") break;
1368
1379
  if ((arg === "--model" || arg === "-m") && typeof nextArgs[i + 1] === "string") {
1369
1380
  nextArgs[i + 1] = nextModel;
1370
1381
  return nextArgs;
@@ -1859,6 +1870,11 @@ async function forwardToRealCodex(codexBin, rawArgs, baseEnv = process.env) {
1859
1870
  function hasCliAuthCredentialsStoreOverride(args) {
1860
1871
  for (let i = 0; i < args.length; i += 1) {
1861
1872
  const arg = args[i];
1873
+ // Everything after `--` is the root `[PROMPT]` positional, not options:
1874
+ // a prompt whose text spells `--config=cli_auth_credentials_store=...` is
1875
+ // not a caller override, and treating it as one would silently drop the
1876
+ // file auth store this wrapper depends on.
1877
+ if (arg === "--") break;
1862
1878
  if (arg === "-c" || arg === "--config") {
1863
1879
  const next = args[i + 1];
1864
1880
  if (!next || !next.includes("=")) continue;
@@ -2357,6 +2373,10 @@ function coerceReasoningEffortForModel(model, effort) {
2357
2373
  function extractRequestedModel(args) {
2358
2374
  for (let i = 0; i < args.length; i += 1) {
2359
2375
  const arg = args[i];
2376
+ // Past `--` every token is root `[PROMPT]` text; a `-m` in there names
2377
+ // no model, and reading one would coerce reasoning config for a model
2378
+ // the user never requested.
2379
+ if (arg === "--") break;
2360
2380
  if (arg === "--model" || arg === "-m") {
2361
2381
  const next = args[i + 1];
2362
2382
  if (typeof next === "string" && next.trim().length > 0) {
@@ -2427,6 +2447,8 @@ function rewriteReasoningConfigArgs(rawArgs) {
2427
2447
  const nextArgs = [...rawArgs];
2428
2448
  for (let i = 0; i < nextArgs.length; i += 1) {
2429
2449
  const arg = nextArgs[i];
2450
+ // Past `--` a `-c key=value` pair is prompt text, not a config override.
2451
+ if (arg === "--") break;
2430
2452
  if ((arg === "-c" || arg === "--config") && typeof nextArgs[i + 1] === "string") {
2431
2453
  nextArgs[i + 1] = rewriteReasoningConfigAssignment(
2432
2454
  nextArgs[i + 1],
@@ -4903,13 +4925,20 @@ async function createRuntimeRotationAppHelperContext(
4903
4925
  }
4904
4926
  };
4905
4927
 
4928
+ const injectedArgs = [
4929
+ ...helperArgs,
4930
+ "-c",
4931
+ `model_provider=${configTomlModule.tomlStringLiteral(RUNTIME_ROTATION_PROXY_PROVIDER_ID)}`,
4932
+ ];
4906
4933
  return {
4907
- args: [
4908
- ...baseContext.args,
4909
- ...helperArgs,
4910
- "-c",
4911
- `model_provider=${configTomlModule.tomlStringLiteral(RUNTIME_ROTATION_PROXY_PROVIDER_ID)}`,
4912
- ],
4934
+ // Root TUI argv can end in the optional `[PROMPT]` positional, and `--`
4935
+ // binds everything after it to that positional — overrides appended
4936
+ // there would become prompt text, so the interactive branch asks for
4937
+ // them to be injected ahead of the prompt instead.
4938
+ args:
4939
+ options.injectArgsBeforeRootPrompt === true
4940
+ ? insertArgsBeforeRootPrompt(baseContext.args, injectedArgs)
4941
+ : insertArgsBeforeForwardedSeparator(baseContext.args, injectedArgs),
4913
4942
  env: {
4914
4943
  ...baseContext.env,
4915
4944
  ...helperEnv,
@@ -4991,13 +5020,19 @@ async function createRuntimeRotationProxyContextIfEnabled(
4991
5020
  if (isCodexAppCommand(rawArgs)) {
4992
5021
  return startAppHelperContext();
4993
5022
  }
4994
- if (
4995
- isCodexInteractiveTuiCommand(rawArgs) ||
4996
- isCodexInteractiveResumeCommand(rawArgs)
4997
- ) {
5023
+ // Classify once: each predicate re-walks the whole argv, and the root-TUI
5024
+ // answer is needed twice below.
5025
+ const isRootTuiLaunch = isCodexInteractiveTuiCommand(rawArgs);
5026
+ if (isRootTuiLaunch || isCodexInteractiveResumeCommand(rawArgs)) {
4998
5027
  return startAppHelperContext({
4999
5028
  detachOnExit: true,
5000
5029
  useCanonicalHome: true,
5030
+ // Root TUI launches may carry the optional `[PROMPT]` positional
5031
+ // (possibly forced by `--`); the provider overrides must stay on the
5032
+ // option side of it. `resume`/`fork` keep the appended ordering their
5033
+ // argv has always forwarded with — their tokens are subcommand args,
5034
+ // not the root prompt.
5035
+ injectArgsBeforeRootPrompt: isRootTuiLaunch,
5001
5036
  });
5002
5037
  }
5003
5038
 
@@ -5088,90 +5123,257 @@ function isPureHelpOrVersionArgs(rawArgs) {
5088
5123
  );
5089
5124
  }
5090
5125
 
5126
+ // Hoisted: every argv walk calls consumesNextArg once per token, and a Set
5127
+ // rebuilt per call allocated this list on every one of them.
5128
+ const OPTIONS_CONSUMING_NEXT_ARG = new Set([
5129
+ "-c",
5130
+ "--config",
5131
+ "--enable",
5132
+ "--disable",
5133
+ "--listen",
5134
+ "--remote",
5135
+ "--remote-auth-token-env",
5136
+ "--ws-auth",
5137
+ "--ws-token-file",
5138
+ "--ws-token-sha256",
5139
+ "--ws-shared-secret-file",
5140
+ "--ws-issuer",
5141
+ "--ws-audience",
5142
+ "--ws-max-clock-skew-seconds",
5143
+ "--download-url",
5144
+ "-i",
5145
+ "--image",
5146
+ "-m",
5147
+ "--model",
5148
+ "--local-provider",
5149
+ "-p",
5150
+ "--profile",
5151
+ "-s",
5152
+ "--sandbox",
5153
+ "-a",
5154
+ "--ask-for-approval",
5155
+ "-C",
5156
+ "--cd",
5157
+ "--add-dir",
5158
+ "--output-schema",
5159
+ "--color",
5160
+ "-o",
5161
+ "--output-last-message",
5162
+ ]);
5163
+
5091
5164
  function consumesNextArg(arg) {
5092
- return new Set([
5093
- "-c",
5094
- "--config",
5095
- "--enable",
5096
- "--disable",
5097
- "--listen",
5098
- "--remote",
5099
- "--remote-auth-token-env",
5100
- "--ws-auth",
5101
- "--ws-token-file",
5102
- "--ws-token-sha256",
5103
- "--ws-shared-secret-file",
5104
- "--ws-issuer",
5105
- "--ws-audience",
5106
- "--ws-max-clock-skew-seconds",
5107
- "--download-url",
5108
- "-i",
5109
- "--image",
5110
- "-m",
5111
- "--model",
5112
- "--local-provider",
5113
- "-p",
5114
- "--profile",
5115
- "-s",
5116
- "--sandbox",
5117
- "-a",
5118
- "--ask-for-approval",
5119
- "-C",
5120
- "--cd",
5121
- "--add-dir",
5122
- "--output-schema",
5123
- "--color",
5124
- "-o",
5125
- "--output-last-message",
5126
- ]).has(arg);
5165
+ return OPTIONS_CONSUMING_NEXT_ARG.has(arg);
5127
5166
  }
5128
5167
 
5129
- function findForwardedCommand(rawArgs) {
5130
- if (!Array.isArray(rawArgs) || rawArgs.length === 0) {
5131
- return null;
5168
+ // Codex's root grammar is `codex [OPTIONS] [PROMPT]` / `codex [OPTIONS]
5169
+ // <COMMAND> [ARGS]`, so the first positional is only a command when it names a
5170
+ // real root subcommand — otherwise it is the optional initial prompt of an
5171
+ // interactive TUI launch. The allowlist mirrors `codex --help`; treating an
5172
+ // unknown positional as a prompt matches native Codex, where an unrecognized
5173
+ // token also falls through to the prompt positional rather than erroring as a
5174
+ // bad subcommand. Routing predicates all resolve through this map so aliases
5175
+ // classify like their canonical command.
5176
+ //
5177
+ // A real root subcommand missing from this set is misrouted, not merely
5178
+ // misnamed: it classifies as an interactive prompt and takes the app-helper
5179
+ // branch with `detachOnExit: true`, so a short-lived command leaves a detached
5180
+ // helper and its loopback proxy idling until the rotation idle timeout. Keep
5181
+ // the set in sync with the upstream grammar — clap publishes the authoritative
5182
+ // root list in its own completions, so
5183
+ // codex completion bash | grep -oE 'opts="[^"]*"' | grep ' exec '
5184
+ // prints every root command (and alias) for the installed codex-cli.
5185
+
5186
+ const CODEX_ROOT_COMMAND_ALIASES = new Map([
5187
+ ["e", "exec"],
5188
+ ["a", "apply"],
5189
+ ]);
5190
+ const CODEX_ROOT_COMMANDS = new Set([
5191
+ "exec",
5192
+ "review",
5193
+ "login",
5194
+ "logout",
5195
+ "mcp",
5196
+ "plugin",
5197
+ "mcp-server",
5198
+ "app-server",
5199
+ "remote-control",
5200
+ "app",
5201
+ "completion",
5202
+ "update",
5203
+ "doctor",
5204
+ "sandbox",
5205
+ "debug",
5206
+ "apply",
5207
+ "resume",
5208
+ "archive",
5209
+ "delete",
5210
+ "migrate-rollouts",
5211
+ "unarchive",
5212
+ "fork",
5213
+ "cloud",
5214
+ "exec-server",
5215
+ "features",
5216
+ "help",
5217
+ "auth",
5218
+ // Hidden root subcommands: absent from `codex --help`, but real — each is
5219
+ // documented by `codex help <name>`.
5220
+ "responses-api-proxy",
5221
+ "cloud-tasks",
5222
+ "execpolicy",
5223
+ // Internal stdio/UDS relay. Hidden like the three above, and short-lived:
5224
+ // omitting it classified `codex stdio-to-uds <socket>` as a root prompt,
5225
+ // which took the detached app-helper branch and leaked a helper per call.
5226
+ "stdio-to-uds",
5227
+ ]);
5228
+
5229
+ function resolveCodexRootCommand(token) {
5230
+ const command = CODEX_ROOT_COMMAND_ALIASES.get(token) ?? token;
5231
+ return CODEX_ROOT_COMMANDS.has(command) ? command : null;
5232
+ }
5233
+
5234
+ // `-i/--image` is greedy (`<FILE>...`): native Codex consumes every following
5235
+ // free token up to the next option-like token, so a prompt can only follow the
5236
+ // image list after another option or a `--`. Every argv walker below skips the
5237
+ // same span, or the wrapper would disagree with native Codex about where the
5238
+ // positional side starts.
5239
+ function consumesRemainingFreeArgs(arg) {
5240
+ return arg === "-i" || arg === "--image";
5241
+ }
5242
+
5243
+ function skipOptionValueSpan(args, i) {
5244
+ const arg = args[i];
5245
+ if (consumesRemainingFreeArgs(arg)) {
5246
+ let end = i;
5247
+ while (
5248
+ end + 1 < args.length &&
5249
+ typeof args[end + 1] === "string" &&
5250
+ args[end + 1].length > 0 &&
5251
+ (args[end + 1] === "-" || !args[end + 1].startsWith("-"))
5252
+ ) {
5253
+ end += 1;
5254
+ }
5255
+ return end;
5132
5256
  }
5133
- for (let i = 0; i < rawArgs.length; i += 1) {
5134
- const arg = rawArgs[i];
5257
+ return consumesNextArg(arg) ? i + 1 : i;
5258
+ }
5259
+
5260
+ /**
5261
+ * The single definition of where an argv's option side ends. Walking from
5262
+ * `startIndex`, skips option flags and the values they consume — including a
5263
+ * greedy `-i a.png b.png` span — and reports what stopped the walk:
5264
+ *
5265
+ * - `index`: the first free (positional) token, or null when there is none.
5266
+ * - `terminatorIndex`: the bare `--` that ended option parsing, or null.
5267
+ * - `boundary`: where option-side content ends, i.e. the positional, the
5268
+ * `--`, or `args.length`. This is where injected overrides belong.
5269
+ *
5270
+ * Callers keep their own policy for `--` (the root grammar binds everything
5271
+ * after it to `[PROMPT]`; a subcommand's does not), but they must not keep
5272
+ * their own copy of the walk: a classifier and an injector that disagree by
5273
+ * one token put a `-c` override into prompt text or read prompt text as a
5274
+ * subcommand.
5275
+ */
5276
+ function findRootPositional(args, startIndex = 0) {
5277
+ if (!Array.isArray(args)) {
5278
+ return { index: null, terminatorIndex: null, boundary: 0 };
5279
+ }
5280
+ for (let i = startIndex; i < args.length; i += 1) {
5281
+ const arg = args[i];
5135
5282
  if (typeof arg !== "string" || arg.length === 0) continue;
5136
5283
  if (arg === "--") {
5137
- return i + 1 < rawArgs.length
5138
- ? { command: rawArgs[i + 1], index: i + 1 }
5139
- : null;
5284
+ return { index: null, terminatorIndex: i, boundary: i };
5140
5285
  }
5141
5286
  if (arg.startsWith("--config=")) {
5142
5287
  continue;
5143
5288
  }
5144
5289
  if (arg.startsWith("--") || (arg.startsWith("-") && arg !== "-")) {
5145
- if (consumesNextArg(arg)) {
5146
- i += 1;
5147
- }
5290
+ i = skipOptionValueSpan(args, i);
5148
5291
  continue;
5149
5292
  }
5150
- return { command: arg, index: i };
5293
+ return { index: i, terminatorIndex: null, boundary: i };
5294
+ }
5295
+ return { index: null, terminatorIndex: null, boundary: args.length };
5296
+ }
5297
+
5298
+ function findForwardedCommand(rawArgs) {
5299
+ if (!Array.isArray(rawArgs) || rawArgs.length === 0) {
5300
+ return null;
5301
+ }
5302
+ // `--` ends option parsing: everything after it binds to the root
5303
+ // `[PROMPT]` positional, never to a subcommand, even when the text happens
5304
+ // to spell a command name. `findRootPositional` reports it as a terminator
5305
+ // and yields no positional, which settles the launch as interactive.
5306
+ //
5307
+ // Native Codex fills the root `[PROMPT]` slot with the first free token and
5308
+ // still tries a later one as a subcommand (`codex hello exec …` runs exec),
5309
+ // so an unknown positional keeps the scan going.
5310
+ for (
5311
+ let cursor = findRootPositional(rawArgs, 0);
5312
+ cursor.index !== null;
5313
+ cursor = findRootPositional(rawArgs, cursor.index + 1)
5314
+ ) {
5315
+ const command = resolveCodexRootCommand(rawArgs[cursor.index]);
5316
+ if (command !== null) {
5317
+ return { command, index: cursor.index };
5318
+ }
5151
5319
  }
5152
5320
 
5153
5321
  return null;
5154
5322
  }
5155
5323
 
5324
+ // Inserts option-side args ahead of the root `[PROMPT]` positional (or the
5325
+ // `--` that forces one), so injected overrides cannot be read as prompt text.
5326
+ // With no positional at all this is a plain append, which keeps bare-TUI argv
5327
+ // byte-identical to the pre-insertion shape.
5328
+ function insertArgsBeforeRootPrompt(baseArgs, injectedArgs) {
5329
+ const { boundary } = findRootPositional(baseArgs);
5330
+ return [
5331
+ ...baseArgs.slice(0, boundary),
5332
+ ...injectedArgs,
5333
+ ...baseArgs.slice(boundary),
5334
+ ];
5335
+ }
5336
+
5337
+ // Inserts args before a `--` separator when one is present, else appends.
5338
+ // Subcommand argv keeps its leading subcommand token — `resume`/`fork` argv is
5339
+ // pinned to it — but anything appended past a `--` lands in the subcommand's
5340
+ // own positional list: Codex rejects that outright for `exec`/`review`
5341
+ // ("unexpected argument '-c' found"), and worse, silently forwards it as
5342
+ // arguments for `sandbox` and into the stored config for `mcp add`. The
5343
+ // separator bounds the append.
5344
+ function insertArgsBeforeForwardedSeparator(baseArgs, injectedArgs) {
5345
+ // Deliberately not `findRootPositional`: that reports where the option side
5346
+ // ends, stopping at the first positional, and a subcommand's own arguments
5347
+ // are positionals — it would answer `exec` for `exec -- hi`. The question
5348
+ // here is only where the separator sits, and a bare `indexOf` answers it
5349
+ // exactly: clap never consumes `--` as an option value (`codex --cd -- hi`
5350
+ // is "a value is required for '--cd'"), so the first `--` is always the
5351
+ // separator, and it always follows the subcommand token because
5352
+ // `findForwardedCommand` returns null the moment it sees one.
5353
+ const separatorIndex = baseArgs.indexOf("--");
5354
+ if (separatorIndex === -1) {
5355
+ return [...baseArgs, ...injectedArgs];
5356
+ }
5357
+ return [
5358
+ ...baseArgs.slice(0, separatorIndex),
5359
+ ...injectedArgs,
5360
+ ...baseArgs.slice(separatorIndex),
5361
+ ];
5362
+ }
5363
+
5156
5364
  function findForwardedSubcommand(rawArgs, commandIndex) {
5157
- for (let i = commandIndex + 1; i < rawArgs.length; i += 1) {
5158
- const arg = rawArgs[i];
5159
- if (typeof arg !== "string" || arg.length === 0) continue;
5160
- if (arg === "--") {
5161
- return i + 1 < rawArgs.length ? rawArgs[i + 1] : null;
5162
- }
5163
- if (arg.startsWith("--config=")) {
5164
- continue;
5165
- }
5166
- if (arg.startsWith("--") || (arg.startsWith("-") && arg !== "-")) {
5167
- if (consumesNextArg(arg)) {
5168
- i += 1;
5169
- }
5170
- continue;
5171
- }
5172
- return arg;
5365
+ const { index, terminatorIndex } = findRootPositional(
5366
+ rawArgs,
5367
+ commandIndex + 1,
5368
+ );
5369
+ // Unlike the root grammar, a subcommand's `--` still precedes its own
5370
+ // positional args, so the token after it is the nested subcommand.
5371
+ if (terminatorIndex !== null) {
5372
+ return terminatorIndex + 1 < rawArgs.length
5373
+ ? rawArgs[terminatorIndex + 1]
5374
+ : null;
5173
5375
  }
5174
- return null;
5376
+ return index === null ? null : rawArgs[index];
5175
5377
  }
5176
5378
 
5177
5379
  function hasHelpFlagAfterCommand(rawArgs, commandIndex) {
@@ -5179,8 +5381,8 @@ function hasHelpFlagAfterCommand(rawArgs, commandIndex) {
5179
5381
  const arg = rawArgs[i];
5180
5382
  if (arg === "--") return false;
5181
5383
  if (arg === "--help" || arg === "-h" || arg === "help") return true;
5182
- if (typeof arg === "string" && consumesNextArg(arg)) {
5183
- i += 1;
5384
+ if (typeof arg === "string") {
5385
+ i = skipOptionValueSpan(rawArgs, i);
5184
5386
  }
5185
5387
  }
5186
5388
  return false;
@@ -5194,6 +5396,11 @@ function isCodexAppServerCommand(rawArgs) {
5194
5396
  return findForwardedCommand(rawArgs)?.command === "app-server";
5195
5397
  }
5196
5398
 
5399
+ // True for every root TUI launch: bare `codex [OPTIONS]`, and `codex
5400
+ // [OPTIONS] [PROMPT]` with the optional initial prompt — including a prompt
5401
+ // forced by `--`. Both shapes start the same interactive session and need the
5402
+ // canonical home, or Codex stalls rebuilding the omitted thread index inside
5403
+ // the shadow mirror before it can submit the already-delivered prompt.
5197
5404
  function isCodexInteractiveTuiCommand(rawArgs) {
5198
5405
  return findForwardedCommand(rawArgs) === null;
5199
5406
  }
@@ -5219,7 +5426,14 @@ function shouldUseRuntimeRoutingForForwardedArgs(rawArgs) {
5219
5426
 
5220
5427
  const command = findForwardedCommand(rawArgs);
5221
5428
  if (!command) {
5222
- return true;
5429
+ // A help flag alongside a root prompt (`codex "prompt" --help`) prints
5430
+ // help and exits clean, so it must skip the transport for the same
5431
+ // reason as the request-command help forms below: the interactive
5432
+ // branch detaches its helper on a clean exit, and a helper started
5433
+ // just to print help would idle until its detached timeout. The scan
5434
+ // stops at `--`, so help-looking text inside a forced prompt still
5435
+ // routes normally.
5436
+ return !hasHelpFlagAfterCommand(rawArgs, -1);
5223
5437
  }
5224
5438
 
5225
5439
  const requestCommands = new Set(["exec", "review", "resume", "fork", "app"]);
@@ -5450,12 +5664,16 @@ function buildForwardArgs(rawArgs) {
5450
5664
  return { args: compatibilityArgs, requestedModel };
5451
5665
  }
5452
5666
 
5667
+ const authStoreArgs = ["-c", 'cli_auth_credentials_store="file"'];
5453
5668
  return {
5454
- args: [
5455
- ...compatibilityArgs,
5456
- "-c",
5457
- 'cli_auth_credentials_store="file"',
5458
- ],
5669
+ // A root launch may end in the `[PROMPT]` positional — possibly forced
5670
+ // by `--`, where an appended `-c` pair would be read as prompt text —
5671
+ // so the override is inserted on the option side of the prompt there.
5672
+ // Subcommand argv keeps the appended ordering it has always forwarded.
5673
+ args:
5674
+ findForwardedCommand(compatibilityArgs) === null
5675
+ ? insertArgsBeforeRootPrompt(compatibilityArgs, authStoreArgs)
5676
+ : insertArgsBeforeForwardedSeparator(compatibilityArgs, authStoreArgs),
5459
5677
  requestedModel,
5460
5678
  };
5461
5679
  }