ai-browser-bridge 0.5.1 → 0.6.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/bridge.js CHANGED
@@ -11150,7 +11150,7 @@ var serveAskGatewayStdio = async (deps) => {
11150
11150
  // src/features/terminal/chatOrganizationQueue.ts
11151
11151
  import { createHash as createHash2, randomUUID as randomUUID4 } from "crypto";
11152
11152
  import { existsSync } from "fs";
11153
- import { mkdir as mkdir7, open, readFile as readFile10, rename, unlink, writeFile as writeFile5 } from "fs/promises";
11153
+ import { mkdir as mkdir7, open, readdir as readdir5, readFile as readFile10, rename, unlink, writeFile as writeFile5 } from "fs/promises";
11154
11154
  import { dirname as dirname3, isAbsolute, join as join11, resolve as resolve7 } from "path";
11155
11155
  import { Schema as Schema8 } from "effect";
11156
11156
  var ChatOrganizationTaskSchema = Schema8.Struct({
@@ -11187,14 +11187,34 @@ var ChatOrganizationQueueItemSchema = Schema8.Union(
11187
11187
  CompletedQueueItemSchema,
11188
11188
  FailedQueueItemSchema
11189
11189
  );
11190
+ var ChatOrganizationPacingSchema = Schema8.Struct({
11191
+ currentSeconds: Schema8.Number.pipe(Schema8.int(), Schema8.positive()),
11192
+ successStreak: Schema8.Number.pipe(Schema8.int(), Schema8.nonNegative()),
11193
+ rateLimitCount: Schema8.Number.pipe(Schema8.int(), Schema8.nonNegative())
11194
+ });
11195
+ var ChatOrganizationVerificationSchema = Schema8.Struct({
11196
+ complete: Schema8.Boolean,
11197
+ inventoryComplete: Schema8.Boolean,
11198
+ remainingOrphans: Schema8.Number.pipe(Schema8.int(), Schema8.nonNegative()),
11199
+ plannedStillLoose: Schema8.Array(Schema8.String),
11200
+ verifiedAt: Schema8.String,
11201
+ error: Schema8.optional(Schema8.String)
11202
+ });
11190
11203
  var ChatOrganizationQueueSchema = Schema8.Struct({
11191
11204
  version: Schema8.Literal(1),
11192
11205
  fingerprint: Schema8.String,
11193
11206
  createdAt: Schema8.String,
11194
11207
  updatedAt: Schema8.String,
11195
- items: Schema8.Array(ChatOrganizationQueueItemSchema).pipe(Schema8.minItems(1))
11208
+ items: Schema8.Array(ChatOrganizationQueueItemSchema).pipe(Schema8.minItems(1)),
11209
+ pacing: Schema8.optional(ChatOrganizationPacingSchema),
11210
+ verification: Schema8.optional(ChatOrganizationVerificationSchema)
11196
11211
  });
11197
11212
  var ORGANIZATION_INTERVAL = /^(?<minimum>\d+)(?:-(?<maximum>\d+))?$/u;
11213
+ var CLOSED_BROWSER_SESSION = /(?:target page, context or browser has been closed|browser has been closed|context has been closed|page has been closed)/iu;
11214
+ var chatOrganizationSessionWasClosed = (reason) => {
11215
+ if (reason === void 0) return false;
11216
+ return CLOSED_BROWSER_SESSION.test(reason);
11217
+ };
11198
11218
  var chatOrganizationIntervalFrom = (value, defaultSeconds) => {
11199
11219
  if (value === void 0) {
11200
11220
  return { minimumSeconds: defaultSeconds, maximumSeconds: defaultSeconds };
@@ -11218,6 +11238,40 @@ var nextChatOrganizationIntervalSeconds = (interval, randomFraction) => {
11218
11238
  const width = interval.maximumSeconds - interval.minimumSeconds + 1;
11219
11239
  return interval.minimumSeconds + Math.floor(randomFraction * width);
11220
11240
  };
11241
+ var initialChatOrganizationPacing = (currentSeconds) => ({
11242
+ currentSeconds,
11243
+ successStreak: 0,
11244
+ rateLimitCount: 0
11245
+ });
11246
+ var constrainChatOrganizationPacing = (pacing, options) => ({
11247
+ ...pacing,
11248
+ currentSeconds: Math.min(
11249
+ options.maximumSeconds,
11250
+ Math.max(options.minimumSeconds, pacing.currentSeconds)
11251
+ ),
11252
+ successStreak: Math.min(pacing.successStreak, options.speedUpAfter - 1)
11253
+ });
11254
+ var adaptiveChatOrganizationPacingAfterSuccess = (pacing, options) => {
11255
+ const successStreak = pacing.successStreak + 1;
11256
+ if (successStreak < options.speedUpAfter) return { ...pacing, successStreak };
11257
+ return {
11258
+ ...pacing,
11259
+ currentSeconds: Math.min(
11260
+ pacing.currentSeconds,
11261
+ Math.max(options.minimumSeconds, Math.floor(pacing.currentSeconds * 0.8))
11262
+ ),
11263
+ successStreak: 0
11264
+ };
11265
+ };
11266
+ var adaptiveChatOrganizationPacingAfterRateLimit = (pacing, options) => ({
11267
+ currentSeconds: Math.min(options.maximumSeconds, Math.ceil(pacing.currentSeconds * 1.5)),
11268
+ successStreak: 0,
11269
+ rateLimitCount: pacing.rateLimitCount + 1
11270
+ });
11271
+ var nextAdaptiveChatOrganizationIntervalSeconds = (pacing, randomFraction) => {
11272
+ const jitter = Math.max(1, Math.ceil(pacing.currentSeconds * 0.2));
11273
+ return pacing.currentSeconds + Math.floor(randomFraction * (jitter + 1));
11274
+ };
11221
11275
  var chatOrganizationIntervalLabel = (interval) => {
11222
11276
  if (interval.minimumSeconds === interval.maximumSeconds) return `${interval.minimumSeconds}s`;
11223
11277
  return `${interval.minimumSeconds}-${interval.maximumSeconds}s`;
@@ -11294,11 +11348,98 @@ var persistChatOrganizationQueue = async (queuePath, queue) => {
11294
11348
  }
11295
11349
  }
11296
11350
  };
11351
+ var updateChatOrganizationQueuePacing = (input) => ({
11352
+ ...input.queue,
11353
+ pacing: input.pacing,
11354
+ updatedAt: input.timestamp
11355
+ });
11356
+ var updateChatOrganizationQueueVerification = (input) => ({
11357
+ ...input.queue,
11358
+ verification: input.verification,
11359
+ updatedAt: input.timestamp
11360
+ });
11297
11361
  var errorCodeOf = (error) => {
11298
11362
  if (typeof error !== "object" || error === null || !("code" in error)) return void 0;
11299
11363
  if (typeof error.code !== "string") return void 0;
11300
11364
  return error.code;
11301
11365
  };
11366
+ var chatOrganizationPausePath = (queuePath) => `${queuePath}.pause`;
11367
+ var chatOrganizationQueueIsPaused = async (queuePath) => existsSync(chatOrganizationPausePath(queuePath));
11368
+ var pauseChatOrganizationQueue = async (queuePath, timestamp) => {
11369
+ await mkdir7(dirname3(queuePath), { recursive: true });
11370
+ await writeFile5(
11371
+ chatOrganizationPausePath(queuePath),
11372
+ `${JSON.stringify({ pausedAt: timestamp })}
11373
+ `,
11374
+ "utf8"
11375
+ );
11376
+ };
11377
+ var clearChatOrganizationQueuePause = async (queuePath) => {
11378
+ try {
11379
+ await unlink(chatOrganizationPausePath(queuePath));
11380
+ } catch (error) {
11381
+ if (errorCodeOf(error) !== "ENOENT") throw error;
11382
+ }
11383
+ };
11384
+ var organizationQueueIsRunning = async (queuePath) => {
11385
+ let owner;
11386
+ try {
11387
+ owner = JSON.parse(await readFile10(`${queuePath}.lock`, "utf8"));
11388
+ } catch {
11389
+ return { running: false };
11390
+ }
11391
+ if (typeof owner !== "object" || owner === null || !("pid" in owner)) {
11392
+ return { running: false };
11393
+ }
11394
+ if (typeof owner.pid !== "number" || !Number.isInteger(owner.pid)) return { running: false };
11395
+ try {
11396
+ process.kill(owner.pid, 0);
11397
+ return { running: true, ownerPid: owner.pid };
11398
+ } catch (error) {
11399
+ if (errorCodeOf(error) === "ESRCH") return { running: false, ownerPid: owner.pid };
11400
+ return { running: true, ownerPid: owner.pid };
11401
+ }
11402
+ };
11403
+ var readChatOrganizationQueue = async (queuePath) => {
11404
+ const stored = JSON.parse(await readFile10(queuePath, "utf8"));
11405
+ return Schema8.decodeUnknownSync(ChatOrganizationQueueSchema)(stored);
11406
+ };
11407
+ var resolveChatOrganizationQueue = async (repoRoot, selector) => {
11408
+ const queueDirectory = join11(bridgeDir(repoRoot), "chat-organization-queues");
11409
+ let queuePath;
11410
+ if (selector?.trim()) {
11411
+ const trimmed = selector.trim();
11412
+ if (isAbsolute(trimmed) || trimmed.includes("/")) queuePath = resolve7(repoRoot, trimmed);
11413
+ else queuePath = join11(queueDirectory, trimmed.endsWith(".json") ? trimmed : `${trimmed}.json`);
11414
+ } else {
11415
+ let names;
11416
+ try {
11417
+ names = (await readdir5(queueDirectory)).filter((name) => /^[a-f0-9]{16}\.json$/u.test(name));
11418
+ } catch (error) {
11419
+ if (errorCodeOf(error) === "ENOENT") names = [];
11420
+ else throw error;
11421
+ }
11422
+ const queues = await Promise.all(
11423
+ names.map(async (name) => {
11424
+ const path2 = join11(queueDirectory, name);
11425
+ return { path: path2, queue: await readChatOrganizationQueue(path2) };
11426
+ })
11427
+ );
11428
+ queues.sort((left, right) => right.queue.updatedAt.localeCompare(left.queue.updatedAt));
11429
+ queuePath = queues[0]?.path;
11430
+ }
11431
+ if (queuePath === void 0 || !existsSync(queuePath)) {
11432
+ throw new Error("No persisted ChatGPT organization queue was found.");
11433
+ }
11434
+ const queue = await readChatOrganizationQueue(queuePath);
11435
+ const ownership = await organizationQueueIsRunning(queuePath);
11436
+ return {
11437
+ path: queuePath,
11438
+ queue,
11439
+ paused: await chatOrganizationQueueIsPaused(queuePath),
11440
+ ...ownership
11441
+ };
11442
+ };
11302
11443
  var removeStaleQueueLock = async (lockPath) => {
11303
11444
  let owner;
11304
11445
  try {
@@ -11429,6 +11570,47 @@ var summarizeChatOrganizationQueue = (queue) => {
11429
11570
  }
11430
11571
  return summary;
11431
11572
  };
11573
+ var conversationIdentity = (value) => {
11574
+ const trimmed = value.trim();
11575
+ const conversationPath = /\/c\/(?<id>[^/?#]+)/u.exec(trimmed)?.groups?.id;
11576
+ if (conversationPath !== void 0) return conversationPath;
11577
+ return trimmed;
11578
+ };
11579
+ var reopenChatOrganizationQueueItems = (input) => {
11580
+ const targets = new Set(input.conversations.map(conversationIdentity));
11581
+ let changed = false;
11582
+ const items = input.queue.items.map((item) => {
11583
+ if (item.status !== "moved" && item.status !== "already-filed" || item.attempts >= input.maxAttempts || !targets.has(conversationIdentity(item.conversation))) {
11584
+ return item;
11585
+ }
11586
+ changed = true;
11587
+ return {
11588
+ status: "pending",
11589
+ conversation: item.conversation,
11590
+ project: item.project,
11591
+ attempts: item.attempts,
11592
+ lastReason: "Full-history audit found the Conversation still loose."
11593
+ };
11594
+ });
11595
+ if (!changed) return input.queue;
11596
+ return { ...input.queue, items, updatedAt: input.timestamp };
11597
+ };
11598
+ var chatOrganizationVerificationFrom = (input) => {
11599
+ const orphanIdentities = /* @__PURE__ */ new Set();
11600
+ for (const orphan of input.orphans) {
11601
+ orphanIdentities.add(conversationIdentity(orphan.id));
11602
+ orphanIdentities.add(orphan.title.trim());
11603
+ }
11604
+ const plannedStillLoose = input.queue.items.filter((item) => orphanIdentities.has(conversationIdentity(item.conversation))).map((item) => item.conversation);
11605
+ const summary = summarizeChatOrganizationQueue(input.queue);
11606
+ return {
11607
+ complete: summary.pending === 0 && summary.failed === 0 && plannedStillLoose.length === 0,
11608
+ inventoryComplete: true,
11609
+ remainingOrphans: input.orphans.length,
11610
+ plannedStillLoose,
11611
+ verifiedAt: input.timestamp
11612
+ };
11613
+ };
11432
11614
 
11433
11615
  // src/features/terminal/providerLabel.ts
11434
11616
  var providerDisplayName = (id2) => {
@@ -11995,7 +12177,7 @@ var applyInputSuggestion = (input, group, index = 0) => {
11995
12177
  };
11996
12178
 
11997
12179
  // src/features/terminal/tui/composer/fileAutocompleteComplete.ts
11998
- import { readdir as readdir5 } from "fs/promises";
12180
+ import { readdir as readdir6 } from "fs/promises";
11999
12181
 
12000
12182
  // src/features/terminal/tui/composer/fileAutocompleteTypes.ts
12001
12183
  var DEFAULT_COMPLETION_LIMIT = 20;
@@ -12100,7 +12282,7 @@ var completionSearchDirectory = (input) => {
12100
12282
  };
12101
12283
  var readCompletionMatches = async (input) => {
12102
12284
  try {
12103
- const dirents = await readdir5(input.absoluteSearchDir, { withFileTypes: true });
12285
+ const dirents = await readdir6(input.absoluteSearchDir, { withFileTypes: true });
12104
12286
  return dirents.filter((dirent) => dirent.isDirectory() || dirent.isFile()).filter((dirent) => !IGNORED_COMPLETION_ENTRIES.has(dirent.name)).filter((dirent) => input.namePrefix.startsWith(".") || !dirent.name.startsWith(".")).filter((dirent) => dirent.name.startsWith(input.namePrefix)).map((dirent) => mapDirent({ dirent, dirPrefix: input.dirPrefix })).sort((left, right) => compareCompletionMatches(left, right)).slice(0, input.limit);
12105
12287
  } catch {
12106
12288
  return [];
@@ -12141,7 +12323,7 @@ var hasTrailingWhitespace = (input) => {
12141
12323
  };
12142
12324
 
12143
12325
  // src/features/terminal/tui/suggestions/repoPathSuggestions.ts
12144
- import { readdir as readdir6 } from "fs/promises";
12326
+ import { readdir as readdir7 } from "fs/promises";
12145
12327
  import { extname, sep as sep3 } from "path";
12146
12328
  var IGNORED_COMPLETION_ENTRIES2 = /* @__PURE__ */ new Set([
12147
12329
  ".git",
@@ -12186,7 +12368,7 @@ var searchDirectory = (input) => {
12186
12368
  };
12187
12369
  var listMatchingEntries = async (input) => {
12188
12370
  try {
12189
- const entries = await readdir6(input.absoluteSearchDir, { withFileTypes: true });
12371
+ const entries = await readdir7(input.absoluteSearchDir, { withFileTypes: true });
12190
12372
  return entries.filter((entry) => isCompletableEntry({ name: entry.name, namePrefix: input.namePrefix })).filter((entry) => matchesKind({ entry, kind: input.kind, namePrefix: input.namePrefix })).map((entry) => pathEntrySuggestion(entry.name, input.dirPrefix, entry.isDirectory())).sort(comparePathSuggestions).slice(0, input.limit);
12191
12373
  } catch {
12192
12374
  return [];
@@ -15076,11 +15258,15 @@ var runChatMove = async (chat, options) => {
15076
15258
  writeMoveOutcomes(outcomes, options);
15077
15259
  process.exit(outcomes.every((outcome) => outcome.moved || outcome.alreadyFiled) ? 0 : 1);
15078
15260
  };
15079
- var DEFAULT_ORGANIZATION_INTERVAL_SECONDS = 30;
15080
- var DEFAULT_ORGANIZATION_COOLDOWN_SECONDS = 300;
15081
- var DEFAULT_ORGANIZATION_MAX_ATTEMPTS = 3;
15261
+ var DEFAULT_ORGANIZATION_INTERVAL_SECONDS = 60;
15262
+ var DEFAULT_ORGANIZATION_MIN_INTERVAL_SECONDS = 15;
15263
+ var DEFAULT_ORGANIZATION_MAX_INTERVAL_SECONDS = 180;
15264
+ var DEFAULT_ORGANIZATION_SPEED_UP_AFTER = 3;
15265
+ var DEFAULT_ORGANIZATION_COOLDOWN_SECONDS = 600;
15266
+ var DEFAULT_ORGANIZATION_MAX_ATTEMPTS = 4;
15082
15267
  var MAX_CONSECUTIVE_ORGANIZATION_COOLDOWNS = 12;
15083
15268
  var RATE_LIMIT_REASON = "ChatGPT temporarily limited access to Conversation history.";
15269
+ var CLOSED_SESSION_REASON = "ChatGPT browser session closed; reopening before retry.";
15084
15270
  var positiveIntegerOption = (value, optionName, defaultValue) => {
15085
15271
  if (value === void 0) return defaultValue;
15086
15272
  if (!/^[1-9]\d*$/u.test(value.trim())) {
@@ -15096,8 +15282,16 @@ var organizationIntervalOption = (value) => {
15096
15282
  return fail(error instanceof Error ? error.message : String(error));
15097
15283
  }
15098
15284
  };
15099
- var waitForOrganizationInterval = async (seconds) => {
15100
- await new Promise((complete) => setTimeout(complete, seconds * 1e3));
15285
+ var waitForOrganizationInterval = async (seconds, queuePath) => {
15286
+ let remainingMilliseconds = seconds * 1e3;
15287
+ while (remainingMilliseconds > 0) {
15288
+ if (await chatOrganizationQueueIsPaused(queuePath)) return "paused";
15289
+ const slice = Math.min(1e3, remainingMilliseconds);
15290
+ await new Promise((complete) => setTimeout(complete, slice));
15291
+ remainingMilliseconds -= slice;
15292
+ }
15293
+ if (await chatOrganizationQueueIsPaused(queuePath)) return "paused";
15294
+ return "elapsed";
15101
15295
  };
15102
15296
  var writeChatOrganizationProgress = (message, options) => {
15103
15297
  if (options.json) {
@@ -15115,18 +15309,29 @@ var moveFailureReason = (outcome) => {
15115
15309
  var writeChatOrganizationSummary = (input) => {
15116
15310
  const summary = summarizeChatOrganizationQueue(input.queue);
15117
15311
  if (input.options.json) {
15118
- process.stdout.write(`${JSON.stringify({ queuePath: input.queuePath, summary })}
15119
- `);
15312
+ process.stdout.write(
15313
+ `${JSON.stringify({
15314
+ queuePath: input.queuePath,
15315
+ state: input.paused ? "paused" : "finished",
15316
+ summary,
15317
+ pacing: input.queue.pacing,
15318
+ verification: input.queue.verification
15319
+ })}
15320
+ `
15321
+ );
15120
15322
  return;
15121
15323
  }
15122
15324
  process.stdout.write(
15123
15325
  `${[
15124
- "Organization queue finished.",
15326
+ input.paused ? "Organization queue paused." : "Organization queue finished.",
15125
15327
  `Moved: ${summary.moved}`,
15126
15328
  `Already filed: ${summary.alreadyFiled}`,
15329
+ `Pending: ${summary.pending}`,
15127
15330
  `Failed: ${summary.failed}`,
15331
+ input.queue.pacing === void 0 ? void 0 : `Adaptive pace: ${input.queue.pacing.currentSeconds}s base (${input.queue.pacing.rateLimitCount} rate limits)`,
15332
+ input.queue.verification === void 0 ? void 0 : `Full-history verification: ${input.queue.verification.complete ? "complete" : "incomplete"}; ${input.queue.verification.remainingOrphans} intentional/remaining orphans`,
15128
15333
  `Queue state: ${input.queuePath}`
15129
- ].join("\n")}
15334
+ ].filter((line) => line !== void 0).join("\n")}
15130
15335
  `
15131
15336
  );
15132
15337
  };
@@ -15137,6 +15342,10 @@ var writeChatOrganizationDryRun = (input) => {
15137
15342
  interval: input.interval,
15138
15343
  cooldownSeconds: input.cooldownSeconds,
15139
15344
  maxAttempts: input.maxAttempts,
15345
+ adaptive: input.adaptive,
15346
+ minimumIntervalSeconds: input.minimumIntervalSeconds,
15347
+ maximumIntervalSeconds: input.maximumIntervalSeconds,
15348
+ speedUpAfter: input.speedUpAfter,
15140
15349
  tasks: input.tasks
15141
15350
  };
15142
15351
  if (input.options.json) {
@@ -15148,6 +15357,7 @@ var writeChatOrganizationDryRun = (input) => {
15148
15357
  `${[
15149
15358
  `Organization queue dry run: ${input.tasks.length} Conversations`,
15150
15359
  `Interval: ${chatOrganizationIntervalLabel(input.interval)}`,
15360
+ `Adaptive pacing: ${input.adaptive ? `yes (${input.minimumIntervalSeconds}-${input.maximumIntervalSeconds}s; speed up after ${input.speedUpAfter} successes)` : "no"}`,
15151
15361
  `Rate-limit cooldown: ${input.cooldownSeconds}s`,
15152
15362
  `Attempts per Conversation: ${input.maxAttempts}`,
15153
15363
  `Resume state: ${input.queuePath}`,
@@ -15159,7 +15369,14 @@ var writeChatOrganizationDryRun = (input) => {
15159
15369
  var recordChatOrganizationAttempt = async (input) => {
15160
15370
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
15161
15371
  let queue;
15162
- if (input.rateLimited) {
15372
+ if (input.sessionClosed) {
15373
+ queue = deferChatOrganizationQueueItem({
15374
+ queue: input.queue,
15375
+ index: input.index,
15376
+ reason: CLOSED_SESSION_REASON,
15377
+ timestamp
15378
+ });
15379
+ } else if (input.rateLimited) {
15163
15380
  queue = deferChatOrganizationQueueItem({
15164
15381
  queue: input.queue,
15165
15382
  index: input.index,
@@ -15195,6 +15412,132 @@ var recordChatOrganizationAttempt = async (input) => {
15195
15412
  await persistChatOrganizationQueue(input.queuePath, queue);
15196
15413
  return queue;
15197
15414
  };
15415
+ var persistChatOrganizationPacing = async (input) => {
15416
+ const queue = updateChatOrganizationQueuePacing({
15417
+ queue: input.queue,
15418
+ pacing: input.pacing,
15419
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
15420
+ });
15421
+ await persistChatOrganizationQueue(input.queuePath, queue);
15422
+ return queue;
15423
+ };
15424
+ var verifyCompletedChatOrganizationQueue = async (input) => {
15425
+ writeChatOrganizationProgress(
15426
+ "Verifying the completed plan against an exhaustive full-history orphan scan.",
15427
+ input.options
15428
+ );
15429
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
15430
+ let verification;
15431
+ try {
15432
+ const orphans = await input.workspace.engine.getOrchestrator().listConversations({ orphans: true });
15433
+ verification = chatOrganizationVerificationFrom({
15434
+ queue: input.queue,
15435
+ orphans,
15436
+ timestamp
15437
+ });
15438
+ } catch (error) {
15439
+ verification = {
15440
+ complete: false,
15441
+ inventoryComplete: false,
15442
+ remainingOrphans: 0,
15443
+ plannedStillLoose: [],
15444
+ verifiedAt: timestamp,
15445
+ error: error instanceof Error ? error.message : String(error)
15446
+ };
15447
+ }
15448
+ let queue = updateChatOrganizationQueueVerification({
15449
+ queue: input.queue,
15450
+ verification,
15451
+ timestamp
15452
+ });
15453
+ if (verification.plannedStillLoose.length > 0) {
15454
+ queue = reopenChatOrganizationQueueItems({
15455
+ queue,
15456
+ conversations: verification.plannedStillLoose,
15457
+ maxAttempts: input.maxAttempts,
15458
+ timestamp
15459
+ });
15460
+ }
15461
+ await persistChatOrganizationQueue(input.queuePath, queue);
15462
+ if (verification.inventoryComplete) {
15463
+ writeChatOrganizationProgress(
15464
+ `Full-history scan reached the stable end: ${verification.remainingOrphans} loose Conversations remain; ${verification.plannedStillLoose.length} planned Conversations are still loose.`,
15465
+ input.options
15466
+ );
15467
+ } else {
15468
+ writeChatOrganizationProgress(
15469
+ `Full-history verification could not prove completion: ${verification.error ?? "unknown scan failure"}`,
15470
+ input.options
15471
+ );
15472
+ }
15473
+ return queue;
15474
+ };
15475
+ var organizationQueueState = (input) => {
15476
+ if (input.running) return input.paused ? "pausing" : "running";
15477
+ if (input.paused) return "paused";
15478
+ if (input.summary.pending === 0) return input.summary.failed > 0 ? "failed" : "completed";
15479
+ return "idle";
15480
+ };
15481
+ var runChatOrganizeStatus = async (options) => {
15482
+ const selected = await resolveChatOrganizationQueue(repositoryRoot(options.repo), options.queue);
15483
+ const summary = summarizeChatOrganizationQueue(selected.queue);
15484
+ const state = organizationQueueState({
15485
+ paused: selected.paused,
15486
+ running: selected.running,
15487
+ summary
15488
+ });
15489
+ const status = {
15490
+ state,
15491
+ queuePath: selected.path,
15492
+ ownerPid: selected.ownerPid,
15493
+ summary,
15494
+ pacing: selected.queue.pacing,
15495
+ verification: selected.queue.verification
15496
+ };
15497
+ if (options.json) process.stdout.write(`${JSON.stringify(status)}
15498
+ `);
15499
+ else {
15500
+ process.stdout.write(
15501
+ `${[
15502
+ `Organization queue: ${state}`,
15503
+ `Moved: ${summary.moved}`,
15504
+ `Already filed: ${summary.alreadyFiled}`,
15505
+ `Pending: ${summary.pending}`,
15506
+ `Failed: ${summary.failed}`,
15507
+ selected.queue.pacing === void 0 ? "Adaptive pace: not initialized" : `Adaptive pace: ${selected.queue.pacing.currentSeconds}s base (${selected.queue.pacing.successStreak} success streak; ${selected.queue.pacing.rateLimitCount} rate limits)`,
15508
+ selected.queue.verification === void 0 ? "Full-history verification: not run" : `Full-history verification: ${selected.queue.verification.complete ? "complete" : "incomplete"}`,
15509
+ `Queue state: ${selected.path}`
15510
+ ].join("\n")}
15511
+ `
15512
+ );
15513
+ }
15514
+ };
15515
+ var runChatOrganizePause = async (options) => {
15516
+ const selected = await resolveChatOrganizationQueue(repositoryRoot(options.repo), options.queue);
15517
+ await pauseChatOrganizationQueue(selected.path, (/* @__PURE__ */ new Date()).toISOString());
15518
+ const message = selected.running ? "Pause requested; the active UI operation will finish before the queue releases its lock." : "Organization queue paused.";
15519
+ if (options.json) {
15520
+ process.stdout.write(
15521
+ `${JSON.stringify({ state: selected.running ? "pausing" : "paused", queuePath: selected.path })}
15522
+ `
15523
+ );
15524
+ } else process.stdout.write(`${message}
15525
+ Queue state: ${selected.path}
15526
+ `);
15527
+ };
15528
+ var runChatOrganizeResume = async (options) => {
15529
+ assertChatgptWorkspace(options);
15530
+ const selected = await resolveChatOrganizationQueue(repositoryRoot(options.repo), options.queue);
15531
+ if (selected.running) return fail(`Organization queue is already running: ${selected.path}`);
15532
+ await clearChatOrganizationQueuePause(selected.path);
15533
+ const plan = JSON.stringify(
15534
+ selected.queue.items.map((item) => ({
15535
+ conversation: item.conversation,
15536
+ project: item.project
15537
+ }))
15538
+ );
15539
+ return runChatOrganize({ ...options, plan, restart: false, dryRun: false });
15540
+ };
15198
15541
  var runChatOrganize = async (options) => {
15199
15542
  assertChatgptWorkspace(options);
15200
15543
  const plan = options.plan;
@@ -15202,6 +15545,25 @@ var runChatOrganize = async (options) => {
15202
15545
  return fail("Usage: bridge chat organize --plan <fileOrJson>");
15203
15546
  }
15204
15547
  const interval = organizationIntervalOption(options.interval);
15548
+ const adaptive = options.adaptive !== false;
15549
+ const minimumIntervalSeconds = positiveIntegerOption(
15550
+ options.minInterval,
15551
+ "--min-interval",
15552
+ DEFAULT_ORGANIZATION_MIN_INTERVAL_SECONDS
15553
+ );
15554
+ const maximumIntervalSeconds = positiveIntegerOption(
15555
+ options.maxInterval,
15556
+ "--max-interval",
15557
+ DEFAULT_ORGANIZATION_MAX_INTERVAL_SECONDS
15558
+ );
15559
+ if (maximumIntervalSeconds < minimumIntervalSeconds) {
15560
+ return fail("--max-interval must be greater than or equal to --min-interval.");
15561
+ }
15562
+ const speedUpAfter = positiveIntegerOption(
15563
+ options.speedUpAfter,
15564
+ "--speed-up-after",
15565
+ DEFAULT_ORGANIZATION_SPEED_UP_AFTER
15566
+ );
15205
15567
  const cooldownSeconds = positiveIntegerOption(
15206
15568
  options.cooldown,
15207
15569
  "--cooldown",
@@ -15227,6 +15589,10 @@ var runChatOrganize = async (options) => {
15227
15589
  interval,
15228
15590
  cooldownSeconds,
15229
15591
  maxAttempts,
15592
+ adaptive,
15593
+ minimumIntervalSeconds,
15594
+ maximumIntervalSeconds,
15595
+ speedUpAfter,
15230
15596
  options
15231
15597
  });
15232
15598
  process.exit(0);
@@ -15246,6 +15612,26 @@ var runChatOrganize = async (options) => {
15246
15612
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
15247
15613
  });
15248
15614
  queue = opened.queue;
15615
+ if (adaptive) {
15616
+ const pacing = queue.pacing === void 0 ? initialChatOrganizationPacing(
15617
+ Math.min(
15618
+ maximumIntervalSeconds,
15619
+ Math.max(
15620
+ minimumIntervalSeconds,
15621
+ nextChatOrganizationIntervalSeconds(interval, Math.random())
15622
+ )
15623
+ )
15624
+ ) : constrainChatOrganizationPacing(queue.pacing, {
15625
+ minimumSeconds: minimumIntervalSeconds,
15626
+ maximumSeconds: maximumIntervalSeconds,
15627
+ speedUpAfter
15628
+ });
15629
+ queue = await persistChatOrganizationPacing({
15630
+ queue,
15631
+ queuePath,
15632
+ pacing
15633
+ });
15634
+ }
15249
15635
  } catch (error) {
15250
15636
  await releaseQueueLock();
15251
15637
  return fail(
@@ -15257,10 +15643,13 @@ var runChatOrganize = async (options) => {
15257
15643
  `Organization queue: ${initialSummary.pending} pending of ${initialSummary.total}; state ${queuePath}`,
15258
15644
  options
15259
15645
  );
15260
- if (initialSummary.pending === 0) {
15646
+ const needsVerification = options.verify !== false && queue.verification?.complete !== true;
15647
+ if (initialSummary.pending === 0 && !needsVerification) {
15261
15648
  writeChatOrganizationSummary({ queuePath, queue, options });
15262
15649
  await releaseQueueLock();
15263
- process.exit(initialSummary.failed === 0 ? 0 : 1);
15650
+ process.exit(
15651
+ initialSummary.failed === 0 && (options.verify === false || queue.verification?.complete === true) ? 0 : 1
15652
+ );
15264
15653
  }
15265
15654
  let workspace;
15266
15655
  try {
@@ -15269,97 +15658,187 @@ var runChatOrganize = async (options) => {
15269
15658
  await releaseQueueLock();
15270
15659
  throw error;
15271
15660
  }
15272
- const { engine, page } = workspace;
15661
+ let workspaceWasShutdown = false;
15662
+ let paused = false;
15273
15663
  try {
15274
- let index = nextChatOrganizationQueueIndex(queue);
15275
15664
  let consecutiveRateLimitCooldowns = 0;
15276
- while (index !== void 0) {
15277
- const item = queue.items[index];
15278
- if (item === void 0 || item.status !== "pending") {
15279
- index = nextChatOrganizationQueueIndex(queue);
15280
- continue;
15281
- }
15282
- if (await acknowledgeChatGptHistoryRateLimit(page)) {
15283
- consecutiveRateLimitCooldowns += 1;
15284
- if (consecutiveRateLimitCooldowns >= MAX_CONSECUTIVE_ORGANIZATION_COOLDOWNS) {
15665
+ let halted = false;
15666
+ while (!paused && !halted) {
15667
+ let index = nextChatOrganizationQueueIndex(queue);
15668
+ while (index !== void 0) {
15669
+ if (await chatOrganizationQueueIsPaused(queuePath)) {
15670
+ paused = true;
15285
15671
  writeChatOrganizationProgress(
15286
- `ChatGPT remained rate-limited after ${consecutiveRateLimitCooldowns} cooldowns; leaving the queue pending for a later resume.`,
15672
+ "Organization queue pause acknowledged; no new UI operation will start.",
15287
15673
  options
15288
15674
  );
15289
15675
  break;
15290
15676
  }
15677
+ const item = queue.items[index];
15678
+ if (item === void 0 || item.status !== "pending") {
15679
+ index = nextChatOrganizationQueueIndex(queue);
15680
+ continue;
15681
+ }
15682
+ if (await acknowledgeChatGptHistoryRateLimit(workspace.page)) {
15683
+ consecutiveRateLimitCooldowns += 1;
15684
+ if (adaptive && queue.pacing !== void 0) {
15685
+ queue = await persistChatOrganizationPacing({
15686
+ queue,
15687
+ queuePath,
15688
+ pacing: adaptiveChatOrganizationPacingAfterRateLimit(queue.pacing, {
15689
+ maximumSeconds: maximumIntervalSeconds
15690
+ })
15691
+ });
15692
+ }
15693
+ if (consecutiveRateLimitCooldowns >= MAX_CONSECUTIVE_ORGANIZATION_COOLDOWNS) {
15694
+ writeChatOrganizationProgress(
15695
+ `ChatGPT remained rate-limited after ${consecutiveRateLimitCooldowns} cooldowns; leaving the queue pending for a later resume.`,
15696
+ options
15697
+ );
15698
+ halted = true;
15699
+ break;
15700
+ }
15701
+ writeChatOrganizationProgress(
15702
+ `ChatGPT rate limit detected; cooling down for ${cooldownSeconds}s before continuing${queue.pacing === void 0 ? "." : ` at a slower ${queue.pacing.currentSeconds}s adaptive pace.`}`,
15703
+ options
15704
+ );
15705
+ if (await waitForOrganizationInterval(cooldownSeconds, queuePath) === "paused") {
15706
+ paused = true;
15707
+ break;
15708
+ }
15709
+ continue;
15710
+ }
15711
+ consecutiveRateLimitCooldowns = 0;
15291
15712
  writeChatOrganizationProgress(
15292
- `ChatGPT rate limit detected; cooling down for ${cooldownSeconds}s before continuing.`,
15713
+ `Moving "${item.conversation}" -> ${item.project} (attempt ${item.attempts + 1}/${maxAttempts})`,
15293
15714
  options
15294
15715
  );
15295
- await waitForOrganizationInterval(cooldownSeconds);
15296
- continue;
15716
+ let moveOutcome;
15717
+ let thrownReason;
15718
+ try {
15719
+ moveOutcome = await moveChatToProject(workspace.page, {
15720
+ chat: item.conversation,
15721
+ project: item.project
15722
+ });
15723
+ } catch (error) {
15724
+ thrownReason = error instanceof Error ? error.message : String(error);
15725
+ }
15726
+ const sessionClosed = chatOrganizationSessionWasClosed(thrownReason);
15727
+ const rateLimited = await acknowledgeChatGptHistoryRateLimit(workspace.page);
15728
+ queue = await recordChatOrganizationAttempt({
15729
+ queue,
15730
+ queuePath,
15731
+ index,
15732
+ maxAttempts,
15733
+ sessionClosed,
15734
+ rateLimited,
15735
+ moveOutcome,
15736
+ thrownReason
15737
+ });
15738
+ if (adaptive && queue.pacing !== void 0) {
15739
+ let pacing = queue.pacing;
15740
+ if (rateLimited) {
15741
+ pacing = adaptiveChatOrganizationPacingAfterRateLimit(pacing, {
15742
+ maximumSeconds: maximumIntervalSeconds
15743
+ });
15744
+ } else if (moveOutcome?.moved || moveOutcome?.alreadyFiled) {
15745
+ pacing = adaptiveChatOrganizationPacingAfterSuccess(pacing, {
15746
+ minimumSeconds: minimumIntervalSeconds,
15747
+ speedUpAfter
15748
+ });
15749
+ } else if (pacing.successStreak > 0) {
15750
+ pacing = { ...pacing, successStreak: 0 };
15751
+ }
15752
+ queue = await persistChatOrganizationPacing({ queue, queuePath, pacing });
15753
+ }
15754
+ if (sessionClosed) {
15755
+ writeChatOrganizationProgress(
15756
+ "ChatGPT browser session closed; reopening it without consuming a retry attempt.",
15757
+ options
15758
+ );
15759
+ await workspace.engine.shutdown({ closeBrowser: false });
15760
+ workspaceWasShutdown = true;
15761
+ try {
15762
+ workspace = await startWorkspaceSession(options);
15763
+ workspaceWasShutdown = false;
15764
+ } catch (error) {
15765
+ writeChatOrganizationProgress(
15766
+ `Could not reopen the ChatGPT browser session; leaving the queue pending: ${error instanceof Error ? error.message : String(error)}`,
15767
+ options
15768
+ );
15769
+ halted = true;
15770
+ break;
15771
+ }
15772
+ index = nextChatOrganizationQueueIndex(queue);
15773
+ continue;
15774
+ }
15775
+ const recorded = queue.items[index];
15776
+ if (recorded?.status === "moved") {
15777
+ writeChatOrganizationProgress(`Moved "${recorded.conversation}".`, options);
15778
+ } else if (recorded?.status === "already-filed") {
15779
+ writeChatOrganizationProgress(`Already filed "${recorded.conversation}".`, options);
15780
+ } else if (recorded?.status === "failed") {
15781
+ writeChatOrganizationProgress(
15782
+ `Failed "${recorded.conversation}" after ${recorded.attempts} attempts: ${recorded.reason}`,
15783
+ options
15784
+ );
15785
+ } else if (recorded?.status === "pending") {
15786
+ let reason = "unknown failure";
15787
+ if (recorded.lastReason !== void 0) reason = recorded.lastReason;
15788
+ writeChatOrganizationProgress(
15789
+ `Will retry "${recorded.conversation}": ${reason}`,
15790
+ options
15791
+ );
15792
+ }
15793
+ let waitSeconds = adaptive && queue.pacing !== void 0 ? nextAdaptiveChatOrganizationIntervalSeconds(queue.pacing, Math.random()) : nextChatOrganizationIntervalSeconds(interval, Math.random());
15794
+ if (rateLimited) {
15795
+ consecutiveRateLimitCooldowns += 1;
15796
+ waitSeconds = cooldownSeconds;
15797
+ }
15798
+ index = nextChatOrganizationQueueIndex(queue);
15799
+ if (index !== void 0) {
15800
+ writeChatOrganizationProgress(
15801
+ `Waiting ${waitSeconds}s before the next UI operation${adaptive ? " (adaptive)." : "."}`,
15802
+ options
15803
+ );
15804
+ if (await waitForOrganizationInterval(waitSeconds, queuePath) === "paused") {
15805
+ paused = true;
15806
+ break;
15807
+ }
15808
+ }
15297
15809
  }
15298
- consecutiveRateLimitCooldowns = 0;
15810
+ if (paused || halted) break;
15811
+ if (options.verify !== false && summarizeChatOrganizationQueue(queue).pending === 0) {
15812
+ queue = await verifyCompletedChatOrganizationQueue({
15813
+ queue,
15814
+ queuePath,
15815
+ workspace,
15816
+ options,
15817
+ maxAttempts
15818
+ });
15819
+ }
15820
+ const reopened = nextChatOrganizationQueueIndex(queue);
15821
+ if (reopened === void 0) break;
15299
15822
  writeChatOrganizationProgress(
15300
- `Moving "${item.conversation}" -> ${item.project} (attempt ${item.attempts + 1}/${maxAttempts})`,
15823
+ "The full-history audit found planned Conversations still loose; retrying them automatically.",
15301
15824
  options
15302
15825
  );
15303
- let moveOutcome;
15304
- let thrownReason;
15305
- try {
15306
- moveOutcome = await moveChatToProject(page, {
15307
- chat: item.conversation,
15308
- project: item.project
15309
- });
15310
- } catch (error) {
15311
- thrownReason = error instanceof Error ? error.message : String(error);
15312
- }
15313
- const rateLimited = await acknowledgeChatGptHistoryRateLimit(page);
15314
- queue = await recordChatOrganizationAttempt({
15315
- queue,
15316
- queuePath,
15317
- index,
15318
- maxAttempts,
15319
- rateLimited,
15320
- moveOutcome,
15321
- thrownReason
15322
- });
15323
- const recorded = queue.items[index];
15324
- if (recorded?.status === "moved") {
15325
- writeChatOrganizationProgress(`Moved "${recorded.conversation}".`, options);
15326
- } else if (recorded?.status === "already-filed") {
15327
- writeChatOrganizationProgress(`Already filed "${recorded.conversation}".`, options);
15328
- } else if (recorded?.status === "failed") {
15329
- writeChatOrganizationProgress(
15330
- `Failed "${recorded.conversation}" after ${recorded.attempts} attempts: ${recorded.reason}`,
15331
- options
15332
- );
15333
- } else if (recorded?.status === "pending") {
15334
- let reason = "unknown failure";
15335
- if (recorded.lastReason !== void 0) reason = recorded.lastReason;
15336
- writeChatOrganizationProgress(`Will retry "${recorded.conversation}": ${reason}`, options);
15337
- }
15338
- let waitSeconds = nextChatOrganizationIntervalSeconds(interval, Math.random());
15339
- if (rateLimited) {
15340
- consecutiveRateLimitCooldowns += 1;
15341
- waitSeconds = cooldownSeconds;
15342
- }
15343
- index = nextChatOrganizationQueueIndex(queue);
15344
- if (index !== void 0) {
15345
- writeChatOrganizationProgress(
15346
- `Waiting ${waitSeconds}s before the next UI operation.`,
15347
- options
15348
- );
15349
- await waitForOrganizationInterval(waitSeconds);
15350
- }
15826
+ consecutiveRateLimitCooldowns = 0;
15351
15827
  }
15352
15828
  } finally {
15353
15829
  try {
15354
- await engine.shutdown({ closeBrowser: false });
15830
+ if (!workspaceWasShutdown) await workspace.engine.shutdown({ closeBrowser: false });
15355
15831
  } finally {
15356
15832
  await releaseQueueLock();
15357
15833
  }
15358
15834
  }
15359
15835
  const summary = summarizeChatOrganizationQueue(queue);
15360
- writeChatOrganizationSummary({ queuePath, queue, options });
15836
+ writeChatOrganizationSummary({ queuePath, queue, options, paused });
15837
+ if (paused) process.exit(0);
15361
15838
  let exitCode = 0;
15362
- if (summary.failed > 0 || summary.pending > 0) exitCode = 1;
15839
+ if (summary.failed > 0 || summary.pending > 0 || options.verify !== false && queue.verification?.complete !== true) {
15840
+ exitCode = 1;
15841
+ }
15363
15842
  process.exit(exitCode);
15364
15843
  };
15365
15844
  var writeArchiveOutcomes = (outcomes, options) => {
@@ -15820,7 +16299,7 @@ var subcommandOpts = (command) => {
15820
16299
  // src/features/terminal/registerCli.ts
15821
16300
  var PROVIDER_OPTION = `Browser provider: ${PROVIDER_IDS.join(", ")} (default: ${DEFAULT_PROVIDER})`;
15822
16301
  var registerCliCommands = (program) => {
15823
- program.name("bridge").description("Terminal CLI that bridges ChatGPT or Gemini with local tools via MCP").version("0.5.1").option("-r, --repo <path>", "Path to the target repository (default: cwd)").option("-p, --port <number>", "MCP server port (default: 8765)").option("--provider <name>", PROVIDER_OPTION).option("--no-browser", "Skip Chrome browser connection").action(async (_options, command) => {
16302
+ program.name("bridge").description("Terminal CLI that bridges ChatGPT or Gemini with local tools via MCP").version("0.6.0").option("-r, --repo <path>", "Path to the target repository (default: cwd)").option("-p, --port <number>", "MCP server port (default: 8765)").option("--provider <name>", PROVIDER_OPTION).option("--no-browser", "Skip Chrome browser connection").action(async (_options, command) => {
15824
16303
  if (process.stdin.isTTY !== true || process.stdout.isTTY !== true) {
15825
16304
  command.outputHelp({ error: true });
15826
16305
  process.exitCode = 1;
@@ -15922,6 +16401,15 @@ var withWorkspaceFlags = (command) => {
15922
16401
  "Chrome user-data-dir to drive (parallel accounts; default shared bridge profile)"
15923
16402
  ).option("--json", "Emit JSON instead of human-readable lines");
15924
16403
  };
16404
+ var withOrganizationPacingFlags = (command) => {
16405
+ return command.option(
16406
+ "--interval <secondsOrRange>",
16407
+ "Initial seconds between UI operations, fixed or random range such as 60-90 (default: 60)"
16408
+ ).option("--no-adaptive", "Keep the initial interval instead of adapting to success/limits").option("--min-interval <seconds>", "Fastest adaptive base interval (default: 15)").option("--max-interval <seconds>", "Slowest adaptive base interval (default: 180)").option(
16409
+ "--speed-up-after <count>",
16410
+ "Successful moves before reducing the adaptive interval (default: 3)"
16411
+ ).option("--cooldown <seconds>", "Seconds to wait after rate limiting (default: 600)").option("--max-attempts <count>", "Attempts per Conversation before failing (default: 4)").option("--no-verify", "Skip the exhaustive orphan scan when the queue finishes");
16412
+ };
15925
16413
  var registerWorkspaceCommands = (program) => {
15926
16414
  const project = program.command("project").description("Manage ChatGPT Projects (ChatGPT only)");
15927
16415
  withWorkspaceFlags(project.command("list")).description("List ChatGPT Projects").action(
@@ -15949,15 +16437,21 @@ var registerWorkspaceCommands = (program) => {
15949
16437
  withWorkspaceFlags(chat.command("archive [idOrTitle...]")).description("Archive one or more conversations (reversible \u2014 hides from the sidebar)").option("--id <id...>", "Archive several conversations by id in one session").action(
15950
16438
  (chatParts, _options, command) => runChatArchive(chatParts.join(" "), command.optsWithGlobals())
15951
16439
  );
15952
- withWorkspaceFlags(chat.command("organize")).description("Run a resumable, rate-safe Conversation organization queue").requiredOption(
16440
+ const organize = withOrganizationPacingFlags(withWorkspaceFlags(chat.command("organize"))).description("Run a resumable, rate-safe Conversation organization queue").option(
15953
16441
  "--plan <fileOrJson>",
15954
16442
  "JSON array of {conversation, project} tasks (inline, @file, or a path)"
15955
- ).option(
15956
- "--interval <secondsOrRange>",
15957
- "Seconds between UI operations, fixed or random range such as 10-20 (default: 30)"
15958
- ).option("--cooldown <seconds>", "Seconds to wait after rate limiting (default: 300)").option("--max-attempts <count>", "Attempts per Conversation before failing (default: 3)").option("--restart", "Restart this plan instead of resuming its persisted queue").option("--dry-run", "Validate and show the queue without opening Chrome or writing state").action(
16443
+ ).option("--restart", "Restart this plan instead of resuming its persisted queue").option("--dry-run", "Validate and show the queue without opening Chrome or writing state").action(
15959
16444
  (_options, command) => runChatOrganize(command.optsWithGlobals())
15960
16445
  );
16446
+ withWorkspaceFlags(organize.command("status")).description("Show the latest organization queue state and adaptive pace").option("--queue <pathOrFingerprint>", "Select a queue instead of the latest one").action(
16447
+ (_options, command) => runChatOrganizeStatus(command.optsWithGlobals())
16448
+ );
16449
+ withWorkspaceFlags(organize.command("pause")).description("Pause the latest queue after its active UI operation").option("--queue <pathOrFingerprint>", "Select a queue instead of the latest one").action(
16450
+ (_options, command) => runChatOrganizePause(command.optsWithGlobals())
16451
+ );
16452
+ withOrganizationPacingFlags(withWorkspaceFlags(organize.command("resume"))).description("Resume the latest persisted organization queue").option("--queue <pathOrFingerprint>", "Select a queue instead of the latest one").action(
16453
+ (_options, command) => runChatOrganizeResume(command.optsWithGlobals())
16454
+ );
15961
16455
  const task = program.command("task").description("List or schedule ChatGPT Tasks (ChatGPT only)");
15962
16456
  withWorkspaceFlags(task.command("list")).description("List ChatGPT Scheduled tasks").action(
15963
16457
  (_options, command) => runTaskList(command.optsWithGlobals())