@youdie006/prodex 0.2.0 → 0.3.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.
package/dist/cli.js CHANGED
@@ -11,8 +11,8 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
11
11
  import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
12
12
  import { renderBanner, shouldColorize } from "./banner.js";
13
13
  import { buildDryRunBundle } from "./bundle.js";
14
- import { chatGptVisibilityBlocker, defaultChatGptProfileDir, getChatGptBrowserStatus, normalizeChatGptTargetUrl, openChatGptBrowser, sendChatGptPrompt } from "./chatgpt-browser.js";
15
- import { getTokenExpiryStatus, loadLocalConfig, writeLocalConfig } from "./config.js";
14
+ import { chatGptVisibilityBlocker, defaultChatGptProfileDir, getChatGptBrowserStatus, normalizeChatGptTargetUrl, openChatGptBrowser, parseProMode, parseReasoningEffort, sendChatGptPrompt } from "./chatgpt-browser.js";
15
+ import { getTokenExpiryStatus, loadBrowserDefaults, loadLocalConfig, writeLocalConfig } from "./config.js";
16
16
  import { startHttpMcpServer } from "./http-mcp.js";
17
17
  import { createMcpToolHandlers } from "./mcp-tools.js";
18
18
  import { runMcpServer } from "./mcp.js";
@@ -92,20 +92,26 @@ export async function runCli(args, io = defaultIo()) {
92
92
  return 0;
93
93
  }
94
94
  if (command === "setup") {
95
- if (printHelpIfRequested(rest, "setup", io.stdout, printSetupHelp, { valueFlags: ["--cwd", "--host", "--port", "--token", "--token-ttl-hours"] }))
95
+ const setupValueFlags = ["--cwd", "--host", "--port", "--token", "--token-ttl-hours", ...ASK_PRO_SELECTION_DEFAULT_FLAGS];
96
+ if (printHelpIfRequested(rest, "setup", io.stdout, printSetupHelp, { valueFlags: setupValueFlags }))
96
97
  return 0;
97
- assertOnlyOptions(rest, "setup", ["--cwd", "--host", "--port", "--token", "--token-ttl-hours"]);
98
+ assertOnlyOptions(rest, "setup", setupValueFlags);
98
99
  const targetCwd = resolveCwdFlag(io.cwd, rest);
100
+ const browserDefaults = parseBrowserDefaultFlags(rest);
99
101
  const config = await writeLocalConfig(targetCwd, {
100
102
  host: readFlag(rest, "--host") ?? "127.0.0.1",
101
103
  port: readPortFlag(rest, "--port") ?? 8787,
102
104
  token: readFlag(rest, "--token"),
103
- tokenTtlHours: readPositiveNumberFlag(rest, "--token-ttl-hours")
105
+ tokenTtlHours: readPositiveNumberFlag(rest, "--token-ttl-hours"),
106
+ browserDefaults
104
107
  });
105
108
  io.stdout("Saved local ChatGPT Developer Mode MCP profile.");
106
109
  io.stdout(`Server URL: ${redactServerUrl(config.server_url)}`);
107
110
  io.stdout(formatTokenExpiryLine(config));
108
111
  io.stdout("Full URL is stored in .bridge/config.local.json.");
112
+ if (config.browser_defaults) {
113
+ io.stdout(`Browser send defaults: ${formatBrowserDefaults(config.browser_defaults)}`);
114
+ }
109
115
  return 0;
110
116
  }
