@youdie006/prodex 0.32.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 +138 -1
- package/dist/cli-help.js +14 -0
- package/dist/cli-pro.js +119 -4
- package/package.json +1 -1
package/dist/chatgpt-browser.js
CHANGED
|
@@ -2516,7 +2516,126 @@ export async function navigateChatGptTabTo(url, options = {}) {
|
|
|
2516
2516
|
cdp.close();
|
|
2517
2517
|
}
|
|
2518
2518
|
}
|
|
2519
|
-
/**
|
|
2519
|
+
/**
|
|
2520
|
+
* Which conversation a delete means - or why it refuses to guess.
|
|
2521
|
+
*
|
|
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.
|
|
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
|
+
}
|
|
2592
|
+
export function resolveProjectToDelete(projects, request) {
|
|
2593
|
+
if (request.id) {
|
|
2594
|
+
const byId = projects.find((project) => project.id === request.id);
|
|
2595
|
+
return byId ? { ok: true, id: byId.id, name: byId.name } : { ok: false, reason: `No project has the id ${request.id}.` };
|
|
2596
|
+
}
|
|
2597
|
+
const name = request.name?.trim();
|
|
2598
|
+
if (!name)
|
|
2599
|
+
return { ok: false, reason: "Name the project to delete with --name, or identify it with --id." };
|
|
2600
|
+
const matches = projects.filter((project) => project.name === name);
|
|
2601
|
+
if (matches.length === 0) {
|
|
2602
|
+
return { ok: false, reason: `No project is named exactly "${name}". Run \`prodex pro browser projects\` to see the names as they are stored.` };
|
|
2603
|
+
}
|
|
2604
|
+
if (matches.length > 1) {
|
|
2605
|
+
const ids = matches.map((project) => project.id).join(", ");
|
|
2606
|
+
return {
|
|
2607
|
+
ok: false,
|
|
2608
|
+
reason: `More than one project is named "${name}" (${ids}). Pass --id to say which one, since deleting the wrong one cannot be undone here.`
|
|
2609
|
+
};
|
|
2610
|
+
}
|
|
2611
|
+
return { ok: true, id: matches[0].id, name: matches[0].name };
|
|
2612
|
+
}
|
|
2613
|
+
/** Delete one project by id. The caller is responsible for confirming intent. */
|
|
2614
|
+
export function deleteProjectExpression(projectId) {
|
|
2615
|
+
return `(async () => {
|
|
2616
|
+
let token = "";
|
|
2617
|
+
try {
|
|
2618
|
+
const session = await fetch("/api/auth/session", { credentials: "include" });
|
|
2619
|
+
if (!session.ok) return { ok: false, reason: "session_http_" + session.status };
|
|
2620
|
+
const parsed = await session.json();
|
|
2621
|
+
token = (parsed && parsed.accessToken) || "";
|
|
2622
|
+
} catch (error) {
|
|
2623
|
+
return { ok: false, reason: "session_error" };
|
|
2624
|
+
}
|
|
2625
|
+
try {
|
|
2626
|
+
const response = await fetch("/backend-api/gizmos/" + ${JSON.stringify(projectId)}, {
|
|
2627
|
+
method: "DELETE",
|
|
2628
|
+
credentials: "include",
|
|
2629
|
+
headers: token ? { Authorization: "Bearer " + token, "Content-Type": "application/json" } : { "Content-Type": "application/json" }
|
|
2630
|
+
});
|
|
2631
|
+
const body = await response.text();
|
|
2632
|
+
if (!response.ok) return { ok: false, reason: "delete_http_" + response.status + " " + body.slice(0, 120) };
|
|
2633
|
+
return { ok: true, reason: "" };
|
|
2634
|
+
} catch (error) {
|
|
2635
|
+
return { ok: false, reason: "delete_error" };
|
|
2636
|
+
}
|
|
2637
|
+
})()`;
|
|
2638
|
+
}
|
|
2520
2639
|
export async function listChatGptProjectsWithIds(input = {}) {
|
|
2521
2640
|
const port = resolveCdpPort(input.port);
|
|
2522
2641
|
const page = await findChatGptPage(port, input.timeoutMs ?? 3_000);
|
|
@@ -2530,6 +2649,24 @@ export async function listChatGptProjectsWithIds(input = {}) {
|
|
|
2530
2649
|
return [];
|
|
2531
2650
|
}
|
|
2532
2651
|
}
|
|
2652
|
+
/** Delete one project. Callers must have confirmed intent before calling. */
|
|
2653
|
+
export async function deleteChatGptProject(input) {
|
|
2654
|
+
const port = resolveCdpPort(input.port);
|
|
2655
|
+
const page = await findChatGptPage(port, input.timeoutMs ?? 3_000);
|
|
2656
|
+
if (!page.ok || !page.page) {
|
|
2657
|
+
throw new ChatGptBrowserBlockerError(page.blocker ?? {
|
|
2658
|
+
code: "browser_unreachable",
|
|
2659
|
+
message: `No Chrome DevTools endpoint is reachable on 127.0.0.1:${port}.`,
|
|
2660
|
+
retryable: true,
|
|
2661
|
+
next_step: "Run `prodex pro browser login` to reopen the dedicated window, then retry."
|
|
2662
|
+
});
|
|
2663
|
+
}
|
|
2664
|
+
const result = await evaluateOnPage(page.page, deleteProjectExpression(input.projectId), {
|
|
2665
|
+
timeoutMs: 30_000
|
|
2666
|
+
});
|
|
2667
|
+
if (!result?.ok)
|
|
2668
|
+
throw new Error(`ChatGPT refused to delete the project: ${result?.reason ?? "unknown reason"}`);
|
|
2669
|
+
}
|
|
2533
2670
|
export async function listRecentChatGptConversations(input = {}) {
|
|
2534
2671
|
const port = resolveCdpPort(input.port);
|
|
2535
2672
|
const page = await findChatGptPage(port, input.timeoutMs ?? 3_000);
|
package/dist/cli-help.js
CHANGED
|
@@ -263,6 +263,17 @@ export function printProBrowserHelp(stdout, sourceCli) {
|
|
|
263
263
|
: "prodex pro browser projects [--source-cli /absolute/path/to/dist/cli.js] [--port 9333] [--timeout-ms 15000] # read-only: exact sidebar project names";
|
|
264
264
|
// A send that outlives its budget is not a lost answer, but only if agents
|
|
265
265
|
// know this exists - and this help is where onboarding sends them.
|
|
266
|
+
// Deleting a project takes its chats with it, so the usage line says so and
|
|
267
|
+
// the flag that actually deletes is spelled out rather than implied.
|
|
268
|
+
const projectDeleteUsage = sourceCli
|
|
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
|
+
: `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`;
|
|
266
277
|
const recoverUsage = sourceCli
|
|
267
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`
|
|
268
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";
|
|
@@ -274,6 +285,9 @@ Commands:
|
|
|
274
285
|
${smokeUsage}
|
|
275
286
|
${modelsUsage}
|
|
276
287
|
${projectsUsage}
|
|
288
|
+
${projectDeleteUsage}
|
|
289
|
+
${chatsUsage}
|
|
290
|
+
${chatDeleteUsage}
|
|
277
291
|
${askUsage}
|
|
278
292
|
${recoverUsage}
|
|
279
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, chatGptVisibilityBlocker, defaultChatGptProfileDir, formatDurationMs, getChatGptBrowserStatus, listChatGptModelOptions, 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";
|
|
@@ -463,8 +463,20 @@ export async function runProCommand(rest, io, runCliFn) {
|
|
|
463
463
|
return 0;
|
|
464
464
|
}
|
|
465
465
|
io.stdout("ChatGPT sidebar projects (read-only; exact names as rendered):");
|
|
466
|
-
|
|
467
|
-
|
|
466
|
+
// The rendered sidebar can lag reality - it still showed a project that
|
|
467
|
+
// had just been deleted - so print the account's own listing when it is
|
|
468
|
+
// readable, and its ids, which `project-delete --id` needs to tell two
|
|
469
|
+
// projects of the same name apart.
|
|
470
|
+
const withIds = await listChatGptProjectsWithIds({
|
|
471
|
+
...(projectsPort !== undefined ? { port: projectsPort } : {}),
|
|
472
|
+
...(projectsTimeoutMs !== undefined ? { timeoutMs: projectsTimeoutMs } : {})
|
|
473
|
+
}).catch(() => []);
|
|
474
|
+
if (withIds.length > 0)
|
|
475
|
+
for (const project of withIds)
|
|
476
|
+
io.stdout(` ${project.name} ${project.id}`);
|
|
477
|
+
else
|
|
478
|
+
for (const name of listed.projects)
|
|
479
|
+
io.stdout(` ${name}`);
|
|
468
480
|
io.stdout("Use with `pro browser ask --project \"<name>\"` or pin one with `prodex setup --project \"<name>\"`.");
|
|
469
481
|
return 0;
|
|
470
482
|
}
|
|
@@ -525,7 +537,110 @@ export async function runProCommand(rest, io, runCliFn) {
|
|
|
525
537
|
io.stderr(`recovered: answer saved to .bridge; re-print with \`prodex pro latest --cwd ${recoverCwd}\``);
|
|
526
538
|
return 0;
|
|
527
539
|
}
|
|
528
|
-
|
|
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
|
+
}
|
|
597
|
+
if (browserSubcommand === "project-delete") {
|
|
598
|
+
if (printProBrowserHelpIfRequested(browserArgs, "pro browser project-delete", io, {
|
|
599
|
+
valueFlags: ["--cwd", "--port", "--timeout-ms", "--name", "--id", "--source-cli"],
|
|
600
|
+
booleanFlags: ["--confirm-delete"]
|
|
601
|
+
})) {
|
|
602
|
+
return 0;
|
|
603
|
+
}
|
|
604
|
+
assertOnlyOptions(browserArgs, "pro browser project-delete", ["--cwd", "--port", "--timeout-ms", "--name", "--id", "--source-cli"], ["--confirm-delete"]);
|
|
605
|
+
const deletePort = readPortFlag(browserArgs, "--port");
|
|
606
|
+
const deleteTimeoutMs = readPositiveIntegerFlag(browserArgs, "--timeout-ms");
|
|
607
|
+
const projects = await listChatGptProjectsWithIds({
|
|
608
|
+
...(deletePort !== undefined ? { port: deletePort } : {}),
|
|
609
|
+
...(deleteTimeoutMs !== undefined ? { timeoutMs: deleteTimeoutMs } : {})
|
|
610
|
+
});
|
|
611
|
+
const target = resolveProjectToDelete(projects, {
|
|
612
|
+
...(readFlag(browserArgs, "--name") !== undefined ? { name: readFlag(browserArgs, "--name") } : {}),
|
|
613
|
+
...(readFlag(browserArgs, "--id") !== undefined ? { id: readFlag(browserArgs, "--id") } : {})
|
|
614
|
+
});
|
|
615
|
+
if (!target.ok)
|
|
616
|
+
throw new Error(target.reason);
|
|
617
|
+
// Deleting a project is not undoable from here, so the default is a
|
|
618
|
+
// preview: say exactly what would go, and delete nothing.
|
|
619
|
+
if (!browserArgs.includes("--confirm-delete")) {
|
|
620
|
+
io.stdout(`Would delete project "${target.name}" (${target.id}) and everything filed under it.`);
|
|
621
|
+
io.stdout("Nothing was deleted. Re-run with --confirm-delete to go ahead.");
|
|
622
|
+
return 0;
|
|
623
|
+
}
|
|
624
|
+
await deleteChatGptProject({
|
|
625
|
+
projectId: target.id,
|
|
626
|
+
...(deletePort !== undefined ? { port: deletePort } : {}),
|
|
627
|
+
...(deleteTimeoutMs !== undefined ? { timeoutMs: deleteTimeoutMs } : {})
|
|
628
|
+
});
|
|
629
|
+
io.stdout(`deleted project "${target.name}" (${target.id})`);
|
|
630
|
+
return 0;
|
|
631
|
+
}
|
|
632
|
+
throw unknownSubcommandError("pro browser", browserSubcommand, [
|
|
633
|
+
"login",
|
|
634
|
+
"ask",
|
|
635
|
+
"smoke",
|
|
636
|
+
"check",
|
|
637
|
+
"models",
|
|
638
|
+
"projects",
|
|
639
|
+
"project-delete",
|
|
640
|
+
"chats",
|
|
641
|
+
"chat-delete",
|
|
642
|
+
"recover"
|
|
643
|
+
]);
|
|
529
644
|
}
|
|
530
645
|
if (subcommand === "open" || subcommand === "status" || subcommand === "smoke" || subcommand === "check" || subcommand === "doctor") {
|
|
531
646
|
// Point at a subcommand that EXISTS: `pro status` used to say "use `pro
|