@youdie006/prodex 0.33.0 → 0.34.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/chatgpt-browser.js +70 -5
- package/dist/cli-help.js +8 -0
- package/dist/cli-pro.js +60 -1
- package/package.json +1 -1
package/dist/chatgpt-browser.js
CHANGED
|
@@ -2517,13 +2517,78 @@ export async function navigateChatGptTabTo(url, options = {}) {
|
|
|
2517
2517
|
}
|
|
2518
2518
|
}
|
|
2519
2519
|
/**
|
|
2520
|
-
* Which
|
|
2520
|
+
* Which conversation a delete means - or why it refuses to guess.
|
|
2521
2521
|
*
|
|
2522
|
-
*
|
|
2523
|
-
*
|
|
2524
|
-
*
|
|
2525
|
-
* sharing a name.
|
|
2522
|
+
* Titles are written by ChatGPT and repeat far more often than project names,
|
|
2523
|
+
* so an exact title matching two chats is refused with both ids rather than
|
|
2524
|
+
* resolved by picking the newer one.
|
|
2526
2525
|
*/
|
|
2526
|
+
export function resolveConversationToDelete(conversations, request) {
|
|
2527
|
+
if (request.id) {
|
|
2528
|
+
const byId = conversations.find((conversation) => conversation.id === request.id);
|
|
2529
|
+
return byId ? { ok: true, id: byId.id, title: byId.title } : { ok: false, reason: `No recent conversation has the id ${request.id}.` };
|
|
2530
|
+
}
|
|
2531
|
+
const title = request.title?.trim();
|
|
2532
|
+
if (!title)
|
|
2533
|
+
return { ok: false, reason: "Name the chat to delete with --title, or identify it with --id." };
|
|
2534
|
+
const matches = conversations.filter((conversation) => conversation.title === title);
|
|
2535
|
+
if (matches.length === 0) {
|
|
2536
|
+
return { ok: false, reason: `No recent conversation is titled exactly "${title}". Run \`prodex pro browser chats\` to see them.` };
|
|
2537
|
+
}
|
|
2538
|
+
if (matches.length > 1) {
|
|
2539
|
+
const ids = matches.map((conversation) => conversation.id).join(", ");
|
|
2540
|
+
return { ok: false, reason: `More than one recent conversation is titled "${title}" (${ids}). Pass --id to say which one.` };
|
|
2541
|
+
}
|
|
2542
|
+
return { ok: true, id: matches[0].id, title: matches[0].title };
|
|
2543
|
+
}
|
|
2544
|
+
/**
|
|
2545
|
+
* Remove one conversation. ChatGPT deletes a chat by hiding it, which is the
|
|
2546
|
+
* same call its own UI makes; the caller is responsible for confirming intent.
|
|
2547
|
+
*/
|
|
2548
|
+
export function deleteConversationExpression(conversationId) {
|
|
2549
|
+
return `(async () => {
|
|
2550
|
+
let token = "";
|
|
2551
|
+
try {
|
|
2552
|
+
const session = await fetch("/api/auth/session", { credentials: "include" });
|
|
2553
|
+
if (!session.ok) return { ok: false, reason: "session_http_" + session.status };
|
|
2554
|
+
const parsed = await session.json();
|
|
2555
|
+
token = (parsed && parsed.accessToken) || "";
|
|
2556
|
+
} catch (error) {
|
|
2557
|
+
return { ok: false, reason: "session_error" };
|
|
2558
|
+
}
|
|
2559
|
+
try {
|
|
2560
|
+
const response = await fetch("/backend-api/conversation/" + ${JSON.stringify(conversationId)}, {
|
|
2561
|
+
method: "PATCH",
|
|
2562
|
+
credentials: "include",
|
|
2563
|
+
headers: token ? { Authorization: "Bearer " + token, "Content-Type": "application/json" } : { "Content-Type": "application/json" },
|
|
2564
|
+
body: JSON.stringify({ is_visible: false })
|
|
2565
|
+
});
|
|
2566
|
+
const body = await response.text();
|
|
2567
|
+
if (!response.ok) return { ok: false, reason: "delete_http_" + response.status + " " + body.slice(0, 120) };
|
|
2568
|
+
return { ok: true, reason: "" };
|
|
2569
|
+
} catch (error) {
|
|
2570
|
+
return { ok: false, reason: "delete_error" };
|
|
2571
|
+
}
|
|
2572
|
+
})()`;
|
|
2573
|
+
}
|
|
2574
|
+
/** Remove one conversation. Callers must have confirmed intent before calling. */
|
|
2575
|
+
export async function deleteChatGptConversation(input) {
|
|
2576
|
+
const port = resolveCdpPort(input.port);
|
|
2577
|
+
const page = await findChatGptPage(port, input.timeoutMs ?? 3_000);
|
|
2578
|
+
if (!page.ok || !page.page) {
|
|
2579
|
+
throw new ChatGptBrowserBlockerError(page.blocker ?? {
|
|
2580
|
+
code: "browser_unreachable",
|
|
2581
|
+
message: `No Chrome DevTools endpoint is reachable on 127.0.0.1:${port}.`,
|
|
2582
|
+
retryable: true,
|
|
2583
|
+
next_step: "Run `prodex pro browser login` to reopen the dedicated window, then retry."
|
|
2584
|
+
});
|
|
2585
|
+
}
|
|
2586
|
+
const result = await evaluateOnPage(page.page, deleteConversationExpression(input.conversationId), {
|
|
2587
|
+
timeoutMs: 30_000
|
|
2588
|
+
});
|
|
2589
|
+
if (!result?.ok)
|
|
2590
|
+
throw new Error(`ChatGPT refused to delete the conversation: ${result?.reason ?? "unknown reason"}`);
|
|
2591
|
+
}
|
|
2527
2592
|
export function resolveProjectToDelete(projects, request) {
|
|
2528
2593
|
if (request.id) {
|
|
2529
2594
|
const byId = projects.find((project) => project.id === request.id);
|
package/dist/cli-help.js
CHANGED
|
@@ -268,6 +268,12 @@ export function printProBrowserHelp(stdout, sourceCli) {
|
|
|
268
268
|
const projectDeleteUsage = sourceCli
|
|
269
269
|
? `${cli} pro browser project-delete${sourceCliOption} [--name "exact name" | --id g-p-...] [--confirm-delete] # previews unless --confirm-delete; deleting a project takes its chats with it`
|
|
270
270
|
: `prodex pro browser project-delete [--source-cli /absolute/path/to/dist/cli.js] [--name "exact name" | --id g-p-...] [--confirm-delete] # previews unless --confirm-delete; deleting a project takes its chats with it`;
|
|
271
|
+
const chatsUsage = sourceCli
|
|
272
|
+
? `${cli} pro browser chats${sourceCliOption} [--limit 10] # read-only: recent conversations with their ids`
|
|
273
|
+
: "prodex pro browser chats [--source-cli /absolute/path/to/dist/cli.js] [--limit 10] # read-only: recent conversations with their ids";
|
|
274
|
+
const chatDeleteUsage = sourceCli
|
|
275
|
+
? `${cli} pro browser chat-delete${sourceCliOption} [--title "exact title" | --id <id>] [--confirm-delete] # previews unless --confirm-delete`
|
|
276
|
+
: `prodex pro browser chat-delete [--source-cli /absolute/path/to/dist/cli.js] [--title "exact title" | --id <id>] [--confirm-delete] # previews unless --confirm-delete`;
|
|
271
277
|
const recoverUsage = sourceCli
|
|
272
278
|
? `${cli} pro browser recover${sourceCliOption} [--cwd /absolute/path/to/repo] [--port 9333] --target-url <thread-url> [--timeout-ms 60000] # fetch a finished answer (deep research reports too) from a thread whose send timed out`
|
|
273
279
|
: "prodex pro browser recover [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] --target-url <thread-url> [--timeout-ms 60000] # fetch a finished answer (deep research reports too) from a thread whose send timed out";
|
|
@@ -280,6 +286,8 @@ Commands:
|
|
|
280
286
|
${modelsUsage}
|
|
281
287
|
${projectsUsage}
|
|
282
288
|
${projectDeleteUsage}
|
|
289
|
+
${chatsUsage}
|
|
290
|
+
${chatDeleteUsage}
|
|
283
291
|
${askUsage}
|
|
284
292
|
${recoverUsage}
|
|
285
293
|
|
package/dist/cli-pro.js
CHANGED
|
@@ -2,7 +2,7 @@ import { existsSync, statSync } from "node:fs";
|
|
|
2
2
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { buildDryRunBundle } from "./bundle.js";
|
|
5
|
-
import { DEFAULT_CDP_PORT, resolveCdpPort, resolveProjectToDelete, chatGptVisibilityBlocker, defaultChatGptProfileDir, formatDurationMs, getChatGptBrowserStatus, listChatGptModelOptions, deleteChatGptProject, listChatGptProjectsWithIds, listChatGptSidebarProjects, normalizeChatGptTargetUrl, openChatGptBrowser, openChatGptTab, parseProMode, parseReasoningEffort, defaultTimeoutForTools, ensureVirtualDisplay, minimizeChatGptWindow, readLastBrowserLoginLaunch, resolveVirtualDisplayPreference, resolveBrowserWindowMode, resolveHeadlessPreference, recordBrowserLoginLaunch, recoverChatGptAnswerFromThread, sendChatGptPrompt } from "./chatgpt-browser.js";
|
|
5
|
+
import { DEFAULT_CDP_PORT, resolveCdpPort, resolveConversationToDelete, resolveProjectToDelete, chatGptVisibilityBlocker, defaultChatGptProfileDir, formatDurationMs, getChatGptBrowserStatus, listChatGptModelOptions, deleteChatGptConversation, deleteChatGptProject, listChatGptProjectsWithIds, listRecentChatGptConversations, listChatGptSidebarProjects, normalizeChatGptTargetUrl, openChatGptBrowser, openChatGptTab, parseProMode, parseReasoningEffort, defaultTimeoutForTools, ensureVirtualDisplay, minimizeChatGptWindow, readLastBrowserLoginLaunch, resolveVirtualDisplayPreference, resolveBrowserWindowMode, resolveHeadlessPreference, recordBrowserLoginLaunch, recoverChatGptAnswerFromThread, sendChatGptPrompt } from "./chatgpt-browser.js";
|
|
6
6
|
import { ASK_PRO_BOOLEAN_FLAGS, ASK_PRO_PREVIEW_VALUE_FLAGS, ASK_PRO_VALUE_FLAGS, assertHelpRequestArgs, assertNoExtraArgs, assertOnlyOptions, findHelpFlagIndexBeforePromptDelimiter, formatCliCommand, hasAskProDryRunMode, hasAskProMode, hasAskProSendMode, isHelpSubcommand, parseAskProArgs, printHelpIfRequested, readFlag, readPortFlag, readPositionalsWithOptions, readNonNegativeIntegerFlag, readPositiveIntegerFlag, readRepeatedFlag, resolveCwdFlag, resolveOptionalFileFlag, unknownSubcommandError } from "./cli-args.js";
|
|
7
7
|
import { printProBrowserHelp, printProHelp } from "./cli-help.js";
|
|
8
8
|
import { listRawResultsForInspection, listTasksForInspection } from "./cli-ledger.js";
|
|
@@ -537,6 +537,63 @@ export async function runProCommand(rest, io, runCliFn) {
|
|
|
537
537
|
io.stderr(`recovered: answer saved to .bridge; re-print with \`prodex pro latest --cwd ${recoverCwd}\``);
|
|
538
538
|
return 0;
|
|
539
539
|
}
|
|
540
|
+
if (browserSubcommand === "chats") {
|
|
541
|
+
if (printProBrowserHelpIfRequested(browserArgs, "pro browser chats", io, { valueFlags: ["--port", "--timeout-ms", "--limit", "--source-cli"] }))
|
|
542
|
+
return 0;
|
|
543
|
+
assertOnlyOptions(browserArgs, "pro browser chats", ["--port", "--timeout-ms", "--limit", "--source-cli"]);
|
|
544
|
+
const chatsPort = readPortFlag(browserArgs, "--port");
|
|
545
|
+
const chatsTimeoutMs = readPositiveIntegerFlag(browserArgs, "--timeout-ms");
|
|
546
|
+
const chatsLimit = readPositiveIntegerFlag(browserArgs, "--limit");
|
|
547
|
+
const chats = await listRecentChatGptConversations({
|
|
548
|
+
...(chatsPort !== undefined ? { port: chatsPort } : {}),
|
|
549
|
+
...(chatsTimeoutMs !== undefined ? { timeoutMs: chatsTimeoutMs } : {}),
|
|
550
|
+
...(chatsLimit !== undefined ? { limit: chatsLimit } : {})
|
|
551
|
+
});
|
|
552
|
+
if (chats.length === 0) {
|
|
553
|
+
io.stdout("No recent conversations were readable.");
|
|
554
|
+
return 0;
|
|
555
|
+
}
|
|
556
|
+
io.stdout("Recent ChatGPT conversations (newest first):");
|
|
557
|
+
for (const chat of chats)
|
|
558
|
+
io.stdout(` ${chat.title} ${chat.id}`);
|
|
559
|
+
io.stdout("Delete one with `pro browser chat-delete --id <id> --confirm-delete`.");
|
|
560
|
+
return 0;
|
|
561
|
+
}
|
|
562
|
+
if (browserSubcommand === "chat-delete") {
|
|
563
|
+
if (printProBrowserHelpIfRequested(browserArgs, "pro browser chat-delete", io, {
|
|
564
|
+
valueFlags: ["--port", "--timeout-ms", "--title", "--id", "--limit", "--source-cli"],
|
|
565
|
+
booleanFlags: ["--confirm-delete"]
|
|
566
|
+
})) {
|
|
567
|
+
return 0;
|
|
568
|
+
}
|
|
569
|
+
assertOnlyOptions(browserArgs, "pro browser chat-delete", ["--port", "--timeout-ms", "--title", "--id", "--limit", "--source-cli"], ["--confirm-delete"]);
|
|
570
|
+
const chatDeletePort = readPortFlag(browserArgs, "--port");
|
|
571
|
+
const chatDeleteTimeoutMs = readPositiveIntegerFlag(browserArgs, "--timeout-ms");
|
|
572
|
+
const chatDeleteLimit = readPositiveIntegerFlag(browserArgs, "--limit");
|
|
573
|
+
const chats = await listRecentChatGptConversations({
|
|
574
|
+
...(chatDeletePort !== undefined ? { port: chatDeletePort } : {}),
|
|
575
|
+
...(chatDeleteTimeoutMs !== undefined ? { timeoutMs: chatDeleteTimeoutMs } : {}),
|
|
576
|
+
limit: chatDeleteLimit ?? 40
|
|
577
|
+
});
|
|
578
|
+
const chatTarget = resolveConversationToDelete(chats, {
|
|
579
|
+
...(readFlag(browserArgs, "--title") !== undefined ? { title: readFlag(browserArgs, "--title") } : {}),
|
|
580
|
+
...(readFlag(browserArgs, "--id") !== undefined ? { id: readFlag(browserArgs, "--id") } : {})
|
|
581
|
+
});
|
|
582
|
+
if (!chatTarget.ok)
|
|
583
|
+
throw new Error(chatTarget.reason);
|
|
584
|
+
if (!browserArgs.includes("--confirm-delete")) {
|
|
585
|
+
io.stdout(`Would delete the conversation "${chatTarget.title}" (${chatTarget.id}).`);
|
|
586
|
+
io.stdout("Nothing was deleted. Re-run with --confirm-delete to go ahead.");
|
|
587
|
+
return 0;
|
|
588
|
+
}
|
|
589
|
+
await deleteChatGptConversation({
|
|
590
|
+
conversationId: chatTarget.id,
|
|
591
|
+
...(chatDeletePort !== undefined ? { port: chatDeletePort } : {}),
|
|
592
|
+
...(chatDeleteTimeoutMs !== undefined ? { timeoutMs: chatDeleteTimeoutMs } : {})
|
|
593
|
+
});
|
|
594
|
+
io.stdout(`deleted conversation "${chatTarget.title}" (${chatTarget.id})`);
|
|
595
|
+
return 0;
|
|
596
|
+
}
|
|
540
597
|
if (browserSubcommand === "project-delete") {
|
|
541
598
|
if (printProBrowserHelpIfRequested(browserArgs, "pro browser project-delete", io, {
|
|
542
599
|
valueFlags: ["--cwd", "--port", "--timeout-ms", "--name", "--id", "--source-cli"],
|
|
@@ -580,6 +637,8 @@ export async function runProCommand(rest, io, runCliFn) {
|
|
|
580
637
|
"models",
|
|
581
638
|
"projects",
|
|
582
639
|
"project-delete",
|
|
640
|
+
"chats",
|
|
641
|
+
"chat-delete",
|
|
583
642
|
"recover"
|
|
584
643
|
]);
|
|
585
644
|
}
|