@youdie006/prodex 0.8.3 → 0.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.
package/dist/cli-help.js CHANGED
@@ -6,22 +6,18 @@ export const CLI_VERSION = packageJson.version ?? "0.0.0";
6
6
  export function printHelp(stdout) {
7
7
  stdout(`prodex v${CLI_VERSION}
8
8
 
9
- Commands:
10
- prodex --version
11
- prodex init [--cwd /absolute/path/to/repo]
12
- prodex doctor [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js]
13
- 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"] [--clear-model|--clear-pro-mode|--clear-effort|--clear-project] [--interactive]
14
- prodex start [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js]
15
- prodex status [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js] [--show-token] [--url-only] [--unsafe-show-non-expiring-token]
16
- prodex tunnel url [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js] --public-url https://... [--show-token] [--url-only]
17
- prodex release status [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js]
18
- prodex release pack [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js] --pack-destination /absolute/path [--keep-workdir]
19
- prodex onboard [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js]
20
- prodex project prompt [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js]
21
- prodex claude prompt [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js]
22
- prodex claude config [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js]
9
+ Ask ChatGPT from the terminal (visible logged-in browser):
10
+ prodex ask "Explain this stack trace" # shortcut for: prodex pro browser ask
11
+ prodex ask --file src/auth.ts "Review this for security holes"
12
+
13
+ First-time setup:
14
+ prodex pro browser login # dedicated Chrome; interactive runs wait until your login is READY
15
+ prodex doctor # bridge + MCP + browser health
16
+
17
+ Ask / consult commands:
18
+ prodex ask [same flags as pro browser ask] "prompt" # top-level shortcut for pro browser ask
23
19
  prodex pro ask [--dry-run] [--cwd /absolute/path/to/repo] [--file path] "prompt" # dry-run preview
24
- prodex pro browser login [--cwd /absolute/path/to/repo] [--dry-run] [--source-cli /absolute/path/to/dist/cli.js] [--profile-dir path] [--port 9333] [--url https://chatgpt.com/...] [--launch-timeout-ms 5000] # preview/open visible browser login
20
+ prodex pro browser login [--cwd /absolute/path/to/repo] [--dry-run] [--source-cli /absolute/path/to/dist/cli.js] [--profile-dir path] [--port 9333] [--url https://chatgpt.com/...] [--launch-timeout-ms 5000] [--wait|--no-wait] [--wait-timeout-ms 300000] # preview/open visible browser login
25
21
  prodex pro browser help [--source-cli /absolute/path/to/dist/cli.js]
26
22
  prodex pro browser check [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 1500]
27
23
  prodex pro browser smoke [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 90000]
@@ -30,6 +26,9 @@ Commands:
30
26
  prodex pro latest [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo]
31
27
  prodex pro list [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo]
32
28
  prodex pro show <task-id|latest> [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo]
29
+
30
+ Bridge ledger (durable tasks/results/receipts/sessions under .bridge/):
31
+ prodex init [--cwd /absolute/path/to/repo]
33
32
  prodex tasks create [--cwd /absolute/path/to/repo] --title "Title" --prompt "Prompt"
34
33
  prodex tasks list [--status new|claimed|done|blocked] [--cwd /absolute/path/to/repo]
35
34
  prodex tasks show <task-id|latest> [--cwd /absolute/path/to/repo]
@@ -44,7 +43,23 @@ Commands:
44
43
  prodex receipts rotate-key [--cwd /absolute/path/to/repo]
45
44
  prodex sessions list [--status preview|running|done|blocked] [--cwd /absolute/path/to/repo]
46
45
  prodex sessions show <session-id|latest> [--cwd /absolute/path/to/repo]
47
- prodex mcp [--cwd /absolute/path/to/repo]`);
46
+
47
+ Agent / MCP integration:
48
+ prodex mcp [--cwd /absolute/path/to/repo]
49
+ 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"] [--clear-model|--clear-pro-mode|--clear-effort|--clear-project] [--interactive]
50
+ prodex start [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js]
51
+ prodex status [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js] [--show-token] [--url-only] [--unsafe-show-non-expiring-token]
52
+ prodex tunnel url [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js] --public-url https://... [--show-token] [--url-only]
53
+ prodex claude prompt [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js]
54
+ prodex claude config [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js]
55
+ prodex project prompt [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js]
56
+ prodex onboard [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js]
57
+
58
+ Maintenance:
59
+ prodex --version
60
+ prodex doctor [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js]
61
+ prodex release status [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js]
62
+ prodex release pack [--cwd /absolute/path/to/repo] [--source-cli /absolute/path/to/dist/cli.js] --pack-destination /absolute/path [--keep-workdir]`);
48
63
  }
49
64
  export function printInitHelp(stdout) {
50
65
  stdout(`prodex init
@@ -141,7 +156,7 @@ export function printProHelp(stdout) {
141
156
  Commands:
142
157
  prodex pro ask [--dry-run] [--cwd /absolute/path/to/repo] [--file path] "prompt"
143
158
  prodex pro browser help [--source-cli /absolute/path/to/dist/cli.js]
144
- prodex pro browser login [--cwd /absolute/path/to/repo] [--dry-run] [--source-cli /absolute/path/to/dist/cli.js] [--launch-timeout-ms 5000]
159
+ prodex pro browser login [--cwd /absolute/path/to/repo] [--dry-run] [--source-cli /absolute/path/to/dist/cli.js] [--launch-timeout-ms 5000] [--wait|--no-wait] [--wait-timeout-ms 300000]
145
160
  prodex pro browser check [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo]
146
161
  prodex pro browser smoke [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo]
147
162
  prodex pro browser models [--source-cli /absolute/path/to/dist/cli.js]
@@ -220,8 +235,8 @@ export function printProBrowserHelp(stdout, sourceCli) {
220
235
  const cli = formatCliCommand(sourceCli);
221
236
  const sourceCliOption = formatSourceCliOption(sourceCli);
222
237
  const loginUsage = sourceCli
223
- ? `${cli} pro browser login${sourceCliOption} [--cwd /absolute/path/to/repo] [--dry-run] [--profile-dir path] [--port 9333] [--url https://chatgpt.com/...] [--launch-timeout-ms 5000]`
224
- : "prodex pro browser login [--cwd /absolute/path/to/repo] [--dry-run] [--source-cli /absolute/path/to/dist/cli.js] [--profile-dir path] [--port 9333] [--url https://chatgpt.com/...] [--launch-timeout-ms 5000]";
238
+ ? `${cli} pro browser login${sourceCliOption} [--cwd /absolute/path/to/repo] [--dry-run] [--profile-dir path] [--port 9333] [--url https://chatgpt.com/...] [--launch-timeout-ms 5000] [--wait|--no-wait] [--wait-timeout-ms 300000]`
239
+ : "prodex pro browser login [--cwd /absolute/path/to/repo] [--dry-run] [--source-cli /absolute/path/to/dist/cli.js] [--profile-dir path] [--port 9333] [--url https://chatgpt.com/...] [--launch-timeout-ms 5000] [--wait|--no-wait] [--wait-timeout-ms 300000]";
225
240
  const checkUsage = sourceCli
226
241
  ? `${cli} pro browser check${sourceCliOption} [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 1500]`
227
242
  : "prodex pro browser check [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 1500]";
@@ -1 +1 @@
1
- {"version":3,"file":"cli-help.js","sourceRoot":"","sources":["../src/cli-help.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli-help.js","sourceRoot":"","sources":["../src/cli-help.ts"],"names":[],"mappings":"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"}
package/dist/cli-pro.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type ChatGptBrowserLaunch, sendChatGptPrompt } from "./chatgpt-browser.js";
1
+ import { type ChatGptBrowserLaunch, type SendChatGptProgressEvent, getChatGptBrowserStatus, sendChatGptPrompt } from "./chatgpt-browser.js";
2
2
  import { type HelpRequestOptions } from "./cli-args.js";
3
3
  import { type BrowserCommandOptions } from "./cli-shared.js";
4
4
  import { BridgeStore } from "./store.js";
@@ -7,8 +7,53 @@ export type RunCliFn = (args: string[], io: CliIO) => Promise<number>;
7
7
  export declare function runChatgptCommand(rest: string[], io: CliIO): Promise<number>;
8
8
  export declare function runProCommand(rest: string[], io: CliIO, runCliFn: RunCliFn): Promise<number>;
9
9
  export declare function runConsultsCommand(rest: string[], io: CliIO): Promise<number>;
10
+ /**
11
+ * Turns send progress events into stderr lines so multi-minute Pro consults do
12
+ * not look frozen. Phase transitions print immediately; the per-poll waiting
13
+ * heartbeat is throttled to one line per heartbeatMs.
14
+ */
15
+ export declare function createBrowserSendProgressPrinter(write: (line: string) => void, heartbeatMs?: number): (event: SendChatGptProgressEvent) => void;
10
16
  export declare function runAskProCommand(rest: string[], io: CliIO): Promise<number>;
11
17
  export declare const PRO_BROWSER_SMOKE_TOKEN = "PRODEX_PRO_SMOKE_OK";
18
+ export interface BrowserConsultInput {
19
+ prompt: string;
20
+ model?: string;
21
+ pro_mode?: string;
22
+ effort?: string;
23
+ project?: string;
24
+ timeout_ms?: number;
25
+ files?: string[];
26
+ }
27
+ export interface BrowserConsultOutcome {
28
+ task_id: string;
29
+ status: string;
30
+ thread: string;
31
+ answer: string;
32
+ notes: string[];
33
+ }
34
+ /**
35
+ * MCP-facing wrapper around the visible-browser ask flow. Reuses the full CLI
36
+ * path (send pacing, task/session/receipt persistence, artifact save) by
37
+ * invoking runAskProCommand with captured io, then returns structured fields
38
+ * instead of printed lines. Registered only on the local stdio MCP server -
39
+ * never on the HTTP MCP surface, which is exposed to ChatGPT itself.
40
+ */
41
+ export declare function performBrowserConsultForMcp(cwd: string, input: BrowserConsultInput): Promise<BrowserConsultOutcome>;
42
+ export interface LoginWaitDeps {
43
+ statusFn?: typeof getChatGptBrowserStatus;
44
+ sleepFn?: (ms: number) => Promise<void>;
45
+ now?: () => number;
46
+ }
47
+ /**
48
+ * Guided login: poll the visible browser until a logged-in ChatGPT tab with a
49
+ * usable composer appears, narrating each state change so the user knows what
50
+ * manual step (login, challenge, opening a chat) is still missing.
51
+ */
52
+ export declare function waitForChatGptLoginReady(stderr: (line: string) => void, options: {
53
+ port: number;
54
+ timeoutMs?: number;
55
+ pollMs?: number;
56
+ }, deps?: LoginWaitDeps): Promise<boolean>;
12
57
  export declare function assertBrowserLaunchStayedAlive(opened: ChatGptBrowserLaunch, timeoutMs?: number): Promise<void>;
13
58
  export declare function browserSendBlockerFromError(error: unknown): {
14
59
  code: string;
package/dist/cli-pro.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import { mkdir, readFile, writeFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { buildDryRunBundle } from "./bundle.js";
4
- import { chatGptVisibilityBlocker, defaultChatGptProfileDir, getChatGptBrowserStatus, listChatGptModelOptions, normalizeChatGptTargetUrl, openChatGptBrowser, parseProMode, parseReasoningEffort, sendChatGptPrompt } from "./chatgpt-browser.js";
4
+ import { DEFAULT_CDP_PORT, resolveCdpPort, chatGptVisibilityBlocker, defaultChatGptProfileDir, getChatGptBrowserStatus, listChatGptModelOptions, normalizeChatGptTargetUrl, openChatGptBrowser, parseProMode, parseReasoningEffort, sendChatGptPrompt } from "./chatgpt-browser.js";
5
5
  import { ASK_PRO_BOOLEAN_FLAGS, ASK_PRO_PREVIEW_VALUE_FLAGS, ASK_PRO_VALUE_FLAGS, assertHelpRequestArgs, assertNoExtraArgs, assertOnlyOptions, findHelpFlagIndexBeforePromptDelimiter, hasAskProDryRunMode, hasAskProMode, hasAskProSendMode, isHelpSubcommand, parseAskProArgs, printHelpIfRequested, readFlag, readPortFlag, readPositionalsWithOptions, readPositiveNumberFlag, readRepeatedFlag, resolveCwdFlag, resolveOptionalFileFlag, unknownSubcommandError } from "./cli-args.js";
6
6
  import { printProBrowserHelp, printProHelp } from "./cli-help.js";
7
7
  import { listRawResultsForInspection, listTasksForInspection } from "./cli-ledger.js";
8
8
  import { redactServerUrl } from "./cli-server.js";
9
- import { errorMessage, firstLine, formatBlockedConsultRecordedMessage, formatBrowserCheckCommand, formatBrowserLoginCommand, formatBrowserSmokeCommand, formatBrowserTargetAskCommand, formatInitCommand, formatSetupCommand, isMissingFileError, computeSendPacingWaitMs, isUntrustedResultError, resolveMinSendIntervalMs, sourceAwareBrowserBlocker, sourceAwareBrowserNextStep, sourceAwareResultError, sourceAwareResultMessage, sourceAwareSetupMessage } from "./cli-shared.js";
9
+ import { errorMessage, firstLine, formatBlockedConsultRecordedMessage, formatProLatestCommand, formatBrowserCheckCommand, formatBrowserLoginCommand, formatBrowserSmokeCommand, formatBrowserTargetAskCommand, formatInitCommand, formatSetupCommand, isMissingFileError, computeSendPacingWaitMs, isUntrustedResultError, resolveMinSendIntervalMs, sourceAwareBrowserBlocker, sourceAwareBrowserNextStep, sourceAwareResultError, sourceAwareResultMessage, sourceAwareSetupMessage } from "./cli-shared.js";
10
10
  import { getTokenExpiryStatus, loadBrowserDefaults, loadLocalConfig } from "./config.js";
11
11
  import { BridgeStore, MAX_FETCHABLE_RESULT_ARTIFACT_BYTES } from "./store.js";
12
12
  export async function runChatgptCommand(rest, io) {
@@ -17,7 +17,7 @@ export async function runChatgptCommand(rest, io) {
17
17
  if (subcommand === "open") {
18
18
  assertOnlyOptions(chatgptArgs, "chatgpt open", ["--port", "--profile-dir", "--url"]);
19
19
  const opened = openChatGptBrowser({
20
- port: readPortFlag(chatgptArgs, "--port") ?? 9333,
20
+ port: resolveCdpPort(readPortFlag(chatgptArgs, "--port")),
21
21
  profileDir: readFlag(chatgptArgs, "--profile-dir"),
22
22
  url: readChatGptBrowserUrlFlag(chatgptArgs)
23
23
  });
@@ -29,7 +29,7 @@ export async function runChatgptCommand(rest, io) {
29
29
  }
30
30
  if (subcommand === "status") {
31
31
  assertOnlyOptions(chatgptArgs, "chatgpt status", ["--port"]);
32
- const status = await getChatGptBrowserStatus({ port: readPortFlag(chatgptArgs, "--port") ?? 9333 });
32
+ const status = await getChatGptBrowserStatus({ port: resolveCdpPort(readPortFlag(chatgptArgs, "--port")) });
33
33
  io.stdout(JSON.stringify(status, null, 2));
34
34
  return 0;
35
35
  }
@@ -38,7 +38,7 @@ export async function runChatgptCommand(rest, io) {
38
38
  const targetCwd = resolveCwdFlag(io.cwd, chatgptArgs);
39
39
  const targetStore = new BridgeStore(targetCwd);
40
40
  const sourceCli = resolveOptionalFileFlag(io.cwd, chatgptArgs, "--source-cli");
41
- const port = readPortFlag(chatgptArgs, "--port") ?? 9333;
41
+ const port = resolveCdpPort(readPortFlag(chatgptArgs, "--port"));
42
42
  const timeoutMs = readPositiveNumberFlag(chatgptArgs, "--timeout-ms") ?? 90000;
43
43
  const commandOptions = {
44
44
  ...(readFlag(chatgptArgs, "--cwd") ? { cwd: targetCwd } : {}),
@@ -83,7 +83,8 @@ export async function runChatgptCommand(rest, io) {
83
83
  result = await sendChatGptPrompt({
84
84
  port,
85
85
  prompt: smokePrompt,
86
- timeoutMs
86
+ timeoutMs,
87
+ onProgress: createBrowserSendProgressPrinter(io.stderr)
87
88
  });
88
89
  }
89
90
  catch (error) {
@@ -151,22 +152,25 @@ export async function runProCommand(rest, io, runCliFn) {
151
152
  }
152
153
  if (browserSubcommand === "login") {
153
154
  if (printProBrowserHelpIfRequested(browserArgs, "pro browser login", io, {
154
- valueFlags: ["--cwd", "--profile-dir", "--port", "--url", "--source-cli", "--launch-timeout-ms"],
155
- booleanFlags: ["--dry-run"]
155
+ valueFlags: ["--cwd", "--profile-dir", "--port", "--url", "--source-cli", "--launch-timeout-ms", "--wait-timeout-ms"],
156
+ booleanFlags: ["--dry-run", "--wait", "--no-wait"]
156
157
  })) {
157
158
  return 0;
158
159
  }
159
- assertOnlyOptions(browserArgs, "pro browser login", ["--cwd", "--profile-dir", "--port", "--url", "--source-cli", "--launch-timeout-ms"], ["--dry-run"]);
160
+ assertOnlyOptions(browserArgs, "pro browser login", ["--cwd", "--profile-dir", "--port", "--url", "--source-cli", "--launch-timeout-ms", "--wait-timeout-ms"], ["--dry-run", "--wait", "--no-wait"]);
161
+ if (browserArgs.includes("--wait") && browserArgs.includes("--no-wait")) {
162
+ throw new Error("pro browser login cannot combine --wait and --no-wait");
163
+ }
160
164
  const loginUrl = readChatGptBrowserUrlFlag(browserArgs);
161
165
  const sourceCli = resolveOptionalFileFlag(io.cwd, browserArgs, "--source-cli");
162
166
  const targetCwd = readFlag(browserArgs, "--cwd") ? resolveCwdFlag(io.cwd, browserArgs) : undefined;
163
167
  const profileDir = readFlag(browserArgs, "--profile-dir");
164
- const port = readPortFlag(browserArgs, "--port") ?? 9333;
168
+ const port = resolveCdpPort(readPortFlag(browserArgs, "--port"));
165
169
  const launchTimeoutMs = readPositiveNumberFlag(browserArgs, "--launch-timeout-ms");
166
170
  const commandOptions = {
167
171
  ...(targetCwd ? { cwd: targetCwd } : {}),
168
172
  ...(profileDir ? { profileDir } : {}),
169
- ...(port !== 9333 ? { port } : {}),
173
+ ...(port !== DEFAULT_CDP_PORT ? { port } : {}),
170
174
  ...(readFlag(browserArgs, "--url") ? { url: loginUrl } : {}),
171
175
  ...(launchTimeoutMs !== undefined ? { launchTimeoutMs } : {})
172
176
  };
@@ -195,7 +199,16 @@ export async function runProCommand(rest, io, runCliFn) {
195
199
  sourceCli,
196
200
  commandOptions
197
201
  });
198
- return 0;
202
+ // Guided wait: interactive terminals walk the user to a verified READY
203
+ // state instead of returning while login is still unfinished. Scripts
204
+ // and agents (non-TTY) keep the immediate return unless --wait is
205
+ // passed; --no-wait always skips.
206
+ const shouldWaitForReady = !browserArgs.includes("--no-wait") && (browserArgs.includes("--wait") || process.stdout.isTTY === true);
207
+ if (!shouldWaitForReady)
208
+ return 0;
209
+ const waitTimeoutMs = readPositiveNumberFlag(browserArgs, "--wait-timeout-ms") ?? 300_000;
210
+ const ready = await waitForChatGptLoginReady(io.stderr, { port: opened.port, timeoutMs: waitTimeoutMs });
211
+ return ready ? 0 : 1;
199
212
  }
200
213
  if (browserSubcommand === "ask") {
201
214
  if (printProBrowserHelpIfRequested(browserArgs, "pro browser ask", io, {
@@ -348,6 +361,34 @@ async function enforceVisibleBrowserSendPacing(cwd, stderr) {
348
361
  // best effort: pacing must never block a legitimate send on a write failure
349
362
  }
350
363
  }
364
+ const PROGRESS_PHASE_LABELS = {
365
+ connecting: "connecting to browser",
366
+ tab_ready: "chatgpt tab ready",
367
+ selecting: "applying selection",
368
+ sent: "prompt sent, waiting for answer"
369
+ };
370
+ /**
371
+ * Turns send progress events into stderr lines so multi-minute Pro consults do
372
+ * not look frozen. Phase transitions print immediately; the per-poll waiting
373
+ * heartbeat is throttled to one line per heartbeatMs.
374
+ */
375
+ export function createBrowserSendProgressPrinter(write, heartbeatMs = 10_000) {
376
+ let lastWaitingElapsedMs;
377
+ return (event) => {
378
+ if (event.phase === "waiting") {
379
+ if (lastWaitingElapsedMs !== undefined && event.elapsedMs - lastWaitingElapsedMs < heartbeatMs)
380
+ return;
381
+ lastWaitingElapsedMs = event.elapsedMs;
382
+ write(`progress: waiting ${Math.round(event.elapsedMs / 1000)}s${event.detail ? ` (${event.detail})` : ""}`);
383
+ return;
384
+ }
385
+ if (event.phase === "answered") {
386
+ write(`progress: answer received after ${Math.round(event.elapsedMs / 1000)}s${event.detail ? ` (${event.detail})` : ""}`);
387
+ return;
388
+ }
389
+ write(`progress: ${PROGRESS_PHASE_LABELS[event.phase]}${event.detail ? ` (${event.detail})` : ""}`);
390
+ };
391
+ }
351
392
  export async function runAskProCommand(rest, io) {
352
393
  const parsedAskPro = parseAskProArgs(rest);
353
394
  const hasDryRunMode = parsedAskPro.optionArgs.includes("--dry-run");
@@ -409,7 +450,7 @@ export async function runAskProCommand(rest, io) {
409
450
  ...(selectionProMode ? { pro_mode: selectionProMode } : {}),
410
451
  ...(selectionEffort ? { effort: selectionEffort } : {})
411
452
  };
412
- const browserPort = hasSendMode ? (readPortFlag(parsedAskPro.optionArgs, "--port") ?? 9333) : undefined;
453
+ const browserPort = hasSendMode ? resolveCdpPort(readPortFlag(parsedAskPro.optionArgs, "--port")) : undefined;
413
454
  // Pro extended can legitimately think for minutes, so its default timeout is
414
455
  // higher; an explicit --timeout-ms always wins.
415
456
  const defaultBrowserTimeoutMs = selectionProMode === "확장" ? 300_000 : 90_000;
@@ -480,7 +521,8 @@ export async function runAskProCommand(rest, io) {
480
521
  projectNew: selectionProjectNew,
481
522
  model: selectionModel,
482
523
  proMode: selectionProMode,
483
- effort: selectionEffort
524
+ effort: selectionEffort,
525
+ onProgress: createBrowserSendProgressPrinter(io.stderr)
484
526
  });
485
527
  }
486
528
  catch (error) {
@@ -579,6 +621,10 @@ export async function runAskProCommand(rest, io) {
579
621
  io.stdout(`${result.task_id}\t${result.status}\t${consult.url}`);
580
622
  io.stdout("");
581
623
  io.stdout(result.summary);
624
+ // Discoverability footer on stderr: the answer above is also persisted,
625
+ // and `pro latest` re-prints it without a new browser send.
626
+ const cwdForHints = readFlag(parsedAskPro.optionArgs, "--cwd") ? targetCwd : undefined;
627
+ io.stderr(`${answerArtifactPath ? `saved: ${answerArtifactPath}` : "saved: task result (answer too large for a fetchable artifact)"} | re-print: ${formatProLatestCommand(sourceCli, { cwd: cwdForHints })}`);
582
628
  }
583
629
  else {
584
630
  await writeSessionBestEffort(targetStore, {
@@ -599,6 +645,84 @@ export async function runAskProCommand(rest, io) {
599
645
  return 0;
600
646
  }
601
647
  export const PRO_BROWSER_SMOKE_TOKEN = "PRODEX_PRO_SMOKE_OK";
648
+ /**
649
+ * MCP-facing wrapper around the visible-browser ask flow. Reuses the full CLI
650
+ * path (send pacing, task/session/receipt persistence, artifact save) by
651
+ * invoking runAskProCommand with captured io, then returns structured fields
652
+ * instead of printed lines. Registered only on the local stdio MCP server -
653
+ * never on the HTTP MCP surface, which is exposed to ChatGPT itself.
654
+ */
655
+ export async function performBrowserConsultForMcp(cwd, input) {
656
+ const stdoutLines = [];
657
+ const stderrLines = [];
658
+ const argv = [
659
+ "--send",
660
+ ...(input.model !== undefined ? ["--model", input.model] : []),
661
+ ...(input.pro_mode !== undefined ? ["--pro-mode", input.pro_mode] : []),
662
+ ...(input.effort !== undefined ? ["--effort", input.effort] : []),
663
+ ...(input.project !== undefined ? ["--project", input.project] : []),
664
+ ...(input.timeout_ms !== undefined ? ["--timeout-ms", String(input.timeout_ms)] : []),
665
+ ...(input.files ?? []).flatMap((file) => ["--file", file]),
666
+ "--",
667
+ input.prompt
668
+ ];
669
+ await runAskProCommand(argv, {
670
+ cwd,
671
+ stdout: (line) => stdoutLines.push(line),
672
+ stderr: (line) => stderrLines.push(line),
673
+ allowAskProBrowserSend: true
674
+ });
675
+ const header = stdoutLines[0] ?? "";
676
+ const [taskId = "", status = "", thread = ""] = header.split("\t");
677
+ return {
678
+ task_id: taskId,
679
+ status,
680
+ thread,
681
+ answer: stdoutLines.slice(2).join("\n"),
682
+ notes: stderrLines.filter((line) => !line.startsWith("progress:"))
683
+ };
684
+ }
685
+ /**
686
+ * Guided login: poll the visible browser until a logged-in ChatGPT tab with a
687
+ * usable composer appears, narrating each state change so the user knows what
688
+ * manual step (login, challenge, opening a chat) is still missing.
689
+ */
690
+ export async function waitForChatGptLoginReady(stderr, options, deps = {}) {
691
+ const statusFn = deps.statusFn ?? getChatGptBrowserStatus;
692
+ const sleepFn = deps.sleepFn ?? sleep;
693
+ const now = deps.now ?? Date.now;
694
+ const timeoutMs = options.timeoutMs ?? 300_000;
695
+ const pollMs = options.pollMs ?? 2_000;
696
+ const startedAt = now();
697
+ stderr("login: waiting for a logged-in ChatGPT tab (finish login in the opened window; Ctrl+C stops waiting)...");
698
+ let lastState = "";
699
+ while (now() - startedAt < timeoutMs) {
700
+ const status = await statusFn({ port: options.port, timeoutMs: 1_500 });
701
+ const state = !status.reachable
702
+ ? "login: browser starting..."
703
+ : status.blocker
704
+ ? `login: blocked - ${status.blocker.message}`
705
+ : !status.loggedInLikely
706
+ ? "login: waiting for ChatGPT login in the opened window..."
707
+ : !status.hasComposer
708
+ ? "login: logged in; open a chat so the prompt composer is visible..."
709
+ : "";
710
+ if (state === "") {
711
+ stderr(`login: READY - logged-in ChatGPT tab with composer detected (${Math.round((now() - startedAt) / 1000)}s).`);
712
+ return true;
713
+ }
714
+ if (state !== lastState) {
715
+ lastState = state;
716
+ stderr(state);
717
+ }
718
+ const remainingMs = timeoutMs - (now() - startedAt);
719
+ if (remainingMs <= 0)
720
+ break;
721
+ await sleepFn(Math.min(pollMs, Math.max(1, remainingMs)));
722
+ }
723
+ stderr(`login: not ready after ${Math.round(timeoutMs / 1000)}s. Finish login in the browser, then verify with \`prodex pro browser check\`.`);
724
+ return false;
725
+ }
602
726
  export async function assertBrowserLaunchStayedAlive(opened, timeoutMs) {
603
727
  const outcome = await waitForBrowserLaunchReady(opened, timeoutMs);
604
728
  if (outcome.reachable)
@@ -635,12 +759,17 @@ export function browserSendBlockerFromError(error) {
635
759
  next_step: "Update prodex (npm i -g @youdie006/prodex@latest); if it persists, report it at https://github.com/youdie006/prodex/issues or paste the prompt manually in the visible browser."
636
760
  };
637
761
  }
638
- if (/^Timed out after \d+ms/.test(message)) {
762
+ const timedOut = message.match(/^Timed out after (\d+)ms/);
763
+ if (timedOut) {
764
+ // Suggest a concrete doubled budget so the user can paste a rerun command
765
+ // instead of guessing what "raise --timeout-ms" means in milliseconds.
766
+ const usedMs = Number(timedOut[1]);
767
+ const suggestedMs = Number.isFinite(usedMs) && usedMs > 0 ? usedMs * 2 : 600_000;
639
768
  return {
640
769
  code: "send_timeout",
641
770
  message,
642
771
  retryable: true,
643
- next_step: "Raise --timeout-ms (Pro extended already uses a higher default) and rerun the consult."
772
+ next_step: `Rerun with a bigger budget: \`prodex pro browser ask --timeout-ms ${suggestedMs} "<same prompt>"\`.`
644
773
  };
645
774
  }
646
775
  return {
@@ -847,7 +976,7 @@ export async function printProductCheck(store, io, args, configCwd = io.cwd) {
847
976
  }
848
977
  }
849
978
  const browserStatus = await getChatGptBrowserStatus({
850
- port: readPortFlag(args, "--port") ?? 9333,
979
+ port: resolveCdpPort(readPortFlag(args, "--port")),
851
980
  timeoutMs: readPositiveNumberFlag(args, "--timeout-ms") ?? 1500
852
981
  });
853
982
  const browserCommandOptions = {