111
117
  if (command === "start") {
@@ -909,6 +915,38 @@ export async function runCli(args, io = defaultIo()) {
909
915
  const prompt = parsedAskPro.promptParts.join(" ").trim();
910
916
  if (!prompt)
911
917
  throw new Error("ask-pro requires a prompt");
918
+ const browserDefaults = await loadBrowserDefaults(targetCwd);
919
+ const explicitProject = readFlag(parsedAskPro.optionArgs, "--project");
920
+ const explicitProjectNew = readFlag(parsedAskPro.optionArgs, "--project-new");
921
+ if (explicitProject !== undefined && explicitProjectNew !== undefined) {
922
+ throw new Error("ask-pro cannot combine --project and --project-new; pick an existing project or create one.");
923
+ }
924
+ if (explicitProjectNew !== undefined) {
925
+ // Creating a project mutates the real ChatGPT account and the modal
926
+ // automation is unverified, so this stays gated until it is confirmed live.
927
+ throw new Error('--project-new is not supported yet; create the project in ChatGPT, then use --project "name".');
928
+ }
929
+ const explicitModel = readFlag(parsedAskPro.optionArgs, "--model");
930
+ const explicitProModeRaw = readFlag(parsedAskPro.optionArgs, "--pro-mode");
931
+ const explicitEffortRaw = readFlag(parsedAskPro.optionArgs, "--effort");
932
+ if (explicitProModeRaw !== undefined && explicitEffortRaw !== undefined) {
933
+ throw new Error("ask-pro cannot combine --pro-mode and --effort; Pro sub-modes and reasoning effort are different model axes.");
934
+ }
935
+ const explicitProMode = explicitProModeRaw === undefined ? undefined : parseProMode(explicitProModeRaw);
936
+ const explicitEffort = explicitEffortRaw === undefined ? undefined : parseReasoningEffort(explicitEffortRaw);
937
+ // Explicit per-ask flags override persisted defaults. Choosing either
938
+ // reasoning axis explicitly suppresses the default for the other axis.
939
+ const selectionModel = explicitModel ?? browserDefaults?.model;
940
+ const selectionProject = explicitProject ?? browserDefaults?.project;
941
+ const reasoningAxisChosen = explicitProMode !== undefined || explicitEffort !== undefined;
942
+ const selectionProMode = explicitProMode ?? (reasoningAxisChosen ? undefined : browserDefaults?.pro_mode);
943
+ const selectionEffort = explicitEffort ?? (reasoningAxisChosen ? undefined : browserDefaults?.effort);
944
+ const selectionMetadata = {
945
+ ...(selectionProject ? { project: selectionProject } : {}),
946
+ ...(selectionModel ? { model: selectionModel } : {}),
947
+ ...(selectionProMode ? { pro_mode: selectionProMode } : {}),
948
+ ...(selectionEffort ? { effort: selectionEffort } : {})
949
+ };
912
950
  const browserPort = hasSendMode ? (readPortFlag(parsedAskPro.optionArgs, "--port") ?? 9333) : undefined;
913
951
  const browserTimeoutMs = hasSendMode ? (readPositiveNumberFlag(parsedAskPro.optionArgs, "--timeout-ms") ?? 90000) : undefined;
914
952
  const sourceCli = resolveOptionalFileFlag(io.cwd, parsedAskPro.optionArgs, "--source-cli");
@@ -969,7 +1007,11 @@ export async function runCli(args, io = defaultIo()) {
969
1007
  port: browserPort,
970
1008
  prompt: bundle.text,
971
1009
  targetUrl: normalizedTargetUrl,
972
- timeoutMs: browserTimeoutMs
1010
+ timeoutMs: browserTimeoutMs,
1011
+ project: selectionProject,
1012
+ model: selectionModel,
1013
+ proMode: selectionProMode,
1014
+ effort: selectionEffort
973
1015
  });
974
1016
  }
975
1017
  catch (error) {
@@ -1026,6 +1068,7 @@ export async function runCli(args, io = defaultIo()) {
1026
1068
  metadata: {
1027
1069
  ...(answerArtifactPath ? { artifact_path: answerArtifactPath } : {}),
1028
1070
  thread: consult.url,
1071
+ ...(Object.keys(selectionMetadata).length > 0 ? { selection: selectionMetadata } : {}),
1029
1072
  warnings: persistenceWarnings
1030
1073
  }
1031
1074
  });
@@ -1109,7 +1152,7 @@ Commands:
1109
1152
  prodex --version
1110
1153
  prodex init [--cwd /absolute/path/to/repo]
1111
1154
  prodex doctor [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js]
1112
- prodex setup [--cwd /absolute/path/to/repo] [--host 127.0.0.1] [--port 8787] [--token-ttl-hours <hours>]
1155
+ prodex setup [--cwd /absolute/path/to/repo] [--host 127.0.0.1] [--port 8787] [--token-ttl-hours <hours>] [--model Pro] [--pro-mode 기본|확장] [--effort 즉시|중간|높음|"매우 높음"] [--project "name"]
1113
1156
  prodex start [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js]
1114
1157
  prodex status [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js] [--show-token] [--url-only] [--unsafe-show-non-expiring-token]
1115
1158
  prodex tunnel url [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js] --public-url https://... [--show-token] [--url-only]
@@ -1124,7 +1167,7 @@ Commands:
1124
1167
  prodex pro browser help [--source-cli /absolute/path/to/dist/cli.js]
1125
1168
  prodex pro browser check [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 1500]
1126
1169
  prodex pro browser smoke [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 90000]
1127
- prodex pro browser ask [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 90000] [--target-url url --confirm-target] [--file path] "prompt" # explicit visible-browser send
1170
+ prodex pro browser ask [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 90000] [--target-url url --confirm-target] [--file path] [--model Pro] [--pro-mode 기본|확장] [--effort 즉시|중간|높음|"매우 높음"] [--project "name"] "prompt" # explicit visible-browser send
1128
1171
  prodex pro latest [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo]
1129
1172
  prodex pro list [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo]
1130
1173
  prodex pro show <task-id|latest> [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo]
