ai-browser-bridge 0.5.1 → 0.5.2
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 +12 -8
- package/dist/bridge.js +47 -12
- package/dist/bridge.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -163,17 +163,21 @@ Then validate it and start the autonomous queue:
|
|
|
163
163
|
|
|
164
164
|
```bash
|
|
165
165
|
bridge chat organize --plan @organization-plan.json --dry-run
|
|
166
|
-
bridge chat organize --plan @organization-plan.json
|
|
166
|
+
bridge chat organize --plan @organization-plan.json \
|
|
167
|
+
--interval 60-90 --cooldown 600 --max-attempts 4
|
|
167
168
|
```
|
|
168
169
|
|
|
169
170
|
The queue verifies every move from ChatGPT's loaded Project label, with the destination Project page
|
|
170
|
-
as a fallback. It spaces UI operations by a fixed
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
171
|
+
as a fallback. It spaces UI operations by a fixed interval or randomized range; the defaults are a
|
|
172
|
+
60-second interval, a 600-second rate-limit cooldown, and four attempts per Conversation. For large
|
|
173
|
+
history cleanups, the randomized `--interval 60-90` profile above is recommended. The queue
|
|
174
|
+
acknowledges ChatGPT's “Too many requests” modal before cooling down, and automatically relaunches a
|
|
175
|
+
closed browser session. Neither infrastructure condition consumes a move attempt. Progress is
|
|
176
|
+
persisted under `.bridge/chat-organization-queues/`; rerunning the same plan resumes pending work
|
|
177
|
+
without repeating completed moves. Once the queue has started and processed or deferred one item,
|
|
178
|
+
it can continue unattended without an agent watching it. Use `--restart` only when you intentionally
|
|
179
|
+
want to replay the full plan. `--json` keeps the final summary on stdout and writes progress to
|
|
180
|
+
stderr.
|
|
177
181
|
|
|
178
182
|
## Agents & fan-out
|
|
179
183
|
|
package/dist/bridge.js
CHANGED
|
@@ -11195,6 +11195,11 @@ var ChatOrganizationQueueSchema = Schema8.Struct({
|
|
|
11195
11195
|
items: Schema8.Array(ChatOrganizationQueueItemSchema).pipe(Schema8.minItems(1))
|
|
11196
11196
|
});
|
|
11197
11197
|
var ORGANIZATION_INTERVAL = /^(?<minimum>\d+)(?:-(?<maximum>\d+))?$/u;
|
|
11198
|
+
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;
|
|
11199
|
+
var chatOrganizationSessionWasClosed = (reason) => {
|
|
11200
|
+
if (reason === void 0) return false;
|
|
11201
|
+
return CLOSED_BROWSER_SESSION.test(reason);
|
|
11202
|
+
};
|
|
11198
11203
|
var chatOrganizationIntervalFrom = (value, defaultSeconds) => {
|
|
11199
11204
|
if (value === void 0) {
|
|
11200
11205
|
return { minimumSeconds: defaultSeconds, maximumSeconds: defaultSeconds };
|
|
@@ -15076,11 +15081,12 @@ var runChatMove = async (chat, options) => {
|
|
|
15076
15081
|
writeMoveOutcomes(outcomes, options);
|
|
15077
15082
|
process.exit(outcomes.every((outcome) => outcome.moved || outcome.alreadyFiled) ? 0 : 1);
|
|
15078
15083
|
};
|
|
15079
|
-
var DEFAULT_ORGANIZATION_INTERVAL_SECONDS =
|
|
15080
|
-
var DEFAULT_ORGANIZATION_COOLDOWN_SECONDS =
|
|
15081
|
-
var DEFAULT_ORGANIZATION_MAX_ATTEMPTS =
|
|
15084
|
+
var DEFAULT_ORGANIZATION_INTERVAL_SECONDS = 60;
|
|
15085
|
+
var DEFAULT_ORGANIZATION_COOLDOWN_SECONDS = 600;
|
|
15086
|
+
var DEFAULT_ORGANIZATION_MAX_ATTEMPTS = 4;
|
|
15082
15087
|
var MAX_CONSECUTIVE_ORGANIZATION_COOLDOWNS = 12;
|
|
15083
15088
|
var RATE_LIMIT_REASON = "ChatGPT temporarily limited access to Conversation history.";
|
|
15089
|
+
var CLOSED_SESSION_REASON = "ChatGPT browser session closed; reopening before retry.";
|
|
15084
15090
|
var positiveIntegerOption = (value, optionName, defaultValue) => {
|
|
15085
15091
|
if (value === void 0) return defaultValue;
|
|
15086
15092
|
if (!/^[1-9]\d*$/u.test(value.trim())) {
|
|
@@ -15159,7 +15165,14 @@ var writeChatOrganizationDryRun = (input) => {
|
|
|
15159
15165
|
var recordChatOrganizationAttempt = async (input) => {
|
|
15160
15166
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
15161
15167
|
let queue;
|
|
15162
|
-
if (input.
|
|
15168
|
+
if (input.sessionClosed) {
|
|
15169
|
+
queue = deferChatOrganizationQueueItem({
|
|
15170
|
+
queue: input.queue,
|
|
15171
|
+
index: input.index,
|
|
15172
|
+
reason: CLOSED_SESSION_REASON,
|
|
15173
|
+
timestamp
|
|
15174
|
+
});
|
|
15175
|
+
} else if (input.rateLimited) {
|
|
15163
15176
|
queue = deferChatOrganizationQueueItem({
|
|
15164
15177
|
queue: input.queue,
|
|
15165
15178
|
index: input.index,
|
|
@@ -15269,7 +15282,7 @@ var runChatOrganize = async (options) => {
|
|
|
15269
15282
|
await releaseQueueLock();
|
|
15270
15283
|
throw error;
|
|
15271
15284
|
}
|
|
15272
|
-
|
|
15285
|
+
let workspaceWasShutdown = false;
|
|
15273
15286
|
try {
|
|
15274
15287
|
let index = nextChatOrganizationQueueIndex(queue);
|
|
15275
15288
|
let consecutiveRateLimitCooldowns = 0;
|
|
@@ -15279,7 +15292,7 @@ var runChatOrganize = async (options) => {
|
|
|
15279
15292
|
index = nextChatOrganizationQueueIndex(queue);
|
|
15280
15293
|
continue;
|
|
15281
15294
|
}
|
|
15282
|
-
if (await acknowledgeChatGptHistoryRateLimit(page)) {
|
|
15295
|
+
if (await acknowledgeChatGptHistoryRateLimit(workspace.page)) {
|
|
15283
15296
|
consecutiveRateLimitCooldowns += 1;
|
|
15284
15297
|
if (consecutiveRateLimitCooldowns >= MAX_CONSECUTIVE_ORGANIZATION_COOLDOWNS) {
|
|
15285
15298
|
writeChatOrganizationProgress(
|
|
@@ -15303,23 +15316,45 @@ var runChatOrganize = async (options) => {
|
|
|
15303
15316
|
let moveOutcome;
|
|
15304
15317
|
let thrownReason;
|
|
15305
15318
|
try {
|
|
15306
|
-
moveOutcome = await moveChatToProject(page, {
|
|
15319
|
+
moveOutcome = await moveChatToProject(workspace.page, {
|
|
15307
15320
|
chat: item.conversation,
|
|
15308
15321
|
project: item.project
|
|
15309
15322
|
});
|
|
15310
15323
|
} catch (error) {
|
|
15311
15324
|
thrownReason = error instanceof Error ? error.message : String(error);
|
|
15312
15325
|
}
|
|
15313
|
-
const
|
|
15326
|
+
const sessionClosed = chatOrganizationSessionWasClosed(thrownReason);
|
|
15327
|
+
const rateLimited = await acknowledgeChatGptHistoryRateLimit(workspace.page);
|
|
15314
15328
|
queue = await recordChatOrganizationAttempt({
|
|
15315
15329
|
queue,
|
|
15316
15330
|
queuePath,
|
|
15317
15331
|
index,
|
|
15318
15332
|
maxAttempts,
|
|
15333
|
+
sessionClosed,
|
|
15319
15334
|
rateLimited,
|
|
15320
15335
|
moveOutcome,
|
|
15321
15336
|
thrownReason
|
|
15322
15337
|
});
|
|
15338
|
+
if (sessionClosed) {
|
|
15339
|
+
writeChatOrganizationProgress(
|
|
15340
|
+
"ChatGPT browser session closed; reopening it without consuming a retry attempt.",
|
|
15341
|
+
options
|
|
15342
|
+
);
|
|
15343
|
+
await workspace.engine.shutdown({ closeBrowser: false });
|
|
15344
|
+
workspaceWasShutdown = true;
|
|
15345
|
+
try {
|
|
15346
|
+
workspace = await startWorkspaceSession(options);
|
|
15347
|
+
workspaceWasShutdown = false;
|
|
15348
|
+
} catch (error) {
|
|
15349
|
+
writeChatOrganizationProgress(
|
|
15350
|
+
`Could not reopen the ChatGPT browser session; leaving the queue pending: ${error instanceof Error ? error.message : String(error)}`,
|
|
15351
|
+
options
|
|
15352
|
+
);
|
|
15353
|
+
break;
|
|
15354
|
+
}
|
|
15355
|
+
index = nextChatOrganizationQueueIndex(queue);
|
|
15356
|
+
continue;
|
|
15357
|
+
}
|
|
15323
15358
|
const recorded = queue.items[index];
|
|
15324
15359
|
if (recorded?.status === "moved") {
|
|
15325
15360
|
writeChatOrganizationProgress(`Moved "${recorded.conversation}".`, options);
|
|
@@ -15351,7 +15386,7 @@ var runChatOrganize = async (options) => {
|
|
|
15351
15386
|
}
|
|
15352
15387
|
} finally {
|
|
15353
15388
|
try {
|
|
15354
|
-
await engine.shutdown({ closeBrowser: false });
|
|
15389
|
+
if (!workspaceWasShutdown) await workspace.engine.shutdown({ closeBrowser: false });
|
|
15355
15390
|
} finally {
|
|
15356
15391
|
await releaseQueueLock();
|
|
15357
15392
|
}
|
|
@@ -15820,7 +15855,7 @@ var subcommandOpts = (command) => {
|
|
|
15820
15855
|
// src/features/terminal/registerCli.ts
|
|
15821
15856
|
var PROVIDER_OPTION = `Browser provider: ${PROVIDER_IDS.join(", ")} (default: ${DEFAULT_PROVIDER})`;
|
|
15822
15857
|
var registerCliCommands = (program) => {
|
|
15823
|
-
program.name("bridge").description("Terminal CLI that bridges ChatGPT or Gemini with local tools via MCP").version("0.5.
|
|
15858
|
+
program.name("bridge").description("Terminal CLI that bridges ChatGPT or Gemini with local tools via MCP").version("0.5.2").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
15859
|
if (process.stdin.isTTY !== true || process.stdout.isTTY !== true) {
|
|
15825
15860
|
command.outputHelp({ error: true });
|
|
15826
15861
|
process.exitCode = 1;
|
|
@@ -15954,8 +15989,8 @@ var registerWorkspaceCommands = (program) => {
|
|
|
15954
15989
|
"JSON array of {conversation, project} tasks (inline, @file, or a path)"
|
|
15955
15990
|
).option(
|
|
15956
15991
|
"--interval <secondsOrRange>",
|
|
15957
|
-
"Seconds between UI operations, fixed or random range such as
|
|
15958
|
-
).option("--cooldown <seconds>", "Seconds to wait after rate limiting (default:
|
|
15992
|
+
"Seconds between UI operations, fixed or random range such as 60-90 (default: 60)"
|
|
15993
|
+
).option("--cooldown <seconds>", "Seconds to wait after rate limiting (default: 600)").option("--max-attempts <count>", "Attempts per Conversation before failing (default: 4)").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
15994
|
(_options, command) => runChatOrganize(command.optsWithGlobals())
|
|
15960
15995
|
);
|
|
15961
15996
|
const task = program.command("task").description("List or schedule ChatGPT Tasks (ChatGPT only)");
|