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/README.md +27 -8
- package/dist/bridge.js +586 -92
- package/dist/bridge.js.map +1 -1
- package/package.json +1 -1
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
15080
|
-
var
|
|
15081
|
-
var
|
|
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
|
-
|
|
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(
|
|
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.
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
15661
|
+
let workspaceWasShutdown = false;
|
|
15662
|
+
let paused = false;
|
|
15273
15663
|
try {
|
|
15274
|
-
let index = nextChatOrganizationQueueIndex(queue);
|
|
15275
15664
|
let consecutiveRateLimitCooldowns = 0;
|
|
15276
|
-
|
|
15277
|
-
|
|
15278
|
-
|
|
15279
|
-
|
|
15280
|
-
|
|
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
|
-
|
|
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
|
-
`
|
|
15713
|
+
`Moving "${item.conversation}" -> ${item.project} (attempt ${item.attempts + 1}/${maxAttempts})`,
|
|
15293
15714
|
options
|
|
15294
15715
|
);
|
|
15295
|
-
|
|
15296
|
-
|
|
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
|
-
|
|
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
|
-
|
|
15823
|
+
"The full-history audit found planned Conversations still loose; retrying them automatically.",
|
|
15301
15824
|
options
|
|
15302
15825
|
);
|
|
15303
|
-
|
|
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
|
|
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.
|
|
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").
|
|
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())
|