@@ -1155,9 +1198,16 @@ function printSetupHelp(stdout) {
1155
1198
  stdout(`prodex setup
1156
1199
 
1157
1200
  Commands:
1158
- prodex setup [--cwd /absolute/path/to/repo] [--host 127.0.0.1] [--port 8787] [--token-ttl-hours <hours>]
1201
+ prodex setup [--cwd /absolute/path/to/repo] [--host 127.0.0.1] [--port 8787] [--token-ttl-hours <hours>] [--model Pro] [--pro-mode 기본|확장] [--effort 즉시|중간|높음|"매우 높음"] [--project "name"]
1202
+
1203
+ Save a loopback-only HTTP MCP profile in .bridge/config.local.json. Use --token-ttl-hours before tunnels or ChatGPT Project use.
1159
1204
 
1160
- Save a loopback-only HTTP MCP profile in .bridge/config.local.json. Use --token-ttl-hours before tunnels or ChatGPT Project use.`);
1205
+ Optional visible-browser send defaults (applied by \`pro browser ask\` when the matching per-ask flag is omitted):
1206
+ --model Composer model to pick, e.g. Pro or GPT-5.5
1207
+ --pro-mode Pro sub-mode: 기본 (standard) or 확장 (extended)
1208
+ --effort Reasoning effort for non-Pro models: 즉시 / 중간 / 높음 / 매우 높음 (English aliases: instant/medium/high/max)
1209
+ --project Sidebar project to enter before sending
1210
+ --pro-mode and --effort are different model axes and cannot be combined.`);
1161
1211
  }
1162
1212
  function printStartHelp(stdout) {
1163
1213
  stdout(`prodex start
@@ -1233,13 +1283,20 @@ Commands:
1233
1283
  prodex pro browser login [--cwd /absolute/path/to/repo] [--dry-run] [--source-cli /absolute/path/to/dist/cli.js] [--launch-timeout-ms 5000]
1234
1284
  prodex pro browser check [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo]
1235
1285
  prodex pro browser smoke [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo]
1236
- prodex pro browser ask [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--target-url url --confirm-target] [--file path] "prompt"
1286
+ prodex pro browser ask [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--target-url url --confirm-target] [--file path] [--model Pro] [--pro-mode 기본|확장] [--effort 즉시|중간|높음|"매우 높음"] [--project "name"] "prompt"
1237
1287
  prodex pro latest [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo]
1238
1288
  prodex pro list [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo]
1239
1289
  prodex pro show <task-id|latest> [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo]
1240
1290
 
1241
1291
  Use \`prodex pro ask\` for dry-run/manual previews.
1242
- Use \`prodex pro browser ask\` only when you want an explicit visible-browser send.`);
1292
+ Use \`prodex pro browser ask\` only when you want an explicit visible-browser send.
1293
+ Model/project selection (visible-browser send):
1294
+ --model Pro | GPT-5.5 ... Pick the composer model before sending
1295
+ --pro-mode 기본 | 확장 Pro sub-mode (only when the model is Pro)
1296
+ --effort 즉시|중간|높음|매우 높음 Reasoning effort for non-Pro models (aliases: instant/medium/high/max)
1297
+ --project "name" Enter an existing sidebar project first
1298
+ Persist defaults for these with \`prodex setup --model/--pro-mode/--effort/--project\`; per-ask flags override them.
1299
+ (Creating a new project from the CLI is planned; for now create it in ChatGPT and pass --project.)`);
1243
1300
  }
1244
1301
  function printProjectHelp(stdout) {
1245
1302
  stdout(`prodex project
@@ -2663,9 +2720,10 @@ function printProBrowserHelp(stdout, sourceCli) {
2663
2720
  const smokeUsage = sourceCli
2664
2721
  ? `${cli} pro browser smoke${sourceCliOption} [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 90000]`
2665
2722
  : "prodex pro browser smoke [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 90000]";
2723
+ const selectionUsage = '[--model Pro] [--pro-mode 기본|확장] [--effort 즉시|중간|높음|"매우 높음"] [--project "name"]';
2666
2724
  const askUsage = sourceCli
2667
- ? `${cli} pro browser ask${sourceCliOption} [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 90000] [--target-url url --confirm-target] [--file path] "prompt"`
2668
- : 'prodex pro browser ask [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 90000] [--target-url url --confirm-target] [--file path] "prompt"';
2725
+ ? `${cli} pro browser ask${sourceCliOption} [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 90000] [--target-url url --confirm-target] [--file path] ${selectionUsage} "prompt"`
2726
+ : `prodex pro browser ask [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 90000] [--target-url url --confirm-target] [--file path] ${selectionUsage} "prompt"`;
2669
2727
  stdout(`${cli} pro browser
2670
2728
 
2671
2729
  Commands:
@@ -2675,6 +2733,12 @@ Commands:
2675
2733
  ${askUsage}
2676
2734
 
2677
2735
  Visible-browser sends require a manual browser session and stop on login, captcha, Cloudflare, permission, rate-limit, or usage-limit blockers.
2736
+ Model/project selection (ask):
2737
+ --model Composer model to pick, e.g. Pro or GPT-5.5
2738
+ --pro-mode Pro sub-mode: 기본 (standard) or 확장 (extended), used when the model is Pro
2739
+ --effort Reasoning effort for non-Pro models: 즉시 / 중간 / 높음 / 매우 높음 (aliases: instant/medium/high/max)
2740
+ --project Enter an existing sidebar project before sending
2741
+ --pro-mode and --effort cannot be combined. Persist defaults with \`${cli} setup${sourceCliOption}\`; per-ask flags override them.
2678
2742
  Use \`${cli} pro ask\` for dry-run/manual previews.
2679
2743
  \`${cli} pro browser ask${sourceCliOption}\` always attempts an explicit visible-browser send.`);
2680
2744
  }
