bridgerator 1.1.8 → 1.1.10
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/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/src/bridge.mjs +17 -8
- package/src/cli.mjs +6 -2
- package/src/notice.mjs +7 -1
- package/src/settings-tool.mjs +2 -2
- package/src/tray.mjs +2 -2
- package/src/tray.ps1 +1 -1
- package/ui/app.js +1 -1
- package/ui/i18n/en.json +3 -2
- package/ui/i18n/ru.json +3 -2
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bridgerator",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.10",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "bridgerator",
|
|
9
|
-
"version": "1.1.
|
|
9
|
+
"version": "1.1.10",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bridgerator",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.10",
|
|
4
4
|
"description": "Connect ChatGPT to your Windows PC: files, search and terminal through an outbound-only bridge with folder limits. No inbound ports, no admin rights.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/src/bridge.mjs
CHANGED
|
@@ -251,6 +251,8 @@ export async function startEngine(cfg, log = console.log, { ask: askArg, recycle
|
|
|
251
251
|
|
|
252
252
|
// bridgerator_setup: applied at once; after Apply on the PC only with askSettings on (setup-tool.mjs).
|
|
253
253
|
const say = (t, isError) => ({ content: [{ type: 'text', text: t }], ...(isError ? { isError: true } : {}) });
|
|
254
|
+
// The person sees every settings change not made in the window (notify.settingsChanged, on by default; owner 26.10).
|
|
255
|
+
const toldSettings = (by, lines) => { if (lines.length && cfg.notify?.settingsChanged !== false) showNotice({ kind: 'settings_changed', by, what: lines }, log); };
|
|
254
256
|
async function setup(args) {
|
|
255
257
|
const v = validateSetup(args);
|
|
256
258
|
if (v.error) return say(`Not applied: ${v.error}`, true);
|
|
@@ -261,7 +263,7 @@ export async function startEngine(cfg, log = console.log, { ask: askArg, recycle
|
|
|
261
263
|
delete v.value.preset;
|
|
262
264
|
}
|
|
263
265
|
// Owner 21.10: applied at once; Apply on the PC only when the person turned on "Ask before AI changes settings".
|
|
264
|
-
if (cfg.askSettings !== true) { await applyValues(v.value, 'bridgerator_setup'); return say('Applied on the PC.'); }
|
|
266
|
+
if (cfg.askSettings !== true) { const d = diffSetup(cfg, cfg.confirmIni, v.value).short; await applyValues(v.value, 'bridgerator_setup'); toldSettings('ai', d ? [d] : []); return say('Applied on the PC.'); }
|
|
265
267
|
// A diff that fits the notification gets Apply there; a longer one is reviewed in the window.
|
|
266
268
|
const diff = diffSetup(cfg, cfg.confirmIni, v.value);
|
|
267
269
|
let r;
|
|
@@ -293,12 +295,13 @@ export async function startEngine(cfg, log = console.log, { ask: askArg, recycle
|
|
|
293
295
|
const risky = v.changes.filter(ask1), safe = v.changes.filter((c) => !ask1(c));
|
|
294
296
|
for (const c of safe) await rpc('setSetting', { ...c, via: 'bridgerator_settings' });
|
|
295
297
|
const done = safe.map((c) => describe(cur, c));
|
|
298
|
+
toldSettings('ai', done);
|
|
296
299
|
if (!risky.length) return say(`Applied: ${done.join('; ')}`);
|
|
297
300
|
const lines = risky.map((c) => describe(cur, c)), short = lines.join(' · ');
|
|
298
301
|
const r = short.length <= 180
|
|
299
302
|
? await gate.askPerson('settings', { head: 'ChatGPT wants to change Bridgerator settings', text: short, buttons: [['allow', 'Apply', ''], ['deny', 'Cancel', 'deny']], secs: 120, auto: 'auto-cancel', ...popup() })
|
|
300
303
|
: await gate.askPerson('settings', { review: true, lines });
|
|
301
|
-
if (r === 'allow') { for (const c of risky) await rpc('setSetting', { ...c, via: 'bridgerator_settings' }); return say(`Applied${done.length ? `: ${done.join('; ')};` : ':'} after the person's OK: ${lines.join('; ')}`); }
|
|
304
|
+
if (r === 'allow') { for (const c of risky) await rpc('setSetting', { ...c, via: 'bridgerator_settings' }); toldSettings('ai', lines); return say(`Applied${done.length ? `: ${done.join('; ')};` : ':'} after the person's OK: ${lines.join('; ')}`); }
|
|
302
305
|
return { ...say(`${done.length ? `Applied: ${done.join('; ')}. ` : ''}Not applied (the person at the PC ${r === 'cooldown' ? 'declined a few minutes ago' : 'cancelled or didn\'t answer'}): ${lines.join('; ')}`), notConfirmed: true };
|
|
303
306
|
}
|
|
304
307
|
|
|
@@ -504,7 +507,7 @@ export async function startEngine(cfg, log = console.log, { ask: askArg, recycle
|
|
|
504
507
|
const bannerNow = () => { const b = planBanner(out.plan); return { ...b, visible: bannerVisible(b, cfg.planBannerDismissed) }; };
|
|
505
508
|
out.banner = bannerNow;
|
|
506
509
|
out.onPlanMsg = (m) => { out.plan = readPlan(m); out.onPlan?.(); };
|
|
507
|
-
const BOOL_NOTIFY = ['sound', 'offline', 'queueDone', 'queueStalled', 'limit'];
|
|
510
|
+
const BOOL_NOTIFY = ['sound', 'offline', 'queueDone', 'queueStalled', 'settingsChanged', 'limit'];
|
|
508
511
|
|
|
509
512
|
// Requests of the Bridgerator window (tray helper). Made by the person at the PC: no extra prompt.
|
|
510
513
|
async function rpc(method, p = {}, paths = []) {
|
|
@@ -654,21 +657,27 @@ export async function startEngine(cfg, log = console.log, { ask: askArg, recycle
|
|
|
654
657
|
const den = list(j.deniedDirectories), denNow = cfg.deniedDirectories || [];
|
|
655
658
|
const denRemoved = denNow.filter((x) => !den.some((y) => y.toLowerCase() === x.toLowerCase()));
|
|
656
659
|
if (!changes.length && JSON.stringify(den) === JSON.stringify(denNow)) return;
|
|
657
|
-
|
|
660
|
+
// Owner 26.10: a file edit applies at once like an AI change; Apply on the PC only with askSettings on.
|
|
661
|
+
const ask1 = (c) => cfg.askSettings === true && widens(cur, c);
|
|
662
|
+
const risky = changes.filter(ask1), safe = changes.filter((c) => !ask1(c));
|
|
663
|
+
const denAsk = cfg.askSettings === true && denRemoved.length > 0;
|
|
658
664
|
const back = {};
|
|
659
665
|
const top = (key) => (key === 'terminal' ? 'disabledTools' : key.split('.')[0]);
|
|
660
666
|
for (const c of safe) { try { await rpc('setSetting', { ...c, via: 'settings file' }); } catch (e) { log(`[bridgerator] settings file: ${c.key} not applied (${e.message})`); back[top(c.key)] = cfg[top(c.key)]; } }
|
|
661
|
-
if (!
|
|
662
|
-
const
|
|
667
|
+
if (!denAsk) { cfg.deniedDirectories = den; policy = makePolicy(); }
|
|
668
|
+
const denLine = denRemoved.length ? [`Excluded folders: ${denRemoved.map((x) => `−${x}`).join(', ')}`] : [];
|
|
669
|
+
toldSettings('file', [...safe.filter((c) => !(top(c.key) in back)).map((c) => describe(cur, c)), ...(denAsk ? [] : denLine)]);
|
|
670
|
+
const lines = [...risky.map((c) => describe(cur, c)), ...(denAsk ? denLine : [])];
|
|
663
671
|
if (lines.length) {
|
|
664
672
|
const r = await gate.askPerson('file', { head: 'Bridgerator settings file changed', text: clip(`Apply: ${lines.join(' · ')}?`, '', 180), buttons: [['allow', 'Apply', ''], ['deny', 'Keep', 'deny']], secs: 120, auto: 'auto-keep', ...popup() });
|
|
665
673
|
if (r === 'allow') {
|
|
666
674
|
for (const c of risky) { try { await rpc('setSetting', { ...c, via: 'settings file' }); } catch (e) { log(`[bridgerator] settings file: ${c.key} not applied (${e.message})`); back[top(c.key)] = cfg[top(c.key)]; } }
|
|
667
|
-
if (
|
|
675
|
+
if (denAsk) { cfg.deniedDirectories = den; policy = makePolicy(); }
|
|
676
|
+
toldSettings('file', lines);
|
|
668
677
|
log(`[bridgerator] settings file change applied on the PC: ${lines.join('; ')}`);
|
|
669
678
|
} else {
|
|
670
679
|
for (const c of risky) back[top(c.key)] = cfg[top(c.key)];
|
|
671
|
-
if (
|
|
680
|
+
if (denAsk) back.deniedDirectories = denNow;
|
|
672
681
|
log(`[bridgerator] settings file change kept out (${r}): ${lines.join('; ')}`);
|
|
673
682
|
}
|
|
674
683
|
}
|
package/src/cli.mjs
CHANGED
|
@@ -39,6 +39,8 @@ const INI = path.join(DIR, 'confirm.ini'); // on-PC confirmation settings (confi
|
|
|
39
39
|
const SNAP_DIR = DIR === path.join(APPDATA, 'Bridgerator') ? path.join(LOCALAPPDATA, 'Bridgerator', 'snapshots') : path.join(DIR, 'snapshots');
|
|
40
40
|
// Automations (scheduled scripts, automations.mjs): inside the always-excluded %LOCALAPPDATA%\Bridgerator.
|
|
41
41
|
const SCRIPTS_DIR = DIR === path.join(APPDATA, 'Bridgerator') ? path.join(LOCALAPPDATA, 'Bridgerator', 'scripts') : path.join(DIR, 'scripts');
|
|
42
|
+
// The window's WebView2 data: a second bridge (--home) gets its own, or its window stays black (one data folder = one browser process).
|
|
43
|
+
const WEBVIEW_DIR = DIR === path.join(APPDATA, 'Bridgerator') ? path.join(LOCALAPPDATA, 'Bridgerator', 'webview') : path.join(DIR, 'webview');
|
|
42
44
|
const SELF = fileURLToPath(import.meta.url);
|
|
43
45
|
const PKG_DIR = path.dirname(path.dirname(SELF)); // …\node_modules\bridgerator
|
|
44
46
|
// Private Node.js the installer puts in when there is none (or < 22) — see install.ps1.
|
|
@@ -335,7 +337,9 @@ const defaultDenied = () => [];
|
|
|
335
337
|
/** The setup summary's "excluded" line: only what really applies (sensitive folders only when that switch is on). */
|
|
336
338
|
export const excludedLine = (cfg) => [...(cfg.deniedDirectories || []), `built-in: Bridgerator's own folders${cfg.protectSensitive ? ', AppData, credentials (.ssh, .aws, …), Startup, PowerShell profiles' : ''}`].join(', ');
|
|
337
339
|
/** 'ru' when the Windows display language or regional format is Russian, else 'en'. */
|
|
338
|
-
|
|
340
|
+
// Node's Intl gives only the regional format: the display language comes from Windows, as in install.ps1.
|
|
341
|
+
const uiCulture = () => { try { return process.platform === 'win32' ? ps('[Globalization.CultureInfo]::CurrentUICulture.Name').trim() : ''; } catch { return ''; } };
|
|
342
|
+
export function osLanguage(locales = [Intl.DateTimeFormat().resolvedOptions().locale, process.env.LANG, uiCulture()]) {
|
|
339
343
|
return locales.some((l) => /^ru([-_.]|$)/i.test(String(l || ''))) ? 'ru' : 'en';
|
|
340
344
|
}
|
|
341
345
|
const keptDenied = (list) => (Array.isArray(list) && !(list.length === 1 && process.env.OneDrive && list[0].toLowerCase() === process.env.OneDrive.toLowerCase()) ? list : []);
|
|
@@ -447,7 +451,7 @@ async function main() {
|
|
|
447
451
|
showNotice({ kind: 'offline' }, log); return true;
|
|
448
452
|
});
|
|
449
453
|
const tray = startTray({
|
|
450
|
-
log, account: accountUrlOf(cfg),
|
|
454
|
+
log, account: accountUrlOf(cfg), webview: WEBVIEW_DIR,
|
|
451
455
|
onMenu: (a, m) => {
|
|
452
456
|
if (a === 'quit') { log('[bridgerator] quit from the tray (starts again at the next sign-in)'); tray?.close(); process.exit(0); }
|
|
453
457
|
if (a === 'pause') dc?.setPaused(true, m.minutes);
|
package/src/notice.mjs
CHANGED
|
@@ -34,7 +34,13 @@ export function noticeText(n) {
|
|
|
34
34
|
const title = typeof n.title === 'string' ? n.title.replace(/[\u0000-\u001f\u007f-\u009f]/g, ' ').trim().slice(0, 120) : '';
|
|
35
35
|
if (!title) return undefined;
|
|
36
36
|
const more = int(n.more) || 0;
|
|
37
|
-
t = ['ChatGPT may be waiting for you', `No activity on the queue task "${title}"${more ? ` and ${more} more` : ''} for 10 minutes. Open the ChatGPT chat: it may be asking you to allow an action.`];
|
|
37
|
+
t = ['ChatGPT may be waiting for you', `No activity on the queue task "${title}"${more ? ` and ${more} more` : ''} for 10 minutes. Open the ChatGPT chat: it may be asking you to allow an action, or show an error such as "model is at capacity" — press Retry there or pick another model.`];
|
|
38
|
+
} else if (kind === 'settings_changed') {
|
|
39
|
+
// The bridge's own change lines (describe / diffSetup): paths and labels, no relay text.
|
|
40
|
+
const what = Array.isArray(n.what) ? n.what.map((w) => String(w).replace(/[\u0000-\u001f\u007f-\u009f]/g, ' ').trim()).filter(Boolean) : [];
|
|
41
|
+
if (!what.length || !['ai', 'file'].includes(n.by)) return undefined;
|
|
42
|
+
const all = what.join(' · ');
|
|
43
|
+
t = ['Bridgerator settings changed', `${n.by === 'ai' ? 'By the AI' : 'In the settings file'}: ${all.length > 200 ? `${all.slice(0, 199)}…` : all}. Turn this notice off in the Bridgerator window.`];
|
|
38
44
|
} else if (kind === 'protection_off') {
|
|
39
45
|
// Internal list only (the bridge's own labels), never relay text.
|
|
40
46
|
const ok = new Set(['confirmations', 'your own patterns', ...Object.values(LABEL).map((l) => `confirmations for ${l}`)]);
|
package/src/settings-tool.mjs
CHANGED
|
@@ -21,11 +21,11 @@ export const DEFAULTS = {
|
|
|
21
21
|
preset: 'full', terminal: true, allowedDirectories: [], readOnlyDirectories: [], protectSensitive: false,
|
|
22
22
|
confirm: { enabled: false, ...readSettings('').ask, timeoutSeconds: 120 }, // no confirm.ini = the defaults per category
|
|
23
23
|
recycleBin: true, snapshots: { ...SNAP_DEFAULTS }, fuse: { ...FUSE_DEFAULTS }, keepAwake: true, askSettings: false,
|
|
24
|
-
theme: 'system', language: 'en', popupStyle: 'toast', notify: { sound: true, offline: true, queueDone: true, queueStalled: true, limit: true },
|
|
24
|
+
theme: 'system', language: 'en', popupStyle: 'toast', notify: { sound: true, offline: true, queueDone: true, queueStalled: true, settingsChanged: true, limit: true },
|
|
25
25
|
deviceName: '', autostart: true, localHistory: false, telemetryEnabled: true,
|
|
26
26
|
...EXTRA.defaults(),
|
|
27
27
|
};
|
|
28
|
-
const NOTIFY = ['sound', 'offline', 'queueDone', 'queueStalled', 'limit'];
|
|
28
|
+
const NOTIFY = ['sound', 'offline', 'queueDone', 'queueStalled', 'settingsChanged', 'limit'];
|
|
29
29
|
const dirs = { type: 'array', maxItems: 20, items: { type: 'string' } };
|
|
30
30
|
export const SETTINGS_TOOL_DEF = {
|
|
31
31
|
name: 'bridgerator_settings',
|
package/src/tray.mjs
CHANGED
|
@@ -56,13 +56,13 @@ export function createLink(write, { onMenu = () => {}, onRpc = async () => null,
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
/** Starts the helper (Windows only) and keeps it running while the bridge runs. → link-like object. */
|
|
59
|
-
export function startTray({ log = console.log, onMenu, onRpc, onPower, spawn = nodeSpawn, stderr = 'ignore', testEnv = {}, account = '' } = {}) {
|
|
59
|
+
export function startTray({ log = console.log, onMenu, onRpc, onPower, spawn = nodeSpawn, stderr = 'ignore', testEnv = {}, account = '', webview = '' } = {}) {
|
|
60
60
|
if (process.platform !== 'win32') return null;
|
|
61
61
|
let child = null, link = null, closing = false, restartTimer = null;
|
|
62
62
|
// Our own variables only: BR_* / BRIDGERATOR_* from the environment are ignored (a test harness
|
|
63
63
|
// passes its hooks explicitly as testEnv).
|
|
64
64
|
// BR_ACCOUNT: the account page of the site this PC is linked to (a staging install opens staging; V-5).
|
|
65
|
-
const env = { ...stripOurs(process.env), ...testEnv, BR_PARENT: String(process.pid), BR_PKG: PKG_DIR, ...(/^https:\/\/[a-z0-9.-]+(:\d+)?\/app$/i.test(account) ? { BR_ACCOUNT: account } : {}) };
|
|
65
|
+
const env = { ...stripOurs(process.env), ...testEnv, BR_PARENT: String(process.pid), BR_PKG: PKG_DIR, ...(webview ? { BR_WEBVIEW: webview } : {}), ...(/^https:\/\/[a-z0-9.-]+(:\d+)?\/app$/i.test(account) ? { BR_ACCOUNT: account } : {}) };
|
|
66
66
|
const start = () => {
|
|
67
67
|
// Plain -Command (not encoded): its command line names the package folder, so the one process
|
|
68
68
|
// matcher (stop / update / uninstall) finds the helper too.
|
package/src/tray.ps1
CHANGED
|
@@ -230,7 +230,7 @@ function Open-Window([string]$page = 'home', [switch]$Prewarm) {
|
|
|
230
230
|
$f.MinimumSize = New-Object Drawing.Size([int](760 * $k), [int](520 * $k))
|
|
231
231
|
$wv = New-Object Microsoft.Web.WebView2.WinForms.WebView2; $wv.Dock = 'Fill'; $wv.DefaultBackgroundColor = $bg
|
|
232
232
|
$cp = New-Object Microsoft.Web.WebView2.WinForms.CoreWebView2CreationProperties
|
|
233
|
-
$cp.UserDataFolder = Join-Path $env:LOCALAPPDATA 'Bridgerator\webview'; $wv.CreationProperties = $cp
|
|
233
|
+
$cp.UserDataFolder = if ($env:BR_WEBVIEW) { $env:BR_WEBVIEW } else { Join-Path $env:LOCALAPPDATA 'Bridgerator\webview' }; $wv.CreationProperties = $cp
|
|
234
234
|
if ($env:BR_ZOOM) { $wv.ZoomFactor = [double]$env:BR_ZOOM }
|
|
235
235
|
$f.Controls.Add($wv)
|
|
236
236
|
$post = { param($o) if ($wv.CoreWebView2) { $wv.CoreWebView2.PostWebMessageAsJson(($o | ConvertTo-Json -Compress -Depth 4)) } }.GetNewClosure()
|
package/ui/app.js
CHANGED
|
@@ -334,7 +334,7 @@ P.notifications = () => {
|
|
|
334
334
|
return `<main class="notifications">${bannerHtml()}
|
|
335
335
|
<div class="head"><h1>${esc(t('notify.title'))}</h1><div class="sub">${esc(t('notify.sub'))}</div></div>
|
|
336
336
|
<div class="styles" role="radiogroup" aria-label="${esc(t('aria.style'))}">${style('toast')}${style('popup')}</div>
|
|
337
|
-
<div class="nsplit"><section class="card" aria-label="${esc(t('aria.options'))}">${sw('sound', 'notify.sound')}${sw('offline', 'notify.offline')}${sw('queueDone', 'notify.queueDone')}${sw('queueStalled', 'notify.queueStalled')}${sw('limit', 'notify.limit')}</section>
|
|
337
|
+
<div class="nsplit"><section class="card" aria-label="${esc(t('aria.options'))}">${sw('sound', 'notify.sound')}${sw('offline', 'notify.offline')}${sw('queueDone', 'notify.queueDone')}${sw('queueStalled', 'notify.queueStalled')}${sw('settingsChanged', 'notify.settingsChanged')}${sw('limit', 'notify.limit')}</section>
|
|
338
338
|
<section class="preview" aria-label="${esc(t('notify.preview'))}"><div class="bar-top"><span class="b">${esc(t('notify.preview'))}</span><div class="seg" role="radiogroup" aria-label="${esc(t('aria.previewTheme'))}">${pv('light')}${pv('dark')}</div></div>
|
|
339
339
|
<div class="toast ${previewTheme}"><div class="app">${LOGO16}<span class="grow">Bridgerator</span><span>⋯</span></div><div class="h">${esc(t('notify.pHead'))}</div><div class="c">${esc(t('notify.pCmd'))}</div><div class="m">${esc(t('notify.pMeta', { name: state.name || 'PC' }))}</div>
|
|
340
340
|
<div class="btns"><span>${esc(t('notify.allow'))}</span><span>${esc(t('notify.allow10'))}</span><span>${esc(t('notify.deny'))}</span></div></div>
|
package/ui/i18n/en.json
CHANGED
|
@@ -276,7 +276,8 @@
|
|
|
276
276
|
"sound": "Play a sound",
|
|
277
277
|
"offline": "When the PC goes offline",
|
|
278
278
|
"queueDone": "When a queue task is done",
|
|
279
|
-
"
|
|
279
|
+
"settingsChanged": "When the AI or the settings file changes Bridgerator settings",
|
|
280
|
+
"queueStalled": "When a queue task stalls (ChatGPT may be waiting for your OK or show an error in the chat)",
|
|
280
281
|
"limit": "Monthly limit warnings",
|
|
281
282
|
"preview": "Preview",
|
|
282
283
|
"light": "Light",
|
|
@@ -368,7 +369,7 @@
|
|
|
368
369
|
"Attach files or folders to a task so ChatGPT knows where to look.",
|
|
369
370
|
"In ChatGPT, say “Work through my Bridgerator queue”. Watch the ticks appear here.",
|
|
370
371
|
"Edit, reorder or delete tasks any time. A failed task shows why it failed.",
|
|
371
|
-
"ChatGPT may ask you to allow an action in the chat; the task waits for your answer. If a task stalls, Bridgerator shows a notice."
|
|
372
|
+
"ChatGPT may ask you to allow an action in the chat; the task waits for your answer. If a task stalls, Bridgerator shows a notice. \"Selected model is at capacity\" is ChatGPT's own error: press Retry in the chat or pick another model; the queue keeps its place."
|
|
372
373
|
],
|
|
373
374
|
"tipLabel": "say",
|
|
374
375
|
"tip": "Work through my Bridgerator queue"
|
package/ui/i18n/ru.json
CHANGED
|
@@ -276,7 +276,8 @@
|
|
|
276
276
|
"sound": "Звук",
|
|
277
277
|
"offline": "Когда ПК уходит из сети",
|
|
278
278
|
"queueDone": "Когда задача из очереди готова",
|
|
279
|
-
"
|
|
279
|
+
"settingsChanged": "Когда ИИ или файл настроек меняет настройки Bridgerator",
|
|
280
|
+
"queueStalled": "Когда задача из очереди зависла (ChatGPT может ждать вашего «Разрешить» или показать ошибку в чате)",
|
|
280
281
|
"limit": "Предупреждения о лимите",
|
|
281
282
|
"preview": "Пример",
|
|
282
283
|
"light": "Светлая",
|
|
@@ -368,7 +369,7 @@
|
|
|
368
369
|
"Прикрепите к задаче файлы или папки, чтобы ChatGPT знал, где искать.",
|
|
369
370
|
"Скажите в ChatGPT «Work through my Bridgerator queue» и смотрите, как появляются галочки.",
|
|
370
371
|
"Меняйте, переставляйте и удаляйте задачи когда угодно. У невыполненной задачи видно, почему.",
|
|
371
|
-
"ChatGPT может попросить в чате разрешить действие — задача ждёт вашего ответа. Если задача зависла, Bridgerator покажет уведомление."
|
|
372
|
+
"ChatGPT может попросить в чате разрешить действие — задача ждёт вашего ответа. Если задача зависла, Bridgerator покажет уведомление. «Selected model is at capacity» — ошибка самого ChatGPT: нажмите в чате «Повторить» или выберите другую модель; очередь сохранит место."
|
|
372
373
|
],
|
|
373
374
|
"tipLabel": "say",
|
|
374
375
|
"tip": "Work through my Bridgerator queue"
|