@@ -3353,8 +3417,58 @@ function readRequiredLeadingArgument(args, command, placeholder) {
3353
3417
  return value;
3354
3418
  }
3355
3419
  const ASK_PRO_BOOLEAN_FLAGS = new Set(["--dry-run", "--send", "--confirm-target"]);
3356
- const ASK_PRO_VALUE_FLAGS = new Set(["--cwd", "--file", "--port", "--timeout-ms", "--target-url", "--source-cli"]);
3357
- const ASK_PRO_PREVIEW_VALUE_FLAGS = new Set(["--cwd", "--file", "--port", "--timeout-ms", "--target-url"]);
3420
+ const ASK_PRO_SELECTION_VALUE_FLAGS = ["--project", "--project-new", "--model", "--pro-mode", "--effort"];
3421
+ const ASK_PRO_VALUE_FLAGS = new Set([
3422
+ "--cwd",
3423
+ "--file",
3424
+ "--port",
3425
+ "--timeout-ms",
3426
+ "--target-url",
3427
+ "--source-cli",
3428
+ ...ASK_PRO_SELECTION_VALUE_FLAGS
3429
+ ]);
3430
+ const ASK_PRO_PREVIEW_VALUE_FLAGS = new Set([
3431
+ "--cwd",
3432
+ "--file",
3433
+ "--port",
3434
+ "--timeout-ms",
3435
+ "--target-url",
3436
+ ...ASK_PRO_SELECTION_VALUE_FLAGS
3437
+ ]);
3438
+ // Setup persists defaults for a subset of the per-ask selection flags. A new
3439
+ // project is created per-ask, never as a standing default, so --project-new is
3440
+ // intentionally excluded here.
3441
+ const ASK_PRO_SELECTION_DEFAULT_FLAGS = ["--model", "--pro-mode", "--effort", "--project"];
3442
+ function parseBrowserDefaultFlags(args) {
3443
+ const model = readFlag(args, "--model");
3444
+ const proModeRaw = readFlag(args, "--pro-mode");
3445
+ const effortRaw = readFlag(args, "--effort");
3446
+ const project = readFlag(args, "--project");
3447
+ if (proModeRaw !== undefined && effortRaw !== undefined) {
3448
+ throw new Error("setup cannot combine --pro-mode and --effort; Pro sub-modes and reasoning effort are different model axes.");
3449
+ }
3450
+ if (model === undefined && proModeRaw === undefined && effortRaw === undefined && project === undefined) {
3451
+ return undefined;
3452
+ }
3453
+ return {
3454
+ ...(model !== undefined ? { model } : {}),
3455
+ ...(proModeRaw !== undefined ? { proMode: parseProMode(proModeRaw) } : {}),
3456
+ ...(effortRaw !== undefined ? { effort: parseReasoningEffort(effortRaw) } : {}),
3457
+ ...(project !== undefined ? { project } : {})
3458
+ };
3459
+ }
3460
+ function formatBrowserDefaults(defaults) {
3461
+ const parts = [];
3462
+ if (defaults.model)
3463
+ parts.push(`model=${defaults.model}`);
3464
+ if (defaults.pro_mode)
3465
+ parts.push(`pro-mode=${defaults.pro_mode}`);
3466
+ if (defaults.effort)
3467
+ parts.push(`effort=${defaults.effort}`);
3468
+ if (defaults.project)
3469
+ parts.push(`project=${defaults.project}`);
3470
+ return parts.length > 0 ? parts.join(", ") : "(none)";
3471
+ }
3358
3472
  function parseAskProArgs(args, valueFlags = ASK_PRO_VALUE_FLAGS) {
3359
3473
  const delimiterIndex = args.indexOf("--");
3360
3474
  const optionArgs = delimiterIndex === -1 ? args : args.slice(0, delimiterIndex);